diff --git a/.gitlab/ci/rules.yml b/.gitlab/ci/rules.yml index 491943a5a5..a13a1d175c 100644 --- a/.gitlab/ci/rules.yml +++ b/.gitlab/ci/rules.yml @@ -168,6 +168,7 @@ - "components/bt/controller/lib_esp32c5/esp32c5-bt-lib" - "components/bt/controller/lib_esp32h4/esp32h4-bt-lib" - "components/bt/esp_ble_mesh/lib/lib" + - "components/bt/esp_ble_audio/lib/lib" - ".gitmodules" ############## diff --git a/.gitmodules b/.gitmodules index 5975009eb5..f53698ded6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -149,3 +149,8 @@ path = components/bt/esp_ble_mesh/lib/lib url = ../../espressif/esp-ble-mesh-lib.git shallow = true + +[submodule "components/bt/esp_ble_audio/lib/lib"] + path = components/bt/esp_ble_audio/lib/lib + url = ../../espressif/esp-ble-audio-lib.git + shallow = true diff --git a/components/bt/CMakeLists.txt b/components/bt/CMakeLists.txt index 5eb1855e06..48ef11aff0 100644 --- a/components/bt/CMakeLists.txt +++ b/components/bt/CMakeLists.txt @@ -57,6 +57,14 @@ if(CONFIG_IDF_DOC_BUILD) ${ble_mesh_v11_include_dirs}) endif() +set(ble_iso_include_dirs + "esp_ble_audio/api/iso/include" +) + +set(ble_audio_include_dirs + "esp_ble_audio/api/audio/include" +) + set(bluedroid_include_dirs host/bluedroid/api/include/api) if(CONFIG_BT_CONTROLLER_ENABLED OR CONFIG_IDF_DOC_BUILD) @@ -68,6 +76,8 @@ if(CONFIG_IDF_DOC_BUILD) ${target_specific_include_dirs} ${common_include_dirs} ${ble_mesh_include_dirs} + ${ble_iso_include_dirs} + ${ble_audio_include_dirs} ${bluedroid_include_dirs} ${nimble_hci_include_dirs}) endif() @@ -680,6 +690,160 @@ if(CONFIG_BT_ENABLED) endif() endif() + if(CONFIG_BT_ISO) + list(APPEND include_dirs + ${ble_iso_include_dirs} + "esp_ble_audio/host" + "esp_ble_audio/host/adapter" + "esp_ble_audio/include/subsys/bluetooth" + "esp_ble_audio/include/subsys/bluetooth/host" + "esp_ble_audio/include") + + list(APPEND srcs + "esp_ble_audio/host/adapter/nimble/gatt/gatt.c" + "esp_ble_audio/host/adapter/nimble/gatt/gatt.db.c" + "esp_ble_audio/host/adapter/nimble/gatt/gatt.nrp.c" + "esp_ble_audio/host/adapter/nimble/gap.c" + "esp_ble_audio/host/adapter/nimble/iso.c" + "esp_ble_audio/host/common/adv.c" + "esp_ble_audio/host/common/conn.c" + "esp_ble_audio/host/common/gatt.c" + "esp_ble_audio/host/common/hci.c" + "esp_ble_audio/host/common/host.c" + "esp_ble_audio/host/common/iso.c" + "esp_ble_audio/host/common/scan.c" + "esp_ble_audio/host/common/task.c" + "esp_ble_audio/host/common/app/gap.c" + "esp_ble_audio/host/common/app/gatt.c" + "esp_ble_audio/host/utils/crc/crc32_sw.c" + "esp_ble_audio/host/utils/addr.c" + "esp_ble_audio/host/utils/bt_str.c" + "esp_ble_audio/host/utils/buf.c" + "esp_ble_audio/host/utils/crypto.c" + "esp_ble_audio/host/utils/timer.c" + "esp_ble_audio/host/utils/utf8.c" + "esp_ble_audio/host/utils/utils.c" + "esp_ble_audio/host/utils/uuid.c" + "esp_ble_audio/host/iso/iso.c" + "esp_ble_audio/api/iso/esp_ble_iso_common_api.c") + + if(CONFIG_BT_OTS OR CONFIG_BT_OTS_CLIENT) + list(APPEND srcs + "esp_ble_audio/host/common/l2cap.c" + "esp_ble_audio/host/adapter/nimble/l2cap.c") + endif() + endif() + + if(CONFIG_BT_AUDIO) + list(APPEND include_dirs + ${ble_audio_include_dirs} + "esp_ble_audio/include/subsys/bluetooth/host") + + list(APPEND srcs + "esp_ble_audio/host/adapter/nimble/profiles/server.c" + "esp_ble_audio/host/adapter/nimble/init.c" + "esp_ble_audio/host/common/init.c" + "esp_ble_audio/api/audio/esp_ble_audio_aics_api.c" + "esp_ble_audio/api/audio/esp_ble_audio_bap_api.c" + "esp_ble_audio/api/audio/esp_ble_audio_cap_api.c" + "esp_ble_audio/api/audio/esp_ble_audio_ccp_api.c" + "esp_ble_audio/api/audio/esp_ble_audio_codec_api.c" + "esp_ble_audio/api/audio/esp_ble_audio_common_api.c" + "esp_ble_audio/api/audio/esp_ble_audio_csip_api.c" + "esp_ble_audio/api/audio/esp_ble_audio_gmap_api.c" + "esp_ble_audio/api/audio/esp_ble_audio_has_api.c" + "esp_ble_audio/api/audio/esp_ble_audio_mcc_api.c" + "esp_ble_audio/api/audio/esp_ble_audio_media_proxy_api.c" + "esp_ble_audio/api/audio/esp_ble_audio_micp_api.c" + "esp_ble_audio/api/audio/esp_ble_audio_pacs_api.c" + "esp_ble_audio/api/audio/esp_ble_audio_pbp_api.c" + "esp_ble_audio/api/audio/esp_ble_audio_tbs_api.c" + "esp_ble_audio/api/audio/esp_ble_audio_tmap_api.c" + "esp_ble_audio/api/audio/esp_ble_audio_vcp_api.c" + "esp_ble_audio/api/audio/esp_ble_audio_vocs_api.c") + + if(CONFIG_BT_ASCS) + list(APPEND srcs + "esp_ble_audio/host/adapter/nimble/profiles/ascs.c") + endif() + + if(CONFIG_BT_PACS) + list(APPEND srcs + "esp_ble_audio/host/adapter/nimble/profiles/pacs.c") + endif() + + if(CONFIG_BT_BAP_SCAN_DELEGATOR) + list(APPEND srcs + "esp_ble_audio/host/adapter/nimble/profiles/bass.c") + endif() + + if(CONFIG_BT_CAP_ACCEPTOR) + list(APPEND srcs + "esp_ble_audio/host/adapter/nimble/profiles/cas.c") + endif() + + if(CONFIG_BT_CSIP_SET_MEMBER) + list(APPEND srcs + "esp_ble_audio/host/adapter/nimble/profiles/csis.c") + endif() + + if(CONFIG_BT_TBS) + list(APPEND srcs + "esp_ble_audio/host/adapter/nimble/profiles/tbs.c") + endif() + + if(CONFIG_BT_TMAP) + list(APPEND srcs + "esp_ble_audio/host/adapter/nimble/profiles/tmas.c") + endif() + + if(CONFIG_BT_VCP_VOL_REND) + list(APPEND srcs + "esp_ble_audio/host/adapter/nimble/profiles/vcs.c") + endif() + + if(CONFIG_BT_MICP_MIC_DEV) + list(APPEND srcs + "esp_ble_audio/host/adapter/nimble/profiles/mics.c") + endif() + + if(CONFIG_BT_MCS) + list(APPEND srcs + "esp_ble_audio/host/adapter/nimble/profiles/mcs.c") + endif() + + if(CONFIG_BT_HAS) + list(APPEND srcs + "esp_ble_audio/host/adapter/nimble/profiles/has.c") + endif() + + if(CONFIG_BT_OTS OR CONFIG_BT_OTS_CLIENT) + list(APPEND include_dirs + "esp_ble_audio/host/services/ots") + + list(APPEND srcs + "esp_ble_audio/host/services/ots/ots_l2cap.c") + + if(CONFIG_BT_OTS) + list(APPEND srcs + "esp_ble_audio/host/services/ots/ots_oacp.c" + "esp_ble_audio/host/services/ots/ots_obj_manager.c" + "esp_ble_audio/host/services/ots/ots_olcp.c" + "esp_ble_audio/host/services/ots/ots.c") + + if(CONFIG_BT_OTS_DIR_LIST_OBJ) + list(APPEND srcs + "esp_ble_audio/host/services/ots/ots_dir_list.c") + endif() + endif() + + if(CONFIG_BT_OTS_CLIENT) + list(APPEND srcs + "esp_ble_audio/host/services/ots/ots_client.c") + endif() + endif() + endif() + if(CONFIG_BT_DUAL_MODE_ARCH) add_subdirectory(porting_btdm) list(APPEND srcs @@ -1171,6 +1335,13 @@ if(CONFIG_BT_NIMBLE_MESH) PROPERTIES COMPILE_FLAGS -Wno-type-limits) endif() +if(CONFIG_BT_AUDIO) + if(CONFIG_IDF_TARGET_ESP32H4) + add_prebuilt_library(ble_audio "esp_ble_audio/lib/lib/esp32h4/libble_audio.a") + target_link_libraries(${COMPONENT_LIB} PRIVATE ble_audio) + endif() +endif() + if(CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE AND CONFIG_BT_NIMBLE_ENABLED) # some variables in NimBLE are only used by asserts target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-unused-but-set-variable -Wno-unused-variable) diff --git a/components/bt/Kconfig b/components/bt/Kconfig index d9c2fdc753..53ac96bf45 100644 --- a/components/bt/Kconfig +++ b/components/bt/Kconfig @@ -109,6 +109,16 @@ menu "Bluetooth" This option is to configure the buffer size of the hci adv report cache in hci debug mode. This is a ring buffer, the new data will overwrite the oldest data if the buffer is full. + menu "BLE ISO Options" + depends on BT_ENABLED && SOC_BLE_ISO_SUPPORTED + source "$IDF_PATH/components/bt/esp_ble_audio/host/iso/Kconfig.iso.in" + endmenu + + menu "BLE Audio Options" + depends on BT_ENABLED && SOC_BLE_AUDIO_SUPPORTED + source "$IDF_PATH/components/bt/esp_ble_audio/Kconfig.in" + endmenu + endmenu menuconfig BLE_MESH diff --git a/components/bt/esp_ble_audio/Kconfig.in b/components/bt/esp_ble_audio/Kconfig.in new file mode 100644 index 0000000000..7e97dc28cf --- /dev/null +++ b/components/bt/esp_ble_audio/Kconfig.in @@ -0,0 +1,142 @@ +# Bluetooth Audio configuration options + +# SPDX-FileCopyrightText: 2020 Intel Corporation +# SPDX-FileCopyrightText: 2022 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config BT_AUDIO + bool # hidden + help + This option enables Bluetooth Audio support. The specific + features that are available may depend on other features + that have been enabled in the stack, such as Periodic + Advertisement for Broadcast and L2CAP Dynamic Channel + for Unicast. + +config BT_AUDIO_RX + bool # hidden + default y if BT_ASCS_ASE_SNK || BT_BAP_UNICAST_CLIENT_ASE_SRC || BT_BAP_BROADCAST_SINK + select BT_AUDIO + +config BT_AUDIO_TX + bool # hidden + default y if BT_ASCS_ASE_SRC || BT_BAP_UNICAST_CLIENT_ASE_SNK || BT_BAP_BROADCAST_SOURCE + select BT_AUDIO + +menu "AICS Options" + rsource "Kconfig/Kconfig.aics.in" +endmenu + +menu "ASCS Options" + rsource "Kconfig/Kconfig.ascs.in" +endmenu + +menu "BAP Options" + rsource "Kconfig/Kconfig.bap.in" +endmenu + +menu "CAP Options" + rsource "Kconfig/Kconfig.cap.in" +endmenu + +menu "CCP Options" + rsource "Kconfig/Kconfig.ccp.in" +endmenu + +menu "CSIP Options" + rsource "Kconfig/Kconfig.csip.in" +endmenu + +menu "GMAP Options" + rsource "Kconfig/Kconfig.gmap.in" +endmenu + +menu "MCS Options" + rsource "Kconfig/Kconfig.mcs.in" +endmenu + +menu "MCTL Options" + rsource "Kconfig/Kconfig.mctl.in" +endmenu + +menu "MICP Options" + rsource "Kconfig/Kconfig.micp.in" +endmenu + +menu "MPL Options" + rsource "Kconfig/Kconfig.mpl.in" +endmenu + +menu "PACS Options" + rsource "Kconfig/Kconfig.pacs.in" +endmenu + +menu "TBS Options" + rsource "Kconfig/Kconfig.tbs.in" +endmenu + +menu "VCP Options" + rsource "Kconfig/Kconfig.vcp.in" +endmenu + +menu "VOCS Options" + rsource "Kconfig/Kconfig.vocs.in" +endmenu + +menu "TMAP Options" + rsource "Kconfig/Kconfig.tmap.in" +endmenu + +menu "HAS Options" + rsource "Kconfig/Kconfig.has.in" +endmenu + +menu "PBP Options" + rsource "Kconfig/Kconfig.pbp.in" +endmenu + +menu "OTS Options" + rsource "host/services/ots/Kconfig.ots.in" +endmenu + +config BT_AUDIO_NO_LOG + bool "Disable BLE Audio Debug Log" + default n + help + Select this to save the BLE Audio related rodata code size. Enabling + this option will disable the output of BLE Audio debug log. + +menu "BLE Audio Debug Log Level" + depends on !BT_AUDIO_NO_LOG + + choice BT_AUDIO_LOG_LEVEL + prompt "LE_AUDIO_LOG_LEVEL" + default BT_AUDIO_LOG_LEVEL_WARNING + depends on !BT_AUDIO_NO_LOG + help + Define BLE Audio trace level. + + config BT_AUDIO_LOG_LEVEL_NONE + bool "NONE" + config BT_AUDIO_LOG_LEVEL_ERROR + bool "ERROR" + config BT_AUDIO_LOG_LEVEL_WARNING + bool "WARNING" + config BT_AUDIO_LOG_LEVEL_INFO + bool "INFO" + config BT_AUDIO_LOG_LEVEL_DEBUG + bool "DEBUG" + config BT_AUDIO_LOG_LEVEL_VERBOSE + bool "VERBOSE" + endchoice + + config BT_AUDIO_LOG_LEVEL + int + default 0 if BT_AUDIO_LOG_LEVEL_NONE + default 1 if BT_AUDIO_LOG_LEVEL_ERROR + default 2 if BT_AUDIO_LOG_LEVEL_WARNING + default 3 if BT_AUDIO_LOG_LEVEL_INFO + default 4 if BT_AUDIO_LOG_LEVEL_DEBUG + default 5 if BT_AUDIO_LOG_LEVEL_VERBOSE + default 2 +endmenu diff --git a/components/bt/esp_ble_audio/Kconfig/Kconfig.aics.in b/components/bt/esp_ble_audio/Kconfig/Kconfig.aics.in new file mode 100644 index 0000000000..447f654bac --- /dev/null +++ b/components/bt/esp_ble_audio/Kconfig/Kconfig.aics.in @@ -0,0 +1,50 @@ +# Bluetooth Audio - Audio Input Control Service options +# +# SPDX-FileCopyrightText: 2020 Bose Corporation +# SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +##################### Audio Input Control Service ##################### + +config BT_AICS_MAX_INSTANCE_COUNT + int "Audio Input Control Service max instance count" + default 0 + range 0 15 + help + This option sets the maximum number of instances of Audio Input + Control Services. + +config BT_AICS + bool # hidden + default y if BT_AICS_MAX_INSTANCE_COUNT > 0 + help + This hidden option enables support for Audio Input Control Service. + +if BT_AICS + + config BT_AICS_MAX_INPUT_DESCRIPTION_SIZE + int "Audio Input Control Service max input description size" + default 32 + range 0 512 + help + This option sets the maximum input description size in octets. + +endif # BT_AICS + +##################### Audio Input Control Service Client ##################### + +config BT_AICS_CLIENT_MAX_INSTANCE_COUNT + int "Audio Input Control Service client max instance count" + default 0 + range 0 15 + help + This option sets the maximum number of instances of Audio Input + Control Services. + +config BT_AICS_CLIENT + bool # hidden + default y if BT_AICS_CLIENT_MAX_INSTANCE_COUNT > 0 + help + This hidden option enables support for Audio Input Control Service. diff --git a/components/bt/esp_ble_audio/Kconfig/Kconfig.ascs.in b/components/bt/esp_ble_audio/Kconfig/Kconfig.ascs.in new file mode 100644 index 0000000000..b5eec7673d --- /dev/null +++ b/components/bt/esp_ble_audio/Kconfig/Kconfig.ascs.in @@ -0,0 +1,73 @@ +# Bluetooth Audio - Audio Stream Control configuration options +# +# SPDX-FileCopyrightText: 2020 Intel Corporation +# SPDX-FileCopyrightText: 2022 Nordic Semiconductor ASA + +# SPDX-License-Identifier: Apache-2.0 +# + +config BT_ASCS + bool "Audio Stream Control Service Support" + help + This option enables support for Audio Stream Control Service. + +if BT_ASCS + + config BT_ASCS_MAX_ASE_SNK_COUNT + int "Maximum number of Audio Stream Endpoint Sink Characteristics" + default 2 + range 0 255 + help + An ASE Sink characteristic represents the state of an ASE, which is + coupled to a single direction of a unicast Audio Stream. + + config BT_ASCS_MAX_ASE_SRC_COUNT + int "Maximum number of Audio Stream Endpoint Source Characteristics" + default 2 + range 0 255 + help + An ASE Source characteristic represents the state of an ASE, which is + coupled to a single direction of a unicast Audio Stream. + + config BT_ASCS_ASE_SNK + bool # hidden + default y if BT_ASCS_MAX_ASE_SNK_COUNT > 0 + select BT_PAC_SNK + select BT_AUDIO_RX + + config BT_ASCS_ASE_SRC + bool # hidden + default y if BT_ASCS_MAX_ASE_SRC_COUNT > 0 + select BT_PAC_SRC + select BT_AUDIO_TX + + config BT_ASCS_MAX_ACTIVE_ASES + int "Number of simultaneously supported ASE sessions" + default BT_ISO_MAX_CHAN + range 1 65535 + help + The number of simultaneously supported active ASEs, in particular + meaning the number of ASEs that are allowed to be in a non-idle state at + a single time. + + config BT_ASCS_ISO_DISCONNECT_DELAY + int "Milliseconds of delay before ASCS disconnects ISO after stream stop" + range 0 5000 + default 500 + help + The number of milliseconds ASCS will wait before disconnecting the ISO + of a stopped stream. The delay is added as it is the Unicast Client's + responsibility, but this is a failsafe to ensure that ISO channel is + being properly disconnected. + + config BT_ASCS_ASE_BUF_TIMEOUT + int "Milliseconds of timeout when handle concurrent access to the long read ASE buffer" + range 0 1000 + default 50 + help + The number of milliseconds that the ASCS implementation will maximum wait before rejecting + an ASE read or dropping a notification if the ASE state is being accessed by another + thread. + + +endif # BT_ASCS diff --git a/components/bt/esp_ble_audio/Kconfig/Kconfig.bap.in b/components/bt/esp_ble_audio/Kconfig/Kconfig.bap.in new file mode 100644 index 0000000000..36d060e8bc --- /dev/null +++ b/components/bt/esp_ble_audio/Kconfig/Kconfig.bap.in @@ -0,0 +1,268 @@ +# Bluetooth Audio - Basic Audio Profile configuration options +# +# SPDX-FileCopyrightText: 2020 Intel Corporation +# SPDX-FileCopyrightText: 2022-2025 Nordic Semiconductor ASA + +# SPDX-License-Identifier: Apache-2.0 +# + +config BT_BAP_UNICAST + bool + default y if BT_BAP_UNICAST_SERVER || BT_BAP_UNICAST_CLIENT + +config BT_BAP_UNICAST_SERVER + bool "Bluetooth Unicast Audio Server Support" + select BT_ISO_PERIPHERAL + select BT_ASCS + select BT_PAC_SNK if BT_ASCS_ASE_SNK + select BT_PAC_SRC if BT_ASCS_ASE_SRC + help + This option enables support for Bluetooth Unicast Audio Server + using Isochronous channels. + +config BT_BAP_UNICAST_CLIENT + bool "Bluetooth Unicast Audio Client Support" + select BT_ISO_CENTRAL + help + This option enables support for Bluetooth Unicast Audio Client + using Isochronous channels. + +config BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE + int "Codec Specific Configuration Data Size" + default 19 + range 0 255 + help + Number of octets to support for Codec Specific Configuration data. + The default value 19 matches the required fields for the LC3 codec. + +config BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE + int "Codec Specific Configuration Metadata Size" + default 20 + range 0 255 + help + Number of octets to support for Codec Specific Configuration metadata. + +config BT_BAP_BASS_MAX_SUBGROUPS + int "Maximum number of subgroups supported for the BASS receive states" + default 1 + range 1 24 + help + This option sets the maximum number of subgroups supported. + Due to limitations in advertising data, the maximum size of all subgroups are 249. + The minimum size of a subgroup is 10 octets. + So effectively there can be a maximum of 24 subgroups in a BASE. + +config BT_AUDIO_CODEC_CAP_MAX_DATA_SIZE + int "Codec Capabilities Data Size" + default 19 + range 0 255 + help + Number of octets to support for Codec Specific Capabilities data. + The default value 19 matches the required fields for the LC3 codec. + +config BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE + int "Codec Capabilities Metadata Size" + default 4 + range 0 255 + help + Number of octets to support for Codec Specific Capabilities metadata. + +if BT_BAP_UNICAST_CLIENT + + config BT_BAP_UNICAST_CLIENT_GROUP_COUNT + int "Basic Audio Unicast Group count" + default 1 + range 1 BT_ISO_MAX_CIG + help + This option sets the number of connected audio groups to support as + the unicast client. + + config BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT + int "Basic Audio Profile Unicast Group Connected Isochronous Stream (CIS) count" + depends on BT_BAP_UNICAST_CLIENT_GROUP_COUNT > 0 + default 1 + range 1 BT_ISO_MAX_CHAN if BT_ISO_MAX_CHAN < 31 + range 1 31 + help + This option sets the maximum number of CIS per unicast group to support. + Since BAP streams are unidirectional, two BAP streams may use a single CIS, the number of + BAP audio streams per group may be up to twice of this value. + + config BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT + int "Basic Audio Profile ASE Sink count" + default 2 + range 0 255 + help + This option enables caching a number of Audio Stream Endpoint Sink + instances for Basic Audio Profile on a per connection basis. + + config BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT + int "Basic Audio Profile ASE Source count" + default 2 + range 0 255 + help + This option enables caching a number of Audio Stream Endpoint Source + instances for Basic Audio Profile on a per connection basis. + + config BT_BAP_UNICAST_CLIENT_ASE_SNK + bool # hidden + default y if BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 + + config BT_BAP_UNICAST_CLIENT_ASE_SRC + bool # hidden + default y if BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0 + +endif # BT_BAP_UNICAST_CLIENT + +config BT_BAP_BROADCAST_SOURCE + bool "Bluetooth Broadcast Source Audio Support" + select BT_ISO_BROADCASTER + help + This option enables support for Bluetooth Broadcast Source Audio using + Isochronous channels. + +if BT_BAP_BROADCAST_SOURCE + + config BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT + int "Basic Audio Broadcast Source subgroup count" + default 1 + range 1 BT_ISO_MAX_CHAN if BT_ISO_MAX_CHAN < 31 + range 1 31 + help + This option sets the maximum number of subgroups per broadcast source + to support. + + config BT_BAP_BROADCAST_SRC_COUNT + int "Basic Audio Broadcaster source count" + default 1 + range 1 BT_ISO_MAX_BIG + help + This option sets the number of broadcast sources to support. + One broadcast source can send multiple streams + (up to BT_BAP_BROADCAST_SRC_STREAM_COUNT per broadcast source). + + + config BT_BAP_BROADCAST_SRC_STREAM_COUNT + int "Basic Audio Broadcast Source Stream count" + default 1 + range 1 BT_ISO_MAX_CHAN if BT_ISO_MAX_CHAN < 31 + range 1 31 + help + This option sets the maximum number of streams per broadcast source + to support. + +endif # BT_BAP_BROADCAST_SOURCE + +config BT_BAP_BROADCAST_SINK + bool "Bluetooth Broadcast Sink Audio Support" + select BT_ISO_SYNC_RECEIVER + select BT_PAC_SNK + depends on BT_BAP_SCAN_DELEGATOR + help + This option enables support for Bluetooth Broadcast Sink Audio using + Isochronous channels. + +if BT_BAP_BROADCAST_SINK + + config BT_BAP_BROADCAST_SNK_SUBGROUP_COUNT + int "Basic Audio Profile Broadcast Sink subgroup count" + default 1 + range 1 BT_BAP_BASS_MAX_SUBGROUPS + help + This option sets the maximum number of subgroups per broadcast sink + to support. + + config BT_BAP_BROADCAST_SNK_COUNT + int "Basic Audio Broadcaster Sink count" + default 1 + range 0 BT_ISO_MAX_BIG + help + This option sets the number of broadcast sinks to support. + One broadcast sink can receive multiple streams + (up to BT_BAP_BROADCAST_SNK_STREAM_COUNT per broadcast sink). + + config BT_BAP_BROADCAST_SNK_STREAM_COUNT + int "Basic Audio Broadcast Sink Stream count" + depends on BT_BAP_BROADCAST_SNK_COUNT > 0 + default 1 + range 1 BT_ISO_MAX_CHAN if BT_ISO_MAX_CHAN < 31 + range 1 31 + help + This option sets the maximum number of streams per broadcast sink + to support. + +endif # BT_BAP_BROADCAST_SINK + +config BT_BAP_SCAN_DELEGATOR + bool "Basic Audio Profile Scan Delegator role support" + select BT_ISO_SYNC_RECEIVER + help + This option enables support for the Scan Delegator role and the + Broadcast Audio Scan Service (BASS). + +if BT_BAP_SCAN_DELEGATOR + + config BT_BAP_SCAN_DELEGATOR_RECV_STATE_COUNT + int "Scan Delegator Receive State Count" + default 1 + range 1 3 + help + Sets the number of receive state characteristics present on the + server. Each characteristic may hold information to sync to a + periodic advertise or a broadcast isochronous stream. + + config BT_BAP_SCAN_DELEGATOR_BUF_TIMEOUT + int "Milliseconds of timeout when handle concurrent access to the long read ASE buffer" + range 0 1000 + default 50 + help + The maximum number of milliseconds that the scan delegator implementation will wait + before rejecting a read or dropping a notification if the scan delegator state is + being accessed by another thread. + +endif # BT_BAP_SCAN_DELEGATOR + +config BT_BAP_BROADCAST_ASSISTANT + bool "Basic Audio Profile Broadcast Assistant role support" + select BT_ISO_SYNC_RECEIVER + select BT_AUDIO + help + This option enables support for the Broadcast Assistant role. + +if BT_BAP_BROADCAST_ASSISTANT + + config BT_BAP_BROADCAST_ASSISTANT_RECV_STATE_COUNT + int "Broadcast Assistant Max Receive State Count" + default 1 + range 1 255 + help + Sets the number of maximum receive stat characteristics that will be + discovered and ready to use. Each characteristic may hold information + to sync to a periodic advertise or a broadcast isochronous stream. + +endif # BT_BAP_BROADCAST_ASSISTANT + +config BT_BAP_DEBUG_STREAM_DATA + bool "Bluetooth Audio Stream data debug" + help + Use this option to enable Bluetooth Audio Stream data debug logs for + the Bluetooth Audio functionality. This will enable debug logs for all + audio data received and sent. + +config BT_BAP_STREAM + # Virtual/hidden option + bool + default y if BT_ASCS || BT_BAP_UNICAST_CLIENT || \ + BT_BAP_BROADCAST_SOURCE || BT_BAP_BROADCAST_SINK + +config BT_BAP_DEBUG_STREAM_SEQ_NUM + bool "Bluetooth Audio Stream sequence number debug" + default y + help + Use this option to enable Bluetooth Audio Stream sequence number debugging logs for + the Bluetooth Audio functionality. This will provide a warning if the application + provides unexpected sequence numbers. + +config BT_BAP_BASE + bool + default y if BT_BAP_BROADCAST_SINK || BT_BAP_BROADCAST_ASSISTANT || BT_BAP_SCAN_DELEGATOR diff --git a/components/bt/esp_ble_audio/Kconfig/Kconfig.cap.in b/components/bt/esp_ble_audio/Kconfig/Kconfig.cap.in new file mode 100644 index 0000000000..d845bbbb3c --- /dev/null +++ b/components/bt/esp_ble_audio/Kconfig/Kconfig.cap.in @@ -0,0 +1,58 @@ +# Bluetooth Audio - Common Audio Profile (CAP) options +# +# SPDX-FileCopyrightText: 2022 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +config BT_CAP + bool # hidden + default y if BT_CAP_ACCEPTOR || BT_CAP_INITIATOR + +config BT_CAP_ACCEPTOR + bool "Common Audio Profile Acceptor Role Support" + depends on BT_BAP_UNICAST_SERVER || (BT_BAP_BROADCAST_SINK && BT_BAP_SCAN_DELEGATOR) + depends on BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE >= 4 + help + Enabling this will enable the CAP Acceptor role. This instantiates the + common audio service (CAS). + +config BT_CAP_ACCEPTOR_SET_MEMBER + bool "Common Audio Profile Acceptor Role Set Member support" + depends on BT_CAP_ACCEPTOR + depends on BT_CSIP_SET_MEMBER + help + Enabling this will allow a CAP acceptor to be a set member. + Enabling this will require a manual register of the CAS service. + Enabling will take one of the allocated CSIS instances + (BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT). + +config BT_CAP_INITIATOR_UNICAST + bool # hidden + default y if BT_CAP_INITIATOR && BT_BAP_UNICAST_CLIENT + +config BT_CAP_INITIATOR + bool "Common Audio Profile Initiator Role Support" + depends on (BT_BAP_UNICAST_CLIENT && BT_CSIP_SET_COORDINATOR) || BT_BAP_BROADCAST_SOURCE + depends on BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE >= 4 + help + Enabling this will enable the CAP Initiator role. + +config BT_CAP_COMMANDER + bool "Common Audio Profile Initiator Role Support" + depends on (BT_BAP_BROADCAST_ASSISTANT && BT_BAP_SCAN_DELEGATOR && BT_CSIP_SET_COORDINATOR) || \ + (BT_BAP_SCAN_DELEGATOR && BT_CSIP_SET_COORDINATOR) || \ + (BT_VCP_VOL_CTLR && BT_CSIP_SET_COORDINATOR) || \ + (BT_MICP_MIC_CTLR && BT_CSIP_SET_COORDINATOR) || \ + BT_TBS_CLIENT || \ + BT_MCC + help + Enabling this will enable the CAP Initiator role. + +config BT_CAP_HANDOVER + bool "Common Audio Profile Handover Procedures" + depends on BT_CAP_COMMANDER && BT_CAP_INITIATOR && BT_BAP_BROADCAST_ASSISTANT && \ + BT_BAP_BROADCAST_SOURCE && BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 + help + Enable support for the CAP Handover procedures, allowing a device to switch between + broadcast and unicast for a usecase. diff --git a/components/bt/esp_ble_audio/Kconfig/Kconfig.ccp.in b/components/bt/esp_ble_audio/Kconfig/Kconfig.ccp.in new file mode 100644 index 0000000000..a258d3d6d6 --- /dev/null +++ b/components/bt/esp_ble_audio/Kconfig/Kconfig.ccp.in @@ -0,0 +1,52 @@ +# Bluetooth Audio - Call Control Profile (CCP) configuration options +# +# SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +config BT_CCP_CALL_CONTROL_CLIENT + bool "Call Control Profile Client Support" + depends on BT_TBS_CLIENT + help + This option enables support for the Call Control Profile Client which uses the Telephone + Bearer Service (TBS) client to control calls on a remote device. + +if BT_CCP_CALL_CONTROL_CLIENT + + config BT_CCP_CALL_CONTROL_CLIENT_BEARER_COUNT + int "Telephone bearer count" + default 1 + range 1 255 if BT_TBS_CLIENT_TBS + range 1 1 + help + The number of supported telephone bearers on the CCP Call Control Client + +endif # BT_CCP_CALL_CONTROL_CLIENT + +config BT_CCP_CALL_CONTROL_SERVER + bool "Call Control Profile Call Control Server Support" + depends on BT_TBS + help + This option enables support for the Call Control Profile Call Control Server which uses + the Telephone Bearer Service (TBS) to hold and control calls on a device. + +if BT_CCP_CALL_CONTROL_SERVER + + config BT_CCP_CALL_CONTROL_SERVER_BEARER_COUNT + int "Telephone bearer count" + default 1 + range 1 255 + help + The number of supported telephone bearers on the CCP Call Control Server + + config BT_CCP_CALL_CONTROL_SERVER_PROVIDER_NAME_MAX_LEN + # The original BT_CCP_CALL_CONTROL_SERVER_PROVIDER_NAME_MAX_LENGTH is reported + # as too long while running pre-commit check. + int "The maximum length of the bearer provider name excluding null terminator" + default BT_TBS_MAX_PROVIDER_NAME_LENGTH + range 1 BT_TBS_MAX_PROVIDER_NAME_LENGTH + help + Sets the maximum length of the bearer provider name. + +endif # BT_CCP_CALL_CONTROL_SERVER diff --git a/components/bt/esp_ble_audio/Kconfig/Kconfig.csip.in b/components/bt/esp_ble_audio/Kconfig/Kconfig.csip.in new file mode 100644 index 0000000000..c2dda10cc0 --- /dev/null +++ b/components/bt/esp_ble_audio/Kconfig/Kconfig.csip.in @@ -0,0 +1,95 @@ +# Bluetooth Audio - Broadcast Assistant configuration options +# +# SPDX-FileCopyrightText: 2020 Bose Corporation +# SPDX-FileCopyrightText: 2021 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +#################### Coordinated Set Identification Service #################### + +config BT_CSIP_SET_MEMBER + bool "Coordinated Set Identification Profile Set Member support" + help + This option enables support for Coordinated Set Identification + Profile Set Member role and the Coordinated Set Identification + Service. + +if BT_CSIP_SET_MEMBER + + config BT_CSIP_SET_MEMBER_TEST_SAMPLE_DATA + bool "Coordinated Set Identification Service Test Sample Data" + help + Enable the use of the sample data defined by the CSIS spec SIRK. + This will use the sample SIRK, prand and LTK. + + WARNING: This option enables anyone to track and decrypt the SIRK + (if encrypted) using public sample data. + Should not be used for production builds. + + config BT_CSIP_SET_MEMBER_ENC_SIRK_SUPPORT + bool "Support for encrypted SIRK" + default y + help + Enables support encrypting the SIRK. + + config BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT + int "Coordinated Set Identification Profile max service instance count" + default 1 + range 1 255 + help + This option sets the maximum number of instances of Coordinated Set + Identification Services. If the service is declared as primary service + then only a single instance is possible. + + Enabling BT_CAP_ACCEPTOR_SET_MEMBER will take one of the allocated + instances. + + config BT_CSIP_SET_MEMBER_SIRK_NOTIFIABLE + bool "SIRK notifiable Support" + help + This option enables support for clients to be notified on SIRK changes. + + config BT_CSIP_SET_MEMBER_SIZE_NOTIFIABLE + bool "Set Size notifiable support" + help + This option enables support for clients to be notified on Set Size changes. + +endif # BT_CSIP_SET_MEMBER + +#################### Coordinated Set Identification Client #################### + +config BT_CSIP_SET_COORDINATOR + bool "Coordinated Set Identification Profile Set Coordinator Support" + help + This option enables support for Coordinated Set Identification + Profile Set Coordinator. + +if BT_CSIP_SET_COORDINATOR + + config BT_CSIP_SET_COORDINATOR_TEST_SAMPLE_DATA + bool "Coordinated Set Identification Service Test Sample Data" + help + Enable the use of the sample data defined by the CSIS spec. + This will use the sample SIRK, prand and LTK. + + WARNING: This option enables the client to use the sample data + to locate members and decrypt the SIRK, and thus won't work + with set members that are not using the sample data. + Should not be used for production builds. + + config BT_CSIP_SET_COORDINATOR_MAX_CSIS_INSTANCES + int "Coordinated Set Identification Service Count" + default 1 + range 1 3 + help + Sets the number of service instances, which corresponds to the number + of different sets the peer device may be in. + + config BT_CSIP_SET_COORDINATOR_ENC_SIRK_SUPPORT + bool "Support for encrypted SIRK" + default y + help + Enables support encrypting the SIRK. + +endif # BT_CSIP_SET_COORDINATOR diff --git a/components/bt/esp_ble_audio/Kconfig/Kconfig.gmap.in b/components/bt/esp_ble_audio/Kconfig/Kconfig.gmap.in new file mode 100644 index 0000000000..176bb977eb --- /dev/null +++ b/components/bt/esp_ble_audio/Kconfig/Kconfig.gmap.in @@ -0,0 +1,28 @@ +# Bluetooth Audio - Gaming Audio Profile (GMAP) options +# +# SPDX-FileCopyrightText: 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +config BT_GMAP_UGG_SUPPORTED + bool # hidden + default y if BT_CAP_INITIATOR && BT_BAP_UNICAST_CLIENT && BT_VCP_VOL_CTLR + +config BT_GMAP_UGT_SUPPORTED + bool # hidden + default y if BT_CAP_ACCEPTOR && BT_BAP_UNICAST_SERVER + +config BT_GMAP_BGS_SUPPORTED + bool # hidden + default y if BT_CAP_INITIATOR && BT_BAP_BROADCAST_SOURCE && BT_BAP_BROADCAST_ASSISTANT + +config BT_GMAP_BGR_SUPPORTED + bool # hidden + default y if BT_CAP_ACCEPTOR && BT_BAP_BROADCAST_SINK && BT_VCP_VOL_REND + +config BT_GMAP + bool "Gaming Audio Profile" + depends on BT_CAP_ACCEPTOR || BT_CAP_INITIATOR + help + Enabling this will enable GMAP. diff --git a/components/bt/esp_ble_audio/Kconfig/Kconfig.has.in b/components/bt/esp_ble_audio/Kconfig/Kconfig.has.in new file mode 100644 index 0000000000..f952dcf5ef --- /dev/null +++ b/components/bt/esp_ble_audio/Kconfig/Kconfig.has.in @@ -0,0 +1,59 @@ +# Bluetooth Audio - Hearing Access Service options +# +# SPDX-FileCopyrightText: 2022 Codecoup +# +# SPDX-License-Identifier: Apache-2.0 + +menuconfig BT_HAS + bool "Hearing Access Service support" + depends on BT_BAP_UNICAST_SERVER + help + This option enables support for Hearing Access Service. + +if BT_HAS + + config BT_HAS_FEATURES_NOTIFIABLE + bool "Hearing Aid Features Notifiable Support" + help + This option enables support for clients to subscribe for notifications + on the Hearing Aid Features characteristic. + + config BT_HAS_PRESET_COUNT + int "Preset record list size" + default 2 + range 0 255 + help + This option sets the number of Hearing Access Service Presets + that can be registered. Setting this value to 0 disables Presets support. + + config BT_HAS_PRESET_SUPPORT + bool # hidden + default y if BT_HAS_PRESET_COUNT > 0 + + if BT_HAS_PRESET_SUPPORT + + config BT_HAS_PRESET_NAME_DYNAMIC + bool "Allow to set preset name on runtime" + help + Enabling this option allows for runtime configuration of preset name. + + config BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE + bool "Preset Control Point Notifiable support (depends on EATT)" + help + This option enables support for clients to subscribe for notifications + on the Hearing Aid Preset Control Point characteristic. + + config BT_HAS_ACTIVE_PRESET_INDEX + bool # hidden + default y if BT_HAS_PRESET_SUPPORT + help + This option enables the Hearing Aid Active Preset Index characteristic. + + endif # BT_HAS_PRESET_SUPPORT + +endif # BT_HAS + +config BT_HAS_CLIENT + bool "Hearing Access Service Client support" + help + This option enables support for Hearing Access Service Client. diff --git a/components/bt/esp_ble_audio/Kconfig/Kconfig.mcs.in b/components/bt/esp_ble_audio/Kconfig/Kconfig.mcs.in new file mode 100644 index 0000000000..ef8bb91f05 --- /dev/null +++ b/components/bt/esp_ble_audio/Kconfig/Kconfig.mcs.in @@ -0,0 +1,218 @@ +# Bluetooth Audio - Media control configuration options + +# +# SPDX-FileCopyrightText: 2020-2022 Nordic Semiconductor +# +# SPDX-License-Identifier: Apache-2.0 +# + +#### Media Control Service ################################ + +config BT_MCS + bool "Media Control Service Support" + depends on BT_MCTL_LOCAL_PLAYER_REMOTE_CONTROL + help + This option enables support for the Media Control Service. + +#### Media Control Client ################################ + +config BT_MCC + bool "Media Control Client Support" + help + This option enables support for the Media Control Client. + +if BT_MCC + + config BT_MCC_MEDIA_PLAYER_NAME_MAX + int "Max length of media player name" + default 20 + range 1 255 + help + Sets the maximum number of bytes (including the null termination) of + the name of the media player. If the name is longer, the media + control client will truncate the name when reading it. + + config BT_MCC_ICON_URL_MAX + int "Max length of media player icon URL" + default 40 + range 1 255 + help + Sets the maximum number of bytes (including the null termination) of + the media player icon URL. If the URL is longer, the media control + client will truncate the name when reading it. + + config BT_MCC_TRACK_TITLE_MAX + int "Max length of the title of a track" + default 40 + range 1 255 + help + Sets the maximum number of bytes (including the null termination) of + the title of any track in the media player. If the title is longer, + the media control client will truncate the title when reading it. + + config BT_MCC_SEGMENT_NAME_MAX + int "Max length of the name of a track segment" + default 25 + range 1 255 + help + Sets the maximum number of bytes (including the null termination) + of the name of any track segment in the media player. If the name is + longer, the media control client will truncate the name when reading + it. + + config BT_MCC_OTS + bool "Media Control Client support for Object Transfer Service (depends on OTS Client)" + depends on BT_OTS_CLIENT + help + Use this option to configure support in the Media Control Client for + an included Object Transfer Service in the Media Control Service. + + if BT_MCC_OTS + + config BT_MCC_OTC_OBJ_BUF_SIZE + int "The size of the buffer used for OTC object in MCC" + default 512 + range 1 65536 + help + Sets the size (in octets) of the buffer used for receiving the content + of objects. + Should be set large enough to fit any expected object. + + config BT_MCC_TOTAL_OBJ_CONTENT_MEM + int "Total memory size to use for storing the content of objects" + default 1 + range 0 65536 + help + Sets the total memory size (in octets) to use for storing the content + of objects. + This is used for the total memory pool buffer size from which memory + is allocated when reading object content. + + config BT_MCC_TRACK_SEGS_MAX_CNT + int "Maximum number of tracks segments in a track segment object" + default 25 + range 0 500 + help + Sets the maximum number of tracks segments in a track segment object. + If the received object is bigger, the remaining data in the object + will be ignored. + + config BT_MCC_GROUP_RECORDS_MAX + int "Maximum number of records in a group object" + default 25 + range 0 500 + help + Sets the maximum number of records in a group object. If the received + group object has more records than this, the remaining records in the + object will be ignored. + + endif # BT_MCC_OTS + + config BT_MCC_SHELL + bool "Media Control Client Shell Support" + help + This option enables shell support for the Media Control Client. + + config BT_MCC_MINIMAL + bool "Minimal Media Control Client without optional procedures" + help + This option disables all optional procedures in the Media Control Client. + + config BT_MCC_READ_MEDIA_PLAYER_ICON_URL + bool "Support reading Media Player Icon URL" + default y if !BT_MCC_MINIMAL + help + This option enables support for Read Media Information procedure + optionally read the Media Player Icon URL. + + config BT_MCC_READ_TRACK_TITLE + bool "Support reading Track Title" + default y if !BT_MCC_MINIMAL + help + This option enables support for reading Track Title. + + config BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION + bool "Support to enable or disable the subscription of Track Title" + default y if !BT_MCC_MINIMAL + help + This option enables support for the subscription of Track Title. + + config BT_MCC_READ_TRACK_DURATION + bool "Support reading Track Duration" + default y if !BT_MCC_MINIMAL + help + This option enables support for reading Track Duration. + + config BT_MCC_READ_TRACK_POSITION + bool "Support reading Track Position" + default y if !BT_MCC_MINIMAL + help + This option enables support for reading Track Position. + + config BT_MCC_SET_TRACK_POSITION + bool "Support setting Track Position" + default y if !BT_MCC_MINIMAL + help + This option enables support for setting Track Position. + + config BT_MCC_READ_PLAYBACK_SPEED + bool "Support reading Playback Speed" + default y if !BT_MCC_MINIMAL + help + This option enables support for reading Playback Speed. + + config BT_MCC_SET_PLAYBACK_SPEED + bool "Support setting Playback Speed" + default y if !BT_MCC_MINIMAL + help + This option enables support for setting Playback Speed. + + config BT_MCC_READ_SEEKING_SPEED + bool "Support reading Seeking Speed" + default y if !BT_MCC_MINIMAL + help + This option enables support for reading Seeking Speed. + + config BT_MCC_READ_PLAYING_ORDER + bool "Support reading Playing Order" + default y if !BT_MCC_MINIMAL + help + This option enables support for reading Playing Order. + + config BT_MCC_SET_PLAYING_ORDER + bool "Support setting Playing Order" + default y if !BT_MCC_MINIMAL + help + This option enables support for setting Playing Order. + + config BT_MCC_READ_PLAYING_ORDER_SUPPORTED + bool "Support reading Playing Order Supported" + default y if !BT_MCC_MINIMAL + help + This option enables support for reading Playing Order Supported. + + config BT_MCC_READ_MEDIA_STATE + bool "Support reading Media State" + default y if !BT_MCC_MINIMAL + help + This option enables support for reading Media State. + + config BT_MCC_SET_MEDIA_CONTROL_POINT + bool "Support setting Media Control Point" + default y if !BT_MCC_MINIMAL + help + This option enables support for setting Media Control Point. + + config BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED + bool "Support reading Media Control Point Opcodes Supported" + default y if !BT_MCC_MINIMAL + help + This option enables support for reading Media Control Point Opcodes Supported. + + config BT_MCC_READ_CONTENT_CONTROL_ID + bool "Support reading Content Control ID" + default y if !BT_MCC_MINIMAL + help + This option enables support for reading Content Control ID. + +endif # BT_MCC diff --git a/components/bt/esp_ble_audio/Kconfig/Kconfig.mctl.in b/components/bt/esp_ble_audio/Kconfig/Kconfig.mctl.in new file mode 100644 index 0000000000..d209966c3f --- /dev/null +++ b/components/bt/esp_ble_audio/Kconfig/Kconfig.mctl.in @@ -0,0 +1,59 @@ +# Bluetooth Audio - Media control configuration options + +# +# SPDX-FileCopyrightText: 2022 Nordic Semiconductor +# +# SPDX-License-Identifier: Apache-2.0 +# + +# TODO: Decide, and add, top-level namespace prefix (currently none) to symbols. +# Dependent upon where the module will be placed. + +config BT_MCTL + bool "Support for media player control" + help + Enables support for control of local and remote media players + To enable support for control of a local media player, support for + local media player must be enabled + +if BT_MCTL + + config BT_MCTL_LOCAL_PLAYER_CONTROL + bool "Support for control of local media player" + help + This option enables support for control of a local media player + + config BT_MCTL_LOCAL_PLAYER_LOCAL_CONTROL + bool "Support for local control of local media player" + default y + depends on BT_MCTL_LOCAL_PLAYER_CONTROL + help + This option enables support for local application control of local + media players + + config BT_MCTL_LOCAL_PLAYER_REMOTE_CONTROL + bool "Support for remote control of local media players" + depends on BT_MCTL_LOCAL_PLAYER_CONTROL + help + This option enables support for remote control of local media + players. + + config BT_MCTL_REMOTE_PLAYER_CONTROL + bool "Support for control of remote media player" + default y + # TODO: Remove dependency on BT_MCC once MCC has been reworked + depends on BT_MCC + help + This options enables support for control of a remote media player. + + config BT_MCTL_REMOTE_PLAYER_CONTROL_OBJECTS + bool "Support for accessing objects on remote player" + depends on BT_MCTL_REMOTE_PLAYER_CONTROL + default y + # TODO: Remove dependency on BT_MCC_OTS once MCC has been reworked + depends on BT_MCC_OTS + help + This options enables support for accessing objects (tracks, groups, + search results, ...) on a remote media player + +endif # BT_MCTL diff --git a/components/bt/esp_ble_audio/Kconfig/Kconfig.micp.in b/components/bt/esp_ble_audio/Kconfig/Kconfig.micp.in new file mode 100644 index 0000000000..228622f6aa --- /dev/null +++ b/components/bt/esp_ble_audio/Kconfig/Kconfig.micp.in @@ -0,0 +1,62 @@ +# Bluetooth Audio - Microphone Control Service options +# +# SPDX-FileCopyrightText: 2020 Bose Corporation +# SPDX-FileCopyrightText: 2020-2022 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +########### Microphone Control Profile Microphone Device ########### + +config BT_MICP_MIC_DEV + bool "Microphone Control Profile Microphone Device Support" + help + This option enables support for Microphone Control Profile + Microphone Device. + +if BT_MICP_MIC_DEV + + config BT_MICP_MIC_DEV_AICS_INSTANCE_COUNT + int "Audio Input Control Service instance count for \ + Microphone Control Service Microphone Device" + default 0 + range 0 BT_AICS_MAX_INSTANCE_COUNT + help + This option sets the number of instances of Audio Input Control + Services for Microphone Control Profile Microphone Device. + + config BT_MICP_MIC_DEV_AICS + bool # Hidden + default y if BT_MICP_MIC_DEV_AICS_INSTANCE_COUNT > 0 + help + This hidden option makes it possible to easily check if AICS is + enabled for Microphone Control Profile Microphone Device. + +endif # BT_MICP_MIC_DEV + +########### Microphone Control Profile Microphone Controller ########### + +config BT_MICP_MIC_CTLR + bool "Microphone Control Profile Microphone Controller Support" + help + This option enables support for the Microphone Control Profile + Microphone Controller role + +if BT_MICP_MIC_CTLR + + config BT_MICP_MIC_CTLR_MAX_AICS_INST + int "Maximum number of Audio Input Control Service instances to setup" + default 0 + range 0 BT_AICS_CLIENT_MAX_INSTANCE_COUNT + help + Sets the maximum number of Audio Input Control Service (AICS) + instances to setup and use. + + config BT_MICP_MIC_CTLR_AICS + bool # Hidden + default y if BT_MICP_MIC_CTLR_MAX_AICS_INST > 0 + help + This hidden option makes it possible to easily check if AICS is + enabled for MICP client. + +endif # BT_MICP_MIC_CTLR diff --git a/components/bt/esp_ble_audio/Kconfig/Kconfig.mpl.in b/components/bt/esp_ble_audio/Kconfig/Kconfig.mpl.in new file mode 100644 index 0000000000..c50f4f868f --- /dev/null +++ b/components/bt/esp_ble_audio/Kconfig/Kconfig.mpl.in @@ -0,0 +1,110 @@ +# Bluetooth Audio - Media player configuration options + +# +# SPDX-FileCopyrightText: 2022 Nordic Semiconductor +# +# SPDX-License-Identifier: Apache-2.0 +# + +config BT_MPL + bool "Support for media player" + help + Enables support for media player + Note that the provided media player is a sample that only provides a + mock-up with no actual media being played. + For real media playback, the sample must be extended, hooked up to a + real media player or replaced with a real media player. + +if BT_MPL + + config BT_MPL_MEDIA_PLAYER_NAME + string "Media Player Name" + default "Player0" + help + Use this option to set the name of the media player. + + config BT_MPL_MEDIA_PLAYER_NAME_MAX + int "Max length of media player name" + default 20 + range 1 255 + help + Sets the maximum number of bytes (including the null termination) of + the name of the media player. + + config BT_MPL_ICON_URL + string "Media player Icon URL" + default "http://server.some.where/path/icon.png" + help + Use this option to set the URL of the Media Player Icon. + + config BT_MPL_ICON_URL_MAX + int "Max length of media player icon URL" + default 40 + range 1 255 + help + Sets the maximum number of bytes (including the null termination) of + the media player icon URL. + + config BT_MPL_TRACK_TITLE_MAX + int "Max length of the title of a track" + default 40 + range 1 255 + help + Sets the maximum number of bytes (including the null termination) of + the title of any track in the media player. + + config BT_MPL_SEGMENT_NAME_MAX + int "Max length of the name of a track segment" + default 25 + range 1 255 + help + Sets the maximum number of bytes (including the null termination) + of the name of any track segment in the media player. + + config BT_MPL_GROUP_TITLE_MAX + int "Max length of the title of a group of tracks" + default BT_MPL_TRACK_TITLE_MAX + range 1 255 + help + Sets the maximum number of bytes (including the null termination) of + the title of any group in the media player. + + config BT_MPL_OBJECTS + bool "Support for media player objects" + depends on BT_OTS + # TODO: Temporarily depends also on BT_MCS, to avoid issues with the + # bt_mcs_get_ots() call + depends on BT_MCS + # OTS shall be instantiated as a Secondary Service and shall be + # included in MCS or GMCS. + help + Enables support for objects in the media player + Objects are used to give/get more information about e.g. media tracks. + Requires the Object Transfer Service + + if BT_MPL_OBJECTS + + config BT_MPL_MAX_OBJ_SIZE + int "Total memory size to use for storing the content of objects" + default 127 + range 0 65536 + help + Sets the total memory size (in octets) to use for storing the content of objects. + This is used for the total memory pool buffer size from which memory + is allocated when sending object content. + + config BT_MPL_ICON_BITMAP_SIZE + int "Media player Icon bitmap object size" + default 127 + help + This option sets the maximum size (in octets) of the icon object. + + config BT_MPL_TRACK_MAX_SIZE + int "Maximum size for a track object" + default 127 + help + This option sets the maximum size (in octets) of a track object. + + endif # BT_MPL_OBJECTS + +endif # BT_MPL diff --git a/components/bt/esp_ble_audio/Kconfig/Kconfig.pacs.in b/components/bt/esp_ble_audio/Kconfig/Kconfig.pacs.in new file mode 100644 index 0000000000..99a3181d5f --- /dev/null +++ b/components/bt/esp_ble_audio/Kconfig/Kconfig.pacs.in @@ -0,0 +1,87 @@ +# Bluetooth Audio - Published Audio Capabilities configuration options +# +# SPDX-FileCopyrightText: 2022 Nordic Semiconductor ASA + +# SPDX-License-Identifier: Apache-2.0 +# + +config BT_PAC_SNK + bool "Sink PAC Characteristic Support" + help + This option enables support for Sink Published Audio Capabilities. + +if BT_PAC_SNK + + config BT_PAC_SNK_NOTIFIABLE + bool "Sink PAC Notifiable Support" + help + This option enables support for clients to be notified on the Sink + PAC Characteristic changes. + + config BT_PAC_SNK_LOC + bool "Sink PAC Location Support" + default y + help + This option enables support for Sink PAC Location Characteristic. + + config BT_PAC_SNK_LOC_WRITEABLE + bool "Sink PAC Location Writable Support" + depends on BT_PAC_SNK_LOC + help + This option enables support for clients to write to the Sink PAC + Location Characteristic. + + config BT_PAC_SNK_LOC_NOTIFIABLE + bool "Sink Audio Location Notifiable Support" + depends on BT_PAC_SNK_LOC + help + This option enables support for clients to be notified on the Sink + Audio Location Characteristic changes. + +endif # BT_PACS_SNK + +config BT_PAC_SRC + bool "Source PAC Characteristic Support" + help + This option enables support for Source Published Audio Capabilities. + +if BT_PAC_SRC + + config BT_PAC_SRC_NOTIFIABLE + bool "Source PAC Notifiable Support" + help + This option enables support for clients to be notified on the Source + PAC Characteristic changes. + + config BT_PAC_SRC_LOC + bool "Source PAC Location Support" + default y + help + This option enables support for Source PAC Location Characteristic. + + config BT_PAC_SRC_LOC_WRITEABLE + bool "Source PAC Location Writable Support" + depends on BT_PAC_SRC_LOC + help + This option enables support for clients to write to the Source PAC + Location Characteristic. + + config BT_PAC_SRC_LOC_NOTIFIABLE + bool "Source Audio Location Notifiable Support" + depends on BT_PAC_SRC_LOC + help + This option enables support for clients to be notified on the Source + Audio Location Characteristic changes. + +endif # BT_PAC_SRC + +config BT_PACS + bool # hidden + default y if BT_PAC_SNK || BT_PAC_SRC + +config BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE + bool "Supported Audio Context Notifiable Support" + depends on BT_PACS + help + This option enables support for clients to be notified on the + Supported Audio Contexts Characteristic changes. diff --git a/components/bt/esp_ble_audio/Kconfig/Kconfig.pbp.in b/components/bt/esp_ble_audio/Kconfig/Kconfig.pbp.in new file mode 100644 index 0000000000..84b34c5394 --- /dev/null +++ b/components/bt/esp_ble_audio/Kconfig/Kconfig.pbp.in @@ -0,0 +1,11 @@ +# Bluetooth Audio - Public Broadcast Profile (PBP) options +# +# SPDX-FileCopyrightText: 2023 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +config BT_PBP + bool "Public Broadcast Profile" + help + Enabling this will enable PBP. diff --git a/components/bt/esp_ble_audio/Kconfig/Kconfig.tbs.in b/components/bt/esp_ble_audio/Kconfig/Kconfig.tbs.in new file mode 100644 index 0000000000..c9ad16b89d --- /dev/null +++ b/components/bt/esp_ble_audio/Kconfig/Kconfig.tbs.in @@ -0,0 +1,252 @@ +# Bluetooth Audio - Call control configuration options +# +# SPDX-FileCopyrightText: 2020 Bose Corporation +# SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +##################### Telephone Bearer Service ##################### + +config BT_TBS + bool "Telephone Bearer Service Support" + select BT_AUDIO + help + This option enables support for Telephone Bearer Service. By default this only + initializes the GTBS service. If specific TBS services are wanted, they need to be + enabled by setting BT_TBS_BEARER_COUNT to a non-zero value. + +if BT_TBS + + config BT_TBS_SUPPORTED_FEATURES + int "Telephone Bearer Service Supported Features" + default 1 + range 0 3 + help + Bitfield to set supported features of the bearer. + Bit 0: Local Hold and Retrieve + Bit 1: Join calls within Telephone Bearer Service + + config BT_TBS_MAX_CALLS + int "Telephone Bearer Service Maximum Number Of Calls Supported" + default 3 + range 1 16 + help + Sets the maximum number of calls the service supports per bearer. + + config BT_TBS_BEARER_COUNT + int "How many bearer instances the device instantiates" + default 0 + range 0 255 + help + Sets the number of TBS instances that are instantiated + + config BT_TBS_MAX_SCHEME_LIST_LENGTH + int "The maximum length of the URI scheme list" + default 30 + range 0 512 + help + Sets the maximum length of the URI scheme list. + +endif # BT_TBS + +##################### Call Control Client ##################### + +config BT_TBS_CLIENT_GTBS + bool "Generic Telephone Bearer Service client support" + help + This option enables support for the GTBS-oriented Call Control client. + +config BT_TBS_CLIENT_TBS + bool "Telephone Bearer Service client support" + help + This option enables support for the TBS-oriented Call Control client. + +config BT_TBS_CLIENT + bool # hidden + default y if BT_TBS_CLIENT_GTBS || BT_TBS_CLIENT_TBS + select BT_AUDIO + +if BT_TBS_CLIENT + + config BT_TBS_CLIENT_MAX_CALLS + int "Maximum Number Of Calls Supported" + default 1 + help + Sets the maximum number of calls the client supports per TBS instance. + + config BT_TBS_CLIENT_MAX_TBS_INSTANCES + int "Maximum number of TBS instances to setup" + depends on BT_TBS_CLIENT_TBS + default 1 + range 1 3 + help + Sets the maximum number of Telephone Bearer Service (TBS) + instances to setup and use. + + config BT_TBS_CLIENT_MINIMAL + bool "Minimal TBS Client without optional procedures" + default n + help + This option disables all optional procedures in the TBS Client. + + config BT_TBS_CLIENT_BEARER_PROVIDER_NAME + bool "Support reading Bearer Provider Name" + default y if !BT_TBS_CLIENT_MINIMAL + help + This option enables support for reading Bearer Provider Name. + + config BT_TBS_CLIENT_BEARER_UCI + bool "Support reading Bearer UCI" + default y if !BT_TBS_CLIENT_MINIMAL + help + This option enables support for reading Bearer UCI. + + config BT_TBS_CLIENT_BEARER_TECHNOLOGY + bool "Support reading Bearer Technology" + default y if !BT_TBS_CLIENT_MINIMAL + help + This option enables support for reading Bearer Technology. + + config BT_TBS_CLIENT_BEARER_URI_SCHEMES_SUPPORTED_LIST + bool "Support reading Bearer URI Schemes Supported List" + default y if !BT_TBS_CLIENT_MINIMAL + help + This option enables support for reading Bearer URI Schemes Supported + List. + + config BT_TBS_CLIENT_BEARER_SIGNAL_STRENGTH + bool "Support reading Bearer Signal Strength" + default y if !BT_TBS_CLIENT_MINIMAL + help + This option enables support for reading Bearer Signal Strength. + + config BT_TBS_CLIENT_READ_BEARER_SIGNAL_INTERVAL + bool "Support reading Bearer Signal Strength Reporting Interval" + default y if !BT_TBS_CLIENT_MINIMAL + help + This option enables support for reading Bearer Signal Strength + Reporting Interval. + + config BT_TBS_CLIENT_SET_BEARER_SIGNAL_INTERVAL + bool "Support setting Bearer Signal Strength Reporting Interval" + default y if !BT_TBS_CLIENT_MINIMAL + help + This option enables support for setting Bearer Signal Strength + Reporting Interval. + + config BT_TBS_CLIENT_BEARER_LIST_CURRENT_CALLS + bool "Support reading Bearer List Current Calls" + default y if !BT_TBS_CLIENT_MINIMAL + help + This option enables support for reading Bearer List Current Calls. + + config BT_TBS_CLIENT_CCID + bool "Support reading Content Control ID" + default y if !BT_TBS_CLIENT_MINIMAL + help + This option enables support for reading Content Control ID. + + config BT_TBS_CLIENT_INCOMING_URI + bool "Support reading Incoming Call Target Bearer URI" + default y if !BT_TBS_CLIENT_MINIMAL + help + This option enables support for reading Incoming Call Target Bearer + URI. + + config BT_TBS_CLIENT_STATUS_FLAGS + bool "Support reading Status Flags" + default y if !BT_TBS_CLIENT_MINIMAL + help + This option enables support for reading Status Flags. + + config BT_TBS_CLIENT_CP_PROCEDURES + bool # hidden + default y + depends on (BT_TBS_CLIENT_ACCEPT_CALL || \ + BT_TBS_CLIENT_TERMINATE_CALL || \ + BT_TBS_CLIENT_HOLD_CALL || \ + BT_TBS_CLIENT_RETRIEVE_CALL || \ + BT_TBS_CLIENT_ORIGINATE_CALL || \ + BT_TBS_CLIENT_JOIN_CALLS) + help + This hidden option indicates that there are at least one control + point procedure available. + When this option is disabled it indicates that the control point can + be optimized away. + + config BT_TBS_CLIENT_ACCEPT_CALL + bool "Support Accept Call" + default y if !BT_TBS_CLIENT_MINIMAL + help + This option enables support for answering an incoming call. + + config BT_TBS_CLIENT_TERMINATE_CALL + bool "Support Terminate Call" + default y if !BT_TBS_CLIENT_MINIMAL + help + This option enables support for terminating a call. + + config BT_TBS_CLIENT_HOLD_CALL + bool "Support Hold Call" + default y if !BT_TBS_CLIENT_MINIMAL + help + This option enables support for putting a call on hold. + + config BT_TBS_CLIENT_RETRIEVE_CALL + bool "Support Retrieve Call" + default y if !BT_TBS_CLIENT_MINIMAL + help + This option enables support for retrieving a call on hold. + + config BT_TBS_CLIENT_ORIGINATE_CALL + bool "Support Originate Call" + default y if !BT_TBS_CLIENT_MINIMAL + help + This option enables support for originating a call. + + config BT_TBS_CLIENT_JOIN_CALLS + bool "Support Join Calls" + depends on BT_TBS_CLIENT_MAX_CALLS > 1 + default y if !BT_TBS_CLIENT_MINIMAL + help + This option enables support for joining calls. + + config BT_TBS_CLIENT_OPTIONAL_OPCODES + bool "Support reading Optional Opcodes" + default y if !BT_TBS_CLIENT_MINIMAL + help + This option enables support for reading Optional Opcodes. + + config BT_TBS_CLIENT_INCOMING_CALL + bool "Support reading Incoming Call" + default y if !BT_TBS_CLIENT_MINIMAL + help + This option enables support for reading Incoming Call. + + config BT_TBS_CLIENT_CALL_FRIENDLY_NAME + bool "Support reading Call Friendly Name" + default y if !BT_TBS_CLIENT_MINIMAL + help + This option enables support for reading Call Friendly Name. + +endif # BT_TBS_CLIENT + +if BT_TBS || BT_TBS_CLIENT + + config BT_TBS_MAX_URI_LENGTH + int "The maximum length of the call URI supported" + default 30 + range 4 253 + help + Sets the maximum length of the call URI supported. Note that if this + value is lower than a call URI, the call request will be rejected. + + config BT_TBS_MAX_PROVIDER_NAME_LENGTH + int "The maximum length of the bearer provider name" + default 30 + range 1 512 + help + Sets the maximum length of the bearer provider name. + +endif # BT_TBS || BT_TBS_CLIENT diff --git a/components/bt/esp_ble_audio/Kconfig/Kconfig.tmap.in b/components/bt/esp_ble_audio/Kconfig/Kconfig.tmap.in new file mode 100644 index 0000000000..fdb2c64b21 --- /dev/null +++ b/components/bt/esp_ble_audio/Kconfig/Kconfig.tmap.in @@ -0,0 +1,38 @@ +# Bluetooth Audio - Telephony and Media Audio Profile (TMAP) options +# +# SPDX-FileCopyrightText: 2023 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# +config BT_TMAP_CG_SUPPORTED + bool # hidden + default y if (BT_CAP_INITIATOR && BT_CAP_COMMANDER && BT_BAP_UNICAST_CLIENT && \ + BT_BAP_UNICAST_CLIENT_ASE_SRC > 0 && BT_BAP_UNICAST_CLIENT_ASE_SNK > 0 && \ + BT_VCP_VOL_CTLR && BT_TBS) + +config BT_TMAP_CT_SUPPORTED + bool # hidden + default y if BT_CAP_ACCEPTOR && (BT_ASCS_ASE_SNK > 0 || BT_ASCS_ASE_SRC > 0) + +config BT_TMAP_UMS_SUPPORTED + bool # hidden + default y if (BT_CAP_INITIATOR && BT_CAP_COMMANDER && BT_BAP_UNICAST_CLIENT && \ + BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 && BT_VCP_VOL_CTLR && BT_MCS) + +config BT_TMAP_UMR_SUPPORTED + bool # hidden + default y if BT_CAP_ACCEPTOR && BT_ASCS_ASE_SNK > 0 && BT_VCP_VOL_REND + +config BT_TMAP_BMS_SUPPORTED + bool # hidden + default y if BT_CAP_INITIATOR && BT_BAP_BROADCAST_SOURCE + +config BT_TMAP_BMR_SUPPORTED + bool # hidden + default y if BT_CAP_ACCEPTOR && BT_BAP_BROADCAST_SINK && BT_VCP_VOL_REND + +config BT_TMAP + bool "Telephony and Media Audio Profile" + depends on BT_CAP_ACCEPTOR || BT_CAP_INITIATOR + help + Enabling this will enable TMAP. diff --git a/components/bt/esp_ble_audio/Kconfig/Kconfig.vcp.in b/components/bt/esp_ble_audio/Kconfig/Kconfig.vcp.in new file mode 100644 index 0000000000..d08c9054c7 --- /dev/null +++ b/components/bt/esp_ble_audio/Kconfig/Kconfig.vcp.in @@ -0,0 +1,97 @@ +# Bluetooth Audio - Volume Control Profile configuration options +# +# SPDX-FileCopyrightText: 2020 Bose Corporation +# SPDX-FileCopyrightText: 2020-2022 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +################### Volume Control Profile Volume Renderer ################### + +config BT_VCP_VOL_REND + bool "Volume Control Profile Volume Renderer Support" + help + This option enables support for Volume Control Profile Volume Renderer + role and the Volume Control Service. + +if BT_VCP_VOL_REND + + config BT_VCP_VOL_REND_VOCS_INSTANCE_COUNT + int "Volume Offset Control Service instance count" + default 0 + range 0 BT_VOCS_MAX_INSTANCE_COUNT + help + This option sets the number of instances of Volume Offset Control + Services. + + config BT_VCP_VOL_REND_VOCS + bool # Hidden + default y if BT_VCP_VOL_REND_VOCS_INSTANCE_COUNT > 0 + help + This hidden option makes it possible to easily check if VOCS is + enabled for VCS. + + config BT_VCP_VOL_REND_AICS_INSTANCE_COUNT + int "Audio Input Control Service instance count for VCS" + default 0 + range 0 BT_AICS_MAX_INSTANCE_COUNT + help + This option sets the number of instances of Audio Input Control + Services for VCS. + + config BT_VCP_VOL_REND_AICS + bool # Hidden + default y if BT_VCP_VOL_REND_AICS_INSTANCE_COUNT > 0 + help + This hidden option makes it possible to easily check if AICS is + enabled for VCS. + + config BT_VCP_VOL_REND_VOL_FLAGS_NOTIFIABLE + bool "Volume Flags notifiable support" + help + This option enables support for clients to subscribe for notifications + on the Volume Flags characteristic. + +endif # BT_VCP_VOL_REND + +################### Volume Control Profile Volume Controller ################### + +config BT_VCP_VOL_CTLR + bool "Volume Control Profile Volume Controller Support" + help + This option enables support for Volume Control Profile Volume + Controller. + +if BT_VCP_VOL_CTLR + + config BT_VCP_VOL_CTLR_MAX_VOCS_INST + int "Maximum number of VOCS instances to setup" + default 0 + range 0 BT_VOCS_CLIENT_MAX_INSTANCE_COUNT + help + Sets the maximum number of Volume Offset Control Service (VOCS) + instances to setup and use. + + config BT_VCP_VOL_CTLR_VOCS + bool # Hidden + default y if BT_VCP_VOL_CTLR_MAX_VOCS_INST > 0 + help + This hidden option makes it possible to easily check if VOCS is + enabled for VCS client. + + config BT_VCP_VOL_CTLR_MAX_AICS_INST + int "Maximum number of AICS instances to setup" + default 0 + range 0 3 + help + Sets the maximum number of Audio Input Control Service (AICS) + instances to setup and use. + + config BT_VCP_VOL_CTLR_AICS + bool # Hidden + default y if BT_VCP_VOL_CTLR_MAX_AICS_INST > 0 + help + This hidden option makes it possible to easily check if AICS is + enabled for VCS client. + +endif # BT_VCP_VOL_CTLR diff --git a/components/bt/esp_ble_audio/Kconfig/Kconfig.vocs.in b/components/bt/esp_ble_audio/Kconfig/Kconfig.vocs.in new file mode 100644 index 0000000000..3ce8ae30e1 --- /dev/null +++ b/components/bt/esp_ble_audio/Kconfig/Kconfig.vocs.in @@ -0,0 +1,49 @@ +# Bluetooth Audio - Volume Offset Control Service options +# +# SPDX-FileCopyrightText: 2020 Bose Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +##################### Volume Offset Control Service ##################### + +config BT_VOCS_MAX_INSTANCE_COUNT + int "Volume Offset Control Service max instance count" + default 0 + range 0 15 + help + This option sets the maximum number of instances of Volume Offset + Control Services. + +config BT_VOCS + bool # hidden + default y if BT_VOCS_MAX_INSTANCE_COUNT > 0 + help + This hidden option enables support for Volume Control Service. + +if BT_VOCS + + config BT_VOCS_MAX_OUTPUT_DESCRIPTION_SIZE + int "Volume Offset Control Service max output description size" + default 32 + range 0 512 + help + This option sets the maximum output description size in octets. + +endif # BT_VOCS + +##################### Volume Offset Control Service Client ##################### + +config BT_VOCS_CLIENT_MAX_INSTANCE_COUNT + int "Volume Offset Control Service client max instance count" + default 0 + range 0 15 + help + This option sets the maximum number of instances of Volume Offset + Control Service clients. + +config BT_VOCS_CLIENT + bool # hidden + default y if BT_VOCS_CLIENT_MAX_INSTANCE_COUNT > 0 + help + This hidden option enables support for Volume Offset Control Service. diff --git a/components/bt/esp_ble_audio/api/audio/esp_ble_audio_aics_api.c b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_aics_api.c new file mode 100644 index 0000000000..4105ffc1a9 --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_aics_api.c @@ -0,0 +1,359 @@ +/* + * SPDX-FileCopyrightText: 2020-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_ble_audio_aics_api.h" + +#if CONFIG_BT_AICS +esp_ble_audio_aics_t *esp_ble_audio_aics_free_instance_get(void) +{ + return bt_aics_free_instance_get_safe(); +} + +void *esp_ble_audio_aics_svc_decl_get(esp_ble_audio_aics_t *aics) +{ + if (aics == NULL) { + return NULL; + } + + return bt_aics_svc_decl_get_safe(aics); +} + +esp_err_t esp_ble_audio_aics_register(esp_ble_audio_aics_t *aics, + esp_ble_audio_aics_register_param_t *param) +{ + int err; + + if (aics == NULL || param == NULL) { + return ESP_ERR_INVALID_ARG; + } + + if (param->mute > ESP_BLE_AUDIO_AICS_STATE_MUTE_DISABLED || + param->gain_mode > ESP_BLE_AUDIO_AICS_MODE_AUTO || + param->type > ESP_BLE_AUDIO_AICS_INPUT_TYPE_AMBIENT || + param->units == 0 || + param->min_gain > param->max_gain || + param->gain < param->min_gain || + param->gain > param->max_gain) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_aics_register_safe(aics, param); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_aics_activate(esp_ble_audio_aics_t *inst) +{ + int err; + + if (inst == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_aics_activate_safe(inst); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_aics_deactivate(esp_ble_audio_aics_t *inst) +{ + int err; + + if (inst == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_aics_deactivate_safe(inst); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_AICS */ + +#if CONFIG_BT_AICS || CONFIG_BT_AICS_CLIENT +esp_err_t esp_ble_audio_aics_state_get(esp_ble_audio_aics_t *inst) +{ + int err; + + if (inst == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_aics_state_get_safe(inst); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_aics_gain_setting_get(esp_ble_audio_aics_t *inst) +{ + int err; + + if (inst == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_aics_gain_setting_get_safe(inst); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_aics_type_get(esp_ble_audio_aics_t *inst) +{ + int err; + + if (inst == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_aics_type_get_safe(inst); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_aics_status_get(esp_ble_audio_aics_t *inst) +{ + int err; + + if (inst == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_aics_status_get_safe(inst); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_aics_disable_mute(esp_ble_audio_aics_t *inst) +{ + int err; + + if (inst == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_aics_disable_mute_safe(inst); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_aics_unmute(esp_ble_audio_aics_t *inst) +{ + int err; + + if (inst == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_aics_unmute_safe(inst); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_aics_mute(esp_ble_audio_aics_t *inst) +{ + int err; + + if (inst == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_aics_mute_safe(inst); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_aics_gain_set_manual_only(esp_ble_audio_aics_t *inst) +{ + int err; + + if (inst == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_aics_gain_set_manual_only_safe(inst); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_aics_gain_set_auto_only(esp_ble_audio_aics_t *inst) +{ + int err; + + if (inst == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_aics_gain_set_auto_only_safe(inst); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_aics_manual_gain_set(esp_ble_audio_aics_t *inst) +{ + int err; + + if (inst == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_aics_manual_gain_set_safe(inst); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_aics_automatic_gain_set(esp_ble_audio_aics_t *inst) +{ + int err; + + if (inst == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_aics_automatic_gain_set_safe(inst); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_aics_gain_set(esp_ble_audio_aics_t *inst, int8_t gain) +{ + int err; + + if (inst == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_aics_gain_set_safe(inst, gain); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_aics_description_get(esp_ble_audio_aics_t *inst) +{ + int err; + + if (inst == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_aics_description_get_safe(inst); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_aics_description_set(esp_ble_audio_aics_t *inst, + const char *description) +{ + int err; + + if (inst == NULL || description == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_aics_description_set_safe(inst, description); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_AICS || CONFIG_BT_AICS_CLIENT */ + +#if CONFIG_BT_AICS_CLIENT +esp_err_t esp_ble_audio_aics_discover(uint16_t conn_handle, esp_ble_audio_aics_t *inst, + const esp_ble_audio_aics_discover_param_t *param) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + if (inst == NULL || param == NULL || + param->end_handle <= param->start_handle) { + return ESP_ERR_INVALID_ARG; + } + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_aics_discover(conn, inst, param); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_ble_audio_aics_t *esp_ble_audio_aics_client_free_instance_get(void) +{ + return bt_aics_client_free_instance_get_safe(); +} + +esp_err_t esp_ble_audio_aics_client_cb_register(esp_ble_audio_aics_t *inst, + esp_ble_audio_aics_cb_t *cb) +{ + if (inst == NULL) { + return ESP_ERR_INVALID_ARG; + } + + bt_aics_client_cb_register_safe(inst, cb); + + return ESP_OK; +} +#endif /* CONFIG_BT_AICS_CLIENT */ diff --git a/components/bt/esp_ble_audio/api/audio/esp_ble_audio_bap_api.c b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_bap_api.c new file mode 100644 index 0000000000..11e512c293 --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_bap_api.c @@ -0,0 +1,1426 @@ +/* + * SPDX-FileCopyrightText: 2020 Bose Corporation + * SPDX-FileCopyrightText: 2021-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_ble_audio_bap_api.h" + +#if CONFIG_BT_BAP_UNICAST_SERVER +esp_err_t esp_ble_audio_bap_unicast_server_register(const esp_ble_audio_bap_unicast_server_register_param_t *param) +{ + int err; + + if (param == NULL || + param->snk_cnt > CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT || + param->src_cnt > CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT || + (param->snk_cnt == 0 && param->src_cnt == 0)) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_unicast_server_register_safe(param); + if (err) { + return ESP_FAIL; + } + +#if BLE_AUDIO_SVC_SEP_ADD + err = bt_le_ascs_init(); + if (err) { + bt_bap_unicast_server_unregister_safe(); + return ESP_FAIL; + } +#endif /* BLE_AUDIO_SVC_SEP_ADD */ + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_unicast_server_unregister(void) +{ + int err; + + err = bt_bap_unicast_server_unregister_safe(); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_unicast_server_register_cb(const esp_ble_audio_bap_unicast_server_cb_t *cb) +{ + int err; + + if (cb == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_unicast_server_register_cb_safe(cb); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_unicast_server_unregister_cb(const esp_ble_audio_bap_unicast_server_cb_t *cb) +{ + int err; + + if (cb == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_unicast_server_unregister_cb_safe(cb); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_unicast_server_config_ase(uint16_t conn_handle, + esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_codec_cfg_t *codec_cfg, + const esp_ble_audio_bap_qos_cfg_pref_t *qos_pref) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + if (stream == NULL || codec_cfg == NULL || qos_pref == NULL) { + return ESP_ERR_INVALID_ARG; + } + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_bap_unicast_server_config_ase(conn, stream, codec_cfg, qos_pref); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_BAP_UNICAST_SERVER */ + +#if CONFIG_BT_BAP_UNICAST_CLIENT +esp_err_t esp_ble_audio_bap_unicast_group_create(esp_ble_audio_bap_unicast_group_param_t *param, + esp_ble_audio_bap_unicast_group_t **unicast_group) +{ + int err; + + if (param == NULL || unicast_group == NULL || + param->params == NULL || + param->params_count == 0 || + param->params_count > CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_unicast_group_create_safe(param, unicast_group); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_unicast_group_reconfig(esp_ble_audio_bap_unicast_group_t *unicast_group, + const esp_ble_audio_bap_unicast_group_param_t *param) +{ + int err; + + if (unicast_group == NULL || param == NULL || + param->params_count > CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_unicast_group_reconfig_safe(unicast_group, param); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_unicast_group_add_streams(esp_ble_audio_bap_unicast_group_t *unicast_group, + esp_ble_audio_bap_unicast_group_stream_pair_param_t params[], + size_t num_param) +{ + int err; + + if (unicast_group == NULL || params == NULL || num_param == 0) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_unicast_group_add_streams_safe(unicast_group, params, num_param); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_unicast_group_delete(esp_ble_audio_bap_unicast_group_t *unicast_group) +{ + int err; + + if (unicast_group == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_unicast_group_delete_safe(unicast_group); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_unicast_client_register_cb(esp_ble_audio_bap_unicast_client_cb_t *cb) +{ + int err; + + if (cb == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_unicast_client_register_cb_safe(cb); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_unicast_client_unregister_cb(esp_ble_audio_bap_unicast_client_cb_t *cb) +{ + int err; + + if (cb == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_unicast_client_unregister_cb_safe(cb); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_unicast_client_discover(uint16_t conn_handle, esp_ble_audio_dir_t dir) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_bap_unicast_client_discover(conn, dir); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_bap_stream_config(uint16_t conn_handle, + esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_bap_ep_t *ep, + esp_ble_audio_codec_cfg_t *codec_cfg) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + if (stream == NULL || ep == NULL || codec_cfg == NULL) { + return ESP_ERR_INVALID_ARG; + } + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_bap_stream_config(conn, stream, ep, codec_cfg); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_bap_stream_qos(uint16_t conn_handle, + esp_ble_audio_bap_unicast_group_t *group) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + if (group == NULL) { + return ESP_ERR_INVALID_ARG; + } + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_bap_stream_qos(conn, group); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_bap_stream_enable(esp_ble_audio_bap_stream_t *stream, + const uint8_t meta[], size_t meta_len) +{ + int err; + + if (stream == NULL || stream->ep == NULL || + stream->conn == NULL || meta == NULL || meta_len == 0) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_stream_enable_safe(stream, meta, meta_len); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_stream_connect(esp_ble_audio_bap_stream_t *stream) +{ + int err; + + if (stream == NULL || stream->ep == NULL || stream->conn == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_stream_connect_safe(stream); + if (err) { + return (err == -EALREADY) ? ESP_OK : ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_stream_stop(esp_ble_audio_bap_stream_t *stream) +{ + int err; + + if (stream == NULL || stream->ep == NULL || stream->conn == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_stream_stop_safe(stream); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_BAP_UNICAST_CLIENT */ + +#if CONFIG_BT_BAP_UNICAST +esp_err_t esp_ble_audio_bap_stream_reconfig(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_codec_cfg_t *codec_cfg) +{ + int err; + + if (stream == NULL || stream->ep == NULL || + stream->conn == NULL || codec_cfg == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_stream_reconfig_safe(stream, codec_cfg); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_stream_metadata(esp_ble_audio_bap_stream_t *stream, + const uint8_t meta[], size_t meta_len) +{ + int err; + + if (stream == NULL || stream->ep == NULL || + stream->conn == NULL || meta == NULL || meta_len == 0) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_stream_metadata_safe(stream, meta, meta_len); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_stream_disable(esp_ble_audio_bap_stream_t *stream) +{ + int err; + + if (stream == NULL || stream->ep == NULL || stream->conn == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_stream_disable_safe(stream); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_stream_start(esp_ble_audio_bap_stream_t *stream) +{ + int err; + + if (stream == NULL || stream->ep == NULL || stream->conn == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_stream_start_safe(stream); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_stream_release(esp_ble_audio_bap_stream_t *stream) +{ + int err; + + if (stream == NULL || stream->ep == NULL || stream->conn == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_stream_release_safe(stream); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_BAP_UNICAST */ + +#if CONFIG_BT_BAP_BROADCAST_SOURCE +esp_err_t esp_ble_audio_bap_broadcast_source_register_cb(esp_ble_audio_bap_broadcast_source_cb_t *cb) +{ + int err; + + if (cb == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_broadcast_source_register_cb_safe(cb); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_broadcast_source_unregister_cb(esp_ble_audio_bap_broadcast_source_cb_t *cb) +{ + int err; + + if (cb == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_broadcast_source_unregister_cb_safe(cb); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_broadcast_source_create(esp_ble_audio_bap_broadcast_source_param_t *param, + esp_ble_audio_bap_broadcast_source_t **source) +{ + int err; + + if (param == NULL || source == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_broadcast_source_create_safe(param, source); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_broadcast_source_reconfig(esp_ble_audio_bap_broadcast_source_t *source, + esp_ble_audio_bap_broadcast_source_param_t *param) +{ + int err; + + if (source == NULL || param == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_broadcast_source_reconfig_safe(source, param); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_broadcast_source_update_metadata(esp_ble_audio_bap_broadcast_source_t *source, + const uint8_t meta[], size_t meta_len) +{ + int err; + + if (source == NULL || meta == NULL || meta_len == 0) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_broadcast_source_update_metadata_safe(source, meta, meta_len); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_broadcast_adv_add(esp_ble_audio_bap_broadcast_adv_info_t *info) +{ + if (info == NULL) { + return ESP_ERR_INVALID_ARG; + } + + return esp_ble_iso_big_ext_adv_add(info); +} + +esp_err_t esp_ble_audio_bap_broadcast_adv_delete(esp_ble_audio_bap_broadcast_adv_info_t *info) +{ + if (info == NULL) { + return ESP_ERR_INVALID_ARG; + } + + return esp_ble_iso_big_ext_adv_delete(info); +} + +esp_err_t esp_ble_audio_bap_broadcast_source_start(esp_ble_audio_bap_broadcast_source_t *source, + uint8_t adv_handle) +{ + esp_err_t ret = ESP_OK; + void *adv; + int err; + + if (source == NULL) { + return ESP_ERR_INVALID_ARG; + } + + bt_le_host_lock(); + + adv = bt_le_ext_adv_find(adv_handle); + if (adv == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_bap_broadcast_source_start(source, adv); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_bap_broadcast_source_stop(esp_ble_audio_bap_broadcast_source_t *source) +{ + int err; + + if (source == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_broadcast_source_stop_safe(source); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_broadcast_source_delete(esp_ble_audio_bap_broadcast_source_t *source) +{ + int err; + + if (source == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_broadcast_source_delete_safe(source); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_broadcast_source_get_base(esp_ble_audio_bap_broadcast_source_t *source, + struct net_buf_simple *base_buf) +{ + int err; + + if (source == NULL || base_buf == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_broadcast_source_get_base_safe(source, base_buf); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */ + +#if CONFIG_BT_BAP_BROADCAST_SINK +esp_err_t esp_ble_audio_bap_broadcast_sink_register_cb(esp_ble_audio_bap_broadcast_sink_cb_t *cb) +{ + int err; + + if (cb == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_broadcast_sink_register_cb_safe(cb); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_broadcast_sink_create(uint16_t sync_handle, + uint32_t broadcast_id, + esp_ble_audio_bap_broadcast_sink_t **sink) +{ + void *per_adv_sync; + int err; + + if (broadcast_id > ESP_BLE_AUDIO_BROADCAST_ID_MAX || sink == NULL) { + return ESP_ERR_INVALID_ARG; + } + + per_adv_sync = bt_le_per_adv_sync_find_safe(sync_handle); + if (per_adv_sync == NULL) { + return ESP_ERR_NOT_FOUND; + } + + err = bt_bap_broadcast_sink_create_safe(per_adv_sync, broadcast_id, sink); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_broadcast_sink_sync(esp_ble_audio_bap_broadcast_sink_t *sink, + uint32_t indexes_bitfield, + esp_ble_audio_bap_stream_t *streams[], + const uint8_t broadcast_code[ESP_BLE_ISO_BROADCAST_CODE_SIZE]) +{ + int err; + + if (sink == NULL || indexes_bitfield == 0U || + indexes_bitfield > BIT_MASK(ESP_BLE_ISO_BIS_INDEX_MAX) || streams == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_broadcast_sink_sync_safe(sink, indexes_bitfield, streams, broadcast_code); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_broadcast_sink_stop(esp_ble_audio_bap_broadcast_sink_t *sink) +{ + int err; + + if (sink == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_broadcast_sink_stop_safe(sink); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_broadcast_sink_delete(esp_ble_audio_bap_broadcast_sink_t *sink) +{ + int err; + + if (sink == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_broadcast_sink_delete_safe(sink); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_BAP_BROADCAST_SINK */ + +#if CONFIG_BT_BAP_SCAN_DELEGATOR +esp_err_t esp_ble_audio_bap_scan_delegator_register(esp_ble_audio_bap_scan_delegator_cb_t *cb) +{ + int err; + + err = bt_bap_scan_delegator_register_safe(cb); + if (err) { + return ESP_FAIL; + } + +#if BLE_AUDIO_SVC_SEP_ADD + err = bt_le_bass_init(); + if (err) { + bt_bap_scan_delegator_unregister_safe(); + return ESP_FAIL; + } +#endif /* BLE_AUDIO_SVC_SEP_ADD */ + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_scan_delegator_unregister(void) +{ + int err; + + err = bt_bap_scan_delegator_unregister_safe(); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_scan_delegator_set_pa_state(uint8_t src_id, + esp_ble_audio_bap_pa_state_t pa_state) +{ + int err; + + err = bt_bap_scan_delegator_set_pa_state_safe(src_id, pa_state); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_scan_delegator_set_bis_sync_state(uint8_t src_id, + uint32_t bis_synced[CONFIG_BT_BAP_BASS_MAX_SUBGROUPS]) +{ + int err; + + if (bis_synced == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_scan_delegator_set_bis_sync_state_safe(src_id, bis_synced); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_scan_delegator_add_src(const esp_ble_audio_bap_scan_delegator_add_src_param_t *param, + uint8_t *src_id) +{ + int ret; + + if (param == NULL || src_id == NULL || + param->broadcast_id > ESP_BLE_AUDIO_BROADCAST_ID_MAX || + param->addr.type > BT_ADDR_LE_RANDOM || + param->sid > BT_GAP_SID_MAX || + param->pa_state > ESP_BLE_AUDIO_BAP_PA_STATE_NO_PAST || + param->encrypt_state > ESP_BLE_AUDIO_BAP_BIG_ENC_STATE_BAD_CODE || + param->num_subgroups > CONFIG_BT_BAP_BASS_MAX_SUBGROUPS) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_bap_scan_delegator_add_src_safe(param); + if (ret < 0) { + return ESP_FAIL; + } + + *src_id = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_scan_delegator_mod_src(const esp_ble_audio_bap_scan_delegator_mod_src_param_t *param) +{ + int err; + + if (param == NULL || + param->broadcast_id > ESP_BLE_AUDIO_BROADCAST_ID_MAX || + param->num_subgroups > CONFIG_BT_BAP_BASS_MAX_SUBGROUPS) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_scan_delegator_mod_src_safe(param); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_scan_delegator_rem_src(uint8_t src_id) +{ + int err; + + err = bt_bap_scan_delegator_rem_src_safe(src_id); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_BAP_SCAN_DELEGATOR */ + +#if CONFIG_BT_BAP_BROADCAST_ASSISTANT +esp_err_t esp_ble_audio_bap_broadcast_assistant_discover(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_bap_broadcast_assistant_discover(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_bap_broadcast_assistant_scan_start(uint16_t conn_handle, bool start_scan) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_bap_broadcast_assistant_scan_start(conn, start_scan); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_bap_broadcast_assistant_scan_stop(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_bap_broadcast_assistant_scan_stop(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_bap_broadcast_assistant_register_cb(esp_ble_audio_bap_broadcast_assistant_cb_t *cb) +{ + int err; + + if (cb == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_broadcast_assistant_register_cb_safe(cb); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_broadcast_assistant_unregister_cb(esp_ble_audio_bap_broadcast_assistant_cb_t *cb) +{ + int err; + + if (cb == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_broadcast_assistant_unregister_cb_safe(cb); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_broadcast_assistant_add_src(uint16_t conn_handle, + const esp_ble_audio_bap_broadcast_assistant_add_src_param_t *param) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + if (param == NULL || + param->broadcast_id > ESP_BLE_AUDIO_BROADCAST_ID_MAX || + param->addr.type > BT_ADDR_LE_RANDOM || + param->adv_sid > BT_GAP_SID_MAX || + param->num_subgroups > CONFIG_BT_BAP_BASS_MAX_SUBGROUPS) { + return ESP_ERR_INVALID_ARG; + } + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_bap_broadcast_assistant_add_src(conn, param); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_bap_broadcast_assistant_mod_src(uint16_t conn_handle, + const esp_ble_audio_bap_broadcast_assistant_mod_src_param_t *param) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + if (param == NULL || + param->num_subgroups > CONFIG_BT_BAP_BASS_MAX_SUBGROUPS) { + return ESP_ERR_INVALID_ARG; + } + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_bap_broadcast_assistant_mod_src(conn, param); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_bap_broadcast_assistant_set_broadcast_code(uint16_t conn_handle, uint8_t src_id, + const uint8_t broadcast_code[ESP_BLE_ISO_BROADCAST_CODE_SIZE]) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + if (broadcast_code == NULL) { + return ESP_ERR_INVALID_ARG; + } + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_bap_broadcast_assistant_set_broadcast_code(conn, src_id, broadcast_code); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_bap_broadcast_assistant_rem_src(uint16_t conn_handle, uint8_t src_id) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_bap_broadcast_assistant_rem_src(conn, src_id); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_bap_broadcast_assistant_read_recv_state(uint16_t conn_handle, uint8_t idx) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_bap_broadcast_assistant_read_recv_state(conn, idx); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_BAP_BROADCAST_ASSISTANT */ + +#if CONFIG_BT_BAP_STREAM +esp_err_t esp_ble_audio_bap_ep_get_info(const esp_ble_audio_bap_ep_t *ep, + esp_ble_audio_bap_ep_info_t *info) +{ + int err; + + if (ep == NULL || info == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_ep_get_info_safe(ep, info); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_stream_cb_register(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_bap_stream_ops_t *ops) +{ + if (stream == NULL || ops == NULL) { + return ESP_ERR_INVALID_ARG; + } + + bt_bap_stream_cb_register_safe(stream, ops); + + return ESP_OK; +} +#endif /* CONFIG_BT_BAP_STREAM */ + +#if CONFIG_BT_AUDIO_TX +esp_err_t esp_ble_audio_bap_stream_send(esp_ble_audio_bap_stream_t *stream, + const uint8_t *sdu, uint16_t sdu_len, + uint16_t seq_num) +{ + struct net_buf buf = { + /* Note: only data and len are used */ + .data = (void *)sdu, + .len = sdu_len, + }; + int err; + + if (stream == NULL || (!sdu ^ !sdu_len)) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_stream_send_safe(stream, &buf, seq_num); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_stream_send_ts(esp_ble_audio_bap_stream_t *stream, + const uint8_t *sdu, uint16_t sdu_len, + uint16_t seq_num, uint32_t ts) +{ + struct net_buf buf = { + /* Note: only data and len are used */ + .data = (void *)sdu, + .len = sdu_len, + }; + int err; + + if (stream == NULL || (!sdu ^ !sdu_len)) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_stream_send_ts_safe(stream, &buf, seq_num, ts); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_stream_get_tx_sync(esp_ble_audio_bap_stream_t *stream, + esp_ble_iso_tx_info_t *info) +{ + int err; + + if (stream == NULL || info == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_stream_get_tx_sync_safe(stream, info); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_AUDIO_TX */ + +#if CONFIG_BT_BAP_BASE +const esp_ble_audio_bap_base_t * +esp_ble_audio_bap_base_get_base_from_ad(uint8_t data_type, const uint8_t *data, uint8_t data_len) +{ + struct bt_data ad = { + .type = data_type, + .data = data, + .data_len = data_len, + }; + + if (data_type != BT_DATA_SVC_DATA16 || data == NULL || data_len == 0) { + return NULL; + } + + return bt_bap_base_get_base_from_ad(&ad); +} + +esp_err_t esp_ble_audio_bap_base_get_size(const esp_ble_audio_bap_base_t *base, + size_t *base_size) +{ + int ret; + + if (base == NULL || base_size == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_bap_base_get_size(base); + if (ret < 0) { + return ESP_FAIL; + } + + *base_size = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_base_get_pres_delay(const esp_ble_audio_bap_base_t *base, + uint32_t *pres_delay) +{ + int ret; + + if (base == NULL || pres_delay == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_bap_base_get_pres_delay(base); + if (ret < 0) { + return ESP_FAIL; + } + + *pres_delay = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_base_get_subgroup_count(const esp_ble_audio_bap_base_t *base, + uint8_t *subgroup_count) +{ + int ret; + + if (base == NULL || subgroup_count == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_bap_base_get_subgroup_count(base); + if (ret < 0) { + return ESP_FAIL; + } + + *subgroup_count = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_base_get_bis_indexes(const esp_ble_audio_bap_base_t *base, + uint32_t *bis_indexes) +{ + int err; + + if (base == NULL || bis_indexes == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_base_get_bis_indexes(base, bis_indexes); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_base_foreach_subgroup(const esp_ble_audio_bap_base_t *base, + bool (*func)(const esp_ble_audio_bap_base_subgroup_t *subgroup, + void *user_data), + void *user_data) +{ + int err; + + if (base == NULL || func == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_base_foreach_subgroup(base, func, user_data); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_base_get_subgroup_codec_id(const esp_ble_audio_bap_base_subgroup_t *subgroup, + esp_ble_audio_bap_base_codec_id_t *codec_id) +{ + int err; + + if (subgroup == NULL || codec_id == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_base_get_subgroup_codec_id(subgroup, codec_id); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_base_get_subgroup_codec_data(const esp_ble_audio_bap_base_subgroup_t *subgroup, + uint8_t **data) +{ + int err; + + if (subgroup == NULL || data == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_base_get_subgroup_codec_data(subgroup, data); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_base_get_subgroup_codec_meta(const esp_ble_audio_bap_base_subgroup_t *subgroup, + uint8_t **meta) +{ + int err; + + if (subgroup == NULL || meta == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_base_get_subgroup_codec_meta(subgroup, meta); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_base_subgroup_codec_to_codec_cfg(const esp_ble_audio_bap_base_subgroup_t *subgroup, + esp_ble_audio_codec_cfg_t *codec_cfg) +{ + int err; + + if (subgroup == NULL || codec_cfg == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_base_subgroup_codec_to_codec_cfg(subgroup, codec_cfg); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_base_get_subgroup_bis_count(const esp_ble_audio_bap_base_subgroup_t *subgroup, + uint8_t *bis_count) +{ + int ret; + + if (subgroup == NULL || bis_count == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_bap_base_get_subgroup_bis_count(subgroup); + if (ret < 0) { + return ESP_FAIL; + } + + *bis_count = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_base_subgroup_get_bis_indexes(const esp_ble_audio_bap_base_subgroup_t *subgroup, + uint32_t *bis_indexes) +{ + int err; + + if (subgroup == NULL || bis_indexes == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_base_subgroup_get_bis_indexes(subgroup, bis_indexes); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_base_subgroup_foreach_bis(const esp_ble_audio_bap_base_subgroup_t *subgroup, + bool (*func)(const esp_ble_audio_bap_base_subgroup_bis_t *bis, + void *user_data), + void *user_data) +{ + int err; + + if (subgroup == NULL || func == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_base_subgroup_foreach_bis(subgroup, func, user_data); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_bap_base_subgroup_bis_codec_to_codec_cfg(const esp_ble_audio_bap_base_subgroup_bis_t *bis, + esp_ble_audio_codec_cfg_t *codec_cfg) +{ + int err; + + if (bis == NULL || codec_cfg == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_bap_base_subgroup_bis_codec_to_codec_cfg(bis, codec_cfg); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_BAP_BASE */ diff --git a/components/bt/esp_ble_audio/api/audio/esp_ble_audio_cap_api.c b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_cap_api.c new file mode 100644 index 0000000000..25f60ee7dc --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_cap_api.c @@ -0,0 +1,722 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_ble_audio_cap_api.h" + +#if CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER +esp_err_t esp_ble_audio_cap_acceptor_register(const esp_ble_audio_csip_set_member_register_param_t *param, + esp_ble_audio_csip_set_member_svc_inst_t **svc_inst) +{ + int err; + + if (param == NULL || svc_inst == NULL) { + return ESP_ERR_INVALID_ARG; + } + + if (param->lockable && param->rank == 0) { + /* Rank cannot be 0 if service is lockable */ + return ESP_ERR_INVALID_ARG; + } + + if (param->rank > param->set_size) { + /* Invalid rank (shall be less than or equal to set_size */ + return ESP_ERR_INVALID_ARG; + } + +#if CONFIG_BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT > 1 + if (param->parent == NULL) { + /* Parent service not provided */ + return ESP_ERR_INVALID_ARG; + } +#endif /* CONFIG_BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT > 1 */ + + err = bt_cap_acceptor_register_safe(param, svc_inst); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER */ + +#if CONFIG_BT_CAP +esp_err_t esp_ble_audio_cap_stream_ops_register(esp_ble_audio_cap_stream_t *stream, + esp_ble_audio_bap_stream_ops_t *ops) +{ + if (stream == NULL || ops == NULL) { + return ESP_ERR_INVALID_ARG; + } + + bt_cap_stream_ops_register_safe(stream, ops); + + return ESP_OK; +} + +#if CONFIG_BT_AUDIO_TX +esp_err_t esp_ble_audio_cap_stream_send(esp_ble_audio_cap_stream_t *stream, + const uint8_t *sdu, uint16_t sdu_len, + uint16_t seq_num) +{ + struct net_buf buf = { + /* Note: only data and len are used */ + .data = (void *)sdu, + .len = sdu_len, + }; + int err; + + if (stream == NULL || (!sdu ^ !sdu_len)) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_cap_stream_send_safe(stream, &buf, seq_num); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_cap_stream_send_ts(esp_ble_audio_cap_stream_t *stream, + const uint8_t *sdu, uint16_t sdu_len, + uint16_t seq_num, uint32_t ts) +{ + struct net_buf buf = { + /* Note: only data and len are used */ + .data = (void *)sdu, + .len = sdu_len, + }; + int err; + + if (stream == NULL || (!sdu ^ !sdu_len)) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_cap_stream_send_ts_safe(stream, &buf, seq_num, ts); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_cap_stream_get_tx_sync(esp_ble_audio_cap_stream_t *stream, + esp_ble_iso_tx_info_t *info) +{ + int err; + + if (stream == NULL || info == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_cap_stream_get_tx_sync_safe(stream, info); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_AUDIO_TX */ +#endif /* CONFIG_BT_CAP */ + +#if CONFIG_BT_BAP_UNICAST_CLIENT +esp_err_t esp_ble_audio_cap_unicast_group_create(const esp_ble_audio_cap_unicast_group_param_t *param, + esp_ble_audio_cap_unicast_group_t **unicast_group) +{ + int err; + + if (param == NULL || unicast_group == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_cap_unicast_group_create_safe(param, unicast_group); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_cap_unicast_group_reconfig(esp_ble_audio_cap_unicast_group_t *unicast_group, + const esp_ble_audio_cap_unicast_group_param_t *param) +{ + int err; + + if (unicast_group == NULL || param == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_cap_unicast_group_reconfig_safe(unicast_group, param); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_cap_unicast_group_add_streams(esp_ble_audio_cap_unicast_group_t *unicast_group, + const esp_ble_audio_cap_unicast_group_stream_pair_param_t params[], + size_t num_param) +{ + int err; + + if (unicast_group == NULL || params == NULL || num_param == 0) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_cap_unicast_group_add_streams_safe(unicast_group, params, num_param); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_cap_unicast_group_delete(esp_ble_audio_cap_unicast_group_t *unicast_group) +{ + int err; + + if (unicast_group == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_cap_unicast_group_delete_safe(unicast_group); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_BAP_UNICAST_CLIENT */ + +#if CONFIG_BT_CAP_INITIATOR +esp_err_t esp_ble_audio_cap_initiator_register_cb(const esp_ble_audio_cap_initiator_cb_t *cb) +{ + int err; + + if (cb == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_cap_initiator_register_cb_safe(cb); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_cap_initiator_unregister_cb(const esp_ble_audio_cap_initiator_cb_t *cb) +{ + int err; + + if (cb == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_cap_initiator_unregister_cb_safe(cb); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +#if CONFIG_BT_BAP_UNICAST_CLIENT +esp_err_t esp_ble_audio_cap_initiator_unicast_discover(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_cap_initiator_unicast_discover(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_cap_initiator_unicast_audio_start(const esp_ble_audio_cap_unicast_audio_start_param_t *param) +{ + int err; + + if (param == NULL || param->count == 0 || param->stream_params == NULL || + param->count > CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_cap_initiator_unicast_audio_start_safe(param); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_cap_initiator_unicast_audio_update(const esp_ble_audio_cap_unicast_audio_update_param_t *param) +{ + int err; + + if (param == NULL || param->count == 0 || param->stream_params == NULL || + param->count > CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_cap_initiator_unicast_audio_update_safe(param); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_cap_initiator_unicast_audio_stop(const esp_ble_audio_cap_unicast_audio_stop_param_t *param) +{ + int err; + + if (param == NULL || param->count == 0 || param->streams == NULL || + param->count > CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_cap_initiator_unicast_audio_stop_safe(param); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_cap_initiator_unicast_audio_cancel(void) +{ + int err; + + err = bt_cap_initiator_unicast_audio_cancel_safe(); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_BAP_UNICAST_CLIENT */ + +#if CONFIG_BT_BAP_BROADCAST_SOURCE +esp_err_t esp_ble_audio_cap_initiator_broadcast_audio_create(const esp_ble_audio_cap_initiator_broadcast_create_param_t *param, + esp_ble_audio_cap_broadcast_source_t **broadcast_source) +{ + int err; + + if (param == NULL || broadcast_source == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_cap_initiator_broadcast_audio_create_safe(param, broadcast_source); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_cap_initiator_broadcast_audio_start(esp_ble_audio_cap_broadcast_source_t *broadcast_source, + uint8_t adv_handle) +{ + esp_err_t ret = ESP_OK; + void *adv; + int err; + + if (broadcast_source == NULL) { + return ESP_ERR_INVALID_ARG; + } + + bt_le_host_lock(); + + adv = bt_le_ext_adv_find(adv_handle); + if (adv == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_cap_initiator_broadcast_audio_start(broadcast_source, adv); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_cap_initiator_broadcast_audio_update(esp_ble_audio_cap_broadcast_source_t *broadcast_source, + const uint8_t meta[], size_t meta_len) +{ + int err; + + if (broadcast_source == NULL || meta == NULL || meta_len == 0) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_cap_initiator_broadcast_audio_update_safe(broadcast_source, meta, meta_len); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_cap_initiator_broadcast_audio_stop(esp_ble_audio_cap_broadcast_source_t *broadcast_source) +{ + int err; + + if (broadcast_source == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_cap_initiator_broadcast_audio_stop_safe(broadcast_source); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_cap_initiator_broadcast_audio_delete(esp_ble_audio_cap_broadcast_source_t *broadcast_source) +{ + int err; + + if (broadcast_source == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_cap_initiator_broadcast_audio_delete_safe(broadcast_source); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_cap_initiator_broadcast_get_base(esp_ble_audio_cap_broadcast_source_t *broadcast_source, + struct net_buf_simple *base_buf) +{ + int err; + + if (broadcast_source == NULL || base_buf == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_cap_initiator_broadcast_get_base_safe(broadcast_source, base_buf); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */ +#endif /* CONFIG_BT_CAP_INITIATOR */ + +#if CONFIG_BT_CAP_HANDOVER +esp_err_t esp_ble_audio_cap_handover_register_cb(const esp_ble_audio_cap_handover_cb_t *cb) +{ + int err; + + if (cb == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_cap_handover_register_cb_safe(cb); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_cap_handover_unregister_cb(const esp_ble_audio_cap_handover_cb_t *cb) +{ + int err; + + if (cb == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_cap_handover_unregister_cb_safe(cb); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_cap_handover_unicast_to_broadcast( + const esp_ble_audio_cap_handover_unicast_to_broadcast_param_t *param) +{ + int err; + + if (param == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_cap_handover_unicast_to_broadcast_safe(param); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_cap_handover_broadcast_to_unicast( + const esp_ble_audio_cap_handover_broadcast_to_unicast_param_t *param) +{ + int err; + + if (param == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_cap_handover_broadcast_to_unicast_safe(param); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_CAP_HANDOVER */ + +#if CONFIG_BT_CAP_COMMANDER +esp_err_t esp_ble_audio_cap_commander_register_cb(const esp_ble_audio_cap_commander_cb_t *cb) +{ + int err; + + if (cb == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_cap_commander_register_cb_safe(cb); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_cap_commander_unregister_cb(const esp_ble_audio_cap_commander_cb_t *cb) +{ + int err; + + if (cb == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_cap_commander_unregister_cb_safe(cb); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_cap_commander_discover(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_cap_commander_discover(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_cap_commander_cancel(void) +{ + int err; + + err = bt_cap_commander_cancel_safe(); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +#if CONFIG_BT_BAP_BROADCAST_ASSISTANT +esp_err_t esp_ble_audio_cap_commander_broadcast_reception_start( + const esp_ble_audio_cap_commander_broadcast_reception_start_param_t *param) +{ + int err; + + if (param == NULL || param->count == 0 || + param->count > CONFIG_BT_MAX_CONN || param->param == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_cap_commander_broadcast_reception_start_safe(param); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_cap_commander_broadcast_reception_stop( + const esp_ble_audio_cap_commander_broadcast_reception_stop_param_t *param) +{ + int err; + + if (param == NULL || param->count == 0 || + param->count > CONFIG_BT_MAX_CONN || param->param == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_cap_commander_broadcast_reception_stop_safe(param); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_cap_commander_distribute_broadcast_code( + const esp_ble_audio_cap_commander_distribute_broadcast_code_param_t *param) +{ + int err; + + if (param == NULL || param->count == 0 || + param->count > CONFIG_BT_MAX_CONN || param->param == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_cap_commander_distribute_broadcast_code_safe(param); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_BAP_BROADCAST_ASSISTANT */ + +#if CONFIG_BT_VCP_VOL_CTLR +esp_err_t esp_ble_audio_cap_commander_change_volume( + const esp_ble_audio_cap_commander_change_volume_param_t *param) +{ + int err; + + if (param == NULL || param->count == 0 || + param->count > CONFIG_BT_MAX_CONN || param->members == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_cap_commander_change_volume_safe(param); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +#if CONFIG_BT_VCP_VOL_CTLR_VOCS +esp_err_t esp_ble_audio_cap_commander_change_volume_offset( + const esp_ble_audio_cap_commander_change_volume_offset_param_t *param) +{ + int err; + + if (param == NULL || param->count == 0 || + param->count > CONFIG_BT_MAX_CONN || param->param == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_cap_commander_change_volume_offset_safe(param); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */ + +esp_err_t esp_ble_audio_cap_commander_change_volume_mute_state( + const esp_ble_audio_cap_commander_change_volume_mute_state_param_t *param) +{ + int err; + + if (param == NULL || param->count == 0 || + param->count > CONFIG_BT_MAX_CONN || param->members == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_cap_commander_change_volume_mute_state_safe(param); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_VCP_VOL_CTLR */ + +#if CONFIG_BT_MICP_MIC_CTLR +esp_err_t esp_ble_audio_cap_commander_change_microphone_mute_state( + const esp_ble_audio_cap_commander_change_microphone_mute_state_param_t *param) +{ + int err; + + if (param == NULL || param->count == 0 || + param->count > CONFIG_BT_MAX_CONN || param->members == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_cap_commander_change_microphone_mute_state_safe(param); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +#if CONFIG_BT_MICP_MIC_CTLR_AICS +esp_err_t esp_ble_audio_cap_commander_change_microphone_gain_setting( + const esp_ble_audio_cap_commander_change_microphone_gain_setting_param_t *param) +{ + int err; + + if (param == NULL || param->count == 0 || + param->count > CONFIG_BT_MAX_CONN || param->param == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_cap_commander_change_microphone_gain_setting_safe(param); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */ +#endif /* CONFIG_BT_MICP_MIC_CTLR */ +#endif /* CONFIG_BT_CAP_COMMANDER */ diff --git a/components/bt/esp_ble_audio/api/audio/esp_ble_audio_ccp_api.c b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_ccp_api.c new file mode 100644 index 0000000000..222d91b529 --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_ccp_api.c @@ -0,0 +1,181 @@ +/* + * SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_ble_audio_ccp_api.h" + +#if CONFIG_BT_CCP_CALL_CONTROL_SERVER +esp_err_t esp_ble_audio_ccp_call_control_server_register_bearer( + const esp_ble_audio_tbs_register_param_t *param, + esp_ble_audio_ccp_call_control_server_bearer_t **bearer) +{ + esp_err_t err; + + if (param == NULL || bearer == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_ccp_call_control_server_register_bearer_safe(param, bearer); + if (err) { + /* Map Zephyr error codes to ESP-IDF error codes */ + switch (err) { + case -EINVAL: + return ESP_ERR_INVALID_ARG; + case -ENOMEM: + return ESP_ERR_NO_MEM; + case -EALREADY: + return ESP_ERR_INVALID_STATE; + case -EAGAIN: + return ESP_ERR_INVALID_STATE; + default: + return ESP_FAIL; + } + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_ccp_call_control_server_unregister_bearer( + esp_ble_audio_ccp_call_control_server_bearer_t *bearer) +{ + esp_err_t err; + + if (bearer == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_ccp_call_control_server_unregister_bearer_safe(bearer); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_ccp_call_control_server_set_bearer_provider_name( + esp_ble_audio_ccp_call_control_server_bearer_t *bearer, const char *name) +{ + esp_err_t err; + + if (bearer == NULL || name == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_ccp_call_control_server_set_bearer_provider_name_safe(bearer, name); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_ccp_call_control_server_get_bearer_provider_name( + esp_ble_audio_ccp_call_control_server_bearer_t *bearer, const char **name) +{ + esp_err_t err; + + if (bearer == NULL || name == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_ccp_call_control_server_get_bearer_provider_name_safe(bearer, name); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_CCP_CALL_CONTROL_SERVER */ + +#if CONFIG_BT_CCP_CALL_CONTROL_CLIENT +esp_err_t esp_ble_audio_ccp_call_control_client_discover( + esp_ble_conn_t *conn, esp_ble_audio_ccp_call_control_client_t **out_client) +{ + esp_err_t err; + + if (conn == NULL || out_client == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_ccp_call_control_client_discover_safe(conn, out_client); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_ccp_call_control_client_register_cb( + esp_ble_audio_ccp_call_control_client_cb_t *cb) +{ + esp_err_t err; + + if (cb == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_ccp_call_control_client_register_cb_safe(cb); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_ccp_call_control_client_unregister_cb( + esp_ble_audio_ccp_call_control_client_cb_t *cb) +{ + esp_err_t err; + + if (cb == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_ccp_call_control_client_unregister_cb_safe(cb); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_ccp_call_control_client_get_bearers( + esp_ble_audio_ccp_call_control_client_t *client, + esp_ble_audio_ccp_call_control_client_bearers_t *bearers) +{ + esp_err_t err; + + if (client == NULL || bearers == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_ccp_call_control_client_get_bearers_safe(client, bearers); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_CCP_CALL_CONTROL_CLIENT */ + +#if CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME +esp_err_t esp_ble_audio_ccp_call_control_client_read_bearer_provider_name( + esp_ble_audio_ccp_call_control_client_bearer_t *bearer) +{ + esp_err_t err; + + if (bearer == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_ccp_call_control_client_read_bearer_provider_name_safe(bearer); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME */ diff --git a/components/bt/esp_ble_audio/api/audio/esp_ble_audio_codec_api.c b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_codec_api.c new file mode 100644 index 0000000000..3dec72fa94 --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_codec_api.c @@ -0,0 +1,1714 @@ +/* + * SPDX-FileCopyrightText: 2020 Intel Corporation + * SPDX-FileCopyrightText: 2020-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "esp_ble_audio_codec_api.h" + +#if CONFIG_BT_BAP_STREAM +esp_err_t esp_ble_audio_codec_cfg_freq_to_freq_hz(esp_ble_audio_codec_cfg_freq_t freq, + uint32_t *freq_hz) +{ + int ret; + + if (freq_hz == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_freq_to_freq_hz(freq); + if (ret < 0) { + return ESP_FAIL; + } + + *freq_hz = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_freq_hz_to_freq(uint32_t freq_hz, + esp_ble_audio_codec_cfg_freq_t *freq) +{ + int ret; + + if (freq == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_freq_hz_to_freq(freq_hz); + if (ret < 0) { + return ESP_FAIL; + } + + *freq = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_get_freq(const esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_codec_cfg_freq_t *freq) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->data == NULL || freq == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_get_freq(codec_cfg); + if (ret < 0) { + return ESP_FAIL; + } + + *freq = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_set_freq(esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_codec_cfg_freq_t freq) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->data == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_set_freq(codec_cfg, freq); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_frame_dur_to_frame_dur_us(esp_ble_audio_codec_cfg_frame_dur_t frame_dur, + uint32_t *frame_dur_us) +{ + int ret; + + if (frame_dur_us == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_frame_dur_to_frame_dur_us(frame_dur); + if (ret < 0) { + return ESP_FAIL; + } + + *frame_dur_us = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_frame_dur_us_to_frame_dur(uint32_t frame_dur_us, + esp_ble_audio_codec_cfg_frame_dur_t *frame_dur) +{ + int ret; + + if (frame_dur == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_frame_dur_us_to_frame_dur(frame_dur_us); + if (ret < 0) { + return ESP_FAIL; + } + + *frame_dur = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_get_frame_dur(const esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_codec_cfg_frame_dur_t *frame_dur) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->data == NULL || frame_dur == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_get_frame_dur(codec_cfg); + if (ret < 0) { + return ESP_FAIL; + } + + *frame_dur = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_set_frame_dur(esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_codec_cfg_frame_dur_t frame_dur) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->data == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_set_frame_dur(codec_cfg, frame_dur); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_get_chan_allocation(const esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_location_t *chan_allocation, + bool fallback_to_default) +{ + int err; + + if (codec_cfg == NULL || codec_cfg->data == NULL || chan_allocation == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_audio_codec_cfg_get_chan_allocation(codec_cfg, chan_allocation, fallback_to_default); + if (err < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_set_chan_allocation(esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_location_t chan_allocation) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->data == NULL || + (chan_allocation & ESP_BLE_AUDIO_LOCATION_ANY) != chan_allocation) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_set_chan_allocation(codec_cfg, chan_allocation); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_get_octets_per_frame(const esp_ble_audio_codec_cfg_t *codec_cfg, + uint16_t *octets_per_frame) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->data == NULL || octets_per_frame == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_get_octets_per_frame(codec_cfg); + if (ret < 0) { + return ESP_FAIL; + } + + *octets_per_frame = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_set_octets_per_frame(esp_ble_audio_codec_cfg_t *codec_cfg, + uint16_t octets_per_frame) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->data == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_set_octets_per_frame(codec_cfg, octets_per_frame); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_get_frame_blocks_per_sdu(const esp_ble_audio_codec_cfg_t *codec_cfg, + uint8_t *frame_blocks, + bool fallback_to_default) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->data == NULL || frame_blocks == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, fallback_to_default); + if (ret < 0) { + return ESP_FAIL; + } + + *frame_blocks = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_set_frame_blocks_per_sdu(esp_ble_audio_codec_cfg_t *codec_cfg, + uint8_t frame_blocks) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->data == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_set_frame_blocks_per_sdu(codec_cfg, frame_blocks); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_get_val(const esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_codec_cfg_type_t type, + const uint8_t **data, size_t *data_len) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->data == NULL || + data == NULL || data_len == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_get_val(codec_cfg, type, data); + if (ret < 0) { + return ESP_FAIL; + } + + *data_len = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_set_val(esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_codec_cfg_type_t type, + const uint8_t *data, size_t data_len) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->data == NULL || + data == NULL || + data_len == 0 || data_len > UINT8_MAX) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_set_val(codec_cfg, type, data, data_len); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_unset_val(esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_codec_cfg_type_t type) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->data == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_unset_val(codec_cfg, type); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_meta_get_val(const esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_metadata_type_t type, + const uint8_t **data, size_t *data_len) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->meta == NULL || + data == NULL || data_len == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_meta_get_val(codec_cfg, type, data); + if (ret < 0) { + return ESP_FAIL; + } + + *data_len = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_meta_set_val(esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_metadata_type_t type, + const uint8_t *data, size_t data_len) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->meta == NULL || + data == NULL || + data_len == 0 || data_len > UINT8_MAX) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_meta_set_val(codec_cfg, type, data, data_len); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_meta_unset_val(esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_metadata_type_t type) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->meta == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_meta_unset_val(codec_cfg, type); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_meta_get_pref_context(const esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_context_t *ctx, + bool fallback_to_default) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->meta == NULL || ctx == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_meta_get_pref_context(codec_cfg, fallback_to_default); + if (ret < 0) { + return ESP_FAIL; + } + + *ctx = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_meta_set_pref_context(esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_context_t ctx) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->meta == NULL || + (ctx & ESP_BLE_AUDIO_CONTEXT_TYPE_ANY) != ctx) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_meta_set_pref_context(codec_cfg, ctx); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_meta_get_stream_context(const esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_context_t *ctx) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->meta == NULL || ctx == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_meta_get_stream_context(codec_cfg); + if (ret < 0) { + return ESP_FAIL; + } + + *ctx = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_meta_set_stream_context(esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_context_t ctx) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->meta == NULL || + (ctx & ESP_BLE_AUDIO_CONTEXT_TYPE_ANY) != ctx) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_meta_set_stream_context(codec_cfg, ctx); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_meta_get_program_info(const esp_ble_audio_codec_cfg_t *codec_cfg, + const uint8_t **program_info, + size_t *program_info_len) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->meta == NULL || + program_info == NULL || program_info_len == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_meta_get_program_info(codec_cfg, program_info); + if (ret < 0) { + return ESP_FAIL; + } + + *program_info_len = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_meta_set_program_info(esp_ble_audio_codec_cfg_t *codec_cfg, + const uint8_t *program_info, + size_t program_info_len) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->meta == NULL || + program_info == NULL || + program_info_len == 0 || program_info_len > UINT8_MAX) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_meta_set_program_info(codec_cfg, program_info, program_info_len); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_meta_get_language(const esp_ble_audio_codec_cfg_t *codec_cfg, + const uint8_t **language) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->meta == NULL || language == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_meta_get_lang(codec_cfg, language); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_meta_set_language(esp_ble_audio_codec_cfg_t *codec_cfg, + const uint8_t language[ESP_BLE_AUDIO_LANG_SIZE]) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->meta == NULL || language == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_meta_set_lang(codec_cfg, language); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_meta_get_ccid_list(const esp_ble_audio_codec_cfg_t *codec_cfg, + const uint8_t **ccid_list, + size_t *ccid_list_len) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->meta == NULL || + ccid_list == NULL || ccid_list_len == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_meta_get_ccid_list(codec_cfg, ccid_list); + if (ret < 0) { + return ESP_FAIL; + } + + *ccid_list_len = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_meta_set_ccid_list(esp_ble_audio_codec_cfg_t *codec_cfg, + const uint8_t *ccid_list, + size_t ccid_list_len) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->meta == NULL || + ccid_list == NULL || + ccid_list_len == 0 || ccid_list_len > UINT8_MAX) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_meta_set_ccid_list(codec_cfg, ccid_list, ccid_list_len); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_meta_get_parental_rating(const esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_parental_rating_t *parental_rating) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->meta == NULL || parental_rating == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_meta_get_parental_rating(codec_cfg); + if (ret < 0) { + return ESP_FAIL; + } + + *parental_rating = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_meta_set_parental_rating(esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_parental_rating_t parental_rating) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->meta == NULL || + parental_rating > ESP_BLE_AUDIO_PARENTAL_RATING_AGE_18_OR_ABOVE) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_meta_set_parental_rating(codec_cfg, parental_rating); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_meta_get_program_info_uri(const esp_ble_audio_codec_cfg_t *codec_cfg, + const uint8_t **program_info_uri, + size_t *program_info_uri_len) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->meta == NULL || + program_info_uri == NULL || program_info_uri_len == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_meta_get_program_info_uri(codec_cfg, program_info_uri); + if (ret < 0) { + return ESP_FAIL; + } + + *program_info_uri_len = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_meta_set_program_info_uri(esp_ble_audio_codec_cfg_t *codec_cfg, + const uint8_t *program_info_uri, + size_t program_info_uri_len) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->meta == NULL || + program_info_uri == NULL || + program_info_uri_len == 0 || program_info_uri_len > UINT8_MAX) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_meta_set_program_info_uri(codec_cfg, program_info_uri, program_info_uri_len); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_meta_get_audio_active_state(const esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_active_state_t *state) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->meta == NULL || state == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_meta_get_audio_active_state(codec_cfg); + if (ret < 0) { + return ESP_FAIL; + } + + *state = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_meta_set_audio_active_state(esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_active_state_t state) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->meta == NULL || + (state != ESP_BLE_AUDIO_ACTIVE_STATE_DISABLED && + state != ESP_BLE_AUDIO_ACTIVE_STATE_ENABLED)) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_meta_set_audio_active_state(codec_cfg, state); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_meta_get_broadcast_audio_immediate_rend_flag(const esp_ble_audio_codec_cfg_t *codec_cfg, + bool *found) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->meta == NULL || found == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_meta_get_bcast_audio_immediate_rend_flag(codec_cfg); + if (ret == 0) { + *found = true; + } else if (ret == -ENODATA) { + *found = false; + } else { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_meta_set_broadcast_audio_immediate_rend_flag(esp_ble_audio_codec_cfg_t *codec_cfg) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->meta == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_meta_set_bcast_audio_immediate_rend_flag(codec_cfg); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_meta_get_assisted_listening_stream(const esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_assisted_listening_stream_t *val) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->meta == NULL || val == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_meta_get_assisted_listening_stream(codec_cfg); + if (ret < 0) { + return ESP_FAIL; + } + + *val = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_meta_set_assisted_listening_stream(esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_assisted_listening_stream_t val) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->meta == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_meta_set_assisted_listening_stream(codec_cfg, val); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_meta_get_broadcast_name(const esp_ble_audio_codec_cfg_t *codec_cfg, + const uint8_t **broadcast_name, + size_t *broadcast_name_len) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->meta == NULL || + broadcast_name == NULL || broadcast_name_len == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_meta_get_broadcast_name(codec_cfg, broadcast_name); + if (ret < 0) { + return ESP_FAIL; + } + + *broadcast_name_len = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_meta_set_broadcast_name(esp_ble_audio_codec_cfg_t *codec_cfg, + const uint8_t *broadcast_name, + size_t broadcast_name_len) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->meta == NULL || + broadcast_name == NULL || + broadcast_name_len == 0 || broadcast_name_len > UINT8_MAX) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_meta_set_broadcast_name(codec_cfg, broadcast_name, broadcast_name_len); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_meta_get_extended(const esp_ble_audio_codec_cfg_t *codec_cfg, + const uint8_t **extended_meta, + size_t *extended_meta_len) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->meta == NULL || + extended_meta == NULL || extended_meta_len == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_meta_get_extended(codec_cfg, extended_meta); + if (ret < 0) { + return ESP_FAIL; + } + + *extended_meta_len = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_meta_set_extended(esp_ble_audio_codec_cfg_t *codec_cfg, + const uint8_t *extended_meta, + size_t extended_meta_len) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->meta == NULL || + extended_meta == NULL || + extended_meta_len == 0 || extended_meta_len > UINT8_MAX) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_meta_set_extended(codec_cfg, extended_meta, extended_meta_len); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_meta_get_vendor(const esp_ble_audio_codec_cfg_t *codec_cfg, + const uint8_t **vendor_meta, + size_t *vendor_meta_len) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->meta == NULL || + vendor_meta == NULL || vendor_meta_len == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_meta_get_vendor(codec_cfg, vendor_meta); + if (ret < 0) { + return ESP_FAIL; + } + + *vendor_meta_len = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cfg_meta_set_vendor(esp_ble_audio_codec_cfg_t *codec_cfg, + const uint8_t *vendor_meta, + size_t vendor_meta_len) +{ + int ret; + + if (codec_cfg == NULL || codec_cfg->meta == NULL || + vendor_meta == NULL || + vendor_meta_len == 0 || vendor_meta_len > UINT8_MAX) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cfg_meta_set_vendor(codec_cfg, vendor_meta, vendor_meta_len); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_get_val(const esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_codec_cap_type_t type, + const uint8_t **data, size_t *data_len) +{ + int ret; + + if (codec_cap == NULL || codec_cap->data == NULL || + data == NULL || data_len == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_get_val(codec_cap, type, data); + if (ret < 0) { + return ESP_FAIL; + } + + *data_len = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_set_val(esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_codec_cap_type_t type, + const uint8_t *data, size_t data_len) +{ + int ret; + + if (codec_cap == NULL || codec_cap->data == NULL || + data == NULL || + data_len == 0 || data_len > UINT8_MAX) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_set_val(codec_cap, type, data, data_len); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_unset_val(esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_codec_cap_type_t type) +{ + int ret; + + if (codec_cap == NULL || codec_cap->data == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_unset_val(codec_cap, type); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_get_freq(const esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_codec_cap_freq_t *freq) +{ + int ret; + + if (codec_cap == NULL || codec_cap->data == NULL || freq == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_get_freq(codec_cap); + if (ret < 0) { + return ESP_FAIL; + } + + *freq = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_set_freq(esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_codec_cap_freq_t freq) +{ + int ret; + + if (codec_cap == NULL || codec_cap->data == NULL || + (freq & ESP_BLE_AUDIO_CODEC_CAP_FREQ_ANY) != freq) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_set_freq(codec_cap, freq); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_get_frame_dur(const esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_codec_cap_frame_dur_t *frame_dur) +{ + int ret; + + if (codec_cap == NULL || codec_cap->data == NULL || frame_dur == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_get_frame_dur(codec_cap); + if (ret < 0) { + return ESP_FAIL; + } + + *frame_dur = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_set_frame_dur(esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_codec_cap_frame_dur_t frame_dur) +{ + int ret; + + if (codec_cap == NULL || codec_cap->data == NULL || + (frame_dur & ESP_BLE_AUDIO_CODEC_CAP_DURATION_ANY) == 0 || + (frame_dur & ~(ESP_BLE_AUDIO_CODEC_CAP_DURATION_ANY | + ESP_BLE_AUDIO_CODEC_CAP_DURATION_PREFER_7_5 | + ESP_BLE_AUDIO_CODEC_CAP_DURATION_PREFER_10)) != 0) { + return ESP_ERR_INVALID_ARG; + } + + if ((frame_dur & ESP_BLE_AUDIO_CODEC_CAP_DURATION_PREFER_7_5) != 0) { + if ((frame_dur & ESP_BLE_AUDIO_CODEC_CAP_DURATION_PREFER_10) != 0) { + /* Cannot prefer both 7.5 and 10ms */ + return ESP_ERR_INVALID_ARG; + } + + if ((frame_dur & ESP_BLE_AUDIO_CODEC_CAP_DURATION_7_5) == 0) { + /* Cannot prefer 7.5ms when not supported */ + return ESP_ERR_INVALID_ARG; + } + } + + if ((frame_dur & ESP_BLE_AUDIO_CODEC_CAP_DURATION_PREFER_10) != 0 && + (frame_dur & ESP_BLE_AUDIO_CODEC_CAP_DURATION_10) == 0) { + /* Cannot prefer 10ms when not supported */ + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_set_frame_dur(codec_cap, frame_dur); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_get_supported_audio_chan_counts(const esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_codec_cap_chan_count_t *chan_count, + bool fallback_to_default) +{ + int ret; + + if (codec_cap == NULL || codec_cap->data == NULL || chan_count == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_get_supported_audio_chan_counts(codec_cap, fallback_to_default); + if (ret < 0) { + return ESP_FAIL; + } + + *chan_count = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_set_supported_audio_chan_counts(esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_codec_cap_chan_count_t chan_count) +{ + int ret; + + if (codec_cap == NULL || codec_cap->data == NULL || + (chan_count & ESP_BLE_AUDIO_CODEC_CAP_CHAN_COUNT_ANY) != chan_count) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_set_supported_audio_chan_counts(codec_cap, chan_count); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_get_octets_per_frame(const esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_codec_octets_per_codec_frame_t *codec_frame) +{ + int ret; + + if (codec_cap == NULL || codec_cap->data == NULL || codec_frame == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_get_octets_per_frame(codec_cap, codec_frame); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_set_octets_per_frame(esp_ble_audio_codec_cap_t *codec_cap, + const esp_ble_audio_codec_octets_per_codec_frame_t *codec_frame) +{ + int ret; + + if (codec_cap == NULL || codec_cap->data == NULL || + codec_frame == NULL || codec_frame->min > codec_frame->max) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_set_octets_per_frame(codec_cap, codec_frame); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_get_max_codec_frames_per_sdu(const esp_ble_audio_codec_cap_t *codec_cap, + uint8_t *codec_frames_per_sdu, + bool fallback_to_default) +{ + int ret; + + if (codec_cap == NULL || codec_cap->data == NULL || codec_frames_per_sdu == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_get_max_codec_frames_per_sdu(codec_cap, fallback_to_default); + if (ret < 0) { + return ESP_FAIL; + } + + *codec_frames_per_sdu = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_set_max_codec_frames_per_sdu(esp_ble_audio_codec_cap_t *codec_cap, + uint8_t codec_frames_per_sdu) +{ + int ret; + + if (codec_cap == NULL || codec_cap->data == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_set_max_codec_frames_per_sdu(codec_cap, codec_frames_per_sdu); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_meta_get_val(const esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_metadata_type_t type, + const uint8_t **data, size_t *data_len) +{ + int ret; + + if (codec_cap == NULL || codec_cap->meta == NULL || + data == NULL || data_len == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_meta_get_val(codec_cap, type, data); + if (ret < 0) { + return ESP_FAIL; + } + + *data_len = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_meta_set_val(esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_metadata_type_t type, + const uint8_t *data, size_t data_len) +{ + int ret; + + if (codec_cap == NULL || codec_cap->meta == NULL || + data == NULL || + data_len == 0 || data_len > UINT8_MAX) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_meta_set_val(codec_cap, type, data, data_len); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_meta_unset_val(esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_metadata_type_t type) +{ + int ret; + + if (codec_cap == NULL || codec_cap->meta == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_meta_unset_val(codec_cap, type); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_meta_get_pref_context(const esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_context_t *ctx) +{ + int ret; + + if (codec_cap == NULL || codec_cap->meta == NULL || ctx == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_meta_get_pref_context(codec_cap); + if (ret < 0) { + return ESP_FAIL; + } + + *ctx = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_meta_set_pref_context(esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_context_t ctx) +{ + int ret; + + if (codec_cap == NULL || codec_cap->meta == NULL || + (ctx & ESP_BLE_AUDIO_CONTEXT_TYPE_ANY) != ctx) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_meta_set_pref_context(codec_cap, ctx); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_meta_get_stream_context(const esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_context_t *ctx) +{ + int ret; + + if (codec_cap == NULL || codec_cap->meta == NULL || ctx == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_meta_get_stream_context(codec_cap); + if (ret < 0) { + return ESP_FAIL; + } + + *ctx = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_meta_set_stream_context(esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_context_t ctx) +{ + int ret; + + if (codec_cap == NULL || codec_cap->meta == NULL || + (ctx & ESP_BLE_AUDIO_CONTEXT_TYPE_ANY) != ctx) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_meta_set_stream_context(codec_cap, ctx); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_meta_get_program_info(const esp_ble_audio_codec_cap_t *codec_cap, + const uint8_t **program_info, + size_t *program_info_len) +{ + int ret; + + if (codec_cap == NULL || codec_cap->meta == NULL || + program_info == NULL || program_info_len == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_meta_get_program_info(codec_cap, program_info); + if (ret < 0) { + return ESP_FAIL; + } + + *program_info_len = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_meta_set_program_info(esp_ble_audio_codec_cap_t *codec_cap, + const uint8_t *program_info, + size_t program_info_len) +{ + int ret; + + if (codec_cap == NULL || codec_cap->meta == NULL || + program_info == NULL || + program_info_len == 0 || program_info_len > UINT8_MAX) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_meta_set_program_info(codec_cap, program_info, program_info_len); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_meta_get_language(const esp_ble_audio_codec_cap_t *codec_cap, + const uint8_t **language) +{ + int ret; + + if (codec_cap == NULL || codec_cap->meta == NULL || language == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_meta_get_lang(codec_cap, language); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_meta_set_language(esp_ble_audio_codec_cap_t *codec_cap, + const uint8_t language[ESP_BLE_AUDIO_LANG_SIZE]) +{ + int ret; + + if (codec_cap == NULL || codec_cap->meta == NULL || language == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_meta_set_lang(codec_cap, language); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_meta_get_ccid_list(const esp_ble_audio_codec_cap_t *codec_cap, + const uint8_t **ccid_list, + size_t *ccid_list_len) +{ + int ret; + + if (codec_cap == NULL || codec_cap->meta == NULL || + ccid_list == NULL || ccid_list_len == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_meta_get_ccid_list(codec_cap, ccid_list); + if (ret < 0) { + return ESP_FAIL; + } + + *ccid_list_len = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_meta_set_ccid_list(esp_ble_audio_codec_cap_t *codec_cap, + const uint8_t *ccid_list, + size_t ccid_list_len) +{ + int ret; + + if (codec_cap == NULL || codec_cap->meta == NULL || + ccid_list == NULL || + ccid_list_len == 0 || ccid_list_len > UINT8_MAX) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_meta_set_ccid_list(codec_cap, ccid_list, ccid_list_len); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_meta_get_parental_rating(const esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_parental_rating_t *parental_rating) +{ + int ret; + + if (codec_cap == NULL || codec_cap->meta == NULL || parental_rating == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_meta_get_parental_rating(codec_cap); + if (ret < 0) { + return ESP_FAIL; + } + + *parental_rating = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_meta_set_parental_rating(esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_parental_rating_t parental_rating) +{ + int ret; + + if (codec_cap == NULL || codec_cap->meta == NULL || + parental_rating > ESP_BLE_AUDIO_PARENTAL_RATING_AGE_18_OR_ABOVE) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_meta_set_parental_rating(codec_cap, parental_rating); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_meta_get_program_info_uri(const esp_ble_audio_codec_cap_t *codec_cap, + const uint8_t **program_info_uri, + size_t *program_info_uri_len) +{ + int ret; + + if (codec_cap == NULL || codec_cap->meta == NULL || + program_info_uri == NULL || program_info_uri_len == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_meta_get_program_info_uri(codec_cap, program_info_uri); + if (ret < 0) { + return ESP_FAIL; + } + + *program_info_uri_len = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_meta_set_program_info_uri(esp_ble_audio_codec_cap_t *codec_cap, + const uint8_t *program_info_uri, + size_t program_info_uri_len) +{ + int ret; + + if (codec_cap == NULL || codec_cap->meta == NULL || + program_info_uri == NULL || + program_info_uri_len == 0 || program_info_uri_len > UINT8_MAX) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_meta_set_program_info_uri(codec_cap, program_info_uri, program_info_uri_len); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_meta_get_audio_active_state(const esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_active_state_t *state) +{ + int ret; + + if (codec_cap == NULL || codec_cap->meta == NULL || state == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_meta_get_audio_active_state(codec_cap); + if (ret < 0) { + return ESP_FAIL; + } + + *state = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_meta_set_audio_active_state(esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_active_state_t state) +{ + int ret; + + if (codec_cap == NULL || codec_cap->meta == NULL || + (state != ESP_BLE_AUDIO_ACTIVE_STATE_DISABLED && + state != ESP_BLE_AUDIO_ACTIVE_STATE_ENABLED)) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_meta_set_audio_active_state(codec_cap, state); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_meta_get_broadcast_audio_immediate_rend_flag(const esp_ble_audio_codec_cap_t *codec_cap, + bool *found) +{ + int ret; + + if (codec_cap == NULL || codec_cap->meta == NULL || found == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_meta_get_bcast_audio_immediate_rend_flag(codec_cap); + if (ret == 0) { + *found = true; + } else if (ret == -ENODATA) { + *found = false; + } else { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_meta_set_broadcast_audio_immediate_rend_flag(esp_ble_audio_codec_cap_t *codec_cap) +{ + int ret; + + if (codec_cap == NULL || codec_cap->meta == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_meta_set_bcast_audio_immediate_rend_flag(codec_cap); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_meta_get_assisted_listening_stream(const esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_assisted_listening_stream_t *val) +{ + int ret; + + if (codec_cap == NULL || codec_cap->meta == NULL || val == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_meta_get_assisted_listening_stream(codec_cap); + if (ret < 0) { + return ESP_FAIL; + } + + *val = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_meta_set_assisted_listening_stream(esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_assisted_listening_stream_t val) +{ + int ret; + + if (codec_cap == NULL || codec_cap->meta == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_meta_set_assisted_listening_stream(codec_cap, val); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_meta_get_broadcast_name(const esp_ble_audio_codec_cap_t *codec_cap, + const uint8_t **broadcast_name, + size_t *broadcast_name_len) +{ + int ret; + + if (codec_cap == NULL || codec_cap->meta == NULL || + broadcast_name == NULL || broadcast_name_len == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_meta_get_broadcast_name(codec_cap, broadcast_name); + if (ret < 0) { + return ESP_FAIL; + } + + *broadcast_name_len = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_meta_set_broadcast_name(esp_ble_audio_codec_cap_t *codec_cap, + const uint8_t *broadcast_name, + size_t broadcast_name_len) +{ + int ret; + + if (codec_cap == NULL || codec_cap->meta == NULL || + broadcast_name == NULL || + broadcast_name_len == 0 || broadcast_name_len > UINT8_MAX) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_meta_set_broadcast_name(codec_cap, broadcast_name, broadcast_name_len); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_meta_get_extended(const esp_ble_audio_codec_cap_t *codec_cap, + const uint8_t **extended_meta, + size_t *extended_meta_len) +{ + int ret; + + if (codec_cap == NULL || codec_cap->meta == NULL || + extended_meta == NULL || extended_meta_len == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_meta_get_extended(codec_cap, extended_meta); + if (ret < 0) { + return ESP_FAIL; + } + + *extended_meta_len = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_meta_set_extended(esp_ble_audio_codec_cap_t *codec_cap, + const uint8_t *extended_meta, + size_t extended_meta_len) +{ + int ret; + + if (codec_cap == NULL || codec_cap->meta == NULL || + extended_meta == NULL || + extended_meta_len == 0 || extended_meta_len > UINT8_MAX) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_meta_set_extended(codec_cap, extended_meta, extended_meta_len); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_meta_get_vendor(const esp_ble_audio_codec_cap_t *codec_cap, + const uint8_t **vendor_meta, + size_t *vendor_meta_len) +{ + int ret; + + if (codec_cap == NULL || codec_cap->meta == NULL || + vendor_meta == NULL || vendor_meta_len == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_meta_get_vendor(codec_cap, vendor_meta); + if (ret < 0) { + return ESP_FAIL; + } + + *vendor_meta_len = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_codec_cap_meta_set_vendor(esp_ble_audio_codec_cap_t *codec_cap, + const uint8_t *vendor_meta, + size_t vendor_meta_len) +{ + int ret; + + if (codec_cap == NULL || codec_cap->meta == NULL || + vendor_meta == NULL || + vendor_meta_len == 0 || vendor_meta_len > UINT8_MAX) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_codec_cap_meta_set_vendor(codec_cap, vendor_meta, vendor_meta_len); + if (ret < 0) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_BAP_STREAM */ diff --git a/components/bt/esp_ble_audio/api/audio/esp_ble_audio_common_api.c b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_common_api.c new file mode 100644 index 0000000000..d6c33b81ad --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_common_api.c @@ -0,0 +1,153 @@ +/* + * SPDX-FileCopyrightText: 2020 Intel Corporation + * SPDX-FileCopyrightText: 2020-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "esp_ble_audio_common_api.h" + +esp_err_t esp_ble_audio_data_parse(const uint8_t ltv[], size_t size, + bool (*func)(uint8_t type, + const uint8_t *data, + uint8_t data_len, + void *user_data), + void *user_data) +{ + return esp_ble_iso_data_parse(ltv, size, func, user_data); +} + +esp_err_t esp_ble_audio_data_get_val(const uint8_t ltv_data[], + size_t size, uint8_t type, + const uint8_t **data, + uint8_t *data_len) +{ + int ret; + + if (ltv_data == NULL || data == NULL || data_len == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_audio_data_get_val(ltv_data, size, type, data); + if (ret < 0) { + return ESP_FAIL; + } + + *data_len = ret; + + return ESP_OK; +} + +uint8_t esp_ble_audio_get_chan_count(esp_ble_audio_location_t chan_allocation) +{ + return bt_audio_get_chan_count(chan_allocation); +} + +esp_err_t esp_ble_audio_gattc_disc_start(uint16_t conn_handle) +{ + int err; + + err = bt_gattc_disc_start_safe(conn_handle); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +void esp_ble_audio_gap_app_post_event(uint8_t type, void *param) +{ + bt_le_gap_app_post_event(type, param); +} + +void esp_ble_audio_gatt_app_post_event(uint8_t type, void *param) +{ + bt_le_gatt_app_post_event(type, param); +} + +esp_err_t esp_ble_audio_common_init(esp_ble_audio_init_info_t *info) +{ + bool gap_cb_registered = false; + bool gatt_cb_registered = false; + int err; + + if (info) { + if (info->gap_cb) { + err = bt_le_gap_app_cb_register(info->gap_cb); + if (err) { + return ESP_FAIL; + } + + gap_cb_registered = true; + } + + if (info->gatt_cb) { + err = bt_le_gatt_app_cb_register(info->gatt_cb); + if (err) { + goto unregister_gap; + } + + gatt_cb_registered = true; + } + } + + err = bt_le_host_init(); + if (err) { + goto unregister_gatt; + } + + err = bt_le_audio_init(); + if (err) { + bt_le_host_deinit(); + goto unregister_gatt; + } + + return ESP_OK; + +unregister_gatt: + if (gatt_cb_registered) { + bt_le_gatt_app_cb_unregister(); + } +unregister_gap: + if (gap_cb_registered) { + bt_le_gap_app_cb_unregister(); + } + return ESP_FAIL; +} + +esp_err_t esp_ble_audio_common_start(esp_ble_audio_start_info_t *info) +{ + int err; + + if (info) { +#if CONFIG_BT_CSIP_SET_MEMBER + uint8_t cas_included = 0; + + for (size_t i = 0; i < ARRAY_SIZE(info->csis_insts); i++) { + if (info->csis_insts[i].svc_inst && + info->csis_insts[i].included_by_cas) { + cas_included++; + } + } + + /* From CAS Spec: + * The CAS shall include no more than one instance of CSIS. + */ + if (cas_included > 1) { + return ESP_ERR_INVALID_ARG; + } +#endif /* CONFIG_BT_CSIP_SET_MEMBER */ + } + + err = bt_le_audio_start(info); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} diff --git a/components/bt/esp_ble_audio/api/audio/esp_ble_audio_csip_api.c b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_csip_api.c new file mode 100644 index 0000000000..54b07c9db2 --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_csip_api.c @@ -0,0 +1,290 @@ +/* + * SPDX-FileCopyrightText: 2021-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_ble_audio_csip_api.h" + +#if CONFIG_BT_CSIP_SET_MEMBER +void *esp_ble_audio_csip_set_member_svc_decl_get(const esp_ble_audio_csip_set_member_svc_inst_t *svc_inst) +{ + if (svc_inst == NULL) { + return NULL; + } + + return bt_csip_set_member_svc_decl_get_safe(svc_inst); +} + +esp_err_t esp_ble_audio_csip_set_member_register(const esp_ble_audio_csip_set_member_register_param_t *param, + esp_ble_audio_csip_set_member_svc_inst_t **svc_inst) +{ + int err; + + if (param == NULL || svc_inst == NULL) { + return ESP_ERR_INVALID_ARG; + } + + if (param->lockable && param->rank == 0) { + /* Rank cannot be 0 if service is lockable */ + return ESP_ERR_INVALID_ARG; + } + + if (param->rank > param->set_size) { + /* Invalid rank (shall be less than or equal to set_size */ + return ESP_ERR_INVALID_ARG; + } + +#if CONFIG_BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT > 1 + if (param->parent == NULL) { + /* Parent service not provided */ + return ESP_ERR_INVALID_ARG; + } +#endif /* CONFIG_BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT > 1 */ + + err = bt_csip_set_member_register_safe(param, svc_inst); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_csip_set_member_unregister(esp_ble_audio_csip_set_member_svc_inst_t *svc_inst) +{ + int err; + + if (svc_inst == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_csip_set_member_unregister_safe(svc_inst); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_csip_set_member_sirk(esp_ble_audio_csip_set_member_svc_inst_t *svc_inst, + const uint8_t sirk[ESP_BLE_AUDIO_CSIP_SIRK_SIZE]) +{ + int err; + + if (svc_inst == NULL || sirk == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_csip_set_member_sirk_safe(svc_inst, sirk); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_csip_set_member_set_size_and_rank(esp_ble_audio_csip_set_member_svc_inst_t *svc_inst, + uint8_t size, uint8_t rank) +{ + int err; + + if (svc_inst == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_csip_set_member_set_size_and_rank_safe(svc_inst, size, rank); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_csip_set_member_get_info(const esp_ble_audio_csip_set_member_svc_inst_t *svc_inst, + esp_ble_audio_csip_set_member_set_info_t *info) +{ + int err; + + if (svc_inst == NULL || info == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_csip_set_member_get_info_safe(svc_inst, info); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_csip_set_member_generate_rsi(const esp_ble_audio_csip_set_member_svc_inst_t *svc_inst, + uint8_t rsi[ESP_BLE_AUDIO_CSIP_RSI_SIZE]) +{ + int err; + + if (svc_inst == NULL || rsi == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_csip_set_member_generate_rsi_safe(svc_inst, rsi); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_csip_set_member_lock(esp_ble_audio_csip_set_member_svc_inst_t *svc_inst, + bool lock, bool force) +{ + int err; + + if (svc_inst == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_csip_set_member_lock_safe(svc_inst, lock, force); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_CSIP_SET_MEMBER */ + +#if CONFIG_BT_CSIP_SET_COORDINATOR +esp_err_t esp_ble_audio_csip_set_coordinator_discover(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_csip_set_coordinator_discover(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_ble_audio_csip_set_coordinator_set_member_t * +esp_ble_audio_csip_set_coordinator_set_member_by_conn(uint16_t conn_handle) +{ + esp_ble_audio_csip_set_coordinator_set_member_t *ret = NULL; + void *conn; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + goto unlock; + } + + ret = bt_csip_set_coordinator_set_member_by_conn(conn); + +unlock: + bt_le_host_unlock(); + return ret; +} + +bool esp_ble_audio_csip_set_coordinator_is_set_member(const uint8_t sirk[ESP_BLE_AUDIO_CSIP_SIRK_SIZE], + uint8_t data_type, const uint8_t *data, uint8_t data_len) +{ + struct bt_data ad = { + .type = data_type, + .data = data, + .data_len = data_len, + }; + + if (sirk == NULL || data_type != BT_DATA_CSIS_RSI || + data == NULL || data_len != ESP_BLE_AUDIO_CSIP_RSI_SIZE) { + return false; + } + + return bt_csip_set_coordinator_is_set_member_safe(sirk, &ad); +} + +esp_err_t esp_ble_audio_csip_set_coordinator_register_cb(esp_ble_audio_csip_set_coordinator_cb_t *cb) +{ + int err; + + if (cb == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_csip_set_coordinator_register_cb_safe(cb); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_csip_set_coordinator_ordered_access(const esp_ble_audio_csip_set_coordinator_set_member_t *members[], + uint8_t count, + const esp_ble_audio_csip_set_coordinator_set_info_t *set_info, + bt_csip_set_coordinator_ordered_access_t cb) +{ + int err; + + if (members == NULL || + count == 0 || count > CONFIG_BT_MAX_CONN || + set_info == NULL || cb == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_csip_set_coordinator_ordered_access_safe(members, count, set_info, cb); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_csip_set_coordinator_lock(const esp_ble_audio_csip_set_coordinator_set_member_t **members, + uint8_t count, + const esp_ble_audio_csip_set_coordinator_set_info_t *set_info) +{ + int err; + + if (members == NULL || count > CONFIG_BT_MAX_CONN || set_info == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_csip_set_coordinator_lock_safe(members, count, set_info); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_csip_set_coordinator_release(const esp_ble_audio_csip_set_coordinator_set_member_t **members, + uint8_t count, + const esp_ble_audio_csip_set_coordinator_set_info_t *set_info) +{ + int err; + + if (members == NULL || count > CONFIG_BT_MAX_CONN || set_info == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_csip_set_coordinator_release_safe(members, count, set_info); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_CSIP_SET_COORDINATOR */ diff --git a/components/bt/esp_ble_audio/api/audio/esp_ble_audio_gmap_api.c b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_gmap_api.c new file mode 100644 index 0000000000..c6282f6107 --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_gmap_api.c @@ -0,0 +1,268 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_ble_audio_gmap_api.h" + +#if CONFIG_BT_GMAP +esp_err_t esp_ble_audio_gmap_cb_register(const esp_ble_audio_gmap_cb_t *cb) +{ + int err; + + if (cb == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_gmap_cb_register_safe(cb); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_gmap_discover(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_gmap_discover(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +#define GMAP_ROLE_MASK (ESP_BLE_AUDIO_GMAP_ROLE_UGG | \ + ESP_BLE_AUDIO_GMAP_ROLE_UGT | \ + ESP_BLE_AUDIO_GMAP_ROLE_BGS | \ + ESP_BLE_AUDIO_GMAP_ROLE_BGR) + +static bool valid_gmap_role(esp_ble_audio_gmap_role_t role) +{ + if (role == 0 || (role & GMAP_ROLE_MASK) != role) { + /* Invalid role */ + return false; + } + + if ((role & ESP_BLE_AUDIO_GMAP_ROLE_UGG) != 0 && + !IS_ENABLED(CONFIG_BT_GMAP_UGG_SUPPORTED)) { + /* Device does not support the UGG role */ + return false; + } + + if ((role & ESP_BLE_AUDIO_GMAP_ROLE_UGT) != 0 && + !IS_ENABLED(CONFIG_BT_GMAP_UGT_SUPPORTED)) { + /* Device does not support the UGT role */ + return false; + } + + if ((role & ESP_BLE_AUDIO_GMAP_ROLE_BGS) != 0 && + !IS_ENABLED(CONFIG_BT_GMAP_BGS_SUPPORTED)) { + /* Device does not support the BGS role */ + return false; + } + + if ((role & ESP_BLE_AUDIO_GMAP_ROLE_BGR) != 0 && + !IS_ENABLED(CONFIG_BT_GMAP_BGR_SUPPORTED)) { + /* Device does not support the BGR role */ + return false; + } + + return true; +} + +static bool valid_gmap_features(esp_ble_audio_gmap_role_t role, + esp_ble_audio_gmap_feat_t features) +{ +#if CONFIG_BT_GMAP_UGG_SUPPORTED + if ((role & ESP_BLE_AUDIO_GMAP_ROLE_UGG) != 0) { + esp_ble_audio_gmap_ugg_feat_t ugg_feat = features.ugg_feat; + + if ((ugg_feat & ESP_BLE_AUDIO_GMAP_UGG_FEAT_MULTIPLEX) != 0 && + CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT == 0) { + /* Cannot support ESP_BLE_AUDIO_GMAP_UGG_FEAT_MULTIPLEX with + * CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT == 0. + */ + return false; + } + + if ((ugg_feat & ESP_BLE_AUDIO_GMAP_UGG_FEAT_96KBPS_SOURCE) != 0 && + CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT == 0) { + /* Cannot support ESP_BLE_AUDIO_GMAP_UGG_FEAT_96KBPS_SOURCE with + * CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT == 0. + */ + return false; + } + + if ((ugg_feat & ESP_BLE_AUDIO_GMAP_UGG_FEAT_MULTISINK) != 0 && + (CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT < 2 || + CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT < 2)) { + /* Cannot support ESP_BLE_AUDIO_GMAP_UGG_FEAT_MULTISINK with + * CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT or + * CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT < 2. + */ + return false; + } + } +#endif /* CONFIG_BT_GMAP_UGG_SUPPORTED */ + +#if CONFIG_BT_GMAP_UGT_SUPPORTED + if ((role & ESP_BLE_AUDIO_GMAP_ROLE_UGT) != 0) { + esp_ble_audio_gmap_ugt_feat_t ugt_feat = features.ugt_feat; + esp_ble_audio_gmap_bgr_feat_t bgr_feat = features.bgr_feat; + + if ((ugt_feat & ESP_BLE_AUDIO_GMAP_UGT_FEAT_SOURCE) == 0 && + (ugt_feat & ESP_BLE_AUDIO_GMAP_UGT_FEAT_SINK) == 0) { + /* Device shall support either ESP_BLE_AUDIO_GMAP_UGT_FEAT_SOURCE or + * ESP_BLE_AUDIO_GMAP_UGT_FEAT_SINK. + */ + return false; + } + + if ((ugt_feat & ESP_BLE_AUDIO_GMAP_UGT_FEAT_SOURCE) == 0 && + ((ugt_feat & ESP_BLE_AUDIO_GMAP_UGT_FEAT_80KBPS_SOURCE) != 0 || + (ugt_feat & ESP_BLE_AUDIO_GMAP_UGT_FEAT_MULTISOURCE) != 0)) { + /* Device shall support ESP_BLE_AUDIO_GMAP_UGT_FEAT_SOURCE if + * ESP_BLE_AUDIO_GMAP_UGT_FEAT_80KBPS_SOURCE or + * ESP_BLE_AUDIO_GMAP_UGT_FEAT_MULTISOURCE is supported. + */ + return false; + } + + if ((ugt_feat & ESP_BLE_AUDIO_GMAP_UGT_FEAT_SOURCE) != 0 && + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT == 0) { + /* Cannot support ESP_BLE_AUDIO_GMAP_UGT_FEAT_SOURCE with + * CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT == 0. + */ + return false; + } + + if ((ugt_feat & ESP_BLE_AUDIO_GMAP_UGT_FEAT_MULTISOURCE) != 0 && + (CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT < 2 || + CONFIG_BT_ASCS_MAX_ACTIVE_ASES < 2)) { + /* Cannot support ESP_BLE_AUDIO_GMAP_UGT_FEAT_MULTISOURCE with + * CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT or + * CONFIG_BT_ASCS_MAX_ACTIVE_ASES < 2. + */ + return false; + } + + if ((ugt_feat & ESP_BLE_AUDIO_GMAP_UGT_FEAT_SINK) != 0 && + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT == 0) { + /* Cannot support ESP_BLE_AUDIO_GMAP_UGT_FEAT_SINK with + * CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT == 0. + */ + return false; + } + + if ((ugt_feat & ESP_BLE_AUDIO_GMAP_UGT_FEAT_SINK) == 0 && + ((ugt_feat & ESP_BLE_AUDIO_GMAP_UGT_FEAT_64KBPS_SINK) != 0 || + (ugt_feat & ESP_BLE_AUDIO_GMAP_UGT_FEAT_MULTISINK) != 0 || + (ugt_feat & ESP_BLE_AUDIO_GMAP_UGT_FEAT_MULTIPLEX) != 0)) { + /* Device shall support ESP_BLE_AUDIO_GMAP_UGT_FEAT_SINK if + * ESP_BLE_AUDIO_GMAP_UGT_FEAT_64KBPS_SINK, + * ESP_BLE_AUDIO_GMAP_UGT_FEAT_MULTISINK or + * ESP_BLE_AUDIO_GMAP_UGT_FEAT_MULTIPLEX is supported. + */ + return false; + } + + if ((ugt_feat & ESP_BLE_AUDIO_GMAP_UGT_FEAT_MULTISINK) != 0 && + (CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT < 2 || + CONFIG_BT_ASCS_MAX_ACTIVE_ASES < 2)) { + /* Cannot support ESP_BLE_AUDIO_GMAP_UGT_FEAT_MULTISINK with + * CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT or + * CONFIG_BT_ASCS_MAX_ACTIVE_ASES < 2. + */ + return false; + } + + /* If the device supports both the UGT and BGT roles, then it needs + * have the same support for multiplexing for both roles. + */ + if ((role & ESP_BLE_AUDIO_GMAP_ROLE_BGR) != 0 && + IS_ENABLED(CONFIG_BT_GMAP_BGR_SUPPORTED) && + !!(ugt_feat & ESP_BLE_AUDIO_GMAP_UGT_FEAT_MULTIPLEX) != + !!(bgr_feat & ESP_BLE_AUDIO_GMAP_BGR_FEAT_MULTIPLEX)) { + /* Device shall support ESP_BLE_AUDIO_GMAP_UGT_FEAT_MULTIPLEX if + * ESP_BLE_AUDIO_GMAP_BGR_FEAT_MULTIPLEX is supported, and vice versa. + */ + return false; + } + } +#endif /* CONFIG_BT_GMAP_UGT_SUPPORTED */ + +#if CONFIG_BT_GMAP_BGR_SUPPORTED + if ((role & ESP_BLE_AUDIO_GMAP_ROLE_BGR) != 0) { + esp_ble_audio_gmap_bgr_feat_t bgr_feat = features.bgr_feat; + + if ((bgr_feat & ESP_BLE_AUDIO_GMAP_BGR_FEAT_MULTISINK) != 0 && + CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT < 2) { + /* Cannot support ESP_BLE_AUDIO_GMAP_BGR_FEAT_MULTISINK with + * CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT < 2. + */ + return false; + } + } +#endif /* CONFIG_BT_GMAP_BGR_SUPPORTED */ + + /* If the roles are not supported, then the feature characteristics + * are not instantiated and the feature values do not need to be + * checked, as they will never be read (thus ignore by the stack). + */ + + return true; +} + +esp_err_t esp_ble_audio_gmap_register(esp_ble_audio_gmap_role_t role, + esp_ble_audio_gmap_feat_t features) +{ + int err; + + if (valid_gmap_role(role) == false || + valid_gmap_features(role, features) == false) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_gmap_register_safe(role, features); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_gmap_set_role(esp_ble_audio_gmap_role_t role, + esp_ble_audio_gmap_feat_t features) +{ + int err; + + if (valid_gmap_role(role) == false || + valid_gmap_features(role, features) == false) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_gmap_set_role_safe(role, features); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_GMAP */ diff --git a/components/bt/esp_ble_audio/api/audio/esp_ble_audio_has_api.c b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_has_api.c new file mode 100644 index 0000000000..68dd6c082e --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_has_api.c @@ -0,0 +1,281 @@ +/* + * SPDX-FileCopyrightText: 2022 Codecoup + * SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_ble_audio_has_api.h" + +#if CONFIG_BT_HAS_CLIENT +esp_err_t esp_ble_audio_has_client_cb_register(const esp_ble_audio_has_client_cb_t *cb) +{ + int err; + + if (cb == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_has_client_cb_register_safe(cb); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_has_client_discover(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_has_client_discover(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_has_client_presets_read(esp_ble_audio_has_t *has, + uint8_t index, + uint8_t max_count) +{ + int err; + + if (has == NULL || + index == ESP_BLE_AUDIO_HAS_PRESET_INDEX_NONE || + max_count == 0) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_has_client_presets_read_safe(has, index, max_count); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_has_client_preset_set(esp_ble_audio_has_t *has, + uint8_t index, bool sync) +{ + int err; + + if (has == NULL || index == ESP_BLE_AUDIO_HAS_PRESET_INDEX_NONE) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_has_client_preset_set_safe(has, index, sync); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_has_client_preset_next(esp_ble_audio_has_t *has, bool sync) +{ + int err; + + if (has == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_has_client_preset_next_safe(has, sync); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_has_client_preset_prev(esp_ble_audio_has_t *has, bool sync) +{ + int err; + + if (has == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_has_client_preset_prev_safe(has, sync); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_HAS_CLIENT */ + +#if CONFIG_BT_HAS +esp_err_t esp_ble_audio_has_register(const esp_ble_audio_has_features_param_t *features) +{ + int err; + + if (features == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_has_register_safe(features); + if (err) { + return ESP_FAIL; + } + +#if BLE_AUDIO_SVC_SEP_ADD + err = bt_le_has_init(); + if (err) { + return ESP_FAIL; + } +#endif /* BLE_AUDIO_SVC_SEP_ADD */ + + return ESP_OK; +} + +esp_err_t esp_ble_audio_has_preset_register(const esp_ble_audio_has_preset_register_param_t *param) +{ + int err; + + if (param == NULL || + param->index == ESP_BLE_AUDIO_HAS_PRESET_INDEX_NONE || + param->name == NULL || + param->ops == NULL || param->ops->select == NULL) { + return ESP_ERR_INVALID_ARG; + } + + if (strlen(param->name) < ESP_BLE_AUDIO_HAS_PRESET_NAME_MIN || + strlen(param->name) > ESP_BLE_AUDIO_HAS_PRESET_NAME_MAX) { + return ESP_ERR_INVALID_ARG; + } + + if (!IS_ENABLED(CONFIG_BT_HAS_PRESET_NAME_DYNAMIC) && + (param->properties & ESP_BLE_AUDIO_HAS_PROP_WRITABLE) > 0) { + /* Writable presets is not supported */ + return ESP_ERR_INVALID_ARG; + } + + err = bt_has_preset_register_safe(param); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_has_preset_unregister(uint8_t index) +{ + int err; + + if (index == ESP_BLE_AUDIO_HAS_PRESET_INDEX_NONE) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_has_preset_unregister_safe(index); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_has_preset_available(uint8_t index) +{ + int err; + + if (index == ESP_BLE_AUDIO_HAS_PRESET_INDEX_NONE) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_has_preset_available_safe(index); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_has_preset_unavailable(uint8_t index) +{ + int err; + + if (index == ESP_BLE_AUDIO_HAS_PRESET_INDEX_NONE) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_has_preset_unavailable_safe(index); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_has_preset_active_set(uint8_t index) +{ + int err; + + if (index == ESP_BLE_AUDIO_HAS_PRESET_INDEX_NONE) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_has_preset_active_set_safe(index); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +uint8_t esp_ble_audio_has_preset_active_get(void) +{ + return bt_has_preset_active_get_safe(); +} + +esp_err_t esp_ble_audio_has_preset_name_change(uint8_t index, const char *name) +{ + int err; + + if (index == ESP_BLE_AUDIO_HAS_PRESET_INDEX_NONE || name == NULL) { + return ESP_ERR_INVALID_ARG; + } + + if (strlen(name) < ESP_BLE_AUDIO_HAS_PRESET_NAME_MIN || + strlen(name) > ESP_BLE_AUDIO_HAS_PRESET_NAME_MAX) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_has_preset_name_change_safe(index, name); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_has_features_set(const esp_ble_audio_has_features_param_t *features) +{ + int err; + + if (features == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_has_features_set_safe(features); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_HAS */ diff --git a/components/bt/esp_ble_audio/api/audio/esp_ble_audio_mcc_api.c b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_mcc_api.c new file mode 100644 index 0000000000..7a74337411 --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_mcc_api.c @@ -0,0 +1,947 @@ +/* + * SPDX-FileCopyrightText: 2019-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_ble_audio_mcs_defs.h" +#include "esp_ble_audio_mcc_api.h" + +#if CONFIG_BT_MCC +esp_err_t esp_ble_audio_mcc_init(esp_ble_audio_mcc_cb_t *cb) +{ + int err; + + err = bt_mcc_init_safe(cb); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_mcc_discover_mcs(uint16_t conn_handle, bool subscribe) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_discover_mcs(conn, subscribe); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_mcc_read_player_name(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_read_player_name(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +#if CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL +esp_err_t esp_ble_audio_mcc_read_icon_url(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_read_icon_url(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL */ + +#if CONFIG_BT_MCC_READ_TRACK_TITLE +esp_err_t esp_ble_audio_mcc_read_track_title(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_read_track_title(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_MCC_READ_TRACK_TITLE */ + +#if CONFIG_BT_MCC_READ_TRACK_DURATION +esp_err_t esp_ble_audio_mcc_read_track_duration(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_read_track_duration(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_MCC_READ_TRACK_DURATION */ + +#if CONFIG_BT_MCC_READ_TRACK_POSITION +esp_err_t esp_ble_audio_mcc_read_track_position(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_read_track_position(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_MCC_READ_TRACK_POSITION */ + +#if CONFIG_BT_MCC_SET_TRACK_POSITION +esp_err_t esp_ble_audio_mcc_set_track_position(uint16_t conn_handle, int32_t pos) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_set_track_position(conn, pos); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_MCC_SET_TRACK_POSITION */ + +#if CONFIG_BT_MCC_READ_PLAYBACK_SPEED +esp_err_t esp_ble_audio_mcc_read_playback_speed(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_read_playback_speed(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_MCC_READ_PLAYBACK_SPEED */ + +#if CONFIG_BT_MCC_SET_PLAYBACK_SPEED +esp_err_t esp_ble_audio_mcc_set_playback_speed(uint16_t conn_handle, int8_t speed) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_set_playback_speed(conn, speed); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_MCC_SET_PLAYBACK_SPEED */ + +#if CONFIG_BT_MCC_READ_SEEKING_SPEED +esp_err_t esp_ble_audio_mcc_read_seeking_speed(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_read_seeking_speed(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_MCC_READ_SEEKING_SPEED */ + +#if CONFIG_BT_MCC_READ_PLAYING_ORDER +esp_err_t esp_ble_audio_mcc_read_playing_order(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_read_playing_order(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_MCC_READ_PLAYING_ORDER */ + +#if CONFIG_BT_MCC_SET_PLAYING_ORDER +esp_err_t esp_ble_audio_mcc_set_playing_order(uint16_t conn_handle, uint8_t order) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_set_playing_order(conn, order); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_MCC_SET_PLAYING_ORDER */ + +#if CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED +esp_err_t esp_ble_audio_mcc_read_playing_orders_supported(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_read_playing_orders_supported(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED */ + +#if CONFIG_BT_MCC_READ_MEDIA_STATE +esp_err_t esp_ble_audio_mcc_read_media_state(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_read_media_state(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_MCC_READ_MEDIA_STATE */ + +#if CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT +#define MCS_VALID_OP(opcode) \ + (IN_RANGE((opcode), ESP_BLE_AUDIO_MCS_OPC_PLAY, ESP_BLE_AUDIO_MCS_OPC_STOP) || \ + (opcode == ESP_BLE_AUDIO_MCS_OPC_MOVE_RELATIVE) || \ + IN_RANGE((opcode), ESP_BLE_AUDIO_MCS_OPC_PREV_SEGMENT, ESP_BLE_AUDIO_MCS_OPC_GOTO_SEGMENT) || \ + IN_RANGE((opcode), ESP_BLE_AUDIO_MCS_OPC_PREV_TRACK, ESP_BLE_AUDIO_MCS_OPC_GOTO_TRACK) || \ + IN_RANGE((opcode), ESP_BLE_AUDIO_MCS_OPC_PREV_GROUP, ESP_BLE_AUDIO_MCS_OPC_GOTO_GROUP)) + +esp_err_t esp_ble_audio_mcc_send_cmd(uint16_t conn_handle, + const esp_ble_audio_mpl_cmd_t *cmd) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + if (cmd == NULL || MCS_VALID_OP(cmd->opcode) == false) { + return ESP_ERR_INVALID_ARG; + } + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_send_cmd(conn, cmd); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT */ + +#if CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED +esp_err_t esp_ble_audio_mcc_read_opcodes_supported(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_read_opcodes_supported(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED */ + +#if CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID +esp_err_t esp_ble_audio_mcc_read_content_control_id(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_read_content_control_id(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID */ + +#if CONFIG_BT_MCC_OTS +esp_err_t esp_ble_audio_mcc_read_icon_obj_id(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_read_icon_obj_id(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_mcc_read_segments_obj_id(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_read_segments_obj_id(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_mcc_read_current_track_obj_id(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_read_current_track_obj_id(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_mcc_set_current_track_obj_id(uint16_t conn_handle, uint64_t id) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + if (ESP_BLE_AUDIO_MCS_VALID_OBJ_ID(id) == false) { + return ESP_ERR_INVALID_ARG; + } + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_set_current_track_obj_id(conn, id); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_mcc_read_next_track_obj_id(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_read_next_track_obj_id(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_mcc_set_next_track_obj_id(uint16_t conn_handle, uint64_t id) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + if (ESP_BLE_AUDIO_MCS_VALID_OBJ_ID(id) == false) { + return ESP_ERR_INVALID_ARG; + } + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_set_next_track_obj_id(conn, id); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_mcc_read_current_group_obj_id(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_read_current_group_obj_id(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_mcc_set_current_group_obj_id(uint16_t conn_handle, uint64_t id) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + if (ESP_BLE_AUDIO_MCS_VALID_OBJ_ID(id) == false) { + return ESP_ERR_INVALID_ARG; + } + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_set_current_group_obj_id(conn, id); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_mcc_read_parent_group_obj_id(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_read_parent_group_obj_id(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_mcc_send_search(uint16_t conn_handle, + const esp_ble_audio_mpl_search_t *search) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + if (search == NULL || IN_RANGE(search->len, + ESP_BLE_AUDIO_SEARCH_LEN_MIN, + ESP_BLE_AUDIO_SEARCH_LEN_MAX) == false) { + return ESP_ERR_INVALID_ARG; + } + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_send_search(conn, search); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_mcc_read_search_results_obj_id(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_read_search_results_obj_id(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_mcc_otc_read_object_metadata(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_otc_read_object_metadata(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_mcc_otc_read_icon_object(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_otc_read_icon_object(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_mcc_otc_read_track_segments_object(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_otc_read_track_segments_object(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_mcc_otc_read_current_track_object(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_otc_read_current_track_object(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_mcc_otc_read_next_track_object(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_otc_read_next_track_object(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_mcc_otc_read_current_group_object(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_otc_read_current_group_object(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_mcc_otc_read_parent_group_object(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_mcc_otc_read_parent_group_object(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +#if CONFIG_BT_MCC_SHELL +struct bt_ots_client *esp_ble_audio_mcc_otc_inst(uint16_t conn_handle) +{ + struct bt_ots_client *ret = NULL; + void *conn; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + goto unlock; + } + + ret = bt_mcc_otc_inst(conn); + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_MCC_SHELL */ +#endif /* CONFIG_BT_MCC_OTS */ +#endif /* CONFIG_BT_MCC */ diff --git a/components/bt/esp_ble_audio/api/audio/esp_ble_audio_media_proxy_api.c b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_media_proxy_api.c new file mode 100644 index 0000000000..9e1a37375d --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_media_proxy_api.c @@ -0,0 +1,585 @@ +/* + * SPDX-FileCopyrightText: 2019-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_ble_audio_mcs_defs.h" +#include "esp_ble_audio_media_proxy_api.h" + +#if CONFIG_BT_MCTL_LOCAL_PLAYER_LOCAL_CONTROL +esp_err_t esp_ble_audio_media_proxy_ctrl_register(esp_ble_audio_media_proxy_ctrl_cbs_t *ctrl_cbs) +{ + int err; + + if (ctrl_cbs == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_media_proxy_ctrl_register_safe(ctrl_cbs); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */ + +#if CONFIG_BT_MCTL_REMOTE_PLAYER_CONTROL +esp_err_t esp_ble_audio_media_proxy_ctrl_discover_player(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_media_proxy_ctrl_discover_player(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_MCTL_REMOTE_PLAYER_CONTROL */ + +#if CONFIG_BT_MCTL_LOCAL_PLAYER_LOCAL_CONTROL || CONFIG_BT_MCTL_REMOTE_PLAYER_CONTROL +esp_err_t esp_ble_audio_media_proxy_ctrl_get_player_name(esp_ble_audio_media_player_t *player) +{ + int err; + + if (player == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_media_proxy_ctrl_get_player_name_safe(player); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_media_proxy_ctrl_get_icon_id(esp_ble_audio_media_player_t *player) +{ + int err; + + if (player == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_media_proxy_ctrl_get_icon_id_safe(player); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_media_proxy_ctrl_get_icon_url(esp_ble_audio_media_player_t *player) +{ + int err; + + if (player == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_media_proxy_ctrl_get_icon_url_safe(player); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_media_proxy_ctrl_get_track_title(esp_ble_audio_media_player_t *player) +{ + int err; + + if (player == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_media_proxy_ctrl_get_track_title_safe(player); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_media_proxy_ctrl_get_track_duration(esp_ble_audio_media_player_t *player) +{ + int err; + + if (player == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_media_proxy_ctrl_get_track_duration_safe(player); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_media_proxy_ctrl_get_track_position(esp_ble_audio_media_player_t *player) +{ + int err; + + if (player == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_media_proxy_ctrl_get_track_position_safe(player); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_media_proxy_ctrl_set_track_position(esp_ble_audio_media_player_t *player, + int32_t position) +{ + int err; + + if (player == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_media_proxy_ctrl_set_track_position_safe(player, position); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_media_proxy_ctrl_get_playback_speed(esp_ble_audio_media_player_t *player) +{ + int err; + + if (player == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_media_proxy_ctrl_get_playback_speed_safe(player); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_media_proxy_ctrl_set_playback_speed(esp_ble_audio_media_player_t *player, + int8_t speed) +{ + int err; + + if (player == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_media_proxy_ctrl_set_playback_speed_safe(player, speed); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_media_proxy_ctrl_get_seeking_speed(esp_ble_audio_media_player_t *player) +{ + int err; + + if (player == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_media_proxy_ctrl_get_seeking_speed_safe(player); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_media_proxy_ctrl_get_track_segments_id(esp_ble_audio_media_player_t *player) +{ + int err; + + if (player == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_media_proxy_ctrl_get_track_segments_id_safe(player); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_media_proxy_ctrl_get_current_track_id(esp_ble_audio_media_player_t *player) +{ + int err; + + if (player == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_media_proxy_ctrl_get_current_track_id_safe(player); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_media_proxy_ctrl_set_current_track_id(esp_ble_audio_media_player_t *player, + uint64_t id) +{ + int err; + + if (player == NULL || (IS_ENABLED(CONFIG_BT_MCTL_LOCAL_PLAYER_LOCAL_CONTROL) && + ESP_BLE_AUDIO_MCS_VALID_OBJ_ID(id) == false)) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_media_proxy_ctrl_set_current_track_id_safe(player, id); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_media_proxy_ctrl_get_next_track_id(esp_ble_audio_media_player_t *player) +{ + int err; + + if (player == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_media_proxy_ctrl_get_next_track_id_safe(player); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_media_proxy_ctrl_set_next_track_id(esp_ble_audio_media_player_t *player, + uint64_t id) +{ + int err; + + if (player == NULL || ESP_BLE_AUDIO_MCS_VALID_OBJ_ID(id) == false) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_media_proxy_ctrl_set_next_track_id_safe(player, id); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_media_proxy_ctrl_get_parent_group_id(esp_ble_audio_media_player_t *player) +{ + int err; + + if (player == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_media_proxy_ctrl_get_parent_group_id_safe(player); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_media_proxy_ctrl_get_current_group_id(esp_ble_audio_media_player_t *player) +{ + int err; + + if (player == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_media_proxy_ctrl_get_current_group_id_safe(player); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_media_proxy_ctrl_set_current_group_id(esp_ble_audio_media_player_t *player, + uint64_t id) +{ + int err; + + if (player == NULL || (IS_ENABLED(CONFIG_BT_MCTL_LOCAL_PLAYER_LOCAL_CONTROL) && + ESP_BLE_AUDIO_MCS_VALID_OBJ_ID(id) == false)) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_media_proxy_ctrl_set_current_group_id_safe(player, id); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_media_proxy_ctrl_get_playing_order(esp_ble_audio_media_player_t *player) +{ + int err; + + if (player == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_media_proxy_ctrl_get_playing_order_safe(player); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_media_proxy_ctrl_set_playing_order(esp_ble_audio_media_player_t *player, + uint8_t order) +{ + int err; + + if (player == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_media_proxy_ctrl_set_playing_order_safe(player, order); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_media_proxy_ctrl_get_playing_orders_supported(esp_ble_audio_media_player_t *player) +{ + int err; + + if (player == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_media_proxy_ctrl_get_playing_orders_supported_safe(player); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_media_proxy_ctrl_get_media_state(esp_ble_audio_media_player_t *player) +{ + int err; + + if (player == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_media_proxy_ctrl_get_media_state_safe(player); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_media_proxy_ctrl_send_command(esp_ble_audio_media_player_t *player, + const esp_ble_audio_mpl_cmd_t *command) +{ + int err; + + if (player == NULL || command == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_media_proxy_ctrl_send_command_safe(player, command); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_media_proxy_ctrl_get_commands_supported(esp_ble_audio_media_player_t *player) +{ + int err; + + if (player == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_media_proxy_ctrl_get_commands_supported_safe(player); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_media_proxy_ctrl_send_search(esp_ble_audio_media_player_t *player, + const esp_ble_audio_mpl_search_t *search) +{ + int err; + + if (player == NULL || search == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_media_proxy_ctrl_send_search_safe(player, search); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_media_proxy_ctrl_get_search_results_id(esp_ble_audio_media_player_t *player) +{ + int err; + + if (player == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_media_proxy_ctrl_get_search_results_id_safe(player); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_media_proxy_ctrl_get_content_ctrl_id(esp_ble_audio_media_player_t *player) +{ + int err; + + if (player == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_media_proxy_ctrl_get_content_ctrl_id_safe(player); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_MCTL_LOCAL_PLAYER_LOCAL_CONTROL || CONFIG_BT_MCTL_REMOTE_PLAYER_CONTROL */ + +#if CONFIG_BT_MCTL_LOCAL_PLAYER_CONTROL +static bool pl_calls_is_valid(const esp_ble_audio_media_proxy_pl_calls_t *pl_calls) +{ + if (pl_calls == NULL) { + return false; + } + + if (pl_calls->get_player_name == NULL || + pl_calls->get_icon_url == NULL || + pl_calls->get_track_title == NULL || + pl_calls->get_track_duration == NULL || + pl_calls->get_track_position == NULL || + pl_calls->set_track_position == NULL || + pl_calls->get_playback_speed == NULL || + pl_calls->set_playback_speed == NULL || + pl_calls->get_seeking_speed == NULL || + pl_calls->get_playing_order == NULL || + pl_calls->set_playing_order == NULL || + pl_calls->get_playing_orders_supported == NULL || + pl_calls->get_media_state == NULL || + pl_calls->send_command == NULL || + pl_calls->get_commands_supported == NULL || + pl_calls->get_content_ctrl_id == NULL) { + return false; + } + +#if CONFIG_BT_MPL_OBJECTS + if (pl_calls->get_icon_id == NULL || + pl_calls->get_track_segments_id == NULL || + pl_calls->get_current_track_id == NULL || + pl_calls->set_current_track_id == NULL || + pl_calls->get_next_track_id == NULL || + pl_calls->set_next_track_id == NULL || + pl_calls->get_parent_group_id == NULL || + pl_calls->get_current_group_id == NULL || + pl_calls->set_current_group_id == NULL || + pl_calls->send_search == NULL || + pl_calls->get_search_results_id == NULL) { + return false; + } +#endif /* CONFIG_BT_MPL_OBJECTS */ + + return true; +} + +esp_err_t esp_ble_audio_media_proxy_pl_register(esp_ble_audio_media_proxy_pl_calls_t *pl_calls) +{ + int err; + + if (pl_calls_is_valid(pl_calls) == false) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_media_proxy_pl_register_safe(pl_calls); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_media_proxy_pl_init(void) +{ + int err; + + err = bt_media_proxy_pl_init_safe(); + if (err) { + return ESP_FAIL; + } + +#if CONFIG_BT_MCS && BLE_AUDIO_SVC_SEP_ADD + err = bt_le_media_proxy_pl_init(); + if (err) { + return ESP_FAIL; + } +#endif /* CONFIG_BT_MCS && BLE_AUDIO_SVC_SEP_ADD */ + + return ESP_OK; +} +#endif /* CONFIG_BT_MCTL_LOCAL_PLAYER_CONTROL */ + +#if CONFIG_BT_MCS && CONFIG_BT_OTS +struct bt_ots *esp_ble_audio_mcs_get_ots(void) +{ + return bt_mcs_get_ots_safe(); +} +#endif /* CONFIG_BT_MCS && CONFIG_BT_OTS */ diff --git a/components/bt/esp_ble_audio/api/audio/esp_ble_audio_micp_api.c b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_micp_api.c new file mode 100644 index 0000000000..bc2b6a561e --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_micp_api.c @@ -0,0 +1,231 @@ +/* + * SPDX-FileCopyrightText: 2020-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_ble_audio_micp_api.h" + +#if CONFIG_BT_MICP_MIC_DEV +esp_err_t esp_ble_audio_micp_mic_dev_register(esp_ble_audio_micp_mic_dev_register_param_t *param) +{ + int err; + + if (param == NULL || + (CONFIG_BT_MICP_MIC_DEV_AICS_INSTANCE_COUNT && param->aics_param == NULL)) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_micp_mic_dev_register_safe(param); + if (err) { + return ESP_FAIL; + } + +#if BLE_AUDIO_SVC_SEP_ADD + err = bt_le_micp_mic_dev_init(); + if (err) { + return ESP_FAIL; + } +#endif /* BLE_AUDIO_SVC_SEP_ADD */ + + return ESP_OK; +} + +esp_err_t esp_ble_audio_micp_mic_dev_included_get(esp_ble_audio_micp_included_t *included) +{ + int err; + + if (included == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_micp_mic_dev_included_get_safe(included); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_micp_mic_dev_unmute(void) +{ + int err; + + err = bt_micp_mic_dev_unmute_safe(); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_micp_mic_dev_mute(void) +{ + int err; + + err = bt_micp_mic_dev_mute_safe(); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_micp_mic_dev_mute_disable(void) +{ + int err; + + err = bt_micp_mic_dev_mute_disable_safe(); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_micp_mic_dev_mute_get(void) +{ + int err; + + err = bt_micp_mic_dev_mute_get_safe(); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_MICP_MIC_DEV */ + +#if CONFIG_BT_MICP_MIC_CTLR +#if CONFIG_BT_MICP_MIC_CTLR_AICS +esp_err_t esp_ble_audio_micp_mic_ctlr_included_get(esp_ble_audio_micp_mic_ctlr_t *mic_ctlr, + esp_ble_audio_micp_included_t *included) +{ + int err; + + if (mic_ctlr == NULL || included == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_micp_mic_ctlr_included_get_safe(mic_ctlr, included); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */ + +esp_ble_audio_micp_mic_ctlr_t *esp_ble_audio_micp_mic_ctlr_get_by_conn(uint16_t conn_handle) +{ + esp_ble_audio_micp_mic_ctlr_t *ret = NULL; + void *conn; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + goto unlock; + } + + ret = bt_micp_mic_ctlr_get_by_conn(conn); + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_micp_mic_ctlr_discover(uint16_t conn_handle, + esp_ble_audio_micp_mic_ctlr_t **mic_ctlr) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + if (mic_ctlr == NULL) { + return ESP_ERR_INVALID_ARG; + } + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_micp_mic_ctlr_discover(conn, mic_ctlr); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_micp_mic_ctlr_unmute(esp_ble_audio_micp_mic_ctlr_t *mic_ctlr) +{ + int err; + + if (mic_ctlr == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_micp_mic_ctlr_unmute_safe(mic_ctlr); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_micp_mic_ctlr_mute(esp_ble_audio_micp_mic_ctlr_t *mic_ctlr) +{ + int err; + + if (mic_ctlr == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_micp_mic_ctlr_mute_safe(mic_ctlr); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_micp_mic_ctlr_mute_get(esp_ble_audio_micp_mic_ctlr_t *mic_ctlr) +{ + int err; + + if (mic_ctlr == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_micp_mic_ctlr_mute_get_safe(mic_ctlr); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_micp_mic_ctlr_cb_register(esp_ble_audio_micp_mic_ctlr_cb_t *cb) +{ + int err; + + if (cb == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_micp_mic_ctlr_cb_register_safe(cb); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_MICP_MIC_CTLR */ diff --git a/components/bt/esp_ble_audio/api/audio/esp_ble_audio_pacs_api.c b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_pacs_api.c new file mode 100644 index 0000000000..5050ccc73d --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_pacs_api.c @@ -0,0 +1,200 @@ +/* + * SPDX-FileCopyrightText: 2021 Intel Corporation + * SPDX-FileCopyrightText: 2021-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_ble_audio_pacs_api.h" + +#if CONFIG_BT_PACS +esp_err_t esp_ble_audio_pacs_register(const esp_ble_audio_pacs_register_param_t *param) +{ + int err; + + if (param == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_pacs_register_safe(param); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_pacs_unregister(void) +{ + int err; + + err = bt_pacs_unregister_safe(); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +static bool dir_is_valid(esp_ble_audio_dir_t dir) +{ + if (dir != ESP_BLE_AUDIO_DIR_SINK && + dir != ESP_BLE_AUDIO_DIR_SOURCE) { + return false; + } + + return true; +} + +esp_err_t esp_ble_audio_pacs_cap_register(esp_ble_audio_dir_t dir, + esp_ble_audio_pacs_cap_t *cap) +{ + int err; + + if (dir_is_valid(dir) == false || + cap == NULL || cap->codec_cap == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_pacs_cap_register_safe(dir, cap); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_pacs_cap_unregister(esp_ble_audio_dir_t dir, + esp_ble_audio_pacs_cap_t *cap) +{ + int err; + + if (dir_is_valid(dir) == false || cap == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_pacs_cap_unregister_safe(dir, cap); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_pacs_set_location(esp_ble_audio_dir_t dir, + esp_ble_audio_location_t location) +{ + int err; + + if (dir_is_valid(dir) == false) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_pacs_set_location_safe(dir, location); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_pacs_set_available_contexts(esp_ble_audio_dir_t dir, + esp_ble_audio_context_t contexts) +{ + int err; + + if (dir_is_valid(dir) == false) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_pacs_set_available_contexts_safe(dir, contexts); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_ble_audio_context_t esp_ble_audio_pacs_get_available_contexts(esp_ble_audio_dir_t dir) +{ + if (dir_is_valid(dir) == false) { + return ESP_BLE_AUDIO_CONTEXT_TYPE_NONE; + } + + return bt_pacs_get_available_contexts_safe(dir); +} + +esp_err_t esp_ble_audio_pacs_conn_set_available_contexts_for_conn(uint16_t conn_handle, + esp_ble_audio_dir_t dir, + esp_ble_audio_context_t *contexts) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + /* Note: contexts could be NULL */ + + if (dir_is_valid(dir) == false) { + return ESP_ERR_INVALID_ARG; + } + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_pacs_conn_set_available_contexts_for_conn(conn, dir, contexts); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_ble_audio_context_t esp_ble_audio_pacs_get_available_contexts_for_conn(uint16_t conn_handle, + esp_ble_audio_dir_t dir) +{ + esp_ble_audio_context_t ret = ESP_BLE_AUDIO_CONTEXT_TYPE_NONE; + void *conn; + + if (dir_is_valid(dir) == false) { + return ESP_BLE_AUDIO_CONTEXT_TYPE_NONE; + } + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + goto unlock; + } + + ret = bt_pacs_get_available_contexts_for_conn(conn, dir); + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_err_t esp_ble_audio_pacs_set_supported_contexts(esp_ble_audio_dir_t dir, + esp_ble_audio_context_t contexts) +{ + int err; + + if (dir_is_valid(dir) == false) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_pacs_set_supported_contexts_safe(dir, contexts); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_PACS */ diff --git a/components/bt/esp_ble_audio/api/audio/esp_ble_audio_pbp_api.c b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_pbp_api.c new file mode 100644 index 0000000000..be837df7ec --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_pbp_api.c @@ -0,0 +1,65 @@ +/* + * SPDX-FileCopyrightText: 2023 NXP + * SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_ble_audio_pbp_api.h" + +#if CONFIG_BT_PBP +esp_err_t esp_ble_audio_pbp_get_announcement(const uint8_t meta[], size_t meta_len, + esp_ble_audio_pbp_announcement_feature_t features, + struct net_buf_simple *pba_data_buf) +{ + int err; + + if (pba_data_buf == NULL || + pba_data_buf->size < (meta_len + ESP_BLE_AUDIO_PBP_MIN_PBA_SIZE)) { + return ESP_ERR_INVALID_ARG; + } + + if ((meta == NULL && meta_len != 0) || (meta != NULL && meta_len == 0)) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_pbp_get_announcement(meta, meta_len, features, pba_data_buf); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_pbp_parse_announcement(uint8_t data_type, const uint8_t *data, uint8_t data_len, + esp_ble_audio_pbp_announcement_feature_t *features, + uint8_t **meta, uint8_t *meta_len) +{ + struct bt_data ad = { + .type = data_type, + .data = data, + .data_len = data_len, + }; + int ret; + + if (data == NULL || data_len == 0 || features == NULL || + meta == NULL || meta_len == NULL) { + return ESP_ERR_INVALID_ARG; + } + + if (data_type != BT_DATA_SVC_DATA16 || + data_len < ESP_BLE_AUDIO_PBP_MIN_PBA_SIZE) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_pbp_parse_announcement(&ad, features, meta); + if (ret < 0) { + return ESP_FAIL; + } + + *meta_len = ret; + + return ESP_OK; +} +#endif /* CONFIG_BT_PBP */ diff --git a/components/bt/esp_ble_audio/api/audio/esp_ble_audio_tbs_api.c b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_tbs_api.c new file mode 100644 index 0000000000..20aab0bbef --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_tbs_api.c @@ -0,0 +1,997 @@ +/* + * SPDX-FileCopyrightText: 2020 Bose Corporation + * SPDX-FileCopyrightText: 2021 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_ble_audio_tbs_api.h" + +#if CONFIG_BT_TBS +esp_err_t esp_ble_audio_tbs_accept(uint8_t call_index) +{ + int err; + + err = bt_tbs_accept_safe(call_index); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_tbs_hold(uint8_t call_index) +{ + int err; + + err = bt_tbs_hold_safe(call_index); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_tbs_retrieve(uint8_t call_index) +{ + int err; + + err = bt_tbs_retrieve_safe(call_index); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_tbs_terminate(uint8_t call_index) +{ + int err; + + err = bt_tbs_terminate_safe(call_index); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_tbs_originate(uint8_t bearer_index, + char *uri, + uint8_t *call_index) +{ + int err; + + if (uri == NULL || call_index == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_tbs_originate_safe(bearer_index, uri, call_index); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_tbs_join(uint8_t call_index_cnt, uint8_t *call_indexes) +{ + int err; + + if (call_index_cnt == 0 || call_indexes == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_tbs_join_safe(call_index_cnt, call_indexes); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_tbs_remote_answer(uint8_t call_index) +{ + int err; + + err = bt_tbs_remote_answer_safe(call_index); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_tbs_remote_hold(uint8_t call_index) +{ + int err; + + err = bt_tbs_remote_hold_safe(call_index); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_tbs_remote_retrieve(uint8_t call_index) +{ + int err; + + err = bt_tbs_remote_retrieve_safe(call_index); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_tbs_remote_terminate(uint8_t call_index) +{ + int err; + + err = bt_tbs_remote_terminate_safe(call_index); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_tbs_remote_incoming(uint8_t bearer_index, + const char *to, + const char *from, + const char *friendly_name, + uint8_t *call_index) +{ + int ret; + + if (to == NULL || from == NULL || + friendly_name == NULL || call_index == NULL) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_tbs_remote_incoming_safe(bearer_index, to, from, friendly_name); + if (ret < 0) { + return ESP_FAIL; + } + + *call_index = ret; + + return ESP_OK; +} + +esp_err_t esp_ble_audio_tbs_set_bearer_provider_name(uint8_t bearer_index, const char *name) +{ + int err; + + if (name == NULL || strlen(name) == 0 || + strlen(name) >= CONFIG_BT_TBS_MAX_PROVIDER_NAME_LENGTH) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_tbs_set_bearer_provider_name_safe(bearer_index, name); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_tbs_set_bearer_technology(uint8_t bearer_index, uint8_t new_technology) +{ + int err; + + if (new_technology < ESP_BLE_AUDIO_TBS_TECHNOLOGY_3G || + new_technology > ESP_BLE_AUDIO_TBS_TECHNOLOGY_WCDMA) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_tbs_set_bearer_technology_safe(bearer_index, new_technology); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_tbs_set_signal_strength(uint8_t bearer_index, uint8_t new_signal_strength) +{ + int err; + + if (new_signal_strength > ESP_BLE_AUDIO_TBS_SIGNAL_STRENGTH_MAX && + new_signal_strength != ESP_BLE_AUDIO_TBS_SIGNAL_STRENGTH_UNKNOWN) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_tbs_set_signal_strength_safe(bearer_index, new_signal_strength); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +#define TBS_VALID_STATUS_FLAGS(val) ((val) <= (BIT(0) | BIT(1))) + +esp_err_t esp_ble_audio_tbs_set_status_flags(uint8_t bearer_index, uint16_t status_flags) +{ + int err; + + if (TBS_VALID_STATUS_FLAGS(status_flags) == false) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_tbs_set_status_flags_safe(bearer_index, status_flags); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_tbs_set_uri_scheme_list(uint8_t bearer_index, + const char **uri_list, + uint8_t uri_count) +{ + uint8_t count = CONFIG_BT_TBS_BEARER_COUNT; + int err; + + if (count == 0 || bearer_index >= count || + (uri_count && uri_list == NULL)) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_tbs_set_uri_scheme_list_safe(bearer_index, uri_list, uri_count); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +void esp_ble_audio_tbs_register_cb(esp_ble_audio_tbs_cb_t *cbs) +{ + bt_tbs_register_cb_safe(cbs); +} + +static bool valid_register_param(const esp_ble_audio_tbs_register_param_t *param) +{ + if (param == NULL) { + return false; + } + + if (param->provider_name == NULL) { + return false; + } + + if (strlen(param->provider_name) == 0 || + strlen(param->provider_name) >= CONFIG_BT_TBS_MAX_PROVIDER_NAME_LENGTH) { + /* Provider name empty or length not less than CONFIG_BT_TBS_MAX_PROVIDER_NAME_LENGTH */ + return false; + } + + if (param->uci == NULL) { + return false; + } + + if (param->uri_schemes_supported == NULL) { + return false; + } + + if (IN_RANGE(param->technology, + ESP_BLE_AUDIO_TBS_TECHNOLOGY_3G, + ESP_BLE_AUDIO_TBS_TECHNOLOGY_WCDMA) == false) { + return false; + } + + if (param->supported_features > ESP_BLE_AUDIO_TBS_FEATURE_ALL) { + return false; + } + + if (CONFIG_BT_TBS_BEARER_COUNT == 0 && param->gtbs == false) { + return false; + } + + return true; +} + +esp_err_t esp_ble_audio_tbs_register_bearer(const esp_ble_audio_tbs_register_param_t *param, + uint8_t *bearer_index) +{ + int ret; + + if (param == NULL || valid_register_param(param) == false || bearer_index == NULL) { + return ESP_ERR_INVALID_ARG; + } + + /* Note: currently only GTBS is supported */ + if (param->gtbs == false) { + return ESP_ERR_INVALID_ARG; + } + + ret = bt_tbs_register_bearer_safe(param); + if (ret < 0) { + return ESP_FAIL; + } + + *bearer_index = ret; + +#if BLE_AUDIO_SVC_SEP_ADD + if (bt_le_gtbs_init()) { + bt_tbs_unregister_bearer_safe(*bearer_index); + return ESP_FAIL; + } +#endif /* BLE_AUDIO_SVC_SEP_ADD */ + + return ESP_OK; +} + +esp_err_t esp_ble_audio_tbs_unregister_bearer(uint8_t bearer_index) +{ + int err; + + err = bt_tbs_unregister_bearer_safe(bearer_index); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_TBS */ + +#if CONFIG_BT_TBS_CLIENT +esp_err_t esp_ble_audio_tbs_client_discover(uint16_t conn_handle) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_tbs_client_discover(conn); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +#if CONFIG_BT_TBS_CLIENT_SET_BEARER_SIGNAL_INTERVAL +esp_err_t esp_ble_audio_tbs_client_set_signal_strength_interval(uint16_t conn_handle, + uint8_t inst_index, + uint8_t interval) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_tbs_client_set_signal_strength_interval(conn, inst_index, interval); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_TBS_CLIENT_SET_BEARER_SIGNAL_INTERVAL */ + +#if CONFIG_BT_TBS_CLIENT_ORIGINATE_CALL +#define TBS_MIN_URI_LEN 3 /* a:b */ +#define FIRST_PRINTABLE_ASCII_CHAR ' ' /* space */ + +static inline bool tbs_valid_uri(const uint8_t *uri, size_t uri_len) +{ + if (uri_len > CONFIG_BT_TBS_MAX_URI_LENGTH || uri_len < TBS_MIN_URI_LEN) { + return false; + } + + if (uri[0] < FIRST_PRINTABLE_ASCII_CHAR) { + /* Invalid first char */ + return false; + } + + for (size_t i = 1; i < uri_len; i++) { + if (uri[i] == ':' && uri[i + 1] >= FIRST_PRINTABLE_ASCII_CHAR) { + return true; + } + } + + return false; +} + +esp_err_t esp_ble_audio_tbs_client_originate_call(uint16_t conn_handle, + uint8_t inst_index, + const char *uri) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + if (uri == NULL || + tbs_valid_uri((const uint8_t *)uri, strlen(uri)) == false) { + return ESP_ERR_INVALID_ARG; + } + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_tbs_client_originate_call(conn, inst_index, uri); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_TBS_CLIENT_ORIGINATE_CALL */ + +#if CONFIG_BT_TBS_CLIENT_TERMINATE_CALL +esp_err_t esp_ble_audio_tbs_client_terminate_call(uint16_t conn_handle, + uint8_t inst_index, + uint8_t call_index) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_tbs_client_terminate_call(conn, inst_index, call_index); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_TBS_CLIENT_TERMINATE_CALL */ + +#if CONFIG_BT_TBS_CLIENT_HOLD_CALL +esp_err_t esp_ble_audio_tbs_client_hold_call(uint16_t conn_handle, + uint8_t inst_index, + uint8_t call_index) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_tbs_client_hold_call(conn, inst_index, call_index); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_TBS_CLIENT_HOLD_CALL */ + +#if CONFIG_BT_TBS_CLIENT_ACCEPT_CALL +esp_err_t esp_ble_audio_tbs_client_accept_call(uint16_t conn_handle, + uint8_t inst_index, + uint8_t call_index) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_tbs_client_accept_call(conn, inst_index, call_index); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_TBS_CLIENT_ACCEPT_CALL */ + +#if CONFIG_BT_TBS_CLIENT_RETRIEVE_CALL +esp_err_t esp_ble_audio_tbs_client_retrieve_call(uint16_t conn_handle, + uint8_t inst_index, + uint8_t call_index) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_tbs_client_retrieve_call(conn, inst_index, call_index); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_TBS_CLIENT_RETRIEVE_CALL */ + +#if CONFIG_BT_TBS_CLIENT_JOIN_CALLS +esp_err_t esp_ble_audio_tbs_client_join_calls(uint16_t conn_handle, + uint8_t inst_index, + const uint8_t *call_indexes, + uint8_t count) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + if (call_indexes == NULL || + count < 2 || count > CONFIG_BT_TBS_CLIENT_MAX_CALLS) { + return ESP_ERR_INVALID_ARG; + } + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_tbs_client_join_calls(conn, inst_index, call_indexes, count); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_TBS_CLIENT_JOIN_CALLS */ + +#if CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME +esp_err_t esp_ble_audio_tbs_client_read_bearer_provider_name(uint16_t conn_handle, uint8_t inst_index) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_tbs_client_read_bearer_provider_name(conn, inst_index); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME */ + +#if CONFIG_BT_TBS_CLIENT_BEARER_UCI +esp_err_t esp_ble_audio_tbs_client_read_bearer_uci(uint16_t conn_handle, uint8_t inst_index) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_tbs_client_read_bearer_uci(conn, inst_index); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_TBS_CLIENT_BEARER_UCI */ + +#if CONFIG_BT_TBS_CLIENT_BEARER_TECHNOLOGY +esp_err_t esp_ble_audio_tbs_client_read_technology(uint16_t conn_handle, uint8_t inst_index) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_tbs_client_read_technology(conn, inst_index); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_TBS_CLIENT_BEARER_TECHNOLOGY */ + +#if CONFIG_BT_TBS_CLIENT_BEARER_URI_SCHEMES_SUPPORTED_LIST +esp_err_t esp_ble_audio_tbs_client_read_uri_list(uint16_t conn_handle, uint8_t inst_index) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_tbs_client_read_uri_list(conn, inst_index); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_TBS_CLIENT_BEARER_URI_SCHEMES_SUPPORTED_LIST */ + +#if CONFIG_BT_TBS_CLIENT_BEARER_SIGNAL_STRENGTH +esp_err_t esp_ble_audio_tbs_client_read_signal_strength(uint16_t conn_handle, uint8_t inst_index) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_tbs_client_read_signal_strength(conn, inst_index); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_TBS_CLIENT_BEARER_SIGNAL_STRENGTH */ + +#if CONFIG_BT_TBS_CLIENT_READ_BEARER_SIGNAL_INTERVAL +esp_err_t esp_ble_audio_tbs_client_read_signal_interval(uint16_t conn_handle, uint8_t inst_index) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_tbs_client_read_signal_interval(conn, inst_index); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_TBS_CLIENT_READ_BEARER_SIGNAL_INTERVAL */ + +#if CONFIG_BT_TBS_CLIENT_BEARER_LIST_CURRENT_CALLS +esp_err_t esp_ble_audio_tbs_client_read_current_calls(uint16_t conn_handle, uint8_t inst_index) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_tbs_client_read_current_calls(conn, inst_index); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_TBS_CLIENT_BEARER_LIST_CURRENT_CALLS */ + +#if CONFIG_BT_TBS_CLIENT_CCID +esp_err_t esp_ble_audio_tbs_client_read_ccid(uint16_t conn_handle, uint8_t inst_index) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_tbs_client_read_ccid(conn, inst_index); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_TBS_CLIENT_CCID */ + +#if CONFIG_BT_TBS_CLIENT_INCOMING_URI +esp_err_t esp_ble_audio_tbs_client_read_call_uri(uint16_t conn_handle, uint8_t inst_index) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_tbs_client_read_call_uri(conn, inst_index); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_TBS_CLIENT_INCOMING_URI */ + +#if CONFIG_BT_TBS_CLIENT_STATUS_FLAGS +esp_err_t esp_ble_audio_tbs_client_read_status_flags(uint16_t conn_handle, uint8_t inst_index) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_tbs_client_read_status_flags(conn, inst_index); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_TBS_CLIENT_STATUS_FLAGS */ + +esp_err_t esp_ble_audio_tbs_client_read_call_state(uint16_t conn_handle, uint8_t inst_index) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_tbs_client_read_call_state(conn, inst_index); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +#if CONFIG_BT_TBS_CLIENT_INCOMING_CALL +esp_err_t esp_ble_audio_tbs_client_read_remote_uri(uint16_t conn_handle, uint8_t inst_index) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_tbs_client_read_remote_uri(conn, inst_index); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_TBS_CLIENT_INCOMING_CALL */ + +#if CONFIG_BT_TBS_CLIENT_CALL_FRIENDLY_NAME +esp_err_t esp_ble_audio_tbs_client_read_friendly_name(uint16_t conn_handle, uint8_t inst_index) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_tbs_client_read_friendly_name(conn, inst_index); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_TBS_CLIENT_CALL_FRIENDLY_NAME */ + +#if CONFIG_BT_TBS_CLIENT_OPTIONAL_OPCODES +esp_err_t esp_ble_audio_tbs_client_read_optional_opcodes(uint16_t conn_handle, uint8_t inst_index) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_tbs_client_read_optional_opcodes(conn, inst_index); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_TBS_CLIENT_OPTIONAL_OPCODES */ + +esp_err_t esp_ble_audio_tbs_client_register_cb(esp_ble_audio_tbs_client_cb_t *cbs) +{ + int err; + + if (cbs == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_tbs_client_register_cb_safe(cbs); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +#if CONFIG_BT_TBS_CLIENT_CCID +esp_ble_audio_tbs_instance_t *esp_ble_audio_tbs_client_get_by_ccid(uint16_t conn_handle, uint8_t ccid) +{ + esp_ble_audio_tbs_instance_t *ret = NULL; + void *conn; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + goto unlock; + } + + ret = lib_tbs_client_get_by_ccid(conn, ccid); + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_TBS_CLIENT_CCID */ +#endif /* CONFIG_BT_TBS_CLIENT */ diff --git a/components/bt/esp_ble_audio/api/audio/esp_ble_audio_tmap_api.c b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_tmap_api.c new file mode 100644 index 0000000000..934e0af4ff --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_tmap_api.c @@ -0,0 +1,60 @@ +/* + * SPDX-FileCopyrightText: 2023 NXP + * SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_ble_audio_tmap_api.h" + +#if CONFIG_BT_TMAP +esp_err_t esp_ble_audio_tmap_register(esp_ble_audio_tmap_role_t role) +{ + int err; + + err = bt_tmap_register_safe(role); + if (err) { + return ESP_FAIL; + } + +#if BLE_AUDIO_SVC_SEP_ADD + err = bt_le_tmas_init(); + if (err) { + return ESP_FAIL; + } +#endif /* BLE_AUDIO_SVC_SEP_ADD */ + + return ESP_OK; +} + +esp_err_t esp_ble_audio_tmap_discover(uint16_t conn_handle, + const esp_ble_audio_tmap_cb_t *tmap_cb) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_tmap_discover(conn, tmap_cb); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +void esp_ble_audio_tmap_set_role(esp_ble_audio_tmap_role_t role) +{ + bt_tmap_set_role_safe(role); +} +#endif /* CONFIG_BT_TMAP */ diff --git a/components/bt/esp_ble_audio/api/audio/esp_ble_audio_vcp_api.c b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_vcp_api.c new file mode 100644 index 0000000000..6f071f5686 --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_vcp_api.c @@ -0,0 +1,430 @@ +/* + * SPDX-FileCopyrightText: 2020-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_ble_audio_vcp_api.h" + +#if CONFIG_BT_VCP_VOL_REND +esp_err_t esp_ble_audio_vcp_vol_rend_included_get(esp_ble_audio_vcp_included_t *included) +{ + int err; + + if (included == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_vcp_vol_rend_included_get_safe(included); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_vcp_vol_rend_register(esp_ble_audio_vcp_vol_rend_register_param_t *param) +{ + int err; + + if (param == NULL) { + return ESP_ERR_INVALID_ARG; + } + + if (CONFIG_BT_VCP_VOL_REND_VOCS_INSTANCE_COUNT && param->vocs_param == NULL) { + return ESP_ERR_INVALID_ARG; + } + + if (CONFIG_BT_VCP_VOL_REND_AICS_INSTANCE_COUNT && param->aics_param == NULL) { + return ESP_ERR_INVALID_ARG; + } + + if (param->mute > ESP_BLE_AUDIO_VCP_STATE_MUTED || param->step == 0) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_vcp_vol_rend_register_safe(param); + if (err) { + return ESP_FAIL; + } + +#if BLE_AUDIO_SVC_SEP_ADD + err = bt_le_vcp_vol_rend_init(); + if (err) { + return ESP_FAIL; + } +#endif /* BLE_AUDIO_SVC_SEP_ADD */ + + return ESP_OK; +} + +esp_err_t esp_ble_audio_vcp_vol_rend_set_step(uint8_t volume_step) +{ + int err; + + if (volume_step == 0) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_vcp_vol_rend_set_step_safe(volume_step); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_vcp_vol_rend_get_state(void) +{ + int err; + + err = bt_vcp_vol_rend_get_state_safe(); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_vcp_vol_rend_get_flags(void) +{ + int err; + + err = bt_vcp_vol_rend_get_flags_safe(); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_vcp_vol_rend_vol_down(void) +{ + int err; + + err = bt_vcp_vol_rend_vol_down_safe(); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_vcp_vol_rend_vol_up(void) +{ + int err; + + err = bt_vcp_vol_rend_vol_up_safe(); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_vcp_vol_rend_unmute_vol_down(void) +{ + int err; + + err = bt_vcp_vol_rend_unmute_vol_down_safe(); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_vcp_vol_rend_unmute_vol_up(void) +{ + int err; + + err = bt_vcp_vol_rend_unmute_vol_up_safe(); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_vcp_vol_rend_set_vol(uint8_t volume) +{ + int err; + + err = bt_vcp_vol_rend_set_vol_safe(volume); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_vcp_vol_rend_unmute(void) +{ + int err; + + err = bt_vcp_vol_rend_unmute_safe(); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_vcp_vol_rend_mute(void) +{ + int err; + + err = bt_vcp_vol_rend_mute_safe(); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_VCP_VOL_REND */ + +#if CONFIG_BT_VCP_VOL_CTLR +esp_err_t esp_ble_audio_vcp_vol_ctlr_cb_register(esp_ble_audio_vcp_vol_ctlr_cb_t *cb) +{ + int err; + + if (cb == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_vcp_vol_ctlr_cb_register_safe(cb); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_vcp_vol_ctlr_cb_unregister(esp_ble_audio_vcp_vol_ctlr_cb_t *cb) +{ + int err; + + if (cb == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_vcp_vol_ctlr_cb_unregister_safe(cb); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_vcp_vol_ctlr_discover(uint16_t conn_handle, + esp_ble_audio_vcp_vol_ctlr_t **vol_ctlr) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + if (vol_ctlr == NULL) { + return ESP_ERR_INVALID_ARG; + } + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_vcp_vol_ctlr_discover(conn, vol_ctlr); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} + +esp_ble_audio_vcp_vol_ctlr_t *esp_ble_audio_vcp_vol_ctlr_get_by_conn(uint16_t conn_handle) +{ + esp_ble_audio_vcp_vol_ctlr_t *ret = NULL; + void *conn; + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + goto unlock; + } + + ret = bt_vcp_vol_ctlr_get_by_conn(conn); + +unlock: + bt_le_host_unlock(); + return ret; +} + +#if CONFIG_BT_VCP_VOL_CTLR_VOCS || CONFIG_BT_VCP_VOL_CTLR_AICS +esp_err_t esp_ble_audio_vcp_vol_ctlr_included_get(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr, + esp_ble_audio_vcp_included_t *included) +{ + int err; + + if (vol_ctlr == NULL || included == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_vcp_vol_ctlr_included_get_safe(vol_ctlr, included); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS || CONFIG_BT_VCP_VOL_CTLR_AICS */ + +esp_err_t esp_ble_audio_vcp_vol_ctlr_read_state(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr) +{ + int err; + + if (vol_ctlr == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_vcp_vol_ctlr_read_state_safe(vol_ctlr); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_vcp_vol_ctlr_read_flags(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr) +{ + int err; + + if (vol_ctlr == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_vcp_vol_ctlr_read_flags_safe(vol_ctlr); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_vcp_vol_ctlr_vol_down(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr) +{ + int err; + + if (vol_ctlr == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_vcp_vol_ctlr_vol_down_safe(vol_ctlr); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_vcp_vol_ctlr_vol_up(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr) +{ + int err; + + if (vol_ctlr == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_vcp_vol_ctlr_vol_up_safe(vol_ctlr); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_vcp_vol_ctlr_unmute_vol_down(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr) +{ + int err; + + if (vol_ctlr == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_vcp_vol_ctlr_unmute_vol_down_safe(vol_ctlr); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_vcp_vol_ctlr_unmute_vol_up(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr) +{ + int err; + + if (vol_ctlr == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_vcp_vol_ctlr_unmute_vol_up_safe(vol_ctlr); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_vcp_vol_ctlr_set_vol(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr, uint8_t volume) +{ + int err; + + if (vol_ctlr == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_vcp_vol_ctlr_set_vol_safe(vol_ctlr, volume); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_vcp_vol_ctlr_unmute(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr) +{ + int err; + + if (vol_ctlr == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_vcp_vol_ctlr_unmute_safe(vol_ctlr); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_vcp_vol_ctlr_mute(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr) +{ + int err; + + if (vol_ctlr == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_vcp_vol_ctlr_mute_safe(vol_ctlr); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_VCP_VOL_CTLR */ diff --git a/components/bt/esp_ble_audio/api/audio/esp_ble_audio_vocs_api.c b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_vocs_api.c new file mode 100644 index 0000000000..af97589044 --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/esp_ble_audio_vocs_api.c @@ -0,0 +1,198 @@ +/* + * SPDX-FileCopyrightText: 2020-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_ble_audio_vocs_api.h" + +#if CONFIG_BT_VOCS +esp_ble_audio_vocs_t *esp_ble_audio_vocs_free_instance_get(void) +{ + return bt_vocs_free_instance_get_safe(); +} + +void *esp_ble_audio_vocs_svc_decl_get(esp_ble_audio_vocs_t *vocs) +{ + if (vocs == NULL) { + return NULL; + } + + return bt_vocs_svc_decl_get_safe(vocs); +} + +esp_err_t esp_ble_audio_vocs_register(esp_ble_audio_vocs_t *vocs, + const esp_ble_audio_vocs_register_param_t *param) +{ + int err; + + if (vocs == NULL || param == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_vocs_register_safe(vocs, param); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_VOCS */ + +#if CONFIG_BT_VOCS || CONFIG_BT_VOCS_CLIENT +esp_err_t esp_ble_audio_vocs_state_get(esp_ble_audio_vocs_t *inst) +{ + int err; + + if (inst == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_vocs_state_get_safe(inst); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_vocs_state_set(esp_ble_audio_vocs_t *inst, int16_t offset) +{ + int err; + + if (inst == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_vocs_state_set_safe(inst, offset); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_vocs_location_get(esp_ble_audio_vocs_t *inst) +{ + int err; + + if (inst == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_vocs_location_get_safe(inst); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_vocs_location_set(esp_ble_audio_vocs_t *inst, uint32_t location) +{ + int err; + + if (inst == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_vocs_location_set_safe(inst, location); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_vocs_description_get(esp_ble_audio_vocs_t *inst) +{ + int err; + + if (inst == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_vocs_description_get_safe(inst); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_audio_vocs_description_set(esp_ble_audio_vocs_t *inst, + const char *description) +{ + int err; + + if (inst == NULL || description == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_vocs_description_set_safe(inst, description); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_VOCS || CONFIG_BT_VOCS_CLIENT */ + +#if CONFIG_BT_VOCS_CLIENT +esp_err_t esp_ble_audio_vocs_client_cb_register(esp_ble_audio_vocs_t *inst, + esp_ble_audio_vocs_cb_t *cb) +{ + if (inst == NULL) { + return ESP_ERR_INVALID_ARG; + } + + bt_vocs_client_cb_register_safe(inst, cb); + + return ESP_OK; +} + +esp_ble_audio_vocs_t *esp_ble_audio_vocs_client_free_instance_get(void) +{ + return bt_vocs_client_free_instance_get_safe(); +} + +esp_err_t esp_ble_audio_vocs_discover(uint16_t conn_handle, + esp_ble_audio_vocs_t *inst, + const esp_ble_audio_vocs_discover_param_t *param) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + if (inst == NULL || param == NULL) { + return ESP_ERR_INVALID_ARG; + } + + if (param->start_handle == 0 || + param->end_handle == 0 || + param->end_handle < param->start_handle) { + /* Start handle and end handle shall be non-zero and + * start handle shall be less than end handle. + */ + return ESP_ERR_INVALID_ARG; + } + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_vocs_discover(conn, inst, param); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_VOCS_CLIENT */ diff --git a/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_aics_api.h b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_aics_api.h new file mode 100644 index 0000000000..54559ef4b2 --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_aics_api.h @@ -0,0 +1,293 @@ +/* + * SPDX-FileCopyrightText: 2020-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ESP_BLE_AUDIO_AICS_API_H_ +#define ESP_BLE_AUDIO_AICS_API_H_ + +#include +#include +#include + +#include "sdkconfig.h" +#include "esp_err.h" + +#include +#include + +#include "common/init.h" +#include "common/host.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*!< The mute state is unmuted */ +#define ESP_BLE_AUDIO_AICS_STATE_UNMUTED BT_AICS_STATE_UNMUTED +/*!< The mute state is muted */ +#define ESP_BLE_AUDIO_AICS_STATE_MUTED BT_AICS_STATE_MUTED +/*!< The mute state is disabled */ +#define ESP_BLE_AUDIO_AICS_STATE_MUTE_DISABLED BT_AICS_STATE_MUTE_DISABLED + +/*!< The gain mode is manual only and cannot be changed to automatic */ +#define ESP_BLE_AUDIO_AICS_MODE_MANUAL_ONLY BT_AICS_MODE_MANUAL_ONLY +/*!< The gain mode is automatic only and cannot be changed to manual */ +#define ESP_BLE_AUDIO_AICS_MODE_AUTO_ONLY BT_AICS_MODE_AUTO_ONLY +/*!< The gain mode is manual */ +#define ESP_BLE_AUDIO_AICS_MODE_MANUAL BT_AICS_MODE_MANUAL +/*!< The gain mode is automatic */ +#define ESP_BLE_AUDIO_AICS_MODE_AUTO BT_AICS_MODE_AUTO + +/*!< The input is unspecified */ +#define ESP_BLE_AUDIO_AICS_INPUT_TYPE_UNSPECIFIED BT_AICS_INPUT_TYPE_UNSPECIFIED +/*!< The input is a Bluetooth Audio Stream */ +#define ESP_BLE_AUDIO_AICS_INPUT_TYPE_BLUETOOTH BT_AICS_INPUT_TYPE_BLUETOOTH +/*!< The input is a microphone */ +#define ESP_BLE_AUDIO_AICS_INPUT_TYPE_MICROPHONE BT_AICS_INPUT_TYPE_MICROPHONE +/*!< The input is analog */ +#define ESP_BLE_AUDIO_AICS_INPUT_TYPE_ANALOG BT_AICS_INPUT_TYPE_ANALOG +/*!< The input is digital */ +#define ESP_BLE_AUDIO_AICS_INPUT_TYPE_DIGITAL BT_AICS_INPUT_TYPE_DIGITAL +/*!< The input is a radio (AM/FM/XM/etc.) */ +#define ESP_BLE_AUDIO_AICS_INPUT_TYPE_RADIO BT_AICS_INPUT_TYPE_RADIO +/*!< The input is a Streaming Audio Source */ +#define ESP_BLE_AUDIO_AICS_INPUT_TYPE_STREAMING BT_AICS_INPUT_TYPE_STREAMING +/*!< The input is transparent / pass-through */ +#define ESP_BLE_AUDIO_AICS_INPUT_TYPE_AMBIENT BT_AICS_INPUT_TYPE_AMBIENT + +/** Audio Input Control Service instance. */ +typedef struct bt_aics esp_ble_audio_aics_t; + +/** Structure to hold callbacks for Audio Input Control Service. */ +typedef struct bt_aics_cb esp_ble_audio_aics_cb_t; + +/** Structure for initializing an Audio Input Control Service instance. */ +typedef struct bt_aics_register_param esp_ble_audio_aics_register_param_t; + +/** Structure for discovering an Audio Input Control Service instance. */ +typedef struct bt_aics_discover_param esp_ble_audio_aics_discover_param_t; + +/** + * @brief Get a free instance of Audio Input Control Service from the pool. + * + * @return Audio Input Control Service instance in case of success or NULL in case of error. + */ +esp_ble_audio_aics_t *esp_ble_audio_aics_free_instance_get(void); + +/** + * @brief Get the service declaration attribute. + * + * The first service attribute returned can be included in any other GATT service. + * + * @param aics Audio Input Control Service instance. + * + * @return Pointer to the attributes of the service. + */ +void *esp_ble_audio_aics_svc_decl_get(esp_ble_audio_aics_t *aics); + +/** + * @brief Initialize the Audio Input Control Service instance. + * + * @param aics Audio Input Control Service instance. + * @param param Audio Input Control Service register parameters. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_aics_register(esp_ble_audio_aics_t *aics, + esp_ble_audio_aics_register_param_t *param); + +/** + * @brief Activates an Audio Input Control Service instance. + * + * Audio Input Control Services are activated by default, but this will allow + * the server reactivate an Audio Input Control Service instance after it has + * been deactivated. + * + * @param inst The instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_aics_activate(esp_ble_audio_aics_t *inst); + +/** + * @brief Deactivates an Audio Input Control Service instance. + * + * Audio Input Control Services are activated by default, but this will allow + * the server to deactivate an Audio Input Control Service. + * + * @param inst The instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_aics_deactivate(esp_ble_audio_aics_t *inst); + +/** + * @brief Read the Audio Input Control Service input state. + * + * @param inst The instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_aics_state_get(esp_ble_audio_aics_t *inst); + +/** + * @brief Read the Audio Input Control Service gain settings. + * + * @param inst The instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_aics_gain_setting_get(esp_ble_audio_aics_t *inst); + +/** + * @brief Read the Audio Input Control Service input type. + * + * @param inst The instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_aics_type_get(esp_ble_audio_aics_t *inst); + +/** + * @brief Read the Audio Input Control Service input status. + * + * @param inst The instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_aics_status_get(esp_ble_audio_aics_t *inst); + +/** + * @brief Disable mute in the Audio Input Control Service. + * + * @param inst The instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_aics_disable_mute(esp_ble_audio_aics_t *inst); + +/** + * @brief Unmute the Audio Input Control Service input. + * + * @param inst The instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_aics_unmute(esp_ble_audio_aics_t *inst); + +/** + * @brief Mute the Audio Input Control Service input. + * + * @param inst The instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_aics_mute(esp_ble_audio_aics_t *inst); + +/** + * @brief Set manual only gain mode in Audio Input Control Service. + * + * @param inst The instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_aics_gain_set_manual_only(esp_ble_audio_aics_t *inst); + +/** + * @brief Set automatic only gain mode in Audio Input Control Service. + * + * @param inst The instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_aics_gain_set_auto_only(esp_ble_audio_aics_t *inst); + +/** + * @brief Set input gain to manual. + * + * @param inst The instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_aics_manual_gain_set(esp_ble_audio_aics_t *inst); + +/** + * @brief Set the input gain to automatic. + * + * @param inst The instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_aics_automatic_gain_set(esp_ble_audio_aics_t *inst); + +/** + * @brief Set the input gain. + * + * @param inst The instance pointer. + * @param gain The gain to set (-128 to 127) in gain setting units. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_aics_gain_set(esp_ble_audio_aics_t *inst, int8_t gain); + +/** + * @brief Read the Audio Input Control Service description. + * + * @param inst The instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_aics_description_get(esp_ble_audio_aics_t *inst); + +/** + * @brief Set the Audio Input Control Service description. + * + * @param inst The instance pointer. + * @param description The description as an UTF-8 encoded string. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_aics_description_set(esp_ble_audio_aics_t *inst, + const char *description); + +/** + * @brief Discover an Audio Input Control Service. + * + * Attempts to discover an Audio Input Control Service on a server given the + * @p param. + * + * @param conn_handle Connection handle. + * @param inst The instance pointer. + * @param param Pointer to the parameters. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_aics_discover(uint16_t conn_handle, esp_ble_audio_aics_t *inst, + const esp_ble_audio_aics_discover_param_t *param); + +/** + * @brief Get a new Audio Input Control Service client instance. + * + * @return Pointer to the instance, or NULL if no free instances are left. + */ +esp_ble_audio_aics_t *esp_ble_audio_aics_client_free_instance_get(void); + +/** + * @brief Registers the callbacks for the Audio Input Control Service client. + * + * @param inst The instance pointer. + * @param cb Pointer to the callback structure. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_aics_client_cb_register(esp_ble_audio_aics_t *inst, + esp_ble_audio_aics_cb_t *cb); + +#ifdef __cplusplus +} +#endif + +#endif /* ESP_BLE_AUDIO_AICS_API_H_ */ diff --git a/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_bap_api.h b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_bap_api.h new file mode 100644 index 0000000000..394dec325f --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_bap_api.h @@ -0,0 +1,1345 @@ +/* + * SPDX-FileCopyrightText: 2020 Bose Corporation + * SPDX-FileCopyrightText: 2021-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ESP_BLE_AUDIO_BAP_API_H_ +#define ESP_BLE_AUDIO_BAP_API_H_ + +#include +#include +#include + +#include "sdkconfig.h" +#include "esp_err.h" + +#include +#include +#include + +#include "common/init.h" +#include "common/host.h" + +#include "esp_ble_iso_common_api.h" + +#include "esp_ble_audio_codec_api.h" +#include "esp_ble_audio_common_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Check if a BAP BASS BIS_Sync bitfield is valid. + * + * Valid options are either a bitmask of valid BIS indices, including + * none (0x00000000) or no ref (0xFFFFFFFF). + * + * @param _bis_bitfield BIS_Sync bitfield (uint32). + */ +#define ESP_BLE_AUDIO_BAP_BASS_VALID_BIT_BITFIELD(_bis_bitfield) \ + BT_BAP_BASS_VALID_BIT_BITFIELD(_bis_bitfield) + +/** + * @brief Helper to declare elements of BAP QoS Configuration. + * + * @param _interval SDU interval (usec). + * @param _framing Framing. + * @param _phy Target PHY. + * @param _sdu Maximum SDU Size. + * @param _rtn Retransmission number. + * @param _latency Maximum Transport Latency (msec). + * @param _pd Presentation Delay (usec). + */ +#define ESP_BLE_AUDIO_BAP_QOS_CFG(_interval, _framing, _phy, _sdu, _rtn, _latency, _pd) \ + BT_BAP_QOS_CFG(_interval, _framing, _phy, _sdu, _rtn, _latency, _pd) + +/** + * @brief Helper to declare Input Unframed BAP QoS Configuration. + * + * @param _interval SDU interval (usec). + * @param _sdu Maximum SDU Size. + * @param _rtn Retransmission number. + * @param _latency Maximum Transport Latency (msec). + * @param _pd Presentation Delay (usec). + */ +#define ESP_BLE_AUDIO_BAP_QOS_CFG_UNFRAMED(_interval, _sdu, _rtn, _latency, _pd) \ + BT_BAP_QOS_CFG_UNFRAMED(_interval, _sdu, _rtn, _latency, _pd) + +/** + * @brief Helper to declare Input Framed BAP QoS Configuration. + * + * @param _interval SDU interval (usec). + * @param _sdu Maximum SDU Size. + * @param _rtn Retransmission number. + * @param _latency Maximum Transport Latency (msec). + * @param _pd Presentation Delay (usec). + */ +#define ESP_BLE_AUDIO_BAP_QOS_CFG_FRAMED(_interval, _sdu, _rtn, _latency, _pd) \ + BT_BAP_QOS_CFG_FRAMED(_interval, _sdu, _rtn, _latency, _pd) + +/** + * @brief Helper to declare elements of BAP QoS Configuration Preference. + * + * @param _unframed_supported Unframed PDUs supported. + * @param _phy Preferred Target PHY. + * @param _rtn Preferred Retransmission number. + * @param _latency Preferred Maximum Transport Latency (msec). + * @param _pd_min Minimum Presentation Delay (usec). + * @param _pd_max Maximum Presentation Delay (usec). + * @param _pref_pd_min Preferred Minimum Presentation Delay (usec). + * @param _pref_pd_max Preferred Maximum Presentation Delay (usec). + */ +#define ESP_BLE_AUDIO_BAP_QOS_CFG_PREF(_unframed_supported, _phy, _rtn, \ + _latency, _pd_min, _pd_max, \ + _pref_pd_min, _pref_pd_max) \ + BT_BAP_QOS_CFG_PREF(_unframed_supported, _phy, _rtn, \ + _latency, _pd_min, _pd_max, \ + _pref_pd_min, _pref_pd_max) + +/** + * @brief Macro used to initialise the object storing values of + * ASE Control Point notification. + * + * @param c Response Code field. + * @param r Reason field. + */ +#define ESP_BLE_AUDIO_BAP_ASCS_RSP(c, r) BT_BAP_ASCS_RSP(c, r) + +/*!< LE 1M PHY */ +#define ESP_BLE_AUDIO_BAP_QOS_CFG_1M BT_BAP_QOS_CFG_1M +/*!< LE 2M PHY */ +#define ESP_BLE_AUDIO_BAP_QOS_CFG_2M BT_BAP_QOS_CFG_2M +/*!< LE Coded PHY */ +#define ESP_BLE_AUDIO_BAP_QOS_CFG_CODED BT_BAP_QOS_CFG_CODED + +/*!< An invalid Broadcast ID */ +#define ESP_BLE_AUDIO_BAP_INVALID_BROADCAST_ID BT_BAP_INVALID_BROADCAST_ID + +/*!< Value indicating that the periodic advertising interval is unknown */ +#define ESP_BLE_AUDIO_BAP_PA_INTERVAL_UNKNOWN BT_BAP_PA_INTERVAL_UNKNOWN + +/*!< Indicate that the Broadcast Assistant has no preference to which BIS the Scan Delegator syncs to */ +#define ESP_BLE_AUDIO_BAP_BIS_SYNC_NO_PREF BT_BAP_BIS_SYNC_NO_PREF +/*!< BIS sync value indicating that the BIG sync has failed for any reason */ +#define ESP_BLE_AUDIO_BAP_BIS_SYNC_FAILED BT_BAP_BIS_SYNC_FAILED + +/*!< Packets may be framed or unframed */ +#define ESP_BLE_AUDIO_BAP_QOS_CFG_FRAMING_UNFRAMED BT_BAP_QOS_CFG_FRAMING_UNFRAMED +/*!< Packets are always framed */ +#define ESP_BLE_AUDIO_BAP_QOS_CFG_FRAMING_FRAMED BT_BAP_QOS_CFG_FRAMING_FRAMED +/** QoS Framing */ +typedef enum bt_bap_qos_cfg_framing esp_ble_audio_bap_qos_cfg_framing_t; + +/*!< The periodic advertising has not been synchronized */ +#define ESP_BLE_AUDIO_BAP_PA_STATE_NOT_SYNCED BT_BAP_PA_STATE_NOT_SYNCED +/*!< Waiting for SyncInfo from Broadcast Assistant */ +#define ESP_BLE_AUDIO_BAP_PA_STATE_INFO_REQ BT_BAP_PA_STATE_INFO_REQ +/*!< Synchronized to periodic advertising */ +#define ESP_BLE_AUDIO_BAP_PA_STATE_SYNCED BT_BAP_PA_STATE_SYNCED +/*!< Failed to synchronized to periodic advertising */ +#define ESP_BLE_AUDIO_BAP_PA_STATE_FAILED BT_BAP_PA_STATE_FAILED +/*!< No periodic advertising sync transfer receiver from Broadcast Assistant */ +#define ESP_BLE_AUDIO_BAP_PA_STATE_NO_PAST BT_BAP_PA_STATE_NO_PAST +/** Periodic advertising state reported by the Scan Delegator */ +typedef enum bt_bap_pa_state esp_ble_audio_bap_pa_state_t; + +/*!< The Broadcast Isochronous Group not encrypted */ +#define ESP_BLE_AUDIO_BAP_BIG_ENC_STATE_NO_ENC BT_BAP_BIG_ENC_STATE_NO_ENC +/*!< The Broadcast Isochronous Group broadcast code requested */ +#define ESP_BLE_AUDIO_BAP_BIG_ENC_STATE_BCODE_REQ BT_BAP_BIG_ENC_STATE_BCODE_REQ +/*!< The Broadcast Isochronous Group decrypted */ +#define ESP_BLE_AUDIO_BAP_BIG_ENC_STATE_DEC BT_BAP_BIG_ENC_STATE_DEC +/*!< The Broadcast Isochronous Group bad broadcast code */ +#define ESP_BLE_AUDIO_BAP_BIG_ENC_STATE_BAD_CODE BT_BAP_BIG_ENC_STATE_BAD_CODE +/** Broadcast Isochronous Group encryption state reported by the Scan Delegator */ +typedef enum bt_bap_big_enc_state esp_ble_audio_bap_big_enc_state_t; + +/*!< Audio Stream Endpoint Idle state */ +#define ESP_BLE_AUDIO_BAP_EP_STATE_IDLE BT_BAP_EP_STATE_IDLE +/*!< Audio Stream Endpoint Codec Configured state */ +#define ESP_BLE_AUDIO_BAP_EP_STATE_CODEC_CONFIGURED BT_BAP_EP_STATE_CODEC_CONFIGURED +/*!< Audio Stream Endpoint QoS Configured state */ +#define ESP_BLE_AUDIO_BAP_EP_STATE_QOS_CONFIGURED BT_BAP_EP_STATE_QOS_CONFIGURED +/*!< Audio Stream Endpoint Enabling state */ +#define ESP_BLE_AUDIO_BAP_EP_STATE_ENABLING BT_BAP_EP_STATE_ENABLING +/*!< Audio Stream Endpoint Streaming state */ +#define ESP_BLE_AUDIO_BAP_EP_STATE_STREAMING BT_BAP_EP_STATE_STREAMING +/*!< Audio Stream Endpoint Disabling state */ +#define ESP_BLE_AUDIO_BAP_EP_STATE_DISABLING BT_BAP_EP_STATE_DISABLING +/*!< Audio Stream Endpoint Releasing state */ +#define ESP_BLE_AUDIO_BAP_EP_STATE_RELEASING BT_BAP_EP_STATE_RELEASING +/** Endpoint states */ +typedef enum bt_bap_ep_state esp_ble_audio_bap_ep_state_t; + +/*!< No reason */ +#define ESP_BLE_AUDIO_BAP_ASCS_REASON_NONE BT_BAP_ASCS_REASON_NONE +/*!< Codec ID */ +#define ESP_BLE_AUDIO_BAP_ASCS_REASON_CODEC BT_BAP_ASCS_REASON_CODEC +/*!< Codec configuration */ +#define ESP_BLE_AUDIO_BAP_ASCS_REASON_CODEC_DATA BT_BAP_ASCS_REASON_CODEC_DATA +/*!< SDU interval */ +#define ESP_BLE_AUDIO_BAP_ASCS_REASON_INTERVAL BT_BAP_ASCS_REASON_INTERVAL +/*!< Framing */ +#define ESP_BLE_AUDIO_BAP_ASCS_REASON_FRAMING BT_BAP_ASCS_REASON_FRAMING +/*!< PHY */ +#define ESP_BLE_AUDIO_BAP_ASCS_REASON_PHY BT_BAP_ASCS_REASON_PHY +/*!< Maximum SDU size*/ +#define ESP_BLE_AUDIO_BAP_ASCS_REASON_SDU BT_BAP_ASCS_REASON_SDU +/*!< RTN */ +#define ESP_BLE_AUDIO_BAP_ASCS_REASON_RTN BT_BAP_ASCS_REASON_RTN +/*!< Max transport latency */ +#define ESP_BLE_AUDIO_BAP_ASCS_REASON_LATENCY BT_BAP_ASCS_REASON_LATENCY +/*!< Presentation delay */ +#define ESP_BLE_AUDIO_BAP_ASCS_REASON_PD BT_BAP_ASCS_REASON_PD +/*!< Invalid CIS mapping */ +#define ESP_BLE_AUDIO_BAP_ASCS_REASON_CIS BT_BAP_ASCS_REASON_CIS +/** Response Reasons */ +typedef enum bt_bap_ascs_reason esp_ble_audio_bap_ascs_reason_t; + +/*!< Server completed operation successfully */ +#define ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_SUCCESS BT_BAP_ASCS_RSP_CODE_SUCCESS +/*!< Server did not support operation by client */ +#define ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_NOT_SUPPORTED BT_BAP_ASCS_RSP_CODE_NOT_SUPPORTED +/*!< Server rejected due to invalid operation length */ +#define ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_INVALID_LENGTH BT_BAP_ASCS_RSP_CODE_INVALID_LENGTH +/*!< Invalid ASE ID */ +#define ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_INVALID_ASE BT_BAP_ASCS_RSP_CODE_INVALID_ASE +/*!< Invalid ASE state */ +#define ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE +/*!< Invalid operation for direction */ +#define ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_INVALID_DIR BT_BAP_ASCS_RSP_CODE_INVALID_DIR +/*!< Capabilities not supported by server */ +#define ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_CAP_UNSUPPORTED BT_BAP_ASCS_RSP_CODE_CAP_UNSUPPORTED +/*!< Configuration parameters not supported by server */ +#define ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_CONF_UNSUPPORTED BT_BAP_ASCS_RSP_CODE_CONF_UNSUPPORTED +/*!< Configuration parameters rejected by server */ +#define ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_CONF_REJECTED BT_BAP_ASCS_RSP_CODE_CONF_REJECTED +/*!< Invalid Configuration parameters */ +#define ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_CONF_INVALID BT_BAP_ASCS_RSP_CODE_CONF_INVALID +/*!< Unsupported metadata */ +#define ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_METADATA_UNSUPPORTED BT_BAP_ASCS_RSP_CODE_METADATA_UNSUPPORTED +/*!< Metadata rejected by server */ +#define ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_METADATA_REJECTED BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED +/*!< Invalid metadata */ +#define ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_METADATA_INVALID BT_BAP_ASCS_RSP_CODE_METADATA_INVALID +/*!< Server has insufficient resources */ +#define ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_NO_MEM BT_BAP_ASCS_RSP_CODE_NO_MEM +/*!< Unspecified error */ +#define ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_UNSPECIFIED BT_BAP_ASCS_RSP_CODE_UNSPECIFIED +/** Response Status Code */ +typedef enum bt_bap_ascs_rsp_code esp_ble_audio_bap_ascs_rsp_code_t; + +/** Broadcast Audio Source Endpoint (BASE) structure */ +typedef struct bt_bap_base esp_ble_audio_bap_base_t; + +/** Broadcast Audio Source Endpoint (BASE) subgroup structure */ +typedef struct bt_bap_base_subgroup esp_ble_audio_bap_base_subgroup_t; + +/** Codec ID structure for a Broadcast Audio Source Endpoint (BASE) */ +typedef struct bt_bap_base_codec_id esp_ble_audio_bap_base_codec_id_t; + +/** BIS structure for each BIS in a Broadcast Audio Source Endpoint (BASE) subgroup */ +typedef struct bt_bap_base_subgroup_bis esp_ble_audio_bap_base_subgroup_bis_t; + +/** QoS configuration structure */ +typedef struct bt_bap_qos_cfg esp_ble_audio_bap_qos_cfg_t; + +/** Audio Stream Quality of Service Preference structure */ +typedef struct bt_bap_qos_cfg_pref esp_ble_audio_bap_qos_cfg_pref_t; + +/** Audio Endpoint structure */ +typedef struct bt_bap_ep esp_ble_audio_bap_ep_t; + +/** Structure holding information of audio stream endpoint */ +typedef struct bt_bap_ep_info esp_ble_audio_bap_ep_info_t; + +/** Basic Audio Profile stream structure */ +typedef struct bt_bap_stream esp_ble_audio_bap_stream_t; + +/** Stream operation */ +typedef struct bt_bap_stream_ops esp_ble_audio_bap_stream_ops_t; + +/** Structure storing values of fields of ASE Control Point notification */ +typedef struct bt_bap_ascs_rsp esp_ble_audio_bap_ascs_rsp_t; + +/** Struct to hold subgroup specific information for the receive state */ +typedef struct bt_bap_bass_subgroup esp_ble_audio_bap_bass_subgroup_t; + +/** Audio Unicast Group structure */ +typedef struct bt_bap_unicast_group esp_ble_audio_bap_unicast_group_t; + +/** Parameter struct for each stream in the unicast group */ +typedef struct bt_bap_unicast_group_stream_param esp_ble_audio_bap_unicast_group_stream_param_t; + +/** Parameter struct for the unicast group functions */ +typedef struct bt_bap_unicast_group_stream_pair_param esp_ble_audio_bap_unicast_group_stream_pair_param_t; + +/** Parameters for creating unicast groups */ +typedef struct bt_bap_unicast_group_param esp_ble_audio_bap_unicast_group_param_t; + +/** Structure for registering Unicast Server */ +typedef struct bt_bap_unicast_server_register_param esp_ble_audio_bap_unicast_server_register_param_t; + +/** Unicast Server callback structure */ +typedef struct bt_bap_unicast_server_cb esp_ble_audio_bap_unicast_server_cb_t; + +/** Unicast Client callback structure */ +typedef struct bt_bap_unicast_client_cb esp_ble_audio_bap_unicast_client_cb_t; + +/** Broadcast Source advertising information */ +typedef esp_ble_iso_ext_adv_info_t esp_ble_audio_bap_broadcast_adv_info_t; + +/** Broadcast Source callback structure */ +typedef struct bt_bap_broadcast_source_cb esp_ble_audio_bap_broadcast_source_cb_t; + +/** Broadcast Source structure */ +typedef struct bt_bap_broadcast_source esp_ble_audio_bap_broadcast_source_t; + +/** Broadcast Source stream parameters */ +typedef struct bt_bap_broadcast_source_stream_param esp_ble_audio_bap_broadcast_source_stream_param_t; + +/** Broadcast Source subgroup parameters */ +typedef struct bt_bap_broadcast_source_subgroup_param esp_ble_audio_bap_broadcast_source_subgroup_param_t; + +/** Broadcast Source create parameters */ +typedef struct bt_bap_broadcast_source_param esp_ble_audio_bap_broadcast_source_param_t; + +/** Broadcast Sink handle */ +typedef struct bt_bap_broadcast_sink esp_ble_audio_bap_broadcast_sink_t; + +/** Broadcast Audio Sink callback structure */ +typedef struct bt_bap_broadcast_sink_cb esp_ble_audio_bap_broadcast_sink_cb_t; + +/** Struct to hold the Basic Audio Profile Broadcast Assistant callbacks */ +typedef struct bt_bap_broadcast_assistant_cb esp_ble_audio_bap_broadcast_assistant_cb_t; + +/** Parameters for adding a source to a Broadcast Audio Scan Service server */ +typedef struct bt_bap_broadcast_assistant_add_src_param esp_ble_audio_bap_broadcast_assistant_add_src_param_t; + +/** Parameters for modifying a source */ +typedef struct bt_bap_broadcast_assistant_mod_src_param esp_ble_audio_bap_broadcast_assistant_mod_src_param_t; + +/** Struct to hold the Basic Audio Profile Scan Delegator callbacks */ +typedef struct bt_bap_scan_delegator_cb esp_ble_audio_bap_scan_delegator_cb_t; + +/** Represents the Broadcast Audio Scan Service receive state */ +typedef struct bt_bap_scan_delegator_recv_state esp_ble_audio_bap_scan_delegator_recv_state_t; + +/** Parameters for adding a source by Scan Delegator */ +typedef struct bt_bap_scan_delegator_add_src_param esp_ble_audio_bap_scan_delegator_add_src_param_t; + +/** Parameters for modifying a source by Scan Delegator */ +typedef struct bt_bap_scan_delegator_mod_src_param esp_ble_audio_bap_scan_delegator_mod_src_param_t; + +/** + * @brief Register the Unicast Server. + * + * Register the Unicast Server. Only a single Unicast Server can be registered at any one time. + * This will register ASCS in the GATT database. + * + * @param param Registration parameters for ascs. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_unicast_server_register(const esp_ble_audio_bap_unicast_server_register_param_t *param); + +/** + * @brief Unregister the Unicast Server. + * + * Unregister the Unicast Server. + * This will unregister ASCS in the GATT database. + * Before calling this function, any callbacks registered through + * esp_ble_audio_bap_unicast_server_register_cb() needs to be + * unregistered with esp_ble_audio_bap_unicast_server_unregister_cb(). + * + * Calling this function will issue an release operation on any ASE + * in a non-idle state. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_unicast_server_unregister(void); + +/** + * @brief Register unicast server callbacks. + * + * Only one callback structure can be registered, and attempting to + * registering more than one will result in an error. + * Prior to calling this function the Unicast Server needs to be + * registered with esp_ble_audio_bap_unicast_server_register(). + * + * @param cb Unicast server callback structure. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_unicast_server_register_cb(const esp_ble_audio_bap_unicast_server_cb_t *cb); + +/** + * @brief Unregister unicast server callbacks. + * + * May only unregister a callback structure that has previously been + * registered by esp_ble_audio_bap_unicast_server_register_cb(). + * + * Calling this function will issue an release operation on any ASE + * in a non-idle state. + * + * @param cb Unicast server callback structure. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_unicast_server_unregister_cb(const esp_ble_audio_bap_unicast_server_cb_t *cb); + +/** + * @brief Initialize and configure a new ASE. + * + * @param conn_handle Connection handle. + * @param stream Configured stream object to be attached to the ASE. + * @param codec_cfg Codec configuration. + * @param qos_pref Audio Stream Quality of Service Preference. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_unicast_server_config_ase(uint16_t conn_handle, + esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_codec_cfg_t *codec_cfg, + const esp_ble_audio_bap_qos_cfg_pref_t *qos_pref); + +/** + * @brief Create unicast group. + * + * Create a new audio unicast group with one or more audio streams as a unicast client. + * All streams shall share the same framing. + * All streams in the same direction shall share the same interval and latency. + * + * @param param The unicast group create parameters. + * @param unicast_group Pointer to the unicast group created. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_unicast_group_create(esp_ble_audio_bap_unicast_group_param_t *param, + esp_ble_audio_bap_unicast_group_t **unicast_group); + +/** + * @brief Reconfigure unicast group. + * + * Reconfigure a unicast group with one or more audio streams as a unicast client. + * All streams shall share the same framing. + * All streams in the same direction shall share the same interval and latency. + * All streams in @p param shall already belong to @p unicast_group. + * Use esp_ble_audio_bap_unicast_group_add_streams() to add additional streams. + * + * @param unicast_group Pointer to the unicast group created. + * @param param The unicast group reconfigure parameters. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_unicast_group_reconfig(esp_ble_audio_bap_unicast_group_t *unicast_group, + const esp_ble_audio_bap_unicast_group_param_t *param); + +/** + * @brief Add streams to a unicast group as a unicast client. + * + * This function can be used to add additional streams to a BAP unicast group. + * + * This can be called at any time before any of the streams in the group has been started. + * This can also be called after the streams have been stopped. + * + * Once a stream has been added to a unicast group, it cannot be removed. To remove a stream + * from a group, the group must be deleted with esp_ble_audio_bap_unicast_group_delete(), + * but this will require all streams in the group to be released first. + * + * @param unicast_group Pointer to the unicast group. + * @param params Array of stream parameters with streams being added to the group. + * @param num_param Number of parameters in @p params. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_unicast_group_add_streams(esp_ble_audio_bap_unicast_group_t *unicast_group, + esp_ble_audio_bap_unicast_group_stream_pair_param_t params[], + size_t num_param); + +/** + * @brief Delete audio unicast group. + * + * Delete an audio unicast group as a client. All streams in the group shall + * be in the idle or configured state. + * + * @param unicast_group Pointer to the unicast group to delete. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_unicast_group_delete(esp_ble_audio_bap_unicast_group_t *unicast_group); + +/** + * @brief Register unicast client callbacks. + * + * Only one callback structure can be registered, and attempting to + * registering more than one will result in an error. + * + * @param cb Unicast client callback structure. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_unicast_client_register_cb(esp_ble_audio_bap_unicast_client_cb_t *cb); + +/** + * @brief Unregister unicast client callbacks. + * + * @param cb Unicast client callback structure to unregister. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_unicast_client_unregister_cb(esp_ble_audio_bap_unicast_client_cb_t *cb); + +/** + * @brief Discover remote capabilities and endpoints. + * + * This procedure is used by a client to discover remote capabilities and + * endpoints and notifies via params callback. + * + * @param conn_handle Connection handle. + * @param dir The type of remote endpoints and capabilities to discover. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_unicast_client_discover(uint16_t conn_handle, esp_ble_audio_dir_t dir); + +/** + * @brief Configure Audio Stream. + * + * This procedure is used by a client to configure a new stream using the + * remote endpoint, local capability and codec configuration. + * + * @param conn_handle Connection handle. + * @param stream Stream object being configured. + * @param ep Remote Audio Endpoint being configured. + * @param codec_cfg Codec configuration. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_stream_config(uint16_t conn_handle, + esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_bap_ep_t *ep, + esp_ble_audio_codec_cfg_t *codec_cfg); + +/** + * @brief Configure Audio Stream QoS + * + * This procedure is used by a client to configure the Quality of Service of streams in a unicast + * group. All streams in the group for the specified @p conn_handle will have the Quality of Service + * configured. This shall only be used to configure unicast streams. + * + * @param conn_handle Connection handle. + * @param group Unicast group object. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_stream_qos(uint16_t conn_handle, + esp_ble_audio_bap_unicast_group_t *group); + +/** + * @brief Enable Audio Stream. + * + * This procedure is used by a client to enable a stream. + * + * This shall only be called for unicast streams, as broadcast streams + * will always be enabled once created. + * + * @param stream Stream object. + * @param meta Metadata. + * @param meta_len Metadata length. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_stream_enable(esp_ble_audio_bap_stream_t *stream, + const uint8_t meta[], size_t meta_len); + +/** + * @brief Connect unicast audio stream. + * + * This procedure is used by a unicast client to connect the connected isochronous stream (CIS) + * associated with the audio stream. If two audio streams share a CIS, then this only needs to be + * done once for those streams. This can only be done for streams in the QoS configured or enabled + * states. + * + * @param stream Stream object. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_stream_connect(esp_ble_audio_bap_stream_t *stream); + +/** + * @brief Stop Audio Stream. + * + * This procedure is used by a client to make a stream stop streaming. + * + * This shall only be called for unicast streams. + * Broadcast sinks cannot be stopped. + * + * @param stream Stream object. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_stream_stop(esp_ble_audio_bap_stream_t *stream); + +/** + * @brief Reconfigure Audio Stream. + * + * This procedure is used by a unicast client or unicast server to reconfigure + * a stream to use a different local codec configuration. + * + * This can only be done for unicast streams. + * + * @param stream Stream object being reconfigured. + * @param codec_cfg Codec configuration. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_stream_reconfig(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_codec_cfg_t *codec_cfg); + +/** + * @brief Change Audio Stream Metadata. + * + * This procedure is used by a unicast client or unicast server to change the metadata of a stream. + * + * @param stream Stream object. + * @param meta Metadata. + * @param meta_len Metadata length. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_stream_metadata(esp_ble_audio_bap_stream_t *stream, + const uint8_t meta[], size_t meta_len); + +/** + * @brief Disable Audio Stream. + * + * This procedure is used by a unicast client or unicast server to disable a stream. + * + * This shall only be called for unicast streams, as broadcast streams will + * always be enabled once created. + * + * @param stream Stream object. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_stream_disable(esp_ble_audio_bap_stream_t *stream); + +/** + * @brief Start Audio Stream. + * + * This procedure is used by a unicast client or unicast server to make a stream start streaming. + * + * For the unicast client, this will send the receiver start ready command to the unicast server + * for ESP_BLE_AUDIO_DIR_SOURCE ASEs. The CIS is required to be connected first by + * esp_ble_audio_bap_stream_connect() before the command can be sent. + * + * For the unicast server, this will execute the receiver start ready command on the unicast server + * for ESP_BLE_AUDIO_DIR_SINK ASEs. If the CIS is not connected yet, the stream will go into + * the streaming state as soon as the CIS is connected. + * + * This shall only be called for unicast streams. + * + * Broadcast sinks will always be started once synchronized, and broadcast + * source streams shall be started with esp_ble_audio_bap_broadcast_source_start(). + * + * @param stream Stream object. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_stream_start(esp_ble_audio_bap_stream_t *stream); + +/** + * @brief Release Audio Stream. + * + * This procedure is used by a unicast client or unicast server to release a unicast stream. + * + * Broadcast sink streams cannot be released, but can be deleted by + * esp_ble_audio_bap_broadcast_sink_delete(). + * Broadcast source streams cannot be released, but can be deleted by + * esp_ble_audio_bap_broadcast_source_delete(). + * + * @param stream Stream object. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_stream_release(esp_ble_audio_bap_stream_t *stream); + +/** + * @brief Registers callbacks for Broadcast Sources. + * + * @param cb Pointer to the callback structure. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_broadcast_source_register_cb(esp_ble_audio_bap_broadcast_source_cb_t *cb); + +/** + * @brief Unregisters callbacks for Broadcast Sources. + * + * @param cb Pointer to the callback structure. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_broadcast_source_unregister_cb(esp_ble_audio_bap_broadcast_source_cb_t *cb); + +/** + * @brief Create audio broadcast source. + * + * Create a new audio broadcast source with one or more audio streams. + * + * The broadcast source will be visible for scanners once this has been called, + * and the device will advertise audio announcements. + * + * No audio data can be sent until esp_ble_audio_bap_broadcast_source_start() has been called and + * no audio information (BIGInfo) will be visible to scanners. + * + * @param param Pointer to parameters used to create the broadcast source. + * @param source Pointer to the broadcast source created. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_broadcast_source_create(esp_ble_audio_bap_broadcast_source_param_t *param, + esp_ble_audio_bap_broadcast_source_t **source); + +/** + * @brief Reconfigure audio broadcast source. + * + * Reconfigure an audio broadcast source with a new codec and codec quality of + * service parameters. This can only be done when the source is stopped. + * + * Since this may modify the Broadcast Audio Source Endpoint (BASE), + * esp_ble_audio_bap_broadcast_source_get_base() should be called after this to get the new BASE + * information. + * + * If the @p param.params_count is smaller than the number of subgroups that have been created in + * the Broadcast Source, only the first @p param.params_count subgroups are updated. If a stream + * exist in a subgroup not part of @p param, then that stream is left as is (i.e. it is not removed; + * the only way to remove a stream from a Broadcast Source is to recreate the Broadcast Source). + * + * @param source Pointer to the broadcast source. + * @param param Pointer to parameters used to reconfigure the broadcast source. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_broadcast_source_reconfig(esp_ble_audio_bap_broadcast_source_t *source, + esp_ble_audio_bap_broadcast_source_param_t *param); + +/** + * @brief Modify the metadata of an audio broadcast source. + * + * Modify the metadata an audio broadcast source. This can only be done when the source is started. + * To update the metadata in the stopped state, use esp_ble_audio_bap_broadcast_source_reconfig(). + * + * @param source Pointer to the broadcast source. + * @param meta Metadata. + * @param meta_len Length of metadata. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_broadcast_source_update_metadata(esp_ble_audio_bap_broadcast_source_t *source, + const uint8_t meta[], size_t meta_len); + +/** + * @brief Add extended advertising for an audio broadcast source. + * + * @param info Extended advertising information. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_broadcast_adv_add(esp_ble_audio_bap_broadcast_adv_info_t *info); + +/** + * @brief Delete extended advertising for an audio broadcast source. + * + * @param info Extended advertising information. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_broadcast_adv_delete(esp_ble_audio_bap_broadcast_adv_info_t *info); + +/** + * @brief Start audio broadcast source. + * + * Start an audio broadcast source with one or more audio streams. + * The broadcast source will start advertising BIGInfo, and audio data can be streamed. + * + * @param source Pointer to the broadcast source. + * @param adv_handle Handle of an extended advertising set with periodic advertising configured. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_broadcast_source_start(esp_ble_audio_bap_broadcast_source_t *source, + uint8_t adv_handle); + +/** + * @brief Stop audio broadcast source. + * + * Stop an audio broadcast source. + * The broadcast source will stop advertising BIGInfo, and audio data can no longer be streamed. + * + * @param source Pointer to the broadcast source. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_broadcast_source_stop(esp_ble_audio_bap_broadcast_source_t *source); + +/** + * @brief Delete audio broadcast source. + * + * Delete an audio broadcast source. + * The broadcast source will stop advertising entirely, and the source can no longer be used. + * + * @param source Pointer to the broadcast source. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_broadcast_source_delete(esp_ble_audio_bap_broadcast_source_t *source); + +/** + * @brief Get the Broadcast Audio Stream Endpoint of a broadcast source. + * + * This will encode the BASE of a broadcast source into a buffer, that can be used for + * advertisement. The encoded BASE will thus be encoded as little-endian. The BASE shall be + * put into the periodic advertising data. + * + * See table 3.15 in the Basic Audio Profile v1.0.1 for the structure. + * + * @param source Pointer to the broadcast source. + * @param base_buf Pointer to a buffer where the BASE will be inserted. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_broadcast_source_get_base(esp_ble_audio_bap_broadcast_source_t *source, + struct net_buf_simple *base_buf); + +/** + * @brief Register Broadcast sink callbacks. + * + * It is possible to register multiple struct of callbacks, but a single struct can only be + * registered once. + * Registering the same callback multiple times is undefined behavior and may break the stack. + * + * @param cb Broadcast sink callback structure. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_broadcast_sink_register_cb(esp_ble_audio_bap_broadcast_sink_cb_t *cb); + +/** + * @brief Create a Broadcast Sink from a periodic advertising sync. + * + * This should only be done after verifying that the periodic advertising sync + * is from a Broadcast Source. + * + * The created Broadcast Sink will need to be supplied to + * esp_ble_audio_bap_broadcast_sink_sync() in order to synchronize to the broadcast audio. + * + * @param sync_handle Sync handle. + * @param broadcast_id 24-bit broadcast ID. + * @param sink Pointer to the Broadcast Sink created. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_broadcast_sink_create(uint16_t sync_handle, + uint32_t broadcast_id, + esp_ble_audio_bap_broadcast_sink_t **sink); + +/** + * @brief Sync to a broadcaster's audio. + * + * @param sink Pointer to the sink object from the base_recv callback. + * @param indexes_bitfield Bitfield of the BIS index to sync to. To sync to e.g. BIS index 1 and + * 2, this should have the value of BIT(1) | BIT(2). + * @param streams Stream object pointers to be used for the receiver. If multiple BIS + * indexes shall be synchronized, multiple streams shall be provided. + * @param broadcast_code The 16-octet broadcast code. Shall be supplied if the broadcast is + * encrypted. + * If the value is a string or a the value is less + * than 16 octets, the remaining octets shall be 0. + * + * Example: + * The string "Broadcast Code" shall be + * [42 72 6F 61 64 63 61 73 74 20 43 6F 64 65 00 00] + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_broadcast_sink_sync(esp_ble_audio_bap_broadcast_sink_t *sink, + uint32_t indexes_bitfield, + esp_ble_audio_bap_stream_t *streams[], + const uint8_t broadcast_code[ESP_BLE_ISO_BROADCAST_CODE_SIZE]); + +/** + * @brief Stop audio broadcast sink. + * + * Stop an audio broadcast sink. + * The broadcast sink will stop receiving BIGInfo, and audio data can no longer be streamed. + * + * @param sink Pointer to the broadcast sink. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_broadcast_sink_stop(esp_ble_audio_bap_broadcast_sink_t *sink); + +/** + * @brief Release a broadcast sink. + * + * Once a broadcast sink has been allocated, it can be deleted using this function. + * If the sink has synchronized to any broadcast audio streams, these must first be + * stopped using esp_ble_audio_bap_stream_stop. + * + * @param sink Pointer to the sink object to delete. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_broadcast_sink_delete(esp_ble_audio_bap_broadcast_sink_t *sink); + +/** + * @brief Register the Basic Audio Profile Scan Delegator and BASS. + * + * Register the scan delegator and Broadcast Audio Scan Service (BASS) + * dynamically at runtime. + * + * Only one set of callbacks can be registered at any one time, and calling this + * function multiple times will override any previously registered callbacks. + * + * @param cb Pointer to the callback struct. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_scan_delegator_register(esp_ble_audio_bap_scan_delegator_cb_t *cb); + +/** + * @brief Unregister the Basic Audio Profile Scan Delegator and BASS. + * + * Unregister the scan delegator and Broadcast Audio Scan Service (BASS) + * dynamically at runtime. + * + * @return ESP_OK on success, or an error code on failure. + * + */ +esp_err_t esp_ble_audio_bap_scan_delegator_unregister(void); + +/** + * @brief Set the periodic advertising sync state to syncing. + * + * Set the periodic advertising sync state for a receive state to syncing, + * notifying Broadcast Assistants. + * + * @param src_id The source id used to identify the receive state. + * @param pa_state The Periodic Advertising sync state to set. + * ESP_BLE_AUDIO_BAP_PA_STATE_NOT_SYNCED and + * ESP_BLE_AUDIO_BAP_PA_STATE_SYNCED is not necessary + * to provide, as they are handled internally. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_scan_delegator_set_pa_state(uint8_t src_id, + esp_ble_audio_bap_pa_state_t pa_state); + +/** + * @brief Set the sync state of a receive state in the server. + * + * @param src_id The source id used to identify the receive state. + * @param bis_synced Array of bitfields to set the BIS sync state for each subgroup. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_scan_delegator_set_bis_sync_state(uint8_t src_id, + uint32_t bis_synced[CONFIG_BT_BAP_BASS_MAX_SUBGROUPS]); + +/** + * @brief Add a receive state source locally. + * + * This will notify any connected clients about the new source. This allows them + * to modify and even remove it. + * + * @param param The parameters for adding the new source. + * @param src_id Source ID on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_scan_delegator_add_src(const esp_ble_audio_bap_scan_delegator_add_src_param_t *param, + uint8_t *src_id); + +/** + * @brief Modify a receive state source. + * + * This will modify the receive state. + * + * @param param The parameters for modifying the source. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_scan_delegator_mod_src(const esp_ble_audio_bap_scan_delegator_mod_src_param_t *param); + +/** + * @brief Remove a receive state source. + * + * This will remove the receive state. + * + * @param src_id The source ID to remove. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_scan_delegator_rem_src(uint8_t src_id); + +/** + * @brief Discover Broadcast Audio Scan Service on the server. + * + * Warning: Only one connection can be active at any time; discovering for + * a new connection, will delete all previous data. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_broadcast_assistant_discover(uint16_t conn_handle); + +/** + * @brief Scan start for BISes for a remote server. + * + * This will let the Broadcast Audio Scan Service server know that this device + * is actively scanning for broadcast sources. + * The function can optionally also start scanning, if the caller does not want + * to start scanning itself. + * + * @param conn_handle Connection handle. + * @param start_scan Start scanning if true. If false, the application should + * enable scan itself. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_broadcast_assistant_scan_start(uint16_t conn_handle, bool start_scan); + +/** + * @brief Stop remote scanning for BISes for a server. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_broadcast_assistant_scan_stop(uint16_t conn_handle); + +/** + * @brief Registers the callbacks used by Broadcast Audio Scan Service client. + * + * @param cb The callback structure. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_broadcast_assistant_register_cb(esp_ble_audio_bap_broadcast_assistant_cb_t *cb); + +/** + * @brief Unregisters the callbacks used by the Broadcast Audio Scan Service client. + * + * @param cb The callback structure. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_broadcast_assistant_unregister_cb(esp_ble_audio_bap_broadcast_assistant_cb_t *cb); + +/** + * @brief Add a source on the server. + * + * @param conn_handle Connection handle. + * @param param Parameter struct. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_broadcast_assistant_add_src(uint16_t conn_handle, + const esp_ble_audio_bap_broadcast_assistant_add_src_param_t *param); + +/** + * @brief Modify a source on the server. + * + * @param conn_handle Connection handle. + * @param param Parameter struct. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_broadcast_assistant_mod_src(uint16_t conn_handle, + const esp_ble_audio_bap_broadcast_assistant_mod_src_param_t *param); + +/** + * @brief Set a broadcast code to the specified receive state. + * + * @param conn_handle Connection handle. + * @param src_id Source ID of the receive state. + * @param broadcast_code The broadcast code. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_broadcast_assistant_set_broadcast_code(uint16_t conn_handle, uint8_t src_id, + const uint8_t broadcast_code[ESP_BLE_ISO_BROADCAST_CODE_SIZE]); + +/** + * @brief Remove a source from the server. + * + * @param conn_handle Connection handle. + * @param src_id Source ID of the receive state. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_broadcast_assistant_rem_src(uint16_t conn_handle, uint8_t src_id); + +/** + * @brief Read the specified receive state from the server. + * + * @param conn_handle Connection handle. + * @param idx The index of the receive start. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_broadcast_assistant_read_recv_state(uint16_t conn_handle, uint8_t idx); + +/** + * @brief Return structure holding information of audio stream endpoint. + * + * @param ep The audio stream endpoint object. + * @param info The structure object to be filled with the info. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_ep_get_info(const esp_ble_audio_bap_ep_t *ep, + esp_ble_audio_bap_ep_info_t *info); + +/** + * @brief Register Audio callbacks for a stream. + * + * Register Audio callbacks for a stream. + * + * @param stream Stream object. + * @param ops Stream operations structure. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_stream_cb_register(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_bap_stream_ops_t *ops); + +/** + * @brief Send data to Audio stream without timestamp. + * + * Send data from buffer to the stream. + * + * @param stream Stream object. + * @param sdu Buffer containing data to be sent. + * @param sdu_len length of data to be sent. + * @param seq_num Packet Sequence number. This value shall be incremented for each call to this + * function and at least once per SDU interval for a specific channel. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_stream_send(esp_ble_audio_bap_stream_t *stream, + const uint8_t *sdu, uint16_t sdu_len, + uint16_t seq_num); + +/** + * @brief Send data to Audio stream with timestamp. + * + * @param stream Stream object. + * @param sdu Buffer containing data to be sent. + * @param sdu_len length of data to be sent. + * @param seq_num Packet Sequence number. This value shall be incremented for each call to this + * function and at least once per SDU interval for a specific channel. + * @param ts Timestamp of the SDU in microseconds (us). This value can be used to transmit + * multiple SDUs in the same SDU interval in a CIG or BIG. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_stream_send_ts(esp_ble_audio_bap_stream_t *stream, + const uint8_t *sdu, uint16_t sdu_len, + uint16_t seq_num, uint32_t ts); + +/** + * @brief Get ISO transmission timing info for a Basic Audio Profile stream. + * + * Reads timing information for transmitted ISO packet on an ISO channel. + * The HCI_LE_Read_ISO_TX_Sync HCI command is used to retrieve this information from the controller. + * + * @note An SDU must have already been successfully transmitted on the ISO channel + * for this function to return successfully. + * + * @param stream Stream object. + * @param info Transmit info object. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_stream_get_tx_sync(esp_ble_audio_bap_stream_t *stream, + esp_ble_iso_tx_info_t *info); + +/** + * @brief Generate a pointer to a BASE from periodic advertising data + * + * @param data_type Type of the periodic advertising data. + * @param data Pointer of the periodic advertising data. + * @param data_len Length of the periodic advertising data. + * + * @return NULL if the data does not contain a BASE. + * Pointer to an esp_ble_audio_bap_base_t structure. + */ +const esp_ble_audio_bap_base_t * +esp_ble_audio_bap_base_get_base_from_ad(uint8_t data_type, const uint8_t *data, uint8_t data_len); + +/** + * @brief Get the size of a BASE. + * + * @param base The BASE pointer. + * @param base_size The size of the BASE on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_base_get_size(const esp_ble_audio_bap_base_t *base, + size_t *base_size); + +/** + * @brief Get the presentation delay value of a BASE. + * + * @param base The BASE pointer. + * @param pres_delay The 24-bit presentation delay value on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_base_get_pres_delay(const esp_ble_audio_bap_base_t *base, + uint32_t *pres_delay); + +/** + * @brief Get the subgroup count of a BASE. + * + * @param base The BASE pointer. + * @param subgroup_count The 8-bit subgroup count value on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_base_get_subgroup_count(const esp_ble_audio_bap_base_t *base, + uint8_t *subgroup_count); + +/** + * @brief Get all BIS indexes of a BASE. + * + * @param base The BASE pointer. + * @param bis_indexes 32-bit BIS index bitfield that will be populated. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_base_get_bis_indexes(const esp_ble_audio_bap_base_t *base, + uint32_t *bis_indexes); + +/** + * @brief Iterate on all subgroups in the BASE. + * + * @param base The BASE pointer. + * @param func Callback function. Return true to continue iterating, or false to stop. + * @param user_data User data supplied to @p func. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_base_foreach_subgroup(const esp_ble_audio_bap_base_t *base, + bool (*func)(const esp_ble_audio_bap_base_subgroup_t *subgroup, + void *user_data), + void *user_data); + +/** + * @brief Get the codec ID of a subgroup. + * + * @param subgroup The subgroup pointer. + * @param codec_id Pointer to the struct where the results are placed. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_base_get_subgroup_codec_id(const esp_ble_audio_bap_base_subgroup_t *subgroup, + esp_ble_audio_bap_base_codec_id_t *codec_id); + +/** + * @brief Get the codec configuration data of a subgroup. + * + * @param subgroup The subgroup pointer. + * @param data Pointer that will point to the resulting codec configuration data. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_base_get_subgroup_codec_data(const esp_ble_audio_bap_base_subgroup_t *subgroup, + uint8_t **data); + +/** + * @brief Get the codec metadata of a subgroup. + * + * @param subgroup The subgroup pointer. + * @param meta Pointer that will point to the resulting codec metadata. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_base_get_subgroup_codec_meta(const esp_ble_audio_bap_base_subgroup_t *subgroup, + uint8_t **meta); + +/** + * @brief Store subgroup codec data in a esp_ble_audio_codec_cfg_t. + * + * @param subgroup The subgroup pointer. + * @param codec_cfg Pointer to the struct where the results are placed. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_base_subgroup_codec_to_codec_cfg(const esp_ble_audio_bap_base_subgroup_t *subgroup, + esp_ble_audio_codec_cfg_t *codec_cfg); + +/** + * @brief Get the BIS count of a subgroup. + * + * @param subgroup The subgroup pointer. + * @param bis_count The 8-bit BIS count value on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_base_get_subgroup_bis_count(const esp_ble_audio_bap_base_subgroup_t *subgroup, + uint8_t *bis_count); + +/** + * @brief Get all BIS indexes of a subgroup. + * + * @param subgroup The subgroup pointer. + * @param bis_indexes 32-bit BIS index bitfield that will be populated. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_base_subgroup_get_bis_indexes(const esp_ble_audio_bap_base_subgroup_t *subgroup, + uint32_t *bis_indexes); + +/** + * @brief Iterate on all BIS in the subgroup. + * + * @param subgroup The subgroup pointer. + * @param func Callback function. Return true to continue iterating, or false to stop. + * @param user_data User data supplied to @p func. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_base_subgroup_foreach_bis(const esp_ble_audio_bap_base_subgroup_t *subgroup, + bool (*func)(const esp_ble_audio_bap_base_subgroup_bis_t *bis, + void *user_data), + void *user_data); + +/** + * @brief Store BIS codec configuration data in a esp_ble_audio_codec_cfg_t. + * + * This only sets the esp_ble_audio_codec_cfg_t data and esp_ble_audio_codec_cfg_t + * data_len, but is useful to use the BIS codec configuration data with the + * esp_ble_audio_codec_cfg_* functions. + * + * @param bis The BIS pointer. + * @param codec_cfg Pointer to the struct where the results are placed. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_bap_base_subgroup_bis_codec_to_codec_cfg(const esp_ble_audio_bap_base_subgroup_bis_t *bis, + esp_ble_audio_codec_cfg_t *codec_cfg); + +#ifdef __cplusplus +} +#endif + +#endif /* ESP_BLE_AUDIO_BAP_API_H_ */ diff --git a/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_bap_lc3_preset_defs.h b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_bap_lc3_preset_defs.h new file mode 100644 index 0000000000..bc5ed17566 --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_bap_lc3_preset_defs.h @@ -0,0 +1,967 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFS_H_ +#define ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFS_H_ + +#include "sdkconfig.h" + +#include + +#include "esp_ble_audio_lc3_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Struct to hold a BAP defined LC3 preset */ +typedef struct bt_bap_lc3_preset esp_ble_audio_bap_lc3_preset_t; + +/*!< Helper to declare an LC3 preset structure */ +#define ESP_BLE_AUDIO_BAP_LC3_PRESET(_codec, _qos) \ + BT_BAP_LC3_PRESET(_codec, _qos) + +/** + * @brief Define an LC3 preset configuration. + * + * @param _name Preset configuration name. + * @param _freq Sample frequency (in Hz). + * @param _duration Frame duration (in microseconds). + * @param _loc Audio channel location. + * @param _len Frame length in octets. + * @param _frames_per_sdu Number of frames per SDU. + * @param _stream_context Stream context (e.g., Media, Conversational, etc.). + * @param _interval Audio frame interval (in microseconds). + * @param _sdu SDU size in octets. + * @param _rtn Number of retransmissions. + * @param _latency Maximum transport latency (in milliseconds). + * @param _pd Presentation delay (in microseconds). + */ +#define ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, _freq, _duration, _loc, _len, \ + _frames_per_sdu, _stream_context, \ + _interval, _sdu, _rtn, _latency, _pd) \ + static uint8_t codec_cfg_data_##_name[] = \ + ESP_BLE_AUDIO_CODEC_CFG_LC3_DATA(_freq, _duration, _loc, _len, _frames_per_sdu); \ + static uint8_t codec_cfg_meta_##_name[] = \ + ESP_BLE_AUDIO_CODEC_CFG_LC3_META(_stream_context); \ + static esp_ble_audio_bap_lc3_preset_t _name = \ + ESP_BLE_AUDIO_BAP_LC3_PRESET(ESP_BLE_AUDIO_CODEC_CFG_LC3(codec_cfg_data_##_name, \ + codec_cfg_meta_##_name), \ + ESP_BLE_AUDIO_BAP_QOS_CFG_UNFRAMED(_interval, _sdu, _rtn, \ + _latency, _pd)); + +/** + * @brief Helper to declare LC3 Unicast 8_1_1 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_8_1_1_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_8KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 26u, 1, \ + _stream_context, \ + 7500u, 26u, 2u, 8u, 40000u) + +/** + * @brief Helper to declare LC3 Unicast 8_2_1 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_8_2_1_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_8KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 30U, 1, \ + _stream_context, \ + 10000u, 30u, 2u, 10u, 40000u) + +/** + * @brief Helper to declare LC3 Unicast 16_1_1 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_16_1_1_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_16KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 30U, 1, \ + _stream_context, \ + 7500u, 30u, 2u, 8u, 40000u) + +/** + * @brief Helper to declare LC3 Unicast 16_2_1 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_16_2_1_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_16KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 40U, 1, \ + _stream_context, \ + 10000u, 40u, 2u, 10u, 40000u) + +/** + * @brief Helper to declare LC3 Unicast 24_1_1 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_24_1_1_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_24KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 45U, 1, \ + _stream_context, \ + 7500u, 45u, 2u, 8u, 40000u) + +/** + * @brief Helper to declare LC3 Unicast 24_2_1 codec configuration. + * + * Mandatory to support as unicast server. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_24_2_1_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_24KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 60U, 1, \ + _stream_context, \ + 10000u, 60u, 2u, 10u, 40000u) + +/** + * @brief Helper to declare LC3 Unicast 32_1_1 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_32_1_1_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 60U, 1, \ + _stream_context, \ + 7500u, 60u, 2u, 8u, 40000u) + +/** + * @brief Helper to declare LC3 Unicast 32_2_1 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_32_2_1_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 80U, 1, \ + _stream_context, \ + 10000u, 80u, 2u, 10u, 40000u) + +/** + * @brief Helper to declare LC3 Unicast 441_1_1 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_441_1_1_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_44KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 97U, 1, \ + _stream_context, \ + 8163u, 97u, 5u, 24u, 40000u) + +/** + * @brief Helper to declare LC3 Unicast 441_2_1 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_441_2_1_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_44KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 130U, 1, \ + _stream_context, \ + 10884u, 130u, 5u, 31u, 40000u) + +/** + * @brief Helper to declare LC3 Unicast 48_1_1 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_48_1_1_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 75U, 1, \ + _stream_context, \ + 7500u, 75u, 5u, 15u, 40000u) + +/** + * @brief Helper to declare LC3 Unicast 48_2_1 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_48_2_1_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 100U, 1, \ + _stream_context, \ + 10000u, 100u, 5u, 20u, 40000u) + +/** + * @brief Helper to declare LC3 Unicast 48_3_1 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_48_3_1_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 90U, 1, \ + _stream_context, \ + 7500u, 90u, 5u, 15u, 40000u) + +/** + * @brief Helper to declare LC3 Unicast 48_4_1 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_48_4_1_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 120u, 1, \ + _stream_context, \ + 10000u, 120u, 5u, 20u, 40000u) + +/** + * @brief Helper to declare LC3 Unicast 48_5_1 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_48_5_1_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 117u, 1, \ + _stream_context, \ + 7500u, 117u, 5u, 15u, 40000u) + +/** + * @brief Helper to declare LC3 Unicast 48_6_1 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_48_6_1_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 155u, 1, \ + _stream_context, \ + 10000u, 155u, 5u, 20u, 40000u) + +/** + * @brief Helper to declare LC3 Unicast 8_1_2 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_8_1_2_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_8KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 26u, 1, \ + _stream_context, \ + 7500u, 26u, 13u, 75u, 40000u) + +/** + * @brief Helper to declare LC3 Unicast 8_2_2 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_8_2_2_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_8KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 30U, 1, \ + _stream_context, \ + 10000u, 30u, 13u, 95u, 40000u) + +/** + * @brief Helper to declare LC3 Unicast 16_1_2 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_16_1_2_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_16KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 30U, 1, \ + _stream_context, \ + 7500u, 30u, 13u, 75u, 40000u) + +/** + * @brief Helper to declare LC3 Unicast 16_2_2 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_16_2_2_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_16KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 40U, 1, \ + _stream_context, \ + 10000u, 40u, 13u, 95u, 40000u) + +/** + * @brief Helper to declare LC3 Unicast 24_1_2 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_24_1_2_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_24KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 45U, 1, \ + _stream_context, \ + 7500u, 45u, 13u, 75u, 40000u) + +/** + * @brief Helper to declare LC3 Unicast 24_2_2 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_24_2_2_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_24KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 60U, 1, \ + _stream_context, \ + 10000u, 60u, 13u, 95u, 40000u) + +/** + * @brief Helper to declare LC3 Unicast 32_1_2 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_32_1_2_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 60U, 1, \ + _stream_context, \ + 7500u, 60u, 13u, 75u, 40000u) + +/** + * @brief Helper to declare LC3 Unicast 32_2_2 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_32_2_2_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 80U, 1, \ + _stream_context, \ + 10000u, 80u, 13u, 95u, 40000u) + +/** + * @brief Helper to declare LC3 Unicast 441_1_2 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_441_1_2_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_44KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 97U, 1, \ + _stream_context, \ + 8163u, 97u, 13u, 80u, 40000u) + +/** + * @brief Helper to declare LC3 Unicast 441_2_2 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_441_2_2_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_44KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 130U, 1, \ + _stream_context, \ + 10884u, 130u, 13u, 85u, 40000u) + +/** + * @brief Helper to declare LC3 Unicast 48_1_2 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_48_1_2_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 75U, 1, \ + _stream_context, \ + 7500u, 75u, 13u, 75u, 40000u) + +/** + * @brief Helper to declare LC3 Unicast 48_2_2 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_48_2_2_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 100U, 1, \ + _stream_context, \ + 10000u, 100u, 13u, 95u, 40000u) + +/** + * @brief Helper to declare LC3 Unicast 48_3_2 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_48_3_2_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 90U, 1, \ + _stream_context, \ + 7500u, 90u, 13u, 75u, 40000u) + +/** + * @brief Helper to declare LC3 Unicast 48_4_2 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_48_4_2_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 120u, 1, \ + _stream_context, \ + 10000u, 120u, 13u, 100u, 40000u) + +/** + * @brief Helper to declare LC3 Unicast 48_5_2 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_48_5_2_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 117u, 1, \ + _stream_context, \ + 7500u, 117u, 13u, 75u, 40000u) + +/** + * @brief Helper to declare LC3 Unicast 48_6_2 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_48_6_2_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 155u, 1, \ + _stream_context, \ + 10000u, 155u, 13u, 100u, 40000u) + +/** + * @brief Helper to declare LC3 Broadcast 8_1_1 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_8_1_1_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_8KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 26u, 1, \ + _stream_context, \ + 7500u, 26u, 2u, 8u, 40000u) + +/** + * @brief Helper to declare LC3 Broadcast 8_2_1 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_8_2_1_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_8KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 30U, 1, \ + _stream_context, \ + 10000u, 30u, 2u, 10u, 40000u) + +/** + * @brief Helper to declare LC3 Broadcast 16_1_1 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_16_1_1_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_16KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 30U, 1, \ + _stream_context, \ + 7500u, 30u, 2u, 8u, 40000u) + +/** + * @brief Helper to declare LC3 Broadcast 16_2_1 codec configuration. + * + * Mandatory to support as both broadcast source and sink. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_16_2_1_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_16KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 40U, 1, \ + _stream_context, \ + 10000u, 40u, 2u, 10u, 40000u) + +/** + * @brief Helper to declare LC3 Broadcast 24_1_1 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_24_1_1_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_24KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 45U, 1, \ + _stream_context, \ + 7500u, 45u, 2u, 8u, 40000u) + +/** + * @brief Helper to declare LC3 Broadcast 24_2_1 codec configuration. + * + * Mandatory to support as broadcast sink. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_24_2_1_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_24KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 60U, 1, \ + _stream_context, \ + 10000u, 60u, 2u, 10u, 40000u) + +/** + * @brief Helper to declare LC3 Broadcast 32_1_1 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_32_1_1_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 60U, 1, \ + _stream_context, \ + 7500u, 60u, 2u, 8u, 40000u) + +/** + * @brief Helper to declare LC3 Broadcast 32_2_1 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_32_2_1_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 80U, 1, \ + _stream_context, \ + 10000u, 80u, 2u, 10u, 40000u) + +/** + * @brief Helper to declare LC3 Broadcast 441_1_1 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_441_1_1_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_44KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 97U, 1, \ + _stream_context, \ + 8163u, 97u, 4u, 24u, 40000u) + +/** + * @brief Helper to declare LC3 Broadcast 441_2_1 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_441_2_1_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_44KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 130U, 1, \ + _stream_context, \ + 10884u, 130u, 4u, 31u, 40000u) + +/** + * @brief Helper to declare LC3 Broadcast 48_1_1 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_48_1_1_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 75U, 1, \ + _stream_context, \ + 7500u, 75u, 4u, 15u, 40000u) + +/** + * @brief Helper to declare LC3 Broadcast 48_2_1 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_48_2_1_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 100U, 1, \ + _stream_context, \ + 10000u, 100u, 4u, 20u, 40000u) + +/** + * @brief Helper to declare LC3 Broadcast 48_3_1 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_48_3_1_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 90U, 1, \ + _stream_context, \ + 7500u, 90u, 4u, 15u, 40000u) + +/** + * @brief Helper to declare LC3 Broadcast 48_4_1 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_48_4_1_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 120u, 1, \ + _stream_context, \ + 10000u, 120u, 4u, 20u, 40000u) + +/** + * @brief Helper to declare LC3 Broadcast 48_5_1 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_48_5_1_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 117u, 1, \ + _stream_context, \ + 7500u, 117u, 4u, 15u, 40000u) + +/** + * @brief Helper to declare LC3 Broadcast 48_6_1 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_48_6_1_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 155u, 1, \ + _stream_context, \ + 10000u, 155u, 4u, 20u, 40000u) + +/** + * @brief Helper to declare LC3 Broadcast 8_1_2 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_8_1_2_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_8KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 26u, 1, \ + _stream_context, \ + 7500u, 26u, 4u, 45u, 40000u) + +/** + * @brief Helper to declare LC3 Broadcast 8_2_2 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_8_2_2_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_8KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 30U, 1, \ + _stream_context, \ + 10000u, 30u, 4u, 60u, 40000u) + +/** + * @brief Helper to declare LC3 Broadcast 16_1_2 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_16_1_2_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_16KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 30U, 1, \ + _stream_context, \ + 7500u, 30u, 4u, 45u, 40000u) + +/** + * @brief Helper to declare LC3 Broadcast 16_2_2 codec configuration. + * + * Mandatory to support as both broadcast source and sink. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_16_2_2_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_16KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 40U, 1, \ + _stream_context, \ + 10000u, 40u, 4u, 60u, 40000u) + +/** + * @brief Helper to declare LC3 Broadcast 24_1_2 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_24_1_2_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_24KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 45U, 1, \ + _stream_context, \ + 7500u, 45u, 4u, 45u, 40000u) + +/** + * @brief Helper to declare LC3 Broadcast 24_2_2 codec configuration. + * + * Mandatory to support as broadcast sink. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_24_2_2_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_24KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 60U, 1, \ + _stream_context, \ + 10000u, 60u, 4u, 60u, 40000u) + +/** + * @brief Helper to declare LC3 Broadcast 32_1_2 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_32_1_2_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 60U, 1, \ + _stream_context, \ + 7500u, 60u, 4u, 45u, 40000u) + +/** + * @brief Helper to declare LC3 Broadcast 32_2_2 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_32_2_2_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 80U, 1, \ + _stream_context, \ + 10000u, 80u, 4u, 60u, 40000u) + +/** + * @brief Helper to declare LC3 Broadcast 441_1_2 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_441_1_2_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_44KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 97U, 1, \ + _stream_context, \ + 8163u, 97u, 4u, 54u, 40000u) + +/** + * @brief Helper to declare LC3 Broadcast 441_2_2 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_441_2_2_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_44KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 130U, 1, \ + _stream_context, \ + 10884u, 130u, 4u, 60u, 40000u) + +/** + * @brief Helper to declare LC3 Broadcast 48_1_2 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_48_1_2_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 75U, 1, \ + _stream_context, \ + 7500u, 75u, 4u, 50u, 40000u) + +/** + * @brief Helper to declare LC3 Broadcast 48_2_2 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_48_2_2_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 100U, 1, \ + _stream_context, \ + 10000u, 100u, 4u, 65u, 40000u) + +/** + * @brief Helper to declare LC3 Broadcast 48_3_2 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_48_3_2_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 90U, 1, \ + _stream_context, \ + 7500u, 90u, 4u, 50u, 40000u) + +/** + * @brief Helper to declare LC3 Broadcast 48_4_2 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_48_4_2_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 120u, 1, \ + _stream_context, \ + 10000u, 120u, 4u, 65u, 40000u) + +/** + * @brief Helper to declare LC3 Broadcast 48_5_2 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_48_5_2_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 117u, 1, \ + _stream_context, \ + 7500u, 117u, 4u, 50u, 40000u) + +/** + * @brief Helper to declare LC3 Broadcast 48_6_2 codec configuration. + * + * @param _loc Audio channel location bitfield. + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_48_6_2_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 155u, 1, \ + _stream_context, \ + 10000u, 155u, 4u, 65u, 40000u) + +#ifdef __cplusplus +} +#endif + +#endif /* ESP_BLE_AUDIO_BAP_LC3_PRESET_DEFS_H_ */ diff --git a/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_cap_api.h b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_cap_api.h new file mode 100644 index 0000000000..738c4dcabb --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_cap_api.h @@ -0,0 +1,659 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ESP_BLE_AUDIO_CAP_API_H_ +#define ESP_BLE_AUDIO_CAP_API_H_ + +#include +#include +#include + +#include "sdkconfig.h" +#include "esp_err.h" + +#include +#include + +#include "common/init.h" +#include "common/host.h" + +#include "esp_ble_audio_bap_api.h" +#include "esp_ble_audio_csip_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*!< The set is an ad-hoc set */ +#define ESP_BLE_AUDIO_CAP_SET_TYPE_AD_HOC BT_CAP_SET_TYPE_AD_HOC +/*!< The set is a CSIP Coordinated Set */ +#define ESP_BLE_AUDIO_CAP_SET_TYPE_CSIP BT_CAP_SET_TYPE_CSIP +/** Type of CAP set */ +typedef enum bt_cap_set_type esp_ble_audio_cap_set_type_t; + +/** Common Audio Profile stream structure */ +typedef struct bt_cap_stream esp_ble_audio_cap_stream_t; + +/** Common Audio Broadcast Source structure */ +typedef struct bt_cap_broadcast_source esp_ble_audio_cap_broadcast_source_t; + +/** Common Audio Unicast Group structure */ +typedef struct bt_cap_unicast_group esp_ble_audio_cap_unicast_group_t; + +/** Callback structure for CAP procedures */ +typedef struct bt_cap_initiator_cb esp_ble_audio_cap_initiator_cb_t; + +/** Union represents a Common Audio Set member that are either in a Coordinated or ad-hoc set */ +typedef union bt_cap_set_member esp_ble_audio_cap_set_member_t; + +/** Parameter structure for each stream in the unicast group */ +typedef struct bt_cap_unicast_group_stream_param \ + esp_ble_audio_cap_unicast_group_stream_param_t; + +/* Parameter structure for the unicast group functions */ +typedef struct bt_cap_unicast_group_stream_pair_param \ + esp_ble_audio_cap_unicast_group_stream_pair_param_t; + +/** Parameters for the creating unicast groups */ +typedef struct bt_cap_unicast_group_param \ + esp_ble_audio_cap_unicast_group_param_t; + +/** CAP unicast audio stream specific parameters for starting audio */ +typedef struct bt_cap_unicast_audio_start_stream_param \ + esp_ble_audio_cap_unicast_audio_start_stream_param_t; + +/** CAP unicast audio specific parameters for starting audio */ +typedef struct bt_cap_unicast_audio_start_param \ + esp_ble_audio_cap_unicast_audio_start_param_t; + +/** CAP unicast audio stream specific parameters for updating audio */ +typedef struct bt_cap_unicast_audio_update_stream_param \ + esp_ble_audio_cap_unicast_audio_update_stream_param_t; + +/** CAP unicast audio specific parameters for updating audio */ +typedef struct bt_cap_unicast_audio_update_param \ + esp_ble_audio_cap_unicast_audio_update_param_t; + +/** CAP unicast audio specific parameters for stopping audio */ +typedef struct bt_cap_unicast_audio_stop_param \ + esp_ble_audio_cap_unicast_audio_stop_param_t; + +/** CAP Initiator broadcast audio stream specific parameters */ +typedef struct bt_cap_initiator_broadcast_stream_param \ + esp_ble_audio_cap_initiator_broadcast_stream_param_t; + +/** CAP Initiator broadcast audio subgroup specific parameters */ +typedef struct bt_cap_initiator_broadcast_subgroup_param \ + esp_ble_audio_cap_initiator_broadcast_subgroup_param_t; + +/** CAP Initiator broadcast audio specific parameters for creating audio */ +typedef struct bt_cap_initiator_broadcast_create_param \ + esp_ble_audio_cap_initiator_broadcast_create_param_t; + +/** Callback structure for CAP Handover procedures */ +typedef struct bt_cap_handover_cb esp_ble_audio_cap_handover_cb_t; + +/** CAP Handover unicast audio to broadcast audio specific parameters */ +typedef struct bt_cap_handover_unicast_to_broadcast_param \ + esp_ble_audio_cap_handover_unicast_to_broadcast_param_t; + +/** CAP Handover broadcast audio to unicast audio specific parameters */ +typedef struct bt_cap_handover_broadcast_to_unicast_param \ + esp_ble_audio_cap_handover_broadcast_to_unicast_param_t; + +/** Callback structure for CAP Commander procedures */ +typedef struct bt_cap_commander_cb esp_ble_audio_cap_commander_cb_t; + +/** CAP Commander broadcast audio member specific parameters for starting audio reception */ +typedef struct bt_cap_commander_broadcast_reception_start_member_param \ + esp_ble_audio_cap_commander_broadcast_reception_start_member_param_t; + +/** CAP Commander broadcast audio specific parameters for starting audio reception */ +typedef struct bt_cap_commander_broadcast_reception_start_param \ + esp_ble_audio_cap_commander_broadcast_reception_start_param_t; + +/** CAP Commander broadcast audio member specific parameters for stopping audio reception */ +typedef struct bt_cap_commander_broadcast_reception_stop_member_param \ + esp_ble_audio_cap_commander_broadcast_reception_stop_member_param_t; + +/** CAP Commander broadcast audio specific parameters for stopping audio reception */ +typedef struct bt_cap_commander_broadcast_reception_stop_param \ + esp_ble_audio_cap_commander_broadcast_reception_stop_param_t; + +/** CAP Commander member parameters for distributing broadcast code */ +typedef struct bt_cap_commander_distribute_broadcast_code_member_param \ + esp_ble_audio_cap_commander_distribute_broadcast_code_member_param_t; + +/** Parameters for distributing broadcast code */ +typedef struct bt_cap_commander_distribute_broadcast_code_param \ + esp_ble_audio_cap_commander_distribute_broadcast_code_param_t; + +/** Parameters for changing absolute volume */ +typedef struct bt_cap_commander_change_volume_param \ + esp_ble_audio_cap_commander_change_volume_param_t; + +/** Parameters for changing volume offset for a member */ +typedef struct bt_cap_commander_change_volume_offset_member_param \ + esp_ble_audio_cap_commander_change_volume_offset_member_param_t; + +/** Parameters for changing volume offset */ +typedef struct bt_cap_commander_change_volume_offset_param \ + esp_ble_audio_cap_commander_change_volume_offset_param_t; + +/** Parameters for changing volume mute state */ +typedef struct bt_cap_commander_change_volume_mute_state_param \ + esp_ble_audio_cap_commander_change_volume_mute_state_param_t; + +/** Parameters for changing microphone mute state */ +typedef struct bt_cap_commander_change_microphone_mute_state_param \ + esp_ble_audio_cap_commander_change_microphone_mute_state_param_t; + +/** Parameters for changing microphone gain setting for a member */ +typedef struct bt_cap_commander_change_microphone_gain_setting_member_param \ + esp_ble_audio_cap_commander_change_microphone_gain_setting_member_param_t; + +/** Parameters for changing microphone gain setting */ +typedef struct bt_cap_commander_change_microphone_gain_setting_param \ + esp_ble_audio_cap_commander_change_microphone_gain_setting_param_t; + +/** + * @brief Register the Common Audio Service. + * + * This will register and enable the service and make it discoverable by + * clients. This will also register a Coordinated Set Identification + * Service instance. + * + * @param param Coordinated Set Identification Service register parameters. + * @param svc_inst Pointer to the registered Coordinated Set Identification Service. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_acceptor_register(const esp_ble_audio_csip_set_member_register_param_t *param, + esp_ble_audio_csip_set_member_svc_inst_t **svc_inst); + +/** + * @brief Discovers audio support on a remote device. + * + * This will discover the Common Audio Service (CAS) on the remote device, to + * verify if the remote device supports the Common Audio Profile. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_initiator_unicast_discover(uint16_t conn_handle); + +/** + * @brief Register Audio operations for a Common Audio Profile stream. + * + * Register Audio operations for a stream. + * + * @param stream Stream object. + * @param ops Stream operations structure. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_stream_ops_register(esp_ble_audio_cap_stream_t *stream, + esp_ble_audio_bap_stream_ops_t *ops); + +/** + * @brief Send data to Common Audio Profile stream without timestamp. + * + * Sends data over the specified CAP audio stream with a sequence number. + * + * @param stream Stream object. + * @param sdu Buffer containing data to be sent. + * @param sdu_len Length of data to be sent. + * @param seq_num Packet Sequence number. This value shall be incremented + * for each call to this function and at least once per SDU + * interval for a specific channel. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_stream_send(esp_ble_audio_cap_stream_t *stream, + const uint8_t *sdu, uint16_t sdu_len, + uint16_t seq_num); + +/** + * @brief Send data to Common Audio Profile stream with timestamp. + * + * Sends data over the specified CAP audio stream with a sequence number. + * + * @param stream Stream object. + * @param sdu Buffer containing data to be sent. + * @param sdu_len Length of data to be sent. + * @param seq_num Packet Sequence number. This value shall be incremented + * for each call to this function and at least once per SDU + * interval for a specific channel. + * @param ts Timestamp of the SDU in microseconds (us). This value can + * be used to transmit multiple SDUs in the same SDU interval + * in a CIG or BIG. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_stream_send_ts(esp_ble_audio_cap_stream_t *stream, + const uint8_t *sdu, uint16_t sdu_len, + uint16_t seq_num, uint32_t ts); + +/** + * @brief Get ISO transmission timing info for a Common Audio Profile stream. + * + * @param stream Stream object. + * @param info Transmit info object. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_stream_get_tx_sync(esp_ble_audio_cap_stream_t *stream, + esp_ble_iso_tx_info_t *info); + +/** + * @brief Create unicast group. + * + * Create a new audio unicast group with one or more audio streams as a unicast client. + * All streams shall share the same framing. + * All streams in the same direction shall share the same interval and latency (see + * esp_ble_audio_bap_qos_cfg_t). + * + * @param param The unicast group create parameters. + * @param unicast_group Pointer to the unicast group created. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_unicast_group_create(const esp_ble_audio_cap_unicast_group_param_t *param, + esp_ble_audio_cap_unicast_group_t **unicast_group); + +/** + * @brief Reconfigure unicast group. + * + * Reconfigure a unicast group with one or more audio streams as a unicast client. + * All streams shall share the same framing. + * All streams in the same direction shall share the same interval and latency (see + * esp_ble_audio_bap_qos_cfg_t). + * All streams in @p param shall already belong to @p unicast_group. + * Use esp_ble_audio_cap_unicast_group_add_streams() to add additional streams. + * + * @param unicast_group Pointer to the unicast group created. + * @param param The unicast group reconfigure parameters. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_unicast_group_reconfig(esp_ble_audio_cap_unicast_group_t *unicast_group, + const esp_ble_audio_cap_unicast_group_param_t *param); + +/** + * @brief Add streams to a unicast group as a unicast client. + * + * This function can be used to add additional streams to a esp_ble_audio_cap_unicast_group_t. + * + * This can be called at any time before any of the streams in the group has been started + * (see esp_ble_audio_bap_stream_ops_t.started()). + * This can also be called after the streams have been stopped (see + * esp_ble_audio_bap_stream_ops_t.stopped()). + * + * Once a stream has been added to a unicast group, it cannot be removed. To remove a stream + * from a group, the group must be deleted with esp_ble_audio_cap_unicast_group_delete(), but + * this will require all streams in the group to be released first. + * + * @param unicast_group Pointer to the unicast group + * @param params Array of stream parameters with streams being added to the group. + * @param num_param Number of parameters in @p params. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_unicast_group_add_streams(esp_ble_audio_cap_unicast_group_t *unicast_group, + const esp_ble_audio_cap_unicast_group_stream_pair_param_t params[], + size_t num_param); + +/** + * @brief Delete audio unicast group. + * + * Delete a audio unicast group as a client. All streams in the group shall + * be in the idle or configured state. + * + * @param unicast_group Pointer to the unicast group to delete. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_unicast_group_delete(esp_ble_audio_cap_unicast_group_t *unicast_group); + +/** + * @brief Register Common Audio Profile Initiator callbacks. + * + * @param cb The callback structure. Shall remain static. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_initiator_register_cb(const esp_ble_audio_cap_initiator_cb_t *cb); + +/** + * @brief Unregister Common Audio Profile Initiator callbacks. + * + * @param cb The callback structure that was previously registered. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_initiator_unregister_cb(const esp_ble_audio_cap_initiator_cb_t *cb); + +/** + * @brief Setup and start unicast audio streams for a set of devices. + * + * @param param Parameters to start the audio streams. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_initiator_unicast_audio_start(const esp_ble_audio_cap_unicast_audio_start_param_t *param); + +/** + * @brief Update unicast audio streams. + * + * This will update the metadata of one or more streams. + * + * @param param Update parameters. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_initiator_unicast_audio_update(const esp_ble_audio_cap_unicast_audio_update_param_t *param); + +/** + * @brief Stop unicast audio streams. + * + * This will stop one or more streams. + * + * @param param Stop parameters. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_initiator_unicast_audio_stop(const esp_ble_audio_cap_unicast_audio_stop_param_t *param); + +/** + * @brief Cancel any current Common Audio Profile procedure. + * + * This will stop the current procedure from continuing and making it possible to run a new + * Common Audio Profile procedure. + * + * It is recommended to do this if any existing procedure takes longer time than expected, which + * could indicate a missing response from the Common Audio Profile Acceptor. + * + * This does not send any requests to any Common Audio Profile Acceptors involved with the current + * procedure, and thus notifications from the Common Audio Profile Acceptors may arrive after this + * has been called. It is thus recommended to either only use this if a procedure has stalled, or + * wait a short while before starting any new Common Audio Profile procedure after this has been + * called to avoid getting notifications from the cancelled procedure. The wait time depends on + * the connection interval, the number of devices in the previous procedure and the behavior of the + * Common Audio Profile Acceptors. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_initiator_unicast_audio_cancel(void); + +/** + * @brief Create a Common Audio Profile broadcast source. + * + * Create a new audio broadcast source with one or more audio streams. + * + * @param param Parameters to start the audio streams. + * @param broadcast_source Pointer to the broadcast source created. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_initiator_broadcast_audio_create(const esp_ble_audio_cap_initiator_broadcast_create_param_t *param, + esp_ble_audio_cap_broadcast_source_t **broadcast_source); + +/** + * @brief Start Common Audio Profile broadcast source. + * + * The broadcast source will be visible for scanners once this has been called, + * and the device will advertise audio announcements. + * + * @param broadcast_source Pointer to the broadcast source. + * @param adv_handle Handle of an extended advertising set with + * periodic advertising configured. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_initiator_broadcast_audio_start( + esp_ble_audio_cap_broadcast_source_t *broadcast_source, + uint8_t adv_handle); + +/** + * @brief Update broadcast audio streams for a Common Audio Profile broadcast source. + * + * @param broadcast_source The broadcast source to update. + * @param meta The new metadata. The metadata shall contain a list + * of CCIDs as well as a non-0 context bitfield. + * @param meta_len The length of @p meta. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_initiator_broadcast_audio_update(esp_ble_audio_cap_broadcast_source_t *broadcast_source, + const uint8_t meta[], size_t meta_len); + +/** + * @brief Stop broadcast audio streams for a Common Audio Profile broadcast source. + * + * @param broadcast_source The broadcast source to stop. The audio streams + * in this will be stopped and reset. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_initiator_broadcast_audio_stop(esp_ble_audio_cap_broadcast_source_t *broadcast_source); + +/** + * @brief Delete Common Audio Profile broadcast source. + * + * @param broadcast_source The broadcast source to delete. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_initiator_broadcast_audio_delete(esp_ble_audio_cap_broadcast_source_t *broadcast_source); + +/** + * @brief Get the Broadcast Audio Stream Endpoint of a Common Audio Profile + * broadcast source. + * + * This will encode the BASE of a broadcast source into a buffer, that can be + * used for advertisement. The encoded BASE will thus be encoded as + * little-endian. The BASE shall be put into the periodic advertising data. + * + * See table 3.15 in the Basic Audio Profile v1.0.1 for the structure. + * + * @param broadcast_source Pointer to the broadcast source. + * @param base_buf Pointer to a buffer where the BASE will be inserted. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_initiator_broadcast_get_base(esp_ble_audio_cap_broadcast_source_t *broadcast_source, + struct net_buf_simple *base_buf); + +/** + * @brief Register Common Audio Profile Handover callbacks. + * + * @param cb The callback structure. Shall remain static. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_handover_register_cb(const esp_ble_audio_cap_handover_cb_t *cb); + +/** + * @brief Unregister Common Audio Profile Handover callbacks. + * + * @param cb The callback structure that was previously registered. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_handover_unregister_cb(const esp_ble_audio_cap_handover_cb_t *cb); + +/** + * @brief Hands over the sink streams in a unicast group to a broadcast source. + * + * All streams in the provided unicast group will be stopped and released. The sink streams + * will be transferred to a broadcast source, and the broadcast source information will be + * shared with all accepters that are currently receiving audio. Any stream that is not in + * the streaming state will only be released. + * + * esp_ble_audio_bap_broadcast_assistant_discover() must have been successfully perform for + * all members in @p param before starting this procedure. + * + * @param param The parameters for the handover. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_handover_unicast_to_broadcast( + const esp_ble_audio_cap_handover_unicast_to_broadcast_param_t *param); + +/** + * @brief Hands over the data streams in a broadcast source to a unicast group. + * + * The streams in the broadcast source will be stopped and the broadcast source + * will be deleted. + * + * @param param The parameters for the handover. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_handover_broadcast_to_unicast( + const esp_ble_audio_cap_handover_broadcast_to_unicast_param_t *param); + +/** + * @brief Register Common Audio Profile Commander callbacks. + * + * @param cb The callback structure. Shall remain static. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_commander_register_cb(const esp_ble_audio_cap_commander_cb_t *cb); + +/** + * @brief Unregister Common Audio Profile Commander callbacks. + * + * @param cb The callback structure that was previously registered. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_commander_unregister_cb(const esp_ble_audio_cap_commander_cb_t *cb); + +/** + * @brief Discovers audio support on a remote device. + * + * This will discover the Common Audio Service (CAS) on the remote device, + * to verify if the remote device supports the Common Audio Profile. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_commander_discover(uint16_t conn_handle); + +/** + * @brief Cancel any current Common Audio Profile commander procedure. + * + * This will stop the current procedure from continuing and making it possible to run a new + * Common Audio Profile procedure. + * + * It is recommended to do this if any existing procedure takes longer time than expected, which + * could indicate a missing response from the Common Audio Profile Acceptor. + * + * This does not send any requests to any Common Audio Profile Acceptors involved with the + * current procedure, and thus notifications from the Common Audio Profile Acceptors may + * arrive after this has been called. It is thus recommended to either only use this if a + * procedure has stalled, or wait a short while before starting any new Common Audio Profile + * procedure after this has been called to avoid getting notifications from the cancelled + * procedure. The wait time depends on the connection interval, the number of devices in the + * previous procedure and the behavior of the Common Audio Profile Acceptors. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_commander_cancel(void); + +/** + * @brief Starts the reception of broadcast audio on one or more remote + * Common Audio Profile Acceptors. + * + * @param param The parameters to start the broadcast audio + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_commander_broadcast_reception_start( + const esp_ble_audio_cap_commander_broadcast_reception_start_param_t *param); + +/** + * @brief Stops the reception of broadcast audio on one or more remote + * Common Audio Profile Acceptors. + * + * @param param The parameters to stop the broadcast audio + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_commander_broadcast_reception_stop( + const esp_ble_audio_cap_commander_broadcast_reception_stop_param_t *param); + +/** + * @brief Distributes the broadcast code on one or more remote Common + * Audio Profile Acceptors. + * + * @param param The parameters for distributing the broadcast code. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_commander_distribute_broadcast_code( + const esp_ble_audio_cap_commander_distribute_broadcast_code_param_t *param); + +/** + * @brief Change the volume on one or more Common Audio Profile Acceptors. + * + * @param param The parameters for the volume change. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_commander_change_volume( + const esp_ble_audio_cap_commander_change_volume_param_t *param); + +/** + * @brief Change the volume offset on one or more Common Audio Profile Acceptors. + * + * @param param The parameters for the volume offset change. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_commander_change_volume_offset( + const esp_ble_audio_cap_commander_change_volume_offset_param_t *param); + +/** + * @brief Change the volume mute state on one or more Common Audio Profile Acceptors. + * + * @param param The parameters for the volume mute state change. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_commander_change_volume_mute_state( + const esp_ble_audio_cap_commander_change_volume_mute_state_param_t *param); + +/** + * @brief Change the microphone mute state on one or more Common Audio Profile Acceptors. + * + * @param param The parameters for the microphone mute state change. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_commander_change_microphone_mute_state( + const esp_ble_audio_cap_commander_change_microphone_mute_state_param_t *param); + +/** + * @brief Change the microphone gain setting on one or more Common Audio Profile Acceptors. + * + * @param param The parameters for the microphone gain setting change. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_cap_commander_change_microphone_gain_setting( + const esp_ble_audio_cap_commander_change_microphone_gain_setting_param_t *param); + +#ifdef __cplusplus +} +#endif + +#endif /* ESP_BLE_AUDIO_CAP_API_H_ */ diff --git a/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_ccp_api.h b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_ccp_api.h new file mode 100644 index 0000000000..346850c869 --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_ccp_api.h @@ -0,0 +1,171 @@ +/* + * SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ESP_BLE_AUDIO_CCP_API_H_ +#define ESP_BLE_AUDIO_CCP_API_H_ + +#include +#include +#include + +#include "sdkconfig.h" +#include "esp_err.h" + +#include +#include + +#include "common/init.h" +#include "common/host.h" + +#include "esp_ble_audio_tbs_api.h" +#include "esp_ble_audio_common_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Abstract Call Control Server Telephone Bearer structure */ +typedef struct bt_ccp_call_control_server_bearer \ + esp_ble_audio_ccp_call_control_server_bearer_t; + +/** Abstract Call Control Client structure. */ +typedef struct bt_ccp_call_control_client \ + esp_ble_audio_ccp_call_control_client_t; + +/** Abstract Call Control Client bearer structure. */ +typedef struct bt_ccp_call_control_client_bearer \ + esp_ble_audio_ccp_call_control_client_bearer_t; + +/** Struct with information about bearers of a client */ +typedef struct bt_ccp_call_control_client_bearers \ + esp_ble_audio_ccp_call_control_client_bearers_t; + +/** Struct to hold the Telephone Bearer Service client callbacks */ +typedef struct bt_ccp_call_control_client_cb \ + esp_ble_audio_ccp_call_control_client_cb_t; + +/** + * @brief Register a Telephone Bearer. + * + * This will register a Telephone Bearer Service (TBS) (or a Generic Telephone + * Bearer service (GTBS)) with the provided parameters. + * + * As per the TBS specification, the GTBS shall be instantiated for the feature, + * and as such a GTBS shall always be registered before any TBS can be registered. + * Similarly, all TBS shall be unregistered before the GTBS can be unregistered + * with esp_ble_audio_ccp_call_control_server_unregister_bearer(). + * + * @param param The parameters to initialize the bearer. + * @param bearer Pointer to the initialized bearer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_ccp_call_control_server_register_bearer( + const esp_ble_audio_tbs_register_param_t *param, + esp_ble_audio_ccp_call_control_server_bearer_t **bearer); + +/** + * @brief Unregister a Telephone Bearer. + * + * This will unregister a Telephone Bearer Service (TBS) (or a Generic Telephone + * Bearer service (GTBS)) with the provided parameters. The bearer shall be + * registered first by esp_ble_audio_ccp_call_control_server_register_bearer() + * before it can be unregistered. + * + * All TBS shall be unregistered before the GTBS can be unregistered with. + * + * @param bearer The bearer to unregister. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_ccp_call_control_server_unregister_bearer( + esp_ble_audio_ccp_call_control_server_bearer_t *bearer); + +/** + * @brief Set a new bearer provider name. + * + * @param bearer The bearer to set the name for. + * @param name The new bearer provider name. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_ccp_call_control_server_set_bearer_provider_name( + esp_ble_audio_ccp_call_control_server_bearer_t *bearer, const char *name); + +/** + * @brief Get the bearer provider name. + * + * @param bearer The bearer to get the name for. + * @param name Pointer that will be updated to be the bearer provider name. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_ccp_call_control_server_get_bearer_provider_name( + esp_ble_audio_ccp_call_control_server_bearer_t *bearer, const char **name); + +/** + * @brief Discovers the Telephone Bearer Service (TBS) support on a remote device. + * + * This will discover the Telephone Bearer Service (TBS) and Generic Telephone Bearer + * Service (GTBS) on the remote device. + * + * @param conn Connection to a remote server. + * @param out_client Pointer to client instance on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_ccp_call_control_client_discover( + esp_ble_conn_t *conn, esp_ble_audio_ccp_call_control_client_t **out_client); + +/** + * @brief Register callbacks for the Call Control Client. + * + * @param cb The callback struct. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_ccp_call_control_client_register_cb( + esp_ble_audio_ccp_call_control_client_cb_t *cb); + +/** + * @brief Unregister callbacks for the Call Control Client. + * + * @param cb The callback struct. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_ccp_call_control_client_unregister_cb( + esp_ble_audio_ccp_call_control_client_cb_t *cb); + +/** + * @brief Get the bearers of a client instance. + * + * @param client The client to get the bearers of. + * @param bearers The bearers struct that will be populated + * with the bearers of @p client. + + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_ccp_call_control_client_get_bearers( + esp_ble_audio_ccp_call_control_client_t *client, + esp_ble_audio_ccp_call_control_client_bearers_t *bearers); + +/** + * @brief Read the bearer provider name of a remote TBS bearer. + * + * @param bearer The bearer to read the name from. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_ccp_call_control_client_read_bearer_provider_name( + esp_ble_audio_ccp_call_control_client_bearer_t *bearer); + +#ifdef __cplusplus +} +#endif + +#endif /* ESP_BLE_AUDIO_CCP_API_H_ */ diff --git a/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_codec_api.h b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_codec_api.h new file mode 100644 index 0000000000..12545623c5 --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_codec_api.h @@ -0,0 +1,1351 @@ +/* + * SPDX-FileCopyrightText: 2020 Intel Corporation + * SPDX-FileCopyrightText: 2020-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ESP_BLE_AUDIO_CODEC_API_H_ +#define ESP_BLE_AUDIO_CODEC_API_H_ + +#include +#include +#include +#include + +#include "sdkconfig.h" + +#include "esp_ble_audio_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Helper to declare elements of bt_audio_codec_cap arrays. + * + * This macro is mainly for creating an array of struct bt_audio_codec_cap data arrays. + * + * @param _type Type of advertising data field. + * @param _bytes Variable number of single-byte parameters. + */ +#define ESP_BLE_AUDIO_CODEC_DATA BT_AUDIO_CODEC_DATA + +/*!< Target low latency */ +#define ESP_BLE_AUDIO_CODEC_CFG_TARGET_LATENCY_LOW BT_AUDIO_CODEC_CFG_TARGET_LATENCY_LOW +/*!< Target balanced latency */ +#define ESP_BLE_AUDIO_CODEC_CFG_TARGET_LATENCY_BALANCED BT_AUDIO_CODEC_CFG_TARGET_LATENCY_BALANCED +/*!< Target high latency */ +#define ESP_BLE_AUDIO_CODEC_CFG_TARGET_LATENCY_HIGH BT_AUDIO_CODEC_CFG_TARGET_LATENCY_HIGH +/** Codec configuration target latency */ +typedef enum bt_audio_codec_cfg_target_latency esp_ble_audio_codec_cfg_target_latency_t; + +/*!< LE 1M PHY */ +#define ESP_BLE_AUDIO_CODEC_CFG_TARGET_PHY_1M BT_AUDIO_CODEC_CFG_TARGET_PHY_1M +/*!< LE 2M PHY */ +#define ESP_BLE_AUDIO_CODEC_CFG_TARGET_PHY_2M BT_AUDIO_CODEC_CFG_TARGET_PHY_2M +/*!< LE Coded PHY */ +#define ESP_BLE_AUDIO_CODEC_CFG_TARGET_PHY_CODED BT_AUDIO_CODEC_CFG_TARGET_PHY_CODED +/** Codec configuration target PHY */ +typedef enum bt_audio_codec_cfg_target_phy esp_ble_audio_codec_cfg_target_phy_t; + +/** + * @brief Helper to declare esp_ble_audio_codec_cfg_t. + * + * @param _id Codec ID. + * @param _cid Company ID. + * @param _vid Vendor ID. + * @param _data Codec Specific Data in LVT format. + * @param _meta Codec Specific Metadata in LVT format. + */ +#define ESP_BLE_AUDIO_CODEC_CFG(_id, _cid, _vid, _data, _meta) \ + ((esp_ble_audio_codec_cfg_t){ \ + /* Use HCI data path as default, can be overwritten by application */ \ + .path_id = ESP_BLE_ISO_DATA_PATH_HCI, \ + .ctlr_transcode = false, \ + COND_CODE_1(IS_ENABLED(CONFIG_BT_BAP_UNICAST), \ + (.target_latency = ESP_BLE_AUDIO_CODEC_CFG_TARGET_LATENCY_BALANCED, \ + .target_phy = ESP_BLE_AUDIO_CODEC_CFG_TARGET_PHY_2M,), \ + ()) \ + .id = (_id), \ + .cid = (_cid), \ + .vid = (_vid), \ + .data_len = sizeof(_data), \ + .data = (_data), \ + .meta_len = sizeof(_meta), \ + .meta = (_meta), \ + }) + +/** + * @brief Helper to declare esp_ble_audio_codec_cap_t. + * + * @param _id Codec ID. + * @param _cid Company ID. + * @param _vid Vendor-specific codec ID. + * @param _data Codec-specific capability data. + * @param _meta Metadata capabilities. + */ +#define ESP_BLE_AUDIO_CODEC_CAP(_id, _cid, _vid, _data, _meta) \ + ((esp_ble_audio_codec_cap_t){ \ + /* Use HCI data path as default, can be overwritten by application */ \ + .path_id = ESP_BLE_ISO_DATA_PATH_HCI, \ + .ctlr_transcode = false, \ + .id = (_id), \ + .cid = (_cid), \ + .vid = (_vid), \ + .data_len = sizeof(_data), \ + .data = (_data), \ + .meta_len = sizeof(_meta), \ + .meta = (_meta), \ + }) + +/*!< Supported sampling frequencies */ +#define ESP_BLE_AUDIO_CODEC_CAP_TYPE_FREQ BT_AUDIO_CODEC_CAP_TYPE_FREQ +/*!< Supported frame durations */ +#define ESP_BLE_AUDIO_CODEC_CAP_TYPE_DURATION BT_AUDIO_CODEC_CAP_TYPE_DURATION +/*!< Supported audio channel counts */ +#define ESP_BLE_AUDIO_CODEC_CAP_TYPE_CHAN_COUNT BT_AUDIO_CODEC_CAP_TYPE_CHAN_COUNT +/*!< Supported octets per codec frame */ +#define ESP_BLE_AUDIO_CODEC_CAP_TYPE_FRAME_LEN BT_AUDIO_CODEC_CAP_TYPE_FRAME_LEN +/*!< Supported maximum codec frames per SDU */ +#define ESP_BLE_AUDIO_CODEC_CAP_TYPE_FRAME_COUNT BT_AUDIO_CODEC_CAP_TYPE_FRAME_COUNT +/** Codec capability types */ +typedef enum bt_audio_codec_cap_type esp_ble_audio_codec_cap_type_t; + +/*!< 8 Khz sampling frequency */ +#define ESP_BLE_AUDIO_CODEC_CAP_FREQ_8KHZ BT_AUDIO_CODEC_CAP_FREQ_8KHZ +/*!< 11.025 Khz sampling frequency */ +#define ESP_BLE_AUDIO_CODEC_CAP_FREQ_11KHZ BT_AUDIO_CODEC_CAP_FREQ_11KHZ +/*!< 16 Khz sampling frequency */ +#define ESP_BLE_AUDIO_CODEC_CAP_FREQ_16KHZ BT_AUDIO_CODEC_CAP_FREQ_16KHZ +/*!< 22.05 Khz sampling frequency */ +#define ESP_BLE_AUDIO_CODEC_CAP_FREQ_22KHZ BT_AUDIO_CODEC_CAP_FREQ_22KHZ +/*!< 24 Khz sampling frequency */ +#define ESP_BLE_AUDIO_CODEC_CAP_FREQ_24KHZ BT_AUDIO_CODEC_CAP_FREQ_24KHZ +/*!< 32 Khz sampling frequency */ +#define ESP_BLE_AUDIO_CODEC_CAP_FREQ_32KHZ BT_AUDIO_CODEC_CAP_FREQ_32KHZ +/*!< 44.1 Khz sampling frequency */ +#define ESP_BLE_AUDIO_CODEC_CAP_FREQ_44KHZ BT_AUDIO_CODEC_CAP_FREQ_44KHZ +/*!< 48 Khz sampling frequency */ +#define ESP_BLE_AUDIO_CODEC_CAP_FREQ_48KHZ BT_AUDIO_CODEC_CAP_FREQ_48KHZ +/*!< 88.2 Khz sampling frequency */ +#define ESP_BLE_AUDIO_CODEC_CAP_FREQ_88KHZ BT_AUDIO_CODEC_CAP_FREQ_88KHZ +/*!< 96 Khz sampling frequency */ +#define ESP_BLE_AUDIO_CODEC_CAP_FREQ_96KHZ BT_AUDIO_CODEC_CAP_FREQ_96KHZ +/*!< 176.4 Khz sampling frequency */ +#define ESP_BLE_AUDIO_CODEC_CAP_FREQ_176KHZ BT_AUDIO_CODEC_CAP_FREQ_176KHZ +/*!< 192 Khz sampling frequency */ +#define ESP_BLE_AUDIO_CODEC_CAP_FREQ_192KHZ BT_AUDIO_CODEC_CAP_FREQ_192KHZ +/*!< 384 Khz sampling frequency */ +#define ESP_BLE_AUDIO_CODEC_CAP_FREQ_384KHZ BT_AUDIO_CODEC_CAP_FREQ_384KHZ +/*!< Any frequency capability */ +#define ESP_BLE_AUDIO_CODEC_CAP_FREQ_ANY BT_AUDIO_CODEC_CAP_FREQ_ANY +/** Supported frequencies bitfield */ +typedef enum bt_audio_codec_cap_freq esp_ble_audio_codec_cap_freq_t; + +/*!< 7.5 msec frame duration capability */ +#define ESP_BLE_AUDIO_CODEC_CAP_DURATION_7_5 BT_AUDIO_CODEC_CAP_DURATION_7_5 +/*!< 10 msec frame duration capability */ +#define ESP_BLE_AUDIO_CODEC_CAP_DURATION_10 BT_AUDIO_CODEC_CAP_DURATION_10 +/*!< Any frame duration capability */ +#define ESP_BLE_AUDIO_CODEC_CAP_DURATION_ANY BT_AUDIO_CODEC_CAP_DURATION_ANY +/*!< 7.5 msec preferred frame duration capability */ +#define ESP_BLE_AUDIO_CODEC_CAP_DURATION_PREFER_7_5 BT_AUDIO_CODEC_CAP_DURATION_PREFER_7_5 +/*!< 10 msec preferred frame duration capability */ +#define ESP_BLE_AUDIO_CODEC_CAP_DURATION_PREFER_10 BT_AUDIO_CODEC_CAP_DURATION_PREFER_10 +/** Supported frame durations bitfield */ +typedef enum bt_audio_codec_cap_frame_dur esp_ble_audio_codec_cap_frame_dur_t; + +/*!< Supporting 1 channel */ +#define ESP_BLE_AUDIO_CODEC_CAP_CHAN_COUNT_1 BT_AUDIO_CODEC_CAP_CHAN_COUNT_1 +/*!< Supporting 2 channel */ +#define ESP_BLE_AUDIO_CODEC_CAP_CHAN_COUNT_2 BT_AUDIO_CODEC_CAP_CHAN_COUNT_2 +/*!< Supporting 3 channel */ +#define ESP_BLE_AUDIO_CODEC_CAP_CHAN_COUNT_3 BT_AUDIO_CODEC_CAP_CHAN_COUNT_3 +/*!< Supporting 4 channel */ +#define ESP_BLE_AUDIO_CODEC_CAP_CHAN_COUNT_4 BT_AUDIO_CODEC_CAP_CHAN_COUNT_4 +/*!< Supporting 5 channel */ +#define ESP_BLE_AUDIO_CODEC_CAP_CHAN_COUNT_5 BT_AUDIO_CODEC_CAP_CHAN_COUNT_5 +/*!< Supporting 6 channel */ +#define ESP_BLE_AUDIO_CODEC_CAP_CHAN_COUNT_6 BT_AUDIO_CODEC_CAP_CHAN_COUNT_6 +/*!< Supporting 7 channel */ +#define ESP_BLE_AUDIO_CODEC_CAP_CHAN_COUNT_7 BT_AUDIO_CODEC_CAP_CHAN_COUNT_7 +/*!< Supporting 8 channel */ +#define ESP_BLE_AUDIO_CODEC_CAP_CHAN_COUNT_8 BT_AUDIO_CODEC_CAP_CHAN_COUNT_8 +/*!< Supporting all channels */ +#define ESP_BLE_AUDIO_CODEC_CAP_CHAN_COUNT_ANY BT_AUDIO_CODEC_CAP_CHAN_COUNT_ANY + +/*!< Minimum supported channel counts */ +#define ESP_BLE_AUDIO_CODEC_CAP_CHAN_COUNT_MIN BT_AUDIO_CODEC_CAP_CHAN_COUNT_MIN +/*!< Maximum supported channel counts */ +#define ESP_BLE_AUDIO_CODEC_CAP_CHAN_COUNT_MAX BT_AUDIO_CODEC_CAP_CHAN_COUNT_MAX + +/** + * @brief Channel count support capability. + * + * Macro accepts variable number of channel counts. + * The allowed channel counts are defined by specification and have to be in range from + * ESP_BLE_AUDIO_CODEC_CAP_CHAN_COUNT_MIN to ESP_BLE_AUDIO_CODEC_CAP_CHAN_COUNT_MAX + * inclusive. + * + * Example to support 1 and 3 channels: + * ESP_BLE_AUDIO_CODEC_CAP_CHAN_COUNT_SUPPORT(1, 3) + */ +#define ESP_BLE_AUDIO_CODEC_CAP_CHAN_COUNT_SUPPORT BT_AUDIO_CODEC_CAP_CHAN_COUNT_SUPPORT +/** Supported audio capabilities channel count bitfield */ +typedef enum bt_audio_codec_cap_chan_count esp_ble_audio_codec_cap_chan_count_t; + +/*!< Sampling frequency */ +#define ESP_BLE_AUDIO_CODEC_CFG_FREQ BT_AUDIO_CODEC_CFG_FREQ +/*!< Frame duration */ +#define ESP_BLE_AUDIO_CODEC_CFG_DURATION BT_AUDIO_CODEC_CFG_DURATION +/*!< Audio channel allocation */ +#define ESP_BLE_AUDIO_CODEC_CFG_CHAN_ALLOC BT_AUDIO_CODEC_CFG_CHAN_ALLOC +/*!< Octets per codec frame */ +#define ESP_BLE_AUDIO_CODEC_CFG_FRAME_LEN BT_AUDIO_CODEC_CFG_FRAME_LEN +/*!< Codec frame blocks per SDU */ +#define ESP_BLE_AUDIO_CODEC_CFG_FRAME_BLKS_PER_SDU BT_AUDIO_CODEC_CFG_FRAME_BLKS_PER_SDU +/** Codec configuration types */ +typedef enum bt_audio_codec_cfg_type esp_ble_audio_codec_cfg_type_t; + +/*!< 8 Khz codec sampling frequency */ +#define ESP_BLE_AUDIO_CODEC_CFG_FREQ_8KHZ BT_AUDIO_CODEC_CFG_FREQ_8KHZ +/*!< 11.025 Khz codec sampling frequency */ +#define ESP_BLE_AUDIO_CODEC_CFG_FREQ_11KHZ BT_AUDIO_CODEC_CFG_FREQ_11KHZ +/*!< 16 Khz codec sampling frequency */ +#define ESP_BLE_AUDIO_CODEC_CFG_FREQ_16KHZ BT_AUDIO_CODEC_CFG_FREQ_16KHZ +/*!< 22.05 Khz codec sampling frequency */ +#define ESP_BLE_AUDIO_CODEC_CFG_FREQ_22KHZ BT_AUDIO_CODEC_CFG_FREQ_22KHZ +/*!< 24 Khz codec sampling frequency */ +#define ESP_BLE_AUDIO_CODEC_CFG_FREQ_24KHZ BT_AUDIO_CODEC_CFG_FREQ_24KHZ +/*!< 32 Khz codec sampling frequency */ +#define ESP_BLE_AUDIO_CODEC_CFG_FREQ_32KHZ BT_AUDIO_CODEC_CFG_FREQ_32KHZ +/*!< 44.1 Khz codec sampling frequency */ +#define ESP_BLE_AUDIO_CODEC_CFG_FREQ_44KHZ BT_AUDIO_CODEC_CFG_FREQ_44KHZ +/*!< 48 Khz codec sampling frequency */ +#define ESP_BLE_AUDIO_CODEC_CFG_FREQ_48KHZ BT_AUDIO_CODEC_CFG_FREQ_48KHZ +/*!< 88.2 Khz codec sampling frequency */ +#define ESP_BLE_AUDIO_CODEC_CFG_FREQ_88KHZ BT_AUDIO_CODEC_CFG_FREQ_88KHZ +/*!< 96 Khz codec sampling frequency */ +#define ESP_BLE_AUDIO_CODEC_CFG_FREQ_96KHZ BT_AUDIO_CODEC_CFG_FREQ_96KHZ +/*!< 176.4 Khz codec sampling frequency */ +#define ESP_BLE_AUDIO_CODEC_CFG_FREQ_176KHZ BT_AUDIO_CODEC_CFG_FREQ_176KHZ +/*!< 192 Khz codec sampling frequency */ +#define ESP_BLE_AUDIO_CODEC_CFG_FREQ_192KHZ BT_AUDIO_CODEC_CFG_FREQ_192KHZ +/*!< 384 Khz codec sampling frequency */ +#define ESP_BLE_AUDIO_CODEC_CFG_FREQ_384KHZ BT_AUDIO_CODEC_CFG_FREQ_384KHZ +/** Codec configuration sampling frequency */ +typedef enum bt_audio_codec_cfg_freq esp_ble_audio_codec_cfg_freq_t; + +/*!< 7.5 msec Frame Duration configuration */ +#define ESP_BLE_AUDIO_CODEC_CFG_DURATION_7_5 BT_AUDIO_CODEC_CFG_DURATION_7_5 +/*!< 10 msec Frame Duration configuration */ +#define ESP_BLE_AUDIO_CODEC_CFG_DURATION_10 BT_AUDIO_CODEC_CFG_DURATION_10 +/** Codec configuration frame duration */ +typedef enum bt_audio_codec_cfg_frame_dur esp_ble_audio_codec_cfg_frame_dur_t; + +/** Codec specific configuration structure */ +typedef struct bt_audio_codec_cfg esp_ble_audio_codec_cfg_t; + +/** Codec capability structure */ +typedef struct bt_audio_codec_cap esp_ble_audio_codec_cap_t; + +/** Struct to hold minimum and maximum supported codec frame sizes */ +typedef struct bt_audio_codec_octets_per_codec_frame esp_ble_audio_codec_octets_per_codec_frame_t; + +/** + * @brief Convert assigned numbers frequency to frequency value. + * + * @param freq The assigned numbers frequency to convert. + * @param freq_hz The converted frequency value in Hz on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_freq_to_freq_hz(esp_ble_audio_codec_cfg_freq_t freq, + uint32_t *freq_hz); + +/** + * @brief Convert frequency value to assigned numbers frequency. + * + * @param freq_hz Frequency in Hz. + * @param freq The assigned numbers frequency on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_freq_hz_to_freq(uint32_t freq_hz, + esp_ble_audio_codec_cfg_freq_t *freq); + +/** + * @brief Extract the frequency from a codec configuration. + * + * @param codec_cfg The codec configuration to extract data from. + * @param freq The assigned numbers frequency on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_get_freq(const esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_codec_cfg_freq_t *freq); + +/** + * @brief Set the frequency of a codec configuration. + * + * @param codec_cfg The codec configuration to set data for. + * @param freq The assigned numbers frequency to set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_set_freq(esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_codec_cfg_freq_t freq); + +/** + * @brief Convert assigned numbers frame duration to duration in microseconds. + * + * @param frame_dur The assigned numbers frame duration to convert. + * @param frame_dur_us The converted frame duration value in microseconds on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_frame_dur_to_frame_dur_us(esp_ble_audio_codec_cfg_frame_dur_t frame_dur, + uint32_t *frame_dur_us); + +/** + * @brief Convert frame duration in microseconds to assigned numbers frame duration. + * + * @param frame_dur_us The frame duration in microseconds to convert. + * @param frame_dur The assigned numbers frame duration on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_frame_dur_us_to_frame_dur(uint32_t frame_dur_us, + esp_ble_audio_codec_cfg_frame_dur_t *frame_dur); + +/** + * @brief Extract frame duration from codec config. + * + * @param codec_cfg The codec configuration to extract data from. + * @param frame_dur The assigned numbers frame duration on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_get_frame_dur(const esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_codec_cfg_frame_dur_t *frame_dur); + +/** + * @brief Set the frame duration of a codec configuration. + * + * @param codec_cfg The codec configuration to set data for. + * @param frame_dur The assigned numbers frame duration to set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_set_frame_dur(esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_codec_cfg_frame_dur_t frame_dur); + +/** + * @brief Extract channel allocation from codec config. + * + * The value returned is a bit field representing one or more audio locations as + * specified by esp_ble_audio_location_t. + * Shall match one or more of the bits set in ESP_BLE_AUDIO_PAC_SNK_LOC or + * ESP_BLE_AUDIO_PAC_SRC_LOC. + * + * Up to the configured ESP_BLE_AUDIO_CODEC_CAP_TYPE_CHAN_COUNT number of + * channels can be present. + * + * @param codec_cfg The codec configuration to extract data from. + * @param chan_allocation Pointer to the variable to store the extracted value in. + * @param fallback_to_default If true this function will provide the default value of + * ESP_BLE_AUDIO_LOCATION_MONO_AUDIO if the type is not + * found when @p codec_cfg.id is BT_HCI_CODING_FORMAT_LC3. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_get_chan_allocation(const esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_location_t *chan_allocation, + bool fallback_to_default); + +/** + * @brief Set the channel allocation of a codec configuration. + * + * @param codec_cfg The codec configuration to set data for. + * @param chan_allocation The channel allocation to set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_set_chan_allocation(esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_location_t chan_allocation); + +/** + * @brief Extract frame size in octets from codec config. + * + * The overall SDU size will be octets_per_frame * blocks_per_sdu. + * + * The Bluetooth specifications are not clear about this value - it does not state that + * the codec shall use this SDU size only. A codec like LC3 supports variable bit-rate + * (per SDU) hence it might be allowed for an encoder to reduce the frame size below this + * value. + * Hence it is recommended to use the received SDU size and divide by + * blocks_per_sdu rather than relying on this octets_per_sdu value to be fixed. + * + * @param codec_cfg The codec configuration to extract data from. + * @param octets_per_frame The frame length in octets on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_get_octets_per_frame(const esp_ble_audio_codec_cfg_t *codec_cfg, + uint16_t *octets_per_frame); + +/** + * @brief Set the octets per codec frame of a codec configuration. + * + * @param codec_cfg The codec configuration to set data for. + * @param octets_per_frame The octets per codec frame to set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_set_octets_per_frame(esp_ble_audio_codec_cfg_t *codec_cfg, + uint16_t octets_per_frame); + +/** + * @brief Extract number of audio frame blocks in each SDU from codec config. + * + * The overall SDU size will be octets_per_frame * frame_blocks_per_sdu * number-of-channels. + * + * If this value is not present a default value of 1 shall be used. + * + * A frame block is one or more frames that represents data for the same period of time + * but for different channels. If the stream have two audio channels and this value is + * two there will be four frames in the SDU. + * + * @param codec_cfg The codec configuration to extract data from. + * @param frame_blocks The count of codec frame blocks in each SDU on success. + * @param fallback_to_default If true this function will return the default value of 1 + * if the type is not found when @p codec_cfg.id is + * BT_HCI_CODING_FORMAT_LC3. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_get_frame_blocks_per_sdu(const esp_ble_audio_codec_cfg_t *codec_cfg, + uint8_t *frame_blocks, + bool fallback_to_default); + +/** + * @brief Set the frame blocks per SDU of a codec configuration. + * + * @param codec_cfg The codec configuration to set data for. + * @param frame_blocks The frame blocks per SDU to set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_set_frame_blocks_per_sdu(esp_ble_audio_codec_cfg_t *codec_cfg, + uint8_t frame_blocks); + +/** + * @brief Lookup a specific codec configuration value. + * + * @param codec_cfg The codec data to search in. + * @param type The type id to look for. + * @param data Pointer to the data-pointer to update when item is found. + * @param data_len Length of found @p data (may be 0) on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_get_val(const esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_codec_cfg_type_t type, + const uint8_t **data, size_t *data_len); + +/** + * @brief Set or add a specific codec configuration value. + * + * @param codec_cfg The codec data to set the value in. + * @param type The type id to set. + * @param data Pointer to the data-pointer to set. + * @param data_len Length of @p data. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_set_val(esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_codec_cfg_type_t type, + const uint8_t *data, size_t data_len); + +/** + * @brief Unset a specific codec configuration value. + * + * The type and the value will be removed from the codec configuration. + * + * @param codec_cfg The codec data to set the value in. + * @param type The type id to unset. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_unset_val(esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_codec_cfg_type_t type); + +/** + * @brief Lookup a specific metadata value based on type. + * + * @param codec_cfg The codec data to search in. + * @param type The type id to look for + * @param data Pointer to the data-pointer to update when item is found. + * @param data_len Length of found @p data (may be 0) on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_meta_get_val(const esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_metadata_type_t type, + const uint8_t **data, size_t *data_len); + +/** + * @brief Set or add a specific codec configuration metadata value. + * + * @param codec_cfg The codec configuration to set the value in. + * @param type The type id to set. + * @param data Pointer to the data-pointer to set. + * @param data_len Length of @p data. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_meta_set_val(esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_metadata_type_t type, + const uint8_t *data, size_t data_len); + +/** + * @brief Unset a specific codec configuration metadata value. + * + * The type and the value will be removed from the codec configuration metadata. + * + * @param codec_cfg The codec data to set the value in. + * @param type The type id to unset. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_meta_unset_val(esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_metadata_type_t type); + +/** + * @brief Extract preferred contexts. + * + * @param codec_cfg The codec data to search in. + * @param ctx The preferred context type on success. + * @param fallback_to_default If true this function will provide the default value of + * ESP_BLE_AUDIO_CONTEXT_TYPE_UNSPECIFIED if the type + * is not found when @p codec_cfg.id is + * BT_HCI_CODING_FORMAT_LC3. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_meta_get_pref_context(const esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_context_t *ctx, + bool fallback_to_default); + +/** + * @brief Set the preferred context of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param ctx The preferred context to set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_meta_set_pref_context(esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_context_t ctx); + +/** + * @brief Extract stream contexts. + * + * @param codec_cfg The codec data to search in. + * @param ctx The stream context type on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_meta_get_stream_context(const esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_context_t *ctx); + +/** + * @brief Set the stream context of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param ctx The stream context to set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_meta_set_stream_context(esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_context_t ctx); + +/** + * @brief Extract program info. + * + * @param codec_cfg The codec data to search in. + * @param program_info Pointer to the UTF-8 formatted program info. + * @param program_info_len The length of the @p program_info (may be 0) on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_meta_get_program_info(const esp_ble_audio_codec_cfg_t *codec_cfg, + const uint8_t **program_info, + size_t *program_info_len); + +/** + * @brief Set the program info of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param program_info The program info to set. + * @param program_info_len The length of @p program_info. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_meta_set_program_info(esp_ble_audio_codec_cfg_t *codec_cfg, + const uint8_t *program_info, + size_t program_info_len); + +/** + * @brief Extract language. + * + * @param codec_cfg The codec data to search in. + * @param language Pointer to the language bytes (of length ESP_BLE_AUDIO_LANG_SIZE). + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_meta_get_language(const esp_ble_audio_codec_cfg_t *codec_cfg, + const uint8_t **language); + +/** + * @brief Set the language of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param language The 24-bit language to set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_meta_set_language(esp_ble_audio_codec_cfg_t *codec_cfg, + const uint8_t language[ESP_BLE_AUDIO_LANG_SIZE]); + +/** + * @brief Extract CCID list. + * + * @param codec_cfg The codec data to search in. + * @param ccid_list Pointer to the array containing 8-bit CCIDs. + * @param ccid_list_len The length of the @p ccid_list (may be 0) on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_meta_get_ccid_list(const esp_ble_audio_codec_cfg_t *codec_cfg, + const uint8_t **ccid_list, + size_t *ccid_list_len); + +/** + * @brief Set the CCID list of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param ccid_list The program info to set. + * @param ccid_list_len The length of @p ccid_list. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_meta_set_ccid_list(esp_ble_audio_codec_cfg_t *codec_cfg, + const uint8_t *ccid_list, + size_t ccid_list_len); + +/** + * @brief Extract parental rating. + * + * @param codec_cfg The codec data to search in. + * @param parental_rating The parental rating on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_meta_get_parental_rating(const esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_parental_rating_t *parental_rating); + +/** + * @brief Set the parental rating of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param parental_rating The parental rating to set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_meta_set_parental_rating(esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_parental_rating_t parental_rating); + +/** + * @brief Extract program info URI. + * + * @param codec_cfg The codec data to search in. + * @param program_info_uri Pointer to the UTF-8 formatted program info URI. + * @param program_info_uri_len The length of the @p program_info_uri (may be 0) on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_meta_get_program_info_uri(const esp_ble_audio_codec_cfg_t *codec_cfg, + const uint8_t **program_info_uri, + size_t *program_info_uri_len); + +/** + * @brief Set the program info URI of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param program_info_uri The program info URI to set. + * @param program_info_uri_len The length of @p program_info_uri. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_meta_set_program_info_uri(esp_ble_audio_codec_cfg_t *codec_cfg, + const uint8_t *program_info_uri, + size_t program_info_uri_len); + +/** + * @brief Extract audio active state. + * + * @param codec_cfg The codec data to search in. + * @param state The preferred context type on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_meta_get_audio_active_state(const esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_active_state_t *state); + +/** + * @brief Set the audio active state of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param state The audio active state to set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_meta_set_audio_active_state(esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_active_state_t state); + +/** + * @brief Extract broadcast audio immediate rendering flag. + * + * @param codec_cfg The codec data to search in. + * @param found Indicate if the flag is found on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_meta_get_broadcast_audio_immediate_rend_flag(const esp_ble_audio_codec_cfg_t *codec_cfg, + bool *found); + +/** + * @brief Set the broadcast audio immediate rendering flag of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_meta_set_broadcast_audio_immediate_rend_flag(esp_ble_audio_codec_cfg_t *codec_cfg); + +/** + * @brief Extract assisted listening stream. + * + * @param codec_cfg The codec data to search in. + * @param val The assisted listening stream value on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_meta_get_assisted_listening_stream(const esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_assisted_listening_stream_t *val); + +/** + * @brief Set the assisted listening stream value of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param val The assisted listening stream value to set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_meta_set_assisted_listening_stream(esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_assisted_listening_stream_t val); + +/** + * @brief Extract broadcast name. + * + * @param codec_cfg The codec data to search in. + * @param broadcast_name Pointer to the UTF-8 formatted broadcast name. + * @param broadcast_name_len The length of the @p broadcast_name (may be 0) on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_meta_get_broadcast_name(const esp_ble_audio_codec_cfg_t *codec_cfg, + const uint8_t **broadcast_name, + size_t *broadcast_name_len); + +/** + * @brief Set the broadcast name of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param broadcast_name The broadcast name to set. + * @param broadcast_name_len The length of @p broadcast_name. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_meta_set_broadcast_name(esp_ble_audio_codec_cfg_t *codec_cfg, + const uint8_t *broadcast_name, + size_t broadcast_name_len); + +/** + * @brief Extract extended metadata. + * + * @param codec_cfg The codec data to search in. + * @param extended_meta Pointer to the extended metadata. + * @param extended_meta_len The length of the @p extended_meta (may be 0) on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_meta_get_extended(const esp_ble_audio_codec_cfg_t *codec_cfg, + const uint8_t **extended_meta, + size_t *extended_meta_len); + +/** + * @brief Set the extended metadata of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param extended_meta The extended metadata to set. + * @param extended_meta_len The length of @p extended_meta. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_meta_set_extended(esp_ble_audio_codec_cfg_t *codec_cfg, + const uint8_t *extended_meta, + size_t extended_meta_len); + +/** + * @brief Extract vendor specific metadata. + * + * @param codec_cfg The codec data to search in. + * @param vendor_meta Pointer to the vendor specific metadata. + * @param vendor_meta_len The length of the @p vendor_meta (may be 0) on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_meta_get_vendor(const esp_ble_audio_codec_cfg_t *codec_cfg, + const uint8_t **vendor_meta, + size_t *vendor_meta_len); + +/** + * @brief Set the vendor specific metadata of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param vendor_meta The vendor specific metadata to set. + * @param vendor_meta_len The length of @p vendor_meta. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cfg_meta_set_vendor(esp_ble_audio_codec_cfg_t *codec_cfg, + const uint8_t *vendor_meta, + size_t vendor_meta_len); + +/** + * @brief Lookup a specific value based on type. + * + * @param codec_cap The codec data to search in. + * @param type The type id to look for. + * @param data Pointer to the data-pointer to update when item is found. + * @param data_len Length of found @p data (may be 0) on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_get_val(const esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_codec_cap_type_t type, + const uint8_t **data, size_t *data_len); + +/** + * @brief Set or add a specific codec capability value. + * + * @param codec_cap The codec data to set the value in. + * @param type The type id to set. + * @param data Pointer to the data-pointer to set. + * @param data_len Length of @p data. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_set_val(esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_codec_cap_type_t type, + const uint8_t *data, size_t data_len); + +/** + * @brief Unset a specific codec capability value. + * + * The type and the value will be removed from the codec capability. + * + * @param codec_cap The codec data to set the value in. + * @param type The type id to unset. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_unset_val(esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_codec_cap_type_t type); + +/** + * @brief Extract the frequency from a codec capability. + * + * @param codec_cap The codec capabilities to extract data from. + * @param freq Bitfield of supported frequencies on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_get_freq(const esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_codec_cap_freq_t *freq); + +/** + * @brief Set the supported frequencies of a codec capability. + * + * @param codec_cap The codec capabilities to set data for. + * @param freq The supported frequencies to set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_set_freq(esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_codec_cap_freq_t freq); + +/** + * @brief Extract the frequency from a codec capability. + * + * @param codec_cap The codec capabilities to extract data from. + * @param frame_dur Bitfield of supported frame durations on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_get_frame_dur(const esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_codec_cap_frame_dur_t *frame_dur); + +/** + * @brief Set the frame duration of a codec capability. + * + * @param codec_cap The codec capabilities to set data for. + * @param frame_dur The frame duration to set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_set_frame_dur(esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_codec_cap_frame_dur_t frame_dur); + +/** + * @brief Extract the frequency from a codec capability. + * + * @param codec_cap The codec capabilities to extract data from. + * @param chan_count Number of supported channel counts on success. + * @param fallback_to_default If true this function will provide the default value of 1 + * if the type is not found when @p codec_cap.id is + * BT_HCI_CODING_FORMAT_LC3. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_get_supported_audio_chan_counts(const esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_codec_cap_chan_count_t *chan_count, + bool fallback_to_default); + +/** + * @brief Set the channel count of a codec capability. + * + * @param codec_cap The codec capabilities to set data for. + * @param chan_count The channel count frequency to set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_set_supported_audio_chan_counts(esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_codec_cap_chan_count_t chan_count); + +/** + * @brief Extract the supported octets per codec frame from a codec capability. + * + * @param codec_cap The codec capabilities to extract data from. + * @param codec_frame Struct to place the resulting values in. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_get_octets_per_frame(const esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_codec_octets_per_codec_frame_t *codec_frame); + +/** + * @brief Set the octets per codec frame of a codec capability. + * + * @param codec_cap The codec capabilities to set data for. + * @param codec_frame The octets per codec frame to set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_set_octets_per_frame(esp_ble_audio_codec_cap_t *codec_cap, + const esp_ble_audio_codec_octets_per_codec_frame_t *codec_frame); + +/** + * @brief Extract the maximum codec frames per SDU from a codec capability. + * + * @param codec_cap The codec capabilities to extract data from. + * @param codec_frames_per_sdu Maximum number of codec frames per SDU supported on success. + * @param fallback_to_default If true this function will provide the default value of 1 + * if the type is not found when @p codec_cap.id is + * BT_HCI_CODING_FORMAT_LC3. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_get_max_codec_frames_per_sdu(const esp_ble_audio_codec_cap_t *codec_cap, + uint8_t *codec_frames_per_sdu, + bool fallback_to_default); + +/** + * @brief Set the maximum codec frames per SDU of a codec capability. + * + * @param codec_cap The codec capabilities to set data for. + * @param codec_frames_per_sdu The maximum codec frames per SDU to set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_set_max_codec_frames_per_sdu(esp_ble_audio_codec_cap_t *codec_cap, + uint8_t codec_frames_per_sdu); + +/** + * @brief Lookup a specific metadata value based on type. + * + * @param codec_cap The codec data to search in. + * @param type The type id to look for. + * @param data Pointer to the data-pointer to update when item is found. + * @param data_len Length of found @p data (may be 0) on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_meta_get_val(const esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_metadata_type_t type, + const uint8_t **data, size_t *data_len); + +/** + * @brief Set or add a specific codec capability metadata value. + * + * @param codec_cap The codec capability to set the value in. + * @param type The type id to set. + * @param data Pointer to the data-pointer to set. + * @param data_len Length of @p data. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_meta_set_val(esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_metadata_type_t type, + const uint8_t *data, size_t data_len); + +/** + * @brief Unset a specific codec capability metadata value. + * + * The type and the value will be removed from the codec capability metadata. + * + * @param codec_cap The codec data to set the value in. + * @param type The type id to unset. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_meta_unset_val(esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_metadata_type_t type); + +/** + * @brief Extract preferred contexts. + * + * @param codec_cap The codec data to search in. + * @param ctx The preferred context type on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_meta_get_pref_context(const esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_context_t *ctx); + +/** + * @brief Set the preferred context of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param ctx The preferred context to set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_meta_set_pref_context(esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_context_t ctx); + +/** + * @brief Extract stream contexts. + * + * @param codec_cap The codec data to search in. + * @param ctx The stream context type on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_meta_get_stream_context(const esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_context_t *ctx); + +/** + * @brief Set the stream context of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param ctx The stream context to set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_meta_set_stream_context(esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_context_t ctx); + +/** + * @brief Extract program info. + * + * @param codec_cap The codec data to search in. + * @param program_info Pointer to the UTF-8 formatted program info. + * @param program_info_len The length of the @p program_info (may be 0) on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_meta_get_program_info(const esp_ble_audio_codec_cap_t *codec_cap, + const uint8_t **program_info, + size_t *program_info_len); + +/** + * @brief Set the program info of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param program_info The program info to set. + * @param program_info_len The length of @p program_info. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_meta_set_program_info(esp_ble_audio_codec_cap_t *codec_cap, + const uint8_t *program_info, + size_t program_info_len); + +/** + * @brief Extract language. + * + * @param codec_cap The codec data to search in. + * @param language Pointer to the language bytes (of length ESP_BLE_AUDIO_LANG_SIZE). + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_meta_get_language(const esp_ble_audio_codec_cap_t *codec_cap, + const uint8_t **language); + +/** + * @brief Set the language of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param language The 24-bit language to set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_meta_set_language(esp_ble_audio_codec_cap_t *codec_cap, + const uint8_t language[ESP_BLE_AUDIO_LANG_SIZE]); + +/** + * @brief Extract CCID list. + * + * @param codec_cap The codec data to search in. + * @param ccid_list Pointer to the array containing 8-bit CCIDs. + * @param ccid_list_len The length of the @p ccid_list (may be 0) on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_meta_get_ccid_list(const esp_ble_audio_codec_cap_t *codec_cap, + const uint8_t **ccid_list, + size_t *ccid_list_len); + +/** + * @brief Set the CCID list of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param ccid_list The program info to set. + * @param ccid_list_len The length of @p ccid_list. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_meta_set_ccid_list(esp_ble_audio_codec_cap_t *codec_cap, + const uint8_t *ccid_list, + size_t ccid_list_len); + +/** + * @brief Extract parental rating. + * + * @param codec_cap The codec data to search in. + * @param parental_rating The parental rating on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_meta_get_parental_rating(const esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_parental_rating_t *parental_rating); + +/** + * @brief Set the parental rating of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param parental_rating The parental rating to set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_meta_set_parental_rating(esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_parental_rating_t parental_rating); + +/** + * @brief Extract program info URI. + * + * @param codec_cap The codec data to search in. + * @param program_info_uri Pointer to the UTF-8 formatted program info URI. + * @param program_info_uri_len The length of the @p program_info_uri (may be 0) on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_meta_get_program_info_uri(const esp_ble_audio_codec_cap_t *codec_cap, + const uint8_t **program_info_uri, + size_t *program_info_uri_len); + +/** + * @brief Set the program info URI of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param program_info_uri The program info URI to set. + * @param program_info_uri_len The length of @p program_info_uri. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_meta_set_program_info_uri(esp_ble_audio_codec_cap_t *codec_cap, + const uint8_t *program_info_uri, + size_t program_info_uri_len); + +/** + * @brief Extract audio active state. + * + * @param codec_cap The codec data to search in. + * @param state The preferred context type on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_meta_get_audio_active_state(const esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_active_state_t *state); + +/** + * @brief Set the audio active state of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param state The audio active state to set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_meta_set_audio_active_state(esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_active_state_t state); + +/** + * @brief Extract broadcast audio immediate rendering flag. + * + * @param codec_cap The codec data to search in. + * @param found Indicate if the flag is found on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_meta_get_broadcast_audio_immediate_rend_flag(const esp_ble_audio_codec_cap_t *codec_cap, + bool *found); + +/** + * @brief Set the broadcast audio immediate rendering flag of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_meta_set_broadcast_audio_immediate_rend_flag(esp_ble_audio_codec_cap_t *codec_cap); + +/** + * @brief Extract assisted listening stream. + * + * @param codec_cap The codec data to search in. + * @param val The assisted listening stream value on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_meta_get_assisted_listening_stream(const esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_assisted_listening_stream_t *val); + +/** + * @brief Set the assisted listening stream value of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param val The assisted listening stream value to set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_meta_set_assisted_listening_stream(esp_ble_audio_codec_cap_t *codec_cap, + esp_ble_audio_assisted_listening_stream_t val); + +/** + * @brief Extract broadcast name. + * + * @param codec_cap The codec data to search in. + * @param broadcast_name Pointer to the UTF-8 formatted broadcast name. + * @param broadcast_name_len The length of the @p broadcast_name (may be 0) on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_meta_get_broadcast_name(const esp_ble_audio_codec_cap_t *codec_cap, + const uint8_t **broadcast_name, + size_t *broadcast_name_len); + +/** + * @brief Set the broadcast name of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param broadcast_name The broadcast name to set. + * @param broadcast_name_len The length of @p broadcast_name. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_meta_set_broadcast_name(esp_ble_audio_codec_cap_t *codec_cap, + const uint8_t *broadcast_name, + size_t broadcast_name_len); + +/** + * @brief Extract extended metadata. + * + * @param codec_cap The codec data to search in. + * @param extended_meta Pointer to the extended metadata. + * @param extended_meta_len The length of the @p extended_meta (may be 0) on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_meta_get_extended(const esp_ble_audio_codec_cap_t *codec_cap, + const uint8_t **extended_meta, + size_t *extended_meta_len); + +/** + * @brief Set the extended metadata of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param extended_meta The extended metadata to set. + * @param extended_meta_len The length of @p extended_meta. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_meta_set_extended(esp_ble_audio_codec_cap_t *codec_cap, + const uint8_t *extended_meta, + size_t extended_meta_len); + +/** + * @brief Extract vendor specific metadata. + * + * @param codec_cap The codec data to search in. + * @param vendor_meta Pointer to the vendor specific metadata. + * @param vendor_meta_len The length of the @p vendor_meta (may be 0) on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_meta_get_vendor(const esp_ble_audio_codec_cap_t *codec_cap, + const uint8_t **vendor_meta, + size_t *vendor_meta_len); + +/** + * @brief Set the vendor specific metadata of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param vendor_meta The vendor specific metadata to set. + * @param vendor_meta_len The length of @p vendor_meta. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_codec_cap_meta_set_vendor(esp_ble_audio_codec_cap_t *codec_cap, + const uint8_t *vendor_meta, + size_t vendor_meta_len); + +#ifdef __cplusplus +} +#endif + +#endif /* ESP_BLE_AUDIO_CODEC_API_H_ */ diff --git a/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_common_api.h b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_common_api.h new file mode 100644 index 0000000000..ee6add40b7 --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_common_api.h @@ -0,0 +1,172 @@ +/* + * SPDX-FileCopyrightText: 2020 Intel Corporation + * SPDX-FileCopyrightText: 2020-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ESP_BLE_AUDIO_COMMON_API_H_ +#define ESP_BLE_AUDIO_COMMON_API_H_ + +#include +#include +#include +#include + +#include "sdkconfig.h" +#include "esp_err.h" + +#include "common/init.h" +#include "common/host.h" +#include "common/app/gatt.h" + +#include "esp_ble_iso_common_api.h" + +#include "esp_ble_audio_defs.h" +#include "esp_ble_audio_csip_api.h" +#include "esp_ble_audio_vcp_api.h" +#include "esp_ble_audio_micp_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Helper for parsing length-type-value data. + * + * @param ltv Length-type-value (LTV) encoded data. + * @param size Size of the @p ltv data. + * @param func Callback function which will be called for each element + * that's found in the data. The callback should return + * true to continue parsing, or false to stop parsing. + * @param user_data User data to be passed to the callback. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_data_parse(const uint8_t ltv[], size_t size, + bool (*func)(uint8_t type, + const uint8_t *data, + uint8_t data_len, + void *user_data), + void *user_data); + +/** + * @brief Get the value of a specific data type in an length-type-value data array. + * + * @param ltv_data The array containing the length-type-value tuples. + * @param size The size of @p ltv_data. + * @param type The type to get the value for. + * @param data Pointer to the data-pointer to update when item is found. + * Any found data will be little endian. + * @param data_len Length The length of found @p data (may be 0). + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_data_get_val(const uint8_t ltv_data[], + size_t size, uint8_t type, + const uint8_t **data, + uint8_t *data_len); + +/** + * @brief Function to get the number of channels from the channel allocation. + * + * @param chan_allocation The channel allocation. + * + * @return The number of channels. + */ +uint8_t esp_ble_audio_get_chan_count(esp_ble_audio_location_t chan_allocation); + +/** + * @brief Start GATT service discovery. + * + * @note This function is only needed while using NimBLE Host. + * + * @param conn_handle Connection Handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_gattc_disc_start(uint16_t conn_handle); + +/*!< Audio GAP Extended Scan Recv event */ +#define ESP_BLE_AUDIO_GAP_EVENT_EXT_SCAN_RECV BT_LE_GAP_APP_EVENT_EXT_SCAN_RECV +/*!< Audio GAP Periodic Sync Established event */ +#define ESP_BLE_AUDIO_GAP_EVENT_PA_SYNC BT_LE_GAP_APP_EVENT_PA_SYNC +/*!< Audio GAP Periodic Sync Lost event */ +#define ESP_BLE_AUDIO_GAP_EVENT_PA_SYNC_LOST BT_LE_GAP_APP_EVENT_PA_SYNC_LOST +/*!< Audio GAP Connection Complete event */ +#define ESP_BLE_AUDIO_GAP_EVENT_ACL_CONNECT BT_LE_GAP_APP_EVENT_ACL_CONNECT +/*!< Audio GAP Disconnection Complete event */ +#define ESP_BLE_AUDIO_GAP_EVENT_ACL_DISCONNECT BT_LE_GAP_APP_EVENT_ACL_DISCONNECT +/*!< Audio GAP Security Change event */ +#define ESP_BLE_AUDIO_GAP_EVENT_SECURITY_CHANGE BT_LE_GAP_APP_EVENT_SECURITY_CHANGE +/** Audio GAP application event structure */ +typedef struct bt_le_gap_app_event esp_ble_audio_gap_app_event_t; + +/*!< Audio GATT MTU exchange complete event */ +#define ESP_BLE_AUDIO_GATT_EVENT_GATT_MTU_CHANGE BT_LE_GATT_APP_EVENT_GATT_MTU_CHANGE +/*!< Audio GATT client discovery complete event */ +#define ESP_BLE_AUDIO_GATT_EVENT_GATTC_DISC_CMPL BT_LE_GATT_APP_EVENT_GATTC_DISC_CMPL +/** Audio GATT application event structure */ +typedef struct bt_le_gatt_app_event esp_ble_audio_gatt_app_event_t; + +/** Contains callback functions for GAP and GATT events */ +typedef struct { + bt_le_gap_app_cb gap_cb; /*!< GAP event callbacks */ + bt_le_gatt_app_cb gatt_cb; /*!< GATT event callbacks */ +} esp_ble_audio_init_info_t; + +/** + * @brief Post an application-layer GAP event for audio internal usage. + * + * @note This function is only needed while using NimBLE Host. + * + * @param type Event type. + * @param param Event parameters. + */ +void esp_ble_audio_gap_app_post_event(uint8_t type, void *param); + +/** + * @brief Post an application-layer GATT event for audio internal usage. + * + * @note This function is only needed while using NimBLE Host. + * + * @param type Event type. + * @param param Event parameters. + */ +void esp_ble_audio_gatt_app_post_event(uint8_t type, void *param); + +/** + * @brief Initialize BLE Audio common functionality. + * + * @param info Initialization parameters. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_common_init(esp_ble_audio_init_info_t *info); + +/** Contains service instances for audio profiles */ +typedef struct { +#if CONFIG_BT_CSIP_SET_MEMBER + struct { + esp_ble_audio_csip_set_member_svc_inst_t *svc_inst; /*!< Pointer of CSIS Service instance */ + bool included_by_cas; /*!< Indicate if the CSIS Service is included by CAS */ + } csis_insts[CONFIG_BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT]; /*!< Structures of CSIS Service instances */ +#endif /* CONFIG_BT_CSIP_SET_MEMBER */ + uint8_t dummy; /*!< Dummy field to avoid empty struct */ +} esp_ble_audio_start_info_t; + +/** + * @brief Start BLE Audio services. + * + * @param info Service instances to start. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_common_start(esp_ble_audio_start_info_t *info); + +#ifdef __cplusplus +} +#endif + +#endif /* ESP_BLE_AUDIO_COMMON_API_H_ */ diff --git a/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_csip_api.h b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_csip_api.h new file mode 100644 index 0000000000..6dbe03e49b --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_csip_api.h @@ -0,0 +1,294 @@ +/* + * SPDX-FileCopyrightText: 2021-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ESP_BLE_AUDIO_CSIP_API_H_ +#define ESP_BLE_AUDIO_CSIP_API_H_ + +#include +#include +#include + +#include "sdkconfig.h" +#include "esp_err.h" + +#include +#include + +#include "common/init.h" +#include "common/host.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*!< Size of the Set Identification Resolving Key (SIRK) */ +#define ESP_BLE_AUDIO_CSIP_SIRK_SIZE BT_CSIP_SIRK_SIZE + +/*!< Size of the Resolvable Set Identifier (RSI) */ +#define ESP_BLE_AUDIO_CSIP_RSI_SIZE BT_CSIP_RSI_SIZE + +/*!< Accept the request to read the SIRK as plaintext */ +#define ESP_BLE_AUDIO_CSIP_READ_SIRK_REQ_RSP_ACCEPT BT_CSIP_READ_SIRK_REQ_RSP_ACCEPT +/*!< Accept the request to read the SIRK, but return encrypted SIRK */ +#define ESP_BLE_AUDIO_CSIP_READ_SIRK_REQ_RSP_ACCEPT_ENC BT_CSIP_READ_SIRK_REQ_RSP_ACCEPT_ENC +/*!< Reject the request to read the SIRK */ +#define ESP_BLE_AUDIO_CSIP_READ_SIRK_REQ_RSP_REJECT BT_CSIP_READ_SIRK_REQ_RSP_REJECT +/*!< SIRK is available only via an OOB procedure */ +#define ESP_BLE_AUDIO_CSIP_READ_SIRK_REQ_RSP_OOB_ONLY BT_CSIP_READ_SIRK_REQ_RSP_OOB_ONLY + +/** + * @brief Helper to declare bt_data array including RSI. + * + * This macro is mainly for creating an array of struct bt_data elements. + * + * @param _rsi Pointer to the RSI value. + */ +#define ESP_BLE_AUDIO_CSIP_DATA_RSI(_rsi) BT_CSIP_DATA_RSI(_rsi) + +/** Callback structure for the Coordinated Set Identification Service */ +typedef struct bt_csip_set_member_cb esp_ble_audio_csip_set_member_cb_t; + +/** Coordinated Set Identification Service instance */ +typedef struct bt_csip_set_member_svc_inst esp_ble_audio_csip_set_member_svc_inst_t; + +/** Register structure for Coordinated Set Identification Service */ +typedef struct bt_csip_set_member_register_param esp_ble_audio_csip_set_member_register_param_t; + +/** Struct to hold information about a service instance */ +typedef struct bt_csip_set_member_set_info esp_ble_audio_csip_set_member_set_info_t; + +/** Struct to hold the Coordinated Set Identification Profile Set Coordinator callbacks */ +typedef struct bt_csip_set_coordinator_cb esp_ble_audio_csip_set_coordinator_cb_t; + +/** Information about a specific set */ +typedef struct bt_csip_set_coordinator_set_info esp_ble_audio_csip_set_coordinator_set_info_t; + +/** Struct representing a coordinated set instance on a remote device */ +typedef struct bt_csip_set_coordinator_csis_inst esp_ble_audio_csip_set_coordinator_csis_inst_t; + +/** Struct representing a remote device as a set member */ +typedef struct bt_csip_set_coordinator_set_member esp_ble_audio_csip_set_coordinator_set_member_t; + +/** + * @brief Get the service declaration attribute. + * + * The first service attribute can be included in any other GATT service. + * + * @param svc_inst Pointer to the Coordinated Set Identification Service. + * + * @return The first CSIS attribute instance. + */ +void *esp_ble_audio_csip_set_member_svc_decl_get(const esp_ble_audio_csip_set_member_svc_inst_t *svc_inst); + +/** + * @brief Register a Coordinated Set Identification Service instance. + * + * This will register and enable the service and make it discoverable by clients. + * + * This shall only be done as a server. + * + * @param param Coordinated Set Identification Service register parameters. + * @param svc_inst Pointer to the registered Coordinated Set Identification Service. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_csip_set_member_register(const esp_ble_audio_csip_set_member_register_param_t *param, + esp_ble_audio_csip_set_member_svc_inst_t **svc_inst); + +/** + * @brief Unregister a Coordinated Set Identification Service instance. + * + * This will unregister and disable the service instance. + * + * @param svc_inst Pointer to the registered Coordinated Set Identification Service. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_csip_set_member_unregister(esp_ble_audio_csip_set_member_svc_inst_t *svc_inst); + +/** + * @brief Set the SIRK of a service instance. + * + * @param svc_inst Pointer to the registered Coordinated Set Identification Service. + * @param sirk The new SIRK. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_csip_set_member_sirk(esp_ble_audio_csip_set_member_svc_inst_t *svc_inst, + const uint8_t sirk[ESP_BLE_AUDIO_CSIP_SIRK_SIZE]); + +/** + * @brief Set a new size and rank for a service instance. + * + * This function can be used to dynamically change the size and rank of a service instance. + * It is important to note that a set cannot have multiple devices with the same rank in a + * set, and it is up to the caller of this function to ensure that. + * Similarly, it is important that the size is updated on all devices in the set at the same + * time. + * + * If CONFIG_BT_CSIP_SET_MEMBER_SIZE_NOTIFIABLE is enabled, this will also send a notification + * to all connected or bonded clients. + * + * @param svc_inst The service instance. + * @param size The new set size. + * @param rank The new rank. Ignored if the @p svc_inst is not lockable. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_csip_set_member_set_size_and_rank(esp_ble_audio_csip_set_member_svc_inst_t *svc_inst, + uint8_t size, uint8_t rank); + +/** + * @brief Get information about a service instances. + * + * @param svc_inst The service instance. + * @param info Pointer to a struct to store the information in. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_csip_set_member_get_info(const esp_ble_audio_csip_set_member_svc_inst_t *svc_inst, + esp_ble_audio_csip_set_member_set_info_t *info); + +/** + * @brief Generate the Resolvable Set Identifier (RSI) value. + * + * This will generate RSI for given @p svc_inst instance. + * + * @param svc_inst Pointer to the Coordinated Set Identification Service. + * @param rsi Pointer to the 6-octet newly generated RSI data in little-endian. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_csip_set_member_generate_rsi(const esp_ble_audio_csip_set_member_svc_inst_t *svc_inst, + uint8_t rsi[ESP_BLE_AUDIO_CSIP_RSI_SIZE]); + +/** + * @brief Locks a specific Coordinated Set Identification Service instance on the server. + * + * @param svc_inst Pointer to the Coordinated Set Identification Service. + * @param lock If true lock the set, if false release the set. + * @param force This argument only have meaning when @p lock is false + * (release) and will force release the lock, regardless of who + * took the lock. + + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_csip_set_member_lock(esp_ble_audio_csip_set_member_svc_inst_t *svc_inst, + bool lock, bool force); + +/** + * @brief Initialise the csip_set_coordinator instance for a connection. + * This will do a discovery on the device and prepare the instance + * for following commands. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_csip_set_coordinator_discover(uint16_t conn_handle); + +/** + * @brief Get the set member from a connection pointer. + * + * Get the Coordinated Set Identification Profile Set Coordinator pointer + * from connection handle. + * Only Set Coordinators that have been initiated can be retrieved. + * + * @param conn_handle Connection handle. + * + * @return Pointer to a Coordinated Set Identification Profile Set Coordinator instance. + * NULL if the connection has not been found or has not done discovery yet. + */ +esp_ble_audio_csip_set_coordinator_set_member_t * +esp_ble_audio_csip_set_coordinator_set_member_by_conn(uint16_t conn_handle); + +/** + * @brief Check if advertising data indicates a set member. + * + * @param sirk The SIRK of the set to check against. + * @param data_type Type of the advertising data. + * @param data Pointer of the advertising data. + * @param data_len Length of the advertising data. + * + * @return True if the advertising data indicates a set member, false otherwise. + */ +bool esp_ble_audio_csip_set_coordinator_is_set_member(const uint8_t sirk[ESP_BLE_AUDIO_CSIP_SIRK_SIZE], + uint8_t data_type, const uint8_t *data, uint8_t data_len); + +/** + * @brief Registers callbacks for csip_set_coordinator. + * + * @param cb Pointer to the callback structure. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_csip_set_coordinator_register_cb(esp_ble_audio_csip_set_coordinator_cb_t *cb); + +/** + * @brief Access Coordinated Set devices in an ordered manner as a client. + * + * This function will read the lock state of all devices and if all devices are + * in the unlocked state, then @p cb will be called with the same members as + * provided by @p members, but where the members are ordered by rank (if present). + * + * This procedure only works if all the members have the lock characteristic, + * and all either has rank = 0 or unique ranks. + * + * If any of the members are in the locked state, the procedure will be cancelled. + * + * This can only be done on members that are bonded. + * + * @param members Array of set members to access. + * @param count Number of set members in @p members. + * @param set_info Pointer to the a specific set_info struct, as a member may + * be part of multiple sets. + * @param cb The callback function to be called for each member. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_csip_set_coordinator_ordered_access(const esp_ble_audio_csip_set_coordinator_set_member_t *members[], + uint8_t count, + const esp_ble_audio_csip_set_coordinator_set_info_t *set_info, + bt_csip_set_coordinator_ordered_access_t cb); + +/** + * @brief Lock an array of set members. + * + * The members will be locked starting from lowest rank going up. + * + * @param members Array of set members to lock. + * @param count Number of set members in @p members. + * @param set_info Pointer to the a specific set_info struct, as a member + * may be part of multiple sets. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_csip_set_coordinator_lock(const esp_ble_audio_csip_set_coordinator_set_member_t **members, + uint8_t count, + const esp_ble_audio_csip_set_coordinator_set_info_t *set_info); + +/** + * @brief Release an array of set members. + * + * The members will be released starting from highest rank going down. + * + * @param members Array of set members to lock. + * @param count Number of set members in @p members. + * @param set_info Pointer to the a specific set_info struct, as a member + * may be part of multiple sets. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_csip_set_coordinator_release(const esp_ble_audio_csip_set_coordinator_set_member_t **members, + uint8_t count, + const esp_ble_audio_csip_set_coordinator_set_info_t *set_info); + +#ifdef __cplusplus +} +#endif + +#endif /* ESP_BLE_AUDIO_CSIP_API_H_ */ diff --git a/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_defs.h b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_defs.h new file mode 100644 index 0000000000..df8e32fbd1 --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_defs.h @@ -0,0 +1,567 @@ +/* + * SPDX-FileCopyrightText: 2020 Intel Corporation + * SPDX-FileCopyrightText: 2020-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ESP_BLE_AUDIO_DEFS_H_ +#define ESP_BLE_AUDIO_DEFS_H_ + +#include +#include + +#include "sdkconfig.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*!< Minimum ATT MTU size required by Basic Audio Profile (BAP) */ +#define ESP_BLE_AUDIO_ATT_MTU_MIN 64 + +/** + * Audio direction sink. + * + * For a BAP Unicast Client or Broadcast Source this is considered outgoing audio (TX). + * For a BAP Unicast Server or Broadcast Sink this is considered incoming audio (RX). + */ +#define ESP_BLE_AUDIO_DIR_SINK BT_AUDIO_DIR_SINK +/** + * Audio direction source. + * + * For a BAP Unicast Client or Broadcast Source this is considered incoming audio (RX). + * For a BAP Unicast Server or Broadcast Sink this is considered outgoing audio (TX). + */ +#define ESP_BLE_AUDIO_DIR_SOURCE BT_AUDIO_DIR_SOURCE +/** Audio direction from the perspective of the BAP Unicast Server / BAP Broadcast Sink */ +typedef enum bt_audio_dir esp_ble_audio_dir_t; + +/*!< Size of the stream language value, e.g. "eng" */ +#define ESP_BLE_AUDIO_LANG_SIZE BT_AUDIO_LANG_SIZE + +/*!< Size of the broadcast ID in octets */ +#define ESP_BLE_AUDIO_BROADCAST_ID_SIZE BT_AUDIO_BROADCAST_ID_SIZE +/*!< Maximum broadcast ID value */ +#define ESP_BLE_AUDIO_BROADCAST_ID_MAX BT_AUDIO_BROADCAST_ID_MAX +/*!< Indicates that the server have no preference for the presentation delay */ +#define ESP_BLE_AUDIO_PD_PREF_NONE BT_AUDIO_PD_PREF_NONE +/*!< Maximum presentation delay in microseconds */ +#define ESP_BLE_AUDIO_PD_MAX BT_AUDIO_PD_MAX +/*!< Indicates that the unicast server does not have a preference for any retransmission number */ +#define ESP_BLE_AUDIO_RTN_PREF_NONE BT_AUDIO_RTN_PREF_NONE +/*!< The minimum size of a Broadcast Name as defined by Bluetooth Assigned Numbers */ +#define ESP_BLE_AUDIO_BROADCAST_NAME_LEN_MIN BT_AUDIO_BROADCAST_NAME_LEN_MIN +/*!< The maximum size of a Broadcast Name as defined by Bluetooth Assigned Numbers */ +#define ESP_BLE_AUDIO_BROADCAST_NAME_LEN_MAX BT_AUDIO_BROADCAST_NAME_LEN_MAX + +/*!< Unicast Server is connectable and is requesting a connection. */ +#define ESP_BLE_AUDIO_UNICAST_ANNOUNCEMENT_GENERAL BT_AUDIO_UNICAST_ANNOUNCEMENT_GENERAL +/*!< Unicast Server is connectable but is not requesting a connection. */ +#define ESP_BLE_AUDIO_UNICAST_ANNOUNCEMENT_TARGETED BT_AUDIO_UNICAST_ANNOUNCEMENT_TARGETED + +/*!< No context type */ +#define ESP_BLE_AUDIO_CONTEXT_TYPE_NONE BT_AUDIO_CONTEXT_TYPE_NONE +/** + * Identifies audio where the use case context does not match any other defined value, + * or where the context is unknown or cannot be determined. + */ +#define ESP_BLE_AUDIO_CONTEXT_TYPE_UNSPECIFIED BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED +/** + * Conversation between humans, for example, in telephony or video calls, including + * traditional cellular as well as VoIP and Push-to-Talk + */ +#define ESP_BLE_AUDIO_CONTEXT_TYPE_CONVERSATIONAL BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL +/*!< Media, for example, music playback, radio, podcast or movie soundtrack, or tv audio */ +#define ESP_BLE_AUDIO_CONTEXT_TYPE_MEDIA BT_AUDIO_CONTEXT_TYPE_MEDIA +/** + * Audio associated with video gaming, for example gaming media; gaming effects; music + * and in-game voice chat between participants; or a mix of all the above + */ +#define ESP_BLE_AUDIO_CONTEXT_TYPE_GAME BT_AUDIO_CONTEXT_TYPE_GAME +/*!< Instructional audio, for example, in navigation, announcements, or user guidance */ +#define ESP_BLE_AUDIO_CONTEXT_TYPE_INSTRUCTIONAL BT_AUDIO_CONTEXT_TYPE_INSTRUCTIONAL +/*!< Man-machine communication, for example, with voice recognition or virtual assistants */ +#define ESP_BLE_AUDIO_CONTEXT_TYPE_VOICE_ASSISTANTS BT_AUDIO_CONTEXT_TYPE_VOICE_ASSISTANTS +/** + * Live audio, for example, from a microphone where audio is perceived both through a + * direct acoustic path and through an LE Audio Stream + */ +#define ESP_BLE_AUDIO_CONTEXT_TYPE_LIVE BT_AUDIO_CONTEXT_TYPE_LIVE +/** + * Sound effects including keyboard and touch feedback; menu and user interface sounds; + * and other system sounds + */ +#define ESP_BLE_AUDIO_CONTEXT_TYPE_SOUND_EFFECTS BT_AUDIO_CONTEXT_TYPE_SOUND_EFFECTS +/** + * Notification and reminder sounds; attention-seeking audio, for example, + * in beeps signaling the arrival of a message + */ +#define ESP_BLE_AUDIO_CONTEXT_TYPE_NOTIFICATIONS BT_AUDIO_CONTEXT_TYPE_NOTIFICATIONS +/** + * Alerts the user to an incoming call, for example, an incoming telephony or video call, + * including traditional cellular as well as VoIP and Push-to-Talk + */ +#define ESP_BLE_AUDIO_CONTEXT_TYPE_RINGTONE BT_AUDIO_CONTEXT_TYPE_RINGTONE +/** + * Alarms and timers; immediate alerts, for example, in a critical battery alarm, + * timer expiry or alarm clock, toaster, cooker, kettle, microwave, etc. + */ +#define ESP_BLE_AUDIO_CONTEXT_TYPE_ALERTS BT_AUDIO_CONTEXT_TYPE_ALERTS +/*!< Emergency alarm Emergency sounds, for example, fire alarms or other urgent alerts */ +#define ESP_BLE_AUDIO_CONTEXT_TYPE_EMERGENCY_ALARM BT_AUDIO_CONTEXT_TYPE_EMERGENCY_ALARM +/*!< Any known context */ +#define ESP_BLE_AUDIO_CONTEXT_TYPE_ANY BT_AUDIO_CONTEXT_TYPE_ANY +/** Audio Context Type for Generic Audio */ +typedef enum bt_audio_context esp_ble_audio_context_t; + +/*!< No rating */ +#define ESP_BLE_AUDIO_PARENTAL_RATING_NO_RATING BT_AUDIO_PARENTAL_RATING_NO_RATING +/*!< For all ages */ +#define ESP_BLE_AUDIO_PARENTAL_RATING_AGE_ANY BT_AUDIO_PARENTAL_RATING_AGE_ANY +/*!< Recommended for listeners of age 5 and above */ +#define ESP_BLE_AUDIO_PARENTAL_RATING_AGE_5_OR_ABOVE BT_AUDIO_PARENTAL_RATING_AGE_5_OR_ABOVE +/*!< Recommended for listeners of age 6 and above */ +#define ESP_BLE_AUDIO_PARENTAL_RATING_AGE_6_OR_ABOVE BT_AUDIO_PARENTAL_RATING_AGE_6_OR_ABOVE +/*!< Recommended for listeners of age 7 and above */ +#define ESP_BLE_AUDIO_PARENTAL_RATING_AGE_7_OR_ABOVE BT_AUDIO_PARENTAL_RATING_AGE_7_OR_ABOVE +/*!< Recommended for listeners of age 8 and above */ +#define ESP_BLE_AUDIO_PARENTAL_RATING_AGE_8_OR_ABOVE BT_AUDIO_PARENTAL_RATING_AGE_8_OR_ABOVE +/*!< Recommended for listeners of age 9 and above */ +#define ESP_BLE_AUDIO_PARENTAL_RATING_AGE_9_OR_ABOVE BT_AUDIO_PARENTAL_RATING_AGE_9_OR_ABOVE +/*!< Recommended for listeners of age 10 and above */ +#define ESP_BLE_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE +/*!< Recommended for listeners of age 11 and above */ +#define ESP_BLE_AUDIO_PARENTAL_RATING_AGE_11_OR_ABOVE BT_AUDIO_PARENTAL_RATING_AGE_11_OR_ABOVE +/*!< Recommended for listeners of age 12 and above */ +#define ESP_BLE_AUDIO_PARENTAL_RATING_AGE_12_OR_ABOVE BT_AUDIO_PARENTAL_RATING_AGE_12_OR_ABOVE +/*!< Recommended for listeners of age 13 and above */ +#define ESP_BLE_AUDIO_PARENTAL_RATING_AGE_13_OR_ABOVE BT_AUDIO_PARENTAL_RATING_AGE_13_OR_ABOVE +/*!< Recommended for listeners of age 14 and above */ +#define ESP_BLE_AUDIO_PARENTAL_RATING_AGE_14_OR_ABOVE BT_AUDIO_PARENTAL_RATING_AGE_14_OR_ABOVE +/*!< Recommended for listeners of age 15 and above */ +#define ESP_BLE_AUDIO_PARENTAL_RATING_AGE_15_OR_ABOVE BT_AUDIO_PARENTAL_RATING_AGE_15_OR_ABOVE +/*!< Recommended for listeners of age 16 and above */ +#define ESP_BLE_AUDIO_PARENTAL_RATING_AGE_16_OR_ABOVE BT_AUDIO_PARENTAL_RATING_AGE_16_OR_ABOVE +/*!< Recommended for listeners of age 17 and above */ +#define ESP_BLE_AUDIO_PARENTAL_RATING_AGE_17_OR_ABOVE BT_AUDIO_PARENTAL_RATING_AGE_17_OR_ABOVE +/*!< Recommended for listeners of age 18 and above */ +#define ESP_BLE_AUDIO_PARENTAL_RATING_AGE_18_OR_ABOVE BT_AUDIO_PARENTAL_RATING_AGE_18_OR_ABOVE +/** Parental rating defined by the Generic Audio assigned numbers */ +typedef enum bt_audio_parental_rating esp_ble_audio_parental_rating_t; + +/*!< No audio data is being transmitted */ +#define ESP_BLE_AUDIO_ACTIVE_STATE_DISABLED BT_AUDIO_ACTIVE_STATE_DISABLED +/*!< Audio data is being transmitted */ +#define ESP_BLE_AUDIO_ACTIVE_STATE_ENABLED BT_AUDIO_ACTIVE_STATE_ENABLED +/** Audio Active State defined by the Generic Audio assigned numbers */ +typedef enum bt_audio_active_state esp_ble_audio_active_state_t; + +/*!< Preferred audio context */ +#define ESP_BLE_AUDIO_METADATA_TYPE_PREF_CONTEXT BT_AUDIO_METADATA_TYPE_PREF_CONTEXT +/*!< Streaming audio context */ +#define ESP_BLE_AUDIO_METADATA_TYPE_STREAM_CONTEXT BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT +/*!< UTF-8 encoded title or summary of stream content */ +#define ESP_BLE_AUDIO_METADATA_TYPE_PROGRAM_INFO BT_AUDIO_METADATA_TYPE_PROGRAM_INFO +/*!< Language */ +#define ESP_BLE_AUDIO_METADATA_TYPE_LANG BT_AUDIO_METADATA_TYPE_LANG +/*!< Array of 8-bit CCID values */ +#define ESP_BLE_AUDIO_METADATA_TYPE_CCID_LIST BT_AUDIO_METADATA_TYPE_CCID_LIST +/*!< Parental rating */ +#define ESP_BLE_AUDIO_METADATA_TYPE_PARENTAL_RATING BT_AUDIO_METADATA_TYPE_PARENTAL_RATING +/*!< UTF-8 encoded URI for additional Program information */ +#define ESP_BLE_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI BT_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI +/*!< Audio active state */ +#define ESP_BLE_AUDIO_METADATA_TYPE_AUDIO_STATE BT_AUDIO_METADATA_TYPE_AUDIO_STATE +/*!< Broadcast Audio Immediate Rendering flag */ +#define ESP_BLE_AUDIO_METADATA_TYPE_BROADCAST_IMMEDIATE BT_AUDIO_METADATA_TYPE_BROADCAST_IMMEDIATE +/*!< Assisted listening stream */ +#define ESP_BLE_AUDIO_METADATA_TYPE_ASSISTED_LISTENING_STREAM BT_AUDIO_METADATA_TYPE_ASSISTED_LISTENING_STREAM +/*!< UTF-8 encoded Broadcast name */ +#define ESP_BLE_AUDIO_METADATA_TYPE_BROADCAST_NAME BT_AUDIO_METADATA_TYPE_BROADCAST_NAME +/*!< Extended metadata */ +#define ESP_BLE_AUDIO_METADATA_TYPE_EXTENDED BT_AUDIO_METADATA_TYPE_EXTENDED +/*!< Vendor specific metadata */ +#define ESP_BLE_AUDIO_METADATA_TYPE_VENDOR BT_AUDIO_METADATA_TYPE_VENDOR +/** + * @brief Helper to check whether metadata type is known by the stack. + * + * @param _type Metadata type. + */ +#define ESP_BLE_AUDIO_METADATA_TYPE_IS_KNOWN(_type) \ + BT_AUDIO_METADATA_TYPE_IS_KNOWN(_type) +/** Metadata types defined by the Generic Audio assigned numbers */ +typedef enum bt_audio_metadata_type esp_ble_audio_metadata_type_t; + +/*!< Mono Audio (no specified Audio Location) */ +#define ESP_BLE_AUDIO_LOCATION_MONO_AUDIO BT_AUDIO_LOCATION_MONO_AUDIO +/*!< Front Left */ +#define ESP_BLE_AUDIO_LOCATION_FRONT_LEFT BT_AUDIO_LOCATION_FRONT_LEFT +/*!< Front Right */ +#define ESP_BLE_AUDIO_LOCATION_FRONT_RIGHT BT_AUDIO_LOCATION_FRONT_RIGHT +/*!< Front Center */ +#define ESP_BLE_AUDIO_LOCATION_FRONT_CENTER BT_AUDIO_LOCATION_FRONT_CENTER +/*!< Low Frequency Effects 1 */ +#define ESP_BLE_AUDIO_LOCATION_LOW_FREQ_EFFECTS_1 BT_AUDIO_LOCATION_LOW_FREQ_EFFECTS_1 +/*!< Back Left */ +#define ESP_BLE_AUDIO_LOCATION_BACK_LEFT BT_AUDIO_LOCATION_BACK_LEFT +/*!< Back Right */ +#define ESP_BLE_AUDIO_LOCATION_BACK_RIGHT BT_AUDIO_LOCATION_BACK_RIGHT +/*!< Front Left of Center */ +#define ESP_BLE_AUDIO_LOCATION_FRONT_LEFT_OF_CENTER BT_AUDIO_LOCATION_FRONT_LEFT_OF_CENTER +/*!< Front Right of Center */ +#define ESP_BLE_AUDIO_LOCATION_FRONT_RIGHT_OF_CENTER BT_AUDIO_LOCATION_FRONT_RIGHT_OF_CENTER +/*!< Back Center */ +#define ESP_BLE_AUDIO_LOCATION_BACK_CENTER BT_AUDIO_LOCATION_BACK_CENTER +/*!< Low Frequency Effects 2 */ +#define ESP_BLE_AUDIO_LOCATION_LOW_FREQ_EFFECTS_2 BT_AUDIO_LOCATION_LOW_FREQ_EFFECTS_2 +/*!< Side Left */ +#define ESP_BLE_AUDIO_LOCATION_SIDE_LEFT BT_AUDIO_LOCATION_SIDE_LEFT +/*!< Side Right */ +#define ESP_BLE_AUDIO_LOCATION_SIDE_RIGHT BT_AUDIO_LOCATION_SIDE_RIGHT +/*!< Top Front Left */ +#define ESP_BLE_AUDIO_LOCATION_TOP_FRONT_LEFT BT_AUDIO_LOCATION_TOP_FRONT_LEFT +/*!< Top Front Right */ +#define ESP_BLE_AUDIO_LOCATION_TOP_FRONT_RIGHT BT_AUDIO_LOCATION_TOP_FRONT_RIGHT +/*!< Top Front Center */ +#define ESP_BLE_AUDIO_LOCATION_TOP_FRONT_CENTER BT_AUDIO_LOCATION_TOP_FRONT_CENTER +/*!< Top Center */ +#define ESP_BLE_AUDIO_LOCATION_TOP_CENTER BT_AUDIO_LOCATION_TOP_CENTER +/*!< Top Back Left */ +#define ESP_BLE_AUDIO_LOCATION_TOP_BACK_LEFT BT_AUDIO_LOCATION_TOP_BACK_LEFT +/*!< Top Back Right */ +#define ESP_BLE_AUDIO_LOCATION_TOP_BACK_RIGHT BT_AUDIO_LOCATION_TOP_BACK_RIGHT +/*!< Top Side Left */ +#define ESP_BLE_AUDIO_LOCATION_TOP_SIDE_LEFT BT_AUDIO_LOCATION_TOP_SIDE_LEFT +/*!< Top Side Right */ +#define ESP_BLE_AUDIO_LOCATION_TOP_SIDE_RIGHT BT_AUDIO_LOCATION_TOP_SIDE_RIGHT +/*!< Top Back Center */ +#define ESP_BLE_AUDIO_LOCATION_TOP_BACK_CENTER BT_AUDIO_LOCATION_TOP_BACK_CENTER +/*!< Bottom Front Center */ +#define ESP_BLE_AUDIO_LOCATION_BOTTOM_FRONT_CENTER BT_AUDIO_LOCATION_BOTTOM_FRONT_CENTER +/*!< Bottom Front Left */ +#define ESP_BLE_AUDIO_LOCATION_BOTTOM_FRONT_LEFT BT_AUDIO_LOCATION_BOTTOM_FRONT_LEFT +/*!< Bottom Front Right */ +#define ESP_BLE_AUDIO_LOCATION_BOTTOM_FRONT_RIGHT BT_AUDIO_LOCATION_BOTTOM_FRONT_RIGHT +/*!< Front Left Wide */ +#define ESP_BLE_AUDIO_LOCATION_FRONT_LEFT_WIDE BT_AUDIO_LOCATION_FRONT_LEFT_WIDE +/*!< Front Right Wide */ +#define ESP_BLE_AUDIO_LOCATION_FRONT_RIGHT_WIDE BT_AUDIO_LOCATION_FRONT_RIGHT_WIDE +/*!< Left Surround */ +#define ESP_BLE_AUDIO_LOCATION_LEFT_SURROUND BT_AUDIO_LOCATION_LEFT_SURROUND +/*!< Right Surround */ +#define ESP_BLE_AUDIO_LOCATION_RIGHT_SURROUND BT_AUDIO_LOCATION_RIGHT_SURROUND +/*!< Any known location */ +#define ESP_BLE_AUDIO_LOCATION_ANY BT_AUDIO_LOCATION_ANY +/** Location values defined by the Generic Audio assigned numbers */ +typedef enum bt_audio_location esp_ble_audio_location_t; + +/*!< Unspecified audio enhancement */ +#define ESP_BLE_AUDIO_ASSISTED_LISTENING_STREAM_UNSPECIFIED BT_AUDIO_ASSISTED_LISTENING_STREAM_UNSPECIFIED +/** Assisted Listening Stream defined by the Generic Audio assigned numbers */ +typedef enum bt_audio_assisted_listening_stream esp_ble_audio_assisted_listening_stream_t; + +/*!< Size in octets of a 16-bit UUID */ +#define ESP_BLE_AUDIO_UUID_SIZE_16 BT_UUID_SIZE_16 + +/*!< Audio Input Control Service UUID value */ +#define ESP_BLE_AUDIO_UUID_AICS_VAL BT_UUID_AICS_VAL +/*!< Audio Stream Control Service UUID value */ +#define ESP_BLE_AUDIO_UUID_ASCS_VAL BT_UUID_ASCS_VAL +/*!< Broadcast Audio Scan Service UUID value */ +#define ESP_BLE_AUDIO_UUID_BASS_VAL BT_UUID_BASS_VAL +/*!< Basic Audio Announcement Service UUID value */ +#define ESP_BLE_AUDIO_UUID_BASIC_AUDIO_VAL BT_UUID_BASIC_AUDIO_VAL +/*!< Broadcast Audio Announcement Service UUID value */ +#define ESP_BLE_AUDIO_UUID_BROADCAST_AUDIO_VAL BT_UUID_BROADCAST_AUDIO_VAL +/*!< Common Audio Service UUID value */ +#define ESP_BLE_AUDIO_UUID_CAS_VAL BT_UUID_CAS_VAL +/*!< Coordinated Set Identification Service UUID value */ +#define ESP_BLE_AUDIO_UUID_CSIS_VAL BT_UUID_CSIS_VAL +/*!< Gaming Service UUID value */ +#define ESP_BLE_AUDIO_UUID_GMAS_VAL BT_UUID_GMAS_VAL +/*!< Generic Media Control Service UUID value */ +#define ESP_BLE_AUDIO_UUID_GMCS_VAL BT_UUID_GMCS_VAL +/*!< Generic Telephone Bearer Service UUID value */ +#define ESP_BLE_AUDIO_UUID_GTBS_VAL BT_UUID_GTBS_VAL +/*!< Hearing Access Service UUID value */ +#define ESP_BLE_AUDIO_UUID_HAS_VAL BT_UUID_HAS_VAL +/*!< Media Control Service UUID value */ +#define ESP_BLE_AUDIO_UUID_MCS_VAL BT_UUID_MCS_VAL +/*!< Microphone Control Service UUID value */ +#define ESP_BLE_AUDIO_UUID_MICS_VAL BT_UUID_MICS_VAL +/*!< Published Audio Capabilities Service UUID value */ +#define ESP_BLE_AUDIO_UUID_PACS_VAL BT_UUID_PACS_VAL +/*!< Public Broadcast Announcement Service UUID value */ +#define ESP_BLE_AUDIO_UUID_PBA_VAL BT_UUID_PBA_VAL +/*!< Telephone Bearer Service UUID value */ +#define ESP_BLE_AUDIO_UUID_TBS_VAL BT_UUID_TBS_VAL +/*!< Telephony and Media Audio Service UUID value */ +#define ESP_BLE_AUDIO_UUID_TMAS_VAL BT_UUID_TMAS_VAL +/*!< Volume Control Service UUID value */ +#define ESP_BLE_AUDIO_UUID_VCS_VAL BT_UUID_VCS_VAL +/*!< Volume Offset Control Service UUID value */ +#define ESP_BLE_AUDIO_UUID_VOCS_VAL BT_UUID_VOCS_VAL +/*!< Object Transfer Service UUID value */ +#define ESP_BLE_AUDIO_UUID_OTS_VAL BT_UUID_OTS_VAL + +/*!< Audio Input Control Service State value */ +#define ESP_BLE_AUDIO_UUID_AICS_STATE_VAL BT_UUID_AICS_STATE_VAL +/*!< Audio Input Control Service Gain Settings Properties value */ +#define ESP_BLE_AUDIO_UUID_AICS_GAIN_SETTINGS_VAL BT_UUID_AICS_GAIN_SETTINGS_VAL +/*!< Audio Input Control Service Input Type value */ +#define ESP_BLE_AUDIO_UUID_AICS_INPUT_TYPE_VAL BT_UUID_AICS_INPUT_TYPE_VAL +/*!< Audio Input Control Service Input Status value */ +#define ESP_BLE_AUDIO_UUID_AICS_INPUT_STATUS_VAL BT_UUID_AICS_INPUT_STATUS_VAL +/*!< Audio Input Control Service Control Point value */ +#define ESP_BLE_AUDIO_UUID_AICS_CONTROL_VAL BT_UUID_AICS_CONTROL_VAL +/*!< Audio Input Control Service Input Description value */ +#define ESP_BLE_AUDIO_UUID_AICS_DESCRIPTION_VAL BT_UUID_AICS_DESCRIPTION_VAL + +/*!< Audio Stream Endpoint Sink Characteristic value */ +#define ESP_BLE_AUDIO_UUID_ASCS_ASE_SNK_VAL BT_UUID_ASCS_ASE_SNK_VAL +/*!< Audio Stream Endpoint Source Characteristic value */ +#define ESP_BLE_AUDIO_UUID_ASCS_ASE_SRC_VAL BT_UUID_ASCS_ASE_SRC_VAL +/*!< Audio Stream Endpoint Control Point Characteristic value */ +#define ESP_BLE_AUDIO_UUID_ASCS_ASE_CP_VAL BT_UUID_ASCS_ASE_CP_VAL + +/*!< Broadcast Audio Scan Service Scan State value */ +#define ESP_BLE_AUDIO_UUID_BASS_CONTROL_POINT_VAL BT_UUID_BASS_CONTROL_POINT_VAL +/*!< Broadcast Audio Scan Service Receive State value */ +#define ESP_BLE_AUDIO_UUID_BASS_RECV_STATE_VAL BT_UUID_BASS_RECV_STATE_VAL + +/*!< Set Identity Resolving Key value */ +#define ESP_BLE_AUDIO_UUID_CSIS_SIRK_VAL BT_UUID_CSIS_SIRK_VAL +/*!< Set size value */ +#define ESP_BLE_AUDIO_UUID_CSIS_SET_SIZE_VAL BT_UUID_CSIS_SET_SIZE_VAL +/*!< Set lock value */ +#define ESP_BLE_AUDIO_UUID_CSIS_SET_LOCK_VAL BT_UUID_CSIS_SET_LOCK_VAL +/*!< Rank value */ +#define ESP_BLE_AUDIO_UUID_CSIS_RANK_VAL BT_UUID_CSIS_RANK_VAL + +/*!< Gaming Audio Profile Role UUID value */ +#define ESP_BLE_AUDIO_UUID_GMAP_ROLE_VAL BT_UUID_GMAP_ROLE_VAL +/*!< Gaming Audio Profile Unicast Game Gateway Features UUID value */ +#define ESP_BLE_AUDIO_UUID_GMAP_UGG_FEAT_VAL BT_UUID_GMAP_UGG_FEAT_VAL +/*!< Gaming Audio Profile Unicast Game Terminal Features UUID value */ +#define ESP_BLE_AUDIO_UUID_GMAP_UGT_FEAT_VAL BT_UUID_GMAP_UGT_FEAT_VAL +/*!< Gaming Audio Profile Broadcast Game Sender Features UUID value */ +#define ESP_BLE_AUDIO_UUID_GMAP_BGS_FEAT_VAL BT_UUID_GMAP_BGS_FEAT_VAL +/*!< Gaming Audio Profile Broadcast Game Receiver Features UUID value */ +#define ESP_BLE_AUDIO_UUID_GMAP_BGR_FEAT_VAL BT_UUID_GMAP_BGR_FEAT_VAL + +/*!< Hearing Aid Features Characteristic value */ +#define ESP_BLE_AUDIO_UUID_HAS_HEARING_AID_FEATURES_VAL BT_UUID_HAS_HEARING_AID_FEATURES_VAL +/*!< Hearing Aid Preset Control Point Characteristic value */ +#define ESP_BLE_AUDIO_UUID_HAS_PRESET_CONTROL_POINT_VAL BT_UUID_HAS_PRESET_CONTROL_POINT_VAL +/*!< Hearing Aid Active Preset Index Characteristic value */ +#define ESP_BLE_AUDIO_UUID_HAS_ACTIVE_PRESET_INDEX_VAL BT_UUID_HAS_ACTIVE_PRESET_INDEX_VAL + +/*!< Media player name value */ +#define ESP_BLE_AUDIO_UUID_MCS_PLAYER_NAME_VAL BT_UUID_MCS_PLAYER_NAME_VAL +/*!< Media Icon Object ID value */ +#define ESP_BLE_AUDIO_UUID_MCS_ICON_OBJ_ID_VAL BT_UUID_MCS_ICON_OBJ_ID_VAL +/*!< Media Icon URL value */ +#define ESP_BLE_AUDIO_UUID_MCS_ICON_URL_VAL BT_UUID_MCS_ICON_URL_VAL +/*!< Track Changed value */ +#define ESP_BLE_AUDIO_UUID_MCS_TRACK_CHANGED_VAL BT_UUID_MCS_TRACK_CHANGED_VAL +/*!< Track Title value */ +#define ESP_BLE_AUDIO_UUID_MCS_TRACK_TITLE_VAL BT_UUID_MCS_TRACK_TITLE_VAL +/*!< Track Duration value */ +#define ESP_BLE_AUDIO_UUID_MCS_TRACK_DURATION_VAL BT_UUID_MCS_TRACK_DURATION_VAL +/*!< Track Position value */ +#define ESP_BLE_AUDIO_UUID_MCS_TRACK_POSITION_VAL BT_UUID_MCS_TRACK_POSITION_VAL +/*!< Playback Speed value */ +#define ESP_BLE_AUDIO_UUID_MCS_PLAYBACK_SPEED_VAL BT_UUID_MCS_PLAYBACK_SPEED_VAL +/*!< Seeking Speed value */ +#define ESP_BLE_AUDIO_UUID_MCS_SEEKING_SPEED_VAL BT_UUID_MCS_SEEKING_SPEED_VAL +/*!< Track Segments Object ID value */ +#define ESP_BLE_AUDIO_UUID_MCS_TRACK_SEGMENTS_OBJ_ID_VAL BT_UUID_MCS_TRACK_SEGMENTS_OBJ_ID_VAL +/*!< Current Track Object ID value */ +#define ESP_BLE_AUDIO_UUID_MCS_CURRENT_TRACK_OBJ_ID_VAL BT_UUID_MCS_CURRENT_TRACK_OBJ_ID_VAL +/*!< Next Track Object ID value */ +#define ESP_BLE_AUDIO_UUID_MCS_NEXT_TRACK_OBJ_ID_VAL BT_UUID_MCS_NEXT_TRACK_OBJ_ID_VAL +/*!< Parent Group Object ID value */ +#define ESP_BLE_AUDIO_UUID_MCS_PARENT_GROUP_OBJ_ID_VAL BT_UUID_MCS_PARENT_GROUP_OBJ_ID_VAL +/*!< Group Object ID value */ +#define ESP_BLE_AUDIO_UUID_MCS_CURRENT_GROUP_OBJ_ID_VAL BT_UUID_MCS_CURRENT_GROUP_OBJ_ID_VAL +/*!< Playing Order value */ +#define ESP_BLE_AUDIO_UUID_MCS_PLAYING_ORDER_VAL BT_UUID_MCS_PLAYING_ORDER_VAL +/*!< Playing Orders supported value */ +#define ESP_BLE_AUDIO_UUID_MCS_PLAYING_ORDERS_VAL BT_UUID_MCS_PLAYING_ORDERS_VAL +/*!< Media State value */ +#define ESP_BLE_AUDIO_UUID_MCS_MEDIA_STATE_VAL BT_UUID_MCS_MEDIA_STATE_VAL +/*!< Media Control Point value */ +#define ESP_BLE_AUDIO_UUID_MCS_MEDIA_CONTROL_POINT_VAL BT_UUID_MCS_MEDIA_CONTROL_POINT_VAL +/*!< Media control opcodes supported value */ +#define ESP_BLE_AUDIO_UUID_MCS_MEDIA_CONTROL_OPCODES_VAL BT_UUID_MCS_MEDIA_CONTROL_OPCODES_VAL +/*!< Search result object ID value */ +#define ESP_BLE_AUDIO_UUID_MCS_SEARCH_RESULTS_OBJ_ID_VAL BT_UUID_MCS_SEARCH_RESULTS_OBJ_ID_VAL +/*!< Search control point value */ +#define ESP_BLE_AUDIO_UUID_MCS_SEARCH_CONTROL_POINT_VAL BT_UUID_MCS_SEARCH_CONTROL_POINT_VAL + +/*!< Microphone Control Service Mute value */ +#define ESP_BLE_AUDIO_UUID_MICS_MUTE_VAL BT_UUID_MICS_MUTE_VAL + +/*!< Sink PAC Characteristic value */ +#define ESP_BLE_AUDIO_UUID_PACS_SNK_VAL BT_UUID_PACS_SNK_VAL +/*!< Sink PAC Locations Characteristic value */ +#define ESP_BLE_AUDIO_UUID_PACS_SNK_LOC_VAL BT_UUID_PACS_SNK_LOC_VAL +/*!< Source PAC Characteristic value */ +#define ESP_BLE_AUDIO_UUID_PACS_SRC_VAL BT_UUID_PACS_SRC_VAL +/*!< Source PAC Locations Characteristic value */ +#define ESP_BLE_AUDIO_UUID_PACS_SRC_LOC_VAL BT_UUID_PACS_SRC_LOC_VAL +/*!< Available Audio Contexts Characteristic value */ +#define ESP_BLE_AUDIO_UUID_PACS_AVAILABLE_CONTEXT_VAL BT_UUID_PACS_AVAILABLE_CONTEXT_VAL +/*!< Supported Audio Context Characteristic value */ +#define ESP_BLE_AUDIO_UUID_PACS_SUPPORTED_CONTEXT_VAL BT_UUID_PACS_SUPPORTED_CONTEXT_VAL + +/*!< Bearer Provider Name value */ +#define ESP_BLE_AUDIO_UUID_TBS_PROVIDER_NAME_VAL BT_UUID_TBS_PROVIDER_NAME_VAL +/*!< Bearer UCI value */ +#define ESP_BLE_AUDIO_UUID_TBS_UCI_VAL BT_UUID_TBS_UCI_VAL +/*!< Bearer Technology value */ +#define ESP_BLE_AUDIO_UUID_TBS_TECHNOLOGY_VAL BT_UUID_TBS_TECHNOLOGY_VAL +/*!< Bearer URI Prefixes Supported List value */ +#define ESP_BLE_AUDIO_UUID_TBS_URI_LIST_VAL BT_UUID_TBS_URI_LIST_VAL +/*!< Bearer Signal Strength value */ +#define ESP_BLE_AUDIO_UUID_TBS_SIGNAL_STRENGTH_VAL BT_UUID_TBS_SIGNAL_STRENGTH_VAL +/*!< Bearer Signal Strength Reporting Interval value */ +#define ESP_BLE_AUDIO_UUID_TBS_SIGNAL_INTERVAL_VAL BT_UUID_TBS_SIGNAL_INTERVAL_VAL +/*!< Bearer List Current Calls value */ +#define ESP_BLE_AUDIO_UUID_TBS_LIST_CURRENT_CALLS_VAL BT_UUID_TBS_LIST_CURRENT_CALLS_VAL +/*!< Status flags value */ +#define ESP_BLE_AUDIO_UUID_TBS_STATUS_FLAGS_VAL BT_UUID_TBS_STATUS_FLAGS_VAL +/*!< Incoming Call Target Caller ID value */ +#define ESP_BLE_AUDIO_UUID_TBS_INCOMING_URI_VAL BT_UUID_TBS_INCOMING_URI_VAL +/*!< Call State value */ +#define ESP_BLE_AUDIO_UUID_TBS_CALL_STATE_VAL BT_UUID_TBS_CALL_STATE_VAL +/*!< Call Control Point value */ +#define ESP_BLE_AUDIO_UUID_TBS_CALL_CONTROL_POINT_VAL BT_UUID_TBS_CALL_CONTROL_POINT_VAL +/*!< Optional Opcodes value */ +#define ESP_BLE_AUDIO_UUID_TBS_OPTIONAL_OPCODES_VAL BT_UUID_TBS_OPTIONAL_OPCODES_VAL +/*!< Terminate reason value */ +#define ESP_BLE_AUDIO_UUID_TBS_TERMINATE_REASON_VAL BT_UUID_TBS_TERMINATE_REASON_VAL +/*!< Incoming Call value */ +#define ESP_BLE_AUDIO_UUID_TBS_INCOMING_CALL_VAL BT_UUID_TBS_INCOMING_CALL_VAL +/*!< Incoming Call Friendly name value */ +#define ESP_BLE_AUDIO_UUID_TBS_FRIENDLY_NAME_VAL BT_UUID_TBS_FRIENDLY_NAME_VAL + +/*!< Volume Control Setting value */ +#define ESP_BLE_AUDIO_UUID_VCS_STATE_VAL BT_UUID_VCS_STATE_VAL +/*!< Volume Control Control point value */ +#define ESP_BLE_AUDIO_UUID_VCS_CONTROL_VAL BT_UUID_VCS_CONTROL_VAL +/*!< Volume Control Flags value */ +#define ESP_BLE_AUDIO_UUID_VCS_FLAGS_VAL BT_UUID_VCS_FLAGS_VAL + +/*!< Volume Offset State value */ +#define ESP_BLE_AUDIO_UUID_VOCS_STATE_VAL BT_UUID_VOCS_STATE_VAL +/*!< Audio Location value */ +#define ESP_BLE_AUDIO_UUID_VOCS_LOCATION_VAL BT_UUID_VOCS_LOCATION_VAL +/*!< Volume Offset Control Point value */ +#define ESP_BLE_AUDIO_UUID_VOCS_CONTROL_VAL BT_UUID_VOCS_CONTROL_VAL +/*!< Volume Offset Audio Output Description value */ +#define ESP_BLE_AUDIO_UUID_VOCS_DESCRIPTION_VAL BT_UUID_VOCS_DESCRIPTION_VAL + +/*!< Content Control ID value */ +#define ESP_BLE_AUDIO_UUID_CCID_VAL BT_UUID_CCID_VAL + +/*!< OTS Feature Characteristic UUID value */ +#define ESP_BLE_AUDIO_UUID_OTS_FEATURE_VAL BT_UUID_OTS_FEATURE_VAL +/*!< OTS Object Name Characteristic UUID value */ +#define ESP_BLE_AUDIO_UUID_OTS_NAME_VAL BT_UUID_OTS_NAME_VAL +/*!< OTS Object Type Characteristic UUID value */ +#define ESP_BLE_AUDIO_UUID_OTS_TYPE_VAL BT_UUID_OTS_TYPE_VAL +/*!< OTS Object Size Characteristic UUID value */ +#define ESP_BLE_AUDIO_UUID_OTS_SIZE_VAL BT_UUID_OTS_SIZE_VAL +/*!< OTS Object First-Created Characteristic UUID value */ +#define ESP_BLE_AUDIO_UUID_OTS_FIRST_CREATED_VAL BT_UUID_OTS_FIRST_CREATED_VAL +/*!< OTS Object Last-Modified Characteristic UUI value */ +#define ESP_BLE_AUDIO_UUID_OTS_LAST_MODIFIED_VAL BT_UUID_OTS_LAST_MODIFIED_VAL +/*!< OTS Object ID Characteristic UUID value */ +#define ESP_BLE_AUDIO_UUID_OTS_ID_VAL BT_UUID_OTS_ID_VAL +/*!< OTS Object Properties Characteristic UUID value */ +#define ESP_BLE_AUDIO_UUID_OTS_PROPERTIES_VAL BT_UUID_OTS_PROPERTIES_VAL +/*!< OTS Object Action Control Point Characteristic UUID value */ +#define ESP_BLE_AUDIO_UUID_OTS_ACTION_CP_VAL BT_UUID_OTS_ACTION_CP_VAL +/*!< OTS Object List Control Point Characteristic UUID value */ +#define ESP_BLE_AUDIO_UUID_OTS_LIST_CP_VAL BT_UUID_OTS_LIST_CP_VAL +/*!< OTS Object List Filter Characteristic UUID value */ +#define ESP_BLE_AUDIO_UUID_OTS_LIST_FILTER_VAL BT_UUID_OTS_LIST_FILTER_VAL +/*!< OTS Object Changed Characteristic UUID value */ +#define ESP_BLE_AUDIO_UUID_OTS_CHANGED_VAL BT_UUID_OTS_CHANGED_VAL +/*!< OTS Unspecified Object Type UUID value */ +#define ESP_BLE_AUDIO_UUID_OTS_TYPE_UNSPECIFIED_VAL BT_UUID_OTS_TYPE_UNSPECIFIED_VAL +/*!< OTS Directory Listing UUID value */ +#define ESP_BLE_AUDIO_UUID_OTS_DIRECTORY_LISTING_VAL BT_UUID_OTS_DIRECTORY_LISTING_VAL +/*!< OTS Media Player Icon Object Type value */ +#define ESP_BLE_AUDIO_UUID_OTS_TYPE_MPL_ICON_VAL BT_UUID_OTS_TYPE_MPL_ICON_VAL +/*!< OTS Track Segments Object Type value */ +#define ESP_BLE_AUDIO_UUID_OTS_TYPE_TRACK_SEGMENT_VAL BT_UUID_OTS_TYPE_TRACK_SEGMENT_VAL +/*!< OTS Track Object Type value */ +#define ESP_BLE_AUDIO_UUID_OTS_TYPE_TRACK_VAL BT_UUID_OTS_TYPE_TRACK_VAL +/*!< OTS Group Object Type value */ +#define ESP_BLE_AUDIO_UUID_OTS_TYPE_GROUP_VAL BT_UUID_OTS_TYPE_GROUP_VAL + +/*!< Generic Audio Sink */ +#define ESP_BLE_AUDIO_APPEARANCE_GENERIC_AUDIO_SINK BT_APPEARANCE_GENERIC_AUDIO_SINK +/*!< Standalone Speaker */ +#define ESP_BLE_AUDIO_APPEARANCE_AUDIO_SINK_STANDALONE_SPEAKER BT_APPEARANCE_AUDIO_SINK_STANDALONE_SPEAKER +/*!< Soundbar */ +#define ESP_BLE_AUDIO_APPEARANCE_AUDIO_SINK_SOUNDBAR BT_APPEARANCE_AUDIO_SINK_SOUNDBAR +/*!< Bookshelf Speaker */ +#define ESP_BLE_AUDIO_APPEARANCE_AUDIO_SINK_BOOKSHELF_SPEAKER BT_APPEARANCE_AUDIO_SINK_BOOKSHELF_SPEAKER +/*!< Standmounted Speaker */ +#define ESP_BLE_AUDIO_APPEARANCE_AUDIO_SINK_STANDMOUNTED_SPEAKER BT_APPEARANCE_AUDIO_SINK_STANDMOUNTED_SPEAKER +/*!< Speakerphone */ +#define ESP_BLE_AUDIO_APPEARANCE_AUDIO_SINK_SPEAKERPHONE BT_APPEARANCE_AUDIO_SINK_SPEAKERPHONE + +/*!< Generic Audio Source */ +#define ESP_BLE_AUDIO_APPEARANCE_GENERIC_AUDIO_SOURCE BT_APPEARANCE_GENERIC_AUDIO_SOURCE +/*!< Microphone */ +#define ESP_BLE_AUDIO_APPEARANCE_AUDIO_SOURCE_MICROPHONE BT_APPEARANCE_AUDIO_SOURCE_MICROPHONE +/*!< Alarm */ +#define ESP_BLE_AUDIO_APPEARANCE_AUDIO_SOURCE_ALARM BT_APPEARANCE_AUDIO_SOURCE_ALARM +/*!< Bell */ +#define ESP_BLE_AUDIO_APPEARANCE_AUDIO_SOURCE_BELL BT_APPEARANCE_AUDIO_SOURCE_BELL +/*!< Horn */ +#define ESP_BLE_AUDIO_APPEARANCE_AUDIO_SOURCE_HORN BT_APPEARANCE_AUDIO_SOURCE_HORN +/*!< Broadcasting Device */ +#define ESP_BLE_AUDIO_APPEARANCE_AUDIO_SOURCE_BROADCASTING_DEVICE BT_APPEARANCE_AUDIO_SOURCE_BROADCASTING_DEVICE +/*!< Service Desk */ +#define ESP_BLE_AUDIO_APPEARANCE_AUDIO_SOURCE_SERVICE_DESK BT_APPEARANCE_AUDIO_SOURCE_SERVICE_DESK +/*!< Kiosk */ +#define ESP_BLE_AUDIO_APPEARANCE_AUDIO_SOURCE_KIOSK BT_APPEARANCE_AUDIO_SOURCE_KIOSK +/*!< Broadcasting Room */ +#define ESP_BLE_AUDIO_APPEARANCE_AUDIO_SOURCE_BROADCASTING_ROOM BT_APPEARANCE_AUDIO_SOURCE_BROADCASTING_ROOM +/*!< Auditorium */ +#define ESP_BLE_AUDIO_APPEARANCE_AUDIO_SOURCE_AUDITORIUM BT_APPEARANCE_AUDIO_SOURCE_AUDITORIUM + +/*!< Generic Wearable Audio Device */ +#define ESP_BLE_AUDIO_APPEARANCE_GENERIC_WEARABLE_AUDIO_DEVICE BT_APPEARANCE_GENERIC_WEARABLE_AUDIO_DEVICE +/*!< Earbud */ +#define ESP_BLE_AUDIO_APPEARANCE_WEARABLE_AUDIO_DEVICE_EARBUD BT_APPEARANCE_WEARABLE_AUDIO_DEVICE_EARBUD +/*!< Headset */ +#define ESP_BLE_AUDIO_APPEARANCE_WEARABLE_AUDIO_DEVICE_HEADSET BT_APPEARANCE_WEARABLE_AUDIO_DEVICE_HEADSET +/*!< Headphones */ +#define ESP_BLE_AUDIO_APPEARANCE_WEARABLE_AUDIO_DEVICE_HEADPHONES BT_APPEARANCE_WEARABLE_AUDIO_DEVICE_HEADPHONES +/*!< Neck Band */ +#define ESP_BLE_AUDIO_APPEARANCE_WEARABLE_AUDIO_DEVICE_NECK_BAND BT_APPEARANCE_WEARABLE_AUDIO_DEVICE_NECK_BAND + +/*!< Generic Hearing aid */ +#define ESP_BLE_AUDIO_APPEARANCE_GENERIC_HEARING_AID BT_APPEARANCE_GENERIC_HEARING_AID +/*!< In-ear hearing aid */ +#define ESP_BLE_AUDIO_APPEARANCE_HEARING_AID_IN_EAR BT_APPEARANCE_HEARING_AID_IN_EAR +/*!< Behind-ear hearing aid */ +#define ESP_BLE_AUDIO_APPEARANCE_HEARING_AID_BEHIND_EAR BT_APPEARANCE_HEARING_AID_BEHIND_EAR +/*!< Cochlear Implant */ +#define ESP_BLE_AUDIO_APPEARANCE_HEARING_AID_COCHLEAR_IMPLANT BT_APPEARANCE_HEARING_AID_COCHLEAR_IMPLANT + +#ifdef __cplusplus +} +#endif + +#endif /* ESP_BLE_AUDIO_DEFS_H_ */ diff --git a/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_gmap_api.h b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_gmap_api.h new file mode 100644 index 0000000000..2b7c0c958d --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_gmap_api.h @@ -0,0 +1,134 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ESP_BLE_AUDIO_GMAP_API_H_ +#define ESP_BLE_AUDIO_GMAP_API_H_ + +#include +#include +#include + +#include "sdkconfig.h" +#include "esp_err.h" + +#include + +#include "common/init.h" +#include "common/host.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*!< Gaming Role Unicast Game Gateway */ +#define ESP_BLE_AUDIO_GMAP_ROLE_UGG BT_GMAP_ROLE_UGG +/*!< Gaming Role Unicast Game Terminal */ +#define ESP_BLE_AUDIO_GMAP_ROLE_UGT BT_GMAP_ROLE_UGT +/*!< Gaming Role Broadcast Game Sender */ +#define ESP_BLE_AUDIO_GMAP_ROLE_BGS BT_GMAP_ROLE_BGS +/*!< Gaming Role Broadcast Game Receiver */ +#define ESP_BLE_AUDIO_GMAP_ROLE_BGR BT_GMAP_ROLE_BGR +/** Gaming Role bitfield */ +typedef enum bt_gmap_role esp_ble_audio_gmap_role_t; + +/*!< Support transmitting multiple LC3 codec frames per block in an SDU */ +#define ESP_BLE_AUDIO_GMAP_UGG_FEAT_MULTIPLEX BT_GMAP_UGG_FEAT_MULTIPLEX +/*!< 96 kbps source support */ +#define ESP_BLE_AUDIO_GMAP_UGG_FEAT_96KBPS_SOURCE BT_GMAP_UGG_FEAT_96KBPS_SOURCE +/*!< Support for receiving at least two channels of audio, each in a separate CIS */ +#define ESP_BLE_AUDIO_GMAP_UGG_FEAT_MULTISINK BT_GMAP_UGG_FEAT_MULTISINK +/** Unicast Game Gateway Feature bitfield */ +typedef enum bt_gmap_ugg_feat esp_ble_audio_gmap_ugg_feat_t; + +/*!< Source support */ +#define ESP_BLE_AUDIO_GMAP_UGT_FEAT_SOURCE BT_GMAP_UGT_FEAT_SOURCE +/*!< 80 kbps source support */ +#define ESP_BLE_AUDIO_GMAP_UGT_FEAT_80KBPS_SOURCE BT_GMAP_UGT_FEAT_80KBPS_SOURCE +/*!< Sink support */ +#define ESP_BLE_AUDIO_GMAP_UGT_FEAT_SINK BT_GMAP_UGT_FEAT_SINK +/*!< 64 kbps sink support */ +#define ESP_BLE_AUDIO_GMAP_UGT_FEAT_64KBPS_SINK BT_GMAP_UGT_FEAT_64KBPS_SINK +/*!< Support for receiving multiple LC3 codec frames per block in an SDU */ +#define ESP_BLE_AUDIO_GMAP_UGT_FEAT_MULTIPLEX BT_GMAP_UGT_FEAT_MULTIPLEX +/*!< Support for receiving at least two audio channels, each in a separate CIS */ +#define ESP_BLE_AUDIO_GMAP_UGT_FEAT_MULTISINK BT_GMAP_UGT_FEAT_MULTISINK +/*!< Support for sending at least two audio channels, each in a separate CIS */ +#define ESP_BLE_AUDIO_GMAP_UGT_FEAT_MULTISOURCE BT_GMAP_UGT_FEAT_MULTISOURCE +/** Unicast Game Terminal Feature bitfield */ +typedef enum bt_gmap_ugt_feat esp_ble_audio_gmap_ugt_feat_t; + +/*!< 96 kbps support */ +#define ESP_BLE_AUDIO_GMAP_BGS_FEAT_96KBPS BT_GMAP_BGS_FEAT_96KBPS +/** Broadcast Game Receiver Feature bitfield */ +typedef enum bt_gmap_bgs_feat esp_ble_audio_gmap_bgs_feat_t; + +/*!< Support for receiving at least two audio channels, each in a separate BIS */ +#define ESP_BLE_AUDIO_GMAP_BGR_FEAT_MULTISINK BT_GMAP_BGR_FEAT_MULTISINK +/*!< Support for receiving multiple LC3 codec frames per block in an SDU */ +#define ESP_BLE_AUDIO_GMAP_BGR_FEAT_MULTIPLEX BT_GMAP_BGR_FEAT_MULTIPLEX +/** Broadcast Game Receiver Feature bitfield */ +typedef enum bt_gmap_bgr_feat esp_ble_audio_gmap_bgr_feat_t; + +/** Hearing Access Service Client callback structure */ +typedef struct bt_gmap_cb esp_ble_audio_gmap_cb_t; + +/** Broadcast Game Receiver Feature bitfield */ +typedef struct bt_gmap_feat esp_ble_audio_gmap_feat_t; + +/** + * @brief Registers the callbacks used by the Gaming Audio Profile. + * + * @param cb The callback structure. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_gmap_cb_register(const esp_ble_audio_gmap_cb_t *cb); + +/** + * @brief Discover Gaming Service on a remote device. + * + * Procedure to find a Gaming Service on a server identified by @p conn_handle. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_gmap_discover(uint16_t conn_handle); + +/** + * @brief Adds GMAS instance to database and sets the received Gaming Audio Profile role(s). + * + * @param role Gaming Audio Profile role(s) of the device (one or multiple). + * @param features Features of the roles. If a role is not in the @p role parameter, then + * the feature value for that role is simply ignored. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_gmap_register(esp_ble_audio_gmap_role_t role, + esp_ble_audio_gmap_feat_t features); + +/** + * @brief Set one or multiple Gaming Audio Profile roles and features dynamically. + * + * Previously registered value will be overwritten. If there is a role change, this will trigger + * a Gaming Audio Service (GMAS) service change. If there is only a feature change, no service + * change will happen. + * + * @param role Gaming Audio Profile role(s). + * @param features Features of the roles. If a role is not in the @p role parameter, then + * the feature value for that role is simply ignored. + + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_gmap_set_role(esp_ble_audio_gmap_role_t role, + esp_ble_audio_gmap_feat_t features); + +#ifdef __cplusplus +} +#endif + +#endif /* ESP_BLE_AUDIO_GMAP_API_H_ */ diff --git a/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_gmap_lc3_preset_defs.h b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_gmap_lc3_preset_defs.h new file mode 100644 index 0000000000..138ff50908 --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_gmap_lc3_preset_defs.h @@ -0,0 +1,324 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFS_H_ +#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFS_H_ + +#include + +#include "esp_ble_audio_bap_lc3_preset_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Base macro for defining GMAP LC3 presets. + * + * @param _name Preset name. + * @param _freq Sampling frequency (16, 32, or 48 kHz). + * @param _duration Frame duration (7.5 or 10 ms). + * @param _loc Audio channel location. + * @param _len Frame length in bytes. + * @param _frames_per_sdu Number of frames per SDU. + * @param _stream_context Stream context type. + * @param _interval Interval between packets in microseconds. + * @param _sdu SDU size in bytes. + * @param _rtn Maximum number of retransmissions. + * @param _latency Maximum latency in milliseconds. + * @param _pd Presentation delay in microseconds. + */ +#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, _freq, _duration, _loc, _len, \ + _frames_per_sdu, _stream_context, \ + _interval, _sdu, _rtn, _latency, _pd) \ + static uint8_t codec_cfg_data_##_name[] = \ + ESP_BLE_AUDIO_CODEC_CFG_LC3_DATA(_freq, _duration, _loc, _len, _frames_per_sdu); \ + static uint8_t codec_cfg_meta_##_name[] = \ + ESP_BLE_AUDIO_CODEC_CFG_LC3_META(_stream_context); \ + static esp_ble_audio_bap_lc3_preset_t _name = \ + ESP_BLE_AUDIO_BAP_LC3_PRESET(ESP_BLE_AUDIO_CODEC_CFG_LC3(codec_cfg_data_##_name, \ + codec_cfg_meta_##_name), \ + ESP_BLE_AUDIO_BAP_QOS_CFG_UNFRAMED(_interval, _sdu, _rtn, \ + _latency, _pd)); + +/** + * @brief Gaming Reliable (GR) preset at 32kHz, 7.5ms frame duration. + * + * Optimized for reliable gaming audio with low latency (15ms) and standard presentation delay (10ms). + * + * @param _name Preset name. + * @param _loc Audio channel location. + * @param _stream_context Stream context type. + */ +#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_32_1_GR_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 60U, 1, \ + _stream_context, \ + 7500u, 60U, 1U, 15U, 10000U) + +/** + * @brief Gaming Reliable (GR) preset at 32kHz, 10ms frame duration. + * + * Higher quality variant with increased frame duration for better audio quality. + * + * @param _name Preset name. + * @param _loc Audio channel location. + * @param _stream_context Stream context type. + */ +#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_32_2_GR_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 80U, 1, \ + _stream_context, \ + 10000u, 80U, 1U, 20U, 10000U) + +/** + * @brief Gaming Reliable (GR) preset at 48kHz, 7.5ms frame duration. + * + * High-quality gaming audio with minimal latency. + * + * @param _name Preset name. + * @param _loc Audio channel location. + * @param _stream_context Stream context type. + */ +#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_48_1_GR_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 75U, 1, \ + _stream_context, \ + 7500u, 75U, 1U, 15U, 10000U) + +/** + * @brief Gaming Reliable (GR) preset at 48kHz, 10ms frame duration. + * + * High-quality gaming audio with balanced latency and quality. + * + * @param _name Preset name. + * @param _loc Audio channel location. + * @param _stream_context Stream context type. + */ +#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_48_2_GR_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 100U, 1, \ + _stream_context, \ + 10000u, 100U, 1U, 20U, 10000U) + +/** + * @brief Gaming Reliable (GR) preset at 48kHz, 7.5ms frame duration, higher bitrate. + * + * Enhanced quality gaming audio with minimal latency. + * + * @param _name Preset name. + * @param _loc Audio channel location. + * @param _stream_context Stream context type. + */ +#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_48_3_GR_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 90U, 1, \ + _stream_context, \ + 7500u, 90U, 1U, 15U, 10000U) + +/** + * @brief Gaming Reliable (GR) preset at 48kHz, 10ms frame duration, higher bitrate. + * + * Premium quality gaming audio with balanced latency. + * + * @param _name Preset name. + * @param _loc Audio channel location. + * @param _stream_context Stream context type. + */ +#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_48_4_GR_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 120u, 1, \ + _stream_context, \ + 10000u, 120U, 1U, 20U, 10000U) + +/** + * @brief Gaming Standard (GS) preset at 16kHz, 7.5ms frame duration. + * + * Basic gaming audio with longer presentation delay (60ms). + * + * @param _name Preset name. + * @param _loc Audio channel location. + * @param _stream_context Stream context type. + */ +#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_16_1_GS_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_16KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 30U, 1, \ + _stream_context, \ + 7500u, 30U, 1U, 15U, 60000U) + +/** + * @brief Gaming Standard (GS) preset at 16kHz, 10ms frame duration. + * + * Basic gaming audio with better quality and longer presentation delay. + * + * @param _name Preset name. + * @param _loc Audio channel location. + * @param _stream_context Stream context type. + */ +#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_16_2_GS_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_16KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 40U, 1, \ + _stream_context, \ + 10000u, 40U, 1U, 20U, 60000U) + +/** + * @brief Gaming Standard (GS) preset at 32kHz, 7.5ms frame duration. + * + * Medium quality gaming audio with standard latency. + * + * @param _name Preset name. + * @param _loc Audio channel location. + * @param _stream_context Stream context type. + */ +#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_32_1_GS_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 60U, 1, \ + _stream_context, \ + 7500u, 60U, 1U, 15U, 60000U) + +/** + * @brief Gaming Standard (GS) preset at 32kHz, 10ms frame duration. + * + * Enhanced medium quality gaming audio. + * + * @param _name Preset name. + * @param _loc Audio channel location. + * @param _stream_context Stream context type. + */ +#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_32_2_GS_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 80U, 1, \ + _stream_context, \ + 10000u, 80U, 1U, 20U, 60000U) + +/** + * @brief Gaming Standard (GS) preset at 48kHz, 7.5ms frame duration. + * + * High quality gaming audio with standard latency. + * + * @param _name Preset name. + * @param _loc Audio channel location. + * @param _stream_context Stream context type. + */ +#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_48_1_GS_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 75U, 1, \ + _stream_context, \ + 7500u, 75U, 1U, 15U, 60000U) + +/** + * @brief Gaming Standard (GS) preset at 48kHz, 10ms frame duration. + * + * Premium quality gaming audio with standard latency. + * + * @param _name Preset name. + * @param _loc Audio channel location. + * @param _stream_context Stream context type. + */ +#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_48_2_GS_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 100U, 1, \ + _stream_context, \ + 10000u, 100U, 1U, 20U, 60000U) + +/** + * @brief Generic Gaming (G) preset at 48kHz, 7.5ms frame duration. + * + * High quality gaming audio with ultra-low latency (8ms). + * + * @param _name Preset name. + * @param _loc Audio channel location. + * @param _stream_context Stream context type. + */ +#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_48_1_G_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 75U, 1, \ + _stream_context, \ + 7500u, 75U, 1U, 8U, 10000U) + +/** + * @brief Generic Gaming (G) preset at 48kHz, 10ms frame duration. + * + * High quality gaming audio with very low latency (10ms). + * + * @param _name Preset name. + * @param _loc Audio channel location. + * @param _stream_context Stream context type. + */ +#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_48_2_G_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 100U, 1, \ + _stream_context, \ + 10000u, 100U, 1U, 10U, 10000U) + +/** + * @brief Generic Gaming (G) preset at 48kHz, 7.5ms frame duration, higher bitrate. + * + * Premium quality gaming audio with ultra-low latency. + * + * @param _name Preset name. + * @param _loc Audio channel location. + * @param _stream_context Stream context type. + */ +#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_48_3_G_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, \ + _loc, 90U, 1, \ + _stream_context, \ + 7500u, 90U, 1U, 8U, 10000U) + +/** + * @brief Generic Gaming (G) preset at 48kHz, 10ms frame duration, higher bitrate. + * + * Highest quality gaming audio with very low latency. + * + * @param _name Preset name. + * @param _loc Audio channel location. + * @param _stream_context Stream context type. + */ +#define ESP_BLE_AUDIO_GMAP_LC3_PRESET_48_4_G_DEFINE(_name, _loc, _stream_context) \ + ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFINE(_name, \ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, \ + _loc, 120u, 1, \ + _stream_context, \ + 10000u, 120U, 1U, 10U, 10000U) + +#ifdef __cplusplus +} +#endif + +#endif /* ESP_BLE_AUDIO_GMAP_LC3_PRESET_DEFS_H_ */ diff --git a/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_has_api.h b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_has_api.h new file mode 100644 index 0000000000..12e8bab46e --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_has_api.h @@ -0,0 +1,267 @@ +/* + * SPDX-FileCopyrightText: 2022 Codecoup + * SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ESP_BLE_AUDIO_HAS_API_H_ +#define ESP_BLE_AUDIO_HAS_API_H_ + +#include +#include +#include + +#include "sdkconfig.h" +#include "esp_err.h" + +#include +#include + +#include "common/init.h" +#include "common/host.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*!< No index */ +#define ESP_BLE_AUDIO_HAS_PRESET_INDEX_NONE BT_HAS_PRESET_INDEX_NONE +/*!< First preset index */ +#define ESP_BLE_AUDIO_HAS_PRESET_INDEX_FIRST BT_HAS_PRESET_INDEX_FIRST +/*!< Last preset index */ +#define ESP_BLE_AUDIO_HAS_PRESET_INDEX_LAST BT_HAS_PRESET_INDEX_LAST + +/*!< Preset name minimum length */ +#define ESP_BLE_AUDIO_HAS_PRESET_NAME_MIN BT_HAS_PRESET_NAME_MIN +/*!< Preset name maximum length */ +#define ESP_BLE_AUDIO_HAS_PRESET_NAME_MAX BT_HAS_PRESET_NAME_MAX + +/*!< No properties set */ +#define ESP_BLE_AUDIO_HAS_PROP_NONE BT_HAS_PROP_NONE +/*!< Preset name can be written by the client */ +#define ESP_BLE_AUDIO_HAS_PROP_WRITABLE BT_HAS_PROP_WRITABLE +/*!< Preset availability */ +#define ESP_BLE_AUDIO_HAS_PROP_AVAILABLE BT_HAS_PROP_AVAILABLE +/** Preset Properties values */ +typedef enum bt_has_properties esp_ble_audio_has_properties_t; + +/*!< Indicate support for presets */ +#define ESP_BLE_AUDIO_HAS_PRESET_SUPPORT BT_HAS_PRESET_SUPPORT +/** Hearing Aid device capabilities */ +typedef enum bt_has_capabilities esp_ble_audio_has_capabilities_t; + +/** + * Two hearing aids that form a Coordinated Set, one for the right ear and one for the left + * ear of the user. Typically used by a user with bilateral hearing loss. + */ +#define ESP_BLE_AUDIO_HAS_HEARING_AID_TYPE_BINAURAL BT_HAS_HEARING_AID_TYPE_BINAURAL +/** + * A single hearing aid for the left or the right ear. Typically used by a user with + * unilateral hearing loss. + */ +#define ESP_BLE_AUDIO_HAS_HEARING_AID_TYPE_MONAURAL BT_HAS_HEARING_AID_TYPE_MONAURAL +/** + * Two hearing aids with a connection to one another that expose a single Bluetooth radio + * interface. + */ +#define ESP_BLE_AUDIO_HAS_HEARING_AID_TYPE_BANDED BT_HAS_HEARING_AID_TYPE_BANDED +/** Hearing Aid device type */ +typedef enum bt_has_hearing_aid_type esp_ble_audio_has_hearing_aid_type_t; + +/** Hearing Access Service object */ +typedef struct bt_has esp_ble_audio_has_t; + +/** Hearing Access Service Client callback structure */ +typedef struct bt_has_client_cb esp_ble_audio_has_client_cb_t; + +/** Structure for registering features of a Hearing Access Service instance */ +typedef struct bt_has_features_param esp_ble_audio_has_features_param_t; + +/** Preset operations structure */ +typedef struct bt_has_preset_ops esp_ble_audio_has_preset_ops_t; + +/** Preset record definition */ +typedef struct bt_has_preset_record esp_ble_audio_has_preset_record_t; + +/** Register structure for preset */ +typedef struct bt_has_preset_register_param esp_ble_audio_has_preset_register_param_t; + +/** + * @brief Registers the callbacks used by the Hearing Access Service client. + * + * @param cb The callback structure. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_has_client_cb_register(const esp_ble_audio_has_client_cb_t *cb); + +/** + * @brief Discover Hearing Access Service on a remote device. + * + * Client method to find a Hearing Access Service on a server identified by @p conn_handle. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_has_client_discover(uint16_t conn_handle); + +/** + * @brief Read Preset Records. + * + * Client method to read up to @p max_count presets starting from given @p index. + * + * @param has Pointer to the Hearing Access Service object. + * @param index The index to start with. + * @param max_count Maximum number of presets to read. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_has_client_presets_read(esp_ble_audio_has_t *has, + uint8_t index, + uint8_t max_count); + +/** + * @brief Set Active Preset. + * + * Client procedure to set preset identified by @p index as active. + * + * @param has Pointer to the Hearing Access Service object. + * @param index Preset index to activate. + * @param sync Request active preset synchronization in set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_has_client_preset_set(esp_ble_audio_has_t *has, + uint8_t index, bool sync); + +/** + * @brief Activate Next Preset. + * + * Client procedure to set next available preset as active. + * + * @param has Pointer to the Hearing Access Service object. + * @param sync Request active preset synchronization in set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_has_client_preset_next(esp_ble_audio_has_t *has, bool sync); + +/** + * @brief Activate Previous Preset. + * + * Client procedure to set previous available preset as active. + * + * @param has Pointer to the Hearing Access Service object. + * @param sync Request active preset synchronization in set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_has_client_preset_prev(esp_ble_audio_has_t *has, bool sync); + +/** + * @brief Register the Hearing Access Service instance. + * + * @param features Hearing Access Service register parameters. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_has_register(const esp_ble_audio_has_features_param_t *features); + +/** + * @brief Register preset. + * + * Register preset. The preset will be added to the list of exposed preset records. + * + * @param param Preset registration parameter. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_has_preset_register(const esp_ble_audio_has_preset_register_param_t *param); + +/** + * @brief Unregister Preset. + * + * Unregister preset. The preset will be removed from the list of preset records. + * + * @param index The index of preset that's being requested to unregister. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_has_preset_unregister(uint8_t index); + +/** + * @brief Set the preset as available. + * + * This will notify preset availability to peer devices. Only available preset can + * be selected as active preset. + * + * @param index The index of preset that's became available. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_has_preset_available(uint8_t index); + +/** + * @brief Set the preset as unavailable. + * + * This will notify preset availability to peer devices. Unavailable preset cannot + * be selected as active preset. + * + * @param index The index of preset that's became unavailable. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_has_preset_unavailable(uint8_t index); + +/** + * @brief Set active preset. + * + * Function used to set the preset identified by the @p index as the active preset. + * The preset index will be notified to peer devices. + * + * @param index Preset index. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_has_preset_active_set(uint8_t index); + +/** + * @brief Get active preset. + * + * Function used to get the currently active preset index. + * + * @return Active preset index. + */ +uint8_t esp_ble_audio_has_preset_active_get(void); + +/** + * @brief Change the Preset Name. + * + * Change the name of the preset identified by @p index. + * + * @param index The index of the preset to change the name of. + * @param name Name to write. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_has_preset_name_change(uint8_t index, const char *name); + +/** + * @brief Change the Hearing Aid Features. + * + * Change the hearing aid features. + * + * @param features The features to be set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_has_features_set(const esp_ble_audio_has_features_param_t *features); + +#ifdef __cplusplus +} +#endif + +#endif /* ESP_BLE_AUDIO_HAS_API_H_ */ diff --git a/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_lc3_defs.h b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_lc3_defs.h new file mode 100644 index 0000000000..2fca7f5905 --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_lc3_defs.h @@ -0,0 +1,89 @@ +/* + * SPDX-FileCopyrightText: 2020 Intel Corporation + * SPDX-FileCopyrightText: 2022-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ESP_BLE_AUDIO_LC3_DEFS_H_ +#define ESP_BLE_AUDIO_LC3_DEFS_H_ + +#include + +#include "esp_ble_audio_codec_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Helper to declare LC3 codec capability. + * + * @param _freq Supported Sampling Frequencies bitfield. + * @param _duration Supported Frame Durations bitfield. + * @param _chan_count Supported channels. + * @param _len_min Minimum number of octets supported per codec frame. + * @param _len_max Maximum number of octets supported per codec frame. + * @param _max_frames_per_sdu Supported maximum codec frames per SDU. + * Optional and will be included only if != 1. + */ +#define ESP_BLE_AUDIO_CODEC_CAP_LC3_DATA(_freq, _duration, _chan_count, \ + _len_min, _len_max, \ + _max_frames_per_sdu) \ + BT_AUDIO_CODEC_CAP_LC3_DATA(_freq, _duration, _chan_count, \ + _len_min, _len_max, \ + _max_frames_per_sdu) + +/** + * @brief Helper to declare LC3 codec metadata. + * + * @param _prefer_context Preferred contexts. + */ +#define ESP_BLE_AUDIO_CODEC_CAP_LC3_META(_prefer_context) \ + BT_AUDIO_CODEC_CAP_LC3_META(_prefer_context) + +/** + * @brief Helper to declare LC3 codec capability. + * + * @param _data LC3 codec capability data. + * @param _meta LC3 codec capability metadata. + */ +#define ESP_BLE_AUDIO_CODEC_CAP_LC3(_data, _meta) \ + ESP_BLE_AUDIO_CODEC_CAP(ESP_BLE_ISO_CODING_FORMAT_LC3, 0x0000, 0x0000, _data, _meta) + +/** + * @brief Helper to declare LC3 codec data configuration. + * + * @param _freq Sampling frequency. + * @param _duration Frame duration. + * @param _loc Audio channel location bitfield. + * @param _len Octets per frame (16-bit integer). + * @param _frames_per_sdu Frames per SDU (8-bit integer). This value is + * optional and will be included only if != 1. + */ +#define ESP_BLE_AUDIO_CODEC_CFG_LC3_DATA(_freq, _duration, _loc, _len, _frames_per_sdu) \ + BT_AUDIO_CODEC_CFG_LC3_DATA(_freq, _duration, _loc, _len, _frames_per_sdu) + +/** + * @brief Helper to declare LC3 codec metadata configuration. + * + * @param _stream_context Stream context. + */ +#define ESP_BLE_AUDIO_CODEC_CFG_LC3_META(_stream_context) \ + BT_AUDIO_CODEC_CFG_LC3_META(_stream_context) + +/** + * @brief Helper to declare LC3 codec configuration. + * + * @param _data LC3 codec configuration data. + * @param _meta LC3 codec configuration metadata. + */ +#define ESP_BLE_AUDIO_CODEC_CFG_LC3(_data, _meta) \ + ESP_BLE_AUDIO_CODEC_CFG(ESP_BLE_ISO_CODING_FORMAT_LC3, 0x0000, 0x0000, _data, _meta) + +#ifdef __cplusplus +} +#endif + +#endif /* ESP_BLE_AUDIO_LC3_DEFS_H_ */ diff --git a/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_mcc_api.h b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_mcc_api.h new file mode 100644 index 0000000000..e975ac66cd --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_mcc_api.h @@ -0,0 +1,393 @@ +/* + * SPDX-FileCopyrightText: 2019-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ESP_BLE_AUDIO_MCC_API_H_ +#define ESP_BLE_AUDIO_MCC_API_H_ + +#include +#include +#include + +#include "sdkconfig.h" +#include "esp_err.h" + +#include +#include + +#include "common/init.h" +#include "common/host.h" + +#include "esp_ble_audio_media_proxy_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Media control client callbacks */ +typedef struct bt_mcc_cb esp_ble_audio_mcc_cb_t; + +/** + * @brief Initialize Media Control Client. + * + * @param cb Callbacks to be used. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_init(esp_ble_audio_mcc_cb_t *cb); + +/** + * @brief Discover Media Control Service. + * + * Discover Media Control Service (MCS) on the server given by the connection + * Optionally subscribe to notifications. + * + * Shall be called once, after media control client initialization and before + * using other media control client functionality. + * + * @param conn_handle Connection handle. + * @param subscribe Whether to subscribe to notifications. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_discover_mcs(uint16_t conn_handle, bool subscribe); + +/** + * @brief Read Media Player Name. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_read_player_name(uint16_t conn_handle); + +/** + * @brief Read Icon Object ID. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_read_icon_obj_id(uint16_t conn_handle); + +/** + * @brief Read Icon Object URL. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_read_icon_url(uint16_t conn_handle); + +/** + * @brief Read Track Title. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_read_track_title(uint16_t conn_handle); + +/** + * @brief Read Track Duration. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_read_track_duration(uint16_t conn_handle); + +/** + * @brief Read Track Position. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_read_track_position(uint16_t conn_handle); + +/** + * @brief Set Track position. + * + * @param conn_handle Connection handle. + * @param pos Track position. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_set_track_position(uint16_t conn_handle, int32_t pos); + +/** + * @brief Read Playback speed. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_read_playback_speed(uint16_t conn_handle); + +/** + * @brief Set Playback Speed. + * + * @param conn_handle Connection handle. + * @param speed Playback speed. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_set_playback_speed(uint16_t conn_handle, int8_t speed); + +/** + * @brief Read Seeking speed. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_read_seeking_speed(uint16_t conn_handle); + +/** + * @brief Read Track Segments Object ID. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_read_segments_obj_id(uint16_t conn_handle); + +/** + * @brief Read Current Track Object ID. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_read_current_track_obj_id(uint16_t conn_handle); + +/** + * @brief Set Current Track Object ID. + * + * Set the Current Track to the track given by the @p id parameter. + * + * @param conn_handle Connection handle. + * @param id Object Transfer Service ID (UINT48) of the track to set as the current track. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_set_current_track_obj_id(uint16_t conn_handle, uint64_t id); + +/** + * @brief Read Next Track Object ID. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_read_next_track_obj_id(uint16_t conn_handle); + +/** + * @brief Set Next Track Object ID. + * + * @param conn_handle Connection handle. + * @param id Object Transfer Service ID (UINT48) of the track to set as the next track. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_set_next_track_obj_id(uint16_t conn_handle, uint64_t id); + +/** + * @brief Read Current Group Object ID. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_read_current_group_obj_id(uint16_t conn_handle); + +/** + * @brief Set Current Group Object ID. + * + * @param conn_handle Connection handle. + * @param id Object Transfer Service ID (UINT48) of the group to set as the current group. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_set_current_group_obj_id(uint16_t conn_handle, uint64_t id); + +/** + * @brief Read Parent Group Object ID. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_read_parent_group_obj_id(uint16_t conn_handle); + +/** + * @brief Read Playing Order. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_read_playing_order(uint16_t conn_handle); + +/** + * @brief Set Playing Order. + * + * @param conn_handle Connection handle. + * @param order Playing order. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_set_playing_order(uint16_t conn_handle, uint8_t order); + +/** + * @brief Read Playing Orders Supported. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_read_playing_orders_supported(uint16_t conn_handle); + +/** + * @brief Read Media State. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_read_media_state(uint16_t conn_handle); + +/** + * @brief Send a command. + * + * Write a command (e.g. "play", "pause") to the server's media control point. + * + * @param conn_handle Connection handle. + * @param cmd The command to send. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_send_cmd(uint16_t conn_handle, + const esp_ble_audio_mpl_cmd_t *cmd); + +/** + * @brief Read Opcodes Supported. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_read_opcodes_supported(uint16_t conn_handle); + +/** + * @brief Send a Search command. + * + * Write a search to the server's search control point. + * + * @param conn_handle Connection handle. + * @param search The search. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_send_search(uint16_t conn_handle, + const esp_ble_audio_mpl_search_t *search); + +/** + * @brief Search Results Group Object ID. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_read_search_results_obj_id(uint16_t conn_handle); + +/** + * @brief Read Content Control ID. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_read_content_control_id(uint16_t conn_handle); + +/** + * @brief Read the current object metadata. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_otc_read_object_metadata(uint16_t conn_handle); + +/** + * @brief Read the Icon Object. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_otc_read_icon_object(uint16_t conn_handle); + +/** + * @brief Read the Track Segments Object. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_otc_read_track_segments_object(uint16_t conn_handle); + +/** + * @brief Read the Current Track Object. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_otc_read_current_track_object(uint16_t conn_handle); + +/** + * @brief Read the Next Track Object. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_otc_read_next_track_object(uint16_t conn_handle); + +/** + * @brief Read the Current Group Object. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_otc_read_current_group_object(uint16_t conn_handle); + +/** + * @brief Read the Parent Group Object. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_mcc_otc_read_parent_group_object(uint16_t conn_handle); + +/** + * @brief Look up MCC OTC instance. + * + * @param conn_handle Connection handle. + * + * @return Pointer to a MCC OTC instance if found else NULL. + */ +struct bt_ots_client *esp_ble_audio_mcc_otc_inst(uint16_t conn_handle); + +#ifdef __cplusplus +} +#endif + +#endif /* ESP_BLE_AUDIO_MCC_API_H_ */ diff --git a/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_mcs_defs.h b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_mcs_defs.h new file mode 100644 index 0000000000..3a75a162f4 --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_mcs_defs.h @@ -0,0 +1,268 @@ +/* + * SPDX-FileCopyrightText: 2019-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ESP_BLE_AUDIO_MCS_DEFS_H_ +#define ESP_BLE_AUDIO_MCS_DEFS_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*!< Minimum playback speed, resulting in 25% speed */ +#define ESP_BLE_AUDIO_MCS_PLAYBACK_SPEED_MIN BT_MCS_PLAYBACK_SPEED_MIN +/*!< Quarter playback speed, resulting in 25% speed */ +#define ESP_BLE_AUDIO_MCS_PLAYBACK_SPEED_QUARTER BT_MCS_PLAYBACK_SPEED_QUARTER +/*!< Half playback speed, resulting in 50% speed */ +#define ESP_BLE_AUDIO_MCS_PLAYBACK_SPEED_HALF BT_MCS_PLAYBACK_SPEED_HALF +/*!< Unity playback speed, resulting in 100% speed */ +#define ESP_BLE_AUDIO_MCS_PLAYBACK_SPEED_UNITY BT_MCS_PLAYBACK_SPEED_UNITY +/*!< Double playback speed, resulting in 200% speed */ +#define ESP_BLE_AUDIO_MCS_PLAYBACK_SPEED_DOUBLE BT_MCS_PLAYBACK_SPEED_DOUBLE +/*!< Max playback speed, resulting in 395.7% speed (nearly 400%) */ +#define ESP_BLE_AUDIO_MCS_PLAYBACK_SPEED_MAX BT_MCS_PLAYBACK_SPEED_MAX + +/*!< Maximum seeking speed - Can be negated */ +#define ESP_BLE_AUDIO_MCS_SEEKING_SPEED_FACTOR_MAX BT_MCS_SEEKING_SPEED_FACTOR_MAX +/*!< Minimum seeking speed - Can be negated */ +#define ESP_BLE_AUDIO_MCS_SEEKING_SPEED_FACTOR_MIN BT_MCS_SEEKING_SPEED_FACTOR_MIN +/*!< No seeking */ +#define ESP_BLE_AUDIO_MCS_SEEKING_SPEED_FACTOR_ZERO BT_MCS_SEEKING_SPEED_FACTOR_ZERO + +/*!< A single track is played once; there is no next track. */ +#define ESP_BLE_AUDIO_MCS_PLAYING_ORDER_SINGLE_ONCE BT_MCS_PLAYING_ORDER_SINGLE_ONCE +/*!< A single track is played repeatedly; the next track is the current track. */ +#define ESP_BLE_AUDIO_MCS_PLAYING_ORDER_SINGLE_REPEAT BT_MCS_PLAYING_ORDER_SINGLE_REPEAT +/*!< The tracks within a group are played once in track order. */ +#define ESP_BLE_AUDIO_MCS_PLAYING_ORDER_INORDER_ONCE BT_MCS_PLAYING_ORDER_INORDER_ONCE +/*!< The tracks within a group are played in track order repeatedly. */ +#define ESP_BLE_AUDIO_MCS_PLAYING_ORDER_INORDER_REPEAT BT_MCS_PLAYING_ORDER_INORDER_REPEAT +/*!< The tracks within a group are played once only from the oldest first. */ +#define ESP_BLE_AUDIO_MCS_PLAYING_ORDER_OLDEST_ONCE BT_MCS_PLAYING_ORDER_OLDEST_ONCE +/*!< The tracks within a group are played from the oldest first repeatedly. */ +#define ESP_BLE_AUDIO_MCS_PLAYING_ORDER_OLDEST_REPEAT BT_MCS_PLAYING_ORDER_OLDEST_REPEAT +/*!< The tracks within a group are played once only from the newest first. */ +#define ESP_BLE_AUDIO_MCS_PLAYING_ORDER_NEWEST_ONCE BT_MCS_PLAYING_ORDER_NEWEST_ONCE +/*!< The tracks within a group are played from the newest first repeatedly. */ +#define ESP_BLE_AUDIO_MCS_PLAYING_ORDER_NEWEST_REPEAT BT_MCS_PLAYING_ORDER_NEWEST_REPEAT +/*!< The tracks within a group are played in random order once. */ +#define ESP_BLE_AUDIO_MCS_PLAYING_ORDER_SHUFFLE_ONCE BT_MCS_PLAYING_ORDER_SHUFFLE_ONCE +/*!< The tracks within a group are played in random order repeatedly. */ +#define ESP_BLE_AUDIO_MCS_PLAYING_ORDER_SHUFFLE_REPEAT BT_MCS_PLAYING_ORDER_SHUFFLE_REPEAT + +/*!< The current track is invalid, and no track has been selected. */ +#define ESP_BLE_AUDIO_MCS_MEDIA_STATE_INACTIVE BT_MCS_MEDIA_STATE_INACTIVE +/*!< The media player is playing the current track. */ +#define ESP_BLE_AUDIO_MCS_MEDIA_STATE_PLAYING BT_MCS_MEDIA_STATE_PLAYING +/*!< The current track is paused. The media player has a current track, but it is not being played */ +#define ESP_BLE_AUDIO_MCS_MEDIA_STATE_PAUSED BT_MCS_MEDIA_STATE_PAUSED +/*!< The current track is fast forwarding or fast rewinding. */ +#define ESP_BLE_AUDIO_MCS_MEDIA_STATE_SEEKING BT_MCS_MEDIA_STATE_SEEKING + +/*!< Start playing the current track. */ +#define ESP_BLE_AUDIO_MCS_OPC_PLAY BT_MCS_OPC_PLAY +/*!< Pause playing the current track. */ +#define ESP_BLE_AUDIO_MCS_OPC_PAUSE BT_MCS_OPC_PAUSE +/*!< Fast rewind the current track. */ +#define ESP_BLE_AUDIO_MCS_OPC_FAST_REWIND BT_MCS_OPC_FAST_REWIND +/*!< Fast forward the current track. */ +#define ESP_BLE_AUDIO_MCS_OPC_FAST_FORWARD BT_MCS_OPC_FAST_FORWARD +/** + * Stop current activity and return to the paused state and set + * the current track position to the start of the current track. + */ +#define ESP_BLE_AUDIO_MCS_OPC_STOP BT_MCS_OPC_STOP + +/*!< Set a new current track position relative to the current track position. */ +#define ESP_BLE_AUDIO_MCS_OPC_MOVE_RELATIVE BT_MCS_OPC_MOVE_RELATIVE + +/** + * Set the current track position to the starting position of + * the previous segment of the current track. + */ +#define ESP_BLE_AUDIO_MCS_OPC_PREV_SEGMENT BT_MCS_OPC_PREV_SEGMENT +/** + * Set the current track position to the starting position of + * the next segment of the current track. + */ +#define ESP_BLE_AUDIO_MCS_OPC_NEXT_SEGMENT BT_MCS_OPC_NEXT_SEGMENT +/** + * Set the current track position to the starting position of + * the first segment of the current track. + */ +#define ESP_BLE_AUDIO_MCS_OPC_FIRST_SEGMENT BT_MCS_OPC_FIRST_SEGMENT +/** + * Set the current track position to the starting position of + * the last segment of the current track. + */ +#define ESP_BLE_AUDIO_MCS_OPC_LAST_SEGMENT BT_MCS_OPC_LAST_SEGMENT +/** + * Set the current track position to the starting position of + * the nth segment of the current track. + */ +#define ESP_BLE_AUDIO_MCS_OPC_GOTO_SEGMENT BT_MCS_OPC_GOTO_SEGMENT + +/*!< Set the current track to the previous track based on the playing order. */ +#define ESP_BLE_AUDIO_MCS_OPC_PREV_TRACK BT_MCS_OPC_PREV_TRACK +/*!< Set the current track to the next track based on the playing order. */ +#define ESP_BLE_AUDIO_MCS_OPC_NEXT_TRACK BT_MCS_OPC_NEXT_TRACK +/*!< Set the current track to the first track based on the playing order. */ +#define ESP_BLE_AUDIO_MCS_OPC_FIRST_TRACK BT_MCS_OPC_FIRST_TRACK +/*!< Set the current track to the last track based on the playing order. */ +#define ESP_BLE_AUDIO_MCS_OPC_LAST_TRACK BT_MCS_OPC_LAST_TRACK +/*!< Set the current track to the nth track based on the playing order. */ +#define ESP_BLE_AUDIO_MCS_OPC_GOTO_TRACK BT_MCS_OPC_GOTO_TRACK + +/*!< Set the current group to the previous group in the sequence of groups. */ +#define ESP_BLE_AUDIO_MCS_OPC_PREV_GROUP BT_MCS_OPC_PREV_GROUP +/*!< Set the current group to the next group in the sequence of groups. */ +#define ESP_BLE_AUDIO_MCS_OPC_NEXT_GROUP BT_MCS_OPC_NEXT_GROUP +/*!< Set the current group to the first group in the sequence of groups. */ +#define ESP_BLE_AUDIO_MCS_OPC_FIRST_GROUP BT_MCS_OPC_FIRST_GROUP +/*!< Set the current group to the last group in the sequence of groups. */ +#define ESP_BLE_AUDIO_MCS_OPC_LAST_GROUP BT_MCS_OPC_LAST_GROUP +/*!< Set the current group to the nth group in the sequence of groups. */ +#define ESP_BLE_AUDIO_MCS_OPC_GOTO_GROUP BT_MCS_OPC_GOTO_GROUP + +/*!< Media control point supported opcodes length */ +#define ESP_BLE_AUDIO_MCS_OPCODES_SUPPORTED_LEN BT_MCS_OPCODES_SUPPORTED_LEN + +/*!< Support the Play opcode */ +#define ESP_BLE_AUDIO_MCS_OPC_SUP_PLAY BT_MCS_OPC_SUP_PLAY +/*!< Support the Pause opcode */ +#define ESP_BLE_AUDIO_MCS_OPC_SUP_PAUSE BT_MCS_OPC_SUP_PAUSE +/*!< Support the Fast Rewind opcode */ +#define ESP_BLE_AUDIO_MCS_OPC_SUP_FAST_REWIND BT_MCS_OPC_SUP_FAST_REWIND +/*!< Support the Fast Forward opcode */ +#define ESP_BLE_AUDIO_MCS_OPC_SUP_FAST_FORWARD BT_MCS_OPC_SUP_FAST_FORWARD +/*!< Support the Stop opcode */ +#define ESP_BLE_AUDIO_MCS_OPC_SUP_STOP BT_MCS_OPC_SUP_STOP +/*!< Support the Move Relative opcode */ +#define ESP_BLE_AUDIO_MCS_OPC_SUP_MOVE_RELATIVE BT_MCS_OPC_SUP_MOVE_RELATIVE +/*!< Support the Previous Segment opcode */ +#define ESP_BLE_AUDIO_MCS_OPC_SUP_PREV_SEGMENT BT_MCS_OPC_SUP_PREV_SEGMENT +/*!< Support the Next Segment opcode */ +#define ESP_BLE_AUDIO_MCS_OPC_SUP_NEXT_SEGMENT BT_MCS_OPC_SUP_NEXT_SEGMENT +/*!< Support the First Segment opcode */ +#define ESP_BLE_AUDIO_MCS_OPC_SUP_FIRST_SEGMENT BT_MCS_OPC_SUP_FIRST_SEGMENT +/*!< Support the Last Segment opcode */ +#define ESP_BLE_AUDIO_MCS_OPC_SUP_LAST_SEGMENT BT_MCS_OPC_SUP_LAST_SEGMENT +/*!< Support the Goto Segment opcode */ +#define ESP_BLE_AUDIO_MCS_OPC_SUP_GOTO_SEGMENT BT_MCS_OPC_SUP_GOTO_SEGMENT + +/*!< Support the Previous Track opcode */ +#define ESP_BLE_AUDIO_MCS_OPC_SUP_PREV_TRACK BT_MCS_OPC_SUP_PREV_TRACK +/*!< Support the Next Track opcode */ +#define ESP_BLE_AUDIO_MCS_OPC_SUP_NEXT_TRACK BT_MCS_OPC_SUP_NEXT_TRACK +/*!< Support the First Track opcode */ +#define ESP_BLE_AUDIO_MCS_OPC_SUP_FIRST_TRACK BT_MCS_OPC_SUP_FIRST_TRACK +/*!< Support the Last Track opcode */ +#define ESP_BLE_AUDIO_MCS_OPC_SUP_LAST_TRACK BT_MCS_OPC_SUP_LAST_TRACK +/*!< Support the Goto Track opcode */ +#define ESP_BLE_AUDIO_MCS_OPC_SUP_GOTO_TRACK BT_MCS_OPC_SUP_GOTO_TRACK + +/*!< Support the Previous Group opcode */ +#define ESP_BLE_AUDIO_MCS_OPC_SUP_PREV_GROUP BT_MCS_OPC_SUP_PREV_GROUP +/*!< Support the Next Group opcode */ +#define ESP_BLE_AUDIO_MCS_OPC_SUP_NEXT_GROUP BT_MCS_OPC_SUP_NEXT_GROUP +/*!< Support the First Group opcode */ +#define ESP_BLE_AUDIO_MCS_OPC_SUP_FIRST_GROUP BT_MCS_OPC_SUP_FIRST_GROUP +/*!< Support the Last Group opcode */ +#define ESP_BLE_AUDIO_MCS_OPC_SUP_LAST_GROUP BT_MCS_OPC_SUP_LAST_GROUP +/*!< Support the Goto Group opcode */ +#define ESP_BLE_AUDIO_MCS_OPC_SUP_GOTO_GROUP BT_MCS_OPC_SUP_GOTO_GROUP + +/** Action requested by the opcode write was completed successfully. */ +#define ESP_BLE_AUDIO_MCS_OPC_NTF_SUCCESS BT_MCS_OPC_NTF_SUCCESS +/** An invalid or unsupported opcode was used for the Media Control Point write. */ +#define ESP_BLE_AUDIO_MCS_OPC_NTF_NOT_SUPPORTED BT_MCS_OPC_NTF_NOT_SUPPORTED +/** + * The Media Player State characteristic value is Inactive when the opcode is + * received or the result of the requested action of the opcode results in the + * Media Player State characteristic being set to Inactive. + */ +#define ESP_BLE_AUDIO_MCS_OPC_NTF_PLAYER_INACTIVE BT_MCS_OPC_NTF_PLAYER_INACTIVE +/** + * The requested action of any Media Control Point write cannot be completed + * successfully because of a condition within the player. + */ +#define ESP_BLE_AUDIO_MCS_OPC_NTF_CANNOT_BE_COMPLETED BT_MCS_OPC_NTF_CANNOT_BE_COMPLETED + +/*!< Search for Track Name */ +#define ESP_BLE_AUDIO_MCS_SEARCH_TYPE_TRACK_NAME BT_MCS_SEARCH_TYPE_TRACK_NAME +/*!< Search for Artist Name */ +#define ESP_BLE_AUDIO_MCS_SEARCH_TYPE_ARTIST_NAME BT_MCS_SEARCH_TYPE_ARTIST_NAME +/*!< Search for Album Name */ +#define ESP_BLE_AUDIO_MCS_SEARCH_TYPE_ALBUM_NAME BT_MCS_SEARCH_TYPE_ALBUM_NAME +/*!< Search for Group Name */ +#define ESP_BLE_AUDIO_MCS_SEARCH_TYPE_GROUP_NAME BT_MCS_SEARCH_TYPE_GROUP_NAME +/*!< Search for Earliest Year */ +#define ESP_BLE_AUDIO_MCS_SEARCH_TYPE_EARLIEST_YEAR BT_MCS_SEARCH_TYPE_EARLIEST_YEAR +/*!< Search for Latest Year */ +#define ESP_BLE_AUDIO_MCS_SEARCH_TYPE_LATEST_YEAR BT_MCS_SEARCH_TYPE_LATEST_YEAR +/*!< Search for Genre */ +#define ESP_BLE_AUDIO_MCS_SEARCH_TYPE_GENRE BT_MCS_SEARCH_TYPE_GENRE +/*!< Search for Tracks only */ +#define ESP_BLE_AUDIO_MCS_SEARCH_TYPE_ONLY_TRACKS BT_MCS_SEARCH_TYPE_ONLY_TRACKS +/*!< Search for Groups only */ +#define ESP_BLE_AUDIO_MCS_SEARCH_TYPE_ONLY_GROUPS BT_MCS_SEARCH_TYPE_ONLY_GROUPS + +/*!< Search control point minimum length */ +#define ESP_BLE_AUDIO_SEARCH_LEN_MIN SEARCH_LEN_MIN +/*!< Search control point maximum length */ +#define ESP_BLE_AUDIO_SEARCH_LEN_MAX SEARCH_LEN_MAX + +/*!< Search control point item (SCI) minimum length */ +#define ESP_BLE_AUDIO_SEARCH_SCI_LEN_MIN SEARCH_SCI_LEN_MIN + +/*!< Search parameters maximum length */ +#define ESP_BLE_AUDIO_SEARCH_PARAM_MAX SEARCH_PARAM_MAX + +/*!< Search request was accepted; search has started. */ +#define ESP_BLE_AUDIO_MCS_SCP_NTF_SUCCESS BT_MCS_SCP_NTF_SUCCESS +/*!< Search request was invalid; no search started. */ +#define ESP_BLE_AUDIO_MCS_SCP_NTF_FAILURE BT_MCS_SCP_NTF_FAILURE + +/*!< Group object type is track */ +#define ESP_BLE_AUDIO_MCS_GROUP_OBJECT_TRACK_TYPE BT_MCS_GROUP_OBJECT_TRACK_TYPE +/*!< Group object type is group */ +#define ESP_BLE_AUDIO_MCS_GROUP_OBJECT_GROUP_TYPE BT_MCS_GROUP_OBJECT_GROUP_TYPE + +/*!< A single track is played once; there is no next track. */ +#define ESP_BLE_AUDIO_MCS_PLAYING_ORDERS_SUPPORTED_SINGLE_ONCE BT_MCS_PLAYING_ORDERS_SUPPORTED_SINGLE_ONCE +/*!< A single track is played repeatedly; the next track is the current track. */ +#define ESP_BLE_AUDIO_MCS_PLAYING_ORDERS_SUPPORTED_SINGLE_REPEAT BT_MCS_PLAYING_ORDERS_SUPPORTED_SINGLE_REPEAT +/*!< The tracks within a group are played once in track order. */ +#define ESP_BLE_AUDIO_MCS_PLAYING_ORDERS_SUPPORTED_INORDER_ONCE BT_MCS_PLAYING_ORDERS_SUPPORTED_INORDER_ONCE +/*!< The tracks within a group are played in track order repeatedly. */ +#define ESP_BLE_AUDIO_MCS_PLAYING_ORDERS_SUPPORTED_INORDER_REPEAT BT_MCS_PLAYING_ORDERS_SUPPORTED_INORDER_REPEAT +/*!< The tracks within a group are played once only from the oldest first. */ +#define ESP_BLE_AUDIO_MCS_PLAYING_ORDERS_SUPPORTED_OLDEST_ONCE BT_MCS_PLAYING_ORDERS_SUPPORTED_OLDEST_ONCE +/*!< The tracks within a group are played from the oldest first repeatedly. */ +#define ESP_BLE_AUDIO_MCS_PLAYING_ORDERS_SUPPORTED_OLDEST_REPEAT BT_MCS_PLAYING_ORDERS_SUPPORTED_OLDEST_REPEAT +/*!< The tracks within a group are played once only from the newest first. */ +#define ESP_BLE_AUDIO_MCS_PLAYING_ORDERS_SUPPORTED_NEWEST_ONCE BT_MCS_PLAYING_ORDERS_SUPPORTED_NEWEST_ONCE +/*!< The tracks within a group are played from the newest first repeatedly. */ +#define ESP_BLE_AUDIO_MCS_PLAYING_ORDERS_SUPPORTED_NEWEST_REPEAT BT_MCS_PLAYING_ORDERS_SUPPORTED_NEWEST_REPEAT +/*!< The tracks within a group are played in random order once. */ +#define ESP_BLE_AUDIO_MCS_PLAYING_ORDERS_SUPPORTED_SHUFFLE_ONCE BT_MCS_PLAYING_ORDERS_SUPPORTED_SHUFFLE_ONCE +/*!< The tracks within a group are played in random order repeatedly. */ +#define ESP_BLE_AUDIO_MCS_PLAYING_ORDERS_SUPPORTED_SHUFFLE_REPEAT BT_MCS_PLAYING_ORDERS_SUPPORTED_SHUFFLE_REPEAT + +/** + * Check if an Object ID is valid for MCS. + * This differs from BT_OTS_VALID_OBJ_ID as MCS does not use the directory list object. + */ +#define ESP_BLE_AUDIO_MCS_VALID_OBJ_ID(id) \ + (IN_RANGE((id), BT_OTS_OBJ_ID_MIN, BT_OTS_OBJ_ID_MAX)) + +#ifdef __cplusplus +} +#endif + +#endif /* ESP_BLE_AUDIO_MCS_DEFS_H_ */ diff --git a/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_media_proxy_api.h b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_media_proxy_api.h new file mode 100644 index 0000000000..c8a9609670 --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_media_proxy_api.h @@ -0,0 +1,743 @@ +/* + * SPDX-FileCopyrightText: 2019-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ESP_BLE_AUDIO_MEDIA_PROXY_API_H_ +#define ESP_BLE_AUDIO_MEDIA_PROXY_API_H_ + +#include +#include +#include + +#include "sdkconfig.h" +#include "esp_err.h" + +#include +#include + +#include "common/init.h" +#include "common/host.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*!< Minimum playback speed, resulting in 25% speed */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYBACK_SPEED_MIN MEDIA_PROXY_PLAYBACK_SPEED_MIN +/*!< Quarter playback speed, resulting in 25% speed */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYBACK_SPEED_QUARTER MEDIA_PROXY_PLAYBACK_SPEED_QUARTER +/*!< Half playback speed, resulting in 50% speed */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYBACK_SPEED_HALF MEDIA_PROXY_PLAYBACK_SPEED_HALF +/*!< Unity playback speed, resulting in 100% speed */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYBACK_SPEED_UNITY MEDIA_PROXY_PLAYBACK_SPEED_UNITY +/*!< Double playback speed, resulting in 200% speed */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYBACK_SPEED_DOUBLE MEDIA_PROXY_PLAYBACK_SPEED_DOUBLE +/*!< Max playback speed, resulting in 395.7% speed (nearly 400%) */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYBACK_SPEED_MAX MEDIA_PROXY_PLAYBACK_SPEED_MAX + +/*!< The current track is invalid, and no track has been selected. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_STATE_INACTIVE MEDIA_PROXY_STATE_INACTIVE +/*!< The media player is playing the current track. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_STATE_PLAYING MEDIA_PROXY_STATE_PLAYING +/*!< The current track is paused. The media player has a current track, but it is not being played */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_STATE_PAUSED MEDIA_PROXY_STATE_PAUSED +/*!< The current track is fast forwarding or fast rewinding. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_STATE_SEEKING MEDIA_PROXY_STATE_SEEKING +/*!< Used internally as the last state value */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_STATE_LAST MEDIA_PROXY_STATE_LAST + +/*!< Start playing the current track. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_PLAY MEDIA_PROXY_OP_PLAY +/*!< Pause playing the current track. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_PAUSE MEDIA_PROXY_OP_PAUSE +/*!< Fast rewind the current track. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_FAST_REWIND MEDIA_PROXY_OP_FAST_REWIND +/*!< Fast forward the current track. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_FAST_FORWARD MEDIA_PROXY_OP_FAST_FORWARD +/** + * Stop current activity and return to the paused state and set + * the current track position to the start of the current track. + */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_STOP MEDIA_PROXY_OP_STOP + +/*!< Set a new current track position relative to the current track position. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_MOVE_RELATIVE MEDIA_PROXY_OP_MOVE_RELATIVE + +/** + * Set the current track position to the starting position of + * the previous segment of the current track. + */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_PREV_SEGMENT MEDIA_PROXY_OP_PREV_SEGMENT +/** + * Set the current track position to the starting position of + * the next segment of the current track. + */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_NEXT_SEGMENT MEDIA_PROXY_OP_NEXT_SEGMENT +/** + * Set the current track position to the starting position of + * the first segment of the current track. + */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_FIRST_SEGMENT MEDIA_PROXY_OP_FIRST_SEGMENT +/** + * Set the current track position to the starting position of + * the last segment of the current track. + */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_LAST_SEGMENT MEDIA_PROXY_OP_LAST_SEGMENT +/** + * Set the current track position to the starting position of + * the nth segment of the current track. + */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_GOTO_SEGMENT MEDIA_PROXY_OP_GOTO_SEGMENT + +/*!< Set the current track to the previous track based on the playing order. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_PREV_TRACK MEDIA_PROXY_OP_PREV_TRACK +/*!< Set the current track to the next track based on the playing order. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_NEXT_TRACK MEDIA_PROXY_OP_NEXT_TRACK +/*!< Set the current track to the first track based on the playing order. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_FIRST_TRACK MEDIA_PROXY_OP_FIRST_TRACK +/*!< Set the current track to the last track based on the playing order. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_LAST_TRACK MEDIA_PROXY_OP_LAST_TRACK +/*!< Set the current track to the nth track based on the playing order. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_GOTO_TRACK MEDIA_PROXY_OP_GOTO_TRACK + +/*!< Set the current group to the previous group in the sequence of groups. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_PREV_GROUP MEDIA_PROXY_OP_PREV_GROUP +/*!< Set the current group to the next group in the sequence of groups. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_NEXT_GROUP MEDIA_PROXY_OP_NEXT_GROUP +/*!< Set the current group to the first group in the sequence of groups. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_FIRST_GROUP MEDIA_PROXY_OP_FIRST_GROUP +/*!< Set the current group to the last group in the sequence of groups. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_LAST_GROUP MEDIA_PROXY_OP_LAST_GROUP +/*!< Set the current group to the nth group in the sequence of groups. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_GOTO_GROUP MEDIA_PROXY_OP_GOTO_GROUP + +/*!< Media player supported opcodes length */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OPCODES_SUPPORTED_LEN MEDIA_PROXY_OPCODES_SUPPORTED_LEN + +/*!< Support the Play opcode */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_PLAY MEDIA_PROXY_OP_SUP_PLAY +/*!< Support the Pause opcode */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_PAUSE MEDIA_PROXY_OP_SUP_PAUSE +/*!< Support the Fast Rewind opcode */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_FAST_REWIND MEDIA_PROXY_OP_SUP_FAST_REWIND +/*!< Support the Fast Forward opcode */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_FAST_FORWARD MEDIA_PROXY_OP_SUP_FAST_FORWARD +/*!< Support the Stop opcode */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_STOP MEDIA_PROXY_OP_SUP_STOP + +/*!< Support the Move Relative opcode */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_MOVE_RELATIVE MEDIA_PROXY_OP_SUP_MOVE_RELATIVE + +/*!< Support the Previous Segment opcode */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_PREV_SEGMENT MEDIA_PROXY_OP_SUP_PREV_SEGMENT +/*!< Support the Next Segment opcode */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_NEXT_SEGMENT MEDIA_PROXY_OP_SUP_NEXT_SEGMENT +/*!< Support the First Segment opcode */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_FIRST_SEGMENT MEDIA_PROXY_OP_SUP_FIRST_SEGMENT +/*!< Support the Last Segment opcode */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_LAST_SEGMENT MEDIA_PROXY_OP_SUP_LAST_SEGMENT +/*!< Support the Goto Segment opcode */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_GOTO_SEGMENT MEDIA_PROXY_OP_SUP_GOTO_SEGMENT + +/*!< Support the Previous Track opcode */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_PREV_TRACK MEDIA_PROXY_OP_SUP_PREV_TRACK +/*!< Support the Next Track opcode */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_NEXT_TRACK MEDIA_PROXY_OP_SUP_NEXT_TRACK +/*!< Support the First Track opcode */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_FIRST_TRACK MEDIA_PROXY_OP_SUP_FIRST_TRACK +/*!< Support the Last Track opcode */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_LAST_TRACK MEDIA_PROXY_OP_SUP_LAST_TRACK +/*!< Support the Goto Track opcode */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_GOTO_TRACK MEDIA_PROXY_OP_SUP_GOTO_TRACK + +/*!< Support the Previous Group opcode */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_PREV_GROUP MEDIA_PROXY_OP_SUP_PREV_GROUP +/*!< Support the Next Group opcode */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_NEXT_GROUP MEDIA_PROXY_OP_SUP_NEXT_GROUP +/*!< Support the First Group opcode */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_FIRST_GROUP MEDIA_PROXY_OP_SUP_FIRST_GROUP +/*!< Support the Last Group opcode */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_LAST_GROUP MEDIA_PROXY_OP_SUP_LAST_GROUP +/*!< Support the Goto Group opcode */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_OP_SUP_GOTO_GROUP MEDIA_PROXY_OP_SUP_GOTO_GROUP + +/*!< Action requested by the opcode write was completed successfully. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_CMD_SUCCESS MEDIA_PROXY_CMD_SUCCESS +/*!< An invalid or unsupported opcode was used for the Media Control Point write. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_CMD_NOT_SUPPORTED MEDIA_PROXY_CMD_NOT_SUPPORTED +/** + * The Media Player State characteristic value is Inactive when the opcode + * is received or the result of the requested action of the opcode results + * in the Media Player State characteristic being set to Inactive. + */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_CMD_PLAYER_INACTIVE MEDIA_PROXY_CMD_PLAYER_INACTIVE +/** + * The requested action of any Media Control Point write cannot be completed + * successfully because of a condition within the player. + */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED + +/*!< Search for Track Name */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_SEARCH_TYPE_TRACK_NAME MEDIA_PROXY_SEARCH_TYPE_TRACK_NAME +/*!< Search for Artist Name */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_SEARCH_TYPE_ARTIST_NAME MEDIA_PROXY_SEARCH_TYPE_ARTIST_NAME +/*!< Search for Album Name */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_SEARCH_TYPE_ALBUM_NAME MEDIA_PROXY_SEARCH_TYPE_ALBUM_NAME +/*!< Search for Group Name */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_SEARCH_TYPE_GROUP_NAME MEDIA_PROXY_SEARCH_TYPE_GROUP_NAME +/*!< Search for Earliest Year */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_SEARCH_TYPE_EARLIEST_YEAR MEDIA_PROXY_SEARCH_TYPE_EARLIEST_YEAR +/*!< Search for Latest Year */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_SEARCH_TYPE_LATEST_YEAR MEDIA_PROXY_SEARCH_TYPE_LATEST_YEAR +/*!< Search for Genre */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_SEARCH_TYPE_GENRE MEDIA_PROXY_SEARCH_TYPE_GENRE +/*!< Search for Tracks only */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_SEARCH_TYPE_ONLY_TRACKS MEDIA_PROXY_SEARCH_TYPE_ONLY_TRACKS +/*!< Search for Groups only */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_SEARCH_TYPE_ONLY_GROUPS MEDIA_PROXY_SEARCH_TYPE_ONLY_GROUPS + +/*!< Search request was accepted; search has started. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_SEARCH_SUCCESS MEDIA_PROXY_SEARCH_SUCCESS +/*!< Search request was invalid; no search started. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_SEARCH_FAILURE MEDIA_PROXY_SEARCH_FAILURE + +/*!< Group object type is track */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_GROUP_OBJECT_TRACK_TYPE MEDIA_PROXY_GROUP_OBJECT_TRACK_TYPE +/*!< Group object type is group */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_GROUP_OBJECT_GROUP_TYPE MEDIA_PROXY_GROUP_OBJECT_GROUP_TYPE + +/*!< Maximum seeking speed - Can be negated */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_SEEKING_SPEED_FACTOR_MAX MEDIA_PROXY_SEEKING_SPEED_FACTOR_MAX +/*!< Minimum seeking speed - Can be negated */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_SEEKING_SPEED_FACTOR_MIN MEDIA_PROXY_SEEKING_SPEED_FACTOR_MIN +/*!< No seeking */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO + +/*!< A single track is played once; there is no next track. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDER_SINGLE_ONCE MEDIA_PROXY_PLAYING_ORDER_SINGLE_ONCE +/*!< A single track is played repeatedly; the next track is the current track. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDER_SINGLE_REPEAT MEDIA_PROXY_PLAYING_ORDER_SINGLE_REPEAT +/*!< The tracks within a group are played once in track order. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDER_INORDER_ONCE MEDIA_PROXY_PLAYING_ORDER_INORDER_ONCE +/*!< The tracks within a group are played in track order repeatedly. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDER_INORDER_REPEAT MEDIA_PROXY_PLAYING_ORDER_INORDER_REPEAT +/*!< The tracks within a group are played once only from the oldest first. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDER_OLDEST_ONCE MEDIA_PROXY_PLAYING_ORDER_OLDEST_ONCE +/*!< The tracks within a group are played from the oldest first repeatedly. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDER_OLDEST_REPEAT MEDIA_PROXY_PLAYING_ORDER_OLDEST_REPEAT +/*!< The tracks within a group are played once only from the newest first. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDER_NEWEST_ONCE MEDIA_PROXY_PLAYING_ORDER_NEWEST_ONCE +/*!< The tracks within a group are played from the newest first repeatedly. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDER_NEWEST_REPEAT MEDIA_PROXY_PLAYING_ORDER_NEWEST_REPEAT +/*!< The tracks within a group are played in random order once. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDER_SHUFFLE_ONCE MEDIA_PROXY_PLAYING_ORDER_SHUFFLE_ONCE +/*!< The tracks within a group are played in random order repeatedly. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDER_SHUFFLE_REPEAT MEDIA_PROXY_PLAYING_ORDER_SHUFFLE_REPEAT + +/*!< A single track is played once; there is no next track. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_SINGLE_ONCE MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_SINGLE_ONCE +/*!< A single track is played repeatedly; the next track is the current track. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_SINGLE_REPEAT MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_SINGLE_REPEAT +/*!< The tracks within a group are played once in track order. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_INORDER_ONCE MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_INORDER_ONCE +/*!< The tracks within a group are played in track order repeatedly. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_INORDER_REPEAT MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_INORDER_REPEAT +/*!< The tracks within a group are played once only from the oldest first. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_OLDEST_ONCE MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_OLDEST_ONCE +/*!< The tracks within a group are played from the oldest first repeatedly. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_OLDEST_REPEAT MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_OLDEST_REPEAT +/*!< The tracks within a group are played once only from the newest first. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_NEWEST_ONCE MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_NEWEST_ONCE +/*!< The tracks within a group are played from the newest first repeatedly. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_NEWEST_REPEAT MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_NEWEST_REPEAT +/*!< The tracks within a group are played in random order once. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_SHUFFLE_ONCE MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_SHUFFLE_ONCE +/*!< The tracks within a group are played in random order repeatedly. */ +#define ESP_BLE_AUDIO_MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_SHUFFLE_REPEAT MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_SHUFFLE_REPEAT + +/** Media player command */ +typedef struct mpl_cmd esp_ble_audio_mpl_cmd_t; + +/** Media command notification */ +typedef struct mpl_cmd_ntf esp_ble_audio_mpl_cmd_ntf_t; + +/** Search control item */ +typedef struct mpl_sci esp_ble_audio_mpl_sci_t; + +/** Search */ +typedef struct mpl_search esp_ble_audio_mpl_search_t; + +/** Media player instance */ +typedef struct media_player esp_ble_audio_media_player_t; + +/** Callbacks to a controller, from the media proxy */ +typedef struct media_proxy_ctrl_cbs esp_ble_audio_media_proxy_ctrl_cbs_t; + +/** Available calls in a player, that the media proxy can call */ +typedef struct media_proxy_pl_calls esp_ble_audio_media_proxy_pl_calls_t; + +/** + * @brief Register a controller with the media_proxy. + * + * @param ctrl_cbs Callbacks to the controller. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_media_proxy_ctrl_register(esp_ble_audio_media_proxy_ctrl_cbs_t *ctrl_cbs); + +/** + * @brief Discover a remote media player. + * + * Discover a remote media player instance. + * The remote player instance will be discovered, and accessed, using Bluetooth, + * via the media control client and a remote media control service. + * This call will start a GATT discovery of the Media Control Service on the peer, + * and setup handles and subscriptions. + * + * This shall be called once before any other actions can be executed for the + * remote player. The remote player instance will be returned in the + * discover_player() callback. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_media_proxy_ctrl_discover_player(uint16_t conn_handle); + +/** + * @brief Read Media Player Name. + * + * @param player Media player instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_media_proxy_ctrl_get_player_name(esp_ble_audio_media_player_t *player); + +/** + * @brief Read Icon Object ID. + * + * Get an ID (48 bit) that can be used to retrieve the Icon + * Object from an Object Transfer Service. + * + * See the Media Control Service spec v1.0 sections 3.2 and + * 4.1 for a description of the Icon Object. + * + * Requires Object Transfer Service + * + * @param player Media player instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_media_proxy_ctrl_get_icon_id(esp_ble_audio_media_player_t *player); + +/** + * @brief Read Icon URL. + * + * Get a URL to the media player's icon. + * + * @param player Media player instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_media_proxy_ctrl_get_icon_url(esp_ble_audio_media_player_t *player); + +/** + * @brief Read Track Title. + * + * @param player Media player instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_media_proxy_ctrl_get_track_title(esp_ble_audio_media_player_t *player); + +/** + * @brief Read Track Duration. + * + * The duration of a track is measured in hundredths of a second. + * + * @param player Media player instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_media_proxy_ctrl_get_track_duration(esp_ble_audio_media_player_t *player); + +/** + * @brief Read Track Position. + * + * The position of the player (the playing position) is measured + * in hundredths of a second from the beginning of the track. + * + * @param player Media player instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_media_proxy_ctrl_get_track_position(esp_ble_audio_media_player_t *player); + +/** + * @brief Set Track Position. + * + * Set the playing position of the media player in the current + * track. The position is given in hundredths of a second, + * from the beginning of the track of the track for positive + * values, and (backwards) from the end of the track for + * negative values. + * + * @param player Media player instance pointer. + * @param position The track position to set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_media_proxy_ctrl_set_track_position(esp_ble_audio_media_player_t *player, + int32_t position); + +/** + * @brief Get Playback Speed. + * + * The playback speed parameter is related to the actual + * playback speed as follows: + * actual playback speed = 2^(speed_parameter/64) + * + * A speed parameter of 0 corresponds to unity speed playback + * (i.e. playback at "normal" speed). A speed parameter of + * -128 corresponds to playback at one fourth of normal speed, + * 127 corresponds to playback at almost four times the normal + * speed. + * + * @param player Media player instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_media_proxy_ctrl_get_playback_speed(esp_ble_audio_media_player_t *player); + +/** + * @brief Set Playback Speed. + * + * See the get_playback_speed() function for an explanation of + * the playback speed parameter. + * + * Note that the media player may not support all possible + * values of the playback speed parameter. If the value given + * is not supported, and is higher than the current value, the + * player should set the playback speed to the next higher + * supported value. (And correspondingly to the next lower + * supported value for given values lower than the current + * value.) + * + * @param player Media player instance pointer. + * @param speed The playback speed parameter to set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_media_proxy_ctrl_set_playback_speed(esp_ble_audio_media_player_t *player, + int8_t speed); + +/** + * @brief Get Seeking Speed. + * + * The seeking speed gives the speed with which the player is + * seeking. It is a factor, relative to real-time playback + * speed - a factor four means seeking happens at four times + * the real-time playback speed. Positive values are for + * forward seeking, negative values for backwards seeking. + * + * The seeking speed is not settable - a non-zero seeking speed + * is the result of "fast rewind" of "fast forward" commands. + * + * @param player Media player instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_media_proxy_ctrl_get_seeking_speed(esp_ble_audio_media_player_t *player); + +/** + * @brief Read Current Track Segments Object ID. + * + * Get an ID (48 bit) that can be used to retrieve the Current + * Track Segments Object from an Object Transfer Service. + * + * See the Media Control Service spec v1.0 sections 3.10 and + * 4.2 for a description of the Track Segments Object. + * + * Requires Object Transfer Service. + * + * @param player Media player instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_media_proxy_ctrl_get_track_segments_id(esp_ble_audio_media_player_t *player); + +/** + * @brief Read Current Track Object ID. + * + * Get an ID (48 bit) that can be used to retrieve the Current + * Track Object from an Object Transfer Service. + * + * See the Media Control Service spec v1.0 sections 3.11 and + * 4.3 for a description of the Current Track Object. + * + * Requires Object Transfer Service. + * + * @param player Media player instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_media_proxy_ctrl_get_current_track_id(esp_ble_audio_media_player_t *player); + +/** + * @brief Set Current Track Object ID. + * + * Change the player's current track to the track given by the ID. + * (Behaves similarly to the goto track command.) + * + * Requires Object Transfer Service. + * + * @param player Media player instance pointer. + * @param id The ID of a track object. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_media_proxy_ctrl_set_current_track_id(esp_ble_audio_media_player_t *player, + uint64_t id); + +/** + * @brief Read Next Track Object ID. + * + * Get an ID (48 bit) that can be used to retrieve the Next + * Track Object from an Object Transfer Service. + * + * Requires Object Transfer Service. + * + * @param player Media player instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_media_proxy_ctrl_get_next_track_id(esp_ble_audio_media_player_t *player); + +/** + * @brief Set Next Track Object ID. + * + * Change the player's next track to the track given by the ID. + * + * Requires Object Transfer Service. + * + * @param player Media player instance pointer. + * @param id The ID of a track object. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_media_proxy_ctrl_set_next_track_id(esp_ble_audio_media_player_t *player, + uint64_t id); + +/** + * @brief Read Parent Group Object ID. + * + * Get an ID (48 bit) that can be used to retrieve the Parent + * Track Object from an Object Transfer Service. + * + * The parent group is the parent of the current group. + * + * See the Media Control Service spec v1.0 sections 3.14 and + * 4.4 for a description of the Current Track Object. + * + * Requires Object Transfer Service. + * + * @param player Media player instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_media_proxy_ctrl_get_parent_group_id(esp_ble_audio_media_player_t *player); + +/** + * @brief Read Current Group Object ID. + * + * Get an ID (48 bit) that can be used to retrieve the Current + * Track Object from an Object Transfer Service + * + * See the Media Control Service spec v1.0 sections 3.14 and + * 4.4 for a description of the Current Group Object. + * + * Requires Object Transfer Service. + * + * @param player Media player instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_media_proxy_ctrl_get_current_group_id(esp_ble_audio_media_player_t *player); + +/** + * @brief Set Current Group Object ID. + * + * Change the player's current group to the group given by the + * ID, and the current track to the first track in that group. + * + * Requires Object Transfer Service. + * + * @param player Media player instance pointer. + * @param id The ID of a group object. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_media_proxy_ctrl_set_current_group_id(esp_ble_audio_media_player_t *player, + uint64_t id); + +/** + * @brief Read Playing Order. + * + * @param player Media player instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_media_proxy_ctrl_get_playing_order(esp_ble_audio_media_player_t *player); + +/** + * @brief Set Playing Order. + * + * Set the media player's playing order. + * + * @param player Media player instance pointer. + * @param order The playing order to set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_media_proxy_ctrl_set_playing_order(esp_ble_audio_media_player_t *player, + uint8_t order); + +/** + * @brief Read Playing Orders Supported. + * + * Read a bitmap containing the media player's supported playing orders. + * + * @param player Media player instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_media_proxy_ctrl_get_playing_orders_supported(esp_ble_audio_media_player_t *player); + +/** + * @brief Read Media State. + * + * Read the media player's state. + * + * @param player Media player instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_media_proxy_ctrl_get_media_state(esp_ble_audio_media_player_t *player); + +/** + * @brief Send Command. + * + * Send a command to the media player. + * Commands may cause the media player to change its state. + * May result in two callbacks - one for the actual sending of the command + * to the player, one for the result of the command from the player. + * + * @param player Media player instance pointer. + * @param command The command to send. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_media_proxy_ctrl_send_command(esp_ble_audio_media_player_t *player, + const esp_ble_audio_mpl_cmd_t *command); + +/** + * @brief Read Commands Supported. + * + * Read a bitmap containing the media player's supported command opcodes. + * + * @param player Media player instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_media_proxy_ctrl_get_commands_supported(esp_ble_audio_media_player_t *player); + +/** + * @brief Set Search. + * + * Write a search to the media player. + * If the search is successful, the search results will be available as + * a group object in the Object Transfer Service (OTS). + * + * May result in up to three callbacks: + * - one for the actual sending of the search to the player; + * - one for the result code for the search from the player; + * - if the search is successful, one for the search results object ID + * in the OTs. + * + * Requires Object Transfer Service. + * + * @param player Media player instance pointer. + * @param search The search to write. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_media_proxy_ctrl_send_search(esp_ble_audio_media_player_t *player, + const esp_ble_audio_mpl_search_t *search); + +/** + * @brief Read Search Results Object ID. + * + * Get an ID (48 bit) that can be used to retrieve the Search + * Results Object from an Object Transfer Service. + * + * The search results object is a group object. + * The search results object only exists if a successful + * search operation has been done. + * + * Requires Object Transfer Service. + * + * @param player Media player instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_media_proxy_ctrl_get_search_results_id(esp_ble_audio_media_player_t *player); + +/** + * @brief Read Content Control ID. + * + * The content control ID identifies a content control service + * on a device, and links it to the corresponding audio stream. + * + * @param player Media player instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_media_proxy_ctrl_get_content_ctrl_id(esp_ble_audio_media_player_t *player); + +/** + * @brief Register a player with the media proxy. + * + * Register a player with the media proxy module, for use by media + * controllers. + * + * The media proxy may call any non-NULL function pointers in the + * supplied media_proxy_pl_calls structure. + * + * @param pl_calls Function pointers to the media player's calls. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_media_proxy_pl_register(esp_ble_audio_media_proxy_pl_calls_t *pl_calls); + +/** + * @brief Initialize player. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_media_proxy_pl_init(void); + +/** + * @brief Get the pointer of the Object Transfer Service used by the Media Control Service. + * + * @return Pointer to an OTS instance if found else NULL. + */ +struct bt_ots *esp_ble_audio_mcs_get_ots(void); + +#ifdef __cplusplus +} +#endif + +#endif /* ESP_BLE_AUDIO_MEDIA_PROXY_API_H_ */ diff --git a/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_micp_api.h b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_micp_api.h new file mode 100644 index 0000000000..397ef872ea --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_micp_api.h @@ -0,0 +1,184 @@ +/* + * SPDX-FileCopyrightText: 2020-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ESP_BLE_AUDIO_MICP_API_H_ +#define ESP_BLE_AUDIO_MICP_API_H_ + +#include +#include +#include + +#include "sdkconfig.h" +#include "esp_err.h" + +#include + +#include "common/init.h" +#include "common/host.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*!< The microphone state is unmuted */ +#define ESP_BLE_AUDIO_MICP_MUTE_UNMUTED BT_MICP_MUTE_UNMUTED +/*!< The microphone state is muted */ +#define ESP_BLE_AUDIO_MICP_MUTE_MUTED BT_MICP_MUTE_MUTED +/*!< The microphone state is disabled and cannot be muted or unmuted */ +#define ESP_BLE_AUDIO_MICP_MUTE_DISABLED BT_MICP_MUTE_DISABLED + +/** Microphone Controller instance */ +typedef struct bt_micp_mic_ctlr esp_ble_audio_micp_mic_ctlr_t; + +/** Struct to hold the Microphone Controller callbacks */ +typedef struct bt_micp_mic_ctlr_cb esp_ble_audio_micp_mic_ctlr_cb_t; + +/** Struct to hold the Microphone Device callbacks */ +typedef struct bt_micp_mic_dev_cb esp_ble_audio_micp_mic_dev_cb_t; + +/** Register parameters structure for Microphone Control Service */ +typedef struct bt_micp_mic_dev_register_param esp_ble_audio_micp_mic_dev_register_param_t; + +/** Microphone Control Profile included services */ +typedef struct bt_micp_included esp_ble_audio_micp_included_t; + +/** + * @brief Initialize the Microphone Control Profile Microphone Device. + * + * This will enable the Microphone Control Service instance and make it + * discoverable by Microphone Controllers. + * + * @param param Pointer to an initialization structure. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_micp_mic_dev_register(esp_ble_audio_micp_mic_dev_register_param_t *param); + +/** + * @brief Get Microphone Device included services. + * + * Returns a pointer to a struct that contains information about the + * Microphone Device included Audio Input Control Service instances. + * + * @param included Pointer to store the result in. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_micp_mic_dev_included_get(esp_ble_audio_micp_included_t *included); + +/** + * @brief Unmute the Microphone Device. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_micp_mic_dev_unmute(void); + +/** + * @brief Mute the Microphone Device. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_micp_mic_dev_mute(void); + +/** + * @brief Disable the mute functionality on the Microphone Device. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_micp_mic_dev_mute_disable(void); + +/** + * @brief Read the mute state on the Microphone Device. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_micp_mic_dev_mute_get(void); + +/** + * @brief Get Microphone Control Profile included services. + * + * Returns a pointer to a struct that contains information about the + * Microphone Control Profile included services instances, such as + * pointers to the Audio Input Control Service instances. + * + * @param mic_ctlr Microphone Controller instance pointer. + * @param included Pointer to store the result in. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_micp_mic_ctlr_included_get(esp_ble_audio_micp_mic_ctlr_t *mic_ctlr, + esp_ble_audio_micp_included_t *included); + +/** + * @brief Get the Microphone controller from a connection pointer. + * + * Only Microphone controllers that have been initiated can be retrieved. + * + * @param conn_handle Connection handle. + * + * @return Pointer to a Microphone controller instance or NULL if not found. + */ +esp_ble_audio_micp_mic_ctlr_t *esp_ble_audio_micp_mic_ctlr_get_by_conn(uint16_t conn_handle); + +/** + * @brief Discover Microphone Control Service. + * + * This will start a GATT discovery and setup handles and subscriptions. + * This shall be called once before any other actions can be executed + * for the peer device. + * + * @param conn_handle Connection handle. + * @param mic_ctlr Valid remote instance object on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_micp_mic_ctlr_discover(uint16_t conn_handle, + esp_ble_audio_micp_mic_ctlr_t **mic_ctlr); + +/** + * @brief Unmute a remote Microphone Device. + * + * @param mic_ctlr Microphone Controller instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_micp_mic_ctlr_unmute(esp_ble_audio_micp_mic_ctlr_t *mic_ctlr); + +/** + * @brief Mute a remote Microphone Device. + * + * @param mic_ctlr Microphone Controller instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_micp_mic_ctlr_mute(esp_ble_audio_micp_mic_ctlr_t *mic_ctlr); + +/** + * @brief Read the mute state of a remote Microphone Device. + * + * @param mic_ctlr Microphone Controller instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_micp_mic_ctlr_mute_get(esp_ble_audio_micp_mic_ctlr_t *mic_ctlr); + +/** + * @brief Registers the callbacks used by Microphone Controller. + * + * This can only be done as the client. + * + * @param cb The callback structure. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_micp_mic_ctlr_cb_register(esp_ble_audio_micp_mic_ctlr_cb_t *cb); + +#ifdef __cplusplus +} +#endif + +#endif /* ESP_BLE_AUDIO_MICP_API_H_ */ diff --git a/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_pacs_api.h b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_pacs_api.h new file mode 100644 index 0000000000..a5cc4123ec --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_pacs_api.h @@ -0,0 +1,153 @@ +/* + * SPDX-FileCopyrightText: 2021 Intel Corporation + * SPDX-FileCopyrightText: 2021-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ESP_BLE_AUDIO_PACS_API_H_ +#define ESP_BLE_AUDIO_PACS_API_H_ + +#include +#include +#include + +#include "sdkconfig.h" +#include "esp_err.h" + +#include + +#include "common/init.h" +#include "common/host.h" + +#include "esp_ble_audio_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Structure for registering PACS */ +typedef struct bt_pacs_register_param esp_ble_audio_pacs_register_param_t; + +/** Published Audio Capability structure. */ +typedef struct bt_pacs_cap esp_ble_audio_pacs_cap_t; + +/** + * @brief Register the Published Audio Capability Service instance. + * + * @param param PACS register parameters. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_pacs_register(const esp_ble_audio_pacs_register_param_t *param); + +/** + * @brief Unregister the Published Audio Capability Service instance. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_pacs_unregister(void); + +/** + * @brief Register Published Audio Capability. + * + * Register Audio Local Capability. + * + * @param dir Direction of the endpoint to register capability for. + * @param cap Capability structure. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_pacs_cap_register(esp_ble_audio_dir_t dir, + esp_ble_audio_pacs_cap_t *cap); + +/** + * @brief Unregister Published Audio Capability. + * + * Unregister Audio Local Capability. + * + * @param dir Direction of the endpoint to unregister capability for. + * @param cap Capability structure. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_pacs_cap_unregister(esp_ble_audio_dir_t dir, + esp_ble_audio_pacs_cap_t *cap); + +/** + * @brief Set the location for an endpoint type. + * + * @param dir Direction of the endpoints to change location for. + * @param location The location to be set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_pacs_set_location(esp_ble_audio_dir_t dir, + esp_ble_audio_location_t location); + +/** + * @brief Set the available contexts for an endpoint type. + * + * @param dir Direction of the endpoints to change available contexts for. + * @param contexts The contexts to be set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_pacs_set_available_contexts(esp_ble_audio_dir_t dir, + esp_ble_audio_context_t contexts); + +/** + * @brief Get the available contexts for an endpoint type. + * + * @param dir Direction of the endpoints to get contexts for. + * + * @return Bitmask of available contexts. + */ +esp_ble_audio_context_t esp_ble_audio_pacs_get_available_contexts(esp_ble_audio_dir_t dir); + +/** + * @brief Set the available contexts for a given connection. + * + * This function sets the available contexts value for a given connection. + * The Available Context Value is reset to default on ACL disconnection. + * + * @param conn_handle Connection handle. + * @param dir Direction of the endpoints to change available contexts for. + * @param contexts The contexts to be set or NULL to reset to default. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_pacs_conn_set_available_contexts_for_conn(uint16_t conn_handle, + esp_ble_audio_dir_t dir, + esp_ble_audio_context_t *contexts); + +/** + * @brief Get the available contexts for a given connection. + * + * This server function returns the available contexts value for a given connection. + * + * @param conn_handle Connection handle. + * @param dir Direction of the endpoints to get contexts for. + * + * @return Bitmask of available contexts. + */ +esp_ble_audio_context_t esp_ble_audio_pacs_get_available_contexts_for_conn(uint16_t conn_handle, + esp_ble_audio_dir_t dir); + +/** + * @brief Set the supported contexts for an endpoint type. + * + * @param dir Direction of the endpoints to change available contexts for. + * @param contexts The contexts to be set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_pacs_set_supported_contexts(esp_ble_audio_dir_t dir, + esp_ble_audio_context_t contexts); + +#ifdef __cplusplus +} +#endif + +#endif /* ESP_BLE_AUDIO_PACS_API_H_ */ diff --git a/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_pbp_api.h b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_pbp_api.h new file mode 100644 index 0000000000..a1a234206c --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_pbp_api.h @@ -0,0 +1,78 @@ +/* + * SPDX-FileCopyrightText: 2023 NXP + * SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ESP_BLE_AUDIO_PBP_API_H_ +#define ESP_BLE_AUDIO_PBP_API_H_ + +#include +#include +#include + +#include "sdkconfig.h" +#include "esp_err.h" + +#include + +#include "common/init.h" +#include "common/host.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Minimum size of the Public Broadcast Announcement */ +#define ESP_BLE_AUDIO_PBP_MIN_PBA_SIZE BT_PBP_MIN_PBA_SIZE + +/*!< Broadcast Streams encryption status */ +#define ESP_BLE_AUDIO_PBP_ANNOUNCEMENT_FEATURE_ENCRYPTION BT_PBP_ANNOUNCEMENT_FEATURE_ENCRYPTION +/*!< Standard Quality Public Broadcast Audio configuration */ +#define ESP_BLE_AUDIO_PBP_ANNOUNCEMENT_FEATURE_STANDARD_QUALITY BT_PBP_ANNOUNCEMENT_FEATURE_STANDARD_QUALITY +/*!< High Quality Public Broadcast Audio configuration */ +#define ESP_BLE_AUDIO_PBP_ANNOUNCEMENT_FEATURE_HIGH_QUALITY BT_PBP_ANNOUNCEMENT_FEATURE_HIGH_QUALITY +/** Public Broadcast Announcement features */ +typedef enum bt_pbp_announcement_feature esp_ble_audio_pbp_announcement_feature_t; + +/** + * @brief Creates a Public Broadcast Announcement based on the information received + * in the features parameter. + * + * @param meta Metadata to be included in the advertising data. + * @param meta_len Size of the metadata fields to be included in the advertising data. + * @param features Public Broadcast Announcement features. + * @param pba_data_buf Pointer to store the PBA advertising data. Buffer size needs to be + * meta_len + ESP_BLE_AUDIO_PBP_MIN_PBA_SIZE. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_pbp_get_announcement(const uint8_t meta[], size_t meta_len, + esp_ble_audio_pbp_announcement_feature_t features, + struct net_buf_simple *pba_data_buf); + +/** + * @brief Parses the received advertising data corresponding to a Public Broadcast + * Announcement. + * Returns the advertised Public Broadcast Announcement features and metadata. + * + * @param data_type Type of advertising data to be checked. + * @param data Pointer of advertising data to be checked. + * @param data_len Length of advertising data to be checked. + * @param features Pointer to public broadcast source features to store the parsed features in. + * @param meta Pointer to the metadata present in the advertising data. + * @param meta_len Size of the metadata fields to be included in the advertising data. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_pbp_parse_announcement(uint8_t data_type, const uint8_t *data, uint8_t data_len, + esp_ble_audio_pbp_announcement_feature_t *features, + uint8_t **meta, uint8_t *meta_len); + +#ifdef __cplusplus +} +#endif + +#endif /* ESP_BLE_AUDIO_PBP_API_H_ */ diff --git a/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_tbs_api.h b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_tbs_api.h new file mode 100644 index 0000000000..0248eb4cf2 --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_tbs_api.h @@ -0,0 +1,635 @@ +/* + * SPDX-FileCopyrightText: 2020 Bose Corporation + * SPDX-FileCopyrightText: 2021 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ESP_BLE_AUDIO_TBS_API_H_ +#define ESP_BLE_AUDIO_TBS_API_H_ + +#include +#include +#include + +#include "sdkconfig.h" +#include "esp_err.h" + +#include + +#include "common/init.h" +#include "common/host.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * The GTBS index denotes whenever a callback is from a Generic Telephone + * Bearer Service (GTBS) instance, or whenever the client should perform + * on action on the GTBS instance of the server, rather than any of the + * specific Telephone Bearer Service instances. + */ +#define ESP_BLE_AUDIO_TBS_GTBS_INDEX BT_TBS_GTBS_INDEX + +/*!< A remote party is calling (incoming call). */ +#define ESP_BLE_AUDIO_TBS_CALL_STATE_INCOMING BT_TBS_CALL_STATE_INCOMING +/** + * The process to call the remote party has started on the server, but the + * remote party is not being alerted (outgoing call). + */ +#define ESP_BLE_AUDIO_TBS_CALL_STATE_DIALING BT_TBS_CALL_STATE_DIALING +/*!< A remote party is being alerted (outgoing call). */ +#define ESP_BLE_AUDIO_TBS_CALL_STATE_ALERTING BT_TBS_CALL_STATE_ALERTING +/*!< The call is in an active conversation. */ +#define ESP_BLE_AUDIO_TBS_CALL_STATE_ACTIVE BT_TBS_CALL_STATE_ACTIVE +/** + * The call is connected but held locally. Locally Held implies that either + * the server or the client can affect the state. + */ +#define ESP_BLE_AUDIO_TBS_CALL_STATE_LOCALLY_HELD BT_TBS_CALL_STATE_LOCALLY_HELD +/** + * The call is connected but held remotely. Remotely Held means that the state + * is controlled by the remote party of a call. + */ +#define ESP_BLE_AUDIO_TBS_CALL_STATE_REMOTELY_HELD BT_TBS_CALL_STATE_REMOTELY_HELD +/*!< The call is connected but held both locally and remotely. */ +#define ESP_BLE_AUDIO_TBS_CALL_STATE_LOCALLY_AND_REMOTELY_HELD BT_TBS_CALL_STATE_LOCALLY_AND_REMOTELY_HELD + +/*!< The URI value used to originate a call was formed improperly. */ +#define ESP_BLE_AUDIO_TBS_REASON_BAD_REMOTE_URI BT_TBS_REASON_BAD_REMOTE_URI +/*!< The call failed. */ +#define ESP_BLE_AUDIO_TBS_REASON_CALL_FAILED BT_TBS_REASON_CALL_FAILED +/*!< The remote party ended the call. */ +#define ESP_BLE_AUDIO_TBS_REASON_REMOTE_ENDED_CALL BT_TBS_REASON_REMOTE_ENDED_CALL +/*!< The call ended from the server. */ +#define ESP_BLE_AUDIO_TBS_REASON_SERVER_ENDED_CALL BT_TBS_REASON_SERVER_ENDED_CALL +/*!< The line was busy. */ +#define ESP_BLE_AUDIO_TBS_REASON_LINE_BUSY BT_TBS_REASON_LINE_BUSY +/*!< Network congestion. */ +#define ESP_BLE_AUDIO_TBS_REASON_NETWORK_CONGESTED BT_TBS_REASON_NETWORK_CONGESTED +/*!< The client terminated the call. */ +#define ESP_BLE_AUDIO_TBS_REASON_CLIENT_TERMINATED BT_TBS_REASON_CLIENT_TERMINATED +/*!< No service. */ +#define ESP_BLE_AUDIO_TBS_REASON_NO_SERVICE BT_TBS_REASON_NO_SERVICE +/*!< No answer. */ +#define ESP_BLE_AUDIO_TBS_REASON_NO_ANSWER BT_TBS_REASON_NO_ANSWER +/*!< Unspecified. */ +#define ESP_BLE_AUDIO_TBS_REASON_UNSPECIFIED BT_TBS_REASON_UNSPECIFIED + +/*!< The opcode write was successful. */ +#define ESP_BLE_AUDIO_TBS_RESULT_CODE_SUCCESS BT_TBS_RESULT_CODE_SUCCESS +/*!< An invalid opcode was used for the Call Control Point write. */ +#define ESP_BLE_AUDIO_TBS_RESULT_CODE_OPCODE_NOT_SUPPORTED BT_TBS_RESULT_CODE_OPCODE_NOT_SUPPORTED +/*!< The requested operation cannot be completed. */ +#define ESP_BLE_AUDIO_TBS_RESULT_CODE_OPERATION_NOT_POSSIBLE BT_TBS_RESULT_CODE_OPERATION_NOT_POSSIBLE +/*!< The Call Index used for the Call Control Point write is invalid. */ +#define ESP_BLE_AUDIO_TBS_RESULT_CODE_INVALID_CALL_INDEX BT_TBS_RESULT_CODE_INVALID_CALL_INDEX +/** + * The opcode written to the Call Control Point was received when the current + * Call State for the Call Index was not in the expected state. + */ +#define ESP_BLE_AUDIO_TBS_RESULT_CODE_STATE_MISMATCH BT_TBS_RESULT_CODE_STATE_MISMATCH +/*!< Lack of internal resources to complete the requested action. */ +#define ESP_BLE_AUDIO_TBS_RESULT_CODE_OUT_OF_RESOURCES BT_TBS_RESULT_CODE_OUT_OF_RESOURCES +/*!< The Outgoing URI is incorrect or invalid when an Originate opcode is sent. */ +#define ESP_BLE_AUDIO_TBS_RESULT_CODE_INVALID_URI BT_TBS_RESULT_CODE_INVALID_URI + +/*!< Local Hold and Local Retrieve Call Control Point Opcodes supported */ +#define ESP_BLE_AUDIO_TBS_FEATURE_HOLD BT_TBS_FEATURE_HOLD +/*!< Join Call Control Point Opcode supported */ +#define ESP_BLE_AUDIO_TBS_FEATURE_JOIN BT_TBS_FEATURE_JOIN +/*!< All Control Point Opcodes supported */ +#define ESP_BLE_AUDIO_TBS_FEATURE_ALL BT_TBS_FEATURE_ALL + +/*!< No service */ +#define ESP_BLE_AUDIO_TBS_SIGNAL_STRENGTH_NO_SERVICE BT_TBS_SIGNAL_STRENGTH_NO_SERVICE +/*!< Maximum signal strength */ +#define ESP_BLE_AUDIO_TBS_SIGNAL_STRENGTH_MAX BT_TBS_SIGNAL_STRENGTH_MAX +/*!< Signal strength is unknown */ +#define ESP_BLE_AUDIO_TBS_SIGNAL_STRENGTH_UNKNOWN BT_TBS_SIGNAL_STRENGTH_UNKNOWN + +/*!< 3G */ +#define ESP_BLE_AUDIO_TBS_TECHNOLOGY_3G BT_TBS_TECHNOLOGY_3G +/*!< 4G */ +#define ESP_BLE_AUDIO_TBS_TECHNOLOGY_4G BT_TBS_TECHNOLOGY_4G +/*!< Long-term evolution (LTE) */ +#define ESP_BLE_AUDIO_TBS_TECHNOLOGY_LTE BT_TBS_TECHNOLOGY_LTE +/*!< Wifi */ +#define ESP_BLE_AUDIO_TBS_TECHNOLOGY_WIFI BT_TBS_TECHNOLOGY_WIFI +/*!< 5G */ +#define ESP_BLE_AUDIO_TBS_TECHNOLOGY_5G BT_TBS_TECHNOLOGY_5G +/*!< Global System for Mobile Communications (GSM) */ +#define ESP_BLE_AUDIO_TBS_TECHNOLOGY_GSM BT_TBS_TECHNOLOGY_GSM +/*!< Code-Division Multiple Access (CDMA) */ +#define ESP_BLE_AUDIO_TBS_TECHNOLOGY_CDMA BT_TBS_TECHNOLOGY_CDMA +/*!< 2G */ +#define ESP_BLE_AUDIO_TBS_TECHNOLOGY_2G BT_TBS_TECHNOLOGY_2G +/*!< Wideband Code-Division Multiple Access (WCDMA) */ +#define ESP_BLE_AUDIO_TBS_TECHNOLOGY_WCDMA BT_TBS_TECHNOLOGY_WCDMA + +/*!< Inband ringtone enabled */ +#define ESP_BLE_AUDIO_TBS_STATUS_FLAG_INBAND_RINGTONE BT_TBS_STATUS_FLAG_INBAND_RINGTONE +/*!< Server is in silent mod */ +#define ESP_BLE_AUDIO_TBS_STATUS_FLAG_SILENT_MOD BT_TBS_STATUS_FLAG_SILENT_MOD + +/*!< If set, call is outgoing else incoming */ +#define ESP_BLE_AUDIO_TBS_CALL_FLAG_OUTGOING BT_TBS_CALL_FLAG_OUTGOING +/*!< If set call is withheld, else not withheld */ +#define ESP_BLE_AUDIO_TBS_CALL_FLAG_WITHHELD BT_TBS_CALL_FLAG_WITHHELD +/*!< If set call is withheld by network, else provided by network */ +#define ESP_BLE_AUDIO_TBS_CALL_FLAG_WITHHELD_BY_NETWORK BT_TBS_CALL_FLAG_WITHHELD_BY_NETWORK + +/** Struct to hold the Telephone Bearer Service callbacks */ +typedef struct bt_tbs_cb esp_ble_audio_tbs_cb_t; + +/** Telephone Bearer Service instance */ +typedef struct bt_tbs_instance esp_ble_audio_tbs_instance_t; + +/** Struct to hold the parameters to initialize the bearer */ +typedef struct bt_tbs_register_param esp_ble_audio_tbs_register_param_t; + +/** Struct to hold the Telephone Bearer Service client callbacks */ +typedef struct bt_tbs_client_cb esp_ble_audio_tbs_client_cb_t; + +/** Struct to hold a call as the Telephone Bearer Service client */ +typedef struct bt_tbs_client_call esp_ble_audio_tbs_client_call_t; + +/** Struct to hold a call state */ +typedef struct bt_tbs_client_call_state esp_ble_audio_tbs_client_call_state_t; + +/** + * @brief Accept an alerting call. + * + * @param call_index The index of the call that will be accepted. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_accept(uint8_t call_index); + +/** + * @brief Hold a call. + * + * @param call_index The index of the call that will be held. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_hold(uint8_t call_index); + +/** + * @brief Retrieve a call. + * + * @param call_index The index of the call that will be retrieved. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_retrieve(uint8_t call_index); + +/** + * @brief Terminate a call. + * + * @param call_index The index of the call that will be terminated. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_terminate(uint8_t call_index); + +/** + * @brief Originate a call. + * + * @param bearer_index The index of the Telephone Bearer. + * @param uri The remote URI. + * @param call_index Pointer to a value where the new call_index will be stored. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_originate(uint8_t bearer_index, + char *uri, + uint8_t *call_index); + +/** + * @brief Join calls. + * + * @param call_index_cnt The number of call indexes to join. + * @param call_indexes Array of call indexes to join. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_join(uint8_t call_index_cnt, uint8_t *call_indexes); + +/** + * @brief Notify the server that the remote party answered the call. + * + * @param call_index The index of the call that was answered. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_remote_answer(uint8_t call_index); + +/** + * @brief Notify the server that the remote party held the call. + * + * @param call_index The index of the call that was held. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_remote_hold(uint8_t call_index); + +/** + * @brief Notify the server that the remote party retrieved the call. + * + * @param call_index The index of the call that was retrieved. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_remote_retrieve(uint8_t call_index); + +/** + * @brief Notify the server that the remote party terminated the call. + * + * @param call_index The index of the call that was terminated. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_remote_terminate(uint8_t call_index); + +/** + * @brief Notify the server of an incoming call. + * + * @param bearer_index The index of the Telephone Bearer. + * @param to The URI that is receiving the call. + * @param from The URI of the remote caller. + * @param friendly_name The friendly name of the remote caller. + * @param call_index The call index on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_remote_incoming(uint8_t bearer_index, + const char *to, + const char *from, + const char *friendly_name, + uint8_t *call_index); + +/** + * @brief Set a new bearer provider. + * + * @param bearer_index The index of the Telephone Bearer or + * ESP_BLE_AUDIO_TBS_GTBS_INDEX for GTBS. + * @param name The new bearer provider name. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_set_bearer_provider_name(uint8_t bearer_index, const char *name); + +/** + * @brief Set a new bearer technology. + * + * @param bearer_index The index of the Telephone Bearer or + * ESP_BLE_AUDIO_TBS_GTBS_INDEX for GTBS. + * @param new_technology The new bearer technology. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_set_bearer_technology(uint8_t bearer_index, uint8_t new_technology); + +/** + * @brief Update the signal strength reported by the server. + * + * @param bearer_index The index of the Telephone Bearer or + * ESP_BLE_AUDIO_TBS_GTBS_INDEX for GTBS. + * @param new_signal_strength The new signal strength. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_set_signal_strength(uint8_t bearer_index, uint8_t new_signal_strength); + +/** + * @brief Sets the feature and status value. + * + * @param bearer_index The index of the Telephone Bearer or + * ESP_BLE_AUDIO_TBS_GTBS_INDEX for GTBS. + * @param status_flags The new feature and status value. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_set_status_flags(uint8_t bearer_index, uint16_t status_flags); + +/** + * @brief Sets the URI scheme list of a bearer. + * + * @param bearer_index The index of the Telephone Bearer. + * @param uri_list List of URI prefixes (e.g. {"skype", "tel"}). + * @param uri_count Number of URI prefixes in @p uri_list. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_set_uri_scheme_list(uint8_t bearer_index, + const char **uri_list, + uint8_t uri_count); + +/** + * @brief Register the callbacks for TBS. + * + * @param cbs Pointer to the callback structure. + */ +void esp_ble_audio_tbs_register_cb(esp_ble_audio_tbs_cb_t *cbs); + +/** + * @brief Register a Telephone Bearer. + * + * This will register a Telephone Bearer Service (TBS) (or a Generic Telephone + * Bearer service (GTBS)) with the provided parameters. + * + * As per the TBS specification, the GTBS shall be instantiated for the feature, + * and as such a GTBS shall always be registered before any TBS can be registered. + * + * @param param The parameters to initialize the bearer. + * @param bearer_index The registered bearer index on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_register_bearer(const esp_ble_audio_tbs_register_param_t *param, + uint8_t *bearer_index); + +/** + * @brief Unregister a Telephone Bearer. + * + * This will unregister a Telephone Bearer Service (TBS) (or a Generic Telephone + * Bearer service (GTBS)) with the provided parameters. + * + * Similarly, all TBS shall be unregistered before the GTBS can be unregistered with. + * + * @param bearer_index The index of the bearer to unregister. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_unregister_bearer(uint8_t bearer_index); + +/** + * @brief Discover TBS for a connection. This will start a GATT + * discover and setup handles and subscriptions. + * + * @param conn_handle Connection handle. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_client_discover(uint16_t conn_handle); + +/** + * @brief Set the signal strength reporting interval for a TBS instance. + * + * @param conn_handle Connection handle. + * @param inst_index The index of the TBS instance. + * @param interval The interval to write (0-255 seconds). + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_client_set_signal_strength_interval(uint16_t conn_handle, + uint8_t inst_index, + uint8_t interval); + +/** + * @brief Request to originate a call. + * + * @param conn_handle Connection handle. + * @param inst_index The index of the TBS instance. + * @param uri The URI of the callee. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_client_originate_call(uint16_t conn_handle, + uint8_t inst_index, + const char *uri); + +/** + * @brief Request to terminate a call. + * + * @param conn_handle Connection handle. + * @param inst_index The index of the TBS instance. + * @param call_index The call index to terminate. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_client_terminate_call(uint16_t conn_handle, + uint8_t inst_index, + uint8_t call_index); + +/** + * @brief Request to hold a call. + * + * @param conn_handle Connection handle. + * @param inst_index The index of the TBS instance. + * @param call_index The call index to place on hold. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_client_hold_call(uint16_t conn_handle, + uint8_t inst_index, + uint8_t call_index); + +/** + * @brief Accept an incoming call. + * + * @param conn_handle Connection handle. + * @param inst_index The index of the TBS instance. + * @param call_index The call index to accept. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_client_accept_call(uint16_t conn_handle, + uint8_t inst_index, + uint8_t call_index); + +/** + * @brief Retrieve call from (local) hold. + * + * @param conn_handle Connection handle. + * @param inst_index The index of the TBS instance. + * @param call_index The call index to retrieve. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_client_retrieve_call(uint16_t conn_handle, + uint8_t inst_index, + uint8_t call_index); + +/** + * @brief Join multiple calls. + * + * @param conn_handle Connection handle. + * @param inst_index The index of the TBS instance. + * @param call_indexes Array of call indexes. + * @param count Number of call indexes in the call_indexes array. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_client_join_calls(uint16_t conn_handle, + uint8_t inst_index, + const uint8_t *call_indexes, + uint8_t count); + +/** + * @brief Read the bearer provider name of a TBS instance. + * + * @param conn_handle Connection handle. + * @param inst_index The index of the TBS instance. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_client_read_bearer_provider_name(uint16_t conn_handle, uint8_t inst_index); + +/** + * @brief Read the UCI of a TBS instance. + * + * @param conn_handle Connection handle. + * @param inst_index The index of the TBS instance. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_client_read_bearer_uci(uint16_t conn_handle, uint8_t inst_index); + +/** + * @brief Read the technology of a TBS instance. + * + * @param conn_handle Connection handle. + * @param inst_index The index of the TBS instance. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_client_read_technology(uint16_t conn_handle, uint8_t inst_index); + +/** + * @brief Read the URI schemes list of a TBS instance. + * + * @param conn_handle Connection handle. + * @param inst_index The index of the TBS instance. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_client_read_uri_list(uint16_t conn_handle, uint8_t inst_index); + +/** + * @brief Read the current signal strength of a TBS instance. + * + * @param conn_handle Connection handle. + * @param inst_index The index of the TBS instance. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_client_read_signal_strength(uint16_t conn_handle, uint8_t inst_index); + +/** + * @brief Read the signal strength reporting interval of a TBS instance. + * + * @param conn_handle Connection handle. + * @param inst_index The index of the TBS instance. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_client_read_signal_interval(uint16_t conn_handle, uint8_t inst_index); + +/** + * @brief Read the list of current calls of a TBS instance. + * + * @param conn_handle Connection handle. + * @param inst_index The index of the TBS instance. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_client_read_current_calls(uint16_t conn_handle, uint8_t inst_index); + +/** + * @brief Read the content ID of a TBS instance. + * + * @param conn_handle Connection handle. + * @param inst_index The index of the TBS instance. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_client_read_ccid(uint16_t conn_handle, uint8_t inst_index); + +/** + * @brief Read the call target URI of a TBS instance. + * + * @param conn_handle Connection handle. + * @param inst_index The index of the TBS instance. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_client_read_call_uri(uint16_t conn_handle, uint8_t inst_index); + +/** + * @brief Read the feature and status value of a TBS instance. + * + * @param conn_handle Connection handle. + * @param inst_index The index of the TBS instance. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_client_read_status_flags(uint16_t conn_handle, uint8_t inst_index); + +/** + * @brief Read the states of the current calls of a TBS instance. + * + * @param conn_handle Connection handle. + * @param inst_index The index of the TBS instance. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_client_read_call_state(uint16_t conn_handle, uint8_t inst_index); + +/** + * @brief Read the remote URI of a TBS instance. + * + * @param conn_handle Connection handle. + * @param inst_index The index of the TBS instance. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_client_read_remote_uri(uint16_t conn_handle, uint8_t inst_index); + +/** + * @brief Read the friendly name of a call for a TBS instance. + * + * @param conn_handle Connection handle. + * @param inst_index The index of the TBS instance. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_client_read_friendly_name(uint16_t conn_handle, uint8_t inst_index); + +/** + * @brief Read the supported opcode of a TBS instance. + * + * @param conn_handle Connection handle. + * @param inst_index The index of the TBS instance. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_client_read_optional_opcodes(uint16_t conn_handle, uint8_t inst_index); + +/** + * @brief Register the callbacks for CCP. + * + * @param cbs Pointer to the callback structure. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tbs_client_register_cb(esp_ble_audio_tbs_client_cb_t *cbs); + +/** + * @brief Look up Telephone Bearer Service instance by CCID. + * + * @param conn_handle Connection handle. + * @param ccid The CCID to lookup a service instance for. + * + * @return Pointer to TBS instance if found, NULL otherwise. + */ +esp_ble_audio_tbs_instance_t *esp_ble_audio_tbs_client_get_by_ccid(uint16_t conn_handle, uint8_t ccid); + +#ifdef __cplusplus +} +#endif + +#endif /* ESP_BLE_AUDIO_TBS_API_H_ */ diff --git a/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_tmap_api.h b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_tmap_api.h new file mode 100644 index 0000000000..f90467c4a8 --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_tmap_api.h @@ -0,0 +1,79 @@ +/* + * SPDX-FileCopyrightText: 2023 NXP + * SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ESP_BLE_AUDIO_TMAP_API_H_ +#define ESP_BLE_AUDIO_TMAP_API_H_ + +#include +#include +#include + +#include "sdkconfig.h" +#include "esp_err.h" + +#include + +#include "common/init.h" +#include "common/host.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*!< TMAP Call Gateway role */ +#define ESP_BLE_AUDIO_TMAP_ROLE_CG BT_TMAP_ROLE_CG +/*!< TMAP Call Terminal role */ +#define ESP_BLE_AUDIO_TMAP_ROLE_CT BT_TMAP_ROLE_CT +/*!< TMAP Unicast Media Sender role */ +#define ESP_BLE_AUDIO_TMAP_ROLE_UMS BT_TMAP_ROLE_UMS +/*!< TMAP Unicast Media Receiver role */ +#define ESP_BLE_AUDIO_TMAP_ROLE_UMR BT_TMAP_ROLE_UMR +/*!< TMAP Broadcast Media Sender role */ +#define ESP_BLE_AUDIO_TMAP_ROLE_BMS BT_TMAP_ROLE_BMS +/*!< TMAP Broadcast Media Receiver role */ +#define ESP_BLE_AUDIO_TMAP_ROLE_BMR BT_TMAP_ROLE_BMR + +/** TMAP Role characteristic */ +typedef enum bt_tmap_role esp_ble_audio_tmap_role_t; + +/** TMAP callback structure */ +typedef struct bt_tmap_cb esp_ble_audio_tmap_cb_t; + +/** + * @brief Adds TMAS instance to database and sets the received TMAP role(s). + * + * @param role TMAP role(s) of the device (one or multiple). + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tmap_register(esp_ble_audio_tmap_role_t role); + +/** + * @brief Perform service discovery as TMAP Client. + * + * @param conn_handle Connection handle. + * @param tmap_cb Pointer to struct of TMAP callbacks. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_tmap_discover(uint16_t conn_handle, + const esp_ble_audio_tmap_cb_t *tmap_cb); + +/** + * @brief Set one or multiple TMAP roles dynamically. + * Previously registered value will be overwritten. + * + * @param role TMAP role(s). + */ +void esp_ble_audio_tmap_set_role(esp_ble_audio_tmap_role_t role); + +#ifdef __cplusplus +} +#endif + +#endif /* ESP_BLE_AUDIO_TMAP_API_H_ */ diff --git a/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_vcp_api.h b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_vcp_api.h new file mode 100644 index 0000000000..6d0c2168c9 --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_vcp_api.h @@ -0,0 +1,299 @@ +/* + * SPDX-FileCopyrightText: 2020-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ESP_BLE_AUDIO_VCP_API_H_ +#define ESP_BLE_AUDIO_VCP_API_H_ + +#include +#include +#include + +#include "sdkconfig.h" +#include "esp_err.h" + +#include + +#include "common/init.h" +#include "common/host.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*!< The volume state is unmuted */ +#define ESP_BLE_AUDIO_VCP_STATE_UNMUTED BT_VCP_STATE_UNMUTED +/*!< The volume state is muted */ +#define ESP_BLE_AUDIO_VCP_STATE_MUTED BT_VCP_STATE_MUTED + +/** Volume Control Service included services */ +typedef struct bt_vcp_included esp_ble_audio_vcp_included_t; + +/** Volume Control Service instance */ +typedef struct bt_vcp_vol_ctlr esp_ble_audio_vcp_vol_ctlr_t; + +/** Struct to hold the Volume Controller callbacks */ +typedef struct bt_vcp_vol_ctlr_cb esp_ble_audio_vcp_vol_ctlr_cb_t; + +/** Struct to hold the Volume Renderer callbacks */ +typedef struct bt_vcp_vol_rend_cb esp_ble_audio_vcp_vol_rend_cb_t; + +/** Register structure for Volume Control Service */ +typedef struct bt_vcp_vol_rend_register_param esp_ble_audio_vcp_vol_rend_register_param_t; + +/** + * @brief Get Volume Control Service included services. + * + * Returns a pointer to a struct that contains information about the + * Volume Control Service included service instances, such as pointers + * to the Volume Offset Control Service (Volume Offset Control Service) + * or Audio Input Control Service (AICS) instances. + * + * @param included Pointer to store the result in. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vcp_vol_rend_included_get(esp_ble_audio_vcp_included_t *included); + +/** + * @brief Register the Volume Control Service. + * + * This will register and enable the service and make it discoverable by + * clients. + * + * @param param Volume Control Service register parameters. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vcp_vol_rend_register(esp_ble_audio_vcp_vol_rend_register_param_t *param); + +/** + * @brief Set the Volume Control Service volume step size. + * + * This can only be done as the server. + * + * @param volume_step The volume step size (1-255). + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vcp_vol_rend_set_step(uint8_t volume_step); + +/** + * @brief Get the Volume Control Service volume state. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vcp_vol_rend_get_state(void); + +/** + * @brief Get the Volume Control Service flags. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vcp_vol_rend_get_flags(void); + +/** + * @brief Turn the volume down by one step on the server. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vcp_vol_rend_vol_down(void); + +/** + * @brief Turn the volume up by one step on the server. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vcp_vol_rend_vol_up(void); + +/** + * @brief Turn the volume down and unmute the server. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vcp_vol_rend_unmute_vol_down(void); + +/** + * @brief Turn the volume up and unmute the server. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vcp_vol_rend_unmute_vol_up(void); + +/** + * @brief Set the volume on the server. + * + * @param volume The absolute volume to set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vcp_vol_rend_set_vol(uint8_t volume); + +/** + * @brief Unmute the server. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vcp_vol_rend_unmute(void); + +/** + * @brief Mute the server. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vcp_vol_rend_mute(void); + +/** + * @brief Registers the callbacks used by the Volume Controller. + * + * @param cb The callback structure. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vcp_vol_ctlr_cb_register(esp_ble_audio_vcp_vol_ctlr_cb_t *cb); + +/** + * @brief Unregisters the callbacks used by the Volume Controller. + * + * @param cb The callback structure. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vcp_vol_ctlr_cb_unregister(esp_ble_audio_vcp_vol_ctlr_cb_t *cb); + +/** + * @brief Discover Volume Control Service and included services. + * + * This will start a GATT discovery and setup handles and subscriptions. + * This shall be called once before any other actions can be executed + * for the peer device. + * + * This shall only be done as the client, + * + * @param conn_handle Connection handle. + * @param vol_ctlr Valid remote instance object on success. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vcp_vol_ctlr_discover(uint16_t conn_handle, + esp_ble_audio_vcp_vol_ctlr_t **vol_ctlr); + +/** + * @brief Get the volume controller from a connection pointer + * + * Get the Volume Control Profile Volume Controller pointer from a connection. + * Only volume controllers that have been initiated can be retrieved. + * + * @param conn_handle Connection handle. + * + * @return Pointer to a Volume Control Profile Volume Controller instance. + * NULL if the connection has not been found has not done discovery yet. + */ +esp_ble_audio_vcp_vol_ctlr_t *esp_ble_audio_vcp_vol_ctlr_get_by_conn(uint16_t conn_handle); + +/** + * @brief Get Volume Control Service included services. + * + * Returns a pointer to a struct that contains information about the + * Volume Control Service included service instances, such as pointers + * to the Volume Offset Control Service (Volume Offset Control Service) + * or Audio Input Control Service (AICS) instances. + * + * @param vol_ctlr Volume Controller instance pointer. + * @param included Pointer to store the result in. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vcp_vol_ctlr_included_get(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr, + esp_ble_audio_vcp_included_t *included); + +/** + * @brief Read the volume state of a remote Volume Renderer. + * + * @param vol_ctlr Volume Controller instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vcp_vol_ctlr_read_state(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr); + +/** + * @brief Read the volume flags of a remote Volume Renderer. + * + * @param vol_ctlr Volume Controller instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vcp_vol_ctlr_read_flags(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr); + +/** + * @brief Turn the volume down one step on a remote Volume Renderer. + * + * @param vol_ctlr Volume Controller instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vcp_vol_ctlr_vol_down(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr); + +/** + * @brief Turn the volume up one step on a remote Volume Renderer. + * + * @param vol_ctlr Volume Controller instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vcp_vol_ctlr_vol_up(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr); + +/** + * @brief Turn the volume down one step and unmute on a remote Volume Renderer. + * + * @param vol_ctlr Volume Controller instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vcp_vol_ctlr_unmute_vol_down(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr); + +/** + * @brief Turn the volume up one step and unmute on a remote Volume Renderer. + * + * @param vol_ctlr Volume Controller instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vcp_vol_ctlr_unmute_vol_up(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr); + +/** + * @brief Set the absolute volume on a remote Volume Renderer. + * + * @param vol_ctlr Volume Controller instance pointer. + * @param volume The absolute volume to set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vcp_vol_ctlr_set_vol(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr, uint8_t volume); + +/** + * @brief Unmute a remote Volume Renderer. + * + * @param vol_ctlr Volume Controller instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vcp_vol_ctlr_unmute(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr); + +/** + * @brief Mute a remote Volume Renderer. + * + * @param vol_ctlr Volume Controller instance pointer. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vcp_vol_ctlr_mute(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr); + +#ifdef __cplusplus +} +#endif + +#endif /* ESP_BLE_AUDIO_VCP_API_H_ */ diff --git a/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_vocs_api.h b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_vocs_api.h new file mode 100644 index 0000000000..a6c248f202 --- /dev/null +++ b/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_vocs_api.h @@ -0,0 +1,168 @@ +/* + * SPDX-FileCopyrightText: 2020-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ESP_BLE_AUDIO_VOCS_API_H_ +#define ESP_BLE_AUDIO_VOCS_API_H_ + +#include +#include +#include + +#include "sdkconfig.h" +#include "esp_err.h" + +#include + +#include "common/init.h" +#include "common/host.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*!< Minimum offset value */ +#define ESP_BLE_AUDIO_VOCS_MIN_OFFSET BT_VOCS_MIN_OFFSET +/*!< Maximum offset value */ +#define ESP_BLE_AUDIO_VOCS_MAX_OFFSET BT_VOCS_MAX_OFFSET + +/** Volume Offset Control Service instance */ +typedef struct bt_vocs esp_ble_audio_vocs_t; + +/** Struct to hold the Volume Offset Control Service callbacks */ +typedef struct bt_vocs_cb esp_ble_audio_vocs_cb_t; + +/** Structure for registering a Volume Offset Control Service instance */ +typedef struct bt_vocs_register_param esp_ble_audio_vocs_register_param_t; + +/** Structure for discovering a Volume Offset Control Service instance */ +typedef struct bt_vocs_discover_param esp_ble_audio_vocs_discover_param_t; + +/** + * @brief Get a free service instance of Volume Offset Control Service from the pool. + * + * @return Volume Offset Control Service instance in case of success or NULL in case of error. + */ +esp_ble_audio_vocs_t *esp_ble_audio_vocs_free_instance_get(void); + +/** + * @brief Get the service declaration attribute. + * + * The first service attribute returned can be included in any other GATT service. + * + * @param vocs Volume Offset Control Service instance. + * + * @return Pointer to the attributes of the service. + */ +void *esp_ble_audio_vocs_svc_decl_get(esp_ble_audio_vocs_t *vocs); + +/** + * @brief Register the Volume Offset Control Service instance. + * + * @param vocs Volume Offset Control Service instance. + * @param param Volume Offset Control Service register parameters. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vocs_register(esp_ble_audio_vocs_t *vocs, + const esp_ble_audio_vocs_register_param_t *param); + +/** + * @brief Read the Volume Offset Control Service offset state. + * + * @param inst Pointer to the Volume Offset Control Service instance. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vocs_state_get(esp_ble_audio_vocs_t *inst); + +/** + * @brief Set the Volume Offset Control Service offset state. + * + * @param inst Pointer to the Volume Offset Control Service instance. + * @param offset The offset to set (-255 to 255). + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vocs_state_set(esp_ble_audio_vocs_t *inst, int16_t offset); + +/** + * @brief Read the Volume Offset Control Service location. + * + * @param inst Pointer to the Volume Offset Control Service instance. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vocs_location_get(esp_ble_audio_vocs_t *inst); + +/** + * @brief Set the Volume Offset Control Service location. + * + * @param inst Pointer to the Volume Offset Control Service instance. + * @param location The location to set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vocs_location_set(esp_ble_audio_vocs_t *inst, uint32_t location); + +/** + * @brief Read the Volume Offset Control Service output description. + * + * @param inst Pointer to the Volume Offset Control Service instance. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vocs_description_get(esp_ble_audio_vocs_t *inst); + +/** + * @brief Set the Volume Offset Control Service description. + * + * @param inst Pointer to the Volume Offset Control Service instance. + * @param description The UTF-8 encoded string description to set. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vocs_description_set(esp_ble_audio_vocs_t *inst, + const char *description); + +/** + * @brief Registers the callbacks for the Volume Offset Control Service client. + * + * @param inst Pointer to the Volume Offset Control Service client instance. + * @param cb Pointer to the callback structure. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vocs_client_cb_register(esp_ble_audio_vocs_t *inst, + esp_ble_audio_vocs_cb_t *cb); + +/** + * @brief Returns a pointer to a Volume Offset Control Service client instance. + * + * @return Pointer to the instance, or NULL if no free instances are left. + */ +esp_ble_audio_vocs_t *esp_ble_audio_vocs_client_free_instance_get(void); + +/** + * @brief Discover a Volume Offset Control Service. + * + * Attempts to discover a Volume Offset Control Service on a server given the @p param. + * + * @param conn_handle Connection handle. + * @param inst Pointer to the Volume Offset Control Service client instance. + * @param param Pointer to the parameters. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_audio_vocs_discover(uint16_t conn_handle, + esp_ble_audio_vocs_t *inst, + const esp_ble_audio_vocs_discover_param_t *param); + +#ifdef __cplusplus +} +#endif + +#endif /* ESP_BLE_AUDIO_VOCS_API_H_ */ diff --git a/components/bt/esp_ble_audio/api/iso/esp_ble_iso_common_api.c b/components/bt/esp_ble_audio/api/iso/esp_ble_iso_common_api.c new file mode 100644 index 0000000000..62e7f6f6a6 --- /dev/null +++ b/components/bt/esp_ble_audio/api/iso/esp_ble_iso_common_api.c @@ -0,0 +1,432 @@ +/* + * SPDX-FileCopyrightText: 2020 Intel Corporation + * SPDX-FileCopyrightText: 2021-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_ble_iso_common_api.h" + +esp_err_t esp_ble_iso_data_parse(const uint8_t ltv[], size_t size, + bool (*func)(uint8_t type, + const uint8_t *data, + uint8_t data_len, + void *user_data), + void *user_data) +{ + if (ltv == NULL || func == NULL) { + return ESP_ERR_INVALID_ARG; + } + + for (size_t i = 0; i < size;) { + const size_t remaining = size - i; + const uint8_t len = ltv[i]; + uint8_t data_len; + uint8_t type; + + /* LTV item format: [len][type][value...], total item size is len + 1. + * len includes type and value, but excludes itself. + */ + if (len < sizeof(uint8_t) || len > (remaining - 1)) { + return ESP_ERR_INVALID_SIZE; + } + + type = ltv[i + 1]; + data_len = len - sizeof(uint8_t); + + /* Skip empty value entries in strict parsing mode. */ + if (data_len == 0) { + i += (size_t)len + 1; + continue; + } + + if (func(type, <v[i + 2], data_len, user_data) == false) { + return ESP_OK; + } + + i += (size_t)len + 1; + } + + return ESP_OK; +} + +#if CONFIG_BT_ISO_UNICAST +#if CONFIG_BT_ISO_PERIPHERAL +esp_err_t esp_ble_iso_server_register(esp_ble_iso_server_t *server) +{ + int err; + + err = bt_iso_server_register_safe(server); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_iso_server_unregister(esp_ble_iso_server_t *server) +{ + int err; + + err = bt_iso_server_unregister_safe(server); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_ISO_PERIPHERAL */ + +#if CONFIG_BT_ISO_CENTRAL +esp_err_t esp_ble_iso_cig_create(esp_ble_iso_cig_param_t *param, + esp_ble_iso_cig_t **out_cig) +{ + int err; + + err = bt_iso_cig_create_safe(param, out_cig); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_iso_cig_reconfigure(esp_ble_iso_cig_t *cig, + esp_ble_iso_cig_param_t *param) +{ + int err; + + err = bt_iso_cig_reconfigure_safe(cig, param); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_iso_cig_terminate(esp_ble_iso_cig_t *cig) +{ + int err; + + err = bt_iso_cig_terminate_safe(cig); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_iso_chan_connect(esp_ble_iso_connect_param_t *param, + uint16_t conn_handle, size_t count) +{ + esp_err_t ret = ESP_OK; + void *conn; + int err; + + if (param == NULL || count == 0) { + return ESP_ERR_INVALID_ARG; + } + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + for (size_t i = 0; i < count; i++) { + param[i].acl = conn; + } + + err = bt_iso_chan_connect(param, count); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_ISO_CENTRAL */ + +esp_err_t esp_ble_iso_chan_disconnect(esp_ble_iso_chan_t *chan) +{ + int err; + + err = bt_iso_chan_disconnect_safe(chan); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_ISO_UNICAST */ + +static inline bool valid_dir(uint8_t dir) +{ + if (dir != ESP_BLE_ISO_DATA_PATH_DIR_INPUT && + dir != ESP_BLE_ISO_DATA_PATH_DIR_OUTPUT) { + return false; + } + + return true; +} + +esp_err_t esp_ble_iso_setup_data_path(const esp_ble_iso_chan_t *chan, uint8_t dir, + const esp_ble_iso_chan_path_t *path) +{ + int err; + + if (chan == NULL || path == NULL || valid_dir(dir) == false) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_iso_setup_data_path_safe(chan, dir, path); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_iso_remove_data_path(const esp_ble_iso_chan_t *chan, uint8_t dir) +{ + int err; + + if (chan == NULL || valid_dir(dir) == false) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_iso_remove_data_path_safe(chan, dir); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +#if CONFIG_BT_ISO_BROADCAST +esp_err_t esp_ble_iso_big_register_cb(esp_ble_iso_big_cb_t *cb) +{ + int err; + + if (cb == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_iso_big_register_cb_safe(cb); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +#if CONFIG_BT_ISO_BROADCASTER +esp_err_t esp_ble_iso_big_ext_adv_add(esp_ble_iso_ext_adv_info_t *info) +{ + int err; + + if (info == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_le_ext_adv_new_safe(info->adv_handle); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_iso_big_ext_adv_delete(esp_ble_iso_ext_adv_info_t *info) +{ + int err; + + if (info == NULL) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_le_ext_adv_delete_safe(info->adv_handle); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_iso_big_create(uint8_t adv_handle, + esp_ble_iso_big_create_param_t *param, + esp_ble_iso_big_t **out_big) +{ + esp_err_t ret = ESP_OK; + void *adv; + int err; + + bt_le_host_lock(); + + adv = bt_le_ext_adv_find(adv_handle); + if (adv == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto unlock; + } + + err = bt_iso_big_create(adv, param, out_big); + if (err) { + ret = ESP_FAIL; + } + +unlock: + bt_le_host_unlock(); + return ret; +} +#endif /* CONFIG_BT_ISO_BROADCASTER */ + +#if CONFIG_BT_ISO_SYNC_RECEIVER +esp_err_t esp_ble_iso_big_sync(uint16_t sync_handle, + esp_ble_iso_big_sync_param_t *param, + esp_ble_iso_big_t **out_big) +{ + void *per_adv_sync; + int err; + + per_adv_sync = bt_le_per_adv_sync_find_safe(sync_handle); + if (per_adv_sync == NULL) { + return ESP_ERR_NOT_FOUND; + } + + err = bt_iso_big_sync_safe(per_adv_sync, param, out_big); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_ISO_SYNC_RECEIVER */ + +esp_err_t esp_ble_iso_big_terminate(esp_ble_iso_big_t *big) +{ + int err; + + err = bt_iso_big_terminate_safe(big); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_ISO_BROADCAST */ + +esp_err_t esp_ble_iso_chan_get_info(esp_ble_iso_chan_t *chan, + esp_ble_iso_info_t *info) +{ + int err; + + err = bt_iso_chan_get_info_safe(chan, info); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +#if CONFIG_BT_ISO_TX +esp_err_t esp_ble_iso_chan_get_tx_sync(esp_ble_iso_chan_t *chan, + esp_ble_iso_tx_info_t *info) +{ + int err; + + err = bt_iso_chan_get_tx_sync_safe(chan, info); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_iso_chan_send(esp_ble_iso_chan_t *chan, + const uint8_t *sdu, + uint16_t sdu_len, + uint16_t seq_num) +{ + struct net_buf buf = { + /* Note: only data and len are used */ + .data = (void *)sdu, + .len = sdu_len, + }; + int err; + + if (chan == NULL || (!sdu ^ !sdu_len)) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_iso_chan_send_safe(chan, &buf, seq_num); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_ble_iso_chan_send_ts(esp_ble_iso_chan_t *chan, + const uint8_t *sdu, + uint16_t sdu_len, + uint16_t seq_num, + uint32_t ts) +{ + struct net_buf buf = { + /* Note: only data and len are used */ + .data = (void *)sdu, + .len = sdu_len, + }; + int err; + + if (chan == NULL || (!sdu ^ !sdu_len)) { + return ESP_ERR_INVALID_ARG; + } + + err = bt_iso_chan_send_ts_safe(chan, &buf, seq_num, ts); + if (err) { + return ESP_FAIL; + } + + return ESP_OK; +} +#endif /* CONFIG_BT_ISO_TX */ + +void esp_ble_iso_gap_app_post_event(uint8_t type, void *param) +{ + bt_le_gap_app_post_event(type, param); +} + +esp_err_t esp_ble_iso_common_init(esp_ble_iso_init_info_t *info) +{ + bool gap_cb_registered = false; + int err; + + if (info) { + if (info->gap_cb) { + err = bt_le_gap_app_cb_register(info->gap_cb); + if (err) { + return ESP_FAIL; + } + + gap_cb_registered = true; + } + } + + err = bt_le_host_init(); + if (err) { + goto unregister_gap; + } + + return ESP_OK; + +unregister_gap: + if (gap_cb_registered) { + bt_le_gap_app_cb_unregister(); + } + return ESP_FAIL; +} diff --git a/components/bt/esp_ble_audio/api/iso/include/esp_ble_iso_common_api.h b/components/bt/esp_ble_audio/api/iso/include/esp_ble_iso_common_api.h new file mode 100644 index 0000000000..d46d6020f4 --- /dev/null +++ b/components/bt/esp_ble_audio/api/iso/include/esp_ble_iso_common_api.h @@ -0,0 +1,594 @@ +/* + * SPDX-FileCopyrightText: 2020 Intel Corporation + * SPDX-FileCopyrightText: 2021-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ESP_BLE_ISO_COMMON_API_H_ +#define ESP_BLE_ISO_COMMON_API_H_ + +#include +#include +#include +#include + +#include "sdkconfig.h" +#include "esp_err.h" + +#include +#include + +#include <../host/conn_internal.h> + +#include "common/host.h" +#include "common/app/gap.h" +#include "common/app/gatt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Convert BIS index to bit + * + * The BIS indexes start from 0x01, so the lowest allowed bit is + * BIT(0) that represents index 0x01. To synchronize to e.g. BIS + * indexes 0x01 and 0x02, the bitfield value should be BIT(0) | BIT(1). + * As a general notation, to sync to BIS index N use BIT(N - 1). + */ +#define ESP_BLE_ISO_BIS_INDEX_BIT(x) BT_ISO_BIS_INDEX_BIT(x) + +/*!< The minimum value for vendor specific data path ID */ +#define ESP_BLE_ISO_DATA_PATH_VS_ID_MIN BT_ISO_DATA_PATH_VS_ID_MIN +/*!< The maximum value for vendor specific data path ID */ +#define ESP_BLE_ISO_DATA_PATH_VS_ID_MAX BT_ISO_DATA_PATH_VS_ID_MAX + +/*!< Minimum controller delay in microseconds */ +#define ESP_BLE_ISO_CONTROLLER_DELAY_MIN BT_ISO_CONTROLLER_DELAY_MIN +/*!< Maximum controller delay in microseconds */ +#define ESP_BLE_ISO_CONTROLLER_DELAY_MAX BT_ISO_CONTROLLER_DELAY_MAX + +/*!< Unknown SDU interval */ +#define ESP_BLE_ISO_SDU_INTERVAL_UNKNOWN BT_ISO_SDU_INTERVAL_UNKNOWN +/*!< Minimum interval value in microseconds */ +#define ESP_BLE_ISO_SDU_INTERVAL_MIN BT_ISO_SDU_INTERVAL_MIN +/*!< Maximum interval value in microseconds */ +#define ESP_BLE_ISO_SDU_INTERVAL_MAX BT_ISO_SDU_INTERVAL_MAX + +/*!< Minimum ISO interval (N * 1.25 ms) */ +#define ESP_BLE_ISO_ISO_INTERVAL_MIN BT_ISO_ISO_INTERVAL_MIN +/*!< Maximum ISO interval (N * 1.25 ms) */ +#define ESP_BLE_ISO_ISO_INTERVAL_MAX BT_ISO_ISO_INTERVAL_MAX + +/*!< Minimum latency value in milliseconds */ +#define ESP_BLE_ISO_LATENCY_MIN BT_ISO_LATENCY_MIN +/*!< Maximum latency value in milliseconds */ +#define ESP_BLE_ISO_LATENCY_MAX BT_ISO_LATENCY_MAX + +/*!< Packets will be sent sequentially between the channels in the group */ +#define ESP_BLE_ISO_PACKING_SEQUENTIAL BT_ISO_PACKING_SEQUENTIAL +/*!< Packets will be sent interleaved between the channels in the group */ +#define ESP_BLE_ISO_PACKING_INTERLEAVED BT_ISO_PACKING_INTERLEAVED + +/*!< Packets may be framed or unframed */ +#define ESP_BLE_ISO_FRAMING_UNFRAMED BT_ISO_FRAMING_UNFRAMED +/*!< Packets are always framed */ +#define ESP_BLE_ISO_FRAMING_FRAMED BT_ISO_FRAMING_FRAMED + +/*!< Maximum number of isochronous channels in a single group */ +#define ESP_BLE_ISO_MAX_GROUP_ISO_COUNT BT_ISO_MAX_GROUP_ISO_COUNT + +/*!< Minimum SDU size */ +#define ESP_BLE_ISO_MIN_SDU BT_ISO_MIN_SDU +/*!< Maximum SDU size */ +#define ESP_BLE_ISO_MAX_SDU BT_ISO_MAX_SDU + +/*!< Minimum PDU size */ +#define ESP_BLE_ISO_CONNECTED_PDU_MIN BT_ISO_CONNECTED_PDU_MIN +/*!< Minimum PDU size */ +#define ESP_BLE_ISO_BROADCAST_PDU_MIN BT_ISO_BROADCAST_PDU_MIN +/*!< Maximum PDU size */ +#define ESP_BLE_ISO_PDU_MAX BT_ISO_PDU_MAX + +/*!< Minimum burst number */ +#define ESP_BLE_ISO_BN_MIN BT_ISO_BN_MIN +/*!< Maximum burst number */ +#define ESP_BLE_ISO_BN_MAX BT_ISO_BN_MAX + +/*!< Minimum flush timeout */ +#define ESP_BLE_ISO_FT_MIN BT_ISO_FT_MIN +/*!< Maximum flush timeout */ +#define ESP_BLE_ISO_FT_MAX BT_ISO_FT_MAX + +/*!< Minimum number of subevents */ +#define ESP_BLE_ISO_NSE_MIN BT_ISO_NSE_MIN +/*!< Maximum number of subevents */ +#define ESP_BLE_ISO_NSE_MAX BT_ISO_NSE_MAX + +/*!< Minimum BIG sync timeout value (N * 10 ms) */ +#define ESP_BLE_ISO_SYNC_TIMEOUT_MIN BT_ISO_SYNC_TIMEOUT_MIN +/*!< Maximum BIG sync timeout value (N * 10 ms) */ +#define ESP_BLE_ISO_SYNC_TIMEOUT_MAX BT_ISO_SYNC_TIMEOUT_MAX + +/*!< Controller controlled maximum subevent count value */ +#define ESP_BLE_ISO_SYNC_MSE_ANY BT_ISO_SYNC_MSE_ANY +/*!< Minimum BIG sync maximum subevent count value */ +#define ESP_BLE_ISO_SYNC_MSE_MIN BT_ISO_SYNC_MSE_MIN +/*!< Maximum BIG sync maximum subevent count value */ +#define ESP_BLE_ISO_SYNC_MSE_MAX BT_ISO_SYNC_MSE_MAX + +/*!< Minimum connected ISO retransmission value */ +#define ESP_BLE_ISO_CONNECTED_RTN_MIN BT_ISO_CONNECTED_RTN_MIN +/*!< Maximum connected ISO retransmission value */ +#define ESP_BLE_ISO_CONNECTED_RTN_MAX BT_ISO_CONNECTED_RTN_MAX +/*!< Minimum broadcast ISO retransmission value */ +#define ESP_BLE_ISO_BROADCAST_RTN_MIN BT_ISO_BROADCAST_RTN_MIN +/*!< Maximum broadcast ISO retransmission value */ +#define ESP_BLE_ISO_BROADCAST_RTN_MAX BT_ISO_BROADCAST_RTN_MAX + +/*!< Broadcast code size */ +#define ESP_BLE_ISO_BROADCAST_CODE_SIZE BT_ISO_BROADCAST_CODE_SIZE + +/*!< Lowest BIS index */ +#define ESP_BLE_ISO_BIS_INDEX_MIN BT_ISO_BIS_INDEX_MIN +/*!< Highest BIS index */ +#define ESP_BLE_ISO_BIS_INDEX_MAX BT_ISO_BIS_INDEX_MAX + +/*!< Minimum Immediate Repetition Count */ +#define ESP_BLE_ISO_IRC_MIN BT_ISO_IRC_MIN +/*!< Maximum Immediate Repetition Count */ +#define ESP_BLE_ISO_IRC_MAX BT_ISO_IRC_MAX + +/*!< Minimum pre-transmission offset */ +#define ESP_BLE_ISO_PTO_MIN BT_ISO_PTO_MIN +/*!< Maximum pre-transmission offset */ +#define ESP_BLE_ISO_PTO_MAX BT_ISO_PTO_MAX + +/*!< No subinterval */ +#define ESP_BLE_ISO_SUBINTERVAL_NONE BT_ISO_SUBINTERVAL_NONE +/*!< Unknown subinterval */ +#define ESP_BLE_ISO_SUBINTERVAL_UNKNOWN BT_ISO_SUBINTERVAL_UNKNOWN +/*!< Minimum subinterval in microseconds */ +#define ESP_BLE_ISO_SUBINTERVAL_MIN BT_ISO_SUBINTERVAL_MIN +/*!< Maximum subinterval in microseconds */ +#define ESP_BLE_ISO_SUBINTERVAL_MAX BT_ISO_SUBINTERVAL_MAX + +/*!< Audio Input (Host to Controller) Data Path Direction */ +#define ESP_BLE_ISO_DATA_PATH_DIR_INPUT BT_HCI_DATAPATH_DIR_HOST_TO_CTLR +/*!< Audio Output (Controller to Host) Data Path Direction */ +#define ESP_BLE_ISO_DATA_PATH_DIR_OUTPUT BT_HCI_DATAPATH_DIR_CTLR_TO_HOST + +/*!< Value to set the ISO data path over HCI */ +#define ESP_BLE_ISO_DATA_PATH_HCI BT_ISO_DATA_PATH_HCI + +/*!< Transparent Coding Format */ +#define ESP_BLE_ISO_CODING_FORMAT_TRANSPARENT BT_HCI_CODING_FORMAT_TRANSPARENT +/*!< LC3 Coding Format */ +#define ESP_BLE_ISO_CODING_FORMAT_LC3 BT_HCI_CODING_FORMAT_LC3 + +/*!< The ISO packet is valid */ +#define ESP_BLE_ISO_FLAGS_VALID BT_ISO_FLAGS_VALID +/*!< The ISO packet may possibly contain errors */ +#define ESP_BLE_ISO_FLAGS_ERROR BT_ISO_FLAGS_ERROR +/*!< The ISO packet was lost */ +#define ESP_BLE_ISO_FLAGS_LOST BT_ISO_FLAGS_LOST +/*!< Timestamp is valid */ +#define ESP_BLE_ISO_FLAGS_TS BT_ISO_FLAGS_TS + +/*!< LE 1M PHY */ +#define ESP_BLE_ISO_PHY_1M BT_GAP_LE_PHY_1M +/*!< LE 2M PHY */ +#define ESP_BLE_ISO_PHY_2M BT_GAP_LE_PHY_2M +/*!< LE Coded PHY, coding scheme not specified */ +#define ESP_BLE_ISO_PHY_CODED BT_GAP_LE_PHY_CODED + +/*!< Unknown */ +#define ESP_BLE_ISO_SCA_UNKNOWN BT_GAP_SCA_UNKNOWN +/*!< 251 ppm to 500 ppm */ +#define ESP_BLE_ISO_SCA_251_500 BT_GAP_SCA_251_500 +/*!< 151 ppm to 250 ppm */ +#define ESP_BLE_ISO_SCA_151_250 BT_GAP_SCA_151_250 +/*!< 101 ppm to 150 ppm */ +#define ESP_BLE_ISO_SCA_101_150 BT_GAP_SCA_101_150 +/*!< 76 ppm to 100 ppm */ +#define ESP_BLE_ISO_SCA_76_100 BT_GAP_SCA_76_100 +/*!< 51 ppm to 75 ppm */ +#define ESP_BLE_ISO_SCA_51_75 BT_GAP_SCA_51_75 +/*!< 31 ppm to 50 ppm */ +#define ESP_BLE_ISO_SCA_31_50 BT_GAP_SCA_31_50 +/*!< 21 ppm to 30 ppm */ +#define ESP_BLE_ISO_SCA_21_30 BT_GAP_SCA_21_30 +/*!< 0 ppm to 20 ppm */ +#define ESP_BLE_ISO_SCA_0_20 BT_GAP_SCA_0_20 + +/*!< Security Level 1: No encryption and no authentication */ +#define ESP_BLE_ISO_SECURITY_NONE BT_SECURITY_L1 +/*!< Security Level 2: Encryption and no authentication (no MITM) */ +#define ESP_BLE_ISO_SECURITY_NO_MITM BT_SECURITY_L2 +/*!< Security Level 3: Encryption and authentication (MITM) */ +#define ESP_BLE_ISO_SECURITY_MITM BT_SECURITY_L3 + +/** Connection structure. */ +typedef struct bt_conn esp_ble_conn_t; + +/** ISO Channel structure. */ +typedef struct bt_iso_chan esp_ble_iso_chan_t; + +/** ISO Channel operations structure. */ +typedef struct bt_iso_chan_ops esp_ble_iso_chan_ops_t; + +/** ISO Channel QoS structure. */ +typedef struct bt_iso_chan_qos esp_ble_iso_chan_qos_t; + +/** ISO Channel IO QoS structure. */ +typedef struct bt_iso_chan_io_qos esp_ble_iso_chan_io_qos_t; + +/** ISO Channel Data Path structure. */ +typedef struct bt_iso_chan_path esp_ble_iso_chan_path_t; + +/** Connected Isochronous Group (CIG). */ +typedef struct bt_iso_cig esp_ble_iso_cig_t; + +/** Connected Isochronous Group (CIG) parameters. */ +typedef struct bt_iso_cig_param esp_ble_iso_cig_param_t; + +/** ISO connection parameters structure. */ +typedef struct bt_iso_connect_param esp_ble_iso_connect_param_t; + +/** ISO Accept Info Structure. */ +typedef struct bt_iso_accept_info esp_ble_iso_accept_info_t; + +/** ISO Server structure. */ +typedef struct bt_iso_server esp_ble_iso_server_t; + +/** ISO Unicast Info Structure. */ +typedef struct bt_iso_unicast_info esp_ble_iso_unicast_info_t; + +/** ISO Unicast TX Info Structure. */ +typedef struct bt_iso_unicast_tx_info esp_ble_iso_unicast_tx_info_t; + +/** ISO Broadcast callbacks */ +typedef struct bt_iso_big_cb esp_ble_iso_big_cb_t; + +/** Broadcast Isochronous Group (BIG). */ +typedef struct bt_iso_big esp_ble_iso_big_t; + +/** Broadcast Isochronous Group (BIG) creation parameters. */ +typedef struct bt_iso_big_create_param esp_ble_iso_big_create_param_t; + +/** Broadcast Isochronous Group (BIG) Sync Parameters. */ +typedef struct bt_iso_big_sync_param esp_ble_iso_big_sync_param_t; + +/** Broadcast Isochronous Group (BIG) information. */ +typedef struct bt_iso_biginfo esp_ble_iso_biginfo_t; + +/** ISO Broadcaster Info Structure. */ +typedef struct bt_iso_broadcaster_info esp_ble_iso_broadcaster_info_t; + +/** ISO Synchronized Receiver Info Structure. */ +typedef struct bt_iso_sync_receiver_info esp_ble_iso_sync_receiver_info_t; + +/** ISO channel Info Structure. */ +typedef struct bt_iso_info esp_ble_iso_info_t; + +/** ISO Meta Data structure for received ISO packets. */ +typedef struct bt_iso_recv_info esp_ble_iso_recv_info_t; + +/** ISO Meta Data structure for transmitted ISO packets. */ +typedef struct bt_iso_tx_info esp_ble_iso_tx_info_t; + +/** ISO Unicast & Broadcast TX Callback Info Structure. */ +typedef struct bt_iso_tx_cb_info esp_ble_iso_tx_cb_info_t; + +/** Extended advertising information structure */ +typedef struct { + uint8_t adv_handle; /*!< Handle for the advertising set */ +} esp_ble_iso_ext_adv_info_t; + +/** + * @brief Helper for parsing length-type-value data. + * + * @param ltv Length-type-value (LTV) encoded data. + * @param size Size of the @p ltv data. + * @param func Callback function which will be called for each element + * that's found in the data. The callback should return + * true to continue parsing, or false to stop parsing. + * @param user_data User data to be passed to the callback. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_iso_data_parse(const uint8_t ltv[], size_t size, + bool (*func)(uint8_t type, + const uint8_t *data, + uint8_t data_len, + void *user_data), + void *user_data); + +/** + * @brief Register an ISO server. + * + * @param server Pointer to the ISO server structure. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_iso_server_register(esp_ble_iso_server_t *server); + +/** + * @brief Unregister an ISO server. + * + * @param server Pointer to the ISO server structure. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_iso_server_unregister(esp_ble_iso_server_t *server); + +/** + * @brief Create a Connected ISO Group (CIG). + * + * @param param Parameters for CIG creation. + * @param out_cig Pointer to store created CIG. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_iso_cig_create(esp_ble_iso_cig_param_t *param, + esp_ble_iso_cig_t **out_cig); + +/** + * @brief Reconfigure a Connected ISO Group. + * + * @param cig Pointer to the CIG to reconfigure. + * @param param New parameters for the CIG. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_iso_cig_reconfigure(esp_ble_iso_cig_t *cig, + esp_ble_iso_cig_param_t *param); + +/** + * @brief Terminate a Connected ISO Group. + * + * @param cig Pointer to the CIG to terminate. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_iso_cig_terminate(esp_ble_iso_cig_t *cig); + +/** + * @brief Connect ISO channels. + * + * @param param Connection parameters. + * @param conn_handle Connection handle. + * @param count Number of channels to connect. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_iso_chan_connect(esp_ble_iso_connect_param_t *param, + uint16_t conn_handle, size_t count); + +/** + * @brief Disconnect an ISO channel. + * + * @param chan Pointer to the ISO channel. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_iso_chan_disconnect(esp_ble_iso_chan_t *chan); + +/** + * @brief Set up the ISO data path for an ISO channel. + * + * The channel must be associated with a BIS or CIS handle first which it is when the + * esp_ble_iso_chan_ops_t.connected() callback is called. + * + * @param chan The channel to setup the ISO data path for. + * @param dir The direction to setup, either ESP_BLE_ISO_DATA_PATH_DIR_INPUT + * or ESP_BLE_ISO_DATA_PATH_DIR_OUTPUT. + * For ISO broadcast channels this can only be + * ESP_BLE_ISO_DATA_PATH_DIR_INPUT, and for ISO sync receiver + * channels this can only be ESP_BLE_ISO_DATA_PATH_DIR_OUTPUT. + * @param path The data path. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_iso_setup_data_path(const esp_ble_iso_chan_t *chan, uint8_t dir, + const esp_ble_iso_chan_path_t *path); + +/** + * @brief Removes the ISO data path for an ISO channel. + * + * Removes the ISO data path configured by esp_ble_iso_setup_data_path() for the provided + * @p dir. + * + * The data paths of CIS for Peripherals are deleted by the controller, and thus it is not + * necessary (or possible) to remove data paths of CIS after they have disconnected for a + * Peripheral, as per Bluetooth Core specification 6.0, Vol 4, Part E, Section 7.7.5. + * The data paths for CIS for a Central remain valid, even after a disconnection, and thus + * a Central device should call bt_iso_remove_data_path() on disconnect if it no longer + * wants to use that CIS. + * All data paths created by a Central are removed when the CIG is removed with + * esp_ble_iso_cig_terminate(). + * + * Any data paths associated with an ISO Sync Receiver BIG are removed by the controller + * when the BIG sync is lost or terminated, and thus it is not necessary (or possible) to + * remove data paths of ISO channels associated with a BIG for a Sync Receiver, as per + * Bluetooth Core specification 6.0, Vol 4, Part E, Section 7.7.65.30. + * + * All data paths associated with an ISO Broadcaster BIG are removed when the BIG is + * terminated by esp_ble_iso_big_terminate(), and thus it is not necessary (or possible) + * to remove data paths of ISO channels associated with a BIG for a Broadcaster, + * as per Bluetooth Core specification 6.0, Vol 4, Part E, Section 7.8.105. + * + * @param chan The channel to setup the ISO data path for. + * @param dir The direction to setup, either ESP_BLE_ISO_DATA_PATH_DIR_INPUT or + * ESP_BLE_ISO_DATA_PATH_DIR_OUTPUT. For ISO broadcast channels this + * can only be ESP_BLE_ISO_DATA_PATH_DIR_INPUT, and for ISO sync + * receiver channels this can only be ESP_BLE_ISO_DATA_PATH_DIR_OUTPUT. + + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_iso_remove_data_path(const esp_ble_iso_chan_t *chan, uint8_t dir); + +/** + * @brief Registers callbacks for Broadcast Sources. + * + * @param cb Pointer to the callback structure. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_iso_big_register_cb(esp_ble_iso_big_cb_t *cb); + +/** + * @brief Add extended advertising for BIG. + * + * @param info Extended advertising information. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_iso_big_ext_adv_add(esp_ble_iso_ext_adv_info_t *info); + +/** + * @brief Delete extended advertising for BIG. + * + * @param info Extended advertising information. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_iso_big_ext_adv_delete(esp_ble_iso_ext_adv_info_t *info); + +/** + * @brief Create a Broadcast ISO Group (BIG). + * + * @param adv_handle Advertising handle. + * @param param Parameters for BIG creation. + * @param out_big Pointer to store created BIG. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_iso_big_create(uint8_t adv_handle, + esp_ble_iso_big_create_param_t *param, + esp_ble_iso_big_t **out_big); + +/** + * @brief Synchronize with a Broadcast ISO Group. + * + * @param sync_handle Sync handle. + * @param param Sync parameters. + * @param out_big Pointer to store synchronized BIG. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_iso_big_sync(uint16_t sync_handle, + esp_ble_iso_big_sync_param_t *param, + esp_ble_iso_big_t **out_big); + +/** + * @brief Terminate a Broadcast ISO Group. + * + * @param big Pointer to the BIG to terminate. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_iso_big_terminate(esp_ble_iso_big_t *big); + +/** + * @brief Get ISO channel information. + * + * @param chan Pointer to the ISO channel. + * @param info Pointer to store channel information. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_iso_chan_get_info(esp_ble_iso_chan_t *chan, + esp_ble_iso_info_t *info); + +/** + * @brief Get TX sync information for an ISO channel. + * + * @param chan Pointer to the ISO channel. + * @param info Pointer to store TX sync information. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_iso_chan_get_tx_sync(esp_ble_iso_chan_t *chan, + esp_ble_iso_tx_info_t *info); + +/** + * @brief Send data over an ISO channel. + * + * @param chan Pointer to the ISO channel. + * @param sdu Pointer to the SDU data. + * @param sdu_len Length of the SDU. + * @param seq_num Sequence number. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_iso_chan_send(esp_ble_iso_chan_t *chan, + const uint8_t *sdu, + uint16_t sdu_len, + uint16_t seq_num); + +/** + * @brief Send timestamped data over an ISO channel. + * + * @param chan Pointer to the ISO channel. + * @param sdu Pointer to the SDU data. + * @param sdu_len Length of the SDU. + * @param seq_num Sequence number. + * @param ts Timestamp. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_iso_chan_send_ts(esp_ble_iso_chan_t *chan, + const uint8_t *sdu, + uint16_t sdu_len, + uint16_t seq_num, + uint32_t ts); + +/*!< ISO GAP Extended Scan Recv event */ +#define ESP_BLE_ISO_GAP_EVENT_EXT_SCAN_RECV BT_LE_GAP_APP_EVENT_EXT_SCAN_RECV +/*!< ISO GAP Periodic Sync Established event */ +#define ESP_BLE_ISO_GAP_EVENT_PA_SYNC BT_LE_GAP_APP_EVENT_PA_SYNC +/*!< ISO GAP Periodic Sync Lost event */ +#define ESP_BLE_ISO_GAP_EVENT_PA_SYNC_LOST BT_LE_GAP_APP_EVENT_PA_SYNC_LOST +/*!< ISO GAP Connection Complete event */ +#define ESP_BLE_ISO_GAP_EVENT_ACL_CONNECT BT_LE_GAP_APP_EVENT_ACL_CONNECT +/*!< ISO GAP Disconnection Complete event */ +#define ESP_BLE_ISO_GAP_EVENT_ACL_DISCONNECT BT_LE_GAP_APP_EVENT_ACL_DISCONNECT +/*!< ISO GAP Security Changed event */ +#define ESP_BLE_ISO_GAP_EVENT_SECURITY_CHANGE BT_LE_GAP_APP_EVENT_SECURITY_CHANGE +/*!< ISO GAP BIGInfo Adv Report event */ +#define ESP_BLE_ISO_GAP_EVENT_BIGINFO_RECV BT_LE_GAP_APP_EVENT_BIGINFO_RECV +/** ISO GAP application event structure */ +typedef struct bt_le_gap_app_event esp_ble_iso_gap_app_event_t; + +/** ISO initialization information structure */ +typedef struct { + bt_le_gap_app_cb gap_cb; /*!< GAP event callbacks */ +} esp_ble_iso_init_info_t; + +/** + * @brief Post an application-layer GAP event for ISO internal usage. + * + * @note This function is only needed while using NimBLE Host. + * + * @param type Event type. + * @param param Event parameters. + */ +void esp_ble_iso_gap_app_post_event(uint8_t type, void *param); + +/** + * @brief Initialize ISO common functionality. + * + * @param info Initialization information. + * + * @return ESP_OK on success, or an error code on failure. + */ +esp_err_t esp_ble_iso_common_init(esp_ble_iso_init_info_t *info); + +#ifdef __cplusplus +} +#endif + +#endif /* ESP_BLE_ISO_COMMON_API_H_ */ diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/gap.c b/components/bt/esp_ble_audio/host/adapter/nimble/gap.c new file mode 100644 index 0000000000..079c98034b --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/gap.c @@ -0,0 +1,205 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include <../host/hci_core.h> +#include <../host/iso_internal.h> + +#include "host/ble_gap.h" +#include "services/gap/ble_svc_gap.h" + +#include "common/host.h" +#include "common/app/gap.h" + +void bt_le_nimble_gap_post_event(void *param) +{ + struct bt_le_gap_app_param *qev; + struct ble_gap_conn_desc desc; + struct ble_gap_event *ev; + int err; + + qev = calloc(1, sizeof(*qev)); + assert(qev); + + memset(&desc, 0, sizeof(desc)); + ev = param; + + if (ev->type != BLE_GAP_EVENT_EXT_DISC && + ev->type != BLE_GAP_EVENT_PERIODIC_REPORT) { + LOG_DBG("[N]PostGapEvt[%u]", ev->type); + } + + /* TODO: + * - Limit the adv report posted to ISO task; + * - Limit the extended adv report posted to ISO task; + * - Limit the periodic adv report posted to ISO task; + * - E.g. If the adv report contains any information interested by LE Audio. + */ + + switch (ev->type) { + case BLE_GAP_EVENT_EXT_DISC: + qev->type = BT_LE_GAP_APP_PARAM_EXT_SCAN_RECV; + + qev->ext_scan_recv.event_type = (ev->ext_disc.data_status << 5) | ev->ext_disc.props; + qev->ext_scan_recv.addr.type = ev->ext_disc.addr.type; + memcpy(qev->ext_scan_recv.addr.val, ev->ext_disc.addr.val, BT_ADDR_SIZE); + qev->ext_scan_recv.rssi = ev->ext_disc.rssi; + qev->ext_scan_recv.tx_power = ev->ext_disc.tx_power; + qev->ext_scan_recv.sid = ev->ext_disc.sid; + qev->ext_scan_recv.pri_phy = ev->ext_disc.prim_phy; + qev->ext_scan_recv.sec_phy = ev->ext_disc.sec_phy; + qev->ext_scan_recv.per_adv_itvl = ev->ext_disc.periodic_adv_itvl; + qev->ext_scan_recv.data_len = ev->ext_disc.length_data; + + if (qev->ext_scan_recv.data_len) { + qev->ext_scan_recv.data = calloc(1, qev->ext_scan_recv.data_len); + assert(qev->ext_scan_recv.data); + + memcpy(qev->ext_scan_recv.data, ev->ext_disc.data, qev->ext_scan_recv.data_len); + } + break; + + case BLE_GAP_EVENT_PERIODIC_SYNC: + qev->type = BT_LE_GAP_APP_PARAM_PA_SYNC; + + qev->pa_sync.status = ev->periodic_sync.status; + qev->pa_sync.sync_handle = ev->periodic_sync.sync_handle; + qev->pa_sync.addr.type = ev->periodic_sync.adv_addr.type; + memcpy(qev->pa_sync.addr.val, ev->periodic_sync.adv_addr.val, BT_ADDR_SIZE); + qev->pa_sync.sid = ev->periodic_sync.sid; + qev->pa_sync.adv_phy = ev->periodic_sync.adv_phy; + qev->pa_sync.per_adv_itvl = ev->periodic_sync.per_adv_ival; + qev->pa_sync.adv_ca = ev->periodic_sync.adv_clk_accuracy; + break; + + case BLE_GAP_EVENT_PERIODIC_SYNC_LOST: + qev->type = BT_LE_GAP_APP_PARAM_PA_SYNC_LOST; + + qev->pa_sync_lost.sync_handle = ev->periodic_sync_lost.sync_handle; + qev->pa_sync_lost.reason = ev->periodic_sync_lost.reason; + break; + + case BLE_GAP_EVENT_PERIODIC_REPORT: + qev->type = BT_LE_GAP_APP_PARAM_PA_SYNC_RECV; + + qev->pa_sync_recv.sync_handle = ev->periodic_report.sync_handle; + qev->pa_sync_recv.tx_power = ev->periodic_report.tx_power; + qev->pa_sync_recv.rssi = ev->periodic_report.rssi; + qev->pa_sync_recv.data_status = ev->periodic_report.data_status; + qev->pa_sync_recv.data_len = ev->periodic_report.data_length; + + if (qev->pa_sync_recv.data_len) { + qev->pa_sync_recv.data = calloc(1, qev->pa_sync_recv.data_len); + assert(qev->pa_sync_recv.data); + + memcpy(qev->pa_sync_recv.data, ev->periodic_report.data, qev->pa_sync_recv.data_len); + } + break; + + case BLE_GAP_EVENT_CONNECT: + qev->type = BT_LE_GAP_APP_PARAM_ACL_CONNECT; + + qev->acl_connect.status = ev->connect.status; + if (qev->acl_connect.status == 0) { + err = ble_gap_conn_find(ev->connect.conn_handle, &desc); + assert(err == 0); + + qev->acl_connect.conn_handle = desc.conn_handle; + qev->acl_connect.role = desc.role; + qev->acl_connect.dst.type = desc.peer_id_addr.type; + memcpy(qev->acl_connect.dst.val, desc.peer_id_addr.val, BT_ADDR_SIZE); + } + break; + + case BLE_GAP_EVENT_DISCONNECT: + qev->type = BT_LE_GAP_APP_PARAM_ACL_DISCONNECT; + + qev->acl_disconnect.conn_handle = ev->disconnect.conn.conn_handle; + qev->acl_disconnect.reason = ev->disconnect.reason; + break; + + case BLE_GAP_EVENT_ENC_CHANGE: + qev->type = BT_LE_GAP_APP_PARAM_SECURITY_CHANGE; + + qev->security_change.status = ev->enc_change.status; + if (qev->security_change.status == 0) { + err = ble_gap_conn_find(ev->enc_change.conn_handle, &desc); + assert(err == 0); + + qev->security_change.conn_handle = ev->enc_change.conn_handle; + qev->security_change.role = desc.role; + qev->security_change.sec_level = BT_SECURITY_L3; + qev->security_change.dst.type = desc.peer_id_addr.type; + memcpy(qev->security_change.dst.val, desc.peer_id_addr.val, BT_ADDR_SIZE); + } + break; + + default: + free(qev); + assert(0); + break; + } + + err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GAP_EVENT, qev, sizeof(*qev)); + if (err) { + LOG_ERR("[N]GapPostEvtFail[%d][%u]", err, qev->type); + goto free; + } + + return; + +free: + switch (qev->type) { + case BT_LE_GAP_APP_PARAM_EXT_SCAN_RECV: + if (qev->ext_scan_recv.data) { + free(qev->ext_scan_recv.data); + qev->ext_scan_recv.data = NULL; + } + break; + case BT_LE_GAP_APP_PARAM_PA_SYNC_RECV: + if (qev->pa_sync_recv.data) { + free(qev->pa_sync_recv.data); + qev->pa_sync_recv.data = NULL; + } + break; + default: + break; + } + + free(qev); +} + +int bt_le_nimble_scan_start(const struct bt_le_scan_param *param, ble_gap_event_fn *cb) +{ + struct ble_gap_disc_params scan_param = {0}; + + scan_param.itvl = param->interval; + scan_param.window = param->window; + scan_param.filter_policy = 0; + scan_param.limited = 0; + scan_param.passive = !param->type; + scan_param.filter_duplicates = 0; + + return ble_gap_disc(BLE_OWN_ADDR_PUBLIC, BLE_HS_FOREVER, &scan_param, cb, NULL); +} + +int bt_le_nimble_scan_stop(void) +{ + return ble_gap_disc_cancel(); +} + +int bt_le_nimble_iso_disconnect(uint16_t conn_handle, uint8_t reason) +{ + return ble_gap_iso_disconnect(conn_handle, reason); +} diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/gap.h b/components/bt/esp_ble_audio/host/adapter/nimble/gap.h new file mode 100644 index 0000000000..a15eef9404 --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/gap.h @@ -0,0 +1,30 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef HOST_NIMBLE_APP_GAP_H_ +#define HOST_NIMBLE_APP_GAP_H_ + +#include + +#include "host/ble_gap.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void bt_le_nimble_gap_post_event(void *param); + +int bt_le_nimble_scan_start(const struct bt_le_scan_param *param, ble_gap_event_fn *cb); + +int bt_le_nimble_scan_stop(void); + +int bt_le_nimble_iso_disconnect(uint16_t conn_handle, uint8_t reason); + +#ifdef __cplusplus +} +#endif + +#endif /* HOST_NIMBLE_APP_GAP_H_ */ diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/gatt/gatt.c b/components/bt/esp_ble_audio/host/adapter/nimble/gatt/gatt.c new file mode 100644 index 0000000000..6b6f52beea --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/gatt/gatt.c @@ -0,0 +1,525 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include <../host/conn_internal.h> + +#include "host/ble_hs.h" +#include "host/ble_att.h" +#include "host/ble_gatt.h" +#include "host/ble_hs_mbuf.h" + +#include "common/host.h" +#include "common/app/gatt.h" + +void bt_le_nimble_gatt_post_event(void *param) +{ + struct bt_le_gatt_event_param *qev; + struct ble_gap_event *ev; + int err; + + ev = param; + + /* LOG_DBG("[N]PostGattEvt[%u]", ev->type); */ + + /* Currently we only handle this event for indication */ + if (ev->type == BLE_GAP_EVENT_NOTIFY_TX && ev->notify_tx.indication == 0) { + return; + } + + qev = calloc(1, sizeof(*qev)); + assert(qev); + + switch (ev->type) { + case BLE_GAP_EVENT_MTU: + qev->type = BT_LE_GATT_MTU_CHANGE_EVENT; + + qev->gatt_mtu_change.conn_handle = ev->mtu.conn_handle; + qev->gatt_mtu_change.mtu = ev->mtu.value; + break; + + case BLE_GAP_EVENT_SUBSCRIBE: + qev->type = BT_LE_GATTS_SUBSCRIBE_EVENT; + + qev->gatts_subscribe.conn_handle = ev->subscribe.conn_handle; + qev->gatts_subscribe.attr_handle = ev->subscribe.attr_handle; + qev->gatts_subscribe.prev_notify = ev->subscribe.prev_notify; + qev->gatts_subscribe.cur_notify = ev->subscribe.cur_notify; + qev->gatts_subscribe.prev_indicate = ev->subscribe.prev_indicate; + qev->gatts_subscribe.cur_indicate = ev->subscribe.cur_indicate; + qev->gatts_subscribe.reason = ev->subscribe.reason; + break; + + case BLE_GAP_EVENT_NOTIFY_RX: + qev->type = BT_LE_GATTC_NOTIFY_RX_EVENT; + + qev->gattc_notify_rx.conn_handle = ev->notify_rx.conn_handle; + qev->gattc_notify_rx.attr_handle = ev->notify_rx.attr_handle; + qev->gattc_notify_rx.is_notify = (ev->notify_rx.indication == 0); + + if (ev->notify_rx.om && OS_MBUF_PKTLEN(ev->notify_rx.om)) { + uint16_t total_len = OS_MBUF_PKTLEN(ev->notify_rx.om); + qev->gattc_notify_rx.len = total_len; + + qev->gattc_notify_rx.value = calloc(1, total_len); + assert(qev->gattc_notify_rx.value); + + os_mbuf_copydata(ev->notify_rx.om, 0, total_len, qev->gattc_notify_rx.value); + } + break; + + case BLE_GAP_EVENT_NOTIFY_TX: + qev->type = BT_LE_GATTS_NOTIFY_TX_EVENT; + + qev->gatts_notify_tx.is_notify = (ev->notify_tx.indication == 0); + qev->gatts_notify_tx.conn_handle = ev->notify_tx.conn_handle; + qev->gatts_notify_tx.attr_handle = ev->notify_tx.attr_handle; + qev->gatts_notify_tx.status = ev->notify_tx.status; + break; + + default: + free(qev); + assert(0); + break; + } + + err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GATT_EVENT, qev, sizeof(*qev)); + if (err) { + LOG_ERR("[N]GattPostEvtFail[%d][%u]", err, qev->type); + + if (qev->type == BT_LE_GATTC_NOTIFY_RX_EVENT && + qev->gattc_notify_rx.value) { + free(qev->gattc_notify_rx.value); + qev->gattc_notify_rx.value = NULL; + } + + free(qev); + } +} + +int bt_le_nimble_gatt_post_disc_event(uint16_t conn_handle, ble_uuid16_t *uuid, + struct bt_gatt_discover_params *params, + uint8_t type) +{ + struct bt_le_gatt_event_param *qev; + int err; + + LOG_DBG("[N]GattcDiscHdlr[%u][%u]", conn_handle, type); + + if (type == GATTC_DISC_TYPE_DUMMY || type >= GATTC_DISC_TYPE_MAX) { + LOG_ERR("[N]InvDiscType[%u]", type); + return -EINVAL; + } + + qev = calloc(1, sizeof(*qev)); + assert(qev); + + qev->type = BT_LE_GATTC_DISCOVER_EVENT; + + qev->gattc_discover.type = type; + qev->gattc_discover.conn_handle = conn_handle; + qev->gattc_discover.uuid = (uuid ? uuid->value : 0x0000); + qev->gattc_discover.params = params; + + err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GATT_EVENT, qev, sizeof(*qev)); + if (err) { + LOG_ERR("[N]GattPostDiscEvtFail[%d][%u]", err, type); + free(qev); + return err; + } + + return 0; +} + +int bt_le_nimble_gatt_post_disc_cmpl_event(uint16_t conn_handle, uint8_t status) +{ + struct bt_le_gatt_event_param *qev; + int err; + + LOG_DBG("[N]GattcDiscCmplEvtHdlr[%u][%02x]", conn_handle, status); + + qev = calloc(1, sizeof(*qev)); + assert(qev); + + qev->type = BT_LE_GATTC_DISC_CMPL_EVENT; + + qev->gattc_disc_cmpl.status = status; + qev->gattc_disc_cmpl.conn_handle = conn_handle; + + err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GATT_EVENT, qev, sizeof(*qev)); + if (err) { + LOG_ERR("[N]GattPostDiscCmplEvtFail[%d][%u][%02x]", err, conn_handle, status); + free(qev); + return err; + } + + return 0; +} + +static void handle_gatts_subscribe_event_safe(struct bt_le_gatts_subscribe_event *event) +{ + /* LOG_DBG("[N]HdlGattsSubEvt[%u][%u][%u][%u][%02x]", */ + /* event->conn_handle, event->attr_handle, event->cur_notify, */ + /* event->cur_indicate, event->reason); */ + + /* Note: + * For NimBLE Host, the attr_handle is the handle of characteristic value + * declaration. For CCCD, its attr_handle shall be incremented with 1. + */ + bt_le_host_lock(); + + bt_gatts_sub_changed(event->conn_handle, + event->attr_handle + 1, + event->cur_notify, + event->cur_indicate, + event->reason); + + bt_le_host_unlock(); + + bt_le_gatts_app_subscribe_event(event); +} + +static void handle_gattc_notify_rx_event_safe(struct bt_le_gattc_notify_rx_event *event) +{ + struct bt_gatt_subscribe_params *params; + struct gattc_sub *sub; + struct bt_conn *conn; + + LOG_DBG("[N]HdlGattcNtfRxEvt[%u][%u][%u]", + event->conn_handle, event->attr_handle, event->len); + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(event->conn_handle); + if (conn == NULL || conn->state != BT_CONN_CONNECTED) { + LOG_ERR("[N]NotConn[%d]", __LINE__); + goto end; + } + + sub = bt_gattc_sub_find(conn); + if (sub == NULL) { + goto end; + } + + SYS_SLIST_FOR_EACH_CONTAINER(&sub->list, params, node) { + if (params->ccc_handle != BT_GATT_AUTO_DISCOVER_CCC_HANDLE && + params->value_handle == event->attr_handle) { + if (params->notify) { + params->notify(conn, params, event->value, event->len); + } + } + } + +end: + if (event->value) { + free(event->value); + } + + bt_le_host_unlock(); +} + +static void handle_gatts_notify_tx_event_safe(struct bt_le_gatts_notify_tx_event *event) +{ + LOG_DBG("[N]HdlGattsNtfTxEvt[%u][%u][%u][%02x]", + event->conn_handle, event->attr_handle, event->is_notify, event->status); + + /* Currently we only handle this event for indication */ + if (event->is_notify) { + return; + } + + /* The event->status could be: + * - 0: Indication is sent successfully; + * - BLE_HS_EDONE: Confirm is received; + * - BLE_HS_ENOTCONN: Not connected; + * - BLE_HS_ETIMEOUT: ATT procedure times out. + */ + bt_le_host_lock(); + + bt_le_nimble_gatts_nrp_indicate_cb(event->conn_handle, event->attr_handle, event->status); + + bt_le_host_unlock(); +} + +void bt_le_nimble_gatt_handle_event(uint8_t *data, size_t data_len) +{ + struct bt_le_gatt_event_param *param; + + param = (struct bt_le_gatt_event_param *)data; + + /* LOG_DBG("[N]HdlGattEvt[%u]", param->type); */ + + switch (param->type) { + case BT_LE_GATT_MTU_CHANGE_EVENT: + bt_le_gatt_app_mtu_change_event(param->gatt_mtu_change.conn_handle, + param->gatt_mtu_change.mtu); + break; + + case BT_LE_GATTC_DISCOVER_EVENT: + handle_gattc_db_disc_event_safe(¶m->gattc_discover); + break; + + case BT_LE_GATTC_DISC_CMPL_EVENT: + bt_le_gattc_app_disc_cmpl_event(¶m->gattc_disc_cmpl); + break; + + case BT_LE_GATTS_SUBSCRIBE_EVENT: + handle_gatts_subscribe_event_safe(¶m->gatts_subscribe); + break; + + case BT_LE_GATTC_NOTIFY_RX_EVENT: + handle_gattc_notify_rx_event_safe(¶m->gattc_notify_rx); + break; + + case BT_LE_GATTS_NOTIFY_TX_EVENT: + handle_gatts_notify_tx_event_safe(¶m->gatts_notify_tx); + break; + + default: + assert(0); + break; + } + + free(data); +} + +uint16_t bt_le_nimble_gatt_get_mtu(struct bt_conn *conn) +{ + LOG_DBG("[N]GattGetMtu[%u]", conn->handle); + + return ble_att_mtu(conn->handle); +} + +ssize_t bt_le_nimble_gatts_attr_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, + void *buf, uint16_t buf_len, uint16_t offset, + const void *value, uint16_t value_len) +{ + uint16_t len; + + if (buf_len == UINT16_MAX) { + /* TODO: A better solution for using a variable for the cb pointer */ + struct bt_le_nimble_gatt_read_cb *cb = buf; + assert(cb->read_cb); + + len = cb->read_cb(cb->read_arg, offset, value, value_len); + } else { + assert(attr); + + LOG_DBG("[N]Hdl[%u]", attr->handle); + + if (offset >= value_len) { + LOG_WRN("[N]OffsetTooLarge[%u][%u]", offset, value_len); + return 0; + } + + len = MIN(buf_len, value_len - offset); + memcpy(buf, (uint8_t *)value + offset, len); + } + + LOG_DBG("[N]GattsAttrRd[%u]", len); + + return len; +} + +static int gatts_notify(struct bt_conn *conn, struct bt_gatt_notify_params *params) +{ + struct notify_data data; + struct bt_conn *conns; + uint8_t conns_count; + struct os_mbuf *om; + int rc = 0; + + memset(&data, 0, sizeof(data)); + + data.attr = params->attr; + data.handle = bt_gatt_attr_get_handle(data.attr); + + /* Lookup UUID if it was given */ + if (params->uuid) { + if (bt_gatts_find_attr_by_uuid(&data, params->uuid) == false) { + return -ENOENT; + } + + params->attr = data.attr; + } else { + if (data.handle == 0) { + LOG_WRN("[N]DataHdlZero"); + return -ENOENT; + } + } + + /* Check if attribute is a characteristic then adjust the handle */ + if (bt_uuid_cmp(data.attr->uuid, BT_UUID_GATT_CHRC) == 0) { + struct bt_gatt_chrc *chrc; + + assert(data.attr->user_data); + chrc = data.attr->user_data; + + if ((chrc->properties & BT_GATT_CHRC_NOTIFY) == 0) { + LOG_WRN("[N]NtfNotSupp[%u][%02x]", data.handle, chrc->properties); + return -EINVAL; + } + + data.handle = bt_gatt_attr_value_handle(data.attr); + + LOG_INF("[N]DataHdl[%u][%u]", data.attr->handle, data.handle); + } + + if (conn) { + om = ble_hs_mbuf_from_flat(params->data, params->len); + if (om == NULL) { + LOG_ERR("[N]NoMemForNtf[%u]", params->len); + return -ENOMEM; + } + + rc = ble_gatts_notify_custom(conn->handle, data.handle, om); + if (rc && rc != BLE_HS_ENOTCONN) { + LOG_ERR("[N]GattsNtfCustomFail[%d]", rc); + } + } else { + bt_conn_get_acl_conns(&conns, &conns_count); + + for (size_t i = 0; i < conns_count; i++) { + if (conns[i].state == BT_CONN_CONNECTED) { + om = ble_hs_mbuf_from_flat(params->data, params->len); + if (om == NULL) { + LOG_ERR("[N]NoMemForNtf[%u]", params->len); + return -ENOMEM; + } + + rc = ble_gatts_notify_custom(conns[i].handle, data.handle, om); + if (rc && rc != BLE_HS_ENOTCONN) { + LOG_ERR("[N]GattsNtfCustomFail[%d]", rc); + } + } + } + + /* For sending notifications to all connected peers, always return success */ + rc = 0; + } + + return rc; +} + +int bt_le_nimble_gatts_notify(struct bt_conn *conn, struct bt_gatt_notify_params *params) +{ + LOG_DBG("[N]GattsNtf[%u]", conn ? conn->handle : UINT16_MAX); + + return gatts_notify(conn, params); +} + +int bt_le_nimble_gatts_indicate(struct bt_conn *conn, struct bt_gatt_indicate_params *params) +{ + LOG_DBG("[N]GattsInd[%u]", conn ? conn->handle : UINT16_MAX); + + return bt_le_nimble_gatt_nrp_insert(conn, GATTS_NRP_INDICATE, params); +} + +int bt_le_nimble_gattc_disc_start(uint16_t conn_handle) +{ + LOG_DBG("[N]GattcDiscStart[%u]", conn_handle); + + return bt_le_nimble_gattc_db_auto_disc(conn_handle); +} + +int bt_le_nimble_gattc_discover(struct bt_conn *conn, struct bt_gatt_discover_params *params) +{ + ble_uuid16_t uuid = {0}; + + LOG_DBG("[N]GattcDisc[%u]", conn->handle); + + if (params->uuid) { + uuid.u.type = BLE_UUID_TYPE_16; + uuid.value = BT_UUID_16(params->uuid)->val; + } + + switch (params->type) { + case BT_GATT_DISCOVER_PRIMARY: + if (params->uuid) { + return bt_le_nimble_gattc_db_disc_svc_by_uuid(conn, &uuid, params); + } + + LOG_ERR("[N]NotSuppDiscAllPrimarySvcs"); + return -ENOTSUP; + + case BT_GATT_DISCOVER_INCLUDE: + return bt_le_nimble_gattc_db_find_inc_svcs(conn, params); + + case BT_GATT_DISCOVER_CHARACTERISTIC: + if (params->uuid) { + return bt_le_nimble_gattc_db_disc_chrs_by_uuid(conn, &uuid, params); + } + + return bt_le_nimble_gattc_db_disc_all_chrs(conn, params); + + case BT_GATT_DISCOVER_DESCRIPTOR: + assert(params->uuid); + + /* Only descriptors can be filtered */ + if (bt_uuid_cmp(params->uuid, BT_UUID_GATT_PRIMARY) == 0 || + bt_uuid_cmp(params->uuid, BT_UUID_GATT_SECONDARY) == 0 || + bt_uuid_cmp(params->uuid, BT_UUID_GATT_INCLUDE) == 0 || + bt_uuid_cmp(params->uuid, BT_UUID_GATT_CHRC) == 0) { + LOG_ERR("[N]InvDscToDisc[%02x]", params->uuid->type); + return -EINVAL; + } + + return bt_le_nimble_gattc_db_disc_all_dscs(conn, params); + + default: + LOG_ERR("[N]DiscNotSupp[%u]", params->type); + return -ENOTSUP; + } +} + +int bt_le_nimble_gattc_read(struct bt_conn *conn, struct bt_gatt_read_params *params) +{ + uint8_t type; + + if (params->handle_count == 0) { + type = GATTC_NRP_READ_BY_UUID; + } else if (params->single.offset) { + type = GATTC_NRP_READ_LONG; + } else { + type = GATTC_NRP_READ_SINGLE; + } + + LOG_DBG("[N]GattcRd[%u][%u]", conn->handle, type); + + return bt_le_nimble_gatt_nrp_insert(conn, type, params); +} + +int bt_le_nimble_gattc_write(struct bt_conn *conn, struct bt_gatt_write_params *params) +{ + LOG_DBG("[N]GattcWr[%u]", conn->handle); + + return bt_le_nimble_gatt_nrp_insert(conn, GATTC_NRP_WRITE_REQ, params); +} + +int bt_le_nimble_gattc_write_without_rsp(struct bt_conn *conn, uint16_t handle, + const void *data, uint16_t length) +{ + LOG_DBG("[N]GattcWrCmd[%u][%u][%u]", conn->handle, handle, length); + + return ble_gattc_write_no_rsp_flat(conn->handle, handle, data, length); +} + +int bt_le_nimble_gattc_write_ccc(struct bt_conn *conn, struct bt_gatt_subscribe_params *params) +{ + /* LOG_DBG("[N]GattcWrCcc[%u]", conn->handle); */ + + return bt_le_nimble_gatt_nrp_insert(conn, GATTC_NRP_SUBSCRIBE, params); +} diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/gatt/gatt.db.c b/components/bt/esp_ble_audio/host/adapter/nimble/gatt/gatt.db.c new file mode 100644 index 0000000000..acc3007fc3 --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/gatt/gatt.db.c @@ -0,0 +1,1440 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include <../host/conn_internal.h> + +#include "host/ble_hs.h" +#include "host/ble_att.h" +#include "host/ble_gatt.h" +#include "host/ble_hs_mbuf.h" + +#include "common/host.h" + +static int gattc_db_find_inc_svcs_cb_safe(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_svc *svc, + void *arg); + +static int gattc_db_disc_all_inc_chrs_cb_safe(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_chr *chrc, + void *arg); + +static int gattc_db_disc_all_chrs_cb_safe(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_chr *chrc, + void *arg); + +static int gattc_db_disc_all_inc_dscs_cb_safe(uint16_t conn_handle, + const struct ble_gatt_error *error, + uint16_t chr_val_handle, + const struct ble_gatt_dsc *dsc, + void *arg); + +static int gattc_db_disc_all_dscs_cb_safe(uint16_t conn_handle, + const struct ble_gatt_error *error, + uint16_t chr_val_handle, + const struct ble_gatt_dsc *dsc, + void *arg); + +static int gattc_db_enable_notify_cb_safe(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + void *arg); + +struct gattc_db_svc { + struct ble_gatt_svc svc; /* Information of this service */ + + uint8_t inc_svc_disc : 1; + uint8_t chrc_disc : 1; + uint8_t dsc_disc : 1; + uint8_t cccd_write : 1; + + size_t inc_svc_num; /* Number of included services */ + + sys_slist_t inc_svc_list; /* List of the included services of this service */ + sys_slist_t chrc_list; /* List of the characteristics of this service */ + + sys_snode_t node; +}; + +struct gattc_db_inc_svc { + uint16_t attr_handle; /* Attribute handle of Include declaration */ + + struct ble_gatt_svc svc; /* Information of this included service */ + + uint8_t chrc_disc : 1; + uint8_t dsc_disc : 1; + uint8_t is_primary : 1; + + sys_slist_t chrc_list; /* List of the characteristics of this included service */ + + sys_snode_t node; +}; + +struct gattc_db_chrc { + struct ble_gatt_chr chrc; /* Information of this characteristic */ + + uint8_t cccd_write : 1; + + struct ble_gatt_dsc cccd; /* For each characteristic, only store the CCCD information */ + + sys_snode_t node; +}; + +struct gattc_db_dsc { + struct ble_gatt_dsc dsc; /* Information of this descriptor */ + + sys_snode_t node; +}; + +static struct gattc_db { + uint16_t conn_handle; + enum { + DISC_IDLE = 0, + DISC_IN_PROGRESS, + DISC_SUCCESS, + DISC_FAIL, + } status; + sys_slist_t svc_list; /* List of the GATT server database of the connection */ +} gattc_db[CONFIG_BT_MAX_CONN] = { + [0 ...(CONFIG_BT_MAX_CONN - 1)] = { + .conn_handle = UINT16_MAX, + .status = DISC_IDLE, + }, +}; + +static struct gattc_db *gattc_db_add(uint16_t conn_handle) +{ + for (size_t i = 0; i < ARRAY_SIZE(gattc_db); i++) { + if (gattc_db[i].conn_handle == UINT16_MAX) { + gattc_db[i].conn_handle = conn_handle; + sys_slist_init(&gattc_db[i].svc_list); + + return &gattc_db[i]; + } + } + + return NULL; +} + +static struct gattc_db *gattc_db_find(uint16_t conn_handle) +{ + for (size_t i = 0; i < ARRAY_SIZE(gattc_db); i++) { + if (gattc_db[i].conn_handle == conn_handle) { + return &gattc_db[i]; + } + } + + return NULL; +} + +static void gattc_db_chrc_clear(sys_slist_t *chrc_list) +{ + struct gattc_db_chrc *achrc; + sys_snode_t *node; + + while ((node = sys_slist_get(chrc_list)) != NULL) { + achrc = SYS_SLIST_CONTAINER(node, achrc, node); + free(achrc); + } +} + +static void gattc_db_del(struct gattc_db *adb) +{ + struct gattc_db_inc_svc *ainc_svc; + struct gattc_db_svc *asvc; + sys_snode_t *node; + + assert(adb); + + while ((node = sys_slist_get(&adb->svc_list)) != NULL) { + asvc = SYS_SLIST_CONTAINER(node, asvc, node); + + while ((node = sys_slist_get(&asvc->inc_svc_list)) != NULL) { + ainc_svc = SYS_SLIST_CONTAINER(node, ainc_svc, node); + gattc_db_chrc_clear(&ainc_svc->chrc_list); + free(ainc_svc); + } + + gattc_db_chrc_clear(&asvc->chrc_list); + free(asvc); + } + + adb->conn_handle = UINT16_MAX; + adb->status = DISC_IDLE; + sys_slist_init(&adb->svc_list); +} + +static void gattc_db_svc_insert(struct gattc_db *adb, const struct ble_gatt_svc *svc) +{ + struct gattc_db_svc *asvc; + + asvc = calloc(1, sizeof(*asvc)); + assert(asvc); + + memcpy(&asvc->svc, svc, sizeof(asvc->svc)); + sys_slist_init(&asvc->inc_svc_list); + sys_slist_init(&asvc->chrc_list); + + sys_slist_append(&adb->svc_list, &asvc->node); + + LOG_DBG("[N]GattcDbSvcInsert"); +} + +static void gattc_db_inc_svc_insert(struct gattc_db_svc *asvc, const struct ble_gatt_svc *inc_svc) +{ + struct gattc_db_inc_svc *ainc_svc; + + ainc_svc = calloc(1, sizeof(*ainc_svc)); + assert(ainc_svc); + + memcpy(&ainc_svc->svc, inc_svc, sizeof(ainc_svc->svc)); + sys_slist_init(&ainc_svc->chrc_list); + + sys_slist_append(&asvc->inc_svc_list, &ainc_svc->node); + asvc->inc_svc_num += 1; + + /* Record the attribute handle of Include declaration. + * TODO: + * Update attr_handle properly when CONFIG_BT_NIMBLE_INCL_SVC_DISCOVERY is enabled. + */ + ainc_svc->attr_handle = asvc->svc.start_handle + asvc->inc_svc_num; + + LOG_DBG("[N]GattcDbIncSvcInsert[%u][%u]", asvc->svc.start_handle, asvc->inc_svc_num); +} + +static void gattc_db_chrc_insert(sys_slist_t *chrc_list, const struct ble_gatt_chr *chrc) +{ + struct gattc_db_chrc *achrc; + + achrc = calloc(1, sizeof(*achrc)); + assert(achrc); + + memcpy(&achrc->chrc, chrc, sizeof(achrc->chrc)); + + sys_slist_append(chrc_list, &achrc->node); + + LOG_DBG("[N]GattcDbChrcInsert"); +} + +static void gattc_db_dsc_cccd_store(sys_slist_t *chrc_list, + uint16_t chr_val_handle, + const struct ble_gatt_dsc *dsc) +{ + struct gattc_db_chrc *achrc; + + /* LOG_DBG("[N]GattcDbDscCccdStore[%u]", chr_val_handle); */ + + SYS_SLIST_FOR_EACH_CONTAINER(chrc_list, achrc, node) { + if (achrc->chrc.val_handle == dsc->handle - 1) { + if (achrc->cccd.handle) { + LOG_WRN("[N]GattcDbCccAlreadyUpd[%u][%u]", chr_val_handle, achrc->cccd.handle); + return; + } + + /* LOG_DBG("[N]GattcDbCccUpd[%u][%u]", achrc->chrc.val_handle, dsc->handle); */ + + memcpy(&achrc->cccd, dsc, sizeof(achrc->cccd)); + return; + } + } +} + +static struct gattc_db_svc *gattc_db_disc_find(struct gattc_db *adb) +{ + struct gattc_db_svc *asvc; + + /* LOG_DBG("[N]GattcDbDiscFind"); */ + + SYS_SLIST_FOR_EACH_CONTAINER(&adb->svc_list, asvc, node) { + /* LOG_DBG("[N]GattcDbSvc[%u][%u][%u][%u]", */ + /* asvc->inc_svc_disc, asvc->chrc_disc, */ + /* asvc->dsc_disc, asvc->cccd_write); */ + + if (asvc->inc_svc_disc == 0 || + asvc->chrc_disc == 0 || + asvc->dsc_disc == 0 || + asvc->cccd_write == 0) { + return asvc; + } + } + + return NULL; +} + +static int gattc_db_disc_start(struct gattc_db *adb, struct gattc_db_svc *asvc) +{ + struct gattc_db_inc_svc *ainc_svc; + struct gattc_db_chrc *achrc; + uint16_t value = 0; + int rc; + + /* LOG_DBG("[N]GattcDbDiscStart[%u]", adb->conn_handle); */ + + if (asvc->inc_svc_disc == 0) { + LOG_DBG("[N]GattcDbIncSvcDisc[%u][%u]", asvc->svc.start_handle, asvc->svc.end_handle); + + /* TODO: + * Enable CONFIG_BT_NIMBLE_INCL_SVC_DISCOVERY for discovering included services. + */ + rc = ble_gattc_find_inc_svcs(adb->conn_handle, + asvc->svc.start_handle, + asvc->svc.end_handle, + gattc_db_find_inc_svcs_cb_safe, + asvc); + if (rc) { + LOG_ERR("[N]GattcDbFindIncSvcsFail[%d]", rc); + adb->status = DISC_FAIL; + } else { + adb->status = DISC_IN_PROGRESS; + } + return rc; + } + + /* Start characteristic discovery, the included service if existed + * will be discovered firstly. + */ + SYS_SLIST_FOR_EACH_CONTAINER(&asvc->inc_svc_list, ainc_svc, node) { + if (ainc_svc->chrc_disc == 0) { + LOG_DBG("[N]GattcDbIncChrcDisc[%u][%u]", ainc_svc->svc.start_handle, ainc_svc->svc.end_handle); + + rc = ble_gattc_disc_all_chrs(adb->conn_handle, + ainc_svc->svc.start_handle, + ainc_svc->svc.end_handle, + gattc_db_disc_all_inc_chrs_cb_safe, + ainc_svc); + if (rc) { + LOG_ERR("[N]GattcDbDiscAllChrsFail[%d]", rc); + adb->status = DISC_FAIL; + } else { + adb->status = DISC_IN_PROGRESS; + } + return rc; + } + } + + /* Discover the characteristics of this service (all the included services are done) */ + if (asvc->chrc_disc == 0) { + LOG_DBG("[N]GattcDbChrcDisc[%u][%u]", asvc->svc.start_handle, asvc->svc.end_handle); + + rc = ble_gattc_disc_all_chrs(adb->conn_handle, + asvc->svc.start_handle, + asvc->svc.end_handle, + gattc_db_disc_all_chrs_cb_safe, + asvc); + if (rc) { + LOG_ERR("[N]GattcDbDiscAllChrsFail[%d]", rc); + adb->status = DISC_FAIL; + } else { + adb->status = DISC_IN_PROGRESS; + } + return rc; + } + + SYS_SLIST_FOR_EACH_CONTAINER(&asvc->inc_svc_list, ainc_svc, node) { + if (ainc_svc->dsc_disc == 0) { + /* If trying to discover CCCD of a characteristic, then the service + * end_handle must be not smaller than start_handle plus 4, i.e. at + * least 4 attributes shall exist in the service. They are: + * - Service declaration + * - Characteristic declaration + * - Characteristic value + * - Characteristic CCCD + */ + LOG_DBG("[N]GattcDbIncDscDisc[%u][%u]", ainc_svc->svc.start_handle, ainc_svc->svc.end_handle); + + if (ainc_svc->svc.end_handle >= ainc_svc->svc.start_handle + 4) { + rc = ble_gattc_disc_all_dscs(adb->conn_handle, + ainc_svc->svc.start_handle, + ainc_svc->svc.end_handle, + gattc_db_disc_all_inc_dscs_cb_safe, + ainc_svc); + if (rc) { + LOG_ERR("[N]GattcDbDiscAllDscsFail[%d]", rc); + adb->status = DISC_FAIL; + } else { + adb->status = DISC_IN_PROGRESS; + } + return rc; + } + + ainc_svc->dsc_disc = 1; + } + } + + if (asvc->dsc_disc == 0) { + /* If trying to discover CCCD of a characteristic, then the service + * end_handle must be not smaller than start_handle plus 4, i.e. at + * least 4 attributes shall exist in the service. They are: + * - Service declaration + * - Characteristic declaration + * - Characteristic value + * - Characteristic CCCD + */ + LOG_DBG("[N]GattcDbDscDisc[%u][%u]", asvc->svc.start_handle, asvc->svc.end_handle); + + if (asvc->svc.end_handle >= asvc->svc.start_handle + 4) { + rc = ble_gattc_disc_all_dscs(adb->conn_handle, + asvc->svc.start_handle, + asvc->svc.end_handle, + gattc_db_disc_all_dscs_cb_safe, + asvc); + if (rc) { + LOG_ERR("[N]GattcDbDiscAllDscsFail[%d]", rc); + adb->status = DISC_FAIL; + } else { + adb->status = DISC_IN_PROGRESS; + } + return rc; + } + + asvc->dsc_disc = 1; + } + + SYS_SLIST_FOR_EACH_CONTAINER(&asvc->inc_svc_list, ainc_svc, node) { + SYS_SLIST_FOR_EACH_CONTAINER(&ainc_svc->chrc_list, achrc, node) { + LOG_DBG("[N]GattcDbIncCccWr[%u][%u]", achrc->cccd.handle, achrc->cccd_write); + + if (achrc->cccd.handle && achrc->cccd_write == 0) { + /* Reset value for each characteristic */ + value = 0; + + if (achrc->chrc.properties & BLE_GATT_CHR_PROP_NOTIFY) { + value |= BT_GATT_CCC_NOTIFY; + } + if (achrc->chrc.properties & BLE_GATT_CHR_PROP_INDICATE) { + value |= BT_GATT_CCC_INDICATE; + } + + rc = ble_gattc_write_flat(adb->conn_handle, + achrc->cccd.handle, + &value, sizeof(value), + gattc_db_enable_notify_cb_safe, + achrc); + if (rc) { + LOG_ERR("[N]GattcDbWrFlatFail[%d]", rc); + adb->status = DISC_FAIL; + } else { + adb->status = DISC_IN_PROGRESS; + } + return rc; + } + } + } + + SYS_SLIST_FOR_EACH_CONTAINER(&asvc->chrc_list, achrc, node) { + /* LOG_DBG("[N]GattcDbCccWr[%u][%u]", achrc->cccd.handle, achrc->cccd_write); */ + + if (achrc->cccd.handle && achrc->cccd_write == 0) { + /* Reset value for each characteristic */ + value = 0; + + if (achrc->chrc.properties & BLE_GATT_CHR_PROP_NOTIFY) { + value |= BT_GATT_CCC_NOTIFY; + } + if (achrc->chrc.properties & BLE_GATT_CHR_PROP_INDICATE) { + value |= BT_GATT_CCC_INDICATE; + } + + rc = ble_gattc_write_flat(adb->conn_handle, + achrc->cccd.handle, + &value, sizeof(value), + gattc_db_enable_notify_cb_safe, + achrc); + if (rc) { + LOG_ERR("[N]GattcDbWrFlatFail[%d]", rc); + adb->status = DISC_FAIL; + } else { + adb->status = DISC_IN_PROGRESS; + } + return rc; + } + } + + LOG_DBG("[N]GattcDbDiscEnd"); + + asvc->cccd_write = 1; + adb->status = DISC_SUCCESS; + + return 0; +} + +static bool gattc_inc_svc_is_primary(struct gattc_db *adb, + struct gattc_db_inc_svc *ainc_svc) +{ + struct gattc_db_svc *asvc; + + LOG_DBG("[N]GattcDbIncSvcIsPrimary"); + + SYS_SLIST_FOR_EACH_CONTAINER(&adb->svc_list, asvc, node) { + if (ainc_svc->svc.start_handle == asvc->svc.start_handle && + ainc_svc->svc.end_handle == asvc->svc.end_handle) { + if (ble_uuid_cmp(&ainc_svc->svc.uuid.u, &asvc->svc.uuid.u)) { + LOG_WRN("[N]GattcDbInvSvcMismatch[%u][%u][%u][%u][%04x][%04x]", + ainc_svc->svc.start_handle, ainc_svc->svc.end_handle, + asvc->svc.start_handle, asvc->svc.end_handle, + ainc_svc->svc.uuid.u16.value, asvc->svc.uuid.u16.value); + return false; + } + + LOG_DBG("[N]GattcDbIncSvcPrimary[%u][%u][%04x]", + ainc_svc->svc.start_handle, ainc_svc->svc.end_handle, + ainc_svc->svc.uuid.u16.value); + return true; + } + } + + return false; +} + +static void gattc_inc_svc_extra_check(struct gattc_db *adb) +{ + struct gattc_db_inc_svc *ainc_svc; + struct gattc_db_svc *asvc; + + LOG_DBG("[N]GattcDbIncSvcExtraCheck"); + + SYS_SLIST_FOR_EACH_CONTAINER(&adb->svc_list, asvc, node) { + SYS_SLIST_FOR_EACH_CONTAINER(&asvc->inc_svc_list, ainc_svc, node) { + ainc_svc->is_primary = gattc_inc_svc_is_primary(adb, ainc_svc); + } + } +} + +static void gattc_db_disc(struct gattc_db *adb, uint8_t status) +{ + struct gattc_db_svc *asvc = NULL; + int rc; + + /* LOG_DBG("[N]GattcDbDisc"); */ + + /* Delete the gatt client database and notify the discovery failure + * to the upper layer. + */ + if (status == DISC_FAIL) { + gattc_db_del(adb); + + bt_le_nimble_gatt_post_disc_cmpl_event(adb->conn_handle, 0x01); + return; + } + + while (1) { + asvc = gattc_db_disc_find(adb); + if (asvc == NULL) { + /* All the GATT server database is discovered */ + + /* Check if any included service is a primary service */ + gattc_inc_svc_extra_check(adb); + + bt_le_nimble_gatt_post_disc_cmpl_event(adb->conn_handle, 0x00); + break; + } + + rc = gattc_db_disc_start(adb, asvc); + if (rc) { + /* If the discovery of this gatt client database fails, + * we will delete the gatt client database and post the + * discovery completion event. + */ + gattc_db_del(adb); + + bt_le_nimble_gatt_post_disc_cmpl_event(adb->conn_handle, 0x01); + break; + } + + if (adb->status == DISC_IN_PROGRESS) { + break; + } + + /* If the discovery of this gatt client database is completed, + * we will continue and try to find the next to-be-discovered + * gatt client database. + */ + } +} + +static int gattc_db_disc_all_svcs_cb_safe(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_svc *svc, + void *arg) +{ + struct gattc_db *adb; + int rc = 0; + + /* LOG_DBG("[N]GattcDbDiscAllSvcsCb[%u][%04x]", conn_handle, error->status); */ + + bt_le_host_lock(); + + adb = arg; + assert(adb); + assert(adb->conn_handle == conn_handle); + + switch (error->status) { + case 0: + assert(svc); + + LOG_DBG("[N]GattcDbDiscAllSvcs[%s][%u][%u]", + audio_svc_uuid_to_str(svc->uuid.u16.value), + svc->start_handle, svc->end_handle); + + gattc_db_svc_insert(adb, svc); + break; + + case BLE_HS_EDONE: + break; + + default: + LOG_WRN("[N]GattcDbDiscAllSvcsStatus[%04x]", error->status); + rc = error->status; + break; + } + + if (error->status) { + if (error->status == BLE_HS_EDONE) { + gattc_db_disc(adb, DISC_SUCCESS); + } else { + gattc_db_disc(adb, DISC_FAIL); + } + } + + bt_le_host_unlock(); + + return rc; +} + +static int gattc_db_find_inc_svcs_cb_safe(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_svc *svc, + void *arg) +{ + struct gattc_db_svc *asvc; + struct gattc_db *adb; + int rc = 0; + + asvc = arg; + assert(asvc); + + /* LOG_DBG("[N]GattcDbFindIncSvcsCb[%u][%04x]", conn_handle, error->status); */ + + bt_le_host_lock(); + + adb = gattc_db_find(conn_handle); + if (adb == NULL) { + LOG_ERR("[N]GattcDbNotFound"); + rc = -ENODEV; + goto end; + } + + switch (error->status) { + case 0: + assert(svc); + + LOG_DBG("[N]GattcDbFindIncSvcs[%s][%u][%u]", + audio_svc_uuid_to_str(svc->uuid.u16.value), + svc->start_handle, svc->end_handle); + + gattc_db_inc_svc_insert(asvc, svc); + break; + + case BLE_HS_EDONE: + break; + + default: + rc = error->status; + break; + } + + if (error->status) { + if (error->status == BLE_HS_EDONE || + error->status == BLE_HS_EINVAL) { + /* If a service of the remote GATT server: + * - Has an included service; + * - Only have 2 attributes, i.e. Service declaration and + * Include declaration; + * - Not the last service within the remote GATT database; + * + * These will cause BLE_HS_EINVAL returned while finding + * included services, mark the included service discovery + * as completed to prevent the discovery state machine from + * stalling. + * + * Mark the included service discovery as completed. + */ + asvc->inc_svc_disc = 1; + + gattc_db_disc(adb, DISC_SUCCESS); + } else { + LOG_WRN("[N]GattcDbFindIncSvcsStatus[%04x]", error->status); + gattc_db_disc(adb, DISC_FAIL); + } + } + +end: + bt_le_host_unlock(); + + return rc; +} + +static int gattc_db_disc_all_inc_chrs_cb_safe(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_chr *chrc, + void *arg) +{ + struct gattc_db_inc_svc *ainc_svc; + struct gattc_db *adb; + int rc = 0; + + ainc_svc = arg; + assert(ainc_svc); + + /* LOG_DBG("[N]GattcDbDiscAllIncChrsCb[%u][%04x]", conn_handle, error->status); */ + + bt_le_host_lock(); + + adb = gattc_db_find(conn_handle); + if (adb == NULL) { + LOG_ERR("[N]GattcDbNotFound"); + rc = -ENODEV; + goto end; + } + + switch (error->status) { + case 0: + assert(chrc); + + LOG_DBG("[N]GattcDbDiscAllIncChrs[%u][%u]", chrc->def_handle, chrc->val_handle); + + gattc_db_chrc_insert(&ainc_svc->chrc_list, chrc); + break; + + case BLE_HS_EDONE: + break; + + default: + LOG_WRN("[N]GattcDbDiscAllIncChrsStatus[%04x]", error->status); + rc = error->status; + break; + } + + if (error->status) { + if (error->status == BLE_HS_EDONE) { + /* Mark the characteristic discovery as completed */ + ainc_svc->chrc_disc = 1; + + gattc_db_disc(adb, DISC_SUCCESS); + } else { + gattc_db_disc(adb, DISC_FAIL); + } + } + +end: + bt_le_host_unlock(); + + return rc; +} + +static int gattc_db_disc_all_chrs_cb_safe(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_chr *chrc, + void *arg) +{ + struct gattc_db_svc *asvc; + struct gattc_db *adb; + int rc = 0; + + asvc = arg; + assert(asvc); + + /* LOG_DBG("[N]GattcDbDiscAllChrsCb[%u][%04x]", conn_handle, error->status); */ + + bt_le_host_lock(); + + adb = gattc_db_find(conn_handle); + if (adb == NULL) { + LOG_ERR("[N]GattcDbNotFound"); + rc = -ENODEV; + goto end; + } + + switch (error->status) { + case 0: + assert(chrc); + + LOG_DBG("[N]GattcDbDiscAllChrs[%u][%u]", chrc->def_handle, chrc->val_handle); + + gattc_db_chrc_insert(&asvc->chrc_list, chrc); + break; + + case BLE_HS_EDONE: + break; + + default: + LOG_WRN("[N]GattcDbDiscAllChrsStatus[%04x]", error->status); + rc = error->status; + break; + } + + if (error->status) { + if (error->status == BLE_HS_EDONE) { + /* Mark the characteristic discovery as completed */ + asvc->chrc_disc = 1; + + gattc_db_disc(adb, DISC_SUCCESS); + } else { + gattc_db_disc(adb, DISC_FAIL); + } + } + +end: + bt_le_host_unlock(); + + return rc; +} + +static int gattc_db_disc_all_inc_dscs_cb_safe(uint16_t conn_handle, + const struct ble_gatt_error *error, + uint16_t chr_val_handle, + const struct ble_gatt_dsc *dsc, + void *arg) +{ + struct gattc_db_inc_svc *ainc_svc; + struct gattc_db *adb; + int rc = 0; + + ainc_svc = arg; + assert(ainc_svc); + + LOG_DBG("[N]GattcDbDiscAllIncDscsCb[%u][%04x][%u]", + conn_handle, error->status, chr_val_handle); + + bt_le_host_lock(); + + adb = gattc_db_find(conn_handle); + if (adb == NULL) { + LOG_ERR("[N]GattcDbNotFound"); + rc = -ENODEV; + goto end; + } + + switch (error->status) { + case 0: + assert(dsc); + + if (dsc->uuid.u.type == BLE_UUID_TYPE_16 && + dsc->uuid.u16.value == BT_UUID_GATT_CCC_VAL) { + LOG_DBG("[N]GattcDbDiscAllIncDscs[%u][%u]", chr_val_handle, dsc->handle); + + gattc_db_dsc_cccd_store(&ainc_svc->chrc_list, chr_val_handle, dsc); + } + break; + + case BLE_HS_EDONE: + break; + + default: + LOG_WRN("[N]GattcDbDiscAllIncDscsStatus[%04x]", error->status); + rc = error->status; + break; + } + + if (error->status) { + if (error->status == BLE_HS_EDONE) { + /* Mark the descriptor discovery as completed */ + ainc_svc->dsc_disc = 1; + + gattc_db_disc(adb, DISC_SUCCESS); + } else { + gattc_db_disc(adb, DISC_FAIL); + } + } + +end: + bt_le_host_unlock(); + + return rc; +} + +static int gattc_db_disc_all_dscs_cb_safe(uint16_t conn_handle, + const struct ble_gatt_error *error, + uint16_t chr_val_handle, + const struct ble_gatt_dsc *dsc, + void *arg) +{ + struct gattc_db_svc *asvc; + struct gattc_db *adb; + int rc = 0; + + asvc = arg; + assert(asvc); + + /* LOG_DBG("[N]GattcDbDiscAllDscsCb[%u][%04x][%u]", */ + /* conn_handle, error->status, chr_val_handle); */ + + bt_le_host_lock(); + + adb = gattc_db_find(conn_handle); + if (adb == NULL) { + LOG_ERR("[N]GattcDbNotFound"); + rc = -ENODEV; + goto end; + } + + switch (error->status) { + case 0: + assert(dsc); + + if (dsc->uuid.u.type == BLE_UUID_TYPE_16 && + dsc->uuid.u16.value == BT_UUID_GATT_CCC_VAL) { + LOG_DBG("[N]GattcDbDiscAllDscs[%u]", dsc->handle); + + gattc_db_dsc_cccd_store(&asvc->chrc_list, chr_val_handle, dsc); + } + break; + + case BLE_HS_EDONE: + break; + + default: + LOG_WRN("[N]GattcDbDiscAllDscsStatus[%04x]", error->status); + rc = error->status; + break; + } + + if (error->status) { + if (error->status == BLE_HS_EDONE) { + /* Mark the descriptor discovery as completed */ + asvc->dsc_disc = 1; + + gattc_db_disc(adb, DISC_SUCCESS); + } else { + gattc_db_disc(adb, DISC_FAIL); + } + } + +end: + bt_le_host_unlock(); + + return rc; +} + +static int gattc_db_enable_notify_cb_safe(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + void *arg) +{ + struct gattc_db_chrc *achrc; + struct gattc_db *adb; + int rc = 0; + + achrc = arg; + assert(achrc); + + /* LOG_DBG("[N]GattcDbEnableNtfCb[%u][%04x]", conn_handle, error->status); */ + + bt_le_host_lock(); + + adb = gattc_db_find(conn_handle); + if (adb == NULL) { + LOG_ERR("[N]GattcDbNotFound"); + rc = -ENODEV; + goto end; + } + + switch (error->status) { + case 0: + assert(attr); + LOG_DBG("[N]GattcDbEnableNotify[%u]", attr->handle); + break; + + case BLE_HS_EDONE: + break; + + default: + LOG_WRN("[N]GattcDbEnableNotifyStatus[%04x]", error->status); + rc = error->status; + break; + } + + /* Mark the CCCD write as completed */ + achrc->cccd_write = 1; + + gattc_db_disc(adb, DISC_SUCCESS); + +end: + bt_le_host_unlock(); + + return rc; +} + +static int handle_gattc_disc_svc_by_uuid(struct bt_conn *conn, ble_uuid16_t *uuid, + struct bt_gatt_discover_params *params) +{ + struct bt_gatt_service_val svc = {0}; + struct bt_uuid_16 svc_uuid = {0}; + struct bt_gatt_attr attr = {0}; + struct gattc_db_svc *asvc; + struct gattc_db *adb; + uint8_t ret; + + LOG_DBG("[N]GattcDbHdlDiscSvcByUuid[%u]", conn->handle); + + ret = BT_GATT_ITER_CONTINUE; + + adb = gattc_db_find(conn->handle); + if (adb == NULL) { + LOG_ERR("[N]GattcDbNotFound"); + goto end; + } + + SYS_SLIST_FOR_EACH_CONTAINER(&adb->svc_list, asvc, node) { + if (asvc->svc.uuid.u.type != uuid->u.type || + asvc->svc.uuid.u16.value != uuid->value) { + continue; + } + + svc_uuid.uuid.type = BT_UUID_TYPE_16; + svc_uuid.val = asvc->svc.uuid.u16.value; + + svc.uuid = &svc_uuid.uuid; + svc.end_handle = asvc->svc.end_handle; + + attr.user_data = &svc; + attr.handle = asvc->svc.start_handle; + attr.uuid = params->uuid; + + ret = params->func(conn, &attr, params); + + /* LOG_DBG("[N]GattcDbSvcIter%s", ret == BT_GATT_ITER_CONTINUE ? "Cont" : "Stop"); */ + + if (ret == BT_GATT_ITER_STOP) { + goto end; + } + } + +end: + if (ret == BT_GATT_ITER_CONTINUE) { + params->func(conn, NULL, params); + } + + return 0; +} + +static int handle_gattc_find_inc_svcs(struct bt_conn *conn, + struct bt_gatt_discover_params *params) +{ + struct bt_gatt_include inc_svc = {0}; + struct gattc_db_inc_svc *ainc_svc; + struct bt_uuid_16 svc_uuid = {0}; + struct bt_gatt_attr attr = {0}; + struct gattc_db_svc *asvc; + struct gattc_db *adb; + uint8_t ret; + + LOG_DBG("[N]GattcDbHdlFindIncSvcs[%u]", conn->handle); + + ret = BT_GATT_ITER_CONTINUE; + + adb = gattc_db_find(conn->handle); + if (adb == NULL) { + LOG_ERR("[N]GattcDbNotFound"); + goto end; + } + + SYS_SLIST_FOR_EACH_CONTAINER(&adb->svc_list, asvc, node) { + SYS_SLIST_FOR_EACH_CONTAINER(&asvc->inc_svc_list, ainc_svc, node) { + /* Make sure the attribute handle of Include declaration is within range */ + if (ainc_svc->attr_handle < params->start_handle || + ainc_svc->attr_handle > params->end_handle) { + continue; + } + + svc_uuid.uuid.type = BT_UUID_TYPE_16; + svc_uuid.val = ainc_svc->svc.uuid.u16.value; + + inc_svc.uuid = &svc_uuid.uuid; + inc_svc.start_handle = ainc_svc->svc.start_handle; + inc_svc.end_handle = ainc_svc->svc.end_handle; + + attr.user_data = &inc_svc; + /* TODO: + * When CONFIG_BT_NIMBLE_INCL_SVC_DISCOVERY is enabled, use ainc_svc->attr_handle here. + */ + attr.handle = params->start_handle; /* Include declaration handle */ + + ret = params->func(conn, &attr, params); + + /* LOG_DBG("[N]GattcDbSvcIter%s", ret == BT_GATT_ITER_CONTINUE ? "Cont" : "Stop"); */ + + if (ret == BT_GATT_ITER_STOP) { + goto end; + } + } + } + +end: + if (ret == BT_GATT_ITER_CONTINUE) { + params->func(conn, NULL, params); + } + + return 0; +} + +static uint8_t gattc_disc_chr_each(struct bt_conn *conn, + struct gattc_db_chrc *achrc, + struct bt_gatt_discover_params *params) +{ + struct bt_uuid_16 chrc_uuid = {0}; + struct bt_gatt_attr attr = {0}; + struct bt_gatt_chrc chrc = {0}; + + /* Copy the full UUID based on actual type */ + switch (achrc->chrc.uuid.u.type) { + case BLE_UUID_TYPE_16: + chrc_uuid.uuid.type = BT_UUID_TYPE_16; + chrc_uuid.val = achrc->chrc.uuid.u16.value; + break; + default: + return BT_GATT_ITER_STOP; + } + + chrc.uuid = &chrc_uuid.uuid; + chrc.value_handle = achrc->chrc.val_handle; + chrc.properties = achrc->chrc.properties; + + attr.user_data = &chrc; + attr.handle = achrc->chrc.def_handle; + + /* LOG_DBG("[N]GattcDbDiscChrEach[%u][%s][%u][%u][%02x]", */ + /* conn->handle, bt_uuid_str(chrc.uuid), attr.handle, */ + /* chrc.value_handle, chrc.properties); */ + + return params->func(conn, &attr, params); +} + +static int handle_gattc_disc_chrs(struct bt_conn *conn, ble_uuid16_t *uuid, + struct bt_gatt_discover_params *params) +{ + struct gattc_db_inc_svc *ainc_svc; + struct gattc_db_chrc *achrc; + struct gattc_db_svc *asvc; + struct gattc_db *adb; + uint8_t ret; + + LOG_DBG("[N]GattcDbHdlDiscChrs[%u]", conn->handle); + + ret = BT_GATT_ITER_CONTINUE; + + adb = gattc_db_find(conn->handle); + if (adb == NULL) { + LOG_ERR("[N]GattcDbNotFound"); + goto end; + } + + SYS_SLIST_FOR_EACH_CONTAINER(&adb->svc_list, asvc, node) { + SYS_SLIST_FOR_EACH_CONTAINER(&asvc->inc_svc_list, ainc_svc, node) { + /* If the included service is a primary service, which means it still exists + * in the adb->svc_list, hence no need to find the characteristics here. + */ + if (ainc_svc->is_primary) { + continue; + } + + SYS_SLIST_FOR_EACH_CONTAINER(&ainc_svc->chrc_list, achrc, node) { + if (uuid && (achrc->chrc.uuid.u.type != uuid->u.type || + achrc->chrc.uuid.u16.value != uuid->value)) { + continue; + } + + /* Check if the characteristic value handle is within range */ + if (achrc->chrc.val_handle < params->start_handle || + achrc->chrc.val_handle > params->end_handle) { + continue; + } + + ret = gattc_disc_chr_each(conn, achrc, params); + + /* LOG_DBG("[N]GattcDbIncSvcIter%s", ret == BT_GATT_ITER_CONTINUE ? "Cont" : "Stop"); */ + + if (ret == BT_GATT_ITER_STOP) { + goto end; + } + } + } + + SYS_SLIST_FOR_EACH_CONTAINER(&asvc->chrc_list, achrc, node) { + if (uuid && (achrc->chrc.uuid.u.type != uuid->u.type || + achrc->chrc.uuid.u16.value != uuid->value)) { + continue; + } + + /* Check if the characteristic value handle is within range */ + if (achrc->chrc.val_handle < params->start_handle || + achrc->chrc.val_handle > params->end_handle) { + continue; + } + + ret = gattc_disc_chr_each(conn, achrc, params); + + /* LOG_DBG("[N]GattcDbSvcIter%s", ret == BT_GATT_ITER_CONTINUE ? "Cont" : "Stop"); */ + + if (ret == BT_GATT_ITER_STOP) { + goto end; + } + } + } + +end: + if (ret == BT_GATT_ITER_CONTINUE) { + params->func(conn, NULL, params); + } + + return 0; +} + +void handle_gattc_db_disc_event_safe(struct bt_le_gattc_discover_event *event) +{ + struct bt_conn *conn; + ble_uuid16_t uuid; + + LOG_DBG("[N]GattcDbHdlDiscEvt[%u][%u]", event->conn_handle, event->type); + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(event->conn_handle); + if (conn == NULL || conn->state != BT_CONN_CONNECTED) { + LOG_ERR("[N]GattcDbNotConn[%d]", __LINE__); + goto end; + } + + assert(event->params); + + switch (event->type) { + case GATTC_DISC_TYPE_SVC_BY_UUID: + uuid.u.type = BLE_UUID_TYPE_16; + uuid.value = event->uuid; + + handle_gattc_disc_svc_by_uuid(conn, &uuid, event->params); + break; + + case GATTC_DISC_TYPE_INC_SVCS: + handle_gattc_find_inc_svcs(conn, event->params); + break; + + case GATTC_DISC_TYPE_CHRS_BY_UUID: + uuid.u.type = BLE_UUID_TYPE_16; + uuid.value = event->uuid; + + handle_gattc_disc_chrs(conn, &uuid, event->params); + break; + + case GATTC_DISC_TYPE_ALL_CHRS: + handle_gattc_disc_chrs(conn, NULL, event->params); + break; + + default: + assert(0); + break; + } + +end: + bt_le_host_unlock(); +} + +int bt_le_nimble_gattc_db_disc_svc_by_uuid(struct bt_conn *conn, ble_uuid16_t *uuid, + struct bt_gatt_discover_params *params) +{ + LOG_DBG("[N]GattcDbDiscSvcByUuid[%u]", conn->handle); + + return bt_le_nimble_gatt_post_disc_event(conn->handle, uuid, params, GATTC_DISC_TYPE_SVC_BY_UUID); +} + +int bt_le_nimble_gattc_db_find_inc_svcs(struct bt_conn *conn, + struct bt_gatt_discover_params *params) +{ + LOG_DBG("[N]GattcDbFindIncSvcs[%u]", conn->handle); + + return bt_le_nimble_gatt_post_disc_event(conn->handle, NULL, params, GATTC_DISC_TYPE_INC_SVCS); +} + +int bt_le_nimble_gattc_db_disc_chrs_by_uuid(struct bt_conn *conn, ble_uuid16_t *uuid, + struct bt_gatt_discover_params *params) +{ + LOG_DBG("[N]GattcDbDiscChrsByUuid[%u]", conn->handle); + + return bt_le_nimble_gatt_post_disc_event(conn->handle, uuid, params, GATTC_DISC_TYPE_CHRS_BY_UUID); +} + +int bt_le_nimble_gattc_db_disc_all_chrs(struct bt_conn *conn, + struct bt_gatt_discover_params *params) +{ + LOG_DBG("[N]GattcDbDiscAllChrs[%u]", conn->handle); + + return bt_le_nimble_gatt_post_disc_event(conn->handle, NULL, params, GATTC_DISC_TYPE_ALL_CHRS); +} + +static int handle_gattc_disc_all_dscs(struct bt_conn *conn, + struct bt_gatt_discover_params *params) +{ + struct bt_gatt_subscribe_params *sub_params; + struct gattc_db_inc_svc *ainc_svc; + struct bt_gatt_attr *found = NULL; + struct bt_gatt_attr attr = {0}; + struct gattc_db_chrc *achrc; + struct gattc_db_svc *asvc; + struct gattc_db *adb; + int rc = 0; + + /* Note: + * For MCC, the procedures will be: + * - Find GMCS; + * - Find all characteristics of GMCS; + * - Enable notification of the characteristics; + * - Find included service (e.g. OTS); + * + * In this case, we will post events to the ISO task for finding GMCS + * and all its characteristics. + * But for enabling notification, if auto discovery is enabled (which + * is by default), the only thing needs to be done is updating the + * ccc_handle of each characteristic. In this case, no event will be + * posted to the ISO task, instead after finding all characteristics, + * we will directly do subscribe. + * And after all the subscription are done, we will post an event for + * finding the included service. + */ + + sub_params = params->sub_params; + assert(sub_params); + + LOG_DBG("[N]GattcDbHdlDiscAllDscs[%u][%u]", conn->handle, sub_params->value_handle); + + adb = gattc_db_find(conn->handle); + if (adb == NULL) { + LOG_ERR("[N]GattcDbNotFound"); + rc = -ENODEV; + goto end; + } + + SYS_SLIST_FOR_EACH_CONTAINER(&adb->svc_list, asvc, node) { + SYS_SLIST_FOR_EACH_CONTAINER(&asvc->inc_svc_list, ainc_svc, node) { + if (sub_params->value_handle < ainc_svc->svc.start_handle || + sub_params->value_handle > ainc_svc->svc.end_handle) { + continue; + } + + SYS_SLIST_FOR_EACH_CONTAINER(&ainc_svc->chrc_list, achrc, node) { + if (achrc->chrc.val_handle == sub_params->value_handle) { + if (achrc->cccd.handle) { + attr.handle = achrc->cccd.handle; + found = &attr; + } + + LOG_DBG("[N]GattcDbIncCccFound[%u]", achrc->cccd.handle); + goto end; + } + } + } + + if (sub_params->value_handle < asvc->svc.start_handle || + sub_params->value_handle > asvc->svc.end_handle) { + continue; + } + + SYS_SLIST_FOR_EACH_CONTAINER(&asvc->chrc_list, achrc, node) { + if (achrc->chrc.val_handle == sub_params->value_handle) { + if (achrc->cccd.handle) { + attr.handle = achrc->cccd.handle; + found = &attr; + } + + LOG_DBG("[N]GattcDbCccFound[%u]", achrc->cccd.handle); + goto end; + } + } + } + +end: + params->func(conn, found, params); + + return rc; +} + +int bt_le_nimble_gattc_db_disc_all_dscs(struct bt_conn *conn, + struct bt_gatt_discover_params *params) +{ + return handle_gattc_disc_all_dscs(conn, params); +} + +int bt_le_nimble_gattc_db_auto_disc(uint16_t conn_handle) +{ + /* The GATTC procedures will be: + * - Find all the primary services; + * - Find if any service is included by each primary service; + * - Find the characteristics of each Primary or Secondary service; + * - Find the descriptor of each characteristic of each service. + */ + struct gattc_db *adb; + int rc = 0; + + LOG_DBG("[N]GattcDbAutoDisc[%u]", conn_handle); + + adb = gattc_db_find(conn_handle); + if (adb) { + LOG_WRN("[N]GattcDbExist"); + return -EALREADY; + } + + adb = gattc_db_add(conn_handle); + if (adb == NULL) { + LOG_ERR("[N]GattcDbFull"); + return -ENOMEM; + } + + rc = ble_gattc_disc_all_svcs(conn_handle, gattc_db_disc_all_svcs_cb_safe, adb); + if (rc) { + LOG_ERR("[N]GattcDbDiscAllSvcsFail[%d]", rc); + + /* Revert the previous addition of the GATT client database */ + gattc_db_del(adb); + } + + return rc; +} + +void bt_le_nimble_gattc_db_remove(uint16_t conn_handle) +{ + /* Note: + * Even if the connection is disconnected, the GATT client database should + * not be removed. And after the connection is re-established, no need to + * re-discover the GATT client database which can save time. + * + * TODO: + * If Service Change Indication is received, the GATT client database should + * be removed and re-discovered. + */ + struct gattc_db *adb = NULL; + + LOG_DBG("[N]GattcDbRemove[%u]", conn_handle); + + adb = gattc_db_find(conn_handle); + if (adb == NULL) { + LOG_WRN("[N]GattcDbNotFoundToRemove[%u]", conn_handle); + return; + } + + gattc_db_del(adb); +} diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/gatt/gatt.h b/components/bt/esp_ble_audio/host/adapter/nimble/gatt/gatt.h new file mode 100644 index 0000000000..6adb58869d --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/gatt/gatt.h @@ -0,0 +1,124 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef HOST_NIMBLE_GATT_H_ +#define HOST_NIMBLE_GATT_H_ + +#include +#include + +#include + +#include "host/ble_uuid.h" +#include "host/ble_gatt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_le_nimble_gatt_read_cb { + int (*read_cb)(void *arg, uint16_t offset, const void *data, uint16_t len); + void *read_arg; +}; + +static inline uint8_t BT_LE_NIMBLE_GATT_UUID_TO_Z(uint8_t type) +{ + /* Used to convert NimBLE UUID to Zephyr UUID */ + + if (type == BLE_UUID_TYPE_16) { + return BT_UUID_TYPE_16; + } else if (type == BLE_UUID_TYPE_32) { + return BT_UUID_TYPE_32; + } else if (type == BLE_UUID_TYPE_128) { + return BT_UUID_TYPE_128; + } else { + assert(0); + return BT_UUID_TYPE_16; + } +} + +void bt_le_nimble_gatt_post_event(void *event); + +int bt_le_nimble_gatt_post_disc_event(uint16_t conn_handle, ble_uuid16_t *uuid, + struct bt_gatt_discover_params *params, + uint8_t type); + +int bt_le_nimble_gatt_post_disc_cmpl_event(uint16_t conn_handle, uint8_t status); + +void bt_le_nimble_gatt_handle_event(uint8_t *data, size_t data_len); + +uint16_t bt_le_nimble_gatt_get_mtu(struct bt_conn *conn); + +ssize_t bt_le_nimble_gatts_attr_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, + void *buf, uint16_t buf_len, uint16_t offset, + const void *value, uint16_t value_len); + +int bt_le_nimble_gatts_notify(struct bt_conn *conn, struct bt_gatt_notify_params *params); + +int bt_le_nimble_gatts_indicate(struct bt_conn *conn, struct bt_gatt_indicate_params *params); + +int bt_le_nimble_gattc_disc_start(uint16_t conn_handle); + +int bt_le_nimble_gattc_discover(struct bt_conn *conn, struct bt_gatt_discover_params *params); + +int bt_le_nimble_gattc_read(struct bt_conn *conn, struct bt_gatt_read_params *params); + +int bt_le_nimble_gattc_write(struct bt_conn *conn, struct bt_gatt_write_params *params); + +int bt_le_nimble_gattc_write_without_rsp(struct bt_conn *conn, uint16_t handle, + const void *data, uint16_t length); + +int bt_le_nimble_gattc_write_ccc(struct bt_conn *conn, struct bt_gatt_subscribe_params *params); + +struct bt_le_gattc_discover_event; + +void handle_gattc_db_disc_event_safe(struct bt_le_gattc_discover_event *event); + +int bt_le_nimble_gattc_db_disc_svc_by_uuid(struct bt_conn *conn, ble_uuid16_t *uuid, + struct bt_gatt_discover_params *params); + +int bt_le_nimble_gattc_db_find_inc_svcs(struct bt_conn *conn, + struct bt_gatt_discover_params *params); + +int bt_le_nimble_gattc_db_disc_chrs_by_uuid(struct bt_conn *conn, ble_uuid16_t *uuid, + struct bt_gatt_discover_params *params); + +int bt_le_nimble_gattc_db_disc_all_chrs(struct bt_conn *conn, + struct bt_gatt_discover_params *params); + +int bt_le_nimble_gattc_db_disc_all_dscs(struct bt_conn *conn, + struct bt_gatt_discover_params *params); + +int bt_le_nimble_gattc_db_auto_disc(uint16_t conn_handle); + +void bt_le_nimble_gattc_db_remove(uint16_t conn_handle); + +enum { + GATTC_NRP_READ_BY_UUID, + GATTC_NRP_READ_LONG, + GATTC_NRP_READ_SINGLE, + GATTC_NRP_WRITE_REQ, + GATTC_NRP_SUBSCRIBE, + GATTS_NRP_INDICATE, + + GATT_NRP_MAX_NUM, +}; + +void bt_le_nimble_gatts_nrp_indicate_cb(uint16_t conn_handle, + int16_t attr_handle, + uint8_t status); + +int bt_le_nimble_gatt_nrp_insert(struct bt_conn *conn, uint8_t type, void *params); + +int bt_le_nimble_gatt_nrp_remove(struct bt_conn *conn, uint8_t type, void *params); + +void bt_le_nimble_gatt_nrp_clear(uint16_t conn_handle); + +#ifdef __cplusplus +} +#endif + +#endif /* HOST_NIMBLE_GATT_H_ */ diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/gatt/gatt.nrp.c b/components/bt/esp_ble_audio/host/adapter/nimble/gatt/gatt.nrp.c new file mode 100644 index 0000000000..347bff8cc2 --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/gatt/gatt.nrp.c @@ -0,0 +1,901 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include <../host/conn_internal.h> + +#include "host/ble_hs.h" +#include "host/ble_att.h" +#include "host/ble_gatt.h" +#include "host/ble_hs_mbuf.h" + +#include "common/host.h" + +struct gatt_nrp_node { + uint8_t type; + + union { + struct { + struct bt_gatt_read_params *params; + } read_by_uuid; + + struct { + struct bt_gatt_read_params *params; + } read_long; + + struct { + struct bt_gatt_read_params *params; + } read_single; + + struct { + struct bt_gatt_write_params *params; + } write_req; + + struct { + struct bt_gatt_subscribe_params *params; + } subscribe; + + struct { + struct bt_gatt_indicate_params *params; + } indicate; + }; + + sys_snode_t node; +}; + +static struct gatt_nrp { + uint16_t conn_handle; + + sys_slist_t list; /* List of GATT need response pdu (e.g., read req, write req, indication, etc.) */ +} gatt_nrp[CONFIG_BT_MAX_CONN] = { + [0 ...(CONFIG_BT_MAX_CONN - 1)] = { + .conn_handle = UINT16_MAX, + }, +}; + +static int gattc_nrp_read_by_uuid_cb_safe(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + void *arg) +{ + struct bt_gatt_read_params *read_params; + struct bt_conn *conn; + int rc = 0; + + read_params = arg; + assert(read_params); + assert(read_params->func); + assert(read_params->handle_count == 0); + assert(read_params->by_uuid.uuid); + assert(read_params->by_uuid.uuid->type == BT_UUID_TYPE_16); + + LOG_DBG("[N]GattcNrpRdByUuidCb[%u][%04x][%s]", + conn_handle, error->status, bt_uuid_str(read_params->by_uuid.uuid)); + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL || conn->state != BT_CONN_CONNECTED) { + LOG_ERR("[N]GattcNrpNotConn[%d]", __LINE__); + rc = -ENOTCONN; + /* Note: + * Cannot remove NRP node or invoke callback without valid conn. + * Consider if bt_le_nimble_gatt_nrp_clear() should be invoked. + */ + goto end; + } + + /* Shall be invoked before the read_params->func is invoked */ + bt_le_nimble_gatt_nrp_remove(conn, GATTC_NRP_READ_BY_UUID, read_params); + + switch (error->status) { + case 0: + assert(attr); + assert(attr->om); + + LOG_DBG("[N]GattcNrpHdl[%u][%u][%u]Len[%u]", + attr->handle, read_params->by_uuid.start_handle, + read_params->by_uuid.end_handle, attr->om->om_len); + + if (read_params->by_uuid.start_handle == BT_ATT_FIRST_ATTRIBUTE_HANDLE) { + read_params->by_uuid.start_handle = attr->handle; + } + + read_params->func(conn, 0, read_params, attr->om->om_data, attr->om->om_len); + break; + + case BLE_HS_EDONE: + read_params->func(conn, 0, read_params, NULL, 0); + break; + + default: + LOG_WRN("[N]GattcNrpStatus[%04x]", error->status); + + if (error->status & BLE_HS_ERR_ATT_BASE) { + read_params->func(conn, (uint8_t)error->status, read_params, NULL, 0); + } else { + /* Note: for other errors, currently we just ignore it. */ + } + + rc = error->status; + break; + } + +end: + bt_le_host_unlock(); + + return rc; +} + +static int gattc_nrp_read_long_cb_safe(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + void *arg) +{ + struct bt_gatt_read_params *read_params; + struct bt_conn *conn; + int rc = 0; + + read_params = arg; + assert(read_params); + assert(read_params->func); + assert(read_params->handle_count == 1); + assert(read_params->single.offset != 0); + + LOG_DBG("[N]GattcNrpRdLongCb[%u][%04x]", conn_handle, error->status); + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL || conn->state != BT_CONN_CONNECTED) { + LOG_ERR("[N]GattcNrpNotConn[%d]", __LINE__); + rc = -ENOTCONN; + goto end; + } + + /* Shall be invoked before the read_params->func is invoked */ + bt_le_nimble_gatt_nrp_remove(conn, GATTC_NRP_READ_LONG, read_params); + + switch (error->status) { + case 0: + assert(attr); + assert(attr->om); + + LOG_DBG("[N]GattcNrpHdl[%u][%u]Offset[%u]Len[%u]", + attr->handle, read_params->single.handle, attr->offset, attr->om->om_len); + + read_params->func(conn, 0, read_params, attr->om->om_data, attr->om->om_len); + break; + + case BLE_HS_EDONE: + read_params->func(conn, 0, read_params, NULL, 0); + break; + + default: + LOG_WRN("[N]GattcNrpStatus[%04x]", error->status); + + if (error->status & BLE_HS_ERR_ATT_BASE) { + read_params->func(conn, (uint8_t)error->status, read_params, NULL, 0); + } else { + /* Note: for other errors, currently we just ignore it. */ + } + + rc = error->status; + break; + } + +end: + bt_le_host_unlock(); + + return rc; +} + +static int gattc_nrp_read_single_cb_safe(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + void *arg) +{ + struct bt_gatt_read_params *read_params; + struct bt_conn *conn; + int rc = 0; + + read_params = arg; + assert(read_params); + assert(read_params->func); + assert(read_params->handle_count == 1); + assert(read_params->single.offset == 0); + + LOG_DBG("[N]GattcNrpRdSingleCb[%u][%04x]", conn_handle, error->status); + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL || conn->state != BT_CONN_CONNECTED) { + LOG_ERR("[N]GattcNrpNotConn[%d]", __LINE__); + rc = -ENOTCONN; + goto end; + } + + /* Shall be invoked before the read_params->func is invoked */ + bt_le_nimble_gatt_nrp_remove(conn, GATTC_NRP_READ_SINGLE, read_params); + + switch (error->status) { + case 0: + assert(attr); + assert(attr->om); + + LOG_DBG("[N]GattcNrpHdl[%u][%u]Len[%u]", + attr->handle, read_params->single.handle, attr->om->om_len); + + if (read_params->func(conn, 0, read_params, + attr->om->om_data, + attr->om->om_len) == BT_GATT_ITER_CONTINUE) { + /* Workaround for completing the handling of ATT Read Response + * by BAP Unicast Client. + */ + read_params->func(conn, 0, read_params, NULL, 0); + } + break; + + case BLE_HS_EDONE: + read_params->func(conn, 0, read_params, NULL, 0); + break; + + default: + LOG_WRN("[N]GattcNrpStatus[%04x]", error->status); + + if (error->status & BLE_HS_ERR_ATT_BASE) { + read_params->func(conn, (uint8_t)error->status, read_params, NULL, 0); + } else { + /* Note: for other errors, currently we just ignore it. */ + } + + rc = error->status; + break; + } + +end: + bt_le_host_unlock(); + + return rc; +} + +static int gattc_nrp_read(struct bt_conn *conn, struct bt_gatt_read_params *params) +{ + int rc; + + LOG_DBG("[N]GattcNrpRd[%u][%u]", conn->handle, params->handle_count); + + if (params->handle_count == 0) { + LOG_DBG("[N]GattcNrpByUuid[%u][%u][%s]", + params->by_uuid.start_handle, params->by_uuid.end_handle, + bt_uuid_str(params->by_uuid.uuid)); + + ble_uuid16_t uuid = { + .u.type = BLE_UUID_TYPE_16, + .value = BT_UUID_16(params->by_uuid.uuid)->val, + }; + + rc = ble_gattc_read_by_uuid(conn->handle, + params->by_uuid.start_handle, + params->by_uuid.end_handle, + &uuid.u, + gattc_nrp_read_by_uuid_cb_safe, + params); + if (rc) { + LOG_ERR("[N]GattcNrpRdByUuidFail[%d]", rc); + } + } else if (params->single.offset) { + LOG_DBG("[N]GattcNrpLong[%u][%u]", params->single.handle, params->single.offset); + + rc = ble_gattc_read_long(conn->handle, + params->single.handle, + params->single.offset, + gattc_nrp_read_long_cb_safe, + params); + if (rc) { + LOG_ERR("[N]GattcNrpRdLongFail[%d]", rc); + } + } else { + LOG_DBG("[N]GattcNrpSingle[%u]", params->single.handle); + + rc = ble_gattc_read(conn->handle, + params->single.handle, + gattc_nrp_read_single_cb_safe, + params); + if (rc) { + LOG_ERR("[N]GattcNrpRdFail[%d]", rc); + } + } + + return rc; +} + +static int gattc_nrp_write_cb_safe(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + void *arg) +{ + struct bt_gatt_write_params *write_params; + struct bt_conn *conn; + int rc = 0; + + write_params = arg; + assert(write_params); + assert(write_params->func); + + LOG_DBG("[N]GattcNrpWrCb[%u][%04x]", conn_handle, error->status); + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL || conn->state != BT_CONN_CONNECTED) { + LOG_ERR("[N]GattcNrpNotConn[%d]", __LINE__); + rc = -ENOTCONN; + goto end; + } + + /* Shall be invoked before the write_params->func is invoked */ + bt_le_nimble_gatt_nrp_remove(conn, GATTC_NRP_WRITE_REQ, write_params); + + switch (error->status) { + case 0: + assert(attr); + LOG_DBG("[N]GattcNrpHdl[%u][%u]", attr->handle, write_params->handle); + + write_params->func(conn, 0, write_params); + break; + + case BLE_HS_EDONE: + /* Note: for sending write request, the EDONE status will not be reported. */ + break; + + default: + LOG_WRN("[N]GattcNrpStatus[%04x]", error->status); + + if (error->status & BLE_HS_ERR_ATT_BASE) { + write_params->func(conn, (uint8_t)error->status, write_params); + } else { + /* Note: for other errors, currently we just ignore it. */ + } + + rc = error->status; + break; + } + +end: + bt_le_host_unlock(); + + return rc; +} + +static int gattc_nrp_write(struct bt_conn *conn, struct bt_gatt_write_params *params) +{ + int rc; + + LOG_DBG("[N]GattcNrpWr[%u][%u][%u]", + conn->handle, params->handle, params->length); + + rc = ble_gattc_write_flat(conn->handle, + params->handle, + params->data, + params->length, + gattc_nrp_write_cb_safe, + params); + if (rc) { + LOG_ERR("[N]GattcNrpWrFlatFail[%d]", rc); + } + + return rc; +} + +static int gattc_nrp_subscribe_cb_safe(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + void *arg) +{ + struct bt_gatt_subscribe_params *sub_params; + struct bt_conn *conn; + int rc = 0; + + sub_params = arg; + assert(sub_params); + + LOG_DBG("[N]GattcNrpSubCb[%u][%04x]", conn_handle, error->status); + + bt_le_host_lock(); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL || conn->state != BT_CONN_CONNECTED) { + LOG_ERR("[N]GattcNrpNotConn[%d]", __LINE__); + rc = -ENOTCONN; + goto end; + } + + /* Should be invoked here */ + bt_le_nimble_gatt_nrp_remove(conn, GATTC_NRP_SUBSCRIBE, sub_params); + + switch (error->status) { + case 0: + assert(attr); + LOG_DBG("[N]GattcNrpHdl[%u]", attr->handle); + +#if 0 + /* Mask the callback invocation for now. + * Check the bt_gatt_subscribe function for details. + */ + if (sub_params->subscribe) { + sub_params->subscribe(conn, 0, sub_params); + } +#endif + break; + + case BLE_HS_EDONE: + break; + + default: + LOG_WRN("[N]GattcNrpStatus[%04x]", error->status); + +#if 0 + /* Mask the callback invocation for now. + * Check the bt_gatt_subscribe function for details. + */ + if (sub_params->subscribe && (error->status & BLE_HS_ERR_ATT_BASE)) { + sub_params->subscribe(conn, (uint8_t)error->status, sub_params); + } +#endif + + rc = error->status; + break; + } + +end: + bt_le_host_unlock(); + + return rc; +} + +static int gattc_nrp_subscribe(struct bt_conn *conn, struct bt_gatt_subscribe_params *params) +{ + int rc; + + LOG_DBG("[N]GattcNrpSub[%u][%u][%04x]", + conn->handle, params->ccc_handle, params->value); + + rc = ble_gattc_write_flat(conn->handle, + params->ccc_handle, + ¶ms->value, + sizeof(params->value), + gattc_nrp_subscribe_cb_safe, + params); + if (rc && rc != BLE_HS_ENOTCONN) { + LOG_ERR("[N]GattcNrpSubFail[%d]", rc); + } + + return rc; +} + +void bt_le_nimble_gatts_nrp_indicate_cb(uint16_t conn_handle, + int16_t attr_handle, + uint8_t status) +{ + struct bt_gatt_indicate_params params = {0}; + struct bt_gatt_attr attr = {0}; + struct bt_conn *conn; + + LOG_DBG("[N]GattsNrpIndCb[%u][%u][%u]", conn_handle, attr_handle, status); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL || conn->state != BT_CONN_CONNECTED) { + LOG_ERR("[N]GattsNrpNotConn[%d]", __LINE__); + return; + } + + switch (status) { + case 0: + break; + + case BLE_HS_EDONE: + break; + + default: + LOG_WRN("[N]GattsNrpIndCbStatus[%u]", status); + break; + } + + if (status) { + attr.handle = attr_handle; + params.attr = &attr; + + bt_le_nimble_gatt_nrp_remove(conn, GATTS_NRP_INDICATE, ¶ms); + } +} + +static int gatts_nrp_indicate(struct bt_conn *conn, struct bt_gatt_indicate_params *params) +{ + struct notify_data data = {0}; + struct os_mbuf *om = NULL; + int rc; + + assert(conn && params); + assert(params->attr); + assert(params->data); + assert(params->len); + + data.attr = params->attr; + data.handle = bt_gatt_attr_get_handle(data.attr); + + LOG_DBG("[N]GattsNrpInd[%u][%u]", conn->handle, data.handle); + + /* Lookup UUID if it was given */ + if (params->uuid) { + if (bt_gatts_find_attr_by_uuid(&data, params->uuid) == false) { + return -ENOENT; + } + + params->attr = data.attr; + } else { + if (data.handle == 0) { + LOG_WRN("[N]GattsNrpDataHdlZero"); + return -ENOENT; + } + } + + /* Check if attribute is a characteristic then adjust the handle */ + if (bt_uuid_cmp(data.attr->uuid, BT_UUID_GATT_CHRC) == 0) { + struct bt_gatt_chrc *chrc; + + assert(data.attr->user_data); + chrc = data.attr->user_data; + + if ((chrc->properties & BT_GATT_CHRC_INDICATE) == 0) { + LOG_WRN("[N]GattsNrpIndNotSupp[%u][%02x]", data.handle, chrc->properties); + return -EINVAL; + } + + data.handle = bt_gatt_attr_value_handle(data.attr); + + LOG_INF("[N]GattsNrpDataHdl[%u][%u]", data.attr->handle, data.handle); + } + + om = ble_hs_mbuf_from_flat(params->data, params->len); + if (om == NULL) { + LOG_ERR("[N]GattsNrpNoMemForInd[%u]", params->len); + return -ENOMEM; + } + + rc = ble_gatts_indicate_custom(conn->handle, data.handle, om); + if (rc) { + LOG_ERR("[N]GattsNrpIndCustomFail[%d]", rc); + } + + return rc; +} + +static struct gatt_nrp *gatt_nrp_add(uint16_t conn_handle) +{ + for (size_t i = 0; i < ARRAY_SIZE(gatt_nrp); i++) { + if (gatt_nrp[i].conn_handle == UINT16_MAX) { + gatt_nrp[i].conn_handle = conn_handle; + sys_slist_init(&gatt_nrp[i].list); + + return &gatt_nrp[i]; + } + } + + LOG_ERR("[N]GattNrpNoFreeGattNrp[%u]", conn_handle); + return NULL; +} + +static struct gatt_nrp *gatt_nrp_find(uint16_t conn_handle) +{ + for (size_t i = 0; i < ARRAY_SIZE(gatt_nrp); i++) { + if (gatt_nrp[i].conn_handle == conn_handle) { + LOG_DBG("[N]GattNrpFound[%u]", conn_handle); + return &gatt_nrp[i]; + } + } + + return NULL; +} + +static void gatt_nrp_del(struct gatt_nrp *nrp) +{ + struct gatt_nrp_node *nrp_head; + sys_snode_t *node; + + assert(nrp); + + while (1) { + node = sys_slist_get(&nrp->list); + if (node == NULL) { + break; + } + + nrp_head = CONTAINER_OF(node, struct gatt_nrp_node, node); + + LOG_DBG("[N]GattNrpFree[%p]", nrp_head); + + free(nrp_head); + } + + nrp->conn_handle = UINT16_MAX; +} + +static int gatt_nrp_insert(struct bt_conn *conn, uint8_t type, void *params) +{ + struct gatt_nrp_node *nrp_node; + struct gatt_nrp *nrp; + int rc = 0; + + LOG_DBG("[N]GattNrpInsert[%u][%u]", conn->handle, type); + + nrp = gatt_nrp_find(conn->handle); + if (nrp == NULL) { + nrp = gatt_nrp_add(conn->handle); + } + + if (nrp == NULL) { + return -ENOMEM; + } + + nrp_node = calloc(1, sizeof(*nrp_node)); + assert(nrp_node); + + nrp_node->type = type; + + switch (type) { + case GATTC_NRP_READ_BY_UUID: + nrp_node->read_by_uuid.params = params; + break; + case GATTC_NRP_READ_LONG: + nrp_node->read_long.params = params; + break; + case GATTC_NRP_READ_SINGLE: + nrp_node->read_single.params = params; + break; + case GATTC_NRP_WRITE_REQ: + nrp_node->write_req.params = params; + break; + case GATTC_NRP_SUBSCRIBE: + nrp_node->subscribe.params = params; + break; + case GATTS_NRP_INDICATE: + nrp_node->indicate.params = params; + break; + default: + assert(0); + } + + if (sys_slist_is_empty(&nrp->list)) { + LOG_DBG("[N]GattNrpListEmpty"); + + if (type == GATTC_NRP_READ_BY_UUID || + type == GATTC_NRP_READ_LONG || + type == GATTC_NRP_READ_SINGLE) { + rc = gattc_nrp_read(conn, params); + } else if (type == GATTC_NRP_WRITE_REQ) { + rc = gattc_nrp_write(conn, params); + } else if (type == GATTC_NRP_SUBSCRIBE) { + rc = gattc_nrp_subscribe(conn, params); + } else if (type == GATTS_NRP_INDICATE) { + rc = gatts_nrp_indicate(conn, params); + } + } else { + LOG_DBG("[N]GattNrpListNotEmpty"); + rc = 0; + } + + if (rc == 0) { + LOG_DBG("[N]GattNrpAppend[%p]", nrp_node); + sys_slist_append(&nrp->list, &nrp_node->node); + } else { + LOG_ERR("[N]GattNrpInsertFail[%d]", rc); + free(nrp_node); + } + + return rc; +} + +static int gatts_nrp_indicate_insert(struct bt_conn *conn, struct bt_gatt_indicate_params *params) +{ + struct bt_conn *conns; + uint8_t conns_count; + int rc = 0; + + LOG_DBG("[N]GattsNrpIndInsert[%p]", conn); + + if (conn) { + return gatt_nrp_insert(conn, GATTS_NRP_INDICATE, params); + } + + bt_conn_get_acl_conns(&conns, &conns_count); + + for (size_t i = 0; i < conns_count; i++) { + LOG_DBG("[N]GattsNrpConn[%u][%u][%u]", i, conns[i].handle, conns[i].state); + + if (conns[i].state == BT_CONN_CONNECTED) { + rc = gatt_nrp_insert(&conns[i], GATTS_NRP_INDICATE, params); + if (rc) { + return rc; + } + } + } + + return 0; +} + +int bt_le_nimble_gatt_nrp_insert(struct bt_conn *conn, uint8_t type, void *params) +{ + int rc; + if (type == GATTS_NRP_INDICATE) { + rc = gatts_nrp_indicate_insert(conn, params); + } else { + rc = gatt_nrp_insert(conn, type, params); + } + return rc; +} + +int bt_le_nimble_gatt_nrp_remove(struct bt_conn *conn, uint8_t type, void *params) +{ + struct gatt_nrp_node *nrp_head; + struct gatt_nrp *nrp; + sys_snode_t *node; + int rc = 0; + + LOG_DBG("[N]GattNrpRemove[%u][%u]", conn->handle, type); + + nrp = gatt_nrp_find(conn->handle); + if (nrp == NULL) { + LOG_ERR("[N]GattNrpNotFound[%u]", conn->handle); + return -ENODEV; + } + + /* Fetch and remove the first node from list */ + node = sys_slist_get(&nrp->list); + assert(node); + + nrp_head = CONTAINER_OF(node, struct gatt_nrp_node, node); + assert(nrp_head->type == type); + + switch (type) { + case GATTC_NRP_READ_BY_UUID: + assert(nrp_head->read_by_uuid.params == params); + break; + case GATTC_NRP_READ_LONG: + assert(nrp_head->read_long.params == params); + break; + case GATTC_NRP_READ_SINGLE: + assert(nrp_head->read_single.params == params); + break; + case GATTC_NRP_WRITE_REQ: + assert(nrp_head->write_req.params == params); + break; + case GATTC_NRP_SUBSCRIBE: + assert(nrp_head->subscribe.params == params); + break; + case GATTS_NRP_INDICATE: + assert(nrp_head->indicate.params); + + if (nrp_head->indicate.params->attr->handle != + ((struct bt_gatt_indicate_params *)params)->attr->handle) { + LOG_ERR("[N]GattNrpMismatchIndHdl[%u][%u]", + ((struct bt_gatt_indicate_params *)params)->attr->handle, + nrp_head->indicate.params->attr->handle); + assert(0); /* Should not happen */ + } + + /* Note: + * The params may be shared by multiple connections. And currently + * in this case, the params will not be updated in the func callback. + */ + nrp_head->indicate.params->func(conn, nrp_head->indicate.params, 0); + break; + default: + assert(0); + } + + LOG_DBG("[N]GattNrpFree[%p]", nrp_head); + free(nrp_head); + + while (1) { + if (sys_slist_is_empty(&nrp->list)) { + break; + } + + /* Fetch the first node from list */ + node = sys_slist_peek_head(&nrp->list); + + nrp_head = CONTAINER_OF(node, struct gatt_nrp_node, node); + + if (nrp_head->type == GATTC_NRP_READ_BY_UUID) { + rc = gattc_nrp_read(conn, nrp_head->read_by_uuid.params); + if (rc) { + LOG_ERR("[N]GattcNrpRdByUuidFail[%d]", rc); + + assert(nrp_head->read_by_uuid.params->func); + nrp_head->read_by_uuid.params->func(conn, rc, nrp_head->read_by_uuid.params, NULL, 0); + } + } else if (nrp_head->type == GATTC_NRP_READ_LONG) { + rc = gattc_nrp_read(conn, nrp_head->read_long.params); + if (rc) { + LOG_ERR("[N]GattcNrpRdLongFail[%d]", rc); + + assert(nrp_head->read_long.params->func); + nrp_head->read_long.params->func(conn, rc, nrp_head->read_long.params, NULL, 0); + } + } else if (nrp_head->type == GATTC_NRP_READ_SINGLE) { + rc = gattc_nrp_read(conn, nrp_head->read_single.params); + if (rc) { + LOG_ERR("[N]GattcNrpRdSingleFail[%d]", rc); + + assert(nrp_head->read_single.params->func); + nrp_head->read_single.params->func(conn, rc, nrp_head->read_single.params, NULL, 0); + } + } else if (nrp_head->type == GATTC_NRP_WRITE_REQ) { + rc = gattc_nrp_write(conn, nrp_head->write_req.params); + if (rc) { + LOG_ERR("[N]GattcNrpWrFail[%d]", rc); + + assert(nrp_head->write_req.params->func); + nrp_head->write_req.params->func(conn, rc, nrp_head->write_req.params); + } + } else if (nrp_head->type == GATTC_NRP_SUBSCRIBE) { + rc = gattc_nrp_subscribe(conn, nrp_head->subscribe.params); + if (rc) { + LOG_ERR("[N]GattcNrpSubFail[%d]", rc); + } + } else if (nrp_head->type == GATTS_NRP_INDICATE) { + rc = gatts_nrp_indicate(conn, nrp_head->indicate.params); + if (rc) { + LOG_ERR("[N]GattsNrpIndFail[%d]", rc); + + assert(nrp_head->indicate.params->func); + nrp_head->indicate.params->func(conn, nrp_head->indicate.params, rc); + } + } + + if (rc == 0) { + LOG_DBG("[N]GattNrpOnGoing[%p]", nrp_head); + break; + } + + LOG_DBG("[N]GattNrpRemoveAndFree[%p]", nrp_head); + + /* If this nrp operation failed, then remove it from list, + * peek the next node and start. + */ + sys_slist_remove(&nrp->list, NULL, node); + + free(nrp_head); + } + + return 0; +} + +void bt_le_nimble_gatt_nrp_clear(uint16_t conn_handle) +{ + struct gatt_nrp *nrp; + + LOG_DBG("[N]GattNrpClear[%u]", conn_handle); + + nrp = gatt_nrp_find(conn_handle); + if (nrp == NULL) { + return; + } + + gatt_nrp_del(nrp); +} diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/init.c b/components/bt/esp_ble_audio/host/adapter/nimble/init.c new file mode 100644 index 0000000000..b774520582 --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/init.c @@ -0,0 +1,455 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "sdkconfig.h" + +#include +#include +#include + +#include "host/ble_gatt.h" +#include "services/gap/ble_svc_gap.h" +#include "services/gatt/ble_svc_gatt.h" + +#include "nimble/init.h" +#include "common/init.h" + +#include "../../../lib/include/audio.h" + +#if CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT +#define ASCS_ASE_SNK_CCCD_COUNT CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT +#else /* CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT */ +#define ASCS_ASE_SNK_CCCD_COUNT 0 +#endif /* CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT */ + +#if CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT +#define ASCS_ASE_SRC_CCCD_COUNT CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT +#else /* CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT */ +#define ASCS_ASE_SRC_CCCD_COUNT 0 +#endif /* CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT */ + +#if CONFIG_BT_PAC_SNK_NOTIFIABLE +#define PAC_SNK_CCCD_COUNT 1 +#else /* CONFIG_BT_PAC_SNK_NOTIFIABLE */ +#define PAC_SNK_CCCD_COUNT 0 +#endif /* CONFIG_BT_PAC_SNK_NOTIFIABLE */ + +#if CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE +#define PAC_SNK_LOC_CCCD_COUNT 1 +#else /* CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE */ +#define PAC_SNK_LOC_CCCD_COUNT 0 +#endif /* CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE */ + +#if CONFIG_BT_PAC_SRC_NOTIFIABLE +#define PAC_SRC_CCCD_COUNT 1 +#else /* CONFIG_BT_PAC_SRC_NOTIFIABLE */ +#define PAC_SRC_CCCD_COUNT 0 +#endif /* CONFIG_BT_PAC_SRC_NOTIFIABLE */ + +#if CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE +#define PAC_SRC_LOC_CCCD_COUNT 1 +#else /* CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE */ +#define PAC_SRC_LOC_CCCD_COUNT 0 +#endif /* CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE */ + +#if CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE +#define PACS_SUPPORTED_CONTEXT_CCCD_COUNT 1 +#else /* CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE */ +#define PACS_SUPPORTED_CONTEXT_CCCD_COUNT 0 +#endif /* CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE */ + +#if CONFIG_BT_BAP_SCAN_DELEGATOR_RECV_STATE_COUNT +#define SCAN_DELEGATOR_RECV_STATE_CCCD_COUNT CONFIG_BT_BAP_SCAN_DELEGATOR_RECV_STATE_COUNT +#else /* CONFIG_BT_BAP_SCAN_DELEGATOR_RECV_STATE_COUNT */ +#define SCAN_DELEGATOR_RECV_STATE_CCCD_COUNT 0 +#endif /* CONFIG_BT_BAP_SCAN_DELEGATOR_RECV_STATE_COUNT */ + +#if CONFIG_BT_CSIP_SET_MEMBER_SIRK_NOTIFIABLE +#define CSIP_SET_MEMBER_CCCD_COUNT 1 +#else /* CONFIG_BT_CSIP_SET_MEMBER_SIRK_NOTIFIABLE */ +#define CSIP_SET_MEMBER_CCCD_COUNT 0 +#endif /* CONFIG_BT_CSIP_SET_MEMBER_SIRK_NOTIFIABLE */ + +#if CONFIG_BT_VCP_VOL_REND_VOL_FLAGS_NOTIFIABLE +#define VCP_VOL_REND_VOL_FLAGS_CCCD_COUNT 1 +#else /* CONFIG_BT_VCP_VOL_REND_VOL_FLAGS_NOTIFIABLE */ +#define VCP_VOL_REND_VOL_FLAGS_CCCD_COUNT 0 +#endif /* CONFIG_BT_VCP_VOL_REND_VOL_FLAGS_NOTIFIABLE */ + +#if CONFIG_BT_VOCS_MAX_INSTANCE_COUNT +#define VOCS_CCCD_COUNT (CONFIG_BT_VOCS_MAX_INSTANCE_COUNT * 3) +#else /* CONFIG_BT_VOCS_MAX_INSTANCE_COUNT */ +#define VOCS_CCCD_COUNT 0 +#endif /* CONFIG_BT_VOCS_MAX_INSTANCE_COUNT */ + +#if CONFIG_BT_AICS_MAX_INSTANCE_COUNT +#define AICS_CCCD_COUNT (CONFIG_BT_AICS_MAX_INSTANCE_COUNT * 3) +#else /* CONFIG_BT_AICS_MAX_INSTANCE_COUNT */ +#define AICS_CCCD_COUNT 0 +#endif /* CONFIG_BT_AICS_MAX_INSTANCE_COUNT */ + +#if CONFIG_BT_HAS_FEATURES_NOTIFIABLE +#define HAS_FEATURES_CCCD_COUNT 1 +#else /* CONFIG_BT_HAS_FEATURES_NOTIFIABLE */ +#define HAS_FEATURES_CCCD_COUNT 0 +#endif /* CONFIG_BT_HAS_FEATURES_NOTIFIABLE */ + +#if CONFIG_BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE +#define HAS_PRESET_CONTROL_POINT_CCCD_COUNT 1 +#else /* CONFIG_BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE */ +#define HAS_PRESET_CONTROL_POINT_CCCD_COUNT 0 +#endif /* CONFIG_BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE */ + +#if CONFIG_BT_HAS_ACTIVE_PRESET_INDEX +#define HAS_ACTIVE_PRESET_INDEX_CCCD_COUNT 1 +#else /* CONFIG_BT_HAS_ACTIVE_PRESET_INDEX */ +#define HAS_ACTIVE_PRESET_INDEX_CCCD_COUNT 0 +#endif /* CONFIG_BT_HAS_ACTIVE_PRESET_INDEX */ + +#if CONFIG_BT_OTS +#define OTS_CCCD_COUNT (CONFIG_BT_OTS_MAX_INST_CNT * 2) +#else /* CONFIG_BT_OTS */ +#define OTS_CCCD_COUNT 0 +#endif /* CONFIG_BT_OTS */ + +/* 6 is reserved for other GATT services. + * TODO: + * - OTS + * - MCS (GMCS is used for now) + * - TBS (GTBS is used for now) + */ +#define TOTAL_CCCDS_COUNT (6 + \ + (IS_ENABLED(CONFIG_BT_ASCS) ? (1 + ASCS_ASE_SNK_CCCD_COUNT + \ + ASCS_ASE_SRC_CCCD_COUNT) : 0) + \ + (IS_ENABLED(CONFIG_BT_PACS) ? (PAC_SNK_CCCD_COUNT + PAC_SNK_LOC_CCCD_COUNT + \ + PAC_SRC_CCCD_COUNT + PAC_SRC_LOC_CCCD_COUNT + \ + 1 + PACS_SUPPORTED_CONTEXT_CCCD_COUNT) : 0) + \ + (IS_ENABLED(CONFIG_BT_BAP_SCAN_DELEGATOR) ? SCAN_DELEGATOR_RECV_STATE_CCCD_COUNT : 0) + \ + (IS_ENABLED(CONFIG_BT_MCS) ? 11 : 0) + \ + (IS_ENABLED(CONFIG_BT_CSIP_SET_MEMBER) ? (CSIP_SET_MEMBER_CCCD_COUNT + 2) : 0) + \ + (IS_ENABLED(CONFIG_BT_VCP_VOL_REND) ? (1 + VCP_VOL_REND_VOL_FLAGS_CCCD_COUNT) : 0) + \ + VOCS_CCCD_COUNT + \ + AICS_CCCD_COUNT + \ + (IS_ENABLED(CONFIG_BT_TBS) ? 12 : 0) + \ + (IS_ENABLED(CONFIG_BT_HAS) ? (HAS_FEATURES_CCCD_COUNT + \ + HAS_PRESET_CONTROL_POINT_CCCD_COUNT + \ + HAS_ACTIVE_PRESET_INDEX_CCCD_COUNT) : 0) + \ + (IS_ENABLED(CONFIG_BT_OTS) ? OTS_CCCD_COUNT : 0)) + +_Static_assert(TOTAL_CCCDS_COUNT <= CONFIG_BT_NIMBLE_MAX_CCCDS, "Too small BT_NIMBLE_MAX_CCCDS"); + +int bt_le_nimble_audio_init(void) +{ + int err = 0; + + err = ble_att_set_preferred_mtu(BLE_AUDIO_ATT_MTU_MIN); + if (err) { + LOG_ERR("[N]SetPrefMtuFail[%d]", err); + return err; + } + + ble_svc_gap_init(); + + ble_svc_gatt_init(); + +#if CONFIG_BT_PACS + err = bt_le_nimble_pacs_init(); + if (err) { + return err; + } +#endif /* CONFIG_BT_PACS */ + +#if (BLE_AUDIO_SVC_SEP_ADD == 0) +#if CONFIG_BT_ASCS + err = bt_le_nimble_ascs_init(); + if (err) { + return err; + } +#endif /* CONFIG_BT_ASCS */ + +#if CONFIG_BT_BAP_SCAN_DELEGATOR + err = bt_le_nimble_bass_init(); + if (err) { + return err; + } +#endif /* CONFIG_BT_BAP_SCAN_DELEGATOR */ + +#if CONFIG_BT_TMAP + err = bt_le_nimble_tmas_init(); + if (err) { + return err; + } +#endif /* CONFIG_BT_TMAP */ + +#if CONFIG_BT_TBS + err = bt_le_nimble_gtbs_init(); + if (err) { + return err; + } +#endif /* CONFIG_BT_TBS */ + +#if CONFIG_BT_HAS + err = bt_le_nimble_has_init(); + if (err) { + return err; + } +#endif /* CONFIG_BT_HAS */ +#endif /* (BLE_AUDIO_SVC_SEP_ADD == 0) */ + + return err; +} + +static int nimble_gatt_attr_handle_set(void) +{ + int err = 0; + +#if CONFIG_BT_ASCS + err = bt_le_nimble_ascs_attr_handle_set(); + if (err) { + return err; + } +#endif /* CONFIG_BT_ASCS */ + +#if CONFIG_BT_PACS + err = bt_le_nimble_pacs_attr_handle_set(); + if (err) { + return err; + } +#endif /* CONFIG_BT_PACS */ + +#if CONFIG_BT_BAP_SCAN_DELEGATOR + err = bt_le_nimble_bass_attr_handle_set(); + if (err) { + return err; + } +#endif /* CONFIG_BT_BAP_SCAN_DELEGATOR */ + +#if CONFIG_BT_CAP_ACCEPTOR + err = bt_le_nimble_cas_attr_handle_set(); + if (err) { + return err; + } +#endif /* CONFIG_BT_CAP_ACCEPTOR */ + +#if CONFIG_BT_TMAP + err = bt_le_nimble_tmas_attr_handle_set(); + if (err) { + return err; + } +#endif /* CONFIG_BT_TMAP */ + +#if CONFIG_BT_CSIP_SET_MEMBER + err = bt_le_nimble_csis_attr_handle_set(); + if (err) { + return err; + } +#endif /* CONFIG_BT_CSIP_SET_MEMBER */ + +#if CONFIG_BT_VCP_VOL_REND + err = bt_le_nimble_vcs_attr_handle_set(); + if (err) { + return err; + } +#endif /* CONFIG_BT_VCP_VOL_REND */ + +#if CONFIG_BT_MICP_MIC_DEV + err = bt_le_nimble_mics_attr_handle_set(); + if (err) { + return err; + } +#endif /* CONFIG_BT_MICP_MIC_DEV */ + +#if CONFIG_BT_MCS + err = bt_le_nimble_gmcs_attr_handle_set(); + if (err) { + return err; + } +#endif /* CONFIG_BT_MCS */ + +#if CONFIG_BT_TBS + err = bt_le_nimble_gtbs_attr_handle_set(); + if (err) { + return err; + } +#endif /* CONFIG_BT_TBS */ + +#if CONFIG_BT_HAS + err = bt_le_nimble_has_attr_handle_set(); + if (err) { + return err; + } +#endif /* CONFIG_BT_HAS */ + + return err; +} + +#if CONFIG_BT_CSIP_SET_MEMBER +static int nimble_gatt_csis_init(struct bt_le_audio_start_info *info, + struct bt_gatt_service **inc_csis_svc) +{ + struct bt_gatt_service *csis_svc[CONFIG_BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT]; + uint8_t count; + int err; + + if (info == NULL) { + return 0; + } + + *inc_csis_svc = NULL; + count = 0; + + for (size_t i = 0; i < ARRAY_SIZE(info->csis_insts); i++) { + if (info->csis_insts[i].svc_inst == NULL) { + continue; + } + + csis_svc[count] = lib_csip_set_member_svc_get(info->csis_insts[i].svc_inst); + assert(csis_svc[count]); + + if (info->csis_insts[i].included_by_cas) { + if (*inc_csis_svc == NULL) { + *inc_csis_svc = csis_svc[count]; + } else { + assert(0); + } + } + + count++; + } + + err = bt_le_nimble_csis_init(csis_svc, count); + if (err) { + return err; + } + + return 0; +} +#endif /* CONFIG_BT_CSIP_SET_MEMBER */ + +#if CONFIG_BT_MCS +int bt_le_nimble_media_proxy_pl_init(void) +{ + /* Note: + * Currently the existence of some characteristics within GMCS + * are determined by the enabling of OTS. + */ +#if CONFIG_BT_OTS + return bt_le_nimble_gmcs_init(true); +#else /* CONFIG_BT_OTS */ + return bt_le_nimble_gmcs_init(false); +#endif /* CONFIG_BT_OTS */ +} +#endif /* CONFIG_BT_MCS */ + +#if CONFIG_BT_VCP_VOL_REND +int bt_le_nimble_vcp_vol_rend_init(void) +{ + struct bt_vcp_included vcp_included; + int err; + + memset(&vcp_included, 0, sizeof(vcp_included)); + + err = bt_vcp_vol_rend_included_get_safe(&vcp_included); + if (err) { + return err; + } + + err = bt_le_nimble_vcs_init(&vcp_included); + if (err) { + return err; + } + + return 0; +} +#endif /* CONFIG_BT_VCP_VOL_REND */ + +#if CONFIG_BT_MICP_MIC_DEV +int bt_le_nimble_micp_mic_dev_init(void) +{ + struct bt_micp_included micp_included; + int err; + + memset(&micp_included, 0, sizeof(micp_included)); + + err = bt_micp_mic_dev_included_get_safe(&micp_included); + if (err) { + return err; + } + + err = bt_le_nimble_mics_init(&micp_included); + if (err) { + return err; + } + + return 0; +} +#endif /* CONFIG_BT_MICP_MIC_DEV */ + +int bt_le_nimble_audio_start(void *info) +{ + struct bt_gatt_service *inc_csis_svc = NULL; + int err = 0; + +#if CONFIG_BT_CSIP_SET_MEMBER + /* Note: + * Should add CSIS before CAS in case one CSIS instance + * is included by CAS. + */ + err = nimble_gatt_csis_init(info, &inc_csis_svc); + if (err) { + return err; + } +#endif /* CONFIG_BT_CSIP_SET_MEMBER */ + +#if CONFIG_BT_CAP_ACCEPTOR + err = bt_le_nimble_cas_init(inc_csis_svc); + if (err) { + return err; + } +#else /* CONFIG_BT_CAP_ACCEPTOR */ + ARG_UNUSED(inc_csis_svc); +#endif /* CONFIG_BT_CAP_ACCEPTOR */ + +#if (BLE_AUDIO_SVC_SEP_ADD == 0) +#if CONFIG_BT_MCS + err = bt_le_nimble_media_proxy_pl_init(); + if (err) { + return err; + } +#endif /* CONFIG_BT_MCS */ + +#if CONFIG_BT_VCP_VOL_REND + err = bt_le_nimble_vcp_vol_rend_init(); + if (err) { + return err; + } +#endif /* CONFIG_BT_VCP_VOL_REND */ + +#if CONFIG_BT_MICP_MIC_DEV + err = bt_le_nimble_micp_mic_dev_init(); + if (err) { + return err; + } +#endif /* CONFIG_BT_MICP_MIC_DEV */ +#endif /* (BLE_AUDIO_SVC_SEP_ADD == 0) */ + + err = ble_gatts_start(); + if (err) { + LOG_ERR("[N]GattsStartFail[%d]", err); + return err; + } + + err = nimble_gatt_attr_handle_set(); + if (err) { + return err; + } + + return err; +} diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/init.h b/components/bt/esp_ble_audio/host/adapter/nimble/init.h new file mode 100644 index 0000000000..5e7d0211d3 --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/init.h @@ -0,0 +1,42 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef HOST_NIMBLE_INIT_H_ +#define HOST_NIMBLE_INIT_H_ + +#include + +#include "nimble/profiles/ascs.h" +#include "nimble/profiles/bass.h" +#include "nimble/profiles/cas.h" +#include "nimble/profiles/csis.h" +#include "nimble/profiles/mcs.h" +#include "nimble/profiles/mics.h" +#include "nimble/profiles/pacs.h" +#include "nimble/profiles/tbs.h" +#include "nimble/profiles/tmas.h" +#include "nimble/profiles/vcs.h" +#include "nimble/profiles/has.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int bt_le_nimble_audio_init(void); + +int bt_le_nimble_media_proxy_pl_init(void); + +int bt_le_nimble_vcp_vol_rend_init(void); + +int bt_le_nimble_micp_mic_dev_init(void); + +int bt_le_nimble_audio_start(void *info); + +#ifdef __cplusplus +} +#endif + +#endif /* HOST_NIMBLE_INIT_H_ */ diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/iso.c b/components/bt/esp_ble_audio/host/adapter/nimble/iso.c new file mode 100644 index 0000000000..3ad173f444 --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/iso.c @@ -0,0 +1,861 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include + +#include <../host/conn_internal.h> +#include <../host/iso_internal.h> + +#include "../src/ble_hs_priv.h" +#include "host/ble_hs_iso.h" +#include "host/ble_hs_iso_hci.h" + +#include "common/host.h" + +extern int ble_hs_iso_evt_rx_cb_set(void *cb); +#if CONFIG_BT_ISO_RX +extern int ble_hs_iso_pkt_rx_cb_set(ble_hs_iso_pkt_rx_fn cb); +#endif /* CONFIG_BT_ISO_RX */ + +static int hci_cmd_read_iso_tx_sync(struct net_buf *buf, struct net_buf **rsp) +{ + uint16_t packet_seq_num = 0; + uint32_t tx_time_stamp = 0; + uint32_t time_offset = 0; + uint16_t conn_handle; + int status; + + assert(rsp); + + assert(buf->len >= 5); + + conn_handle = sys_get_le16(buf->data + 3); + + ble_hs_lock(); + + status = ble_hs_hci_read_iso_tx_sync(conn_handle, + &packet_seq_num, + &tx_time_stamp, + &time_offset); + if (status) { + LOG_ERR("[N]RdIsoTxSyncFail[%u][%02x]", conn_handle, status); + } + + ble_hs_unlock(); + + if (status) { + net_buf_unref(buf); + *rsp = NULL; + } else { + net_buf_reset(buf); + net_buf_add_u8(buf, status); + net_buf_add_le16(buf, conn_handle); + net_buf_add_le16(buf, packet_seq_num); + net_buf_add_le32(buf, tx_time_stamp); + net_buf_add_le24(buf, time_offset); + *rsp = buf; + } + + return status; +} + +static int hci_cmd_set_cig_params(struct net_buf *buf, struct net_buf **rsp) +{ + struct ble_hci_le_cis_params *cis_params = NULL; + uint32_t sdu_interval_c_to_p; + uint32_t sdu_interval_p_to_c; + uint8_t worst_case_sca; + uint16_t mtl_c_to_p; + uint16_t mtl_p_to_c; + uint8_t cis_count; + uint8_t packing; + uint8_t framing; + uint8_t cig_id; + uint8_t rp_len; + uint8_t *rp; + int status; + + assert(rsp); + + assert(buf->len >= 18); + + cig_id = buf->data[3]; + sdu_interval_c_to_p = sys_get_le24(buf->data + 4); + sdu_interval_p_to_c = sys_get_le24(buf->data + 7); + worst_case_sca = buf->data[10]; + packing = buf->data[11]; + framing = buf->data[12]; + mtl_c_to_p = sys_get_le16(buf->data + 13); + mtl_p_to_c = sys_get_le16(buf->data + 15); + cis_count = buf->data[17]; + + assert(buf->len >= 18 + cis_count * sizeof(struct ble_hci_le_cis_params)); + + /* The cis_count can be 0 */ + if (cis_count) { + cis_params = calloc(1, cis_count * sizeof(struct ble_hci_le_cis_params)); + assert(cis_params); + } + + rp_len = sizeof(struct ble_hci_le_set_cig_params_rp) + cis_count * 2; + rp = calloc(1, rp_len); + assert(rp); + + for (size_t i = 0; i < cis_count; i++) { + cis_params[i].cis_id = buf->data[18 + i * sizeof(struct ble_hci_le_cis_params)]; + cis_params[i].max_sdu_c_to_p = sys_get_le16(buf->data + 19 + i * sizeof(struct ble_hci_le_cis_params)); + cis_params[i].max_sdu_p_to_c = sys_get_le16(buf->data + 21 + i * sizeof(struct ble_hci_le_cis_params)); + cis_params[i].phy_c_to_p = buf->data[23 + i * sizeof(struct ble_hci_le_cis_params)]; + cis_params[i].phy_p_to_c = buf->data[24 + i * sizeof(struct ble_hci_le_cis_params)]; + cis_params[i].rtn_c_to_p = buf->data[25 + i * sizeof(struct ble_hci_le_cis_params)]; + cis_params[i].rtn_p_to_c = buf->data[26 + i * sizeof(struct ble_hci_le_cis_params)]; + } + + ble_hs_lock(); + + status = ble_hs_hci_set_cig_params(cig_id, + sdu_interval_c_to_p, + sdu_interval_p_to_c, + worst_case_sca, + packing, + framing, + mtl_c_to_p, + mtl_p_to_c, + cis_count, + cis_params, + rp, + rp_len); + if (status) { + LOG_ERR("[N]SetCigParamsFail[%u][%02x]", cig_id, status); + } + + ble_hs_unlock(); + + if (status) { + net_buf_unref(buf); + *rsp = NULL; + } else { + net_buf_reset(buf); + net_buf_add_u8(buf, status); + net_buf_add_u8(buf, rp[0]); + net_buf_add_u8(buf, rp[1]); + for (size_t i = 0; i < cis_count; i++) { + net_buf_add_le16(buf, sys_get_le16(rp + sizeof(struct ble_hci_le_set_cig_params_rp) + i * 2)); + } + *rsp = buf; + } + + free(cis_params); + free(rp); + + return status; +} + +static int hci_cmd_set_cig_params_test(struct net_buf *buf, struct net_buf **rsp) +{ + struct ble_hci_le_cis_params_test *cis_params = NULL; + uint32_t sdu_interval_c_to_p; + uint32_t sdu_interval_p_to_c; + uint8_t worst_case_sca; + uint16_t iso_interval; + uint8_t ft_c_to_p; + uint8_t ft_p_to_c; + uint8_t cis_count; + uint8_t packing; + uint8_t framing; + uint8_t cig_id; + uint8_t rp_len; + uint8_t *rp; + int status; + + assert(rsp); + + assert(buf->len >= 18); + + cig_id = buf->data[3]; + sdu_interval_c_to_p = sys_get_le24(buf->data + 4); + sdu_interval_p_to_c = sys_get_le24(buf->data + 7); + ft_c_to_p = buf->data[10]; + ft_p_to_c = buf->data[11]; + iso_interval = sys_get_le16(buf->data + 12); + worst_case_sca = buf->data[14]; + packing = buf->data[15]; + framing = buf->data[16]; + cis_count = buf->data[17]; + + assert(buf->len >= 18 + cis_count * sizeof(struct ble_hci_le_cis_params_test)); + + /* The cis_count can be 0 */ + if (cis_count) { + cis_params = calloc(1, cis_count * sizeof(struct ble_hci_le_cis_params_test)); + assert(cis_params); + } + + rp_len = sizeof(struct ble_hci_le_set_cig_params_test_rp) + cis_count * 2; + rp = calloc(1, rp_len); + assert(rp); + + for (size_t i = 0; i < cis_count; i++) { + cis_params[i].cis_id = buf->data[18 + i * sizeof(struct ble_hci_le_cis_params_test)]; + cis_params[i].nse = buf->data[19 + i * sizeof(struct ble_hci_le_cis_params_test)]; + cis_params[i].max_sdu_c_to_p = sys_get_le16(buf->data + 20 + i * sizeof(struct ble_hci_le_cis_params_test)); + cis_params[i].max_sdu_p_to_c = sys_get_le16(buf->data + 22 + i * sizeof(struct ble_hci_le_cis_params_test)); + cis_params[i].max_pdu_c_to_p = sys_get_le16(buf->data + 24 + i * sizeof(struct ble_hci_le_cis_params_test)); + cis_params[i].max_pdu_p_to_c = sys_get_le16(buf->data + 26 + i * sizeof(struct ble_hci_le_cis_params_test)); + cis_params[i].phy_c_to_p = buf->data[28 + i * sizeof(struct ble_hci_le_cis_params_test)]; + cis_params[i].phy_p_to_c = buf->data[29 + i * sizeof(struct ble_hci_le_cis_params_test)]; + cis_params[i].bn_c_to_p = buf->data[30 + i * sizeof(struct ble_hci_le_cis_params_test)]; + cis_params[i].bn_p_to_c = buf->data[31 + i * sizeof(struct ble_hci_le_cis_params_test)]; + } + + ble_hs_lock(); + + status = ble_hs_hci_set_cig_params_test(cig_id, + sdu_interval_c_to_p, + sdu_interval_p_to_c, + ft_c_to_p, + ft_p_to_c, + iso_interval, + worst_case_sca, + packing, + framing, + cis_count, + cis_params, + rp, + rp_len); + if (status) { + LOG_ERR("[N]SetCigParamsTestFail[%u][%02x]", cig_id, status); + } + + ble_hs_unlock(); + + if (status) { + net_buf_unref(buf); + *rsp = NULL; + } else { + net_buf_reset(buf); + net_buf_add_u8(buf, status); + net_buf_add_u8(buf, rp[0]); + net_buf_add_u8(buf, rp[1]); + for (size_t i = 0; i < cis_count; i++) { + net_buf_add_le16(buf, sys_get_le16(rp + sizeof(struct ble_hci_le_set_cig_params_test_rp) + i * 2)); + } + *rsp = buf; + } + + free(cis_params); + free(rp); + + return status; +} + +static int hci_cmd_create_cis(struct net_buf *buf, struct net_buf **rsp) +{ + struct ble_hci_le_create_cis_params *cis_params; + uint8_t cis_count; + int status; + + ARG_UNUSED(rsp); + + assert(buf->len >= 4); + + /* The cis_count shall be at least 1 */ + cis_count = buf->data[3]; + + assert(buf->len >= 4 + cis_count * sizeof(struct ble_hci_le_create_cis_params)); + + cis_params = calloc(1, cis_count * sizeof(struct ble_hci_le_create_cis_params)); + assert(cis_params); + + for (size_t i = 0; i < cis_count; i++) { + cis_params[i].cis_handle = sys_get_le16(buf->data + 4 + i * sizeof(struct ble_hci_le_create_cis_params)); + cis_params[i].conn_handle = sys_get_le16(buf->data + 6 + i * sizeof(struct ble_hci_le_create_cis_params)); + } + + ble_hs_lock(); + + status = ble_hs_hci_create_cis(cis_count, cis_params); + if (status) { + LOG_ERR("[N]CreateCisFail[%u][%02x]", cis_count, status); + } + + ble_hs_unlock(); + + net_buf_unref(buf); + free(cis_params); + + return status; +} + +static int hci_cmd_remove_cig(struct net_buf *buf, struct net_buf **rsp) +{ + uint8_t cig_id; + int status; + + ARG_UNUSED(rsp); + + assert(buf->len >= 4); + + cig_id = buf->data[3]; + + ble_hs_lock(); + + status = ble_hs_hci_remove_cig(cig_id); + if (status) { + LOG_ERR("[N]RemoveCigFail[%u][%02x]", cig_id, status); + } + + ble_hs_unlock(); + + net_buf_unref(buf); + + return status; +} + +static int hci_cmd_accept_cis_req(struct net_buf *buf, struct net_buf **rsp) +{ + uint16_t cis_handle; + int status; + + ARG_UNUSED(rsp); + + assert(buf->len >= 5); + + cis_handle = sys_get_le16(buf->data + 3); + + ble_hs_lock(); + + status = ble_hs_hci_accept_cis_request(cis_handle); + if (status) { + LOG_ERR("[N]AcceptCisReqFail[%u][%02x]", cis_handle, status); + } + + ble_hs_unlock(); + + net_buf_unref(buf); + + return status; +} + +static int hci_cmd_reject_cis_req(struct net_buf *buf, struct net_buf **rsp) +{ + uint16_t cis_handle; + uint8_t reason; + int status; + + ARG_UNUSED(rsp); + + assert(buf->len >= 6); + + cis_handle = sys_get_le16(buf->data + 3); + reason = buf->data[5]; + + ble_hs_lock(); + + status = ble_hs_hci_reject_cis_request(cis_handle, reason); + if (status) { + LOG_ERR("[N]RejectCisReqFail[%u][%02x]", cis_handle, status); + } + + ble_hs_unlock(); + + net_buf_unref(buf); + + return status; +} + +static int hci_cmd_create_big(struct net_buf *buf, struct net_buf **rsp) +{ + uint8_t big_handle; + uint8_t adv_handle; + uint8_t num_bis; + uint32_t sdu_interval; + uint16_t max_sdu; + uint16_t mtl; + uint8_t rtn; + uint8_t phy; + uint8_t packing; + uint8_t framing; + uint8_t encryption; + uint8_t *bst_code; + int status; + + ARG_UNUSED(rsp); + + assert(buf->len >= 34); + + big_handle = buf->data[3]; + adv_handle = buf->data[4]; + num_bis = buf->data[5]; + sdu_interval = sys_get_le24(buf->data + 6); + max_sdu = sys_get_le16(buf->data + 9); + mtl = sys_get_le16(buf->data + 11); + rtn = buf->data[13]; + phy = buf->data[14]; + packing = buf->data[15]; + framing = buf->data[16]; + encryption = buf->data[17]; + bst_code = buf->data + 18; + + ble_hs_lock(); + + status = ble_hs_hci_create_big(big_handle, + adv_handle, + num_bis, + sdu_interval, + max_sdu, + mtl, + rtn, + phy, + packing, + framing, + encryption, + bst_code); + if (status) { + LOG_ERR("[N]CreateBigFail[%u][%02x]", big_handle, status); + } + + ble_hs_unlock(); + + net_buf_unref(buf); + + return status; +} + +static int hci_cmd_create_big_test(struct net_buf *buf, struct net_buf **rsp) +{ + uint8_t big_handle; + uint8_t adv_handle; + uint8_t num_bis; + uint32_t sdu_interval; + uint16_t iso_interval; + uint16_t max_sdu; + uint16_t max_pdu; + uint8_t nse; + uint8_t phy; + uint8_t packing; + uint8_t framing; + uint8_t bn; + uint8_t irc; + uint8_t pto; + uint8_t encryption; + uint8_t *bst_code; + int status; + + ARG_UNUSED(rsp); + + assert(buf->len >= 39); + + big_handle = buf->data[3]; + adv_handle = buf->data[4]; + num_bis = buf->data[5]; + sdu_interval = sys_get_le24(buf->data + 6); + iso_interval = sys_get_le16(buf->data + 9); + nse = buf->data[11]; + max_sdu = sys_get_le16(buf->data + 12); + max_pdu = sys_get_le16(buf->data + 14); + phy = buf->data[16]; + packing = buf->data[17]; + framing = buf->data[18]; + bn = buf->data[19]; + irc = buf->data[20]; + pto = buf->data[21]; + encryption = buf->data[22]; + bst_code = buf->data + 23; + + ble_hs_lock(); + + status = ble_hs_hci_create_big_test(big_handle, + adv_handle, + num_bis, + sdu_interval, + iso_interval, + nse, + max_sdu, + max_pdu, + phy, + packing, + framing, + bn, + irc, + pto, + encryption, + bst_code); + if (status) { + LOG_ERR("[N]CreateBigTestFail[%u][%02x]", big_handle, status); + } + + ble_hs_unlock(); + + net_buf_unref(buf); + + return status; +} + +static int hci_cmd_terminate_big(struct net_buf *buf, struct net_buf **rsp) +{ + uint8_t big_handle; + uint8_t reason; + int status; + + ARG_UNUSED(rsp); + + assert(buf->len >= 5); + + big_handle = buf->data[3]; + reason = buf->data[4]; + + ble_hs_lock(); + + status = ble_hs_hci_terminate_big(big_handle, reason); + if (status) { + LOG_ERR("[N]TerminateBigFail[%u][%02x]", big_handle, status); + } + + ble_hs_unlock(); + + net_buf_unref(buf); + + return status; +} + +static int hci_cmd_big_create_sync(struct net_buf *buf, struct net_buf **rsp) +{ + uint16_t sync_timeout; + uint16_t sync_handle; + uint8_t big_handle; + uint8_t encryption; + uint8_t *bst_code; + uint8_t num_bis; + uint8_t *bis; + uint8_t mse; + int status; + + ARG_UNUSED(rsp); + + assert(buf->len >= 27); + + big_handle = buf->data[3]; + sync_handle = sys_get_le16(buf->data + 4); + encryption = buf->data[6]; + bst_code = buf->data + 7; + mse = buf->data[23]; + sync_timeout = sys_get_le16(buf->data + 24); + num_bis = buf->data[26]; + bis = buf->data + 27; + + assert(buf->len >= 27 + num_bis); + + ble_hs_lock(); + + status = ble_hs_hci_big_create_sync(big_handle, + sync_handle, + encryption, + bst_code, + mse, + sync_timeout, + num_bis, + bis); + if (status) { + LOG_ERR("[N]BigCreateSyncFail[%u][%02x]", big_handle, status); + } + + ble_hs_unlock(); + + net_buf_unref(buf); + + return status; +} + +static int hci_cmd_big_terminate_sync(struct net_buf *buf, struct net_buf **rsp) +{ + uint8_t big_handle; + int status; + + assert(rsp); + + assert(buf->len >= 4); + + big_handle = buf->data[3]; + + ble_hs_lock(); + + status = ble_hs_hci_big_terminate_sync(big_handle); + if (status) { + LOG_ERR("[N]BigTerminateSyncFail[%u][%02x]", big_handle, status); + } + + ble_hs_unlock(); + + if (status) { + net_buf_unref(buf); + *rsp = NULL; + } else { + net_buf_reset(buf); + net_buf_add_u8(buf, status); + net_buf_add_u8(buf, big_handle); + *rsp = buf; + } + + return status; +} + +static int hci_cmd_setup_iso_data_path(struct net_buf *buf, struct net_buf **rsp) +{ + uint8_t data_path_direction; + uint32_t controller_delay; + uint16_t conn_handle; + uint8_t data_path_id; + uint8_t coding_format; + uint16_t company_id; + uint16_t vs_codec_id; + uint8_t codec_cfg_len; + uint8_t *codec_cfg; + int status; + + assert(rsp); + + assert(buf->len >= 16); + + conn_handle = sys_get_le16(buf->data + 3); + data_path_direction = buf->data[5]; + data_path_id = buf->data[6]; + coding_format = buf->data[7]; + company_id = sys_get_le16(buf->data + 8); + vs_codec_id = sys_get_le16(buf->data + 10); + controller_delay = sys_get_le24(buf->data + 12); + codec_cfg_len = buf->data[15]; + codec_cfg = buf->data + 16; + + assert(buf->len >= 16 + codec_cfg_len); + + ble_hs_lock(); + + status = ble_hs_hci_setup_iso_data_path(conn_handle, + data_path_direction, + data_path_id, + coding_format, + company_id, + vs_codec_id, + controller_delay, + codec_cfg_len, + codec_cfg); + if (status) { + LOG_ERR("[N]SetupIsoDataPathFail[%u][%02x]", conn_handle, status); + } + + ble_hs_unlock(); + + if (status) { + net_buf_unref(buf); + *rsp = NULL; + } else { + net_buf_reset(buf); + net_buf_add_u8(buf, status); + net_buf_add_le16(buf, conn_handle); + *rsp = buf; + } + + return status; +} + +static int hci_cmd_remove_iso_data_path(struct net_buf *buf, struct net_buf **rsp) +{ + uint8_t data_path_direction; + uint16_t conn_handle; + int status; + + assert(rsp); + + assert(buf->len >= 6); + + conn_handle = sys_get_le16(buf->data + 3); + data_path_direction = buf->data[5]; + + ble_hs_lock(); + + status = ble_hs_hci_remove_iso_data_path(conn_handle, data_path_direction); + if (status) { + LOG_ERR("[N]RemoveIsoDataPathFail[%u][%02x]", conn_handle, status); + } + + ble_hs_unlock(); + + if (status) { + net_buf_unref(buf); + *rsp = NULL; + } else { + net_buf_reset(buf); + net_buf_add_u8(buf, status); + net_buf_add_le16(buf, conn_handle); + *rsp = buf; + } + + return status; +} + +int bt_le_nimble_iso_cmd_send_sync(uint16_t opcode, + struct net_buf *buf, + struct net_buf **rsp) +{ + switch (opcode) { + case BT_HCI_OP_LE_READ_ISO_TX_SYNC: + return hci_cmd_read_iso_tx_sync(buf, rsp); + + case BT_HCI_OP_LE_SET_CIG_PARAMS: + return hci_cmd_set_cig_params(buf, rsp); + + case BT_HCI_OP_LE_SET_CIG_PARAMS_TEST: + return hci_cmd_set_cig_params_test(buf, rsp); + + case BT_HCI_OP_LE_CREATE_CIS: + return hci_cmd_create_cis(buf, rsp); + + case BT_HCI_OP_LE_REMOVE_CIG: + return hci_cmd_remove_cig(buf, rsp); + + case BT_HCI_OP_LE_ACCEPT_CIS: + return hci_cmd_accept_cis_req(buf, rsp); + + case BT_HCI_OP_LE_REJECT_CIS: + return hci_cmd_reject_cis_req(buf, rsp); + + case BT_HCI_OP_LE_CREATE_BIG: + return hci_cmd_create_big(buf, rsp); + + case BT_HCI_OP_LE_CREATE_BIG_TEST: + return hci_cmd_create_big_test(buf, rsp); + + case BT_HCI_OP_LE_TERMINATE_BIG: + return hci_cmd_terminate_big(buf, rsp); + + case BT_HCI_OP_LE_BIG_CREATE_SYNC: + return hci_cmd_big_create_sync(buf, rsp); + + case BT_HCI_OP_LE_BIG_TERMINATE_SYNC: + return hci_cmd_big_terminate_sync(buf, rsp); + + case BT_HCI_OP_LE_SETUP_ISO_PATH: + return hci_cmd_setup_iso_data_path(buf, rsp); + + case BT_HCI_OP_LE_REMOVE_ISO_PATH: + return hci_cmd_remove_iso_data_path(buf, rsp); + + default: + LOG_ERR("[N]IsoCmdNotSupp[%04x]", opcode); + net_buf_unref(buf); + return -ENOTSUP; + } +} + +static void iso_evt_rx(uint8_t event, const void *data, + unsigned int len, bool le_meta) +{ + size_t qdata_len; + uint8_t *qdata; + int err; + + if (event != BT_HCI_EVT_LE_BIGINFO_ADV_REPORT) { + LOG_DBG("[N]ISOEvtRx[%02x][%u][%u]", event, len, le_meta); + } + + qdata_len = len + 2; + + qdata = calloc(1, qdata_len); + assert(qdata); + + qdata[0] = le_meta; + qdata[1] = event; + memcpy(qdata + 2, data, len); + + err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_ISO_HCI_EVENT, qdata, qdata_len); + if (err) { + LOG_ERR("[N]IsoPostEvtFail[%d][%02x]", err, event); + free(qdata); + } +} + +#if CONFIG_BT_ISO_UNICAST +static int iso_enable_cis(void) +{ + int err; + + ble_hs_lock(); + + err = ble_hs_hci_set_host_feature(32, 1); + if (err) { + LOG_ERR("[N]IsoEnableCisFail[%d]", err); + } + + ble_hs_unlock(); + + return err; +} + +static int iso_disable_cis(void) +{ + int err; + + ble_hs_lock(); + + err = ble_hs_hci_set_host_feature(32, 0); + if (err) { + LOG_ERR("[N]IsoDisableCisFail[%d]", err); + } + + ble_hs_unlock(); + + return err; +} +#endif /* CONFIG_BT_ISO_UNICAST */ + +int bt_le_nimble_iso_init(void) +{ + int err; + + err = ble_hs_iso_evt_rx_cb_set(iso_evt_rx); + if (err) { + LOG_ERR("[N]IsoEvtRxCbSetFail[%d]", err); + return err; + } + +#if CONFIG_BT_ISO_RX + err = ble_hs_iso_pkt_rx_cb_set(bt_le_iso_rx); + if (err) { + LOG_ERR("[N]IsoPktRxCbSetFail[%d]", err); + return err; + } +#endif /* CONFIG_BT_ISO_RX */ + +#if CONFIG_BT_ISO_UNICAST + /* Set Connected Isochronous Streams - Host support */ + err = iso_enable_cis(); + if (err) { + return err; + } +#endif /* CONFIG_BT_ISO_UNICAST */ + + return 0; +} + +void bt_le_nimble_iso_deinit(void) +{ + LOG_DBG("IsoDeinit"); + + ble_hs_iso_evt_rx_cb_set(NULL); + +#if CONFIG_BT_ISO_RX + ble_hs_iso_pkt_rx_cb_set(NULL); +#endif /* CONFIG_BT_ISO_RX */ + +#if CONFIG_BT_ISO_UNICAST + iso_disable_cis(); +#endif /* CONFIG_BT_ISO_UNICAST */ +} diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/iso.h b/components/bt/esp_ble_audio/host/adapter/nimble/iso.h new file mode 100644 index 0000000000..06c33a77bd --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/iso.h @@ -0,0 +1,28 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef HOST_NIMBLE_ISO_H_ +#define HOST_NIMBLE_ISO_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int bt_le_nimble_iso_cmd_send_sync(uint16_t opcode, + struct net_buf *buf, + struct net_buf **rsp); + +int bt_le_nimble_iso_init(void); + +void bt_le_nimble_iso_deinit(void); + +#ifdef __cplusplus +} +#endif + +#endif /* HOST_NIMBLE_ISO_H_ */ diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/l2cap.c b/components/bt/esp_ble_audio/host/adapter/nimble/l2cap.c new file mode 100644 index 0000000000..2f6e49c9ef --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/l2cap.c @@ -0,0 +1,322 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include <../host/conn_internal.h> + +#include "host/ble_hs.h" +#include "host/ble_l2cap.h" +#include "host/ble_hs_mbuf.h" +#include "../../../nimble/host/src/ble_l2cap_priv.h" + +#include "common/host.h" + +_Static_assert(CONFIG_BT_NIMBLE_L2CAP_COC_MAX_NUM && "At least one L2CAP coc shall be supported"); + +#define OTS_L2CAP_BUF_COUNT (3 * CONFIG_BT_NIMBLE_L2CAP_COC_MAX_NUM) +#define OTS_L2CAP_MEM_SIZE OS_MEMPOOL_SIZE(OTS_L2CAP_BUF_COUNT, L2CAP_LE_OTS_MTU * 2) + +static os_membuf_t ots_mem[OTS_L2CAP_MEM_SIZE]; +static struct os_mempool ots_mbuf_mempool; +static struct os_mbuf_pool ots_mbuf_pool; + +static struct ble_l2cap_chan *ots_chan; + +static int ots_l2cap_recv_ready(struct ble_l2cap_chan *chan) +{ + struct os_mbuf *sdu_rx; + int rc; + + LOG_DBG("[N]OtsRecvReady"); + + sdu_rx = os_mbuf_get_pkthdr(&ots_mbuf_pool, 0); + if (sdu_rx == NULL) { + LOG_ERR("[N]NoBufForL2capRecv"); + return -ENOMEM; + } + + rc = ble_l2cap_recv_ready(chan, sdu_rx); + if (rc) { + LOG_ERR("[N]L2capRecvFail[%d]", rc); + + os_mbuf_free_chain(sdu_rx); + return rc; + } + + return 0; +} + +static int ots_l2cap_event_cb(struct ble_l2cap_event *event, void *arg) +{ + struct ble_l2cap_chan_info chan_info; + uint16_t result = 0; + size_t sdu_len; + uint8_t *sdu; + int err; + + LOG_DBG("[N]OtsEvtCb[%u]", event->type); + + switch (event->type) { + case BLE_L2CAP_EVENT_COC_CONNECTED: + if (event->connect.status) { + LOG_ERR("[N]CocConnectFail[%d]", event->connect.status); + return 0; + } + + if (ots_chan) { + LOG_ERR("[N]CocChanExist"); + return 0; + } + + ots_chan = event->connect.chan; + + if (ble_l2cap_get_chan_info(event->connect.chan, &chan_info)) { + assert(0); + } + + LOG_DBG("[N]CocConnect[%u][%04x][%04x][%04x][%u][%u][%u][%u]", + event->connect.conn_handle, chan_info.scid, chan_info.dcid, + chan_info.psm, chan_info.our_l2cap_mtu, chan_info.peer_l2cap_mtu, + chan_info.our_coc_mtu, chan_info.peer_coc_mtu); + + bt_le_l2cap_connected(event->connect.conn_handle, chan_info.psm, + chan_info.dcid, chan_info.peer_coc_mtu, + chan_info.scid, chan_info.our_coc_mtu); + return 0; + + case BLE_L2CAP_EVENT_COC_DISCONNECTED: + if (ots_chan != event->disconnect.chan) { + LOG_ERR("[N]DisconnectInvCocChan"); + return 0; + } + + LOG_DBG("[N]CocDisconnect[%u][%04x]", + event->disconnect.conn_handle, event->disconnect.chan->psm); + + bt_le_l2cap_disconnected(event->disconnect.conn_handle, event->disconnect.chan->psm); + + ots_chan = NULL; + return 0; + + case BLE_L2CAP_EVENT_COC_ACCEPT: + if (event->accept.peer_sdu_size > L2CAP_LE_OTS_MTU) { + LOG_ERR("[N]InvAcceptMtu[%u][%u]", + event->accept.peer_sdu_size, L2CAP_LE_OTS_MTU); + return -EINVAL; + } + + LOG_DBG("[N]CocAccept[%u][%04x][%04x][%u][%u][%u][%u]", + event->accept.conn_handle, event->accept.chan->psm, + event->accept.chan->dcid, event->accept.chan->coc_tx.mtu, + event->accept.chan->peer_coc_mps, event->accept.peer_sdu_size, + event->accept.chan->coc_tx.credits); + + err = bt_le_l2cap_accept(event->accept.conn_handle, + event->accept.chan->psm, + event->accept.chan->dcid, + event->accept.chan->coc_tx.mtu, + event->accept.chan->peer_coc_mps, + event->accept.chan->coc_tx.credits, + &result); + if (err) { + return err; + } + + ARG_UNUSED(result); + + return ots_l2cap_recv_ready(event->accept.chan); + + case BLE_L2CAP_EVENT_COC_DATA_RECEIVED: + if (ots_chan != event->receive.chan) { + LOG_ERR("[N]RecvOnInvCocChan"); + return 0; + } + + assert(event->receive.sdu_rx); + + LOG_DBG("[N]CocReceive[%u][%04x][%u]", + event->receive.conn_handle, event->receive.chan->psm, + event->receive.sdu_rx->om_len); + + sdu_len = OS_MBUF_PKTLEN(event->receive.sdu_rx); + + sdu = calloc(1, sdu_len); + assert(sdu); + + err = os_mbuf_copydata(event->receive.sdu_rx, 0, sdu_len, sdu); + assert(err == 0); + + bt_le_l2cap_received(event->receive.conn_handle, + event->receive.chan->psm, + sdu, sdu_len); + + os_mbuf_free_chain(event->receive.sdu_rx); + free(sdu); + + return ots_l2cap_recv_ready(event->receive.chan); + + case BLE_L2CAP_EVENT_COC_TX_UNSTALLED: + if (ots_chan != event->tx_unstalled.chan) { + LOG_ERR("[N]TxUnstalledOnInvCocChan"); + return 0; + } + + LOG_DBG("[N]CocTxUnstalled[%u][%d]", + event->tx_unstalled.conn_handle, event->tx_unstalled.status); + + /* TODO: transmit the remaining data */ + return 0; + + default: + return 0; + } +} + +int bt_le_nimble_l2cap_chan_connect(uint16_t conn_handle) +{ + struct os_mbuf *sdu_rx; + int rc; + + if (ots_chan) { + LOG_WRN("[N]OtsChanExist"); + return -EALREADY; + } + + sdu_rx = os_mbuf_get_pkthdr(&ots_mbuf_pool, 0); + if (sdu_rx == NULL) { + LOG_ERR("[N]NoBufForL2capConnect"); + return -ENOMEM; + } + + rc = ble_l2cap_connect(conn_handle, L2CAP_LE_OTS_PSM, L2CAP_LE_OTS_MTU, + sdu_rx, ots_l2cap_event_cb, NULL); + if (rc) { + LOG_ERR("[N]L2capConnectFail[%d]", rc); + + os_mbuf_free_chain(sdu_rx); + return rc; + } + + return 0; +} + +int bt_le_nimble_l2cap_chan_disconnect(struct bt_l2cap_chan *chan) +{ + int rc; + + if (ots_chan == NULL) { + LOG_WRN("[N]NoOtsChan"); + return -ENOTCONN; + } + + if (ble_l2cap_get_conn_handle(ots_chan) != chan->conn->handle) { + LOG_ERR("[N]UnexpOtsChan[%u][%u]", + ble_l2cap_get_conn_handle(ots_chan), chan->conn->handle); + return -EINVAL; + } + + rc = ble_l2cap_disconnect(ots_chan); + if (rc) { + LOG_ERR("[N]L2capDisconnectFail[%d]", rc); + return rc; + } + + return 0; +} + +int bt_le_nimble_l2cap_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf) +{ + struct os_mbuf *sdu_tx; + int rc; + + if (ots_chan == NULL) { + LOG_WRN("[N]NoOtsChan"); + return -ENOTCONN; + } + + if (ble_l2cap_get_conn_handle(ots_chan) != chan->conn->handle) { + LOG_ERR("[N]UnexpOtsChan[%u][%u]", + ble_l2cap_get_conn_handle(ots_chan), chan->conn->handle); + return -EINVAL; + } + + sdu_tx = os_mbuf_get_pkthdr(&ots_mbuf_pool, 0); + if (sdu_tx == NULL) { + LOG_ERR("[N]NoBufForL2capSend"); + return -ENOMEM; + } + + rc = os_mbuf_append(sdu_tx, buf->data, buf->len); + if (rc) { + LOG_ERR("[N]AppendBufFail[%d]", rc); + os_mbuf_free_chain(sdu_tx); + return -EIO; + } + + rc = ble_l2cap_send(ots_chan, sdu_tx); + if (rc) { + if (rc == BLE_HS_ESTALLED) { + /* TODO: + * Wait for the BLE_L2CAP_EVENT_COC_TX_UNSTALLED event and continue. + */ + LOG_WRN("[N]MoreCreditsForL2capSend"); + } else { + LOG_ERR("[N]L2capSendFail[%d]", rc); + } + + os_mbuf_free_chain(sdu_tx); + return rc; + } + + return 0; +} + +int bt_le_nimble_l2cap_init(void) +{ + int rc; + + rc = os_mempool_init(&ots_mbuf_mempool, OTS_L2CAP_BUF_COUNT, L2CAP_LE_OTS_MTU * 2, ots_mem, "ots_pool"); + if (rc) { + LOG_ERR("[N]InitOtsMempoolFail[%d]", rc); + return rc; + } + + rc = os_mbuf_pool_init(&ots_mbuf_pool, &ots_mbuf_mempool, L2CAP_LE_OTS_MTU, OTS_L2CAP_BUF_COUNT); + if (rc) { + LOG_ERR("[N]InitOtsMbufPoolFail[%d]", rc); + return rc; + } + +#if CONFIG_BT_OTS + rc = ble_l2cap_create_server(L2CAP_LE_OTS_PSM, L2CAP_LE_OTS_MTU, ots_l2cap_event_cb, NULL); + if (rc) { + LOG_ERR("[N]CreateL2capSrvFail[%d]", rc); + return rc; + } +#endif /* CONFIG_BT_OTS */ + + return 0; +} + +void bt_le_nimble_l2cap_deinit(void) +{ + LOG_DBG("NimbleL2capDeinit"); + + /* TODO: free the ots_mbuf_pool and ots_mbuf_mempool */ + +#if CONFIG_BT_OTS + /* TODO: destroy the server */ +#endif /* CONFIG_BT_OTS */ +} diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/l2cap.h b/components/bt/esp_ble_audio/host/adapter/nimble/l2cap.h new file mode 100644 index 0000000000..b3b3aa8c14 --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/l2cap.h @@ -0,0 +1,32 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef HOST_NIMBLE_L2CAP_H_ +#define HOST_NIMBLE_L2CAP_H_ + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int bt_le_nimble_l2cap_chan_connect(uint16_t conn_handle); + +int bt_le_nimble_l2cap_chan_disconnect(struct bt_l2cap_chan *chan); + +int bt_le_nimble_l2cap_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf); + +int bt_le_nimble_l2cap_init(void); + +void bt_le_nimble_l2cap_deinit(void); + +#ifdef __cplusplus +} +#endif + +#endif /* HOST_NIMBLE_L2CAP_H_ */ diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/profiles/ascs.c b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/ascs.c new file mode 100644 index 0000000000..d19314b1a7 --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/ascs.c @@ -0,0 +1,230 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include <../host/conn_internal.h> + +#include "os/os_mbuf.h" +#include "os/os_mempool.h" +#include "host/ble_att.h" +#include "host/ble_gatt.h" +#include "host/ble_hs_mbuf.h" + +#include "nimble/profiles/server.h" + +#include "common/host.h" + +#include "../../../lib/include/audio.h" + +static const ble_uuid16_t ascs_uuid_ase_cp = BLE_UUID16_INIT(BT_UUID_ASCS_ASE_CP_VAL); +static const ble_uuid16_t ascs_uuid_ase_snk = BLE_UUID16_INIT(BT_UUID_ASCS_ASE_SNK_VAL); +static const ble_uuid16_t ascs_uuid_ase_src = BLE_UUID16_INIT(BT_UUID_ASCS_ASE_SRC_VAL); + +static uint16_t ase_control_point_handle; +static uint16_t ase_snk_handle[CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT]; +static uint16_t ase_src_handle[CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT]; + +static struct ble_gatt_svc_def gatt_svc_ascs[] = { + { + /* Audio Stream Control Service */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(BT_UUID_ASCS_VAL), + .includes = NULL, + .characteristics = NULL, + }, + { + 0, /* No more services. */ + }, +}; + +static void ascs_svc_add_ase_cp_chr(struct ble_gatt_chr_def *chr) +{ + LOG_DBG("[N]AscsSvcAddAseCpChr"); + + chr->uuid = &ascs_uuid_ase_cp.u; + chr->access_cb = bt_le_nimble_gatts_access_cb_safe; + chr->arg = NULL; + chr->descriptors = NULL; /* NULL if no descriptors. Do not include CCCD */ + chr->flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_NO_RSP | \ + BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_WRITE_ENC; + chr->min_key_size = 16; + chr->val_handle = &ase_control_point_handle; +} + +#if CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT > 0 +static void ascs_svc_add_ase_snk_chr(struct ble_gatt_chr_def *chrs) +{ + for (size_t i = 0 ; i < CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT; i++) { + struct ble_gatt_chr_def *chr = chrs + i; + + LOG_DBG("[N]AscsSvcAddAseSnkChr[%u]", i); + + chr->uuid = &ascs_uuid_ase_snk.u; + chr->access_cb = bt_le_nimble_gatts_access_cb_safe; + chr->arg = UINT_TO_POINTER(i); + chr->descriptors = NULL; /* NULL if no descriptors. Do not include CCCD */ + chr->flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC; + chr->min_key_size = 16; + chr->val_handle = &ase_snk_handle[i]; + } +} +#endif /* CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT > 0 */ + +#if CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT > 0 +static void ascs_svc_add_ase_src_chr(struct ble_gatt_chr_def *chrs) +{ + for (size_t i = 0 ; i < CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT; i++) { + struct ble_gatt_chr_def *chr = chrs + i; + + LOG_DBG("[N]AscsSvcAddAseSrcChr[%u]", i); + + chr->uuid = &ascs_uuid_ase_src.u; + chr->access_cb = bt_le_nimble_gatts_access_cb_safe; + chr->arg = UINT_TO_POINTER(i); + chr->descriptors = NULL; /* NULL if no descriptors. Do not include CCCD */ + chr->flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC; + chr->min_key_size = 16; + chr->val_handle = &ase_src_handle[i]; + } +} +#endif /* CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT > 0 */ + +int bt_le_nimble_ascs_attr_handle_set(void) +{ + struct bt_gatt_service *ascs_svc; + struct bt_gatt_attr *attr; + uint16_t start_handle; + uint16_t end_handle; + + ascs_svc = lib_ascs_svc_get(); + assert(ascs_svc); + + assert(ase_control_point_handle >= 2); + start_handle = ase_control_point_handle - 2; /* server attr handle & char def handle */ +#if CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT > 0 + end_handle = ase_src_handle[CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT - 1] + 1; /* cccd attr handle */ +#elif CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT > 0 + end_handle = ase_snk_handle[CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT - 1] + 1; /* cccd attr handle */ +#else + end_handle = ase_control_point_handle + 1; /* cccd attr handle */ +#endif + + LOG_DBG("[N]AscsAttrHdlSet[%u][%u][%u]", + start_handle, end_handle, ascs_svc->attr_count); + + for (size_t i = 0; i < ascs_svc->attr_count; i++) { + (ascs_svc->attrs + i)->handle = start_handle + i; + } + + /* Last attribute in ASCS */ + attr = ascs_svc->attrs + ascs_svc->attr_count - 1; + + if (attr->handle != end_handle) { + LOG_ERR("[N]AscsMismatchAttrHhl[%u][%u][%u][%u]", + start_handle, end_handle, attr->handle, ascs_svc->attr_count); + return -1; + } + + return 0; +} + +static int ascs_svc_check(void) +{ + struct bt_gatt_service *ascs_svc; + const struct bt_uuid_16 *uuid; + bool chr_found; + + /* This function is used to make sure the characteristics within + * the service exist in the service defined by Zephyr. + */ + + ascs_svc = lib_ascs_svc_get(); + assert(ascs_svc); + + LOG_DBG("[N]AscsSvcCheck"); + + for (const struct ble_gatt_chr_def *chr = gatt_svc_ascs[0].characteristics; + chr && chr->uuid; chr++) { + const ble_uuid16_t *check = (const ble_uuid16_t *)chr->uuid; + + chr_found = false; + + for (size_t i = 0; i < ascs_svc->attr_count; i++) { + uuid = (const struct bt_uuid_16 *)(ascs_svc->attrs + i)->uuid; + + if (uuid && uuid->uuid.type == BT_LE_NIMBLE_GATT_UUID_TO_Z(check->u.type) && + uuid->val == check->value) { + chr_found = true; + break; + } + } + + if (chr_found == false) { + LOG_ERR("[N]AscsChrNotFound[%04x]", check->value); + return -1; + } + } + + return 0; +} + +int bt_le_nimble_ascs_init(void) +{ + uint16_t chr_count; + int rc; + + /* An additional characteristic consist of all 0s indicating end of characteristics */ + chr_count = 1 + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT + 1; + + LOG_DBG("[N]AscsInit[%u]", chr_count); + + gatt_svc_ascs[0].characteristics = calloc(chr_count, sizeof(struct ble_gatt_chr_def)); + assert(gatt_svc_ascs[0].characteristics); + + ascs_svc_add_ase_cp_chr((void *)(gatt_svc_ascs[0].characteristics + 0)); + +#if CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT > 0 + ascs_svc_add_ase_snk_chr((void *)(gatt_svc_ascs[0].characteristics + 1)); +#endif /* CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT > 0 */ + +#if CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT > 0 + ascs_svc_add_ase_src_chr((void *)(gatt_svc_ascs[0].characteristics + 1 + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT)); +#endif /* CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT > 0 */ + + rc = ble_gatts_count_cfg(gatt_svc_ascs); + if (rc) { + LOG_ERR("[N]AscsCountCfgFail[%d]", rc); + goto free; + } + + rc = ble_gatts_add_svcs(gatt_svc_ascs); + if (rc) { + LOG_ERR("[N]AscsAddSvcsFail[%d]", rc); + goto free; + } + + rc = ascs_svc_check(); + if (rc) { + goto free; + } + + return 0; + +free: + free((void *)gatt_svc_ascs[0].characteristics); + gatt_svc_ascs[0].characteristics = NULL; + return rc; +} diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/profiles/ascs.h b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/ascs.h new file mode 100644 index 0000000000..20ed621c08 --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/ascs.h @@ -0,0 +1,25 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef HOST_NIMBLE_PROFILE_ASCS_H_ +#define HOST_NIMBLE_PROFILE_ASCS_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int bt_le_nimble_ascs_attr_handle_set(void); + +int bt_le_nimble_ascs_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* HOST_NIMBLE_PROFILE_ASCS_H_ */ diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/profiles/bass.c b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/bass.c new file mode 100644 index 0000000000..096b0800b9 --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/bass.c @@ -0,0 +1,194 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include <../host/conn_internal.h> + +#include "os/os_mbuf.h" +#include "os/os_mempool.h" +#include "host/ble_att.h" +#include "host/ble_gatt.h" +#include "host/ble_hs_mbuf.h" + +#include "nimble/profiles/server.h" + +#include "common/host.h" + +#include "../../../lib/include/audio.h" + +static const ble_uuid16_t bass_uuid_control_point = BLE_UUID16_INIT(BT_UUID_BASS_CONTROL_POINT_VAL); +static const ble_uuid16_t bass_uuid_recv_state = BLE_UUID16_INIT(BT_UUID_BASS_RECV_STATE_VAL); + +static uint16_t bass_control_point_handle; +static uint16_t bass_recv_state_handle[CONFIG_BT_BAP_SCAN_DELEGATOR_RECV_STATE_COUNT]; + +static struct ble_gatt_svc_def gatt_svc_bass[] = { + { + /* Broadcast Audio Scan Service */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(BT_UUID_BASS_VAL), + .includes = NULL, + .characteristics = NULL, + }, + { + 0, /* No more services. */ + }, +}; + +static void bass_svc_add_control_point_chr(struct ble_gatt_chr_def *chr) +{ + LOG_DBG("[N]BassSvcAddControlPointChr"); + + chr->uuid = &bass_uuid_control_point.u; + chr->access_cb = bt_le_nimble_gatts_access_cb_safe; + chr->arg = NULL; + chr->descriptors = NULL; /* NULL if no descriptors. Do not include CCCD */ + chr->flags = BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_ENC; + chr->min_key_size = 16; + chr->val_handle = &bass_control_point_handle; +} + +static void bass_svc_add_recv_state_chr(struct ble_gatt_chr_def *chrs) +{ + for (size_t i = 0 ; i < CONFIG_BT_BAP_SCAN_DELEGATOR_RECV_STATE_COUNT; i++) { + struct ble_gatt_chr_def *chr = chrs + i; + + LOG_DBG("[N]BassSvcAddRecvStateChr[%u]", i); + + chr->uuid = &bass_uuid_recv_state.u; + chr->access_cb = bt_le_nimble_gatts_access_cb_safe; + chr->arg = UINT_TO_POINTER(i); + chr->descriptors = NULL; /* NULL if no descriptors. Do not include CCCD */ + chr->flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC; + chr->min_key_size = 16; + chr->val_handle = &bass_recv_state_handle[i]; + } +} + +int bt_le_nimble_bass_attr_handle_set(void) +{ + struct bt_gatt_service *bass_svc; + struct bt_gatt_attr *attr; + uint16_t start_handle; + uint16_t end_handle; + + bass_svc = lib_bap_bass_svc_get(); + assert(bass_svc); + + assert(bass_control_point_handle >= 2); + start_handle = bass_control_point_handle - 2; /* server attr handle & char def handle */ + end_handle = bass_recv_state_handle[CONFIG_BT_BAP_SCAN_DELEGATOR_RECV_STATE_COUNT - 1] + 1; /* cccd attr handle */ + + LOG_DBG("[N]BassAttrHdlSet[%u][%u][%u]", + start_handle, end_handle, bass_svc->attr_count); + + for (size_t i = 0; i < bass_svc->attr_count; i++) { + (bass_svc->attrs + i)->handle = start_handle + i; + } + + /* Last attribute in BASS */ + attr = bass_svc->attrs + bass_svc->attr_count - 1; + + if (attr->handle != end_handle) { + LOG_ERR("[N]BassMismatchAttrHdl[%u][%u][%u][%u]", + start_handle, end_handle, attr->handle, bass_svc->attr_count); + return -1; + } + + return 0; +} + +static int bass_svc_check(void) +{ + struct bt_gatt_service *bass_svc; + const struct bt_uuid_16 *uuid; + bool chr_found; + + /* This function is used to make sure the characteristics within + * the service exist in the service defined by Zephyr. + */ + + bass_svc = lib_bap_bass_svc_get(); + assert(bass_svc); + + LOG_DBG("[N]BassSvcCheck"); + + for (const struct ble_gatt_chr_def *chr = gatt_svc_bass->characteristics; + chr && chr->uuid; chr++) { + const ble_uuid16_t *check = (const ble_uuid16_t *)chr->uuid; + + chr_found = false; + + for (size_t i = 0; i < bass_svc->attr_count; i++) { + uuid = (const struct bt_uuid_16 *)(bass_svc->attrs + i)->uuid; + + if (uuid->uuid.type == BT_LE_NIMBLE_GATT_UUID_TO_Z(check->u.type) && + uuid->val == check->value) { + chr_found = true; + break; + } + } + + if (chr_found == false) { + LOG_ERR("[N]BassChrNotFound[%04x]", check->value); + return -1; + } + } + + return 0; +} + +int bt_le_nimble_bass_init(void) +{ + uint16_t chr_count; + int rc; + + /* An additional characteristic consist of all 0s indicating end of characteristics */ + chr_count = 1 + CONFIG_BT_BAP_SCAN_DELEGATOR_RECV_STATE_COUNT + 1; + + LOG_DBG("[N]BassInit[%u]", chr_count); + + gatt_svc_bass->characteristics = calloc(chr_count, sizeof(struct ble_gatt_chr_def)); + assert(gatt_svc_bass->characteristics); + + bass_svc_add_control_point_chr((void *)(gatt_svc_bass->characteristics + 0)); + + bass_svc_add_recv_state_chr((void *)(gatt_svc_bass->characteristics + 1)); + + rc = ble_gatts_count_cfg(gatt_svc_bass); + if (rc) { + LOG_ERR("[N]BassCountCfgFail[%d]", rc); + goto free; + } + + rc = ble_gatts_add_svcs(gatt_svc_bass); + if (rc) { + LOG_ERR("[N]BassAddSvcsFail[%d]", rc); + goto free; + } + + rc = bass_svc_check(); + if (rc) { + goto free; + } + + return 0; + +free: + free((void *)gatt_svc_bass->characteristics); + gatt_svc_bass->characteristics = NULL; + return rc; +} diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/profiles/bass.h b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/bass.h new file mode 100644 index 0000000000..69ddc64c29 --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/bass.h @@ -0,0 +1,25 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef HOST_NIMBLE_PROFILE_BASS_H_ +#define HOST_NIMBLE_PROFILE_BASS_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int bt_le_nimble_bass_attr_handle_set(void); + +int bt_le_nimble_bass_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* HOST_NIMBLE_PROFILE_BASS_H_ */ diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/profiles/cas.c b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/cas.c new file mode 100644 index 0000000000..1b7bd92907 --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/cas.c @@ -0,0 +1,126 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include <../host/conn_internal.h> + +#include "host/ble_gatt.h" + +#include "common/host.h" + +#include "../../../lib/include/audio.h" + +#if CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER +extern struct ble_gatt_svc_def *cas_get_included_csis(void *csis_svc_p); + +static struct bt_gatt_service *inc_csis_svc; + +static struct ble_gatt_svc_def *cas_inc_svcs[] = { + NULL, + NULL, +}; +#endif /* CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER */ + +static struct ble_gatt_svc_def gatt_svc_cas[] = { + { + /* Published Audio Capabilities Service */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(BT_UUID_CAS_VAL), + .includes = NULL, + .characteristics = NULL, + }, + { + 0, /* No more services. */ + }, +}; + +int bt_le_nimble_cas_attr_handle_set(void) +{ + struct bt_gatt_service *cas_svc; + uint16_t handle; + int rc; + + cas_svc = lib_cas_svc_get(); + assert(cas_svc); + + LOG_DBG("[N]CasAttrHdlSet[%u]", cas_svc->attr_count); + + rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_CAS_VAL), &handle); + if (rc) { + LOG_ERR("[N]CasNotFound[%d]", rc); + return rc; + } + + LOG_DBG("[N]Hdl[%u]", handle); + + for (size_t i = 0; i < cas_svc->attr_count; i++) { + (cas_svc->attrs + i)->handle = handle + i; + } + + return 0; +} + +int bt_le_nimble_cas_init(void *csis_svc_p) +{ + int rc; + + LOG_DBG("[N]CasInit[%p]", csis_svc_p); + +#if CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER + /* The instance of CSIS is included by CAS */ + if (csis_svc_p) { + cas_inc_svcs[0] = cas_get_included_csis(csis_svc_p); + if (cas_inc_svcs[0] == NULL) { + LOG_ERR("[N]CasIncCsisNotFound"); + return -1; + } + + /* Terminate the included service array with NULL */ + cas_inc_svcs[1] = NULL; + + gatt_svc_cas[0].includes = (const struct ble_gatt_svc_def **)cas_inc_svcs; + + inc_csis_svc = csis_svc_p; + } +#else /* CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER */ + ARG_UNUSED(csis_svc_p); +#endif /* CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER */ + + rc = ble_gatts_count_cfg(gatt_svc_cas); + if (rc) { + LOG_ERR("[N]CasCountCfgFail[%d]", rc); + return rc; + } + + rc = ble_gatts_add_svcs(gatt_svc_cas); + if (rc) { + LOG_ERR("[N]CasAddSvcsFail[%d]", rc); + return rc; + } + +#if !CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER + struct bt_gatt_service *cas_svc; + + cas_svc = lib_cas_svc_get(); + assert(cas_svc); + + /* Insert CAS to the GATT db list */ + rc = bt_gatt_service_register_safe(cas_svc); + if (rc) { + LOG_ERR("[N]CasSvcRegFail[%d]", rc); + } +#endif /* !CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER */ + + return rc; +} diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/profiles/cas.h b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/cas.h new file mode 100644 index 0000000000..55ede2ddba --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/cas.h @@ -0,0 +1,25 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef HOST_NIMBLE_PROFILE_CAS_H_ +#define HOST_NIMBLE_PROFILE_CAS_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int bt_le_nimble_cas_attr_handle_set(void); + +int bt_le_nimble_cas_init(void *csis_svc); + +#ifdef __cplusplus +} +#endif + +#endif /* HOST_NIMBLE_PROFILE_CAS_H_ */ diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/profiles/csis.c b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/csis.c new file mode 100644 index 0000000000..992e84a0c8 --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/csis.c @@ -0,0 +1,271 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include <../host/conn_internal.h> + +#include "os/os_mbuf.h" +#include "os/os_mempool.h" +#include "host/ble_att.h" +#include "host/ble_gatt.h" +#include "host/ble_hs_mbuf.h" + +#include "nimble/profiles/server.h" + +#include "common/host.h" + +#include "../../../lib/include/audio.h" + +#define CSIS_SVC_COUNT CONFIG_BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT + +#define CSIS_CHR_COUNT (4 + 1) + +#if CONFIG_BT_CSIP_SET_MEMBER_SIRK_NOTIFIABLE +#define CSIS_CHR_FLAGS_SIRK \ + (BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC) +#else /* CONFIG_BT_CSIP_SET_MEMBER_SIRK_NOTIFIABLE */ +#define CSIS_CHR_FLAGS_SIRK \ + (BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC) +#endif /* CONFIG_BT_CSIP_SET_MEMBER_SIRK_NOTIFIABLE */ + +#define CSIS_CHR_FLAGS_SET_SIZE \ + (BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC) + +#define CSIS_CHR_FLAGS_SET_LOCK \ + (BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_WRITE | \ + BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC) + +#define CSIS_CHR_FLAGS_RANK \ + (BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC) + +static const ble_uuid16_t csis_uuid_svc = BLE_UUID16_INIT(BT_UUID_CSIS_VAL); +static const ble_uuid16_t csis_uuid_sirk = BLE_UUID16_INIT(BT_UUID_CSIS_SIRK_VAL); +static const ble_uuid16_t csis_uuid_set_size = BLE_UUID16_INIT(BT_UUID_CSIS_SET_SIZE_VAL); +static const ble_uuid16_t csis_uuid_set_lock = BLE_UUID16_INIT(BT_UUID_CSIS_SET_LOCK_VAL); +static const ble_uuid16_t csis_uuid_rank = BLE_UUID16_INIT(BT_UUID_CSIS_RANK_VAL); + +static struct csis_inst { + struct bt_gatt_service *svc_p; + uint16_t sirk_handle; + uint16_t set_size_handle; + uint16_t set_lock_handle; + uint16_t rank_handle; +} csis_insts[CSIS_SVC_COUNT]; + +static uint8_t csis_svc_count; + +/* Extra one for terminating the CSIS service array */ +static struct ble_gatt_svc_def gatt_svc_csis[CSIS_SVC_COUNT + 1]; + +struct ble_gatt_svc_def *cas_get_included_csis(void *csis_svc_p) +{ + size_t i; + + LOG_DBG("[N]CasGetIncCsis[%u]", csis_svc_count); + + for (i = 0; i < csis_svc_count; i++) { + if (csis_insts[i].svc_p == csis_svc_p) { + break; + } + } + + if (i == csis_svc_count) { + return NULL; + } + + return &gatt_svc_csis[i]; +} + +static int csis_svc_check(void) +{ + const struct bt_uuid_16 *uuid; + bool chr_found; + + /* This function is used to make sure the characteristics within + * the service exist in the service defined by Zephyr. + */ + + LOG_DBG("[N]CsisSvcCheck[%u]", csis_svc_count); + + for (size_t i = 0; i < csis_svc_count; i++) { + struct ble_gatt_svc_def *csis = &gatt_svc_csis[i]; + struct bt_gatt_service *svc = csis_insts[i].svc_p; + + assert(svc); + + for (const struct ble_gatt_chr_def *chr = csis->characteristics; + chr && chr->uuid; chr++) { + const ble_uuid16_t *check = (const ble_uuid16_t *)chr->uuid; + + chr_found = false; + + for (size_t j = 0; j < svc->attr_count; j++) { + uuid = (const struct bt_uuid_16 *)(svc->attrs + j)->uuid; + + if (uuid->uuid.type == BT_LE_NIMBLE_GATT_UUID_TO_Z(check->u.type) && + uuid->val == check->value) { + chr_found = true; + break; + } + } + + if (chr_found == false) { + LOG_ERR("[N]CsisChrNotFound[%u][%04x]", i, check->value); + return -1; + } + } + } + + return 0; +} + +int bt_le_nimble_csis_attr_handle_set(void) +{ + struct bt_gatt_attr *attr; + uint16_t start_handle; + uint16_t end_handle; + + LOG_DBG("[N]CsisAttrHdlSet[%u]", csis_svc_count); + + for (size_t i = 0; i < csis_svc_count; i++) { + assert(csis_insts[i].svc_p); + + assert(csis_insts[i].sirk_handle >= 2); + start_handle = csis_insts[i].sirk_handle - 2; /* server attr handle & char def handle */ + end_handle = csis_insts[i].rank_handle; /* no cccd for chr Set Member Rank */ + + LOG_DBG("[N]CsisInst[%u][%u][%u][%u]", + i, start_handle, end_handle, csis_insts[i].svc_p->attr_count); + + for (size_t j = 0; j < csis_insts[i].svc_p->attr_count; j++) { + (csis_insts[i].svc_p->attrs + j)->handle = start_handle + j; + } + + /* Last attribute in CSIS */ + attr = csis_insts[i].svc_p->attrs + csis_insts[i].svc_p->attr_count - 1; + + if (attr->handle != end_handle) { + LOG_ERR("[N]CsisMismatchAttrHdl[%u][%u][%u][%u][%u]", + i, start_handle, end_handle, attr->handle, + csis_insts[i].svc_p->attr_count); + return -1; + } + } + + return 0; +} + +static inline void csis_chr_init(struct ble_gatt_chr_def *chr, + const ble_uuid16_t *uuid, + uint16_t *val_handle, + ble_gatt_chr_flags flags) +{ + LOG_DBG("[N]CsisChrInit[%04x]", uuid->value); + + chr->uuid = &uuid->u; + chr->access_cb = bt_le_nimble_gatts_access_cb_safe; + chr->arg = NULL; + chr->descriptors = NULL; /* NULL if no descriptors. Do not include CCCD */ + chr->flags = flags; + chr->min_key_size = 16; + chr->val_handle = val_handle; +} + +static void csis_svc_init(struct csis_inst *inst, + struct ble_gatt_svc_def *svc) +{ + LOG_DBG("[N]CsisSvcInit"); + + svc->type = BLE_GATT_SVC_TYPE_PRIMARY; + svc->uuid = &csis_uuid_svc.u; + svc->includes = NULL; + + svc->characteristics = calloc(CSIS_CHR_COUNT, sizeof(struct ble_gatt_chr_def)); + assert(svc->characteristics); + + /* Characteristic - Set Identity Resolving Key */ + csis_chr_init((void *)&svc->characteristics[0], + &csis_uuid_sirk, + &inst->sirk_handle, + CSIS_CHR_FLAGS_SIRK); + + /* Characteristic - Coordinated Set Size */ + csis_chr_init((void *)&svc->characteristics[1], + &csis_uuid_set_size, + &inst->set_size_handle, + CSIS_CHR_FLAGS_SET_SIZE); + + /* Characteristic - Set Member Lock */ + csis_chr_init((void *)&svc->characteristics[2], + &csis_uuid_set_lock, + &inst->set_lock_handle, + CSIS_CHR_FLAGS_SET_LOCK); + + /* Characteristic - Set Member Rank */ + csis_chr_init((void *)&svc->characteristics[3], + &csis_uuid_rank, + &inst->rank_handle, + CSIS_CHR_FLAGS_RANK); +} + +int bt_le_nimble_csis_init(void *svc, uint8_t count) +{ + int rc; + + LOG_DBG("[N]CsisInit[%u]", count); + + if (count > CSIS_SVC_COUNT) { + LOG_ERR("[N]InvCsisCount[%u][%u]", count, CSIS_SVC_COUNT); + return -1; + } + + csis_svc_count = count; + + for (size_t i = 0; i < csis_svc_count; i++) { + csis_svc_init(&csis_insts[i], &gatt_svc_csis[i]); + + csis_insts[i].svc_p = ((struct bt_gatt_service **)svc)[i]; + } + + rc = ble_gatts_count_cfg(gatt_svc_csis); + if (rc) { + LOG_ERR("[N]CsisCountCfgFail[%d]", rc); + goto free; + } + + rc = ble_gatts_add_svcs(gatt_svc_csis); + if (rc) { + LOG_ERR("[N]CsisAddSvcsFail[%d]", rc); + goto free; + } + + rc = csis_svc_check(); + if (rc) { + goto free; + } + + return 0; + +free: + for (size_t i = 0; i < csis_svc_count; i++) { + free((void *)gatt_svc_csis[i].characteristics); + gatt_svc_csis[i].characteristics = NULL; + } + csis_svc_count = 0; + return rc; +} diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/profiles/csis.h b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/csis.h new file mode 100644 index 0000000000..e2912395e2 --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/csis.h @@ -0,0 +1,28 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef HOST_NIMBLE_PROFILE_CSIS_H_ +#define HOST_NIMBLE_PROFILE_CSIS_H_ + +#include +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int bt_le_nimble_csis_attr_handle_set(void); + +int bt_le_nimble_csis_init(void *csis_svc, uint8_t count); + +#ifdef __cplusplus +} +#endif + +#endif /* HOST_NIMBLE_PROFILE_CSIS_H_ */ diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/profiles/has.c b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/has.c new file mode 100644 index 0000000000..599e06e95f --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/has.c @@ -0,0 +1,231 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include <../host/conn_internal.h> + +#include "os/os_mbuf.h" +#include "os/os_mempool.h" +#include "host/ble_att.h" +#include "host/ble_gatt.h" +#include "host/ble_hs_mbuf.h" + +#include "nimble/profiles/server.h" + +#include "common/host.h" + +#include "../../../lib/include/audio.h" + +static const ble_uuid16_t has_uuid_features = BLE_UUID16_INIT(BT_UUID_HAS_HEARING_AID_FEATURES_VAL); +static const ble_uuid16_t has_uuid_control_point = BLE_UUID16_INIT(BT_UUID_HAS_PRESET_CONTROL_POINT_VAL); +static const ble_uuid16_t has_uuid_preset_index = BLE_UUID16_INIT(BT_UUID_HAS_ACTIVE_PRESET_INDEX_VAL); + +static uint16_t has_features_handle; +static uint16_t has_control_point_handle; +static uint16_t has_preset_index_handle; + +static struct ble_gatt_svc_def gatt_svc_has[] = { + { + /* Hearing Access Service */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(BT_UUID_HAS_VAL), + .includes = NULL, + .characteristics = NULL, + }, + { + 0, /* No more services. */ + }, +}; + +static void has_svc_add_features_chr(struct ble_gatt_chr_def *chr) +{ + chr->uuid = &has_uuid_features.u; + chr->access_cb = bt_le_nimble_gatts_access_cb_safe; + chr->arg = NULL; + chr->descriptors = NULL; /* NULL if no descriptors. Do not include CCCD */ +#if CONFIG_BT_HAS_FEATURES_NOTIFIABLE + chr->flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC; +#else /* CONFIG_BT_HAS_FEATURES_NOTIFIABLE */ + chr->flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC; +#endif /* CONFIG_BT_HAS_FEATURES_NOTIFIABLE */ + chr->min_key_size = 16; + chr->val_handle = &has_features_handle; + + LOG_DBG("[N]HasSvcAddFeatChr[%04x]", chr->flags); +} + +static void has_svc_add_control_point_chr(struct ble_gatt_chr_def *chr) +{ + chr->uuid = &has_uuid_control_point.u; + chr->access_cb = bt_le_nimble_gatts_access_cb_safe; + chr->arg = NULL; + chr->descriptors = NULL; /* NULL if no descriptors. Do not include CCCD */ +#if CONFIG_BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE + chr->flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_INDICATE | + BLE_GATT_CHR_F_WRITE_ENC | BLE_GATT_CHR_F_NOTIFY; +#else /* CONFIG_BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE */ + chr->flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_INDICATE | BLE_GATT_CHR_F_WRITE_ENC; +#endif /* CONFIG_BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE */ + chr->min_key_size = 16; + chr->val_handle = &has_control_point_handle; + + LOG_DBG("[N]HasSvcAddControlPointChr[%04x]", chr->flags); +} + +#if CONFIG_BT_HAS_ACTIVE_PRESET_INDEX +static void has_svc_add_preset_index_chr(struct ble_gatt_chr_def *chr) +{ + LOG_DBG("[N]HasSvcAddPresetIndexChr"); + + chr->uuid = &has_uuid_preset_index.u; + chr->access_cb = bt_le_nimble_gatts_access_cb_safe; + chr->arg = NULL; + chr->descriptors = NULL; /* NULL if no descriptors. Do not include CCCD */ + chr->flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC; + chr->min_key_size = 16; + chr->val_handle = &has_preset_index_handle; +} +#endif /* CONFIG_BT_HAS_ACTIVE_PRESET_INDEX */ + +int bt_le_nimble_has_attr_handle_set(void) +{ + struct bt_gatt_service *has_svc; + struct bt_gatt_attr *attr; + uint16_t start_handle = 0; + uint16_t end_handle = 0; + int rc; + + has_svc = lib_has_svc_get(); + assert(has_svc); + + LOG_DBG("[N]HasAttrHdlSet[%u]", has_svc->attr_count); + assert(has_svc->attr_count > 0); + + rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_HAS_VAL), &start_handle); + if (rc) { + LOG_ERR("[N]HasNotFound[%d]", rc); + return rc; + } + + end_handle = start_handle + has_svc->attr_count - 1; + + LOG_DBG("[N]Hdl[%u][%u]", start_handle, end_handle); + + for (size_t i = 0; i < has_svc->attr_count; i++) { + (has_svc->attrs + i)->handle = start_handle + i; + } + + /* Last attribute in HAS */ + attr = has_svc->attrs + has_svc->attr_count - 1; + + if (attr->handle != end_handle) { + LOG_ERR("[N]HasMismatchAttrHdl (%u %u %u %u)", + start_handle, end_handle, attr->handle, has_svc->attr_count); + return -1; + } + + return 0; +} + +static int has_svc_check(void) +{ + struct bt_gatt_service *has_svc; + const struct bt_uuid_16 *uuid; + bool chr_found; + + /* This function is used to make sure the characteristics within + * the service exist in the service defined by Zephyr. + */ + + has_svc = lib_has_svc_get(); + assert(has_svc); + + LOG_DBG("[N]HasSvcCheck"); + + for (const struct ble_gatt_chr_def *chr = gatt_svc_has[0].characteristics; + chr && chr->uuid; chr++) { + const ble_uuid16_t *check = (const ble_uuid16_t *)chr->uuid; + + chr_found = false; + + for (size_t i = 0; i < has_svc->attr_count; i++) { + uuid = (const struct bt_uuid_16 *)(has_svc->attrs + i)->uuid; + + if (uuid->uuid.type == BT_LE_NIMBLE_GATT_UUID_TO_Z(check->u.type) && + uuid->val == check->value) { + chr_found = true; + break; + } + } + + if (chr_found == false) { + LOG_ERR("[N]HasChrNotFound[%04x]", check->value); + return -1; + } + } + + return 0; +} + +int bt_le_nimble_has_init(void) +{ + uint8_t chr_count; + int rc; + + /* An additional characteristic consist of all 0s indicating end of characteristics */ +#if CONFIG_BT_HAS_ACTIVE_PRESET_INDEX + chr_count = 1 + 1 + 1 + 1; +#else /* CONFIG_BT_HAS_ACTIVE_PRESET_INDEX */ + chr_count = 1 + 1 + 1; +#endif /* CONFIG_BT_HAS_ACTIVE_PRESET_INDEX */ + + LOG_DBG("[N]HasInit[%u]", chr_count); + + gatt_svc_has->characteristics = calloc(chr_count, sizeof(struct ble_gatt_chr_def)); + assert(gatt_svc_has->characteristics); + + has_svc_add_features_chr((void *)(gatt_svc_has->characteristics + 0)); + + has_svc_add_control_point_chr((void *)(gatt_svc_has->characteristics + 1)); + +#if CONFIG_BT_HAS_ACTIVE_PRESET_INDEX + has_svc_add_preset_index_chr((void *)(gatt_svc_has->characteristics + 2)); +#endif /* CONFIG_BT_HAS_ACTIVE_PRESET_INDEX */ + + rc = ble_gatts_count_cfg(gatt_svc_has); + if (rc) { + LOG_ERR("[N]HasCountCfgFail[%d]", rc); + goto free; + } + + rc = ble_gatts_add_svcs(gatt_svc_has); + if (rc) { + LOG_ERR("[N]HasAddSvcsFail[%d]", rc); + goto free; + } + + rc = has_svc_check(); + if (rc) { + goto free; + } + + return 0; + +free: + free((void *)gatt_svc_has->characteristics); + gatt_svc_has->characteristics = NULL; + return rc; +} diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/profiles/has.h b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/has.h new file mode 100644 index 0000000000..8c6cca72a9 --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/has.h @@ -0,0 +1,27 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef HOST_NIMBLE_PROFILE_HAS_H_ +#define HOST_NIMBLE_PROFILE_HAS_H_ + +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int bt_le_nimble_has_attr_handle_set(void); + +int bt_le_nimble_has_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* HOST_NIMBLE_PROFILE_HAS_H_ */ diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/profiles/mcs.c b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/mcs.c new file mode 100644 index 0000000000..2353808a17 --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/mcs.c @@ -0,0 +1,705 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#if CONFIG_BT_OTS +#include "ots_internal.h" +#endif /* CONFIG_BT_OTS */ + +#include <../host/conn_internal.h> + +#include "os/os_mbuf.h" +#include "os/os_mempool.h" +#include "host/ble_att.h" +#include "host/ble_gatt.h" +#include "host/ble_hs_mbuf.h" + +#include "nimble/profiles/server.h" + +#include "common/host.h" + +#include "../../../lib/include/audio.h" + +#if CONFIG_BT_OTS +#define INC_OTS_CHR_COUNT 8 /* - OTS Feature (M) + * - Object Name (M) + * - Object Type (M) + * - Object Size (M) + * - Object ID (C.1) + * - Object Properties (M) + * - Object Action Control Point (M) + * - Object List Control Point (C.1) + */ + +#define INC_OTS_CHR_FLAGS_FEATURE \ + (BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC) + +#if CONFIG_BT_OTS_OBJ_NAME_WRITE_SUPPORT +#define INC_OTS_CHR_FLAGS_NAME \ + (BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_ENC) +#else /* CONFIG_BT_OTS_OBJ_NAME_WRITE_SUPPORT */ +#define INC_OTS_CHR_FLAGS_NAME \ + (BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC) +#endif /* CONFIG_BT_OTS_OBJ_NAME_WRITE_SUPPORT */ + +#define INC_OTS_CHR_FLAGS_TYPE \ + (BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC) + +#define INC_OTS_CHR_FLAGS_SIZE \ + (BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC) + +#define INC_OTS_CHR_FLAGS_ID \ + (BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC) + +#define INC_OTS_CHR_FLAGS_PROPS \ + (BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC) + +#define INC_OTS_CHR_FLAGS_ACTION_CP \ + (BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_INDICATE | BLE_GATT_CHR_F_WRITE_ENC) + +#define INC_OTS_CHR_FLAGS_LIST_CP \ + (BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_INDICATE | BLE_GATT_CHR_F_WRITE_ENC) + +static uint8_t inc_ots_svc_count; + +static struct bt_ots *ots; +static uint16_t inc_ots_chr_feature_handle; +static uint16_t inc_ots_chr_name_handle; +static uint16_t inc_ots_chr_type_handle; +static uint16_t inc_ots_chr_size_handle; +static uint16_t inc_ots_chr_id_handle; +static uint16_t inc_ots_chr_props_handle; +static uint16_t inc_ots_chr_action_cp_handle; +static uint16_t inc_ots_chr_list_cp_handle; + +static struct ble_gatt_svc_def *gatt_svc_inc_ots; + +static struct ble_gatt_svc_def **gmcs_inc_svcs; + +static const ble_uuid16_t inc_ots_uuid_svc = BLE_UUID16_INIT(BT_UUID_OTS_VAL); +static const ble_uuid16_t inc_ots_uuid_feature = BLE_UUID16_INIT(BT_UUID_OTS_FEATURE_VAL); +static const ble_uuid16_t inc_ots_uuid_name = BLE_UUID16_INIT(BT_UUID_OTS_NAME_VAL); +static const ble_uuid16_t inc_ots_uuid_type = BLE_UUID16_INIT(BT_UUID_OTS_TYPE_VAL); +static const ble_uuid16_t inc_ots_uuid_size = BLE_UUID16_INIT(BT_UUID_OTS_SIZE_VAL); +static const ble_uuid16_t inc_ots_uuid_id = BLE_UUID16_INIT(BT_UUID_OTS_ID_VAL); +static const ble_uuid16_t inc_ots_uuid_props = BLE_UUID16_INIT(BT_UUID_OTS_PROPERTIES_VAL); +static const ble_uuid16_t inc_ots_uuid_action_cp = BLE_UUID16_INIT(BT_UUID_OTS_ACTION_CP_VAL); +static const ble_uuid16_t inc_ots_uuid_list_cp = BLE_UUID16_INIT(BT_UUID_OTS_LIST_CP_VAL); +#endif /* CONFIG_BT_OTS */ + +static uint16_t mcs_player_name_handle; +#if CONFIG_BT_OTS +static uint16_t mcs_icon_obj_id_handle; +#endif /* CONFIG_BT_OTS */ +static uint16_t mcs_icon_url_handle; +static uint16_t mcs_track_changed_handle; +static uint16_t mcs_track_title_handle; +static uint16_t mcs_track_duration_handle; +static uint16_t mcs_track_position_handle; +static uint16_t mcs_playback_speed_handle; +static uint16_t mcs_seeking_speed_handle; +#if CONFIG_BT_OTS +static uint16_t mcs_track_segments_obj_id_handle; +static uint16_t mcs_current_track_obj_id_handle; +static uint16_t mcs_next_track_obj_id_handle; +static uint16_t mcs_parent_group_obj_id_handle; +static uint16_t mcs_current_group_obj_id_handle; +#endif /* CONFIG_BT_OTS */ +static uint16_t mcs_playing_order_handle; +static uint16_t mcs_playing_orders_handle; +static uint16_t mcs_media_state_handle; +static uint16_t mcs_media_control_point_handle; +static uint16_t mcs_media_control_opcodes_handle; +#if CONFIG_BT_OTS +static uint16_t mcs_search_control_point_handle; +static uint16_t mcs_search_results_obj_id_handle; +#endif /* CONFIG_BT_OTS */ +static uint16_t ccid_handle; + +static struct ble_gatt_svc_def gatt_svc_gmcs[] = { + { + /* Published Audio Capabilities Service */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(BT_UUID_GMCS_VAL), + .includes = NULL, + .characteristics = (struct ble_gatt_chr_def[]) + { + { + .uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_PLAYER_NAME_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC, + .min_key_size = 16, + .val_handle = &mcs_player_name_handle, + }, +#if CONFIG_BT_OTS + { + .uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_ICON_OBJ_ID_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC, + .min_key_size = 16, + .val_handle = &mcs_icon_obj_id_handle, + }, +#endif /* CONFIG_BT_OTS */ + { + .uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_ICON_URL_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC, + .min_key_size = 16, + .val_handle = &mcs_icon_url_handle, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_TRACK_CHANGED_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_NOTIFY, + .min_key_size = 16, + .val_handle = &mcs_track_changed_handle, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_TRACK_TITLE_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC, + .min_key_size = 16, + .val_handle = &mcs_track_title_handle, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_TRACK_DURATION_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC, + .min_key_size = 16, + .val_handle = &mcs_track_duration_handle, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_TRACK_POSITION_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | \ + BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_NOTIFY | \ + BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC, + .min_key_size = 16, + .val_handle = &mcs_track_position_handle, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_PLAYBACK_SPEED_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | \ + BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_NOTIFY | \ + BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC, + .min_key_size = 16, + .val_handle = &mcs_playback_speed_handle, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_SEEKING_SPEED_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC, + .min_key_size = 16, + .val_handle = &mcs_seeking_speed_handle, + }, +#if CONFIG_BT_OTS + { + .uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_TRACK_SEGMENTS_OBJ_ID_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC, + .min_key_size = 16, + .val_handle = &mcs_track_segments_obj_id_handle, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_CURRENT_TRACK_OBJ_ID_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | \ + BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_NOTIFY | \ + BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC, + .min_key_size = 16, + .val_handle = &mcs_current_track_obj_id_handle, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_NEXT_TRACK_OBJ_ID_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | \ + BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_NOTIFY | \ + BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC, + .min_key_size = 16, + .val_handle = &mcs_next_track_obj_id_handle, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_PARENT_GROUP_OBJ_ID_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC, + .min_key_size = 16, + .val_handle = &mcs_parent_group_obj_id_handle, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_CURRENT_GROUP_OBJ_ID_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | \ + BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_NOTIFY | \ + BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC, + .min_key_size = 16, + .val_handle = &mcs_current_group_obj_id_handle, + }, +#endif /* CONFIG_BT_OTS */ + { + .uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_PLAYING_ORDER_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | \ + BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_NOTIFY | \ + BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC, + .min_key_size = 16, + .val_handle = &mcs_playing_order_handle, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_PLAYING_ORDERS_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC, + .min_key_size = 16, + .val_handle = &mcs_playing_orders_handle, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_MEDIA_STATE_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC, + .min_key_size = 16, + .val_handle = &mcs_media_state_handle, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_MEDIA_CONTROL_POINT_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_NO_RSP | \ + BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_WRITE_ENC, + .min_key_size = 16, + .val_handle = &mcs_media_control_point_handle, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_MEDIA_CONTROL_OPCODES_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC, + .min_key_size = 16, + .val_handle = &mcs_media_control_opcodes_handle, + }, +#if CONFIG_BT_OTS + { + .uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_SEARCH_CONTROL_POINT_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_NO_RSP | \ + BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_WRITE_ENC, + .min_key_size = 16, + .val_handle = &mcs_search_control_point_handle, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_MCS_SEARCH_RESULTS_OBJ_ID_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC, + .min_key_size = 16, + .val_handle = &mcs_search_results_obj_id_handle, + }, +#endif /* CONFIG_BT_OTS */ + { + .uuid = BLE_UUID16_DECLARE(BT_UUID_CCID_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC, + .min_key_size = 16, + .val_handle = &ccid_handle, + }, { + 0, /* No more characteristics in this service. */ + } + } + }, + { + 0, /* No more services. */ + }, +}; + +#if CONFIG_BT_OTS +static int inc_ots_attr_handle_set(void) +{ + struct bt_gatt_attr *attr; + uint16_t start_handle; + uint16_t end_handle; + + assert(ots && ots->service); + + assert(inc_ots_chr_feature_handle >= 2); + start_handle = inc_ots_chr_feature_handle - 2; /* server attr handle & char def handle */ + end_handle = inc_ots_chr_list_cp_handle + 1; /* cccd for chr Object List Control Point */ + + LOG_DBG("[N]IncOtsAttrHdlSet[%u][%u][%u]", + start_handle, end_handle, ots->service->attr_count); + + for (size_t i = 0; i < ots->service->attr_count; i++) { + (ots->service->attrs + i)->handle = start_handle + i; + } + + /* Last attribute in included OTS */ + attr = ots->service->attrs + ots->service->attr_count - 1; + + if (attr->handle != end_handle) { + LOG_ERR("[N]IncOtsMismatchAttrHdl[%u][%u][%u][%u]", + start_handle, end_handle, attr->handle, ots->service->attr_count); + return -1; + } + + return 0; +} +#endif /* CONFIG_BT_OTS */ + +int bt_le_nimble_gmcs_attr_handle_set(void) +{ + struct bt_gatt_service *gmcs_svc; + struct bt_gatt_attr *attr; + uint16_t start_handle = 0; + uint16_t end_handle = 0; + int rc; + + gmcs_svc = lib_mcs_svc_get(); + assert(gmcs_svc); + + LOG_DBG("[N]GmcsAttrHdlSet[%u]", gmcs_svc->attr_count); + + rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_GMCS_VAL), &start_handle); + if (rc) { + LOG_ERR("[N]GmcsNotFound[%d]", rc); + return rc; + } + + end_handle = start_handle + gmcs_svc->attr_count - 1; + + LOG_DBG("[N]Hdl[%u][%u]", start_handle, end_handle); + + for (size_t i = 0; i < gmcs_svc->attr_count; i++) { + (gmcs_svc->attrs + i)->handle = start_handle + i; + } + + /* Last attribute in MCS */ + attr = gmcs_svc->attrs + gmcs_svc->attr_count - 1; + + if (attr->handle != end_handle) { + LOG_ERR("[N]GmcsMismatchAttrHdl[%u][%u][%u][%u]", + start_handle, end_handle, attr->handle, gmcs_svc->attr_count); + return -1; + } + +#if CONFIG_BT_OTS + if (inc_ots_svc_count) { + rc = inc_ots_attr_handle_set(); + if (rc) { + return rc; + } + } +#endif /* CONFIG_BT_OTS */ + + return 0; +} + +static int gmcs_svc_check(void) +{ + struct bt_gatt_service *gmcs_svc; + const struct bt_uuid_16 *uuid; + bool chr_found; + + /* This function is used to make sure the characteristics within + * the service exist in the service defined by Zephyr. + */ + + gmcs_svc = lib_mcs_svc_get(); + assert(gmcs_svc); + + LOG_DBG("[N]GmcsSvcCheck"); + + for (const struct ble_gatt_chr_def *chr = gatt_svc_gmcs[0].characteristics; + chr && chr->uuid; chr++) { + const ble_uuid16_t *check = (const ble_uuid16_t *)chr->uuid; + + chr_found = false; + + for (size_t i = 0; i < gmcs_svc->attr_count; i++) { + uuid = (const struct bt_uuid_16 *)(gmcs_svc->attrs + i)->uuid; + + if (uuid->uuid.type == BT_LE_NIMBLE_GATT_UUID_TO_Z(check->u.type) && + uuid->val == check->value) { + chr_found = true; + break; + } + } + + if (chr_found == false) { + LOG_ERR("[N]GmcsChrNotFound[%04x]", check->value); + return -1; + } + } + + return 0; +} + +#if CONFIG_BT_OTS +static int inc_ots_svc_check(void) +{ + const struct bt_uuid_16 *uuid; + bool chr_found; + + /* This function is used to make sure the characteristics within + * the service exist in the service defined by Zephyr. + */ + + assert(gatt_svc_inc_ots); + assert(ots && ots->service); + + LOG_DBG("[N]IncOtsSvcCheck"); + + for (const struct ble_gatt_chr_def *chr = gatt_svc_inc_ots[0].characteristics; + chr && chr->uuid; chr++) { + const ble_uuid16_t *check = (const ble_uuid16_t *)chr->uuid; + + chr_found = false; + + for (size_t i = 0; i < ots->service->attr_count; i++) { + uuid = (const struct bt_uuid_16 *)(ots->service->attrs + i)->uuid; + + if (uuid->uuid.type == BT_LE_NIMBLE_GATT_UUID_TO_Z(check->u.type) && + uuid->val == check->value) { + chr_found = true; + break; + } + } + + if (chr_found == false) { + LOG_ERR("[N]IncOtsChrNotFound[%04x]", check->value); + return -1; + } + } + + return 0; +} + +static inline void inc_ots_chr_init(struct ble_gatt_chr_def *chr, + const ble_uuid16_t *uuid, + uint16_t *val_handle, + ble_gatt_chr_flags flags) +{ + LOG_DBG("[N]IncOtsChrInit[%04x]", uuid->value); + + chr->uuid = &uuid->u; + chr->access_cb = bt_le_nimble_gatts_access_cb_safe; + chr->arg = NULL; + chr->descriptors = NULL; /* NULL if no descriptors. Do not include CCCD */ + chr->flags = flags; + chr->min_key_size = 16; + chr->val_handle = val_handle; +} + +static int inc_ots_svc_init(void) +{ + struct ble_gatt_svc_def *svc; + struct bt_gatt_attr *attrs; + uint8_t chr_count; + + attrs = bt_ots_svc_decl_get(ots); + assert(attrs); + + chr_count = 0; + + for (size_t i = 0; i < ots->service->attr_count; i++) { + if (bt_uuid_cmp(attrs[i].uuid, BT_UUID_GATT_CHRC) == 0) { + chr_count++; + } + } + + LOG_DBG("[N]IncOtsSvcInit[%u]", chr_count); + + if (chr_count != INC_OTS_CHR_COUNT) { + LOG_ERR("[N]InvOtsChrCount[%u][%u]", chr_count, INC_OTS_CHR_COUNT); + return -EINVAL; + } + + svc = &gatt_svc_inc_ots[0]; + + svc->type = BLE_GATT_SVC_TYPE_SECONDARY; + svc->uuid = &inc_ots_uuid_svc.u; + svc->includes = NULL; + + /* An additional characteristic consist of all 0s indicating end of characteristics */ + svc->characteristics = calloc(INC_OTS_CHR_COUNT + 1, sizeof(struct ble_gatt_chr_def)); + assert(svc->characteristics); + + /* Characteristic - OTS Feature */ + inc_ots_chr_init((void *)&svc->characteristics[0], + &inc_ots_uuid_feature, + &inc_ots_chr_feature_handle, + INC_OTS_CHR_FLAGS_FEATURE); + + /* Characteristic - Object Name */ + inc_ots_chr_init((void *)&svc->characteristics[1], + &inc_ots_uuid_name, + &inc_ots_chr_name_handle, + INC_OTS_CHR_FLAGS_NAME); + + /* Characteristic - Object Type */ + inc_ots_chr_init((void *)&svc->characteristics[2], + &inc_ots_uuid_type, + &inc_ots_chr_type_handle, + INC_OTS_CHR_FLAGS_TYPE); + + /* Characteristic - Object Size */ + inc_ots_chr_init((void *)&svc->characteristics[3], + &inc_ots_uuid_size, + &inc_ots_chr_size_handle, + INC_OTS_CHR_FLAGS_SIZE); + + /* Characteristic - Object ID */ + inc_ots_chr_init((void *)&svc->characteristics[4], + &inc_ots_uuid_id, + &inc_ots_chr_id_handle, + INC_OTS_CHR_FLAGS_ID); + + /* Characteristic - Object Properties */ + inc_ots_chr_init((void *)&svc->characteristics[5], + &inc_ots_uuid_props, + &inc_ots_chr_props_handle, + INC_OTS_CHR_FLAGS_PROPS); + + /* Characteristic - Object Action Control Point */ + inc_ots_chr_init((void *)&svc->characteristics[6], + &inc_ots_uuid_action_cp, + &inc_ots_chr_action_cp_handle, + INC_OTS_CHR_FLAGS_ACTION_CP); + + /* Characteristic - Object List Control Point */ + inc_ots_chr_init((void *)&svc->characteristics[7], + &inc_ots_uuid_list_cp, + &inc_ots_chr_list_cp_handle, + INC_OTS_CHR_FLAGS_LIST_CP); + + return 0; +} +#endif /* CONFIG_BT_OTS */ + +int bt_le_nimble_gmcs_init(bool ots_included) +{ + int rc; + + LOG_DBG("[N]GmcsInit[%u]", ots_included); + +#if CONFIG_BT_OTS + if (ots_included) { + inc_ots_svc_count = 1; + + /* Extra one for terminating the included service array with NULL */ + gmcs_inc_svcs = calloc(2, sizeof(struct ble_gatt_svc_def *)); + assert(gmcs_inc_svcs); + + /* Extra one for terminating the OTS service array */ + gatt_svc_inc_ots = calloc(2, sizeof(struct ble_gatt_svc_def)); + assert(gatt_svc_inc_ots); + + ots = lib_mcs_get_ots(); + assert(ots && ots->service); + + rc = inc_ots_svc_init(); + if (rc) { + goto free; + } + + gmcs_inc_svcs[0] = &gatt_svc_inc_ots[0]; + + rc = ble_gatts_count_cfg(gatt_svc_inc_ots); + if (rc) { + LOG_ERR("[N]IncOtsCountCfgFail[%d]", rc); + goto free; + } + + rc = ble_gatts_add_svcs(gatt_svc_inc_ots); + if (rc) { + LOG_ERR("[N]IncOtsAddSvcsFail[%d]", rc); + goto free; + } + + rc = inc_ots_svc_check(); + if (rc) { + goto free; + } + + /* Terminate the included service array with NULL */ + gmcs_inc_svcs[1] = NULL; + } + + gatt_svc_gmcs[0].includes = (const struct ble_gatt_svc_def **)gmcs_inc_svcs; +#endif /* CONFIG_BT_OTS */ + + rc = ble_gatts_count_cfg(gatt_svc_gmcs); + if (rc) { + LOG_ERR("[N]GmcsCountCfgFail[%d]", rc); + goto free; + } + + rc = ble_gatts_add_svcs(gatt_svc_gmcs); + if (rc) { + LOG_ERR("[N]GmcsAddSvcsFail[%d]", rc); + goto free; + } + + rc = gmcs_svc_check(); + if (rc) { + goto free; + } + + return 0; + +free: +#if CONFIG_BT_OTS + if (ots_included) { + inc_ots_svc_count = 0; + + free(gmcs_inc_svcs); + gmcs_inc_svcs = NULL; + + if (gatt_svc_inc_ots[0].characteristics) { + free((void *)gatt_svc_inc_ots[0].characteristics); + gatt_svc_inc_ots[0].characteristics = NULL; + } + free(gatt_svc_inc_ots); + gatt_svc_inc_ots = NULL; + } + gatt_svc_gmcs[0].includes = NULL; +#endif /* CONFIG_BT_OTS */ + return rc; +} diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/profiles/mcs.h b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/mcs.h new file mode 100644 index 0000000000..f63593eb01 --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/mcs.h @@ -0,0 +1,28 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef HOST_NIMBLE_PROFILE_MCS_H_ +#define HOST_NIMBLE_PROFILE_MCS_H_ + +#include +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int bt_le_nimble_gmcs_attr_handle_set(void); + +int bt_le_nimble_gmcs_init(bool ots_included); + +#ifdef __cplusplus +} +#endif + +#endif /* HOST_NIMBLE_PROFILE_MCS_H_ */ diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/profiles/mics.c b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/mics.c new file mode 100644 index 0000000000..d20fe88f48 --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/mics.c @@ -0,0 +1,447 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include <../host/conn_internal.h> + +#include "os/os_mbuf.h" +#include "os/os_mempool.h" +#include "host/ble_att.h" +#include "host/ble_gatt.h" +#include "host/ble_hs_mbuf.h" + +#include "nimble/profiles/server.h" + +#include "common/host.h" + +#include "../../../lib/include/audio.h" + +#define INC_AICS_CHR_COUNT (6 + 1) + +#define INC_AICS_CHR_FLAGS_STATE \ + (BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC) + +#define INC_AICS_CHR_FLAGS_GAIN \ + (BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC) + +#define INC_AICS_CHR_FLAGS_TYPE \ + (BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC) + +#define INC_AICS_CHR_FLAGS_STATUS \ + (BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC) + +#define INC_AICS_CHR_FLAGS_CONTROL \ + (BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_ENC) + +#define INC_AICS_CHR_FLAGS_DESCRIPTION \ + (BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_WRITE_NO_RSP | \ + BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC) + +static uint8_t inc_aics_svc_count; + +static struct inc_aics_inst { + struct bt_gatt_service *svc_p; + uint16_t state_handle; + uint16_t gain_handle; + uint16_t type_handle; + uint16_t status_handle; + uint16_t control_handle; + uint16_t description_handle; +} *inc_aics_insts; + +static struct ble_gatt_svc_def *gatt_svc_inc_aics; + +static const ble_uuid16_t inc_aics_uuid_svc = BLE_UUID16_INIT(BT_UUID_AICS_VAL); +static const ble_uuid16_t inc_aics_uuid_state = BLE_UUID16_INIT(BT_UUID_AICS_STATE_VAL); +static const ble_uuid16_t inc_aics_uuid_gain = BLE_UUID16_INIT(BT_UUID_AICS_GAIN_SETTINGS_VAL); +static const ble_uuid16_t inc_aics_uuid_type = BLE_UUID16_INIT(BT_UUID_AICS_INPUT_TYPE_VAL); +static const ble_uuid16_t inc_aics_uuid_status = BLE_UUID16_INIT(BT_UUID_AICS_INPUT_STATUS_VAL); +static const ble_uuid16_t inc_aics_uuid_control = BLE_UUID16_INIT(BT_UUID_AICS_CONTROL_VAL); +static const ble_uuid16_t inc_aics_uuid_description = BLE_UUID16_INIT(BT_UUID_AICS_DESCRIPTION_VAL); + +static struct ble_gatt_svc_def **mics_inc_svcs; + +static uint16_t mics_mute_handle; + +static struct ble_gatt_svc_def gatt_svc_mics[] = { + { + /* Microphone Control Service */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(BT_UUID_MICS_VAL), + .includes = NULL, + .characteristics = (struct ble_gatt_chr_def[]) + { + { + .uuid = BLE_UUID16_DECLARE(BT_UUID_MICS_MUTE_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | \ + BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ_ENC | \ + BLE_GATT_CHR_F_WRITE_ENC, + .min_key_size = 16, + .val_handle = &mics_mute_handle, + }, { + 0, /* No more characteristics in this service. */ + } + } + }, + { + 0, /* No more services. */ + } +}; + +static int inc_aics_svc_check(void) +{ + const struct bt_uuid_16 *uuid; + bool chr_found; + + /* This function is used to make sure the characteristics within + * the service exist in the service defined by Zephyr. + */ + + assert(gatt_svc_inc_aics); + assert(inc_aics_insts); + + LOG_DBG("[N]IncAicsSvcCheck[%u]", inc_aics_svc_count); + + for (size_t i = 0; i < inc_aics_svc_count; i++) { + struct ble_gatt_svc_def *aics = &gatt_svc_inc_aics[i]; + struct bt_gatt_service *svc = inc_aics_insts[i].svc_p; + + assert(svc); + + for (const struct ble_gatt_chr_def *chr = aics->characteristics; + chr && chr->uuid; chr++) { + const ble_uuid16_t *check = (const ble_uuid16_t *)chr->uuid; + + chr_found = false; + + for (size_t j = 0; j < svc->attr_count; j++) { + uuid = (const struct bt_uuid_16 *)(svc->attrs + j)->uuid; + + if (uuid->uuid.type == BT_LE_NIMBLE_GATT_UUID_TO_Z(check->u.type) && + uuid->val == check->value) { + chr_found = true; + break; + } + } + + if (chr_found == false) { + LOG_ERR("[N]IncAicsChrNotFound[%u][%04x]", i, check->value); + return -1; + } + } + } + + return 0; +} + +static int mics_svc_check(void) +{ + struct bt_gatt_service *mics_svc; + const struct bt_uuid_16 *uuid; + bool chr_found; + + mics_svc = lib_mics_svc_get(); + assert(mics_svc); + + LOG_DBG("[N]MicsSvcCheck"); + + for (const struct ble_gatt_chr_def *chr = gatt_svc_mics->characteristics; + chr && chr->uuid; chr++) { + const ble_uuid16_t *check = (const ble_uuid16_t *)chr->uuid; + + chr_found = false; + + for (size_t i = 0; i < mics_svc->attr_count; i++) { + uuid = (const struct bt_uuid_16 *)(mics_svc->attrs + i)->uuid; + + if (uuid->uuid.type == BT_LE_NIMBLE_GATT_UUID_TO_Z(check->u.type) && + uuid->val == check->value) { + chr_found = true; + break; + } + } + + if (chr_found == false) { + LOG_ERR("[N]MicsChrNotFound[%04x]", check->value); + return -1; + } + } + + return 0; +} + +static int inc_aics_attr_handle_set(void) +{ + struct bt_gatt_attr *attr; + uint16_t start_handle; + uint16_t end_handle; + + assert(inc_aics_insts); + + LOG_DBG("[N]IncAicsAttrHdlSet[%u]", inc_aics_svc_count); + + for (size_t i = 0; i < inc_aics_svc_count; i++) { + assert(inc_aics_insts[i].svc_p); + + assert(inc_aics_insts[i].state_handle >= 2); + start_handle = inc_aics_insts[i].state_handle - 2; /* server attr handle & char def handle */ + end_handle = inc_aics_insts[i].description_handle + 1; /* cccd for chr Audio Input Description */ + + LOG_DBG("[N]IncAicsInst[%u][%u][%u][%u]", + i, start_handle, end_handle, inc_aics_insts[i].svc_p->attr_count); + + for (size_t j = 0; j < inc_aics_insts[i].svc_p->attr_count; j++) { + (inc_aics_insts[i].svc_p->attrs + j)->handle = start_handle + j; + } + + /* Last attribute in included AICS */ + attr = inc_aics_insts[i].svc_p->attrs + inc_aics_insts[i].svc_p->attr_count - 1; + + if (attr->handle != end_handle) { + LOG_ERR("[N]IncAicsMismatchAttrHdl[%u][%u][%u][%u]", + start_handle, end_handle, attr->handle, + inc_aics_insts[i].svc_p->attr_count); + return -1; + } + } + + return 0; +} + +int bt_le_nimble_mics_attr_handle_set(void) +{ + struct bt_gatt_service *mics_svc; + struct bt_gatt_attr *attr; + uint16_t start_handle = 0; + uint16_t end_handle = 0; + int rc; + + mics_svc = lib_mics_svc_get(); + assert(mics_svc); + + LOG_DBG("[N]MicsAttrHdlSet[%u]", mics_svc->attr_count); + + rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MICS_VAL), &start_handle); + if (rc) { + LOG_ERR("[N]MicsNotFound[%d]", rc); + return rc; + } + + end_handle = start_handle + mics_svc->attr_count - 1; + + LOG_DBG("[N]Hdl[%u][%u]", start_handle, end_handle); + + for (size_t i = 0; i < mics_svc->attr_count; i++) { + (mics_svc->attrs + i)->handle = start_handle + i; + } + + /* Last attribute in MICS */ + attr = mics_svc->attrs + mics_svc->attr_count - 1; + + if (attr->handle != end_handle) { + LOG_ERR("[N]MicsMismatchAttrHdl[%u][%u][%u][%u]", + start_handle, end_handle, attr->handle, mics_svc->attr_count); + return -1; + } + + if (inc_aics_svc_count) { + rc = inc_aics_attr_handle_set(); + if (rc) { + return rc; + } + } + + return 0; +} + +static inline void inc_aics_chr_init(struct ble_gatt_chr_def *chr, + const ble_uuid16_t *uuid, + uint16_t *val_handle, + ble_gatt_chr_flags flags) +{ + LOG_DBG("[N]IncAicsChrInit[%04x]", uuid->value); + + chr->uuid = &uuid->u; + chr->access_cb = bt_le_nimble_gatts_access_cb_safe; + chr->arg = NULL; + chr->descriptors = NULL; /* NULL if no descriptors. Do not include CCCD */ + chr->flags = flags; + chr->min_key_size = 16; + chr->val_handle = val_handle; +} + +static void inc_aics_svc_init(struct inc_aics_inst *inst, + struct ble_gatt_svc_def *svc) +{ + LOG_DBG("[N]IncAicsSvcInit"); + + svc->type = BLE_GATT_SVC_TYPE_SECONDARY; + svc->uuid = &inc_aics_uuid_svc.u; + svc->includes = NULL; + + svc->characteristics = calloc(INC_AICS_CHR_COUNT, sizeof(struct ble_gatt_chr_def)); + assert(svc->characteristics); + + /* Characteristic - Audio Input State */ + inc_aics_chr_init((void *)&svc->characteristics[0], + &inc_aics_uuid_state, + &inst->state_handle, + INC_AICS_CHR_FLAGS_STATE); + + /* Characteristic - Gain Setting Properties */ + inc_aics_chr_init((void *)&svc->characteristics[1], + &inc_aics_uuid_gain, + &inst->gain_handle, + INC_AICS_CHR_FLAGS_GAIN); + + /* Characteristic - Audio Input Type */ + inc_aics_chr_init((void *)&svc->characteristics[2], + &inc_aics_uuid_type, + &inst->type_handle, + INC_AICS_CHR_FLAGS_TYPE); + + /* Characteristic - Audio Input Status */ + inc_aics_chr_init((void *)&svc->characteristics[3], + &inc_aics_uuid_status, + &inst->status_handle, + INC_AICS_CHR_FLAGS_STATUS); + + /* Characteristic - Audio Input Control Point */ + inc_aics_chr_init((void *)&svc->characteristics[4], + &inc_aics_uuid_control, + &inst->control_handle, + INC_AICS_CHR_FLAGS_CONTROL); + + /* Characteristic - Audio Input Description */ + inc_aics_chr_init((void *)&svc->characteristics[5], + &inc_aics_uuid_description, + &inst->description_handle, + INC_AICS_CHR_FLAGS_DESCRIPTION); +} + +int bt_le_nimble_mics_init(void *micp_inc) +{ + struct bt_micp_included *micp_included; + uint8_t inc_count; + int rc; + + LOG_DBG("[N]MicsInit[%p]", micp_inc); + + micp_included = micp_inc; + + if (micp_included) { + LOG_DBG("[N]MicpIncCount[%u]", micp_included->aics_cnt); + + if (micp_included->aics_cnt > CONFIG_BT_MICP_MIC_DEV_AICS_INSTANCE_COUNT) { + LOG_ERR("[N]InvMicpIncCount[%u][%u]", + micp_included->aics_cnt, CONFIG_BT_MICP_MIC_DEV_AICS_INSTANCE_COUNT); + return -1; + } + + inc_aics_svc_count = micp_included->aics_cnt; + + /* Extra one for terminating the included service array with NULL */ + inc_count = inc_aics_svc_count + 1; + + mics_inc_svcs = calloc(inc_count, sizeof(struct ble_gatt_svc_def *)); + assert(mics_inc_svcs); + + /* MICS may include zero or more instances of AICS */ + if (inc_aics_svc_count) { + inc_aics_insts = calloc(inc_aics_svc_count, sizeof(struct inc_aics_inst)); + assert(inc_aics_insts); + + /* Extra one for terminating the AICS service array */ + gatt_svc_inc_aics = calloc(inc_aics_svc_count + 1, sizeof(struct ble_gatt_svc_def)); + assert(gatt_svc_inc_aics); + + for (size_t i = 0; i < inc_aics_svc_count; i++) { + inc_aics_svc_init(&inc_aics_insts[i], &gatt_svc_inc_aics[i]); + + inc_aics_insts[i].svc_p = lib_aics_svc_get(micp_included->aics[i]); + + mics_inc_svcs[i] = &gatt_svc_inc_aics[i]; + } + + rc = ble_gatts_count_cfg(gatt_svc_inc_aics); + if (rc) { + LOG_ERR("[N]IncAicsCountCfgFail[%d]", rc); + goto free; + } + + rc = ble_gatts_add_svcs(gatt_svc_inc_aics); + if (rc) { + LOG_ERR("[N]IncAicsAddSvcsFail[%d]", rc); + goto free; + } + + rc = inc_aics_svc_check(); + if (rc) { + goto free; + } + } + + /* Terminate the included service array with NULL */ + mics_inc_svcs[inc_count - 1] = NULL; + } + + gatt_svc_mics[0].includes = (const struct ble_gatt_svc_def **)mics_inc_svcs; + + rc = ble_gatts_count_cfg(gatt_svc_mics); + if (rc) { + LOG_ERR("[N]MicsCountCfgFail[%d]", rc); + goto free; + } + + rc = ble_gatts_add_svcs(gatt_svc_mics); + if (rc) { + LOG_ERR("[N]MicsAddSvcsFail[%d]", rc); + goto free; + } + + rc = mics_svc_check(); + if (rc) { + goto free; + } + + return 0; + +free: + if (micp_included) { + free(mics_inc_svcs); + mics_inc_svcs = NULL; + + if (inc_aics_svc_count) { + free(inc_aics_insts); + inc_aics_insts = NULL; + + for (size_t i = 0; i < inc_aics_svc_count; i++) { + free((void *)gatt_svc_inc_aics[i].characteristics); + gatt_svc_inc_aics[i].characteristics = NULL; + } + + free(gatt_svc_inc_aics); + gatt_svc_inc_aics = NULL; + + inc_aics_svc_count = 0; + } + } + gatt_svc_mics[0].includes = NULL; + return rc; +} diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/profiles/mics.h b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/mics.h new file mode 100644 index 0000000000..73177597de --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/mics.h @@ -0,0 +1,28 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef HOST_NIMBLE_PROFILE_MICS_H_ +#define HOST_NIMBLE_PROFILE_MICS_H_ + +#include +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int bt_le_nimble_mics_attr_handle_set(void); + +int bt_le_nimble_mics_init(void *micp_inc); + +#ifdef __cplusplus +} +#endif + +#endif /* HOST_NIMBLE_PROFILE_MICS_H_ */ diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/profiles/pacs.c b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/pacs.c new file mode 100644 index 0000000000..a32ea80c54 --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/pacs.c @@ -0,0 +1,268 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include <../host/conn_internal.h> + +#include "os/os_mbuf.h" +#include "os/os_mempool.h" +#include "host/ble_att.h" +#include "host/ble_gatt.h" +#include "host/ble_hs_mbuf.h" + +#include "nimble/profiles/server.h" + +#include "common/host.h" + +#include "../../../lib/include/audio.h" + +#if CONFIG_BT_PAC_SNK +static uint16_t pacs_snk_handle; +#if CONFIG_BT_PAC_SNK_LOC +static uint16_t pacs_snk_loc_handle; +#endif /* CONFIG_BT_PAC_SNK_LOC */ +#endif /* CONFIG_BT_PAC_SNK */ + +#if CONFIG_BT_PAC_SRC +static uint16_t pacs_src_handle; +#if CONFIG_BT_PAC_SRC_LOC +static uint16_t pacs_src_loc_handle; +#endif /* CONFIG_BT_PAC_SRC_LOC */ +#endif /* CONFIG_BT_PAC_SRC */ + +static uint16_t pacs_ava_ctx_handle; +static uint16_t pacs_sup_ctx_handle; + +static const struct ble_gatt_svc_def gatt_svc_pacs[] = { + { + /* Published Audio Capabilities Service */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(BT_UUID_PACS_VAL), + .includes = NULL, + .characteristics = (struct ble_gatt_chr_def[]) + { +#if CONFIG_BT_PAC_SNK + { + .uuid = BLE_UUID16_DECLARE(BT_UUID_PACS_SNK_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ +#if CONFIG_BT_PAC_SNK_NOTIFIABLE + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC, +#else /* CONFIG_BT_PAC_SNK_NOTIFIABLE */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC, +#endif /* CONFIG_BT_PAC_SNK_NOTIFIABLE */ + .min_key_size = 16, + .val_handle = &pacs_snk_handle, + }, +#if CONFIG_BT_PAC_SNK_LOC + { + .uuid = BLE_UUID16_DECLARE(BT_UUID_PACS_SNK_LOC_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ +#if CONFIG_BT_PAC_SNK_LOC_WRITEABLE && CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | \ + BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC | \ + BLE_GATT_CHR_F_WRITE_ENC, +#elif CONFIG_BT_PAC_SNK_LOC_WRITEABLE && !CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | \ + BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC, +#elif !CONFIG_BT_PAC_SNK_LOC_WRITEABLE && CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC, +#else /* !CONFIG_BT_PAC_SNK_LOC_WRITEABLE && !CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC, +#endif /* CONFIG_BT_PAC_SNK_LOC_WRITEABLE && CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE */ + .min_key_size = 16, + .val_handle = &pacs_snk_loc_handle, + }, +#endif /* CONFIG_BT_PAC_SNK_LOC */ +#endif /* CONFIG_BT_PAC_SNK */ +#if CONFIG_BT_PAC_SRC + { + .uuid = BLE_UUID16_DECLARE(BT_UUID_PACS_SRC_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ +#if CONFIG_BT_PAC_SRC_NOTIFIABLE + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC, +#else /* CONFIG_BT_PAC_SRC_NOTIFIABLE */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC, +#endif /* CONFIG_BT_PAC_SRC_NOTIFIABLE */ + .min_key_size = 16, + .val_handle = &pacs_src_handle, + }, +#if CONFIG_BT_PAC_SRC_LOC + { + .uuid = BLE_UUID16_DECLARE(BT_UUID_PACS_SRC_LOC_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ +#if CONFIG_BT_PAC_SRC_LOC_WRITEABLE && CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | \ + BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC | \ + BLE_GATT_CHR_F_WRITE_ENC, +#elif CONFIG_BT_PAC_SRC_LOC_WRITEABLE && !CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | \ + BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC, +#elif !CONFIG_BT_PAC_SRC_LOC_WRITEABLE && CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC, +#else /* !CONFIG_BT_PAC_SRC_LOC_WRITEABLE && !CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC, +#endif /* CONFIG_BT_PAC_SRC_LOC_WRITEABLE && CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE */ + .min_key_size = 16, + .val_handle = &pacs_src_loc_handle, + }, +#endif /* CONFIG_BT_PAC_SRC_LOC */ +#endif /* CONFIG_BT_PAC_SRC */ + { + .uuid = BLE_UUID16_DECLARE(BT_UUID_PACS_AVAILABLE_CONTEXT_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC, + .min_key_size = 16, + .val_handle = &pacs_ava_ctx_handle, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_PACS_SUPPORTED_CONTEXT_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ +#if CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC, +#else /* CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC, +#endif /* CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE */ + .min_key_size = 16, + .val_handle = &pacs_sup_ctx_handle, + }, { + 0, /* No more characteristics in this service. */ + } + } + }, + { + 0, /* No more services. */ + }, +}; + +int bt_le_nimble_pacs_attr_handle_set(void) +{ + struct bt_gatt_service *pacs_svc; + struct bt_gatt_attr *attr; + uint16_t start_handle; + uint16_t end_handle; + + pacs_svc = lib_pacs_svc_get(); + assert(pacs_svc); + +#if CONFIG_BT_PAC_SNK + assert(pacs_snk_handle >= 2); + start_handle = pacs_snk_handle - 2; /* server attr handle & char def handle */ +#elif CONFIG_BT_PAC_SRC + assert(pacs_src_handle >= 2); + start_handle = pacs_src_handle - 2; /* server attr handle & char def handle */ +#else + assert(pacs_ava_ctx_handle >= 2); + start_handle = pacs_ava_ctx_handle - 2; /* server attr handle & char def handle */ +#endif +#if CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE + end_handle = pacs_sup_ctx_handle + 1; /* cccd attr handle */ +#else /* CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE */ + end_handle = pacs_sup_ctx_handle; /* char value attr handle */ +#endif /* CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE */ + + LOG_DBG("[N]PacsAttrHdlSet[%u][%u][%u][%u]", + start_handle, end_handle, pacs_sup_ctx_handle, pacs_svc->attr_count); + + for (size_t i = 0; i < pacs_svc->attr_count; i++) { + (pacs_svc->attrs + i)->handle = start_handle + i; + } + + /* Last attribute in PACS */ + attr = pacs_svc->attrs + pacs_svc->attr_count - 1; + + if (attr->handle != end_handle) { + LOG_ERR("[N]PacsMismatchAttrHdl[%u][%u][%u][%u]", + start_handle, end_handle, attr->handle, pacs_svc->attr_count); + return -1; + } + + return 0; +} + +static int pacs_svc_check(void) +{ + struct bt_gatt_service *pacs_svc; + const struct bt_uuid_16 *uuid; + bool chr_found; + + /* This function is used to make sure the characteristics within + * the service exist in the service defined by Zephyr. + */ + + pacs_svc = lib_pacs_svc_get(); + assert(pacs_svc); + + LOG_DBG("[N]PacsSvcCheck"); + + for (const struct ble_gatt_chr_def *chr = gatt_svc_pacs[0].characteristics; + chr && chr->uuid; chr++) { + const ble_uuid16_t *check = (const ble_uuid16_t *)chr->uuid; + + chr_found = false; + + for (size_t i = 0; i < pacs_svc->attr_count; i++) { + uuid = (const struct bt_uuid_16 *)(pacs_svc->attrs + i)->uuid; + + if (uuid->uuid.type == BT_LE_NIMBLE_GATT_UUID_TO_Z(check->u.type) && + uuid->val == check->value) { + chr_found = true; + break; + } + } + + if (chr_found == false) { + LOG_ERR("[N]PacsChrNotFound[%04x]", check->value); + return -1; + } + } + + return 0; +} + +int bt_le_nimble_pacs_init(void) +{ + int rc; + + LOG_DBG("[N]PacsInit"); + + rc = ble_gatts_count_cfg(gatt_svc_pacs); + if (rc) { + LOG_ERR("[N]PacsCountCfgFail[%d]", rc); + return rc; + } + + rc = ble_gatts_add_svcs(gatt_svc_pacs); + if (rc) { + LOG_ERR("[N]PacsAddSvcsFail[%d]", rc); + return rc; + } + + rc = pacs_svc_check(); + if (rc) { + return rc; + } + + return 0; +} diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/profiles/pacs.h b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/pacs.h new file mode 100644 index 0000000000..e7d470fcb9 --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/pacs.h @@ -0,0 +1,28 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef HOST_NIMBLE_PROFILE_PACS_H_ +#define HOST_NIMBLE_PROFILE_PACS_H_ + +#include +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int bt_le_nimble_pacs_attr_handle_set(void); + +int bt_le_nimble_pacs_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* HOST_NIMBLE_PROFILE_PACS_H_ */ diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/profiles/server.c b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/server.c new file mode 100644 index 0000000000..6dfe2b090f --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/server.c @@ -0,0 +1,174 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include <../host/conn_internal.h> + +#include "os/os_mbuf.h" +#include "os/os_mempool.h" +#include "host/ble_hs.h" +#include "host/ble_att.h" +#include "host/ble_gatt.h" +#include "host/ble_hs_mbuf.h" + +#include "common/host.h" + +static ssize_t gatts_read_cb(void *arg, uint16_t offset, const void *data, uint16_t len) +{ + struct os_mbuf *om; + int rc; + + ARG_UNUSED(offset); + + om = (struct os_mbuf *)arg; + assert(om); + + LOG_DBG("[N]GattsRdCb[%u][%u]", offset, len); + + if (data == NULL || len == 0) { + rc = 0; + } else { + rc = os_mbuf_append(om, data, len); + if (rc) { + LOG_ERR("[N]MbufAppendFail[%d]", rc); + } + } + + return (rc == 0 ? len : 0); +} + +static int gatts_access_cb(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctx, void *arg) +{ + struct bt_le_nimble_gatt_read_cb cb; + const struct bt_gatt_attr *attr; + struct bt_conn *conn; + uint8_t *data; + ssize_t rc; + + assert(ctx); + + LOG_DBG("[N]GattsAccessCb[%u][%u][%02x]", conn_handle, attr_handle, ctx->op); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL || conn->state != BT_CONN_CONNECTED) { + LOG_ERR("[N]NotConn[%d]", __LINE__); + return -ENOTCONN; + } + + switch (ctx->op) { + case BLE_GATT_ACCESS_OP_READ_CHR: + attr = bt_gatts_find_attr_by_handle(attr_handle); + if (attr == NULL) { + LOG_WRN("[N]RdInvHdl[%u]", attr_handle); + return BT_GATT_ERR(BT_ATT_ERR_INVALID_HANDLE); + } + + if (attr->read == NULL) { + LOG_WRN("[N]RdNotPermit"); + return BT_GATT_ERR(BT_ATT_ERR_READ_NOT_PERMITTED); + } + + cb.read_cb = gatts_read_cb; + cb.read_arg = ctx->om; + + rc = attr->read(conn, attr, (void *)&cb, UINT16_MAX, 0); + if (rc < 0) { + LOG_ERR("[N]RdFail[%u][%d]", attr_handle, rc); + return BT_GATT_ERR(rc); + } + + return 0; + + case BLE_GATT_ACCESS_OP_WRITE_CHR: + attr = bt_gatts_find_attr_by_handle(attr_handle); + if (attr == NULL) { + LOG_WRN("[N]WrInvHdl[%u]", attr_handle); + return BT_GATT_ERR(BT_ATT_ERR_INVALID_HANDLE); + } + + if (attr->write == NULL) { + LOG_WRN("[N]WrNotPermit"); + return BT_GATT_ERR(BT_ATT_ERR_WRITE_NOT_PERMITTED); + } + + if (BT_UUID_16(attr->uuid)->val == BT_UUID_BASS_CONTROL_POINT_VAL) { + /* Receive Write Long Characteristic for assistant adding source. + * TODO: + * Check if the following operation could be directly used? + * "write(conn, attr, ctx->om->om_data, OS_MBUF_PKTLEN(ctx->om), 0, 0)" + */ + uint16_t alloc_len = 16 + CONFIG_BT_BAP_BASS_MAX_SUBGROUPS * + (5 + CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE); + + LOG_DBG("[N]WrBassControlPoint[%u]", alloc_len); + + if (OS_MBUF_PKTLEN(ctx->om) > alloc_len) { + LOG_ERR("[N]WrBassCtrlPtTooLong[%u > %u]", + OS_MBUF_PKTLEN(ctx->om), alloc_len); + return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + } + + data = calloc(1, alloc_len); + assert(data); + + rc = os_mbuf_copydata(ctx->om, 0, OS_MBUF_PKTLEN(ctx->om), data); + assert(rc == 0); + + rc = attr->write(conn, attr, data, OS_MBUF_PKTLEN(ctx->om), 0, 0); + + free(data); + data = NULL; + } else { + LOG_DBG("[N]Wr[%u]", OS_MBUF_PKTLEN(ctx->om)); + + data = calloc(1, OS_MBUF_PKTLEN(ctx->om)); + assert(data); + + rc = os_mbuf_copydata(ctx->om, 0, OS_MBUF_PKTLEN(ctx->om), data); + assert(rc == 0); + + rc = attr->write(conn, attr, data, OS_MBUF_PKTLEN(ctx->om), 0, 0); + + free(data); + data = NULL; + } + if (rc < 0) { + LOG_ERR("[N]WrFail[%u][%d]", attr_handle, rc); + return BT_GATT_ERR(rc); + } + + return 0; + + case BLE_GATT_ACCESS_OP_READ_DSC: + return 0; + + case BLE_GATT_ACCESS_OP_WRITE_DSC: + return 0; + + default: + return BLE_ATT_ERR_UNLIKELY; + } +} + +int bt_le_nimble_gatts_access_cb_safe(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctx, void *arg) +{ + int err; + bt_le_host_lock(); + err = gatts_access_cb(conn_handle, attr_handle, ctx, arg); + bt_le_host_unlock(); + return err; +} diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/profiles/server.h b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/server.h new file mode 100644 index 0000000000..a6e5f3abc4 --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/server.h @@ -0,0 +1,26 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef HOST_NIMBLE_SERVER_H_ +#define HOST_NIMBLE_SERVER_H_ + +#include +#include + +#include "host/ble_gatt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int bt_le_nimble_gatts_access_cb_safe(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctx, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif /* HOST_NIMBLE_SERVER_H_ */ diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/profiles/tbs.c b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/tbs.c new file mode 100644 index 0000000000..ee1391c340 --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/tbs.c @@ -0,0 +1,253 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include <../host/conn_internal.h> + +#include "os/os_mbuf.h" +#include "os/os_mempool.h" +#include "host/ble_att.h" +#include "host/ble_gatt.h" +#include "host/ble_hs_mbuf.h" + +#include "nimble/profiles/server.h" + +#include "common/host.h" + +#include "../../../lib/include/audio.h" + +static const struct ble_gatt_svc_def gatt_svc_gtbs[] = { + { + /* Generic Telephone Bearer Service */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(BT_UUID_GTBS_VAL), + .includes = NULL, + .characteristics = (struct ble_gatt_chr_def[]) + { + { + .uuid = BLE_UUID16_DECLARE(BT_UUID_TBS_PROVIDER_NAME_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC, + .min_key_size = 16, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_TBS_UCI_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC, + .min_key_size = 16, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_TBS_TECHNOLOGY_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC, + .min_key_size = 16, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_TBS_URI_LIST_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC, + .min_key_size = 16, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_TBS_SIGNAL_STRENGTH_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC, + .min_key_size = 16, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_TBS_SIGNAL_INTERVAL_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | \ + BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_READ_ENC | \ + BLE_GATT_CHR_F_WRITE_ENC, + .min_key_size = 16, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_TBS_LIST_CURRENT_CALLS_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC, + .min_key_size = 16, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_CCID_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC, + .min_key_size = 16, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_TBS_STATUS_FLAGS_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC, + .min_key_size = 16, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_TBS_INCOMING_URI_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC, + .min_key_size = 16, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_TBS_CALL_STATE_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC, + .min_key_size = 16, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_TBS_CALL_CONTROL_POINT_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_WRITE | \ + BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_WRITE_ENC, + .min_key_size = 16, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_TBS_OPTIONAL_OPCODES_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC, + .min_key_size = 16, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_TBS_TERMINATE_REASON_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_NOTIFY, + .min_key_size = 16, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_TBS_INCOMING_CALL_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC, + .min_key_size = 16, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_TBS_FRIENDLY_NAME_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC, + .min_key_size = 16, + }, { + 0, /* No more characteristics in this service. */ + } + } + }, + { + 0, /* No more services. */ + }, +}; + +int bt_le_nimble_gtbs_attr_handle_set(void) +{ + struct bt_gatt_service *gtbs_svc; + uint16_t handle; + int rc; + + gtbs_svc = lib_gtbs_svc_get(); + assert(gtbs_svc); + + LOG_DBG("[N]GtbsAttrHdlSet[%u]", gtbs_svc->attr_count); + + rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_GTBS_VAL), &handle); + if (rc) { + LOG_ERR("[N]GtbsNotFound[%d]", rc); + return rc; + } + + LOG_DBG("[N]Hdl[%u]", handle); + + for (size_t i = 0; i < gtbs_svc->attr_count; i++) { + (gtbs_svc->attrs + i)->handle = handle + i; + } + + return 0; +} + +static int gtbs_svc_check(void) +{ + struct bt_gatt_service *gtbs_svc; + const struct bt_uuid_16 *uuid; + bool chr_found; + + /* This function is used to make sure the characteristics within + * the service exist in the service defined by Zephyr. + */ + + gtbs_svc = lib_gtbs_svc_get(); + assert(gtbs_svc); + + LOG_DBG("[N]GtbsSvcCheck"); + + for (const struct ble_gatt_chr_def *chr = gatt_svc_gtbs[0].characteristics; + chr && chr->uuid; chr++) { + const ble_uuid16_t *check = (const ble_uuid16_t *)chr->uuid; + + chr_found = false; + + for (size_t i = 0; i < gtbs_svc->attr_count; i++) { + uuid = (const struct bt_uuid_16 *)(gtbs_svc->attrs + i)->uuid; + + if (uuid->uuid.type == BT_LE_NIMBLE_GATT_UUID_TO_Z(check->u.type) && + uuid->val == check->value) { + chr_found = true; + break; + } + } + + if (chr_found == false) { + LOG_ERR("[N]GtbsChrNotFound[%04x]", check->value); + return -1; + } + } + + return 0; +} + +int bt_le_nimble_gtbs_init(void) +{ + int rc; + + LOG_DBG("[N]GtbsInit"); + + rc = ble_gatts_count_cfg(gatt_svc_gtbs); + if (rc) { + LOG_ERR("[N]GtbsCountCfgFail[%d]", rc); + return rc; + } + + rc = ble_gatts_add_svcs(gatt_svc_gtbs); + if (rc) { + LOG_ERR("[N]GtbsAddSvcsFail[%d]", rc); + return rc; + } + + rc = gtbs_svc_check(); + if (rc) { + return rc; + } + + return 0; +} diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/profiles/tbs.h b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/tbs.h new file mode 100644 index 0000000000..e41154028d --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/tbs.h @@ -0,0 +1,25 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef HOST_NIMBLE_PROFILE_TBS_H_ +#define HOST_NIMBLE_PROFILE_TBS_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int bt_le_nimble_gtbs_attr_handle_set(void); + +int bt_le_nimble_gtbs_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* HOST_NIMBLE_PROFILE_TBS_H_ */ diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/profiles/tmas.c b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/tmas.c new file mode 100644 index 0000000000..1f9a511da1 --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/tmas.c @@ -0,0 +1,146 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include <../host/conn_internal.h> + +#include "os/os_mbuf.h" +#include "os/os_mempool.h" +#include "host/ble_att.h" +#include "host/ble_gatt.h" +#include "host/ble_hs_mbuf.h" + +#include "nimble/profiles/server.h" + +#include "common/host.h" + +#include "../../../lib/include/audio.h" + +static const struct ble_gatt_svc_def gatt_svc_tmas[] = { + { + /* Telephony and Media Audio Service */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(BT_UUID_TMAS_VAL), + .includes = NULL, + .characteristics = (struct ble_gatt_chr_def[]) + { + { + .uuid = BLE_UUID16_DECLARE(BT_UUID_GATT_TMAPR_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ, + .min_key_size = 0, + .val_handle = NULL, + }, { + 0, /* No more characteristics in this service. */ + } + } + }, + { + 0, /* No more services. */ + }, +}; + +int bt_le_nimble_tmas_attr_handle_set(void) +{ + struct bt_gatt_service *tmas_svc; + uint16_t handle; + int rc; + + tmas_svc = lib_tmas_svc_get(); + assert(tmas_svc); + + LOG_DBG("[N]TmasAttrHdlSet[%u]", tmas_svc->attr_count); + + rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_TMAS_VAL), &handle); + if (rc) { + LOG_ERR("[N]TmasNotFound[%d]", rc); + return rc; + } + + LOG_DBG("[N]Hdl[%u]", handle); + + for (size_t i = 0; i < tmas_svc->attr_count; i++) { + (tmas_svc->attrs + i)->handle = handle + i; + } + + return 0; +} + +static int tmas_svc_check(void) +{ + struct bt_gatt_service *tmas_svc; + const struct bt_uuid_16 *uuid; + bool chr_found; + + /* This function is used to make sure the characteristics within + * the service exist in the service defined by Zephyr. + */ + + tmas_svc = lib_tmas_svc_get(); + assert(tmas_svc); + + LOG_DBG("[N]TmasSvcCheck"); + + for (const struct ble_gatt_chr_def *chr = gatt_svc_tmas[0].characteristics; + chr && chr->uuid; chr++) { + const ble_uuid16_t *check = (const ble_uuid16_t *)chr->uuid; + + chr_found = false; + + for (size_t i = 0; i < tmas_svc->attr_count; i++) { + uuid = (const struct bt_uuid_16 *)(tmas_svc->attrs + i)->uuid; + + if (uuid->uuid.type == BT_LE_NIMBLE_GATT_UUID_TO_Z(check->u.type) && + uuid->val == check->value) { + chr_found = true; + break; + } + } + + if (chr_found == false) { + LOG_ERR("[N]TmasChrNotFound[%04x]", check->value); + return -1; + } + } + + return 0; +} + +int bt_le_nimble_tmas_init(void) +{ + int rc; + + LOG_DBG("[N]TmasInit"); + + rc = ble_gatts_count_cfg(gatt_svc_tmas); + if (rc) { + LOG_ERR("[N]TmasCountCfgFail[%d]", rc); + return rc; + } + + rc = ble_gatts_add_svcs(gatt_svc_tmas); + if (rc) { + LOG_ERR("[N]TmasAddSvcsFail[%d]", rc); + return rc; + } + + rc = tmas_svc_check(); + if (rc) { + return rc; + } + + return 0; +} diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/profiles/tmas.h b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/tmas.h new file mode 100644 index 0000000000..58f61cd7e3 --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/tmas.h @@ -0,0 +1,25 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef HOST_NIMBLE_PROFILE_TMAS_H_ +#define HOST_NIMBLE_PROFILE_TMAS_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int bt_le_nimble_tmas_attr_handle_set(void); + +int bt_le_nimble_tmas_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* HOST_NIMBLE_PROFILE_TMAS_H_ */ diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/profiles/vcs.c b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/vcs.c new file mode 100644 index 0000000000..7691e3671d --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/vcs.c @@ -0,0 +1,685 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include <../host/conn_internal.h> + +#include "os/os_mbuf.h" +#include "os/os_mempool.h" +#include "host/ble_att.h" +#include "host/ble_gatt.h" +#include "host/ble_hs_mbuf.h" + +#include "nimble/profiles/server.h" + +#include "common/host.h" + +#include "../../../lib/include/audio.h" + +#define VOCS_INST_COUNT CONFIG_BT_VCP_VOL_REND_VOCS_INSTANCE_COUNT + +#define INC_VOCS_CHR_COUNT (4 + 1) + +#define INC_VOCS_CHR_FLAGS_STATE \ + (BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC) + +#define INC_VOCS_CHR_FLAGS_LOCATION \ + (BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_WRITE_NO_RSP | \ + BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC) + +#define INC_VOCS_CHR_FLAGS_CONTROL \ + (BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_ENC) + +#define INC_VOCS_CHR_FLAGS_DESCRIPTION \ + (BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_WRITE_NO_RSP | \ + BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC) + +static uint8_t inc_vocs_svc_count; + +static struct inc_vocs_inst { + struct bt_gatt_service *svc_p; + uint16_t state_handle; + uint16_t location_handle; + uint16_t control_handle; + uint16_t description_handle; +} inc_vocs_insts[VOCS_INST_COUNT]; + +static struct ble_gatt_svc_def *gatt_svc_inc_vocs; + +static const ble_uuid16_t inc_vocs_uuid_svc = BLE_UUID16_INIT(BT_UUID_VOCS_VAL); +static const ble_uuid16_t inc_vocs_uuid_state = BLE_UUID16_INIT(BT_UUID_VOCS_STATE_VAL); +static const ble_uuid16_t inc_vocs_uuid_location = BLE_UUID16_INIT(BT_UUID_VOCS_LOCATION_VAL); +static const ble_uuid16_t inc_vocs_uuid_control = BLE_UUID16_INIT(BT_UUID_VOCS_CONTROL_VAL); +static const ble_uuid16_t inc_vocs_uuid_description = BLE_UUID16_INIT(BT_UUID_VOCS_DESCRIPTION_VAL); + +#define AICS_INST_COUNT CONFIG_BT_VCP_VOL_REND_AICS_INSTANCE_COUNT + +#define INC_AICS_CHR_COUNT (6 + 1) + +#define INC_AICS_CHR_FLAGS_STATE \ + (BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC) + +#define INC_AICS_CHR_FLAGS_GAIN \ + (BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC) + +#define INC_AICS_CHR_FLAGS_TYPE \ + (BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC) + +#define INC_AICS_CHR_FLAGS_STATUS \ + (BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC) + +#define INC_AICS_CHR_FLAGS_CONTROL \ + (BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_ENC) + +#define INC_AICS_CHR_FLAGS_DESCRIPTION \ + (BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_WRITE_NO_RSP | \ + BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC) + +static uint8_t inc_aics_svc_count; + +static struct inc_aics_inst { + struct bt_gatt_service *svc_p; + uint16_t state_handle; + uint16_t gain_handle; + uint16_t type_handle; + uint16_t status_handle; + uint16_t control_handle; + uint16_t description_handle; +} inc_aics_insts[AICS_INST_COUNT]; + +static struct ble_gatt_svc_def *gatt_svc_inc_aics; + +static const ble_uuid16_t inc_aics_uuid_svc = BLE_UUID16_INIT(BT_UUID_AICS_VAL); +static const ble_uuid16_t inc_aics_uuid_state = BLE_UUID16_INIT(BT_UUID_AICS_STATE_VAL); +static const ble_uuid16_t inc_aics_uuid_gain = BLE_UUID16_INIT(BT_UUID_AICS_GAIN_SETTINGS_VAL); +static const ble_uuid16_t inc_aics_uuid_type = BLE_UUID16_INIT(BT_UUID_AICS_INPUT_TYPE_VAL); +static const ble_uuid16_t inc_aics_uuid_status = BLE_UUID16_INIT(BT_UUID_AICS_INPUT_STATUS_VAL); +static const ble_uuid16_t inc_aics_uuid_control = BLE_UUID16_INIT(BT_UUID_AICS_CONTROL_VAL); +static const ble_uuid16_t inc_aics_uuid_description = BLE_UUID16_INIT(BT_UUID_AICS_DESCRIPTION_VAL); + +static struct ble_gatt_svc_def **vcs_inc_svcs; + +static struct ble_gatt_svc_def gatt_svc_vcs[] = { + { + /* Volume Control Service */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(BT_UUID_VCS_VAL), + .includes = NULL, + .characteristics = (struct ble_gatt_chr_def[]) + { + { + /* Volume Control Service -- Volume state characteristic */ + .uuid = BLE_UUID16_DECLARE(BT_UUID_VCS_STATE_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC, + .min_key_size = 16, + }, { + /* Volume Control Service -- Volume COntrol Point characteristic */ + .uuid = BLE_UUID16_DECLARE(BT_UUID_VCS_CONTROL_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ + .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_ENC, + .min_key_size = 16, + }, { + /* Volume Control Service -- Volume Flags characteristic */ + .uuid = BLE_UUID16_DECLARE(BT_UUID_VCS_FLAGS_VAL), + .access_cb = bt_le_nimble_gatts_access_cb_safe, + .arg = NULL, + .descriptors = NULL, /* NULL if no descriptors. Do not include CCCD */ +#if CONFIG_BT_VCP_VOL_REND_VOL_FLAGS_NOTIFIABLE + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_READ_ENC, +#else /* CONFIG_BT_VCP_VOL_REND_VOL_FLAGS_NOTIFIABLE */ + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC, +#endif /* CONFIG_BT_VCP_VOL_REND_VOL_FLAGS_NOTIFIABLE */ + .min_key_size = 16, + }, { + 0, /* No more characteristics in this service. */ + } + } + }, + { + 0, /* No more services. */ + }, +}; + +static int inc_vocs_svc_check(void) +{ + const struct bt_uuid_16 *uuid; + bool chr_found; + + /* This function is used to make sure the characteristics within + * the service exist in the service defined by Zephyr. + */ + + assert(gatt_svc_inc_vocs); + + LOG_DBG("[N]IncVocsSvcCheck[%u]", inc_vocs_svc_count); + + for (size_t i = 0; i < inc_vocs_svc_count; i++) { + struct ble_gatt_svc_def *vocs = &gatt_svc_inc_vocs[i]; + struct bt_gatt_service *svc = inc_vocs_insts[i].svc_p; + + assert(svc); + + for (const struct ble_gatt_chr_def *chr = vocs->characteristics; + chr && chr->uuid; chr++) { + const ble_uuid16_t *check = (const ble_uuid16_t *)chr->uuid; + + chr_found = false; + + for (size_t j = 0; j < svc->attr_count; j++) { + uuid = (const struct bt_uuid_16 *)(svc->attrs + j)->uuid; + + if (uuid->uuid.type == BT_LE_NIMBLE_GATT_UUID_TO_Z(check->u.type) && + uuid->val == check->value) { + chr_found = true; + break; + } + } + + if (chr_found == false) { + LOG_ERR("[N]IncVocsChrNotFound[%u][%04x]", i, check->value); + return -1; + } + } + } + + return 0; +} + +static int inc_aics_svc_check(void) +{ + const struct bt_uuid_16 *uuid; + bool chr_found; + + /* This function is used to make sure the characteristics within + * the service exist in the service defined by Zephyr. + */ + + assert(gatt_svc_inc_aics); + + LOG_DBG("[N]IncAicsSvcCheck[%u]", inc_aics_svc_count); + + for (size_t i = 0; i < inc_aics_svc_count; i++) { + struct ble_gatt_svc_def *aics = &gatt_svc_inc_aics[i]; + struct bt_gatt_service *svc = inc_aics_insts[i].svc_p; + + assert(svc); + + for (const struct ble_gatt_chr_def *chr = aics->characteristics; + chr && chr->uuid; chr++) { + const ble_uuid16_t *check = (const ble_uuid16_t *)chr->uuid; + + chr_found = false; + + for (size_t j = 0; j < svc->attr_count; j++) { + uuid = (const struct bt_uuid_16 *)(svc->attrs + j)->uuid; + + if (uuid->uuid.type == BT_LE_NIMBLE_GATT_UUID_TO_Z(check->u.type) && + uuid->val == check->value) { + chr_found = true; + break; + } + } + + if (chr_found == false) { + LOG_ERR("[N]IncAicsChrNotFound[%u][%04x]", i, check->value); + return -1; + } + } + } + + return 0; +} + +static int vcs_svc_check(void) +{ + struct bt_gatt_service *vcs_svc; + const struct bt_uuid_16 *uuid; + bool chr_found; + + /* This function is used to make sure the characteristics within + * the service exist in the service defined by Zephyr. + */ + + vcs_svc = lib_vcs_svc_get(); + assert(vcs_svc); + + LOG_DBG("[N]VCSSvcCheck"); + + for (const struct ble_gatt_chr_def *chr = gatt_svc_vcs[0].characteristics; + chr && chr->uuid; chr++) { + const ble_uuid16_t *check = (const ble_uuid16_t *)chr->uuid; + + chr_found = false; + + for (size_t i = 0; i < vcs_svc->attr_count; i++) { + uuid = (const struct bt_uuid_16 *)(vcs_svc->attrs + i)->uuid; + + if (uuid->uuid.type == BT_LE_NIMBLE_GATT_UUID_TO_Z(check->u.type) && + uuid->val == check->value) { + chr_found = true; + break; + } + } + + if (chr_found == false) { + LOG_ERR("[N]VcsChrNotFound[%04x]", check->value); + return -1; + } + } + + return 0; +} + +static int inc_vocs_attr_handle_set(void) +{ + struct bt_gatt_attr *attr; + uint16_t start_handle; + uint16_t end_handle; + + LOG_DBG("[N]IncVocsAttrHdlSet[%u]", inc_vocs_svc_count); + + for (size_t i = 0; i < inc_vocs_svc_count; i++) { + assert(inc_vocs_insts[i].svc_p); + + assert(inc_vocs_insts[i].state_handle >= 2); + start_handle = inc_vocs_insts[i].state_handle - 2; /* server attr handle & char def handle */ + end_handle = inc_vocs_insts[i].description_handle + 1; /* cccd for chr Audio Output Description */ + + LOG_DBG("[N]IncVocsInst[%u][%u][%u][%u]", + i, start_handle, end_handle, inc_vocs_insts[i].svc_p->attr_count); + + for (size_t j = 0; j < inc_vocs_insts[i].svc_p->attr_count; j++) { + (inc_vocs_insts[i].svc_p->attrs + j)->handle = start_handle + j; + } + + /* Last attribute in included VOCS */ + attr = inc_vocs_insts[i].svc_p->attrs + inc_vocs_insts[i].svc_p->attr_count - 1; + + if (attr->handle != end_handle) { + LOG_ERR("[N]IncVocsMismatchAttrHdl[%u][%u][%u][%u]", + start_handle, end_handle, attr->handle, + inc_vocs_insts[i].svc_p->attr_count); + return -1; + } + } + + return 0; +} + +static int inc_aics_attr_handle_set(void) +{ + struct bt_gatt_attr *attr; + uint16_t start_handle; + uint16_t end_handle; + + LOG_DBG("[N]IncAicsAttrHdlSet[%u]", inc_aics_svc_count); + + for (size_t i = 0; i < inc_aics_svc_count; i++) { + assert(inc_aics_insts[i].svc_p); + + assert(inc_aics_insts[i].state_handle >= 2); + start_handle = inc_aics_insts[i].state_handle - 2; /* server attr handle & char def handle */ + end_handle = inc_aics_insts[i].description_handle + 1; /* cccd for chr Audio Input Description */ + + LOG_DBG("[N]IncAicsInst[%u][%u][%u][%u]", + i, start_handle, end_handle, inc_aics_insts[i].svc_p->attr_count); + + for (size_t j = 0; j < inc_aics_insts[i].svc_p->attr_count; j++) { + (inc_aics_insts[i].svc_p->attrs + j)->handle = start_handle + j; + } + + /* Last attribute in included AICS */ + attr = inc_aics_insts[i].svc_p->attrs + inc_aics_insts[i].svc_p->attr_count - 1; + + if (attr->handle != end_handle) { + LOG_ERR("[N]IncAicsMismatchAttrHdl[%u][%u][%u][%u]", + start_handle, end_handle, attr->handle, + inc_aics_insts[i].svc_p->attr_count); + return -1; + } + } + + return 0; +} + +int bt_le_nimble_vcs_attr_handle_set(void) +{ + struct bt_gatt_service *vcs_svc; + struct bt_gatt_attr *attr; + uint16_t start_handle = 0; + uint16_t end_handle = 0; + int rc; + + vcs_svc = lib_vcs_svc_get(); + assert(vcs_svc); + + LOG_DBG("[N]VcsAttrHdlSet[%u]", vcs_svc->attr_count); + + rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_VCS_VAL), &start_handle); + if (rc) { + LOG_ERR("[N]VcsNotFound[%d]", rc); + return rc; + } + + end_handle = start_handle + vcs_svc->attr_count - 1; + + LOG_DBG("[N]Hdl[%u][%u]", start_handle, end_handle); + + for (size_t i = 0; i < vcs_svc->attr_count; i++) { + (vcs_svc->attrs + i)->handle = start_handle + i; + } + + /* Last attribute in VCS */ + attr = vcs_svc->attrs + vcs_svc->attr_count - 1; + + if (attr->handle != end_handle) { + LOG_ERR("[N]VcsMismatchAttrHdl[%u][%u][%u][%u]", + start_handle, end_handle, attr->handle, vcs_svc->attr_count); + return -1; + } + + if (inc_vocs_svc_count) { + rc = inc_vocs_attr_handle_set(); + if (rc) { + return rc; + } + } + + if (inc_aics_svc_count) { + rc = inc_aics_attr_handle_set(); + if (rc) { + return rc; + } + } + + return 0; +} + +static inline void inc_vocs_chr_init(struct ble_gatt_chr_def *chr, + const ble_uuid16_t *uuid, + uint16_t *val_handle, + ble_gatt_chr_flags flags) +{ + LOG_DBG("[N]IncVocsChrInit[%04x]", uuid->value); + + chr->uuid = &uuid->u; + chr->access_cb = bt_le_nimble_gatts_access_cb_safe; + chr->arg = NULL; + chr->descriptors = NULL; /* NULL if no descriptors. Do not include CCCD */ + chr->flags = flags; + chr->min_key_size = 16; + chr->val_handle = val_handle; +} + +static void inc_vocs_svc_init(struct inc_vocs_inst *inst, + struct ble_gatt_svc_def *svc) +{ + LOG_DBG("[N]IncVocsSvcInit"); + + svc->type = BLE_GATT_SVC_TYPE_SECONDARY; + svc->uuid = &inc_vocs_uuid_svc.u; + svc->includes = NULL; + + svc->characteristics = calloc(INC_VOCS_CHR_COUNT, sizeof(struct ble_gatt_chr_def)); + assert(svc->characteristics); + + /* Characteristic - Volume Offset State */ + inc_vocs_chr_init((void *)&svc->characteristics[0], + &inc_vocs_uuid_state, + &inst->state_handle, + INC_VOCS_CHR_FLAGS_STATE); + + /* Characteristic - Audio Location */ + inc_vocs_chr_init((void *)&svc->characteristics[1], + &inc_vocs_uuid_location, + &inst->location_handle, + INC_VOCS_CHR_FLAGS_LOCATION); + + /* Characteristic - Volume Offset Control Point */ + inc_vocs_chr_init((void *)&svc->characteristics[2], + &inc_vocs_uuid_control, + &inst->control_handle, + INC_VOCS_CHR_FLAGS_CONTROL); + + /* Characteristic - Audio Output Description */ + inc_vocs_chr_init((void *)&svc->characteristics[3], + &inc_vocs_uuid_description, + &inst->description_handle, + INC_VOCS_CHR_FLAGS_DESCRIPTION); +} + +static inline void inc_aics_chr_init(struct ble_gatt_chr_def *chr, + const ble_uuid16_t *uuid, + uint16_t *val_handle, + ble_gatt_chr_flags flags) +{ + LOG_DBG("[N]IncAicsChrInit[%04x]", uuid->value); + + chr->uuid = &uuid->u; + chr->access_cb = bt_le_nimble_gatts_access_cb_safe; + chr->arg = NULL; + chr->descriptors = NULL; /* NULL if no descriptors. Do not include CCCD */ + chr->flags = flags; + chr->min_key_size = 16; + chr->val_handle = val_handle; +} + +static void inc_aics_svc_init(struct inc_aics_inst *inst, + struct ble_gatt_svc_def *svc) +{ + LOG_DBG("[N]IncAicsSvcInit"); + + svc->type = BLE_GATT_SVC_TYPE_SECONDARY; + svc->uuid = &inc_aics_uuid_svc.u; + svc->includes = NULL; + + svc->characteristics = calloc(INC_AICS_CHR_COUNT, sizeof(struct ble_gatt_chr_def)); + assert(svc->characteristics); + + /* Characteristic - Audio Input State */ + inc_aics_chr_init((void *)&svc->characteristics[0], + &inc_aics_uuid_state, + &inst->state_handle, + INC_AICS_CHR_FLAGS_STATE); + + /* Characteristic - Gain Setting Properties */ + inc_aics_chr_init((void *)&svc->characteristics[1], + &inc_aics_uuid_gain, + &inst->gain_handle, + INC_AICS_CHR_FLAGS_GAIN); + + /* Characteristic - Audio Input Type */ + inc_aics_chr_init((void *)&svc->characteristics[2], + &inc_aics_uuid_type, + &inst->type_handle, + INC_AICS_CHR_FLAGS_TYPE); + + /* Characteristic - Audio Input Status */ + inc_aics_chr_init((void *)&svc->characteristics[3], + &inc_aics_uuid_status, + &inst->status_handle, + INC_AICS_CHR_FLAGS_STATUS); + + /* Characteristic - Audio Input Control Point */ + inc_aics_chr_init((void *)&svc->characteristics[4], + &inc_aics_uuid_control, + &inst->control_handle, + INC_AICS_CHR_FLAGS_CONTROL); + + /* Characteristic - Audio Input Description */ + inc_aics_chr_init((void *)&svc->characteristics[5], + &inc_aics_uuid_description, + &inst->description_handle, + INC_AICS_CHR_FLAGS_DESCRIPTION); +} + +int bt_le_nimble_vcs_init(void *vcp_inc) +{ + struct bt_vcp_included *vcp_included; + uint8_t inc_count; + int rc; + + LOG_DBG("[N]VcsInit[%p]", vcp_inc); + + vcp_included = vcp_inc; + + if (vcp_included) { + LOG_DBG("[N]VcpIncCount[%u][%u]", + vcp_included->vocs_cnt, vcp_included->aics_cnt); + + if (vcp_included->vocs_cnt > VOCS_INST_COUNT || + vcp_included->aics_cnt > AICS_INST_COUNT) { + LOG_ERR("[N]InvVcpIncCount[%u][%u][%u][%u]", + vcp_included->vocs_cnt, VOCS_INST_COUNT, + vcp_included->aics_cnt, AICS_INST_COUNT); + return -1; + } + + inc_vocs_svc_count = vcp_included->vocs_cnt; + inc_aics_svc_count = vcp_included->aics_cnt; + + /* Extra one for terminating the included service array with NULL */ + inc_count = inc_vocs_svc_count + inc_aics_svc_count + 1; + + vcs_inc_svcs = calloc(inc_count, sizeof(struct ble_gatt_svc_def *)); + assert(vcs_inc_svcs); + + /* VCS may include zero or more instances of VOCS */ + if (inc_vocs_svc_count) { + /* Extra one for terminating the VOCS service array */ + gatt_svc_inc_vocs = calloc(inc_vocs_svc_count + 1, sizeof(struct ble_gatt_svc_def)); + assert(gatt_svc_inc_vocs); + + for (size_t i = 0; i < inc_vocs_svc_count; i++) { + inc_vocs_svc_init(&inc_vocs_insts[i], &gatt_svc_inc_vocs[i]); + + inc_vocs_insts[i].svc_p = lib_vocs_svc_get(vcp_included->vocs[i]); + + vcs_inc_svcs[i] = &gatt_svc_inc_vocs[i]; + } + + rc = ble_gatts_count_cfg(gatt_svc_inc_vocs); + if (rc) { + LOG_ERR("[N]IncVocsCountCfgFail[%d]", rc); + goto free; + } + + rc = ble_gatts_add_svcs(gatt_svc_inc_vocs); + if (rc) { + LOG_ERR("[N]IncVocsAddSvcsFail[%d]", rc); + goto free; + } + + rc = inc_vocs_svc_check(); + if (rc) { + goto free; + } + } + + /* VCS may include zero or more instances of AICS */ + if (inc_aics_svc_count) { + /* Extra one for terminating the AICS service array */ + gatt_svc_inc_aics = calloc(inc_aics_svc_count + 1, sizeof(struct ble_gatt_svc_def)); + assert(gatt_svc_inc_aics); + + for (size_t i = 0; i < inc_aics_svc_count; i++) { + inc_aics_svc_init(&inc_aics_insts[i], &gatt_svc_inc_aics[i]); + + inc_aics_insts[i].svc_p = lib_aics_svc_get(vcp_included->aics[i]); + + vcs_inc_svcs[inc_vocs_svc_count + i] = &gatt_svc_inc_aics[i]; + } + + rc = ble_gatts_count_cfg(gatt_svc_inc_aics); + if (rc) { + LOG_ERR("[N]IncAicsCountCfgFail[%d]", rc); + goto free; + } + + rc = ble_gatts_add_svcs(gatt_svc_inc_aics); + if (rc) { + LOG_ERR("[N]IncAicsAddSvcsFail[%d]", rc); + goto free; + } + + rc = inc_aics_svc_check(); + if (rc) { + goto free; + } + } + + /* Terminate the included service array with NULL */ + vcs_inc_svcs[inc_count - 1] = NULL; + } + + gatt_svc_vcs[0].includes = (const struct ble_gatt_svc_def **)vcs_inc_svcs; + + rc = ble_gatts_count_cfg(gatt_svc_vcs); + if (rc) { + LOG_ERR("[N]VcsCountCfgFail[%d]", rc); + goto free; + } + + rc = ble_gatts_add_svcs(gatt_svc_vcs); + if (rc) { + LOG_ERR("[N]VcsAddSvcsFail[%d]", rc); + goto free; + } + + rc = vcs_svc_check(); + if (rc) { + goto free; + } + + return 0; + +free: + if (vcp_included) { + if (inc_vocs_svc_count) { + for (size_t i = 0; i < inc_vocs_svc_count; i++) { + free((void *)gatt_svc_inc_vocs[i].characteristics); + gatt_svc_inc_vocs[i].characteristics = NULL; + } + + free(gatt_svc_inc_vocs); + gatt_svc_inc_vocs = NULL; + + inc_vocs_svc_count = 0; + } + + if (inc_aics_svc_count) { + for (size_t i = 0; i < inc_aics_svc_count; i++) { + free((void *)gatt_svc_inc_aics[i].characteristics); + gatt_svc_inc_aics[i].characteristics = NULL; + } + + free(gatt_svc_inc_aics); + gatt_svc_inc_aics = NULL; + + inc_aics_svc_count = 0; + } + + free(vcs_inc_svcs); + vcs_inc_svcs = NULL; + } + gatt_svc_vcs[0].includes = NULL; + return rc; +} diff --git a/components/bt/esp_ble_audio/host/adapter/nimble/profiles/vcs.h b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/vcs.h new file mode 100644 index 0000000000..db72dc6221 --- /dev/null +++ b/components/bt/esp_ble_audio/host/adapter/nimble/profiles/vcs.h @@ -0,0 +1,25 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef HOST_NIMBLE_PROFILE_VCS_H_ +#define HOST_NIMBLE_PROFILE_VCS_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int bt_le_nimble_vcs_attr_handle_set(void); + +int bt_le_nimble_vcs_init(void *vcp_inc); + +#ifdef __cplusplus +} +#endif + +#endif /* HOST_NIMBLE_PROFILE_VCS_H_ */ diff --git a/components/bt/esp_ble_audio/host/common/adv.c b/components/bt/esp_ble_audio/host/common/adv.c new file mode 100644 index 0000000000..8962c84700 --- /dev/null +++ b/components/bt/esp_ble_audio/host/common/adv.c @@ -0,0 +1,142 @@ +/* + * SPDX-FileCopyrightText: 2017-2021 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2015-2016 Intel Corporation + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include +#include + +#include <../host/hci_core.h> + +#include "common/host.h" + +static struct bt_le_ext_adv ext_adv_pool[CONFIG_BT_EXT_ADV_MAX_ADV_SET]; + +static struct bt_le_ext_adv *ext_adv_find(uint8_t adv_handle) +{ + struct bt_le_ext_adv *adv = NULL; + + for (size_t i = 0; i < ARRAY_SIZE(ext_adv_pool); i++) { + if (atomic_test_bit(ext_adv_pool[i].flags, + BT_PER_ADV_PARAMS_SET) && + ext_adv_pool[i].handle == adv_handle) { + LOG_DBG("ExtAdvFound[%u][%u]", i, adv_handle); + adv = &ext_adv_pool[i]; + break; + } + } + + return adv; +} + +static struct bt_le_ext_adv *ext_adv_new(void) +{ + struct bt_le_ext_adv *adv = NULL; + + for (size_t i = 0; i < ARRAY_SIZE(ext_adv_pool); i++) { + if (atomic_test_bit(ext_adv_pool[i].flags, + BT_PER_ADV_PARAMS_SET) == false) { + adv = &ext_adv_pool[i]; + + memset(adv, 0, sizeof(*adv)); + atomic_set_bit(adv->flags, BT_PER_ADV_PARAMS_SET); + break; + } + } + + return adv; +} + +static void ext_adv_delete(struct bt_le_ext_adv *adv) +{ + atomic_clear_bit(adv->flags, BT_PER_ADV_PARAMS_SET); +} + +_IDF_ONLY +struct bt_le_ext_adv *bt_le_ext_adv_find(uint8_t adv_handle) +{ + LOG_DBG("ExtAdvFind[%u]", adv_handle); + return ext_adv_find(adv_handle); +} + +_IDF_ONLY +int bt_le_ext_adv_new_safe(uint8_t adv_handle) +{ + struct bt_le_ext_adv *adv = NULL; + int err = 0; + + bt_le_host_lock(); + + adv = ext_adv_find(adv_handle); + if (adv) { + LOG_WRN("ExtAdvExist[%u]", adv_handle); + err = -EEXIST; + goto end; + } + + adv = ext_adv_new(); + if (adv == NULL) { + LOG_ERR("NoFreeExtAdv[%u]", adv_handle); + err = -ENOMEM; + goto end; + } + + adv->handle = adv_handle; + +end: + bt_le_host_unlock(); + + return err; +} + +_IDF_ONLY +int bt_le_ext_adv_delete_safe(uint8_t adv_handle) +{ + struct bt_le_ext_adv *adv = NULL; + int err = 0; + + bt_le_host_lock(); + + adv = ext_adv_find(adv_handle); + if (adv == NULL) { + LOG_ERR("ExtAdvNotFound[%u]", adv_handle); + err = -ENODEV; + goto end; + } + + ext_adv_delete(adv); + +end: + bt_le_host_unlock(); + + return err; +} + +_LIB_ONLY +int bt_le_ext_adv_get_info(const struct bt_le_ext_adv *adv, + struct bt_le_ext_adv_info *info) +{ + if (adv == NULL || info == NULL) { + LOG_ERR("ParamNull[%p][%p]", adv, info); + return -EINVAL; + } + + if (!IS_ARRAY_ELEMENT(ext_adv_pool, adv)) { + LOG_ERR("ExtAdvNotInPool[%p]", adv); + return -EINVAL; + } + + /* Force to use ENABLED state for LIB usage */ + info->ext_adv_state = BT_LE_EXT_ADV_STATE_ENABLED; + info->per_adv_state = BT_LE_PER_ADV_STATE_ENABLED; + + return 0; +} diff --git a/components/bt/esp_ble_audio/host/common/adv.h b/components/bt/esp_ble_audio/host/common/adv.h new file mode 100644 index 0000000000..229942139a --- /dev/null +++ b/components/bt/esp_ble_audio/host/common/adv.h @@ -0,0 +1,28 @@ +/* + * SPDX-FileCopyrightText: 2017-2021 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2015-2016 Intel Corporation + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef HOST_COMMON_ADV_H_ +#define HOST_COMMON_ADV_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_le_ext_adv *bt_le_ext_adv_find(uint8_t adv_handle); + +int bt_le_ext_adv_new_safe(uint8_t adv_handle); + +int bt_le_ext_adv_delete_safe(uint8_t adv_handle); + +#ifdef __cplusplus +} +#endif + +#endif /* HOST_COMMON_ADV_H_ */ diff --git a/components/bt/esp_ble_audio/host/common/app/gap.c b/components/bt/esp_ble_audio/host/common/app/gap.c new file mode 100644 index 0000000000..24a312910b --- /dev/null +++ b/components/bt/esp_ble_audio/host/common/app/gap.c @@ -0,0 +1,473 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include +#include + +#include <../host/hci_core.h> +#include <../host/iso_internal.h> + +#include "common/host.h" +#include "common/app/gap.h" + +static bt_le_gap_app_cb gap_app_cb; + +int bt_le_gap_app_cb_register(bt_le_gap_app_cb cb) +{ + LOG_DBG("GapAppCbReg"); + + if (cb == NULL) { + LOG_ERR("GapAppCbNull"); + return -EINVAL; + } + + if (gap_app_cb) { + LOG_WRN("GapAppCbExist"); + return -EALREADY; + } + + gap_app_cb = cb; + + return 0; +} + +void bt_le_gap_app_cb_unregister(void) +{ + if (gap_app_cb) { + LOG_DBG("GapAppCbUnreg"); + gap_app_cb = NULL; + } +} + +static inline void bt_le_gap_app_cb_evt(struct bt_le_gap_app_event *event) +{ + if (gap_app_cb) { + gap_app_cb(event); + } +} + +struct biginfo { + uint16_t sync_handle; + uint8_t num_bis; + uint8_t nse; + uint16_t iso_interval; + uint8_t bn; + uint8_t pto; + uint8_t irc; + uint16_t max_pdu; + uint8_t sdu_interval[3]; + uint16_t max_sdu; + uint8_t phy; + uint8_t framing; + uint8_t encryption; +} __packed; + +void bt_le_gap_app_biginfo_event(uint8_t *param) +{ + struct bt_le_gap_app_event event = { + .type = BT_LE_GAP_APP_EVENT_BIGINFO_RECV, + }; + struct biginfo *biginfo; + + biginfo = (void *)param; + + event.biginfo_recv.sync_handle = biginfo->sync_handle; + event.biginfo_recv.num_bis = biginfo->num_bis; + event.biginfo_recv.nse = biginfo->nse; + event.biginfo_recv.iso_interval = biginfo->iso_interval; + event.biginfo_recv.bn = biginfo->bn; + event.biginfo_recv.pto = biginfo->pto; + event.biginfo_recv.irc = biginfo->irc; + event.biginfo_recv.max_pdu = biginfo->max_pdu; + event.biginfo_recv.sdu_interval = sys_get_le24(biginfo->sdu_interval); + event.biginfo_recv.max_sdu = biginfo->max_sdu; + event.biginfo_recv.phy = biginfo->phy; + event.biginfo_recv.framing = biginfo->framing; + event.biginfo_recv.encryption = biginfo->encryption; + + bt_le_gap_app_cb_evt(&event); +} + +static void handle_ext_scan_recv_event_safe(struct bt_le_gap_app_param *param) +{ + struct bt_le_gap_app_event event = { + .type = BT_LE_GAP_APP_EVENT_EXT_SCAN_RECV, + }; + + event.ext_scan_recv.event_type = param->ext_scan_recv.event_type; + event.ext_scan_recv.addr.type = param->ext_scan_recv.addr.type; + memcpy(event.ext_scan_recv.addr.val, param->ext_scan_recv.addr.val, BT_ADDR_SIZE); + event.ext_scan_recv.rssi = param->ext_scan_recv.rssi; + event.ext_scan_recv.tx_power = param->ext_scan_recv.tx_power; + event.ext_scan_recv.sid = param->ext_scan_recv.sid; + event.ext_scan_recv.pri_phy = param->ext_scan_recv.pri_phy; + event.ext_scan_recv.sec_phy = param->ext_scan_recv.sec_phy; + event.ext_scan_recv.per_adv_itvl = param->ext_scan_recv.per_adv_itvl; + event.ext_scan_recv.data_len = param->ext_scan_recv.data_len; + event.ext_scan_recv.data = param->ext_scan_recv.data; + + bt_le_host_lock(); + + bt_le_scan_recv_listener(event.ext_scan_recv.event_type, + event.ext_scan_recv.addr.type, + event.ext_scan_recv.addr.val, + event.ext_scan_recv.rssi, + event.ext_scan_recv.tx_power, + event.ext_scan_recv.sid, + event.ext_scan_recv.pri_phy, + event.ext_scan_recv.sec_phy, + event.ext_scan_recv.per_adv_itvl, + event.ext_scan_recv.data_len, + event.ext_scan_recv.data); + + bt_le_host_unlock(); + + bt_le_gap_app_cb_evt(&event); + + if (param->ext_scan_recv.data) { + free(param->ext_scan_recv.data); + } +} + +static void handle_pa_sync_event_safe(struct bt_le_gap_app_param *param) +{ + struct bt_le_gap_app_event event = { + .type = BT_LE_GAP_APP_EVENT_PA_SYNC, + }; + struct bt_le_per_adv_sync *per_adv_sync; + int err; + + event.pa_sync.status = param->pa_sync.status; + event.pa_sync.sync_handle = param->pa_sync.sync_handle; + event.pa_sync.addr.type = param->pa_sync.addr.type; + memcpy(event.pa_sync.addr.val, param->pa_sync.addr.val, BT_ADDR_SIZE); + event.pa_sync.sid = param->pa_sync.sid; + event.pa_sync.adv_phy = param->pa_sync.adv_phy; + event.pa_sync.per_adv_itvl = param->pa_sync.per_adv_itvl; + event.pa_sync.adv_ca = param->pa_sync.adv_ca; + + bt_le_host_lock(); + + if (event.pa_sync.status) { + goto end; + } + + err = bt_le_per_adv_sync_new(event.pa_sync.sync_handle, + event.pa_sync.sid, + event.pa_sync.adv_phy, + event.pa_sync.per_adv_itvl, + event.pa_sync.addr.type, + event.pa_sync.addr.val, + &per_adv_sync); + if (err) { + goto end; + } + + err = bt_le_per_adv_sync_establish_listener(event.pa_sync.sync_handle); + assert(err == 0); + +end: + bt_le_host_unlock(); + + bt_le_gap_app_cb_evt(&event); +} + +static void handle_pa_sync_lost_event_safe(struct bt_le_gap_app_param *param) +{ + struct bt_le_gap_app_event event = { + .type = BT_LE_GAP_APP_EVENT_PA_SYNC_LOST, + }; + int err; + + event.pa_sync_lost.sync_handle = param->pa_sync_lost.sync_handle; + event.pa_sync_lost.reason = param->pa_sync_lost.reason; + + bt_le_host_lock(); + + err = bt_le_per_adv_sync_lost_listener(event.pa_sync_lost.sync_handle); + if (err) { + goto end; + } + + err = bt_le_per_adv_sync_delete(event.pa_sync_lost.sync_handle); + assert(err == 0); + +end: + bt_le_host_unlock(); + + bt_le_gap_app_cb_evt(&event); +} + +static void handle_pa_sync_recv_event_safe(struct bt_le_gap_app_param *param) +{ + struct bt_le_gap_app_event event = { + .type = BT_LE_GAP_APP_EVENT_PA_SYNC_RECV, + }; + + event.pa_sync_recv.sync_handle = param->pa_sync_recv.sync_handle; + event.pa_sync_recv.tx_power = param->pa_sync_recv.tx_power; + event.pa_sync_recv.rssi = param->pa_sync_recv.rssi; + event.pa_sync_recv.data_status = param->pa_sync_recv.data_status; + event.pa_sync_recv.data_len = param->pa_sync_recv.data_len; + event.pa_sync_recv.data = param->pa_sync_recv.data; + + bt_le_host_lock(); + + bt_le_per_adv_sync_report_recv_listener(event.pa_sync_recv.sync_handle, + event.pa_sync_recv.data, + event.pa_sync_recv.data_len); + + bt_le_host_unlock(); + + bt_le_gap_app_cb_evt(&event); + + if (param->pa_sync_recv.data) { + free(param->pa_sync_recv.data); + } +} + +static void handle_acl_connect_event_safe(struct bt_le_gap_app_param *param) +{ + struct bt_le_gap_app_event event = { + .type = BT_LE_GAP_APP_EVENT_ACL_CONNECT, + }; + struct bt_conn *conn; + bt_addr_le_t dst; + int err; + + event.acl_connect.status = param->acl_connect.status; + event.acl_connect.conn_handle = param->acl_connect.conn_handle; + event.acl_connect.role = param->acl_connect.role; + event.acl_connect.dst.type = param->acl_connect.dst.type; + memcpy(event.acl_connect.dst.val, param->acl_connect.dst.val, BT_ADDR_SIZE); + + bt_le_host_lock(); + + if (event.acl_connect.status) { + goto end; + } + + conn = bt_le_acl_conn_find(event.acl_connect.conn_handle); + if (conn) { + LOG_WRN("AclConnExist[%u]", event.acl_connect.conn_handle); + goto end; + } + + dst.type = event.acl_connect.dst.type; + memcpy(dst.a.val, event.acl_connect.dst.val, BT_ADDR_SIZE); + + /* Not encrypted at this moment */ + err = bt_le_acl_conn_new(event.acl_connect.conn_handle, + event.acl_connect.role, + &dst, BT_SECURITY_L1); + if (err) { + goto end; + } + + err = bt_le_acl_conn_connected_listener(event.acl_connect.conn_handle); + assert(err == 0); + +end: + bt_le_host_unlock(); + + bt_le_gap_app_cb_evt(&event); +} + +static void handle_acl_disconnect_event_safe(struct bt_le_gap_app_param *param) +{ + struct bt_le_gap_app_event event = { + .type = BT_LE_GAP_APP_EVENT_ACL_DISCONNECT, + }; + int err; + + event.acl_disconnect.conn_handle = param->acl_disconnect.conn_handle; + event.acl_disconnect.reason = param->acl_disconnect.reason; + + bt_le_host_lock(); + + err = bt_le_acl_conn_disconnected_listener(event.acl_disconnect.conn_handle, + event.acl_disconnect.reason); + if (err) { + goto end; + } + + err = bt_le_acl_conn_delete(event.acl_disconnect.conn_handle); + assert(err == 0); + +end: + bt_le_host_unlock(); + + bt_le_gap_app_cb_evt(&event); +} + +static void handle_security_change_event_safe(struct bt_le_gap_app_param *param) +{ + struct bt_le_gap_app_event event = { + .type = BT_LE_GAP_APP_EVENT_SECURITY_CHANGE, + }; + struct bt_conn *conn; + bt_addr_le_t dst; + bool encrypted; + int err; + + event.security_change.status = param->security_change.status; + event.security_change.conn_handle = param->security_change.conn_handle; + event.security_change.role = param->security_change.role; + event.security_change.sec_level = param->security_change.sec_level; + event.security_change.bonded = param->security_change.bonded; + event.security_change.dst.type = param->security_change.dst.type; + memcpy(event.security_change.dst.val, param->security_change.dst.val, BT_ADDR_SIZE); + + encrypted = false; + + bt_le_host_lock(); + + if (event.security_change.status) { + goto end; + } + + conn = bt_le_acl_conn_find(event.security_change.conn_handle); + if (conn == NULL) { + dst.type = event.security_change.dst.type; + memcpy(dst.a.val, event.security_change.dst.val, BT_ADDR_SIZE); + + err = bt_le_acl_conn_new(event.security_change.conn_handle, + event.security_change.role, + &dst, event.security_change.sec_level); + if (err) { + goto end; + } + } else { + err = bt_le_acl_conn_update(event.security_change.conn_handle, + event.security_change.sec_level, + &encrypted); + assert(err == 0); + } + + err = bt_le_acl_conn_security_changed_listener(event.security_change.conn_handle, + event.security_change.sec_level); + assert(err == 0); + + if (encrypted) { + /* TODO: check if bonded or not */ + err = bt_le_acl_conn_pairing_completed_listener(event.security_change.conn_handle, true); + assert(err == 0); + } + +end: + bt_le_host_unlock(); + + bt_le_gap_app_cb_evt(&event); +} + +static void handle_identity_resolve_event_safe(struct bt_le_gap_app_param *param) +{ + struct bt_le_gap_app_event event = { + .type = BT_LE_GAP_APP_EVENT_IDENTITY_RESOLVE, + }; + bt_addr_le_t identity; + bt_addr_le_t rpa; + + event.identity_resolve.conn_handle = param->identity_resolve.conn_handle; + event.identity_resolve.rpa.type = param->identity_resolve.rpa.type; + memcpy(event.identity_resolve.rpa.val, param->identity_resolve.rpa.val, BT_ADDR_SIZE); + event.identity_resolve.identity.type = param->identity_resolve.identity.type; + memcpy(event.identity_resolve.identity.val, param->identity_resolve.identity.val, BT_ADDR_SIZE); + + identity.type = event.identity_resolve.identity.type; + memcpy(identity.a.val, event.identity_resolve.identity.val, BT_ADDR_SIZE); + + rpa.type = event.identity_resolve.rpa.type; + memcpy(rpa.a.val, event.identity_resolve.rpa.val, BT_ADDR_SIZE); + + bt_le_host_lock(); + + bt_le_acl_conn_identity_resolved_listener(event.identity_resolve.conn_handle, &rpa, &identity); + + bt_le_host_unlock(); + + bt_le_gap_app_cb_evt(&event); +} + +static void handle_bond_delete_event_safe(struct bt_le_gap_app_param *param) +{ + struct bt_le_gap_app_event event = { + .type = BT_LE_GAP_APP_EVENT_BOND_DELETE, + }; + bt_addr_le_t peer; + + event.bond_delete.id = param->bond_delete.id; + event.bond_delete.peer.type = param->bond_delete.peer.type; + memcpy(event.bond_delete.peer.val, param->bond_delete.peer.val, BT_ADDR_SIZE); + + peer.type = event.bond_delete.peer.type; + memcpy(peer.a.val, event.bond_delete.peer.val, sizeof(peer.a.val)); + + bt_le_host_lock(); + + bt_le_acl_conn_bond_deleted_listener(event.bond_delete.id, &peer); + + bt_le_host_unlock(); + + bt_le_gap_app_cb_evt(&event); +} + +void bt_le_gap_handle_event(uint8_t *data, size_t data_len) +{ + struct bt_le_gap_app_param *param; + + assert(data && data_len); + + param = (struct bt_le_gap_app_param *)data; + + switch (param->type) { + case BT_LE_GAP_APP_PARAM_EXT_SCAN_RECV: + handle_ext_scan_recv_event_safe(param); + break; + case BT_LE_GAP_APP_PARAM_PA_SYNC: + handle_pa_sync_event_safe(param); + break; + case BT_LE_GAP_APP_PARAM_PA_SYNC_LOST: + handle_pa_sync_lost_event_safe(param); + break; + case BT_LE_GAP_APP_PARAM_PA_SYNC_RECV: + handle_pa_sync_recv_event_safe(param); + break; + case BT_LE_GAP_APP_PARAM_ACL_CONNECT: + handle_acl_connect_event_safe(param); + break; + case BT_LE_GAP_APP_PARAM_ACL_DISCONNECT: + handle_acl_disconnect_event_safe(param); + break; + case BT_LE_GAP_APP_PARAM_SECURITY_CHANGE: + handle_security_change_event_safe(param); + break; + case BT_LE_GAP_APP_PARAM_IDENTITY_RESOLVE: + handle_identity_resolve_event_safe(param); + break; + case BT_LE_GAP_APP_PARAM_BOND_DELETE: + handle_bond_delete_event_safe(param); + break; + default: + assert(0); + break; + } + + free(data); +} + +void bt_le_gap_app_post_event(uint8_t type, void *param) +{ + /* Currently type is not used */ + ARG_UNUSED(type); + + bt_le_nimble_gap_post_event(param); +} diff --git a/components/bt/esp_ble_audio/host/common/app/gap.h b/components/bt/esp_ble_audio/host/common/app/gap.h new file mode 100644 index 0000000000..0676d8679b --- /dev/null +++ b/components/bt/esp_ble_audio/host/common/app/gap.h @@ -0,0 +1,273 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef HOST_COMMON_APP_GAP_H_ +#define HOST_COMMON_APP_GAP_H_ + +#include + +#include "sdkconfig.h" + +#include "nimble/gap.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_le_addr { + uint8_t type; + uint8_t val[6]; +}; + +struct bt_le_gap_app_ext_scan_recv_param { + uint16_t event_type; + struct bt_le_addr addr; + int8_t rssi; + int8_t tx_power; + uint8_t sid; + uint8_t pri_phy; + uint8_t sec_phy; + uint16_t per_adv_itvl; + uint8_t data_len; + uint8_t *data; +}; + +struct bt_le_gap_app_pa_sync_param { + uint8_t status; + uint16_t sync_handle; + struct bt_le_addr addr; + uint8_t sid; + uint8_t adv_phy; + uint16_t per_adv_itvl; + uint8_t adv_ca; +}; + +struct bt_le_gap_app_pa_sync_lost_param { + uint16_t sync_handle; + uint8_t reason; +}; + +struct bt_le_gap_app_pa_sync_recv_param { + uint16_t sync_handle; + int8_t tx_power; + int8_t rssi; + uint8_t data_status; + uint8_t data_len; + uint8_t *data; +}; + +struct bt_le_gap_app_acl_connect_param { + uint8_t status; + uint16_t conn_handle; + uint8_t role; + struct bt_le_addr dst; +}; + +struct bt_le_gap_app_acl_disconnect_param { + uint16_t conn_handle; + uint8_t reason; +}; + +struct bt_le_gap_app_security_change_param { + uint8_t status; + uint16_t conn_handle; + uint8_t role; + uint8_t sec_level; + uint8_t bonded : 1; + struct bt_le_addr dst; +}; + +struct bt_le_gap_app_identity_resolve_param { + uint16_t conn_handle; + struct bt_le_addr rpa; + struct bt_le_addr identity; +}; + +struct bt_le_gap_app_bond_delete_param { + uint8_t id; + struct bt_le_addr peer; +}; + +struct bt_le_gap_app_biginfo_recv_param { + uint16_t sync_handle; + uint8_t num_bis; + uint8_t nse; + uint16_t iso_interval; + uint8_t bn; + uint8_t pto; + uint8_t irc; + uint16_t max_pdu; + uint32_t sdu_interval; + uint16_t max_sdu; + uint8_t phy; + uint8_t framing; + uint8_t encryption; +}; + +struct bt_le_gap_app_param { + uint8_t type; + + union { + struct bt_le_gap_app_ext_scan_recv_param ext_scan_recv; + struct bt_le_gap_app_pa_sync_param pa_sync; + struct bt_le_gap_app_pa_sync_lost_param pa_sync_lost; + struct bt_le_gap_app_pa_sync_recv_param pa_sync_recv; + struct bt_le_gap_app_acl_connect_param acl_connect; + struct bt_le_gap_app_acl_disconnect_param acl_disconnect; + struct bt_le_gap_app_security_change_param security_change; + struct bt_le_gap_app_identity_resolve_param identity_resolve; + struct bt_le_gap_app_bond_delete_param bond_delete; + }; +}; + +enum bt_le_gap_app_param_type { + BT_LE_GAP_APP_PARAM_EXT_SCAN_RECV, + BT_LE_GAP_APP_PARAM_PA_SYNC, + BT_LE_GAP_APP_PARAM_PA_SYNC_LOST, + BT_LE_GAP_APP_PARAM_PA_SYNC_RECV, + BT_LE_GAP_APP_PARAM_ACL_CONNECT, + BT_LE_GAP_APP_PARAM_ACL_DISCONNECT, + BT_LE_GAP_APP_PARAM_SECURITY_CHANGE, + BT_LE_GAP_APP_PARAM_IDENTITY_RESOLVE, + BT_LE_GAP_APP_PARAM_BOND_DELETE, + + BT_LE_GAP_APP_PARAM_MAX, +}; + +struct bt_le_gap_app_event_ext_scan_recv { + uint16_t event_type; + struct bt_le_addr addr; + int8_t rssi; + int8_t tx_power; + uint8_t sid; + uint8_t pri_phy; + uint8_t sec_phy; + uint16_t per_adv_itvl; + uint8_t data_len; + uint8_t *data; /* Will be freed after the event is processed */ +}; + +struct bt_le_gap_app_event_pa_sync { + uint8_t status; + uint16_t sync_handle; + struct bt_le_addr addr; + uint8_t sid; + uint8_t adv_phy; + uint16_t per_adv_itvl; + uint8_t adv_ca; +}; + +struct bt_le_gap_app_event_pa_sync_lost { + uint16_t sync_handle; + uint8_t reason; +}; + +struct bt_le_gap_app_event_pa_sync_recv { + uint16_t sync_handle; + int8_t tx_power; + int8_t rssi; + uint8_t data_status; + uint8_t data_len; + uint8_t *data; /* Will be freed after the event is processed */ +}; + +struct bt_le_gap_app_event_acl_connect { + uint8_t status; + uint16_t conn_handle; + uint8_t role; + struct bt_le_addr dst; +}; + +struct bt_le_gap_app_event_acl_disconnect { + uint16_t conn_handle; + uint8_t reason; +}; + +struct bt_le_gap_app_event_security_change { + uint8_t status; + uint16_t conn_handle; + uint8_t role; + uint8_t sec_level; + uint8_t bonded : 1; + struct bt_le_addr dst; +}; + +struct bt_le_gap_app_event_identity_resolve { + uint16_t conn_handle; + struct bt_le_addr rpa; + struct bt_le_addr identity; +}; + +struct bt_le_gap_app_event_bond_delete { + uint8_t id; + struct bt_le_addr peer; +}; + +struct bt_le_gap_app_event_biginfo_recv { + uint16_t sync_handle; + uint8_t num_bis; + uint8_t nse; + uint16_t iso_interval; + uint8_t bn; + uint8_t pto; + uint8_t irc; + uint16_t max_pdu; + uint32_t sdu_interval; + uint16_t max_sdu; + uint8_t phy; + uint8_t framing; + uint8_t encryption; +}; + +struct bt_le_gap_app_event { + uint8_t type; + + union { + struct bt_le_gap_app_event_ext_scan_recv ext_scan_recv; + struct bt_le_gap_app_event_pa_sync pa_sync; + struct bt_le_gap_app_event_pa_sync_lost pa_sync_lost; + struct bt_le_gap_app_event_pa_sync_recv pa_sync_recv; + struct bt_le_gap_app_event_acl_connect acl_connect; + struct bt_le_gap_app_event_acl_disconnect acl_disconnect; + struct bt_le_gap_app_event_security_change security_change; + struct bt_le_gap_app_event_identity_resolve identity_resolve; + struct bt_le_gap_app_event_bond_delete bond_delete; + struct bt_le_gap_app_event_biginfo_recv biginfo_recv; + }; +}; + +enum bt_le_gap_app_event_type { + BT_LE_GAP_APP_EVENT_EXT_SCAN_RECV, + BT_LE_GAP_APP_EVENT_PA_SYNC, + BT_LE_GAP_APP_EVENT_PA_SYNC_LOST, + BT_LE_GAP_APP_EVENT_PA_SYNC_RECV, + BT_LE_GAP_APP_EVENT_ACL_CONNECT, + BT_LE_GAP_APP_EVENT_ACL_DISCONNECT, + BT_LE_GAP_APP_EVENT_SECURITY_CHANGE, + BT_LE_GAP_APP_EVENT_IDENTITY_RESOLVE, + BT_LE_GAP_APP_EVENT_BOND_DELETE, + BT_LE_GAP_APP_EVENT_BIGINFO_RECV, + + BT_LE_GAP_APP_EVENT_MAX, +}; + +typedef void (*bt_le_gap_app_cb)(struct bt_le_gap_app_event *event); + +int bt_le_gap_app_cb_register(bt_le_gap_app_cb cb); + +void bt_le_gap_app_cb_unregister(void); + +void bt_le_gap_app_biginfo_event(uint8_t *param); + +void bt_le_gap_handle_event(uint8_t *data, size_t data_len); + +void bt_le_gap_app_post_event(uint8_t type, void *param); + +#ifdef __cplusplus +} +#endif + +#endif /* HOST_COMMON_APP_GAP_H_ */ diff --git a/components/bt/esp_ble_audio/host/common/app/gatt.c b/components/bt/esp_ble_audio/host/common/app/gatt.c new file mode 100644 index 0000000000..6c1d75c57c --- /dev/null +++ b/components/bt/esp_ble_audio/host/common/app/gatt.c @@ -0,0 +1,113 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include +#include + +#include <../host/hci_core.h> +#include <../host/iso_internal.h> + +#include "common/host.h" +#include "common/app/gatt.h" + +static bt_le_gatt_app_cb gatt_app_cb; + +int bt_le_gatt_app_cb_register(bt_le_gatt_app_cb cb) +{ + LOG_DBG("GattAppCbReg"); + + if (cb == NULL) { + LOG_ERR("GattAppCbNull"); + return -EINVAL; + } + + if (gatt_app_cb) { + LOG_WRN("GattAppCbExist"); + return -EALREADY; + } + + gatt_app_cb = cb; + + return 0; +} + +void bt_le_gatt_app_cb_unregister(void) +{ + if (gatt_app_cb) { + LOG_DBG("GattAppCbUnreg"); + gatt_app_cb = NULL; + } +} + +static inline void bt_le_gatt_app_cb_evt(struct bt_le_gatt_app_event *event) +{ + if (gatt_app_cb) { + gatt_app_cb(event); + } +} + +void bt_le_gatt_app_mtu_change_event(uint16_t conn_handle, uint16_t mtu) +{ + struct bt_le_gatt_app_event event = { + .type = BT_LE_GATT_APP_EVENT_GATT_MTU_CHANGE, + }; + + LOG_DBG("GattMtuChangeAppEvt[%u][%u]", conn_handle, mtu); + + event.gatt_mtu_change.conn_handle = conn_handle; + event.gatt_mtu_change.mtu = mtu; + + bt_le_gatt_app_cb_evt(&event); +} + +void bt_le_gattc_app_disc_cmpl_event(struct bt_le_gattc_disc_cmpl_event *param) +{ + struct bt_le_gatt_app_event event = { + .type = BT_LE_GATT_APP_EVENT_GATTC_DISC_CMPL, + }; + + LOG_DBG("GattcDiscCmplAppEvt[%u][%02x]", param->conn_handle, param->status); + + event.gattc_disc_cmpl.status = param->status; + event.gattc_disc_cmpl.conn_handle = param->conn_handle; + + bt_le_gatt_app_cb_evt(&event); +} + +void bt_le_gatts_app_subscribe_event(struct bt_le_gatts_subscribe_event *param) +{ + struct bt_le_gatt_app_event event = { + .type = BT_LE_GATT_APP_EVENT_GATTS_SUBSCRIBE, + }; + + /* LOG_DBG("GattsSubAppEvt[%d][%u][%u][%u][%u][%u][%u][%02x]", */ + /* err, param->conn_handle, param->attr_handle, param->prev_notify, */ + /* param->cur_notify, param->prev_indicate, param->cur_indicate, */ + /* param->reason); */ + + event.gatts_subscribe.conn_handle = param->conn_handle; + event.gatts_subscribe.attr_handle = param->attr_handle; + event.gatts_subscribe.prev_notify = param->prev_notify; + event.gatts_subscribe.cur_notify = param->cur_notify; + event.gatts_subscribe.prev_indicate = param->prev_indicate; + event.gatts_subscribe.cur_indicate = param->cur_indicate; + event.gatts_subscribe.reason = param->reason; + + bt_le_gatt_app_cb_evt(&event); +} + +void bt_le_gatt_app_post_event(uint8_t type, void *param) +{ + /* Currently type is not used */ + ARG_UNUSED(type); + + bt_le_nimble_gatt_post_event(param); +} diff --git a/components/bt/esp_ble_audio/host/common/app/gatt.h b/components/bt/esp_ble_audio/host/common/app/gatt.h new file mode 100644 index 0000000000..91350b9a4e --- /dev/null +++ b/components/bt/esp_ble_audio/host/common/app/gatt.h @@ -0,0 +1,76 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef HOST_COMMON_APP_GATT_H_ +#define HOST_COMMON_APP_GATT_H_ + +#include + +#include "sdkconfig.h" + +#include "nimble/gatt/gatt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_le_gatt_app_event_gatt_mtu_change { + uint16_t conn_handle; + uint16_t mtu; +}; + +struct bt_le_gatt_app_event_gattc_disc_cmpl { + uint8_t status; + uint16_t conn_handle; +}; + +struct bt_le_gatt_app_event_gatts_subscribe { + uint16_t conn_handle; + uint16_t attr_handle; + uint8_t prev_notify : 1; + uint8_t cur_notify : 1; + uint8_t prev_indicate : 1; + uint8_t cur_indicate : 1; + uint8_t reason; +}; + +struct bt_le_gatt_app_event { + uint8_t type; + + union { + struct bt_le_gatt_app_event_gatt_mtu_change gatt_mtu_change; + struct bt_le_gatt_app_event_gattc_disc_cmpl gattc_disc_cmpl; + struct bt_le_gatt_app_event_gatts_subscribe gatts_subscribe; + }; +}; + +enum bt_le_gatt_app_event_type { + BT_LE_GATT_APP_EVENT_GATT_MTU_CHANGE, + BT_LE_GATT_APP_EVENT_GATTC_DISC_CMPL, + BT_LE_GATT_APP_EVENT_GATTS_SUBSCRIBE, + + BT_LE_GATT_APP_EVENT_MAX, +}; + +typedef void (*bt_le_gatt_app_cb)(struct bt_le_gatt_app_event *event); + +int bt_le_gatt_app_cb_register(bt_le_gatt_app_cb cb); + +void bt_le_gatt_app_cb_unregister(void); + +void bt_le_gatt_app_mtu_change_event(uint16_t conn_handle, uint16_t mtu); + +void bt_le_gattc_app_disc_cmpl_event(struct bt_le_gattc_disc_cmpl_event *param); + +void bt_le_gatts_app_subscribe_event(struct bt_le_gatts_subscribe_event *param); + +void bt_le_gatt_app_post_event(uint8_t type, void *param); + +#ifdef __cplusplus +} +#endif + +#endif /* HOST_COMMON_APP_GATT_H_ */ diff --git a/components/bt/esp_ble_audio/host/common/conn.c b/components/bt/esp_ble_audio/host/common/conn.c new file mode 100644 index 0000000000..662c3e692e --- /dev/null +++ b/components/bt/esp_ble_audio/host/common/conn.c @@ -0,0 +1,678 @@ +/* + * SPDX-FileCopyrightText: 2015-2016 Intel Corporation + * SPDX-FileCopyrightText: 2025 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include +#include + +#include <../host/keys.h> +#include <../host/conn_internal.h> +#include <../host/iso_internal.h> + +#include "common/host.h" +#include "common/app/gap.h" + +static struct bt_conn acl_conns[CONFIG_BT_MAX_CONN]; + +extern struct bt_conn iso_conns[CONFIG_BT_ISO_MAX_CHAN]; + +static sys_slist_t conn_cbs = SYS_SLIST_STATIC_INIT(&conn_cbs); + +static sys_slist_t auth_info_cbs = SYS_SLIST_STATIC_INIT(&auth_info_cbs); + +_IDF_ONLY +void bt_conn_get_acl_conns(struct bt_conn **conns, uint8_t *count) +{ + LOG_DBG("GetAclConns[%u]", ARRAY_SIZE(acl_conns)); + + *conns = acl_conns; + *count = ARRAY_SIZE(acl_conns); +} + +_IDF_ONLY +bool bt_conn_is_peer_addr_le(const struct bt_conn *conn, uint8_t id, + const bt_addr_le_t *peer) +{ + /* LOG_DBG("IsLeAddr[%s][%s]", bt_addr_le_str(&conn->le.dst), bt_addr_le_str(peer)); */ + + ARG_UNUSED(id); + + assert(conn && peer); + + /* Check against conn dst address as it may be the identity address */ + if (bt_addr_le_eq(peer, &conn->le.dst)) { + return true; + } + + return false; +} + +_LIB_IDF +struct bt_conn *bt_conn_ref(struct bt_conn *conn) +{ + return conn; +} + +_LIB_IDF +void bt_conn_unref(struct bt_conn *conn) +{ + ARG_UNUSED(conn); +} + +_LIB_ONLY +void bt_conn_foreach(enum bt_conn_type type, + void (*func)(struct bt_conn *conn, void *data), + void *data) +{ + assert(type == BT_CONN_TYPE_LE); + + for (size_t i = 0; i < ARRAY_SIZE(acl_conns); i++) { + struct bt_conn *conn = &acl_conns[i]; + + /* Add this to avoid unexpected error log */ + if (conn->type == BT_CONN_TYPE_LE) { + func(&acl_conns[i], data); + } + } +} + +_LIB_ONLY +const bt_addr_le_t *bt_conn_get_dst(const struct bt_conn *conn) +{ + assert(conn); + + return &conn->le.dst; +} + +_LIB_IDF +uint8_t bt_conn_index(const struct bt_conn *conn) +{ + ptrdiff_t index = 0; + + assert(conn); + + switch (conn->type) { + case BT_CONN_TYPE_LE: + index = conn - acl_conns; + assert(index >= 0 && index < ARRAY_SIZE(acl_conns)); + break; + case BT_CONN_TYPE_ISO: + index = conn - iso_conns; + assert(index >= 0 && index < ARRAY_SIZE(iso_conns)); + break; + default: + assert(0); + break; + } + + /* LOG_DBG("ConnIdx[%u]", index); */ + + return (uint8_t)index; +} + +#if CONFIG_BT_SMP +_IDF_ONLY +int bt_conn_set_security(struct bt_conn *conn, bt_security_t sec) +{ + /* This function is used by CIS to set security level, + * currently always return failure here to make sure + * that before creating CIS, the ACL connection is + * encrypted. + */ + return -ENOTSUP; +} +#endif /* CONFIG_BT_SMP */ + +static enum bt_conn_state conn_internal_to_public_state(bt_conn_state_t state) +{ + switch (state) { + case BT_CONN_DISCONNECTED: + case BT_CONN_DISCONNECT_COMPLETE: + return BT_CONN_STATE_DISCONNECTED; + case BT_CONN_INITIATING: + return BT_CONN_STATE_CONNECTING; + case BT_CONN_CONNECTED: + return BT_CONN_STATE_CONNECTED; + case BT_CONN_DISCONNECTING: + return BT_CONN_STATE_DISCONNECTING; + default: + assert(0); + return 0; + } +} + +_LIB_ONLY +int bt_conn_get_info(const struct bt_conn *conn, struct bt_conn_info *info) +{ + assert(conn && info); + + info->type = conn->type; + info->role = conn->role; + info->id = conn->id; + info->state = conn_internal_to_public_state(conn->state); + info->le.dst = &conn->le.dst; + info->le.interval = conn->le.interval; + + if (conn->encrypt) { + /* Currently the flags is updated for lib usage. + * TODO: + * Update the flags based on the security information. + */ + info->security.flags = (BT_SECURITY_FLAG_SC | BT_SECURITY_FLAG_OOB); + info->security.level = conn->sec_level; + info->security.enc_key_size = BT_ENC_KEY_SIZE_MAX; /* 16 octets */ + } else { + info->security.flags = 0; + info->security.level = BT_SECURITY_L1; + info->security.enc_key_size = 0; + } + + /* LOG_DBG("ConnGetInfo[%u][%02x]", info->state, info->security.flags); */ + + return 0; +} + +_LIB_ONLY +int bt_conn_cb_register(struct bt_conn_cb *cb) +{ + LOG_DBG("ConnCbReg"); + + if (cb == NULL) { + LOG_ERR("ConnCbNull"); + return -EINVAL; + } + + if (sys_slist_find(&conn_cbs, &cb->_node, NULL)) { + LOG_WRN("ConnCbExist"); + return -EEXIST; + } + + sys_slist_append(&conn_cbs, &cb->_node); + + return 0; +} + +_IDF_ONLY +int bt_conn_cb_register_safe(struct bt_conn_cb *cb) +{ + int err; + bt_le_host_lock(); + err = bt_conn_cb_register(cb); + bt_le_host_unlock(); + return err; +} + +_NOT_USED +int bt_conn_cb_unregister(struct bt_conn_cb *cb) +{ + LOG_DBG("ConnCbUnreg"); + + if (cb == NULL) { + LOG_ERR("ConnCbNull"); + return -EINVAL; + } + + if (!sys_slist_find_and_remove(&conn_cbs, &cb->_node)) { + LOG_ERR("ConnCbNotFound"); + return -EALREADY; + } + + return 0; +} + +_LIB_ONLY +int bt_conn_auth_info_cb_register(struct bt_conn_auth_info_cb *cb) +{ + LOG_DBG("ConnAuthInfoCbReg"); + + if (cb == NULL) { + LOG_ERR("ConnAuthInfoCbNull"); + return -EINVAL; + } + + if (sys_slist_find(&auth_info_cbs, &cb->node, NULL)) { + LOG_WRN("ConnAuthInfoCbExist"); + return -EALREADY; + } + + sys_slist_append(&auth_info_cbs, &cb->node); + + return 0; +} + +_NOT_USED +int bt_conn_auth_info_cb_unregister(struct bt_conn_auth_info_cb *cb) +{ + LOG_DBG("ConnAuthInfoCbUnreg"); + + if (cb == NULL) { + LOG_ERR("ConnAuthInfoCbNull"); + return -EINVAL; + } + + if (!sys_slist_find_and_remove(&auth_info_cbs, &cb->node)) { + LOG_ERR("ConnAuthInfoCbNotFound"); + return -EALREADY; + } + + return 0; +} + +_IDF_ONLY +struct bt_conn *bt_conn_new(struct bt_conn *conns, size_t size) +{ + assert(conns); + + for (size_t i = 0; i < size; i++) { + struct bt_conn *conn = &conns[i]; + + if (conn->type == 0) { + (void)memset(conn, 0, sizeof(struct bt_conn)); + return conn; + } + } + + return NULL; +} + +static struct bt_conn *acl_conn_lookup(uint16_t handle) +{ + for (size_t i = 0; i < ARRAY_SIZE(acl_conns); i++) { + if (acl_conns[i].type == BT_CONN_TYPE_LE && + acl_conns[i].handle == handle) { + return &acl_conns[i]; + } + } + + LOG_INF("AclConnNotFound[%u]", handle); + return NULL; +} + +static struct bt_conn *iso_conn_lookup(uint16_t handle) +{ + for (size_t i = 0; i < ARRAY_SIZE(iso_conns); i++) { + if (iso_conns[i].type == BT_CONN_TYPE_ISO && + iso_conns[i].handle == handle) { + return &iso_conns[i]; + } + } + + LOG_INF("IsoConnNotFound[%u]", handle); + return NULL; +} + +_IDF_ONLY +struct bt_conn *bt_conn_lookup_handle(uint16_t handle, enum bt_conn_type type) +{ + struct bt_conn *conn = NULL; + + assert(type == BT_CONN_TYPE_LE || type == BT_CONN_TYPE_ISO); + + /* LOG_DBG("ConnLookupHdl[%u][%u]", handle, type); */ + + if (type == BT_CONN_TYPE_LE) { + conn = acl_conn_lookup(handle); + } else { + conn = iso_conn_lookup(handle); + } + + return conn; +} + +_IDF_ONLY +struct bt_conn *bt_le_acl_conn_find(uint16_t conn_handle) +{ + /* LOG_DBG("AclConnFind[%u]", conn_handle); */ + + return bt_conn_lookup_handle(conn_handle, BT_CONN_TYPE_LE); +} + +_IDF_ONLY +struct bt_conn *bt_le_acl_conn_find_safe(uint16_t conn_handle) +{ + struct bt_conn *conn = NULL; + /* LOG_DBG("AclConnFind[%u]", conn_handle); */ + bt_le_host_lock(); + conn = bt_conn_lookup_handle(conn_handle, BT_CONN_TYPE_LE); + bt_le_host_unlock(); + return conn; +} + +_IDF_ONLY +int bt_le_acl_conn_new(uint16_t conn_handle, + uint8_t role, + bt_addr_le_t *dst, + uint8_t sec_level) +{ + struct bt_conn *conn; + + assert(dst); + + LOG_DBG("AclNew[%u][%u][%u][%s]", + conn_handle, role, sec_level, bt_addr_le_str(dst)); + + conn = bt_conn_new(acl_conns, ARRAY_SIZE(acl_conns)); + if (conn) { + conn->handle = conn_handle; + conn->type = BT_CONN_TYPE_LE; + conn->role = role; + conn->state = BT_CONN_CONNECTED; + conn->sec_level = sec_level; + memcpy(&conn->le.dst, dst, sizeof(conn->le.dst)); + } else { + LOG_ERR("NoFreeConn[%u]", conn_handle); + } + + return (conn ? 0 : -ENOMEM); +} + +_IDF_ONLY +int bt_le_acl_conn_delete(uint16_t conn_handle) +{ + struct bt_conn *conn; + + LOG_DBG("AclConnDel[%u]", conn_handle); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL || conn->state != BT_CONN_CONNECTED) { + LOG_ERR("NotConn[%d]", __LINE__); + return -ENOTCONN; + } + + memset(conn, 0, sizeof(struct bt_conn)); + + return 0; +} + +_IDF_ONLY +int bt_le_acl_conn_update(uint16_t conn_handle, + uint8_t sec_level, + bool *encrypted) +{ + struct bt_conn *conn; + + LOG_DBG("AclConnUpd[%u][%u]", conn_handle, sec_level); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL || conn->state != BT_CONN_CONNECTED) { + LOG_ERR("NotConn[%d]", __LINE__); + return -ENOTCONN; + } + + if (encrypted) { + *encrypted = false; + } + + if (conn->sec_level < sec_level) { + /* No encryption to encryption */ + if (conn->encrypt == 0 && conn->sec_level == BT_SECURITY_L1) { + conn->encrypt = 1; + + if (encrypted) { + *encrypted = true; + } + } + + LOG_DBG("SecLevelUpd[%u][%u]", conn->sec_level, sec_level); + conn->sec_level = sec_level; + } + + return 0; +} + +static void acl_conn_set_state(struct bt_conn *conn, bt_conn_state_t state) +{ + LOG_DBG("AclConnSetState"); + + conn->state = state; + + switch (conn->state) { + case BT_CONN_CONNECTED: + break; + case BT_CONN_INITIATING: + break; + case BT_CONN_DISCONNECT_COMPLETE: + break; + default: + break; + } +} + +static void iso_conn_set_state(struct bt_conn *conn, bt_conn_state_t state) +{ + LOG_DBG("IsoConnSetState[%u]", state); + + conn->state = state; + + switch (conn->state) { + case BT_CONN_CONNECTED: + bt_iso_connected(conn); + break; + case BT_CONN_INITIATING: + break; + case BT_CONN_DISCONNECT_COMPLETE: + conn->type = 0; + /* Note: + * The bt_iso_disconnected is not called here, the ISO + * disconnected callback will be called by the ISO layer. + */ + /* bt_iso_disconnected(conn); */ + break; + default: + break; + } +} + +_IDF_ONLY +void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state) +{ + bt_conn_state_t old_state; + + assert(conn); + assert(conn->type == BT_CONN_TYPE_LE || conn->type == BT_CONN_TYPE_ISO); + + LOG_DBG("ConnSetState[%u][%u]", conn->state, state); + + if (conn->state == state) { + return; + } + + old_state = conn->state; + + switch (old_state) { + case BT_CONN_DISCONNECTED: + /* TODO: check if anything to do */ + break; + case BT_CONN_INITIATING: + /* TODO: check if anything to do */ + break; + default: + break; + } + + if (conn->type == BT_CONN_TYPE_LE) { + acl_conn_set_state(conn, state); + } else { + iso_conn_set_state(conn, state); + } +} + +static int iso_disconnect(struct bt_conn *conn, uint8_t reason) +{ + return bt_le_iso_disconnect(conn->handle, reason); +} + +_IDF_ONLY +int bt_conn_disconnect(struct bt_conn *conn, uint8_t reason) +{ + assert(conn); + + LOG_DBG("ConnDisconnect[%u][%u][%02x]", conn->state, conn->type, reason); + + switch (conn->state) { + case BT_CONN_CONNECTED: + if (conn->type == BT_CONN_TYPE_LE) { + return -ENOTSUP; + } + + if (conn->type == BT_CONN_TYPE_ISO) { + return iso_disconnect(conn, reason); + } + + assert(0); + case BT_CONN_DISCONNECTING: + return 0; + case BT_CONN_DISCONNECTED: + default: + return -ENOTCONN; + } +} + +_IDF_ONLY +int bt_le_acl_conn_connected_listener(uint16_t conn_handle) +{ + struct bt_conn_cb *listener = NULL; + struct bt_conn *conn; + + LOG_DBG("AclConnConnectedListener[%u]", conn_handle); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL || conn->state != BT_CONN_CONNECTED) { + LOG_ERR("NotConn[%d]", __LINE__); + return -ENOTCONN; + } + + SYS_SLIST_FOR_EACH_CONTAINER(&conn_cbs, listener, _node) { + if (listener->connected) { + listener->connected(conn, BT_HCI_ERR_SUCCESS); + } + } + + return 0; +} + +_IDF_ONLY +int bt_le_acl_conn_disconnected_listener(uint16_t conn_handle, uint8_t reason) +{ + struct bt_conn_cb *listener = NULL; + struct bt_conn *conn; + + LOG_DBG("AclConnDisconnectedListener[%u][%02x]", conn_handle, reason); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL || conn->state != BT_CONN_CONNECTED) { + LOG_ERR("NotConn[%d]", __LINE__); + return -ENOTCONN; + } + + SYS_SLIST_FOR_EACH_CONTAINER(&conn_cbs, listener, _node) { + if (listener->disconnected) { + listener->disconnected(conn, reason); + } + } + +#if CONFIG_BT_ISO_UNICAST + bt_le_acl_conn_disconnected_gatt_listener(conn_handle); +#endif /* CONFIG_BT_ISO_UNICAST */ + + return 0; +} + +_IDF_ONLY +int bt_le_acl_conn_security_changed_listener(uint16_t conn_handle, bt_security_t level) +{ + struct bt_conn_cb *listener = NULL; + struct bt_conn *conn; + + LOG_DBG("AclConnSecurityChangedListener[%u][%u]", conn_handle, level); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL || conn->state != BT_CONN_CONNECTED) { + LOG_ERR("NotConn[%d]", __LINE__); + return -ENOTCONN; + } + + SYS_SLIST_FOR_EACH_CONTAINER(&conn_cbs, listener, _node) { + if (listener->security_changed) { + listener->security_changed(conn, level, BT_SECURITY_ERR_SUCCESS); + } + } + + return 0; +} + +_IDF_ONLY +int bt_le_acl_conn_identity_resolved_listener(uint16_t conn_handle, + const bt_addr_le_t *rpa, + const bt_addr_le_t *identity) +{ + struct bt_conn_cb *listener = NULL; + struct bt_conn *conn; + + LOG_DBG("AclConnIdentityResolvedListener[%u][%s]", + conn_handle, bt_addr_le_str(rpa)); + LOG_DBG("AclConnIdentityResolvedListener[%s]", + bt_addr_le_str(identity)); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL || conn->state != BT_CONN_CONNECTED) { + LOG_ERR("NotConn[%d]", __LINE__); + return -ENOTCONN; + } + + SYS_SLIST_FOR_EACH_CONTAINER(&conn_cbs, listener, _node) { + if (listener->identity_resolved) { + listener->identity_resolved(conn, rpa, identity); + } + } + + return 0; +} + +_IDF_ONLY +int bt_le_acl_conn_pairing_completed_listener(uint16_t conn_handle, bool bonded) +{ + struct bt_conn_auth_info_cb *listener = NULL; + struct bt_conn *conn; + + LOG_DBG("AclConnPairingCompletedListener[%u][%u]", conn_handle, bonded); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL || conn->state != BT_CONN_CONNECTED) { + LOG_ERR("NotConn[%d]", __LINE__); + return -ENOTCONN; + } + + SYS_SLIST_FOR_EACH_CONTAINER(&auth_info_cbs, listener, node) { + if (listener->pairing_complete) { + listener->pairing_complete(conn, bonded); + } + } + + return 0; +} + +_IDF_ONLY +int bt_le_acl_conn_bond_deleted_listener(uint8_t id, const bt_addr_le_t *peer) +{ + struct bt_conn_auth_info_cb *listener = NULL; + + LOG_DBG("AclConnBondDeletedListener[%02x][%s]", id, bt_addr_le_str(peer)); + + SYS_SLIST_FOR_EACH_CONTAINER(&auth_info_cbs, listener, node) { + if (listener->bond_deleted) { + listener->bond_deleted(id, peer); + } + } + + return 0; +} diff --git a/components/bt/esp_ble_audio/host/common/conn.h b/components/bt/esp_ble_audio/host/common/conn.h new file mode 100644 index 0000000000..7860d8f092 --- /dev/null +++ b/components/bt/esp_ble_audio/host/common/conn.h @@ -0,0 +1,58 @@ +/* + * SPDX-FileCopyrightText: 2015-2016 Intel Corporation + * SPDX-FileCopyrightText: 2025 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef HOST_COMMON_CONN_H_ +#define HOST_COMMON_CONN_H_ + +#include + +#include "sdkconfig.h" + +#include "nimble/gap.h" +#include "nimble/iso.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void bt_conn_get_acl_conns(struct bt_conn **conns, uint8_t *count); + +struct bt_conn *bt_le_acl_conn_find(uint16_t conn_handle); + +struct bt_conn *bt_le_acl_conn_find_safe(uint16_t conn_handle); + +int bt_le_acl_conn_new(uint16_t conn_handle, + uint8_t role, + bt_addr_le_t *dst, + uint8_t sec_level); + +int bt_le_acl_conn_delete(uint16_t conn_handle); + +int bt_le_acl_conn_update(uint16_t conn_handle, + uint8_t sec_level, + bool *encrypted); + +int bt_le_acl_conn_connected_listener(uint16_t conn_handle); + +int bt_le_acl_conn_disconnected_listener(uint16_t conn_handle, uint8_t reason); + +int bt_le_acl_conn_security_changed_listener(uint16_t conn_handle, bt_security_t level); + +int bt_le_acl_conn_identity_resolved_listener(uint16_t conn_handle, + const bt_addr_le_t *rpa, + const bt_addr_le_t *identity); + +int bt_le_acl_conn_pairing_completed_listener(uint16_t conn_handle, bool bonded); + +int bt_le_acl_conn_bond_deleted_listener(uint8_t id, const bt_addr_le_t *peer); + +#ifdef __cplusplus +} +#endif + +#endif /* HOST_COMMON_CONN_H_ */ diff --git a/components/bt/esp_ble_audio/host/common/gatt.c b/components/bt/esp_ble_audio/host/common/gatt.c new file mode 100644 index 0000000000..e04d886011 --- /dev/null +++ b/components/bt/esp_ble_audio/host/common/gatt.c @@ -0,0 +1,1366 @@ +/* + * SPDX-FileCopyrightText: 2015-2016 Intel Corporation + * SPDX-FileCopyrightText: 2023 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include <../host/conn_internal.h> + +#include "common/host.h" + +static sys_slist_t gatt_db = SYS_SLIST_STATIC_INIT(&gatt_db); + +static struct gattc_sub subscriptions[CONFIG_BT_MAX_CONN]; + +_LIB_ONLY +int bt_gatt_service_register(struct bt_gatt_service *svc) +{ + const struct bt_uuid_16 *uuid; + + LOG_DBG("GattServiceReg"); + + if (svc == NULL) { + LOG_ERR("GattSvcNull"); + return -EINVAL; + } + + uuid = svc->attrs[0].user_data; + assert(uuid); + + LOG_DBG("GattSvc[%04x]", uuid->val); + + if (sys_slist_find(&gatt_db, &svc->node, NULL)) { + LOG_WRN("GattSvcExist"); + return -EALREADY; + } + + sys_slist_append(&gatt_db, &svc->node); + + return 0; +} + +_IDF_ONLY +int bt_gatt_service_register_safe(struct bt_gatt_service *svc) +{ + int err; + bt_le_host_lock(); + err = bt_gatt_service_register(svc); + bt_le_host_unlock(); + return err; +} + +_LIB_ONLY +int bt_gatt_service_unregister(struct bt_gatt_service *svc) +{ + LOG_DBG("GattServiceUnreg"); + + if (svc == NULL) { + LOG_ERR("GattSvcNull"); + return -EINVAL; + } + + if (!sys_slist_find_and_remove(&gatt_db, &svc->node)) { + LOG_ERR("GattSvcNotFound"); + return -ENOENT; + } + + return 0; +} + +_IDF_ONLY +int bt_gatt_service_unregister_safe(struct bt_gatt_service *svc) +{ + int err; + bt_le_host_lock(); + err = bt_gatt_service_unregister(svc); + bt_le_host_unlock(); + return err; +} + +_LIB_ONLY +uint16_t bt_gatt_get_mtu(struct bt_conn *conn) +{ + uint16_t mtu; + + assert(conn); + + mtu = bt_le_nimble_gatt_get_mtu(conn); + + LOG_DBG("GattGetMtu[%u]", mtu); + + return mtu; +} + +_LIB_ONLY +size_t bt_eatt_count(struct bt_conn *conn) +{ + return 0; +} + +_IDF_ONLY +struct bt_gatt_attr *bt_gatts_find_attr_by_handle(uint16_t handle) +{ + struct bt_gatt_service *svc = NULL; + struct bt_gatt_attr *attr = NULL; + + LOG_DBG("GattsFindAttrByHdl[%u]", handle); + + SYS_SLIST_FOR_EACH_CONTAINER(&gatt_db, svc, node) { + for (size_t i = 0; i < svc->attr_count; i++) { + if (svc->attrs[i].handle == handle) { + attr = &svc->attrs[i]; + break; + } + } + } + + if (attr == NULL) { + LOG_WRN("AttrNotFound[%u]", handle); + } + + return attr; +} + +_IDF_ONLY +uint16_t bt_gatt_attr_get_handle(const struct bt_gatt_attr *attr) +{ + uint16_t handle = 0; + + LOG_DBG("GattAttrGetHdl"); + + if (attr && attr->handle) { + handle = attr->handle; + } + + LOG_DBG("Hdl[%u]", handle); + return handle; +} + +_LIB_IDF +uint16_t bt_gatt_attr_value_handle(const struct bt_gatt_attr *attr) +{ + uint16_t handle = 0; + + /* Note: + * This function is used to get the handle of the + * characteristic value descriptor. + * Currently this function is only used by TMAP. + */ + + LOG_DBG("GattAttrValHdl"); + + if (attr) { + if (attr->uuid == NULL) { + handle = (attr->handle + 1); + } else { + LOG_DBG("Uuid[%s]", bt_uuid_str(attr->uuid)); + + if (bt_uuid_cmp(attr->uuid, BT_UUID_GATT_CHRC) == 0) { + struct bt_gatt_chrc *chrc = attr->user_data; + + assert(chrc); + handle = chrc->value_handle; + + LOG_DBG("ValHdl[%u]", handle); + + if (handle == 0) { + /* Fall back to Zephyr value handle policy */ + handle = bt_gatt_attr_get_handle(attr) + 1; + LOG_INF("ValHdlNew[%u]", handle); + } + } + } + } + + LOG_DBG("Hdl[%u]", handle); + return handle; +} + +static uint8_t find_next(const struct bt_gatt_attr *attr, + uint16_t handle, void *user_data) +{ + struct bt_gatt_attr **next = user_data; + + LOG_DBG("FindNext"); + + *next = (struct bt_gatt_attr *)attr; + + return BT_GATT_ITER_STOP; +} + +_IDF_ONLY +struct bt_gatt_attr *bt_gatt_attr_next(const struct bt_gatt_attr *attr) +{ + struct bt_gatt_attr *next = NULL; + uint16_t handle; + + LOG_DBG("GattAttrNext"); + + assert(attr); + handle = bt_gatt_attr_get_handle(attr); + + bt_gatt_foreach_attr(handle + 1, handle + 1, find_next, &next); + + return next; +} + +static uint8_t gatt_foreach_iter(const struct bt_gatt_attr *attr, + uint16_t handle, + uint16_t start_handle, + uint16_t end_handle, + const struct bt_uuid *uuid, + const void *attr_data, + uint16_t *num_matches, + bt_gatt_attr_func_t func, + void *user_data) +{ + uint8_t result; + + /* LOG_DBG("GattForeachIter[%u][%u][%u]", handle, start_handle, end_handle); */ + + /* Continue if over the requested range (stop is not suitable for our Hosts) */ + if (handle > end_handle) { + return BT_GATT_ITER_CONTINUE; + } + + /* Check if attribute handle is within range */ + if (handle < start_handle) { + return BT_GATT_ITER_CONTINUE; + } + + /* Match attribute UUID if set */ + if (uuid && bt_uuid_cmp(uuid, attr->uuid)) { + /* LOG_DBG("MismatchUuid[%s][%s]", bt_uuid_str(uuid), bt_uuid_str(attr->uuid)); */ + return BT_GATT_ITER_CONTINUE; + } + + /* Match attribute user_data if set */ + if (attr_data && attr_data != attr->user_data) { + LOG_DBG("MismatchAttrData"); + return BT_GATT_ITER_CONTINUE; + } + + *num_matches -= 1; + + result = func(attr, handle, user_data); + + if (*num_matches == 0) { + LOG_DBG("NumMatchesZero"); + return BT_GATT_ITER_STOP; + } + + LOG_DBG("GattIter%s", result == BT_GATT_ITER_CONTINUE ? "Cont" : "Stop"); + return result; +} + +static void foreach_attr_type_dyndb(uint16_t start_handle, + uint16_t end_handle, + const struct bt_uuid *uuid, + const void *attr_data, + uint16_t num_matches, + bt_gatt_attr_func_t func, + void *user_data) +{ + struct bt_gatt_service *svc; + + SYS_SLIST_FOR_EACH_CONTAINER(&gatt_db, svc, node) { +#if 0 + /* Note: this check is not suitable for our Hosts */ + struct bt_gatt_service *next; + + next = SYS_SLIST_PEEK_NEXT_CONTAINER(svc, node); + if (next) { + /* Skip ahead if start is not within service handles */ + if (next->attrs[0].handle <= start_handle) { + continue; + } + } +#endif + + for (size_t i = 0; i < svc->attr_count; i++) { + struct bt_gatt_attr *attr = &svc->attrs[i]; + + assert(attr->uuid); + + if (gatt_foreach_iter(attr, attr->handle, + start_handle, + end_handle, + uuid, attr_data, + &num_matches, + func, user_data) == BT_GATT_ITER_STOP) { + return; + } + } + } +} + +_LIB_IDF +void bt_gatt_foreach_attr_type(uint16_t start_handle, + uint16_t end_handle, + const struct bt_uuid *uuid, + const void *attr_data, + uint16_t num_matches, + bt_gatt_attr_func_t func, + void *user_data) +{ + LOG_DBG("GattForeachAttrType[%u][%u][%u]", start_handle, end_handle, num_matches); + + if (num_matches == 0) { + num_matches = UINT16_MAX; + } + + /* Iterate over dynamic db */ + foreach_attr_type_dyndb(start_handle, end_handle, uuid, attr_data, + num_matches, func, user_data); +} + +static uint8_t match_uuid(const struct bt_gatt_attr *attr, uint16_t handle, void *user_data) +{ + struct notify_data *data = user_data; + + LOG_DBG("MatchUuid[%u]", handle); + + data->attr = attr; + data->handle = handle; + + return BT_GATT_ITER_STOP; +} + +_IDF_ONLY +bool bt_gatts_find_attr_by_uuid(struct notify_data *found, const struct bt_uuid *uuid) +{ + LOG_DBG("GattsFindAttrByUuid[%u][%s]", found->handle, bt_uuid_str(uuid)); + + found->attr = NULL; + + bt_gatt_foreach_attr_type(found->handle, 0xffff, uuid, NULL, 1, match_uuid, found); + + if (found->attr) { + LOG_DBG("AttrFoundByUuid"); + } else { + LOG_WRN("AttrNotFoundByUuid"); + } + + return (found->attr ? true : false); +} + +_LIB_ONLY +struct bt_gatt_attr *bt_gatt_find_by_uuid(const struct bt_gatt_attr *attr, + uint16_t attr_count, + const struct bt_uuid *uuid) +{ + struct bt_gatt_attr *found = NULL; + uint16_t start_handle; + uint16_t end_handle; + + start_handle = bt_gatt_attr_get_handle(attr); + end_handle = (start_handle && attr_count) ? (start_handle + attr_count) : 0xffff; + + LOG_DBG("GattFindByUuid[%u][%u]", start_handle, end_handle); + + bt_gatt_foreach_attr_type(start_handle, end_handle, uuid, + NULL, 1, find_next, &found); + + return found; +} + +_LIB_IDF +ssize_t bt_gatt_attr_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, + void *buf, uint16_t buf_len, uint16_t offset, + const void *value, uint16_t value_len) +{ + assert(buf); + + LOG_DBG("GattAttrRd[%u][%u][%u]", buf_len, offset, value_len); + + if (offset > value_len) { + LOG_ERR("TooLargeOffset[%u][%u]", offset, value_len); + return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); + } + + return bt_le_nimble_gatts_attr_read(conn, attr, buf, buf_len, + offset, value, value_len); +} + +_LIB_ONLY +int bt_gatt_notify_cb(struct bt_conn *conn, struct bt_gatt_notify_params *params) +{ + assert(params); + + LOG_DBG("GattNtfCb[%u]", params->len); + + if (conn && conn->state != BT_CONN_CONNECTED) { + LOG_ERR("NotConn[%d]", __LINE__); + return -ENOTCONN; + } + + return bt_le_nimble_gatts_notify(conn, params); +} + +_LIB_IDF +int bt_gatt_indicate(struct bt_conn *conn, struct bt_gatt_indicate_params *params) +{ + assert(params); + assert(params->attr && params->attr->uuid); + + LOG_DBG("GattInd[%s]", bt_uuid_str(params->attr->uuid)); + + if (conn && conn->state != BT_CONN_CONNECTED) { + LOG_ERR("NotConn[%d]", __LINE__); + return -ENOTCONN; + } + + if ((!params->data ^ !params->len)) { + LOG_ERR("InvData[%p][%u]", params->data, params->len); + return -EINVAL; + } + + if (params->attr->uuid->type != BT_UUID_TYPE_16) { + LOG_ERR("InvUuidType[%u]", params->attr->uuid->type); + return -ENOTSUP; + } + + return bt_le_nimble_gatts_indicate(conn, params); +} + +_LIB_IDF +ssize_t bt_gatt_attr_read_service(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + void *buf, uint16_t len, + uint16_t offset) +{ + struct bt_uuid *uuid = attr->user_data; + + assert(uuid); + + LOG_DBG("GattAttrRdSvc[%s]", bt_uuid_str(uuid)); + + if (uuid->type == BT_UUID_TYPE_16) { + uint16_t uuid16 = sys_cpu_to_le16(BT_UUID_16(uuid)->val); + + return bt_gatt_attr_read(conn, attr, buf, len, offset, &uuid16, 2); + } + + /* BT_UUID_TYPE_32 is not expected for service UUIDs in LE Audio */ + assert(uuid->type == BT_UUID_TYPE_128); + + return bt_gatt_attr_read(conn, attr, buf, len, offset, BT_UUID_128(uuid)->val, 16); +} + +static uint8_t gatts_get_svc_handles(const struct bt_gatt_attr *attr, uint16_t handle, void *user_data) +{ + struct gatt_incl *include = user_data; + + LOG_DBG("GattsGetSvcHdl[%s][%u]", bt_uuid_str(attr->uuid), handle); + + /* Stop if attribute is a service */ + if (bt_uuid_cmp(attr->uuid, BT_UUID_GATT_PRIMARY) == 0 || + bt_uuid_cmp(attr->uuid, BT_UUID_GATT_SECONDARY) == 0) { + LOG_DBG("SvcAttr"); + return BT_GATT_ITER_STOP; + } + + include->end_handle = sys_cpu_to_le16(handle); + + return BT_GATT_ITER_CONTINUE; +} + +_LIB_ONLY +ssize_t bt_gatt_attr_read_included(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + void *buf, uint16_t len, + uint16_t offset) +{ + struct bt_gatt_attr *incl = NULL; + struct bt_uuid *uuid = NULL; + struct gatt_incl pdu = {0}; + uint8_t value_len; + uint16_t handle; + + incl = attr->user_data; + assert(incl); + assert(incl->user_data); + + handle = bt_gatt_attr_get_handle(incl); + uuid = incl->user_data; + + LOG_DBG("GattAttrRdInc[%u][%u][%u][%s]", + len, offset, handle, bt_uuid_str(uuid)); + + /* first attr points to the start handle */ + pdu.start_handle = sys_cpu_to_le16(handle); + value_len = sizeof(pdu.start_handle) + sizeof(pdu.end_handle); + + /* The Service UUID shall only be present when the UUID is a + * 16-bit Bluetooth UUID. + */ + if (uuid->type == BT_UUID_TYPE_16) { + pdu.uuid16 = sys_cpu_to_le16(BT_UUID_16(uuid)->val); + value_len += sizeof(pdu.uuid16); + } + + /* Lookup for service end handle */ + bt_gatt_foreach_attr(handle + 1, 0xffff, gatts_get_svc_handles, &pdu); + + return bt_gatt_attr_read(conn, attr, buf, len, offset, &pdu, value_len); +} + +_LIB_IDF +ssize_t bt_gatt_attr_read_chrc(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + void *buf, uint16_t len, + uint16_t offset) +{ + struct bt_gatt_chrc *chrc = attr->user_data; + struct gatt_chrc pdu; + uint8_t value_len; + + assert(chrc); + assert(chrc->uuid); + + pdu.properties = chrc->properties; + pdu.value_handle = sys_cpu_to_le16(bt_gatt_attr_value_handle(attr)); + + LOG_DBG("GattAttrRdChrc[%u][%u][%02x][%u][%s]", + len, offset, pdu.properties, pdu.value_handle, bt_uuid_str(chrc->uuid)); + + value_len = sizeof(pdu.properties) + sizeof(pdu.value_handle); + + if (chrc->uuid->type == BT_UUID_TYPE_16) { + pdu.uuid16 = sys_cpu_to_le16(BT_UUID_16(chrc->uuid)->val); + value_len += 2U; + } else if (chrc->uuid->type == BT_UUID_TYPE_128) { + memcpy(pdu.uuid, BT_UUID_128(chrc->uuid)->val, 16); + value_len += 16U; + } else { + LOG_ERR("UnsupportedUuidType[%u]", chrc->uuid->type); + return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY); + } + + return bt_gatt_attr_read(conn, attr, buf, len, offset, &pdu, value_len); +} + +static struct bt_gatt_ccc_cfg *gatts_find_ccc_cfg(const struct bt_conn *conn, + struct bt_gatt_ccc_managed_user_data *ccc) +{ + /* LOG_DBG("GattsFindCccCfg"); */ + + for (size_t i = 0; i < ARRAY_SIZE(ccc->cfg); i++) { + struct bt_gatt_ccc_cfg *cfg = &ccc->cfg[i]; + + if (conn) { + if (bt_conn_is_peer_addr_le(conn, cfg->id, &cfg->peer)) { + /* LOG_DBG("CccCfgFound[%u]", i); */ + return cfg; + } + } else if (bt_addr_le_eq(&cfg->peer, BT_ADDR_LE_ANY)) { + LOG_DBG("CccCfgNew[%u]", i); + return cfg; + } + } + + if (conn) { + /* LOG_DBG("CccCfgNotFound"); */ + } else { + LOG_ERR("CccNoFreeCfg"); + } + + return NULL; +} + +static void gatts_ccc_changed(const struct bt_gatt_attr *attr, + struct bt_gatt_ccc_managed_user_data *ccc) +{ + uint16_t value = 0x0000; + + for (size_t i = 0; i < ARRAY_SIZE(ccc->cfg); i++) { + if (ccc->cfg[i].value > value) { + value = ccc->cfg[i].value; + } + } + + /* LOG_DBG("GattsCccChanged[%04x][%04x]", ccc->value, value); */ + + if (ccc->value != value) { + ccc->value = value; + if (ccc->cfg_changed) { + ccc->cfg_changed(attr, value); + } + } +} + +static void gatts_clear_ccc_cfg(struct bt_gatt_ccc_cfg *cfg) +{ + /* LOG_DBG("GattsClearCccCfg"); */ + + bt_addr_le_copy(&cfg->peer, BT_ADDR_LE_ANY); + cfg->id = 0U; + cfg->value = 0U; +} + +_LIB_IDF +ssize_t bt_gatt_attr_read_ccc(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + void *buf, uint16_t len, + uint16_t offset) +{ + struct bt_gatt_ccc_managed_user_data *ccc; + const struct bt_gatt_ccc_cfg *cfg; + uint16_t value; + + assert(attr); + + ccc = attr->user_data; + assert(ccc); + + LOG_DBG("GattAttrRdCcc[%u][%u]", len, offset); + + cfg = gatts_find_ccc_cfg(conn, ccc); + if (cfg) { + value = sys_cpu_to_le16(cfg->value); + } else { + /* Default to disable if there is no cfg for the peer */ + value = 0x0000; + } + + return bt_gatt_attr_read(conn, attr, buf, len, offset, &value, sizeof(value)); +} + +_LIB_IDF +ssize_t bt_gatt_attr_write_ccc(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, + uint16_t offset, uint8_t flags) +{ + struct bt_gatt_ccc_managed_user_data *ccc; + struct bt_gatt_ccc_cfg *cfg; + bool value_changed; + bool new_entry; + uint16_t value; + + assert(attr); + + ccc = attr->user_data; + assert(ccc); + + LOG_DBG("GattAttrWrChrc[%u][%u][%02x]", len, offset, flags); + + if (offset) { + return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); + } + + if (len == 0 || len > sizeof(uint16_t)) { + return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + } + + if (len < sizeof(uint16_t)) { + value = *(uint8_t *)buf; + } else { + value = sys_get_le16(buf); + } + + new_entry = false; + + cfg = gatts_find_ccc_cfg(conn, ccc); + if (cfg == NULL) { + /* If there's no existing entry, but the new value is zero, + * we don't need to do anything, since a disabled CCC is + * behaviorally the same as no written CCC. + */ + if (value == 0) { + LOG_INF("CccValZero"); + return len; + } + + cfg = gatts_find_ccc_cfg(NULL, ccc); + if (cfg == NULL) { + return BT_GATT_ERR(BT_ATT_ERR_INSUFFICIENT_RESOURCES); + } + + bt_addr_le_copy(&cfg->peer, &conn->le.dst); + cfg->id = conn->id; + + new_entry = true; + } + + /* Confirm write if cfg is managed by application */ + if (ccc->cfg_write) { + ssize_t write = ccc->cfg_write(conn, attr, value); + + LOG_INF("CccCfgWr[%d]", write); + + if (write < 0) { + if (new_entry) { + gatts_clear_ccc_cfg(cfg); + } + return write; + } + + /* Accept size=1 for backwards compatibility */ + if (write != sizeof(value) && write != 1) { + if (new_entry) { + gatts_clear_ccc_cfg(cfg); + } + return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY); + } + } + + LOG_DBG("CccCfg[%u][%04x][%04x]", attr->handle, cfg->value, value); + + value_changed = (cfg->value != value); + cfg->value = value; + + /* Update cfg if don't match */ + if (cfg->value != ccc->value) { + gatts_ccc_changed(attr, ccc); + } + + if (value_changed) { + /* TBD: ccc store? */ + } + + /* Disabled CCC is the same as no configured CCC, so clear the entry */ + if (value == 0) { + gatts_clear_ccc_cfg(cfg); + } + + return len; +} + +_LIB_ONLY +bool bt_gatt_is_subscribed(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + uint16_t ccc_type) +{ + const struct bt_gatt_ccc_managed_user_data *ccc; + + assert(conn); + assert(attr && attr->uuid); + + LOG_DBG("GattIsSub[%04x][%s]", ccc_type, bt_uuid_str(attr->uuid)); + + if (conn->state != BT_CONN_CONNECTED) { + LOG_ERR("NotConn[%d]", __LINE__); + return false; + } + + /* Check if attribute is a characteristic declaration */ + if (bt_uuid_cmp(attr->uuid, BT_UUID_GATT_CHRC) == 0) { + uint8_t properties; + ssize_t len; + + if (attr->read == NULL) { + LOG_WRN("AttrRdCbNull"); + return false; + } + + /* The characteristic properties is the first byte of the attribute value */ + len = attr->read(NULL, attr, &properties, 1, 0); + if (len < 0) { + LOG_ERR("RdAttrFail[%zd]", len); + return false; + } + + if (len != 1) { + LOG_ERR("InvRdLen[%zd]", len); + return false; + } + + if (!(properties & (BT_GATT_CHRC_NOTIFY | BT_GATT_CHRC_INDICATE))) { + /* Characteristic doesn't support subscription */ + LOG_WRN("SubNotSupp[%02x]", properties); + return false; + } + + attr = bt_gatt_attr_next(attr); + assert(attr && attr->uuid); + + LOG_DBG("Attr[%s][%d]", bt_uuid_str(attr->uuid), __LINE__); + } + + /* Check if attribute is a characteristic value */ + if (bt_uuid_cmp(attr->uuid, BT_UUID_GATT_CCC)) { + attr = bt_gatt_attr_next(attr); + if (attr == NULL) { + return false; + } + + assert(attr->uuid); + LOG_DBG("Attr[%s][%d]", bt_uuid_str(attr->uuid), __LINE__); + } + + /* Find the CCC Descriptor */ + while (bt_uuid_cmp(attr->uuid, BT_UUID_GATT_CCC) && + /* Also stop if we leave the current characteristic definition */ + bt_uuid_cmp(attr->uuid, BT_UUID_GATT_CHRC) && + bt_uuid_cmp(attr->uuid, BT_UUID_GATT_PRIMARY) && + bt_uuid_cmp(attr->uuid, BT_UUID_GATT_SECONDARY)) { + attr = bt_gatt_attr_next(attr); + if (attr == NULL) { + return false; + } + } + + assert(attr->uuid); + + LOG_DBG("Attr[%s][%d]", bt_uuid_str(attr->uuid), __LINE__); + + if (bt_uuid_cmp(attr->uuid, BT_UUID_GATT_CCC)) { + return false; + } + + ccc = attr->user_data; + assert(ccc); + + /* Check if the connection is subscribed */ + for (size_t i = 0; i < ARRAY_SIZE(ccc->cfg); i++) { + const struct bt_gatt_ccc_cfg *cfg = &ccc->cfg[i]; + + LOG_DBG("CccCfg[%u][%04x]", i, ccc->cfg[i].value); + + if (bt_conn_is_peer_addr_le(conn, cfg->id, &cfg->peer) && + (ccc_type & ccc->cfg[i].value)) { + return true; + } + } + + return false; +} + +static int gatts_ccc_cfg_update(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + uint16_t value) +{ + struct bt_gatt_ccc_managed_user_data *ccc; + struct bt_gatt_ccc_cfg *cfg; + bool value_changed; + + ccc = attr->user_data; + assert(ccc); + + /* LOG_DBG("GattsCccCfgUpd[%04x]", value); */ + + cfg = gatts_find_ccc_cfg(conn, ccc); + if (cfg == NULL) { + /* If there's no existing entry, and the new notification value + * is zero, we don't need to do anything, since a disabled CCC + * is behaviorally the same as no written CCC. + */ + if (value == 0) { + LOG_INF("CccValZero"); + return 0; + } + + cfg = gatts_find_ccc_cfg(NULL, ccc); + if (cfg == NULL) { + return -ENOMEM; + } + + bt_addr_le_copy(&cfg->peer, &conn->le.dst); + cfg->id = conn->id; + } + + /* LOG_DBG("CccCfg[%u][%04x][%04x]", attr->handle, cfg->value, value); */ + + value_changed = (cfg->value != value); + cfg->value = value; + + if (value_changed) { + /* TBD: ccc store? */ + } + + if (cfg->value != ccc->value) { + gatts_ccc_changed(attr, ccc); + } + + /* Disabled CCC is the same as no configured CCC, so clear the entry */ + if (value == 0) { + gatts_clear_ccc_cfg(cfg); + } + + return 0; +} + +static struct bt_gatt_attr *gatts_ccc_attr_find(uint16_t ccc_handle) +{ + struct bt_gatt_service *svc = NULL; + struct bt_gatt_attr *attr = NULL; + + /* LOG_DBG("GattsCccAttrFind[%u]", ccc_handle); */ + + SYS_SLIST_FOR_EACH_CONTAINER(&gatt_db, svc, node) { + for (size_t i = 0; i < svc->attr_count; i++) { + if (svc->attrs[i].uuid->type == BT_UUID_TYPE_16 && + BT_UUID_16(svc->attrs[i].uuid)->val == BT_UUID_GATT_CCC_VAL && + svc->attrs[i].handle == ccc_handle) { + attr = &svc->attrs[i]; + /* LOG_DBG("CccAttrFound[%u][%u]", svc->attr_count, i); */ + break; + } + } + } + + return attr; +} + +_IDF_ONLY +int bt_gatts_sub_changed(uint16_t conn_handle, + uint16_t ccc_handle, + uint8_t cur_notify, + uint8_t cur_indicate, + uint8_t reason) +{ + const struct bt_gatt_attr *attr; + struct bt_conn *conn; + + /* LOG_DBG("GattsSubChanged[%u][%u][%u][%u][%02x]", */ + /* conn_handle, ccc_handle, cur_notify, cur_indicate, reason); */ + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL || conn->state != BT_CONN_CONNECTED) { + LOG_ERR("NotConn[%d]", __LINE__); + return -ENOTCONN; + } + + attr = gatts_ccc_attr_find(ccc_handle); + if (attr == NULL) { + /* May not be characteristic value declaration of LE Audio */ + return 0; + } + + /* TODO: + * Check the indication support for some characteristics, e.g., + * HAS Hearing Aid Preset Control Point characteristic. + */ + return gatts_ccc_cfg_update(conn, attr, (cur_indicate << 1) | cur_notify); +} + +_IDF_ONLY +int bt_gattc_disc_start_safe(uint16_t conn_handle) +{ + int err; + LOG_DBG("GattcDiscStart[%u]", conn_handle); + bt_le_host_lock(); + err = bt_le_nimble_gattc_disc_start(conn_handle); + bt_le_host_unlock(); + return err; +} + +_LIB_ONLY +int bt_gatt_discover(struct bt_conn *conn, struct bt_gatt_discover_params *params) +{ + assert(conn); + assert(params); + assert(params->start_handle && params->end_handle); + assert(params->start_handle <= params->end_handle); + + LOG_DBG("GattDisc[%u][%u]", params->start_handle, params->end_handle); + + if (conn->state != BT_CONN_CONNECTED) { + LOG_ERR("NotConn[%d]", __LINE__); + return -ENOTCONN; + } + + if (params->uuid && params->uuid->type != BT_UUID_TYPE_16) { + LOG_ERR("InvUuid[%s]", bt_uuid_str(params->uuid)); + return -ENOTSUP; + } + + return bt_le_nimble_gattc_discover(conn, params); +} + +static struct gattc_sub *gattc_sub_find(struct bt_conn *conn) +{ + /* LOG_DBG("GattcSubFind[%p]", conn); */ + + for (size_t i = 0; i < ARRAY_SIZE(subscriptions); i++) { + struct gattc_sub *sub = &subscriptions[i]; + + if (conn == NULL) { + if (bt_addr_le_eq(&sub->peer, BT_ADDR_LE_ANY)) { + LOG_DBG("SubNew[%u]", i); + return sub; + } + } else if (bt_conn_is_peer_addr_le(conn, sub->id, &sub->peer)) { + /* LOG_DBG("SubFound[%u]", i); */ + return sub; + } + } + + if (conn) { + /* LOG_DBG("SubNotFound"); */ + } else { + LOG_WRN("NoFreeSub"); + } + + return NULL; +} + +static struct gattc_sub *gattc_sub_add(struct bt_conn *conn) +{ + struct gattc_sub *sub; + + /* LOG_DBG("GattsSubAdd"); */ + + sub = gattc_sub_find(conn); + if (sub == NULL) { + sub = gattc_sub_find(NULL); + if (sub) { + bt_addr_le_copy(&sub->peer, &conn->le.dst); + sub->id = conn->id; + LOG_DBG("SubPeer[%s]", bt_addr_le_str(&sub->peer)); + } + } + + return sub; +} + +_IDF_ONLY +struct gattc_sub *bt_gattc_sub_find(struct bt_conn *conn) +{ + return gattc_sub_find(conn); +} + +static uint8_t gattc_ccc_discover_cb(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) +{ + struct bt_gatt_subscribe_params *sub_params = params->sub_params; + + LOG_DBG("GattcCccDiscCb[%u]", params->type); + + if (attr == NULL) { + memset(params, 0, sizeof(*params)); + + /* Notify with NULL data to complete unsubscribe */ + sub_params->notify(conn, sub_params, NULL, 0); + + return BT_GATT_ITER_STOP; + } + + if (params->type == BT_GATT_DISCOVER_DESCRIPTOR) { + memset(params, 0, sizeof(*params)); + + LOG_DBG("CccHdl[%u]", attr->handle); + + sub_params->ccc_handle = attr->handle; + + return BT_GATT_ITER_STOP; + } + + return BT_GATT_ITER_CONTINUE; +} + +static int gattc_ccc_discover(struct bt_conn *conn, struct bt_gatt_subscribe_params *params) +{ + static struct bt_uuid_16 ccc_uuid = { + .uuid.type = BT_UUID_TYPE_16, + .val = BT_UUID_GATT_CCC_VAL, + }; + + assert(params->disc_params); + + LOG_DBG("GattcCccDisc[%u][%u]", params->value_handle, params->end_handle); + + memset(params->disc_params, 0, sizeof(*params->disc_params)); + + params->disc_params->sub_params = params; + params->disc_params->uuid = &ccc_uuid.uuid; + params->disc_params->type = BT_GATT_DISCOVER_DESCRIPTOR; + params->disc_params->start_handle = params->value_handle; + params->disc_params->end_handle = params->end_handle; + params->disc_params->func = gattc_ccc_discover_cb; + + return bt_gatt_discover(conn, params->disc_params); +} + +static int gattc_write_ccc(struct bt_conn *conn, struct bt_gatt_subscribe_params *params) +{ + LOG_DBG("GattcWrCcc[%u][%04x]", params->ccc_handle, params->value); + + return bt_le_nimble_gattc_write_ccc(conn, params); +} + +_LIB_ONLY +int bt_gatt_subscribe(struct bt_conn *conn, struct bt_gatt_subscribe_params *params) +{ + struct bt_gatt_subscribe_params *tmp; + bool has_subscription = false; + struct gattc_sub *sub; + + assert(conn); + assert(params); + assert(params->notify); + assert(params->value); + assert(params->ccc_handle == BT_GATT_AUTO_DISCOVER_CCC_HANDLE || + (params->end_handle && params->disc_params)); + + LOG_DBG("GattcSub[%04x][%u][%u][%u]", + params->value, params->value_handle, params->ccc_handle, params->end_handle); + + if (conn->state != BT_CONN_CONNECTED) { + LOG_ERR("NotConn[%d]", __LINE__); + return -ENOTCONN; + } + + sub = gattc_sub_add(conn); + if (sub == NULL) { + return -ENOMEM; + } + +#if 0 + if (params->disc_params && + params->disc_params->func == gattc_ccc_discover_cb) { + /* Already in progress */ + LOG_ERR("GattcSubAlreadyInProgress[%u][%u][%u]", + params->ccc_handle, params->value_handle, params->end_handle); + return -EBUSY; + } +#endif + + /* Lookup existing subscriptions */ + SYS_SLIST_FOR_EACH_CONTAINER(&sub->list, tmp, node) { + /* Fail if entry already exists */ + if (tmp == params) { + LOG_WRN("GattcSubExist[%u][%04x]", params->ccc_handle, params->value); + return -EALREADY; + } + + /* Check if another subscription exists, i.e. multiple + * subscribe to the same characteristic value handle. + */ + if (tmp->value_handle == params->value_handle && + tmp->value >= params->value) { + LOG_INF("AnotherSubExist[%04x]", tmp->value); + has_subscription = true; + } + } + + /* Skip write if already subscribed */ + if (has_subscription == false) { + if (params->ccc_handle == BT_GATT_AUTO_DISCOVER_CCC_HANDLE) { + int err = gattc_ccc_discover(conn, params); + if (err) { + LOG_ERR("DiscCccFail[%d]", err); + return err; + } + } else { + /* Note: + * If the CCC handle is auto-discovered, and during the + * auto-discovery procedure, the indication/notification + * has already been enabled, no need to write CCC again. + */ + } + } + + /* Add subscription before write complete as some implementation + * were reported to send notification before reply to CCC write. + */ + sys_slist_append(&sub->list, ¶ms->node); + + /* Add this here to complete the discovery procedure directly. + * For Zephyr, this subscribe callback will be invoked after + * the response of updating CCCD (Write Request) is received. + */ + if (params->subscribe) { + params->subscribe(conn, 0, params); + } + + return 0; +} + +_LIB_ONLY +int bt_gatt_unsubscribe(struct bt_conn *conn, struct bt_gatt_subscribe_params *params) +{ + struct bt_gatt_subscribe_params *tmp; + bool has_subscription = false; + struct gattc_sub *sub; + bool found = false; + int err = 0; + + assert(conn); + assert(params); + + LOG_DBG("GattcUnsub[%04x][%u][%u][%u]", + params->value, params->value_handle, params->ccc_handle, params->end_handle); + + if (conn->state != BT_CONN_CONNECTED) { + LOG_ERR("NotConn[%d]", __LINE__); + return -ENOTCONN; + } + + sub = gattc_sub_find(conn); + if (sub == NULL) { + return -ENODEV; + } + + /* Lookup existing subscriptions */ + SYS_SLIST_FOR_EACH_CONTAINER(&sub->list, tmp, node) { + if (params == tmp) { + found = true; + continue; + } + + /* Check if there still remains any other subscription. + * I.e. subscribed with different sub_params but the same + * characteristic value handle. + */ + if (tmp->value_handle == params->value_handle) { + LOG_INF("AnotherSubFound"); + has_subscription = true; + } + } + + if (!found) { + /* Note: + * For unsubscribe, the -EINVAL will not be treated as error. + */ + /* LOG_DBG("GattcSubNotFound"); */ + return -EINVAL; + } + + if (has_subscription == false) { + params->value = 0x0000; + + err = gattc_write_ccc(conn, params); + if (err) { + LOG_ERR("WrCccFail[%d]", err); + return err; + } + } + + sys_slist_find_and_remove(&sub->list, ¶ms->node); + + if (sys_slist_is_empty(&sub->list)) { + LOG_DBG("SubListEmpty"); + bt_addr_le_copy(&sub->peer, BT_ADDR_LE_ANY); + } + + LOG_DBG("GattcUnsub[%u][%d]", has_subscription, err); + + if (has_subscription || err) { + /* Notify with NULL data to complete unsubscribe */ + params->notify(conn, params, NULL, 0); + } + + return 0; +} + +_LIB_IDF +int bt_gatt_read(struct bt_conn *conn, struct bt_gatt_read_params *params) +{ + assert(conn); + assert(params); + + LOG_DBG("GattRd[%u]", params->handle_count); + + if (conn->state != BT_CONN_CONNECTED) { + LOG_ERR("NotConn[%d]", __LINE__); + return -ENOTCONN; + } + + if (params->handle_count > 1) { + LOG_ERR("NotSuppToRdHdl[%u]", params->handle_count); + return -ENOTSUP; + } + + if (params->handle_count == 0) { + assert(params->by_uuid.uuid); + + if (params->by_uuid.uuid->type != BT_UUID_TYPE_16) { + LOG_ERR("InvUuid[%s]", bt_uuid_str(params->by_uuid.uuid)); + return -ENOTSUP; + } + } + + return bt_le_nimble_gattc_read(conn, params); +} + +_LIB_IDF +int bt_gatt_write(struct bt_conn *conn, struct bt_gatt_write_params *params) +{ + assert(conn); + assert(params); + assert(params->func); + assert(params->handle); + assert((!params->data ^ !params->length) == 0); + + LOG_DBG("GattWr[%u][%u][%u]", params->handle, params->length, params->offset); + + if (conn->state != BT_CONN_CONNECTED) { + LOG_ERR("NotConn[%d]", __LINE__); + return -ENOTCONN; + } + + if (params->offset != 0) { + LOG_ERR("PrepWrNotSupp[%u][%u]", params->handle, params->offset); + return -ENOTSUP; + } + + return bt_le_nimble_gattc_write(conn, params); +} + +_LIB_ONLY +int bt_gatt_write_without_response_cb(struct bt_conn *conn, uint16_t handle, + const void *data, uint16_t length, + bool sign, bt_gatt_complete_func_t func, + void *user_data) +{ + assert(conn); + assert(handle); + assert((!data ^ !length) == 0); + + ARG_UNUSED(func); + ARG_UNUSED(user_data); + + LOG_DBG("GattWrCmd[%u][%u][%u]", handle, length, sign); + + if (conn->state != BT_CONN_CONNECTED) { + LOG_ERR("NotConn[%d]", __LINE__); + return -ENOTCONN; + } + + if (sign) { + LOG_ERR("WrCmdNotSupp"); + return -ENOTSUP; + } + + return bt_le_nimble_gattc_write_without_rsp(conn, handle, data, length); +} + +_LIB_ONLY +void bt_le_acl_conn_disconnected_gatt_listener(uint16_t conn_handle) +{ + LOG_DBG("AclConnDisconnectedGattListener[%u]", conn_handle); + + bt_le_nimble_gatt_nrp_clear(conn_handle); + + /* Note: + * If the connection is disconnected, currently we will not delete + * the gatt client database. + * Hence after the connection is re-established, there is no need + * to re-discover the gatt client database which can save time. + * And the unsubscribe -> re-subscribe procedure is not needed. + */ +} + +void bt_le_gatt_handle_event(uint8_t *data, size_t data_len) +{ + assert(data && data_len); + + bt_le_nimble_gatt_handle_event(data, data_len); +} diff --git a/components/bt/esp_ble_audio/host/common/gatt.h b/components/bt/esp_ble_audio/host/common/gatt.h new file mode 100644 index 0000000000..289f44d801 --- /dev/null +++ b/components/bt/esp_ble_audio/host/common/gatt.h @@ -0,0 +1,382 @@ +/* + * SPDX-FileCopyrightText: 2015-2016 Intel Corporation + * SPDX-FileCopyrightText: 2023 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef HOST_COMMON_GATT_H_ +#define HOST_COMMON_GATT_H_ + +#include + +#include +#include + +#include "nimble/gatt/gatt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_le_gatt_mtu_change_event { + uint16_t conn_handle; + uint16_t mtu; +}; + +enum { + GATTC_DISC_TYPE_DUMMY, + GATTC_DISC_TYPE_SVC_BY_UUID, + GATTC_DISC_TYPE_INC_SVCS, + GATTC_DISC_TYPE_CHRS_BY_UUID, + GATTC_DISC_TYPE_ALL_CHRS, + GATTC_DISC_TYPE_ALL_DSCS, /* Not used for now */ + + GATTC_DISC_TYPE_MAX, +}; + +struct bt_le_gattc_discover_event { + uint8_t type; + uint16_t conn_handle; + uint16_t uuid; + struct bt_gatt_discover_params *params; +}; + +struct bt_le_gattc_disc_cmpl_event { + uint8_t status; + uint16_t conn_handle; +}; + +struct bt_le_gatts_subscribe_event { + uint16_t conn_handle; + uint16_t attr_handle; + uint8_t prev_notify : 1; + uint8_t cur_notify : 1; + uint8_t prev_indicate : 1; + uint8_t cur_indicate : 1; + uint8_t reason; +}; + +struct bt_le_gattc_notify_rx_event { + bool is_notify; + uint16_t conn_handle; + uint16_t attr_handle; + uint16_t len; + uint8_t *value; +}; + +struct bt_le_gatts_notify_tx_event { + bool is_notify; + uint16_t conn_handle; + uint16_t attr_handle; + uint8_t status; +}; + +struct bt_le_gatt_event_param { + uint8_t type; + + union { + struct bt_le_gatt_mtu_change_event gatt_mtu_change; + struct bt_le_gattc_discover_event gattc_discover; + struct bt_le_gattc_disc_cmpl_event gattc_disc_cmpl; + struct bt_le_gatts_subscribe_event gatts_subscribe; + struct bt_le_gattc_notify_rx_event gattc_notify_rx; + struct bt_le_gatts_notify_tx_event gatts_notify_tx; + }; +}; + +enum { + BT_LE_GATT_MTU_CHANGE_EVENT, + BT_LE_GATTC_DISCOVER_EVENT, + BT_LE_GATTC_DISC_CMPL_EVENT, + BT_LE_GATTS_SUBSCRIBE_EVENT, + BT_LE_GATTC_NOTIFY_RX_EVENT, + BT_LE_GATTS_NOTIFY_TX_EVENT, + + BT_LE_GATT_EVENT_MAX, +}; + +static inline char *audio_svc_uuid_to_str(uint16_t uuid) +{ + switch (uuid) { + case BT_UUID_GAP_VAL: + return "GAP"; + case BT_UUID_GATT_VAL: + return "GATT"; + case BT_UUID_AICS_VAL: + return "AICS"; + case BT_UUID_CAS_VAL: + return "CAS"; + case BT_UUID_VCS_VAL: + return "VCS"; + case BT_UUID_VOCS_VAL: + return "VOCS"; + case BT_UUID_CSIS_VAL: + return "CSIS"; + case BT_UUID_MCS_VAL: + return "MCS"; + case BT_UUID_GMCS_VAL: + return "GMCS"; + case BT_UUID_TBS_VAL: + return "TBS"; + case BT_UUID_GTBS_VAL: + return "GTBS"; + case BT_UUID_MICS_VAL: + return "MICS"; + case BT_UUID_ASCS_VAL: + return "ASCS"; + case BT_UUID_BASS_VAL: + return "BASS"; + case BT_UUID_PACS_VAL: + return "PACS"; + case BT_UUID_BASIC_AUDIO_VAL: + return "BASIC_AUDIO"; + case BT_UUID_HAS_VAL: + return "HAS"; + case BT_UUID_TMAS_VAL: + return "TMAS"; + case BT_UUID_PBA_VAL: + return "PBA"; + case BT_UUID_GMAS_VAL: + return "GMAS"; + case BT_UUID_OTS_VAL: + return "OTS"; + default: + return "Unknown"; + } +} + +static inline char *audio_chrc_uuid_to_str(uint16_t uuid) +{ + switch (uuid) { + case BT_UUID_OTS_FEATURE_VAL: + return "OTS_FEATURE"; + case BT_UUID_OTS_NAME_VAL: + return "OTS_NAME"; + case BT_UUID_OTS_TYPE_VAL: + return "OTS_TYPE"; + case BT_UUID_OTS_SIZE_VAL: + return "OTS_SIZE"; + case BT_UUID_OTS_FIRST_CREATED_VAL: + return "OTS_FIRST_CREATED"; + case BT_UUID_OTS_LAST_MODIFIED_VAL: + return "OTS_LAST_MODIFIED"; + case BT_UUID_OTS_ID_VAL: + return "OTS_ID"; + case BT_UUID_OTS_PROPERTIES_VAL: + return "OTS_PROPERTIES"; + case BT_UUID_OTS_ACTION_CP_VAL: + return "OTS_ACTION_CP"; + case BT_UUID_OTS_LIST_CP_VAL: + return "OTS_LIST_CP"; + case BT_UUID_OTS_LIST_FILTER_VAL: + return "OTS_LIST_FILTER"; + case BT_UUID_OTS_CHANGED_VAL: + return "OTS_CHANGED"; + case BT_UUID_GATT_TMAPR_VAL: + return "TMAP_ROLE"; + case BT_UUID_AICS_STATE_VAL: + return "AICS_STATE"; + case BT_UUID_AICS_GAIN_SETTINGS_VAL: + return "AICS_GAIN_SETTINGS"; + case BT_UUID_AICS_INPUT_TYPE_VAL: + return "AICS_INPUT_TYPE"; + case BT_UUID_AICS_INPUT_STATUS_VAL: + return "AICS_INPUT_STATUS"; + case BT_UUID_AICS_CONTROL_VAL: + return "AICS_CONTROL"; + case BT_UUID_AICS_DESCRIPTION_VAL: + return "AICS_DESCRIPTION"; + case BT_UUID_VCS_STATE_VAL: + return "VCS_STATE"; + case BT_UUID_VCS_CONTROL_VAL: + return "VCS_CONTROL"; + case BT_UUID_VCS_FLAGS_VAL: + return "VCS_FLAGS"; + case BT_UUID_VOCS_STATE_VAL: + return "VOCS_STATE"; + case BT_UUID_VOCS_LOCATION_VAL: + return "VOCS_LOCATION"; + case BT_UUID_VOCS_CONTROL_VAL: + return "VOCS_CONTROL"; + case BT_UUID_VOCS_DESCRIPTION_VAL: + return "VOCS_DESCRIPTION"; + case BT_UUID_CSIS_SIRK_VAL: + return "CSIS_SIRK"; + case BT_UUID_CSIS_SET_SIZE_VAL: + return "CSIS_SET_SIZE"; + case BT_UUID_CSIS_SET_LOCK_VAL: + return "CSIS_SET_LOCK"; + case BT_UUID_CSIS_RANK_VAL: + return "CSIS_RANK"; + case BT_UUID_MCS_PLAYER_NAME_VAL: + return "MCS_PLAYER_NAME"; + case BT_UUID_MCS_ICON_OBJ_ID_VAL: + return "MCS_ICON_OBJ_ID"; + case BT_UUID_MCS_ICON_URL_VAL: + return "MCS_ICON_URL"; + case BT_UUID_MCS_TRACK_CHANGED_VAL: + return "MCS_TRACK_CHANGED"; + case BT_UUID_MCS_TRACK_TITLE_VAL: + return "MCS_TRACK_TITLE"; + case BT_UUID_MCS_TRACK_DURATION_VAL: + return "MCS_TRACK_DURATION"; + case BT_UUID_MCS_TRACK_POSITION_VAL: + return "MCS_TRACK_POSITION"; + case BT_UUID_MCS_PLAYBACK_SPEED_VAL: + return "MCS_PLAYBACK_SPEED"; + case BT_UUID_MCS_SEEKING_SPEED_VAL: + return "MCS_SEEKING_SPEED"; + case BT_UUID_MCS_TRACK_SEGMENTS_OBJ_ID_VAL: + return "MCS_TRACK_SEGMENTS_OBJ_ID"; + case BT_UUID_MCS_CURRENT_TRACK_OBJ_ID_VAL: + return "MCS_CURRENT_TRACK_OBJ_ID"; + case BT_UUID_MCS_NEXT_TRACK_OBJ_ID_VAL: + return "MCS_NEXT_TRACK_OBJ_ID"; + case BT_UUID_MCS_PARENT_GROUP_OBJ_ID_VAL: + return "MCS_PARENT_GROUP_OBJ_ID"; + case BT_UUID_MCS_CURRENT_GROUP_OBJ_ID_VAL: + return "MCS_CURRENT_GROUP_OBJ_ID"; + case BT_UUID_MCS_PLAYING_ORDER_VAL: + return "MCS_PLAYING_ORDER"; + case BT_UUID_MCS_PLAYING_ORDERS_VAL: + return "MCS_PLAYING_ORDERS"; + case BT_UUID_MCS_MEDIA_STATE_VAL: + return "MCS_MEDIA_STATE"; + case BT_UUID_MCS_MEDIA_CONTROL_POINT_VAL: + return "MCS_MEDIA_CONTROL_POINT"; + case BT_UUID_MCS_MEDIA_CONTROL_OPCODES_VAL: + return "MCS_MEDIA_CONTROL_OPCODES"; + case BT_UUID_MCS_SEARCH_RESULTS_OBJ_ID_VAL: + return "MCS_SEARCH_RESULTS_OBJ_ID"; + case BT_UUID_MCS_SEARCH_CONTROL_POINT_VAL: + return "MCS_SEARCH_CONTROL_POINT"; + case BT_UUID_TBS_PROVIDER_NAME_VAL: + return "TBS_PROVIDER_NAME"; + case BT_UUID_TBS_UCI_VAL: + return "TBS_UCI"; + case BT_UUID_TBS_TECHNOLOGY_VAL: + return "TBS_TECHNOLOGY"; + case BT_UUID_TBS_URI_LIST_VAL: + return "TBS_URI_LIST"; + case BT_UUID_TBS_SIGNAL_STRENGTH_VAL: + return "TBS_SIGNAL_STRENGTH"; + case BT_UUID_TBS_SIGNAL_INTERVAL_VAL: + return "TBS_SIGNAL_INTERVAL"; + case BT_UUID_TBS_LIST_CURRENT_CALLS_VAL: + return "TBS_LIST_CURRENT_CALLS"; + case BT_UUID_CCID_VAL: + return "CCID"; + case BT_UUID_TBS_STATUS_FLAGS_VAL: + return "TBS_STATUS_FLAGS"; + case BT_UUID_TBS_INCOMING_URI_VAL: + return "TBS_INCOMING_URI"; + case BT_UUID_TBS_CALL_STATE_VAL: + return "TBS_CALL_STATE"; + case BT_UUID_TBS_CALL_CONTROL_POINT_VAL: + return "TBS_CALL_CONTROL_POINT"; + case BT_UUID_TBS_OPTIONAL_OPCODES_VAL: + return "TBS_OPTIONAL_OPCODES"; + case BT_UUID_TBS_TERMINATE_REASON_VAL: + return "TBS_TERMINATE_REASON"; + case BT_UUID_TBS_INCOMING_CALL_VAL: + return "TBS_INCOMING_CALL"; + case BT_UUID_TBS_FRIENDLY_NAME_VAL: + return "TBS_FRIENDLY_NAME"; + case BT_UUID_MICS_MUTE_VAL: + return "MICS_MUTE"; + case BT_UUID_ASCS_ASE_SNK_VAL: + return "ASCS_ASE_SNK"; + case BT_UUID_ASCS_ASE_SRC_VAL: + return "ASCS_ASE_SRC"; + case BT_UUID_ASCS_ASE_CP_VAL: + return "ASCS_ASE_CP"; + case BT_UUID_BASS_CONTROL_POINT_VAL: + return "BASS_CP"; + case BT_UUID_BASS_RECV_STATE_VAL: + return "BASS_RECV_STATE"; + case BT_UUID_PACS_SNK_VAL: + return "PACS_SNK"; + case BT_UUID_PACS_SNK_LOC_VAL: + return "PACS_SNK_LOC"; + case BT_UUID_PACS_SRC_VAL: + return "PACS_SRC"; + case BT_UUID_PACS_SRC_LOC_VAL: + return "PACS_SRC_LOC"; + case BT_UUID_PACS_AVAILABLE_CONTEXT_VAL: + return "PACS_AVAILABLE_CONTEXT"; + case BT_UUID_PACS_SUPPORTED_CONTEXT_VAL: + return "PACS_SUPPORTED_CONTEXT"; + case BT_UUID_HAS_HEARING_AID_FEATURES_VAL: + return "HAS_HEARING_AID_FEATURES"; + case BT_UUID_HAS_PRESET_CONTROL_POINT_VAL: + return "HAS_PRESET_CONTROL_POINT"; + case BT_UUID_HAS_ACTIVE_PRESET_INDEX_VAL: + return "HAS_ACTIVE_PRESET_INDEX"; + default: + return "Unknown"; + } +} + +struct gattc_sub { + uint8_t id; + bt_addr_le_t peer; + sys_slist_t list; +}; + +struct gatt_incl { + uint16_t start_handle; + uint16_t end_handle; + uint16_t uuid16; +} __attribute__((packed)); + +struct gatt_chrc { + uint8_t properties; + uint16_t value_handle; + union { + uint16_t uuid16; + uint8_t uuid[16]; + }; +} __attribute__((packed)); + +struct bt_att_write_req { + uint16_t handle; + uint8_t value[0]; +} __attribute__((packed)); + +struct notify_data { + const struct bt_gatt_attr *attr; + uint16_t handle; + int err; + uint16_t type; + union { + struct bt_gatt_notify_params *nfy_params; + struct bt_gatt_indicate_params *ind_params; + }; +}; + +struct bt_gatt_attr *bt_gatts_find_attr_by_handle(uint16_t handle); + +bool bt_gatts_find_attr_by_uuid(struct notify_data *found, + const struct bt_uuid *uuid); + +int bt_gatts_sub_changed(uint16_t conn_handle, + uint16_t ccc_handle, + uint8_t cur_notify, + uint8_t cur_indicate, + uint8_t reason); + +int bt_gattc_disc_start_safe(uint16_t conn_handle); + +struct gattc_sub *bt_gattc_sub_find(struct bt_conn *conn); + +void bt_le_acl_conn_disconnected_gatt_listener(uint16_t conn_handle); + +void bt_le_gatt_handle_event(uint8_t *data, size_t data_len); + +#ifdef __cplusplus +} +#endif + +#endif /* HOST_COMMON_GATT_H_ */ diff --git a/components/bt/esp_ble_audio/host/common/hci.c b/components/bt/esp_ble_audio/host/common/hci.c new file mode 100644 index 0000000000..4e808abf2d --- /dev/null +++ b/components/bt/esp_ble_audio/host/common/hci.c @@ -0,0 +1,72 @@ +/* + * SPDX-FileCopyrightText: 2017-2025 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2015-2016 Intel Corporation + * SPDX-FileCopyrightText: 2025 NXP + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include <../host/hci_core.h> +#include <../host/iso_internal.h> + +#include "common/host.h" + +struct cmd_data { + /** HCI status of the command completion */ + uint8_t status; + + /** The command OpCode that the buffer contains */ + uint16_t opcode; + + /** The state to update when command completes with success. */ + struct bt_hci_cmd_state_set *state; +}; + +static struct cmd_data cmd_data; + +#define cmd(buf) (&cmd_data) + +NET_BUF_POOL_FIXED_DEFINE(hci_cmd_pool, 1, 255, 0, NULL); + +_IDF_ONLY +struct net_buf *bt_hci_cmd_create(uint16_t opcode, uint8_t param_len) +{ + struct bt_hci_cmd_hdr *hdr; + struct net_buf *buf; + + LOG_DBG("HciCmdCreate[%04x][%u]", opcode, param_len); + + buf = net_buf_alloc(&hci_cmd_pool, K_NO_WAIT); + assert(buf); + + net_buf_reserve(buf, BT_BUF_RESERVE); + + cmd(buf)->opcode = opcode; + cmd(buf)->state = NULL; + + hdr = net_buf_add(buf, sizeof(*hdr)); + hdr->opcode = sys_cpu_to_le16(opcode); + hdr->param_len = param_len; + + return buf; +} + +_IDF_ONLY +int bt_hci_cmd_send_sync(uint16_t opcode, + struct net_buf *buf, + struct net_buf **rsp) +{ + LOG_DBG("HciCmdSendSync[%04x]", opcode); + + return bt_le_nimble_iso_cmd_send_sync(opcode, buf, rsp); +} diff --git a/components/bt/esp_ble_audio/host/common/host.c b/components/bt/esp_ble_audio/host/common/host.c new file mode 100644 index 0000000000..deb07b6119 --- /dev/null +++ b/components/bt/esp_ble_audio/host/common/host.c @@ -0,0 +1,92 @@ +/* + * SPDX-FileCopyrightText: 2015-2016 Intel Corporation + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include + +#include "common/host.h" +#include "common/app/gap.h" +#include "common/app/gatt.h" + +static struct k_mutex host_mutex; + +#define TIMEOUT_MS (5000 / portTICK_PERIOD_MS) /* 5s */ + +#if HOST_LOCK_DEBUG +void bt_le_host_lock_debug(const char *func, int line) +#else /* HOST_LOCK_DEBUG */ +void bt_le_host_lock(void) +#endif /* HOST_LOCK_DEBUG */ +{ + /* LOG_DBG("%s: %d", func, line); */ + k_mutex_lock(&host_mutex, TIMEOUT_MS); +} + +#if HOST_LOCK_DEBUG +void bt_le_host_unlock_debug(const char *func, int line) +#else /* HOST_LOCK_DEBUG */ +void bt_le_host_unlock(void) +#endif /* HOST_LOCK_DEBUG */ +{ + /* LOG_DBG("%s: %d", func, line); */ + k_mutex_unlock(&host_mutex); +} + +int bt_le_host_init(void) +{ + int err; + + LOG_DBG("HostInit"); + + k_mutex_create(&host_mutex); + +#if CONFIG_BT_OTS || CONFIG_BT_OTS_CLIENT + err = bt_le_l2cap_init(); + if (err) { + goto delete_mutex; + } +#endif /* CONFIG_BT_OTS || CONFIG_BT_OTS_CLIENT */ + + err = bt_le_iso_init(); + if (err) { + goto deinit_l2cap; + } + + err = bt_le_iso_task_init(); + if (err) { + goto deinit_iso; + } + + return 0; + +deinit_iso: + bt_le_iso_deinit(); +deinit_l2cap: +#if CONFIG_BT_OTS || CONFIG_BT_OTS_CLIENT + bt_le_l2cap_deinit(); +delete_mutex: +#endif /* CONFIG_BT_OTS || CONFIG_BT_OTS_CLIENT */ + k_mutex_delete(&host_mutex); + + return err; +} + +void bt_le_host_deinit(void) +{ + LOG_DBG("HostDeinit"); + +#if CONFIG_BT_OTS || CONFIG_BT_OTS_CLIENT + bt_le_l2cap_deinit(); +#endif /* CONFIG_BT_OTS || CONFIG_BT_OTS_CLIENT */ + bt_le_iso_deinit(); + bt_le_iso_task_deinit(); + + k_mutex_delete(&host_mutex); +} diff --git a/components/bt/esp_ble_audio/host/common/host.h b/components/bt/esp_ble_audio/host/common/host.h new file mode 100644 index 0000000000..80b4bc1543 --- /dev/null +++ b/components/bt/esp_ble_audio/host/common/host.h @@ -0,0 +1,50 @@ +/* + * SPDX-FileCopyrightText: 2015-2016 Intel Corporation + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef HOST_COMMON_HOST_H_ +#define HOST_COMMON_HOST_H_ + +#include + +#include +#include +#include + +#include "common/adv.h" +#include "common/conn.h" +#include "common/iso.h" +#include "common/l2cap.h" +#include "common/scan.h" +#include "common/gatt.h" +#include "common/task.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define HOST_LOCK_DEBUG 0 + +#if HOST_LOCK_DEBUG +void bt_le_host_lock_debug(const char *func, int line); +void bt_le_host_unlock_debug(const char *func, int line); + +#define bt_le_host_lock(...) bt_le_host_lock_debug(__func__, __LINE__) +#define bt_le_host_unlock(...) bt_le_host_unlock_debug(__func__, __LINE__) +#else /* HOST_LOCK_DEBUG */ +void bt_le_host_lock(void); +void bt_le_host_unlock(void); +#endif /* HOST_LOCK_DEBUG */ + +int bt_le_host_init(void); + +void bt_le_host_deinit(void); + +#ifdef __cplusplus +} +#endif + +#endif /* HOST_COMMON_HOST_H_ */ diff --git a/components/bt/esp_ble_audio/host/common/init.c b/components/bt/esp_ble_audio/host/common/init.c new file mode 100644 index 0000000000..c2e550e4bb --- /dev/null +++ b/components/bt/esp_ble_audio/host/common/init.c @@ -0,0 +1,2146 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "sdkconfig.h" +#include "esp_system.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include <../host/conn_internal.h> +#include <../host/hci_core.h> + +#include "nimble/init.h" + +#include "../../../lib/include/audio.h" + +#include "esp_ble_audio_common_api.h" + +_Static_assert(sizeof(struct bt_le_audio_start_info) == + sizeof(esp_ble_audio_start_info_t), + "Mismatch LE Audio start info structure"); +#if CONFIG_BT_CSIP_SET_MEMBER +_Static_assert(offsetof(struct bt_le_audio_start_info, csis_insts) == + offsetof(esp_ble_audio_start_info_t, csis_insts), + "Mismatch LE Audio start info structure"); +#endif /* CONFIG_BT_CSIP_SET_MEMBER */ + +#if CONFIG_BT_TBS +_Static_assert(CONFIG_BT_TBS_BEARER_COUNT == 0, "Currently only support GTBS"); +#endif /* CONFIG_BT_TBS */ + +#if CONFIG_BT_OTS && !CONFIG_BT_OTS_SECONDARY_SVC +_Static_assert(0, "Currently only support using OTS as Secondary Service"); +#endif /* CONFIG_BT_OTS && !CONFIG_BT_OTS_SECONDARY_SVC */ + +static const uint16_t ext_structs[] = { + /* gatt.h */ + sizeof(struct bt_gatt_attr), + sizeof(struct bt_gatt_ccc_managed_user_data), + sizeof(struct bt_gatt_notify_params), + sizeof(struct bt_gatt_indicate_params), + sizeof(struct bt_gatt_discover_params), + sizeof(struct bt_gatt_read_params), + sizeof(struct bt_gatt_write_params), + sizeof(struct bt_gatt_subscribe_params), + /* iso.h */ + sizeof(struct bt_iso_chan), + sizeof(struct bt_iso_chan_io_qos), + sizeof(struct bt_iso_chan_qos), + sizeof(struct bt_iso_cig_param), + sizeof(struct bt_iso_big_create_param), + sizeof(struct bt_iso_big_sync_param), + sizeof(struct bt_iso_biginfo), + sizeof(struct bt_iso_chan_ops), + sizeof(struct bt_iso_server), + sizeof(struct bt_iso_unicast_info), + sizeof(struct bt_iso_info), + /* ots.h */ + sizeof(struct bt_ots_obj_metadata), + sizeof(struct bt_ots_client), + /* aics.h */ + sizeof(struct bt_aics_register_param), + sizeof(struct bt_aics_cb), + /* audio.h */ + sizeof(struct bt_audio_codec_cap), + sizeof(struct bt_audio_codec_cfg), + /* bap.h */ + sizeof(struct bt_bap_qos_cfg), + sizeof(struct bt_bap_qos_cfg_pref), + sizeof(struct bt_bap_ascs_rsp), + sizeof(struct bt_bap_bass_subgroup), + sizeof(struct bt_bap_scan_delegator_recv_state), + sizeof(struct bt_bap_scan_delegator_cb), + sizeof(struct bt_bap_ep_info), + sizeof(struct bt_bap_stream), + sizeof(struct bt_bap_stream_ops), + sizeof(struct bt_bap_unicast_server_cb), + sizeof(struct bt_bap_unicast_group_param), + sizeof(struct bt_bap_unicast_client_cb), + sizeof(struct bt_bap_broadcast_source_stream_param), + sizeof(struct bt_bap_broadcast_source_param), + sizeof(struct bt_bap_broadcast_sink_cb), + sizeof(struct bt_bap_scan_delegator_add_src_param), + sizeof(struct bt_bap_scan_delegator_mod_src_param), + sizeof(struct bt_bap_broadcast_assistant_cb), + sizeof(struct bt_bap_broadcast_assistant_add_src_param), + sizeof(struct bt_bap_broadcast_assistant_mod_src_param), + /* cap.h */ + sizeof(struct bt_cap_initiator_cb), + sizeof(struct bt_cap_stream), + sizeof(struct bt_cap_unicast_audio_start_stream_param), + sizeof(struct bt_cap_initiator_broadcast_create_param), + sizeof(struct bt_cap_commander_cb), + sizeof(struct bt_cap_commander_broadcast_reception_start_member_param), + /* ccp.h */ + sizeof(struct bt_ccp_call_control_client_bearers), + sizeof(struct bt_ccp_call_control_client_cb), + /* csip.h */ + sizeof(struct bt_csip_set_member_register_param), + sizeof(struct bt_csip_set_coordinator_set_member), + /* mcc.h */ + sizeof(struct bt_mcc_cb), + /* media_proxy.h */ + sizeof(struct media_proxy_ctrl_cbs), + sizeof(struct media_proxy_pl_calls), + /* micp.h */ + sizeof(struct bt_micp_mic_dev_register_param), + sizeof(struct bt_micp_mic_ctlr_cb), + /* tbs.h */ + sizeof(struct bt_tbs_register_param), + sizeof(struct bt_tbs_client_cb), + /* vcp.h */ + sizeof(struct bt_vcp_vol_rend_register_param), + sizeof(struct bt_vcp_vol_ctlr_cb), + /* vocs.h */ + sizeof(struct bt_vocs_cb), + /* buf.h */ + sizeof(struct net_buf), + sizeof(struct net_buf_simple), + sizeof(struct net_buf_pool), + /* Others */ + sizeof(struct bt_dev), + sizeof(struct bt_le_ext_adv), + sizeof(struct bt_le_ext_adv_info), + sizeof(struct bt_le_per_adv_sync), + sizeof(struct bt_conn), + sizeof(struct k_work), + sizeof(struct k_mutex), + sizeof(struct bt_data), + sizeof(struct bt_le_per_adv_sync_synced_info), + sizeof(struct bt_le_per_adv_sync_term_info), + sizeof(struct bt_le_per_adv_sync_recv_info), + sizeof(struct bt_le_per_adv_sync_cb), + sizeof(struct bt_le_per_adv_sync_info), + sizeof(struct bt_le_scan_param), + sizeof(struct bt_le_scan_recv_info), + sizeof(struct bt_le_scan_cb), + sizeof(struct bt_bond_info), +}; + +#define LEA_VERSION (0x20260412) + +struct lib_ext_cfgs { + /* BLE */ + bool config_past_sender; + bool config_past_receiver; + uint8_t config_max_conn; + uint8_t config_max_paired; + uint16_t config_max_attr_len; + uint16_t config_l2cap_tx_mtu; + uint16_t config_l2cap_rx_mtu; + + /* ISO */ + bool config_iso_test_params; + uint8_t config_iso_max_chan; + + /* Audio (Audio Profiles Related) */ + bool config_audio_tx; + bool config_audio_rx; + uint16_t config_audio_notify_retry_delay; + + /* AICS (Audio Input Control Service) */ + bool config_aics; + uint8_t config_aics_max_instance_count; + uint16_t config_aics_max_input_description_size; + bool config_aics_client; + uint8_t config_aics_client_max_instance_count; + + /* ASCS (Audio Stream Control Service) */ + bool config_ascs_ase_snk; + uint8_t config_ascs_max_ase_snk_count; + bool config_ascs_ase_src; + uint8_t config_ascs_max_ase_src_count; + uint8_t config_ascs_max_active_ases; + uint16_t config_ascs_iso_disconnect_delay; + + /* BAP (Basic Audio Profile) */ + bool config_bap_unicast_server; + bool config_bap_unicast_client; + uint8_t config_bap_unicast_client_group_count; + uint8_t config_bap_unicast_client_group_stream_count; + bool config_bap_unicast_client_ase_snk; + uint8_t config_bap_unicast_client_ase_snk_count; + bool config_bap_unicast_client_ase_src; + uint8_t config_bap_unicast_client_ase_src_count; + bool config_bap_broadcast_sink; + uint8_t config_bap_broadcast_snk_count; + uint8_t config_bap_broadcast_snk_subgroup_count; + uint8_t config_bap_broadcast_snk_stream_count; + bool config_bap_broadcast_source; + uint8_t config_bap_broadcast_src_count; + uint8_t config_bap_broadcast_src_subgroup_count; + uint8_t config_bap_broadcast_src_stream_count; + bool config_bap_scan_delegator; + uint8_t config_bap_scan_delegator_recv_state_count; + bool config_bap_broadcast_assistant; + uint8_t config_bap_broadcast_assistant_recv_state_count; + uint8_t config_bap_bass_max_subgroups; + uint8_t config_audio_codec_cfg_max_data_size; + uint8_t config_audio_codec_cfg_max_metadata_size; + uint8_t config_audio_codec_cap_max_data_size; + uint8_t config_audio_codec_cap_max_metadata_size; + bool config_bap_debug_stream_data; + bool config_bap_debug_stream_seq_num; + + /* CAP (Common Audio Profile) */ + bool config_cap_acceptor; + bool config_cap_acceptor_set_member; + bool config_cap_initiator; + bool config_cap_initiator_unicast; + bool config_cap_commander; + bool config_cap_handover; + + /* CCP (Call Control Profile) */ + bool config_ccp_call_control_client; + uint8_t config_ccp_call_control_client_bearer_count; + bool config_ccp_call_control_server; + uint8_t config_ccp_call_control_server_bearer_count; + uint16_t config_ccp_call_control_server_provider_name_max_len; + + /* CSIP (Coordinated Set Identification Profile) */ + bool config_csip_set_member; + uint8_t config_csip_set_member_max_instance_count; + bool config_csip_set_member_enc_sirk_support; + bool config_csip_set_member_sirk_notifiable; + bool config_csip_set_member_size_notifiable; + bool config_csip_set_member_test_sample_data; + bool config_csip_set_coordinator; + uint8_t config_csip_set_coordinator_max_csis_instances; + bool config_csip_set_coordinator_enc_sirk_support; + bool config_csip_set_coordinator_test_sample_data; + + /* GMAP (Gaming Audio Profile) */ + bool config_gmap; + bool config_gmap_ugg_supported; + bool config_gmap_ugt_supported; + bool config_gmap_bgs_supported; + bool config_gmap_bgr_supported; + + /* HAS (Hearing Access Service) */ + bool config_has; + uint8_t config_has_preset_count; + bool config_has_features_notifiable; + bool config_has_preset_support; + bool config_has_preset_name_dynamic; + bool config_has_preset_control_point_notifiable; + bool config_has_active_preset_index; + bool config_has_client; + + /* MCS (Media Control Service) */ + bool config_mcs; + bool config_mcc; + uint8_t config_mcc_media_player_name_max; + uint8_t config_mcc_icon_url_max; + uint8_t config_mcc_track_title_max; + uint8_t config_mcc_segment_name_max; + bool config_mcc_ots; + uint16_t config_mcc_otc_obj_buf_size; + uint16_t config_mcc_total_obj_content_mem; + uint16_t config_mcc_track_segs_max_cnt; + uint16_t config_mcc_group_records_max; + bool config_mcc_read_media_player_icon_url; + bool config_mcc_read_track_title; + bool config_mcc_read_track_title_enable_subscription; + bool config_mcc_read_track_duration; + bool config_mcc_read_track_position; + bool config_mcc_set_track_position; + bool config_mcc_read_playback_speed; + bool config_mcc_set_playback_speed; + bool config_mcc_read_seeking_speed; + bool config_mcc_read_playing_order; + bool config_mcc_set_playing_order; + bool config_mcc_read_playing_order_supported; + bool config_mcc_read_media_state; + bool config_mcc_set_media_control_point; + bool config_mcc_read_media_control_point_opcodes_supported; + bool config_mcc_read_content_control_id; + + /* MCTL (Media Control) */ + bool config_mctl; + bool config_mctl_local_player_control; + bool config_mctl_local_player_local_control; + bool config_mctl_local_player_remote_control; + bool config_mctl_remote_player_control; + bool config_mctl_remote_player_control_objects; + + /* MICP (Microphone Control Profile) */ + bool config_micp_mic_dev; + bool config_micp_mic_dev_aics; + uint8_t config_micp_mic_dev_aics_instance_count; + bool config_micp_mic_ctlr; + bool config_micp_mic_ctlr_aics; + uint8_t config_micp_mic_ctlr_max_aics_inst; + + /* MPL (Media player) */ + bool config_mpl; + char *config_mpl_media_player_name; + uint8_t config_mpl_media_player_name_max; + char *config_mpl_icon_url; + uint8_t config_mpl_icon_url_max; + uint8_t config_mpl_track_title_max; + uint8_t config_mpl_segment_name_max; + uint8_t config_mpl_group_title_max; + bool config_mpl_objects; + uint16_t config_mpl_max_obj_size; + uint16_t config_mpl_icon_bitmap_size; + uint16_t config_mpl_track_max_size; + + /* PACS (Published Audio Capabilities Service) */ + bool config_pac_snk; + bool config_pac_snk_notifiable; + bool config_pac_snk_loc; + bool config_pac_snk_loc_writeable; + bool config_pac_snk_loc_notifiable; + bool config_pac_src; + bool config_pac_src_notifiable; + bool config_pac_src_loc; + bool config_pac_src_loc_writeable; + bool config_pac_src_loc_notifiable; + bool config_pacs_supported_context_notifiable; + + /* PBP (Public Broadcast Profile) */ + bool config_pbp; + + /* TBS (Telephone Bearer Service) */ + bool config_tbs; + uint8_t config_tbs_supported_features; + uint8_t config_tbs_max_calls; + uint8_t config_tbs_bearer_count; + uint16_t config_tbs_max_scheme_list_length; + bool config_tbs_client; + bool config_tbs_client_gtbs; + bool config_tbs_client_tbs; + uint8_t config_tbs_client_max_calls; + uint8_t config_tbs_client_max_tbs_instances; + bool config_tbs_client_bearer_provider_name; + bool config_tbs_client_bearer_uci; + bool config_tbs_client_bearer_technology; + bool config_tbs_client_bearer_uri_schemes_supported_list; + bool config_tbs_client_bearer_signal_strength; + bool config_tbs_client_read_bearer_signal_interval; + bool config_tbs_client_set_bearer_signal_interval; + bool config_tbs_client_bearer_list_current_calls; + bool config_tbs_client_ccid; + bool config_tbs_client_incoming_uri; + bool config_tbs_client_status_flags; + bool config_tbs_client_cp_procedures; + bool config_tbs_client_accept_call; + bool config_tbs_client_terminate_call; + bool config_tbs_client_hold_call; + bool config_tbs_client_retrieve_call; + bool config_tbs_client_originate_call; + bool config_tbs_client_join_calls; + bool config_tbs_client_optional_opcodes; + bool config_tbs_client_incoming_call; + bool config_tbs_client_call_friendly_name; + uint8_t config_tbs_max_uri_length; + uint16_t config_tbs_max_provider_name_length; + + /* TMAP (Telephony and Media Audio Profile) */ + bool config_tmap_cg_supported; + bool config_tmap_ct_supported; + bool config_tmap_ums_supported; + bool config_tmap_umr_supported; + bool config_tmap_bms_supported; + bool config_tmap_bmr_supported; + bool config_tmap; + + /* VCP (Volume Control Profile) */ + bool config_vcp_vol_rend; + bool config_vcp_vol_rend_vocs; + uint8_t config_vcp_vol_rend_vocs_instance_count; + bool config_vcp_vol_rend_aics; + uint8_t config_vcp_vol_rend_aics_instance_count; + bool config_vcp_vol_rend_vol_flags_notifiable; + bool config_vcp_vol_ctlr; + bool config_vcp_vol_ctlr_vocs; + uint8_t config_vcp_vol_ctlr_max_vocs_inst; + bool config_vcp_vol_ctlr_aics; + uint8_t config_vcp_vol_ctlr_max_aics_inst; + + /* VOCS (Volume Control Service) */ + bool config_vocs; + uint8_t config_vocs_max_instance_count; + uint16_t config_vocs_max_output_description_size; + bool config_vocs_client; + uint8_t config_vocs_client_max_instance_count; + + /* OTS (Object Transfer Service) */ + bool config_ots; + bool config_ots_client; + uint8_t config_ots_obj_max_name_len; + + /* Version Check */ + uint32_t config_version; +}; + +static const struct lib_ext_cfgs ext_cfgs = { + /* BLE */ + .config_past_sender = CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER, + .config_past_receiver = CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER, + .config_max_conn = CONFIG_BT_MAX_CONN, + .config_max_paired = CONFIG_BT_MAX_PAIRED, + .config_max_attr_len = 251, + .config_l2cap_tx_mtu = 251, + .config_l2cap_rx_mtu = 251, + + /* ISO */ +#if CONFIG_BT_ISO_TEST_PARAMS + .config_iso_test_params = CONFIG_BT_ISO_TEST_PARAMS, +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ +#if CONFIG_BT_ISO_MAX_CHAN + .config_iso_max_chan = CONFIG_BT_ISO_MAX_CHAN, +#endif /* CONFIG_BT_ISO_MAX_CHAN */ + + /* Audio (Audio Profiles Related) */ +#if CONFIG_BT_AUDIO_TX + .config_audio_tx = CONFIG_BT_AUDIO_TX, +#endif /* CONFIG_BT_AUDIO_TX */ +#if CONFIG_BT_AUDIO_RX + .config_audio_rx = CONFIG_BT_AUDIO_RX, +#endif /* CONFIG_BT_AUDIO_RX */ + .config_audio_notify_retry_delay = 20, + + /* AICS (Audio Input Control Service) */ +#if CONFIG_BT_AICS + .config_aics = CONFIG_BT_AICS, + .config_aics_max_instance_count = CONFIG_BT_AICS_MAX_INSTANCE_COUNT, + .config_aics_max_input_description_size = CONFIG_BT_AICS_MAX_INPUT_DESCRIPTION_SIZE, +#endif /* CONFIG_BT_AICS */ +#if CONFIG_BT_AICS_CLIENT + .config_aics_client = CONFIG_BT_AICS_CLIENT, + .config_aics_client_max_instance_count = CONFIG_BT_AICS_CLIENT_MAX_INSTANCE_COUNT, +#endif /* CONFIG_BT_AICS_CLIENT */ + + /* ASCS (Audio Stream Control Service) */ +#if CONFIG_BT_ASCS +#if CONFIG_BT_ASCS_ASE_SNK + .config_ascs_ase_snk = CONFIG_BT_ASCS_ASE_SNK, + .config_ascs_max_ase_snk_count = CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT, +#endif /* CONFIG_BT_ASCS_ASE_SNK */ +#if CONFIG_BT_ASCS_ASE_SRC + .config_ascs_ase_src = CONFIG_BT_ASCS_ASE_SRC, + .config_ascs_max_ase_src_count = CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT, +#endif /* CONFIG_BT_ASCS_ASE_SRC */ + .config_ascs_max_active_ases = CONFIG_BT_ASCS_MAX_ACTIVE_ASES, + /* .config_ascs_iso_disconnect_delay = CONFIG_BT_ASCS_ISO_DISCONNECT_DELAY, */ + .config_ascs_iso_disconnect_delay = 0, +#endif /* CONFIG_BT_ASCS */ + + /* BAP (Basic Audio Profile) */ +#if CONFIG_BT_BAP_UNICAST_SERVER + .config_bap_unicast_server = CONFIG_BT_BAP_UNICAST_SERVER, +#endif /* CONFIG_BT_BAP_UNICAST_SERVER */ +#if CONFIG_BT_BAP_UNICAST_CLIENT + .config_bap_unicast_client = CONFIG_BT_BAP_UNICAST_CLIENT, + .config_bap_unicast_client_group_count = CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_COUNT, + .config_bap_unicast_client_group_stream_count = CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT, +#if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK + .config_bap_unicast_client_ase_snk = CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK, + .config_bap_unicast_client_ase_snk_count = CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT, +#endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK */ +#if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC + .config_bap_unicast_client_ase_src = CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC, + .config_bap_unicast_client_ase_src_count = CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT, +#endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC */ +#endif /* CONFIG_BT_BAP_UNICAST_CLIENT */ +#if CONFIG_BT_BAP_BROADCAST_SINK + .config_bap_broadcast_sink = CONFIG_BT_BAP_BROADCAST_SINK, + .config_bap_broadcast_snk_count = CONFIG_BT_BAP_BROADCAST_SNK_COUNT, + .config_bap_broadcast_snk_subgroup_count = CONFIG_BT_BAP_BROADCAST_SNK_SUBGROUP_COUNT, + .config_bap_broadcast_snk_stream_count = CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT, +#endif /* CONFIG_BT_BAP_BROADCAST_SINK */ +#if CONFIG_BT_BAP_BROADCAST_SOURCE + .config_bap_broadcast_source = CONFIG_BT_BAP_BROADCAST_SOURCE, + .config_bap_broadcast_src_count = CONFIG_BT_BAP_BROADCAST_SRC_COUNT, + .config_bap_broadcast_src_subgroup_count = CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT, + .config_bap_broadcast_src_stream_count = CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT, +#endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */ +#if CONFIG_BT_BAP_SCAN_DELEGATOR + .config_bap_scan_delegator = CONFIG_BT_BAP_SCAN_DELEGATOR, + .config_bap_scan_delegator_recv_state_count = CONFIG_BT_BAP_SCAN_DELEGATOR_RECV_STATE_COUNT, +#endif /* CONFIG_BT_BAP_SCAN_DELEGATOR */ +#if CONFIG_BT_BAP_BROADCAST_ASSISTANT + .config_bap_broadcast_assistant = CONFIG_BT_BAP_BROADCAST_ASSISTANT, + .config_bap_broadcast_assistant_recv_state_count = CONFIG_BT_BAP_BROADCAST_ASSISTANT_RECV_STATE_COUNT, +#endif /* CONFIG_BT_BAP_BROADCAST_ASSISTANT */ + .config_bap_bass_max_subgroups = CONFIG_BT_BAP_BASS_MAX_SUBGROUPS, + .config_audio_codec_cfg_max_data_size = CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE, + .config_audio_codec_cfg_max_metadata_size = CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE, + .config_audio_codec_cap_max_data_size = CONFIG_BT_AUDIO_CODEC_CAP_MAX_DATA_SIZE, + .config_audio_codec_cap_max_metadata_size = CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE, +#if CONFIG_BT_BAP_DEBUG_STREAM_DATA + .config_bap_debug_stream_data = CONFIG_BT_BAP_DEBUG_STREAM_DATA, +#endif /* CONFIG_BT_BAP_DEBUG_STREAM_DATA */ +#if CONFIG_BT_BAP_DEBUG_STREAM_SEQ_NUM + .config_bap_debug_stream_seq_num = CONFIG_BT_BAP_DEBUG_STREAM_SEQ_NUM, +#endif /* CONFIG_BT_BAP_DEBUG_STREAM_SEQ_NUM */ + + /* CAP (Common Audio Profile) */ +#if CONFIG_BT_CAP_ACCEPTOR + .config_cap_acceptor = CONFIG_BT_CAP_ACCEPTOR, +#if CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER + .config_cap_acceptor_set_member = CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER, +#endif /* CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER */ +#endif /* CONFIG_BT_CAP_ACCEPTOR */ +#if CONFIG_BT_CAP_INITIATOR + .config_cap_initiator = CONFIG_BT_CAP_INITIATOR, +#if CONFIG_BT_CAP_INITIATOR_UNICAST + .config_cap_initiator_unicast = CONFIG_BT_CAP_INITIATOR_UNICAST, +#endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */ +#endif /* CONFIG_BT_CAP_INITIATOR */ +#if CONFIG_BT_CAP_COMMANDER + .config_cap_commander = CONFIG_BT_CAP_COMMANDER, +#endif /* CONFIG_BT_CAP_COMMANDER */ +#if CONFIG_BT_CAP_HANDOVER + .config_cap_handover = CONFIG_BT_CAP_HANDOVER, +#endif /* CONFIG_BT_CAP_HANDOVER */ + + /* CCP (Call Control Profile) */ +#if CONFIG_BT_CCP_CALL_CONTROL_CLIENT + .config_ccp_call_control_client = CONFIG_BT_CCP_CALL_CONTROL_CLIENT, +#if CONFIG_BT_CCP_CALL_CONTROL_CLIENT_BEARER_COUNT + .config_ccp_call_control_client_bearer_count = CONFIG_BT_CCP_CALL_CONTROL_CLIENT_BEARER_COUNT, +#endif /* CONFIG_BT_CCP_CALL_CONTROL_CLIENT_BEARER_COUNT */ +#endif /* CONFIG_BT_CCP_CALL_CONTROL_CLIENT */ +#if CONFIG_BT_CCP_CALL_CONTROL_SERVER + .config_ccp_call_control_server = CONFIG_BT_CCP_CALL_CONTROL_SERVER, +#if CONFIG_BT_CCP_CALL_CONTROL_SERVER_BEARER_COUNT + .config_ccp_call_control_server_bearer_count = CONFIG_BT_CCP_CALL_CONTROL_SERVER_BEARER_COUNT, +#endif /* CONFIG_BT_CCP_CALL_CONTROL_SERVER_BEARER_COUNT */ +#if CONFIG_BT_CCP_CALL_CONTROL_SERVER_PROVIDER_NAME_MAX_LEN + .config_ccp_call_control_server_provider_name_max_len = CONFIG_BT_CCP_CALL_CONTROL_SERVER_PROVIDER_NAME_MAX_LEN, +#endif /* CONFIG_BT_CCP_CALL_CONTROL_SERVER_PROVIDER_NAME_MAX_LEN */ +#endif /* CONFIG_BT_CCP_CALL_CONTROL_SERVER */ + + /* CSIP (Coordinated Set Identification Profile) */ +#if CONFIG_BT_CSIP_SET_MEMBER + .config_csip_set_member = CONFIG_BT_CSIP_SET_MEMBER, + .config_csip_set_member_max_instance_count = CONFIG_BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT, + .config_csip_set_member_enc_sirk_support = CONFIG_BT_CSIP_SET_MEMBER_ENC_SIRK_SUPPORT, +#if CONFIG_BT_CSIP_SET_MEMBER_SIRK_NOTIFIABLE + .config_csip_set_member_sirk_notifiable = CONFIG_BT_CSIP_SET_MEMBER_SIRK_NOTIFIABLE, +#endif /* CONFIG_BT_CSIP_SET_MEMBER_SIRK_NOTIFIABLE */ +#if CONFIG_BT_CSIP_SET_MEMBER_SIZE_NOTIFIABLE + .config_csip_set_member_size_notifiable = CONFIG_BT_CSIP_SET_MEMBER_SIZE_NOTIFIABLE, +#endif /* CONFIG_BT_CSIP_SET_MEMBER_SIZE_NOTIFIABLE */ +#if CONFIG_BT_CSIP_SET_MEMBER_TEST_SAMPLE_DATA + .config_csip_set_member_test_sample_data = CONFIG_BT_CSIP_SET_MEMBER_TEST_SAMPLE_DATA, +#endif /* CONFIG_BT_CSIP_SET_MEMBER_TEST_SAMPLE_DATA */ +#endif /* CONFIG_BT_CSIP_SET_MEMBER */ +#if CONFIG_BT_CSIP_SET_COORDINATOR + .config_csip_set_coordinator = CONFIG_BT_CSIP_SET_COORDINATOR, + .config_csip_set_coordinator_max_csis_instances = CONFIG_BT_CSIP_SET_COORDINATOR_MAX_CSIS_INSTANCES, + .config_csip_set_coordinator_enc_sirk_support = CONFIG_BT_CSIP_SET_COORDINATOR_ENC_SIRK_SUPPORT, +#if CONFIG_BT_CSIP_SET_COORDINATOR_TEST_SAMPLE_DATA + .config_csip_set_coordinator_test_sample_data = CONFIG_BT_CSIP_SET_COORDINATOR_TEST_SAMPLE_DATA, +#endif /* CONFIG_BT_CSIP_SET_COORDINATOR_TEST_SAMPLE_DATA */ +#endif /* CONFIG_BT_CSIP_SET_COORDINATOR */ + + /* GMAP (Gaming Audio Profile) */ +#if CONFIG_BT_GMAP + .config_gmap = CONFIG_BT_GMAP, +#if CONFIG_BT_GMAP_UGG_SUPPORTED + .config_gmap_ugg_supported = CONFIG_BT_GMAP_UGG_SUPPORTED, +#endif /* CONFIG_BT_GMAP_UGG_SUPPORTED */ +#if CONFIG_BT_GMAP_UGT_SUPPORTED + .config_gmap_ugt_supported = CONFIG_BT_GMAP_UGT_SUPPORTED, +#endif /* CONFIG_BT_GMAP_UGT_SUPPORTED */ +#if CONFIG_BT_GMAP_BGS_SUPPORTED + .config_gmap_bgs_supported = CONFIG_BT_GMAP_BGS_SUPPORTED, +#endif /* CONFIG_BT_GMAP_BGS_SUPPORTED */ +#if CONFIG_BT_GMAP_BGR_SUPPORTED + .config_gmap_bgr_supported = CONFIG_BT_GMAP_BGR_SUPPORTED, +#endif /* CONFIG_BT_GMAP_BGR_SUPPORTED */ +#endif /* CONFIG_BT_GMAP */ + + /* HAS (Hearing Access Service) */ +#if CONFIG_BT_HAS + .config_has = CONFIG_BT_HAS, + .config_has_preset_count = CONFIG_BT_HAS_PRESET_COUNT, +#if CONFIG_BT_HAS_FEATURES_NOTIFIABLE + .config_has_features_notifiable = CONFIG_BT_HAS_FEATURES_NOTIFIABLE, +#endif /* CONFIG_BT_HAS_FEATURES_NOTIFIABLE */ +#if CONFIG_BT_HAS_PRESET_SUPPORT + .config_has_preset_support = CONFIG_BT_HAS_PRESET_SUPPORT, +#if CONFIG_BT_HAS_PRESET_NAME_DYNAMIC + .config_has_preset_name_dynamic = CONFIG_BT_HAS_PRESET_NAME_DYNAMIC, +#endif /* CONFIG_BT_HAS_PRESET_NAME_DYNAMIC */ +#if CONFIG_BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE + .config_has_preset_control_point_notifiable = CONFIG_BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE, +#endif /* CONFIG_BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE */ +#if CONFIG_BT_HAS_ACTIVE_PRESET_INDEX + .config_has_active_preset_index = CONFIG_BT_HAS_ACTIVE_PRESET_INDEX, +#endif /* CONFIG_BT_HAS_ACTIVE_PRESET_INDEX */ +#endif /* CONFIG_BT_HAS_PRESET_SUPPORT */ +#endif /* CONFIG_BT_HAS */ +#if CONFIG_BT_HAS_CLIENT + .config_has_client = CONFIG_BT_HAS_CLIENT, +#endif /* CONFIG_BT_HAS_CLIENT */ + + /* MCS (Media Control Service) */ +#if CONFIG_BT_MCS + .config_mcs = CONFIG_BT_MCS, +#endif /* CONFIG_BT_MCS */ +#if CONFIG_BT_MCC + .config_mcc = CONFIG_BT_MCC, + .config_mcc_media_player_name_max = CONFIG_BT_MCC_MEDIA_PLAYER_NAME_MAX, + .config_mcc_icon_url_max = CONFIG_BT_MCC_ICON_URL_MAX, + .config_mcc_track_title_max = CONFIG_BT_MCC_TRACK_TITLE_MAX, + .config_mcc_segment_name_max = CONFIG_BT_MCC_SEGMENT_NAME_MAX, +#if CONFIG_BT_MCC_OTS + .config_mcc_ots = CONFIG_BT_MCC_OTS, + .config_mcc_otc_obj_buf_size = CONFIG_BT_MCC_OTC_OBJ_BUF_SIZE, + .config_mcc_total_obj_content_mem = CONFIG_BT_MCC_TOTAL_OBJ_CONTENT_MEM, + .config_mcc_track_segs_max_cnt = CONFIG_BT_MCC_TRACK_SEGS_MAX_CNT, + .config_mcc_group_records_max = CONFIG_BT_MCC_GROUP_RECORDS_MAX, +#endif /* CONFIG_BT_MCC_OTS */ +#if CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL + .config_mcc_read_media_player_icon_url = CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL, +#endif /* CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL */ +#if CONFIG_BT_MCC_READ_TRACK_TITLE + .config_mcc_read_track_title = CONFIG_BT_MCC_READ_TRACK_TITLE, +#endif /* CONFIG_BT_MCC_READ_TRACK_TITLE */ +#if CONFIG_BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION + .config_mcc_read_track_title_enable_subscription = CONFIG_BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION, +#endif /* CONFIG_BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION */ +#if CONFIG_BT_MCC_READ_TRACK_DURATION + .config_mcc_read_track_duration = CONFIG_BT_MCC_READ_TRACK_DURATION, +#endif /* CONFIG_BT_MCC_READ_TRACK_DURATION */ +#if CONFIG_BT_MCC_READ_TRACK_POSITION + .config_mcc_read_track_position = CONFIG_BT_MCC_READ_TRACK_POSITION, +#endif /* CONFIG_BT_MCC_READ_TRACK_POSITION */ +#if CONFIG_BT_MCC_SET_TRACK_POSITION + .config_mcc_set_track_position = CONFIG_BT_MCC_SET_TRACK_POSITION, +#endif /* CONFIG_BT_MCC_SET_TRACK_POSITION */ +#if CONFIG_BT_MCC_READ_PLAYBACK_SPEED + .config_mcc_read_playback_speed = CONFIG_BT_MCC_READ_PLAYBACK_SPEED, +#endif /* CONFIG_BT_MCC_READ_PLAYBACK_SPEED */ +#if CONFIG_BT_MCC_SET_PLAYBACK_SPEED + .config_mcc_set_playback_speed = CONFIG_BT_MCC_SET_PLAYBACK_SPEED, +#endif /* CONFIG_BT_MCC_SET_PLAYBACK_SPEED */ +#if CONFIG_BT_MCC_READ_SEEKING_SPEED + .config_mcc_read_seeking_speed = CONFIG_BT_MCC_READ_SEEKING_SPEED, +#endif /* CONFIG_BT_MCC_READ_SEEKING_SPEED */ +#if CONFIG_BT_MCC_READ_PLAYING_ORDER + .config_mcc_read_playing_order = CONFIG_BT_MCC_READ_PLAYING_ORDER, +#endif /* CONFIG_BT_MCC_READ_PLAYING_ORDER */ +#if CONFIG_BT_MCC_SET_PLAYING_ORDER + .config_mcc_set_playing_order = CONFIG_BT_MCC_SET_PLAYING_ORDER, +#endif /* CONFIG_BT_MCC_SET_PLAYING_ORDER */ +#if CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED + .config_mcc_read_playing_order_supported = CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED, +#endif /* CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED */ +#if CONFIG_BT_MCC_READ_MEDIA_STATE + .config_mcc_read_media_state = CONFIG_BT_MCC_READ_MEDIA_STATE, +#endif /* CONFIG_BT_MCC_READ_MEDIA_STATE */ +#if CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT + .config_mcc_set_media_control_point = CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT, +#endif /* CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT */ +#if CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED + .config_mcc_read_media_control_point_opcodes_supported = CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED, +#endif /* CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED */ +#if CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID + .config_mcc_read_content_control_id = CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID, +#endif /* CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID */ +#endif /* CONFIG_BT_MCC */ + + /* MCTL (Media Control) */ +#if CONFIG_BT_MCTL + .config_mctl = CONFIG_BT_MCTL, +#if CONFIG_BT_MCTL_LOCAL_PLAYER_CONTROL + .config_mctl_local_player_control = CONFIG_BT_MCTL_LOCAL_PLAYER_CONTROL, +#if CONFIG_BT_MCTL_LOCAL_PLAYER_LOCAL_CONTROL + .config_mctl_local_player_local_control = CONFIG_BT_MCTL_LOCAL_PLAYER_LOCAL_CONTROL, +#endif /* CONFIG_BT_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */ +#if CONFIG_BT_MCTL_LOCAL_PLAYER_REMOTE_CONTROL + .config_mctl_local_player_remote_control = CONFIG_BT_MCTL_LOCAL_PLAYER_REMOTE_CONTROL, +#endif /* CONFIG_BT_MCTL_LOCAL_PLAYER_REMOTE_CONTROL */ +#endif /* CONFIG_BT_MCTL_LOCAL_PLAYER_CONTROL */ +#if CONFIG_BT_MCTL_REMOTE_PLAYER_CONTROL + .config_mctl_remote_player_control = CONFIG_BT_MCTL_REMOTE_PLAYER_CONTROL, +#if CONFIG_BT_MCTL_REMOTE_PLAYER_CONTROL_OBJECTS + .config_mctl_remote_player_control_objects = CONFIG_BT_MCTL_REMOTE_PLAYER_CONTROL_OBJECTS, +#endif /* CONFIG_BT_MCTL_REMOTE_PLAYER_CONTROL_OBJECTS */ +#endif /* CONFIG_BT_MCTL_REMOTE_PLAYER_CONTROL */ +#endif /* CONFIG_BT_MCTL */ + + /* MICP (Microphone Control Profile) */ +#if CONFIG_BT_MICP_MIC_DEV + .config_micp_mic_dev = CONFIG_BT_MICP_MIC_DEV, +#if CONFIG_BT_MICP_MIC_DEV_AICS + .config_micp_mic_dev_aics = CONFIG_BT_MICP_MIC_DEV_AICS, + .config_micp_mic_dev_aics_instance_count = CONFIG_BT_MICP_MIC_DEV_AICS_INSTANCE_COUNT, +#endif /* CONFIG_BT_MICP_MIC_DEV_AICS */ +#endif /* CONFIG_BT_MICP_MIC_DEV */ +#if CONFIG_BT_MICP_MIC_CTLR + .config_micp_mic_ctlr = CONFIG_BT_MICP_MIC_CTLR, +#if CONFIG_BT_MICP_MIC_CTLR_AICS + .config_micp_mic_ctlr_aics = CONFIG_BT_MICP_MIC_CTLR_AICS, + .config_micp_mic_ctlr_max_aics_inst = CONFIG_BT_MICP_MIC_CTLR_MAX_AICS_INST, +#endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */ +#endif /* CONFIG_BT_MICP_MIC_CTLR */ + + /* MPL (Media player) */ +#if CONFIG_BT_MPL + .config_mpl = CONFIG_BT_MPL, + .config_mpl_media_player_name = CONFIG_BT_MPL_MEDIA_PLAYER_NAME, + .config_mpl_media_player_name_max = CONFIG_BT_MPL_MEDIA_PLAYER_NAME_MAX, + .config_mpl_icon_url = CONFIG_BT_MPL_ICON_URL, + .config_mpl_icon_url_max = CONFIG_BT_MPL_ICON_URL_MAX, + .config_mpl_track_title_max = CONFIG_BT_MPL_TRACK_TITLE_MAX, + .config_mpl_segment_name_max = CONFIG_BT_MPL_SEGMENT_NAME_MAX, + .config_mpl_group_title_max = CONFIG_BT_MPL_GROUP_TITLE_MAX, +#if CONFIG_BT_MPL_OBJECTS + .config_mpl_objects = CONFIG_BT_MPL_OBJECTS, + .config_mpl_max_obj_size = CONFIG_BT_MPL_MAX_OBJ_SIZE, + .config_mpl_icon_bitmap_size = CONFIG_BT_MPL_ICON_BITMAP_SIZE, + .config_mpl_track_max_size = CONFIG_BT_MPL_TRACK_MAX_SIZE, +#endif /* CONFIG_BT_MPL_OBJECTS */ +#endif /* CONFIG_BT_MPL */ + + /* PACS (Published Audio Capabilities Service) */ +#if CONFIG_BT_PAC_SNK + .config_pac_snk = CONFIG_BT_PAC_SNK, +#if CONFIG_BT_PAC_SNK_NOTIFIABLE + .config_pac_snk_notifiable = CONFIG_BT_PAC_SNK_NOTIFIABLE, +#endif /* CONFIG_BT_PAC_SNK_NOTIFIABLE */ +#if CONFIG_BT_PAC_SNK_LOC + .config_pac_snk_loc = CONFIG_BT_PAC_SNK_LOC, +#if CONFIG_BT_PAC_SNK_LOC_WRITEABLE + .config_pac_snk_loc_writeable = CONFIG_BT_PAC_SNK_LOC_WRITEABLE, +#endif /* CONFIG_BT_PAC_SNK_LOC_WRITEABLE */ +#if CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE + .config_pac_snk_loc_notifiable = CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE, +#endif /* CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE */ +#endif /* CONFIG_BT_PAC_SNK_LOC */ +#endif /* CONFIG_BT_PAC_SNK */ +#if CONFIG_BT_PAC_SRC + .config_pac_src = CONFIG_BT_PAC_SRC, +#if CONFIG_BT_PAC_SRC_NOTIFIABLE + .config_pac_src_notifiable = CONFIG_BT_PAC_SRC_NOTIFIABLE, +#endif /* CONFIG_BT_PAC_SRC_NOTIFIABLE */ +#if CONFIG_BT_PAC_SRC_LOC + .config_pac_src_loc = CONFIG_BT_PAC_SRC_LOC, +#if CONFIG_BT_PAC_SRC_LOC_WRITEABLE + .config_pac_src_loc_writeable = CONFIG_BT_PAC_SRC_LOC_WRITEABLE, +#endif /* CONFIG_BT_PAC_SRC_LOC_WRITEABLE */ +#if CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE + .config_pac_src_loc_notifiable = CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE, +#endif /* CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE */ +#endif /* CONFIG_BT_PAC_SRC_LOC */ +#endif /* CONFIG_BT_PAC_SRC */ +#if CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE + .config_pacs_supported_context_notifiable = CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE, +#endif /* CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE */ + + /* PBP (Public Broadcast Profile) */ +#if CONFIG_BT_PBP + .config_pbp = CONFIG_BT_PBP, +#endif /* CONFIG_BT_PBP */ + + /* TBS (Telephone Bearer Service) */ +#if CONFIG_BT_TBS + .config_tbs = CONFIG_BT_TBS, + .config_tbs_supported_features = CONFIG_BT_TBS_SUPPORTED_FEATURES, + .config_tbs_max_calls = CONFIG_BT_TBS_MAX_CALLS, + .config_tbs_bearer_count = CONFIG_BT_TBS_BEARER_COUNT, + .config_tbs_max_scheme_list_length = CONFIG_BT_TBS_MAX_SCHEME_LIST_LENGTH, +#endif /* CONFIG_BT_TBS */ +#if CONFIG_BT_TBS_CLIENT + .config_tbs_client = CONFIG_BT_TBS_CLIENT, +#if CONFIG_BT_TBS_CLIENT_GTBS + .config_tbs_client_gtbs = CONFIG_BT_TBS_CLIENT_GTBS, +#endif /* CONFIG_BT_TBS_CLIENT_GTBS */ +#if CONFIG_BT_TBS_CLIENT_TBS + .config_tbs_client_tbs = CONFIG_BT_TBS_CLIENT_TBS, +#endif /* CONFIG_BT_TBS_CLIENT_TBS */ + .config_tbs_client_max_calls = CONFIG_BT_TBS_CLIENT_MAX_CALLS, +#if CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES + .config_tbs_client_max_tbs_instances = CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES, +#endif /* CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES */ +#if CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME + .config_tbs_client_bearer_provider_name = CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME, +#endif /* CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME */ +#if CONFIG_BT_TBS_CLIENT_BEARER_UCI + .config_tbs_client_bearer_uci = CONFIG_BT_TBS_CLIENT_BEARER_UCI, +#endif /* CONFIG_BT_TBS_CLIENT_BEARER_UCI */ +#if CONFIG_BT_TBS_CLIENT_BEARER_TECHNOLOGY + .config_tbs_client_bearer_technology = CONFIG_BT_TBS_CLIENT_BEARER_TECHNOLOGY, +#endif /* CONFIG_BT_TBS_CLIENT_BEARER_TECHNOLOGY */ +#if CONFIG_BT_TBS_CLIENT_BEARER_URI_SCHEMES_SUPPORTED_LIST + .config_tbs_client_bearer_uri_schemes_supported_list = CONFIG_BT_TBS_CLIENT_BEARER_URI_SCHEMES_SUPPORTED_LIST, +#endif /* CONFIG_BT_TBS_CLIENT_BEARER_URI_SCHEMES_SUPPORTED_LIST */ +#if CONFIG_BT_TBS_CLIENT_BEARER_SIGNAL_STRENGTH + .config_tbs_client_bearer_signal_strength = CONFIG_BT_TBS_CLIENT_BEARER_SIGNAL_STRENGTH, +#endif /* CONFIG_BT_TBS_CLIENT_BEARER_SIGNAL_STRENGTH */ +#if CONFIG_BT_TBS_CLIENT_READ_BEARER_SIGNAL_INTERVAL + .config_tbs_client_read_bearer_signal_interval = CONFIG_BT_TBS_CLIENT_READ_BEARER_SIGNAL_INTERVAL, +#endif /* CONFIG_BT_TBS_CLIENT_READ_BEARER_SIGNAL_INTERVAL */ +#if CONFIG_BT_TBS_CLIENT_SET_BEARER_SIGNAL_INTERVAL + .config_tbs_client_set_bearer_signal_interval = CONFIG_BT_TBS_CLIENT_SET_BEARER_SIGNAL_INTERVAL, +#endif /* CONFIG_BT_TBS_CLIENT_SET_BEARER_SIGNAL_INTERVAL */ +#if CONFIG_BT_TBS_CLIENT_BEARER_LIST_CURRENT_CALLS + .config_tbs_client_bearer_list_current_calls = CONFIG_BT_TBS_CLIENT_BEARER_LIST_CURRENT_CALLS, +#endif /* CONFIG_BT_TBS_CLIENT_BEARER_LIST_CURRENT_CALLS */ +#if CONFIG_BT_TBS_CLIENT_CCID + .config_tbs_client_ccid = CONFIG_BT_TBS_CLIENT_CCID, +#endif /* CONFIG_BT_TBS_CLIENT_CCID */ +#if CONFIG_BT_TBS_CLIENT_INCOMING_URI + .config_tbs_client_incoming_uri = CONFIG_BT_TBS_CLIENT_INCOMING_URI, +#endif /* CONFIG_BT_TBS_CLIENT_INCOMING_URI */ +#if CONFIG_BT_TBS_CLIENT_STATUS_FLAGS + .config_tbs_client_status_flags = CONFIG_BT_TBS_CLIENT_STATUS_FLAGS, +#endif /* CONFIG_BT_TBS_CLIENT_STATUS_FLAGS */ +#if CONFIG_BT_TBS_CLIENT_CP_PROCEDURES + .config_tbs_client_cp_procedures = CONFIG_BT_TBS_CLIENT_CP_PROCEDURES, +#endif /* CONFIG_BT_TBS_CLIENT_CP_PROCEDURES */ +#if CONFIG_BT_TBS_CLIENT_ACCEPT_CALL + .config_tbs_client_accept_call = CONFIG_BT_TBS_CLIENT_ACCEPT_CALL, +#endif /* CONFIG_BT_TBS_CLIENT_ACCEPT_CALL */ +#if CONFIG_BT_TBS_CLIENT_TERMINATE_CALL + .config_tbs_client_terminate_call = CONFIG_BT_TBS_CLIENT_TERMINATE_CALL, +#endif /* CONFIG_BT_TBS_CLIENT_TERMINATE_CALL */ +#if CONFIG_BT_TBS_CLIENT_HOLD_CALL + .config_tbs_client_hold_call = CONFIG_BT_TBS_CLIENT_HOLD_CALL, +#endif /* CONFIG_BT_TBS_CLIENT_HOLD_CALL */ +#if CONFIG_BT_TBS_CLIENT_RETRIEVE_CALL + .config_tbs_client_retrieve_call = CONFIG_BT_TBS_CLIENT_RETRIEVE_CALL, +#endif /* CONFIG_BT_TBS_CLIENT_RETRIEVE_CALL */ +#if CONFIG_BT_TBS_CLIENT_ORIGINATE_CALL + .config_tbs_client_originate_call = CONFIG_BT_TBS_CLIENT_ORIGINATE_CALL, +#endif /* CONFIG_BT_TBS_CLIENT_ORIGINATE_CALL */ +#if CONFIG_BT_TBS_CLIENT_JOIN_CALLS + .config_tbs_client_join_calls = CONFIG_BT_TBS_CLIENT_JOIN_CALLS, +#endif /* CONFIG_BT_TBS_CLIENT_JOIN_CALLS */ +#if CONFIG_BT_TBS_CLIENT_OPTIONAL_OPCODES + .config_tbs_client_optional_opcodes = CONFIG_BT_TBS_CLIENT_OPTIONAL_OPCODES, +#endif /* CONFIG_BT_TBS_CLIENT_OPTIONAL_OPCODES */ +#if CONFIG_BT_TBS_CLIENT_INCOMING_CALL + .config_tbs_client_incoming_call = CONFIG_BT_TBS_CLIENT_INCOMING_CALL, +#endif /* CONFIG_BT_TBS_CLIENT_INCOMING_CALL */ +#if CONFIG_BT_TBS_CLIENT_CALL_FRIENDLY_NAME + .config_tbs_client_call_friendly_name = CONFIG_BT_TBS_CLIENT_CALL_FRIENDLY_NAME, +#endif /* CONFIG_BT_TBS_CLIENT_CALL_FRIENDLY_NAME */ +#endif /* CONFIG_BT_TBS_CLIENT */ +#if CONFIG_BT_TBS || CONFIG_BT_TBS_CLIENT + .config_tbs_max_uri_length = CONFIG_BT_TBS_MAX_URI_LENGTH, + .config_tbs_max_provider_name_length = CONFIG_BT_TBS_MAX_PROVIDER_NAME_LENGTH, +#endif /* CONFIG_BT_TBS || CONFIG_BT_TBS_CLIENT */ + + /* TMAP (Telephony and Media Audio Profile) */ +#if CONFIG_BT_TMAP_CG_SUPPORTED + .config_tmap_cg_supported = CONFIG_BT_TMAP_CG_SUPPORTED, +#endif /* CONFIG_BT_TMAP_CG_SUPPORTED */ +#if CONFIG_BT_TMAP_CT_SUPPORTED + .config_tmap_ct_supported = CONFIG_BT_TMAP_CT_SUPPORTED, +#endif /* CONFIG_BT_TMAP_CT_SUPPORTED */ +#if CONFIG_BT_TMAP_UMS_SUPPORTED + .config_tmap_ums_supported = CONFIG_BT_TMAP_UMS_SUPPORTED, +#endif /* CONFIG_BT_TMAP_UMS_SUPPORTED */ +#if CONFIG_BT_TMAP_UMR_SUPPORTED + .config_tmap_umr_supported = CONFIG_BT_TMAP_UMR_SUPPORTED, +#endif /* CONFIG_BT_TMAP_UMR_SUPPORTED */ +#if CONFIG_BT_TMAP_BMS_SUPPORTED + .config_tmap_bms_supported = CONFIG_BT_TMAP_BMS_SUPPORTED, +#endif /* CONFIG_BT_TMAP_BMS_SUPPORTED */ +#if CONFIG_BT_TMAP_BMR_SUPPORTED + .config_tmap_bmr_supported = CONFIG_BT_TMAP_BMR_SUPPORTED, +#endif /* CONFIG_BT_TMAP_BMR_SUPPORTED */ +#if CONFIG_BT_TMAP + .config_tmap = CONFIG_BT_TMAP, +#endif /* CONFIG_BT_TMAP */ + + /* VCP (Volume Control Profile) */ +#if CONFIG_BT_VCP_VOL_REND + .config_vcp_vol_rend = CONFIG_BT_VCP_VOL_REND, +#if CONFIG_BT_VCP_VOL_REND_VOCS + .config_vcp_vol_rend_vocs = CONFIG_BT_VCP_VOL_REND_VOCS, + .config_vcp_vol_rend_vocs_instance_count = CONFIG_BT_VCP_VOL_REND_VOCS_INSTANCE_COUNT, +#endif /* CONFIG_BT_VCP_VOL_REND_VOCS */ +#if CONFIG_BT_VCP_VOL_REND_AICS + .config_vcp_vol_rend_aics = CONFIG_BT_VCP_VOL_REND_AICS, + .config_vcp_vol_rend_aics_instance_count = CONFIG_BT_VCP_VOL_REND_AICS_INSTANCE_COUNT, +#endif /* CONFIG_BT_VCP_VOL_REND_AICS */ +#if CONFIG_BT_VCP_VOL_REND_VOL_FLAGS_NOTIFIABLE + .config_vcp_vol_rend_vol_flags_notifiable = CONFIG_BT_VCP_VOL_REND_VOL_FLAGS_NOTIFIABLE, +#endif /* CONFIG_BT_VCP_VOL_REND_VOL_FLAGS_NOTIFIABLE */ +#endif /* CONFIG_BT_VCP_VOL_REND */ +#if CONFIG_BT_VCP_VOL_CTLR + .config_vcp_vol_ctlr = CONFIG_BT_VCP_VOL_CTLR, +#if CONFIG_BT_VCP_VOL_CTLR_VOCS + .config_vcp_vol_ctlr_vocs = CONFIG_BT_VCP_VOL_CTLR_VOCS, + .config_vcp_vol_ctlr_max_vocs_inst = CONFIG_BT_VCP_VOL_CTLR_MAX_VOCS_INST, +#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */ +#if CONFIG_BT_VCP_VOL_CTLR_AICS + .config_vcp_vol_ctlr_aics = CONFIG_BT_VCP_VOL_CTLR_AICS, + .config_vcp_vol_ctlr_max_aics_inst = CONFIG_BT_VCP_VOL_CTLR_MAX_AICS_INST, +#endif /* CONFIG_BT_VCP_VOL_CTLR_AICS */ +#endif /* CONFIG_BT_VCP_VOL_CTLR */ + + /* VOCS (Volume Control Service) */ +#if CONFIG_BT_VOCS + .config_vocs = CONFIG_BT_VOCS, + .config_vocs_max_instance_count = CONFIG_BT_VOCS_MAX_INSTANCE_COUNT, + .config_vocs_max_output_description_size = CONFIG_BT_VOCS_MAX_OUTPUT_DESCRIPTION_SIZE, +#endif /* CONFIG_BT_VOCS */ +#if CONFIG_BT_VOCS_CLIENT + .config_vocs_client = CONFIG_BT_VOCS_CLIENT, + .config_vocs_client_max_instance_count = CONFIG_BT_VOCS_CLIENT_MAX_INSTANCE_COUNT, +#endif /* CONFIG_BT_VOCS_CLIENT */ + + /* OTS (Object Transfer Service) */ +#if CONFIG_BT_OTS + .config_ots = CONFIG_BT_OTS, +#endif /* CONFIG_BT_OTS */ +#if CONFIG_BT_OTS_CLIENT + .config_ots_client = CONFIG_BT_OTS_CLIENT, +#endif /* CONFIG_BT_OTS_CLIENT */ +#if CONFIG_BT_OTS || CONFIG_BT_OTS_CLIENT + .config_ots_obj_max_name_len = CONFIG_BT_OTS_OBJ_MAX_NAME_LEN, +#endif /* CONFIG_BT_OTS || CONFIG_BT_OTS_CLIENT */ + + .config_version = LEA_VERSION, +}; + +struct lib_ext_funcs { + /* LOG */ + void (*_log_dbg)(const char *format, ...); + void (*_log_inf)(const char *format, ...); + void (*_log_wrn)(const char *format, ...); + void (*_log_err)(const char *format, ...); + + /* Memory */ + void *(*_malloc)(size_t size); + void *(*_calloc)(size_t n, size_t size); + void (*_free)(void *ptr); + + /* Crypto */ + int (*_rand)(void *buf, size_t len); + int (*_encrypt_le)(const uint8_t key[16], + const uint8_t plaintext[16], + uint8_t enc_data[16]); + int (*_aes_cmac)(const uint8_t *key, const uint8_t *in, + size_t len, uint8_t *out); + + /* UTF8 */ + char *(*_utf8_trunc)(char *utf8_str); + char *(*_utf8_lcpy)(char *dst, const char *src, size_t n); + + /* Mutex */ + void (*_mutex_create)(void *mutex); + void (*_mutex_delete)(void *mutex); + int (*_mutex_lock)(void *mutex, uint32_t timeout); + int (*_mutex_unlock)(void *mutex); + void (*_lock)(void); + void (*_unlock)(void); + + /* Net buf */ + void (*_buf_simple_init)(void *buf, size_t reserve_head); + void (*_buf_simple_init_with_data)(void *buf, void *data, size_t size); + void (*_buf_simple_reset)(void *buf); + void (*_buf_simple_clone)(const void *original, void *clone); + void *(*_buf_simple_add)(void *buf, size_t len); + void *(*_buf_simple_add_mem)(void *buf, const void *mem, size_t len); + uint8_t *(*_buf_simple_add_u8)(void *buf, uint8_t val); + void (*_buf_simple_add_le16)(void *buf, uint16_t val); + void (*_buf_simple_add_le24)(void *buf, uint32_t val); + void (*_buf_simple_add_le32)(void *buf, uint32_t val); + void (*_buf_simple_add_le48)(void *buf, uint64_t val); + void (*_buf_simple_add_le64)(void *buf, uint64_t val); + void *(*_buf_simple_pull)(void *buf, size_t len); + void *(*_buf_simple_pull_mem)(void *buf, size_t len); + uint8_t (*_buf_simple_pull_u8)(void *buf); + uint16_t (*_buf_simple_pull_le16)(void *buf); + uint32_t (*_buf_simple_pull_le24)(void *buf); + uint32_t (*_buf_simple_pull_le32)(void *buf); + uint64_t (*_buf_simple_pull_le48)(void *buf); + uint64_t (*_buf_simple_pull_le64)(void *buf); + size_t (*_buf_simple_headroom)(const void *buf); + size_t (*_buf_simple_tailroom)(void *buf); + void (*_buf_simple_save)(void *buf, void *state); + void (*_buf_simple_restore)(void *buf, void *state); + void *(*_buf_user_data)(void *buf); + size_t (*_buf_frags_len)(void *buf); + + /* Timer */ + int (*_dwork_init)(void *dwork, void *handler); + int (*_dwork_deinit)(void *dwork); + int (*_dwork_schedule)(void *dwork, uint32_t delay); + int (*_dwork_cancel)(void *dwork); + bool (*_dwork_cancel_sync)(void *dwork, void *sync); + uint32_t (*_dwork_remaining_get)(void *dwork); + bool (*_work_is_pending)(void *work); + int (*_work_submit)(void *work); + void *(*_dwork_from_work)(void *work); + + /* BT_STR */ + const char *(*_bt_hex)(const void *buf, size_t len); + const char *(*_bt_addr_str)(const bt_addr_t *addr); + const char *(*_bt_addr_le_str)(const bt_addr_le_t *addr); + int (*_bt_addr_le_to_str)(const bt_addr_le_t *addr, char *str, size_t len); + bool (*_bt_addr_le_eq)(const bt_addr_le_t *a, const bt_addr_le_t *b); + void (*_bt_addr_copy)(bt_addr_t *dst, const bt_addr_t *src); + void (*_bt_addr_le_copy)(bt_addr_le_t *dst, const bt_addr_le_t *src); + const char *(*_bt_uuid_str)(const struct bt_uuid *uuid); + + /* UUID */ + int (*_uuid_cmp)(const struct bt_uuid *u1, const struct bt_uuid *u2); + bool (*_uuid_create)(struct bt_uuid *uuid, const uint8_t *data, uint8_t data_len); + void (*_uuid_to_str)(const struct bt_uuid *uuid, char *str, size_t len); + + /* SMP */ + bool (*_bt_le_bond_exists)(uint8_t id, const bt_addr_le_t *addr); + void (*_bt_foreach_bond)(uint8_t id, void *func, void *user_data); + + /* Scan */ + int (*_scan_cb_register)(struct bt_le_scan_cb *cb); + int (*_scan_start)(const struct bt_le_scan_param *param, void *cb); + int (*_scan_stop)(void); + int (*_pa_sync_cb_register)(struct bt_le_per_adv_sync_cb *cb); + int (*_pa_sync_get_info)(struct bt_le_per_adv_sync *per_adv_sync, + struct bt_le_per_adv_sync_info *info); + struct bt_le_per_adv_sync *(*_pa_sync_lookup_addr)(const bt_addr_le_t *adv_addr, uint8_t sid); + + /* Connection */ + int (*_conn_cb_register)(struct bt_conn_cb *cb); + int (*_conn_auth_info_cb_register)(struct bt_conn_auth_info_cb *cb); + void (*_conn_foreach)(enum bt_conn_type type, + void (*func)(struct bt_conn *conn, void *data), + void *data); + int (*_conn_get_info)(const struct bt_conn *conn, struct bt_conn_info *info); + uint8_t (*_conn_index)(const struct bt_conn *conn); + const bt_addr_le_t *(*_conn_get_dst)(const struct bt_conn *conn); + struct bt_conn *(*_conn_ref)(struct bt_conn *conn); + void (*_conn_unref)(struct bt_conn *conn); + + /* GATT */ + int (*_gatt_svc_register)(void *svc); + int (*_gatt_svc_unregister)(void *svc); + uint16_t (*_gatt_get_mtu)(void *conn); + size_t (*_gatt_eatt_count)(void *conn); + uint16_t (*_gatt_attr_value_handle)(const void *attr); + void (*_gatt_foreach_attr_type)(uint16_t start_handle, uint16_t end_handle, + const void *uuid, const void *attr_data, + uint16_t num_matches, void *func, void *user_data); + void *(*_gatt_find_by_uuid)(const void *attr, uint16_t attr_count, const void *uuid); + ssize_t (*_gatts_attr_read)(void *conn, const void *attr, void *buf, uint16_t buf_len, + uint16_t offset, const void *value, uint16_t value_len); + int (*_gatts_notify_cb)(void *conn, void *params); + int (*_gatts_notify)(void *conn, const void *attr, const void *data, uint16_t len); + int (*_gatts_notify_uuid)(void *conn, const void *uuid, const void *attr, + const void *data, uint16_t len); + int (*_gatts_indicate)(void *conn, void *params); + bool (*_gatts_is_subscribed)(void *conn, const void *attr, uint16_t ccc_type); + int (*_gattc_discover)(void *conn, void *params); + int (*_gattc_subscribe)(void *conn, void *params); + int (*_gattc_unsubscribe)(void *conn, void *params); + int (*_gattc_read)(void *conn, void *params); + int (*_gattc_write)(void *conn, void *params); + int (*_gattc_write_without_response_cb)(void *conn, uint16_t handle, const void *data, + uint16_t length, bool sign, void *func, + void *user_data); + int (*_gattc_write_without_response)(void *conn, uint16_t handle, const void *data, + uint16_t length, bool sign); + + /* OTS */ + int (*_ots_init)(void *ots, void *ots_init); + int (*_ots_obj_add)(void *ots, const void *param); + void *(*_ots_free_instance_get)(void); + void *(*_ots_svc_decl_get)(void *ots); + int (*_ots_client_register)(void *ots_inst); + uint8_t (*_ots_client_indicate_handler)(void *conn, void *params, + const void *data, uint16_t length); + int (*_ots_client_read_object_metadata)(void *otc_inst, void *conn, uint8_t metadata); + int (*_ots_client_read_object_data)(void *otc_inst, void *conn); + void (*_ots_metadata_display)(void *metadata, uint16_t count); +}; + +#define LEA_TAG "LIB" + +static void log_debug(const char *format, ...) +{ +#if (CONFIG_BT_AUDIO_LOG_LEVEL >= BT_AUDIO_LOG_DEBUG) + va_list args; + + va_start(args, format); + + /* Note: do not use `ESP_LOG_DEBUG` here! */ + esp_log_write(ESP_LOG_INFO, LEA_TAG, BT_ISO_LOG_COLOR_D "D (%lu) %s: ", esp_log_timestamp(), LEA_TAG); + esp_log_writev(ESP_LOG_INFO, LEA_TAG, format, args); + esp_log_write(ESP_LOG_INFO, LEA_TAG, BT_ISO_LOG_RESET_COLOR "\n"); + + va_end(args); +#endif /* (CONFIG_BT_AUDIO_LOG_LEVEL >= BT_AUDIO_LOG_DEBUG) */ +} + +static void log_info(const char *format, ...) +{ +#if (CONFIG_BT_AUDIO_LOG_LEVEL >= BT_AUDIO_LOG_INFO) + va_list args; + + va_start(args, format); + + esp_log_write(ESP_LOG_INFO, LEA_TAG, BT_ISO_LOG_COLOR_I "I (%lu) %s: ", esp_log_timestamp(), LEA_TAG); + esp_log_writev(ESP_LOG_INFO, LEA_TAG, format, args); + esp_log_write(ESP_LOG_INFO, LEA_TAG, BT_ISO_LOG_RESET_COLOR "\n"); + + va_end(args); +#endif /* (CONFIG_BT_AUDIO_LOG_LEVEL >= BT_AUDIO_LOG_INFO) */ +} + +static void log_warn(const char *format, ...) +{ +#if (CONFIG_BT_AUDIO_LOG_LEVEL >= BT_AUDIO_LOG_WARN) + va_list args; + + va_start(args, format); + + esp_log_write(ESP_LOG_WARN, LEA_TAG, BT_ISO_LOG_COLOR_W "W (%lu) %s: ", esp_log_timestamp(), LEA_TAG); + esp_log_writev(ESP_LOG_WARN, LEA_TAG, format, args); + esp_log_write(ESP_LOG_WARN, LEA_TAG, BT_ISO_LOG_RESET_COLOR "\n"); + + va_end(args); +#endif /* (CONFIG_BT_AUDIO_LOG_LEVEL >= BT_AUDIO_LOG_WARN) */ +} + +static void log_error(const char *format, ...) +{ +#if (CONFIG_BT_AUDIO_LOG_LEVEL >= BT_AUDIO_LOG_ERROR) + va_list args; + + va_start(args, format); + + esp_log_write(ESP_LOG_ERROR, LEA_TAG, BT_ISO_LOG_COLOR_E "E (%lu) %s: ", esp_log_timestamp(), LEA_TAG); + esp_log_writev(ESP_LOG_ERROR, LEA_TAG, format, args); + esp_log_write(ESP_LOG_ERROR, LEA_TAG, BT_ISO_LOG_RESET_COLOR "\n"); + + va_end(args); +#endif /* (CONFIG_BT_AUDIO_LOG_LEVEL >= BT_AUDIO_LOG_ERROR) */ +} + +static const struct lib_ext_funcs ext_funcs = { + ._log_dbg = (void *)log_debug, + ._log_inf = (void *)log_info, + ._log_wrn = (void *)log_warn, + ._log_err = (void *)log_error, + + ._malloc = (void *)malloc, + ._calloc = (void *)calloc, + ._free = (void *)free, + + ._rand = (void *)bt_rand, + ._encrypt_le = (void *)bt_encrypt_le, + ._aes_cmac = (void *)bt_crypto_aes_cmac, + + ._utf8_trunc = (void *)utf8_trunc, + ._utf8_lcpy = (void *)utf8_lcpy, + + ._mutex_create = (void *)k_mutex_create, + ._mutex_delete = (void *)k_mutex_delete, + ._mutex_lock = (void *)k_mutex_lock, + ._mutex_unlock = (void *)k_mutex_unlock, + ._lock = (void *)bt_le_host_lock, + ._unlock = (void *)bt_le_host_unlock, + + ._buf_simple_init = (void *)net_buf_simple_init, + ._buf_simple_init_with_data = (void *)net_buf_simple_init_with_data, + ._buf_simple_reset = (void *)net_buf_simple_reset, + ._buf_simple_clone = (void *)net_buf_simple_clone, + ._buf_simple_add = (void *)net_buf_simple_add, + ._buf_simple_add_mem = (void *)net_buf_simple_add_mem, + ._buf_simple_add_u8 = (void *)net_buf_simple_add_u8, + ._buf_simple_add_le16 = (void *)net_buf_simple_add_le16, + ._buf_simple_add_le24 = (void *)net_buf_simple_add_le24, + ._buf_simple_add_le32 = (void *)net_buf_simple_add_le32, + ._buf_simple_add_le48 = (void *)net_buf_simple_add_le48, + ._buf_simple_add_le64 = (void *)net_buf_simple_add_le64, + ._buf_simple_pull = (void *)net_buf_simple_pull, + ._buf_simple_pull_mem = (void *)net_buf_simple_pull_mem, + ._buf_simple_pull_u8 = (void *)net_buf_simple_pull_u8, + ._buf_simple_pull_le16 = (void *)net_buf_simple_pull_le16, + ._buf_simple_pull_le24 = (void *)net_buf_simple_pull_le24, + ._buf_simple_pull_le32 = (void *)net_buf_simple_pull_le32, + ._buf_simple_pull_le48 = (void *)net_buf_simple_pull_le48, + ._buf_simple_pull_le64 = (void *)net_buf_simple_pull_le64, + ._buf_simple_headroom = (void *)net_buf_simple_headroom, + ._buf_simple_tailroom = (void *)net_buf_simple_tailroom, + ._buf_simple_save = (void *)net_buf_simple_save, + ._buf_simple_restore = (void *)net_buf_simple_restore, + ._buf_user_data = (void *)net_buf_user_data, + ._buf_frags_len = (void *)net_buf_frags_len, + + ._dwork_init = (void *)k_work_init_delayable, + ._dwork_deinit = (void *)k_work_deinit_delayable, + ._dwork_schedule = (void *)k_work_schedule, + ._dwork_cancel = (void *)k_work_cancel_delayable, + ._dwork_cancel_sync = (void *)k_work_cancel_delayable_sync, + ._dwork_remaining_get = (void *)k_work_delayable_remaining_get, + ._work_is_pending = (void *)k_work_is_pending, + ._work_submit = (void *)k_work_submit, + ._dwork_from_work = (void *)k_work_delayable_from_work, + + ._bt_hex = (void *)bt_hex, + ._bt_addr_str = (void *)bt_addr_str, + ._bt_addr_le_str = (void *)bt_addr_le_str, + ._bt_addr_le_to_str = (void *)bt_addr_le_to_str, + ._bt_addr_le_eq = (void *)bt_addr_le_eq, + ._bt_addr_copy = (void *)bt_addr_copy, + ._bt_addr_le_copy = (void *)bt_addr_le_copy, + ._bt_uuid_str = (void *)bt_uuid_str, + + ._uuid_cmp = (void *)bt_uuid_cmp, + ._uuid_create = (void *)bt_uuid_create, + ._uuid_to_str = (void *)bt_uuid_to_str, + + ._bt_le_bond_exists = (void *)bt_le_bond_exists, + ._bt_foreach_bond = (void *)bt_foreach_bond, + + ._scan_cb_register = (void *)bt_le_scan_cb_register, + ._scan_start = (void *)bt_le_scan_start, + ._scan_stop = (void *)bt_le_scan_stop, + ._pa_sync_cb_register = (void *)bt_le_per_adv_sync_cb_register, + ._pa_sync_get_info = (void *)bt_le_per_adv_sync_get_info, + ._pa_sync_lookup_addr = (void *)bt_le_per_adv_sync_lookup_addr, + + ._conn_cb_register = (void *)bt_conn_cb_register, + ._conn_auth_info_cb_register = (void *)bt_conn_auth_info_cb_register, + ._conn_foreach = (void *)bt_conn_foreach, + ._conn_get_info = (void *)bt_conn_get_info, + ._conn_index = (void *)bt_conn_index, + ._conn_get_dst = (void *)bt_conn_get_dst, + ._conn_ref = (void *)bt_conn_ref, + ._conn_unref = (void *)bt_conn_unref, + + ._gatt_svc_register = (void *)bt_gatt_service_register, + ._gatt_svc_unregister = (void *)bt_gatt_service_unregister, + ._gatt_get_mtu = (void *)bt_gatt_get_mtu, + ._gatt_eatt_count = (void *)bt_eatt_count, + ._gatt_attr_value_handle = (void *)bt_gatt_attr_value_handle, + ._gatt_foreach_attr_type = (void *)bt_gatt_foreach_attr_type, + ._gatt_find_by_uuid = (void *)bt_gatt_find_by_uuid, + ._gatts_attr_read = (void *)bt_gatt_attr_read, + ._gatts_notify_cb = (void *)bt_gatt_notify_cb, + ._gatts_notify = (void *)bt_gatt_notify, + ._gatts_notify_uuid = (void *)bt_gatt_notify_uuid, + ._gatts_indicate = (void *)bt_gatt_indicate, + ._gatts_is_subscribed = (void *)bt_gatt_is_subscribed, + ._gattc_discover = (void *)bt_gatt_discover, + ._gattc_subscribe = (void *)bt_gatt_subscribe, + ._gattc_unsubscribe = (void *)bt_gatt_unsubscribe, + ._gattc_read = (void *)bt_gatt_read, + ._gattc_write = (void *)bt_gatt_write, + ._gattc_write_without_response_cb = (void *)bt_gatt_write_without_response_cb, + ._gattc_write_without_response = (void *)bt_gatt_write_without_response, + +#if CONFIG_BT_OTS + ._ots_init = (void *)bt_ots_init, + ._ots_obj_add = (void *)bt_ots_obj_add, + ._ots_free_instance_get = (void *)bt_ots_free_instance_get, +#if CONFIG_BT_OTS_SECONDARY_SVC + ._ots_svc_decl_get = (void *)bt_ots_svc_decl_get, +#endif /* CONFIG_BT_OTS_SECONDARY_SVC */ +#endif /* CONFIG_BT_OTS */ +#if CONFIG_BT_OTS_CLIENT + ._ots_client_register = (void *)bt_ots_client_register, + ._ots_client_indicate_handler = (void *)bt_ots_client_indicate_handler, + ._ots_client_read_object_metadata = (void *)bt_ots_client_read_object_metadata, + ._ots_client_read_object_data = (void *)bt_ots_client_read_object_data, + ._ots_metadata_display = (void *)bt_ots_metadata_display, +#endif /* CONFIG_BT_OTS_CLIENT */ +}; + +struct lib_funcs { + /* AICS Client */ + int (*_aics_client_state_get)(struct bt_aics *inst); + int (*_aics_client_gain_setting_get)(struct bt_aics *inst); + int (*_aics_client_type_get)(struct bt_aics *inst); + int (*_aics_client_status_get)(struct bt_aics *inst); + int (*_aics_client_unmute)(struct bt_aics *inst); + int (*_aics_client_mute)(struct bt_aics *inst); + int (*_aics_client_manual_gain_set)(struct bt_aics *inst); + int (*_aics_client_automatic_gain_set)(struct bt_aics *inst); + int (*_aics_client_gain_set)(struct bt_aics *inst, int8_t gain); + int (*_aics_client_description_get)(struct bt_aics *inst); + int (*_aics_client_description_set)(struct bt_aics *inst, const char *description); + + /* BAP Broadcast Sink */ + bool (*_bap_broadcast_sink_has_ep)(const struct bt_bap_ep *ep); + + /* BAP Broadcast Source */ + bool (*_bap_broadcast_source_has_ep)(const struct bt_bap_ep *ep); + + /* BAP Unicast Client */ + bool (*_bap_unicast_client_has_ep)(const struct bt_bap_ep *ep); + int (*_bap_unicast_client_register_cb)(struct bt_bap_unicast_client_cb *cb); + int (*_bap_unicast_client_config)(struct bt_bap_stream *stream, + const struct bt_audio_codec_cfg *codec_cfg); + int (*_bap_unicast_client_metadata)(struct bt_bap_stream *stream, + const uint8_t meta[], size_t meta_len); + int (*_bap_unicast_client_connect)(struct bt_bap_stream *stream); + int (*_bap_unicast_client_start)(struct bt_bap_stream *stream); + int (*_bap_unicast_client_disable)(struct bt_bap_stream *stream); + int (*_bap_unicast_client_release)(struct bt_bap_stream *stream); + + /* BAP Unicast Server */ + bool (*_bap_unicast_server_has_ep)(const struct bt_bap_ep *ep); + int (*_bap_unicast_server_reconfig)(struct bt_bap_stream *stream, + const struct bt_audio_codec_cfg *codec_cfg); + int (*_bap_unicast_server_start)(struct bt_bap_stream *stream); + int (*_bap_unicast_server_metadata)(struct bt_bap_stream *stream, + const uint8_t meta[], size_t meta_len); + int (*_bap_unicast_server_disable)(struct bt_bap_stream *stream); + int (*_bap_unicast_server_release)(struct bt_bap_stream *stream); + + /* CAP Acceptor */ + bool (*_cap_acceptor_ccids_exist)(const struct bt_conn *conn, const uint8_t ccids[], + uint8_t ccid_cnt); + + /* CAP Initiator */ + void (*_cap_common_set_subproc)(enum bt_cap_common_subproc_type subproc_type); + bool (*_cap_common_proc_is_type)(enum bt_cap_common_proc_type proc_type); + bool (*_cap_common_subproc_is_type)(enum bt_cap_common_subproc_type subproc_type); + void (*_cap_initiator_cp_cb)(struct bt_cap_stream *cap_stream, + enum bt_bap_ascs_rsp_code rsp_code, + enum bt_bap_ascs_reason reason); + void (*_cap_initiator_codec_configured)(struct bt_cap_stream *cap_stream); + void (*_cap_initiator_qos_configured)(struct bt_cap_stream *cap_stream); + void (*_cap_initiator_enabled)(struct bt_cap_stream *cap_stream); + void (*_cap_initiator_connected)(struct bt_cap_stream *cap_stream); + void (*_cap_initiator_started)(struct bt_cap_stream *cap_stream); + void (*_cap_initiator_metadata_updated)(struct bt_cap_stream *cap_stream); + void (*_cap_initiator_disabled)(struct bt_cap_stream *cap_stream); + void (*_cap_initiator_stopped)(struct bt_cap_stream *cap_stream); + void (*_cap_initiator_released)(struct bt_cap_stream *cap_stream); + + /* CAP Handover */ + bool (*_cap_common_handover_is_active)(void); + bool (*_cap_handover_is_handover_broadcast_source)(const struct bt_cap_broadcast_source *cap_broadcast_source); + void (*_cap_handover_complete)(void); + void (*_cap_handover_unicast_proc_complete)(void); + void (*_cap_handover_broadcast_source_stopped)(uint8_t reason); + void (*_cap_handover_unicast_to_broadcast_reception_start)(void); + int (*_cap_handover_broadcast_reception_stopped)(void); + void (*_cap_handover_receive_state_updated)(const struct bt_conn *conn, + const struct bt_bap_scan_delegator_recv_state *state); + + /* CAP Stream */ + void (*_cap_stream_configured_cb)(struct bt_bap_stream *bap_stream, + const struct bt_bap_qos_cfg_pref *pref); + void (*_cap_stream_qos_set_cb)(struct bt_bap_stream *bap_stream); + void (*_cap_stream_enabled_cb)(struct bt_bap_stream *bap_stream); + void (*_cap_stream_metadata_updated_cb)(struct bt_bap_stream *bap_stream); + void (*_cap_stream_disabled_cb)(struct bt_bap_stream *bap_stream); + void (*_cap_stream_released_cb)(struct bt_bap_stream *bap_stream); + void (*_cap_stream_recv_cb)(struct bt_bap_stream *bap_stream, + const struct bt_iso_recv_info *info, + const uint8_t *data, uint16_t len); + void (*_cap_stream_sent_cb)(struct bt_bap_stream *bap_stream, void *user_data); + + /* MCC */ + void (*_mcc_on_obj_selected)(struct bt_ots_client *otc_inst, + struct bt_conn *conn, int result); + int (*_mcc_on_icon_content)(struct bt_ots_client *otc_inst, + struct bt_conn *conn, + uint32_t offset, uint32_t len, + uint8_t *data_p, bool is_complete); + void (*_mcc_on_object_metadata)(struct bt_ots_client *otc_inst, + struct bt_conn *conn, int err, + uint8_t metadata_read); + + /* MCS */ + struct bt_ots *(*_mcs_get_ots)(void); + void (*_mcs_media_proxy_sctrl_current_track_id_cb)(uint64_t id); + void (*_mcs_media_proxy_sctrl_next_track_id_cb)(uint64_t id); + void (*_mcs_media_proxy_sctrl_parent_group_id_cb)(uint64_t id); + void (*_mcs_media_proxy_sctrl_current_group_id_cb)(uint64_t id); + void (*_mcs_media_proxy_sctrl_search_cb)(uint8_t result_code); + void (*_mcs_media_proxy_sctrl_search_results_id_cb)(uint64_t id); + void (*_mcs_svc_inc_init)(void); + void (*_mcs_chrc_icon_obj_id_init)(void); + void (*_mcs_chrc_track_segments_obj_id_init)(void); + void (*_mcs_chrc_current_track_obj_id_init)(void); + void (*_mcs_chrc_next_track_obj_id_init)(void); + void (*_mcs_chrc_parent_group_obj_id_init)(void); + void (*_mcs_chrc_current_group_obj_id_init)(void); + void (*_mcs_chrc_search_control_point_init)(void); + void (*_mcs_chrc_search_results_obj_id_init)(void); + + /* Media Proxy */ + uint64_t (*_media_proxy_sctrl_get_icon_id)(void); + uint64_t (*_media_proxy_sctrl_get_track_segments_id)(void); + uint64_t (*_media_proxy_sctrl_get_current_track_id)(void); + void (*_media_proxy_sctrl_set_current_track_id)(uint64_t id); + uint64_t (*_media_proxy_sctrl_get_next_track_id)(void); + void (*_media_proxy_sctrl_set_next_track_id)(uint64_t id); + uint64_t (*_media_proxy_sctrl_get_parent_group_id)(void); + uint64_t (*_media_proxy_sctrl_get_current_group_id)(void); + void (*_media_proxy_sctrl_set_current_group_id)(uint64_t id); + void (*_media_proxy_sctrl_send_search)(const struct mpl_search *search); + uint64_t (*_media_proxy_sctrl_get_search_results_id)(void); + void (*_media_proxy_pl_current_track_id_cb)(uint64_t id); + void (*_media_proxy_pl_next_track_id_cb)(uint64_t id); + void (*_media_proxy_pl_parent_group_id_cb)(uint64_t id); + void (*_media_proxy_pl_current_group_id_cb)(uint64_t id); + void (*_media_proxy_pl_search_cb)(uint8_t result_code); + void (*_media_proxy_pl_search_results_id_cb)(uint64_t id); + + /* MICP Microphone Controller */ + uint8_t (*_micp_discover_include_func)(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params); + int (*_micp_mic_ctrl_aics_init)(void); + + /* MICP Microphone Device */ + int (*_micp_mic_dev_prepare_aics_inst)(struct bt_micp_mic_dev_register_param *param); + + /* MPL */ + uint64_t (*_mpl_get_icon_id)(void); + uint64_t (*_mpl_get_track_segments_id)(void); + uint64_t (*_mpl_get_current_track_id)(void); + void (*_mpl_set_current_track_id)(uint64_t id); + uint64_t (*_mpl_get_next_track_id)(void); + void (*_mpl_set_next_track_id)(uint64_t id); + uint64_t (*_mpl_get_parent_group_id)(void); + uint64_t (*_mpl_get_current_group_id)(void); + void (*_mpl_set_current_group_id)(uint64_t id); + void (*_mpl_send_search)(const struct mpl_search *search); + uint64_t (*_mpl_get_search_results_id)(void); + + /* TBS Client */ + int (*_tbs_client_primary_discover_tbs)(struct bt_conn *conn); + int (*_tbs_client_primary_discover_gtbs)(struct bt_conn *conn); + struct bt_tbs_instance *(*_tbs_client_get_by_ccid)(const struct bt_conn *conn, + uint8_t ccid); + + /* VCP Volume Controller */ + void (*_vcp_vol_ctlr_aics_init)(void); + void (*_vcp_vol_ctlr_vocs_init)(void); + uint8_t (*_vcp_vol_ctlr_vcs_discover_include_func)(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params); + int (*_vcp_vol_ctlr_included_get)(struct bt_vcp_vol_ctlr *vol_ctlr, + struct bt_vcp_included *included); + + /* VCP Volume Renderer */ + int (*_vcp_vol_rend_prepare_aics_inst)(struct bt_vcp_vol_rend_register_param *param); + int (*_vcp_vol_rend_prepare_vocs_inst)(struct bt_vcp_vol_rend_register_param *param); + + /* VOCS Client */ + int (*_vocs_client_state_get)(struct bt_vocs_client *inst); + int (*_vocs_client_state_set)(struct bt_vocs_client *inst, int16_t offset); + int (*_vocs_client_location_get)(struct bt_vocs_client *inst); + int (*_vocs_client_location_set)(struct bt_vocs_client *inst, uint32_t location); + int (*_vocs_client_description_get)(struct bt_vocs_client *inst); + int (*_vocs_client_description_set)(struct bt_vocs_client *inst, const char *description); +}; + +static const struct lib_funcs lib_funcs = { +#if CONFIG_BT_AICS_CLIENT + ._aics_client_state_get = lib_aics_client_state_get, + ._aics_client_gain_setting_get = lib_aics_client_gain_setting_get, + ._aics_client_type_get = lib_aics_client_type_get, + ._aics_client_status_get = lib_aics_client_status_get, + ._aics_client_unmute = lib_aics_client_unmute, + ._aics_client_mute = lib_aics_client_mute, + ._aics_client_manual_gain_set = lib_aics_client_manual_gain_set, + ._aics_client_automatic_gain_set = lib_aics_client_automatic_gain_set, + ._aics_client_gain_set = lib_aics_client_gain_set, + ._aics_client_description_get = lib_aics_client_description_get, + ._aics_client_description_set = lib_aics_client_description_set, +#endif /* CONFIG_BT_AICS_CLIENT */ + +#if CONFIG_BT_BAP_BROADCAST_SINK + ._bap_broadcast_sink_has_ep = lib_bap_broadcast_sink_has_ep, +#endif /* CONFIG_BT_BAP_BROADCAST_SINK */ + +#if CONFIG_BT_BAP_BROADCAST_SOURCE + ._bap_broadcast_source_has_ep = lib_bap_broadcast_source_has_ep, +#endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */ + +#if CONFIG_BT_BAP_UNICAST_CLIENT + ._bap_unicast_client_has_ep = lib_bap_unicast_client_has_ep, + ._bap_unicast_client_register_cb = lib_bap_unicast_client_register_cb, + ._bap_unicast_client_config = lib_bap_unicast_client_config, + ._bap_unicast_client_metadata = lib_bap_unicast_client_metadata, + ._bap_unicast_client_connect = lib_bap_unicast_client_connect, + ._bap_unicast_client_start = lib_bap_unicast_client_start, + ._bap_unicast_client_disable = lib_bap_unicast_client_disable, + ._bap_unicast_client_release = lib_bap_unicast_client_release, +#endif /* CONFIG_BT_BAP_UNICAST_CLIENT */ + +#if CONFIG_BT_BAP_UNICAST_SERVER + ._bap_unicast_server_has_ep = lib_bap_unicast_server_has_ep, + ._bap_unicast_server_reconfig = lib_bap_unicast_server_reconfig, + ._bap_unicast_server_start = lib_bap_unicast_server_start, + ._bap_unicast_server_metadata = lib_bap_unicast_server_metadata, + ._bap_unicast_server_disable = lib_bap_unicast_server_disable, + ._bap_unicast_server_release = lib_bap_unicast_server_release, +#endif /* CONFIG_BT_BAP_UNICAST_SERVER */ + +#if CONFIG_BT_CAP_ACCEPTOR + ._cap_acceptor_ccids_exist = lib_cap_acceptor_ccids_exist, +#endif /* CONFIG_BT_CAP_ACCEPTOR */ + +#if CONFIG_BT_CAP_INITIATOR_UNICAST + ._cap_common_set_subproc = lib_cap_common_set_subproc, + ._cap_common_proc_is_type = lib_cap_common_proc_is_type, + ._cap_common_subproc_is_type = lib_cap_common_subproc_is_type, + ._cap_initiator_cp_cb = lib_cap_initiator_cp_cb, + ._cap_initiator_codec_configured = lib_cap_initiator_codec_configured, + ._cap_initiator_qos_configured = lib_cap_initiator_qos_configured, + ._cap_initiator_enabled = lib_cap_initiator_enabled, + ._cap_initiator_connected = lib_cap_initiator_connected, + ._cap_initiator_started = lib_cap_initiator_started, + ._cap_initiator_metadata_updated = lib_cap_initiator_metadata_updated, + ._cap_initiator_disabled = lib_cap_initiator_disabled, + ._cap_initiator_stopped = lib_cap_initiator_stopped, + ._cap_initiator_released = lib_cap_initiator_released, +#endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */ + +#if CONFIG_BT_CAP_HANDOVER + ._cap_common_handover_is_active = lib_cap_common_handover_is_active, + ._cap_handover_is_handover_broadcast_source = lib_cap_handover_is_handover_broadcast_source, + ._cap_handover_complete = lib_cap_handover_complete, + ._cap_handover_unicast_proc_complete = lib_cap_handover_unicast_proc_complete, + ._cap_handover_broadcast_source_stopped = lib_cap_handover_broadcast_source_stopped, + ._cap_handover_unicast_to_broadcast_reception_start = lib_cap_handover_unicast_to_broadcast_reception_start, + ._cap_handover_broadcast_reception_stopped = lib_cap_handover_broadcast_reception_stopped, + ._cap_handover_receive_state_updated = lib_cap_handover_receive_state_updated, +#endif /* CONFIG_BT_CAP_HANDOVER */ + +#if CONFIG_BT_CAP && CONFIG_BT_BAP_UNICAST + ._cap_stream_configured_cb = lib_cap_stream_configured_cb, + ._cap_stream_qos_set_cb = lib_cap_stream_qos_set_cb, + ._cap_stream_enabled_cb = lib_cap_stream_enabled_cb, + ._cap_stream_metadata_updated_cb = lib_cap_stream_metadata_updated_cb, + ._cap_stream_disabled_cb = lib_cap_stream_disabled_cb, + ._cap_stream_released_cb = lib_cap_stream_released_cb, +#endif /* CONFIG_BT_CAP && CONFIG_BT_BAP_UNICAST */ + +#if CONFIG_BT_CAP && CONFIG_BT_AUDIO_RX + ._cap_stream_recv_cb = lib_cap_stream_recv_cb, +#endif /* CONFIG_BT_CAP && CONFIG_BT_AUDIO_RX */ + +#if CONFIG_BT_CAP && CONFIG_BT_AUDIO_TX + ._cap_stream_sent_cb = lib_cap_stream_sent_cb, +#endif /* CONFIG_BT_CAP && CONFIG_BT_AUDIO_TX */ + +#if CONFIG_BT_MCC_OTS + ._mcc_on_obj_selected = lib_mcc_on_obj_selected, + ._mcc_on_icon_content = lib_mcc_on_icon_content, + ._mcc_on_object_metadata = lib_mcc_on_object_metadata, +#endif /* CONFIG_BT_MCC_OTS */ + +#if CONFIG_BT_MCS && CONFIG_BT_OTS + ._mcs_get_ots = lib_mcs_get_ots, + ._mcs_media_proxy_sctrl_current_track_id_cb = lib_mcs_media_proxy_sctrl_current_track_id_cb, + ._mcs_media_proxy_sctrl_next_track_id_cb = lib_mcs_media_proxy_sctrl_next_track_id_cb, + ._mcs_media_proxy_sctrl_parent_group_id_cb = lib_mcs_media_proxy_sctrl_parent_group_id_cb, + ._mcs_media_proxy_sctrl_current_group_id_cb = lib_mcs_media_proxy_sctrl_current_group_id_cb, + ._mcs_media_proxy_sctrl_search_cb = lib_mcs_media_proxy_sctrl_search_cb, + ._mcs_media_proxy_sctrl_search_results_id_cb = lib_mcs_media_proxy_sctrl_search_results_id_cb, + ._mcs_svc_inc_init = lib_mcs_svc_inc_init, + ._mcs_chrc_icon_obj_id_init = lib_mcs_chrc_icon_obj_id_init, + ._mcs_chrc_track_segments_obj_id_init = lib_mcs_chrc_track_segments_obj_id_init, + ._mcs_chrc_current_track_obj_id_init = lib_mcs_chrc_current_track_obj_id_init, + ._mcs_chrc_next_track_obj_id_init = lib_mcs_chrc_next_track_obj_id_init, + ._mcs_chrc_parent_group_obj_id_init = lib_mcs_chrc_parent_group_obj_id_init, + ._mcs_chrc_current_group_obj_id_init = lib_mcs_chrc_current_group_obj_id_init, + ._mcs_chrc_search_control_point_init = lib_mcs_chrc_search_control_point_init, + ._mcs_chrc_search_results_obj_id_init = lib_mcs_chrc_search_results_obj_id_init, +#endif /* CONFIG_BT_MCS && CONFIG_BT_OTS */ + +#if CONFIG_BT_MPL_OBJECTS + ._media_proxy_sctrl_get_icon_id = lib_media_proxy_sctrl_get_icon_id, + ._media_proxy_sctrl_get_track_segments_id = lib_media_proxy_sctrl_get_track_segments_id, + ._media_proxy_sctrl_get_current_track_id = lib_media_proxy_sctrl_get_current_track_id, + ._media_proxy_sctrl_set_current_track_id = lib_media_proxy_sctrl_set_current_track_id, + ._media_proxy_sctrl_get_next_track_id = lib_media_proxy_sctrl_get_next_track_id, + ._media_proxy_sctrl_set_next_track_id = lib_media_proxy_sctrl_set_next_track_id, + ._media_proxy_sctrl_get_parent_group_id = lib_media_proxy_sctrl_get_parent_group_id, + ._media_proxy_sctrl_get_current_group_id = lib_media_proxy_sctrl_get_current_group_id, + ._media_proxy_sctrl_set_current_group_id = lib_media_proxy_sctrl_set_current_group_id, + ._media_proxy_sctrl_send_search = lib_media_proxy_sctrl_send_search, + ._media_proxy_sctrl_get_search_results_id = lib_media_proxy_sctrl_get_search_results_id, + ._media_proxy_pl_current_track_id_cb = lib_media_proxy_pl_current_track_id_cb, + ._media_proxy_pl_next_track_id_cb = lib_media_proxy_pl_next_track_id_cb, + ._media_proxy_pl_parent_group_id_cb = lib_media_proxy_pl_parent_group_id_cb, + ._media_proxy_pl_current_group_id_cb = lib_media_proxy_pl_current_group_id_cb, + ._media_proxy_pl_search_cb = lib_media_proxy_pl_search_cb, + ._media_proxy_pl_search_results_id_cb = lib_media_proxy_pl_search_results_id_cb, +#endif /* CONFIG_BT_MPL_OBJECTS */ + +#if CONFIG_BT_MICP_MIC_CTLR_AICS + ._micp_discover_include_func = lib_micp_discover_include_func, + ._micp_mic_ctrl_aics_init = lib_micp_mic_ctrl_aics_init, +#endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */ + +#if CONFIG_BT_MICP_MIC_DEV_AICS + ._micp_mic_dev_prepare_aics_inst = lib_micp_mic_dev_prepare_aics_inst, +#endif /* CONFIG_BT_MICP_MIC_DEV_AICS */ + +#if CONFIG_BT_MPL_OBJECTS + ._mpl_get_icon_id = lib_mpl_get_icon_id, + ._mpl_get_track_segments_id = lib_mpl_get_track_segments_id, + ._mpl_get_current_track_id = lib_mpl_get_current_track_id, + ._mpl_set_current_track_id = lib_mpl_set_current_track_id, + ._mpl_get_next_track_id = lib_mpl_get_next_track_id, + ._mpl_set_next_track_id = lib_mpl_set_next_track_id, + ._mpl_get_parent_group_id = lib_mpl_get_parent_group_id, + ._mpl_get_current_group_id = lib_mpl_get_current_group_id, + ._mpl_set_current_group_id = lib_mpl_set_current_group_id, + ._mpl_send_search = lib_mpl_send_search, + ._mpl_get_search_results_id = lib_mpl_get_search_results_id, +#endif /* CONFIG_BT_MPL_OBJECTS */ + +#if CONFIG_BT_TBS_CLIENT_TBS + ._tbs_client_primary_discover_tbs = lib_tbs_client_primary_discover_tbs, +#endif /* CONFIG_BT_TBS_CLIENT_TBS */ + +#if CONFIG_BT_TBS_CLIENT_GTBS + ._tbs_client_primary_discover_gtbs = lib_tbs_client_primary_discover_gtbs, +#endif /* CONFIG_BT_TBS_CLIENT_GTBS */ + +#if CONFIG_BT_TBS_CLIENT_CCID + ._tbs_client_get_by_ccid = lib_tbs_client_get_by_ccid, +#endif /* CONFIG_BT_TBS_CLIENT_CCID */ + +#if CONFIG_BT_VCP_VOL_CTLR_AICS + ._vcp_vol_ctlr_aics_init = lib_vcp_vol_ctlr_aics_init, +#endif /* CONFIG_BT_VCP_VOL_CTLR_AICS */ + +#if CONFIG_BT_VCP_VOL_CTLR_VOCS + ._vcp_vol_ctlr_vocs_init = lib_vcp_vol_ctlr_vocs_init, +#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */ + +#if CONFIG_BT_VCP_VOL_CTLR_AICS || CONFIG_BT_VCP_VOL_CTLR_VOCS + ._vcp_vol_ctlr_vcs_discover_include_func = lib_vcp_vol_ctlr_vcs_discover_include_func, + ._vcp_vol_ctlr_included_get = lib_vcp_vol_ctlr_included_get, +#endif /* CONFIG_BT_VCP_VOL_CTLR_AICS || CONFIG_BT_VCP_VOL_CTLR_VOCS */ + +#if (CONFIG_BT_VCP_VOL_REND_AICS_INSTANCE_COUNT > 0) + ._vcp_vol_rend_prepare_aics_inst = lib_vcp_vol_rend_prepare_aics_inst, +#endif /* (CONFIG_BT_VCP_VOL_REND_AICS_INSTANCE_COUNT > 0) */ + +#if (CONFIG_BT_VCP_VOL_REND_VOCS_INSTANCE_COUNT > 0) + ._vcp_vol_rend_prepare_vocs_inst = lib_vcp_vol_rend_prepare_vocs_inst, +#endif /* (CONFIG_BT_VCP_VOL_REND_VOCS_INSTANCE_COUNT > 0) */ + +#if CONFIG_BT_VOCS_CLIENT + ._vocs_client_state_get = lib_vocs_client_state_get, + ._vocs_client_state_set = lib_vocs_client_state_set, + ._vocs_client_location_get = lib_vocs_client_location_get, + ._vocs_client_location_set = lib_vocs_client_location_set, + ._vocs_client_description_get = lib_vocs_client_description_get, + ._vocs_client_description_set = lib_vocs_client_description_set, +#endif /* CONFIG_BT_VOCS_CLIENT */ +}; + +static int lib_resources_init(void) +{ + int err = 0; + +#if CONFIG_BT_AICS || CONFIG_BT_AICS_CLIENT + err = lib_aics_init(); + if (err) { + LOG_ERR("LibAicsInitFail"); + return err; + } +#endif /* CONFIG_BT_AICS || CONFIG_BT_AICS_CLIENT */ + +#if CONFIG_BT_AICS_CLIENT + err = lib_aics_client_init(); + if (err) { + LOG_ERR("LibAicsCliInitFail"); + return err; + } +#endif /* CONFIG_BT_AICS_CLIENT */ + +#if CONFIG_BT_BAP_BASE + err = lib_bap_base_init(); + if (err) { + LOG_ERR("LibBapBaseInitFail"); + return err; + } +#endif /* CONFIG_BT_BAP_BASE */ + +#if CONFIG_BT_BAP_STREAM + err = lib_bap_iso_init(); + if (err) { + LOG_ERR("LibBapIsoInitFail"); + return err; + } + + err = lib_bap_stream_init(); + if (err) { + LOG_ERR("LibBapStreamInitFail"); + return err; + } +#endif /* CONFIG_BT_BAP_STREAM */ + +#if CONFIG_BT_ASCS + err = lib_ascs_init(); + if (err) { + LOG_ERR("LibAscsInitFail"); + return err; + } +#endif /* CONFIG_BT_ASCS */ + +#if CONFIG_BT_PACS + err = lib_pacs_init(); + if (err) { + LOG_ERR("LibPacsInitFail"); + return err; + } +#endif /* CONFIG_BT_PACS */ + +#if CONFIG_BT_BAP_BROADCAST_SINK + err = lib_bap_broadcast_sink_init(); + if (err) { + LOG_ERR("LibBapBsnkInitFail"); + return err; + } +#endif /* CONFIG_BT_BAP_BROADCAST_SINK */ + +#if CONFIG_BT_BAP_BROADCAST_SOURCE + err = lib_bap_broadcast_source_init(); + if (err) { + LOG_ERR("LibBapBsrcInitFail"); + return err; + } +#endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */ + +#if CONFIG_BT_BAP_SCAN_DELEGATOR + err = lib_bap_scan_delegator_init(); + if (err) { + LOG_ERR("LibBapSdeInitFail"); + return err; + } +#endif /* CONFIG_BT_BAP_SCAN_DELEGATOR */ + +#if CONFIG_BT_BAP_BROADCAST_ASSISTANT + err = lib_bap_broadcast_assistant_init(); + if (err) { + LOG_ERR("LibBapBaInitFail"); + return err; + } +#endif /* CONFIG_BT_BAP_BROADCAST_ASSISTANT */ + +#if CONFIG_BT_BAP_UNICAST_CLIENT + err = lib_bap_unicast_client_init(); + if (err) { + LOG_ERR("LibBapUclInitFail"); + return err; + } +#endif /* CONFIG_BT_BAP_UNICAST_CLIENT */ + +#if CONFIG_BT_BAP_UNICAST_SERVER + err = lib_bap_unicast_server_init(); + if (err) { + LOG_ERR("LibBapUsrInitFail"); + return err; + } +#endif /* CONFIG_BT_BAP_UNICAST_SERVER */ + +#if CONFIG_BT_CAP_INITIATOR_UNICAST || CONFIG_BT_CAP_COMMANDER + err = lib_cap_common_init(); + if (err) { + LOG_ERR("LibCapCommonInitFail"); + return err; + } +#endif /* CONFIG_BT_CAP_INITIATOR_UNICAST || CONFIG_BT_CAP_COMMANDER */ + +#if CONFIG_BT_CAP + err = lib_cap_stream_init(); + if (err) { + LOG_ERR("LibCapStreamInitFail"); + return err; + } +#endif /* CONFIG_BT_CAP */ + +#if CONFIG_BT_CAP_INITIATOR + err = lib_cap_initiator_init(); + if (err) { + LOG_ERR("LibCapIniInitFail"); + return err; + } +#endif /* CONFIG_BT_CAP_INITIATOR */ + +#if CONFIG_BT_CAP_ACCEPTOR + err = lib_cap_acceptor_init(); + if (err) { + LOG_ERR("LibCapAccInitFail"); + return err; + } +#endif /* CONFIG_BT_CAP_ACCEPTOR */ + +#if CONFIG_BT_CAP_COMMANDER + err = lib_cap_commander_init(); + if (err) { + LOG_ERR("LibCapComInitFail"); + return err; + } +#endif /* CONFIG_BT_CAP_COMMANDER */ + + err = lib_ccid_init(); + if (err) { + LOG_ERR("LibCcidInitFail"); + return err; + } + +#if CONFIG_BT_CCP_CALL_CONTROL_CLIENT + err = lib_ccp_call_control_client_init(); + if (err) { + LOG_ERR("LibCcpCallControlClientInitFail"); + return err; + } +#endif /* CONFIG_BT_CCP_CALL_CONTROL_CLIENT */ + +#if CONFIG_BT_CCP_CALL_CONTROL_SERVER + err = lib_ccp_call_control_server_init(); + if (err) { + LOG_ERR("LibCcpCallControlServerInitFail"); + return err; + } +#endif /* CONFIG_BT_CCP_CALL_CONTROL_SERVER */ + +#if CONFIG_BT_BAP_STREAM + err = lib_codec_init(); + if (err) { + LOG_ERR("LibCodecInitFail"); + return err; + } +#endif /* CONFIG_BT_BAP_STREAM */ + +#if CONFIG_BT_CSIP_SET_MEMBER + err = lib_csip_set_member_init(); + if (err) { + LOG_ERR("LibCsipSetMemberInitFail"); + return err; + } +#endif /* CONFIG_BT_CSIP_SET_MEMBER */ + +#if CONFIG_BT_CSIP_SET_COORDINATOR + err = lib_csip_set_coordinator_init(); + if (err) { + LOG_ERR("LibCsipSetCoordinatorInitFail"); + return err; + } +#endif /* CONFIG_BT_CSIP_SET_COORDINATOR */ + +#if CONFIG_BT_MCC + err = lib_mcc_init(); + if (err) { + LOG_ERR("LibMccInitFail"); + return err; + } +#endif /* CONFIG_BT_MCC */ + +#if CONFIG_BT_MCS + err = lib_mcs_init(); + if (err) { + LOG_ERR("LibMcsInitFail"); + return err; + } +#endif /* CONFIG_BT_MCS */ + +#if CONFIG_BT_MCTL + err = lib_media_proxy_init(); + if (err) { + LOG_ERR("LibMprxInitFail"); + return err; + } +#endif /* CONFIG_BT_MCTL */ + +#if CONFIG_BT_MICP_MIC_CTLR + err = lib_micp_mic_ctlr_init(); + if (err) { + LOG_ERR("LibMicpMicCtlrInitFail"); + return err; + } +#endif /* CONFIG_BT_MICP_MIC_CTLR */ + +#if CONFIG_BT_MICP_MIC_DEV + err = lib_micp_mic_dev_init(); + if (err) { + LOG_ERR("LibMicpMicDevInitFail"); + return err; + } +#endif /* CONFIG_BT_MICP_MIC_DEV */ + +#if CONFIG_BT_MPL + err = lib_mpl_init(); + if (err) { + LOG_ERR("LibMplInitFail"); + return err; + } +#endif /* CONFIG_BT_MPL */ + +#if CONFIG_BT_PBP + err = lib_pbp_init(); + if (err) { + LOG_ERR("LibPbpInitFail"); + return err; + } +#endif /* CONFIG_BT_PBP */ + +#if CONFIG_BT_TBS_CLIENT + err = lib_tbs_client_init(); + if (err) { + LOG_ERR("LibTbsCliInitFail"); + return err; + } +#endif /* CONFIG_BT_TBS_CLIENT */ + +#if CONFIG_BT_TBS + err = lib_tbs_init(); + if (err) { + LOG_ERR("LibTbsInitFail"); + return err; + } +#endif /* CONFIG_BT_TBS */ + +#if CONFIG_BT_TMAP + err = lib_tmap_init(); + if (err) { + LOG_ERR("LibTmapInitFail"); + return err; + } +#endif /* CONFIG_BT_TMAP */ + +#if CONFIG_BT_VCP_VOL_CTLR + err = lib_vcp_vol_ctlr_init(); + if (err) { + LOG_ERR("LibVcpVolCtlrInitFail"); + return err; + } +#endif /* CONFIG_BT_VCP_VOL_CTLR */ + +#if CONFIG_BT_VCP_VOL_REND + err = lib_vcp_vol_rend_init(); + if (err) { + LOG_ERR("LibVcpVolRendInitFail"); + return err; + } +#endif /* CONFIG_BT_VCP_VOL_REND */ + +#if CONFIG_BT_VOCS || CONFIG_BT_VOCS_CLIENT + err = lib_vocs_init(); + if (err) { + LOG_ERR("LibVocsInitFail"); + return err; + } +#endif /* CONFIG_BT_VOCS || CONFIG_BT_VOCS_CLIENT */ + +#if CONFIG_BT_VOCS_CLIENT + err = lib_vocs_client_init(); + if (err) { + LOG_ERR("LibVocsClientInitFail"); + return err; + } +#endif /* CONFIG_BT_VOCS_CLIENT */ + +#if CONFIG_BT_HAS + err = lib_has_init(); + if (err) { + LOG_ERR("LibHasInitFail"); + return err; + } +#endif /* CONFIG_BT_HAS */ + +#if CONFIG_BT_HAS_CLIENT + err = lib_has_client_init(); + if (err) { + LOG_ERR("LibHasCliInitFail"); + return err; + } +#endif /* CONFIG_BT_HAS_CLIENT */ + +#if CONFIG_BT_GMAP + err = lib_gmap_client_init(); + if (err) { + LOG_ERR("LibGmapCliInitFail"); + return err; + } +#endif /* CONFIG_BT_GMAP */ + + return err; +} + +int bt_le_audio_init(void) +{ + int err; + + err = lib_ext_structs_check(ext_structs, sizeof(ext_structs)); + if (err) { + LOG_ERR("LibExtStructsCheckFail"); + return err; + } + + err = lib_ext_cfgs_set(&ext_cfgs, sizeof(ext_cfgs)); + if (err) { + LOG_ERR("LibExtCfgsSetFail"); + return err; + } + + err = lib_ext_funcs_set(&ext_funcs, sizeof(ext_funcs)); + if (err) { + LOG_ERR("LibExtFuncsSetFail"); + return err; + } + + err = lib_funcs_set(&lib_funcs, sizeof(lib_funcs)); + if (err) { + LOG_ERR("LibFuncsSetFail"); + return err; + } + +#if 0 + lib_dymem_size_init(); +#endif + + printf(BT_ISO_LOG_COLOR_I "BLE Audio lib commit: [%s]" \ + BT_ISO_LOG_RESET_COLOR "\n", lib_ext_commit_get()); + + err = lib_resources_init(); + if (err) { + return err; + } + + return bt_le_nimble_audio_init(); +} + +#if BLE_AUDIO_SVC_SEP_ADD +#if CONFIG_BT_ASCS +int bt_le_ascs_init(void) +{ + LOG_DBG("AscsInit"); + + return bt_le_nimble_ascs_init(); +} +#endif /* CONFIG_BT_ASCS */ + +#if CONFIG_BT_BAP_SCAN_DELEGATOR +int bt_le_bass_init(void) +{ + LOG_DBG("BassInit"); + + return bt_le_nimble_bass_init(); +} +#endif /* CONFIG_BT_BAP_SCAN_DELEGATOR */ + +#if CONFIG_BT_TMAP +int bt_le_tmas_init(void) +{ + LOG_DBG("TmasInit"); + + return bt_le_nimble_tmas_init(); +} +#endif /* CONFIG_BT_TMAP */ + +#if CONFIG_BT_TBS +int bt_le_gtbs_init(void) +{ + LOG_DBG("GtbsInit"); + + return bt_le_nimble_gtbs_init(); +} +#endif /* CONFIG_BT_TBS */ + +#if CONFIG_BT_HAS +int bt_le_has_init(void) +{ + LOG_DBG("HasInit"); + + return bt_le_nimble_has_init(); +} +#endif /* CONFIG_BT_HAS */ + +#if CONFIG_BT_MCS +int bt_le_media_proxy_pl_init(void) +{ + LOG_DBG("MprxPlInit"); + + return bt_le_nimble_media_proxy_pl_init(); +} +#endif /* CONFIG_BT_MCS */ + +#if CONFIG_BT_VCP_VOL_REND +int bt_le_vcp_vol_rend_init(void) +{ + LOG_DBG("VcpVolRendInit"); + + return bt_le_nimble_vcp_vol_rend_init(); +} +#endif /* CONFIG_BT_VCP_VOL_REND */ + +#if CONFIG_BT_MICP_MIC_DEV +int bt_le_micp_mic_dev_init(void) +{ + LOG_DBG("MicpMicDevInit"); + + return bt_le_nimble_micp_mic_dev_init(); +} +#endif /* CONFIG_BT_MICP_MIC_DEV */ +#endif /* BLE_AUDIO_SVC_SEP_ADD */ + +int bt_le_audio_start(void *info) +{ + LOG_DBG("AudioStart"); + + return bt_le_nimble_audio_start(info); +} diff --git a/components/bt/esp_ble_audio/host/common/init.h b/components/bt/esp_ble_audio/host/common/init.h new file mode 100644 index 0000000000..6f4418e645 --- /dev/null +++ b/components/bt/esp_ble_audio/host/common/init.h @@ -0,0 +1,64 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef HOST_COMMON_INIT_H_ +#define HOST_COMMON_INIT_H_ + +#include + +#include "sdkconfig.h" + +#include "../../../lib/include/audio.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define BLE_AUDIO_SVC_SEP_ADD 0 /* Indicate if adding LE Audio services separately */ + +/* Minimum value required by BAP. + * 64 octets is not enough for running 4 ASEs. + * Hence use 128 as the default value here. + */ +#define BLE_AUDIO_ATT_MTU_MIN 128 + +struct bt_csip_set_member_svc_inst; + +struct bt_le_audio_start_info { +#if CONFIG_BT_CSIP_SET_MEMBER + struct { + struct bt_csip_set_member_svc_inst *svc_inst; + bool included_by_cas; + } csis_insts[CONFIG_BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT]; +#endif /* CONFIG_BT_CSIP_SET_MEMBER */ + uint8_t dummy; /*!< Dummy field to avoid empty struct */ +}; + +int bt_le_audio_init(void); + +int bt_le_ascs_init(void); + +int bt_le_bass_init(void); + +int bt_le_tmas_init(void); + +int bt_le_gtbs_init(void); + +int bt_le_has_init(void); + +int bt_le_media_proxy_pl_init(void); + +int bt_le_vcp_vol_rend_init(void); + +int bt_le_micp_mic_dev_init(void); + +int bt_le_audio_start(void *info); + +#ifdef __cplusplus +} +#endif + +#endif /* HOST_COMMON_INIT_H_ */ diff --git a/components/bt/esp_ble_audio/host/common/iso.c b/components/bt/esp_ble_audio/host/common/iso.c new file mode 100644 index 0000000000..7b54364aa8 --- /dev/null +++ b/components/bt/esp_ble_audio/host/common/iso.c @@ -0,0 +1,844 @@ +/* + * SPDX-FileCopyrightText: 2015-2016 Intel Corporation + * SPDX-FileCopyrightText: 2023 Nordic Semiconductor + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include <../host/conn_internal.h> +#include <../host/iso_internal.h> +#include <../host/hci_core.h> + +#include "common/host.h" +#include "common/task.h" +#include "common/app/gap.h" + +#ifdef CONFIG_BT_NIMBLE_ISO_STD_FLOW_CTRL +#define ISO_STD_FLOW_CTRL true +#else /* CONFIG_BT_NIMBLE_ISO_STD_FLOW_CTRL */ +#define ISO_STD_FLOW_CTRL false +#endif /* CONFIG_BT_NIMBLE_ISO_STD_FLOW_CTRL */ + +#define ISO_PKT_FIRST_FRAG (0b00) +#define ISO_PKT_CONT_FRAG (0b01) +#define ISO_PKT_COMP_SDU (0b10) +#define ISO_PKT_LAST_FRAG (0b11) + +#define BT_LE_FEAT_SET(feat, n) (feat[(n) >> 3] |= BIT((n) & 7)) +#define BT_LE_FEAT_UNSET(feat, n) (feat[(n) >> 3] &= ~BIT((n) & 7)) + +static sys_slist_t iso_cbs = SYS_SLIST_STATIC_INIT(&iso_cbs); + +#if CONFIG_BT_ISO_UNICAST +static void hci_le_cis_disconnected(struct net_buf *buf); +#endif /* CONFIG_BT_ISO_UNICAST */ + +#if CONFIG_BT_ISO_TX +static void iso_tx_sdu_clear(uint16_t conn_handle, bool is_big); +#endif /* CONFIG_BT_ISO_TX */ + +extern void hci_le_biginfo_adv_report(struct net_buf *buf); + +static struct bt_le_iso_cb iso_cb = { +#if CONFIG_BT_ISO_UNICAST + .cis_dis = hci_le_cis_disconnected, + .cis_est = hci_le_cis_established, +#if CONFIG_BT_ISO_PERIPHERAL + .cis_req = hci_le_cis_req, +#endif /* CONFIG_BT_ISO_PERIPHERAL */ +#endif /* CONFIG_BT_ISO_UNICAST */ +#if CONFIG_BT_ISO_BROADCASTER + .big_create = hci_le_big_complete, + .big_term = hci_le_big_terminate, +#endif /* CONFIG_BT_ISO_BROADCASTER */ +#if CONFIG_BT_ISO_SYNC_RECEIVER + .big_est = hci_le_big_sync_established, + .big_lost = hci_le_big_sync_lost, + .biginfo = hci_le_biginfo_adv_report, +#endif /* CONFIG_BT_ISO_SYNC_RECEIVER */ +}; + +bool iso_log_enable = true; +bool iso_hw_log_enable = true; +bool isoal_post_lost = true; + +extern uint16_t r_ble_ll_iso_free_buf_num_get(uint16_t conn_handle); +extern int r_ble_hci_trans_hs_iso_tx(const uint8_t *data, uint16_t length, void *arg); +extern void r_ble_ll_isoal_tx_comp_cb_set(void *cb); + +_IDF_ONLY +int bt_le_iso_cb_register_safe(struct bt_le_iso_cb *cb) +{ + int err = 0; + + LOG_DBG("IsoCbReg"); + + if (cb == NULL) { + LOG_ERR("IsoCbNull"); + return -EINVAL; + } + + bt_le_host_lock(); + + if (sys_slist_find(&iso_cbs, &cb->node, NULL)) { + LOG_WRN("IsoCbExist"); + err = -EEXIST; + goto end; + } + + sys_slist_append(&iso_cbs, &cb->node); + +end: + bt_le_host_unlock(); + + return err; +} + +_IDF_ONLY +void bt_le_iso_cb_unregister_safe(struct bt_le_iso_cb *cb) +{ + LOG_DBG("IsoCbUnreg"); + + if (cb == NULL) { + LOG_ERR("IsoCbNull"); + return; + } + + bt_le_host_lock(); + sys_slist_find_and_remove(&iso_cbs, &cb->node); + bt_le_host_unlock(); +} + +#if CONFIG_BT_ISO_UNICAST +static void hci_le_cis_disconnected(struct net_buf *buf) +{ + struct bt_hci_evt_disconn_complete *evt = (void *)buf->data; + struct bt_conn *iso; + + LOG_DBG("CisDisconnectedEvt[%u]", evt->handle); + + iso = bt_conn_lookup_handle(evt->handle, BT_CONN_TYPE_ISO); + assert(iso); + + iso->err = evt->reason; + + bt_iso_disconnected(iso); + bt_conn_unref(iso); +} + +static int iso_cis_disconn_evt_listener_safe(uint8_t *data) +{ + struct bt_le_iso_cb *listener = NULL; + struct net_buf buf = {0}; + + LOG_DBG("CisDisconnEvtListener"); + + bt_le_host_lock(); + + SYS_SLIST_FOR_EACH_CONTAINER(&iso_cbs, listener, node) { + if (listener->cis_dis) { + buf.data = data; + listener->cis_dis(&buf); + } + } + +#if CONFIG_BT_ISO_TX + iso_tx_sdu_clear(sys_get_le16(data + 1), false); +#endif /* CONFIG_BT_ISO_TX */ + + bt_le_host_unlock(); + + return 0; +} + +static int iso_cis_est_evt_listener_safe(uint8_t *data) +{ + struct bt_le_iso_cb *listener = NULL; + struct net_buf buf = {0}; + + LOG_DBG("CisEstEvtListener"); + + bt_le_host_lock(); + + SYS_SLIST_FOR_EACH_CONTAINER(&iso_cbs, listener, node) { + if (listener->cis_est) { + buf.data = data + 1; /* The first octet is subev_code */ + listener->cis_est(&buf); + } + } + + bt_le_host_unlock(); + + return 0; +} + +#if CONFIG_BT_ISO_PERIPHERAL +static int iso_cis_req_evt_listener_safe(uint8_t *data) +{ + struct bt_le_iso_cb *listener = NULL; + struct net_buf buf = {0}; + + LOG_DBG("CisReqEvtListener"); + + bt_le_host_lock(); + + SYS_SLIST_FOR_EACH_CONTAINER(&iso_cbs, listener, node) { + if (listener->cis_req) { + buf.data = data + 1; /* The first octet is subev_code */ + listener->cis_req(&buf); + } + } + + bt_le_host_unlock(); + + return 0; +} +#endif /* CONFIG_BT_ISO_PERIPHERAL */ +#endif /* CONFIG_BT_ISO_UNICAST */ + +#if CONFIG_BT_ISO_BROADCASTER +static int iso_create_big_comp_evt_listener_safe(uint8_t *data) +{ + struct bt_le_iso_cb *listener = NULL; + struct net_buf buf = {0}; + + LOG_DBG("CreateBigCompEvtListener"); + + bt_le_host_lock(); + + SYS_SLIST_FOR_EACH_CONTAINER(&iso_cbs, listener, node) { + if (listener->big_create) { + buf.data = data + 1; /* The first octet is subev_code */ + listener->big_create(&buf); + } + } + + bt_le_host_unlock(); + + return 0; +} + +static int iso_term_big_comp_evt_listener_safe(uint8_t *data) +{ + struct bt_le_iso_cb *listener = NULL; + struct net_buf buf = {0}; + + LOG_DBG("TermBigCompEvtListener"); + + bt_le_host_lock(); + + SYS_SLIST_FOR_EACH_CONTAINER(&iso_cbs, listener, node) { + if (listener->big_term) { + buf.data = data + 1; /* The first octet is subev_code */ + listener->big_term(&buf); + } + } + + iso_tx_sdu_clear(data[1], true); + + bt_le_host_unlock(); + + return 0; +} +#endif /* CONFIG_BT_ISO_BROADCASTER */ + +#if CONFIG_BT_ISO_SYNC_RECEIVER +static int iso_big_sync_est_evt_listener_safe(uint8_t *data) +{ + struct bt_le_iso_cb *listener = NULL; + struct net_buf buf = {0}; + + LOG_DBG("BigSyncEstEvtListener"); + + bt_le_host_lock(); + + SYS_SLIST_FOR_EACH_CONTAINER(&iso_cbs, listener, node) { + if (listener->big_est) { + buf.data = data + 1; /* The first octet is subev_code */ + listener->big_est(&buf); + } + } + + bt_le_host_unlock(); + + return 0; +} + +static int iso_big_sync_lost_evt_listener_safe(uint8_t *data) +{ + struct bt_le_iso_cb *listener = NULL; + struct net_buf buf = {0}; + + LOG_DBG("BigSyncLostEvtListener"); + + bt_le_host_lock(); + + SYS_SLIST_FOR_EACH_CONTAINER(&iso_cbs, listener, node) { + if (listener->big_lost) { + buf.data = data + 1; /* The first octet is subev_code */ + listener->big_lost(&buf); + } + } + + bt_le_host_unlock(); + + return 0; +} + +static int iso_biginfo_adv_report_listener_safe(uint8_t *data) +{ + struct bt_le_iso_cb *listener = NULL; + struct net_buf buf = {0}; + + /* LOG_DBG("BigInfoAdvReportEvtListener"); */ + + bt_le_host_lock(); + + SYS_SLIST_FOR_EACH_CONTAINER(&iso_cbs, listener, node) { + if (listener->biginfo) { + buf.data = data + 1; /* The first octet is subev_code */ + listener->biginfo(&buf); + } + } + + bt_le_host_unlock(); + + /* The first octet is subev_code */ + bt_le_gap_app_biginfo_event(data + 1); + + return 0; +} +#endif /* CONFIG_BT_ISO_SYNC_RECEIVER */ + +static void handle_iso_event(uint8_t *data, size_t data_len) +{ + uint8_t event; + bool le_meta; + + /* Note: + * The data_len is guaranteed by the Host that it is exactly + * matching the expected length. + */ + + le_meta = data[0]; + event = data[1]; + + if (event != BT_HCI_EVT_LE_BIGINFO_ADV_REPORT) { + LOG_DBG("HandleIsoEvt[%u][%u]", le_meta, event); + } + +#if CONFIG_BT_ISO_UNICAST + if (le_meta == false) { + assert(event == BT_HCI_EVT_DISCONN_COMPLETE); + iso_cis_disconn_evt_listener_safe(data + 2); + return; + } +#else /* CONFIG_BT_ISO_UNICAST */ + ARG_UNUSED(le_meta); +#endif /* CONFIG_BT_ISO_UNICAST */ + + switch (event) { +#if CONFIG_BT_ISO_UNICAST + case BT_HCI_EVT_LE_CIS_ESTABLISHED: + iso_cis_est_evt_listener_safe(data + 2); + break; +#if CONFIG_BT_ISO_PERIPHERAL + case BT_HCI_EVT_LE_CIS_REQ: + iso_cis_req_evt_listener_safe(data + 2); + break; +#endif /* CONFIG_BT_ISO_PERIPHERAL */ +#endif /* CONFIG_BT_ISO_UNICAST */ +#if CONFIG_BT_ISO_BROADCASTER + case BT_HCI_EVT_LE_BIG_COMPLETE: + iso_create_big_comp_evt_listener_safe(data + 2); + break; + case BT_HCI_EVT_LE_BIG_TERMINATE: + iso_term_big_comp_evt_listener_safe(data + 2); + break; +#endif /* CONFIG_BT_ISO_BROADCASTER */ +#if CONFIG_BT_ISO_SYNC_RECEIVER + case BT_HCI_EVT_LE_BIG_SYNC_ESTABLISHED: + iso_big_sync_est_evt_listener_safe(data + 2); + break; + case BT_HCI_EVT_LE_BIG_SYNC_LOST: + iso_big_sync_lost_evt_listener_safe(data + 2); + break; + case BT_HCI_EVT_LE_BIGINFO_ADV_REPORT: + iso_biginfo_adv_report_listener_safe(data + 2); + break; +#endif /* CONFIG_BT_ISO_SYNC_RECEIVER */ + default: + assert(0); + break; + } +} + +void bt_le_iso_handle_hci_event(uint8_t *data, size_t data_len) +{ + assert(data && data_len); + handle_iso_event(data, data_len); + free(data); +} + +#if CONFIG_BT_ISO_TX +struct iso_tx_sdu_node { + struct bt_iso_chan *chan; + + const uint8_t *sdu; + uint16_t sdu_len; + + sys_snode_t node; +}; + +static sys_slist_t iso_tx_sdu_list = SYS_SLIST_STATIC_INIT(&iso_tx_sdu_list); + +static int iso_tx_sdu_insert(struct bt_iso_chan *chan, const uint8_t *sdu, uint16_t sdu_len) +{ + struct iso_tx_sdu_node *sdu_node; + + sdu_node = calloc(1, sizeof(*sdu_node)); + if (sdu_node == NULL) { + LOG_ERR("IsoTxInsertNoMem[%u]", sizeof(*sdu_node)); + return -ENOMEM; + } + + sdu_node->chan = chan; + sdu_node->sdu = sdu; + sdu_node->sdu_len = sdu_len; + + sys_slist_append(&iso_tx_sdu_list, &sdu_node->node); + + return 0; +} + +static void iso_tx_sdu_clear(uint16_t handle, bool is_big) +{ + struct iso_tx_sdu_node *sdu_node; + struct iso_tx_sdu_node *sdu_tmp; + struct bt_conn *iso; + sys_snode_t *prev; + + LOG_DBG("IsoTxSduClear[%u][%u]", handle, is_big); + + prev = NULL; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&iso_tx_sdu_list, sdu_node, sdu_tmp, node) { + iso = sdu_node->chan->iso; + + if ((is_big == false && iso->handle == handle) || + (is_big && iso->iso.info.type == BT_ISO_CHAN_TYPE_BROADCASTER && + iso->iso.info.broadcaster.big_handle == handle)) { + LOG_DBG("IsoSduRem[%u]", sdu_node->sdu_len); + + sys_slist_remove(&iso_tx_sdu_list, prev, &sdu_node->node); + + free((void *)sdu_node->sdu); + free(sdu_node); + + continue; + } + + prev = &sdu_node->node; + } +} + +static int validate_iso_send(struct bt_iso_chan *chan, struct net_buf *buf) +{ + if (chan == NULL || buf == NULL || + (buf->data == NULL && buf->len != 0)) { + LOG_ERR("InvSendParam[%p][%p]", chan, buf); + return -EINVAL; + } + + if (chan->state != BT_ISO_STATE_CONNECTED) { + LOG_ERR("ChanNotConn[%u]", chan->iso->handle); + return -ENOTCONN; + } + + if (chan->iso->iso.info.can_send == false) { + LOG_ERR("ChanNotSend[%u]", chan->iso->handle); + return -EINVAL; + } + + if (buf->len > chan->qos->tx->sdu) { + LOG_ERR("ChanCannotSend[%u][%u][%u]", + chan->iso->handle, buf->len, chan->qos->tx->sdu); + return -EMSGSIZE; + } + + return 0; +} + +static int iso_tx_now(struct bt_iso_chan *chan, const uint8_t *sdu, + uint16_t sdu_len, uint16_t seq_num, + uint32_t time_stamp, bool ts_valid) +{ + uint16_t data_total_len; + uint8_t pb_flag; + uint8_t *pkt; + int err; + + pb_flag = ISO_PKT_COMP_SDU; + data_total_len = (ts_valid ? 4 : 0) + 4 + sdu_len; + + /* From Spec: + * In the Host to Controller direction, Data_Total_Length shall + * be less than or equal to the size of buffer supported by the + * Controller (which is returned using the ISO_Data_Packet_Length + * return parameter of the LE Read Buffer Size command). + * + * TODO: + * Check if ISO SDU needs to be fragmented here. + */ + + pkt = malloc(4 + data_total_len); + if (pkt == NULL) { + LOG_ERR("IsoTxNoMem[%u]", 4 + data_total_len); + return -ENOMEM; + } + + sys_put_le16((ts_valid << 14) | (pb_flag << 12) | chan->iso->handle, pkt); + sys_put_le16(data_total_len, pkt + 2); + if (ts_valid) { + sys_put_le32(time_stamp, pkt + 4); + } + sys_put_le16(seq_num, pkt + (ts_valid ? 8 : 4)); + sys_put_le16(sdu_len, pkt + (ts_valid ? 10 : 6)); + + memcpy(pkt + (ts_valid ? 12 : 8), sdu, sdu_len); + +#if ISO_STD_FLOW_CTRL + /* TODO: + * - Use variables to record the ISO buffer size & count; + * - Check if the available ISO buffers are enough to hold the SDU; + */ +#else /* ISO_STD_FLOW_CTRL */ + /* If the list is not empty, which means some ISO SDUs ahead of this + * one are still waiting to be transmitted. In this case, this SDU + * must be appended in the list. + * + * If the list is empty, but no free buffer exists in the controller, + * then ISO flow control is triggered. + */ + if (sys_slist_is_empty(&iso_tx_sdu_list) == false || + r_ble_ll_iso_free_buf_num_get(chan->iso->handle) == 0) { + /* LOG_INF("IsoFlowCtrl!"); */ + err = iso_tx_sdu_insert(chan, pkt, 4 + data_total_len); + if (err) { + free(pkt); + } + return err; + } +#endif /* ISO_STD_FLOW_CTRL */ + + err = r_ble_hci_trans_hs_iso_tx(pkt, 4 + data_total_len, NULL); + if (err) { + /* err = -1: No BIS or CIS found; + * err = -2: Bad ISO packet; + * err = -3: Not able to send (e.g., CIS tx bn is 0, etc); + * err = -4: Not ready to send (e.g. BIS or CIS not established, DP not setup, etc.); + * err = -5: Last SDU fragment (generated over HCI) is failed to send; + * + * Note: + * The allocated pkt buffer will be freed in our controller. + * + * TODO: + * If using controller from other vendors, the pkt buffer may + * needs to be freed here. + */ + LOG_WRN("IsoTxFail[%d]", err); + return err; + } + +#if ISO_STD_FLOW_CTRL + /* TODO: + * - Decrease the available ISO buffer count; + * - Increase the available ISO buffer count once NoCP is received; + */ +#endif /* ISO_STD_FLOW_CTRL */ + + return 0; +} + +int bt_le_iso_tx(struct bt_iso_chan *chan, + struct net_buf *buf, + uint16_t seq_num, + uint32_t time_stamp, + bool ts_valid) +{ + int err; + + err = validate_iso_send(chan, buf); + if (err) { + return err; + } + + return iso_tx_now(chan, buf->data, buf->len, seq_num, time_stamp, ts_valid); +} + +struct iso_tx_comp_event { + uint16_t conn_handle; + struct bt_iso_tx_cb_info info; +}; + +void bt_le_iso_handle_tx_comp(uint8_t *data, size_t data_len) +{ + struct iso_tx_comp_event *evt = (struct iso_tx_comp_event *)data; + struct iso_tx_sdu_node *sdu_node; + struct bt_iso_chan *chan; + struct bt_conn *iso; + bt_conn_tx_cb_t cb; + sys_snode_t *node; + void *ud; + int err; + + assert(data && data_len == sizeof(*evt)); + + bt_le_host_lock(); + + while (1) { + /* If no free buffer exists, no need to check if any SDU is pending */ + if (r_ble_ll_iso_free_buf_num_get(evt->conn_handle) == 0) { + break; + } + + /* Fetch and remove the first ISO SDU from list if list is not empty */ + node = sys_slist_get(&iso_tx_sdu_list); + if (node == NULL) { + break; + } + + sdu_node = CONTAINER_OF(node, struct iso_tx_sdu_node, node); + + err = r_ble_hci_trans_hs_iso_tx(sdu_node->sdu, sdu_node->sdu_len, NULL); + if (err) { + /* err = -1: No BIS or CIS found; + * err = -2: Bad ISO packet; + * err = -3: Not able to send (e.g., CIS tx bn is 0, etc); + * err = -4: Not ready to send (e.g. BIS or CIS not established, DP not setup, etc.); + * err = -5: Last SDU fragment (generated over HCI) is failed to send; + * + * Note: + * The allocated pkt buffer will be freed in our controller. + * + * TODO: + * If using controller from other vendors, the pkt buffer may + * needs to be freed here. + */ + LOG_WRN("IsoTxFail[%d]", err); + } + + free(sdu_node); + } + + iso = bt_conn_lookup_handle(evt->conn_handle, BT_CONN_TYPE_ISO); + if (iso == NULL) { + goto end; + } + + chan = iso->iso.chan; + assert(chan); + + cb = NULL; + ud = NULL; + chan->iso->get_and_clear_cb(NULL, NULL, &cb, &ud); + + if (cb) { + cb(chan->iso, &evt->info, 0); + } + +end: + bt_le_host_unlock(); + free(data); +} + +static void iso_tx_comp_cb(uint16_t conn_handle, void *info, size_t size) +{ + struct iso_tx_comp_event *evt; + int err; + + /* Note: + * This callback is invoked in the BLE Controller task, the operation in + * this function shall be as simple as possible and avoid log output. + * Avoid acquiring host_lock here to prevent deadlock when the ISO task + * holds host_lock while waiting for a Controller response. Instead, post + * the event to the ISO task for processing. + */ + + assert(size == sizeof(struct bt_iso_tx_cb_info)); + + evt = calloc(1, sizeof(*evt)); + if (evt == NULL) { + LOG_ERR("IsoTxCompNoMem[%u]", sizeof(*evt)); + return; + } + + evt->conn_handle = conn_handle; + memcpy(&evt->info, info, sizeof(evt->info)); + + err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_ISO_TX_COMP, evt, sizeof(*evt)); + if (err) { + LOG_ERR("IsoTxCompPostFail[%d]", err); + free(evt); + } +} +#else /* CONFIG_BT_ISO_TX */ +void bt_le_iso_handle_tx_comp(uint8_t *data, size_t data_len) +{ + ARG_UNUSED(data); + ARG_UNUSED(data_len); +} +#endif /* CONFIG_BT_ISO_TX */ + +#if CONFIG_BT_ISO_RX +void bt_le_iso_handle_rx_data(uint8_t *data, size_t data_len) +{ + struct net_buf buf = {0}; + + assert(data && data_len); + + bt_le_host_lock(); + net_buf_simple_init_with_data(&buf.b, (void *)data, data_len); + hci_iso(&buf); + bt_le_host_unlock(); + + free(data); +} + +int bt_le_iso_rx(const uint8_t *data, uint16_t len, void *arg) +{ + uint8_t *rx_data; + int err; + + /* Note: + * This callback is invoked in the BLE Controller task. The data directly + * points to the start of an ISO SDU, i.e. the conn_handle, etc. No extra + * information for now. + * Avoid acquiring host_lock here to prevent deadlock when the ISO task + * holds host_lock while waiting for a Controller response. Instead, copy + * the data and post the event to the ISO task for further processing. + */ + + ARG_UNUSED(arg); + + rx_data = calloc(1, len); + if (rx_data == NULL) { + LOG_ERR("IsoRxNoMem[%u]", len); + return -ENOMEM; + } + + memcpy(rx_data, data, len); + + err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_ISO_RX_DATA, rx_data, len); + if (err) { + LOG_ERR("IsoRxPostFail[%d]", err); + free(rx_data); + return -EIO; + } + + return 0; +} +#else /* CONFIG_BT_ISO_RX */ +void bt_le_iso_handle_rx_data(uint8_t *data, size_t data_len) +{ + ARG_UNUSED(data); + ARG_UNUSED(data_len); +} +#endif /* CONFIG_BT_ISO_RX */ + +int bt_le_iso_disconnect(uint16_t conn_handle, uint8_t reason) +{ + return bt_le_nimble_iso_disconnect(conn_handle, reason); +} + +static void iso_features_set(void) +{ +#if CONFIG_BT_ISO_CENTRAL + BT_LE_FEAT_SET(bt_dev.le.features, BT_LE_FEAT_BIT_CIS_CENTRAL); +#endif /* CONFIG_BT_ISO_CENTRAL */ + +#if CONFIG_BT_ISO_PERIPHERAL + BT_LE_FEAT_SET(bt_dev.le.features, BT_LE_FEAT_BIT_CIS_PERIPHERAL); +#endif /* CONFIG_BT_ISO_PERIPHERAL */ + +#if CONFIG_BT_ISO_BROADCASTER + BT_LE_FEAT_SET(bt_dev.le.features, BT_LE_FEAT_BIT_ISO_BROADCASTER); +#endif /* CONFIG_BT_ISO_BROADCASTER */ + +#if CONFIG_BT_ISO_SYNC_RECEIVER + BT_LE_FEAT_SET(bt_dev.le.features, BT_LE_FEAT_BIT_SYNC_RECEIVER); +#endif /* CONFIG_BT_ISO_SYNC_RECEIVER */ + + LOG_DBG("IsoFeatSet[%s]", bt_hex(bt_dev.le.features, sizeof(bt_dev.le.features))); +} + +static void iso_features_unset(void) +{ +#if CONFIG_BT_ISO_CENTRAL + BT_LE_FEAT_UNSET(bt_dev.le.features, BT_LE_FEAT_BIT_CIS_CENTRAL); +#endif /* CONFIG_BT_ISO_CENTRAL */ + +#if CONFIG_BT_ISO_PERIPHERAL + BT_LE_FEAT_UNSET(bt_dev.le.features, BT_LE_FEAT_BIT_CIS_PERIPHERAL); +#endif /* CONFIG_BT_ISO_PERIPHERAL */ + +#if CONFIG_BT_ISO_BROADCASTER + BT_LE_FEAT_UNSET(bt_dev.le.features, BT_LE_FEAT_BIT_ISO_BROADCASTER); +#endif /* CONFIG_BT_ISO_BROADCASTER */ + +#if CONFIG_BT_ISO_SYNC_RECEIVER + BT_LE_FEAT_UNSET(bt_dev.le.features, BT_LE_FEAT_BIT_SYNC_RECEIVER); +#endif /* CONFIG_BT_ISO_SYNC_RECEIVER */ + + LOG_DBG("IsoFeatUnset[%s]", bt_hex(bt_dev.le.features, sizeof(bt_dev.le.features))); +} + +int bt_le_iso_init(void) +{ + int err; + + LOG_DBG("IsoInit"); + + iso_features_set(); + + err = bt_le_iso_cb_register_safe(&iso_cb); + if (err) { + return err; + } + +#if CONFIG_BT_ISO_TX + r_ble_ll_isoal_tx_comp_cb_set(iso_tx_comp_cb); +#endif /* CONFIG_BT_ISO_TX */ + + err = bt_le_nimble_iso_init(); + if (err) { + return err; + } + + return 0; +} + +void bt_le_iso_deinit(void) +{ + LOG_DBG("IsoDeinit"); + + iso_features_unset(); + + bt_le_iso_cb_unregister_safe(&iso_cb); + +#if CONFIG_BT_ISO_TX + r_ble_ll_isoal_tx_comp_cb_set(NULL); +#endif /* CONFIG_BT_ISO_TX */ + + bt_le_nimble_iso_deinit(); +} diff --git a/components/bt/esp_ble_audio/host/common/iso.h b/components/bt/esp_ble_audio/host/common/iso.h new file mode 100644 index 0000000000..2c7ff8cf6c --- /dev/null +++ b/components/bt/esp_ble_audio/host/common/iso.h @@ -0,0 +1,79 @@ +/* + * SPDX-FileCopyrightText: 2015-2016 Intel Corporation + * SPDX-FileCopyrightText: 2023 Nordic Semiconductor + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef HOST_COMMON_ISO_H_ +#define HOST_COMMON_ISO_H_ + +#include + +#include "sdkconfig.h" + +#include "nimble/iso.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_le_iso_cb { + void (*cis_dis)(struct net_buf *buf); + void (*cis_est)(struct net_buf *buf); + void (*cis_req)(struct net_buf *buf); + void (*big_create)(struct net_buf *buf); + void (*big_term)(struct net_buf *buf); + void (*big_est)(struct net_buf *buf); + void (*big_lost)(struct net_buf *buf); + void (*biginfo)(struct net_buf *buf); + + sys_snode_t node; +}; + +struct bt_iso_tx_cb_info { + uint16_t completed_pkts; + uint16_t not_txd_pkts; + + uint8_t pkt_cnt; + struct { + uint16_t seq_num; + uint32_t tx_time_stamp; + uint32_t time_offset : 24; + uint32_t drift : 1; + uint32_t sdu_ref_time; + uint32_t sdu_hdl_time; + uint32_t sdu_rec_time; + } pkt[2]; +}; + +int bt_le_iso_cb_register_safe(struct bt_le_iso_cb *cb); + +void bt_le_iso_cb_unregister_safe(struct bt_le_iso_cb *cb); + +void bt_le_iso_handle_hci_event(uint8_t *data, size_t data_len); + +void bt_le_iso_handle_tx_comp(uint8_t *data, size_t data_len); + +void bt_le_iso_handle_rx_data(uint8_t *data, size_t data_len); + +int bt_le_iso_tx(struct bt_iso_chan *chan, + struct net_buf *buf, + uint16_t seq_num, + uint32_t time_stamp, + bool ts_valid); + +int bt_le_iso_rx(const uint8_t *data, uint16_t len, void *arg); + +int bt_le_iso_disconnect(uint16_t conn_handle, uint8_t reason); + +int bt_le_iso_init(void); + +void bt_le_iso_deinit(void); + +#ifdef __cplusplus +} +#endif + +#endif /* HOST_COMMON_ISO_H_ */ diff --git a/components/bt/esp_ble_audio/host/common/l2cap.c b/components/bt/esp_ble_audio/host/common/l2cap.c new file mode 100644 index 0000000000..e4416f0310 --- /dev/null +++ b/components/bt/esp_ble_audio/host/common/l2cap.c @@ -0,0 +1,504 @@ +/* + * SPDX-FileCopyrightText: 2015-2016 Intel Corporation + * SPDX-FileCopyrightText: 2023 Nordic Semiconductor + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include +#include + +#include <../host/conn_internal.h> +#include + +#include "common/host.h" +#include "common/app/gap.h" + +#define L2CAP_LE_MIN_MTU 23 +#define L2CAP_ECRED_MIN_MTU 64 + +#define L2CAP_LE_CID_DYN_START 0x0040 +#define L2CAP_LE_CID_DYN_END 0x007F +#define L2CAP_LE_CID_IS_DYN(_cid) (_cid >= L2CAP_LE_CID_DYN_START && _cid <= L2CAP_LE_CID_DYN_END) + +#define L2CAP_LE_PSM_FIXED_START 0x0001 +#define L2CAP_LE_PSM_FIXED_END 0x007F +#define L2CAP_LE_PSM_DYN_START 0x0080 +#define L2CAP_LE_PSM_DYN_END 0x00FF +#define L2CAP_LE_PSM_IS_DYN(_psm) (_psm >= L2CAP_LE_PSM_DYN_START && _psm <= L2CAP_LE_PSM_DYN_END) + +static sys_slist_t l2cap_servers = SYS_SLIST_STATIC_INIT(&l2cap_servers); + +static struct bt_l2cap_chan *l2cap_lookup_tx_cid(struct bt_conn *conn, uint16_t cid) +{ + struct bt_l2cap_chan *chan; + + SYS_SLIST_FOR_EACH_CONTAINER(&conn->channels, chan, node) { + if (BT_L2CAP_LE_CHAN(chan)->tx.cid == cid) { + return chan; + } + } + + return NULL; +} + +__attribute__((unused)) +static struct bt_l2cap_chan *l2cap_lookup_rx_cid(struct bt_conn *conn, uint16_t cid) +{ + struct bt_l2cap_chan *chan; + + SYS_SLIST_FOR_EACH_CONTAINER(&conn->channels, chan, node) { + if (BT_L2CAP_LE_CHAN(chan)->rx.cid == cid) { + return chan; + } + } + + return NULL; +} + +static struct bt_l2cap_chan *l2cap_lookup_psm(struct bt_conn *conn, uint16_t psm) +{ + struct bt_l2cap_chan *chan; + + SYS_SLIST_FOR_EACH_CONTAINER(&conn->channels, chan, node) { + if (BT_L2CAP_LE_CHAN(chan)->psm == psm) { + return chan; + } + } + + return NULL; +} + +static bool l2cap_chan_add(struct bt_conn *conn, struct bt_l2cap_chan *chan, uint16_t psm) +{ + LOG_DBG("L2capChanAdd[%04x]", psm); + + /* Attach channel to the connection */ + if (sys_slist_find(&conn->channels, &chan->node, NULL)) { + LOG_WRN("L2capChanExists[%04x]", psm); + return false; + } + + sys_slist_append(&conn->channels, &chan->node); + chan->conn = conn; + + /* Set channel PSM */ + BT_L2CAP_LE_CHAN(chan)->psm = psm; + + return true; +} + +static struct bt_l2cap_server *l2cap_server_lookup_psm(uint16_t psm) +{ + struct bt_l2cap_server *server = NULL; + + SYS_SLIST_FOR_EACH_CONTAINER(&l2cap_servers, server, node) { + if (server->psm == psm) { + break; + } + } + + return server; +} + +static inline uint16_t err_to_result(int err) +{ + switch (err) { + case -ENOMEM: + return L2CAP_LE_ERR_NO_RESOURCES; + case -EACCES: + return L2CAP_LE_ERR_AUTHORIZATION; + case -EPERM: + return L2CAP_LE_ERR_KEY_SIZE; + case -ENOTSUP: + /* This handle the cases where a fixed channel is registered but + * for some reason (e.g. controller not supporting a feature) + * cannot be used. + */ + return L2CAP_LE_ERR_PSM_NOT_SUPP; + default: + return L2CAP_LE_ERR_UNACCEPT_PARAMS; + } +} + +_IDF_ONLY +int bt_le_l2cap_accept(uint16_t conn_handle, uint16_t psm, + uint16_t scid, uint16_t mtu, + uint16_t mps, uint16_t credits, + uint16_t *result) +{ + struct bt_l2cap_server *server; + struct bt_l2cap_chan *chan; + struct bt_conn *conn; + int err; + + ARG_UNUSED(credits); + + LOG_DBG("L2capAccept[%u][%04x][%04x][%u][%u]", conn_handle, psm, scid, mtu, mps); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL || conn->state != BT_CONN_CONNECTED) { + LOG_ERR("NotConn[%d]", __LINE__); + + *result = L2CAP_LE_ERR_INVALID_PARAMS; + return -ENOTCONN; + } + + /* Check if there is a server registered */ + server = l2cap_server_lookup_psm(psm); + if (server == NULL) { + LOG_ERR("SrvNotReg[%04x]", psm); + + *result = L2CAP_LE_ERR_PSM_NOT_SUPP; + return -ENOTSUP; + } + + if (!L2CAP_LE_CID_IS_DYN(scid)) { + LOG_ERR("NotDynScid[%04x]", scid); + + *result = L2CAP_LE_ERR_INVALID_SCID; + return -EINVAL; + } + + chan = l2cap_lookup_tx_cid(conn, scid); + if (chan) { + LOG_WRN("ScidUsed[%04x]", scid); + + *result = L2CAP_LE_ERR_SCID_IN_USE; + return -EALREADY; + } + + if (server->accept == NULL) { + LOG_ERR("SrvAcceptNull"); + + *result = L2CAP_LE_ERR_INVALID_PARAMS; + return -EIO; + } + + err = server->accept(conn, server, &chan); + if (err) { + LOG_ERR("SrvAcceptFail[%d]", err); + + *result = err_to_result(err); + return -EIO; + } + + if (chan == NULL) { + LOG_ERR("SrvAcceptNullChan"); + *result = L2CAP_LE_ERR_NO_RESOURCES; + return -ENOMEM; + } + + if (l2cap_chan_add(conn, chan, psm) == false) { + *result = L2CAP_LE_ERR_NO_RESOURCES; + return -ENOMEM; + } + + *result = L2CAP_LE_SUCCESS; + return 0; +} + +_IDF_ONLY +void bt_le_l2cap_connected(uint16_t conn_handle, uint16_t psm, + uint16_t tx_cid, uint16_t tx_mtu, + uint16_t rx_cid, uint16_t rx_mtu) +{ + struct bt_l2cap_chan *chan; + struct bt_conn *conn; + + LOG_DBG("L2capConnected[%u][%04x][%04x][%u][%04x][%u]", + conn_handle, psm, tx_cid, tx_mtu, rx_cid, rx_mtu); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL || conn->state != BT_CONN_CONNECTED) { + LOG_ERR("NotConn[%d]", __LINE__); + return; + } + + chan = l2cap_lookup_psm(conn, psm); + if (chan == NULL) { + LOG_ERR("PsmNotFound[%04x]", psm); + return; + } + + BT_L2CAP_LE_CHAN(chan)->tx.cid = tx_cid; + BT_L2CAP_LE_CHAN(chan)->tx.mtu = tx_mtu; + BT_L2CAP_LE_CHAN(chan)->rx.cid = rx_cid; + BT_L2CAP_LE_CHAN(chan)->rx.mtu = rx_mtu; + + if (chan->ops->connected) { + chan->ops->connected(chan); + } +} + +#define L2CAP_UGLY_TX_DONE_WORKAROUND 1 + +_IDF_ONLY +void bt_le_l2cap_disconnected(uint16_t conn_handle, uint16_t psm) +{ +#if L2CAP_UGLY_TX_DONE_WORKAROUND + struct bt_gatt_ots_l2cap *l2cap_ctx; + struct bt_l2cap_le_chan *l2chan; +#endif /* L2CAP_UGLY_TX_DONE_WORKAROUND */ + struct bt_l2cap_chan *chan; + struct bt_conn *conn; + + LOG_DBG("L2capDisconnected[%u][%04x]", conn_handle, psm); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL || conn->state != BT_CONN_CONNECTED) { + LOG_ERR("NotConn[%d]", __LINE__); + return; + } + + chan = l2cap_lookup_psm(conn, psm); + if (chan == NULL) { + LOG_ERR("PsmNotFound[%04x]", psm); + return; + } + +#if L2CAP_UGLY_TX_DONE_WORKAROUND + l2chan = CONTAINER_OF(chan, struct bt_l2cap_le_chan, chan); + l2cap_ctx = CONTAINER_OF(l2chan, struct bt_gatt_ots_l2cap, ot_chan); + + if (chan->ops->sent && l2cap_ctx->tx_done) { + chan->ops->sent(chan); + } +#endif /* L2CAP_UGLY_TX_DONE_WORKAROUND */ + + if (chan->ops->disconnected) { + chan->ops->disconnected(chan); + } + + sys_slist_find_and_remove(&conn->channels, &chan->node); + chan->conn = NULL; +} + +_IDF_ONLY +void bt_le_l2cap_received(uint16_t conn_handle, uint16_t psm, + uint8_t *data, uint16_t len) +{ + struct bt_l2cap_chan *chan; + struct net_buf buf = {0}; + struct bt_conn *conn; + + LOG_DBG("L2capReceived[%u][%04x][%u]", conn_handle, psm, len); + + conn = bt_le_acl_conn_find(conn_handle); + if (conn == NULL || conn->state != BT_CONN_CONNECTED) { + LOG_ERR("NotConn[%d]", __LINE__); + return; + } + + chan = l2cap_lookup_psm(conn, psm); + if (chan == NULL) { + LOG_ERR("PsmNotFound[%04x]", psm); + return; + } + + buf.data = data; + buf.len = len; + + if (chan->ops->recv) { + chan->ops->recv(chan, &buf); + } +} + +_IDF_ONLY +int bt_l2cap_chan_connect(struct bt_conn *conn, struct bt_l2cap_chan *chan, uint16_t psm) +{ + int err; + + LOG_DBG("L2capChanConnect[%04x]", psm); + + if (chan == NULL) { + LOG_ERR("L2capChanNull"); + return -EINVAL; + } + + if (conn == NULL || conn->state != BT_CONN_CONNECTED) { + LOG_ERR("L2capChanNotConn[%p]", conn); + return -ENOTCONN; + } + + if (psm < L2CAP_LE_PSM_FIXED_START || psm > L2CAP_LE_PSM_DYN_END) { + LOG_ERR("InvPsm[%04x]", psm); + return -EINVAL; + } + + err = bt_le_nimble_l2cap_chan_connect(conn->handle); + if (err) { + return err; + } + + l2cap_chan_add(conn, chan, psm); + + return 0; +} + +_IDF_ONLY +int bt_l2cap_chan_disconnect(struct bt_l2cap_chan *chan) +{ + int err; + + LOG_DBG("L2capChanDisconnect"); + + if (chan == NULL) { + LOG_ERR("L2capChanNull"); + return -EINVAL; + } + + if (chan->conn == NULL || chan->conn->state != BT_CONN_CONNECTED) { + LOG_ERR("L2capChanNotConn[%p]", chan->conn); + return -ENOTCONN; + } + + err = bt_le_nimble_l2cap_chan_disconnect(chan); + if (err) { + /* If the disconnect failed, remove the channel from the connection. + * Otherwise the removal will be handled by the disconnect callback. + */ + sys_slist_find_and_remove(&chan->conn->channels, &chan->node); + chan->conn = NULL; + } + + return err; +} + +_IDF_ONLY +int bt_l2cap_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf) +{ + if (chan == NULL || buf == NULL) { + LOG_ERR("L2capChanBufNull[%p][%p]", chan, buf); + return -EINVAL; + } + + LOG_DBG("L2capChanSend[%u]", buf->len); + + if (chan->conn == NULL || chan->conn->state != BT_CONN_CONNECTED) { + LOG_ERR("L2capChanNotConn[%p]", chan->conn); + return -ENOTCONN; + } + + if (buf->len > L2CAP_LE_OTS_MTU) { + LOG_ERR("L2capTooLargeBufToSend[%u][%u]", buf->len, L2CAP_LE_OTS_MTU); + return -EMSGSIZE; + } + + return bt_le_nimble_l2cap_chan_send(chan, buf); +} + +_IDF_ONLY +int bt_l2cap_server_register(struct bt_l2cap_server *server) +{ + LOG_DBG("L2capSrvReg"); + + if (server == NULL) { + LOG_ERR("SrvNull"); + return -EINVAL; + } + + if (server->accept == NULL) { + LOG_ERR("SrvAcceptNull"); + return -EINVAL; + } + + if (server->sec_level > BT_SECURITY_L4) { + LOG_ERR("InvSecLevel[%u]", server->sec_level); + return -EINVAL; + } + + if (server->psm) { + if (server->psm < L2CAP_LE_PSM_FIXED_START || + server->psm > L2CAP_LE_PSM_DYN_END) { + LOG_ERR("InvPsm[%04x]", server->psm); + return -EINVAL; + } + + /* Check if given PSM is already in use */ + if (l2cap_server_lookup_psm(server->psm)) { + LOG_WRN("PsmReg"); + return -EADDRINUSE; + } + + LOG_DBG("SrvPsm[%04x]", server->psm); + } else { + uint16_t psm; + + for (psm = L2CAP_LE_PSM_DYN_START; + psm <= L2CAP_LE_PSM_DYN_END; psm++) { + if (l2cap_server_lookup_psm(psm) == NULL) { + break; + } + } + + if (psm > L2CAP_LE_PSM_DYN_END) { + LOG_ERR("NoFreeDynPsm"); + return -EADDRNOTAVAIL; + } + + LOG_DBG("PsmNew[%04x]", psm); + + server->psm = psm; + } + + if (server->sec_level < BT_SECURITY_L1) { + server->sec_level = BT_SECURITY_L1; + } + + sys_slist_append(&l2cap_servers, &server->node); + + return 0; +} + +int bt_le_l2cap_init(void) +{ + int err; + + LOG_DBG("L2capInit"); + +#if CONFIG_BT_OTS + extern int bt_gatt_ots_conn_cb_register(void); + err = bt_gatt_ots_conn_cb_register(); + if (err) { + LOG_ERR("OtsConnCbRegFail[%d]", err); + return err; + } + + extern int bt_gatt_ots_instances_prepare_v2(void); + err = bt_gatt_ots_instances_prepare_v2(); + if (err) { + LOG_ERR("PrepOtsInstsFail[%d]", err); + return err; + } +#endif /* CONFIG_BT_OTS */ + +#if CONFIG_BT_OTS || CONFIG_BT_OTS_CLIENT + extern int bt_gatt_ots_l2cap_init_v2(void); + err = bt_gatt_ots_l2cap_init_v2(); + if (err) { + LOG_ERR("OtsL2capInitFail[%d]", err); + return err; + } +#endif /* CONFIG_BT_OTS || CONFIG_BT_OTS_CLIENT */ + + err = bt_le_nimble_l2cap_init(); + if (err) { + return err; + } + + return 0; +} + +void bt_le_l2cap_deinit(void) +{ + LOG_DBG("L2capDeinit"); + + /* TODO: L2CAP server deinit */ +} diff --git a/components/bt/esp_ble_audio/host/common/l2cap.h b/components/bt/esp_ble_audio/host/common/l2cap.h new file mode 100644 index 0000000000..53cda7ff8e --- /dev/null +++ b/components/bt/esp_ble_audio/host/common/l2cap.h @@ -0,0 +1,60 @@ +/* + * SPDX-FileCopyrightText: 2015-2016 Intel Corporation + * SPDX-FileCopyrightText: 2023 Nordic Semiconductor + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef HOST_COMMON_L2CAP_H_ +#define HOST_COMMON_L2CAP_H_ + +#include + +#include "sdkconfig.h" + +#include "nimble/l2cap.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define L2CAP_LE_SUCCESS 0x0000 +#define L2CAP_LE_ERR_PSM_NOT_SUPP 0x0002 +#define L2CAP_LE_ERR_NO_RESOURCES 0x0004 +#define L2CAP_LE_ERR_AUTHENTICATION 0x0005 +#define L2CAP_LE_ERR_AUTHORIZATION 0x0006 +#define L2CAP_LE_ERR_KEY_SIZE 0x0007 +#define L2CAP_LE_ERR_ENCRYPTION 0x0008 +#define L2CAP_LE_ERR_INVALID_SCID 0x0009 +#define L2CAP_LE_ERR_SCID_IN_USE 0x000A +#define L2CAP_LE_ERR_UNACCEPT_PARAMS 0x000B +#define L2CAP_LE_ERR_INVALID_PARAMS 0x000C + +#define L2CAP_LE_OTS_PSM 0x0025 +#define L2CAP_LE_OTS_MTU MIN(CONFIG_BT_OTS_L2CAP_CHAN_TX_MTU, \ + CONFIG_BT_OTS_L2CAP_CHAN_RX_MTU) + +int bt_le_l2cap_accept(uint16_t conn_handle, uint16_t psm, + uint16_t scid, uint16_t mtu, + uint16_t mps, uint16_t credits, + uint16_t *result); + +void bt_le_l2cap_connected(uint16_t conn_handle, uint16_t psm, + uint16_t tx_cid, uint16_t tx_mtu, + uint16_t rx_cid, uint16_t rx_mtu); + +void bt_le_l2cap_disconnected(uint16_t conn_handle, uint16_t psm); + +void bt_le_l2cap_received(uint16_t conn_handle, uint16_t psm, + uint8_t *data, uint16_t len); + +int bt_le_l2cap_init(void); + +void bt_le_l2cap_deinit(void); + +#ifdef __cplusplus +} +#endif + +#endif /* HOST_COMMON_L2CAP_H_ */ diff --git a/components/bt/esp_ble_audio/host/common/scan.c b/components/bt/esp_ble_audio/host/common/scan.c new file mode 100644 index 0000000000..0a6a23a9c5 --- /dev/null +++ b/components/bt/esp_ble_audio/host/common/scan.c @@ -0,0 +1,492 @@ +/* + * SPDX-FileCopyrightText: 2017-2021 Nordic Semiconductor + * SPDX-FileCopyrightText: 2015-2016 Intel Corporation + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include <../host/hci_core.h> + +#include "common/host.h" + +static sys_slist_t scan_cbs = SYS_SLIST_STATIC_INIT(&scan_cbs); + +_LIB_ONLY +int bt_le_scan_cb_register(struct bt_le_scan_cb *cb) +{ + LOG_DBG("ScanCbReg"); + + if (cb == NULL) { + LOG_ERR("ScanCbNull"); + return -EINVAL; + } + + if (sys_slist_find(&scan_cbs, &cb->node, NULL)) { + LOG_WRN("ScanCbExist"); + return -EEXIST; + } + + sys_slist_append(&scan_cbs, &cb->node); + + return 0; +} + +_NOT_USED +void bt_le_scan_cb_unregister(struct bt_le_scan_cb *cb) +{ + LOG_DBG("ScanCbUnreg"); + + if (cb == NULL) { + LOG_ERR("ScanCbNull"); + return; + } + + sys_slist_find_and_remove(&scan_cbs, &cb->node); +} + +static uint8_t get_adv_type(uint8_t evt_type) +{ + /* LOG_DBG("GetAdvType[%02x]", evt_type); */ + + switch (evt_type) { + case (BT_HCI_LE_ADV_EVT_TYPE_CONN | + BT_HCI_LE_ADV_EVT_TYPE_SCAN | + BT_HCI_LE_ADV_EVT_TYPE_LEGACY): + return BT_GAP_ADV_TYPE_ADV_IND; + + case (BT_HCI_LE_ADV_EVT_TYPE_CONN | + BT_HCI_LE_ADV_EVT_TYPE_DIRECT | + BT_HCI_LE_ADV_EVT_TYPE_LEGACY): + return BT_GAP_ADV_TYPE_ADV_DIRECT_IND; + + case (BT_HCI_LE_ADV_EVT_TYPE_SCAN | + BT_HCI_LE_ADV_EVT_TYPE_LEGACY): + return BT_GAP_ADV_TYPE_ADV_SCAN_IND; + + case BT_HCI_LE_ADV_EVT_TYPE_LEGACY: + return BT_GAP_ADV_TYPE_ADV_NONCONN_IND; + + case (BT_HCI_LE_ADV_EVT_TYPE_SCAN_RSP | + BT_HCI_LE_ADV_EVT_TYPE_CONN | + BT_HCI_LE_ADV_EVT_TYPE_SCAN | + BT_HCI_LE_ADV_EVT_TYPE_LEGACY): + case (BT_HCI_LE_ADV_EVT_TYPE_SCAN_RSP | + BT_HCI_LE_ADV_EVT_TYPE_SCAN | + BT_HCI_LE_ADV_EVT_TYPE_LEGACY): + return BT_GAP_ADV_TYPE_SCAN_RSP; + + default: + return BT_GAP_ADV_TYPE_EXT_ADV; + } +} + +_IDF_ONLY +void bt_le_scan_recv_listener(uint16_t event_type, + uint8_t addr_type, + uint8_t addr_val[6], + int8_t rssi, + int8_t tx_power, + uint8_t sid, + uint8_t pri_phy, + uint8_t sec_phy, + uint16_t per_adv_itvl, + uint8_t data_len, + uint8_t *data) +{ + struct net_buf_simple_state state = {0}; + struct bt_le_scan_recv_info info = {0}; + struct bt_le_scan_cb *listener = NULL; + struct net_buf_simple buf = {0}; + bt_addr_le_t addr = {0}; + + /* LOG_DBG("ScanRecvListener[%u]", data_len); */ + + if (data == NULL || data_len == 0) { + LOG_DBG("ScanRecvDataNull[%u]", data_len); + return; + } + + addr.type = addr_type; + memcpy(addr.a.val, addr_val, BT_ADDR_SIZE); + + info.addr = &addr; + info.sid = sid; + info.rssi = rssi; + info.tx_power = tx_power; + info.adv_type = get_adv_type(event_type); + info.adv_props = event_type; + info.interval = per_adv_itvl; + info.primary_phy = pri_phy; + info.secondary_phy = sec_phy; + + net_buf_simple_init_with_data(&buf, (void *)data, data_len); + + SYS_SLIST_FOR_EACH_CONTAINER(&scan_cbs, listener, node) { + if (listener->recv) { + net_buf_simple_save(&buf, &state); + listener->recv(&info, &buf); + net_buf_simple_restore(&buf, &state); + } + } +} + +static struct bt_le_per_adv_sync per_adv_sync_pool[CONFIG_BT_PER_ADV_SYNC_MAX]; + +static sys_slist_t pa_sync_cbs = SYS_SLIST_STATIC_INIT(&pa_sync_cbs); + +_LIB_ONLY +int bt_le_per_adv_sync_cb_register(struct bt_le_per_adv_sync_cb *cb) +{ + LOG_DBG("PaSyncCbReg"); + + if (cb == NULL) { + LOG_ERR("PaSyncCbNull"); + return -EINVAL; + } + + if (sys_slist_find(&pa_sync_cbs, &cb->node, NULL)) { + LOG_WRN("PaSyncCbExist"); + return -EEXIST; + } + + sys_slist_append(&pa_sync_cbs, &cb->node); + + return 0; +} + +_LIB_ONLY +int bt_le_per_adv_sync_get_info(struct bt_le_per_adv_sync *per_adv_sync, + struct bt_le_per_adv_sync_info *info) +{ + LOG_DBG("PaSyncGetInfo"); + + if (per_adv_sync == NULL || info == NULL) { + LOG_ERR("PaSyncInfoNull[%p][%p]", per_adv_sync, info); + return -EINVAL; + } + + bt_addr_le_copy(&info->addr, &per_adv_sync->addr); + info->sid = per_adv_sync->sid; + info->phy = per_adv_sync->phy; + info->interval = per_adv_sync->interval; + + LOG_DBG("[%s][%u][%u][%u]", + bt_addr_le_str(&info->addr), info->sid, info->phy, info->interval); + + return 0; +} + +_LIB_ONLY +struct bt_le_per_adv_sync *bt_le_per_adv_sync_lookup_addr(const bt_addr_le_t *adv_addr, + uint8_t sid) +{ + struct bt_le_per_adv_sync *per_adv_sync = NULL; + + assert(adv_addr); + + LOG_DBG("PaSyncLookupAddr[%s][%u]", bt_addr_le_str(adv_addr), sid); + + for (size_t i = 0; i < ARRAY_SIZE(per_adv_sync_pool); i++) { + if (atomic_test_bit(per_adv_sync_pool[i].flags, BT_PER_ADV_SYNC_SYNCED) && + bt_addr_le_eq(&per_adv_sync_pool[i].addr, adv_addr) && + per_adv_sync_pool[i].sid == sid) { + per_adv_sync = &per_adv_sync_pool[i]; + break; + } + } + + if (per_adv_sync == NULL) { + LOG_INF("PaSyncNotFound"); + } + + return per_adv_sync; +} + +static struct bt_le_per_adv_sync *per_adv_sync_find(uint16_t handle) +{ + struct bt_le_per_adv_sync *per_adv_sync = NULL; + + for (size_t i = 0; i < ARRAY_SIZE(per_adv_sync_pool); i++) { + if (atomic_test_bit(per_adv_sync_pool[i].flags, + BT_PER_ADV_SYNC_SYNCED) && + per_adv_sync_pool[i].handle == handle) { + per_adv_sync = &per_adv_sync_pool[i]; + break; + } + } + + return per_adv_sync; +} + +_IDF_ONLY +struct bt_le_per_adv_sync *bt_le_per_adv_sync_find_safe(uint16_t sync_handle) +{ + struct bt_le_per_adv_sync *per_adv_sync = NULL; + LOG_DBG("PaSyncFind[%u]", sync_handle); + bt_le_host_lock(); + per_adv_sync = per_adv_sync_find(sync_handle); + bt_le_host_unlock(); + return per_adv_sync; +} + +static struct bt_le_per_adv_sync *per_adv_sync_new(void) +{ + struct bt_le_per_adv_sync *per_adv_sync = NULL; + + for (size_t i = 0; i < ARRAY_SIZE(per_adv_sync_pool); i++) { + if (atomic_test_bit(per_adv_sync_pool[i].flags, + BT_PER_ADV_SYNC_SYNCED) == false) { + per_adv_sync = &per_adv_sync_pool[i]; + break; + } + } + + if (per_adv_sync) { + (void)memset(per_adv_sync, 0, sizeof(*per_adv_sync)); + atomic_set_bit(per_adv_sync->flags, BT_PER_ADV_SYNC_SYNCED); + } + + return per_adv_sync; +} + +_IDF_ONLY +int bt_le_per_adv_sync_new(uint16_t sync_handle, + uint8_t sid, + uint8_t phy, + uint16_t interval, + uint8_t addr_type, + const uint8_t addr[6], + struct bt_le_per_adv_sync **out_sync) +{ + struct bt_le_per_adv_sync *per_adv_sync; + + LOG_DBG("PaSyncNew[%u][%u][%u][%u]", sync_handle, sid, phy, interval); + + if (addr_type > BT_ADDR_LE_RANDOM_ID || addr == NULL) { + LOG_ERR("InvAddr[%02x][%p]", addr_type, addr); + return -EINVAL; + } + + per_adv_sync = per_adv_sync_find(sync_handle); + if (per_adv_sync) { + LOG_WRN("PaSyncExist[%u]", sync_handle); + return -EEXIST; + } + + per_adv_sync = per_adv_sync_new(); + if (per_adv_sync == NULL) { + LOG_ERR("NoFreePaSync[%u]", sync_handle); + return -ENOMEM; + } + + per_adv_sync->handle = sync_handle; + per_adv_sync->sid = sid; + per_adv_sync->phy = phy; + per_adv_sync->interval = interval; + per_adv_sync->addr.type = addr_type; + memcpy(per_adv_sync->addr.a.val, addr, BT_ADDR_SIZE); + + LOG_DBG("Addr[%s]", bt_addr_le_str(&per_adv_sync->addr)); + + if (out_sync) { + *out_sync = per_adv_sync; + } + + return 0; +} + +_IDF_ONLY +int bt_le_per_adv_sync_delete(uint16_t sync_handle) +{ + struct bt_le_per_adv_sync *per_adv_sync = NULL; + + LOG_DBG("PaSyncDelete[%u]", sync_handle); + + per_adv_sync = per_adv_sync_find(sync_handle); + if (per_adv_sync == NULL) { + LOG_ERR("PaSyncNotFound[%u]", sync_handle); + return -ENODEV; + } + + (void)memset(per_adv_sync, 0, sizeof(*per_adv_sync)); + + return 0; +} + +_IDF_ONLY +int bt_le_per_adv_sync_establish_listener(uint16_t sync_handle) +{ + struct bt_le_per_adv_sync_synced_info info = {0}; + struct bt_le_per_adv_sync *per_adv_sync = NULL; + struct bt_le_per_adv_sync_cb *listener = NULL; + + LOG_DBG("PaSyncEstabListener[%u]", sync_handle); + + per_adv_sync = per_adv_sync_find(sync_handle); + if (per_adv_sync == NULL) { + LOG_ERR("PaSyncNotFound[%u]", sync_handle); + return -ENODEV; + } + + info.addr = &per_adv_sync->addr; + info.sid = per_adv_sync->sid; + info.interval = per_adv_sync->interval; + info.phy = per_adv_sync->phy; + info.conn = NULL; /* TODO: update for PAST */ + + SYS_SLIST_FOR_EACH_CONTAINER(&pa_sync_cbs, listener, node) { + if (listener->synced) { + listener->synced(per_adv_sync, &info); + } + } + + return 0; +} + +_IDF_ONLY +int bt_le_per_adv_sync_lost_listener(uint16_t sync_handle) +{ + struct bt_le_per_adv_sync_term_info info = {0}; + struct bt_le_per_adv_sync *per_adv_sync = NULL; + struct bt_le_per_adv_sync_cb *listener = NULL; + + LOG_DBG("PaSyncLostListener[%u]", sync_handle); + + per_adv_sync = per_adv_sync_find(sync_handle); + if (per_adv_sync == NULL) { + LOG_ERR("PaSyncNotFound[%u]", sync_handle); + return -ENODEV; + } + + info.addr = &per_adv_sync->addr; + info.sid = per_adv_sync->sid; + + SYS_SLIST_FOR_EACH_CONTAINER(&pa_sync_cbs, listener, node) { + if (listener->term) { + listener->term(per_adv_sync, &info); + } + } + + return 0; +} + +_IDF_ONLY +int bt_le_per_adv_sync_report_recv_listener(uint16_t sync_handle, + const uint8_t *data, + size_t data_length) +{ + struct bt_le_per_adv_sync_recv_info info = {0}; + struct bt_le_per_adv_sync *per_adv_sync = NULL; + struct bt_le_per_adv_sync_cb *listener = NULL; + struct net_buf_simple_state state = {0}; + struct net_buf_simple buf = {0}; + + /* LOG_DBG("PaSyncReportRecvListener[%u][%u]", sync_handle, data_length); */ + + if (data == NULL || data_length == 0) { + LOG_DBG("PaSyncRecvDataNull[%u]", data_length); + return -EINVAL; + } + + per_adv_sync = per_adv_sync_find(sync_handle); + if (per_adv_sync == NULL) { + LOG_ERR("PaSyncNotFound[%u]", sync_handle); + return -ENODEV; + } + + info.addr = &per_adv_sync->addr; + info.sid = per_adv_sync->sid; + + net_buf_simple_init_with_data(&buf, (void *)data, data_length); + + SYS_SLIST_FOR_EACH_CONTAINER(&pa_sync_cbs, listener, node) { + if (listener->recv) { + net_buf_simple_save(&buf, &state); + listener->recv(per_adv_sync, &info, &buf); + net_buf_simple_restore(&buf, &state); + } + } + + return 0; +} + +_IDF_ONLY +void hci_le_biginfo_adv_report(struct net_buf *buf) +{ + struct bt_hci_evt_le_biginfo_adv_report *evt = (void *)buf->data; + struct bt_le_per_adv_sync *per_adv_sync = NULL; + struct bt_le_per_adv_sync_cb *listener = NULL; + struct bt_iso_biginfo biginfo = {0}; + + /* LOG_DBG("BigInfoRecvListener[%u]", evt->sync_handle); */ + + per_adv_sync = per_adv_sync_find(evt->sync_handle); + if (per_adv_sync == NULL) { + LOG_ERR("PaSyncNotFound[%u]", evt->sync_handle); + return; + } + + biginfo.addr = &per_adv_sync->addr; + biginfo.sid = per_adv_sync->sid; + biginfo.num_bis = evt->num_bis; + biginfo.sub_evt_count = evt->nse; + biginfo.iso_interval = evt->iso_interval; + biginfo.burst_number = evt->bn; + biginfo.offset = evt->pto; + biginfo.rep_count = evt->irc; + biginfo.max_pdu = evt->max_pdu; + biginfo.sdu_interval = sys_get_le24(evt->sdu_interval); + biginfo.max_sdu = evt->max_sdu; + biginfo.phy = evt->phy; + biginfo.framing = evt->framing; + biginfo.encryption = (evt->encryption ? true : false); + + SYS_SLIST_FOR_EACH_CONTAINER(&pa_sync_cbs, listener, node) { + if (listener->biginfo) { + listener->biginfo(per_adv_sync, &biginfo); + } + } +} + +_LIB_ONLY +int bt_le_scan_start(const struct bt_le_scan_param *param, void *cb) +{ + int err = 0; + + if (atomic_test_bit(bt_dev.flags, BT_DEV_SCANNING) == false) { + err = bt_le_nimble_scan_start(param, cb); + if (err == 0) { + atomic_set_bit(bt_dev.flags, BT_DEV_SCANNING); + } + } else { + err = -EALREADY; + } + + return err; +} + +_LIB_ONLY +int bt_le_scan_stop(void) +{ + int err = 0; + + if (atomic_test_bit(bt_dev.flags, BT_DEV_SCANNING)) { + err = bt_le_nimble_scan_stop(); + if (err == 0) { + atomic_clear_bit(bt_dev.flags, BT_DEV_SCANNING); + } + } + + return err; +} diff --git a/components/bt/esp_ble_audio/host/common/scan.h b/components/bt/esp_ble_audio/host/common/scan.h new file mode 100644 index 0000000000..12271db38d --- /dev/null +++ b/components/bt/esp_ble_audio/host/common/scan.h @@ -0,0 +1,58 @@ +/* + * SPDX-FileCopyrightText: 2017-2021 Nordic Semiconductor + * SPDX-FileCopyrightText: 2015-2016 Intel Corporation + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef HOST_COMMON_SCAN_H_ +#define HOST_COMMON_SCAN_H_ + +#include + +#include "sdkconfig.h" + +#include "nimble/gap.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void bt_le_scan_recv_listener(uint16_t event_type, + uint8_t addr_type, + uint8_t addr_val[6], + int8_t rssi, + int8_t tx_power, + uint8_t sid, + uint8_t pri_phy, + uint8_t sec_phy, + uint16_t per_adv_itvl, + uint8_t data_len, + uint8_t *data); + +struct bt_le_per_adv_sync *bt_le_per_adv_sync_find_safe(uint16_t sync_handle); + +int bt_le_per_adv_sync_new(uint16_t sync_handle, + uint8_t sid, + uint8_t phy, + uint16_t interval, + uint8_t addr_type, + const uint8_t addr[6], + struct bt_le_per_adv_sync **out_sync); + +int bt_le_per_adv_sync_delete(uint16_t sync_handle); + +int bt_le_per_adv_sync_establish_listener(uint16_t sync_handle); + +int bt_le_per_adv_sync_lost_listener(uint16_t sync_handle); + +int bt_le_per_adv_sync_report_recv_listener(uint16_t sync_handle, + const uint8_t *data, + size_t data_length); + +#ifdef __cplusplus +} +#endif + +#endif /* HOST_COMMON_SCAN_H_ */ diff --git a/components/bt/esp_ble_audio/host/common/task.c b/components/bt/esp_ble_audio/host/common/task.c new file mode 100644 index 0000000000..bc21e38044 --- /dev/null +++ b/components/bt/esp_ble_audio/host/common/task.c @@ -0,0 +1,127 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include <../host/conn_internal.h> + +#include "common/host.h" +#include "common/iso.h" +#include "common/app/gap.h" +#include "common/app/gatt.h" + +static QueueHandle_t iso_queue_handle; + +static TaskHandle_t iso_task_handle; + +extern void bt_le_timer_handle_event(void *arg); + +static void iso_task(void *p) +{ + struct iso_queue_item item = {0}; + + while (1) { + xQueueReceive(iso_queue_handle, &item, portMAX_DELAY); + + switch (item.type) { + case ISO_QUEUE_ITEM_TYPE_TIMER_EVENT: + bt_le_timer_handle_event(item.data); + break; + case ISO_QUEUE_ITEM_TYPE_GAP_EVENT: + bt_le_gap_handle_event(item.data, item.data_len); + break; + case ISO_QUEUE_ITEM_TYPE_GATT_EVENT: + bt_le_gatt_handle_event(item.data, item.data_len); + break; + case ISO_QUEUE_ITEM_TYPE_ISO_HCI_EVENT: + bt_le_iso_handle_hci_event(item.data, item.data_len); + break; + case ISO_QUEUE_ITEM_TYPE_ISO_TX_COMP: + bt_le_iso_handle_tx_comp(item.data, item.data_len); + break; + case ISO_QUEUE_ITEM_TYPE_ISO_RX_DATA: + bt_le_iso_handle_rx_data(item.data, item.data_len); + break; + default: + if (item.data) { + free(item.data); + } + assert(0); + break; + } + } +} + +int bt_le_iso_task_post(enum iso_queue_item_type type, + void *data, size_t data_len) +{ + struct iso_queue_item item = {0}; + int ret; + + item.type = type; + item.data = data; + item.data_len = data_len; + + ret = xQueueSend(iso_queue_handle, &item, portMAX_DELAY); + if (ret != pdTRUE) { + LOG_ERR("IsoQPostFail[%d]", ret); + return -1; + } + + return 0; +} + +int bt_le_iso_task_init(void) +{ + int ret; + + LOG_DBG("IsoTaskInit"); + + iso_queue_handle = xQueueCreate(ISO_QUEUE_ITEM_COUNT, ISO_QUEUE_ITEM_SIZE); + if (iso_queue_handle == NULL) { + LOG_ERR("IsoQCreateFail"); + return -EIO; + } + + ret = xTaskCreatePinnedToCore(iso_task, + ISO_TASK_NAME, + ISO_TASK_STACK_SIZE, + NULL, + ISO_TASK_PRIO, + &iso_task_handle, + ISO_TASK_CORE); + if (ret != pdTRUE) { + LOG_ERR("IsoTaskCreateFail[%d]", ret); + vQueueDelete(iso_queue_handle); + iso_queue_handle = NULL; + return -EIO; + } + + return 0; +} + +void bt_le_iso_task_deinit(void) +{ + LOG_DBG("IsoTaskDeinit"); + + if (iso_task_handle) { + vTaskDelete(iso_task_handle); + iso_task_handle = NULL; + } + + if (iso_queue_handle) { + vQueueDelete(iso_queue_handle); + iso_queue_handle = NULL; + } +} diff --git a/components/bt/esp_ble_audio/host/common/task.h b/components/bt/esp_ble_audio/host/common/task.h new file mode 100644 index 0000000000..92c7ef0cda --- /dev/null +++ b/components/bt/esp_ble_audio/host/common/task.h @@ -0,0 +1,67 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef HOST_COMMON_TASK_H_ +#define HOST_COMMON_TASK_H_ + +#include + +#include "sdkconfig.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "freertos/semphr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if CONFIG_BT_NIMBLE_PINNED_TO_CORE +#define ISO_TASK_CORE CONFIG_BT_NIMBLE_PINNED_TO_CORE +#else /* CONFIG_BT_NIMBLE_PINNED_TO_CORE */ +#define ISO_TASK_CORE (0) +#endif /* CONFIG_BT_NIMBLE_PINNED_TO_CORE */ + +#define ISO_TASK_STACK_SIZE 4096 +#define ISO_TASK_NAME "iso_task" +/* Ref: + * - NimBLE Host task: configMAX_PRIORITIES - 4 + */ +#define ISO_TASK_PRIO (configMAX_PRIORITIES - 4) + +enum iso_queue_item_type { + ISO_QUEUE_ITEM_TYPE_TIMER_EVENT, + ISO_QUEUE_ITEM_TYPE_GAP_EVENT, + ISO_QUEUE_ITEM_TYPE_GATT_EVENT, + ISO_QUEUE_ITEM_TYPE_ISO_HCI_EVENT, + ISO_QUEUE_ITEM_TYPE_ISO_TX_COMP, + ISO_QUEUE_ITEM_TYPE_ISO_RX_DATA, + + ISO_QUEUE_ITEM_TYPE_MAX, +}; + +struct iso_queue_item { + uint8_t type; + uint8_t *data; + size_t data_len; +}; + +#define ISO_QUEUE_ITEM_COUNT 100 +#define ISO_QUEUE_ITEM_SIZE sizeof(struct iso_queue_item) + +int bt_le_iso_task_post(enum iso_queue_item_type type, + void *data, size_t data_len); + +int bt_le_iso_task_init(void); + +void bt_le_iso_task_deinit(void); + +#ifdef __cplusplus +} +#endif + +#endif /* HOST_COMMON_TASK_H_ */ diff --git a/components/bt/esp_ble_audio/host/iso/Kconfig.iso.in b/components/bt/esp_ble_audio/host/iso/Kconfig.iso.in new file mode 100644 index 0000000000..099231c7a9 --- /dev/null +++ b/components/bt/esp_ble_audio/host/iso/Kconfig.iso.in @@ -0,0 +1,150 @@ +# SPDX-FileCopyrightText: 2016 Intel Corporation +# SPDX-FileCopyrightText: 2021 Nordic Semiconductor ASA +# SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 + +config BT_ISO + bool + select BT_NIMBLE_ISO if BT_NIMBLE_ENABLED + +config BT_ISO_TX + bool + +config BT_ISO_RX + bool + +config BT_ISO_UNICAST + bool + select BT_ISO + select BT_ISO_TX + select BT_ISO_RX + help + This option enables support for Bluetooth Unicast + Isochronous channels. + +config BT_ISO_PERIPHERAL + bool "Bluetooth Isochronous Channel Unicast Peripheral Support" + select BT_ISO_UNICAST + help + This option enables support for Bluetooth Unicast + Isochronous channels for the peripheral role. + +config BT_ISO_CENTRAL + bool "Bluetooth Isochronous Channel Unicast Central Support" + select BT_ISO_UNICAST + help + This option enables support for Bluetooth Broadcast + Isochronous channels for the central role. + +config BT_ISO_BROADCAST + bool + select BT_ISO + +config BT_ISO_BROADCASTER + bool "Bluetooth Isochronous Broadcaster Support" + select BT_ISO_BROADCAST + select BT_ISO_TX + select BT_BROADCASTER + help + This option enables support for the Bluetooth Isochronous Broadcaster. + +config BT_ISO_SYNC_RECEIVER + bool "Bluetooth Isochronous Synchronized Receiver Support" + select BT_ISO_BROADCAST + select BT_ISO_RX + help + This option enables support for the Bluetooth Isochronous + Synchronized Receiver. + +if BT_ISO + + config BT_ISO_MAX_CHAN + int "Maximum number of simultaneous ISO channels" + default 1 + range 1 64 + help + Maximum number of simultaneous Bluetooth isochronous channels + supported. + + config BT_ISO_TEST_PARAMS + bool "ISO test parameters support" + default BT_NIMBLE_ISO_TEST if BT_NIMBLE_ENABLED + help + Enabling advanced ISO parameters will allow the use of the ISO test + parameters for creating a CIG or a BIG. These test parameters were + intended for testing, but can be used to allow the host to set more + settings that are otherwise usually controlled by the controller. + + if BT_ISO_UNICAST + + config BT_ISO_MAX_CIG + int "Maximum number of Connected Isochronous Groups (CIGs) to support" + range 1 BT_NIMBLE_ISO_CIG + help + Maximum number of CIGs that are supported by the host. A CIG can be + used for either transmitting or receiving. + + endif # BT_ISO_UNICAST + + if BT_ISO_BROADCAST + + config BT_ISO_MAX_BIG + int "Maximum number of Broadcast Isochronous Groups (BIGs) to support" + range 1 BT_NIMBLE_ISO_BIG + help + Maximum number of BIGs that are supported by the host. A BIG can be + used for either transmitting or receiving, but not at the same time. + + endif # BT_ISO_BROADCAST + + config BT_ISO_NO_LOG + bool "Disable ISO Debug Log" + default n + help + Select this to save the ISO related rodata code size. Enabling + this option will disable the output of ISO debug log. + + menu "ISO Debug Log Level" + depends on !BT_ISO_NO_LOG + + choice BT_ISO_LOG_LEVEL + prompt "ISO_LOG_LEVEL" + default BT_ISO_LOG_LEVEL_WARNING + depends on !BT_ISO_NO_LOG + help + Define ISO trace level. + + config BT_ISO_LOG_LEVEL_NONE + bool "NONE" + config BT_ISO_LOG_LEVEL_ERROR + bool "ERROR" + config BT_ISO_LOG_LEVEL_WARNING + bool "WARNING" + config BT_ISO_LOG_LEVEL_INFO + bool "INFO" + config BT_ISO_LOG_LEVEL_DEBUG + bool "DEBUG" + config BT_ISO_LOG_LEVEL_VERBOSE + bool "VERBOSE" + endchoice + + config BT_ISO_LOG_LEVEL + int + default 0 if BT_ISO_LOG_LEVEL_NONE + default 1 if BT_ISO_LOG_LEVEL_ERROR + default 2 if BT_ISO_LOG_LEVEL_WARNING + default 3 if BT_ISO_LOG_LEVEL_INFO + default 4 if BT_ISO_LOG_LEVEL_DEBUG + default 5 if BT_ISO_LOG_LEVEL_VERBOSE + default 2 + endmenu + + config BT_DEBUG_ISO_DATA + bool # hidden + depends on !BT_ISO_NO_LOG + help + Use this option to enable ISO channels data debug logs for the + Bluetooth Audio functionality. This will enable debug logs for + all ISO data received and sent. + +endif # BT_ISO diff --git a/components/bt/esp_ble_audio/host/iso/iso.c b/components/bt/esp_ble_audio/host/iso/iso.c new file mode 100644 index 0000000000..256fce4344 --- /dev/null +++ b/components/bt/esp_ble_audio/host/iso/iso.c @@ -0,0 +1,3582 @@ +/* Bluetooth ISO */ + +/* + * SPDX-FileCopyrightText: 2020 Intel Corporation + * SPDX-FileCopyrightText: 2021-2025 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "host/hci_core.h" +#include "host/conn_internal.h" +#include "iso_internal.h" + +#include "common/host.h" + +#if CONFIG_FREERTOS_HZ < 1000 +#warning "FreeRTOS with 1ms tick rate is strongly recommended for running ISO." +#endif /* CONFIG_FREERTOS_HZ < 1000 */ + +LOG_MODULE_REGISTER(bt_iso, CONFIG_BT_ISO_LOG_LEVEL); + +#if defined(CONFIG_BT_DEBUG_ISO_DATA) +#define BT_ISO_DATA_DBG(fmt, ...) LOG_DBG(fmt, ##__VA_ARGS__) +#else +#define BT_ISO_DATA_DBG(fmt, ...) +#endif /* CONFIG_BT_DEBUG_ISO_DATA */ + +#define iso_chan(_iso) ((_iso)->iso.chan); + +struct bt_conn iso_conns[CONFIG_BT_ISO_MAX_CHAN]; + +/* TODO: Allow more than one server? */ +#if defined(CONFIG_BT_ISO_CENTRAL) +struct bt_iso_cig cigs[CONFIG_BT_ISO_MAX_CIG]; + +static struct bt_iso_cig *get_cig(const struct bt_iso_chan *iso_chan); +#endif /* CONFIG_BT_ISO_CENTRAL */ + +#if defined(CONFIG_BT_ISO_PERIPHERAL) +static struct bt_iso_server *iso_server; + +static struct bt_conn *bt_conn_add_iso(struct bt_conn *acl); +#endif /* CONFIG_BT_ISO_PERIPHERAL */ + +#if defined(CONFIG_BT_ISO_BROADCAST) +struct bt_iso_big bigs[CONFIG_BT_ISO_MAX_BIG]; + +static struct bt_iso_big *lookup_big_by_handle(uint8_t big_handle); +#endif /* CONFIG_BT_ISO_BROADCAST */ + +static void bt_iso_sent_cb(struct bt_conn *iso, void *user_data, int err) +{ +#if defined(CONFIG_BT_ISO_TX) + struct bt_iso_chan *chan = iso->iso.chan; + struct bt_iso_chan_ops *ops; + + assert(chan != NULL && "NUllConnForISOSentCb"); + + ops = chan->ops; + + if (!err && ops != NULL && ops->sent != NULL) { + ops->sent(chan, user_data); + } +#endif /* CONFIG_BT_ISO_TX */ +} + +void hci_iso(struct net_buf *buf) +{ + struct bt_hci_iso_hdr *hdr; + uint16_t handle, len; + struct bt_conn *iso; + uint8_t flags; + + if (buf->len < sizeof(*hdr)) { + LOG_ERR("InvIsoPktSize[%u]", buf->len); + return; + } + + hdr = net_buf_pull_mem(buf, sizeof(*hdr)); + len = bt_iso_hdr_len(sys_le16_to_cpu(hdr->len)); + handle = sys_le16_to_cpu(hdr->handle); + flags = bt_iso_flags(handle); + + iso(buf)->handle = bt_iso_handle(handle); + iso(buf)->index = BT_CONN_INDEX_INVALID; + + if (buf->len != len) { + LOG_ERR("MismatchIsoDataLen[%u][%u]", buf->len, len); + return; + } + + iso = bt_conn_lookup_handle(iso(buf)->handle, BT_CONN_TYPE_ISO); + if (iso == NULL) { + LOG_ERR("ConnNotFoundForHdl[%u]", iso(buf)->handle); + return; + } + + iso(buf)->index = bt_conn_index(iso); + + bt_iso_recv(iso, buf, flags); + bt_conn_unref(iso); +} + +static void iso_get_and_clear_cb(struct bt_conn *conn, struct net_buf *buf, bt_conn_tx_cb_t *cb, + void **ud) +{ + if (IS_ENABLED(CONFIG_BT_ISO_TX)) { + *cb = bt_iso_sent_cb; + } else { + *cb = NULL; + } + + *ud = NULL; +} + +static struct bt_conn *iso_new(void) +{ + struct bt_conn *iso = bt_conn_new(iso_conns, ARRAY_SIZE(iso_conns)); + + LOG_DBG("IsoNew"); + + if (iso) { + iso->type = BT_CONN_TYPE_ISO; + iso->get_and_clear_cb = iso_get_and_clear_cb; + } + + return iso; +} + +static int hci_le_setup_iso_data_path(const struct bt_conn *iso, uint8_t dir, + const struct bt_iso_chan_path *path) +{ + struct bt_hci_cp_le_setup_iso_path *cp; + struct bt_hci_rp_le_setup_iso_path *rp; + struct net_buf *buf, *rsp; + uint8_t *cc; + int err; + + LOG_DBG("SetupIsoDataPath[%u]", dir); + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_SETUP_ISO_PATH, sizeof(*cp) + path->cc_len); + if (!buf) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + cp->handle = sys_cpu_to_le16(iso->handle); + cp->path_dir = dir; + cp->path_id = path->pid; + cp->codec_id.coding_format = path->format; + cp->codec_id.company_id = sys_cpu_to_le16(path->cid); + cp->codec_id.vs_codec_id = sys_cpu_to_le16(path->vid); + sys_put_le24(path->delay, cp->controller_delay); + cp->codec_config_len = path->cc_len; + cc = net_buf_add(buf, path->cc_len); + if (path->cc_len) { + memcpy(cc, path->cc, path->cc_len); + } + err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SETUP_ISO_PATH, buf, &rsp); + if (err) { + return err; + } + + rp = (void *)rsp->data; + if (rp->status || (sys_le16_to_cpu(rp->handle) != iso->handle)) { + LOG_ERR("SetupIsoDataPathFail[%02x][%u][%u]", + rp->status, rp->handle, iso->handle); + err = -EIO; + } + + net_buf_unref(rsp); + + return err; +} + +static void bt_iso_chan_add(struct bt_conn *iso, struct bt_iso_chan *chan) +{ + /* Attach ISO channel to the connection */ + chan->iso = iso; + iso->iso.chan = chan; + + LOG_DBG("IsoChanAdd"); +} + +static int validate_iso_setup_data_path_parms(const struct bt_iso_chan *chan, uint8_t dir, + const struct bt_iso_chan_path *path) +{ + struct bt_conn *iso; + + CHECKIF(chan == NULL) { + LOG_DBG("ChanNull"); + + return -EINVAL; + } + + CHECKIF(path == NULL) { + LOG_DBG("PathNull"); + + return -EINVAL; + } + + CHECKIF(dir != BT_HCI_DATAPATH_DIR_HOST_TO_CTLR && + dir != BT_HCI_DATAPATH_DIR_CTLR_TO_HOST) { + LOG_DBG("InvDir[%u]", dir); + + return -EINVAL; + } + + iso = chan->iso; + if (iso == NULL) { + LOG_DBG("ChanNotAssociated[%p]", chan); + + return -ENODEV; + } + + if (!iso->iso.info.can_recv && dir == BT_HCI_DATAPATH_DIR_CTLR_TO_HOST) { + LOG_DBG("InvDirForChanCannotRecv[%u][%p]", dir, chan); + + return -EINVAL; + } + + if (!iso->iso.info.can_send && dir == BT_HCI_DATAPATH_DIR_HOST_TO_CTLR) { + LOG_DBG("InvDirForChanCannotSend[%u][%p]", dir, chan); + + return -EINVAL; + } + + CHECKIF(path->pid != BT_ISO_DATA_PATH_HCI && + !IN_RANGE(path->pid, BT_ISO_DATA_PATH_VS_ID_MIN, BT_ISO_DATA_PATH_VS_ID_MAX)) { + LOG_DBG("InvPid[%u]", path->pid); + + return -EINVAL; + } + + CHECKIF(path->format > BT_HCI_CODING_FORMAT_G729A && + path->format != BT_HCI_CODING_FORMAT_VS) { + LOG_DBG("InvFormat[%u]", path->format); + + return -EINVAL; + } + + CHECKIF(path->delay > BT_ISO_CONTROLLER_DELAY_MAX) { + LOG_DBG("InvDelay[%u]", path->delay); + + return -EINVAL; + } + + CHECKIF(path->cc_len > 0U && path->cc == NULL) { + LOG_DBG("NoCcProvidedForCcLen[%u]", path->cc_len); + + return -EINVAL; + } + + return 0; +} + +int bt_iso_setup_data_path(const struct bt_iso_chan *chan, uint8_t dir, + const struct bt_iso_chan_path *path) +{ + int err; + + LOG_DBG("IsoSetupDataPath"); + + err = validate_iso_setup_data_path_parms(chan, dir, path); + if (err != 0) { + return err; + } + + err = hci_le_setup_iso_data_path(chan->iso, dir, path); + if (err != 0) { + LOG_DBG("SetDataPathFail[%d]", err); + + /* Return known possible errors */ + if (err == -ENOBUFS || err == -EIO || err == -EACCES) { + return err; + } + + LOG_DBG("UnkErrFromSetupIsoDataPath[%d]", err); + + return -ENOEXEC; + } + + return 0; +} + +static int hci_le_remove_iso_data_path(struct bt_conn *iso, uint8_t dir) +{ + struct bt_hci_cp_le_remove_iso_path *cp; + struct bt_hci_rp_le_remove_iso_path *rp; + struct net_buf *buf, *rsp; + int err; + + LOG_DBG("RemoveIsoDataPath[%u]", dir); + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_REMOVE_ISO_PATH, sizeof(*cp)); + if (!buf) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + cp->handle = sys_cpu_to_le16(iso->handle); + /* The path_dir is a bitfield and it's technically possible to do BIT(0) | BIT(1) but for + * simplicity our API only supports removing a single ISO data path at a time. + * We can convert from BT_HCI_DATAPATH_DIR_HOST_TO_CTLR and BT_HCI_DATAPATH_DIR_CTLR_TO_HOST + * to the proper values just by using `BIT` + */ + cp->path_dir = BIT(dir); + + err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_REMOVE_ISO_PATH, buf, &rsp); + if (err) { + return err; + } + + rp = (void *)rsp->data; + if (rp->status || (sys_le16_to_cpu(rp->handle) != iso->handle)) { + LOG_ERR("RemoveIsoDataPathFail[%02x][%u][%u]", + rp->status, rp->handle, iso->handle); + err = -EIO; + } + + net_buf_unref(rsp); + + return err; +} + +static int validate_iso_remove_data_path(const struct bt_iso_chan *chan, uint8_t dir) +{ + struct bt_conn *iso; + + CHECKIF(chan == NULL) { + LOG_DBG("ChanNull"); + + return -EINVAL; + } + + CHECKIF(dir != BT_HCI_DATAPATH_DIR_HOST_TO_CTLR && + dir != BT_HCI_DATAPATH_DIR_CTLR_TO_HOST) { + LOG_DBG("InvDir[%u]", dir); + + return -EINVAL; + } + + iso = chan->iso; + if (iso == NULL) { + LOG_DBG("ChanNotAssociated[%p]", chan); + + return -ENODEV; + } + + return 0; +} + +int bt_iso_remove_data_path(const struct bt_iso_chan *chan, uint8_t dir) +{ + int err; + + err = validate_iso_remove_data_path(chan, dir); + if (err != 0) { + return err; + } + + err = hci_le_remove_iso_data_path(chan->iso, dir); + if (err != 0) { + LOG_DBG("RemoveDataPathFail[%d]", err); + + /* Return known possible errors */ + if (err == -ENOBUFS || err == -EIO || err == -EACCES) { + return err; + } + + LOG_DBG("UnkErrFromRemoveIsoDataPath[%d]", err); + + return -ENOEXEC; + } + + return 0; +} + +void bt_iso_connected(struct bt_conn *iso) +{ + struct bt_iso_chan *chan; + + if (iso == NULL || iso->type != BT_CONN_TYPE_ISO) { + LOG_ERR("InvParams[%p][%u]", iso, iso ? iso->type : 0); + return; + } + + LOG_DBG("IsoConnected"); + + chan = iso_chan(iso); + if (chan == NULL) { + LOG_ERR("ChanFromConnectedIsoNotFound"); + return; + } + + bt_iso_chan_set_state(chan, BT_ISO_STATE_CONNECTED); + + if (chan->ops->connected) { + chan->ops->connected(chan); + } +} + +static void bt_iso_chan_disconnected(struct bt_iso_chan *chan, uint8_t reason) +{ + assert(chan->iso != NULL && "NullConnForIsoChan"); + + const uint8_t conn_type = chan->iso->iso.info.type; + + LOG_DBG("IsoChanDisconnected[%02x]", reason); + + bt_iso_chan_set_state(chan, BT_ISO_STATE_DISCONNECTED); + bt_conn_set_state(chan->iso, BT_CONN_DISCONNECT_COMPLETE); + + /* Calling disconnected before final cleanup allows users to use bt_iso_chan_get_info in + * the callback and to be more similar to the ACL disconnected callback. This also means + * that the channel cannot be reused or memset in the callback + */ + if (chan->ops->disconnected) { + chan->ops->disconnected(chan, reason); + } + + /* The peripheral does not have the concept of a CIG, so once a CIS + * disconnects it is completely freed by unref'ing it + */ + if (IS_ENABLED(CONFIG_BT_ISO_UNICAST) && + (conn_type == BT_ISO_CHAN_TYPE_CENTRAL || conn_type == BT_ISO_CHAN_TYPE_PERIPHERAL)) { + bt_iso_cleanup_acl(chan->iso); + + if (conn_type == BT_ISO_CHAN_TYPE_PERIPHERAL) { + bt_conn_unref(chan->iso); + chan->iso = NULL; +#if defined(CONFIG_BT_ISO_CENTRAL) + } else { + bool is_chan_connected; + struct bt_iso_cig *cig; + struct bt_iso_chan *cis_chan; + + /* Update CIG state */ + cig = get_cig(chan); + assert(cig != NULL && "CigNull"); + + is_chan_connected = false; + SYS_SLIST_FOR_EACH_CONTAINER(&cig->cis_channels, cis_chan, node) { + if (cis_chan->state != BT_ISO_STATE_DISCONNECTED) { + is_chan_connected = true; + break; + } + } + + if (!is_chan_connected) { + cig->state = BT_ISO_CIG_STATE_INACTIVE; + } +#endif /* CONFIG_BT_ISO_CENTRAL */ + } + } else if (IS_ENABLED(CONFIG_BT_ISO_BROADCASTER) && + conn_type == BT_ISO_CHAN_TYPE_BROADCASTER) { + /* BIS do not get a HCI Disconnected event and will not handle cleanup of pending TX + * complete in the same way as ACL and CIS do. Call bt_conn_tx_notify directly here + * to flush the chan->iso->tx_complete for each disconnected BIS + */ + } else { + /* No special handling for BT_ISO_CHAN_TYPE_SYNC_RECEIVER */ + } +} + +void bt_iso_disconnected(struct bt_conn *iso) +{ + struct bt_iso_chan *chan; + + if (iso == NULL || iso->type != BT_CONN_TYPE_ISO) { + LOG_ERR("InvParams[%p][%u]", iso, iso ? iso->type : 0); + return; + } + + LOG_DBG("IsoDisconnected"); + + chan = iso_chan(iso); + if (chan == NULL) { + LOG_ERR("ChanNotFoundForDisconnectedIso"); + return; + } + + bt_iso_chan_disconnected(chan, iso->err); +} + +#if defined(CONFIG_BT_ISO_LOG_LEVEL_DBG) +const char *bt_iso_chan_state_str(uint8_t state) +{ + switch (state) { + case BT_ISO_STATE_DISCONNECTED: + return "disconnected"; + case BT_ISO_STATE_CONNECTING: + return "connecting"; + case BT_ISO_STATE_ENCRYPT_PENDING: + return "encryption pending"; + case BT_ISO_STATE_CONNECTED: + return "connected"; + case BT_ISO_STATE_DISCONNECTING: + return "disconnecting"; + default: + return "unknown"; + } +} + +void bt_iso_chan_set_state_debug(struct bt_iso_chan *chan, enum bt_iso_state state, + const char *func, int line) +{ + LOG_DBG("IsoChanSetState[%p][%s][%s]", + chan, bt_iso_chan_state_str(chan->state), bt_iso_chan_state_str(state)); + + /* check transitions validness */ + switch (state) { + case BT_ISO_STATE_DISCONNECTED: + /* regardless of old state always allows this states */ + break; + case BT_ISO_STATE_ENCRYPT_PENDING: + __fallthrough; + case BT_ISO_STATE_CONNECTING: + if (chan->state != BT_ISO_STATE_DISCONNECTED) { + LOG_WRN("InvTransition[%s][%d]", func, line); + } + break; + case BT_ISO_STATE_CONNECTED: + if (chan->state != BT_ISO_STATE_CONNECTING) { + LOG_WRN("InvTransition[%s][%d]", func, line); + } + break; + case BT_ISO_STATE_DISCONNECTING: + if (chan->state != BT_ISO_STATE_CONNECTING && + chan->state != BT_ISO_STATE_CONNECTED) { + LOG_WRN("InvTransition[%s][%d]", func, line); + } + break; + default: + LOG_ERR("UnkState[%s][%d][%u]", func, line, state); + return; + } + + chan->state = state; +} +#else +void bt_iso_chan_set_state(struct bt_iso_chan *chan, enum bt_iso_state state) +{ + LOG_DBG("IsoChanSetState[%p][%u]", chan, state); + chan->state = state; +} +#endif /* CONFIG_BT_ISO_LOG_LEVEL_DBG */ + +int bt_iso_chan_get_info(const struct bt_iso_chan *chan, struct bt_iso_info *info) +{ + LOG_DBG("IsoChanGetInfo"); + + CHECKIF(chan == NULL) { + LOG_ERR("ChanNull"); + return -EINVAL; + } + + CHECKIF(chan->iso == NULL) { + LOG_ERR("ChanIsoNull"); + return -EINVAL; + } + + CHECKIF(info == NULL) { + LOG_ERR("InfoNull"); + return -EINVAL; + } + + (void)memcpy(info, &chan->iso->iso.info, sizeof(*info)); + + return 0; +} + +#if defined(CONFIG_BT_ISO_RX) +void bt_iso_recv(struct bt_conn *iso, struct net_buf *buf, uint8_t flags) +{ + struct bt_iso_recv_info iso_info = {0}; + struct bt_hci_iso_sdu_hdr *hdr; + struct bt_iso_chan *chan; + uint8_t pb, ts; + uint16_t len, pkt_seq_no; + + pb = bt_iso_flags_pb(flags); + ts = bt_iso_flags_ts(flags); + + /* When the PB_Flag does not equal BT_ISO_START or BT_ISO_SINGLE, + * the fields Time_Stamp, Packet_Sequence_Number, Packet_Status_Flag + * and ISO_SDU_Length are omitted from the HCI ISO Data packet. + */ + switch (pb) { + case BT_ISO_SINGLE: + iso_info.flags = 0; + + /* The ISO_Data_Load field contains either the first fragment + * of an SDU or a complete SDU. + */ + if (ts) { + struct bt_hci_iso_sdu_ts_hdr *ts_hdr; + + ts_hdr = net_buf_pull_mem(buf, sizeof(*ts_hdr)); + iso_info.ts = sys_le32_to_cpu(ts_hdr->ts); + + hdr = &ts_hdr->sdu; + iso_info.flags |= BT_ISO_FLAGS_TS; + } else { + hdr = net_buf_pull_mem(buf, sizeof(*hdr)); + /* TODO: Generate a timestamp? */ + iso_info.ts = 0x00000000; + } + + len = sys_le16_to_cpu(hdr->slen); + flags = bt_iso_pkt_flags(len); + len = bt_iso_pkt_len(len); + pkt_seq_no = sys_le16_to_cpu(hdr->sn); + iso_info.seq_num = pkt_seq_no; + if (flags == BT_ISO_DATA_VALID) { + iso_info.flags |= BT_ISO_FLAGS_VALID; + } else if (flags == BT_ISO_DATA_INVALID) { + iso_info.flags |= BT_ISO_FLAGS_ERROR; + } else if (flags == BT_ISO_DATA_NOP) { + iso_info.flags |= BT_ISO_FLAGS_LOST; + } else { + LOG_WRN("InvIsoPsFlag[%02x]", flags); + iso_info.flags = 0; + } + break; + + default: + LOG_ERR("UnexpIsoPbFlag[%02x]", pb); + return; + } + + chan = iso_chan(iso); + if (chan == NULL) { + LOG_ERR("NoChanForIsoRecv"); + } else if (chan->ops->recv != NULL) { + chan->ops->recv(chan, &iso_info, buf->data, buf->len); + } +} +#endif /* CONFIG_BT_ISO_RX */ + +#if defined(CONFIG_BT_ISO_TX) +int bt_iso_chan_send(struct bt_iso_chan *chan, struct net_buf *buf, uint16_t seq_num) +{ + return bt_le_iso_tx(chan, buf, seq_num, 0, false); +} + +int bt_iso_chan_send_ts(struct bt_iso_chan *chan, struct net_buf *buf, uint16_t seq_num, + uint32_t ts) +{ + return bt_le_iso_tx(chan, buf, seq_num, ts, true); +} + +#if defined(CONFIG_BT_ISO_CENTRAL) || defined(CONFIG_BT_ISO_BROADCASTER) +static bool valid_chan_io_qos(const struct bt_iso_chan_io_qos *io_qos, bool is_tx, + bool is_broadcast, bool advanced) +{ + LOG_DBG("ValidChanIoQos[%u][%u][%u]", is_tx, is_broadcast, advanced); + + if (io_qos->phy != BT_GAP_LE_PHY_1M && + io_qos->phy != BT_GAP_LE_PHY_2M && + io_qos->phy != BT_GAP_LE_PHY_CODED) { + LOG_ERR("InvPhy[%u]", io_qos->phy); + + return false; + } + + if (IS_ENABLED(CONFIG_BT_ISO_BROADCASTER) && is_broadcast && + io_qos->rtn > BT_ISO_BROADCAST_RTN_MAX) { + LOG_ERR("InvRtn[%u]", io_qos->rtn); + + return false; + } + +#if defined(CONFIG_BT_ISO_TEST_PARAMS) + if (advanced) { + if (IS_ENABLED(CONFIG_BT_ISO_BROADCASTER) && is_broadcast) { + if (!IN_RANGE(io_qos->max_pdu, BT_ISO_BROADCAST_PDU_MIN, BT_ISO_PDU_MAX)) { + LOG_ERR("InvBroadcastPdu[%u]", io_qos->max_pdu); + + return false; + } + } else if (IS_ENABLED(CONFIG_BT_ISO_CENTRAL)) { + if (!IN_RANGE(io_qos->max_pdu, BT_ISO_CONNECTED_PDU_MIN, BT_ISO_PDU_MAX)) { + LOG_ERR("InvUnicastPdu[%u]", io_qos->max_pdu); + + return false; + } + } + + if (!IN_RANGE(io_qos->burst_number, BT_ISO_BN_MIN, BT_ISO_BN_MAX)) { + LOG_ERR("InvBn[%u]", io_qos->burst_number); + + return false; + } + } +#else + ARG_UNUSED(advanced); +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ + + return true; +} +#endif /* CONFIG_BT_ISO_CENTRAL || CONFIG_BT_ISO_BROADCASTER */ + +int bt_iso_chan_get_tx_sync(const struct bt_iso_chan *chan, struct bt_iso_tx_info *info) +{ + struct bt_hci_cp_le_read_iso_tx_sync *cp; + struct bt_hci_rp_le_read_iso_tx_sync *rp; + struct net_buf *buf; + struct net_buf *rsp = NULL; + int err; + + LOG_DBG("IsoChanGetTxSync"); + + CHECKIF(chan == NULL) { + LOG_ERR("ChanNUll"); + return -EINVAL; + } + + CHECKIF(chan->iso == NULL) { + LOG_ERR("ChanIsoNull"); + return -EINVAL; + } + + CHECKIF(info == NULL) { + LOG_ERR("InfoNUll"); + return -EINVAL; + } + + CHECKIF(chan->state != BT_ISO_STATE_CONNECTED) { + LOG_ERR("ChanNotConnected[%u]", chan->state); + return -ENOTCONN; + } + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_READ_ISO_TX_SYNC, sizeof(*cp)); + if (!buf) { + return -ENOMEM; + } + + cp = net_buf_add(buf, sizeof(*cp)); + cp->handle = sys_cpu_to_le16(chan->iso->handle); + + err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_READ_ISO_TX_SYNC, buf, &rsp); + if (err) { + return err; + } + + if (rsp) { + rp = (struct bt_hci_rp_le_read_iso_tx_sync *)rsp->data; + + info->ts = sys_le32_to_cpu(rp->timestamp); + info->seq_num = sys_le16_to_cpu(rp->seq); + info->offset = sys_get_le24(rp->offset); + + net_buf_unref(rsp); + } else { + return -ENOTSUP; + } + + return 0; +} +#endif /* CONFIG_BT_ISO_TX */ + +#if defined(CONFIG_BT_ISO_UNICAST) +int bt_iso_chan_disconnect(struct bt_iso_chan *chan) +{ + int err; + + LOG_DBG("IsoChanDisconnect"); + + CHECKIF(!chan) { + LOG_ERR("ChanNull"); + return -EINVAL; + } + + CHECKIF(chan->iso == NULL) { + LOG_ERR("ChanIsoNull"); + return -EINVAL; + } + + if (chan->iso->iso.acl == NULL || chan->state == BT_ISO_STATE_DISCONNECTED) { + LOG_ERR("ChanNotConnected[%u]", chan->state); + return -ENOTCONN; + } + + if (chan->state == BT_ISO_STATE_ENCRYPT_PENDING) { + LOG_WRN("ChanAlreadyDisconnected"); + bt_iso_chan_set_state(chan, BT_ISO_STATE_DISCONNECTED); + + if (chan->ops->disconnected) { + chan->ops->disconnected(chan, BT_HCI_ERR_LOCALHOST_TERM_CONN); + } + + return 0; + } + + if (chan->state == BT_ISO_STATE_DISCONNECTING) { + LOG_WRN("AlreadyDisconnecting"); + + return -EALREADY; + } + + if (IS_ENABLED(CONFIG_BT_ISO_PERIPHERAL) && chan->iso->role == BT_HCI_ROLE_PERIPHERAL && + chan->state == BT_ISO_STATE_CONNECTING) { + /* A CIS peripheral is not allowed to disconnect a CIS in the connecting state - It + * has to wait for a CIS Established event + */ + LOG_ERR("CisPerConnecting"); + return -EAGAIN; + } + + err = bt_conn_disconnect(chan->iso, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + if (err == 0) { + bt_iso_chan_set_state(chan, BT_ISO_STATE_DISCONNECTING); + } + + return err; +} + +void bt_iso_cleanup_acl(struct bt_conn *iso) +{ + LOG_DBG("IsoCleanupAcl[%u]", iso->iso.acl ? iso->iso.acl->handle : UINT16_MAX); + + if (iso->iso.acl) { + bt_conn_unref(iso->iso.acl); + iso->iso.acl = NULL; + } +} + +static void store_cis_info(const struct bt_hci_evt_le_cis_established *evt, struct bt_conn *iso) +{ + struct bt_conn_iso *iso_conn = &iso->iso; + struct bt_iso_info *info = &iso_conn->info; + struct bt_iso_unicast_info *unicast_info = &info->unicast; + struct bt_iso_unicast_tx_info *peripheral = &unicast_info->peripheral; + struct bt_iso_unicast_tx_info *central = &unicast_info->central; + const uint8_t c_phy = bt_get_phy(evt->c_phy); + const uint8_t p_phy = bt_get_phy(evt->p_phy); + struct bt_iso_chan_io_qos *tx; + struct bt_iso_chan_io_qos *rx; + struct bt_iso_chan *chan; + + iso_conn = &iso->iso; + chan = iso_conn->chan; + if (chan == NULL || chan->qos == NULL) { + LOG_ERR("CisChanOrQosNull[%p]", chan); + return; + } + + rx = chan->qos->rx; + tx = chan->qos->tx; + + LOG_DBG("StoreCisInfo[%p][%p][%p]", chan, tx, rx); + + if (iso->role == BT_HCI_ROLE_PERIPHERAL) { + /* As of BT Core 6.0, we can only get the SDU size if the controller + * supports bt_hci_evt_le_cis_established_v2. Since this is not guaranteeds, + * we fallback to using the PDU size as the SDU size. + */ + if (rx != NULL) { + rx->phy = c_phy; + rx->sdu = sys_le16_to_cpu(evt->c_max_pdu); + } + + if (tx != NULL) { + tx->phy = p_phy; + tx->sdu = sys_le16_to_cpu(evt->p_max_pdu); + } + + iso_conn->info.type = BT_ISO_CHAN_TYPE_PERIPHERAL; + } else { + /* values are already set for central - Verify */ + if (tx != NULL && tx->phy != c_phy) { + LOG_WRN("UnexpC2PPhy[%u][%u]", c_phy, tx->phy); + /* We assume that tx->phy has become invalid, and will use the event from + * the controller as the truth + */ + tx->phy = c_phy; + } + + if (rx != NULL && rx->phy != p_phy) { + LOG_WRN("UnexpP2CMaxSdu[%u][%u]", p_phy, rx->phy); + /* We assume that rx->phy has become invalid, and will use the event from + * the controller as the truth + */ + rx->phy = p_phy; + } + } + + /* Verify if device can send */ + iso_conn->info.can_send = false; + if (tx != NULL) { + if (iso->role == BT_HCI_ROLE_PERIPHERAL && evt->p_bn > 0) { + iso_conn->info.can_send = true; + } else if (iso->role == BT_HCI_ROLE_CENTRAL && evt->c_bn > 0) { + iso_conn->info.can_send = true; + } + } + + /* Verify if device can recv */ + iso_conn->info.can_recv = false; + if (rx != NULL) { + if (iso->role == BT_HCI_ROLE_PERIPHERAL && evt->c_bn > 0) { + iso_conn->info.can_recv = true; + } else if (iso->role == BT_HCI_ROLE_CENTRAL && evt->p_bn > 0) { + iso_conn->info.can_recv = true; + } + } + + info->iso_interval = sys_le16_to_cpu(evt->interval); + info->max_subevent = evt->nse; + + unicast_info->cig_sync_delay = sys_get_le24(evt->cig_sync_delay); + unicast_info->cis_sync_delay = sys_get_le24(evt->cis_sync_delay); + unicast_info->cig_id = iso_conn->info.unicast.cig_id; + unicast_info->cis_id = iso_conn->info.unicast.cis_id; + + central->bn = evt->c_bn; + central->phy = bt_get_phy(evt->c_phy); + central->latency = sys_get_le16(evt->c_latency); + central->max_pdu = sys_le16_to_cpu(evt->c_max_pdu); + /* Transform to n * 1.25ms */ + central->flush_timeout = info->iso_interval * evt->c_ft; + + peripheral->bn = evt->p_bn; + peripheral->phy = bt_get_phy(evt->p_phy); + peripheral->latency = sys_get_le16(evt->p_latency); + peripheral->max_pdu = sys_le16_to_cpu(evt->p_max_pdu); + /* Transform to n * 1.25ms */ + peripheral->flush_timeout = info->iso_interval * evt->p_ft; + + /* The following values are only available with bt_hci_evt_le_cis_established_v2 so + * initialize them to the "unknown" values + */ + unicast_info->subinterval = BT_ISO_SUBINTERVAL_UNKNOWN; + + if (iso->role == BT_HCI_ROLE_PERIPHERAL) { + central->max_sdu = central->max_pdu; + central->sdu_interval = BT_ISO_SDU_INTERVAL_UNKNOWN; + + peripheral->max_sdu = peripheral->max_pdu; + peripheral->sdu_interval = BT_ISO_SDU_INTERVAL_UNKNOWN; + } else { + central->max_sdu = tx == NULL ? 0 : tx->sdu; + central->sdu_interval = BT_ISO_SDU_INTERVAL_UNKNOWN; + + peripheral->max_sdu = rx == NULL ? 0 : rx->sdu; + peripheral->sdu_interval = BT_ISO_SDU_INTERVAL_UNKNOWN; + } +} + +/** Only store information that is not stored by store_cis_info + * Assumes that store_cis_info has been called first + */ +static void store_cis_info_v2(const struct bt_hci_evt_le_cis_established_v2 *evt, + struct bt_conn *iso) +{ + struct bt_conn_iso *iso_conn = &iso->iso; + struct bt_iso_info *info = &iso_conn->info; + struct bt_iso_unicast_info *unicast_info = &info->unicast; + struct bt_iso_unicast_tx_info *peripheral = &unicast_info->peripheral; + struct bt_iso_unicast_tx_info *central = &unicast_info->central; + const uint16_t c_max_sdu = sys_le16_to_cpu(evt->c_max_sdu); + const uint16_t p_max_sdu = sys_le16_to_cpu(evt->p_max_sdu); + struct bt_iso_chan_io_qos *tx; + struct bt_iso_chan_io_qos *rx; + struct bt_iso_chan *chan; + + /* The v1 version of the event is a subset of the v2 version - We can thus use the + * store_cis_info function for the majority of the info + */ + store_cis_info((const struct bt_hci_evt_le_cis_established *)evt, iso); + + LOG_DBG("StoreCisInfoV2"); + + chan = iso_conn->chan; + rx = chan->qos->rx; + tx = chan->qos->tx; + + if (iso->role == BT_HCI_ROLE_PERIPHERAL) { + /* Update the SDU sizes in the IO QoS fields stored by store_cis_info */ + if (rx != NULL) { + rx->sdu = c_max_sdu; + } + + if (tx != NULL) { + tx->sdu = p_max_sdu; + } + } else { + /* values are already set for central - Verify */ + if (tx != NULL && tx->sdu != c_max_sdu) { + LOG_WRN("UnexpC2PMaxSdu[%u][%u]", c_max_sdu, tx->sdu); + /* We assume that tx->sdu has become invalid, and will use the event from + * the controller as the truth + */ + tx->sdu = c_max_sdu; + } + + if (rx != NULL && rx->sdu != p_max_sdu) { + LOG_WRN("UnexpP2CMaxSdu[%u][%u]", p_max_sdu, rx->sdu); + /* We assume that rx->sdu has become invalid, and will use the event from + * the controller as the truth + */ + rx->sdu = p_max_sdu; + } + } + + unicast_info->subinterval = sys_get_le24(evt->sub_interval); + + central->max_sdu = sys_le16_to_cpu(evt->c_max_sdu); + central->sdu_interval = sys_get_le24(evt->c_sdu_interval); + + peripheral->max_sdu = sys_le16_to_cpu(evt->p_max_sdu); + peripheral->sdu_interval = sys_get_le24(evt->p_sdu_interval); +} + +void hci_le_cis_established(struct net_buf *buf) +{ + struct bt_hci_evt_le_cis_established *evt = (void *)buf->data; + uint16_t handle = sys_le16_to_cpu(evt->conn_handle); + struct bt_conn *iso; + + LOG_INF("CisEstab"); + LOG_INF("Evt[%02x][%04x][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u]", + evt->status, handle, sys_get_le24(evt->cig_sync_delay), + sys_get_le24(evt->cis_sync_delay), sys_get_le24(evt->c_latency), + sys_get_le24(evt->p_latency), evt->c_phy, evt->p_phy, evt->nse, + evt->c_bn, evt->p_bn, evt->c_ft, evt->p_ft, evt->c_max_pdu, + evt->p_max_pdu, evt->interval); + + /* ISO connection handles are already assigned at this point */ + iso = bt_conn_lookup_handle(handle, BT_CONN_TYPE_ISO); + if (!iso) { + /* If it is a local disconnect, then we may have received the disconnect complete + * event before this event, and in which case we do not expect to find the CIS + * object + */ + if (evt->status != BT_HCI_ERR_OP_CANCELLED_BY_HOST) { + LOG_ERR("NoConnFoundForHdl[%u]", handle); + } + + return; + } + + if (evt->status == BT_HCI_ERR_SUCCESS) { + store_cis_info(evt, iso); + bt_conn_set_state(iso, BT_CONN_CONNECTED); + } else if (iso->role == BT_HCI_ROLE_PERIPHERAL || + evt->status != BT_HCI_ERR_OP_CANCELLED_BY_HOST) { + iso->err = evt->status; + bt_iso_disconnected(iso); + } /* else we wait for disconnect event */ + + bt_conn_unref(iso); +} + +void hci_le_cis_established_v2(struct net_buf *buf) +{ + struct bt_hci_evt_le_cis_established_v2 *evt = (void *)buf->data; + uint16_t handle = sys_le16_to_cpu(evt->conn_handle); + struct bt_conn *iso; + + LOG_INF("CisEstabV2"); + LOG_INF("Evt[%02x][%04x][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u]", + evt->status, handle, sys_get_le24(evt->cig_sync_delay), + sys_get_le24(evt->cis_sync_delay), sys_get_le24(evt->c_latency), + sys_get_le24(evt->p_latency), evt->c_phy, evt->p_phy, evt->nse, + evt->c_bn, evt->p_bn, evt->c_ft, evt->p_ft, evt->c_max_pdu, + evt->p_max_pdu, evt->interval, sys_get_le24(evt->sub_interval), + evt->c_max_sdu, evt->p_max_sdu, sys_get_le24(evt->c_sdu_interval), + sys_get_le24(evt->p_sdu_interval), evt->framing); + + /* ISO connection handles are already assigned at this point */ + iso = bt_conn_lookup_handle(handle, BT_CONN_TYPE_ISO); + if (!iso) { + /* If it is a local disconnect, then we may have received the disconnect complete + * event before this event, and in which case we do not expect to find the CIS + * object + */ + if (evt->status != BT_HCI_ERR_OP_CANCELLED_BY_HOST) { + LOG_ERR("NoConnFoundForHdl[%u]", handle); + } + + return; + } + + if (evt->status == BT_HCI_ERR_SUCCESS) { + store_cis_info_v2(evt, iso); + bt_conn_set_state(iso, BT_CONN_CONNECTED); + } else if (iso->role == BT_HCI_ROLE_PERIPHERAL || + evt->status != BT_HCI_ERR_OP_CANCELLED_BY_HOST) { + iso->err = evt->status; + bt_iso_disconnected(iso); + } /* else we wait for disconnect event */ + + bt_conn_unref(iso); +} + +#if defined(CONFIG_BT_ISO_PERIPHERAL) +int bt_iso_server_register(struct bt_iso_server *server) +{ + LOG_DBG("IsoSrvReg"); + + CHECKIF(!server) { + LOG_ERR("SrvNull"); + return -EINVAL; + } + + /* Check if controller is ISO capable */ + if (!BT_FEAT_LE_CIS_PERIPHERAL(bt_dev.le.features)) { + LOG_ERR("CisPerNotSupp"); + return -ENOTSUP; + } + + if (iso_server) { + LOG_WRN("SrvExist"); + return -EADDRINUSE; + } + + if (!server->accept) { + LOG_ERR("SrvAcceptNull"); + return -EINVAL; + } + +#if defined(CONFIG_BT_SMP) + if (server->sec_level > BT_SECURITY_L3) { + LOG_ERR("InvSrvSecLevel[%u]", server->sec_level); + return -EINVAL; + } else if (server->sec_level < BT_SECURITY_L1) { + LOG_DBG("SrvSecLevelUpdatedToL1"); + /* Level 0 is only applicable for BR/EDR */ + server->sec_level = BT_SECURITY_L1; + } +#endif /* CONFIG_BT_SMP */ + + iso_server = server; + + return 0; +} + +int bt_iso_server_unregister(struct bt_iso_server *server) +{ + LOG_DBG("IsoSrvUnreg"); + + CHECKIF(!server) { + LOG_ERR("SrvNull"); + return -EINVAL; + } + + if (iso_server != server) { + LOG_ERR("SrvMismatch[%p][%p]", iso_server, server); + return -EINVAL; + } + + iso_server = NULL; + + return 0; +} + +static int iso_accept(struct bt_conn *acl, struct bt_conn *iso) +{ + struct bt_iso_accept_info accept_info; + struct bt_iso_chan *chan; + int err; + + CHECKIF(!iso || iso->type != BT_CONN_TYPE_ISO) { + LOG_ERR("InvParams[%p][%u]", iso, iso ? iso->type : 0); + return -EINVAL; + } + + LOG_DBG("IsoAccept"); + + accept_info.acl = acl; + accept_info.cig_id = iso->iso.info.unicast.cig_id; + accept_info.cis_id = iso->iso.info.unicast.cis_id; + + err = iso_server->accept(&accept_info, &chan); + if (err < 0) { + LOG_ERR("IsoSrvAcceptFail[%d]", err); + return err; + } + + if (chan == NULL) { + LOG_ERR("AcceptCbReturnedNullChan"); + return -ENOMEM; + } + +#if defined(CONFIG_BT_SMP) + chan->required_sec_level = iso_server->sec_level; +#endif /* CONFIG_BT_SMP */ + + bt_iso_chan_add(iso, chan); + bt_iso_chan_set_state(chan, BT_ISO_STATE_CONNECTING); + + return 0; +} + +static int hci_le_reject_cis(uint16_t handle, uint8_t reason) +{ + struct bt_hci_cp_le_reject_cis *cp; + struct net_buf *buf; + int err; + + LOG_DBG("RejectCis[%u][%02x]", handle, reason); + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_REJECT_CIS, sizeof(*cp)); + if (!buf) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + cp->handle = sys_cpu_to_le16(handle); + cp->reason = reason; + + err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_REJECT_CIS, buf, NULL); + if (err) { + return err; + } + + return 0; +} + +static int hci_le_accept_cis(uint16_t handle) +{ + struct bt_hci_cp_le_accept_cis *cp; + struct net_buf *buf; + int err; + + LOG_DBG("AcceptCis[%u]", handle); + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_ACCEPT_CIS, sizeof(*cp)); + if (!buf) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + cp->handle = sys_cpu_to_le16(handle); + + err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_ACCEPT_CIS, buf, NULL); + if (err) { + return err; + } + + return 0; +} + +static uint8_t iso_server_check_security(struct bt_conn *conn) +{ + LOG_DBG("IsoSrvCheckSec[%u][%u]", conn->sec_level, iso_server->sec_level); + + if (IS_ENABLED(CONFIG_BT_CONN_DISABLE_SECURITY)) { + return BT_HCI_ERR_SUCCESS; + } + +#if defined(CONFIG_BT_SMP) + if (conn->sec_level >= iso_server->sec_level) { + return BT_HCI_ERR_SUCCESS; + } + + return BT_HCI_ERR_INSUFFICIENT_SECURITY; +#else + return BT_HCI_ERR_SUCCESS; +#endif /* CONFIG_BT_SMP */ +} + +void hci_le_cis_req(struct net_buf *buf) +{ + struct bt_hci_evt_le_cis_req *evt = (void *)buf->data; + uint16_t acl_handle = sys_le16_to_cpu(evt->acl_handle); + uint16_t cis_handle = sys_le16_to_cpu(evt->cis_handle); + struct bt_conn *acl, *iso; + uint8_t sec_err; + int err; + + LOG_DBG("CisReqEvt[%u][%u][%u][%u]", + acl_handle, cis_handle, evt->cig_id, evt->cis_id); + + if (iso_server == NULL) { + LOG_WRN("NoIsoSrvReg"); + hci_le_reject_cis(cis_handle, BT_HCI_ERR_UNSPECIFIED); + return; + } + + /* Lookup existing connection with same handle */ + iso = bt_conn_lookup_handle(cis_handle, BT_CONN_TYPE_ISO); + if (iso) { + LOG_ERR("InvCisHdl[%u]", cis_handle); + hci_le_reject_cis(cis_handle, BT_HCI_ERR_CONN_LIMIT_EXCEEDED); + bt_conn_unref(iso); + return; + } + + /* Lookup ACL connection to attach */ + acl = bt_conn_lookup_handle(acl_handle, BT_CONN_TYPE_LE); + if (!acl) { + LOG_ERR("InvAclHdl[%u]", acl_handle); + hci_le_reject_cis(cis_handle, BT_HCI_ERR_UNKNOWN_CONN_ID); + return; + } + + sec_err = iso_server_check_security(acl); + if (sec_err != BT_HCI_ERR_SUCCESS) { + LOG_DBG("InsuffSec[%u]", sec_err); + err = hci_le_reject_cis(cis_handle, sec_err); + if (err != 0) { + LOG_ERR("RejectCisFail[%d]", err); + } + + bt_conn_unref(acl); + return; + } + + /* Add ISO connection */ + iso = bt_conn_add_iso(acl); + + bt_conn_unref(acl); + + if (!iso) { + LOG_ERR("AddCisToAclFail[%u]", acl_handle); + hci_le_reject_cis(cis_handle, BT_HCI_ERR_INSUFFICIENT_RESOURCES); + return; + } + + iso->iso.info.type = BT_ISO_CHAN_TYPE_PERIPHERAL; + iso->iso.info.unicast.cig_id = evt->cig_id; + iso->iso.info.unicast.cis_id = evt->cis_id; + + /* Request application to accept */ + err = iso_accept(acl, iso); + if (err) { + LOG_DBG("AppRejectedCis[%d]", err); + bt_iso_cleanup_acl(iso); + bt_conn_unref(iso); + hci_le_reject_cis(cis_handle, BT_HCI_ERR_INSUFFICIENT_RESOURCES); + return; + } + + iso->handle = cis_handle; + iso->role = BT_HCI_ROLE_PERIPHERAL; + bt_conn_set_state(iso, BT_CONN_INITIATING); + + err = hci_le_accept_cis(cis_handle); + if (err) { + bt_iso_cleanup_acl(iso); + bt_conn_unref(iso); + hci_le_reject_cis(cis_handle, BT_HCI_ERR_INSUFFICIENT_RESOURCES); + return; + } +} + +static struct bt_conn *bt_conn_add_iso(struct bt_conn *acl) +{ + struct bt_conn *iso = iso_new(); + + LOG_DBG("ConnAddIso[%u]", acl->handle); + + if (iso == NULL) { + LOG_ERR("NoFreeIso"); + return NULL; + } + + iso->iso.acl = bt_conn_ref(acl); + + return iso; +} +#endif /* CONFIG_BT_ISO_PERIPHERAL */ + +#if defined(CONFIG_BT_ISO_CENTRAL) +static bool valid_chan_qos(const struct bt_iso_chan_qos *qos, bool advanced) +{ + LOG_DBG("ValidChanQos[%u]", advanced); + +#if defined(CONFIG_BT_ISO_TEST_PARAMS) + if (advanced && !IN_RANGE(qos->num_subevents, BT_ISO_NSE_MIN, BT_ISO_NSE_MAX)) { + LOG_ERR("InvNse[%u]", qos->num_subevents); + + return false; + } +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ + + if (qos->rx == NULL && qos->tx == NULL) { + LOG_DBG("BothRxAndTxQosNull"); + return false; + } + + if (qos->rx != NULL && !valid_chan_io_qos(qos->rx, false, false, advanced)) { + LOG_DBG("InvRxQos"); + return false; + } + + if (qos->tx != NULL && !valid_chan_io_qos(qos->tx, true, false, advanced)) { + LOG_DBG("InvTxQos"); + return false; + } + + return true; +} + +static int hci_le_remove_cig(uint8_t cig_id) +{ + struct bt_hci_cp_le_remove_cig *req; + struct net_buf *buf; + + LOG_DBG("RemoveCig[%u]", cig_id); + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_REMOVE_CIG, sizeof(*req)); + if (!buf) { + return -ENOBUFS; + } + + req = net_buf_add(buf, sizeof(*req)); + + memset(req, 0, sizeof(*req)); + + req->cig_id = cig_id; + + return bt_hci_cmd_send_sync(BT_HCI_OP_LE_REMOVE_CIG, buf, NULL); +} + +static struct net_buf *hci_le_set_cig_params(const struct bt_iso_cig *cig, + const struct bt_iso_cig_param *param) +{ + struct bt_hci_cp_le_set_cig_params *req; + struct bt_hci_cis_params *cis_param; + struct net_buf *buf; + struct net_buf *rsp; + int i, err; + + LOG_DBG("SetCigParams[%u]", cig->id); + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_CIG_PARAMS, + sizeof(*req) + sizeof(*cis_param) * param->num_cis); + if (!buf) { + return NULL; + } + + req = net_buf_add(buf, sizeof(*req)); + + memset(req, 0, sizeof(*req)); + + req->cig_id = cig->id; + req->c_latency = sys_cpu_to_le16(param->c_to_p_latency); + req->p_latency = sys_cpu_to_le16(param->p_to_c_latency); + sys_put_le24(param->c_to_p_interval, req->c_interval); + sys_put_le24(param->p_to_c_interval, req->p_interval); + + req->sca = param->sca; + req->packing = param->packing; + req->framing = param->framing; + req->num_cis = param->num_cis; + + LOG_DBG("[%u][%u][%u][%u][%u][%u][%u][%u][%u]", + cig->id, param->c_to_p_latency, param->p_to_c_latency, + param->c_to_p_interval, param->p_to_c_interval, param->sca, + param->packing, param->framing, param->num_cis); + + /* Program the cis parameters */ + for (i = 0; i < param->num_cis; i++) { + struct bt_iso_chan *cis = param->cis_channels[i]; + struct bt_iso_chan_qos *qos = cis->qos; + + cis_param = net_buf_add(buf, sizeof(*cis_param)); + + memset(cis_param, 0, sizeof(*cis_param)); + + cis_param->cis_id = cis->iso->iso.info.unicast.cis_id; + + if (!qos->tx && !qos->rx) { + LOG_ERR("BothCisTxAndRxDisabled"); + net_buf_unref(buf); + return NULL; + } + + if (!qos->tx) { + /* Use RX PHY if TX is not set (disabled) + * to avoid setting invalid values + */ + cis_param->c_phy = qos->rx->phy; + } else { + cis_param->c_sdu = sys_cpu_to_le16(qos->tx->sdu); + cis_param->c_phy = qos->tx->phy; + cis_param->c_rtn = qos->tx->rtn; + } + + if (!qos->rx) { + /* Use TX PHY if RX is not set (disabled) + * to avoid setting invalid values + */ + cis_param->p_phy = qos->tx->phy; + } else { + cis_param->p_sdu = sys_cpu_to_le16(qos->rx->sdu); + cis_param->p_phy = qos->rx->phy; + cis_param->p_rtn = qos->rx->rtn; + } + + LOG_DBG("[%d]:[%u][%u][%u][%u][%u][%u][%u]", + i, cis_param->cis_id, cis_param->c_phy, cis_param->c_sdu, + cis_param->c_rtn, cis_param->p_phy, cis_param->p_sdu, + cis_param->p_rtn); + } + + err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_CIG_PARAMS, buf, &rsp); + if (err) { + return NULL; + } + + return rsp; +} + +#if defined(CONFIG_BT_ISO_TEST_PARAMS) +static struct net_buf *hci_le_set_cig_test_params(const struct bt_iso_cig *cig, + const struct bt_iso_cig_param *param) +{ + struct bt_hci_cp_le_set_cig_params_test *req; + struct bt_hci_cis_params_test *cis_param; + struct net_buf *buf; + struct net_buf *rsp; + int err; + + LOG_DBG("SetCigTestParams"); + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_CIG_PARAMS_TEST, + sizeof(*req) + sizeof(*cis_param) * param->num_cis); + if (!buf) { + return NULL; + } + + req = net_buf_add(buf, sizeof(*req)); + + memset(req, 0, sizeof(*req)); + + req->cig_id = cig->id; + sys_put_le24(param->c_to_p_interval, req->c_interval); + sys_put_le24(param->p_to_c_interval, req->p_interval); + + req->c_ft = param->c_to_p_ft; + req->p_ft = param->p_to_c_ft; + req->iso_interval = sys_cpu_to_le16(param->iso_interval); + req->sca = param->sca; + req->packing = param->packing; + req->framing = param->framing; + req->num_cis = param->num_cis; + + LOG_DBG("[%u][%u][%u][%u][%u][%u][%u][%u][%u][%u]", + cig->id, param->c_to_p_interval, param->p_to_c_interval, + param->c_to_p_ft, param->p_to_c_ft, param->iso_interval, + param->sca, param->packing, param->framing, param->num_cis); + + /* Program the cis parameters */ + for (uint8_t i = 0U; i < param->num_cis; i++) { + const struct bt_iso_chan *cis = param->cis_channels[i]; + const struct bt_iso_chan_qos *qos = cis->qos; + + cis_param = net_buf_add(buf, sizeof(*cis_param)); + + memset(cis_param, 0, sizeof(*cis_param)); + + cis_param->cis_id = cis->iso->iso.info.unicast.cis_id; + cis_param->nse = qos->num_subevents; + + if (!qos->tx && !qos->rx) { + LOG_ERR("BothCisTxAndRxDisabled"); + net_buf_unref(buf); + return NULL; + } + + if (!qos->tx) { + /* Use RX PHY if TX is not set (disabled) + * to avoid setting invalid values + */ + cis_param->c_phy = qos->rx->phy; + } else { + cis_param->c_sdu = sys_cpu_to_le16(qos->tx->sdu); + cis_param->c_pdu = sys_cpu_to_le16(qos->tx->max_pdu); + cis_param->c_phy = qos->tx->phy; + cis_param->c_bn = qos->tx->burst_number; + } + + if (!qos->rx) { + /* Use TX PHY if RX is not set (disabled) + * to avoid setting invalid values + */ + cis_param->p_phy = qos->tx->phy; + } else { + cis_param->p_sdu = sys_cpu_to_le16(qos->rx->sdu); + cis_param->p_pdu = sys_cpu_to_le16(qos->rx->max_pdu); + cis_param->p_phy = qos->rx->phy; + cis_param->p_bn = qos->rx->burst_number; + } + + LOG_DBG("[%d]:[%u][%u][%u][%u][%u][%u][%u][%u][%u][%u]", + i, cis_param->cis_id, cis_param->nse, cis_param->c_sdu, + cis_param->p_sdu, cis_param->c_pdu, cis_param->p_pdu, + cis_param->c_phy, cis_param->p_phy, cis_param->c_bn, + cis_param->p_bn); + } + + err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_CIG_PARAMS_TEST, buf, &rsp); + if (err) { + return NULL; + } + + return rsp; +} + +static bool is_advanced_cig_param(const struct bt_iso_cig_param *param) +{ + LOG_DBG("IsAdvancedCigParam[%u][%u][%u]", + param->c_to_p_ft, param->p_to_c_ft, param->iso_interval); + + if (param->c_to_p_ft != 0U || param->p_to_c_ft != 0U || param->iso_interval != 0U) { + return true; + } + + /* Check if any of the CIS contain any test-param-only values */ + for (uint8_t i = 0U; i < param->num_cis; i++) { + const struct bt_iso_chan *cis = param->cis_channels[i]; + const struct bt_iso_chan_qos *qos = cis->qos; + + if (qos->num_subevents > 0U) { + return true; + } + + if (qos->tx != NULL) { + if (qos->tx->max_pdu > 0U || qos->tx->burst_number > 0U) { + return true; + } + } + + if (qos->rx != NULL) { + if (qos->rx->max_pdu > 0U || qos->rx->burst_number > 0U) { + return true; + } + } + } + + return false; +} +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ + +static struct bt_iso_cig *get_cig(const struct bt_iso_chan *iso_chan) +{ + LOG_DBG("GetCig[%p]", iso_chan); + + if (iso_chan == NULL || iso_chan->iso == NULL) { + return NULL; + } + + assert(iso_chan->iso->iso.info.unicast.cig_id < ARRAY_SIZE(cigs) && "InvCIGID"); + + return &cigs[iso_chan->iso->iso.info.unicast.cig_id]; +} + +static struct bt_iso_cig *get_free_cig(void) +{ + /* We can use the index in the `cigs` array as CIG ID */ + + LOG_DBG("GetFreeCig"); + + for (size_t i = 0; i < ARRAY_SIZE(cigs); i++) { + if (cigs[i].state == BT_ISO_CIG_STATE_IDLE) { + cigs[i].state = BT_ISO_CIG_STATE_CONFIGURED; + cigs[i].id = i; + sys_slist_init(&cigs[i].cis_channels); + LOG_DBG("CigNew[%zu]", i); + return &cigs[i]; + } + } + + LOG_ERR("NoFreeCig"); + + return NULL; +} + +static bool cis_is_in_cig(const struct bt_iso_cig *cig, const struct bt_iso_chan *cis) +{ + if (cig == NULL || cis == NULL || cis->iso == NULL) { + return false; + } + + return cig->id == cis->iso->iso.info.unicast.cig_id; +} + +static int cig_init_cis(struct bt_iso_cig *cig, const struct bt_iso_cig_param *param) +{ + LOG_DBG("CigInitCis[%u]", cig->id); + + for (uint8_t i = 0; i < param->num_cis; i++) { + struct bt_iso_chan *cis = param->cis_channels[i]; + + if (cis->iso == NULL) { + struct bt_conn_iso *iso_conn; + + cis->iso = iso_new(); + if (cis->iso == NULL) { + LOG_ERR("NoFreeCis"); + return -ENOMEM; + } + iso_conn = &cis->iso->iso; + + iso_conn->info.unicast.cig_id = cig->id; + iso_conn->info.type = BT_ISO_CHAN_TYPE_CENTRAL; + iso_conn->info.unicast.cis_id = cig->num_cis++; + + bt_iso_chan_add(cis->iso, cis); + + sys_slist_append(&cig->cis_channels, &cis->node); + } /* else already initialized */ + } + + return 0; +} + +static void cleanup_cig(struct bt_iso_cig *cig) +{ + struct bt_iso_chan *cis, *tmp; + + LOG_DBG("CleanupCig"); + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&cig->cis_channels, cis, tmp, node) { + if (cis->iso != NULL) { + bt_conn_unref(cis->iso); + cis->iso = NULL; + } + + sys_slist_remove(&cig->cis_channels, NULL, &cis->node); + } + + memset(cig, 0, sizeof(*cig)); +} + +static bool valid_cig_param(const struct bt_iso_cig_param *param, bool advanced, + const struct bt_iso_cig *cig) +{ + bool is_c_to_p = false; + bool is_p_to_c = false; + + if (param == NULL) { + return false; + } + + if (param->num_cis > BT_ISO_MAX_GROUP_ISO_COUNT || + param->num_cis > CONFIG_BT_ISO_MAX_CHAN) { + LOG_ERR("TooLargeNumCis[%u][%u]", + param->num_cis, MAX(CONFIG_BT_ISO_MAX_CHAN, BT_ISO_MAX_GROUP_ISO_COUNT)); + return false; + } + + for (uint8_t i = 0; i < param->num_cis; i++) { + struct bt_iso_chan *cis = param->cis_channels[i]; + + if (cis == NULL) { + LOG_ERR("CisChansNull[%u]", i); + return false; + } + + if (cis->qos == NULL) { + LOG_ERR("CisChanQosNull[%u]", i); + return false; + } + + if (cis->iso != NULL && !cis_is_in_cig(cig, cis)) { + LOG_WRN("CisChanExist[%u][%p]", i, get_cig(cis)); + return false; + } + + if (!valid_chan_qos(cis->qos, advanced)) { + LOG_ERR("InvCisChanQos[%u]", i); + return false; + } + + for (uint8_t j = 0; j < i; j++) { + if (cis == param->cis_channels[j]) { + LOG_ERR("DuplicateCis[%u][%u]", i, j); + return false; + } + } + + if (cis->qos->rx != NULL && cis->qos->rx->sdu != 0U) { + is_p_to_c = true; + } + + if (cis->qos->tx != NULL && cis->qos->tx->sdu != 0U) { + is_c_to_p = true; + } + } + + if (param->framing != BT_ISO_FRAMING_UNFRAMED && param->framing != BT_ISO_FRAMING_FRAMED) { + LOG_ERR("InvFraming[%u]", param->framing); + return false; + } + + if (param->packing != BT_ISO_PACKING_SEQUENTIAL && + param->packing != BT_ISO_PACKING_INTERLEAVED) { + LOG_ERR("InvPacking[%u]", param->packing); + return false; + } + + if (is_c_to_p && + !IN_RANGE(param->c_to_p_interval, BT_ISO_SDU_INTERVAL_MIN, BT_ISO_SDU_INTERVAL_MAX)) { + LOG_ERR("InvC2PInterval[%u]", param->c_to_p_interval); + return false; + } + + if (is_p_to_c && + !IN_RANGE(param->p_to_c_interval, BT_ISO_SDU_INTERVAL_MIN, BT_ISO_SDU_INTERVAL_MAX)) { + LOG_ERR("InvP2CInterval[%u]", param->p_to_c_interval); + return false; + } + + if (!advanced) { + if (is_c_to_p && + !IN_RANGE(param->c_to_p_latency, BT_ISO_LATENCY_MIN, BT_ISO_LATENCY_MAX)) { + LOG_ERR("InvC2PLatency[%u]", param->c_to_p_latency); + return false; + } + + if (is_p_to_c && + !IN_RANGE(param->p_to_c_latency, BT_ISO_LATENCY_MIN, BT_ISO_LATENCY_MAX)) { + LOG_ERR("InvP2CLatency[%u]", param->p_to_c_latency); + return false; + } + } + +#if defined(CONFIG_BT_ISO_TEST_PARAMS) + if (advanced) { + if (!IN_RANGE(param->c_to_p_ft, BT_ISO_FT_MIN, BT_ISO_FT_MAX)) { + LOG_ERR("InvC2PFt[%u]", param->c_to_p_ft); + + return false; + } + + if (!IN_RANGE(param->p_to_c_ft, BT_ISO_FT_MIN, BT_ISO_FT_MAX)) { + LOG_ERR("InvP2CFt[%u]", param->p_to_c_ft); + + return false; + } + + if (!IN_RANGE(param->iso_interval, BT_ISO_ISO_INTERVAL_MIN, + BT_ISO_ISO_INTERVAL_MAX)) { + LOG_ERR("InvIsoInterval[%u]", param->iso_interval); + + return false; + } + } +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ + + return true; +} + +int bt_iso_cig_create(const struct bt_iso_cig_param *param, struct bt_iso_cig **out_cig) +{ + int err; + struct net_buf *rsp = NULL; + struct bt_iso_cig *cig; + struct bt_hci_rp_le_set_cig_params *cig_rsp; + struct bt_iso_chan *cis; + bool advanced = false; + int i; + + LOG_DBG("IsoCigCreate"); + + CHECKIF(param == NULL) { + LOG_ERR("ParamNull"); + return -EINVAL; + } + + CHECKIF(out_cig == NULL) { + LOG_ERR("OutCigNull"); + return -EINVAL; + } + + *out_cig = NULL; + + /* Check if controller is ISO capable as a central */ + if (!BT_FEAT_LE_CIS_CENTRAL(bt_dev.le.features)) { + LOG_ERR("CisCenNotSupp"); + return -ENOTSUP; + } + + /* TBD: Should we allow creating empty CIGs? */ + CHECKIF(param->cis_channels == NULL) { + LOG_ERR("CisChansNull"); + return -EINVAL; + } + + CHECKIF(param->num_cis == 0) { + LOG_ERR("InvNumCis[%u]", param->num_cis); + return -EINVAL; + } + +#if defined(CONFIG_BT_ISO_TEST_PARAMS) + advanced = is_advanced_cig_param(param); +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ + + CHECKIF(!valid_cig_param(param, advanced, NULL)) { + LOG_ERR("InvCigParams[%u]", advanced); + return -EINVAL; + } + + cig = get_free_cig(); + + if (!cig) { + return -ENOMEM; + } + + err = cig_init_cis(cig, param); + if (err) { + LOG_DBG("InitCisFail[%d]", err); + cleanup_cig(cig); + return err; + } + + if (!advanced) { + rsp = hci_le_set_cig_params(cig, param); +#if defined(CONFIG_BT_ISO_TEST_PARAMS) + } else { + rsp = hci_le_set_cig_test_params(cig, param); +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ + } + + if (rsp == NULL) { + LOG_WRN("SetCigParamsFail"); + err = -EIO; + cleanup_cig(cig); + return err; + } + + cig_rsp = (void *)rsp->data; + + if (rsp->len < sizeof(*cig_rsp) || cig_rsp->num_handles != param->num_cis) { + LOG_WRN("InvSetCigParamsRsp[%u][%zu][%u][%u]", + rsp->len, sizeof(*cig_rsp), cig_rsp->num_handles, param->num_cis); + err = -EIO; + net_buf_unref(rsp); + cleanup_cig(cig); + return err; + } + + i = 0; + SYS_SLIST_FOR_EACH_CONTAINER(&cig->cis_channels, cis, node) { + const uint16_t handle = cig_rsp->handle[i++]; + + /* Assign the connection handle */ + cis->iso->handle = sys_le16_to_cpu(handle); + } + + net_buf_unref(rsp); + + *out_cig = cig; + + LOG_DBG("OutCig[%u]", cig->id); + + return err; +} + +static void restore_cig(struct bt_iso_cig *cig, uint8_t existing_num_cis) +{ + struct bt_iso_chan *cis, *tmp; + sys_snode_t *prev = NULL; + + LOG_DBG("RestoreCig[%u][%u]", cig->id, existing_num_cis); + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&cig->cis_channels, cis, tmp, node) { + /* Remove all newly added by comparing the cis_id to the number + * of CIS that was previously added before + * bt_iso_cig_reconfigure was called + */ + if (cis->iso != NULL && cis->iso->iso.info.unicast.cis_id >= existing_num_cis) { + bt_conn_unref(cis->iso); + cis->iso = NULL; + + sys_slist_remove(&cig->cis_channels, prev, &cis->node); + cig->num_cis--; + /* prev stays unchanged: the removed node is gone, the next + * iteration will process tmp which follows prev directly */ + } else { + prev = &cis->node; + } + } +} + +int bt_iso_cig_reconfigure(struct bt_iso_cig *cig, const struct bt_iso_cig_param *param) +{ + struct bt_hci_rp_le_set_cig_params *cig_rsp; + uint8_t existing_num_cis; + bool advanced = false; + struct net_buf *rsp = NULL; + int err; + + LOG_DBG("IsoCigReconfigure"); + + CHECKIF(cig == NULL) { + LOG_ERR("CigNull"); + return -EINVAL; + } + + CHECKIF(param == NULL) { + LOG_ERR("ParamNull"); + return -EINVAL; + } + + if (cig->state != BT_ISO_CIG_STATE_CONFIGURED) { + LOG_ERR("InvCigState[%u]", cig->state); + return -EINVAL; + } + +#if defined(CONFIG_BT_ISO_TEST_PARAMS) + advanced = is_advanced_cig_param(param); +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ + + CHECKIF(!valid_cig_param(param, advanced, cig)) { + LOG_DBG("InvCigParams"); + return -EINVAL; + } + + /* Used to restore CIG in case of error */ + existing_num_cis = cig->num_cis; + + err = cig_init_cis(cig, param); + if (err != 0) { + LOG_DBG("InitCisFail[%d]", err); + restore_cig(cig, existing_num_cis); + return err; + } + + if (!advanced) { + rsp = hci_le_set_cig_params(cig, param); +#if defined(CONFIG_BT_ISO_TEST_PARAMS) + } else { + rsp = hci_le_set_cig_test_params(cig, param); +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ + } + + if (rsp == NULL) { + LOG_WRN("SetCigParamsFail"); + err = -EIO; + restore_cig(cig, existing_num_cis); + return err; + } + + cig_rsp = (void *)rsp->data; + + if (rsp->len < sizeof(*cig_rsp)) { + LOG_WRN("InvSetCigParamsRspLen[%u][%zu]", + rsp->len, sizeof(*cig_rsp)); + err = -EIO; + net_buf_unref(rsp); + restore_cig(cig, existing_num_cis); + return err; + } + + if (cig_rsp->num_handles != param->num_cis) { + LOG_WRN("InvSetCigParamsRspNumHdl[%u][%u]", + cig_rsp->num_handles, param->num_cis); + err = -EIO; + net_buf_unref(rsp); + restore_cig(cig, existing_num_cis); + return err; + } + + for (uint8_t i = 0u; i < param->num_cis; i++) { + const uint16_t handle = cig_rsp->handle[i]; + struct bt_iso_chan *cis = param->cis_channels[i]; + + /* Assign the connection handle */ + cis->iso->handle = sys_le16_to_cpu(handle); + } + + net_buf_unref(rsp); + + return err; +} + +int bt_iso_cig_terminate(struct bt_iso_cig *cig) +{ + int err; + + LOG_DBG("IsoCigTerminate"); + + CHECKIF(cig == NULL) { + LOG_ERR("CigNull"); + return -EINVAL; + } + + if (cig->state != BT_ISO_CIG_STATE_INACTIVE && cig->state != BT_ISO_CIG_STATE_CONFIGURED) { + LOG_ERR("InvCigState[%u]", cig->state); + return -EINVAL; + } + + err = hci_le_remove_cig(cig->id); + if (err != 0) { + LOG_ERR("TerminateCigFail[%d]", err); + return err; + } + + cleanup_cig(cig); + + return 0; +} + +static int hci_le_create_cis(const struct bt_iso_connect_param *param, size_t count) +{ + struct bt_hci_cis *cis; + struct bt_hci_cp_le_create_cis *req; + struct net_buf *buf; + + LOG_DBG("CreateCis[%u]", count); + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_CREATE_CIS, sizeof(*req) + sizeof(*cis) * count); + if (!buf) { + return -ENOBUFS; + } + + req = net_buf_add(buf, sizeof(*req)); + + memset(req, 0, sizeof(*req)); + + /* Program the cis parameters */ + for (size_t i = 0; i < count; i++) { + struct bt_iso_chan *iso_chan = param[i].iso_chan; + + if (iso_chan->state == BT_ISO_STATE_ENCRYPT_PENDING) { + continue; + } + + cis = net_buf_add(buf, sizeof(*cis)); + + memset(cis, 0, sizeof(*cis)); + + cis->cis_handle = sys_cpu_to_le16(param[i].iso_chan->iso->handle); + cis->acl_handle = sys_cpu_to_le16(param[i].acl->handle); + req->num_cis++; + } + + /* If all CIS are pending for security, do nothing, + * but return a recognizable return value + */ + if (req->num_cis == 0) { + net_buf_unref(buf); + + return -ECANCELED; + } + + return bt_hci_cmd_send_sync(BT_HCI_OP_LE_CREATE_CIS, buf, NULL); +} + +#if defined(CONFIG_BT_SMP) +static int iso_chan_connect_security(const struct bt_iso_connect_param *param, size_t count) +{ + /* conn_idx_handled is an array of booleans for which conn indexes + * already have been used to call bt_conn_set_security. + * Using indexes avoids looping the array when checking if it has been + * handled. + */ + bool conn_idx_handled[CONFIG_BT_MAX_CONN]; + + LOG_DBG("IsoChanConnectSec[%u]", count); + + memset(conn_idx_handled, false, sizeof(conn_idx_handled)); + for (size_t i = 0; i < count; i++) { + struct bt_iso_chan *iso_chan = param[i].iso_chan; + struct bt_conn *acl = param[i].acl; + uint8_t conn_idx = bt_conn_index(acl); + + LOG_DBG("SecLevel[%zu][%u][%u]", + i, acl->sec_level, iso_chan->required_sec_level); + + if (acl->sec_level < iso_chan->required_sec_level) { + if (!conn_idx_handled[conn_idx]) { + int err; + + err = bt_conn_set_security(acl, iso_chan->required_sec_level); + if (err != 0) { + LOG_ERR("SetSecFail[%zu][%d]", i, err); + + /* Restore states */ + for (size_t j = 0; j < i; j++) { + iso_chan = param[j].iso_chan; + + if (iso_chan->state == BT_ISO_STATE_ENCRYPT_PENDING) { + bt_iso_cleanup_acl(iso_chan->iso); + bt_iso_chan_set_state(iso_chan, + BT_ISO_STATE_DISCONNECTED); + } + } + + return err; + } + + conn_idx_handled[conn_idx] = true; + } + + iso_chan->iso->iso.acl = bt_conn_ref(acl); + bt_iso_chan_set_state(iso_chan, BT_ISO_STATE_ENCRYPT_PENDING); + } + } + + return 0; +} +#endif /* CONFIG_BT_SMP */ + +static bool iso_chans_connecting(void) +{ + LOG_DBG("IsoChansConnecting"); + + for (size_t i = 0U; i < ARRAY_SIZE(iso_conns); i++) { + const struct bt_conn *iso = &iso_conns[i]; + const struct bt_iso_chan *iso_chan; + + if (!(iso->iso.info.type == BT_ISO_CHAN_TYPE_CENTRAL || + iso->iso.info.type == BT_ISO_CHAN_TYPE_PERIPHERAL)) { + continue; + } + + iso_chan = iso_chan(iso); + if (iso_chan != NULL && + (iso_chan->state == BT_ISO_STATE_CONNECTING || + iso_chan->state == BT_ISO_STATE_ENCRYPT_PENDING)) { + return true; + } + } + + return false; +} + +int bt_iso_chan_connect(const struct bt_iso_connect_param *param, size_t count) +{ + int err; + + LOG_DBG("IsoChanConnect[%u]", count); + + CHECKIF(param == NULL) { + LOG_ERR("ParamNull"); + return -EINVAL; + } + + CHECKIF(count == 0) { + LOG_ERR("InvCount[%zu]", count); + return -EINVAL; + } + + CHECKIF(count > CONFIG_BT_ISO_MAX_CHAN) { + LOG_ERR("TooLargeCount[%zu][%u]", count, CONFIG_BT_ISO_MAX_CHAN); + return -EINVAL; + } + + /* Validate input */ + for (size_t i = 0; i < count; i++) { + CHECKIF(param[i].iso_chan == NULL) { + LOG_ERR("IsoNull[%zu]", i); + return -EINVAL; + } + + CHECKIF(param[i].acl == NULL) { + LOG_ERR("AclNull[%zu]", i); + return -EINVAL; + } + + CHECKIF((param[i].acl->type & BT_CONN_TYPE_LE) == 0) { + LOG_ERR("InvAclType[%zu][%u]", i, param[i].acl->type); + return -EINVAL; + } + + if (param[i].iso_chan->iso == NULL) { + LOG_ERR("IsoNotInit[%zu]", i); + return -EINVAL; + } + + if (param[i].iso_chan->state != BT_ISO_STATE_DISCONNECTED) { + LOG_ERR("IsoNotDisconnected[%zu][%u]", i, param[i].iso_chan->state); + return -EINVAL; + } + } + + if (iso_chans_connecting()) { + LOG_ERR("PendingIsoExist"); + return -EBUSY; + } + +#if defined(CONFIG_BT_SMP) + /* Check for and initiate security for all channels that have + * requested encryption if the ACL link is not already secured + */ + err = iso_chan_connect_security(param, count); + if (err != 0) { + LOG_ERR("InitSecForCisFail[%d]", err); + return err; + } +#endif /* CONFIG_BT_SMP */ + + err = hci_le_create_cis(param, count); + if (err == -ECANCELED) { + LOG_DBG("CisPendingOnSec"); + + return 0; + } else if (err != 0) { + LOG_ERR("ConnectCisFail[%d]", err); + + return err; + } + + /* Set connection states */ + for (size_t i = 0; i < count; i++) { + struct bt_iso_chan *iso_chan = param[i].iso_chan; + struct bt_iso_cig *cig; + + if (iso_chan->state == BT_ISO_STATE_ENCRYPT_PENDING) { + continue; + } + + iso_chan->iso->iso.acl = bt_conn_ref(param[i].acl); + bt_conn_set_state(iso_chan->iso, BT_CONN_INITIATING); + bt_iso_chan_set_state(iso_chan, BT_ISO_STATE_CONNECTING); + + cig = get_cig(iso_chan); + assert(cig && "CigNull"); + cig->state = BT_ISO_CIG_STATE_ACTIVE; + } + + return 0; +} +#endif /* CONFIG_BT_ISO_CENTRAL */ +#endif /* CONFIG_BT_ISO_UNICAST */ + +#if defined(CONFIG_BT_ISO_BROADCAST) +static sys_slist_t iso_big_cbs = SYS_SLIST_STATIC_INIT(&iso_big_cbs); + +static struct bt_iso_big *lookup_big_by_handle(uint8_t big_handle) +{ + LOG_DBG("LookupBigByHdl[%u]", big_handle); + return &bigs[big_handle]; +} + +static struct bt_iso_big *get_free_big(void) +{ + /* We can use the index in the `bigs` array as BIG handles, for both + * broadcaster and receiver (even if the device is both!) + */ + + LOG_DBG("GetFreeBig"); + + for (size_t i = 0; i < ARRAY_SIZE(bigs); i++) { + if (!atomic_test_and_set_bit(bigs[i].flags, BT_BIG_INITIALIZED)) { + bigs[i].handle = i; + sys_slist_init(&bigs[i].bis_channels); + LOG_DBG("BigNew[%u]", i); + return &bigs[i]; + } + } + + LOG_ERR("NoFreeBig"); + + return NULL; +} + +static struct bt_iso_big *big_lookup_flag(int bit) +{ + LOG_DBG("BigLookupFlag[%d]", bit); + + for (size_t i = 0; i < ARRAY_SIZE(bigs); i++) { + if (atomic_test_bit(bigs[i].flags, bit)) { + return &bigs[i]; + } + } + + LOG_WRN("NoBigFound[%d]", bit); + + return NULL; +} + +static void cleanup_big(struct bt_iso_big *big) +{ + struct bt_iso_chan *bis, *tmp; + + LOG_DBG("CleanupBig"); + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&big->bis_channels, bis, tmp, node) { + if (bis->iso != NULL) { + bt_conn_unref(bis->iso); + bis->iso = NULL; + } + + sys_slist_remove(&big->bis_channels, NULL, &bis->node); + } + + memset(big, 0, sizeof(*big)); +} + +static void big_disconnect(struct bt_iso_big *big, uint8_t reason) +{ + struct bt_iso_chan *bis; + + LOG_DBG("BigDisconnect[%02x]", reason); + + atomic_set_bit(big->flags, BT_BIG_BUSY); + + SYS_SLIST_FOR_EACH_CONTAINER(&big->bis_channels, bis, node) { + bis->iso->err = reason; + + bt_iso_chan_disconnected(bis, reason); + } + + /* Cleanup the BIG before calling the `stopped` so that the `big` pointer and the ISO + * channels in the `big` can be reused in the callback + */ + cleanup_big(big); + + if (!sys_slist_is_empty(&iso_big_cbs)) { + struct bt_iso_big_cb *listener; + + SYS_SLIST_FOR_EACH_CONTAINER(&iso_big_cbs, listener, _node) { + if (listener->stopped != NULL) { + listener->stopped(big, reason); + } + } + } +} + +static int big_init_bis(struct bt_iso_big *big, struct bt_iso_chan *bis, uint8_t bis_number, + bool broadcaster) +{ + LOG_DBG("BigInitBis[%u][%u][%u]", big->handle, bis_number, broadcaster); + + struct bt_conn_iso *iso_conn; + + bis->iso = iso_new(); + if (bis->iso == NULL) { + LOG_ERR("NoFreeBis"); + return -ENOMEM; + } + + iso_conn = &bis->iso->iso; + +#if defined(CONFIG_BT_ISO_BROADCASTER) + if (broadcaster) { + iso_conn->info.type = BT_ISO_CHAN_TYPE_BROADCASTER; + iso_conn->info.broadcaster.big_handle = big->handle; + iso_conn->info.broadcaster.bis_number = bis_number; + } +#endif /* CONFIG_BT_ISO_BROADCASTER */ +#if defined(CONFIG_BT_ISO_SYNC_RECEIVER) + if (!broadcaster) { + iso_conn->info.type = BT_ISO_CHAN_TYPE_SYNC_RECEIVER; + iso_conn->info.sync_receiver.big_handle = big->handle; + iso_conn->info.sync_receiver.bis_number = bis_number; + } +#endif /* CONFIG_BT_ISO_SYNC_RECEIVER */ + + bt_iso_chan_add(bis->iso, bis); + + sys_slist_append(&big->bis_channels, &bis->node); + + return 0; +} + +int bt_iso_big_register_cb(struct bt_iso_big_cb *cb) +{ + CHECKIF(cb == NULL) { + LOG_DBG("BigCbNull"); + + return -EINVAL; + } + + if (sys_slist_find(&iso_big_cbs, &cb->_node, NULL)) { + LOG_DBG("BigCbAlreadyReg[%p]", cb); + + return -EEXIST; + } + + sys_slist_append(&iso_big_cbs, &cb->_node); + + return 0; +} + +#if defined(CONFIG_BT_ISO_BROADCASTER) +static int hci_le_create_big(struct bt_le_ext_adv *padv, struct bt_iso_big *big, + struct bt_iso_big_create_param *param) +{ + const struct bt_iso_chan_io_qos *qos; + struct bt_hci_cp_le_create_big *req; + struct net_buf *buf; + int err; + struct bt_iso_chan *bis; + + LOG_DBG("CreateBig"); + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_CREATE_BIG, sizeof(*req)); + + if (!buf) { + return -ENOBUFS; + } + + bis = SYS_SLIST_PEEK_HEAD_CONTAINER(&big->bis_channels, bis, node); + assert(bis != NULL && "BisNull"); + + /* All BIS will share the same QOS */ + qos = bis->qos->tx; + + req = net_buf_add(buf, sizeof(*req)); + req->big_handle = big->handle; + req->adv_handle = padv->handle; + req->num_bis = big->num_bis; + sys_put_le24(param->interval, req->sdu_interval); + req->max_sdu = sys_cpu_to_le16(qos->sdu); + req->max_latency = sys_cpu_to_le16(param->latency); + req->rtn = qos->rtn; + req->phy = qos->phy; + req->packing = param->packing; + req->framing = param->framing; + req->encryption = param->encryption; + if (req->encryption) { + memcpy(req->bcode, param->bcode, sizeof(req->bcode)); + } else { + memset(req->bcode, 0, sizeof(req->bcode)); + } + + LOG_DBG("[%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u]", + req->big_handle, req->adv_handle, req->num_bis, param->interval, + req->max_sdu, req->max_latency, req->rtn, req->phy, req->packing, + req->framing, req->encryption); + if (req->encryption) { + LOG_DBG("[%s]", bt_hex(req->bcode, sizeof(req->bcode))); + } + + err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_CREATE_BIG, buf, NULL); + + if (err) { + return err; + } + + SYS_SLIST_FOR_EACH_CONTAINER(&big->bis_channels, bis, node) { + bt_iso_chan_set_state(bis, BT_ISO_STATE_CONNECTING); + } + + return err; +} + +#if defined(CONFIG_BT_ISO_TEST_PARAMS) +static int hci_le_create_big_test(const struct bt_le_ext_adv *padv, struct bt_iso_big *big, + const struct bt_iso_big_create_param *param) +{ + struct bt_hci_cp_le_create_big_test *req; + const struct bt_iso_chan_qos *qos; + struct bt_iso_chan *bis; + struct net_buf *buf; + int err; + + LOG_DBG("CreateBigTest"); + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_CREATE_BIG_TEST, sizeof(*req)); + + if (!buf) { + return -ENOBUFS; + } + + bis = SYS_SLIST_PEEK_HEAD_CONTAINER(&big->bis_channels, bis, node); + assert(bis != NULL && "BisNull"); + + /* All BIS will share the same QOS */ + qos = bis->qos; + + req = net_buf_add(buf, sizeof(*req)); + req->big_handle = big->handle; + req->adv_handle = padv->handle; + req->num_bis = big->num_bis; + sys_put_le24(param->interval, req->sdu_interval); + req->iso_interval = sys_cpu_to_le16(param->iso_interval); + req->nse = qos->num_subevents; + req->max_sdu = sys_cpu_to_le16(qos->tx->sdu); + req->max_pdu = sys_cpu_to_le16(qos->tx->max_pdu); + req->phy = qos->tx->phy; + req->packing = param->packing; + req->framing = param->framing; + req->bn = qos->tx->burst_number; + req->irc = param->irc; + req->pto = param->pto; + req->encryption = param->encryption; + if (req->encryption) { + memcpy(req->bcode, param->bcode, sizeof(req->bcode)); + } else { + memset(req->bcode, 0, sizeof(req->bcode)); + } + + LOG_DBG("[%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u]", + req->big_handle, req->adv_handle, req->num_bis, param->interval, + param->iso_interval, req->nse, req->max_sdu, req->max_pdu, + req->phy, req->packing, req->framing, req->bn, req->irc, + req->pto, req->encryption); + if (req->encryption) { + LOG_DBG("[%s]", bt_hex(req->bcode, sizeof(req->bcode))); + } + + err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_CREATE_BIG_TEST, buf, NULL); + if (err) { + return err; + } + + SYS_SLIST_FOR_EACH_CONTAINER(&big->bis_channels, bis, node) { + bt_iso_chan_set_state(bis, BT_ISO_STATE_CONNECTING); + } + + return err; +} + +static bool is_advanced_big_param(const struct bt_iso_big_create_param *param) +{ + LOG_DBG("IsAdvancedBigParam[%u][%u]", param->irc, param->iso_interval); + + if (param->irc != 0U || param->iso_interval != 0U) { + return true; + } + + /* Check if any of the CIS contain any test-param-only values */ + for (uint8_t i = 0U; i < param->num_bis; i++) { + const struct bt_iso_chan *bis = param->bis_channels[i]; + const struct bt_iso_chan_qos *qos = bis->qos; + + if (qos->num_subevents > 0U) { + return true; + } + + assert(qos->tx != NULL && "BigWithNullTx"); + + if (qos->tx->max_pdu > 0U || qos->tx->burst_number > 0U) { + return true; + } + } + + return false; +} +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ + +static bool valid_big_param(const struct bt_iso_big_create_param *param, bool advanced) +{ + CHECKIF(!param->bis_channels) { + LOG_ERR("BisChansNull"); + + return false; + } + + CHECKIF(!param->num_bis) { + LOG_ERR("InvNumBis[%u]", param->num_bis); + + return false; + } + + for (uint8_t i = 0; i < param->num_bis; i++) { + struct bt_iso_chan *bis = param->bis_channels[i]; + + CHECKIF(bis == NULL) { + LOG_ERR("BisChanNull[%u]", i); + + return false; + } + + if (bis->iso) { + LOG_WRN("BisChanExist[%u]", i); + + return false; + } + + CHECKIF(bis->qos == NULL) { + LOG_ERR("BisChanQosNull[%u]", i); + + return false; + } + + CHECKIF(bis->qos->tx == NULL || + !valid_chan_io_qos(bis->qos->tx, true, true, advanced)) { + LOG_ERR("InvBisChanQos[%u]", i); + + return false; + } + } + + CHECKIF(param->framing != BT_ISO_FRAMING_UNFRAMED && + param->framing != BT_ISO_FRAMING_FRAMED) { + LOG_ERR("InvFraming[%u]", param->framing); + + return false; + } + + CHECKIF(param->packing != BT_ISO_PACKING_SEQUENTIAL && + param->packing != BT_ISO_PACKING_INTERLEAVED) { + LOG_ERR("InvPacking[%u]", param->packing); + + return false; + } + + CHECKIF(param->num_bis > BT_ISO_MAX_GROUP_ISO_COUNT || + param->num_bis > CONFIG_BT_ISO_MAX_CHAN) { + LOG_ERR("TooLargeNumBis[%u][%u]", + param->num_bis, MAX(CONFIG_BT_ISO_MAX_CHAN, BT_ISO_MAX_GROUP_ISO_COUNT)); + + return false; + } + + CHECKIF(!IN_RANGE(param->interval, BT_ISO_SDU_INTERVAL_MIN, BT_ISO_SDU_INTERVAL_MAX)) { + LOG_ERR("InvInterval[%u]", param->interval); + + return false; + } + + CHECKIF(!advanced && !IN_RANGE(param->latency, BT_ISO_LATENCY_MIN, BT_ISO_LATENCY_MAX)) { + LOG_ERR("InvLatency[%u]", param->latency); + + return false; + } + +#if defined(CONFIG_BT_ISO_TEST_PARAMS) + if (advanced) { + CHECKIF(!IN_RANGE(param->irc, BT_ISO_IRC_MIN, BT_ISO_IRC_MAX)) { + LOG_ERR("InvIrc[%u]", param->irc); + + return false; + } + + CHECKIF(!IN_RANGE(param->pto, BT_ISO_PTO_MIN, BT_ISO_PTO_MAX)) { + LOG_ERR("InvPto[%u]", param->pto); + + return false; + } + + CHECKIF(!IN_RANGE(param->iso_interval, BT_ISO_ISO_INTERVAL_MIN, + BT_ISO_ISO_INTERVAL_MAX)) { + LOG_ERR("InvIsoInterval[%u]", param->iso_interval); + + return false; + } + } +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ + + return true; +} + +int bt_iso_big_create(struct bt_le_ext_adv *padv, struct bt_iso_big_create_param *param, + struct bt_iso_big **out_big) +{ + struct bt_iso_chan **bis_channels; + int err; + struct bt_iso_big *big; + bool advanced = false; + + LOG_DBG("IsoBigCreate"); + + CHECKIF(padv == NULL) { + LOG_ERR("PaNull"); + return -EINVAL; + } + + CHECKIF(param == NULL) { + LOG_ERR("ParamNull"); + return -EINVAL; + } + + CHECKIF(out_big == NULL) { + LOG_ERR("OutBigNull"); + return -EINVAL; + } + + if (!atomic_test_bit(padv->flags, BT_PER_ADV_PARAMS_SET)) { + LOG_ERR("PaParamsNotSet"); + return -EINVAL; + } + +#if defined(CONFIG_BT_ISO_TEST_PARAMS) + advanced = is_advanced_big_param(param); +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ + + if (!valid_big_param(param, advanced)) { + LOG_ERR("InvBigParams[%u]", advanced); + return -EINVAL; + } + + big = get_free_big(); + + if (!big) { + return -ENOMEM; + } + + bis_channels = param->bis_channels; + for (uint8_t i = 0; i < param->num_bis; i++) { + /* BIS numbers start from 1, so the first BIS will get BIS Number = 1 */ + const uint8_t bis_number = i + 1U; + + err = big_init_bis(big, bis_channels[i], bis_number, true); + if (err != 0) { + LOG_DBG("InitBisFail[%u][%d]", i, err); + cleanup_big(big); + + return err; + } + } + + big->num_bis = param->num_bis; + + if (!advanced) { + err = hci_le_create_big(padv, big, param); +#if defined(CONFIG_BT_ISO_TEST_PARAMS) + } else { + err = hci_le_create_big_test(padv, big, param); +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ + } + + if (err) { + LOG_ERR("CreateBigFail[%d]", err); + cleanup_big(big); + return err; + } + + *out_big = big; + + LOG_DBG("OutBig[%u]", big->handle); + + return err; +} + +static void store_bis_broadcaster_info(const struct bt_hci_evt_le_big_complete *evt, + struct bt_conn *iso) +{ + struct bt_conn_iso *iso_conn = &iso->iso; + struct bt_iso_info *info = &iso_conn->info; + struct bt_iso_broadcaster_info *broadcaster_info = &info->broadcaster; + + info->iso_interval = sys_le16_to_cpu(evt->iso_interval); + info->max_subevent = evt->nse; + + broadcaster_info->sync_delay = sys_get_le24(evt->sync_delay); + broadcaster_info->latency = sys_get_le24(evt->latency); + broadcaster_info->phy = bt_get_phy(evt->phy); + broadcaster_info->bn = evt->bn; + broadcaster_info->irc = evt->irc; + /* Transform to n * 1.25ms */ + broadcaster_info->pto = info->iso_interval * evt->pto; + broadcaster_info->max_pdu = sys_le16_to_cpu(evt->max_pdu); + broadcaster_info->big_handle = iso_conn->info.broadcaster.big_handle; + broadcaster_info->bis_number = iso_conn->info.broadcaster.bis_number; + + info->can_send = true; + info->can_recv = false; + + LOG_DBG("StoreBisInfo[%u]", broadcaster_info->pto); +} + +void hci_le_big_complete(struct net_buf *buf) +{ + struct bt_hci_evt_le_big_complete *evt = (void *)buf->data; + struct bt_iso_chan *bis; + struct bt_iso_big *big; + int i; + + LOG_DBG("BigComp"); + LOG_DBG("Evt[%02x][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u][%u]", + evt->status, evt->big_handle, sys_get_le24(evt->sync_delay), + sys_get_le24(evt->latency), evt->phy, evt->nse, evt->bn, + evt->pto, evt->irc, evt->max_pdu, evt->iso_interval, + evt->num_bis); + + if (evt->big_handle >= ARRAY_SIZE(bigs)) { + LOG_ERR("InvBigHdl[%u][%u]", evt->big_handle, ARRAY_SIZE(bigs)); + + big = big_lookup_flag(BT_BIG_PENDING); + if (big) { + big_disconnect(big, evt->status ? evt->status : BT_HCI_ERR_UNSPECIFIED); + } + + return; + } + + big = lookup_big_by_handle(evt->big_handle); + atomic_clear_bit(big->flags, BT_BIG_PENDING); + + LOG_DBG("BigComp[%u][%p][%02x][%s]", big->handle, big, evt->status, + bt_hci_err_to_str(evt->status)); + + if (evt->status || evt->num_bis != big->num_bis) { + if (evt->status == BT_HCI_ERR_SUCCESS && evt->num_bis != big->num_bis) { + LOG_ERR("InvNumOfBisCreated[%u][%u]", evt->num_bis, big->num_bis); + } + big_disconnect(big, evt->status ? evt->status : BT_HCI_ERR_UNSPECIFIED); + return; + } + + atomic_set_bit(big->flags, BT_BIG_BUSY); + i = 0; + SYS_SLIST_FOR_EACH_CONTAINER(&big->bis_channels, bis, node) { + const uint16_t handle = evt->handle[i++]; + struct bt_conn *iso_conn = bis->iso; + + LOG_DBG("BisHdl[%04x]", handle); + + iso_conn->handle = sys_le16_to_cpu(handle); + store_bis_broadcaster_info(evt, iso_conn); + bt_conn_set_state(iso_conn, BT_CONN_CONNECTED); + } + + atomic_clear_bit(big->flags, BT_BIG_BUSY); + + if (!sys_slist_is_empty(&iso_big_cbs)) { + struct bt_iso_big_cb *listener; + + SYS_SLIST_FOR_EACH_CONTAINER(&iso_big_cbs, listener, _node) { + if (listener->started != NULL) { + listener->started(big); + } + } + } +} + +void hci_le_big_terminate(struct net_buf *buf) +{ + struct bt_hci_evt_le_big_terminate *evt = (void *)buf->data; + struct bt_iso_big *big; + + LOG_DBG("BigTerminateEvt[%u][%02x]", evt->big_handle, evt->reason); + + if (evt->big_handle >= ARRAY_SIZE(bigs)) { + LOG_ERR("InvBigHdl[%u][%u]", evt->big_handle, ARRAY_SIZE(bigs)); + return; + } + + big = lookup_big_by_handle(evt->big_handle); + + if (!atomic_test_bit(big->flags, BT_BIG_INITIALIZED)) { + LOG_ERR("BigNotInit[%u]", evt->big_handle); + return; + } + + LOG_DBG("BigTerminated[%u][%p]", big->handle, big); + + big_disconnect(big, evt->reason); +} +#endif /* CONFIG_BT_ISO_BROADCASTER */ + +static int hci_le_terminate_big(struct bt_iso_big *big) +{ + struct bt_hci_cp_le_terminate_big *req; + struct net_buf *buf; + + LOG_DBG("TerminateBig[%u]", big->handle); + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_TERMINATE_BIG, sizeof(*req)); + if (!buf) { + return -ENOBUFS; + } + + req = net_buf_add(buf, sizeof(*req)); + req->big_handle = big->handle; + req->reason = BT_HCI_ERR_REMOTE_USER_TERM_CONN; + + return bt_hci_cmd_send_sync(BT_HCI_OP_LE_TERMINATE_BIG, buf, NULL); +} + +static int hci_le_big_sync_term(struct bt_iso_big *big) +{ + struct bt_hci_cp_le_big_terminate_sync *req; + struct bt_hci_rp_le_big_terminate_sync *evt; + struct net_buf *buf; + struct net_buf *rsp; + int err; + + LOG_DBG("BigSyncTerm[%u]", big->handle); + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_BIG_TERMINATE_SYNC, sizeof(*req)); + if (!buf) { + return -ENOBUFS; + } + + req = net_buf_add(buf, sizeof(*req)); + req->big_handle = big->handle; + err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_BIG_TERMINATE_SYNC, buf, &rsp); + if (err) { + return err; + } + + evt = (struct bt_hci_rp_le_big_terminate_sync *)rsp->data; + if (evt->status || (evt->big_handle != big->handle)) { + LOG_ERR("BigSyncTermFail[%02x][%u][%u]", + evt->status, evt->big_handle, big->handle); + err = -EIO; + } + + net_buf_unref(rsp); + + return err; +} + +int bt_iso_big_terminate(struct bt_iso_big *big) +{ + struct bt_iso_chan *bis; + int err; + + LOG_DBG("IsoBigTerminate"); + + CHECKIF(big == NULL) { + LOG_ERR("BigNull"); + return -EINVAL; + } + + if (!atomic_test_bit(big->flags, BT_BIG_INITIALIZED) || !big->num_bis) { + LOG_ERR("BigNotInit[%u]", big->num_bis); + return -EINVAL; + } + + if (atomic_test_bit(big->flags, BT_BIG_BUSY)) { + LOG_DBG("BigBusy[%u]", big->handle); + return -EBUSY; + } + + bis = SYS_SLIST_PEEK_HEAD_CONTAINER(&big->bis_channels, bis, node); + assert(bis != NULL && "BisNull"); + + if (IS_ENABLED(CONFIG_BT_ISO_BROADCASTER) && + bis->iso->iso.info.type == BT_ISO_CHAN_TYPE_BROADCASTER) { + err = hci_le_terminate_big(big); + + /* Wait for BT_HCI_EVT_LE_BIG_TERMINATE before cleaning up + * the BIG in hci_le_big_terminate + */ + if (!err) { + SYS_SLIST_FOR_EACH_CONTAINER(&big->bis_channels, bis, node) { + bt_iso_chan_set_state(bis, BT_ISO_STATE_DISCONNECTING); + } + } + } else if (IS_ENABLED(CONFIG_BT_ISO_SYNC_RECEIVER) && + bis->iso->iso.info.type == BT_ISO_CHAN_TYPE_SYNC_RECEIVER) { + err = hci_le_big_sync_term(big); + + if (!err) { + big_disconnect(big, BT_HCI_ERR_LOCALHOST_TERM_CONN); + } + } else { + err = -EINVAL; + } + + if (err) { + LOG_ERR("TerminateBigFail[%d]", err); + } + + return err; +} + +#if defined(CONFIG_BT_ISO_SYNC_RECEIVER) +static void store_bis_sync_receiver_info(const struct bt_hci_evt_le_big_sync_established *evt, + struct bt_conn *iso) +{ + struct bt_conn_iso *iso_conn = &iso->iso; + struct bt_iso_info *info = &iso_conn->info; + struct bt_iso_sync_receiver_info *receiver_info = &info->sync_receiver; + + info->max_subevent = evt->nse; + info->iso_interval = sys_le16_to_cpu(evt->iso_interval); + + receiver_info->latency = sys_get_le24(evt->latency); + receiver_info->bn = evt->bn; + receiver_info->irc = evt->irc; + /* Transform to n * 1.25ms */ + receiver_info->pto = info->iso_interval * evt->pto; + receiver_info->max_pdu = sys_le16_to_cpu(evt->max_pdu); + receiver_info->big_handle = iso_conn->info.sync_receiver.big_handle; + receiver_info->bis_number = iso_conn->info.sync_receiver.bis_number; + + info->can_send = false; + info->can_recv = true; + + LOG_DBG("StoreBisInfo[%u]", receiver_info->pto); +} + +void hci_le_big_sync_established(struct net_buf *buf) +{ + struct bt_hci_evt_le_big_sync_established *evt = (void *)buf->data; + struct bt_iso_chan *bis; + struct bt_iso_big *big; + int i; + + LOG_DBG("BigSyncEstab"); + LOG_DBG("Evt[%02x][%u][%u][%u][%u][%u][%u][%u][%u][%u]", + evt->status, evt->big_handle, sys_get_le24(evt->latency), + evt->nse, evt->bn, evt->pto, evt->irc, evt->max_pdu, + evt->iso_interval, evt->num_bis); + + if (evt->big_handle >= ARRAY_SIZE(bigs)) { + LOG_ERR("InvBigHdl[%u][%u]", evt->big_handle, ARRAY_SIZE(bigs)); + + big = big_lookup_flag(BT_BIG_SYNCING); + if (big) { + big_disconnect(big, evt->status ? evt->status : BT_HCI_ERR_UNSPECIFIED); + } + + return; + } + + big = lookup_big_by_handle(evt->big_handle); + atomic_clear_bit(big->flags, BT_BIG_SYNCING); + + LOG_DBG("BigSyncEstab[%u][%p][%02x][%s]", big->handle, big, evt->status, + bt_hci_err_to_str(evt->status)); + + if (evt->status || evt->num_bis != big->num_bis) { + if (evt->status == BT_HCI_ERR_SUCCESS && evt->num_bis != big->num_bis) { + LOG_ERR("InvNumOfBisSynced[%u][%u]", evt->num_bis, big->num_bis); + } + big_disconnect(big, evt->status ? evt->status : BT_HCI_ERR_UNSPECIFIED); + return; + } + + atomic_set_bit(big->flags, BT_BIG_BUSY); + i = 0; + SYS_SLIST_FOR_EACH_CONTAINER(&big->bis_channels, bis, node) { + const uint16_t handle = evt->handle[i++]; + struct bt_conn *iso_conn = bis->iso; + + LOG_DBG("BisHdl[%04x]", handle); + + iso_conn->handle = sys_le16_to_cpu(handle); + store_bis_sync_receiver_info(evt, iso_conn); + bt_conn_set_state(iso_conn, BT_CONN_CONNECTED); + } + + atomic_clear_bit(big->flags, BT_BIG_BUSY); + + if (!sys_slist_is_empty(&iso_big_cbs)) { + struct bt_iso_big_cb *listener; + + SYS_SLIST_FOR_EACH_CONTAINER(&iso_big_cbs, listener, _node) { + if (listener->started != NULL) { + listener->started(big); + } + } + } +} + +void hci_le_big_sync_lost(struct net_buf *buf) +{ + struct bt_hci_evt_le_big_sync_lost *evt = (void *)buf->data; + struct bt_iso_big *big; + + LOG_DBG("BigSyncLostEvt[%u][%02x]", evt->big_handle, evt->reason); + + if (evt->big_handle >= ARRAY_SIZE(bigs)) { + LOG_ERR("InvBigHdl[%u][%u]", evt->big_handle, ARRAY_SIZE(bigs)); + return; + } + + big = lookup_big_by_handle(evt->big_handle); + + LOG_DBG("BigSyncLost[%u][%p]", big->handle, big); + + big_disconnect(big, evt->reason); +} + +static int hci_le_big_create_sync(const struct bt_le_per_adv_sync *sync, struct bt_iso_big *big, + const struct bt_iso_big_sync_param *param) +{ + struct bt_hci_cp_le_big_create_sync *req; + struct net_buf *buf; + int err; + uint8_t bit_idx = 0; + + LOG_DBG("BigCreateSync[%u][%u]", big->handle, big->num_bis); + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_BIG_CREATE_SYNC, sizeof(*req) + big->num_bis); + if (!buf) { + return -ENOBUFS; + } + + req = net_buf_add(buf, sizeof(*req) + big->num_bis); + req->big_handle = big->handle; + req->sync_handle = sys_cpu_to_le16(sync->handle); + req->encryption = param->encryption; + if (req->encryption) { + memcpy(req->bcode, param->bcode, sizeof(req->bcode)); + } else { + memset(req->bcode, 0, sizeof(req->bcode)); + } + req->mse = param->mse; + req->sync_timeout = sys_cpu_to_le16(param->sync_timeout); + req->num_bis = big->num_bis; + /* Transform from bitfield to array */ + for (int i = 1; i <= BT_ISO_MAX_GROUP_ISO_COUNT; i++) { + if (param->bis_bitfield & BT_ISO_BIS_INDEX_BIT(i)) { + if (bit_idx == big->num_bis) { + LOG_ERR("BigCannotContainBis[%u]", bit_idx + 1); + net_buf_unref(buf); + return -EINVAL; + } + req->bis[bit_idx++] = i; + } + } + + if (bit_idx != big->num_bis) { + LOG_ERR("BitfieldNotMatchNumBis[%u][%u]", bit_idx, big->num_bis); + net_buf_unref(buf); + return -EINVAL; + } + + err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_BIG_CREATE_SYNC, buf, NULL); + + return err; +} + +int bt_iso_big_sync(struct bt_le_per_adv_sync *sync, struct bt_iso_big_sync_param *param, + struct bt_iso_big **out_big) +{ + struct bt_iso_chan **bis_channels; + int err; + struct bt_iso_chan *bis; + struct bt_iso_big *big; + uint32_t bitfield_copy; + + LOG_DBG("IsoBigSync"); + + CHECKIF(sync == NULL) { + LOG_ERR("SyncNull"); + return -EINVAL; + } + + CHECKIF(param == NULL) { + LOG_ERR("ParamNull"); + return -EINVAL; + } + + CHECKIF(out_big == NULL) { + LOG_ERR("OutBigNull"); + return -EINVAL; + } + + if (!atomic_test_bit(sync->flags, BT_PER_ADV_SYNC_SYNCED)) { + LOG_ERR("PaNotSynced"); + return -EINVAL; + } + + CHECKIF(param->mse > BT_ISO_SYNC_MSE_MAX) { + LOG_ERR("InvMse[%02x]", param->mse); + return -EINVAL; + } + + CHECKIF(param->sync_timeout < BT_ISO_SYNC_TIMEOUT_MIN || + param->sync_timeout > BT_ISO_SYNC_TIMEOUT_MAX) { + LOG_ERR("InvSyncTimeout[%04x]", param->sync_timeout); + return -EINVAL; + } + + CHECKIF(!BT_ISO_VALID_BIS_BITFIELD(param->bis_bitfield)) { + LOG_ERR("InvBisBitfield[%08x]", param->bis_bitfield); + return -EINVAL; + } + + CHECKIF(!param->bis_channels) { + LOG_ERR("BisChansNull"); + return -EINVAL; + } + + CHECKIF(!param->num_bis) { + LOG_ERR("InvNumBis[%u]", param->num_bis); + return -EINVAL; + } + + for (uint8_t i = 0; i < param->num_bis; i++) { + struct bt_iso_chan *param_bis = param->bis_channels[i]; + + CHECKIF(param_bis == NULL) { + LOG_ERR("BisChanNull[%u]", i); + return -EINVAL; + } + + if (param_bis->iso) { + LOG_WRN("BisChanExist[%u]", i); + return -EALREADY; + } + + CHECKIF(param_bis->qos == NULL) { + LOG_ERR("BisChanQosNull[%u]", i); + return -EINVAL; + } + + CHECKIF(param_bis->qos->rx == NULL) { + LOG_ERR("BisChanQosRxNull[%u]", i); + return -EINVAL; + } + } + + big = get_free_big(); + + if (!big) { + return -ENOMEM; + } + + bitfield_copy = param->bis_bitfield; + bis_channels = param->bis_channels; + for (uint8_t i = 0; i < param->num_bis; i++) { + const uint8_t bis_number = find_lsb_set(bitfield_copy); + + if (bis_number == 0) { + LOG_ERR("BitfieldExhausted[%u][%u]", i, param->num_bis); + cleanup_big(big); + return -EINVAL; + } + + /* pop the least significant bit from the bitfield */ + bitfield_copy &= ~BIT(bis_number - 1U); + + /* The least significant bit will be the bis_number, so that if the bitfield is + * 0b0101 then the first pop will be 1 and the bitfield_copy will be 0b0100 and + * then the second pop will be 3 and the bitfield_copy will be 0b0000 + * Since find_lsb_set returns the index starting from 1 we can use the result + * directly as the bis_numbers also start from 1. + */ + err = big_init_bis(big, bis_channels[i], bis_number, false); + if (err != 0) { + LOG_DBG("InitBisFail[%u]: %d", i, err); + cleanup_big(big); + + return err; + } + } + + big->num_bis = param->num_bis; + + err = hci_le_big_create_sync(sync, big, param); + if (err) { + LOG_DBG("CreateBigSyncFail[%d]", err); + cleanup_big(big); + return err; + } + + SYS_SLIST_FOR_EACH_CONTAINER(&big->bis_channels, bis, node) { + bt_iso_chan_set_state(bis, BT_ISO_STATE_CONNECTING); + } + + *out_big = big; + + LOG_DBG("OutBig[%u]", big->handle); + + return 0; +} +#endif /* CONFIG_BT_ISO_SYNC_RECEIVER */ +#endif /* CONFIG_BT_ISO_BROADCAST */ + +void bt_iso_reset(void) +{ + LOG_DBG("IsoReset"); + +#if defined(CONFIG_BT_ISO_CENTRAL) + for (size_t i = 0U; i < ARRAY_SIZE(cigs); i++) { + struct bt_iso_cig *cig = &cigs[i]; + struct bt_iso_chan *cis; + + /* Disconnect any connected CIS and call the callback + * We cannot use bt_iso_chan_disconnected directly here, as that + * attempts to also remove the ISO data path, which we shouldn't attempt to + * during the reset, as that sends HCI commands. + */ + SYS_SLIST_FOR_EACH_CONTAINER(&cig->cis_channels, cis, node) { + if (cis->state != BT_ISO_STATE_DISCONNECTED) { + bt_iso_chan_set_state(cis, BT_ISO_STATE_DISCONNECTED); + bt_iso_cleanup_acl(cis->iso); + if (cis->ops != NULL && cis->ops->disconnected != NULL) { + cis->ops->disconnected(cis, BT_HCI_ERR_UNSPECIFIED); + } + } + } + + cleanup_cig(cig); + } +#endif /* CONFIG_BT_ISO_CENTRAL */ + +#if defined(CONFIG_BT_ISO_BROADCAST) + for (size_t i = 0U; i < ARRAY_SIZE(bigs); i++) { + struct bt_iso_big *big = &bigs[i]; + + big_disconnect(big, BT_HCI_ERR_UNSPECIFIED); + } +#endif /* CONFIG_BT_ISO_BROADCAST */ +} + +/************************ Thread-safe wrapper functions ************************/ + +int bt_iso_setup_data_path_safe(const struct bt_iso_chan *chan, uint8_t dir, + const struct bt_iso_chan_path *path) +{ + int err; + bt_le_host_lock(); + err = bt_iso_setup_data_path(chan, dir, path); + bt_le_host_unlock(); + return err; +} + +int bt_iso_remove_data_path_safe(const struct bt_iso_chan *chan, uint8_t dir) +{ + int err; + bt_le_host_lock(); + err = bt_iso_remove_data_path(chan, dir); + bt_le_host_unlock(); + return err; +} + +int bt_iso_chan_get_info_safe(const struct bt_iso_chan *chan, struct bt_iso_info *info) +{ + int err; + bt_le_host_lock(); + err = bt_iso_chan_get_info(chan, info); + bt_le_host_unlock(); + return err; +} + +#if CONFIG_BT_ISO_TX +int bt_iso_chan_send_safe(struct bt_iso_chan *chan, struct net_buf *buf, uint16_t seq_num) +{ + int err; + bt_le_host_lock(); + err = bt_iso_chan_send(chan, buf, seq_num); + bt_le_host_unlock(); + return err; +} + +int bt_iso_chan_send_ts_safe(struct bt_iso_chan *chan, struct net_buf *buf, uint16_t seq_num, + uint32_t ts) +{ + int err; + bt_le_host_lock(); + err = bt_iso_chan_send_ts(chan, buf, seq_num, ts); + bt_le_host_unlock(); + return err; +} + +int bt_iso_chan_get_tx_sync_safe(const struct bt_iso_chan *chan, struct bt_iso_tx_info *info) +{ + int err; + bt_le_host_lock(); + err = bt_iso_chan_get_tx_sync(chan, info); + bt_le_host_unlock(); + return err; +} +#endif /* CONFIG_BT_ISO_TX */ + +#if CONFIG_BT_ISO_UNICAST +int bt_iso_chan_disconnect_safe(struct bt_iso_chan *chan) +{ + int err; + bt_le_host_lock(); + err = bt_iso_chan_disconnect(chan); + bt_le_host_unlock(); + return err; +} + +#if CONFIG_BT_ISO_PERIPHERAL +int bt_iso_server_register_safe(struct bt_iso_server *server) +{ + int err; + bt_le_host_lock(); + err = bt_iso_server_register(server); + bt_le_host_unlock(); + return err; +} + +int bt_iso_server_unregister_safe(struct bt_iso_server *server) +{ + int err; + bt_le_host_lock(); + err = bt_iso_server_unregister(server); + bt_le_host_unlock(); + return err; +} +#endif /* CONFIG_BT_ISO_PERIPHERAL */ + +#if CONFIG_BT_ISO_CENTRAL +int bt_iso_cig_create_safe(const struct bt_iso_cig_param *param, struct bt_iso_cig **out_cig) +{ + int err; + bt_le_host_lock(); + err = bt_iso_cig_create(param, out_cig); + bt_le_host_unlock(); + return err; +} + +int bt_iso_cig_reconfigure_safe(struct bt_iso_cig *cig, const struct bt_iso_cig_param *param) +{ + int err; + bt_le_host_lock(); + err = bt_iso_cig_reconfigure(cig, param); + bt_le_host_unlock(); + return err; +} + +int bt_iso_cig_terminate_safe(struct bt_iso_cig *cig) +{ + int err; + bt_le_host_lock(); + err = bt_iso_cig_terminate(cig); + bt_le_host_unlock(); + return err; +} + +int bt_iso_chan_connect_safe(const struct bt_iso_connect_param *param, size_t count) +{ + int err; + bt_le_host_lock(); + err = bt_iso_chan_connect(param, count); + bt_le_host_unlock(); + return err; +} +#endif /* CONFIG_BT_ISO_CENTRAL */ +#endif /* CONFIG_BT_ISO_UNICAST */ + +#if CONFIG_BT_ISO_BROADCAST +#if CONFIG_BT_ISO_BROADCASTER +int bt_iso_big_register_cb_safe(struct bt_iso_big_cb *cb) +{ + int err; + bt_le_host_lock(); + err = bt_iso_big_register_cb(cb); + bt_le_host_unlock(); + return err; +} + +int bt_iso_big_create_safe(struct bt_le_ext_adv *padv, struct bt_iso_big_create_param *param, + struct bt_iso_big **out_big) +{ + int err; + bt_le_host_lock(); + err = bt_iso_big_create(padv, param, out_big); + bt_le_host_unlock(); + return err; +} +#endif /* CONFIG_BT_ISO_BROADCASTER */ + +int bt_iso_big_terminate_safe(struct bt_iso_big *big) +{ + int err; + bt_le_host_lock(); + err = bt_iso_big_terminate(big); + bt_le_host_unlock(); + return err; +} + +#if CONFIG_BT_ISO_SYNC_RECEIVER +int bt_iso_big_sync_safe(struct bt_le_per_adv_sync *sync, struct bt_iso_big_sync_param *param, + struct bt_iso_big **out_big) +{ + int err; + bt_le_host_lock(); + err = bt_iso_big_sync(sync, param, out_big); + bt_le_host_unlock(); + return err; +} +#endif /* CONFIG_BT_ISO_SYNC_RECEIVER */ +#endif /* CONFIG_BT_ISO_BROADCAST */ + +void bt_iso_reset_safe(void) +{ + bt_le_host_lock(); + bt_iso_reset(); + bt_le_host_unlock(); +} diff --git a/components/bt/esp_ble_audio/host/services/ots/Kconfig.ots.in b/components/bt/esp_ble_audio/host/services/ots/Kconfig.ots.in new file mode 100644 index 0000000000..0bcb78b191 --- /dev/null +++ b/components/bt/esp_ble_audio/host/services/ots/Kconfig.ots.in @@ -0,0 +1,107 @@ +# Bluetooth Object Transfer service + +# SPDX-FileCopyrightText: 2020-2022 Nordic Semiconductor ASA +# SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 + +config BT_OTS + bool "Object Transfer Service (OTS) [EXPERIMENTAL]" + select BT_OTS_SECONDARY_SVC + help + Enable Object Transfer Service. + +if BT_OTS + + config BT_OTS_DIR_LIST_OBJ + bool "The Directory Listing Object" + help + Enables the Directory Listing Object, which is an object that contains all the metadata + from all other objects, for easy exposure to a client. Enabling this will use one of the + objects given by BT_OTS_MAX_OBJ_CNT. + + config BT_OTS_DIR_LIST_OBJ_NAME + string "The object name of the Directory Listing Object" + default "Directory" + depends on BT_OTS_DIR_LIST_OBJ + help + The name of the Directory Listing Object when it is read by a client. + + config BT_OTS_MAX_INST_CNT + int "Maximum number of available OTS instances" + default 1 + range 1 1 if !BT_OTS_SECONDARY_SVC + + config BT_OTS_SECONDARY_SVC + bool "Register OTS as Secondary Service" + + config BT_OTS_OACP_CREATE_SUPPORT + bool "Support OACP Create Operation" + depends on BT_OTS_OACP_WRITE_SUPPORT + depends on BT_OTS_OBJ_NAME_WRITE_SUPPORT + + config BT_OTS_OACP_CHECKSUM_SUPPORT + bool "Support OACP Calculate Checksum operation" + + config BT_OTS_OACP_DELETE_SUPPORT + bool "Support OACP Delete Operation" + + config BT_OTS_OACP_READ_SUPPORT + bool "Support OACP Read Operation" + default y + + config BT_OTS_OACP_WRITE_SUPPORT + bool "Support OACP Write Operation" + + config BT_OTS_OACP_PATCH_SUPPORT + bool "Support patching of objects" + depends on BT_OTS_OACP_WRITE_SUPPORT + + config BT_OTS_OLCP_GO_TO_SUPPORT + bool "Support OLCP Go To Operation" + default y + + config BT_OTS_OBJ_NAME_WRITE_SUPPORT + bool "Support object name write" + +endif # BT_OTS + +#### Object Transfer Service Client ################################ + +config BT_OTS_CLIENT + bool "Object Transfer Service Client [Experimental]" + help + This option enables support for the Object Transfer Service Client. + +if BT_OTS || BT_OTS_CLIENT + + config BT_OTS_MAX_OBJ_CNT + hex "Maximum number of objects that each service instance can store" + default 0x05 + # Given the maximum size of a directory listing record (172) and the maximum size of an + # object using the net_buf implementation is 2^16-1, the maximum number of objects is given + # by 2^16-1 / 172 = 381 == 0x17D) + range 0x02 0x17D if BT_OTS_DIR_LIST_OBJ + # Max obj count is otherwise the non-RFU IDs available + range 0x01 0xFFFFFFFFFFFFFEFF + + config BT_OTS_L2CAP_CHAN_TX_MTU + int "Size of TX MTU for Object Transfer Channel" + default 256 + range 21 65533 + + config BT_OTS_L2CAP_CHAN_RX_MTU + int "Size of RX MTU for Object Transfer Channel" + # RX MTU will be truncated to account for the L2CAP PDU and SDU header. + default 256 + range 21 65533 # TODO: check + + config BT_OTS_OBJ_MAX_NAME_LEN + # int "Maximum object name length" + int # Fixed value (i.e. max 120) for now + # Max name length allowed by OTS spec is 120 octets + # TODO: Set separate max name length for client, as other + # servers may use the full 120 octets. + default 120 + range 1 120 + +endif # BT_OTS || BT_OTS_CLIENT diff --git a/components/bt/esp_ble_audio/host/services/ots/ots.c b/components/bt/esp_ble_audio/host/services/ots/ots.c new file mode 100644 index 0000000000..15167a72e5 --- /dev/null +++ b/components/bt/esp_ble_audio/host/services/ots/ots.c @@ -0,0 +1,718 @@ +/* + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include "ots_internal.h" +#include "ots_obj_manager_internal.h" +#include "ots_dir_list_internal.h" + +#include + +LOG_MODULE_REGISTER(bt_ots, CONFIG_BT_OTS_LOG_LEVEL); + +#if defined(CONFIG_BT_OTS_OACP_CREATE_SUPPORT) +#define OACP_FEAT_BIT_CREATE BIT(BT_OTS_OACP_FEAT_CREATE) +#else +#define OACP_FEAT_BIT_CREATE 0 +#endif + +#if defined(CONFIG_BT_OTS_OACP_DELETE_SUPPORT) +#define OACP_FEAT_BIT_DELETE BIT(BT_OTS_OACP_FEAT_DELETE) +#else +#define OACP_FEAT_BIT_DELETE 0 +#endif + +#if defined(CONFIG_BT_OTS_OACP_CHECKSUM_SUPPORT) +#define OACP_FEAT_BIT_CRC BIT(BT_OTS_OACP_FEAT_CHECKSUM) +#else +#define OACP_FEAT_BIT_CRC 0 +#endif + +#if defined(CONFIG_BT_OTS_OACP_READ_SUPPORT) +#define OACP_FEAT_BIT_READ BIT(BT_OTS_OACP_FEAT_READ) +#else +#define OACP_FEAT_BIT_READ 0 +#endif + +#if defined(CONFIG_BT_OTS_OACP_WRITE_SUPPORT) +#define OACP_FEAT_BIT_WRITE BIT(BT_OTS_OACP_FEAT_WRITE) +#else +#define OACP_FEAT_BIT_WRITE 0 +#endif + +#if defined(CONFIG_BT_OTS_OACP_PATCH_SUPPORT) +#define OACP_FEAT_BIT_PATCH BIT(BT_OTS_OACP_FEAT_PATCH) +#else +#define OACP_FEAT_BIT_PATCH 0 +#endif + +/* OACP features supported by Kconfig */ +#define OACP_FEAT ( \ + OACP_FEAT_BIT_CREATE | \ + OACP_FEAT_BIT_DELETE | \ + OACP_FEAT_BIT_CRC | \ + OACP_FEAT_BIT_READ | \ + OACP_FEAT_BIT_WRITE | \ + OACP_FEAT_BIT_PATCH) + +#if defined(CONFIG_BT_OTS_OLCP_GO_TO_SUPPORT) +#define OLCP_FEAT_BIT_GOTO BIT(BT_OTS_OLCP_FEAT_GO_TO) +#else +#define OLCP_FEAT_BIT_GOTO 0 +#endif + +/* OLCP features supported by Kconfig */ +#define OLCP_FEAT OLCP_FEAT_BIT_GOTO + +static bool ots_obj_validate_prop_against_oacp(uint32_t prop, uint32_t oacp) +{ + if (BT_OTS_OBJ_GET_PROP_DELETE(prop) > 0 && BT_OTS_OACP_GET_FEAT_DELETE(oacp) == 0) { + return false; + } + + if (BT_OTS_OBJ_GET_PROP_EXECUTE(prop) > 0 && BT_OTS_OACP_GET_FEAT_EXECUTE(oacp) == 0) { + return false; + } + + if (BT_OTS_OBJ_GET_PROP_READ(prop) > 0 && BT_OTS_OACP_GET_FEAT_READ(oacp) == 0) { + return false; + } + + if (BT_OTS_OBJ_GET_PROP_WRITE(prop) > 0 && BT_OTS_OACP_GET_FEAT_WRITE(oacp) == 0) { + return false; + } + + if (BT_OTS_OBJ_GET_PROP_APPEND(prop) > 0 && BT_OTS_OACP_GET_FEAT_APPEND(oacp) == 0) { + return false; + } + + if (BT_OTS_OBJ_GET_PROP_TRUNCATE(prop) > 0 && BT_OTS_OACP_GET_FEAT_TRUNCATE(oacp) == 0) { + return false; + } + + if (BT_OTS_OBJ_GET_PROP_PATCH(prop) > 0 && BT_OTS_OACP_GET_FEAT_PATCH(oacp) == 0) { + return false; + } + + return true; +} + +static ssize_t ots_feature_read(struct bt_conn *conn, + const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset) +{ + struct bt_ots *ots = (struct bt_ots *) attr->user_data; + + LOG_DBG("OTS Feature GATT Read Operation"); + + return bt_gatt_attr_read(conn, attr, buf, len, offset, &ots->features, + sizeof(ots->features)); +} + +static ssize_t ots_obj_name_read(struct bt_conn *conn, + const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset) +{ + struct bt_ots *ots = (struct bt_ots *) attr->user_data; + + LOG_DBG("OTS Object Name GATT Read Operation"); + + if (!ots->cur_obj) { + LOG_DBG("No Current Object selected in OTS!"); + return BT_GATT_ERR(BT_GATT_OTS_OBJECT_NOT_SELECTED); + } + + if (!ots->cur_obj->metadata.name) { + LOG_DBG("Current Object has no name!"); + return BT_GATT_ERR(BT_GATT_OTS_OBJECT_NOT_SELECTED); + } + + return bt_gatt_attr_read(conn, attr, buf, len, offset, + ots->cur_obj->metadata.name, + strlen(ots->cur_obj->metadata.name)); +} + +#if defined(CONFIG_BT_OTS_OBJ_NAME_WRITE_SUPPORT) +ssize_t ots_obj_name_write(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, + uint16_t offset, uint8_t flags) +{ + struct bt_ots *ots = (struct bt_ots *) attr->user_data; + struct bt_gatt_ots_object *obj = NULL; + int rc = 0; + char name[CONFIG_BT_OTS_OBJ_MAX_NAME_LEN + 1]; + + LOG_DBG("OTS Object Name GATT Write Operation"); + + if (!ots->cur_obj) { + LOG_DBG("No Current Object selected in OTS!"); + return BT_GATT_ERR(BT_GATT_OTS_OBJECT_NOT_SELECTED); + } + + if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ) && + ots->cur_obj->id == OTS_OBJ_ID_DIR_LIST) { + LOG_DBG("Rejecting name write for the directory list object."); + return BT_GATT_ERR(BT_GATT_OTS_WRITE_REQUEST_REJECTED); + } + + if (offset > 0) { + LOG_DBG("Rejecting a long write, offset must be 0!"); + return BT_GATT_ERR(BT_GATT_OTS_WRITE_REQUEST_REJECTED); + } + + if (len == 0 || len > CONFIG_BT_OTS_OBJ_MAX_NAME_LEN) { + LOG_DBG("Invalid object name length!"); + return BT_GATT_ERR(BT_GATT_OTS_WRITE_REQUEST_REJECTED); + } + + /* Construct a temporary name for duplication detection */ + memcpy(name, buf, len); + name[len] = '\0'; + + rc = bt_gatt_ots_obj_manager_first_obj_get(ots->obj_manager, &obj); + while (rc == 0) { + if (obj != ots->cur_obj && strcmp(name, obj->metadata.name) == 0) { + LOG_DBG("Object name is duplicated!"); + return BT_GATT_ERR(BT_GATT_OTS_OBJECT_NAME_ALREADY_EXISTS); + } + rc = bt_gatt_ots_obj_manager_next_obj_get(ots->obj_manager, obj, &obj); + } + + /* No duplicate detected, notify application and update real object name */ + if (ots->cb->obj_name_written) { + ots->cb->obj_name_written(ots, conn, ots->cur_obj->id, + ots->cur_obj->metadata.name, name); + } + + /* Ensure the name fits; use strncpy or ensure metadata.name buffer + * is always allocated to CONFIG_BT_OTS_OBJ_MAX_NAME_LEN + 1. + */ + strncpy(ots->cur_obj->metadata.name, name, CONFIG_BT_OTS_OBJ_MAX_NAME_LEN); + ots->cur_obj->metadata.name[CONFIG_BT_OTS_OBJ_MAX_NAME_LEN] = '\0'; + + return len; +} +#endif + +static ssize_t ots_obj_type_read(struct bt_conn *conn, + const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset) +{ + struct bt_ots *ots = (struct bt_ots *) attr->user_data; + struct bt_ots_obj_metadata *obj_meta; + + LOG_DBG("OTS Object Type GATT Read Operation"); + + if (!ots->cur_obj) { + LOG_DBG("No Current Object selected in OTS!"); + return BT_GATT_ERR(BT_GATT_OTS_OBJECT_NOT_SELECTED); + } + + obj_meta = &ots->cur_obj->metadata; + switch (obj_meta->type.uuid.type) { + case BT_UUID_TYPE_16: + return bt_gatt_attr_read(conn, attr, buf, len, offset, + &obj_meta->type.uuid_16.val, + sizeof(obj_meta->type.uuid_16.val)); + case BT_UUID_TYPE_128: + return bt_gatt_attr_read(conn, attr, buf, len, offset, + obj_meta->type.uuid_128.val, + sizeof(obj_meta->type.uuid_128.val)); + default: + return -EINVAL; + } +} + +static ssize_t ots_obj_size_read(struct bt_conn *conn, + const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset) +{ + struct bt_ots *ots = (struct bt_ots *) attr->user_data; + + LOG_DBG("OTS Object Size GATT Read Operation"); + + if (!ots->cur_obj) { + LOG_DBG("No Current Object selected in OTS!"); + return BT_GATT_ERR(BT_GATT_OTS_OBJECT_NOT_SELECTED); + } + + return bt_gatt_attr_read(conn, attr, buf, len, offset, + &ots->cur_obj->metadata.size, + sizeof(ots->cur_obj->metadata.size)); +} + +static ssize_t ots_obj_id_read(struct bt_conn *conn, + const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset) +{ + struct bt_ots *ots = (struct bt_ots *) attr->user_data; + uint8_t id[BT_OTS_OBJ_ID_SIZE]; + char id_str[BT_OTS_OBJ_ID_STR_LEN]; + + LOG_DBG("OTS Object ID GATT Read Operation"); + + if (!ots->cur_obj) { + LOG_DBG("No Current Object selected in OTS!"); + return BT_GATT_ERR(BT_GATT_OTS_OBJECT_NOT_SELECTED); + } + + sys_put_le48(ots->cur_obj->id, id); + + bt_ots_obj_id_to_str(ots->cur_obj->id, id_str, + sizeof(id_str)); + LOG_DBG("Current Object ID: %s", id_str); + + return bt_gatt_attr_read(conn, attr, buf, len, offset, id, sizeof(id)); +} + +static ssize_t ots_obj_prop_read(struct bt_conn *conn, + const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset) +{ + struct bt_ots *ots = (struct bt_ots *) attr->user_data; + + LOG_DBG("OTS Object Properties GATT Read Operation"); + + if (!ots->cur_obj) { + LOG_DBG("No Current Object selected in OTS!"); + return BT_GATT_ERR(BT_GATT_OTS_OBJECT_NOT_SELECTED); + } + + return bt_gatt_attr_read(conn, attr, buf, len, offset, + &ots->cur_obj->metadata.props, + sizeof(ots->cur_obj->metadata.props)); +} + +int bt_ots_obj_add_internal(struct bt_ots *ots, struct bt_conn *conn, + const struct bt_ots_obj_add_param *param, + struct bt_gatt_ots_object **obj) +{ + int err; + struct bt_gatt_ots_object *new_obj; + struct bt_ots_obj_created_desc created_desc; + + if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ) && ots->dir_list && + !bt_ots_dir_list_is_idle(ots->dir_list)) { + LOG_DBG("Directory Listing Object is being read"); + return -EBUSY; + } + + err = bt_gatt_ots_obj_manager_obj_add(ots->obj_manager, &new_obj); + if (err) { + LOG_ERR("No space available in the object manager"); + return err; + } + + (void)memset(&created_desc, 0, sizeof(created_desc)); + + if (ots->cb->obj_created) { + err = ots->cb->obj_created(ots, conn, new_obj->id, param, &created_desc); + + if (err) { + (void)bt_gatt_ots_obj_manager_obj_delete(new_obj); + + return err; + } + + if (!ots_obj_validate_prop_against_oacp(created_desc.props, ots->features.oacp)) { + LOG_ERR("Object properties (0x%04X) are not a subset of OACP (0x%04X)", + created_desc.props, ots->features.oacp); + + (void)bt_ots_obj_delete(ots, new_obj->id); + return -ECANCELED; + } + + if (created_desc.name == NULL) { + LOG_ERR("Object name must be set by application after object creation."); + + (void)bt_ots_obj_delete(ots, new_obj->id); + return -ECANCELED; + } + + if (created_desc.size.alloc < param->size) { + LOG_ERR("Object allocated size must >= requested size."); + + (void)bt_ots_obj_delete(ots, new_obj->id); + return -ECANCELED; + } + } else { + /* obj_created callback is required to populate the descriptor */ + LOG_ERR("obj_created callback is not set"); + + (void)bt_gatt_ots_obj_manager_obj_delete(new_obj); + return -EINVAL; + } + + new_obj->metadata.type = param->type; + new_obj->metadata.name = created_desc.name; + new_obj->metadata.size = created_desc.size; + new_obj->metadata.props = created_desc.props; + + if (obj) { + *obj = new_obj; + } + + return 0; +} + +int bt_ots_obj_add(struct bt_ots *ots, const struct bt_ots_obj_add_param *param) +{ + int err; + size_t name_len; + struct bt_gatt_ots_object *obj; + + err = bt_ots_obj_add_internal(ots, NULL, param, &obj); + if (err) { + return err; + } + + if (obj->metadata.name == NULL) { + LOG_ERR("Object name is NULL"); + + (void)bt_ots_obj_delete(ots, obj->id); + return -ECANCELED; + } + + name_len = strlen(obj->metadata.name); + if (name_len == 0 || name_len > CONFIG_BT_OTS_OBJ_MAX_NAME_LEN) { + LOG_ERR("Invalid name length %zu", name_len); + + (void)bt_ots_obj_delete(ots, obj->id); + return -ECANCELED; + } + + if (obj->metadata.size.cur > param->size) { + LOG_ERR("Object current size must be less than or equal to requested size."); + + (void)bt_ots_obj_delete(ots, obj->id); + return -ECANCELED; + } + + return obj->id; +} + +int bt_ots_obj_delete(struct bt_ots *ots, uint64_t id) +{ + int err; + struct bt_gatt_ots_object *obj; + + CHECKIF(!BT_OTS_VALID_OBJ_ID(id)) { + LOG_DBG("Invalid object ID 0x%016llx", id); + + return -EINVAL; + } + + err = bt_gatt_ots_obj_manager_obj_get(ots->obj_manager, id, &obj); + if (err) { + return err; + } + + if (obj->state.type != BT_GATT_OTS_OBJECT_IDLE_STATE) { + return -EBUSY; + } + + if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ) && ots->dir_list && + !bt_ots_dir_list_is_idle(ots->dir_list)) { + LOG_DBG("Directory Listing Object is being read"); + return -EBUSY; + } + + if (ots->cb->obj_deleted) { + err = ots->cb->obj_deleted(ots, NULL, obj->id); + if (err) { + return err; + } + } + + err = bt_gatt_ots_obj_manager_obj_delete(obj); + if (err) { + return err; + } + + if (ots->cur_obj == obj) { + ots->cur_obj = NULL; + } + + return 0; +} + +#if defined(CONFIG_BT_OTS_SECONDARY_SVC) +void *bt_ots_svc_decl_get(struct bt_ots *ots) +{ + return ots->service->attrs; +} +#endif + +static void oacp_indicate_work_handler(struct k_work *work) +{ + struct bt_gatt_ots_indicate *ind = CONTAINER_OF(work, struct bt_gatt_ots_indicate, work); + struct bt_ots *ots = CONTAINER_OF(ind, struct bt_ots, oacp_ind); + + bt_gatt_indicate(NULL, &ots->oacp_ind.params); +} + +static void olcp_indicate_work_handler(struct k_work *work) +{ + struct bt_gatt_ots_indicate *ind = CONTAINER_OF(work, struct bt_gatt_ots_indicate, work); + struct bt_ots *ots = CONTAINER_OF(ind, struct bt_ots, olcp_ind); + + bt_gatt_indicate(NULL, &ots->olcp_ind.params); +} + +int bt_ots_init(struct bt_ots *ots, + struct bt_ots_init_param *ots_init) +{ + int err; + + if (!ots || !ots_init || !ots_init->cb) { + return -EINVAL; + } + + __ASSERT(ots_init->cb->obj_created || !BT_OTS_OACP_GET_FEAT_CREATE(ots_init->features.oacp), + "Callback for object creation is not set and object creation is enabled"); + __ASSERT(ots_init->cb->obj_deleted || !BT_OTS_OACP_GET_FEAT_DELETE(ots_init->features.oacp), + "Callback for object deletion is not set and object deletion is enabled"); +#if defined(CONFIG_BT_OTS_OACP_CHECKSUM_SUPPORT) + __ASSERT(ots_init->cb->obj_cal_checksum || + !BT_OTS_OACP_GET_FEAT_CHECKSUM(ots_init->features.oacp), + "Callback for object calculate checksum is not set and checksum is enabled"); +#endif + __ASSERT(ots_init->cb->obj_read || !BT_OTS_OACP_GET_FEAT_READ(ots_init->features.oacp), + "Callback for object reading is not set and object read is enabled"); + __ASSERT(ots_init->cb->obj_write || !BT_OTS_OACP_GET_FEAT_WRITE(ots_init->features.oacp), + "Callback for object write is not set and object write is enabled"); + + /* Set callback structure. */ + ots->cb = ots_init->cb; + + /* Check OACP supported features against Kconfig. */ + if (ots_init->features.oacp & (~((uint32_t) OACP_FEAT))) { + return -ENOTSUP; + } + + __ASSERT(!BT_OTS_OACP_GET_FEAT_CREATE(ots_init->features.oacp) || + BT_OTS_OACP_GET_FEAT_WRITE(ots_init->features.oacp), + "Object creation requires object write to be supported"); + + ots->features.oacp = ots_init->features.oacp; + LOG_DBG("OACP features: 0x%04X", ots->features.oacp); + + /* Check OLCP supported features against Kconfig. */ + if (ots_init->features.olcp & (~((uint32_t) OLCP_FEAT))) { + return -ENOTSUP; + } + ots->features.olcp = ots_init->features.olcp; + LOG_DBG("OLCP features: 0x%04X", ots->features.olcp); + + /* Register L2CAP context. */ + err = bt_gatt_ots_l2cap_register(&ots->l2cap); + if (err) { + return err; + } + + err = bt_gatt_service_register(ots->service); + if (err) { + bt_gatt_ots_l2cap_unregister(&ots->l2cap); + + return err; + } + + if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ)) { + bt_ots_dir_list_init(&ots->dir_list, ots->obj_manager); + } + + k_work_init(&ots->oacp_ind.work, oacp_indicate_work_handler); + k_work_init(&ots->olcp_ind.work, olcp_indicate_work_handler); + + LOG_DBG("Initialized OTS"); + + return 0; +} + +#if defined(CONFIG_BT_OTS_SECONDARY_SVC) +#define BT_GATT_OTS_SERVICE BT_GATT_SECONDARY_SERVICE +#else +#define BT_GATT_OTS_SERVICE BT_GATT_PRIMARY_SERVICE +#endif + +#if defined(CONFIG_BT_OTS_OBJ_NAME_WRITE_SUPPORT) +#define BT_OTS_OBJ_NAME_GATT_CHRC (BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE) +#define BT_OTS_OBJ_NAME_GATT_PERM (BT_GATT_PERM_READ | BT_GATT_PERM_WRITE) +#define BT_OTS_OBJ_NAME_GATT_WRITE (ots_obj_name_write) +#else +#define BT_OTS_OBJ_NAME_GATT_CHRC (BT_GATT_CHRC_READ) +#define BT_OTS_OBJ_NAME_GATT_PERM (BT_GATT_PERM_READ) +#define BT_OTS_OBJ_NAME_GATT_WRITE (NULL) +#endif + +#define BT_GATT_OTS_ATTRS(_ots) { \ + BT_GATT_OTS_SERVICE(BT_UUID_OTS), \ + BT_GATT_CHARACTERISTIC(BT_UUID_OTS_FEATURE, \ + BT_GATT_CHRC_READ, BT_GATT_PERM_READ, \ + ots_feature_read, NULL, &_ots), \ + BT_GATT_CHARACTERISTIC(BT_UUID_OTS_NAME, \ + BT_OTS_OBJ_NAME_GATT_CHRC, BT_OTS_OBJ_NAME_GATT_PERM, \ + ots_obj_name_read, BT_OTS_OBJ_NAME_GATT_WRITE, &_ots), \ + BT_GATT_CHARACTERISTIC(BT_UUID_OTS_TYPE, \ + BT_GATT_CHRC_READ, BT_GATT_PERM_READ, \ + ots_obj_type_read, NULL, &_ots), \ + BT_GATT_CHARACTERISTIC(BT_UUID_OTS_SIZE, \ + BT_GATT_CHRC_READ, BT_GATT_PERM_READ, \ + ots_obj_size_read, NULL, &_ots), \ + BT_GATT_CHARACTERISTIC(BT_UUID_OTS_ID, \ + BT_GATT_CHRC_READ, BT_GATT_PERM_READ, \ + ots_obj_id_read, NULL, &_ots), \ + BT_GATT_CHARACTERISTIC(BT_UUID_OTS_PROPERTIES, \ + BT_GATT_CHRC_READ, BT_GATT_PERM_READ, \ + ots_obj_prop_read, NULL, &_ots), \ + BT_GATT_CHARACTERISTIC(BT_UUID_OTS_ACTION_CP, \ + BT_GATT_CHRC_WRITE | BT_GATT_CHRC_INDICATE, \ + BT_GATT_PERM_WRITE, NULL, \ + bt_gatt_ots_oacp_write, &_ots), \ + BT_GATT_CCC_MANAGED(&_ots.oacp_ind.ccc, \ + BT_GATT_PERM_READ | BT_GATT_PERM_WRITE), \ + BT_GATT_CHARACTERISTIC(BT_UUID_OTS_LIST_CP, \ + BT_GATT_CHRC_WRITE | BT_GATT_CHRC_INDICATE, \ + BT_GATT_PERM_WRITE, NULL, \ + bt_gatt_ots_olcp_write, &_ots), \ + BT_GATT_CCC_MANAGED(&_ots.olcp_ind.ccc, \ + BT_GATT_PERM_READ | BT_GATT_PERM_WRITE) \ +} + +#define BT_GATT_OTS_INSTANCE_LIST_SIZE (ARRAY_SIZE(ots_instances)) +#define BT_GATT_OTS_INSTANCE_LIST_START ots_instances +#define BT_GATT_OTS_INSTANCE_LIST_END \ + (&ots_instances[BT_GATT_OTS_INSTANCE_LIST_SIZE]) + +#define BT_GATT_OTS_SERVICE_LIST_START ots_service_list + +static struct bt_ots ots_instances[CONFIG_BT_OTS_MAX_INST_CNT]; +static uint32_t instance_cnt; +BT_GATT_SERVICE_INSTANCE_DEFINE(ots_service_list, ots_instances, + CONFIG_BT_OTS_MAX_INST_CNT, + BT_GATT_OTS_ATTRS); + +static void ots_delete_empty_name_objects(struct bt_ots *ots, struct bt_conn *conn) +{ + char id_str[BT_OTS_OBJ_ID_STR_LEN]; + struct bt_gatt_ots_object *obj; + struct bt_gatt_ots_object *next_obj; + int err; + + err = bt_gatt_ots_obj_manager_first_obj_get(ots->obj_manager, &next_obj); + while (!err) { + obj = next_obj; + + /* Get the next object before we potentially delete the current object and + * no longer can get the next object + */ + err = bt_gatt_ots_obj_manager_next_obj_get(ots->obj_manager, obj, &next_obj); + + if (strlen(obj->metadata.name) == 0) { + bt_ots_obj_id_to_str(obj->id, id_str, sizeof(id_str)); + LOG_DBG("Deleting object with %s ID due to empty name", id_str); + + if (ots->cb && ots->cb->obj_deleted) { + ots->cb->obj_deleted(ots, conn, obj->id); + } + + if (bt_gatt_ots_obj_manager_obj_delete(obj)) { + LOG_ERR("Failed to remove object with %s ID from object manager", + id_str); + } + } + } +} + +static void ots_conn_disconnected(struct bt_conn *conn, uint8_t reason) +{ + uint32_t index; + struct bt_ots *instance; + + for (instance = BT_GATT_OTS_INSTANCE_LIST_START, index = 0; + index < instance_cnt; + instance++, index++) { + + LOG_DBG("Processing disconnect for OTS instance %u", index); + + if (instance->cur_obj != NULL) { + __ASSERT(instance->cur_obj->state.type == BT_GATT_OTS_OBJECT_IDLE_STATE, + "The current object is expected to be in idle state as part " + "of cleanup of the L2CAP channel connection close."); + instance->cur_obj = NULL; + } + + ots_delete_empty_name_objects(instance, conn); + } +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .disconnected = ots_conn_disconnected, +}; + +struct bt_ots *bt_ots_free_instance_get(void) +{ + if (instance_cnt >= BT_GATT_OTS_INSTANCE_LIST_SIZE) { + return NULL; + } + + return &BT_GATT_OTS_INSTANCE_LIST_START[instance_cnt++]; +} + +static int bt_gatt_ots_instances_prepare(void) +{ + uint32_t index; + struct bt_ots *instance; + + for (instance = BT_GATT_OTS_INSTANCE_LIST_START, index = 0; + instance != BT_GATT_OTS_INSTANCE_LIST_END; + instance++, index++) { + /* Assign an object pool to the OTS instance. */ + instance->obj_manager = bt_gatt_ots_obj_manager_assign(); + + if (!instance->obj_manager) { + LOG_ERR("OTS Object manager instance not available"); + return -ENOMEM; + } + + /* Assign pointer to the service descriptor. */ + instance->service = &BT_GATT_OTS_SERVICE_LIST_START[index]; + + /* Initialize CCC descriptors for characteristics with + * indication properties. + */ + instance->oacp_ind.ccc.cfg_changed = + bt_gatt_ots_oacp_cfg_changed; + instance->olcp_ind.ccc.cfg_changed = + bt_gatt_ots_olcp_cfg_changed; + } + + return 0; +} + +SYS_INIT(bt_gatt_ots_instances_prepare, APPLICATION, + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); + +int bt_gatt_ots_conn_cb_register(void) +{ + return bt_conn_cb_register_safe((void *)&bt_conn_cb_conn_callbacks); +} diff --git a/components/bt/esp_ble_audio/host/services/ots/ots_client.c b/components/bt/esp_ble_audio/host/services/ots/ots_client.c new file mode 100644 index 0000000000..fb7c041021 --- /dev/null +++ b/components/bt/esp_ble_audio/host/services/ots/ots_client.c @@ -0,0 +1,1900 @@ +/** @file + * @brief Bluetooth Object Transfer Client + * + * SPDX-FileCopyrightText: 2020-2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include "ots_internal.h" +#include "ots_client_internal.h" +#include "ots_l2cap_internal.h" +#include "ots_dir_list_internal.h" +#include "ots_oacp_internal.h" +#include "ots_olcp_internal.h" + +#define LOG_LEVEL CONFIG_BT_OTS_CLIENT_LOG_LEVEL +#include +LOG_MODULE_REGISTER(bt_otc); + +/* TODO: KConfig options */ +#define OTS_CLIENT_INST_COUNT 1 + +#define OTS_CLIENT_MAX_WRITE_SIZE 23 +/* 64-bit value, outside of 48-bit Object ID range */ +#define OTS_CLIENT_UNKNOWN_ID 0x0001000000000000 + +struct dirlisting_record_t { + uint16_t len; + uint8_t flags; + uint8_t name_len; + struct bt_ots_obj_metadata metadata; +}; + +/**@brief String literals for the OACP result codes. Used for logging output.*/ +static const char * const lit_request[] = { + "RFU", + "Create", + "Delete", + "Calculate Checksum", + "Execute", + "Read", + "Write", + "Abort", +}; + +/**@brief String literals for the OACP result codes. Used for logging output.*/ +static const char * const lit_result[] = { + "RFU", + "Success", + "Op Code Not Supported", + "Invalid Parameter", + "Insufficient Resources", + "Invalid Object", + "Channel Unavailable", + "Unsupported Type", + "Procedure Not Permitted", + "Object Locked", + "Operation Failed" +}; + +/**@brief String literals for the OLCP request codes. Used for logging output.*/ +static const char * const lit_olcp_request[] = { + "RFU", + "FIRST", + "LAST", + "PREV", + "NEXT", + "GOTO", + "ORDER", + "REQ_NUM_OBJS", + "CLEAR_MARKING", +}; + +/**@brief String literals for the OLCP result codes. Used for logging output.*/ +static const char * const lit_olcp_result[] = { + "RFU", + "Success", + "Op Code Not Supported", + "Invalid Parameter", + "Operation Failed", + "Out of Bonds", + "Too Many Objects", + "No Object", + "Object ID not found", +}; + +struct bt_otc_internal_instance_t { + struct bt_ots_client *otc_inst; + struct bt_gatt_ots_l2cap l2cap_ctx; + bool busy; + /** Bitfield that is used to determine how much metadata to read */ + uint8_t metadata_to_read; + /** Bitfield of how much metadata has been attempted to read */ + uint8_t metadata_read_attempted; + /** Bitfield of how much metadata has been read */ + uint8_t metadata_read; + int metadata_err; + uint32_t rcvd_size; + uint32_t sent_size; +}; + +/* The profile clients that uses the OTS are responsible for discovery and + * will simply register any OTS instances as pointers, which is stored here. + */ +static struct bt_otc_internal_instance_t otc_insts[OTS_CLIENT_INST_COUNT]; +NET_BUF_SIMPLE_DEFINE_STATIC(otc_tx_buf, OTS_CLIENT_MAX_WRITE_SIZE); +static struct bt_otc_internal_instance_t *cur_inst; + +static int oacp_read(struct bt_conn *conn, + struct bt_otc_internal_instance_t *inst); +static int oacp_write(struct bt_conn *conn, struct bt_otc_internal_instance_t *inst, + const void *buf, uint32_t len, uint32_t offset, + enum bt_ots_oacp_write_op_mode mode); +static int oacp_checksum(struct bt_conn *conn, struct bt_otc_internal_instance_t *inst, + uint32_t offset, uint32_t len); +static void read_next_metadata(struct bt_conn *conn, + struct bt_otc_internal_instance_t *inst); +static int read_attr(struct bt_conn *conn, + struct bt_otc_internal_instance_t *inst, + uint16_t handle, bt_gatt_read_func_t cb); + +/* L2CAP callbacks */ +static void tx_done(struct bt_gatt_ots_l2cap *l2cap_ctx, + struct bt_conn *conn) +{ + /* Not doing any writes yet */ + LOG_ERR("Unexpected call, context: %p, conn: %p", l2cap_ctx, (void *)conn); +} + +static void write_obj_tx_done(struct bt_gatt_ots_l2cap *l2cap_ctx, + struct bt_conn *conn) +{ + int err; + size_t written; + + if (cur_inst == NULL) { + LOG_ERR("OTS instance invalid"); + return; + } + + written = cur_inst->sent_size; + LOG_DBG("ctx: %p, conn: %p, written: %d", l2cap_ctx, (void *)conn, written); + + err = bt_gatt_ots_l2cap_disconnect(l2cap_ctx); + if (err < 0) { + LOG_WRN("Disconnecting L2CAP returned error %d", err); + } + + if ((cur_inst->otc_inst != NULL) && (cur_inst->otc_inst->cb != NULL)) { + if (cur_inst->otc_inst->cb->obj_data_written) { + cur_inst->otc_inst->cb->obj_data_written(cur_inst->otc_inst, conn, written); + } + } + + cur_inst = NULL; +} + +static ssize_t rx_done(struct bt_gatt_ots_l2cap *l2cap_ctx, + struct bt_conn *conn, struct net_buf *buf) +{ + if (cur_inst == NULL) { + LOG_ERR("OTS instance invalid"); + return -EINVAL; + } + + const uint32_t offset = cur_inst->rcvd_size; + bool is_complete = false; + const struct bt_ots_obj_metadata *cur_object = + &cur_inst->otc_inst->cur_object; + int cb_ret; + + LOG_DBG("Incoming L2CAP data, context: %p, conn: %p, len: %u, offset: %u", l2cap_ctx, + (void *)conn, buf->len, offset); + + cur_inst->rcvd_size += buf->len; + + if (cur_inst->rcvd_size >= cur_object->size.cur) { + is_complete = true; + } + + if (cur_inst->rcvd_size > cur_object->size.cur) { + LOG_WRN("Received %u but expected maximum %u", cur_inst->rcvd_size, + cur_object->size.cur); + } + + if (cur_inst->otc_inst->cb != NULL && cur_inst->otc_inst->cb->obj_data_read != NULL) { + cb_ret = cur_inst->otc_inst->cb->obj_data_read(cur_inst->otc_inst, conn, offset, + buf->len, buf->data, + is_complete); + } else { + LOG_ERR("obj_data_read callback not set"); + return -EINVAL; + } + + if (is_complete) { + const uint32_t rcv_size = cur_object->size.cur; + int err; + + LOG_DBG("Received the whole object (%u bytes). " + "Disconnecting L2CAP CoC", rcv_size); + err = bt_gatt_ots_l2cap_disconnect(l2cap_ctx); + if (err < 0) { + LOG_WRN("Disconnecting L2CAP returned error %d", err); + } + + cur_inst = NULL; + } else if (cb_ret == BT_OTS_STOP) { + const uint32_t rcv_size = cur_object->size.cur; + int err; + + LOG_DBG("Stopped receiving after%u bytes. " + "Disconnecting L2CAP CoC", rcv_size); + err = bt_gatt_ots_l2cap_disconnect(l2cap_ctx); + + if (err < 0) { + LOG_WRN("Disconnecting L2CAP returned error %d", err); + } + + cur_inst = NULL; + } + + return 0; +} + +static void chan_closed(struct bt_gatt_ots_l2cap *l2cap_ctx, + struct bt_conn *conn) +{ + LOG_DBG("L2CAP closed, context: %p, conn: %p", l2cap_ctx, (void *)conn); + if (cur_inst) { + cur_inst = NULL; + } +} +/* End L2CAP callbacks */ + +static void print_oacp_response(enum bt_gatt_ots_oacp_proc_type req_opcode, + enum bt_gatt_ots_oacp_res_code result_code) +{ + if (req_opcode < ARRAY_SIZE(lit_request)) { + LOG_DBG("Request OP Code: %s", lit_request[req_opcode]); + } else { + LOG_DBG("Request OP Code: Unknown (0x%02X)", req_opcode); + } + if (result_code < ARRAY_SIZE(lit_result)) { + LOG_DBG("Result Code : %s", lit_result[result_code]); + } else { + LOG_DBG("Result Code : Unknown (0x%02X)", result_code); + } +} + +static void print_olcp_response(enum bt_gatt_ots_olcp_proc_type req_opcode, + enum bt_gatt_ots_olcp_res_code result_code) +{ + if (req_opcode < ARRAY_SIZE(lit_olcp_request)) { + LOG_DBG("Request OP Code: %s", lit_olcp_request[req_opcode]); + } else { + LOG_DBG("Request OP Code: Unknown (0x%02X)", req_opcode); + } + if (result_code < ARRAY_SIZE(lit_olcp_result)) { + LOG_DBG("Result Code : %s", lit_olcp_result[result_code]); + } else { + LOG_DBG("Result Code : Unknown (0x%02X)", result_code); + } +} + +static void date_time_decode(struct net_buf_simple *buf, + struct bt_ots_date_time *p_date_time) +{ + p_date_time->year = net_buf_simple_pull_le16(buf); + p_date_time->month = net_buf_simple_pull_u8(buf); + p_date_time->day = net_buf_simple_pull_u8(buf); + p_date_time->hours = net_buf_simple_pull_u8(buf); + p_date_time->minutes = net_buf_simple_pull_u8(buf); + p_date_time->seconds = net_buf_simple_pull_u8(buf); +} + +static struct bt_otc_internal_instance_t *lookup_inst_by_handle(uint16_t handle) +{ + for (int i = 0; i < ARRAY_SIZE(otc_insts); i++) { + if (otc_insts[i].otc_inst && + otc_insts[i].otc_inst->start_handle <= handle && + otc_insts[i].otc_inst->end_handle >= handle) { + return &otc_insts[i]; + } + } + + LOG_DBG("Could not find OTS instance with handle 0x%04x", handle); + + return NULL; +} + +static void on_object_selected(struct bt_conn *conn, + enum bt_gatt_ots_olcp_res_code res, + struct bt_ots_client *otc_inst) +{ + memset(&otc_inst->cur_object, 0, sizeof(otc_inst->cur_object)); + otc_inst->cur_object.id = OTS_CLIENT_UNKNOWN_ID; + + if (otc_inst->cb && otc_inst->cb->obj_selected) { + otc_inst->cb->obj_selected(otc_inst, conn, res); + } + + LOG_DBG("Object selected"); +} + +static void olcp_ind_handler(struct bt_conn *conn, + struct bt_ots_client *otc_inst, + const void *data, uint16_t length) +{ + enum bt_gatt_ots_olcp_proc_type op_code; + struct net_buf_simple net_buf; + + if (length < sizeof(op_code)) { + LOG_DBG("Invalid indication length: %u", length); + return; + } + + net_buf_simple_init_with_data(&net_buf, (void *)data, length); + + op_code = net_buf_simple_pull_u8(&net_buf); + + LOG_DBG("OLCP indication"); + + if (op_code == BT_GATT_OTS_OLCP_PROC_RESP) { + if (net_buf.len < (sizeof(uint8_t) + sizeof(uint8_t))) { + LOG_DBG("Invalid indication length for op_code %u: %u", op_code, + net_buf.len); + return; + } + + enum bt_gatt_ots_olcp_proc_type req_opcode = + net_buf_simple_pull_u8(&net_buf); + enum bt_gatt_ots_olcp_res_code result_code = + net_buf_simple_pull_u8(&net_buf); + + print_olcp_response(req_opcode, result_code); + + switch (req_opcode) { + case BT_GATT_OTS_OLCP_PROC_FIRST: + LOG_DBG("First"); + on_object_selected(conn, result_code, otc_inst); + break; + case BT_GATT_OTS_OLCP_PROC_LAST: + LOG_DBG("Last"); + on_object_selected(conn, result_code, otc_inst); + break; + case BT_GATT_OTS_OLCP_PROC_PREV: + LOG_DBG("Previous"); + on_object_selected(conn, result_code, otc_inst); + break; + case BT_GATT_OTS_OLCP_PROC_NEXT: + LOG_DBG("Next"); + on_object_selected(conn, result_code, otc_inst); + break; + case BT_GATT_OTS_OLCP_PROC_GOTO: + LOG_DBG("Goto"); + on_object_selected(conn, result_code, otc_inst); + break; + case BT_GATT_OTS_OLCP_PROC_ORDER: + LOG_DBG("Order"); + on_object_selected(conn, result_code, otc_inst); + break; + case BT_GATT_OTS_OLCP_PROC_REQ_NUM_OBJS: + LOG_DBG("Request number of objects"); + if (net_buf.len == sizeof(uint32_t)) { + uint32_t obj_cnt = + net_buf_simple_pull_le32(&net_buf); + LOG_DBG("Number of objects %u", obj_cnt); + } + break; + case BT_GATT_OTS_OLCP_PROC_CLEAR_MARKING: + LOG_DBG("Clear marking"); + break; + default: + LOG_DBG("Invalid indication req opcode %u", req_opcode); + break; + } + } else { + LOG_DBG("Invalid indication opcode %u", op_code); + } +} + +static void oacp_ind_handler(struct bt_conn *conn, + struct bt_ots_client *otc_inst, + const void *data, uint16_t length) +{ + enum bt_gatt_ots_oacp_proc_type op_code; + enum bt_gatt_ots_oacp_proc_type req_opcode; + enum bt_gatt_ots_oacp_res_code result_code; + uint32_t checksum; + struct net_buf_simple net_buf; + + if (length < sizeof(op_code)) { + LOG_DBG("Invalid indication length: %u", length); + return; + } + + net_buf_simple_init_with_data(&net_buf, (void *)data, length); + + op_code = net_buf_simple_pull_u8(&net_buf); + + LOG_DBG("OACP indication"); + + if (op_code == BT_GATT_OTS_OACP_PROC_RESP) { + if (net_buf.len >= (sizeof(req_opcode) + sizeof(result_code))) { + req_opcode = net_buf_simple_pull_u8(&net_buf); + result_code = net_buf_simple_pull_u8(&net_buf); + } else { + LOG_ERR("Invalid indication data len %u", net_buf.len); + return; + } + + if (req_opcode == BT_GATT_OTS_OACP_PROC_CHECKSUM_CALC) { + if (net_buf.len == sizeof(checksum)) { + checksum = net_buf_simple_pull_le32(&net_buf); + LOG_DBG("Object checksum 0x%08x", checksum); + if (otc_inst->cb && otc_inst->cb->obj_checksum_calculated) { + otc_inst->cb->obj_checksum_calculated( + otc_inst, conn, result_code, checksum); + } + } else { + LOG_ERR("Invalid indication data len %u after opcode and result " + "pulled", net_buf.len); + return; + } + } + + print_oacp_response(req_opcode, result_code); + } else { + LOG_DBG("Invalid indication opcode %u", op_code); + } +} + +uint8_t bt_ots_client_indicate_handler(struct bt_conn *conn, + struct bt_gatt_subscribe_params *params, + const void *data, uint16_t length) +{ + uint16_t handle = params->value_handle; + struct bt_otc_internal_instance_t *inst; + + if (conn == NULL) { + return BT_GATT_ITER_CONTINUE; + } + + inst = lookup_inst_by_handle(handle); + + /* TODO: Can we somehow avoid exposing this + * callback via the public API? + */ + + if (!inst) { + LOG_ERR("Instance not found"); + return BT_GATT_ITER_STOP; + } + + inst->busy = false; + + if (data) { + if (handle == inst->otc_inst->olcp_handle) { + olcp_ind_handler(conn, inst->otc_inst, data, length); + } else if (handle == inst->otc_inst->oacp_handle) { + oacp_ind_handler(conn, inst->otc_inst, data, length); + } + } + return BT_GATT_ITER_CONTINUE; +} + +static uint8_t read_feature_cb(struct bt_conn *conn, uint8_t err, + struct bt_gatt_read_params *params, + const void *data, uint16_t length) +{ + uint8_t cb_err = err; + struct bt_otc_internal_instance_t *inst = + lookup_inst_by_handle(params->single.handle); + struct net_buf_simple net_buf; + + ARG_UNUSED(cb_err); + + net_buf_simple_init_with_data(&net_buf, (void *)data, length); + + if (!inst) { + LOG_ERR("Instance not found"); + return BT_GATT_ITER_STOP; + } + + inst->busy = false; + + if (err) { + LOG_DBG("err: 0x%02X", err); + } else if (data) { + if (length == OTS_FEATURE_LEN) { + inst->otc_inst->features.oacp = + net_buf_simple_pull_le32(&net_buf); + + inst->otc_inst->features.olcp = + net_buf_simple_pull_le32(&net_buf); + + LOG_DBG("features : oacp 0x%x, olcp 0x%x", inst->otc_inst->features.oacp, + inst->otc_inst->features.olcp); + } else { + LOG_DBG("Invalid length %u (expected %u)", length, OTS_FEATURE_LEN); + cb_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN; + } + } + + return BT_GATT_ITER_STOP; +} + +int bt_ots_client_register(struct bt_ots_client *otc_inst) +{ + for (int i = 0; i < ARRAY_SIZE(otc_insts); i++) { + int err; + + if (otc_insts[i].otc_inst) { + continue; + } + + LOG_DBG("%u", i); + err = bt_gatt_ots_l2cap_register(&otc_insts[i].l2cap_ctx); + if (err) { + LOG_WRN("Could not register L2CAP context %d", err); + return err; + } + + otc_insts[i].otc_inst = otc_inst; + return 0; + } + + return -ENOMEM; +} + +int bt_ots_client_unregister(uint8_t index) +{ + if (index < ARRAY_SIZE(otc_insts)) { + bt_gatt_ots_l2cap_unregister(&otc_insts[index].l2cap_ctx); + memset(&otc_insts[index], 0, sizeof(otc_insts[index])); + } else { + return -EINVAL; + } + + return 0; +} + +int bt_ots_client_read_feature(struct bt_ots_client *otc_inst, + struct bt_conn *conn) +{ + if (OTS_CLIENT_INST_COUNT > 0) { + struct bt_otc_internal_instance_t *inst; + int err; + + if (!conn) { + LOG_WRN("Invalid Connection"); + return -ENOTCONN; + } else if (!otc_inst) { + LOG_ERR("Invalid OTC instance"); + return -EINVAL; + } else if (!otc_inst->feature_handle) { + LOG_DBG("Handle not set"); + return -EINVAL; + } + + inst = lookup_inst_by_handle(otc_inst->start_handle); + + if (!inst) { + LOG_ERR("Invalid OTC instance"); + return -EINVAL; + } else if (inst->busy) { + return -EBUSY; + } + + otc_inst->read_proc.func = read_feature_cb; + otc_inst->read_proc.handle_count = 1; + otc_inst->read_proc.single.handle = otc_inst->feature_handle; + otc_inst->read_proc.single.offset = 0U; + + err = bt_gatt_read(conn, &otc_inst->read_proc); + if (!err) { + inst->busy = true; + } + return err; + } + + LOG_DBG("Not supported"); + return -EOPNOTSUPP; +} + +static void write_olcp_cb(struct bt_conn *conn, uint8_t err, + struct bt_gatt_write_params *params) +{ + struct bt_otc_internal_instance_t *inst = + lookup_inst_by_handle(params->handle); + + LOG_DBG("Write %s (0x%02X)", err ? "failed" : "successful", err); + + if (!inst) { + LOG_ERR("Instance not found"); + return; + } + + inst->busy = false; +} + +static int write_olcp(struct bt_otc_internal_instance_t *inst, + struct bt_conn *conn, enum bt_gatt_ots_olcp_proc_type opcode, + uint8_t *params, uint8_t param_len) +{ + int err; + + net_buf_simple_reset(&otc_tx_buf); + + net_buf_simple_add_u8(&otc_tx_buf, opcode); + + if (param_len && params) { + net_buf_simple_add_mem(&otc_tx_buf, params, param_len); + } + + inst->otc_inst->write_params.offset = 0; + inst->otc_inst->write_params.data = otc_tx_buf.data; + inst->otc_inst->write_params.length = otc_tx_buf.len; + inst->otc_inst->write_params.handle = inst->otc_inst->olcp_handle; + inst->otc_inst->write_params.func = write_olcp_cb; + + err = bt_gatt_write(conn, &inst->otc_inst->write_params); + + if (!err) { + inst->busy = true; + } + return err; +} + +int bt_ots_client_select_id(struct bt_ots_client *otc_inst, + struct bt_conn *conn, + uint64_t obj_id) +{ + CHECKIF(!BT_OTS_VALID_OBJ_ID(obj_id)) { + LOG_DBG("Invalid object ID 0x%016llx", obj_id); + + return -EINVAL; + } + + if (OTS_CLIENT_INST_COUNT > 0) { + struct bt_otc_internal_instance_t *inst; + uint8_t param[BT_OTS_OBJ_ID_SIZE]; + + if (!conn) { + LOG_WRN("Invalid Connection"); + return -ENOTCONN; + } else if (!otc_inst) { + LOG_ERR("Invalid OTC instance"); + return -EINVAL; + } else if (!otc_inst->olcp_handle) { + LOG_DBG("Handle not set"); + return -EINVAL; + } + + inst = lookup_inst_by_handle(otc_inst->start_handle); + + if (!inst) { + LOG_ERR("Invalid OTC instance"); + return -EINVAL; + } else if (inst->busy) { + return -EBUSY; + } + + /* TODO: Should not update this before ID is read */ + otc_inst->cur_object.id = obj_id; + sys_put_le48(obj_id, param); + + return write_olcp(inst, conn, BT_GATT_OTS_OLCP_PROC_GOTO, + param, BT_OTS_OBJ_ID_SIZE); + } + + LOG_DBG("Not supported"); + return -EOPNOTSUPP; +} + +int bt_ots_client_select_first(struct bt_ots_client *otc_inst, + struct bt_conn *conn) +{ + if (OTS_CLIENT_INST_COUNT > 0) { + struct bt_otc_internal_instance_t *inst; + + if (!conn) { + LOG_WRN("Invalid Connection"); + return -ENOTCONN; + } else if (!otc_inst) { + LOG_ERR("Invalid OTC instance"); + return -EINVAL; + } else if (!otc_inst->olcp_handle) { + LOG_DBG("Handle not set"); + return -EINVAL; + } + + inst = lookup_inst_by_handle(otc_inst->start_handle); + + if (!inst) { + LOG_ERR("Invalid OTC instance"); + return -EINVAL; + } else if (inst->busy) { + return -EBUSY; + } + + return write_olcp(inst, conn, BT_GATT_OTS_OLCP_PROC_FIRST, + NULL, 0); + } + + LOG_DBG("Not supported"); + return -EOPNOTSUPP; +} + +int bt_ots_client_select_last(struct bt_ots_client *otc_inst, + struct bt_conn *conn) +{ + if (OTS_CLIENT_INST_COUNT > 0) { + struct bt_otc_internal_instance_t *inst; + + if (!conn) { + LOG_WRN("Invalid Connection"); + return -ENOTCONN; + } else if (!otc_inst) { + LOG_ERR("Invalid OTC instance"); + return -EINVAL; + } else if (!otc_inst->olcp_handle) { + LOG_DBG("Handle not set"); + return -EINVAL; + } + + inst = lookup_inst_by_handle(otc_inst->start_handle); + + if (!inst) { + LOG_ERR("Invalid OTC instance"); + return -EINVAL; + } else if (inst->busy) { + return -EBUSY; + } + + return write_olcp(inst, conn, BT_GATT_OTS_OLCP_PROC_LAST, + NULL, 0); + + } + + LOG_DBG("Not supported"); + return -EOPNOTSUPP; +} + +int bt_ots_client_select_next(struct bt_ots_client *otc_inst, + struct bt_conn *conn) +{ + if (OTS_CLIENT_INST_COUNT > 0) { + struct bt_otc_internal_instance_t *inst; + + if (!conn) { + LOG_WRN("Invalid Connection"); + return -ENOTCONN; + } else if (!otc_inst) { + LOG_ERR("Invalid OTC instance"); + return -EINVAL; + } else if (!otc_inst->olcp_handle) { + LOG_DBG("Handle not set"); + return -EINVAL; + } + + inst = lookup_inst_by_handle(otc_inst->start_handle); + + if (!inst) { + LOG_ERR("Invalid OTC instance"); + return -EINVAL; + } else if (inst->busy) { + return -EBUSY; + } + + return write_olcp(inst, conn, BT_GATT_OTS_OLCP_PROC_NEXT, + NULL, 0); + } + + LOG_DBG("Not supported"); + return -EOPNOTSUPP; +} + +int bt_ots_client_select_prev(struct bt_ots_client *otc_inst, + struct bt_conn *conn) +{ + if (OTS_CLIENT_INST_COUNT > 0) { + struct bt_otc_internal_instance_t *inst; + + if (!conn) { + LOG_WRN("Invalid Connection"); + return -ENOTCONN; + } else if (!otc_inst) { + LOG_ERR("Invalid OTC instance"); + return -EINVAL; + } else if (!otc_inst->olcp_handle) { + LOG_DBG("Handle not set"); + return -EINVAL; + } + + inst = lookup_inst_by_handle(otc_inst->start_handle); + + if (!inst) { + LOG_ERR("Invalid OTC instance"); + return -EINVAL; + } else if (inst->busy) { + return -EBUSY; + } + + return write_olcp(inst, conn, BT_GATT_OTS_OLCP_PROC_PREV, + NULL, 0); + } + + LOG_DBG("Not supported"); + return -EOPNOTSUPP; +} + +static uint8_t read_object_size_cb(struct bt_conn *conn, uint8_t err, + struct bt_gatt_read_params *params, + const void *data, uint16_t length) +{ + struct bt_otc_internal_instance_t *inst = + lookup_inst_by_handle(params->single.handle); + struct net_buf_simple net_buf; + + net_buf_simple_init_with_data(&net_buf, (void *)data, length); + + LOG_DBG("handle %d, length %u", params->single.handle, length); + + if (!inst) { + LOG_ERR("Instance not found"); + return BT_GATT_ITER_STOP; + } + + if (err) { + LOG_DBG("err: 0x%02X", err); + } else if (data) { + if (length != OTS_SIZE_LEN) { + LOG_DBG("Invalid length %u (expected %u)", length, OTS_SIZE_LEN); + err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN; + } else { + struct bt_ots_obj_metadata *cur_object = + &inst->otc_inst->cur_object; + cur_object->size.cur = + net_buf_simple_pull_le32(&net_buf); + cur_object->size.alloc = + net_buf_simple_pull_le32(&net_buf); + + LOG_DBG("Object Size : current size %u, " + "allocated size %u", + cur_object->size.cur, + cur_object->size.alloc); + + if (cur_object->size.cur == 0) { + LOG_WRN("Obj size read returned a current " + "size of 0"); + } else if (cur_object->size.cur > + cur_object->size.alloc && + cur_object->size.alloc != 0) { + LOG_WRN("Allocated size %u is smaller than " + "current size %u", + cur_object->size.alloc, + cur_object->size.cur); + } + + BT_OTS_SET_METADATA_REQ_SIZE(inst->metadata_read); + } + } + + if (err) { + LOG_WRN("err: 0x%02X", err); + if (!inst->metadata_err) { + inst->metadata_err = err; + } + } + + read_next_metadata(conn, inst); + + return BT_GATT_ITER_STOP; +} + +static uint8_t read_obj_id_cb(struct bt_conn *conn, uint8_t err, + struct bt_gatt_read_params *params, + const void *data, uint16_t length) +{ + struct bt_otc_internal_instance_t *inst = + lookup_inst_by_handle(params->single.handle); + struct net_buf_simple net_buf; + + net_buf_simple_init_with_data(&net_buf, (void *)data, length); + + LOG_DBG("handle %d, length %u", params->single.handle, length); + + if (!inst) { + LOG_ERR("Instance not found"); + return BT_GATT_ITER_STOP; + } + + if (err) { + LOG_DBG("err: 0x%02X", err); + } else if (data) { + if (length == BT_OTS_OBJ_ID_SIZE) { + uint64_t obj_id = net_buf_simple_pull_le48(&net_buf); + char t[BT_OTS_OBJ_ID_STR_LEN]; + struct bt_ots_obj_metadata *cur_object = + &inst->otc_inst->cur_object; + + (void)bt_ots_obj_id_to_str(obj_id, t, sizeof(t)); + LOG_DBG("Object Id : %s", t); + + if (cur_object->id != OTS_CLIENT_UNKNOWN_ID && + cur_object->id != obj_id) { + char str[BT_OTS_OBJ_ID_STR_LEN]; + + (void)bt_ots_obj_id_to_str(cur_object->id, str, + sizeof(str)); + LOG_INF("Read Obj Id %s not selected obj Id %s", t, str); + } else { + LOG_INF("Read Obj Id confirmed correct Obj Id"); + cur_object->id = obj_id; + + BT_OTS_SET_METADATA_REQ_ID(inst->metadata_read); + } + } else { + LOG_DBG("Invalid length %u (expected %u)", length, BT_OTS_OBJ_ID_SIZE); + err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN; + } + } + + if (err) { + LOG_WRN("err: 0x%02X", err); + if (!inst->metadata_err) { + inst->metadata_err = err; + } + } + + read_next_metadata(conn, inst); + + return BT_GATT_ITER_STOP; +} + +static uint8_t read_obj_name_cb(struct bt_conn *conn, uint8_t err, + struct bt_gatt_read_params *params, + const void *data, uint16_t length) +{ + struct bt_otc_internal_instance_t *inst = + lookup_inst_by_handle(params->single.handle); + + LOG_DBG("handle %d, length %u", params->single.handle, length); + + if (!inst) { + LOG_ERR("Instance not found"); + return BT_GATT_ITER_STOP; + } + + if (data) { + if (length <= CONFIG_BT_OTS_OBJ_MAX_NAME_LEN) { + memcpy(inst->otc_inst->cur_object.name_c, data, length); + inst->otc_inst->cur_object.name_c[length] = '\0'; + + BT_OTS_SET_METADATA_REQ_NAME(inst->metadata_read); + } else { + LOG_WRN("Invalid length %u (expected max %u)", length, + CONFIG_BT_OTS_OBJ_MAX_NAME_LEN); + err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN; + } + } + + if (err) { + LOG_WRN("err: 0x%02X", err); + if (!inst->metadata_err) { + inst->metadata_err = err; + } + } + + read_next_metadata(conn, inst); + + return BT_GATT_ITER_STOP; +} + +static uint8_t read_obj_type_cb(struct bt_conn *conn, uint8_t err, + struct bt_gatt_read_params *params, + const void *data, uint16_t length) +{ + struct bt_otc_internal_instance_t *inst = + lookup_inst_by_handle(params->single.handle); + + LOG_DBG("handle %d, length %u", params->single.handle, length); + + if (!inst) { + LOG_ERR("Instance not found"); + return BT_GATT_ITER_STOP; + } + + if (data) { + if (length == BT_UUID_SIZE_128 || length == BT_UUID_SIZE_16) { + char uuid_str[BT_UUID_STR_LEN]; + struct bt_uuid *uuid = + &inst->otc_inst->cur_object.type.uuid; + + if (!bt_uuid_create(uuid, data, length)) { + LOG_WRN("Failed to create UUID from data"); + err = BT_ATT_ERR_UNLIKELY; + } else { + bt_uuid_to_str(uuid, uuid_str, sizeof(uuid_str)); + LOG_DBG("UUID type read: %s", uuid_str); + + BT_OTS_SET_METADATA_REQ_TYPE(inst->metadata_read); + } + } else { + LOG_WRN("Invalid length %u (expected max %u)", length, OTS_TYPE_MAX_LEN); + err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN; + } + } + + if (err) { + LOG_WRN("err: 0x%02X", err); + if (!inst->metadata_err) { + inst->metadata_err = err; + } + } + + read_next_metadata(conn, inst); + + return BT_GATT_ITER_STOP; +} + +static uint8_t read_obj_created_cb(struct bt_conn *conn, uint8_t err, + struct bt_gatt_read_params *params, + const void *data, uint16_t length) +{ + struct bt_otc_internal_instance_t *inst = + lookup_inst_by_handle(params->single.handle); + struct net_buf_simple net_buf; + + net_buf_simple_init_with_data(&net_buf, (void *)data, length); + + LOG_DBG("handle %d, length %u", params->single.handle, length); + + if (!inst) { + LOG_ERR("Instance not found"); + return BT_GATT_ITER_STOP; + } + + if (data) { + if (length == BT_OTS_DATE_TIME_FIELD_SIZE) { + date_time_decode( + &net_buf, + &inst->otc_inst->cur_object.first_created); + } else { + LOG_WRN("Invalid length %u (expected max %u)", length, + BT_OTS_DATE_TIME_FIELD_SIZE); + err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN; + } + } + + if (err) { + LOG_WRN("err: 0x%02X", err); + if (!inst->metadata_err) { + inst->metadata_err = err; + } + } + + read_next_metadata(conn, inst); + + return BT_GATT_ITER_STOP; +} + +static uint8_t read_obj_modified_cb(struct bt_conn *conn, uint8_t err, + struct bt_gatt_read_params *params, + const void *data, uint16_t length) +{ + struct bt_otc_internal_instance_t *inst = + lookup_inst_by_handle(params->single.handle); + struct net_buf_simple net_buf; + + net_buf_simple_init_with_data(&net_buf, (void *)data, length); + + LOG_DBG("handle %d, length %u", params->single.handle, length); + + if (!inst) { + LOG_ERR("Instance not found"); + return BT_GATT_ITER_STOP; + } + + if (data) { + if (length == BT_OTS_DATE_TIME_FIELD_SIZE) { + date_time_decode(&net_buf, + &inst->otc_inst->cur_object.modified); + } else { + LOG_WRN("Invalid length %u (expected max %u)", length, + BT_OTS_DATE_TIME_FIELD_SIZE); + err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN; + } + } + + if (err) { + LOG_WRN("err: 0x%02X", err); + if (!inst->metadata_err) { + inst->metadata_err = err; + } + } + + read_next_metadata(conn, inst); + + return BT_GATT_ITER_STOP; +} + +static int read_attr(struct bt_conn *conn, + struct bt_otc_internal_instance_t *inst, + uint16_t handle, bt_gatt_read_func_t cb) +{ + if (!handle) { + LOG_DBG("Handle not set"); + return -EINVAL; + } else if (cb == NULL) { + LOG_ERR("No callback set"); + return -EINVAL; + } + + /* TODO: With EATT we can request multiple metadata to be read at once*/ + inst->otc_inst->read_proc.func = cb; + inst->otc_inst->read_proc.handle_count = 1; + inst->otc_inst->read_proc.single.handle = handle; + inst->otc_inst->read_proc.single.offset = 0; + + return bt_gatt_read(conn, &inst->otc_inst->read_proc); +} + +static uint8_t read_obj_properties_cb(struct bt_conn *conn, uint8_t err, + struct bt_gatt_read_params *params, + const void *data, uint16_t length) +{ + uint8_t cb_err = err; + struct bt_otc_internal_instance_t *inst = + lookup_inst_by_handle(params->single.handle); + struct net_buf_simple net_buf; + + net_buf_simple_init_with_data(&net_buf, (void *)data, length); + + LOG_INF("handle %d, length %u", params->single.handle, length); + + if (!inst) { + LOG_ERR("Instance not found"); + return BT_GATT_ITER_STOP; + } + + if (err) { + LOG_WRN("err: 0x%02X", err); + } else if (data && length == OTS_PROPERTIES_LEN) { + struct bt_ots_obj_metadata *cur_object = + &inst->otc_inst->cur_object; + + cur_object->props = net_buf_simple_pull_le32(&net_buf); + + LOG_INF("Object properties (raw) : 0x%x", cur_object->props); + + if (!BT_OTS_OBJ_GET_PROP_READ(cur_object->props)) { + LOG_WRN("Obj properties: Obj read not supported"); + } + + BT_OTS_SET_METADATA_REQ_PROPS(inst->metadata_read); + } else { + LOG_WRN("Invalid length %u (expected %u)", length, OTS_PROPERTIES_LEN); + cb_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN; + } + + if (cb_err) { + LOG_WRN("err: 0x%02X", cb_err); + if (!inst->metadata_err) { + inst->metadata_err = cb_err; + } + } + + read_next_metadata(conn, inst); + + return BT_GATT_ITER_STOP; +} + +static void write_oacp_cp_cb(struct bt_conn *conn, uint8_t err, + struct bt_gatt_write_params *params) +{ + struct bt_otc_internal_instance_t *inst = + lookup_inst_by_handle(params->handle); + + LOG_DBG("Write %s (0x%02X)", err ? "failed" : "successful", err); + + if (!inst) { + LOG_ERR("Instance not found"); + return; + } + + inst->busy = false; +} + +static void write_oacp_cp_write_req_cb(struct bt_conn *conn, uint8_t err, + struct bt_gatt_write_params *params) +{ + struct bt_otc_internal_instance_t *inst = + lookup_inst_by_handle(params->handle); + uint32_t len; + + LOG_DBG("Write Object request %s (0x%02X)", err ? "failed" : "successful", err); + if (!inst) { + LOG_ERR("Instance not found"); + return; + } + + if (err) { + LOG_WRN("OACP Write request failed (0x%02X), aborting L2CAP send", err); + inst->busy = false; + cur_inst = NULL; + return; + } + + len = inst->l2cap_ctx.tx.len; + inst->l2cap_ctx.tx.len = 0; + err = bt_gatt_ots_l2cap_send(&inst->l2cap_ctx, inst->l2cap_ctx.tx.data, len); + if (err) { + LOG_WRN("L2CAP CoC error: %d while trying to execute OACP " + "Write procedure", err); + cur_inst = NULL; + } + + inst->busy = false; +} + +static int oacp_read(struct bt_conn *conn, + struct bt_otc_internal_instance_t *inst) +{ + int err; + uint32_t offset = 0; + uint32_t length; + struct bt_gatt_ots_l2cap *l2cap; + + if (!inst->otc_inst->oacp_handle) { + LOG_DBG("Handle not set"); + return -EINVAL; + } else if (inst->busy) { + return -EBUSY; + } else if (cur_inst) { + return -EBUSY; + } + + /* TODO: How do we ensure that the L2CAP is connected in time for the + * transfer? + */ + + err = bt_gatt_ots_l2cap_connect(conn, &l2cap); + if (err) { + LOG_DBG("Could not connect l2cap: %d", err); + return err; + } + + l2cap->tx_done = tx_done; + l2cap->rx_done = rx_done; + l2cap->closed = chan_closed; + + net_buf_simple_reset(&otc_tx_buf); + + /* OP Code */ + net_buf_simple_add_u8(&otc_tx_buf, BT_GATT_OTS_OACP_PROC_READ); + + /* Offset */ + net_buf_simple_add_le32(&otc_tx_buf, offset); + + /* Len */ + length = inst->otc_inst->cur_object.size.cur - offset; + net_buf_simple_add_le32(&otc_tx_buf, length); + + inst->otc_inst->write_params.offset = 0; + inst->otc_inst->write_params.data = otc_tx_buf.data; + inst->otc_inst->write_params.length = otc_tx_buf.len; + inst->otc_inst->write_params.handle = inst->otc_inst->oacp_handle; + inst->otc_inst->write_params.func = write_oacp_cp_cb; + + err = bt_gatt_write(conn, &inst->otc_inst->write_params); + + if (!err) { + inst->busy = true; + cur_inst = inst; + } + + inst->rcvd_size = 0; + + return err; +} + +static int oacp_write(struct bt_conn *conn, struct bt_otc_internal_instance_t *inst, + const void *buf, uint32_t len, uint32_t offset, + enum bt_ots_oacp_write_op_mode mode) +{ + int err; + struct bt_gatt_ots_l2cap *l2cap; + + if (!inst->otc_inst->oacp_handle) { + LOG_DBG("Handle not set"); + return -EINVAL; + } else if (inst->busy) { + return -EBUSY; + } else if (cur_inst) { + return -EBUSY; + } + + err = bt_gatt_ots_l2cap_connect(conn, &l2cap); + if (err) { + LOG_DBG("Could not connect l2cap: %d", err); + return err; + } + + l2cap->tx_done = write_obj_tx_done; + l2cap->rx_done = rx_done; + l2cap->closed = chan_closed; + l2cap->tx.data = (uint8_t *)buf; + l2cap->tx.len = len; + net_buf_simple_reset(&otc_tx_buf); + + /* OP Code */ + net_buf_simple_add_u8(&otc_tx_buf, BT_GATT_OTS_OACP_PROC_WRITE); + + /* Offset */ + net_buf_simple_add_le32(&otc_tx_buf, offset); + + /* Len */ + net_buf_simple_add_le32(&otc_tx_buf, len); + + /* Mode, truncate or not */ + net_buf_simple_add_u8(&otc_tx_buf, mode); + + inst->otc_inst->write_params.offset = 0; + inst->otc_inst->write_params.data = otc_tx_buf.data; + inst->otc_inst->write_params.length = otc_tx_buf.len; + inst->otc_inst->write_params.handle = inst->otc_inst->oacp_handle; + inst->otc_inst->write_params.func = write_oacp_cp_write_req_cb; + inst->sent_size = len; + err = bt_gatt_write(conn, &inst->otc_inst->write_params); + + if (!err) { + inst->busy = true; + cur_inst = inst; + } + + inst->rcvd_size = 0; + + return err; +} + +static int oacp_checksum(struct bt_conn *conn, struct bt_otc_internal_instance_t *inst, + uint32_t offset, uint32_t len) +{ + int err; + + if (!inst->otc_inst->oacp_handle) { + LOG_DBG("Handle not set"); + return -EINVAL; + } else if (inst->busy) { + LOG_DBG("Client is busy"); + return -EBUSY; + } else if (cur_inst) { + LOG_DBG("Previous operation is not finished"); + return -EBUSY; + } + + net_buf_simple_reset(&otc_tx_buf); + + /* OP Code */ + net_buf_simple_add_u8(&otc_tx_buf, BT_GATT_OTS_OACP_PROC_CHECKSUM_CALC); + + /* Offset */ + net_buf_simple_add_le32(&otc_tx_buf, offset); + + /* Len */ + net_buf_simple_add_le32(&otc_tx_buf, len); + + inst->otc_inst->write_params.offset = 0; + inst->otc_inst->write_params.data = otc_tx_buf.data; + inst->otc_inst->write_params.length = otc_tx_buf.len; + inst->otc_inst->write_params.handle = inst->otc_inst->oacp_handle; + inst->otc_inst->write_params.func = write_oacp_cp_cb; + + err = bt_gatt_write(conn, &inst->otc_inst->write_params); + if (!err) { + inst->busy = true; + cur_inst = inst; + } + + return err; +} + +int bt_ots_client_read_object_data(struct bt_ots_client *otc_inst, + struct bt_conn *conn) +{ + struct bt_otc_internal_instance_t *inst; + + if (!conn) { + LOG_WRN("Invalid Connection"); + return -ENOTCONN; + } else if (!otc_inst) { + LOG_ERR("Invalid OTC instance"); + return -EINVAL; + } + + inst = lookup_inst_by_handle(otc_inst->start_handle); + + if (!inst) { + LOG_ERR("Invalid OTC instance"); + return -EINVAL; + } + + if (otc_inst->cur_object.size.cur == 0) { + LOG_WRN("Unknown object size"); + return -EINVAL; + } + + return oacp_read(conn, inst); +} + +int bt_ots_client_write_object_data(struct bt_ots_client *otc_inst, + struct bt_conn *conn, const void *buf, size_t len, + off_t offset, enum bt_ots_oacp_write_op_mode mode) +{ + struct bt_otc_internal_instance_t *inst; + + CHECKIF(!conn) { + LOG_WRN("Invalid Connection"); + return -ENOTCONN; + } + + CHECKIF(!otc_inst) { + LOG_ERR("Invalid OTC instance"); + return -EINVAL; + } + + CHECKIF((mode != BT_OTS_OACP_WRITE_OP_MODE_NONE) && + (mode != BT_OTS_OACP_WRITE_OP_MODE_TRUNCATE)) { + LOG_ERR("Invalid write object mode parameter %d", mode); + return -EINVAL; + } + + /* OTS_v10.pdf Table 3.9: Object Action Control Point Procedure Requirements + * Offset and Length field are UINT32 Length + */ + CHECKIF(len > UINT32_MAX) { + LOG_ERR("length %zu exceeds UINT32", len); + return -EINVAL; + } + + CHECKIF(len == 0) { + LOG_ERR("length equals zero"); + return -EINVAL; + } + + CHECKIF((sizeof(offset) > sizeof(uint32_t) && (offset > UINT32_MAX)) || (offset < 0)) { + LOG_ERR("offset %ld exceeds UINT32 and must be >= 0", offset); + return -EINVAL; + } + + CHECKIF(offset > otc_inst->cur_object.size.cur) { + LOG_ERR("offset %ld exceeds cur size %zu", offset, otc_inst->cur_object.size.cur); + return -EINVAL; + } + + CHECKIF((offset < otc_inst->cur_object.size.cur) && + !BT_OTS_OBJ_GET_PROP_PATCH(otc_inst->cur_object.props)) { + LOG_ERR("Patch is not supported"); + return -EACCES; + } + + CHECKIF(((uint64_t)len + (uint64_t)offset > otc_inst->cur_object.size.alloc) && + !BT_OTS_OBJ_GET_PROP_APPEND(otc_inst->cur_object.props)) { + LOG_ERR("APPEND is not supported. Invalid new end of object %lu alloc %zu." + , (len + offset), otc_inst->cur_object.size.alloc); + return -EINVAL; + } + + inst = lookup_inst_by_handle(otc_inst->start_handle); + + if (!inst) { + LOG_ERR("Invalid OTC instance"); + return -EINVAL; + } + + return oacp_write(conn, inst, buf, (uint32_t)len, (uint32_t)offset, mode); +} + +int bt_ots_client_get_object_checksum(struct bt_ots_client *otc_inst, struct bt_conn *conn, + off_t offset, size_t len) +{ + struct bt_otc_internal_instance_t *inst; + + CHECKIF(!conn) { + LOG_DBG("Invalid Connection"); + return -ENOTCONN; + } + + CHECKIF(!otc_inst) { + LOG_DBG("Invalid OTC instance"); + return -EINVAL; + } + + /* OTS_v10.pdf Table 3.9: Object Action Control Point Procedure Requirements + * Offset and Length field are UINT32 Length + */ + CHECKIF(len > UINT32_MAX) { + LOG_DBG("length %zu exceeds UINT32", len); + return -EINVAL; + } + + CHECKIF(len == 0) { + LOG_DBG("length equals zero"); + return -EINVAL; + } + + CHECKIF((sizeof(offset) > sizeof(uint32_t) && (offset > UINT32_MAX)) || (offset < 0)) { + LOG_DBG("offset exceeds %ld UINT32 and must be >= 0", offset); + return -EINVAL; + } + + CHECKIF((len + offset) > otc_inst->cur_object.size.cur) { + LOG_DBG("The sum of offset (%ld) and length (%zu) equals %lu which exceeds " + "the Current Size %zu.", offset, len, (len + offset), otc_inst->cur_object.size.cur); + return -EINVAL; + } + + inst = lookup_inst_by_handle(otc_inst->start_handle); + if (!inst) { + LOG_DBG("Invalid OTC instance"); + return -EINVAL; + } + + return oacp_checksum(conn, inst, (uint32_t)offset, (uint32_t)len); +} + +static void read_next_metadata(struct bt_conn *conn, + struct bt_otc_internal_instance_t *inst) +{ + uint8_t metadata_remaining = + inst->metadata_to_read ^ inst->metadata_read_attempted; + int err = 0; + + LOG_DBG("Attempting to read metadata 0x%02X", metadata_remaining); + + if (BT_OTS_GET_METADATA_REQ_NAME(metadata_remaining)) { + BT_OTS_SET_METADATA_REQ_NAME(inst->metadata_read_attempted); + err = read_attr(conn, inst, inst->otc_inst->obj_name_handle, + read_obj_name_cb); + } else if (BT_OTS_GET_METADATA_REQ_TYPE(metadata_remaining)) { + BT_OTS_SET_METADATA_REQ_TYPE(inst->metadata_read_attempted); + err = read_attr(conn, inst, inst->otc_inst->obj_type_handle, + read_obj_type_cb); + } else if (BT_OTS_GET_METADATA_REQ_SIZE(metadata_remaining)) { + BT_OTS_SET_METADATA_REQ_SIZE(inst->metadata_read_attempted); + err = read_attr(conn, inst, inst->otc_inst->obj_size_handle, + read_object_size_cb); + } else if (BT_OTS_GET_METADATA_REQ_CREATED(metadata_remaining)) { + BT_OTS_SET_METADATA_REQ_CREATED(inst->metadata_read_attempted); + err = read_attr(conn, inst, inst->otc_inst->obj_created_handle, + read_obj_created_cb); + } else if (BT_OTS_GET_METADATA_REQ_MODIFIED(metadata_remaining)) { + BT_OTS_SET_METADATA_REQ_MODIFIED(inst->metadata_read_attempted); + err = read_attr(conn, inst, inst->otc_inst->obj_modified_handle, + read_obj_modified_cb); + } else if (BT_OTS_GET_METADATA_REQ_ID(metadata_remaining)) { + BT_OTS_SET_METADATA_REQ_ID(inst->metadata_read_attempted); + err = read_attr(conn, inst, inst->otc_inst->obj_id_handle, + read_obj_id_cb); + } else if (BT_OTS_GET_METADATA_REQ_PROPS(metadata_remaining)) { + BT_OTS_SET_METADATA_REQ_PROPS(inst->metadata_read_attempted); + err = read_attr(conn, inst, + inst->otc_inst->obj_properties_handle, + read_obj_properties_cb); + } else { + inst->busy = false; + if (inst->otc_inst->cb->obj_metadata_read) { + inst->otc_inst->cb->obj_metadata_read( + inst->otc_inst, conn, inst->metadata_err, + inst->metadata_read); + } + return; + } + + if (err) { + LOG_DBG("Metadata read failed (%d), trying next", err); + read_next_metadata(conn, inst); + } +} + +int bt_ots_client_read_object_metadata(struct bt_ots_client *otc_inst, + struct bt_conn *conn, + uint8_t metadata) +{ + struct bt_otc_internal_instance_t *inst; + + if (!conn) { + LOG_WRN("Invalid Connection"); + return -ENOTCONN; + } else if (!otc_inst) { + LOG_ERR("Invalid OTC instance"); + return -EINVAL; + } else if (!metadata) { + LOG_WRN("No metadata to read"); + return -ENOEXEC; + } + + inst = lookup_inst_by_handle(otc_inst->start_handle); + + if (!inst) { + LOG_ERR("Invalid OTC instance"); + return -EINVAL; + } else if (inst->busy) { + return -EBUSY; + } + + inst->metadata_read = 0; + inst->metadata_to_read = metadata & BT_OTS_METADATA_REQ_ALL; + inst->metadata_read_attempted = 0; + inst->metadata_err = 0; + + inst->busy = true; + read_next_metadata(conn, inst); + + return 0; +} + +static int decode_record(struct net_buf_simple *buf, + struct dirlisting_record_t *rec) +{ + uint16_t start_len = buf->len; + + rec->len = net_buf_simple_pull_le16(buf); + + if (rec->len < 2 || rec->len > start_len) { + LOG_WRN("incorrect DirListing record length %u, " + "longer than remaining size %u", + rec->len, start_len); + return -EINVAL; + } + + if ((start_len - buf->len) + BT_OTS_OBJ_ID_SIZE > rec->len) { + LOG_WRN("incorrect DirListing record, reclen %u too short, " + "includes only record length", + rec->len); + return -EINVAL; + } + + rec->metadata.id = net_buf_simple_pull_le48(buf); + + if (IS_ENABLED(CONFIG_BT_OTS_CLIENT_LOG_LEVEL_DBG)) { + char t[BT_OTS_OBJ_ID_STR_LEN]; + + (void)bt_ots_obj_id_to_str(rec->metadata.id, t, sizeof(t)); + LOG_DBG("Object ID 0x%s", t); + } + + if ((start_len - buf->len) + sizeof(uint8_t) > rec->len) { + LOG_WRN("incorrect DirListing record, reclen %u too short, " + "includes only record length + ObjId", + rec->len); + return -EINVAL; + } + + rec->name_len = net_buf_simple_pull_u8(buf); + + if (rec->name_len > 0) { + uint8_t *name; + + if ((start_len - buf->len) + rec->name_len > rec->len) { + LOG_WRN("incorrect DirListing record, remaining length " + "%u shorter than name length %u", + rec->len - (start_len - buf->len), + rec->name_len); + return -EINVAL; + } + + if (rec->name_len >= sizeof(rec->metadata.name_c)) { + LOG_WRN("Name length %u too long, invalid record", rec->name_len); + return -EINVAL; + } + + name = net_buf_simple_pull_mem(buf, rec->name_len); + memcpy(rec->metadata.name_c, name, rec->name_len); + } + + rec->metadata.name_c[rec->name_len] = '\0'; + rec->flags = 0; + + if ((start_len - buf->len) + sizeof(uint8_t) > rec->len) { + LOG_WRN("incorrect DirListing record, reclen %u too short, " + "does not include flags", rec->len); + return -EINVAL; + } + + rec->flags = net_buf_simple_pull_u8(buf); + LOG_DBG("flags 0x%x", rec->flags); + + if (BT_OTS_DIR_LIST_GET_FLAG_TYPE_128(rec->flags)) { + uint8_t *uuid; + + if ((start_len - buf->len) + BT_UUID_SIZE_128 > rec->len) { + LOG_WRN("incorrect DirListing record, reclen %u " + "flags indicates uuid128, too short", + rec->len); + LOG_INF("flags 0x%x", rec->flags); + return -EINVAL; + } + + uuid = net_buf_simple_pull_mem(buf, BT_UUID_SIZE_128); + if (!bt_uuid_create(&rec->metadata.type.uuid, uuid, BT_UUID_SIZE_128)) { + LOG_DBG("Failed to create UUID"); + return -EINVAL; + } + } else { + if ((start_len - buf->len) + BT_UUID_SIZE_16 > rec->len) { + LOG_WRN("incorrect DirListing record, reclen %u " + "flags indicates uuid16, too short", + rec->len); + LOG_INF("flags 0x%x", rec->flags); + return -EINVAL; + } + + rec->metadata.type.uuid.type = BT_UUID_TYPE_16; + rec->metadata.type.uuid_16.val = + net_buf_simple_pull_le16(buf); + } + + if (BT_OTS_DIR_LIST_GET_FLAG_CUR_SIZE(rec->flags)) { + if ((start_len - buf->len) + sizeof(uint32_t) > rec->len) { + LOG_WRN("incorrect DirListing record, reclen %u " + "flags indicates cur_size, too short", + rec->len); + LOG_INF("flags 0x%x", rec->flags); + return -EINVAL; + } + + rec->metadata.size.cur = net_buf_simple_pull_le32(buf); + } + + if (BT_OTS_DIR_LIST_GET_FLAG_ALLOC_SIZE(rec->flags)) { + if ((start_len - buf->len) + sizeof(uint32_t) > rec->len) { + LOG_WRN("incorrect DirListing record, reclen %u " + "flags indicates allocated size, too short", + rec->len); + LOG_INF("flags 0x%x", rec->flags); + return -EINVAL; + } + + rec->metadata.size.alloc = net_buf_simple_pull_le32(buf); + } + + if (BT_OTS_DIR_LIST_GET_FLAG_FIRST_CREATED(rec->flags)) { + if ((start_len - buf->len) + BT_OTS_DATE_TIME_FIELD_SIZE > rec->len) { + LOG_WRN("incorrect DirListing record, reclen %u " + "too short flags indicates first_created", + rec->len); + LOG_INF("flags 0x%x", rec->flags); + return -EINVAL; + } + + date_time_decode(buf, &rec->metadata.first_created); + } + + if (BT_OTS_DIR_LIST_GET_FLAG_LAST_MODIFIED(rec->flags)) { + if ((start_len - buf->len) + BT_OTS_DATE_TIME_FIELD_SIZE > rec->len) { + LOG_WRN("incorrect DirListing record, reclen %u " + "flags indicates las_mod, too short", + rec->len); + LOG_INF("flags 0x%x", rec->flags); + return -EINVAL; + } + + date_time_decode(buf, &rec->metadata.modified); + } + + if (BT_OTS_DIR_LIST_GET_FLAG_PROPERTIES(rec->flags)) { + if ((start_len - buf->len) + sizeof(uint32_t) > rec->len) { + LOG_WRN("incorrect DirListing record, reclen %u " + "flags indicates properties, too short", + rec->len); + LOG_INF("flags 0x%x", rec->flags); + return -EINVAL; + } + + rec->metadata.props = net_buf_simple_pull_le32(buf); + } + + if (start_len - buf->len < rec->len) { + net_buf_simple_pull(buf, rec->len - (start_len - buf->len)); + } + + return rec->len; +} + +int bt_ots_client_decode_dirlisting(uint8_t *data, uint16_t length, + bt_ots_client_dirlisting_cb cb) +{ + struct net_buf_simple net_buf = {0}; + int count = 0; + struct dirlisting_record_t record = {0}; + + net_buf_simple_init_with_data(&net_buf, (void *)data, length); + + if (!data || length == 0) { + return -EINVAL; + } + + while (net_buf.len) { + int ret; + + count++; + + if (net_buf.len < sizeof(uint16_t)) { + LOG_WRN("incorrect DirListing record, len %u too short", net_buf.len); + return -EINVAL; + } + + LOG_DBG("Decoding record %u", count); + ret = decode_record(&net_buf, &record); + + if (ret < 0) { + LOG_WRN("DirListing, record %u invalid", count); + return ret; + } + + ret = cb(&record.metadata); + + if (ret == BT_OTS_STOP) { + break; + } + } + + return count; +} + +void bt_ots_metadata_display(struct bt_ots_obj_metadata *metadata, + uint16_t count) +{ + LOG_INF("--- Displaying %u metadata records ---", count); + + for (int i = 0; i < count; i++) { + char t[BT_OTS_OBJ_ID_STR_LEN]; + + (void)bt_ots_obj_id_to_str(metadata[i].id, t, sizeof(t)); + LOG_INF("Object ID: 0x%s", t); + LOG_INF("Object name: %s", metadata[i].name_c); + LOG_INF("Object Current Size: %u", metadata[i].size.cur); + LOG_INF("Object Allocate Size: %u", metadata[i].size.alloc); + + if (!bt_uuid_cmp(&metadata[i].type.uuid, + BT_UUID_OTS_TYPE_MPL_ICON)) { + LOG_INF("Type: Icon Obj Type"); + } else if (!bt_uuid_cmp(&metadata[i].type.uuid, + BT_UUID_OTS_TYPE_TRACK_SEGMENT)) { + LOG_INF("Type: Track Segment Obj Type"); + } else if (!bt_uuid_cmp(&metadata[i].type.uuid, + BT_UUID_OTS_TYPE_TRACK)) { + LOG_INF("Type: Track Obj Type"); + } else if (!bt_uuid_cmp(&metadata[i].type.uuid, + BT_UUID_OTS_TYPE_GROUP)) { + LOG_INF("Type: Group Obj Type"); + } else if (!bt_uuid_cmp(&metadata[i].type.uuid, + BT_UUID_OTS_DIRECTORY_LISTING)) { + LOG_INF("Type: Directory Listing"); + } + + LOG_INF("Properties:0x%x", metadata[i].props); + + if (BT_OTS_OBJ_GET_PROP_APPEND(metadata[i].props)) { + LOG_INF(" - append permitted"); + } + if (BT_OTS_OBJ_GET_PROP_DELETE(metadata[i].props)) { + LOG_INF(" - delete permitted"); + } + if (BT_OTS_OBJ_GET_PROP_EXECUTE(metadata[i].props)) { + LOG_INF(" - execute permitted"); + } + if (BT_OTS_OBJ_GET_PROP_MARKED(metadata[i].props)) { + LOG_INF(" - marked"); + } + if (BT_OTS_OBJ_GET_PROP_PATCH(metadata[i].props)) { + LOG_INF(" - patch permitted"); + } + if (BT_OTS_OBJ_GET_PROP_READ(metadata[i].props)) { + LOG_INF(" - read permitted"); + } + if (BT_OTS_OBJ_GET_PROP_TRUNCATE(metadata[i].props)) { + LOG_INF(" - truncate permitted"); + } + if (BT_OTS_OBJ_GET_PROP_WRITE(metadata[i].props)) { + LOG_INF(" - write permitted"); + } + } +} diff --git a/components/bt/esp_ble_audio/host/services/ots/ots_client_internal.h b/components/bt/esp_ble_audio/host/services/ots/ots_client_internal.h new file mode 100644 index 0000000000..8109f407cf --- /dev/null +++ b/components/bt/esp_ble_audio/host/services/ots/ots_client_internal.h @@ -0,0 +1,43 @@ +/* @file + * @brief Object Transfer client internal header file + * + * For use with the Object Transfer Service Client (OTC) + * + * SPDX-FileCopyrightText: 2020-2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef BT_GATT_OTC_INTERNAL_H_ +#define BT_GATT_OTC_INTERNAL_H_ + +#include "ots_oacp_internal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief Translate OTS OLCP result code to "normal" error + * + * Replace the OTS SUCCESS value with the value 0. + * + * The OLCP result code has the value "1" for success. + * Elsewhere in the le-audio host stack, "0" is used for no error. + * + * TODO: Update to also convert the non-SUCCESS values + * TODO: The macro is called OLCP, but uses OACP success value + * TODO: See https://github.com/zephyrproject-rtos/zephyr/issues/41184 + * OTS does not use the value "0". + */ +#define OLCP_RESULT_TO_ERROR(RESULT) \ + (((RESULT) == BT_GATT_OTS_OACP_RES_SUCCESS) ? 0 : RESULT) + +#define OTS_FEATURE_LEN (uint32_t)(2 * sizeof(uint32_t)) +#define OTS_SIZE_LEN (uint32_t)(2 * sizeof(uint32_t)) +#define OTS_PROPERTIES_LEN (uint32_t)(sizeof(uint32_t)) +#define OTS_TYPE_MAX_LEN (uint32_t)(sizeof(struct bt_ots_obj_type)) + +#ifdef __cplusplus +} +#endif + +#endif /* BT_GATT_OTC_INTERNAL_H_ */ diff --git a/components/bt/esp_ble_audio/host/services/ots/ots_dir_list.c b/components/bt/esp_ble_audio/host/services/ots/ots_dir_list.c new file mode 100644 index 0000000000..1b7c885cb4 --- /dev/null +++ b/components/bt/esp_ble_audio/host/services/ots/ots_dir_list.c @@ -0,0 +1,370 @@ +/* + * SPDX-FileCopyrightText: 2021 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include +#include "ots_internal.h" +#include "ots_obj_manager_internal.h" +#include "ots_dir_list_internal.h" + +#include + +LOG_MODULE_DECLARE(bt_ots, CONFIG_BT_OTS_LOG_LEVEL); + +static struct bt_ots_dir_list dir_lists[CONFIG_BT_OTS_MAX_INST_CNT]; + +static size_t dir_list_object_record_size(const struct bt_gatt_ots_object *obj) +{ + uint16_t len; + size_t obj_name_len; + + /* Record Length */ + len = sizeof(len); + + /* ID */ + len += BT_OTS_OBJ_ID_SIZE; + + /* Name length (single octet is used for the name length) */ + len += sizeof(uint8_t); + + /* Name */ + obj_name_len = strlen(obj->metadata.name); + __ASSERT(obj_name_len > 0 && obj_name_len <= CONFIG_BT_OTS_OBJ_MAX_NAME_LEN, + "Dir list object len is incorrect %zu", obj_name_len); + len += obj_name_len; + + /* Flags */ + len += sizeof(uint8_t); + + /* Object type */ + if (obj->metadata.type.uuid.type == BT_UUID_TYPE_16) { + len += BT_UUID_SIZE_16; + } else { + len += BT_UUID_SIZE_128; + } + + /* Object Current size */ + len += sizeof(obj->metadata.size.cur); + + /* Object properties */ + len += sizeof(obj->metadata.props); + + __ASSERT(len >= DIR_LIST_OBJ_RECORD_MIN_SIZE, + "Dir list object len is too small %u", len); + __ASSERT(len <= DIR_LIST_OBJ_RECORD_MAX_SIZE, + "Dir list object len is too large %u", len); + + return len; +} + +static void dir_list_object_encode(const struct bt_gatt_ots_object *obj, + struct net_buf_simple *net_buf) +{ + uint8_t flags = 0; + uint8_t *start; + uint16_t len; + size_t obj_name_len; + + BT_OTS_DIR_LIST_SET_FLAG_PROPERTIES(flags); + BT_OTS_DIR_LIST_SET_FLAG_CUR_SIZE(flags); + if (obj->metadata.type.uuid.type == BT_UUID_TYPE_128) { + BT_OTS_DIR_LIST_SET_FLAG_TYPE_128(flags); + } + + /* skip 16bits at the beginning of the record for the record's length */ + start = net_buf_simple_add(net_buf, sizeof(len)); + + /* ID */ + net_buf_simple_add_le48(net_buf, obj->id); + + /* Name length */ + obj_name_len = strlen(obj->metadata.name); + __ASSERT(obj_name_len > 0 && obj_name_len <= CONFIG_BT_OTS_OBJ_MAX_NAME_LEN, + "Dir list object len is incorrect %zu", obj_name_len); + net_buf_simple_add_u8(net_buf, obj_name_len); + + /* Name */ + net_buf_simple_add_mem(net_buf, obj->metadata.name, obj_name_len); + + /* Flags */ + net_buf_simple_add_u8(net_buf, flags); + + /* encode Object type */ + if (obj->metadata.type.uuid.type == BT_UUID_TYPE_16) { + net_buf_simple_add_le16(net_buf, obj->metadata.type.uuid_16.val); + } else { + net_buf_simple_add_mem(net_buf, obj->metadata.type.uuid_128.val, + BT_UUID_SIZE_128); + } + + /* encode Object Current size */ + net_buf_simple_add_le32(net_buf, obj->metadata.size.cur); + + /* Object properties */ + net_buf_simple_add_le32(net_buf, obj->metadata.props); + + len = net_buf_simple_tail(net_buf) - start; + + __ASSERT(len >= DIR_LIST_OBJ_RECORD_MIN_SIZE, + "Dir list object len is too small %u", len); + __ASSERT(len <= DIR_LIST_OBJ_RECORD_MAX_SIZE, + "Dir list object len is too large %u", len); + + /* Update the record length at the beginning */ + sys_put_le16(len, start); +} + +static void bt_ots_dir_list_reset_anchor(struct bt_ots_dir_list *dir_list, void *obj_manager) +{ + int err; + + /* Reset the dir_list - Ignore any error as we can't do anything about it anyways */ + err = bt_gatt_ots_obj_manager_first_obj_get(obj_manager, &dir_list->anchor_object); + if (err) { + return; + } + + dir_list->anchor_offset = 0; + return; +} + +static int bt_ots_dir_list_search_forward(struct bt_ots_dir_list *dir_list, void *obj_manager, + off_t offset) +{ + int err; + char id_str[BT_OTS_OBJ_ID_STR_LEN]; + struct bt_gatt_ots_object *obj = dir_list->anchor_object; + size_t rec_len = dir_list_object_record_size(obj); + + bt_ots_obj_id_to_str(obj->id, id_str, sizeof(id_str)); + LOG_DBG("Searching forward for offset %ld starting at %ld with object ID %s", + (long)offset, (long)dir_list->anchor_offset, id_str); + + while (dir_list->anchor_offset + rec_len <= offset) { + + err = bt_gatt_ots_obj_manager_next_obj_get(obj_manager, obj, &obj); + if (err) { + return err; + } + + dir_list->anchor_offset += rec_len; + dir_list->anchor_object = obj; + + rec_len = dir_list_object_record_size(obj); + } + + return 0; +} + +static int bt_ots_dir_list_search_backward(struct bt_ots_dir_list *dir_list, void *obj_manager, + off_t offset) +{ + int err; + char id_str[BT_OTS_OBJ_ID_STR_LEN]; + struct bt_gatt_ots_object *obj = dir_list->anchor_object; + + bt_ots_obj_id_to_str(obj->id, id_str, sizeof(id_str)); + LOG_DBG("Searching backward for offset %ld starting at %ld with object ID %s", + (long)offset, (long)dir_list->anchor_offset, id_str); + + while (dir_list->anchor_offset > offset) { + + err = bt_gatt_ots_obj_manager_prev_obj_get(obj_manager, obj, &obj); + if (err) { + return err; + } + + dir_list->anchor_offset -= dir_list_object_record_size(obj); + dir_list->anchor_object = obj; + } + + return 0; +} + +static int bt_ots_dir_list_search(struct bt_ots_dir_list *dir_list, void *obj_manager, off_t offset) +{ + int err = 0; + char id_str[BT_OTS_OBJ_ID_STR_LEN]; + + /* decide start location and direction of movement based on offset, we can only choose + * current anchor point, beginning, or end as those are the only places where we know + * the associated object that builds up the record. + */ + if (offset >= dir_list->anchor_offset) { + const size_t last = dir_list->dir_list_obj->metadata.size.cur; + const size_t mid = dir_list->anchor_offset + (last - dir_list->anchor_offset) / 2; + + if (offset < mid) { + err = bt_ots_dir_list_search_forward(dir_list, obj_manager, offset); + } else { + size_t rec_len; + + LOG_DBG("Offset %ld is closer to %zu than %ld, start from end", + (long)offset, last, (long)dir_list->anchor_offset); + err = bt_gatt_ots_obj_manager_last_obj_get(obj_manager, &dir_list->anchor_object); + if (err) { + return err; + } + rec_len = dir_list_object_record_size(dir_list->anchor_object); + dir_list->anchor_offset = last - rec_len; + err = bt_ots_dir_list_search_backward(dir_list, obj_manager, offset); + } + } else { + const size_t mid = dir_list->anchor_offset / 2; + + if (offset < mid) { + LOG_DBG("Offset %ld is closer to 0 than %ld, start from beginning", + (long)offset, (long)dir_list->anchor_offset); + bt_ots_dir_list_reset_anchor(dir_list, obj_manager); + err = bt_ots_dir_list_search_forward(dir_list, obj_manager, offset); + } else { + err = bt_ots_dir_list_search_backward(dir_list, obj_manager, offset); + } + } + + if (err) { + return err; + } + + bt_ots_obj_id_to_str(dir_list->anchor_object->id, id_str, sizeof(id_str)); + LOG_DBG("Found offset %ld starting at %ld in object with ID %s", + (long)offset, (long)dir_list->anchor_offset, id_str); + + return 0; +} + +static void dir_list_update_size(struct bt_ots_dir_list *dir_list, void *obj_manager) +{ + struct bt_gatt_ots_object *obj; + int err; + size_t len = 0; + + err = bt_gatt_ots_obj_manager_first_obj_get(obj_manager, &obj); + + __ASSERT(err == 0 && obj == dir_list->dir_list_obj, + "Expecting first object to be the Directory Listing Object"); + + do { + len += dir_list_object_record_size(obj); + + err = bt_gatt_ots_obj_manager_next_obj_get(obj_manager, obj, &obj); + } while (!err); + + LOG_DBG("Update directory listing current size to 0x%zx", len); + dir_list->dir_list_obj->metadata.size.cur = len; +} + +void bt_ots_dir_list_selected(struct bt_ots_dir_list *dir_list, void *obj_manager, + struct bt_gatt_ots_object *cur_obj) +{ + if (dir_list->dir_list_obj != cur_obj) { + /* We only need to update the object directory listing if it is currently selected, + * as we otherwise only create it when it is selected. + */ + return; + } + + bt_ots_dir_list_reset_anchor(dir_list, obj_manager); + dir_list_update_size(dir_list, obj_manager); +} + +void bt_ots_dir_list_init(struct bt_ots_dir_list **dir_list, void *obj_manager) +{ + struct bt_gatt_ots_object *dir_list_obj; + int err; + static char *dir_list_obj_name = CONFIG_BT_OTS_DIR_LIST_OBJ_NAME; + + __ASSERT(*dir_list == NULL, "Already initialized"); + + for (size_t i = 0; i < ARRAY_SIZE(dir_lists); i++) { + if (!dir_lists[i].dir_list_obj) { + *dir_list = &dir_lists[i]; + } + } + + __ASSERT(*dir_list, "Could not assign Directory Listing Object"); + + __ASSERT(strlen(dir_list_obj_name) <= CONFIG_BT_OTS_OBJ_MAX_NAME_LEN, + "BT_OTS_DIR_LIST_OBJ_NAME shall be less than or equal to %u octets", + CONFIG_BT_OTS_OBJ_MAX_NAME_LEN); + + err = bt_gatt_ots_obj_manager_obj_add(obj_manager, &dir_list_obj); + + __ASSERT(!err, "Could not add Directory Listing Object for object manager %p", obj_manager); + + memset(&dir_list_obj->metadata, 0, sizeof(dir_list_obj->metadata)); + dir_list_obj->metadata.name = dir_list_obj_name; + dir_list_obj->metadata.size.alloc = DIR_LIST_MAX_SIZE; + dir_list_obj->metadata.type.uuid.type = BT_UUID_TYPE_16; + dir_list_obj->metadata.type.uuid_16.val = BT_UUID_OTS_DIRECTORY_LISTING_VAL; + BT_OTS_OBJ_SET_PROP_READ(dir_list_obj->metadata.props); + + (*dir_list)->dir_list_obj = dir_list_obj; + + bt_ots_dir_list_reset_anchor(*dir_list, obj_manager); + dir_list_update_size(*dir_list, obj_manager); +} + +ssize_t bt_ots_dir_list_content_get(struct bt_ots_dir_list *dir_list, void *obj_manager, + void **data, size_t len, off_t offset) +{ + int err; + size_t last_rec_len; + size_t rec_len; + off_t rec_offset; + struct bt_gatt_ots_object *obj; + + err = bt_ots_dir_list_search(dir_list, obj_manager, offset); + if (err) { + return err; + } + + net_buf_simple_init_with_data(&dir_list->net_buf, dir_list->_content, + sizeof(dir_list->_content)); + net_buf_simple_reset(&dir_list->net_buf); + + obj = dir_list->anchor_object; + rec_offset = dir_list->anchor_offset; + + last_rec_len = 0; + rec_len = dir_list_object_record_size(obj); + while (net_buf_simple_tailroom(&dir_list->net_buf) >= rec_len) { + + dir_list_object_encode(obj, &dir_list->net_buf); + + dir_list->anchor_object = obj; + dir_list->anchor_offset += last_rec_len; + + if (dir_list->net_buf.len - (offset - rec_offset) >= len) { + /* we have encoded as much data as the client has asked */ + break; + } + + err = bt_gatt_ots_obj_manager_next_obj_get(obj_manager, obj, &obj); + if (err) { + /* there are no more objects to encode */ + break; + } + + last_rec_len = rec_len; + rec_len = dir_list_object_record_size(obj); + } + + *data = dir_list->net_buf.data + (offset - rec_offset); + + return MIN(len, dir_list->net_buf.len - (offset - rec_offset)); +} + +bool bt_ots_dir_list_is_idle(const struct bt_ots_dir_list *dir_list) +{ + return dir_list->dir_list_obj->state.type == BT_GATT_OTS_OBJECT_IDLE_STATE; +} diff --git a/components/bt/esp_ble_audio/host/services/ots/ots_dir_list_internal.h b/components/bt/esp_ble_audio/host/services/ots/ots_dir_list_internal.h new file mode 100644 index 0000000000..ea30cc4bf2 --- /dev/null +++ b/components/bt/esp_ble_audio/host/services/ots/ots_dir_list_internal.h @@ -0,0 +1,170 @@ +/* + * SPDX-FileCopyrightText: 2021 - 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef BT_OTS_DIR_LIST_INTERNAL_H_ +#define BT_OTS_DIR_LIST_INTERNAL_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +/** Maximum size of the Directory Listing Object Record. Table 4.1 in the OTS spec. */ +#define DIR_LIST_OBJ_RECORD_MIN_SIZE 13 +#define DIR_LIST_OBJ_RECORD_MAX_SIZE 172 +#define DIR_LIST_MAX_SIZE (DIR_LIST_OBJ_RECORD_MAX_SIZE * CONFIG_BT_OTS_MAX_OBJ_CNT) + +/** @brief Directory Listing Buffer Size + * + * In order to transmit the maximum size we choose CONFIG_BT_OTS_L2CAP_CHAN_TX_MTU + * as the buffer size. However, dir_list_object_encode function encodes one full + * object record at a time so the buffer must be a multiple of object record length. + */ +#define OTS_DIR_LIST_BUFFER_SIZE (DIR_LIST_OBJ_RECORD_MAX_SIZE * \ + DIV_ROUND_UP(CONFIG_BT_OTS_L2CAP_CHAN_TX_MTU, DIR_LIST_OBJ_RECORD_MAX_SIZE)) + +struct bt_ots_dir_list { + struct net_buf_simple net_buf; + struct bt_gatt_ots_object *dir_list_obj; + off_t anchor_offset; + struct bt_gatt_ots_object *anchor_object; + uint8_t _content[OTS_DIR_LIST_BUFFER_SIZE]; +}; + +/** @brief Directory Listing record flag field. */ +enum { + /** Bit 0 Object Type UUID Size 0: 16bit 1: 128bit*/ + BT_OTS_DIR_LIST_FLAG_TYPE_128 = 0, + /** Bit 1 Current Size Present*/ + BT_OTS_DIR_LIST_FLAG_CUR_SIZE = 1, + /** Bit 2 Allocated Size Present */ + BT_OTS_DIR_LIST_FLAG_ALLOC_SIZE = 2, + /** Bit 3 Object First-Created Present*/ + BT_OTS_DIR_LIST_FLAG_FIRST_CREATED = 3, + /** Bit 4 Object Last-Modified Present*/ + BT_OTS_DIR_LIST_FLAG_LAST_MODIFIED = 4, + /** Bit 5 Object Properties Present*/ + BT_OTS_DIR_LIST_FLAG_PROPERTIES = 5, + /** Bit 6 RFU*/ + BT_OTS_DIR_LIST_FLAG_RFU = 6, + /** Bit 7 Extended Flags Present*/ + BT_OTS_DIR_LIST_FLAG_EXTENDED = 7, +}; + +/** @brief Set @ref BT_OTS_DIR_LIST_SET_FLAG_TYPE_128 flag. + * + * @param flags Directory Listing Object flags. + */ +#define BT_OTS_DIR_LIST_SET_FLAG_TYPE_128(flags) \ + WRITE_BIT((flags), BT_OTS_DIR_LIST_FLAG_TYPE_128, 1) + +/** @brief Set @ref BT_OTS_DIR_LIST_FLAG_CUR_SIZE flag. + * + * @param flags Directory Listing Object flags. + */ +#define BT_OTS_DIR_LIST_SET_FLAG_CUR_SIZE(flags) \ + WRITE_BIT((flags), BT_OTS_DIR_LIST_FLAG_CUR_SIZE, 1) + +/** @brief Set @ref BT_OTS_DIR_LIST_FLAG_ALLOC_SIZE flag. + * + * @param flags Directory Listing Object flags. + */ +#define BT_OTS_DIR_LIST_SET_FLAG_ALLOC_SIZE(flags) \ + WRITE_BIT((flags), BT_OTS_DIR_LIST_FLAG_ALLOC_SIZE, 1) + +/** @brief Set @ref BT_OTS_DIR_LIST_FLAG_FIRST_CREATED flag. + * + * @param flags Directory Listing Object flags. + */ +#define BT_OTS_DIR_LIST_SET_FLAG_FIRST_CREATED(flags) \ + WRITE_BIT((flags), BT_OTS_DIR_LIST_FLAG_FIRST_CREATED, 1) + +/** @brief Set @ref BT_OTS_DIR_LIST_FLAG_LAST_MODIFIED flag. + * + * @param flags Directory Listing Object flags. + */ +#define BT_OTS_DIR_LIST_SET_FLAG_LAST_MODIFIED(flags) \ + WRITE_BIT((flags), BT_OTS_DIR_LIST_FLAG_LAST_MODIFIED, 1) + +/** @brief Set @ref BT_OTS_DIR_LIST_FLAG_PROPERTIES flag. + * + * @param flags Directory Listing Object flags. + */ +#define BT_OTS_DIR_LIST_SET_FLAG_PROPERTIES(flags) \ + WRITE_BIT((flags), BT_OTS_DIR_LIST_FLAG_PROPERTIES, 1) + +/** @brief Set @ref BT_OTS_DIR_LIST_FLAG_EXTENDED flag. + * + * @param flags Directory Listing Object flags. + */ +#define BT_OTS_DIR_LIST_SET_FLAG_EXTENDED(flags) \ + WRITE_BIT((flags), BT_OTS_DIR_LIST_FLAG_EXTENDED, 1) + +/** @brief Get @ref BT_OTS_DIR_LIST_GET_FLAG_TYPE_128 flag. + * + * @param flags Directory Listing Object flags. + */ +#define BT_OTS_DIR_LIST_GET_FLAG_TYPE_128(flags) \ + ((flags) & BIT(BT_OTS_DIR_LIST_FLAG_TYPE_128)) + +/** @brief Get @ref BT_OTS_DIR_LIST_GET_FLAG_CUR_SIZE flag. + * + * @param flags Directory Listing Object flags. + */ +#define BT_OTS_DIR_LIST_GET_FLAG_CUR_SIZE(flags) \ + ((flags) & BIT(BT_OTS_DIR_LIST_FLAG_CUR_SIZE)) + +/** @brief Get @ref BT_OTS_DIR_LIST_GET_FLAG_ALLOC_SIZE flag. + * + * @param flags Directory Listing Object flags. + */ +#define BT_OTS_DIR_LIST_GET_FLAG_ALLOC_SIZE(flags) \ + ((flags) & BIT(BT_OTS_DIR_LIST_FLAG_ALLOC_SIZE)) + +/** @brief Get @ref BT_OTS_DIR_LIST_GET_FLAG_FIRST_CREATED flag. + * + * @param flags Directory Listing Object flags. + */ +#define BT_OTS_DIR_LIST_GET_FLAG_FIRST_CREATED(flags) \ + ((flags) & BIT(BT_OTS_DIR_LIST_FLAG_FIRST_CREATED)) + +/** @brief Get @ref BT_OTS_DIR_LIST_GET_FLAG_LAST_MODIFIED flag. + * + * @param flags Directory Listing Object flags. + */ +#define BT_OTS_DIR_LIST_GET_FLAG_LAST_MODIFIED(flags) \ + ((flags) & BIT(BT_OTS_DIR_LIST_FLAG_LAST_MODIFIED)) + +/** @brief Get @ref BT_OTS_DIR_LIST_GET_FLAG_PROPERTIES flag. + * + * @param flags Directory Listing Object flags. + */ +#define BT_OTS_DIR_LIST_GET_FLAG_PROPERTIES(flags) \ + ((flags) & BIT(BT_OTS_DIR_LIST_FLAG_PROPERTIES)) + +/** @brief Get @ref BT_OTS_DIR_LIST_GET_FLAG_EXTENDED flag. + * + * @param flags Directory Listing Object flags. + */ +#define BT_OTS_DIR_LIST_GET_FLAG_EXTENDED(flags) \ + ((flags) & BIT(BT_OTS_DIR_LIST_FLAG_EXTENDED)) + +void bt_ots_dir_list_selected(struct bt_ots_dir_list *dir_list, void *obj_manager, + struct bt_gatt_ots_object *cur_obj); +void bt_ots_dir_list_init(struct bt_ots_dir_list **dir_list, void *obj_manager); +ssize_t bt_ots_dir_list_content_get(struct bt_ots_dir_list *dir_list, void *obj_manager, + void **data, size_t len, off_t offset); +bool bt_ots_dir_list_is_idle(const struct bt_ots_dir_list *dir_list); + +#ifdef __cplusplus +} +#endif + +#endif /* BT_OTS_DIR_LIST_INTERNAL_H_ */ diff --git a/components/bt/esp_ble_audio/host/services/ots/ots_internal.h b/components/bt/esp_ble_audio/host/services/ots/ots_internal.h new file mode 100644 index 0000000000..a692d4c371 --- /dev/null +++ b/components/bt/esp_ble_audio/host/services/ots/ots_internal.h @@ -0,0 +1,148 @@ +/* + * SPDX-FileCopyrightText: 2020-2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef BT_GATT_OTS_INTERNAL_H_ +#define BT_GATT_OTS_INTERNAL_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "ots_l2cap_internal.h" +#include "ots_oacp_internal.h" +#include "ots_olcp_internal.h" + +/** + * Both OACP and OLCP have same max size of 7 bytes + * + * Table 3.10: Format of OACP Response Value + * OACP Response Value contains + * 1 octet Procedure code + * 1 octet Request op code + * 1 octet Result Code + * 4 octet CRC checksum (if present) + * + * Table 3.24: Format of the OLCP Response Value + * 1 octet Procedure code + * 1 octet Request op code + * 1 octet Result Code + * 0 or 4 octets Response Parameter + * + **/ +#define OACP_OLCP_RES_MAX_SIZE 7 + +#define BT_OTS_VALID_OBJ_ID(id) (IN_RANGE((id), BT_OTS_OBJ_ID_MIN, BT_OTS_OBJ_ID_MAX) || \ + (id) == OTS_OBJ_ID_DIR_LIST) + +#define BT_OTS_SET_METADATA_REQ_NAME(metadata) \ + ((metadata) = (metadata) | BT_OTS_METADATA_REQ_NAME) +#define BT_OTS_SET_METADATA_REQ_TYPE(metadata) \ + ((metadata) = (metadata) | BT_OTS_METADATA_REQ_TYPE) +#define BT_OTS_SET_METADATA_REQ_SIZE(metadata) \ + ((metadata) = (metadata) | BT_OTS_METADATA_REQ_SIZE) +#define BT_OTS_SET_METADATA_REQ_CREATED(metadata) \ + ((metadata) = (metadata) | BT_OTS_METADATA_REQ_CREATED) +#define BT_OTS_SET_METADATA_REQ_MODIFIED(metadata) \ + ((metadata) = (metadata) | BT_OTS_METADATA_REQ_MODIFIED) +#define BT_OTS_SET_METADATA_REQ_ID(metadata) \ + ((metadata) = (metadata) | BT_OTS_METADATA_REQ_ID) +#define BT_OTS_SET_METADATA_REQ_PROPS(metadata) \ + ((metadata) = (metadata) | BT_OTS_METADATA_REQ_PROPS) + +#define BT_OTS_GET_METADATA_REQ_NAME(metadata) \ + ((metadata) & BT_OTS_METADATA_REQ_NAME) +#define BT_OTS_GET_METADATA_REQ_TYPE(metadata) \ + ((metadata) & BT_OTS_METADATA_REQ_TYPE) +#define BT_OTS_GET_METADATA_REQ_SIZE(metadata) \ + ((metadata) & BT_OTS_METADATA_REQ_SIZE) +#define BT_OTS_GET_METADATA_REQ_CREATED(metadata) \ + ((metadata) & BT_OTS_METADATA_REQ_CREATED) +#define BT_OTS_GET_METADATA_REQ_MODIFIED(metadata) \ + ((metadata) & BT_OTS_METADATA_REQ_MODIFIED) +#define BT_OTS_GET_METADATA_REQ_ID(metadata) \ + ((metadata) & BT_OTS_METADATA_REQ_ID) +#define BT_OTS_GET_METADATA_REQ_PROPS(metadata) \ + ((metadata) & BT_OTS_METADATA_REQ_PROPS) + +/**@brief OTS Attribute Protocol Application Error codes. */ +enum bt_gatt_ots_att_err_codes { + /** An attempt was made to write a value that is invalid or + * not supported by this Server for a reason other than + * the attribute permissions. + */ + BT_GATT_OTS_WRITE_REQUEST_REJECTED = 0x80, + /** An attempt was made to read or write to an Object Metadata + * characteristic while the Current Object was an Invalid Object. + */ + BT_GATT_OTS_OBJECT_NOT_SELECTED = 0x81, + /** The Server is unable to service the Read Request or Write Request + * because it exceeds the concurrency limit of the service. + */ + BT_GATT_OTS_CONCURRENCY_LIMIT_EXCEEDED = 0x82, + /** The requested object name was rejected because + * the name was already in use by an existing object on the Server. + */ + BT_GATT_OTS_OBJECT_NAME_ALREADY_EXISTS = 0x83, +}; + +enum bt_gatt_ots_object_state_type { + BT_GATT_OTS_OBJECT_IDLE_STATE, + + BT_GATT_OTS_OBJECT_READ_OP_STATE, + + BT_GATT_OTS_OBJECT_WRITE_OP_STATE, +}; + +struct bt_gatt_ots_object_state { + enum bt_gatt_ots_object_state_type type; + union { + struct bt_gatt_ots_object_read_op { + struct bt_gatt_ots_oacp_read_params oacp_params; + uint32_t sent_len; + } read_op; + struct bt_gatt_ots_object_write_op { + struct bt_gatt_ots_oacp_write_params oacp_params; + uint32_t recv_len; + } write_op; + }; +}; + +struct bt_gatt_ots_object { + uint64_t id; + struct bt_ots_obj_metadata metadata; + struct bt_gatt_ots_object_state state; +}; + +struct bt_gatt_ots_indicate { + struct bt_gatt_indicate_params params; + struct bt_gatt_attr attr; + struct bt_gatt_ccc_managed_user_data ccc; + bool is_enabled; + struct k_work work; + uint8_t res[OACP_OLCP_RES_MAX_SIZE]; +}; + +struct bt_ots { + struct bt_ots_feat features; + struct bt_gatt_ots_object *cur_obj; + struct bt_gatt_service *service; + struct bt_gatt_ots_indicate oacp_ind; + struct bt_gatt_ots_indicate olcp_ind; + struct bt_gatt_ots_l2cap l2cap; + struct bt_ots_cb *cb; + struct bt_ots_dir_list *dir_list; + void *obj_manager; +}; + +int bt_ots_obj_add_internal(struct bt_ots *ots, struct bt_conn *conn, + const struct bt_ots_obj_add_param *param, + struct bt_gatt_ots_object **obj); +#ifdef __cplusplus +} +#endif + +#endif /* BT_GATT_OTS_INTERNAL_H_ */ diff --git a/components/bt/esp_ble_audio/host/services/ots/ots_l2cap.c b/components/bt/esp_ble_audio/host/services/ots/ots_l2cap.c new file mode 100644 index 0000000000..3dfa740c16 --- /dev/null +++ b/components/bt/esp_ble_audio/host/services/ots/ots_l2cap.c @@ -0,0 +1,330 @@ +/* + * SPDX-FileCopyrightText: 2020-2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "ots_l2cap_internal.h" + +#include + +/* This l2cap is the only OTS-file in use for OTC. + * If only OTC is used, the OTS log module must be registered here. + */ +#if defined(CONFIG_BT_OTS) +LOG_MODULE_DECLARE(bt_ots, CONFIG_BT_OTS_LOG_LEVEL); +#elif defined(CONFIG_BT_OTS_CLIENT) +LOG_MODULE_REGISTER(bt_ots, CONFIG_BT_OTS_CLIENT_LOG_LEVEL); +#endif + +/* According to Bluetooth specification Assigned Numbers that are used in the + * Logical Link Control for protocol/service multiplexers. + */ +#define BT_GATT_OTS_L2CAP_PSM 0x0025 + +NET_BUF_POOL_FIXED_DEFINE(ot_chan_tx_pool, 1, + BT_L2CAP_SDU_BUF_SIZE(CONFIG_BT_OTS_L2CAP_CHAN_TX_MTU), + CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); + +#if (CONFIG_BT_OTS_L2CAP_CHAN_RX_MTU > BT_L2CAP_SDU_RX_MTU) +NET_BUF_POOL_FIXED_DEFINE(ot_chan_rx_pool, 1, CONFIG_BT_OTS_L2CAP_CHAN_RX_MTU, 8, + NULL); +#endif + +/* List of Object Transfer Channels. */ +static sys_slist_t channels; + +static int ots_l2cap_send(struct bt_gatt_ots_l2cap *l2cap_ctx) +{ + int ret; + struct net_buf *buf; + uint32_t len; + + /* Calculate maximum length of data chunk. */ + len = MIN(l2cap_ctx->ot_chan.tx.mtu, CONFIG_BT_OTS_L2CAP_CHAN_TX_MTU); + len = MIN(len, l2cap_ctx->tx.len - l2cap_ctx->tx.len_sent); + + /* Prepare buffer for sending. */ + buf = net_buf_alloc(&ot_chan_tx_pool, K_FOREVER); + net_buf_reserve(buf, BT_L2CAP_SDU_CHAN_SEND_RESERVE); + net_buf_add_mem(buf, &l2cap_ctx->tx.data[l2cap_ctx->tx.len_sent], len); + + ret = bt_l2cap_chan_send(&l2cap_ctx->ot_chan.chan, buf); + if (ret < 0) { + LOG_ERR("Unable to send data over CoC: %d", ret); + net_buf_unref(buf); + + return -ENOEXEC; + } + + /* Mark that L2CAP TX was accepted. */ + l2cap_ctx->tx.len_sent += len; + + LOG_DBG("Sending TX chunk with %d bytes on L2CAP CoC", len); + + return 0; +} + +#if (CONFIG_BT_OTS_L2CAP_CHAN_RX_MTU > BT_L2CAP_SDU_RX_MTU) +static struct net_buf *l2cap_alloc_buf(struct bt_l2cap_chan *chan) +{ + LOG_DBG("Channel %p allocating buffer", chan); + + return net_buf_alloc(&ot_chan_rx_pool, K_FOREVER); +} +#endif + +static void l2cap_sent(struct bt_l2cap_chan *chan) +{ + struct bt_l2cap_le_chan *l2chan = CONTAINER_OF(chan, struct bt_l2cap_le_chan, chan); + struct bt_gatt_ots_l2cap *l2cap_ctx; + + LOG_DBG("Outgoing data channel %p transmitted", chan); + + l2cap_ctx = CONTAINER_OF(l2chan, struct bt_gatt_ots_l2cap, ot_chan); + + /* Ongoing TX - sending next chunk. */ + if (l2cap_ctx->tx.len != l2cap_ctx->tx.len_sent) { + if (ots_l2cap_send(l2cap_ctx)) { + /* Send failed - clean up TX state to unblock channel. */ + LOG_ERR("Failed to send next chunk, aborting TX"); + memset(&l2cap_ctx->tx, 0, sizeof(l2cap_ctx->tx)); + if (l2cap_ctx->tx_done) { + l2cap_ctx->tx_done(l2cap_ctx, chan->conn); + } + } + + return; + } + + /* TX completed - notify upper layers and clean up. */ + memset(&l2cap_ctx->tx, 0, sizeof(l2cap_ctx->tx)); + + LOG_DBG("Scheduled TX on L2CAP CoC is complete"); + + if (l2cap_ctx->tx_done) { + l2cap_ctx->tx_done(l2cap_ctx, chan->conn); + } +} + +static int l2cap_recv(struct bt_l2cap_chan *chan, struct net_buf *buf) +{ + struct bt_l2cap_le_chan *l2chan = CONTAINER_OF(chan, struct bt_l2cap_le_chan, chan); + struct bt_gatt_ots_l2cap *l2cap_ctx; + + LOG_DBG("Incoming data channel %p received", chan); + + l2cap_ctx = CONTAINER_OF(l2chan, struct bt_gatt_ots_l2cap, ot_chan); + + if (!l2cap_ctx->rx_done) { + return -ENODEV; + } + + return l2cap_ctx->rx_done(l2cap_ctx, chan->conn, buf); +} + +static void l2cap_status(struct bt_l2cap_chan *chan, atomic_t *status) +{ + LOG_DBG("Channel %p status %lu", chan, atomic_get(status)); +} + +static void l2cap_connected(struct bt_l2cap_chan *chan) +{ + LOG_DBG("Channel %p connected", chan); +} + +static void l2cap_disconnected(struct bt_l2cap_chan *chan) +{ + struct bt_l2cap_le_chan *l2chan = CONTAINER_OF(chan, struct bt_l2cap_le_chan, chan); + struct bt_gatt_ots_l2cap *l2cap_ctx; + + LOG_DBG("Channel %p disconnected", chan); + + l2cap_ctx = CONTAINER_OF(l2chan, struct bt_gatt_ots_l2cap, ot_chan); + + /* Clean up any in-progress TX */ + memset(&l2cap_ctx->tx, 0, sizeof(l2cap_ctx->tx)); + + if (l2cap_ctx->closed) { + l2cap_ctx->closed(l2cap_ctx, chan->conn); + } +} + +static const struct bt_l2cap_chan_ops l2cap_ops = { +#if (CONFIG_BT_OTS_L2CAP_CHAN_RX_MTU > BT_L2CAP_SDU_RX_MTU) + .alloc_buf = l2cap_alloc_buf, +#endif + .sent = l2cap_sent, + .recv = l2cap_recv, + .status = l2cap_status, + .connected = l2cap_connected, + .disconnected = l2cap_disconnected, +}; + +static inline void l2cap_chan_init(struct bt_l2cap_le_chan *chan) +{ + chan->rx.mtu = CONFIG_BT_OTS_L2CAP_CHAN_RX_MTU; + chan->chan.ops = &l2cap_ops; + + LOG_DBG("RX MTU set to %u", chan->rx.mtu); +} + +static struct bt_gatt_ots_l2cap *find_free_l2cap_ctx(void) +{ + struct bt_gatt_ots_l2cap *l2cap_ctx; + + SYS_SLIST_FOR_EACH_CONTAINER(&channels, l2cap_ctx, node) { + if (l2cap_ctx->ot_chan.chan.conn) { + continue; + } + + return l2cap_ctx; + } + + return NULL; +} + +static int l2cap_accept(struct bt_conn *conn, struct bt_l2cap_server *server, + struct bt_l2cap_chan **chan) +{ + struct bt_gatt_ots_l2cap *l2cap_ctx; + + LOG_DBG("Incoming conn %p", (void *)conn); + + l2cap_ctx = find_free_l2cap_ctx(); + if (l2cap_ctx) { + l2cap_chan_init(&l2cap_ctx->ot_chan); + memset(&l2cap_ctx->tx, 0, sizeof(l2cap_ctx->tx)); + + *chan = &l2cap_ctx->ot_chan.chan; + + return 0; + } + + return -ENOMEM; +} + +static struct bt_l2cap_server l2cap_server = { + .psm = BT_GATT_OTS_L2CAP_PSM, + .accept = l2cap_accept, +}; + +static int bt_gatt_ots_l2cap_init(void) +{ + int err; + + sys_slist_init(&channels); + + err = bt_l2cap_server_register(&l2cap_server); + if (err) { + LOG_ERR("Unable to register OTS PSM"); + return err; + } + + LOG_DBG("Initialized OTS L2CAP"); + + return 0; +} + +bool bt_gatt_ots_l2cap_is_open(struct bt_gatt_ots_l2cap *l2cap_ctx, + struct bt_conn *conn) +{ + return (l2cap_ctx->ot_chan.chan.conn == conn); +} + +int bt_gatt_ots_l2cap_send(struct bt_gatt_ots_l2cap *l2cap_ctx, + uint8_t *data, uint32_t len) +{ + int err; + + if (l2cap_ctx->tx.len != 0) { + LOG_ERR("L2CAP TX in progress"); + + return -EAGAIN; + } + + l2cap_ctx->tx.data = data; + l2cap_ctx->tx.len = len; + + LOG_DBG("Starting TX on L2CAP CoC with %d byte packet", len); + + err = ots_l2cap_send(l2cap_ctx); + if (err) { + LOG_ERR("Unable to send data over CoC: %d", err); + memset(&l2cap_ctx->tx, 0, sizeof(l2cap_ctx->tx)); + + return err; + } + + return 0; +} + +int bt_gatt_ots_l2cap_register(struct bt_gatt_ots_l2cap *l2cap_ctx) +{ + sys_slist_append(&channels, &l2cap_ctx->node); + + return 0; +} + +int bt_gatt_ots_l2cap_unregister(struct bt_gatt_ots_l2cap *l2cap_ctx) +{ + sys_slist_find_and_remove(&channels, &l2cap_ctx->node); + + return 0; +} + +/* Similar to l2cap_accept(), but for the client side */ +int bt_gatt_ots_l2cap_connect(struct bt_conn *conn, + struct bt_gatt_ots_l2cap **l2cap_ctx) +{ + int err; + struct bt_gatt_ots_l2cap *ctx; + + if (!conn) { + LOG_WRN("Invalid Connection"); + return -ENOTCONN; + } + + if (!l2cap_ctx) { + LOG_WRN("Invalid context"); + return -EINVAL; + } + + *l2cap_ctx = NULL; + + ctx = find_free_l2cap_ctx(); + if (!ctx) { + return -ENOMEM; + } + + l2cap_chan_init(&ctx->ot_chan); + (void)memset(&ctx->tx, 0, sizeof(ctx->tx)); + + LOG_DBG("Connecting L2CAP CoC"); + err = bt_l2cap_chan_connect(conn, &ctx->ot_chan.chan, BT_GATT_OTS_L2CAP_PSM); + if (err) { + LOG_WRN("Unable to connect to psm %u (err %d)", BT_GATT_OTS_L2CAP_PSM, err); + } else { + LOG_DBG("L2CAP connection pending"); + *l2cap_ctx = ctx; + } + + return err; +} + +int bt_gatt_ots_l2cap_disconnect(struct bt_gatt_ots_l2cap *l2cap_ctx) +{ + return bt_l2cap_chan_disconnect(&l2cap_ctx->ot_chan.chan); +} + +SYS_INIT(bt_gatt_ots_l2cap_init, APPLICATION, + CONFIG_APPLICATION_INIT_PRIORITY); diff --git a/components/bt/esp_ble_audio/host/services/ots/ots_l2cap_internal.h b/components/bt/esp_ble_audio/host/services/ots/ots_l2cap_internal.h new file mode 100644 index 0000000000..765c0f8853 --- /dev/null +++ b/components/bt/esp_ble_audio/host/services/ots/ots_l2cap_internal.h @@ -0,0 +1,73 @@ +/* + * SPDX-FileCopyrightText: 2020-2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef BT_GATT_OTS_L2CAP_H_ +#define BT_GATT_OTS_L2CAP_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#include + +struct bt_gatt_ots_l2cap_tx { + uint8_t *data; + uint32_t len; + uint32_t len_sent; +}; + +struct bt_gatt_ots_l2cap { + sys_snode_t node; + struct bt_l2cap_le_chan ot_chan; + struct bt_gatt_ots_l2cap_tx tx; + void (*tx_done)(struct bt_gatt_ots_l2cap *l2cap_ctx, + struct bt_conn *conn); + ssize_t (*rx_done)(struct bt_gatt_ots_l2cap *l2cap_ctx, + struct bt_conn *conn, struct net_buf *buf); + void (*closed)(struct bt_gatt_ots_l2cap *l2cap_ctx, + struct bt_conn *conn); +}; + +bool bt_gatt_ots_l2cap_is_open(struct bt_gatt_ots_l2cap *l2cap_ctx, + struct bt_conn *conn); + +int bt_gatt_ots_l2cap_send(struct bt_gatt_ots_l2cap *l2cap_ctx, + uint8_t *data, + uint32_t len); + +int bt_gatt_ots_l2cap_register(struct bt_gatt_ots_l2cap *l2cap_ctx); + +int bt_gatt_ots_l2cap_unregister(struct bt_gatt_ots_l2cap *l2cap_ctx); + +/** @brief Connect OTS L2CAP channel + * + * This function is for the OTS client to make an L2CAP connection to + * the OTS server. One of the available registered L2CAP contexts + * will be used for the connection. + * + * @param[in] conn Connection pointer + * @param[out] l2cap_ctx The context that was connected + * + * @return 0 in case of success or negative value in case of error + */ +int bt_gatt_ots_l2cap_connect(struct bt_conn *conn, + struct bt_gatt_ots_l2cap **l2cap_ctx); + +int bt_gatt_ots_l2cap_disconnect(struct bt_gatt_ots_l2cap *l2cap_ctx); + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* BT_GATT_OTS_L2CAP_H_ */ diff --git a/components/bt/esp_ble_audio/host/services/ots/ots_oacp.c b/components/bt/esp_ble_audio/host/services/ots/ots_oacp.c new file mode 100644 index 0000000000..d135c1cb5d --- /dev/null +++ b/components/bt/esp_ble_audio/host/services/ots/ots_oacp.c @@ -0,0 +1,754 @@ +/* + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "ots_internal.h" +#include "ots_dir_list_internal.h" +#include "ots_obj_manager_internal.h" + +#include + +LOG_MODULE_DECLARE(bt_ots, CONFIG_BT_OTS_LOG_LEVEL); + +#define OACP_PROC_TYPE_SIZE 1 + +#if defined(CONFIG_BT_OTS_OACP_WRITE_SUPPORT) +static ssize_t oacp_write_proc_cb(struct bt_gatt_ots_l2cap *l2cap_ctx, + struct bt_conn *conn, struct net_buf *buf); +#endif + +static void oacp_l2cap_closed(struct bt_gatt_ots_l2cap *l2cap_ctx, + struct bt_conn *conn) +{ + struct bt_ots *ots; + + ots = CONTAINER_OF(l2cap_ctx, struct bt_ots, l2cap); + + if (!ots->cur_obj) { + return; + } + + ots->cur_obj->state.type = BT_GATT_OTS_OBJECT_IDLE_STATE; + l2cap_ctx->rx_done = NULL; + l2cap_ctx->tx_done = NULL; +} + +#if defined(CONFIG_BT_OTS_OACP_CREATE_SUPPORT) +static enum bt_gatt_ots_oacp_res_code oacp_create_proc_validate( + struct bt_conn *conn, + struct bt_ots *ots, + struct bt_gatt_ots_oacp_proc *proc) +{ + char str[BT_UUID_STR_LEN]; + int err; + struct bt_gatt_ots_object *obj; + const struct bt_ots_obj_add_param param = { + .size = proc->create_params.size, + .type = proc->create_params.type, + }; + + bt_uuid_to_str(¶m.type.uuid, str, BT_UUID_STR_LEN); + LOG_DBG("Validating Create procedure with size: 0x%08X and " + "type: %s", param.size, str); + + if (!BT_OTS_OACP_GET_FEAT_CREATE(ots->features.oacp)) { + LOG_DBG("Create Procedure is not supported."); + return BT_GATT_OTS_OACP_RES_OPCODE_NOT_SUP; + } + + err = bt_ots_obj_add_internal(ots, conn, ¶m, &obj); + if (err) { + goto exit; + } + + /* Verify Initialization Metadata */ + if (strlen(obj->metadata.name) > 0) { + LOG_ERR("Object name shall be a zero length string after object creation."); + (void)bt_ots_obj_delete(ots, obj->id); + err = -ECANCELED; + goto exit; + } + + if (obj->metadata.size.cur > 0) { + LOG_ERR("Object current size must be 0."); + (void)bt_ots_obj_delete(ots, obj->id); + err = -ECANCELED; + goto exit; + } + + if (!BT_OTS_OBJ_GET_PROP_WRITE(obj->metadata.props)) { + LOG_ERR("Created object must have write property."); + (void)bt_ots_obj_delete(ots, obj->id); + err = -ECANCELED; + goto exit; + } + + ots->cur_obj = obj; + ots->cur_obj->state.type = BT_GATT_OTS_OBJECT_IDLE_STATE; + + LOG_DBG("Create procedure is complete"); + +exit: + switch (err) { + case 0: + return BT_GATT_OTS_OACP_RES_SUCCESS; + case -ENOTSUP: + return BT_GATT_OTS_OACP_RES_UNSUP_TYPE; + case -ENOMEM: + return BT_GATT_OTS_OACP_RES_INSUFF_RES; + case -EINVAL: + return BT_GATT_OTS_OACP_RES_INV_PARAM; + case -ECANCELED: + default: + return BT_GATT_OTS_OACP_RES_OPER_FAILED; + } +} +#endif + +#if defined(CONFIG_BT_OTS_OACP_DELETE_SUPPORT) +static enum bt_gatt_ots_oacp_res_code oacp_delete_proc_validate( + struct bt_conn *conn, + struct bt_ots *ots, + struct bt_gatt_ots_oacp_proc *proc) +{ + int err; + + if (!BT_OTS_OACP_GET_FEAT_DELETE(ots->features.oacp)) { + LOG_DBG("Delete Procedure is not supported."); + return BT_GATT_OTS_OACP_RES_OPCODE_NOT_SUP; + } + + if (!ots->cur_obj) { + LOG_DBG("No object is selected."); + return BT_GATT_OTS_OACP_RES_INV_OBJ; + } + + if (!BT_OTS_OBJ_GET_PROP_DELETE(ots->cur_obj->metadata.props)) { + LOG_DBG("Object properties do not permit deletion."); + return BT_GATT_OTS_OACP_RES_NOT_PERMITTED; + } + + err = bt_ots_obj_delete(ots, ots->cur_obj->id); + if (err) { + LOG_ERR("Deleting object during Delete procedure failed: %d", err); + goto exit; + } + + LOG_DBG("Delete procedure is complete"); + +exit: + switch (err) { + case 0: + return BT_GATT_OTS_OACP_RES_SUCCESS; + case -EBUSY: + return BT_GATT_OTS_OACP_RES_OBJ_LOCKED; + default: + return BT_GATT_OTS_OACP_RES_OPER_FAILED; + } +} +#endif + +#if defined(CONFIG_BT_OTS_OACP_CHECKSUM_SUPPORT) +static enum bt_gatt_ots_oacp_res_code oacp_checksum_proc_validate( + struct bt_conn *conn, + struct bt_ots *ots, + struct bt_gatt_ots_oacp_proc *proc, + struct net_buf_simple *resp_param) +{ + struct bt_gatt_ots_oacp_cs_calc_params *params = &proc->cs_calc_params; + void *obj_data; + int err; + uint32_t checksum; + + LOG_DBG("Validating Checksum procedure with offset: 0x%08X and " + "length: 0x%08X", params->offset, params->len); + + if (!ots->cur_obj) { + return BT_GATT_OTS_OACP_RES_INV_OBJ; + } + + if (params->offset > ots->cur_obj->metadata.size.cur) { + return BT_GATT_OTS_OACP_RES_INV_PARAM; + } + + if ((params->offset + (uint64_t) params->len) > ots->cur_obj->metadata.size.cur) { + return BT_GATT_OTS_OACP_RES_INV_PARAM; + } + + if (ots->cur_obj->state.type != BT_GATT_OTS_OBJECT_IDLE_STATE) { + return BT_GATT_OTS_OACP_RES_OBJ_LOCKED; + } + + if (ots->cb->obj_cal_checksum) { + err = ots->cb->obj_cal_checksum(ots, conn, ots->cur_obj->id, params->offset, + params->len, &obj_data); + if (err != 0) { + return BT_GATT_OTS_OACP_RES_OPER_FAILED; + } + + checksum = bt_ots_client_calc_checksum((const uint8_t *)obj_data, params->len); + net_buf_simple_add_le32(resp_param, checksum); + LOG_DBG("Calculate from offset %u len %u checksum 0x%08x", params->offset, + params->len, checksum); + return BT_GATT_OTS_OACP_RES_SUCCESS; + } else { + return BT_GATT_OTS_OACP_RES_OPER_FAILED; + } +} +#endif + +static enum bt_gatt_ots_oacp_res_code oacp_read_proc_validate( + struct bt_conn *conn, + struct bt_ots *ots, + const struct bt_gatt_ots_oacp_proc *proc) +{ + const struct bt_gatt_ots_oacp_read_params *params = &proc->read_params; + + LOG_DBG("Validating Read procedure with offset: 0x%08X and " + "length: 0x%08X", params->offset, params->len); + + if (!ots->cur_obj) { + return BT_GATT_OTS_OACP_RES_INV_OBJ; + } + + if (!BT_OTS_OBJ_GET_PROP_READ(ots->cur_obj->metadata.props)) { + return BT_GATT_OTS_OACP_RES_NOT_PERMITTED; + } + + if (!bt_gatt_ots_l2cap_is_open(&ots->l2cap, conn)) { + return BT_GATT_OTS_OACP_RES_CHAN_UNAVAIL; + } + + if ((params->offset + (uint64_t) params->len) > + ots->cur_obj->metadata.size.cur) { + return BT_GATT_OTS_OACP_RES_INV_PARAM; + } + + if (ots->cur_obj->state.type != BT_GATT_OTS_OBJECT_IDLE_STATE) { + return BT_GATT_OTS_OACP_RES_OBJ_LOCKED; + } + + ots->cur_obj->state.type = BT_GATT_OTS_OBJECT_READ_OP_STATE; + ots->cur_obj->state.read_op.sent_len = 0; + memcpy(&ots->cur_obj->state.read_op.oacp_params, &proc->read_params, + sizeof(ots->cur_obj->state.read_op.oacp_params)); + + LOG_DBG("Read procedure is accepted"); + + return BT_GATT_OTS_OACP_RES_SUCCESS; +} + +#if defined(CONFIG_BT_OTS_OACP_WRITE_SUPPORT) +static enum bt_gatt_ots_oacp_res_code oacp_write_proc_validate( + struct bt_conn *conn, + struct bt_ots *ots, + struct bt_gatt_ots_oacp_proc *proc) +{ + struct bt_gatt_ots_oacp_write_params *params = &proc->write_params; + + LOG_DBG("Validating Write procedure with offset: 0x%08X and " + "length: 0x%08X", params->offset, params->len); + + if (!ots->cur_obj) { + return BT_GATT_OTS_OACP_RES_INV_OBJ; + } + + if (!BT_OTS_OACP_GET_FEAT_WRITE(ots->features.oacp)) { + LOG_DBG("Write Procedure is not supported."); + return BT_GATT_OTS_OACP_RES_OPCODE_NOT_SUP; + } + + if (!BT_OTS_OBJ_GET_PROP_WRITE(ots->cur_obj->metadata.props)) { + return BT_GATT_OTS_OACP_RES_NOT_PERMITTED; + } + + /* patching is attempted */ + if (params->offset < ots->cur_obj->metadata.size.cur) { + if (!BT_OTS_OACP_GET_FEAT_PATCH(ots->features.oacp)) { + return BT_GATT_OTS_OACP_RES_NOT_PERMITTED; + } + if (!BT_OTS_OBJ_GET_PROP_PATCH(ots->cur_obj->metadata.props)) { + return BT_GATT_OTS_OACP_RES_NOT_PERMITTED; + } + } + + /* truncation is not supported */ + if (BT_GATT_OTS_OACP_PROC_WRITE_MODE_GET_TRUNC(params->mode)) { + return BT_GATT_OTS_OACP_RES_NOT_PERMITTED; + } + + if (!bt_gatt_ots_l2cap_is_open(&ots->l2cap, conn)) { + return BT_GATT_OTS_OACP_RES_CHAN_UNAVAIL; + } + + if (BT_GATT_OTS_OACP_PROC_WRITE_MODE_GET_RFU(params->mode)) { + return BT_GATT_OTS_OACP_RES_INV_PARAM; + } + + if (params->offset > ots->cur_obj->metadata.size.cur) { + return BT_GATT_OTS_OACP_RES_INV_PARAM; + } + + /* append is not supported */ + if ((params->offset + (uint64_t) params->len) > ots->cur_obj->metadata.size.cur) { + return BT_GATT_OTS_OACP_RES_INV_PARAM; + } + + if (ots->cur_obj->state.type != BT_GATT_OTS_OBJECT_IDLE_STATE) { + return BT_GATT_OTS_OACP_RES_OBJ_LOCKED; + } + + ots->l2cap.rx_done = oacp_write_proc_cb; + ots->l2cap.closed = oacp_l2cap_closed; + ots->cur_obj->state.type = BT_GATT_OTS_OBJECT_WRITE_OP_STATE; + ots->cur_obj->state.write_op.recv_len = 0; + memcpy(&ots->cur_obj->state.write_op.oacp_params, params, + sizeof(ots->cur_obj->state.write_op.oacp_params)); + + LOG_DBG("Write procedure is accepted"); + + return BT_GATT_OTS_OACP_RES_SUCCESS; +} +#endif + +static enum bt_gatt_ots_oacp_res_code oacp_proc_validate( + struct bt_conn *conn, + struct bt_ots *ots, + struct bt_gatt_ots_oacp_proc *proc, + struct net_buf_simple *resp_param) +{ + switch (proc->type) { + case BT_GATT_OTS_OACP_PROC_READ: + return oacp_read_proc_validate(conn, ots, proc); +#if defined(CONFIG_BT_OTS_OACP_WRITE_SUPPORT) + case BT_GATT_OTS_OACP_PROC_WRITE: + return oacp_write_proc_validate(conn, ots, proc); +#endif +#if defined(CONFIG_BT_OTS_OACP_CREATE_SUPPORT) + case BT_GATT_OTS_OACP_PROC_CREATE: + return oacp_create_proc_validate(conn, ots, proc); +#endif +#if defined(CONFIG_BT_OTS_OACP_DELETE_SUPPORT) + case BT_GATT_OTS_OACP_PROC_DELETE: + return oacp_delete_proc_validate(conn, ots, proc); +#endif +#if defined(CONFIG_BT_OTS_OACP_CHECKSUM_SUPPORT) + case BT_GATT_OTS_OACP_PROC_CHECKSUM_CALC: + return oacp_checksum_proc_validate(conn, ots, proc, resp_param); +#endif + case BT_GATT_OTS_OACP_PROC_EXECUTE: + case BT_GATT_OTS_OACP_PROC_ABORT: + default: + return BT_GATT_OTS_OACP_RES_OPCODE_NOT_SUP; + } +}; + +static int oacp_command_decode(const uint8_t *buf, uint16_t len, + struct bt_gatt_ots_oacp_proc *proc) +{ + struct net_buf_simple net_buf; + + if (len < OACP_PROC_TYPE_SIZE) { + return -ENODATA; + } + + net_buf_simple_init_with_data(&net_buf, (void *) buf, len); + + proc->type = net_buf_simple_pull_u8(&net_buf); + switch (proc->type) { +#if defined(CONFIG_BT_OTS_OACP_CREATE_SUPPORT) + case BT_GATT_OTS_OACP_PROC_CREATE: + if (net_buf.len < BT_GATT_OTS_OACP_CREATE_GENERIC_PARAMS_SIZE) { + return -EBADMSG; + } + proc->create_params.size = net_buf_simple_pull_le32(&net_buf); + if (!bt_uuid_create(&proc->create_params.type.uuid, net_buf.data, + net_buf.len)) { + return -EBADMSG; + } + net_buf_simple_pull_mem(&net_buf, net_buf.len); + + /* Only 16-bit and 128-bit UUIDs are supported */ + switch (proc->create_params.type.uuid.type) { + case BT_UUID_TYPE_16: + case BT_UUID_TYPE_128: + return 0; + default: + break; + } + + return -EBADMSG; +#endif +#if defined(CONFIG_BT_OTS_OACP_DELETE_SUPPORT) + case BT_GATT_OTS_OACP_PROC_DELETE: + if (net_buf.len != 0) { + return -EBADMSG; + } + + return 0; +#endif +#if defined(CONFIG_BT_OTS_OACP_CHECKSUM_SUPPORT) + case BT_GATT_OTS_OACP_PROC_CHECKSUM_CALC: + if (net_buf.len != BT_GATT_OTS_OACP_CS_CALC_PARAMS_SIZE) { + return -EBADMSG; + } + proc->cs_calc_params.offset = + net_buf_simple_pull_le32(&net_buf); + proc->cs_calc_params.len = + net_buf_simple_pull_le32(&net_buf); + + return 0; +#endif + case BT_GATT_OTS_OACP_PROC_EXECUTE: + if (net_buf.len != 0) { + return -EBADMSG; + } + + return 0; + case BT_GATT_OTS_OACP_PROC_READ: + if (net_buf.len != BT_GATT_OTS_OACP_READ_PARAMS_SIZE) { + return -EBADMSG; + } + proc->read_params.offset = + net_buf_simple_pull_le32(&net_buf); + proc->read_params.len = + net_buf_simple_pull_le32(&net_buf); + + return 0; +#if defined(CONFIG_BT_OTS_OACP_WRITE_SUPPORT) + case BT_GATT_OTS_OACP_PROC_WRITE: + if (net_buf.len != BT_GATT_OTS_OACP_WRITE_PARAMS_SIZE) { + return -EBADMSG; + } + proc->write_params.offset = + net_buf_simple_pull_le32(&net_buf); + proc->write_params.len = + net_buf_simple_pull_le32(&net_buf); + proc->write_params.mode = + net_buf_simple_pull_u8(&net_buf); + + return 0; +#endif + case BT_GATT_OTS_OACP_PROC_ABORT: + default: + break; + } + + return -ENOTSUP; +} + +static void oacp_read_proc_cb(struct bt_gatt_ots_l2cap *l2cap_ctx, + struct bt_conn *conn) +{ + int err; + void *obj_chunk; + off_t offset; + ssize_t len; + struct bt_ots *ots; + struct bt_gatt_ots_object_read_op *read_op; + + ots = CONTAINER_OF(l2cap_ctx, struct bt_ots, l2cap); + + if (!ots->cur_obj) { + LOG_ERR("OTS Read operation failed: no current object"); + return; + } + + if (ots->cb->obj_read == NULL && + !(IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ) && ots->cur_obj->id == OTS_OBJ_ID_DIR_LIST)) { + ots->cur_obj->state.type = BT_GATT_OTS_OBJECT_IDLE_STATE; + LOG_ERR("OTS Read operation failed: there is no OTS Read callback"); + + return; + } + + read_op = &ots->cur_obj->state.read_op; + offset = read_op->oacp_params.offset + read_op->sent_len; + + if (read_op->sent_len >= read_op->oacp_params.len) { + LOG_DBG("OACP Read Op over L2CAP is completed"); + + if (read_op->sent_len > read_op->oacp_params.len) { + LOG_WRN("More bytes sent that the client requested"); + } + + ots->cur_obj->state.type = BT_GATT_OTS_OBJECT_IDLE_STATE; + + if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ) && + ots->cur_obj->id == OTS_OBJ_ID_DIR_LIST) { + return; + } + + ots->cb->obj_read(ots, conn, ots->cur_obj->id, NULL, 0, + offset); + return; + } + + len = read_op->oacp_params.len - read_op->sent_len; + if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ) && + ots->cur_obj->id == OTS_OBJ_ID_DIR_LIST) { + len = bt_ots_dir_list_content_get(ots->dir_list, ots->obj_manager, + &obj_chunk, len, offset); + } else { + len = ots->cb->obj_read(ots, conn, ots->cur_obj->id, &obj_chunk, + len, offset); + } + + if (len < 0) { + LOG_ERR("OCAP Read Op failed with error: %zd", len); + + bt_gatt_ots_l2cap_disconnect(&ots->l2cap); + ots->cur_obj->state.type = BT_GATT_OTS_OBJECT_IDLE_STATE; + + return; + } + + ots->l2cap.tx_done = oacp_read_proc_cb; + ots->l2cap.closed = oacp_l2cap_closed; + err = bt_gatt_ots_l2cap_send(&ots->l2cap, obj_chunk, len); + if (err) { + LOG_ERR("L2CAP CoC error: %d while trying to execute OACP " + "Read procedure", err); + ots->cur_obj->state.type = BT_GATT_OTS_OBJECT_IDLE_STATE; + } else { + read_op->sent_len += len; + } +} + +static void oacp_read_proc_execute(struct bt_ots *ots, + struct bt_conn *conn) +{ + struct bt_gatt_ots_oacp_read_params *params; + + if (!ots->cur_obj) { + LOG_ERR("Invalid Current Object on OACP Read procedure"); + return; + } + + params = &ots->cur_obj->state.read_op.oacp_params; + + LOG_DBG("Executing Read procedure with offset: 0x%08X and " + "length: 0x%08X", params->offset, params->len); + + oacp_read_proc_cb(&ots->l2cap, conn); +} + +#if defined(CONFIG_BT_OTS_OACP_WRITE_SUPPORT) +static ssize_t oacp_write_proc_cb(struct bt_gatt_ots_l2cap *l2cap_ctx, + struct bt_conn *conn, struct net_buf *buf) +{ + struct bt_gatt_ots_object_write_op *write_op; + struct bt_ots *ots; + uint32_t offset; + size_t rem; + size_t len; + ssize_t rc; + + ots = CONTAINER_OF(l2cap_ctx, struct bt_ots, l2cap); + + if (!ots->cur_obj) { + LOG_ERR("Invalid Current Object on OACP Write procedure"); + return -ENODEV; + } + + if (!ots->cb->obj_write) { + LOG_ERR("OTS Write operation failed: " + "there is no OTS Write callback"); + ots->cur_obj->state.type = BT_GATT_OTS_OBJECT_IDLE_STATE; + return -ENODEV; + } + + write_op = &ots->cur_obj->state.write_op; + offset = write_op->oacp_params.offset + write_op->recv_len; + len = buf->len; + if (write_op->recv_len + len > write_op->oacp_params.len) { + LOG_WRN("More bytes received than the client indicated"); + len = write_op->oacp_params.len - write_op->recv_len; + } + rem = write_op->oacp_params.len - (write_op->recv_len + len); + + rc = ots->cb->obj_write(ots, conn, ots->cur_obj->id, buf->data, len, + (off_t)offset, rem); + + if (rc < 0) { + len = 0; + + /* + * Returning an EINPROGRESS return code results in the write buffer not being + * released by the l2cap layer. This is an unsupported use case at the moment. + */ + if (rc == -EINPROGRESS) { + LOG_ERR("Unsupported error code %zd returned by object write callback", rc); + } + + LOG_ERR("OTS Write operation failed with error: %zd", rc); + ots->cur_obj->state.type = BT_GATT_OTS_OBJECT_IDLE_STATE; + } else { + /* Return -EIO as an error if all of data was not written */ + if (rc != len) { + len = 0; + rc = -EIO; + LOG_ERR("OTS Write operation partially failed"); + ots->cur_obj->state.type = BT_GATT_OTS_OBJECT_IDLE_STATE; + } + } + + write_op->recv_len += len; + if (write_op->recv_len == write_op->oacp_params.len) { + LOG_DBG("OACP Write Op over L2CAP is completed"); + ots->cur_obj->state.type = BT_GATT_OTS_OBJECT_IDLE_STATE; + } + + if (offset + len > ots->cur_obj->metadata.size.cur) { + ots->cur_obj->metadata.size.cur = offset + len; + } + + return rc; +} +#endif + +static void oacp_ind_cb(struct bt_conn *conn, + struct bt_gatt_indicate_params *params, + uint8_t err) +{ + struct bt_ots *ots = (struct bt_ots *) params->attr->user_data; + + LOG_DBG("Received OACP Indication ACK with status: 0x%04X", err); + + if (!ots->cur_obj) { + LOG_DBG("There is no object associated with this ACK"); + return; + } + + switch (ots->cur_obj->state.type) { + case BT_GATT_OTS_OBJECT_READ_OP_STATE: + oacp_read_proc_execute(ots, conn); + break; + case BT_GATT_OTS_OBJECT_WRITE_OP_STATE: + /* procedure execution is driven by L2CAP socket receive */ + break; + case BT_GATT_OTS_OBJECT_IDLE_STATE: + /* procedure is not in progress and was already completed */ + break; + default: + LOG_ERR("Unsupported OTS state: %d", ots->cur_obj->state.type); + break; + } +} + +static void oacp_ind_send(const struct bt_gatt_attr *oacp_attr, + struct bt_gatt_ots_oacp_proc oacp_proc, + enum bt_gatt_ots_oacp_res_code oacp_status, + struct net_buf_simple *resp_param) +{ + struct bt_ots *ots = (struct bt_ots *) oacp_attr->user_data; + uint8_t *oacp_res = ots->oacp_ind.res; + uint16_t oacp_res_len = 0; + + /* Encode OACP Response */ + oacp_res[oacp_res_len++] = BT_GATT_OTS_OACP_PROC_RESP; + oacp_res[oacp_res_len++] = oacp_proc.type; + oacp_res[oacp_res_len++] = oacp_status; + + if (oacp_proc.type == BT_GATT_OTS_OACP_PROC_CHECKSUM_CALC && + oacp_status == BT_GATT_OTS_OACP_RES_SUCCESS) { + sys_put_le32(net_buf_simple_pull_le32(resp_param), (oacp_res + oacp_res_len)); + oacp_res_len += sizeof(uint32_t); + } + + /* Prepare indication parameters */ + memset(&ots->oacp_ind.params, 0, sizeof(ots->oacp_ind.params)); + memcpy(&ots->oacp_ind.attr, oacp_attr, sizeof(ots->oacp_ind.attr)); + ots->oacp_ind.params.attr = &ots->oacp_ind.attr; + ots->oacp_ind.params.func = oacp_ind_cb; + ots->oacp_ind.params.data = oacp_res; + ots->oacp_ind.params.len = oacp_res_len; + + LOG_DBG("Sending OACP indication"); + + k_work_submit(&ots->oacp_ind.work); +} + +ssize_t bt_gatt_ots_oacp_write(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, + uint16_t offset, uint8_t flags) +{ + enum bt_gatt_ots_oacp_res_code oacp_status; + int decode_status; + struct bt_gatt_ots_oacp_proc oacp_proc = {0}; + struct bt_ots *ots = (struct bt_ots *) attr->user_data; + NET_BUF_SIMPLE_DEFINE(resp_param, sizeof(uint32_t)); + + LOG_DBG("Object Action Control Point GATT Write Operation"); + + if (!ots->oacp_ind.is_enabled) { + LOG_WRN("OACP indications not enabled"); + return BT_GATT_ERR(BT_ATT_ERR_CCC_IMPROPER_CONF); + } + + if (offset != 0) { + LOG_ERR("Invalid offset of OACP Write Request"); + return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); + } + + if (k_work_is_pending(&ots->oacp_ind.work)) { + LOG_ERR("OACP Write received before indication sent"); + return BT_GATT_ERR(BT_ATT_ERR_PROCEDURE_IN_PROGRESS); + } + + decode_status = oacp_command_decode(buf, len, &oacp_proc); + switch (decode_status) { + case 0: + oacp_status = oacp_proc_validate(conn, ots, &oacp_proc, &resp_param); + if (oacp_status != BT_GATT_OTS_OACP_RES_SUCCESS) { + LOG_WRN("OACP Write error status: 0x%02X", oacp_status); + } + break; + case -ENOTSUP: + oacp_status = BT_GATT_OTS_OACP_RES_OPCODE_NOT_SUP; + LOG_WRN("OACP unsupported procedure type: 0x%02X", oacp_proc.type); + break; + case -EBADMSG: + LOG_ERR("Invalid length of OACP Write Request for 0x%02X " + "Op Code", oacp_proc.type); + return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + case -ENODATA: + LOG_ERR("Invalid length of OACP Write Request"); + return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + default: + LOG_ERR("Invalid return code from oacp_command_decode: %d", decode_status); + return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY); + } + + oacp_ind_send(attr, oacp_proc, oacp_status, &resp_param); + return len; +} + +void bt_gatt_ots_oacp_cfg_changed(const struct bt_gatt_attr *attr, + uint16_t value) +{ + struct bt_gatt_ots_indicate *oacp_ind = + CONTAINER_OF((struct bt_gatt_ccc_managed_user_data *) attr->user_data, + struct bt_gatt_ots_indicate, ccc); + + LOG_DBG("Object Action Control Point CCCD value: 0x%04X", value); + + oacp_ind->is_enabled = false; + if (value == BT_GATT_CCC_INDICATE) { + oacp_ind->is_enabled = true; + } +} diff --git a/components/bt/esp_ble_audio/host/services/ots/ots_oacp_internal.h b/components/bt/esp_ble_audio/host/services/ots/ots_oacp_internal.h new file mode 100644 index 0000000000..a72f3e61f5 --- /dev/null +++ b/components/bt/esp_ble_audio/host/services/ots/ots_oacp_internal.h @@ -0,0 +1,119 @@ +/* + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef BT_GATT_OTS_OACP_H_ +#define BT_GATT_OTS_OACP_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +/* Types of Object Action Control Point Procedures. */ +enum bt_gatt_ots_oacp_proc_type { + /** Create object.*/ + BT_GATT_OTS_OACP_PROC_CREATE = 0x01, + /** Delete object.*/ + BT_GATT_OTS_OACP_PROC_DELETE = 0x02, + /** Calculate Checksum.*/ + BT_GATT_OTS_OACP_PROC_CHECKSUM_CALC = 0x03, + /** Execute Object.*/ + BT_GATT_OTS_OACP_PROC_EXECUTE = 0x04, + /** Read object.*/ + BT_GATT_OTS_OACP_PROC_READ = 0x05, + /** Write object.*/ + BT_GATT_OTS_OACP_PROC_WRITE = 0x06, + /** Abort object.*/ + BT_GATT_OTS_OACP_PROC_ABORT = 0x07, + /** Procedure response.*/ + BT_GATT_OTS_OACP_PROC_RESP = 0x60 +}; + +/* Object Action Control Point return codes. */ +enum bt_gatt_ots_oacp_res_code { + /** Success.*/ + BT_GATT_OTS_OACP_RES_SUCCESS = 0x01, + /** Not supported*/ + BT_GATT_OTS_OACP_RES_OPCODE_NOT_SUP = 0x02, + /** Invalid parameter*/ + BT_GATT_OTS_OACP_RES_INV_PARAM = 0x03, + /** Insufficient resources.*/ + BT_GATT_OTS_OACP_RES_INSUFF_RES = 0x04, + /** Invalid object.*/ + BT_GATT_OTS_OACP_RES_INV_OBJ = 0x05, + /** Channel unavailable.*/ + BT_GATT_OTS_OACP_RES_CHAN_UNAVAIL = 0x06, + /** Unsupported procedure.*/ + BT_GATT_OTS_OACP_RES_UNSUP_TYPE = 0x07, + /** Procedure not permitted.*/ + BT_GATT_OTS_OACP_RES_NOT_PERMITTED = 0x08, + /** Object locked.*/ + BT_GATT_OTS_OACP_RES_OBJ_LOCKED = 0x09, + /** Operation Failed.*/ + BT_GATT_OTS_OACP_RES_OPER_FAILED = 0x0A +}; + +#define BT_GATT_OTS_OACP_PROC_WRITE_MODE_TRUNC 1 + +#define BT_GATT_OTS_OACP_PROC_WRITE_MODE_GET_TRUNC(mode) \ + ((mode) & BIT(BT_GATT_OTS_OACP_PROC_WRITE_MODE_TRUNC)) + +#define BT_GATT_OTS_OACP_PROC_WRITE_MODE_GET_RFU(mode) \ + ((mode) & ~BIT(BT_GATT_OTS_OACP_PROC_WRITE_MODE_TRUNC)) + +/* Object Action Control Point procedure definition. */ +struct bt_gatt_ots_oacp_proc { + enum bt_gatt_ots_oacp_proc_type type; + union { + struct bt_gatt_ots_oacp_create_params { + uint32_t size; + struct bt_ots_obj_type type; + } create_params; + struct bt_gatt_ots_oacp_cs_calc_params { + uint32_t offset; + uint32_t len; + } cs_calc_params; + struct bt_gatt_ots_oacp_read_params { + uint32_t offset; + uint32_t len; + } read_params; + struct bt_gatt_ots_oacp_write_params { + uint32_t offset; + uint32_t len; + uint8_t mode; + } write_params; + }; +}; + +/* Size of the generic part of the Object Action Control Point create procedure */ +#define BT_GATT_OTS_OACP_CREATE_GENERIC_PARAMS_SIZE 4 + +/* Size of Object Action Control Point checksum calculation procedure */ +#define BT_GATT_OTS_OACP_CS_CALC_PARAMS_SIZE 8 + +/* Size of Object Action Control Point read procedure */ +#define BT_GATT_OTS_OACP_READ_PARAMS_SIZE 8 + +/* Size of Object Action Control Point write procedure */ +#define BT_GATT_OTS_OACP_WRITE_PARAMS_SIZE 9 + +ssize_t bt_gatt_ots_oacp_write(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, + uint16_t offset, uint8_t flags); + +void bt_gatt_ots_oacp_cfg_changed(const struct bt_gatt_attr *attr, + uint16_t value); + +#ifdef __cplusplus +} +#endif + +#endif /* BT_GATT_OTS_OACP_H_ */ diff --git a/components/bt/esp_ble_audio/host/services/ots/ots_obj_manager.c b/components/bt/esp_ble_audio/host/services/ots/ots_obj_manager.c new file mode 100644 index 0000000000..833336d428 --- /dev/null +++ b/components/bt/esp_ble_audio/host/services/ots/ots_obj_manager.c @@ -0,0 +1,259 @@ +/* + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include +#include "ots_internal.h" + +#include + +LOG_MODULE_DECLARE(bt_ots, CONFIG_BT_OTS_LOG_LEVEL); + +struct bt_gatt_ots_pool_item { + sys_dnode_t dnode; + struct bt_gatt_ots_object val; + bool is_allocated; +}; + +struct bt_gatt_ots_obj_manager { + sys_dlist_t list; + struct bt_gatt_ots_pool_item pool[CONFIG_BT_OTS_MAX_OBJ_CNT]; + bool is_assigned; +}; + +static uint64_t obj_id_to_index(uint64_t id) +{ + if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ)) { + if (id == OTS_OBJ_ID_DIR_LIST) { + return id; + } else { + return id - BT_OTS_OBJ_ID_MIN + 1; + } + } else { + return id - BT_OTS_OBJ_ID_MIN; + } +} + +static uint64_t obj_index_to_id(uint64_t index) +{ + if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ)) { + if (index == 0) { + return OTS_OBJ_ID_DIR_LIST; + } else { + return BT_OTS_OBJ_ID_MIN + index - 1; + } + } else { + return BT_OTS_OBJ_ID_MIN + index; + } +} + +int bt_gatt_ots_obj_manager_first_obj_get( + struct bt_gatt_ots_obj_manager *obj_manager, + struct bt_gatt_ots_object **obj) +{ + sys_dnode_t *obj_dnode; + struct bt_gatt_ots_pool_item *first_item; + + if (sys_dlist_is_empty(&obj_manager->list)) { + return -ENOENT; + } + + obj_dnode = sys_dlist_peek_head_not_empty(&obj_manager->list); + first_item = CONTAINER_OF(obj_dnode, struct bt_gatt_ots_pool_item, + dnode); + *obj = &first_item->val; + + return 0; +} + +int bt_gatt_ots_obj_manager_last_obj_get( + struct bt_gatt_ots_obj_manager *obj_manager, + struct bt_gatt_ots_object **obj) +{ + sys_dnode_t *obj_dnode; + struct bt_gatt_ots_pool_item *last_item; + + if (sys_dlist_is_empty(&obj_manager->list)) { + return -ENOENT; + } + + obj_dnode = sys_dlist_peek_tail(&obj_manager->list); + last_item = CONTAINER_OF(obj_dnode, struct bt_gatt_ots_pool_item, + dnode); + *obj = &last_item->val; + + return 0; +} + +int bt_gatt_ots_obj_manager_prev_obj_get( + struct bt_gatt_ots_obj_manager *obj_manager, + const struct bt_gatt_ots_object *cur_obj, + struct bt_gatt_ots_object **prev_obj) +{ + sys_dnode_t *prev_obj_dnode; + struct bt_gatt_ots_pool_item *cur_item, *prev_item; + + if (sys_dlist_is_empty(&obj_manager->list)) { + return -ENOENT; + } + + cur_item = CONTAINER_OF(cur_obj, struct bt_gatt_ots_pool_item, val); + prev_obj_dnode = sys_dlist_peek_prev_no_check(&obj_manager->list, + &cur_item->dnode); + if (!prev_obj_dnode) { + return -ENFILE; + } + + prev_item = CONTAINER_OF(prev_obj_dnode, + struct bt_gatt_ots_pool_item, + dnode); + *prev_obj = &prev_item->val; + + return 0; +} + +int bt_gatt_ots_obj_manager_next_obj_get( + struct bt_gatt_ots_obj_manager *obj_manager, + const struct bt_gatt_ots_object *cur_obj, + struct bt_gatt_ots_object **next_obj) +{ + sys_dnode_t *next_obj_dnode; + struct bt_gatt_ots_pool_item *cur_item, *next_item; + + if (sys_dlist_is_empty(&obj_manager->list)) { + return -ENOENT; + } + + cur_item = CONTAINER_OF(cur_obj, struct bt_gatt_ots_pool_item, val); + next_obj_dnode = sys_dlist_peek_next_no_check(&obj_manager->list, + &cur_item->dnode); + if (!next_obj_dnode) { + return -ENFILE; + } + + next_item = CONTAINER_OF(next_obj_dnode, + struct bt_gatt_ots_pool_item, + dnode); + *next_obj = &next_item->val; + + return 0; +} + +int bt_gatt_ots_obj_manager_obj_get( + struct bt_gatt_ots_obj_manager *obj_manager, uint64_t id, + struct bt_gatt_ots_object **object) +{ + uint64_t index; + + if (sys_dlist_is_empty(&obj_manager->list)) { + return -ENOENT; + } + + if (id == OTS_OBJ_ID_DIR_LIST && !IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ)) { + return -EINVAL; + } + + index = obj_id_to_index(id); + + if (index >= ARRAY_SIZE(obj_manager->pool)) { + return -EINVAL; + } + + if (!obj_manager->pool[index].is_allocated) { + return -EINVAL; + } + + *object = &obj_manager->pool[index].val; + + return 0; +} + +int bt_gatt_ots_obj_manager_obj_add( + struct bt_gatt_ots_obj_manager *obj_manager, + struct bt_gatt_ots_object **object) +{ + for (uint64_t i = 0; i < ARRAY_SIZE(obj_manager->pool); i++) { + struct bt_gatt_ots_pool_item *cur_obj = + &obj_manager->pool[i]; + + if (!cur_obj->is_allocated) { + cur_obj->is_allocated = true; + /* TODO: do we need to reset cur_obj->val to 0 here? */ + cur_obj->val.id = obj_index_to_id(i); + sys_dlist_append(&obj_manager->list, &cur_obj->dnode); + + *object = &cur_obj->val; + return 0; + } + } + + return -ENOMEM; +} + +int bt_gatt_ots_obj_manager_obj_delete(struct bt_gatt_ots_object *obj) +{ + struct bt_gatt_ots_pool_item *item; + + item = CONTAINER_OF(obj, struct bt_gatt_ots_pool_item, val); + + if (!item->is_allocated) { + return -EINVAL; + } + + if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ) && + obj->id == OTS_OBJ_ID_DIR_LIST) { + return -EINVAL; + } + + item->is_allocated = false; + sys_dlist_remove(&item->dnode); + + return 0; +} + +bool bt_gatt_ots_obj_manager_obj_contains(struct bt_gatt_ots_obj_manager *obj_manager, + struct bt_gatt_ots_object *obj) +{ + struct bt_gatt_ots_pool_item *item; + + item = CONTAINER_OF(obj, struct bt_gatt_ots_pool_item, val); + + return PART_OF_ARRAY(obj_manager->pool, item); +} + +void *bt_gatt_ots_obj_manager_assign(void) +{ + static struct bt_gatt_ots_obj_manager + obj_manager[CONFIG_BT_OTS_MAX_INST_CNT]; + struct bt_gatt_ots_obj_manager *cur_manager; + + for (cur_manager = obj_manager; + cur_manager != obj_manager + CONFIG_BT_OTS_MAX_INST_CNT; + cur_manager++) { + if (!cur_manager->is_assigned) { + break; + } + } + + if (cur_manager == obj_manager + CONFIG_BT_OTS_MAX_INST_CNT) { + return NULL; + } + + if (cur_manager->is_assigned) { + return NULL; + } + + cur_manager->is_assigned = true; + sys_dlist_init(&cur_manager->list); + + return cur_manager; +} diff --git a/components/bt/esp_ble_audio/host/services/ots/ots_obj_manager_internal.h b/components/bt/esp_ble_audio/host/services/ots/ots_obj_manager_internal.h new file mode 100644 index 0000000000..4bc2f5cba4 --- /dev/null +++ b/components/bt/esp_ble_audio/host/services/ots/ots_obj_manager_internal.h @@ -0,0 +1,49 @@ +/* + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef BT_GATT_OTS_OBJ_MANAGER_H_ +#define BT_GATT_OTS_OBJ_MANAGER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +int bt_gatt_ots_obj_manager_first_obj_get(void *obj_manager, + struct bt_gatt_ots_object **obj); + +int bt_gatt_ots_obj_manager_last_obj_get(void *obj_manager, + struct bt_gatt_ots_object **obj); + +int bt_gatt_ots_obj_manager_prev_obj_get( + void *obj_manager, + const struct bt_gatt_ots_object *cur_obj, + struct bt_gatt_ots_object **prev_obj); + +int bt_gatt_ots_obj_manager_next_obj_get( + void *obj_manager, + const struct bt_gatt_ots_object *cur_obj, + struct bt_gatt_ots_object **next_obj); + +int bt_gatt_ots_obj_manager_obj_get(void *obj_manager, + uint64_t id, + struct bt_gatt_ots_object **obj); + +int bt_gatt_ots_obj_manager_obj_add(void *obj_manager, + struct bt_gatt_ots_object **obj); + +int bt_gatt_ots_obj_manager_obj_delete(struct bt_gatt_ots_object *obj); + +bool bt_gatt_ots_obj_manager_obj_contains(void *obj_manager, struct bt_gatt_ots_object *obj); + +void *bt_gatt_ots_obj_manager_assign(void); + +#ifdef __cplusplus +} +#endif + +#endif /* BT_GATT_OTS_OBJ_MANAGER_H_ */ diff --git a/components/bt/esp_ble_audio/host/services/ots/ots_olcp.c b/components/bt/esp_ble_audio/host/services/ots/ots_olcp.c new file mode 100644 index 0000000000..95e3477ae0 --- /dev/null +++ b/components/bt/esp_ble_audio/host/services/ots/ots_olcp.c @@ -0,0 +1,322 @@ +/* + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include "ots_internal.h" +#include "ots_obj_manager_internal.h" +#include "ots_dir_list_internal.h" + +#include + +LOG_MODULE_DECLARE(bt_ots, CONFIG_BT_OTS_LOG_LEVEL); + +#define OLCP_PROC_TYPE_SIZE 1 + +static enum bt_gatt_ots_olcp_res_code obj_manager_to_olcp_err_map(int err) +{ + switch (-err) { + case EINVAL: + return BT_GATT_OTS_OLCP_RES_OBJECT_ID_NOT_FOUND; + case ENFILE: + return BT_GATT_OTS_OLCP_RES_OUT_OF_BONDS; + case ENOENT: + default: + return BT_GATT_OTS_OLCP_RES_NO_OBJECT; + } +} + +static enum bt_gatt_ots_olcp_res_code olcp_first_proc_execute( + struct bt_ots *ots) +{ + int err; + struct bt_gatt_ots_object *first_obj; + + err = bt_gatt_ots_obj_manager_first_obj_get(ots->obj_manager, + &first_obj); + if (err) { + return obj_manager_to_olcp_err_map(err); + } + + ots->cur_obj = first_obj; + + return BT_GATT_OTS_OLCP_RES_SUCCESS; +} + +static enum bt_gatt_ots_olcp_res_code olcp_last_proc_execute( + struct bt_ots *ots) +{ + int err; + struct bt_gatt_ots_object *last_obj; + + err = bt_gatt_ots_obj_manager_last_obj_get(ots->obj_manager, + &last_obj); + if (err) { + return obj_manager_to_olcp_err_map(err); + } + + ots->cur_obj = last_obj; + + return BT_GATT_OTS_OLCP_RES_SUCCESS; +} + +static enum bt_gatt_ots_olcp_res_code olcp_prev_proc_execute( + struct bt_ots *ots) +{ + int err; + struct bt_gatt_ots_object *prev_obj; + + if (!ots->cur_obj) { + return BT_GATT_OTS_OLCP_RES_OPERATION_FAILED; + } + err = bt_gatt_ots_obj_manager_prev_obj_get(ots->obj_manager, + ots->cur_obj, + &prev_obj); + if (err) { + return obj_manager_to_olcp_err_map(err); + } + + ots->cur_obj = prev_obj; + + return BT_GATT_OTS_OLCP_RES_SUCCESS; +} + +static enum bt_gatt_ots_olcp_res_code olcp_next_proc_execute( + struct bt_ots *ots) +{ + int err; + struct bt_gatt_ots_object *next_obj; + + if (!ots->cur_obj) { + return BT_GATT_OTS_OLCP_RES_OPERATION_FAILED; + } + err = bt_gatt_ots_obj_manager_next_obj_get(ots->obj_manager, + ots->cur_obj, + &next_obj); + if (err) { + return obj_manager_to_olcp_err_map(err); + } + + ots->cur_obj = next_obj; + + return BT_GATT_OTS_OLCP_RES_SUCCESS; +} + +static enum bt_gatt_ots_olcp_res_code olcp_goto_proc_execute( + struct bt_ots *ots, uint64_t id) +{ + int err; + struct bt_gatt_ots_object *id_obj; + + if (!BT_OTS_VALID_OBJ_ID(id)) { + LOG_DBG("Invalid object ID 0x%016llx", id); + + return BT_GATT_OTS_OLCP_RES_INVALID_PARAMETER; + } + + err = bt_gatt_ots_obj_manager_obj_get(ots->obj_manager, + id, + &id_obj); + if (err) { + return obj_manager_to_olcp_err_map(err); + } + + ots->cur_obj = id_obj; + + return BT_GATT_OTS_OLCP_RES_SUCCESS; +} + +static enum bt_gatt_ots_olcp_res_code olcp_proc_execute( + struct bt_ots *ots, struct bt_gatt_ots_olcp_proc *proc) +{ + LOG_DBG("Executing OLCP procedure with 0x%02X Op Code", proc->type); + + switch (proc->type) { + case BT_GATT_OTS_OLCP_PROC_FIRST: + return olcp_first_proc_execute(ots); + case BT_GATT_OTS_OLCP_PROC_LAST: + return olcp_last_proc_execute(ots); + case BT_GATT_OTS_OLCP_PROC_PREV: + return olcp_prev_proc_execute(ots); + case BT_GATT_OTS_OLCP_PROC_NEXT: + return olcp_next_proc_execute(ots); + case BT_GATT_OTS_OLCP_PROC_GOTO: + return olcp_goto_proc_execute(ots, proc->goto_params.id); + case BT_GATT_OTS_OLCP_PROC_ORDER: + case BT_GATT_OTS_OLCP_PROC_REQ_NUM_OBJS: + case BT_GATT_OTS_OLCP_PROC_CLEAR_MARKING: + default: + return BT_GATT_OTS_OLCP_RES_PROC_NOT_SUP; + } +}; + +static int olcp_command_decode(const uint8_t *buf, uint16_t len, + struct bt_gatt_ots_olcp_proc *proc) +{ + if (len < OLCP_PROC_TYPE_SIZE) { + return -ENODATA; + } + + memset(proc, 0, sizeof(*proc)); + + proc->type = *buf++; + len -= OLCP_PROC_TYPE_SIZE; + + switch (proc->type) { + case BT_GATT_OTS_OLCP_PROC_FIRST: + case BT_GATT_OTS_OLCP_PROC_LAST: + case BT_GATT_OTS_OLCP_PROC_PREV: + case BT_GATT_OTS_OLCP_PROC_NEXT: + if (len != 0) { + return -EBADMSG; + } + + return 0; + case BT_GATT_OTS_OLCP_PROC_GOTO: + if (len != BT_GATT_OTS_OLCP_GOTO_PARAMS_SIZE) { + return -EBADMSG; + } + proc->goto_params.id = sys_get_le48(buf); + + return 0; + default: + break; + } + + return -ENOTSUP; +} + +static void olcp_ind_cb(struct bt_conn *conn, + struct bt_gatt_indicate_params *params, + uint8_t err) +{ + LOG_DBG("Received OLCP Indication ACK with status: 0x%04X", err); +} + +static void olcp_ind_send(const struct bt_gatt_attr *olcp_attr, + enum bt_gatt_ots_olcp_proc_type req_op_code, + enum bt_gatt_ots_olcp_res_code olcp_status) +{ + struct bt_ots *ots = (struct bt_ots *) olcp_attr->user_data; + uint8_t *olcp_res = ots->olcp_ind.res; + uint16_t olcp_res_len = 0; + + /* Encode OLCP Response */ + olcp_res[olcp_res_len++] = BT_GATT_OTS_OLCP_PROC_RESP; + olcp_res[olcp_res_len++] = req_op_code; + olcp_res[olcp_res_len++] = olcp_status; + + /* Prepare indication parameters */ + memset(&ots->olcp_ind.params, 0, sizeof(ots->olcp_ind.params)); + memcpy(&ots->olcp_ind.attr, olcp_attr, sizeof(ots->olcp_ind.attr)); + ots->olcp_ind.params.attr = olcp_attr; + ots->olcp_ind.params.func = olcp_ind_cb; + ots->olcp_ind.params.data = olcp_res; + ots->olcp_ind.params.len = olcp_res_len; +#if defined(CONFIG_BT_EATT) + ots->olcp_ind.params.chan_opt = BT_ATT_CHAN_OPT_NONE; +#endif /* CONFIG_BT_EATT */ + + LOG_DBG("Sending OLCP indication"); + + k_work_submit(&ots->olcp_ind.work); +} + +ssize_t bt_gatt_ots_olcp_write(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, + uint16_t offset, uint8_t flags) +{ + struct bt_gatt_ots_object *old_obj; + enum bt_gatt_ots_olcp_res_code olcp_status; + int decode_status; + struct bt_gatt_ots_olcp_proc olcp_proc; + struct bt_ots *ots = (struct bt_ots *) attr->user_data; + + LOG_DBG("Object List Control Point GATT Write Operation"); + + if (!ots->olcp_ind.is_enabled) { + LOG_WRN("OLCP indications not enabled"); + return BT_GATT_ERR(BT_ATT_ERR_CCC_IMPROPER_CONF); + } + + if (offset != 0) { + LOG_ERR("Invalid offset of OLCP Write Request"); + return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); + } + + if (k_work_is_pending(&ots->olcp_ind.work)) { + LOG_ERR("OLCP Write received before indication sent"); + return BT_GATT_ERR(BT_ATT_ERR_PROCEDURE_IN_PROGRESS); + } + + old_obj = ots->cur_obj; + + decode_status = olcp_command_decode(buf, len, &olcp_proc); + switch (decode_status) { + case 0: + olcp_status = olcp_proc_execute(ots, &olcp_proc); + if (olcp_status != BT_GATT_OTS_OLCP_RES_SUCCESS) { + LOG_WRN("OLCP Write error status: 0x%02X", olcp_status); + } else if (old_obj != ots->cur_obj) { + char id[BT_OTS_OBJ_ID_STR_LEN]; + + bt_ots_obj_id_to_str(ots->cur_obj->id, id, + sizeof(id)); + LOG_DBG("Selecting a new Current Object with id: %s", + id); + + if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ)) { + bt_ots_dir_list_selected(ots->dir_list, ots->obj_manager, + ots->cur_obj); + } + + if (ots->cb->obj_selected) { + ots->cb->obj_selected(ots, conn, ots->cur_obj->id); + } + } + break; + case -ENOTSUP: + olcp_status = BT_GATT_OTS_OLCP_RES_PROC_NOT_SUP; + LOG_WRN("OLCP unsupported procedure type: 0x%02X", olcp_proc.type); + break; + case -EBADMSG: + LOG_ERR("Invalid length of OLCP Write Request for 0x%02X " + "Op Code", olcp_proc.type); + return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + case -ENODATA: + LOG_ERR("Invalid size of OLCP Write Request"); + return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + default: + LOG_ERR("Invalid return code from olcp_command_decode: %d", decode_status); + return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY); + } + + olcp_ind_send(attr, olcp_proc.type, olcp_status); + return len; +} + +void bt_gatt_ots_olcp_cfg_changed(const struct bt_gatt_attr *attr, + uint16_t value) +{ + struct bt_gatt_ots_indicate *olcp_ind = + CONTAINER_OF((struct bt_gatt_ccc_managed_user_data *) attr->user_data, + struct bt_gatt_ots_indicate, ccc); + + LOG_DBG("Object List Control Point CCCD value: 0x%04X", value); + + olcp_ind->is_enabled = false; + if (value == BT_GATT_CCC_INDICATE) { + olcp_ind->is_enabled = true; + } +} diff --git a/components/bt/esp_ble_audio/host/services/ots/ots_olcp_internal.h b/components/bt/esp_ble_audio/host/services/ots/ots_olcp_internal.h new file mode 100644 index 0000000000..d0fa74fb6f --- /dev/null +++ b/components/bt/esp_ble_audio/host/services/ots/ots_olcp_internal.h @@ -0,0 +1,122 @@ +/* + * SPDX-FileCopyrightText: 2020-2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef BT_GATT_OTS_OLCP_H_ +#define BT_GATT_OTS_OLCP_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/* The types of OLCP procedures. */ +enum bt_gatt_ots_olcp_proc_type { + /* Select the first object.*/ + BT_GATT_OTS_OLCP_PROC_FIRST = 0x01, + /* Select the last object.*/ + BT_GATT_OTS_OLCP_PROC_LAST = 0x02, + /* Select the previous object.*/ + BT_GATT_OTS_OLCP_PROC_PREV = 0x03, + /* Select the next object.*/ + BT_GATT_OTS_OLCP_PROC_NEXT = 0x04, + /* Select the object with the given object ID.*/ + BT_GATT_OTS_OLCP_PROC_GOTO = 0x05, + /* Order the objects.*/ + BT_GATT_OTS_OLCP_PROC_ORDER = 0x06, + /* Request the number of objects.*/ + BT_GATT_OTS_OLCP_PROC_REQ_NUM_OBJS = 0x07, + /* Clear Marking.*/ + BT_GATT_OTS_OLCP_PROC_CLEAR_MARKING = 0x08, + /* Response.*/ + BT_GATT_OTS_OLCP_PROC_RESP = 0x70, +}; + +/** @brief The types of OLCP sort orders. */ +enum bt_ots_olcp_sort_order { + /** Order the list by object name, ascending */ + BT_OTS_SORT_BY_NAME_ASCEND = 0x01, + /** Order the list by object type, ascending*/ + BT_OTS_SORT_BY_TYPE_ASCEND = 0x02, + /** Order the list by object current size, ascending*/ + BT_OTS_SORT_BY_SIZE_ASCEND = 0x03, + /** Order the list by object first-created timestamp, ascending*/ + BT_OTS_SORT_BY_FC_ASCEND = 0x04, + /** Order the list by object last-modified timestamp, ascending */ + BT_OTS_SORT_BY_LM_ASCEND = 0x05, + /** Order the list by object name, descending */ + BT_OTS_SORT_BY_NAME_DESCEND = 0x11, + /** Order the list by object type, descending*/ + BT_OTS_SORT_BY_TYPE_DESCEND = 0x12, + /** Order the list by object current size, descending*/ + BT_OTS_SORT_BY_SIZE_DESCEND = 0x13, + /** Order the list by object first-created timestamp, descending*/ + BT_OTS_SORT_BY_FC_DESCEND = 0x14, + /** Order the list by object last-modified timestamp, descending */ + BT_OTS_SORT_BY_LM_DESCEND = 0x15, +}; + +/* Definition of a OLCP procedure. */ +struct bt_gatt_ots_olcp_proc { + enum bt_gatt_ots_olcp_proc_type type; + union { + struct { + uint64_t id; + } goto_params; + }; +}; + +/* Size of Object List Control Point goto procedure */ +#define BT_GATT_OTS_OLCP_GOTO_PARAMS_SIZE 6 + +/* The return codes obtained from doing OLCP procedures. */ +enum bt_gatt_ots_olcp_res_code { + /* Response for successful operation. */ + BT_GATT_OTS_OLCP_RES_SUCCESS = 0x01, + /* Response if unsupported Op Code is received.*/ + BT_GATT_OTS_OLCP_RES_PROC_NOT_SUP = 0x02, + /* Response if Parameter received does not meet + * the requirements of the service. + */ + BT_GATT_OTS_OLCP_RES_INVALID_PARAMETER = 0x03, + /* Response if the requested procedure failed for a reason + * other than those enumerated below. + */ + BT_GATT_OTS_OLCP_RES_OPERATION_FAILED = 0x04, + /* Response if the requested procedure attempted to select an object + * beyond the first object or + * beyond the last object in the current list. + */ + BT_GATT_OTS_OLCP_RES_OUT_OF_BONDS = 0x05, + /* Response if the requested procedure failed due + * to too many objects in the current list. + */ + BT_GATT_OTS_OLCP_RES_TOO_MANY_OBJECTS = 0x06, + /* Response if the requested procedure failed due + * to there being zero objects in the current list. + */ + BT_GATT_OTS_OLCP_RES_NO_OBJECT = 0x07, + /* Response if the requested procedure failed due + * to there being no object with the requested Object ID. + */ + BT_GATT_OTS_OLCP_RES_OBJECT_ID_NOT_FOUND = 0x08, +}; + +ssize_t bt_gatt_ots_olcp_write(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, + uint16_t offset, uint8_t flags); + +void bt_gatt_ots_olcp_cfg_changed(const struct bt_gatt_attr *attr, + uint16_t value); + +#ifdef __cplusplus +} +#endif + +#endif /* BT_GATT_OTS_OLCP_H_ */ diff --git a/components/bt/esp_ble_audio/host/utils/addr.c b/components/bt/esp_ble_audio/host/utils/addr.c new file mode 100644 index 0000000000..b90472d8c5 --- /dev/null +++ b/components/bt/esp_ble_audio/host/utils/addr.c @@ -0,0 +1,12 @@ +/* + * SPDX-FileCopyrightText: 2022 Stephanos Ioannidis + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +const bt_addr_t bt_addr_any = { { 0, 0, 0, 0, 0, 0 } }; +const bt_addr_t bt_addr_none = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } }; +const bt_addr_le_t bt_addr_le_any = { 0, { { 0, 0, 0, 0, 0, 0 } } }; +const bt_addr_le_t bt_addr_le_none = { 0, { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } } }; diff --git a/components/bt/esp_ble_audio/host/utils/bt_str.c b/components/bt/esp_ble_audio/host/utils/bt_str.c new file mode 100644 index 0000000000..43054e7e93 --- /dev/null +++ b/components/bt/esp_ble_audio/host/utils/bt_str.c @@ -0,0 +1,152 @@ +/* + * SPDX-FileCopyrightText: 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Helper for printk parameters to convert from binary to hex. + * We declare multiple buffers so the helper can be used multiple times + * in a single printk call. + */ + +#include + +#include +#include +#include +#include +#include +#include + +const char *bt_hex(const void *buf, size_t len) +{ + static const char hex[] = "0123456789abcdef"; + static char str[129]; + const uint8_t *b = buf; + size_t i; + + len = MIN(len, (sizeof(str) - 1) / 2); + + for (i = 0; i < len; i++) { + str[i * 2] = hex[b[i] >> 4]; + str[i * 2 + 1] = hex[b[i] & 0xf]; + } + + str[i * 2] = '\0'; + + return str; +} + +const char *bt_addr_str(const bt_addr_t *addr) +{ + static char str[BT_ADDR_STR_LEN]; + + bt_addr_to_str(addr, str, sizeof(str)); + + return str; +} + +const char *bt_addr_le_str(const bt_addr_le_t *addr) +{ + static char str[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(addr, str, sizeof(str)); + + return str; +} + +const char *bt_uuid_str(const struct bt_uuid *uuid) +{ + static char str[BT_UUID_STR_LEN]; + + bt_uuid_to_str(uuid, str, sizeof(str)); + + return str; +} + +#if defined(CONFIG_BT_HCI_ERR_TO_STR) +const char *bt_hci_err_to_str(uint8_t hci_err) +{ +#define HCI_ERR(err) [err] = #err + + const char * const mapping_table[] = { + HCI_ERR(BT_HCI_ERR_SUCCESS), + HCI_ERR(BT_HCI_ERR_UNKNOWN_CMD), + HCI_ERR(BT_HCI_ERR_UNKNOWN_CONN_ID), + HCI_ERR(BT_HCI_ERR_HW_FAILURE), + HCI_ERR(BT_HCI_ERR_PAGE_TIMEOUT), + HCI_ERR(BT_HCI_ERR_AUTH_FAIL), + HCI_ERR(BT_HCI_ERR_PIN_OR_KEY_MISSING), + HCI_ERR(BT_HCI_ERR_MEM_CAPACITY_EXCEEDED), + HCI_ERR(BT_HCI_ERR_CONN_TIMEOUT), + HCI_ERR(BT_HCI_ERR_CONN_LIMIT_EXCEEDED), + HCI_ERR(BT_HCI_ERR_SYNC_CONN_LIMIT_EXCEEDED), + HCI_ERR(BT_HCI_ERR_CONN_ALREADY_EXISTS), + HCI_ERR(BT_HCI_ERR_CMD_DISALLOWED), + HCI_ERR(BT_HCI_ERR_INSUFFICIENT_RESOURCES), + HCI_ERR(BT_HCI_ERR_INSUFFICIENT_SECURITY), + HCI_ERR(BT_HCI_ERR_BD_ADDR_UNACCEPTABLE), + HCI_ERR(BT_HCI_ERR_CONN_ACCEPT_TIMEOUT), + HCI_ERR(BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL), + HCI_ERR(BT_HCI_ERR_INVALID_PARAM), + HCI_ERR(BT_HCI_ERR_REMOTE_USER_TERM_CONN), + HCI_ERR(BT_HCI_ERR_REMOTE_LOW_RESOURCES), + HCI_ERR(BT_HCI_ERR_REMOTE_POWER_OFF), + HCI_ERR(BT_HCI_ERR_LOCALHOST_TERM_CONN), + HCI_ERR(BT_HCI_ERR_REPEATED_ATTEMPTS), + HCI_ERR(BT_HCI_ERR_PAIRING_NOT_ALLOWED), + HCI_ERR(BT_HCI_ERR_UNKNOWN_LMP_PDU), + HCI_ERR(BT_HCI_ERR_UNSUPP_REMOTE_FEATURE), + HCI_ERR(BT_HCI_ERR_SCO_OFFSET_REJECTED), + HCI_ERR(BT_HCI_ERR_SCO_INTERVAL_REJECTED), + HCI_ERR(BT_HCI_ERR_SCO_AIR_MODE_REJECTED), + HCI_ERR(BT_HCI_ERR_INVALID_LL_PARAM), + HCI_ERR(BT_HCI_ERR_UNSPECIFIED), + HCI_ERR(BT_HCI_ERR_UNSUPP_LL_PARAM_VAL), + HCI_ERR(BT_HCI_ERR_ROLE_CHANGE_NOT_ALLOWED), + HCI_ERR(BT_HCI_ERR_LL_RESP_TIMEOUT), + HCI_ERR(BT_HCI_ERR_LL_PROC_COLLISION), + HCI_ERR(BT_HCI_ERR_LMP_PDU_NOT_ALLOWED), + HCI_ERR(BT_HCI_ERR_ENC_MODE_NOT_ACCEPTABLE), + HCI_ERR(BT_HCI_ERR_LINK_KEY_CANNOT_BE_CHANGED), + HCI_ERR(BT_HCI_ERR_REQUESTED_QOS_NOT_SUPPORTED), + HCI_ERR(BT_HCI_ERR_INSTANT_PASSED), + HCI_ERR(BT_HCI_ERR_PAIRING_NOT_SUPPORTED), + HCI_ERR(BT_HCI_ERR_DIFF_TRANS_COLLISION), + HCI_ERR(BT_HCI_ERR_QOS_UNACCEPTABLE_PARAM), + HCI_ERR(BT_HCI_ERR_QOS_REJECTED), + HCI_ERR(BT_HCI_ERR_CHAN_ASSESS_NOT_SUPPORTED), + HCI_ERR(BT_HCI_ERR_INSUFF_SECURITY), + HCI_ERR(BT_HCI_ERR_PARAM_OUT_OF_MANDATORY_RANGE), + HCI_ERR(BT_HCI_ERR_ROLE_SWITCH_PENDING), + HCI_ERR(BT_HCI_ERR_RESERVED_SLOT_VIOLATION), + HCI_ERR(BT_HCI_ERR_ROLE_SWITCH_FAILED), + HCI_ERR(BT_HCI_ERR_EXT_INQ_RESP_TOO_LARGE), + HCI_ERR(BT_HCI_ERR_SIMPLE_PAIR_NOT_SUPP_BY_HOST), + HCI_ERR(BT_HCI_ERR_HOST_BUSY_PAIRING), + HCI_ERR(BT_HCI_ERR_CONN_REJECTED_DUE_TO_NO_CHAN), + HCI_ERR(BT_HCI_ERR_CONTROLLER_BUSY), + HCI_ERR(BT_HCI_ERR_UNACCEPT_CONN_PARAM), + HCI_ERR(BT_HCI_ERR_ADV_TIMEOUT), + HCI_ERR(BT_HCI_ERR_TERM_DUE_TO_MIC_FAIL), + HCI_ERR(BT_HCI_ERR_CONN_FAIL_TO_ESTAB), + HCI_ERR(BT_HCI_ERR_MAC_CONN_FAILED), + HCI_ERR(BT_HCI_ERR_CLOCK_ADJUST_REJECTED), + HCI_ERR(BT_HCI_ERR_SUBMAP_NOT_DEFINED), + HCI_ERR(BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER), + HCI_ERR(BT_HCI_ERR_LIMIT_REACHED), + HCI_ERR(BT_HCI_ERR_OP_CANCELLED_BY_HOST), + HCI_ERR(BT_HCI_ERR_PACKET_TOO_LONG), + HCI_ERR(BT_HCI_ERR_TOO_LATE), + HCI_ERR(BT_HCI_ERR_TOO_EARLY), + }; + + if (hci_err < ARRAY_SIZE(mapping_table) && mapping_table[hci_err]) { + return mapping_table[hci_err]; + } else { + return "(unknown)"; + } + +#undef HCI_ERR +} +#endif /* CONFIG_BT_HCI_ERR_TO_STR */ diff --git a/components/bt/esp_ble_audio/host/utils/buf.c b/components/bt/esp_ble_audio/host/utils/buf.c new file mode 100644 index 0000000000..632046eda7 --- /dev/null +++ b/components/bt/esp_ble_audio/host/utils/buf.c @@ -0,0 +1,739 @@ +/* + * SPDX-FileCopyrightText: 2015 Intel Corporation + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include + +int net_buf_id(struct net_buf *buf) +{ + struct net_buf_pool *pool = buf->pool; + + return buf - pool->__bufs; +} + +static inline struct net_buf *pool_get_uninit(struct net_buf_pool *pool, + uint16_t uninit_count) +{ + struct net_buf *buf = NULL; + + buf = &pool->__bufs[pool->buf_count - uninit_count]; + + buf->pool = pool; + + return buf; +} + +void net_buf_simple_clone(const struct net_buf_simple *original, + struct net_buf_simple *clone) +{ + memcpy(clone, original, sizeof(struct net_buf_simple)); +} + +void *net_buf_simple_add(struct net_buf_simple *buf, size_t len) +{ + uint8_t *tail = net_buf_simple_tail(buf); + + NET_BUF_SIMPLE_DBG("buf %p len %u", buf, len); + + NET_BUF_SIMPLE_ASSERT(net_buf_simple_tailroom(buf) >= len); + + buf->len += len; + return tail; +} + +void *net_buf_simple_add_mem(struct net_buf_simple *buf, const void *mem, + size_t len) +{ + NET_BUF_SIMPLE_DBG("buf %p len %u", buf, len); + + return memcpy(net_buf_simple_add(buf, len), mem, len); +} + +uint8_t *net_buf_simple_add_u8(struct net_buf_simple *buf, uint8_t val) +{ + uint8_t *u8 = NULL; + + NET_BUF_SIMPLE_DBG("buf %p val 0x%02x", buf, val); + + u8 = net_buf_simple_add(buf, 1); + *u8 = val; + + return u8; +} + +void net_buf_simple_add_le16(struct net_buf_simple *buf, uint16_t val) +{ + NET_BUF_SIMPLE_DBG("buf %p val %u", buf, val); + + sys_put_le16(val, net_buf_simple_add(buf, sizeof(val))); +} + +void net_buf_simple_add_be16(struct net_buf_simple *buf, uint16_t val) +{ + NET_BUF_SIMPLE_DBG("buf %p val %u", buf, val); + + sys_put_be16(val, net_buf_simple_add(buf, sizeof(val))); +} + +void net_buf_simple_add_le24(struct net_buf_simple *buf, uint32_t val) +{ + NET_BUF_SIMPLE_DBG("buf %p val %u", buf, val); + + sys_put_le24(val, net_buf_simple_add(buf, 3)); +} + +void net_buf_simple_add_be24(struct net_buf_simple *buf, uint32_t val) +{ + NET_BUF_SIMPLE_DBG("buf %p val %u", buf, val); + + sys_put_be24(val, net_buf_simple_add(buf, 3)); +} + +void net_buf_simple_add_le32(struct net_buf_simple *buf, uint32_t val) +{ + NET_BUF_SIMPLE_DBG("buf %p val %u", buf, val); + + sys_put_le32(val, net_buf_simple_add(buf, sizeof(val))); +} + +void net_buf_simple_add_be32(struct net_buf_simple *buf, uint32_t val) +{ + NET_BUF_SIMPLE_DBG("buf %p val %u", buf, val); + + sys_put_be32(val, net_buf_simple_add(buf, sizeof(val))); +} + +void net_buf_simple_add_le48(struct net_buf_simple *buf, uint64_t val) +{ + NET_BUF_SIMPLE_DBG("buf %p val %" PRIu64, buf, val); + + sys_put_le48(val, net_buf_simple_add(buf, 6)); +} + +void net_buf_simple_add_be48(struct net_buf_simple *buf, uint64_t val) +{ + NET_BUF_SIMPLE_DBG("buf %p val %" PRIu64, buf, val); + + sys_put_be48(val, net_buf_simple_add(buf, 6)); +} + +void net_buf_simple_add_le64(struct net_buf_simple *buf, uint64_t val) +{ + NET_BUF_SIMPLE_DBG("buf %p val %" PRIu64, buf, val); + + sys_put_le64(val, net_buf_simple_add(buf, sizeof(val))); +} + +void net_buf_simple_add_be64(struct net_buf_simple *buf, uint64_t val) +{ + NET_BUF_SIMPLE_DBG("buf %p val %" PRIu64, buf, val); + + sys_put_be64(val, net_buf_simple_add(buf, sizeof(val))); +} + +void *net_buf_simple_push(struct net_buf_simple *buf, size_t len) +{ + NET_BUF_SIMPLE_DBG("buf %p len %u", buf, len); + + NET_BUF_SIMPLE_ASSERT(net_buf_simple_headroom(buf) >= len); + + buf->data -= len; + buf->len += len; + return buf->data; +} + +void net_buf_simple_push_le16(struct net_buf_simple *buf, uint16_t val) +{ + NET_BUF_SIMPLE_DBG("buf %p val %u", buf, val); + + sys_put_le16(val, net_buf_simple_push(buf, sizeof(val))); +} + +void net_buf_simple_push_be16(struct net_buf_simple *buf, uint16_t val) +{ + NET_BUF_SIMPLE_DBG("buf %p val %u", buf, val); + + sys_put_be16(val, net_buf_simple_push(buf, sizeof(val))); +} + +void net_buf_simple_push_u8(struct net_buf_simple *buf, uint8_t val) +{ + uint8_t *data = net_buf_simple_push(buf, 1); + + *data = val; +} + +void net_buf_simple_push_le24(struct net_buf_simple *buf, uint32_t val) +{ + NET_BUF_SIMPLE_DBG("buf %p val %u", buf, val); + + sys_put_le24(val, net_buf_simple_push(buf, 3)); +} + +void net_buf_simple_push_be24(struct net_buf_simple *buf, uint32_t val) +{ + NET_BUF_SIMPLE_DBG("buf %p val %u", buf, val); + + sys_put_be24(val, net_buf_simple_push(buf, 3)); +} + +void net_buf_simple_push_le32(struct net_buf_simple *buf, uint32_t val) +{ + NET_BUF_SIMPLE_DBG("buf %p val %u", buf, val); + + sys_put_le32(val, net_buf_simple_push(buf, sizeof(val))); +} + +void net_buf_simple_push_be32(struct net_buf_simple *buf, uint32_t val) +{ + NET_BUF_SIMPLE_DBG("buf %p val %u", buf, val); + + sys_put_be32(val, net_buf_simple_push(buf, sizeof(val))); +} + +void net_buf_simple_push_le48(struct net_buf_simple *buf, uint64_t val) +{ + NET_BUF_SIMPLE_DBG("buf %p val %" PRIu64, buf, val); + + sys_put_le48(val, net_buf_simple_push(buf, 6)); +} + +void net_buf_simple_push_be48(struct net_buf_simple *buf, uint64_t val) +{ + NET_BUF_SIMPLE_DBG("buf %p val %" PRIu64, buf, val); + + sys_put_be48(val, net_buf_simple_push(buf, 6)); +} + +void net_buf_simple_push_le64(struct net_buf_simple *buf, uint64_t val) +{ + NET_BUF_SIMPLE_DBG("buf %p val %" PRIu64, buf, val); + + sys_put_le64(val, net_buf_simple_push(buf, sizeof(val))); +} + +void net_buf_simple_push_be64(struct net_buf_simple *buf, uint64_t val) +{ + NET_BUF_SIMPLE_DBG("buf %p val %" PRIu64, buf, val); + + sys_put_be64(val, net_buf_simple_push(buf, sizeof(val))); +} + +void *net_buf_simple_pull(struct net_buf_simple *buf, size_t len) +{ + NET_BUF_SIMPLE_DBG("buf %p len %u", buf, len); + + NET_BUF_SIMPLE_ASSERT(buf->len >= len); + + buf->len -= len; + return buf->data += len; +} + +void *net_buf_simple_pull_mem(struct net_buf_simple *buf, size_t len) +{ + void *data = buf->data; + + NET_BUF_SIMPLE_DBG("buf %p len %zu", buf, len); + + NET_BUF_SIMPLE_ASSERT(buf->len >= len); + + buf->len -= len; + buf->data += len; + + return data; +} + +uint8_t net_buf_simple_pull_u8(struct net_buf_simple *buf) +{ + uint8_t val = 0U; + + val = buf->data[0]; + net_buf_simple_pull(buf, 1); + + return val; +} + +uint16_t net_buf_simple_pull_le16(struct net_buf_simple *buf) +{ + uint16_t val = 0U; + + val = UNALIGNED_GET((uint16_t *)buf->data); + net_buf_simple_pull(buf, sizeof(val)); + + return sys_le16_to_cpu(val); +} + +uint16_t net_buf_simple_pull_be16(struct net_buf_simple *buf) +{ + uint16_t val = 0U; + + val = UNALIGNED_GET((uint16_t *)buf->data); + net_buf_simple_pull(buf, sizeof(val)); + + return sys_be16_to_cpu(val); +} + +uint32_t net_buf_simple_pull_le24(struct net_buf_simple *buf) +{ + uint32_t val = 0U; + + val = sys_get_le24(buf->data); + net_buf_simple_pull(buf, 3); + + return val; +} + +uint32_t net_buf_simple_pull_be24(struct net_buf_simple *buf) +{ + uint32_t val = 0U; + + val = sys_get_be24(buf->data); + net_buf_simple_pull(buf, 3); + + return val; +} + +uint32_t net_buf_simple_pull_le32(struct net_buf_simple *buf) +{ + uint32_t val = 0U; + + val = UNALIGNED_GET((uint32_t *)buf->data); + net_buf_simple_pull(buf, sizeof(val)); + + return sys_le32_to_cpu(val); +} + +uint32_t net_buf_simple_pull_be32(struct net_buf_simple *buf) +{ + uint32_t val = 0U; + + val = UNALIGNED_GET((uint32_t *)buf->data); + net_buf_simple_pull(buf, sizeof(val)); + + return sys_be32_to_cpu(val); +} + +uint64_t net_buf_simple_pull_le48(struct net_buf_simple *buf) +{ + uint64_t val = 0U; + + val = sys_get_le48(buf->data); + net_buf_simple_pull(buf, 6); + + return val; +} + +uint64_t net_buf_simple_pull_be48(struct net_buf_simple *buf) +{ + uint64_t val = 0U; + + val = sys_get_be48(buf->data); + net_buf_simple_pull(buf, 6); + + return val; +} + +uint64_t net_buf_simple_pull_le64(struct net_buf_simple *buf) +{ + uint64_t val; + + val = UNALIGNED_GET((uint64_t *)buf->data); + net_buf_simple_pull(buf, sizeof(val)); + + return sys_le64_to_cpu(val); +} + +uint64_t net_buf_simple_pull_be64(struct net_buf_simple *buf) +{ + uint64_t val; + + val = UNALIGNED_GET((uint64_t *)buf->data); + net_buf_simple_pull(buf, sizeof(val)); + + return sys_be64_to_cpu(val); +} + +size_t net_buf_simple_headroom(const struct net_buf_simple *buf) +{ + return buf->data - buf->__buf; +} + +size_t net_buf_simple_tailroom(struct net_buf_simple *buf) +{ + return buf->size - net_buf_simple_headroom(buf) - buf->len; +} + +void net_buf_reset(struct net_buf *buf) +{ + buf->flags = 0; + buf->frags = NULL; + + net_buf_simple_reset(&buf->b); +} + +void net_buf_simple_init_with_data(struct net_buf_simple *buf, + void *data, size_t size) +{ + buf->__buf = data; + buf->data = data; + buf->size = size; + buf->len = size; +} + +void net_buf_simple_reserve(struct net_buf_simple *buf, size_t reserve) +{ + NET_BUF_ASSERT(buf); + NET_BUF_ASSERT(buf->len == 0U); + NET_BUF_DBG("buf %p reserve %zu", buf, reserve); + + buf->data = buf->__buf + reserve; +} + +void net_buf_slist_put(sys_slist_t *list, struct net_buf *buf) +{ + struct net_buf *tail = NULL; + + NET_BUF_ASSERT(list); + NET_BUF_ASSERT(buf); + + for (tail = buf; tail->frags; tail = tail->frags) { + tail->flags |= NET_BUF_FRAGS; + } + + sys_slist_append_list(list, &buf->node, &tail->node); +} + +struct net_buf *net_buf_slist_get(sys_slist_t *list) +{ + struct net_buf *buf = NULL, *frag = NULL; + + NET_BUF_ASSERT(list); + + buf = (void *)sys_slist_get(list); + + if (!buf) { + return NULL; + } + + /* Get any fragments belonging to this buffer */ + for (frag = buf; (frag->flags & NET_BUF_FRAGS); frag = frag->frags) { + frag->frags = (void *)sys_slist_get(list); + + NET_BUF_ASSERT(frag->frags); + + /* The fragments flag is only for list-internal usage */ + frag->flags &= ~NET_BUF_FRAGS; + } + + /* Mark the end of the fragment list */ + frag->frags = NULL; + + return buf; +} + +struct net_buf *net_buf_ref(struct net_buf *buf) +{ + NET_BUF_ASSERT(buf); + + NET_BUF_DBG("buf %p (old) ref %u pool %p", buf, buf->ref, buf->pool); + + buf->ref++; + return buf; +} + +#if defined(CONFIG_NET_BUF_LOG) +void net_buf_unref_debug(struct net_buf *buf, const char *func, int line) +#else +void net_buf_unref(struct net_buf *buf) +#endif +{ + NET_BUF_ASSERT(buf); + + while (buf) { + struct net_buf *frags = buf->frags; + struct net_buf_pool *pool = NULL; + +#if defined(CONFIG_NET_BUF_LOG) + if (!buf->ref) { + NET_BUF_ERR("%s():%d: buf %p double free", func, line, + buf); + return; + } +#endif + NET_BUF_DBG("buf %p ref %u pool %p frags %p", buf, buf->ref, + buf->pool, buf->frags); + + /* Changed by Espressif. Add !buf->ref to avoid minus 0 */ + if (!buf->ref || --buf->ref > 0) { + return; + } + + buf->frags = NULL; + + pool = buf->pool; + + pool->uninit_count++; +#if defined(CONFIG_NET_BUF_POOL_USAGE) + pool->avail_count++; + NET_BUF_DBG("Unref, pool %p, avail_count %d, uninit_count %d", + pool, pool->avail_count, pool->uninit_count); + NET_BUF_ASSERT(pool->avail_count <= pool->buf_count); +#endif + + if (pool->destroy) { + pool->destroy(buf); + } + + buf = frags; + } +} + +static uint8_t *fixed_data_alloc(struct net_buf *buf, size_t *size, int32_t timeout) +{ + struct net_buf_pool *pool = buf->pool; + const struct net_buf_pool_fixed *fixed = pool->alloc->alloc_data; + + *size = MIN(fixed->data_size, *size); + + return fixed->data_pool + fixed->data_size * net_buf_id(buf); +} + +static void fixed_data_unref(struct net_buf *buf, uint8_t *data) +{ + /* Nothing needed for fixed-size data pools */ +} + +const struct net_buf_data_cb net_buf_fixed_cb = { + .alloc = fixed_data_alloc, + .unref = fixed_data_unref, +}; + +static uint8_t *data_alloc(struct net_buf *buf, size_t *size, int32_t timeout) +{ + struct net_buf_pool *pool = buf->pool; + + return pool->alloc->cb->alloc(buf, size, timeout); +} + +#if defined(CONFIG_NET_BUF_LOG) +struct net_buf *net_buf_alloc_len_debug(struct net_buf_pool *pool, size_t size, + int32_t timeout, const char *func, int line) +#else +struct net_buf *net_buf_alloc_len(struct net_buf_pool *pool, size_t size, + int32_t timeout) +#endif +{ + struct net_buf *buf = NULL; + int i; + + NET_BUF_ASSERT(pool); + + NET_BUF_DBG("Alloc, pool %p, uninit_count %d, buf_count %d", + pool, pool->uninit_count, pool->buf_count); + + /* If there are uninitialized buffers we're guaranteed to succeed + * with the allocation one way or another. + */ + if (pool->uninit_count) { + for (i = pool->buf_count; i > 0; i--) { + buf = pool_get_uninit(pool, i); + if (!buf->ref) { + goto success; + } + } + } + + NET_BUF_ERR("Out of free buffer, pool %p", pool); + return NULL; + +success: + NET_BUF_DBG("allocated buf %p", buf); + + if (size) { + buf->__buf = data_alloc(buf, &size, timeout); + if (!buf->__buf) { + NET_BUF_ERR("Out of data, buf %p", buf); + return NULL; + } + } else { + NET_BUF_WARN("Zero data size, buf %p", buf); + buf->__buf = NULL; + } + + buf->ref = 1; + buf->flags = 0; + buf->frags = NULL; + buf->size = size; + net_buf_reset(buf); + + pool->uninit_count--; +#if defined(CONFIG_NET_BUF_POOL_USAGE) + pool->avail_count--; + NET_BUF_ASSERT(pool->avail_count >= 0); +#endif + + return buf; +} + +#if defined(CONFIG_NET_BUF_LOG) +struct net_buf *net_buf_alloc_fixed_debug(struct net_buf_pool *pool, + int32_t timeout, const char *func, + int line) +{ + const struct net_buf_pool_fixed *fixed = pool->alloc->alloc_data; + + return net_buf_alloc_len_debug(pool, fixed->data_size, timeout, func, line); +} +#else +struct net_buf *net_buf_alloc_fixed(struct net_buf_pool *pool, int32_t timeout) +{ + const struct net_buf_pool_fixed *fixed = pool->alloc->alloc_data; + + return net_buf_alloc_len(pool, fixed->data_size, timeout); +} +#endif + +struct net_buf *net_buf_frag_last(struct net_buf *buf) +{ + NET_BUF_ASSERT(buf); + + while (buf->frags) { + buf = buf->frags; + } + + return buf; +} + +void net_buf_frag_insert(struct net_buf *parent, struct net_buf *frag) +{ + NET_BUF_ASSERT(parent); + NET_BUF_ASSERT(frag); + + if (parent->frags) { + net_buf_frag_last(frag)->frags = parent->frags; + } + /* Take ownership of the fragment reference */ + parent->frags = frag; +} + +struct net_buf *net_buf_frag_add(struct net_buf *head, struct net_buf *frag) +{ + NET_BUF_ASSERT(frag); + + if (!head) { + return net_buf_ref(frag); + } + + net_buf_frag_insert(net_buf_frag_last(head), frag); + + return head; +} + +#if defined(CONFIG_NET_BUF_LOG) +struct net_buf *net_buf_frag_del_debug(struct net_buf *parent, + struct net_buf *frag, + const char *func, int line) +#else +struct net_buf *net_buf_frag_del(struct net_buf *parent, struct net_buf *frag) +#endif +{ + struct net_buf *next_frag = NULL; + + NET_BUF_ASSERT(frag); + + if (parent) { + NET_BUF_ASSERT(parent->frags); + NET_BUF_ASSERT(parent->frags == frag); + parent->frags = frag->frags; + } + + next_frag = frag->frags; + + frag->frags = NULL; + +#if defined(CONFIG_NET_BUF_LOG) + net_buf_unref_debug(frag, func, line); +#else + net_buf_unref(frag); +#endif + + return next_frag; +} + +size_t net_buf_linearize(void *dst, size_t dst_len, struct net_buf *src, + size_t offset, size_t len) +{ + struct net_buf *frag = NULL; + size_t to_copy = 0U; + size_t copied = 0U; + + len = MIN(len, dst_len); + + frag = src; + + /* find the right fragment to start copying from */ + while (frag && offset >= frag->len) { + offset -= frag->len; + frag = frag->frags; + } + + /* traverse the fragment chain until len bytes are copied */ + copied = 0; + while (frag && len > 0) { + to_copy = MIN(len, frag->len - offset); + memcpy((uint8_t *)dst + copied, frag->data + offset, to_copy); + + copied += to_copy; + + /* to_copy is always <= len */ + len -= to_copy; + frag = frag->frags; + + /* after the first iteration, this value will be 0 */ + offset = 0; + } + + return copied; +} + +/* This helper routine will append multiple bytes, if there is no place for + * the data in current fragment then create new fragment and add it to + * the buffer. It assumes that the buffer has at least one fragment. + */ +size_t net_buf_append_bytes(struct net_buf *buf, size_t len, + const void *value, int32_t timeout, + net_buf_allocator_cb allocate_cb, void *user_data) +{ + struct net_buf *frag = net_buf_frag_last(buf); + size_t added_len = 0U; + const uint8_t *value8 = value; + + do { + uint16_t count = MIN(len, net_buf_tailroom(frag)); + + net_buf_add_mem(frag, value8, count); + len -= count; + added_len += count; + value8 += count; + + if (len == 0) { + return added_len; + } + + frag = allocate_cb(timeout, user_data); + if (!frag) { + return added_len; + } + + net_buf_frag_add(buf, frag); + } while (1); + + /* Unreachable */ + return 0; +} diff --git a/components/bt/esp_ble_audio/host/utils/crc/crc32_sw.c b/components/bt/esp_ble_audio/host/utils/crc/crc32_sw.c new file mode 100644 index 0000000000..17db73f622 --- /dev/null +++ b/components/bt/esp_ble_audio/host/utils/crc/crc32_sw.c @@ -0,0 +1,34 @@ +/* + * SPDX-FileCopyrightText: 2018 Workaround GmbH. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +uint32_t crc32_ieee(const uint8_t *data, size_t len) +{ + return crc32_ieee_update(0x0, data, len); +} + +uint32_t crc32_ieee_update(uint32_t crc, const uint8_t *data, size_t len) +{ + /* crc table generated from polynomial 0xedb88320 */ + static const uint32_t table[16] = { + 0x00000000U, 0x1db71064U, 0x3b6e20c8U, 0x26d930acU, + 0x76dc4190U, 0x6b6b51f4U, 0x4db26158U, 0x5005713cU, + 0xedb88320U, 0xf00f9344U, 0xd6d6a3e8U, 0xcb61b38cU, + 0x9b64c2b0U, 0x86d3d2d4U, 0xa00ae278U, 0xbdbdf21cU, + }; + + crc = ~crc; + + for (size_t i = 0; i < len; i++) { + uint8_t byte = data[i]; + + crc = (crc >> 4) ^ table[(crc ^ byte) & 0x0f]; + crc = (crc >> 4) ^ table[(crc ^ ((uint32_t)byte >> 4)) & 0x0f]; + } + + return (~crc); +} diff --git a/components/bt/esp_ble_audio/host/utils/crypto.c b/components/bt/esp_ble_audio/host/utils/crypto.c new file mode 100644 index 0000000000..cdfcbaf93b --- /dev/null +++ b/components/bt/esp_ble_audio/host/utils/crypto.c @@ -0,0 +1,172 @@ +/* + * SPDX-FileCopyrightText: 2015-2016 Intel Corporation + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include +#include +#include + +#define USE_MBEDTLS 0 + +#if USE_MBEDTLS +#include "mbedtls/aes.h" +#include "mbedtls/cipher.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/cmac.h" +#include "mbedtls/ecdh.h" +#include "mbedtls/ecp.h" +#else /* USE_MBEDTLS */ +#include +#include +#include +#endif /* USE_MBEDTLS */ + +#include "esp_random.h" + +int bt_rand(void *buf, size_t len) +{ + if (buf == NULL || len == 0) { + return -EINVAL; + } + + esp_fill_random(buf, len); + + return 0; +} + +int bt_encrypt_le(const uint8_t key[16], + const uint8_t plaintext[16], + uint8_t enc_data[16]) +{ + uint8_t tmp[16]; + + CHECKIF(key == NULL || plaintext == NULL || enc_data == NULL) { + return -EINVAL; + } + + LOG_DBG("EncKey[%s]", bt_hex(key, 16)); + LOG_DBG("EncPlainText[%s]", bt_hex(plaintext, 16)); + +#if USE_MBEDTLS + mbedtls_aes_context ctx = {0}; + int ret = 0; + + mbedtls_aes_init(&ctx); + + sys_memcpy_swap(tmp, key, 16); + + if ((ret = mbedtls_aes_setkey_enc(&ctx, tmp, 128)) != 0) { + goto exit; + } + + sys_memcpy_swap(tmp, plaintext, 16); + + if ((ret = mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, + tmp, enc_data)) != 0) { + goto exit; + } + + sys_mem_swap(enc_data, 16); + + LOG_DBG("EncData[%s]", bt_hex(enc_data, 16)); + +exit: + mbedtls_aes_free(&ctx); + return ret; +#else /* USE_MBEDTLS */ + struct tc_aes_key_sched_struct s; + + sys_memcpy_swap(tmp, key, 16); + + if (tc_aes128_set_encrypt_key(&s, tmp) == TC_CRYPTO_FAIL) { + return -EINVAL; + } + + sys_memcpy_swap(tmp, plaintext, 16); + + if (tc_aes_encrypt(enc_data, tmp, &s) == TC_CRYPTO_FAIL) { + return -EINVAL; + } + + sys_mem_swap(enc_data, 16); + + LOG_DBG("EncData[%s]", bt_hex(enc_data, 16)); + + return 0; +#endif /* USE_MBEDTLS */ +} + +int bt_crypto_aes_cmac(const uint8_t *key, + const uint8_t *in, + size_t len, + uint8_t *out) +{ + CHECKIF(key == NULL || in == NULL || len == 0 || out == NULL) { + return -EINVAL; + } + + LOG_DBG("CmacKey[%s]", bt_hex(key, 16)); + LOG_DBG("CmacInput[%s]", bt_hex(in, len)); + +#if USE_MBEDTLS + const mbedtls_cipher_info_t *cipher_info; + mbedtls_cipher_context_t ctx; + int ret = 0; + + mbedtls_cipher_init(&ctx); + + cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB); + if (cipher_info == NULL) { + ret = -1; + goto exit; + } + + if ((ret = mbedtls_cipher_setup(&ctx, cipher_info)) != 0) { + goto exit; + } + + if ((ret = mbedtls_cipher_cmac_starts(&ctx, key, 128)) != 0) { + goto exit; + } + + if ((ret = mbedtls_cipher_cmac_update(&ctx, in, len)) != 0) { + goto exit; + } + + if ((ret = mbedtls_cipher_cmac_finish(&ctx, out)) != 0) { + goto exit; + } + + ret = 0; + +exit: + mbedtls_cipher_free(&ctx); + return ret; +#else /* USE_MBEDTLS */ + struct tc_aes_key_sched_struct sched; + struct tc_cmac_struct state; + + if (tc_cmac_setup(&state, key, &sched) == TC_CRYPTO_FAIL) { + return -EIO; + } + + if (tc_cmac_update(&state, in, len) == TC_CRYPTO_FAIL) { + return -EIO; + } + + if (tc_cmac_final(out, &state) == TC_CRYPTO_FAIL) { + return -EIO; + } + + return 0; +#endif /* USE_MBEDTLS */ +} diff --git a/components/bt/esp_ble_audio/host/utils/timer.c b/components/bt/esp_ble_audio/host/utils/timer.c new file mode 100644 index 0000000000..f082b978fa --- /dev/null +++ b/components/bt/esp_ble_audio/host/utils/timer.c @@ -0,0 +1,314 @@ +/* + * SPDX-FileCopyrightText: 2016 Intel Corporation + * SPDX-FileCopyrightText: 2016 Wind River Systems, Inc. + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include "esp_timer.h" + +#include +#include +#include +#include + +#include "common/host.h" + +static void iso_timer_cb(void *arg) +{ + struct k_work *work = arg; + int err; + + LOG_DBG("IsoTimerCb[%p]", work); + + assert(work); + assert(work->timer); + assert(work->handler); + + err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_TIMER_EVENT, work, 0); + if (err) { + LOG_ERR("IsoTimerPostFail[%d]", err); + } +} + +int k_work_submit(struct k_work *work) +{ + LOG_DBG("WorkSubmit[%p]", work); + + assert(work); + + if (work->handler == NULL) { + LOG_WRN("WorkHdlrNull"); + return -EINVAL; + } + + work->handler(work); + + return 0; +} + +int k_work_submit_safe(struct k_work *work) +{ + int err; + bt_le_host_lock(); + err = k_work_submit(work); + bt_le_host_unlock(); + return err; +} + +bool k_work_is_pending(struct k_work *work) +{ + bool is_pending; + + LOG_DBG("WorkIsPending[%p]", work); + + assert(work); + + if (work->handler == NULL) { + LOG_WRN("WorkHdlrNull"); + return false; + } + + is_pending = (work->timer ? esp_timer_is_active(work->timer) : false); + + LOG_DBG("%sPending", is_pending ? "Is" : "Not"); + + return is_pending; +} + +void k_work_init(struct k_work *work, k_work_handler_t handler) +{ + LOG_DBG("WorkInit[%p]", work); + + assert(work); + + work->handler = handler; +} + +struct k_work_delayable *k_work_delayable_from_work(struct k_work *work) +{ + LOG_DBG("DworkFromWork[%p]", work); + + assert(work); + + return (struct k_work_delayable *)work; +} + +void k_work_init_delayable(struct k_work_delayable *dwork, + k_work_handler_t handler) +{ + LOG_DBG("DworkInit[%p]", dwork); + + assert(dwork); + + const esp_timer_create_args_t timer_args = { + .callback = &iso_timer_cb, + .arg = &dwork->work, + .name = "iso_timer", + }; + int err; + + if (dwork->work.timer) { + LOG_WRN("TimerCreated"); + return; + } + + err = esp_timer_create(&timer_args, (esp_timer_handle_t *)&dwork->work.timer); + if (err) { + LOG_ERR("CreateTimerFail[%d]", err); + /* Reset handler so the object remains in a clean uninitialized state */ + dwork->work.handler = NULL; + return; + } + + dwork->work.handler = handler; +} + +void k_work_deinit_delayable(struct k_work_delayable *dwork) +{ + int err; + + LOG_DBG("DworkDeinit[%p]", dwork); + + assert(dwork); + + if (dwork->work.timer == NULL) { + LOG_INF("TimerNotCreated"); + return; + } + + err = esp_timer_delete(dwork->work.timer); + if (err) { + LOG_ERR("DeleteTimerFail[%d]", err); + return; + } + + memset(&dwork->work, 0, sizeof(dwork->work)); +} + +int k_work_cancel_delayable(struct k_work_delayable *dwork) +{ + LOG_DBG("DworkCancel[%p]", dwork); + + assert(dwork); + + if (dwork->work.timer == NULL) { + LOG_INF("TimerNotCreated"); + return -EINVAL; + } + + esp_timer_stop(dwork->work.timer); + + return 0; +} + +bool k_work_cancel_delayable_sync(struct k_work_delayable *dwork, + struct k_work_sync *sync) +{ + LOG_DBG("DworkCancelSync[%p]", dwork); + + assert(dwork); + + ARG_UNUSED(sync); + + if (dwork->work.timer == NULL) { + LOG_INF("TimerNotCreated"); + return false; + } + + esp_timer_stop(dwork->work.timer); + + /* TODO: check the return result */ + return false; +} + +int k_work_schedule(struct k_work_delayable *dwork, k_timeout_t ms) +{ + int err; + + LOG_DBG("WorkSchedule[%p][%u]", dwork, ms); + + assert(dwork); + + if (dwork->work.timer == NULL) { + LOG_WRN("TimerNotCreated"); + return -EINVAL; + } + + esp_timer_stop(dwork->work.timer); + + dwork->work.timeout_us = esp_timer_get_time() + (int64_t)ms * 1000; + + if (ms == K_NO_WAIT) { + k_work_submit(&dwork->work); + return 0; + } + + err = esp_timer_start_once(dwork->work.timer, ms * 1000); + if (err) { + LOG_ERR("StartTimerFail[%d]", err); + return -EIO; + } + + return 0; +} + +int k_work_reschedule(struct k_work_delayable *dwork, k_timeout_t ms) +{ + int err; + + LOG_DBG("WorkReschedule[%p][%u]", dwork, ms); + + assert(dwork); + + if (dwork->work.timer == NULL) { + LOG_WRN("TimerNotCreated"); + return -EINVAL; + } + + esp_timer_stop(dwork->work.timer); + + dwork->work.timeout_us = esp_timer_get_time() + (int64_t)ms * 1000; + + if (ms == K_NO_WAIT) { + k_work_submit(&dwork->work); + return 0; + } + + err = esp_timer_start_once(dwork->work.timer, ms * 1000); + if (err) { + LOG_ERR("RestartTimerFail[%d]", err); + return -EIO; + } + + return 0; +} + +int k_work_schedule_periodic(struct k_work_delayable *dwork, k_timeout_t period_ms) +{ + int err; + + LOG_DBG("WorkSchedulePeriodic[%p][%u]", dwork, period_ms); + + assert(dwork); + assert(period_ms > 0); + + if (dwork->work.timer == NULL) { + LOG_WRN("TimerNotCreated"); + return -EINVAL; + } + + esp_timer_stop(dwork->work.timer); + + err = esp_timer_start_periodic(dwork->work.timer, (uint64_t)period_ms * 1000); + if (err) { + LOG_ERR("StartPeriodicTimerFail[%d]", err); + return -EIO; + } + + return 0; +} + +k_timeout_t k_work_delayable_remaining_get(struct k_work_delayable *dwork) +{ + k_timeout_t timeout; + int64_t delta_us; + + LOG_DBG("DworkRemainingGet[%p]", dwork); + + assert(dwork); + + if (dwork->work.timer == NULL) { + LOG_WRN("TimerNotCreated"); + return 0; + } + + if (dwork->work.timeout_us == 0) { + LOG_DBG("WorkTimeoutZero"); + return 0; + } + + delta_us = dwork->work.timeout_us - esp_timer_get_time(); + + timeout = (delta_us > 0 ? (k_timeout_t)(delta_us / 1000) : 0); + + LOG_DBG("Timeout[%u]", timeout); + + return timeout; +} + +void bt_le_timer_handle_event(void *arg) +{ + struct k_work *work = arg; + + LOG_DBG("HdlTimerEvt[%p]", work); + + k_work_submit_safe(work); +} diff --git a/components/bt/esp_ble_audio/host/utils/utf8.c b/components/bt/esp_ble_audio/host/utils/utf8.c new file mode 100644 index 0000000000..4fe979bc8d --- /dev/null +++ b/components/bt/esp_ble_audio/host/utils/utf8.c @@ -0,0 +1,81 @@ +/* + * SPDX-FileCopyrightText: 2021 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#define ASCII_CHAR 0x7F +#define SEQUENCE_FIRST_MASK 0xC0 +#define SEQUENCE_LEN_2_BYTE 0xC0 +#define SEQUENCE_LEN_3_BYTE 0xE0 +#define SEQUENCE_LEN_4_BYTE 0xF0 + +char *utf8_trunc(char *utf8_str) +{ + const size_t len = strlen(utf8_str); + + if (len == 0U) { + /* no-op */ + return utf8_str; + } + + char *last_byte_p = utf8_str + len - 1U; + uint8_t bytes_truncated; + char seq_start_byte; + + if ((*last_byte_p & ASCII_CHAR) == *last_byte_p) { + /* Not part of an UTF8 sequence, return */ + return utf8_str; + } + + /* Find the starting byte and NULL-terminate other bytes */ + bytes_truncated = 0; + while ((*last_byte_p & SEQUENCE_FIRST_MASK) != SEQUENCE_FIRST_MASK && + last_byte_p > utf8_str) { + last_byte_p--; + bytes_truncated++; + } + bytes_truncated++; /* include the starting byte */ + + /* Verify if the last character actually need to be truncated + * Handles the case where the number of bytes in the last UTF8-char + * matches the number of bytes we searched for the starting byte + */ + seq_start_byte = *last_byte_p; + if ((seq_start_byte & SEQUENCE_LEN_4_BYTE) == SEQUENCE_LEN_4_BYTE) { + if (bytes_truncated == 4) { + return utf8_str; + } + } else if ((seq_start_byte & SEQUENCE_LEN_3_BYTE) == SEQUENCE_LEN_3_BYTE) { + if (bytes_truncated == 3) { + return utf8_str; + } + } else if ((seq_start_byte & SEQUENCE_LEN_2_BYTE) == SEQUENCE_LEN_2_BYTE) { + if (bytes_truncated == 2) { + return utf8_str; + } + } + + /* NULL-terminate the unterminated starting byte */ + *last_byte_p = '\0'; + + return utf8_str; +} + +char *utf8_lcpy(char *dst, const char *src, size_t n) +{ + if (n > 0) { + strncpy(dst, src, n - 1); + dst[n - 1] = '\0'; + + if (n != 1) { + utf8_trunc(dst); + } + } + + return dst; +} diff --git a/components/bt/esp_ble_audio/host/utils/utils.c b/components/bt/esp_ble_audio/host/utils/utils.c new file mode 100644 index 0000000000..c1bb2e1da2 --- /dev/null +++ b/components/bt/esp_ble_audio/host/utils/utils.c @@ -0,0 +1,72 @@ +/* + * SPDX-FileCopyrightText: 2015-2016 Intel Corporation + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include <../host/keys.h> +#include <../host/hci_core.h> + +struct bt_dev bt_dev; + +uint8_t bt_get_phy(uint8_t hci_phy) +{ + switch (hci_phy) { + case BT_HCI_LE_PHY_1M: + return BT_GAP_LE_PHY_1M; + case BT_HCI_LE_PHY_2M: + return BT_GAP_LE_PHY_2M; + case BT_HCI_LE_PHY_CODED: + return BT_GAP_LE_PHY_CODED; + default: + return 0; + } +} + +static struct bt_keys key_pool[CONFIG_BT_MAX_PAIRED]; + +void bt_foreach_bond(uint8_t id, void (*func)(const struct bt_bond_info *info, + void *user_data), + void *user_data) +{ + assert(func); + + for (size_t i = 0; i < ARRAY_SIZE(key_pool); i++) { + struct bt_keys *keys = &key_pool[i]; + + if (keys->keys && keys->id == id) { + struct bt_bond_info info; + + bt_addr_le_copy(&info.addr, &keys->addr); + func(&info, user_data); + } + } +} + +bool bt_le_bond_exists(uint8_t id, const bt_addr_le_t *addr) +{ + if (addr == NULL) { + return false; + } + + for (size_t i = 0; i < ARRAY_SIZE(key_pool); i++) { + struct bt_keys *keys = &key_pool[i]; + + if (keys->keys && keys->id == id && + bt_addr_le_eq(&keys->addr, addr)) { + return true; + } + } + + return false; +} diff --git a/components/bt/esp_ble_audio/host/utils/uuid.c b/components/bt/esp_ble_audio/host/utils/uuid.c new file mode 100644 index 0000000000..0c9f5b75c4 --- /dev/null +++ b/components/bt/esp_ble_audio/host/utils/uuid.c @@ -0,0 +1,138 @@ +/* + * SPDX-FileCopyrightText: 2015-2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include + +#define UUID_16_BASE_OFFSET 12 + +/* TODO: Decide whether to continue using BLE format or switch to RFC 4122 */ + +/* Base UUID : 0000[0000]-0000-1000-8000-00805F9B34FB + * 0x2800 : 0000[2800]-0000-1000-8000-00805F9B34FB + * little endian 0x2800 : [00 28] -> no swapping required + * big endian 0x2800 : [28 00] -> swapping required + */ +static const struct bt_uuid_128 uuid128_base = { + .uuid = { BT_UUID_TYPE_128 }, + .val = { + BT_UUID_128_ENCODE( + 0x00000000, 0x0000, 0x1000, 0x8000, 0x00805F9B34FB) + } +}; + +static void uuid_to_uuid128(const struct bt_uuid *src, struct bt_uuid_128 *dst) +{ + switch (src->type) { + case BT_UUID_TYPE_16: + *dst = uuid128_base; + sys_put_le16(BT_UUID_16(src)->val, + &dst->val[UUID_16_BASE_OFFSET]); + return; + case BT_UUID_TYPE_32: + *dst = uuid128_base; + sys_put_le32(BT_UUID_32(src)->val, + &dst->val[UUID_16_BASE_OFFSET]); + return; + case BT_UUID_TYPE_128: + memcpy(dst, src, sizeof(*dst)); + return; + default: + memset(dst, 0, sizeof(*dst)); + return; + } +} + +static int uuid128_cmp(const struct bt_uuid *u1, const struct bt_uuid *u2) +{ + struct bt_uuid_128 uuid1, uuid2; + + uuid_to_uuid128(u1, &uuid1); + uuid_to_uuid128(u2, &uuid2); + + return memcmp(uuid1.val, uuid2.val, 16); +} + +int bt_uuid_cmp(const struct bt_uuid *u1, const struct bt_uuid *u2) +{ + /* Convert to 128 bit if types don't match */ + if (u1->type != u2->type) { + return uuid128_cmp(u1, u2); + } + + switch (u1->type) { + case BT_UUID_TYPE_16: + return (int)BT_UUID_16(u1)->val - (int)BT_UUID_16(u2)->val; + case BT_UUID_TYPE_32: + if (BT_UUID_32(u1)->val > BT_UUID_32(u2)->val) { + return 1; + } else if (BT_UUID_32(u1)->val < BT_UUID_32(u2)->val) { + return -1; + } + return 0; + case BT_UUID_TYPE_128: + return memcmp(BT_UUID_128(u1)->val, BT_UUID_128(u2)->val, 16); + } + + return -EINVAL; +} + +bool bt_uuid_create(struct bt_uuid *uuid, const uint8_t *data, uint8_t data_len) +{ + /* Copy UUID from packet data/internal variable to internal bt_uuid */ + switch (data_len) { + case BT_UUID_SIZE_16: + uuid->type = BT_UUID_TYPE_16; + BT_UUID_16(uuid)->val = sys_get_le16(data); + break; + case BT_UUID_SIZE_32: + uuid->type = BT_UUID_TYPE_32; + BT_UUID_32(uuid)->val = sys_get_le32(data); + break; + case BT_UUID_SIZE_128: + uuid->type = BT_UUID_TYPE_128; + memcpy(&BT_UUID_128(uuid)->val, data, 16); + break; + default: + return false; + } + return true; +} + +void bt_uuid_to_str(const struct bt_uuid *uuid, char *str, size_t len) +{ + uint32_t tmp1, tmp5; + uint16_t tmp0, tmp2, tmp3, tmp4; + + switch (uuid->type) { + case BT_UUID_TYPE_16: + snprintf(str, len, "%04x", BT_UUID_16(uuid)->val); + break; + case BT_UUID_TYPE_32: + snprintf(str, len, "%08x", BT_UUID_32(uuid)->val); + break; + case BT_UUID_TYPE_128: + memcpy(&tmp0, &BT_UUID_128(uuid)->val[0], sizeof(tmp0)); + memcpy(&tmp1, &BT_UUID_128(uuid)->val[2], sizeof(tmp1)); + memcpy(&tmp2, &BT_UUID_128(uuid)->val[6], sizeof(tmp2)); + memcpy(&tmp3, &BT_UUID_128(uuid)->val[8], sizeof(tmp3)); + memcpy(&tmp4, &BT_UUID_128(uuid)->val[10], sizeof(tmp4)); + memcpy(&tmp5, &BT_UUID_128(uuid)->val[12], sizeof(tmp5)); + + snprintf(str, len, "%08x-%04x-%04x-%04x-%08x%04x", + sys_le32_to_cpu(tmp5), sys_le16_to_cpu(tmp4), + sys_le16_to_cpu(tmp3), sys_le16_to_cpu(tmp2), + sys_le32_to_cpu(tmp1), sys_le16_to_cpu(tmp0)); + break; + default: + (void)memset(str, 0, len); + return; + } +} diff --git a/components/bt/esp_ble_audio/include/subsys/bluetooth/host/conn_internal.h b/components/bt/esp_ble_audio/include/subsys/bluetooth/host/conn_internal.h new file mode 100644 index 0000000000..b9d8c12518 --- /dev/null +++ b/components/bt/esp_ble_audio/include/subsys/bluetooth/host/conn_internal.h @@ -0,0 +1,118 @@ +/** @file + * @brief Internal APIs for Bluetooth connection handling. + */ + +/* + * SPDX-FileCopyrightText: 2015 Intel Corporation + * SPDX-FileCopyrightText: 2021 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include + +#include + +typedef enum __packed { + BT_CONN_DISCONNECTED, /* Disconnected, conn is completely down */ + BT_CONN_DISCONNECT_COMPLETE, /* Received disconn comp event, transition to DISCONNECTED */ + + BT_CONN_INITIATING, /* Central connection establishment */ + + BT_CONN_CONNECTED, /* Peripheral or Central connected */ + BT_CONN_DISCONNECTING, /* Peripheral or Central issued disconnection command */ +} bt_conn_state_t; + +struct bt_conn_le { + bt_addr_le_t dst; + + uint16_t interval; + + /** @brief Remote LE features + * + * Available after `atomic_test_bit(conn->flags, BT_CONN_LE_FEATURES_EXCHANGED)`. + * Signaled by bt_conn_cb.remote_info_available(). + */ + uint8_t features[8]; + + struct bt_keys *keys; +}; + +struct bt_conn_iso { + /* Reference to ACL Connection */ + struct bt_conn *acl; + + /* Reference to the struct bt_iso_chan */ + struct bt_iso_chan *chan; + + /** Stored information about the ISO stream */ + struct bt_iso_info info; +}; + +typedef void (*bt_conn_tx_cb_t)(struct bt_conn *conn, void *user_data, int err); + +struct bt_conn_rx { + /* Index into the bt_conn storage array */ + uint8_t index; + + /** Connection handle */ + uint16_t handle; +}; + +struct bt_conn { + uint16_t handle; + enum bt_conn_type type; + uint8_t role; + + /* Which local identity address this connection uses */ + uint8_t id; + + bt_security_t sec_level; + uint8_t encrypt; + + /* Connection error or reason for disconnect */ + uint8_t err; + + bt_conn_state_t state; + uint16_t rx_len; + struct net_buf *rx; + + /* Active L2CAP channels */ + sys_slist_t channels; + + union { + struct bt_conn_le le; + struct bt_conn_iso iso; + }; + + /* Get (and clears for ACL conns) callback and user-data for `buf`. */ + void (*get_and_clear_cb)(struct bt_conn *conn, struct net_buf *buf, + bt_conn_tx_cb_t *cb, void **ud); +}; + +/* Cleanup ISO references */ +void bt_iso_cleanup_acl(struct bt_conn *iso_conn); + +void bt_iso_reset(void); + +/* Allocate new connection object */ +struct bt_conn *bt_conn_new(struct bt_conn *conns, size_t size); + +/* Look up an existing connection */ +struct bt_conn *bt_conn_lookup_handle(uint16_t handle, enum bt_conn_type type); + +/* Check if the connection is with the given peer. */ +bool bt_conn_is_peer_addr_le(const struct bt_conn *conn, uint8_t id, + const bt_addr_le_t *peer); + +/* Helpers for identifying & looking up connections based on the index to + * the connection list. This is useful for O(1) lookups, but can't be used + * e.g. as the handle since that's assigned to us by the controller. + */ +#define BT_CONN_INDEX_INVALID 0xff + +/* Set connection object in certain state and perform action related to state */ +void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state); diff --git a/components/bt/esp_ble_audio/include/subsys/bluetooth/host/hci_core.h b/components/bt/esp_ble_audio/include/subsys/bluetooth/host/hci_core.h new file mode 100644 index 0000000000..6f7efc8a12 --- /dev/null +++ b/components/bt/esp_ble_audio/include/subsys/bluetooth/host/hci_core.h @@ -0,0 +1,109 @@ +/* hci_core.h - Bluetooth HCI core access */ + +/* + * SPDX-FileCopyrightText: 2021 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2015-2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +/* bt_dev flags: the flags defined here represent BT controller state */ +enum { + /** The application either explicitly or implicitly instructed the stack to scan + * for advertisers. + * + * Examples of such cases + * - Explicit scanning, @ref BT_LE_SCAN_USER_EXPLICIT_SCAN. + * - The application instructed the stack to automatically connect if a given device + * is detected. + * - The application wants to connect to a peer device using private addresses, but + * the controller resolving list is too small. The host will fallback to using + * host-based privacy and first scan for the device before it initiates a connection. + * - The application wants to synchronize to a periodic advertiser. + * The host will implicitly start scanning if it is not already doing so. + * + * The host needs to keep track of this state to ensure it can restart scanning + * when a connection is established/lost, explicit scanning is started or stopped etc. + * Also, when the scanner and advertiser share the same identity, the scanner may need + * to be restarted upon RPA refresh. + */ + BT_DEV_SCANNING, + + /* Total number of flags - must be at the end of the enum */ + BT_DEV_NUM_FLAGS, +}; + +enum { + /* Periodic Advertising parameters has been set in the controller. */ + BT_PER_ADV_PARAMS_SET, + + BT_ADV_NUM_FLAGS, +}; + +struct bt_le_ext_adv { + /* Advertising handle */ + uint8_t handle; + + ATOMIC_DEFINE(flags, BT_ADV_NUM_FLAGS); +}; + +enum { + /** Periodic Advertising Sync has been created in the host. */ + BT_PER_ADV_SYNC_CREATED, + + /** Periodic Advertising Sync is established and can be terminated */ + BT_PER_ADV_SYNC_SYNCED, + + /** Periodic Advertising Sync is attempting to create sync */ + BT_PER_ADV_SYNC_SYNCING, + + BT_PER_ADV_SYNC_NUM_FLAGS, +}; + +struct bt_le_per_adv_sync { + /** Periodic Advertiser Address */ + bt_addr_le_t addr; + + /** Advertiser SID */ + uint8_t sid; + + /** Sync handle */ + uint16_t handle; + + /** Periodic advertising interval (N * 1.25 ms) */ + uint16_t interval; + + /** Advertiser PHY */ + uint8_t phy; + + /** Flags */ + ATOMIC_DEFINE(flags, BT_PER_ADV_SYNC_NUM_FLAGS); +}; + +struct bt_dev_le { + /* LE features */ + uint8_t features[8]; +}; + +/* State tracking for the local Bluetooth controller */ +struct bt_dev { + ATOMIC_DEFINE(flags, BT_DEV_NUM_FLAGS); + + /* LE controller specific features */ + struct bt_dev_le le; +}; + +extern struct bt_dev bt_dev; + +/* Data type to store state related with command to be updated + * when command completes successfully. + */ +struct bt_hci_cmd_state_set { + /* Dummy */ +}; + +uint8_t bt_get_phy(uint8_t hci_phy); + +bool bt_le_bond_exists(uint8_t id, const bt_addr_le_t *addr); diff --git a/components/bt/esp_ble_audio/include/subsys/bluetooth/host/iso_internal.h b/components/bt/esp_ble_audio/include/subsys/bluetooth/host/iso_internal.h new file mode 100644 index 0000000000..27ddbfb047 --- /dev/null +++ b/components/bt/esp_ble_audio/include/subsys/bluetooth/host/iso_internal.h @@ -0,0 +1,126 @@ +/** @file + * @brief Internal APIs for Bluetooth ISO handling. + */ + +/* + * SPDX-FileCopyrightText: 2020 Intel Corporation + * SPDX-FileCopyrightText: 2021-2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include + +enum bt_iso_cig_state { + BT_ISO_CIG_STATE_IDLE, + BT_ISO_CIG_STATE_CONFIGURED, + BT_ISO_CIG_STATE_ACTIVE, + BT_ISO_CIG_STATE_INACTIVE +}; + +struct bt_iso_cig { + /** List of ISO channels to setup as CIS (the CIG). */ + sys_slist_t cis_channels; + + /** Total number of CISes in the CIG. */ + uint8_t num_cis; + + /** The CIG ID */ + uint8_t id; + + /** The CIG state + * + * Refer to BT Core Spec 5.3, Vol 6, Part 6, Figure 4.63 + */ + enum bt_iso_cig_state state; +}; + +enum { + BT_BIG_INITIALIZED, + + /* Creating a BIG as a broadcaster */ + BT_BIG_PENDING, + /* Creating a BIG as a receiver */ + BT_BIG_SYNCING, + /* BIG is busy handling an HCI event. + * + * Use this to prevent API calls from modifying the BIG while the event is being processed. + */ + BT_BIG_BUSY, + + BT_BIG_NUM_FLAGS, +}; + +struct bt_iso_big { + /** List of ISO channels to setup as BIS (the BIG). */ + sys_slist_t bis_channels; + + /** Total number of BISes in the BIG. */ + uint8_t num_bis; + + /** The BIG handle */ + uint8_t handle; + + ATOMIC_DEFINE(flags, BT_BIG_NUM_FLAGS); +}; + +#define iso(buf) ((struct bt_conn_rx *)net_buf_user_data(buf)) + +/* Process ISO buffer */ +void hci_iso(struct net_buf *buf); + +/* Process CIS Established event */ +void hci_le_cis_established(struct net_buf *buf); +void hci_le_cis_established_v2(struct net_buf *buf); + +/* Process CIS Request event */ +void hci_le_cis_req(struct net_buf *buf); + +/** Process BIG complete event */ +void hci_le_big_complete(struct net_buf *buf); + +/** Process BIG terminate event */ +void hci_le_big_terminate(struct net_buf *buf); + +/** Process BIG sync established event */ +void hci_le_big_sync_established(struct net_buf *buf); + +/** Process BIG sync lost event */ +void hci_le_big_sync_lost(struct net_buf *buf); + +/* Notify ISO channels of a new connection */ +void bt_iso_connected(struct bt_conn *iso); + +/* Notify ISO channels of a disconnect event */ +void bt_iso_disconnected(struct bt_conn *iso); + +#if defined(CONFIG_BT_ISO_LOG_LEVEL_DBG) +void bt_iso_chan_set_state_debug(struct bt_iso_chan *chan, + enum bt_iso_state state, + const char *func, int line); +#define bt_iso_chan_set_state(_chan, _state) \ + bt_iso_chan_set_state_debug(_chan, _state, __func__, __LINE__) +#else +void bt_iso_chan_set_state(struct bt_iso_chan *chan, enum bt_iso_state state); +#endif /* CONFIG_BT_ISO_LOG_LEVEL_DBG */ + +/* Process incoming data for a connection */ +void bt_iso_recv(struct bt_conn *iso, struct net_buf *buf, uint8_t flags); + +/* Whether the HCI ISO data packet contains a timestamp or not. + * Per spec, the TS flag can only be set for the first fragment. + */ +enum bt_iso_timestamp { + BT_ISO_TS_ABSENT = 0, + BT_ISO_TS_PRESENT, +}; diff --git a/components/bt/esp_ble_audio/include/subsys/bluetooth/host/keys.h b/components/bt/esp_ble_audio/include/subsys/bluetooth/host/keys.h new file mode 100644 index 0000000000..95d5e2ab59 --- /dev/null +++ b/components/bt/esp_ble_audio/include/subsys/bluetooth/host/keys.h @@ -0,0 +1,29 @@ +/* + * SPDX-FileCopyrightText: 2015-2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SUBSYS_BLUETOOTH_HOST_KEYS_H_ +#define ZEPHYR_SUBSYS_BLUETOOTH_HOST_KEYS_H_ + +#include + +/** @cond INTERNAL_HIDDEN */ + +struct bt_ltk { + uint8_t rand[8]; + uint8_t ediv[2]; + uint8_t val[16]; +}; + +struct bt_keys { + uint8_t id; + bt_addr_le_t addr; + uint16_t keys; + struct bt_ltk ltk; +}; + +/** @endcond */ + +#endif /* ZEPHYR_SUBSYS_BLUETOOTH_HOST_KEYS_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/autoconf.h b/components/bt/esp_ble_audio/include/zephyr/autoconf.h new file mode 100644 index 0000000000..086b9d1d09 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/autoconf.h @@ -0,0 +1,48 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "sdkconfig.h" + +#include + +#define CONFIG_LITTLE_ENDIAN 1 +#define CONFIG_BT_CONN_TX_USER_DATA_SIZE 8 + +#define CONFIG_BT_MAX_CONN CONFIG_BT_NIMBLE_MAX_CONNECTIONS +#define CONFIG_BT_SMP CONFIG_BT_NIMBLE_SECURITY_ENABLE +#define CONFIG_BT_MAX_PAIRED CONFIG_BT_NIMBLE_MAX_BONDS + +#if CONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES +#define CONFIG_BT_EXT_ADV_MAX_ADV_SET CONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES +#else /* CONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES */ +#define CONFIG_BT_EXT_ADV_MAX_ADV_SET 0 +#endif /* CONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES */ + +#if CONFIG_BT_NIMBLE_MAX_PERIODIC_SYNCS +#define CONFIG_BT_PER_ADV_SYNC_MAX CONFIG_BT_NIMBLE_MAX_PERIODIC_SYNCS +#else /* CONFIG_BT_NIMBLE_MAX_PERIODIC_SYNCS */ +#define CONFIG_BT_PER_ADV_SYNC_MAX 0 +#endif /* CONFIG_BT_NIMBLE_MAX_PERIODIC_SYNCS */ + +#if CONFIG_BT_NIMBLE_PERIODIC_ADV_SYNC_TRANSFER +#define CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER CONFIG_BT_NIMBLE_PERIODIC_ADV_SYNC_TRANSFER +#define CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER CONFIG_BT_NIMBLE_PERIODIC_ADV_SYNC_TRANSFER +#else /* CONFIG_BT_NIMBLE_PERIODIC_ADV_SYNC_TRANSFER */ +#define CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER 0 +#define CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER 0 +#endif /* CONFIG_BT_NIMBLE_PERIODIC_ADV_SYNC_TRANSFER */ + +#if CONFIG_BT_ISO_UNICAST && CONFIG_BT_ISO_BROADCAST +_Static_assert(CONFIG_BT_ISO_MAX_CHAN <= CONFIG_BT_NIMBLE_ISO_CIS + CONFIG_BT_NIMBLE_ISO_BIS, "Too large ISO channels"); +#elif CONFIG_BT_ISO_UNICAST && !CONFIG_BT_ISO_BROADCAST +_Static_assert(CONFIG_BT_ISO_MAX_CHAN <= CONFIG_BT_NIMBLE_ISO_CIS, "Too large ISO channels"); +#elif !CONFIG_BT_ISO_UNICAST && CONFIG_BT_ISO_BROADCAST +_Static_assert(CONFIG_BT_ISO_MAX_CHAN <= CONFIG_BT_NIMBLE_ISO_BIS, "Too large ISO channels"); +#else /* CONFIG_BT_ISO_UNICAST && CONFIG_BT_ISO_BROADCAST */ +_Static_assert(CONFIG_BT_ISO_MAX_CHAN == 0, "Too large ISO channels"); +#endif /* CONFIG_BT_ISO_UNICAST && CONFIG_BT_ISO_BROADCAST */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/addr.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/addr.h new file mode 100644 index 0000000000..5abed74092 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/addr.h @@ -0,0 +1,272 @@ +/** @file + * @brief Bluetooth device address definitions and utilities. + */ + +/* + * SPDX-FileCopyrightText: 2019 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_ADDR_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_ADDR_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Bluetooth device address definitions and utilities. + * @defgroup bt_addr Device Address + * @ingroup bluetooth + * @{ + */ + +#define BT_ADDR_LE_PUBLIC 0x00 +#define BT_ADDR_LE_RANDOM 0x01 +#define BT_ADDR_LE_PUBLIC_ID 0x02 +#define BT_ADDR_LE_RANDOM_ID 0x03 +#define BT_ADDR_LE_UNRESOLVED 0xFE /* Resolvable Private Address + * (Controller unable to resolve) + */ +#define BT_ADDR_LE_ANONYMOUS 0xFF /* No address provided + * (anonymous advertisement) + */ + +/** Length in bytes of a standard Bluetooth address */ +#define BT_ADDR_SIZE 6 + +/** Bluetooth Device Address */ +typedef struct { + uint8_t val[BT_ADDR_SIZE]; +} bt_addr_t; +/**/ + +/** Length in bytes of an LE Bluetooth address. Not packed, so no sizeof() */ +#define BT_ADDR_LE_SIZE 7 + +/** Bluetooth LE Device Address */ +typedef struct { + uint8_t type; + bt_addr_t a; +} bt_addr_le_t; + +/* Global Bluetooth address constants defined in bluetooth/common/addr.c */ +extern const bt_addr_t bt_addr_any; +extern const bt_addr_t bt_addr_none; +extern const bt_addr_le_t bt_addr_le_any; +extern const bt_addr_le_t bt_addr_le_none; + +/** Bluetooth device "any" address, not a valid address */ +#define BT_ADDR_ANY (&bt_addr_any) +/** Bluetooth device "none" address, not a valid address */ +#define BT_ADDR_NONE (&bt_addr_none) +/** Bluetooth LE device "any" address, not a valid address */ +#define BT_ADDR_LE_ANY (&bt_addr_le_any) +/** Bluetooth LE device "none" address, not a valid address */ +#define BT_ADDR_LE_NONE (&bt_addr_le_none) + +/** @brief Compare Bluetooth device addresses. + * + * @param a First Bluetooth device address to compare + * @param b Second Bluetooth device address to compare + * + * @return negative value if @a a < @a b, 0 if @a a == @a b, else positive + */ +static inline int bt_addr_cmp(const bt_addr_t *a, const bt_addr_t *b) +{ + return memcmp(a, b, sizeof(*a)); +} + +/** @brief Determine equality of two Bluetooth device addresses. + * + * @retval #true if the two addresses are equal + * @retval #false otherwise + */ +static inline bool bt_addr_eq(const bt_addr_t *a, const bt_addr_t *b) +{ + return bt_addr_cmp(a, b) == 0; +} + +/** @brief Compare Bluetooth LE device addresses. + * + * @param a First Bluetooth LE device address to compare + * @param b Second Bluetooth LE device address to compare + * + * @return negative value if @a a < @a b, 0 if @a a == @a b, else positive + * + * @sa bt_addr_le_eq + */ +static inline int bt_addr_le_cmp(const bt_addr_le_t *a, const bt_addr_le_t *b) +{ + return memcmp(a, b, sizeof(*a)); +} + +/** @brief Determine equality of two Bluetooth LE device addresses. + * + * The Bluetooth LE addresses are equal if and only if both the types and + * the 48-bit addresses are numerically equal. + * + * @retval #true if the two addresses are equal + * @retval #false otherwise + */ +static inline bool bt_addr_le_eq(const bt_addr_le_t *a, const bt_addr_le_t *b) +{ + return bt_addr_le_cmp(a, b) == 0; +} + +/** @brief Copy Bluetooth device address. + * + * @param dst Bluetooth device address destination buffer. + * @param src Bluetooth device address source buffer. + */ +static inline void bt_addr_copy(bt_addr_t *dst, const bt_addr_t *src) +{ + memcpy(dst, src, sizeof(*dst)); +} + +/** @brief Copy Bluetooth LE device address. + * + * @param dst Bluetooth LE device address destination buffer. + * @param src Bluetooth LE device address source buffer. + */ +static inline void bt_addr_le_copy(bt_addr_le_t *dst, const bt_addr_le_t *src) +{ + memcpy(dst, src, sizeof(*dst)); +} + +/** Check if a Bluetooth LE random address is resolvable private address. */ +#define BT_ADDR_IS_RPA(a) (((a)->val[5] & 0xc0) == 0x40) +/** Check if a Bluetooth LE random address is a non-resolvable private address. + */ +#define BT_ADDR_IS_NRPA(a) (((a)->val[5] & 0xc0) == 0x00) +/** Check if a Bluetooth LE random address is a static address. */ +#define BT_ADDR_IS_STATIC(a) (((a)->val[5] & 0xc0) == 0xc0) + +/** Set a Bluetooth LE random address as a resolvable private address. */ +#define BT_ADDR_SET_RPA(a) ((a)->val[5] = (((a)->val[5] & 0x3f) | 0x40)) +/** Set a Bluetooth LE random address as a non-resolvable private address. */ +#define BT_ADDR_SET_NRPA(a) ((a)->val[5] &= 0x3f) +/** Set a Bluetooth LE random address as a static address. */ +#define BT_ADDR_SET_STATIC(a) ((a)->val[5] |= 0xc0) + +/** @brief Check if a Bluetooth LE address is a random private resolvable + * address. + * + * @param addr Bluetooth LE device address. + * + * @return true if address is a random private resolvable address. + */ +static inline bool bt_addr_le_is_rpa(const bt_addr_le_t *addr) +{ + if (addr->type != BT_ADDR_LE_RANDOM) { + return false; + } + + return BT_ADDR_IS_RPA(&addr->a); +} + +/** @brief Check if a Bluetooth LE address is valid identity address. + * + * Valid Bluetooth LE identity addresses are either public address or + * random static address. + * + * @param addr Bluetooth LE device address. + * + * @return true if address is a valid identity address. + */ +static inline bool bt_addr_le_is_identity(const bt_addr_le_t *addr) +{ + if (addr->type == BT_ADDR_LE_PUBLIC) { + return true; + } + + return BT_ADDR_IS_STATIC(&addr->a); +} + +/** + * @brief Recommended length of user string buffer for Bluetooth address + * + * @details The recommended length guarantee the output of address + * conversion will not lose valuable information about address being + * processed. + */ +#define BT_ADDR_STR_LEN 18 + +/** + * @brief Recommended length of user string buffer for Bluetooth LE address + * + * @details The recommended length guarantee the output of address + * conversion will not lose valuable information about address being + * processed. + */ +#define BT_ADDR_LE_STR_LEN 30 + +/** @brief Converts binary Bluetooth address to string. + * + * @param addr Address of buffer containing binary Bluetooth address. + * @param str Address of user buffer with enough room to store formatted + * string containing binary address. + * @param len Length of data to be copied to user string buffer. Refer to + * BT_ADDR_STR_LEN about recommended value. + * + * @return Number of successfully formatted bytes from binary address. + */ +static inline int bt_addr_to_str(const bt_addr_t *addr, char *str, size_t len) +{ + return snprintf(str, len, "%02X:%02X:%02X:%02X:%02X:%02X", + addr->val[5], addr->val[4], addr->val[3], + addr->val[2], addr->val[1], addr->val[0]); +} + +/** @brief Converts binary LE Bluetooth address to string. + * + * @param addr Address of buffer containing binary LE Bluetooth address. + * @param str Address of user buffer with enough room to store + * formatted string containing binary LE address. + * @param len Length of data to be copied to user string buffer. Refer to + * BT_ADDR_LE_STR_LEN about recommended value. + * + * @return Number of successfully formatted bytes from binary address. + */ +static inline int bt_addr_le_to_str(const bt_addr_le_t *addr, char *str, + size_t len) +{ + char type[10]; + + switch (addr->type) { + case BT_ADDR_LE_PUBLIC: + strcpy(type, "public"); + break; + case BT_ADDR_LE_RANDOM: + strcpy(type, "random"); + break; + case BT_ADDR_LE_PUBLIC_ID: + strcpy(type, "public-id"); + break; + case BT_ADDR_LE_RANDOM_ID: + strcpy(type, "random-id"); + break; + default: + snprintf(type, sizeof(type), "0x%02x", addr->type); + break; + } + + return snprintf(str, len, "%02X:%02X:%02X:%02X:%02X:%02X (%s)", + addr->a.val[5], addr->a.val[4], addr->a.val[3], + addr->a.val[2], addr->a.val[1], addr->a.val[0], type); +} + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_ADDR_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/assigned_numbers.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/assigned_numbers.h new file mode 100644 index 0000000000..a85059feb8 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/assigned_numbers.h @@ -0,0 +1,1276 @@ +/** @file + * @brief Bluetooth Assigned Numbers, codes and identifiers. + */ + +/* + * SPDX-FileCopyrightText: 2015-2025 Intel Corporation + * SPDX-FileCopyrightText: 2017-2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_ASSIGNED_NUMBERS_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_ASSIGNED_NUMBERS_H_ + +/** + * @brief Bluetooth Assigned Numbers, codes and identifiers. + * @defgroup bt_assigned_numbers Assigned Numbers. + * @since 1.0 + * @version 1.0.0 + * @ingroup bluetooth + * @{ + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Core Specification Assigned Numbers + * @defgroup bt_assigned_numbers_core Core Specification Assigned Numbers + * @ingroup bt_assigned_numbers + * @{ + */ + +/** + * @name Appearance Numbers + * + * Last Modified on 2023-01-05 + * @{ + */ + +/** Generic Unknown */ +#define BT_APPEARANCE_UNKNOWN 0x0000 +/** Generic Phone */ +#define BT_APPEARANCE_GENERIC_PHONE 0x0040 +/** Generic Computer */ +#define BT_APPEARANCE_GENERIC_COMPUTER 0x0080 +/** Desktop Workstation */ +#define BT_APPEARANCE_COMPUTER_DESKTOP_WORKSTATION 0x0081 +/** Server-class Computer */ +#define BT_APPEARANCE_COMPUTER_SERVER_CLASS 0x0082 +/** Laptop */ +#define BT_APPEARANCE_COMPUTER_LAPTOP 0x0083 +/** Handheld PC/PDA (clamshell) */ +#define BT_APPEARANCE_COMPUTER_HANDHELD_PCPDA 0x0084 +/** Palm­size PC/PDA */ +#define BT_APPEARANCE_COMPUTER_PALMSIZE_PCPDA 0x0085 +/** Wearable computer (watch size) */ +#define BT_APPEARANCE_COMPUTER_WEARABLE_COMPUTER 0x0086 +/** Tablet */ +#define BT_APPEARANCE_COMPUTER_TABLET 0x0087 +/** Docking Station */ +#define BT_APPEARANCE_COMPUTER_DOCKING_STATION 0x0088 +/** All in One */ +#define BT_APPEARANCE_COMPUTER_ALL_IN_ONE 0x0089 +/** Blade Server */ +#define BT_APPEARANCE_COMPUTER_BLADE_SERVER 0x008A +/** Convertible */ +#define BT_APPEARANCE_COMPUTER_CONVERTIBLE 0x008B +/** Detachable */ +#define BT_APPEARANCE_COMPUTER_DETACHABLE 0x008C +/** IoT Gateway */ +#define BT_APPEARANCE_COMPUTER_IOT_GATEWAY 0x008D +/** Mini PC */ +#define BT_APPEARANCE_COMPUTER_MINI_PC 0x008E +/** Stick PC */ +#define BT_APPEARANCE_COMPUTER_STICK_PC 0x008F +/** Generic Watch */ +#define BT_APPEARANCE_GENERIC_WATCH 0x00C0 +/** Sports Watch */ +#define BT_APPEARANCE_SPORTS_WATCH 0x00C1 +/** Smartwatch */ +#define BT_APPEARANCE_SMARTWATCH 0x00C2 +/** Generic Clock */ +#define BT_APPEARANCE_GENERIC_CLOCK 0x0100 +/** Generic Display */ +#define BT_APPEARANCE_GENERIC_DISPLAY 0x0140 +/** Generic Remote Control */ +#define BT_APPEARANCE_GENERIC_REMOTE 0x0180 +/** Generic Eye-glasses */ +#define BT_APPEARANCE_GENERIC_EYEGLASSES 0x01C0 +/** Generic Tag */ +#define BT_APPEARANCE_GENERIC_TAG 0x0200 +/** Generic Keyring */ +#define BT_APPEARANCE_GENERIC_KEYRING 0x0240 +/** Generic Media Player */ +#define BT_APPEARANCE_GENERIC_MEDIA_PLAYER 0x0280 +/** Generic Barcode Scanner */ +#define BT_APPEARANCE_GENERIC_BARCODE_SCANNER 0x02C0 +/** Generic Thermometer */ +#define BT_APPEARANCE_GENERIC_THERMOMETER 0x0300 +/** Ear Thermometer */ +#define BT_APPEARANCE_THERMOMETER_EAR 0x0301 +/** Generic Heart Rate Sensor */ +#define BT_APPEARANCE_GENERIC_HEART_RATE 0x0340 +/** Heart Rate Belt */ +#define BT_APPEARANCE_HEART_RATE_BELT 0x0341 +/** Generic Blood Pressure */ +#define BT_APPEARANCE_GENERIC_BLOOD_PRESSURE 0x0380 +/** Arm Blood Pressure */ +#define BT_APPEARANCE_BLOOD_PRESSURE_ARM 0x0381 +/** Wrist Blood Pressure */ +#define BT_APPEARANCE_BLOOD_PRESSURE_WRIST 0x0382 +/** Generic Human Interface Device */ +#define BT_APPEARANCE_GENERIC_HID 0x03C0 +/** Keyboard */ +#define BT_APPEARANCE_HID_KEYBOARD 0x03C1 +/** Mouse */ +#define BT_APPEARANCE_HID_MOUSE 0x03C2 +/** Joystick */ +#define BT_APPEARANCE_HID_JOYSTICK 0x03C3 +/** Gamepad */ +#define BT_APPEARANCE_HID_GAMEPAD 0x03C4 +/** Digitizer Tablet */ +#define BT_APPEARANCE_HID_DIGITIZER_TABLET 0x03C5 +/** Card Reader */ +#define BT_APPEARANCE_HID_CARD_READER 0x03C6 +/** Digital Pen */ +#define BT_APPEARANCE_HID_DIGITAL_PEN 0x03C7 +/** Barcode Scanner */ +#define BT_APPEARANCE_HID_BARCODE_SCANNER 0x03C8 +/** Touchpad */ +#define BT_APPEARANCE_HID_TOUCHPAD 0x03C9 +/** Presentation Remote */ +#define BT_APPEARANCE_HID_PRESENTATION_REMOTE 0x03CA +/** Generic Glucose Meter */ +#define BT_APPEARANCE_GENERIC_GLUCOSE 0x0400 +/** Generic Running Walking Sensor */ +#define BT_APPEARANCE_GENERIC_WALKING 0x0440 +/** In-Shoe Running Walking Sensor */ +#define BT_APPEARANCE_WALKING_IN_SHOE 0x0441 +/** On-Shoe Running Walking Sensor */ +#define BT_APPEARANCE_WALKING_ON_SHOE 0x0442 +/** On-Hip Running Walking Sensor */ +#define BT_APPEARANCE_WALKING_ON_HIP 0x0443 +/** Generic Cycling */ +#define BT_APPEARANCE_GENERIC_CYCLING 0x0480 +/** Cycling Computer */ +#define BT_APPEARANCE_CYCLING_COMPUTER 0x0481 +/** Speed Sensor */ +#define BT_APPEARANCE_CYCLING_SPEED 0x0482 +/** Cadence Sensor */ +#define BT_APPEARANCE_CYCLING_CADENCE 0x0483 +/** Power Sensor */ +#define BT_APPEARANCE_CYCLING_POWER 0x0484 +/** Speed and Cadence Sensor */ +#define BT_APPEARANCE_CYCLING_SPEED_CADENCE 0x0485 +/** Generic Control Device */ +#define BT_APPEARANCE_GENERIC_CONTROL_DEVICE 0x04C0 +/** Switch */ +#define BT_APPEARANCE_CONTROL_SWITCH 0x04C1 +/** Multi-switch */ +#define BT_APPEARANCE_CONTROL_MULTI_SWITCH 0x04C2 +/** Button */ +#define BT_APPEARANCE_CONTROL_BUTTON 0x04C3 +/** Slider */ +#define BT_APPEARANCE_CONTROL_SLIDER 0x04C4 +/** Rotary Switch */ +#define BT_APPEARANCE_CONTROL_ROTARY_SWITCH 0x04C5 +/** Touch Panel */ +#define BT_APPEARANCE_CONTROL_TOUCH_PANEL 0x04C6 +/** Single Switch */ +#define BT_APPEARANCE_CONTROL_SINGLE_SWITCH 0x04C7 +/** Double Switch */ +#define BT_APPEARANCE_CONTROL_DOUBLE_SWITCH 0x04C8 +/** Triple Switch */ +#define BT_APPEARANCE_CONTROL_TRIPLE_SWITCH 0x04C9 +/** Battery Switch */ +#define BT_APPEARANCE_CONTROL_BATTERY_SWITCH 0x04CA +/** Energy Harvesting Switch */ +#define BT_APPEARANCE_CONTROL_ENERGY_HARVESTING_SWITCH 0x04CB +/** Push Button */ +#define BT_APPEARANCE_CONTROL_PUSH_BUTTON 0x04CC +/** Generic Network Device */ +#define BT_APPEARANCE_GENERIC_NETWORK_DEVICE 0x0500 +/** Access Point */ +#define BT_APPEARANCE_NETWORK_ACCESS_POINT 0x0501 +/** Mesh Device */ +#define BT_APPEARANCE_NETWORK_MESH_DEVICE 0x0502 +/** Mesh Network Proxy */ +#define BT_APPEARANCE_NETWORK_MESH_PROXY 0x0503 +/** Generic Sensor */ +#define BT_APPEARANCE_GENERIC_SENSOR 0x0540 +/** Motion Sensor */ +#define BT_APPEARANCE_SENSOR_MOTION 0x0541 +/** Air quality Sensor */ +#define BT_APPEARANCE_SENSOR_AIR_QUALITY 0x0542 +/** Temperature Sensor */ +#define BT_APPEARANCE_SENSOR_TEMPERATURE 0x0543 +/** Humidity Sensor */ +#define BT_APPEARANCE_SENSOR_HUMIDITY 0x0544 +/** Leak Sensor */ +#define BT_APPEARANCE_SENSOR_LEAK 0x0545 +/** Smoke Sensor */ +#define BT_APPEARANCE_SENSOR_SMOKE 0x0546 +/** Occupancy Sensor */ +#define BT_APPEARANCE_SENSOR_OCCUPANCY 0x0547 +/** Contact Sensor */ +#define BT_APPEARANCE_SENSOR_CONTACT 0x0548 +/** Carbon Monoxide Sensor */ +#define BT_APPEARANCE_SENSOR_CARBON_MONOXIDE 0x0549 +/** Carbon Dioxide Sensor */ +#define BT_APPEARANCE_SENSOR_CARBON_DIOXIDE 0x054A +/** Ambient Light Sensor */ +#define BT_APPEARANCE_SENSOR_AMBIENT_LIGHT 0x054B +/** Energy Sensor */ +#define BT_APPEARANCE_SENSOR_ENERGY 0x054C +/** Color Light Sensor */ +#define BT_APPEARANCE_SENSOR_COLOR_LIGHT 0x054D +/** Rain Sensor */ +#define BT_APPEARANCE_SENSOR_RAIN 0x054E +/** Fire Sensor */ +#define BT_APPEARANCE_SENSOR_FIRE 0x054F +/** Wind Sensor */ +#define BT_APPEARANCE_SENSOR_WIND 0x0550 +/** Proximity Sensor */ +#define BT_APPEARANCE_SENSOR_PROXIMITY 0x0551 +/** Multi-Sensor */ +#define BT_APPEARANCE_SENSOR_MULTI 0x0552 +/** Flush Mounted Sensor */ +#define BT_APPEARANCE_SENSOR_FLUSH_MOUNTED 0x0553 +/** Ceiling Mounted Sensor */ +#define BT_APPEARANCE_SENSOR_CEILING_MOUNTED 0x0554 +/** Wall Mounted Sensor */ +#define BT_APPEARANCE_SENSOR_WALL_MOUNTED 0x0555 +/** Multisensor */ +#define BT_APPEARANCE_MULTISENSOR 0x0556 +/** Energy Meter */ +#define BT_APPEARANCE_SENSOR_ENERGY_METER 0x0557 +/** Flame Detector */ +#define BT_APPEARANCE_SENSOR_FLAME_DETECTOR 0x0558 +/** Vehicle Tire Pressure Sensor */ +#define BT_APPEARANCE_SENSOR_VEHICLE_TIRE_PRESSURE 0x0559 +/** Generic Light Fixtures */ +#define BT_APPEARANCE_GENERIC_LIGHT_FIXTURES 0x0580 +/** Wall Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_WALL 0x0581 +/** Ceiling Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_CEILING 0x0582 +/** Floor Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_FLOOR 0x0583 +/** Cabinet Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_CABINET 0x0584 +/** Desk Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_DESK 0x0585 +/** Troffer Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_TROFFER 0x0586 +/** Pendant Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_PENDANT 0x0587 +/** In-ground Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_IN_GROUND 0x0588 +/** Flood Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_FLOOD 0x0589 +/** Underwater Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_UNDERWATER 0x058A +/** Bollard with Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_BOLLARD_WITH 0x058B +/** Pathway Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_PATHWAY 0x058C +/** Garden Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_GARDEN 0x058D +/** Pole-top Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_POLE_TOP 0x058E +/** Spotlight */ +#define BT_APPEARANCE_SPOT_LIGHT 0x058F +/** Linear Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_LINEAR 0x0590 +/** Street Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_STREET 0x0591 +/** Shelves Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_SHELVES 0x0592 +/** Bay Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_BAY 0x0593 +/** Emergency Exit Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_EMERGENCY_EXIT 0x0594 +/** Light Controller */ +#define BT_APPEARANCE_LIGHT_FIXTURES_CONTROLLER 0x0595 +/** Light Driver */ +#define BT_APPEARANCE_LIGHT_FIXTURES_DRIVER 0x0596 +/** Bulb */ +#define BT_APPEARANCE_LIGHT_FIXTURES_BULB 0x0597 +/** Low-bay Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_LOW_BAY 0x0598 +/** High-bay Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_HIGH_BAY 0x0599 +/** Generic Fan */ +#define BT_APPEARANCE_GENERIC_FAN 0x05C0 +/** Ceiling Fan */ +#define BT_APPEARANCE_FAN_CEILING 0x05C1 +/** Axial Fan */ +#define BT_APPEARANCE_FAN_AXIAL 0x05C2 +/** Exhaust Fan */ +#define BT_APPEARANCE_FAN_EXHAUST 0x05C3 +/** Pedestal Fan */ +#define BT_APPEARANCE_FAN_PEDESTAL 0x05C4 +/** Desk Fan */ +#define BT_APPEARANCE_FAN_DESK 0x05C5 +/** Wall Fan */ +#define BT_APPEARANCE_FAN_WALL 0x05C6 +/** Generic HVAC */ +#define BT_APPEARANCE_GENERIC_HVAC 0x0600 +/** Thermostat */ +#define BT_APPEARANCE_HVAC_THERMOSTAT 0x0601 +/** Humidifier */ +#define BT_APPEARANCE_HVAC_HUMIDIFIER 0x0602 +/** De-humidifier */ +#define BT_APPEARANCE_HVAC_DEHUMIDIFIER 0x0603 +/** Heater */ +#define BT_APPEARANCE_HVAC_HEATER 0x0604 +/** Radiator */ +#define BT_APPEARANCE_HVAC_RADIATOR 0x0605 +/** Boiler */ +#define BT_APPEARANCE_HVAC_BOILER 0x0606 +/** Heat Pump */ +#define BT_APPEARANCE_HVAC_HEAT_PUMP 0x0607 +/** Infrared Heater */ +#define BT_APPEARANCE_HVAC_INFRARED_HEATER 0x0608 +/** Radiant Panel Heater */ +#define BT_APPEARANCE_HVAC_RADIANT_PANEL_HEATER 0x0609 +/** Fan Heater */ +#define BT_APPEARANCE_HVAC_FAN_HEATER 0x060A +/** Air Curtain */ +#define BT_APPEARANCE_HVAC_AIR_CURTAIN 0x060B +/** Generic Air Conditioning */ +#define BT_APPEARANCE_GENERIC_AIR_CONDITIONING 0x0640 +/** Generic Humidifier */ +#define BT_APPEARANCE_GENERIC_HUMIDIFIER 0x0680 +/** Generic Heating */ +#define BT_APPEARANCE_GENERIC_HEATING 0x06C0 +/** Radiator */ +#define BT_APPEARANCE_HEATING_RADIATOR 0x06C1 +/** Boiler */ +#define BT_APPEARANCE_HEATING_BOILER 0x06C2 +/** Heat Pump */ +#define BT_APPEARANCE_HEATING_HEAT_PUMP 0x06C3 +/** Infrared Heater */ +#define BT_APPEARANCE_HEATING_INFRARED_HEATER 0x06C4 +/** Radiant Panel Heater */ +#define BT_APPEARANCE_HEATING_RADIANT_PANEL_HEATER 0x06C5 +/** Fan Heater */ +#define BT_APPEARANCE_HEATING_FAN_HEATER 0x06C6 +/** Air Curtain */ +#define BT_APPEARANCE_HEATING_AIR_CURTAIN 0x06C7 +/** Generic Access Control */ +#define BT_APPEARANCE_GENERIC_ACCESS_CONTROL 0x0700 +/** Access Door */ +#define BT_APPEARANCE_CONTROL_ACCESS_DOOR 0x0701 +/** Garage Door */ +#define BT_APPEARANCE_CONTROL_GARAGE_DOOR 0x0702 +/** Emergency Exit Door */ +#define BT_APPEARANCE_CONTROL_EMERGENCY_EXIT_DOOR 0x0703 +/** Access Lock */ +#define BT_APPEARANCE_CONTROL_ACCESS_LOCK 0x0704 +/** Elevator */ +#define BT_APPEARANCE_CONTROL_ELEVATOR 0x0705 +/** Window */ +#define BT_APPEARANCE_CONTROL_WINDOW 0x0706 +/** Entrance Gate */ +#define BT_APPEARANCE_CONTROL_ENTRANCE_GATE 0x0707 +/** Door Lock */ +#define BT_APPEARANCE_CONTROL_DOOR_LOCK 0x0708 +/** Locker */ +#define BT_APPEARANCE_CONTROL_LOCKER 0x0709 +/** Generic Motorized Device */ +#define BT_APPEARANCE_GENERIC_MOTORIZED_DEVICE 0x0740 +/** Motorized Gate */ +#define BT_APPEARANCE_MOTORIZED_GATE 0x0741 +/** Awning */ +#define BT_APPEARANCE_MOTORIZED_AWNING 0x0742 +/** Blinds or Shades */ +#define BT_APPEARANCE_MOTORIZED_BLINDS_OR_SHADES 0x0743 +/** Curtains */ +#define BT_APPEARANCE_MOTORIZED_CURTAINS 0x0744 +/** Screen */ +#define BT_APPEARANCE_MOTORIZED_SCREEN 0x0745 +/** Generic Power Device */ +#define BT_APPEARANCE_GENERIC_POWER_DEVICE 0x0780 +/** Power Outlet */ +#define BT_APPEARANCE_POWER_OUTLET 0x0781 +/** Power Strip */ +#define BT_APPEARANCE_POWER_STRIP 0x0782 +/** Plug */ +#define BT_APPEARANCE_POWER_PLUG 0x0783 +/** Power Supply */ +#define BT_APPEARANCE_POWER_SUPPLY 0x0784 +/** LED Driver */ +#define BT_APPEARANCE_POWER_LED_DRIVER 0x0785 +/** Fluorescent Lamp Gear */ +#define BT_APPEARANCE_POWER_FLUORESCENT_LAMP_GEAR 0x0786 +/** HID Lamp Gear */ +#define BT_APPEARANCE_POWER_HID_LAMP_GEAR 0x0787 +/** Charge Case */ +#define BT_APPEARANCE_POWER_CHARGE_CASE 0x0788 +/** Power Bank */ +#define BT_APPEARANCE_POWER_POWER_BANK 0x0789 +/** Generic Light Source */ +#define BT_APPEARANCE_GENERIC_LIGHT_SOURCE 0x07C0 +/** Incandescent Light Bulb */ +#define BT_APPEARANCE_LIGHT_SOURCE_INCANDESCENT_BULB 0x07C1 +/** LED Lamp */ +#define BT_APPEARANCE_LIGHT_SOURCE_LED_LAMP 0x07C2 +/** HID Lamp */ +#define BT_APPEARANCE_LIGHT_SOURCE_HID_LAMP 0x07C3 +/** Fluorescent Lamp */ +#define BT_APPEARANCE_LIGHT_SOURCE_FLUORESCENT_LAMP 0x07C4 +/** LED Array */ +#define BT_APPEARANCE_LIGHT_SOURCE_LED_ARRAY 0x07C5 +/** Multi-Color LED Array */ +#define BT_APPEARANCE_LIGHT_SOURCE_MULTICOLOR_LED_ARRAY 0x07C6 +/** Low voltage halogen */ +#define BT_APPEARANCE_LIGHT_SOURCE_LOW_VOLTAGE_HALOGEN 0x07C7 +/** Organic light emitting diode */ +#define BT_APPEARANCE_LIGHT_SOURCE_OLED 0x07C8 +/** Generic Window Covering */ +#define BT_APPEARANCE_GENERIC_WINDOW_COVERING 0x0800 +/** Window Shades */ +#define BT_APPEARANCE_WINDOW_SHADES 0x0801 +/** Window Blinds */ +#define BT_APPEARANCE_WINDOW_BLINDS 0x0802 +/** Window Awning */ +#define BT_APPEARANCE_WINDOW_AWNING 0x0803 +/** Window Curtain */ +#define BT_APPEARANCE_WINDOW_CURTAIN 0x0804 +/** Exterior Shutter */ +#define BT_APPEARANCE_WINDOW_EXTERIOR_SHUTTER 0x0805 +/** Exterior Screen */ +#define BT_APPEARANCE_WINDOW_EXTERIOR_SCREEN 0x0806 +/** Generic Audio Sink */ +#define BT_APPEARANCE_GENERIC_AUDIO_SINK 0x0840 +/** Standalone Speaker */ +#define BT_APPEARANCE_AUDIO_SINK_STANDALONE_SPEAKER 0x0841 +/** Soundbar */ +#define BT_APPEARANCE_AUDIO_SINK_SOUNDBAR 0x0842 +/** Bookshelf Speaker */ +#define BT_APPEARANCE_AUDIO_SINK_BOOKSHELF_SPEAKER 0x0843 +/** Standmounted Speaker */ +#define BT_APPEARANCE_AUDIO_SINK_STANDMOUNTED_SPEAKER 0x0844 +/** Speakerphone */ +#define BT_APPEARANCE_AUDIO_SINK_SPEAKERPHONE 0x0845 +/** Generic Audio Source */ +#define BT_APPEARANCE_GENERIC_AUDIO_SOURCE 0x0880 +/** Microphone */ +#define BT_APPEARANCE_AUDIO_SOURCE_MICROPHONE 0x0881 +/** Alarm */ +#define BT_APPEARANCE_AUDIO_SOURCE_ALARM 0x0882 +/** Bell */ +#define BT_APPEARANCE_AUDIO_SOURCE_BELL 0x0883 +/** Horn */ +#define BT_APPEARANCE_AUDIO_SOURCE_HORN 0x0884 +/** Broadcasting Device */ +#define BT_APPEARANCE_AUDIO_SOURCE_BROADCASTING_DEVICE 0x0885 +/** Service Desk */ +#define BT_APPEARANCE_AUDIO_SOURCE_SERVICE_DESK 0x0886 +/** Kiosk */ +#define BT_APPEARANCE_AUDIO_SOURCE_KIOSK 0x0887 +/** Broadcasting Room */ +#define BT_APPEARANCE_AUDIO_SOURCE_BROADCASTING_ROOM 0x0888 +/** Auditorium */ +#define BT_APPEARANCE_AUDIO_SOURCE_AUDITORIUM 0x0889 +/** Generic Motorized Vehicle */ +#define BT_APPEARANCE_GENERIC_MOTORIZED_VEHICLE 0x08C0 +/** Car */ +#define BT_APPEARANCE_VEHICLE_CAR 0x08C1 +/** Large Goods Vehicle */ +#define BT_APPEARANCE_VEHICLE_LARGE_GOODS 0x08C2 +/** 2-Wheeled Vehicle */ +#define BT_APPEARANCE_VEHICLE_TWO_WHEELED 0x08C3 +/** Motorbike */ +#define BT_APPEARANCE_VEHICLE_MOTORBIKE 0x08C4 +/** Scooter */ +#define BT_APPEARANCE_VEHICLE_SCOOTER 0x08C5 +/** Moped */ +#define BT_APPEARANCE_VEHICLE_MOPED 0x08C6 +/** 3-Wheeled Vehicle */ +#define BT_APPEARANCE_VEHICLE_THREE_WHEELED 0x08C7 +/** Light Vehicle */ +#define BT_APPEARANCE_VEHICLE_LIGHT 0x08C8 +/** Quad Bike */ +#define BT_APPEARANCE_VEHICLE_QUAD_BIKE 0x08C9 +/** Minibus */ +#define BT_APPEARANCE_VEHICLE_MINIBUS 0x08CA +/** Bus */ +#define BT_APPEARANCE_VEHICLE_BUS 0x08CB +/** Trolley */ +#define BT_APPEARANCE_VEHICLE_TROLLEY 0x08CC +/** Agricultural Vehicle */ +#define BT_APPEARANCE_VEHICLE_AGRICULTURAL 0x08CD +/** Camper/Caravan */ +#define BT_APPEARANCE_VEHICLE_CAMPER_OR_CARAVAN 0x08CE +/** Recreational Vehicle/Motor Home */ +#define BT_APPEARANCE_VEHICLE_RECREATIONAL 0x08CF +/** Generic Domestic Appliance */ +#define BT_APPEARANCE_GENERIC_DOMESTIC_APPLIANCE 0x0900 +/** Refrigerator */ +#define BT_APPEARANCE_APPLIANCE_REFRIGERATOR 0x0901 +/** Freezer */ +#define BT_APPEARANCE_APPLIANCE_FREEZER 0x0902 +/** Oven */ +#define BT_APPEARANCE_APPLIANCE_OVEN 0x0903 +/** Microwave */ +#define BT_APPEARANCE_APPLIANCE_MICROWAVE 0x0904 +/** Toaster */ +#define BT_APPEARANCE_APPLIANCE_TOASTER 0x0905 +/** Washing Machine */ +#define BT_APPEARANCE_APPLIANCE_WASHING_MACHINE 0x0906 +/** Dryer */ +#define BT_APPEARANCE_APPLIANCE_DRYER 0x0907 +/** Coffee maker */ +#define BT_APPEARANCE_APPLIANCE_COFFEE_MAKER 0x0908 +/** Clothes iron */ +#define BT_APPEARANCE_APPLIANCE_CLOTHES_IRON 0x0909 +/** Curling iron */ +#define BT_APPEARANCE_APPLIANCE_CURLING_IRON 0x090A +/** Hair dryer */ +#define BT_APPEARANCE_APPLIANCE_HAIR_DRYER 0x090B +/** Vacuum cleaner */ +#define BT_APPEARANCE_APPLIANCE_VACUUM_CLEANER 0x090C +/** Robotic vacuum cleaner */ +#define BT_APPEARANCE_APPLIANCE_ROBOTIC_VACUUM_CLEANER 0x090D +/** Rice cooker */ +#define BT_APPEARANCE_APPLIANCE_RICE_COOKER 0x090E +/** Clothes steamer */ +#define BT_APPEARANCE_APPLIANCE_CLOTHES_STEAMER 0x090F +/** Generic Wearable Audio Device */ +#define BT_APPEARANCE_GENERIC_WEARABLE_AUDIO_DEVICE 0x0940 +/** Earbud */ +#define BT_APPEARANCE_WEARABLE_AUDIO_DEVICE_EARBUD 0x0941 +/** Headset */ +#define BT_APPEARANCE_WEARABLE_AUDIO_DEVICE_HEADSET 0x0942 +/** Headphones */ +#define BT_APPEARANCE_WEARABLE_AUDIO_DEVICE_HEADPHONES 0x0943 +/** Neck Band */ +#define BT_APPEARANCE_WEARABLE_AUDIO_DEVICE_NECK_BAND 0x0944 +/** Generic Aircraft */ +#define BT_APPEARANCE_GENERIC_AIRCRAFT 0x0980 +/** Light Aircraft */ +#define BT_APPEARANCE_AIRCRAFT_LIGHT 0x0981 +/** Microlight */ +#define BT_APPEARANCE_AIRCRAFT_MICROLIGHT 0x0982 +/** Paraglider */ +#define BT_APPEARANCE_AIRCRAFT_PARAGLIDER 0x0983 +/** Large Passenger Aircraft */ +#define BT_APPEARANCE_AIRCRAFT_LARGE_PASSENGER 0x0984 +/** Generic AV Equipment */ +#define BT_APPEARANCE_GENERIC_AV_EQUIPMENT 0x09C0 +/** Amplifier */ +#define BT_APPEARANCE_AV_EQUIPMENT_AMPLIFIER 0x09C1 +/** Receiver */ +#define BT_APPEARANCE_AV_EQUIPMENT_RECEIVER 0x09C2 +/** Radio */ +#define BT_APPEARANCE_AV_EQUIPMENT_RADIO 0x09C3 +/** Tuner */ +#define BT_APPEARANCE_AV_EQUIPMENT_TUNER 0x09C4 +/** Turntable */ +#define BT_APPEARANCE_AV_EQUIPMENT_TURNTABLE 0x09C5 +/** CD Player */ +#define BT_APPEARANCE_AV_EQUIPMENT_CD_PLAYER 0x09C6 +/** DVD Player */ +#define BT_APPEARANCE_AV_EQUIPMENT_DVD_PLAYER 0x09C7 +/** Bluray Player */ +#define BT_APPEARANCE_AV_EQUIPMENT_BLURAY_PLAYER 0x09C8 +/** Optical Disc Player */ +#define BT_APPEARANCE_AV_EQUIPMENT_OPTICAL_DISC_PLAYER 0x09C9 +/** Set-Top Box */ +#define BT_APPEARANCE_AV_EQUIPMENT_SET_TOP_BOX 0x09CA +/** Generic Display Equipment */ +#define BT_APPEARANCE_GENERIC_DISPLAY_EQUIPMENT 0x0A00 +/** Television */ +#define BT_APPEARANCE_DISPLAY_EQUIPMENT_TELEVISION 0x0A01 +/** Monitor */ +#define BT_APPEARANCE_DISPLAY_EQUIPMENT_MONITOR 0x0A02 +/** Projector */ +#define BT_APPEARANCE_DISPLAY_EQUIPMENT_PROJECTOR 0x0A03 +/** Generic Hearing aid */ +#define BT_APPEARANCE_GENERIC_HEARING_AID 0x0A40 +/** In-ear hearing aid */ +#define BT_APPEARANCE_HEARING_AID_IN_EAR 0x0A41 +/** Behind-ear hearing aid */ +#define BT_APPEARANCE_HEARING_AID_BEHIND_EAR 0x0A42 +/** Cochlear Implant */ +#define BT_APPEARANCE_HEARING_AID_COCHLEAR_IMPLANT 0x0A43 +/** Generic Gaming */ +#define BT_APPEARANCE_GENERIC_GAMING 0x0A80 +/** Home Video Game Console */ +#define BT_APPEARANCE_HOME_VIDEO_GAME_CONSOLE 0x0A81 +/** Portable handheld console */ +#define BT_APPEARANCE_PORTABLE_HANDHELD_CONSOLE 0x0A82 +/** Generic Signage */ +#define BT_APPEARANCE_GENERIC_SIGNAGE 0x0AC0 +/** Digital Signage */ +#define BT_APPEARANCE_SIGNAGE_DIGITAL 0x0AC1 +/** Electronic Label */ +#define BT_APPEARANCE_SIGNAGE_ELECTRONIC_LABEL 0x0AC2 +/** Generic Pulse Oximeter */ +#define BT_APPEARANCE_GENERIC_PULSE_OXIMETER 0x0C40 +/** Fingertip Pulse Oximeter */ +#define BT_APPEARANCE_PULSE_OXIMETER_FINGERTIP 0x0C41 +/** Wrist Worn Pulse Oximeter */ +#define BT_APPEARANCE_PULSE_OXIMETER_WRIST 0x0C42 +/** Generic Weight Scale */ +#define BT_APPEARANCE_GENERIC_WEIGHT_SCALE 0x0C80 +/** Generic Personal Mobility Device */ +#define BT_APPEARANCE_GENERIC_PERSONAL_MOBILITY_DEVICE 0x0CC0 +/** Powered Wheelchair */ +#define BT_APPEARANCE_MOBILITY_POWERED_WHEELCHAIR 0x0CC1 +/** Mobility Scooter */ +#define BT_APPEARANCE_MOBILITY_SCOOTER 0x0CC2 +/** Continuous Glucose Monitor */ +#define BT_APPEARANCE_CONTINUOUS_GLUCOSE_MONITOR 0x0D00 +/** Generic Insulin Pump */ +#define BT_APPEARANCE_GENERIC_INSULIN_PUMP 0x0D40 +/** Insulin Pump, durable pump */ +#define BT_APPEARANCE_INSULIN_PUMP_DURABLE 0x0D41 +/** Insulin Pump, patch pump */ +#define BT_APPEARANCE_INSULIN_PUMP_PATCH 0x0D44 +/** Insulin Pen */ +#define BT_APPEARANCE_INSULIN_PEN 0x0D48 +/** Generic Medication Delivery */ +#define BT_APPEARANCE_GENERIC_MEDICATION_DELIVERY 0x0D80 +/** Generic Spirometer */ +#define BT_APPEARANCE_GENERIC_SPIROMETER 0x0DC0 +/** Handheld Spirometer */ +#define BT_APPEARANCE_SPIROMETER_HANDHELD 0x0DC1 +/** Generic Outdoor Sports Activity */ +#define BT_APPEARANCE_GENERIC_OUTDOOR_SPORTS 0x1440 +/** Location Display */ +#define BT_APPEARANCE_OUTDOOR_SPORTS_LOCATION 0x1441 +/** Location and Navigation Display */ +#define BT_APPEARANCE_OUTDOOR_SPORTS_LOCATION_AND_NAV 0x1442 +/** Location Pod */ +#define BT_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD 0x1443 +/** Location and Navigation Pod */ +#define BT_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD_AND_NAV 0x1444 + +/** @} */ /* end of @name Appearance Numbers */ + +/** + * @name Common Data Types + * @{ + */ +#define BT_DATA_FLAGS 0x01 /**< AD flags */ +#define BT_DATA_UUID16_SOME 0x02 /**< 16-bit UUID, more available */ +#define BT_DATA_UUID16_ALL 0x03 /**< 16-bit UUID, all listed */ +#define BT_DATA_UUID32_SOME 0x04 /**< 32-bit UUID, more available */ +#define BT_DATA_UUID32_ALL 0x05 /**< 32-bit UUID, all listed */ +#define BT_DATA_UUID128_SOME 0x06 /**< 128-bit UUID, more available */ +#define BT_DATA_UUID128_ALL 0x07 /**< 128-bit UUID, all listed */ +#define BT_DATA_NAME_SHORTENED 0x08 /**< Shortened name */ +#define BT_DATA_NAME_COMPLETE 0x09 /**< Complete name */ +#define BT_DATA_TX_POWER 0x0a /**< Tx Power */ +#define BT_DATA_DEVICE_CLASS 0x0d /**< Class of Device */ +#define BT_DATA_SIMPLE_PAIRING_HASH_C192 0x0e /**< Simple Pairing Hash C-192 */ +#define BT_DATA_SIMPLE_PAIRING_RAND_C192 0x0f /**< Simple Pairing Randomizer R-192 */ +#define BT_DATA_DEVICE_ID 0x10 /**< Device ID (Profile) */ +#define BT_DATA_SM_TK_VALUE 0x10 /**< Security Manager TK Value */ +#define BT_DATA_SM_OOB_FLAGS 0x11 /**< Security Manager OOB Flags */ +#define BT_DATA_PERIPHERAL_INT_RANGE 0x12 /**< Peripheral Connection Interval Range */ +#define BT_DATA_SOLICIT16 0x14 /**< Solicit UUIDs, 16-bit */ +#define BT_DATA_SOLICIT128 0x15 /**< Solicit UUIDs, 128-bit */ +#define BT_DATA_SVC_DATA16 0x16 /**< Service data, 16-bit UUID */ +#define BT_DATA_PUB_TARGET_ADDR 0x17 /**< Public Target Address */ +#define BT_DATA_RAND_TARGET_ADDR 0x18 /**< Random Target Address */ +#define BT_DATA_GAP_APPEARANCE 0x19 /**< GAP appearance */ +#define BT_DATA_ADV_INT 0x1a /**< Advertising Interval */ +#define BT_DATA_LE_BT_DEVICE_ADDRESS 0x1b /**< LE Bluetooth Device Address */ +#define BT_DATA_LE_ROLE 0x1c /**< LE Role */ +#define BT_DATA_SIMPLE_PAIRING_HASH 0x1d /**< Simple Pairing Hash C256 */ +#define BT_DATA_SIMPLE_PAIRING_RAND 0x1e /**< Simple Pairing Randomizer R256 */ +#define BT_DATA_SOLICIT32 0x1f /**< Solicit UUIDs, 32-bit */ +#define BT_DATA_SVC_DATA32 0x20 /**< Service data, 32-bit UUID */ +#define BT_DATA_SVC_DATA128 0x21 /**< Service data, 128-bit UUID */ +#define BT_DATA_LE_SC_CONFIRM_VALUE 0x22 /**< LE SC Confirmation Value */ +#define BT_DATA_LE_SC_RANDOM_VALUE 0x23 /**< LE SC Random Value */ +#define BT_DATA_URI 0x24 /**< URI */ +#define BT_DATA_INDOOR_POS 0x25 /**< Indoor Positioning */ +#define BT_DATA_TRANS_DISCOVER_DATA 0x26 /**< Transport Discovery Data */ +#define BT_DATA_LE_SUPPORTED_FEATURES 0x27 /**< LE Supported Features */ +#define BT_DATA_CHANNEL_MAP_UPDATE_IND 0x28 /**< Channel Map Update Indication */ +#define BT_DATA_MESH_PROV 0x29 /**< Mesh Provisioning PDU */ +#define BT_DATA_MESH_MESSAGE 0x2a /**< Mesh Networking PDU */ +#define BT_DATA_MESH_BEACON 0x2b /**< Mesh Beacon */ +#define BT_DATA_BIG_INFO 0x2c /**< BIGInfo */ +#define BT_DATA_BROADCAST_CODE 0x2d /**< Broadcast Code */ +#define BT_DATA_CSIS_RSI 0x2e /**< CSIS Random Set ID type */ +#define BT_DATA_ADV_INT_LONG 0x2f /**< Advertising Interval long */ +#define BT_DATA_BROADCAST_NAME 0x30 /**< Broadcast Name */ +#define BT_DATA_ENCRYPTED_AD_DATA 0x31 /**< Encrypted Advertising Data */ +#define BT_DATA_PAWR_TIMING_INFO 0x32 /**< Periodic Advertising Response Timing Info */ +#define BT_DATA_ESL 0x34 /**< Electronic Shelf Label Profile */ +#define BT_DATA_3D_INFO 0x3D /**< 3D Information Data */ + +#define BT_DATA_MANUFACTURER_DATA 0xff /**< Manufacturer Specific Data */ + +/** @} */ /* end of @name Common Data Types */ + +/** + * @name Flags data type values + * @{ + */ + +#define BT_LE_AD_LIMITED 0x01 /**< Limited Discoverable */ +#define BT_LE_AD_GENERAL 0x02 /**< General Discoverable */ +#define BT_LE_AD_NO_BREDR 0x04 /**< BR/EDR not supported */ + +/** @} */ /* end of @name Flags data type values */ +/** @} */ /* end of bt_assigned_numbers_core */ + +/** + * @brief Generic Audio Assigned Numbers + * @defgroup bt_assigned_numbers_audio Generic Audio Assigned Numbers + * @ingroup bt_assigned_numbers + * @{ + */ + +/** + * @brief Codec capability types + * + * Used to build and parse codec capabilities as specified in the PAC specification. + * Source is assigned numbers for Generic Audio, bluetooth.com. + */ +enum bt_audio_codec_cap_type { + /** Supported sampling frequencies */ + BT_AUDIO_CODEC_CAP_TYPE_FREQ = 0x01, + + /** Supported frame durations */ + BT_AUDIO_CODEC_CAP_TYPE_DURATION = 0x02, + + /** Supported audio channel counts */ + BT_AUDIO_CODEC_CAP_TYPE_CHAN_COUNT = 0x03, + + /** Supported octets per codec frame */ + BT_AUDIO_CODEC_CAP_TYPE_FRAME_LEN = 0x04, + + /** Supported maximum codec frames per SDU */ + BT_AUDIO_CODEC_CAP_TYPE_FRAME_COUNT = 0x05, +}; + +/** @brief Supported frequencies bitfield */ +enum bt_audio_codec_cap_freq { + /** 8 Khz sampling frequency */ + BT_AUDIO_CODEC_CAP_FREQ_8KHZ = BIT(0), + + /** 11.025 Khz sampling frequency */ + BT_AUDIO_CODEC_CAP_FREQ_11KHZ = BIT(1), + + /** 16 Khz sampling frequency */ + BT_AUDIO_CODEC_CAP_FREQ_16KHZ = BIT(2), + + /** 22.05 Khz sampling frequency */ + BT_AUDIO_CODEC_CAP_FREQ_22KHZ = BIT(3), + + /** 24 Khz sampling frequency */ + BT_AUDIO_CODEC_CAP_FREQ_24KHZ = BIT(4), + + /** 32 Khz sampling frequency */ + BT_AUDIO_CODEC_CAP_FREQ_32KHZ = BIT(5), + + /** 44.1 Khz sampling frequency */ + BT_AUDIO_CODEC_CAP_FREQ_44KHZ = BIT(6), + + /** 48 Khz sampling frequency */ + BT_AUDIO_CODEC_CAP_FREQ_48KHZ = BIT(7), + + /** 88.2 Khz sampling frequency */ + BT_AUDIO_CODEC_CAP_FREQ_88KHZ = BIT(8), + + /** 96 Khz sampling frequency */ + BT_AUDIO_CODEC_CAP_FREQ_96KHZ = BIT(9), + + /** 176.4 Khz sampling frequency */ + BT_AUDIO_CODEC_CAP_FREQ_176KHZ = BIT(10), + + /** 192 Khz sampling frequency */ + BT_AUDIO_CODEC_CAP_FREQ_192KHZ = BIT(11), + + /** 384 Khz sampling frequency */ + BT_AUDIO_CODEC_CAP_FREQ_384KHZ = BIT(12), + + /** Any frequency capability */ + BT_AUDIO_CODEC_CAP_FREQ_ANY = + (BT_AUDIO_CODEC_CAP_FREQ_8KHZ | BT_AUDIO_CODEC_CAP_FREQ_11KHZ | + BT_AUDIO_CODEC_CAP_FREQ_16KHZ | BT_AUDIO_CODEC_CAP_FREQ_22KHZ | + BT_AUDIO_CODEC_CAP_FREQ_24KHZ | BT_AUDIO_CODEC_CAP_FREQ_32KHZ | + BT_AUDIO_CODEC_CAP_FREQ_44KHZ | BT_AUDIO_CODEC_CAP_FREQ_48KHZ | + BT_AUDIO_CODEC_CAP_FREQ_88KHZ | BT_AUDIO_CODEC_CAP_FREQ_96KHZ | + BT_AUDIO_CODEC_CAP_FREQ_176KHZ | BT_AUDIO_CODEC_CAP_FREQ_192KHZ | + BT_AUDIO_CODEC_CAP_FREQ_384KHZ), +}; + +/** @brief Supported frame durations bitfield */ +enum bt_audio_codec_cap_frame_dur { + /** 7.5 msec frame duration capability */ + BT_AUDIO_CODEC_CAP_DURATION_7_5 = BIT(0), + + /** 10 msec frame duration capability */ + BT_AUDIO_CODEC_CAP_DURATION_10 = BIT(1), + + /** Any frame duration capability */ + BT_AUDIO_CODEC_CAP_DURATION_ANY = + (BT_AUDIO_CODEC_CAP_DURATION_7_5 | BT_AUDIO_CODEC_CAP_DURATION_10), + + /** + * @brief 7.5 msec preferred frame duration capability. + * + * This shall only be set if @ref BT_AUDIO_CODEC_CAP_DURATION_7_5 is also set, and if @ref + * BT_AUDIO_CODEC_CAP_DURATION_PREFER_10 is not set. + */ + BT_AUDIO_CODEC_CAP_DURATION_PREFER_7_5 = BIT(4), + + /** + * @brief 10 msec preferred frame duration capability + * + * This shall only be set if @ref BT_AUDIO_CODEC_CAP_DURATION_10 is also set, and if @ref + * BT_AUDIO_CODEC_CAP_DURATION_PREFER_7_5 is not set. + */ + BT_AUDIO_CODEC_CAP_DURATION_PREFER_10 = BIT(5), +}; + +/** Supported audio capabilities channel count bitfield */ +enum bt_audio_codec_cap_chan_count { + /** Supporting 1 channel */ + BT_AUDIO_CODEC_CAP_CHAN_COUNT_1 = BIT(0), + + /** Supporting 2 channel */ + BT_AUDIO_CODEC_CAP_CHAN_COUNT_2 = BIT(1), + + /** Supporting 3 channel */ + BT_AUDIO_CODEC_CAP_CHAN_COUNT_3 = BIT(2), + + /** Supporting 4 channel */ + BT_AUDIO_CODEC_CAP_CHAN_COUNT_4 = BIT(3), + + /** Supporting 5 channel */ + BT_AUDIO_CODEC_CAP_CHAN_COUNT_5 = BIT(4), + + /** Supporting 6 channel */ + BT_AUDIO_CODEC_CAP_CHAN_COUNT_6 = BIT(5), + + /** Supporting 7 channel */ + BT_AUDIO_CODEC_CAP_CHAN_COUNT_7 = BIT(6), + + /** Supporting 8 channel */ + BT_AUDIO_CODEC_CAP_CHAN_COUNT_8 = BIT(7), + + /** Supporting all channels */ + BT_AUDIO_CODEC_CAP_CHAN_COUNT_ANY = + (BT_AUDIO_CODEC_CAP_CHAN_COUNT_1 | BT_AUDIO_CODEC_CAP_CHAN_COUNT_2 | + BT_AUDIO_CODEC_CAP_CHAN_COUNT_3 | BT_AUDIO_CODEC_CAP_CHAN_COUNT_4 | + BT_AUDIO_CODEC_CAP_CHAN_COUNT_5 | BT_AUDIO_CODEC_CAP_CHAN_COUNT_6 | + BT_AUDIO_CODEC_CAP_CHAN_COUNT_7 | BT_AUDIO_CODEC_CAP_CHAN_COUNT_8), +}; + +/** Minimum supported channel counts */ +#define BT_AUDIO_CODEC_CAP_CHAN_COUNT_MIN 1 +/** Maximum supported channel counts */ +#define BT_AUDIO_CODEC_CAP_CHAN_COUNT_MAX 8 + +/** The minimum size of a Broadcast Name as defined by Bluetooth Assigned Numbers */ +#define BT_AUDIO_BROADCAST_NAME_LEN_MIN 4 +/** The maximum size of a Broadcast Name as defined by Bluetooth Assigned Numbers */ +#define BT_AUDIO_BROADCAST_NAME_LEN_MAX 128 + +/** + * @brief Codec configuration types + * + * Used to build and parse codec configurations as specified in the ASCS and BAP specifications. + * Source is assigned numbers for Generic Audio, bluetooth.com. + */ +enum bt_audio_codec_cfg_type { + /** Sampling frequency */ + BT_AUDIO_CODEC_CFG_FREQ = 0x01, + + /** Frame duration */ + BT_AUDIO_CODEC_CFG_DURATION = 0x02, + + /** Audio channel allocation */ + BT_AUDIO_CODEC_CFG_CHAN_ALLOC = 0x03, + + /** Octets per codec frame */ + BT_AUDIO_CODEC_CFG_FRAME_LEN = 0x04, + + /** Codec frame blocks per SDU */ + BT_AUDIO_CODEC_CFG_FRAME_BLKS_PER_SDU = 0x05, +}; + +/** Codec configuration sampling frequency */ +enum bt_audio_codec_cfg_freq { + /** 8 Khz codec sampling frequency */ + BT_AUDIO_CODEC_CFG_FREQ_8KHZ = 0x01, + + /** 11.025 Khz codec sampling frequency */ + BT_AUDIO_CODEC_CFG_FREQ_11KHZ = 0x02, + + /** 16 Khz codec sampling frequency */ + BT_AUDIO_CODEC_CFG_FREQ_16KHZ = 0x03, + + /** 22.05 Khz codec sampling frequency */ + BT_AUDIO_CODEC_CFG_FREQ_22KHZ = 0x04, + + /** 24 Khz codec sampling frequency */ + BT_AUDIO_CODEC_CFG_FREQ_24KHZ = 0x05, + + /** 32 Khz codec sampling frequency */ + BT_AUDIO_CODEC_CFG_FREQ_32KHZ = 0x06, + + /** 44.1 Khz codec sampling frequency */ + BT_AUDIO_CODEC_CFG_FREQ_44KHZ = 0x07, + + /** 48 Khz codec sampling frequency */ + BT_AUDIO_CODEC_CFG_FREQ_48KHZ = 0x08, + + /** 88.2 Khz codec sampling frequency */ + BT_AUDIO_CODEC_CFG_FREQ_88KHZ = 0x09, + + /** 96 Khz codec sampling frequency */ + BT_AUDIO_CODEC_CFG_FREQ_96KHZ = 0x0a, + + /** 176.4 Khz codec sampling frequency */ + BT_AUDIO_CODEC_CFG_FREQ_176KHZ = 0x0b, + + /** 192 Khz codec sampling frequency */ + BT_AUDIO_CODEC_CFG_FREQ_192KHZ = 0x0c, + + /** 384 Khz codec sampling frequency */ + BT_AUDIO_CODEC_CFG_FREQ_384KHZ = 0x0d, +}; + +/** Codec configuration frame duration */ +enum bt_audio_codec_cfg_frame_dur { + /** 7.5 msec Frame Duration configuration */ + BT_AUDIO_CODEC_CFG_DURATION_7_5 = 0x00, + + /** 10 msec Frame Duration configuration */ + BT_AUDIO_CODEC_CFG_DURATION_10 = 0x01, +}; + +/** + * @brief Audio Context Type for Generic Audio + * + * These values are defined by the Generic Audio Assigned Numbers, bluetooth.com + */ +enum bt_audio_context { + /** No context type */ + BT_AUDIO_CONTEXT_TYPE_NONE = 0, + /** + * Identifies audio where the use case context does not match any other defined value, + * or where the context is unknown or cannot be determined. + */ + BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED = BIT(0), + /** + * Conversation between humans, for example, in telephony or video calls, including + * traditional cellular as well as VoIP and Push-to-Talk + */ + BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL = BIT(1), + /** Media, for example, music playback, radio, podcast or movie soundtrack, or tv audio */ + BT_AUDIO_CONTEXT_TYPE_MEDIA = BIT(2), + /** + * Audio associated with video gaming, for example gaming media; gaming effects; music + * and in-game voice chat between participants; or a mix of all the above + */ + BT_AUDIO_CONTEXT_TYPE_GAME = BIT(3), + /** Instructional audio, for example, in navigation, announcements, or user guidance */ + BT_AUDIO_CONTEXT_TYPE_INSTRUCTIONAL = BIT(4), + /** Man-machine communication, for example, with voice recognition or virtual assistants */ + BT_AUDIO_CONTEXT_TYPE_VOICE_ASSISTANTS = BIT(5), + /** + * Live audio, for example, from a microphone where audio is perceived both through a + * direct acoustic path and through an LE Audio Stream + */ + BT_AUDIO_CONTEXT_TYPE_LIVE = BIT(6), + /** + * Sound effects including keyboard and touch feedback; menu and user interface sounds; + * and other system sounds + */ + BT_AUDIO_CONTEXT_TYPE_SOUND_EFFECTS = BIT(7), + /** + * Notification and reminder sounds; attention-seeking audio, for example, + * in beeps signaling the arrival of a message + */ + BT_AUDIO_CONTEXT_TYPE_NOTIFICATIONS = BIT(8), + /** + * Alerts the user to an incoming call, for example, an incoming telephony or video call, + * including traditional cellular as well as VoIP and Push-to-Talk + */ + BT_AUDIO_CONTEXT_TYPE_RINGTONE = BIT(9), + /** + * Alarms and timers; immediate alerts, for example, in a critical battery alarm, + * timer expiry or alarm clock, toaster, cooker, kettle, microwave, etc. + */ + BT_AUDIO_CONTEXT_TYPE_ALERTS = BIT(10), + /** Emergency alarm Emergency sounds, for example, fire alarms or other urgent alerts */ + BT_AUDIO_CONTEXT_TYPE_EMERGENCY_ALARM = BIT(11), +}; + +/** + * Any known context. + */ +#define BT_AUDIO_CONTEXT_TYPE_ANY (BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED | \ + BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | \ + BT_AUDIO_CONTEXT_TYPE_MEDIA | \ + BT_AUDIO_CONTEXT_TYPE_GAME | \ + BT_AUDIO_CONTEXT_TYPE_INSTRUCTIONAL | \ + BT_AUDIO_CONTEXT_TYPE_VOICE_ASSISTANTS | \ + BT_AUDIO_CONTEXT_TYPE_LIVE | \ + BT_AUDIO_CONTEXT_TYPE_SOUND_EFFECTS | \ + BT_AUDIO_CONTEXT_TYPE_NOTIFICATIONS | \ + BT_AUDIO_CONTEXT_TYPE_RINGTONE | \ + BT_AUDIO_CONTEXT_TYPE_ALERTS | \ + BT_AUDIO_CONTEXT_TYPE_EMERGENCY_ALARM) + +/** + * @brief Parental rating defined by the Generic Audio assigned numbers (bluetooth.com). + * + * The numbering scheme is aligned with Annex F of EN 300 707 v1.2.1 which + * defined parental rating for viewing. + */ +enum bt_audio_parental_rating { + /** No rating */ + BT_AUDIO_PARENTAL_RATING_NO_RATING = 0x00, + /** For all ages */ + BT_AUDIO_PARENTAL_RATING_AGE_ANY = 0x01, + /** Recommended for listeners of age 5 and above */ + BT_AUDIO_PARENTAL_RATING_AGE_5_OR_ABOVE = 0x02, + /** Recommended for listeners of age 6 and above */ + BT_AUDIO_PARENTAL_RATING_AGE_6_OR_ABOVE = 0x03, + /** Recommended for listeners of age 7 and above */ + BT_AUDIO_PARENTAL_RATING_AGE_7_OR_ABOVE = 0x04, + /** Recommended for listeners of age 8 and above */ + BT_AUDIO_PARENTAL_RATING_AGE_8_OR_ABOVE = 0x05, + /** Recommended for listeners of age 9 and above */ + BT_AUDIO_PARENTAL_RATING_AGE_9_OR_ABOVE = 0x06, + /** Recommended for listeners of age 10 and above */ + BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE = 0x07, + /** Recommended for listeners of age 11 and above */ + BT_AUDIO_PARENTAL_RATING_AGE_11_OR_ABOVE = 0x08, + /** Recommended for listeners of age 12 and above */ + BT_AUDIO_PARENTAL_RATING_AGE_12_OR_ABOVE = 0x09, + /** Recommended for listeners of age 13 and above */ + BT_AUDIO_PARENTAL_RATING_AGE_13_OR_ABOVE = 0x0A, + /** Recommended for listeners of age 14 and above */ + BT_AUDIO_PARENTAL_RATING_AGE_14_OR_ABOVE = 0x0B, + /** Recommended for listeners of age 15 and above */ + BT_AUDIO_PARENTAL_RATING_AGE_15_OR_ABOVE = 0x0C, + /** Recommended for listeners of age 16 and above */ + BT_AUDIO_PARENTAL_RATING_AGE_16_OR_ABOVE = 0x0D, + /** Recommended for listeners of age 17 and above */ + BT_AUDIO_PARENTAL_RATING_AGE_17_OR_ABOVE = 0x0E, + /** Recommended for listeners of age 18 and above */ + BT_AUDIO_PARENTAL_RATING_AGE_18_OR_ABOVE = 0x0F +}; + +/** @brief Audio Active State defined by the Generic Audio assigned numbers (bluetooth.com). */ +enum bt_audio_active_state { + /** No audio data is being transmitted */ + BT_AUDIO_ACTIVE_STATE_DISABLED = 0x00, + /** Audio data is being transmitted */ + BT_AUDIO_ACTIVE_STATE_ENABLED = 0x01, +}; + +/** Assisted Listening Stream defined by the Generic Audio assigned numbers (bluetooth.com). */ +enum bt_audio_assisted_listening_stream { + /** Unspecified audio enhancement */ + BT_AUDIO_ASSISTED_LISTENING_STREAM_UNSPECIFIED = 0x00, +}; + +/** + * @brief Codec metadata type IDs + * + * Metadata types defined by the Generic Audio assigned numbers (bluetooth.com). + */ +enum bt_audio_metadata_type { + /** + * @brief Preferred audio context. + * + * Bitfield of preferred audio contexts. + * + * If 0, the context type is not a preferred use case for this codec + * configuration. + * + * See the BT_AUDIO_CONTEXT_* for valid values. + */ + BT_AUDIO_METADATA_TYPE_PREF_CONTEXT = 0x01, + + /** + * @brief Streaming audio context. + * + * Bitfield of streaming audio contexts. + * + * If 0, the context type is not a preferred use case for this codec + * configuration. + * + * See the BT_AUDIO_CONTEXT_* for valid values. + */ + BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT = 0x02, + + /** UTF-8 encoded title or summary of stream content */ + BT_AUDIO_METADATA_TYPE_PROGRAM_INFO = 0x03, + + /** + * @brief Language + * + * 3 octet lower case language code defined by ISO 639-3 + * Possible values can be found at https://iso639-3.sil.org/code_tables/639/data + */ + BT_AUDIO_METADATA_TYPE_LANG = 0x04, + + /** Array of 8-bit CCID values */ + BT_AUDIO_METADATA_TYPE_CCID_LIST = 0x05, + + /** + * @brief Parental rating + * + * See @ref bt_audio_parental_rating for valid values. + */ + BT_AUDIO_METADATA_TYPE_PARENTAL_RATING = 0x06, + + /** UTF-8 encoded URI for additional Program information */ + BT_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI = 0x07, + + /** + * @brief Audio active state + * + * See @ref bt_audio_active_state for valid values. + */ + BT_AUDIO_METADATA_TYPE_AUDIO_STATE = 0x08, + + /** Broadcast Audio Immediate Rendering flag */ + BT_AUDIO_METADATA_TYPE_BROADCAST_IMMEDIATE = 0x09, + + /** + * @brief Assisted listening stream + * + * See @ref bt_audio_assisted_listening_stream for valid values. + */ + BT_AUDIO_METADATA_TYPE_ASSISTED_LISTENING_STREAM = 0x0A, + + /** UTF-8 encoded Broadcast name */ + BT_AUDIO_METADATA_TYPE_BROADCAST_NAME = 0x0B, + + /** Extended metadata */ + BT_AUDIO_METADATA_TYPE_EXTENDED = 0xFE, + + /** Vendor specific metadata */ + BT_AUDIO_METADATA_TYPE_VENDOR = 0xFF, +}; + +/** + * @brief Location values for BT Audio. + * + * These values are defined by the Generic Audio Assigned Numbers, bluetooth.com + */ +enum bt_audio_location { + /** Mono Audio (no specified Audio Location) */ + BT_AUDIO_LOCATION_MONO_AUDIO = 0, + /** Front Left */ + BT_AUDIO_LOCATION_FRONT_LEFT = BIT(0), + /** Front Right */ + BT_AUDIO_LOCATION_FRONT_RIGHT = BIT(1), + /** Front Center */ + BT_AUDIO_LOCATION_FRONT_CENTER = BIT(2), + /** Low Frequency Effects 1 */ + BT_AUDIO_LOCATION_LOW_FREQ_EFFECTS_1 = BIT(3), + /** Back Left */ + BT_AUDIO_LOCATION_BACK_LEFT = BIT(4), + /** Back Right */ + BT_AUDIO_LOCATION_BACK_RIGHT = BIT(5), + /** Front Left of Center */ + BT_AUDIO_LOCATION_FRONT_LEFT_OF_CENTER = BIT(6), + /** Front Right of Center */ + BT_AUDIO_LOCATION_FRONT_RIGHT_OF_CENTER = BIT(7), + /** Back Center */ + BT_AUDIO_LOCATION_BACK_CENTER = BIT(8), + /** Low Frequency Effects 2 */ + BT_AUDIO_LOCATION_LOW_FREQ_EFFECTS_2 = BIT(9), + /** Side Left */ + BT_AUDIO_LOCATION_SIDE_LEFT = BIT(10), + /** Side Right */ + BT_AUDIO_LOCATION_SIDE_RIGHT = BIT(11), + /** Top Front Left */ + BT_AUDIO_LOCATION_TOP_FRONT_LEFT = BIT(12), + /** Top Front Right */ + BT_AUDIO_LOCATION_TOP_FRONT_RIGHT = BIT(13), + /** Top Front Center */ + BT_AUDIO_LOCATION_TOP_FRONT_CENTER = BIT(14), + /** Top Center */ + BT_AUDIO_LOCATION_TOP_CENTER = BIT(15), + /** Top Back Left */ + BT_AUDIO_LOCATION_TOP_BACK_LEFT = BIT(16), + /** Top Back Right */ + BT_AUDIO_LOCATION_TOP_BACK_RIGHT = BIT(17), + /** Top Side Left */ + BT_AUDIO_LOCATION_TOP_SIDE_LEFT = BIT(18), + /** Top Side Right */ + BT_AUDIO_LOCATION_TOP_SIDE_RIGHT = BIT(19), + /** Top Back Center */ + BT_AUDIO_LOCATION_TOP_BACK_CENTER = BIT(20), + /** Bottom Front Center */ + BT_AUDIO_LOCATION_BOTTOM_FRONT_CENTER = BIT(21), + /** Bottom Front Left */ + BT_AUDIO_LOCATION_BOTTOM_FRONT_LEFT = BIT(22), + /** Bottom Front Right */ + BT_AUDIO_LOCATION_BOTTOM_FRONT_RIGHT = BIT(23), + /** Front Left Wide */ + BT_AUDIO_LOCATION_FRONT_LEFT_WIDE = BIT(24), + /** Front Right Wide */ + BT_AUDIO_LOCATION_FRONT_RIGHT_WIDE = BIT(25), + /** Left Surround */ + BT_AUDIO_LOCATION_LEFT_SURROUND = BIT(26), + /** Right Surround */ + BT_AUDIO_LOCATION_RIGHT_SURROUND = BIT(27), +}; + +/** + * Any known location. + */ +#define BT_AUDIO_LOCATION_ANY (BT_AUDIO_LOCATION_FRONT_LEFT | \ + BT_AUDIO_LOCATION_FRONT_RIGHT | \ + BT_AUDIO_LOCATION_FRONT_CENTER | \ + BT_AUDIO_LOCATION_LOW_FREQ_EFFECTS_1 | \ + BT_AUDIO_LOCATION_BACK_LEFT | \ + BT_AUDIO_LOCATION_BACK_RIGHT | \ + BT_AUDIO_LOCATION_FRONT_LEFT_OF_CENTER | \ + BT_AUDIO_LOCATION_FRONT_RIGHT_OF_CENTER | \ + BT_AUDIO_LOCATION_BACK_CENTER | \ + BT_AUDIO_LOCATION_LOW_FREQ_EFFECTS_2 | \ + BT_AUDIO_LOCATION_SIDE_LEFT | \ + BT_AUDIO_LOCATION_SIDE_RIGHT | \ + BT_AUDIO_LOCATION_TOP_FRONT_LEFT | \ + BT_AUDIO_LOCATION_TOP_FRONT_RIGHT | \ + BT_AUDIO_LOCATION_TOP_FRONT_CENTER | \ + BT_AUDIO_LOCATION_TOP_CENTER | \ + BT_AUDIO_LOCATION_TOP_BACK_LEFT | \ + BT_AUDIO_LOCATION_TOP_BACK_RIGHT | \ + BT_AUDIO_LOCATION_TOP_SIDE_LEFT | \ + BT_AUDIO_LOCATION_TOP_SIDE_RIGHT | \ + BT_AUDIO_LOCATION_TOP_BACK_CENTER | \ + BT_AUDIO_LOCATION_BOTTOM_FRONT_CENTER | \ + BT_AUDIO_LOCATION_BOTTOM_FRONT_LEFT | \ + BT_AUDIO_LOCATION_BOTTOM_FRONT_RIGHT | \ + BT_AUDIO_LOCATION_FRONT_LEFT_WIDE | \ + BT_AUDIO_LOCATION_FRONT_RIGHT_WIDE | \ + BT_AUDIO_LOCATION_LEFT_SURROUND | \ + BT_AUDIO_LOCATION_RIGHT_SURROUND) + +/** @} */ /* end of bt_assigned_numbers_audio */ + +/** + * @name Company Identifiers (see Bluetooth Assigned Numbers) + * @{ + */ + +#define BT_COMP_ID_LF 0x05f1 /**< The Linux Foundation */ + +/** @} */ /* end of @name Company Identifiers */ + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_ASSIGNED_NUMBERS_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/att.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/att.h new file mode 100644 index 0000000000..5f0443c78c --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/att.h @@ -0,0 +1,136 @@ +/** @file + * @brief Attribute Protocol handling. + */ + +/* + * SPDX-FileCopyrightText: 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_ATT_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_ATT_H_ + +/** + * @brief Attribute Protocol (ATT) + * @defgroup bt_att Attribute Protocol (ATT) + * @ingroup bluetooth + * @{ + */ + +#include +#include + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Error codes for Error response PDU + * + * Defined by The Bluetooth Core Specification, Version 5.4, Vol 3, Part F, Section 3.4.1.1 + */ +/** The ATT operation was successful */ +#define BT_ATT_ERR_SUCCESS 0x00 +/** The attribute handle given was not valid on the server */ +#define BT_ATT_ERR_INVALID_HANDLE 0x01 +/** The attribute cannot be read */ +#define BT_ATT_ERR_READ_NOT_PERMITTED 0x02 +/** The attribute cannot be written */ +#define BT_ATT_ERR_WRITE_NOT_PERMITTED 0x03 +/** The attribute PDU was invalid */ +#define BT_ATT_ERR_INVALID_PDU 0x04 +/** The attribute requires authentication before it can be read or written */ +#define BT_ATT_ERR_AUTHENTICATION 0x05 +/** The ATT Server does not support the request received from the client */ +#define BT_ATT_ERR_NOT_SUPPORTED 0x06 +/** Offset specified was past the end of the attribute */ +#define BT_ATT_ERR_INVALID_OFFSET 0x07 +/** The attribute requires authorization before it can be read or written */ +#define BT_ATT_ERR_AUTHORIZATION 0x08 +/** Too many prepare writes have been queued */ +#define BT_ATT_ERR_PREPARE_QUEUE_FULL 0x09 +/** No attribute found within the given attribute handle range */ +#define BT_ATT_ERR_ATTRIBUTE_NOT_FOUND 0x0a +/** The attribute cannot be read using the ATT_READ_BLOB_REQ PDU */ +#define BT_ATT_ERR_ATTRIBUTE_NOT_LONG 0x0b +/** The Encryption Key Size used for encrypting this link is too short */ +#define BT_ATT_ERR_ENCRYPTION_KEY_SIZE 0x0c +/** The attribute value length is invalid for the operation */ +#define BT_ATT_ERR_INVALID_ATTRIBUTE_LEN 0x0d +/** + * @brief The attribute request that was requested has encountered an error that was unlikely + * + * The attribute request could therefore not be completed as requested + */ +#define BT_ATT_ERR_UNLIKELY 0x0e +/** The attribute requires encryption before it can be read or written */ +#define BT_ATT_ERR_INSUFFICIENT_ENCRYPTION 0x0f +/** + * @brief The attribute type is not a supported grouping attribute + * + * The attribute type is not a supported grouping attribute as defined by a higher layer + * specification. + */ +#define BT_ATT_ERR_UNSUPPORTED_GROUP_TYPE 0x10 +/** Insufficient Resources to complete the request */ +#define BT_ATT_ERR_INSUFFICIENT_RESOURCES 0x11 +/** The server requests the client to rediscover the database */ +#define BT_ATT_ERR_DB_OUT_OF_SYNC 0x12 +/** The attribute parameter value was not allowed */ +#define BT_ATT_ERR_VALUE_NOT_ALLOWED 0x13 + +/* Common Profile Error Codes + * + * Defined by the Supplement to the Bluetooth Core Specification (CSS), v11, Part B, Section 1.2. + */ +/** Write Request Rejected */ +#define BT_ATT_ERR_WRITE_REQ_REJECTED 0xfc +/** Client Characteristic Configuration Descriptor Improperly Configured */ +#define BT_ATT_ERR_CCC_IMPROPER_CONF 0xfd +/** Procedure Already in Progress */ +#define BT_ATT_ERR_PROCEDURE_IN_PROGRESS 0xfe +/** Out of Range */ +#define BT_ATT_ERR_OUT_OF_RANGE 0xff + +/* Version 5.2, Vol 3, Part F, 3.2.9 defines maximum attribute length to 512 */ +#define BT_ATT_MAX_ATTRIBUTE_LEN 512 + +/* Handle 0x0000 is reserved for future use */ +#define BT_ATT_FIRST_ATTRIBUTE_HANDLE 0x0001 +/* 0xffff is defined as the maximum, and thus last, valid attribute handle */ +#define BT_ATT_LAST_ATTRIBUTE_HANDLE 0xffff + +/** @brief Get number of EATT channels connected. + * + * @param conn The connection to get the number of EATT channels for. + * + * @return The number of EATT channels connected. + * Returns 0 if @p conn is NULL or not connected. + */ +size_t bt_eatt_count(struct bt_conn *conn); + +/** @brief ATT channel option bit field values. + * @note @ref BT_ATT_CHAN_OPT_UNENHANCED_ONLY and @ref BT_ATT_CHAN_OPT_ENHANCED_ONLY are mutually + * exclusive and both bits may not be set. + */ +enum bt_att_chan_opt { + /** Both Enhanced and Unenhanced channels can be used */ + BT_ATT_CHAN_OPT_NONE = 0x0, + /** Only Unenhanced channels will be used */ + BT_ATT_CHAN_OPT_UNENHANCED_ONLY = BIT(0), + /** Only Enhanced channels will be used */ + BT_ATT_CHAN_OPT_ENHANCED_ONLY = BIT(1), +}; + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_ATT_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/aics.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/aics.h new file mode 100644 index 0000000000..bb3390534b --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/aics.h @@ -0,0 +1,553 @@ +/** + * @file + * @brief Bluetooth Audio Input Control Service APIs. + */ + +/* + * SPDX-FileCopyrightText: 2020-2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_SERVICES_AICS_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_SERVICES_AICS_H_ + +/** + * @brief Audio Input Control Service (AICS) + * + * @defgroup bt_aics Audio Input Control Service (AICS) + * + * @since 2.6 + * @version 0.8.0 + * + * @ingroup bluetooth + * @{ + * + * The Audio Input Control Service is a secondary service, and as such should not be used on its + * own, but rather in the context of another (primary) service. + * + * This API implements both the server and client functionality. + * Note that the API abstracts away the change counter in the audio input control state and will + * automatically handle any changes to that. If out of date, the client implementation will + * autonomously read the change counter value when executing a write request. + * + */ +#include +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Audio Input Control Service mute states + * @{ + */ +/** The mute state is unmuted */ +#define BT_AICS_STATE_UNMUTED 0x00 +/** The mute state is muted */ +#define BT_AICS_STATE_MUTED 0x01 +/** The mute state is disabled */ +#define BT_AICS_STATE_MUTE_DISABLED 0x02 +/** @} */ + +/** + * @name Audio Input Control Service input modes + * @{ + */ +/** + * @brief The gain mode is manual only and cannot be changed to automatic. + * + * The gain can be controlled by the client. + */ +#define BT_AICS_MODE_MANUAL_ONLY 0x00 +/** + * @brief The gain mode is automatic only and cannot be changed to manual. + * + * The gain cannot be controlled by the client. + */ +#define BT_AICS_MODE_AUTO_ONLY 0x01 +/** + * @brief The gain mode is manual. + * + * The gain can be controlled by the client. + */ +#define BT_AICS_MODE_MANUAL 0x02 +/** + * @brief The gain mode is automatic. + * + * The gain cannot be controlled by the client. + */ +#define BT_AICS_MODE_AUTO 0x03 +/** @} */ + +/** + * @name Audio Input Control Service input types + * @{ + */ +/** The input is unspecified */ +#define BT_AICS_INPUT_TYPE_UNSPECIFIED 0x00 +/** The input is a Bluetooth Audio Stream */ +#define BT_AICS_INPUT_TYPE_BLUETOOTH 0x01 +/** The input is a microphone */ +#define BT_AICS_INPUT_TYPE_MICROPHONE 0x02 +/** The input is analog */ +#define BT_AICS_INPUT_TYPE_ANALOG 0x03 +/** The input is digital */ +#define BT_AICS_INPUT_TYPE_DIGITAL 0x04 +/** The input is a radio (AM/FM/XM/etc.) */ +#define BT_AICS_INPUT_TYPE_RADIO 0x05 +/** The input is a Streaming Audio Source */ +#define BT_AICS_INPUT_TYPE_STREAMING 0x06 +/** The input is transparent / pass-through */ +#define BT_AICS_INPUT_TYPE_AMBIENT 0x07 +/** @} */ + +/** + * @name Audio Input Control Service Error codes + * @{ + */ +/** + * The Change_Counter operand value does not match the Change_Counter field value of the + * Audio Input State characteristic. + */ +#define BT_AICS_ERR_INVALID_COUNTER 0x80 +/** An invalid opcode has been used in a control point procedure */ +#define BT_AICS_ERR_OP_NOT_SUPPORTED 0x81 +/** Mute/unmute commands are disabled.(see @ref BT_AICS_STATE_MUTE_DISABLED) */ +#define BT_AICS_ERR_MUTE_DISABLED 0x82 +/** An operand value used in a control point procedure is outside the permissible range */ +#define BT_AICS_ERR_OUT_OF_RANGE 0x83 +/** A requested gain mode change is not allowed */ +#define BT_AICS_ERR_GAIN_MODE_NOT_ALLOWED 0x84 +/** @} */ + +/** @brief Opaque Audio Input Control Service instance. */ +struct bt_aics; + +/** @brief Structure for initializing a Audio Input Control Service instance. */ +struct bt_aics_register_param { + /** Initial audio input gain (-128 to 127) */ + int8_t gain; + + /** Initial audio input mute state */ + uint8_t mute; + + /** Initial audio input mode */ + uint8_t gain_mode; + + /** Initial audio input gain units (N * 0.1 dB) */ + uint8_t units; + + /** Initial audio input minimum gain */ + int8_t min_gain; + + /** Initial audio input maximum gain */ + int8_t max_gain; + + /** Initial audio input type */ + uint8_t type; + + /** Initial audio input status (active/inactive) */ + bool status; + + /** Boolean to set whether the description is writable by clients */ + bool desc_writable; + + /** Initial audio input description */ + char *description; + + /** Pointer to the callback structure. */ + struct bt_aics_cb *cb; +}; + +/** @brief Structure for discovering a Audio Input Control Service instance. */ +struct bt_aics_discover_param { + /** + * @brief The start handle of the discovering. + * + * Typically the @p start_handle of a @ref bt_gatt_include. + */ + uint16_t start_handle; + /** + * @brief The end handle of the discovering. + * + * Typically the @p end_handle of a @ref bt_gatt_include. + */ + uint16_t end_handle; +}; + +/** + * @brief Get a free instance of Audio Input Control Service from the pool. + * + * @return Audio Input Control Service instance in case of success or NULL in case of error. + */ +struct bt_aics *bt_aics_free_instance_get_safe(void); + +/** + * @brief Get the service declaration attribute. + * + * The first service attribute returned can be included in any other GATT service. + * + * @param aics Audio Input Control Service instance. + * + * @return Pointer to the attributes of the service. + */ +void *bt_aics_svc_decl_get_safe(struct bt_aics *aics); + +/** + * @brief Get the connection pointer of a client instance + * + * Get the Bluetooth connection pointer of a Audio Input Control Service + * client instance. + * + * @param aics Audio Input Control Service client instance pointer. + * @param conn Connection pointer. + * + * @return 0 if success, errno on failure. + */ +int bt_aics_client_conn_get(const struct bt_aics *aics, struct bt_conn **conn); + +/** + * @brief Initialize the Audio Input Control Service instance. + * + * @param aics Audio Input Control Service instance. + * @param param Audio Input Control Service register parameters. + * + * @return 0 if success, errno on failure. + */ +int bt_aics_register_safe(struct bt_aics *aics, struct bt_aics_register_param *param); + +/** + * @brief Callback function for writes. + * + * @param inst The instance pointer. + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + */ +typedef void (*bt_aics_write_cb)(struct bt_aics *inst, int err); + +/** + * @brief Callback function for the input state. + * + * Called when the value is read, + * or if the value is changed by either the server or client. + * + * @param inst The instance pointer. + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * For notifications, this will always be 0. + * @param gain The gain setting value. + * @param mute The mute value. + * @param mode The mode value. + */ +typedef void (*bt_aics_state_cb)(struct bt_aics *inst, int err, int8_t gain, + uint8_t mute, uint8_t mode); + +/** + * @brief Callback function for the gain settings. + * + * Called when the value is read, + * or if the value is changed by either the server or client. + * + * @param inst The instance pointer. + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * For notifications, this will always be 0. + * @param units The value that reflect the size of a single increment or decrement of the + * Gain Setting value in 0.1 decibel units. + * @param minimum The minimum gain allowed for the gain setting. + * @param maximum The maximum gain allowed for the gain setting. + */ +typedef void (*bt_aics_gain_setting_cb)(struct bt_aics *inst, int err, + uint8_t units, int8_t minimum, + int8_t maximum); + +/** + * @brief Callback function for the input type. + * + * Called when the value is read, or if the value is changed by either the server or client. + * + * @param inst The instance pointer. + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * For notifications, this will always be 0. + * @param type The input type. + */ +typedef void (*bt_aics_type_cb)(struct bt_aics *inst, int err, uint8_t type); + +/** + * @brief Callback function for the input status. + * + * Called when the value is read, or if the value is changed by either the server or client. + * + * @param inst The instance pointer. + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * For notifications, this will always be 0. + * @param active Whether the instance is active or inactive. + */ +typedef void (*bt_aics_status_cb)(struct bt_aics *inst, int err, bool active); + +/** + * @brief Callback function for the description. + * + * Called when the value is read, or if the value is changed by either the server or client. + * + * @param inst The instance pointer. + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * For notifications, this will always be 0. + * @param description The description as an UTF-8 encoded string (may have been clipped). + */ +typedef void (*bt_aics_description_cb)(struct bt_aics *inst, int err, + char *description); + +/** + * @brief Callback function for bt_aics_discover. + * + * This callback will usually be overwritten by the primary service that + * includes the Audio Input Control Service client. + * + * @param inst The instance pointer. + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * For notifications, this will always be 0. + */ +typedef void (*bt_aics_discover_cb)(struct bt_aics *inst, int err); + +/** + * @brief Struct to hold callbacks for the Audio Input Control Service. + * + * Used by both clients and servers + */ +struct bt_aics_cb { + /** The audio input state has changed */ + bt_aics_state_cb state; + /** The gain setting has changed */ + bt_aics_gain_setting_cb gain_setting; + /** The audio input type has changed */ + bt_aics_type_cb type; + /** The audio input status has changed */ + bt_aics_status_cb status; + /** The audio input description has changed */ + bt_aics_description_cb description; + + /** The discovery has completed */ + bt_aics_discover_cb discover; + /** The set gain operation has completed */ + bt_aics_write_cb set_gain; + /** The unmute operation has completed */ + bt_aics_write_cb unmute; + /** The mut operation has completed */ + bt_aics_write_cb mute; + /** The set manual mode operation has completed */ + bt_aics_write_cb set_manual_mode; + /** The set automatic mode has completed */ + bt_aics_write_cb set_auto_mode; +}; + +/** + * @brief Discover a Audio Input Control Service. + * + * Attempts to discover a Audio Input Control Service on a server given the + * @p param. + * + * @param conn Connection to the peer with the Audio Input Control Service. + * @param inst The instance pointer. + * @param param Pointer to the parameters. + * + * @return 0 on success, errno on fail. + */ +int bt_aics_discover(struct bt_conn *conn, struct bt_aics *inst, + const struct bt_aics_discover_param *param); +int bt_aics_discover_safe(struct bt_conn *conn, struct bt_aics *inst, + const struct bt_aics_discover_param *param); + +/** + * @brief Deactivates a Audio Input Control Service instance. + * + * Audio Input Control Services are activated by default, but this will allow + * the server to deactivate an Audio Input Control Service. + * + * @param inst The instance pointer. + * + * @return 0 if success, errno on failure. + */ +int bt_aics_deactivate_safe(struct bt_aics *inst); + +/** + * @brief Activates a Audio Input Control Service instance. + * + * Audio Input Control Services are activated by default, but this will allow + * the server reactivate a Audio Input Control Service instance after it has + * been deactivated with @ref bt_aics_deactivate. + * + * @param inst The instance pointer. + * + * @return 0 if success, errno on failure. + */ +int bt_aics_activate_safe(struct bt_aics *inst); + +/** + * @brief Read the Audio Input Control Service input state. + * + * @param inst The instance pointer. + * + * @return 0 on success, GATT error value on fail. + */ +int bt_aics_state_get_safe(struct bt_aics *inst); + +/** + * @brief Read the Audio Input Control Service gain settings. + * + * @param inst The instance pointer. + * + * @return 0 on success, GATT error value on fail. + */ +int bt_aics_gain_setting_get_safe(struct bt_aics *inst); + +/** + * @brief Read the Audio Input Control Service input type. + * + * @param inst The instance pointer. + * + * @return 0 on success, GATT error value on fail. + */ +int bt_aics_type_get_safe(struct bt_aics *inst); + +/** + * @brief Read the Audio Input Control Service input status. + * + * @param inst The instance pointer. + * + * @return 0 on success, GATT error value on fail. + */ +int bt_aics_status_get_safe(struct bt_aics *inst); + +/** + * @brief Disable mute in the Audio Input Control Service. + * + * Calling bt_aics_unmute() or bt_aics_mute() will enable + * mute again and set the mute state to either unmuted or muted. + * + * @param inst The instance pointer. + * + * @return 0 on success, errno value on fail. + */ +int bt_aics_disable_mute_safe(struct bt_aics *inst); + +/** + * @brief Unmute the Audio Input Control Service input. + * + * @param inst The instance pointer. + * + * @return 0 on success, GATT error value on fail. + */ +int bt_aics_unmute_safe(struct bt_aics *inst); + +/** + * @brief Mute the Audio Input Control Service input. + * + * @param inst The instance pointer. + * + * @return 0 on success, GATT error value on fail. + */ +int bt_aics_mute_safe(struct bt_aics *inst); + +/** + * @brief Set manual only gain mode in Audio Input Control Service. + * + * @param inst The instance pointer. + * + * @return 0 on success, errno value on fail. + */ +int bt_aics_gain_set_manual_only_safe(struct bt_aics *inst); + +/** + * @brief Set automatic only gain mode in Audio Input Control Service. + * + * Using this function and enabling automatic only gain disables + * setting the gain with bt_aics_gain_set + * + * @param inst The instance pointer. + * + * @return 0 on success, errno value on fail. + */ +int bt_aics_gain_set_auto_only_safe(struct bt_aics *inst); + +/** + * @brief Set input gain to manual. + * + * @param inst The instance pointer. + * + * @return 0 on success, GATT error value on fail. + */ +int bt_aics_manual_gain_set_safe(struct bt_aics *inst); + +/** + * @brief Set the input gain to automatic. + * + * @param inst The instance pointer. + * + * @return 0 on success, GATT error value on fail. + */ +int bt_aics_automatic_gain_set_safe(struct bt_aics *inst); + +/** + * @brief Set the input gain. + * + * @param inst The instance pointer. + * @param gain The gain to set (-128 to 127) in gain setting units + * (see @ref bt_aics_gain_setting_cb). + * + * @return 0 on success, GATT error value on fail. + */ +int bt_aics_gain_set_safe(struct bt_aics *inst, int8_t gain); + +/** + * @brief Read the Audio Input Control Service description. + * + * @param inst The instance pointer. + * + * @return 0 on success, GATT error value on fail. + */ +int bt_aics_description_get_safe(struct bt_aics *inst); + +/** + * @brief Set the Audio Input Control Service description. + * + * @param inst The instance pointer. + * @param description The description as an UTF-8 encoded string. + * + * @return 0 on success, GATT error value on fail. + */ +int bt_aics_description_set_safe(struct bt_aics *inst, const char *description); + +/** + * @brief Get a new Audio Input Control Service client instance. + * + * @return Pointer to the instance, or NULL if no free instances are left. + */ +struct bt_aics *bt_aics_client_free_instance_get_safe(void); + +/** + * @brief Registers the callbacks for the Audio Input Control Service client. + * + * @param inst The instance pointer. + * @param cb Pointer to the callback structure. + */ +void bt_aics_client_cb_register_safe(struct bt_aics *inst, struct bt_aics_cb *cb); + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_SERVICES_AICS_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/audio.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/audio.h new file mode 100644 index 0000000000..e09930c852 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/audio.h @@ -0,0 +1,1896 @@ +/** + * @file + * @brief Bluetooth Audio handling + */ + +/* + * SPDX-FileCopyrightText: 2020 Intel Corporation + * SPDX-FileCopyrightText: 2020-2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_AUDIO_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_AUDIO_H_ + +/** + * @brief Bluetooth Audio + * @defgroup bt_audio Bluetooth Audio + * @ingroup bluetooth + * @{ + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Size of the broadcast ID in octets */ +#define BT_AUDIO_BROADCAST_ID_SIZE 3 +/** Maximum broadcast ID value */ +#define BT_AUDIO_BROADCAST_ID_MAX 0xFFFFFFU +/** Indicates that the server have no preference for the presentation delay */ +#define BT_AUDIO_PD_PREF_NONE 0x000000U +/** Maximum presentation delay in microseconds */ +#define BT_AUDIO_PD_MAX 0xFFFFFFU +/** Indicates that the unicast server does not have a preference for any retransmission number */ +#define BT_AUDIO_RTN_PREF_NONE 0xFFU + +/** Size of the stream language value, e.g. "eng" */ +#define BT_AUDIO_LANG_SIZE 3 + +/** + * @brief Channel count support capability + * + * Macro accepts variable number of channel counts. + * The allowed channel counts are defined by specification and have to be in range from + * @ref BT_AUDIO_CODEC_CAP_CHAN_COUNT_MIN to @ref BT_AUDIO_CODEC_CAP_CHAN_COUNT_MAX inclusive. + * + * Example to support 1 and 3 channels: + * BT_AUDIO_CODEC_CAP_CHAN_COUNT_SUPPORT(1, 3) + */ +#define BT_AUDIO_CODEC_CAP_CHAN_COUNT_SUPPORT(...) \ + ((enum bt_audio_codec_cap_chan_count)((FOR_EACH(BIT, (|), __VA_ARGS__)) >> 1)) + +/** struct to hold minimum and maximum supported codec frame sizes */ +struct bt_audio_codec_octets_per_codec_frame { + /** Minimum number of octets supported per codec frame */ + uint16_t min; + /** Maximum number of octets supported per codec frame */ + uint16_t max; +}; + +/** + * @brief Helper to check whether metadata type is known by the stack. + * + * @note @p _type is evaluated thrice. + */ +#define BT_AUDIO_METADATA_TYPE_IS_KNOWN(_type) \ + (IN_RANGE((_type), BT_AUDIO_METADATA_TYPE_PREF_CONTEXT, \ + BT_AUDIO_METADATA_TYPE_BROADCAST_IMMEDIATE) || \ + (_type) == BT_AUDIO_METADATA_TYPE_EXTENDED || (_type) == BT_AUDIO_METADATA_TYPE_VENDOR) + +/** + * @name Unicast Announcement Type + * @{ + */ +/** Unicast Server is connectable and is requesting a connection. */ +#define BT_AUDIO_UNICAST_ANNOUNCEMENT_GENERAL 0x00 +/** Unicast Server is connectable but is not requesting a connection. */ +#define BT_AUDIO_UNICAST_ANNOUNCEMENT_TARGETED 0x01 +/** @} */ + +/** + * @brief Helper to declare elements of bt_audio_codec_cap arrays + * + * This macro is mainly for creating an array of struct bt_audio_codec_cap data arrays. + * + * @param _type Type of advertising data field + * @param _bytes Variable number of single-byte parameters + */ +#define BT_AUDIO_CODEC_DATA(_type, _bytes...) \ + (sizeof((uint8_t)_type) + sizeof((uint8_t[]){_bytes})), (_type), _bytes + +/** + * @brief Helper to declare @ref bt_audio_codec_cfg + * + * @param _id Codec ID + * @param _cid Company ID + * @param _vid Vendor ID + * @param _data Codec Specific Data in LVT format + * @param _meta Codec Specific Metadata in LVT format + */ +#define BT_AUDIO_CODEC_CFG(_id, _cid, _vid, _data, _meta) \ + ((struct bt_audio_codec_cfg){ \ + /* Use HCI data path as default, can be overwritten by application */ \ + .path_id = BT_ISO_DATA_PATH_HCI, \ + .ctlr_transcode = false, \ + COND_CODE_1(IS_ENABLED(CONFIG_BT_BAP_UNICAST), \ + (.target_latency = BT_AUDIO_CODEC_CFG_TARGET_LATENCY_BALANCED, \ + .target_phy = BT_AUDIO_CODEC_CFG_TARGET_PHY_2M,), \ + ()) \ + .id = _id, \ + .cid = _cid, \ + .vid = _vid, \ + .data_len = sizeof((uint8_t[])_data), \ + .data = _data, \ + .meta_len = sizeof((uint8_t[])_meta), \ + .meta = _meta, \ + }) + +/** + * @brief Helper to declare @ref bt_audio_codec_cap structure + * + * @param _id Codec ID + * @param _cid Company ID + * @param _vid Vendor ID + * @param _data Codec Specific Data in LVT format + * @param _meta Codec Specific Metadata in LVT format + */ +#define BT_AUDIO_CODEC_CAP(_id, _cid, _vid, _data, _meta) \ + ((struct bt_audio_codec_cap){ \ + /* Use HCI data path as default, can be overwritten by application */ \ + .path_id = BT_ISO_DATA_PATH_HCI, \ + .ctlr_transcode = false, \ + .id = (_id), \ + .cid = (_cid), \ + .vid = (_vid), \ + .data_len = sizeof((uint8_t[])_data), \ + .data = _data, \ + .meta_len = sizeof((uint8_t[])_meta), \ + .meta = _meta, \ + }) + +/** @brief Codec capability structure. */ +struct bt_audio_codec_cap { + /** Data path ID + * + * @ref BT_ISO_DATA_PATH_HCI for HCI path, or any other value for + * vendor specific ID. + */ + uint8_t path_id; + /** Whether or not the local controller should transcode + * + * This effectively sets the coding format for the ISO data path to @ref + * BT_HCI_CODING_FORMAT_TRANSPARENT if false, else uses the @ref bt_audio_codec_cfg.id. + */ + bool ctlr_transcode; + /** Codec ID */ + uint8_t id; + /** Codec Company ID */ + uint16_t cid; + /** Codec Company Vendor ID */ + uint16_t vid; + /** Codec Specific Capabilities Data count */ + size_t data_len; + /** Codec Specific Capabilities Data */ + uint8_t *data; + /** Codec Specific Capabilities Metadata count */ + size_t meta_len; + /** Codec Specific Capabilities Metadata */ + uint8_t *meta; +}; + +/** + * @brief Codec configuration target latency + * + * Set by the BAP Unicast Client to provide context for the BAP Unicast Server for the server to + * set its QoS preferences. + */ +enum bt_audio_codec_cfg_target_latency { + /** Target low latency */ + BT_AUDIO_CODEC_CFG_TARGET_LATENCY_LOW = 0x01, + + /** Target balanced latency */ + BT_AUDIO_CODEC_CFG_TARGET_LATENCY_BALANCED = 0x02, + + /** Target high latency */ + BT_AUDIO_CODEC_CFG_TARGET_LATENCY_HIGH = 0x03, +}; + +/** + * @brief Codec configuration target PHY + * + * The target PHY to achieve the target latency (@ref bt_audio_codec_cfg_target_latency). + */ +enum bt_audio_codec_cfg_target_phy { + /** LE 1M PHY */ + BT_AUDIO_CODEC_CFG_TARGET_PHY_1M = 0x01, + + /** LE 2M PHY */ + BT_AUDIO_CODEC_CFG_TARGET_PHY_2M = 0x02, + + /** LE Coded PHY */ + BT_AUDIO_CODEC_CFG_TARGET_PHY_CODED = 0x03, +}; + +/** @brief Codec specific configuration structure. */ +struct bt_audio_codec_cfg { + /** Data path ID + * + * @ref BT_ISO_DATA_PATH_HCI for HCI path, or any other value for + * vendor specific ID. + */ + uint8_t path_id; + /** Whether or not the local controller should transcode + * + * This effectively sets the coding format for the ISO data path to @ref + * BT_HCI_CODING_FORMAT_TRANSPARENT if false, else uses the @ref bt_audio_codec_cfg.id. + */ + bool ctlr_transcode; + /** Target latency + * + * Unused for broadcast streams. + */ + enum bt_audio_codec_cfg_target_latency target_latency; + /** Target PHY + * + * Unused for broadcast streams. + */ + enum bt_audio_codec_cfg_target_phy target_phy; + /** Codec ID */ + uint8_t id; + /** Codec Company ID */ + uint16_t cid; + /** Codec Company Vendor ID */ + uint16_t vid; + /** Codec Specific Capabilities Data count */ + size_t data_len; + /** Codec Specific Capabilities Data */ + uint8_t *data; + /** Codec Specific Capabilities Metadata count */ + size_t meta_len; + /** Codec Specific Capabilities Metadata */ + uint8_t *meta; +}; + +/** + * @brief Helper for parsing length-type-value data. + * + * @param ltv Length-type-value (LTV) encoded data. + * @param size Size of the @p ltv data. + * @param func Callback function which will be called for each element + * that's found in the data. The callback should return + * true to continue parsing, or false to stop parsing. + * @param user_data User data to be passed to the callback. + * + * @retval 0 All entries were parsed. + * @retval -EINVAL The data is incorrectly encoded + * @retval -ECANCELED Parsing was prematurely cancelled by the callback + */ +int bt_audio_data_parse(const uint8_t ltv[], size_t size, + bool (*func)(uint8_t type, const uint8_t *data, uint8_t data_len, void *user_data), + void *user_data); + +/** + * @brief Get the value of a specific data type in an length-type-value data array + * + * @param[in] ltv_data The array containing the length-type-value tuples + * @param[in] size The size of @p ltv_data + * @param[in] type The type to get the value for. May be any type, but typically either + * @ref bt_audio_codec_cap_type, @ref bt_audio_codec_cfg_type or + * @ref bt_audio_metadata_type. + * @param[out] data Pointer to the data-pointer to update when item is found. + * Any found data will be little endian. + * + * @retval length The length of found @p data (may be 0). + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + */ +int bt_audio_data_get_val(const uint8_t ltv_data[], size_t size, uint8_t type, + const uint8_t **data); + +/** + * @brief Function to get the number of channels from the channel allocation + * + * @param chan_allocation The channel allocation + * + * @return The number of channels + */ +uint8_t bt_audio_get_chan_count(enum bt_audio_location chan_allocation); + +/** @brief Audio direction from the perspective of the BAP Unicast Server / BAP Broadcast Sink */ +enum bt_audio_dir { + /** + * @brief Audio direction sink + * + * For a BAP Unicast Client or Broadcast Source this is considered outgoing audio (TX). + * For a BAP Unicast Server or Broadcast Sink this is considered incoming audio (RX). + */ + BT_AUDIO_DIR_SINK = 0x01, + /** + * @brief Audio direction source + * + * For a BAP Unicast Client or Broadcast Source this is considered incoming audio (RX). + * For a BAP Unicast Server or Broadcast Sink this is considered outgoing audio (TX). + */ + BT_AUDIO_DIR_SOURCE = 0x02, +}; + +/** + * @brief Audio codec Config APIs + * @defgroup bt_audio_codec_cfg Codec config parsing APIs + * + * Functions to parse codec config data when formatted as LTV wrapped into @ref bt_audio_codec_cfg. + * + * @{ + */ + +/** + * @brief Convert assigned numbers frequency to frequency value. + * + * @param freq The assigned numbers frequency to convert. + * + * @retval frequency The converted frequency value in Hz. + * @retval -EINVAL Arguments are invalid. + */ +int bt_audio_codec_cfg_freq_to_freq_hz(enum bt_audio_codec_cfg_freq freq); + +/** + * @brief Convert frequency value to assigned numbers frequency. + * + * @param freq_hz The frequency value to convert. + * + * @retval frequency The assigned numbers frequency (@ref bt_audio_codec_cfg_freq). + * @retval -EINVAL Arguments are invalid. + */ +int bt_audio_codec_cfg_freq_hz_to_freq(uint32_t freq_hz); + +/** + * @brief Extract the frequency from a codec configuration. + * + * @param codec_cfg The codec configuration to extract data from. + * + * @retval frequency A @ref bt_audio_codec_cfg_freq value + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + * @retval -EBADMSG The found value has invalid size or value + */ +int bt_audio_codec_cfg_get_freq(const struct bt_audio_codec_cfg *codec_cfg); + +/** + * @brief Set the frequency of a codec configuration. + * + * @param codec_cfg The codec configuration to set data for. + * @param freq The assigned numbers frequency to set. + * + * @retval data_len The @p codec_cfg.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cfg_set_freq(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_codec_cfg_freq freq); + +/** + * @brief Convert assigned numbers frame duration to duration in microseconds. + * + * @param frame_dur The assigned numbers frame duration to convert. + * + * @retval duration The converted frame duration value in microseconds. + * @retval -EINVAL Arguments are invalid. + */ +int bt_audio_codec_cfg_frame_dur_to_frame_dur_us(enum bt_audio_codec_cfg_frame_dur frame_dur); + +/** + * @brief Convert frame duration in microseconds to assigned numbers frame duration. + * + * @param frame_dur_us The frame duration in microseconds to convert. + * + * @retval duration The assigned numbers frame duration (@ref bt_audio_codec_cfg_frame_dur). + * @retval -EINVAL Arguments are invalid. + */ +int bt_audio_codec_cfg_frame_dur_us_to_frame_dur(uint32_t frame_dur_us); + +/** + * @brief Extract frame duration from BT codec config + * + * @param codec_cfg The codec configuration to extract data from. + * + * @retval frequency A @ref bt_audio_codec_cfg_frame_dur value + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + * @retval -EBADMSG The found value has invalid size or value + */ +int bt_audio_codec_cfg_get_frame_dur(const struct bt_audio_codec_cfg *codec_cfg); + +/** + * @brief Set the frame duration of a codec configuration. + * + * @param codec_cfg The codec configuration to set data for. + * @param frame_dur The assigned numbers frame duration to set. + * + * @retval data_len The @p codec_cfg.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cfg_set_frame_dur(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_codec_cfg_frame_dur frame_dur); + +/** + * @brief Extract channel allocation from BT codec config + * + * The value returned is a bit field representing one or more audio locations as + * specified by @ref bt_audio_location + * Shall match one or more of the bits set in BT_PAC_SNK_LOC/BT_PAC_SRC_LOC. + * + * Up to the configured @ref BT_AUDIO_CODEC_CAP_TYPE_CHAN_COUNT number of channels can be present. + * + * @param codec_cfg The codec configuration to extract data from. + * @param chan_allocation Pointer to the variable to store the extracted value in. + * @param fallback_to_default If true this function will provide the default value of + * @ref BT_AUDIO_LOCATION_MONO_AUDIO if the type is not found when @p codec_cfg.id is @ref + * BT_HCI_CODING_FORMAT_LC3. + * + * @retval 0 Value is found and stored in the pointer provided + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + * @retval -EBADMSG The found value has invalid size or value + */ +int bt_audio_codec_cfg_get_chan_allocation(const struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_location *chan_allocation, + bool fallback_to_default); + +/** + * @brief Set the channel allocation of a codec configuration. + * + * @param codec_cfg The codec configuration to set data for. + * @param chan_allocation The channel allocation to set. + * + * @retval data_len The @p codec_cfg.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cfg_set_chan_allocation(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_location chan_allocation); + +/** + * @brief Extract frame size in octets from BT codec config + * + * The overall SDU size will be octets_per_frame * blocks_per_sdu. + * + * The Bluetooth specifications are not clear about this value - it does not state that + * the codec shall use this SDU size only. A codec like LC3 supports variable bit-rate + * (per SDU) hence it might be allowed for an encoder to reduce the frame size below this + * value. + * Hence it is recommended to use the received SDU size and divide by + * blocks_per_sdu rather than relying on this octets_per_sdu value to be fixed. + * + * @param codec_cfg The codec configuration to extract data from. + * + * @retval frame_length Frame length in octets + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + * @retval -EBADMSG The found value has invalid size or value + */ +int bt_audio_codec_cfg_get_octets_per_frame(const struct bt_audio_codec_cfg *codec_cfg); + +/** + * @brief Set the octets per codec frame of a codec configuration. + * + * @param codec_cfg The codec configuration to set data for. + * @param octets_per_frame The octets per codec frame to set. + * + * @retval data_len The @p codec_cfg.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cfg_set_octets_per_frame(struct bt_audio_codec_cfg *codec_cfg, + uint16_t octets_per_frame); + +/** + * @brief Extract number of audio frame blocks in each SDU from BT codec config + * + * The overall SDU size will be octets_per_frame * frame_blocks_per_sdu * number-of-channels. + * + * If this value is not present a default value of 1 shall be used. + * + * A frame block is one or more frames that represents data for the same period of time but + * for different channels. If the stream have two audio channels and this value is two + * there will be four frames in the SDU. + * + * @param codec_cfg The codec configuration to extract data from. + * @param fallback_to_default If true this function will return the default value of 1 + * if the type is not found when @p codec_cfg.id is @ref BT_HCI_CODING_FORMAT_LC3. + * + * @retval frame_blocks_per_sdu The count of codec frame blocks in each SDU. + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + * @retval -EBADMSG The found value has invalid size or value + */ +int bt_audio_codec_cfg_get_frame_blocks_per_sdu(const struct bt_audio_codec_cfg *codec_cfg, + bool fallback_to_default); + +/** + * @brief Set the frame blocks per SDU of a codec configuration. + * + * @param codec_cfg The codec configuration to set data for. + * @param frame_blocks The frame blocks per SDU to set. + * + * @retval data_len The @p codec_cfg.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cfg_set_frame_blocks_per_sdu(struct bt_audio_codec_cfg *codec_cfg, + uint8_t frame_blocks); + +/** + * @brief Lookup a specific codec configuration value + * + * @param[in] codec_cfg The codec data to search in. + * @param[in] type The type id to look for + * @param[out] data Pointer to the data-pointer to update when item is found + * + * @retval len Length of found @p data (may be 0) + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + */ +int bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_codec_cfg_type type, const uint8_t **data); + +/** + * @brief Set or add a specific codec configuration value + * + * @param codec_cfg The codec data to set the value in. + * @param type The type id to set + * @param data Pointer to the data-pointer to set + * @param data_len Length of @p data + * + * @retval data_len The @p codec_cfg.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cfg_set_val(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_codec_cfg_type type, const uint8_t *data, + size_t data_len); + +/** + * @brief Unset a specific codec configuration value + * + * The type and the value will be removed from the codec configuration. + * + * @param codec_cfg The codec data to set the value in. + * @param type The type id to unset. + * + * @retval data_len The @p codec_cfg.data_len on success + * @retval -EINVAL Arguments are invalid + */ +int bt_audio_codec_cfg_unset_val(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_codec_cfg_type type); + +/** + * @brief Lookup a specific metadata value based on type + * + * + * @param[in] codec_cfg The codec data to search in. + * @param[in] type The type id to look for + * @param[out] data Pointer to the data-pointer to update when item is found + * + * @retval len Length of found @p data (may be 0) + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + */ +int bt_audio_codec_cfg_meta_get_val(const struct bt_audio_codec_cfg *codec_cfg, uint8_t type, + const uint8_t **data); + +/** + * @brief Set or add a specific codec configuration metadata value. + * + * @param codec_cfg The codec configuration to set the value in. + * @param type The type id to set. + * @param data Pointer to the data-pointer to set. + * @param data_len Length of @p data. + * + * @retval meta_len The @p codec_cfg.meta_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cfg_meta_set_val(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_metadata_type type, const uint8_t *data, + size_t data_len); + +/** + * @brief Unset a specific codec configuration metadata value + * + * The type and the value will be removed from the codec configuration metadata. + * + * @param codec_cfg The codec data to set the value in. + * @param type The type id to unset. + * + * @retval meta_len The of @p codec_cfg.meta_len success + * @retval -EINVAL Arguments are invalid + */ +int bt_audio_codec_cfg_meta_unset_val(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_metadata_type type); +/** + * @brief Extract preferred contexts + * + * See @ref BT_AUDIO_METADATA_TYPE_PREF_CONTEXT for more information about this value. + * + * @param codec_cfg The codec data to search in. + * @param fallback_to_default If true this function will provide the default value of + * @ref BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED if the type is not found when @p codec_cfg.id is + * @ref BT_HCI_CODING_FORMAT_LC3. + * + * @retval context The preferred context type if positive or 0 + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + * @retval -EBADMSG The found value has invalid size + */ +int bt_audio_codec_cfg_meta_get_pref_context(const struct bt_audio_codec_cfg *codec_cfg, + bool fallback_to_default); + +/** + * @brief Set the preferred context of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param ctx The preferred context to set. + * + * @retval data_len The @p codec_cfg.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cfg_meta_set_pref_context(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_context ctx); + +/** + * @brief Extract stream contexts + * + * See @ref BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT for more information about this value. + * + * @param codec_cfg The codec data to search in. + * + * @retval context The stream context type if positive or 0 + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + * @retval -EBADMSG The found value has invalid size + */ +int bt_audio_codec_cfg_meta_get_stream_context(const struct bt_audio_codec_cfg *codec_cfg); + +/** + * @brief Set the stream context of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param ctx The stream context to set. + * + * @retval data_len The @p codec_cfg.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cfg_meta_set_stream_context(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_context ctx); + +/** + * @brief Extract program info + * + * See @ref BT_AUDIO_METADATA_TYPE_PROGRAM_INFO for more information about this value. + * + * @param[in] codec_cfg The codec data to search in. + * @param[out] program_info Pointer to the UTF-8 formatted program info. + * + * @retval len The length of the @p program_info (may be 0) + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + */ +int bt_audio_codec_cfg_meta_get_program_info(const struct bt_audio_codec_cfg *codec_cfg, + const uint8_t **program_info); + +/** + * @brief Set the program info of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param program_info The program info to set. + * @param program_info_len The length of @p program_info. + * + * @retval data_len The @p codec_cfg.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cfg_meta_set_program_info(struct bt_audio_codec_cfg *codec_cfg, + const uint8_t *program_info, size_t program_info_len); + +/** + * @brief Extract language + * + * See @ref BT_AUDIO_METADATA_TYPE_LANG for more information about this value. + * + * @param[in] codec_cfg The codec data to search in. + * @param[out] lang Pointer to the language bytes (of length BT_AUDIO_LANG_SIZE) + * + * @retval 0 Success + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + * @retval -EBADMSG The found value has invalid size + */ +int bt_audio_codec_cfg_meta_get_lang(const struct bt_audio_codec_cfg *codec_cfg, + const uint8_t **lang); + +/** + * @brief Set the language of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param lang The 24-bit language to set. + * + * @retval data_len The @p codec_cfg.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cfg_meta_set_lang(struct bt_audio_codec_cfg *codec_cfg, + const uint8_t lang[BT_AUDIO_LANG_SIZE]); + +/** + * @brief Extract CCID list + * + * See @ref BT_AUDIO_METADATA_TYPE_CCID_LIST for more information about this value. + * + * @param[in] codec_cfg The codec data to search in. + * @param[out] ccid_list Pointer to the array containing 8-bit CCIDs. + * + * @retval len The length of the @p ccid_list (may be 0) + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + */ +int bt_audio_codec_cfg_meta_get_ccid_list(const struct bt_audio_codec_cfg *codec_cfg, + const uint8_t **ccid_list); + +/** + * @brief Set the CCID list of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param ccid_list The program info to set. + * @param ccid_list_len The length of @p ccid_list. + * + * @retval data_len The @p codec_cfg.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cfg_meta_set_ccid_list(struct bt_audio_codec_cfg *codec_cfg, + const uint8_t *ccid_list, size_t ccid_list_len); + +/** + * @brief Extract parental rating + * + * See @ref BT_AUDIO_METADATA_TYPE_PARENTAL_RATING for more information about this value. + * + * @param codec_cfg The codec data to search in. + * + * @retval parental_rating The parental rating if positive or 0 + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + * @retval -EBADMSG The found value has invalid size + */ +int bt_audio_codec_cfg_meta_get_parental_rating(const struct bt_audio_codec_cfg *codec_cfg); + +/** + * @brief Set the parental rating of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param parental_rating The parental rating to set. + * + * @retval data_len The @p codec_cfg.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cfg_meta_set_parental_rating(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_parental_rating parental_rating); + +/** + * @brief Extract program info URI + * + * See @ref BT_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI for more information about this value. + * + * @param[in] codec_cfg The codec data to search in. + * @param[out] program_info_uri Pointer to the UTF-8 formatted program info URI. + * + * @retval len The length of the @p program_info_uri (may be 0) + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + */ +int bt_audio_codec_cfg_meta_get_program_info_uri(const struct bt_audio_codec_cfg *codec_cfg, + const uint8_t **program_info_uri); + +/** + * @brief Set the program info URI of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param program_info_uri The program info URI to set. + * @param program_info_uri_len The length of @p program_info_uri. + * + * @retval data_len The @p codec_cfg.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cfg_meta_set_program_info_uri(struct bt_audio_codec_cfg *codec_cfg, + const uint8_t *program_info_uri, + size_t program_info_uri_len); + +/** + * @brief Extract audio active state + * + * See @ref BT_AUDIO_METADATA_TYPE_AUDIO_STATE for more information about this value. + * + * @param codec_cfg The codec data to search in. + * + * @retval context The preferred context type if positive or 0 + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + * @retval -EBADMSG The found value has invalid size + */ +int bt_audio_codec_cfg_meta_get_audio_active_state(const struct bt_audio_codec_cfg *codec_cfg); + +/** + * @brief Set the audio active state of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param state The audio active state to set. + * + * @retval data_len The @p codec_cfg.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cfg_meta_set_audio_active_state(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_active_state state); + +/** + * @brief Extract broadcast audio immediate rendering flag + * + * See @ref BT_AUDIO_METADATA_TYPE_BROADCAST_IMMEDIATE for more information about this value. + * + * @param codec_cfg The codec data to search in. + * + * @retval 0 The flag was found + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA The flag was not found + */ +int bt_audio_codec_cfg_meta_get_bcast_audio_immediate_rend_flag( + const struct bt_audio_codec_cfg *codec_cfg); + +/** + * @brief Set the broadcast audio immediate rendering flag of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * + * @retval data_len The @p codec_cfg.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cfg_meta_set_bcast_audio_immediate_rend_flag( + struct bt_audio_codec_cfg *codec_cfg); + +/** + * @brief Extract assisted listening stream + * + * See @ref BT_AUDIO_METADATA_TYPE_ASSISTED_LISTENING_STREAM for more information about this value. + * + * @param codec_cfg The codec data to search in. + * + * @retval value The assisted listening stream value if positive or 0 + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + * @retval -EBADMSG The found value has invalid size + */ +int bt_audio_codec_cfg_meta_get_assisted_listening_stream( + const struct bt_audio_codec_cfg *codec_cfg); + +/** + * @brief Set the assisted listening stream value of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param val The assisted listening stream value to set. + * + * @retval data_len The @p codec_cap.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cfg_meta_set_assisted_listening_stream( + struct bt_audio_codec_cfg *codec_cfg, enum bt_audio_assisted_listening_stream val); + +/** + * @brief Extract broadcast name + * + * See @ref BT_AUDIO_METADATA_TYPE_BROADCAST_NAME for more information about this value. + * + * @param[in] codec_cfg The codec data to search in. + * @param[out] broadcast_name Pointer to the UTF-8 formatted broadcast name. + * + * @retval length The length of the @p broadcast_name (may be 0) + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + */ +int bt_audio_codec_cfg_meta_get_broadcast_name(const struct bt_audio_codec_cfg *codec_cfg, + const uint8_t **broadcast_name); + +/** + * @brief Set the broadcast name of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param broadcast_name The broadcast name to set. + * @param broadcast_name_len The length of @p broadcast_name. + * + * @retval data_len The @p codec_cfg.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cfg_meta_set_broadcast_name(struct bt_audio_codec_cfg *codec_cfg, + const uint8_t *broadcast_name, + size_t broadcast_name_len); + +/** + * @brief Extract extended metadata + * + * See @ref BT_AUDIO_METADATA_TYPE_EXTENDED for more information about this value. + * + * @param[in] codec_cfg The codec data to search in. + * @param[out] extended_meta Pointer to the extended metadata. + * + * @retval len The length of the @p extended_meta (may be 0) + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + */ +int bt_audio_codec_cfg_meta_get_extended(const struct bt_audio_codec_cfg *codec_cfg, + const uint8_t **extended_meta); + +/** + * @brief Set the extended metadata of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param extended_meta The extended metadata to set. + * @param extended_meta_len The length of @p extended_meta. + * + * @retval data_len The @p codec_cfg.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cfg_meta_set_extended(struct bt_audio_codec_cfg *codec_cfg, + const uint8_t *extended_meta, size_t extended_meta_len); + +/** + * @brief Extract vendor specific metadata + * + * See @ref BT_AUDIO_METADATA_TYPE_VENDOR for more information about this value. + * + * @param[in] codec_cfg The codec data to search in. + * @param[out] vendor_meta Pointer to the vendor specific metadata. + * + * @retval len The length of the @p vendor_meta (may be 0) + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + */ +int bt_audio_codec_cfg_meta_get_vendor(const struct bt_audio_codec_cfg *codec_cfg, + const uint8_t **vendor_meta); + +/** + * @brief Set the vendor specific metadata of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param vendor_meta The vendor specific metadata to set. + * @param vendor_meta_len The length of @p vendor_meta. + * + * @retval data_len The @p codec_cfg.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cfg_meta_set_vendor(struct bt_audio_codec_cfg *codec_cfg, + const uint8_t *vendor_meta, size_t vendor_meta_len); +/** @} */ /* End of bt_audio_codec_cfg */ + +/** + * @brief Audio codec capabilities APIs + * @defgroup bt_audio_codec_cap Codec capability parsing APIs + * + * Functions to parse codec capability data when formatted as LTV wrapped into @ref + * bt_audio_codec_cap. + * + * @{ + */ + +/** + * @brief Lookup a specific value based on type + * + * @param[in] codec_cap The codec data to search in. + * @param[in] type The type id to look for + * @param[out] data Pointer to the data-pointer to update when item is found + * + * @retval len Length of found @p data (may be 0) + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + */ +int bt_audio_codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, + enum bt_audio_codec_cap_type type, const uint8_t **data); + +/** + * @brief Set or add a specific codec capability value + * + * @param codec_cap The codec data to set the value in. + * @param type The type id to set + * @param data Pointer to the data-pointer to set + * @param data_len Length of @p data + * + * @retval data_len The @p codec_cap.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cap_set_val(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_codec_cap_type type, const uint8_t *data, + size_t data_len); + +/** + * @brief Unset a specific codec capability value + * + * The type and the value will be removed from the codec capability. + * + * @param codec_cap The codec data to set the value in. + * @param type The type id to unset. + * + * @retval data_len The @p codec_cap.data_len on success + * @retval -EINVAL Arguments are invalid + */ +int bt_audio_codec_cap_unset_val(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_codec_cap_type type); + +/** + * @brief Extract the frequency from a codec capability. + * + * @param codec_cap The codec capabilities to extract data from. + * + * @retval frequencies Bitfield of supported frequencies (@ref bt_audio_codec_cap_freq) if 0 or + * positive + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + * @retval -EBADMSG The found value has invalid size or value + */ +int bt_audio_codec_cap_get_freq(const struct bt_audio_codec_cap *codec_cap); + +/** + * @brief Set the supported frequencies of a codec capability. + * + * @param codec_cap The codec capabilities to set data for. + * @param freq The supported frequencies to set. + * + * @retval data_len The @p codec_cap.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cap_set_freq(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_codec_cap_freq freq); + +/** + * @brief Extract the frequency from a codec capability. + * + * @param codec_cap The codec capabilities to extract data from. + * + * @retval durations Bitfield of supported frame durations if 0 or positive + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + * @retval -EBADMSG The found value has invalid size or value + */ +int bt_audio_codec_cap_get_frame_dur(const struct bt_audio_codec_cap *codec_cap); + +/** + * @brief Set the frame duration of a codec capability. + * + * @param codec_cap The codec capabilities to set data for. + * @param frame_dur The frame duration to set. + * + * @retval data_len The @p codec_cap.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cap_set_frame_dur(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_codec_cap_frame_dur frame_dur); + +/** + * @brief Extract the frequency from a codec capability. + * + * @param codec_cap The codec capabilities to extract data from. + * @param fallback_to_default If true this function will provide the default value of 1 + * if the type is not found when @p codec_cap.id is @ref BT_HCI_CODING_FORMAT_LC3. + * + * @retval channel_counts Number of supported channel counts if 0 or positive + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + * @retval -EBADMSG The found value has invalid size or value + */ +int bt_audio_codec_cap_get_supported_audio_chan_counts(const struct bt_audio_codec_cap *codec_cap, + bool fallback_to_default); + +/** + * @brief Set the channel count of a codec capability. + * + * @param codec_cap The codec capabilities to set data for. + * @param chan_count The channel count frequency to set. + * + * @retval data_len The @p codec_cap.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cap_set_supported_audio_chan_counts( + struct bt_audio_codec_cap *codec_cap, enum bt_audio_codec_cap_chan_count chan_count); + +/** + * @brief Extract the supported octets per codec frame from a codec capability. + * + * @param[in] codec_cap The codec capabilities to extract data from. + * @param[out] codec_frame Struct to place the resulting values in + * + * @retval 0 Success + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + * @retval -EBADMSG The found value has invalid size or value + */ +int bt_audio_codec_cap_get_octets_per_frame( + const struct bt_audio_codec_cap *codec_cap, + struct bt_audio_codec_octets_per_codec_frame *codec_frame); + +/** + * @brief Set the octets per codec frame of a codec capability. + * + * @param codec_cap The codec capabilities to set data for. + * @param codec_frame The octets per codec frame to set. + * + * @retval data_len The @p codec_cap.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cap_set_octets_per_frame( + struct bt_audio_codec_cap *codec_cap, + const struct bt_audio_codec_octets_per_codec_frame *codec_frame); + +/** + * @brief Extract the maximum codec frames per SDU from a codec capability. + * + * @param codec_cap The codec capabilities to extract data from. + * @param fallback_to_default If true this function will provide the default value of 1 + * if the type is not found when @p codec_cap.id is @ref BT_HCI_CODING_FORMAT_LC3. + * + * @retval codec_frames_per_sdu Maximum number of codec frames per SDU supported + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + * @retval -EBADMSG The found value has invalid size or value + */ +int bt_audio_codec_cap_get_max_codec_frames_per_sdu(const struct bt_audio_codec_cap *codec_cap, + bool fallback_to_default); + +/** + * @brief Set the maximum codec frames per SDU of a codec capability. + * + * @param codec_cap The codec capabilities to set data for. + * @param codec_frames_per_sdu The maximum codec frames per SDU to set. + * + * @retval data_len The @p codec_cap.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cap_set_max_codec_frames_per_sdu(struct bt_audio_codec_cap *codec_cap, + uint8_t codec_frames_per_sdu); + +/** + * @brief Lookup a specific metadata value based on type + * + * @param[in] codec_cap The codec data to search in. + * @param[in] type The type id to look for + * @param[out] data Pointer to the data-pointer to update when item is found + * + * @retval len Length of found @p data (may be 0) + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + */ +int bt_audio_codec_cap_meta_get_val(const struct bt_audio_codec_cap *codec_cap, uint8_t type, + const uint8_t **data); + +/** + * @brief Set or add a specific codec capability metadata value. + * + * @param codec_cap The codec capability to set the value in. + * @param type The type id to set. + * @param data Pointer to the data-pointer to set. + * @param data_len Length of @p data. + * + * @retval meta_len The @p codec_cap.meta_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cap_meta_set_val(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_metadata_type type, const uint8_t *data, + size_t data_len); + +/** + * @brief Unset a specific codec capability metadata value + * + * The type and the value will be removed from the codec capability metadata. + * + * @param codec_cap The codec data to set the value in. + * @param type The type id to unset. + * + * @retval meta_len The of @p codec_cap.meta_len on success + * @retval -EINVAL Arguments are invalid + */ +int bt_audio_codec_cap_meta_unset_val(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_metadata_type type); + +/** + * @brief Extract preferred contexts + * + * See @ref BT_AUDIO_METADATA_TYPE_PREF_CONTEXT for more information about this value. + * + * @param codec_cap The codec data to search in. + * + * @retval The preferred context type if positive or 0 + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + * @retval -EBADMSG The found value has invalid size + */ +int bt_audio_codec_cap_meta_get_pref_context(const struct bt_audio_codec_cap *codec_cap); + +/** + * @brief Set the preferred context of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param ctx The preferred context to set. + * + * @retval data_len The @p codec_cap.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cap_meta_set_pref_context(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_context ctx); + +/** + * @brief Extract stream contexts + * + * See @ref BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT for more information about this value. + * + * @param codec_cap The codec data to search in. + * + * @retval context The stream context type if positive or 0 + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + * @retval -EBADMSG The found value has invalid size + */ +int bt_audio_codec_cap_meta_get_stream_context(const struct bt_audio_codec_cap *codec_cap); + +/** + * @brief Set the stream context of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param ctx The stream context to set. + * + * @retval data_len The @p codec_cap.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cap_meta_set_stream_context(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_context ctx); + +/** + * @brief Extract program info + * + * See @ref BT_AUDIO_METADATA_TYPE_PROGRAM_INFO for more information about this value. + * + * @param[in] codec_cap The codec data to search in. + * @param[out] program_info Pointer to the UTF-8 formatted program info. + * + * @retval len The length of the @p program_info (may be 0) + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + */ +int bt_audio_codec_cap_meta_get_program_info(const struct bt_audio_codec_cap *codec_cap, + const uint8_t **program_info); + +/** + * @brief Set the program info of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param program_info The program info to set. + * @param program_info_len The length of @p program_info. + * + * @retval data_len The @p codec_cap.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cap_meta_set_program_info(struct bt_audio_codec_cap *codec_cap, + const uint8_t *program_info, size_t program_info_len); + +/** + * @brief Extract language + * + * See @ref BT_AUDIO_METADATA_TYPE_LANG for more information about this value. + * + * @param[in] codec_cap The codec data to search in. + * @param[out] lang Pointer to the language bytes (of length BT_AUDIO_LANG_SIZE) + * + * @retval 0 Success + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + * @retval -EBADMSG The found value has invalid size + */ +int bt_audio_codec_cap_meta_get_lang(const struct bt_audio_codec_cap *codec_cap, + const uint8_t **lang); + +/** + * @brief Set the language of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param lang The 24-bit language to set. + * + * @retval data_len The @p codec_cap.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cap_meta_set_lang(struct bt_audio_codec_cap *codec_cap, + const uint8_t lang[BT_AUDIO_LANG_SIZE]); + +/** + * @brief Extract CCID list + * + * See @ref BT_AUDIO_METADATA_TYPE_CCID_LIST for more information about this value. + * + * @param[in] codec_cap The codec data to search in. + * @param[out] ccid_list Pointer to the array containing 8-bit CCIDs. + * + * @retval len The length of the @p ccid_list (may be 0) + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + */ +int bt_audio_codec_cap_meta_get_ccid_list(const struct bt_audio_codec_cap *codec_cap, + const uint8_t **ccid_list); + +/** + * @brief Set the CCID list of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param ccid_list The program info to set. + * @param ccid_list_len The length of @p ccid_list. + * + * @retval data_len The @p codec_cap.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cap_meta_set_ccid_list(struct bt_audio_codec_cap *codec_cap, + const uint8_t *ccid_list, size_t ccid_list_len); + +/** + * @brief Extract parental rating + * + * See @ref BT_AUDIO_METADATA_TYPE_PARENTAL_RATING for more information about this value. + * + * @param codec_cap The codec data to search in. + * + * @retval The parental rating if positive or 0 + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + * @retval -EBADMSG The found value has invalid size + */ +int bt_audio_codec_cap_meta_get_parental_rating(const struct bt_audio_codec_cap *codec_cap); + +/** + * @brief Set the parental rating of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param parental_rating The parental rating to set. + * + * @retval data_len The @p codec_cap.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cap_meta_set_parental_rating(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_parental_rating parental_rating); + +/** + * @brief Extract program info URI + * + * See @ref BT_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI for more information about this value. + * + * @param[in] codec_cap The codec data to search in. + * @param[out] program_info_uri Pointer to the UTF-8 formatted program info URI. + * + * @retval len The length of the @p program_info_uri (may be 0) + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + */ +int bt_audio_codec_cap_meta_get_program_info_uri(const struct bt_audio_codec_cap *codec_cap, + const uint8_t **program_info_uri); + +/** + * @brief Set the program info URI of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param program_info_uri The program info URI to set. + * @param program_info_uri_len The length of @p program_info_uri. + * + * @retval data_len The @p codec_cap.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cap_meta_set_program_info_uri(struct bt_audio_codec_cap *codec_cap, + const uint8_t *program_info_uri, + size_t program_info_uri_len); + +/** + * @brief Extract audio active state + * + * See @ref BT_AUDIO_METADATA_TYPE_AUDIO_STATE for more information about this value. + * + * @param codec_cap The codec data to search in. + * + * @retval context The preferred context type if positive or 0 + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + * @retval -EBADMSG The found value has invalid size + */ +int bt_audio_codec_cap_meta_get_audio_active_state(const struct bt_audio_codec_cap *codec_cap); + +/** + * @brief Set the audio active state of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param state The audio active state to set. + * + * @retval data_len The @p codec_cap.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cap_meta_set_audio_active_state(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_active_state state); + +/** + * @brief Extract broadcast audio immediate rendering flag + * + * See @ref BT_AUDIO_METADATA_TYPE_BROADCAST_IMMEDIATE for more information about this value. + * + * @param codec_cap The codec data to search in. + * + * @retval 0 The flag was found + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA The flag was not found + */ +int bt_audio_codec_cap_meta_get_bcast_audio_immediate_rend_flag( + const struct bt_audio_codec_cap *codec_cap); + +/** + * @brief Set the broadcast audio immediate rendering flag of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * + * @retval data_len The @p codec_cap.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cap_meta_set_bcast_audio_immediate_rend_flag( + struct bt_audio_codec_cap *codec_cap); + +/** + * @brief Extract assisted listening stream + * + * See @ref BT_AUDIO_METADATA_TYPE_ASSISTED_LISTENING_STREAM for more information about this value. + * + * @param codec_cap The codec data to search in. + * + * @retval value The assisted listening stream value if positive or 0 + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + * @retval -EBADMSG The found value has invalid size + */ +int bt_audio_codec_cap_meta_get_assisted_listening_stream( + const struct bt_audio_codec_cap *codec_cap); + +/** + * @brief Set the assisted listening stream value of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param val The assisted listening stream value to set. + * + * @retval data_len The @p codec_cap.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cap_meta_set_assisted_listening_stream( + struct bt_audio_codec_cap *codec_cap, enum bt_audio_assisted_listening_stream val); + +/** + * @brief Extract broadcast name + * + * See @ref BT_AUDIO_METADATA_TYPE_BROADCAST_NAME for more information about this value. + * + * @param[in] codec_cap The codec data to search in. + * @param[out] broadcast_name Pointer to the UTF-8 formatted broadcast name. + * + * @retval length The length of the @p broadcast_name (may be 0) + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + */ +int bt_audio_codec_cap_meta_get_broadcast_name(const struct bt_audio_codec_cap *codec_cap, + const uint8_t **broadcast_name); + +/** + * @brief Set the broadcast name of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param broadcast_name The broadcast name to set. + * @param broadcast_name_len The length of @p broadcast_name. + * + * @retval data_len The @p codec_cap.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cap_meta_set_broadcast_name(struct bt_audio_codec_cap *codec_cap, + const uint8_t *broadcast_name, + size_t broadcast_name_len); +/** + * @brief Extract extended metadata + * + * See @ref BT_AUDIO_METADATA_TYPE_EXTENDED for more information about this value. + * + * @param[in] codec_cap The codec data to search in. + * @param[out] extended_meta Pointer to the extended metadata. + * + * @retval len The length of the @p extended_meta (may be 0) + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + */ +int bt_audio_codec_cap_meta_get_extended(const struct bt_audio_codec_cap *codec_cap, + const uint8_t **extended_meta); + +/** + * @brief Set the extended metadata of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param extended_meta The extended metadata to set. + * @param extended_meta_len The length of @p extended_meta. + * + * @retval data_len The @p codec_cap.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cap_meta_set_extended(struct bt_audio_codec_cap *codec_cap, + const uint8_t *extended_meta, size_t extended_meta_len); + +/** + * @brief Extract vendor specific metadata + * + * See @ref BT_AUDIO_METADATA_TYPE_VENDOR for more information about this value. + * + * @param[in] codec_cap The codec data to search in. + * @param[out] vendor_meta Pointer to the vendor specific metadata. + * + * @retval len The length of the @p vendor_meta (may be 0) + * @retval -EINVAL Arguments are invalid + * @retval -ENODATA Data not found + */ +int bt_audio_codec_cap_meta_get_vendor(const struct bt_audio_codec_cap *codec_cap, + const uint8_t **vendor_meta); + +/** + * @brief Set the vendor specific metadata of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param vendor_meta The vendor specific metadata to set. + * @param vendor_meta_len The length of @p vendor_meta. + * + * @retval data_len The @p codec_cap.data_len on success + * @retval -EINVAL Arguments are invalid + * @retval -ENOMEM The new value could not be set or added due to lack of memory + */ +int bt_audio_codec_cap_meta_set_vendor(struct bt_audio_codec_cap *codec_cap, + const uint8_t *vendor_meta, size_t vendor_meta_len); + +/** @} */ /* End of bt_audio_codec_cap */ + +/** + * @brief Assigned numbers to string API + * @defgroup bt_audio_to_str Assigned numbers to string API + * + * Functions to return string representation of Bluetooth Audio assigned number values. + * + * @{ + */ + +/** + * @brief Returns a string representation of a specific @ref bt_audio_context bit + * + * If @p context contains multiple bits, it will return "Unknown context" + * + * @param context A single context bit + * + * @return String representation of the supplied bit + */ +static inline char *bt_audio_context_bit_to_str(enum bt_audio_context context) +{ + switch (context) { + case BT_AUDIO_CONTEXT_TYPE_NONE: + return "None"; + case BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED: + return "Unspecified"; + case BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL: + return "Conversational"; + case BT_AUDIO_CONTEXT_TYPE_MEDIA: + return "Media"; + case BT_AUDIO_CONTEXT_TYPE_GAME: + return "Game"; + case BT_AUDIO_CONTEXT_TYPE_INSTRUCTIONAL: + return "Instructional"; + case BT_AUDIO_CONTEXT_TYPE_VOICE_ASSISTANTS: + return "Voice assistant"; + case BT_AUDIO_CONTEXT_TYPE_LIVE: + return "Live"; + case BT_AUDIO_CONTEXT_TYPE_SOUND_EFFECTS: + return "Sound effects"; + case BT_AUDIO_CONTEXT_TYPE_NOTIFICATIONS: + return "Notifications"; + case BT_AUDIO_CONTEXT_TYPE_RINGTONE: + return "Ringtone"; + case BT_AUDIO_CONTEXT_TYPE_ALERTS: + return "Alerts"; + case BT_AUDIO_CONTEXT_TYPE_EMERGENCY_ALARM: + return "Emergency alarm"; + default: + return "Unknown context"; + } +} + +/** + * @brief Returns a string representation of a @ref bt_audio_parental_rating value + * + * @param parental_rating The parental rating value + * + * @return String representation of the supplied parental rating value + */ +static inline char *bt_audio_parental_rating_to_str(enum bt_audio_parental_rating parental_rating) +{ + switch (parental_rating) { + case BT_AUDIO_PARENTAL_RATING_NO_RATING: + return "No rating"; + case BT_AUDIO_PARENTAL_RATING_AGE_ANY: + return "Any"; + case BT_AUDIO_PARENTAL_RATING_AGE_5_OR_ABOVE: + return "Age 5 or above"; + case BT_AUDIO_PARENTAL_RATING_AGE_6_OR_ABOVE: + return "Age 6 or above"; + case BT_AUDIO_PARENTAL_RATING_AGE_7_OR_ABOVE: + return "Age 7 or above"; + case BT_AUDIO_PARENTAL_RATING_AGE_8_OR_ABOVE: + return "Age 8 or above"; + case BT_AUDIO_PARENTAL_RATING_AGE_9_OR_ABOVE: + return "Age 9 or above"; + case BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE: + return "Age 10 or above"; + case BT_AUDIO_PARENTAL_RATING_AGE_11_OR_ABOVE: + return "Age 11 or above"; + case BT_AUDIO_PARENTAL_RATING_AGE_12_OR_ABOVE: + return "Age 12 or above"; + case BT_AUDIO_PARENTAL_RATING_AGE_13_OR_ABOVE: + return "Age 13 or above"; + case BT_AUDIO_PARENTAL_RATING_AGE_14_OR_ABOVE: + return "Age 14 or above"; + case BT_AUDIO_PARENTAL_RATING_AGE_15_OR_ABOVE: + return "Age 15 or above"; + case BT_AUDIO_PARENTAL_RATING_AGE_16_OR_ABOVE: + return "Age 16 or above"; + case BT_AUDIO_PARENTAL_RATING_AGE_17_OR_ABOVE: + return "Age 17 or above"; + case BT_AUDIO_PARENTAL_RATING_AGE_18_OR_ABOVE: + return "Age 18 or above"; + default: + return "Unknown rating"; + } +} + +/** + * @brief Returns a string representation of a @ref bt_audio_active_state value + * + * @param state The active state value + * + * @return String representation of the supplied active state value + */ +static inline char *bt_audio_active_state_to_str(enum bt_audio_active_state state) +{ + switch (state) { + case BT_AUDIO_ACTIVE_STATE_DISABLED: + return "Disabled"; + case BT_AUDIO_ACTIVE_STATE_ENABLED: + return "Enabled"; + default: + return "Unknown active state"; + } +} + +/** + * @brief Returns a string representation of a specific @ref bt_audio_codec_cap_freq bit + * + * If @p freq contains multiple bits, it will return "Unknown supported frequency" + * + * @param freq A single frequency bit + * + * @return String representation of the supplied bit + */ +static inline char *bt_audio_codec_cap_freq_bit_to_str(enum bt_audio_codec_cap_freq freq) +{ + switch (freq) { + case BT_AUDIO_CODEC_CAP_FREQ_8KHZ: + return "8000 Hz"; + case BT_AUDIO_CODEC_CAP_FREQ_11KHZ: + return "11025 Hz"; + case BT_AUDIO_CODEC_CAP_FREQ_16KHZ: + return "16000 Hz"; + case BT_AUDIO_CODEC_CAP_FREQ_22KHZ: + return "22050 Hz"; + case BT_AUDIO_CODEC_CAP_FREQ_24KHZ: + return "24000 Hz"; + case BT_AUDIO_CODEC_CAP_FREQ_32KHZ: + return "32000 Hz"; + case BT_AUDIO_CODEC_CAP_FREQ_44KHZ: + return "44100 Hz"; + case BT_AUDIO_CODEC_CAP_FREQ_48KHZ: + return "48000 Hz"; + case BT_AUDIO_CODEC_CAP_FREQ_88KHZ: + return "88200 Hz"; + case BT_AUDIO_CODEC_CAP_FREQ_96KHZ: + return "96000 Hz"; + case BT_AUDIO_CODEC_CAP_FREQ_176KHZ: + return "176400 Hz"; + case BT_AUDIO_CODEC_CAP_FREQ_192KHZ: + return "192000 Hz"; + case BT_AUDIO_CODEC_CAP_FREQ_384KHZ: + return "384000 Hz"; + default: + return "Unknown supported frequency"; + } +} + +/** + * @brief Returns a string representation of a specific @ref bt_audio_codec_cap_frame_dur bit + * + * If @p frame_dur contains multiple bits, it will return "Unknown frame duration" + * + * @param frame_dur A single frame duration bit + * + * @return String representation of the supplied bit + */ +static inline char * +bt_audio_codec_cap_frame_dur_bit_to_str(enum bt_audio_codec_cap_frame_dur frame_dur) +{ + switch (frame_dur) { + case BT_AUDIO_CODEC_CAP_DURATION_7_5: + return "7.5 ms"; + case BT_AUDIO_CODEC_CAP_DURATION_10: + return "10 ms"; + case BT_AUDIO_CODEC_CAP_DURATION_PREFER_7_5: + return "7.5 ms preferred"; + case BT_AUDIO_CODEC_CAP_DURATION_PREFER_10: + return "10 ms preferred"; + default: + return "Unknown frame duration"; + } +} + +/** + * @brief Returns a string representation of a specific @ref bt_audio_codec_cap_chan_count bit + * + * If @p chan_count contains multiple bits, it will return "Unknown channel count" + * + * @param chan_count A single frame channel count bit + * + * @return String representation of the supplied bit + */ +static inline char * +bt_audio_codec_cap_chan_count_bit_to_str(enum bt_audio_codec_cap_chan_count chan_count) +{ + switch (chan_count) { + case BT_AUDIO_CODEC_CAP_CHAN_COUNT_1: + return "1 channel"; + case BT_AUDIO_CODEC_CAP_CHAN_COUNT_2: + return "2 channels"; + case BT_AUDIO_CODEC_CAP_CHAN_COUNT_3: + return "3 channels"; + case BT_AUDIO_CODEC_CAP_CHAN_COUNT_4: + return "4 channels"; + case BT_AUDIO_CODEC_CAP_CHAN_COUNT_5: + return "5 channels"; + case BT_AUDIO_CODEC_CAP_CHAN_COUNT_6: + return "6 channels"; + case BT_AUDIO_CODEC_CAP_CHAN_COUNT_7: + return "7 channels"; + case BT_AUDIO_CODEC_CAP_CHAN_COUNT_8: + return "8 channels"; + default: + return "Unknown channel count"; + } +} + +/** + * @brief Returns a string representation of a specific @ref bt_audio_location bit + * + * If @p location contains multiple bits, it will return "Unknown location" + * + * @param location A single location bit + * + * @return String representation of the supplied bit + */ +static inline char *bt_audio_location_bit_to_str(enum bt_audio_location location) +{ + switch (location) { + case BT_AUDIO_LOCATION_MONO_AUDIO: + return "Mono"; + case BT_AUDIO_LOCATION_FRONT_LEFT: + return "Front left"; + case BT_AUDIO_LOCATION_FRONT_RIGHT: + return "Front right"; + case BT_AUDIO_LOCATION_FRONT_CENTER: + return "Front center"; + case BT_AUDIO_LOCATION_LOW_FREQ_EFFECTS_1: + return "Low frequency effects 1"; + case BT_AUDIO_LOCATION_BACK_LEFT: + return "Back left"; + case BT_AUDIO_LOCATION_BACK_RIGHT: + return "Back right"; + case BT_AUDIO_LOCATION_FRONT_LEFT_OF_CENTER: + return "Front left of center"; + case BT_AUDIO_LOCATION_FRONT_RIGHT_OF_CENTER: + return "Front right of center"; + case BT_AUDIO_LOCATION_BACK_CENTER: + return "Back center"; + case BT_AUDIO_LOCATION_LOW_FREQ_EFFECTS_2: + return "Low frequency effects 2"; + case BT_AUDIO_LOCATION_SIDE_LEFT: + return "Side left"; + case BT_AUDIO_LOCATION_SIDE_RIGHT: + return "Side right"; + case BT_AUDIO_LOCATION_TOP_FRONT_LEFT: + return "Top front left"; + case BT_AUDIO_LOCATION_TOP_FRONT_RIGHT: + return "Top front right"; + case BT_AUDIO_LOCATION_TOP_FRONT_CENTER: + return "Top front center"; + case BT_AUDIO_LOCATION_TOP_CENTER: + return "Top center"; + case BT_AUDIO_LOCATION_TOP_BACK_LEFT: + return "Top back left"; + case BT_AUDIO_LOCATION_TOP_BACK_RIGHT: + return "Top back right"; + case BT_AUDIO_LOCATION_TOP_SIDE_LEFT: + return "Top side left"; + case BT_AUDIO_LOCATION_TOP_SIDE_RIGHT: + return "Top side right"; + case BT_AUDIO_LOCATION_TOP_BACK_CENTER: + return "Top back center"; + case BT_AUDIO_LOCATION_BOTTOM_FRONT_CENTER: + return "Bottom front center"; + case BT_AUDIO_LOCATION_BOTTOM_FRONT_LEFT: + return "Bottom front left"; + case BT_AUDIO_LOCATION_BOTTOM_FRONT_RIGHT: + return "Bottom front right"; + case BT_AUDIO_LOCATION_FRONT_LEFT_WIDE: + return "Front left wide"; + case BT_AUDIO_LOCATION_FRONT_RIGHT_WIDE: + return "Front right wde"; + case BT_AUDIO_LOCATION_LEFT_SURROUND: + return "Left surround"; + case BT_AUDIO_LOCATION_RIGHT_SURROUND: + return "Right surround"; + default: + return "Unknown location"; + } +} + +/** @} */ /* End of bt_audio_to_str */ +#ifdef __cplusplus +} +#endif + +/** @} */ /* end of bt_audio */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/bap.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/bap.h new file mode 100644 index 0000000000..56a0f9790e --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/bap.h @@ -0,0 +1,3151 @@ +/** + * @file + * @brief Header for Bluetooth BAP. + * + * SPDX-FileCopyrightText: 2020 Bose Corporation + * SPDX-FileCopyrightText: 2021-2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_BAP_ +#define ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_BAP_ + +/** + * @brief Bluetooth Basic Audio Profile (BAP) + * @defgroup bt_bap Bluetooth Basic Audio Profile + * + * @since 3.0 + * @version 0.8.0 + * + * @ingroup bluetooth + * @{ + * + * The Basic Audio Profile (BAP) allows for both unicast and broadcast Audio Stream control. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Maximum size of BASE excluding service data header */ +#define BT_BASE_MAX_SIZE (UINT8_MAX - 1 /* type */ - BT_UUID_SIZE_16) + +/** An invalid Broadcast ID */ +#define BT_BAP_INVALID_BROADCAST_ID 0xFFFFFFFFU + +/** Value that represents an unset presentation delay value */ +#define BT_BAP_PD_UNSET 0xFFFFFFFFU + +/** + * @brief Recommended connectable advertising parameters + * + * If connection has not been established after 30 seconds, the device should switch to + * @ref BT_BAP_ADV_PARAM_CONN_REDUCED + * + * Defined by Table 8.1 in BAP 1.0.2 + */ +#define BT_BAP_ADV_PARAM_CONN_QUICK \ + BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONN | BT_LE_ADV_OPT_EXT_ADV, BT_GAP_MS_TO_ADV_INTERVAL(20), \ + BT_GAP_MS_TO_ADV_INTERVAL(30), NULL) + +/** + * @brief Reduced connectable advertising parameters + * + * Defined by Table 8.1 in BAP 1.0.2 + */ +#define BT_BAP_ADV_PARAM_CONN_REDUCED \ + BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONN | BT_LE_ADV_OPT_EXT_ADV, \ + BT_GAP_MS_TO_ADV_INTERVAL(150), BT_GAP_MS_TO_ADV_INTERVAL(150), NULL) + +/** + * @brief Recommended connection parameters for initial connection request for 7.5 ms SDU interval + * + * Once service discovery has completed and a stream is setup, it is recommended to switch to + * @ref BT_BAP_CONN_PARAM_RELAXED + * + * Defined by Table 8.3 in BAP 1.0.2 + */ +#define BT_BAP_CONN_PARAM_SHORT_7_5 \ + BT_LE_CONN_PARAM(BT_GAP_US_TO_CONN_INTERVAL(7500), BT_GAP_MS_TO_CONN_INTERVAL(30), 0, \ + BT_GAP_MS_TO_CONN_TIMEOUT(4000)) + +/** + * @brief Recommended connection parameters for initial connection request for 10 ms SDU interval + * + * Once service discovery has completed and a stream is setup, it is recommended to switch to + * @ref BT_BAP_CONN_PARAM_RELAXED + * + * Defined by Table 8.3 in BAP 1.0.2 + */ +#define BT_BAP_CONN_PARAM_SHORT_10 \ + BT_LE_CONN_PARAM(BT_GAP_MS_TO_CONN_INTERVAL(10), BT_GAP_MS_TO_CONN_INTERVAL(30), 0, \ + BT_GAP_MS_TO_CONN_TIMEOUT(4000)) + +/** + * @brief Recommended connection parameters for coexistence of ACL and ISO + * + * Defined by Table 8.3 in BAP 1.0.2 + */ +#define BT_BAP_CONN_PARAM_RELAXED \ + BT_LE_CONN_PARAM(BT_GAP_MS_TO_CONN_INTERVAL(50), BT_GAP_MS_TO_CONN_INTERVAL(70), 0, \ + BT_GAP_MS_TO_CONN_TIMEOUT(4000)) + +/** + * @brief Fast advertising parameters for broadcast audio + * + * This is suitable for both 7.5 ms and 10 ms SDU intervals, but prioritizes lower time to + * synchronize over coexistence with ISO and power consumption. + */ +#define BT_BAP_ADV_PARAM_BROADCAST_FAST \ + BT_LE_ADV_PARAM(BT_LE_ADV_OPT_EXT_ADV, BT_GAP_MS_TO_ADV_INTERVAL(60), \ + BT_GAP_MS_TO_ADV_INTERVAL(60), NULL) + +/** + * @brief Slow advertising parameters for broadcast audio + * + * This is suitable for both 7.5 ms and 10 ms SDU intervals, but prioritizes coexistence with ISO + * and power consumption over lower time to synchronize. + */ +#define BT_BAP_ADV_PARAM_BROADCAST_SLOW \ + BT_LE_ADV_PARAM(BT_LE_ADV_OPT_EXT_ADV, BT_GAP_MS_TO_ADV_INTERVAL(150), \ + BT_GAP_MS_TO_ADV_INTERVAL(150), NULL) + +/** + * @brief Fast advertising parameters for broadcast audio + * + * This is suitable for both 7.5 ms and 10 ms SDU intervals, but prioritizes lower time to + * synchronize over coexistence with ISO and power consumption. + */ +#define BT_BAP_PER_ADV_PARAM_BROADCAST_FAST \ + BT_LE_PER_ADV_PARAM(BT_GAP_MS_TO_PER_ADV_INTERVAL(60), BT_GAP_MS_TO_PER_ADV_INTERVAL(60), \ + BT_LE_PER_ADV_OPT_NONE) + +/** + * @brief Slow advertising parameters for broadcast audio + * + * This is suitable for both 7.5 ms and 10 ms SDU intervals, but prioritizes coexistence with ISO + * and power consumption over lower time to synchronize. + */ +#define BT_BAP_PER_ADV_PARAM_BROADCAST_SLOW \ + BT_LE_PER_ADV_PARAM(BT_GAP_MS_TO_PER_ADV_INTERVAL(150), \ + BT_GAP_MS_TO_PER_ADV_INTERVAL(150), BT_LE_PER_ADV_OPT_NONE) + +/** + * @brief Check if a BAP BASS BIS_Sync bitfield is valid + * + * Valid options are either a bitmask of valid BIS indices, including none (0x00000000) + * or @ref BT_BAP_BIS_SYNC_NO_PREF (0xFFFFFFFF). + * + * @param _bis_bitfield BIS_Sync bitfield (uint32) + */ +#define BT_BAP_BASS_VALID_BIT_BITFIELD(_bis_bitfield) \ + ((_bis_bitfield) == 0U || (_bis_bitfield) == BT_BAP_BIS_SYNC_NO_PREF || \ + BT_ISO_VALID_BIS_BITFIELD(_bis_bitfield)) + +/** + * @brief Helper to declare elements of bt_bap_qos_cfg + * + * @param _interval SDU interval (usec) + * @param _framing Framing + * @param _phy Target PHY + * @param _sdu Maximum SDU Size + * @param _rtn Retransmission number + * @param _latency Maximum Transport Latency (msec) + * @param _pd Presentation Delay (usec) + */ +#define BT_BAP_QOS_CFG(_interval, _framing, _phy, _sdu, _rtn, _latency, _pd) \ + ((struct bt_bap_qos_cfg){ \ + .interval = _interval, \ + .framing = _framing, \ + .phy = _phy, \ + .sdu = _sdu, \ + .rtn = _rtn, \ + IF_ENABLED(UTIL_OR(IS_ENABLED(CONFIG_BT_BAP_BROADCAST_SOURCE), \ + IS_ENABLED(CONFIG_BT_BAP_UNICAST)), \ + (.latency = _latency,)) \ + .pd = _pd, \ + }) + +/** @brief QoS Framing */ +enum bt_bap_qos_cfg_framing { + /** Packets may be framed or unframed */ + BT_BAP_QOS_CFG_FRAMING_UNFRAMED = 0x00, + /** Packets are always framed */ + BT_BAP_QOS_CFG_FRAMING_FRAMED = 0x01, +}; + +/** @brief QoS Preferred PHY */ +enum { + /** LE 1M PHY */ + BT_BAP_QOS_CFG_1M = BIT(0), + /** LE 2M PHY */ + BT_BAP_QOS_CFG_2M = BIT(1), + /** LE Coded PHY */ + BT_BAP_QOS_CFG_CODED = BIT(2), +}; + +/** + * @brief Helper to declare Input Unframed bt_bap_qos_cfg + * + * @param _interval SDU interval (usec) + * @param _sdu Maximum SDU Size + * @param _rtn Retransmission number + * @param _latency Maximum Transport Latency (msec) + * @param _pd Presentation Delay (usec) + */ +#define BT_BAP_QOS_CFG_UNFRAMED(_interval, _sdu, _rtn, _latency, _pd) \ + BT_BAP_QOS_CFG(_interval, BT_BAP_QOS_CFG_FRAMING_UNFRAMED, BT_BAP_QOS_CFG_2M, _sdu, _rtn, \ + _latency, _pd) + +/** + * @brief Helper to declare Input Framed bt_bap_qos_cfg + * + * @param _interval SDU interval (usec) + * @param _sdu Maximum SDU Size + * @param _rtn Retransmission number + * @param _latency Maximum Transport Latency (msec) + * @param _pd Presentation Delay (usec) + */ +#define BT_BAP_QOS_CFG_FRAMED(_interval, _sdu, _rtn, _latency, _pd) \ + BT_BAP_QOS_CFG(_interval, BT_BAP_QOS_CFG_FRAMING_FRAMED, BT_BAP_QOS_CFG_2M, _sdu, _rtn, \ + _latency, _pd) + +/** @brief QoS configuration structure. */ +struct bt_bap_qos_cfg { + /** + * @brief Presentation Delay in microseconds + * + * This value can be changed up and until bt_bap_stream_qos() has been called. + * Once a stream has been QoS configured, modifying this field does not modify the value. + * It is however possible to modify this field and call bt_bap_stream_qos() again to update + * the value, assuming that the stream is in the correct state. + * + * Value range 0 to @ref BT_AUDIO_PD_MAX. + */ + uint32_t pd; + + /** + * @brief Connected Isochronous Group (CIG) parameters + * + * The fields in this struct affect the value sent to the controller via HCI + * when creating the CIG. Once the group has been created with + * bt_bap_unicast_group_create(), modifying these fields will not affect the group. + */ + struct { + /** QoS Framing */ + enum bt_bap_qos_cfg_framing framing; + + /** + * @brief PHY + * + * Allowed values are @ref BT_BAP_QOS_CFG_1M, @ref BT_BAP_QOS_CFG_2M and + * @ref BT_BAP_QOS_CFG_CODED. + */ + uint8_t phy; + + /** + * @brief Retransmission Number + * + * This a recommendation to the controller, and the actual retransmission number + * may be different than this. + */ + uint8_t rtn; + + /** + * @brief Maximum SDU size + * + * Value range @ref BT_ISO_MIN_SDU to @ref BT_ISO_MAX_SDU. + */ + uint16_t sdu; + + /** + * @brief Maximum Transport Latency + * + * Not used for the @kconfig{CONFIG_BT_BAP_BROADCAST_SINK} role. + */ + uint16_t latency; + + /** + * @brief SDU Interval + * + * Value range @ref BT_ISO_SDU_INTERVAL_MIN to @ref BT_ISO_SDU_INTERVAL_MAX + */ + uint32_t interval; + + /** + * @brief Maximum PDU size + * + * Maximum size, in octets, of the payload from link layer to link layer. + * + * Value range @ref BT_ISO_CONNECTED_PDU_MIN to @ref BT_ISO_PDU_MAX for + * connected ISO. + * + * Value range @ref BT_ISO_BROADCAST_PDU_MIN to @ref BT_ISO_PDU_MAX for + * broadcast ISO. + */ + uint16_t max_pdu; + + /** + * @brief Burst number + * + * Value range @ref BT_ISO_BN_MIN to @ref BT_ISO_BN_MAX. + */ + uint8_t burst_number; + + /** + * @brief Number of subevents + * + * Maximum number of subevents in each CIS or BIS event. + * + * Value range @ref BT_ISO_NSE_MIN to @ref BT_ISO_NSE_MAX. + */ + uint8_t num_subevents; + }; +}; + +/** + * @brief Helper to declare elements of @ref bt_bap_qos_cfg_pref + * + * @param _unframed_supported Unframed PDUs supported + * @param _phy Preferred Target PHY + * @param _rtn Preferred Retransmission number + * @param _latency Preferred Maximum Transport Latency (msec) + * @param _pd_min Minimum Presentation Delay (usec) + * @param _pd_max Maximum Presentation Delay (usec) + * @param _pref_pd_min Preferred Minimum Presentation Delay (usec) + * @param _pref_pd_max Preferred Maximum Presentation Delay (usec) + */ +#define BT_BAP_QOS_CFG_PREF(_unframed_supported, _phy, _rtn, _latency, _pd_min, _pd_max, \ + _pref_pd_min, _pref_pd_max) \ + { \ + .unframed_supported = _unframed_supported, .phy = _phy, .rtn = _rtn, \ + .latency = _latency, .pd_min = _pd_min, .pd_max = _pd_max, \ + .pref_pd_min = _pref_pd_min, .pref_pd_max = _pref_pd_max, \ + } + +/** @brief Audio Stream Quality of Service Preference structure. */ +struct bt_bap_qos_cfg_pref { + /** + * @brief Unframed PDUs supported + * + * Unlike the other fields, this is not a preference but whether + * the codec supports unframed ISOAL PDUs. + */ + bool unframed_supported; + + /** + * @brief Preferred PHY bitfield + * + * Bitfield consisting of one or more of @ref BT_GAP_LE_PHY_1M, @ref BT_GAP_LE_PHY_2M and + * @ref BT_GAP_LE_PHY_CODED. + */ + uint8_t phy; + + /** + * @brief Preferred Retransmission Number + * + * @ref BT_AUDIO_RTN_PREF_NONE indicates no preference. + */ + uint8_t rtn; + + /** + * Preferred Transport Latency + * + * Value range @ref BT_ISO_LATENCY_MIN to @ref BT_ISO_LATENCY_MAX + */ + uint16_t latency; + + /** + * @brief Minimum Presentation Delay in microseconds + * + * Unlike the other fields, this is not a preference but a minimum requirement. + * + * Value range 0 to @ref BT_AUDIO_PD_MAX + */ + uint32_t pd_min; + + /** + * @brief Maximum Presentation Delay in microseconds + * + * Unlike the other fields, this is not a preference but a maximum requirement. + * + * Value range @ref bt_bap_qos_cfg_pref.pd_min to @ref BT_AUDIO_PD_MAX + */ + uint32_t pd_max; + + /** + * @brief Preferred minimum Presentation Delay in microseconds + * + * Value range @ref bt_bap_qos_cfg_pref.pd_min to @ref bt_bap_qos_cfg_pref.pd_max, or + * @ref BT_AUDIO_PD_PREF_NONE to indicate no preference. + */ + uint32_t pref_pd_min; + + /** + * @brief Preferred maximum Presentation Delay in microseconds + * + * Value range @ref bt_bap_qos_cfg_pref.pd_min to @ref bt_bap_qos_cfg_pref.pd_max, + * and higher than or equal to @ref bt_bap_qos_cfg_pref.pref_pd_min, or + * @ref BT_AUDIO_PD_PREF_NONE to indicate no preference. + */ + uint32_t pref_pd_max; +}; + +/** Periodic advertising state reported by the Scan Delegator */ +enum bt_bap_pa_state { + /** The periodic advertising has not been synchronized */ + BT_BAP_PA_STATE_NOT_SYNCED = 0x00, + + /** Waiting for SyncInfo from Broadcast Assistant */ + BT_BAP_PA_STATE_INFO_REQ = 0x01, + + /** Synchronized to periodic advertising */ + BT_BAP_PA_STATE_SYNCED = 0x02, + + /** Failed to synchronized to periodic advertising */ + BT_BAP_PA_STATE_FAILED = 0x03, + + /** No periodic advertising sync transfer receiver from Broadcast Assistant */ + BT_BAP_PA_STATE_NO_PAST = 0x04, +}; + +/** Broadcast Isochronous Group encryption state reported by the Scan Delegator */ +enum bt_bap_big_enc_state { + /** The Broadcast Isochronous Group not encrypted */ + BT_BAP_BIG_ENC_STATE_NO_ENC = 0x00, + + /** The Broadcast Isochronous Group broadcast code requested */ + BT_BAP_BIG_ENC_STATE_BCODE_REQ = 0x01, + + /** The Broadcast Isochronous Group decrypted */ + BT_BAP_BIG_ENC_STATE_DEC = 0x02, + + /** The Broadcast Isochronous Group bad broadcast code */ + BT_BAP_BIG_ENC_STATE_BAD_CODE = 0x03, +}; + +/** Broadcast Audio Scan Service (BASS) specific ATT error codes */ +enum bt_bap_bass_att_err { + /** Opcode not supported */ + BT_BAP_BASS_ERR_OPCODE_NOT_SUPPORTED = 0x80, + + /** Invalid source ID supplied */ + BT_BAP_BASS_ERR_INVALID_SRC_ID = 0x81, +}; + +/** Value indicating that the periodic advertising interval is unknown */ +#define BT_BAP_PA_INTERVAL_UNKNOWN 0xFFFF + +/** + * @brief Broadcast Assistant no BIS sync preference + * + * Value indicating that the Broadcast Assistant has no preference to which BIS + * the Scan Delegator syncs to + */ +#define BT_BAP_BIS_SYNC_NO_PREF 0xFFFFFFFF +/** BIS sync value indicating that the BIG sync has failed for any reason */ +#define BT_BAP_BIS_SYNC_FAILED 0xFFFFFFFF + +/** Endpoint states */ +enum bt_bap_ep_state { + /** Audio Stream Endpoint Idle state */ + BT_BAP_EP_STATE_IDLE = 0x00, + + /** Audio Stream Endpoint Codec Configured state */ + BT_BAP_EP_STATE_CODEC_CONFIGURED = 0x01, + + /** Audio Stream Endpoint QoS Configured state */ + BT_BAP_EP_STATE_QOS_CONFIGURED = 0x02, + + /** Audio Stream Endpoint Enabling state */ + BT_BAP_EP_STATE_ENABLING = 0x03, + + /** Audio Stream Endpoint Streaming state */ + BT_BAP_EP_STATE_STREAMING = 0x04, + + /** Audio Stream Endpoint Disabling state */ + BT_BAP_EP_STATE_DISABLING = 0x05, + + /** Audio Stream Endpoint Streaming state */ + BT_BAP_EP_STATE_RELEASING = 0x06, +}; + +/** + * @brief Response Status Code + * + * These are sent by the server to the client when a stream operation is + * requested. + */ +enum bt_bap_ascs_rsp_code { + /** Server completed operation successfully */ + BT_BAP_ASCS_RSP_CODE_SUCCESS = 0x00, + /** Server did not support operation by client */ + BT_BAP_ASCS_RSP_CODE_NOT_SUPPORTED = 0x01, + /** Server rejected due to invalid operation length */ + BT_BAP_ASCS_RSP_CODE_INVALID_LENGTH = 0x02, + /** Invalid ASE ID */ + BT_BAP_ASCS_RSP_CODE_INVALID_ASE = 0x03, + /** Invalid ASE state */ + BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE = 0x04, + /** Invalid operation for direction */ + BT_BAP_ASCS_RSP_CODE_INVALID_DIR = 0x05, + /** Capabilities not supported by server */ + BT_BAP_ASCS_RSP_CODE_CAP_UNSUPPORTED = 0x06, + /** Configuration parameters not supported by server */ + BT_BAP_ASCS_RSP_CODE_CONF_UNSUPPORTED = 0x07, + /** Configuration parameters rejected by server */ + BT_BAP_ASCS_RSP_CODE_CONF_REJECTED = 0x08, + /** Invalid Configuration parameters */ + BT_BAP_ASCS_RSP_CODE_CONF_INVALID = 0x09, + /** Unsupported metadata */ + BT_BAP_ASCS_RSP_CODE_METADATA_UNSUPPORTED = 0x0a, + /** Metadata rejected by server */ + BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED = 0x0b, + /** Invalid metadata */ + BT_BAP_ASCS_RSP_CODE_METADATA_INVALID = 0x0c, + /** Server has insufficient resources */ + BT_BAP_ASCS_RSP_CODE_NO_MEM = 0x0d, + /** Unspecified error */ + BT_BAP_ASCS_RSP_CODE_UNSPECIFIED = 0x0e, +}; + +/** + * @brief Response Reasons + * + * These are used if the @ref bt_bap_ascs_rsp_code value is + * @ref BT_BAP_ASCS_RSP_CODE_CONF_UNSUPPORTED, @ref BT_BAP_ASCS_RSP_CODE_CONF_REJECTED or + * @ref BT_BAP_ASCS_RSP_CODE_CONF_INVALID. + */ +enum bt_bap_ascs_reason { + /** No reason */ + BT_BAP_ASCS_REASON_NONE = 0x00, + /** Codec ID */ + BT_BAP_ASCS_REASON_CODEC = 0x01, + /** Codec configuration */ + BT_BAP_ASCS_REASON_CODEC_DATA = 0x02, + /** SDU interval */ + BT_BAP_ASCS_REASON_INTERVAL = 0x03, + /** Framing */ + BT_BAP_ASCS_REASON_FRAMING = 0x04, + /** PHY */ + BT_BAP_ASCS_REASON_PHY = 0x05, + /** Maximum SDU size*/ + BT_BAP_ASCS_REASON_SDU = 0x06, + /** RTN */ + BT_BAP_ASCS_REASON_RTN = 0x07, + /** Max transport latency */ + BT_BAP_ASCS_REASON_LATENCY = 0x08, + /** Presendation delay */ + BT_BAP_ASCS_REASON_PD = 0x09, + /** Invalid CIS mapping */ + BT_BAP_ASCS_REASON_CIS = 0x0a, +}; + +/** @brief Structure storing values of fields of ASE Control Point notification. */ +struct bt_bap_ascs_rsp { + /** + * @brief Value of the Response Code field. + * + * The following response codes are accepted: + * - @ref BT_BAP_ASCS_RSP_CODE_SUCCESS + * - @ref BT_BAP_ASCS_RSP_CODE_CAP_UNSUPPORTED + * - @ref BT_BAP_ASCS_RSP_CODE_CONF_UNSUPPORTED + * - @ref BT_BAP_ASCS_RSP_CODE_CONF_REJECTED + * - @ref BT_BAP_ASCS_RSP_CODE_METADATA_UNSUPPORTED + * - @ref BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED + * - @ref BT_BAP_ASCS_RSP_CODE_NO_MEM + * - @ref BT_BAP_ASCS_RSP_CODE_UNSPECIFIED + */ + enum bt_bap_ascs_rsp_code code; + + /** + * @brief Value of the Reason field. + * + * The meaning of this value depend on the Response Code field. + */ + union { + /** + * @brief Response reason + * + * If the Response Code is one of the following: + * - @ref BT_BAP_ASCS_RSP_CODE_CONF_UNSUPPORTED + * - @ref BT_BAP_ASCS_RSP_CODE_CONF_REJECTED + * all values from @ref bt_bap_ascs_reason can be used. + * + * If the Response Code is one of the following: + * - @ref BT_BAP_ASCS_RSP_CODE_SUCCESS + * - @ref BT_BAP_ASCS_RSP_CODE_CAP_UNSUPPORTED + * - @ref BT_BAP_ASCS_RSP_CODE_NO_MEM + * - @ref BT_BAP_ASCS_RSP_CODE_UNSPECIFIED + * only value @ref BT_BAP_ASCS_REASON_NONE shall be used. + */ + enum bt_bap_ascs_reason reason; + + /** + * @brief Response metadata type + * + * If the Response Code is one of the following: + * - @ref BT_BAP_ASCS_RSP_CODE_METADATA_UNSUPPORTED + * - @ref BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED + * the value of the Metadata Type shall be used. + */ + enum bt_audio_metadata_type metadata_type; + }; +}; + +/** + * @brief Macro used to initialise the object storing values of ASE Control Point notification. + * + * @param c Response Code field + * @param r Reason field - @ref bt_bap_ascs_reason or @ref bt_audio_metadata_type (see notes in + * @ref bt_bap_ascs_rsp). + */ +#define BT_BAP_ASCS_RSP(c, r) (struct bt_bap_ascs_rsp) { .code = c, .reason = r } + +/** @brief Abstract Audio Broadcast Source structure. */ +struct bt_bap_broadcast_source; + +/** @brief Abstract Audio Broadcast Sink structure. */ +struct bt_bap_broadcast_sink; + +/** @brief Abstract Audio Unicast Group structure. */ +struct bt_bap_unicast_group; + +/** @brief Abstract Audio Endpoint structure. */ +struct bt_bap_ep; + +/** Struct to hold subgroup specific information for the receive state */ +struct bt_bap_bass_subgroup { + /** BIS synced bitfield */ + uint32_t bis_sync; + + /** Length of the metadata */ + uint8_t metadata_len; + + /** The metadata */ + uint8_t *metadata; +}; + +/** Represents the Broadcast Audio Scan Service receive state */ +struct bt_bap_scan_delegator_recv_state { + /** The source ID */ + uint8_t src_id; + + /** The Bluetooth address */ + bt_addr_le_t addr; + + /** The advertising set ID*/ + uint8_t adv_sid; + + /** The periodic adverting sync state */ + enum bt_bap_pa_state pa_sync_state; + + /** The broadcast isochronous group encryption state */ + enum bt_bap_big_enc_state encrypt_state; + + /** The 24-bit broadcast ID */ + uint32_t broadcast_id; + + /** + * @brief The bad broadcast code + * + * Only valid if encrypt_state is @ref BT_BAP_BIG_ENC_STATE_BCODE_REQ + */ + uint8_t bad_code[BT_ISO_BROADCAST_CODE_SIZE]; + + /** Number of subgroups */ + uint8_t num_subgroups; + + /** Subgroup specific information + * + * If the @ref bt_bap_bass_subgroup.bis_sync value is @ref BT_BAP_BIS_SYNC_FAILED then it + * indicates that the BIG sync failed. + */ + struct bt_bap_bass_subgroup *subgroups; +}; + +/** + * @brief Struct to hold the Basic Audio Profile Scan Delegator callbacks + * + * These can be registered for usage with bt_bap_scan_delegator_register(). + */ +struct bt_bap_scan_delegator_cb { + /** + * @brief Receive state updated + * + * @param conn Pointer to the connection to a remote device if + * the change was caused by it, otherwise NULL. + * @param recv_state Pointer to the receive state that was updated. + * + * @return 0 in case of success or negative value in case of error. + */ + void (*recv_state_updated)(struct bt_conn *conn, + const struct bt_bap_scan_delegator_recv_state *recv_state); + + /** + * @brief Periodic advertising sync request + * + * Request from peer device to synchronize with the periodic advertiser + * denoted by the @p recv_state. To notify the Broadcast Assistant about + * any pending sync + * + * @param conn Pointer to the connection requesting the + * periodic advertising sync. + * @param recv_state Pointer to the receive state that is being + * requested for periodic advertising sync. + * @param past_avail True if periodic advertising sync transfer is available. + * @param pa_interval The periodic advertising interval. + * + * @return 0 in case of accept, or other value to reject. + */ + int (*pa_sync_req)(struct bt_conn *conn, + const struct bt_bap_scan_delegator_recv_state *recv_state, + bool past_avail, uint16_t pa_interval); + + /** + * @brief Periodic advertising sync termination request + * + * Request from peer device to terminate the periodic advertiser sync + * denoted by the @p recv_state. + * + * @param conn Pointer to the connection requesting the periodic + * advertising sync termination. + * @param recv_state Pointer to the receive state that is being + * requested for periodic advertising sync. + * + * @return 0 in case of success or negative value in case of error. + */ + int (*pa_sync_term_req)(struct bt_conn *conn, + const struct bt_bap_scan_delegator_recv_state *recv_state); + + /** + * @brief Broadcast code received + * + * Broadcast code received from a broadcast assistant + * + * @param conn Pointer to the connection providing the + * broadcast code. + * @param recv_state Pointer to the receive state the broadcast code + * is being provided for. + * @param broadcast_code The 16-octet broadcast code + */ + void (*broadcast_code)(struct bt_conn *conn, + const struct bt_bap_scan_delegator_recv_state *recv_state, + const uint8_t broadcast_code[BT_ISO_BROADCAST_CODE_SIZE]); + /** + * @brief Broadcast Isochronous Stream synchronize request + * + * Request from Broadcast Assistant device to modify the Broadcast + * Isochronous Stream states. The request shall be fulfilled with + * accordance to the @p bis_sync_req within reasonable time. The + * Broadcast Assistant may also request fewer, or none, indexes to + * be synchronized. + * + * @param[in] conn Pointer to the connection of the + * Broadcast Assistant requesting the sync. + * @param[in] recv_state Pointer to the receive state that is being + * requested for the sync. + * @param[in] bis_sync_req Array of bitfields of which BIS indexes + * that is requested to sync for each subgroup + * by the Broadcast Assistant. A value of 0 + * indicates a request to terminate the BIG + * sync. + * + * @return 0 in case of accept, or other value to reject. + */ + int (*bis_sync_req)(struct bt_conn *conn, + const struct bt_bap_scan_delegator_recv_state *recv_state, + const uint32_t bis_sync_req[CONFIG_BT_BAP_BASS_MAX_SUBGROUPS]); + /** + * @brief Broadcast Assistant scanning state callback + * + * Callback triggered when a Broadcast Assistant notifies the Scan Delegator about the + * assistants scanning state. + * + * @param conn Pointer to the connection that initiated the scan. + * @param is_scanning true if scanning started, false if scanning stopped. + */ + void (*scanning_state)(struct bt_conn *conn, bool is_scanning); + /** + * @brief Add Source operation callback + * + * These callbacks notify the application when a request comes + * in to add a source. The application can return 0 to + * accept or any other value to reject the request. + * + * @param conn Pointer to the connection that initiated the request, + * or NULL if locally triggered. + * @param recv_state Pointer to the requested receive state to be added. + * + * @return 0 in case of accept, or other value to reject. + */ + int (*add_source)(struct bt_conn *conn, + const struct bt_bap_scan_delegator_recv_state *recv_state); + + /** + * @brief Modify Source operation callback + * + * These callbacks notify the application when a request comes + * in to modify a source. The application can return 0 to + * accept or any other value to reject the request. + * + * @param conn Pointer to the connection that initiated the request, + * or NULL if locally triggered. + * @param recv_state Pointer to the requested receive state to be modified. + * + * @return 0 in case of accept, or other value to reject. + */ + int (*modify_source)(struct bt_conn *conn, + const struct bt_bap_scan_delegator_recv_state *recv_state); + + /** + * @brief Remove Source operation callback + * + * These callbacks notify the application when a request comes + * in to remove a source. The application can return 0 to + * accept or any other value to reject the request. + * + * @param conn Pointer to the connection that initiated the request, + * or NULL if locally triggered. + * @param src_id The Source ID that is requested to be removed. + * + * @return 0 in case of accept, or other value to reject. + */ + int (*remove_source)(struct bt_conn *conn, uint8_t src_id); +}; + +/** Structure holding information of audio stream endpoint */ +struct bt_bap_ep_info { + /** The ID of the endpoint */ + uint8_t id; + + /** The state of the endpoint */ + enum bt_bap_ep_state state; + + /** Capabilities type */ + enum bt_audio_dir dir; + + /** The isochronous channel associated with the endpoint. */ + struct bt_iso_chan *iso_chan; + + /** @brief True if the stream associated with the endpoint is able to send data */ + bool can_send; + + /** @brief True if the stream associated with the endpoint is able to receive data */ + bool can_recv; + + /** Pointer to paired endpoint if the endpoint is part of a bidirectional CIS, + * otherwise NULL + */ + struct bt_bap_ep *paired_ep; + + /** Pointer to the preferred QoS settings associated with the endpoint */ + const struct bt_bap_qos_cfg_pref *qos_pref; +}; + +/** + * @brief Return structure holding information of audio stream endpoint + * + * @param ep The audio stream endpoint object. + * @param info The structure object to be filled with the info. + * + * @retval 0 in case of success + * @retval -EINVAL if @p ep or @p info are NULL + */ +int bt_bap_ep_get_info_safe(const struct bt_bap_ep *ep, struct bt_bap_ep_info *info); + +/** + * @brief Basic Audio Profile stream structure. + * + * Streams represents a stream configuration of a Remote Endpoint and a Local Capability. + * + * @note Streams are unidirectional but can be paired with other streams to use a bidirectional + * connected isochronous stream. + */ +struct bt_bap_stream { + /** Connection reference */ + struct bt_conn *conn; + + /** Endpoint reference */ + struct bt_bap_ep *ep; + + /** Codec Configuration */ + struct bt_audio_codec_cfg *codec_cfg; + + /** QoS Configuration */ + struct bt_bap_qos_cfg *qos; + + /** Audio stream operations */ + struct bt_bap_stream_ops *ops; + + /** Stream user data */ + void *user_data; + + /** ISO channel reference + * + * This will become valid once the stream is added to a group (bt_bap_unicast_group, + * bt_bap_broadcast_source or bt_bap_broadcast_sink). + */ + struct bt_iso_chan *iso; + + /** Unicast or Broadcast group - Used internally */ + void *group; + + /** Previously sent sequence number */ + uint16_t _prev_seq_num; + + /** @cond INTERNAL_HIDDEN */ + /** Internally used list node */ + sys_snode_t _node; + /** @endcond */ +}; + +/** @brief Stream operation. */ +struct bt_bap_stream_ops { + /** + * @brief Stream configured callback + * + * Configured callback is called whenever an Audio Stream has been configured. + * + * @param stream Stream object that has been configured. + * @param pref Remote QoS preferences. + */ + void (*configured)(struct bt_bap_stream *stream, const struct bt_bap_qos_cfg_pref *pref); + + /** + * @brief Stream QoS set callback + * + * QoS set callback is called whenever an Audio Stream Quality of Service has been set or + * updated. + * + * @param stream Stream object that had its QoS updated. + */ + void (*qos_set)(struct bt_bap_stream *stream); + + /** + * @brief Stream enabled callback + * + * Enabled callback is called whenever an Audio Stream has been enabled. + * + * @param stream Stream object that has been enabled. + */ + void (*enabled)(struct bt_bap_stream *stream); + + /** + * @brief Stream metadata updated callback + * + * Metadata Updated callback is called whenever an Audio Stream's metadata has been + * updated. + * + * @param stream Stream object that had its metadata updated. + */ + void (*metadata_updated)(struct bt_bap_stream *stream); + + /** + * @brief Stream disabled callback + * + * Disabled callback is called whenever an Audio Stream has been disabled. + * + * @param stream Stream object that has been disabled. + */ + void (*disabled)(struct bt_bap_stream *stream); + + /** + * @brief Stream released callback + * + * Released callback is called whenever a Audio Stream has been released and can be + * deallocated. + * + * @param stream Stream object that has been released. + */ + void (*released)(struct bt_bap_stream *stream); + + /** + * @brief Stream started callback + * + * Started callback is called whenever an Audio Stream has been started + * and will be usable for streaming. + * + * @param stream Stream object that has been started. + */ + void (*started)(struct bt_bap_stream *stream); + + /** + * @brief Stream stopped callback + * + * Stopped callback is called whenever an Audio Stream has been stopped. + * + * @param stream Stream object that has been stopped. + * @param reason BT_HCI_ERR_* reason for the disconnection. + */ + void (*stopped)(struct bt_bap_stream *stream, uint8_t reason); + + /** + * @brief Stream audio HCI receive callback. + * + * This callback is only used if the ISO data path is HCI. + * + * @param stream Stream object. + * @param info Pointer to the metadata for the buffer. The lifetime of the pointer is + * linked to the lifetime of the net_buf. Metadata such as sequence number and + * timestamp can be provided by the bluetooth controller. + * @param buf Buffer containing incoming audio data. + */ + void (*recv)(struct bt_bap_stream *stream, const struct bt_iso_recv_info *info, + const uint8_t *data, uint16_t len); + + /** + * @brief Stream audio HCI sent callback + * + * This callback will be called once the controller marks the SDU + * as completed. When the controller does so is implementation + * dependent. It could be after the SDU is enqueued for transmission, + * or after it is sent on air or flushed. + * + * This callback is only used if the ISO data path is HCI. + * + * @param stream Stream object. + */ + void (*sent)(struct bt_bap_stream *stream, void *user_data); + + /** + * @brief Isochronous channel connected callback + * + * If this callback is provided it will be called whenever the isochronous channel for the + * stream has been connected. This does not mean that the stream is ready to be used, which + * is indicated by the @ref bt_bap_stream_ops.started callback. + * + * If the stream shares an isochronous channel with another stream, then this callback may + * still be called, without the stream going into the started state. + * + * @param stream Stream object. + */ + void (*connected)(struct bt_bap_stream *stream); + + /** + * @brief Isochronous channel disconnected callback + * + * If this callback is provided it will be called whenever the isochronous channel is + * disconnected, including when a connection gets rejected. + * + * If the stream shares an isochronous channel with another stream, then this callback may + * not be called, even if the stream is leaving the streaming state. + * + * @param stream Stream object. + * @param reason BT_HCI_ERR_* reason for the disconnection. + */ + void (*disconnected)(struct bt_bap_stream *stream, uint8_t reason); +}; + +/** Structure for registering Unicast Server */ +struct bt_bap_unicast_server_register_param { + /** + * @brief Sink Count to register. + * + * Should be in range 0 to @kconfig{CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT} + */ + uint8_t snk_cnt; + + /** @brief Source Count to register. + * + * Should be in range 0 to @kconfig{CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT} + */ + uint8_t src_cnt; +}; + +/** + * @brief Register Audio callbacks for a stream. + * + * Register Audio callbacks for a stream. + * + * @param stream Stream object. + * @param ops Stream operations structure. + */ +void bt_bap_stream_cb_register_safe(struct bt_bap_stream *stream, struct bt_bap_stream_ops *ops); + +/** + * @brief Configure Audio Stream + * + * This procedure is used by a client to configure a new stream using the + * remote endpoint, local capability and codec configuration. + * + * @param conn Connection object + * @param stream Stream object being configured + * @param ep Remote Audio Endpoint being configured + * @param codec_cfg Codec configuration + * + * @return Allocated Audio Stream object or NULL in case of error. + */ +int bt_bap_stream_config(struct bt_conn *conn, struct bt_bap_stream *stream, struct bt_bap_ep *ep, + struct bt_audio_codec_cfg *codec_cfg); +int bt_bap_stream_config_safe(struct bt_conn *conn, struct bt_bap_stream *stream, struct bt_bap_ep *ep, + struct bt_audio_codec_cfg *codec_cfg); + +/** + * @brief Reconfigure Audio Stream + * + * This procedure is used by a unicast client or unicast server to reconfigure + * a stream to use a different local codec configuration. + * + * This can only be done for unicast streams. + * + * @param stream Stream object being reconfigured + * @param codec_cfg Codec configuration + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_bap_stream_reconfig_safe(struct bt_bap_stream *stream, struct bt_audio_codec_cfg *codec_cfg); + +/** + * @brief Configure Audio Stream QoS + * + * This procedure is used by a client to configure the Quality of Service of streams in a unicast + * group. All streams in the group for the specified @p conn will have the Quality of Service + * configured. This shall only be used to configure unicast streams. + * + * @param conn Connection object + * @param group Unicast group object + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_bap_stream_qos(struct bt_conn *conn, struct bt_bap_unicast_group *group); +int bt_bap_stream_qos_safe(struct bt_conn *conn, struct bt_bap_unicast_group *group); + +/** + * @brief Enable Audio Stream + * + * This procedure is used by a client to enable a stream. + * + * This shall only be called for unicast streams, as broadcast streams will always be enabled once + * created. + * + * @param stream Stream object + * @param meta Metadata + * @param meta_len Metadata length + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_bap_stream_enable_safe(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len); + +/** + * @brief Change Audio Stream Metadata + * + * This procedure is used by a unicast client or unicast server to change the metadata of a stream. + * + * @param stream Stream object + * @param meta Metadata + * @param meta_len Metadata length + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_bap_stream_metadata_safe(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len); + +/** + * @brief Disable Audio Stream + * + * This procedure is used by a unicast client or unicast server to disable a stream. + * + * This shall only be called for unicast streams, as broadcast streams will + * always be enabled once created. + * + * @param stream Stream object + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_bap_stream_disable_safe(struct bt_bap_stream *stream); + +/** + * @brief Connect unicast audio stream + * + * This procedure is used by a unicast client to connect the connected isochronous stream (CIS) + * associated with the audio stream. If two audio streams share a CIS, then this only needs to be + * done once for those streams. This can only be done for streams in the QoS configured or enabled + * states. + * + * The bt_bap_stream_ops.connected() callback will be called on the streams once this has finished. + * + * This shall only be called for unicast streams, and only as the unicast client + * (@kconfig{CONFIG_BT_BAP_UNICAST_CLIENT}). + * + * @param stream Stream object + * + * @retval 0 in case of success + * @retval -EINVAL if the stream, endpoint, ISO channel or connection is NULL + * @retval -EBADMSG if the stream or ISO channel is in an invalid state for connection + * @retval -EOPNOTSUPP if the role of the stream is not @ref BT_HCI_ROLE_CENTRAL + * @retval -EALREADY if the ISO channel is already connecting or connected + * @retval -EBUSY if another ISO channel is connecting + * @retval -ENOEXEC if otherwise rejected by the ISO layer + */ +int bt_bap_stream_connect_safe(struct bt_bap_stream *stream); + +/** + * @brief Start Audio Stream + * + * This procedure is used by a unicast client or unicast server to make a stream start streaming. + * + * For the unicast client, this will send the receiver start ready command to the unicast server for + * @ref BT_AUDIO_DIR_SOURCE ASEs. The CIS is required to be connected first by + * bt_bap_stream_connect() before the command can be sent. + * + * For the unicast server, this will execute the receiver start ready command on the unicast server + * for @ref BT_AUDIO_DIR_SINK ASEs. If the CIS is not connected yet, the stream will go into the + * streaming state as soon as the CIS is connected. + * + * This shall only be called for unicast streams. + * + * Broadcast sinks will always be started once synchronized, and broadcast + * source streams shall be started with bt_bap_broadcast_source_start(). + * + * @param stream Stream object + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_bap_stream_start_safe(struct bt_bap_stream *stream); + +/** + * @brief Stop Audio Stream + * + * This procedure is used by a client to make a stream stop streaming. + * + * This shall only be called for unicast streams. + * Broadcast sinks cannot be stopped. + * Broadcast sources shall be stopped with bt_bap_broadcast_source_stop(). + * + * @param stream Stream object + * + * @retval 0 Success + * @retval -EINVAL The @p stream does not have an endpoint or a connection, of the stream's + * connection's role is not @p BT_HCI_ROLE_CENTRAL + * @retval -EBADMSG The state of the @p stream endpoint is not @ref BT_BAP_EP_STATE_DISABLING + * @retval -EALREADY The CIS state of the @p is not in a connected state, and thus is already + * stopping + * @retval -EBUSY The @p stream is busy with another operation + * @retval -ENOTCONN The @p stream ACL connection is not connected + * @retval -ENOMEM No memory to send request + * @retval -ENOEXEC The request was rejected by GATT + * @return 0 in case of success or negative value in case of error. + */ +int bt_bap_stream_stop_safe(struct bt_bap_stream *stream); + +/** + * @brief Release Audio Stream + * + * This procedure is used by a unicast client or unicast server to release a unicast stream. + * + * Broadcast sink streams cannot be released, but can be deleted by bt_bap_broadcast_sink_delete(). + * Broadcast source streams cannot be released, but can be deleted by + * bt_bap_broadcast_source_delete(). + * + * @param stream Stream object + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_bap_stream_release_safe(struct bt_bap_stream *stream); + +/** + * @brief Send data to Audio stream without timestamp + * + * Send data from buffer to the stream. + * + * @note Support for sending must be supported, determined by @kconfig{CONFIG_BT_AUDIO_TX}. + * + * @param stream Stream object. + * @param buf Buffer containing data to be sent. + * @param seq_num Packet Sequence number. This value shall be incremented for each call to this + * function and at least once per SDU interval for a specific channel. + * + * @return Bytes sent in case of success or negative value in case of error. + */ +int bt_bap_stream_send_safe(struct bt_bap_stream *stream, struct net_buf *buf, uint16_t seq_num); + +/** + * @brief Send data to Audio stream with timestamp + * + * Send data from buffer to the stream. + * + * @note Support for sending must be supported, determined by @kconfig{CONFIG_BT_AUDIO_TX}. + * + * @param stream Stream object. + * @param buf Buffer containing data to be sent. + * @param seq_num Packet Sequence number. This value shall be incremented for each call to this + * function and at least once per SDU interval for a specific channel. + * @param ts Timestamp of the SDU in microseconds (us). This value can be used to transmit + * multiple SDUs in the same SDU interval in a CIG or BIG. + * + * @return Bytes sent in case of success or negative value in case of error. + */ +int bt_bap_stream_send_ts_safe(struct bt_bap_stream *stream, struct net_buf *buf, uint16_t seq_num, + uint32_t ts); + +/** + * @brief Get ISO transmission timing info for a Basic Audio Profile stream + * + * Reads timing information for transmitted ISO packet on an ISO channel. + * The HCI_LE_Read_ISO_TX_Sync HCI command is used to retrieve this information from the controller. + * + * @note An SDU must have already been successfully transmitted on the ISO channel + * for this function to return successfully. + * Support for sending must be supported, determined by @kconfig{CONFIG_BT_AUDIO_TX}. + * + * @param[in] stream Stream object. + * @param[out] info Transmit info object. + * + * @retval 0 on success + * @retval -EINVAL if the stream is invalid, if the stream is not configured for sending or if it is + * not connected with a isochronous stream + * @retval Any return value from bt_iso_chan_get_tx_sync() + */ +int bt_bap_stream_get_tx_sync_safe(struct bt_bap_stream *stream, struct bt_iso_tx_info *info); + +/** + * @defgroup bt_bap_unicast_server BAP Unicast Server APIs + * @ingroup bt_bap + * @{ + */ + +/** Unicast Server callback structure */ +struct bt_bap_unicast_server_cb { + /** + * @brief Endpoint config request callback + * + * Config callback is called whenever an endpoint is requested to be + * configured + * + * @param[in] conn Connection object. + * @param[in] ep Local Audio Endpoint being configured. + * @param[in] dir Direction of the endpoint. + * @param[in] codec_cfg Codec configuration. + * @param[out] stream Pointer to stream that will be configured for the endpoint. + * @param[out] pref Pointer to a QoS preference object that shall be populated with + * values. Invalid values will reject the codec configuration request. + * @param[out] rsp Object for the ASE operation response. Only used if the return + * value is non-zero. + * + * @return 0 in case of success or negative value in case of error. + */ + int (*config)(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_audio_dir dir, + const struct bt_audio_codec_cfg *codec_cfg, struct bt_bap_stream **stream, + struct bt_bap_qos_cfg_pref *const pref, struct bt_bap_ascs_rsp *rsp); + + /** + * @brief Stream reconfig request callback + * + * Reconfig callback is called whenever an Audio Stream needs to be + * reconfigured with different codec configuration. + * + * @param[in] stream Stream object being reconfigured. + * @param[in] dir Direction of the endpoint. + * @param[in] codec_cfg Codec configuration. + * @param[out] pref Pointer to a QoS preference object that shall be populated with + * values. Invalid values will reject the codec configuration request. + * @param[out] rsp Object for the ASE operation response. Only used if the return + * value is non-zero. + * + * @return 0 in case of success or negative value in case of error. + */ + int (*reconfig)(struct bt_bap_stream *stream, enum bt_audio_dir dir, + const struct bt_audio_codec_cfg *codec_cfg, + struct bt_bap_qos_cfg_pref *const pref, struct bt_bap_ascs_rsp *rsp); + + /** + * @brief Stream QoS request callback + * + * QoS callback is called whenever an Audio Stream Quality of + * Service needs to be configured. + * + * @param[in] stream Stream object being reconfigured. + * @param[in] qos Quality of Service configuration. + * @param[out] rsp Object for the ASE operation response. Only used if the return + * value is non-zero. + * + * @return 0 in case of success or negative value in case of error. + */ + int (*qos)(struct bt_bap_stream *stream, const struct bt_bap_qos_cfg *qos, + struct bt_bap_ascs_rsp *rsp); + + /** + * @brief Stream Enable request callback + * + * Enable callback is called whenever an Audio Stream is requested to be enabled to stream. + * + * @param[in] stream Stream object being enabled. + * @param[in] meta Metadata entries. + * @param[in] meta_len Length of metadata. + * @param[out] rsp Object for the ASE operation response. Only used if the return + * value is non-zero. + * + * @return 0 in case of success or negative value in case of error. + */ + int (*enable)(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len, + struct bt_bap_ascs_rsp *rsp); + + /** + * @brief Stream Start request callback + * + * Start callback is called whenever an Audio Stream is requested to start streaming. + * + * @param[in] stream Stream object. + * @param[out] rsp Object for the ASE operation response. Only used if the return + * value is non-zero. + * + * @return 0 in case of success or negative value in case of error. + */ + int (*start)(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp); + + /** + * @brief Stream Metadata update request callback + * + * Metadata callback is called whenever an Audio Stream is requested to update its metadata. + * + * @param[in] stream Stream object. + * @param[in] meta Metadata entries. + * @param[in] meta_len Length of metadata. + * @param[out] rsp Object for the ASE operation response. Only used if the return + * value is non-zero. + * + * @return 0 in case of success or negative value in case of error. + */ + int (*metadata)(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len, + struct bt_bap_ascs_rsp *rsp); + + /** + * @brief Stream Disable request callback + * + * Disable callback is called whenever an Audio Stream is requested to disable the stream. + * + * @param[in] stream Stream object being disabled. + * @param[out] rsp Object for the ASE operation response. Only used if the return + * value is non-zero. + * + * @return 0 in case of success or negative value in case of error. + */ + int (*disable)(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp); + + /** + * @brief Stream Stop callback + * + * Stop callback is called whenever an Audio Stream is requested to stop streaming. + * + * @param[in] stream Stream object. + * @param[out] rsp Object for the ASE operation response. Only used if the return + * value is non-zero. + * + * @return 0 in case of success or negative value in case of error. + */ + int (*stop)(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp); + + /** + * @brief Stream release callback + * + * Release callback is called whenever a new Audio Stream needs to be released and thus + * deallocated. + * + * @param[in] stream Stream object. + * @param[out] rsp Object for the ASE operation response. Only used if the return + * value is non-zero. + * + * @return 0 in case of success or negative value in case of error. + */ + int (*release)(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp); +}; + +/** + * @brief Register the Unicast Server. + * + * Register the Unicast Server. Only a single Unicast Server can be registered at any one time. + * This will register ASCS in the GATT database. + * + * @param param Registration parameters for ascs. + * + * @return 0 in case of success, negative error code otherwise. + */ +int bt_bap_unicast_server_register_safe(const struct bt_bap_unicast_server_register_param *param); + +/** + * @brief Unregister the Unicast Server. + * + * Unregister the Unicast Server. + * This will unregister ASCS in the GATT database. + * Before calling this function, any callbacks registered through + * bt_bap_unicast_server_register_cb() needs to be unregistered with + * bt_bap_unicast_server_unregister_cb(). + * + * Calling this function will issue an release operation on any ASE + * in a non-idle state. + * + * @return 0 in case of success, negative error code otherwise. + */ +int bt_bap_unicast_server_unregister_safe(void); + +/** + * @brief Register unicast server callbacks. + * + * Only one callback structure can be registered, and attempting to + * registering more than one will result in an error. + * Prior to calling this function the Unicast Server needs to be + * registered with bt_bap_unicast_server_register(). + * + * @param cb Unicast server callback structure. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_bap_unicast_server_register_cb_safe(const struct bt_bap_unicast_server_cb *cb); + +/** + * @brief Unregister unicast server callbacks. + * + * May only unregister a callback structure that has previously been + * registered by bt_bap_unicast_server_register_cb(). + * + * Calling this function will issue an release operation on any ASE + * in a non-idle state. + * + * @param cb Unicast server callback structure. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_bap_unicast_server_unregister_cb_safe(const struct bt_bap_unicast_server_cb *cb); + +/** + * @typedef bt_bap_ep_func_t + * @brief The callback function called for each endpoint. + * + * @param ep The structure object with endpoint info. + * @param user_data Data to pass to the function. + */ +typedef void (*bt_bap_ep_func_t)(struct bt_bap_ep *ep, void *user_data); + +/** + * @brief Iterate through all endpoints of the given connection. + * + * @param conn Connection object + * @param func Function to call for each endpoint. + * @param user_data Data to pass to the callback function. + */ +void bt_bap_unicast_server_foreach_ep(struct bt_conn *conn, bt_bap_ep_func_t func, void *user_data); + +/** + * @brief Initialize and configure a new ASE. + * + * @param conn Connection object + * @param stream Configured stream object to be attached to the ASE + * @param codec_cfg Codec configuration + * @param qos_pref Audio Stream Quality of Service Preference + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_bap_unicast_server_config_ase(struct bt_conn *conn, struct bt_bap_stream *stream, + struct bt_audio_codec_cfg *codec_cfg, + const struct bt_bap_qos_cfg_pref *qos_pref); +int bt_bap_unicast_server_config_ase_safe(struct bt_conn *conn, struct bt_bap_stream *stream, + struct bt_audio_codec_cfg *codec_cfg, + const struct bt_bap_qos_cfg_pref *qos_pref); + +/** @} */ /* End of group bt_bap_unicast_server */ + +/** + * @defgroup bt_bap_unicast_client BAP Unicast Client APIs + * @ingroup bt_bap + * @{ + */ + +/** Parameter struct for each stream in the unicast group */ +struct bt_bap_unicast_group_stream_param { + /** Pointer to a stream object. */ + struct bt_bap_stream *stream; + + /** The QoS settings for the stream object. */ + struct bt_bap_qos_cfg *qos; +}; + +/** + * @brief Parameter struct for the unicast group functions + * + * Parameter struct for the bt_bap_unicast_group_create() and + * bt_bap_unicast_group_add_streams() functions. + */ +struct bt_bap_unicast_group_stream_pair_param { + /** Pointer to a receiving stream parameters. */ + struct bt_bap_unicast_group_stream_param *rx_param; + + /** Pointer to a transmitting stream parameters. */ + struct bt_bap_unicast_group_stream_param *tx_param; +}; + +/** Parameters for the creating unicast groups with bt_bap_unicast_group_create() */ +struct bt_bap_unicast_group_param { + /** The number of parameters in @p params */ + size_t params_count; + + /** Array of stream parameters */ + struct bt_bap_unicast_group_stream_pair_param *params; + + /** + * @brief Unicast Group packing mode. + * + * @ref BT_ISO_PACKING_SEQUENTIAL or @ref BT_ISO_PACKING_INTERLEAVED. + * + * @note This is a recommendation to the controller, which the controller may ignore. + */ + uint8_t packing; + + /** + * @brief Central to Peripheral flush timeout + * + * The flush timeout in multiples of ISO_Interval for each payload sent + * from the Central to Peripheral. + * + * Value range from @ref BT_ISO_FT_MIN to @ref BT_ISO_FT_MAX + */ + uint8_t c_to_p_ft; + + /** + * @brief Peripheral to Central flush timeout + * + * The flush timeout in multiples of ISO_Interval for each payload sent + * from the Peripheral to Central. + * + * Value range from @ref BT_ISO_FT_MIN to @ref BT_ISO_FT_MAX. + */ + uint8_t p_to_c_ft; + + /** + * @brief ISO interval + * + * Time between consecutive CIS anchor points. + * + * Value range from @ref BT_ISO_ISO_INTERVAL_MIN to @ref BT_ISO_ISO_INTERVAL_MAX. + */ + uint16_t iso_interval; +}; + +/** + * @brief Create unicast group. + * + * Create a new audio unicast group with one or more audio streams as a unicast client. + * All streams shall share the same framing. + * All streams in the same direction shall share the same interval and latency (see + * @ref bt_bap_qos_cfg). + * + * @param[in] param The unicast group create parameters. + * @param[out] unicast_group Pointer to the unicast group created. + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_bap_unicast_group_create_safe(struct bt_bap_unicast_group_param *param, + struct bt_bap_unicast_group **unicast_group); + +/** + * @brief Reconfigure unicast group. + * + * Reconfigure a unicast group with one or more audio streams as a unicast client. + * All streams shall share the same framing. + * All streams in the same direction shall share the same interval and latency (see + * @ref bt_bap_qos_cfg). + * All streams in @p param shall already belong to @p unicast_group. + * Use bt_bap_unicast_group_add_streams() to add additional streams. + * + * @param unicast_group Pointer to the unicast group created. + * @param param The unicast group reconfigure parameters. + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_bap_unicast_group_reconfig_safe(struct bt_bap_unicast_group *unicast_group, + const struct bt_bap_unicast_group_param *param); + +/** + * @brief Add streams to a unicast group as a unicast client + * + * This function can be used to add additional streams to a bt_bap_unicast_group. + * + * This can be called at any time before any of the streams in the group has been started + * (see bt_bap_stream_ops.started()). + * This can also be called after the streams have been stopped (see bt_bap_stream_ops.stopped()). + * + * Once a stream has been added to a unicast group, it cannot be removed. To remove a stream from a + * group, the group must be deleted with bt_bap_unicast_group_delete(), but this will require all + * streams in the group to be released first. + * + * @param unicast_group Pointer to the unicast group + * @param params Array of stream parameters with streams being added to the group. + * @param num_param Number of parameters in @p params. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_bap_unicast_group_add_streams_safe(struct bt_bap_unicast_group *unicast_group, + struct bt_bap_unicast_group_stream_pair_param params[], + size_t num_param); + +/** + * @brief Delete audio unicast group. + * + * Delete a audio unicast group as a client. All streams in the group shall + * be in the idle or configured state. + * + * @param unicast_group Pointer to the unicast group to delete + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_bap_unicast_group_delete_safe(struct bt_bap_unicast_group *unicast_group); + +/** Callback function for bt_bap_unicast_group_foreach_stream() + * + * @param stream The audio stream + * @param user_data User data + * + * @retval true Stop iterating. + * @retval false Continue iterating. + */ +typedef bool (*bt_bap_unicast_group_foreach_stream_func_t)(struct bt_bap_stream *stream, + void *user_data); + +/** + * @brief Iterate through all streams in a unicast group + * + * @param unicast_group The unicast group + * @param func The callback function + * @param user_data User specified data that sent to the callback function + * + * @retval 0 Success (even if no streams exists in the group). + * @retval -ECANCELED Iteration was stopped by the callback function before complete. + * @retval -EINVAL @p unicast_group or @p func were NULL. + */ +int bt_bap_unicast_group_foreach_stream_safe(struct bt_bap_unicast_group *unicast_group, + bt_bap_unicast_group_foreach_stream_func_t func, + void *user_data); + +/** Structure holding information of audio stream endpoint */ +struct bt_bap_unicast_group_info { + /** Presentation delay for sink ASEs + * + * Will be @ref BT_BAP_PD_UNSET if no sink ASEs have been QoS configured + */ + uint32_t sink_pd; + + /** Presentation delay for source ASEs + * + * Will be @ref BT_BAP_PD_UNSET if no source ASEs have been QoS configured + */ + uint32_t source_pd; +}; + +/** + * @brief Return structure holding information of unicast group + * + * @param unicast_group The unicast group object. + * @param info The structure object to be filled with the info. + * + * @retval 0 Success + * @retval -EINVAL @p unicast_group or @p info are NULL + */ +int bt_bap_unicast_group_get_info_safe(const struct bt_bap_unicast_group *unicast_group, + struct bt_bap_unicast_group_info *info); + +/** Unicast Client callback structure */ +struct bt_bap_unicast_client_cb { + /** + * @brief Remote Unicast Server Audio Locations + * + * This callback is called whenever the audio locations is read from + * the server or otherwise notified to the client. + * + * @param conn Connection to the remote unicast server. + * @param dir Direction of the location. + * @param loc The location bitfield value. + * + * @return 0 in case of success or negative value in case of error. + */ + void (*location)(struct bt_conn *conn, enum bt_audio_dir dir, enum bt_audio_location loc); + + /** + * @brief Remote Unicast Server Available Contexts + * + * This callback is called whenever the available contexts are read + * from the server or otherwise notified to the client. + * + * @param conn Connection to the remote unicast server. + * @param snk_ctx The sink context bitfield value. + * @param src_ctx The source context bitfield value. + * + * @return 0 in case of success or negative value in case of error. + */ + void (*available_contexts)(struct bt_conn *conn, enum bt_audio_context snk_ctx, + enum bt_audio_context src_ctx); + + /** + * @brief Callback function for bt_bap_stream_config() and bt_bap_stream_reconfig(). + * + * Called when the codec configure operation is completed on the server. + * + * @param stream Stream the operation was performed on. + * @param rsp_code Response code. + * @param reason Reason code. + */ + void (*config)(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code, + enum bt_bap_ascs_reason reason); + + /** + * @brief Callback function for bt_bap_stream_qos(). + * + * Called when the QoS configure operation is completed on the server. + * This will be called for each stream in the group that was being QoS + * configured. + * + * @param stream Stream the operation was performed on. May be NULL if there is no stream + * associated with the ASE ID sent by the server. + * @param rsp_code Response code. + * @param reason Reason code. + */ + void (*qos)(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code, + enum bt_bap_ascs_reason reason); + + /** + * @brief Callback function for bt_bap_stream_enable(). + * + * Called when the enable operation is completed on the server. + * + * @param stream Stream the operation was performed on. May be NULL if there is no stream + * associated with the ASE ID sent by the server. + * @param rsp_code Response code. + * @param reason Reason code. + */ + void (*enable)(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code, + enum bt_bap_ascs_reason reason); + + /** + * @brief Callback function for bt_bap_stream_start(). + * + * Called when the start operation is completed on the server. This will + * only be called if the stream supplied to bt_bap_stream_start() is + * for a @ref BT_AUDIO_DIR_SOURCE endpoint. + * + * @param stream Stream the operation was performed on. May be NULL if there is no stream + * associated with the ASE ID sent by the server. + * @param rsp_code Response code. + * @param reason Reason code. + */ + void (*start)(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code, + enum bt_bap_ascs_reason reason); + + /** + * @brief Callback function for bt_bap_stream_stop(). + * + * Called when the stop operation is completed on the server. This will + * only be called if the stream supplied to bt_bap_stream_stop() is + * for a @ref BT_AUDIO_DIR_SOURCE endpoint. + * + * @param stream Stream the operation was performed on. May be NULL if there is no stream + * associated with the ASE ID sent by the server. + * @param rsp_code Response code. + * @param reason Reason code. + */ + void (*stop)(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code, + enum bt_bap_ascs_reason reason); + + /** + * @brief Callback function for bt_bap_stream_disable(). + * + * Called when the disable operation is completed on the server. + * + * @param stream Stream the operation was performed on. May be NULL if there is no stream + * associated with the ASE ID sent by the server. + * @param rsp_code Response code. + * @param reason Reason code. + */ + void (*disable)(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code, + enum bt_bap_ascs_reason reason); + + /** + * @brief Callback function for bt_bap_stream_metadata(). + * + * Called when the metadata operation is completed on the server. + * + * @param stream Stream the operation was performed on. May be NULL if there is no stream + * associated with the ASE ID sent by the server. + * @param rsp_code Response code. + * @param reason Reason code. + */ + void (*metadata)(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code, + enum bt_bap_ascs_reason reason); + + /** + * @brief Callback function for bt_bap_stream_release(). + * + * Called when the release operation is completed on the server. + * + * @param stream Stream the operation was performed on. May be NULL if there is no stream + * associated with the ASE ID sent by the server. + * @param rsp_code Response code. + * @param reason Reason code. + */ + void (*release)(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code, + enum bt_bap_ascs_reason reason); + + /** + * @brief Remote Published Audio Capability (PAC) record discovered + * + * Called when a PAC record has been discovered as part of the discovery procedure. + * + * The @p codec is only valid while in the callback, so the values must be stored by the + * receiver if future use is wanted. + * + * @param conn Connection to the remote unicast server. + * @param dir The type of remote endpoints and capabilities discovered. + * @param codec_cap Remote capabilities. + * + * If discovery procedure has complete both @p codec and @p ep are set to NULL. + */ + void (*pac_record)(struct bt_conn *conn, enum bt_audio_dir dir, + const struct bt_audio_codec_cap *codec_cap); + + /** + * @brief Remote Audio Stream Endpoint (ASE) discovered + * + * Called when an ASE has been discovered as part of the discovery procedure. + * + * @param conn Connection to the remote unicast server. + * @param dir The type of remote endpoints and capabilities discovered. + * @param ep Remote endpoint. + * + * If discovery procedure has complete both @p codec and @p ep are set to NULL. + */ + void (*endpoint)(struct bt_conn *conn, enum bt_audio_dir dir, struct bt_bap_ep *ep); + + /** + * @brief BAP discovery callback function. + * + * If discovery procedure has completed @p ep is set to NULL and @p err is 0. + * + * @param conn Connection to the remote unicast server. + * @param err Error value. 0 on success, GATT error on positive value or errno on + * negative value. + * @param dir The type of remote endpoints and capabilities discovered. + * + * If discovery procedure has complete both @p codec and @p ep are set to NULL. + */ + void (*discover)(struct bt_conn *conn, int err, enum bt_audio_dir dir); + + /** @cond INTERNAL_HIDDEN */ + /** Internally used field for list handling */ + sys_snode_t _node; + /** @endcond */ +}; + +/** + * @brief Register unicast client callbacks. + * + * @param cb Unicast client callback structure to register. + * + * @retval 0 Success + * @retval -EINVAL @p cb is NULL. + * @retval -EEXIST @p cb is already registered. + */ +int bt_bap_unicast_client_register_cb_safe(struct bt_bap_unicast_client_cb *cb); + +/** + * @brief Unregister unicast client callbacks. + * + * @param cb Unicast client callback structure to unregister. + * + * @retval 0 Success + * @retval -EINVAL @p cb is NULL or @p cb was not registered + */ +int bt_bap_unicast_client_unregister_cb_safe(struct bt_bap_unicast_client_cb *cb); + +/** + * @brief Discover remote capabilities and endpoints + * + * This procedure is used by a client to discover remote capabilities and + * endpoints and notifies via params callback. + * + * @param conn Connection object + * @param dir The type of remote endpoints and capabilities to discover. + */ +int bt_bap_unicast_client_discover(struct bt_conn *conn, enum bt_audio_dir dir); +int bt_bap_unicast_client_discover_safe(struct bt_conn *conn, enum bt_audio_dir dir); + +/** @} */ /* End of group bt_bap_unicast_client */ +/** + * @brief BAP Broadcast APIs + * @defgroup bt_bap_broadcast BAP Broadcast APIs + * @ingroup bt_bap + * @{ + */ + +/** @brief Abstract Broadcast Audio Source Endpoint (BASE) subgroup structure. */ +struct bt_bap_base_subgroup; +/** @brief Abstract Broadcast Audio Source Endpoint (BASE) structure. */ +struct bt_bap_base; + +/** Codec ID structure for a Broadcast Audio Source Endpoint (BASE) */ +struct bt_bap_base_codec_id { + /** Codec ID */ + uint8_t id; + /** Codec Company ID */ + uint16_t cid; + /** Codec Company Vendor ID */ + uint16_t vid; +}; + +/** BIS structure for each BIS in a Broadcast Audio Source Endpoint (BASE) subgroup */ +struct bt_bap_base_subgroup_bis { + /** Unique index of the BIS */ + uint8_t index; + /** Codec Specific Data length. */ + uint8_t data_len; + /** Codec Specific Data */ + uint8_t *data; +}; + +/** + * @brief Generate a pointer to a BASE from periodic advertising data + * + * @param ad The periodic advertising data + * + * @retval NULL if the data does not contain a BASE + * @retval Pointer to a bt_bap_base structure + */ +const struct bt_bap_base *bt_bap_base_get_base_from_ad(const struct bt_data *ad); + +/** + * @brief Get the size of a BASE + * + * @param base The BASE pointer + * + * @retval -EINVAL if arguments are invalid + * @retval The size of the BASE + */ +int bt_bap_base_get_size(const struct bt_bap_base *base); + +/** + * @brief Get the presentation delay value of a BASE + * + * @param base The BASE pointer + * + * @retval -EINVAL if arguments are invalid + * @retval The 24-bit presentation delay value + */ +int bt_bap_base_get_pres_delay(const struct bt_bap_base *base); + +/** + * @brief Get the subgroup count of a BASE + * + * @param base The BASE pointer + * + * @retval -EINVAL if arguments are invalid + * @retval The 8-bit subgroup count value + */ +int bt_bap_base_get_subgroup_count(const struct bt_bap_base *base); + +/** + * @brief Get all BIS indexes of a BASE + * + * @param[in] base The BASE pointer + * @param[out] bis_indexes 32-bit BIS index bitfield that will be populated + * + * @retval -EINVAL if arguments are invalid + * @retval 0 on success + */ +int bt_bap_base_get_bis_indexes(const struct bt_bap_base *base, uint32_t *bis_indexes); + +/** + * @brief Iterate on all subgroups in the BASE + * + * @param base The BASE pointer + * @param func Callback function. Return true to continue iterating, or false to stop. + * @param user_data Userdata supplied to @p func + * + * @retval -EINVAL if arguments are invalid + * @retval -ECANCELED if iterating over the subgroups stopped prematurely by @p func + * @retval 0 if all subgroups were iterated + */ +int bt_bap_base_foreach_subgroup(const struct bt_bap_base *base, + bool (*func)(const struct bt_bap_base_subgroup *subgroup, + void *user_data), + void *user_data); + +/** + * @brief Get the codec ID of a subgroup + * + * @param[in] subgroup The subgroup pointer + * @param[out] codec_id Pointer to the struct where the results are placed + * + * @retval -EINVAL if arguments are invalid + * @retval 0 on success + */ +int bt_bap_base_get_subgroup_codec_id(const struct bt_bap_base_subgroup *subgroup, + struct bt_bap_base_codec_id *codec_id); + +/** + * @brief Get the codec configuration data of a subgroup + * + * @param[in] subgroup The subgroup pointer + * @param[out] data Pointer that will point to the resulting codec configuration data + * + * @retval -EINVAL if arguments are invalid + * @retval 0 on success + */ +int bt_bap_base_get_subgroup_codec_data(const struct bt_bap_base_subgroup *subgroup, + uint8_t **data); + +/** + * @brief Get the codec metadata of a subgroup + * + * @param[in] subgroup The subgroup pointer + * @param[out] meta Pointer that will point to the resulting codec metadata + * + * @retval -EINVAL if arguments are invalid + * @retval 0 on success + */ +int bt_bap_base_get_subgroup_codec_meta(const struct bt_bap_base_subgroup *subgroup, + uint8_t **meta); + +/** + * @brief Store subgroup codec data in a @ref bt_audio_codec_cfg + * + * @param[in] subgroup The subgroup pointer + * @param[out] codec_cfg Pointer to the struct where the results are placed + * + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the @p codec_cfg cannot store the @p subgroup codec data + * @retval 0 on success + */ +int bt_bap_base_subgroup_codec_to_codec_cfg(const struct bt_bap_base_subgroup *subgroup, + struct bt_audio_codec_cfg *codec_cfg); + +/** + * @brief Get the BIS count of a subgroup + * + * @param subgroup The subgroup pointer + * + * @retval -EINVAL if arguments are invalid + * @retval The 8-bit BIS count value + */ +int bt_bap_base_get_subgroup_bis_count(const struct bt_bap_base_subgroup *subgroup); + +/** + * @brief Get all BIS indexes of a subgroup + * + * @param[in] subgroup The subgroup pointer + * @param[out] bis_indexes 32-bit BIS index bitfield that will be populated + * + * @retval -EINVAL if arguments are invalid + * @retval 0 on success + */ +int bt_bap_base_subgroup_get_bis_indexes(const struct bt_bap_base_subgroup *subgroup, + uint32_t *bis_indexes); + +/** + * @brief Iterate on all BIS in the subgroup + * + * @param subgroup The subgroup pointer + * @param func Callback function. Return true to continue iterating, or false to stop. + * @param user_data Userdata supplied to @p func + * + * @retval -EINVAL if arguments are invalid + * @retval -ECANCELED if iterating over the subgroups stopped prematurely by @p func + * @retval 0 if all BIS were iterated + */ +int bt_bap_base_subgroup_foreach_bis(const struct bt_bap_base_subgroup *subgroup, + bool (*func)(const struct bt_bap_base_subgroup_bis *bis, + void *user_data), + void *user_data); + +/** + * @brief Store BIS codec configuration data in a @ref bt_audio_codec_cfg + * + * This only sets the @ref bt_audio_codec_cfg data and @ref bt_audio_codec_cfg data_len, but is + * useful to use the BIS codec configuration data with the bt_audio_codec_cfg_* functions. + * + * @param[in] bis The BIS pointer + * @param[out] codec_cfg Pointer to the struct where the results are placed + * + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the @p codec_cfg cannot store the @p subgroup codec data + * @retval 0 on success + */ +int bt_bap_base_subgroup_bis_codec_to_codec_cfg(const struct bt_bap_base_subgroup_bis *bis, + struct bt_audio_codec_cfg *codec_cfg); + +/** @} */ /* End of group bt_bap_broadcast */ + +/** + * @brief BAP Broadcast Source APIs + * @defgroup bt_bap_broadcast_source BAP Broadcast Source APIs + * @ingroup bt_bap_broadcast + * @{ + */ + +/** + * @brief Struct to hold the Broadcast Source callbacks + * + * These can be registered for usage with bt_bap_broadcast_source_register_cb(). + */ +struct bt_bap_broadcast_source_cb { + /** + * @brief The Broadcast Source has started and all of the streams are ready for audio data + * + * @param source The started Broadcast Source + */ + void (*started)(struct bt_bap_broadcast_source *source); + + /** + * @brief The Broadcast Source has stopped and none of the streams are ready for audio data + * + * @param source The stopped Broadcast Source + * @param reason The reason why the Broadcast Source stopped (see the BT_HCI_ERR_* values) + */ + void (*stopped)(struct bt_bap_broadcast_source *source, uint8_t reason); + + /** @cond INTERNAL_HIDDEN */ + /** Internally used field for list handling */ + sys_snode_t _node; + /** @endcond */ +}; + +/** + * @brief Registers callbacks for Broadcast Sources + * + * @param cb Pointer to the callback structure. + * + * @retval 0 on success + * @retval -EINVAL if @p cb is NULL + * @retval -EEXIST if @p cb is already registered + */ +int bt_bap_broadcast_source_register_cb_safe(struct bt_bap_broadcast_source_cb *cb); + +/** + * @brief Unregisters callbacks for Broadcast Sources + * + * @param cb Pointer to the callback structure. + * + * @retval 0 on success + * @retval -EINVAL if @p cb is NULL + * @retval -ENOENT if @p cb is not registered + */ +int bt_bap_broadcast_source_unregister_cb_safe(struct bt_bap_broadcast_source_cb *cb); + +/** Broadcast Source stream parameters */ +struct bt_bap_broadcast_source_stream_param { + /** Audio stream */ + struct bt_bap_stream *stream; + + /** + * @brief The number of elements in the @p data array. + * + * The BIS specific data may be omitted and this set to 0. + */ + size_t data_len; + + /** BIS Codec Specific Configuration */ + uint8_t *data; +}; + +/** Broadcast Source subgroup parameters*/ +struct bt_bap_broadcast_source_subgroup_param { + /** The number of parameters in @p stream_params */ + size_t params_count; + + /** Array of stream parameters */ + struct bt_bap_broadcast_source_stream_param *params; + + /** Subgroup Codec configuration. */ + struct bt_audio_codec_cfg *codec_cfg; +}; + +/** Broadcast Source create parameters */ +struct bt_bap_broadcast_source_param { + /** The number of parameters in @p subgroup_params */ + size_t params_count; + + /** Array of stream parameters */ + struct bt_bap_broadcast_source_subgroup_param *params; + + /** Quality of Service configuration. */ + struct bt_bap_qos_cfg *qos; + + /** + * @brief Broadcast Source packing mode. + * + * @ref BT_ISO_PACKING_SEQUENTIAL or @ref BT_ISO_PACKING_INTERLEAVED. + * + * @note This is a recommendation to the controller, which the controller may ignore. + */ + uint8_t packing; + + /** Whether or not to encrypt the streams. */ + bool encryption; + + /** + * @brief Broadcast code + * + * If the value is a string or a the value is less than 16 octets, + * the remaining octets shall be 0. + * + * Example: + * The string "Broadcast Code" shall be + * [42 72 6F 61 64 63 61 73 74 20 43 6F 64 65 00 00] + */ + uint8_t broadcast_code[BT_ISO_BROADCAST_CODE_SIZE]; + + /** + * @brief Immediate Repetition Count + * + * The number of times the scheduled payloads are transmitted in a given event. + * + * Value range from @ref BT_ISO_IRC_MIN to @ref BT_ISO_IRC_MAX. + */ + uint8_t irc; + + /** + * @brief Pre-transmission offset + * + * Offset used for pre-transmissions. + * + * Value range from @ref BT_ISO_PTO_MIN to @ref BT_ISO_PTO_MAX. + */ + uint8_t pto; + + /** + * @brief ISO interval + * + * Time between consecutive BIS anchor points. + * + * Value range from @ref BT_ISO_ISO_INTERVAL_MIN to @ref BT_ISO_ISO_INTERVAL_MAX. + */ + uint16_t iso_interval; +}; + +/** + * @brief Create audio broadcast source. + * + * Create a new audio broadcast source with one or more audio streams. + * + * The broadcast source will be visible for scanners once this has been called, + * and the device will advertise audio announcements. + * + * No audio data can be sent until bt_bap_broadcast_source_start() has been called and no audio + * information (BIGInfo) will be visible to scanners (see @ref bt_le_per_adv_sync_cb). + * + * @param[in] param Pointer to parameters used to create the broadcast source. + * @param[out] source Pointer to the broadcast source created + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_bap_broadcast_source_create_safe(struct bt_bap_broadcast_source_param *param, + struct bt_bap_broadcast_source **source); + +/** + * @brief Reconfigure audio broadcast source. + * + * Reconfigure an audio broadcast source with a new codec and codec quality of + * service parameters. This can only be done when the source is stopped. + * + * Since this may modify the Broadcast Audio Source Endpoint (BASE), + * bt_bap_broadcast_source_get_base() should be called after this to get the new BASE information. + * + * If the @p param.params_count is smaller than the number of subgroups that have been created in + * the Broadcast Source, only the first @p param.params_count subgroups are updated. If a stream + * exist in a subgroup not part of @p param, then that stream is left as is (i.e. it is not removed; + * the only way to remove a stream from a Broadcast Source is to recreate the Broadcast Source). + * + * @param source Pointer to the broadcast source + * @param param Pointer to parameters used to reconfigure the broadcast source. + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_bap_broadcast_source_reconfig_safe(struct bt_bap_broadcast_source *source, + struct bt_bap_broadcast_source_param *param); + +/** + * @brief Modify the metadata of an audio broadcast source. + * + * Modify the metadata an audio broadcast source. This can only be done when the source is started. + * To update the metadata in the stopped state, use bt_bap_broadcast_source_reconfig(). + * + * @param source Pointer to the broadcast source. + * @param meta Metadata. + * @param meta_len Length of metadata. + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_bap_broadcast_source_update_metadata_safe(struct bt_bap_broadcast_source *source, + const uint8_t meta[], size_t meta_len); + +/** + * @brief Start audio broadcast source. + * + * Start an audio broadcast source with one or more audio streams. + * The broadcast source will start advertising BIGInfo, and audio data can be streamed. + * + * @param source Pointer to the broadcast source + * @param adv Pointer to an extended advertising set with periodic advertising configured. + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_bap_broadcast_source_start(struct bt_bap_broadcast_source *source, + struct bt_le_ext_adv *adv); +int bt_bap_broadcast_source_start_safe(struct bt_bap_broadcast_source *source, + struct bt_le_ext_adv *adv); + +/** + * @brief Stop audio broadcast source. + * + * Stop an audio broadcast source. + * The broadcast source will stop advertising BIGInfo, and audio data can no longer be streamed. + * + * @param source Pointer to the broadcast source + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_bap_broadcast_source_stop_safe(struct bt_bap_broadcast_source *source); + +/** + * @brief Delete audio broadcast source. + * + * Delete an audio broadcast source. + * The broadcast source will stop advertising entirely, and the source can no longer be used. + * + * @param source Pointer to the broadcast source + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_bap_broadcast_source_delete_safe(struct bt_bap_broadcast_source *source); + +/** + * @brief Get the Broadcast Audio Stream Endpoint of a broadcast source + * + * This will encode the BASE of a broadcast source into a buffer, that can be used for + * advertisement. The encoded BASE will thus be encoded as little-endian. The BASE shall be put into + * the periodic advertising data (see bt_le_per_adv_set_data()). + * + * See table 3.15 in the Basic Audio Profile v1.0.1 for the structure. + * + * @param source Pointer to the broadcast source. + * @param base_buf Pointer to a buffer where the BASE will be inserted. + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_bap_broadcast_source_get_base_safe(struct bt_bap_broadcast_source *source, + struct net_buf_simple *base_buf); + +/** + * @brief Callback function for bt_bap_broadcast_source_foreach_stream() + * + * @param stream The audio stream + * @param user_data User data + * + * @retval true Stop iterating. + * @retval false Continue iterating. + */ +typedef bool (*bt_bap_broadcast_source_foreach_stream_func_t)(struct bt_bap_stream *stream, + void *user_data); + +/** + * @brief Iterate through all streams in a broadcast source + * + * @param source The broadcast source + * @param func The callback function + * @param user_data User specified data that is sent to the callback function + * + * @retval 0 Success (even if no streams exists in the broadcast source). + * @retval -ECANCELED The @p func returned true. + * @retval -EINVAL @p source or @p func were NULL. + */ +int bt_bap_broadcast_source_foreach_stream_safe(struct bt_bap_broadcast_source *source, + bt_bap_broadcast_source_foreach_stream_func_t func, + void *user_data); +/** @} */ /* End of bt_bap_broadcast_source */ + +/** + * @brief BAP Broadcast Sink APIs + * @defgroup bt_bap_broadcast_sink BAP Broadcast Sink APIs + * @ingroup bt_bap_broadcast + * @{ + */ + +/** Broadcast Audio Sink callback structure */ +struct bt_bap_broadcast_sink_cb { + /** + * @brief Broadcast Audio Source Endpoint (BASE) received + * + * Callback for when we receive a BASE from a broadcaster after + * syncing to the broadcaster's periodic advertising. + * + * @param sink Pointer to the sink structure. + * @param base Broadcast Audio Source Endpoint (BASE). + * @param base_size Size of the @p base + */ + void (*base_recv)(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base, + size_t base_size); + + /** + * @brief Broadcast sink is syncable + * + * Called whenever a broadcast sink is not synchronized to audio, but the audio is + * synchronizable. This is inferred when a BIGInfo report is received. + * + * Once this callback has been called, it is possible to call + * bt_bap_broadcast_sink_sync() to synchronize to the audio stream(s). + * + * @param sink Pointer to the sink structure. + * @param biginfo The BIGInfo report. + */ + void (*syncable)(struct bt_bap_broadcast_sink *sink, const struct bt_iso_biginfo *biginfo); + + /** + * @brief The Broadcast Sink has started and audio data may be received from all of the + * streams + * + * @param sink The started Broadcast Sink + */ + void (*started)(struct bt_bap_broadcast_sink *sink); + + /** + * @brief The Broadcast Sink has stopped and none of the streams will receive audio data + * + * @param sink The stopped Broadcast Sink + * @param reason The reason why the Broadcast Sink stopped (see the BT_HCI_ERR_* values) + */ + void (*stopped)(struct bt_bap_broadcast_sink *sink, uint8_t reason); + + /** @cond INTERNAL_HIDDEN */ + /** Internally used list node */ + sys_snode_t _node; + /** @endcond */ +}; + +/** + * @brief Register Broadcast sink callbacks + * + * It is possible to register multiple struct of callbacks, but a single struct can only be + * registered once. + * Registering the same callback multiple times is undefined behavior and may break the stack. + * + * @param cb Broadcast sink callback structure. + * + * @retval 0 on success + * @retval -EINVAL if @p cb is NULL + * @retval -EALREADY if @p cb was already registered + */ +int bt_bap_broadcast_sink_register_cb_safe(struct bt_bap_broadcast_sink_cb *cb); + +/** + * @brief Create a Broadcast Sink from a periodic advertising sync + * + * This should only be done after verifying that the periodic advertising sync + * is from a Broadcast Source. + * + * The created Broadcast Sink will need to be supplied to + * bt_bap_broadcast_sink_sync() in order to synchronize to the broadcast audio. + * + * bt_bap_broadcast_sink_cb.pa_synced() will be called with the Broadcast + * Sink object created if this is successful. + * + * @param pa_sync Pointer to the periodic advertising sync object. + * @param broadcast_id 24-bit broadcast ID. + * @param[out] sink Pointer to the Broadcast Sink created. + * + * @return 0 in case of success or errno value in case of error. + */ +int bt_bap_broadcast_sink_create_safe(struct bt_le_per_adv_sync *pa_sync, uint32_t broadcast_id, + struct bt_bap_broadcast_sink **sink); + +/** + * @brief Sync to a broadcaster's audio + * + * @param sink Pointer to the sink object from the base_recv callback. + * @param indexes_bitfield Bitfield of the BIS index to sync to. To sync to e.g. BIS index 1 and + * 2, this should have the value of BIT(1) | BIT(2). + * @param streams Stream object pointers to be used for the receiver. If multiple BIS + * indexes shall be synchronized, multiple streams shall be provided. + * @param broadcast_code The 16-octet broadcast code. Shall be supplied if the broadcast is + * encrypted (see @ref bt_bap_broadcast_sink_cb.syncable). + * If the value is a string or a the value is less + * than 16 octets, the remaining octets shall be 0. + * + * Example: + * The string "Broadcast Code" shall be + * [42 72 6F 61 64 63 61 73 74 20 43 6F 64 65 00 00] + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_bap_broadcast_sink_sync_safe(struct bt_bap_broadcast_sink *sink, uint32_t indexes_bitfield, + struct bt_bap_stream *streams[], + const uint8_t broadcast_code[BT_ISO_BROADCAST_CODE_SIZE]); + +/** + * @brief Stop audio broadcast sink. + * + * Stop an audio broadcast sink. + * The broadcast sink will stop receiving BIGInfo, and audio data can no longer be streamed. + * + * @param sink Pointer to the broadcast sink + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_bap_broadcast_sink_stop_safe(struct bt_bap_broadcast_sink *sink); + +/** + * @brief Release a broadcast sink + * + * Once a broadcast sink has been allocated after the pa_synced callback, it can be deleted using + * this function. If the sink has synchronized to any broadcast audio streams, these must first be + * stopped using bt_bap_stream_stop. + * + * @param sink Pointer to the sink object to delete. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_bap_broadcast_sink_delete_safe(struct bt_bap_broadcast_sink *sink); + +/** @} */ /* End of group bt_bap_broadcast_sink */ + +/** + * @brief Register the Basic Audio Profile Scan Delegator and BASS. + * + * Register the scan deligator and Broadcast Audio Scan Service (BASS) + * dynamically at runtime. + * + * Only one set of callbacks can be registered at any one time, and calling this function multiple + * times will override any previously registered callbacks. + * + * @param cb Pointer to the callback struct + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_bap_scan_delegator_register_safe(struct bt_bap_scan_delegator_cb *cb); + +/** + * @brief unregister the Basic Audio Profile Scan Delegator and BASS. + * + * Unregister the scan deligator and Broadcast Audio Scan Service (BASS) + * dynamically at runtime. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_bap_scan_delegator_unregister_safe(void); + +/** + * @brief Set the periodic advertising sync state to syncing + * + * Set the periodic advertising sync state for a receive state to syncing, + * notifying Broadcast Assistants. + * + * @param src_id The source id used to identify the receive state. + * @param pa_state The Periodic Advertising sync state to set. + * + * @return int Error value. 0 on success, errno on fail. + */ +int bt_bap_scan_delegator_set_pa_state_safe(uint8_t src_id, + enum bt_bap_pa_state pa_state); + +/** + * @brief Set the sync state of a receive state in the server + * + * @param src_id The source id used to identify the receive state. + * @param bis_synced Array of bitfields to set the BIS sync state for each + * subgroup. + * @return int Error value. 0 on success, ERRNO on fail. + */ +int bt_bap_scan_delegator_set_bis_sync_state_safe(uint8_t src_id, + uint32_t bis_synced[CONFIG_BT_BAP_BASS_MAX_SUBGROUPS]); + +/** Parameters for bt_bap_scan_delegator_add_src() */ +struct bt_bap_scan_delegator_add_src_param { + /** Periodic Advertiser Address */ + bt_addr_le_t addr; + + /** Advertiser SID */ + uint8_t sid; + + /** + * @brief Periodic Advertising sync state + * + * This will typically be either @ref BT_BAP_PA_STATE_NOT_SYNCED or + * @ref BT_BAP_PA_STATE_SYNCED. + */ + enum bt_bap_pa_state pa_state; + + /** The broadcast isochronous group encryption state */ + enum bt_bap_big_enc_state encrypt_state; + + /** The 24-bit broadcast ID */ + uint32_t broadcast_id; + + /** Number of subgroups */ + uint8_t num_subgroups; + + /** Subgroup specific information */ + struct bt_bap_bass_subgroup *subgroups; +}; + +/** + * @brief Add a receive state source locally + * + * This will notify any connected clients about the new source. This allows them + * to modify and even remove it. + * + * If @kconfig{CONFIG_BT_BAP_BROADCAST_SINK} is enabled, any Broadcast Sink + * sources are autonomously added. + * + * @param param The parameters for adding the new source + * + * @return int errno on failure, or source ID on success. + */ +int bt_bap_scan_delegator_add_src_safe(const struct bt_bap_scan_delegator_add_src_param *param); + +/** Parameters for bt_bap_scan_delegator_mod_src() */ +struct bt_bap_scan_delegator_mod_src_param { + /** The periodic adverting sync */ + uint8_t src_id; + + /** The broadcast isochronous group encryption state */ + enum bt_bap_big_enc_state encrypt_state; + + /** The 24-bit broadcast ID */ + uint32_t broadcast_id; + + /** Number of subgroups */ + uint8_t num_subgroups; + + /** + * @brief Subgroup specific information + * + * If a subgroup's metadata_len is set to 0, the existing metadata + * for the subgroup will remain unchanged + */ + struct bt_bap_bass_subgroup *subgroups; +}; + +/** + * @brief Add a receive state source locally + * + * This will notify any connected clients about the new source. This allows them + * to modify and even remove it. + * + * If @kconfig{CONFIG_BT_BAP_BROADCAST_SINK} is enabled, any Broadcast Sink + * sources are autonomously modified. + * + * @param param The parameters for adding the new source + * + * @return int errno on failure, or source ID on success. + */ +int bt_bap_scan_delegator_mod_src_safe(const struct bt_bap_scan_delegator_mod_src_param *param); + +/** + * @brief Remove a receive state source + * + * This will remove the receive state. If the receive state periodic advertising + * is synced, bt_bap_scan_delegator_cb.pa_sync_term_req() will be called. + * + * If @kconfig{CONFIG_BT_BAP_BROADCAST_SINK} is enabled, any Broadcast Sink + * sources are autonomously removed. + * + * @param src_id The source ID to remove + * + * @return int Error value. 0 on success, errno on fail. + */ +int bt_bap_scan_delegator_rem_src_safe(uint8_t src_id); + +/** Callback function for Scan Delegator receive state search functions + * + * @param recv_state The receive state. + * @param user_data User data. + * + * @retval true to stop iterating. If this is used in the context of + * bt_bap_scan_delegator_find_state(), the recv_state will be returned by + * bt_bap_scan_delegator_find_state() + * @retval false to continue iterating + */ +typedef bool (*bt_bap_scan_delegator_state_func_t)( + const struct bt_bap_scan_delegator_recv_state *recv_state, void *user_data); + +/** + * @brief Iterate through all existing receive states + * + * @param func The callback function + * @param user_data User specified data that sent to the callback function + */ +void bt_bap_scan_delegator_foreach_state_safe(bt_bap_scan_delegator_state_func_t func, + void *user_data); + +/** + * @brief Find and return a receive state based on a compare function + * + * @param func The compare callback function + * @param user_data User specified data that sent to the callback function + * + * @return The first receive state where the @p func returned true, or NULL + */ +const struct bt_bap_scan_delegator_recv_state *bt_bap_scan_delegator_find_state_safe( + bt_bap_scan_delegator_state_func_t func, void *user_data); + +/******************************** CLIENT API ********************************/ + +/** + * @brief Callback function for writes. + * + * @param conn The connection to the peer device. + * @param err Error value. 0 on success, GATT error on fail. + */ +typedef void (*bt_bap_broadcast_assistant_write_cb)(struct bt_conn *conn, + int err); + +/** + * @brief Struct to hold the Basic Audio Profile Broadcast Assistant callbacks + * + * These can be registered for usage with bt_bap_broadcast_assistant_register_cb(). + */ +struct bt_bap_broadcast_assistant_cb { + /** + * @brief Callback function for bt_bap_broadcast_assistant_discover. + * + * @param conn The connection that was used to discover + * Broadcast Audio Scan Service. + * @param err Error value. 0 on success, + * GATT error or ERRNO on fail. + * @param recv_state_count Number of receive states on the server. + */ + void (*discover)(struct bt_conn *conn, int err, + uint8_t recv_state_count); + + /** + * @brief Callback function for Broadcast Audio Scan Service client scan results + * + * Called when the scanner finds an advertiser that advertises the + * BT_UUID_BROADCAST_AUDIO UUID. + * + * @param info Advertiser information. + * @param broadcast_id 24-bit broadcast ID. + */ + void (*scan)(const struct bt_le_scan_recv_info *info, + uint32_t broadcast_id); + + /** + * @brief Callback function for when a receive state is read or updated + * + * Called whenever a receive state is read or updated. + * + * @param conn The connection to the Broadcast Audio Scan Service server. + * @param err Error value. 0 on success, GATT error on fail. + * @param state The receive state or NULL if the receive state is empty. + */ + void (*recv_state)(struct bt_conn *conn, int err, + const struct bt_bap_scan_delegator_recv_state *state); + + /** + * @brief Callback function for when a receive state is removed. + * + * @param conn The connection to the Broadcast Audio Scan Service server. + * @param src_id The receive state. + */ + void (*recv_state_removed)(struct bt_conn *conn, uint8_t src_id); + + /** + * @brief Callback function for bt_bap_broadcast_assistant_scan_start(). + * + * @param conn The connection to the peer device. + * @param err Error value. 0 on success, GATT error on fail. + */ + void (*scan_start)(struct bt_conn *conn, int err); + + /** + * @brief Callback function for bt_bap_broadcast_assistant_scan_stop(). + * + * @param conn The connection to the peer device. + * @param err Error value. 0 on success, GATT error on fail. + */ + void (*scan_stop)(struct bt_conn *conn, int err); + + /** + * @brief Callback function for bt_bap_broadcast_assistant_add_src(). + * + * @param conn The connection to the peer device. + * @param err Error value. 0 on success, GATT error on fail. + */ + void (*add_src)(struct bt_conn *conn, int err); + + /** + * @brief Callback function for bt_bap_broadcast_assistant_mod_src(). + * + * @param conn The connection to the peer device. + * @param err Error value. 0 on success, GATT error on fail. + */ + void (*mod_src)(struct bt_conn *conn, int err); + + /** + * @brief Callback function for bt_bap_broadcast_assistant_set_broadcast_code(). + * + * @param conn The connection to the peer device. + * @param err Error value. 0 on success, GATT error on fail. + */ + void (*broadcast_code)(struct bt_conn *conn, int err); + + /** + * @brief Callback function for bt_bap_broadcast_assistant_rem_src(). + * + * @param conn The connection to the peer device. + * @param err Error value. 0 on success, GATT error on fail. + */ + void (*rem_src)(struct bt_conn *conn, int err); + + /** @cond INTERNAL_HIDDEN */ + /** Internally used list node */ + sys_snode_t _node; + /** @endcond */ +}; + +/** + * @brief Discover Broadcast Audio Scan Service on the server. + * + * Warning: Only one connection can be active at any time; discovering for a + * new connection, will delete all previous data. + * + * @param conn The connection + * + * @retval 0 Success + * @retval -EINVAL @p conn is NULL + * @retval -EBUSY Another operation is already in progress for this @p conn + * @retval -ENOTCONN @p conn is not connected + * @retval -ENOMEM Could not allocated memory for the request + * @retval -ENOEXEC Unexpected GATT error + */ +int bt_bap_broadcast_assistant_discover(struct bt_conn *conn); +int bt_bap_broadcast_assistant_discover_safe(struct bt_conn *conn); + +/** + * @brief Scan start for BISes for a remote server. + * + * This will let the Broadcast Audio Scan Service server know that this device + * is actively scanning for broadcast sources. + * The function can optionally also start scanning, if the caller does not want + * to start scanning itself. + * + * Scan results, if @p start_scan is true, is sent to the + * bt_bap_broadcast_assistant_scan_cb callback. + * + * @param conn Connection to the Broadcast Audio Scan Service server. + * Used to let the server know that we are scanning. + * @param start_scan Start scanning if true. If false, the application should + * enable scan itself. + + * @retval 0 Success + * @retval -EINVAL @p conn is NULL of if @p conn has not done discovery + * @retval -EBUSY Another operation is already in progress for this @p conn + * @retval -EAGAIN Bluetooth has not been enabled. + * @retval -ENOTCONN @p conn is not connected + * @retval -ENOMEM Could not allocated memory for the request + * @retval -ENOEXEC Unexpected scan or GATT error + */ +int bt_bap_broadcast_assistant_scan_start(struct bt_conn *conn, bool start_scan); +int bt_bap_broadcast_assistant_scan_start_safe(struct bt_conn *conn, + bool start_scan); + +/** + * @brief Stop remote scanning for BISes for a server. + * + * @param conn Connection to the server. + + * @retval 0 Success + * @retval -EINVAL @p conn is NULL of if @p conn has not done discovery + * @retval -EBUSY Another operation is already in progress for this @p conn + * @retval -EAGAIN Bluetooth has not been enabled. + * @retval -ENOTCONN @p conn is not connected + * @retval -ENOMEM Could not allocated memory for the request + * @retval -ENOEXEC Unexpected scan or GATT error + */ +int bt_bap_broadcast_assistant_scan_stop(struct bt_conn *conn); +int bt_bap_broadcast_assistant_scan_stop_safe(struct bt_conn *conn); + +/** + * @brief Registers the callbacks used by Broadcast Audio Scan Service client. + * + * @param cb The callback structure. + * + * @retval 0 on success + * @retval -EINVAL if @p cb is NULL + * @retval -EALREADY if @p cb was already registered + */ +int bt_bap_broadcast_assistant_register_cb_safe(struct bt_bap_broadcast_assistant_cb *cb); + +/** + * @brief Unregisters the callbacks used by the Broadcast Audio Scan Service client. + * + * @param cb The callback structure. + * + * @retval 0 on success + * @retval -EINVAL if @p cb is NULL + * @retval -EALREADY if @p cb was not registered + */ +int bt_bap_broadcast_assistant_unregister_cb_safe(struct bt_bap_broadcast_assistant_cb *cb); + +/** Parameters for adding a source to a Broadcast Audio Scan Service server */ +struct bt_bap_broadcast_assistant_add_src_param { + /** Address of the advertiser. */ + bt_addr_le_t addr; + + /** SID of the advertising set. */ + uint8_t adv_sid; + + /** Whether to sync to periodic advertisements. */ + bool pa_sync; + + /** 24-bit broadcast ID */ + uint32_t broadcast_id; + + /** + * @brief Periodic advertising interval in milliseconds. + * + * BT_BAP_PA_INTERVAL_UNKNOWN if unknown. + */ + uint16_t pa_interval; + + /** Number of subgroups */ + uint8_t num_subgroups; + + /** Pointer to array of subgroups + * + * The @ref bt_bap_bass_subgroup.bis_sync value can be set to BT_BAP_BIS_SYNC_NO_PREF to + * let the broadcast sink decide which BIS to synchronize to. + */ + struct bt_bap_bass_subgroup *subgroups; +}; + +/** + * @brief Add a source on the server. + * + * @param conn Connection to the server. + * @param param Parameter struct. + * + * @retval 0 Success + * @retval -EINVAL @p conn is NULL or %p conn has not done discovery or if @p param is invalid + * @retval -EBUSY Another operation is already in progress for this @p conn + * @retval -ENOTCONN @p conn is not connected + * @retval -ENOMEM Could not allocated memory for the request + * @retval -ENOEXEC Unexpected scan or GATT error + */ +int bt_bap_broadcast_assistant_add_src( + struct bt_conn *conn, const struct bt_bap_broadcast_assistant_add_src_param *param); +int bt_bap_broadcast_assistant_add_src_safe( + struct bt_conn *conn, const struct bt_bap_broadcast_assistant_add_src_param *param); + +/** Parameters for modifying a source */ +struct bt_bap_broadcast_assistant_mod_src_param { + /** Source ID of the receive state. */ + uint8_t src_id; + + /** Whether to sync to periodic advertisements. */ + bool pa_sync; + + /** + * @brief Periodic advertising interval. + * + * BT_BAP_PA_INTERVAL_UNKNOWN if unknown. + */ + uint16_t pa_interval; + + /** Number of subgroups */ + uint8_t num_subgroups; + + /** Pointer to array of subgroups */ + struct bt_bap_bass_subgroup *subgroups; +}; + +/** + * @brief Modify a source on the server. + * + * @param conn Connection to the server. + * @param param Parameter struct. + * + * @retval 0 Success + * @retval -EINVAL @p conn is NULL or %p conn has not done discovery or if @p param is invalid + * @retval -EBUSY Another operation is already in progress for this @p conn + * @retval -ENOTCONN @p conn is not connected + * @retval -ENOMEM Could not allocated memory for the request + * @retval -ENOEXEC Unexpected scan or GATT error + */ +int bt_bap_broadcast_assistant_mod_src( + struct bt_conn *conn, const struct bt_bap_broadcast_assistant_mod_src_param *param); +int bt_bap_broadcast_assistant_mod_src_safe( + struct bt_conn *conn, const struct bt_bap_broadcast_assistant_mod_src_param *param); + +/** + * @brief Set a broadcast code to the specified receive state. + * + * @param conn Connection to the server. + * @param src_id Source ID of the receive state. + * @param broadcast_code The broadcast code. + * + * @retval 0 Success + * @retval -EINVAL @p conn is NULL or %p conn has not done discovery or @p src_id is invalid + * @retval -EBUSY Another operation is already in progress for this @p conn + * @retval -ENOTCONN @p conn is not connected + * @retval -ENOMEM Could not allocated memory for the request + * @retval -ENOEXEC Unexpected scan or GATT error + */ +int bt_bap_broadcast_assistant_set_broadcast_code( + struct bt_conn *conn, uint8_t src_id, + const uint8_t broadcast_code[BT_ISO_BROADCAST_CODE_SIZE]); +int bt_bap_broadcast_assistant_set_broadcast_code_safe( + struct bt_conn *conn, uint8_t src_id, + const uint8_t broadcast_code[BT_ISO_BROADCAST_CODE_SIZE]); + +/** + * @brief Remove a source from the server. + * + * @param conn Connection to the server. + * @param src_id Source ID of the receive state. + * + * @retval 0 Success + * @retval -EINVAL @p conn is NULL or %p conn has not done discovery or @p src_id is invalid + * @retval -EBUSY Another operation is already in progress for this @p conn + * @retval -ENOTCONN @p conn is not connected + * @retval -ENOMEM Could not allocated memory for the request + * @retval -ENOEXEC Unexpected scan or GATT error + */ +int bt_bap_broadcast_assistant_rem_src(struct bt_conn *conn, uint8_t src_id); +int bt_bap_broadcast_assistant_rem_src_safe(struct bt_conn *conn, uint8_t src_id); + +/** + * @brief Read the specified receive state from the server. + * + * @param conn Connection to the server. + * @param idx The index of the receive start (0 up to the value from + * bt_bap_broadcast_assistant_discover_cb) + * + * @retval 0 Success + * @retval -EINVAL @p conn is NULL or %p conn has not done discovery or @p src_id is invalid + * @retval -EBUSY Another operation is already in progress for this @p conn + * @retval -ENOTCONN @p conn is not connected + * @retval -ENOMEM Could not allocated memory for the request + * @retval -ENOEXEC Unexpected scan or GATT error + */ +int bt_bap_broadcast_assistant_read_recv_state(struct bt_conn *conn, uint8_t idx); +int bt_bap_broadcast_assistant_read_recv_state_safe(struct bt_conn *conn, uint8_t idx); + +/** @} */ /* end of bt_bap */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_BAP_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/bap_lc3_preset.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/bap_lc3_preset.h new file mode 100644 index 0000000000..81656d7d05 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/bap_lc3_preset.h @@ -0,0 +1,841 @@ +/** + * @file + * @brief Header for Bluetooth BAP LC3 presets. + * + * SPDX-FileCopyrightText: 2023-2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_BAP_LC3_PRESET_ +#define ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_BAP_LC3_PRESET_ + +/** + * @brief Basic Audio Profile (BAP) LC3 Presets + * + * @defgroup bt_bap_lc3_preset Basic Audio Profile (BAP) LC3 Presets + * + * @since 3.0 + * @version 0.8.0 + * + * @ingroup bluetooth + * @{ + * + * These APIs provide preset for codec configuration and QoS based on values supplied by the + * codec configuration tables in the BAP specification. + * + */ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Struct to hold a BAP defined LC3 preset */ +struct bt_bap_lc3_preset { + /** The LC3 Codec */ + struct bt_audio_codec_cfg codec_cfg; + /** The BAP spec defined QoS values */ + struct bt_bap_qos_cfg qos; +}; + +/** Helper to declare an LC3 preset structure */ +#define BT_BAP_LC3_PRESET(_codec, _qos) \ + { \ + .codec_cfg = _codec, .qos = _qos, \ + } + +/* LC3 Unicast presets defined by table 5.2 in the BAP v1.0 specification */ + +/** + * @brief Helper to declare LC3 Unicast 8_1_1 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_UNICAST_PRESET_8_1_1(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_8KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 26u, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 26u, 2u, 8u, 40000u)) + +/** + * @brief Helper to declare LC3 Unicast 8_2_1 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_UNICAST_PRESET_8_2_1(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_8KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 30U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 30u, 2u, 10u, 40000u)) + +/** + * @brief Helper to declare LC3 Unicast 16_1_1 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_UNICAST_PRESET_16_1_1(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_16KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 30U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 30u, 2u, 8u, 40000u)) + +/** + * @brief Helper to declare LC3 Unicast 16_2_1 codec configuration + * + * Mandatory to support as both unicast client and server + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_UNICAST_PRESET_16_2_1(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_16KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 40U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 40u, 2u, 10u, 40000u)) + +/** + * @brief Helper to declare LC3 Unicast 24_1_1 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_UNICAST_PRESET_24_1_1(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_24KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 45U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 45u, 2u, 8u, 40000u)) + +/** + * @brief Helper to declare LC3 Unicast 24_2_1 codec configuration + * + * Mandatory to support as unicast server + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_UNICAST_PRESET_24_2_1(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_24KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 60U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 60u, 2u, 10u, 40000u)) + +/** + * @brief Helper to declare LC3 Unicast 32_1_1 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_UNICAST_PRESET_32_1_1(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 60U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 60u, 2u, 8u, 40000u)) + +/** + * @brief Helper to declare LC3 Unicast 32_2_1 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_UNICAST_PRESET_32_2_1(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 80U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 80u, 2u, 10u, 40000u)) + +/** + * @brief Helper to declare LC3 Unicast 441_1_1 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_UNICAST_PRESET_441_1_1(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_44KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 97U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_FRAMED(8163u, 97u, 5u, 24u, 40000u)) + +/** + * @brief Helper to declare LC3 Unicast 441_2_1 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_UNICAST_PRESET_441_2_1(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_44KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 130U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_FRAMED(10884u, 130u, 5u, 31u, 40000u)) + +/** + * @brief Helper to declare LC3 Unicast 48_1_1 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_UNICAST_PRESET_48_1_1(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 75U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 75u, 5u, 15u, 40000u)) + +/** + * @brief Helper to declare LC3 Unicast 48_2_1 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_UNICAST_PRESET_48_2_1(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 100U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 100u, 5u, 20u, 40000u)) + +/** + * @brief Helper to declare LC3 Unicast 48_3_1 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_UNICAST_PRESET_48_3_1(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 90U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 90u, 5u, 15u, 40000u)) + +/** + * @brief Helper to declare LC3 Unicast 48_4_1 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_UNICAST_PRESET_48_4_1(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 120u, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 120u, 5u, 20u, 40000u)) + +/** + * @brief Helper to declare LC3 Unicast 8_5_1 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_UNICAST_PRESET_48_5_1(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 117u, \ + 1, _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 117u, 5u, 15u, 40000u)) + +/** + * @brief Helper to declare LC3 Unicast 48_6_1 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_UNICAST_PRESET_48_6_1(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 155u, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 155u, 5u, 20u, 40000u)) + +/** + * @brief Helper to declare LC3 Unicast 8_1_2 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +/* Following presets are for unicast high reliability audio data */ +#define BT_BAP_LC3_UNICAST_PRESET_8_1_2(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_8KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 26u, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 26u, 13u, 75u, 40000u)) + +/** + * @brief Helper to declare LC3 Unicast 8_2_2 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_UNICAST_PRESET_8_2_2(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_8KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 30U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 30u, 13u, 95u, 40000u)) + +/** + * @brief Helper to declare LC3 Unicast 16_1_2 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_UNICAST_PRESET_16_1_2(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_16KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 30U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 30u, 13u, 75u, 40000u)) + +/** + * @brief Helper to declare LC3 Unicast 16_2_2 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_UNICAST_PRESET_16_2_2(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_16KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 40U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 40u, 13u, 95u, 40000u)) + +/** + * @brief Helper to declare LC3 Unicast 24_1_2 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_UNICAST_PRESET_24_1_2(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_24KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 45U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 45u, 13u, 75u, 40000u)) + +/** + * @brief Helper to declare LC3 Unicast 24_2_2 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_UNICAST_PRESET_24_2_2(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_24KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 60U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 60u, 13u, 95u, 40000u)) + +/** + * @brief Helper to declare LC3 Unicast 32_1_2 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_UNICAST_PRESET_32_1_2(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 60U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 60u, 13u, 75u, 40000u)) + +/** + * @brief Helper to declare LC3 Unicast 32_2_2 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_UNICAST_PRESET_32_2_2(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 80U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 80u, 13u, 95u, 40000u)) + +/** + * @brief Helper to declare LC3 Unicast 441_1_2 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_UNICAST_PRESET_441_1_2(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_44KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 97U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_FRAMED(8163u, 97u, 13u, 80u, 40000u)) + +/** + * @brief Helper to declare LC3 Unicast 441_2_2 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_UNICAST_PRESET_441_2_2(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_44KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 130U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_FRAMED(10884u, 130u, 13u, 85u, 40000u)) + +/** + * @brief Helper to declare LC3 Unicast 48_1_2 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_UNICAST_PRESET_48_1_2(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 75U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 75u, 13u, 75u, 40000u)) + +/** + * @brief Helper to declare LC3 Unicast 48_2_2 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_UNICAST_PRESET_48_2_2(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 100U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 100u, 13u, 95u, 40000u)) + +/** + * @brief Helper to declare LC3 Unicast 48_3_2 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_UNICAST_PRESET_48_3_2(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 90U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 90u, 13u, 75u, 40000u)) + +/** + * @brief Helper to declare LC3 Unicast 48_4_2 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_UNICAST_PRESET_48_4_2(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 120u, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 120u, 13u, 100u, 40000u)) + +/** + * @brief Helper to declare LC3 Unicast 48_5_2 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_UNICAST_PRESET_48_5_2(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 117u, \ + 1, _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 117u, 13u, 75u, 40000u)) + +/** + * @brief Helper to declare LC3 Unicast 48_6_2 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_UNICAST_PRESET_48_6_2(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 155u, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 155u, 13u, 100u, 40000u)) + +/** + * @brief Helper to declare LC3 Broadcast 8_1_1 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +/* LC3 Broadcast presets defined by table 6.4 in the BAP v1.0 specification */ +#define BT_BAP_LC3_BROADCAST_PRESET_8_1_1(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_8KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 26u, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 26u, 2u, 8u, 40000u)) + +/** + * @brief Helper to declare LC3 Broadcast 8_2_1 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_BROADCAST_PRESET_8_2_1(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_8KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 30U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 30u, 2u, 10u, 40000u)) + +/** + * @brief Helper to declare LC3 Broadcast 16_1_1 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_BROADCAST_PRESET_16_1_1(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_16KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 30U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 30u, 2u, 8u, 40000u)) + +/** + * @brief Helper to declare LC3 Broadcast 16_2_1 codec configuration + * + * Mandatory to support as both broadcast source and sink + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_BROADCAST_PRESET_16_2_1(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_16KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 40U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 40u, 2u, 10u, 40000u)) + +/** + * @brief Helper to declare LC3 Broadcast 24_1_1 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_BROADCAST_PRESET_24_1_1(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_24KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 45U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 45u, 2u, 8u, 40000u)) + +/** + * @brief Helper to declare LC3 Broadcast 24_2_1 codec configuration + * + * Mandatory to support as broadcast sink + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_BROADCAST_PRESET_24_2_1(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_24KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 60U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 60u, 2u, 10u, 40000u)) + +/** + * @brief Helper to declare LC3 Broadcast 32_1_1 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_BROADCAST_PRESET_32_1_1(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 60U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 60u, 2u, 8u, 40000u)) + +/** + * @brief Helper to declare LC3 Broadcast 32_2_1 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_BROADCAST_PRESET_32_2_1(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 80U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 80u, 2u, 10u, 40000u)) + +/** + * @brief Helper to declare LC3 Broadcast 441_1_1 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_BROADCAST_PRESET_441_1_1(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_44KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 97U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_FRAMED(8163u, 97u, 4u, 24u, 40000u)) + +/** + * @brief Helper to declare LC3 Broadcast 441_2_1 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_BROADCAST_PRESET_441_2_1(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_44KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 130U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_FRAMED(10884u, 130u, 4u, 31u, 40000u)) + +/** + * @brief Helper to declare LC3 Broadcast 48_1_1 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_BROADCAST_PRESET_48_1_1(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 75U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 75u, 4u, 15u, 40000u)) + +/** + * @brief Helper to declare LC3 Broadcast 48_2_1 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_BROADCAST_PRESET_48_2_1(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 100U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 100u, 4u, 20u, 40000u)) + +/** + * @brief Helper to declare LC3 Broadcast 48_3_1 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_BROADCAST_PRESET_48_3_1(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 90U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 90u, 4u, 15u, 40000u)) + +/** + * @brief Helper to declare LC3 Broadcast 48_4_1 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_BROADCAST_PRESET_48_4_1(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 120u, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 120u, 4u, 20u, 40000u)) + +/** + * @brief Helper to declare LC3 Broadcast 48_5_1 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_BROADCAST_PRESET_48_5_1(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 117u, \ + 1, _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 117u, 4u, 15u, 40000u)) + +/** + * @brief Helper to declare LC3 Broadcast 48_6_1 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_BROADCAST_PRESET_48_6_1(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 155u, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 155u, 4u, 20u, 40000u)) + +/** + * @brief Helper to declare LC3 Broadcast 8_1_2 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +/* Following presets are for broadcast high reliability audio data */ +#define BT_BAP_LC3_BROADCAST_PRESET_8_1_2(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_8KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 26u, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 26u, 4u, 45u, 40000u)) + +/** + * @brief Helper to declare LC3 Broadcast 8_2_2 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_BROADCAST_PRESET_8_2_2(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_8KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 30U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 30u, 4u, 60u, 40000u)) + +/** + * @brief Helper to declare LC3 Broadcast 16_1_2 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_BROADCAST_PRESET_16_1_2(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_16KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 30U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 30u, 4u, 45u, 40000u)) + +/** + * @brief Helper to declare LC3 Broadcast 16_2_2 codec configuration + * + * Mandatory to support as both broadcast source and sink + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_BROADCAST_PRESET_16_2_2(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_16KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 40U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 40u, 4u, 60u, 40000u)) + +/** + * @brief Helper to declare LC3 Broadcast 24_1_2 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_BROADCAST_PRESET_24_1_2(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_24KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 45U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 45u, 4u, 45u, 40000u)) + +/** + * @brief Helper to declare LC3 Broadcast 24_2_2 codec configuration + * + * Mandatory to support as broadcast sink + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_BROADCAST_PRESET_24_2_2(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_24KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 60U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 60u, 4u, 60u, 40000u)) + +/** + * @brief Helper to declare LC3 Broadcast 32_1_2 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_BROADCAST_PRESET_32_1_2(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 60U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 60u, 4u, 45u, 40000u)) + +/** + * @brief Helper to declare LC3 Broadcast 32_2_2 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_BROADCAST_PRESET_32_2_2(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 80U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 80u, 4u, 60u, 40000u)) + +/** + * @brief Helper to declare LC3 Broadcast 441_1_2 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_BROADCAST_PRESET_441_1_2(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_44KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 97U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_FRAMED(8163u, 97u, 4u, 54u, 40000u)) + +/** + * @brief Helper to declare LC3 Broadcast 441_2_2 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_BROADCAST_PRESET_441_2_2(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_44KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 130U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_FRAMED(10884u, 130u, 4u, 60u, 40000u)) + +/** + * @brief Helper to declare LC3 Broadcast 48_1_2 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_BROADCAST_PRESET_48_1_2(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 75U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 75u, 4u, 50u, 40000u)) + +/** + * @brief Helper to declare LC3 Broadcast 48_2_2 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_BROADCAST_PRESET_48_2_2(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 100U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 100u, 4u, 65u, 40000u)) + +/** + * @brief Helper to declare LC3 Broadcast 48_3_2 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_BROADCAST_PRESET_48_3_2(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 90U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 90u, 4u, 50u, 40000u)) + +/** + * @brief Helper to declare LC3 Broadcast 48_4_2 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_BROADCAST_PRESET_48_4_2(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 120u, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 120u, 4u, 65u, 40000u)) + +/** + * @brief Helper to declare LC3 Broadcast 48_5_2 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_BROADCAST_PRESET_48_5_2(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 117u, \ + 1, _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 117u, 4u, 50u, 40000u)) + +/** + * @brief Helper to declare LC3 Broadcast 48_6_2 codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_BAP_LC3_BROADCAST_PRESET_48_6_2(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 155u, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 155u, 4u, 65u, 40000u)) + +#ifdef __cplusplus +} +#endif +/** @} */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_BAP_LC3_PRESET_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/cap.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/cap.h new file mode 100644 index 0000000000..2786d172fe --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/cap.h @@ -0,0 +1,1496 @@ +/** + * @file + * @brief Bluetooth Common Audio Profile (CAP) APIs. + */ + +/* + * SPDX-FileCopyrightText: 2022-2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_CAP_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_CAP_H_ + +/** + * @brief Common Audio Profile (CAP) + * + * @defgroup bt_cap Common Audio Profile (CAP) + * + * @since 3.2 + * @version 0.8.0 + * + * @ingroup bluetooth + * @{ + * + * Common Audio Profile (CAP) provides procedures to start, update, and stop unicast and broadcast + * Audio Streams on individual or groups of devices using procedures in the Basic Audio Profile + * (BAP). This profile also provides procedures to control volume and device input on groups of + * devices using procedures in the Volume Control Profile (VCP) and the Microphone Control Profile + * (MICP). This profile specification also refers to the Common Audio Service (CAS). + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief Abstract Audio Broadcast Source structure. */ +struct bt_cap_broadcast_source; + +/** @brief Abstract CAP Unicast Group structure. */ +struct bt_cap_unicast_group; + +/** + * @brief Register the Common Audio Service. + * + * This will register and enable the service and make it discoverable by + * clients. This will also register a Coordinated Set Identification + * Service instance. + * + * This shall only be done as a server, and requires + * @kconfig{BT_CAP_ACCEPTOR_SET_MEMBER}. If @kconfig{BT_CAP_ACCEPTOR_SET_MEMBER} + * is not enabled, the Common Audio Service will by statically registered. + * + * @param[in] param Coordinated Set Identification Service register + * parameters. + * @param[out] svc_inst Pointer to the registered Coordinated Set + * Identification Service. + * + * @return 0 if success, errno on failure. + */ +int bt_cap_acceptor_register_safe(const struct bt_csip_set_member_register_param *param, + struct bt_csip_set_member_svc_inst **svc_inst); + +/** Callback structure for CAP procedures */ +struct bt_cap_initiator_cb { + /** + * @brief Callback for bt_cap_initiator_unicast_discover(). + * + * @param conn The connection pointer supplied to + * bt_cap_initiator_unicast_discover(). + * @param err 0 if Common Audio Service was found else -ENODATA. + * @param member Pointer to the set member. NULL if err != 0. + * @param csis_inst The Coordinated Set Identification Service if + * Common Audio Service was found and includes a + * Coordinated Set Identification Service. + * NULL on error or if remote device does not include + * Coordinated Set Identification Service. NULL if err != 0. + */ + void (*unicast_discovery_complete)( + struct bt_conn *conn, int err, + const struct bt_csip_set_coordinator_set_member *member, + const struct bt_csip_set_coordinator_csis_inst *csis_inst); + + /** + * @brief Callback for bt_cap_initiator_unicast_audio_start(). + * + * @param err 0 if success, BT_GATT_ERR() with a + * specific ATT (BT_ATT_ERR_*) error code or -ECANCELED if cancelled + * by bt_cap_initiator_unicast_audio_cancel(). + * @param conn Pointer to the connection where the error + * occurred. NULL if @p err is 0 or if cancelled by + * bt_cap_initiator_unicast_audio_cancel() + */ + void (*unicast_start_complete)(int err, struct bt_conn *conn); + + /** + * @brief Callback for bt_cap_initiator_unicast_audio_update(). + * + * @param err 0 if success, BT_GATT_ERR() with a + * specific ATT (BT_ATT_ERR_*) error code or -ECANCELED if cancelled + * by bt_cap_initiator_unicast_audio_cancel(). + * @param conn Pointer to the connection where the error + * occurred. NULL if @p err is 0 or if cancelled by + * bt_cap_initiator_unicast_audio_cancel() + */ + void (*unicast_update_complete)(int err, struct bt_conn *conn); + + /** + * @brief Callback for bt_cap_initiator_unicast_audio_stop(). + * + * @param err 0 if success, BT_GATT_ERR() with a + * specific ATT (BT_ATT_ERR_*) error code or -ECANCELED if cancelled + * by bt_cap_initiator_unicast_audio_cancel(). + * @param conn Pointer to the connection where the error + * occurred. NULL if @p err is 0 or if cancelled by + * bt_cap_initiator_unicast_audio_cancel() + */ + void (*unicast_stop_complete)(int err, struct bt_conn *conn); + + /** + * @brief The Broadcast Source has started and all of the streams are ready for audio data + * + * @param source The started Broadcast Source + */ + void (*broadcast_started)(struct bt_cap_broadcast_source *source); + + /** + * @brief The Broadcast Source has stopped and none of the streams are ready for audio data + * + * @param source The stopped Broadcast Source + * @param reason The reason why the Broadcast Source stopped (see the BT_HCI_ERR_* values) + */ + void (*broadcast_stopped)(struct bt_cap_broadcast_source *source, uint8_t reason); +}; + +/** + * @brief Discovers audio support on a remote device. + * + * This will discover the Common Audio Service (CAS) on the remote device, to + * verify if the remote device supports the Common Audio Profile. + * + * @param conn Connection to a remote server. + * + * @retval 0 Success + * @retval -EINVAL @p conn is NULL + * @retval -ENOTCONN @p conn is not connected + * @retval -ENOMEM Could not allocated memory for the request + */ +int bt_cap_initiator_unicast_discover(struct bt_conn *conn); +int bt_cap_initiator_unicast_discover_safe(struct bt_conn *conn); + +/** Type of CAP set */ +enum bt_cap_set_type { + /** The set is an ad-hoc set */ + BT_CAP_SET_TYPE_AD_HOC, + /** The set is a CSIP Coordinated Set */ + BT_CAP_SET_TYPE_CSIP, +}; + +/** Represents a Common Audio Set member that are either in a Coordinated or ad-hoc set */ +union bt_cap_set_member { + /** Connection pointer if the type is BT_CAP_SET_TYPE_AD_HOC. */ + struct bt_conn *member; + + /** CSIP Coordinated Set struct used if type is BT_CAP_SET_TYPE_CSIP. */ + struct bt_csip_set_coordinator_csis_inst *csip; +}; + +/** + * @brief Common Audio Profile stream structure. + * + * Streams represents a Basic Audio Profile (BAP) stream and operation callbacks. + * See @ref bt_bap_stream for additional information. + */ +struct bt_cap_stream { + /** The underlying BAP audio stream */ + struct bt_bap_stream bap_stream; + + /** Audio stream operations */ + struct bt_bap_stream_ops *ops; +}; + +/** + * @brief Register Audio operations for a Common Audio Profile stream. + * + * Register Audio operations for a stream. + * + * @param stream Stream object. + * @param ops Stream operations structure. + */ +void bt_cap_stream_ops_register_safe(struct bt_cap_stream *stream, struct bt_bap_stream_ops *ops); + +/** + * @brief Send data to Common Audio Profile stream without timestamp + * + * See bt_bap_stream_send() for more information + * + * @note Support for sending must be supported, determined by @kconfig{CONFIG_BT_AUDIO_TX}. + * + * @param stream Stream object. + * @param buf Buffer containing data to be sent. + * @param seq_num Packet Sequence number. This value shall be incremented for each call to this + * function and at least once per SDU interval for a specific channel. + * + * @retval -EINVAL if stream object is NULL + * @retval Any return value from bt_bap_stream_send() + */ +int bt_cap_stream_send_safe(struct bt_cap_stream *stream, struct net_buf *buf, uint16_t seq_num); + +/** + * @brief Send data to Common Audio Profile stream with timestamp + * + * See bt_bap_stream_send() for more information + * + * @note Support for sending must be supported, determined by @kconfig{CONFIG_BT_AUDIO_TX}. + * + * @param stream Stream object. + * @param buf Buffer containing data to be sent. + * @param seq_num Packet Sequence number. This value shall be incremented for each call to this + * function and at least once per SDU interval for a specific channel. + * @param ts Timestamp of the SDU in microseconds (us). This value can be used to transmit + * multiple SDUs in the same SDU interval in a CIG or BIG. + * + * @retval -EINVAL if stream object is NULL + * @retval Any return value from bt_bap_stream_send() + */ +int bt_cap_stream_send_ts_safe(struct bt_cap_stream *stream, struct net_buf *buf, uint16_t seq_num, + uint32_t ts); + +/** + * @brief Get ISO transmission timing info for a Common Audio Profile stream + * + * See bt_bap_stream_get_tx_sync() for more information + * + * @note Support for sending must be supported, determined by @kconfig{CONFIG_BT_AUDIO_TX}. + * + * @param[in] stream Stream object. + * @param[out] info Transmit info object. + * + * @retval -EINVAL if stream object is NULL + * @retval Any return value from bt_bap_stream_get_tx_sync() + */ +int bt_cap_stream_get_tx_sync_safe(struct bt_cap_stream *stream, struct bt_iso_tx_info *info); + +/** Parameter struct for each stream in the unicast group */ +struct bt_cap_unicast_group_stream_param { + /** Pointer to a stream object. */ + struct bt_cap_stream *stream; + + /** The QoS settings for the stream object. */ + struct bt_bap_qos_cfg *qos_cfg; +}; + +/** + * @brief Parameter struct for the unicast group functions + * + * Parameter struct for the bt_cap_unicast_group_create() and + * bt_cap_unicast_group_add_streams() functions. + */ +struct bt_cap_unicast_group_stream_pair_param { + /** Pointer to a receiving stream parameters. */ + struct bt_cap_unicast_group_stream_param *rx_param; + + /** Pointer to a transmitting stream parameters. */ + struct bt_cap_unicast_group_stream_param *tx_param; +}; + +/** Parameters for the creating unicast groups with bt_cap_unicast_group_create() */ +struct bt_cap_unicast_group_param { + /** The number of parameters in @p params */ + size_t params_count; + + /** Array of stream parameters */ + struct bt_cap_unicast_group_stream_pair_param *params; + + /** + * @brief Unicast Group packing mode. + * + * @ref BT_ISO_PACKING_SEQUENTIAL or @ref BT_ISO_PACKING_INTERLEAVED. + * + * @note This is a recommendation to the controller, which the controller may ignore. + */ + uint8_t packing; + + /** + * @brief Central to Peripheral flush timeout + * + * The flush timeout in multiples of ISO_Interval for each payload sent + * from the Central to Peripheral. + * + * Value range from @ref BT_ISO_FT_MIN to @ref BT_ISO_FT_MAX + */ + uint8_t c_to_p_ft; + + /** + * @brief Peripheral to Central flush timeout + * + * The flush timeout in multiples of ISO_Interval for each payload sent + * from the Peripheral to Central. + * + * Value range from @ref BT_ISO_FT_MIN to @ref BT_ISO_FT_MAX. + */ + uint8_t p_to_c_ft; + + /** + * @brief ISO interval + * + * Time between consecutive CIS anchor points. + * + * Value range from @ref BT_ISO_ISO_INTERVAL_MIN to @ref BT_ISO_ISO_INTERVAL_MAX. + */ + uint16_t iso_interval; +}; + +/** + * @brief Create unicast group. + * + * Create a new audio unicast group with one or more audio streams as a unicast client. + * All streams shall share the same framing. + * All streams in the same direction shall share the same interval and latency (see + * @ref bt_bap_qos_cfg). + * + * @param[in] param The unicast group create parameters. + * @param[out] unicast_group Pointer to the unicast group created. + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_cap_unicast_group_create_safe(const struct bt_cap_unicast_group_param *param, + struct bt_cap_unicast_group **unicast_group); + +/** + * @brief Reconfigure unicast group. + * + * Reconfigure a unicast group with one or more audio streams as a unicast client. + * All streams shall share the same framing. + * All streams in the same direction shall share the same interval and latency (see + * @ref bt_bap_qos_cfg). + * All streams in @p param shall already belong to @p unicast_group. + * Use bt_cap_unicast_group_add_streams() to add additional streams. + * + * @param unicast_group Pointer to the unicast group created. + * @param param The unicast group reconfigure parameters. + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_cap_unicast_group_reconfig_safe(struct bt_cap_unicast_group *unicast_group, + const struct bt_cap_unicast_group_param *param); + +/** + * @brief Add streams to a unicast group as a unicast client + * + * This function can be used to add additional streams to a bt_cap_unicast_group. + * + * This can be called at any time before any of the streams in the group has been started + * (see bt_bap_stream_ops.started()). + * This can also be called after the streams have been stopped (see bt_bap_stream_ops.stopped()). + * + * Once a stream has been added to a unicast group, it cannot be removed. To remove a stream from a + * group, the group must be deleted with bt_cap_unicast_group_delete(), but this will require all + * streams in the group to be released first. + * + * @param unicast_group Pointer to the unicast group + * @param params Array of stream parameters with streams being added to the group. + * @param num_param Number of parameters in @p params. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_cap_unicast_group_add_streams_safe(struct bt_cap_unicast_group *unicast_group, + const struct bt_cap_unicast_group_stream_pair_param params[], + size_t num_param); + +/** + * @brief Delete audio unicast group. + * + * Delete a audio unicast group as a client. All streams in the group shall + * be in the idle or configured state. + * + * @param unicast_group Pointer to the unicast group to delete + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_cap_unicast_group_delete_safe(struct bt_cap_unicast_group *unicast_group); + +/** Callback function for bt_bap_unicast_group_foreach_stream() + * + * @param stream The audio stream + * @param user_data User data + * + * @retval true Stop iterating. + * @retval false Continue iterating. + */ +typedef bool (*bt_cap_unicast_group_foreach_stream_func_t)(struct bt_cap_stream *stream, + void *user_data); + +/** + * @brief Iterate through all streams in a unicast group + * + * @param unicast_group The unicast group + * @param func The callback function + * @param user_data User specified data that is sent to the callback function + * + * @retval 0 Success (even if no streams exists in the group). + * @retval -ECANCELED The @p func returned true. + * @retval -EINVAL @p unicast_group or @p func were NULL. + */ +int bt_cap_unicast_group_foreach_stream_safe(struct bt_cap_unicast_group *unicast_group, + bt_cap_unicast_group_foreach_stream_func_t func, + void *user_data); + +/** Structure holding information of audio stream endpoint */ +struct bt_cap_unicast_group_info { + /** Pointer to the underlying Basic Audio Profile unicast group */ + const struct bt_bap_unicast_group *unicast_group; +}; + +/** + * @brief Return structure holding information of unicast group + * + * @param unicast_group The unicast group object. + * @param info The structure object to be filled with the info. + * + * @retval 0 Success + * @retval -EINVAL @p unicast_group or @p info are NULL + */ +int bt_cap_unicast_group_get_info_safe(const struct bt_cap_unicast_group *unicast_group, + struct bt_cap_unicast_group_info *info); + +/** Stream specific parameters for the bt_cap_initiator_unicast_audio_start() function */ +struct bt_cap_unicast_audio_start_stream_param { + /** Coordinated or ad-hoc set member. */ + union bt_cap_set_member member; + + /** @brief Stream for the @p member */ + struct bt_cap_stream *stream; + + /** Endpoint reference for the @p stream */ + struct bt_bap_ep *ep; + + /** + * @brief Codec configuration. + * + * The @p codec_cfg.meta shall include a list of CCIDs + * (@ref BT_AUDIO_METADATA_TYPE_CCID_LIST) as well as a non-0 + * stream context (@ref BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT) bitfield. + * + * This value is assigned to the @p stream, and shall remain valid while the stream is + * non-idle. + */ + struct bt_audio_codec_cfg *codec_cfg; +}; + +/** Parameters for the bt_cap_initiator_unicast_audio_start() function */ +struct bt_cap_unicast_audio_start_param { + /** The type of the set. */ + enum bt_cap_set_type type; + + /** The number of parameters in @p stream_params */ + size_t count; + + /** Array of stream parameters */ + struct bt_cap_unicast_audio_start_stream_param *stream_params; +}; + +/** Stream specific parameters for the bt_cap_initiator_unicast_audio_update() function */ +struct bt_cap_unicast_audio_update_stream_param { + /** Stream to update */ + struct bt_cap_stream *stream; + + /** The length of @p meta. */ + size_t meta_len; + + /** + * @brief The new metadata. + * + * The metadata shall contain a list of CCIDs as well as a non-0 context bitfield. + */ + uint8_t *meta; +}; + +/** Parameters for the bt_cap_initiator_unicast_audio_update() function */ +struct bt_cap_unicast_audio_update_param { + /** The type of the set. */ + enum bt_cap_set_type type; + + /** The number of parameters in @p stream_params */ + size_t count; + + /** Array of stream parameters */ + struct bt_cap_unicast_audio_update_stream_param *stream_params; +}; + +/** Parameters for the bt_cap_initiator_unicast_audio_stop() function */ +struct bt_cap_unicast_audio_stop_param { + /** The type of the set. */ + enum bt_cap_set_type type; + + /** The number of streams in @p streams */ + size_t count; + + /** Array of streams to stop */ + struct bt_cap_stream **streams; + + /** Whether to release the streams after they have stopped */ + bool release; +}; + +/** + * @brief Register Common Audio Profile Initiator callbacks + * + * @param cb The callback structure. Shall remain static. + * + * @return 0 on success or negative error value on failure. + */ +int bt_cap_initiator_register_cb_safe(const struct bt_cap_initiator_cb *cb); + +/** + * @brief Unregister Common Audio Profile Initiator callbacks + * + * @param cb The callback structure that was previously registered. + * + * @retval 0 Success + * @retval -EINVAL @p cb is NULL or @p cb was not registered + */ +int bt_cap_initiator_unregister_cb_safe(const struct bt_cap_initiator_cb *cb); + +/** + * @brief Setup and start unicast audio streams for a set of devices. + * + * The result of this operation is that the streams in @p param will be + * initialized and will be usable for streaming audio data. + * The @p unicast_group value can be used to update and stop the streams. + * + * @note @kconfig{CONFIG_BT_CAP_INITIATOR} and + * @kconfig{CONFIG_BT_BAP_UNICAST_CLIENT} must be enabled for this function + * to be enabled. + * + * @param param Parameters to start the audio streams. + * + * @retval 0 on success + * @retval -EBUSY if a CAP procedure is already in progress + * @retval -EINVAL if any parameter is invalid + * @retval -EALREADY All streams are already in the streaming state + */ +int bt_cap_initiator_unicast_audio_start_safe(const struct bt_cap_unicast_audio_start_param *param); + +/** + * @brief Update unicast audio streams. + * + * This will update the metadata of one or more streams. + * + * @note @kconfig{CONFIG_BT_CAP_INITIATOR} and + * @kconfig{CONFIG_BT_BAP_UNICAST_CLIENT} must be enabled for this function + * to be enabled. + * + * @param param Update parameters. + * + * @return 0 on success or negative error value on failure. + */ +int bt_cap_initiator_unicast_audio_update_safe(const struct bt_cap_unicast_audio_update_param *param); + +/** + * @brief Stop unicast audio streams. + * + * This will stop one or more streams. + * + * @note @kconfig{CONFIG_BT_CAP_INITIATOR} and + * @kconfig{CONFIG_BT_BAP_UNICAST_CLIENT} must be enabled for this function + * to be enabled. + * + * @param param Stop parameters. + * + * @return 0 on success + * @retval -EBUSY if a CAP procedure is already in progress + * @retval -EINVAL if any parameter is invalid + * @retval -EALREADY if no state changes will occur + */ +int bt_cap_initiator_unicast_audio_stop_safe(const struct bt_cap_unicast_audio_stop_param *param); + +/** + * @brief Cancel any current Common Audio Profile procedure + * + * This will stop the current procedure from continuing and making it possible to run a new + * Common Audio Profile procedure. + * + * It is recommended to do this if any existing procedure takes longer time than expected, which + * could indicate a missing response from the Common Audio Profile Acceptor. + * + * This does not send any requests to any Common Audio Profile Acceptors involved with the current + * procedure, and thus notifications from the Common Audio Profile Acceptors may arrive after this + * has been called. It is thus recommended to either only use this if a procedure has stalled, or + * wait a short while before starting any new Common Audio Profile procedure after this has been + * called to avoid getting notifications from the cancelled procedure. The wait time depends on + * the connection interval, the number of devices in the previous procedure and the behavior of the + * Common Audio Profile Acceptors. + * + * The respective callbacks of the procedure will be called as part of this with the connection + * pointer set to 0 and the err value set to -ECANCELED. + * + * @retval 0 on success + * @retval -EALREADY if no procedure is active + */ +int bt_cap_initiator_unicast_audio_cancel_safe(void); + +/** + * Parameters part of @p bt_cap_initiator_broadcast_subgroup_param for + * bt_cap_initiator_broadcast_audio_create() + */ +struct bt_cap_initiator_broadcast_stream_param { + /** Audio stream */ + struct bt_cap_stream *stream; + + /** The length of the %p data array. + * + * The BIS specific data may be omitted and this set to 0. + */ + size_t data_len; + + /** BIS Codec Specific Configuration */ + uint8_t *data; +}; + +/** + * Parameters part of @p bt_cap_initiator_broadcast_create_param for + * bt_cap_initiator_broadcast_audio_create() + */ +struct bt_cap_initiator_broadcast_subgroup_param { + /** The number of parameters in @p stream_params */ + size_t stream_count; + + /** Array of stream parameters */ + struct bt_cap_initiator_broadcast_stream_param *stream_params; + + /** Subgroup Codec configuration. */ + struct bt_audio_codec_cfg *codec_cfg; +}; + +/** Parameters for * bt_cap_initiator_broadcast_audio_create() */ +struct bt_cap_initiator_broadcast_create_param { + /** The number of parameters in @p subgroup_params */ + size_t subgroup_count; + + /** Array of stream parameters */ + struct bt_cap_initiator_broadcast_subgroup_param *subgroup_params; + + /** Quality of Service configuration. */ + struct bt_bap_qos_cfg *qos; + + /** + * @brief Broadcast Source packing mode. + * + * @ref BT_ISO_PACKING_SEQUENTIAL or @ref BT_ISO_PACKING_INTERLEAVED. + * + * @note This is a recommendation to the controller, which the controller may ignore. + */ + uint8_t packing; + + /** Whether or not to encrypt the streams. */ + bool encryption; + + /** + * @brief 16-octet broadcast code. + * + * Only valid if @p encrypt is true. + * + * If the value is a string or a the value is less than 16 octets, + * the remaining octets shall be 0. + * + * Example: + * The string "Broadcast Code" shall be + * [42 72 6F 61 64 63 61 73 74 20 43 6F 64 65 00 00] + */ + uint8_t broadcast_code[BT_ISO_BROADCAST_CODE_SIZE]; + + /** + * @brief Immediate Repetition Count + * + * The number of times the scheduled payloads are transmitted in a given event. + * + * Value range from @ref BT_ISO_IRC_MIN to @ref BT_ISO_IRC_MAX. + */ + uint8_t irc; + + /** + * @brief Pre-transmission offset + * + * Offset used for pre-transmissions. + * + * Value range from @ref BT_ISO_PTO_MIN to @ref BT_ISO_PTO_MAX. + */ + uint8_t pto; + + /** + * @brief ISO interval + * + * Time between consecutive BIS anchor points. + * + * Value range from @ref BT_ISO_ISO_INTERVAL_MIN to @ref BT_ISO_ISO_INTERVAL_MAX. + */ + uint16_t iso_interval; +}; + +/** + * @brief Create a Common Audio Profile broadcast source. + * + * Create a new audio broadcast source with one or more audio streams. + * + * @note @kconfig{CONFIG_BT_CAP_INITIATOR} and + * @kconfig{CONFIG_BT_BAP_BROADCAST_SOURCE} must be enabled for this function + * to be enabled. + * + * @param[in] param Parameters to start the audio streams. + * @param[out] broadcast_source Pointer to the broadcast source created. + * + * @retval 0 Success + * @retval -EINVAL @p param is invalid or @p broadcast_source is NULL + * @retval -ENOMEM Could not allocate more broadcast sources, subgroups or ISO streams, or the + * provided codec configuration data is too large when merging the BIS and subgroup + * configuration data. + * @retval -ENOEXEC The broadcast source failed to be created for other reasons + */ +int bt_cap_initiator_broadcast_audio_create_safe( + const struct bt_cap_initiator_broadcast_create_param *param, + struct bt_cap_broadcast_source **broadcast_source); + +/** + * @brief Start Common Audio Profile broadcast source. + * + * The broadcast source will be visible for scanners once this has been called, + * and the device will advertise audio announcements. + * + * This will allow the streams in the broadcast source to send audio by calling + * bt_bap_stream_send(). + * + * @note @kconfig{CONFIG_BT_CAP_INITIATOR} and + * @kconfig{CONFIG_BT_BAP_BROADCAST_SOURCE} must be enabled for this function + * to be enabled. + * + * @param broadcast_source Pointer to the broadcast source. + * @param adv Pointer to an extended advertising set with + * periodic advertising configured. + * + * @return 0 on success or negative error value on failure. + */ +int bt_cap_initiator_broadcast_audio_start(struct bt_cap_broadcast_source *broadcast_source, + struct bt_le_ext_adv *adv); +int bt_cap_initiator_broadcast_audio_start_safe(struct bt_cap_broadcast_source *broadcast_source, + struct bt_le_ext_adv *adv); + +/** + * @brief Update broadcast audio streams for a Common Audio Profile broadcast source. + * + * @note @kconfig{CONFIG_BT_CAP_INITIATOR} and + * @kconfig{CONFIG_BT_BAP_BROADCAST_SOURCE} must be enabled for this function + * to be enabled. + * + * @param broadcast_source The broadcast source to update. + * @param meta The new metadata. The metadata shall contain a list + * of CCIDs as well as a non-0 context bitfield. + * @param meta_len The length of @p meta. + * + * @return 0 on success or negative error value on failure. + */ +int bt_cap_initiator_broadcast_audio_update_safe(struct bt_cap_broadcast_source *broadcast_source, + const uint8_t meta[], size_t meta_len); + +/** + * @brief Stop broadcast audio streams for a Common Audio Profile broadcast source. + * + * @note @kconfig{CONFIG_BT_CAP_INITIATOR} and + * @kconfig{CONFIG_BT_BAP_BROADCAST_SOURCE} must be enabled for this function + * to be enabled. + * + * @param broadcast_source The broadcast source to stop. The audio streams + * in this will be stopped and reset. + * + * @return 0 on success or negative error value on failure. + */ +int bt_cap_initiator_broadcast_audio_stop_safe(struct bt_cap_broadcast_source *broadcast_source); + +/** + * @brief Delete Common Audio Profile broadcast source + * + * This can only be done after the broadcast source has been stopped by calling + * bt_cap_initiator_broadcast_audio_stop() and after the + * bt_bap_stream_ops.stopped() callback has been called for all streams in the + * broadcast source. + * + * @note @kconfig{CONFIG_BT_CAP_INITIATOR} and + * @kconfig{CONFIG_BT_BAP_BROADCAST_SOURCE} must be enabled for this function + * to be enabled. + * + * @param broadcast_source The broadcast source to delete. + * The @p broadcast_source will be invalidated. + * + * @return 0 on success or negative error value on failure. + */ +int bt_cap_initiator_broadcast_audio_delete_safe(struct bt_cap_broadcast_source *broadcast_source); + +/** + * @brief Get the Broadcast Audio Stream Endpoint of a Common Audio Profile broadcast source + * + * This will encode the BASE of a broadcast source into a buffer, that can be + * used for advertisement. The encoded BASE will thus be encoded as + * little-endian. The BASE shall be put into the periodic advertising data + * (see bt_le_per_adv_set_data()). + * + * See table 3.15 in the Basic Audio Profile v1.0.1 for the structure. + * + * @param broadcast_source Pointer to the broadcast source. + * @param base_buf Pointer to a buffer where the BASE will be inserted. + * + * @return int 0 if on success, errno on error. + */ +int bt_cap_initiator_broadcast_get_base_safe(struct bt_cap_broadcast_source *broadcast_source, + struct net_buf_simple *base_buf); + +/** Callback function for bt_cap_initiator_broadcast_foreach_stream() + * + * @param stream The audio stream + * @param user_data User data + * + * @retval true Stop iterating. + * @retval false Continue iterating. + */ +typedef bool (*bt_cap_initiator_broadcast_foreach_stream_func_t)(struct bt_cap_stream *stream, + void *user_data); + +/** + * @brief Iterate through all streams in a broadcast source + * + * @param broadcast_source The broadcast source. + * @param func The callback function. + * @param user_data User specified data that is sent to the callback function. + * + * @retval 0 Success (even if no streams exists in the group). + * @retval -ECANCELED The @p func returned true. + * @retval -EINVAL @p broadcast_source or @p func were NULL. + */ +int bt_cap_initiator_broadcast_foreach_stream_safe(struct bt_cap_broadcast_source *broadcast_source, + bt_cap_initiator_broadcast_foreach_stream_func_t func, + void *user_data); + +/** Parameters for bt_cap_handover_unicast_to_broadcast() */ +struct bt_cap_handover_unicast_to_broadcast_param { + /** The type of the set. */ + enum bt_cap_set_type type; + + /** The source unicast group with the streams. */ + struct bt_cap_unicast_group *unicast_group; + + /** + * @brief The advertising set to use for the broadcast source + * + * This shall remain valid until the procedure has completed. + * If the advertising set is not started at the time of calling + * bt_cap_handover_unicast_to_broadcast(), + * the procedure will start the advertising set with @ref BT_LE_EXT_ADV_START_DEFAULT. + */ + struct bt_le_ext_adv *ext_adv; + + /** The periodic advertising interval configured for the advertising set. */ + uint16_t pa_interval; + + /** The broadcast ID the advertising set is, or will be, using. */ + uint32_t broadcast_id; + + /** + * @brief Broadcast source parameters. + * + * These parameters shall remain valid until the procedure has completed. + */ + struct bt_cap_initiator_broadcast_create_param *broadcast_create_param; +}; + +/** Callback structure for CAP procedures */ +struct bt_cap_handover_cb { + /** + * @brief The unicast to broadcast handover procedure has finished + * + * @param err 0 if success else a negative errno value. + * @param conn Pointer to the connection where the error occurred or NULL if local failure. + * @param unicast_group NULL if the unicast group was deleted during the procedure, else + * pointer to the unicast group provided in the parameters. + * @param broadcast_source Pointer to newly created broadcast source, or NULL in case of an + * error happening before it was created. + */ + void (*unicast_to_broadcast_complete)(int err, struct bt_conn *conn, + struct bt_cap_unicast_group *unicast_group, + struct bt_cap_broadcast_source *broadcast_source); + + /** + * @brief The broadcast to unicast handover procedure has finished + * + * @param err 0 if success else a negative errno value. + * @param conn Pointer to the connection where the error occurred or NULL if local failure. + * @param broadcast_source NULL if the broadcast sourced was deleted during the procedure, + * else pointer to the broadcast sourced provided in the parameters. + * @param unicast_group Pointer to newly created unicast group, or NULL in case of an + * error happening before it was created. + */ + void (*broadcast_to_unicast_complete)(int err, struct bt_conn *conn, + struct bt_cap_broadcast_source *broadcast_source, + struct bt_cap_unicast_group *unicast_group); +}; + +/** + * @brief Register Common Audio Profile Handover callbacks + * + * @param cb The callback structure. Shall remain static. + * + * @return 0 on success or negative error value on failure. + */ +int bt_cap_handover_register_cb_safe(const struct bt_cap_handover_cb *cb); + +/** + * @brief Unregister Common Audio Profile Handover callbacks + * + * @param cb The callback structure that was previously registered. + * + * @retval 0 Success + * @retval -EINVAL @p cb is NULL or @p cb was not registered + */ +int bt_cap_handover_unregister_cb_safe(const struct bt_cap_handover_cb *cb); + +/** + * @brief Hands over the sink streams in a unicast group to a broadcast source. + * + * All streams in the provided unicast group will be stopped and released. The sink streams will be + * transferred to a broadcast source, and the broadcast source information will be shared with + * all accepters that are currently receiving audio. Any stream that is not in the streaming state + * will only be released. + * + * bt_bap_broadcast_assistant_discover() must have been successfully perform for all members in @p + * param before starting this procedure. + * + * @kconfig_dep{CONFIG_BT_CAP_HANDOVER} + * + * @param param The parameters for the handover. + * + * @return 0 on success or negative error value on failure. + */ +int bt_cap_handover_unicast_to_broadcast_safe( + const struct bt_cap_handover_unicast_to_broadcast_param *param); + +/** Parameters for bt_cap_handover_broadcast_to_unicast() */ +struct bt_cap_handover_broadcast_to_unicast_param { + /** + * @brief Parameters for stopping broadcast audio reception on acceptors + * + * This parameter is optional as stopping the broadcast audio should automatically stop + * broadcast audio reception on the acceptors. Omitting this parameter will rely on the CAP + * acceptors timing out on the BIG once it is stopped. The timeout on the CAP acceptors will + * be between @ref BT_ISO_SYNC_TIMEOUT_MIN and @ref BT_ISO_SYNC_TIMEOUT_MAX. + */ + struct bt_cap_commander_broadcast_reception_stop_param *reception_stop_param; + + /** @brief Broadcast ID of the @p broadcast_source + * + * Ignored if @p reception_stop_param is not NULL. + */ + uint32_t broadcast_id; + + /** @brief Advertising set ID of the @p broadcast_source + * + * Ignored if @p reception_stop_param is not NULL. + */ + uint8_t adv_sid; + + /** @brief Advertising type of the advertising address of @p broadcast_source + * + * Ignored if @p reception_stop_param is not NULL. + */ + uint8_t adv_type; + + /** + * @brief The source broadcast source with the streams. + * + * The broadcast source will be stopped and deleted. + */ + struct bt_cap_broadcast_source *broadcast_source; + + /* Parameters for the unicast group to be created */ + struct bt_cap_unicast_group_param *unicast_group_param; + + /* Parameters for starting the unicast audio */ + struct bt_cap_unicast_audio_start_param *unicast_start_param; +}; + +/** + * @brief Hands over the data streams in a broadcast source to a unicast group. + * + * The streams in the broadcast source will be stopped and the broadcast source + * will be deleted. + * + * @kconfig_dep{CONFIG_BT_CAP_HANDOVER} + * + * @param[in] param The parameters for the handover. + * + * @return 0 on success or negative error value on failure. + */ +int bt_cap_handover_broadcast_to_unicast_safe( + const struct bt_cap_handover_broadcast_to_unicast_param *param); + +/** Callback structure for CAP procedures */ +struct bt_cap_commander_cb { + /** + * @brief Callback for bt_cap_initiator_unicast_discover(). + * + * @param conn The connection pointer supplied to + * bt_cap_initiator_unicast_discover(). + * @param err 0 if Common Audio Service was found else -ENODATA. + * @param member Pointer to the set member. NULL if err != 0. + * @param csis_inst The Coordinated Set Identification Service if + * Common Audio Service was found and includes a + * Coordinated Set Identification Service. + * NULL on error or if remote device does not include + * Coordinated Set Identification Service. NULL if err != 0. + */ + void (*discovery_complete)(struct bt_conn *conn, int err, + const struct bt_csip_set_coordinator_set_member *member, + const struct bt_csip_set_coordinator_csis_inst *csis_inst); + + /** + * @brief Callback for bt_cap_commander_change_volume(). + * + * @param conn Pointer to the connection where the error + * occurred. NULL if @p err is 0 or if cancelled by + * bt_cap_commander_cancel() + * @param err 0 on success, BT_GATT_ERR() with a + * specific ATT (BT_ATT_ERR_*) error code or -ECANCELED if cancelled + * by bt_cap_commander_cancel(). + */ + void (*volume_changed)(struct bt_conn *conn, int err); + + /** + * @brief Callback for bt_cap_commander_change_volume_mute_state(). + * + * @param conn Pointer to the connection where the error + * occurred. NULL if @p err is 0 or if cancelled by + * bt_cap_commander_cancel() + * @param err 0 on success, BT_GATT_ERR() with a + * specific ATT (BT_ATT_ERR_*) error code or -ECANCELED if cancelled + * by bt_cap_commander_cancel(). + */ + void (*volume_mute_changed)(struct bt_conn *conn, int err); + + /** + * @brief Callback for bt_cap_commander_change_volume_offset(). + * + * @param conn Pointer to the connection where the error + * occurred. NULL if @p err is 0 or if cancelled by + * bt_cap_commander_cancel() + * @param err 0 on success, BT_GATT_ERR() with a + * specific ATT (BT_ATT_ERR_*) error code or -ECANCELED if cancelled + * by bt_cap_commander_cancel(). + */ + void (*volume_offset_changed)(struct bt_conn *conn, int err); + + /** + * @brief Callback for bt_cap_commander_change_microphone_mute_state(). + * + * @param conn Pointer to the connection where the error + * occurred. NULL if @p err is 0 or if cancelled by + * bt_cap_commander_cancel() + * @param err 0 on success, BT_GATT_ERR() with a + * specific ATT (BT_ATT_ERR_*) error code or -ECANCELED if cancelled + * by bt_cap_commander_cancel(). + */ + void (*microphone_mute_changed)(struct bt_conn *conn, int err); + + /** + * @brief Callback for bt_cap_commander_change_microphone_gain_setting(). + * + * @param conn Pointer to the connection where the error + * occurred. NULL if @p err is 0 or if cancelled by + * bt_cap_commander_cancel() + * @param err 0 on success, BT_GATT_ERR() with a + * specific ATT (BT_ATT_ERR_*) error code or -ECANCELED if cancelled + * by bt_cap_commander_cancel(). + */ + void (*microphone_gain_changed)(struct bt_conn *conn, int err); + + /** + * @brief Callback for bt_cap_commander_broadcast_reception_start(). + * + * @param conn Pointer to the connection where the error + * occurred. NULL if @p err is 0 or if cancelled by + * bt_cap_commander_cancel() + * @param err 0 on success, BT_GATT_ERR() with a + * specific ATT (BT_ATT_ERR_*) error code or -ECANCELED if cancelled + * by bt_cap_commander_cancel(). + */ + void (*broadcast_reception_start)(struct bt_conn *conn, int err); + /** + * @brief Callback for bt_cap_commander_broadcast_reception_stop(). + * + * @param conn Pointer to the connection where the error + * occurred. NULL if @p err is 0 or if cancelled by + * bt_cap_commander_cancel() + * @param err 0 on success, BT_GATT_ERR() with a + * specific ATT (BT_ATT_ERR_*) error code or -ECANCELED if cancelled + * by bt_cap_commander_cancel(). + */ + void (*broadcast_reception_stop)(struct bt_conn *conn, int err); + /** + * @brief Callback for bt_cap_commander_distribute_broadcast_code(). + * + * @param conn Pointer to the connection where the error + * occurred. NULL if @p err is 0 or if cancelled by + * bt_cap_commander_cancel() + * @param err 0 on success, BT_GATT_ERR() with a + * specific ATT (BT_ATT_ERR_*) error code or -ECANCELED if cancelled + * by bt_cap_commander_cancel(). + */ + void (*distribute_broadcast_code)(struct bt_conn *conn, int err); +}; + +/** + * @brief Register Common Audio Profile Commander callbacks + * + * @param cb The callback structure. Shall remain static. + * + * @retval 0 Success + * @retval -EINVAL @p cb is NULL + * @retval -EALREADY Callbacks are already registered + */ +int bt_cap_commander_register_cb_safe(const struct bt_cap_commander_cb *cb); + +/** + * @brief Unregister Common Audio Profile Commander callbacks + * + * @param cb The callback structure that was previously registered. + * + * @retval 0 Success + * @retval -EINVAL @p cb is NULL or @p cb was not registered + */ +int bt_cap_commander_unregister_cb_safe(const struct bt_cap_commander_cb *cb); + +/** + * @brief Discovers audio support on a remote device. + * + * This will discover the Common Audio Service (CAS) on the remote device, to + * verify if the remote device supports the Common Audio Profile. + * + * @note @kconfig{CONFIG_BT_CAP_COMMANDER} must be enabled for this function. If + * @kconfig{CONFIG_BT_CAP_INITIATOR} is also enabled, it does not matter if + * bt_cap_commander_discover() or bt_cap_initiator_unicast_discover() is used. + * + * @param conn Connection to a remote server. + * + * @retval 0 Success + * @retval -EINVAL @p conn is NULL + * @retval -ENOTCONN @p conn is not connected + * @retval -ENOMEM Could not allocated memory for the request + * @retval -EBUSY Already doing discovery for @p conn + */ +int bt_cap_commander_discover(struct bt_conn *conn); +int bt_cap_commander_discover_safe(struct bt_conn *conn); + +/** + * @brief Cancel any current Common Audio Profile commander procedure + * + * This will stop the current procedure from continuing and making it possible to run a new + * Common Audio Profile procedure. + * + * It is recommended to do this if any existing procedure takes longer time than expected, which + * could indicate a missing response from the Common Audio Profile Acceptor. + * + * This does not send any requests to any Common Audio Profile Acceptors involved with the + * current procedure, and thus notifications from the Common Audio Profile Acceptors may + * arrive after this has been called. It is thus recommended to either only use this if a + * procedure has stalled, or wait a short while before starting any new Common Audio Profile + * procedure after this has been called to avoid getting notifications from the cancelled + * procedure. The wait time depends on the connection interval, the number of devices in the + * previous procedure and the behavior of the Common Audio Profile Acceptors. + * + * The respective callbacks of the procedure will be called as part of this with the connection + * pointer set to NULL and the err value set to -ECANCELED. + * + * @retval 0 on success + * @retval -EALREADY if no procedure is active + */ +int bt_cap_commander_cancel_safe(void); + +/** + * Parameters part of @ref bt_cap_commander_broadcast_reception_start_param for + * bt_cap_commander_broadcast_reception_start() + */ +struct bt_cap_commander_broadcast_reception_start_member_param { + /** Coordinated or ad-hoc set member. */ + union bt_cap_set_member member; + + /** Address of the advertiser. */ + bt_addr_le_t addr; + + /** SID of the advertising set. */ + uint8_t adv_sid; + + /** + * @brief Periodic advertising interval in milliseconds. + * + * BT_BAP_PA_INTERVAL_UNKNOWN if unknown. + */ + uint16_t pa_interval; + + /** 24-bit broadcast ID */ + uint32_t broadcast_id; + + /** + * @brief Pointer to array of subgroups + * + * At least one bit in one of the subgroups bis_sync parameters shall be set. + */ + struct bt_bap_bass_subgroup *subgroups; + + /** Number of subgroups */ + size_t num_subgroups; +}; + +/** Parameters for starting broadcast reception */ +struct bt_cap_commander_broadcast_reception_start_param { + /** The type of the set. */ + enum bt_cap_set_type type; + + /** The set of devices for this procedure */ + struct bt_cap_commander_broadcast_reception_start_member_param *param; + + /** The number of parameters in @p param */ + size_t count; +}; + +/** + * @brief Starts the reception of broadcast audio on one or more remote Common Audio Profile + * Acceptors + * + * @param param The parameters to start the broadcast audio + * + * @return 0 on success or negative error value on failure. + */ +int bt_cap_commander_broadcast_reception_start_safe( + const struct bt_cap_commander_broadcast_reception_start_param *param); + +/** Member parameters for stopping broadcast reception */ +struct bt_cap_commander_broadcast_reception_stop_member_param { + /** Coordinated or ad-hoc set member. */ + union bt_cap_set_member member; + + /** Source ID of the receive state. */ + uint8_t src_id; + + /** Number of subgroups */ + size_t num_subgroups; +}; + +/** Parameters for stopping broadcast reception */ +struct bt_cap_commander_broadcast_reception_stop_param { + /** The type of the set. */ + enum bt_cap_set_type type; + + /** The set of devices for this procedure */ + struct bt_cap_commander_broadcast_reception_stop_member_param *param; + + /** The number of parameters in @p param */ + size_t count; +}; + +/** + * @brief Stops the reception of broadcast audio on one or more remote Common Audio Profile + * Acceptors + * + * @param param The parameters to stop the broadcast audio + * + * @return 0 on success or negative error value on failure. + */ +int bt_cap_commander_broadcast_reception_stop_safe( + const struct bt_cap_commander_broadcast_reception_stop_param *param); + +/** Member parameters for distributing broadcast code */ +struct bt_cap_commander_distribute_broadcast_code_member_param { + /** Coordinated or ad-hoc set member. */ + union bt_cap_set_member member; + + /** Source ID of the receive state. */ + uint8_t src_id; +}; + +/** Parameters for distributing broadcast code */ +struct bt_cap_commander_distribute_broadcast_code_param { + /** The type of the set. */ + enum bt_cap_set_type type; + + /** The set of devices for this procedure */ + struct bt_cap_commander_distribute_broadcast_code_member_param *param; + + /** The number of parameters in @p param */ + size_t count; + + /** + * @brief 16-octet broadcast code. + * + * If the value is a string or a the value is less than 16 octets, + * the remaining octets shall be 0. + * + * Example: + * The string "Broadcast Code" shall be + * [42 72 6F 61 64 63 61 73 74 20 43 6F 64 65 00 00] + */ + uint8_t broadcast_code[BT_ISO_BROADCAST_CODE_SIZE]; +}; + +/** + * @brief Distributes the broadcast code on one or more remote Common Audio Profile + * Acceptors + * + * @param param The parameters for distributing the broadcast code + * + * @return 0 on success or negative error value on failure. + */ +int bt_cap_commander_distribute_broadcast_code_safe( + const struct bt_cap_commander_distribute_broadcast_code_param *param); + +/** Parameters for changing absolute volume */ +struct bt_cap_commander_change_volume_param { + /** The type of the set. */ + enum bt_cap_set_type type; + + /** Coordinated or ad-hoc set member. */ + union bt_cap_set_member *members; + + /** The number of members in @p members */ + size_t count; + + /** The absolute volume to set */ + uint8_t volume; +}; + +/** + * @brief Change the volume on one or more Common Audio Profile Acceptors + * + * @param param The parameters for the volume change + * + * @return 0 on success or negative error value on failure. + */ +int bt_cap_commander_change_volume_safe(const struct bt_cap_commander_change_volume_param *param); + +/** + * Parameters part of @ref bt_cap_commander_change_volume_offset_param for + * bt_cap_commander_change_volume_offset() + */ +struct bt_cap_commander_change_volume_offset_member_param { + /** Coordinated or ad-hoc set member. */ + union bt_cap_set_member member; + + /** + * @brief The offset to set + * + * Value shall be between @ref BT_VOCS_MIN_OFFSET and @ref BT_VOCS_MAX_OFFSET + */ + int16_t offset; +}; + +/** Parameters for changing volume offset */ +struct bt_cap_commander_change_volume_offset_param { + /** The type of the set. */ + enum bt_cap_set_type type; + + /** The set of devices for this procedure */ + struct bt_cap_commander_change_volume_offset_member_param *param; + + /** The number of parameters in @p param */ + size_t count; +}; + +/** + * @brief Change the volume offset on one or more Common Audio Profile Acceptors + * + * @param param The parameters for the volume offset change + * + * @return 0 on success or negative error value on failure. + */ +int bt_cap_commander_change_volume_offset_safe( + const struct bt_cap_commander_change_volume_offset_param *param); + +/** Parameters for changing volume mute state */ +struct bt_cap_commander_change_volume_mute_state_param { + /** The type of the set. */ + enum bt_cap_set_type type; + + /** Coordinated or ad-hoc set member. */ + union bt_cap_set_member *members; + + /** The number of members in @p members */ + size_t count; + + /** + * @brief The volume mute state to set + * + * true to mute, and false to unmute + */ + bool mute; +}; + +/** + * @brief Change the volume mute state on one or more Common Audio Profile Acceptors + * + * @param param The parameters for the volume mute state change + * + * @return 0 on success or negative error value on failure. + */ +int bt_cap_commander_change_volume_mute_state_safe( + const struct bt_cap_commander_change_volume_mute_state_param *param); + +/** Parameters for changing microphone mute state */ +struct bt_cap_commander_change_microphone_mute_state_param { + /** The type of the set. */ + enum bt_cap_set_type type; + + /** Coordinated or ad-hoc set member. */ + union bt_cap_set_member *members; + + /** The number of members in @p members */ + size_t count; + + /** + * @brief The microphone mute state to set + * + * true to mute, and false to unmute + */ + bool mute; +}; + +/** + * @brief Change the microphone mute state on one or more Common Audio Profile Acceptors + * + * @param param The parameters for the microphone mute state change + * + * @return 0 on success or negative error value on failure. + */ +int bt_cap_commander_change_microphone_mute_state_safe( + const struct bt_cap_commander_change_microphone_mute_state_param *param); + +/** + * Parameters part of @ref bt_cap_commander_change_microphone_gain_setting_param for + * bt_cap_commander_change_microphone_gain_setting() + */ +struct bt_cap_commander_change_microphone_gain_setting_member_param { + /** Coordinated or ad-hoc set member. */ + union bt_cap_set_member member; + + /** @brief The microphone gain setting to set */ + int8_t gain; +}; + +/** Parameters for changing microphone mute state */ +struct bt_cap_commander_change_microphone_gain_setting_param { + /** The type of the set. */ + enum bt_cap_set_type type; + + /** The set of devices for this procedure */ + struct bt_cap_commander_change_microphone_gain_setting_member_param *param; + + /** The number of parameters in @p param */ + size_t count; +}; + +/** + * @brief Change the microphone gain setting on one or more Common Audio Profile Acceptors + * + * @param param The parameters for the microphone gain setting change + * + * @return 0 on success or negative error value on failure. + */ +int bt_cap_commander_change_microphone_gain_setting_safe( + const struct bt_cap_commander_change_microphone_gain_setting_param *param); +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_CAP_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/ccid.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/ccid.h new file mode 100644 index 0000000000..26448a929e --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/ccid.h @@ -0,0 +1,74 @@ +/** + * @file + * @brief Header for Bluetooth Audio Content Control Identifier. + * + * SPDX-FileCopyrightText: 2020 Bose Corporation + * SPDX-FileCopyrightText: 2021-2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_CCID_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_CCID_H_ + +/** + * @brief Bluetooth Content Control Identifier (CCID) + * @defgroup bt_ccid Bluetooth Content Control Identifier + * + * @since 3.7 + * @version 0.8.0 + * + * @ingroup bluetooth + * @{ + * + * The Content Control Identifier (CCID) API manages CCIDs for @ref BT_UUID_CCID characteristics. + */ + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Minimum CCID value */ +#define BT_CCID_MIN 0 +/** Maximum CCID value */ +#define BT_CCID_MAX 255 + +/** + * @brief Allocates a CCID value. + * + * This should always be called right before registering a GATT service that contains a + * @ref BT_UUID_CCID characteristic. Allocating a CCID without registering the characteristic + * may (in very rare cases) result in duplicated CCIDs on the device. + * + * Requires that @kconfig{CONFIG_BT_CONN} is enabled. + * + * @retval ccid 8-bit unsigned CCID value on success + * @retval -ENOMEM No more CCIDs can be allocated + */ +int bt_ccid_alloc_value(void); + +/** + * @brief Get the GATT attribute of a CCID value + * + * Searches the current GATT database for a CCID characteristic that has the supplied CCID value. + * + * Requires that @kconfig{CONFIG_BT_CONN} is enabled. + * + * @param ccid The CCID to search for + * + * @retval NULL None was found + * @retval attr Pointer to a GATT attribute + */ +const struct bt_gatt_attr *bt_ccid_find_attr(uint8_t ccid); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_CCID_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/ccp.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/ccp.h new file mode 100644 index 0000000000..ccd6db4be0 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/ccp.h @@ -0,0 +1,267 @@ +/** + * @file + * @brief Bluetooth Call Control Profile (CCP) APIs. + */ + +/* + * SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_CCP_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_CCP_H_ + +/** + * @brief Call Control Profile (CCP) + * + * @defgroup bt_ccp Call Control Profile (CCP) + * + * @since 3.7 + * @version 0.1.0 + * + * @ingroup bluetooth + * @{ + * + * Call Control Profile (CCP) provides procedures to initiate and control calls. + * It provides the Call Control Client and the Call Control Server roles, + * where the former is usually placed on resource constrained devices like headphones, + * and the latter placed on more powerful devices like phones and PCs. + * + * The profile is not limited to carrier phone calls and can be used with common applications like + * Discord and Teams. + */ + +#include + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif +/** + * @defgroup bt_ccp_call_control_server CCP Call Control Server APIs + * @ingroup bt_ccp + * @{ + */ +/** @brief Abstract Call Control Server Telephone Bearer structure. */ +struct bt_ccp_call_control_server_bearer; + +/** + * @brief Register a Telephone Bearer + * + * This will register a Telephone Bearer Service (TBS) (or a Generic Telephone Bearer service + * (GTBS)) with the provided parameters. + * + * As per the TBS specification, the GTBS shall be instantiated for the feature, + * and as such a GTBS shall always be registered before any TBS can be registered. + * Similarly, all TBS shall be unregistered before the GTBS can be unregistered with + * bt_ccp_call_control_server_unregister_bearer(). + * + * @param[in] param The parameters to initialize the bearer. + * @param[out] bearer Pointer to the initialized bearer. + * + * @retval 0 Success + * @retval -EINVAL @p param contains invalid data + * @retval -EALREADY @p param.gtbs is true and GTBS has already been registered + * @retval -EAGAIN @p param.gtbs is false and GTBS has not been registered + * @retval -ENOMEM @p param.gtbs is false and no more TBS can be registered (see + * @kconfig{CONFIG_BT_TBS_BEARER_COUNT}) + * @retval -ENOEXEC The service failed to be registered + */ +int bt_ccp_call_control_server_register_bearer_safe(const struct bt_tbs_register_param *param, + struct bt_ccp_call_control_server_bearer **bearer); + +/** + * @brief Unregister a Telephone Bearer + * + * This will unregister a Telephone Bearer Service (TBS) (or a Generic Telephone Bearer service + * (GTBS)) with the provided parameters. The bearer shall be registered first by + * bt_ccp_call_control_server_register_bearer() before it can be unregistered. + * + * All TBS shall be unregistered before the GTBS can be unregistered with. + * + * @param bearer The bearer to unregister. + * + * @retval 0 Success + * @retval -EINVAL @p bearer is NULL + * @retval -EALREADY The bearer is not registered + * @retval -ENOEXEC The service failed to be unregistered + */ +int bt_ccp_call_control_server_unregister_bearer_safe(struct bt_ccp_call_control_server_bearer *bearer); + +/** + * @brief Set a new bearer provider name. + * + * @param bearer The bearer to set the name for. + * @param name The new bearer provider name. + * + * @retval 0 Success + * @retval -EINVAL @p bearer or @p name is NULL, or @p name is the empty string or @p name is larger + * than @kconfig{CONFIG_BT_TBS_MAX_PROVIDER_NAME_LENGTH} + * @retval -EFAULT @p bearer is not registered + */ +int bt_ccp_call_control_server_set_bearer_provider_name_safe( + struct bt_ccp_call_control_server_bearer *bearer, const char *name); + +/** + * @brief Get the bearer provider name. + * + * @param[in] bearer The bearer to get the name for. + * @param[out] name Pointer that will be updated to be the bearer provider name. + * + * @retval 0 Success + * @retval -EINVAL @p bearer or @p name is NULL + * @retval -EFAULT @p bearer is not registered + */ +int bt_ccp_call_control_server_get_bearer_provider_name_safe( + struct bt_ccp_call_control_server_bearer *bearer, const char **name); + +/** @} */ /* End of group bt_ccp_call_control_server */ + +/** + * @defgroup bt_ccp_call_control_client CCP Call Control Client APIs + * @ingroup bt_ccp + * @{ + */ +/** Abstract Call Control Client structure. */ +struct bt_ccp_call_control_client; + +/** Abstract Call Control Client bearer structure. */ +struct bt_ccp_call_control_client_bearer; + +/** Struct with information about bearers of a client */ +struct bt_ccp_call_control_client_bearers { + /** The GTBS bearer. */ + struct bt_ccp_call_control_client_bearer *gtbs_bearer; + + /** Number of TBS bearers in @p tbs_bearers */ + size_t tbs_count; + + /** Array of pointers of TBS bearers */ + struct bt_ccp_call_control_client_bearer **tbs_bearers; +}; + +/** + * @brief Struct to hold the Telephone Bearer Service client callbacks + * + * These can be registered for usage with bt_tbs_client_register_cb(). + */ +struct bt_ccp_call_control_client_cb { + /** + * @brief Callback function for bt_ccp_call_control_client_discover(). + * + * This callback is called once the discovery procedure is completed. + * + * @param client Call Control Client pointer. + * @param err Error value. 0 on success, GATT error on positive + * value or errno on negative value. + * @param bearers The bearers found. + */ + void (*discover)(struct bt_ccp_call_control_client *client, int err, + struct bt_ccp_call_control_client_bearers *bearers); + + /** + * @brief Callback function for bt_ccp_call_control_client_read_bearer_provider_name(). + * + * This callback is called once the read bearer provider name procedure is completed. + * + * @param client Call Control Client instance pointer. + * @param err Error value. 0 on success, GATT error on positive + * value or errno on negative value. + * @param name The bearer provider name. NULL if @p err is not 0. + */ + void (*bearer_provider_name)(struct bt_ccp_call_control_client_bearer *bearer, int err, + const char *name); + + /** @cond INTERNAL_HIDDEN */ + /** Internally used field for list handling */ + sys_snode_t _node; + /** @endcond */ +}; + +/** + * @brief Discovers the Telephone Bearer Service (TBS) support on a remote device. + * + * This will discover the Telephone Bearer Service (TBS) and Generic Telephone Bearer Service (GTBS) + * on the remote device. + * + * @kconfig_dep{CONFIG_BT_CCP_CALL_CONTROL_CLIENT}. + * + * @param conn Connection to a remote server. + * @param out_client Pointer to client instance on success + * + * @retval 0 Success + * @retval -EINVAL @p conn or @p out_client is NULL + * @retval -ENOTCONN @p conn is not connected + * @retval -ENOMEM Could not allocated memory for the request + * @retval -EBUSY Already doing discovery for @p conn + * @retval -ENOEXEC Rejected by the GATT layer + */ +int bt_ccp_call_control_client_discover_safe(struct bt_conn *conn, + struct bt_ccp_call_control_client **out_client); + +/** + * @brief Register callbacks for the Call Control Client + * + * @param cb The callback struct + * + * @retval 0 Success + * @retval -EINVAL @p cb is NULL + * @retval -EEXISTS @p cb is already registered + */ +int bt_ccp_call_control_client_register_cb_safe(struct bt_ccp_call_control_client_cb *cb); + +/** + * @brief Unregister callbacks for the Call Control Client + * + * @param cb The callback struct + * + * @retval 0 Success + * @retval -EINVAL @p cb is NULL + * @retval -EALREADY @p cb is not registered + */ +int bt_ccp_call_control_client_unregister_cb_safe(struct bt_ccp_call_control_client_cb *cb); + +/** + * @brief Get the bearers of a client instance + * + * @param[in] client The client to get the bearers of. + * @param[out] bearers The bearers struct that will be populated with the bearers of @p client. + + * @retval 0 Success + * @retval -EINVAL @p client or @p bearers is NULL + */ +int bt_ccp_call_control_client_get_bearers_safe(struct bt_ccp_call_control_client *client, + struct bt_ccp_call_control_client_bearers *bearers); + +/** + * @brief Read the bearer provider name of a remote TBS bearer. + * + * @kconfig_dep{CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME} + * + * @param bearer The bearer to read the name from + * + * @retval 0 Success + * @retval -EINVAL @p bearer is NULL + * @retval -EFAULT @p bearer has not been discovered + * @retval -EEXIST A @ref bt_ccp_call_control_client could not be identified for @p bearer + * @retval -EBUSY The @ref bt_ccp_call_control_client identified by @p bearer is busy, or the TBS + * instance of @p bearer is busy. + * @retval -ENOTCONN The @ref bt_ccp_call_control_client identified by @p bearer is not connected + */ +int bt_ccp_call_control_client_read_bearer_provider_name_safe( + struct bt_ccp_call_control_client_bearer *bearer); +/** @} */ /* End of group bt_ccp_call_control_client */ +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_CCP_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/csip.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/csip.h new file mode 100644 index 0000000000..166f5ad84e --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/csip.h @@ -0,0 +1,607 @@ +/** + * @file + * @brief Bluetooth Coordinated Set Identification Profile (CSIP) APIs. + */ + +/* + * SPDX-FileCopyrightText: 2021-2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SUBSYS_BLUETOOTH_AUDIO_CSIP_H_ +#define ZEPHYR_SUBSYS_BLUETOOTH_AUDIO_CSIP_H_ + +/** + * @brief Coordinated Set Identification Profile (CSIP) + * + * @defgroup bt_csip Coordinated Set Identification Profile (CSIP) + * + * @since 3.0 + * @version 0.8.0 + * + * @ingroup bluetooth + * @{ + * + * The Coordinated Set Identification Profile (CSIP) provides procedures to discover and coordinate + * sets of devices. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Recommended timer for member discovery */ +#define BT_CSIP_SET_COORDINATOR_DISCOVER_TIMER_VALUE K_SECONDS(10) + +/** Accept the request to read the SIRK as plaintext */ +#define BT_CSIP_READ_SIRK_REQ_RSP_ACCEPT 0x00 +/** Accept the request to read the SIRK, but return encrypted SIRK */ +#define BT_CSIP_READ_SIRK_REQ_RSP_ACCEPT_ENC 0x01 +/** Reject the request to read the SIRK */ +#define BT_CSIP_READ_SIRK_REQ_RSP_REJECT 0x02 +/** SIRK is available only via an OOB procedure */ +#define BT_CSIP_READ_SIRK_REQ_RSP_OOB_ONLY 0x03 + +/** Size of the Set Identification Resolving Key (SIRK) */ +#define BT_CSIP_SIRK_SIZE 16 + +/** Size of the Resolvable Set Identifier (RSI) */ +#define BT_CSIP_RSI_SIZE 6 + +/* Coordinate Set Identification Service Error codes */ +/** Service is already locked */ +#define BT_CSIP_ERROR_LOCK_DENIED 0x80 +/** Service is not locked */ +#define BT_CSIP_ERROR_LOCK_RELEASE_DENIED 0x81 +/** Invalid lock value */ +#define BT_CSIP_ERROR_LOCK_INVAL_VALUE 0x82 +/** SIRK only available out-of-band */ +#define BT_CSIP_ERROR_SIRK_OOB_ONLY 0x83 +/** Client is already owner of the lock */ +#define BT_CSIP_ERROR_LOCK_ALREADY_GRANTED 0x84 + +/** + * @brief Helper to declare bt_data array including RSI + * + * This macro is mainly for creating an array of struct bt_data + * elements which is then passed to e.g. @ref bt_le_ext_adv_start(). + * + * @param _rsi Pointer to the RSI value + */ +#define BT_CSIP_DATA_RSI(_rsi) BT_DATA(BT_DATA_CSIS_RSI, _rsi, BT_CSIP_RSI_SIZE) + +/** @brief Opaque Coordinated Set Identification Service instance. */ +struct bt_csip_set_member_svc_inst; + +/** Callback structure for the Coordinated Set Identification Service */ +struct bt_csip_set_member_cb { + /** + * @brief Callback whenever the lock changes on the server. + * + * @param conn The connection to the client that changed the lock. + * NULL if server changed it, either by calling + * bt_csip_set_member_lock() or by timeout. + * @param svc_inst Pointer to the Coordinated Set Identification + * Service. + * @param locked Whether the lock was locked or released. + * + */ + void (*lock_changed)(struct bt_conn *conn, + struct bt_csip_set_member_svc_inst *svc_inst, + bool locked); + + /** + * @brief Request from a peer device to read the sirk. + * + * If this callback is not set, all clients will be allowed to read + * the SIRK unencrypted. + * + * @param conn The connection to the client that requested to read + * the SIRK. + * @param svc_inst Pointer to the Coordinated Set Identification + * Service. + * + * @return A BT_CSIP_READ_SIRK_REQ_RSP_* response code. + */ + uint8_t (*sirk_read_req)(struct bt_conn *conn, + struct bt_csip_set_member_svc_inst *svc_inst); +}; + +/** Register structure for Coordinated Set Identification Service */ +struct bt_csip_set_member_register_param { + /** + * @brief Size of the set. + * + * If set to 0, the set size characteristic won't be initialized. + */ + uint8_t set_size; + + /** + * @brief The unique Set Identity Resolving Key (SIRK) + * + * This shall be unique between different sets, and shall be the same + * for each set member for each set. + */ + uint8_t sirk[BT_CSIP_SIRK_SIZE]; + + /** + * @brief Boolean to set whether the set is lockable by clients + * + * Setting this to false will disable the lock characteristic. + */ + bool lockable; + + /** + * @brief Rank of this device in this set. + * + * If the lockable parameter is set to true, this shall be > 0 and + * <= to the set_size. If the lockable parameter is set to false, this + * may be set to 0 to disable the rank characteristic. + */ + uint8_t rank; + + /** Pointer to the callback structure. */ + struct bt_csip_set_member_cb *cb; + + /** + * @brief Parent service pointer + * + * Mandatory parent service pointer if this CSIS instance is included + * by another service. All CSIS instances when + * @kconfig{CONFIG_BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT} is above 1 + * shall be included by another service, as per the + * Coordinated Set Identification Profile (CSIP). + */ + const struct bt_gatt_service *parent; +}; + +/** + * @brief Get the service declaration attribute. + * + * The first service attribute can be included in any other GATT service. + * + * @param svc_inst Pointer to the Coordinated Set Identification Service. + * + * @return The first CSIS attribute instance. + */ +void *bt_csip_set_member_svc_decl_get_safe(const struct bt_csip_set_member_svc_inst *svc_inst); + +/** + * @brief Register a Coordinated Set Identification Service instance. + * + * This will register and enable the service and make it discoverable by + * clients. + * + * This shall only be done as a server. + * + * @param param Coordinated Set Identification Service register + * parameters. + * @param[out] svc_inst Pointer to the registered Coordinated Set + * Identification Service. + * + * @return 0 if success, errno on failure. + */ +int bt_csip_set_member_register_safe(const struct bt_csip_set_member_register_param *param, + struct bt_csip_set_member_svc_inst **svc_inst); + +/** + * @brief Unregister a Coordinated Set Identification Service instance. + * + * This will unregister and disable the service instance. + * + * @param svc_inst Pointer to the registered Coordinated Set Identification Service. + * + * @return 0 if success, errno on failure. + */ +int bt_csip_set_member_unregister_safe(struct bt_csip_set_member_svc_inst *svc_inst); + +/** + * @brief Set the SIRK of a service instance + * + * @param svc_inst Pointer to the registered Coordinated Set Identification Service. + * @param sirk The new SIRK. + */ +int bt_csip_set_member_sirk_safe(struct bt_csip_set_member_svc_inst *svc_inst, + const uint8_t sirk[BT_CSIP_SIRK_SIZE]); + +/** + * @brief Set a new size and rank for a service instance + * + * This function can be used to dynamically change the size and rank of a service instance. + * It is important to note that a set cannot have multiple devices with the same rank in a set, + * and it is up to the caller of this function to ensure that. + * Similarly, it is important that the size is updated on all devices in the set at the same time. + * + * If @kconfig{CONFIG_BT_CSIP_SET_MEMBER_SIZE_NOTIFIABLE} is enabled, this will also send a + * notification to all connected or bonded clients. + * + * @param svc_inst The service instance. + * @param size The new set size. + * @param rank The new rank. Ignored if the @p svc_inst is not lockable. + * + * @retval -EINVAL @p svc_inst is NULL, @p size is less than 1, @p rank is less than 1 or higher + * than @p size for a lockable @p svc_inst. + * @retval -EALREADY @p size and @p rank are already the provided values. + * @retval 0 Success. + */ +int bt_csip_set_member_set_size_and_rank_safe(struct bt_csip_set_member_svc_inst *svc_inst, uint8_t size, + uint8_t rank); + +/** Struct to hold information about a service instance */ +struct bt_csip_set_member_set_info { + /** The 16-octet SIRK */ + uint8_t sirk[BT_CSIP_SIRK_SIZE]; + + /** The set size */ + uint8_t set_size; + + /** + * @brief The rank + * + * May be 0 if the set is not lockable + */ + uint8_t rank; + + /** Whether the set is lockable */ + bool lockable: 1; + + /** Whether the set is currently locked */ + bool locked: 1; + + /** + * @brief The address of the client that currently holds the lock + * + * Will be @ref BT_ADDR_LE_NONE if the server holds the lock + */ + bt_addr_le_t lock_client_addr; +}; + +/** + * @brief Get information about a service instances + * + * @param svc_inst The service instance. + * @param info Pointer to a struct to store the information in. + * + * @retval -EINVAL @p svc_inst or @p info is NULL. + * @retval 0 Success. + */ +int bt_csip_set_member_get_info_safe(const struct bt_csip_set_member_svc_inst *svc_inst, + struct bt_csip_set_member_set_info *info); + +/** + * @brief Generate the Resolvable Set Identifier (RSI) value. + * + * This will generate RSI for given @p svc_inst instance. + * + * @param svc_inst Pointer to the Coordinated Set Identification Service. + * @param rsi Pointer to the 6-octet newly generated RSI data in little-endian. + * + * @return int 0 if on success, errno on error. + */ +int bt_csip_set_member_generate_rsi_safe(const struct bt_csip_set_member_svc_inst *svc_inst, + uint8_t rsi[BT_CSIP_RSI_SIZE]); + +/** + * @brief Locks a specific Coordinated Set Identification Service instance on the server. + * + * @param svc_inst Pointer to the Coordinated Set Identification Service. + * @param lock If true lock the set, if false release the set. + * @param force This argument only have meaning when @p lock is false + * (release) and will force release the lock, regardless of who + * took the lock. + * + * @return 0 on success, GATT error on error. + */ +int bt_csip_set_member_lock_safe(struct bt_csip_set_member_svc_inst *svc_inst, + bool lock, bool force); + +/** Information about a specific set */ +struct bt_csip_set_coordinator_set_info { + /** + * @brief The 16 octet set Set Identity Resolving Key (SIRK) + * + * The SIRK may not be exposed by the server over Bluetooth, and + * may require an out-of-band solution. + */ + uint8_t sirk[BT_CSIP_SIRK_SIZE]; + + /** + * @brief The size of the set + * + * Will be 0 if not exposed by the server. + */ + uint8_t set_size; + + /** + * @brief The rank of the set on the remote device + * + * Will be 0 if not exposed by the server. + */ + uint8_t rank; + + /** Whether or not the set can be locked on this device */ + bool lockable; +}; + +/** + * @brief Struct representing a coordinated set instance on a remote device + * + * The values in this struct will be populated during discovery of sets + * (bt_csip_set_coordinator_discover()). + */ +struct bt_csip_set_coordinator_csis_inst { + /** Information about the coordinated set */ + struct bt_csip_set_coordinator_set_info info; + + /** Internally used pointer value */ + void *svc_inst; +}; + +/** Struct representing a remote device as a set member */ +struct bt_csip_set_coordinator_set_member { + /** Array of Coordinated Set Identification Service instances for the remote device */ + struct bt_csip_set_coordinator_csis_inst *insts; +}; + +/** + * @typedef bt_csip_set_coordinator_discover_cb + * @brief Callback for discovering Coordinated Set Identification Services. + * + * @param conn Pointer to the remote device. + * @param member Pointer to the set member. + * @param err 0 on success, or an errno value on error. + * @param set_count Number of sets on the member. + */ +typedef void (*bt_csip_set_coordinator_discover_cb)( + struct bt_conn *conn, + const struct bt_csip_set_coordinator_set_member *member, + int err, size_t set_count); + +/** + * @brief Initialise the csip_set_coordinator instance for a connection. This will do a + * discovery on the device and prepare the instance for following commands. + * + * @param conn Pointer to remote device to perform discovery on. + * + * @return int Return 0 on success, or an errno value on error. + */ +int bt_csip_set_coordinator_discover(struct bt_conn *conn); +int bt_csip_set_coordinator_discover_safe(struct bt_conn *conn); + +/** + * @brief Get the set member from a connection pointer + * + * Get the Coordinated Set Identification Profile Set Coordinator pointer from a connection pointer. + * Only Set Coordinators that have been initiated via bt_csip_set_coordinator_discover() can be + * retrieved. + * + * @param conn Connection pointer. + * + * @retval Pointer to a Coordinated Set Identification Profile Set Coordinator instance + * @retval NULL if @p conn is NULL or if the connection has not done discovery yet + */ +struct bt_csip_set_coordinator_set_member * +bt_csip_set_coordinator_set_member_by_conn(const struct bt_conn *conn); +struct bt_csip_set_coordinator_set_member * +bt_csip_set_coordinator_set_member_by_conn_safe(const struct bt_conn *conn); + +/** + * @typedef bt_csip_set_coordinator_lock_set_cb + * @brief Callback for locking a set across one or more devices + * + * @param err 0 on success, or an errno value on error. + */ +typedef void (*bt_csip_set_coordinator_lock_set_cb)(int err); + +/** + * @typedef bt_csip_set_coordinator_lock_changed_cb + * @brief Callback when the lock value on a set of a connected device changes. + * + * @param inst The Coordinated Set Identification Service instance that was + * changed. + * @param locked Whether the lock is locked or release. + * + * @return int Return 0 on success, or an errno value on error. + */ +typedef void (*bt_csip_set_coordinator_lock_changed_cb)( + struct bt_csip_set_coordinator_csis_inst *inst, bool locked); + +/** + * @typedef bt_csip_set_coordinator_sirk_changed_cb + * @brief Callback when the SIRK value of a set of a connected device changes. + * + * @param inst The Coordinated Set Identification Service instance that was changed. + * The new SIRK can be accessed via the @p inst.info. + */ +typedef void (*bt_csip_set_coordinator_sirk_changed_cb)( + struct bt_csip_set_coordinator_csis_inst *inst); + +/** + * @typedef bt_csip_set_coordinator_size_changed_cb + * @brief Callback when the size of a set of a connected device changes. + * + * Since all devices in a set shall have the same set size value. + * Each connected device may send the same new size set in a notification, + * assuming that the remote device supports notifications of the set size. + * + * The rank of each device in the set may also change as part of this, so it is advisable to call + * bt_csip_set_coordinator_discover() to rediscover and read the characteristic values of the sets + * on each device. + * + * @param inst The Coordinated Set Identification Service instance that was changed. + * The new size is stored in the @p inst->info.size. + */ +typedef void (*bt_csip_set_coordinator_size_changed_cb)( + struct bt_conn *conn, const struct bt_csip_set_coordinator_csis_inst *inst); + +/** + * @typedef bt_csip_set_coordinator_ordered_access_cb_t + * @brief Callback for bt_csip_set_coordinator_ordered_access() + * + * If any of the set members supplied to bt_csip_set_coordinator_ordered_access() is + * in the locked state, this will be called with @p locked true and @p member + * will be the locked member, and the ordered access procedure is cancelled. + * Likewise, if any error occurs, the procedure will also be aborted. + * + * @param set_info Pointer to the a specific set_info struct. + * @param err Error value. 0 on success, GATT error or errno on fail. + * @param locked Whether the lock is locked or release. + * @param member The locked member if @p locked is true, otherwise NULL. + */ +typedef void (*bt_csip_set_coordinator_ordered_access_cb_t)( + const struct bt_csip_set_coordinator_set_info *set_info, + int err, bool locked, + struct bt_csip_set_coordinator_set_member *member); + +/** + * @brief Struct to hold the Coordinated Set Identification Profile Set Coordinator callbacks + * + * These can be registered for usage with bt_csip_set_coordinator_register_cb(). + */ +struct bt_csip_set_coordinator_cb { + /** Callback when discovery has finished */ + bt_csip_set_coordinator_discover_cb discover; + /** Callback when locking a set has finished */ + bt_csip_set_coordinator_lock_set_cb lock_set; + /** Callback when unlocking a set has finished */ + bt_csip_set_coordinator_lock_set_cb release_set; + /** Callback when a set's lock state has changed */ + bt_csip_set_coordinator_lock_changed_cb lock_changed; + /** Callback when a set's SIRK has changed */ + bt_csip_set_coordinator_sirk_changed_cb sirk_changed; + /** Callback when a set's size has changed */ + bt_csip_set_coordinator_size_changed_cb size_changed; + /** Callback for the ordered access procedure */ + bt_csip_set_coordinator_ordered_access_cb_t ordered_access; + + /** @cond INTERNAL_HIDDEN */ + /** Internally used field for list handling */ + sys_snode_t _node; + /** @endcond */ +}; + +/** + * @brief Check if advertising data indicates a set member + * + * @param sirk The SIRK of the set to check against + * @param data The advertising data + * + * @return true if the advertising data indicates a set member, false otherwise + */ +bool bt_csip_set_coordinator_is_set_member_safe(const uint8_t sirk[BT_CSIP_SIRK_SIZE], + struct bt_data *data); + +/** + * @brief Registers callbacks for csip_set_coordinator. + * + * @param cb Pointer to the callback structure. + * + * @return Return 0 on success, or an errno value on error. + */ +int bt_csip_set_coordinator_register_cb_safe(struct bt_csip_set_coordinator_cb *cb); + +/** + * @brief Callback function definition for bt_csip_set_coordinator_ordered_access() + * + * @param set_info Pointer to the a specific set_info struct. + * @param members Array of members ordered by rank. The procedure shall be + * done on the members in ascending order. + * @param count Number of members in @p members. + * + * @return true if the procedures can be successfully done, or false to stop the + * procedure. + */ +typedef bool (*bt_csip_set_coordinator_ordered_access_t)( + const struct bt_csip_set_coordinator_set_info *set_info, + struct bt_csip_set_coordinator_set_member *members[], + size_t count); + +/** + * @brief Access Coordinated Set devices in an ordered manner as a client + * + * This function will read the lock state of all devices and if all devices are + * in the unlocked state, then @p cb will be called with the same members as + * provided by @p members, but where the members are ordered by rank + * (if present). Once this procedure is finished or an error occurs, + * @ref bt_csip_set_coordinator_cb.ordered_access will be called. + * + * This procedure only works if all the members have the lock characteristic, + * and all either has rank = 0 or unique ranks. + * + * If any of the members are in the locked state, the procedure will be + * cancelled. + * + * This can only be done on members that are bonded. + * + * @param members Array of set members to access. + * @param count Number of set members in @p members. + * @param set_info Pointer to the a specific set_info struct, as a member may + * be part of multiple sets. + * @param cb The callback function to be called for each member. + */ +int bt_csip_set_coordinator_ordered_access_safe( + const struct bt_csip_set_coordinator_set_member *members[], + uint8_t count, + const struct bt_csip_set_coordinator_set_info *set_info, + bt_csip_set_coordinator_ordered_access_t cb); + +/** + * @brief Lock an array of set members + * + * The members will be locked starting from lowest rank going up. + * + * @kconfig_dep{CONFIG_BT_CSIP_SET_COORDINATOR,CONFIG_BT_BONDABLE} + * + * TODO: If locking fails, the already locked members will not be unlocked. + * + * @param members Array of set members to lock. + * @param count Number of set members in @p members. + * @param set_info Pointer to the a specific set_info struct, as a member may + * be part of multiple sets. + * + * @return Return 0 on success, or an errno value on error. + */ +int bt_csip_set_coordinator_lock_safe(const struct bt_csip_set_coordinator_set_member **members, + uint8_t count, + const struct bt_csip_set_coordinator_set_info *set_info); + +/** + * @brief Release an array of set members + * + * The members will be released starting from highest rank going down. + * + * @kconfig_dep{CONFIG_BT_CSIP_SET_COORDINATOR,CONFIG_BT_BONDABLE} + * + * @param members Array of set members to lock. + * @param count Number of set members in @p members. + * @param set_info Pointer to the a specific set_info struct, as a member may + * be part of multiple sets. + * + * @return Return 0 on success, or an errno value on error. + */ +int bt_csip_set_coordinator_release_safe(const struct bt_csip_set_coordinator_set_member **members, + uint8_t count, + const struct bt_csip_set_coordinator_set_info *set_info); + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_SUBSYS_BLUETOOTH_AUDIO_CSIP_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/gmap.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/gmap.h new file mode 100644 index 0000000000..a9a65cfa04 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/gmap.h @@ -0,0 +1,248 @@ +/** + * @file + * @brief Header for Bluetooth Gaming Audio Profile (GMAP). + * + * SPDX-FileCopyrightText: 2023-2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_GMAP_ +#define ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_GMAP_ + +/** + * @brief Bluetooth Gaming Audio Profile (GMAP) + * + * @defgroup bt_gmap Bluetooth Gaming Audio Profile + * + * @since 3.5 + * @version 0.8.0 + * + * @ingroup bluetooth + * @{ + */ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Gaming Role bitfield */ +enum bt_gmap_role { + /** + * @brief Gaming Role Unicast Game Gateway + * + * Requires @kconfig{CONFIG_BT_CAP_INITIATOR}, @kconfig{CONFIG_BT_BAP_UNICAST_CLIENT} and + * @kconfig{CONFIG_BT_VCP_VOL_CTLR} to be enabled. + */ + BT_GMAP_ROLE_UGG = BIT(0), + /** + * @brief Gaming Role Unicast Game Terminal + * + * Requires @kconfig{CONFIG_BT_CAP_ACCEPTOR} and @kconfig{CONFIG_BT_BAP_UNICAST_SERVER} to + * be enabled. + */ + BT_GMAP_ROLE_UGT = BIT(1), + /** + * @brief Gaming Role Broadcast Game Sender + * + * Requires @kconfig{CONFIG_BT_CAP_INITIATOR} and @kconfig{CONFIG_BT_BAP_BROADCAST_SOURCE} + * to be enabled. + */ + BT_GMAP_ROLE_BGS = BIT(2), + /** + * @brief Gaming Role Broadcast Game Receiver + * + * Requires @kconfig{CONFIG_BT_CAP_ACCEPTOR}, @kconfig{CONFIG_BT_BAP_BROADCAST_SINK} and + * @kconfig{CONFIG_BT_VCP_VOL_REND} to be enabled. + */ + BT_GMAP_ROLE_BGR = BIT(3), +}; + +/** Unicast Game Gateway Feature bitfield */ +enum bt_gmap_ugg_feat { + /** + * @brief Support transmitting multiple LC3 codec frames per block in an SDU + * + * Requires @kconfig{CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT} > 0 + */ + BT_GMAP_UGG_FEAT_MULTIPLEX = BIT(0), + /** + * @brief 96 kbps source support + * + * Requires @kconfig{CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT} > 0 + */ + BT_GMAP_UGG_FEAT_96KBPS_SOURCE = BIT(1), + /** + * @brief Support for receiving at least two channels of audio, each in a separate CIS + * + * Requires @kconfig{CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT} > 1 and + * @kconfig{CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT} > 1 + */ + BT_GMAP_UGG_FEAT_MULTISINK = BIT(2), +}; + +/** Unicast Game Terminal Feature bitfield */ +enum bt_gmap_ugt_feat { + /** + * @brief Source support + * + * Requires @kconfig{CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT} > 0 + */ + BT_GMAP_UGT_FEAT_SOURCE = BIT(0), + /** + * @brief 80 kbps source support + * + * Requires BT_GMAP_UGT_FEAT_SOURCE to be set as well + */ + BT_GMAP_UGT_FEAT_80KBPS_SOURCE = BIT(1), + /** + * @brief Sink support + * + * Requires @kconfig{CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT} > 0 + */ + BT_GMAP_UGT_FEAT_SINK = BIT(2), + /** + * @brief 64 kbps sink support + * + * Requires BT_GMAP_UGT_FEAT_SINK to be set as well + */ + BT_GMAP_UGT_FEAT_64KBPS_SINK = BIT(3), + /** + * @brief Support for receiving multiple LC3 codec frames per block in an SDU + * + * Requires BT_GMAP_UGT_FEAT_SINK to be set as well + */ + BT_GMAP_UGT_FEAT_MULTIPLEX = BIT(4), + /** + * @brief Support for receiving at least two audio channels, each in a separate CIS + * + * Requires @kconfig{CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT} > 1 and + * @kconfig{CONFIG_BT_ASCS_MAX_ACTIVE_ASES} > 1, and BT_GMAP_UGT_FEAT_SINK to be set as well + */ + BT_GMAP_UGT_FEAT_MULTISINK = BIT(5), + /** + * @brief Support for sending at least two audio channels, each in a separate CIS + * + * Requires @kconfig{CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT} > 1 and + * @kconfig{CONFIG_BT_ASCS_MAX_ACTIVE_ASES} > 1, and BT_GMAP_UGT_FEAT_SOURCE to be set + * as well + */ + BT_GMAP_UGT_FEAT_MULTISOURCE = BIT(6), +}; + +/** Broadcast Game Sender Feature bitfield */ +enum bt_gmap_bgs_feat { + /** 96 kbps support */ + BT_GMAP_BGS_FEAT_96KBPS = BIT(0), +}; + +/** Broadcast Game Receiver Feature bitfield */ +enum bt_gmap_bgr_feat { + /** + * @brief Support for receiving at least two audio channels, each in a separate BIS + * + * Requires @kconfig{CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT} > 1 + */ + BT_GMAP_BGR_FEAT_MULTISINK = BIT(0), + /** @brief Support for receiving multiple LC3 codec frames per block in an SDU */ + BT_GMAP_BGR_FEAT_MULTIPLEX = BIT(1), +}; + +/** Broadcast Game Receiver Feature bitfield */ +struct bt_gmap_feat { + /** Unicast Game Gateway features */ + enum bt_gmap_ugg_feat ugg_feat; + /** Unicast Game Terminal features */ + enum bt_gmap_ugt_feat ugt_feat; + /** Remote Broadcast Game Sender features */ + enum bt_gmap_bgs_feat bgs_feat; + /** Remote Broadcast Game Receiver features */ + enum bt_gmap_bgr_feat bgr_feat; +}; + +/** @brief Hearing Access Service Client callback structure. */ +struct bt_gmap_cb { + /** + * @brief Callback function for bt_has_discover. + * + * This callback is called when discovery procedure is complete. + * + * @param conn Bluetooth connection object. + * @param err 0 on success, ATT error or negative errno otherwise. + * @param role Role of remote device. 0 on failure. + * @param features Remote features. + */ + void (*discover)(struct bt_conn *conn, int err, enum bt_gmap_role role, + struct bt_gmap_feat features); +}; + +/** + * @brief Registers the callbacks used by the Gaming Audio Profile. + * + * @param cb The callback structure. + * + * @retval -EINVAL if @p cb is NULL + * @retval -EALREADY if callbacks have already be registered + * @retval 0 on success + */ +int bt_gmap_cb_register_safe(const struct bt_gmap_cb *cb); + +/** + * @brief Discover Gaming Service on a remote device. + * + * Procedure to find a Gaming Service on a server identified by @p conn. + * The @ref bt_gmap_cb.discover callback is called when the discovery procedure completes of fails. + * On discovery success the callback contains information about the remote device. + * + * @param conn Bluetooth connection object. + * + * @retval -EINVAL if @p conn is NULL + * @retval -EBUSY if discovery is already in progress for @p conn + * @retval -ENOEXEC if discovery failed to initiate + * @retval 0 on success + */ +int bt_gmap_discover(struct bt_conn *conn); +int bt_gmap_discover_safe(struct bt_conn *conn); + +/** + * @brief Adds GMAS instance to database and sets the received Gaming Audio Profile role(s). + * + * @param role Gaming Audio Profile role(s) of the device (one or multiple). + * @param features Features of the roles. If a role is not in the @p role parameter, then the + * feature value for that role is simply ignored. + * + * @retval -EINVAL on invalid arguments + * @retval -ENOEXEC on service register failure + * @retval 0 on success + */ +int bt_gmap_register_safe(enum bt_gmap_role role, struct bt_gmap_feat features); + +/** + * @brief Set one or multiple Gaming Audio Profile roles and features dynamically. + * + * Previously registered value will be overwritten. If there is a role change, this will trigger + * a Gaming Audio Service (GMAS) service change. If there is only a feature change, no service + * change will happen. + * + * @param role Gaming Audio Profile role(s). + * @param features Features of the roles. If a role is not in the @p role parameter, then the + * feature value for that role is simply ignored. + * + * @retval -ENOEXEC if the service has not yet been registered + * @retval -EINVAL on invalid arguments + * @retval -EALREADY if the @p role and @p features are the same as existing ones + * @retval -ENOENT on service unregister failure + * @retval -ECANCELED on service re-register failure + * @retval 0 on success + */ +int bt_gmap_set_role_safe(enum bt_gmap_role role, struct bt_gmap_feat features); + +#ifdef __cplusplus +} +#endif +/** @} */ /* end of bt_gmap */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_GMAP_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/gmap_lc3_preset.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/gmap_lc3_preset.h new file mode 100644 index 0000000000..1a1b1545dc --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/gmap_lc3_preset.h @@ -0,0 +1,240 @@ +/** + * @file + * @brief Header for Bluetooth GMAP LC3 presets. + * + * SPDX-FileCopyrightText: 2023-2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_GMAP_LC3_PRESET_ +#define ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_GMAP_LC3_PRESET_ + +/** + * @brief Gaming Audio Profile (GMAP) LC3 Presets + * + * @defgroup bt_gmap_lc3_preset Gaming Audio Profile (GMAP) LC3 Presets + * + * @since 3.5 + * @version 0.8.0 + * + * @ingroup bluetooth + * @{ + * + * These APIs provide presets for codec configuration and QoS based on values supplied by the + * codec configurations from table 3.16 in the GMAP v1.0 specification + */ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Helper to declare LC3 32_1_gr codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_GMAP_LC3_PRESET_32_1_GR(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 60U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 60U, 1U, 15U, 10000U)) + +/** + * @brief Helper to declare LC3 32_2_gr codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_GMAP_LC3_PRESET_32_2_GR(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 80U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 80U, 1U, 20U, 10000U)) + +/** + * @brief Helper to declare LC3 48_1_gr codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_GMAP_LC3_PRESET_48_1_GR(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 75U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 75U, 1U, 15U, 10000U)) + +/** + * @brief Helper to declare LC3 48_2_gr codec configuration + * + * Mandatory to support as both unicast client and server + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_GMAP_LC3_PRESET_48_2_GR(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 100U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 100U, 1U, 20U, 10000U)) + +/** + * @brief Helper to declare LC3 48_3_gr codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_GMAP_LC3_PRESET_48_3_GR(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 90U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 90U, 1U, 15U, 10000U)) + +/** + * @brief Helper to declare LC3 48_4_gr codec configuration + * + * Mandatory to support as unicast server + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_GMAP_LC3_PRESET_48_4_GR(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 120u, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 120U, 1U, 20U, 10000U)) + +/** + * @brief Helper to declare LC3 16_1_gs codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_GMAP_LC3_PRESET_16_1_GS(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_16KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 30U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 30U, 1U, 15U, 60000U)) + +/** + * @brief Helper to declare LC3 16_2_gs codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_GMAP_LC3_PRESET_16_2_GS(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_16KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 40U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 40U, 1U, 20U, 60000U)) + +/** + * @brief Helper to declare LC3 32_1_gs codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_GMAP_LC3_PRESET_32_1_GS(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 60U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 60U, 1U, 15U, 60000U)) + +/** + * @brief Helper to declare LC3 32_2_gs codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_GMAP_LC3_PRESET_32_2_GS(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_32KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 80U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 80U, 1U, 20U, 60000U)) + +/** + * @brief Helper to declare LC3 48_1_gs codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_GMAP_LC3_PRESET_48_1_GS(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 75U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 75U, 1U, 15U, 60000U)) + +/** + * @brief Helper to declare LC3 48_2_gs codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_GMAP_LC3_PRESET_48_2_GS(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 100U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 100U, 1U, 20U, 60000U)) + +/* GMAP LC3 broadcast presets defined by table 3.22 in the GMAP v1.0 specification */ + +/** + * @brief Helper to declare LC3 48_1_g codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_GMAP_LC3_PRESET_48_1_G(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 75U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 75U, 1U, 8U, 10000U)) + +/** + * @brief Helper to declare LC3 48_2_g codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_GMAP_LC3_PRESET_48_2_G(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 100U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 100U, 1U, 10U, 10000U)) + +/** + * @brief Helper to declare LC3 48_3_g codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_GMAP_LC3_PRESET_48_3_G(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_7_5, _loc, 90U, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(7500u, 90U, 1U, 8U, 10000U)) + +/** + * @brief Helper to declare LC3 48_4_g codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_GMAP_LC3_PRESET_48_4_G(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CFG_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CFG_DURATION_10, _loc, 120u, 1, \ + _stream_context), \ + BT_BAP_QOS_CFG_UNFRAMED(10000u, 120U, 1U, 10U, 10000U)) + +#ifdef __cplusplus +} +#endif +/** @} */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_GMAP_LC3_PRESET_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/has.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/has.h new file mode 100644 index 0000000000..70efc5c574 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/has.h @@ -0,0 +1,525 @@ +/** + * @file + * @brief Bluetooth Hearing Access Service (HAS) APIs. + */ + +/* + * SPDX-FileCopyrightText: 2022 Codecoup + * SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_HAS_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_HAS_H_ + +/** + * @brief Hearing Access Service (HAS) + * + * @defgroup bt_has Hearing Access Service (HAS) + * + * @since 3.1 + * @version 0.8.0 + * + * @ingroup bluetooth + * @{ + * + * The Hearing Access Service is used to identify a hearing aid and optionally + * to control hearing aid presets. + */ + +#include +#include + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Preset index definitions + * @{ + */ +/** No index */ +#define BT_HAS_PRESET_INDEX_NONE 0x00 +/** First preset index */ +#define BT_HAS_PRESET_INDEX_FIRST 0x01 +/** Last preset index */ +#define BT_HAS_PRESET_INDEX_LAST 0xFF +/** @} */ + +/** Preset name minimum length */ +#define BT_HAS_PRESET_NAME_MIN 1 +/** Preset name maximum length */ +#define BT_HAS_PRESET_NAME_MAX 40 + +/** @brief Opaque Hearing Access Service object. */ +struct bt_has; + +/** Hearing Aid device type */ +enum bt_has_hearing_aid_type { + /** + * Two hearing aids that form a Coordinated Set, one for the right ear and one for the left + * ear of the user. Typically used by a user with bilateral hearing loss. + */ + BT_HAS_HEARING_AID_TYPE_BINAURAL = 0x00, + /** + * A single hearing aid for the left or the right ear. Typically used by a user with + * unilateral hearing loss. + */ + BT_HAS_HEARING_AID_TYPE_MONAURAL = 0x01, + /** + * Two hearing aids with a connection to one another that expose a single Bluetooth radio + * interface. + */ + BT_HAS_HEARING_AID_TYPE_BANDED = 0x02, +}; + +/** Preset Properties values */ +enum bt_has_properties { + /** No properties set */ + BT_HAS_PROP_NONE = 0, + + /** Preset name can be written by the client */ + BT_HAS_PROP_WRITABLE = BIT(0), + + /** Preset availability */ + BT_HAS_PROP_AVAILABLE = BIT(1), +}; + +/** Hearing Aid device capabilities */ +enum bt_has_capabilities { + /** Indicate support for presets */ + BT_HAS_PRESET_SUPPORT = BIT(0), +}; + +/** @brief Structure for registering features of a Hearing Access Service instance. */ +struct bt_has_features_param { + /** Hearing Aid Type value */ + enum bt_has_hearing_aid_type type; + + /** + * @brief Preset Synchronization Support. + * + * Only applicable if @p type is @ref BT_HAS_HEARING_AID_TYPE_BINAURAL + * and @kconfig{CONFIG_BT_HAS_PRESET_COUNT} is non-zero. + */ + bool preset_sync_support; + + /** + * @brief Independent Presets. + * + * Only applicable if @p type is @ref BT_HAS_HEARING_AID_TYPE_BINAURAL + * and @kconfig{CONFIG_BT_HAS_PRESET_COUNT} is non-zero. + */ + bool independent_presets; +}; + +/** @brief Preset record definition */ +struct bt_has_preset_record { + /** Unique preset index. */ + uint8_t index; + + /** Bitfield of preset properties. */ + enum bt_has_properties properties; + + /** Preset name. */ + const char *name; +}; + +/** @brief Hearing Access Service Client callback structure. */ +struct bt_has_client_cb { + /** + * @brief Callback function for bt_has_discover. + * + * This callback is called when discovery procedure is complete. + * + * @param conn Bluetooth connection object. + * @param err 0 on success, ATT error or negative errno otherwise. + * @param has Pointer to the Hearing Access Service object or NULL on errors. + * @param type Hearing Aid type. + * @param caps Hearing Aid capabilities. + */ + void (*discover)(struct bt_conn *conn, int err, struct bt_has *has, + enum bt_has_hearing_aid_type type, enum bt_has_capabilities caps); + + /** + * @brief Callback function for Hearing Access Service active preset changes. + * + * Optional callback called when the active preset is changed by the remote server when the + * preset switch procedure is complete. The callback must be set to receive active preset + * changes and enable support for switching presets. If the callback is not set, the Active + * Index and Control Point characteristics will not be discovered by + * @ref bt_has_client_discover. + * + * @param has Pointer to the Hearing Access Service object. + * @param err 0 on success, ATT error or negative errno otherwise. + * @param index Active preset index. + */ + void (*preset_switch)(struct bt_has *has, int err, uint8_t index); + + /** + * @brief Callback function for presets read operation. + * + * The callback is called when the preset read response is sent by the remote server. + * The record object as well as its members are temporary and must be copied to in order + * to cache its information. + * + * @param has Pointer to the Hearing Access Service object. + * @param err 0 on success, ATT error or negative errno otherwise. + * @param record Preset record or NULL on errors. + * @param is_last True if Read Presets operation can be considered concluded. + */ + void (*preset_read_rsp)(struct bt_has *has, int err, + const struct bt_has_preset_record *record, bool is_last); + + /** + * @brief Callback function for preset update notifications. + * + * The callback is called when the preset record update is notified by the remote server. + * The record object as well as its objects are temporary and must be copied to in order + * to cache its information. + * + * @param has Pointer to the Hearing Access Service object. + * @param index_prev Index of the previous preset in the list. + * @param record Preset record. + * @param is_last True if preset list update operation can be considered concluded. + */ + void (*preset_update)(struct bt_has *has, uint8_t index_prev, + const struct bt_has_preset_record *record, bool is_last); + + /** + * @brief Callback function for preset deletion notifications. + * + * The callback is called when the preset has been deleted by the remote server. + * + * @param has Pointer to the Hearing Access Service object. + * @param index Preset index. + * @param is_last True if preset list update operation can be considered concluded. + */ + void (*preset_deleted)(struct bt_has *has, uint8_t index, bool is_last); + + /** + * @brief Callback function for preset availability notifications. + * + * The callback is called when the preset availability change is notified by the remote + * server. + * + * @param has Pointer to the Hearing Access Service object. + * @param index Preset index. + * @param available True if available, false otherwise. + * @param is_last True if preset list update operation can be considered concluded. + */ + void (*preset_availability)(struct bt_has *has, uint8_t index, bool available, + bool is_last); +}; + +/** + * @brief Registers the callbacks used by the Hearing Access Service client. + * + * @param cb The callback structure. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_has_client_cb_register_safe(const struct bt_has_client_cb *cb); + +/** + * @brief Discover Hearing Access Service on a remote device. + * + * Client method to find a Hearing Access Service on a server identified by @p conn. + * The @ref bt_has_client_cb.discover callback will be called when the discovery procedure + * is complete to provide user a @ref bt_has object. + * + * @param conn Bluetooth connection object. + * + * @return 0 if success, errno on failure. + */ +int bt_has_client_discover(struct bt_conn *conn); +int bt_has_client_discover_safe(struct bt_conn *conn); + +/** + * @brief Get the Bluetooth connection object of the service object. + * + * The caller gets a new reference to the connection object which must be + * released with bt_conn_unref() once done using the object. + * + * @param[in] has Pointer to the Hearing Access Service object. + * @param[out] conn Connection object. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_has_client_conn_get_safe(const struct bt_has *has, struct bt_conn **conn); + +/** + * @brief Read Preset Records. + * + * Client method to read up to @p max_count presets starting from given @p index. + * The preset records are returned in the @ref bt_has_client_cb.preset_read_rsp callback + * (called once for each preset). + * + * @param has Pointer to the Hearing Access Service object. + * @param index The index to start with. + * @param max_count Maximum number of presets to read. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_has_client_presets_read_safe(struct bt_has *has, uint8_t index, uint8_t max_count); + +/** + * @brief Set Active Preset. + * + * Client procedure to set preset identified by @p index as active. + * The status is returned in the @ref bt_has_client_cb.preset_switch callback. + * + * @param has Pointer to the Hearing Access Service object. + * @param index Preset index to activate. + * @param sync Request active preset synchronization in set. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_has_client_preset_set_safe(struct bt_has *has, uint8_t index, bool sync); + +/** + * @brief Activate Next Preset. + * + * Client procedure to set next available preset as active. + * The status is returned in the @ref bt_has_client_cb.preset_switch callback. + * + * @param has Pointer to the Hearing Access Service object. + * @param sync Request active preset synchronization in set. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_has_client_preset_next_safe(struct bt_has *has, bool sync); + +/** + * @brief Activate Previous Preset. + * + * Client procedure to set previous available preset as active. + * The status is returned in the @ref bt_has_client_cb.preset_switch callback. + * + * @param has Pointer to the Hearing Access Service object. + * @param sync Request active preset synchronization in set. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_has_client_preset_prev_safe(struct bt_has *has, bool sync); + +/** @brief Preset operations structure. */ +struct bt_has_preset_ops { + /** + * @brief Preset select callback. + * + * This callback is called when the client requests to select preset identified by + * @p index. + * + * @param index Preset index requested to activate. + * @param sync Whether the server must relay this change to the other member of the + * Binaural Hearing Aid Set. + * + * @return 0 in case of success or negative value in case of error. + * @return -EBUSY if operation cannot be performed at the time. + * @return -EINPROGRESS in case where user has to confirm once the requested preset + * becomes active by calling @ref bt_has_preset_active_set. + */ + int (*select)(uint8_t index, bool sync); + + /** + * @brief Preset name changed callback + * + * This callback is called when the name of the preset identified by @p index has changed. + * + * @param index Preset index that name has been changed. + * @param name Preset current name. + */ + void (*name_changed)(uint8_t index, const char *name); +}; + +/** @brief Register structure for preset. */ +struct bt_has_preset_register_param { + /** + * @brief Preset index. + * + * Unique preset identifier. The value shall be other than @ref BT_HAS_PRESET_INDEX_NONE. + */ + uint8_t index; + + /** + * @brief Preset properties. + * + * Bitfield of preset properties. + */ + enum bt_has_properties properties; + + /** + * @brief Preset name. + * + * Preset name that further can be changed by either server or client if + * @kconfig{CONFIG_BT_HAS_PRESET_NAME_DYNAMIC} configuration option has been enabled. + * It's length shall be greater than @ref BT_HAS_PRESET_NAME_MIN. If the length exceeds + * @ref BT_HAS_PRESET_NAME_MAX, the name will be truncated. + */ + const char *name; + + /** Preset operations structure. */ + const struct bt_has_preset_ops *ops; +}; + +/** + * @brief Register the Hearing Access Service instance. + * + * @param features Hearing Access Service register parameters. + * + * @return 0 if success, errno on failure. + */ +int bt_has_register_safe(const struct bt_has_features_param *features); + +/** + * @brief Register preset. + * + * Register preset. The preset will be a added to the list of exposed preset records. + * This symbol is linkable if @kconfig{CONFIG_BT_HAS_PRESET_COUNT} is non-zero. + * + * @param param Preset registration parameter. + * + * @return 0 if success, errno on failure. + */ +int bt_has_preset_register_safe(const struct bt_has_preset_register_param *param); + +/** + * @brief Unregister Preset. + * + * Unregister preset. The preset will be removed from the list of preset records. + * + * @param index The index of preset that's being requested to unregister. + * + * @return 0 if success, errno on failure. + */ +int bt_has_preset_unregister_safe(uint8_t index); + +/** + * @brief Set the preset as available. + * + * Set the @ref BT_HAS_PROP_AVAILABLE property bit. This will notify preset availability + * to peer devices. Only available preset can be selected as active preset. + * + * @param index The index of preset that's became available. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_has_preset_available_safe(uint8_t index); + +/** + * @brief Set the preset as unavailable. + * + * Clear the @ref BT_HAS_PROP_AVAILABLE property bit. This will notify preset availability + * to peer devices. Unavailable preset cannot be selected as active preset. + * + * @param index The index of preset that's became unavailable. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_has_preset_unavailable_safe(uint8_t index); + +/** Enum for return values for @ref bt_has_preset_func_t functions */ +enum { + /** Stop iterating */ + BT_HAS_PRESET_ITER_STOP = 0, + /** Continue iterating */ + BT_HAS_PRESET_ITER_CONTINUE, +}; + +/** + * @typedef bt_has_preset_func_t + * @brief Preset iterator callback. + * + * @param index The index of preset found. + * @param properties Preset properties. + * @param name Preset name. + * @param user_data Data given. + * + * @return BT_HAS_PRESET_ITER_CONTINUE if should continue to the next preset. + * @return BT_HAS_PRESET_ITER_STOP to stop. + */ +typedef uint8_t (*bt_has_preset_func_t)(uint8_t index, enum bt_has_properties properties, + const char *name, void *user_data); + +/** + * @brief Preset iterator. + * + * Iterate presets. Optionally, match non-zero index if given. + * + * @param index Preset index, passing @ref BT_HAS_PRESET_INDEX_NONE skips index matching. + * @param func Callback function. + * @param user_data Data to pass to the callback. + */ +void bt_has_preset_foreach_safe(uint8_t index, bt_has_preset_func_t func, void *user_data); + +/** + * @brief Set active preset. + * + * Function used to set the preset identified by the @p index as the active preset. + * The preset index will be notified to peer devices. + * + * @param index Preset index. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_has_preset_active_set_safe(uint8_t index); + +/** + * @brief Get active preset. + * + * Function used to get the currently active preset index. + * + * @return Active preset index. + */ +uint8_t bt_has_preset_active_get_safe(void); + +/** + * @brief Clear out active preset. + * + * Used by server to deactivate currently active preset. + * + * @return 0 in case of success or negative value in case of error. + */ +static inline int bt_has_preset_active_clear_safe(void) +{ + return bt_has_preset_active_set_safe(BT_HAS_PRESET_INDEX_NONE); +} + +/** + * @brief Change the Preset Name. + * + * Change the name of the preset identified by @p index. + * + * @param index The index of the preset to change the name of. + * @param name Name to write. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_has_preset_name_change_safe(uint8_t index, const char *name); + +/** + * @brief Change the Hearing Aid Features. + * + * Change the hearing aid features. + * + * @param features The features to be set. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_has_features_set_safe(const struct bt_has_features_param *features); + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_HAS_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/lc3.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/lc3.h new file mode 100644 index 0000000000..00d74bb3ca --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/lc3.h @@ -0,0 +1,147 @@ +/** + * @file + * @brief Bluetooth LC3 codec handling + */ + +/* + * SPDX-FileCopyrightText: 2020 Intel Corporation + * SPDX-FileCopyrightText: 2022-2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_LC3_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_LC3_H_ + +/** + * @brief LC3 + * @defgroup bt_lc3 Bluetooth LC3 codec + + * @since 3.0 + * @version 0.8.0 + + * @ingroup bluetooth + * @{ + */ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Helper to declare LC3 codec capability + * + * @p _max_frames_per_sdu is optional and will be included only if != 1 + * + * @ref COND_CODE_1 is used to omit an LTV entry in case the @p _frames_per_sdu is 1. + * @ref COND_CODE_1 will evaluate to second argument if the flag parameter(first argument) is 1 + * - removing one layer of paranteses. + * If the flags argument is != 1 it will evaluate to the third argument which inserts a LTV + * entry for the max_frames_per_sdu value. + + * @param _freq Supported Sampling Frequencies bitfield (see ``BT_AUDIO_CODEC_CAP_FREQ_*``) + * @param _duration Supported Frame Durations bitfield (see ``BT_AUDIO_CODEC_CAP_DURATION_*``) + * @param _chan_count Supported channels (see @ref BT_AUDIO_CODEC_CAP_CHAN_COUNT_SUPPORT) + * @param _len_min Minimum number of octets supported per codec frame + * @param _len_max Maximum number of octets supported per codec frame + * @param _max_frames_per_sdu Supported maximum codec frames per SDU + */ +#define BT_AUDIO_CODEC_CAP_LC3_DATA(_freq, _duration, _chan_count, _len_min, _len_max, \ + _max_frames_per_sdu) \ + { \ + BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CAP_TYPE_FREQ, BT_BYTES_LIST_LE16(_freq)), \ + BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CAP_TYPE_DURATION, (_duration)), \ + BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CAP_TYPE_CHAN_COUNT, (_chan_count)), \ + BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CAP_TYPE_FRAME_LEN, \ + BT_BYTES_LIST_LE16(_len_min), \ + BT_BYTES_LIST_LE16(_len_max)), \ + COND_CODE_1(_max_frames_per_sdu, (), \ + (BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CAP_TYPE_FRAME_COUNT, \ + (_max_frames_per_sdu)))) \ + } + +/** + * @brief Helper to declare LC3 codec metadata + * + * @param _prefer_context Preferred contexts (@ref bt_audio_context) + */ +#define BT_AUDIO_CODEC_CAP_LC3_META(_prefer_context) \ + { \ + BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PREF_CONTEXT, \ + BT_BYTES_LIST_LE16(_prefer_context)) \ + } + +/** + * @brief Helper to declare LC3 codec + * + * @param _freq Supported Sampling Frequencies bitfield (see ``BT_AUDIO_CODEC_CAP_FREQ_*``) + * @param _duration Supported Frame Durations bitfield (see ``BT_AUDIO_CODEC_CAP_DURATION_*``) + * @param _chan_count Supported channels (see @ref BT_AUDIO_CODEC_CAP_CHAN_COUNT_SUPPORT) + * @param _len_min Minimum number of octets supported per codec frame + * @param _len_max Maximum number of octets supported per codec frame + * @param _max_frames_per_sdu Supported maximum codec frames per SDU + * @param _prefer_context Preferred contexts (@ref bt_audio_context) + */ +#define BT_AUDIO_CODEC_CAP_LC3(_freq, _duration, _chan_count, _len_min, _len_max, \ + _max_frames_per_sdu, _prefer_context) \ + BT_AUDIO_CODEC_CAP(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, \ + BT_AUDIO_CODEC_CAP_LC3_DATA(_freq, _duration, _chan_count, _len_min, \ + _len_max, _max_frames_per_sdu), \ + BT_AUDIO_CODEC_CAP_LC3_META(_prefer_context)) + +/** + * @brief Helper to declare LC3 codec data configuration + * + * @param _freq Sampling frequency (``BT_AUDIO_CODEC_CFG_FREQ_*``) + * @param _duration Frame duration (``BT_AUDIO_CODEC_CFG_DURATION_*``) + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _len Octets per frame (16-bit integer) + * @param _frames_per_sdu Frames per SDU (8-bit integer). This value is optional and will be + * included only if != 1 + */ +#define BT_AUDIO_CODEC_CFG_LC3_DATA(_freq, _duration, _loc, _len, _frames_per_sdu) \ + { \ + BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CFG_FREQ, (_freq)), \ + BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CFG_DURATION, (_duration)), \ + BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CFG_CHAN_ALLOC, BT_BYTES_LIST_LE32(_loc)), \ + BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CFG_FRAME_LEN, BT_BYTES_LIST_LE16(_len)), \ + COND_CODE_1(_frames_per_sdu, (), \ + (BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CFG_FRAME_BLKS_PER_SDU, \ + (_frames_per_sdu)))) \ + } + +/** @brief Helper to declare LC3 codec metadata configuration */ +#define BT_AUDIO_CODEC_CFG_LC3_META(_stream_context) \ + { \ + BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, \ + BT_BYTES_LIST_LE16(_stream_context)) \ + } + +/** + * @brief Helper to declare LC3 codec configuration. + * + * @param _freq Sampling frequency (``BT_AUDIO_CODEC_CFG_FREQ_*``) + * @param _duration Frame duration (``BT_AUDIO_CODEC_CFG_DURATION_*``) + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _len Octets per frame (16-bit integer) + * @param _frames_per_sdu Frames per SDU (8-bit integer) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_AUDIO_CODEC_LC3_CONFIG(_freq, _duration, _loc, _len, _frames_per_sdu, _stream_context) \ + BT_AUDIO_CODEC_CFG( \ + BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, \ + BT_AUDIO_CODEC_CFG_LC3_DATA(_freq, _duration, _loc, _len, _frames_per_sdu), \ + BT_AUDIO_CODEC_CFG_LC3_META(_stream_context)) + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_LC3_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/mcc.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/mcc.h new file mode 100644 index 0000000000..68767950b5 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/mcc.h @@ -0,0 +1,997 @@ +/** + * @file + * @brief Bluetooth Media Control Client (MCC) APIs. + */ + +/* + * SPDX-FileCopyrightText: 2019-2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_MCC_ +#define ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_MCC_ + +/** + * @brief Bluetooth Media Control Client (MCC) interface + * + * Updated to the Media Control Profile specification revision 1.0 + * + * @defgroup bt_mcc Media Control Client (MCC) + * + * @since 3.0 + * @version 0.8.0 + * + * @ingroup bluetooth + * @{ + */ + +#include +#include + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/**** Callback functions ******************************************************/ + +/** + * @brief Callback function for bt_mcc_discover_mcs() + * + * Called when a media control server is discovered + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + */ +typedef void (*bt_mcc_discover_mcs_cb)(struct bt_conn *conn, int err); + +/** + * @brief Callback function for bt_mcc_read_player_name() + * + * Called when the player name is read or notified + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param name Player name + */ +typedef void (*bt_mcc_read_player_name_cb)(struct bt_conn *conn, int err, const char *name); + +/** + * @brief Callback function for bt_mcc_read_icon_obj_id() + * + * Called when the icon object ID is read + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param icon_id The ID of the Icon Object. This is a UINT48 in a uint64_t + */ +typedef void (*bt_mcc_read_icon_obj_id_cb)(struct bt_conn *conn, int err, uint64_t icon_id); + +/** + * @brief Callback function for bt_mcc_read_icon_url() + * + * Called when the icon URL is read + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param icon_url The URL of the Icon + */ +typedef void (*bt_mcc_read_icon_url_cb)(struct bt_conn *conn, int err, const char *icon_url); + +/** + * @brief Callback function for track changed notifications + * + * Called when a track change is notified. + * + * The track changed characteristic is a special case. It can not be read or + * set, it can only be notified. + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + */ +typedef void (*bt_mcc_track_changed_ntf_cb)(struct bt_conn *conn, int err); + +/** + * @brief Callback function for bt_mcc_read_track_title() + * + * Called when the track title is read or notified + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param title The title of the track + */ +typedef void (*bt_mcc_read_track_title_cb)(struct bt_conn *conn, int err, const char *title); + +/** + * @brief Callback function for bt_mcc_read_track_duration() + * + * Called when the track duration is read or notified + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param dur The duration of the track + */ +typedef void (*bt_mcc_read_track_duration_cb)(struct bt_conn *conn, int err, int32_t dur); + +/** + * @brief Callback function for bt_mcc_read_track_position() + * + * Called when the track position is read or notified + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param pos The Track Position + */ +typedef void (*bt_mcc_read_track_position_cb)(struct bt_conn *conn, int err, int32_t pos); + +/** + * @brief Callback function for bt_mcc_set_track_position() + * + * Called when the track position is set + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param pos The Track Position set (or attempted to set) + */ +typedef void (*bt_mcc_set_track_position_cb)(struct bt_conn *conn, int err, int32_t pos); + +/** + * @brief Callback function for bt_mcc_read_playback_speed() + * + * Called when the playback speed is read or notified + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param speed The Playback Speed + */ +typedef void (*bt_mcc_read_playback_speed_cb)(struct bt_conn *conn, int err, int8_t speed); + +/** + * @brief Callback function for bt_mcc_set_playback_speed() + * + * Called when the playback speed is set + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param speed The Playback Speed set (or attempted to set) + */ +typedef void (*bt_mcc_set_playback_speed_cb)(struct bt_conn *conn, int err, int8_t speed); + +/** + * @brief Callback function for bt_mcc_read_seeking_speed() + * + * Called when the seeking speed is read or notified + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param speed The Seeking Speed + */ +typedef void (*bt_mcc_read_seeking_speed_cb)(struct bt_conn *conn, int err, int8_t speed); + +/** + * @brief Callback function for bt_mcc_read_segments_obj_id() + * + * Called when the track segments object ID is read + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param id The Track Segments Object ID (UINT48) + */ +typedef void (*bt_mcc_read_segments_obj_id_cb)(struct bt_conn *conn, int err, uint64_t id); + +/** + * @brief Callback function for bt_mcc_read_current_track_obj_id() + * + * Called when the current track object ID is read or notified + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param id The Current Track Object ID (UINT48) + */ +typedef void (*bt_mcc_read_current_track_obj_id_cb)(struct bt_conn *conn, int err, uint64_t id); + +/** + * @brief Callback function for bt_mcc_set_current_track_obj_id() + * + * Called when the current track object ID is set + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param id The Object ID (UINT48) set (or attempted to set) + */ +typedef void (*bt_mcc_set_current_track_obj_id_cb)(struct bt_conn *conn, int err, uint64_t id); + +/** + * @brief Callback function for bt_mcc_read_next_track_obj_id_obj() + * + * Called when the next track object ID is read or notified + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param id The Next Track Object ID (UINT48) + */ +typedef void (*bt_mcc_read_next_track_obj_id_cb)(struct bt_conn *conn, int err, uint64_t id); + +/** + * @brief Callback function for bt_mcc_set_next_track_obj_id() + * + * Called when the next track object ID is set + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param id The Object ID (UINT48) set (or attempted to set) + */ +typedef void (*bt_mcc_set_next_track_obj_id_cb)(struct bt_conn *conn, int err, uint64_t id); + +/** + * @brief Callback function for bt_mcc_read_parent_group_obj_id() + * + * Called when the parent group object ID is read or notified + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param id The Parent Group Object ID (UINT48) + */ +typedef void (*bt_mcc_read_parent_group_obj_id_cb)(struct bt_conn *conn, int err, uint64_t id); + +/** + * @brief Callback function for bt_mcc_read_current_group_obj_id() + * + * Called when the current group object ID is read or notified + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param id The Current Group Object ID (UINT48) + */ +typedef void (*bt_mcc_read_current_group_obj_id_cb)(struct bt_conn *conn, int err, uint64_t id); + +/** + * @brief Callback function for bt_mcc_set_current_group_obj_id() + * + * Called when the current group object ID is set + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param obj_id The Object ID (UINT48) set (or attempted to set) + */ +typedef void (*bt_mcc_set_current_group_obj_id_cb)(struct bt_conn *conn, int err, uint64_t obj_id); + +/** + * @brief Callback function for bt_mcc_read_playing_order() + * + * Called when the playing order is read or notified + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param order The playback order + */ +typedef void (*bt_mcc_read_playing_order_cb)(struct bt_conn *conn, int err, uint8_t order); + +/** + * @brief Callback function for bt_mcc_set_playing_order() + * + * Called when the playing order is set + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param order The Playing Order set (or attempted to set) + */ +typedef void (*bt_mcc_set_playing_order_cb)(struct bt_conn *conn, int err, uint8_t order); + +/** + * @brief Callback function for bt_mcc_read_playing_orders_supported() + * + * Called when the supported playing orders are read or notified + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param orders The playing orders supported (bitmap) + */ +typedef void (*bt_mcc_read_playing_orders_supported_cb)(struct bt_conn *conn, int err, + uint16_t orders); + +/** + * @brief Callback function for bt_mcc_read_media_state() + * + * Called when the media state is read or notified + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param state The Media State + */ +typedef void (*bt_mcc_read_media_state_cb)(struct bt_conn *conn, int err, uint8_t state); + +/** + * @brief Callback function for bt_mcc_send_cmd() + * + * Called when a command is sent, i.e. when the media control point is set + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param cmd The command sent + */ +typedef void (*bt_mcc_send_cmd_cb)(struct bt_conn *conn, int err, const struct mpl_cmd *cmd); + +/** + * @brief Callback function for command notifications + * + * Called when the media control point is notified + * + * Notifications for commands (i.e. for writes to the media control point) use a + * different parameter structure than what is used for sending commands (writing + * to the media control point) + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param ntf The command notification + */ +typedef void (*bt_mcc_cmd_ntf_cb)(struct bt_conn *conn, int err, const struct mpl_cmd_ntf *ntf); + +/** + * @brief Callback function for bt_mcc_read_opcodes_supported() + * + * Called when the supported opcodes (commands) are read or notified + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param opcodes The supported opcodes + */ +typedef void (*bt_mcc_read_opcodes_supported_cb)(struct bt_conn *conn, int err, + uint32_t opcodes); + +/** + * @brief Callback function for bt_mcc_send_search() + * + * Called when a search is sent, i.e. when the search control point is set + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param search The search set (or attempted to set) + */ +typedef void (*bt_mcc_send_search_cb)(struct bt_conn *conn, int err, + const struct mpl_search *search); + +/** + * @brief Callback function for search notifications + * + * Called when the search control point is notified + * + * Notifications for searches (i.e. for writes to the search control point) use a + * different parameter structure than what is used for sending searches (writing + * to the search control point) + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param result_code The search notification + */ +typedef void (*bt_mcc_search_ntf_cb)(struct bt_conn *conn, int err, + uint8_t result_code); + +/** + * @brief Callback function for bt_mcc_read_search_results_obj_id() + * + * Called when the search results object ID is read or notified + * + * Note that the Search Results Object ID value may be zero, in case the + * characteristic does not exist on the server. (This will be the case if + * there has not been a successful search.) + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param id The Search Results Object ID (UINT48) + */ +typedef void (*bt_mcc_read_search_results_obj_id_cb)(struct bt_conn *conn, + int err, uint64_t id); + +/** + * @brief Callback function for bt_mcc_read_content_control_id() + * + * Called when the content control ID is read + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param ccid The Content Control ID + */ +typedef void (*bt_mcc_read_content_control_id_cb)(struct bt_conn *conn, + int err, uint8_t ccid); + +/**** Callback functions for the included Object Transfer service *************/ + +/** + * @brief Callback function for object selected + * + * Called when an object is selected + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + */ +typedef void (*bt_mcc_otc_obj_selected_cb)(struct bt_conn *conn, int err); + +/** + * @brief Callback function for bt_mcc_otc_read_object_metadata() + * + * Called when object metadata is read + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + */ +typedef void (*bt_mcc_otc_obj_metadata_cb)(struct bt_conn *conn, int err); + +/** + * @brief Callback function for bt_mcc_otc_read_icon_object() + * + * Called when the icon object is read + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param buf Buffer containing the object contents + * + * If err is EMSGSIZE, the object contents have been truncated. + */ +typedef void (*bt_mcc_otc_read_icon_object_cb)(struct bt_conn *conn, int err, + struct net_buf_simple *buf); + +/** + * @brief Callback function for bt_mcc_otc_read_track_segments_object() + * + * Called when the track segments object is read + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param buf Buffer containing the object contents + * + * If err is EMSGSIZE, the object contents have been truncated. + */ +typedef void (*bt_mcc_otc_read_track_segments_object_cb)(struct bt_conn *conn, int err, + struct net_buf_simple *buf); + +/** + * @brief Callback function for bt_mcc_otc_read_current_track_object() + * + * Called when the current track object is read + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param buf Buffer containing the object contents + * + * If err is EMSGSIZE, the object contents have been truncated. + */ +typedef void (*bt_mcc_otc_read_current_track_object_cb)(struct bt_conn *conn, int err, + struct net_buf_simple *buf); + +/** + * @brief Callback function for bt_mcc_otc_read_next_track_object() + * + * Called when the next track object is read + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param buf Buffer containing the object contents + * + * If err is EMSGSIZE, the object contents have been truncated. + */ +typedef void (*bt_mcc_otc_read_next_track_object_cb)(struct bt_conn *conn, int err, + struct net_buf_simple *buf); + +/** + * @brief Callback function for bt_mcc_otc_read_parent_group_object() + * + * Called when the parent group object is read + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param buf Buffer containing the object contents + * + * If err is EMSGSIZE, the object contents have been truncated. + */ +typedef void (*bt_mcc_otc_read_parent_group_object_cb)(struct bt_conn *conn, int err, + struct net_buf_simple *buf); + +/** + * @brief Callback function for bt_mcc_otc_read_current_group_object() + * + * Called when the current group object is read + * + * @param conn The connection that was used to initialise the media control client + * @param err Error value. 0 on success, GATT error or errno on fail + * @param buf Buffer containing the object contents + * + * If err is EMSGSIZE, the object contents have been truncated. + */ +typedef void (*bt_mcc_otc_read_current_group_object_cb)(struct bt_conn *conn, int err, + struct net_buf_simple *buf); + +/** + * @brief Media control client callbacks + */ +struct bt_mcc_cb { + /** Callback when discovery has finished */ + bt_mcc_discover_mcs_cb discover_mcs; + /** Callback when reading the player name */ + bt_mcc_read_player_name_cb read_player_name; + /** Callback when reading the icon object ID */ + bt_mcc_read_icon_obj_id_cb read_icon_obj_id; + /** Callback when reading the icon URL */ + bt_mcc_read_icon_url_cb read_icon_url; + /** Callback when getting a track changed notification */ + bt_mcc_track_changed_ntf_cb track_changed_ntf; + /** Callback when reading the track title */ + bt_mcc_read_track_title_cb read_track_title; + /** Callback when reading the track duration */ + bt_mcc_read_track_duration_cb read_track_duration; + /** Callback when reading the track position */ + bt_mcc_read_track_position_cb read_track_position; + /** Callback when setting the track position */ + bt_mcc_set_track_position_cb set_track_position; + /** Callback when reading the playback speed */ + bt_mcc_read_playback_speed_cb read_playback_speed; + /** Callback when setting the playback speed */ + bt_mcc_set_playback_speed_cb set_playback_speed; + /** Callback when reading the seeking speed */ + bt_mcc_read_seeking_speed_cb read_seeking_speed; + /** Callback when reading the segments object ID */ + bt_mcc_read_segments_obj_id_cb read_segments_obj_id; + /** Callback when reading the current track object ID */ + bt_mcc_read_current_track_obj_id_cb read_current_track_obj_id; + /** Callback when setting the current track object ID */ + bt_mcc_set_current_track_obj_id_cb set_current_track_obj_id; + /** Callback when reading the next track object ID */ + bt_mcc_read_next_track_obj_id_cb read_next_track_obj_id; + /** Callback when setting the next track object ID */ + bt_mcc_set_next_track_obj_id_cb set_next_track_obj_id; + /** Callback when reading the current group object ID */ + bt_mcc_read_current_group_obj_id_cb read_current_group_obj_id; + /** Callback when setting the current group object ID */ + bt_mcc_set_current_group_obj_id_cb set_current_group_obj_id; + /** Callback when reading the parent group object ID */ + bt_mcc_read_parent_group_obj_id_cb read_parent_group_obj_id; + /** Callback when reading the playing order */ + bt_mcc_read_playing_order_cb read_playing_order; + /** Callback when setting the playing order */ + bt_mcc_set_playing_order_cb set_playing_order; + /** Callback when reading the supported playing orders */ + bt_mcc_read_playing_orders_supported_cb read_playing_orders_supported; + /** Callback when reading the media state */ + bt_mcc_read_media_state_cb read_media_state; + /** Callback when sending a command */ + bt_mcc_send_cmd_cb send_cmd; + /** Callback command notifications */ + bt_mcc_cmd_ntf_cb cmd_ntf; + /** Callback when reading the supported opcodes */ + bt_mcc_read_opcodes_supported_cb read_opcodes_supported; + /** Callback when sending the a search query */ + bt_mcc_send_search_cb send_search; + /** Callback when receiving a search notification */ + bt_mcc_search_ntf_cb search_ntf; + /** Callback when reading the search results object ID */ + bt_mcc_read_search_results_obj_id_cb read_search_results_obj_id; + /** Callback when reading the content control ID */ + bt_mcc_read_content_control_id_cb read_content_control_id; + /** Callback when selecting an object */ + bt_mcc_otc_obj_selected_cb otc_obj_selected; + /** Callback when receiving the current object metadata */ + bt_mcc_otc_obj_metadata_cb otc_obj_metadata; + /** Callback when reading the current icon object */ + bt_mcc_otc_read_icon_object_cb otc_icon_object; + /** Callback when reading the track segments object */ + bt_mcc_otc_read_track_segments_object_cb otc_track_segments_object; + /** Callback when reading the current track object */ + bt_mcc_otc_read_current_track_object_cb otc_current_track_object; + /** Callback when reading the next track object */ + bt_mcc_otc_read_next_track_object_cb otc_next_track_object; + /** Callback when reading the current group object */ + bt_mcc_otc_read_current_group_object_cb otc_current_group_object; + /** Callback when reading the parent group object */ + bt_mcc_otc_read_parent_group_object_cb otc_parent_group_object; +}; + +/**** Functions ***************************************************************/ + +/** + * @brief Initialize Media Control Client + * + * @param cb Callbacks to be used + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_init_safe(struct bt_mcc_cb *cb); + +/** + * @brief Discover Media Control Service + * + * Discover Media Control Service (MCS) on the server given by the connection + * Optionally subscribe to notifications. + * + * Shall be called once, after media control client initialization and before + * using other media control client functionality. + * + * @param conn Connection to the peer device + * @param subscribe Whether to subscribe to notifications + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_discover_mcs(struct bt_conn *conn, bool subscribe); +int bt_mcc_discover_mcs_safe(struct bt_conn *conn, bool subscribe); + +/** + * @brief Read Media Player Name + * + * @param conn Connection to the peer device + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_read_player_name(struct bt_conn *conn); +int bt_mcc_read_player_name_safe(struct bt_conn *conn); + +/** + * @brief Read Icon Object ID + * + * @param conn Connection to the peer device + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_read_icon_obj_id(struct bt_conn *conn); +int bt_mcc_read_icon_obj_id_safe(struct bt_conn *conn); + +/** + * @brief Read Icon Object URL + * + * @param conn Connection to the peer device + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_read_icon_url(struct bt_conn *conn); +int bt_mcc_read_icon_url_safe(struct bt_conn *conn); + +/** + * @brief Read Track Title + * + * @param conn Connection to the peer device + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_read_track_title(struct bt_conn *conn); +int bt_mcc_read_track_title_safe(struct bt_conn *conn); + +/** + * @brief Read Track Duration + * + * @param conn Connection to the peer device + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_read_track_duration(struct bt_conn *conn); +int bt_mcc_read_track_duration_safe(struct bt_conn *conn); + +/** + * @brief Read Track Position + * + * @param conn Connection to the peer device + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_read_track_position(struct bt_conn *conn); +int bt_mcc_read_track_position_safe(struct bt_conn *conn); + +/** + * @brief Set Track position + * + * @param conn Connection to the peer device + * @param pos Track position + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_set_track_position(struct bt_conn *conn, int32_t pos); +int bt_mcc_set_track_position_safe(struct bt_conn *conn, int32_t pos); + +/** + * @brief Read Playback speed + * + * @param conn Connection to the peer device + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_read_playback_speed(struct bt_conn *conn); +int bt_mcc_read_playback_speed_safe(struct bt_conn *conn); + +/** + * @brief Set Playback Speed + * + * @param conn Connection to the peer device + * @param speed Playback speed + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_set_playback_speed(struct bt_conn *conn, int8_t speed); +int bt_mcc_set_playback_speed_safe(struct bt_conn *conn, int8_t speed); + +/** + * @brief Read Seeking speed + * + * @param conn Connection to the peer device + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_read_seeking_speed(struct bt_conn *conn); +int bt_mcc_read_seeking_speed_safe(struct bt_conn *conn); + +/** + * @brief Read Track Segments Object ID + * + * @param conn Connection to the peer device + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_read_segments_obj_id(struct bt_conn *conn); +int bt_mcc_read_segments_obj_id_safe(struct bt_conn *conn); + +/** + * @brief Read Current Track Object ID + * + * @param conn Connection to the peer device + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_read_current_track_obj_id(struct bt_conn *conn); +int bt_mcc_read_current_track_obj_id_safe(struct bt_conn *conn); + +/** + * @brief Set Current Track Object ID + * + * Set the Current Track to the track given by the @p id parameter + * + * @param conn Connection to the peer device + * @param id Object Transfer Service ID (UINT48) of the track to set as the current track + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_set_current_track_obj_id(struct bt_conn *conn, uint64_t id); +int bt_mcc_set_current_track_obj_id_safe(struct bt_conn *conn, uint64_t id); + +/** + * @brief Read Next Track Object ID + * + * @param conn Connection to the peer device + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_read_next_track_obj_id(struct bt_conn *conn); +int bt_mcc_read_next_track_obj_id_safe(struct bt_conn *conn); + +/** + * @brief Set Next Track Object ID + * + * Set the Next Track to the track given by the @p id parameter + * + * @param conn Connection to the peer device + * @param id Object Transfer Service ID (UINT48) of the track to set as the next track + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_set_next_track_obj_id(struct bt_conn *conn, uint64_t id); +int bt_mcc_set_next_track_obj_id_safe(struct bt_conn *conn, uint64_t id); + +/** + * @brief Read Current Group Object ID + * + * @param conn Connection to the peer device + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_read_current_group_obj_id(struct bt_conn *conn); +int bt_mcc_read_current_group_obj_id_safe(struct bt_conn *conn); + +/** + * @brief Set Current Group Object ID + * + * Set the Current Group to the group given by the @p id parameter + * + * @param conn Connection to the peer device + * @param id Object Transfer Service ID (UINT48) of the group to set as the current group + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_set_current_group_obj_id(struct bt_conn *conn, uint64_t id); +int bt_mcc_set_current_group_obj_id_safe(struct bt_conn *conn, uint64_t id); + +/** + * @brief Read Parent Group Object ID + * + * @param conn Connection to the peer device + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_read_parent_group_obj_id(struct bt_conn *conn); +int bt_mcc_read_parent_group_obj_id_safe(struct bt_conn *conn); + +/** + * @brief Read Playing Order + * + * @param conn Connection to the peer device + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_read_playing_order(struct bt_conn *conn); +int bt_mcc_read_playing_order_safe(struct bt_conn *conn); + +/** + * @brief Set Playing Order + * + * @param conn Connection to the peer device + * @param order Playing order + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_set_playing_order(struct bt_conn *conn, uint8_t order); +int bt_mcc_set_playing_order_safe(struct bt_conn *conn, uint8_t order); + +/** + * @brief Read Playing Orders Supported + * + * @param conn Connection to the peer device + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_read_playing_orders_supported(struct bt_conn *conn); +int bt_mcc_read_playing_orders_supported_safe(struct bt_conn *conn); + +/** + * @brief Read Media State + * + * @param conn Connection to the peer device + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_read_media_state(struct bt_conn *conn); +int bt_mcc_read_media_state_safe(struct bt_conn *conn); + +/** + * @brief Send a command + * + * Write a command (e.g. "play", "pause") to the server's media control point. + * + * @param conn Connection to the peer device + * @param cmd The command to send + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_send_cmd(struct bt_conn *conn, const struct mpl_cmd *cmd); +int bt_mcc_send_cmd_safe(struct bt_conn *conn, const struct mpl_cmd *cmd); + +/** + * @brief Read Opcodes Supported + * + * @param conn Connection to the peer device + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_read_opcodes_supported(struct bt_conn *conn); +int bt_mcc_read_opcodes_supported_safe(struct bt_conn *conn); + +/** + * @brief Send a Search command + * + * Write a search to the server's search control point. + * + * @param conn Connection to the peer device + * @param search The search + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_send_search(struct bt_conn *conn, const struct mpl_search *search); +int bt_mcc_send_search_safe(struct bt_conn *conn, const struct mpl_search *search); + +/** + * @brief Search Results Group Object ID + * + * @param conn Connection to the peer device + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_read_search_results_obj_id(struct bt_conn *conn); +int bt_mcc_read_search_results_obj_id_safe(struct bt_conn *conn); + +/** + * @brief Read Content Control ID + * + * @param conn Connection to the peer device + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_read_content_control_id(struct bt_conn *conn); +int bt_mcc_read_content_control_id_safe(struct bt_conn *conn); + +/** + * @brief Read the current object metadata + * + * @param conn Connection to the peer device + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_otc_read_object_metadata(struct bt_conn *conn); +int bt_mcc_otc_read_object_metadata_safe(struct bt_conn *conn); + +/** + * @brief Read the Icon Object + * + * @param conn Connection to the peer device + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_otc_read_icon_object(struct bt_conn *conn); +int bt_mcc_otc_read_icon_object_safe(struct bt_conn *conn); + +/** + * @brief Read the Track Segments Object + * + * @param conn Connection to the peer device + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_otc_read_track_segments_object(struct bt_conn *conn); +int bt_mcc_otc_read_track_segments_object_safe(struct bt_conn *conn); + +/** + * @brief Read the Current Track Object + * + * @param conn Connection to the peer device + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_otc_read_current_track_object(struct bt_conn *conn); +int bt_mcc_otc_read_current_track_object_safe(struct bt_conn *conn); + +/** + * @brief Read the Next Track Object + * + * @param conn Connection to the peer device + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_otc_read_next_track_object(struct bt_conn *conn); +int bt_mcc_otc_read_next_track_object_safe(struct bt_conn *conn); + +/** + * @brief Read the Current Group Object + * + * @param conn Connection to the peer device + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_otc_read_current_group_object(struct bt_conn *conn); +int bt_mcc_otc_read_current_group_object_safe(struct bt_conn *conn); + +/** + * @brief Read the Parent Group Object + * + * @param conn Connection to the peer device + * + * @return 0 if success, errno on failure. + */ +int bt_mcc_otc_read_parent_group_object(struct bt_conn *conn); +int bt_mcc_otc_read_parent_group_object_safe(struct bt_conn *conn); + +/** + * @brief Look up MCC OTC instance + * + * @param conn The connection to the MCC server. + * + * @return Pointer to a MCC OTC instance if found else NULL. + * + */ +struct bt_ots_client *bt_mcc_otc_inst(struct bt_conn *conn); +struct bt_ots_client *bt_mcc_otc_inst_safe(struct bt_conn *conn); + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_MCC__ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/mcs.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/mcs.h new file mode 100644 index 0000000000..66898f125b --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/mcs.h @@ -0,0 +1,376 @@ +/** + * @file + * @brief Bluetooth Media Control Service (MCS) APIs. + */ +/* + * SPDX-FileCopyrightText: 2019-2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_MCS_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_MCS_H_ + +/** + * @brief Media Control Service (MCS) + * + * @defgroup bt_mcs Media Control Service (MCS) + * + * @since 3.0 + * @version 0.8.0 + * + * @ingroup bluetooth + * @{ + * + * Definitions and types related to the Media Control Service and Media Control + * Profile specifications. + */ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * A characteristic value has changed while a Read Long Value Characteristic sub-procedure is in + * progress. + */ +#define BT_MCS_ERR_LONG_VAL_CHANGED 0x80 + +/** + * @name Playback speeds + * + * The playback speed (s) is calculated by the value of 2 to the power of p divided by 64. + * All values from -128 to 127 allowed, only some examples defined. + * @{ + */ +/** Minimum playback speed, resulting in 25 % speed */ +#define BT_MCS_PLAYBACK_SPEED_MIN -128 +/** Quarter playback speed, resulting in 25 % speed */ +#define BT_MCS_PLAYBACK_SPEED_QUARTER -128 +/** Half playback speed, resulting in 50 % speed */ +#define BT_MCS_PLAYBACK_SPEED_HALF -64 +/** Unity playback speed, resulting in 100 % speed */ +#define BT_MCS_PLAYBACK_SPEED_UNITY 0 +/** Double playback speed, resulting in 200 % speed */ +#define BT_MCS_PLAYBACK_SPEED_DOUBLE 64 +/** Max playback speed, resulting in 395.7 % speed (nearly 400 %) */ +#define BT_MCS_PLAYBACK_SPEED_MAX 127 +/** @} */ + +/** + * @name Seeking speed + * + * The allowed values for seeking speed are the range -64 to -4 + * (endpoints included), the value 0, and the range 4 to 64 + * (endpoints included). + * @{ + */ +/** Maximum seeking speed - Can be negated */ +#define BT_MCS_SEEKING_SPEED_FACTOR_MAX 64 +/** Minimum seeking speed - Can be negated */ +#define BT_MCS_SEEKING_SPEED_FACTOR_MIN 4 +/** No seeking */ +#define BT_MCS_SEEKING_SPEED_FACTOR_ZERO 0 +/** @} */ + +/** + * @name Playing orders + * @{ + */ +/** A single track is played once; there is no next track. */ +#define BT_MCS_PLAYING_ORDER_SINGLE_ONCE 0X01 +/** A single track is played repeatedly; the next track is the current track. */ +#define BT_MCS_PLAYING_ORDER_SINGLE_REPEAT 0x02 +/** The tracks within a group are played once in track order. */ +#define BT_MCS_PLAYING_ORDER_INORDER_ONCE 0x03 +/** The tracks within a group are played in track order repeatedly. */ +#define BT_MCS_PLAYING_ORDER_INORDER_REPEAT 0x04 +/** The tracks within a group are played once only from the oldest first. */ +#define BT_MCS_PLAYING_ORDER_OLDEST_ONCE 0x05 +/** The tracks within a group are played from the oldest first repeatedly. */ +#define BT_MCS_PLAYING_ORDER_OLDEST_REPEAT 0x06 +/** The tracks within a group are played once only from the newest first. */ +#define BT_MCS_PLAYING_ORDER_NEWEST_ONCE 0x07 +/** The tracks within a group are played from the newest first repeatedly. */ +#define BT_MCS_PLAYING_ORDER_NEWEST_REPEAT 0x08 +/** The tracks within a group are played in random order once. */ +#define BT_MCS_PLAYING_ORDER_SHUFFLE_ONCE 0x09 +/** The tracks within a group are played in random order repeatedly. */ +#define BT_MCS_PLAYING_ORDER_SHUFFLE_REPEAT 0x0a +/** @} */ + +/** @name Playing orders supported + * + * A bitmap, in the same order as the playing orders above. + * Note that playing order 1 corresponds to bit 0, and so on. + * @{ + */ +/** A single track is played once; there is no next track. */ +#define BT_MCS_PLAYING_ORDERS_SUPPORTED_SINGLE_ONCE BIT(0) +/** A single track is played repeatedly; the next track is the current track. */ +#define BT_MCS_PLAYING_ORDERS_SUPPORTED_SINGLE_REPEAT BIT(1) +/** The tracks within a group are played once in track order. */ +#define BT_MCS_PLAYING_ORDERS_SUPPORTED_INORDER_ONCE BIT(2) +/** The tracks within a group are played in track order repeatedly. */ +#define BT_MCS_PLAYING_ORDERS_SUPPORTED_INORDER_REPEAT BIT(3) +/** The tracks within a group are played once only from the oldest first. */ +#define BT_MCS_PLAYING_ORDERS_SUPPORTED_OLDEST_ONCE BIT(4) +/** The tracks within a group are played from the oldest first repeatedly. */ +#define BT_MCS_PLAYING_ORDERS_SUPPORTED_OLDEST_REPEAT BIT(5) +/** The tracks within a group are played once only from the newest first. */ +#define BT_MCS_PLAYING_ORDERS_SUPPORTED_NEWEST_ONCE BIT(6) +/** The tracks within a group are played from the newest first repeatedly. */ +#define BT_MCS_PLAYING_ORDERS_SUPPORTED_NEWEST_REPEAT BIT(7) +/** The tracks within a group are played in random order once. */ +#define BT_MCS_PLAYING_ORDERS_SUPPORTED_SHUFFLE_ONCE BIT(8) +/** The tracks within a group are played in random order repeatedly. */ +#define BT_MCS_PLAYING_ORDERS_SUPPORTED_SHUFFLE_REPEAT BIT(9) +/** @} */ + +/** + * @name Media states + * @{ + */ +/** The current track is invalid, and no track has been selected. */ +#define BT_MCS_MEDIA_STATE_INACTIVE 0x00 +/** The media player is playing the current track. */ +#define BT_MCS_MEDIA_STATE_PLAYING 0x01 +/** The current track is paused. The media player has a current track, but it is not being played */ +#define BT_MCS_MEDIA_STATE_PAUSED 0x02 +/** The current track is fast forwarding or fast rewinding. */ +#define BT_MCS_MEDIA_STATE_SEEKING 0x03 +/** @} */ + +/** + * @name Media control point opcodes + * @{ + */ +/** Start playing the current track. */ +#define BT_MCS_OPC_PLAY 0x01 +/** Pause playing the current track. */ +#define BT_MCS_OPC_PAUSE 0x02 +/** Fast rewind the current track. */ +#define BT_MCS_OPC_FAST_REWIND 0x03 +/** Fast forward the current track. */ +#define BT_MCS_OPC_FAST_FORWARD 0x04 +/** + * Stop current activity and return to the paused state and set the current track position to the + * start of the current track. + */ +#define BT_MCS_OPC_STOP 0x05 + +/** Set a new current track position relative to the current track position. */ +#define BT_MCS_OPC_MOVE_RELATIVE 0x10 + +/** + * Set the current track position to the starting position of the previous segment of the current + * track. + */ +#define BT_MCS_OPC_PREV_SEGMENT 0x20 +/** + * Set the current track position to the starting position of + * the next segment of the current track. + */ +#define BT_MCS_OPC_NEXT_SEGMENT 0x21 +/** + * Set the current track position to the starting position of + * the first segment of the current track. + */ +#define BT_MCS_OPC_FIRST_SEGMENT 0x22 +/** + * Set the current track position to the starting position of + * the last segment of the current track. + */ +#define BT_MCS_OPC_LAST_SEGMENT 0x23 +/** + * Set the current track position to the starting position of + * the nth segment of the current track. + */ +#define BT_MCS_OPC_GOTO_SEGMENT 0x24 + +/** Set the current track to the previous track based on the playing order. */ +#define BT_MCS_OPC_PREV_TRACK 0x30 +/** Set the current track to the next track based on the playing order. */ +#define BT_MCS_OPC_NEXT_TRACK 0x31 +/** Set the current track to the first track based on the playing order. */ +#define BT_MCS_OPC_FIRST_TRACK 0x32 +/** Set the current track to the last track based on the playing order. */ +#define BT_MCS_OPC_LAST_TRACK 0x33 +/** Set the current track to the nth track based on the playing order. */ +#define BT_MCS_OPC_GOTO_TRACK 0x34 + +/** Set the current group to the previous group in the sequence of groups. */ +#define BT_MCS_OPC_PREV_GROUP 0x40 +/** Set the current group to the next group in the sequence of groups. */ +#define BT_MCS_OPC_NEXT_GROUP 0x41 +/** Set the current group to the first group in the sequence of groups. */ +#define BT_MCS_OPC_FIRST_GROUP 0x42 +/** Set the current group to the last group in the sequence of groups. */ +#define BT_MCS_OPC_LAST_GROUP 0x43 +/** Set the current group to the nth group in the sequence of groups. */ +#define BT_MCS_OPC_GOTO_GROUP 0x44 +/** @} */ + +/** Media control point supported opcodes length */ +#define BT_MCS_OPCODES_SUPPORTED_LEN 4 + +/** + * @name Media control point supported opcodes values + * @{ + */ +/** Support the Play opcode */ +#define BT_MCS_OPC_SUP_PLAY BIT(0) +/** Support the Pause opcode */ +#define BT_MCS_OPC_SUP_PAUSE BIT(1) +/** Support the Fast Rewind opcode */ +#define BT_MCS_OPC_SUP_FAST_REWIND BIT(2) +/** Support the Fast Forward opcode */ +#define BT_MCS_OPC_SUP_FAST_FORWARD BIT(3) +/** Support the Stop opcode */ +#define BT_MCS_OPC_SUP_STOP BIT(4) + +/** Support the Move Relative opcode */ +#define BT_MCS_OPC_SUP_MOVE_RELATIVE BIT(5) + +/** Support the Previous Segment opcode */ +#define BT_MCS_OPC_SUP_PREV_SEGMENT BIT(6) +/** Support the Next Segment opcode */ +#define BT_MCS_OPC_SUP_NEXT_SEGMENT BIT(7) +/** Support the First Segment opcode */ +#define BT_MCS_OPC_SUP_FIRST_SEGMENT BIT(8) +/** Support the Last Segment opcode */ +#define BT_MCS_OPC_SUP_LAST_SEGMENT BIT(9) +/** Support the Goto Segment opcode */ +#define BT_MCS_OPC_SUP_GOTO_SEGMENT BIT(10) + +/** Support the Previous Track opcode */ +#define BT_MCS_OPC_SUP_PREV_TRACK BIT(11) +/** Support the Next Track opcode */ +#define BT_MCS_OPC_SUP_NEXT_TRACK BIT(12) +/** Support the First Track opcode */ +#define BT_MCS_OPC_SUP_FIRST_TRACK BIT(13) +/** Support the Last Track opcode */ +#define BT_MCS_OPC_SUP_LAST_TRACK BIT(14) +/** Support the Goto Track opcode */ +#define BT_MCS_OPC_SUP_GOTO_TRACK BIT(15) + +/** Support the Previous Group opcode */ +#define BT_MCS_OPC_SUP_PREV_GROUP BIT(16) +/** Support the Next Group opcode */ +#define BT_MCS_OPC_SUP_NEXT_GROUP BIT(17) +/** Support the First Group opcode */ +#define BT_MCS_OPC_SUP_FIRST_GROUP BIT(18) +/** Support the Last Group opcode */ +#define BT_MCS_OPC_SUP_LAST_GROUP BIT(19) +/** Support the Goto Group opcode */ +#define BT_MCS_OPC_SUP_GOTO_GROUP BIT(20) +/** @} */ + +/** + * @name Media control point notification result codes + * @{ + */ +/** Action requested by the opcode write was completed successfully. */ +#define BT_MCS_OPC_NTF_SUCCESS 0x01 +/** An invalid or unsupported opcode was used for the Media Control Point write. */ +#define BT_MCS_OPC_NTF_NOT_SUPPORTED 0x02 +/** + * The Media Player State characteristic value is Inactive when the opcode is received or the + * result of the requested action of the opcode results in the Media Player State characteristic + * being set to Inactive. + */ +#define BT_MCS_OPC_NTF_PLAYER_INACTIVE 0x03 +/** + * The requested action of any Media Control Point write cannot be completed successfully because of + * a condition within the player. + */ +#define BT_MCS_OPC_NTF_CANNOT_BE_COMPLETED 0x04 +/** @} */ + +/** + * @name Search control point type values + * + * Reference: Media Control Service spec v1.0 section 3.20.2 + * @{ + */ +/** Search for Track Name */ +#define BT_MCS_SEARCH_TYPE_TRACK_NAME 0x01 +/** Search for Artist Name */ +#define BT_MCS_SEARCH_TYPE_ARTIST_NAME 0x02 +/** Search for Album Name */ +#define BT_MCS_SEARCH_TYPE_ALBUM_NAME 0x03 +/** Search for Group Name */ +#define BT_MCS_SEARCH_TYPE_GROUP_NAME 0x04 +/** Search for Earliest Year */ +#define BT_MCS_SEARCH_TYPE_EARLIEST_YEAR 0x05 +/** Search for Latest Year */ +#define BT_MCS_SEARCH_TYPE_LATEST_YEAR 0x06 +/** Search for Genre */ +#define BT_MCS_SEARCH_TYPE_GENRE 0x07 +/** Search for Tracks only */ +#define BT_MCS_SEARCH_TYPE_ONLY_TRACKS 0x08 +/** Search for Groups only */ +#define BT_MCS_SEARCH_TYPE_ONLY_GROUPS 0x09 +/** @} */ + +/** + * @brief Search control point minimum length + * + * At least one search control item (SCI), consisting of the length octet and the type octet. + * (The * parameter field may be empty.) + */ +#define SEARCH_LEN_MIN 2 + +/** Search control point maximum length */ +#define SEARCH_LEN_MAX 64 + +/** + * @brief Search control point item (SCI) minimum length + * + * An SCI length can be as little as one byte, for an SCI that has only the type field. + * (The SCI len is the length of type + param.) + */ +#define SEARCH_SCI_LEN_MIN 1 /* An SCI length can be as little as one byte, + * for an SCI that has only the type field. + * (The SCI len is the length of type + param.) + */ + +/** Search parameters maximum length */ +#define SEARCH_PARAM_MAX 62 + +/** + * @name Search notification result codes + * + * Reference: Media Control Service spec v1.0 section 3.20.2 + * @{ + */ +/** Search request was accepted; search has started. */ +#define BT_MCS_SCP_NTF_SUCCESS 0x01 +/** Search request was invalid; no search started. */ +#define BT_MCS_SCP_NTF_FAILURE 0x02 +/** @} */ + +/** + * @name Group object object types + * + * Reference: Media Control Service spec v1.0 section 4.4.1 + * @{ + */ +/** Group object type is track */ +#define BT_MCS_GROUP_OBJECT_TRACK_TYPE 0x00 +/** Group object type is group */ +#define BT_MCS_GROUP_OBJECT_GROUP_TYPE 0x01 +/** @} */ + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_MCS_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/media_proxy.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/media_proxy.h new file mode 100644 index 0000000000..8626cfddda --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/media_proxy.h @@ -0,0 +1,1799 @@ +/** + * @file + * @brief Bluetooth Media Proxy APIs + */ + +/* + * SPDX-FileCopyrightText: 2019-2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_MEDIA_PROXY_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_MEDIA_PROXY_H_ + +/** + * @brief Media proxy module + * + * @defgroup bt_media_proxy Media Proxy + * + * @since 3.0 + * @version 0.8.0 + * + * @ingroup bluetooth + * @{ + * + * The media proxy module is the connection point between media players + * and media controllers. + * + * A media player has (access to) media content and knows how to + * navigate and play this content. A media controller reads or gets + * information from a player and controls the player by setting player + * parameters and giving the player commands. + * + * The media proxy module allows media player implementations to make + * themselves available to media controllers. And it allows + * controllers to access, and get updates from, any player. + * + * The media proxy module allows both local and remote control of + * local player instances: A media controller may be a local + * application, or it may be a Media Control Service relaying requests + * from a remote Media Control Client. There may be either local or + * remote control, or both, or even multiple instances of each. + */ + +#include +#include + +#include +#include + +/* TODO: Remove dependency on mcs.h */ +#include "mcs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Media player command + */ +struct mpl_cmd { + /** The opcode. See the MEDIA_PROXY_OP_* values */ + uint8_t opcode; + /** Whether or not the @ref mpl_cmd.param is used */ + bool use_param; + /** A 32-bit signed parameter. The parameter value depends on the @ref mpl_cmd.opcode */ + int32_t param; +}; + +/** + * @brief Media command notification + */ +struct mpl_cmd_ntf { + /** The opcode that was sent */ + uint8_t requested_opcode; + /** The result of the operation */ + uint8_t result_code; +}; + +/** + * @brief Search control item + */ +struct mpl_sci { + uint8_t len; /**< Length of type and parameter */ + uint8_t type; /**< MEDIA_PROXY_SEARCH_TYPE_<...> */ + char param[SEARCH_PARAM_MAX]; /**< Search parameter */ +}; + +/** + * @brief Search + */ +struct mpl_search { + /** The length of the @ref mpl_search.search value */ + uint8_t len; + /** Concatenated search control items - (type, length, param) */ + char search[SEARCH_LEN_MAX]; +}; + +/** + * @name Playback speed parameters + * + * All values from -128 to 127 allowed, only some defined + * @{ + */ +/** Minimum playback speed, resulting in 25 % speed */ +#define MEDIA_PROXY_PLAYBACK_SPEED_MIN -128 +/** Quarter playback speed, resulting in 25 % speed */ +#define MEDIA_PROXY_PLAYBACK_SPEED_QUARTER -128 +/** Half playback speed, resulting in 50 % speed */ +#define MEDIA_PROXY_PLAYBACK_SPEED_HALF -64 +/** Unity playback speed, resulting in 100 % speed */ +#define MEDIA_PROXY_PLAYBACK_SPEED_UNITY 0 +/** Double playback speed, resulting in 200 % speed */ +#define MEDIA_PROXY_PLAYBACK_SPEED_DOUBLE 64 +/** Max playback speed, resulting in 395.7 % speed (nearly 400 %) */ +#define MEDIA_PROXY_PLAYBACK_SPEED_MAX 127 +/** @} */ + +/** + * @name Seeking speed factors + * + * The allowed values for seeking speed are the range -64 to -4 + * (endpoints included), the value 0, and the range 4 to 64 + * (endpoints included). + * @{ + */ +/** Maximum seeking speed - Can be negated */ +#define MEDIA_PROXY_SEEKING_SPEED_FACTOR_MAX 64 +/** Minimum seeking speed - Can be negated */ +#define MEDIA_PROXY_SEEKING_SPEED_FACTOR_MIN 4 +/** No seeking */ +#define MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO 0 +/** @} */ + +/** + * @name Playing orders + * @{ + */ +/** A single track is played once; there is no next track. */ +#define MEDIA_PROXY_PLAYING_ORDER_SINGLE_ONCE 0x01 +/** A single track is played repeatedly; the next track is the current track. */ +#define MEDIA_PROXY_PLAYING_ORDER_SINGLE_REPEAT 0x02 +/** The tracks within a group are played once in track order. */ +#define MEDIA_PROXY_PLAYING_ORDER_INORDER_ONCE 0x03 +/** The tracks within a group are played in track order repeatedly. */ +#define MEDIA_PROXY_PLAYING_ORDER_INORDER_REPEAT 0x04 +/** The tracks within a group are played once only from the oldest first. */ +#define MEDIA_PROXY_PLAYING_ORDER_OLDEST_ONCE 0x05 +/** The tracks within a group are played from the oldest first repeatedly. */ +#define MEDIA_PROXY_PLAYING_ORDER_OLDEST_REPEAT 0x06 +/** The tracks within a group are played once only from the newest first. */ +#define MEDIA_PROXY_PLAYING_ORDER_NEWEST_ONCE 0x07 +/** The tracks within a group are played from the newest first repeatedly. */ +#define MEDIA_PROXY_PLAYING_ORDER_NEWEST_REPEAT 0x08 +/** The tracks within a group are played in random order once. */ +#define MEDIA_PROXY_PLAYING_ORDER_SHUFFLE_ONCE 0x09 +/** The tracks within a group are played in random order repeatedly. */ +#define MEDIA_PROXY_PLAYING_ORDER_SHUFFLE_REPEAT 0x0a +/** @} */ + +/** + * @name Playing orders supported + * + * A bitmap, in the same order as the playing orders above. + * Note that playing order 1 corresponds to bit 0, and so on. + * @{ + */ +/** A single track is played once; there is no next track. */ +#define MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_SINGLE_ONCE BIT(0) +/** A single track is played repeatedly; the next track is the current track. */ +#define MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_SINGLE_REPEAT BIT(1) +/** The tracks within a group are played once in track order. */ +#define MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_INORDER_ONCE BIT(2) +/** The tracks within a group are played in track order repeatedly. */ +#define MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_INORDER_REPEAT BIT(3) +/** The tracks within a group are played once only from the oldest first. */ +#define MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_OLDEST_ONCE BIT(4) +/** The tracks within a group are played from the oldest first repeatedly. */ +#define MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_OLDEST_REPEAT BIT(5) +/** The tracks within a group are played once only from the newest first. */ +#define MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_NEWEST_ONCE BIT(6) +/** The tracks within a group are played from the newest first repeatedly. */ +#define MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_NEWEST_REPEAT BIT(7) +/** The tracks within a group are played in random order once. */ +#define MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_SHUFFLE_ONCE BIT(8) +/** The tracks within a group are played in random order repeatedly. */ +#define MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_SHUFFLE_REPEAT BIT(9) +/** @} */ + +/** + * @name Media player states + * @{ + */ +/** The current track is invalid, and no track has been selected. */ +#define MEDIA_PROXY_STATE_INACTIVE 0x00 +/** The media player is playing the current track. */ +#define MEDIA_PROXY_STATE_PLAYING 0x01 +/** The current track is paused. The media player has a current track, but it is not being played */ +#define MEDIA_PROXY_STATE_PAUSED 0x02 +/** The current track is fast forwarding or fast rewinding. */ +#define MEDIA_PROXY_STATE_SEEKING 0x03 +/** Used internally as the last state value */ +#define MEDIA_PROXY_STATE_LAST 0x04 +/** @} */ + +/** + * @name Media player command opcodes + * @{ + */ +/** Start playing the current track. */ +#define MEDIA_PROXY_OP_PLAY 0x01 +/** Pause playing the current track. */ +#define MEDIA_PROXY_OP_PAUSE 0x02 +/** Fast rewind the current track. */ +#define MEDIA_PROXY_OP_FAST_REWIND 0x03 +/** Fast forward the current track. */ +#define MEDIA_PROXY_OP_FAST_FORWARD 0x04 +/** + * Stop current activity and return to the paused state and set the current track position to the + * start of the current track. + */ +#define MEDIA_PROXY_OP_STOP 0x05 + +/** Set a new current track position relative to the current track position. */ +#define MEDIA_PROXY_OP_MOVE_RELATIVE 0x10 + +/** + * Set the current track position to the starting position of the previous segment of the current + * track. + */ +#define MEDIA_PROXY_OP_PREV_SEGMENT 0x20 +/** + * Set the current track position to the starting position of + * the next segment of the current track. + */ +#define MEDIA_PROXY_OP_NEXT_SEGMENT 0x21 +/** + * Set the current track position to the starting position of + * the first segment of the current track. + */ +#define MEDIA_PROXY_OP_FIRST_SEGMENT 0x22 +/** + * Set the current track position to the starting position of + * the last segment of the current track. + */ +#define MEDIA_PROXY_OP_LAST_SEGMENT 0x23 +/** + * Set the current track position to the starting position of + * the nth segment of the current track. + */ +#define MEDIA_PROXY_OP_GOTO_SEGMENT 0x24 + +/** Set the current track to the previous track based on the playing order. */ +#define MEDIA_PROXY_OP_PREV_TRACK 0x30 +/** Set the current track to the next track based on the playing order. */ +#define MEDIA_PROXY_OP_NEXT_TRACK 0x31 +/** Set the current track to the first track based on the playing order. */ +#define MEDIA_PROXY_OP_FIRST_TRACK 0x32 +/** Set the current track to the last track based on the playing order. */ +#define MEDIA_PROXY_OP_LAST_TRACK 0x33 +/** Set the current track to the nth track based on the playing order. */ +#define MEDIA_PROXY_OP_GOTO_TRACK 0x34 + +/** Set the current group to the previous group in the sequence of groups. */ +#define MEDIA_PROXY_OP_PREV_GROUP 0x40 +/** Set the current group to the next group in the sequence of groups. */ +#define MEDIA_PROXY_OP_NEXT_GROUP 0x41 +/** Set the current group to the first group in the sequence of groups. */ +#define MEDIA_PROXY_OP_FIRST_GROUP 0x42 +/** Set the current group to the last group in the sequence of groups. */ +#define MEDIA_PROXY_OP_LAST_GROUP 0x43 +/** Set the current group to the nth group in the sequence of groups. */ +#define MEDIA_PROXY_OP_GOTO_GROUP 0x44 +/** @} */ + +/** + * @brief Media player supported opcodes length + */ +#define MEDIA_PROXY_OPCODES_SUPPORTED_LEN 4 + +/** + * @brief Media player supported command opcodes + * @{ + */ +/** Support the Play opcode */ +#define MEDIA_PROXY_OP_SUP_PLAY BIT(0) +/** Support the Pause opcode */ +#define MEDIA_PROXY_OP_SUP_PAUSE BIT(1) +/** Support the Fast Rewind opcode */ +#define MEDIA_PROXY_OP_SUP_FAST_REWIND BIT(2) +/** Support the Fast Forward opcode */ +#define MEDIA_PROXY_OP_SUP_FAST_FORWARD BIT(3) +/** Support the Stop opcode */ +#define MEDIA_PROXY_OP_SUP_STOP BIT(4) + +/** Support the Move Relative opcode */ +#define MEDIA_PROXY_OP_SUP_MOVE_RELATIVE BIT(5) + +/** Support the Previous Segment opcode */ +#define MEDIA_PROXY_OP_SUP_PREV_SEGMENT BIT(6) +/** Support the Next Segment opcode */ +#define MEDIA_PROXY_OP_SUP_NEXT_SEGMENT BIT(7) +/** Support the First Segment opcode */ +#define MEDIA_PROXY_OP_SUP_FIRST_SEGMENT BIT(8) +/** Support the Last Segment opcode */ +#define MEDIA_PROXY_OP_SUP_LAST_SEGMENT BIT(9) +/** Support the Goto Segment opcode */ +#define MEDIA_PROXY_OP_SUP_GOTO_SEGMENT BIT(10) + +/** Support the Previous Track opcode */ +#define MEDIA_PROXY_OP_SUP_PREV_TRACK BIT(11) +/** Support the Next Track opcode */ +#define MEDIA_PROXY_OP_SUP_NEXT_TRACK BIT(12) +/** Support the First Track opcode */ +#define MEDIA_PROXY_OP_SUP_FIRST_TRACK BIT(13) +/** Support the Last Track opcode */ +#define MEDIA_PROXY_OP_SUP_LAST_TRACK BIT(14) +/** Support the Goto Track opcode */ +#define MEDIA_PROXY_OP_SUP_GOTO_TRACK BIT(15) + +/** Support the Previous Group opcode */ +#define MEDIA_PROXY_OP_SUP_PREV_GROUP BIT(16) +/** Support the Next Group opcode */ +#define MEDIA_PROXY_OP_SUP_NEXT_GROUP BIT(17) +/** Support the First Group opcode */ +#define MEDIA_PROXY_OP_SUP_FIRST_GROUP BIT(18) +/** Support the Last Group opcode */ +#define MEDIA_PROXY_OP_SUP_LAST_GROUP BIT(19) +/** Support the Goto Group opcode */ +#define MEDIA_PROXY_OP_SUP_GOTO_GROUP BIT(20) +/** @} */ + +/** + * @name Media player command result codes + * @{ + */ +/** Action requested by the opcode write was completed successfully. */ +#define MEDIA_PROXY_CMD_SUCCESS 0x01 +/** An invalid or unsupported opcode was used for the Media Control Point write. */ +#define MEDIA_PROXY_CMD_NOT_SUPPORTED 0x02 +/** + * The Media Player State characteristic value is Inactive when the opcode is received or the + * result of the requested action of the opcode results in the Media Player State characteristic + * being set to Inactive. + */ +#define MEDIA_PROXY_CMD_PLAYER_INACTIVE 0x03 +/** + * The requested action of any Media Control Point write cannot be completed successfully because of + * a condition within the player. + */ +#define MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED 0x04 +/** @} */ + +/** + * @name Search operation type values + * @{ + */ +/** Search for Track Name */ +#define MEDIA_PROXY_SEARCH_TYPE_TRACK_NAME 0x01 +/** Search for Artist Name */ +#define MEDIA_PROXY_SEARCH_TYPE_ARTIST_NAME 0x02 +/** Search for Album Name */ +#define MEDIA_PROXY_SEARCH_TYPE_ALBUM_NAME 0x03 +/** Search for Group Name */ +#define MEDIA_PROXY_SEARCH_TYPE_GROUP_NAME 0x04 +/** Search for Earliest Year */ +#define MEDIA_PROXY_SEARCH_TYPE_EARLIEST_YEAR 0x05 +/** Search for Latest Year */ +#define MEDIA_PROXY_SEARCH_TYPE_LATEST_YEAR 0x06 +/** Search for Genre */ +#define MEDIA_PROXY_SEARCH_TYPE_GENRE 0x07 +/** Search for Tracks only */ +#define MEDIA_PROXY_SEARCH_TYPE_ONLY_TRACKS 0x08 +/** Search for Groups only */ +#define MEDIA_PROXY_SEARCH_TYPE_ONLY_GROUPS 0x09 +/** @} */ + +/** + * @name Search notification result codes + * + * @{ + */ +/** Search request was accepted; search has started. */ +#define MEDIA_PROXY_SEARCH_SUCCESS 0x01 +/** Search request was invalid; no search started. */ +#define MEDIA_PROXY_SEARCH_FAILURE 0x02 +/** @} */ + +/** + * @name Group object object types + * + * @{ + */ +/** Group object type is track */ +#define MEDIA_PROXY_GROUP_OBJECT_TRACK_TYPE 0x00 +/** Group object type is group */ +#define MEDIA_PROXY_GROUP_OBJECT_GROUP_TYPE 0x01 +/** @} */ + +/** + * @brief Opaque media player instance + */ +struct media_player; + +/* PUBLIC API FOR CONTROLLERS */ + +/** + * @brief Callbacks to a controller, from the media proxy + * + * Given by a controller when registering + */ +struct media_proxy_ctrl_cbs { + + /** + * @brief Media Player Instance callback + * + * Called when the local Media Player instance is registered or read (TODO). + * Also called if the local player instance is already registered when + * the controller is registered. + * Provides the controller with the pointer to the local player instance. + * + * @param player Media player instance pointer + * @param err Error value. 0 on success, or errno on negative value. + */ + void (*local_player_instance)(struct media_player *player, int err); + + /** + * @brief Discover Player Instance callback + * + * Called when a remote player instance has been discovered. + * The instance has been discovered, and will be accessed, using Bluetooth, + * via media control client and a remote media control service. + * + * @param player Instance pointer to the remote player + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + */ + void (*discover_player)(struct media_player *player, int err); + + /** + * @brief Media Player Name receive callback + * + * Called when the Media Player Name is read or changed + * See also media_proxy_ctrl_name_get() + * + * @param player Media player instance pointer + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * @param name The name of the media player + */ + void (*player_name_recv)(struct media_player *player, int err, const char *name); + + /** + * @brief Media Player Icon Object ID receive callback + * + * Called when the Media Player Icon Object ID is read + * See also media_proxy_ctrl_get_icon_id() + * + * @param player Media player instance pointer + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * @param id The ID of the Icon object in the Object Transfer Service (48 bits) + */ + void (*icon_id_recv)(struct media_player *player, int err, uint64_t id); + + /** + * @brief Media Player Icon URL receive callback + * + * Called when the Media Player Icon URL is read + * See also media_proxy_ctrl_get_icon_url() + * + * @param player Media player instance pointer + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * @param url The URL of the icon + */ + void (*icon_url_recv)(struct media_player *player, int err, const char *url); + + /** + * @brief Track changed receive callback + * + * Called when the Current Track is changed + * + * @param player Media player instance pointer + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + */ + void (*track_changed_recv)(struct media_player *player, int err); + + /** + * @brief Track Title receive callback + * + * Called when the Track Title is read or changed + * See also media_proxy_ctrl_get_track_title() + * + * @param player Media player instance pointer + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * @param title The title of the current track + */ + void (*track_title_recv)(struct media_player *player, int err, const char *title); + + /** + * @brief Track Duration receive callback + * + * Called when the Track Duration is read or changed + * See also media_proxy_ctrl_get_track_duration() + * + * @param player Media player instance pointer + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * @param duration The duration of the current track + */ + void (*track_duration_recv)(struct media_player *player, int err, int32_t duration); + + /** + * @brief Track Position receive callback + * + * Called when the Track Position is read or changed + * See also media_proxy_ctrl_get_track_position() and + * media_proxy_ctrl_set_track_position() + * + * @param player Media player instance pointer + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * @param position The player's position in the track + */ + void (*track_position_recv)(struct media_player *player, int err, int32_t position); + + /** + * @brief Track Position write callback + * + * Called when the Track Position is written + * See also media_proxy_ctrl_set_track_position(). + * + * @param player Media player instance pointer + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * @param position The position given attempted to write + */ + void (*track_position_write)(struct media_player *player, int err, int32_t position); + + /** + * @brief Playback Speed receive callback + * + * Called when the Playback Speed is read or changed + * See also media_proxy_ctrl_get_playback_speed() and + * media_proxy_ctrl_set_playback_speed() + * + * @param player Media player instance pointer + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * @param speed The playback speed parameter + */ + void (*playback_speed_recv)(struct media_player *player, int err, int8_t speed); + + /** + * @brief Playback Speed write callback + * + * Called when the Playback Speed is written + * See also media_proxy_ctrl_set_playback_speed() + * + * @param player Media player instance pointer + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * @param speed The playback speed parameter attempted to write + */ + void (*playback_speed_write)(struct media_player *player, int err, int8_t speed); + + /** + * @brief Seeking Speed receive callback + * + * Called when the Seeking Speed is read or changed + * See also media_proxy_ctrl_get_seeking_speed() + * + * @param player Media player instance pointer + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * @param speed The seeking speed factor + */ + void (*seeking_speed_recv)(struct media_player *player, int err, int8_t speed); + + /** + * @brief Track Segments Object ID receive callback + * + * Called when the Track Segments Object ID is read + * See also media_proxy_ctrl_get_track_segments_id() + * + * @param player Media player instance pointer + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * @param id The ID of the track segments object in Object Transfer Service (48 bits) + */ + void (*track_segments_id_recv)(struct media_player *player, int err, uint64_t id); + + /** + * @brief Current Track Object ID receive callback + * + * Called when the Current Track Object ID is read or changed + * See also media_proxy_ctrl_get_current_track_id() and + * media_proxy_ctrl_set_current_track_id() + * + * @param player Media player instance pointer + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * @param id The ID of the current track object in Object Transfer Service (48 bits) + */ + void (*current_track_id_recv)(struct media_player *player, int err, uint64_t id); + + /** + * @brief Current Track Object ID write callback + * + * Called when the Current Track Object ID is written + * See also media_proxy_ctrl_set_current_track_id() + * + * @param player Media player instance pointer + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * @param id The ID (48 bits) attempted to write + */ + void (*current_track_id_write)(struct media_player *player, int err, uint64_t id); + + /** + * @brief Next Track Object ID receive callback + * + * Called when the Next Track Object ID is read or changed + * See also media_proxy_ctrl_get_next_track_id() and + * media_proxy_ctrl_set_next_track_id() + * + * @param player Media player instance pointer + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * @param id The ID of the next track object in Object Transfer Service (48 bits) + */ + void (*next_track_id_recv)(struct media_player *player, int err, uint64_t id); + + /** + * @brief Next Track Object ID write callback + * + * Called when the Next Track Object ID is written + * See also media_proxy_ctrl_set_next_track_id() + * + * @param player Media player instance pointer + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * @param id The ID (48 bits) attempted to write + */ + void (*next_track_id_write)(struct media_player *player, int err, uint64_t id); + + /** + * @brief Parent Group Object ID receive callback + * + * Called when the Parent Group Object ID is read or changed + * See also media_proxy_ctrl_get_parent_group_id() + * + * @param player Media player instance pointer + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * @param id The ID of the parent group object in Object Transfer Service (48 bits) + */ + void (*parent_group_id_recv)(struct media_player *player, int err, uint64_t id); + + /** + * @brief Current Group Object ID receive callback + * + * Called when the Current Group Object ID is read or changed + * See also media_proxy_ctrl_get_current_group_id() and + * media_proxy_ctrl_set_current_group_id() + * + * @param player Media player instance pointer + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * @param id The ID of the current group object in Object Transfer Service (48 bits) + */ + void (*current_group_id_recv)(struct media_player *player, int err, uint64_t id); + + /** + * @brief Current Group Object ID write callback + * + * Called when the Current Group Object ID is written + * See also media_proxy_ctrl_set_current_group_id() + * + * @param player Media player instance pointer + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * @param id The ID (48 bits) attempted to write + */ + void (*current_group_id_write)(struct media_player *player, int err, uint64_t id); + + /** + * @brief Playing Order receive callback + * + * Called when the Playing Order is read or changed + * See also media_proxy_ctrl_get_playing_order() and + * media_proxy_ctrl_set_playing_order() + * + * @param player Media player instance pointer + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * @param order The playing order + */ + void (*playing_order_recv)(struct media_player *player, int err, uint8_t order); + + /** + * @brief Playing Order write callback + * + * Called when the Playing Order is written + * See also media_proxy_ctrl_set_playing_order() + * + * @param player Media player instance pointer + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * @param order The playing order attempted to write + */ + void (*playing_order_write)(struct media_player *player, int err, uint8_t order); + + /** + * @brief Playing Orders Supported receive callback + * + * Called when the Playing Orders Supported is read + * See also media_proxy_ctrl_get_playing_orders_supported() + * + * @param player Media player instance pointer + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * @param orders The playing orders supported + */ + void (*playing_orders_supported_recv)(struct media_player *player, int err, + uint16_t orders); + + /** + * @brief Media State receive callback + * + * Called when the Media State is read or changed + * See also media_proxy_ctrl_get_media_state() and + * media_proxy_ctrl_send_command() + * + * @param player Media player instance pointer + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * @param state The media player state + */ + void (*media_state_recv)(struct media_player *player, int err, uint8_t state); + + /** + * @brief Command send callback + * + * Called when a command has been sent + * See also media_proxy_ctrl_send_command() + * + * @param player Media player instance pointer + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * @param cmd The command sent + */ + void (*command_send)(struct media_player *player, int err, const struct mpl_cmd *cmd); + + /** + * @brief Command result receive callback + * + * Called when a command result has been received + * See also media_proxy_ctrl_send_command() + * + * @param player Media player instance pointer + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * @param result The result received + */ + void (*command_recv)(struct media_player *player, int err, + const struct mpl_cmd_ntf *result); + + /** + * @brief Commands supported receive callback + * + * Called when the Commands Supported is read or changed + * See also media_proxy_ctrl_get_commands_supported() + * + * @param player Media player instance pointer + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * @param opcodes The supported command opcodes (bitmap) + */ + void (*commands_supported_recv)(struct media_player *player, int err, uint32_t opcodes); + + /** + * @brief Search send callback + * + * Called when a search has been sent + * See also media_proxy_ctrl_send_search() + * + * @param player Media player instance pointer + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * @param search The search sent + */ + void (*search_send)(struct media_player *player, int err, const struct mpl_search *search); + + /** + * @brief Search result code receive callback + * + * Called when a search result code has been received + * See also media_proxy_ctrl_send_search() + * + * The search result code tells whether the search was successful or not. + * For a successful search, the actual results of the search (i.e. what was found + * as a result of the search)can be accessed using the Search Results Object ID. + * The Search Results Object ID has a separate callback - search_results_id_recv(). + * + * @param player Media player instance pointer + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * @param result_code Search result code + */ + void (*search_recv)(struct media_player *player, int err, uint8_t result_code); + + /** + * @brief Search Results Object ID receive callback + * See also media_proxy_ctrl_get_search_results_id() + * + * Called when the Search Results Object ID is read or changed + * + * @param player Media player instance pointer + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * @param id The ID of the search results object in Object Transfer Service (48 bits) + */ + void (*search_results_id_recv)(struct media_player *player, int err, uint64_t id); + + /** + * @brief Content Control ID receive callback + * + * Called when the Content Control ID is read + * See also media_proxy_ctrl_get_content_ctrl_id() + * + * @param player Media player instance pointer + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * @param ccid The content control ID + */ + void (*content_ctrl_id_recv)(struct media_player *player, int err, uint8_t ccid); +}; + +/** + * @brief Register a controller with the media_proxy + * + * @param ctrl_cbs Callbacks to the controller + * + * @return 0 if success, errno on failure + */ +int bt_media_proxy_ctrl_register_safe(struct media_proxy_ctrl_cbs *ctrl_cbs); + +/** + * @brief Discover a remote media player + * + * Discover a remote media player instance. + * The remote player instance will be discovered, and accessed, using Bluetooth, + * via the media control client and a remote media control service. + * This call will start a GATT discovery of the Media Control Service on the peer, + * and setup handles and subscriptions. + * + * This shall be called once before any other actions can be executed for the + * remote player. The remote player instance will be returned in the + * discover_player() callback. + * + * @param conn The connection to do discovery for + * + * @return 0 if success, errno on failure + */ +int bt_media_proxy_ctrl_discover_player(struct bt_conn *conn); +int bt_media_proxy_ctrl_discover_player_safe(struct bt_conn *conn); + +/** + * @brief Read Media Player Name + * + * @param player Media player instance pointer + * + * @return 0 if success, errno on failure. + */ +int bt_media_proxy_ctrl_get_player_name_safe(struct media_player *player); + +/** + * @brief Read Icon Object ID + * + * Get an ID (48 bit) that can be used to retrieve the Icon + * Object from an Object Transfer Service + * + * See the Media Control Service spec v1.0 sections 3.2 and + * 4.1 for a description of the Icon Object. + * + * Requires Object Transfer Service + * + * @param player Media player instance pointer + * + * @return 0 if success, errno on failure. + */ +int bt_media_proxy_ctrl_get_icon_id_safe(struct media_player *player); + +/** + * @brief Read Icon URL + * + * Get a URL to the media player's icon. + * + * @param player Media player instance pointer + */ +int bt_media_proxy_ctrl_get_icon_url_safe(struct media_player *player); + +/** + * @brief Read Track Title + * + * @param player Media player instance pointer + * + * @return 0 if success, errno on failure. + */ +int bt_media_proxy_ctrl_get_track_title_safe(struct media_player *player); + +/** + * @brief Read Track Duration + * + * The duration of a track is measured in hundredths of a + * second. + * + * @param player Media player instance pointer + * + * @return 0 if success, errno on failure. + */ +int bt_media_proxy_ctrl_get_track_duration_safe(struct media_player *player); + +/** + * @brief Read Track Position + * + * The position of the player (the playing position) is + * measured in hundredths of a second from the beginning of + * the track + * + * @param player Media player instance pointer + * + * @return 0 if success, errno on failure. + */ +int bt_media_proxy_ctrl_get_track_position_safe(struct media_player *player); + +/** + * @brief Set Track Position + * + * Set the playing position of the media player in the current + * track. The position is given in hundredths of a second, + * from the beginning of the track of the track for positive + * values, and (backwards) from the end of the track for + * negative values. + * + * @param player Media player instance pointer + * @param position The track position to set + * + * @return 0 if success, errno on failure. + */ +int bt_media_proxy_ctrl_set_track_position_safe(struct media_player *player, int32_t position); + +/** + * @brief Get Playback Speed + * + * The playback speed parameter is related to the actual + * playback speed as follows: + * actual playback speed = 2^(speed_parameter/64) + * + * A speed parameter of 0 corresponds to unity speed playback + * (i.e. playback at "normal" speed). A speed parameter of + * -128 corresponds to playback at one fourth of normal speed, + * 127 corresponds to playback at almost four times the normal + * speed. + * + * @param player Media player instance pointer + * + * @return 0 if success, errno on failure. + */ +int bt_media_proxy_ctrl_get_playback_speed_safe(struct media_player *player); + +/** + * @brief Set Playback Speed + * + * See the get_playback_speed() function for an explanation of + * the playback speed parameter. + * + * Note that the media player may not support all possible + * values of the playback speed parameter. If the value given + * is not supported, and is higher than the current value, the + * player should set the playback speed to the next higher + * supported value. (And correspondingly to the next lower + * supported value for given values lower than the current + * value.) + * + * @param player Media player instance pointer + * @param speed The playback speed parameter to set + * + * @return 0 if success, errno on failure. + */ +int bt_media_proxy_ctrl_set_playback_speed_safe(struct media_player *player, int8_t speed); + +/** + * @brief Get Seeking Speed + * + * The seeking speed gives the speed with which the player is + * seeking. It is a factor, relative to real-time playback + * speed - a factor four means seeking happens at four times + * the real-time playback speed. Positive values are for + * forward seeking, negative values for backwards seeking. + * + * The seeking speed is not settable - a non-zero seeking speed + * is the result of "fast rewind" of "fast forward" commands. + * + * @param player Media player instance pointer + * + * @return 0 if success, errno on failure. + */ +int bt_media_proxy_ctrl_get_seeking_speed_safe(struct media_player *player); + +/** + * @brief Read Current Track Segments Object ID + * + * Get an ID (48 bit) that can be used to retrieve the Current + * Track Segments Object from an Object Transfer Service + * + * See the Media Control Service spec v1.0 sections 3.10 and + * 4.2 for a description of the Track Segments Object. + * + * Requires Object Transfer Service + * + * @param player Media player instance pointer + * + * @return 0 if success, errno on failure. + */ +int bt_media_proxy_ctrl_get_track_segments_id_safe(struct media_player *player); + +/** + * @brief Read Current Track Object ID + * + * Get an ID (48 bit) that can be used to retrieve the Current + * Track Object from an Object Transfer Service + * + * See the Media Control Service spec v1.0 sections 3.11 and + * 4.3 for a description of the Current Track Object. + * + * Requires Object Transfer Service + * + * @param player Media player instance pointer + * + * @return 0 if success, errno on failure. + */ +int bt_media_proxy_ctrl_get_current_track_id_safe(struct media_player *player); + +/** + * @brief Set Current Track Object ID + * + * Change the player's current track to the track given by the ID. + * (Behaves similarly to the goto track command.) + * + * Requires Object Transfer Service + * + * @param player Media player instance pointer + * @param id The ID of a track object + * + * @return 0 if success, errno on failure. + */ +int bt_media_proxy_ctrl_set_current_track_id_safe(struct media_player *player, uint64_t id); + +/** + * @brief Read Next Track Object ID + * + * Get an ID (48 bit) that can be used to retrieve the Next + * Track Object from an Object Transfer Service + * + * Requires Object Transfer Service + * + * @param player Media player instance pointer + * + * @return 0 if success, errno on failure. + */ +int bt_media_proxy_ctrl_get_next_track_id_safe(struct media_player *player); + +/** + * @brief Set Next Track Object ID + * + * Change the player's next track to the track given by the ID. + * + * Requires Object Transfer Service + * + * @param player Media player instance pointer + * @param id The ID of a track object + * + * @return 0 if success, errno on failure. + */ +int bt_media_proxy_ctrl_set_next_track_id_safe(struct media_player *player, uint64_t id); + +/** + * @brief Read Parent Group Object ID + * + * Get an ID (48 bit) that can be used to retrieve the Parent + * Track Object from an Object Transfer Service + * + * The parent group is the parent of the current group. + * + * See the Media Control Service spec v1.0 sections 3.14 and + * 4.4 for a description of the Current Track Object. + * + * Requires Object Transfer Service + * + * @param player Media player instance pointer + * + * @return 0 if success, errno on failure. + */ +int bt_media_proxy_ctrl_get_parent_group_id_safe(struct media_player *player); + +/** + * @brief Read Current Group Object ID + * + * Get an ID (48 bit) that can be used to retrieve the Current + * Track Object from an Object Transfer Service + * + * See the Media Control Service spec v1.0 sections 3.14 and + * 4.4 for a description of the Current Group Object. + * + * Requires Object Transfer Service + * + * @param player Media player instance pointer + * + * @return 0 if success, errno on failure. + */ +int bt_media_proxy_ctrl_get_current_group_id_safe(struct media_player *player); + +/** + * @brief Set Current Group Object ID + * + * Change the player's current group to the group given by the + * ID, and the current track to the first track in that group. + * + * Requires Object Transfer Service + * + * @param player Media player instance pointer + * @param id The ID of a group object + * + * @return 0 if success, errno on failure. + */ +int bt_media_proxy_ctrl_set_current_group_id_safe(struct media_player *player, uint64_t id); + +/** + * @brief Read Playing Order + * + * @param player Media player instance pointer + * + * @return 0 if success, errno on failure. + */ +int bt_media_proxy_ctrl_get_playing_order_safe(struct media_player *player); + +/** + * @brief Set Playing Order + * + * Set the media player's playing order + * + * @param player Media player instance pointer + * @param order The playing order to set + * + * @return 0 if success, errno on failure. + */ +int bt_media_proxy_ctrl_set_playing_order_safe(struct media_player *player, uint8_t order); + +/** + * @brief Read Playing Orders Supported + * + * Read a bitmap containing the media player's supported + * playing orders. + * + * @param player Media player instance pointer + * + * @return 0 if success, errno on failure. + */ +int bt_media_proxy_ctrl_get_playing_orders_supported_safe(struct media_player *player); + +/** + * @brief Read Media State + * + * Read the media player's state + * + * @param player Media player instance pointer + * + * @return 0 if success, errno on failure. + */ +int bt_media_proxy_ctrl_get_media_state_safe(struct media_player *player); + +/** + * @brief Send Command + * + * Send a command to the media player. + * Commands may cause the media player to change its state + * May result in two callbacks - one for the actual sending of the command to the + * player, one for the result of the command from the player. + * + * @param player Media player instance pointer + * @param command The command to send + * + * @return 0 if success, errno on failure. + */ +int bt_media_proxy_ctrl_send_command_safe(struct media_player *player, const struct mpl_cmd *command); + +/** + * @brief Read Commands Supported + * + * Read a bitmap containing the media player's supported + * command opcodes. + * + * @param player Media player instance pointer + * + * @return 0 if success, errno on failure. + */ +int bt_media_proxy_ctrl_get_commands_supported_safe(struct media_player *player); + +/** + * @brief Set Search + * + * Write a search to the media player. + * If the search is successful, the search results will be available as a group object + * in the Object Transfer Service (OTS). + * + * May result in up to three callbacks + * - one for the actual sending of the search to the player + * - one for the result code for the search from the player + * - if the search is successful, one for the search results object ID in the OTs + * + * Requires Object Transfer Service + * + * @param player Media player instance pointer + * @param search The search to write + * + * @return 0 if success, errno on failure. + */ +int bt_media_proxy_ctrl_send_search_safe(struct media_player *player, const struct mpl_search *search); + +/** + * @brief Read Search Results Object ID + * + * Get an ID (48 bit) that can be used to retrieve the Search + * Results Object from an Object Transfer Service + * + * The search results object is a group object. + * The search results object only exists if a successful + * search operation has been done. + * + * Requires Object Transfer Service + * + * @param player Media player instance pointer + * + * @return 0 if success, errno on failure. + */ +int bt_media_proxy_ctrl_get_search_results_id_safe(struct media_player *player); + +/** + * @brief Read Content Control ID + * + * The content control ID identifies a content control service + * on a device, and links it to the corresponding audio + * stream. + * + * @param player Media player instance pointer + * + * @return 0 if success, errno on failure. + */ +uint8_t bt_media_proxy_ctrl_get_content_ctrl_id_safe(struct media_player *player); + +/** + * @brief Available calls in a player, that the media proxy can call + * + * Given by a player when registering. + */ +struct media_proxy_pl_calls { + + /** + * @brief Read Media Player Name + * + * @return The name of the media player + */ + const char *(*get_player_name)(void); + + /** + * @brief Read Icon Object ID + * + * Get an ID (48 bit) that can be used to retrieve the Icon + * Object from an Object Transfer Service + * + * See the Media Control Service spec v1.0 sections 3.2 and + * 4.1 for a description of the Icon Object. + * + * @return The Icon Object ID + */ + uint64_t (*get_icon_id)(void); + + /** + * @brief Read Icon URL + * + * Get a URL to the media player's icon. + * + * @return The URL of the Icon + */ + const char *(*get_icon_url)(void); + + /** + * @brief Read Track Title + * + * @return The title of the current track + */ + const char *(*get_track_title)(void); + + /** + * @brief Read Track Duration + * + * The duration of a track is measured in hundredths of a + * second. + * + * @return The duration of the current track + */ + int32_t (*get_track_duration)(void); + + /** + * @brief Read Track Position + * + * The position of the player (the playing position) is + * measured in hundredths of a second from the beginning of + * the track + * + * @return The position of the player in the current track + */ + int32_t (*get_track_position)(void); + + /** + * @brief Set Track Position + * + * Set the playing position of the media player in the current + * track. The position is given in hundredths of a second, + * from the beginning of the track of the track for positive + * values, and (backwards) from the end of the track for + * negative values. + * + * @param position The player position to set + */ + void (*set_track_position)(int32_t position); + + /** + * @brief Get Playback Speed + * + * The playback speed parameter is related to the actual + * playback speed as follows: + * actual playback speed = 2^(speed_parameter/64) + * + * A speed parameter of 0 corresponds to unity speed playback + * (i.e. playback at "normal" speed). A speed parameter of + * -128 corresponds to playback at one fourth of normal speed, + * 127 corresponds to playback at almost four times the normal + * speed. + * + * @return The playback speed parameter + */ + int8_t (*get_playback_speed)(void); + + /** + * @brief Set Playback Speed + * + * See the get_playback_speed() function for an explanation of + * the playback speed parameter. + * + * Note that the media player may not support all possible + * values of the playback speed parameter. If the value given + * is not supported, and is higher than the current value, the + * player should set the playback speed to the next higher + * supported value. (And correspondingly to the next lower + * supported value for given values lower than the current + * value.) + * + * @param speed The playback speed parameter to set + */ + void (*set_playback_speed)(int8_t speed); + + /** + * @brief Get Seeking Speed + * + * The seeking speed gives the speed with which the player is + * seeking. It is a factor, relative to real-time playback + * speed - a factor four means seeking happens at four times + * the real-time playback speed. Positive values are for + * forward seeking, negative values for backwards seeking. + * + * The seeking speed is not settable - a non-zero seeking speed + * is the result of "fast rewind" of "fast forward" commands. + * + * @return The seeking speed factor + */ + int8_t (*get_seeking_speed)(void); + + /** + * @brief Read Current Track Segments Object ID + * + * Get an ID (48 bit) that can be used to retrieve the Current + * Track Segments Object from an Object Transfer Service + * + * See the Media Control Service spec v1.0 sections 3.10 and + * 4.2 for a description of the Track Segments Object. + * + * @return Current The Track Segments Object ID + */ + uint64_t (*get_track_segments_id)(void); + + /** + * @brief Read Current Track Object ID + * + * Get an ID (48 bit) that can be used to retrieve the Current + * Track Object from an Object Transfer Service + * + * See the Media Control Service spec v1.0 sections 3.11 and + * 4.3 for a description of the Current Track Object. + * + * @return The Current Track Object ID + */ + uint64_t (*get_current_track_id)(void); + + /** + * @brief Set Current Track Object ID + * + * Change the player's current track to the track given by the ID. + * (Behaves similarly to the goto track command.) + * + * @param id The ID of a track object + */ + void (*set_current_track_id)(uint64_t id); + + /** + * @brief Read Next Track Object ID + * + * Get an ID (48 bit) that can be used to retrieve the Next + * Track Object from an Object Transfer Service + * + * @return The Next Track Object ID + */ + uint64_t (*get_next_track_id)(void); + + /** + * @brief Set Next Track Object ID + * + * Change the player's next track to the track given by the ID. + * + * @param id The ID of a track object + */ + void (*set_next_track_id)(uint64_t id); + + /** + * @brief Read Parent Group Object ID + * + * Get an ID (48 bit) that can be used to retrieve the Parent + * Track Object from an Object Transfer Service + * + * The parent group is the parent of the current group. + * + * See the Media Control Service spec v1.0 sections 3.14 and + * 4.4 for a description of the Current Track Object. + * + * @return The Current Group Object ID + */ + uint64_t (*get_parent_group_id)(void); + + /** + * @brief Read Current Group Object ID + * + * Get an ID (48 bit) that can be used to retrieve the Current + * Track Object from an Object Transfer Service + * + * See the Media Control Service spec v1.0 sections 3.14 and + * 4.4 for a description of the Current Group Object. + * + * @return The Current Group Object ID + */ + uint64_t (*get_current_group_id)(void); + + /** + * @brief Set Current Group Object ID + * + * Change the player's current group to the group given by the + * ID, and the current track to the first track in that group. + * + * @param id The ID of a group object + */ + void (*set_current_group_id)(uint64_t id); + + /** + * @brief Read Playing Order + * + * return The media player's current playing order + */ + uint8_t (*get_playing_order)(void); + + /** + * @brief Set Playing Order + * + * Set the media player's playing order. + * See the MEDIA_PROXY_PLAYING_ORDER_* defines. + * + * @param order The playing order to set + */ + void (*set_playing_order)(uint8_t order); + + /** + * @brief Read Playing Orders Supported + * + * Read a bitmap containing the media player's supported + * playing orders. + * See the MEDIA_PROXY_PLAYING_ORDERS_SUPPORTED_* defines. + * + * @return The media player's supported playing orders + */ + uint16_t (*get_playing_orders_supported)(void); + + /** + * @brief Read Media State + * + * Read the media player's state + * See the MEDIA_PROXY_MEDIA_STATE_* defines. + * + * @return The media player's state + */ + uint8_t (*get_media_state)(void); + + /** + * @brief Send Command + * + * Send a command to the media player. + * For command opcodes (play, pause, ...) - see the MEDIA_PROXY_OP_* + * defines. + * + * @param command The command to send + */ + void (*send_command)(const struct mpl_cmd *command); + + /** + * @brief Read Commands Supported + * + * Read a bitmap containing the media player's supported + * command opcodes. + * See the MEDIA_PROXY_OP_SUP_* defines. + * + * @return The media player's supported command opcodes + */ + uint32_t (*get_commands_supported)(void); + + /** + * @brief Set Search + * + * Write a search to the media player. + * (For the formatting of a search, see the Media Control + * Service spec and the mcs.h file.) + * + * @param search The search to write + */ + void (*send_search)(const struct mpl_search *search); + + /** + * @brief Read Search Results Object ID + * + * Get an ID (48 bit) that can be used to retrieve the Search + * Results Object from an Object Transfer Service + * + * The search results object is a group object. + * The search results object only exists if a successful + * search operation has been done. + * + * @return The Search Results Object ID + */ + uint64_t (*get_search_results_id)(void); + + /** + * @brief Read Content Control ID + * + * The content control ID identifies a content control service + * on a device, and links it to the corresponding audio + * stream. + * + * @return The content control ID for the media player + */ + uint8_t (*get_content_ctrl_id)(void); +}; + +/** + * @brief Register a player with the media proxy + * + * Register a player with the media proxy module, for use by media + * controllers. + * + * The media proxy may call any non-NULL function pointers in the + * supplied media_proxy_pl_calls structure. + * + * @param pl_calls Function pointers to the media player's calls + * + * @return 0 if success, errno on failure + */ +int bt_media_proxy_pl_register_safe(struct media_proxy_pl_calls *pl_calls); + +/** + * @brief Initialize player + * + * TODO: Move to player header file + */ +int bt_media_proxy_pl_init_safe(void); + +/** + * @brief Get the pointer of the Object Transfer Service used by the Media Control Service + * + * TODO: Find best location for this call, and move this one also + */ +struct bt_ots *bt_mcs_get_ots_safe(void); + +/** + * @brief Player name changed callback + * + * To be called when the player's name is changed. + * + * @param name The name of the player + */ +void bt_media_proxy_pl_name_cb_safe(const char *name); + +/** + * @brief Player icon URL changed callback + * + * To be called when the player's icon URL is changed. + * + * @param url The URL of the player's icon + */ +void bt_media_proxy_pl_icon_url_cb_safe(const char *url); + +/** + * @brief Track changed callback + * + * To be called when the player's current track is changed + */ +void bt_media_proxy_pl_track_changed_cb_safe(void); + +/** + * @brief Track title callback + * + * To be called when the player's current track is changed + * + * @param title The title of the track + */ +void bt_media_proxy_pl_track_title_cb_safe(char *title); + +/** + * @brief Track duration callback + * + * To be called when the current track's duration is changed (e.g. due + * to a track change) + * + * The track duration is given in hundredths of a second. + * + * @param duration The track duration + */ +void bt_media_proxy_pl_track_duration_cb_safe(int32_t duration); + +/** + * @brief Track position callback + * + * To be called when the media player's position in the track is + * changed, or when the player is paused or similar. + * + * Exception: This callback should not be called when the position + * changes during regular playback, i.e. while the player is playing + * and playback happens at a constant speed. + * + * The track position is given in hundredths of a second from the + * start of the track. + * + * @param position The media player's position in the track + */ +void bt_media_proxy_pl_track_position_cb_safe(int32_t position); + +/** + * @brief Playback speed callback + * + * To be called when the playback speed is changed. + * + * @param speed The playback speed parameter + */ +void bt_media_proxy_pl_playback_speed_cb_safe(int8_t speed); + +/** + * @brief Seeking speed callback + * + * To be called when the seeking speed is changed. + * + * @param speed The seeking speed factor + */ +void bt_media_proxy_pl_seeking_speed_cb_safe(int8_t speed); + +/** + * @brief Current track object ID callback + * + * To be called when the ID of the current track is changed (e.g. due + * to a track change). + * + * @param id The ID of the current track object in the OTS + */ +void bt_media_proxy_pl_current_track_id_cb_safe(uint64_t id); + +/** + * @brief Next track object ID callback + * + * To be called when the ID of the current track is changes + * + * @param id The ID of the next track object in the OTS + */ +void bt_media_proxy_pl_next_track_id_cb_safe(uint64_t id); + +/** + * @brief Parent group object ID callback + * + * To be called when the ID of the parent group is changed + * + * @param id The ID of the parent group object in the OTS + */ +void bt_media_proxy_pl_parent_group_id_cb_safe(uint64_t id); + +/** + * @brief Current group object ID callback + * + * To be called when the ID of the current group is changed + * + * @param id The ID of the current group object in the OTS + */ +void bt_media_proxy_pl_current_group_id_cb_safe(uint64_t id); + +/** + * @brief Playing order callback + * + * To be called when the playing order is changed + * + * @param order The playing order + */ +void bt_media_proxy_pl_playing_order_cb_safe(uint8_t order); + +/** + * @brief Media state callback + * + * To be called when the media state is changed + * + * @param state The media player's state + */ +void bt_media_proxy_pl_media_state_cb_safe(uint8_t state); + +/** + * @brief Command callback + * + * To be called when a command has been sent, to notify whether the + * command was successfully performed or not. + * See the MEDIA_PROXY_CMD_* result code defines. + * + * @param cmd_ntf The result of the command + */ +void bt_media_proxy_pl_command_cb_safe(const struct mpl_cmd_ntf *cmd_ntf); + +/** + * @brief Commands supported callback + * + * To be called when the set of commands supported is changed + * + * @param opcodes The supported commands opcodes + */ +void bt_media_proxy_pl_commands_supported_cb_safe(uint32_t opcodes); + +/** + * @brief Search callback + * + * To be called when a search has been set to notify whether the + * search was successfully performed or not. + * See the MEDIA_PROXY_SEARCH_* result code defines. + * + * The actual results of the search, if successful, can be found in + * the search results object. + * + * @param result_code The result (success or failure) of the search + */ +void bt_media_proxy_pl_search_cb_safe(uint8_t result_code); + +/** + * @brief Search Results object ID callback + * + * To be called when the ID of the search results is changed + * (typically as the result of a new successful search). + * + * @param id The ID of the search results object in the OTS + */ +void bt_media_proxy_pl_search_results_id_cb_safe(uint64_t id); + +#ifdef __cplusplus +} +#endif + +/** @} */ /* End of group bt_media_proxy */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_MEDIA_PROXY_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/micp.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/micp.h new file mode 100644 index 0000000000..f2edec701a --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/micp.h @@ -0,0 +1,321 @@ +/** + * @file + * @brief Bluetooth Microphone Control Profile (MICP) APIs. + */ + +/* + * SPDX-FileCopyrightText: 2020-2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MICP_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_MICP_H_ + +/** + * @brief Microphone Control Profile (MICP) + * + * @defgroup bt_micp Microphone Control Profile (MICP) + * + * @since 2.7 + * @version 0.8.0 + * + * @ingroup bluetooth + * @{ + */ + +#include + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Application error codes + * @{ + */ +/** Mute/unmute commands are disabled. */ +#define BT_MICP_ERR_MUTE_DISABLED 0x80 +/** @} */ + +/** + * @name Microphone Control Profile mute states + * @{ + */ +/** The microphone state is unmuted */ +#define BT_MICP_MUTE_UNMUTED 0x00 +/** The microphone state is muted */ +#define BT_MICP_MUTE_MUTED 0x01 +/** The microphone state is disabled and cannot be muted or unmuted */ +#define BT_MICP_MUTE_DISABLED 0x02 +/** @} */ + +/** @brief Opaque Microphone Controller instance. */ +struct bt_micp_mic_ctlr; + +/** @brief Register parameters structure for Microphone Control Service */ +struct bt_micp_mic_dev_register_param { + /** Register parameter structure for Audio Input Control Services */ + struct bt_aics_register_param *aics_param; + + /** Microphone Control Profile callback structure. */ + struct bt_micp_mic_dev_cb *cb; +}; + +/** + * @brief Microphone Control Profile included services + * + * Used for to represent the Microphone Control Profile included service + * instances, for either a Microphone Controller or a Microphone Device. + * The instance pointers either represent local service instances, + * or remote service instances. + */ +struct bt_micp_included { + /** Number of Audio Input Control Service instances */ + uint8_t aics_cnt; + /** Array of pointers to Audio Input Control Service instances */ + struct bt_aics **aics; +}; + +/** + * @brief Initialize the Microphone Control Profile Microphone Device + * + * This will enable the Microphone Control Service instance and make it + * discoverable by Microphone Controllers. + * + * @param param Pointer to an initialization structure. + * + * @return 0 if success, errno on failure. + */ +int bt_micp_mic_dev_register_safe(struct bt_micp_mic_dev_register_param *param); + +/** + * @brief Get Microphone Device included services + * + * Returns a pointer to a struct that contains information about the + * Microphone Device included Audio Input Control Service instances. + * + * Requires that @kconfig{CONFIG_BT_MICP_MIC_DEV_AICS} is enabled. + * + * @param included Pointer to store the result in. + * + * @return 0 if success, errno on failure. + */ +int bt_micp_mic_dev_included_get_safe(struct bt_micp_included *included); + +/** + * @brief Struct to hold the Microphone Device callbacks + * + * These can be registered for usage with bt_micp_mic_dev_register(). + */ +struct bt_micp_mic_dev_cb { + /** + * @brief Callback function for Microphone Device mute. + * + * Called when the value is read with bt_micp_mic_dev_mute_get(), + * or if the value is changed by either the Microphone Device or a + * Microphone Controller. + * + * @param mute The mute setting of the Microphone Control Service. + */ + void (*mute)(uint8_t mute); +}; + +/** + * @brief Unmute the Microphone Device. + * + * @return 0 on success, GATT error value on fail. + */ +int bt_micp_mic_dev_unmute_safe(void); + +/** + * @brief Mute the Microphone Device. + * + * @return 0 on success, GATT error value on fail. + */ +int bt_micp_mic_dev_mute_safe(void); + +/** + * @brief Disable the mute functionality on the Microphone Device. + * + * Can be re-enabled by called @ref bt_micp_mic_dev_mute or @ref bt_micp_mic_dev_unmute. + * + * @return 0 on success, GATT error value on fail. + */ +int bt_micp_mic_dev_mute_disable_safe(void); + +/** + * @brief Read the mute state on the Microphone Device. + * + * @return 0 on success, GATT error value on fail. + */ +int bt_micp_mic_dev_mute_get_safe(void); + +/** + * @brief Struct to hold the Microphone Controller callbacks + * + * These can be registered for usage with bt_micp_mic_ctlr_cb_register(). + */ +struct bt_micp_mic_ctlr_cb { + /** + * @brief Callback function for Microphone Control Profile mute. + * + * Called when the value is read, + * or if the value is changed by either the Microphone Device or a + * Microphone Controller. + * + * @param mic_ctlr Microphone Controller instance pointer. + * @param err Error value. 0 on success, GATT error or errno on fail. + * For notifications, this will always be 0. + * @param mute The mute setting of the Microphone Control Service. + */ + void (*mute)(struct bt_micp_mic_ctlr *mic_ctlr, int err, uint8_t mute); + + /** + * @brief Callback function for bt_micp_mic_ctlr_discover(). + * + * @param mic_ctlr Microphone Controller instance pointer. + * @param err Error value. 0 on success, GATT error or errno on fail. + * @param aics_count Number of Audio Input Control Service instances on + * peer device. + */ + void (*discover)(struct bt_micp_mic_ctlr *mic_ctlr, int err, + uint8_t aics_count); + + /** + * @brief Callback function for Microphone Control Profile mute/unmute. + * + * @param mic_ctlr Microphone Controller instance pointer. + * @param err Error value. 0 on success, GATT error or errno on fail. + */ + void (*mute_written)(struct bt_micp_mic_ctlr *mic_ctlr, int err); + + /** + * @brief Callback function for Microphone Control Profile mute/unmute. + * + * @param mic_ctlr Microphone Controller instance pointer. + * @param err Error value. 0 on success, GATT error or errno on fail. + */ + void (*unmute_written)(struct bt_micp_mic_ctlr *mic_ctlr, int err); + + /** Audio Input Control Service client callback */ + struct bt_aics_cb aics_cb; + + /** @cond INTERNAL_HIDDEN */ + /** Internally used field for list handling */ + sys_snode_t _node; + /** @endcond */ +}; + +/** + * @brief Get Microphone Control Profile included services + * + * Returns a pointer to a struct that contains information about the + * Microphone Control Profile included services instances, such as + * pointers to the Audio Input Control Service instances. + * + * Requires that @kconfig{CONFIG_BT_MICP_MIC_CTLR_AICS} is enabled. + * + * @param mic_ctlr Microphone Controller instance pointer. + * @param[out] included Pointer to store the result in. + * + * @return 0 if success, errno on failure. + */ +int bt_micp_mic_ctlr_included_get_safe(struct bt_micp_mic_ctlr *mic_ctlr, + struct bt_micp_included *included); + +/** + * @brief Get the connection pointer of a Microphone Controller instance + * + * Get the Bluetooth connection pointer of a Microphone Controller instance. + * + * @param mic_ctlr Microphone Controller instance pointer. + * @param conn Connection pointer. + * + * @return 0 if success, errno on failure. + */ +int bt_micp_mic_ctlr_conn_get_safe(const struct bt_micp_mic_ctlr *mic_ctlr, + struct bt_conn **conn); + +/** + * @brief Get the volume controller from a connection pointer + * + * Get the Volume Control Profile Volume Controller pointer from a connection pointer. + * Only volume controllers that have been initiated via bt_micp_mic_ctlr_discover() can be + * retrieved. + * + * @param conn Connection pointer. + * + * @retval Pointer to a Microphone Control Profile Microphone Controller instance + * @retval NULL if @p conn is NULL or if the connection has not done discovery yet + */ +struct bt_micp_mic_ctlr *bt_micp_mic_ctlr_get_by_conn(const struct bt_conn *conn); + +/** + * @brief Discover Microphone Control Service + * + * This will start a GATT discovery and setup handles and subscriptions. + * This shall be called once before any other actions can be executed for the + * peer device, and the @ref bt_micp_mic_ctlr_cb.discover callback will notify + * when it is possible to start remote operations. + * * + * @param conn The connection to initialize the profile for. + * @param[out] mic_ctlr Valid remote instance object on success. + * + * @return 0 on success, GATT error value on fail. + */ +int bt_micp_mic_ctlr_discover(struct bt_conn *conn, + struct bt_micp_mic_ctlr **mic_ctlr); +int bt_micp_mic_ctlr_discover_safe(struct bt_conn *conn, + struct bt_micp_mic_ctlr **mic_ctlr); + +/** + * @brief Unmute a remote Microphone Device. + * + * @param mic_ctlr Microphone Controller instance pointer. + * + * @return 0 on success, GATT error value on fail. + */ +int bt_micp_mic_ctlr_unmute_safe(struct bt_micp_mic_ctlr *mic_ctlr); + +/** + * @brief Mute a remote Microphone Device. + * + * @param mic_ctlr Microphone Controller instance pointer. + * + * @return 0 on success, GATT error value on fail. + */ +int bt_micp_mic_ctlr_mute_safe(struct bt_micp_mic_ctlr *mic_ctlr); + +/** + * @brief Read the mute state of a remote Microphone Device. + * + * @param mic_ctlr Microphone Controller instance pointer. + * + * @return 0 on success, GATT error value on fail. + */ +int bt_micp_mic_ctlr_mute_get_safe(struct bt_micp_mic_ctlr *mic_ctlr); + +/** + * @brief Registers the callbacks used by Microphone Controller. + * + * This can only be done as the client. + * + * @param cb The callback structure. + * + * @return 0 if success, errno on failure. + */ +int bt_micp_mic_ctlr_cb_register_safe(struct bt_micp_mic_ctlr_cb *cb); +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MICP_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/pacs.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/pacs.h new file mode 100644 index 0000000000..0183a0ae27 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/pacs.h @@ -0,0 +1,234 @@ +/** + * @file + * @brief Bluetooth Published Audio Capabilities Service (PACS) APIs + */ + +/* SPDX-FileCopyrightText: 2021 Intel Corporation + * SPDX-FileCopyrightText: 2021-2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_PACS_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_PACS_H_ + +/** + * @brief Published Audio Capabilities Service (PACS) + * + * @defgroup bt_pacs Published Audio Capabilities Service (PACS) + * + * @since 3.0 + * @version 0.8.0 + * + * @ingroup bluetooth + * @{ + * + * The Published Audio Capabilities Service (PACS) is used to expose capabilities to remote devices. + */ + +#include + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief Published Audio Capability structure. */ +struct bt_pacs_cap { + /** Codec capability reference */ + const struct bt_audio_codec_cap *codec_cap; + + /** @cond INTERNAL_HIDDEN */ + /** Internally used field for list handling */ + sys_snode_t _node; + /** @endcond */ +}; + +/** Structure for registering PACS */ +struct bt_pacs_register_param { + /** + * @brief Enables or disables registration of Sink PAC Characteristic. + */ + bool snk_pac; + + /** + * @brief Enables or disables registration of Sink Location Characteristic. + * + * Registration of Sink Location is dependent on @ref bt_pacs_register_param.snk_pac + * also being set. + */ + bool snk_loc; + + /** + * @brief Enables or disables registration of Source PAC Characteristic. + */ + bool src_pac; + + /** + * @brief Enables or disables registration of Source Location Characteristic. + * + * Registration of Source Location is dependent on @ref bt_pacs_register_param.src_pac + * also being set. + */ + bool src_loc; +}; + +/** + * @typedef bt_pacs_cap_foreach_func_t + * @brief Published Audio Capability iterator callback. + * + * @param cap Capability found. + * @param user_data Data given. + * + * @return true to continue to the next capability + * @return false to stop the iteration + */ +typedef bool (*bt_pacs_cap_foreach_func_t)(const struct bt_pacs_cap *cap, + void *user_data); + +/** + * @brief Published Audio Capability iterator. + * + * Iterate capabilities with endpoint direction specified. + * + * @param dir Direction of the endpoint to look capability for. + * @param func Callback function. + * @param user_data Data to pass to the callback. + */ +void bt_pacs_cap_foreach_safe(enum bt_audio_dir dir, + bt_pacs_cap_foreach_func_t func, + void *user_data); + +/** + * @brief Register the Published Audio Capability Service instance. + * + * @param param PACS register parameters. + * + * @retval 0 Success + * @retval -EINVAL @p param is NULL or bad combination of values in @p param + * @retval -EALREADY Already registered + * @retval -ENOEXEC Request was rejected by GATT + */ +int bt_pacs_register_safe(const struct bt_pacs_register_param *param); + +/** + * @brief Unregister the Published Audio Capability Service instance. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_pacs_unregister_safe(void); + +/** + * @brief Register Published Audio Capability. + * + * Register Audio Local Capability. + * + * @param dir Direction of the endpoint to register capability for. + * @param cap Capability structure. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_pacs_cap_register_safe(enum bt_audio_dir dir, struct bt_pacs_cap *cap); + +/** + * @brief Unregister Published Audio Capability. + * + * Unregister Audio Local Capability. + * + * @param dir Direction of the endpoint to unregister capability for. + * @param cap Capability structure. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_pacs_cap_unregister_safe(enum bt_audio_dir dir, struct bt_pacs_cap *cap); + +/** + * @brief Set the location for an endpoint type + * + * @param dir Direction of the endpoints to change location for. + * @param location The location to be set. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_pacs_set_location_safe(enum bt_audio_dir dir, + enum bt_audio_location location); + +/** + * @brief Set the available contexts for an endpoint type + * + * @param dir Direction of the endpoints to change available contexts for. + * @param contexts The contexts to be set. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_pacs_set_available_contexts_safe(enum bt_audio_dir dir, + enum bt_audio_context contexts); + +/** + * @brief Get the available contexts for an endpoint type + * + * @param dir Direction of the endpoints to get contexts for. + * + * @return Bitmask of available contexts. + */ +enum bt_audio_context bt_pacs_get_available_contexts_safe(enum bt_audio_dir dir); + +/** + * @brief Set the available contexts for a given connection + * + * This function sets the available contexts value for a given @p conn connection object. + * If the @p contexts parameter is NULL the available contexts value is reset to default. + * The default value of the available contexts is set using @ref bt_pacs_set_available_contexts + * function. + * The Available Context Value is reset to default on ACL disconnection. + * + * @param conn Connection object. + * @param dir Direction of the endpoints to change available contexts for. + * @param contexts The contexts to be set or NULL to reset to default. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_pacs_conn_set_available_contexts_for_conn(struct bt_conn *conn, enum bt_audio_dir dir, + enum bt_audio_context *contexts); +int bt_pacs_conn_set_available_contexts_for_conn_safe(struct bt_conn *conn, enum bt_audio_dir dir, + enum bt_audio_context *contexts); + +/** + * @brief Get the available contexts for a given connection + * + * This server function returns the available contexts value for a given @p conn connection object. + * The value returned is the one set with @ref bt_pacs_conn_set_available_contexts_for_conn function + * or the default value set with @ref bt_pacs_set_available_contexts function. + * + * @param conn Connection object. + * @param dir Direction of the endpoints to get contexts for. + * + * @return Bitmask of available contexts. + * @retval BT_AUDIO_CONTEXT_TYPE_NONE if @p conn or @p dir are invalid + */ +enum bt_audio_context bt_pacs_get_available_contexts_for_conn(struct bt_conn *conn, + enum bt_audio_dir dir); +enum bt_audio_context bt_pacs_get_available_contexts_for_conn_safe(struct bt_conn *conn, + enum bt_audio_dir dir); + +/** + * @brief Set the supported contexts for an endpoint type + * + * @param dir Direction of the endpoints to change available contexts for. + * @param contexts The contexts to be set. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_pacs_set_supported_contexts_safe(enum bt_audio_dir dir, + enum bt_audio_context contexts); + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_PACS_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/pbp.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/pbp.h new file mode 100644 index 0000000000..7010a0fa42 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/pbp.h @@ -0,0 +1,103 @@ +/** + * @file + * @brief Public Broadcast Profile (PBP) APIs. + */ +/* + * SPDX-FileCopyrightText: 2023 NXP + * SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_PBP_ +#define ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_PBP_ + +/** + * @brief Public Broadcast Profile (PBP) + * + * @defgroup bt_pbp Public Broadcast Profile (PBP) + * + * @since 3.5 + * @version 0.8.0 + * + * @ingroup bluetooth + * @{ + * + * The Public Broadcast Profile (PBP) is used for public broadcasts by providing additional + * information in the advertising data. + */ +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Minimum size of the Public Broadcast Announcement + * + * It contains the Public Broadcast Announcement UUID (2), the Public Broadcast Announcement + * features (1) and the metadata length (1) + */ +#define BT_PBP_MIN_PBA_SIZE (BT_UUID_SIZE_16 + 1 + 1) + +/** Public Broadcast Announcement features */ +enum bt_pbp_announcement_feature { + /** Broadcast Streams encryption status */ + BT_PBP_ANNOUNCEMENT_FEATURE_ENCRYPTION = BIT(0), + /** Standard Quality Public Broadcast Audio configuration */ + BT_PBP_ANNOUNCEMENT_FEATURE_STANDARD_QUALITY = BIT(1), + /** High Quality Public Broadcast Audio configuration */ + BT_PBP_ANNOUNCEMENT_FEATURE_HIGH_QUALITY = BIT(2), +}; + +/** + * @brief Creates a Public Broadcast Announcement based on the information received + * in the features parameter. + * + * @param meta Metadata to be included in the advertising data + * @param meta_len Size of the metadata fields to be included in the advertising data + * @param features Public Broadcast Announcement features + * @param pba_data_buf Pointer to store the PBA advertising data. Buffer size needs to be + * meta_len + @ref BT_PBP_MIN_PBA_SIZE. + * + * @return 0 on success or an appropriate error code. + */ +int bt_pbp_get_announcement(const uint8_t meta[], size_t meta_len, + enum bt_pbp_announcement_feature features, + struct net_buf_simple *pba_data_buf); + +/** + * @brief Parses the received advertising data corresponding to a Public Broadcast + * Announcement. Returns the advertised Public Broadcast Announcement features and metadata. + * + * @param[in] data Advertising data to be checked + * @param[out] features Pointer to public broadcast source features to store the parsed features in + * @param[out] meta Pointer to the metadata present in the advertising data + * + * @return parsed metadata length on success. + * @retval -EINVAL if @p data, @p features or @p meta are NULL. + * @retval -ENOENT if @p data is not of type @ref BT_DATA_SVC_DATA16 or if the UUID in the service + * data is not @ref BT_UUID_PBA. + * @retval -EMSGSIZE if @p data is not large enough to contain a PBP announcement. + * @retval -EBADMSG if the @p data contains invalid data. + */ +int bt_pbp_parse_announcement(struct bt_data *data, enum bt_pbp_announcement_feature *features, + uint8_t **meta); + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_PBP_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/tbs.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/tbs.h new file mode 100644 index 0000000000..6609dbc519 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/tbs.h @@ -0,0 +1,1124 @@ +/** + * @file + * @brief Public APIs for Bluetooth Telephone Bearer Service. + * + * SPDX-FileCopyrightText: 2020 Bose Corporation + * SPDX-FileCopyrightText: 2021 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_TBS_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_TBS_H_ + +/** + * @brief Telephone Bearer Service (TBS) + * + * @defgroup bt_tbs Telephone Bearer Service (TBS) + * + * @since 3.0 + * @version 0.8.0 + * + * @ingroup bluetooth + * @{ + * + * The Telephone Bearer Service (TBS) provide procedures to discover telephone bearers and control + * calls. + */ + +#include +#include + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** A characteristic value has changed while a Read Long Value Characteristic sub-procedure is in + * progress + */ +#define BT_TBS_ERR_VAL_CHANGED 0x80 + +/** + * @name Call States + * @{ + */ +/** A remote party is calling (incoming call). */ +#define BT_TBS_CALL_STATE_INCOMING 0x00 +/** + * The process to call the remote party has started on the server, but the remote party is not + * being alerted (outgoing call). + */ +#define BT_TBS_CALL_STATE_DIALING 0x01 +/** A remote party is being alerted (outgoing call). */ +#define BT_TBS_CALL_STATE_ALERTING 0x02 +/** The call is in an active conversation. */ +#define BT_TBS_CALL_STATE_ACTIVE 0x03 +/** + * The call is connected but held locally. Locally Held implies that either the server or the + * client can affect the state. + */ +#define BT_TBS_CALL_STATE_LOCALLY_HELD 0x04 +/** + *The call is connected but held remotely. Remotely Held means that the state is controlled by the + * remote party of a call. + */ +#define BT_TBS_CALL_STATE_REMOTELY_HELD 0x05 +/** The call is connected but held both locally and remotely. */ +#define BT_TBS_CALL_STATE_LOCALLY_AND_REMOTELY_HELD 0x06 +/** @} */ + +/** + * @name Terminate Reason + * @{ + */ +/** The URI value used to originate a call was formed improperly. */ +#define BT_TBS_REASON_BAD_REMOTE_URI 0x00 +/** The call failed. */ +#define BT_TBS_REASON_CALL_FAILED 0x01 +/** The remote party ended the call. */ +#define BT_TBS_REASON_REMOTE_ENDED_CALL 0x02 +/** The call ended from the server. */ +#define BT_TBS_REASON_SERVER_ENDED_CALL 0x03 +/** The line was busy. */ +#define BT_TBS_REASON_LINE_BUSY 0x04 +/** Network congestion. */ +#define BT_TBS_REASON_NETWORK_CONGESTED 0x05 +/** The client terminated the call. */ +#define BT_TBS_REASON_CLIENT_TERMINATED 0x06 +/** No service. */ +#define BT_TBS_REASON_NO_SERVICE 0x07 +/** No answer. */ +#define BT_TBS_REASON_NO_ANSWER 0x08 +/** Unspecified. */ +#define BT_TBS_REASON_UNSPECIFIED 0x09 +/** @} */ + +/** + * @name Control point error codes + * @{ + */ +/** The opcode write was successful. */ +#define BT_TBS_RESULT_CODE_SUCCESS 0x00 +/** An invalid opcode was used for the Call Control Point write. */ +#define BT_TBS_RESULT_CODE_OPCODE_NOT_SUPPORTED 0x01 +/** The requested operation cannot be completed. */ +#define BT_TBS_RESULT_CODE_OPERATION_NOT_POSSIBLE 0x02 +/** The Call Index used for the Call Control Point write is invalid. */ +#define BT_TBS_RESULT_CODE_INVALID_CALL_INDEX 0x03 +/** + * The opcode written to the Call Control Point was received when the current Call State for the + * Call Index was not in the expected state. + */ +#define BT_TBS_RESULT_CODE_STATE_MISMATCH 0x04 +/** Lack of internal resources to complete the requested action. */ +#define BT_TBS_RESULT_CODE_OUT_OF_RESOURCES 0x05 +/** The Outgoing URI is incorrect or invalid when an Originate opcode is sent. */ +#define BT_TBS_RESULT_CODE_INVALID_URI 0x06 +/** @} */ + +/** + * @name Optional feature bits + * + * Optional features that can be supported. See bt_tbs_client_read_optional_opcodes() on how to + * read these from a remote device + * @{ + */ +/** Local Hold and Local Retrieve Call Control Point Opcodes supported */ +#define BT_TBS_FEATURE_HOLD BIT(0) +/** Join Call Control Point Opcode supported */ +#define BT_TBS_FEATURE_JOIN BIT(1) +/** All Control Point Opcodes supported */ +#define BT_TBS_FEATURE_ALL (BT_TBS_FEATURE_HOLD | BT_TBS_FEATURE_JOIN) +/** @} */ + +/** + * @name Signal strength value limits + * @{ + */ +/** No service */ +#define BT_TBS_SIGNAL_STRENGTH_NO_SERVICE 0 +/** Maximum signal strength */ +#define BT_TBS_SIGNAL_STRENGTH_MAX 100 +/** Signal strength is unknown */ +#define BT_TBS_SIGNAL_STRENGTH_UNKNOWN 255 +/** @} */ + +/** + * @name Bearer Technology + * @{ + */ +/** 3G */ +#define BT_TBS_TECHNOLOGY_3G 0x01 +/** 4G */ +#define BT_TBS_TECHNOLOGY_4G 0x02 +/** Long-term evolution (LTE) */ +#define BT_TBS_TECHNOLOGY_LTE 0x03 +/** Wifi */ +#define BT_TBS_TECHNOLOGY_WIFI 0x04 +/** 5G */ +#define BT_TBS_TECHNOLOGY_5G 0x05 +/** Global System for Mobile Communications (GSM) */ +#define BT_TBS_TECHNOLOGY_GSM 0x06 +/** Code-Division Multiple Access (CDMA) */ +#define BT_TBS_TECHNOLOGY_CDMA 0x07 +/** 2G */ +#define BT_TBS_TECHNOLOGY_2G 0x08 +/** Wideband Code-Division Multiple Access (WCDMA) */ +#define BT_TBS_TECHNOLOGY_WCDMA 0x09 +/** @} */ + +/** + * @name Call status flags bitfield + * @{ + */ +/** Inband ringtone enabled */ +#define BT_TBS_STATUS_FLAG_INBAND_RINGTONE BIT(0) +/** Server is in silent mod */ +#define BT_TBS_STATUS_FLAG_SILENT_MOD BIT(1) +/** @} */ + +/** + * @name Call flags bitfield + * @{ + */ +/** If set, call is outgoing else incoming */ +#define BT_TBS_CALL_FLAG_OUTGOING BIT(0) +/** If set call is withheld, else not withheld */ +#define BT_TBS_CALL_FLAG_WITHHELD BIT(1) +/** If set call is withheld by network, else provided by network */ +#define BT_TBS_CALL_FLAG_WITHHELD_BY_NETWORK BIT(2) +/** @} */ + +/** + * @brief The GTBS index denotes whenever a callback is from a + * Generic Telephone Bearer Service (GTBS) instance, or + * whenever the client should perform on action on the GTBS instance of the + * server, rather than any of the specific Telephone Bearer Service instances. + */ +#define BT_TBS_GTBS_INDEX 0xFF + +/** @brief Opaque Telephone Bearer Service instance. */ +struct bt_tbs_instance; + +/** + * @brief Callback function for client originating a call. + * + * @param conn The connection used. + * @param call_index The call index. + * @param uri The URI. The value may change, so should be + * copied if persistence is wanted. + * + * @return true if the call request was accepted and remote party is alerted. + */ +typedef bool (*bt_tbs_originate_call_cb)(struct bt_conn *conn, + uint8_t call_index, + const char *uri); + +/** + * @brief Callback function for client terminating a call. + * + * The call may be either terminated by the client or the server. + * + * @param conn The connection used. + * @param call_index The call index. + * @param reason The termination BT_TBS_REASON_* reason. + */ +typedef void (*bt_tbs_terminate_call_cb)(struct bt_conn *conn, + uint8_t call_index, + uint8_t reason); + +/** + * @brief Callback function for client joining calls. + * + * @param conn The connection used. + * @param call_index_count The number of call indexes to join. + * @param call_indexes The call indexes. + */ +typedef void (*bt_tbs_join_calls_cb)(struct bt_conn *conn, + uint8_t call_index_count, + const uint8_t *call_indexes); + +/** + * @brief Callback function for client request call state change + * + * @param conn The connection used. + * @param call_index The call index. + */ +typedef void (*bt_tbs_call_change_cb)(struct bt_conn *conn, + uint8_t call_index); + +/** + * @brief Callback function for authorizing a client. + * + * @param conn The connection used. + * + * @return true if authorized, false otherwise + */ +typedef bool (*bt_tbs_authorize_cb)(struct bt_conn *conn); + +/** + * @brief Struct to hold the Telephone Bearer Service callbacks + * + * These can be registered for usage with bt_tbs_register_cb(). + */ +struct bt_tbs_cb { + /** Client originating call */ + bt_tbs_originate_call_cb originate_call; + /** Client terminating call */ + bt_tbs_terminate_call_cb terminate_call; + /** Client holding call */ + bt_tbs_call_change_cb hold_call; + /** Client accepting call */ + bt_tbs_call_change_cb accept_call; + /** Client retrieving call */ + bt_tbs_call_change_cb retrieve_call; + /** Client joining calls */ + bt_tbs_join_calls_cb join_calls; + /** Callback to authorize a client */ + bt_tbs_authorize_cb authorize; +}; + +/** + * @brief Accept an alerting call. + * + * @param call_index The index of the call that will be accepted. + * + * @return int BT_TBS_RESULT_CODE_* if positive or 0, + * errno value if negative. + */ +int bt_tbs_accept_safe(uint8_t call_index); + +/** + * @brief Hold a call. + * + * @param call_index The index of the call that will be held. + * + * @return int BT_TBS_RESULT_CODE_* if positive or 0, + * errno value if negative. + */ +int bt_tbs_hold_safe(uint8_t call_index); + +/** + * @brief Retrieve a call. + * + * @param call_index The index of the call that will be retrieved. + * + * @return int BT_TBS_RESULT_CODE_* if positive or 0, + * errno value if negative. + */ +int bt_tbs_retrieve_safe(uint8_t call_index); + +/** + * @brief Terminate a call. + * + * @param call_index The index of the call that will be terminated. + * + * @return int BT_TBS_RESULT_CODE_* if positive or 0, + * errno value if negative. + */ +int bt_tbs_terminate_safe(uint8_t call_index); + +/** + * @brief Originate a call + * + * @param[in] bearer_index The index of the Telephone Bearer. + * @param[in] uri The remote URI. + * @param[out] call_index Pointer to a value where the new call_index will be + * stored. + * + * @return int A call index on success (positive value), + * errno value on fail. + */ +int bt_tbs_originate_safe(uint8_t bearer_index, char *uri, uint8_t *call_index); + +/** + * @brief Join calls + * + * @param call_index_cnt The number of call indexes to join + * @param call_indexes Array of call indexes to join. + * + * @return int BT_TBS_RESULT_CODE_* if positive or 0, + * errno value if negative. + */ +int bt_tbs_join_safe(uint8_t call_index_cnt, uint8_t *call_indexes); + +/** + * @brief Notify the server that the remote party answered the call. + * + * @param call_index The index of the call that was answered. + * + * @return int BT_TBS_RESULT_CODE_* if positive or 0, + * errno value if negative. + */ +int bt_tbs_remote_answer_safe(uint8_t call_index); + +/** + * @brief Notify the server that the remote party held the call. + * + * @param call_index The index of the call that was held. + * + * @return int BT_TBS_RESULT_CODE_* if positive or 0, + * errno value if negative. + */ +int bt_tbs_remote_hold_safe(uint8_t call_index); + +/** + * @brief Notify the server that the remote party retrieved the call. + * + * @param call_index The index of the call that was retrieved. + * + * @return int BT_TBS_RESULT_CODE_* if positive or 0, + * errno value if negative. + */ +int bt_tbs_remote_retrieve_safe(uint8_t call_index); + +/** + * @brief Notify the server that the remote party terminated the call. + * + * @param call_index The index of the call that was terminated. + * + * @return int BT_TBS_RESULT_CODE_* if positive or 0, + * errno value if negative. + */ +int bt_tbs_remote_terminate_safe(uint8_t call_index); + +/** + * @brief Notify the server of an incoming call. + * + * @param bearer_index The index of the Telephone Bearer. + * @param to The URI that is receiving the call. + * @param from The URI of the remote caller. + * @param friendly_name The friendly name of the remote caller. + * + * @return int New call index if positive or 0, + * errno value if negative. + */ +int bt_tbs_remote_incoming_safe(uint8_t bearer_index, const char *to, + const char *from, const char *friendly_name); + +/** + * @brief Set a new bearer provider. + * + * @param bearer_index The index of the Telephone Bearer or BT_TBS_GTBS_INDEX + * for GTBS. + * @param name The new bearer provider name. + * + * @return int BT_TBS_RESULT_CODE_* if positive or 0, + * errno value if negative. + */ +int bt_tbs_set_bearer_provider_name_safe(uint8_t bearer_index, const char *name); + +/** + * @brief Set a new bearer technology. + * + * @param bearer_index The index of the Telephone Bearer or BT_TBS_GTBS_INDEX + * for GTBS. + * @param new_technology The new bearer technology. + * + * @return int BT_TBS_RESULT_CODE_* if positive or 0, + * errno value if negative. + */ +int bt_tbs_set_bearer_technology_safe(uint8_t bearer_index, uint8_t new_technology); + +/** + * @brief Update the signal strength reported by the server. + * + * @param bearer_index The index of the Telephone Bearer or + * BT_TBS_GTBS_INDEX for GTBS. + * @param new_signal_strength The new signal strength. + * + * @return int BT_TBS_RESULT_CODE_* if positive or 0, + * errno value if negative. + */ +int bt_tbs_set_signal_strength_safe(uint8_t bearer_index, + uint8_t new_signal_strength); + +/** + * @brief Sets the feature and status value. + * + * @param bearer_index The index of the Telephone Bearer or BT_TBS_GTBS_INDEX + * for GTBS. + * @param status_flags The new feature and status value. + * + * @return int BT_TBS_RESULT_CODE_* if positive or 0, + * errno value if negative. + */ +int bt_tbs_set_status_flags_safe(uint8_t bearer_index, uint16_t status_flags); + +/** + * @brief Sets the URI scheme list of a bearer. + * + * @param bearer_index The index of the Telephone Bearer. + * @param uri_list List of URI prefixes (e.g. {"skype", "tel"}). + * @param uri_count Number of URI prefixes in @p uri_list. + * + * @return BT_TBS_RESULT_CODE_* if positive or 0, errno value if negative. + */ +int bt_tbs_set_uri_scheme_list_safe(uint8_t bearer_index, const char **uri_list, + uint8_t uri_count); +/** + * @brief Register the callbacks for TBS. + * + * @param cbs Pointer to the callback structure. + */ +void bt_tbs_register_cb_safe(struct bt_tbs_cb *cbs); + +/** Parameters for registering a Telephone Bearer Service */ +struct bt_tbs_register_param { + /** The name of the provider, for example a cellular service provider */ + char *provider_name; + + /** + * @brief The Uniform Caller Identifier of the bearer + * + * See the Uniform Caller Identifiers table in Bluetooth Assigned Numbers + */ + char *uci; + + /** + * The Uniform Resource Identifiers schemes supported by this bearer as an UTF-8 string + * + * See https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml for possible values. + * If multiple values are used, these shall be comma separated, e.g. "tel,skype". + */ + char *uri_schemes_supported; + + /** + * @brief Whether this bearer shall be registered as a Generic Telephone Bearer server + * + * A GTBS shall be registered before any non-GTBS services. There can only be a single GTBS + * registered. + */ + bool gtbs; + + /** + * @brief Whether the application will need to authorize changes to calls + * + * If set to false then the service will automatically accept write requests from clients. + */ + bool authorization_required; + + /** + * @brief The technology of the bearer + * + * See the BT_TBS_TECHNOLOGY_* values. + */ + uint8_t technology; + + /** + * @brief The optional supported features of the bearer + * + * See the BT_TBS_FEATURE_* values. + */ + uint8_t supported_features; +}; + +/** + * @brief Register a Telephone Bearer + * + * This will register a Telephone Bearer Service (TBS) (or a Generic Telephone Bearer service + * (GTBS)) with the provided parameters. + * + * As per the TBS specification, the GTBS shall be instantiated for the feature, and as such a GTBS + * shall always be registered before any TBS can be registered. + * Similarly, all TBS shall be unregistered before the GTBS can be unregistered with + * bt_tbs_unregister_bearer(). + * + * @param param The parameters to initialize the bearer. + + * @retval index The bearer index if return value is >= 0 + * @retval -EINVAL @p param contains invalid data + * @retval -EALREADY @p param.gtbs is true and GTBS has already been registered + * @retval -EAGAIN @p param.gtbs is false and GTBS has not been registered + * @retval -ENOMEM @p param.gtbs is false and no more TBS can be registered (see + * @kconfig{CONFIG_BT_TBS_BEARER_COUNT}) + * @retval -ENOEXEC The service failed to be registered + */ +int bt_tbs_register_bearer_safe(const struct bt_tbs_register_param *param); + +/** + * @brief Unregister a Telephone Bearer + * + * This will unregister a Telephone Bearer Service (TBS) (or a Generic Telephone Bearer service + * (GTBS)) with the provided parameters. The bearer shall be registered first by + * bt_tbs_register_bearer() before it can be unregistered. + * + * Similarly, all TBS shall be unregistered before the GTBS can be unregistered with. + * + * @param bearer_index The index of the bearer to unregister. + * + * @retval 0 Success + * @retval -EINVAL @p bearer_index is invalid + * @retval -EALREADY The bearer identified by @p bearer_index is not registered + * @retval -EAGAIN The bearer identified by @p bearer_index is GTBS and there are TBS instances + * registered. + * @retval -ENOEXEC The service failed to be unregistered + */ +int bt_tbs_unregister_bearer_safe(uint8_t bearer_index); + +/** @brief Prints all calls of all services to the debug log */ +void bt_tbs_dbg_print_calls(void); + +/** Struct to hold a call state */ +struct bt_tbs_client_call_state { + /** Index of the call */ + uint8_t index; + /** State of the call (see BT_TBS_CALL_STATE_*) */ + uint8_t state; + /** Call flags (see BT_TBS_CALL_FLAG_*) */ + uint8_t flags; +} __packed; + +/** Struct to hold a call as the Telephone Bearer Service client */ +struct bt_tbs_client_call { + /** Call information */ + struct bt_tbs_client_call_state call_info; + /** The remove URI */ + char *remote_uri; +}; + +/** + * @brief Callback function for ccp_discover. + * + * @param conn The connection that was used to discover CCP for a + * device. + * @param err Error value. BT_TBS_CLIENT_RESULT_CODE_*, + * GATT error or errno value. + * @param tbs_count Number of TBS instances on peer device. + * @param gtbs_found Whether or not the server has a Generic TBS instance. + */ +typedef void (*bt_tbs_client_discover_cb)(struct bt_conn *conn, int err, + uint8_t tbs_count, bool gtbs_found); + +/** + * @brief Callback function for writing values to peer device. + * + * @param conn The connection used in the function. + * @param err Error value. BT_TBS_CLIENT_RESULT_CODE_*, + * GATT error or errno value. + * @param inst_index The index of the TBS instance that was updated. + */ +typedef void (*bt_tbs_client_write_value_cb)(struct bt_conn *conn, int err, + uint8_t inst_index); + +/** + * @brief Callback function for the CCP call control functions. + * + * @param conn The connection used in the function. + * @param err Error value. BT_TBS_CLIENT_RESULT_CODE_*, + * GATT error or errno value. + * @param inst_index The index of the TBS instance that was updated. + * @param call_index The call index. For #bt_tbs_client_originate_call this will + * always be 0, and does not reflect the actual call index. + */ +typedef void (*bt_tbs_client_cp_cb)(struct bt_conn *conn, int err, + uint8_t inst_index, uint8_t call_index); + +/** + * @brief Callback function for functions that read a string value. + * + * @param conn The connection used in the function. + * @param err Error value. BT_TBS_CLIENT_RESULT_CODE_*, + * GATT error or errno value. + * @param inst_index The index of the TBS instance that was updated. + * @param value The Null-terminated string value. The value is not kept + * by the client, so must be copied to be saved. + */ +typedef void (*bt_tbs_client_read_string_cb)(struct bt_conn *conn, int err, + uint8_t inst_index, + const char *value); + +/** + * @brief Callback function for functions that read an integer value. + * + * @param conn The connection used in the function. + * @param err Error value. BT_TBS_CLIENT_RESULT_CODE_*, + * GATT error or errno value. + * @param inst_index The index of the TBS instance that was updated. + * @param value The integer value. + */ +typedef void (*bt_tbs_client_read_value_cb)(struct bt_conn *conn, int err, + uint8_t inst_index, uint32_t value); + +/** + * @brief Callback function for ccp_read_termination_reason. + * + * @param conn The connection used in the function. + * @param err Error value. BT_TBS_CLIENT_RESULT_CODE_*, + * GATT error or errno value. + * @param inst_index The index of the TBS instance that was updated. + * @param call_index The call index. + * @param reason The termination reason. + */ +typedef void (*bt_tbs_client_termination_reason_cb)(struct bt_conn *conn, + int err, uint8_t inst_index, + uint8_t call_index, + uint8_t reason); + +/** + * @brief Callback function for ccp_read_current_calls. + * + * @param conn The connection used in the function. + * @param err Error value. BT_TBS_CLIENT_RESULT_CODE_*, + * GATT error or errno value. + * @param inst_index The index of the TBS instance that was updated. + * @param call_count Number of calls read. + * @param calls Array of calls. The array is not kept by + * the client, so must be copied to be saved. + */ +typedef void (*bt_tbs_client_current_calls_cb)(struct bt_conn *conn, int err, + uint8_t inst_index, + uint8_t call_count, + const struct bt_tbs_client_call *calls); + +/** + * @brief Callback function for ccp_read_call_state. + * + * @param conn The connection used in the function. + * @param err Error value. BT_TBS_CLIENT_RESULT_CODE_*, + * GATT error or errno value. + * @param inst_index The index of the TBS instance that was updated. + * @param call_count Number of call states read. + * @param call_states Array of call states. The array is not kept by + * the client, so must be copied to be saved. + */ +typedef void (*bt_tbs_client_call_states_cb)(struct bt_conn *conn, int err, + uint8_t inst_index, + uint8_t call_count, + const struct bt_tbs_client_call_state *call_states); + +/** + * @brief Struct to hold the Telephone Bearer Service client callbacks + * + * These can be registered for usage with bt_tbs_client_register_cb(). + */ +struct bt_tbs_client_cb { + /** Discovery has completed */ + bt_tbs_client_discover_cb discover; + /** Originate call has completed */ + bt_tbs_client_cp_cb originate_call; + /** Terminate call has completed */ + bt_tbs_client_cp_cb terminate_call; + /** Hold call has completed */ + bt_tbs_client_cp_cb hold_call; + /** Accept call has completed */ + bt_tbs_client_cp_cb accept_call; + /** Retrieve call has completed */ + bt_tbs_client_cp_cb retrieve_call; + /** Join calls has completed */ + bt_tbs_client_cp_cb join_calls; + /** Bearer provider name has been read */ + bt_tbs_client_read_string_cb bearer_provider_name; + /** Bearer UCI has been read */ + bt_tbs_client_read_string_cb bearer_uci; + /** Bearer technology has been read */ + bt_tbs_client_read_value_cb technology; + /** Bearer URI list has been read */ + bt_tbs_client_read_string_cb uri_list; + /** Bearer signal strength has been read */ + bt_tbs_client_read_value_cb signal_strength; + /** Bearer signal interval has been read */ + bt_tbs_client_read_value_cb signal_interval; + /** Bearer current calls has been read */ + bt_tbs_client_current_calls_cb current_calls; + /** Bearer CCID has been read */ + bt_tbs_client_read_value_cb ccid; + /** Bearer call URI has been read */ + bt_tbs_client_read_string_cb call_uri; + /** Bearer status flags has been read */ + bt_tbs_client_read_value_cb status_flags; + /** Bearer call states has been read */ + bt_tbs_client_call_states_cb call_state; + /** Bearer optional opcodes has been read */ + bt_tbs_client_read_value_cb optional_opcodes; + /** Bearer terminate reason has been read */ + bt_tbs_client_termination_reason_cb termination_reason; + /** Bearer remote URI has been read */ + bt_tbs_client_read_string_cb remote_uri; + /** Bearer friendly name has been read */ + bt_tbs_client_read_string_cb friendly_name; + + /** @cond INTERNAL_HIDDEN */ + /** Internally used field for list handling */ + sys_snode_t _node; + /** @endcond */ +}; + +/** + * @brief Discover TBS for a connection. This will start a GATT + * discover and setup handles and subscriptions. + * + * @param conn The connection to discover TBS for. + * + * @return int 0 on success, GATT error value on fail. + */ +int bt_tbs_client_discover(struct bt_conn *conn); +int bt_tbs_client_discover_safe(struct bt_conn *conn); + +/** + * @brief Set the outgoing URI for a TBS instance on the peer device. + * + * @param conn The connection to the TBS server. + * @param inst_index The index of the TBS instance. + * @param uri The Null-terminated URI string. + * + * @return int 0 on success, errno value on fail. + */ +int bt_tbs_client_set_outgoing_uri_safe(struct bt_conn *conn, uint8_t inst_index, + const char *uri); + +/** + * @brief Set the signal strength reporting interval for a TBS instance. + * + * @param conn The connection to the TBS server. + * @param inst_index The index of the TBS instance. + * @param interval The interval to write (0-255 seconds). + * + * @return int 0 on success, errno value on fail. + * + * @note @kconfig{CONFIG_BT_TBS_CLIENT_SET_BEARER_SIGNAL_INTERVAL} must be set + * for this function to be effective. + */ +int bt_tbs_client_set_signal_strength_interval(struct bt_conn *conn, + uint8_t inst_index, + uint8_t interval); +int bt_tbs_client_set_signal_strength_interval_safe(struct bt_conn *conn, + uint8_t inst_index, + uint8_t interval); + +/** + * @brief Request to originate a call. + * + * @param conn The connection to the TBS server. + * @param inst_index The index of the TBS instance. + * @param uri The URI of the callee. + * + * @return int 0 on success, errno value on fail. + * + * @note @kconfig{CONFIG_BT_TBS_CLIENT_ORIGINATE_CALL} must be set + * for this function to be effective. + */ +int bt_tbs_client_originate_call(struct bt_conn *conn, uint8_t inst_index, + const char *uri); +int bt_tbs_client_originate_call_safe(struct bt_conn *conn, uint8_t inst_index, + const char *uri); + +/** + * @brief Request to terminate a call + * + * @param conn The connection to the TBS server. + * @param inst_index The index of the TBS instance. + * @param call_index The call index to terminate. + * + * @return int 0 on success, errno value on fail. + * + * @note @kconfig{CONFIG_BT_TBS_CLIENT_TERMINATE_CALL} must be set + * for this function to be effective. + */ +int bt_tbs_client_terminate_call(struct bt_conn *conn, uint8_t inst_index, + uint8_t call_index); +int bt_tbs_client_terminate_call_safe(struct bt_conn *conn, uint8_t inst_index, + uint8_t call_index); + +/** + * @brief Request to hold a call + * + * @param conn The connection to the TBS server. + * @param inst_index The index of the TBS instance. + * @param call_index The call index to place on hold. + * + * @return int 0 on success, errno value on fail. + * + * @note @kconfig{CONFIG_BT_TBS_CLIENT_HOLD_CALL} must be set + * for this function to be effective. + */ +int bt_tbs_client_hold_call(struct bt_conn *conn, uint8_t inst_index, + uint8_t call_index); +int bt_tbs_client_hold_call_safe(struct bt_conn *conn, uint8_t inst_index, + uint8_t call_index); + +/** + * @brief Accept an incoming call + * + * @param conn The connection to the TBS server. + * @param inst_index The index of the TBS instance. + * @param call_index The call index to accept. + * + * @return int 0 on success, errno value on fail. + * + * @note @kconfig{CONFIG_BT_TBS_CLIENT_ACCEPT_CALL} must be set + * for this function to be effective. + */ +int bt_tbs_client_accept_call(struct bt_conn *conn, uint8_t inst_index, + uint8_t call_index); +int bt_tbs_client_accept_call_safe(struct bt_conn *conn, uint8_t inst_index, + uint8_t call_index); + +/** + * @brief Retrieve call from (local) hold. + * + * @param conn The connection to the TBS server. + * @param inst_index The index of the TBS instance. + * @param call_index The call index to retrieve. + * + * @return int 0 on success, errno value on fail. + * + * @note @kconfig{CONFIG_BT_TBS_CLIENT_RETRIEVE_CALL} must be set + * for this function to be effective. + */ +int bt_tbs_client_retrieve_call(struct bt_conn *conn, uint8_t inst_index, + uint8_t call_index); +int bt_tbs_client_retrieve_call_safe(struct bt_conn *conn, uint8_t inst_index, + uint8_t call_index); + +/** + * @brief Join multiple calls. + * + * @param conn The connection to the TBS server. + * @param inst_index The index of the TBS instance. + * @param call_indexes Array of call indexes. + * @param count Number of call indexes in the call_indexes array. + * + * @return int 0 on success, errno value on fail. + * + * @note @kconfig{CONFIG_BT_TBS_CLIENT_JOIN_CALLS} must be set + * for this function to be effective. + */ +int bt_tbs_client_join_calls(struct bt_conn *conn, uint8_t inst_index, + const uint8_t *call_indexes, uint8_t count); +int bt_tbs_client_join_calls_safe(struct bt_conn *conn, uint8_t inst_index, + const uint8_t *call_indexes, uint8_t count); + +/** + * @brief Read the bearer provider name of a TBS instance. + * + * @param conn The connection to the TBS server. + * @param inst_index The index of the TBS instance. + * + * @return int 0 on success, errno value on fail. + * + * @note @kconfig{CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME} must be set + * for this function to be effective. + */ +int bt_tbs_client_read_bearer_provider_name(struct bt_conn *conn, uint8_t inst_index); +int bt_tbs_client_read_bearer_provider_name_safe(struct bt_conn *conn, + uint8_t inst_index); + +/** + * @brief Read the UCI of a TBS instance. + * + * @param conn The connection to the TBS server. + * @param inst_index The index of the TBS instance. + * + * @return int 0 on success, errno value on fail. + * + * @note @kconfig{CONFIG_BT_TBS_CLIENT_BEARER_UCI} must be set + * for this function to be effective. + */ +int bt_tbs_client_read_bearer_uci(struct bt_conn *conn, uint8_t inst_index); +int bt_tbs_client_read_bearer_uci_safe(struct bt_conn *conn, uint8_t inst_index); + +/** + * @brief Read the technology of a TBS instance. + * + * @param conn The connection to the TBS server. + * @param inst_index The index of the TBS instance. + * + * @return int 0 on success, errno value on fail. + * + * @note @kconfig{CONFIG_BT_TBS_CLIENT_BEARER_TECHNOLOGY} must be set + * for this function to be effective. + */ +int bt_tbs_client_read_technology(struct bt_conn *conn, uint8_t inst_index); +int bt_tbs_client_read_technology_safe(struct bt_conn *conn, uint8_t inst_index); + +/** + * @brief Read the URI schemes list of a TBS instance. + * + * @param conn The connection to the TBS server. + * @param inst_index The index of the TBS instance. + * + * @return int 0 on success, errno value on fail. + * + * @note @kconfig{CONFIG_BT_TBS_CLIENT_BEARER_URI_SCHEMES_SUPPORTED_LIST} must be set + * for this function to be effective. + */ +int bt_tbs_client_read_uri_list(struct bt_conn *conn, uint8_t inst_index); +int bt_tbs_client_read_uri_list_safe(struct bt_conn *conn, uint8_t inst_index); + +/** + * @brief Read the current signal strength of a TBS instance. + * + * @param conn The connection to the TBS server. + * @param inst_index The index of the TBS instance. + * + * @return int 0 on success, errno value on fail. + * + * @note @kconfig{CONFIG_BT_TBS_CLIENT_BEARER_SIGNAL_STRENGTH} must be set + * for this function to be effective. + */ +int bt_tbs_client_read_signal_strength(struct bt_conn *conn, uint8_t inst_index); +int bt_tbs_client_read_signal_strength_safe(struct bt_conn *conn, + uint8_t inst_index); + +/** + * @brief Read the signal strength reporting interval of a TBS instance. + * + * @param conn The connection to the TBS server. + * @param inst_index The index of the TBS instance. + * + * @return int 0 on success, errno value on fail. + * + * @note @kconfig{CONFIG_BT_TBS_CLIENT_READ_BEARER_SIGNAL_INTERVAL} must be set + * for this function to be effective. + */ +int bt_tbs_client_read_signal_interval(struct bt_conn *conn, uint8_t inst_index); +int bt_tbs_client_read_signal_interval_safe(struct bt_conn *conn, + uint8_t inst_index); + +/** + * @brief Read the list of current calls of a TBS instance. + * + * @param conn The connection to the TBS server. + * @param inst_index The index of the TBS instance. + * + * @return int 0 on success, errno value on fail. + * + * @note @kconfig{CONFIG_BT_TBS_CLIENT_BEARER_LIST_CURRENT_CALLS} must be set + * for this function to be effective. + */ +int bt_tbs_client_read_current_calls(struct bt_conn *conn, uint8_t inst_index); +int bt_tbs_client_read_current_calls_safe(struct bt_conn *conn, uint8_t inst_index); + +/** + * @brief Read the content ID of a TBS instance. + * + * @param conn The connection to the TBS server. + * @param inst_index The index of the TBS instance. + * + * @return int 0 on success, errno value on fail. + * + * @note @kconfig{CONFIG_BT_TBS_CLIENT_CCID} must be set + * for this function to be effective. + */ +int bt_tbs_client_read_ccid(struct bt_conn *conn, uint8_t inst_index); +int bt_tbs_client_read_ccid_safe(struct bt_conn *conn, uint8_t inst_index); + +/** + * @brief Read the call target URI of a TBS instance. + * + * @param conn The connection to the TBS server. + * @param inst_index The index of the TBS instance. + * + * @return int 0 on success, errno value on fail. + * + * @note @kconfig{CONFIG_BT_TBS_CLIENT_INCOMING_URI} must be set + * for this function to be effective. + */ +int bt_tbs_client_read_call_uri(struct bt_conn *conn, uint8_t inst_index); +int bt_tbs_client_read_call_uri_safe(struct bt_conn *conn, uint8_t inst_index); + +/** + * @brief Read the feature and status value of a TBS instance. + * + * @param conn The connection to the TBS server. + * @param inst_index The index of the TBS instance. + * + * @return int 0 on success, errno value on fail. + * + * @note @kconfig{CONFIG_BT_TBS_CLIENT_STATUS_FLAGS} must be set + * for this function to be effective. + */ +int bt_tbs_client_read_status_flags(struct bt_conn *conn, uint8_t inst_index); +int bt_tbs_client_read_status_flags_safe(struct bt_conn *conn, uint8_t inst_index); + +/** + * @brief Read the states of the current calls of a TBS instance. + * + * @param conn The connection to the TBS server. + * @param inst_index The index of the TBS instance. + * + * @return int 0 on success, errno value on fail. + */ +int bt_tbs_client_read_call_state(struct bt_conn *conn, uint8_t inst_index); +int bt_tbs_client_read_call_state_safe(struct bt_conn *conn, uint8_t inst_index); + +/** + * @brief Read the remote URI of a TBS instance. + * + * @param conn The connection to the TBS server. + * @param inst_index The index of the TBS instance. + * + * @return int 0 on success, errno value on fail. + * + * @note @kconfig{CONFIG_BT_TBS_CLIENT_INCOMING_CALL} must be set + * for this function to be effective. + */ +int bt_tbs_client_read_remote_uri(struct bt_conn *conn, uint8_t inst_index); +int bt_tbs_client_read_remote_uri_safe(struct bt_conn *conn, uint8_t inst_index); + +/** + * @brief Read the friendly name of a call for a TBS instance. + * + * @param conn The connection to the TBS server. + * @param inst_index The index of the TBS instance. + * + * @return int 0 on success, errno value on fail. + * + * @note @kconfig{CONFIG_BT_TBS_CLIENT_CALL_FRIENDLY_NAME} must be set + * for this function to be effective. + */ +int bt_tbs_client_read_friendly_name(struct bt_conn *conn, uint8_t inst_index); +int bt_tbs_client_read_friendly_name_safe(struct bt_conn *conn, uint8_t inst_index); + +/** + * @brief Read the supported opcode of a TBS instance. + * + * @param conn The connection to the TBS server. + * @param inst_index The index of the TBS instance. + * + * @return int 0 on success, errno value on fail. + * + * @note @kconfig{CONFIG_BT_TBS_CLIENT_OPTIONAL_OPCODES} must be set + * for this function to be effective. + */ +int bt_tbs_client_read_optional_opcodes(struct bt_conn *conn, uint8_t inst_index); +int bt_tbs_client_read_optional_opcodes_safe(struct bt_conn *conn, + uint8_t inst_index); + +/** + * @brief Register the callbacks for CCP. + * + * @param cbs Pointer to the callback structure. + * + * @retval 0 Success + * @retval -EINVAL @p cbs is NULL + * @retval -EEXIST @p cbs is already registered + */ +int bt_tbs_client_register_cb_safe(struct bt_tbs_client_cb *cbs); + +/** + * @brief Look up Telephone Bearer Service instance by CCID + * + * @param conn The connection to the TBS server. + * @param ccid The CCID to lookup a service instance for. + * + * @return Pointer to a Telephone Bearer Service instance if found else NULL. + * + * @note @kconfig{CONFIG_BT_TBS_CLIENT_CCID} must be set + * for this function to be effective. + */ +struct bt_tbs_instance *bt_tbs_client_get_by_ccid_safe(const struct bt_conn *conn, + uint8_t ccid); + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_TBS_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/tmap.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/tmap.h new file mode 100644 index 0000000000..95c2ac5c52 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/tmap.h @@ -0,0 +1,130 @@ +/** + * @file + * @brief Header for Bluetooth TMAP. + * + * SPDX-FileCopyrightText: 2023 NXP + * SPDX-FileCopyrightText: 2024-2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_TMAP_ +#define ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_TMAP_ + +/** + * @brief Telephone and Media Audio Profile (TMAP) + * + * @defgroup bt_tmap Telephone and Media Audio Profile (TMAP) + * + * @since 3.4 + * @version 0.8.0 + * + * @ingroup bluetooth + * @{ + * + * The Telephone and Media Audio Profile (TMAP) uses a collection of Bluetooth features and profiles + * to enable interoperability between devices for telephony and media audio. + */ + +#include +#include +#include +#include + +/** @brief TMAP Role characteristic */ +enum bt_tmap_role { + /** + * @brief TMAP Call Gateway role + * + * This role is defined to telephone and VoIP applications using the Call Control Profile + * to control calls on a remote TMAP Call Terminal. + * Audio streams in this role are typically bi-directional. + */ + BT_TMAP_ROLE_CG = BIT(0), + /** + * @brief TMAP Call Terminal role + * + * This role is defined to telephone and VoIP applications using the Call Control Profile + * to expose calls to remote TMAP Call Gateways. + * Audio streams in this role are typically bi-directional. + */ + BT_TMAP_ROLE_CT = BIT(1), + /** + * @brief TMAP Unicast Media Sender role + * + * This role is defined send media audio to TMAP Unicast Media Receivers. + * Audio streams in this role are typically uni-directional. + */ + BT_TMAP_ROLE_UMS = BIT(2), + /** + * @brief TMAP Unicast Media Receiver role + * + * This role is defined receive media audio to TMAP Unicast Media Senders. + * Audio streams in this role are typically uni-directional. + */ + BT_TMAP_ROLE_UMR = BIT(3), + /** + * @brief TMAP Broadcast Media Sender role + * + * This role is defined send media audio to TMAP Broadcast Media Receivers. + * Audio streams in this role are always uni-directional. + */ + BT_TMAP_ROLE_BMS = BIT(4), + /** + * @brief TMAP Broadcast Media Receiver role + * + * This role is defined send media audio to TMAP Broadcast Media Senders. + * Audio streams in this role are always uni-directional. + */ + BT_TMAP_ROLE_BMR = BIT(5), +}; + +/** @brief TMAP callback structure. */ +struct bt_tmap_cb { + /** + * @brief TMAP discovery complete callback + * + * This callback notifies the application about the value of the + * TMAP Role characteristic on the peer. + * + * @param role Peer TMAP role(s). + * @param conn Pointer to the connection + * @param err 0 if success, ATT error received from server otherwise. + */ + void (*discovery_complete)(enum bt_tmap_role role, struct bt_conn *conn, int err); +}; + +/** + * @brief Adds TMAS instance to database and sets the received TMAP role(s). + * + * @param role TMAP role(s) of the device (one or multiple). + * + * @return 0 on success or negative error value on failure. + */ +int bt_tmap_register_safe(enum bt_tmap_role role); + +/** + * @brief Perform service discovery as TMAP Client + * + * @param conn Pointer to the connection. + * @param tmap_cb Pointer to struct of TMAP callbacks. + * + * @return 0 on success or negative error value on failure. + */ +int bt_tmap_discover(struct bt_conn *conn, const struct bt_tmap_cb *tmap_cb); +int bt_tmap_discover_safe(struct bt_conn *conn, const struct bt_tmap_cb *tmap_cb); + +/** + * @brief Set one or multiple TMAP roles dynamically. + * Previously registered value will be overwritten. + * + * @param role TMAP role(s). + * + */ +void bt_tmap_set_role_safe(enum bt_tmap_role role); + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_TMAP_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/vcp.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/vcp.h new file mode 100644 index 0000000000..9b12c761b5 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/vcp.h @@ -0,0 +1,574 @@ +/** + * @file + * @brief Bluetooth Volume Control Profile (VCP) APIs. + */ + +/* + * SPDX-FileCopyrightText: 2020-2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_SERVICES_VCP_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_SERVICES_VCP_H_ + +/** + * @brief Volume Control Profile (VCP) + * + * @defgroup bt_vcp Volume Control Profile (VCP) + * + * @since 2.7 + * @version 0.8.0 + * + * @ingroup bluetooth + * @{ + * + * The Volume Control Profile (VCP) provides procedures to control the volume level and mute state + * on audio devices. + */ + +#include + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Volume Control Service Error codes + * @{ + */ +/** + * The Change_Counter operand value does not match the Change_Counter field value of the Volume + * State characteristic. + */ +#define BT_VCP_ERR_INVALID_COUNTER 0x80 +/** An invalid opcode has been used in a control point procedure. */ +#define BT_VCP_ERR_OP_NOT_SUPPORTED 0x81 +/** @} */ + +/** + * @name Volume Control Service Mute Values + * @{ + */ +/** The volume state is unmuted */ +#define BT_VCP_STATE_UNMUTED 0x00 +/** The volume state is muted */ +#define BT_VCP_STATE_MUTED 0x01 +/** @} */ + +/** @brief Opaque Volume Control Service instance. */ +struct bt_vcp_vol_ctlr; + +/** Register structure for Volume Control Service */ +struct bt_vcp_vol_rend_register_param { + /** Initial step size (1-255) */ + uint8_t step; + + /** Initial mute state (0-1) */ + uint8_t mute; + + /** Initial volume level (0-255) */ + uint8_t volume; + + /** Register parameters for Volume Offset Control Services */ + struct bt_vocs_register_param *vocs_param; + + /** Register parameters for Audio Input Control Services */ + struct bt_aics_register_param *aics_param; + + /** Volume Control Service callback structure. */ + struct bt_vcp_vol_rend_cb *cb; +}; + +/** + * @brief Volume Control Service included services + * + * Used for to represent the Volume Control Service included service instances, + * for either a client or a server. The instance pointers either represent + * local server instances, or remote service instances. + */ +struct bt_vcp_included { + /** Number of Volume Offset Control Service instances */ + uint8_t vocs_cnt; + /** Array of pointers to Volume Offset Control Service instances */ + struct bt_vocs **vocs; + + /** Number of Audio Input Control Service instances */ + uint8_t aics_cnt; + /** Array of pointers to Audio Input Control Service instances */ + struct bt_aics **aics; +}; + +/** + * @brief Get Volume Control Service included services. + * + * Returns a pointer to a struct that contains information about the + * Volume Control Service included service instances, such as pointers to the + * Volume Offset Control Service (Volume Offset Control Service) or + * Audio Input Control Service (AICS) instances. + * + * @param[out] included Pointer to store the result in. + * + * @return 0 if success, errno on failure. + */ +int bt_vcp_vol_rend_included_get_safe(struct bt_vcp_included *included); + +/** + * @brief Register the Volume Control Service. + * + * This will register and enable the service and make it discoverable by + * clients. + * + * @param param Volume Control Service register parameters. + * + * @return 0 if success, errno on failure. + */ +int bt_vcp_vol_rend_register_safe(struct bt_vcp_vol_rend_register_param *param); + +/** + * @brief Struct to hold the Volume Renderer callbacks + * + * These can be registered for usage with bt_vcp_vol_rend_register(). + */ +struct bt_vcp_vol_rend_cb { + /** + * @brief Callback function for Volume Control Service volume state. + * + * Called when the value is locally read with + * bt_vcp_vol_rend_get_state(), or if the state is changed by either + * the Volume Renderer or a remote Volume Controller. + * + * @param conn Pointer to the connection to a remote device if + * the change was caused by it, otherwise NULL. + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * @param volume The volume of the Volume Control Service server. + * @param mute The mute setting of the Volume Control Service server. + */ + void (*state)(struct bt_conn *conn, int err, uint8_t volume, uint8_t mute); + + /** + * @brief Callback function for Volume Control Service flags. + * + * Called when the value is locally read as the server. + * Called when the value is remotely read as the client. + * Called if the value is changed by either the server or client. + * + * @param conn Pointer to the connection to a remote device if + * the change was caused by it, otherwise NULL. + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * @param flags The flags of the Volume Control Service server. + */ + void (*flags)(struct bt_conn *conn, int err, uint8_t flags); +}; + +/** + * @brief Set the Volume Control Service volume step size. + * + * Set the value that the volume changes, when changed relatively with e.g. + * @ref bt_vcp_vol_rend_vol_down or @ref bt_vcp_vol_rend_vol_up. + * + * This can only be done as the server. + * + * @param volume_step The volume step size (1-255). + * + * @return 0 if success, errno on failure. + */ +int bt_vcp_vol_rend_set_step_safe(uint8_t volume_step); + +/** + * @brief Get the Volume Control Service volume state. + * + * @return 0 if success, errno on failure. + */ +int bt_vcp_vol_rend_get_state_safe(void); + +/** + * @brief Get the Volume Control Service flags. + * + * @return 0 if success, errno on failure. + */ +int bt_vcp_vol_rend_get_flags_safe(void); + +/** + * @brief Turn the volume down by one step on the server. + * + * @return 0 if success, errno on failure. + */ +int bt_vcp_vol_rend_vol_down_safe(void); + +/** + * @brief Turn the volume up by one step on the server. + * + * @return 0 if success, errno on failure. + */ +int bt_vcp_vol_rend_vol_up_safe(void); + +/** + * @brief Turn the volume down and unmute the server. + * + * @return 0 if success, errno on failure. + */ +int bt_vcp_vol_rend_unmute_vol_down_safe(void); + +/** + * @brief Turn the volume up and unmute the server. + * + * @return 0 if success, errno on failure. + */ +int bt_vcp_vol_rend_unmute_vol_up_safe(void); + +/** + * @brief Set the volume on the server + * + * @param volume The absolute volume to set. + * + * @return 0 if success, errno on failure. + */ +int bt_vcp_vol_rend_set_vol_safe(uint8_t volume); + +/** + * @brief Unmute the server. + * + * @return 0 if success, errno on failure. + */ +int bt_vcp_vol_rend_unmute_safe(void); + +/** + * @brief Mute the server. + * + * @return 0 if success, errno on failure. + */ +int bt_vcp_vol_rend_mute_safe(void); + +/** + * @brief Struct to hold the Volume Controller callbacks + * + * These can be registered for usage with bt_vcp_vol_ctlr_cb_register(). + */ +struct bt_vcp_vol_ctlr_cb { + /** + * @brief Callback function for Volume Control Profile volume state. + * + * Called when the value is remotely read as the Volume Controller. + * Called if the value is changed by either the Volume Renderer or + * Volume Controller, and notified to the to Volume Controller. + * + * @param vol_ctlr Volume Controller instance pointer. + * @param err Error value. 0 on success, GATT error on positive + * value or errno on negative value. + * @param volume The volume of the Volume Renderer. + * @param mute The mute setting of the Volume Renderer. + */ + void (*state)(struct bt_vcp_vol_ctlr *vol_ctlr, int err, uint8_t volume, + uint8_t mute); + + /** + * @brief Callback function for Volume Control Profile volume flags. + * + * Called when the value is remotely read as the Volume Controller. + * Called if the value is changed by the Volume Renderer. + * + * A non-zero value indicates the volume has been changed on the + * Volume Renderer since it was booted. + * + * @param vol_ctlr Volume Controller instance pointer. + * @param err Error value. 0 on success, GATT error on positive + * value or errno on negative value. + * @param flags The flags of the Volume Renderer. + */ + + void (*flags)(struct bt_vcp_vol_ctlr *vol_ctlr, int err, uint8_t flags); + + /** + * @brief Callback function for bt_vcp_vol_ctlr_discover(). + * + * This callback is called once the discovery procedure is completed. + * + * @param vol_ctlr Volume Controller instance pointer. + * @param err Error value. 0 on success, GATT error on positive + * value or errno on negative value. + * @param vocs_count Number of Volume Offset Control Service instances + * on the remote Volume Renderer. + * @param aics_count Number of Audio Input Control Service instances + * the remote Volume Renderer. + */ + void (*discover)(struct bt_vcp_vol_ctlr *vol_ctlr, int err, uint8_t vocs_count, + uint8_t aics_count); + + /** + * @brief Callback function for bt_vcp_vol_ctlr_vol_down(). + * + * Called when the volume down procedure is completed. + * + * @param vol_ctlr Volume Controller instance pointer. + * @param err Error value. 0 on success, GATT error on positive + * value or errno on negative value. + */ + void (*vol_down)(struct bt_vcp_vol_ctlr *vol_ctlr, int err); + + /** + * @brief Callback function for bt_vcp_vol_ctlr_vol_up(). + * + * Called when the volume up procedure is completed. + * + * @param vol_ctlr Volume Controller instance pointer. + * @param err Error value. 0 on success, GATT error on positive + * value or errno on negative value. + */ + void (*vol_up)(struct bt_vcp_vol_ctlr *vol_ctlr, int err); + + /** + * @brief Callback function for bt_vcp_vol_ctlr_mute(). + * + * Called when the mute procedure is completed. + * + * @param vol_ctlr Volume Controller instance pointer. + * @param err Error value. 0 on success, GATT error on positive + * value or errno on negative value. + */ + void (*mute)(struct bt_vcp_vol_ctlr *vol_ctlr, int err); + + /** + * @brief Callback function for bt_vcp_vol_ctlr_unmute(). + * + * Called when the unmute procedure is completed. + * + * @param vol_ctlr Volume Controller instance pointer. + * @param err Error value. 0 on success, GATT error on positive + * value or errno on negative value. + */ + void (*unmute)(struct bt_vcp_vol_ctlr *vol_ctlr, int err); + + /** + * @brief Callback function for bt_vcp_vol_ctlr_vol_down_unmute(). + * + * Called when the volume down and unmute procedure is completed. + * + * @param vol_ctlr Volume Controller instance pointer. + * @param err Error value. 0 on success, GATT error on positive + * value or errno on negative value. + */ + void (*vol_down_unmute)(struct bt_vcp_vol_ctlr *vol_ctlr, int err); + + /** + * @brief Callback function for bt_vcp_vol_ctlr_vol_up_unmute(). + * + * Called when the volume up and unmute procedure is completed. + * + * @param vol_ctlr Volume Controller instance pointer. + * @param err Error value. 0 on success, GATT error on positive + * value or errno on negative value. + */ + void (*vol_up_unmute)(struct bt_vcp_vol_ctlr *vol_ctlr, int err); + + /** + * @brief Callback function for bt_vcp_vol_ctlr_vol_set(). + * + * Called when the set absolute volume procedure is completed. + * + * @param vol_ctlr Volume Controller instance pointer. + * @param err Error value. 0 on success, GATT error on positive + * value or errno on negative value. + */ + void (*vol_set)(struct bt_vcp_vol_ctlr *vol_ctlr, int err); + + /** Volume Offset Control Service callbacks */ + struct bt_vocs_cb vocs_cb; + + /** Audio Input Control Service callbacks */ + struct bt_aics_cb aics_cb; + + /** @cond INTERNAL_HIDDEN */ + /** Internally used field for list handling */ + sys_snode_t _node; + /** @endcond */ +}; + +/** + * @brief Registers the callbacks used by the Volume Controller. + * + * @param cb The callback structure. + * + * @retval 0 on success + * @retval -EINVAL if @p cb is NULL + * @retval -EALREADY if @p cb was already registered + */ +int bt_vcp_vol_ctlr_cb_register_safe(struct bt_vcp_vol_ctlr_cb *cb); + +/** + * @brief Unregisters the callbacks used by the Volume Controller. + * + * @param cb The callback structure. + * + * @retval 0 on success + * @retval -EINVAL if @p cb is NULL + * @retval -EALREADY if @p cb was not registered + */ +int bt_vcp_vol_ctlr_cb_unregister_safe(struct bt_vcp_vol_ctlr_cb *cb); + +/** + * @brief Discover Volume Control Service and included services. + * + * This will start a GATT discovery and setup handles and subscriptions. + * This shall be called once before any other actions can be + * executed for the peer device, and the + * @ref bt_vcp_vol_ctlr_cb.discover callback will notify when it is possible to + * start remote operations. + * + * This shall only be done as the client, + * + * @param conn The connection to discover Volume Control Service for. + * @param[out] vol_ctlr Valid remote instance object on success. + * + * @return 0 if success, errno on failure. + */ +int bt_vcp_vol_ctlr_discover(struct bt_conn *conn, + struct bt_vcp_vol_ctlr **vol_ctlr); +int bt_vcp_vol_ctlr_discover_safe(struct bt_conn *conn, + struct bt_vcp_vol_ctlr **vol_ctlr); + +/** + * @brief Get the volume controller from a connection pointer + * + * Get the Volume Control Profile Volume Controller pointer from a connection pointer. + * Only volume controllers that have been initiated via bt_vcp_vol_ctlr_discover() can be + * retrieved. + * + * @param conn Connection pointer. + * + * @retval Pointer to a Volume Control Profile Volume Controller instance + * @retval NULL if @p conn is NULL or if the connection has not done discovery yet + */ +struct bt_vcp_vol_ctlr *bt_vcp_vol_ctlr_get_by_conn(const struct bt_conn *conn); + +/** + * @brief Get the connection pointer of a client instance + * + * Get the Bluetooth connection pointer of a Volume Control Service + * client instance. + * + * @param vol_ctlr Volume Controller instance pointer. + * @param[out] conn Connection pointer. + * + * @return 0 if success, errno on failure. + */ +int bt_vcp_vol_ctlr_conn_get_safe(const struct bt_vcp_vol_ctlr *vol_ctlr, + struct bt_conn **conn); + +/** + * @brief Get Volume Control Service included services. + * + * Returns a pointer to a struct that contains information about the + * Volume Control Service included service instances, such as pointers to the + * Volume Offset Control Service (Volume Offset Control Service) or + * Audio Input Control Service (AICS) instances. + * + * Requires that @kconfig{CONFIG_BT_VCP_VOL_CTLR_VOCS} or @kconfig{CONFIG_BT_VCP_VOL_CTLR_AICS} is + * enabled. + * + * @param vol_ctlr Volume Controller instance pointer. + * @param[out] included Pointer to store the result in. + * + * @return 0 if success, errno on failure. + */ +int bt_vcp_vol_ctlr_included_get_safe(struct bt_vcp_vol_ctlr *vol_ctlr, + struct bt_vcp_included *included); + +/** + * @brief Read the volume state of a remote Volume Renderer. + * + * @param vol_ctlr Volume Controller instance pointer. + * + * @return 0 if success, errno on failure. + */ +int bt_vcp_vol_ctlr_read_state_safe(struct bt_vcp_vol_ctlr *vol_ctlr); + +/** + * @brief Read the volume flags of a remote Volume Renderer. + * + * @param vol_ctlr Volume Controller instance pointer. + * + * @return 0 if success, errno on failure. + */ +int bt_vcp_vol_ctlr_read_flags_safe(struct bt_vcp_vol_ctlr *vol_ctlr); + +/** + * @brief Turn the volume down one step on a remote Volume Renderer + * + * @param vol_ctlr Volume Controller instance pointer. + * + * @return 0 if success, errno on failure. + */ +int bt_vcp_vol_ctlr_vol_down_safe(struct bt_vcp_vol_ctlr *vol_ctlr); + +/** + * @brief Turn the volume up one step on a remote Volume Renderer + * + * @param vol_ctlr Volume Controller instance pointer. + * + * @return 0 if success, errno on failure. + */ +int bt_vcp_vol_ctlr_vol_up_safe(struct bt_vcp_vol_ctlr *vol_ctlr); + +/** + * @brief Turn the volume down one step and unmute on a remote Volume Renderer + * + * @param vol_ctlr Volume Controller instance pointer. + * + * @return 0 if success, errno on failure. + */ +int bt_vcp_vol_ctlr_unmute_vol_down_safe(struct bt_vcp_vol_ctlr *vol_ctlr); + +/** + * @brief Turn the volume up one step and unmute on a remote Volume Renderer + * + * @param vol_ctlr Volume Controller instance pointer. + * + * @return 0 if success, errno on failure. + */ +int bt_vcp_vol_ctlr_unmute_vol_up_safe(struct bt_vcp_vol_ctlr *vol_ctlr); + +/** + * @brief Set the absolute volume on a remote Volume Renderer + * + * @param vol_ctlr Volume Controller instance pointer. + * @param volume The absolute volume to set. + * + * @return 0 if success, errno on failure. + */ +int bt_vcp_vol_ctlr_set_vol_safe(struct bt_vcp_vol_ctlr *vol_ctlr, uint8_t volume); + +/** + * @brief Unmute a remote Volume Renderer. + * + * @param vol_ctlr Volume Controller instance pointer. + * + * @return 0 if success, errno on failure. + */ +int bt_vcp_vol_ctlr_unmute_safe(struct bt_vcp_vol_ctlr *vol_ctlr); + +/** + * @brief Mute a remote Volume Renderer. + * + * @param vol_ctlr Volume Controller instance pointer. + * + * @return 0 if success, errno on failure. + */ +int bt_vcp_vol_ctlr_mute_safe(struct bt_vcp_vol_ctlr *vol_ctlr); + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_SERVICES_VCP_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/vocs.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/vocs.h new file mode 100644 index 0000000000..ff9afcb290 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/audio/vocs.h @@ -0,0 +1,345 @@ +/** + * @file + * @brief Bluetooth Volume Offset Control Service (VOCS) APIs. + */ + +/* + * SPDX-FileCopyrightText: 2020-2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_SERVICES_VOCS_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_SERVICES_VOCS_H_ + +/** + * @brief Volume Offset Control Service (VOCS) + * + * @defgroup bt_vocs Volume Offset Control Service (VOCS) + * + * @since 2.6 + * @version 0.8.0 + * + * @ingroup bluetooth + * @{ + * + * The Volume Offset Control Service is a secondary service, and as such should not be used own its + * own, but rather in the context of another (primary) service. + * + * This API implements both the server and client functionality. + * Note that the API abstracts away the change counter in the volume offset control state and will + * automatically handle any changes to that. If out of date, the client implementation will + * autonomously read the change counter value when executing a write request. + */ + +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Volume Offset Control Service Error codes + * @{ + */ +/** + * The Change_Counter operand value does not match the Change_Counter field value of the Volume + * Offset State characteristic. + */ +#define BT_VOCS_ERR_INVALID_COUNTER 0x80 +/** An invalid opcode has been used in a control point procedure. */ +#define BT_VOCS_ERR_OP_NOT_SUPPORTED 0x81 +/** An operand value used in a control point procedure is outside the permissible range. */ +#define BT_VOCS_ERR_OUT_OF_RANGE 0x82 +/** @} */ + +/** + * @name Volume Offset Control Service offset limits + * @{ + */ +/** Minimum offset value */ +#define BT_VOCS_MIN_OFFSET -255 +/** Maximum offset value */ +#define BT_VOCS_MAX_OFFSET 255 +/** @} */ + +/** @brief Opaque Volume Offset Control Service instance. */ +struct bt_vocs; + +/** @brief Structure for registering a Volume Offset Control Service instance. */ +struct bt_vocs_register_param { + /** Audio Location bitmask */ + uint32_t location; + + /** Boolean to set whether the location is writable by clients */ + bool location_writable; + + /** Initial volume offset (-255 to 255) */ + int16_t offset; + + /** Initial audio output description */ + char *output_desc; + + /** Boolean to set whether the description is writable by clients */ + bool desc_writable; + + /** Pointer to the callback structure. */ + struct bt_vocs_cb *cb; +}; + +/** @brief Structure for discovering a Volume Offset Control Service instance. */ +struct bt_vocs_discover_param { + /** + * @brief The start handle of the discovering. + * + * Typically the @p start_handle of a @ref bt_gatt_include. + */ + uint16_t start_handle; + /** + * @brief The end handle of the discovering. + * + * Typically the @p end_handle of a @ref bt_gatt_include. + */ + uint16_t end_handle; +}; + +/** + * @brief Get a free service instance of Volume Offset Control Service from the pool. + * + * @return Volume Offset Control Service instance in case of success or NULL in case of error. + */ +struct bt_vocs *bt_vocs_free_instance_get_safe(void); + +/** + * @brief Get the service declaration attribute. + * + * The first service attribute returned can be included in any other GATT service. + * + * @param vocs Volume Offset Control Service instance. + * + * @return Pointer to the attributes of the service. + */ +void *bt_vocs_svc_decl_get_safe(struct bt_vocs *vocs); + +/** + * @brief Get the connection pointer of a client instance + * + * Get the Bluetooth connection pointer of a Audio Input Control Service + * client instance. + * + * @param vocs Audio Input Control Service client instance pointer. + * @param conn Connection pointer. + * + * @return 0 if success, errno on failure. + */ +int bt_vocs_client_conn_get_safe(const struct bt_vocs *vocs, struct bt_conn **conn); + +/** + * @brief Register the Volume Offset Control Service instance. + * + * @param vocs Volume Offset Control Service instance. + * @param param Volume Offset Control Service register parameters. + * + * @return 0 if success, errno on failure. + */ +int bt_vocs_register_safe(struct bt_vocs *vocs, + const struct bt_vocs_register_param *param); + +/** + * @brief Callback function for the offset state. + * + * Called when the value is read, or if the value is changed by either the server or client. + * + * @param inst The instance pointer. + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * For notifications, this will always be 0. + * @param offset The offset value. + */ +typedef void (*bt_vocs_state_cb)(struct bt_vocs *inst, int err, int16_t offset); + +/** + * @brief Callback function for setting offset. + * + * @param inst The instance pointer. + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + */ +typedef void (*bt_vocs_set_offset_cb)(struct bt_vocs *inst, int err); + +/** + * @brief Callback function for the location. + * + * Called when the value is read, or if the value is changed by either the server or client. + * + * @param inst The instance pointer. + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * For notifications, this will always be 0. + * @param location The location value. + */ +typedef void (*bt_vocs_location_cb)(struct bt_vocs *inst, int err, + uint32_t location); + +/** + * @brief Callback function for the description. + * + * Called when the value is read, or if the value is changed by either the server or client. + * + * @param inst The instance pointer. + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * For notifications, this will always be 0. + * @param description The description as an UTF-8 encoded string. + */ +typedef void (*bt_vocs_description_cb)(struct bt_vocs *inst, int err, + char *description); + +/** + * @brief Callback function for bt_vocs_discover. + * + * This callback should be overwritten by the primary service that + * includes the Volume Control Offset Service client, and should thus not be + * set by the application. + * + * @param inst The instance pointer. + * @param err Error value. 0 on success, GATT error on positive value + * or errno on negative value. + * For notifications, this will always be 0. + */ +typedef void (*bt_vocs_discover_cb)(struct bt_vocs *inst, int err); + +/** + * @brief Struct to hold the Volume Offset Control Service callbacks + * + * These can be registered for usage with bt_vocs_client_cb_register() or bt_vocs_register() + * depending on the role. + */ +struct bt_vocs_cb { + /** The offset state has changed */ + bt_vocs_state_cb state; + /** The location has changed */ + bt_vocs_location_cb location; + /** The Description has changed */ + bt_vocs_description_cb description; + + /** + * The discovery procedure has completed + * + * Only settable for the client and requires enabling@kconfig{CONFIG_BT_VOCS_CLIENT}. + */ + bt_vocs_discover_cb discover; + /** + * The set offset procedure has completed + * + * Only settable for the client and requires enabling@kconfig{CONFIG_BT_VOCS_CLIENT}. + */ + bt_vocs_set_offset_cb set_offset; +}; + +/** + * @brief Read the Volume Offset Control Service offset state. + * + * The value is returned in the bt_vocs_cb.state callback. + * + * @param inst Pointer to the Volume Offset Control Service instance. + * + * @return 0 on success, GATT error value on fail. + */ +int bt_vocs_state_get_safe(struct bt_vocs *inst); + +/** + * @brief Set the Volume Offset Control Service offset state. + * + * @param inst Pointer to the Volume Offset Control Service instance. + * @param offset The offset to set (-255 to 255). + * + * @return 0 on success, GATT error value on fail. + */ +int bt_vocs_state_set_safe(struct bt_vocs *inst, int16_t offset); + +/** + * @brief Read the Volume Offset Control Service location. + * + * The value is returned in the bt_vocs_cb.location callback. + * + * @param inst Pointer to the Volume Offset Control Service instance. + * + * @return 0 on success, GATT error value on fail. + */ +int bt_vocs_location_get_safe(struct bt_vocs *inst); + +/** + * @brief Set the Volume Offset Control Service location. + * + * @param inst Pointer to the Volume Offset Control Service instance. + * @param location The location to set. + * + * @return 0 on success, GATT error value on fail. + */ +int bt_vocs_location_set_safe(struct bt_vocs *inst, uint32_t location); + +/** + * @brief Read the Volume Offset Control Service output description. + * + * The value is returned in the bt_vocs_cb.description callback. + * + * @param inst Pointer to the Volume Offset Control Service instance. + * + * @return 0 on success, GATT error value on fail. + */ +int bt_vocs_description_get_safe(struct bt_vocs *inst); + +/** + * @brief Set the Volume Offset Control Service description. + * + * @param inst Pointer to the Volume Offset Control Service instance. + * @param description The UTF-8 encoded string description to set. + * + * @return 0 on success, GATT error value on fail. + */ +int bt_vocs_description_set_safe(struct bt_vocs *inst, const char *description); + +/** + * @brief Registers the callbacks for the Volume Offset Control Service client. + * + * @param inst Pointer to the Volume Offset Control Service client instance. + * @param cb Pointer to the callback structure. + */ +void bt_vocs_client_cb_register_safe(struct bt_vocs *inst, struct bt_vocs_cb *cb); + +/** + * @brief Returns a pointer to a Volume Offset Control Service client instance. + * + * @return Pointer to the instance, or NULL if no free instances are left. + */ +struct bt_vocs *bt_vocs_client_free_instance_get_safe(void); + +/** + * @brief Discover a Volume Offset Control Service. + * + * Attempts to discover a Volume Offset Control Service on a server given the @p param. + * + * @param conn Connection to the peer with the Volume Offset Control Service. + * @param inst Pointer to the Volume Offset Control Service client instance. + * @param param Pointer to the parameters. + * + * @return 0 on success, errno on fail. + */ +int bt_vocs_discover(struct bt_conn *conn, struct bt_vocs *inst, + const struct bt_vocs_discover_param *param); +int bt_vocs_discover_safe(struct bt_conn *conn, struct bt_vocs *inst, + const struct bt_vocs_discover_param *param); + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_SERVICES_VOCS_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/bluetooth.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/bluetooth.h new file mode 100644 index 0000000000..8a73206c08 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/bluetooth.h @@ -0,0 +1,635 @@ +/** + * @file + * @brief Bluetooth subsystem core APIs. + */ + +/* + * SPDX-FileCopyrightText: 2017 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2015-2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_BLUETOOTH_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_BLUETOOTH_H_ + +/** + * @brief Bluetooth APIs + * + * @details The Bluetooth Subsystem Core APIs provide essential functionalities + * to use and manage Bluetooth based communication. These APIs include + * APIs for Bluetooth stack initialization, device discovery, + * connection management, data transmission, profiles and services. + * These APIs support both classic Bluetooth and Bluetooth Low Energy + * (LE) operations. + * + * @defgroup bluetooth Bluetooth APIs + * @ingroup connectivity + * @{ + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Generic Access Profile (GAP) + * + * @details The Generic Access Profile (GAP) defines fundamental Bluetooth + * operations, including device discovery, pairing, and connection + * management. Zephyr's GAP implementation supports both classic + * Bluetooth and Bluetooth Low Energy (LE) functionalities, enabling + * roles such as Broadcaster, Observer, Peripheral, and Central. These + * roles define the device's behavior in advertising, scanning, and + * establishing connections within Bluetooth networks. + * + * @defgroup bt_gap Generic Access Profile (GAP) + * @since 1.0 + * @version 1.0.0 + * @ingroup bluetooth + * @{ + */ + +/** Opaque type representing an advertiser. */ +struct bt_le_ext_adv; + +/** Opaque type representing an periodic advertising sync. */ +struct bt_le_per_adv_sync; + +/* Don't require everyone to include conn.h */ +struct bt_conn; + +/* Don't require everyone to include iso.h */ +struct bt_iso_biginfo; + +/** + * @brief Bluetooth data. + * + * @details Description of different AD Types that can be encoded into advertising data. Used to + * form arrays that are passed to the @ref bt_le_adv_start function. The @ref BT_DATA define can + * be used as a helpter to declare the elements of an @ref bt_data array. + */ +struct bt_data { + /** Type of scan response data or advertisement data. */ + uint8_t type; + /** Length of scan response data or advertisement data. */ + uint8_t data_len; + /** Pointer to Scan response or advertisement data. */ + const uint8_t *data; +}; + +/** + * @brief Helper to declare elements of bt_data arrays + * + * This macro is mainly for creating an array of struct bt_data + * elements which is then passed to e.g. @ref bt_le_adv_start function. + * + * @param _type Type of advertising data field + * @param _data Pointer to the data field payload + * @param _data_len Number of octets behind the _data pointer + */ +#define BT_DATA(_type, _data, _data_len) \ + { \ + .type = (_type), \ + .data_len = (_data_len), \ + .data = (const uint8_t *)(_data), \ + } + +/** + * @brief Parameters for starting an extended advertising session. + * + * @details This struct provides the parameters to control the behavior of an extended advertising + * session, including the timeout and the number of advertising events to send. The timeout is + * specified in units of 10 ms, and the number of events determines how many times the advertising + * will be sent before stopping. If either the timeout or number of events is reached, the + * advertising session will be stopped, and the application will be notified via the advertiser sent + * callback. If both parameters are provided, the advertising session will stop when either limit is + * reached. + * + * @note Used in @ref bt_le_ext_adv_start function. + */ +struct bt_le_ext_adv_start_param { + /** + * @brief Maximum advertising set duration (N * 10 ms) + * + * The advertising set can be automatically disabled after a + * certain amount of time has passed since it first appeared on + * air. + * + * Set to zero for no limit. Set in units of 10 ms. + * + * When the advertising set is automatically disabled because of + * this limit, @ref bt_le_ext_adv_cb.sent will be called. + * + * When using high duty cycle directed connectable advertising + * then this parameters must be set to a non-zero value less + * than or equal to the maximum of + * @ref BT_GAP_ADV_HIGH_DUTY_CYCLE_MAX_TIMEOUT. + * + * If privacy @kconfig{CONFIG_BT_PRIVACY} is enabled then the + * timeout must be less than @kconfig{CONFIG_BT_RPA_TIMEOUT}. + * + * For background information, see parameter "Duration" in + * Bluetooth Core Specification Version 6.0 Vol. 4 Part E, + * Section 7.8.56. + */ + uint16_t timeout; + + /** + * @brief Maximum number of extended advertising events to be + * sent + * + * The advertiser can be automatically disabled once the whole + * advertisement (i.e. extended advertising event) has been sent + * a certain number of times. The number of advertising PDUs + * sent may be higher and is not relevant. + * + * Set to zero for no limit. + * + * When the advertising set is automatically disabled because of + * this limit, @ref bt_le_ext_adv_cb.sent will be called. + * + * For background information, see parameter + * "Max_Extended_Advertising_Events" in Bluetooth Core + * Specification Version 6.0 Vol. 4 Part E, Section 7.8.56. + */ + uint8_t num_events; +}; + +/** + * @brief Start advertising with the given advertising set + * + * If the advertiser is limited by either the @p param.timeout or @p param.num_events, + * the application will be notified by the @ref bt_le_ext_adv_cb.sent callback once + * the limit is reached. + * If the advertiser is limited by both the timeout and the number of + * advertising events, then the limit that is reached first will stop the + * advertiser. + * + * @note The advertising set @p adv can be created with @ref bt_le_ext_adv_create. + * + * @param adv Advertising set object. + * @param param Advertise start parameters. + */ +int bt_le_ext_adv_start(struct bt_le_ext_adv *adv, + const struct bt_le_ext_adv_start_param *param); + +/** Advertising states. */ +enum bt_le_ext_adv_state { + /** The advertising set has been created but not enabled. */ + BT_LE_EXT_ADV_STATE_DISABLED, + + /** The advertising set is enabled. */ + BT_LE_EXT_ADV_STATE_ENABLED, +}; + +/** Periodic Advertising states. */ +enum bt_le_per_adv_state { + /** Not configured for periodic advertising. */ + BT_LE_PER_ADV_STATE_NONE, + + /** The advertising set has been configured for periodic advertising, but is not enabled. */ + BT_LE_PER_ADV_STATE_DISABLED, + + /** Periodic advertising is enabled. */ + BT_LE_PER_ADV_STATE_ENABLED, +}; + +/** @brief Advertising set info structure. */ +struct bt_le_ext_adv_info { + /** Advertising Set ID */ + uint8_t sid; + + /** Current local advertising address used. */ + const bt_addr_le_t *addr; + + /** Extended advertising state. */ + enum bt_le_ext_adv_state ext_adv_state; + + /** Periodic advertising state. */ + enum bt_le_per_adv_state per_adv_state; +}; + +/** + * @brief Get advertising set info + * + * @param adv Advertising set object + * @param info Advertising set info object. The values in this object are only valid on success. + * + * @retval 0 Success. + * @retval -EINVAL @p adv is not valid advertising set or @p info is NULL. + */ +int bt_le_ext_adv_get_info(const struct bt_le_ext_adv *adv, + struct bt_le_ext_adv_info *info); + +struct bt_le_per_adv_sync_synced_info { + /** Advertiser LE address and type. */ + const bt_addr_le_t *addr; + + /** Advertising Set Identifier, valid range @ref BT_GAP_SID_MIN to @ref BT_GAP_SID_MAX. */ + uint8_t sid; + + /** Periodic advertising interval (N * 1.25 ms) */ + uint16_t interval; + + /** Advertiser PHY (see @ref bt_gap_le_phy). */ + uint8_t phy; + + /** + * @brief Peer that transferred the periodic advertising sync + * + * Will always be NULL when the sync is locally created. + * + */ + struct bt_conn *conn; +}; + +/** + * @brief Information about the termination of a periodic advertising sync. + * + * @details This struct provides information about the termination of a periodic advertising sync. + * It includes the advertiser’s address and SID, along with the reason for the sync termination. + * This information is provided in the callback when the sync is terminated, either due to a + * local or remote request, or due to missing data (e.g., out of range or lost sync). + * + * @note Used in @ref bt_le_per_adv_sync_cb structure. + */ +struct bt_le_per_adv_sync_term_info { + /** Advertiser LE address and type. */ + const bt_addr_le_t *addr; + + /** Advertising Set Identifier, valid range @ref BT_GAP_SID_MIN to @ref BT_GAP_SID_MAX. */ + uint8_t sid; + + /** Cause of periodic advertising termination (see the BT_HCI_ERR_* values). */ + uint8_t reason; +}; + +/** + * @brief Information about a received periodic advertising report. + * + * @details This struct holds information about a periodic advertising event that has been received. + * It contains details such as the advertiser’s address, SID, transmit power, RSSI, CTE type, and + * additional information depending on the configuration (e.g., event counter and subevent in case + * of a subevent indication). This information is provided in the callback when periodic advertising + * data is received. + * + * @note Used in @ref bt_le_per_adv_sync_cb structure. + */ +struct bt_le_per_adv_sync_recv_info { + /** Advertiser LE address and type. */ + const bt_addr_le_t *addr; + + /** Advertising Set Identifier, valid range @ref BT_GAP_SID_MIN to @ref BT_GAP_SID_MAX. */ + uint8_t sid; + + /** The TX power of the advertisement. */ + int8_t tx_power; + + /** The RSSI of the advertisement excluding any CTE. */ + int8_t rssi; +}; + +/** + * @brief Callback struct for periodic advertising sync events. + * + * @details This struct defines the callback functions that are invoked for various periodic + * advertising sync events. These include when the sync is successfully established, terminated, + * when data is received, state changes, BIG info reports, and IQ samples from the periodic + * advertising. + * + * @note Used in @ref bt_le_per_adv_sync_cb_register function. + */ + +struct bt_le_per_adv_sync_cb { + /** + * @brief The periodic advertising has been successfully synced. + * + * This callback notifies the application that the periodic advertising + * set has been successfully synced, and will now start to + * receive periodic advertising reports. + * + * @param sync The periodic advertising sync object. + * @param info Information about the sync event. + */ + void (*synced)(struct bt_le_per_adv_sync *sync, + struct bt_le_per_adv_sync_synced_info *info); + + /** + * @brief The periodic advertising sync has been terminated. + * + * This callback notifies the application that the periodic advertising + * sync has been terminated, either by local request, remote request or + * because due to missing data, e.g. by being out of range or sync. + * + * @param sync The periodic advertising sync object. + * @param info Information about the termination event. + */ + void (*term)(struct bt_le_per_adv_sync *sync, + const struct bt_le_per_adv_sync_term_info *info); + + /** + * @brief Periodic advertising data received. + * + * This callback notifies the application of an periodic advertising + * report. + * + * @param sync The advertising set object. + * @param info Information about the periodic advertising event. + * @param buf Buffer containing the periodic advertising data. + * NULL if the controller failed to receive a subevent + * indication. Only happens if + * @kconfig{CONFIG_BT_PER_ADV_SYNC_RSP} is enabled. + */ + void (*recv)(struct bt_le_per_adv_sync *sync, + const struct bt_le_per_adv_sync_recv_info *info, + struct net_buf_simple *buf); + + /** + * @brief BIGInfo advertising report received. + * + * This callback notifies the application of a BIGInfo advertising report. + * This is received if the advertiser is broadcasting isochronous streams in a BIG. + * See iso.h for more information. + * + * @param sync The advertising set object. + * @param biginfo The BIGInfo report. + */ + void (*biginfo)(struct bt_le_per_adv_sync *sync, const struct bt_iso_biginfo *biginfo); + + sys_snode_t node; +}; + +/** @brief Periodic advertising set info structure. */ +struct bt_le_per_adv_sync_info { + /** Periodic Advertiser Address */ + bt_addr_le_t addr; + + /** Advertising Set Identifier, valid range @ref BT_GAP_SID_MIN to @ref BT_GAP_SID_MAX. */ + uint8_t sid; + + /** Periodic advertising interval (N * 1.25 ms) */ + uint16_t interval; + + /** Advertiser PHY (see @ref bt_gap_le_phy). */ + uint8_t phy; +}; + +/** + * @brief Get periodic adv sync information. + * + * @param per_adv_sync Periodic advertising sync object. + * @param info Periodic advertising sync info object + * + * @return Zero on success or (negative) error code on failure. + */ +int bt_le_per_adv_sync_get_info(struct bt_le_per_adv_sync *per_adv_sync, + struct bt_le_per_adv_sync_info *info); + +/** + * @brief Look up an existing periodic advertising sync object by advertiser address. + * + * @param adv_addr Advertiser address. + * @param sid The periodic advertising set ID. + * + * @return Periodic advertising sync object or NULL if not found. + */ +struct bt_le_per_adv_sync *bt_le_per_adv_sync_lookup_addr(const bt_addr_le_t *adv_addr, + uint8_t sid); + +/** + * @brief Register periodic advertising sync callbacks. + * + * Adds the callback structure to the list of callback structures for periodic + * advertising syncs. + * + * This callback will be called for all periodic advertising sync activity, + * such as synced, terminated and when data is received. + * + * @param cb Callback struct. Must point to memory that remains valid. + * + * @retval 0 Success. + * @retval -EEXIST if @p cb was already registered. + */ +int bt_le_per_adv_sync_cb_register(struct bt_le_per_adv_sync_cb *cb); + +/** LE scan parameters */ +struct bt_le_scan_param { + /** Scan type. @ref BT_LE_SCAN_TYPE_ACTIVE or @ref BT_LE_SCAN_TYPE_PASSIVE. */ + uint8_t type; + + /** Bit-field of scanning options. */ + uint8_t options; + + /** Scan interval (N * 0.625 ms). + * + * @note When @kconfig{CONFIG_BT_SCAN_AND_INITIATE_IN_PARALLEL} is enabled + * and the application wants to scan and connect in parallel, + * the Bluetooth Controller may require the scan interval used + * for scanning and connection establishment to be equal to + * obtain the best performance. + */ + uint16_t interval; + + /** Scan window (N * 0.625 ms) + * + * @note When @kconfig{CONFIG_BT_SCAN_AND_INITIATE_IN_PARALLEL} is enabled + * and the application wants to scan and connect in parallel, + * the Bluetooth Controller may require the scan window used + * for scanning and connection establishment to be equal to + * obtain the best performance. + */ + uint16_t window; + + /** + * @brief Scan timeout (N * 10 ms) + * + * Application will be notified by the scan timeout callback. + * Set zero to disable timeout. + */ + uint16_t timeout; + + /** + * @brief Scan interval LE Coded PHY (N * 0.625 MS) + * + * Set zero to use same as LE 1M PHY scan interval. + */ + uint16_t interval_coded; + + /** + * @brief Scan window LE Coded PHY (N * 0.625 MS) + * + * Set zero to use same as LE 1M PHY scan window. + */ + uint16_t window_coded; +}; + +/** LE advertisement and scan response packet information */ +struct bt_le_scan_recv_info { + /** + * @brief Advertiser LE address and type. + * + * If advertiser is anonymous then this address will be + * @ref BT_ADDR_LE_ANY. + */ + const bt_addr_le_t *addr; + + /** Advertising Set Identifier, valid range @ref BT_GAP_SID_MIN to @ref BT_GAP_SID_MAX. */ + uint8_t sid; + + /** Strength of advertiser signal. */ + int8_t rssi; + + /** Transmit power of the advertiser. */ + int8_t tx_power; + + /** + * @brief Advertising packet type. + * + * Uses the @ref bt_gap_adv_type value. + * + * May indicate that this is a scan response if the type is + * @ref BT_GAP_ADV_TYPE_SCAN_RSP. + */ + uint8_t adv_type; + + /** + * @brief Advertising packet properties bitfield. + * + * Uses the @ref bt_gap_adv_prop values. + * May indicate that this is a scan response if the value contains the + * @ref BT_GAP_ADV_PROP_SCAN_RESPONSE bit. + * + */ + uint16_t adv_props; + + /** + * @brief Periodic advertising interval (N * 1.25 ms). + * + * If 0 there is no periodic advertising. + */ + uint16_t interval; + + /** Primary advertising channel PHY. */ + uint8_t primary_phy; + + /** Secondary advertising channel PHY. */ + uint8_t secondary_phy; +}; + +/** Listener context for (LE) scanning. */ +struct bt_le_scan_cb { + + /** + * @brief Advertisement packet and scan response received callback. + * + * @param info Advertiser packet and scan response information. + * @param buf Buffer containing advertiser data. + */ + void (*recv)(const struct bt_le_scan_recv_info *info, + struct net_buf_simple *buf); + + sys_snode_t node; +}; + +/** + * @brief Start (LE) scanning + * + * Start LE scanning with given parameters and provide results through + * the specified callback. + * + * @note The LE scanner by default does not use the Identity Address of the + * local device when @kconfig{CONFIG_BT_PRIVACY} is disabled. This is to + * prevent the active scanner from disclosing the identity address information + * when requesting additional information from advertisers. + * In order to enable directed advertiser reports then + * @kconfig{CONFIG_BT_SCAN_WITH_IDENTITY} must be enabled. + * + * @note Setting the `param.timeout` parameter is not supported when + * @kconfig{CONFIG_BT_PRIVACY} is enabled, when the param.type is @ref + * BT_LE_SCAN_TYPE_ACTIVE. Supplying a non-zero timeout will result in an + * -EINVAL error code. + * + * @param param Scan parameters. + * @param cb Callback to notify scan results. May be NULL if callback + * registration through @ref bt_le_scan_cb_register is preferred. + * + * @return Zero on success or error code otherwise, positive in case of + * protocol error or negative (POSIX) in case of stack internal error. + * @retval -EBUSY if the scanner is already being started in a different thread. + */ +int bt_le_scan_start(const struct bt_le_scan_param *param, void *cb); + +/** + * @brief Stop (LE) scanning. + * + * Stops ongoing LE scanning. + * + * @return Zero on success or error code otherwise, positive in case of + * protocol error or negative (POSIX) in case of stack internal error. + */ +int bt_le_scan_stop(void); + +/** + * @brief Register scanner packet callbacks. + * + * Adds the callback structure to the list of callback structures that monitors + * scanner activity. + * + * This callback will be called for all scanner activity. + * + * @param cb Callback struct. Must point to memory that remains valid. + * + * @retval 0 Success. + * @retval -EEXIST if @p cb was already registered. + */ +int bt_le_scan_cb_register(struct bt_le_scan_cb *cb); + +/** + * @brief Unregister scanner packet callbacks. + * + * Remove the callback structure from the list of scanner callbacks. + * + * @param cb Callback struct. Must point to memory that remains valid. + */ +void bt_le_scan_cb_unregister(struct bt_le_scan_cb *cb); + +/** Information about a bond with a remote device. */ +struct bt_bond_info { + /** Address of the remote device. */ + bt_addr_le_t addr; +}; + +/** + * @brief Iterate through all existing bonds. + * + * @param id Local identity handle (typically @ref BT_ID_DEFAULT). Corresponds to the + * identity address used in iteration. + * @param func Function to call for each bond. + * @param user_data Data to pass to the callback function. + */ +void bt_foreach_bond(uint8_t id, void (*func)(const struct bt_bond_info *info, + void *user_data), + void *user_data); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_BLUETOOTH_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/buf.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/buf.h new file mode 100644 index 0000000000..3c96f14884 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/buf.h @@ -0,0 +1,55 @@ +/** @file + * @brief Bluetooth data buffer API + */ + +/* + * SPDX-FileCopyrightText: 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_BUF_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_BUF_H_ + +/** + * @brief Data buffers + * @defgroup bt_buf Data buffers + * @ingroup bluetooth + * @{ + */ + +#include +#include + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Headroom reserved in buffers, primarily for HCI transport encoding purposes */ +#define BT_BUF_RESERVE 1 + +/** Helper to include reserved HCI data in buffer calculations */ +#define BT_BUF_SIZE(size) (BT_BUF_RESERVE + (size)) + +/** Helper to calculate needed buffer size for HCI ACL packets */ +#define BT_BUF_ACL_SIZE(size) BT_BUF_SIZE(BT_HCI_ACL_HDR_SIZE + (size)) + +/** Helper to calculate needed buffer size for HCI ISO packets. */ +#define BT_BUF_ISO_SIZE(size) BT_BUF_SIZE(BT_HCI_ISO_HDR_SIZE + \ + BT_HCI_ISO_SDU_TS_HDR_SIZE + \ + (size)) + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_BUF_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/byteorder.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/byteorder.h new file mode 100644 index 0000000000..cfe7d1a8ac --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/byteorder.h @@ -0,0 +1,189 @@ +/** @file + * @brief Bluetooth byteorder API + */ + +/* + * SPDX-FileCopyrightText: 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_BYTEORDER_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_BYTEORDER_H_ + +/** + * @brief Byteorder + * @defgroup bt_byteorder Byteorder + * @ingroup bluetooth + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief Encode 16-bit value into array values in little-endian format. + * + * Helper macro to encode 16-bit values into comma separated values. + * + * @note @p _v is evaluated 2 times. + * + * @param _v 16-bit integer in host endianness. + * + * @return The comma separated values for the 16-bit value. + */ +#define BT_BYTES_LIST_LE16(_v) \ + (((_v) >> 0) & 0xFFU), \ + (((_v) >> 8) & 0xFFU) \ + +/** @brief Encode 24-bit value into array values in little-endian format. + * + * Helper macro to encode 24-bit values into comma separated values. + * + * @note @p _v is evaluated 3 times. + * + * @param _v 24-bit integer in host endianness. + * + * @return The comma separated values for the 24-bit value. + */ +#define BT_BYTES_LIST_LE24(_v) \ + BT_BYTES_LIST_LE16(_v), \ + (((_v) >> 16) & 0xFFU) \ + +/** @brief Encode 32-bit value into array values in little-endian format. + * + * Helper macro to encode 32-bit values into comma separated values. + * + * @note @p _v is evaluated 4 times. + * + * @param _v 32-bit integer in host endianness. + * + * @return The comma separated values for the 32-bit value. + */ +#define BT_BYTES_LIST_LE32(_v) \ + BT_BYTES_LIST_LE24(_v), \ + (((_v) >> 24) & 0xFFU) \ + +/** @brief Encode 40-bit value into array values in little-endian format. + * + * Helper macro to encode 40-bit values into comma separated values. + * + * @note @p _v is evaluated 5 times. + * + * @param _v 40-bit integer in host endianness. + * + * @return The comma separated values for the 40-bit value. + */ +#define BT_BYTES_LIST_LE40(_v) \ + BT_BYTES_LIST_LE24(_v), \ + BT_BYTES_LIST_LE16((_v) >> 24) \ + +/** @brief Encode 48-bit value into array values in little-endian format. + * + * Helper macro to encode 48-bit values into comma separated values. + * + * @note @p _v is evaluated 6 times. + * + * @param _v 48-bit integer in host endianness. + * + * @return The comma separated values for the 48-bit value. + */ +#define BT_BYTES_LIST_LE48(_v) \ + BT_BYTES_LIST_LE32(_v), \ + BT_BYTES_LIST_LE16((_v) >> 32) \ + +/** @brief Encode 64-bit value into array values in little-endian format. + * + * Helper macro to encode 64-bit values into comma separated values. + * + * @note @p _v is evaluated 8 times. + * + * @param _v 64-bit integer in host endianness. + * + * @return The comma separated values for the 64-bit value. + */ +#define BT_BYTES_LIST_LE64(_v) \ + BT_BYTES_LIST_LE32(_v), \ + BT_BYTES_LIST_LE32((_v) >> 32) \ + +/** @brief Encode 16-bit value into array values in big-endian format. + * + * Helper macro to encode 16-bit values into comma separated values. + * + * @note @p _v is evaluated 2 times. + * + * @param _v 16-bit integer in host endianness. + * + * @return The comma separated values for the 16-bit value. + */ +#define BT_BYTES_LIST_BE16(_v) (((_v) >> 8) & 0xFFU), (((_v) >> 0) & 0xFFU) + +/** @brief Encode 24-bit value into array values in big-endian format. + * + * Helper macro to encode 24-bit values into comma separated values. + * + * @note @p _v is evaluated 3 times. + * + * @param _v 24-bit integer in host endianness. + * + * @return The comma separated values for the 24-bit value. + */ +#define BT_BYTES_LIST_BE24(_v) (((_v) >> 16) & 0xFFU), BT_BYTES_LIST_BE16(_v) + +/** @brief Encode 32-bit value into array values in big-endian format. + * + * Helper macro to encode 32-bit values into comma separated values. + * + * @note @p _v is evaluated 4 times. + * + * @param _v 32-bit integer in host endianness. + * + * @return The comma separated values for the 32-bit value. + */ +#define BT_BYTES_LIST_BE32(_v) (((_v) >> 24) & 0xFFU), BT_BYTES_LIST_BE24(_v) + +/** @brief Encode 40-bit value into array values in big-endian format. + * + * Helper macro to encode 40-bit values into comma separated values. + * + * @note @p _v is evaluated 5 times. + * + * @param _v 40-bit integer in host endianness. + * + * @return The comma separated values for the 40-bit value. + */ +#define BT_BYTES_LIST_BE40(_v) BT_BYTES_LIST_BE16((_v) >> 24), BT_BYTES_LIST_BE24(_v) + +/** @brief Encode 48-bit value into array values in big-endian format. + * + * Helper macro to encode 48-bit values into comma separated values. + * + * @note @p _v is evaluated 6 times. + * + * @param _v 48-bit integer in host endianness. + * + * @return The comma separated values for the 48-bit value. + */ +#define BT_BYTES_LIST_BE48(_v) BT_BYTES_LIST_BE16((_v) >> 32), BT_BYTES_LIST_BE32(_v) + +/** @brief Encode 64-bit value into array values in big-endian format. + * + * Helper macro to encode 64-bit values into comma separated values. + * + * @note @p _v is evaluated 8 times. + * + * @param _v 64-bit integer in host endianness. + * + * @return The comma separated values for the 64-bit value. + */ +#define BT_BYTES_LIST_BE64(_v) BT_BYTES_LIST_BE32((_v) >> 32), BT_BYTES_LIST_BE32(_v) + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_BYTEORDER_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/common/bt_str.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/common/bt_str.h new file mode 100644 index 0000000000..8778abd976 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/common/bt_str.h @@ -0,0 +1,19 @@ +/* + * SPDX-FileCopyrightText: 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/* NOTE: These helper functions always encodes into the same buffer storage. + * It is the responsibility of the user of this function to copy the information + * in this string if needed. + * + * NOTE: These functions are not thread-safe! + */ +const char *bt_hex(const void *buf, size_t len); +const char *bt_addr_str(const bt_addr_t *addr); +const char *bt_addr_le_str(const bt_addr_le_t *addr); +const char *bt_uuid_str(const struct bt_uuid *uuid); diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/conn.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/conn.h new file mode 100644 index 0000000000..61d441168a --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/conn.h @@ -0,0 +1,485 @@ +/** @file + * @brief Bluetooth connection handling + */ + +/* + * SPDX-FileCopyrightText: 2015-2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_CONN_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_CONN_H_ + +/** + * @brief Connection management + * @defgroup bt_conn Connection management + * @ingroup bluetooth + * @{ + */ + +#include +#include + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Opaque type representing a connection to a remote device */ +struct bt_conn; + +/** Connection Type */ +enum __packed bt_conn_type { + /** LE Connection Type */ + BT_CONN_TYPE_LE = BIT(0), + /** ISO Connection Type */ + BT_CONN_TYPE_ISO = BIT(3), + /** All Connection Type */ + BT_CONN_TYPE_ALL = BT_CONN_TYPE_LE | BT_CONN_TYPE_ISO, +}; + +/** @brief Increment a connection's reference count. + * + * Increment the reference count of a connection object. + * + * @note Will return NULL if the reference count is zero. + * + * @param conn Connection object. + * + * @return Connection object with incremented reference count, or NULL if the + * reference count is zero. + */ +struct bt_conn *bt_conn_ref(struct bt_conn *conn); + +/** @brief Decrement a connection's reference count. + * + * Decrement the reference count of a connection object. + * + * @param conn Connection object. + */ +void bt_conn_unref(struct bt_conn *conn); + +/** @brief Iterate through all bt_conn objects. + * + * Iterates through all bt_conn objects that are alive in the Host allocator. + * + * To find established connections, combine this with @ref bt_conn_get_info. + * Check that @ref bt_conn_info.state is @ref BT_CONN_STATE_CONNECTED. + * + * Thread safety: This API is thread safe, but it does not guarantee a + * sequentially-consistent view for objects allocated during the current + * invocation of this API. E.g. If preempted while allocations A then B then C + * happen then results may include A and C but miss B. + * + * @param type Connection Type + * @param func Function to call for each connection. + * @param data Data to pass to the callback function. + */ +void bt_conn_foreach(enum bt_conn_type type, + void (*func)(struct bt_conn *conn, void *data), + void *data); + +/** @brief Get destination (peer) address of a connection. + * + * @param conn Connection object. + * + * @return Destination address if @p conn is a valid @ref BT_CONN_TYPE_LE connection + */ +const bt_addr_le_t *bt_conn_get_dst(const struct bt_conn *conn); + +/** @brief Get array index of a connection + * + * This function is used to map bt_conn to index of an array of + * connections. The array has CONFIG_BT_MAX_CONN elements. + * + * @param conn Connection object. + * + * @return Index of the connection object. + * The range of the returned value is 0..CONFIG_BT_MAX_CONN-1 + */ +uint8_t bt_conn_index(const struct bt_conn *conn); + +/** LE Connection Info Structure */ +struct bt_conn_le_info { + /** Destination (Remote) Identity Address or remote Resolvable Private + * Address (RPA) before identity has been resolved. + */ + const bt_addr_le_t *dst; + uint16_t interval; /**< Connection interval */ +}; + +/** @brief Convert connection interval to milliseconds + * + * Multiply by 1.25 to get milliseconds. + * + * Note that this may be inaccurate, as something like 7.5 ms cannot be + * accurately presented with integers. + */ +#define BT_CONN_INTERVAL_TO_MS(interval) ((interval) * 5U / 4U) + +/** @brief Convert connection interval to microseconds + * + * Multiply by 1250 to get microseconds. + */ +#define BT_CONN_INTERVAL_TO_US(interval) ((interval) * 1250U) + +enum { + BT_CONN_ROLE_CENTRAL = 0, + BT_CONN_ROLE_PERIPHERAL = 1, +}; + +enum bt_conn_state { + /** Channel disconnected */ + BT_CONN_STATE_DISCONNECTED, + /** Channel in connecting state */ + BT_CONN_STATE_CONNECTING, + /** Channel connected and ready for upper layer traffic on it */ + BT_CONN_STATE_CONNECTED, + /** Channel in disconnecting state */ + BT_CONN_STATE_DISCONNECTING, +}; + +/** Security level. */ +typedef enum __packed { + /** Level 0: Only for BR/EDR special cases, like SDP */ + BT_SECURITY_L0, + /** Level 1: No encryption and no authentication. */ + BT_SECURITY_L1, + /** Level 2: Encryption and no authentication (no MITM). */ + BT_SECURITY_L2, + /** Level 3: Encryption and authentication (MITM). */ + BT_SECURITY_L3, + /** Level 4: Authenticated Secure Connections and 128-bit key. */ + BT_SECURITY_L4, + /** Bit to force new pairing procedure, bit-wise OR with requested + * security level. + */ + BT_SECURITY_FORCE_PAIR = BIT(7), +} bt_security_t; + +/** Security Info Flags. */ +enum bt_security_flag { + /** Paired with Secure Connections. */ + BT_SECURITY_FLAG_SC = BIT(0), + /** Paired with Out of Band method. */ + BT_SECURITY_FLAG_OOB = BIT(1), +}; + +/** Security Info Structure. */ +struct bt_security_info { + /** Security Level. */ + bt_security_t level; + /** Encryption Key Size. */ + uint8_t enc_key_size; + /** Flags. */ + enum bt_security_flag flags; +}; + +/** Connection Info Structure */ +struct bt_conn_info { + /** Connection Type. */ + enum bt_conn_type type; + /** Connection Role. */ + uint8_t role; + /** Which local identity the connection was created with */ + uint8_t id; + /** LE Connection specific Info. */ + struct bt_conn_le_info le; + /** Connection state. */ + enum bt_conn_state state; + /** Security specific info. */ + struct bt_security_info security; +}; + +/** @brief Get connection info + * + * @param conn Connection object. + * @param info Connection info object. + * + * @return Zero on success or (negative) error code on failure. + */ +int bt_conn_get_info(const struct bt_conn *conn, struct bt_conn_info *info); + +/** @brief Disconnect from a remote device or cancel pending connection. + * + * Disconnect an active connection with the specified reason code or cancel + * pending outgoing connection. + * + * The disconnect reason for a normal disconnect should be: + * @ref BT_HCI_ERR_REMOTE_USER_TERM_CONN. + * + * The following disconnect reasons are accepted: + * - @ref BT_HCI_ERR_AUTH_FAIL + * - @ref BT_HCI_ERR_REMOTE_USER_TERM_CONN + * - @ref BT_HCI_ERR_REMOTE_LOW_RESOURCES + * - @ref BT_HCI_ERR_REMOTE_POWER_OFF + * - @ref BT_HCI_ERR_UNSUPP_REMOTE_FEATURE + * - @ref BT_HCI_ERR_PAIRING_NOT_SUPPORTED + * - @ref BT_HCI_ERR_UNACCEPT_CONN_PARAM + * + * @param conn Connection to disconnect. + * @param reason Reason code for the disconnection. + * + * @return Zero on success or (negative) error code on failure. + */ +int bt_conn_disconnect(struct bt_conn *conn, uint8_t reason); + +/** @brief Set security level for a connection. + * + * This function enable security (encryption) for a connection. If the device + * has bond information for the peer with sufficiently strong key encryption + * will be enabled. If the connection is already encrypted with sufficiently + * strong key this function does nothing. + * + * If the device has no bond information for the peer and is not already paired + * then the pairing procedure will be initiated. Note that @p sec has no effect + * on the security level selected for the pairing process. The selection is + * instead controlled by the values of the registered @ref bt_conn_auth_cb. If + * the device has bond information or is already paired and the keys are too + * weak then the pairing procedure will be initiated. + * + * This function may return an error if the required level of security defined using + * @p sec is not possible to achieve due to local or remote device limitation + * (e.g., input output capabilities), or if the maximum number of paired devices + * has been reached. + * + * This function may return an error if the pairing procedure has already been + * initiated by the local device or the peer device. + * + * @note When @kconfig{CONFIG_BT_SMP_SC_ONLY} is enabled then the security + * level will always be level 4. + * + * @note When @kconfig{CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY} is enabled then the + * security level will always be level 3. + * + * @note When @ref BT_SECURITY_FORCE_PAIR within @p sec is enabled then the pairing + * procedure will always be initiated. + * + * @param conn Connection object. + * @param sec Requested minimum security level. + * + * @return 0 on success or negative error + */ +int bt_conn_set_security(struct bt_conn *conn, bt_security_t sec); + +enum bt_security_err { + /** Security procedure successful. */ + BT_SECURITY_ERR_SUCCESS, + + /** Authentication failed. */ + BT_SECURITY_ERR_AUTH_FAIL, + + /** PIN or encryption key is missing. */ + BT_SECURITY_ERR_PIN_OR_KEY_MISSING, + + /** OOB data is not available. */ + BT_SECURITY_ERR_OOB_NOT_AVAILABLE, + + /** The requested security level could not be reached. */ + BT_SECURITY_ERR_AUTH_REQUIREMENT, + + /** Pairing is not supported */ + BT_SECURITY_ERR_PAIR_NOT_SUPPORTED, + + /** Pairing is not allowed. */ + BT_SECURITY_ERR_PAIR_NOT_ALLOWED, + + /** Invalid parameters. */ + BT_SECURITY_ERR_INVALID_PARAM, + + /** Distributed Key Rejected */ + BT_SECURITY_ERR_KEY_REJECTED, + + /** Pairing failed but the exact reason could not be specified. */ + BT_SECURITY_ERR_UNSPECIFIED, +}; + +/** @brief Connection callback structure. + * + * This structure is used for tracking the state of a connection. + * It is registered with the help of the bt_conn_cb_register() API. + * It's permissible to register multiple instances of this @ref bt_conn_cb + * type, in case different modules of an application are interested in + * tracking the connection state. If a callback is not of interest for + * an instance, it may be set to NULL and will as a consequence not be + * used for that instance. + */ +struct bt_conn_cb { + /** @brief A new connection has been established. + * + * This callback notifies the application of a new connection. + * In case the err parameter is non-zero it means that the + * connection establishment failed. + * + * @note If the connection was established from an advertising set then + * the advertising set cannot be restarted directly from this + * callback. Instead use the connected callback of the + * advertising set. + * + * @param conn New connection object. + * @param err HCI error. Zero for success, non-zero otherwise. + * + * @p err can mean either of the following: + * - @ref BT_HCI_ERR_UNKNOWN_CONN_ID Creating the connection started by + * @ref bt_conn_le_create was canceled either by the user through + * @ref bt_conn_disconnect or by the timeout in the host through + * @ref bt_conn_le_create_param timeout parameter, which defaults to + * @kconfig{CONFIG_BT_CREATE_CONN_TIMEOUT} seconds. + * - @p BT_HCI_ERR_ADV_TIMEOUT High duty cycle directed connectable + * advertiser started by @ref bt_le_adv_start failed to be connected + * within the timeout. + */ + void (*connected)(struct bt_conn *conn, uint8_t err); + + /** @brief A connection has been disconnected. + * + * This callback notifies the application that a connection + * has been disconnected. + * + * When this callback is called the stack still has one reference to + * the connection object. If the application in this callback tries to + * start either a connectable advertiser or create a new connection + * this might fail because there are no free connection objects + * available. + * To avoid this issue it is recommended to either start connectable + * advertise or create a new connection using @ref k_work_submit or + * increase @kconfig{CONFIG_BT_MAX_CONN}. + * + * @param conn Connection object. + * @param reason BT_HCI_ERR_* reason for the disconnection. + */ + void (*disconnected)(struct bt_conn *conn, uint8_t reason); + + /** @brief Remote Identity Address has been resolved. + * + * This callback notifies the application that a remote + * Identity Address has been resolved + * + * @param conn Connection object. + * @param rpa Resolvable Private Address. + * @param identity Identity Address. + */ + void (*identity_resolved)(struct bt_conn *conn, + const bt_addr_le_t *rpa, + const bt_addr_le_t *identity); + + /** @brief The security level of a connection has changed. + * + * This callback notifies the application that the security of a + * connection has changed. + * + * The security level of the connection can either have been increased + * or remain unchanged. An increased security level means that the + * pairing procedure has been performed or the bond information from + * a previous connection has been applied. If the security level + * remains unchanged this means that the encryption key has been + * refreshed for the connection. + * + * @param conn Connection object. + * @param level New security level of the connection. + * @param err Security error. Zero for success, non-zero otherwise. + */ + void (*security_changed)(struct bt_conn *conn, bt_security_t level, + enum bt_security_err err); + + /** @internal Internally used field for list handling */ + sys_snode_t _node; +}; + +/** @brief Register connection callbacks. + * + * Register callbacks to monitor the state of connections. + * + * @param cb Callback struct. Must point to memory that remains valid. + * + * @retval 0 Success. + * @retval -EEXIST if @p cb was already registered. + */ +int bt_conn_cb_register(struct bt_conn_cb *cb); +int bt_conn_cb_register_safe(struct bt_conn_cb *cb); + +/** + * @brief Unregister connection callbacks. + * + * Unregister the state of connections callbacks. + * + * @param cb Callback struct point to memory that remains valid. + * + * @retval 0 Success + * @retval -EINVAL If @p cb is NULL + * @retval -ENOENT if @p cb was not registered + */ +int bt_conn_cb_unregister(struct bt_conn_cb *cb); + +/** + * @brief Register a callback structure for connection events. + * + * @param _name Name of callback structure. + */ +#define BT_CONN_CB_DEFINE(_name) \ + static const STRUCT_SECTION_ITERABLE(bt_conn_cb, \ + _CONCAT(bt_conn_cb_, \ + _name)) + +/** Authenticated pairing information callback structure */ +struct bt_conn_auth_info_cb { + /** @brief notify that pairing procedure was complete. + * + * This callback notifies the application that the pairing procedure + * has been completed. + * + * @param conn Connection object. + * @param bonded Bond information has been distributed during the + * pairing procedure. + */ + void (*pairing_complete)(struct bt_conn *conn, bool bonded); + + /** @brief Notify that bond has been deleted. + * + * This callback notifies the application that the bond information + * for the remote peer has been deleted + * + * @param id Which local identity had the bond. + * @param peer Remote address. + */ + void (*bond_deleted)(uint8_t id, const bt_addr_le_t *peer); + + /** Internally used field for list handling */ + sys_snode_t node; +}; + +/** @brief Register authentication information callbacks. + * + * Register callbacks to get authenticated pairing information. Multiple + * registrations can be done. + * + * @param cb Callback struct. + * + * @return Zero on success or negative error code otherwise + */ +int bt_conn_auth_info_cb_register(struct bt_conn_auth_info_cb *cb); + +/** @brief Unregister authentication information callbacks. + * + * Unregister callbacks to stop getting authenticated pairing information. + * + * @param cb Callback struct. + * + * @return Zero on success or negative error code otherwise + */ +int bt_conn_auth_info_cb_unregister(struct bt_conn_auth_info_cb *cb); + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_CONN_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/crypto.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/crypto.h new file mode 100644 index 0000000000..b8f03ee92b --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/crypto.h @@ -0,0 +1,65 @@ +/** @file + * @brief Bluetooth subsystem crypto APIs. + */ + +/* + * SPDX-FileCopyrightText: 2017-2020 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2015-2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_CRYPTO_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_CRYPTO_H_ + +/** + * @brief Cryptography + * @defgroup bt_crypto Cryptography + * @ingroup bluetooth + * @{ + */ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief Generate random data. + * + * A random number generation helper which utilizes the Bluetooth + * controller's own RNG. + * + * @param buf Buffer to insert the random data + * @param len Length of random data to generate + * + * @return Zero on success or error code otherwise, positive in case + * of protocol error or negative (POSIX) in case of stack internal error + */ +int bt_rand(void *buf, size_t len); + +/** @brief AES encrypt little-endian data. + * + * An AES encrypt helper is used to request the Bluetooth controller's own + * hardware to encrypt the plaintext using the key and returns the encrypted + * data. + * + * @param key 128 bit LS byte first key for the encryption of the plaintext + * @param plaintext 128 bit LS byte first plaintext data block to be encrypted + * @param enc_data 128 bit LS byte first encrypted data block + * + * @return Zero on success or error code otherwise. + */ +int bt_encrypt_le(const uint8_t key[16], const uint8_t plaintext[16], + uint8_t enc_data[16]); + +#ifdef __cplusplus +} +#endif +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_CRYPTO_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/crypto/bt_crypto.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/crypto/bt_crypto.h new file mode 100644 index 0000000000..0796db7216 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/crypto/bt_crypto.h @@ -0,0 +1,152 @@ +/* + * SPDX-FileCopyrightText: 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __BT_CRYPTO_H +#define __BT_CRYPTO_H + +#include +#include + +#include + +/** + * @brief Cypher based Message Authentication Code (CMAC) with AES 128 bit + * + * Defined in Core Vol. 3, part H 2.2.5. + * + * @param[in] key 128-bit key + * @param[in] in message to be authenticated + * @param[in] len length of the message in octets + * @param[out] out message authentication code + * + * @retval 0 Computation was successful. @p res contains the result. + * @retval -EIO Computation failed. + */ +int bt_crypto_aes_cmac(const uint8_t *key, const uint8_t *in, size_t len, uint8_t *out); + +/** + * @brief Cryptographic Toolbox f4 + * + * Defined in Core Vol. 3, part H 2.2.6. + * + * @param[in] u 256-bit + * @param[in] v 256-bit + * @param[in] x 128-bit key + * @param[in] z 8-bit + * @param[out] res + * + * @retval 0 Computation was successful. @p res contains the result. + * @retval -EIO Computation failed. + */ +int bt_crypto_f4(const uint8_t *u, const uint8_t *v, const uint8_t *x, uint8_t z, uint8_t res[16]); + +/** + * @brief Cryptographic Toolbox f5 + * + * Defined in Core Vol. 3, part H 2.2.7. + * + * @param[in] w 256-bit + * @param[in] n1 128-bit + * @param[in] n2 128-bit + * @param[in] a1 56-bit + * @param[in] a2 56-bit + * @param[out] mackey most significant 128-bit of the result + * @param[out] ltk least significant 128-bit of the result + * + * @retval 0 Computation was successful. @p res contains the result. + * @retval -EIO Computation failed. + */ +int bt_crypto_f5(const uint8_t *w, const uint8_t *n1, const uint8_t *n2, const bt_addr_le_t *a1, + const bt_addr_le_t *a2, uint8_t *mackey, uint8_t *ltk); + +/** + * @brief Cryptographic Toolbox f6 + * + * Defined in Core Vol. 3, part H 2.2.8. + * + * @param[in] w 128-bit + * @param[in] n1 128-bit + * @param[in] n2 128-bit + * @param[in] r 128-bit + * @param[in] iocap 24-bit + * @param[in] a1 56-bit + * @param[in] a2 56-bit + * @param[out] check + * + * @retval 0 Computation was successful. @p res contains the result. + * @retval -EIO Computation failed. + */ +int bt_crypto_f6(const uint8_t *w, const uint8_t *n1, const uint8_t *n2, const uint8_t *r, + const uint8_t *iocap, const bt_addr_le_t *a1, const bt_addr_le_t *a2, + uint8_t *check); + +/** + * @brief Cryptographic Toolbox g2 + + * Defined in Core Vol. 3, part H 2.2.9. + * + * @param[in] u 256-bit + * @param[in] v 256-bit + * @param[in] x 128-bit + * @param[in] y 128-bit + * @param[out] passkey + * + * @retval 0 Computation was successful. @p res contains the result. + * @retval -EIO Computation failed. + */ +int bt_crypto_g2(const uint8_t u[32], const uint8_t v[32], const uint8_t x[16], const uint8_t y[16], + uint32_t *passkey); + +/** + * @brief Cryptographic Toolbox h6 + * + * Link key conversion defined in Core Vol. 3, part H 2.2.10. + * + * @param[in] w 128-bit key + * @param[in] key_id 32-bit + * @param[out] res 128-bit + * + * @retval 0 Computation was successful. @p res contains the result. + * @retval -EIO Computation failed. + */ +int bt_crypto_h6(const uint8_t w[16], const uint8_t key_id[4], uint8_t res[16]); + +/** + * @brief Cryptographic Toolbox h7 + * + * Link key conversion defined in Core Vol. 3, part H 2.2.11. + * + * @param[in] salt 128-bit key + * @param[in] w 128-bit input of the AES-CMAC function + * @param[out] res 128-bit + * + * @retval 0 Computation was successful. @p res contains the result. + * @retval -EIO Computation failed. + */ +int bt_crypto_h7(const uint8_t salt[16], const uint8_t w[16], uint8_t res[16]); + +/** + * @brief Cryptographic Toolbox function h8 + * + * Defined in Core Vol. 6, part E 1.1.1. + * + * @note This function is purely a shorthand for the calculation. The parameters + * are therefore intentionally not assigned meaning. + * + * Pseudocode: `aes_cmac(key=aes_cmac(key=s, plaintext=k), plaintext=key_id)` + * + * @param[in] k (128-bit number in big endian) + * @param[in] s (128-bit number in big endian) + * @param[in] key_id (32-bit number in big endian) + * @param[out] res (128-bit number in big endian) + * + * @retval 0 Computation was successful. @p res contains the result. + * @retval -EIO Computation failed. + */ +int bt_crypto_h8(const uint8_t k[16], const uint8_t s[16], const uint8_t key_id[4], + uint8_t res[16]); + +#endif /* __BT_CRYPTO_H */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/gap.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/gap.h new file mode 100644 index 0000000000..9f7252a06b --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/gap.h @@ -0,0 +1,351 @@ +/** @file + * @brief Bluetooth Generic Access Profile defines and Assigned Numbers. + */ + +/* + * SPDX-FileCopyrightText: 2019 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_GAP_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_GAP_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Bluetooth Generic Access Profile defines and Assigned Numbers. + * @defgroup bt_gap_defines Defines and Assigned Numbers + * @ingroup bt_gap + * @{ + */ + +/** + * @name Company Identifiers (see Bluetooth Assigned Numbers) + * @{ + */ +#define BT_COMP_ID_LF 0x05f1 /**< The Linux Foundation */ +/** + * @} + */ + +/** + * @name Defined GAP timers + * @{ + */ +#define BT_GAP_SCAN_FAST_INTERVAL_MIN 0x0030 /* 30 ms */ +#define BT_GAP_SCAN_FAST_INTERVAL 0x0060 /* 60 ms */ +#define BT_GAP_SCAN_FAST_WINDOW 0x0030 /* 30 ms */ +#define BT_GAP_SCAN_SLOW_INTERVAL_1 0x0800 /* 1.28 s */ +#define BT_GAP_SCAN_SLOW_WINDOW_1 0x0012 /* 11.25 ms */ +#define BT_GAP_SCAN_SLOW_INTERVAL_2 0x1000 /* 2.56 s */ +#define BT_GAP_SCAN_SLOW_WINDOW_2 0x0012 /* 11.25 ms */ +#define BT_GAP_ADV_FAST_INT_MIN_1 0x0030 /* 30 ms */ +#define BT_GAP_ADV_FAST_INT_MAX_1 0x0060 /* 60 ms */ +#define BT_GAP_ADV_FAST_INT_MIN_2 0x00a0 /* 100 ms */ +#define BT_GAP_ADV_FAST_INT_MAX_2 0x00f0 /* 150 ms */ +#define BT_GAP_ADV_SLOW_INT_MIN 0x0640 /* 1 s */ +#define BT_GAP_ADV_SLOW_INT_MAX 0x0780 /* 1.2 s */ +#define BT_GAP_PER_ADV_FAST_INT_MIN_1 0x0018 /* 30 ms */ +#define BT_GAP_PER_ADV_FAST_INT_MAX_1 0x0030 /* 60 ms */ +#define BT_GAP_PER_ADV_FAST_INT_MIN_2 0x0050 /* 100 ms */ +#define BT_GAP_PER_ADV_FAST_INT_MAX_2 0x0078 /* 150 ms */ +#define BT_GAP_PER_ADV_SLOW_INT_MIN 0x0320 /* 1 s */ +#define BT_GAP_PER_ADV_SLOW_INT_MAX 0x03C0 /* 1.2 s */ +#define BT_GAP_INIT_CONN_INT_MIN 0x0018 /* 30 ms */ +#define BT_GAP_INIT_CONN_INT_MAX 0x0028 /* 50 ms */ +/** + * @} + */ + +/** LE PHY types */ +enum bt_gap_le_phy { + /** Convenience macro for when no PHY is set. */ + BT_GAP_LE_PHY_NONE = 0, + /** LE 1M PHY */ + BT_GAP_LE_PHY_1M = BIT(0), + /** LE 2M PHY */ + BT_GAP_LE_PHY_2M = BIT(1), + /** LE Coded PHY, coding scheme not specified */ + BT_GAP_LE_PHY_CODED = BIT(2), + /** LE Coded S=8 PHY. Only used for advertising reports + * when Kconfig BT_EXT_ADV_CODING_SELECTION is enabled. + */ + BT_GAP_LE_PHY_CODED_S8 = BIT(3), + /** LE Coded S=2 PHY. Only used for advertising reports + * when Kconfig BT_EXT_ADV_CODING_SELECTION is enabled. + */ + BT_GAP_LE_PHY_CODED_S2 = BIT(4), +}; + +/** Advertising PDU types */ +enum bt_gap_adv_type { + /** Scannable and connectable advertising. */ + BT_GAP_ADV_TYPE_ADV_IND = 0x00, + /** Directed connectable advertising. */ + BT_GAP_ADV_TYPE_ADV_DIRECT_IND = 0x01, + /** Non-connectable and scannable advertising. */ + BT_GAP_ADV_TYPE_ADV_SCAN_IND = 0x02, + /** Non-connectable and non-scannable advertising. */ + BT_GAP_ADV_TYPE_ADV_NONCONN_IND = 0x03, + /** Additional advertising data requested by an active scanner. */ + BT_GAP_ADV_TYPE_SCAN_RSP = 0x04, + /** Extended advertising, see advertising properties. */ + BT_GAP_ADV_TYPE_EXT_ADV = 0x05, +}; + +/** Advertising PDU properties */ +enum bt_gap_adv_prop { + /** Connectable advertising. */ + BT_GAP_ADV_PROP_CONNECTABLE = BIT(0), + /** Scannable advertising. */ + BT_GAP_ADV_PROP_SCANNABLE = BIT(1), + /** Directed advertising. */ + BT_GAP_ADV_PROP_DIRECTED = BIT(2), + /** Additional advertising data requested by an active scanner. */ + BT_GAP_ADV_PROP_SCAN_RESPONSE = BIT(3), + /** Extended advertising. */ + BT_GAP_ADV_PROP_EXT_ADV = BIT(4), +}; + +/** Maximum advertising data length. */ +#define BT_GAP_ADV_MAX_ADV_DATA_LEN 31 +/** Maximum extended advertising data length. + * + * @note The maximum advertising data length that can be sent by an extended + * advertiser is defined by the controller. + */ +#define BT_GAP_ADV_MAX_EXT_ADV_DATA_LEN 1650 + +#define BT_GAP_TX_POWER_INVALID 0x7f +#define BT_GAP_RSSI_INVALID 0x7f +#define BT_GAP_SID_INVALID 0xff +#define BT_GAP_NO_TIMEOUT 0x0000 + +/* The maximum allowed high duty cycle directed advertising timeout, 1.28 + * seconds in 10 ms unit. + */ +#define BT_GAP_ADV_HIGH_DUTY_CYCLE_MAX_TIMEOUT 128 + +/** Default data length */ +#define BT_GAP_DATA_LEN_DEFAULT 0x001b /* 27 bytes */ +/** Maximum data length */ +#define BT_GAP_DATA_LEN_MAX 0x00fb /* 251 bytes */ + +/** Default data time */ +#define BT_GAP_DATA_TIME_DEFAULT 0x0148 /* 328 us */ +/** Maximum data time */ +#define BT_GAP_DATA_TIME_MAX 0x4290 /* 17040 us */ + +/** Minimum advertising set number */ +#define BT_GAP_SID_MIN 0x00 +/** Maximum advertising set number */ +#define BT_GAP_SID_MAX 0x0F +/** Maximum number of consecutive periodic advertisement events that can be + * skipped after a successful receive. + */ +#define BT_GAP_PER_ADV_MAX_SKIP 0x01F3 +/** Minimum Periodic Advertising Timeout (N * 10 ms) */ +#define BT_GAP_PER_ADV_MIN_TIMEOUT 0x000A /* 100 ms */ +/** Maximum Periodic Advertising Timeout (N * 10 ms) */ +#define BT_GAP_PER_ADV_MAX_TIMEOUT 0x4000 /* 163.84 s */ +/** Minimum Periodic Advertising Interval (N * 1.25 ms) */ +#define BT_GAP_PER_ADV_MIN_INTERVAL 0x0006 /* 7.5 ms */ +/** Maximum Periodic Advertising Interval (N * 1.25 ms) */ +#define BT_GAP_PER_ADV_MAX_INTERVAL 0xFFFF /* 81.91875 s */ + +/** + * @brief Convert periodic advertising interval (N * 0.625 ms) to microseconds + * + * Value range of @p _interval is @ref BT_LE_ADV_INTERVAL_MIN to @ref BT_LE_ADV_INTERVAL_MAX + */ +#define BT_GAP_ADV_INTERVAL_TO_US(_interval) ((uint32_t)((_interval) * 625U)) + +/** + * @brief Convert periodic advertising interval (N * 0.625 ms) to milliseconds + * + * Value range of @p _interval is @ref BT_LE_ADV_INTERVAL_MIN to @ref BT_LE_ADV_INTERVAL_MAX + * + * @note When intervals cannot be represented in milliseconds, this will round down. + * For example BT_GAP_ADV_INTERVAL_TO_MS(0x0021) will become 20 ms instead of 20.625 ms + */ +#define BT_GAP_ADV_INTERVAL_TO_MS(_interval) (BT_GAP_ADV_INTERVAL_TO_US(_interval) / USEC_PER_MSEC) + +/** + * @brief Convert isochronous interval (N * 1.25 ms) to microseconds + * + * Value range of @p _interval is @ref BT_HCI_ISO_INTERVAL_MIN to @ref BT_HCI_ISO_INTERVAL_MAX + */ +#define BT_GAP_ISO_INTERVAL_TO_US(_interval) ((uint32_t)((_interval) * 1250U)) + +/** + * @brief Convert isochronous interval (N * 1.25 ms) to milliseconds + * + * Value range of @p _interval is @ref BT_HCI_ISO_INTERVAL_MIN to @ref BT_HCI_ISO_INTERVAL_MAX + * + * @note When intervals cannot be represented in milliseconds, this will round down. + * For example BT_GAP_ISO_INTERVAL_TO_MS(0x0005) will become 6 ms instead of 6.25 ms + */ +#define BT_GAP_ISO_INTERVAL_TO_MS(_interval) (BT_GAP_ISO_INTERVAL_TO_US(_interval) / USEC_PER_MSEC) + +/** @brief Convert periodic advertising interval (N * 1.25 ms) to microseconds * + * + * Value range of @p _interval is @ref BT_HCI_LE_PER_ADV_INTERVAL_MIN to @ref + * BT_HCI_LE_PER_ADV_INTERVAL_MAX + */ +#define BT_GAP_PER_ADV_INTERVAL_TO_US(_interval) ((uint32_t)((_interval) * 1250U)) + +/** + * @brief Convert periodic advertising interval (N * 1.25 ms) to milliseconds + * + * @note When intervals cannot be represented in milliseconds, this will round down. + * For example BT_GAP_PER_ADV_INTERVAL_TO_MS(0x0009) will become 11 ms instead of 11.25 ms + */ +#define BT_GAP_PER_ADV_INTERVAL_TO_MS(_interval) \ + (BT_GAP_PER_ADV_INTERVAL_TO_US(_interval) / 1000U) + +/** @brief Peripheral sleep clock accuracy (SCA) in ppm (parts per million) */ +enum bt_gap_sca { + BT_GAP_SCA_UNKNOWN = 0, /**< Unknown */ + BT_GAP_SCA_251_500 = 0, /**< 251 ppm to 500 ppm */ + BT_GAP_SCA_151_250 = 1, /**< 151 ppm to 250 ppm */ + BT_GAP_SCA_101_150 = 2, /**< 101 ppm to 150 ppm */ + BT_GAP_SCA_76_100 = 3, /**< 76 ppm to 100 ppm */ + BT_GAP_SCA_51_75 = 4, /**< 51 ppm to 75 ppm */ + BT_GAP_SCA_31_50 = 5, /**< 31 ppm to 50 ppm */ + BT_GAP_SCA_21_30 = 6, /**< 21 ppm to 30 ppm */ + BT_GAP_SCA_0_20 = 7, /**< 0 ppm to 20 ppm */ +}; + +/** + * @brief Encode 40 least significant bits of 64-bit LE Supported Features into array values + * in little-endian format. + * + * Helper macro to encode 40 least significant bits of 64-bit LE Supported Features value into + * advertising data. The number of bits that are encoded is a number of LE Supported Features + * defined by BT 5.3 Core specification. + * + * Example of how to encode the `0x000000DFF00DF00D` into advertising data. + * + * @code + * BT_DATA_BYTES(BT_DATA_LE_SUPPORTED_FEATURES, BT_LE_SUPP_FEAT_40_ENCODE(0x000000DFF00DF00D)) + * @endcode + * + * @param w64 LE Supported Features value (64-bits) + * + * @return The comma separated values for LE Supported Features value that + * may be used directly as an argument for @ref BT_DATA_BYTES. + */ +#define BT_LE_SUPP_FEAT_40_ENCODE(w64) BT_BYTES_LIST_LE40(w64) + +/** @brief Encode 4 least significant bytes of 64-bit LE Supported Features into + * 4 bytes long array of values in little-endian format. + * + * Helper macro to encode 64-bit LE Supported Features value into advertising + * data. The macro encodes 4 least significant bytes into advertising data. + * Other 4 bytes are not encoded. + * + * Example of how to encode the `0x000000DFF00DF00D` into advertising data. + * + * @code + * BT_DATA_BYTES(BT_DATA_LE_SUPPORTED_FEATURES, BT_LE_SUPP_FEAT_32_ENCODE(0x000000DFF00DF00D)) + * @endcode + * + * @param w64 LE Supported Features value (64-bits) + * + * @return The comma separated values for LE Supported Features value that + * may be used directly as an argument for @ref BT_DATA_BYTES. + */ +#define BT_LE_SUPP_FEAT_32_ENCODE(w64) BT_BYTES_LIST_LE32(w64) + +/** + * @brief Encode 3 least significant bytes of 64-bit LE Supported Features into + * 3 bytes long array of values in little-endian format. + * + * Helper macro to encode 64-bit LE Supported Features value into advertising + * data. The macro encodes 3 least significant bytes into advertising data. + * Other 5 bytes are not encoded. + * + * Example of how to encode the `0x000000DFF00DF00D` into advertising data. + * + * @code + * BT_DATA_BYTES(BT_DATA_LE_SUPPORTED_FEATURES, BT_LE_SUPP_FEAT_24_ENCODE(0x000000DFF00DF00D)) + * @endcode + * + * @param w64 LE Supported Features value (64-bits) + * + * @return The comma separated values for LE Supported Features value that + * may be used directly as an argument for @ref BT_DATA_BYTES. + */ +#define BT_LE_SUPP_FEAT_24_ENCODE(w64) BT_BYTES_LIST_LE24(w64) + +/** + * @brief Encode 2 least significant bytes of 64-bit LE Supported Features into + * 2 bytes long array of values in little-endian format. + * + * Helper macro to encode 64-bit LE Supported Features value into advertising + * data. The macro encodes 3 least significant bytes into advertising data. + * Other 6 bytes are not encoded. + * + * Example of how to encode the `0x000000DFF00DF00D` into advertising data. + * + * @code + * BT_DATA_BYTES(BT_DATA_LE_SUPPORTED_FEATURES, BT_LE_SUPP_FEAT_16_ENCODE(0x000000DFF00DF00D)) + * @endcode + * + * @param w64 LE Supported Features value (64-bits) + * + * @return The comma separated values for LE Supported Features value that + * may be used directly as an argument for @ref BT_DATA_BYTES. + */ +#define BT_LE_SUPP_FEAT_16_ENCODE(w64) BT_BYTES_LIST_LE16(w64) + +/** + * @brief Encode the least significant byte of 64-bit LE Supported Features into + * single byte long array. + * + * Helper macro to encode 64-bit LE Supported Features value into advertising + * data. The macro encodes the least significant byte into advertising data. + * Other 7 bytes are not encoded. + * + * Example of how to encode the `0x000000DFF00DF00D` into advertising data. + * + * @code + * BT_DATA_BYTES(BT_DATA_LE_SUPPORTED_FEATURES, BT_LE_SUPP_FEAT_8_ENCODE(0x000000DFF00DF00D)) + * @endcode + * + * @param w64 LE Supported Features value (64-bits) + * + * @return The value of least significant byte of LE Supported Features value + * that may be used directly as an argument for @ref BT_DATA_BYTES. + */ +#define BT_LE_SUPP_FEAT_8_ENCODE(w64) \ + (((w64) >> 0) & 0xFF) + +/** + * @brief Validate whether LE Supported Features value does not use bits that are reserved for + * future use. + * + * Helper macro to check if @p w64 has zeros as bits 40-63. The macro is compliant with BT 5.3 + * Core Specification where bits 0-40 has assigned values. In case of invalid value, build time + * error is reported. + */ +#define BT_LE_SUPP_FEAT_VALIDATE(w64) \ + BUILD_ASSERT(!((w64) & (~BIT64_MASK(40))), \ + "RFU bit in LE Supported Features are not zeros.") + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_GAP_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/gatt.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/gatt.h new file mode 100644 index 0000000000..3eb7370886 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/gatt.h @@ -0,0 +1,2056 @@ +/** @file + * @brief Generic Attribute Profile handling. + */ + +/* + * SPDX-FileCopyrightText: 2015-2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_GATT_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_GATT_H_ + +/** + * @brief Generic Attribute Profile (GATT) + * @details The GATT layer manages the service database by providing APIs for + * service registration and attribute declaration. For more + * information, see @ref bt_gatt_client and @ref bt_gatt_server. + * @defgroup bt_gatt Generic Attribute Profile (GATT) + * @ingroup bluetooth + * @{ + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** GATT attribute permission bit field values */ +enum bt_gatt_perm { + /** No operations supported, e.g. for notify-only */ + BT_GATT_PERM_NONE = 0, + + /** Attribute read permission. */ + BT_GATT_PERM_READ = BIT(0), + + /** Attribute write permission. */ + BT_GATT_PERM_WRITE = BIT(1), + + /** @brief Attribute read permission with encryption. + * + * If set, requires encryption for read access. + */ + BT_GATT_PERM_READ_ENCRYPT = BIT(2), + + /** @brief Attribute write permission with encryption. + * + * If set, requires encryption for write access. + */ + BT_GATT_PERM_WRITE_ENCRYPT = BIT(3), + + /** @brief Attribute read permission with authentication. + * + * If set, requires encryption using authenticated link-key for read + * access. + */ + BT_GATT_PERM_READ_AUTHEN = BIT(4), + + /** @brief Attribute write permission with authentication. + * + * If set, requires encryption using authenticated link-key for write + * access. + */ + BT_GATT_PERM_WRITE_AUTHEN = BIT(5), + + /** @brief Attribute prepare write permission. + * + * If set, allows prepare writes with use of ``BT_GATT_WRITE_FLAG_PREPARE`` + * passed to write callback. + */ + BT_GATT_PERM_PREPARE_WRITE = BIT(6), + + /** @brief Attribute read permission with LE Secure Connection encryption. + * + * If set, requires that LE Secure Connections is used for read access. + */ + BT_GATT_PERM_READ_LESC = BIT(7), + + /** @brief Attribute write permission with LE Secure Connection encryption. + * + * If set, requires that LE Secure Connections is used for write access. + */ + BT_GATT_PERM_WRITE_LESC = BIT(8), +}; + +/** + * @brief Construct error return value for attribute read and write callbacks. + * + * @param _att_err ATT error code + * + * @return Appropriate error code for the attribute callbacks. + */ +#define BT_GATT_ERR(_att_err) (-(_att_err)) + +/** GATT attribute write flags */ +enum bt_gatt_attr_write_flag { + /** @brief Attribute prepare write flag + * + * If set, write callback should only check if the device is + * authorized but no data shall be written. + */ + BT_GATT_WRITE_FLAG_PREPARE = BIT(0), + + /** @brief Attribute write command flag + * + * If set, indicates that write operation is a command (Write without + * response) which doesn't generate any response. + */ + BT_GATT_WRITE_FLAG_CMD = BIT(1), + + /** @brief Attribute write execute flag + * + * If set, indicates that write operation is a execute, which indicates + * the end of a long write, and will come after 1 or more + * @ref BT_GATT_WRITE_FLAG_PREPARE. + */ + BT_GATT_WRITE_FLAG_EXECUTE = BIT(2), +}; + +/* Forward declaration of GATT Attribute structure */ +struct bt_gatt_attr; + +/** @typedef bt_gatt_attr_read_func_t + * @brief Attribute read callback + * + * This is the type of the bt_gatt_attr.read() method. + * + * This function may safely assume the Attribute Permissions + * are satisfied for this read. Callers are responsible for + * this. + * + * Callers may set @p conn to emulate a GATT client read, or + * leave it NULL for local reads. + * + * @note GATT server relies on this method to handle read + * operations from remote GATT clients. But this method is not + * reserved for the GATT server. E.g. You can lookup attributes + * in the local ATT database and invoke this method. + * + * @note The GATT server propagates the return value from this + * method back to the remote client. + * + * @param conn The connection that is requesting to read. + * NULL if local. + * @param attr The attribute that's being read + * @param buf Buffer to place the read result in + * @param len Length of data to read + * @param offset Offset to start reading from + * + * @return Number of bytes read, or in case of an error + * ``BT_GATT_ERR()`` with a specific ``BT_ATT_ERR_*`` error code. + */ +typedef ssize_t (*bt_gatt_attr_read_func_t)(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + void *buf, uint16_t len, + uint16_t offset); + +/** @typedef bt_gatt_attr_write_func_t + * @brief Attribute Value write implementation + * + * This is the type of the bt_gatt_attr.write() method. + * + * This function may safely assume the Attribute Permissions + * are satisfied for this write. Callers are responsible for + * this. + * + * Callers may set @p conn to emulate a GATT client write, or + * leave it NULL for local writes. + * + * If @p flags contains @ref BT_GATT_WRITE_FLAG_PREPARE, then + * the method shall not perform a write, but instead only check + * if the write is authorized and return an error code if not. + * + * Attribute Value write implementations can and often do have + * side effects besides potentially storing the value. E.g. + * togging an LED. + * + * @note GATT server relies on this method to handle write + * operations from remote GATT clients. But this method is not + * reserved for the GATT server. E.g. You can lookup attributes + * in the local ATT database and invoke this method. + * + * @note The GATT server propagates the return value from this + * method back to the remote client. + * + * @param conn The connection that is requesting to write + * @param attr The attribute that's being written + * @param buf Buffer with the data to write + * @param len Number of bytes in the buffer + * @param offset Offset to start writing from + * @param flags Flags of type @ref bt_gatt_attr_write_flag + * + * @return Number of bytes written, or in case of an error + * ``BT_GATT_ERR()`` with a specific ``BT_ATT_ERR_*`` error code. + */ +typedef ssize_t (*bt_gatt_attr_write_func_t)(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, + uint16_t offset, uint8_t flags); + +/** @brief GATT Attribute + * + * This type primarily represents an ATT Attribute that may be + * an entry in the local ATT database. The objects of this type + * must be part of an array that forms a GATT service. + * + * While the formed GATT service is registered with the local + * GATT server, pointers to this type can typically be given to + * GATT server APIs, like bt_gatt_notify(). + */ +struct bt_gatt_attr { + /** @brief Attribute Type + * + * The Attribute Type is a UUID which determines the interface that can + * be expected from the read() and write() methods and + * the possible permission configurations. + * + * E.g. Attribute of type @ref BT_UUID_GATT_CPF will act as a + * GATT Characteristic Presentation Format descriptor as + * specified in Core Specification 3.G.3.3.3.5. + * + * You can define a new Attribute Type for your application specific + * use by generating a new UUID for it. + */ + const struct bt_uuid *uuid; + + /** @brief Attribute Value read method + * + * Readable Attributes must implement this method. + * + * Must be NULL if the attribute is not readable. + * + * The behavior of this method is determined by the Attribute + * Type. + * + * See @ref bt_gatt_attr_read_func_t. + */ + bt_gatt_attr_read_func_t read; + + /** @brief Attribute Value write method + * + * Writeable Attributes must implement this method. + * + * Must be NULL if the attribute is not writable. + * + * The behavior of this method is determined by the Attribute + * Type. + * + * See @ref bt_gatt_attr_write_func_t. + */ + bt_gatt_attr_write_func_t write; + + /** @brief Private data for read() and write() implementation + * + * The meaning of this field varies and is not specified here. + * + * @note Attributes may have the same Attribute Type but have + * different implementations, with incompatible user data. + * Attribute Type alone must not be used to infer the type of + * the user data. + * + * @sa bt_gatt_discover_func_t about this field. + */ + void *user_data; + + /** @brief Attribute Handle + * + * The Attribute Handle is an index corresponding to a specific + * Attribute in the ATT database. + * + * @note Use bt_gatt_attr_get_handle() for attributes in the + * local ATT database. + */ + uint16_t handle; + + /** @brief Attribute Permissions + * + * Bit field of @ref bt_gatt_perm. + * + * The permissions are security requirements that must be + * satisfied before calling read() or write(). + */ + uint16_t perm: 15; + + /** @cond INTERNAL_HIDDEN + * Indicates if the attribute handle was assigned automatically. + * + * This flag is set to 1 if the attribute handle was assigned by the stack, + * and 0 if it was manually set by the application. + * + * @note Applications must not modify this field. + */ + bool _auto_assigned_handle: 1; + /** @endcond */ +}; + +/** @brief Static GATT Service structure + * + * Allows the user the declare static GATT Services with the aim of reducing the + * used RAM. The @ref BT_GATT_SERVICE_DEFINE macro can be used to statically + * define and register a service. + */ +struct bt_gatt_service_static { + /** Service Attributes */ + struct bt_gatt_attr *attrs; + /** Service Attribute count */ + size_t attr_count; +}; + +/** @brief GATT Service structure + * + * This structure is used to define GATT services which can be registered and + * unregistered at runtime. See @ref bt_gatt_service_register for when services + * should be registered. + */ +struct bt_gatt_service { + /** Service Attributes */ + struct bt_gatt_attr *attrs; + /** Service Attribute count */ + size_t attr_count; + /** @cond INTERNAL_HIDDEN + * Field used for list handling. + */ + sys_snode_t node; + /** @endcond */ +}; + +/** @brief Service Attribute Value. + * + * This is the data described by the Attribute Type and indexed by the + * Attribute Handle in the database. + */ +struct bt_gatt_service_val { + /** Service UUID. */ + const struct bt_uuid *uuid; + /** Handle of the last Attribute within the Service. */ + uint16_t end_handle; +}; + +/** @brief Include Attribute Value. + * + * This structure represents an included service attribute in the GATT + * server. An included service is a service that is referenced within another + * service, allowing for the reuse of common service definitions. + */ +struct bt_gatt_include { + /** Service UUID. */ + const struct bt_uuid *uuid; + /** Handle of the first attribute within the included service. */ + uint16_t start_handle; + /** Handle of the last attribute within the included service. */ + uint16_t end_handle; +}; + +/** Characteristic Properties Bit field values */ + +/** + * @brief Characteristic broadcast property. + * + * If set, permits broadcasts of the Characteristic Value using Server + * Characteristic Configuration Descriptor. + */ +#define BT_GATT_CHRC_BROADCAST 0x01 +/** + * @brief Characteristic read property. + * + * If set, permits reads of the Characteristic Value. + */ +#define BT_GATT_CHRC_READ 0x02 +/** + * @brief Characteristic write without response property. + * + * If set, permits write of the Characteristic Value without response. + */ +#define BT_GATT_CHRC_WRITE_WITHOUT_RESP 0x04 +/** + * @brief Characteristic write with response property. + * + * If set, permits write of the Characteristic Value with response. + */ +#define BT_GATT_CHRC_WRITE 0x08 +/** + * @brief Characteristic notify property. + * + * If set, permits notifications of a Characteristic Value without + * acknowledgment. + */ +#define BT_GATT_CHRC_NOTIFY 0x10 +/** + * @brief Characteristic indicate property. + * + * If set, permits indications of a Characteristic Value with acknowledgment. + */ +#define BT_GATT_CHRC_INDICATE 0x20 +/** + * @brief Characteristic Authenticated Signed Writes property. + * + * If set, permits signed writes to the Characteristic Value. + */ +#define BT_GATT_CHRC_AUTH 0x40 +/** + * @brief Characteristic Extended Properties property. + * + * If set, additional characteristic properties are defined in the + * Characteristic Extended Properties Descriptor. + */ +#define BT_GATT_CHRC_EXT_PROP 0x80 + +/** @brief Attribute Value of a Characteristic Declaration. + * + * This is the data associated with the characteristic, and can be read from or + * written to by a GATT client depending on the characteristic properties. + */ +struct bt_gatt_chrc { + /** Characteristic UUID. */ + const struct bt_uuid *uuid; + /** Characteristic Value handle. */ + uint16_t value_handle; + /** Characteristic properties, a bitmap of ``BT_GATT_CHRC_*`` macros. */ + uint8_t properties; +}; + +/** Characteristic Extended Properties Bit field values */ +#define BT_GATT_CEP_RELIABLE_WRITE 0x0001 +#define BT_GATT_CEP_WRITABLE_AUX 0x0002 + +/** @brief Characteristic Extended Properties Attribute Value. + * + * Used in the discovery of standard characteristic descriptor values. Shall + * exist if the @ref BT_GATT_CHRC_EXT_PROP bit is set in the characteristic + * properties. Can be used with the @ref BT_GATT_CEP macro to declare the CEP + * descriptor. + */ +struct bt_gatt_cep { + /** Characteristic Extended properties, a bitmap of ``BT_GATT_CEP_*`` macros. */ + uint16_t properties; +}; + +/** Client Characteristic Configuration Values */ + +/** + * @brief Client Characteristic Configuration Notification. + * + * If set, changes to Characteristic Value shall be notified. + */ +#define BT_GATT_CCC_NOTIFY 0x0001 +/** + * @brief Client Characteristic Configuration Indication. + * + * If set, changes to Characteristic Value shall be indicated. + */ +#define BT_GATT_CCC_INDICATE 0x0002 + +/** @brief Client Characteristic Configuration Attribute Value + * + * Used in the discovery of standard characteristic descriptor values. + */ +struct bt_gatt_ccc { + /** Client Characteristic Configuration flags, a bitmap of ``BT_GATT_CCC_*`` macros. */ + uint16_t flags; +}; + +/** Server Characteristic Configuration Values */ + +/** + * @brief Server Characteristic Configuration Broadcast + * + * If set, the characteristic value shall be broadcast in the advertising data + * when the server is advertising. + */ +#define BT_GATT_SCC_BROADCAST 0x0001 + +/** @brief Server Characteristic Configuration Attribute Value + * + * Used in the discovery of standard characteristic descriptor values. + */ +struct bt_gatt_scc { + /** Server Characteristic Configuration flags, a bitmap of ``BT_GATT_SCC_*`` macros. */ + uint16_t flags; +}; + +/** @brief GATT Characteristic Presentation Format Attribute Value. + * + * Used in the discovery of standard characteristic descriptor values. Can be + * used with the @ref BT_GATT_CPF macro to declare the CPF descriptor. + */ +struct bt_gatt_cpf { + /** @brief Format of the value of the characteristic. + * + * The format types can be found in section 2.4.1 of the Bluetooth SIG + * Assigned Numbers document. + */ + uint8_t format; + /** @brief Exponent field for value formatting. + * + * Only used on integer format types. + * actual value = Characteristic Value x 10^Exponent + */ + int8_t exponent; + /** @brief UUID of the unit of the characteristic. + * + * The units can be found in section 3.5 of the Bluetooth SIG Assigned + * Numbers document. + */ + uint16_t unit; + /** @brief Name space of the description. + * + * Used to identify the organization that is responsible for defining + * the enumerations for the description field. See section 2.4.2 of the + * Bluetooth SIG Assigned Numbers document. + */ + uint8_t name_space; + /** @brief Description of the characteristic as defined in a higher layer profile. + * + * An enumerated value defined by the organization identified by the + * name_space field. See section 2.4.2.1 of the Bluetooth SIG Assigned + * Numbers document. + */ + uint16_t description; +}; + +/** + * @defgroup bt_gatt_server GATT Server APIs + * @ingroup bt_gatt + * @{ + */ + +/** @brief Register GATT service. + * + * To register a GATT service, applications can make use of macros such as + * ``BT_GATT_PRIMARY_SERVICE``, ``BT_GATT_CHARACTERISTIC``, + * ``BT_GATT_DESCRIPTOR``, etc. + * + * When using @kconfig{CONFIG_BT_SETTINGS} then all services that should have + * bond configuration loaded, i.e. CCC values, must be registered before + * calling @ref settings_load. + * + * When using @kconfig{CONFIG_BT_GATT_CACHING} and @kconfig{CONFIG_BT_SETTINGS} + * then all services that should be included in the GATT Database Hash + * calculation should be added before calling @ref settings_load. + * All services registered after settings_load will trigger a new database hash + * calculation and a new hash stored. + * + * There are two situations where this function can be called: either before + * `bt_init()` has been called, or after `settings_load()` has been called. + * Registering a service in the middle is not supported and will return an + * error. + * + * @param svc Service containing the available attributes + * + * @return 0 in case of success or negative value in case of error. + * @return -EAGAIN if ``bt_init()`` has been called but ``settings_load()`` hasn't yet. + */ +int bt_gatt_service_register(struct bt_gatt_service *svc); +int bt_gatt_service_register_safe(struct bt_gatt_service *svc); + +/** @brief Unregister GATT service. + * + * @param svc Service to be unregistered. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_gatt_service_unregister(struct bt_gatt_service *svc); +int bt_gatt_service_unregister_safe(struct bt_gatt_service *svc); + +/** @brief to be used as return values for @ref bt_gatt_attr_func_t and @ref bt_gatt_read_func_t + * type callbacks. + */ +enum bt_gatt_iter { + BT_GATT_ITER_STOP = 0, + BT_GATT_ITER_CONTINUE, +}; + +/** @typedef bt_gatt_attr_func_t + * @brief Attribute iterator callback. + * + * @param attr Attribute found. + * @param handle Attribute handle found. + * @param user_data Data given. + * + * @return ``BT_GATT_ITER_CONTINUE`` if should continue to the next attribute. + * @return ``BT_GATT_ITER_STOP`` to stop. + */ +typedef uint8_t (*bt_gatt_attr_func_t)(const struct bt_gatt_attr *attr, + uint16_t handle, + void *user_data); + +/** @brief Attribute iterator by type. + * + * Iterate attributes in the given range matching given UUID and/or data. + * + * @param start_handle Start attribute handle. + * @param end_handle End attribute handle. Often set to start_handle + attr_count or + * BT_ATT_LAST_ATTRIBUTE_HANDLE. + * @param uuid UUID to match, passing NULL skips UUID matching. + * @param attr_data Attribute data to match, passing NULL skips data matching. + * @param num_matches Number matches, passing 0 makes it unlimited. + * @param func Callback function. + * @param user_data Data to pass to the callback. + */ +void bt_gatt_foreach_attr_type(uint16_t start_handle, uint16_t end_handle, + const struct bt_uuid *uuid, + const void *attr_data, uint16_t num_matches, + bt_gatt_attr_func_t func, + void *user_data); + +/** @brief Attribute iterator. + * + * Iterate attributes in the given range. + * + * @param start_handle Starting attribute handle. + * @param end_handle Ending attribute handle. + * @param func Callback function. + * @param user_data Data to pass to the callback. + */ +static inline void bt_gatt_foreach_attr(uint16_t start_handle, uint16_t end_handle, + bt_gatt_attr_func_t func, + void *user_data) +{ + bt_gatt_foreach_attr_type(start_handle, end_handle, NULL, NULL, 0, func, + user_data); +} + +/** @brief Iterate to the next attribute + * + * Iterate to the next attribute following a given attribute. + * + * @param attr Current Attribute. + * + * @return The next attribute or NULL if it cannot be found. + */ +struct bt_gatt_attr *bt_gatt_attr_next(const struct bt_gatt_attr *attr); + +/** @brief Find Attribute by UUID. + * + * Find the attribute with the matching UUID. + * To limit the search to a service set the attr to the service attributes and + * the ``attr_count`` to the service attribute count . + * + * @param attr Pointer to an attribute that serves as the starting point + * for the search of a match for the UUID. + * Passing NULL will search the entire range. + * @param attr_count The number of attributes from the starting point to + * search for a match for the UUID. + * Set to 0 to search until the end. + * @param uuid UUID to match. + */ +struct bt_gatt_attr *bt_gatt_find_by_uuid(const struct bt_gatt_attr *attr, + uint16_t attr_count, + const struct bt_uuid *uuid); + +/** @brief Get Attribute handle. + * + * @param attr An attribute object currently registered in the + * local ATT server. + * + * @return Handle of the corresponding attribute or zero if the attribute + * could not be found. + */ +uint16_t bt_gatt_attr_get_handle(const struct bt_gatt_attr *attr); + +/** @brief Get the handle of the characteristic value descriptor. + * + * @param attr A Characteristic Attribute. + * + * @note The ``user_data`` of the attribute must be of type @ref bt_gatt_chrc and the ``uuid`` shall + * be BT_UUID_GATT_CHRC. + * + * @return the handle of the corresponding Characteristic Value. The value will + * be zero (the invalid handle) if @p attr was not a characteristic + * attribute. + */ +uint16_t bt_gatt_attr_value_handle(const struct bt_gatt_attr *attr); + +/** @brief Generic Read Attribute value helper. + * + * Read attribute value from local database storing the result into buffer. + * + * @param conn Connection object. + * @param attr Attribute to read. + * @param buf Buffer to store the value. + * @param buf_len Buffer length. + * @param offset Start offset. + * @param value Attribute value. + * @param value_len Length of the attribute value. + * + * @return number of bytes read in case of success or negative values in + * case of error. + */ +ssize_t bt_gatt_attr_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, + void *buf, uint16_t buf_len, uint16_t offset, + const void *value, uint16_t value_len); + +/** @brief Read Service Attribute helper. + * + * Read service attribute value from local database storing the result into + * buffer after encoding it. + * @note Only use this with attributes which ``user_data`` is a ``bt_uuid``. + * + * @param conn Connection object. + * @param attr Attribute to read. + * @param buf Buffer to store the value read. + * @param len Buffer length. + * @param offset Start offset. + * + * @return number of bytes read in case of success or negative values in + * case of error. + */ +ssize_t bt_gatt_attr_read_service(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + void *buf, uint16_t len, uint16_t offset); + +/** + * @brief Statically define and register a service. + * + * Helper macro to statically define and register a service. + * + * @param _name Service name. + */ +#define BT_GATT_SERVICE_DEFINE(_name, ...) \ + struct bt_gatt_attr attr_##_name[] = { __VA_ARGS__ }; \ + STRUCT_SECTION_ITERABLE(bt_gatt_service_static, _name) = \ + BT_GATT_SERVICE(attr_##_name) + +#define _BT_GATT_ATTRS_ARRAY_DEFINE(n, _instances, _attrs_def) \ + static struct bt_gatt_attr attrs_##n[] = _attrs_def(_instances[n]) + +#define _BT_GATT_SERVICE_ARRAY_ITEM(_n, _) BT_GATT_SERVICE(attrs_##_n) + +/** + * @brief Statically define service structure array. + * + * Helper macro to statically define service structure array. Each element + * of the array is linked to the service attribute array which is also + * defined in this scope using ``_attrs_def`` macro. + * + * @param _name Name of service structure array. + * @param _instances Array of instances to pass as user context to the + * attribute callbacks. + * @param _instance_num Number of elements in instance array. + * @param _attrs_def Macro provided by the user that defines attribute + * array for the service. This macro should accept single + * parameter which is the instance context. + */ +#define BT_GATT_SERVICE_INSTANCE_DEFINE( \ + _name, _instances, _instance_num, _attrs_def) \ + BUILD_ASSERT(ARRAY_SIZE(_instances) == _instance_num, \ + "The number of array elements does not match its size"); \ + LISTIFY(_instance_num, _BT_GATT_ATTRS_ARRAY_DEFINE, (;), \ + _instances, _attrs_def); \ + static struct bt_gatt_service _name[] = { \ + LISTIFY(_instance_num, _BT_GATT_SERVICE_ARRAY_ITEM, (,)) \ + } + +/** + * @brief Service Structure Declaration Macro. + * + * Helper macro to declare a service structure. + * + * @param _attrs Service attributes. + */ +#define BT_GATT_SERVICE(_attrs) \ +{ \ + .attrs = _attrs, \ + .attr_count = ARRAY_SIZE(_attrs), \ +} + +/** + * @brief Primary Service Declaration Macro. + * + * Helper macro to declare a primary service attribute. + * + * @param _service Service attribute value. + */ +#define BT_GATT_PRIMARY_SERVICE(_service) \ + BT_GATT_ATTRIBUTE(BT_UUID_GATT_PRIMARY, BT_GATT_PERM_READ, \ + bt_gatt_attr_read_service, NULL, (void *)_service) + +/** + * @brief Secondary Service Declaration Macro. + * + * Helper macro to declare a secondary service attribute. + * + * @note A secondary service is only intended to be included from a primary + * service or another secondary service or other higher layer specification. + * + * @param _service Service attribute value. + */ +#define BT_GATT_SECONDARY_SERVICE(_service) \ + BT_GATT_ATTRIBUTE(BT_UUID_GATT_SECONDARY, BT_GATT_PERM_READ, \ + bt_gatt_attr_read_service, NULL, (void *)_service) + +/** @brief Read Include Attribute helper. + * + * Read include service attribute value from local database storing the result + * into buffer after encoding it. + * @note Only use this with attributes which user_data is a ``bt_gatt_include``. + * The function returns EINVAL if @p attr or @p attr->user_data is NULL. + * + * @param conn Connection object. + * @param attr Attribute to read. + * @param buf Buffer to store the value read. + * @param len Buffer length. + * @param offset Start offset. + * + * @return number of bytes read in case of success or negative values in + * case of error. + */ +ssize_t bt_gatt_attr_read_included(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + void *buf, uint16_t len, uint16_t offset); + +/** + * @brief Include Service Declaration Macro. + * + * Helper macro to declare database internal include service attribute. + * + * @param _service_incl the first service attribute of service to include + */ +#define BT_GATT_INCLUDE_SERVICE(_service_incl) \ + BT_GATT_ATTRIBUTE(BT_UUID_GATT_INCLUDE, BT_GATT_PERM_READ, \ + bt_gatt_attr_read_included, NULL, _service_incl) + +/** @brief Read Characteristic Attribute helper. + * + * Read characteristic attribute value from local database storing the result + * into buffer after encoding it. + * @note Only use this with attributes which ``user_data`` is a ``bt_gatt_chrc``. + * + * @param conn Connection object. + * @param attr Attribute to read. + * @param buf Buffer to store the value read. + * @param len Buffer length. + * @param offset Start offset. + * + * @return number of bytes read in case of success or negative values in + * case of error. + */ +ssize_t bt_gatt_attr_read_chrc(struct bt_conn *conn, + const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset); + +/** @brief Gatt Characteristic Initialization Macro. + * + * Helper macro used within the @ref BT_GATT_CHARACTERISTIC macro in the GATT attribute declaration + * to set the attribute user data. + * + * @param _uuid Characteristic attribute uuid. + * @param _handle Characcteristic attribute handle at init. + * @param _props Characteristic attribute properties, + * a bitmap of ``BT_GATT_CHRC_*`` macros. + */ +#define BT_GATT_CHRC_INIT(_uuid, _handle, _props) \ +{ \ + .uuid = _uuid, \ + .value_handle = _handle, \ + .properties = _props, \ +} + +/** + * @brief Characteristic and Value Declaration Macro. + * + * Helper macro to declare a characteristic attribute along with its + * attribute value. + * + * @param _uuid Characteristic attribute uuid. + * @param _props Characteristic attribute properties, + * a bitmap of ``BT_GATT_CHRC_*`` macros. + * @param _perm Characteristic Attribute access permissions, + * a bitmap of @ref bt_gatt_perm values. + * @param _read Characteristic Attribute read callback + * (@ref bt_gatt_attr_read_func_t). + * @param _write Characteristic Attribute write callback + * (@ref bt_gatt_attr_write_func_t). + * @param _user_data Characteristic Attribute user data. + */ +#define BT_GATT_CHARACTERISTIC(_uuid, _props, _perm, _read, _write, _user_data) \ + BT_GATT_ATTRIBUTE(BT_UUID_GATT_CHRC, BT_GATT_PERM_READ, \ + bt_gatt_attr_read_chrc, NULL, \ + ((struct bt_gatt_chrc[]) { \ + BT_GATT_CHRC_INIT(_uuid, 0U, _props), \ + })), \ + BT_GATT_ATTRIBUTE(_uuid, _perm, _read, _write, _user_data) + +#define BT_GATT_CCC_MAX (1) + +/** @brief GATT CCC configuration entry. + * + * bt_gatt_ccc_cfg is used within @ref bt_gatt_attr_read_ccc and @ref bt_gatt_attr_write_ccc to + * read and write the ccc configurations respectively. + * + */ +struct bt_gatt_ccc_cfg { + /** Local identity, BT_ID_DEFAULT in most cases. */ + uint8_t id; + /** Remote peer address. */ + bt_addr_le_t peer; + /** @brief Configuration value + * Value used to enable or disable notifications or indications for a specific + * characteristic. + */ + uint16_t value; +}; + +/** Internal representation of CCC value */ +struct bt_gatt_ccc_managed_user_data { + /** Configuration for each connection */ + struct bt_gatt_ccc_cfg cfg[BT_GATT_CCC_MAX]; + + /** Highest value of all connected peer's subscriptions */ + uint16_t value; + + /** @brief CCC attribute changed callback + * + * @param attr The attribute that's changed value + * @param value New value + */ + void (*cfg_changed)(const struct bt_gatt_attr *attr, uint16_t value); + + /** @brief CCC attribute write validation callback + * + * @param conn The connection that is requesting to write + * @param attr The attribute that's being written + * @param value CCC value to write + * + * @return Number of bytes to write, or in case of an error + * BT_GATT_ERR() with a specific error code. + */ + ssize_t (*cfg_write)(struct bt_conn *conn, + const struct bt_gatt_attr *attr, uint16_t value); + + /** @brief CCC attribute match handler + * + * Indicate if it is OK to send a notification or indication + * to the subscriber. + * + * @param conn The connection that is being checked + * @param attr The attribute that's being checked + * + * @return true if application has approved notification/indication, + * false if application does not approve. + */ + bool (*cfg_match)(struct bt_conn *conn, + const struct bt_gatt_attr *attr); +}; + +/** @brief Read Client Characteristic Configuration Attribute helper. + * + * Read CCC attribute value from local database storing the result into buffer + * after encoding it. + * + * @param conn Connection object. + * @param attr Attribute to read. + * @param buf Buffer to store the value read. + * @param len Buffer length. + * @param offset Start offset. + * + * @return number of bytes read in case of success or negative values in + * case of error. + */ +/** @cond INTERNAL_HIDDEN + * @note Only use this with attributes which user_data is a bt_gatt_ccc_managed_user_data. + * @ref bt_gatt_ccc_managed_user_data being the internal representation of CCC value. + */ +/** @endcond */ +ssize_t bt_gatt_attr_read_ccc(struct bt_conn *conn, + const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset); + +/** @brief Write Client Characteristic Configuration Attribute helper. + * + * Write value in the buffer into CCC attribute. + * + * @param conn Connection object. + * @param attr Attribute to read. + * @param buf Buffer to store the value read. + * @param len Buffer length. + * @param offset Start offset. + * @param flags Write flags, see @ref bt_gatt_attr_write_flag. + * + * @return number of bytes written in case of success or negative values in + * case of error. + */ +/** @cond INTERNAL_HIDDEN + * @note Only use this with attributes which user_data is a bt_gatt_ccc_managed_user_data. + * @ref bt_gatt_ccc_managed_user_data being the internal representation of CCC value. + */ +/** @endcond */ +ssize_t bt_gatt_attr_write_ccc(struct bt_conn *conn, + const struct bt_gatt_attr *attr, const void *buf, + uint16_t len, uint16_t offset, uint8_t flags); + +/** + * @brief Initialize Client Characteristic Configuration Declaration Macro. + * + * Helper macro to initialize a Managed CCC attribute value. + * + * @param _changed Configuration changed callback. + * @param _write Configuration write callback. + * @param _match Configuration match callback. + */ +#define BT_GATT_CCC_MANAGED_USER_DATA_INIT(_changed, _write, _match) \ + { \ + .cfg = { \ + [0 ... (BT_GATT_CCC_MAX - 1)] = {0}, \ + }, \ + .cfg_changed = _changed, \ + .cfg_write = _write, \ + .cfg_match = _match, \ + } + +/** + * @brief Managed Client Characteristic Configuration Declaration Macro. + * + * Helper macro to declare a Managed CCC attribute. + * + * @param _ccc A new @ref bt_gatt_ccc_managed_user_data object with the same lifetime + * as the results of the call to BT_GATT_CCC_MANAGED. + * See the documentation of @ref bt_gatt_ccc_managed_user_data on how + * to initialize it. + * @param _perm CCC access permissions, + * a bitmap of @ref bt_gatt_perm values. + */ +#define BT_GATT_CCC_MANAGED(_ccc, _perm) \ + BT_GATT_ATTRIBUTE(BT_UUID_GATT_CCC, _perm, \ + bt_gatt_attr_read_ccc, bt_gatt_attr_write_ccc, \ + _ccc) + +/** + * @brief Client Characteristic Configuration Declaration Macro. + * + * Helper macro to declare a CCC attribute. + * + * @param _changed Configuration changed callback. + * @param _perm CCC access permissions, + * a bitmap of @ref bt_gatt_perm values. + */ +#define BT_GATT_CCC(_changed, _perm) \ + BT_GATT_CCC_MANAGED(((struct bt_gatt_ccc_managed_user_data[]){ \ + BT_GATT_CCC_MANAGED_USER_DATA_INIT(_changed, NULL, NULL)}), \ + _perm) + +/** @brief Read Characteristic Extended Properties Attribute helper + * + * Read CEP attribute value from local database storing the result into buffer + * after encoding it. + * + * @note Only use this with attributes which user_data is a bt_gatt_cep. + * + * @param conn Connection object + * @param attr Attribute to read + * @param buf Buffer to store the value read + * @param len Buffer length + * @param offset Start offset + * + * @return number of bytes read in case of success or negative values in + * case of error. + */ +ssize_t bt_gatt_attr_read_cep(struct bt_conn *conn, + const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset); + +/** + * @brief Characteristic Extended Properties Declaration Macro. + * + * Helper macro to declare a CEP attribute. + * + * @param _value Pointer to a struct bt_gatt_cep. + */ +#define BT_GATT_CEP(_value) \ + BT_GATT_DESCRIPTOR(BT_UUID_GATT_CEP, BT_GATT_PERM_READ, \ + bt_gatt_attr_read_cep, NULL, (void *)_value) + +/** @brief Read Characteristic User Description Descriptor Attribute helper + * + * Read CUD attribute value from local database storing the result into buffer + * after encoding it. + * + * @note Only use this with attributes which user_data is a NULL-terminated C + * string. + * + * @param conn Connection object + * @param attr Attribute to read + * @param buf Buffer to store the value read + * @param len Buffer length + * @param offset Start offset + * + * @return number of bytes read in case of success or negative values in + * case of error. + */ +ssize_t bt_gatt_attr_read_cud(struct bt_conn *conn, + const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset); + +/** + * @brief Characteristic User Format Descriptor Declaration Macro. + * + * Helper macro to declare a CUD attribute. + * + * @param _value User description NULL-terminated C string. + * @param _perm Descriptor attribute access permissions, + * a bitmap of @ref bt_gatt_perm values. + */ +#define BT_GATT_CUD(_value, _perm) \ + BT_GATT_DESCRIPTOR(BT_UUID_GATT_CUD, _perm, bt_gatt_attr_read_cud, \ + NULL, (void *)_value) + +/** @brief Read Characteristic Presentation format Descriptor Attribute helper + * + * Read CPF attribute value from local database storing the result into buffer + * after encoding it. + * + * @note Only use this with attributes which user_data is a @ref bt_gatt_cpf. + * + * @param conn Connection object + * @param attr Attribute to read + * @param buf Buffer to store the value read + * @param len Buffer length + * @param offset Start offset + * + * @return number of bytes read in case of success or negative values in + * case of error. + */ +ssize_t bt_gatt_attr_read_cpf(struct bt_conn *conn, + const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset); + +/** + * @brief Characteristic Presentation Format Descriptor Declaration Macro. + * + * Helper macro to declare a CPF attribute. + * + * @param _value Pointer to a struct bt_gatt_cpf. + */ +#define BT_GATT_CPF(_value) \ + BT_GATT_DESCRIPTOR(BT_UUID_GATT_CPF, BT_GATT_PERM_READ, \ + bt_gatt_attr_read_cpf, NULL, (void *)_value) + +/** + * @brief Descriptor Declaration Macro. + * + * Helper macro to declare a descriptor attribute. + * + * @param _uuid Descriptor attribute uuid. + * @param _perm Descriptor attribute access permissions, + * a bitmap of @ref bt_gatt_perm values. + * @param _read Descriptor attribute read callback + * (@ref bt_gatt_attr_read_func_t). + * @param _write Descriptor attribute write callback + * (@ref bt_gatt_attr_write_func_t). + * @param _user_data Descriptor attribute user data. + */ +#define BT_GATT_DESCRIPTOR(_uuid, _perm, _read, _write, _user_data) \ + BT_GATT_ATTRIBUTE(_uuid, _perm, _read, _write, _user_data) + +/** + * @brief Attribute Declaration Macro. + * + * Helper macro to declare an attribute. + * + * @param _uuid Attribute uuid. + * @param _perm Attribute access permissions, + * a bitmap of @ref bt_gatt_perm values. + * @param _read Attribute read callback (@ref bt_gatt_attr_read_func_t). + * @param _write Attribute write callback (@ref bt_gatt_attr_write_func_t). + * @param _user_data Attribute user data. + */ +#define BT_GATT_ATTRIBUTE(_uuid, _perm, _read, _write, _user_data) \ +{ \ + .uuid = _uuid, \ + .read = _read, \ + .write = _write, \ + .user_data = _user_data, \ + .handle = 0, \ + .perm = _perm, \ +} + +/** @brief Notification complete result callback. + * + * @param conn Connection object. + * @param user_data Data passed in by the user. + */ +typedef void (*bt_gatt_complete_func_t)(struct bt_conn *conn, void *user_data); + +/** @brief GATT notification parameters + * + * See also @ref bt_gatt_notify_cb and @ref bt_gatt_notify_multiple, using this parameter. + */ +struct bt_gatt_notify_params { + /** @brief Notification Attribute UUID type + * + * Optional, use to search for an attribute with matching UUID when + * the attribute object pointer is not known. + */ + const struct bt_uuid *uuid; + /** @brief Notification Attribute object + * + * Optional if uuid is provided, in this case it will be used as start + * range to search for the attribute with the given UUID. + */ + const struct bt_gatt_attr *attr; + /** Notification Value data */ + const void *data; + /** Notification Value length */ + uint16_t len; + /** Notification Value callback */ + bt_gatt_complete_func_t func; + /** Att channel options. */ + enum bt_att_chan_opt chan_opt; +}; + +/** @brief Notify attribute value change. + * + * This function works in the same way as @ref bt_gatt_notify. + * With the addition that after sending the notification the + * callback function will be called. + * + * The callback is run from System Workqueue context. + * When called from the System Workqueue context this API will not wait for + * resources for the callback but instead return an error. + * + * Alternatively it is possible to notify by UUID by setting it on the + * parameters, when using this method the attribute if provided is used as the + * start range when looking up for possible matches. + * + * @param conn Connection object. + * @param params Notification parameters. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_gatt_notify_cb(struct bt_conn *conn, + struct bt_gatt_notify_params *params); + +/** @brief Notify attribute value change. + * + * Send notification of attribute value change, if connection is NULL notify + * all peer that have notification enabled via CCC otherwise do a direct + * notification only the given connection. + * + * The attribute object on the parameters can be the so called Characteristic + * Declaration, which is usually declared with BT_GATT_CHARACTERISTIC followed + * by BT_GATT_CCC, or the Characteristic Value Declaration which is + * automatically created after the Characteristic Declaration when using + * BT_GATT_CHARACTERISTIC. + * + * @param conn Connection object. + * @param attr Characteristic or Characteristic Value attribute. + * @param data Pointer to Attribute data. + * @param len Attribute value length. + * + * @return 0 in case of success or negative value in case of error. + */ +static inline int bt_gatt_notify(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + const void *data, uint16_t len) +{ + struct bt_gatt_notify_params params; + + memset(¶ms, 0, sizeof(params)); + + params.attr = attr; + params.data = data; + params.len = len; + params.chan_opt = BT_ATT_CHAN_OPT_NONE; + + return bt_gatt_notify_cb(conn, ¶ms); +} + +/** @brief Notify attribute value change by UUID. + * + * Send notification of attribute value change, if connection is NULL notify + * all peer that have notification enabled via CCC otherwise do a direct + * notification only on the given connection. + * + * The attribute object is the starting point for the search of the UUID. + * + * @param conn Connection object. + * @param uuid The UUID. If the server contains multiple services with the same + * UUID, then the first occurrence, starting from the attr given, + * is used. + * @param attr Pointer to an attribute that serves as the starting point for + * the search of a match for the UUID. + * @param data Pointer to Attribute data. + * @param len Attribute value length. + * + * @return 0 in case of success or negative value in case of error. + */ +static inline int bt_gatt_notify_uuid(struct bt_conn *conn, + const struct bt_uuid *uuid, + const struct bt_gatt_attr *attr, + const void *data, uint16_t len) +{ + struct bt_gatt_notify_params params; + + memset(¶ms, 0, sizeof(params)); + + params.uuid = uuid; + params.attr = attr; + params.data = data; + params.len = len; + params.chan_opt = BT_ATT_CHAN_OPT_NONE; + + return bt_gatt_notify_cb(conn, ¶ms); +} + +/* Forward declaration of the bt_gatt_indicate_params structure */ +struct bt_gatt_indicate_params; + +/** @typedef bt_gatt_indicate_func_t + * @brief Indication complete result callback. + * + * @param conn Connection object. + * @param params Indication params object. + * @param err ATT error code + */ +typedef void (*bt_gatt_indicate_func_t)(struct bt_conn *conn, + struct bt_gatt_indicate_params *params, + uint8_t err); + +/** @brief GATT Indicate Value parameters + * + * See also @ref bt_gatt_indicate, using this parameter. + * + */ +struct bt_gatt_indicate_params { + /** @brief Indicate Attribute UUID type + * + * Optional, use to search for an attribute with matching UUID when + * the attribute object pointer is not known. + */ + const struct bt_uuid *uuid; + /** @brief Indicate Attribute object + * + * Optional if uuid is provided, in this case it will be used as start + * range to search for the attribute with the given UUID. + */ + const struct bt_gatt_attr *attr; + /** Indicate Value callback */ + bt_gatt_indicate_func_t func; + /** Indicate Value data*/ + const void *data; + /** Indicate Value length*/ + uint16_t len; + /** Att channel options. */ + enum bt_att_chan_opt chan_opt; +}; + +/** @brief Indicate attribute value change. + * + * Send an indication of attribute value change. if connection is NULL + * indicate all peer that have notification enabled via CCC otherwise do a + * direct indication only the given connection. + * + * The attribute object on the parameters can be the so called Characteristic + * Declaration, which is usually declared with BT_GATT_CHARACTERISTIC followed + * by BT_GATT_CCC, or the Characteristic Value Declaration which is + * automatically created after the Characteristic Declaration when using + * BT_GATT_CHARACTERISTIC. + * + * Alternatively it is possible to indicate by UUID by setting it on the + * parameters, when using this method the attribute if provided is used as the + * start range when looking up for possible matches. + * + * @note This procedure is asynchronous therefore the parameters need to + * remains valid while it is active. The procedure is active until + * the destroy callback is run. + * + * @param conn Connection object. + * @param params Indicate parameters. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_gatt_indicate(struct bt_conn *conn, + struct bt_gatt_indicate_params *params); + +/** @brief Check if connection have subscribed to attribute + * + * Check if the connection has subscribed to an attribute value change. + * + * The attribute object can be the so called Characteristic Declaration, + * which is usually declared with BT_GATT_CHARACTERISTIC followed + * by BT_GATT_CCC, or the Characteristic Value Declaration which is + * automatically created after the Characteristic Declaration when using + * BT_GATT_CHARACTERISTIC, or the Client Characteristic Configuration + * Descriptor (CCCD) which is created by BT_GATT_CCC. + * + * @param conn Connection object. + * @param attr Attribute object. + * @param ccc_type The subscription type, @ref BT_GATT_CCC_NOTIFY and/or + * @ref BT_GATT_CCC_INDICATE. + * + * @return true if the attribute object has been subscribed. + */ +bool bt_gatt_is_subscribed(struct bt_conn *conn, + const struct bt_gatt_attr *attr, uint16_t ccc_type); + +/** @brief Get ATT MTU for a connection + * + * Get negotiated ATT connection MTU, note that this does not equal the largest + * amount of attribute data that can be transferred within a single packet. + * + * @param conn Connection object. + * + * @return MTU in bytes + */ +uint16_t bt_gatt_get_mtu(struct bt_conn *conn); + +/** @} */ + +/** + * @defgroup bt_gatt_client GATT Client APIs + * @ingroup bt_gatt + * @{ + */ + +/** @brief GATT Exchange MTU parameters + * + * Used with @ref bt_gatt_exchange_mtu function to initiate an MTU exchange. The + * response is handled in the callback @p func, which is called upon + * completion from the 'config BT_RECV_CONTEXT' context. + * + * @p params must remain valid until the callback executes. + */ +struct bt_gatt_exchange_params { + /** Callback for MTU exchange response */ + void (*func)(struct bt_conn *conn, uint8_t err, + struct bt_gatt_exchange_params *params); +}; + +/** @brief Exchange MTU + * + * Once per connection, this client procedure can be used to set the MTU to + * the maximum possible size the buffers can hold. + * + * As the response comes in callback @p params->func, for example + * @ref bt_gatt_get_mtu can be invoked in the mtu_exchange-callback to read + * out the new negotiated ATT connection MTU. The callback is run from the + * context specified by 'config BT_RECV_CONTEXT' and @p params must remain + * valid until start of callback. + * + * @param conn Connection object. + * @param params Exchange MTU parameters. + * + * @retval 0 Successfully queued request. Will call @p params->func on + * resolution. + * + * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. + * Allow a pending request to resolve before retrying, or call this function + * from a separate thread to get blocking behavior. Queue size is controlled + * by @kconfig{CONFIG_BT_ATT_TX_COUNT}. + * + * @retval -EALREADY The MTU exchange procedure has been already performed. + */ +int bt_gatt_exchange_mtu(struct bt_conn *conn, + struct bt_gatt_exchange_params *params); + +struct bt_gatt_discover_params; + +/** @typedef bt_gatt_discover_func_t + * @brief Discover attribute callback function. + * + * @param conn Connection object. + * @param attr Attribute found, or NULL if not found. + * @param params Discovery parameters given. + * + * If discovery procedure has completed this callback will be called with + * attr set to NULL. This will not happen if procedure was stopped by returning + * BT_GATT_ITER_STOP. + * + * The attribute object as well as its UUID and value objects are temporary and + * must be copied to in order to cache its information. + * + * @note @ref bt_gatt_attr is given as an argument to @ref bt_gatt_discover function, but + * it's not a proper object of this type. @ref bt_gatt_attr.perm, and methods + * bt_gatt_attr.read() and bt_gatt_attr.write() are not available, and it's + * unsound to pass the pointer to GATT server APIs. + * Only the following fields of the attribute contains valid information: + * - uuid UUID representing the type of attribute. + * - handle Handle in the remote database. + * - user_data The value of the attribute, if the discovery type maps to an + * ATT operation that provides this information. NULL otherwise. + * See below. + * + * The effective type of @c attr->user_data is determined by @c params. Note + * that the fields @c params->type and @c params->uuid are left unchanged by + * the discovery procedure. + * + * @c params->type | @c params->uuid | Type of @c attr->user_data + * -------------------------------------|-------------------------|--------------------------- + * @ref BT_GATT_DISCOVER_PRIMARY | any | @ref bt_gatt_service_val + * @ref BT_GATT_DISCOVER_SECONDARY | any | @ref bt_gatt_service_val + * @ref BT_GATT_DISCOVER_INCLUDE | any | @ref bt_gatt_include + * @ref BT_GATT_DISCOVER_CHARACTERISTIC | any | @ref bt_gatt_chrc + * @ref BT_GATT_DISCOVER_STD_CHAR_DESC | @ref BT_UUID_GATT_CEP | @ref bt_gatt_cep + * @ref BT_GATT_DISCOVER_STD_CHAR_DESC | @ref BT_UUID_GATT_CCC | @ref bt_gatt_ccc + * @ref BT_GATT_DISCOVER_STD_CHAR_DESC | @ref BT_UUID_GATT_SCC | @ref bt_gatt_scc + * @ref BT_GATT_DISCOVER_STD_CHAR_DESC | @ref BT_UUID_GATT_CPF | @ref bt_gatt_cpf + * @ref BT_GATT_DISCOVER_DESCRIPTOR | any | NULL + * @ref BT_GATT_DISCOVER_ATTRIBUTE | any | NULL + * + * Also consider if using read-by-type instead of discovery is more convenient. + * See @ref bt_gatt_read with @ref bt_gatt_read_params.handle_count set to + * @c 0. + * + * @return BT_GATT_ITER_CONTINUE to continue discovery procedure. + * @return BT_GATT_ITER_STOP to stop discovery procedure. + */ +typedef uint8_t (*bt_gatt_discover_func_t)(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params); + +/** GATT Discover types */ +enum bt_gatt_discover_type { + /** Discover Primary Services. */ + BT_GATT_DISCOVER_PRIMARY, + /** Discover Secondary Services. */ + BT_GATT_DISCOVER_SECONDARY, + /** Discover Included Services. */ + BT_GATT_DISCOVER_INCLUDE, + /** @brief Discover Characteristic Values. + * + * Discover Characteristic Value and its properties. + */ + BT_GATT_DISCOVER_CHARACTERISTIC, + /** @brief Discover Descriptors. + * + * Discover Attributes which are not services or characteristics. + * + * @note The use of this type of discover is not recommended for + * discovering in ranges across multiple services/characteristics + * as it may incur in extra round trips. + */ + BT_GATT_DISCOVER_DESCRIPTOR, + /** @brief Discover Attributes. + * + * Discover Attributes of any type. + * + * @note The use of this type of discover is not recommended for + * discovering in ranges across multiple services/characteristics + * as it may incur in more round trips. + */ + BT_GATT_DISCOVER_ATTRIBUTE, + /** @brief Discover standard characteristic descriptor values. + * + * Discover standard characteristic descriptor values and their + * properties. + * Supported descriptors: + * - Characteristic Extended Properties + * - Client Characteristic Configuration + * - Server Characteristic Configuration + * - Characteristic Presentation Format + */ + BT_GATT_DISCOVER_STD_CHAR_DESC, +}; + +/** Handle value to denote that the CCC will be automatically discovered */ +#define BT_GATT_AUTO_DISCOVER_CCC_HANDLE 0x0000U + +/** @brief GATT Discover Attributes parameters */ +struct bt_gatt_discover_params { + /** Discover UUID type */ + const struct bt_uuid *uuid; + /** Discover attribute callback */ + bt_gatt_discover_func_t func; + union { + /** See @ref bt_gatt_include for more on included services. */ + struct { + /** Include service attribute declaration handle */ + uint16_t attr_handle; + /** Starting attribute handle for included service */ + uint16_t start_handle; + /** Ending attribute handle for included service */ + uint16_t end_handle; + } _included; + /** Starting attribute handle to begin discovery */ + uint16_t start_handle; + }; + /** @brief Ending attribute handle to stop discovery at + * + * @note When discovery begins this can be set to + * @ref BT_ATT_LAST_ATTRIBUTE_HANDLE to discover all attributes + * in the service. + */ + uint16_t end_handle; + /** Discover type */ + uint8_t type; + /** Only for stack-internal use, used for automatic discovery. */ + struct bt_gatt_subscribe_params *sub_params; + /** Att channel options. */ + enum bt_att_chan_opt chan_opt; +}; + +/** @brief GATT Discover function + * + * This procedure is used by a client to discover attributes on a server. + * + * Primary Service Discovery: Procedure allows to discover primary services + * either by Discover All Primary Services or + * Discover Primary Services by Service UUID. + * Include Service Discovery: Procedure allows to discover all Include Services + * within specified range. + * Characteristic Discovery: Procedure allows to discover all characteristics + * within specified handle range as well as + * discover characteristics with specified UUID. + * Descriptors Discovery: Procedure allows to discover all characteristic + * descriptors within specified range. + * + * For each attribute found the callback is called which can then decide + * whether to continue discovering or stop. + * + * The Response comes in callback @p params->func. The callback is run from + * the BT RX thread. @p params must remain valid until start of callback where + * iter `attr` is `NULL` or callback will return `BT_GATT_ITER_STOP`. + * + * @param conn Connection object. + * @param params Discover parameters. + * + * @retval 0 Successfully queued request. Will call @p params->func on + * resolution. + * + * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. + * Allow a pending request to resolve before retrying, or call this function + * from a separate thread to get blocking behavior. Queue size is controlled + * by @kconfig{CONFIG_BT_ATT_TX_COUNT}. + */ +int bt_gatt_discover(struct bt_conn *conn, + struct bt_gatt_discover_params *params); + +struct bt_gatt_read_params; + +/** @typedef bt_gatt_read_func_t + * @brief Read callback function + * + * When reading using by_uuid, `params->start_handle` is the attribute handle + * for this `data` item. + * + * If the received data length is invalid, the callback will called with the + * error @ref BT_ATT_ERR_INVALID_PDU. + * + * @param conn Connection object. + * @param err ATT error code. + * @param params Read parameters used. + * @param data Attribute value data. NULL means read has completed. + * @param length Attribute value length. + * + * @return BT_GATT_ITER_CONTINUE if should continue to the next attribute. + * @return BT_GATT_ITER_STOP to stop. + */ +typedef uint8_t (*bt_gatt_read_func_t)(struct bt_conn *conn, uint8_t err, + struct bt_gatt_read_params *params, + const void *data, uint16_t length); + +/** @brief GATT Read parameters */ +struct bt_gatt_read_params { + /** Read attribute callback. */ + bt_gatt_read_func_t func; + /** If equals to 1 single.handle and single.offset are used. + * If greater than 1 multiple.handles are used. + * If equals to 0 by_uuid is used for Read Using Characteristic UUID. + */ + size_t handle_count; + union { + struct { + /** Attribute handle. */ + uint16_t handle; + /** Attribute data offset. */ + uint16_t offset; + } single; + struct { + /** Attribute handles to read with Read Multiple + * Characteristic Values. + */ + uint16_t *handles; + /** If true use Read Multiple Variable Length + * Characteristic Values procedure. + * The values of the set of attributes may be of + * variable or unknown length. + * If false use Read Multiple Characteristic Values + * procedure. + * The values of the set of attributes must be of a + * known fixed length, with the exception of the last + * value that can have a variable length. + */ + bool variable; + } multiple; + struct { + /** @brief Requested start attribute handle number. + * + * @details The starting handle is set to the starting point of the range + * over which this read should be performed. For example, this could be + * set to @ref BT_ATT_FIRST_ATTRIBUTE_HANDLE to set the starting point of + * the range at the beginning of the GATT database, or to the starting + * handle of a service after discovery. + * + * This value is automatically incremented by the stack after + * processing each matching handle-value pair returned by the server. + */ + uint16_t start_handle; + /** @brief Requested end attribute handle number. + * + * @details The end handle is set to the ending point of the range over + * which this read should be performed. For example, this could be set to + * @ref BT_ATT_LAST_ATTRIBUTE_HANDLE to set the ending point of the range + * at the end of the GATT database, or to the end handle for service after + * discovery, where the end_handle is available in the + * @ref bt_gatt_service_val. + */ + uint16_t end_handle; + /** 2 or 16 octet UUID. */ + const struct bt_uuid *uuid; + } by_uuid; + }; + /** Att channel options. */ + enum bt_att_chan_opt chan_opt; +}; + +/** @brief Read Attribute Value by handle + * + * This procedure reads the attribute value and returns it to the callback. + * + * When reading attributes by UUID the callback can be called multiple times + * depending on how many instances of a given UUID exists with the start_handle + * being updated for each instance. + * + * To perform a GATT Long Read procedure, start with a Characteristic Value + * Read (by setting @c offset @c 0 and @c handle_count @c 1) and then return + * @ref BT_GATT_ITER_CONTINUE from the callback. This is equivalent to calling + * @ref bt_gatt_read again, but with the correct offset to continue the read. + * This may be repeated until the procedure is complete, which is signaled by + * the callback being called with @p data set to @c NULL. + * + * Note that returning @ref BT_GATT_ITER_CONTINUE is really starting a new ATT + * operation, so this can fail to allocate resources. However, all API errors + * are reported as if the server returned @ref BT_ATT_ERR_UNLIKELY. There is no + * way to distinguish between this condition and a @ref BT_ATT_ERR_UNLIKELY + * response from the server itself. + * + * Note that the effect of returning @ref BT_GATT_ITER_CONTINUE from the + * callback varies depending on the type of read operation. + * + * The Response comes in callback @p params->func. The callback is run from + * the context specified by 'config BT_RECV_CONTEXT'. + * @p params must remain valid until start of callback. + * If the received data length is invalid, the callback @p params->func will + * called with the error @ref BT_ATT_ERR_INVALID_PDU. + * + * @param conn Connection object. + * @param params Read parameters. + * + * @retval 0 Successfully queued request. Will call @p params->func on + * resolution. + * + * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. + * Allow a pending request to resolve before retrying, or call this function + * from a separate thread to get blocking behavior. Queue size is controlled + * by @kconfig{CONFIG_BT_ATT_TX_COUNT}. + */ +int bt_gatt_read(struct bt_conn *conn, struct bt_gatt_read_params *params); + +struct bt_gatt_write_params; + +/** @typedef bt_gatt_write_func_t + * @brief Write callback function + * + * @param conn Connection object. + * @param err ATT error code. + * @param params Write parameters used. + */ +typedef void (*bt_gatt_write_func_t)(struct bt_conn *conn, uint8_t err, + struct bt_gatt_write_params *params); + +/** @brief GATT Write parameters */ +struct bt_gatt_write_params { + /** Response callback */ + bt_gatt_write_func_t func; + /** Attribute handle */ + uint16_t handle; + /** Attribute data offset */ + uint16_t offset; + /** Data to be written */ + const void *data; + /** Length of the data */ + uint16_t length; + /** Att channel options. */ + enum bt_att_chan_opt chan_opt; +}; + +/** @brief Write Attribute Value by handle + * + * The Response comes in callback @p params->func. The callback is run from + * the context specified by 'config BT_RECV_CONTEXT'. + * @p params must remain valid until start of callback. + * + * @param conn Connection object. + * @param params Write parameters. + * + * @retval 0 Successfully queued request. Will call @p params->func on + * resolution. + * + * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. + * Allow a pending request to resolve before retrying, or call this function + * from a separate thread to get blocking behavior. Queue size is controlled + * by @kconfig{CONFIG_BT_ATT_TX_COUNT}. + */ +int bt_gatt_write(struct bt_conn *conn, struct bt_gatt_write_params *params); + +/** @brief Write Attribute Value by handle without response with callback. + * + * This function works in the same way as @ref bt_gatt_write_without_response. + * With the addition that after sending the write the callback function will be + * called. + * + * The callback is run from System Workqueue context. + * When called from the System Workqueue context this API will not wait for + * resources for the callback but instead return an error. + * + * @param conn Connection object. + * @param handle Attribute handle. + * @param data Data to be written. + * @param length Data length. + * @param sign Whether to sign data. + * @param func Transmission complete callback. + * @param user_data User data to be passed back to callback. + * + * @retval 0 Successfully queued request. + * + * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. + * Allow a pending request to resolve before retrying, or call this function + * from a separate thread to get blocking behavior. Queue size is controlled + * by @kconfig{CONFIG_BT_ATT_TX_COUNT}. + */ +int bt_gatt_write_without_response_cb(struct bt_conn *conn, uint16_t handle, + const void *data, uint16_t length, + bool sign, bt_gatt_complete_func_t func, + void *user_data); + +/** @brief Write Attribute Value by handle without response + * + * This procedure write the attribute value without requiring an + * acknowledgment that the write was successfully performed + * + * @param conn Connection object. + * @param handle Attribute handle. + * @param data Data to be written. + * @param length Data length. + * @param sign Whether to sign data. + * + * @retval 0 Successfully queued request. + * + * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. + * Allow a pending request to resolve before retrying, or call this function + * from a separate thread to get blocking behavior. Queue size is controlled + * by @kconfig{CONFIG_BT_ATT_TX_COUNT}. + */ +static inline int bt_gatt_write_without_response(struct bt_conn *conn, + uint16_t handle, const void *data, + uint16_t length, bool sign) +{ + return bt_gatt_write_without_response_cb(conn, handle, data, length, + sign, NULL, NULL); +} + +struct bt_gatt_subscribe_params; + +/** @typedef bt_gatt_notify_func_t + * @brief Notification callback function + * + * In the case of an empty notification, the @p data pointer will be non-NULL + * while the @p length will be 0, which is due to the special case where + * a @p data NULL pointer means unsubscribed. + * + * @param conn Connection object. May be NULL, indicating that the peer is + * being unpaired + * @param params Subscription parameters. + * @param data Attribute value data. If NULL then subscription was removed. + * @param length Attribute value length. + * + * @return BT_GATT_ITER_CONTINUE to continue receiving value notifications. + * BT_GATT_ITER_STOP to unsubscribe from value notifications. + */ +typedef uint8_t (*bt_gatt_notify_func_t)(struct bt_conn *conn, + struct bt_gatt_subscribe_params *params, + const void *data, uint16_t length); + +/** @typedef bt_gatt_subscribe_func_t + * @brief Subscription callback function + * + * @param conn Connection object. + * @param err ATT error code. + * @param params Subscription parameters used. + */ +typedef void (*bt_gatt_subscribe_func_t)(struct bt_conn *conn, uint8_t err, + struct bt_gatt_subscribe_params *params); + +/** Subscription flags */ +enum bt_gatt_sub_flag { + /** @brief Persistence flag + * + * If set, indicates that the subscription is not saved + * on the GATT server side. Therefore, upon disconnection, + * the subscription will be automatically removed + * from the client's subscriptions list and + * when the client reconnects, it will have to + * issue a new subscription. + */ + BT_GATT_SUBSCRIBE_FLAG_VOLATILE, + + /** @brief No resubscribe flag + * + * By default when BT_GATT_SUBSCRIBE_FLAG_VOLATILE is unset, the + * subscription will be automatically renewed when the client + * reconnects, as a workaround for GATT servers that do not persist + * subscriptions. + * + * This flag will disable the automatic resubscription. It is useful + * if the application layer knows that the GATT server remembers + * subscriptions from previous connections and wants to avoid renewing + * the subscriptions. + */ + BT_GATT_SUBSCRIBE_FLAG_NO_RESUB, + + /** @brief Write pending flag + * + * If set, indicates write operation is pending waiting remote end to + * respond. + * + * @note Internal use only. + */ + BT_GATT_SUBSCRIBE_FLAG_WRITE_PENDING, + + /** @brief Sent flag + * + * If set, indicates that a subscription request (CCC write) has + * already been sent in the active connection. + * + * Used to avoid sending subscription requests multiple times when the + * @kconfig{CONFIG_BT_GATT_AUTO_RESUBSCRIBE} quirk is enabled. + * + * @note Internal use only. + */ + BT_GATT_SUBSCRIBE_FLAG_SENT, + + BT_GATT_SUBSCRIBE_NUM_FLAGS +}; + +/** @brief GATT Subscribe parameters */ +struct bt_gatt_subscribe_params { + /** Notification value callback */ + bt_gatt_notify_func_t notify; + /** Subscribe CCC write request response callback + * If given, called with the subscription parameters given when subscribing + */ + bt_gatt_subscribe_func_t subscribe; + + /** Subscribe value handle */ + uint16_t value_handle; + /** Subscribe CCC handle */ + uint16_t ccc_handle; + /** Subscribe End handle (for automatic discovery) */ + uint16_t end_handle; + /** Discover parameters used when ccc_handle = @ref BT_GATT_AUTO_DISCOVER_CCC_HANDLE */ + struct bt_gatt_discover_params *disc_params; + /** Subscribe value */ + uint16_t value; + /** Subscription flags, see @ref bt_gatt_sub_flag */ + ATOMIC_DEFINE(flags, BT_GATT_SUBSCRIBE_NUM_FLAGS); + + sys_snode_t node; + /** Att channel options. */ + enum bt_att_chan_opt chan_opt; +}; + +/** @brief Subscribe Attribute Value Notification + * + * This procedure subscribe to value notification using the Client + * Characteristic Configuration handle. + * If notification received subscribe value callback is called to return + * notified value. One may then decide whether to unsubscribe directly from + * this callback. Notification callback with NULL data will not be called if + * subscription was removed by this method. + * + * The Response comes in callback @p params->subscribe. The callback is run from + * the context specified by 'config BT_RECV_CONTEXT'. + * The Notification callback @p params->notify is also called from the BT RX + * thread. + * + * @note Notifications are asynchronous therefore the @p params must remain + * valid while subscribed and cannot be reused for additional subscriptions + * whilst active. + * + * @param conn Connection object. + * @param params Subscribe parameters. + * + * @retval 0 Successfully queued request. Will call @p params->write on + * resolution. + * + * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. + * Allow a pending request to resolve before retrying, or call this function + * from a separate thread to get blocking behavior. Queue size is controlled + * by @kconfig{CONFIG_BT_ATT_TX_COUNT}. + * + * @retval -EALREADY if there already exist a subscription using the @p params. + * + * @retval -EBUSY if @p params.ccc_handle is 0 and @kconfig{CONFIG_BT_GATT_AUTO_DISCOVER_CCC} is + * enabled and discovery for the @p params is already in progress. + */ +int bt_gatt_subscribe(struct bt_conn *conn, + struct bt_gatt_subscribe_params *params); + +/** @brief Unsubscribe Attribute Value Notification + * + * This procedure unsubscribe to value notification using the Client + * Characteristic Configuration handle. Notification callback with NULL data + * will be called if subscription was removed by this call, until then the + * parameters cannot be reused. + * + * The Response comes in callback @p params->func. The callback is run from + * the BT RX thread. + * + * @param conn Connection object. + * @param params Subscribe parameters. The parameters shall be a @ref bt_gatt_subscribe_params from + * a previous call to bt_gatt_subscribe(). + * + * @retval 0 Successfully queued request. Will call @p params->write on + * resolution. + * + * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. + * Allow a pending request to resolve before retrying, or call this function + * from a separate thread to get blocking behavior. Queue size is controlled + * by @kconfig{CONFIG_BT_ATT_TX_COUNT}. + */ +int bt_gatt_unsubscribe(struct bt_conn *conn, + struct bt_gatt_subscribe_params *params); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_GATT_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/hci.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/hci.h new file mode 100644 index 0000000000..4502b3d008 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/hci.h @@ -0,0 +1,92 @@ +/* hci.h - Bluetooth Host Control Interface definitions */ + +/* + * SPDX-FileCopyrightText: 2015-2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_HCI_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_HCI_H_ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Converts a HCI error to string. + * + * The error codes are described in the Bluetooth Core specification, + * Vol 1, Part F, Section 2. + * + * The HCI documentation found in Vol 4, Part E, + * describes when the different error codes are used. + * + * See also the defined BT_HCI_ERR_* macros. + * + * @return The string representation of the HCI error code. + * If @kconfig{CONFIG_BT_HCI_ERR_TO_STR} is not enabled, + * this just returns the empty string + */ +static inline const char *bt_hci_err_to_str(uint8_t hci_err) +{ + ARG_UNUSED(hci_err); + + return ""; +} + +/** Allocate a HCI command buffer. + * + * This function allocates a new buffer for a HCI command. It is given + * the OpCode (encoded e.g. using the BT_OP macro) and the total length + * of the parameters. Upon successful return the buffer is ready to have + * the parameters encoded into it. + * + * @deprecated Use bt_hci_cmd_alloc() instead. + * + * @param opcode Command OpCode. + * @param param_len Length of command parameters. + * + * @return Newly allocated buffer. + */ +struct net_buf *bt_hci_cmd_create(uint16_t opcode, uint8_t param_len); + +/** Send a HCI command synchronously. + * + * This function is used for sending a HCI command synchronously. It can + * either be called for a buffer created using bt_hci_cmd_create(), or + * if the command has no parameters a NULL can be passed instead. + * + * The function will block until a Command Status or a Command Complete + * event is returned. If either of these have a non-zero status the function + * will return a negative error code and the response reference will not + * be set. If the command completed successfully and a non-NULL rsp parameter + * was given, this parameter will be set to point to a buffer containing + * the response parameters. + * + * @param opcode Command OpCode. + * @param buf Command buffer or NULL (if no parameters). + * @param rsp Place to store a reference to the command response. May + * be NULL if the caller is not interested in the response + * parameters. If non-NULL is passed the caller is responsible + * for calling net_buf_unref() on the buffer when done parsing + * it. + * + * @return 0 on success or negative error value on failure. + */ +int bt_hci_cmd_send_sync(uint16_t opcode, struct net_buf *buf, + struct net_buf **rsp); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_HCI_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/hci_types.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/hci_types.h new file mode 100644 index 0000000000..1e30fd5c8a --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/hci_types.h @@ -0,0 +1,4052 @@ +/* hci.h - Bluetooth Host Control Interface types */ + +/* + * SPDX-FileCopyrightText: 2015-2016 Intel Corporation + * SPDX-FileCopyrightText: 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_HCI_TYPES_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_HCI_TYPES_H_ + +#include +#include +#include + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Bluetooth spec v5.4 Vol 4, Part A Table 2.1: HCI packet indicators + * The following definitions are intended for use with the UART Transport Layer and + * may be reused with other transport layers if desired. + */ +#define BT_HCI_H4_NONE 0x00 /* None of the known packet types */ +#define BT_HCI_H4_CMD 0x01 /* HCI Command packet */ +#define BT_HCI_H4_ACL 0x02 /* HCI ACL Data packet */ +#define BT_HCI_H4_SCO 0x03 /* HCI Synchronous Data packet */ +#define BT_HCI_H4_EVT 0x04 /* HCI Event packet */ +#define BT_HCI_H4_ISO 0x05 /* HCI ISO Data packet */ + +#define BT_HCI_OWN_ADDR_PUBLIC 0x00 +#define BT_HCI_OWN_ADDR_RANDOM 0x01 +#define BT_HCI_OWN_ADDR_RPA_OR_PUBLIC 0x02 +#define BT_HCI_OWN_ADDR_RPA_OR_RANDOM 0x03 +#define BT_HCI_OWN_ADDR_RPA_MASK 0x02 + +#define BT_HCI_PEER_ADDR_RPA_UNRESOLVED 0xfe +#define BT_HCI_PEER_ADDR_ANONYMOUS 0xff + +#define BT_ENC_KEY_SIZE_MIN 0x07 +#define BT_ENC_KEY_SIZE_MAX 0x10 + +#define BT_HCI_ADV_HANDLE_INVALID 0xff +#define BT_HCI_SYNC_HANDLE_INVALID 0xffff +#define BT_HCI_PAWR_SUBEVENT_MAX 128 + +/* Bluetooth spec v5.4 Vol 4, Part E - 5.4.3 HCI Synchronous Data Packets */ +struct bt_hci_sco_hdr { + uint16_t handle; /* 12 bit handle, 2 bit Packet Status Flag, 1 bit RFU */ + uint8_t len; +} __packed; +#define BT_HCI_SCO_HDR_SIZE 3 + +/* Bluetooth spec v5.4 Vol 4, Part E - 5.4.4 HCI Event Packet */ +struct bt_hci_evt_hdr { + uint8_t evt; + uint8_t len; +} __packed; +#define BT_HCI_EVT_HDR_SIZE 2 + +#define BT_ACL_START_NO_FLUSH 0x00 +#define BT_ACL_CONT 0x01 +#define BT_ACL_START 0x02 +#define BT_ACL_COMPLETE 0x03 + +#define BT_ACL_POINT_TO_POINT 0x00 +#define BT_ACL_BROADCAST 0x01 + +#define BT_ACL_HANDLE_MASK BIT_MASK(12) + +#define bt_acl_handle(h) ((h) & BT_ACL_HANDLE_MASK) +#define bt_acl_flags(h) ((h) >> 12) +#define bt_acl_flags_pb(f) ((f) & BIT_MASK(2)) +#define bt_acl_flags_bc(f) ((f) >> 2) +#define bt_acl_handle_pack(h, f) ((h) | ((f) << 12)) + +/* Bluetooth spec v5.4 Vol 4, Part E - 5.4.2 ACL Data Packets */ +struct bt_hci_acl_hdr { + uint16_t handle; + uint16_t len; +} __packed; +#define BT_HCI_ACL_HDR_SIZE 4 + +#define BT_ISO_START 0x00 +#define BT_ISO_CONT 0x01 +#define BT_ISO_SINGLE 0x02 +#define BT_ISO_END 0x03 + +#define bt_iso_handle(h) ((h) & 0x0fff) +#define bt_iso_flags(h) ((h) >> 12) +#define bt_iso_flags_pb(f) ((f) & 0x0003) +#define bt_iso_flags_ts(f) (((f) >> 2) & 0x0001) +#define bt_iso_pack_flags(pb, ts) \ + (((pb) & 0x0003) | (((ts) & 0x0001) << 2)) +#define bt_iso_handle_pack(h, pb, ts) \ + ((h) | (bt_iso_pack_flags(pb, ts) << 12)) +#define bt_iso_hdr_len(h) ((h) & BIT_MASK(14)) + +#define BT_ISO_DATA_VALID 0x00 +#define BT_ISO_DATA_INVALID 0x01 +#define BT_ISO_DATA_NOP 0x02 + +#define bt_iso_pkt_len(h) ((h) & BIT_MASK(12)) +#define bt_iso_pkt_flags(h) ((h) >> 14) +#define bt_iso_pkt_len_pack(h, f) (((h) & BIT_MASK(12)) | ((f) << 14)) + +struct bt_hci_iso_sdu_hdr { + uint16_t sn; + uint16_t slen; /* 12 bit len, 2 bit RFU, 2 bit packet status */ +} __packed; +#define BT_HCI_ISO_SDU_HDR_SIZE 4 + +struct bt_hci_iso_sdu_ts_hdr { + uint32_t ts; + struct bt_hci_iso_sdu_hdr sdu; +} __packed; +#define BT_HCI_ISO_SDU_TS_HDR_SIZE 8 + +/* Bluetooth spec v5.4 Vol 4, Part E - 5.4.5 HCI ISO Data Packets */ +struct bt_hci_iso_hdr { + uint16_t handle; /* 12 bit handle, 2 bit PB flags, 1 bit TS_Flag, 1 bit RFU */ + uint16_t len; /* 14 bits, 2 bits RFU */ +} __packed; +#define BT_HCI_ISO_HDR_SIZE 4 + +/* Bluetooth spec v5.4 Vol 4, Part E - 5.4.1 HCI Command Packet */ +struct bt_hci_cmd_hdr { + uint16_t opcode; + uint8_t param_len; +} __packed; +#define BT_HCI_CMD_HDR_SIZE 3 + +/* Supported Commands */ +#define BT_CMD_TEST(cmd, octet, bit) (cmd[octet] & BIT(bit)) +#define BT_CMD_LE_STATES(cmd) BT_CMD_TEST(cmd, 28, 3) + +#define BT_FEAT_TEST(feat, page, octet, bit) (feat[page][octet] & BIT(bit)) + +#define BT_FEAT_BREDR(feat) !BT_FEAT_TEST(feat, 0, 4, 5) +#define BT_FEAT_LE(feat) BT_FEAT_TEST(feat, 0, 4, 6) +#define BT_FEAT_EXT_FEATURES(feat) BT_FEAT_TEST(feat, 0, 7, 7) +#define BT_FEAT_HOST_SSP(feat) BT_FEAT_TEST(feat, 1, 0, 0) +#define BT_FEAT_SC(feat) BT_FEAT_TEST(feat, 2, 1, 0) + +#define BT_FEAT_LMP_SCO_CAPABLE(feat) BT_FEAT_TEST(feat, 0, 1, 3) +#define BT_FEAT_LMP_ESCO_CAPABLE(feat) BT_FEAT_TEST(feat, 0, 3, 7) +#define BT_FEAT_HV2_PKT(feat) BT_FEAT_TEST(feat, 0, 1, 4) +#define BT_FEAT_HV3_PKT(feat) BT_FEAT_TEST(feat, 0, 1, 5) +#define BT_FEAT_EV4_PKT(feat) BT_FEAT_TEST(feat, 0, 4, 0) +#define BT_FEAT_EV5_PKT(feat) BT_FEAT_TEST(feat, 0, 4, 1) +#define BT_FEAT_2EV3_PKT(feat) BT_FEAT_TEST(feat, 0, 5, 5) +#define BT_FEAT_3EV3_PKT(feat) BT_FEAT_TEST(feat, 0, 5, 6) +#define BT_FEAT_3SLOT_PKT(feat) BT_FEAT_TEST(feat, 0, 5, 7) + +/* LE features */ +#define BT_LE_FEAT_BIT_ENC 0 +#define BT_LE_FEAT_BIT_CONN_PARAM_REQ 1 +#define BT_LE_FEAT_BIT_EXT_REJ_IND 2 +#define BT_LE_FEAT_BIT_PER_INIT_FEAT_XCHG 3 +#define BT_LE_FEAT_BIT_PING 4 +#define BT_LE_FEAT_BIT_DLE 5 +#define BT_LE_FEAT_BIT_PRIVACY 6 +#define BT_LE_FEAT_BIT_EXT_SCAN 7 +#define BT_LE_FEAT_BIT_PHY_2M 8 +#define BT_LE_FEAT_BIT_SMI_TX 9 +#define BT_LE_FEAT_BIT_SMI_RX 10 +#define BT_LE_FEAT_BIT_PHY_CODED 11 +#define BT_LE_FEAT_BIT_EXT_ADV 12 +#define BT_LE_FEAT_BIT_PER_ADV 13 +#define BT_LE_FEAT_BIT_CHAN_SEL_ALGO_2 14 +#define BT_LE_FEAT_BIT_PWR_CLASS_1 15 +#define BT_LE_FEAT_BIT_MIN_USED_CHAN_PROC 16 +#define BT_LE_FEAT_BIT_CONN_CTE_REQ 17 +#define BT_LE_FEAT_BIT_CONN_CTE_RESP 18 +#define BT_LE_FEAT_BIT_CONNECTIONLESS_CTE_TX 19 +#define BT_LE_FEAT_BIT_CONNECTIONLESS_CTE_RX 20 +#define BT_LE_FEAT_BIT_ANT_SWITCH_TX_AOD 21 +#define BT_LE_FEAT_BIT_ANT_SWITCH_RX_AOA 22 +#define BT_LE_FEAT_BIT_RX_CTE 23 +#define BT_LE_FEAT_BIT_PAST_SEND 24 +#define BT_LE_FEAT_BIT_PAST_RECV 25 +#define BT_LE_FEAT_BIT_SCA_UPDATE 26 +#define BT_LE_FEAT_BIT_REMOTE_PUB_KEY_VALIDATE 27 +#define BT_LE_FEAT_BIT_CIS_CENTRAL 28 +#define BT_LE_FEAT_BIT_CIS_PERIPHERAL 29 +#define BT_LE_FEAT_BIT_ISO_BROADCASTER 30 +#define BT_LE_FEAT_BIT_SYNC_RECEIVER 31 +#define BT_LE_FEAT_BIT_ISO_CHANNELS 32 +#define BT_LE_FEAT_BIT_PWR_CTRL_REQ 33 +#define BT_LE_FEAT_BIT_PWR_CHG_IND 34 +#define BT_LE_FEAT_BIT_PATH_LOSS_MONITOR 35 +#define BT_LE_FEAT_BIT_PER_ADV_ADI_SUPP 36 +#define BT_LE_FEAT_BIT_CONN_SUBRATING 37 +#define BT_LE_FEAT_BIT_CONN_SUBRATING_HOST_SUPP 38 +#define BT_LE_FEAT_BIT_CHANNEL_CLASSIFICATION 39 + +#define BT_LE_FEAT_BIT_PAWR_ADVERTISER 43 +#define BT_LE_FEAT_BIT_PAWR_SCANNER 44 + +#define BT_LE_FEAT_BIT_CHANNEL_SOUNDING 46 +#define BT_LE_FEAT_BIT_CHANNEL_SOUNDING_HOST 47 + +#define BT_LE_FEAT_TEST(feat, n) (feat[(n) >> 3] & \ + BIT((n) & 7)) + +#define BT_FEAT_LE_ENCR(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_ENC) +#define BT_FEAT_LE_CONN_PARAM_REQ_PROC(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CONN_PARAM_REQ) +#define BT_FEAT_LE_PER_INIT_FEAT_XCHG(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PER_INIT_FEAT_XCHG) +#define BT_FEAT_LE_DLE(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_DLE) +#define BT_FEAT_LE_PHY_2M(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PHY_2M) +#define BT_FEAT_LE_PHY_CODED(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PHY_CODED) +#define BT_FEAT_LE_PRIVACY(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PRIVACY) +#define BT_FEAT_LE_EXT_ADV(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_EXT_ADV) +#define BT_FEAT_LE_EXT_PER_ADV(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PER_ADV) +#define BT_FEAT_LE_CONNECTION_CTE_REQ(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CONN_CTE_REQ) +#define BT_FEAT_LE_CONNECTION_CTE_RESP(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CONN_CTE_RESP) +#define BT_FEAT_LE_CONNECTIONLESS_CTE_TX(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CONNECTIONLESS_CTE_TX) +#define BT_FEAT_LE_CONNECTIONLESS_CTE_RX(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CONNECTIONLESS_CTE_RX) +#define BT_FEAT_LE_ANT_SWITCH_TX_AOD(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_ANT_SWITCH_TX_AOD) +#define BT_FEAT_LE_ANT_SWITCH_RX_AOA(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_ANT_SWITCH_RX_AOA) +#define BT_FEAT_LE_RX_CTE(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_RX_CTE) +#define BT_FEAT_LE_PAST_SEND(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PAST_SEND) +#define BT_FEAT_LE_PAST_RECV(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PAST_RECV) +#define BT_FEAT_LE_CIS_CENTRAL(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CIS_CENTRAL) +#define BT_FEAT_LE_CIS_PERIPHERAL(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CIS_PERIPHERAL) +#define BT_FEAT_LE_ISO_BROADCASTER(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_ISO_BROADCASTER) +#define BT_FEAT_LE_SYNC_RECEIVER(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_SYNC_RECEIVER) +#define BT_FEAT_LE_ISO_CHANNELS(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_ISO_CHANNELS) +#define BT_FEAT_LE_PWR_CTRL_REQ(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PWR_CTRL_REQ) +#define BT_FEAT_LE_PWR_CHG_IND(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PWR_CHG_IND) +#define BT_FEAT_LE_PATH_LOSS_MONITOR(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PATH_LOSS_MONITOR) +#define BT_FEAT_LE_PER_ADV_ADI_SUPP(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PER_ADV_ADI_SUPP) +#define BT_FEAT_LE_CONN_SUBRATING(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CONN_SUBRATING) +#define BT_FEAT_LE_CONN_SUBRATING_HOST_SUPP(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CONN_SUBRATING_HOST_SUPP) +#define BT_FEAT_LE_CHANNEL_CLASSIFICATION(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CHANNEL_CLASSIFICATION) +#define BT_FEAT_LE_PAWR_ADVERTISER(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PAWR_ADVERTISER) +#define BT_FEAT_LE_PAWR_SCANNER(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PAWR_SCANNER) +#define BT_FEAT_LE_CHANNEL_SOUNDING(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CHANNEL_SOUNDING) +#define BT_FEAT_LE_CHANNEL_SOUNDING_HOST(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CHANNEL_SOUNDING_HOST) + +#define BT_FEAT_LE_CIS(feat) (BT_FEAT_LE_CIS_CENTRAL(feat) | \ + BT_FEAT_LE_CIS_PERIPHERAL(feat)) +#define BT_FEAT_LE_BIS(feat) (BT_FEAT_LE_ISO_BROADCASTER(feat) | \ + BT_FEAT_LE_SYNC_RECEIVER(feat)) +#define BT_FEAT_LE_ISO(feat) (BT_FEAT_LE_CIS(feat) | \ + BT_FEAT_LE_BIS(feat)) + +/* LE States. See Core_v5.4, Vol 4, Part E, Section 7.8.27 */ +#define BT_LE_STATES_PER_CONN_ADV(states) (states & BIT64_MASK(38)) + +#if defined(CONFIG_BT_SCAN_AND_INITIATE_IN_PARALLEL) +/* Both passive and active scanner can be run in parallel with initiator. */ +#define BT_LE_STATES_SCAN_INIT(states) ((states) & BIT64_MASK(22) && \ + (states) & BIT64_MASK(23)) + +#else +#define BT_LE_STATES_SCAN_INIT(states) 0 +#endif + +/* Bonding/authentication types */ +#define BT_HCI_NO_BONDING 0x00 +#define BT_HCI_NO_BONDING_MITM 0x01 +#define BT_HCI_DEDICATED_BONDING 0x02 +#define BT_HCI_DEDICATED_BONDING_MITM 0x03 +#define BT_HCI_GENERAL_BONDING 0x04 +#define BT_HCI_GENERAL_BONDING_MITM 0x05 + +/* + * MITM protection is enabled in SSP authentication requirements octet when + * LSB bit is set. + */ +#define BT_MITM 0x01 + +/* I/O capabilities */ +#define BT_IO_DISPLAY_ONLY 0x00 +#define BT_IO_DISPLAY_YESNO 0x01 +#define BT_IO_KEYBOARD_ONLY 0x02 +#define BT_IO_NO_INPUT_OUTPUT 0x03 + +/* SCO packet types */ +#define HCI_PKT_TYPE_HV1 0x0020 +#define HCI_PKT_TYPE_HV2 0x0040 +#define HCI_PKT_TYPE_HV3 0x0080 + +/* eSCO packet types */ +#define HCI_PKT_TYPE_SCO_HV1 0x0001 +#define HCI_PKT_TYPE_SCO_HV2 0x0002 +#define HCI_PKT_TYPE_SCO_HV3 0x0004 +#define HCI_PKT_TYPE_ESCO_EV3 0x0008 +#define HCI_PKT_TYPE_ESCO_EV4 0x0010 +#define HCI_PKT_TYPE_ESCO_EV5 0x0020 +#define HCI_PKT_TYPE_ESCO_2EV3 0x0040 +#define HCI_PKT_TYPE_ESCO_3EV3 0x0080 +#define HCI_PKT_TYPE_ESCO_2EV5 0x0100 +#define HCI_PKT_TYPE_ESCO_3EV5 0x0200 + +#define ESCO_PKT_MASK (HCI_PKT_TYPE_SCO_HV1 | \ + HCI_PKT_TYPE_SCO_HV2 | \ + HCI_PKT_TYPE_SCO_HV3 | \ + HCI_PKT_TYPE_ESCO_EV3 | \ + HCI_PKT_TYPE_ESCO_EV4 | \ + HCI_PKT_TYPE_ESCO_EV5) +#define SCO_PKT_MASK (HCI_PKT_TYPE_SCO_HV1 | \ + HCI_PKT_TYPE_SCO_HV2 | \ + HCI_PKT_TYPE_SCO_HV3) +#define EDR_ESCO_PKT_MASK (HCI_PKT_TYPE_ESCO_2EV3 | \ + HCI_PKT_TYPE_ESCO_3EV3 | \ + HCI_PKT_TYPE_ESCO_2EV5 | \ + HCI_PKT_TYPE_ESCO_3EV5) + +/* HCI BR/EDR link types */ +#define BT_HCI_SCO 0x00 +#define BT_HCI_ACL 0x01 +#define BT_HCI_ESCO 0x02 + +/* OpCode Group Fields */ +#define BT_OGF_LINK_CTRL 0x01 +#define BT_OGF_BASEBAND 0x03 +#define BT_OGF_INFO 0x04 +#define BT_OGF_STATUS 0x05 +#define BT_OGF_LE 0x08 +#define BT_OGF_VS 0x3f + +/* Construct OpCode from OGF and OCF */ +#define BT_OP(ogf, ocf) ((ocf) | ((ogf) << 10)) + +/* Invalid opcode */ +#define BT_OP_NOP 0x0000 + +/* Obtain OGF from OpCode */ +#define BT_OGF(opcode) (((opcode) >> 10) & BIT_MASK(6)) +/* Obtain OCF from OpCode */ +#define BT_OCF(opcode) ((opcode) & BIT_MASK(10)) + +#define BT_HCI_OP_INQUIRY BT_OP(BT_OGF_LINK_CTRL, 0x0001) /* 0x0401 */ +struct bt_hci_op_inquiry { + uint8_t lap[3]; + uint8_t length; + uint8_t num_rsp; +} __packed; + +#define BT_HCI_OP_INQUIRY_CANCEL BT_OP(BT_OGF_LINK_CTRL, 0x0002) /* 0x0402 */ + +#define BT_HCI_OP_CONNECT BT_OP(BT_OGF_LINK_CTRL, 0x0005) /* 0x0405 */ +struct bt_hci_cp_connect { + bt_addr_t bdaddr; + uint16_t packet_type; + uint8_t pscan_rep_mode; + uint8_t reserved; + uint16_t clock_offset; + uint8_t allow_role_switch; +} __packed; + +#define BT_HCI_OP_DISCONNECT BT_OP(BT_OGF_LINK_CTRL, 0x0006) /* 0x0406 */ +struct bt_hci_cp_disconnect { + uint16_t handle; + uint8_t reason; +} __packed; + +#define BT_HCI_OP_CONNECT_CANCEL BT_OP(BT_OGF_LINK_CTRL, 0x0008) /* 0x0408 */ +struct bt_hci_cp_connect_cancel { + bt_addr_t bdaddr; +} __packed; +struct bt_hci_rp_connect_cancel { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_ACCEPT_CONN_REQ BT_OP(BT_OGF_LINK_CTRL, 0x0009) /* 0x0409 */ +struct bt_hci_cp_accept_conn_req { + bt_addr_t bdaddr; + uint8_t role; +} __packed; + +#define BT_HCI_OP_SETUP_SYNC_CONN BT_OP(BT_OGF_LINK_CTRL, 0x0028) /* 0x0428 */ +struct bt_hci_cp_setup_sync_conn { + uint16_t handle; + uint32_t tx_bandwidth; + uint32_t rx_bandwidth; + uint16_t max_latency; + uint16_t content_format; + uint8_t retrans_effort; + uint16_t pkt_type; +} __packed; + +#define BT_HCI_OP_ACCEPT_SYNC_CONN_REQ BT_OP(BT_OGF_LINK_CTRL, 0x0029) /* 0x0429 */ +struct bt_hci_cp_accept_sync_conn_req { + bt_addr_t bdaddr; + uint32_t tx_bandwidth; + uint32_t rx_bandwidth; + uint16_t max_latency; + uint16_t content_format; + uint8_t retrans_effort; + uint16_t pkt_type; +} __packed; + +#define BT_HCI_OP_REJECT_CONN_REQ BT_OP(BT_OGF_LINK_CTRL, 0x000a) /* 0x040a */ +struct bt_hci_cp_reject_conn_req { + bt_addr_t bdaddr; + uint8_t reason; +} __packed; + +#define BT_HCI_OP_LINK_KEY_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x000b) /* 0x040b */ +struct bt_hci_cp_link_key_reply { + bt_addr_t bdaddr; + uint8_t link_key[16]; +} __packed; + +#define BT_HCI_OP_LINK_KEY_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x000c) /* 0x040c */ +struct bt_hci_cp_link_key_neg_reply { + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_PIN_CODE_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x000d) /* 0x040d */ +struct bt_hci_cp_pin_code_reply { + bt_addr_t bdaddr; + uint8_t pin_len; + uint8_t pin_code[16]; +} __packed; +struct bt_hci_rp_pin_code_reply { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_PIN_CODE_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x000e) /* 0x040e */ +struct bt_hci_cp_pin_code_neg_reply { + bt_addr_t bdaddr; +} __packed; +struct bt_hci_rp_pin_code_neg_reply { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_AUTH_REQUESTED BT_OP(BT_OGF_LINK_CTRL, 0x0011) /* 0x0411 */ +struct bt_hci_cp_auth_requested { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_SET_CONN_ENCRYPT BT_OP(BT_OGF_LINK_CTRL, 0x0013) /* 0x0413 */ +struct bt_hci_cp_set_conn_encrypt { + uint16_t handle; + uint8_t encrypt; +} __packed; + +#define BT_HCI_OP_REMOTE_NAME_REQUEST BT_OP(BT_OGF_LINK_CTRL, 0x0019) /* 0x0419 */ +struct bt_hci_cp_remote_name_request { + bt_addr_t bdaddr; + uint8_t pscan_rep_mode; + uint8_t reserved; + uint16_t clock_offset; +} __packed; + +#define BT_HCI_OP_REMOTE_NAME_CANCEL BT_OP(BT_OGF_LINK_CTRL, 0x001a) /* 0x041a */ +struct bt_hci_cp_remote_name_cancel { + bt_addr_t bdaddr; +} __packed; +struct bt_hci_rp_remote_name_cancel { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_READ_REMOTE_FEATURES BT_OP(BT_OGF_LINK_CTRL, 0x001b) /* 0x041b */ +struct bt_hci_cp_read_remote_features { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_READ_REMOTE_EXT_FEATURES BT_OP(BT_OGF_LINK_CTRL, 0x001c) /* 0x041c */ +struct bt_hci_cp_read_remote_ext_features { + uint16_t handle; + uint8_t page; +} __packed; + +#define BT_HCI_OP_READ_REMOTE_VERSION_INFO BT_OP(BT_OGF_LINK_CTRL, 0x001d) /* 0x041d */ +struct bt_hci_cp_read_remote_version_info { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_IO_CAPABILITY_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002b) /* 0x042b */ +struct bt_hci_cp_io_capability_reply { + bt_addr_t bdaddr; + uint8_t capability; + uint8_t oob_data; + uint8_t authentication; +} __packed; + +#define BT_HCI_OP_USER_CONFIRM_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002c) /* 0x042c */ +#define BT_HCI_OP_USER_CONFIRM_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002d) /* 0x042d */ +struct bt_hci_cp_user_confirm_reply { + bt_addr_t bdaddr; +} __packed; +struct bt_hci_rp_user_confirm_reply { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_USER_PASSKEY_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002e) /* 0x042e */ +struct bt_hci_cp_user_passkey_reply { + bt_addr_t bdaddr; + uint32_t passkey; +} __packed; + +#define BT_HCI_OP_USER_PASSKEY_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002f) /* 0x042f */ +struct bt_hci_cp_user_passkey_neg_reply { + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_IO_CAPABILITY_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x0034) /* 0x0434 */ +struct bt_hci_cp_io_capability_neg_reply { + bt_addr_t bdaddr; + uint8_t reason; +} __packed; + +#define BT_HCI_OP_SET_EVENT_MASK BT_OP(BT_OGF_BASEBAND, 0x0001) /* 0x0c01 */ +struct bt_hci_cp_set_event_mask { + uint8_t events[8]; +} __packed; + +#define BT_HCI_OP_RESET BT_OP(BT_OGF_BASEBAND, 0x0003) /* 0x0c03 */ + +#define BT_HCI_OP_WRITE_LOCAL_NAME BT_OP(BT_OGF_BASEBAND, 0x0013) /* 0x0c13 */ +struct bt_hci_write_local_name { + uint8_t local_name[248]; +} __packed; + +#define BT_HCI_OP_READ_CONN_ACCEPT_TIMEOUT BT_OP(BT_OGF_BASEBAND, 0x0015) /* 0x0c15 */ +struct bt_hci_rp_read_conn_accept_timeout { + uint8_t status; + uint16_t conn_accept_timeout; +} __packed; + +#define BT_HCI_OP_WRITE_CONN_ACCEPT_TIMEOUT BT_OP(BT_OGF_BASEBAND, 0x0016) /* 0x0c16 */ +struct bt_hci_cp_write_conn_accept_timeout { + uint16_t conn_accept_timeout; +} __packed; + +struct bt_hci_rp_write_conn_accept_timeout { + uint8_t status; +} __packed; + +#define BT_HCI_OP_WRITE_PAGE_TIMEOUT BT_OP(BT_OGF_BASEBAND, 0x0018) /* 0x0c18 */ + +#define BT_HCI_OP_WRITE_SCAN_ENABLE BT_OP(BT_OGF_BASEBAND, 0x001a) /* 0x0c1a */ +#define BT_BREDR_SCAN_DISABLED 0x00 +#define BT_BREDR_SCAN_INQUIRY 0x01 +#define BT_BREDR_SCAN_PAGE 0x02 + +#define BT_COD(major_service, major_device, minor_device) \ + (((uint32_t)major_service << 13) | ((uint32_t)major_device << 8) | \ + ((uint32_t)minor_device << 2)) +#define BT_COD_VALID(cod) ((0 == (cod[0] & (BIT(0) | BIT(1)))) ? true : false) +#define BT_COD_MAJOR_SERVICE_CLASSES(cod) \ + ((((uint32_t)cod[2] & 0xFF) >> 5) | (((uint32_t)cod[1] & 0xD0) >> 5)) +#define BT_COD_MAJOR_DEVICE_CLASS(cod) ((((uint32_t)cod[1]) & 0x1FUL)) +#define BT_COD_MINOR_DEVICE_CLASS(cod) (((((uint32_t)cod[0]) & 0xFF) >> 2)) + +#define BT_COD_MAJOR_MISC 0x00 +#define BT_COD_MAJOR_COMPUTER 0x01 +#define BT_COD_MAJOR_PHONE 0x02 +#define BT_COD_MAJOR_LAN_NETWORK_AP 0x03 +#define BT_COD_MAJOR_AUDIO_VIDEO 0x04 +#define BT_COD_MAJOR_PERIPHERAL 0x05 +#define BT_COD_MAJOR_IMAGING 0x06 +#define BT_COD_MAJOR_WEARABLE 0x07 +#define BT_COD_MAJOR_TOY 0x08 +#define BT_COD_MAJOR_HEALTH 0x09 +#define BT_COD_MAJOR_UNCATEGORIZED 0x1F + +/* Minor Device Class field - Computer Major Class */ +#define BT_COD_MAJOR_COMPUTER_MINOR_UNCATEGORIZED 0x00 +#define BT_COD_MAJOR_COMPUTER_MINOR_DESKTOP 0x01 +#define BT_COD_MAJOR_COMPUTER_MINOR_SERVER_CLASS_COMPUTER 0x02 +#define BT_COD_MAJOR_COMPUTER_MINOR_LAPTOP 0x03 +#define BT_COD_MAJOR_COMPUTER_MINOR_HANDHELD_PC_PDA 0x04 +#define BT_COD_MAJOR_COMPUTER_MINOR_PALM_SIZE_PC_PDA 0x05 +#define BT_COD_MAJOR_COMPUTER_MINOR_WEARABLE_COMPUTER 0x06 +#define BT_COD_MAJOR_COMPUTER_MINOR_TABLET 0x07 + +/* Minor Device Class field - Phone Major Class */ +#define BT_COD_MAJOR_PHONE_MINOR_UNCATEGORIZED 0x00 +#define BT_COD_MAJOR_PHONE_MINOR_CELLULAR 0x01 +#define BT_COD_MAJOR_PHONE_MINOR_CORDLESS 0x02 +#define BT_COD_MAJOR_PHONE_MINOR_SMARTPHONE 0x03 +#define BT_COD_MAJOR_PHONE_MINOR_WIRED_MODEM_VOICE_GATEWAY 0x04 +#define BT_COD_MAJOR_PHONE_MINOR_ISDN 0x05 + +/* Minor Device Class field - Audio/Video Major Class */ +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_UNCATEGORIZED 0x00 +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_WEARABLE_HEADSET 0x01 +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_HANDS_FREE 0x02 +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_RFU 0x03 +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_MICROPHONE 0x04 +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_LOUDSPEAKER 0x05 +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_HEADPHONES 0x06 +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_PORTABLE_AUDIO 0x07 +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_CAR_AUDIO 0x08 +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_SET_TOP_BOX 0x09 +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_HIFI_AUDIO 0x0A +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_VCR 0x0B +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_VIDEO_CAMERA 0x0C +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_CAMCORDER 0x0D +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_VIDEO_MONITOR 0x0E +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_VIDEO_DISPLAY_LOUDSPEAKER 0x0F +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_VIDEO_CONFERENCING 0x10 +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_RFU2 0x11 +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_GAME_TOY 0x12 + +#define BT_HCI_OP_WRITE_CLASS_OF_DEVICE BT_OP(BT_OGF_BASEBAND, 0x0024) /* 0x0c24 */ +struct bt_hci_cp_write_class_of_device { + uint8_t class_of_device[3]; +} __packed; + +#define BT_TX_POWER_LEVEL_CURRENT 0x00 +#define BT_TX_POWER_LEVEL_MAX 0x01 +#define BT_HCI_OP_READ_TX_POWER_LEVEL BT_OP(BT_OGF_BASEBAND, 0x002d) /* 0x0c2d */ +struct bt_hci_cp_read_tx_power_level { + uint16_t handle; + uint8_t type; +} __packed; + +struct bt_hci_rp_read_tx_power_level { + uint8_t status; + uint16_t handle; + int8_t tx_power_level; +} __packed; + +#define BT_HCI_LE_TX_POWER_PHY_1M 0x01 +#define BT_HCI_LE_TX_POWER_PHY_2M 0x02 +#define BT_HCI_LE_TX_POWER_PHY_CODED_S8 0x03 +#define BT_HCI_LE_TX_POWER_PHY_CODED_S2 0x04 +#define BT_HCI_OP_LE_ENH_READ_TX_POWER_LEVEL BT_OP(BT_OGF_LE, 0x0076) /* 0x2076 */ +struct bt_hci_cp_le_read_tx_power_level { + uint16_t handle; + uint8_t phy; +} __packed; + +struct bt_hci_rp_le_read_tx_power_level { + uint8_t status; + uint16_t handle; + uint8_t phy; + int8_t current_tx_power_level; + int8_t max_tx_power_level; +} __packed; + +#define BT_HCI_OP_LE_READ_REMOTE_TX_POWER_LEVEL BT_OP(BT_OGF_LE, 0x0077) /* 0x2077 */ + +#define BT_HCI_LE_TX_POWER_REPORT_DISABLE 0x00 +#define BT_HCI_LE_TX_POWER_REPORT_ENABLE 0x01 +#define BT_HCI_OP_LE_SET_TX_POWER_REPORT_ENABLE BT_OP(BT_OGF_LE, 0x007A) /* 0x207A */ +struct bt_hci_cp_le_set_tx_power_report_enable { + uint16_t handle; + uint8_t local_enable; + uint8_t remote_enable; +} __packed; + +struct bt_hci_cp_le_set_path_loss_reporting_parameters { + uint16_t handle; + uint8_t high_threshold; + uint8_t high_hysteresis; + uint8_t low_threshold; + uint8_t low_hysteresis; + uint16_t min_time_spent; +} __packed; + +struct bt_hci_cp_le_set_path_loss_reporting_enable { + uint16_t handle; + uint8_t enable; +} __packed; + +#define BT_HCI_OP_LE_SET_PATH_LOSS_REPORTING_PARAMETERS BT_OP(BT_OGF_LE, 0x0078) /* 0x2078 */ + +#define BT_HCI_LE_PATH_LOSS_REPORTING_DISABLE 0x00 +#define BT_HCI_LE_PATH_LOSS_REPORTING_ENABLE 0x01 +#define BT_HCI_OP_LE_SET_PATH_LOSS_REPORTING_ENABLE BT_OP(BT_OGF_LE, 0x0079) /* 0x2079 */ + +struct bt_hci_cp_le_set_default_subrate { + uint16_t subrate_min; + uint16_t subrate_max; + uint16_t max_latency; + uint16_t continuation_number; + uint16_t supervision_timeout; +} __packed; + +struct bt_hci_cp_le_subrate_request { + uint16_t handle; + uint16_t subrate_min; + uint16_t subrate_max; + uint16_t max_latency; + uint16_t continuation_number; + uint16_t supervision_timeout; +} __packed; + +#define BT_HCI_OP_LE_SET_DEFAULT_SUBRATE BT_OP(BT_OGF_LE, 0x007D) /* 0x207D */ +#define BT_HCI_OP_LE_SUBRATE_REQUEST BT_OP(BT_OGF_LE, 0x007E) /* 0x207E */ + +#define BT_HCI_CTL_TO_HOST_FLOW_DISABLE 0x00 +#define BT_HCI_CTL_TO_HOST_FLOW_ENABLE 0x01 +#define BT_HCI_OP_SET_CTL_TO_HOST_FLOW BT_OP(BT_OGF_BASEBAND, 0x0031) /* 0x0c31 */ +struct bt_hci_cp_set_ctl_to_host_flow { + uint8_t flow_enable; +} __packed; + +#define BT_HCI_OP_HOST_BUFFER_SIZE BT_OP(BT_OGF_BASEBAND, 0x0033) /* 0x0c33 */ +struct bt_hci_cp_host_buffer_size { + uint16_t acl_mtu; + uint8_t sco_mtu; + uint16_t acl_pkts; + uint16_t sco_pkts; +} __packed; + +struct bt_hci_handle_count { + uint16_t handle; + uint16_t count; +} __packed; + +#define BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS BT_OP(BT_OGF_BASEBAND, 0x0035) /* 0x0c35 */ +struct bt_hci_cp_host_num_completed_packets { + uint8_t num_handles; + struct bt_hci_handle_count h[0]; +} __packed; + +#define BT_HCI_OP_WRITE_INQUIRY_MODE BT_OP(BT_OGF_BASEBAND, 0x0045) /* 0x0c45 */ +struct bt_hci_cp_write_inquiry_mode { + uint8_t mode; +} __packed; + +#define BT_HCI_OP_WRITE_SSP_MODE BT_OP(BT_OGF_BASEBAND, 0x0056) /* 0x0c56 */ +struct bt_hci_cp_write_ssp_mode { + uint8_t mode; +} __packed; + +#define BT_HCI_OP_SET_EVENT_MASK_PAGE_2 BT_OP(BT_OGF_BASEBAND, 0x0063) /* 0x0c63 */ +struct bt_hci_cp_set_event_mask_page_2 { + uint8_t events_page_2[8]; +} __packed; + +#define BT_HCI_OP_LE_WRITE_LE_HOST_SUPP BT_OP(BT_OGF_BASEBAND, 0x006d) /* 0x0c6d */ +struct bt_hci_cp_write_le_host_supp { + uint8_t le; + uint8_t simul; +} __packed; + +#define BT_HCI_OP_WRITE_SC_HOST_SUPP BT_OP(BT_OGF_BASEBAND, 0x007a) /* 0x0c7a */ +struct bt_hci_cp_write_sc_host_supp { + uint8_t sc_support; +} __packed; + +#define BT_HCI_OP_READ_AUTH_PAYLOAD_TIMEOUT BT_OP(BT_OGF_BASEBAND, 0x007b) /* 0x0c7b */ +struct bt_hci_cp_read_auth_payload_timeout { + uint16_t handle; +} __packed; + +struct bt_hci_rp_read_auth_payload_timeout { + uint8_t status; + uint16_t handle; + uint16_t auth_payload_timeout; +} __packed; + +#define BT_HCI_OP_WRITE_AUTH_PAYLOAD_TIMEOUT BT_OP(BT_OGF_BASEBAND, 0x007c) /* 0x0c7c */ +struct bt_hci_cp_write_auth_payload_timeout { + uint16_t handle; + uint16_t auth_payload_timeout; +} __packed; + +struct bt_hci_rp_write_auth_payload_timeout { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_CONFIGURE_DATA_PATH BT_OP(BT_OGF_BASEBAND, 0x0083) /* 0x0c83 */ +struct bt_hci_cp_configure_data_path { + uint8_t data_path_dir; + uint8_t data_path_id; + uint8_t vs_config_len; + uint8_t vs_config[0]; +} __packed; + +struct bt_hci_rp_configure_data_path { + uint8_t status; +} __packed; + +/* HCI version from Assigned Numbers */ +#define BT_HCI_VERSION_1_0B 0 +#define BT_HCI_VERSION_1_1 1 +#define BT_HCI_VERSION_1_2 2 +#define BT_HCI_VERSION_2_0 3 +#define BT_HCI_VERSION_2_1 4 +#define BT_HCI_VERSION_3_0 5 +#define BT_HCI_VERSION_4_0 6 +#define BT_HCI_VERSION_4_1 7 +#define BT_HCI_VERSION_4_2 8 +#define BT_HCI_VERSION_5_0 9 +#define BT_HCI_VERSION_5_1 10 +#define BT_HCI_VERSION_5_2 11 +#define BT_HCI_VERSION_5_3 12 +#define BT_HCI_VERSION_5_4 13 +#define BT_HCI_VERSION_6_0 14 + +#define BT_HCI_OP_READ_LOCAL_VERSION_INFO BT_OP(BT_OGF_INFO, 0x0001) /* 0x1001 */ +struct bt_hci_rp_read_local_version_info { + uint8_t status; + uint8_t hci_version; + uint16_t hci_revision; + uint8_t lmp_version; + uint16_t manufacturer; + uint16_t lmp_subversion; +} __packed; + +#define BT_HCI_OP_READ_SUPPORTED_COMMANDS BT_OP(BT_OGF_INFO, 0x0002) /* 0x1002 */ +struct bt_hci_rp_read_supported_commands { + uint8_t status; + uint8_t commands[64]; +} __packed; + +#define BT_HCI_OP_READ_LOCAL_EXT_FEATURES BT_OP(BT_OGF_INFO, 0x0004) /* 0x1004 */ +struct bt_hci_cp_read_local_ext_features { + uint8_t page; +}; +struct bt_hci_rp_read_local_ext_features { + uint8_t status; + uint8_t page; + uint8_t max_page; + uint8_t ext_features[8]; +} __packed; + +#define BT_HCI_OP_READ_LOCAL_FEATURES BT_OP(BT_OGF_INFO, 0x0003) /* 0x1003 */ +struct bt_hci_rp_read_local_features { + uint8_t status; + uint8_t features[8]; +} __packed; + +#define BT_HCI_OP_READ_BUFFER_SIZE BT_OP(BT_OGF_INFO, 0x0005) /* 0x1005 */ +struct bt_hci_rp_read_buffer_size { + uint8_t status; + uint16_t acl_max_len; + uint8_t sco_max_len; + uint16_t acl_max_num; + uint16_t sco_max_num; +} __packed; + +#define BT_HCI_OP_READ_BD_ADDR BT_OP(BT_OGF_INFO, 0x0009) /* 0x1009 */ +struct bt_hci_rp_read_bd_addr { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +/* logic transport type bits as returned when reading supported codecs */ +#define BT_HCI_CODEC_TRANSPORT_MASK_BREDR_ACL BIT(0) +#define BT_HCI_CODEC_TRANSPORT_MASK_BREDR_SCO BIT(1) +#define BT_HCI_CODEC_TRANSPORT_MASK_LE_CIS BIT(2) +#define BT_HCI_CODEC_TRANSPORT_MASK_LE_BIS BIT(3) + +/* logic transport types for reading codec capabilities and controller delays */ +#define BT_HCI_LOGICAL_TRANSPORT_TYPE_BREDR_ACL 0x00 +#define BT_HCI_LOGICAL_TRANSPORT_TYPE_BREDR_SCO 0x01 +#define BT_HCI_LOGICAL_TRANSPORT_TYPE_LE_CIS 0x02 +#define BT_HCI_LOGICAL_TRANSPORT_TYPE_LE_BIS 0x03 + +/* audio datapath directions */ +#define BT_HCI_DATAPATH_DIR_HOST_TO_CTLR 0x00 +#define BT_HCI_DATAPATH_DIR_CTLR_TO_HOST 0x01 + +/* audio datapath IDs */ +#define BT_HCI_DATAPATH_ID_HCI 0x00 +#define BT_HCI_DATAPATH_ID_VS 0x01 +#define BT_HCI_DATAPATH_ID_VS_END 0xfe + +/* coding format assigned numbers, used for codec IDs */ +#define BT_HCI_CODING_FORMAT_ULAW_LOG 0x00 +#define BT_HCI_CODING_FORMAT_ALAW_LOG 0x01 +#define BT_HCI_CODING_FORMAT_CVSD 0x02 +#define BT_HCI_CODING_FORMAT_TRANSPARENT 0x03 +#define BT_HCI_CODING_FORMAT_LINEAR_PCM 0x04 +#define BT_HCI_CODING_FORMAT_MSBC 0x05 +#define BT_HCI_CODING_FORMAT_LC3 0x06 +#define BT_HCI_CODING_FORMAT_G729A 0x07 +#define BT_HCI_CODING_FORMAT_VS 0xFF + +#define BT_HCI_OP_READ_CODECS BT_OP(BT_OGF_INFO, 0x000b) /* 0x100b */ +struct bt_hci_std_codec_info { + uint8_t codec_id; +} __packed; +struct bt_hci_std_codecs { + uint8_t num_codecs; + struct bt_hci_std_codec_info codec_info[0]; +} __packed; +struct bt_hci_vs_codec_info { + uint16_t company_id; + uint16_t codec_id; +} __packed; +struct bt_hci_vs_codecs { + uint8_t num_codecs; + struct bt_hci_vs_codec_info codec_info[0]; +} __packed; +struct bt_hci_rp_read_codecs { + uint8_t status; + /* other fields filled in dynamically */ + uint8_t codecs[0]; +} __packed; + +#define BT_HCI_OP_READ_CODECS_V2 BT_OP(BT_OGF_INFO, 0x000d) /* 0x100d */ +struct bt_hci_std_codec_info_v2 { + uint8_t codec_id; + uint8_t transports; /* bitmap */ +} __packed; +struct bt_hci_std_codecs_v2 { + uint8_t num_codecs; + struct bt_hci_std_codec_info_v2 codec_info[0]; +} __packed; +struct bt_hci_vs_codec_info_v2 { + uint16_t company_id; + uint16_t codec_id; + uint8_t transports; /* bitmap */ +} __packed; +struct bt_hci_vs_codecs_v2 { + uint8_t num_codecs; + struct bt_hci_vs_codec_info_v2 codec_info[0]; +} __packed; +struct bt_hci_rp_read_codecs_v2 { + uint8_t status; + /* other fields filled in dynamically */ + uint8_t codecs[0]; +} __packed; + +struct bt_hci_cp_codec_id { + uint8_t coding_format; + uint16_t company_id; + uint16_t vs_codec_id; +} __packed; + +#define BT_HCI_OP_READ_CODEC_CAPABILITIES BT_OP(BT_OGF_INFO, 0x000e) /* 0x100e */ +struct bt_hci_cp_read_codec_capabilities { + struct bt_hci_cp_codec_id codec_id; + uint8_t transport; + uint8_t direction; +} __packed; +struct bt_hci_codec_capability_info { + uint8_t length; + uint8_t data[0]; +} __packed; +struct bt_hci_rp_read_codec_capabilities { + uint8_t status; + uint8_t num_capabilities; + /* other fields filled in dynamically */ + uint8_t capabilities[0]; +} __packed; + +#define BT_HCI_OP_READ_CTLR_DELAY BT_OP(BT_OGF_INFO, 0x000f) /* 0x100f */ +struct bt_hci_cp_read_ctlr_delay { + struct bt_hci_cp_codec_id codec_id; + uint8_t transport; + uint8_t direction; + uint8_t codec_config_len; + uint8_t codec_config[0]; +} __packed; +struct bt_hci_rp_read_ctlr_delay { + uint8_t status; + uint8_t min_ctlr_delay[3]; + uint8_t max_ctlr_delay[3]; +} __packed; + +#define BT_HCI_OP_READ_RSSI BT_OP(BT_OGF_STATUS, 0x0005) /* 0x1405 */ +struct bt_hci_cp_read_rssi { + uint16_t handle; +} __packed; +struct bt_hci_rp_read_rssi { + uint8_t status; + uint16_t handle; + int8_t rssi; +} __packed; + +#define BT_HCI_ENCRYPTION_KEY_SIZE_MIN 7 +#define BT_HCI_ENCRYPTION_KEY_SIZE_MAX 16 + +#define BT_HCI_OP_READ_ENCRYPTION_KEY_SIZE BT_OP(BT_OGF_STATUS, 0x0008) /* 0x1408 */ +struct bt_hci_cp_read_encryption_key_size { + uint16_t handle; +} __packed; +struct bt_hci_rp_read_encryption_key_size { + uint8_t status; + uint16_t handle; + uint8_t key_size; +} __packed; + +/* BLE */ + +#define BT_HCI_OP_LE_SET_EVENT_MASK BT_OP(BT_OGF_LE, 0x0001) /* 0x2001 */ +struct bt_hci_cp_le_set_event_mask { + uint8_t events[8]; +} __packed; + +#define BT_HCI_OP_LE_READ_BUFFER_SIZE BT_OP(BT_OGF_LE, 0x0002) /* 0x2002 */ +struct bt_hci_rp_le_read_buffer_size { + uint8_t status; + uint16_t le_max_len; + uint8_t le_max_num; +} __packed; + +#define BT_HCI_OP_LE_READ_LOCAL_FEATURES BT_OP(BT_OGF_LE, 0x0003) /* 0x2003 */ +struct bt_hci_rp_le_read_local_features { + uint8_t status; + uint8_t features[8]; +} __packed; + +#define BT_HCI_OP_LE_SET_RANDOM_ADDRESS BT_OP(BT_OGF_LE, 0x0005) /* 0x2005 */ +struct bt_hci_cp_le_set_random_address { + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_ADV_IND 0x00 +#define BT_HCI_ADV_DIRECT_IND 0x01 +#define BT_HCI_ADV_SCAN_IND 0x02 +#define BT_HCI_ADV_NONCONN_IND 0x03 +#define BT_HCI_ADV_DIRECT_IND_LOW_DUTY 0x04 +#define BT_HCI_ADV_SCAN_RSP 0x04 + +#define BT_LE_ADV_INTERVAL_MIN 0x0020 +#define BT_LE_ADV_INTERVAL_MAX 0x4000 +#define BT_LE_ADV_INTERVAL_DEFAULT 0x0800 + +#define BT_LE_ADV_CHAN_MAP_CHAN_37 0x01 +#define BT_LE_ADV_CHAN_MAP_CHAN_38 0x02 +#define BT_LE_ADV_CHAN_MAP_CHAN_39 0x04 +#define BT_LE_ADV_CHAN_MAP_ALL 0x07 + +#define BT_LE_ADV_FP_NO_FILTER 0x00 +#define BT_LE_ADV_FP_FILTER_SCAN_REQ 0x01 +#define BT_LE_ADV_FP_FILTER_CONN_IND 0x02 +#define BT_LE_ADV_FP_FILTER_BOTH 0x03 + +#define BT_HCI_OP_LE_SET_ADV_PARAM BT_OP(BT_OGF_LE, 0x0006) /* 0x2006 */ +struct bt_hci_cp_le_set_adv_param { + uint16_t min_interval; + uint16_t max_interval; + uint8_t type; + uint8_t own_addr_type; + bt_addr_le_t direct_addr; + uint8_t channel_map; + uint8_t filter_policy; +} __packed; + +#define BT_HCI_OP_LE_READ_ADV_CHAN_TX_POWER BT_OP(BT_OGF_LE, 0x0007) /* 0x2007 */ +struct bt_hci_rp_le_read_chan_tx_power { + uint8_t status; + int8_t tx_power_level; +} __packed; + +#define BT_HCI_OP_LE_SET_ADV_DATA BT_OP(BT_OGF_LE, 0x0008) /* 0x2008 */ +struct bt_hci_cp_le_set_adv_data { + uint8_t len; + uint8_t data[31]; +} __packed; + +#define BT_HCI_OP_LE_SET_SCAN_RSP_DATA BT_OP(BT_OGF_LE, 0x0009) /* 0x2009 */ +struct bt_hci_cp_le_set_scan_rsp_data { + uint8_t len; + uint8_t data[31]; +} __packed; + +#define BT_HCI_LE_ADV_DISABLE 0x00 +#define BT_HCI_LE_ADV_ENABLE 0x01 + +#define BT_HCI_OP_LE_SET_ADV_ENABLE BT_OP(BT_OGF_LE, 0x000a) /* 0x200a */ +struct bt_hci_cp_le_set_adv_enable { + uint8_t enable; +} __packed; + +/* Scan types */ +#define BT_HCI_OP_LE_SET_SCAN_PARAM BT_OP(BT_OGF_LE, 0x000b) /* 0x200b */ +#define BT_HCI_LE_SCAN_PASSIVE 0x00 +#define BT_HCI_LE_SCAN_ACTIVE 0x01 + +#define BT_HCI_LE_SCAN_FP_BASIC_NO_FILTER 0x00 +#define BT_HCI_LE_SCAN_FP_BASIC_FILTER 0x01 +#define BT_HCI_LE_SCAN_FP_EXT_NO_FILTER 0x02 +#define BT_HCI_LE_SCAN_FP_EXT_FILTER 0x03 + +struct bt_hci_cp_le_set_scan_param { + uint8_t scan_type; + uint16_t interval; + uint16_t window; + uint8_t addr_type; + uint8_t filter_policy; +} __packed; + +#define BT_HCI_OP_LE_SET_SCAN_ENABLE BT_OP(BT_OGF_LE, 0x000c) /* 0x200c */ + +#define BT_HCI_LE_SCAN_DISABLE 0x00 +#define BT_HCI_LE_SCAN_ENABLE 0x01 + +#define BT_HCI_LE_SCAN_FILTER_DUP_DISABLE 0x00 +#define BT_HCI_LE_SCAN_FILTER_DUP_ENABLE 0x01 + +struct bt_hci_cp_le_set_scan_enable { + uint8_t enable; + uint8_t filter_dup; +} __packed; + +#define BT_HCI_OP_LE_CREATE_CONN BT_OP(BT_OGF_LE, 0x000d) /* 0x200d */ + +#define BT_HCI_LE_CREATE_CONN_FP_NO_FILTER 0x00 +#define BT_HCI_LE_CREATE_CONN_FP_FILTER 0x01 + +struct bt_hci_cp_le_create_conn { + uint16_t scan_interval; + uint16_t scan_window; + uint8_t filter_policy; + bt_addr_le_t peer_addr; + uint8_t own_addr_type; + uint16_t conn_interval_min; + uint16_t conn_interval_max; + uint16_t conn_latency; + uint16_t supervision_timeout; + uint16_t min_ce_len; + uint16_t max_ce_len; +} __packed; + +#define BT_HCI_OP_LE_CREATE_CONN_CANCEL BT_OP(BT_OGF_LE, 0x000e) /* 0x200e */ + +#define BT_HCI_OP_LE_READ_FAL_SIZE BT_OP(BT_OGF_LE, 0x000f) /* 0x200f */ +struct bt_hci_rp_le_read_fal_size { + uint8_t status; + uint8_t fal_size; +} __packed; + +#define BT_HCI_OP_LE_CLEAR_FAL BT_OP(BT_OGF_LE, 0x0010) /* 0x2010 */ + +#define BT_HCI_OP_LE_ADD_DEV_TO_FAL BT_OP(BT_OGF_LE, 0x0011) /* 0x2011 */ +struct bt_hci_cp_le_add_dev_to_fal { + bt_addr_le_t addr; +} __packed; + +#define BT_HCI_OP_LE_REM_DEV_FROM_FAL BT_OP(BT_OGF_LE, 0x0012) /* 0x2012 */ +struct bt_hci_cp_le_rem_dev_from_fal { + bt_addr_le_t addr; +} __packed; + +#define BT_HCI_OP_LE_CONN_UPDATE BT_OP(BT_OGF_LE, 0x0013) /* 0x2013 */ +struct hci_cp_le_conn_update { + uint16_t handle; + uint16_t conn_interval_min; + uint16_t conn_interval_max; + uint16_t conn_latency; + uint16_t supervision_timeout; + uint16_t min_ce_len; + uint16_t max_ce_len; +} __packed; + +#define BT_HCI_OP_LE_SET_HOST_CHAN_CLASSIF BT_OP(BT_OGF_LE, 0x0014) /* 0x2014 */ +struct bt_hci_cp_le_set_host_chan_classif { + uint8_t ch_map[5]; +} __packed; + +#define BT_HCI_OP_LE_READ_CHAN_MAP BT_OP(BT_OGF_LE, 0x0015) /* 0x2015 */ +struct bt_hci_cp_le_read_chan_map { + uint16_t handle; +} __packed; +struct bt_hci_rp_le_read_chan_map { + uint8_t status; + uint16_t handle; + uint8_t ch_map[5]; +} __packed; + +#define BT_HCI_OP_LE_READ_REMOTE_FEATURES BT_OP(BT_OGF_LE, 0x0016) /* 0x2016 */ +struct bt_hci_cp_le_read_remote_features { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_ENCRYPT BT_OP(BT_OGF_LE, 0x0017) /* 0x2017 */ +struct bt_hci_cp_le_encrypt { + uint8_t key[16]; + uint8_t plaintext[16]; +} __packed; +struct bt_hci_rp_le_encrypt { + uint8_t status; + uint8_t enc_data[16]; +} __packed; + +#define BT_HCI_OP_LE_RAND BT_OP(BT_OGF_LE, 0x0018) /* 0x2018 */ +struct bt_hci_rp_le_rand { + uint8_t status; + uint8_t rand[8]; +} __packed; + +#define BT_HCI_OP_LE_START_ENCRYPTION BT_OP(BT_OGF_LE, 0x0019) /* 0x2019 */ +struct bt_hci_cp_le_start_encryption { + uint16_t handle; + uint64_t rand; + uint16_t ediv; + uint8_t ltk[16]; +} __packed; + +#define BT_HCI_OP_LE_LTK_REQ_REPLY BT_OP(BT_OGF_LE, 0x001a) /* 0x201a */ +struct bt_hci_cp_le_ltk_req_reply { + uint16_t handle; + uint8_t ltk[16]; +} __packed; +struct bt_hci_rp_le_ltk_req_reply { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_LTK_REQ_NEG_REPLY BT_OP(BT_OGF_LE, 0x001b) /* 0x201b */ +struct bt_hci_cp_le_ltk_req_neg_reply { + uint16_t handle; +} __packed; +struct bt_hci_rp_le_ltk_req_neg_reply { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_READ_SUPP_STATES BT_OP(BT_OGF_LE, 0x001c) /* 0x201c */ +struct bt_hci_rp_le_read_supp_states { + uint8_t status; + uint8_t le_states[8]; +} __packed; + +#define BT_HCI_OP_LE_RX_TEST BT_OP(BT_OGF_LE, 0x001d) /* 0x201d */ +struct bt_hci_cp_le_rx_test { + uint8_t rx_ch; +} __packed; + +#define BT_HCI_TEST_PKT_PAYLOAD_PRBS9 0x00 +#define BT_HCI_TEST_PKT_PAYLOAD_11110000 0x01 +#define BT_HCI_TEST_PKT_PAYLOAD_10101010 0x02 +#define BT_HCI_TEST_PKT_PAYLOAD_PRBS15 0x03 +#define BT_HCI_TEST_PKT_PAYLOAD_11111111 0x04 +#define BT_HCI_TEST_PKT_PAYLOAD_00000000 0x05 +#define BT_HCI_TEST_PKT_PAYLOAD_00001111 0x06 +#define BT_HCI_TEST_PKT_PAYLOAD_01010101 0x07 + +#define BT_HCI_OP_LE_TX_TEST BT_OP(BT_OGF_LE, 0x001e) /* 0x201e */ +struct bt_hci_cp_le_tx_test { + uint8_t tx_ch; + uint8_t test_data_len; + uint8_t pkt_payload; +} __packed; + +#define BT_HCI_OP_LE_TEST_END BT_OP(BT_OGF_LE, 0x001f) /* 0x201f */ +struct bt_hci_rp_le_test_end { + uint8_t status; + uint16_t rx_pkt_count; +} __packed; + +#define BT_HCI_OP_LE_CONN_PARAM_REQ_REPLY BT_OP(BT_OGF_LE, 0x0020) /* 0x2020 */ +struct bt_hci_cp_le_conn_param_req_reply { + uint16_t handle; + uint16_t interval_min; + uint16_t interval_max; + uint16_t latency; + uint16_t timeout; + uint16_t min_ce_len; + uint16_t max_ce_len; +} __packed; +struct bt_hci_rp_le_conn_param_req_reply { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_CONN_PARAM_REQ_NEG_REPLY BT_OP(BT_OGF_LE, 0x0021) /* 0x2021 */ +struct bt_hci_cp_le_conn_param_req_neg_reply { + uint16_t handle; + uint8_t reason; +} __packed; +struct bt_hci_rp_le_conn_param_req_neg_reply { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_SET_DATA_LEN BT_OP(BT_OGF_LE, 0x0022) /* 0x2022 */ +struct bt_hci_cp_le_set_data_len { + uint16_t handle; + uint16_t tx_octets; + uint16_t tx_time; +} __packed; +struct bt_hci_rp_le_set_data_len { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_READ_DEFAULT_DATA_LEN BT_OP(BT_OGF_LE, 0x0023) /* 0x2023 */ +struct bt_hci_rp_le_read_default_data_len { + uint8_t status; + uint16_t max_tx_octets; + uint16_t max_tx_time; +} __packed; + +#define BT_HCI_OP_LE_WRITE_DEFAULT_DATA_LEN BT_OP(BT_OGF_LE, 0x0024) /* 0x2024 */ +struct bt_hci_cp_le_write_default_data_len { + uint16_t max_tx_octets; + uint16_t max_tx_time; +} __packed; + +#define BT_HCI_OP_LE_P256_PUBLIC_KEY BT_OP(BT_OGF_LE, 0x0025) /* 0x2025 */ + +#define BT_HCI_OP_LE_GENERATE_DHKEY BT_OP(BT_OGF_LE, 0x0026) /* 0x2026 */ +struct bt_hci_cp_le_generate_dhkey { + uint8_t key[64]; +} __packed; + +#define BT_HCI_OP_LE_GENERATE_DHKEY_V2 BT_OP(BT_OGF_LE, 0x005e) /* 0x205e */ + +#define BT_HCI_LE_KEY_TYPE_GENERATED 0x00 +#define BT_HCI_LE_KEY_TYPE_DEBUG 0x01 + +struct bt_hci_cp_le_generate_dhkey_v2 { + uint8_t key[64]; + uint8_t key_type; +} __packed; + +#define BT_HCI_OP_LE_ADD_DEV_TO_RL BT_OP(BT_OGF_LE, 0x0027) /* 0x2027 */ +struct bt_hci_cp_le_add_dev_to_rl { + bt_addr_le_t peer_id_addr; + uint8_t peer_irk[16]; + uint8_t local_irk[16]; +} __packed; + +#define BT_HCI_OP_LE_REM_DEV_FROM_RL BT_OP(BT_OGF_LE, 0x0028) /* 0x2028 */ +struct bt_hci_cp_le_rem_dev_from_rl { + bt_addr_le_t peer_id_addr; +} __packed; + +#define BT_HCI_OP_LE_CLEAR_RL BT_OP(BT_OGF_LE, 0x0029) /* 0x2029 */ + +#define BT_HCI_OP_LE_READ_RL_SIZE BT_OP(BT_OGF_LE, 0x002a) /* 0x202a */ +struct bt_hci_rp_le_read_rl_size { + uint8_t status; + uint8_t rl_size; +} __packed; + +#define BT_HCI_OP_LE_READ_PEER_RPA BT_OP(BT_OGF_LE, 0x002b) /* 0x202b */ +struct bt_hci_cp_le_read_peer_rpa { + bt_addr_le_t peer_id_addr; +} __packed; +struct bt_hci_rp_le_read_peer_rpa { + uint8_t status; + bt_addr_t peer_rpa; +} __packed; + +#define BT_HCI_OP_LE_READ_LOCAL_RPA BT_OP(BT_OGF_LE, 0x002c) /* 0x202c */ +struct bt_hci_cp_le_read_local_rpa { + bt_addr_le_t peer_id_addr; +} __packed; +struct bt_hci_rp_le_read_local_rpa { + uint8_t status; + bt_addr_t local_rpa; +} __packed; + +#define BT_HCI_ADDR_RES_DISABLE 0x00 +#define BT_HCI_ADDR_RES_ENABLE 0x01 + +#define BT_HCI_OP_LE_SET_ADDR_RES_ENABLE BT_OP(BT_OGF_LE, 0x002d) /* 0x202d */ +struct bt_hci_cp_le_set_addr_res_enable { + uint8_t enable; +} __packed; + +#define BT_HCI_OP_LE_SET_RPA_TIMEOUT BT_OP(BT_OGF_LE, 0x002e) /* 0x202e */ +struct bt_hci_cp_le_set_rpa_timeout { + uint16_t rpa_timeout; +} __packed; + +/* All limits according to BT Core spec 5.4 [Vol 4, Part E, 7.8.46] */ +#define BT_HCI_LE_MAX_TX_OCTETS_MIN 0x001B +#define BT_HCI_LE_MAX_TX_OCTETS_MAX 0x00FB +#define BT_HCI_LE_MAX_RX_OCTETS_MIN 0x001B +#define BT_HCI_LE_MAX_RX_OCTETS_MAX 0x00FB + +#define BT_HCI_LE_MAX_TX_TIME_MIN 0x0148 +#define BT_HCI_LE_MAX_TX_TIME_MAX 0x4290 +#define BT_HCI_LE_MAX_RX_TIME_MIN 0x0148 +#define BT_HCI_LE_MAX_RX_TIME_MAX 0x4290 + +#define BT_HCI_OP_LE_READ_MAX_DATA_LEN BT_OP(BT_OGF_LE, 0x002f) /* 0x202f */ +struct bt_hci_rp_le_read_max_data_len { + uint8_t status; + uint16_t max_tx_octets; + uint16_t max_tx_time; + uint16_t max_rx_octets; + uint16_t max_rx_time; +} __packed; + +#define BT_HCI_LE_PHY_1M 0x01 +#define BT_HCI_LE_PHY_2M 0x02 +#define BT_HCI_LE_PHY_CODED 0x03 + +#define BT_HCI_OP_LE_READ_PHY BT_OP(BT_OGF_LE, 0x0030) /* 0x2030 */ +struct bt_hci_cp_le_read_phy { + uint16_t handle; +} __packed; +struct bt_hci_rp_le_read_phy { + uint8_t status; + uint16_t handle; + uint8_t tx_phy; + uint8_t rx_phy; +} __packed; + +#define BT_HCI_LE_PHY_TX_ANY BIT(0) +#define BT_HCI_LE_PHY_RX_ANY BIT(1) + +#define BT_HCI_LE_PHY_PREFER_1M BIT(0) +#define BT_HCI_LE_PHY_PREFER_2M BIT(1) +#define BT_HCI_LE_PHY_PREFER_CODED BIT(2) + +#define BT_HCI_OP_LE_SET_DEFAULT_PHY BT_OP(BT_OGF_LE, 0x0031) /* 0x2031 */ +struct bt_hci_cp_le_set_default_phy { + uint8_t all_phys; + uint8_t tx_phys; + uint8_t rx_phys; +} __packed; + +#define BT_HCI_LE_PHY_CODED_ANY 0x00 +#define BT_HCI_LE_PHY_CODED_S2 0x01 +#define BT_HCI_LE_PHY_CODED_S8 0x02 + +#define BT_HCI_OP_LE_SET_PHY BT_OP(BT_OGF_LE, 0x0032) /* 0x2032 */ +struct bt_hci_cp_le_set_phy { + uint16_t handle; + uint8_t all_phys; + uint8_t tx_phys; + uint8_t rx_phys; + uint16_t phy_opts; +} __packed; + +#define BT_HCI_LE_MOD_INDEX_STANDARD 0x00 +#define BT_HCI_LE_MOD_INDEX_STABLE 0x01 + +#define BT_HCI_LE_RX_PHY_1M 0x01 +#define BT_HCI_LE_RX_PHY_2M 0x02 +#define BT_HCI_LE_RX_PHY_CODED 0x03 + +#define BT_HCI_OP_LE_ENH_RX_TEST BT_OP(BT_OGF_LE, 0x0033) /* 0x2033 */ +struct bt_hci_cp_le_enh_rx_test { + uint8_t rx_ch; + uint8_t phy; + uint8_t mod_index; +} __packed; + +#define BT_HCI_LE_TX_PHY_1M 0x01 +#define BT_HCI_LE_TX_PHY_2M 0x02 +#define BT_HCI_LE_TX_PHY_CODED_S8 0x03 +#define BT_HCI_LE_TX_PHY_CODED_S2 0x04 + +#define BT_HCI_OP_LE_ENH_TX_TEST BT_OP(BT_OGF_LE, 0x0034) /* 0x2034 */ +struct bt_hci_cp_le_enh_tx_test { + uint8_t tx_ch; + uint8_t test_data_len; + uint8_t pkt_payload; + uint8_t phy; +} __packed; + +#define BT_HCI_OP_LE_SET_ADV_SET_RANDOM_ADDR BT_OP(BT_OGF_LE, 0x0035) /* 0x2035 */ +struct bt_hci_cp_le_set_adv_set_random_addr { + uint8_t handle; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_LE_ADV_PROP_CONN BIT(0) +#define BT_HCI_LE_ADV_PROP_SCAN BIT(1) +#define BT_HCI_LE_ADV_PROP_DIRECT BIT(2) +#define BT_HCI_LE_ADV_PROP_HI_DC_CONN BIT(3) +#define BT_HCI_LE_ADV_PROP_LEGACY BIT(4) +#define BT_HCI_LE_ADV_PROP_ANON BIT(5) +#define BT_HCI_LE_ADV_PROP_TX_POWER BIT(6) + +#define BT_HCI_LE_PRIM_ADV_INTERVAL_MIN 0x000020 +#define BT_HCI_LE_PRIM_ADV_INTERVAL_MAX 0xFFFFFF + +#define BT_HCI_LE_ADV_SCAN_REQ_ENABLE 1 +#define BT_HCI_LE_ADV_SCAN_REQ_DISABLE 0 + +#define BT_HCI_LE_ADV_TX_POWER_NO_PREF 0x7F + +#define BT_HCI_LE_ADV_HANDLE_MAX 0xEF + +#define BT_HCI_LE_EXT_ADV_SID_INVALID 0xFF + +#define BT_HCI_OP_LE_SET_EXT_ADV_PARAM BT_OP(BT_OGF_LE, 0x0036) /* 0x2036 */ +struct bt_hci_cp_le_set_ext_adv_param { + uint8_t handle; + uint16_t props; + uint8_t prim_min_interval[3]; + uint8_t prim_max_interval[3]; + uint8_t prim_channel_map; + uint8_t own_addr_type; + bt_addr_le_t peer_addr; + uint8_t filter_policy; + int8_t tx_power; + uint8_t prim_adv_phy; + uint8_t sec_adv_max_skip; + uint8_t sec_adv_phy; + uint8_t sid; + uint8_t scan_req_notify_enable; +} __packed; +struct bt_hci_rp_le_set_ext_adv_param { + uint8_t status; + int8_t tx_power; +} __packed; + +#define BT_HCI_LE_EXT_ADV_OP_INTERM_FRAG 0x00 +#define BT_HCI_LE_EXT_ADV_OP_FIRST_FRAG 0x01 +#define BT_HCI_LE_EXT_ADV_OP_LAST_FRAG 0x02 +#define BT_HCI_LE_EXT_ADV_OP_COMPLETE_DATA 0x03 +#define BT_HCI_LE_EXT_ADV_OP_UNCHANGED_DATA 0x04 + +#define BT_HCI_LE_EXT_ADV_FRAG_ENABLED 0x00 +#define BT_HCI_LE_EXT_ADV_FRAG_DISABLED 0x01 + +#define BT_HCI_LE_EXT_ADV_FRAG_MAX_LEN 251 + +#define BT_HCI_OP_LE_SET_EXT_ADV_DATA BT_OP(BT_OGF_LE, 0x0037) /* 0x2037 */ +struct bt_hci_cp_le_set_ext_adv_data { + uint8_t handle; + uint8_t op; + uint8_t frag_pref; + uint8_t len; + uint8_t data[0]; +} __packed; + +#define BT_HCI_OP_LE_SET_EXT_SCAN_RSP_DATA BT_OP(BT_OGF_LE, 0x0038) /* 0x2038 */ +struct bt_hci_cp_le_set_ext_scan_rsp_data { + uint8_t handle; + uint8_t op; + uint8_t frag_pref; + uint8_t len; + uint8_t data[0]; +} __packed; + +#define BT_HCI_OP_LE_SET_EXT_ADV_ENABLE BT_OP(BT_OGF_LE, 0x0039) /* 0x2039 */ +struct bt_hci_ext_adv_set { + uint8_t handle; + uint16_t duration; + uint8_t max_ext_adv_evts; +} __packed; + +struct bt_hci_cp_le_set_ext_adv_enable { + uint8_t enable; + uint8_t set_num; + struct bt_hci_ext_adv_set s[0]; +} __packed; + +#define BT_HCI_OP_LE_READ_MAX_ADV_DATA_LEN BT_OP(BT_OGF_LE, 0x003a) /* 0x203a */ +struct bt_hci_rp_le_read_max_adv_data_len { + uint8_t status; + uint16_t max_adv_data_len; +} __packed; + +#define BT_HCI_OP_LE_READ_NUM_ADV_SETS BT_OP(BT_OGF_LE, 0x003b) /* 0x203b */ +struct bt_hci_rp_le_read_num_adv_sets { + uint8_t status; + uint8_t num_sets; +} __packed; + +#define BT_HCI_OP_LE_REMOVE_ADV_SET BT_OP(BT_OGF_LE, 0x003c) /* 0x203c */ +struct bt_hci_cp_le_remove_adv_set { + uint8_t handle; +} __packed; + +#define BT_HCI_OP_CLEAR_ADV_SETS BT_OP(BT_OGF_LE, 0x003d) /* 0x203d */ + +#define BT_HCI_LE_PER_ADV_INTERVAL_MIN 0x0006 +#define BT_HCI_LE_PER_ADV_INTERVAL_MAX 0xFFFF + +#define BT_HCI_OP_LE_SET_PER_ADV_PARAM BT_OP(BT_OGF_LE, 0x003e) /* 0x203e */ +struct bt_hci_cp_le_set_per_adv_param { + uint8_t handle; + uint16_t min_interval; + uint16_t max_interval; + uint16_t props; +} __packed; + +#define BT_HCI_LE_PER_ADV_OP_INTERM_FRAG 0x00 +#define BT_HCI_LE_PER_ADV_OP_FIRST_FRAG 0x01 +#define BT_HCI_LE_PER_ADV_OP_LAST_FRAG 0x02 +#define BT_HCI_LE_PER_ADV_OP_COMPLETE_DATA 0x03 + +#define BT_HCI_LE_PER_ADV_FRAG_MAX_LEN 252 + +#define BT_HCI_OP_LE_SET_PER_ADV_DATA BT_OP(BT_OGF_LE, 0x003f) /* 0x203f */ +struct bt_hci_cp_le_set_per_adv_data { + uint8_t handle; + uint8_t op; + uint8_t len; + uint8_t data[0]; +} __packed; + +#define BT_HCI_LE_SET_PER_ADV_ENABLE_ENABLE BIT(0) +#define BT_HCI_LE_SET_PER_ADV_ENABLE_ADI BIT(1) + +#define BT_HCI_OP_LE_SET_PER_ADV_ENABLE BT_OP(BT_OGF_LE, 0x0040) /* 0x2040 */ +struct bt_hci_cp_le_set_per_adv_enable { + uint8_t enable; + uint8_t handle; +} __packed; + +#define BT_HCI_OP_LE_SET_EXT_SCAN_PARAM BT_OP(BT_OGF_LE, 0x0041) /* 0x2041 */ +struct bt_hci_ext_scan_phy { + uint8_t type; + uint16_t interval; + uint16_t window; +} __packed; + +#define BT_HCI_LE_EXT_SCAN_PHY_1M BIT(0) +#define BT_HCI_LE_EXT_SCAN_PHY_2M BIT(1) +#define BT_HCI_LE_EXT_SCAN_PHY_CODED BIT(2) + +struct bt_hci_cp_le_set_ext_scan_param { + uint8_t own_addr_type; + uint8_t filter_policy; + uint8_t phys; + struct bt_hci_ext_scan_phy p[0]; +} __packed; + +/* Extends BT_HCI_LE_SCAN_FILTER_DUP */ +#define BT_HCI_LE_EXT_SCAN_FILTER_DUP_ENABLE_RESET 0x02 + +#define BT_HCI_OP_LE_SET_EXT_SCAN_ENABLE BT_OP(BT_OGF_LE, 0x0042) /* 0x2042 */ +struct bt_hci_cp_le_set_ext_scan_enable { + uint8_t enable; + uint8_t filter_dup; + uint16_t duration; + uint16_t period; +} __packed; + +#define BT_HCI_OP_LE_EXT_CREATE_CONN BT_OP(BT_OGF_LE, 0x0043) /* 0x2043 */ +#define BT_HCI_OP_LE_EXT_CREATE_CONN_V2 BT_OP(BT_OGF_LE, 0x0085) /* 0x2085 */ +struct bt_hci_ext_conn_phy { + uint16_t scan_interval; + uint16_t scan_window; + uint16_t conn_interval_min; + uint16_t conn_interval_max; + uint16_t conn_latency; + uint16_t supervision_timeout; + uint16_t min_ce_len; + uint16_t max_ce_len; +} __packed; + +struct bt_hci_cp_le_ext_create_conn { + uint8_t filter_policy; + uint8_t own_addr_type; + bt_addr_le_t peer_addr; + uint8_t phys; + struct bt_hci_ext_conn_phy p[0]; +} __packed; + +struct bt_hci_cp_le_ext_create_conn_v2 { + uint8_t adv_handle; + uint8_t subevent; + uint8_t filter_policy; + uint8_t own_addr_type; + bt_addr_le_t peer_addr; + uint8_t phys; + struct bt_hci_ext_conn_phy p[0]; +} __packed; + +#define BT_HCI_OP_LE_SET_PER_ADV_SUBEVENT_DATA BT_OP(BT_OGF_LE, 0x0082) /* 0x2082 */ +struct bt_hci_cp_le_set_pawr_subevent_data_element { + uint8_t subevent; + uint8_t response_slot_start; + uint8_t response_slot_count; + uint8_t subevent_data_length; + uint8_t subevent_data[0]; +} __packed; + +struct bt_hci_cp_le_set_pawr_subevent_data { + uint8_t adv_handle; + uint8_t num_subevents; + struct bt_hci_cp_le_set_pawr_subevent_data_element subevents[0]; +} __packed; + +#define BT_HCI_OP_LE_SET_PER_ADV_RESPONSE_DATA BT_OP(BT_OGF_LE, 0x0083) /* 0x2083 */ +struct bt_hci_cp_le_set_pawr_response_data { + uint16_t sync_handle; + uint16_t request_event; + uint8_t request_subevent; + uint8_t response_subevent; + uint8_t response_slot; + uint8_t response_data_length; + uint8_t response_data[0]; +} __packed; + +#define BT_HCI_OP_LE_SET_PER_ADV_SYNC_SUBEVENT BT_OP(BT_OGF_LE, 0x0084) /* 0x2084 */ +struct bt_hci_cp_le_set_pawr_sync_subevent { + uint16_t sync_handle; + uint16_t periodic_adv_properties; + uint8_t num_subevents; + uint8_t subevents[0]; +} __packed; + +#define BT_HCI_OP_LE_SET_PER_ADV_PARAM_V2 BT_OP(BT_OGF_LE, 0x0086) /* 0x2086 */ +struct bt_hci_cp_le_set_per_adv_param_v2 { + uint8_t handle; + uint16_t min_interval; + uint16_t max_interval; + uint16_t props; + uint8_t num_subevents; + uint8_t subevent_interval; + uint8_t response_slot_delay; + uint8_t response_slot_spacing; + uint8_t num_response_slots; +} __packed; + +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_FP_USE_LIST BIT(0) +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_FP_REPORTS_DISABLED BIT(1) +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_FP_FILTER_DUPLICATE BIT(2) + +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_FILTERING 0 +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_AOA BIT(0) +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_AOD_1US BIT(1) +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_AOD_2US BIT(2) +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_CTE BIT(3) +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_ONLY_CTE BIT(4) +/* Constants to check correctness of CTE type */ +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_ALLOWED_BITS 5 +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_INVALID_VALUE \ + (~BIT_MASK(BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_ALLOWED_BITS)) + +#define BT_HCI_OP_LE_PER_ADV_CREATE_SYNC BT_OP(BT_OGF_LE, 0x0044) /* 0x2044 */ +struct bt_hci_cp_le_per_adv_create_sync { + uint8_t options; + uint8_t sid; + bt_addr_le_t addr; + uint16_t skip; + uint16_t sync_timeout; + uint8_t cte_type; +} __packed; + +#define BT_HCI_OP_LE_PER_ADV_CREATE_SYNC_CANCEL BT_OP(BT_OGF_LE, 0x0045) /* 0x2045 */ + +#define BT_HCI_OP_LE_PER_ADV_TERMINATE_SYNC BT_OP(BT_OGF_LE, 0x0046) /* 0x2046 */ +struct bt_hci_cp_le_per_adv_terminate_sync { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_ADD_DEV_TO_PER_ADV_LIST BT_OP(BT_OGF_LE, 0x0047) /* 0x2047 */ +struct bt_hci_cp_le_add_dev_to_per_adv_list { + bt_addr_le_t addr; + uint8_t sid; +} __packed; + +#define BT_HCI_OP_LE_REM_DEV_FROM_PER_ADV_LIST BT_OP(BT_OGF_LE, 0x0048) /* 0x2048 */ +struct bt_hci_cp_le_rem_dev_from_per_adv_list { + bt_addr_le_t addr; + uint8_t sid; +} __packed; + +#define BT_HCI_OP_LE_CLEAR_PER_ADV_LIST BT_OP(BT_OGF_LE, 0x0049) /* 0x2049 */ + +#define BT_HCI_OP_LE_READ_PER_ADV_LIST_SIZE BT_OP(BT_OGF_LE, 0x004a) /* 0x204a */ +struct bt_hci_rp_le_read_per_adv_list_size { + uint8_t status; + uint8_t list_size; +} __packed; + +#define BT_HCI_OP_LE_READ_TX_POWER BT_OP(BT_OGF_LE, 0x004b) /* 0x204b */ +struct bt_hci_rp_le_read_tx_power { + uint8_t status; + int8_t min_tx_power; + int8_t max_tx_power; +} __packed; + +#define BT_HCI_OP_LE_READ_RF_PATH_COMP BT_OP(BT_OGF_LE, 0x004c) /* 0x204c */ +struct bt_hci_rp_le_read_rf_path_comp { + uint8_t status; + int16_t tx_path_comp; + int16_t rx_path_comp; +} __packed; + +#define BT_HCI_OP_LE_WRITE_RF_PATH_COMP BT_OP(BT_OGF_LE, 0x004d) /* 0x204d */ +struct bt_hci_cp_le_write_rf_path_comp { + int16_t tx_path_comp; + int16_t rx_path_comp; +} __packed; + +#define BT_HCI_LE_PRIVACY_MODE_NETWORK 0x00 +#define BT_HCI_LE_PRIVACY_MODE_DEVICE 0x01 + +#define BT_HCI_OP_LE_SET_PRIVACY_MODE BT_OP(BT_OGF_LE, 0x004e) /* 0x204e */ +struct bt_hci_cp_le_set_privacy_mode { + bt_addr_le_t id_addr; + uint8_t mode; +} __packed; + +#define BT_HCI_LE_TEST_CTE_DISABLED 0x00 +#define BT_HCI_LE_TEST_CTE_TYPE_ANY 0x00 +#define BT_HCI_LE_TEST_SLOT_DURATION_ANY 0x00 +#define BT_HCI_LE_TEST_SWITCH_PATTERN_LEN_ANY 0x00 + +#define BT_HCI_OP_LE_RX_TEST_V3 BT_OP(BT_OGF_LE, 0x004f) /* 0x204f */ +struct bt_hci_cp_le_rx_test_v3 { + uint8_t rx_ch; + uint8_t phy; + uint8_t mod_index; + uint8_t expected_cte_len; + uint8_t expected_cte_type; + uint8_t slot_durations; + uint8_t switch_pattern_len; + uint8_t ant_ids[0]; +} __packed; + +#define BT_HCI_OP_LE_TX_TEST_V3 BT_OP(BT_OGF_LE, 0x0050) /* 0x2050 */ + +struct bt_hci_cp_le_tx_test_v3 { + uint8_t tx_ch; + uint8_t test_data_len; + uint8_t pkt_payload; + uint8_t phy; + uint8_t cte_len; + uint8_t cte_type; + uint8_t switch_pattern_len; + uint8_t ant_ids[0]; +} __packed; + +/* Min and max Constant Tone Extension length in 8us units */ +#define BT_HCI_LE_CTE_LEN_MIN 0x2 +#define BT_HCI_LE_CTE_LEN_MAX 0x14 + +#define BT_HCI_LE_AOA_CTE 0x0 +#define BT_HCI_LE_AOD_CTE_1US 0x1 +#define BT_HCI_LE_AOD_CTE_2US 0x2 +#define BT_HCI_LE_NO_CTE 0xFF + +#define BT_HCI_LE_CTE_COUNT_MIN 0x1 +#define BT_HCI_LE_CTE_COUNT_MAX 0x10 + +#define BT_HCI_OP_LE_SET_CL_CTE_TX_PARAMS BT_OP(BT_OGF_LE, 0x0051) /* 0x2051 */ +struct bt_hci_cp_le_set_cl_cte_tx_params { + uint8_t handle; + uint8_t cte_len; + uint8_t cte_type; + uint8_t cte_count; + uint8_t switch_pattern_len; + uint8_t ant_ids[0]; +} __packed; + +#define BT_HCI_OP_LE_SET_CL_CTE_TX_ENABLE BT_OP(BT_OGF_LE, 0x0052) /* 0x2052 */ +struct bt_hci_cp_le_set_cl_cte_tx_enable { + uint8_t handle; + uint8_t cte_enable; +} __packed; + +#define BT_HCI_LE_ANTENNA_SWITCHING_SLOT_1US 0x1 +#define BT_HCI_LE_ANTENNA_SWITCHING_SLOT_2US 0x2 + +#define BT_HCI_LE_SAMPLE_CTE_ALL 0x0 +#define BT_HCI_LE_SAMPLE_CTE_COUNT_MIN 0x1 +#define BT_HCI_LE_SAMPLE_CTE_COUNT_MAX 0x10 + +#define BT_HCI_OP_LE_SET_CL_CTE_SAMPLING_ENABLE BT_OP(BT_OGF_LE, 0x0053) /* 0x2053 */ +struct bt_hci_cp_le_set_cl_cte_sampling_enable { + uint16_t sync_handle; + uint8_t sampling_enable; + uint8_t slot_durations; + uint8_t max_sampled_cte; + uint8_t switch_pattern_len; + uint8_t ant_ids[0]; +} __packed; + +struct bt_hci_rp_le_set_cl_cte_sampling_enable { + uint8_t status; + uint16_t sync_handle; +} __packed; + +#define BT_HCI_OP_LE_SET_CONN_CTE_RX_PARAMS BT_OP(BT_OGF_LE, 0x0054) /* 0x2054 */ +struct bt_hci_cp_le_set_conn_cte_rx_params { + uint16_t handle; + uint8_t sampling_enable; + uint8_t slot_durations; + uint8_t switch_pattern_len; + uint8_t ant_ids[0]; +} __packed; + +struct bt_hci_rp_le_set_conn_cte_rx_params { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_LE_AOA_CTE_RSP BIT(0) +#define BT_HCI_LE_AOD_CTE_RSP_1US BIT(1) +#define BT_HCI_LE_AOD_CTE_RSP_2US BIT(2) + +#define BT_HCI_LE_SWITCH_PATTERN_LEN_MIN 0x2 +#define BT_HCI_LE_SWITCH_PATTERN_LEN_MAX 0x4B + +#define BT_HCI_OP_LE_SET_CONN_CTE_TX_PARAMS BT_OP(BT_OGF_LE, 0x0055) /* 0x2055 */ +struct bt_hci_cp_le_set_conn_cte_tx_params { + uint16_t handle; + uint8_t cte_types; + uint8_t switch_pattern_len; + uint8_t ant_ids[0]; +} __packed; + +struct bt_hci_rp_le_set_conn_cte_tx_params { + uint8_t status; + uint16_t handle; +} __packed; + +/* Interval between consecutive CTE request procedure starts in number of connection events. */ +#define BT_HCI_REQUEST_CTE_ONCE 0x0 +#define BT_HCI_REQUEST_CTE_INTERVAL_MIN 0x1 +#define BT_HCI_REQUEST_CTE_INTERVAL_MAX 0xFFFF + +#define BT_HCI_OP_LE_CONN_CTE_REQ_ENABLE BT_OP(BT_OGF_LE, 0x0056) /* 0x2056 */ +struct bt_hci_cp_le_conn_cte_req_enable { + uint16_t handle; + uint8_t enable; + uint16_t cte_request_interval; + uint8_t requested_cte_length; + uint8_t requested_cte_type; +} __packed; + +struct bt_hci_rp_le_conn_cte_req_enable { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_CONN_CTE_RSP_ENABLE BT_OP(BT_OGF_LE, 0x0057) /* 0x2057 */ +struct bt_hci_cp_le_conn_cte_rsp_enable { + uint16_t handle; + uint8_t enable; +} __packed; + +struct bt_hci_rp_le_conn_cte_rsp_enable { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_LE_1US_AOD_TX BIT(0) +#define BT_HCI_LE_1US_AOD_RX BIT(1) +#define BT_HCI_LE_1US_AOA_RX BIT(2) + +#define BT_HCI_LE_NUM_ANT_MIN 0x1 +#define BT_HCI_LE_NUM_ANT_MAX 0x4B + +#define BT_HCI_LE_MAX_SWITCH_PATTERN_LEN_MIN 0x2 +#define BT_HCI_LE_MAX_SWITCH_PATTERN_LEN_MAX 0x4B + +#define BT_HCI_LE_MAX_CTE_LEN_MIN 0x2 +#define BT_HCI_LE_MAX_CTE_LEN_MAX 0x14 + +#define BT_HCI_OP_LE_READ_ANT_INFO BT_OP(BT_OGF_LE, 0x0058) /* 0x2058 */ +struct bt_hci_rp_le_read_ant_info { + uint8_t status; + uint8_t switch_sample_rates; + uint8_t num_ant; + uint8_t max_switch_pattern_len; + uint8_t max_cte_len; +}; + +#define BT_HCI_LE_SET_PER_ADV_RECV_ENABLE_ENABLE BIT(0) +#define BT_HCI_LE_SET_PER_ADV_RECV_ENABLE_FILTER_DUPLICATE BIT(1) + +#define BT_HCI_OP_LE_SET_PER_ADV_RECV_ENABLE BT_OP(BT_OGF_LE, 0x0059) /* 0x2059 */ +struct bt_hci_cp_le_set_per_adv_recv_enable { + uint16_t handle; + uint8_t enable; +} __packed; + +#define BT_HCI_OP_LE_PER_ADV_SYNC_TRANSFER BT_OP(BT_OGF_LE, 0x005a) /* 0x205a */ +struct bt_hci_cp_le_per_adv_sync_transfer { + uint16_t conn_handle; + uint16_t service_data; + uint16_t sync_handle; +} __packed; + +struct bt_hci_rp_le_per_adv_sync_transfer { + uint8_t status; + uint16_t conn_handle; +} __packed; + +#define BT_HCI_OP_LE_PER_ADV_SET_INFO_TRANSFER BT_OP(BT_OGF_LE, 0x005b) /* 0x205b */ +struct bt_hci_cp_le_per_adv_set_info_transfer { + uint16_t conn_handle; + uint16_t service_data; + uint8_t adv_handle; +} __packed; + +struct bt_hci_rp_le_per_adv_set_info_transfer { + uint8_t status; + uint16_t conn_handle; +} __packed; + +#define BT_HCI_LE_PAST_MODE_NO_SYNC 0x00 +#define BT_HCI_LE_PAST_MODE_NO_REPORTS 0x01 +#define BT_HCI_LE_PAST_MODE_SYNC 0x02 +#define BT_HCI_LE_PAST_MODE_SYNC_FILTER_DUPLICATES 0x03 + +#define BT_HCI_LE_PAST_CTE_TYPE_NO_AOA BIT(0) +#define BT_HCI_LE_PAST_CTE_TYPE_NO_AOD_1US BIT(1) +#define BT_HCI_LE_PAST_CTE_TYPE_NO_AOD_2US BIT(2) +#define BT_HCI_LE_PAST_CTE_TYPE_NO_CTE BIT(3) +#define BT_HCI_LE_PAST_CTE_TYPE_ONLY_CTE BIT(4) + +#define BT_HCI_OP_LE_PAST_PARAM BT_OP(BT_OGF_LE, 0x005c) /* 0x205c */ +struct bt_hci_cp_le_past_param { + uint16_t conn_handle; + uint8_t mode; + uint16_t skip; + uint16_t timeout; + uint8_t cte_type; +} __packed; + +struct bt_hci_rp_le_past_param { + uint8_t status; + uint16_t conn_handle; +} __packed; + +#define BT_HCI_OP_LE_DEFAULT_PAST_PARAM BT_OP(BT_OGF_LE, 0x005d) /* 0x205d */ +struct bt_hci_cp_le_default_past_param { + uint8_t mode; + uint16_t skip; + uint16_t timeout; + uint8_t cte_type; +} __packed; + +struct bt_hci_rp_le_default_past_param { + uint8_t status; +} __packed; + +#define BT_HCI_OP_LE_READ_BUFFER_SIZE_V2 BT_OP(BT_OGF_LE, 0x0060) /* 0x2060 */ +struct bt_hci_rp_le_read_buffer_size_v2 { + uint8_t status; + uint16_t acl_max_len; + uint8_t acl_max_num; + uint16_t iso_max_len; + uint8_t iso_max_num; +} __packed; + +#define BT_HCI_OP_LE_READ_ISO_TX_SYNC BT_OP(BT_OGF_LE, 0x0061) /* 0x2061 */ +struct bt_hci_cp_le_read_iso_tx_sync { + uint16_t handle; +} __packed; + +struct bt_hci_rp_le_read_iso_tx_sync { + uint8_t status; + uint16_t handle; + uint16_t seq; + uint32_t timestamp; + uint8_t offset[3]; +} __packed; + +#define BT_HCI_ISO_CIG_ID_MAX 0xFE +#define BT_HCI_ISO_CIS_COUNT_MAX 0x1F +#define BT_HCI_ISO_SDU_INTERVAL_MIN 0x0000FF +#define BT_HCI_ISO_SDU_INTERVAL_MAX 0x0FFFFF +#define BT_HCI_ISO_WORST_CASE_SCA_VALID_MASK 0x07 +#define BT_HCI_ISO_PACKING_VALID_MASK 0x01 +#define BT_HCI_ISO_FRAMING_VALID_MASK 0x01 +#define BT_HCI_ISO_MAX_TRANSPORT_LATENCY_MIN 0x0005 +#define BT_HCI_ISO_MAX_TRANSPORT_LATENCY_MAX 0x0FA0 +#define BT_HCI_ISO_CIS_ID_VALID_MAX 0xEF +#define BT_HCI_ISO_MAX_SDU_VALID_MASK 0x0FFF +#define BT_HCI_ISO_PHY_VALID_MASK 0x07 +#define BT_HCI_ISO_INTERVAL_MIN 0x0004 +#define BT_HCI_ISO_INTERVAL_MAX 0x0C80 + +#define BT_HCI_OP_LE_SET_CIG_PARAMS BT_OP(BT_OGF_LE, 0x0062) /* 0x2062 */ +struct bt_hci_cis_params { + uint8_t cis_id; + uint16_t c_sdu; + uint16_t p_sdu; + uint8_t c_phy; + uint8_t p_phy; + uint8_t c_rtn; + uint8_t p_rtn; +} __packed; + +struct bt_hci_cp_le_set_cig_params { + uint8_t cig_id; + uint8_t c_interval[3]; + uint8_t p_interval[3]; + uint8_t sca; + uint8_t packing; + uint8_t framing; + uint16_t c_latency; + uint16_t p_latency; + uint8_t num_cis; + struct bt_hci_cis_params cis[0]; +} __packed; + +struct bt_hci_rp_le_set_cig_params { + uint8_t status; + uint8_t cig_id; + uint8_t num_handles; + uint16_t handle[0]; +} __packed; + +#define BT_HCI_OP_LE_SET_CIG_PARAMS_TEST BT_OP(BT_OGF_LE, 0x0063) /* 0x2063 */ +struct bt_hci_cis_params_test { + uint8_t cis_id; + uint8_t nse; + uint16_t c_sdu; + uint16_t p_sdu; + uint16_t c_pdu; + uint16_t p_pdu; + uint8_t c_phy; + uint8_t p_phy; + uint8_t c_bn; + uint8_t p_bn; +} __packed; + +struct bt_hci_cp_le_set_cig_params_test { + uint8_t cig_id; + uint8_t c_interval[3]; + uint8_t p_interval[3]; + uint8_t c_ft; + uint8_t p_ft; + uint16_t iso_interval; + uint8_t sca; + uint8_t packing; + uint8_t framing; + uint8_t num_cis; + struct bt_hci_cis_params_test cis[0]; +} __packed; + +struct bt_hci_rp_le_set_cig_params_test { + uint8_t status; + uint8_t cig_id; + uint8_t num_handles; + uint16_t handle[0]; +} __packed; + +#define BT_HCI_OP_LE_CREATE_CIS BT_OP(BT_OGF_LE, 0x0064) /* 0x2064 */ +struct bt_hci_cis { + uint16_t cis_handle; + uint16_t acl_handle; +} __packed; + +struct bt_hci_cp_le_create_cis { + uint8_t num_cis; + struct bt_hci_cis cis[0]; +} __packed; + +#define BT_HCI_OP_LE_REMOVE_CIG BT_OP(BT_OGF_LE, 0x0065) /* 0x2065 */ +struct bt_hci_cp_le_remove_cig { + uint8_t cig_id; +} __packed; + +struct bt_hci_rp_le_remove_cig { + uint8_t status; + uint8_t cig_id; +} __packed; + +#define BT_HCI_OP_LE_ACCEPT_CIS BT_OP(BT_OGF_LE, 0x0066) /* 0x2066 */ +struct bt_hci_cp_le_accept_cis { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_REJECT_CIS BT_OP(BT_OGF_LE, 0x0067) /* 0x2067 */ +struct bt_hci_cp_le_reject_cis { + uint16_t handle; + uint8_t reason; +} __packed; + +struct bt_hci_rp_le_reject_cis { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_CREATE_BIG BT_OP(BT_OGF_LE, 0x0068) /* 0x2068 */ +struct bt_hci_cp_le_create_big { + uint8_t big_handle; + uint8_t adv_handle; + uint8_t num_bis; + uint8_t sdu_interval[3]; + uint16_t max_sdu; + uint16_t max_latency; + uint8_t rtn; + uint8_t phy; + uint8_t packing; + uint8_t framing; + uint8_t encryption; + uint8_t bcode[16]; +} __packed; + +#define BT_HCI_OP_LE_CREATE_BIG_TEST BT_OP(BT_OGF_LE, 0x0069) /* 0x2069 */ +struct bt_hci_cp_le_create_big_test { + uint8_t big_handle; + uint8_t adv_handle; + uint8_t num_bis; + uint8_t sdu_interval[3]; + uint16_t iso_interval; + uint8_t nse; + uint16_t max_sdu; + uint16_t max_pdu; + uint8_t phy; + uint8_t packing; + uint8_t framing; + uint8_t bn; + uint8_t irc; + uint8_t pto; + uint8_t encryption; + uint8_t bcode[16]; +} __packed; + +#define BT_HCI_OP_LE_TERMINATE_BIG BT_OP(BT_OGF_LE, 0x006a) /* 0x206a */ +struct bt_hci_cp_le_terminate_big { + uint8_t big_handle; + uint8_t reason; +} __packed; + +#define BT_HCI_OP_LE_BIG_CREATE_SYNC BT_OP(BT_OGF_LE, 0x006b) /* 0x206b */ +struct bt_hci_cp_le_big_create_sync { + uint8_t big_handle; + uint16_t sync_handle; + uint8_t encryption; + uint8_t bcode[16]; + uint8_t mse; + uint16_t sync_timeout; + uint8_t num_bis; + uint8_t bis[0]; +} __packed; + +#define BT_HCI_OP_LE_BIG_TERMINATE_SYNC BT_OP(BT_OGF_LE, 0x006c) /* 0x206c */ +struct bt_hci_cp_le_big_terminate_sync { + uint8_t big_handle; +} __packed; + +struct bt_hci_rp_le_big_terminate_sync { + uint8_t status; + uint8_t big_handle; +} __packed; + +#define BT_HCI_OP_LE_REQ_PEER_SC BT_OP(BT_OGF_LE, 0x006d) /* 0x206d */ +struct bt_hci_cp_le_req_peer_sca { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_SETUP_ISO_PATH BT_OP(BT_OGF_LE, 0x006e) /* 0x206e */ +struct bt_hci_cp_le_setup_iso_path { + uint16_t handle; + uint8_t path_dir; + uint8_t path_id; + struct bt_hci_cp_codec_id codec_id; + uint8_t controller_delay[3]; + uint8_t codec_config_len; + uint8_t codec_config[0]; +} __packed; + +struct bt_hci_rp_le_setup_iso_path { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_REMOVE_ISO_PATH BT_OP(BT_OGF_LE, 0x006f) /* 0x206f */ +struct bt_hci_cp_le_remove_iso_path { + uint16_t handle; + uint8_t path_dir; +} __packed; + +struct bt_hci_rp_le_remove_iso_path { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_ISO_TEST_ZERO_SIZE_SDU 0 +#define BT_HCI_ISO_TEST_VARIABLE_SIZE_SDU 1 +#define BT_HCI_ISO_TEST_MAX_SIZE_SDU 2 + +#define BT_HCI_OP_LE_ISO_TRANSMIT_TEST BT_OP(BT_OGF_LE, 0x0070) /* 0x2070 */ +struct bt_hci_cp_le_iso_transmit_test { + uint16_t handle; + uint8_t payload_type; +} __packed; + +struct bt_hci_rp_le_iso_transmit_test { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_ISO_RECEIVE_TEST BT_OP(BT_OGF_LE, 0x0071) /* 0x2071 */ +struct bt_hci_cp_le_iso_receive_test { + uint16_t handle; + uint8_t payload_type; +} __packed; + +struct bt_hci_rp_le_iso_receive_test { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_ISO_READ_TEST_COUNTERS BT_OP(BT_OGF_LE, 0x0072) /* 0x2072 */ +struct bt_hci_cp_le_read_test_counters { + uint16_t handle; +} __packed; + +struct bt_hci_rp_le_read_test_counters { + uint8_t status; + uint16_t handle; + uint32_t received_cnt; + uint32_t missed_cnt; + uint32_t failed_cnt; +} __packed; + +#define BT_HCI_OP_LE_ISO_TEST_END BT_OP(BT_OGF_LE, 0x0073) /* 0x2073 */ +struct bt_hci_cp_le_iso_test_end { + uint16_t handle; +} __packed; + +struct bt_hci_rp_le_iso_test_end { + uint8_t status; + uint16_t handle; + uint32_t received_cnt; + uint32_t missed_cnt; + uint32_t failed_cnt; +} __packed; + +#define BT_HCI_OP_LE_SET_HOST_FEATURE BT_OP(BT_OGF_LE, 0x0074) /* 0x2074 */ +struct bt_hci_cp_le_set_host_feature { + uint8_t bit_number; + uint8_t bit_value; +} __packed; + +struct bt_hci_rp_le_set_host_feature { + uint8_t status; +} __packed; + +#define BT_HCI_OP_LE_READ_ISO_LINK_QUALITY BT_OP(BT_OGF_LE, 0x0075) /* 0x2075 */ +struct bt_hci_cp_le_read_iso_link_quality { + uint16_t handle; +} __packed; + +struct bt_hci_rp_le_read_iso_link_quality { + uint8_t status; + uint16_t handle; + uint32_t tx_unacked_packets; + uint32_t tx_flushed_packets; + uint32_t tx_last_subevent_packets; + uint32_t retransmitted_packets; + uint32_t crc_error_packets; + uint32_t rx_unreceived_packets; + uint32_t duplicate_packets; +} __packed; + +#define BT_HCI_OP_LE_TX_TEST_V4 BT_OP(BT_OGF_LE, 0x007B) /* 0x207B */ + +struct bt_hci_cp_le_tx_test_v4 { + uint8_t tx_ch; + uint8_t test_data_len; + uint8_t pkt_payload; + uint8_t phy; + uint8_t cte_len; + uint8_t cte_type; + uint8_t switch_pattern_len; + uint8_t ant_ids[0]; +} __packed; + +#define BT_HCI_TX_TEST_POWER_MIN -0x7F +#define BT_HCI_TX_TEST_POWER_MAX 0x14 + +#define BT_HCI_TX_TEST_POWER_MIN_SET 0x7E +#define BT_HCI_TX_TEST_POWER_MAX_SET 0x7F + +/* Helper structure for Tx power parameter in the HCI Tx Test v4 command. + * Previous parameter of this command is variable size so having separated structure + * for this parameter helps in command parameters unpacking. + */ +struct bt_hci_cp_le_tx_test_v4_tx_power { + int8_t tx_power; +} __packed; + +#define BT_HCI_OP_LE_CS_READ_LOCAL_SUPPORTED_CAPABILITIES BT_OP(BT_OGF_LE, 0x0089) /* 0x2089 */ + +struct bt_hci_rp_le_read_local_supported_capabilities { + uint8_t status; + uint8_t num_config_supported; + uint16_t max_consecutive_procedures_supported; + uint8_t num_antennas_supported; + uint8_t max_antenna_paths_supported; + uint8_t roles_supported; + uint8_t modes_supported; + uint8_t rtt_capability; + uint8_t rtt_aa_only_n; + uint8_t rtt_sounding_n; + uint8_t rtt_random_payload_n; + uint16_t nadm_sounding_capability; + uint16_t nadm_random_capability; + uint8_t cs_sync_phys_supported; + uint16_t subfeatures_supported; + uint16_t t_ip1_times_supported; + uint16_t t_ip2_times_supported; + uint16_t t_fcs_times_supported; + uint16_t t_pm_times_supported; + uint8_t t_sw_time_supported; + uint8_t tx_snr_capability; +} __packed; + +#define BT_HCI_OP_LE_CS_READ_REMOTE_SUPPORTED_CAPABILITIES BT_OP(BT_OGF_LE, 0x008A) /* 0x208A */ + +struct bt_hci_cp_le_read_remote_supported_capabilities { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_CS_WRITE_CACHED_REMOTE_SUPPORTED_CAPABILITIES \ + BT_OP(BT_OGF_LE, 0x008B) /* 0x208B */ + +struct bt_hci_cp_le_write_cached_remote_supported_capabilities { + uint16_t handle; + uint8_t num_config_supported; + uint16_t max_consecutive_procedures_supported; + uint8_t num_antennas_supported; + uint8_t max_antenna_paths_supported; + uint8_t roles_supported; + uint8_t modes_supported; + uint8_t rtt_capability; + uint8_t rtt_aa_only_n; + uint8_t rtt_sounding_n; + uint8_t rtt_random_payload_n; + uint16_t nadm_sounding_capability; + uint16_t nadm_random_capability; + uint8_t cs_sync_phys_supported; + uint16_t subfeatures_supported; + uint16_t t_ip1_times_supported; + uint16_t t_ip2_times_supported; + uint16_t t_fcs_times_supported; + uint16_t t_pm_times_supported; + uint8_t t_sw_time_supported; + uint8_t tx_snr_capability; +} __packed; + +#define BT_HCI_OP_LE_CS_SECURITY_ENABLE BT_OP(BT_OGF_LE, 0x008C) /* 0x208C */ + +struct bt_hci_cp_le_security_enable { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_CS_SET_DEFAULT_SETTINGS BT_OP(BT_OGF_LE, 0x008D) /* 0x208D */ + +#define BT_HCI_OP_LE_CS_INITIATOR_ROLE_MASK BIT(0) +#define BT_HCI_OP_LE_CS_REFLECTOR_ROLE_MASK BIT(1) + +#define BT_HCI_OP_LE_CS_MIN_MAX_TX_POWER -127 +#define BT_HCI_OP_LE_CS_MAX_MAX_TX_POWER 20 + +#define BT_HCI_OP_LE_CS_ANTENNA_SEL_ONE 0x01 +#define BT_HCI_OP_LE_CS_ANTENNA_SEL_TWO 0x02 +#define BT_HCI_OP_LE_CS_ANTENNA_SEL_THREE 0x03 +#define BT_HCI_OP_LE_CS_ANTENNA_SEL_FOUR 0x04 +#define BT_HCI_OP_LE_CS_ANTENNA_SEL_REP 0xFE +#define BT_HCI_OP_LE_CS_ANTENNA_SEL_NONE 0xFF + +struct bt_hci_cp_le_cs_set_default_settings { + uint16_t handle; + uint8_t role_enable; + uint8_t cs_sync_antenna_selection; + int8_t max_tx_power; +} __packed; + +#define BT_HCI_OP_LE_CS_READ_REMOTE_FAE_TABLE BT_OP(BT_OGF_LE, 0x008E) /* 0x208E */ + +struct bt_hci_cp_le_read_remote_fae_table { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_CS_WRITE_CACHED_REMOTE_FAE_TABLE BT_OP(BT_OGF_LE, 0x008F) /* 0x208F */ + +struct bt_hci_cp_le_write_cached_remote_fae_table { + uint16_t handle; + uint8_t remote_fae_table[72]; +} __packed; + +#define BT_HCI_OP_LE_CS_SET_CHANNEL_CLASSIFICATION BT_OP(BT_OGF_LE, 0x0092) /* 0x2092 */ + +#define BT_HCI_OP_LE_CS_SET_PROCEDURE_PARAMETERS BT_OP(BT_OGF_LE, 0x0093) /* 0x2093 */ + +#define BT_HCI_OP_LE_CS_PROCEDURE_PHY_1M 0x01 +#define BT_HCI_OP_LE_CS_PROCEDURE_PHY_2M 0x02 +#define BT_HCI_OP_LE_CS_PROCEDURE_PHY_CODED_S8 0x03 +#define BT_HCI_OP_LE_CS_PROCEDURE_PHY_CODED_S2 0x04 + +struct bt_hci_cp_le_set_procedure_parameters { + uint16_t handle; + uint8_t config_id; + uint16_t max_procedure_len; + uint16_t min_procedure_interval; + uint16_t max_procedure_interval; + uint16_t max_procedure_count; + uint8_t min_subevent_len[3]; + uint8_t max_subevent_len[3]; + uint8_t tone_antenna_config_selection; + uint8_t phy; + uint8_t tx_power_delta; + uint8_t preferred_peer_antenna; + uint8_t snr_control_initiator; + uint8_t snr_control_reflector; +} __packed; + +#define BT_HCI_OP_LE_CS_PROCEDURE_ENABLE BT_OP(BT_OGF_LE, 0x0094) /* 0x2094 */ + +#define BT_HCI_OP_LE_CS_PROCEDURES_DISABLED 0x00 +#define BT_HCI_OP_LE_CS_PROCEDURES_ENABLED 0x01 + +struct bt_hci_cp_le_procedure_enable { + uint16_t handle; + uint8_t config_id; + uint8_t enable; +} __packed; + +#define BT_HCI_OP_LE_CS_TEST BT_OP(BT_OGF_LE, 0x0095) /* 0x2095 */ + +#define BT_HCI_OP_LE_CS_MAIN_MODE_1 0x1 +#define BT_HCI_OP_LE_CS_MAIN_MODE_2 0x2 +#define BT_HCI_OP_LE_CS_MAIN_MODE_3 0x3 + +#define BT_HCI_OP_LE_CS_SUB_MODE_1 0x1 +#define BT_HCI_OP_LE_CS_SUB_MODE_2 0x2 +#define BT_HCI_OP_LE_CS_SUB_MODE_3 0x3 +#define BT_HCI_OP_LE_CS_SUB_MODE_UNUSED 0xFF + +#define BT_HCI_OP_LE_CS_INITIATOR_ROLE 0x0 +#define BT_HCI_OP_LE_CS_REFLECTOR_ROLE 0x1 + +#define BT_HCI_OP_LE_CS_RTT_TYPE_AA_ONLY 0x0 +#define BT_HCI_OP_LE_CS_RTT_TYPE_32BIT_SOUND 0x1 +#define BT_HCI_OP_LE_CS_RTT_TYPE_96BIT_SOUND 0x2 +#define BT_HCI_OP_LE_CS_RTT_TYPE_32BIT_RAND 0x3 +#define BT_HCI_OP_LE_CS_RTT_TYPE_64BIT_RAND 0x4 +#define BT_HCI_OP_LE_CS_RTT_TYPE_96BIT_RAND 0x5 +#define BT_HCI_OP_LE_CS_RTT_TYPE_128BIT_RAND 0x6 + +#define BT_HCI_OP_LE_CS_CS_SYNC_1M 0x1 +#define BT_HCI_OP_LE_CS_CS_SYNC_2M 0x2 +#define BT_HCI_OP_LE_CS_CS_SYNC_2M_2BT 0x3 + +#define BT_HCI_OP_LE_CS_TEST_MINIMIZE_TX_POWER 0x7E +#define BT_HCI_OP_LE_CS_TEST_MAXIMIZE_TX_POWER 0x7F + +#define BT_HCI_OP_LE_CS_ACI_0 0x0 +#define BT_HCI_OP_LE_CS_ACI_1 0x1 +#define BT_HCI_OP_LE_CS_ACI_2 0x2 +#define BT_HCI_OP_LE_CS_ACI_3 0x3 +#define BT_HCI_OP_LE_CS_ACI_4 0x4 +#define BT_HCI_OP_LE_CS_ACI_5 0x5 +#define BT_HCI_OP_LE_CS_ACI_6 0x6 +#define BT_HCI_OP_LE_CS_ACI_7 0x7 + +#define BT_HCI_OP_LE_CS_INITIATOR_SNR_18 0x0 +#define BT_HCI_OP_LE_CS_INITIATOR_SNR_21 0x1 +#define BT_HCI_OP_LE_CS_INITIATOR_SNR_24 0x2 +#define BT_HCI_OP_LE_CS_INITIATOR_SNR_27 0x3 +#define BT_HCI_OP_LE_CS_INITIATOR_SNR_30 0x4 +#define BT_HCI_OP_LE_CS_INITIATOR_SNR_NOT_USED 0xFF + +#define BT_HCI_OP_LE_CS_REFLECTOR_SNR_18 0x0 +#define BT_HCI_OP_LE_CS_REFLECTOR_SNR_21 0x1 +#define BT_HCI_OP_LE_CS_REFLECTOR_SNR_24 0x2 +#define BT_HCI_OP_LE_CS_REFLECTOR_SNR_27 0x3 +#define BT_HCI_OP_LE_CS_REFLECTOR_SNR_30 0x4 +#define BT_HCI_OP_LE_CS_REFLECTOR_SNR_NOT_USED 0xFF + +#define BT_HCI_OP_LE_CS_TEST_OVERRIDE_CONFIG_0_MASK BIT(0) +#define BT_HCI_OP_LE_CS_TEST_OVERRIDE_CONFIG_2_MASK BIT(2) +#define BT_HCI_OP_LE_CS_TEST_OVERRIDE_CONFIG_3_MASK BIT(3) +#define BT_HCI_OP_LE_CS_TEST_OVERRIDE_CONFIG_4_MASK BIT(4) +#define BT_HCI_OP_LE_CS_TEST_OVERRIDE_CONFIG_5_MASK BIT(5) +#define BT_HCI_OP_LE_CS_TEST_OVERRIDE_CONFIG_6_MASK BIT(6) +#define BT_HCI_OP_LE_CS_TEST_OVERRIDE_CONFIG_7_MASK BIT(7) +#define BT_HCI_OP_LE_CS_TEST_OVERRIDE_CONFIG_8_MASK BIT(8) +#define BT_HCI_OP_LE_CS_TEST_OVERRIDE_CONFIG_10_MASK BIT(10) + +#define BT_HCI_OP_LE_CS_TEST_CHSEL_TYPE_3B 0x0 +#define BT_HCI_OP_LE_CS_TEST_CHSEL_TYPE_3C 0x1 + +#define BT_HCI_OP_LE_CS_TEST_CH3C_SHAPE_HAT 0x0 +#define BT_HCI_OP_LE_CS_TEST_CH3C_SHAPE_X 0x1 + +#define BT_HCI_OP_LE_CS_TEST_TONE_EXT_NONE 0x0 +#define BT_HCI_OP_LE_CS_TEST_TONE_EXT_INIT 0x1 +#define BT_HCI_OP_LE_CS_TEST_TONE_EXT_REFL 0x2 +#define BT_HCI_OP_LE_CS_TEST_TONE_EXT_BOTH 0x3 +#define BT_HCI_OP_LE_CS_TEST_TONE_EXT_REPEAT 0x4 + +#define BT_HCI_OP_LE_CS_TEST_AP_INDEX_00 0x0 +#define BT_HCI_OP_LE_CS_TEST_AP_INDEX_01 0x1 +#define BT_HCI_OP_LE_CS_TEST_AP_INDEX_02 0x2 +#define BT_HCI_OP_LE_CS_TEST_AP_INDEX_03 0x3 +#define BT_HCI_OP_LE_CS_TEST_AP_INDEX_04 0x4 +#define BT_HCI_OP_LE_CS_TEST_AP_INDEX_05 0x5 +#define BT_HCI_OP_LE_CS_TEST_AP_INDEX_06 0x6 +#define BT_HCI_OP_LE_CS_TEST_AP_INDEX_07 0x7 +#define BT_HCI_OP_LE_CS_TEST_AP_INDEX_08 0x8 +#define BT_HCI_OP_LE_CS_TEST_AP_INDEX_09 0x9 +#define BT_HCI_OP_LE_CS_TEST_AP_INDEX_10 0xA +#define BT_HCI_OP_LE_CS_TEST_AP_INDEX_11 0xB +#define BT_HCI_OP_LE_CS_TEST_AP_INDEX_12 0xC +#define BT_HCI_OP_LE_CS_TEST_AP_INDEX_13 0xD +#define BT_HCI_OP_LE_CS_TEST_AP_INDEX_14 0xE +#define BT_HCI_OP_LE_CS_TEST_AP_INDEX_15 0xF +#define BT_HCI_OP_LE_CS_TEST_AP_INDEX_16 0x10 +#define BT_HCI_OP_LE_CS_TEST_AP_INDEX_17 0x11 +#define BT_HCI_OP_LE_CS_TEST_AP_INDEX_18 0x12 +#define BT_HCI_OP_LE_CS_TEST_AP_INDEX_19 0x13 +#define BT_HCI_OP_LE_CS_TEST_AP_INDEX_20 0x14 +#define BT_HCI_OP_LE_CS_TEST_AP_INDEX_21 0x15 +#define BT_HCI_OP_LE_CS_TEST_AP_INDEX_22 0x16 +#define BT_HCI_OP_LE_CS_TEST_AP_INDEX_23 0x17 +#define BT_HCI_OP_LE_CS_TEST_AP_INDEX_LOOP 0xFF + +#define BT_HCI_OP_LE_CS_TEST_SS_MARKER_2_POSITION_NOT_PRESENT 0xFF + +#define BT_HCI_OP_LE_CS_TEST_SS_MARKER_VAL_0011 0x0 +#define BT_HCI_OP_LE_CS_TEST_SS_MARKER_VAL_1100 0x1 +#define BT_HCI_OP_LE_CS_TEST_SS_MARKER_VAL_LOOP 0x2 + +#define BT_HCI_OP_LE_CS_TEST_PAYLOAD_PRBS9 0x00 +#define BT_HCI_OP_LE_CS_TEST_PAYLOAD_11110000 0x01 +#define BT_HCI_OP_LE_CS_TEST_PAYLOAD_10101010 0x02 +#define BT_HCI_OP_LE_CS_TEST_PAYLOAD_PRBS15 0x03 +#define BT_HCI_OP_LE_CS_TEST_PAYLOAD_11111111 0x04 +#define BT_HCI_OP_LE_CS_TEST_PAYLOAD_00000000 0x05 +#define BT_HCI_OP_LE_CS_TEST_PAYLOAD_00001111 0x06 +#define BT_HCI_OP_LE_CS_TEST_PAYLOAD_01010101 0x07 +#define BT_HCI_OP_LE_CS_TEST_PAYLOAD_USER 0x80 + +struct bt_hci_op_le_cs_test { + uint8_t main_mode_type; + uint8_t sub_mode_type; + uint8_t main_mode_repetition; + uint8_t mode_0_steps; + uint8_t role; + uint8_t rtt_type; + uint8_t cs_sync_phy; + uint8_t cs_sync_antenna_selection; + uint8_t subevent_len[3]; + uint16_t subevent_interval; + uint8_t max_num_subevents; + uint8_t transmit_power_level; + uint8_t t_ip1_time; + uint8_t t_ip2_time; + uint8_t t_fcs_time; + uint8_t t_pm_time; + uint8_t t_sw_time; + uint8_t tone_antenna_config_selection; + uint8_t reserved; + uint8_t snr_control_initiator; + uint8_t snr_control_reflector; + uint16_t drbg_nonce; + uint8_t channel_map_repetition; + uint16_t override_config; + uint8_t override_parameters_length; + uint8_t override_parameters_data[]; +} __packed; + +#define BT_HCI_OP_LE_CS_CREATE_CONFIG BT_OP(BT_OGF_LE, 0x0090) /* 0x2090 */ + +struct bt_hci_cp_le_cs_create_config { + uint16_t handle; + uint8_t config_id; + uint8_t create_context; + uint8_t main_mode_type; + uint8_t sub_mode_type; + uint8_t min_main_mode_steps; + uint8_t max_main_mode_steps; + uint8_t main_mode_repetition; + uint8_t mode_0_steps; + uint8_t role; + uint8_t rtt_type; + uint8_t cs_sync_phy; + uint8_t channel_map[10]; + uint8_t channel_map_repetition; + uint8_t channel_selection_type; + uint8_t ch3c_shape; + uint8_t ch3c_jump; + uint8_t reserved; +} __packed; + +#define BT_HCI_OP_LE_CS_REMOVE_CONFIG BT_OP(BT_OGF_LE, 0x0091) /* 0x2091 */ + +struct bt_hci_cp_le_cs_remove_config { + uint16_t handle; + uint8_t config_id; +} __packed; + +#define BT_HCI_OP_LE_CS_TEST_END BT_OP(BT_OGF_LE, 0x0096) /* 0x2096 */ + +/* Event definitions */ + +#define BT_HCI_EVT_UNKNOWN 0x00 +#define BT_HCI_EVT_VENDOR 0xff + +#define BT_HCI_EVT_INQUIRY_COMPLETE 0x01 +struct bt_hci_evt_inquiry_complete { + uint8_t status; +} __packed; + +#define BT_HCI_EVT_CONN_COMPLETE 0x03 +struct bt_hci_evt_conn_complete { + uint8_t status; + uint16_t handle; + bt_addr_t bdaddr; + uint8_t link_type; + uint8_t encr_enabled; +} __packed; + +#define BT_HCI_EVT_CONN_REQUEST 0x04 +struct bt_hci_evt_conn_request { + bt_addr_t bdaddr; + uint8_t dev_class[3]; + uint8_t link_type; +} __packed; + +#define BT_HCI_EVT_DISCONN_COMPLETE 0x05 +struct bt_hci_evt_disconn_complete { + uint8_t status; + uint16_t handle; + uint8_t reason; +} __packed; + +#define BT_HCI_EVT_AUTH_COMPLETE 0x06 +struct bt_hci_evt_auth_complete { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_EVT_REMOTE_NAME_REQ_COMPLETE 0x07 +struct bt_hci_evt_remote_name_req_complete { + uint8_t status; + bt_addr_t bdaddr; + uint8_t name[248]; +} __packed; + +#define BT_HCI_EVT_ENCRYPT_CHANGE 0x08 +struct bt_hci_evt_encrypt_change { + uint8_t status; + uint16_t handle; + uint8_t encrypt; +} __packed; + +#define BT_HCI_EVT_REMOTE_FEATURES 0x0b +struct bt_hci_evt_remote_features { + uint8_t status; + uint16_t handle; + uint8_t features[8]; +} __packed; + +#define BT_HCI_EVT_REMOTE_VERSION_INFO 0x0c +struct bt_hci_evt_remote_version_info { + uint8_t status; + uint16_t handle; + uint8_t version; + uint16_t manufacturer; + uint16_t subversion; +} __packed; + +#define BT_HCI_EVT_CMD_COMPLETE 0x0e +struct bt_hci_evt_cmd_complete { + uint8_t ncmd; + uint16_t opcode; +} __packed; + +struct bt_hci_evt_cc_status { + uint8_t status; +} __packed; + +#define BT_HCI_EVT_CMD_STATUS 0x0f +struct bt_hci_evt_cmd_status { + uint8_t status; + uint8_t ncmd; + uint16_t opcode; +} __packed; + +#define BT_HCI_EVT_HARDWARE_ERROR 0x10 +struct bt_hci_evt_hardware_error { + uint8_t hardware_code; +} __packed; + +#define BT_HCI_EVT_ROLE_CHANGE 0x12 +struct bt_hci_evt_role_change { + uint8_t status; + bt_addr_t bdaddr; + uint8_t role; +} __packed; + +#define BT_HCI_EVT_NUM_COMPLETED_PACKETS 0x13 +struct bt_hci_evt_num_completed_packets { + uint8_t num_handles; + struct bt_hci_handle_count h[0]; +} __packed; + +#define BT_HCI_EVT_PIN_CODE_REQ 0x16 +struct bt_hci_evt_pin_code_req { + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_EVT_LINK_KEY_REQ 0x17 +struct bt_hci_evt_link_key_req { + bt_addr_t bdaddr; +} __packed; + +/* Link Key types */ +#define BT_LK_COMBINATION 0x00 +#define BT_LK_LOCAL_UNIT 0x01 +#define BT_LK_REMOTE_UNIT 0x02 +#define BT_LK_DEBUG_COMBINATION 0x03 +#define BT_LK_UNAUTH_COMBINATION_P192 0x04 +#define BT_LK_AUTH_COMBINATION_P192 0x05 +#define BT_LK_CHANGED_COMBINATION 0x06 +#define BT_LK_UNAUTH_COMBINATION_P256 0x07 +#define BT_LK_AUTH_COMBINATION_P256 0x08 + +#define BT_HCI_EVT_LINK_KEY_NOTIFY 0x18 +struct bt_hci_evt_link_key_notify { + bt_addr_t bdaddr; + uint8_t link_key[16]; + uint8_t key_type; +} __packed; + +/* Overflow link types */ +#define BT_OVERFLOW_LINK_SYNCH 0x00 +#define BT_OVERFLOW_LINK_ACL 0x01 +#define BT_OVERFLOW_LINK_ISO 0x02 + +#define BT_HCI_EVT_DATA_BUF_OVERFLOW 0x1a +struct bt_hci_evt_data_buf_overflow { + uint8_t link_type; +} __packed; + +#define BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI 0x22 +struct bt_hci_evt_inquiry_result_with_rssi { + bt_addr_t addr; + uint8_t pscan_rep_mode; + uint8_t reserved; + uint8_t cod[3]; + uint16_t clock_offset; + int8_t rssi; +} __packed; + +#define BT_HCI_EVT_REMOTE_EXT_FEATURES 0x23 +struct bt_hci_evt_remote_ext_features { + uint8_t status; + uint16_t handle; + uint8_t page; + uint8_t max_page; + uint8_t features[8]; +} __packed; + +#define BT_HCI_EVT_LE_PER_ADV_SYNC_ESTABLISHED_V2 0x24 +struct bt_hci_evt_le_per_adv_sync_established_v2 { + uint8_t status; + uint16_t handle; + uint8_t sid; + bt_addr_le_t adv_addr; + uint8_t phy; + uint16_t interval; + uint8_t clock_accuracy; + uint8_t num_subevents; + uint8_t subevent_interval; + uint8_t response_slot_delay; + uint8_t response_slot_spacing; +} __packed; + +#define BT_HCI_EVT_LE_PER_ADVERTISING_REPORT_V2 0x25 +struct bt_hci_evt_le_per_advertising_report_v2 { + uint16_t handle; + int8_t tx_power; + int8_t rssi; + uint8_t cte_type; + uint16_t periodic_event_counter; + uint8_t subevent; + uint8_t data_status; + uint8_t length; + uint8_t data[0]; +} __packed; + +#define BT_HCI_EVT_LE_PAST_RECEIVED_V2 0x26 +struct bt_hci_evt_le_past_received_v2 { + uint8_t status; + uint16_t conn_handle; + uint16_t service_data; + uint16_t sync_handle; + uint8_t adv_sid; + bt_addr_le_t addr; + uint8_t phy; + uint16_t interval; + uint8_t clock_accuracy; + uint8_t num_subevents; + uint8_t subevent_interval; + uint8_t response_slot_delay; + uint8_t response_slot_spacing; +} __packed; + +#define BT_HCI_EVT_LE_PER_ADV_SUBEVENT_DATA_REQUEST 0x27 +struct bt_hci_evt_le_per_adv_subevent_data_request { + uint8_t adv_handle; + uint8_t subevent_start; + uint8_t subevent_data_count; +} __packed; + +#define BT_HCI_EVT_LE_PER_ADV_RESPONSE_REPORT 0x28 + +struct bt_hci_evt_le_per_adv_response { + int8_t tx_power; + int8_t rssi; + uint8_t cte_type; + uint8_t response_slot; + uint8_t data_status; + uint8_t data_length; + uint8_t data[0]; +} __packed; + +struct bt_hci_evt_le_per_adv_response_report { + uint8_t adv_handle; + uint8_t subevent; + uint8_t tx_status; + uint8_t num_responses; + struct bt_hci_evt_le_per_adv_response responses[0]; +} __packed; + +#define BT_HCI_EVT_LE_ENH_CONN_COMPLETE_V2 0x29 +struct bt_hci_evt_le_enh_conn_complete_v2 { + uint8_t status; + uint16_t handle; + uint8_t role; + bt_addr_le_t peer_addr; + bt_addr_t local_rpa; + bt_addr_t peer_rpa; + uint16_t interval; + uint16_t latency; + uint16_t supv_timeout; + uint8_t clock_accuracy; + uint8_t adv_handle; + uint16_t sync_handle; +} __packed; + +#define BT_HCI_EVT_SYNC_CONN_COMPLETE 0x2c +struct bt_hci_evt_sync_conn_complete { + uint8_t status; + uint16_t handle; + bt_addr_t bdaddr; + uint8_t link_type; + uint8_t tx_interval; + uint8_t retansmission_window; + uint16_t rx_pkt_length; + uint16_t tx_pkt_length; + uint8_t air_mode; +} __packed; + +#define BT_HCI_EVT_EXTENDED_INQUIRY_RESULT 0x2f +struct bt_hci_evt_extended_inquiry_result { + uint8_t num_reports; + bt_addr_t addr; + uint8_t pscan_rep_mode; + uint8_t reserved; + uint8_t cod[3]; + uint16_t clock_offset; + int8_t rssi; + uint8_t eir[240]; +} __packed; + +#define BT_HCI_EVT_ENCRYPT_KEY_REFRESH_COMPLETE 0x30 +struct bt_hci_evt_encrypt_key_refresh_complete { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_EVT_IO_CAPA_REQ 0x31 +struct bt_hci_evt_io_capa_req { + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_EVT_IO_CAPA_RESP 0x32 +struct bt_hci_evt_io_capa_resp { + bt_addr_t bdaddr; + uint8_t capability; + uint8_t oob_data; + uint8_t authentication; +} __packed; + +#define BT_HCI_EVT_USER_CONFIRM_REQ 0x33 +struct bt_hci_evt_user_confirm_req { + bt_addr_t bdaddr; + uint32_t passkey; +} __packed; + +#define BT_HCI_EVT_USER_PASSKEY_REQ 0x34 +struct bt_hci_evt_user_passkey_req { + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_EVT_SSP_COMPLETE 0x36 +struct bt_hci_evt_ssp_complete { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_EVT_USER_PASSKEY_NOTIFY 0x3b +struct bt_hci_evt_user_passkey_notify { + bt_addr_t bdaddr; + uint32_t passkey; +} __packed; + +#define BT_HCI_EVT_LE_META_EVENT 0x3e +struct bt_hci_evt_le_meta_event { + uint8_t subevent; +} __packed; + +#define BT_HCI_EVT_AUTH_PAYLOAD_TIMEOUT_EXP 0x57 +struct bt_hci_evt_auth_payload_timeout_exp { + uint16_t handle; +} __packed; + +#define BT_HCI_ROLE_CENTRAL 0x00 +#define BT_HCI_ROLE_PERIPHERAL 0x01 + +#define BT_HCI_EVT_LE_CONN_COMPLETE 0x01 +struct bt_hci_evt_le_conn_complete { + uint8_t status; + uint16_t handle; + uint8_t role; + bt_addr_le_t peer_addr; + uint16_t interval; + uint16_t latency; + uint16_t supv_timeout; + uint8_t clock_accuracy; +} __packed; + +#define BT_HCI_LE_RSSI_NOT_AVAILABLE 0x7F + +#define BT_HCI_EVT_LE_ADVERTISING_REPORT 0x02 +struct bt_hci_evt_le_advertising_info { + uint8_t evt_type; + bt_addr_le_t addr; + uint8_t length; + uint8_t data[0]; +} __packed; +struct bt_hci_evt_le_advertising_report { + uint8_t num_reports; + struct bt_hci_evt_le_advertising_info adv_info[0]; +} __packed; + +/** All limits according to BT Core Spec v5.4 [Vol 4, Part E]. */ +#define BT_HCI_LE_INTERVAL_MIN 0x0006 +#define BT_HCI_LE_INTERVAL_MAX 0x0c80 +#define BT_HCI_LE_PERIPHERAL_LATENCY_MAX 0x01f3 +#define BT_HCI_LE_SUPERVISON_TIMEOUT_MIN 0x000a +#define BT_HCI_LE_SUPERVISON_TIMEOUT_MAX 0x0c80 + +#define BT_HCI_EVT_LE_CONN_UPDATE_COMPLETE 0x03 +struct bt_hci_evt_le_conn_update_complete { + uint8_t status; + uint16_t handle; + uint16_t interval; + uint16_t latency; + uint16_t supv_timeout; +} __packed; + +#define BT_HCI_EVT_LE_REMOTE_FEAT_COMPLETE 0x04 +struct bt_hci_evt_le_remote_feat_complete { + uint8_t status; + uint16_t handle; + uint8_t features[8]; +} __packed; + +#define BT_HCI_EVT_LE_LTK_REQUEST 0x05 +struct bt_hci_evt_le_ltk_request { + uint16_t handle; + uint64_t rand; + uint16_t ediv; +} __packed; + +#define BT_HCI_EVT_LE_CONN_PARAM_REQ 0x06 +struct bt_hci_evt_le_conn_param_req { + uint16_t handle; + uint16_t interval_min; + uint16_t interval_max; + uint16_t latency; + uint16_t timeout; +} __packed; + +#define BT_HCI_EVT_LE_DATA_LEN_CHANGE 0x07 +struct bt_hci_evt_le_data_len_change { + uint16_t handle; + uint16_t max_tx_octets; + uint16_t max_tx_time; + uint16_t max_rx_octets; + uint16_t max_rx_time; +} __packed; + +#define BT_HCI_EVT_LE_P256_PUBLIC_KEY_COMPLETE 0x08 +struct bt_hci_evt_le_p256_public_key_complete { + uint8_t status; + uint8_t key[64]; +} __packed; + +#define BT_HCI_EVT_LE_GENERATE_DHKEY_COMPLETE 0x09 +struct bt_hci_evt_le_generate_dhkey_complete { + uint8_t status; + uint8_t dhkey[32]; +} __packed; + +#define BT_HCI_EVT_LE_ENH_CONN_COMPLETE 0x0a +struct bt_hci_evt_le_enh_conn_complete { + uint8_t status; + uint16_t handle; + uint8_t role; + bt_addr_le_t peer_addr; + bt_addr_t local_rpa; + bt_addr_t peer_rpa; + uint16_t interval; + uint16_t latency; + uint16_t supv_timeout; + uint8_t clock_accuracy; +} __packed; + +#define BT_HCI_EVT_LE_DIRECT_ADV_REPORT 0x0b +struct bt_hci_evt_le_direct_adv_info { + uint8_t evt_type; + bt_addr_le_t addr; + bt_addr_le_t dir_addr; + int8_t rssi; +} __packed; +struct bt_hci_evt_le_direct_adv_report { + uint8_t num_reports; + struct bt_hci_evt_le_direct_adv_info direct_adv_info[0]; +} __packed; + +#define BT_HCI_EVT_LE_PHY_UPDATE_COMPLETE 0x0c +struct bt_hci_evt_le_phy_update_complete { + uint8_t status; + uint16_t handle; + uint8_t tx_phy; + uint8_t rx_phy; +} __packed; + +#define BT_HCI_EVT_LE_EXT_ADVERTISING_REPORT 0x0d + +#define BT_HCI_LE_ADV_EVT_TYPE_CONN BIT(0) +#define BT_HCI_LE_ADV_EVT_TYPE_SCAN BIT(1) +#define BT_HCI_LE_ADV_EVT_TYPE_DIRECT BIT(2) +#define BT_HCI_LE_ADV_EVT_TYPE_SCAN_RSP BIT(3) +#define BT_HCI_LE_ADV_EVT_TYPE_LEGACY BIT(4) + +#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS(ev_type) (((ev_type) >> 5) & 0x03) +#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_COMPLETE 0 +#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_PARTIAL 1 +#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_INCOMPLETE 2 +#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_RX_FAILED 0xFF + +struct bt_hci_evt_le_ext_advertising_info { + uint16_t evt_type; + bt_addr_le_t addr; + uint8_t prim_phy; + uint8_t sec_phy; + uint8_t sid; + int8_t tx_power; + int8_t rssi; + uint16_t interval; + bt_addr_le_t direct_addr; + uint8_t length; + uint8_t data[0]; +} __packed; +struct bt_hci_evt_le_ext_advertising_report { + uint8_t num_reports; + struct bt_hci_evt_le_ext_advertising_info adv_info[0]; +} __packed; + +#define BT_HCI_EVT_LE_PER_ADV_SYNC_ESTABLISHED 0x0e +struct bt_hci_evt_le_per_adv_sync_established { + uint8_t status; + uint16_t handle; + uint8_t sid; + bt_addr_le_t adv_addr; + uint8_t phy; + uint16_t interval; + uint8_t clock_accuracy; +} __packed; + +#define BT_HCI_EVT_LE_PER_ADVERTISING_REPORT 0x0f +struct bt_hci_evt_le_per_advertising_report { + uint16_t handle; + int8_t tx_power; + int8_t rssi; + uint8_t cte_type; + uint8_t data_status; + uint8_t length; + uint8_t data[0]; +} __packed; + +#define BT_HCI_EVT_LE_PER_ADV_SYNC_LOST 0x10 +struct bt_hci_evt_le_per_adv_sync_lost { + uint16_t handle; +} __packed; + +#define BT_HCI_EVT_LE_SCAN_TIMEOUT 0x11 + +#define BT_HCI_EVT_LE_ADV_SET_TERMINATED 0x12 +struct bt_hci_evt_le_adv_set_terminated { + uint8_t status; + uint8_t adv_handle; + uint16_t conn_handle; + uint8_t num_completed_ext_adv_evts; +} __packed; + +#define BT_HCI_EVT_LE_SCAN_REQ_RECEIVED 0x13 +struct bt_hci_evt_le_scan_req_received { + uint8_t handle; + bt_addr_le_t addr; +} __packed; + +#define BT_HCI_LE_CHAN_SEL_ALGO_1 0x00 +#define BT_HCI_LE_CHAN_SEL_ALGO_2 0x01 + +#define BT_HCI_EVT_LE_CHAN_SEL_ALGO 0x14 +struct bt_hci_evt_le_chan_sel_algo { + uint16_t handle; + uint8_t chan_sel_algo; +} __packed; + +#define BT_HCI_LE_CTE_CRC_OK 0x0 +#define BT_HCI_LE_CTE_CRC_ERR_CTE_BASED_TIME 0x1 +#define BT_HCI_LE_CTE_CRC_ERR_CTE_BASED_OTHER 0x2 +#define BT_HCI_LE_CTE_INSUFFICIENT_RESOURCES 0xFF + +#define B_HCI_LE_CTE_REPORT_SAMPLE_COUNT_MIN 0x9 +#define B_HCI_LE_CTE_REPORT_SAMPLE_COUNT_MAX 0x52 + +#define BT_HCI_LE_CTE_REPORT_NO_VALID_SAMPLE 0x80 + +#define BT_HCI_EVT_LE_CONNECTIONLESS_IQ_REPORT 0x15 +struct bt_hci_le_iq_sample { + int8_t i; + int8_t q; +}; + +struct bt_hci_evt_le_connectionless_iq_report { + uint16_t sync_handle; + uint8_t chan_idx; + int16_t rssi; + uint8_t rssi_ant_id; + uint8_t cte_type; + uint8_t slot_durations; + uint8_t packet_status; + uint16_t per_evt_counter; + uint8_t sample_count; + struct bt_hci_le_iq_sample sample[0]; +} __packed; + +#define BT_HCI_EVT_LE_CONNECTION_IQ_REPORT 0x16 +struct bt_hci_evt_le_connection_iq_report { + uint16_t conn_handle; + uint8_t rx_phy; + uint8_t data_chan_idx; + int16_t rssi; + uint8_t rssi_ant_id; + uint8_t cte_type; + uint8_t slot_durations; + uint8_t packet_status; + uint16_t conn_evt_counter; + uint8_t sample_count; + struct bt_hci_le_iq_sample sample[0]; +} __packed; + +#define BT_HCI_CTE_REQ_STATUS_RSP_WITHOUT_CTE 0x0 + +#define BT_HCI_EVT_LE_CTE_REQUEST_FAILED 0x17 +struct bt_hci_evt_le_cte_req_failed { + /* According to BT 5.3 Core Spec the status field may have following + * values: + * - BT_HCI_CTE_REQ_STATUS_RSP_WITHOUT_CTE when received LL_CTE_RSP_PDU without CTE. + * - Other Controller error code for peer rejected request. + */ + uint8_t status; + uint16_t conn_handle; +} __packed; + +#define BT_HCI_EVT_LE_PAST_RECEIVED 0x18 +struct bt_hci_evt_le_past_received { + uint8_t status; + uint16_t conn_handle; + uint16_t service_data; + uint16_t sync_handle; + uint8_t adv_sid; + bt_addr_le_t addr; + uint8_t phy; + uint16_t interval; + uint8_t clock_accuracy; +} __packed; + +#define BT_HCI_EVT_LE_CIS_ESTABLISHED 0x19 +struct bt_hci_evt_le_cis_established { + uint8_t status; + uint16_t conn_handle; + uint8_t cig_sync_delay[3]; + uint8_t cis_sync_delay[3]; + uint8_t c_latency[3]; + uint8_t p_latency[3]; + uint8_t c_phy; + uint8_t p_phy; + uint8_t nse; + uint8_t c_bn; + uint8_t p_bn; + uint8_t c_ft; + uint8_t p_ft; + uint16_t c_max_pdu; + uint16_t p_max_pdu; + uint16_t interval; +} __packed; + +#define BT_HCI_EVT_LE_CIS_REQ 0x1a +struct bt_hci_evt_le_cis_req { + uint16_t acl_handle; + uint16_t cis_handle; + uint8_t cig_id; + uint8_t cis_id; +} __packed; + +#define BT_HCI_EVT_LE_BIG_COMPLETE 0x1b +struct bt_hci_evt_le_big_complete { + uint8_t status; + uint8_t big_handle; + uint8_t sync_delay[3]; + uint8_t latency[3]; + uint8_t phy; + uint8_t nse; + uint8_t bn; + uint8_t pto; + uint8_t irc; + uint16_t max_pdu; + uint16_t iso_interval; + uint8_t num_bis; + uint16_t handle[0]; +} __packed; + +#define BT_HCI_EVT_LE_BIG_TERMINATE 0x1c +struct bt_hci_evt_le_big_terminate { + uint8_t big_handle; + uint8_t reason; +} __packed; + +#define BT_HCI_EVT_LE_BIG_SYNC_ESTABLISHED 0x1d +struct bt_hci_evt_le_big_sync_established { + uint8_t status; + uint8_t big_handle; + uint8_t latency[3]; + uint8_t nse; + uint8_t bn; + uint8_t pto; + uint8_t irc; + uint16_t max_pdu; + uint16_t iso_interval; + uint8_t num_bis; + uint16_t handle[0]; +} __packed; + +#define BT_HCI_EVT_LE_BIG_SYNC_LOST 0x1e +struct bt_hci_evt_le_big_sync_lost { + uint8_t big_handle; + uint8_t reason; +} __packed; + +#define BT_HCI_EVT_LE_REQ_PEER_SCA_COMPLETE 0x1f +struct bt_hci_evt_le_req_peer_sca_complete { + uint8_t status; + uint16_t handle; + uint8_t sca; +} __packed; + +#define BT_HCI_LE_ZONE_ENTERED_LOW 0x0 +#define BT_HCI_LE_ZONE_ENTERED_MIDDLE 0x1 +#define BT_HCI_LE_ZONE_ENTERED_HIGH 0x2 +#define BT_HCI_LE_PATH_LOSS_UNAVAILABLE 0xFF + +#define BT_HCI_EVT_LE_PATH_LOSS_THRESHOLD 0x20 +struct bt_hci_evt_le_path_loss_threshold { + uint16_t handle; + uint8_t current_path_loss; + uint8_t zone_entered; +} __packed; + +/** Reason for Transmit power reporting. + */ +/* Local Transmit power changed. */ +#define BT_HCI_LE_TX_POWER_REPORT_REASON_LOCAL_CHANGED 0x00 +/* Remote Transmit power changed. */ +#define BT_HCI_LE_TX_POWER_REPORT_REASON_REMOTE_CHANGED 0x01 +/* HCI_LE_Read_Remote_Transmit_Power_Level command completed. */ +#define BT_HCI_LE_TX_POWER_REPORT_REASON_READ_REMOTE_COMPLETED 0x02 + +#define BT_HCI_EVT_LE_TRANSMIT_POWER_REPORT 0x21 +struct bt_hci_evt_le_transmit_power_report { + uint8_t status; + uint16_t handle; + uint8_t reason; + uint8_t phy; + int8_t tx_power_level; + uint8_t tx_power_level_flag; + int8_t delta; +} __packed; + +#define BT_HCI_EVT_LE_BIGINFO_ADV_REPORT 0x22 +struct bt_hci_evt_le_biginfo_adv_report { + uint16_t sync_handle; + uint8_t num_bis; + uint8_t nse; + uint16_t iso_interval; + uint8_t bn; + uint8_t pto; + uint8_t irc; + uint16_t max_pdu; + uint8_t sdu_interval[3]; + uint16_t max_sdu; + uint8_t phy; + uint8_t framing; + uint8_t encryption; +} __packed; + +/** All limits according to BT Core Spec v5.4 [Vol 4, Part E]. */ +#define BT_HCI_LE_SUBRATE_FACTOR_MIN 0x0001 +#define BT_HCI_LE_SUBRATE_FACTOR_MAX 0x01f4 +#define BT_HCI_LE_CONTINUATION_NUM_MAX 0x01f3 + +#define BT_HCI_EVT_LE_SUBRATE_CHANGE 0x23 +struct bt_hci_evt_le_subrate_change { + uint8_t status; + uint16_t handle; + uint16_t subrate_factor; + uint16_t peripheral_latency; + uint16_t continuation_number; + uint16_t supervision_timeout; +} __packed; + +#define BT_HCI_EVT_LE_CIS_ESTABLISHED_V2 0x2a +struct bt_hci_evt_le_cis_established_v2 { + uint8_t status; + uint16_t conn_handle; + uint8_t cig_sync_delay[3]; + uint8_t cis_sync_delay[3]; + uint8_t c_latency[3]; + uint8_t p_latency[3]; + uint8_t c_phy; + uint8_t p_phy; + uint8_t nse; + uint8_t c_bn; + uint8_t p_bn; + uint8_t c_ft; + uint8_t p_ft; + uint16_t c_max_pdu; + uint16_t p_max_pdu; + uint16_t interval; + uint8_t sub_interval[3]; + uint16_t c_max_sdu; + uint16_t p_max_sdu; + uint8_t c_sdu_interval[3]; + uint8_t p_sdu_interval[3]; + uint8_t framing; +} __packed; + +#define BT_HCI_EVT_LE_READ_ALL_REMOTE_FEAT_COMPLETE 0x2b + +#define BT_HCI_LE_FEATURE_PAGE_MAX 10 +#define BT_HCI_LE_BYTES_PER_FEATURE_PAGE 24 +#define BT_HCI_LE_BYTES_PAGE_0_FEATURE_PAGE 8 + +struct bt_hci_evt_le_read_all_remote_feat_complete { + uint8_t status; + uint16_t handle; + uint8_t max_remote_page; + uint8_t max_valid_page; + uint8_t features[248]; +} __packed; + +#define BT_HCI_LE_CS_INITIATOR_ROLE_MASK BIT(0) +#define BT_HCI_LE_CS_REFLECTOR_ROLE_MASK BIT(1) + +#define BT_HCI_LE_CS_MODES_SUPPORTED_MODE_3_MASK BIT(0) + +#define BT_HCI_LE_CS_RTT_AA_ONLY_N_10NS_MASK BIT(0) +#define BT_HCI_LE_CS_RTT_SOUNDING_N_10NS_MASK BIT(1) +#define BT_HCI_LE_CS_RTT_RANDOM_PAYLOAD_N_10NS_MASK BIT(2) + +#define BT_HCI_LE_CS_NADM_SOUNDING_CAPABILITY_PHASE_BASED_MASK BIT(0) +#define BT_HCI_LE_CS_NADM_RANDOM_CAPABILITY_PHASE_BASED_MASK BIT(0) + +#define BT_HCI_LE_CS_SYNC_PHYS_2M_MASK BIT(1) +#define BT_HCI_LE_CS_SYNC_PHYS_2M_2BT_MASK BIT(2) + +#define BT_HCI_LE_CS_SUBFEATURE_NO_TX_FAE_MASK BIT(1) +#define BT_HCI_LE_CS_SUBFEATURE_CHSEL_ALG_3C_MASK BIT(2) +#define BT_HCI_LE_CS_SUBFEATURE_PBR_FROM_RTT_SOUNDING_SEQ_MASK BIT(3) + +#define BT_HCI_LE_CS_T_IP1_TIME_10US_MASK BIT(0) +#define BT_HCI_LE_CS_T_IP1_TIME_20US_MASK BIT(1) +#define BT_HCI_LE_CS_T_IP1_TIME_30US_MASK BIT(2) +#define BT_HCI_LE_CS_T_IP1_TIME_40US_MASK BIT(3) +#define BT_HCI_LE_CS_T_IP1_TIME_50US_MASK BIT(4) +#define BT_HCI_LE_CS_T_IP1_TIME_60US_MASK BIT(5) +#define BT_HCI_LE_CS_T_IP1_TIME_80US_MASK BIT(6) + +#define BT_HCI_LE_CS_T_IP2_TIME_10US_MASK BIT(0) +#define BT_HCI_LE_CS_T_IP2_TIME_20US_MASK BIT(1) +#define BT_HCI_LE_CS_T_IP2_TIME_30US_MASK BIT(2) +#define BT_HCI_LE_CS_T_IP2_TIME_40US_MASK BIT(3) +#define BT_HCI_LE_CS_T_IP2_TIME_50US_MASK BIT(4) +#define BT_HCI_LE_CS_T_IP2_TIME_60US_MASK BIT(5) +#define BT_HCI_LE_CS_T_IP2_TIME_80US_MASK BIT(6) + +#define BT_HCI_LE_CS_T_FCS_TIME_15US_MASK BIT(0) +#define BT_HCI_LE_CS_T_FCS_TIME_20US_MASK BIT(1) +#define BT_HCI_LE_CS_T_FCS_TIME_30US_MASK BIT(2) +#define BT_HCI_LE_CS_T_FCS_TIME_40US_MASK BIT(3) +#define BT_HCI_LE_CS_T_FCS_TIME_50US_MASK BIT(4) +#define BT_HCI_LE_CS_T_FCS_TIME_60US_MASK BIT(5) +#define BT_HCI_LE_CS_T_FCS_TIME_80US_MASK BIT(6) +#define BT_HCI_LE_CS_T_FCS_TIME_100US_MASK BIT(7) +#define BT_HCI_LE_CS_T_FCS_TIME_1200US_MASK BIT(8) + +#define BT_HCI_LE_CS_T_PM_TIME_10US_MASK BIT(0) +#define BT_HCI_LE_CS_T_PM_TIME_20US_MASK BIT(1) + +#define BT_HCI_LE_CS_TX_SNR_CAPABILITY_18DB_MASK BIT(0) +#define BT_HCI_LE_CS_TX_SNR_CAPABILITY_21DB_MASK BIT(1) +#define BT_HCI_LE_CS_TX_SNR_CAPABILITY_24DB_MASK BIT(2) +#define BT_HCI_LE_CS_TX_SNR_CAPABILITY_27DB_MASK BIT(3) +#define BT_HCI_LE_CS_TX_SNR_CAPABILITY_30DB_MASK BIT(4) + +#define BT_HCI_EVT_LE_CS_READ_REMOTE_SUPPORTED_CAPABILITIES_COMPLETE 0x2C +struct bt_hci_evt_le_cs_read_remote_supported_capabilities_complete { + uint8_t status; + uint16_t conn_handle; + uint8_t num_config_supported; + uint16_t max_consecutive_procedures_supported; + uint8_t num_antennas_supported; + uint8_t max_antenna_paths_supported; + uint8_t roles_supported; + uint8_t modes_supported; + uint8_t rtt_capability; + uint8_t rtt_aa_only_n; + uint8_t rtt_sounding_n; + uint8_t rtt_random_payload_n; + uint16_t nadm_sounding_capability; + uint16_t nadm_random_capability; + uint8_t cs_sync_phys_supported; + uint16_t subfeatures_supported; + uint16_t t_ip1_times_supported; + uint16_t t_ip2_times_supported; + uint16_t t_fcs_times_supported; + uint16_t t_pm_times_supported; + uint8_t t_sw_time_supported; + uint8_t tx_snr_capability; +} __packed; + +#define BT_HCI_EVT_LE_CS_READ_REMOTE_FAE_TABLE_COMPLETE 0x2D +struct bt_hci_evt_le_cs_read_remote_fae_table_complete { + uint8_t status; + uint16_t conn_handle; + uint8_t remote_fae_table[72]; +} __packed; + +#define BT_HCI_LE_CS_CONFIG_ACTION_REMOVED 0x00 +#define BT_HCI_LE_CS_CONFIG_ACTION_CREATED 0x01 + +#define BT_HCI_EVT_LE_CS_SECURITY_ENABLE_COMPLETE 0x2E +struct bt_hci_evt_le_cs_security_enable_complete { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_EVT_LE_CS_CONFIG_COMPLETE 0x2F +struct bt_hci_evt_le_cs_config_complete { + uint8_t status; + uint16_t handle; + uint8_t config_id; + uint8_t action; + uint8_t main_mode_type; + uint8_t sub_mode_type; + uint8_t min_main_mode_steps; + uint8_t max_main_mode_steps; + uint8_t main_mode_repetition; + uint8_t mode_0_steps; + uint8_t role; + uint8_t rtt_type; + uint8_t cs_sync_phy; + uint8_t channel_map[10]; + uint8_t channel_map_repetition; + uint8_t channel_selection_type; + uint8_t ch3c_shape; + uint8_t ch3c_jump; + uint8_t reserved; + uint8_t t_ip1_time; + uint8_t t_ip2_time; + uint8_t t_fcs_time; + uint8_t t_pm_time; +} __packed; + +#define BT_HCI_LE_CS_TEST_CONN_HANDLE 0x0FFF + +#define BT_HCI_LE_CS_PROCEDURE_DONE_STATUS_COMPLETE 0x0 +#define BT_HCI_LE_CS_PROCEDURE_DONE_STATUS_PARTIAL 0x1 +#define BT_HCI_LE_CS_PROCEDURE_DONE_STATUS_ABORTED 0xF + +#define BT_HCI_LE_CS_SUBEVENT_DONE_STATUS_COMPLETE 0x0 +#define BT_HCI_LE_CS_SUBEVENT_DONE_STATUS_PARTIAL 0x1 +#define BT_HCI_LE_CS_SUBEVENT_DONE_STATUS_ABORTED 0xF + +#define BT_HCI_LE_CS_PROCEDURE_ABORT_REASON_NO_ABORT 0x0 +#define BT_HCI_LE_CS_PROCEDURE_ABORT_REASON_LOCAL_HOST_OR_REMOTE_REQUEST 0x1 +#define BT_HCI_LE_CS_PROCEDURE_ABORT_REASON_TOO_FEW_CHANNELS 0x2 +#define BT_HCI_LE_CS_PROCEDURE_ABORT_REASON_CHMAP_INSTANT_PASSED 0x3 +#define BT_HCI_LE_CS_PROCEDURE_ABORT_REASON_UNSPECIFIED 0xF + +#define BT_HCI_LE_CS_SUBEVENT_ABORT_REASON_NO_ABORT 0x0 +#define BT_HCI_LE_CS_SUBEVENT_ABORT_REASON_LOCAL_HOST_OR_REMOTE_REQUEST 0x1 +#define BT_HCI_LE_CS_SUBEVENT_ABORT_REASON_NO_CS_SYNC_RECEIVED 0x2 +#define BT_HCI_LE_CS_SUBEVENT_ABORT_REASON_SCHED_CONFLICT 0x3 +#define BT_HCI_LE_CS_SUBEVENT_ABORT_REASON_UNSPECIFIED 0xF + +#define BT_HCI_LE_CS_SUBEVENT_RESULT_N_AP_IGNORED 0x00 +#define BT_HCI_LE_CS_SUBEVENT_RESULT_N_AP_1 0x01 +#define BT_HCI_LE_CS_SUBEVENT_RESULT_N_AP_2 0x02 +#define BT_HCI_LE_CS_SUBEVENT_RESULT_N_AP_3 0x03 +#define BT_HCI_LE_CS_SUBEVENT_RESULT_N_AP_4 0x04 + +#define BT_HCI_LE_CS_SUBEVENT_RESULT_FREQ_COMPENSATION_NOT_AVAILABLE 0xC000 + +#define BT_HCI_LE_CS_SUBEVENT_RESULT_PCT_NOT_AVAILABLE 0xFFFFFFFF + +#define BT_HCI_LE_CS_REF_POWER_LEVEL_UNAVAILABLE 0x7F + +#define BT_HCI_LE_CS_PCT_I_MASK 0x000FFF +#define BT_HCI_LE_CS_PCT_Q_MASK 0xFFF000 + +#define BT_HCI_LE_CS_TONE_QUALITY_HIGH 0x0 +#define BT_HCI_LE_CS_TONE_QUALITY_MED 0x1 +#define BT_HCI_LE_CS_TONE_QUALITY_LOW 0x2 +#define BT_HCI_LE_CS_TONE_QUALITY_UNAVAILABLE 0x3 + +#define BT_HCI_LE_CS_NOT_TONE_EXT_SLOT 0x0 +#define BT_HCI_LE_CS_TONE_EXT_SLOT_EXT_NOT_EXPECTED 0x1 +#define BT_HCI_LE_CS_TONE_EXT_SLOT_EXT_EXPECTED 0x2 + +#define BT_HCI_LE_CS_TIME_DIFFERENCE_NOT_AVAILABLE 0x8000 + +#define BT_HCI_LE_CS_PACKET_NADM_ATTACK_EXT_UNLIKELY 0x00 +#define BT_HCI_LE_CS_PACKET_NADM_ATTACK_VERY_UNLIKELY 0x01 +#define BT_HCI_LE_CS_PACKET_NADM_ATTACK_UNLIKELY 0x02 +#define BT_HCI_LE_CS_PACKET_NADM_ATTACK_POSSIBLE 0x03 +#define BT_HCI_LE_CS_PACKET_NADM_ATTACK_LIKELY 0x04 +#define BT_HCI_LE_CS_PACKET_NADM_ATTACK_VERY_LIKELY 0x05 +#define BT_HCI_LE_CS_PACKET_NADM_ATTACK_EXT_LIKELY 0x06 +#define BT_HCI_LE_CS_PACKET_NADM_UNKNOWN 0xFF + +#define BT_HCI_LE_CS_PACKET_QUALITY_AA_CHECK_SUCCESSFUL 0x0 +#define BT_HCI_LE_CS_PACKET_QUALITY_AA_CHECK_BIT_ERRORS_FOUND 0x1 +#define BT_HCI_LE_CS_PACKET_QUALITY_AA_CHECK_AA_NOT_FOUND 0x2 + +#define BT_HCI_LE_CS_PACKET_RSSI_NOT_AVAILABLE 0x7F + +#define BT_HCI_EVT_LE_CS_SUBEVENT_RESULT 0x31 +/** Subevent result step data format: Mode 0 Initiator */ +struct bt_hci_le_cs_step_data_mode_0_initiator { +#ifdef CONFIG_LITTLE_ENDIAN + uint8_t packet_quality_aa_check: 4; + uint8_t packet_quality_bit_errors: 4; +#else + uint8_t packet_quality_bit_errors: 4; + uint8_t packet_quality_aa_check: 4; +#endif /* CONFIG_LITTLE_ENDIAN */ + uint8_t packet_rssi; + uint8_t packet_antenna; + uint16_t measured_freq_offset; +} __packed; + +/** Subevent result step data format: Mode 0 Reflector */ +struct bt_hci_le_cs_step_data_mode_0_reflector { +#ifdef CONFIG_LITTLE_ENDIAN + uint8_t packet_quality_aa_check: 4; + uint8_t packet_quality_bit_errors: 4; +#else + uint8_t packet_quality_bit_errors: 4; + uint8_t packet_quality_aa_check: 4; +#endif /* CONFIG_LITTLE_ENDIAN */ + uint8_t packet_rssi; + uint8_t packet_antenna; +} __packed; + +/** Subevent result step data format: Mode 1 */ +struct bt_hci_le_cs_step_data_mode_1 { +#ifdef CONFIG_LITTLE_ENDIAN + uint8_t packet_quality_aa_check: 4; + uint8_t packet_quality_bit_errors: 4; +#else + uint8_t packet_quality_bit_errors: 4; + uint8_t packet_quality_aa_check: 4; +#endif /* CONFIG_LITTLE_ENDIAN */ + uint8_t packet_nadm; + uint8_t packet_rssi; + union { + int16_t toa_tod_initiator; + int16_t tod_toa_reflector; + }; + uint8_t packet_antenna; +} __packed; + +/** Subevent result step data format: Mode 1 with sounding sequence RTT support */ +struct bt_hci_le_cs_step_data_mode_1_ss_rtt { +#ifdef CONFIG_LITTLE_ENDIAN + uint8_t packet_quality_aa_check: 4; + uint8_t packet_quality_bit_errors: 4; +#else + uint8_t packet_quality_bit_errors: 4; + uint8_t packet_quality_aa_check: 4; +#endif /* CONFIG_LITTLE_ENDIAN */ + uint8_t packet_nadm; + uint8_t packet_rssi; + union { + int16_t toa_tod_initiator; + int16_t tod_toa_reflector; + }; + uint8_t packet_antenna; + uint8_t packet_pct1[4]; + uint8_t packet_pct2[4]; +} __packed; + +/** Format for per-antenna path step data in modes 2 and 3 */ +struct bt_hci_le_cs_step_data_tone_info { + uint8_t phase_correction_term[3]; +#ifdef CONFIG_LITTLE_ENDIAN + uint8_t quality_indicator: 4; + uint8_t extension_indicator: 4; +#else + uint8_t extension_indicator: 4; + uint8_t quality_indicator: 4; +#endif /* CONFIG_LITTLE_ENDIAN */ +} __packed; + +/** Subevent result step data format: Mode 2 */ +struct bt_hci_le_cs_step_data_mode_2 { + uint8_t antenna_permutation_index; + struct bt_hci_le_cs_step_data_tone_info tone_info[]; +} __packed; + +/** Subevent result step data format: Mode 3 */ +struct bt_hci_le_cs_step_data_mode_3 { +#ifdef CONFIG_LITTLE_ENDIAN + uint8_t packet_quality_aa_check: 4; + uint8_t packet_quality_bit_errors: 4; +#else + uint8_t packet_quality_bit_errors: 4; + uint8_t packet_quality_aa_check: 4; +#endif /* CONFIG_LITTLE_ENDIAN */ + uint8_t packet_nadm; + uint8_t packet_rssi; + union { + int16_t toa_tod_initiator; + int16_t tod_toa_reflector; + }; + uint8_t packet_antenna; + uint8_t antenna_permutation_index; + struct bt_hci_le_cs_step_data_tone_info tone_info[]; +} __packed; + +/** Subevent result step data format: Mode 3 with sounding sequence RTT support */ +struct bt_hci_le_cs_step_data_mode_3_ss_rtt { +#ifdef CONFIG_LITTLE_ENDIAN + uint8_t packet_quality_aa_check: 4; + uint8_t packet_quality_bit_errors: 4; +#else + uint8_t packet_quality_bit_errors: 4; + uint8_t packet_quality_aa_check: 4; +#endif /* CONFIG_LITTLE_ENDIAN */ + uint8_t packet_nadm; + uint8_t packet_rssi; + union { + int16_t toa_tod_initiator; + int16_t tod_toa_reflector; + }; + uint8_t packet_antenna; + uint8_t packet_pct1[4]; + uint8_t packet_pct2[4]; + uint8_t antenna_permutation_index; + struct bt_hci_le_cs_step_data_tone_info tone_info[]; +} __packed; + +struct bt_hci_evt_le_cs_subevent_result_step { + uint8_t step_mode; + uint8_t step_channel; + uint8_t step_data_length; + uint8_t step_data[]; +} __packed; + +struct bt_hci_evt_le_cs_subevent_result { + uint16_t conn_handle; + uint8_t config_id; + uint16_t start_acl_conn_event_counter; + uint16_t procedure_counter; + uint16_t frequency_compensation; + uint8_t reference_power_level; + uint8_t procedure_done_status; + uint8_t subevent_done_status; +#ifdef CONFIG_LITTLE_ENDIAN + uint8_t procedure_abort_reason: 4; + uint8_t subevent_abort_reason: 4; +#else + uint8_t subevent_abort_reason: 4; + uint8_t procedure_abort_reason: 4; +#endif /* CONFIG_LITTLE_ENDIAN */ + uint8_t num_antenna_paths; + uint8_t num_steps_reported; + uint8_t steps[]; +} __packed; + +#define BT_HCI_EVT_LE_CS_SUBEVENT_RESULT_CONTINUE 0x32 + +struct bt_hci_evt_le_cs_subevent_result_continue { + uint16_t conn_handle; + uint8_t config_id; + uint8_t procedure_done_status; + uint8_t subevent_done_status; +#ifdef CONFIG_LITTLE_ENDIAN + uint8_t procedure_abort_reason: 4; + uint8_t subevent_abort_reason: 4; +#else + uint8_t subevent_abort_reason: 4; + uint8_t procedure_abort_reason: 4; +#endif /* CONFIG_LITTLE_ENDIAN */ + uint8_t num_antenna_paths; + uint8_t num_steps_reported; + uint8_t steps[]; +} __packed; + +#define BT_HCI_EVT_LE_CS_TEST_END_COMPLETE 0x33 +struct bt_hci_evt_le_cs_test_end_complete { + uint8_t status; +} __packed; + +#define BT_HCI_EVT_LE_CS_PROCEDURE_ENABLE_COMPLETE 0x30 +struct bt_hci_evt_le_cs_procedure_enable_complete { + uint8_t status; + uint16_t handle; + uint8_t config_id; + uint8_t state; + uint8_t tone_antenna_config_selection; + uint8_t selected_tx_power; + uint8_t subevent_len[3]; + uint8_t subevents_per_event; + uint16_t subevent_interval; + uint16_t event_interval; + uint16_t procedure_interval; + uint16_t procedure_count; + uint16_t max_procedure_len; +} __packed; + +/* Event mask bits */ + +#define BT_EVT_BIT(n) (1ULL << (n)) + +#define BT_EVT_MASK_INQUIRY_COMPLETE BT_EVT_BIT(0) +#define BT_EVT_MASK_CONN_COMPLETE BT_EVT_BIT(2) +#define BT_EVT_MASK_CONN_REQUEST BT_EVT_BIT(3) +#define BT_EVT_MASK_DISCONN_COMPLETE BT_EVT_BIT(4) +#define BT_EVT_MASK_AUTH_COMPLETE BT_EVT_BIT(5) +#define BT_EVT_MASK_REMOTE_NAME_REQ_COMPLETE BT_EVT_BIT(6) +#define BT_EVT_MASK_ENCRYPT_CHANGE BT_EVT_BIT(7) +#define BT_EVT_MASK_REMOTE_FEATURES BT_EVT_BIT(10) +#define BT_EVT_MASK_REMOTE_VERSION_INFO BT_EVT_BIT(11) +#define BT_EVT_MASK_HARDWARE_ERROR BT_EVT_BIT(15) +#define BT_EVT_MASK_ROLE_CHANGE BT_EVT_BIT(17) +#define BT_EVT_MASK_PIN_CODE_REQ BT_EVT_BIT(21) +#define BT_EVT_MASK_LINK_KEY_REQ BT_EVT_BIT(22) +#define BT_EVT_MASK_LINK_KEY_NOTIFY BT_EVT_BIT(23) +#define BT_EVT_MASK_DATA_BUFFER_OVERFLOW BT_EVT_BIT(25) +#define BT_EVT_MASK_INQUIRY_RESULT_WITH_RSSI BT_EVT_BIT(33) +#define BT_EVT_MASK_REMOTE_EXT_FEATURES BT_EVT_BIT(34) +#define BT_EVT_MASK_SYNC_CONN_COMPLETE BT_EVT_BIT(43) +#define BT_EVT_MASK_EXTENDED_INQUIRY_RESULT BT_EVT_BIT(46) +#define BT_EVT_MASK_ENCRYPT_KEY_REFRESH_COMPLETE BT_EVT_BIT(47) +#define BT_EVT_MASK_IO_CAPA_REQ BT_EVT_BIT(48) +#define BT_EVT_MASK_IO_CAPA_RESP BT_EVT_BIT(49) +#define BT_EVT_MASK_USER_CONFIRM_REQ BT_EVT_BIT(50) +#define BT_EVT_MASK_USER_PASSKEY_REQ BT_EVT_BIT(51) +#define BT_EVT_MASK_SSP_COMPLETE BT_EVT_BIT(53) +#define BT_EVT_MASK_USER_PASSKEY_NOTIFY BT_EVT_BIT(58) +#define BT_EVT_MASK_LE_META_EVENT BT_EVT_BIT(61) + +/* Page 2 */ +#define BT_EVT_MASK_NUM_COMPLETE_DATA_BLOCKS BT_EVT_BIT(8) +#define BT_EVT_MASK_TRIGG_CLOCK_CAPTURE BT_EVT_BIT(14) +#define BT_EVT_MASK_SYNCH_TRAIN_COMPLETE BT_EVT_BIT(15) +#define BT_EVT_MASK_SYNCH_TRAIN_RX BT_EVT_BIT(16) +#define BT_EVT_MASK_CL_PER_BC_RX BT_EVT_BIT(17) +#define BT_EVT_MASK_CL_PER_BC_TIMEOUT BT_EVT_BIT(18) +#define BT_EVT_MASK_TRUNC_PAGE_COMPLETE BT_EVT_BIT(19) +#define BT_EVT_MASK_PER_PAGE_RSP_TIMEOUT BT_EVT_BIT(20) +#define BT_EVT_MASK_CL_PER_BC_CH_MAP_CHANGE BT_EVT_BIT(21) +#define BT_EVT_MASK_INQUIRY_RSP_NOT BT_EVT_BIT(22) +#define BT_EVT_MASK_AUTH_PAYLOAD_TIMEOUT_EXP BT_EVT_BIT(23) +#define BT_EVT_MASK_SAM_STATUS_CHANGE BT_EVT_BIT(24) + +#define BT_EVT_MASK_LE_CONN_COMPLETE BT_EVT_BIT(0) +#define BT_EVT_MASK_LE_ADVERTISING_REPORT BT_EVT_BIT(1) +#define BT_EVT_MASK_LE_CONN_UPDATE_COMPLETE BT_EVT_BIT(2) +#define BT_EVT_MASK_LE_REMOTE_FEAT_COMPLETE BT_EVT_BIT(3) +#define BT_EVT_MASK_LE_LTK_REQUEST BT_EVT_BIT(4) +#define BT_EVT_MASK_LE_CONN_PARAM_REQ BT_EVT_BIT(5) +#define BT_EVT_MASK_LE_DATA_LEN_CHANGE BT_EVT_BIT(6) +#define BT_EVT_MASK_LE_P256_PUBLIC_KEY_COMPLETE BT_EVT_BIT(7) +#define BT_EVT_MASK_LE_GENERATE_DHKEY_COMPLETE BT_EVT_BIT(8) +#define BT_EVT_MASK_LE_ENH_CONN_COMPLETE BT_EVT_BIT(9) +#define BT_EVT_MASK_LE_DIRECT_ADV_REPORT BT_EVT_BIT(10) +#define BT_EVT_MASK_LE_PHY_UPDATE_COMPLETE BT_EVT_BIT(11) +#define BT_EVT_MASK_LE_EXT_ADVERTISING_REPORT BT_EVT_BIT(12) +#define BT_EVT_MASK_LE_PER_ADV_SYNC_ESTABLISHED BT_EVT_BIT(13) +#define BT_EVT_MASK_LE_PER_ADVERTISING_REPORT BT_EVT_BIT(14) +#define BT_EVT_MASK_LE_PER_ADV_SYNC_LOST BT_EVT_BIT(15) +#define BT_EVT_MASK_LE_SCAN_TIMEOUT BT_EVT_BIT(16) +#define BT_EVT_MASK_LE_ADV_SET_TERMINATED BT_EVT_BIT(17) +#define BT_EVT_MASK_LE_SCAN_REQ_RECEIVED BT_EVT_BIT(18) +#define BT_EVT_MASK_LE_CHAN_SEL_ALGO BT_EVT_BIT(19) +#define BT_EVT_MASK_LE_CONNECTIONLESS_IQ_REPORT BT_EVT_BIT(20) +#define BT_EVT_MASK_LE_CONNECTION_IQ_REPORT BT_EVT_BIT(21) +#define BT_EVT_MASK_LE_CTE_REQUEST_FAILED BT_EVT_BIT(22) +#define BT_EVT_MASK_LE_PAST_RECEIVED BT_EVT_BIT(23) +#define BT_EVT_MASK_LE_CIS_ESTABLISHED BT_EVT_BIT(24) +#define BT_EVT_MASK_LE_CIS_REQ BT_EVT_BIT(25) +#define BT_EVT_MASK_LE_BIG_COMPLETE BT_EVT_BIT(26) +#define BT_EVT_MASK_LE_BIG_TERMINATED BT_EVT_BIT(27) +#define BT_EVT_MASK_LE_BIG_SYNC_ESTABLISHED BT_EVT_BIT(28) +#define BT_EVT_MASK_LE_BIG_SYNC_LOST BT_EVT_BIT(29) +#define BT_EVT_MASK_LE_REQ_PEER_SCA_COMPLETE BT_EVT_BIT(30) +#define BT_EVT_MASK_LE_PATH_LOSS_THRESHOLD BT_EVT_BIT(31) +#define BT_EVT_MASK_LE_TRANSMIT_POWER_REPORTING BT_EVT_BIT(32) +#define BT_EVT_MASK_LE_BIGINFO_ADV_REPORT BT_EVT_BIT(33) +#define BT_EVT_MASK_LE_SUBRATE_CHANGE BT_EVT_BIT(34) + +#define BT_EVT_MASK_LE_PER_ADV_SYNC_ESTABLISHED_V2 BT_EVT_BIT(35) +#define BT_EVT_MASK_LE_PER_ADVERTISING_REPORT_V2 BT_EVT_BIT(36) +#define BT_EVT_MASK_LE_PAST_RECEIVED_V2 BT_EVT_BIT(37) +#define BT_EVT_MASK_LE_PER_ADV_SUBEVENT_DATA_REQ BT_EVT_BIT(38) +#define BT_EVT_MASK_LE_PER_ADV_RESPONSE_REPORT BT_EVT_BIT(39) +#define BT_EVT_MASK_LE_ENH_CONN_COMPLETE_V2 BT_EVT_BIT(40) + +#define BT_EVT_MASK_LE_CS_READ_REMOTE_SUPPORTED_CAPABILITIES_COMPLETE BT_EVT_BIT(43) +#define BT_EVT_MASK_LE_CS_READ_REMOTE_FAE_TABLE_COMPLETE BT_EVT_BIT(44) +#define BT_EVT_MASK_LE_CS_SECURITY_ENABLE_COMPLETE BT_EVT_BIT(45) +#define BT_EVT_MASK_LE_CS_CONFIG_COMPLETE BT_EVT_BIT(46) +#define BT_EVT_MASK_LE_CS_PROCEDURE_ENABLE_COMPLETE BT_EVT_BIT(47) +#define BT_EVT_MASK_LE_CS_SUBEVENT_RESULT BT_EVT_BIT(48) +#define BT_EVT_MASK_LE_CS_SUBEVENT_RESULT_CONTINUE BT_EVT_BIT(49) +#define BT_EVT_MASK_LE_CS_TEST_END_COMPLETE BT_EVT_BIT(50) + +/** HCI Error Codes, BT Core Spec v5.4 [Vol 1, Part F]. */ +#define BT_HCI_ERR_SUCCESS 0x00 +#define BT_HCI_ERR_UNKNOWN_CMD 0x01 +#define BT_HCI_ERR_UNKNOWN_CONN_ID 0x02 +#define BT_HCI_ERR_HW_FAILURE 0x03 +#define BT_HCI_ERR_PAGE_TIMEOUT 0x04 +#define BT_HCI_ERR_AUTH_FAIL 0x05 +#define BT_HCI_ERR_PIN_OR_KEY_MISSING 0x06 +#define BT_HCI_ERR_MEM_CAPACITY_EXCEEDED 0x07 +#define BT_HCI_ERR_CONN_TIMEOUT 0x08 +#define BT_HCI_ERR_CONN_LIMIT_EXCEEDED 0x09 +#define BT_HCI_ERR_SYNC_CONN_LIMIT_EXCEEDED 0x0a +#define BT_HCI_ERR_CONN_ALREADY_EXISTS 0x0b +#define BT_HCI_ERR_CMD_DISALLOWED 0x0c +#define BT_HCI_ERR_INSUFFICIENT_RESOURCES 0x0d +#define BT_HCI_ERR_INSUFFICIENT_SECURITY 0x0e +#define BT_HCI_ERR_BD_ADDR_UNACCEPTABLE 0x0f +#define BT_HCI_ERR_CONN_ACCEPT_TIMEOUT 0x10 +#define BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL 0x11 +#define BT_HCI_ERR_INVALID_PARAM 0x12 +#define BT_HCI_ERR_REMOTE_USER_TERM_CONN 0x13 +#define BT_HCI_ERR_REMOTE_LOW_RESOURCES 0x14 +#define BT_HCI_ERR_REMOTE_POWER_OFF 0x15 +#define BT_HCI_ERR_LOCALHOST_TERM_CONN 0x16 +#define BT_HCI_ERR_REPEATED_ATTEMPTS 0x17 +#define BT_HCI_ERR_PAIRING_NOT_ALLOWED 0x18 +#define BT_HCI_ERR_UNKNOWN_LMP_PDU 0x19 +#define BT_HCI_ERR_UNSUPP_REMOTE_FEATURE 0x1a +#define BT_HCI_ERR_SCO_OFFSET_REJECTED 0x1b +#define BT_HCI_ERR_SCO_INTERVAL_REJECTED 0x1c +#define BT_HCI_ERR_SCO_AIR_MODE_REJECTED 0x1d +#define BT_HCI_ERR_INVALID_LL_PARAM 0x1e +#define BT_HCI_ERR_UNSPECIFIED 0x1f +#define BT_HCI_ERR_UNSUPP_LL_PARAM_VAL 0x20 +#define BT_HCI_ERR_ROLE_CHANGE_NOT_ALLOWED 0x21 +#define BT_HCI_ERR_LL_RESP_TIMEOUT 0x22 +#define BT_HCI_ERR_LL_PROC_COLLISION 0x23 +#define BT_HCI_ERR_LMP_PDU_NOT_ALLOWED 0x24 +#define BT_HCI_ERR_ENC_MODE_NOT_ACCEPTABLE 0x25 +#define BT_HCI_ERR_LINK_KEY_CANNOT_BE_CHANGED 0x26 +#define BT_HCI_ERR_REQUESTED_QOS_NOT_SUPPORTED 0x27 +#define BT_HCI_ERR_INSTANT_PASSED 0x28 +#define BT_HCI_ERR_PAIRING_NOT_SUPPORTED 0x29 +#define BT_HCI_ERR_DIFF_TRANS_COLLISION 0x2a +#define BT_HCI_ERR_QOS_UNACCEPTABLE_PARAM 0x2c +#define BT_HCI_ERR_QOS_REJECTED 0x2d +#define BT_HCI_ERR_CHAN_ASSESS_NOT_SUPPORTED 0x2e +#define BT_HCI_ERR_INSUFF_SECURITY 0x2f +#define BT_HCI_ERR_PARAM_OUT_OF_MANDATORY_RANGE 0x30 +#define BT_HCI_ERR_ROLE_SWITCH_PENDING 0x32 +#define BT_HCI_ERR_RESERVED_SLOT_VIOLATION 0x34 +#define BT_HCI_ERR_ROLE_SWITCH_FAILED 0x35 +#define BT_HCI_ERR_EXT_INQ_RESP_TOO_LARGE 0x36 +#define BT_HCI_ERR_SIMPLE_PAIR_NOT_SUPP_BY_HOST 0x37 +#define BT_HCI_ERR_HOST_BUSY_PAIRING 0x38 +#define BT_HCI_ERR_CONN_REJECTED_DUE_TO_NO_CHAN 0x39 +#define BT_HCI_ERR_CONTROLLER_BUSY 0x3a +#define BT_HCI_ERR_UNACCEPT_CONN_PARAM 0x3b +#define BT_HCI_ERR_ADV_TIMEOUT 0x3c +#define BT_HCI_ERR_TERM_DUE_TO_MIC_FAIL 0x3d +#define BT_HCI_ERR_CONN_FAIL_TO_ESTAB 0x3e +#define BT_HCI_ERR_MAC_CONN_FAILED 0x3f +#define BT_HCI_ERR_CLOCK_ADJUST_REJECTED 0x40 +#define BT_HCI_ERR_SUBMAP_NOT_DEFINED 0x41 +#define BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER 0x42 +#define BT_HCI_ERR_LIMIT_REACHED 0x43 +#define BT_HCI_ERR_OP_CANCELLED_BY_HOST 0x44 +#define BT_HCI_ERR_PACKET_TOO_LONG 0x45 +#define BT_HCI_ERR_TOO_LATE 0x46 +#define BT_HCI_ERR_TOO_EARLY 0x47 + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_HCI_TYPES_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/iso.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/iso.h new file mode 100644 index 0000000000..08500234ec --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/iso.h @@ -0,0 +1,1328 @@ +/** + * @file + * @brief Bluetooth ISO handling + */ + +/* + * SPDX-FileCopyrightText: 2020 Intel Corporation + * SPDX-FileCopyrightText: 2021-2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_ISO_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_ISO_H_ + +/** + * @brief Isochronous channels (ISO) + * @defgroup bt_iso Isochronous channels (ISO) + * + * @since 2.3 + * @version 0.8.0 + * + * @ingroup bluetooth + * @{ + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Headroom needed for outgoing ISO SDUs + */ +#define BT_ISO_CHAN_SEND_RESERVE BT_BUF_ISO_SIZE(0) + +/** + * @brief Helper to calculate needed buffer size for ISO SDUs. + * Useful for creating buffer pools. + * + * @param mtu Required ISO SDU size + * + * @return Needed buffer size to match the requested ISO SDU MTU. + */ +#define BT_ISO_SDU_BUF_SIZE(mtu) BT_BUF_ISO_SIZE(mtu) + +/** + * Convert BIS index to bit + * + * The BIS indexes start from 0x01, so the lowest allowed bit is + * BIT(0) that represents index 0x01. To synchronize to e.g. BIS + * indexes 0x01 and 0x02, the bitfield value should be BIT(0) | BIT(1). + * As a general notation, to sync to BIS index N use BIT(N - 1). + */ +#define BT_ISO_BIS_INDEX_BIT(x) (BIT((x) - 1)) + +/** Value to set the ISO data path over HCi. */ +#define BT_ISO_DATA_PATH_HCI 0x00 + +/** Unknown SDU interval */ +#define BT_ISO_SDU_INTERVAL_UNKNOWN 0x000000U +/** The minimum value for vendor specific data path ID */ +#define BT_ISO_DATA_PATH_VS_ID_MIN 0x01 +/** The maximum value for vendor specific data path ID */ +#define BT_ISO_DATA_PATH_VS_ID_MAX 0xFE +/** Minimum controller delay in microseconds (0 us) */ +#define BT_ISO_CONTROLLER_DELAY_MIN 0x000000 +/** Maximum controller delay in microseconds (4,000,000 us) */ +#define BT_ISO_CONTROLLER_DELAY_MAX 0x3D0900 +/** Minimum interval value in microseconds (255 us) */ +#define BT_ISO_SDU_INTERVAL_MIN 0x0000FFU +/** Maximum interval value in microseconds (1,048,575 us) */ +#define BT_ISO_SDU_INTERVAL_MAX 0x0FFFFFU +/** Minimum ISO interval in units of 1.25 ms (5 ms) */ +#define BT_ISO_ISO_INTERVAL_MIN 0x0004U +/** Maximum ISO interval in units of 1.25 ms (4,000 ms) */ +#define BT_ISO_ISO_INTERVAL_MAX 0x0C80U +/** Minimum latency value in milliseconds (5 ms) */ +#define BT_ISO_LATENCY_MIN 0x0005 +/** Maximum latency value in milliseconds (4,000 ms)*/ +#define BT_ISO_LATENCY_MAX 0x0FA0 +/** Packets will be sent sequentially between the channels in the group */ +#define BT_ISO_PACKING_SEQUENTIAL 0x00 +/** Packets will be sent interleaved between the channels in the group */ +#define BT_ISO_PACKING_INTERLEAVED 0x01 +/** Packets may be framed or unframed */ +#define BT_ISO_FRAMING_UNFRAMED 0x00 +/** Packets are always framed */ +#define BT_ISO_FRAMING_FRAMED 0x01 +/** Maximum number of isochronous channels in a single group (31) */ +#define BT_ISO_MAX_GROUP_ISO_COUNT 0x1F +/** Minimum SDU size (1 octet) */ +#define BT_ISO_MIN_SDU 0x0001 +/** Maximum SDU size (4095 octets) */ +#define BT_ISO_MAX_SDU 0x0FFF +/** Minimum PDU size (0 octet) */ +#define BT_ISO_CONNECTED_PDU_MIN 0x0000U +/** Minimum PDU size (1 octet) */ +#define BT_ISO_BROADCAST_PDU_MIN 0x0001U +/** Maximum PDU size (251 octets) */ +#define BT_ISO_PDU_MAX 0x00FBU +/** Minimum burst number (1) */ +#define BT_ISO_BN_MIN 0x01U +/** Maximum burst number (15) */ +#define BT_ISO_BN_MAX 0x0FU +/** Minimum flush timeout in multiples of ISO interval (1) */ +#define BT_ISO_FT_MIN 0x01U +/** Maximum flush timeout in multiples of ISO interval (255) */ +#define BT_ISO_FT_MAX 0xFFU +/** Minimum number of subevents (1) */ +#define BT_ISO_NSE_MIN 0x01U +/** Maximum number of subevents (31) */ +#define BT_ISO_NSE_MAX 0x1FU +/** Minimum BIG sync timeout value in units of 10 ms (100 ms) */ +#define BT_ISO_SYNC_TIMEOUT_MIN 0x000A +/** Maximum BIG sync timeout value in units of 10 ms (163,840 ms) */ +#define BT_ISO_SYNC_TIMEOUT_MAX 0x4000 +/** Controller controlled maximum subevent count value */ +#define BT_ISO_SYNC_MSE_ANY 0x00 +/** Minimum BIG sync maximum subevent count value (1) */ +#define BT_ISO_SYNC_MSE_MIN 0x01 +/** Maximum BIG sync maximum subevent count value (31) */ +#define BT_ISO_SYNC_MSE_MAX 0x1F +/** Minimum connected ISO retransmission value (0) */ +#define BT_ISO_CONNECTED_RTN_MIN 0x00 +/** Maximum connected ISO retransmission value (255) */ +#define BT_ISO_CONNECTED_RTN_MAX 0xFF +/** Minimum broadcast ISO retransmission value (0) */ +#define BT_ISO_BROADCAST_RTN_MIN 0x00 +/** Maximum broadcast ISO retransmission value (30) */ +#define BT_ISO_BROADCAST_RTN_MAX 0x1E +/** Broadcast code size (16 octets) */ +#define BT_ISO_BROADCAST_CODE_SIZE 0x10 +/** Lowest BIS index (1) */ +#define BT_ISO_BIS_INDEX_MIN 0x01 +/** Highest BIS index (31) */ +#define BT_ISO_BIS_INDEX_MAX 0x1F +/** Minimum Immediate Repetition Count (1) */ +#define BT_ISO_IRC_MIN 0x01U +/** Maximum Immediate Repetition Count (15) */ +#define BT_ISO_IRC_MAX 0x0FU +/** Minimum pre-transmission offset (0) */ +#define BT_ISO_PTO_MIN 0x00U +/** Maximum pre-transmission offset (15) */ +#define BT_ISO_PTO_MAX 0x0FU +/** No subinterval */ +#define BT_ISO_SUBINTERVAL_NONE 0x00000000U +/** Unknown subinterval */ +#define BT_ISO_SUBINTERVAL_UNKNOWN 0xFFFFFFFFU +/** Minimum subinterval in microseconds (400 us) */ +#define BT_ISO_SUBINTERVAL_MIN 0x00000190U +/** @brief Maximum subinterval in microseconds (3,999,999 us) + * + * This maximum depends on the ISO interval, as the subinterval shall be less than the ISO interval + */ +#define BT_ISO_SUBINTERVAL_MAX 0x00009C3FU + +/** + * @brief Check if ISO BIS bitfield is valid (BT_ISO_BIS_INDEX_BIT(1)|..|BT_ISO_BIS_INDEX_BIT(31)) + * + * @param _bis_bitfield BIS index bitfield (uint32) + */ +#define BT_ISO_VALID_BIS_BITFIELD(_bis_bitfield) \ + ((_bis_bitfield) != 0U && (_bis_bitfield) <= BIT_MASK(BT_ISO_BIS_INDEX_MAX)) + +/** + * @brief Life-span states of ISO channel. Used only by internal APIs dealing with setting channel + * to proper state depending on operational context. + */ +enum bt_iso_state { + /** Channel disconnected */ + BT_ISO_STATE_DISCONNECTED, + /** Channel is pending ACL encryption before connecting */ + BT_ISO_STATE_ENCRYPT_PENDING, + /** Channel in connecting state */ + BT_ISO_STATE_CONNECTING, + /** Channel ready for upper layer traffic on it */ + BT_ISO_STATE_CONNECTED, + /** Channel in disconnecting state */ + BT_ISO_STATE_DISCONNECTING, +}; + +/** + * @brief ISO Channel Type. + */ +enum bt_iso_chan_type { + BT_ISO_CHAN_TYPE_NONE, /**< No channel type */ + BT_ISO_CHAN_TYPE_CENTRAL, /**< Connected as central */ + BT_ISO_CHAN_TYPE_PERIPHERAL, /**< Connected as peripheral */ + BT_ISO_CHAN_TYPE_BROADCASTER, /**< Isochronous broadcaster */ + BT_ISO_CHAN_TYPE_SYNC_RECEIVER /**< Synchronized receiver */ +}; + +/** @brief ISO Channel structure. */ +struct bt_iso_chan { + /** Channel connection reference */ + struct bt_conn *iso; + /** Channel operations reference */ + struct bt_iso_chan_ops *ops; + /** Channel QoS reference */ + struct bt_iso_chan_qos *qos; + /** Channel state */ + enum bt_iso_state state; + /** + * @brief The required security level of the channel + * + * This value can be set as the central before connecting a CIS + * with bt_iso_chan_connect(). + * The value is overwritten to @ref bt_iso_server::sec_level for the + * peripheral once a channel has been accepted. + * + * Only available when @kconfig{CONFIG_BT_SMP} is enabled. + */ + bt_security_t required_sec_level; + /** @internal Node used internally by the stack */ + sys_snode_t node; +}; + +/** @brief ISO Channel IO QoS structure. */ +struct bt_iso_chan_io_qos { + /** + * @brief Channel SDU. + * + * Value range is @ref BT_ISO_MIN_SDU to @ref BT_ISO_MAX_SDU. + */ + uint16_t sdu; + /** + * @brief Channel PHY - See the @ref bt_gap_le_phy values. + * + * Setting @ref BT_GAP_LE_PHY_NONE is invalid. + */ + uint8_t phy; + /** + * @brief Channel Retransmission Number. + * + * This value is ignored if any advanced ISO parameters are set. + */ + uint8_t rtn; + + /** + * @brief Maximum PDU size + * + * Maximum size, in octets, of the payload from link layer to link layer. + * + * Value range @ref BT_ISO_CONNECTED_PDU_MIN to @ref BT_ISO_PDU_MAX for connected ISO. + * + * Value range @ref BT_ISO_BROADCAST_PDU_MIN to @ref BT_ISO_PDU_MAX for broadcast ISO. + */ + uint16_t max_pdu; + + /** + * @brief Burst number + * + * Value range @ref BT_ISO_BN_MIN to @ref BT_ISO_BN_MAX. + */ + uint8_t burst_number; +}; + +/** @brief ISO Channel QoS structure. */ +struct bt_iso_chan_qos { + /** + * @brief Channel Receiving QoS. + * + * Setting NULL disables data path @ref BT_HCI_DATAPATH_DIR_CTLR_TO_HOST. + * + * Can only be set for a connected isochronous channel, or a broadcast isochronous receiver. + */ + struct bt_iso_chan_io_qos *rx; + /** + * @brief Channel Transmission QoS + * + * Setting NULL disables data path @ref BT_HCI_DATAPATH_DIR_HOST_TO_CTLR. + * + * Can only be set for a connected isochronous channel, or a broadcast + * isochronous transmitter. + */ + struct bt_iso_chan_io_qos *tx; + + /** + * @brief Number of subevents + * + * Maximum number of subevents in each CIS or BIS event. + * + * Value range @ref BT_ISO_NSE_MIN to @ref BT_ISO_NSE_MAX. + */ + uint8_t num_subevents; +}; + +/** @brief ISO Channel Data Path structure. */ +struct bt_iso_chan_path { + /** + * @brief Default path ID + * + * @ref BT_ISO_DATA_PATH_HCI to use ISO over HCI or between @ref BT_ISO_DATA_PATH_VS_ID_MIN + * and @ref BT_ISO_DATA_PATH_VS_ID_MAX for vendor specific data paths. + */ + uint8_t pid; + /** + * @brief Coding Format + * + * See the BT_HCI_CODING_FORMAT_* values for valid values. + */ + uint8_t format; + /** Company ID */ + uint16_t cid; + /** Vendor-defined Codec ID */ + uint16_t vid; + /** + * @brief Controller Delay in microseconds + * + * Value range from @ref BT_ISO_CONTROLLER_DELAY_MIN to @ref BT_ISO_CONTROLLER_DELAY_MAX. + */ + uint32_t delay; + /** Codec Configuration length*/ + uint8_t cc_len; + /** + * @brief Pointer to an array containing the Codec Configuration + * + * Shall not be NULL if bt_iso_chan_path.cc_len is non-zero. + */ + uint8_t *cc; +}; + +/** ISO packet status flag bits */ +enum { + /** The ISO packet is valid. */ + BT_ISO_FLAGS_VALID = BIT(0), + + /** + * @brief The ISO packet may possibly contain errors. + * + * May be caused by a failed CRC check or if missing a part of the SDU. + */ + BT_ISO_FLAGS_ERROR = BIT(1), + + /** The ISO packet was lost. */ + BT_ISO_FLAGS_LOST = BIT(2), + + /** + * @brief Timestamp is valid + * + * If not set, then the bt_iso_recv_info.ts value is not valid, and + * should not be used. + */ + BT_ISO_FLAGS_TS = BIT(3) +}; + +/** @brief ISO Meta Data structure for received ISO packets. */ +struct bt_iso_recv_info { + /** + * @brief ISO timestamp + * + * Only valid if @p flags has the @ref BT_ISO_FLAGS_TS bit set. + */ + uint32_t ts; + + /** ISO packet sequence number of the first fragment in the SDU */ + uint16_t seq_num; + + /** ISO packet flags bitfield (BT_ISO_FLAGS_*) */ + uint8_t flags; +}; + +/** @brief ISO Meta Data structure for transmitted ISO packets. */ +struct bt_iso_tx_info { + /** CIG reference point or BIG anchor point of a transmitted SDU, in microseconds. */ + uint32_t ts; + + /** Time offset, in microseconds */ + uint32_t offset; + + /** Packet sequence number */ + uint16_t seq_num; +}; + +/** Opaque type representing an Connected Isochronous Group (CIG). */ +struct bt_iso_cig; + +/** @brief Connected Isochronous Group (CIG) parameters */ +struct bt_iso_cig_param { + /** @brief Array of pointers to CIS channels */ + struct bt_iso_chan **cis_channels; + + /** + * @brief Number of channels in @p cis_channels + * + * Maximum number of channels in a single group is @ref BT_ISO_MAX_GROUP_ISO_COUNT + */ + uint8_t num_cis; + + /** + * @brief Channel interval in us for SDUs sent from Central to Peripheral. + * + * Value range @ref BT_ISO_SDU_INTERVAL_MIN to @ref BT_ISO_SDU_INTERVAL_MAX. + */ + uint32_t c_to_p_interval; + + /** + * @brief Channel interval in us for SDUs sent from Peripheral to Central. + * + * Value range @ref BT_ISO_SDU_INTERVAL_MIN to @ref BT_ISO_SDU_INTERVAL_MAX. + */ + uint32_t p_to_c_interval; + + /** + * @brief Channel Latency in ms for SDUs sent from Central to Peripheral + * + * Value range @ref BT_ISO_LATENCY_MIN to @ref BT_ISO_LATENCY_MAX. + * + * This value is ignored if any advanced ISO parameters are set. + */ + uint16_t c_to_p_latency; + + /** + * @brief Channel Latency in ms for SDUs sent from Peripheral to Central + * + * Value range @ref BT_ISO_LATENCY_MIN to @ref BT_ISO_LATENCY_MAX. + * + * This value is ignored if any advanced ISO parameters are set. + */ + uint16_t p_to_c_latency; + + /** + * @brief Channel peripherals sleep clock accuracy Only for CIS + * + * Shall be worst case sleep clock accuracy of all the peripherals. + * For possible values, see @ref bt_gap_sca. + * If unknown for the peripherals, this should be set to @ref BT_GAP_SCA_UNKNOWN. + */ + uint8_t sca; + + /** + * @brief Channel packing mode. + * + * @ref BT_ISO_PACKING_SEQUENTIAL or @ref BT_ISO_PACKING_INTERLEAVED + */ + uint8_t packing; + + /** + * @brief Channel framing mode. + * + * @ref BT_ISO_FRAMING_UNFRAMED for unframed and @ref BT_ISO_FRAMING_FRAMED for framed. + */ + uint8_t framing; + + /** + * @brief Central to Peripheral flush timeout + * + * The flush timeout in multiples of ISO_Interval for each payload sent + * from the Central to Peripheral. + * + * Value range from @ref BT_ISO_FT_MIN to @ref BT_ISO_FT_MAX + */ + uint8_t c_to_p_ft; + + /** + * @brief Peripheral to Central flush timeout + * + * The flush timeout in multiples of ISO_Interval for each payload sent + * from the Peripheral to Central. + * + * Value range from @ref BT_ISO_FT_MIN to @ref BT_ISO_FT_MAX. + */ + uint8_t p_to_c_ft; + + /** + * @brief ISO interval + * + * Time between consecutive CIS anchor points. + * + * Value range from @ref BT_ISO_ISO_INTERVAL_MIN to @ref BT_ISO_ISO_INTERVAL_MAX. + */ + uint16_t iso_interval; +}; + +/** ISO connection parameters structure */ +struct bt_iso_connect_param { + /** The ISO channel to connect */ + struct bt_iso_chan *iso_chan; + + /** The ACL connection */ + struct bt_conn *acl; +}; + +/** Opaque type representing a Broadcast Isochronous Group (BIG). */ +struct bt_iso_big; + +/** @brief Broadcast Isochronous Group (BIG) creation parameters */ +struct bt_iso_big_create_param { + /** Array of pointers to BIS channels */ + struct bt_iso_chan **bis_channels; + + /** + * @brief Number of channels in @p bis_channels + * + * Maximum number of channels in a single group is @ref BT_ISO_MAX_GROUP_ISO_COUNT + */ + uint8_t num_bis; + + /** + * @brief Channel interval in us. + * + * Value range @ref BT_ISO_SDU_INTERVAL_MIN to @ref BT_ISO_SDU_INTERVAL_MAX. + */ + uint32_t interval; + + /** + * @brief Channel Latency in ms. + * + * Value range @ref BT_ISO_LATENCY_MIN to @ref BT_ISO_LATENCY_MAX. + * + * This value is ignored if any advanced ISO parameters are set. + */ + uint16_t latency; + + /** + * @brief Channel packing mode. + * + * @ref BT_ISO_PACKING_SEQUENTIAL or @ref BT_ISO_PACKING_INTERLEAVED + */ + uint8_t packing; + + /** + * @brief Channel framing mode. + * + * @ref BT_ISO_FRAMING_UNFRAMED for unframed and @ref BT_ISO_FRAMING_FRAMED for framed. + */ + uint8_t framing; + + /** Whether or not to encrypt the streams. */ + bool encryption; + + /** + * @brief Broadcast code + * + * The code used to derive the session key that is used to encrypt and decrypt BIS payloads. + * + * If the value is a string or the value is less than 16 octets, + * the remaining octets shall be 0. + * + * Example: + * The string "Broadcast Code" shall be + * [42 72 6F 61 64 63 61 73 74 20 43 6F 64 65 00 00] + */ + uint8_t bcode[BT_ISO_BROADCAST_CODE_SIZE]; + + /** + * @brief Immediate Repetition Count + * + * The number of times the scheduled payloads are transmitted in a given event. + * + * Value range from @ref BT_ISO_IRC_MIN to @ref BT_ISO_IRC_MAX. + */ + uint8_t irc; + + /** + * @brief Pre-transmission offset + * + * Offset used for pre-transmissions. + * + * Value range from @ref BT_ISO_PTO_MIN to @ref BT_ISO_PTO_MAX. + */ + uint8_t pto; + + /** + * @brief ISO interval + * + * Time between consecutive BIS anchor points. + * + * Value range from @ref BT_ISO_ISO_INTERVAL_MIN to @ref BT_ISO_ISO_INTERVAL_MAX. + */ + uint16_t iso_interval; +}; + +/** @brief Broadcast Isochronous Group (BIG) Sync Parameters */ +struct bt_iso_big_sync_param { + /** Array of pointers to BIS channels */ + struct bt_iso_chan **bis_channels; + + /** + * @brief Number channels in @p bis_channels + * + * Maximum number of channels in a single group is @ref BT_ISO_MAX_GROUP_ISO_COUNT + */ + uint8_t num_bis; + + /** + * @brief Bitfield of the BISes to sync to + * + * Use @ref BT_ISO_BIS_INDEX_BIT to convert BIS indexes to a bitfield. + * + * To synchronize to e.g. BIS indexes 0x01 and 0x02, this can be set to + * BT_ISO_BIS_INDEX_BIT(0x01) | BT_ISO_BIS_INDEX_BIT(0x02). + */ + uint32_t bis_bitfield; + + /** + * @brief Maximum subevents + * + * The MSE (Maximum Subevents) parameter is the maximum number of + * subevents that a Controller should use to receive data payloads + * in each interval for a BIS. + * + * Value range is @ref BT_ISO_SYNC_MSE_MIN to @ref BT_ISO_SYNC_MSE_MAX, or + * @ref BT_ISO_SYNC_MSE_ANY to let the controller choose. + */ + uint32_t mse; + + /** + * @brief Synchronization timeout for the BIG (N * 10 MS) + * + * Value range is @ref BT_ISO_SYNC_TIMEOUT_MIN to @ref BT_ISO_SYNC_TIMEOUT_MAX. + */ + uint16_t sync_timeout; + + /** Whether or not the streams of the BIG are encrypted */ + bool encryption; + + /** + * @brief Broadcast code + * + * The code used to derive the session key that is used to encrypt and decrypt BIS payloads. + * + * If the value is a string or a the value is less than 16 octets, + * the remaining octets shall be 0. + * + * Example: + * The string "Broadcast Code" shall be + * [42 72 6F 61 64 63 61 73 74 20 43 6F 64 65 00 00] + */ + uint8_t bcode[BT_ISO_BROADCAST_CODE_SIZE]; +}; + +/** @brief Broadcast Isochronous Group (BIG) information */ +struct bt_iso_biginfo { + /** Address of the advertiser */ + const bt_addr_le_t *addr; + + /** Advertiser SID */ + uint8_t sid; + + /** Number of BISes in the BIG */ + uint8_t num_bis; + + /** Maximum number of subevents in each isochronous event */ + uint8_t sub_evt_count; + + /** Interval between two BIG anchor point (N * 1.25 ms) */ + uint16_t iso_interval; + + /** The number of new payloads in each BIS event */ + uint8_t burst_number; + + /** Offset used for pre-transmissions */ + uint8_t offset; + + /** The number of times a payload is transmitted in a BIS event */ + uint8_t rep_count; + + /** Maximum size, in octets, of the payload */ + uint16_t max_pdu; + + /** The interval, in microseconds, of periodic SDUs. */ + uint32_t sdu_interval; + + /** Maximum size of an SDU, in octets. */ + uint16_t max_sdu; + + /** Channel PHY */ + uint8_t phy; + + /** Channel framing mode */ + uint8_t framing; + + /** Whether or not the BIG is encrypted */ + bool encryption; +}; + +/** @brief ISO Channel operations structure. */ +struct bt_iso_chan_ops { + /** + * @brief Channel connected callback + * + * If this callback is provided it will be called whenever the connection completes. + * + * For a peripheral, the QoS values (see @ref bt_iso_chan_io_qos) + * are set when this is called. The peripheral does not have any + * information about the RTN though. + * + * @param chan The channel that has been connected + */ + void (*connected)(struct bt_iso_chan *chan); + + /** + * @brief Channel disconnected callback + * + * If this callback is provided it will be called whenever the + * channel is disconnected, including when a connection gets + * rejected or when setting security fails. + * + * If the channel was established (i.e. @ref bt_iso_chan_ops.connected has been called + * for this channel), then the channel object is still valid and the memory of the channel + * shall not be memset to 0 or otherwise free'd. + * To avoid any issues it is recommended to use a @ref k_work_submit or similar to not + * overwrite any data while in the callback. + * + * For the above reason it is still possible to use bt_iso_chan_get_info() on the @p chan. + * + * @param chan The channel that has been Disconnected + * @param reason BT_HCI_ERR_* reason for the disconnection. + */ + void (*disconnected)(struct bt_iso_chan *chan, uint8_t reason); + + /** + * @brief Channel alloc_buf callback + * + * If this callback is provided the channel will use it to allocate + * buffers to store incoming data. + * + * @param chan The channel requesting a buffer. + * + * @return Allocated buffer. + */ + struct net_buf *(*alloc_buf)(struct bt_iso_chan *chan); + + /** + * @brief Channel recv callback + * + * @param chan The channel receiving data. + * @param buf Buffer containing incoming data. + * @param info Pointer to the metadata for the buffer. The lifetime of the + * pointer is linked to the lifetime of the net_buf. + * Metadata such as sequence number and timestamp can be + * provided by the bluetooth controller. + */ + void (*recv)(struct bt_iso_chan *chan, const struct bt_iso_recv_info *info, + const uint8_t *data, uint16_t len); + + /** + * @brief Channel sent callback + * + * This callback will be called once the controller marks the SDU + * as completed. When the controller does so is implementation + * dependent. It could be after the SDU is enqueued for transmission, + * or after it is sent on air or flushed. + * + * @param chan The channel which has sent data. + */ + void (*sent)(struct bt_iso_chan *chan, void *user_data); +}; + +/** @brief ISO Accept Info Structure */ +struct bt_iso_accept_info { + /** The ACL connection that is requesting authorization */ + struct bt_conn *acl; + + /** + * @brief The ID of the connected isochronous group (CIG) on the central + * + * The ID is unique per ACL + */ + uint8_t cig_id; + + /** + * @brief The ID of the connected isochronous stream (CIS) on the central + * + * This ID is unique within a CIG + */ + uint8_t cis_id; +}; + +/** @brief ISO Server structure. */ +struct bt_iso_server { + /** + * @brief Required minimum security level. + * + * Only available when @kconfig{CONFIG_BT_SMP} is enabled. + */ + bt_security_t sec_level; + + /** + * @brief Server accept callback + * + * This callback is called whenever a new incoming connection requires authorization. + * + * @param info The ISO accept information structure + * @param chan Pointer to receive the allocated channel + * + * @return 0 in case of success or negative value in case of error. + */ + int (*accept)(const struct bt_iso_accept_info *info, struct bt_iso_chan **chan); +}; + +/** + * @brief Register ISO server. + * + * Register ISO server, each new connection is authorized using the accept() + * callback which in case of success shall allocate the channel structure + * to be used by the new connection. + * + * @param server Server structure. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_iso_server_register_safe(struct bt_iso_server *server); + +/** + * @brief Unregister ISO server. + * + * Unregister previously registered ISO server. + * + * @param server Server structure. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_iso_server_unregister_safe(struct bt_iso_server *server); + +/** + * @brief Creates a CIG as a central + * + * This can called at any time, even before connecting to a remote device. + * This must be called before any connected isochronous stream (CIS) channel can be connected. + * + * Once a CIG is created, the channels supplied in the @p param can be + * connected using bt_iso_chan_connect(). + * + * @param[in] param The parameters used to create and enable the CIG. + * @param[out] out_cig Connected Isochronous Group object on success. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_iso_cig_create_safe(const struct bt_iso_cig_param *param, struct bt_iso_cig **out_cig); + +/** + * @brief Reconfigure a CIG as a central + * + * This function can be used to update a CIG. It will update the group specific + * parameters, and, if supplied, change the QoS parameters of the individual + * CIS. If the cis_channels in @p param contains CIS that was not originally + * in the call to bt_iso_cig_create(), these will be added to the group. + * It is not possible to remove any CIS from the group after creation. + * + * This can be called at any time before connecting an ISO to a remote device. + * Once any CIS in the group has connected, the group cannot be changed. + * + * Once a CIG is created, the channels supplied in the @p param can be + * connected using bt_iso_chan_connect(). + * + * @param cig Connected Isochronous Group object. + * @param param The parameters used to reconfigure the CIG. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_iso_cig_reconfigure_safe(struct bt_iso_cig *cig, const struct bt_iso_cig_param *param); + +/** + * @brief Terminates a CIG as a central + * + * All the CIS in the CIG shall be disconnected first. + * + * @param cig Pointer to the CIG structure. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_iso_cig_terminate_safe(struct bt_iso_cig *cig); + +/** + * @brief Connect ISO channels on ACL connections + * + * Connect ISO channels. The ISO channels must have been initialized in a CIG + * first by calling bt_iso_cig_create(). + * + * Once the connection is completed the channels' connected() callback will be + * called. If the connection is rejected disconnected() callback is called + * instead. + * + * This function will also setup the ISO data path based on the @p path + * parameter of the @ref bt_iso_chan_io_qos for each channel. + * + * @param param Pointer to a connect parameter array with the ISO and ACL pointers. + * @param count Number of connect parameters. + * + * @retval 0 Successfully started the connecting procedure. + * + * @retval -EINVAL Invalid parameters were supplied. + * + * @retval -EBUSY Some ISO channels are already being connected. + * It is not possible to have multiple outstanding connection requests. + * May also be returned if @kconfig{CONFIG_BT_SMP} is enabled and a + * pairing procedure is already in progress. + * + * @retval -ENOBUFS Not buffers available to send request to controller or if + * @kconfig{CONFIG_BT_SMP} is enabled and no more keys could be stored. + * + * @retval -ENOMEM If @kconfig{CONFIG_BT_SMP} is enabled and no more keys + * could be stored. + * + * @retval -EIO Controller rejected the request or if @kconfig{CONFIG_BT_SMP} + * is enabled and pairing has timed out. + * + * @retval -ENOTCONN If @kconfig{CONFIG_BT_SMP} is enabled the ACL is not + * connected. + */ +int bt_iso_chan_connect(const struct bt_iso_connect_param *param, size_t count); +int bt_iso_chan_connect_safe(const struct bt_iso_connect_param *param, size_t count); + +/** + * @brief Disconnect connected ISO channel + * + * Disconnect connected ISO channel. + * + * If the device is a central and the connection is pending it will be + * canceled and as a result the channel bt_iso_chan_ops.disconnected() callback is called. + * + * If the device is a peripheral and the connection is pending it will be rejected, as a peripheral + * shall wait for a CIS Established event (which may trigger a bt_iso_chan_ops.disconnected() + * callback in case of an error). + * + * Regarding to input parameter, to get details see reference description + * to bt_iso_chan_connect() API. + * + * @param chan Channel object. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_iso_chan_disconnect_safe(struct bt_iso_chan *chan); + +/** + * @brief Send data to ISO channel without timestamp + * + * Send data from buffer to the channel. If credits are not available, buf will + * be queued and sent as and when credits are received from peer. + * Regarding to first input parameter, to get details see reference description + * to bt_iso_chan_connect() API. + * + * @note Buffer ownership is transferred to the stack in case of success, in + * case of an error the caller retains the ownership of the buffer. + * + * @param chan Channel object. + * @param buf Buffer containing data to be sent. + * @param seq_num Packet Sequence number. This value shall be incremented for + * each call to this function and at least once per SDU + * interval for a specific channel. + * + * @return Number of octets sent in case of success or negative value in case of error. + */ +int bt_iso_chan_send_safe(struct bt_iso_chan *chan, struct net_buf *buf, uint16_t seq_num); + +/** + * @brief Send data to ISO channel with timestamp + * + * Send data from buffer to the channel. If credits are not available, buf will + * be queued and sent as and when credits are received from peer. + * Regarding to first input parameter, to get details see reference description + * to bt_iso_chan_connect() API. + * + * @note Buffer ownership is transferred to the stack in case of success, in + * case of an error the caller retains the ownership of the buffer. + * + * @param chan Channel object. + * @param buf Buffer containing data to be sent. + * @param seq_num Packet Sequence number. This value shall be incremented for + * each call to this function and at least once per SDU + * interval for a specific channel. + * @param ts Timestamp of the SDU in microseconds (us). + * This value can be used to transmit multiple + * SDUs in the same SDU interval in a CIG or BIG. + * + * @return Number of octets sent in case of success or negative value in case of error. + */ +int bt_iso_chan_send_ts_safe(struct bt_iso_chan *chan, struct net_buf *buf, uint16_t seq_num, + uint32_t ts); + +/** + * @brief Sets up the ISO data path for a ISO channel + * + * The channel must be associated with a BIS or CIS handle first which it is when the + * bt_iso_chan_ops.connected() callback is called. + * + * @param chan The channel to setup the ISO data path for + * @param dir The direction to setup, either @ref BT_HCI_DATAPATH_DIR_CTLR_TO_HOST or + * @ref BT_HCI_DATAPATH_DIR_HOST_TO_CTLR. For ISO broadcast channels this can only be + * @ref BT_HCI_DATAPATH_DIR_HOST_TO_CTLR, and for ISO sync receiver channels this can + * only be @ref BT_HCI_DATAPATH_DIR_CTLR_TO_HOST. + * @param path The data path + * + * @retval 0 Success + * @retval -EINVAL Invalid parameters + * @retval -ENOBUFS No HCI command buffer could be allocated + * @retval -EIO The controller rejected the request or response contains invalid data + * @retval -ENODEV @p chan is not associated with a CIS or BIS handle + * @retval -EACCES The controller rejected the request as disallowed + * @retval -ENOEXEC Unexpected error occurred + */ +int bt_iso_setup_data_path_safe(const struct bt_iso_chan *chan, uint8_t dir, + const struct bt_iso_chan_path *path); + +/** + * @brief Removes the ISO data path for a ISO channel + * + * Removes the ISO data path configured by bt_iso_setup_data_path() for the provided @p dir. + * + * The data paths of CIS for Peripherals are deleted by the controller, + * and thus it is not necessary (or possible) to remove + * data paths of CIS after they have disconnected for a Peripheral, + * as per Bluetooth Core specification 6.0, Vol 4, Part E, Section 7.7.5. + * The data paths for CIS for a Central remain valid, even after a disconnection, and thus a Central + * device should call bt_iso_remove_data_path() on disconnect if it no longer wants to use that CIS. + * All data paths created by a Central are removed when the CIG is removed with + * bt_iso_cig_terminate(). + * + * Any data paths associated with an ISO Sync Receiver BIG are removed by the controller + * when the BIG sync is lost or terminated, and thus it is not necessary (or possible) to remove + * data paths of ISO channels associated with a BIG for a Sync Receiver, + * as per Bluetooth Core specification 6.0, Vol 4, Part E, Section 7.7.65.30 + * + * All data paths associated with an ISO Broadcaster BIG are removed when the BIG is terminated by + * bt_iso_big_terminate(), and thus it is not necessary (or possible) to remove data paths of ISO + * channels associated with a BIG for a Broadcaster, + * as per Bluetooth Core specification 6.0, Vol 4, Part E, Section 7.8.105 + * + * @param chan The channel to setup the ISO data path for + * @param dir The direction to setup, either @ref BT_HCI_DATAPATH_DIR_CTLR_TO_HOST or + * @ref BT_HCI_DATAPATH_DIR_HOST_TO_CTLR. For ISO broadcast channels this can only be + * @ref BT_HCI_DATAPATH_DIR_HOST_TO_CTLR, and for ISO sync receiver channels this can + * only be @ref BT_HCI_DATAPATH_DIR_CTLR_TO_HOST. + + * @retval 0 Success + * @retval -EINVAL Invalid parameters + * @retval -ENOBUFS No HCI command buffer could be allocated + * @retval -EIO The controller rejected the request or response contains invalid data + * @retval -ENODEV @p chan is not associated with a CIS or BIS handle + * @retval -EACCES The controller rejected the request as disallowed + * @retval -ENOEXEC Unexpected error occurred + */ +int bt_iso_remove_data_path_safe(const struct bt_iso_chan *chan, uint8_t dir); + +/** @brief ISO Unicast TX Info Structure */ +struct bt_iso_unicast_tx_info { + /** The transport latency in us */ + uint32_t latency; + + /** The flush timeout (N * 1.25 ms) */ + uint32_t flush_timeout; + + /** The maximum PDU size in octets */ + uint16_t max_pdu; + + /** The transport PHY */ + uint8_t phy; + + /** The burst number */ + uint8_t bn; + + /** The maximum SDU size in octets + * + * May be set to @ref bt_iso_unicast_tx_info.max_pdu for peripherals if unknown + */ + uint16_t max_sdu; + + /** The SDU interval in microseconds + * + * May be set to @ref BT_ISO_SDU_INTERVAL_UNKNOWN for if unknown. + */ + uint32_t sdu_interval; +}; + +/** @brief ISO Unicast Info Structure */ +struct bt_iso_unicast_info { + /** Connected Isochronous Group ID */ + uint8_t cig_id; + + /** Connected Isochronous Stream ID */ + uint8_t cis_id; + + /** The maximum time in us for all PDUs of all CIS in a CIG event */ + uint32_t cig_sync_delay; + + /** The maximum time in us for all PDUs of this CIS in a CIG event */ + uint32_t cis_sync_delay; + + /** + * @brief The subinterval in microseconds + * + * Will be @ref BT_ISO_SUBINTERVAL_NONE if there is no subinterval (NSE = 1). + * Will be @ref BT_ISO_SUBINTERVAL_UNKNOWN if unknown. + */ + uint32_t subinterval; + + /** @brief TX information for the central to peripheral data path */ + struct bt_iso_unicast_tx_info central; + + /** TX information for the peripheral to central data */ + struct bt_iso_unicast_tx_info peripheral; +}; + +/** @brief ISO Broadcaster Info Structure */ +struct bt_iso_broadcaster_info { + /** Broadcast Isochronous Group Handle */ + uint8_t big_handle; + + /** Broadcast Isochronous Stream number */ + uint8_t bis_number; + + /** The maximum time in us for all PDUs of all BIS in a BIG event */ + uint32_t sync_delay; + + /** The transport latency in us */ + uint32_t latency; + + /** Pre-transmission offset (N * 1.25 ms) */ + uint32_t pto; + + /** The maximum PDU size in octets */ + uint16_t max_pdu; + + /** The transport PHY */ + uint8_t phy; + + /** The burst number */ + uint8_t bn; + + /** Number of times a payload is transmitted in a BIS event */ + uint8_t irc; +}; + +/** @brief ISO Synchronized Receiver Info Structure */ +struct bt_iso_sync_receiver_info { + /** Broadcast Isochronous Group handle */ + uint8_t big_handle; + + /** Broadcast Isochronous Stream number */ + uint8_t bis_number; + + /** The transport latency in us */ + uint32_t latency; + + /** Pre-transmission offset (N * 1.25 ms) */ + uint32_t pto; + + /** The maximum PDU size in octets */ + uint16_t max_pdu; + + /** The burst number */ + uint8_t bn; + + /** Number of times a payload is transmitted in a BIS event */ + uint8_t irc; +}; + +/** ISO channel Info Structure */ +struct bt_iso_info { + /** Channel Type. */ + enum bt_iso_chan_type type; + + /** The ISO interval (N * 1.25 ms) */ + uint16_t iso_interval; + + /** The maximum number of subevents in each ISO event */ + uint8_t max_subevent; + + /** + * @brief True if the channel is able to send data + * + * This is always true when @p type is @ref BT_ISO_CHAN_TYPE_BROADCASTER, + * and never true when @p type is @ref BT_ISO_CHAN_TYPE_SYNC_RECEIVER. + */ + bool can_send; + + /** + * @brief True if the channel is able to recv data + * + * This is always true when @p type is @ref BT_ISO_CHAN_TYPE_SYNC_RECEIVER, + * and never true when @p type is @ref BT_ISO_CHAN_TYPE_BROADCASTER. + */ + bool can_recv; + + /** Connection Type specific Info.*/ + union { + /** + * @brief Unicast specific Info. + * + * Only available when @kconfig{CONFIG_BT_ISO_UNICAST} is enabled. + * Use this when the @ref bt_iso_info.type is @ref BT_ISO_CHAN_TYPE_CENTRAL or + * @ref BT_ISO_CHAN_TYPE_PERIPHERAL. + */ + struct bt_iso_unicast_info unicast; + /** + * @brief Broadcaster specific Info. + * + * Only available when @kconfig{CONFIG_BT_ISO_BROADCASTER} is enabled. + * Use this when the @ref bt_iso_info.type is @ref BT_ISO_CHAN_TYPE_BROADCASTER. + */ + struct bt_iso_broadcaster_info broadcaster; + /** + * @brief Sync receiver specific Info. + * + * Only available when @kconfig{CONFIG_BT_ISO_SYNC_RECEIVER} is enabled. + * Use this when the @ref bt_iso_info.type is @ref BT_ISO_CHAN_TYPE_SYNC_RECEIVER. + */ + struct bt_iso_sync_receiver_info sync_receiver; + }; +}; + +/** + * @brief Get ISO channel info + * + * @param chan Channel object. + * @param info Channel info object. + * + * @return Zero on success or (negative) error code on failure. + */ +int bt_iso_chan_get_info_safe(const struct bt_iso_chan *chan, struct bt_iso_info *info); + +/** + * @brief Get ISO transmission timing info + * + * @details Reads timing information for transmitted ISO packet on an ISO channel. + * The HCI_LE_Read_ISO_TX_Sync HCI command is used to retrieve this information + * from the controller. + * + * @note An SDU must have already been successfully transmitted on the ISO channel + * for this function to return successfully. + * + * @param[in] chan Channel object. + * @param[out] info Transmit info object. + * + * @return Zero on success or (negative) error code on failure. + */ +int bt_iso_chan_get_tx_sync_safe(const struct bt_iso_chan *chan, struct bt_iso_tx_info *info); + +/** + * @brief Struct to hold the Broadcast Isochronous Group callbacks + * + * These can be registered for usage with bt_iso_big_register_cb(). + */ +struct bt_iso_big_cb { + /** + * @brief The BIG has started and all of the streams are ready for data + * + * @param big The started BIG + */ + void (*started)(struct bt_iso_big *big); + + /** + * @brief The BIG has stopped and none of the streams are ready for data + * + * @param big The stopped BIG + * @param reason The reason why the BIG stopped (see the BT_HCI_ERR_* values) + */ + void (*stopped)(struct bt_iso_big *big, uint8_t reason); + + /** @internal Internally used field for list handling */ + sys_snode_t _node; +}; + +/** + * @brief Registers callbacks for Broadcast Sources + * + * @param cb Pointer to the callback structure. + * + * @retval 0 on success + * @retval -EINVAL if @p cb is NULL + * @retval -EEXIST if @p cb is already registered + */ +int bt_iso_big_register_cb_safe(struct bt_iso_big_cb *cb); + +/** + * @brief Creates a BIG as a broadcaster + * + * @param[in] padv Pointer to the periodic advertising object the BIGInfo shall be sent on. + * @param[in] param The parameters used to create and enable the BIG. The QOS parameters are + * determined by the QOS field of the first BIS in the BIS list of this + * parameter. + * @param[out] out_big Broadcast Isochronous Group object on success. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_iso_big_create(struct bt_le_ext_adv *padv, struct bt_iso_big_create_param *param, + struct bt_iso_big **out_big); +int bt_iso_big_create_safe(struct bt_le_ext_adv *padv, struct bt_iso_big_create_param *param, + struct bt_iso_big **out_big); + +/** + * @brief Terminates a BIG as a broadcaster or receiver + * + * This function cannot be called while in @ref bt_iso_big_cb.started, @ref bt_iso_big_cb.stopped, + * @ref bt_iso_chan_ops.connected or @ref bt_iso_chan_ops.disconnected callbacks. + * + * @param big Pointer to the BIG structure. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_iso_big_terminate_safe(struct bt_iso_big *big); + +/** + * @brief Creates a BIG as a receiver + * + * @param[in] sync Pointer to the periodic advertising sync object the BIGInfo was received on. + * @param[in] param The parameters used to create and enable the BIG sync. + * @param[out] out_big Broadcast Isochronous Group object on success. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_iso_big_sync_safe(struct bt_le_per_adv_sync *sync, struct bt_iso_big_sync_param *param, + struct bt_iso_big **out_big); + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_ISO_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/l2cap.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/l2cap.h new file mode 100644 index 0000000000..65fd405560 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/l2cap.h @@ -0,0 +1,603 @@ +/** @file + * @brief Bluetooth L2CAP handling + */ + +/* + * SPDX-FileCopyrightText: 2015-2016 Intel Corporation + * SPDX-FileCopyrightText: 2023 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_L2CAP_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_L2CAP_H_ + +/** + * @brief L2CAP + * @defgroup bt_l2cap L2CAP + * @ingroup bluetooth + * @{ + */ + +#include +#include + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** L2CAP PDU header size, used for buffer size calculations */ +#define BT_L2CAP_HDR_SIZE 4 + +/** Maximum Transmission Unit (MTU) for an outgoing L2CAP PDU. */ +#define BT_L2CAP_TX_MTU (CONFIG_BT_L2CAP_TX_MTU) + +/** Maximum Transmission Unit (MTU) for an incoming L2CAP PDU. */ +#define BT_L2CAP_RX_MTU (CONFIG_BT_L2CAP_RX_MTU - BT_L2CAP_HDR_SIZE) + +/** @brief Helper to calculate needed buffer size for L2CAP PDUs. + * Useful for creating buffer pools. + * + * @param mtu Needed L2CAP PDU MTU. + * + * @return Needed buffer size to match the requested L2CAP PDU MTU. + */ +#define BT_L2CAP_BUF_SIZE(mtu) BT_BUF_ACL_SIZE(BT_L2CAP_HDR_SIZE + (mtu)) + +/** L2CAP SDU header size, used for buffer size calculations */ +#define BT_L2CAP_SDU_HDR_SIZE 2 + +/** @brief Maximum Transmission Unit for an unsegmented outgoing L2CAP SDU. + * + * The Maximum Transmission Unit for an outgoing L2CAP SDU when sent without + * segmentation, i.e. a single L2CAP SDU will fit inside a single L2CAP PDU. + * + * The MTU for outgoing L2CAP SDUs with segmentation is defined by the + * size of the application buffer pool. + */ +#define BT_L2CAP_SDU_TX_MTU (BT_L2CAP_TX_MTU - BT_L2CAP_SDU_HDR_SIZE) + +/** @brief Maximum Transmission Unit for an unsegmented incoming L2CAP SDU. + * + * The Maximum Transmission Unit for an incoming L2CAP SDU when sent without + * segmentation, i.e. a single L2CAP SDU will fit inside a single L2CAP PDU. + * + * The MTU for incoming L2CAP SDUs with segmentation is defined by the + * size of the application buffer pool. The application will have to define + * an alloc_buf callback for the channel in order to support receiving + * segmented L2CAP SDUs. + */ +#define BT_L2CAP_SDU_RX_MTU (BT_L2CAP_RX_MTU - BT_L2CAP_SDU_HDR_SIZE) + +/** + * + * @brief Helper to calculate needed buffer size for L2CAP SDUs. + * Useful for creating buffer pools. + * + * @param mtu Required BT_L2CAP_*_SDU. + * + * @return Needed buffer size to match the requested L2CAP SDU MTU. + */ +#define BT_L2CAP_SDU_BUF_SIZE(mtu) BT_L2CAP_BUF_SIZE(BT_L2CAP_SDU_HDR_SIZE + (mtu)) + +struct bt_l2cap_chan; + +/** @typedef bt_l2cap_chan_destroy_t + * @brief Channel destroy callback + * + * @param chan Channel object. + */ +typedef void (*bt_l2cap_chan_destroy_t)(struct bt_l2cap_chan *chan); + +/** @brief Life-span states of L2CAP CoC channel. + * + * Used only by internal APIs dealing with setting channel to proper state + * depending on operational context. + * + * A channel enters the @ref BT_L2CAP_CONNECTING state upon @ref + * bt_l2cap_chan_connect, @ref bt_l2cap_ecred_chan_connect or upon returning + * from @ref bt_l2cap_server.accept. + * + * When a channel leaves the @ref BT_L2CAP_CONNECTING state, @ref + * bt_l2cap_chan_ops.connected is called. + */ +typedef enum bt_l2cap_chan_state { + /** Channel disconnected */ + BT_L2CAP_DISCONNECTED, + /** Channel in connecting state */ + BT_L2CAP_CONNECTING, + /** Channel in config state, BR/EDR specific */ + BT_L2CAP_CONFIG, + /** Channel ready for upper layer traffic on it */ + BT_L2CAP_CONNECTED, + /** Channel in disconnecting state */ + BT_L2CAP_DISCONNECTING, + +} __packed bt_l2cap_chan_state_t; + +/** @brief Status of L2CAP channel. */ +typedef enum bt_l2cap_chan_status { + /** Channel can send at least one PDU */ + BT_L2CAP_STATUS_OUT, + + /** @brief Channel shutdown status + * + * Once this status is notified it means the channel will no longer be + * able to transmit or receive data. + */ + BT_L2CAP_STATUS_SHUTDOWN, + + /** @brief Channel encryption pending status */ + BT_L2CAP_STATUS_ENCRYPT_PENDING, + + /* Total number of status - must be at the end of the enum */ + BT_L2CAP_NUM_STATUS, +} __packed bt_l2cap_chan_status_t; + +/** @brief L2CAP Channel structure. */ +struct bt_l2cap_chan { + /** Channel connection reference */ + struct bt_conn *conn; + /** Channel operations reference */ + const struct bt_l2cap_chan_ops *ops; + sys_snode_t node; + bt_l2cap_chan_destroy_t destroy; + + ATOMIC_DEFINE(status, BT_L2CAP_NUM_STATUS); +}; + +/** @brief LE L2CAP Endpoint structure. */ +struct bt_l2cap_le_endpoint { + /** Endpoint Channel Identifier (CID) */ + uint16_t cid; + /** Endpoint Maximum Transmission Unit */ + uint16_t mtu; + /** Endpoint Maximum PDU payload Size */ + uint16_t mps; + /** Endpoint credits */ + atomic_t credits; +}; + +/** @brief LE L2CAP Channel structure. */ +struct bt_l2cap_le_chan { + /** Common L2CAP channel reference object */ + struct bt_l2cap_chan chan; + /** @brief Channel Receiving Endpoint. + * + * If the application has set an alloc_buf channel callback for the + * channel to support receiving segmented L2CAP SDUs the application + * should initialize the MTU of the Receiving Endpoint. Otherwise the + * MTU of the receiving endpoint will be initialized to + * @ref BT_L2CAP_SDU_RX_MTU by the stack. + * + * This is the source of the MTU, MPS and credit values when sending + * L2CAP_LE_CREDIT_BASED_CONNECTION_REQ/RSP and + * L2CAP_CONFIGURATION_REQ. + */ + struct bt_l2cap_le_endpoint rx; + + /** Pending RX MTU on ECFC reconfigure, used internally by stack */ + uint16_t pending_rx_mtu; + + /** Channel Transmission Endpoint. + * + * This is an image of the remote's rx. + * + * The MTU and MPS is controlled by the remote by + * L2CAP_LE_CREDIT_BASED_CONNECTION_REQ/RSP or L2CAP_CONFIGURATION_REQ. + */ + struct bt_l2cap_le_endpoint tx; + /** Channel Transmission queue + * + * Internal + * + * SDUs/PDUs given to @ref bt_l2cap_chan_send and @c bt_l2cap_send_pdu + * are stored here until they are sent to the Controller. + * + * The SDU header is prepended to SDUs before they are stored here. The + * head of this list (the next data to be sent) may be just the + * remaining part of an already partially transmitted SDU/PDU due to + * L2CAP segmentation and fragmentation. + * + * This is the outbox for a single channel. Channels may be serviced in + * any order. The transmission order does not follow the sequence of + * @ref bt_l2cap_chan_send calls across channels. + * + * There may be more data here than the channel currently has credits + * for. The transmission will wait until credits are available. + * + * Callbacks given to @ref bt_l2cap_chan_send are stored in the + * user_data of the buffer. These callbacks must be invoked when the + * Controller gives a Number of Buffers Complete Event for the last + * L2CAP PDU of the buffer or when the channel is disconnected. + */ + struct k_fifo tx_queue; + /** Segment SDU packet from upper layer */ + struct net_buf *_sdu; + uint16_t _sdu_len; + uint16_t _sdu_len_done; + + struct k_work rx_work; + struct k_fifo rx_queue; + + bt_l2cap_chan_state_t state; + /** Remote PSM to be connected */ + uint16_t psm; + /** Helps match request context during CoC */ + uint8_t ident; + bt_security_t required_sec_level; + + /* Response Timeout eXpired (RTX) timer */ + struct k_work_delayable rtx_work; + struct k_work_sync rtx_sync; + + /** @internal To be used with @ref bt_conn.upper_data_ready */ + sys_snode_t _pdu_ready; + /** @internal Holds the length of the current PDU/segment */ + size_t _pdu_remaining; +}; + +/** + * @brief Helper macro getting container object of type bt_l2cap_le_chan + * address having the same container chan member address as object in question. + * + * @param _ch Address of object of bt_l2cap_chan type + * + * @return Address of in memory bt_l2cap_le_chan object type containing + * the address of in question object. + */ +#define BT_L2CAP_LE_CHAN(_ch) CONTAINER_OF(_ch, struct bt_l2cap_le_chan, chan) + +/** @brief L2CAP Channel operations structure. + * + * The object has to stay valid and constant for the lifetime of the channel. + */ +struct bt_l2cap_chan_ops { + /** @brief Channel connected callback + * + * If this callback is provided it will be called whenever the + * connection completes. + * + * @param chan The channel that has been connected + */ + void (*connected)(struct bt_l2cap_chan *chan); + + /** @brief Channel disconnected callback + * + * If this callback is provided it will be called whenever the + * channel is disconnected, including when a connection gets + * rejected. + * + * @param chan The channel that has been Disconnected + */ + void (*disconnected)(struct bt_l2cap_chan *chan); + + /** @brief Channel encrypt_change callback + * + * If this callback is provided it will be called whenever the + * security level changed (indirectly link encryption done) or + * authentication procedure fails. In both cases security initiator + * and responder got the final status (HCI status) passed by + * related to encryption and authentication events from local host's + * controller. + * + * @param chan The channel which has made encryption status changed. + * @param status HCI status of performed security procedure caused + * by channel security requirements. The value is populated + * by HCI layer and set to 0 when success and to non-zero (reference to + * HCI Error Codes) when security/authentication failed. + */ + void (*encrypt_change)(struct bt_l2cap_chan *chan, uint8_t hci_status); + + /** @brief Channel alloc_seg callback + * + * If this callback is provided the channel will use it to allocate + * buffers to store segments. This avoids wasting big SDU buffers with + * potentially much smaller PDUs. If this callback is supplied, it must + * return a valid buffer. + * + * @param chan The channel requesting a buffer. + * + * @return Allocated buffer. + */ + struct net_buf *(*alloc_seg)(struct bt_l2cap_chan *chan); + + /** @brief Channel alloc_buf callback + * + * If this callback is provided the channel will use it to allocate + * buffers to store incoming data. Channels that requires segmentation + * must set this callback. + * If the application has not set a callback the L2CAP SDU MTU will be + * truncated to @ref BT_L2CAP_SDU_RX_MTU. + * + * @param chan The channel requesting a buffer. + * + * @return Allocated buffer. + */ + struct net_buf *(*alloc_buf)(struct bt_l2cap_chan *chan); + + /** @brief Channel recv callback + * + * @param chan The channel receiving data. + * @param buf Buffer containing incoming data. + * + * @note This callback is mandatory, unless + * @kconfig{CONFIG_BT_L2CAP_SEG_RECV} is enabled and seg_recv is + * supplied. + * + * If the application returns @c -EINPROGRESS, the application takes + * ownership of the reference in @p buf. (I.e. This pointer value can + * simply be given to @ref bt_l2cap_chan_recv_complete without any + * calls @ref net_buf_ref or @ref net_buf_unref.) + * + * @return 0 in case of success or negative value in case of error. + * @return -EINPROGRESS in case where user has to confirm once the data + * has been processed by calling + * @ref bt_l2cap_chan_recv_complete passing back + * the buffer received with its original user_data + * which contains the number of segments/credits + * used by the packet. + */ + int (*recv)(struct bt_l2cap_chan *chan, struct net_buf *buf); + + /** @brief Channel sent callback + * + * This callback will be called once the controller marks the SDU + * as completed. When the controller does so is implementation + * dependent. It could be after the SDU is enqueued for transmission, + * or after it is sent on air. + * + * @param chan The channel which has sent data. + */ + void (*sent)(struct bt_l2cap_chan *chan); + + /** @brief Channel status callback + * + * If this callback is provided it will be called whenever the + * channel status changes. + * + * @param chan The channel which status changed + * @param status The channel status + */ + void (*status)(struct bt_l2cap_chan *chan, atomic_t *status); + + /* @brief Channel released callback + * + * If this callback is set it is called when the stack has release all + * references to the channel object. + */ + void (*released)(struct bt_l2cap_chan *chan); + + /** @brief Channel reconfigured callback + * + * If this callback is provided it will be called whenever peer or + * local device requested reconfiguration. Application may check + * updated MTU and MPS values by inspecting chan->le endpoints. + * + * @param chan The channel which was reconfigured + */ + void (*reconfigured)(struct bt_l2cap_chan *chan); + + /** @brief Handle L2CAP segments directly + * + * This is an alternative to @ref bt_l2cap_chan_ops.recv. They cannot + * be used together. + * + * This is called immediately for each received segment. + * + * Unlike with @ref bt_l2cap_chan_ops.recv, flow control is explicit. + * Each time this handler is invoked, the remote has permanently used + * up one credit. Use @ref bt_l2cap_chan_give_credits to give credits. + * + * The start of an SDU is marked by `seg_offset == 0`. The end of an + * SDU is marked by `seg_offset + seg->len == sdu_len`. + * + * The stack guarantees that: + * - The sender had the credit. + * - The SDU length does not exceed MTU. + * - The segment length does not exceed MPS. + * + * Additionally, the L2CAP protocol is such that: + * - Segments come in order. + * - SDUs cannot be interleaved or aborted halfway. + * + * @note With this alternative API, the application is responsible for + * setting the RX MTU and MPS. The MPS must not exceed @ref BT_L2CAP_RX_MTU. + * + * @param chan The receiving channel. + * @param sdu_len Byte length of the SDU this segment is part of. + * @param seg_offset The byte offset of this segment in the SDU. + * @param seg The segment payload. + */ + void (*seg_recv)(struct bt_l2cap_chan *chan, size_t sdu_len, + off_t seg_offset, struct net_buf_simple *seg); +}; + +/** + * @brief Headroom needed for outgoing L2CAP PDUs. + */ +#define BT_L2CAP_CHAN_SEND_RESERVE (BT_L2CAP_BUF_SIZE(0)) + +/** + * @brief Headroom needed for outgoing L2CAP SDUs. + */ +#define BT_L2CAP_SDU_CHAN_SEND_RESERVE (BT_L2CAP_SDU_BUF_SIZE(0)) + +/** @brief L2CAP Server structure. */ +struct bt_l2cap_server { + /** @brief Server PSM. + * + * For LE, possible values: + * 0 A dynamic value will be auto-allocated when + * bt_l2cap_server_register() is called. + * + * 0x0001-0x007f Standard, Bluetooth SIG-assigned fixed values. + * + * 0x0080-0x00ff Dynamically allocated. May be pre-set by the + * application before server registration (not + * recommended however), or auto-allocated by the + * stack if the app gave 0 as the value. + * + * For BR, possible values: + * + * The PSM field is at least two octets in length. All PSM values shall have the least + * significant bit of the most significant octet equal to 0 and the least significant bit + * of all other octets equal to 1. + * + * 0 A dynamic value will be auto-allocated when + * bt_l2cap_br_server_register() is called. + * + * 0x0001-0x0eff Standard, Bluetooth SIG-assigned fixed values. + * + * > 0x1000 Dynamically allocated. May be pre-set by the + * application before server registration (not + * recommended however), or auto-allocated by the + * stack if the app gave 0 as the value. + */ + uint16_t psm; + + /** Required minimum security level */ + bt_security_t sec_level; + + /** @brief Server accept callback + * + * This callback is called whenever a new incoming connection requires + * authorization. + * + * @warning It is the responsibility of this callback to zero out the + * parent of the chan object. + * + * @param conn The connection that is requesting authorization + * @param server Pointer to the server structure this callback relates to + * @param chan Pointer to received the allocated channel + * + * @return 0 in case of success or negative value in case of error. + * @return -ENOMEM if no available space for new channel. + * @return -EACCES if application did not authorize the connection. + * @return -EPERM if encryption key size is too short. + */ + int (*accept)(struct bt_conn *conn, struct bt_l2cap_server *server, + struct bt_l2cap_chan **chan); + + sys_snode_t node; +}; + +/** @brief Register L2CAP server. + * + * Register L2CAP server for a PSM, each new connection is authorized using + * the accept() callback which in case of success shall allocate the channel + * structure to be used by the new connection. + * + * For fixed, SIG-assigned PSMs (in the range 0x0001-0x007f) the PSM should + * be assigned to server->psm before calling this API. For dynamic PSMs + * (in the range 0x0080-0x00ff) server->psm may be pre-set to a given value + * (this is however not recommended) or be left as 0, in which case upon + * return a newly allocated value will have been assigned to it. For + * dynamically allocated values the expectation is that it's exposed through + * a GATT service, and that's how L2CAP clients discover how to connect to + * the server. + * + * @param server Server structure. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_l2cap_server_register(struct bt_l2cap_server *server); + +/** @brief Connect L2CAP channel + * + * Connect L2CAP channel by PSM, once the connection is completed channel + * connected() callback will be called. If the connection is rejected + * disconnected() callback is called instead. + * Channel object passed (over an address of it) as second parameter shouldn't + * be instantiated in application as standalone. Instead of, application should + * create transport dedicated L2CAP objects, i.e. type of bt_l2cap_le_chan for + * LE and/or type of bt_l2cap_br_chan for BR/EDR. Then pass to this API + * the location (address) of bt_l2cap_chan type object which is a member + * of both transport dedicated objects. + * + * @warning It is the responsibility of the caller to zero out the + * parent of the chan object. + * + * @param conn Connection object. + * @param chan Channel object. + * @param psm Channel PSM to connect to. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_l2cap_chan_connect(struct bt_conn *conn, struct bt_l2cap_chan *chan, + uint16_t psm); + +/** @brief Disconnect L2CAP channel + * + * Disconnect L2CAP channel, if the connection is pending it will be + * canceled and as a result the channel disconnected() callback is called. + * Regarding to input parameter, to get details see reference description + * to bt_l2cap_chan_connect() API above. + * + * @param chan Channel object. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_l2cap_chan_disconnect(struct bt_l2cap_chan *chan); + +/** @brief Send data to L2CAP channel + * + * Send data from buffer to the channel. For dynamic channels; if credits are + * not available, buf will be queued and sent as and when credits are received + * from peer. + * + * Network buffer fragments (ie `buf->frags`) are not supported. + * + * When sending L2CAP data over an BR/EDR connection or a fixed L2CAP channel, + * the application is sending L2CAP PDUs. The application is required to have + * reserved @ref BT_L2CAP_CHAN_SEND_RESERVE bytes in the buffer before sending. + * The application should use the BT_L2CAP_BUF_SIZE() helper to correctly size + * the buffers for the for the outgoing buffer pool. + * + * When sending L2CAP data over a dynamic L2CAP channel, the application is + * sending L2CAP SDUs. The application shall reserve + * @ref BT_L2CAP_SDU_CHAN_SEND_RESERVE bytes in the buffer before sending. + * The application can use the BT_L2CAP_SDU_BUF_SIZE() helper to correctly size + * the buffer to account for the reserved headroom. + * + * When segmenting an L2CAP SDU into L2CAP PDUs the stack will first attempt to + * allocate buffers from the channel's `alloc_seg` callback and will fallback + * on the stack's global buffer pool (sized + * @kconfig{CONFIG_BT_L2CAP_TX_BUF_COUNT}). + * + * @warning The buffer's user_data _will_ be overwritten by this function. Do + * not store anything in it. As soon as a call to this function has been made, + * consider ownership of user_data transferred into the stack. + * + * @note Buffer ownership is transferred to the stack in case of success, in + * case of an error the caller retains the ownership of the buffer. + * + * @param chan The channel to send the data to. See @ref bt_l2cap_chan_connect + * for more details. + * @param buf Buffer containing the data. + * + * @return 0 in case of success or negative value in case of error. + * @return -EINVAL if `buf` or `chan` is NULL. + * @return -EINVAL if `chan` is not either BR/EDR or LE based. + * @return -EINVAL if buffer doesn't have enough bytes reserved to fit header. + * @return -EINVAL if buffer's reference counter != 1 + * @return -EMSGSIZE if `buf` is larger than `chan`'s MTU. + * @return -ENOTCONN if underlying conn is disconnected. + * @return -ESHUTDOWN if L2CAP channel is disconnected. + * @return -other (from lower layers) if chan is BR/EDR. + */ +int bt_l2cap_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf); + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_L2CAP_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/services/ots.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/services/ots.h new file mode 100644 index 0000000000..ef887f2619 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/services/ots.h @@ -0,0 +1,1171 @@ +/* + * SPDX-FileCopyrightText: 2020-2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_SERVICES_OTS_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_SERVICES_OTS_H_ + +/** + * @brief Object Transfer Service (OTS) + * @defgroup bt_ots Object Transfer Service (OTS) + * @ingroup bluetooth + * @{ + * + * [Experimental] Users should note that the APIs can change + * as a part of ongoing development. + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief Size of OTS object ID (in bytes). */ +#define BT_OTS_OBJ_ID_SIZE 6 + +/** @brief Minimum allowed value for object ID (except ID for directory listing) */ +#define BT_OTS_OBJ_ID_MIN 0x000000000100ULL + +/** @brief Maximum allowed value for object ID (except ID for directory listing) */ +#define BT_OTS_OBJ_ID_MAX 0xFFFFFFFFFFFFULL + +/** @brief ID of the Directory Listing Object */ +#define OTS_OBJ_ID_DIR_LIST 0x000000000000ULL + +/** @brief Mask for OTS object IDs, preserving the 48 bits */ +#define BT_OTS_OBJ_ID_MASK BIT64_MASK(48) + +/** @brief Length of OTS object ID string (in bytes). */ +#define BT_OTS_OBJ_ID_STR_LEN 15 + +/** @brief Type of an OTS object. */ +struct bt_ots_obj_type { + union { + /* Used to indicate UUID type */ + struct bt_uuid uuid; + + /* 16-bit UUID value */ + struct bt_uuid_16 uuid_16; + + /* 128-bit UUID value */ + struct bt_uuid_128 uuid_128; + }; +}; + +/** @brief Properties of an OTS object. */ +enum { + /** Bit 0 Deletion of this object is permitted */ + BT_OTS_OBJ_PROP_DELETE = 0, + + /** Bit 1 Execution of this object is permitted */ + BT_OTS_OBJ_PROP_EXECUTE = 1, + + /** Bit 2 Reading this object is permitted */ + BT_OTS_OBJ_PROP_READ = 2, + + /** Bit 3 Writing data to this object is permitted */ + BT_OTS_OBJ_PROP_WRITE = 3, + + /** @brief Bit 4 Appending data to this object is permitted. + * + * Appending data increases its Allocated Size. + */ + BT_OTS_OBJ_PROP_APPEND = 4, + + /** Bit 5 Truncation of this object is permitted */ + BT_OTS_OBJ_PROP_TRUNCATE = 5, + + /** @brief Bit 6 Patching this object is permitted + * + * Patching this object overwrites some of + * the object's existing contents. + */ + BT_OTS_OBJ_PROP_PATCH = 6, + + /** Bit 7 This object is a marked object */ + BT_OTS_OBJ_PROP_MARKED = 7, +}; + +/** @brief Set @ref BT_OTS_OBJ_PROP_DELETE property. + * + * @param prop Object properties. + */ +#define BT_OTS_OBJ_SET_PROP_DELETE(prop) \ + WRITE_BIT(prop, BT_OTS_OBJ_PROP_DELETE, 1) + +/** @brief Set @ref BT_OTS_OBJ_PROP_EXECUTE property. + * + * @param prop Object properties. + */ +#define BT_OTS_OBJ_SET_PROP_EXECUTE(prop) \ + WRITE_BIT(prop, BT_OTS_OBJ_PROP_EXECUTE, 1) + +/** @brief Set @ref BT_OTS_OBJ_PROP_READ property. + * + * @param prop Object properties. + */ +#define BT_OTS_OBJ_SET_PROP_READ(prop) \ + WRITE_BIT(prop, BT_OTS_OBJ_PROP_READ, 1) + +/** @brief Set @ref BT_OTS_OBJ_PROP_WRITE property. + * + * @param prop Object properties. + */ +#define BT_OTS_OBJ_SET_PROP_WRITE(prop) \ + WRITE_BIT(prop, BT_OTS_OBJ_PROP_WRITE, 1) + +/** @brief Set @ref BT_OTS_OBJ_PROP_APPEND property. + * + * @param prop Object properties. + */ +#define BT_OTS_OBJ_SET_PROP_APPEND(prop) \ + WRITE_BIT(prop, BT_OTS_OBJ_PROP_APPEND, 1) + +/** @brief Set @ref BT_OTS_OBJ_PROP_TRUNCATE property. + * + * @param prop Object properties. + */ +#define BT_OTS_OBJ_SET_PROP_TRUNCATE(prop) \ + WRITE_BIT(prop, BT_OTS_OBJ_PROP_TRUNCATE, 1) + +/** @brief Set @ref BT_OTS_OBJ_PROP_PATCH property. + * + * @param prop Object properties. + */ +#define BT_OTS_OBJ_SET_PROP_PATCH(prop) \ + WRITE_BIT(prop, BT_OTS_OBJ_PROP_PATCH, 1) + +/** @brief Set @ref BT_OTS_OBJ_SET_PROP_MARKED property. + * + * @param prop Object properties. + */ +#define BT_OTS_OBJ_SET_PROP_MARKED(prop) \ + WRITE_BIT(prop, BT_OTS_OBJ_PROP_MARKED, 1) + +/** @brief Get @ref BT_OTS_OBJ_PROP_DELETE property. + * + * @param prop Object properties. + */ +#define BT_OTS_OBJ_GET_PROP_DELETE(prop) \ + ((prop) & BIT(BT_OTS_OBJ_PROP_DELETE)) + +/** @brief Get @ref BT_OTS_OBJ_PROP_EXECUTE property. + * + * @param prop Object properties. + */ +#define BT_OTS_OBJ_GET_PROP_EXECUTE(prop) \ + ((prop) & BIT(BT_OTS_OBJ_PROP_EXECUTE)) + +/** @brief Get @ref BT_OTS_OBJ_PROP_READ property. + * + * @param prop Object properties. + */ +#define BT_OTS_OBJ_GET_PROP_READ(prop) \ + ((prop) & BIT(BT_OTS_OBJ_PROP_READ)) + +/** @brief Get @ref BT_OTS_OBJ_PROP_WRITE property. + * + * @param prop Object properties. + */ +#define BT_OTS_OBJ_GET_PROP_WRITE(prop) \ + ((prop) & BIT(BT_OTS_OBJ_PROP_WRITE)) + +/** @brief Get @ref BT_OTS_OBJ_PROP_APPEND property. + * + * @param prop Object properties. + */ +#define BT_OTS_OBJ_GET_PROP_APPEND(prop) \ + ((prop) & BIT(BT_OTS_OBJ_PROP_APPEND)) + +/** @brief Get @ref BT_OTS_OBJ_PROP_TRUNCATE property. + * + * @param prop Object properties. + */ +#define BT_OTS_OBJ_GET_PROP_TRUNCATE(prop) \ + ((prop) & BIT(BT_OTS_OBJ_PROP_TRUNCATE)) + +/** @brief Get @ref BT_OTS_OBJ_PROP_PATCH property. + * + * @param prop Object properties. + */ +#define BT_OTS_OBJ_GET_PROP_PATCH(prop) \ + ((prop) & BIT(BT_OTS_OBJ_PROP_PATCH)) + +/** @brief Get @ref BT_OTS_OBJ_PROP_MARKED property. + * + * @param prop Object properties. + */ +#define BT_OTS_OBJ_GET_PROP_MARKED(prop) \ + ((prop) & BIT(BT_OTS_OBJ_PROP_MARKED)) + +/** @brief Descriptor for OTS Object Size parameter. */ +struct bt_ots_obj_size { + /** @brief Current Size */ + uint32_t cur; + + /** @brief Allocated Size */ + uint32_t alloc; +} __packed; + +/** @brief Object Action Control Point Feature bits. */ +enum { + /** Bit 0 OACP Create Op Code Supported */ + BT_OTS_OACP_FEAT_CREATE = 0, + + /** Bit 1 OACP Delete Op Code Supported */ + BT_OTS_OACP_FEAT_DELETE = 1, + + /** Bit 2 OACP Calculate Checksum Op Code Supported */ + BT_OTS_OACP_FEAT_CHECKSUM = 2, + + /** Bit 3 OACP Execute Op Code Supported */ + BT_OTS_OACP_FEAT_EXECUTE = 3, + + /** Bit 4 OACP Read Op Code Supported */ + BT_OTS_OACP_FEAT_READ = 4, + + /** Bit 5 OACP Write Op Code Supported */ + BT_OTS_OACP_FEAT_WRITE = 5, + + /** Bit 6 Appending Additional Data to Objects Supported */ + BT_OTS_OACP_FEAT_APPEND = 6, + + /** Bit 7 Truncation of Objects Supported */ + BT_OTS_OACP_FEAT_TRUNCATE = 7, + + /** Bit 8 Patching of Objects Supported */ + BT_OTS_OACP_FEAT_PATCH = 8, + + /** Bit 9 OACP Abort Op Code Supported */ + BT_OTS_OACP_FEAT_ABORT = 9, +}; + +/* + * @enum bt_ots_oacp_write_op_mode + * @brief Mode Parameter for OACP Write Op Code. + */ +enum bt_ots_oacp_write_op_mode { + BT_OTS_OACP_WRITE_OP_MODE_NONE = 0, + BT_OTS_OACP_WRITE_OP_MODE_TRUNCATE = BIT(1), +}; + +/** @brief Set @ref BT_OTS_OACP_SET_FEAT_CREATE feature. + * + * @param feat OTS features. + */ +#define BT_OTS_OACP_SET_FEAT_CREATE(feat) \ + WRITE_BIT(feat, BT_OTS_OACP_FEAT_CREATE, 1) + +/** @brief Set @ref BT_OTS_OACP_FEAT_DELETE feature. + * + * @param feat OTS features. + */ +#define BT_OTS_OACP_SET_FEAT_DELETE(feat) \ + WRITE_BIT(feat, BT_OTS_OACP_FEAT_DELETE, 1) + +/** @brief Set @ref BT_OTS_OACP_FEAT_CHECKSUM feature. + * + * @param feat OTS features. + */ +#define BT_OTS_OACP_SET_FEAT_CHECKSUM(feat) \ + WRITE_BIT(feat, BT_OTS_OACP_FEAT_CHECKSUM, 1) + +/** @brief Set @ref BT_OTS_OACP_FEAT_EXECUTE feature. + * + * @param feat OTS features. + */ +#define BT_OTS_OACP_SET_FEAT_EXECUTE(feat) \ + WRITE_BIT(feat, BT_OTS_OACP_FEAT_EXECUTE, 1) + +/** @brief Set @ref BT_OTS_OACP_FEAT_READ feature. + * + * @param feat OTS features. + */ +#define BT_OTS_OACP_SET_FEAT_READ(feat) \ + WRITE_BIT(feat, BT_OTS_OACP_FEAT_READ, 1) + +/** @brief Set @ref BT_OTS_OACP_FEAT_WRITE feature. + * + * @param feat OTS features. + */ +#define BT_OTS_OACP_SET_FEAT_WRITE(feat) \ + WRITE_BIT(feat, BT_OTS_OACP_FEAT_WRITE, 1) + +/** @brief Set @ref BT_OTS_OACP_FEAT_APPEND feature. + * + * @param feat OTS features. + */ +#define BT_OTS_OACP_SET_FEAT_APPEND(feat) \ + WRITE_BIT(feat, BT_OTS_OACP_FEAT_APPEND, 1) + +/** @brief Set @ref BT_OTS_OACP_FEAT_TRUNCATE feature. + * + * @param feat OTS features. + */ +#define BT_OTS_OACP_SET_FEAT_TRUNCATE(feat) \ + WRITE_BIT(feat, BT_OTS_OACP_FEAT_TRUNCATE, 1) + +/** @brief Set @ref BT_OTS_OACP_FEAT_PATCH feature. + * + * @param feat OTS features. + */ +#define BT_OTS_OACP_SET_FEAT_PATCH(feat) \ + WRITE_BIT(feat, BT_OTS_OACP_FEAT_PATCH, 1) + +/** @brief Set @ref BT_OTS_OACP_FEAT_ABORT feature. + * + * @param feat OTS features. + */ +#define BT_OTS_OACP_SET_FEAT_ABORT(feat) \ + WRITE_BIT(feat, BT_OTS_OACP_FEAT_ABORT, 1) + +/** @brief Get @ref BT_OTS_OACP_FEAT_CREATE feature. + * + * @param feat OTS features. + */ +#define BT_OTS_OACP_GET_FEAT_CREATE(feat) \ + ((feat) & BIT(BT_OTS_OACP_FEAT_CREATE)) + +/** @brief Get @ref BT_OTS_OACP_FEAT_DELETE feature. + * + * @param feat OTS features. + */ +#define BT_OTS_OACP_GET_FEAT_DELETE(feat) \ + ((feat) & BIT(BT_OTS_OACP_FEAT_DELETE)) + +/** @brief Get @ref BT_OTS_OACP_FEAT_CHECKSUM feature. + * + * @param feat OTS features. + */ +#define BT_OTS_OACP_GET_FEAT_CHECKSUM(feat) \ + ((feat) & BIT(BT_OTS_OACP_FEAT_CHECKSUM)) + +/** @brief Get @ref BT_OTS_OACP_FEAT_EXECUTE feature. + * + * @param feat OTS features. + */ +#define BT_OTS_OACP_GET_FEAT_EXECUTE(feat) \ + ((feat) & BIT(BT_OTS_OACP_FEAT_EXECUTE)) + +/** @brief Get @ref BT_OTS_OACP_FEAT_READ feature. + * + * @param feat OTS features. + */ +#define BT_OTS_OACP_GET_FEAT_READ(feat) \ + ((feat) & BIT(BT_OTS_OACP_FEAT_READ)) + +/** @brief Get @ref BT_OTS_OACP_FEAT_WRITE feature. + * + * @param feat OTS features. + */ +#define BT_OTS_OACP_GET_FEAT_WRITE(feat) \ + ((feat) & BIT(BT_OTS_OACP_FEAT_WRITE)) + +/** @brief Get @ref BT_OTS_OACP_FEAT_APPEND feature. + * + * @param feat OTS features. + */ +#define BT_OTS_OACP_GET_FEAT_APPEND(feat) \ + ((feat) & BIT(BT_OTS_OACP_FEAT_APPEND)) + +/** @brief Get @ref BT_OTS_OACP_FEAT_TRUNCATE feature. + * + * @param feat OTS features. + */ +#define BT_OTS_OACP_GET_FEAT_TRUNCATE(feat) \ + ((feat) & BIT(BT_OTS_OACP_FEAT_TRUNCATE)) + +/** @brief Get @ref BT_OTS_OACP_FEAT_PATCH feature. + * + * @param feat OTS features. + */ +#define BT_OTS_OACP_GET_FEAT_PATCH(feat) \ + ((feat) & BIT(BT_OTS_OACP_FEAT_PATCH)) + +/** @brief Get @ref BT_OTS_OACP_FEAT_ABORT feature. + * + * @param feat OTS features. + */ +#define BT_OTS_OACP_GET_FEAT_ABORT(feat) \ + ((feat) & BIT(BT_OTS_OACP_FEAT_ABORT)) + +/** @brief Object List Control Point Feature bits. */ +enum { + /** Bit 0 OLCP Go To Op Code Supported */ + BT_OTS_OLCP_FEAT_GO_TO = 0, + + /** Bit 1 OLCP Order Op Code Supported */ + BT_OTS_OLCP_FEAT_ORDER = 1, + + /** Bit 2 OLCP Request Number of Objects Op Code Supported */ + BT_OTS_OLCP_FEAT_NUM_REQ = 2, + + /** Bit 3 OLCP Clear Marking Op Code Supported*/ + BT_OTS_OLCP_FEAT_CLEAR = 3, +}; + +/** @brief Set @ref BT_OTS_OLCP_FEAT_GO_TO feature. + * + * @param feat OTS features. + */ +#define BT_OTS_OLCP_SET_FEAT_GO_TO(feat) \ + WRITE_BIT(feat, BT_OTS_OLCP_FEAT_GO_TO, 1) + +/** @brief Set @ref BT_OTS_OLCP_FEAT_ORDER feature. + * + * @param feat OTS features. + */ +#define BT_OTS_OLCP_SET_FEAT_ORDER(feat) \ + WRITE_BIT(feat, BT_OTS_OLCP_FEAT_ORDER, 1) + +/** @brief Set @ref BT_OTS_OLCP_FEAT_NUM_REQ feature. + * + * @param feat OTS features. + */ +#define BT_OTS_OLCP_SET_FEAT_NUM_REQ(feat) \ + WRITE_BIT(feat, BT_OTS_OLCP_FEAT_NUM_REQ, 1) + +/** @brief Set @ref BT_OTS_OLCP_FEAT_CLEAR feature. + * + * @param feat OTS features. + */ +#define BT_OTS_OLCP_SET_FEAT_CLEAR(feat) \ + WRITE_BIT(feat, BT_OTS_OLCP_FEAT_CLEAR, 1) + +/** @brief Get @ref BT_OTS_OLCP_GET_FEAT_GO_TO feature. + * + * @param feat OTS features. + */ +#define BT_OTS_OLCP_GET_FEAT_GO_TO(feat) \ + ((feat) & BIT(BT_OTS_OLCP_FEAT_GO_TO)) + +/** @brief Get @ref BT_OTS_OLCP_GET_FEAT_ORDER feature. + * + * @param feat OTS features. + */ +#define BT_OTS_OLCP_GET_FEAT_ORDER(feat) \ + ((feat) & BIT(BT_OTS_OLCP_FEAT_ORDER)) + +/** @brief Get @ref BT_OTS_OLCP_GET_FEAT_NUM_REQ feature. + * + * @param feat OTS features. + */ +#define BT_OTS_OLCP_GET_FEAT_NUM_REQ(feat) \ + ((feat) & BIT(BT_OTS_OLCP_FEAT_NUM_REQ)) + +/** @brief Get @ref BT_OTS_OLCP_GET_FEAT_CLEAR feature. + * + * @param feat OTS features. + */ +#define BT_OTS_OLCP_GET_FEAT_CLEAR(feat) \ + ((feat) & BIT(BT_OTS_OLCP_FEAT_CLEAR)) + +/**@brief Features of the OTS. */ +struct bt_ots_feat { + /* OACP Features */ + uint32_t oacp; + + /* OLCP Features */ + uint32_t olcp; +} __packed; + +/** @brief Object metadata request bit field values */ +enum { + /** @brief Request object name */ + BT_OTS_METADATA_REQ_NAME = BIT(0), + /** @brief Request object type */ + BT_OTS_METADATA_REQ_TYPE = BIT(1), + /** @brief Request object size */ + BT_OTS_METADATA_REQ_SIZE = BIT(2), + /** @brief Request object first created time */ + BT_OTS_METADATA_REQ_CREATED = BIT(3), + /** @brief Request object last modified time */ + BT_OTS_METADATA_REQ_MODIFIED = BIT(4), + /** @brief Request object ID */ + BT_OTS_METADATA_REQ_ID = BIT(5), + /** @brief Request object properties */ + BT_OTS_METADATA_REQ_PROPS = BIT(6), + /** @brief Request all object metadata */ + BT_OTS_METADATA_REQ_ALL = 0x7F, +}; + +/** @brief Date and Time structure */ +struct bt_ots_date_time { + uint16_t year; + uint8_t month; + uint8_t day; + uint8_t hours; + uint8_t minutes; + uint8_t seconds; +}; +#define BT_OTS_DATE_TIME_FIELD_SIZE 7 + +#ifndef CONFIG_BT_OTS_OBJ_MAX_NAME_LEN +#define CONFIG_BT_OTS_OBJ_MAX_NAME_LEN 120 +#endif /* CONFIG_BT_OTS_OBJ_MAX_NAME_LEN */ + +/** @brief Metadata of an OTS object + * + * Used by the server as a descriptor for OTS object initialization. + * Used by the client to present object metadata to the application. + */ +struct bt_ots_obj_metadata { + + /** @brief Object Name */ + char *name; + + /* TODO: Unify client/server name */ + /** @brief Object name (client) */ + char name_c[CONFIG_BT_OTS_OBJ_MAX_NAME_LEN + 1]; + + /** @brief Object Type */ + struct bt_ots_obj_type type; + + /** @brief Object Size */ + struct bt_ots_obj_size size; + + /** @brief Object first created time */ + struct bt_ots_date_time first_created; + + /** @brief Object last modified time */ + struct bt_ots_date_time modified; + + /** @brief Object ID */ + uint64_t id; + + /** @brief Object Properties */ + uint32_t props; +}; + +/** @brief Opaque OTS instance. */ +struct bt_ots; + +/** @brief Descriptor for OTS object addition */ +struct bt_ots_obj_add_param { + /** @brief Object size to allocate */ + uint32_t size; + + /** @brief Object type */ + struct bt_ots_obj_type type; +}; + +/** @brief Descriptor for OTS created object. + * + * Descriptor for OTS object created by the application. This descriptor is + * returned by @ref bt_ots_cb.obj_created callback which contains further + * documentation on distinguishing between server and client object creation. + */ +struct bt_ots_obj_created_desc { + /** @brief Object name + * + * The object name as a NULL terminated string. + * + * When the server creates a new object the name + * shall be > 0 and <= BT_OTS_OBJ_MAX_NAME_LEN + * When the client creates a new object the name + * shall be an empty string + */ + char *name; + + /** @brief Object size + * + * @ref bt_ots_obj_size.alloc shall be >= @ref bt_ots_obj_add_param.size + * + * When the server creates a new object @ref bt_ots_obj_size.cur + * shall be <= @ref bt_ots_obj_add_param.size + * When the client creates a new object @ref bt_ots_obj_size.cur + * shall be 0 + */ + struct bt_ots_obj_size size; + + /** @brief Object properties */ + uint32_t props; +}; + +/** @brief OTS callback structure. */ +struct bt_ots_cb { + /** @brief Object created callback + * + * This callback is called whenever a new object is created. + * Application can reject this request by returning an error + * when it does not have necessary resources to hold this new + * object. This callback is also triggered when the server + * creates a new object with bt_ots_obj_add() API. + * + * @param ots OTS instance. + * @param conn The connection that is requesting object creation or + * NULL if object is created by bt_ots_obj_add(). + * @param id Object ID. + * @param add_param Object creation requested parameters. + * @param created_desc Created object descriptor that shall be filled by the + * receiver of this callback. + * + * @return 0 in case of success or negative value in case of error. + * @return -ENOTSUP if object type is not supported + * @return -ENOMEM if no available space for new object. + * @return -EINVAL if an invalid parameter is provided + * @return other negative values are treated as a generic operation failure + */ + int (*obj_created)(struct bt_ots *ots, struct bt_conn *conn, uint64_t id, + const struct bt_ots_obj_add_param *add_param, + struct bt_ots_obj_created_desc *created_desc); + + /** @brief Object deleted callback + * + * This callback is called whenever an object is deleted. It is + * also triggered when the server deletes an object with + * bt_ots_obj_delete() API. + * + * @param ots OTS instance. + * @param conn The connection that deleted the object or NULL if + * this request came from the server. + * @param id Object ID. + * + * @retval When an error is indicated by using a negative value, the + * object delete procedure is aborted and a corresponding failed + * status is returned to the client. + * @return 0 in case of success. + * @return -EBUSY if the object is locked. This is generally not expected + * to be returned by the application as the OTS layer tracks object + * accesses. An object locked status is returned to the client. + * @return Other negative values in case of error. A generic operation + * failed status is returned to the client. + */ + int (*obj_deleted)(struct bt_ots *ots, struct bt_conn *conn, + uint64_t id); + + /** @brief Object selected callback + * + * This callback is called on successful object selection. + * + * @param ots OTS instance. + * @param conn The connection that selected new object. + * @param id Object ID. + */ + void (*obj_selected)(struct bt_ots *ots, struct bt_conn *conn, + uint64_t id); + + /** @brief Object read callback + * + * This callback is called multiple times during the Object read + * operation. OTS module will keep requesting successive Object + * fragments from the application until the read operation is + * completed. The end of read operation is indicated by NULL data + * parameter. + * + * @param ots OTS instance. + * @param conn The connection that read object. + * @param id Object ID. + * @param data In: NULL once the read operations is completed. + * Out: Next chunk of data to be sent. + * @param len Remaining length requested by the client. + * @param offset Object data offset. + * + * @return Data length to be sent via data parameter. This value + * shall be smaller or equal to the len parameter. + * @return Negative value in case of an error. + */ + ssize_t (*obj_read)(struct bt_ots *ots, struct bt_conn *conn, + uint64_t id, void **data, size_t len, + off_t offset); + + /** @brief Object write callback + * + * This callback is called multiple times during the Object write + * operation. OTS module will keep providing successive Object + * fragments to the application until the write operation is + * completed. The offset and length of each write fragment is + * validated by the OTS module to be within the allocated size + * of the object. The remaining length indicates data length + * remaining to be written and will decrease each write iteration + * until it reaches 0 in the last write fragment. + * + * @param ots OTS instance. + * @param conn The connection that wrote object. + * @param id Object ID. + * @param data Next chunk of data to be written. + * @param len Length of the current chunk of data in the buffer. + * @param offset Object data offset. + * @param rem Remaining length in the write operation. + * + * @return Number of bytes written in case of success, if the number + * of bytes written does not match len, -EIO is returned to + * the L2CAP layer. + * @return A negative value in case of an error. + * @return -EINPROGRESS has a special meaning and is unsupported at + * the moment. It should not be returned. + */ + ssize_t (*obj_write)(struct bt_ots *ots, struct bt_conn *conn, uint64_t id, + const void *data, size_t len, off_t offset, + size_t rem); + + /** @brief Object name written callback + * + * This callback is called when the object name is written. + * This is a notification to the application that the object name + * will be updated by the OTS service implementation. + * + * @param ots OTS instance. + * @param conn The connection that wrote object name. + * @param id Object ID. + * @param cur_name Current object name. + * @param new_name New object name. + */ + void (*obj_name_written)(struct bt_ots *ots, struct bt_conn *conn, + uint64_t id, const char *cur_name, const char *new_name); + + /** @brief Object Calculate checksum callback + * + * This callback is called when the OACP Calculate Checksum procedure is performed. + * Because object data is opaque to OTS, the application is the only one who + * knows where data is and should return pointer of actual object data. + * + * @param[in] ots OTS instance. + * @param[in] conn The connection that wrote object. + * @param[in] id Object ID. + * @param[in] offset The first octet of the object contents need to be calculated. + * @param[in] len The length number of octets object name. + * @param[out] data Pointer of actual object data. + * + * @return 0 to accept, or any negative value to reject. + */ + int (*obj_cal_checksum)(struct bt_ots *ots, struct bt_conn *conn, uint64_t id, + off_t offset, size_t len, void **data); +}; + +/** @brief Descriptor for OTS initialization. */ +struct bt_ots_init_param { + /* OTS features */ + struct bt_ots_feat features; + + /* Callbacks */ + struct bt_ots_cb *cb; +}; + +/** @brief Add an object to the OTS instance. + * + * This function adds an object to the OTS database. When the + * object is being added, a callback obj_created() is called + * to notify the user about a new object ID. + * + * @param ots OTS instance. + * @param param Object addition parameters. + * + * @return ID of created object in case of success. + * @return negative value in case of error. + */ +int bt_ots_obj_add(struct bt_ots *ots, const struct bt_ots_obj_add_param *param); + +/** @brief Delete an object from the OTS instance. + * + * This function deletes an object from the OTS database. When the + * object is deleted a callback obj_deleted() is called + * to notify the user about this event. At this point, it is possible + * to free allocated buffer for object data. + * + * @param ots OTS instance. + * @param id ID of the object to be deleted (uint48). + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_ots_obj_delete(struct bt_ots *ots, uint64_t id); + +/** @brief Get the service declaration attribute. + * + * This function is enabled for CONFIG_BT_OTS_SECONDARY_SVC configuration. + * The first service attribute can be included in any other GATT service. + * + * @param ots OTS instance. + * + * @return The first OTS attribute instance. + */ +void *bt_ots_svc_decl_get(struct bt_ots *ots); + +/** @brief Initialize the OTS instance. + * + * @param ots OTS instance. + * @param ots_init OTS initialization descriptor. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_ots_init(struct bt_ots *ots, struct bt_ots_init_param *ots_init); + +/** @brief Get a free instance of OTS from the pool. + * + * @return OTS instance in case of success or NULL in case of error. + */ +struct bt_ots *bt_ots_free_instance_get(void); + +#define BT_OTS_STOP 0 +#define BT_OTS_CONTINUE 1 + +/* TODO: Merge server and client instance as opaque type */ +/** @brief OTS client instance */ +struct bt_ots_client { + uint16_t start_handle; + uint16_t end_handle; + uint16_t feature_handle; + uint16_t obj_name_handle; + uint16_t obj_type_handle; + uint16_t obj_size_handle; + uint16_t obj_properties_handle; + uint16_t obj_created_handle; + uint16_t obj_modified_handle; + uint16_t obj_id_handle; + uint16_t oacp_handle; + uint16_t olcp_handle; + + struct bt_gatt_subscribe_params oacp_sub_params; + struct bt_gatt_discover_params oacp_sub_disc_params; + struct bt_gatt_subscribe_params olcp_sub_params; + struct bt_gatt_discover_params olcp_sub_disc_params; + + struct bt_gatt_write_params write_params; + struct bt_gatt_read_params read_proc; + struct bt_ots_client_cb *cb; + + struct bt_ots_feat features; + + struct bt_ots_obj_metadata cur_object; +}; + +/** OTS client callback structure */ +struct bt_ots_client_cb { + /** @brief Callback function when a new object is selected. + * + * Called when the a new object is selected and the current + * object has changed. The `cur_object` in `ots_inst` will + * have been reset, and metadata should be read again with + * bt_ots_client_read_object_metadata(). + * + * @param ots_inst Pointer to the OTC instance. + * @param conn The connection to the peer device. + * @param err Error code (bt_ots_olcp_res_code). + */ + void (*obj_selected)(struct bt_ots_client *ots_inst, + struct bt_conn *conn, int err); + + /** @brief Callback function for the data of the selected + * object. + * + * Called when the data of the selected object are read using + * bt_ots_client_read_object_data(). + * + * @param ots_inst Pointer to the OTC instance. + * @param conn The connection to the peer device. + * @param offset Offset of the received data. + * @param len Length of the received data. + * @param data_p Pointer to the received data. + * @param is_complete Indicate if the whole object has been received. + * + * @return int BT_OTS_STOP or BT_OTS_CONTINUE. BT_OTS_STOP can + * be used to stop reading. + */ + int (*obj_data_read)(struct bt_ots_client *ots_inst, + struct bt_conn *conn, uint32_t offset, + uint32_t len, uint8_t *data_p, bool is_complete); + + /** @brief Callback function for metadata of the selected object. + * + * Called when metadata of the selected object are read using + * bt_ots_client_read_object_metadata(). + * Not all of the metadata may have been initialized. + * + * @param ots_inst Pointer to the OTC instance. + * @param conn The connection to the peer device. + * @param err Error value. 0 on success, + * GATT error or ERRNO on fail. + * @param metadata_read Bitfield of the metadata that was + * successfully read. + */ + void (*obj_metadata_read)(struct bt_ots_client *ots_inst, + struct bt_conn *conn, int err, + uint8_t metadata_read); + + /** @brief Callback function for the data of the write object. + * + * Called when the data of the selected object is written using + * bt_ots_client_write_object_data(). + * + * @param ots_inst Pointer to the OTC instance. + * @param conn The connection to the peer device. + * @param len Length of the written data. + */ + void (*obj_data_written)(struct bt_ots_client *ots_inst, + struct bt_conn *conn, size_t len); + + /** @brief Callback function when checksum indication is received. + * + * Called when the oacp_ind_handler received response of + * OP BT_GATT_OTS_OACP_PROC_CHECKSUM_CALC. + * + * @param ots_inst Pointer to the OTC instance. + * @param conn The connection to the peer device. + * @param err Error code (bt_gatt_ots_oacp_res_code). + * @param checksum Checksum if error code is BT_GATT_OTS_OACP_RES_SUCCESS, + * otherwise 0. + */ + void (*obj_checksum_calculated)(struct bt_ots_client *ots_inst, struct bt_conn *conn, + int err, uint32_t checksum); +}; + +/** @brief Register an Object Transfer Service Instance. + * + * Register an Object Transfer Service instance discovered on the peer. + * Call this function when an OTS instance is discovered + * (discovery is to be handled by the higher layer). + * + * @param[in] ots_inst Discovered OTS instance. + * + * @return int 0 if success, ERRNO on failure. + */ +int bt_ots_client_register(struct bt_ots_client *ots_inst); + +/** @brief Unregister an Object Transfer Service Instance. + * + * Unregister an Object Transfer Service instance when disconnect from the peer. + * Call this function when an ACL using OTS instance is disconnected. + * + * @param[in] index Index of OTS instance. + * + * @return int 0 if success, ERRNO on failure. + */ +int bt_ots_client_unregister(uint8_t index); + +/** @brief OTS Indicate Handler function. + * + * Set this function as callback for indicate handler when discovering OTS. + * + * @param conn Connection object. May be NULL, indicating that the + * peer is being unpaired. + * @param params Subscription parameters. + * @param data Attribute value data. If NULL then subscription was + * removed. + * @param length Attribute value length. + */ +uint8_t bt_ots_client_indicate_handler(struct bt_conn *conn, + struct bt_gatt_subscribe_params *params, + const void *data, uint16_t length); + +/** @brief Read the OTS feature characteristic. + * + * @param otc_inst Pointer to the OTC instance. + * @param conn Pointer to the connection object. + * + * @return int 0 if success, ERRNO on failure. + */ +int bt_ots_client_read_feature(struct bt_ots_client *otc_inst, + struct bt_conn *conn); + +/** @brief Select an object by its Object ID. + * + * @param otc_inst Pointer to the OTC instance. + * @param conn Pointer to the connection object. + * @param obj_id Object's ID. + * + * @return int 0 if success, ERRNO on failure. + */ +int bt_ots_client_select_id(struct bt_ots_client *otc_inst, + struct bt_conn *conn, + uint64_t obj_id); + +/** @brief Select the first object. + * + * @param otc_inst Pointer to the OTC instance. + * @param conn Pointer to the connection object. + * + * @return int 0 if success, ERRNO on failure. + */ +int bt_ots_client_select_first(struct bt_ots_client *otc_inst, + struct bt_conn *conn); + +/** @brief Select the last object. + * + * @param otc_inst Pointer to the OTC instance. + * @param conn Pointer to the connection object. + * + * @return int 0 if success, ERRNO on failure. + */ +int bt_ots_client_select_last(struct bt_ots_client *otc_inst, + struct bt_conn *conn); + +/** @brief Select the next object. + * + * @param otc_inst Pointer to the OTC instance. + * @param conn Pointer to the connection object. + * + * @return int 0 if success, ERRNO on failure. + */ +int bt_ots_client_select_next(struct bt_ots_client *otc_inst, + struct bt_conn *conn); + +/** @brief Select the previous object. + * + * @param otc_inst Pointer to the OTC instance. + * @param conn Pointer to the connection object. + * + * @return int 0 if success, ERRNO on failure. + */ +int bt_ots_client_select_prev(struct bt_ots_client *otc_inst, + struct bt_conn *conn); + +/** @brief Read the metadata of the current object. + * + * The metadata are returned in the obj_metadata_read() callback. + * + * @param otc_inst Pointer to the OTC instance. + * @param conn Pointer to the connection object. + * @param metadata Bitfield (`BT_OTS_METADATA_REQ_*`) of the metadata + * to read. + * + * @return int 0 if success, ERRNO on failure. + */ +int bt_ots_client_read_object_metadata(struct bt_ots_client *otc_inst, + struct bt_conn *conn, + uint8_t metadata); + +/** @brief Read the data of the current selected object. + * + * This will trigger an OACP read operation for the current size of the object + * with a 0 offset and then expect receiving the content via the L2CAP CoC. + * + * The data of the object are returned in the obj_data_read() callback. + * + * @param otc_inst Pointer to the OTC instance. + * @param conn Pointer to the connection object. + * + * @return int 0 if success, ERRNO on failure. + */ +int bt_ots_client_read_object_data(struct bt_ots_client *otc_inst, + struct bt_conn *conn); + +/** @brief Write the data of the current selected object. + * + * This will trigger an OACP write operation for the current object + * with a specified offset and then expect transferring the content via the L2CAP CoC. + * + * The length of the data written to object is returned in the obj_data_written() callback. + * + * @param otc_inst Pointer to the OTC instance. + * @param conn Pointer to the connection object. + * @param buf Pointer to the data buffer to be written. + * @param len Size of data. + * @param offset Offset to write, usually 0. + * @param mode Mode Parameter for OACP Write Op Code. See @ref bt_ots_oacp_write_op_mode. + * + * @return int 0 if success, ERRNO on failure. + */ +int bt_ots_client_write_object_data(struct bt_ots_client *otc_inst, struct bt_conn *conn, + const void *buf, size_t len, off_t offset, + enum bt_ots_oacp_write_op_mode mode); + +/** @brief Get the checksum of the current selected object. + * + * This will trigger an OACP calculate checksum operation for the current object + * with a specified offset and length. + * + * The checksum goes to OACP IND and obj_checksum_calculated() callback. + * + * @param otc_inst Pointer to the OTC instance. + * @param conn Pointer to the connection object. + * @param offset Offset to calculate, usually 0. + * @param len Len of data to calculate checksum for. May be less than the current object's + * size, but shall not be larger. + * + * @return int 0 if success, ERRNO on failure. + */ +int bt_ots_client_get_object_checksum(struct bt_ots_client *otc_inst, struct bt_conn *conn, + off_t offset, size_t len); + +/** @brief Directory listing object metadata callback + * + * If a directory listing is decoded using bt_ots_client_decode_dirlisting(), + * this callback will be called for each object in the directory listing. + * + * @param meta The metadata of the decoded object + * + * @return int BT_OTS_STOP or BT_OTS_CONTINUE. BT_OTS_STOP can be used to + * stop the decoding. + */ +typedef int (*bt_ots_client_dirlisting_cb)(struct bt_ots_obj_metadata *meta); + +/** @brief Decode Directory Listing object into object metadata. + * + * If the Directory Listing object contains multiple objects, then the + * callback will be called for each of them. + * + * @param data The data received for the directory listing object. + * @param length Length of the data. + * @param cb The callback that will be called for each object. + */ +int bt_ots_client_decode_dirlisting(uint8_t *data, uint16_t length, + bt_ots_client_dirlisting_cb cb); + +/** @brief Converts binary OTS Object ID to string. + * + * @param obj_id Object ID. + * @param str Address of user buffer with enough room to store + * formatted string containing binary Object ID. + * @param len Length of data to be copied to user string buffer. + * Refer to BT_OTS_OBJ_ID_STR_LEN about + * recommended value. + * + * @return Number of successfully formatted bytes from binary ID. + */ +static inline int bt_ots_obj_id_to_str(uint64_t obj_id, char *str, size_t len) +{ + uint8_t id[6]; + + sys_put_le48(obj_id, id); + + return snprintf(str, len, "%02X%02X%02X%02X%02X%02X", + id[5], id[4], id[3], id[2], id[1], id[0]); +} + +/** @brief Displays one or more object metadata as text with LOG_INF. + * + * @param metadata Pointer to the first (or only) metadata in an array. + * @param count Number of metadata objects to display information of. + */ +void bt_ots_metadata_display(struct bt_ots_obj_metadata *metadata, + uint16_t count); + +/** + * @brief Generate IEEE conform CRC32 checksum. + * + * To abstract IEEE implementation to service layer. + * + * @param data Pointer to data on which the CRC should be calculated. + * @param len Data length. + * + * @return CRC32 value. + * + */ +static inline uint32_t bt_ots_client_calc_checksum(const uint8_t *data, size_t len) +{ + return crc32_ieee(data, len); +} + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_SERVICES_OTS_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/bluetooth/uuid.h b/components/bt/esp_ble_audio/include/zephyr/bluetooth/uuid.h new file mode 100644 index 0000000000..7f9e00a700 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/bluetooth/uuid.h @@ -0,0 +1,5259 @@ +/** @file + * @brief Bluetooth UUID handling + */ + +/* + * SPDX-FileCopyrightText: 2015-2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_UUID_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_UUID_H_ + +/** + * @brief UUIDs + * @defgroup bt_uuid UUIDs + * @ingroup bluetooth + * @{ + */ + +#include +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief Bluetooth UUID types */ +enum { + /** UUID type 16-bit. */ + BT_UUID_TYPE_16, + /** UUID type 32-bit. */ + BT_UUID_TYPE_32, + /** UUID type 128-bit. */ + BT_UUID_TYPE_128, +}; + +/** Size in octets of a 16-bit UUID */ +#define BT_UUID_SIZE_16 2 + +/** Size in octets of a 32-bit UUID */ +#define BT_UUID_SIZE_32 4 + +/** Size in octets of a 128-bit UUID */ +#define BT_UUID_SIZE_128 16 + +/** @brief This is a 'tentative' type and should be used as a pointer only */ +struct bt_uuid { + uint8_t type; +}; + +struct bt_uuid_16 { + /** UUID generic type. */ + struct bt_uuid uuid; + /** UUID value, 16-bit in host endianness. */ + uint16_t val; +}; + +struct bt_uuid_32 { + /** UUID generic type. */ + struct bt_uuid uuid; + /** UUID value, 32-bit in host endianness. */ + uint32_t val; +}; + +struct bt_uuid_128 { + /** UUID generic type. */ + struct bt_uuid uuid; + /** UUID value, 128-bit in little-endian format. */ + uint8_t val[BT_UUID_SIZE_128]; +}; + +/** @brief Initialize a 16-bit UUID. + * + * @param value 16-bit UUID value in host endianness. + */ +#define BT_UUID_INIT_16(value) \ +{ \ + .uuid = { BT_UUID_TYPE_16 }, \ + .val = (value), \ +} + +/** @brief Initialize a 32-bit UUID. + * + * @param value 32-bit UUID value in host endianness. + */ +#define BT_UUID_INIT_32(value) \ +{ \ + .uuid = { BT_UUID_TYPE_32 }, \ + .val = (value), \ +} + +/** @brief Initialize a 128-bit UUID. + * + * @param value 128-bit UUID array values in little-endian format. + * Can be combined with @ref BT_UUID_128_ENCODE to initialize a + * UUID from the readable form of UUIDs. + */ +#define BT_UUID_INIT_128(value...) \ +{ \ + .uuid = { BT_UUID_TYPE_128 }, \ + .val = { value }, \ +} + +/** @brief Helper to declare a 16-bit UUID inline. + * + * @param value 16-bit UUID value in host endianness. + * + * @return Pointer to a generic UUID. + */ +#define BT_UUID_DECLARE_16(value) \ + ((const struct bt_uuid *) ((const struct bt_uuid_16[]) {BT_UUID_INIT_16(value)})) + +/** @brief Helper to declare a 32-bit UUID inline. + * + * @param value 32-bit UUID value in host endianness. + * + * @return Pointer to a generic UUID. + */ +#define BT_UUID_DECLARE_32(value) \ + ((const struct bt_uuid *) ((const struct bt_uuid_32[]) {BT_UUID_INIT_32(value)})) + +/** @brief Helper to declare a 128-bit UUID inline. + * + * @param value 128-bit UUID array values in little-endian format. + * Can be combined with @ref BT_UUID_128_ENCODE to declare a + * UUID from the readable form of UUIDs. + * + * @return Pointer to a generic UUID. + */ +#define BT_UUID_DECLARE_128(value...) \ + ((const struct bt_uuid *) ((const struct bt_uuid_128[]) {BT_UUID_INIT_128(value)})) + +/** Helper macro to access the 16-bit UUID from a generic UUID. */ +#define BT_UUID_16(__u) CONTAINER_OF(__u, struct bt_uuid_16, uuid) + +/** Helper macro to access the 32-bit UUID from a generic UUID. */ +#define BT_UUID_32(__u) CONTAINER_OF(__u, struct bt_uuid_32, uuid) + +/** Helper macro to access the 128-bit UUID from a generic UUID. */ +#define BT_UUID_128(__u) CONTAINER_OF(__u, struct bt_uuid_128, uuid) + +/** @brief Encode 128 bit UUID into array values in little-endian format. + * + * Helper macro to initialize a 128-bit UUID array value from the readable form + * of UUIDs, or encode 128-bit UUID values into advertising data + * Can be combined with BT_UUID_DECLARE_128 to declare a 128-bit UUID. + * + * Example of how to declare the UUID `6E400001-B5A3-F393-E0A9-E50E24DCCA9E` + * + * @code + * BT_UUID_DECLARE_128( + * BT_UUID_128_ENCODE(0x6E400001, 0xB5A3, 0xF393, 0xE0A9, 0xE50E24DCCA9E)) + * @endcode + * + * Example of how to encode the UUID `6E400001-B5A3-F393-E0A9-E50E24DCCA9E` + * into advertising data. + * + * @code + * BT_DATA_BYTES(BT_DATA_UUID128_ALL, + * BT_UUID_128_ENCODE(0x6E400001, 0xB5A3, 0xF393, 0xE0A9, 0xE50E24DCCA9E)) + * @endcode + * + * Just replace the hyphen by the comma and add `0x` prefixes. + * + * @param w32 First part of the UUID (32 bits) + * @param w1 Second part of the UUID (16 bits) + * @param w2 Third part of the UUID (16 bits) + * @param w3 Fourth part of the UUID (16 bits) + * @param w48 Fifth part of the UUID (48 bits) + * + * @return The comma separated values for UUID 128 initializer that + * may be used directly as an argument for + * @ref BT_UUID_INIT_128 or @ref BT_UUID_DECLARE_128 + */ +#define BT_UUID_128_ENCODE(w32, w1, w2, w3, w48) \ + BT_BYTES_LIST_LE48(w48),\ + BT_BYTES_LIST_LE16(w3), \ + BT_BYTES_LIST_LE16(w2), \ + BT_BYTES_LIST_LE16(w1), \ + BT_BYTES_LIST_LE32(w32) + +/** @brief Encode 16-bit UUID into array values in little-endian format. + * + * Helper macro to encode 16-bit UUID values into advertising data. + * + * Example of how to encode the UUID `0x180a` into advertising data. + * + * @code + * BT_DATA_BYTES(BT_DATA_UUID16_ALL, BT_UUID_16_ENCODE(0x180a)) + * @endcode + * + * @param w16 UUID value (16-bits) + * + * @return The comma separated values for UUID 16 value that + * may be used directly as an argument for @ref BT_DATA_BYTES. + */ +#define BT_UUID_16_ENCODE(w16) BT_BYTES_LIST_LE16(w16) + +/** @brief Encode 32-bit UUID into array values in little-endian format. + * + * Helper macro to encode 32-bit UUID values into advertising data. + * + * Example of how to encode the UUID `0x180a01af` into advertising data. + * + * @code + * BT_DATA_BYTES(BT_DATA_UUID32_ALL, BT_UUID_32_ENCODE(0x180a01af)) + * @endcode + * + * @param w32 UUID value (32-bits) + * + * @return The comma separated values for UUID 32 value that + * may be used directly as an argument for @ref BT_DATA_BYTES. + */ +#define BT_UUID_32_ENCODE(w32) BT_BYTES_LIST_LE32(w32) + +/** + * @brief Recommended length of user string buffer for Bluetooth UUID. + * + * @details The recommended length guarantee the output of UUID + * conversion will not lose valuable information about the UUID being + * processed. If the length of the UUID is known the string can be shorter. + */ +#define BT_UUID_STR_LEN 37 + +/** + * @brief Generic Access UUID value + */ +#define BT_UUID_GAP_VAL 0x1800 +/** + * @brief Generic Access + */ +#define BT_UUID_GAP \ + BT_UUID_DECLARE_16(BT_UUID_GAP_VAL) +/** + * @brief Generic attribute UUID value + */ +#define BT_UUID_GATT_VAL 0x1801 +/** + * @brief Generic Attribute + */ +#define BT_UUID_GATT \ + BT_UUID_DECLARE_16(BT_UUID_GATT_VAL) +/** + * @brief Immediate Alert Service UUID value + */ +#define BT_UUID_IAS_VAL 0x1802 +/** + * @brief Immediate Alert Service + */ +#define BT_UUID_IAS \ + BT_UUID_DECLARE_16(BT_UUID_IAS_VAL) +/** + * @brief Link Loss Service UUID value + */ +#define BT_UUID_LLS_VAL 0x1803 +/** + * @brief Link Loss Service + */ +#define BT_UUID_LLS \ + BT_UUID_DECLARE_16(BT_UUID_LLS_VAL) +/** + * @brief Tx Power Service UUID value + */ +#define BT_UUID_TPS_VAL 0x1804 +/** + * @brief Tx Power Service + */ +#define BT_UUID_TPS \ + BT_UUID_DECLARE_16(BT_UUID_TPS_VAL) +/** + * @brief Current Time Service UUID value + */ +#define BT_UUID_CTS_VAL 0x1805 +/** + * @brief Current Time Service + */ +#define BT_UUID_CTS \ + BT_UUID_DECLARE_16(BT_UUID_CTS_VAL) +/** + * @brief Reference Time Update Service UUID value + */ +#define BT_UUID_RTUS_VAL 0x1806 +/** + * @brief Reference Time Update Service + */ +#define BT_UUID_RTUS \ + BT_UUID_DECLARE_16(BT_UUID_RTUS_VAL) +/** + * @brief Next DST Change Service UUID value + */ +#define BT_UUID_NDSTS_VAL 0x1807 +/** + * @brief Next DST Change Service + */ +#define BT_UUID_NDSTS \ + BT_UUID_DECLARE_16(BT_UUID_NDSTS_VAL) +/** + * @brief Glucose Service UUID value + */ +#define BT_UUID_GS_VAL 0x1808 +/** + * @brief Glucose Service + */ +#define BT_UUID_GS \ + BT_UUID_DECLARE_16(BT_UUID_GS_VAL) +/** + * @brief Health Thermometer Service UUID value + */ +#define BT_UUID_HTS_VAL 0x1809 +/** + * @brief Health Thermometer Service + */ +#define BT_UUID_HTS \ + BT_UUID_DECLARE_16(BT_UUID_HTS_VAL) +/** + * @brief Device Information Service UUID value + */ +#define BT_UUID_DIS_VAL 0x180a +/** + * @brief Device Information Service + */ +#define BT_UUID_DIS \ + BT_UUID_DECLARE_16(BT_UUID_DIS_VAL) +/** + * @brief Network Availability Service UUID value + */ +#define BT_UUID_NAS_VAL 0x180b +/** + * @brief Network Availability Service + */ +#define BT_UUID_NAS \ + BT_UUID_DECLARE_16(BT_UUID_NAS_VAL) +/** + * @brief Watchdog Service UUID value + */ +#define BT_UUID_WDS_VAL 0x180c +/** + * @brief Watchdog Service + */ +#define BT_UUID_WDS \ + BT_UUID_DECLARE_16(BT_UUID_WDS_VAL) +/** + * @brief Heart Rate Service UUID value + */ +#define BT_UUID_HRS_VAL 0x180d +/** + * @brief Heart Rate Service + */ +#define BT_UUID_HRS \ + BT_UUID_DECLARE_16(BT_UUID_HRS_VAL) +/** + * @brief Phone Alert Service UUID value + */ +#define BT_UUID_PAS_VAL 0x180e +/** + * @brief Phone Alert Service + */ +#define BT_UUID_PAS \ + BT_UUID_DECLARE_16(BT_UUID_PAS_VAL) +/** + * @brief Battery Service UUID value + */ +#define BT_UUID_BAS_VAL 0x180f +/** + * @brief Battery Service + */ +#define BT_UUID_BAS \ + BT_UUID_DECLARE_16(BT_UUID_BAS_VAL) +/** + * @brief Blood Pressure Service UUID value + */ +#define BT_UUID_BPS_VAL 0x1810 +/** + * @brief Blood Pressure Service + */ +#define BT_UUID_BPS \ + BT_UUID_DECLARE_16(BT_UUID_BPS_VAL) +/** + * @brief Alert Notification Service UUID value + */ +#define BT_UUID_ANS_VAL 0x1811 +/** + * @brief Alert Notification Service + */ +#define BT_UUID_ANS \ + BT_UUID_DECLARE_16(BT_UUID_ANS_VAL) +/** + * @brief HID Service UUID value + */ +#define BT_UUID_HIDS_VAL 0x1812 +/** + * @brief HID Service + */ +#define BT_UUID_HIDS \ + BT_UUID_DECLARE_16(BT_UUID_HIDS_VAL) +/** + * @brief Scan Parameters Service UUID value + */ +#define BT_UUID_SPS_VAL 0x1813 +/** + * @brief Scan Parameters Service + */ +#define BT_UUID_SPS \ + BT_UUID_DECLARE_16(BT_UUID_SPS_VAL) +/** + * @brief Running Speed and Cadence Service UUID value + */ +#define BT_UUID_RSCS_VAL 0x1814 +/** + * @brief Running Speed and Cadence Service + */ +#define BT_UUID_RSCS \ + BT_UUID_DECLARE_16(BT_UUID_RSCS_VAL) +/** + * @brief Automation IO Service UUID value + */ +#define BT_UUID_AIOS_VAL 0x1815 +/** + * @brief Automation IO Service + */ +#define BT_UUID_AIOS \ + BT_UUID_DECLARE_16(BT_UUID_AIOS_VAL) +/** + * @brief Cycling Speed and Cadence Service UUID value + */ +#define BT_UUID_CSC_VAL 0x1816 +/** + * @brief Cycling Speed and Cadence Service + */ +#define BT_UUID_CSC \ + BT_UUID_DECLARE_16(BT_UUID_CSC_VAL) +/** + * @brief Cycling Power Service UUID value + */ +#define BT_UUID_CPS_VAL 0x1818 +/** + * @brief Cycling Power Service + */ +#define BT_UUID_CPS \ + BT_UUID_DECLARE_16(BT_UUID_CPS_VAL) +/** + * @brief Location and Navigation Service UUID value + */ +#define BT_UUID_LNS_VAL 0x1819 +/** + * @brief Location and Navigation Service + */ +#define BT_UUID_LNS \ + BT_UUID_DECLARE_16(BT_UUID_LNS_VAL) +/** + * @brief Environmental Sensing Service UUID value + */ +#define BT_UUID_ESS_VAL 0x181a +/** + * @brief Environmental Sensing Service + */ +#define BT_UUID_ESS \ + BT_UUID_DECLARE_16(BT_UUID_ESS_VAL) +/** + * @brief Body Composition Service UUID value + */ +#define BT_UUID_BCS_VAL 0x181b +/** + * @brief Body Composition Service + */ +#define BT_UUID_BCS \ + BT_UUID_DECLARE_16(BT_UUID_BCS_VAL) +/** + * @brief User Data Service UUID value + */ +#define BT_UUID_UDS_VAL 0x181c +/** + * @brief User Data Service + */ +#define BT_UUID_UDS \ + BT_UUID_DECLARE_16(BT_UUID_UDS_VAL) +/** + * @brief Weight Scale Service UUID value + */ +#define BT_UUID_WSS_VAL 0x181d +/** + * @brief Weight Scale Service + */ +#define BT_UUID_WSS \ + BT_UUID_DECLARE_16(BT_UUID_WSS_VAL) +/** + * @brief Bond Management Service UUID value + */ +#define BT_UUID_BMS_VAL 0x181e +/** + * @brief Bond Management Service + */ +#define BT_UUID_BMS \ + BT_UUID_DECLARE_16(BT_UUID_BMS_VAL) +/** + * @brief Continuous Glucose Monitoring Service UUID value + */ +#define BT_UUID_CGMS_VAL 0x181f +/** + * @brief Continuous Glucose Monitoring Service + */ +#define BT_UUID_CGMS \ + BT_UUID_DECLARE_16(BT_UUID_CGMS_VAL) +/** + * @brief IP Support Service UUID value + */ +#define BT_UUID_IPSS_VAL 0x1820 +/** + * @brief IP Support Service + */ +#define BT_UUID_IPSS \ + BT_UUID_DECLARE_16(BT_UUID_IPSS_VAL) +/** + * @brief Indoor Positioning Service UUID value + */ +#define BT_UUID_IPS_VAL 0x1821 +/** + * @brief Indoor Positioning Service + */ +#define BT_UUID_IPS \ + BT_UUID_DECLARE_16(BT_UUID_IPS_VAL) +/** + * @brief Pulse Oximeter Service UUID value + */ +#define BT_UUID_POS_VAL 0x1822 +/** + * @brief Pulse Oximeter Service + */ +#define BT_UUID_POS \ + BT_UUID_DECLARE_16(BT_UUID_POS_VAL) +/** + * @brief HTTP Proxy Service UUID value + */ +#define BT_UUID_HPS_VAL 0x1823 +/** + * @brief HTTP Proxy Service + */ +#define BT_UUID_HPS \ + BT_UUID_DECLARE_16(BT_UUID_HPS_VAL) +/** + * @brief Transport Discovery Service UUID value + */ +#define BT_UUID_TDS_VAL 0x1824 +/** + * @brief Transport Discovery Service + */ +#define BT_UUID_TDS \ + BT_UUID_DECLARE_16(BT_UUID_TDS_VAL) +/** + * @brief Object Transfer Service UUID value + */ +#define BT_UUID_OTS_VAL 0x1825 +/** + * @brief Object Transfer Service + */ +#define BT_UUID_OTS \ + BT_UUID_DECLARE_16(BT_UUID_OTS_VAL) +/** + * @brief Fitness Machine Service UUID value + */ +#define BT_UUID_FMS_VAL 0x1826 +/** + * @brief Fitness Machine Service + */ +#define BT_UUID_FMS \ + BT_UUID_DECLARE_16(BT_UUID_FMS_VAL) +/** + * @brief Mesh Provisioning Service UUID value + */ +#define BT_UUID_MESH_PROV_VAL 0x1827 +/** + * @brief Mesh Provisioning Service + */ +#define BT_UUID_MESH_PROV \ + BT_UUID_DECLARE_16(BT_UUID_MESH_PROV_VAL) +/** + * @brief Mesh Proxy Service UUID value + */ +#define BT_UUID_MESH_PROXY_VAL 0x1828 +/** + * @brief Mesh Proxy Service + */ +#define BT_UUID_MESH_PROXY \ + BT_UUID_DECLARE_16(BT_UUID_MESH_PROXY_VAL) +/** + * @brief Proxy Solicitation UUID value + */ +#define BT_UUID_MESH_PROXY_SOLICITATION_VAL 0x1859 +/** + * @brief Reconnection Configuration Service UUID value + */ +#define BT_UUID_RCSRV_VAL 0x1829 +/** + * @brief Reconnection Configuration Service + */ +#define BT_UUID_RCSRV \ + BT_UUID_DECLARE_16(BT_UUID_RCSRV_VAL) +/** + * @brief Insulin Delivery Service UUID value + */ +#define BT_UUID_IDS_VAL 0x183a +/** + * @brief Insulin Delivery Service + */ +#define BT_UUID_IDS \ + BT_UUID_DECLARE_16(BT_UUID_IDS_VAL) +/** + * @brief Binary Sensor Service UUID value + */ +#define BT_UUID_BSS_VAL 0x183b +/** + * @brief Binary Sensor Service + */ +#define BT_UUID_BSS \ + BT_UUID_DECLARE_16(BT_UUID_BSS_VAL) +/** + * @brief Emergency Configuration Service UUID value + */ +#define BT_UUID_ECS_VAL 0x183c +/** + * @brief Emergency Configuration Service + */ +#define BT_UUID_ECS \ + BT_UUID_DECLARE_16(BT_UUID_ECS_VAL) +/** + * @brief Authorization Control Service UUID value + */ +#define BT_UUID_ACLS_VAL 0x183d +/** + * @brief Authorization Control Service + */ +#define BT_UUID_ACLS \ + BT_UUID_DECLARE_16(BT_UUID_ACLS_VAL) +/** + * @brief Physical Activity Monitor Service UUID value + */ +#define BT_UUID_PAMS_VAL 0x183e +/** + * @brief Physical Activity Monitor Service + */ +#define BT_UUID_PAMS \ + BT_UUID_DECLARE_16(BT_UUID_PAMS_VAL) +/** + * @brief Audio Input Control Service UUID value + */ +#define BT_UUID_AICS_VAL 0x1843 +/** + * @brief Audio Input Control Service + */ +#define BT_UUID_AICS \ + BT_UUID_DECLARE_16(BT_UUID_AICS_VAL) +/** + * @brief Volume Control Service UUID value + */ +#define BT_UUID_VCS_VAL 0x1844 +/** + * @brief Volume Control Service + */ +#define BT_UUID_VCS \ + BT_UUID_DECLARE_16(BT_UUID_VCS_VAL) +/** + * @brief Volume Offset Control Service UUID value + */ +#define BT_UUID_VOCS_VAL 0x1845 +/** + * @brief Volume Offset Control Service + */ +#define BT_UUID_VOCS \ + BT_UUID_DECLARE_16(BT_UUID_VOCS_VAL) +/** + * @brief Coordinated Set Identification Service UUID value + */ +#define BT_UUID_CSIS_VAL 0x1846 +/** + * @brief Coordinated Set Identification Service + */ +#define BT_UUID_CSIS \ + BT_UUID_DECLARE_16(BT_UUID_CSIS_VAL) +/** + * @brief Device Time Service UUID value + */ +#define BT_UUID_DTS_VAL 0x1847 +/** + * @brief Device Time Service + */ +#define BT_UUID_DTS \ + BT_UUID_DECLARE_16(BT_UUID_DTS_VAL) +/** + * @brief Media Control Service UUID value + */ +#define BT_UUID_MCS_VAL 0x1848 +/** + * @brief Media Control Service + */ +#define BT_UUID_MCS \ + BT_UUID_DECLARE_16(BT_UUID_MCS_VAL) +/** + * @brief Generic Media Control Service UUID value + */ +#define BT_UUID_GMCS_VAL 0x1849 +/** + * @brief Generic Media Control Service + */ +#define BT_UUID_GMCS \ + BT_UUID_DECLARE_16(BT_UUID_GMCS_VAL) +/** + * @brief Constant Tone Extension Service UUID value + */ +#define BT_UUID_CTES_VAL 0x184a +/** + * @brief Constant Tone Extension Service + */ +#define BT_UUID_CTES \ + BT_UUID_DECLARE_16(BT_UUID_CTES_VAL) +/** + * @brief Telephone Bearer Service UUID value + */ +#define BT_UUID_TBS_VAL 0x184b +/** + * @brief Telephone Bearer Service + */ +#define BT_UUID_TBS \ + BT_UUID_DECLARE_16(BT_UUID_TBS_VAL) +/** + * @brief Generic Telephone Bearer Service UUID value + */ +#define BT_UUID_GTBS_VAL 0x184c +/** + * @brief Generic Telephone Bearer Service + */ +#define BT_UUID_GTBS \ + BT_UUID_DECLARE_16(BT_UUID_GTBS_VAL) +/** + * @brief Microphone Control Service UUID value + */ +#define BT_UUID_MICS_VAL 0x184d +/** + * @brief Microphone Control Service + */ +#define BT_UUID_MICS \ + BT_UUID_DECLARE_16(BT_UUID_MICS_VAL) +/** + * @brief Audio Stream Control Service UUID value + */ +#define BT_UUID_ASCS_VAL 0x184e +/** + * @brief Audio Stream Control Service + */ +#define BT_UUID_ASCS \ + BT_UUID_DECLARE_16(BT_UUID_ASCS_VAL) +/** + * @brief Broadcast Audio Scan Service UUID value + */ +#define BT_UUID_BASS_VAL 0x184f +/** + * @brief Broadcast Audio Scan Service + */ +#define BT_UUID_BASS \ + BT_UUID_DECLARE_16(BT_UUID_BASS_VAL) +/** + * @brief Published Audio Capabilities Service UUID value + */ +#define BT_UUID_PACS_VAL 0x1850 +/** + * @brief Published Audio Capabilities Service + */ +#define BT_UUID_PACS \ + BT_UUID_DECLARE_16(BT_UUID_PACS_VAL) +/** + * @brief Basic Audio Announcement Service UUID value + */ +#define BT_UUID_BASIC_AUDIO_VAL 0x1851 +/** + * @brief Basic Audio Announcement Service + */ +#define BT_UUID_BASIC_AUDIO \ + BT_UUID_DECLARE_16(BT_UUID_BASIC_AUDIO_VAL) +/** + * @brief Broadcast Audio Announcement Service UUID value + */ +#define BT_UUID_BROADCAST_AUDIO_VAL 0x1852 +/** + * @brief Broadcast Audio Announcement Service + */ +#define BT_UUID_BROADCAST_AUDIO \ + BT_UUID_DECLARE_16(BT_UUID_BROADCAST_AUDIO_VAL) +/** + * @brief Common Audio Service UUID value + */ +#define BT_UUID_CAS_VAL 0x1853 +/** + * @brief Common Audio Service + */ +#define BT_UUID_CAS \ + BT_UUID_DECLARE_16(BT_UUID_CAS_VAL) +/** + * @brief Hearing Access Service UUID value + */ +#define BT_UUID_HAS_VAL 0x1854 +/** + * @brief Hearing Access Service + */ +#define BT_UUID_HAS \ + BT_UUID_DECLARE_16(BT_UUID_HAS_VAL) +/** + * @brief Telephony and Media Audio Service UUID value + */ +#define BT_UUID_TMAS_VAL 0x1855 +/** + * @brief Telephony and Media Audio Service + */ +#define BT_UUID_TMAS \ + BT_UUID_DECLARE_16(BT_UUID_TMAS_VAL) +/** + * @brief Public Broadcast Announcement Service UUID value + */ +#define BT_UUID_PBA_VAL 0x1856 +/** + * @brief Public Broadcast Announcement Service + */ +#define BT_UUID_PBA \ + BT_UUID_DECLARE_16(BT_UUID_PBA_VAL) +/** + * @brief GATT Primary Service UUID value + */ +#define BT_UUID_GATT_PRIMARY_VAL 0x2800 +/** + * @brief GATT Primary Service + */ +#define BT_UUID_GATT_PRIMARY \ + BT_UUID_DECLARE_16(BT_UUID_GATT_PRIMARY_VAL) +/** + * @brief GATT Secondary Service UUID value + */ +#define BT_UUID_GATT_SECONDARY_VAL 0x2801 +/** + * @brief GATT Secondary Service + */ +#define BT_UUID_GATT_SECONDARY \ + BT_UUID_DECLARE_16(BT_UUID_GATT_SECONDARY_VAL) +/** + * @brief GATT Include Service UUID value + */ +#define BT_UUID_GATT_INCLUDE_VAL 0x2802 +/** + * @brief GATT Include Service + */ +#define BT_UUID_GATT_INCLUDE \ + BT_UUID_DECLARE_16(BT_UUID_GATT_INCLUDE_VAL) +/** + * @brief GATT Characteristic UUID value + */ +#define BT_UUID_GATT_CHRC_VAL 0x2803 +/** + * @brief GATT Characteristic + */ +#define BT_UUID_GATT_CHRC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_CHRC_VAL) +/** + * @brief GATT Characteristic Extended Properties UUID value + */ +#define BT_UUID_GATT_CEP_VAL 0x2900 +/** + * @brief GATT Characteristic Extended Properties + */ +#define BT_UUID_GATT_CEP \ + BT_UUID_DECLARE_16(BT_UUID_GATT_CEP_VAL) +/** + * @brief GATT Characteristic User Description UUID value + */ +#define BT_UUID_GATT_CUD_VAL 0x2901 +/** + * @brief GATT Characteristic User Description + */ +#define BT_UUID_GATT_CUD \ + BT_UUID_DECLARE_16(BT_UUID_GATT_CUD_VAL) +/** + * @brief GATT Client Characteristic Configuration UUID value + */ +#define BT_UUID_GATT_CCC_VAL 0x2902 +/** + * @brief GATT Client Characteristic Configuration + */ +#define BT_UUID_GATT_CCC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_CCC_VAL) +/** + * @brief GATT Server Characteristic Configuration UUID value + */ +#define BT_UUID_GATT_SCC_VAL 0x2903 +/** + * @brief GATT Server Characteristic Configuration + */ +#define BT_UUID_GATT_SCC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_SCC_VAL) +/** + * @brief GATT Characteristic Presentation Format UUID value + */ +#define BT_UUID_GATT_CPF_VAL 0x2904 +/** + * @brief GATT Characteristic Presentation Format + */ +#define BT_UUID_GATT_CPF \ + BT_UUID_DECLARE_16(BT_UUID_GATT_CPF_VAL) +/** + * @brief GATT Characteristic Aggregated Format UUID value + */ +#define BT_UUID_GATT_CAF_VAL 0x2905 +/** + * @brief GATT Characteristic Aggregated Format + */ +#define BT_UUID_GATT_CAF \ + BT_UUID_DECLARE_16(BT_UUID_GATT_CAF_VAL) +/** + * @brief Valid Range Descriptor UUID value + */ +#define BT_UUID_VALID_RANGE_VAL 0x2906 +/** + * @brief Valid Range Descriptor + */ +#define BT_UUID_VALID_RANGE \ + BT_UUID_DECLARE_16(BT_UUID_VALID_RANGE_VAL) +/** + * @brief HID External Report Descriptor UUID value + */ +#define BT_UUID_HIDS_EXT_REPORT_VAL 0x2907 +/** + * @brief HID External Report Descriptor + */ +#define BT_UUID_HIDS_EXT_REPORT \ + BT_UUID_DECLARE_16(BT_UUID_HIDS_EXT_REPORT_VAL) +/** + * @brief HID Report Reference Descriptor UUID value + */ +#define BT_UUID_HIDS_REPORT_REF_VAL 0x2908 +/** + * @brief HID Report Reference Descriptor + */ +#define BT_UUID_HIDS_REPORT_REF \ + BT_UUID_DECLARE_16(BT_UUID_HIDS_REPORT_REF_VAL) +/** + * @brief Value Trigger Setting Descriptor UUID value + */ +#define BT_UUID_VAL_TRIGGER_SETTING_VAL 0x290a +/** + * @brief Value Trigger Setting Descriptor + */ +#define BT_UUID_VAL_TRIGGER_SETTING \ + BT_UUID_DECLARE_16(BT_UUID_VAL_TRIGGER_SETTING_VAL) +/** + * @brief Environmental Sensing Configuration Descriptor UUID value + */ +#define BT_UUID_ES_CONFIGURATION_VAL 0x290b +/** + * @brief Environmental Sensing Configuration Descriptor + */ +#define BT_UUID_ES_CONFIGURATION \ + BT_UUID_DECLARE_16(BT_UUID_ES_CONFIGURATION_VAL) +/** + * @brief Environmental Sensing Measurement Descriptor UUID value + */ +#define BT_UUID_ES_MEASUREMENT_VAL 0x290c +/** + * @brief Environmental Sensing Measurement Descriptor + */ +#define BT_UUID_ES_MEASUREMENT \ + BT_UUID_DECLARE_16(BT_UUID_ES_MEASUREMENT_VAL) +/** + * @brief Environmental Sensing Trigger Setting Descriptor UUID value + */ +#define BT_UUID_ES_TRIGGER_SETTING_VAL 0x290d +/** + * @brief Environmental Sensing Trigger Setting Descriptor + */ +#define BT_UUID_ES_TRIGGER_SETTING \ + BT_UUID_DECLARE_16(BT_UUID_ES_TRIGGER_SETTING_VAL) +/** + * @brief Time Trigger Setting Descriptor UUID value + */ +#define BT_UUID_TM_TRIGGER_SETTING_VAL 0x290e +/** + * @brief Time Trigger Setting Descriptor + */ +#define BT_UUID_TM_TRIGGER_SETTING \ + BT_UUID_DECLARE_16(BT_UUID_TM_TRIGGER_SETTING_VAL) +/** + * @brief GAP Characteristic Device Name UUID value + */ +#define BT_UUID_GAP_DEVICE_NAME_VAL 0x2a00 +/** + * @brief GAP Characteristic Device Name + */ +#define BT_UUID_GAP_DEVICE_NAME \ + BT_UUID_DECLARE_16(BT_UUID_GAP_DEVICE_NAME_VAL) +/** + * @brief GAP Characteristic Appearance UUID value + */ +#define BT_UUID_GAP_APPEARANCE_VAL 0x2a01 +/** + * @brief GAP Characteristic Appearance + */ +#define BT_UUID_GAP_APPEARANCE \ + BT_UUID_DECLARE_16(BT_UUID_GAP_APPEARANCE_VAL) +/** + * @brief GAP Characteristic Peripheral Privacy Flag UUID value + */ +#define BT_UUID_GAP_PPF_VAL 0x2a02 +/** + * @brief GAP Characteristic Peripheral Privacy Flag + */ +#define BT_UUID_GAP_PPF \ + BT_UUID_DECLARE_16(BT_UUID_GAP_PPF_VAL) +/** + * @brief GAP Characteristic Reconnection Address UUID value + */ +#define BT_UUID_GAP_RA_VAL 0x2a03 +/** + * @brief GAP Characteristic Reconnection Address + */ +#define BT_UUID_GAP_RA \ + BT_UUID_DECLARE_16(BT_UUID_GAP_RA_VAL) +/** + * @brief GAP Characteristic Peripheral Preferred Connection Parameters UUID + * value + */ +#define BT_UUID_GAP_PPCP_VAL 0x2a04 +/** + * @brief GAP Characteristic Peripheral Preferred Connection Parameters + */ +#define BT_UUID_GAP_PPCP \ + BT_UUID_DECLARE_16(BT_UUID_GAP_PPCP_VAL) +/** + * @brief GATT Characteristic Service Changed UUID value + */ +#define BT_UUID_GATT_SC_VAL 0x2a05 +/** + * @brief GATT Characteristic Service Changed + */ +#define BT_UUID_GATT_SC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_SC_VAL) +/** + * @brief GATT Characteristic Alert Level UUID value + */ +#define BT_UUID_ALERT_LEVEL_VAL 0x2a06 +/** + * @brief GATT Characteristic Alert Level + */ +#define BT_UUID_ALERT_LEVEL \ + BT_UUID_DECLARE_16(BT_UUID_ALERT_LEVEL_VAL) +/** + * @brief TPS Characteristic Tx Power Level UUID value + */ +#define BT_UUID_TPS_TX_POWER_LEVEL_VAL 0x2a07 +/** + * @brief TPS Characteristic Tx Power Level + */ +#define BT_UUID_TPS_TX_POWER_LEVEL \ + BT_UUID_DECLARE_16(BT_UUID_TPS_TX_POWER_LEVEL_VAL) +/** + * @brief GATT Characteristic Date Time UUID value + */ +#define BT_UUID_GATT_DT_VAL 0x2a08 +/** + * @brief GATT Characteristic Date Time + */ +#define BT_UUID_GATT_DT \ + BT_UUID_DECLARE_16(BT_UUID_GATT_DT_VAL) +/** + * @brief GATT Characteristic Day of Week UUID value + */ +#define BT_UUID_GATT_DW_VAL 0x2a09 +/** + * @brief GATT Characteristic Day of Week + */ +#define BT_UUID_GATT_DW \ + BT_UUID_DECLARE_16(BT_UUID_GATT_DW_VAL) +/** + * @brief GATT Characteristic Day Date Time UUID value + */ +#define BT_UUID_GATT_DDT_VAL 0x2a0a +/** + * @brief GATT Characteristic Day Date Time + */ +#define BT_UUID_GATT_DDT \ + BT_UUID_DECLARE_16(BT_UUID_GATT_DDT_VAL) +/** + * @brief GATT Characteristic Exact Time 256 UUID value + */ +#define BT_UUID_GATT_ET256_VAL 0x2a0c +/** + * @brief GATT Characteristic Exact Time 256 + */ +#define BT_UUID_GATT_ET256 \ + BT_UUID_DECLARE_16(BT_UUID_GATT_ET256_VAL) +/** + * @brief GATT Characteristic DST Offset UUID value + */ +#define BT_UUID_GATT_DST_VAL 0x2a0d +/** + * @brief GATT Characteristic DST Offset + */ +#define BT_UUID_GATT_DST \ + BT_UUID_DECLARE_16(BT_UUID_GATT_DST_VAL) +/** + * @brief GATT Characteristic Time Zone UUID value + */ +#define BT_UUID_GATT_TZ_VAL 0x2a0e +/** + * @brief GATT Characteristic Time Zone + */ +#define BT_UUID_GATT_TZ \ + BT_UUID_DECLARE_16(BT_UUID_GATT_TZ_VAL) +/** + * @brief GATT Characteristic Local Time Information UUID value + */ +#define BT_UUID_GATT_LTI_VAL 0x2a0f +/** + * @brief GATT Characteristic Local Time Information + */ +#define BT_UUID_GATT_LTI \ + BT_UUID_DECLARE_16(BT_UUID_GATT_LTI_VAL) +/** + * @brief GATT Characteristic Time with DST UUID value + */ +#define BT_UUID_GATT_TDST_VAL 0x2a11 +/** + * @brief GATT Characteristic Time with DST + */ +#define BT_UUID_GATT_TDST \ + BT_UUID_DECLARE_16(BT_UUID_GATT_TDST_VAL) +/** + * @brief GATT Characteristic Time Accuracy UUID value + */ +#define BT_UUID_GATT_TA_VAL 0x2a12 +/** + * @brief GATT Characteristic Time Accuracy + */ +#define BT_UUID_GATT_TA \ + BT_UUID_DECLARE_16(BT_UUID_GATT_TA_VAL) +/** + * @brief GATT Characteristic Time Source UUID value + */ +#define BT_UUID_GATT_TS_VAL 0x2a13 +/** + * @brief GATT Characteristic Time Source + */ +#define BT_UUID_GATT_TS \ + BT_UUID_DECLARE_16(BT_UUID_GATT_TS_VAL) +/** + * @brief GATT Characteristic Reference Time Information UUID value + */ +#define BT_UUID_GATT_RTI_VAL 0x2a14 +/** + * @brief GATT Characteristic Reference Time Information + */ +#define BT_UUID_GATT_RTI \ + BT_UUID_DECLARE_16(BT_UUID_GATT_RTI_VAL) +/** + * @brief GATT Characteristic Time Update Control Point UUID value + */ +#define BT_UUID_GATT_TUCP_VAL 0x2a16 +/** + * @brief GATT Characteristic Time Update Control Point + */ +#define BT_UUID_GATT_TUCP \ + BT_UUID_DECLARE_16(BT_UUID_GATT_TUCP_VAL) +/** + * @brief GATT Characteristic Time Update State UUID value + */ +#define BT_UUID_GATT_TUS_VAL 0x2a17 +/** + * @brief GATT Characteristic Time Update State + */ +#define BT_UUID_GATT_TUS \ + BT_UUID_DECLARE_16(BT_UUID_GATT_TUS_VAL) +/** + * @brief GATT Characteristic Glucose Measurement UUID value + */ +#define BT_UUID_GATT_GM_VAL 0x2a18 +/** + * @brief GATT Characteristic Glucose Measurement + */ +#define BT_UUID_GATT_GM \ + BT_UUID_DECLARE_16(BT_UUID_GATT_GM_VAL) +/** + * @brief BAS Characteristic Battery Level UUID value + */ +#define BT_UUID_BAS_BATTERY_LEVEL_VAL 0x2a19 +/** + * @brief BAS Characteristic Battery Level + */ +#define BT_UUID_BAS_BATTERY_LEVEL \ + BT_UUID_DECLARE_16(BT_UUID_BAS_BATTERY_LEVEL_VAL) +/** + * @brief BAS Characteristic Battery Power State UUID value + */ +#define BT_UUID_BAS_BATTERY_POWER_STATE_VAL 0x2a1a +/** + * @brief BAS Characteristic Battery Power State + */ +#define BT_UUID_BAS_BATTERY_POWER_STATE \ + BT_UUID_DECLARE_16(BT_UUID_BAS_BATTERY_POWER_STATE_VAL) +/** + * @brief BAS Characteristic Battery Level StateUUID value + */ +#define BT_UUID_BAS_BATTERY_LEVEL_STATE_VAL 0x2a1b +/** + * @brief BAS Characteristic Battery Level State + */ +#define BT_UUID_BAS_BATTERY_LEVEL_STATE \ + BT_UUID_DECLARE_16(BT_UUID_BAS_BATTERY_LEVEL_STATE_VAL) +/** + * @brief HTS Characteristic Temperature Measurement UUID value + */ +#define BT_UUID_HTS_MEASUREMENT_VAL 0x2a1c +/** + * @brief HTS Characteristic Temperature Measurement Value + */ +#define BT_UUID_HTS_MEASUREMENT \ + BT_UUID_DECLARE_16(BT_UUID_HTS_MEASUREMENT_VAL) +/** + * @brief HTS Characteristic Temperature Type UUID value + */ +#define BT_UUID_HTS_TEMP_TYP_VAL 0x2a1d +/** + * @brief HTS Characteristic Temperature Type + */ +#define BT_UUID_HTS_TEMP_TYP \ + BT_UUID_DECLARE_16(BT_UUID_HTS_TEMP_TYP_VAL) +/** + * @brief HTS Characteristic Intermediate Temperature UUID value + */ +#define BT_UUID_HTS_TEMP_INT_VAL 0x2a1e +/** + * @brief HTS Characteristic Intermediate Temperature + */ +#define BT_UUID_HTS_TEMP_INT \ + BT_UUID_DECLARE_16(BT_UUID_HTS_TEMP_INT_VAL) +/** + * @brief HTS Characteristic Temperature Celsius UUID value + */ +#define BT_UUID_HTS_TEMP_C_VAL 0x2a1f +/** + * @brief HTS Characteristic Temperature Celsius + */ +#define BT_UUID_HTS_TEMP_C \ + BT_UUID_DECLARE_16(BT_UUID_HTS_TEMP_C_VAL) +/** + * @brief HTS Characteristic Temperature Fahrenheit UUID value + */ +#define BT_UUID_HTS_TEMP_F_VAL 0x2a20 +/** + * @brief HTS Characteristic Temperature Fahrenheit + */ +#define BT_UUID_HTS_TEMP_F \ + BT_UUID_DECLARE_16(BT_UUID_HTS_TEMP_F_VAL) +/** + * @brief HTS Characteristic Measurement Interval UUID value + */ +#define BT_UUID_HTS_INTERVAL_VAL 0x2a21 +/** + * @brief HTS Characteristic Measurement Interval + */ +#define BT_UUID_HTS_INTERVAL \ + BT_UUID_DECLARE_16(BT_UUID_HTS_INTERVAL_VAL) +/** + * @brief HID Characteristic Boot Keyboard Input Report UUID value + */ +#define BT_UUID_HIDS_BOOT_KB_IN_REPORT_VAL 0x2a22 +/** + * @brief HID Characteristic Boot Keyboard Input Report + */ +#define BT_UUID_HIDS_BOOT_KB_IN_REPORT \ + BT_UUID_DECLARE_16(BT_UUID_HIDS_BOOT_KB_IN_REPORT_VAL) +/** + * @brief DIS Characteristic System ID UUID value + */ +#define BT_UUID_DIS_SYSTEM_ID_VAL 0x2a23 +/** + * @brief DIS Characteristic System ID + */ +#define BT_UUID_DIS_SYSTEM_ID \ + BT_UUID_DECLARE_16(BT_UUID_DIS_SYSTEM_ID_VAL) +/** + * @brief DIS Characteristic Model Number String UUID value + */ +#define BT_UUID_DIS_MODEL_NUMBER_VAL 0x2a24 +/** + * @brief DIS Characteristic Model Number String + */ +#define BT_UUID_DIS_MODEL_NUMBER \ + BT_UUID_DECLARE_16(BT_UUID_DIS_MODEL_NUMBER_VAL) +/** + * @brief DIS Characteristic Serial Number String UUID value + */ +#define BT_UUID_DIS_SERIAL_NUMBER_VAL 0x2a25 +/** + * @brief DIS Characteristic Serial Number String + */ +#define BT_UUID_DIS_SERIAL_NUMBER \ + BT_UUID_DECLARE_16(BT_UUID_DIS_SERIAL_NUMBER_VAL) +/** + * @brief DIS Characteristic Firmware Revision String UUID value + */ +#define BT_UUID_DIS_FIRMWARE_REVISION_VAL 0x2a26 +/** + * @brief DIS Characteristic Firmware Revision String + */ +#define BT_UUID_DIS_FIRMWARE_REVISION \ + BT_UUID_DECLARE_16(BT_UUID_DIS_FIRMWARE_REVISION_VAL) +/** + * @brief DIS Characteristic Hardware Revision String UUID value + */ +#define BT_UUID_DIS_HARDWARE_REVISION_VAL 0x2a27 +/** + * @brief DIS Characteristic Hardware Revision String + */ +#define BT_UUID_DIS_HARDWARE_REVISION \ + BT_UUID_DECLARE_16(BT_UUID_DIS_HARDWARE_REVISION_VAL) +/** + * @brief DIS Characteristic Software Revision String UUID value + */ +#define BT_UUID_DIS_SOFTWARE_REVISION_VAL 0x2a28 +/** + * @brief DIS Characteristic Software Revision String + */ +#define BT_UUID_DIS_SOFTWARE_REVISION \ + BT_UUID_DECLARE_16(BT_UUID_DIS_SOFTWARE_REVISION_VAL) +/** + * @brief DIS Characteristic Manufacturer Name String UUID Value + */ +#define BT_UUID_DIS_MANUFACTURER_NAME_VAL 0x2a29 +/** + * @brief DIS Characteristic Manufacturer Name String + */ +#define BT_UUID_DIS_MANUFACTURER_NAME \ + BT_UUID_DECLARE_16(BT_UUID_DIS_MANUFACTURER_NAME_VAL) +/** + * @brief GATT Characteristic IEEE Regulatory Certification Data List UUID Value + */ +#define BT_UUID_GATT_IEEE_RCDL_VAL 0x2a2a +/** + * @brief GATT Characteristic IEEE Regulatory Certification Data List + */ +#define BT_UUID_GATT_IEEE_RCDL \ + BT_UUID_DECLARE_16(BT_UUID_GATT_IEEE_RCDL_VAL) +/** + * @brief CTS Characteristic Current Time UUID value + */ +#define BT_UUID_CTS_CURRENT_TIME_VAL 0x2a2b +/** + * @brief CTS Characteristic Current Time + */ +#define BT_UUID_CTS_CURRENT_TIME \ + BT_UUID_DECLARE_16(BT_UUID_CTS_CURRENT_TIME_VAL) +/** + * @brief Magnetic Declination Characteristic UUID value + */ +#define BT_UUID_MAGN_DECLINATION_VAL 0x2a2c +/** + * @brief Magnetic Declination Characteristic + */ +#define BT_UUID_MAGN_DECLINATION \ + BT_UUID_DECLARE_16(BT_UUID_MAGN_DECLINATION_VAL) +/** + * @brief GATT Characteristic Legacy Latitude UUID Value + */ +#define BT_UUID_GATT_LLAT_VAL 0x2a2d +/** + * @brief GATT Characteristic Legacy Latitude + */ +#define BT_UUID_GATT_LLAT \ + BT_UUID_DECLARE_16(BT_UUID_GATT_LLAT_VAL) +/** + * @brief GATT Characteristic Legacy Longitude UUID Value + */ +#define BT_UUID_GATT_LLON_VAL 0x2a2e +/** + * @brief GATT Characteristic Legacy Longitude + */ +#define BT_UUID_GATT_LLON \ + BT_UUID_DECLARE_16(BT_UUID_GATT_LLON_VAL) +/** + * @brief GATT Characteristic Position 2D UUID Value + */ +#define BT_UUID_GATT_POS_2D_VAL 0x2a2f +/** + * @brief GATT Characteristic Position 2D + */ +#define BT_UUID_GATT_POS_2D \ + BT_UUID_DECLARE_16(BT_UUID_GATT_POS_2D_VAL) +/** + * @brief GATT Characteristic Position 3D UUID Value + */ +#define BT_UUID_GATT_POS_3D_VAL 0x2a30 +/** + * @brief GATT Characteristic Position 3D + */ +#define BT_UUID_GATT_POS_3D \ + BT_UUID_DECLARE_16(BT_UUID_GATT_POS_3D_VAL) +/** + * @brief GATT Characteristic Scan Refresh UUID Value + */ +#define BT_UUID_GATT_SR_VAL 0x2a31 +/** + * @brief GATT Characteristic Scan Refresh + */ +#define BT_UUID_GATT_SR \ + BT_UUID_DECLARE_16(BT_UUID_GATT_SR_VAL) +/** + * @brief HID Boot Keyboard Output Report Characteristic UUID value + */ +#define BT_UUID_HIDS_BOOT_KB_OUT_REPORT_VAL 0x2a32 +/** + * @brief HID Boot Keyboard Output Report Characteristic + */ +#define BT_UUID_HIDS_BOOT_KB_OUT_REPORT \ + BT_UUID_DECLARE_16(BT_UUID_HIDS_BOOT_KB_OUT_REPORT_VAL) +/** + * @brief HID Boot Mouse Input Report Characteristic UUID value + */ +#define BT_UUID_HIDS_BOOT_MOUSE_IN_REPORT_VAL 0x2a33 +/** + * @brief HID Boot Mouse Input Report Characteristic + */ +#define BT_UUID_HIDS_BOOT_MOUSE_IN_REPORT \ + BT_UUID_DECLARE_16(BT_UUID_HIDS_BOOT_MOUSE_IN_REPORT_VAL) +/** + * @brief GATT Characteristic Glucose Measurement Context UUID Value + */ +#define BT_UUID_GATT_GMC_VAL 0x2a34 +/** + * @brief GATT Characteristic Glucose Measurement Context + */ +#define BT_UUID_GATT_GMC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_GMC_VAL) +/** + * @brief GATT Characteristic Blood Pressure Measurement UUID Value + */ +#define BT_UUID_GATT_BPM_VAL 0x2a35 +/** + * @brief GATT Characteristic Blood Pressure Measurement + */ +#define BT_UUID_GATT_BPM \ + BT_UUID_DECLARE_16(BT_UUID_GATT_BPM_VAL) +/** + * @brief GATT Characteristic Intermediate Cuff Pressure UUID Value + */ +#define BT_UUID_GATT_ICP_VAL 0x2a36 +/** + * @brief GATT Characteristic Intermediate Cuff Pressure + */ +#define BT_UUID_GATT_ICP \ + BT_UUID_DECLARE_16(BT_UUID_GATT_ICP_VAL) +/** + * @brief HRS Characteristic Measurement Interval UUID value + */ +#define BT_UUID_HRS_MEASUREMENT_VAL 0x2a37 +/** + * @brief HRS Characteristic Measurement Interval + */ +#define BT_UUID_HRS_MEASUREMENT \ + BT_UUID_DECLARE_16(BT_UUID_HRS_MEASUREMENT_VAL) +/** + * @brief HRS Characteristic Body Sensor Location + */ +#define BT_UUID_HRS_BODY_SENSOR_VAL 0x2a38 +/** + * @brief HRS Characteristic Control Point + */ +#define BT_UUID_HRS_BODY_SENSOR \ + BT_UUID_DECLARE_16(BT_UUID_HRS_BODY_SENSOR_VAL) +/** + * @brief HRS Characteristic Control Point UUID value + */ +#define BT_UUID_HRS_CONTROL_POINT_VAL 0x2a39 +/** + * @brief HRS Characteristic Control Point + */ +#define BT_UUID_HRS_CONTROL_POINT \ + BT_UUID_DECLARE_16(BT_UUID_HRS_CONTROL_POINT_VAL) +/** + * @brief GATT Characteristic Removable UUID Value + */ +#define BT_UUID_GATT_REM_VAL 0x2a3a +/** + * @brief GATT Characteristic Removable + */ +#define BT_UUID_GATT_REM \ + BT_UUID_DECLARE_16(BT_UUID_GATT_REM_VAL) +/** + * @brief GATT Characteristic Service Required UUID Value + */ +#define BT_UUID_GATT_SRVREQ_VAL 0x2a3b +/** + * @brief GATT Characteristic Service Required + */ +#define BT_UUID_GATT_SRVREQ \ + BT_UUID_DECLARE_16(BT_UUID_GATT_SRVREQ_VAL) +/** + * @brief GATT Characteristic Scientific Temperature in Celsius UUID Value + */ +#define BT_UUID_GATT_SC_TEMP_C_VAL 0x2a3c +/** + * @brief GATT Characteristic Scientific Temperature in Celsius + */ +#define BT_UUID_GATT_SC_TEMP_C \ + BT_UUID_DECLARE_16(BT_UUID_GATT_SC_TEMP_C_VAL) +/** + * @brief GATT Characteristic String UUID Value + */ +#define BT_UUID_GATT_STRING_VAL 0x2a3d +/** + * @brief GATT Characteristic String + */ +#define BT_UUID_GATT_STRING \ + BT_UUID_DECLARE_16(BT_UUID_GATT_STRING_VAL) +/** + * @brief GATT Characteristic Network Availability UUID Value + */ +#define BT_UUID_GATT_NETA_VAL 0x2a3e +/** + * @brief GATT Characteristic Network Availability + */ +#define BT_UUID_GATT_NETA \ + BT_UUID_DECLARE_16(BT_UUID_GATT_NETA_VAL) +/** + * @brief GATT Characteristic Alert Status UUID Value + */ +#define BT_UUID_GATT_ALRTS_VAL 0x2a3f +/** + * @brief GATT Characteristic Alert Status + */ +#define BT_UUID_GATT_ALRTS \ + BT_UUID_DECLARE_16(BT_UUID_GATT_ALRTS_VAL) +/** + * @brief GATT Characteristic Ringer Control Point UUID Value + */ +#define BT_UUID_GATT_RCP_VAL 0x2a40 +/** + * @brief GATT Characteristic Ringer Control Point + */ +#define BT_UUID_GATT_RCP \ + BT_UUID_DECLARE_16(BT_UUID_GATT_RCP_VAL) +/** + * @brief GATT Characteristic Ringer Setting UUID Value + */ +#define BT_UUID_GATT_RS_VAL 0x2a41 +/** + * @brief GATT Characteristic Ringer Setting + */ +#define BT_UUID_GATT_RS \ + BT_UUID_DECLARE_16(BT_UUID_GATT_RS_VAL) +/** + * @brief GATT Characteristic Alert Category ID Bit Mask UUID Value + */ +#define BT_UUID_GATT_ALRTCID_MASK_VAL 0x2a42 +/** + * @brief GATT Characteristic Alert Category ID Bit Mask + */ +#define BT_UUID_GATT_ALRTCID_MASK \ + BT_UUID_DECLARE_16(BT_UUID_GATT_ALRTCID_MASK_VAL) +/** + * @brief GATT Characteristic Alert Category ID UUID Value + */ +#define BT_UUID_GATT_ALRTCID_VAL 0x2a43 +/** + * @brief GATT Characteristic Alert Category ID + */ +#define BT_UUID_GATT_ALRTCID \ + BT_UUID_DECLARE_16(BT_UUID_GATT_ALRTCID_VAL) +/** + * @brief GATT Characteristic Alert Notification Control Point Value + */ +#define BT_UUID_GATT_ALRTNCP_VAL 0x2a44 +/** + * @brief GATT Characteristic Alert Notification Control Point + */ +#define BT_UUID_GATT_ALRTNCP \ + BT_UUID_DECLARE_16(BT_UUID_GATT_ALRTNCP_VAL) +/** + * @brief GATT Characteristic Unread Alert Status UUID Value + */ +#define BT_UUID_GATT_UALRTS_VAL 0x2a45 +/** + * @brief GATT Characteristic Unread Alert Status + */ +#define BT_UUID_GATT_UALRTS \ + BT_UUID_DECLARE_16(BT_UUID_GATT_UALRTS_VAL) +/** + * @brief GATT Characteristic New Alert UUID Value + */ +#define BT_UUID_GATT_NALRT_VAL 0x2a46 +/** + * @brief GATT Characteristic New Alert + */ +#define BT_UUID_GATT_NALRT \ + BT_UUID_DECLARE_16(BT_UUID_GATT_NALRT_VAL) +/** + * @brief GATT Characteristic Supported New Alert Category UUID Value + */ +#define BT_UUID_GATT_SNALRTC_VAL 0x2a47 +/** + * @brief GATT Characteristic Supported New Alert Category + */ +#define BT_UUID_GATT_SNALRTC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_SNALRTC_VAL) +/** + * @brief GATT Characteristic Supported Unread Alert Category UUID Value + */ +#define BT_UUID_GATT_SUALRTC_VAL 0x2a48 +/** + * @brief GATT Characteristic Supported Unread Alert Category + */ +#define BT_UUID_GATT_SUALRTC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_SUALRTC_VAL) +/** + * @brief GATT Characteristic Blood Pressure Feature UUID Value + */ +#define BT_UUID_GATT_BPF_VAL 0x2a49 +/** + * @brief GATT Characteristic Blood Pressure Feature + */ +#define BT_UUID_GATT_BPF \ + BT_UUID_DECLARE_16(BT_UUID_GATT_BPF_VAL) +/** + * @brief HID Information Characteristic UUID value + */ +#define BT_UUID_HIDS_INFO_VAL 0x2a4a +/** + * @brief HID Information Characteristic + */ +#define BT_UUID_HIDS_INFO \ + BT_UUID_DECLARE_16(BT_UUID_HIDS_INFO_VAL) +/** + * @brief HID Report Map Characteristic UUID value + */ +#define BT_UUID_HIDS_REPORT_MAP_VAL 0x2a4b +/** + * @brief HID Report Map Characteristic + */ +#define BT_UUID_HIDS_REPORT_MAP \ + BT_UUID_DECLARE_16(BT_UUID_HIDS_REPORT_MAP_VAL) +/** + * @brief HID Control Point Characteristic UUID value + */ +#define BT_UUID_HIDS_CTRL_POINT_VAL 0x2a4c +/** + * @brief HID Control Point Characteristic + */ +#define BT_UUID_HIDS_CTRL_POINT \ + BT_UUID_DECLARE_16(BT_UUID_HIDS_CTRL_POINT_VAL) +/** + * @brief HID Report Characteristic UUID value + */ +#define BT_UUID_HIDS_REPORT_VAL 0x2a4d +/** + * @brief HID Report Characteristic + */ +#define BT_UUID_HIDS_REPORT \ + BT_UUID_DECLARE_16(BT_UUID_HIDS_REPORT_VAL) +/** + * @brief HID Protocol Mode Characteristic UUID value + */ +#define BT_UUID_HIDS_PROTOCOL_MODE_VAL 0x2a4e +/** + * @brief HID Protocol Mode Characteristic + */ +#define BT_UUID_HIDS_PROTOCOL_MODE \ + BT_UUID_DECLARE_16(BT_UUID_HIDS_PROTOCOL_MODE_VAL) +/** + * @brief GATT Characteristic Scan Interval Windows UUID Value + */ +#define BT_UUID_GATT_SIW_VAL 0x2a4f +/** + * @brief GATT Characteristic Scan Interval Windows + */ +#define BT_UUID_GATT_SIW \ + BT_UUID_DECLARE_16(BT_UUID_GATT_SIW_VAL) +/** + * @brief DIS Characteristic PnP ID UUID value + */ +#define BT_UUID_DIS_PNP_ID_VAL 0x2a50 +/** + * @brief DIS Characteristic PnP ID + */ +#define BT_UUID_DIS_PNP_ID \ + BT_UUID_DECLARE_16(BT_UUID_DIS_PNP_ID_VAL) +/** + * @brief GATT Characteristic Glucose Feature UUID Value + */ +#define BT_UUID_GATT_GF_VAL 0x2a51 +/** + * @brief GATT Characteristic Glucose Feature + */ +#define BT_UUID_GATT_GF \ + BT_UUID_DECLARE_16(BT_UUID_GATT_GF_VAL) +/** + * @brief Record Access Control Point Characteristic value + */ +#define BT_UUID_RECORD_ACCESS_CONTROL_POINT_VAL 0x2a52 +/** + * @brief Record Access Control Point + */ +#define BT_UUID_RECORD_ACCESS_CONTROL_POINT \ + BT_UUID_DECLARE_16(BT_UUID_RECORD_ACCESS_CONTROL_POINT_VAL) +/** + * @brief RSC Measurement Characteristic UUID value + */ +#define BT_UUID_RSC_MEASUREMENT_VAL 0x2a53 +/** + * @brief RSC Measurement Characteristic + */ +#define BT_UUID_RSC_MEASUREMENT \ + BT_UUID_DECLARE_16(BT_UUID_RSC_MEASUREMENT_VAL) +/** + * @brief RSC Feature Characteristic UUID value + */ +#define BT_UUID_RSC_FEATURE_VAL 0x2a54 +/** + * @brief RSC Feature Characteristic + */ +#define BT_UUID_RSC_FEATURE \ + BT_UUID_DECLARE_16(BT_UUID_RSC_FEATURE_VAL) +/** + * @brief SC Control Point Characteristic UUID value + */ +#define BT_UUID_SC_CONTROL_POINT_VAL 0x2a55 +/** + * @brief SC Control Point Characteristic + */ +#define BT_UUID_SC_CONTROL_POINT \ + BT_UUID_DECLARE_16(BT_UUID_SC_CONTROL_POINT_VAL) +/** + * @brief GATT Characteristic Digital Input UUID Value + */ +#define BT_UUID_GATT_DI_VAL 0x2a56 +/** + * @brief GATT Characteristic Digital Input + */ +#define BT_UUID_GATT_DI \ + BT_UUID_DECLARE_16(BT_UUID_GATT_DI_VAL) +/** + * @brief GATT Characteristic Digital Output UUID Value + */ +#define BT_UUID_GATT_DO_VAL 0x2a57 +/** + * @brief GATT Characteristic Digital Output + */ +#define BT_UUID_GATT_DO \ + BT_UUID_DECLARE_16(BT_UUID_GATT_DO_VAL) +/** + * @brief GATT Characteristic Analog Input UUID Value + */ +#define BT_UUID_GATT_AI_VAL 0x2a58 +/** + * @brief GATT Characteristic Analog Input + */ +#define BT_UUID_GATT_AI \ + BT_UUID_DECLARE_16(BT_UUID_GATT_AI_VAL) +/** + * @brief GATT Characteristic Analog Output UUID Value + */ +#define BT_UUID_GATT_AO_VAL 0x2a59 +/** + * @brief GATT Characteristic Analog Output + */ +#define BT_UUID_GATT_AO \ + BT_UUID_DECLARE_16(BT_UUID_GATT_AO_VAL) +/** + * @brief GATT Characteristic Aggregate UUID Value + */ +#define BT_UUID_GATT_AGGR_VAL 0x2a5a +/** + * @brief GATT Characteristic Aggregate + */ +#define BT_UUID_GATT_AGGR \ + BT_UUID_DECLARE_16(BT_UUID_GATT_AGGR_VAL) +/** + * @brief CSC Measurement Characteristic UUID value + */ +#define BT_UUID_CSC_MEASUREMENT_VAL 0x2a5b +/** + * @brief CSC Measurement Characteristic + */ +#define BT_UUID_CSC_MEASUREMENT \ + BT_UUID_DECLARE_16(BT_UUID_CSC_MEASUREMENT_VAL) +/** + * @brief CSC Feature Characteristic UUID value + */ +#define BT_UUID_CSC_FEATURE_VAL 0x2a5c +/** + * @brief CSC Feature Characteristic + */ +#define BT_UUID_CSC_FEATURE \ + BT_UUID_DECLARE_16(BT_UUID_CSC_FEATURE_VAL) +/** + * @brief Sensor Location Characteristic UUID value + */ +#define BT_UUID_SENSOR_LOCATION_VAL 0x2a5d +/** + * @brief Sensor Location Characteristic + */ +#define BT_UUID_SENSOR_LOCATION \ + BT_UUID_DECLARE_16(BT_UUID_SENSOR_LOCATION_VAL) +/** + * @brief GATT Characteristic PLX Spot-Check Measurement UUID Value + */ +#define BT_UUID_GATT_PLX_SCM_VAL 0x2a5e +/** + * @brief GATT Characteristic PLX Spot-Check Measurement + */ +#define BT_UUID_GATT_PLX_SCM \ + BT_UUID_DECLARE_16(BT_UUID_GATT_PLX_SCM_VAL) +/** + * @brief GATT Characteristic PLX Continuous Measurement UUID Value + */ +#define BT_UUID_GATT_PLX_CM_VAL 0x2a5f +/** + * @brief GATT Characteristic PLX Continuous Measurement + */ +#define BT_UUID_GATT_PLX_CM \ + BT_UUID_DECLARE_16(BT_UUID_GATT_PLX_CM_VAL) +/** + * @brief GATT Characteristic PLX Features UUID Value + */ +#define BT_UUID_GATT_PLX_F_VAL 0x2a60 +/** + * @brief GATT Characteristic PLX Features + */ +#define BT_UUID_GATT_PLX_F \ + BT_UUID_DECLARE_16(BT_UUID_GATT_PLX_F_VAL) +/** + * @brief GATT Characteristic Pulse Oximetry Pulastile Event UUID Value + */ +#define BT_UUID_GATT_POPE_VAL 0x2a61 +/** + * @brief GATT Characteristic Pulse Oximetry Pulsatile Event + */ +#define BT_UUID_GATT_POPE \ + BT_UUID_DECLARE_16(BT_UUID_GATT_POPE_VAL) +/** + * @brief GATT Characteristic Pulse Oximetry Control Point UUID Value + */ +#define BT_UUID_GATT_POCP_VAL 0x2a62 +/** + * @brief GATT Characteristic Pulse Oximetry Control Point + */ +#define BT_UUID_GATT_POCP \ + BT_UUID_DECLARE_16(BT_UUID_GATT_POCP_VAL) +/** + * @brief GATT Characteristic Cycling Power Measurement UUID Value + */ +#define BT_UUID_GATT_CPS_CPM_VAL 0x2a63 +/** + * @brief GATT Characteristic Cycling Power Measurement + */ +#define BT_UUID_GATT_CPS_CPM \ + BT_UUID_DECLARE_16(BT_UUID_GATT_CPS_CPM_VAL) +/** + * @brief GATT Characteristic Cycling Power Vector UUID Value + */ +#define BT_UUID_GATT_CPS_CPV_VAL 0x2a64 +/** + * @brief GATT Characteristic Cycling Power Vector + */ +#define BT_UUID_GATT_CPS_CPV \ + BT_UUID_DECLARE_16(BT_UUID_GATT_CPS_CPV_VAL) +/** + * @brief GATT Characteristic Cycling Power Feature UUID Value + */ +#define BT_UUID_GATT_CPS_CPF_VAL 0x2a65 +/** + * @brief GATT Characteristic Cycling Power Feature + */ +#define BT_UUID_GATT_CPS_CPF \ + BT_UUID_DECLARE_16(BT_UUID_GATT_CPS_CPF_VAL) +/** + * @brief GATT Characteristic Cycling Power Control Point UUID Value + */ +#define BT_UUID_GATT_CPS_CPCP_VAL 0x2a66 +/** + * @brief GATT Characteristic Cycling Power Control Point + */ +#define BT_UUID_GATT_CPS_CPCP \ + BT_UUID_DECLARE_16(BT_UUID_GATT_CPS_CPCP_VAL) +/** + * @brief GATT Characteristic Location and Speed UUID Value + */ +#define BT_UUID_GATT_LOC_SPD_VAL 0x2a67 +/** + * @brief GATT Characteristic Location and Speed + */ +#define BT_UUID_GATT_LOC_SPD \ + BT_UUID_DECLARE_16(BT_UUID_GATT_LOC_SPD_VAL) +/** + * @brief GATT Characteristic Navigation UUID Value + */ +#define BT_UUID_GATT_NAV_VAL 0x2a68 +/** + * @brief GATT Characteristic Navigation + */ +#define BT_UUID_GATT_NAV \ + BT_UUID_DECLARE_16(BT_UUID_GATT_NAV_VAL) +/** + * @brief GATT Characteristic Position Quality UUID Value + */ +#define BT_UUID_GATT_PQ_VAL 0x2a69 +/** + * @brief GATT Characteristic Position Quality + */ +#define BT_UUID_GATT_PQ \ + BT_UUID_DECLARE_16(BT_UUID_GATT_PQ_VAL) +/** + * @brief GATT Characteristic LN Feature UUID Value + */ +#define BT_UUID_GATT_LNF_VAL 0x2a6a +/** + * @brief GATT Characteristic LN Feature + */ +#define BT_UUID_GATT_LNF \ + BT_UUID_DECLARE_16(BT_UUID_GATT_LNF_VAL) +/** + * @brief GATT Characteristic LN Control Point UUID Value + */ +#define BT_UUID_GATT_LNCP_VAL 0x2a6b +/** + * @brief GATT Characteristic LN Control Point + */ +#define BT_UUID_GATT_LNCP \ + BT_UUID_DECLARE_16(BT_UUID_GATT_LNCP_VAL) +/** + * @brief Elevation Characteristic UUID value + */ +#define BT_UUID_ELEVATION_VAL 0x2a6c +/** + * @brief Elevation Characteristic + */ +#define BT_UUID_ELEVATION \ + BT_UUID_DECLARE_16(BT_UUID_ELEVATION_VAL) +/** + * @brief Pressure Characteristic UUID value + */ +#define BT_UUID_PRESSURE_VAL 0x2a6d +/** + * @brief Pressure Characteristic + */ +#define BT_UUID_PRESSURE \ + BT_UUID_DECLARE_16(BT_UUID_PRESSURE_VAL) +/** + * @brief Temperature Characteristic UUID value + */ +#define BT_UUID_TEMPERATURE_VAL 0x2a6e +/** + * @brief Temperature Characteristic + */ +#define BT_UUID_TEMPERATURE \ + BT_UUID_DECLARE_16(BT_UUID_TEMPERATURE_VAL) +/** + * @brief Humidity Characteristic UUID value + */ +#define BT_UUID_HUMIDITY_VAL 0x2a6f +/** + * @brief Humidity Characteristic + */ +#define BT_UUID_HUMIDITY \ + BT_UUID_DECLARE_16(BT_UUID_HUMIDITY_VAL) +/** + * @brief True Wind Speed Characteristic UUID value + */ +#define BT_UUID_TRUE_WIND_SPEED_VAL 0x2a70 +/** + * @brief True Wind Speed Characteristic + */ +#define BT_UUID_TRUE_WIND_SPEED \ + BT_UUID_DECLARE_16(BT_UUID_TRUE_WIND_SPEED_VAL) +/** + * @brief True Wind Direction Characteristic UUID value + */ +#define BT_UUID_TRUE_WIND_DIR_VAL 0x2a71 +/** + * @brief True Wind Direction Characteristic + */ +#define BT_UUID_TRUE_WIND_DIR \ + BT_UUID_DECLARE_16(BT_UUID_TRUE_WIND_DIR_VAL) +/** + * @brief Apparent Wind Speed Characteristic UUID value + */ +#define BT_UUID_APPARENT_WIND_SPEED_VAL 0x2a72 +/** + * @brief Apparent Wind Speed Characteristic + */ +#define BT_UUID_APPARENT_WIND_SPEED \ + BT_UUID_DECLARE_16(BT_UUID_APPARENT_WIND_SPEED_VAL) +/** + * @brief Apparent Wind Direction Characteristic UUID value + */ +#define BT_UUID_APPARENT_WIND_DIR_VAL 0x2a73 +/** + * @brief Apparent Wind Direction Characteristic + */ +#define BT_UUID_APPARENT_WIND_DIR \ + BT_UUID_DECLARE_16(BT_UUID_APPARENT_WIND_DIR_VAL) +/** + * @brief Gust Factor Characteristic UUID value + */ +#define BT_UUID_GUST_FACTOR_VAL 0x2a74 +/** + * @brief Gust Factor Characteristic + */ +#define BT_UUID_GUST_FACTOR \ + BT_UUID_DECLARE_16(BT_UUID_GUST_FACTOR_VAL) +/** + * @brief Pollen Concentration Characteristic UUID value + */ +#define BT_UUID_POLLEN_CONCENTRATION_VAL 0x2a75 +/** + * @brief Pollen Concentration Characteristic + */ +#define BT_UUID_POLLEN_CONCENTRATION \ + BT_UUID_DECLARE_16(BT_UUID_POLLEN_CONCENTRATION_VAL) +/** + * @brief UV Index Characteristic UUID value + */ +#define BT_UUID_UV_INDEX_VAL 0x2a76 +/** + * @brief UV Index Characteristic + */ +#define BT_UUID_UV_INDEX \ + BT_UUID_DECLARE_16(BT_UUID_UV_INDEX_VAL) +/** + * @brief Irradiance Characteristic UUID value + */ +#define BT_UUID_IRRADIANCE_VAL 0x2a77 +/** + * @brief Irradiance Characteristic + */ +#define BT_UUID_IRRADIANCE \ + BT_UUID_DECLARE_16(BT_UUID_IRRADIANCE_VAL) +/** + * @brief Rainfall Characteristic UUID value + */ +#define BT_UUID_RAINFALL_VAL 0x2a78 +/** + * @brief Rainfall Characteristic + */ +#define BT_UUID_RAINFALL \ + BT_UUID_DECLARE_16(BT_UUID_RAINFALL_VAL) +/** + * @brief Wind Chill Characteristic UUID value + */ +#define BT_UUID_WIND_CHILL_VAL 0x2a79 +/** + * @brief Wind Chill Characteristic + */ +#define BT_UUID_WIND_CHILL \ + BT_UUID_DECLARE_16(BT_UUID_WIND_CHILL_VAL) +/** + * @brief Heat Index Characteristic UUID value + */ +#define BT_UUID_HEAT_INDEX_VAL 0x2a7a +/** + * @brief Heat Index Characteristic + */ +#define BT_UUID_HEAT_INDEX \ + BT_UUID_DECLARE_16(BT_UUID_HEAT_INDEX_VAL) +/** + * @brief Dew Point Characteristic UUID value + */ +#define BT_UUID_DEW_POINT_VAL 0x2a7b +/** + * @brief Dew Point Characteristic + */ +#define BT_UUID_DEW_POINT \ + BT_UUID_DECLARE_16(BT_UUID_DEW_POINT_VAL) +/** + * @brief GATT Characteristic Trend UUID Value + */ +#define BT_UUID_GATT_TREND_VAL 0x2a7c +/** + * @brief GATT Characteristic Trend + */ +#define BT_UUID_GATT_TREND \ + BT_UUID_DECLARE_16(BT_UUID_GATT_TREND_VAL) +/** + * @brief Descriptor Value Changed Characteristic UUID value + */ +#define BT_UUID_DESC_VALUE_CHANGED_VAL 0x2a7d +/** + * @brief Descriptor Value Changed Characteristic + */ +#define BT_UUID_DESC_VALUE_CHANGED \ + BT_UUID_DECLARE_16(BT_UUID_DESC_VALUE_CHANGED_VAL) +/** + * @brief GATT Characteristic Aerobic Heart Rate Low Limit UUID Value + */ +#define BT_UUID_GATT_AEHRLL_VAL 0x2a7e +/** + * @brief GATT Characteristic Aerobic Heart Rate Lower Limit + */ +#define BT_UUID_GATT_AEHRLL \ + BT_UUID_DECLARE_16(BT_UUID_GATT_AEHRLL_VAL) +/** + * @brief GATT Characteristic Aerobic Threshold UUID Value + */ +#define BT_UUID_GATT_AETHR_VAL 0x2a7f +/** + * @brief GATT Characteristic Aerobic Threshold + */ +#define BT_UUID_GATT_AETHR \ + BT_UUID_DECLARE_16(BT_UUID_GATT_AETHR_VAL) +/** + * @brief GATT Characteristic Age UUID Value + */ +#define BT_UUID_GATT_AGE_VAL 0x2a80 +/** + * @brief GATT Characteristic Age + */ +#define BT_UUID_GATT_AGE \ + BT_UUID_DECLARE_16(BT_UUID_GATT_AGE_VAL) +/** + * @brief GATT Characteristic Anaerobic Heart Rate Lower Limit UUID Value + */ +#define BT_UUID_GATT_ANHRLL_VAL 0x2a81 +/** + * @brief GATT Characteristic Anaerobic Heart Rate Lower Limit + */ +#define BT_UUID_GATT_ANHRLL \ + BT_UUID_DECLARE_16(BT_UUID_GATT_ANHRLL_VAL) +/** + * @brief GATT Characteristic Anaerobic Heart Rate Upper Limit UUID Value + */ +#define BT_UUID_GATT_ANHRUL_VAL 0x2a82 +/** + * @brief GATT Characteristic Anaerobic Heart Rate Upper Limit + */ +#define BT_UUID_GATT_ANHRUL \ + BT_UUID_DECLARE_16(BT_UUID_GATT_ANHRUL_VAL) +/** + * @brief GATT Characteristic Anaerobic Threshold UUID Value + */ +#define BT_UUID_GATT_ANTHR_VAL 0x2a83 +/** + * @brief GATT Characteristic Anaerobic Threshold + */ +#define BT_UUID_GATT_ANTHR \ + BT_UUID_DECLARE_16(BT_UUID_GATT_ANTHR_VAL) +/** + * @brief GATT Characteristic Aerobic Heart Rate Upper Limit UUID Value + */ +#define BT_UUID_GATT_AEHRUL_VAL 0x2a84 +/** + * @brief GATT Characteristic Aerobic Heart Rate Upper Limit + */ +#define BT_UUID_GATT_AEHRUL \ + BT_UUID_DECLARE_16(BT_UUID_GATT_AEHRUL_VAL) +/** + * @brief GATT Characteristic Date of Birth UUID Value + */ +#define BT_UUID_GATT_DATE_BIRTH_VAL 0x2a85 +/** + * @brief GATT Characteristic Date of Birth + */ +#define BT_UUID_GATT_DATE_BIRTH \ + BT_UUID_DECLARE_16(BT_UUID_GATT_DATE_BIRTH_VAL) +/** + * @brief GATT Characteristic Date of Threshold Assessment UUID Value + */ +#define BT_UUID_GATT_DATE_THRASS_VAL 0x2a86 +/** + * @brief GATT Characteristic Date of Threshold Assessment + */ +#define BT_UUID_GATT_DATE_THRASS \ + BT_UUID_DECLARE_16(BT_UUID_GATT_DATE_THRASS_VAL) +/** + * @brief GATT Characteristic Email Address UUID Value + */ +#define BT_UUID_GATT_EMAIL_VAL 0x2a87 +/** + * @brief GATT Characteristic Email Address + */ +#define BT_UUID_GATT_EMAIL \ + BT_UUID_DECLARE_16(BT_UUID_GATT_EMAIL_VAL) +/** + * @brief GATT Characteristic Fat Burn Heart Rate Lower Limit UUID Value + */ +#define BT_UUID_GATT_FBHRLL_VAL 0x2a88 +/** + * @brief GATT Characteristic Fat Burn Heart Rate Lower Limit + */ +#define BT_UUID_GATT_FBHRLL \ + BT_UUID_DECLARE_16(BT_UUID_GATT_FBHRLL_VAL) +/** + * @brief GATT Characteristic Fat Burn Heart Rate Upper Limit UUID Value + */ +#define BT_UUID_GATT_FBHRUL_VAL 0x2a89 +/** + * @brief GATT Characteristic Fat Burn Heart Rate Upper Limit + */ +#define BT_UUID_GATT_FBHRUL \ + BT_UUID_DECLARE_16(BT_UUID_GATT_FBHRUL_VAL) +/** + * @brief GATT Characteristic First Name UUID Value + */ +#define BT_UUID_GATT_FIRST_NAME_VAL 0x2a8a +/** + * @brief GATT Characteristic First Name + */ +#define BT_UUID_GATT_FIRST_NAME \ + BT_UUID_DECLARE_16(BT_UUID_GATT_FIRST_NAME_VAL) +/** + * @brief GATT Characteristic Five Zone Heart Rate Limits UUID Value + */ +#define BT_UUID_GATT_5ZHRL_VAL 0x2a8b +/** + * @brief GATT Characteristic Five Zone Heart Rate Limits + */ +#define BT_UUID_GATT_5ZHRL \ + BT_UUID_DECLARE_16(BT_UUID_GATT_5ZHRL_VAL) +/** + * @brief GATT Characteristic Gender UUID Value + */ +#define BT_UUID_GATT_GENDER_VAL 0x2a8c +/** + * @brief GATT Characteristic Gender + */ +#define BT_UUID_GATT_GENDER \ + BT_UUID_DECLARE_16(BT_UUID_GATT_GENDER_VAL) +/** + * @brief GATT Characteristic Heart Rate Max UUID Value + */ +#define BT_UUID_GATT_HR_MAX_VAL 0x2a8d +/** + * @brief GATT Characteristic Heart Rate Max + */ +#define BT_UUID_GATT_HR_MAX \ + BT_UUID_DECLARE_16(BT_UUID_GATT_HR_MAX_VAL) +/** + * @brief GATT Characteristic Height UUID Value + */ +#define BT_UUID_GATT_HEIGHT_VAL 0x2a8e +/** + * @brief GATT Characteristic Height + */ +#define BT_UUID_GATT_HEIGHT \ + BT_UUID_DECLARE_16(BT_UUID_GATT_HEIGHT_VAL) +/** + * @brief GATT Characteristic Hip Circumference UUID Value + */ +#define BT_UUID_GATT_HC_VAL 0x2a8f +/** + * @brief GATT Characteristic Hip Circumference + */ +#define BT_UUID_GATT_HC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_HC_VAL) +/** + * @brief GATT Characteristic Last Name UUID Value + */ +#define BT_UUID_GATT_LAST_NAME_VAL 0x2a90 +/** + * @brief GATT Characteristic Last Name + */ +#define BT_UUID_GATT_LAST_NAME \ + BT_UUID_DECLARE_16(BT_UUID_GATT_LAST_NAME_VAL) +/** + * @brief GATT Characteristic Maximum Recommended Heart Rate> UUID Value + */ +#define BT_UUID_GATT_MRHR_VAL 0x2a91 +/** + * @brief GATT Characteristic Maximum Recommended Heart Rate + */ +#define BT_UUID_GATT_MRHR \ + BT_UUID_DECLARE_16(BT_UUID_GATT_MRHR_VAL) +/** + * @brief GATT Characteristic Resting Heart Rate UUID Value + */ +#define BT_UUID_GATT_RHR_VAL 0x2a92 +/** + * @brief GATT Characteristic Resting Heart Rate + */ +#define BT_UUID_GATT_RHR \ + BT_UUID_DECLARE_16(BT_UUID_GATT_RHR_VAL) +/** + * @brief GATT Characteristic Sport Type for Aerobic and Anaerobic Thresholds UUID Value + */ +#define BT_UUID_GATT_AEANTHR_VAL 0x2a93 +/** + * @brief GATT Characteristic Sport Type for Aerobic and Anaerobic Threshold + */ +#define BT_UUID_GATT_AEANTHR \ + BT_UUID_DECLARE_16(BT_UUID_GATT_AEANTHR_VAL) +/** + * @brief GATT Characteristic Three Zone Heart Rate Limits UUID Value + */ +#define BT_UUID_GATT_3ZHRL_VAL 0x2a94 +/** + * @brief GATT Characteristic Three Zone Heart Rate Limits + */ +#define BT_UUID_GATT_3ZHRL \ + BT_UUID_DECLARE_16(BT_UUID_GATT_3ZHRL_VAL) +/** + * @brief GATT Characteristic Two Zone Heart Rate Limits UUID Value + */ +#define BT_UUID_GATT_2ZHRL_VAL 0x2a95 +/** + * @brief GATT Characteristic Two Zone Heart Rate Limits + */ +#define BT_UUID_GATT_2ZHRL \ + BT_UUID_DECLARE_16(BT_UUID_GATT_2ZHRL_VAL) +/** + * @brief GATT Characteristic VO2 Max UUID Value + */ +#define BT_UUID_GATT_VO2_MAX_VAL 0x2a96 +/** + * @brief GATT Characteristic VO2 Max + */ +#define BT_UUID_GATT_VO2_MAX \ + BT_UUID_DECLARE_16(BT_UUID_GATT_VO2_MAX_VAL) +/** + * @brief GATT Characteristic Waist Circumference UUID Value + */ +#define BT_UUID_GATT_WC_VAL 0x2a97 +/** + * @brief GATT Characteristic Waist Circumference + */ +#define BT_UUID_GATT_WC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_WC_VAL) +/** + * @brief GATT Characteristic Weight UUID Value + */ +#define BT_UUID_GATT_WEIGHT_VAL 0x2a98 +/** + * @brief GATT Characteristic Weight + */ +#define BT_UUID_GATT_WEIGHT \ + BT_UUID_DECLARE_16(BT_UUID_GATT_WEIGHT_VAL) +/** + * @brief GATT Characteristic Database Change Increment UUID Value + */ +#define BT_UUID_GATT_DBCHINC_VAL 0x2a99 +/** + * @brief GATT Characteristic Database Change Increment + */ +#define BT_UUID_GATT_DBCHINC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_DBCHINC_VAL) +/** + * @brief GATT Characteristic User Index UUID Value + */ +#define BT_UUID_GATT_USRIDX_VAL 0x2a9a +/** + * @brief GATT Characteristic User Index + */ +#define BT_UUID_GATT_USRIDX \ + BT_UUID_DECLARE_16(BT_UUID_GATT_USRIDX_VAL) +/** + * @brief GATT Characteristic Body Composition Feature UUID Value + */ +#define BT_UUID_GATT_BCF_VAL 0x2a9b +/** + * @brief GATT Characteristic Body Composition Feature + */ +#define BT_UUID_GATT_BCF \ + BT_UUID_DECLARE_16(BT_UUID_GATT_BCF_VAL) +/** + * @brief GATT Characteristic Body Composition Measurement UUID Value + */ +#define BT_UUID_GATT_BCM_VAL 0x2a9c +/** + * @brief GATT Characteristic Body Composition Measurement + */ +#define BT_UUID_GATT_BCM \ + BT_UUID_DECLARE_16(BT_UUID_GATT_BCM_VAL) +/** + * @brief GATT Characteristic Weight Measurement UUID Value + */ +#define BT_UUID_GATT_WM_VAL 0x2a9d +/** + * @brief GATT Characteristic Weight Measurement + */ +#define BT_UUID_GATT_WM \ + BT_UUID_DECLARE_16(BT_UUID_GATT_WM_VAL) +/** + * @brief GATT Characteristic Weight Scale Feature UUID Value + */ +#define BT_UUID_GATT_WSF_VAL 0x2a9e +/** + * @brief GATT Characteristic Weight Scale Feature + */ +#define BT_UUID_GATT_WSF \ + BT_UUID_DECLARE_16(BT_UUID_GATT_WSF_VAL) +/** + * @brief GATT Characteristic User Control Point UUID Value + */ +#define BT_UUID_GATT_USRCP_VAL 0x2a9f +/** + * @brief GATT Characteristic User Control Point + */ +#define BT_UUID_GATT_USRCP \ + BT_UUID_DECLARE_16(BT_UUID_GATT_USRCP_VAL) +/** + * @brief Magnetic Flux Density - 2D Characteristic UUID value + */ +#define BT_UUID_MAGN_FLUX_DENSITY_2D_VAL 0x2aa0 +/** + * @brief Magnetic Flux Density - 2D Characteristic + */ +#define BT_UUID_MAGN_FLUX_DENSITY_2D \ + BT_UUID_DECLARE_16(BT_UUID_MAGN_FLUX_DENSITY_2D_VAL) +/** + * @brief Magnetic Flux Density - 3D Characteristic UUID value + */ +#define BT_UUID_MAGN_FLUX_DENSITY_3D_VAL 0x2aa1 +/** + * @brief Magnetic Flux Density - 3D Characteristic + */ +#define BT_UUID_MAGN_FLUX_DENSITY_3D \ + BT_UUID_DECLARE_16(BT_UUID_MAGN_FLUX_DENSITY_3D_VAL) +/** + * @brief GATT Characteristic Language UUID Value + */ +#define BT_UUID_GATT_LANG_VAL 0x2aa2 +/** + * @brief GATT Characteristic Language + */ +#define BT_UUID_GATT_LANG \ + BT_UUID_DECLARE_16(BT_UUID_GATT_LANG_VAL) +/** + * @brief Barometric Pressure Trend Characteristic UUID value + */ +#define BT_UUID_BAR_PRESSURE_TREND_VAL 0x2aa3 +/** + * @brief Barometric Pressure Trend Characteristic + */ +#define BT_UUID_BAR_PRESSURE_TREND \ + BT_UUID_DECLARE_16(BT_UUID_BAR_PRESSURE_TREND_VAL) +/** + * @brief Bond Management Control Point UUID value + */ +#define BT_UUID_BMS_CONTROL_POINT_VAL 0x2aa4 +/** + * @brief Bond Management Control Point + */ +#define BT_UUID_BMS_CONTROL_POINT \ + BT_UUID_DECLARE_16(BT_UUID_BMS_CONTROL_POINT_VAL) +/** + * @brief Bond Management Feature UUID value + */ +#define BT_UUID_BMS_FEATURE_VAL 0x2aa5 +/** + * @brief Bond Management Feature + */ +#define BT_UUID_BMS_FEATURE \ + BT_UUID_DECLARE_16(BT_UUID_BMS_FEATURE_VAL) +/** + * @brief Central Address Resolution Characteristic UUID value + */ +#define BT_UUID_CENTRAL_ADDR_RES_VAL 0x2aa6 +/** + * @brief Central Address Resolution Characteristic + */ +#define BT_UUID_CENTRAL_ADDR_RES \ + BT_UUID_DECLARE_16(BT_UUID_CENTRAL_ADDR_RES_VAL) +/** + * @brief CGM Measurement Characteristic value + */ +#define BT_UUID_CGM_MEASUREMENT_VAL 0x2aa7 +/** + * @brief CGM Measurement Characteristic + */ +#define BT_UUID_CGM_MEASUREMENT \ + BT_UUID_DECLARE_16(BT_UUID_CGM_MEASUREMENT_VAL) +/** + * @brief CGM Feature Characteristic value + */ +#define BT_UUID_CGM_FEATURE_VAL 0x2aa8 +/** + * @brief CGM Feature Characteristic + */ +#define BT_UUID_CGM_FEATURE \ + BT_UUID_DECLARE_16(BT_UUID_CGM_FEATURE_VAL) +/** + * @brief CGM Status Characteristic value + */ +#define BT_UUID_CGM_STATUS_VAL 0x2aa9 +/** + * @brief CGM Status Characteristic + */ +#define BT_UUID_CGM_STATUS \ + BT_UUID_DECLARE_16(BT_UUID_CGM_STATUS_VAL) +/** + * @brief CGM Session Start Time Characteristic value + */ +#define BT_UUID_CGM_SESSION_START_TIME_VAL 0x2aaa +/** + * @brief CGM Session Start Time + */ +#define BT_UUID_CGM_SESSION_START_TIME \ + BT_UUID_DECLARE_16(BT_UUID_CGM_SESSION_START_TIME_VAL) +/** + * @brief CGM Session Run Time Characteristic value + */ +#define BT_UUID_CGM_SESSION_RUN_TIME_VAL 0x2aab +/** + * @brief CGM Session Run Time + */ +#define BT_UUID_CGM_SESSION_RUN_TIME \ + BT_UUID_DECLARE_16(BT_UUID_CGM_SESSION_RUN_TIME_VAL) +/** + * @brief CGM Specific Ops Control Point Characteristic value + */ +#define BT_UUID_CGM_SPECIFIC_OPS_CONTROL_POINT_VAL 0x2aac +/** + * @brief CGM Specific Ops Control Point + */ +#define BT_UUID_CGM_SPECIFIC_OPS_CONTROL_POINT \ + BT_UUID_DECLARE_16(BT_UUID_CGM_SPECIFIC_OPS_CONTROL_POINT_VAL) +/** + * @brief GATT Characteristic Indoor Positioning Configuration UUID Value + */ +#define BT_UUID_GATT_IPC_VAL 0x2aad +/** + * @brief GATT Characteristic Indoor Positioning Configuration + */ +#define BT_UUID_GATT_IPC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_IPC_VAL) +/** + * @brief GATT Characteristic Latitude UUID Value + */ +#define BT_UUID_GATT_LAT_VAL 0x2aae +/** + * @brief GATT Characteristic Latitude + */ +#define BT_UUID_GATT_LAT \ + BT_UUID_DECLARE_16(BT_UUID_GATT_LAT_VAL) +/** + * @brief GATT Characteristic Longitude UUID Value + */ +#define BT_UUID_GATT_LON_VAL 0x2aaf +/** + * @brief GATT Characteristic Longitude + */ +#define BT_UUID_GATT_LON \ + BT_UUID_DECLARE_16(BT_UUID_GATT_LON_VAL) +/** + * @brief GATT Characteristic Local North Coordinate UUID Value + */ +#define BT_UUID_GATT_LNCOORD_VAL 0x2ab0 +/** + * @brief GATT Characteristic Local North Coordinate + */ +#define BT_UUID_GATT_LNCOORD \ + BT_UUID_DECLARE_16(BT_UUID_GATT_LNCOORD_VAL) +/** + * @brief GATT Characteristic Local East Coordinate UUID Value + */ +#define BT_UUID_GATT_LECOORD_VAL 0x2ab1 +/** + * @brief GATT Characteristic Local East Coordinate + */ +#define BT_UUID_GATT_LECOORD \ + BT_UUID_DECLARE_16(BT_UUID_GATT_LECOORD_VAL) +/** + * @brief GATT Characteristic Floor Number UUID Value + */ +#define BT_UUID_GATT_FN_VAL 0x2ab2 +/** + * @brief GATT Characteristic Floor Number + */ +#define BT_UUID_GATT_FN \ + BT_UUID_DECLARE_16(BT_UUID_GATT_FN_VAL) +/** + * @brief GATT Characteristic Altitude UUID Value + */ +#define BT_UUID_GATT_ALT_VAL 0x2ab3 +/** + * @brief GATT Characteristic Altitude + */ +#define BT_UUID_GATT_ALT \ + BT_UUID_DECLARE_16(BT_UUID_GATT_ALT_VAL) +/** + * @brief GATT Characteristic Uncertainty UUID Value + */ +#define BT_UUID_GATT_UNCERTAINTY_VAL 0x2ab4 +/** + * @brief GATT Characteristic Uncertainty + */ +#define BT_UUID_GATT_UNCERTAINTY \ + BT_UUID_DECLARE_16(BT_UUID_GATT_UNCERTAINTY_VAL) +/** + * @brief GATT Characteristic Location Name UUID Value + */ +#define BT_UUID_GATT_LOC_NAME_VAL 0x2ab5 +/** + * @brief GATT Characteristic Location Name + */ +#define BT_UUID_GATT_LOC_NAME \ + BT_UUID_DECLARE_16(BT_UUID_GATT_LOC_NAME_VAL) +/** + * @brief URI UUID value + */ +#define BT_UUID_URI_VAL 0x2ab6 +/** + * @brief URI + */ +#define BT_UUID_URI \ + BT_UUID_DECLARE_16(BT_UUID_URI_VAL) +/** + * @brief HTTP Headers UUID value + */ +#define BT_UUID_HTTP_HEADERS_VAL 0x2ab7 +/** + * @brief HTTP Headers + */ +#define BT_UUID_HTTP_HEADERS \ + BT_UUID_DECLARE_16(BT_UUID_HTTP_HEADERS_VAL) +/** + * @brief HTTP Status Code UUID value + */ +#define BT_UUID_HTTP_STATUS_CODE_VAL 0x2ab8 +/** + * @brief HTTP Status Code + */ +#define BT_UUID_HTTP_STATUS_CODE \ + BT_UUID_DECLARE_16(BT_UUID_HTTP_STATUS_CODE_VAL) +/** + * @brief HTTP Entity Body UUID value + */ +#define BT_UUID_HTTP_ENTITY_BODY_VAL 0x2ab9 +/** + * @brief HTTP Entity Body + */ +#define BT_UUID_HTTP_ENTITY_BODY \ + BT_UUID_DECLARE_16(BT_UUID_HTTP_ENTITY_BODY_VAL) +/** + * @brief HTTP Control Point UUID value + */ +#define BT_UUID_HTTP_CONTROL_POINT_VAL 0x2aba +/** + * @brief HTTP Control Point + */ +#define BT_UUID_HTTP_CONTROL_POINT \ + BT_UUID_DECLARE_16(BT_UUID_HTTP_CONTROL_POINT_VAL) +/** + * @brief HTTPS Security UUID value + */ +#define BT_UUID_HTTPS_SECURITY_VAL 0x2abb +/** + * @brief HTTPS Security + */ +#define BT_UUID_HTTPS_SECURITY \ + BT_UUID_DECLARE_16(BT_UUID_HTTPS_SECURITY_VAL) +/** + * @brief GATT Characteristic TDS Control Point UUID Value + */ +#define BT_UUID_GATT_TDS_CP_VAL 0x2abc +/** + * @brief GATT Characteristic TDS Control Point + */ +#define BT_UUID_GATT_TDS_CP \ + BT_UUID_DECLARE_16(BT_UUID_GATT_TDS_CP_VAL) +/** + * @brief OTS Feature Characteristic UUID value + */ +#define BT_UUID_OTS_FEATURE_VAL 0x2abd +/** + * @brief OTS Feature Characteristic + */ +#define BT_UUID_OTS_FEATURE \ + BT_UUID_DECLARE_16(BT_UUID_OTS_FEATURE_VAL) +/** + * @brief OTS Object Name Characteristic UUID value + */ +#define BT_UUID_OTS_NAME_VAL 0x2abe +/** + * @brief OTS Object Name Characteristic + */ +#define BT_UUID_OTS_NAME \ + BT_UUID_DECLARE_16(BT_UUID_OTS_NAME_VAL) +/** + * @brief OTS Object Type Characteristic UUID value + */ +#define BT_UUID_OTS_TYPE_VAL 0x2abf +/** + * @brief OTS Object Type Characteristic + */ +#define BT_UUID_OTS_TYPE \ + BT_UUID_DECLARE_16(BT_UUID_OTS_TYPE_VAL) +/** + * @brief OTS Object Size Characteristic UUID value + */ +#define BT_UUID_OTS_SIZE_VAL 0x2ac0 +/** + * @brief OTS Object Size Characteristic + */ +#define BT_UUID_OTS_SIZE \ + BT_UUID_DECLARE_16(BT_UUID_OTS_SIZE_VAL) +/** + * @brief OTS Object First-Created Characteristic UUID value + */ +#define BT_UUID_OTS_FIRST_CREATED_VAL 0x2ac1 +/** + * @brief OTS Object First-Created Characteristic + */ +#define BT_UUID_OTS_FIRST_CREATED \ + BT_UUID_DECLARE_16(BT_UUID_OTS_FIRST_CREATED_VAL) +/** + * @brief OTS Object Last-Modified Characteristic UUI value + */ +#define BT_UUID_OTS_LAST_MODIFIED_VAL 0x2ac2 +/** + * @brief OTS Object Last-Modified Characteristic + */ +#define BT_UUID_OTS_LAST_MODIFIED \ + BT_UUID_DECLARE_16(BT_UUID_OTS_LAST_MODIFIED_VAL) +/** + * @brief OTS Object ID Characteristic UUID value + */ +#define BT_UUID_OTS_ID_VAL 0x2ac3 +/** + * @brief OTS Object ID Characteristic + */ +#define BT_UUID_OTS_ID \ + BT_UUID_DECLARE_16(BT_UUID_OTS_ID_VAL) +/** + * @brief OTS Object Properties Characteristic UUID value + */ +#define BT_UUID_OTS_PROPERTIES_VAL 0x2ac4 +/** + * @brief OTS Object Properties Characteristic + */ +#define BT_UUID_OTS_PROPERTIES \ + BT_UUID_DECLARE_16(BT_UUID_OTS_PROPERTIES_VAL) +/** + * @brief OTS Object Action Control Point Characteristic UUID value + */ +#define BT_UUID_OTS_ACTION_CP_VAL 0x2ac5 +/** + * @brief OTS Object Action Control Point Characteristic + */ +#define BT_UUID_OTS_ACTION_CP \ + BT_UUID_DECLARE_16(BT_UUID_OTS_ACTION_CP_VAL) +/** + * @brief OTS Object List Control Point Characteristic UUID value + */ +#define BT_UUID_OTS_LIST_CP_VAL 0x2ac6 +/** + * @brief OTS Object List Control Point Characteristic + */ +#define BT_UUID_OTS_LIST_CP \ + BT_UUID_DECLARE_16(BT_UUID_OTS_LIST_CP_VAL) +/** + * @brief OTS Object List Filter Characteristic UUID value + */ +#define BT_UUID_OTS_LIST_FILTER_VAL 0x2ac7 +/** + * @brief OTS Object List Filter Characteristic + */ +#define BT_UUID_OTS_LIST_FILTER \ + BT_UUID_DECLARE_16(BT_UUID_OTS_LIST_FILTER_VAL) +/** + * @brief OTS Object Changed Characteristic UUID value + */ +#define BT_UUID_OTS_CHANGED_VAL 0x2ac8 +/** + * @brief OTS Object Changed Characteristic + */ +#define BT_UUID_OTS_CHANGED \ + BT_UUID_DECLARE_16(BT_UUID_OTS_CHANGED_VAL) +/** + * @brief GATT Characteristic Resolvable Private Address Only UUID Value + */ +#define BT_UUID_GATT_RPAO_VAL 0x2ac9 +/** + * @brief GATT Characteristic Resolvable Private Address Only + */ +#define BT_UUID_GATT_RPAO \ + BT_UUID_DECLARE_16(BT_UUID_GATT_RPAO_VAL) +/** + * @brief OTS Unspecified Object Type UUID value + */ +#define BT_UUID_OTS_TYPE_UNSPECIFIED_VAL 0x2aca +/** + * @brief OTS Unspecified Object Type + */ +#define BT_UUID_OTS_TYPE_UNSPECIFIED \ + BT_UUID_DECLARE_16(BT_UUID_OTS_TYPE_UNSPECIFIED_VAL) +/** + * @brief OTS Directory Listing UUID value + */ +#define BT_UUID_OTS_DIRECTORY_LISTING_VAL 0x2acb +/** + * @brief OTS Directory Listing + */ +#define BT_UUID_OTS_DIRECTORY_LISTING \ + BT_UUID_DECLARE_16(BT_UUID_OTS_DIRECTORY_LISTING_VAL) +/** + * @brief GATT Characteristic Fitness Machine Feature UUID Value + */ +#define BT_UUID_GATT_FMF_VAL 0x2acc +/** + * @brief GATT Characteristic Fitness Machine Feature + */ +#define BT_UUID_GATT_FMF \ + BT_UUID_DECLARE_16(BT_UUID_GATT_FMF_VAL) +/** + * @brief GATT Characteristic Treadmill Data UUID Value + */ +#define BT_UUID_GATT_TD_VAL 0x2acd +/** + * @brief GATT Characteristic Treadmill Data + */ +#define BT_UUID_GATT_TD \ + BT_UUID_DECLARE_16(BT_UUID_GATT_TD_VAL) +/** + * @brief GATT Characteristic Cross Trainer Data UUID Value + */ +#define BT_UUID_GATT_CTD_VAL 0x2ace +/** + * @brief GATT Characteristic Cross Trainer Data + */ +#define BT_UUID_GATT_CTD \ + BT_UUID_DECLARE_16(BT_UUID_GATT_CTD_VAL) +/** + * @brief GATT Characteristic Step Climber Data UUID Value + */ +#define BT_UUID_GATT_STPCD_VAL 0x2acf +/** + * @brief GATT Characteristic Step Climber Data + */ +#define BT_UUID_GATT_STPCD \ + BT_UUID_DECLARE_16(BT_UUID_GATT_STPCD_VAL) +/** + * @brief GATT Characteristic Stair Climber Data UUID Value + */ +#define BT_UUID_GATT_STRCD_VAL 0x2ad0 +/** + * @brief GATT Characteristic Stair Climber Data + */ +#define BT_UUID_GATT_STRCD \ + BT_UUID_DECLARE_16(BT_UUID_GATT_STRCD_VAL) +/** + * @brief GATT Characteristic Rower Data UUID Value + */ +#define BT_UUID_GATT_RD_VAL 0x2ad1 +/** + * @brief GATT Characteristic Rower Data + */ +#define BT_UUID_GATT_RD \ + BT_UUID_DECLARE_16(BT_UUID_GATT_RD_VAL) +/** + * @brief GATT Characteristic Indoor Bike Data UUID Value + */ +#define BT_UUID_GATT_IBD_VAL 0x2ad2 +/** + * @brief GATT Characteristic Indoor Bike Data + */ +#define BT_UUID_GATT_IBD \ + BT_UUID_DECLARE_16(BT_UUID_GATT_IBD_VAL) +/** + * @brief GATT Characteristic Training Status UUID Value + */ +#define BT_UUID_GATT_TRSTAT_VAL 0x2ad3 +/** + * @brief GATT Characteristic Training Status + */ +#define BT_UUID_GATT_TRSTAT \ + BT_UUID_DECLARE_16(BT_UUID_GATT_TRSTAT_VAL) +/** + * @brief GATT Characteristic Supported Speed Range UUID Value + */ +#define BT_UUID_GATT_SSR_VAL 0x2ad4 +/** + * @brief GATT Characteristic Supported Speed Range + */ +#define BT_UUID_GATT_SSR \ + BT_UUID_DECLARE_16(BT_UUID_GATT_SSR_VAL) +/** + * @brief GATT Characteristic Supported Inclination Range UUID Value + */ +#define BT_UUID_GATT_SIR_VAL 0x2ad5 +/** + * @brief GATT Characteristic Supported Inclination Range + */ +#define BT_UUID_GATT_SIR \ + BT_UUID_DECLARE_16(BT_UUID_GATT_SIR_VAL) +/** + * @brief GATT Characteristic Supported Resistance Level Range UUID Value + */ +#define BT_UUID_GATT_SRLR_VAL 0x2ad6 +/** + * @brief GATT Characteristic Supported Resistance Level Range + */ +#define BT_UUID_GATT_SRLR \ + BT_UUID_DECLARE_16(BT_UUID_GATT_SRLR_VAL) +/** + * @brief GATT Characteristic Supported Heart Rate Range UUID Value + */ +#define BT_UUID_GATT_SHRR_VAL 0x2ad7 +/** + * @brief GATT Characteristic Supported Heart Rate Range + */ +#define BT_UUID_GATT_SHRR \ + BT_UUID_DECLARE_16(BT_UUID_GATT_SHRR_VAL) +/** + * @brief GATT Characteristic Supported Power Range UUID Value + */ +#define BT_UUID_GATT_SPR_VAL 0x2ad8 +/** + * @brief GATT Characteristic Supported Power Range + */ +#define BT_UUID_GATT_SPR \ + BT_UUID_DECLARE_16(BT_UUID_GATT_SPR_VAL) +/** + * @brief GATT Characteristic Fitness Machine Control Point UUID Value + */ +#define BT_UUID_GATT_FMCP_VAL 0x2ad9 +/** + * @brief GATT Characteristic Fitness Machine Control Point + */ +#define BT_UUID_GATT_FMCP \ + BT_UUID_DECLARE_16(BT_UUID_GATT_FMCP_VAL) +/** + * @brief GATT Characteristic Fitness Machine Status UUID Value + */ +#define BT_UUID_GATT_FMS_VAL 0x2ada +/** + * @brief GATT Characteristic Fitness Machine Status + */ +#define BT_UUID_GATT_FMS \ + BT_UUID_DECLARE_16(BT_UUID_GATT_FMS_VAL) +/** + * @brief Mesh Provisioning Data In UUID value + */ +#define BT_UUID_MESH_PROV_DATA_IN_VAL 0x2adb +/** + * @brief Mesh Provisioning Data In + */ +#define BT_UUID_MESH_PROV_DATA_IN \ + BT_UUID_DECLARE_16(BT_UUID_MESH_PROV_DATA_IN_VAL) +/** + * @brief Mesh Provisioning Data Out UUID value + */ +#define BT_UUID_MESH_PROV_DATA_OUT_VAL 0x2adc +/** + * @brief Mesh Provisioning Data Out + */ +#define BT_UUID_MESH_PROV_DATA_OUT \ + BT_UUID_DECLARE_16(BT_UUID_MESH_PROV_DATA_OUT_VAL) +/** + * @brief Mesh Proxy Data In UUID value + */ +#define BT_UUID_MESH_PROXY_DATA_IN_VAL 0x2add +/** + * @brief Mesh Proxy Data In + */ +#define BT_UUID_MESH_PROXY_DATA_IN \ + BT_UUID_DECLARE_16(BT_UUID_MESH_PROXY_DATA_IN_VAL) +/** + * @brief Mesh Proxy Data Out UUID value + */ +#define BT_UUID_MESH_PROXY_DATA_OUT_VAL 0x2ade +/** + * @brief Mesh Proxy Data Out + */ +#define BT_UUID_MESH_PROXY_DATA_OUT \ + BT_UUID_DECLARE_16(BT_UUID_MESH_PROXY_DATA_OUT_VAL) +/** + * @brief GATT Characteristic New Number Needed UUID Value + */ +#define BT_UUID_GATT_NNN_VAL 0x2adf +/** + * @brief GATT Characteristic New Number Needed + */ +#define BT_UUID_GATT_NNN \ + BT_UUID_DECLARE_16(BT_UUID_GATT_NNN_VAL) +/** + * @brief GATT Characteristic Average Current UUID Value + */ +#define BT_UUID_GATT_AC_VAL 0x2ae0 +/** + * @brief GATT Characteristic Average Current + */ +#define BT_UUID_GATT_AC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_AC_VAL) +/** + * @brief GATT Characteristic Average Voltage UUID Value + */ +#define BT_UUID_GATT_AV_VAL 0x2ae1 +/** + * @brief GATT Characteristic Average Voltage + */ +#define BT_UUID_GATT_AV \ + BT_UUID_DECLARE_16(BT_UUID_GATT_AV_VAL) +/** + * @brief GATT Characteristic Boolean UUID Value + */ +#define BT_UUID_GATT_BOOLEAN_VAL 0x2ae2 +/** + * @brief GATT Characteristic Boolean + */ +#define BT_UUID_GATT_BOOLEAN \ + BT_UUID_DECLARE_16(BT_UUID_GATT_BOOLEAN_VAL) +/** + * @brief GATT Characteristic Chromatic Distance From Planckian UUID Value + */ +#define BT_UUID_GATT_CRDFP_VAL 0x2ae3 +/** + * @brief GATT Characteristic Chromatic Distance From Planckian + */ +#define BT_UUID_GATT_CRDFP \ + BT_UUID_DECLARE_16(BT_UUID_GATT_CRDFP_VAL) +/** + * @brief GATT Characteristic Chromaticity Coordinates UUID Value + */ +#define BT_UUID_GATT_CRCOORDS_VAL 0x2ae4 +/** + * @brief GATT Characteristic Chromaticity Coordinates + */ +#define BT_UUID_GATT_CRCOORDS \ + BT_UUID_DECLARE_16(BT_UUID_GATT_CRCOORDS_VAL) +/** + * @brief GATT Characteristic Chromaticity In CCT And Duv Values UUID Value + */ +#define BT_UUID_GATT_CRCCT_VAL 0x2ae5 +/** + * @brief GATT Characteristic Chromaticity In CCT And Duv Values + */ +#define BT_UUID_GATT_CRCCT \ + BT_UUID_DECLARE_16(BT_UUID_GATT_CRCCT_VAL) +/** + * @brief GATT Characteristic Chromaticity Tolerance UUID Value + */ +#define BT_UUID_GATT_CRT_VAL 0x2ae6 +/** + * @brief GATT Characteristic Chromaticity Tolerance + */ +#define BT_UUID_GATT_CRT \ + BT_UUID_DECLARE_16(BT_UUID_GATT_CRT_VAL) +/** + * @brief GATT Characteristic CIE 13.3-1995 Color Rendering Index UUID Value + */ +#define BT_UUID_GATT_CIEIDX_VAL 0x2ae7 +/** + * @brief GATT Characteristic CIE 13.3-1995 Color Rendering Index + */ +#define BT_UUID_GATT_CIEIDX \ + BT_UUID_DECLARE_16(BT_UUID_GATT_CIEIDX_VAL) +/** + * @brief GATT Characteristic Coefficient UUID Value + */ +#define BT_UUID_GATT_COEFFICIENT_VAL 0x2ae8 +/** + * @brief GATT Characteristic Coefficient + */ +#define BT_UUID_GATT_COEFFICIENT \ + BT_UUID_DECLARE_16(BT_UUID_GATT_COEFFICIENT_VAL) +/** + * @brief GATT Characteristic Correlated Color Temperature UUID Value + */ +#define BT_UUID_GATT_CCTEMP_VAL 0x2ae9 +/** + * @brief GATT Characteristic Correlated Color Temperature + */ +#define BT_UUID_GATT_CCTEMP \ + BT_UUID_DECLARE_16(BT_UUID_GATT_CCTEMP_VAL) +/** + * @brief GATT Characteristic Count 16 UUID Value + */ +#define BT_UUID_GATT_COUNT16_VAL 0x2aea +/** + * @brief GATT Characteristic Count 16 + */ +#define BT_UUID_GATT_COUNT16 \ + BT_UUID_DECLARE_16(BT_UUID_GATT_COUNT16_VAL) +/** + * @brief GATT Characteristic Count 24 UUID Value + */ +#define BT_UUID_GATT_COUNT24_VAL 0x2aeb +/** + * @brief GATT Characteristic Count 24 + */ +#define BT_UUID_GATT_COUNT24 \ + BT_UUID_DECLARE_16(BT_UUID_GATT_COUNT24_VAL) +/** + * @brief GATT Characteristic Country Code UUID Value + */ +#define BT_UUID_GATT_CNTRCODE_VAL 0x2aec +/** + * @brief GATT Characteristic Country Code + */ +#define BT_UUID_GATT_CNTRCODE \ + BT_UUID_DECLARE_16(BT_UUID_GATT_CNTRCODE_VAL) +/** + * @brief GATT Characteristic Date UTC UUID Value + */ +#define BT_UUID_GATT_DATEUTC_VAL 0x2aed +/** + * @brief GATT Characteristic Date UTC + */ +#define BT_UUID_GATT_DATEUTC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_DATEUTC_VAL) +/** + * @brief GATT Characteristic Electric Current UUID Value + */ +#define BT_UUID_GATT_EC_VAL 0x2aee +/** + * @brief GATT Characteristic Electric Current + */ +#define BT_UUID_GATT_EC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_EC_VAL) +/** + * @brief GATT Characteristic Electric Current Range UUID Value + */ +#define BT_UUID_GATT_ECR_VAL 0x2aef +/** + * @brief GATT Characteristic Electric Current Range + */ +#define BT_UUID_GATT_ECR \ + BT_UUID_DECLARE_16(BT_UUID_GATT_ECR_VAL) +/** + * @brief GATT Characteristic Electric Current Specification UUID Value + */ +#define BT_UUID_GATT_ECSPEC_VAL 0x2af0 +/** + * @brief GATT Characteristic Electric Current Specification + */ +#define BT_UUID_GATT_ECSPEC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_ECSPEC_VAL) +/** + * @brief GATT Characteristic Electric Current Statistics UUID Value + */ +#define BT_UUID_GATT_ECSTAT_VAL 0x2af1 +/** + * @brief GATT Characteristic Electric Current Statistics + */ +#define BT_UUID_GATT_ECSTAT \ + BT_UUID_DECLARE_16(BT_UUID_GATT_ECSTAT_VAL) +/** + * @brief GATT Characteristic Energy UUID Value + */ +#define BT_UUID_GATT_ENERGY_VAL 0x2af2 +/** + * @brief GATT Characteristic Energy + */ +#define BT_UUID_GATT_ENERGY \ + BT_UUID_DECLARE_16(BT_UUID_GATT_ENERGY_VAL) +/** + * @brief GATT Characteristic Energy In A Period Of Day UUID Value + */ +#define BT_UUID_GATT_EPOD_VAL 0x2af3 +/** + * @brief GATT Characteristic Energy In A Period Of Day + */ +#define BT_UUID_GATT_EPOD \ + BT_UUID_DECLARE_16(BT_UUID_GATT_EPOD_VAL) +/** + * @brief GATT Characteristic Event Statistics UUID Value + */ +#define BT_UUID_GATT_EVTSTAT_VAL 0x2af4 +/** + * @brief GATT Characteristic Event Statistics + */ +#define BT_UUID_GATT_EVTSTAT \ + BT_UUID_DECLARE_16(BT_UUID_GATT_EVTSTAT_VAL) +/** + * @brief GATT Characteristic Fixed String 16 UUID Value + */ +#define BT_UUID_GATT_FSTR16_VAL 0x2af5 +/** + * @brief GATT Characteristic Fixed String 16 + */ +#define BT_UUID_GATT_FSTR16 \ + BT_UUID_DECLARE_16(BT_UUID_GATT_FSTR16_VAL) +/** + * @brief GATT Characteristic Fixed String 24 UUID Value + */ +#define BT_UUID_GATT_FSTR24_VAL 0x2af6 +/** + * @brief GATT Characteristic Fixed String 24 + */ +#define BT_UUID_GATT_FSTR24 \ + BT_UUID_DECLARE_16(BT_UUID_GATT_FSTR24_VAL) +/** + * @brief GATT Characteristic Fixed String 36 UUID Value + */ +#define BT_UUID_GATT_FSTR36_VAL 0x2af7 +/** + * @brief GATT Characteristic Fixed String 36 + */ +#define BT_UUID_GATT_FSTR36 \ + BT_UUID_DECLARE_16(BT_UUID_GATT_FSTR36_VAL) +/** + * @brief GATT Characteristic Fixed String 8 UUID Value + */ +#define BT_UUID_GATT_FSTR8_VAL 0x2af8 +/** + * @brief GATT Characteristic Fixed String 8 + */ +#define BT_UUID_GATT_FSTR8 \ + BT_UUID_DECLARE_16(BT_UUID_GATT_FSTR8_VAL) +/** + * @brief GATT Characteristic Generic Level UUID Value + */ +#define BT_UUID_GATT_GENLVL_VAL 0x2af9 +/** + * @brief GATT Characteristic Generic Level + */ +#define BT_UUID_GATT_GENLVL \ + BT_UUID_DECLARE_16(BT_UUID_GATT_GENLVL_VAL) +/** + * @brief GATT Characteristic Global Trade Item Number UUID Value + */ +#define BT_UUID_GATT_GTIN_VAL 0x2afa +/** + * @brief GATT Characteristic Global Trade Item Number + */ +#define BT_UUID_GATT_GTIN \ + BT_UUID_DECLARE_16(BT_UUID_GATT_GTIN_VAL) +/** + * @brief GATT Characteristic Illuminance UUID Value + */ +#define BT_UUID_GATT_ILLUM_VAL 0x2afb +/** + * @brief GATT Characteristic Illuminance + */ +#define BT_UUID_GATT_ILLUM \ + BT_UUID_DECLARE_16(BT_UUID_GATT_ILLUM_VAL) +/** + * @brief GATT Characteristic Luminous Efficacy UUID Value + */ +#define BT_UUID_GATT_LUMEFF_VAL 0x2afc +/** + * @brief GATT Characteristic Luminous Efficacy + */ +#define BT_UUID_GATT_LUMEFF \ + BT_UUID_DECLARE_16(BT_UUID_GATT_LUMEFF_VAL) +/** + * @brief GATT Characteristic Luminous Energy UUID Value + */ +#define BT_UUID_GATT_LUMNRG_VAL 0x2afd +/** + * @brief GATT Characteristic Luminous Energy + */ +#define BT_UUID_GATT_LUMNRG \ + BT_UUID_DECLARE_16(BT_UUID_GATT_LUMNRG_VAL) +/** + * @brief GATT Characteristic Luminous Exposure UUID Value + */ +#define BT_UUID_GATT_LUMEXP_VAL 0x2afe +/** + * @brief GATT Characteristic Luminous Exposure + */ +#define BT_UUID_GATT_LUMEXP \ + BT_UUID_DECLARE_16(BT_UUID_GATT_LUMEXP_VAL) +/** + * @brief GATT Characteristic Luminous Flux UUID Value + */ +#define BT_UUID_GATT_LUMFLX_VAL 0x2aff +/** + * @brief GATT Characteristic Luminous Flux + */ +#define BT_UUID_GATT_LUMFLX \ + BT_UUID_DECLARE_16(BT_UUID_GATT_LUMFLX_VAL) +/** + * @brief GATT Characteristic Luminous Flux Range UUID Value + */ +#define BT_UUID_GATT_LUMFLXR_VAL 0x2b00 +/** + * @brief GATT Characteristic Luminous Flux Range + */ +#define BT_UUID_GATT_LUMFLXR \ + BT_UUID_DECLARE_16(BT_UUID_GATT_LUMFLXR_VAL) +/** + * @brief GATT Characteristic Luminous Intensity UUID Value + */ +#define BT_UUID_GATT_LUMINT_VAL 0x2b01 +/** + * @brief GATT Characteristic Luminous Intensity + */ +#define BT_UUID_GATT_LUMINT \ + BT_UUID_DECLARE_16(BT_UUID_GATT_LUMINT_VAL) +/** + * @brief GATT Characteristic Mass Flow UUID Value + */ +#define BT_UUID_GATT_MASSFLOW_VAL 0x2b02 +/** + * @brief GATT Characteristic Mass Flow + */ +#define BT_UUID_GATT_MASSFLOW \ + BT_UUID_DECLARE_16(BT_UUID_GATT_MASSFLOW_VAL) +/** + * @brief GATT Characteristic Perceived Lightness UUID Value + */ +#define BT_UUID_GATT_PERLGHT_VAL 0x2b03 +/** + * @brief GATT Characteristic Perceived Lightness + */ +#define BT_UUID_GATT_PERLGHT \ + BT_UUID_DECLARE_16(BT_UUID_GATT_PERLGHT_VAL) +/** + * @brief GATT Characteristic Percentage 8 UUID Value + */ +#define BT_UUID_GATT_PER8_VAL 0x2b04 +/** + * @brief GATT Characteristic Percentage 8 + */ +#define BT_UUID_GATT_PER8 \ + BT_UUID_DECLARE_16(BT_UUID_GATT_PER8_VAL) +/** + * @brief GATT Characteristic Power UUID Value + */ +#define BT_UUID_GATT_PWR_VAL 0x2b05 +/** + * @brief GATT Characteristic Power + */ +#define BT_UUID_GATT_PWR \ + BT_UUID_DECLARE_16(BT_UUID_GATT_PWR_VAL) +/** + * @brief GATT Characteristic Power Specification UUID Value + */ +#define BT_UUID_GATT_PWRSPEC_VAL 0x2b06 +/** + * @brief GATT Characteristic Power Specification + */ +#define BT_UUID_GATT_PWRSPEC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_PWRSPEC_VAL) +/** + * @brief GATT Characteristic Relative Runtime In A Current Range UUID Value + */ +#define BT_UUID_GATT_RRICR_VAL 0x2b07 +/** + * @brief GATT Characteristic Relative Runtime In A Current Range + */ +#define BT_UUID_GATT_RRICR \ + BT_UUID_DECLARE_16(BT_UUID_GATT_RRICR_VAL) +/** + * @brief GATT Characteristic Relative Runtime In A Generic Level Range UUID Value + */ +#define BT_UUID_GATT_RRIGLR_VAL 0x2b08 +/** + * @brief GATT Characteristic Relative Runtime In A Generic Level Range + */ +#define BT_UUID_GATT_RRIGLR \ + BT_UUID_DECLARE_16(BT_UUID_GATT_RRIGLR_VAL) +/** + * @brief GATT Characteristic Relative Value In A Voltage Range UUID Value + */ +#define BT_UUID_GATT_RVIVR_VAL 0x2b09 +/** + * @brief GATT Characteristic Relative Value In A Voltage Range + */ +#define BT_UUID_GATT_RVIVR \ + BT_UUID_DECLARE_16(BT_UUID_GATT_RVIVR_VAL) +/** + * @brief GATT Characteristic Relative Value In A Illuminance Range UUID Value + */ +#define BT_UUID_GATT_RVIIR_VAL 0x2b0a +/** + * @brief GATT Characteristic Relative Value In A Illuminance Range + */ +#define BT_UUID_GATT_RVIIR \ + BT_UUID_DECLARE_16(BT_UUID_GATT_RVIIR_VAL) +/** + * @brief GATT Characteristic Relative Value In A Period Of Day UUID Value + */ +#define BT_UUID_GATT_RVIPOD_VAL 0x2b0b +/** + * @brief GATT Characteristic Relative Value In A Period Of Day + */ +#define BT_UUID_GATT_RVIPOD \ + BT_UUID_DECLARE_16(BT_UUID_GATT_RVIPOD_VAL) +/** + * @brief GATT Characteristic Relative Value In A Temperature Range UUID Value + */ +#define BT_UUID_GATT_RVITR_VAL 0x2b0c +/** + * @brief GATT Characteristic Relative Value In A Temperature Range + */ +#define BT_UUID_GATT_RVITR \ + BT_UUID_DECLARE_16(BT_UUID_GATT_RVITR_VAL) +/** + * @brief GATT Characteristic Temperature 8 UUID Value + */ +#define BT_UUID_GATT_TEMP8_VAL 0x2b0d +/** + * @brief GATT Characteristic Temperature 8 + */ +#define BT_UUID_GATT_TEMP8 \ + BT_UUID_DECLARE_16(BT_UUID_GATT_TEMP8_VAL) +/** + * @brief GATT Characteristic Temperature 8 In A Period Of Day UUID Value + */ +#define BT_UUID_GATT_TEMP8_IPOD_VAL 0x2b0e +/** + * @brief GATT Characteristic Temperature 8 In A Period Of Day + */ +#define BT_UUID_GATT_TEMP8_IPOD \ + BT_UUID_DECLARE_16(BT_UUID_GATT_TEMP8_IPOD_VAL) +/** + * @brief GATT Characteristic Temperature 8 Statistics UUID Value + */ +#define BT_UUID_GATT_TEMP8_STAT_VAL 0x2b0f +/** + * @brief GATT Characteristic Temperature 8 Statistics + */ +#define BT_UUID_GATT_TEMP8_STAT \ + BT_UUID_DECLARE_16(BT_UUID_GATT_TEMP8_STAT_VAL) +/** + * @brief GATT Characteristic Temperature Range UUID Value + */ +#define BT_UUID_GATT_TEMP_RNG_VAL 0x2b10 +/** + * @brief GATT Characteristic Temperature Range + */ +#define BT_UUID_GATT_TEMP_RNG \ + BT_UUID_DECLARE_16(BT_UUID_GATT_TEMP_RNG_VAL) +/** + * @brief GATT Characteristic Temperature Statistics UUID Value + */ +#define BT_UUID_GATT_TEMP_STAT_VAL 0x2b11 +/** + * @brief GATT Characteristic Temperature Statistics + */ +#define BT_UUID_GATT_TEMP_STAT \ + BT_UUID_DECLARE_16(BT_UUID_GATT_TEMP_STAT_VAL) +/** + * @brief GATT Characteristic Time Decihour 8 UUID Value + */ +#define BT_UUID_GATT_TIM_DC8_VAL 0x2b12 +/** + * @brief GATT Characteristic Time Decihour 8 + */ +#define BT_UUID_GATT_TIM_DC8 \ + BT_UUID_DECLARE_16(BT_UUID_GATT_TIM_DC8_VAL) +/** + * @brief GATT Characteristic Time Exponential 8 UUID Value + */ +#define BT_UUID_GATT_TIM_EXP8_VAL 0x2b13 +/** + * @brief GATT Characteristic Time Exponential 8 + */ +#define BT_UUID_GATT_TIM_EXP8 \ + BT_UUID_DECLARE_16(BT_UUID_GATT_TIM_EXP8_VAL) +/** + * @brief GATT Characteristic Time Hour 24 UUID Value + */ +#define BT_UUID_GATT_TIM_H24_VAL 0x2b14 +/** + * @brief GATT Characteristic Time Hour 24 + */ +#define BT_UUID_GATT_TIM_H24 \ + BT_UUID_DECLARE_16(BT_UUID_GATT_TIM_H24_VAL) +/** + * @brief GATT Characteristic Time Millisecond 24 UUID Value + */ +#define BT_UUID_GATT_TIM_MS24_VAL 0x2b15 +/** + * @brief GATT Characteristic Time Millisecond 24 + */ +#define BT_UUID_GATT_TIM_MS24 \ + BT_UUID_DECLARE_16(BT_UUID_GATT_TIM_MS24_VAL) +/** + * @brief GATT Characteristic Time Second 16 UUID Value + */ +#define BT_UUID_GATT_TIM_S16_VAL 0x2b16 +/** + * @brief GATT Characteristic Time Second 16 + */ +#define BT_UUID_GATT_TIM_S16 \ + BT_UUID_DECLARE_16(BT_UUID_GATT_TIM_S16_VAL) +/** + * @brief GATT Characteristic Time Second 8 UUID Value + */ +#define BT_UUID_GATT_TIM_S8_VAL 0x2b17 +/** + * @brief GATT Characteristic Time Second 8 + */ +#define BT_UUID_GATT_TIM_S8 \ + BT_UUID_DECLARE_16(BT_UUID_GATT_TIM_S8_VAL) +/** + * @brief GATT Characteristic Voltage UUID Value + */ +#define BT_UUID_GATT_V_VAL 0x2b18 +/** + * @brief GATT Characteristic Voltage + */ +#define BT_UUID_GATT_V \ + BT_UUID_DECLARE_16(BT_UUID_GATT_V_VAL) +/** + * @brief GATT Characteristic Voltage Specification UUID Value + */ +#define BT_UUID_GATT_V_SPEC_VAL 0x2b19 +/** + * @brief GATT Characteristic Voltage Specification + */ +#define BT_UUID_GATT_V_SPEC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_V_SPEC_VAL) +/** + * @brief GATT Characteristic Voltage Statistics UUID Value + */ +#define BT_UUID_GATT_V_STAT_VAL 0x2b1a +/** + * @brief GATT Characteristic Voltage Statistics + */ +#define BT_UUID_GATT_V_STAT \ + BT_UUID_DECLARE_16(BT_UUID_GATT_V_STAT_VAL) +/** + * @brief GATT Characteristic Volume Flow UUID Value + */ +#define BT_UUID_GATT_VOLF_VAL 0x2b1b +/** + * @brief GATT Characteristic Volume Flow + */ +#define BT_UUID_GATT_VOLF \ + BT_UUID_DECLARE_16(BT_UUID_GATT_VOLF_VAL) +/** + * @brief GATT Characteristic Chromaticity Coordinate (not Coordinates) UUID Value + */ +#define BT_UUID_GATT_CRCOORD_VAL 0x2b1c +/** + * @brief GATT Characteristic Chromaticity Coordinate (not Coordinates) + */ +#define BT_UUID_GATT_CRCOORD \ + BT_UUID_DECLARE_16(BT_UUID_GATT_CRCOORD_VAL) +/** + * @brief GATT Characteristic RC Feature UUID Value + */ +#define BT_UUID_GATT_RCF_VAL 0x2b1d +/** + * @brief GATT Characteristic RC Feature + */ +#define BT_UUID_GATT_RCF \ + BT_UUID_DECLARE_16(BT_UUID_GATT_RCF_VAL) +/** + * @brief GATT Characteristic RC Settings UUID Value + */ +#define BT_UUID_GATT_RCSET_VAL 0x2b1e +/** + * @brief GATT Characteristic RC Settings + */ +#define BT_UUID_GATT_RCSET \ + BT_UUID_DECLARE_16(BT_UUID_GATT_RCSET_VAL) +/** + * @brief GATT Characteristic Reconnection Configuration Control Point UUID Value + */ +#define BT_UUID_GATT_RCCP_VAL 0x2b1f +/** + * @brief GATT Characteristic Reconnection Configuration Control Point + */ +#define BT_UUID_GATT_RCCP \ + BT_UUID_DECLARE_16(BT_UUID_GATT_RCCP_VAL) +/** + * @brief GATT Characteristic IDD Status Changed UUID Value + */ +#define BT_UUID_GATT_IDD_SC_VAL 0x2b20 +/** + * @brief GATT Characteristic IDD Status Changed + */ +#define BT_UUID_GATT_IDD_SC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_IDD_SC_VAL) +/** + * @brief GATT Characteristic IDD Status UUID Value + */ +#define BT_UUID_GATT_IDD_S_VAL 0x2b21 +/** + * @brief GATT Characteristic IDD Status + */ +#define BT_UUID_GATT_IDD_S \ + BT_UUID_DECLARE_16(BT_UUID_GATT_IDD_S_VAL) +/** + * @brief GATT Characteristic IDD Annunciation Status UUID Value + */ +#define BT_UUID_GATT_IDD_AS_VAL 0x2b22 +/** + * @brief GATT Characteristic IDD Annunciation Status + */ +#define BT_UUID_GATT_IDD_AS \ + BT_UUID_DECLARE_16(BT_UUID_GATT_IDD_AS_VAL) +/** + * @brief GATT Characteristic IDD Features UUID Value + */ +#define BT_UUID_GATT_IDD_F_VAL 0x2b23 +/** + * @brief GATT Characteristic IDD Features + */ +#define BT_UUID_GATT_IDD_F \ + BT_UUID_DECLARE_16(BT_UUID_GATT_IDD_F_VAL) +/** + * @brief GATT Characteristic IDD Status Reader Control Point UUID Value + */ +#define BT_UUID_GATT_IDD_SRCP_VAL 0x2b24 +/** + * @brief GATT Characteristic IDD Status Reader Control Point + */ +#define BT_UUID_GATT_IDD_SRCP \ + BT_UUID_DECLARE_16(BT_UUID_GATT_IDD_SRCP_VAL) +/** + * @brief GATT Characteristic IDD Command Control Point UUID Value + */ +#define BT_UUID_GATT_IDD_CCP_VAL 0x2b25 +/** + * @brief GATT Characteristic IDD Command Control Point + */ +#define BT_UUID_GATT_IDD_CCP \ + BT_UUID_DECLARE_16(BT_UUID_GATT_IDD_CCP_VAL) +/** + * @brief GATT Characteristic IDD Command Data UUID Value + */ +#define BT_UUID_GATT_IDD_CD_VAL 0x2b26 +/** + * @brief GATT Characteristic IDD Command Data + */ +#define BT_UUID_GATT_IDD_CD \ + BT_UUID_DECLARE_16(BT_UUID_GATT_IDD_CD_VAL) +/** + * @brief GATT Characteristic IDD Record Access Control Point UUID Value + */ +#define BT_UUID_GATT_IDD_RACP_VAL 0x2b27 +/** + * @brief GATT Characteristic IDD Record Access Control Point + */ +#define BT_UUID_GATT_IDD_RACP \ + BT_UUID_DECLARE_16(BT_UUID_GATT_IDD_RACP_VAL) +/** + * @brief GATT Characteristic IDD History Data UUID Value + */ +#define BT_UUID_GATT_IDD_HD_VAL 0x2b28 +/** + * @brief GATT Characteristic IDD History Data + */ +#define BT_UUID_GATT_IDD_HD \ + BT_UUID_DECLARE_16(BT_UUID_GATT_IDD_HD_VAL) +/** + * @brief GATT Characteristic Client Supported Features UUID value + */ +#define BT_UUID_GATT_CLIENT_FEATURES_VAL 0x2b29 +/** + * @brief GATT Characteristic Client Supported Features + */ +#define BT_UUID_GATT_CLIENT_FEATURES \ + BT_UUID_DECLARE_16(BT_UUID_GATT_CLIENT_FEATURES_VAL) +/** + * @brief GATT Characteristic Database Hash UUID value + */ +#define BT_UUID_GATT_DB_HASH_VAL 0x2b2a +/** + * @brief GATT Characteristic Database Hash + */ +#define BT_UUID_GATT_DB_HASH \ + BT_UUID_DECLARE_16(BT_UUID_GATT_DB_HASH_VAL) +/** + * @brief GATT Characteristic BSS Control Point UUID Value + */ +#define BT_UUID_GATT_BSS_CP_VAL 0x2b2b +/** + * @brief GATT Characteristic BSS Control Point + */ +#define BT_UUID_GATT_BSS_CP \ + BT_UUID_DECLARE_16(BT_UUID_GATT_BSS_CP_VAL) +/** + * @brief GATT Characteristic BSS Response UUID Value + */ +#define BT_UUID_GATT_BSS_R_VAL 0x2b2c +/** + * @brief GATT Characteristic BSS Response + */ +#define BT_UUID_GATT_BSS_R \ + BT_UUID_DECLARE_16(BT_UUID_GATT_BSS_R_VAL) +/** + * @brief GATT Characteristic Emergency ID UUID Value + */ +#define BT_UUID_GATT_EMG_ID_VAL 0x2b2d +/** + * @brief GATT Characteristic Emergency ID + */ +#define BT_UUID_GATT_EMG_ID \ + BT_UUID_DECLARE_16(BT_UUID_GATT_EMG_ID_VAL) +/** + * @brief GATT Characteristic Emergency Text UUID Value + */ +#define BT_UUID_GATT_EMG_TXT_VAL 0x2b2e +/** + * @brief GATT Characteristic Emergency Text + */ +#define BT_UUID_GATT_EMG_TXT \ + BT_UUID_DECLARE_16(BT_UUID_GATT_EMG_TXT_VAL) +/** + * @brief GATT Characteristic ACS Status UUID Value + */ +#define BT_UUID_GATT_ACS_S_VAL 0x2b2f +/** + * @brief GATT Characteristic ACS Status + */ +#define BT_UUID_GATT_ACS_S \ + BT_UUID_DECLARE_16(BT_UUID_GATT_ACS_S_VAL) +/** + * @brief GATT Characteristic ACS Data In UUID Value + */ +#define BT_UUID_GATT_ACS_DI_VAL 0x2b30 +/** + * @brief GATT Characteristic ACS Data In + */ +#define BT_UUID_GATT_ACS_DI \ + BT_UUID_DECLARE_16(BT_UUID_GATT_ACS_DI_VAL) +/** + * @brief GATT Characteristic ACS Data Out Notify UUID Value + */ +#define BT_UUID_GATT_ACS_DON_VAL 0x2b31 +/** + * @brief GATT Characteristic ACS Data Out Notify + */ +#define BT_UUID_GATT_ACS_DON \ + BT_UUID_DECLARE_16(BT_UUID_GATT_ACS_DON_VAL) +/** + * @brief GATT Characteristic ACS Data Out Indicate UUID Value + */ +#define BT_UUID_GATT_ACS_DOI_VAL 0x2b32 +/** + * @brief GATT Characteristic ACS Data Out Indicate + */ +#define BT_UUID_GATT_ACS_DOI \ + BT_UUID_DECLARE_16(BT_UUID_GATT_ACS_DOI_VAL) +/** + * @brief GATT Characteristic ACS Control Point UUID Value + */ +#define BT_UUID_GATT_ACS_CP_VAL 0x2b33 +/** + * @brief GATT Characteristic ACS Control Point + */ +#define BT_UUID_GATT_ACS_CP \ + BT_UUID_DECLARE_16(BT_UUID_GATT_ACS_CP_VAL) +/** + * @brief GATT Characteristic Enhanced Blood Pressure Measurement UUID Value + */ +#define BT_UUID_GATT_EBPM_VAL 0x2b34 +/** + * @brief GATT Characteristic Enhanced Blood Pressure Measurement + */ +#define BT_UUID_GATT_EBPM \ + BT_UUID_DECLARE_16(BT_UUID_GATT_EBPM_VAL) +/** + * @brief GATT Characteristic Enhanced Intermediate Cuff Pressure UUID Value + */ +#define BT_UUID_GATT_EICP_VAL 0x2b35 +/** + * @brief GATT Characteristic Enhanced Intermediate Cuff Pressure + */ +#define BT_UUID_GATT_EICP \ + BT_UUID_DECLARE_16(BT_UUID_GATT_EICP_VAL) +/** + * @brief GATT Characteristic Blood Pressure Record UUID Value + */ +#define BT_UUID_GATT_BPR_VAL 0x2b36 +/** + * @brief GATT Characteristic Blood Pressure Record + */ +#define BT_UUID_GATT_BPR \ + BT_UUID_DECLARE_16(BT_UUID_GATT_BPR_VAL) +/** + * @brief GATT Characteristic Registered User UUID Value + */ +#define BT_UUID_GATT_RU_VAL 0x2b37 +/** + * @brief GATT Characteristic Registered User + */ +#define BT_UUID_GATT_RU \ + BT_UUID_DECLARE_16(BT_UUID_GATT_RU_VAL) +/** + * @brief GATT Characteristic BR-EDR Handover Data UUID Value + */ +#define BT_UUID_GATT_BR_EDR_HD_VAL 0x2b38 +/** + * @brief GATT Characteristic BR-EDR Handover Data + */ +#define BT_UUID_GATT_BR_EDR_HD \ + BT_UUID_DECLARE_16(BT_UUID_GATT_BR_EDR_HD_VAL) +/** + * @brief GATT Characteristic Bluetooth SIG Data UUID Value + */ +#define BT_UUID_GATT_BT_SIG_D_VAL 0x2b39 +/** + * @brief GATT Characteristic Bluetooth SIG Data + */ +#define BT_UUID_GATT_BT_SIG_D \ + BT_UUID_DECLARE_16(BT_UUID_GATT_BT_SIG_D_VAL) +/** + * @brief GATT Characteristic Server Supported Features UUID value + */ +#define BT_UUID_GATT_SERVER_FEATURES_VAL 0x2b3a +/** + * @brief GATT Characteristic Server Supported Features + */ +#define BT_UUID_GATT_SERVER_FEATURES \ + BT_UUID_DECLARE_16(BT_UUID_GATT_SERVER_FEATURES_VAL) +/** + * @brief GATT Characteristic Physical Activity Monitor Features UUID Value + */ +#define BT_UUID_GATT_PHY_AMF_VAL 0x2b3b +/** + * @brief GATT Characteristic Physical Activity Monitor Features + */ +#define BT_UUID_GATT_PHY_AMF \ + BT_UUID_DECLARE_16(BT_UUID_GATT_PHY_AMF_VAL) +/** + * @brief GATT Characteristic General Activity Instantaneous Data UUID Value + */ +#define BT_UUID_GATT_GEN_AID_VAL 0x2b3c +/** + * @brief GATT Characteristic General Activity Instantaneous Data + */ +#define BT_UUID_GATT_GEN_AID \ + BT_UUID_DECLARE_16(BT_UUID_GATT_GEN_AID_VAL) +/** + * @brief GATT Characteristic General Activity Summary Data UUID Value + */ +#define BT_UUID_GATT_GEN_ASD_VAL 0x2b3d +/** + * @brief GATT Characteristic General Activity Summary Data + */ +#define BT_UUID_GATT_GEN_ASD \ + BT_UUID_DECLARE_16(BT_UUID_GATT_GEN_ASD_VAL) +/** + * @brief GATT Characteristic CardioRespiratory Activity Instantaneous Data UUID Value + */ +#define BT_UUID_GATT_CR_AID_VAL 0x2b3e +/** + * @brief GATT Characteristic CardioRespiratory Activity Instantaneous Data + */ +#define BT_UUID_GATT_CR_AID \ + BT_UUID_DECLARE_16(BT_UUID_GATT_CR_AID_VAL) +/** + * @brief GATT Characteristic CardioRespiratory Activity Summary Data UUID Value + */ +#define BT_UUID_GATT_CR_ASD_VAL 0x2b3f +/** + * @brief GATT Characteristic CardioRespiratory Activity Summary Data + */ +#define BT_UUID_GATT_CR_ASD \ + BT_UUID_DECLARE_16(BT_UUID_GATT_CR_ASD_VAL) +/** + * @brief GATT Characteristic Step Counter Activity Summary Data UUID Value + */ +#define BT_UUID_GATT_SC_ASD_VAL 0x2b40 +/** + * @brief GATT Characteristic Step Counter Activity Summary Data + */ +#define BT_UUID_GATT_SC_ASD \ + BT_UUID_DECLARE_16(BT_UUID_GATT_SC_ASD_VAL) +/** + * @brief GATT Characteristic Sleep Activity Instantaneous Data UUID Value + */ +#define BT_UUID_GATT_SLP_AID_VAL 0x2b41 +/** + * @brief GATT Characteristic Sleep Activity Instantaneous Data + */ +#define BT_UUID_GATT_SLP_AID \ + BT_UUID_DECLARE_16(BT_UUID_GATT_SLP_AID_VAL) +/** + * @brief GATT Characteristic Sleep Activity Summary Data UUID Value + */ +#define BT_UUID_GATT_SLP_ASD_VAL 0x2b42 +/** + * @brief GATT Characteristic Sleep Activity Summary Data + */ +#define BT_UUID_GATT_SLP_ASD \ + BT_UUID_DECLARE_16(BT_UUID_GATT_SLP_ASD_VAL) +/** + * @brief GATT Characteristic Physical Activity Monitor Control Point UUID Value + */ +#define BT_UUID_GATT_PHY_AMCP_VAL 0x2b43 +/** + * @brief GATT Characteristic Physical Activity Monitor Control Point + */ +#define BT_UUID_GATT_PHY_AMCP \ + BT_UUID_DECLARE_16(BT_UUID_GATT_PHY_AMCP_VAL) +/** + * @brief GATT Characteristic Activity Current Session UUID Value + */ +#define BT_UUID_GATT_ACS_VAL 0x2b44 +/** + * @brief GATT Characteristic Activity Current Session + */ +#define BT_UUID_GATT_ACS \ + BT_UUID_DECLARE_16(BT_UUID_GATT_ACS_VAL) +/** + * @brief GATT Characteristic Physical Activity Session Descriptor UUID Value + */ +#define BT_UUID_GATT_PHY_ASDESC_VAL 0x2b45 +/** + * @brief GATT Characteristic Physical Activity Session Descriptor + */ +#define BT_UUID_GATT_PHY_ASDESC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_PHY_ASDESC_VAL) +/** + * @brief GATT Characteristic Preferred Units UUID Value + */ +#define BT_UUID_GATT_PREF_U_VAL 0x2b46 +/** + * @brief GATT Characteristic Preferred Units + */ +#define BT_UUID_GATT_PREF_U \ + BT_UUID_DECLARE_16(BT_UUID_GATT_PREF_U_VAL) +/** + * @brief GATT Characteristic High Resolution Height UUID Value + */ +#define BT_UUID_GATT_HRES_H_VAL 0x2b47 +/** + * @brief GATT Characteristic High Resolution Height + */ +#define BT_UUID_GATT_HRES_H \ + BT_UUID_DECLARE_16(BT_UUID_GATT_HRES_H_VAL) +/** + * @brief GATT Characteristic Middle Name UUID Value + */ +#define BT_UUID_GATT_MID_NAME_VAL 0x2b48 +/** + * @brief GATT Characteristic Middle Name + */ +#define BT_UUID_GATT_MID_NAME \ + BT_UUID_DECLARE_16(BT_UUID_GATT_MID_NAME_VAL) +/** + * @brief GATT Characteristic Stride Length UUID Value + */ +#define BT_UUID_GATT_STRDLEN_VAL 0x2b49 +/** + * @brief GATT Characteristic Stride Length + */ +#define BT_UUID_GATT_STRDLEN \ + BT_UUID_DECLARE_16(BT_UUID_GATT_STRDLEN_VAL) +/** + * @brief GATT Characteristic Handedness UUID Value + */ +#define BT_UUID_GATT_HANDEDNESS_VAL 0x2b4a +/** + * @brief GATT Characteristic Handedness + */ +#define BT_UUID_GATT_HANDEDNESS \ + BT_UUID_DECLARE_16(BT_UUID_GATT_HANDEDNESS_VAL) +/** + * @brief GATT Characteristic Device Wearing Position UUID Value + */ +#define BT_UUID_GATT_DEVICE_WP_VAL 0x2b4b +/** + * @brief GATT Characteristic Device Wearing Position + */ +#define BT_UUID_GATT_DEVICE_WP \ + BT_UUID_DECLARE_16(BT_UUID_GATT_DEVICE_WP_VAL) +/** + * @brief GATT Characteristic Four Zone Heart Rate Limit UUID Value + */ +#define BT_UUID_GATT_4ZHRL_VAL 0x2b4c +/** + * @brief GATT Characteristic Four Zone Heart Rate Limit + */ +#define BT_UUID_GATT_4ZHRL \ + BT_UUID_DECLARE_16(BT_UUID_GATT_4ZHRL_VAL) +/** + * @brief GATT Characteristic High Intensity Exercise Threshold UUID Value + */ +#define BT_UUID_GATT_HIET_VAL 0x2b4d +/** + * @brief GATT Characteristic High Intensity Exercise Threshold + */ +#define BT_UUID_GATT_HIET \ + BT_UUID_DECLARE_16(BT_UUID_GATT_HIET_VAL) +/** + * @brief GATT Characteristic Activity Goal UUID Value + */ +#define BT_UUID_GATT_AG_VAL 0x2b4e +/** + * @brief GATT Characteristic Activity Goal + */ +#define BT_UUID_GATT_AG \ + BT_UUID_DECLARE_16(BT_UUID_GATT_AG_VAL) +/** + * @brief GATT Characteristic Sedentary Interval Notification UUID Value + */ +#define BT_UUID_GATT_SIN_VAL 0x2b4f +/** + * @brief GATT Characteristic Sedentary Interval Notification + */ +#define BT_UUID_GATT_SIN \ + BT_UUID_DECLARE_16(BT_UUID_GATT_SIN_VAL) +/** + * @brief GATT Characteristic Caloric Intake UUID Value + */ +#define BT_UUID_GATT_CI_VAL 0x2b50 +/** + * @brief GATT Characteristic Caloric Intake + */ +#define BT_UUID_GATT_CI \ + BT_UUID_DECLARE_16(BT_UUID_GATT_CI_VAL) +/** + * @brief GATT Characteristic TMAP Role UUID Value + */ +#define BT_UUID_GATT_TMAPR_VAL 0x2b51 +/** + * @brief GATT Characteristic TMAP Role + */ +#define BT_UUID_GATT_TMAPR \ + BT_UUID_DECLARE_16(BT_UUID_GATT_TMAPR_VAL) +/** + * @brief Audio Input Control Service State value + */ +#define BT_UUID_AICS_STATE_VAL 0x2b77 +/** + * @brief Audio Input Control Service State + */ +#define BT_UUID_AICS_STATE \ + BT_UUID_DECLARE_16(BT_UUID_AICS_STATE_VAL) +/** + * @brief Audio Input Control Service Gain Settings Properties value + */ +#define BT_UUID_AICS_GAIN_SETTINGS_VAL 0x2b78 +/** + * @brief Audio Input Control Service Gain Settings Properties + */ +#define BT_UUID_AICS_GAIN_SETTINGS \ + BT_UUID_DECLARE_16(BT_UUID_AICS_GAIN_SETTINGS_VAL) +/** + * @brief Audio Input Control Service Input Type value + */ +#define BT_UUID_AICS_INPUT_TYPE_VAL 0x2b79 +/** + * @brief Audio Input Control Service Input Type + */ +#define BT_UUID_AICS_INPUT_TYPE \ + BT_UUID_DECLARE_16(BT_UUID_AICS_INPUT_TYPE_VAL) +/** + * @brief Audio Input Control Service Input Status value + */ +#define BT_UUID_AICS_INPUT_STATUS_VAL 0x2b7a +/** + * @brief Audio Input Control Service Input Status + */ +#define BT_UUID_AICS_INPUT_STATUS \ + BT_UUID_DECLARE_16(BT_UUID_AICS_INPUT_STATUS_VAL) +/** + * @brief Audio Input Control Service Control Point value + */ +#define BT_UUID_AICS_CONTROL_VAL 0x2b7b +/** + * @brief Audio Input Control Service Control Point + */ +#define BT_UUID_AICS_CONTROL \ + BT_UUID_DECLARE_16(BT_UUID_AICS_CONTROL_VAL) +/** + * @brief Audio Input Control Service Input Description value + */ +#define BT_UUID_AICS_DESCRIPTION_VAL 0x2b7c +/** + * @brief Audio Input Control Service Input Description + */ +#define BT_UUID_AICS_DESCRIPTION \ + BT_UUID_DECLARE_16(BT_UUID_AICS_DESCRIPTION_VAL) +/** + * @brief Volume Control Setting value + */ +#define BT_UUID_VCS_STATE_VAL 0x2b7d +/** + * @brief Volume Control Setting + */ +#define BT_UUID_VCS_STATE \ + BT_UUID_DECLARE_16(BT_UUID_VCS_STATE_VAL) +/** + * @brief Volume Control Control point value + */ +#define BT_UUID_VCS_CONTROL_VAL 0x2b7e +/** + * @brief Volume Control Control point + */ +#define BT_UUID_VCS_CONTROL \ + BT_UUID_DECLARE_16(BT_UUID_VCS_CONTROL_VAL) +/** + * @brief Volume Control Flags value + */ +#define BT_UUID_VCS_FLAGS_VAL 0x2b7f +/** + * @brief Volume Control Flags + */ +#define BT_UUID_VCS_FLAGS \ + BT_UUID_DECLARE_16(BT_UUID_VCS_FLAGS_VAL) +/** + * @brief Volume Offset State value + */ +#define BT_UUID_VOCS_STATE_VAL 0x2b80 +/** + * @brief Volume Offset State + */ +#define BT_UUID_VOCS_STATE \ + BT_UUID_DECLARE_16(BT_UUID_VOCS_STATE_VAL) +/** + * @brief Audio Location value + */ +#define BT_UUID_VOCS_LOCATION_VAL 0x2b81 +/** + * @brief Audio Location + */ +#define BT_UUID_VOCS_LOCATION \ + BT_UUID_DECLARE_16(BT_UUID_VOCS_LOCATION_VAL) +/** + * @brief Volume Offset Control Point value + */ +#define BT_UUID_VOCS_CONTROL_VAL 0x2b82 +/** + * @brief Volume Offset Control Point + */ +#define BT_UUID_VOCS_CONTROL \ + BT_UUID_DECLARE_16(BT_UUID_VOCS_CONTROL_VAL) +/** + * @brief Volume Offset Audio Output Description value + */ +#define BT_UUID_VOCS_DESCRIPTION_VAL 0x2b83 +/** + * @brief Volume Offset Audio Output Description + */ +#define BT_UUID_VOCS_DESCRIPTION \ + BT_UUID_DECLARE_16(BT_UUID_VOCS_DESCRIPTION_VAL) +/** + * @brief Set Identity Resolving Key value + */ +#define BT_UUID_CSIS_SIRK_VAL 0x2b84 +/** + * @brief Set Identity Resolving Key + */ +#define BT_UUID_CSIS_SIRK BT_UUID_DECLARE_16(BT_UUID_CSIS_SIRK_VAL) +/** + * @brief Set size value + */ +#define BT_UUID_CSIS_SET_SIZE_VAL 0x2b85 +/** + * @brief Set size + */ +#define BT_UUID_CSIS_SET_SIZE \ + BT_UUID_DECLARE_16(BT_UUID_CSIS_SET_SIZE_VAL) +/** + * @brief Set lock value + */ +#define BT_UUID_CSIS_SET_LOCK_VAL 0x2b86 +/** + * @brief Set lock + */ +#define BT_UUID_CSIS_SET_LOCK \ + BT_UUID_DECLARE_16(BT_UUID_CSIS_SET_LOCK_VAL) +/** + * @brief Rank value + */ +#define BT_UUID_CSIS_RANK_VAL 0x2b87 +/** + * @brief Rank + */ +#define BT_UUID_CSIS_RANK \ + BT_UUID_DECLARE_16(BT_UUID_CSIS_RANK_VAL) +/** + * @brief GATT Characteristic Encrypted Data Key Material UUID Value + */ +#define BT_UUID_GATT_EDKM_VAL 0x2b88 +/** + * @brief GATT Characteristic Encrypted Data Key Material + */ +#define BT_UUID_GATT_EDKM \ + BT_UUID_DECLARE_16(BT_UUID_GATT_EDKM_VAL) +/** + * @brief GATT Characteristic Apparent Energy 32 UUID Value + */ +#define BT_UUID_GATT_AE32_VAL 0x2b89 +/** + * @brief GATT Characteristic Apparent Energy 32 + */ +#define BT_UUID_GATT_AE32 \ + BT_UUID_DECLARE_16(BT_UUID_GATT_AE32_VAL) +/** + * @brief GATT Characteristic Apparent Power UUID Value + */ +#define BT_UUID_GATT_AP_VAL 0x2b8a +/** + * @brief GATT Characteristic Apparent Power + */ +#define BT_UUID_GATT_AP \ + BT_UUID_DECLARE_16(BT_UUID_GATT_AP_VAL) +/** + * @brief GATT Characteristic CO2 Concentration UUID Value + */ +#define BT_UUID_GATT_CO2CONC_VAL 0x2b8c +/** + * @brief GATT Characteristic CO2 Concentration + */ +#define BT_UUID_GATT_CO2CONC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_CO2CONC_VAL) +/** + * @brief GATT Characteristic Cosine of the Angle UUID Value + */ +#define BT_UUID_GATT_COS_VAL 0x2b8d +/** + * @brief GATT Characteristic Cosine of the Angle + */ +#define BT_UUID_GATT_COS \ + BT_UUID_DECLARE_16(BT_UUID_GATT_COS_VAL) +/** + * @brief GATT Characteristic Device Time Feature UUID Value + */ +#define BT_UUID_GATT_DEVTF_VAL 0x2b8e +/** + * @brief GATT Characteristic Device Time Feature + */ +#define BT_UUID_GATT_DEVTF \ + BT_UUID_DECLARE_16(BT_UUID_GATT_DEVTF_VAL) +/** + * @brief GATT Characteristic Device Time Parameters UUID Value + */ +#define BT_UUID_GATT_DEVTP_VAL 0x2b8f +/** + * @brief GATT Characteristic Device Time Parameters + */ +#define BT_UUID_GATT_DEVTP \ + BT_UUID_DECLARE_16(BT_UUID_GATT_DEVTP_VAL) +/** + * @brief GATT Characteristic Device Time UUID Value + */ +#define BT_UUID_GATT_DEVT_VAL 0x2b90 +/** + * @brief GATT Characteristic Device Time + */ +#define BT_UUID_GATT_DEVT \ + BT_UUID_DECLARE_16(BT_UUID_GATT_DEVT_VAL) +/** + * @brief GATT Characteristic Device Time Control Point UUID Value + */ +#define BT_UUID_GATT_DEVTCP_VAL 0x2b91 +/** + * @brief GATT Characteristic Device Time Control Point + */ +#define BT_UUID_GATT_DEVTCP \ + BT_UUID_DECLARE_16(BT_UUID_GATT_DEVTCP_VAL) +/** + * @brief GATT Characteristic Time Change Log Data UUID Value + */ +#define BT_UUID_GATT_TCLD_VAL 0x2b92 +/** + * @brief GATT Characteristic Time Change Log Data + */ +#define BT_UUID_GATT_TCLD \ + BT_UUID_DECLARE_16(BT_UUID_GATT_TCLD_VAL) +/** + * @brief Media player name value + */ +#define BT_UUID_MCS_PLAYER_NAME_VAL 0x2b93 +/** + * @brief Media player name + */ +#define BT_UUID_MCS_PLAYER_NAME \ + BT_UUID_DECLARE_16(BT_UUID_MCS_PLAYER_NAME_VAL) +/** + * @brief Media Icon Object ID value + */ +#define BT_UUID_MCS_ICON_OBJ_ID_VAL 0x2b94 +/** + * @brief Media Icon Object ID + */ +#define BT_UUID_MCS_ICON_OBJ_ID \ + BT_UUID_DECLARE_16(BT_UUID_MCS_ICON_OBJ_ID_VAL) +/** + * @brief Media Icon URL value + */ +#define BT_UUID_MCS_ICON_URL_VAL 0x2b95 +/** + * @brief Media Icon URL + */ +#define BT_UUID_MCS_ICON_URL \ + BT_UUID_DECLARE_16(BT_UUID_MCS_ICON_URL_VAL) +/** + * @brief Track Changed value + */ +#define BT_UUID_MCS_TRACK_CHANGED_VAL 0x2b96 +/** + * @brief Track Changed + */ +#define BT_UUID_MCS_TRACK_CHANGED \ + BT_UUID_DECLARE_16(BT_UUID_MCS_TRACK_CHANGED_VAL) +/** + * @brief Track Title value + */ +#define BT_UUID_MCS_TRACK_TITLE_VAL 0x2b97 +/** + * @brief Track Title + */ +#define BT_UUID_MCS_TRACK_TITLE \ + BT_UUID_DECLARE_16(BT_UUID_MCS_TRACK_TITLE_VAL) +/** + * @brief Track Duration value + */ +#define BT_UUID_MCS_TRACK_DURATION_VAL 0x2b98 +/** + * @brief Track Duration + */ +#define BT_UUID_MCS_TRACK_DURATION \ + BT_UUID_DECLARE_16(BT_UUID_MCS_TRACK_DURATION_VAL) +/** + * @brief Track Position value + */ +#define BT_UUID_MCS_TRACK_POSITION_VAL 0x2b99 +/** + * @brief Track Position + */ +#define BT_UUID_MCS_TRACK_POSITION \ + BT_UUID_DECLARE_16(BT_UUID_MCS_TRACK_POSITION_VAL) +/** + * @brief Playback Speed value + */ +#define BT_UUID_MCS_PLAYBACK_SPEED_VAL 0x2b9a +/** + * @brief Playback Speed + */ +#define BT_UUID_MCS_PLAYBACK_SPEED \ + BT_UUID_DECLARE_16(BT_UUID_MCS_PLAYBACK_SPEED_VAL) +/** + * @brief Seeking Speed value + */ +#define BT_UUID_MCS_SEEKING_SPEED_VAL 0x2b9b +/** + * @brief Seeking Speed + */ +#define BT_UUID_MCS_SEEKING_SPEED \ + BT_UUID_DECLARE_16(BT_UUID_MCS_SEEKING_SPEED_VAL) +/** + * @brief Track Segments Object ID value + */ +#define BT_UUID_MCS_TRACK_SEGMENTS_OBJ_ID_VAL 0x2b9c +/** + * @brief Track Segments Object ID + */ +#define BT_UUID_MCS_TRACK_SEGMENTS_OBJ_ID \ + BT_UUID_DECLARE_16(BT_UUID_MCS_TRACK_SEGMENTS_OBJ_ID_VAL) +/** + * @brief Current Track Object ID value + */ +#define BT_UUID_MCS_CURRENT_TRACK_OBJ_ID_VAL 0x2b9d +/** + * @brief Current Track Object ID + */ +#define BT_UUID_MCS_CURRENT_TRACK_OBJ_ID \ + BT_UUID_DECLARE_16(BT_UUID_MCS_CURRENT_TRACK_OBJ_ID_VAL) +/** + * @brief Next Track Object ID value + */ +#define BT_UUID_MCS_NEXT_TRACK_OBJ_ID_VAL 0x2b9e +/** + * @brief Next Track Object ID + */ +#define BT_UUID_MCS_NEXT_TRACK_OBJ_ID \ + BT_UUID_DECLARE_16(BT_UUID_MCS_NEXT_TRACK_OBJ_ID_VAL) +/** + * @brief Parent Group Object ID value + */ +#define BT_UUID_MCS_PARENT_GROUP_OBJ_ID_VAL 0x2b9f +/** + * @brief Parent Group Object ID + */ +#define BT_UUID_MCS_PARENT_GROUP_OBJ_ID \ + BT_UUID_DECLARE_16(BT_UUID_MCS_PARENT_GROUP_OBJ_ID_VAL) +/** + * @brief Group Object ID value + */ +#define BT_UUID_MCS_CURRENT_GROUP_OBJ_ID_VAL 0x2ba0 +/** + * @brief Group Object ID + */ +#define BT_UUID_MCS_CURRENT_GROUP_OBJ_ID \ + BT_UUID_DECLARE_16(BT_UUID_MCS_CURRENT_GROUP_OBJ_ID_VAL) +/** + * @brief Playing Order value + */ +#define BT_UUID_MCS_PLAYING_ORDER_VAL 0x2ba1 +/** + * @brief Playing Order + */ +#define BT_UUID_MCS_PLAYING_ORDER \ + BT_UUID_DECLARE_16(BT_UUID_MCS_PLAYING_ORDER_VAL) +/** + * @brief Playing Orders supported value + */ +#define BT_UUID_MCS_PLAYING_ORDERS_VAL 0x2ba2 +/** + * @brief Playing Orders supported + */ +#define BT_UUID_MCS_PLAYING_ORDERS \ + BT_UUID_DECLARE_16(BT_UUID_MCS_PLAYING_ORDERS_VAL) +/** + * @brief Media State value + */ +#define BT_UUID_MCS_MEDIA_STATE_VAL 0x2ba3 +/** + * @brief Media State + */ +#define BT_UUID_MCS_MEDIA_STATE \ + BT_UUID_DECLARE_16(BT_UUID_MCS_MEDIA_STATE_VAL) +/** + * @brief Media Control Point value + */ +#define BT_UUID_MCS_MEDIA_CONTROL_POINT_VAL 0x2ba4 +/** + * @brief Media Control Point + */ +#define BT_UUID_MCS_MEDIA_CONTROL_POINT \ + BT_UUID_DECLARE_16(BT_UUID_MCS_MEDIA_CONTROL_POINT_VAL) +/** + * @brief Media control opcodes supported value + */ +#define BT_UUID_MCS_MEDIA_CONTROL_OPCODES_VAL 0x2ba5 +/** + * @brief Media control opcodes supported + */ +#define BT_UUID_MCS_MEDIA_CONTROL_OPCODES \ + BT_UUID_DECLARE_16(BT_UUID_MCS_MEDIA_CONTROL_OPCODES_VAL) +/** + * @brief Search result object ID value + */ +#define BT_UUID_MCS_SEARCH_RESULTS_OBJ_ID_VAL 0x2ba6 +/** + * @brief Search result object ID + */ +#define BT_UUID_MCS_SEARCH_RESULTS_OBJ_ID \ + BT_UUID_DECLARE_16(BT_UUID_MCS_SEARCH_RESULTS_OBJ_ID_VAL) +/** + * @brief Search control point value + */ +#define BT_UUID_MCS_SEARCH_CONTROL_POINT_VAL 0x2ba7 +/** + * @brief Search control point + */ +#define BT_UUID_MCS_SEARCH_CONTROL_POINT \ + BT_UUID_DECLARE_16(BT_UUID_MCS_SEARCH_CONTROL_POINT_VAL) +/** + * @brief GATT Characteristic Energy 32 UUID Value + */ +#define BT_UUID_GATT_E32_VAL 0x2ba8 +/** + * @brief GATT Characteristic Energy 32 + */ +#define BT_UUID_GATT_E32 \ + BT_UUID_DECLARE_16(BT_UUID_GATT_E32_VAL) + +/** + * @brief Media Player Icon Object Type value + */ +#define BT_UUID_OTS_TYPE_MPL_ICON_VAL 0x2ba9 +/** + * @brief Media Player Icon Object Type + */ +#define BT_UUID_OTS_TYPE_MPL_ICON \ + BT_UUID_DECLARE_16(BT_UUID_OTS_TYPE_MPL_ICON_VAL) +/** + * @brief Track Segments Object Type value + */ +#define BT_UUID_OTS_TYPE_TRACK_SEGMENT_VAL 0x2baa +/** + * @brief Track Segments Object Type + */ +#define BT_UUID_OTS_TYPE_TRACK_SEGMENT \ + BT_UUID_DECLARE_16(BT_UUID_OTS_TYPE_TRACK_SEGMENT_VAL) +/** + * @brief Track Object Type value + */ +#define BT_UUID_OTS_TYPE_TRACK_VAL 0x2bab +/** + * @brief Track Object Type + */ +#define BT_UUID_OTS_TYPE_TRACK \ + BT_UUID_DECLARE_16(BT_UUID_OTS_TYPE_TRACK_VAL) +/** + * @brief Group Object Type value + */ +#define BT_UUID_OTS_TYPE_GROUP_VAL 0x2bac +/** + * @brief Group Object Type + */ +#define BT_UUID_OTS_TYPE_GROUP \ + BT_UUID_DECLARE_16(BT_UUID_OTS_TYPE_GROUP_VAL) +/** + * @brief GATT Characteristic Constant Tone Extension Enable UUID Value + */ +#define BT_UUID_GATT_CTEE_VAL 0x2bad +/** + * @brief GATT Characteristic Constant Tone Extension Enable + */ +#define BT_UUID_GATT_CTEE \ + BT_UUID_DECLARE_16(BT_UUID_GATT_CTEE_VAL) +/** + * @brief GATT Characteristic Advertising Constant Tone Extension Minimum Length UUID Value + */ +#define BT_UUID_GATT_ACTEML_VAL 0x2bae +/** + * @brief GATT Characteristic Advertising Constant Tone Extension Minimum Length + */ +#define BT_UUID_GATT_ACTEML \ + BT_UUID_DECLARE_16(BT_UUID_GATT_ACTEML_VAL) +/** + * @brief GATT Characteristic Advertising Constant Tone Extension Minimum Transmit Count UUID Value + */ +#define BT_UUID_GATT_ACTEMTC_VAL 0x2baf +/** + * @brief GATT Characteristic Advertising Constant Tone Extension Minimum Transmit Count + */ +#define BT_UUID_GATT_ACTEMTC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_ACTEMTC_VAL) +/** + * @brief GATT Characteristic Advertising Constant Tone Extension Transmit Duration UUID Value + */ +#define BT_UUID_GATT_ACTETD_VAL 0x2bb0 +/** + * @brief GATT Characteristic Advertising Constant Tone Extension Transmit Duration + */ +#define BT_UUID_GATT_ACTETD \ + BT_UUID_DECLARE_16(BT_UUID_GATT_ACTETD_VAL) +/** + * @brief GATT Characteristic Advertising Constant Tone Extension Interval UUID Value + */ +#define BT_UUID_GATT_ACTEI_VAL 0x2bb1 +/** + * @brief GATT Characteristic Advertising Constant Tone Extension Interval + */ +#define BT_UUID_GATT_ACTEI \ + BT_UUID_DECLARE_16(BT_UUID_GATT_ACTEI_VAL) +/** + * @brief GATT Characteristic Advertising Constant Tone Extension PHY UUID Value + */ +#define BT_UUID_GATT_ACTEP_VAL 0x2bb2 +/** + * @brief GATT Characteristic Advertising Constant Tone Extension PHY + */ +#define BT_UUID_GATT_ACTEP \ + BT_UUID_DECLARE_16(BT_UUID_GATT_ACTEP_VAL) +/** + * @brief Bearer Provider Name value + */ +#define BT_UUID_TBS_PROVIDER_NAME_VAL 0x2bb3 +/** + * @brief Bearer Provider Name + */ +#define BT_UUID_TBS_PROVIDER_NAME \ + BT_UUID_DECLARE_16(BT_UUID_TBS_PROVIDER_NAME_VAL) +/** + * @brief Bearer UCI value + */ +#define BT_UUID_TBS_UCI_VAL 0x2bb4 +/** + * @brief Bearer UCI + */ +#define BT_UUID_TBS_UCI \ + BT_UUID_DECLARE_16(BT_UUID_TBS_UCI_VAL) +/** + * @brief Bearer Technology value + */ +#define BT_UUID_TBS_TECHNOLOGY_VAL 0x2bb5 +/** + * @brief Bearer Technology + */ +#define BT_UUID_TBS_TECHNOLOGY \ + BT_UUID_DECLARE_16(BT_UUID_TBS_TECHNOLOGY_VAL) +/** + * @brief Bearer URI Prefixes Supported List value + */ +#define BT_UUID_TBS_URI_LIST_VAL 0x2bb6 +/** + * @brief Bearer URI Prefixes Supported List + */ +#define BT_UUID_TBS_URI_LIST \ + BT_UUID_DECLARE_16(BT_UUID_TBS_URI_LIST_VAL) +/** + * @brief Bearer Signal Strength value + */ +#define BT_UUID_TBS_SIGNAL_STRENGTH_VAL 0x2bb7 +/** + * @brief Bearer Signal Strength + */ +#define BT_UUID_TBS_SIGNAL_STRENGTH \ + BT_UUID_DECLARE_16(BT_UUID_TBS_SIGNAL_STRENGTH_VAL) +/** + * @brief Bearer Signal Strength Reporting Interval value + */ +#define BT_UUID_TBS_SIGNAL_INTERVAL_VAL 0x2bb8 +/** + * @brief Bearer Signal Strength Reporting Interval + */ +#define BT_UUID_TBS_SIGNAL_INTERVAL \ + BT_UUID_DECLARE_16(BT_UUID_TBS_SIGNAL_INTERVAL_VAL) +/** + * @brief Bearer List Current Calls value + */ +#define BT_UUID_TBS_LIST_CURRENT_CALLS_VAL 0x2bb9 +/** + * @brief Bearer List Current Calls + */ +#define BT_UUID_TBS_LIST_CURRENT_CALLS \ + BT_UUID_DECLARE_16(BT_UUID_TBS_LIST_CURRENT_CALLS_VAL) +/** + * @brief Content Control ID value + */ +#define BT_UUID_CCID_VAL 0x2bba +/** + * @brief Content Control ID + */ +#define BT_UUID_CCID \ + BT_UUID_DECLARE_16(BT_UUID_CCID_VAL) +/** + * @brief Status flags value + */ +#define BT_UUID_TBS_STATUS_FLAGS_VAL 0x2bbb +/** + * @brief Status flags + */ +#define BT_UUID_TBS_STATUS_FLAGS \ + BT_UUID_DECLARE_16(BT_UUID_TBS_STATUS_FLAGS_VAL) +/** + * @brief Incoming Call Target Caller ID value + */ +#define BT_UUID_TBS_INCOMING_URI_VAL 0x2bbc +/** + * @brief Incoming Call Target Caller ID + */ +#define BT_UUID_TBS_INCOMING_URI \ + BT_UUID_DECLARE_16(BT_UUID_TBS_INCOMING_URI_VAL) +/** + * @brief Call State value + */ +#define BT_UUID_TBS_CALL_STATE_VAL 0x2bbd +/** + * @brief Call State + */ +#define BT_UUID_TBS_CALL_STATE \ + BT_UUID_DECLARE_16(BT_UUID_TBS_CALL_STATE_VAL) +/** + * @brief Call Control Point value + */ +#define BT_UUID_TBS_CALL_CONTROL_POINT_VAL 0x2bbe +/** + * @brief Call Control Point + */ +#define BT_UUID_TBS_CALL_CONTROL_POINT \ + BT_UUID_DECLARE_16(BT_UUID_TBS_CALL_CONTROL_POINT_VAL) +/** + * @brief Optional Opcodes value + */ +#define BT_UUID_TBS_OPTIONAL_OPCODES_VAL 0x2bbf +/** + * @brief Optional Opcodes + */ +#define BT_UUID_TBS_OPTIONAL_OPCODES \ + BT_UUID_DECLARE_16(BT_UUID_TBS_OPTIONAL_OPCODES_VAL) +/** BT_UUID_TBS_TERMINATE_REASON_VAL + * @brief Terminate reason value + */ +#define BT_UUID_TBS_TERMINATE_REASON_VAL 0x2bc0 +/** BT_UUID_TBS_TERMINATE_REASON + * @brief Terminate reason + */ +#define BT_UUID_TBS_TERMINATE_REASON \ + BT_UUID_DECLARE_16(BT_UUID_TBS_TERMINATE_REASON_VAL) +/** + * @brief Incoming Call value + */ +#define BT_UUID_TBS_INCOMING_CALL_VAL 0x2bc1 +/** + * @brief Incoming Call + */ +#define BT_UUID_TBS_INCOMING_CALL \ + BT_UUID_DECLARE_16(BT_UUID_TBS_INCOMING_CALL_VAL) +/** + * @brief Incoming Call Friendly name value + */ +#define BT_UUID_TBS_FRIENDLY_NAME_VAL 0x2bc2 +/** + * @brief Incoming Call Friendly name + */ +#define BT_UUID_TBS_FRIENDLY_NAME \ + BT_UUID_DECLARE_16(BT_UUID_TBS_FRIENDLY_NAME_VAL) +/** + * @brief Microphone Control Service Mute value + */ +#define BT_UUID_MICS_MUTE_VAL 0x2bc3 +/** + * @brief Microphone Control Service Mute + */ +#define BT_UUID_MICS_MUTE \ + BT_UUID_DECLARE_16(BT_UUID_MICS_MUTE_VAL) +/** + * @brief Audio Stream Endpoint Sink Characteristic value + */ +#define BT_UUID_ASCS_ASE_SNK_VAL 0x2bc4 +/** + * @brief Audio Stream Endpoint Sink Characteristic + */ +#define BT_UUID_ASCS_ASE_SNK \ + BT_UUID_DECLARE_16(BT_UUID_ASCS_ASE_SNK_VAL) +/** + * @brief Audio Stream Endpoint Source Characteristic value + */ +#define BT_UUID_ASCS_ASE_SRC_VAL 0x2bc5 +/** + * @brief Audio Stream Endpoint Source Characteristic + */ +#define BT_UUID_ASCS_ASE_SRC \ + BT_UUID_DECLARE_16(BT_UUID_ASCS_ASE_SRC_VAL) +/** + * @brief Audio Stream Endpoint Control Point Characteristic value + */ +#define BT_UUID_ASCS_ASE_CP_VAL 0x2bc6 +/** + * @brief Audio Stream Endpoint Control Point Characteristic + */ +#define BT_UUID_ASCS_ASE_CP \ + BT_UUID_DECLARE_16(BT_UUID_ASCS_ASE_CP_VAL) +/** + * @brief Broadcast Audio Scan Service Scan State value + */ +#define BT_UUID_BASS_CONTROL_POINT_VAL 0x2bc7 +/** + * @brief Broadcast Audio Scan Service Scan State + */ +#define BT_UUID_BASS_CONTROL_POINT \ + BT_UUID_DECLARE_16(BT_UUID_BASS_CONTROL_POINT_VAL) +/** + * @brief Broadcast Audio Scan Service Receive State value + */ +#define BT_UUID_BASS_RECV_STATE_VAL 0x2bc8 +/** + * @brief Broadcast Audio Scan Service Receive State + */ +#define BT_UUID_BASS_RECV_STATE \ + BT_UUID_DECLARE_16(BT_UUID_BASS_RECV_STATE_VAL) +/** + * @brief Sink PAC Characteristic value + */ +#define BT_UUID_PACS_SNK_VAL 0x2bc9 +/** + * @brief Sink PAC Characteristic + */ +#define BT_UUID_PACS_SNK \ + BT_UUID_DECLARE_16(BT_UUID_PACS_SNK_VAL) +/** + * @brief Sink PAC Locations Characteristic value + */ +#define BT_UUID_PACS_SNK_LOC_VAL 0x2bca +/** + * @brief Sink PAC Locations Characteristic + */ +#define BT_UUID_PACS_SNK_LOC \ + BT_UUID_DECLARE_16(BT_UUID_PACS_SNK_LOC_VAL) +/** + * @brief Source PAC Characteristic value + */ +#define BT_UUID_PACS_SRC_VAL 0x2bcb +/** + * @brief Source PAC Characteristic + */ +#define BT_UUID_PACS_SRC \ + BT_UUID_DECLARE_16(BT_UUID_PACS_SRC_VAL) +/** + * @brief Source PAC Locations Characteristic value + */ +#define BT_UUID_PACS_SRC_LOC_VAL 0x2bcc +/** + * @brief Source PAC Locations Characteristic + */ +#define BT_UUID_PACS_SRC_LOC \ + BT_UUID_DECLARE_16(BT_UUID_PACS_SRC_LOC_VAL) +/** + * @brief Available Audio Contexts Characteristic value + */ +#define BT_UUID_PACS_AVAILABLE_CONTEXT_VAL 0x2bcd +/** + * @brief Available Audio Contexts Characteristic + */ +#define BT_UUID_PACS_AVAILABLE_CONTEXT \ + BT_UUID_DECLARE_16(BT_UUID_PACS_AVAILABLE_CONTEXT_VAL) +/** + * @brief Supported Audio Context Characteristic value + */ +#define BT_UUID_PACS_SUPPORTED_CONTEXT_VAL 0x2bce +/** + * @brief Supported Audio Context Characteristic + */ +#define BT_UUID_PACS_SUPPORTED_CONTEXT \ + BT_UUID_DECLARE_16(BT_UUID_PACS_SUPPORTED_CONTEXT_VAL) +/** + * @brief GATT Characteristic Ammonia Concentration UUID Value + */ +#define BT_UUID_GATT_NH4CONC_VAL 0x2bcf +/** + * @brief GATT Characteristic Ammonia Concentration + */ +#define BT_UUID_GATT_NH4CONC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_NH4CONC_VAL) +/** + * @brief GATT Characteristic Carbon Monoxide Concentration UUID Value + */ +#define BT_UUID_GATT_COCONC_VAL 0x2bd0 +/** + * @brief GATT Characteristic Carbon Monoxide Concentration + */ +#define BT_UUID_GATT_COCONC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_COCONC_VAL) +/** + * @brief GATT Characteristic Methane Concentration UUID Value + */ +#define BT_UUID_GATT_CH4CONC_VAL 0x2bd1 +/** + * @brief GATT Characteristic Methane Concentration + */ +#define BT_UUID_GATT_CH4CONC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_CH4CONC_VAL) +/** + * @brief GATT Characteristic Nitrogen Dioxide Concentration UUID Value + */ +#define BT_UUID_GATT_NO2CONC_VAL 0x2bd2 +/** + * @brief GATT Characteristic Nitrogen Dioxide Concentration + */ +#define BT_UUID_GATT_NO2CONC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_NO2CONC_VAL) +/** + * @brief GATT Characteristic Non-Methane Volatile Organic Compounds Concentration UUID Value + */ +#define BT_UUID_GATT_NONCH4CONC_VAL 0x2bd3 +/** + * @brief GATT Characteristic Non-Methane Volatile Organic Compounds Concentration + */ +#define BT_UUID_GATT_NONCH4CONC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_NONCH4CONC_VAL) +/** + * @brief GATT Characteristic Ozone Concentration UUID Value + */ +#define BT_UUID_GATT_O3CONC_VAL 0x2bd4 +/** + * @brief GATT Characteristic Ozone Concentration + */ +#define BT_UUID_GATT_O3CONC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_O3CONC_VAL) +/** + * @brief GATT Characteristic Particulate Matter - PM1 Concentration UUID Value + */ +#define BT_UUID_GATT_PM1CONC_VAL 0x2bd5 +/** + * @brief GATT Characteristic Particulate Matter - PM1 Concentration + */ +#define BT_UUID_GATT_PM1CONC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_PM1CONC_VAL) +/** + * @brief GATT Characteristic Particulate Matter - PM2.5 Concentration UUID Value + */ +#define BT_UUID_GATT_PM25CONC_VAL 0x2bd6 +/** + * @brief GATT Characteristic Particulate Matter - PM2.5 Concentration + */ +#define BT_UUID_GATT_PM25CONC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_PM25CONC_VAL) +/** + * @brief GATT Characteristic Particulate Matter - PM10 Concentration UUID Value + */ +#define BT_UUID_GATT_PM10CONC_VAL 0x2bd7 +/** + * @brief GATT Characteristic Particulate Matter - PM10 Concentration + */ +#define BT_UUID_GATT_PM10CONC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_PM10CONC_VAL) +/** + * @brief GATT Characteristic Sulfur Dioxide Concentration UUID Value + */ +#define BT_UUID_GATT_SO2CONC_VAL 0x2bd8 +/** + * @brief GATT Characteristic Sulfur Dioxide Concentration + */ +#define BT_UUID_GATT_SO2CONC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_SO2CONC_VAL) +/** + * @brief GATT Characteristic Sulfur Hexafluoride Concentration UUID Value + */ +#define BT_UUID_GATT_SF6CONC_VAL 0x2bd9 +/** + * @brief GATT Characteristic Sulfur Hexafluoride Concentration + */ +#define BT_UUID_GATT_SF6CONC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_SF6CONC_VAL) +/** + * @brief Hearing Aid Features Characteristic value + */ +#define BT_UUID_HAS_HEARING_AID_FEATURES_VAL 0x2bda +/** + * @brief Hearing Aid Features Characteristic + */ +#define BT_UUID_HAS_HEARING_AID_FEATURES \ + BT_UUID_DECLARE_16(BT_UUID_HAS_HEARING_AID_FEATURES_VAL) +/** + * @brief Hearing Aid Preset Control Point Characteristic value + */ +#define BT_UUID_HAS_PRESET_CONTROL_POINT_VAL 0x2bdb +/** + * @brief Hearing Aid Preset Control Point Characteristic + */ +#define BT_UUID_HAS_PRESET_CONTROL_POINT \ + BT_UUID_DECLARE_16(BT_UUID_HAS_PRESET_CONTROL_POINT_VAL) +/** + * @brief Active Preset Index Characteristic value + */ +#define BT_UUID_HAS_ACTIVE_PRESET_INDEX_VAL 0x2bdc +/** + * @brief Active Preset Index Characteristic + */ +#define BT_UUID_HAS_ACTIVE_PRESET_INDEX \ + BT_UUID_DECLARE_16(BT_UUID_HAS_ACTIVE_PRESET_INDEX_VAL) +/** + * @brief GATT Characteristic Fixed String 64 UUID Value + */ +#define BT_UUID_GATT_FSTR64_VAL 0x2bde +/** + * @brief GATT Characteristic Fixed String 64 + */ +#define BT_UUID_GATT_FSTR64 \ + BT_UUID_DECLARE_16(BT_UUID_GATT_FSTR64_VAL) +/** + * @brief GATT Characteristic High Temperature UUID Value + */ +#define BT_UUID_GATT_HITEMP_VAL 0x2bdf +/** + * @brief GATT Characteristic High Temperature + */ +#define BT_UUID_GATT_HITEMP \ + BT_UUID_DECLARE_16(BT_UUID_GATT_HITEMP_VAL) +/** + * @brief GATT Characteristic High Voltage UUID Value + */ +#define BT_UUID_GATT_HV_VAL 0x2be0 +/** + * @brief GATT Characteristic High Voltage + */ +#define BT_UUID_GATT_HV \ + BT_UUID_DECLARE_16(BT_UUID_GATT_HV_VAL) +/** + * @brief GATT Characteristic Light Distribution UUID Value + */ +#define BT_UUID_GATT_LD_VAL 0x2be1 +/** + * @brief GATT Characteristic Light Distribution + */ +#define BT_UUID_GATT_LD \ + BT_UUID_DECLARE_16(BT_UUID_GATT_LD_VAL) +/** + * @brief GATT Characteristic Light Output UUID Value + */ +#define BT_UUID_GATT_LO_VAL 0x2be2 +/** + * @brief GATT Characteristic Light Output + */ +#define BT_UUID_GATT_LO \ + BT_UUID_DECLARE_16(BT_UUID_GATT_LO_VAL) +/** + * @brief GATT Characteristic Light Source Type UUID Value + */ +#define BT_UUID_GATT_LST_VAL 0x2be3 +/** + * @brief GATT Characteristic Light Source Type + */ +#define BT_UUID_GATT_LST \ + BT_UUID_DECLARE_16(BT_UUID_GATT_LST_VAL) +/** + * @brief GATT Characteristic Noise UUID Value + */ +#define BT_UUID_GATT_NOISE_VAL 0x2be4 +/** + * @brief GATT Characteristic Noise + */ +#define BT_UUID_GATT_NOISE \ + BT_UUID_DECLARE_16(BT_UUID_GATT_NOISE_VAL) +/** + * @brief GATT Characteristic Relative Runtime in a Correlated Color Temperature Range UUID Value + */ +#define BT_UUID_GATT_RRCCTP_VAL 0x2be5 +/** + * @brief GATT Characteristic Relative Runtime in a Correlated Color Temperature Range + */ +#define BT_UUID_GATT_RRCCTR \ + BT_UUID_DECLARE_16(BT_UUID_GATT_RRCCTR_VAL) +/** + * @brief GATT Characteristic Time Second 32 UUID Value + */ +#define BT_UUID_GATT_TIM_S32_VAL 0x2be6 +/** + * @brief GATT Characteristic Time Second 32 + */ +#define BT_UUID_GATT_TIM_S32 \ + BT_UUID_DECLARE_16(BT_UUID_GATT_TIM_S32_VAL) +/** + * @brief GATT Characteristic VOC Concentration UUID Value + */ +#define BT_UUID_GATT_VOCCONC_VAL 0x2be7 +/** + * @brief GATT Characteristic VOC Concentration + */ +#define BT_UUID_GATT_VOCCONC \ + BT_UUID_DECLARE_16(BT_UUID_GATT_VOCCONC_VAL) +/** + * @brief GATT Characteristic Voltage Frequency UUID Value + */ +#define BT_UUID_GATT_VF_VAL 0x2be8 +/** + * @brief GATT Characteristic Voltage Frequency + */ +#define BT_UUID_GATT_VF \ + BT_UUID_DECLARE_16(BT_UUID_GATT_VF_VAL) +/** + * @brief BAS Characteristic Battery Critical Status UUID Value + */ +#define BT_UUID_BAS_BATTERY_CRIT_STATUS_VAL 0x2be9 +/** + * @brief BAS Characteristic Battery Critical Status + */ +#define BT_UUID_BAS_BATTERY_CRIT_STATUS \ + BT_UUID_DECLARE_16(BT_UUID_BAS_BATTERY_CRIT_STATUS_VAL) +/** + * @brief BAS Characteristic Battery Health Status UUID Value + */ +#define BT_UUID_BAS_BATTERY_HEALTH_STATUS_VAL 0x2bea +/** + * @brief BAS Characteristic Battery Health Status + */ +#define BT_UUID_BAS_BATTERY_HEALTH_STATUS \ + BT_UUID_DECLARE_16(BT_UUID_BAS_BATTERY_HEALTH_STATUS_VAL) +/** + * @brief BAS Characteristic Battery Health Information UUID Value + */ +#define BT_UUID_BAS_BATTERY_HEALTH_INF_VAL 0x2beb +/** + * @brief BAS Characteristic Battery Health Information + */ +#define BT_UUID_BAS_BATTERY_HEALTH_INF \ + BT_UUID_DECLARE_16(BT_UUID_BAS_BATTERY_HEALTH_INF_VAL) +/** + * @brief BAS Characteristic Battery Information UUID Value + */ +#define BT_UUID_BAS_BATTERY_INF_VAL 0x2bec +/** + * @brief BAS Characteristic Battery Information + */ +#define BT_UUID_BAS_BATTERY_INF \ + BT_UUID_DECLARE_16(BT_UUID_BAS_BATTERY_INF_VAL) +/** + * @brief BAS Characteristic Battery Level Status UUID Value + */ +#define BT_UUID_BAS_BATTERY_LEVEL_STATUS_VAL 0x2bed +/** + * @brief BAS Characteristic Battery Level Status + */ +#define BT_UUID_BAS_BATTERY_LEVEL_STATUS \ + BT_UUID_DECLARE_16(BT_UUID_BAS_BATTERY_LEVEL_STATUS_VAL) +/** + * @brief BAS Characteristic Battery Time Status UUID Value + */ +#define BT_UUID_BAS_BATTERY_TIME_STATUS_VAL 0x2bee +/** + * @brief BAS Characteristic Battery Time Status + */ +#define BT_UUID_BAS_BATTERY_TIME_STATUS \ + BT_UUID_DECLARE_16(BT_UUID_BAS_BATTERY_TIME_STATUS_VAL) +/** + * @brief GATT Characteristic Estimated Service Date UUID Value + */ +#define BT_UUID_GATT_ESD_VAL 0x2bef +/** + * @brief GATT Characteristic Estimated Service Date + */ +#define BT_UUID_GATT_ESD \ + BT_UUID_DECLARE_16(BT_UUID_GATT_ESD_VAL) +/** + * @brief BAS Characteristic Battery Energy Status UUID Value + */ +#define BT_UUID_BAS_BATTERY_ENERGY_STATUS_VAL 0x2bf0 +/** + * @brief BAS Characteristic Battery Energy Status + */ +#define BT_UUID_BAS_BATTERY_ENERGY_STATUS \ + BT_UUID_DECLARE_16(BT_UUID_BAS_BATTERY_ENERGY_STATUS_VAL) +/** + * @brief GATT Characteristic LE GATT Security Levels UUID Value + */ +#define BT_UUID_GATT_SL_VAL 0x2bf5 +/** + * @brief GATT Characteristic LE GATT Security Levels + */ +#define BT_UUID_GATT_SL \ + BT_UUID_DECLARE_16(BT_UUID_GATT_SL_VAL) + +/** + * @brief GATT Characteristic UDI for Medical Devices UUID Value + */ +#define BT_UUID_UDI_FOR_MEDICAL_DEVICES_VAL 0x2bff +/** + * @brief GATT Characteristic UDI for Medical Devices + */ +#define BT_UUID_UDI_FOR_MEDICAL_DEVICES \ + BT_UUID_DECLARE_16(BT_UUID_UDI_FOR_MEDICAL_DEVICES_VAL) + +/** + * @brief Gaming Service UUID value + */ +#define BT_UUID_GMAS_VAL 0x1858 +/** + * @brief Common Audio Service + */ +#define BT_UUID_GMAS BT_UUID_DECLARE_16(BT_UUID_GMAS_VAL) + +/** + * @brief Gaming Audio Profile Role UUID value + */ +#define BT_UUID_GMAP_ROLE_VAL 0x2C00 +/** + * @brief Gaming Audio Profile Role + */ +#define BT_UUID_GMAP_ROLE BT_UUID_DECLARE_16(BT_UUID_GMAP_ROLE_VAL) + +/** + * @brief Gaming Audio Profile Unicast Game Gateway Features UUID value + */ +#define BT_UUID_GMAP_UGG_FEAT_VAL 0x2C01 +/** + * @brief Gaming Audio Profile Unicast Game Gateway Features + */ +#define BT_UUID_GMAP_UGG_FEAT BT_UUID_DECLARE_16(BT_UUID_GMAP_UGG_FEAT_VAL) + +/** + * @brief Gaming Audio Profile Unicast Game Terminal Features UUID value + */ +#define BT_UUID_GMAP_UGT_FEAT_VAL 0x2C02 +/** + * @brief Gaming Audio Profile Unicast Game Terminal Features + */ +#define BT_UUID_GMAP_UGT_FEAT BT_UUID_DECLARE_16(BT_UUID_GMAP_UGT_FEAT_VAL) + +/** + * @brief Gaming Audio Profile Broadcast Game Sender Features UUID value + */ +#define BT_UUID_GMAP_BGS_FEAT_VAL 0x2C03 +/** + * @brief Gaming Audio Profile Broadcast Game Sender Features + */ +#define BT_UUID_GMAP_BGS_FEAT BT_UUID_DECLARE_16(BT_UUID_GMAP_BGS_FEAT_VAL) + +/** + * @brief Gaming Audio Profile Broadcast Game Receiver Features UUID value + */ +#define BT_UUID_GMAP_BGR_FEAT_VAL 0x2C04 +/** + * @brief Gaming Audio Profile Broadcast Game Receiver Features + */ +#define BT_UUID_GMAP_BGR_FEAT BT_UUID_DECLARE_16(BT_UUID_GMAP_BGR_FEAT_VAL) + +/* + * Protocol UUIDs + */ +#define BT_UUID_SDP_VAL 0x0001 +#define BT_UUID_SDP BT_UUID_DECLARE_16(BT_UUID_SDP_VAL) +#define BT_UUID_UDP_VAL 0x0002 +#define BT_UUID_UDP BT_UUID_DECLARE_16(BT_UUID_UDP_VAL) +#define BT_UUID_RFCOMM_VAL 0x0003 +#define BT_UUID_RFCOMM BT_UUID_DECLARE_16(BT_UUID_RFCOMM_VAL) +#define BT_UUID_TCP_VAL 0x0004 +#define BT_UUID_TCP BT_UUID_DECLARE_16(BT_UUID_TCP_VAL) +#define BT_UUID_TCS_BIN_VAL 0x0005 +#define BT_UUID_TCS_BIN BT_UUID_DECLARE_16(BT_UUID_TCS_BIN_VAL) +#define BT_UUID_TCS_AT_VAL 0x0006 +#define BT_UUID_TCS_AT BT_UUID_DECLARE_16(BT_UUID_TCS_AT_VAL) +#define BT_UUID_ATT_VAL 0x0007 +#define BT_UUID_ATT BT_UUID_DECLARE_16(BT_UUID_ATT_VAL) +#define BT_UUID_OBEX_VAL 0x0008 +#define BT_UUID_OBEX BT_UUID_DECLARE_16(BT_UUID_OBEX_VAL) +#define BT_UUID_IP_VAL 0x0009 +#define BT_UUID_IP BT_UUID_DECLARE_16(BT_UUID_IP_VAL) +#define BT_UUID_FTP_VAL 0x000a +#define BT_UUID_FTP BT_UUID_DECLARE_16(BT_UUID_FTP_VAL) +#define BT_UUID_HTTP_VAL 0x000c +#define BT_UUID_HTTP BT_UUID_DECLARE_16(BT_UUID_HTTP_VAL) +#define BT_UUID_WSP_VAL 0x000e +#define BT_UUID_WSP BT_UUID_DECLARE_16(BT_UUID_WSP_VAL) +#define BT_UUID_BNEP_VAL 0x000f +#define BT_UUID_BNEP BT_UUID_DECLARE_16(BT_UUID_BNEP_VAL) +#define BT_UUID_UPNP_VAL 0x0010 +#define BT_UUID_UPNP BT_UUID_DECLARE_16(BT_UUID_UPNP_VAL) +#define BT_UUID_HIDP_VAL 0x0011 +#define BT_UUID_HIDP BT_UUID_DECLARE_16(BT_UUID_HIDP_VAL) +#define BT_UUID_HCRP_CTRL_VAL 0x0012 +#define BT_UUID_HCRP_CTRL BT_UUID_DECLARE_16(BT_UUID_HCRP_CTRL_VAL) +#define BT_UUID_HCRP_DATA_VAL 0x0014 +#define BT_UUID_HCRP_DATA BT_UUID_DECLARE_16(BT_UUID_HCRP_DATA_VAL) +#define BT_UUID_HCRP_NOTE_VAL 0x0016 +#define BT_UUID_HCRP_NOTE BT_UUID_DECLARE_16(BT_UUID_HCRP_NOTE_VAL) +#define BT_UUID_AVCTP_VAL 0x0017 +#define BT_UUID_AVCTP BT_UUID_DECLARE_16(BT_UUID_AVCTP_VAL) +#define BT_UUID_AVCTP_BROWSING_VAL 0x0018 +#define BT_UUID_AVCTP_BROWSING BT_UUID_DECLARE_16(BT_UUID_AVCTP_BROWSING_VAL) +#define BT_UUID_AVDTP_VAL 0x0019 +#define BT_UUID_AVDTP BT_UUID_DECLARE_16(BT_UUID_AVDTP_VAL) +#define BT_UUID_CMTP_VAL 0x001b +#define BT_UUID_CMTP BT_UUID_DECLARE_16(BT_UUID_CMTP_VAL) +#define BT_UUID_UDI_VAL 0x001d +#define BT_UUID_UDI BT_UUID_DECLARE_16(BT_UUID_UDI_VAL) +#define BT_UUID_MCAP_CTRL_VAL 0x001e +#define BT_UUID_MCAP_CTRL BT_UUID_DECLARE_16(BT_UUID_MCAP_CTRL_VAL) +#define BT_UUID_MCAP_DATA_VAL 0x001f +#define BT_UUID_MCAP_DATA BT_UUID_DECLARE_16(BT_UUID_MCAP_DATA_VAL) +#define BT_UUID_L2CAP_VAL 0x0100 +#define BT_UUID_L2CAP BT_UUID_DECLARE_16(BT_UUID_L2CAP_VAL) + +/** @brief Compare Bluetooth UUIDs. + * + * Compares 2 Bluetooth UUIDs, if the types are different both UUIDs are + * first converted to 128 bits format before comparing. + * + * @param u1 First Bluetooth UUID to compare + * @param u2 Second Bluetooth UUID to compare + * + * @return negative value if @a u1 < @a u2, 0 if @a u1 == @a u2, else positive + */ +int bt_uuid_cmp(const struct bt_uuid *u1, const struct bt_uuid *u2); + +/** @brief Create a bt_uuid from a little-endian data buffer. + * + * Create a bt_uuid from a little-endian data buffer. The data_len parameter + * is used to determine whether the UUID is in 16, 32 or 128 bit format + * (length 2, 4 or 16). Note: 32 bit format is not allowed over the air. + * + * @param uuid Pointer to the bt_uuid variable + * @param data pointer to UUID stored in little-endian data buffer + * @param data_len length of the UUID in the data buffer + * + * @return true if the data was valid and the UUID was successfully created. + */ +bool bt_uuid_create(struct bt_uuid *uuid, const uint8_t *data, uint8_t data_len); + +/** @brief Convert Bluetooth UUID to string. + * + * Converts Bluetooth UUID to string. + * UUID can be in any format, 16-bit, 32-bit or 128-bit. + * + * @param uuid Bluetooth UUID + * @param str pointer where to put converted string + * @param len length of str + */ +void bt_uuid_to_str(const struct bt_uuid *uuid, char *str, size_t len); + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_UUID_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/kernel.h b/components/bt/esp_ble_audio/include/zephyr/kernel.h new file mode 100644 index 0000000000..0f863a97d3 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/kernel.h @@ -0,0 +1,161 @@ +/* + * SPDX-FileCopyrightText: 2016 Wind River Systems, Inc. + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include +#include + +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "freertos/semphr.h" +#include "toolchain.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Mutex */ + +#define K_MUTEX_FOREVER portMAX_DELAY + +struct k_mutex { + SemaphoreHandle_t handle; +}; + +static inline void k_mutex_create(struct k_mutex *mutex) +{ + assert(mutex); + assert(mutex->handle == NULL); + + mutex->handle = xSemaphoreCreateRecursiveMutex(); + assert(mutex->handle); +} + +static inline void k_mutex_delete(struct k_mutex *mutex) +{ + assert(mutex); + assert(mutex->handle); + + vSemaphoreDelete(mutex->handle); + mutex->handle = NULL; +} + +static inline int k_mutex_lock(struct k_mutex *mutex, uint32_t timeout) +{ + assert(mutex); + assert(mutex->handle); + + if (xSemaphoreTakeRecursive(mutex->handle, timeout) != pdTRUE) { + LOG_ERR("KMutexLockFail"); + return -EIO; + } + + return 0; +} + +static inline int k_mutex_unlock(struct k_mutex *mutex) +{ + assert(mutex); + assert(mutex->handle); + + if (xSemaphoreGiveRecursive(mutex->handle) != pdTRUE) { + LOG_ERR("KMutexUnlockFail"); + return -EIO; + } + + return 0; +} + +/* Timer */ + +typedef uint32_t k_timeout_t; + +#define K_NO_WAIT 0 +#define K_FOREVER (-1) + +#define MSEC_PER_SEC 1000 +#define K_USEC(t) (t) +#define K_MSEC(ms) (ms) +#define K_SECONDS(s) K_MSEC((s) * MSEC_PER_SEC) +#define K_MINUTES(m) K_SECONDS((m) * 60) +#define K_HOURS(h) K_MINUTES((h) * 60) + +struct k_work; + +typedef void (*k_work_handler_t)(struct k_work *work); + +struct k_work { + void *timer; + k_work_handler_t handler; + int64_t timeout_us; + void *user_data; +}; + +struct k_work_sync { + struct k_work work; +}; + +struct k_work_delayable { + struct k_work work; +}; + +#define K_WORK_DEFINE(work, work_handler) \ + struct k_work work = { \ + .handler = work_handler, \ + } + +#define K_WORK_DELAYABLE_DEFINE(dwork, work_handler) \ + struct k_work_delayable dwork = { \ + .work.handler = work_handler, \ + } + +#define K_TIMEOUT_EQ(a, b) ((a) == (b)) + +typedef void (*k_work_handler_t)(struct k_work *work); + +int k_work_submit(struct k_work *work); + +bool k_work_is_pending(struct k_work *work); + +void k_work_init(struct k_work *work, k_work_handler_t handler); + +struct k_work_delayable *k_work_delayable_from_work(struct k_work *work); + +void k_work_init_delayable(struct k_work_delayable *dwork, + k_work_handler_t handler); + +void k_work_deinit_delayable(struct k_work_delayable *dwork); + +int k_work_cancel_delayable(struct k_work_delayable *dwork); + +bool k_work_cancel_delayable_sync(struct k_work_delayable *dwork, + struct k_work_sync *sync); + +int k_work_schedule(struct k_work_delayable *dwork, k_timeout_t delay); + +int k_work_reschedule(struct k_work_delayable *dwork, k_timeout_t delay); + +int k_work_schedule_periodic(struct k_work_delayable *dwork, k_timeout_t period_ms); + +k_timeout_t k_work_delayable_remaining_get(struct k_work_delayable *dwork); + +/* Slist */ + +struct k_fifo { + sys_slist_t slist; +}; + +#ifdef __cplusplus +} +#endif diff --git a/components/bt/esp_ble_audio/include/zephyr/logging/log.h b/components/bt/esp_ble_audio/include/zephyr/logging/log.h new file mode 100644 index 0000000000..de95ea05bd --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/logging/log.h @@ -0,0 +1,121 @@ +/* + * SPDX-FileCopyrightText: 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_LOGGING_LOG_H_ +#define ZEPHYR_INCLUDE_LOGGING_LOG_H_ + +#include +#include + +#include "sdkconfig.h" + +#include "esp_log.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern int ets_printf(const char *fmt, ...); + +#define LOG_MODULE_REGISTER(...) + +#define LOG_MODULE_DECLARE(...) + +#define BT_ISO_LOG_COLOR_BLACK "30" +#define BT_ISO_LOG_COLOR_RED "31" +#define BT_ISO_LOG_COLOR_GREEN "32" +#define BT_ISO_LOG_COLOR_YELLOW "33" +#define BT_ISO_LOG_COLOR_BLUE "34" +#define BT_ISO_LOG_COLOR_PURPLE "35" +#define BT_ISO_LOG_COLOR_CYAN "36" +#define BT_ISO_LOG_COLOR_WHITE "37" +#define BT_ISO_LOG_COLOR(COLOR) "\033[0;" COLOR "m" +#define BT_ISO_LOG_BOLD(COLOR) "\033[1;" COLOR "m" +#define BT_ISO_LOG_RESET_COLOR "\033[0m" +#define BT_ISO_LOG_COLOR_E BT_ISO_LOG_COLOR(BT_ISO_LOG_COLOR_RED) +#define BT_ISO_LOG_COLOR_W BT_ISO_LOG_COLOR(BT_ISO_LOG_COLOR_YELLOW) +#define BT_ISO_LOG_COLOR_I BT_ISO_LOG_COLOR(BT_ISO_LOG_COLOR_GREEN) +#define BT_ISO_LOG_COLOR_D BT_ISO_LOG_COLOR(BT_ISO_LOG_COLOR_WHITE) +#define BT_ISO_LOG_COLOR_V BT_ISO_LOG_COLOR(BT_ISO_LOG_COLOR_WHITE) + +#define BT_ISO_LOG_ERROR 1 +#define BT_ISO_LOG_WARN 2 +#define BT_ISO_LOG_INFO 3 +#define BT_ISO_LOG_DEBUG 4 +#define BT_ISO_LOG_VERBOSE 5 + +#define BT_AUDIO_LOG_ERROR BT_ISO_LOG_ERROR +#define BT_AUDIO_LOG_WARN BT_ISO_LOG_WARN +#define BT_AUDIO_LOG_INFO BT_ISO_LOG_INFO +#define BT_AUDIO_LOG_DEBUG BT_ISO_LOG_DEBUG +#define BT_AUDIO_LOG_VERBOSE BT_ISO_LOG_VERBOSE + +#define BT_ISO_LOG_TAG "ISO" + +#define BT_ISO_LOGE(tag, format, ...) \ + esp_log_write(ESP_LOG_ERROR, tag, LOG_FORMAT(E, format), \ + esp_log_timestamp(), tag, ##__VA_ARGS__); + +#define BT_ISO_LOGW(tag, format, ...) \ + esp_log_write(ESP_LOG_WARN, tag, LOG_FORMAT(W, format), \ + esp_log_timestamp(), tag, ##__VA_ARGS__); + +#define BT_ISO_LOGI(tag, format, ...) \ + esp_log_write(ESP_LOG_INFO, tag, LOG_FORMAT(I, format), \ + esp_log_timestamp(), tag, ##__VA_ARGS__); + +#define BT_ISO_LOGD(tag, format, ...) \ + esp_log_write(ESP_LOG_INFO, tag, LOG_FORMAT(D, format), \ + esp_log_timestamp(), tag, ##__VA_ARGS__); + +#if CONFIG_BT_ISO_NO_LOG +#define LOG_ERR(fmt, args...) +#define LOG_WRN(fmt, args...) +#define LOG_INF(fmt, args...) +#define LOG_DBG(fmt, args...) +#else /* CONFIG_BT_ISO_NO_LOG */ +#if (CONFIG_BT_ISO_LOG_LEVEL >= BT_ISO_LOG_ERROR) +#define LOG_ERR(fmt, args...) BT_ISO_LOGE(BT_ISO_LOG_TAG, fmt, ## args) +#else /* (CONFIG_BT_ISO_LOG_LEVEL >= BT_ISO_LOG_ERROR) */ +#define LOG_ERR(fmt, args...) +#endif /* (CONFIG_BT_ISO_LOG_LEVEL >= BT_ISO_LOG_ERROR) */ + +#if (CONFIG_BT_ISO_LOG_LEVEL >= BT_ISO_LOG_WARN) +#define LOG_WRN(fmt, args...) BT_ISO_LOGW(BT_ISO_LOG_TAG, fmt, ## args) +#else /* (CONFIG_BT_ISO_LOG_LEVEL >= BT_ISO_LOG_WARN) */ +#define LOG_WRN(fmt, args...) +#endif /* (CONFIG_BT_ISO_LOG_LEVEL >= BT_ISO_LOG_WARN) */ + +#if (CONFIG_BT_ISO_LOG_LEVEL >= BT_ISO_LOG_INFO) +#define LOG_INF(fmt, args...) BT_ISO_LOGI(BT_ISO_LOG_TAG, fmt, ## args) +#else /* (CONFIG_BT_ISO_LOG_LEVEL >= BT_ISO_LOG_INFO) */ +#define LOG_INF(fmt, args...) +#endif /* (CONFIG_BT_ISO_LOG_LEVEL >= BT_ISO_LOG_INFO) */ + +#if (CONFIG_BT_ISO_LOG_LEVEL >= BT_ISO_LOG_DEBUG) +#define LOG_DBG(fmt, args...) BT_ISO_LOGD(BT_ISO_LOG_TAG, fmt, ## args) +#else /* (CONFIG_BT_ISO_LOG_LEVEL >= BT_ISO_LOG_DEBUG) */ +#define LOG_DBG(fmt, args...) +#endif /* (CONFIG_BT_ISO_LOG_LEVEL >= BT_ISO_LOG_DEBUG) */ +#endif /* CONFIG_BT_ISO_NO_LOG */ + +#define NET_BUF_ERR(fmt, args...) /* TBD */ +#define NET_BUF_WARN(fmt, args...) /* TBD */ +#define NET_BUF_INFO(fmt, args...) /* TBD */ +#define NET_BUF_DBG(fmt, args...) /* TBD */ +#define NET_BUF_ASSERT assert + +#define NET_BUF_SIMPLE_ERR(fmt, args...) /* TBD */ +#define NET_BUF_SIMPLE_WARN(fmt, args...) /* TBD */ +#define NET_BUF_SIMPLE_INFO(fmt, args...) /* TBD */ +#define NET_BUF_SIMPLE_DBG(fmt, args...) /* TBD */ +#define NET_BUF_SIMPLE_ASSERT assert + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_LOGGING_LOG_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/net_buf.h b/components/bt/esp_ble_audio/include/zephyr/net_buf.h new file mode 100644 index 0000000000..e2024cdad8 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/net_buf.h @@ -0,0 +1,1766 @@ +/* + * SPDX-FileCopyrightText: 2015 Intel Corporation + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BT_AUDIO_BUF_H_ +#define _BT_AUDIO_BUF_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Unaligned access */ +#define UNALIGNED_GET(p) \ +__extension__ ({ \ + struct __attribute__((__packed__)) { \ + __typeof__(*(p)) __v; \ + } *__p = (__typeof__(__p)) (p); \ + __p->__v; \ +}) + +#define NET_BUF_USER_DATA_SIZE 8 + +/** + * @brief Network buffer library + * @defgroup net_buf Network Buffer Library + * @ingroup networking + * @{ + */ + +/* Alignment needed for various parts of the buffer definition */ +#define __net_buf_align __attribute__((__aligned__(sizeof(int)))) + +/** + * @def NET_BUF_SIMPLE_DEFINE + * @brief Define a net_buf_simple stack variable. + * + * This is a helper macro which is used to define a net_buf_simple object + * on the stack. + * + * @param _name Name of the net_buf_simple object. + * @param _size Maximum data storage for the buffer. + */ +#define NET_BUF_SIMPLE_DEFINE(_name, _size) \ + uint8_t net_buf_data_##_name[_size]; \ + struct net_buf_simple _name = { \ + .data = net_buf_data_##_name, \ + .len = 0, \ + .size = _size, \ + .__buf = net_buf_data_##_name, \ + } + +/** + * @def NET_BUF_SIMPLE_DEFINE_STATIC + * @brief Define a static net_buf_simple variable. + * + * This is a helper macro which is used to define a static net_buf_simple + * object. + * + * @param _name Name of the net_buf_simple object. + * @param _size Maximum data storage for the buffer. + */ +#define NET_BUF_SIMPLE_DEFINE_STATIC(_name, _size) \ + static uint8_t net_buf_data_##_name[_size]; \ + static struct net_buf_simple _name = { \ + .data = net_buf_data_##_name, \ + .len = 0, \ + .size = _size, \ + .__buf = net_buf_data_##_name, \ + } + +/** + * @brief Simple network buffer representation. + * + * This is a simpler variant of the net_buf object (in fact net_buf uses + * net_buf_simple internally). It doesn't provide any kind of reference + * counting, user data, dynamic allocation, or in general the ability to + * pass through kernel objects such as FIFOs. + * + * The main use of this is for scenarios where the meta-data of the normal + * net_buf isn't needed and causes too much overhead. This could be e.g. + * when the buffer only needs to be allocated on the stack or when the + * access to and lifetime of the buffer is well controlled and constrained. + */ +struct net_buf_simple { + /** Pointer to the start of data in the buffer. */ + uint8_t *data; + + /** Length of the data behind the data pointer. */ + uint16_t len; + + /** Amount of data that this buffer can store. */ + uint16_t size; + + /** Start of the data storage. Not to be accessed directly + * (the data pointer should be used instead). + */ + uint8_t *__buf; +}; + +/** + * @def NET_BUF_SIMPLE + * @brief Define a net_buf_simple stack variable and get a pointer to it. + * + * This is a helper macro which is used to define a net_buf_simple object on + * the stack and the get a pointer to it as follows: + * + * struct net_buf_simple *my_buf = NET_BUF_SIMPLE(10); + * + * After creating the object it needs to be initialized by calling + * net_buf_simple_init(). + * + * @param _size Maximum data storage for the buffer. + * + * @return Pointer to stack-allocated net_buf_simple object. + */ +#define NET_BUF_SIMPLE(_size) \ + ((struct net_buf_simple *)(&(struct { \ + struct net_buf_simple buf; \ + uint8_t data[_size] __net_buf_align; \ + }) { \ + .buf.size = _size, \ + .buf.__buf = NULL, \ + })) + +/** + * @brief Initialize a net_buf_simple object. + * + * This needs to be called after creating a net_buf_simple object using + * the NET_BUF_SIMPLE macro. + * + * @param buf Buffer to initialize. + * @param reserve_head Headroom to reserve. + */ +static inline void net_buf_simple_init(struct net_buf_simple *buf, + size_t reserve_head) +{ + if (!buf->__buf) { + buf->__buf = (uint8_t *)buf + sizeof(*buf); + } + + buf->data = buf->__buf + reserve_head; + buf->len = 0; +} + +/** + * @brief Initialize a net_buf_simple object with data. + * + * Initialized buffer object with external data. + * + * @param buf Buffer to initialize. + * @param data External data pointer + * @param size Amount of data the pointed data buffer if able to fit. + */ +void net_buf_simple_init_with_data(struct net_buf_simple *buf, + void *data, size_t size); + +/** + * @brief Reset buffer + * + * Reset buffer data so it can be reused for other purposes. + * + * @param buf Buffer to reset. + */ +static inline void net_buf_simple_reset(struct net_buf_simple *buf) +{ + buf->len = 0; + buf->data = buf->__buf; +} + +/** + * Clone buffer state, using the same data buffer. + * + * Initializes a buffer to point to the same data as an existing buffer. + * Allows operations on the same data without altering the length and + * offset of the original. + * + * @param original Buffer to clone. + * @param clone The new clone. + */ +void net_buf_simple_clone(const struct net_buf_simple *original, + struct net_buf_simple *clone); + +/** + * @brief Prepare data to be added at the end of the buffer + * + * Increments the data length of a buffer to account for more data + * at the end. + * + * @param buf Buffer to update. + * @param len Number of bytes to increment the length with. + * + * @return The original tail of the buffer. + */ +void *net_buf_simple_add(struct net_buf_simple *buf, size_t len); + +/** + * @brief Copy given number of bytes from memory to the end of the buffer + * + * Increments the data length of the buffer to account for more data at the + * end. + * + * @param buf Buffer to update. + * @param mem Location of data to be added. + * @param len Length of data to be added + * + * @return The original tail of the buffer. + */ +void *net_buf_simple_add_mem(struct net_buf_simple *buf, const void *mem, + size_t len); + +/** + * @brief Add (8-bit) byte at the end of the buffer + * + * Increments the data length of the buffer to account for more data at the + * end. + * + * @param buf Buffer to update. + * @param val byte value to be added. + * + * @return Pointer to the value added + */ +uint8_t *net_buf_simple_add_u8(struct net_buf_simple *buf, uint8_t val); + +/** + * @brief Add 16-bit value at the end of the buffer + * + * Adds 16-bit value in little endian format at the end of buffer. + * Increments the data length of a buffer to account for more data + * at the end. + * + * @param buf Buffer to update. + * @param val 16-bit value to be added. + */ +void net_buf_simple_add_le16(struct net_buf_simple *buf, uint16_t val); + +/** + * @brief Add 16-bit value at the end of the buffer + * + * Adds 16-bit value in big endian format at the end of buffer. + * Increments the data length of a buffer to account for more data + * at the end. + * + * @param buf Buffer to update. + * @param val 16-bit value to be added. + */ +void net_buf_simple_add_be16(struct net_buf_simple *buf, uint16_t val); + +/** + * @brief Add 24-bit value at the end of the buffer + * + * Adds 24-bit value in little endian format at the end of buffer. + * Increments the data length of a buffer to account for more data + * at the end. + * + * @param buf Buffer to update. + * @param val 24-bit value to be added. + */ +void net_buf_simple_add_le24(struct net_buf_simple *buf, uint32_t val); + +/** + * @brief Add 24-bit value at the end of the buffer + * + * Adds 24-bit value in big endian format at the end of buffer. + * Increments the data length of a buffer to account for more data + * at the end. + * + * @param buf Buffer to update. + * @param val 24-bit value to be added. + */ +void net_buf_simple_add_be24(struct net_buf_simple *buf, uint32_t val); + +/** + * @brief Add 32-bit value at the end of the buffer + * + * Adds 32-bit value in little endian format at the end of buffer. + * Increments the data length of a buffer to account for more data + * at the end. + * + * @param buf Buffer to update. + * @param val 32-bit value to be added. + */ +void net_buf_simple_add_le32(struct net_buf_simple *buf, uint32_t val); + +/** + * @brief Add 32-bit value at the end of the buffer + * + * Adds 32-bit value in big endian format at the end of buffer. + * Increments the data length of a buffer to account for more data + * at the end. + * + * @param buf Buffer to update. + * @param val 32-bit value to be added. + */ +void net_buf_simple_add_be32(struct net_buf_simple *buf, uint32_t val); + +/** + * @brief Add 48-bit value at the end of the buffer + * + * Adds 48-bit value in little endian format at the end of buffer. + * Increments the data length of a buffer to account for more data + * at the end. + * + * @param buf Buffer to update. + * @param val 48-bit value to be added. + */ +void net_buf_simple_add_le48(struct net_buf_simple *buf, uint64_t val); + +/** + * @brief Add 48-bit value at the end of the buffer + * + * Adds 48-bit value in big endian format at the end of buffer. + * Increments the data length of a buffer to account for more data + * at the end. + * + * @param buf Buffer to update. + * @param val 48-bit value to be added. + */ +void net_buf_simple_add_be48(struct net_buf_simple *buf, uint64_t val); + +/** + * @brief Add 64-bit value at the end of the buffer + * + * Adds 64-bit value in little endian format at the end of buffer. + * Increments the data length of a buffer to account for more data + * at the end. + * + * @param buf Buffer to update. + * @param val 64-bit value to be added. + */ +void net_buf_simple_add_le64(struct net_buf_simple *buf, uint64_t val); + +/** + * @brief Add 64-bit value at the end of the buffer + * + * Adds 64-bit value in big endian format at the end of buffer. + * Increments the data length of a buffer to account for more data + * at the end. + * + * @param buf Buffer to update. + * @param val 64-bit value to be added. + */ +void net_buf_simple_add_be64(struct net_buf_simple *buf, uint64_t val); + +/** + * @brief Push data to the beginning of the buffer. + * + * Modifies the data pointer and buffer length to account for more data + * in the beginning of the buffer. + * + * @param buf Buffer to update. + * @param len Number of bytes to add to the beginning. + * + * @return The new beginning of the buffer data. + */ +void *net_buf_simple_push(struct net_buf_simple *buf, size_t len); + +/** + * @brief Push 16-bit value to the beginning of the buffer + * + * Adds 16-bit value in little endian format to the beginning of the + * buffer. + * + * @param buf Buffer to update. + * @param val 16-bit value to be pushed to the buffer. + */ +void net_buf_simple_push_le16(struct net_buf_simple *buf, uint16_t val); + +/** + * @brief Push 16-bit value to the beginning of the buffer + * + * Adds 16-bit value in big endian format to the beginning of the + * buffer. + * + * @param buf Buffer to update. + * @param val 16-bit value to be pushed to the buffer. + */ +void net_buf_simple_push_be16(struct net_buf_simple *buf, uint16_t val); + +/** + * @brief Push 8-bit value to the beginning of the buffer + * + * Adds 8-bit value the beginning of the buffer. + * + * @param buf Buffer to update. + * @param val 8-bit value to be pushed to the buffer. + */ +void net_buf_simple_push_u8(struct net_buf_simple *buf, uint8_t val); + +/** + * @brief Push 24-bit value to the beginning of the buffer + * + * Adds 24-bit value in little endian format to the beginning of the + * buffer. + * + * @param buf Buffer to update. + * @param val 24-bit value to be pushed to the buffer. + */ +void net_buf_simple_push_le24(struct net_buf_simple *buf, uint32_t val); + +/** + * @brief Push 24-bit value to the beginning of the buffer + * + * Adds 24-bit value in big endian format to the beginning of the + * buffer. + * + * @param buf Buffer to update. + * @param val 24-bit value to be pushed to the buffer. + */ +void net_buf_simple_push_be24(struct net_buf_simple *buf, uint32_t val); + +/** + * @brief Push 32-bit value to the beginning of the buffer + * + * Adds 32-bit value in little endian format to the beginning of the + * buffer. + * + * @param buf Buffer to update. + * @param val 32-bit value to be pushed to the buffer. + */ +void net_buf_simple_push_le32(struct net_buf_simple *buf, uint32_t val); + +/** + * @brief Push 32-bit value to the beginning of the buffer + * + * Adds 32-bit value in big endian format to the beginning of the + * buffer. + * + * @param buf Buffer to update. + * @param val 32-bit value to be pushed to the buffer. + */ +void net_buf_simple_push_be32(struct net_buf_simple *buf, uint32_t val); + +/** + * @brief Push 48-bit value to the beginning of the buffer + * + * Adds 48-bit value in little endian format to the beginning of the + * buffer. + * + * @param buf Buffer to update. + * @param val 48-bit value to be pushed to the buffer. + */ +void net_buf_simple_push_le48(struct net_buf_simple *buf, uint64_t val); + +/** + * @brief Push 48-bit value to the beginning of the buffer + * + * Adds 48-bit value in big endian format to the beginning of the + * buffer. + * + * @param buf Buffer to update. + * @param val 48-bit value to be pushed to the buffer. + */ +void net_buf_simple_push_be48(struct net_buf_simple *buf, uint64_t val); + +/** + * @brief Push 64-bit value to the beginning of the buffer + * + * Adds 64-bit value in little endian format to the beginning of the + * buffer. + * + * @param buf Buffer to update. + * @param val 64-bit value to be pushed to the buffer. + */ +void net_buf_simple_push_le64(struct net_buf_simple *buf, uint64_t val); + +/** + * @brief Push 64-bit value to the beginning of the buffer + * + * Adds 64-bit value in big endian format to the beginning of the + * buffer. + * + * @param buf Buffer to update. + * @param val 64-bit value to be pushed to the buffer. + */ +void net_buf_simple_push_be64(struct net_buf_simple *buf, uint64_t val); + +/** + * @brief Remove data from the beginning of the buffer. + * + * Removes data from the beginning of the buffer by modifying the data + * pointer and buffer length. + * + * @param buf Buffer to update. + * @param len Number of bytes to remove. + * + * @return New beginning of the buffer data. + */ +void *net_buf_simple_pull(struct net_buf_simple *buf, size_t len); + +/** + * @brief Remove data from the beginning of the buffer. + * + * Removes data from the beginning of the buffer by modifying the data + * pointer and buffer length. + * + * @param buf Buffer to update. + * @param len Number of bytes to remove. + * + * @return Pointer to the old location of the buffer data. + */ +void *net_buf_simple_pull_mem(struct net_buf_simple *buf, size_t len); + +/** + * @brief Remove a 8-bit value from the beginning of the buffer + * + * Same idea as with net_buf_simple_pull(), but a helper for operating + * on 8-bit values. + * + * @param buf A valid pointer on a buffer. + * + * @return The 8-bit removed value + */ +uint8_t net_buf_simple_pull_u8(struct net_buf_simple *buf); + +/** + * @brief Remove and convert 16 bits from the beginning of the buffer. + * + * Same idea as with net_buf_simple_pull(), but a helper for operating + * on 16-bit little endian data. + * + * @param buf A valid pointer on a buffer. + * + * @return 16-bit value converted from little endian to host endian. + */ +uint16_t net_buf_simple_pull_le16(struct net_buf_simple *buf); + +/** + * @brief Remove and convert 16 bits from the beginning of the buffer. + * + * Same idea as with net_buf_simple_pull(), but a helper for operating + * on 16-bit big endian data. + * + * @param buf A valid pointer on a buffer. + * + * @return 16-bit value converted from big endian to host endian. + */ +uint16_t net_buf_simple_pull_be16(struct net_buf_simple *buf); + +/** + * @brief Remove and convert 24 bits from the beginning of the buffer. + * + * Same idea as with net_buf_simple_pull(), but a helper for operating + * on 24-bit little endian data. + * + * @param buf A valid pointer on a buffer. + * + * @return 24-bit value converted from little endian to host endian. + */ +uint32_t net_buf_simple_pull_le24(struct net_buf_simple *buf); + +/** + * @brief Remove and convert 24 bits from the beginning of the buffer. + * + * Same idea as with net_buf_simple_pull(), but a helper for operating + * on 24-bit big endian data. + * + * @param buf A valid pointer on a buffer. + * + * @return 24-bit value converted from big endian to host endian. + */ +uint32_t net_buf_simple_pull_be24(struct net_buf_simple *buf); + +/** + * @brief Remove and convert 32 bits from the beginning of the buffer. + * + * Same idea as with net_buf_simple_pull(), but a helper for operating + * on 32-bit little endian data. + * + * @param buf A valid pointer on a buffer. + * + * @return 32-bit value converted from little endian to host endian. + */ +uint32_t net_buf_simple_pull_le32(struct net_buf_simple *buf); + +/** + * @brief Remove and convert 32 bits from the beginning of the buffer. + * + * Same idea as with net_buf_simple_pull(), but a helper for operating + * on 32-bit big endian data. + * + * @param buf A valid pointer on a buffer. + * + * @return 32-bit value converted from big endian to host endian. + */ +uint32_t net_buf_simple_pull_be32(struct net_buf_simple *buf); + +/** + * @brief Remove and convert 48 bits from the beginning of the buffer. + * + * Same idea as with net_buf_simple_pull(), but a helper for operating + * on 48-bit little endian data. + * + * @param buf A valid pointer on a buffer. + * + * @return 48-bit value converted from little endian to host endian. + */ +uint64_t net_buf_simple_pull_le48(struct net_buf_simple *buf); + +/** + * @brief Remove and convert 48 bits from the beginning of the buffer. + * + * Same idea as with net_buf_simple_pull(), but a helper for operating + * on 48-bit big endian data. + * + * @param buf A valid pointer on a buffer. + * + * @return 48-bit value converted from big endian to host endian. + */ +uint64_t net_buf_simple_pull_be48(struct net_buf_simple *buf); + +/** + * @brief Remove and convert 64 bits from the beginning of the buffer. + * + * Same idea as with net_buf_simple_pull(), but a helper for operating + * on 64-bit little endian data. + * + * @param buf A valid pointer on a buffer. + * + * @return 64-bit value converted from little endian to host endian. + */ +uint64_t net_buf_simple_pull_le64(struct net_buf_simple *buf); + +/** + * @brief Remove and convert 64 bits from the beginning of the buffer. + * + * Same idea as with net_buf_simple_pull(), but a helper for operating + * on 64-bit big endian data. + * + * @param buf A valid pointer on a buffer. + * + * @return 64-bit value converted from big endian to host endian. + */ +uint64_t net_buf_simple_pull_be64(struct net_buf_simple *buf); + +/** + * @brief Get the tail pointer for a buffer. + * + * Get a pointer to the end of the data in a buffer. + * + * @param buf Buffer. + * + * @return Tail pointer for the buffer. + */ +static inline uint8_t *net_buf_simple_tail(struct net_buf_simple *buf) +{ + return buf->data + buf->len; +} + +/** + * @brief Check buffer headroom. + * + * Check how much free space there is in the beginning of the buffer. + * + * buf A valid pointer on a buffer + * + * @return Number of bytes available in the beginning of the buffer. + */ +size_t net_buf_simple_headroom(const struct net_buf_simple *buf); + +/** + * @brief Check buffer tailroom. + * + * Check how much free space there is at the end of the buffer. + * + * @param buf A valid pointer on a buffer + * + * @return Number of bytes available at the end of the buffer. + */ +size_t net_buf_simple_tailroom(struct net_buf_simple *buf); + +/** + * @brief Parsing state of a buffer. + * + * This is used for temporarily storing the parsing state of a buffer + * while giving control of the parsing to a routine which we don't + * control. + */ +struct net_buf_simple_state { + /** Offset of the data pointer from the beginning of the storage */ + uint16_t offset; + /** Length of data */ + uint16_t len; +}; + +/** + * @brief Save the parsing state of a buffer. + * + * Saves the parsing state of a buffer so it can be restored later. + * + * @param buf Buffer from which the state should be saved. + * @param state Storage for the state. + */ +static inline void net_buf_simple_save(struct net_buf_simple *buf, + struct net_buf_simple_state *state) +{ + state->offset = net_buf_simple_headroom(buf); + state->len = buf->len; +} + +/** + * @brief Restore the parsing state of a buffer. + * + * Restores the parsing state of a buffer from a state previously stored + * by net_buf_simple_save(). + * + * @param buf Buffer to which the state should be restored. + * @param state Stored state. + */ +static inline void net_buf_simple_restore(struct net_buf_simple *buf, + struct net_buf_simple_state *state) +{ + buf->data = buf->__buf + state->offset; + buf->len = state->len; +} + +/** + * @brief Initialize buffer with the given headroom. + * + * The buffer is not expected to contain any data when this API is called. + * + * @param buf Buffer to initialize. + * @param reserve How much headroom to reserve. + */ +void net_buf_simple_reserve(struct net_buf_simple *buf, size_t reserve); + +/** + * Flag indicating that the buffer has associated fragments. Only used + * internally by the buffer handling code while the buffer is inside a + * FIFO, meaning this never needs to be explicitly set or unset by the + * net_buf API user. As long as the buffer is outside of a FIFO, i.e. + * in practice always for the user for this API, the buf->frags pointer + * should be used instead. + */ +#define NET_BUF_FRAGS BIT(0) + +/** + * @brief Network buffer representation. + * + * This struct is used to represent network buffers. Such buffers are + * normally defined through the NET_BUF_POOL_*_DEFINE() APIs and allocated + * using the net_buf_alloc() API. + */ +struct net_buf { + union { + /** Allow placing the buffer into sys_slist_t */ + sys_snode_t node; + + /** Fragments associated with this buffer. */ + struct net_buf *frags; + }; + + /** Reference count. */ + uint8_t ref; + + /** Bit-field of buffer flags. */ + uint8_t flags; + + /** Where the buffer should go when freed up. */ + uint8_t pool_id; + + /** Where the buffer should go when freed up. */ + struct net_buf_pool *pool; + + /** Size of user data on this buffer */ + uint8_t user_data_size; + + /* Union for convenience access to the net_buf_simple members, also + * preserving the old API. + */ + union { + /* The ABI of this struct must match net_buf_simple */ + struct { + /** Pointer to the start of data in the buffer. */ + uint8_t *data; + + /** Length of the data behind the data pointer. */ + uint16_t len; + + /** Amount of data that this buffer can store. */ + uint16_t size; + + /** Start of the data storage. Not to be accessed + * directly (the data pointer should be used + * instead). + */ + uint8_t *__buf; + }; + + struct net_buf_simple b; + }; + + /** System metadata for this buffer. */ + uint8_t user_data[NET_BUF_USER_DATA_SIZE] __net_buf_align; +}; + +struct net_buf_data_cb { + uint8_t *(*alloc)(struct net_buf *buf, size_t *size, int32_t timeout); + uint8_t *(*ref)(struct net_buf *buf, uint8_t *data); + void (*unref)(struct net_buf *buf, uint8_t *data); +}; + +struct net_buf_data_alloc { + const struct net_buf_data_cb *cb; + void *alloc_data; +}; + +struct net_buf_pool { + /** Number of buffers in pool */ + const uint16_t buf_count; + + /** Number of uninitialized buffers */ + uint16_t uninit_count; + +#if defined(CONFIG_NET_BUF_POOL_USAGE) + /** Amount of available buffers in the pool. */ + int16_t avail_count; + + /** Total size of the pool. */ + const uint16_t pool_size; + + /** Name of the pool. Used when printing pool information. */ + const char *name; +#endif /* CONFIG_NET_BUF_POOL_USAGE */ + + /** Optional destroy callback when buffer is freed. */ + void (*const destroy)(struct net_buf *buf); + + /** Data allocation handlers. */ + const struct net_buf_data_alloc *alloc; + + /** Helper to access the start of storage (for net_buf_pool_init) */ + struct net_buf *const __bufs; +}; + +#if defined(CONFIG_NET_BUF_POOL_USAGE) +#define NET_BUF_POOL_INITIALIZER(_pool, _alloc, _bufs, _count, _destroy) \ + { \ + .alloc = _alloc, \ + .__bufs = (struct net_buf *)_bufs, \ + .buf_count = _count, \ + .uninit_count = _count, \ + .avail_count = _count, \ + .destroy = _destroy, \ + .name = STRINGIFY(_pool), \ + } +#else +#define NET_BUF_POOL_INITIALIZER(_pool, _alloc, _bufs, _count, _destroy) \ + { \ + .alloc = _alloc, \ + .__bufs = (struct net_buf *)_bufs, \ + .buf_count = _count, \ + .uninit_count = _count, \ + .destroy = _destroy, \ + } +#endif /* CONFIG_NET_BUF_POOL_USAGE */ + +struct net_buf_pool_fixed { + size_t data_size; + uint8_t *data_pool; +}; + +/** @cond INTERNAL_HIDDEN */ +extern const struct net_buf_data_cb net_buf_fixed_cb; + +/** + * @def NET_BUF_POOL_FIXED_DEFINE + * @brief Define a new pool for buffers based on fixed-size data + * + * Defines a net_buf_pool struct and the necessary memory storage (array of + * structs) for the needed amount of buffers. After this, the buffers can be + * accessed from the pool through net_buf_alloc. The pool is defined as a + * static variable, so if it needs to be exported outside the current module + * this needs to happen with the help of a separate pointer rather than an + * extern declaration. + * + * The data payload of the buffers will be allocated from a byte array + * of fixed sized chunks. This kind of pool does not support blocking on + * the data allocation, so the timeout passed to net_buf_alloc will be + * always treated as K_NO_WAIT when trying to allocate the data. This means + * that allocation failures, i.e. NULL returns, must always be handled + * cleanly. + * + * If provided with a custom destroy callback, this callback is + * responsible for eventually calling net_buf_destroy() to complete the + * process of returning the buffer to the pool. + * + * @param _name Name of the pool variable. + * @param _count Number of buffers in the pool. + * @param _data_size Maximum data payload per buffer. + * @param _ud_size User data space to reserve per buffer. + * @param _destroy Optional destroy callback when buffer is freed. + */ +#define NET_BUF_POOL_FIXED_DEFINE(_name, _count, _data_size, _ud_size, _destroy) \ + static struct net_buf net_buf_##_name[_count]; \ + static uint8_t net_buf_data_##_name[_count][_data_size]; \ + static const struct net_buf_pool_fixed net_buf_fixed_##_name = { \ + .data_size = _data_size, \ + .data_pool = (uint8_t *)net_buf_data_##_name, \ + }; \ + static const struct net_buf_data_alloc net_buf_fixed_alloc_##_name = { \ + .cb = &net_buf_fixed_cb, \ + .alloc_data = (void *)&net_buf_fixed_##_name, \ + }; \ + struct net_buf_pool _name = \ + NET_BUF_POOL_INITIALIZER(_name, &net_buf_fixed_alloc_##_name, \ + net_buf_##_name, _count, _destroy) + +/** + * @def NET_BUF_POOL_DEFINE + * @brief Define a new pool for buffers + * + * Defines a net_buf_pool struct and the necessary memory storage (array of + * structs) for the needed amount of buffers. After this,the buffers can be + * accessed from the pool through net_buf_alloc. The pool is defined as a + * static variable, so if it needs to be exported outside the current module + * this needs to happen with the help of a separate pointer rather than an + * extern declaration. + * + * If provided with a custom destroy callback this callback is + * responsible for eventually calling net_buf_destroy() to complete the + * process of returning the buffer to the pool. + * + * @param _name Name of the pool variable. + * @param _count Number of buffers in the pool. + * @param _size Maximum data size for each buffer. + * @param _ud_size Amount of user data space to reserve. + * @param _destroy Optional destroy callback when buffer is freed. + */ +#define NET_BUF_POOL_DEFINE(_name, _count, _size, _ud_size, _destroy) \ + NET_BUF_POOL_FIXED_DEFINE(_name, _count, _size, _ud_size, _destroy) + +/** + * @brief Get a zero-based index for a buffer. + * + * This function will translate a buffer into a zero-based index, + * based on its placement in its buffer pool. This can be useful if you + * want to associate an external array of meta-data contexts with the + * buffers of a pool. + * + * @param buf Network buffer. + * + * @return Zero-based index for the buffer. + */ +int net_buf_id(struct net_buf *buf); + +/** + * @brief Allocate a new fixed buffer from a pool. + * + * @param pool Which pool to allocate the buffer from. + * @param timeout Affects the action taken should the pool be empty. + * If K_NO_WAIT, then return immediately. If K_FOREVER, then + * wait as long as necessary. Otherwise, wait up to the specified + * number of milliseconds before timing out. Note that some types + * of data allocators do not support blocking (such as the HEAP + * type). In this case it's still possible for net_buf_alloc() to + * fail (return NULL) even if it was given K_FOREVER. + * + * @return New buffer or NULL if out of buffers. + */ +#if defined(CONFIG_NET_BUF_LOG) +struct net_buf *net_buf_alloc_fixed_debug(struct net_buf_pool *pool, int32_t timeout, + const char *func, int line); +#define net_buf_alloc_fixed(_pool, _timeout) \ + net_buf_alloc_fixed_debug(_pool, _timeout, __func__, __LINE__) +#else +struct net_buf *net_buf_alloc_fixed(struct net_buf_pool *pool, int32_t timeout); +#endif + +/** + * @def net_buf_alloc + * + * @copydetails net_buf_alloc_fixed + */ +#define net_buf_alloc(pool, timeout) net_buf_alloc_fixed(pool, timeout) + +/** + * @brief Reset buffer + * + * Reset buffer data and flags so it can be reused for other purposes. + * + * @param buf Buffer to reset. + */ +void net_buf_reset(struct net_buf *buf); + +/** + * @def net_buf_reserve + * @brief Initialize buffer with the given headroom. + * + * The buffer is not expected to contain any data when this API is called. + * + * @param buf Buffer to initialize. + * @param reserve How much headroom to reserve. + */ +#define net_buf_reserve(buf, reserve) net_buf_simple_reserve(&(buf)->b, reserve) + +/** + * @brief Put a buffer into a list + * + * Put a buffer to the end of a list. If the buffer contains follow-up + * fragments this function will take care of inserting them as well + * into the list. + * + * @param list Which list to append the buffer to. + * @param buf Buffer. + */ +void net_buf_slist_put(sys_slist_t *list, struct net_buf *buf); + +/** + * @brief Get a buffer from a list. + * + * Get buffer from a list. If the buffer had any fragments, these will + * automatically be recovered from the list as well and be placed to + * the buffer's fragment list. + * + * @param list Which list to take the buffer from. + * + * @return New buffer or NULL if the FIFO is empty. + */ +struct net_buf *net_buf_slist_get(sys_slist_t *list); + +/** + * @brief Decrements the reference count of a buffer. + * + * Decrements the reference count of a buffer and puts it back into the + * pool if the count reaches zero. + * + * @param buf A valid pointer on a buffer + */ +#if defined(CONFIG_NET_BUF_LOG) +void net_buf_unref_debug(struct net_buf *buf, const char *func, int line); +#define net_buf_unref(_buf) \ + net_buf_unref_debug(_buf, __func__, __LINE__) +#else +void net_buf_unref(struct net_buf *buf); +#endif + +/** + * @brief Increment the reference count of a buffer. + * + * @param buf A valid pointer on a buffer + * + * @return the buffer newly referenced + */ +struct net_buf *net_buf_ref(struct net_buf *buf); + +/** + * @brief Get a pointer to the user data of a buffer. + * + * @param buf A valid pointer on a buffer + * + * @return Pointer to the user data of the buffer. + */ +static inline void *net_buf_user_data(struct net_buf *buf) +{ + return (void *)buf->user_data; +} + +/** + * @def net_buf_add + * @brief Prepare data to be added at the end of the buffer + * + * Increments the data length of a buffer to account for more data + * at the end. + * + * @param buf Buffer to update. + * @param len Number of bytes to increment the length with. + * + * @return The original tail of the buffer. + */ +#define net_buf_add(buf, len) net_buf_simple_add(&(buf)->b, len) + +/** + * @def net_buf_add_mem + * @brief Copy bytes from memory to the end of the buffer + * + * Copies the given number of bytes to the end of the buffer. Increments the + * data length of the buffer to account for more data at the end. + * + * @param buf Buffer to update. + * @param mem Location of data to be added. + * @param len Length of data to be added + * + * @return The original tail of the buffer. + */ +#define net_buf_add_mem(buf, mem, len) net_buf_simple_add_mem(&(buf)->b, mem, len) + +/** + * @def net_buf_add_u8 + * @brief Add (8-bit) byte at the end of the buffer + * + * Adds a byte at the end of the buffer. Increments the data length of + * the buffer to account for more data at the end. + * + * @param buf Buffer to update. + * @param val byte value to be added. + * + * @return Pointer to the value added + */ +#define net_buf_add_u8(buf, val) net_buf_simple_add_u8(&(buf)->b, val) + +/** + * @def net_buf_add_le16 + * @brief Add 16-bit value at the end of the buffer + * + * Adds 16-bit value in little endian format at the end of buffer. + * Increments the data length of a buffer to account for more data + * at the end. + * + * @param buf Buffer to update. + * @param val 16-bit value to be added. + */ +#define net_buf_add_le16(buf, val) net_buf_simple_add_le16(&(buf)->b, val) + +/** + * @def net_buf_add_be16 + * @brief Add 16-bit value at the end of the buffer + * + * Adds 16-bit value in big endian format at the end of buffer. + * Increments the data length of a buffer to account for more data + * at the end. + * + * @param buf Buffer to update. + * @param val 16-bit value to be added. + */ +#define net_buf_add_be16(buf, val) net_buf_simple_add_be16(&(buf)->b, val) + +/** + * @def net_buf_add_le24 + * @brief Add 24-bit value at the end of the buffer + * + * Adds 24-bit value in little endian format at the end of buffer. + * Increments the data length of a buffer to account for more data + * at the end. + * + * @param buf Buffer to update. + * @param val 24-bit value to be added. + */ +#define net_buf_add_le24(buf, val) net_buf_simple_add_le24(&(buf)->b, val) + +/** + * @def net_buf_add_be24 + * @brief Add 24-bit value at the end of the buffer + * + * Adds 24-bit value in big endian format at the end of buffer. + * Increments the data length of a buffer to account for more data + * at the end. + * + * @param buf Buffer to update. + * @param val 24-bit value to be added. + */ +#define net_buf_add_be24(buf, val) net_buf_simple_add_be24(&(buf)->b, val) + +/** + * @def net_buf_add_le32 + * @brief Add 32-bit value at the end of the buffer + * + * Adds 32-bit value in little endian format at the end of buffer. + * Increments the data length of a buffer to account for more data + * at the end. + * + * @param buf Buffer to update. + * @param val 32-bit value to be added. + */ +#define net_buf_add_le32(buf, val) net_buf_simple_add_le32(&(buf)->b, val) + +/** + * @def net_buf_add_be32 + * @brief Add 32-bit value at the end of the buffer + * + * Adds 32-bit value in big endian format at the end of buffer. + * Increments the data length of a buffer to account for more data + * at the end. + * + * @param buf Buffer to update. + * @param val 32-bit value to be added. + */ +#define net_buf_add_be32(buf, val) net_buf_simple_add_be32(&(buf)->b, val) + +/** + * @def net_buf_add_le48 + * @brief Add 48-bit value at the end of the buffer + * + * Adds 48-bit value in little endian format at the end of buffer. + * Increments the data length of a buffer to account for more data + * at the end. + * + * @param buf Buffer to update. + * @param val 48-bit value to be added. + */ +#define net_buf_add_le48(buf, val) net_buf_simple_add_le48(&(buf)->b, val) + +/** + * @def net_buf_add_be48 + * @brief Add 48-bit value at the end of the buffer + * + * Adds 48-bit value in big endian format at the end of buffer. + * Increments the data length of a buffer to account for more data + * at the end. + * + * @param buf Buffer to update. + * @param val 48-bit value to be added. + */ +#define net_buf_add_be48(buf, val) net_buf_simple_add_be48(&(buf)->b, val) + +/** + * @def net_buf_add_le64 + * @brief Add 64-bit value at the end of the buffer + * + * Adds 64-bit value in little endian format at the end of buffer. + * Increments the data length of a buffer to account for more data + * at the end. + * + * @param buf Buffer to update. + * @param val 64-bit value to be added. + */ +#define net_buf_add_le64(buf, val) net_buf_simple_add_le64(&(buf)->b, val) + +/** + * @def net_buf_add_be64 + * @brief Add 64-bit value at the end of the buffer + * + * Adds 64-bit value in big endian format at the end of buffer. + * Increments the data length of a buffer to account for more data + * at the end. + * + * @param buf Buffer to update. + * @param val 64-bit value to be added. + */ +#define net_buf_add_be64(buf, val) net_buf_simple_add_be64(&(buf)->b, val) + +/** + * @def net_buf_push + * @brief Push data to the beginning of the buffer. + * + * Modifies the data pointer and buffer length to account for more data + * in the beginning of the buffer. + * + * @param buf Buffer to update. + * @param len Number of bytes to add to the beginning. + * + * @return The new beginning of the buffer data. + */ +#define net_buf_push(buf, len) net_buf_simple_push(&(buf)->b, len) + +/** + * @def net_buf_push_le16 + * @brief Push 16-bit value to the beginning of the buffer + * + * Adds 16-bit value in little endian format to the beginning of the + * buffer. + * + * @param buf Buffer to update. + * @param val 16-bit value to be pushed to the buffer. + */ +#define net_buf_push_le16(buf, val) net_buf_simple_push_le16(&(buf)->b, val) + +/** + * @def net_buf_push_be16 + * @brief Push 16-bit value to the beginning of the buffer + * + * Adds 16-bit value in little endian format to the beginning of the + * buffer. + * + * @param buf Buffer to update. + * @param val 16-bit value to be pushed to the buffer. + */ +#define net_buf_push_be16(buf, val) net_buf_simple_push_be16(&(buf)->b, val) + +/** + * @def net_buf_push_u8 + * @brief Push 8-bit value to the beginning of the buffer + * + * Adds 8-bit value the beginning of the buffer. + * + * @param buf Buffer to update. + * @param val 8-bit value to be pushed to the buffer. + */ +#define net_buf_push_u8(buf, val) net_buf_simple_push_u8(&(buf)->b, val) + +/** + * @def net_buf_push_le24 + * @brief Push 24-bit value to the beginning of the buffer + * + * Adds 24-bit value in little endian format to the beginning of the + * buffer. + * + * @param buf Buffer to update. + * @param val 24-bit value to be pushed to the buffer. + */ +#define net_buf_push_le24(buf, val) net_buf_simple_push_le24(&(buf)->b, val) + +/** + * @def net_buf_push_be24 + * @brief Push 24-bit value to the beginning of the buffer + * + * Adds 24-bit value in little endian format to the beginning of the + * buffer. + * + * @param buf Buffer to update. + * @param val 24-bit value to be pushed to the buffer. + */ +#define net_buf_push_be24(buf, val) net_buf_simple_push_be24(&(buf)->b, val) + +/** + * @def net_buf_push_le32 + * @brief Push 32-bit value to the beginning of the buffer + * + * Adds 32-bit value in little endian format to the beginning of the + * buffer. + * + * @param buf Buffer to update. + * @param val 32-bit value to be pushed to the buffer. + */ +#define net_buf_push_le32(buf, val) net_buf_simple_push_le32(&(buf)->b, val) + +/** + * @def net_buf_push_be32 + * @brief Push 32-bit value to the beginning of the buffer + * + * Adds 32-bit value in little endian format to the beginning of the + * buffer. + * + * @param buf Buffer to update. + * @param val 32-bit value to be pushed to the buffer. + */ +#define net_buf_push_be32(buf, val) net_buf_simple_push_be32(&(buf)->b, val) + +/** + * @def net_buf_push_le48 + * @brief Push 48-bit value to the beginning of the buffer + * + * Adds 48-bit value in little endian format to the beginning of the + * buffer. + * + * @param buf Buffer to update. + * @param val 48-bit value to be pushed to the buffer. + */ +#define net_buf_push_le48(buf, val) net_buf_simple_push_le48(&(buf)->b, val) + +/** + * @def net_buf_push_be48 + * @brief Push 48-bit value to the beginning of the buffer + * + * Adds 48-bit value in little endian format to the beginning of the + * buffer. + * + * @param buf Buffer to update. + * @param val 48-bit value to be pushed to the buffer. + */ +#define net_buf_push_be48(buf, val) net_buf_simple_push_be48(&(buf)->b, val) + +/** + * @def net_buf_push_le64 + * @brief Push 64-bit value to the beginning of the buffer + * + * Adds 64-bit value in little endian format to the beginning of the + * buffer. + * + * @param buf Buffer to update. + * @param val 64-bit value to be pushed to the buffer. + */ +#define net_buf_push_le64(buf, val) net_buf_simple_push_le64(&(buf)->b, val) + +/** + * @def net_buf_push_be64 + * @brief Push 64-bit value to the beginning of the buffer + * + * Adds 64-bit value in little endian format to the beginning of the + * buffer. + * + * @param buf Buffer to update. + * @param val 64-bit value to be pushed to the buffer. + */ +#define net_buf_push_be64(buf, val) net_buf_simple_push_be64(&(buf)->b, val) + +/** + * @def net_buf_pull + * @brief Remove data from the beginning of the buffer. + * + * Removes data from the beginning of the buffer by modifying the data + * pointer and buffer length. + * + * @param buf Buffer to update. + * @param len Number of bytes to remove. + * + * @return New beginning of the buffer data. + */ +#define net_buf_pull(buf, len) net_buf_simple_pull(&(buf)->b, len) + +/** + * @def net_buf_pull_mem + * @brief Remove data from the beginning of the buffer. + * + * Removes data from the beginning of the buffer by modifying the data + * pointer and buffer length. + * + * @param buf Buffer to update. + * @param len Number of bytes to remove. + * + * @return Pointer to the old beginning of the buffer data. + */ +#define net_buf_pull_mem(buf, len) net_buf_simple_pull_mem(&(buf)->b, len) + +/** + * @def net_buf_pull_u8 + * @brief Remove a 8-bit value from the beginning of the buffer + * + * Same idea as with net_buf_pull(), but a helper for operating on + * 8-bit values. + * + * @param buf A valid pointer on a buffer. + * + * @return The 8-bit removed value + */ +#define net_buf_pull_u8(buf) net_buf_simple_pull_u8(&(buf)->b) + +/** + * @def net_buf_pull_le16 + * @brief Remove and convert 16 bits from the beginning of the buffer. + * + * Same idea as with net_buf_pull(), but a helper for operating on + * 16-bit little endian data. + * + * @param buf A valid pointer on a buffer. + * + * @return 16-bit value converted from little endian to host endian. + */ +#define net_buf_pull_le16(buf) net_buf_simple_pull_le16(&(buf)->b) + +/** + * @def net_buf_pull_be16 + * @brief Remove and convert 16 bits from the beginning of the buffer. + * + * Same idea as with net_buf_pull(), but a helper for operating on + * 16-bit big endian data. + * + * @param buf A valid pointer on a buffer. + * + * @return 16-bit value converted from big endian to host endian. + */ +#define net_buf_pull_be16(buf) net_buf_simple_pull_be16(&(buf)->b) + +/** + * @def net_buf_pull_le24 + * @brief Remove and convert 24 bits from the beginning of the buffer. + * + * Same idea as with net_buf_pull(), but a helper for operating on + * 24-bit little endian data. + * + * @param buf A valid pointer on a buffer. + * + * @return 24-bit value converted from little endian to host endian. + */ +#define net_buf_pull_le24(buf) net_buf_simple_pull_le24(&(buf)->b) + +/** + * @def net_buf_pull_be24 + * @brief Remove and convert 24 bits from the beginning of the buffer. + * + * Same idea as with net_buf_pull(), but a helper for operating on + * 24-bit big endian data. + * + * @param buf A valid pointer on a buffer. + * + * @return 24-bit value converted from big endian to host endian. + */ +#define net_buf_pull_be24(buf) net_buf_simple_pull_be24(&(buf)->b) + +/** + * @def net_buf_pull_le32 + * @brief Remove and convert 32 bits from the beginning of the buffer. + * + * Same idea as with net_buf_pull(), but a helper for operating on + * 32-bit little endian data. + * + * @param buf A valid pointer on a buffer. + * + * @return 32-bit value converted from little endian to host endian. + */ +#define net_buf_pull_le32(buf) net_buf_simple_pull_le32(&(buf)->b) + +/** + * @def net_buf_pull_be32 + * @brief Remove and convert 32 bits from the beginning of the buffer. + * + * Same idea as with net_buf_pull(), but a helper for operating on + * 32-bit big endian data. + * + * @param buf A valid pointer on a buffer + * + * @return 32-bit value converted from big endian to host endian. + */ +#define net_buf_pull_be32(buf) net_buf_simple_pull_be32(&(buf)->b) + +/** + * @def net_buf_pull_le48 + * @brief Remove and convert 48 bits from the beginning of the buffer. + * + * Same idea as with net_buf_pull(), but a helper for operating on + * 48-bit little endian data. + * + * @param buf A valid pointer on a buffer. + * + * @return 48-bit value converted from little endian to host endian. + */ +#define net_buf_pull_le48(buf) net_buf_simple_pull_le48(&(buf)->b) + +/** + * @def net_buf_pull_be48 + * @brief Remove and convert 48 bits from the beginning of the buffer. + * + * Same idea as with net_buf_pull(), but a helper for operating on + * 48-bit big endian data. + * + * @param buf A valid pointer on a buffer + * + * @return 48-bit value converted from big endian to host endian. + */ +#define net_buf_pull_be48(buf) net_buf_simple_pull_be48(&(buf)->b) + +/** + * @def net_buf_pull_le64 + * @brief Remove and convert 64 bits from the beginning of the buffer. + * + * Same idea as with net_buf_pull(), but a helper for operating on + * 64-bit little endian data. + * + * @param buf A valid pointer on a buffer. + * + * @return 64-bit value converted from little endian to host endian. + */ +#define net_buf_pull_le64(buf) net_buf_simple_pull_le64(&(buf)->b) + +/** + * @def net_buf_pull_be64 + * @brief Remove and convert 64 bits from the beginning of the buffer. + * + * Same idea as with net_buf_pull(), but a helper for operating on + * 64-bit big endian data. + * + * @param buf A valid pointer on a buffer + * + * @return 64-bit value converted from big endian to host endian. + */ +#define net_buf_pull_be64(buf) net_buf_simple_pull_be64(&(buf)->b) + +/** + * @def net_buf_tailroom + * @brief Check buffer tailroom. + * + * Check how much free space there is at the end of the buffer. + * + * @param buf A valid pointer on a buffer + * + * @return Number of bytes available at the end of the buffer. + */ +#define net_buf_tailroom(buf) net_buf_simple_tailroom(&(buf)->b) + +/** + * @def net_buf_headroom + * @brief Check buffer headroom. + * + * Check how much free space there is in the beginning of the buffer. + * + * buf A valid pointer on a buffer + * + * @return Number of bytes available in the beginning of the buffer. + */ +#define net_buf_headroom(buf) net_buf_simple_headroom(&(buf)->b) + +/** + * @def net_buf_tail + * @brief Get the tail pointer for a buffer. + * + * Get a pointer to the end of the data in a buffer. + * + * @param buf Buffer. + * + * @return Tail pointer for the buffer. + */ +#define net_buf_tail(buf) net_buf_simple_tail(&(buf)->b) + +/** + * @brief Find the last fragment in the fragment list. + * + * @return Pointer to last fragment in the list. + */ +struct net_buf *net_buf_frag_last(struct net_buf *frags); + +/** + * @brief Insert a new fragment to a chain of bufs. + * + * Insert a new fragment into the buffer fragments list after the parent. + * + * Note: This function takes ownership of the fragment reference so the + * caller is not required to unref. + * + * @param parent Parent buffer/fragment. + * @param frag Fragment to insert. + */ +void net_buf_frag_insert(struct net_buf *parent, struct net_buf *frag); + +/** + * @brief Add a new fragment to the end of a chain of bufs. + * + * Append a new fragment into the buffer fragments list. + * + * Note: This function takes ownership of the fragment reference so the + * caller is not required to unref. + * + * @param head Head of the fragment chain. + * @param frag Fragment to add. + * + * @return New head of the fragment chain. Either head (if head + * was non-NULL) or frag (if head was NULL). + */ +struct net_buf *net_buf_frag_add(struct net_buf *head, struct net_buf *frag); + +/** + * @brief Delete existing fragment from a chain of bufs. + * + * @param parent Parent buffer/fragment, or NULL if there is no parent. + * @param frag Fragment to delete. + * + * @return Pointer to the buffer following the fragment, or NULL if it + * had no further fragments. + */ +#if defined(CONFIG_NET_BUF_LOG) +struct net_buf *net_buf_frag_del_debug(struct net_buf *parent, + struct net_buf *frag, + const char *func, int line); +#define net_buf_frag_del(_parent, _frag) \ + net_buf_frag_del_debug(_parent, _frag, __func__, __LINE__) +#else +struct net_buf *net_buf_frag_del(struct net_buf *parent, struct net_buf *frag); +#endif + +/** + * @brief Copy bytes from net_buf chain starting at offset to linear buffer + * + * Copy (extract) @a len bytes from @a src net_buf chain, starting from @a + * offset in it, to a linear buffer @a dst. Return number of bytes actually + * copied, which may be less than requested, if net_buf chain doesn't have + * enough data, or destination buffer is too small. + * + * @param dst Destination buffer + * @param dst_len Destination buffer length + * @param src Source net_buf chain + * @param offset Starting offset to copy from + * @param len Number of bytes to copy + * @return number of bytes actually copied + */ +size_t net_buf_linearize(void *dst, size_t dst_len, + struct net_buf *src, size_t offset, size_t len); + +/** + * @typedef net_buf_allocator_cb + * @brief Network buffer allocator callback. + * + * @details The allocator callback is called when net_buf_append_bytes + * needs to allocate a new net_buf. + * + * @param timeout Affects the action taken should the net buf pool be empty. + * If K_NO_WAIT, then return immediately. If K_FOREVER, then + * wait as long as necessary. Otherwise, wait up to the specified + * number of milliseconds before timing out. + * @param user_data The user data given in net_buf_append_bytes call. + * @return pointer to allocated net_buf or NULL on error. + */ +typedef struct net_buf *(*net_buf_allocator_cb)(int32_t timeout, void *user_data); + +/** + * @brief Append data to a list of net_buf + * + * @details Append data to a net_buf. If there is not enough space in the + * net_buf then more net_buf will be added, unless there are no free net_buf + * and timeout occurs. + * + * @param buf Network buffer. + * @param len Total length of input data + * @param value Data to be added + * @param timeout Timeout is passed to the net_buf allocator callback. + * @param allocate_cb When a new net_buf is required, use this callback. + * @param user_data A user data pointer to be supplied to the allocate_cb. + * This pointer is can be anything from a mem_pool or a net_pkt, the + * logic is left up to the allocate_cb function. + * + * @return Length of data actually added. This may be less than input + * length if other timeout than K_FOREVER was used, and there + * were no free fragments in a pool to accommodate all data. + */ +size_t net_buf_append_bytes(struct net_buf *buf, size_t len, + const void *value, int32_t timeout, + net_buf_allocator_cb allocate_cb, void *user_data); + +/** + * @brief Skip N number of bytes in a net_buf + * + * @details Skip N number of bytes starting from fragment's offset. If the total + * length of data is placed in multiple fragments, this function will skip from + * all fragments until it reaches N number of bytes. Any fully skipped buffers + * are removed from the net_buf list. + * + * @param buf Network buffer. + * @param len Total length of data to be skipped. + * + * @return Pointer to the fragment or + * NULL and pos is 0 after successful skip, + * NULL and pos is 0xffff otherwise. + */ +static inline struct net_buf *net_buf_skip(struct net_buf *buf, size_t len) +{ + while (buf && len--) { + if (!buf->len) { + buf = net_buf_frag_del(NULL, buf); + if (!buf) { + break; + } + } + net_buf_pull_u8(buf); + if (!buf->len) { + buf = net_buf_frag_del(NULL, buf); + } + } + + return buf; +} + +/** + * @brief Calculate amount of bytes stored in fragments. + * + * Calculates the total amount of data stored in the given buffer and the + * fragments linked to it. + * + * @param buf Buffer to start off with. + * + * @return Number of bytes in the buffer and its fragments. + */ +static inline size_t net_buf_frags_len(struct net_buf *buf) +{ + size_t bytes = 0; + + while (buf) { + bytes += buf->len; + buf = buf->frags; + } + + return bytes; +} + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BT_AUDIO_BUF_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/sys/__assert.h b/components/bt/esp_ble_audio/include/zephyr/sys/__assert.h new file mode 100644 index 0000000000..b5564e10f7 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/sys/__assert.h @@ -0,0 +1,25 @@ +/* + * SPDX-FileCopyrightText: 2011-2014 Wind River Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_SYS_ASSERT_H_ +#define ZEPHYR_INCLUDE_SYS_ASSERT_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define __ASSERT_NO_MSG(test) assert(test) + +#define __ASSERT(test, fmt, ...) assert(test) + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_SYS_ASSERT_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/sys/atomic.h b/components/bt/esp_ble_audio/include/zephyr/sys/atomic.h new file mode 100644 index 0000000000..e685a66ccd --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/sys/atomic.h @@ -0,0 +1,162 @@ +/* + * SPDX-FileCopyrightText: 1997-2015 Wind River Systems, Inc. + * SPDX-FileCopyrightText: 2021 Intel Corporation + * SPDX-FileCopyrightText: 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_SYS_ATOMIC_H_ +#define ZEPHYR_INCLUDE_SYS_ATOMIC_H_ + +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef uint32_t atomic_t; +typedef atomic_t atomic_val_t; +typedef void *atomic_ptr_t; +typedef atomic_ptr_t atomic_ptr_val_t; + +#define ATOMIC_INIT(i) (i) +#define ATOMIC_PTR_INIT(p) (p) +#define ATOMIC_BITS (sizeof(atomic_val_t) * 8) +#define ATOMIC_MASK(bit) BIT((unsigned long)(bit) & (ATOMIC_BITS - 1U)) +#define ATOMIC_ELEM(addr, bit) ((addr) + ((bit) / ATOMIC_BITS)) +#define ATOMIC_BITMAP_SIZE(num_bits) (ROUND_UP(num_bits, ATOMIC_BITS) / ATOMIC_BITS) +#define ATOMIC_DEFINE(name, num_bits) atomic_t name[ATOMIC_BITMAP_SIZE(num_bits)] + +static inline bool atomic_cas(atomic_t *target, + atomic_val_t old_value, + atomic_val_t new_value) +{ + if (*target != old_value) { + return false; + } + + *target = new_value; + return true; +} + +static inline atomic_val_t atomic_inc(atomic_t *target) +{ + atomic_val_t ret = 0; + + ret = *target; + (*target)++; + + return ret; +} + +static inline atomic_val_t atomic_dec(atomic_t *target) +{ + atomic_val_t ret = 0; + + ret = *target; + (*target)--; + + return ret; +} + +static inline atomic_val_t atomic_get(const atomic_t *target) +{ + return *target; +} + +static inline atomic_val_t atomic_set(atomic_t *target, atomic_val_t value) +{ + atomic_val_t ret = 0; + + ret = *target; + *target = value; + + return ret; +} + +static inline atomic_val_t atomic_clear(atomic_t *target) +{ + return atomic_set(target, 0); +} + +static inline atomic_val_t atomic_or(atomic_t *target, atomic_val_t value) +{ + atomic_val_t ret = 0; + + ret = *target; + *target |= value; + + return ret; +} + +static inline atomic_val_t atomic_and(atomic_t *target, atomic_val_t value) +{ + atomic_val_t ret = 0; + + ret = *target; + *target &= value; + + return ret; +} + +static inline void atomic_set_bit_to(atomic_t *target, int bit, bool val) +{ + atomic_val_t mask = ATOMIC_MASK(bit); + + if (val) { + (void)atomic_or(ATOMIC_ELEM(target, bit), mask); + } else { + (void)atomic_and(ATOMIC_ELEM(target, bit), ~mask); + } +} + +static inline bool atomic_test_bit(const atomic_t *target, int bit) +{ + atomic_val_t val = atomic_get(ATOMIC_ELEM(target, bit)); + + return (1 & (val >> (bit & (ATOMIC_BITS - 1)))) != 0; +} + +static inline void atomic_set_bit(atomic_t *target, int bit) +{ + atomic_val_t mask = ATOMIC_MASK(bit); + + (void)atomic_or(ATOMIC_ELEM(target, bit), mask); +} + +static inline void atomic_clear_bit(atomic_t *target, int bit) +{ + atomic_val_t mask = ATOMIC_MASK(bit); + + (void)atomic_and(ATOMIC_ELEM(target, bit), ~mask); +} + +static inline bool atomic_test_and_set_bit(atomic_t *target, int bit) +{ + atomic_val_t mask = ATOMIC_MASK(bit); + atomic_val_t old; + + old = atomic_or(ATOMIC_ELEM(target, bit), mask); + + return (old & mask) != 0; +} + +static inline bool atomic_test_and_clear_bit(atomic_t *target, int bit) +{ + atomic_val_t mask = ATOMIC_MASK(bit); + atomic_val_t old; + + old = atomic_and(ATOMIC_ELEM(target, bit), ~mask); + + return (old & mask) != 0; +} + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_SYS_ATOMIC_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/sys/byteorder.h b/components/bt/esp_ble_audio/include/zephyr/sys/byteorder.h new file mode 100644 index 0000000000..3a488fc34f --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/sys/byteorder.h @@ -0,0 +1,852 @@ +/** @file + * @brief Byte order helpers. + */ + +/* + * SPDX-FileCopyrightText: 2015-2016 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_SYS_BYTEORDER_H_ +#define ZEPHYR_INCLUDE_SYS_BYTEORDER_H_ + +#include +#include +#include +#include +#include +#include + +#define BSWAP_16(x) ((uint16_t) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8))) +#define BSWAP_24(x) ((uint32_t) ((((x) >> 16) & 0xff) | \ + (((x)) & 0xff00) | \ + (((x) & 0xff) << 16))) +#define BSWAP_32(x) ((uint32_t) ((((x) >> 24) & 0xff) | \ + (((x) >> 8) & 0xff00) | \ + (((x) & 0xff00) << 8) | \ + (((x) & 0xff) << 24))) +#define BSWAP_40(x) ((uint64_t) ((((x) >> 32) & 0xff) | \ + (((x) >> 16) & 0xff00) | \ + (((x)) & 0xff0000) | \ + (((x) & 0xff00) << 16) | \ + (((x) & 0xff) << 32))) +#define BSWAP_48(x) ((uint64_t) ((((x) >> 40) & 0xff) | \ + (((x) >> 24) & 0xff00) | \ + (((x) >> 8) & 0xff0000) | \ + (((x) & 0xff0000) << 8) | \ + (((x) & 0xff00) << 24) | \ + (((x) & 0xff) << 40))) +#define BSWAP_64(x) ((uint64_t) ((((x) >> 56) & 0xff) | \ + (((x) >> 40) & 0xff00) | \ + (((x) >> 24) & 0xff0000) | \ + (((x) >> 8) & 0xff000000) | \ + (((x) & 0xff000000) << 8) | \ + (((x) & 0xff0000) << 24) | \ + (((x) & 0xff00) << 40) | \ + (((x) & 0xff) << 56))) + +/** @def sys_le16_to_cpu + * @brief Convert 16-bit integer from little-endian to host endianness. + * + * @param val 16-bit integer in little-endian format. + * + * @return 16-bit integer in host endianness. + */ + +/** @def sys_cpu_to_le16 + * @brief Convert 16-bit integer from host endianness to little-endian. + * + * @param val 16-bit integer in host endianness. + * + * @return 16-bit integer in little-endian format. + */ + +/** @def sys_le24_to_cpu + * @brief Convert 24-bit integer from little-endian to host endianness. + * + * @param val 24-bit integer in little-endian format. + * + * @return 24-bit integer in host endianness. + */ + +/** @def sys_cpu_to_le24 + * @brief Convert 24-bit integer from host endianness to little-endian. + * + * @param val 24-bit integer in host endianness. + * + * @return 24-bit integer in little-endian format. + */ + +/** @def sys_le32_to_cpu + * @brief Convert 32-bit integer from little-endian to host endianness. + * + * @param val 32-bit integer in little-endian format. + * + * @return 32-bit integer in host endianness. + */ + +/** @def sys_cpu_to_le32 + * @brief Convert 32-bit integer from host endianness to little-endian. + * + * @param val 32-bit integer in host endianness. + * + * @return 32-bit integer in little-endian format. + */ + +/** @def sys_le48_to_cpu + * @brief Convert 48-bit integer from little-endian to host endianness. + * + * @param val 48-bit integer in little-endian format. + * + * @return 48-bit integer in host endianness. + */ + +/** @def sys_cpu_to_le48 + * @brief Convert 48-bit integer from host endianness to little-endian. + * + * @param val 48-bit integer in host endianness. + * + * @return 48-bit integer in little-endian format. + */ + +/** @def sys_be16_to_cpu + * @brief Convert 16-bit integer from big-endian to host endianness. + * + * @param val 16-bit integer in big-endian format. + * + * @return 16-bit integer in host endianness. + */ + +/** @def sys_cpu_to_be16 + * @brief Convert 16-bit integer from host endianness to big-endian. + * + * @param val 16-bit integer in host endianness. + * + * @return 16-bit integer in big-endian format. + */ + +/** @def sys_be24_to_cpu + * @brief Convert 24-bit integer from big-endian to host endianness. + * + * @param val 24-bit integer in big-endian format. + * + * @return 24-bit integer in host endianness. + */ + +/** @def sys_cpu_to_be24 + * @brief Convert 24-bit integer from host endianness to big-endian. + * + * @param val 24-bit integer in host endianness. + * + * @return 24-bit integer in big-endian format. + */ + +/** @def sys_be32_to_cpu + * @brief Convert 32-bit integer from big-endian to host endianness. + * + * @param val 32-bit integer in big-endian format. + * + * @return 32-bit integer in host endianness. + */ + +/** @def sys_cpu_to_be32 + * @brief Convert 32-bit integer from host endianness to big-endian. + * + * @param val 32-bit integer in host endianness. + * + * @return 32-bit integer in big-endian format. + */ + +/** @def sys_be48_to_cpu + * @brief Convert 48-bit integer from big-endian to host endianness. + * + * @param val 48-bit integer in big-endian format. + * + * @return 48-bit integer in host endianness. + */ + +/** @def sys_cpu_to_be48 + * @brief Convert 48-bit integer from host endianness to big-endian. + * + * @param val 48-bit integer in host endianness. + * + * @return 48-bit integer in big-endian format. + */ + +/** @def sys_uint16_to_array + * @brief Convert 16-bit unsigned integer to byte array. + * + * @details Byte order aware macro to treat an unsigned integer + * as an array, rather than an integer literal. For example, + * `0x0123` would be converted to `{0x01, 0x23}` for big endian + * machines, and `{0x23, 0x01}` for little endian machines. + * + * @param val 16-bit unsigned integer. + * + * @return 16-bit unsigned integer as byte array. + */ + +/** @def sys_uint32_to_array + * @brief Convert 32-bit unsigned integer to byte array. + * + * @details Byte order aware macro to treat an unsigned integer + * as an array, rather than an integer literal. For example, + * `0x01234567` would be converted to `{0x01, 0x23, 0x45, 0x67}` + * for big endian machines, and `{0x67, 0x45, 0x23, 0x01}` for + * little endian machines. + * + * @param val 32-bit unsigned integer. + * + * @return 32-bit unsigned integer as byte array. + */ + +/** @def sys_uint64_to_array + * @brief Convert 64-bit unsigned integer to byte array. + * + * @details Byte order aware macro to treat an unsigned integer + * as an array, rather than an integer literal. For example, + * `0x0123456789abcdef` would be converted to + * `{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}` + * for big endian machines, and + * `{0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01}` for + * little endian machines. + * + * @param val 64-bit unsigned integer. + * + * @return 64-bit unsigned integer as byte array. + */ + +#ifdef CONFIG_LITTLE_ENDIAN +#define sys_le16_to_cpu(val) (val) +#define sys_cpu_to_le16(val) (val) +#define sys_le24_to_cpu(val) (val) +#define sys_cpu_to_le24(val) (val) +#define sys_le32_to_cpu(val) (val) +#define sys_cpu_to_le32(val) (val) +#define sys_le40_to_cpu(val) (val) +#define sys_cpu_to_le40(val) (val) +#define sys_le48_to_cpu(val) (val) +#define sys_cpu_to_le48(val) (val) +#define sys_le64_to_cpu(val) (val) +#define sys_cpu_to_le64(val) (val) +#define sys_be16_to_cpu(val) BSWAP_16(val) +#define sys_cpu_to_be16(val) BSWAP_16(val) +#define sys_be24_to_cpu(val) BSWAP_24(val) +#define sys_cpu_to_be24(val) BSWAP_24(val) +#define sys_be32_to_cpu(val) BSWAP_32(val) +#define sys_cpu_to_be32(val) BSWAP_32(val) +#define sys_be40_to_cpu(val) BSWAP_40(val) +#define sys_cpu_to_be40(val) BSWAP_40(val) +#define sys_be48_to_cpu(val) BSWAP_48(val) +#define sys_cpu_to_be48(val) BSWAP_48(val) +#define sys_be64_to_cpu(val) BSWAP_64(val) +#define sys_cpu_to_be64(val) BSWAP_64(val) + +#define sys_uint16_to_array(val) { \ + ((val) & 0xff), \ + (((val) >> 8) & 0xff)} + +#define sys_uint32_to_array(val) { \ + ((val) & 0xff), \ + (((val) >> 8) & 0xff), \ + (((val) >> 16) & 0xff), \ + (((val) >> 24) & 0xff)} + +#define sys_uint64_to_array(val) { \ + ((val) & 0xff), \ + (((val) >> 8) & 0xff), \ + (((val) >> 16) & 0xff), \ + (((val) >> 24) & 0xff), \ + (((val) >> 32) & 0xff), \ + (((val) >> 40) & 0xff), \ + (((val) >> 48) & 0xff), \ + (((val) >> 56) & 0xff)} + +#else +#define sys_le16_to_cpu(val) BSWAP_16(val) +#define sys_cpu_to_le16(val) BSWAP_16(val) +#define sys_le24_to_cpu(val) BSWAP_24(val) +#define sys_cpu_to_le24(val) BSWAP_24(val) +#define sys_le32_to_cpu(val) BSWAP_32(val) +#define sys_cpu_to_le32(val) BSWAP_32(val) +#define sys_le40_to_cpu(val) BSWAP_40(val) +#define sys_cpu_to_le40(val) BSWAP_40(val) +#define sys_le48_to_cpu(val) BSWAP_48(val) +#define sys_cpu_to_le48(val) BSWAP_48(val) +#define sys_le64_to_cpu(val) BSWAP_64(val) +#define sys_cpu_to_le64(val) BSWAP_64(val) +#define sys_be16_to_cpu(val) (val) +#define sys_cpu_to_be16(val) (val) +#define sys_be24_to_cpu(val) (val) +#define sys_cpu_to_be24(val) (val) +#define sys_be32_to_cpu(val) (val) +#define sys_cpu_to_be32(val) (val) +#define sys_be40_to_cpu(val) (val) +#define sys_cpu_to_be40(val) (val) +#define sys_be48_to_cpu(val) (val) +#define sys_cpu_to_be48(val) (val) +#define sys_be64_to_cpu(val) (val) +#define sys_cpu_to_be64(val) (val) + +#define sys_uint16_to_array(val) { \ + (((val) >> 8) & 0xff), \ + ((val) & 0xff)} + +#define sys_uint32_to_array(val) { \ + (((val) >> 24) & 0xff), \ + (((val) >> 16) & 0xff), \ + (((val) >> 8) & 0xff), \ + ((val) & 0xff)} + +#define sys_uint64_to_array(val) { \ + (((val) >> 56) & 0xff), \ + (((val) >> 48) & 0xff), \ + (((val) >> 40) & 0xff), \ + (((val) >> 32) & 0xff), \ + (((val) >> 24) & 0xff), \ + (((val) >> 16) & 0xff), \ + (((val) >> 8) & 0xff), \ + ((val) & 0xff)} + +#endif + +/** + * @brief Put a 16-bit integer as big-endian to arbitrary location. + * + * Put a 16-bit integer, originally in host endianness, to a + * potentially unaligned memory location in big-endian format. + * + * @param val 16-bit integer in host endianness. + * @param dst Destination memory address to store the result. + */ +static inline void sys_put_be16(uint16_t val, uint8_t dst[2]) +{ + dst[0] = val >> 8; + dst[1] = val; +} + +/** + * @brief Put a 24-bit integer as big-endian to arbitrary location. + * + * Put a 24-bit integer, originally in host endianness, to a + * potentially unaligned memory location in big-endian format. + * + * @param val 24-bit integer in host endianness. + * @param dst Destination memory address to store the result. + */ +static inline void sys_put_be24(uint32_t val, uint8_t dst[3]) +{ + dst[0] = val >> 16; + sys_put_be16(val, &dst[1]); +} + +/** + * @brief Put a 32-bit integer as big-endian to arbitrary location. + * + * Put a 32-bit integer, originally in host endianness, to a + * potentially unaligned memory location in big-endian format. + * + * @param val 32-bit integer in host endianness. + * @param dst Destination memory address to store the result. + */ +static inline void sys_put_be32(uint32_t val, uint8_t dst[4]) +{ + sys_put_be16(val >> 16, dst); + sys_put_be16(val, &dst[2]); +} +/** + * @brief Put a 40-bit integer as big-endian to arbitrary location. + * + * Put a 40-bit integer, originally in host endianness, to a + * potentially unaligned memory location in big-endian format. + * + * @param val 40-bit integer in host endianness. + * @param dst Destination memory address to store the result. + */ +static inline void sys_put_be40(uint64_t val, uint8_t dst[5]) +{ + dst[0] = val >> 32; + sys_put_be32(val, &dst[1]); +} + +/** + * @brief Put a 48-bit integer as big-endian to arbitrary location. + * + * Put a 48-bit integer, originally in host endianness, to a + * potentially unaligned memory location in big-endian format. + * + * @param val 48-bit integer in host endianness. + * @param dst Destination memory address to store the result. + */ +static inline void sys_put_be48(uint64_t val, uint8_t dst[6]) +{ + sys_put_be16(val >> 32, dst); + sys_put_be32(val, &dst[2]); +} + +/** + * @brief Put a 64-bit integer as big-endian to arbitrary location. + * + * Put a 64-bit integer, originally in host endianness, to a + * potentially unaligned memory location in big-endian format. + * + * @param val 64-bit integer in host endianness. + * @param dst Destination memory address to store the result. + */ +static inline void sys_put_be64(uint64_t val, uint8_t dst[8]) +{ + sys_put_be32(val >> 32, dst); + sys_put_be32(val, &dst[4]); +} + +/** + * @brief Put a 16-bit integer as little-endian to arbitrary location. + * + * Put a 16-bit integer, originally in host endianness, to a + * potentially unaligned memory location in little-endian format. + * + * @param val 16-bit integer in host endianness. + * @param dst Destination memory address to store the result. + */ +static inline void sys_put_le16(uint16_t val, uint8_t dst[2]) +{ + dst[0] = val; + dst[1] = val >> 8; +} + +/** + * @brief Put a 24-bit integer as little-endian to arbitrary location. + * + * Put a 24-bit integer, originally in host endianness, to a + * potentially unaligned memory location in little-endian format. + * + * @param val 24-bit integer in host endianness. + * @param dst Destination memory address to store the result. + */ +static inline void sys_put_le24(uint32_t val, uint8_t dst[3]) +{ + sys_put_le16(val, dst); + dst[2] = val >> 16; +} + +/** + * @brief Put a 32-bit integer as little-endian to arbitrary location. + * + * Put a 32-bit integer, originally in host endianness, to a + * potentially unaligned memory location in little-endian format. + * + * @param val 32-bit integer in host endianness. + * @param dst Destination memory address to store the result. + */ +static inline void sys_put_le32(uint32_t val, uint8_t dst[4]) +{ + sys_put_le16(val, dst); + sys_put_le16(val >> 16, &dst[2]); +} + +/** + * @brief Put a 40-bit integer as little-endian to arbitrary location. + * + * Put a 40-bit integer, originally in host endianness, to a + * potentially unaligned memory location in little-endian format. + * + * @param val 40-bit integer in host endianness. + * @param dst Destination memory address to store the result. + */ +static inline void sys_put_le40(uint64_t val, uint8_t dst[5]) +{ + sys_put_le32(val, dst); + dst[4] = val >> 32; +} + +/** + * @brief Put a 48-bit integer as little-endian to arbitrary location. + * + * Put a 48-bit integer, originally in host endianness, to a + * potentially unaligned memory location in little-endian format. + * + * @param val 48-bit integer in host endianness. + * @param dst Destination memory address to store the result. + */ +static inline void sys_put_le48(uint64_t val, uint8_t dst[6]) +{ + sys_put_le32(val, dst); + sys_put_le16(val >> 32, &dst[4]); +} + +/** + * @brief Put a 64-bit integer as little-endian to arbitrary location. + * + * Put a 64-bit integer, originally in host endianness, to a + * potentially unaligned memory location in little-endian format. + * + * @param val 64-bit integer in host endianness. + * @param dst Destination memory address to store the result. + */ +static inline void sys_put_le64(uint64_t val, uint8_t dst[8]) +{ + sys_put_le32(val, dst); + sys_put_le32(val >> 32, &dst[4]); +} + +/** + * @brief Get a 16-bit integer stored in big-endian format. + * + * Get a 16-bit integer, stored in big-endian format in a potentially + * unaligned memory location, and convert it to the host endianness. + * + * @param src Location of the big-endian 16-bit integer to get. + * + * @return 16-bit integer in host endianness. + */ +static inline uint16_t sys_get_be16(const uint8_t src[2]) +{ + return ((uint16_t)src[0] << 8) | src[1]; +} + +/** + * @brief Get a 24-bit integer stored in big-endian format. + * + * Get a 24-bit integer, stored in big-endian format in a potentially + * unaligned memory location, and convert it to the host endianness. + * + * @param src Location of the big-endian 24-bit integer to get. + * + * @return 24-bit integer in host endianness. + */ +static inline uint32_t sys_get_be24(const uint8_t src[3]) +{ + return ((uint32_t)src[0] << 16) | sys_get_be16(&src[1]); +} + +/** + * @brief Get a 32-bit integer stored in big-endian format. + * + * Get a 32-bit integer, stored in big-endian format in a potentially + * unaligned memory location, and convert it to the host endianness. + * + * @param src Location of the big-endian 32-bit integer to get. + * + * @return 32-bit integer in host endianness. + */ +static inline uint32_t sys_get_be32(const uint8_t src[4]) +{ + return ((uint32_t)sys_get_be16(&src[0]) << 16) | sys_get_be16(&src[2]); +} + +/** + * @brief Get a 40-bit integer stored in big-endian format. + * + * Get a 40-bit integer, stored in big-endian format in a potentially + * unaligned memory location, and convert it to the host endianness. + * + * @param src Location of the big-endian 40-bit integer to get. + * + * @return 40-bit integer in host endianness. + */ +static inline uint64_t sys_get_be40(const uint8_t src[5]) +{ + return ((uint64_t)sys_get_be32(&src[0]) << 8) | src[4]; +} + +/** + * @brief Get a 48-bit integer stored in big-endian format. + * + * Get a 48-bit integer, stored in big-endian format in a potentially + * unaligned memory location, and convert it to the host endianness. + * + * @param src Location of the big-endian 48-bit integer to get. + * + * @return 48-bit integer in host endianness. + */ +static inline uint64_t sys_get_be48(const uint8_t src[6]) +{ + return ((uint64_t)sys_get_be32(&src[0]) << 16) | sys_get_be16(&src[4]); +} + +/** + * @brief Get a 64-bit integer stored in big-endian format. + * + * Get a 64-bit integer, stored in big-endian format in a potentially + * unaligned memory location, and convert it to the host endianness. + * + * @param src Location of the big-endian 64-bit integer to get. + * + * @return 64-bit integer in host endianness. + */ +static inline uint64_t sys_get_be64(const uint8_t src[8]) +{ + return ((uint64_t)sys_get_be32(&src[0]) << 32) | sys_get_be32(&src[4]); +} + +/** + * @brief Get a 16-bit integer stored in little-endian format. + * + * Get a 16-bit integer, stored in little-endian format in a potentially + * unaligned memory location, and convert it to the host endianness. + * + * @param src Location of the little-endian 16-bit integer to get. + * + * @return 16-bit integer in host endianness. + */ +static inline uint16_t sys_get_le16(const uint8_t src[2]) +{ + return ((uint16_t)src[1] << 8) | src[0]; +} + +/** + * @brief Get a 24-bit integer stored in little-endian format. + * + * Get a 24-bit integer, stored in little-endian format in a potentially + * unaligned memory location, and convert it to the host endianness. + * + * @param src Location of the little-endian 24-bit integer to get. + * + * @return 24-bit integer in host endianness. + */ +static inline uint32_t sys_get_le24(const uint8_t src[3]) +{ + return ((uint32_t)src[2] << 16) | sys_get_le16(&src[0]); +} + +/** + * @brief Get a 32-bit integer stored in little-endian format. + * + * Get a 32-bit integer, stored in little-endian format in a potentially + * unaligned memory location, and convert it to the host endianness. + * + * @param src Location of the little-endian 32-bit integer to get. + * + * @return 32-bit integer in host endianness. + */ +static inline uint32_t sys_get_le32(const uint8_t src[4]) +{ + return ((uint32_t)sys_get_le16(&src[2]) << 16) | sys_get_le16(&src[0]); +} + +/** + * @brief Get a 40-bit integer stored in little-endian format. + * + * Get a 40-bit integer, stored in little-endian format in a potentially + * unaligned memory location, and convert it to the host endianness. + * + * @param src Location of the little-endian 40-bit integer to get. + * + * @return 40-bit integer in host endianness. + */ +static inline uint64_t sys_get_le40(const uint8_t src[5]) +{ + return ((uint64_t)sys_get_le32(&src[1]) << 8) | src[0]; +} + +/** + * @brief Get a 48-bit integer stored in little-endian format. + * + * Get a 48-bit integer, stored in little-endian format in a potentially + * unaligned memory location, and convert it to the host endianness. + * + * @param src Location of the little-endian 48-bit integer to get. + * + * @return 48-bit integer in host endianness. + */ +static inline uint64_t sys_get_le48(const uint8_t src[6]) +{ + return ((uint64_t)sys_get_le32(&src[2]) << 16) | sys_get_le16(&src[0]); +} + +/** + * @brief Get a 64-bit integer stored in little-endian format. + * + * Get a 64-bit integer, stored in little-endian format in a potentially + * unaligned memory location, and convert it to the host endianness. + * + * @param src Location of the little-endian 64-bit integer to get. + * + * @return 64-bit integer in host endianness. + */ +static inline uint64_t sys_get_le64(const uint8_t src[8]) +{ + return ((uint64_t)sys_get_le32(&src[4]) << 32) | sys_get_le32(&src[0]); +} + +/** + * @brief Swap one buffer content into another + * + * Copy the content of src buffer into dst buffer in reversed order, + * i.e.: src[n] will be put in dst[end-n] + * Where n is an index and 'end' the last index in both arrays. + * The 2 memory pointers must be pointing to different areas, and have + * a minimum size of given length. + * + * @param dst A valid pointer on a memory area where to copy the data in + * @param src A valid pointer on a memory area where to copy the data from + * @param length Size of both dst and src memory areas + */ +static inline void sys_memcpy_swap(void *dst, const void *src, size_t length) +{ + uint8_t *pdst = (uint8_t *)dst; + const uint8_t *psrc = (const uint8_t *)src; + + __ASSERT(((psrc < pdst && (psrc + length) <= pdst) || + (psrc > pdst && (pdst + length) <= psrc)), + "Source and destination buffers must not overlap"); + + psrc += length - 1; + + for (; length > 0; length--) { + *pdst++ = *psrc--; + } +} + +/** + * @brief Swap buffer content + * + * In-place memory swap, where final content will be reversed. + * I.e.: buf[n] will be put in buf[end-n] + * Where n is an index and 'end' the last index of buf. + * + * @param buf A valid pointer on a memory area to swap + * @param length Size of buf memory area + */ +static inline void sys_mem_swap(void *buf, size_t length) +{ + size_t i; + + for (i = 0; i < (length / 2); i++) { + uint8_t tmp = ((uint8_t *)buf)[i]; + + ((uint8_t *)buf)[i] = ((uint8_t *)buf)[length - 1 - i]; + ((uint8_t *)buf)[length - 1 - i] = tmp; + } +} + +/** + * @brief Convert buffer from little-endian to host endianness. + * + * @param buf A valid pointer on a memory area to convert from little-endian to host endianness. + * @param length Size of buf memory area + */ +static inline void sys_le_to_cpu(void *buf, size_t length) +{ + if (IS_ENABLED(CONFIG_BIG_ENDIAN)) { + sys_mem_swap(buf, length); + } +} + +/** + * @brief Convert buffer from host endianness to little-endian. + * + * @param buf A valid pointer on a memory area to convert from host endianness to little-endian. + * @param length Size of buf memory area + */ +static inline void sys_cpu_to_le(void *buf, size_t length) +{ + if (IS_ENABLED(CONFIG_BIG_ENDIAN)) { + sys_mem_swap(buf, length); + } +} + +/** + * @brief Convert buffer from big-endian to host endianness. + * + * @param buf A valid pointer on a memory area to convert from big-endian to host endianness. + * @param length Size of buf memory area + */ +static inline void sys_be_to_cpu(void *buf, size_t length) +{ + if (IS_ENABLED(CONFIG_LITTLE_ENDIAN)) { + sys_mem_swap(buf, length); + } +} + +/** + * @brief Convert buffer from host endianness to big-endian. + * + * @param buf A valid pointer on a memory area to convert from host endianness to big-endian. + * @param length Size of buf memory area + */ +static inline void sys_cpu_to_be(void *buf, size_t length) +{ + if (IS_ENABLED(CONFIG_LITTLE_ENDIAN)) { + sys_mem_swap(buf, length); + } +} + +/** + * @brief Put a buffer as little-endian to arbitrary location. + * + * Put a buffer originally in host endianness, to a + * potentially unaligned memory location in little-endian format. + * + * @param dst A valid pointer on a memory area where to copy the data in + * @param src A valid pointer on a memory area where to copy the data from + * @param length Size of both dst and src memory areas + */ +static inline void sys_put_le(void *dst, const void *src, size_t length) +{ + if (IS_ENABLED(CONFIG_LITTLE_ENDIAN)) { + (void)memcpy(dst, src, length); + } else { + sys_memcpy_swap(dst, src, length); + } +} + +/** + * @brief Put a buffer as big-endian to arbitrary location. + * + * Put a buffer originally in host endianness, to a + * potentially unaligned memory location in big-endian format. + * + * @param dst A valid pointer on a memory area where to copy the data in + * @param src A valid pointer on a memory area where to copy the data from + * @param length Size of both dst and src memory areas + */ +static inline void sys_put_be(void *dst, const void *src, size_t length) +{ + if (IS_ENABLED(CONFIG_LITTLE_ENDIAN)) { + sys_memcpy_swap(dst, src, length); + } else { + (void)memcpy(dst, src, length); + } +} + +/** + * @brief Get a buffer stored in little-endian format. + * + * Get a buffer, stored in little-endian format in a potentially + * unaligned memory location, and convert it to the host endianness. + * + * @param dst A valid pointer on a memory area where to copy the data in + * @param src A valid pointer on a memory area where to copy the data from + * @param length Size of both dst and src memory areas + */ +static inline void sys_get_le(void *dst, const void *src, size_t length) +{ + if (IS_ENABLED(CONFIG_LITTLE_ENDIAN)) { + (void)memcpy(dst, src, length); + } else { + sys_memcpy_swap(dst, src, length); + } +} + +/** + * @brief Get a buffer stored in big-endian format. + * + * Get a buffer, stored in big-endian format in a potentially + * unaligned memory location, and convert it to the host endianness. + * + * @param dst A valid pointer on a memory area where to copy the data in + * @param src A valid pointer on a memory area where to copy the data from + * @param length Size of both dst and src memory areas + */ +static inline void sys_get_be(void *dst, const void *src, size_t length) +{ + if (IS_ENABLED(CONFIG_LITTLE_ENDIAN)) { + sys_memcpy_swap(dst, src, length); + } else { + (void)memcpy(dst, src, length); + } +} + +#endif /* ZEPHYR_INCLUDE_SYS_BYTEORDER_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/sys/check.h b/components/bt/esp_ble_audio/include/zephyr/sys/check.h new file mode 100644 index 0000000000..311865a07f --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/sys/check.h @@ -0,0 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2019 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#define CHECKIF(expr) if (expr) diff --git a/components/bt/esp_ble_audio/include/zephyr/sys/crc.h b/components/bt/esp_ble_audio/include/zephyr/sys/crc.h new file mode 100644 index 0000000000..5b479dc1fc --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/sys/crc.h @@ -0,0 +1,531 @@ +/* + * SPDX-FileCopyrightText: 2018 Workaround GmbH. + * SPDX-FileCopyrightText: 2017 Intel Corporation. + * SPDX-FileCopyrightText: 2017 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2015 Runtime Inc + * SPDX-FileCopyrightText: 2018 Google LLC. + * SPDX-FileCopyrightText: 2022 Meta + * SPDX-FileCopyrightText: 2024 Intercreate, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ +/** @file + * @brief CRC computation function + */ + +#ifndef ZEPHYR_INCLUDE_SYS_CRC_H_ +#define ZEPHYR_INCLUDE_SYS_CRC_H_ + +#include +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Initial value expected to be used at the beginning of the crc8_ccitt + * computation. + */ +#define CRC8_CCITT_INITIAL_VALUE 0xFF +#define CRC8_ROHC_INITIAL_VALUE 0xFF + +/* Initial value expected to be used at the beginning of the OpenPGP CRC-24 computation. */ +#define CRC24_PGP_INITIAL_VALUE 0x00B704CEU +/* + * The CRC-24 value is stored on a 32-bit value, only the 3 least significant bytes + * are meaningful. Use the following mask to only keep the CRC-24 value. + */ +#define CRC24_FINAL_VALUE_MASK 0x00FFFFFFU + +/** + * @defgroup checksum Checksum + * @ingroup os_services + */ + +/** + * @defgroup crc CRC + * @ingroup checksum + * @{ + */ + +/** + * @brief CRC polynomial definitions + * @anchor CRC_POLYNOMIAL + * + * @{ + */ + +/** CRC4 polynomial */ +#define CRC4_POLY 0x3 + +/** CRC4_TI polynomial */ +#define CRC4_REFLECT_POLY 0xC + +/** CRC7_BE polynomial */ +#define CRC7_BE_POLY 0x09 + +/** CRC8 polynomial */ +#define CRC8_POLY 0x07 + +/** CRC8_CCITT polynomial */ +#define CRC8_REFLECT_POLY 0xE0 + +/** CRC8_ROHC polynomial */ +#define CRC16_POLY 0x8005 + +/** CRC16_ANSI polynomial */ +#define CRC16_REFLECT_POLY 0xA001 + +/** CRC16_CCITT polynomial */ +#define CRC16_CCITT_POLY 0x1021 + +/** CRC16_ITU_T polynomial */ +#define CRC24_PGP_POLY 0x01864CFBU + +/** CRC32_C polynomial */ +#define CRC32_IEEE_POLY 0x04C11DB7U + +/** CRC32C polynomial */ +#define CRC32C_POLY 0x1EDC6F41U + +/** CRC32_K_4_2 polynomial */ +#define CRC32K_4_2_POLY 0x93A409EBU + +/** @} */ + +/** + * @brief CRC algorithm enumeration + * + * These values should be used with the @ref crc dispatch function. + */ +enum crc_type { + CRC4, /**< Use @ref crc4 */ + CRC4_TI, /**< Use @ref crc4_ti */ + CRC7_BE, /**< Use @ref crc7_be */ + CRC8, /**< Use @ref crc8 */ + CRC8_CCITT, /**< Use @ref crc8_ccitt */ + CRC8_ROHC, /**< Use @ref crc8_rohc */ + CRC16, /**< Use @ref crc16 */ + CRC16_ANSI, /**< Use @ref crc16_ansi */ + CRC16_CCITT, /**< Use @ref crc16_ccitt */ + CRC16_ITU_T, /**< Use @ref crc16_itu_t */ + CRC24_PGP, /**< Use @ref crc24_pgp */ + CRC32_C, /**< Use @ref crc32_c */ + CRC32_IEEE, /**< Use @ref crc32_ieee */ + CRC32_K_4_2, /**< Use @ref crc32_k_4_2_update */ +}; + +/** + * @brief Generic function for computing a CRC-16 without input or output + * reflection. + * + * Compute CRC-16 by passing in the address of the input, the input length + * and polynomial used in addition to the initial value. This is O(n*8) where n + * is the length of the buffer provided. No reflection is performed. + * + * @note If you are planning to use a CRC based on poly 0x1012 the functions + * crc16_itu_t() is faster and thus recommended over this one. + * + * @param poly The polynomial to use omitting the leading x^16 + * coefficient + * @param seed Initial value for the CRC computation + * @param src Input bytes for the computation + * @param len Length of the input in bytes + * + * @return The computed CRC16 value (without any XOR applied to it) + */ +uint16_t crc16(uint16_t poly, uint16_t seed, const uint8_t *src, size_t len); + +/** + * @brief Generic function for computing a CRC-16 with input and output + * reflection. + * + * Compute CRC-16 by passing in the address of the input, the input length + * and polynomial used in addition to the initial value. This is O(n*8) where n + * is the length of the buffer provided. Both input and output are reflected. + * + * @note If you are planning to use a CRC based on poly 0x1012 the function + * crc16_ccitt() is faster and thus recommended over this one. + * + * The following checksums can, among others, be calculated by this function, + * depending on the value provided for the initial seed and the value the final + * calculated CRC is XORed with: + * + * - CRC-16/ANSI, CRC-16/MODBUS, CRC-16/USB, CRC-16/IBM + * https://reveng.sourceforge.io/crc-catalogue/16.htm#crc.cat.crc-16-modbus + * poly: 0x8005 (0xA001) initial seed: 0xffff, xor output: 0x0000 + * + * @param poly The polynomial to use omitting the leading x^16 + * coefficient. Important: please reflect the poly. For example, + * use 0xA001 instead of 0x8005 for CRC-16-MODBUS. + * @param seed Initial value for the CRC computation + * @param src Input bytes for the computation + * @param len Length of the input in bytes + * + * @return The computed CRC16 value (without any XOR applied to it) + */ +uint16_t crc16_reflect(uint16_t poly, uint16_t seed, const uint8_t *src, size_t len); +/** + * @brief Generic function for computing CRC 8 + * + * Compute CRC 8 by passing in the address of the input, the input length + * and polynomial used in addition to the initial value. + * + * @param src Input bytes for the computation + * @param len Length of the input in bytes + * @param polynomial The polynomial to use omitting the leading x^8 + * coefficient + * @param initial_value Initial value for the CRC computation + * @param reversed Should we use reflected/reversed values or not + * + * @return The computed CRC8 value + */ +uint8_t crc8(const uint8_t *src, size_t len, uint8_t polynomial, uint8_t initial_value, + bool reversed); + +/** + * @brief Compute the checksum of a buffer with polynomial 0x1021, reflecting + * input and output. + * + * This function is able to calculate any CRC that uses 0x1021 as it polynomial + * and requires reflecting both the input and the output. It is a fast variant + * that runs in O(n) time, where n is the length of the input buffer. + * + * The following checksums can, among others, be calculated by this function, + * depending on the value provided for the initial seed and the value the final + * calculated CRC is XORed with: + * + * - CRC-16/CCITT, CRC-16/CCITT-TRUE, CRC-16/KERMIT + * https://reveng.sourceforge.io/crc-catalogue/16.htm#crc.cat.crc-16-kermit + * initial seed: 0x0000, xor output: 0x0000 + * + * - CRC-16/X-25, CRC-16/IBM-SDLC, CRC-16/ISO-HDLC + * https://reveng.sourceforge.io/crc-catalogue/16.htm#crc.cat.crc-16-ibm-sdlc + * initial seed: 0xffff, xor output: 0xffff + * + * @note To calculate the CRC across non-contiguous blocks use the return + * value from block N-1 as the seed for block N. + * + * See ITU-T Recommendation V.41 (November 1988). + * + * @param seed Value to seed the CRC with + * @param src Input bytes for the computation + * @param len Length of the input in bytes + * + * @return The computed CRC16 value (without any XOR applied to it) + */ +uint16_t crc16_ccitt(uint16_t seed, const uint8_t *src, size_t len); + +/** + * @brief Compute the checksum of a buffer with polynomial 0x1021, no + * reflection of input or output. + * + * This function is able to calculate any CRC that uses 0x1021 as it polynomial + * and requires no reflection on both the input and the output. It is a fast + * variant that runs in O(n) time, where n is the length of the input buffer. + * + * The following checksums can, among others, be calculated by this function, + * depending on the value provided for the initial seed and the value the final + * calculated CRC is XORed with: + * + * - CRC-16/XMODEM, CRC-16/ACORN, CRC-16/LTE + * https://reveng.sourceforge.io/crc-catalogue/16.htm#crc.cat.crc-16-xmodem + * initial seed: 0x0000, xor output: 0x0000 + * + * - CRC16/CCITT-FALSE, CRC-16/IBM-3740, CRC-16/AUTOSAR + * https://reveng.sourceforge.io/crc-catalogue/16.htm#crc.cat.crc-16-ibm-3740 + * initial seed: 0xffff, xor output: 0x0000 + * + * - CRC-16/GSM + * https://reveng.sourceforge.io/crc-catalogue/16.htm#crc.cat.crc-16-gsm + * initial seed: 0x0000, xor output: 0xffff + * + * @note To calculate the CRC across non-contiguous blocks use the return + * value from block N-1 as the seed for block N. + * + * See ITU-T Recommendation V.41 (November 1988) (MSB first). + * + * @param seed Value to seed the CRC with + * @param src Input bytes for the computation + * @param len Length of the input in bytes + * + * @return The computed CRC16 value (without any XOR applied to it) + */ +uint16_t crc16_itu_t(uint16_t seed, const uint8_t *src, size_t len); + +/** + * @brief Compute the ANSI (or Modbus) variant of CRC-16 + * + * The ANSI variant of CRC-16 uses 0x8005 (0xA001 reflected) as its polynomial + * with the initial * value set to 0xffff. + * + * @param src Input bytes for the computation + * @param len Length of the input in bytes + * + * @return The computed CRC16 value + */ +static inline uint16_t crc16_ansi(const uint8_t *src, size_t len) +{ + return crc16_reflect(0xA001, 0xffff, src, len); +} + +/** + * @brief Generate IEEE conform CRC32 checksum. + * + * @param data Pointer to data on which the CRC should be calculated. + * @param len Data length. + * + * @return CRC32 value. + * + */ +uint32_t crc32_ieee(const uint8_t *data, size_t len); + +/** + * @brief Update an IEEE conforming CRC32 checksum. + * + * @param crc CRC32 checksum that needs to be updated. + * @param data Pointer to data on which the CRC should be calculated. + * @param len Data length. + * + * @return CRC32 value. + * + */ +uint32_t crc32_ieee_update(uint32_t crc, const uint8_t *data, size_t len); + +/** + * @brief Calculate CRC32C (Castagnoli) checksum. + * + * @param crc CRC32C checksum that needs to be updated. + * @param data Pointer to data on which the CRC should be calculated. + * @param len Data length. + * @param first_pkt Whether this is the first packet in the stream. + * @param last_pkt Whether this is the last packet in the stream. + * + * @return CRC32 value. + * + */ +uint32_t crc32_c(uint32_t crc, const uint8_t *data, + size_t len, bool first_pkt, bool last_pkt); + +/** + * @brief Update a CRC-32K/4.2 (*op) (Koopman) checksum. This is a good HD=4 + * checksum up to 2,147,483,615 bits and HD=5/6 up to 6,167 bits. + * + * Hamming Distance and properties: + * + * - Polynomial: 0x93a409eb + * - reflect-in: false + * - initial value (xor-in): provided by caller as crc argument (0xFFFFFFFF is OK) + * - reflect-out: false + * - xor-out: 0 + * - HD=4 @ 2,147,483,615 bits + * - HD=5 @ 6,167 bits + * - HD=6 @ 6,167 bits + * - HD=7 @ 148 bits + * + * Reference: https://users.ece.cmu.edu/~koopman/crc/crc32.html + * + * @param crc CRC32 checksum that needs to be updated. + * @param data Pointer to data on which the CRC should be calculated. + * @param len Data length. + * + * @return CRC32 value. + */ +uint32_t crc32_k_4_2_update(uint32_t crc, const uint8_t *data, size_t len); + +/** + * @brief Compute CCITT variant of CRC 8 + * + * Normal CCITT variant of CRC 8 is using 0x07. + * + * @param initial_value Initial value for the CRC computation + * @param buf Input bytes for the computation + * @param len Length of the input in bytes + * + * @return The computed CRC8 value + */ +uint8_t crc8_ccitt(uint8_t initial_value, const void *buf, size_t len); + +/** + * @brief Compute ROHC variant of CRC 8 + * + * ROHC (Robust Header Compression) variant of CRC 8. + * Uses 0x07 as the polynomial with reflection. + * + * @param initial_value Initial value for the CRC computation + * @param buf Input bytes for the computation + * @param len Length of the input in bytes + * + * @return The computed CRC8 value + */ +uint8_t crc8_rohc(uint8_t initial_value, const void *buf, size_t len); + +/** + * @brief Compute the CRC-7 checksum of a buffer. + * + * See JESD84-A441. Used by the MMC protocol. Uses 0x09 as the + * polynomial with no reflection. The CRC is left + * justified, so bit 7 of the result is bit 6 of the CRC. + * + * @param seed Value to seed the CRC with + * @param src Input bytes for the computation + * @param len Length of the input in bytes + * + * @return The computed CRC7 value + */ +uint8_t crc7_be(uint8_t seed, const uint8_t *src, size_t len); + +/** + * @brief Compute the CRC-4 checksum of a buffer. + * + * Used by the TMAG5170 sensor. Uses 0x03 as the + * polynomial with no reflection. 4 most significant + * bits of the CRC result will be set to zero. + * + * @param seed Value to seed the CRC with + * @param src Input bytes for the computation + * @param len Length of the input in bytes + * + * @return The computed CRC4 value + */ +uint8_t crc4_ti(uint8_t seed, const uint8_t *src, size_t len); + +/** + * @brief Generic function for computing CRC 4 + * + * Compute CRC 4 by passing in the address of the input, the input length + * and polynomial used in addition to the initial value. The input buffer + * must be aligned to a whole byte. It is guaranteed that 4 most significant + * bits of the result will be set to zero. + * + * @param src Input bytes for the computation + * @param len Length of the input in bytes + * @param polynomial The polynomial to use omitting the leading x^4 + * coefficient + * @param initial_value Initial value for the CRC computation + * @param reversed Should we use reflected/reversed values or not + * + * @return The computed CRC4 value + */ +uint8_t crc4(const uint8_t *src, size_t len, uint8_t polynomial, uint8_t initial_value, + bool reversed); + +/** + * @brief Generate an OpenPGP CRC-24 checksum as defined in RFC 4880 section 6.1. + * + * @param data A pointer to the data on which the CRC will be calculated. + * @param len Data length in bytes. + * + * @return The CRC-24 value. + */ +uint32_t crc24_pgp(const uint8_t *data, size_t len); + +/** + * @brief Update an OpenPGP CRC-24 checksum. + * + * @param crc The CRC-24 checksum that needs to be updated. The full 32-bit value of the CRC needs + * to be used between calls, do not mask the value to keep only the last 24 bits. + * @param data A pointer to the data on which the CRC will be calculated. + * @param len Data length in bytes. + * + * @return The CRC-24 value. When the last buffer of data has been processed, mask the value + * with CRC24_FINAL_VALUE_MASK to keep only the meaningful 24 bits of the CRC result. + */ +uint32_t crc24_pgp_update(uint32_t crc, const uint8_t *data, size_t len); + +/** + * @brief Calculate an RTCM3 CRC24Q frame checksum + * + * @param[in] data RTCM3 Frame + * @param[in] len Frame length in bytes. + * + * @return 0 if the data-frame contains a checksum and it matches. + * @return Result if data-frame does not contain checksum. + */ +uint32_t crc24q_rtcm3(const uint8_t *data, size_t len); + +/** + * @brief Compute a CRC checksum, in a generic way. + * + * This is a dispatch function that calls the individual CRC routine + * determined by @p type. + * + * For 7, 8, 16 and 24-bit CRCs, the relevant @p seed and @p poly values should + * be passed in via the least-significant byte(s). + * + * Similarly, for 7, 8, 16 and 24-bit CRCs, the relevant result is stored in the + * least-significant byte(s) of the returned value. + * + * @param type CRC algorithm to use. + * @param src Input bytes for the computation + * @param len Length of the input in bytes + * @param seed Seed or existing CRC value to update + * @param poly The polynomial to use omitting the leading coefficient + * @param reflect Should we use reflected/reversed values or not + * @param first Whether this is the first packet in the stream. + * @param last Whether this is the last packet in the stream. + * @return uint32_t the computed CRC value + */ +static inline uint32_t crc_by_type(enum crc_type type, const uint8_t *src, size_t len, + uint32_t seed, uint32_t poly, bool reflect, bool first, + bool last) +{ + switch (type) { + case CRC4: + return crc4(src, len, poly, seed, reflect); + case CRC4_TI: + return crc4_ti(seed, src, len); + case CRC7_BE: + return crc7_be(seed, src, len); + case CRC8: + return crc8(src, len, poly, seed, reflect); + case CRC8_CCITT: + return crc8_ccitt(seed, src, len); + case CRC8_ROHC: + return crc8_rohc(seed, src, len); + case CRC16: + if (reflect) { + return crc16_reflect(poly, seed, src, len); + } else { + return crc16(poly, seed, src, len); + } + case CRC16_ANSI: + return crc16_ansi(src, len); + case CRC16_CCITT: + return crc16_ccitt(seed, src, len); + case CRC16_ITU_T: + return crc16_itu_t(seed, src, len); + case CRC24_PGP: { + uint32_t crc = crc24_pgp_update(seed, src, len); + + if (last) { + crc &= CRC24_FINAL_VALUE_MASK; + } + return crc; + } + case CRC32_C: + return crc32_c(seed, src, len, first, last); + case CRC32_IEEE: + return crc32_ieee_update(seed, src, len); + case CRC32_K_4_2: + return crc32_k_4_2_update(seed, src, len); + default: + break; + } + + __ASSERT_NO_MSG(false); + return -1; +} + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/bt/esp_ble_audio/include/zephyr/sys/dlist.h b/components/bt/esp_ble_audio/include/zephyr/sys/dlist.h new file mode 100644 index 0000000000..8c2d850f19 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/sys/dlist.h @@ -0,0 +1,581 @@ +/* + * SPDX-FileCopyrightText: 2013-2015 Wind River Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @defgroup doubly-linked-list_apis Doubly-linked list + * @ingroup datastructure_apis + * + * @brief Doubly-linked list implementation + * + * Doubly-linked list implementation using inline macros/functions. + * This API is not thread safe, and thus if a list is used across threads, + * calls to functions must be protected with synchronization primitives. + * + * The lists are expected to be initialized such that both the head and tail + * pointers point to the list itself. Initializing the lists in such a fashion + * simplifies the adding and removing of nodes to/from the list. + * + * @{ + */ + +#ifndef ZEPHYR_INCLUDE_SYS_DLIST_H_ +#define ZEPHYR_INCLUDE_SYS_DLIST_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct _dnode { + union { + struct _dnode *head; /* ptr to head of list (sys_dlist_t) */ + struct _dnode *next; /* ptr to next node (sys_dnode_t) */ + }; + union { + struct _dnode *tail; /* ptr to tail of list (sys_dlist_t) */ + struct _dnode *prev; /* ptr to previous node (sys_dnode_t) */ + }; +}; + +/** + * @brief Doubly-linked list structure. + */ +typedef struct _dnode sys_dlist_t; +/** + * @brief Doubly-linked list node structure. + */ +typedef struct _dnode sys_dnode_t; + +/** + * @brief Provide the primitive to iterate on a list + * Note: the loop is unsafe and thus __dn should not be removed + * + * User _MUST_ add the loop statement curly braces enclosing its own code: + * + * SYS_DLIST_FOR_EACH_NODE(l, n) { + * + * } + * + * This and other SYS_DLIST_*() macros are not thread safe. + * + * @param __dl A pointer on a sys_dlist_t to iterate on + * @param __dn A sys_dnode_t pointer to peek each node of the list + */ +#define SYS_DLIST_FOR_EACH_NODE(__dl, __dn) \ + for (__dn = sys_dlist_peek_head(__dl); __dn != NULL; \ + __dn = sys_dlist_peek_next(__dl, __dn)) + +/** + * @brief Provide the primitive to iterate on a list, from a node in the list + * Note: the loop is unsafe and thus __dn should not be removed + * + * User _MUST_ add the loop statement curly braces enclosing its own code: + * + * SYS_DLIST_ITERATE_FROM_NODE(l, n) { + * + * } + * + * Like SYS_DLIST_FOR_EACH_NODE(), but __dn already contains a node in the list + * where to start searching for the next entry from. If NULL, it starts from + * the head. + * + * This and other SYS_DLIST_*() macros are not thread safe. + * + * @param __dl A pointer on a sys_dlist_t to iterate on + * @param __dn A sys_dnode_t pointer to peek each node of the list; + * it contains the starting node, or NULL to start from the head + */ +#define SYS_DLIST_ITERATE_FROM_NODE(__dl, __dn) \ + for (__dn = __dn ? sys_dlist_peek_next_no_check(__dl, __dn) \ + : sys_dlist_peek_head(__dl); \ + __dn != NULL; \ + __dn = sys_dlist_peek_next(__dl, __dn)) + +/** + * @brief Provide the primitive to safely iterate on a list + * Note: __dn can be removed, it will not break the loop. + * + * User _MUST_ add the loop statement curly braces enclosing its own code: + * + * SYS_DLIST_FOR_EACH_NODE_SAFE(l, n, s) { + * + * } + * + * This and other SYS_DLIST_*() macros are not thread safe. + * + * @param __dl A pointer on a sys_dlist_t to iterate on + * @param __dn A sys_dnode_t pointer to peek each node of the list + * @param __dns A sys_dnode_t pointer for the loop to run safely + */ +#define SYS_DLIST_FOR_EACH_NODE_SAFE(__dl, __dn, __dns) \ + for ((__dn) = sys_dlist_peek_head(__dl), \ + (__dns) = sys_dlist_peek_next((__dl), (__dn)); \ + (__dn) != NULL; (__dn) = (__dns), \ + (__dns) = sys_dlist_peek_next(__dl, __dn)) + +/** + * @brief Provide the primitive to resolve the container of a list node + * Note: it is safe to use with NULL pointer nodes + * + * @param __dn A pointer on a sys_dnode_t to get its container + * @param __cn Container struct type pointer + * @param __n The field name of sys_dnode_t within the container struct + */ +#define SYS_DLIST_CONTAINER(__dn, __cn, __n) \ + (((__dn) != NULL) ? CONTAINER_OF(__dn, __typeof__(*(__cn)), __n) : NULL) +/** + * @brief Provide the primitive to peek container of the list head + * + * @param __dl A pointer on a sys_dlist_t to peek + * @param __cn Container struct type pointer + * @param __n The field name of sys_dnode_t within the container struct + */ +#define SYS_DLIST_PEEK_HEAD_CONTAINER(__dl, __cn, __n) \ + SYS_DLIST_CONTAINER(sys_dlist_peek_head(__dl), __cn, __n) + +/** + * @brief Provide the primitive to peek the next container + * + * @param __dl A pointer on a sys_dlist_t to peek + * @param __cn Container struct type pointer + * @param __n The field name of sys_dnode_t within the container struct + */ +#define SYS_DLIST_PEEK_NEXT_CONTAINER(__dl, __cn, __n) \ + (((__cn) != NULL) ? \ + SYS_DLIST_CONTAINER(sys_dlist_peek_next((__dl), &((__cn)->__n)), \ + __cn, __n) : NULL) + +/** + * @brief Provide the primitive to iterate on a list under a container + * Note: the loop is unsafe and thus __cn should not be detached + * + * User _MUST_ add the loop statement curly braces enclosing its own code: + * + * SYS_DLIST_FOR_EACH_CONTAINER(l, c, n) { + * + * } + * + * @param __dl A pointer on a sys_dlist_t to iterate on + * @param __cn A container struct type pointer to peek each entry of the list + * @param __n The field name of sys_dnode_t within the container struct + */ +#define SYS_DLIST_FOR_EACH_CONTAINER(__dl, __cn, __n) \ + for ((__cn) = SYS_DLIST_PEEK_HEAD_CONTAINER(__dl, __cn, __n); \ + (__cn) != NULL; \ + (__cn) = SYS_DLIST_PEEK_NEXT_CONTAINER(__dl, __cn, __n)) + +/** + * @brief Provide the primitive to safely iterate on a list under a container + * Note: __cn can be detached, it will not break the loop. + * + * User _MUST_ add the loop statement curly braces enclosing its own code: + * + * SYS_DLIST_FOR_EACH_CONTAINER_SAFE(l, c, cn, n) { + * + * } + * + * @param __dl A pointer on a sys_dlist_t to iterate on + * @param __cn A container struct type pointer to peek each entry of the list + * @param __cns A container struct type pointer for the loop to run safely + * @param __n The field name of sys_dnode_t within the container struct + */ +#define SYS_DLIST_FOR_EACH_CONTAINER_SAFE(__dl, __cn, __cns, __n) \ + for ((__cn) = SYS_DLIST_PEEK_HEAD_CONTAINER(__dl, __cn, __n), \ + (__cns) = SYS_DLIST_PEEK_NEXT_CONTAINER(__dl, __cn, __n); \ + (__cn) != NULL; (__cn) = (__cns), \ + (__cns) = SYS_DLIST_PEEK_NEXT_CONTAINER(__dl, __cn, __n)) + +/** + * @brief initialize list to its empty state + * + * @param list the doubly-linked list + */ + +static inline void sys_dlist_init(sys_dlist_t *list) +{ + list->head = (sys_dnode_t *)list; + list->tail = (sys_dnode_t *)list; +} + +/** + * @brief Static initializer for a doubly-linked list + */ +#define SYS_DLIST_STATIC_INIT(ptr_to_list) { {(ptr_to_list)}, {(ptr_to_list)} } + +/** + * @brief initialize node to its state when not in a list + * + * @param node the node + */ + +static inline void sys_dnode_init(sys_dnode_t *node) +{ + node->next = NULL; + node->prev = NULL; +} + +/** + * @brief check if a node is a member of any list + * + * @param node the node + * + * @return true if node is linked into a list, false if it is not + */ + +static inline bool sys_dnode_is_linked(const sys_dnode_t *node) +{ + return node->next != NULL; +} + +/** + * @brief check if a node is the list's head + * + * @param list the doubly-linked list to operate on + * @param node the node to check + * + * @return true if node is the head, false otherwise + */ + +static inline bool sys_dlist_is_head(const sys_dlist_t *list, const sys_dnode_t *node) +{ + return list->head == node; +} + +/** + * @brief check if a node is the list's tail + * + * @param list the doubly-linked list to operate on + * @param node the node to check + * + * @return true if node is the tail, false otherwise + */ + +static inline bool sys_dlist_is_tail(const sys_dlist_t *list, const sys_dnode_t *node) +{ + return list->tail == node; +} + +/** + * @brief check if the list is empty + * + * @param list the doubly-linked list to operate on + * + * @return true if empty, false otherwise + */ + +static inline bool sys_dlist_is_empty(const sys_dlist_t *list) +{ + return list->head == list; +} + +/** + * @brief check if more than one node present + * + * This and other sys_dlist_*() functions are not thread safe. + * + * @param list the doubly-linked list to operate on + * + * @return true if multiple nodes, false otherwise + */ + +static inline bool sys_dlist_has_multiple_nodes(const sys_dlist_t *list) +{ + return list->head != list->tail; +} + +/** + * @brief get a reference to the head item in the list + * + * @param list the doubly-linked list to operate on + * + * @return a pointer to the head element, NULL if list is empty + */ + +static inline sys_dnode_t *sys_dlist_peek_head(const sys_dlist_t *list) +{ + return sys_dlist_is_empty(list) ? NULL : list->head; +} + +/** + * @brief get a reference to the head item in the list + * + * The list must be known to be non-empty. + * + * @param list the doubly-linked list to operate on + * + * @return a pointer to the head element + */ + +static inline sys_dnode_t *sys_dlist_peek_head_not_empty(const sys_dlist_t *list) +{ + return list->head; +} + +/** + * @brief get a reference to the next item in the list, node is not NULL + * + * Faster than sys_dlist_peek_next() if node is known not to be NULL. + * + * @param list the doubly-linked list to operate on + * @param node the node from which to get the next element in the list + * + * @return a pointer to the next element from a node, NULL if node is the tail + */ + +static inline sys_dnode_t *sys_dlist_peek_next_no_check(const sys_dlist_t *list, + const sys_dnode_t *node) +{ + return (node == list->tail) ? NULL : node->next; +} + +/** + * @brief get a reference to the next item in the list + * + * @param list the doubly-linked list to operate on + * @param node the node from which to get the next element in the list + * + * @return a pointer to the next element from a node, NULL if node is the tail + * or NULL (when node comes from reading the head of an empty list). + */ + +static inline sys_dnode_t *sys_dlist_peek_next(const sys_dlist_t *list, + const sys_dnode_t *node) +{ + return (node != NULL) ? sys_dlist_peek_next_no_check(list, node) : NULL; +} + +/** + * @brief get a reference to the previous item in the list, node is not NULL + * + * Faster than sys_dlist_peek_prev() if node is known not to be NULL. + * + * @param list the doubly-linked list to operate on + * @param node the node from which to get the previous element in the list + * + * @return a pointer to the previous element from a node, NULL if node is the + * tail + */ + +static inline sys_dnode_t *sys_dlist_peek_prev_no_check(const sys_dlist_t *list, + const sys_dnode_t *node) +{ + return (node == list->head) ? NULL : node->prev; +} + +/** + * @brief get a reference to the previous item in the list + * + * @param list the doubly-linked list to operate on + * @param node the node from which to get the previous element in the list + * + * @return a pointer to the previous element from a node, NULL if node is the + * tail or NULL (when node comes from reading the head of an empty + * list). + */ + +static inline sys_dnode_t *sys_dlist_peek_prev(const sys_dlist_t *list, + const sys_dnode_t *node) +{ + return (node != NULL) ? sys_dlist_peek_prev_no_check(list, node) : NULL; +} + +/** + * @brief get a reference to the tail item in the list + * + * @param list the doubly-linked list to operate on + * + * @return a pointer to the tail element, NULL if list is empty + */ + +static inline sys_dnode_t *sys_dlist_peek_tail(const sys_dlist_t *list) +{ + return sys_dlist_is_empty(list) ? NULL : list->tail; +} + +/** + * @brief add node to tail of list + * + * This and other sys_dlist_*() functions are not thread safe. + * + * @param list the doubly-linked list to operate on + * @param node the element to append + */ + +static inline void sys_dlist_append(sys_dlist_t *list, sys_dnode_t *node) +{ + sys_dnode_t *const tail = list->tail; + + node->next = list; + node->prev = tail; + + tail->next = node; + list->tail = node; +} + +/** + * @brief add node to head of list + * + * This and other sys_dlist_*() functions are not thread safe. + * + * @param list the doubly-linked list to operate on + * @param node the element to append + */ + +static inline void sys_dlist_prepend(sys_dlist_t *list, sys_dnode_t *node) +{ + sys_dnode_t *const head = list->head; + + node->next = head; + node->prev = list; + + head->prev = node; + list->head = node; +} + +/** + * @brief Insert a node into a list + * + * Insert a node before a specified node in a dlist. + * + * @param successor the position before which "node" will be inserted + * @param node the element to insert + */ +static inline void sys_dlist_insert(sys_dnode_t *successor, sys_dnode_t *node) +{ + sys_dnode_t *const prev = successor->prev; + + node->prev = prev; + node->next = successor; + prev->next = node; + successor->prev = node; +} + +/** + * @brief insert node at position + * + * Insert a node in a location depending on a external condition. The cond() + * function checks if the node is to be inserted _before_ the current node + * against which it is checked. + * This and other sys_dlist_*() functions are not thread safe. + * + * @param list the doubly-linked list to operate on + * @param node the element to insert + * @param cond a function that determines if the current node is the correct + * insert point + * @param data parameter to cond() + */ + +static inline void sys_dlist_insert_at(sys_dlist_t *list, sys_dnode_t *node, + int (*cond)(sys_dnode_t *node, void *data), void *data) +{ + if (sys_dlist_is_empty(list)) { + sys_dlist_append(list, node); + } else { + sys_dnode_t *pos = sys_dlist_peek_head(list); + + while ((pos != NULL) && (cond(pos, data) == 0)) { + pos = sys_dlist_peek_next(list, pos); + } + if (pos != NULL) { + sys_dlist_insert(pos, node); + } else { + sys_dlist_append(list, node); + } + } +} + +/** + * @brief remove a specific node from a list + * + * Like :c:func:`sys_dlist_remove()`, this routine removes a specific node + * from a list. However, unlike :c:func:`sys_dlist_remove()`, this routine + * does not re-initialize the removed node. One significant implication of + * this difference is that the function :c:func`sys_dnode_is_linked()` will + * not work on a dequeued node. + * + * The list is implicit from the node. The node must be part of a list. + * This and other sys_dlist_*() functions are not thread safe. + * + * @param node the node to dequeue + */ +static inline void sys_dlist_dequeue(sys_dnode_t *node) +{ + sys_dnode_t *const prev = node->prev; + sys_dnode_t *const next = node->next; + + prev->next = next; + next->prev = prev; +} + +/** + * @brief remove a specific node from a list + * + * The list is implicit from the node. The node must be part of a list. + * This and other sys_dlist_*() functions are not thread safe. + * + * @param node the node to remove + */ + +static inline void sys_dlist_remove(sys_dnode_t *node) +{ + sys_dnode_t *const prev = node->prev; + sys_dnode_t *const next = node->next; + + prev->next = next; + next->prev = prev; + sys_dnode_init(node); +} + +/** + * @brief get the first node in a list + * + * This and other sys_dlist_*() functions are not thread safe. + * + * @param list the doubly-linked list to operate on + * + * @return the first node in the list, NULL if list is empty + */ + +static inline sys_dnode_t *sys_dlist_get(sys_dlist_t *list) +{ + sys_dnode_t *node = NULL; + + if (!sys_dlist_is_empty(list)) { + node = list->head; + sys_dlist_remove(node); + } + + return node; +} + +/** + * @brief Compute the size of the given list in O(n) time + * + * @param list A pointer on the list + * + * @return an integer equal to the size of the list, or 0 if empty + */ +static inline size_t sys_dlist_len(const sys_dlist_t *list) +{ + size_t len = 0; + sys_dnode_t *node = NULL; + + SYS_DLIST_FOR_EACH_NODE(list, node) { + len++; + } + return len; +} + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_SYS_DLIST_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/sys/iterable_sections.h b/components/bt/esp_ble_audio/include/zephyr/sys/iterable_sections.h new file mode 100644 index 0000000000..dd4289dc74 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/sys/iterable_sections.h @@ -0,0 +1,10 @@ +/* + * SPDX-FileCopyrightText: 2020 Intel Corporation + * SPDX-FileCopyrightText: 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#define STRUCT_SECTION_ITERABLE(struct_type, varname) struct struct_type varname diff --git a/components/bt/esp_ble_audio/include/zephyr/sys/list_gen.h b/components/bt/esp_ble_audio/include/zephyr/sys/list_gen.h new file mode 100644 index 0000000000..e3d0539732 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/sys/list_gen.h @@ -0,0 +1,273 @@ +/* + * SPDX-FileCopyrightText: 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_SYS_LIST_GEN_H_ +#define ZEPHYR_INCLUDE_SYS_LIST_GEN_H_ + +#include +#include +#include + +#define Z_GENLIST_FOR_EACH_NODE(__lname, __l, __sn) \ + for ((__sn) = sys_ ## __lname ## _peek_head(__l); (__sn) != NULL; \ + (__sn) = sys_ ## __lname ## _peek_next(__sn)) + +#define Z_GENLIST_ITERATE_FROM_NODE(__lname, __l, __sn) \ + for ((__sn) = (__sn) ? sys_ ## __lname ## _peek_next_no_check(__sn) \ + : sys_ ## __lname ## _peek_head(__l); \ + (__sn) != NULL; \ + (__sn) = sys_ ## __lname ## _peek_next(__sn)) + +#define Z_GENLIST_FOR_EACH_NODE_SAFE(__lname, __l, __sn, __sns) \ + for ((__sn) = sys_ ## __lname ## _peek_head(__l), \ + (__sns) = sys_ ## __lname ## _peek_next(__sn); \ + (__sn) != NULL ; (__sn) = (__sns), \ + (__sns) = sys_ ## __lname ## _peek_next(__sn)) + +#define Z_GENLIST_CONTAINER(__ln, __cn, __n) \ + ((__ln) ? CONTAINER_OF((__ln), __typeof__(*(__cn)), __n) : NULL) + +#define Z_GENLIST_PEEK_HEAD_CONTAINER(__lname, __l, __cn, __n) \ + Z_GENLIST_CONTAINER(sys_ ## __lname ## _peek_head(__l), __cn, __n) + +#define Z_GENLIST_PEEK_TAIL_CONTAINER(__lname, __l, __cn, __n) \ + Z_GENLIST_CONTAINER(sys_ ## __lname ## _peek_tail(__l), __cn, __n) + +#define Z_GENLIST_PEEK_NEXT_CONTAINER(__lname, __cn, __n) \ + ((__cn) ? Z_GENLIST_CONTAINER( \ + sys_ ## __lname ## _peek_next(&((__cn)->__n)), \ + __cn, __n) : NULL) + +#define Z_GENLIST_FOR_EACH_CONTAINER(__lname, __l, __cn, __n) \ + for ((__cn) = Z_GENLIST_PEEK_HEAD_CONTAINER(__lname, __l, __cn, \ + __n); \ + (__cn) != NULL; \ + (__cn) = Z_GENLIST_PEEK_NEXT_CONTAINER(__lname, __cn, __n)) + +#define Z_GENLIST_FOR_EACH_CONTAINER_SAFE(__lname, __l, __cn, __cns, __n) \ + for ((__cn) = Z_GENLIST_PEEK_HEAD_CONTAINER(__lname, __l, __cn, __n), \ + (__cns) = Z_GENLIST_PEEK_NEXT_CONTAINER(__lname, __cn, __n); \ + (__cn) != NULL; (__cn) = (__cns), \ + (__cns) = Z_GENLIST_PEEK_NEXT_CONTAINER(__lname, __cn, __n)) + +#define Z_GENLIST_IS_EMPTY(__lname) \ + static inline bool \ + sys_ ## __lname ## _is_empty(const sys_ ## __lname ## _t *list) \ + { \ + return (sys_ ## __lname ## _peek_head(list) == NULL); \ + } + +#define Z_GENLIST_PEEK_NEXT_NO_CHECK(__lname, __nname) \ + static inline sys_ ## __nname ## _t * \ + sys_ ## __lname ## _peek_next_no_check(const sys_ ## __nname ## _t *node) \ + { \ + return z_ ## __nname ## _next_peek(node); \ + } + +#define Z_GENLIST_PEEK_NEXT(__lname, __nname) \ + static inline sys_ ## __nname ## _t * \ + sys_ ## __lname ## _peek_next(const sys_ ## __nname ## _t *node) \ + { \ + return (node != NULL) ? \ + sys_ ## __lname ## _peek_next_no_check(node) : \ + NULL; \ + } + +#define Z_GENLIST_PREPEND(__lname, __nname) \ + static inline void \ + sys_ ## __lname ## _prepend(sys_ ## __lname ## _t *list, \ + sys_ ## __nname ## _t *node) \ + { \ + z_ ## __nname ## _next_set(node, \ + sys_ ## __lname ## _peek_head(list)); \ + z_ ## __lname ## _head_set(list, node); \ + \ + if (sys_ ## __lname ## _peek_tail(list) == NULL) { \ + z_ ## __lname ## _tail_set(list, \ + sys_ ## __lname ## _peek_head(list)); \ + } \ + } + +#define Z_GENLIST_APPEND(__lname, __nname) \ + static inline void \ + sys_ ## __lname ## _append(sys_ ## __lname ## _t *list, \ + sys_ ## __nname ## _t *node) \ + { \ + z_ ## __nname ## _next_set(node, NULL); \ + \ + if (sys_ ## __lname ## _peek_tail(list) == NULL) { \ + z_ ## __lname ## _tail_set(list, node); \ + z_ ## __lname ## _head_set(list, node); \ + } else { \ + z_ ## __nname ## _next_set( \ + sys_ ## __lname ## _peek_tail(list), \ + node); \ + z_ ## __lname ## _tail_set(list, node); \ + } \ + } + +#define Z_GENLIST_APPEND_LIST(__lname, __nname) \ + static inline void \ + sys_ ## __lname ## _append_list(sys_ ## __lname ## _t *list, \ + void *head, void *tail) \ +{ \ + if (head != NULL && tail != NULL) { \ + if (sys_ ## __lname ## _peek_tail(list) == NULL) { \ + z_ ## __lname ## _head_set(list, \ + (sys_ ## __nname ## _t *)head); \ + } else { \ + z_ ## __nname ## _next_set( \ + sys_ ## __lname ## _peek_tail(list), \ + (sys_ ## __nname ## _t *)head); \ + } \ + z_ ## __lname ## _tail_set(list, \ + (sys_ ## __nname ## _t *)tail); \ + } \ +} + +#define Z_GENLIST_MERGE_LIST(__lname, __nname) \ + static inline void \ + sys_ ## __lname ## _merge_ ## __lname ( \ + sys_ ## __lname ## _t *list, \ + sys_ ## __lname ## _t *list_to_append) \ + { \ + sys_ ## __nname ## _t *head, *tail; \ + head = sys_ ## __lname ## _peek_head(list_to_append); \ + tail = sys_ ## __lname ## _peek_tail(list_to_append); \ + sys_ ## __lname ## _append_list(list, head, tail); \ + sys_ ## __lname ## _init(list_to_append); \ + } + +#define Z_GENLIST_INSERT(__lname, __nname) \ + static inline void \ + sys_ ## __lname ## _insert(sys_ ## __lname ## _t *list, \ + sys_ ## __nname ## _t *prev, \ + sys_ ## __nname ## _t *node) \ + { \ + if (prev == NULL) { \ + sys_ ## __lname ## _prepend(list, node); \ + } else if (z_ ## __nname ## _next_peek(prev) == NULL) { \ + sys_ ## __lname ## _append(list, node); \ + } else { \ + z_ ## __nname ## _next_set(node, \ + z_ ## __nname ## _next_peek(prev)); \ + z_ ## __nname ## _next_set(prev, node); \ + } \ + } + +#define Z_GENLIST_GET_NOT_EMPTY(__lname, __nname) \ + static inline sys_ ## __nname ## _t * \ + sys_ ## __lname ## _get_not_empty(sys_ ## __lname ## _t *list) \ + { \ + sys_ ## __nname ## _t *node = \ + sys_ ## __lname ## _peek_head(list); \ + \ + z_ ## __lname ## _head_set(list, \ + z_ ## __nname ## _next_peek(node)); \ + if (sys_ ## __lname ## _peek_tail(list) == node) { \ + z_ ## __lname ## _tail_set(list, \ + sys_ ## __lname ## _peek_head(list)); \ + } \ + \ + return node; \ + } + +#define Z_GENLIST_GET(__lname, __nname) \ + static inline sys_ ## __nname ## _t * \ + sys_ ## __lname ## _get(sys_ ## __lname ## _t *list) \ + { \ + return sys_ ## __lname ## _is_empty(list) ? NULL : \ + sys_ ## __lname ## _get_not_empty(list); \ + } + +#define Z_GENLIST_REMOVE(__lname, __nname) \ + static inline void \ + sys_ ## __lname ## _remove(sys_ ## __lname ## _t *list, \ + sys_ ## __nname ## _t *prev_node, \ + sys_ ## __nname ## _t *node) \ + { \ + if (prev_node == NULL) { \ + z_ ## __lname ## _head_set(list, \ + z_ ## __nname ## _next_peek(node)); \ + \ + /* Was node also the tail? */ \ + if (sys_ ## __lname ## _peek_tail(list) == node) { \ + z_ ## __lname ## _tail_set(list, \ + sys_ ## __lname ## _peek_head(list)); \ + } \ + } else { \ + z_ ## __nname ## _next_set(prev_node, \ + z_ ## __nname ## _next_peek(node)); \ + \ + /* Was node the tail? */ \ + if (sys_ ## __lname ## _peek_tail(list) == node) { \ + z_ ## __lname ## _tail_set(list, \ + prev_node); \ + } \ + } \ + \ + z_ ## __nname ## _next_set(node, NULL); \ + } + +#define Z_GENLIST_FIND_AND_REMOVE(__lname, __nname) \ + static inline bool \ + sys_ ## __lname ## _find_and_remove(sys_ ## __lname ## _t *list, \ + sys_ ## __nname ## _t *node) \ + { \ + sys_ ## __nname ## _t *prev = NULL; \ + sys_ ## __nname ## _t *test; \ + \ + Z_GENLIST_FOR_EACH_NODE(__lname, list, test) { \ + if (test == node) { \ + sys_ ## __lname ## _remove(list, prev, \ + node); \ + return true; \ + } \ + \ + prev = test; \ + } \ + \ + return false; \ + } + +#define Z_GENLIST_FIND(__lname, __nname) \ + static inline bool sys_##__lname##_find( \ + const sys_##__lname##_t *list, const sys_##__nname##_t *node, \ + sys_##__nname##_t **prev) \ + { \ + sys_##__nname##_t *current = NULL; \ + sys_##__nname##_t *previous = NULL; \ + \ + Z_GENLIST_FOR_EACH_NODE(__lname, list, current) { \ + if (current == node) { \ + if (prev != NULL) { \ + *prev = previous; \ + } \ + return true; \ + } \ + \ + previous = current; \ + } \ + \ + if (prev != NULL) { \ + *prev = previous; \ + } \ + \ + return false; \ + } + +#define Z_GENLIST_LEN(__lname, __nname) \ + static inline size_t sys_##__lname##_len(const sys_##__lname##_t * list) \ + { \ + size_t len = 0; \ + static sys_##__nname##_t * node; \ + Z_GENLIST_FOR_EACH_NODE(__lname, list, node) { \ + len++; \ + } \ + return len; \ + } + +#endif /* ZEPHYR_INCLUDE_SYS_LIST_GEN_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/sys/slist.h b/components/bt/esp_ble_audio/include/zephyr/sys/slist.h new file mode 100644 index 0000000000..d27b29a079 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/sys/slist.h @@ -0,0 +1,452 @@ +/* + * SPDX-FileCopyrightText: 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @defgroup single-linked-list_apis Single-linked list + * @ingroup datastructure_apis + * + * @brief Single-linked list implementation. + * + * Single-linked list implementation using inline macros/functions. + * This API is not thread safe, and thus if a list is used across threads, + * calls to functions must be protected with synchronization primitives. + * @{ + */ + +#ifndef ZEPHYR_INCLUDE_SYS_SLIST_H_ +#define ZEPHYR_INCLUDE_SYS_SLIST_H_ + +#include +#include +#include "list_gen.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond INTERNAL_HIDDEN */ +struct _snode { + struct _snode *next; +}; +/** @endcond */ + +/** Single-linked list node structure. */ +typedef struct _snode sys_snode_t; + +/** @cond INTERNAL_HIDDEN */ +struct _slist { + sys_snode_t *head; + sys_snode_t *tail; +}; +/** @endcond */ + +/** Single-linked list structure. */ +typedef struct _slist sys_slist_t; + +/** + * @brief Provide the primitive to iterate on a list + * Note: the loop is unsafe and thus __sn should not be removed + * + * User _MUST_ add the loop statement curly braces enclosing its own code: + * + * SYS_SLIST_FOR_EACH_NODE(l, n) { + * + * } + * + * This and other SYS_SLIST_*() macros are not thread safe. + * + * @param __sl A pointer on a sys_slist_t to iterate on + * @param __sn A sys_snode_t pointer to peek each node of the list + */ +#define SYS_SLIST_FOR_EACH_NODE(__sl, __sn) \ + Z_GENLIST_FOR_EACH_NODE(slist, __sl, __sn) + +/** + * @brief Provide the primitive to iterate on a list, from a node in the list + * Note: the loop is unsafe and thus __sn should not be removed + * + * User _MUST_ add the loop statement curly braces enclosing its own code: + * + * SYS_SLIST_ITERATE_FROM_NODE(l, n) { + * + * } + * + * Like SYS_SLIST_FOR_EACH_NODE(), but __dn already contains a node in the list + * where to start searching for the next entry from. If NULL, it starts from + * the head. + * + * This and other SYS_SLIST_*() macros are not thread safe. + * + * @param __sl A pointer on a sys_slist_t to iterate on + * @param __sn A sys_snode_t pointer to peek each node of the list + * it contains the starting node, or NULL to start from the head + */ +#define SYS_SLIST_ITERATE_FROM_NODE(__sl, __sn) \ + Z_GENLIST_ITERATE_FROM_NODE(slist, __sl, __sn) + +/** + * @brief Provide the primitive to safely iterate on a list + * Note: __sn can be removed, it will not break the loop. + * + * User _MUST_ add the loop statement curly braces enclosing its own code: + * + * SYS_SLIST_FOR_EACH_NODE_SAFE(l, n, s) { + * + * } + * + * This and other SYS_SLIST_*() macros are not thread safe. + * + * @param __sl A pointer on a sys_slist_t to iterate on + * @param __sn A sys_snode_t pointer to peek each node of the list + * @param __sns A sys_snode_t pointer for the loop to run safely + */ +#define SYS_SLIST_FOR_EACH_NODE_SAFE(__sl, __sn, __sns) \ + Z_GENLIST_FOR_EACH_NODE_SAFE(slist, __sl, __sn, __sns) + +/** + * @brief Provide the primitive to resolve the container of a list node + * Note: it is safe to use with NULL pointer nodes + * + * @param __ln A pointer on a sys_node_t to get its container + * @param __cn Container struct type pointer + * @param __n The field name of sys_node_t within the container struct + */ +#define SYS_SLIST_CONTAINER(__ln, __cn, __n) \ + Z_GENLIST_CONTAINER(__ln, __cn, __n) + +/** + * @brief Provide the primitive to peek container of the list head + * + * @param __sl A pointer on a sys_slist_t to peek + * @param __cn Container struct type pointer + * @param __n The field name of sys_node_t within the container struct + */ +#define SYS_SLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n) \ + Z_GENLIST_PEEK_HEAD_CONTAINER(slist, __sl, __cn, __n) + +/** + * @brief Provide the primitive to peek container of the list tail + * + * @param __sl A pointer on a sys_slist_t to peek + * @param __cn Container struct type pointer + * @param __n The field name of sys_node_t within the container struct + */ +#define SYS_SLIST_PEEK_TAIL_CONTAINER(__sl, __cn, __n) \ + Z_GENLIST_PEEK_TAIL_CONTAINER(slist, __sl, __cn, __n) + +/** + * @brief Provide the primitive to peek the next container + * + * @param __cn Container struct type pointer + * @param __n The field name of sys_node_t within the container struct + */ +#define SYS_SLIST_PEEK_NEXT_CONTAINER(__cn, __n) \ + Z_GENLIST_PEEK_NEXT_CONTAINER(slist, __cn, __n) + +/** + * @brief Provide the primitive to iterate on a list under a container + * Note: the loop is unsafe and thus __cn should not be detached + * + * User _MUST_ add the loop statement curly braces enclosing its own code: + * + * SYS_SLIST_FOR_EACH_CONTAINER(l, c, n) { + * + * } + * + * @param __sl A pointer on a sys_slist_t to iterate on + * @param __cn A pointer to peek each entry of the list + * @param __n The field name of sys_node_t within the container struct + */ +#define SYS_SLIST_FOR_EACH_CONTAINER(__sl, __cn, __n) \ + Z_GENLIST_FOR_EACH_CONTAINER(slist, __sl, __cn, __n) + +/** + * @brief Provide the primitive to safely iterate on a list under a container + * Note: __cn can be detached, it will not break the loop. + * + * User _MUST_ add the loop statement curly braces enclosing its own code: + * + * SYS_SLIST_FOR_EACH_NODE_SAFE(l, c, cn, n) { + * + * } + * + * @param __sl A pointer on a sys_slist_t to iterate on + * @param __cn A pointer to peek each entry of the list + * @param __cns A pointer for the loop to run safely + * @param __n The field name of sys_node_t within the container struct + */ +#define SYS_SLIST_FOR_EACH_CONTAINER_SAFE(__sl, __cn, __cns, __n) \ + Z_GENLIST_FOR_EACH_CONTAINER_SAFE(slist, __sl, __cn, __cns, __n) + +/* + * Required function definitions for the list_gen.h interface + * + * These are the only functions that do not treat the list/node pointers + * as completely opaque types. + */ + +/** + * @brief Initialize a list + * + * @param list A pointer on the list to initialize + */ +static inline void sys_slist_init(sys_slist_t *list) +{ + list->head = NULL; + list->tail = NULL; +} + +/** + * @brief Statically initialize a single-linked list + * @param ptr_to_list A pointer on the list to initialize + */ +#define SYS_SLIST_STATIC_INIT(ptr_to_list) {NULL, NULL} + +static inline sys_snode_t *z_snode_next_peek(const sys_snode_t *node) +{ + return node->next; +} + +static inline void z_snode_next_set(sys_snode_t *parent, sys_snode_t *child) +{ + parent->next = child; +} + +static inline void z_slist_head_set(sys_slist_t *list, sys_snode_t *node) +{ + list->head = node; +} + +static inline void z_slist_tail_set(sys_slist_t *list, sys_snode_t *node) +{ + list->tail = node; +} + +/** + * @brief Peek the first node from the list + * + * @param list A point on the list to peek the first node from + * + * @return A pointer on the first node of the list (or NULL if none) + */ +static inline sys_snode_t *sys_slist_peek_head(const sys_slist_t *list) +{ + return list->head; +} + +/** + * @brief Peek the last node from the list + * + * @param list A point on the list to peek the last node from + * + * @return A pointer on the last node of the list (or NULL if none) + */ +static inline sys_snode_t *sys_slist_peek_tail(const sys_slist_t *list) +{ + return list->tail; +} + +/* + * Derived, generated APIs + */ + +/** + * @brief Test if the given list is empty + * + * @param list A pointer on the list to test + * + * @return a boolean, true if it's empty, false otherwise + */ +static inline bool sys_slist_is_empty(const sys_slist_t *list); + +Z_GENLIST_IS_EMPTY(slist) + +/** + * @brief Peek the next node from current node, node is not NULL + * + * Faster then sys_slist_peek_next() if node is known not to be NULL. + * + * @param node A pointer on the node where to peek the next node + * + * @return a pointer on the next node (or NULL if none) + */ +static inline sys_snode_t *sys_slist_peek_next_no_check(const sys_snode_t *node); + +Z_GENLIST_PEEK_NEXT_NO_CHECK(slist, snode) + +/** + * @brief Peek the next node from current node + * + * @param node A pointer on the node where to peek the next node + * + * @return a pointer on the next node (or NULL if none) + */ +static inline sys_snode_t *sys_slist_peek_next(const sys_snode_t *node); + +Z_GENLIST_PEEK_NEXT(slist, snode) + +/** + * @brief Prepend a node to the given list + * + * This and other sys_slist_*() functions are not thread safe. + * + * @param list A pointer on the list to affect + * @param node A pointer on the node to prepend + */ +static inline void sys_slist_prepend(sys_slist_t *list, + sys_snode_t *node); + +Z_GENLIST_PREPEND(slist, snode) + +/** + * @brief Append a node to the given list + * + * This and other sys_slist_*() functions are not thread safe. + * + * @param list A pointer on the list to affect + * @param node A pointer on the node to append + */ +static inline void sys_slist_append(sys_slist_t *list, + sys_snode_t *node); + +Z_GENLIST_APPEND(slist, snode) + +/** + * @brief Append a list to the given list + * + * Append a singly-linked, NULL-terminated list consisting of nodes containing + * the pointer to the next node as the first element of a node, to @a list. + * This and other sys_slist_*() functions are not thread safe. + * + * @param list A pointer on the list to affect + * @param head A pointer to the first element of the list to append + * @param tail A pointer to the last element of the list to append + */ +static inline void sys_slist_append_list(sys_slist_t *list, + void *head, void *tail); + +Z_GENLIST_APPEND_LIST(slist, snode) + +/** + * @brief merge two slists, appending the second one to the first + * + * When the operation is completed, the appending list is empty. + * This and other sys_slist_*() functions are not thread safe. + * + * @param list A pointer on the list to affect + * @param list_to_append A pointer to the list to append. + */ +static inline void sys_slist_merge_slist(sys_slist_t *list, + sys_slist_t *list_to_append); + +Z_GENLIST_MERGE_LIST(slist, snode) + +/** + * @brief Insert a node to the given list + * + * This and other sys_slist_*() functions are not thread safe. + * + * @param list A pointer on the list to affect + * @param prev A pointer on the previous node + * @param node A pointer on the node to insert + */ +static inline void sys_slist_insert(sys_slist_t *list, + sys_snode_t *prev, + sys_snode_t *node); + +Z_GENLIST_INSERT(slist, snode) + +/** + * @brief Fetch and remove the first node of the given list + * + * List must be known to be non-empty. + * This and other sys_slist_*() functions are not thread safe. + * + * @param list A pointer on the list to affect + * + * @return A pointer to the first node of the list + */ +static inline sys_snode_t *sys_slist_get_not_empty(sys_slist_t *list); + +Z_GENLIST_GET_NOT_EMPTY(slist, snode) + +/** + * @brief Fetch and remove the first node of the given list + * + * This and other sys_slist_*() functions are not thread safe. + * + * @param list A pointer on the list to affect + * + * @return A pointer to the first node of the list (or NULL if empty) + */ +static inline sys_snode_t *sys_slist_get(sys_slist_t *list); + +Z_GENLIST_GET(slist, snode) + +/** + * @brief Remove a node + * + * This and other sys_slist_*() functions are not thread safe. + * + * @param list A pointer on the list to affect + * @param prev_node A pointer on the previous node + * (can be NULL, which means the node is the list's head) + * @param node A pointer on the node to remove + */ +static inline void sys_slist_remove(sys_slist_t *list, + sys_snode_t *prev_node, + sys_snode_t *node); + +Z_GENLIST_REMOVE(slist, snode) + +/** + * @brief Find and remove a node from a list + * + * This and other sys_slist_*() functions are not thread safe. + * + * @param list A pointer on the list to affect + * @param node A pointer on the node to remove from the list + * + * @return true if node was removed + */ +static inline bool sys_slist_find_and_remove(sys_slist_t *list, + sys_snode_t *node); + +/** + * @brief Find if a node is already linked in a singly linked list + * + * This and other sys_slist_*() functions are not thread safe. + * + * @param list A pointer to the list to check + * @param node A pointer to the node to search in the list + * @param[out] prev A pointer to the previous node + * + * @return true if node was found in the list, false otherwise + */ +static inline bool sys_slist_find(const sys_slist_t *list, const sys_snode_t *node, + sys_snode_t **prev); +Z_GENLIST_FIND(slist, snode) + +/** + * @brief Compute the size of the given list in O(n) time + * + * @param list A pointer on the list + * + * @return an integer equal to the size of the list, or 0 if empty + */ +static inline size_t sys_slist_len(const sys_slist_t *list); + +Z_GENLIST_LEN(slist, snode) + +/** @} */ +Z_GENLIST_FIND_AND_REMOVE(slist, snode) + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_SYS_SLIST_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/sys/util.h b/components/bt/esp_ble_audio/include/zephyr/sys/util.h new file mode 100644 index 0000000000..0e7a8a9d0e --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/sys/util.h @@ -0,0 +1,1105 @@ +/* + * SPDX-FileCopyrightText: 2011-2014 Wind River Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Misc utilities + * + * Misc utilities usable by the kernel and application code. + */ + +#ifndef ZEPHYR_INCLUDE_SYS_UTIL_H_ +#define ZEPHYR_INCLUDE_SYS_UTIL_H_ + +#include +#include +#include + +/* needs to be outside _ASMLANGUAGE so 'true' and 'false' can turn + * into '1' and '0' for asm or linker scripts + */ +#include + +#ifndef _ASMLANGUAGE + +#include +#include +#include +#include +#include + +/** @brief Number of bits that make up a type */ +#define NUM_BITS(t) (sizeof(t) * BITS_PER_BYTE) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup sys-util Utility Functions + * @since 2.4 + * @version 0.1.0 + * @ingroup utilities + * @{ + */ + +/** @brief Cast @p x, a pointer, to an unsigned integer. */ +#define POINTER_TO_UINT(x) ((uintptr_t) (x)) +/** @brief Cast @p x, an unsigned integer, to a void*. */ +#define UINT_TO_POINTER(x) ((void *) (uintptr_t) (x)) +/** @brief Cast @p x, a pointer, to a signed integer. */ +#define POINTER_TO_INT(x) ((intptr_t) (x)) +/** @brief Cast @p x, a signed integer, to a void*. */ +#define INT_TO_POINTER(x) ((void *) (intptr_t) (x)) + +#if !(defined(__CHAR_BIT__) && defined(__SIZEOF_LONG__) && defined(__SIZEOF_LONG_LONG__)) +# error Missing required predefined macros for BITS_PER_LONG calculation +#endif + +/** Number of bits in a byte. */ +#define BITS_PER_BYTE (__CHAR_BIT__) + +/** Number of bits in a nibble. */ +#define BITS_PER_NIBBLE (__CHAR_BIT__ / 2) + +/** Number of nibbles in a byte. */ +#define NIBBLES_PER_BYTE (BITS_PER_BYTE / BITS_PER_NIBBLE) + +/** Number of bits in a long int. */ +#define BITS_PER_LONG (__CHAR_BIT__ * __SIZEOF_LONG__) + +/** Number of bits in a long long int. */ +#define BITS_PER_LONG_LONG (__CHAR_BIT__ * __SIZEOF_LONG_LONG__) + +/** + * @brief Create a contiguous bitmask starting at bit position @p l + * and ending at position @p h. + */ +#define GENMASK(h, l) (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) + +/** + * @brief Create a contiguous 64-bit bitmask starting at bit position @p l + * and ending at position @p h. + */ +#define GENMASK64(h, l) (((~0ULL) - (1ULL << (l)) + 1) & (~0ULL >> (BITS_PER_LONG_LONG - 1 - (h)))) + +/** @brief 0 if @p cond is true-ish; causes a compile error otherwise. */ +#define ZERO_OR_COMPILE_ERROR(cond) ((int)sizeof(char[1 - (2 * !(cond))]) - 1) + +#if defined(__cplusplus) + +/* The built-in function used below for type checking in C is not + * supported by GNU C++. + */ +#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) + +#else /* __cplusplus */ + +/** + * @brief Zero if @p array has an array type, a compile error otherwise + * + * This macro is available only from C, not C++. + */ +#define IS_ARRAY(array) \ + ZERO_OR_COMPILE_ERROR( \ + !__builtin_types_compatible_p(__typeof__(array), __typeof__(&(array)[0]))) + +#ifndef ARRAY_SIZE +/** + * @brief Number of elements in the given @p array + * + * In C++, due to language limitations, this will accept as @p array + * any type that implements operator[]. The results may not be + * particularly meaningful in this case. + * + * In C, passing a pointer as @p array causes a compile error. + */ +#define ARRAY_SIZE(array) ((size_t)(IS_ARRAY(array) + (sizeof(array) / sizeof((array)[0])))) +#endif + +#endif /* __cplusplus */ + +/** + * @brief Declare a flexible array member. + * + * This macro declares a flexible array member in a struct. The member + * is named @p name and has type @p type. + * + * Since C99, flexible arrays are part of the C standard, but for historical + * reasons many places still use an older GNU extension that is declare + * zero length arrays. + * + * Although zero length arrays are flexible arrays, we can't blindly + * replace [0] with [] because of some syntax limitations. This macro + * workaround these limitations. + * + * It is specially useful for cases where flexible arrays are + * used in unions or are not the last element in the struct. + */ +#define FLEXIBLE_ARRAY_DECLARE(type, name) \ + struct { \ + struct { \ + } __unused_##name; \ + type name[]; \ + } + +/** + * @brief Whether @p ptr is an element of @p array + * + * This macro can be seen as a slightly stricter version of @ref PART_OF_ARRAY + * in that it also ensures that @p ptr is aligned to an array-element boundary + * of @p array. + * + * In C, passing a pointer as @p array causes a compile error. + * + * @param array the array in question + * @param ptr the pointer to check + * + * @return 1 if @p ptr is part of @p array, 0 otherwise + */ +#define IS_ARRAY_ELEMENT(array, ptr) \ + ((ptr) && POINTER_TO_UINT(array) <= POINTER_TO_UINT(ptr) && \ + POINTER_TO_UINT(ptr) < POINTER_TO_UINT(&(array)[ARRAY_SIZE(array)]) && \ + (POINTER_TO_UINT(ptr) - POINTER_TO_UINT(array)) % sizeof((array)[0]) == 0) + +/** + * @brief Index of @p ptr within @p array + * + * With `CONFIG_ASSERT=y`, this macro will trigger a runtime assertion + * when @p ptr does not fall into the range of @p array or when @p ptr + * is not aligned to an array-element boundary of @p array. + * + * In C, passing a pointer as @p array causes a compile error. + * + * @param array the array in question + * @param ptr pointer to an element of @p array + * + * @return the array index of @p ptr within @p array, on success + */ +#define ARRAY_INDEX(array, ptr) \ + ({ \ + __ASSERT_NO_MSG(IS_ARRAY_ELEMENT(array, ptr)); \ + (__typeof__((array)[0]) *)(ptr) - (array); \ + }) + +/** + * @brief Check if a pointer @p ptr lies within @p array. + * + * In C but not C++, this causes a compile error if @p array is not an array + * (e.g. if @p ptr and @p array are mixed up). + * + * @param array an array + * @param ptr a pointer + * @return 1 if @p ptr is part of @p array, 0 otherwise + */ +#define PART_OF_ARRAY(array, ptr) \ + ((ptr) && POINTER_TO_UINT(array) <= POINTER_TO_UINT(ptr) && \ + POINTER_TO_UINT(ptr) < POINTER_TO_UINT(&(array)[ARRAY_SIZE(array)])) + +/** + * @brief Array-index of @p ptr within @p array, rounded down + * + * This macro behaves much like @ref ARRAY_INDEX with the notable + * difference that it accepts any @p ptr in the range of @p array rather than + * exclusively a @p ptr aligned to an array-element boundary of @p array. + * + * With `CONFIG_ASSERT=y`, this macro will trigger a runtime assertion + * when @p ptr does not fall into the range of @p array. + * + * In C, passing a pointer as @p array causes a compile error. + * + * @param array the array in question + * @param ptr pointer to an element of @p array + * + * @return the array index of @p ptr within @p array, on success + */ +#define ARRAY_INDEX_FLOOR(array, ptr) \ + ({ \ + __ASSERT_NO_MSG(PART_OF_ARRAY(array, ptr)); \ + (POINTER_TO_UINT(ptr) - POINTER_TO_UINT(array)) / sizeof((array)[0]); \ + }) + +/** + * @brief Iterate over members of an array using an index variable + * + * @param array the array in question + * @param idx name of array index variable + */ +#define ARRAY_FOR_EACH(array, idx) for (size_t idx = 0; (idx) < ARRAY_SIZE(array); ++(idx)) + +/** + * @brief Iterate over members of an array using a pointer + * + * @param array the array in question + * @param ptr pointer to an element of @p array + */ +#define ARRAY_FOR_EACH_PTR(array, ptr) \ + for (__typeof__(*(array)) *ptr = (array); (size_t)((ptr) - (array)) < ARRAY_SIZE(array); \ + ++(ptr)) + +/** + * @brief Validate if two entities have a compatible type + * + * @param a the first entity to be compared + * @param b the second entity to be compared + * @return 1 if the two elements are compatible, 0 if they are not + */ +#define SAME_TYPE(a, b) __builtin_types_compatible_p(__typeof__(a), __typeof__(b)) + +/** + * @brief Validate CONTAINER_OF parameters, only applies to C mode. + */ +#ifndef __cplusplus +#define CONTAINER_OF_VALIDATE(ptr, type, field) \ + BUILD_ASSERT(SAME_TYPE(*(ptr), ((type *)0)->field) || SAME_TYPE(*(ptr), void), \ + "pointer type mismatch in CONTAINER_OF"); +#else +#define CONTAINER_OF_VALIDATE(ptr, type, field) +#endif + +/** + * @brief Get a pointer to a structure containing the element + * + * Example: + * + * struct foo { + * int bar; + * }; + * + * struct foo my_foo; + * int *ptr = &my_foo.bar; + * + * struct foo *container = CONTAINER_OF(ptr, struct foo, bar); + * + * Above, @p container points at @p my_foo. + * + * @param ptr pointer to a structure element + * @param type name of the type that @p ptr is an element of + * @param field the name of the field within the struct @p ptr points to + * @return a pointer to the structure that contains @p ptr + */ +#define CONTAINER_OF(ptr, type, field) \ + ({ \ + CONTAINER_OF_VALIDATE(ptr, type, field) \ + ((type *)(((char *)(ptr)) - offsetof(type, field))); \ + }) + +/** + * @brief Report the size of a struct field in bytes. + * + * @param type The structure containing the field of interest. + * @param member The field to return the size of. + * + * @return The field size. + */ +#define SIZEOF_FIELD(type, member) sizeof((((type *)0)->member)) + +/** + * @brief Concatenate input arguments + * + * Concatenate provided tokens into a combined token during the preprocessor pass. + * This can be used to, for ex., build an identifier out of multiple parts, + * where one of those parts may be, for ex, a number, another macro, or a macro argument. + * + * @param ... Tokens to concatencate + * + * @return Concatenated token. + */ +#define CONCAT(...) UTIL_CAT(_CONCAT_, NUM_VA_ARGS_LESS_1(__VA_ARGS__))(__VA_ARGS__) + +/** + * @brief Check if @p ptr is aligned to @p align alignment + */ +#define IS_ALIGNED(ptr, align) (((uintptr_t)(ptr)) % (align) == 0) + +/** + * @brief Value of @p x rounded up to the next multiple of @p align. + */ +#define ROUND_UP(x, align) \ + ((((unsigned long)(x) + ((unsigned long)(align) - 1)) / (unsigned long)(align)) * \ + (unsigned long)(align)) + +/** + * @brief Value of @p x rounded down to the previous multiple of @p align. + */ +#define ROUND_DOWN(x, align) \ + (((unsigned long)(x) / (unsigned long)(align)) * (unsigned long)(align)) + +/** @brief Value of @p x rounded up to the next word boundary. */ +#define WB_UP(x) ROUND_UP(x, sizeof(void *)) + +/** @brief Value of @p x rounded down to the previous word boundary. */ +#define WB_DN(x) ROUND_DOWN(x, sizeof(void *)) + +/** + * @brief Divide and round up. + * + * Example: + * @code{.c} + * DIV_ROUND_UP(1, 2); // 1 + * DIV_ROUND_UP(3, 2); // 2 + * @endcode + * + * @param n Numerator. + * @param d Denominator. + * + * @return The result of @p n / @p d, rounded up. + */ +#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) + +/** + * @brief Divide and round to the nearest integer. + * + * Example: + * @code{.c} + * DIV_ROUND_CLOSEST(5, 2); // 3 + * DIV_ROUND_CLOSEST(5, -2); // -3 + * DIV_ROUND_CLOSEST(5, 3); // 2 + * @endcode + * + * @param n Numerator. + * @param d Denominator. + * + * @return The result of @p n / @p d, rounded to the nearest integer. + */ +#define DIV_ROUND_CLOSEST(n, d) \ + (((((__typeof__(n))-1) < 0) && (((__typeof__(d))-1) < 0) && ((n) < 0) ^ ((d) < 0)) \ + ? ((n) - ((d) / 2)) / (d) \ + : ((n) + ((d) / 2)) / (d)) + +/** + * @cond INTERNAL_HIDDEN + */ +#define Z_INTERNAL_MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define Z_INTERNAL_MIN(a, b) (((a) < (b)) ? (a) : (b)) + +#define _minmax_unique(op, a, b, ua, ub) ({ \ + __typeof__(a) ua = (a); \ + __typeof__(b) ub = (b); \ + op(ua, ub); \ + }) + +#define _minmax_cnt(op, a, b, cnt) \ + _minmax_unique(op, a, b, UTIL_CAT(_value_a_, cnt), UTIL_CAT(_value_b_, cnt)) + +#define _minmax3_unique(op, a, b, c, ua, ub, uc) ({ \ + __typeof__(a) ua = (a); \ + __typeof__(b) ub = (b); \ + __typeof__(c) uc = (c); \ + op(ua, op(ub, uc)); \ + }) + +#define _minmax3_cnt(op, a, b, c, cnt) \ + _minmax3_unique(op, a, b, c, \ + UTIL_CAT(_value_a_, cnt), \ + UTIL_CAT(_value_b_, cnt), \ + UTIL_CAT(_value_c_, cnt)) +/** + * @endcond + */ + +#ifndef MAX +/** + * @brief Obtain the maximum of two values. + * + * @note Arguments are evaluated twice. Use @ref max for a single evaluation + * version. + * + * @param a First value. + * @param b Second value. + * + * @returns Maximum value of @p a and @p b. + */ +#define MAX(a, b) Z_INTERNAL_MAX(a, b) +#endif + +#ifndef __cplusplus +/** @brief Return larger value of two provided expressions. + * + * Macro ensures that expressions are evaluated only once. + * + * @note Macro has limited usage compared to the standard macro as it cannot be + * used: + * - to generate constant integer, e.g. __aligned(max(4,5)) + * - static variable, e.g. array like static uint8_t array[max(...)]; + */ +#define max(a, b) _minmax_cnt(Z_INTERNAL_MAX, a, b, __COUNTER__) +#endif + +/** @brief Return larger value of three provided expressions. + * + * Macro ensures that expressions are evaluated only once. See @ref max for + * macro limitations. + */ +#define max3(a, b, c) _minmax3_cnt(Z_INTERNAL_MAX, a, b, c, __COUNTER__) + +#ifndef MIN +/** + * @brief Obtain the minimum of two values. + * + * @note Arguments are evaluated twice. Use @ref min for a single evaluation + * version. + * + * @param a First value. + * @param b Second value. + * + * @returns Minimum value of @p a and @p b. + */ +#define MIN(a, b) Z_INTERNAL_MIN(a, b) +#endif + +#ifndef __cplusplus +/** @brief Return smaller value of two provided expressions. + * + * Macro ensures that expressions are evaluated only once. See @ref max for + * macro limitations. + */ +#define min(a, b) _minmax_cnt(Z_INTERNAL_MIN, a, b, __COUNTER__) +#endif + +/** @brief Return smaller value of three provided expressions. + * + * Macro ensures that expressions are evaluated only once. See @ref max for + * macro limitations. + */ +#define min3(a, b, c) _minmax3_cnt(Z_INTERNAL_MIN, a, b, c, __COUNTER__) + +#ifndef MAX_FROM_LIST +/** + * @brief Returns the maximum of a single value (base case). + * @param a The value. + * @returns The value `a`. + */ +#define Z_MAX_1(a) a + +/** + * @brief Returns the maximum of two values. + * + * @note Arguments are evaluated multiple times. + * + * @param a First value. + * @param b Second value. + * @returns Maximum value of @p a and @p b. + */ +#define Z_MAX_2(a, b) ((a) > (b) ? (a) : (b)) + +/** + * @brief Returns the maximum of three values. + * @note Arguments may be evaluated multiple times. + * @param a First value. + * @param b Second value. + * @param c Third value. + * @returns Maximum value of @p a, @p b, and @p c. + */ +#define Z_MAX_3(a, b, c) Z_MAX_2(a, Z_MAX_2(b, c)) + +/** + * @brief Returns the maximum of four values. + * @note Arguments may be evaluated multiple times. + * @param a First value. + * @param b Second value. + * @param c Third value. + * @param d Fourth value. + * @returns Maximum value of @p a, @p b, @p c, and @p d. + */ +#define Z_MAX_4(a, b, c, d) Z_MAX_2(Z_MAX_2(a, b), Z_MAX_2(c, d)) + +/** + * @brief Returns the maximum of five values. + * @note Arguments may be evaluated multiple times. + */ +#define Z_MAX_5(a, b, c, d, e) Z_MAX_2(Z_MAX_4(a, b, c, d), e) + +/** + * @brief Returns the maximum of six values. + * @note Arguments may be evaluated multiple times. + */ +#define Z_MAX_6(a, b, c, d, e, f) Z_MAX_2(Z_MAX_5(a, b, c, d, e), f) + +/** + * @brief Returns the maximum of seven values. + * @note Arguments may be evaluated multiple times. + */ +#define Z_MAX_7(a, b, c, d, e, f, g) Z_MAX_2(Z_MAX_6(a, b, c, d, e, f), g) + +/** + * @brief Returns the maximum of eight values. + * @note Arguments may be evaluated multiple times. + */ +#define Z_MAX_8(a, b, c, d, e, f, g, h) Z_MAX_2(Z_MAX_7(a, b, c, d, e, f, g), h) + +/** + * @brief Returns the maximum of nine values. + * @note Arguments may be evaluated multiple times. + */ +#define Z_MAX_9(a, b, c, d, e, f, g, h, i) Z_MAX_2(Z_MAX_8(a, b, c, d, e, f, g, h), i) + +/** + * @brief Returns the maximum of ten values. + * @note Arguments may be evaluated multiple times. + */ +#define Z_MAX_10(a, b, c, d, e, f, g, h, i, j) Z_MAX_2(Z_MAX_9(a, b, c, d, e, f, g, h, i), j) + +/** + * @brief Helper macro to select the correct MAX_N macro. + * + * This macro uses the argument-counting trick to pick the correct + * `Z_MAX_N` macro name from the arguments provided to `MAX_FROM_LIST`. + * The 10th argument (or 11th including `NAME`) effectively becomes the + * macro name to use. + * + * @param _1 Positional argument 1. + * @param _2 Positional argument 2. + * @param _3 Positional argument 3. + * @param _4 Positional argument 4. + * @param _5 Positional argument 5. + * @param _6 Positional argument 6. + * @param _7 Positional argument 7. + * @param _8 Positional argument 8. + * @param _9 Positional argument 9. + * @param _10 Positional argument 10. + * @param NAME The macro name to be selected. + * @param ... Additional arguments. + * @returns The selected macro name `NAME`. + */ +#define Z_GET_MAX_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, NAME, ...) NAME + +/** + * @brief Finds the maximum value from a list of 1 to 10 arguments. + * + * Dispatches to the appropriate internal `Z_MAX_N` macro based on the number of + * arguments provided. + * + * Example Usage: + * MAX_FROM_LIST(1, 5, 2) + * MAX_FROM_LIST(10) + * + * @note Arguments may be evaluated multiple times by the underlying + * `Z_MAX_N` macros. Avoid expressions with side effects. + * + * @param ... A list of 1 to 10 values to compare. + * @returns The maximum value among the arguments. + */ +#define MAX_FROM_LIST(...) \ + Z_GET_MAX_MACRO(__VA_ARGS__, Z_MAX_10, Z_MAX_9, Z_MAX_8, Z_MAX_7, Z_MAX_6, Z_MAX_5, \ + Z_MAX_4, Z_MAX_3, Z_MAX_2, Z_MAX_1)(__VA_ARGS__) +#endif + +#ifndef CLAMP +/** + * @brief Clamp a value to a given range. + * + * @note Arguments are evaluated multiple times. Use @ref clamp for a single + * evaluation version. + * + * @param val Value to be clamped. + * @param low Lowest allowed value (inclusive). + * @param high Highest allowed value (inclusive). + * + * @returns Clamped value. + */ +#define CLAMP(val, low, high) (((val) <= (low)) ? (low) : Z_INTERNAL_MIN(val, high)) +#endif + +#ifndef __cplusplus +/** @brief Return a value clamped to a given range. + * + * Macro ensures that expressions are evaluated only once. See @ref max for + * macro limitations. + */ +#define clamp(val, low, high) ({ \ + /* random suffix to avoid naming conflict */ \ + __typeof__(val) _value_val_ = (val); \ + __typeof__(low) _value_low_ = (low); \ + __typeof__(high) _value_high_ = (high); \ + (_value_val_ < _value_low_) ? _value_low_ : \ + (_value_val_ > _value_high_) ? _value_high_ : \ + _value_val_; \ + }) +#endif + +/** + * @brief Checks if a value is within range. + * + * @note @p val is evaluated twice. + * + * @param val Value to be checked. + * @param min Lower bound (inclusive). + * @param max Upper bound (inclusive). + * + * @retval true If value is within range + * @retval false If the value is not within range + */ +#define IN_RANGE(val, min, max) ((val) >= (min) && (val) <= (max)) + +/** + * Find number of contiguous bits which are not set in the bit mask (32 bits). + * + * It is possible to return immediately when requested number of bits is found or + * iterate over whole mask and return the best fit (smallest from available options). + * + * @param[in] mask 32 bit mask. + * @param[in] num_bits Number of bits to find. + * @param[in] total_bits Total number of LSB bits that can be used in the mask. + * @param[in] first_match If true returns when first match is found, else returns the best fit. + * + * @retval -1 Contiguous bits not found. + * @retval non-negative Starting index of the bits group. + */ +int bitmask_find_gap(uint32_t mask, size_t num_bits, size_t total_bits, bool first_match); + +/** + * @brief Is @p x a power of two? + * @param x value to check + * @return true if @p x is a power of two, false otherwise + */ +static inline bool is_power_of_two(unsigned int x) +{ + return IS_POWER_OF_TWO(x); +} + +/** + * @brief Is @p p equal to ``NULL``? + * + * Some macros may need to check their arguments against NULL to support + * multiple use-cases, but NULL checks can generate warnings if such a macro + * is used in contexts where that particular argument can never be NULL. + * + * The warnings can be triggered if: + * a) all macros are expanded (e.g. when using CONFIG_COMPILER_SAVE_TEMPS=y) + * or + * b) tracking of macro expansions are turned off (-ftrack-macro-expansion=0) + * + * The warnings can be circumvented by using this inline function for doing + * the NULL check within the macro. The compiler is still able to optimize the + * NULL check out at a later stage. + * + * @param p Pointer to check + * @return true if @p p is equal to ``NULL``, false otherwise + */ +static inline bool is_null_no_warn(void *p) +{ + return p == NULL; +} + +/** + * @brief Arithmetic shift right + * @param value value to shift + * @param shift number of bits to shift + * @return @p value shifted right by @p shift; opened bit positions are + * filled with the sign bit + */ +static inline int64_t arithmetic_shift_right(int64_t value, uint8_t shift) +{ + int64_t sign_ext; + + if (shift == 0U) { + return value; + } + + /* extract sign bit */ + sign_ext = (value >> 63) & 1; + + /* make all bits of sign_ext be the same as the value's sign bit */ + sign_ext = -sign_ext; + + /* shift value and fill opened bit positions with sign bit */ + return (value >> shift) | (sign_ext << (64 - shift)); +} + +/** + * @brief byte by byte memcpy. + * + * Copy `size` bytes of `src` into `dest`. This is guaranteed to be done byte by byte. + * + * @param dst Pointer to the destination memory. + * @param src Pointer to the source of the data. + * @param size The number of bytes to copy. + */ +static inline void bytecpy(void *dst, const void *src, size_t size) +{ + size_t i; + + for (i = 0; i < size; ++i) { + ((volatile uint8_t *)dst)[i] = ((volatile const uint8_t *)src)[i]; + } +} + +/** + * @brief byte by byte swap. + * + * Swap @a size bytes between memory regions @a a and @a b. This is + * guaranteed to be done byte by byte. + * + * @param a Pointer to the first memory region. + * @param b Pointer to the second memory region. + * @param size The number of bytes to swap. + */ +static inline void byteswp(void *a, void *b, size_t size) +{ + uint8_t t; + uint8_t *aa = (uint8_t *)a; + uint8_t *bb = (uint8_t *)b; + + for (; size > 0; --size) { + t = *aa; + *aa++ = *bb; + *bb++ = t; + } +} + +/** + * @brief Convert a single character into a hexadecimal nibble. + * + * @param c The character to convert + * @param x The address of storage for the converted number. + * + * @return Zero on success or (negative) error code otherwise. + */ +int char2hex(char c, uint8_t *x); + +/** + * @brief Convert a single hexadecimal nibble into a character. + * + * @param c The number to convert + * @param x The address of storage for the converted character. + * + * @return Zero on success or (negative) error code otherwise. + */ +int hex2char(uint8_t x, char *c); + +/** + * @brief Convert a binary array into string representation. + * + * @param buf The binary array to convert + * @param buflen The length of the binary array to convert + * @param hex Address of where to store the string representation. + * @param hexlen Size of the storage area for string representation. + * + * @return The length of the converted string, or 0 if an error occurred. + */ +size_t bin2hex(const uint8_t *buf, size_t buflen, char *hex, size_t hexlen); + +/** + * @brief Convert a hexadecimal string into a binary array. + * + * @param hex The hexadecimal string to convert + * @param hexlen The length of the hexadecimal string to convert. + * @param buf Address of where to store the binary data + * @param buflen Size of the storage area for binary data + * + * @return The length of the binary array, or 0 if an error occurred. + */ +size_t hex2bin(const char *hex, size_t hexlen, uint8_t *buf, size_t buflen); + +/** + * @brief Convert a binary coded decimal (BCD 8421) value to binary. + * + * @param bcd BCD 8421 value to convert. + * + * @return Binary representation of input value. + */ +static inline uint8_t bcd2bin(uint8_t bcd) +{ + return ((10 * (bcd >> 4)) + (bcd & 0x0F)); +} + +/** + * @brief Convert a binary value to binary coded decimal (BCD 8421). + * + * @param bin Binary value to convert. + * + * @return BCD 8421 representation of input value. + */ +static inline uint8_t bin2bcd(uint8_t bin) +{ + return (((bin / 10) << 4) | (bin % 10)); +} + +/** + * @brief Convert a uint8_t into a decimal string representation. + * + * Convert a uint8_t value into its ASCII decimal string representation. + * The string is terminated if there is enough space in buf. + * + * @param buf Address of where to store the string representation. + * @param buflen Size of the storage area for string representation. + * @param value The value to convert to decimal string + * + * @return The length of the converted string (excluding terminator if + * any), or 0 if an error occurred. + */ +uint8_t u8_to_dec(char *buf, uint8_t buflen, uint8_t value); + +/** + * @brief Sign extend an 8, 16 or 32 bit value using the index bit as sign bit. + * + * @param value The value to sign expand. + * @param index 0 based bit index to sign bit (0 to 31) + */ +static inline int32_t sign_extend(uint32_t value, uint8_t index) +{ + __ASSERT_NO_MSG(index <= 31); + + uint8_t shift = 31 - index; + + return (int32_t)(value << shift) >> shift; +} + +/** + * @brief Sign extend a 64 bit value using the index bit as sign bit. + * + * @param value The value to sign expand. + * @param index 0 based bit index to sign bit (0 to 63) + */ +static inline int64_t sign_extend_64(uint64_t value, uint8_t index) +{ + __ASSERT_NO_MSG(index <= 63); + + uint8_t shift = 63 - index; + + return (int64_t)(value << shift) >> shift; +} + +#define __z_log2d(x) (32 - __builtin_clz(x) - 1) +#define __z_log2q(x) (64 - __builtin_clzll(x) - 1) +#define __z_log2(x) (sizeof(__typeof__(x)) > 4 ? __z_log2q(x) : __z_log2d(x)) + +/** + * @brief Compute log2(x) + * + * @note This macro expands its argument multiple times (to permit use + * in constant expressions), which must not have side effects. + * + * @param x An unsigned integral value to compute logarithm of (positive only) + * + * @return log2(x) when 1 <= x <= max(x), -1 when x < 1 + */ +#define LOG2(x) ((x) < 1 ? -1 : __z_log2(x)) + +/** + * @brief Compute ceil(log2(x)) + * + * @note This macro expands its argument multiple times (to permit use + * in constant expressions), which must not have side effects. + * + * @param x An unsigned integral value + * + * @return ceil(log2(x)) when 1 <= x <= max(type(x)), 0 when x < 1 + */ +#define LOG2CEIL(x) ((x) <= 1 ? 0 : __z_log2((x) - 1) + 1) + +/** + * @brief Compute next highest power of two + * + * Equivalent to 2^ceil(log2(x)) + * + * @note This macro expands its argument multiple times (to permit use + * in constant expressions), which must not have side effects. + * + * @param x An unsigned integral value + * + * @return 2^ceil(log2(x)) or 0 if 2^ceil(log2(x)) would saturate 64-bits + */ +#define NHPOT(x) ((x) < 1 ? 1 : ((x) > (1ULL<<63) ? 0 : 1ULL << LOG2CEIL(x))) + +/** + * @brief Determine if a buffer exceeds highest address + * + * This macro determines if a buffer identified by a starting address @a addr + * and length @a buflen spans a region of memory that goes beyond the highest + * possible address (thereby resulting in a pointer overflow). + * + * @param addr Buffer starting address + * @param buflen Length of the buffer + * + * @return true if pointer overflow detected, false otherwise + */ +#define Z_DETECT_POINTER_OVERFLOW(addr, buflen) \ + (((buflen) != 0) && ((UINTPTR_MAX - (uintptr_t)(addr)) <= ((uintptr_t)((buflen) - 1)))) + +/** + * @brief XOR n bytes + * + * @param dst Destination of where to store result. Shall be @p len bytes. + * @param src1 First source. Shall be @p len bytes. + * @param src2 Second source. Shall be @p len bytes. + * @param len Number of bytes to XOR. + */ +static inline void mem_xor_n(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, size_t len) +{ + while (len--) { + *dst++ = *src1++ ^ *src2++; + } +} + +/** + * @brief XOR 32 bits + * + * @param dst Destination of where to store result. Shall be 32 bits. + * @param src1 First source. Shall be 32 bits. + * @param src2 Second source. Shall be 32 bits. + */ +static inline void mem_xor_32(uint8_t dst[4], const uint8_t src1[4], const uint8_t src2[4]) +{ + mem_xor_n(dst, src1, src2, 4U); +} + +/** + * @brief XOR 128 bits + * + * @param dst Destination of where to store result. Shall be 128 bits. + * @param src1 First source. Shall be 128 bits. + * @param src2 Second source. Shall be 128 bits. + */ +static inline void mem_xor_128(uint8_t dst[16], const uint8_t src1[16], const uint8_t src2[16]) +{ + mem_xor_n(dst, src1, src2, 16); +} + +/** + * @brief Compare memory areas. The same way as `memcmp` it assume areas to be + * the same length + * + * @param m1 First memory area to compare, cannot be NULL even if length is 0 + * @param m2 Second memory area to compare, cannot be NULL even if length is 0 + * @param n First n bytes of @p m1 and @p m2 to compares + * + * @returns true if the @p n first bytes of @p m1 and @p m2 are the same, else + * false + */ +static inline bool util_memeq(const void *m1, const void *m2, size_t n) +{ + return memcmp(m1, m2, n) == 0; +} + +/** + * @brief Compare memory areas and their length + * + * If the length are 0, return true. + * + * @param m1 First memory area to compare, cannot be NULL even if length is 0 + * @param len1 Length of the first memory area to compare + * @param m2 Second memory area to compare, cannot be NULL even if length is 0 + * @param len2 Length of the second memory area to compare + * + * @returns true if both the length of the memory areas and their content are + * equal else false + */ +static inline bool util_eq(const void *m1, size_t len1, const void *m2, size_t len2) +{ + return len1 == len2 && (m1 == m2 || util_memeq(m1, m2, len1)); +} + +/** + * @brief Returns the number of bits set in a value + * + * @param value The value to count number of bits set of + * @param len The number of octets in @p value + */ +static inline size_t sys_count_bits(const void *value, size_t len) +{ + size_t cnt = 0U; + size_t i = 0U; + + for (; i < len / sizeof(unsigned int); i++) { + unsigned int val; + (void)memcpy(&val, (const uint8_t *)value + i * sizeof(unsigned int), + sizeof(unsigned int)); + + cnt += __builtin_popcount(val); + } + i *= sizeof(unsigned int); /* convert to a uint8_t index for the remainder (if any) */ + + for (; i < len; i++) { + uint8_t value_u8 = ((const uint8_t *)value)[i]; + + /* Implements Brian Kernighan’s Algorithm to count bits */ + while (value_u8) { + value_u8 &= (value_u8 - 1); + cnt++; + } + } + + return cnt; +} + +#ifdef __cplusplus +} +#endif + +/* This file must be included at the end of the !_ASMLANGUAGE guard. + * It depends on macros defined in this file above which cannot be forward declared. + */ + +#endif /* !_ASMLANGUAGE */ + +/** @brief Number of bytes in @p x kibibytes */ +#ifdef _LINKER +/* This is used in linker scripts so need to avoid type casting there */ +#define KB(x) ((x) << 10) +#else +#define KB(x) (((size_t)(x)) << 10) +#endif +/** @brief Number of bytes in @p x mebibytes */ +#define MB(x) (KB(x) << 10) +/** @brief Number of bytes in @p x gibibytes */ +#define GB(x) (MB(x) << 10) + +/** @brief Number of Hz in @p x kHz */ +#define KHZ(x) ((x) * 1000) +/** @brief Number of Hz in @p x MHz */ +#define MHZ(x) (KHZ(x) * 1000) + +/** + * @brief For the POSIX architecture add a minimal delay in a busy wait loop. + * For other architectures this is a no-op. + * + * In the POSIX ARCH, code takes zero simulated time to execute, + * so busy wait loops become infinite loops, unless we + * force the loop to take a bit of time. + * Include this macro in all busy wait/spin loops + * so they will also work when building for the POSIX architecture. + * + * @param t Time in microseconds we will busy wait + */ +#if defined(CONFIG_ARCH_POSIX) +#define Z_SPIN_DELAY(t) k_busy_wait(t) +#else +#define Z_SPIN_DELAY(t) +#endif + +/** + * @brief Wait for an expression to return true with a timeout + * + * Spin on an expression with a timeout and optional delay between iterations + * + * Commonly needed when waiting on hardware to complete an asynchronous + * request to read/write/initialize/reset, but useful for any expression. + * + * @param expr Truth expression upon which to poll, e.g.: XYZREG & XYZREG_EN + * @param timeout Timeout to wait for in microseconds, e.g.: 1000 (1ms) + * @param delay_stmt Delay statement to perform each poll iteration + * e.g.: NULL, k_yield(), k_msleep(1) or k_busy_wait(1) + * + * @retval expr As a boolean return, if false then it has timed out. + */ +#define WAIT_FOR(expr, timeout, delay_stmt) \ + ({ \ + uint32_t _wf_cycle_count = k_us_to_cyc_ceil32(timeout); \ + uint32_t _wf_start = k_cycle_get_32(); \ + while (!(expr) && (_wf_cycle_count > (k_cycle_get_32() - _wf_start))) { \ + delay_stmt; \ + Z_SPIN_DELAY(10); \ + } \ + (expr); \ + }) + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_SYS_UTIL_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/sys/util_internal.h b/components/bt/esp_ble_audio/include/zephyr/sys/util_internal.h new file mode 100644 index 0000000000..940de84523 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/sys/util_internal.h @@ -0,0 +1,201 @@ +/* + * SPDX-FileCopyrightText: 2011-2014 Wind River Systems, Inc. + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Misc utilities + * + * Repetitive or obscure helper macros needed by sys/util.h. + */ + +#ifndef ZEPHYR_INCLUDE_SYS_UTIL_INTERNAL_H_ +#define ZEPHYR_INCLUDE_SYS_UTIL_INTERNAL_H_ + +#include "util_loops.h" + +/* IS_ENABLED() helpers */ + +/* This is called from IS_ENABLED(), and sticks on a "_XXXX" prefix, + * it will now be "_XXXX1" if config_macro is "1", or just "_XXXX" if it's + * undefined. + * ENABLED: Z_IS_ENABLED2(_XXXX1) + * DISABLED Z_IS_ENABLED2(_XXXX) + */ +#define Z_IS_ENABLED1(config_macro) Z_IS_ENABLED2(_XXXX##config_macro) + +/* Here's the core trick, we map "_XXXX1" to "_YYYY," (i.e. a string + * with a trailing comma), so it has the effect of making this a + * two-argument tuple to the preprocessor only in the case where the + * value is defined to "1" + * ENABLED: _YYYY, <--- note comma! + * DISABLED: _XXXX + */ +#define _XXXX1 _YYYY, + +/* Then we append an extra argument to fool the gcc preprocessor into + * accepting it as a varargs macro. + * arg1 arg2 arg3 + * ENABLED: Z_IS_ENABLED3(_YYYY, 1, 0) + * DISABLED Z_IS_ENABLED3(_XXXX 1, 0) + */ +#define Z_IS_ENABLED2(one_or_two_args) Z_IS_ENABLED3(one_or_two_args 1, 0) + +/* And our second argument is thus now cooked to be 1 in the case + * where the value is defined to 1, and 0 if not: + */ +#define Z_IS_ENABLED3(ignore_this, val, ...) val + +/* Implementation of IS_EQ(). Returns 1 if _0 and _1 are the same integer from + * 0 to 4096, 0 otherwise. + */ +#define Z_IS_EQ(_0, _1) Z_HAS_COMMA(Z_CAT4(Z_IS_, _0, _EQ_, _1)()) + +/* Used internally by COND_CODE_1 and COND_CODE_0. */ +#define Z_COND_CODE_1(_flag, _if_1_code, _else_code) \ + __COND_CODE(_XXXX##_flag, _if_1_code, _else_code) +#define Z_COND_CODE_0(_flag, _if_0_code, _else_code) \ + __COND_CODE(_ZZZZ##_flag, _if_0_code, _else_code) +#define _ZZZZ0 _YYYY, +#define __COND_CODE(one_or_two_args, _if_code, _else_code) \ + __GET_ARG2_DEBRACKET(one_or_two_args _if_code, _else_code) + +/* Gets second argument and removes brackets around that argument. It + * is expected that the parameter is provided in brackets/parentheses. + */ +#define __GET_ARG2_DEBRACKET(ignore_this, val, ...) __DEBRACKET val + +/* Used to remove brackets from around a single argument. */ +#define __DEBRACKET(...) __VA_ARGS__ + +/* Used by IS_EMPTY() */ +/* reference: https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/ */ +#define Z_HAS_COMMA(...) \ + NUM_VA_ARGS_LESS_1_IMPL(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0) +#define Z_TRIGGER_PARENTHESIS_(...) , +#define Z_IS_EMPTY_(...) \ + Z_IS_EMPTY__( \ + Z_HAS_COMMA(__VA_ARGS__), \ + Z_HAS_COMMA(Z_TRIGGER_PARENTHESIS_ __VA_ARGS__), \ + Z_HAS_COMMA(__VA_ARGS__ (/*empty*/)), \ + Z_HAS_COMMA(Z_TRIGGER_PARENTHESIS_ __VA_ARGS__ (/*empty*/))) +#define Z_CAT4(_0, _1, _2, _3) _0 ## _1 ## _2 ## _3 +#define Z_CAT5(_0, _1, _2, _3, _4) _0 ## _1 ## _2 ## _3 ## _4 +#define Z_IS_EMPTY__(_0, _1, _2, _3) \ + Z_HAS_COMMA(Z_CAT5(Z_IS_EMPTY_CASE_, _0, _1, _2, _3)) +#define Z_IS_EMPTY_CASE_0001 , + +/* Used by LIST_DROP_EMPTY() */ +/* Adding ',' after each element would add empty element at the end of + * list, which is hard to remove, so instead precede each element with ',', + * this way first element is empty, and this one is easy to drop. + */ +#define Z_LIST_ADD_ELEM(e) EMPTY, e +#define Z_LIST_DROP_FIRST(...) GET_ARGS_LESS_N(1, __VA_ARGS__) +#define Z_LIST_NO_EMPTIES(e) \ + COND_CODE_1(IS_EMPTY(e), (), (Z_LIST_ADD_ELEM(e))) + +#define UTIL_CAT(a, ...) UTIL_PRIMITIVE_CAT(a, __VA_ARGS__) +#define UTIL_PRIMITIVE_CAT(a, ...) a##__VA_ARGS__ +#define UTIL_CHECK_N(x, n, ...) n +#define UTIL_CHECK(...) UTIL_CHECK_N(__VA_ARGS__, 0,) +#define UTIL_NOT(x) UTIL_CHECK(UTIL_PRIMITIVE_CAT(UTIL_NOT_, x)) +#define UTIL_NOT_0 ~, 1, +#define UTIL_COMPL(b) UTIL_PRIMITIVE_CAT(UTIL_COMPL_, b) +#define UTIL_COMPL_0 1 +#define UTIL_COMPL_1 0 +#define UTIL_BOOL(x) UTIL_COMPL(UTIL_NOT(x)) + +#define UTIL_EVAL(...) __VA_ARGS__ +#define UTIL_EXPAND(...) __VA_ARGS__ +#define UTIL_REPEAT(...) UTIL_LISTIFY(__VA_ARGS__) + +#define _CONCAT_0(arg, ...) arg +#define _CONCAT_1(arg, ...) UTIL_CAT(arg, _CONCAT_0(__VA_ARGS__)) +#define _CONCAT_2(arg, ...) UTIL_CAT(arg, _CONCAT_1(__VA_ARGS__)) +#define _CONCAT_3(arg, ...) UTIL_CAT(arg, _CONCAT_2(__VA_ARGS__)) +#define _CONCAT_4(arg, ...) UTIL_CAT(arg, _CONCAT_3(__VA_ARGS__)) +#define _CONCAT_5(arg, ...) UTIL_CAT(arg, _CONCAT_4(__VA_ARGS__)) +#define _CONCAT_6(arg, ...) UTIL_CAT(arg, _CONCAT_5(__VA_ARGS__)) +#define _CONCAT_7(arg, ...) UTIL_CAT(arg, _CONCAT_6(__VA_ARGS__)) + +/* Implementation details for NUM_VA_ARGS_LESS_1 */ +#define NUM_VA_ARGS_LESS_1_IMPL( \ + _ignored, \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \ + _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \ + _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \ + _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \ + _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, \ + _61, _62, N, ...) N + +/* Used by MACRO_MAP_CAT */ +#define MACRO_MAP_CAT_(...) \ + /* To make sure it works also for 2 arguments in total */ \ + MACRO_MAP_CAT_N(NUM_VA_ARGS_LESS_1(__VA_ARGS__), __VA_ARGS__) +#define MACRO_MAP_CAT_N_(N, ...) UTIL_CAT(MACRO_MC_, N)(__VA_ARGS__,) +#define MACRO_MC_0(...) +#define MACRO_MC_1(m, a, ...) m(a) +#define MACRO_MC_2(m, a, ...) UTIL_CAT(m(a), MACRO_MC_1(m, __VA_ARGS__,)) +#define MACRO_MC_3(m, a, ...) UTIL_CAT(m(a), MACRO_MC_2(m, __VA_ARGS__,)) +#define MACRO_MC_4(m, a, ...) UTIL_CAT(m(a), MACRO_MC_3(m, __VA_ARGS__,)) +#define MACRO_MC_5(m, a, ...) UTIL_CAT(m(a), MACRO_MC_4(m, __VA_ARGS__,)) +#define MACRO_MC_6(m, a, ...) UTIL_CAT(m(a), MACRO_MC_5(m, __VA_ARGS__,)) +#define MACRO_MC_7(m, a, ...) UTIL_CAT(m(a), MACRO_MC_6(m, __VA_ARGS__,)) +#define MACRO_MC_8(m, a, ...) UTIL_CAT(m(a), MACRO_MC_7(m, __VA_ARGS__,)) +#define MACRO_MC_9(m, a, ...) UTIL_CAT(m(a), MACRO_MC_8(m, __VA_ARGS__,)) +#define MACRO_MC_10(m, a, ...) UTIL_CAT(m(a), MACRO_MC_9(m, __VA_ARGS__,)) +#define MACRO_MC_11(m, a, ...) UTIL_CAT(m(a), MACRO_MC_10(m, __VA_ARGS__,)) +#define MACRO_MC_12(m, a, ...) UTIL_CAT(m(a), MACRO_MC_11(m, __VA_ARGS__,)) +#define MACRO_MC_13(m, a, ...) UTIL_CAT(m(a), MACRO_MC_12(m, __VA_ARGS__,)) +#define MACRO_MC_14(m, a, ...) UTIL_CAT(m(a), MACRO_MC_13(m, __VA_ARGS__,)) +#define MACRO_MC_15(m, a, ...) UTIL_CAT(m(a), MACRO_MC_14(m, __VA_ARGS__,)) + +/* Used by Z_IS_EQ */ +#include "util_internal_is_eq.h" + +/* + * Generic sparse list of odd numbers (check the implementation of + * GPIO_DT_RESERVED_RANGES_NGPIOS as a usage example) + */ +#define Z_SPARSE_LIST_ODD_NUMBERS \ + EMPTY, 1, EMPTY, 3, EMPTY, 5, EMPTY, 7, \ + EMPTY, 9, EMPTY, 11, EMPTY, 13, EMPTY, 15, \ + EMPTY, 17, EMPTY, 19, EMPTY, 21, EMPTY, 23, \ + EMPTY, 25, EMPTY, 27, EMPTY, 29, EMPTY, 31, \ + EMPTY, 33, EMPTY, 35, EMPTY, 37, EMPTY, 39, \ + EMPTY, 41, EMPTY, 43, EMPTY, 45, EMPTY, 47, \ + EMPTY, 49, EMPTY, 51, EMPTY, 53, EMPTY, 55, \ + EMPTY, 57, EMPTY, 59, EMPTY, 61, EMPTY, 63 + +/* + * Generic sparse list of even numbers (check the implementation of + * GPIO_DT_RESERVED_RANGES_NGPIOS as a usage example) + */ +#define Z_SPARSE_LIST_EVEN_NUMBERS \ + 0, EMPTY, 2, EMPTY, 4, EMPTY, 6, EMPTY, \ + 8, EMPTY, 10, EMPTY, 12, EMPTY, 14, EMPTY, \ + 16, EMPTY, 18, EMPTY, 20, EMPTY, 22, EMPTY, \ + 24, EMPTY, 26, EMPTY, 28, EMPTY, 30, EMPTY, \ + 32, EMPTY, 34, EMPTY, 36, EMPTY, 38, EMPTY, \ + 40, EMPTY, 42, EMPTY, 44, EMPTY, 46, EMPTY, \ + 48, EMPTY, 50, EMPTY, 52, EMPTY, 54, EMPTY, \ + 56, EMPTY, 58, EMPTY, 60, EMPTY, 62, EMPTY + +/* Used by UTIL_INC */ +#include "util_internal_util_inc.h" + +/* Used by UTIL_DEC */ +#include "util_internal_util_dec.h" + +/* Used by UTIL_X2 */ +#include "util_internal_util_x2.h" + +#endif /* ZEPHYR_INCLUDE_SYS_UTIL_INTERNAL_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/sys/util_internal_is_eq.h b/components/bt/esp_ble_audio/include/zephyr/sys/util_internal_is_eq.h new file mode 100644 index 0000000000..19e309a6b9 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/sys/util_internal_is_eq.h @@ -0,0 +1,16405 @@ +/* + * SPDX-FileCopyrightText: 2011-2014, Wind River Systems, Inc. + * SPDX-FileCopyrightText: 2020, Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_SYS_UTIL_INTERNAL_H_ +#error "This header should not be used directly, please include util_internal.h instead" +#endif /* ZEPHYR_INCLUDE_SYS_UTIL_INTERNAL_H_ */ + +#ifndef ZEPHYR_INCLUDE_SYS_UTIL_INTERNAL_IS_EQ_H_ +#define ZEPHYR_INCLUDE_SYS_UTIL_INTERNAL_IS_EQ_H_ + +#define Z_IS_0_EQ_0(...) \, +#define Z_IS_0U_EQ_0(...) \, +#define Z_IS_0_EQ_0U(...) \, +#define Z_IS_0U_EQ_0U(...) \, +#define Z_IS_1_EQ_1(...) \, +#define Z_IS_1U_EQ_1(...) \, +#define Z_IS_1_EQ_1U(...) \, +#define Z_IS_1U_EQ_1U(...) \, +#define Z_IS_2_EQ_2(...) \, +#define Z_IS_2U_EQ_2(...) \, +#define Z_IS_2_EQ_2U(...) \, +#define Z_IS_2U_EQ_2U(...) \, +#define Z_IS_3_EQ_3(...) \, +#define Z_IS_3U_EQ_3(...) \, +#define Z_IS_3_EQ_3U(...) \, +#define Z_IS_3U_EQ_3U(...) \, +#define Z_IS_4_EQ_4(...) \, +#define Z_IS_4U_EQ_4(...) \, +#define Z_IS_4_EQ_4U(...) \, +#define Z_IS_4U_EQ_4U(...) \, +#define Z_IS_5_EQ_5(...) \, +#define Z_IS_5U_EQ_5(...) \, +#define Z_IS_5_EQ_5U(...) \, +#define Z_IS_5U_EQ_5U(...) \, +#define Z_IS_6_EQ_6(...) \, +#define Z_IS_6U_EQ_6(...) \, +#define Z_IS_6_EQ_6U(...) \, +#define Z_IS_6U_EQ_6U(...) \, +#define Z_IS_7_EQ_7(...) \, +#define Z_IS_7U_EQ_7(...) \, +#define Z_IS_7_EQ_7U(...) \, +#define Z_IS_7U_EQ_7U(...) \, +#define Z_IS_8_EQ_8(...) \, +#define Z_IS_8U_EQ_8(...) \, +#define Z_IS_8_EQ_8U(...) \, +#define Z_IS_8U_EQ_8U(...) \, +#define Z_IS_9_EQ_9(...) \, +#define Z_IS_9U_EQ_9(...) \, +#define Z_IS_9_EQ_9U(...) \, +#define Z_IS_9U_EQ_9U(...) \, +#define Z_IS_10_EQ_10(...) \, +#define Z_IS_10U_EQ_10(...) \, +#define Z_IS_10_EQ_10U(...) \, +#define Z_IS_10U_EQ_10U(...) \, +#define Z_IS_11_EQ_11(...) \, +#define Z_IS_11U_EQ_11(...) \, +#define Z_IS_11_EQ_11U(...) \, +#define Z_IS_11U_EQ_11U(...) \, +#define Z_IS_12_EQ_12(...) \, +#define Z_IS_12U_EQ_12(...) \, +#define Z_IS_12_EQ_12U(...) \, +#define Z_IS_12U_EQ_12U(...) \, +#define Z_IS_13_EQ_13(...) \, +#define Z_IS_13U_EQ_13(...) \, +#define Z_IS_13_EQ_13U(...) \, +#define Z_IS_13U_EQ_13U(...) \, +#define Z_IS_14_EQ_14(...) \, +#define Z_IS_14U_EQ_14(...) \, +#define Z_IS_14_EQ_14U(...) \, +#define Z_IS_14U_EQ_14U(...) \, +#define Z_IS_15_EQ_15(...) \, +#define Z_IS_15U_EQ_15(...) \, +#define Z_IS_15_EQ_15U(...) \, +#define Z_IS_15U_EQ_15U(...) \, +#define Z_IS_16_EQ_16(...) \, +#define Z_IS_16U_EQ_16(...) \, +#define Z_IS_16_EQ_16U(...) \, +#define Z_IS_16U_EQ_16U(...) \, +#define Z_IS_17_EQ_17(...) \, +#define Z_IS_17U_EQ_17(...) \, +#define Z_IS_17_EQ_17U(...) \, +#define Z_IS_17U_EQ_17U(...) \, +#define Z_IS_18_EQ_18(...) \, +#define Z_IS_18U_EQ_18(...) \, +#define Z_IS_18_EQ_18U(...) \, +#define Z_IS_18U_EQ_18U(...) \, +#define Z_IS_19_EQ_19(...) \, +#define Z_IS_19U_EQ_19(...) \, +#define Z_IS_19_EQ_19U(...) \, +#define Z_IS_19U_EQ_19U(...) \, +#define Z_IS_20_EQ_20(...) \, +#define Z_IS_20U_EQ_20(...) \, +#define Z_IS_20_EQ_20U(...) \, +#define Z_IS_20U_EQ_20U(...) \, +#define Z_IS_21_EQ_21(...) \, +#define Z_IS_21U_EQ_21(...) \, +#define Z_IS_21_EQ_21U(...) \, +#define Z_IS_21U_EQ_21U(...) \, +#define Z_IS_22_EQ_22(...) \, +#define Z_IS_22U_EQ_22(...) \, +#define Z_IS_22_EQ_22U(...) \, +#define Z_IS_22U_EQ_22U(...) \, +#define Z_IS_23_EQ_23(...) \, +#define Z_IS_23U_EQ_23(...) \, +#define Z_IS_23_EQ_23U(...) \, +#define Z_IS_23U_EQ_23U(...) \, +#define Z_IS_24_EQ_24(...) \, +#define Z_IS_24U_EQ_24(...) \, +#define Z_IS_24_EQ_24U(...) \, +#define Z_IS_24U_EQ_24U(...) \, +#define Z_IS_25_EQ_25(...) \, +#define Z_IS_25U_EQ_25(...) \, +#define Z_IS_25_EQ_25U(...) \, +#define Z_IS_25U_EQ_25U(...) \, +#define Z_IS_26_EQ_26(...) \, +#define Z_IS_26U_EQ_26(...) \, +#define Z_IS_26_EQ_26U(...) \, +#define Z_IS_26U_EQ_26U(...) \, +#define Z_IS_27_EQ_27(...) \, +#define Z_IS_27U_EQ_27(...) \, +#define Z_IS_27_EQ_27U(...) \, +#define Z_IS_27U_EQ_27U(...) \, +#define Z_IS_28_EQ_28(...) \, +#define Z_IS_28U_EQ_28(...) \, +#define Z_IS_28_EQ_28U(...) \, +#define Z_IS_28U_EQ_28U(...) \, +#define Z_IS_29_EQ_29(...) \, +#define Z_IS_29U_EQ_29(...) \, +#define Z_IS_29_EQ_29U(...) \, +#define Z_IS_29U_EQ_29U(...) \, +#define Z_IS_30_EQ_30(...) \, +#define Z_IS_30U_EQ_30(...) \, +#define Z_IS_30_EQ_30U(...) \, +#define Z_IS_30U_EQ_30U(...) \, +#define Z_IS_31_EQ_31(...) \, +#define Z_IS_31U_EQ_31(...) \, +#define Z_IS_31_EQ_31U(...) \, +#define Z_IS_31U_EQ_31U(...) \, +#define Z_IS_32_EQ_32(...) \, +#define Z_IS_32U_EQ_32(...) \, +#define Z_IS_32_EQ_32U(...) \, +#define Z_IS_32U_EQ_32U(...) \, +#define Z_IS_33_EQ_33(...) \, +#define Z_IS_33U_EQ_33(...) \, +#define Z_IS_33_EQ_33U(...) \, +#define Z_IS_33U_EQ_33U(...) \, +#define Z_IS_34_EQ_34(...) \, +#define Z_IS_34U_EQ_34(...) \, +#define Z_IS_34_EQ_34U(...) \, +#define Z_IS_34U_EQ_34U(...) \, +#define Z_IS_35_EQ_35(...) \, +#define Z_IS_35U_EQ_35(...) \, +#define Z_IS_35_EQ_35U(...) \, +#define Z_IS_35U_EQ_35U(...) \, +#define Z_IS_36_EQ_36(...) \, +#define Z_IS_36U_EQ_36(...) \, +#define Z_IS_36_EQ_36U(...) \, +#define Z_IS_36U_EQ_36U(...) \, +#define Z_IS_37_EQ_37(...) \, +#define Z_IS_37U_EQ_37(...) \, +#define Z_IS_37_EQ_37U(...) \, +#define Z_IS_37U_EQ_37U(...) \, +#define Z_IS_38_EQ_38(...) \, +#define Z_IS_38U_EQ_38(...) \, +#define Z_IS_38_EQ_38U(...) \, +#define Z_IS_38U_EQ_38U(...) \, +#define Z_IS_39_EQ_39(...) \, +#define Z_IS_39U_EQ_39(...) \, +#define Z_IS_39_EQ_39U(...) \, +#define Z_IS_39U_EQ_39U(...) \, +#define Z_IS_40_EQ_40(...) \, +#define Z_IS_40U_EQ_40(...) \, +#define Z_IS_40_EQ_40U(...) \, +#define Z_IS_40U_EQ_40U(...) \, +#define Z_IS_41_EQ_41(...) \, +#define Z_IS_41U_EQ_41(...) \, +#define Z_IS_41_EQ_41U(...) \, +#define Z_IS_41U_EQ_41U(...) \, +#define Z_IS_42_EQ_42(...) \, +#define Z_IS_42U_EQ_42(...) \, +#define Z_IS_42_EQ_42U(...) \, +#define Z_IS_42U_EQ_42U(...) \, +#define Z_IS_43_EQ_43(...) \, +#define Z_IS_43U_EQ_43(...) \, +#define Z_IS_43_EQ_43U(...) \, +#define Z_IS_43U_EQ_43U(...) \, +#define Z_IS_44_EQ_44(...) \, +#define Z_IS_44U_EQ_44(...) \, +#define Z_IS_44_EQ_44U(...) \, +#define Z_IS_44U_EQ_44U(...) \, +#define Z_IS_45_EQ_45(...) \, +#define Z_IS_45U_EQ_45(...) \, +#define Z_IS_45_EQ_45U(...) \, +#define Z_IS_45U_EQ_45U(...) \, +#define Z_IS_46_EQ_46(...) \, +#define Z_IS_46U_EQ_46(...) \, +#define Z_IS_46_EQ_46U(...) \, +#define Z_IS_46U_EQ_46U(...) \, +#define Z_IS_47_EQ_47(...) \, +#define Z_IS_47U_EQ_47(...) \, +#define Z_IS_47_EQ_47U(...) \, +#define Z_IS_47U_EQ_47U(...) \, +#define Z_IS_48_EQ_48(...) \, +#define Z_IS_48U_EQ_48(...) \, +#define Z_IS_48_EQ_48U(...) \, +#define Z_IS_48U_EQ_48U(...) \, +#define Z_IS_49_EQ_49(...) \, +#define Z_IS_49U_EQ_49(...) \, +#define Z_IS_49_EQ_49U(...) \, +#define Z_IS_49U_EQ_49U(...) \, +#define Z_IS_50_EQ_50(...) \, +#define Z_IS_50U_EQ_50(...) \, +#define Z_IS_50_EQ_50U(...) \, +#define Z_IS_50U_EQ_50U(...) \, +#define Z_IS_51_EQ_51(...) \, +#define Z_IS_51U_EQ_51(...) \, +#define Z_IS_51_EQ_51U(...) \, +#define Z_IS_51U_EQ_51U(...) \, +#define Z_IS_52_EQ_52(...) \, +#define Z_IS_52U_EQ_52(...) \, +#define Z_IS_52_EQ_52U(...) \, +#define Z_IS_52U_EQ_52U(...) \, +#define Z_IS_53_EQ_53(...) \, +#define Z_IS_53U_EQ_53(...) \, +#define Z_IS_53_EQ_53U(...) \, +#define Z_IS_53U_EQ_53U(...) \, +#define Z_IS_54_EQ_54(...) \, +#define Z_IS_54U_EQ_54(...) \, +#define Z_IS_54_EQ_54U(...) \, +#define Z_IS_54U_EQ_54U(...) \, +#define Z_IS_55_EQ_55(...) \, +#define Z_IS_55U_EQ_55(...) \, +#define Z_IS_55_EQ_55U(...) \, +#define Z_IS_55U_EQ_55U(...) \, +#define Z_IS_56_EQ_56(...) \, +#define Z_IS_56U_EQ_56(...) \, +#define Z_IS_56_EQ_56U(...) \, +#define Z_IS_56U_EQ_56U(...) \, +#define Z_IS_57_EQ_57(...) \, +#define Z_IS_57U_EQ_57(...) \, +#define Z_IS_57_EQ_57U(...) \, +#define Z_IS_57U_EQ_57U(...) \, +#define Z_IS_58_EQ_58(...) \, +#define Z_IS_58U_EQ_58(...) \, +#define Z_IS_58_EQ_58U(...) \, +#define Z_IS_58U_EQ_58U(...) \, +#define Z_IS_59_EQ_59(...) \, +#define Z_IS_59U_EQ_59(...) \, +#define Z_IS_59_EQ_59U(...) \, +#define Z_IS_59U_EQ_59U(...) \, +#define Z_IS_60_EQ_60(...) \, +#define Z_IS_60U_EQ_60(...) \, +#define Z_IS_60_EQ_60U(...) \, +#define Z_IS_60U_EQ_60U(...) \, +#define Z_IS_61_EQ_61(...) \, +#define Z_IS_61U_EQ_61(...) \, +#define Z_IS_61_EQ_61U(...) \, +#define Z_IS_61U_EQ_61U(...) \, +#define Z_IS_62_EQ_62(...) \, +#define Z_IS_62U_EQ_62(...) \, +#define Z_IS_62_EQ_62U(...) \, +#define Z_IS_62U_EQ_62U(...) \, +#define Z_IS_63_EQ_63(...) \, +#define Z_IS_63U_EQ_63(...) \, +#define Z_IS_63_EQ_63U(...) \, +#define Z_IS_63U_EQ_63U(...) \, +#define Z_IS_64_EQ_64(...) \, +#define Z_IS_64U_EQ_64(...) \, +#define Z_IS_64_EQ_64U(...) \, +#define Z_IS_64U_EQ_64U(...) \, +#define Z_IS_65_EQ_65(...) \, +#define Z_IS_65U_EQ_65(...) \, +#define Z_IS_65_EQ_65U(...) \, +#define Z_IS_65U_EQ_65U(...) \, +#define Z_IS_66_EQ_66(...) \, +#define Z_IS_66U_EQ_66(...) \, +#define Z_IS_66_EQ_66U(...) \, +#define Z_IS_66U_EQ_66U(...) \, +#define Z_IS_67_EQ_67(...) \, +#define Z_IS_67U_EQ_67(...) \, +#define Z_IS_67_EQ_67U(...) \, +#define Z_IS_67U_EQ_67U(...) \, +#define Z_IS_68_EQ_68(...) \, +#define Z_IS_68U_EQ_68(...) \, +#define Z_IS_68_EQ_68U(...) \, +#define Z_IS_68U_EQ_68U(...) \, +#define Z_IS_69_EQ_69(...) \, +#define Z_IS_69U_EQ_69(...) \, +#define Z_IS_69_EQ_69U(...) \, +#define Z_IS_69U_EQ_69U(...) \, +#define Z_IS_70_EQ_70(...) \, +#define Z_IS_70U_EQ_70(...) \, +#define Z_IS_70_EQ_70U(...) \, +#define Z_IS_70U_EQ_70U(...) \, +#define Z_IS_71_EQ_71(...) \, +#define Z_IS_71U_EQ_71(...) \, +#define Z_IS_71_EQ_71U(...) \, +#define Z_IS_71U_EQ_71U(...) \, +#define Z_IS_72_EQ_72(...) \, +#define Z_IS_72U_EQ_72(...) \, +#define Z_IS_72_EQ_72U(...) \, +#define Z_IS_72U_EQ_72U(...) \, +#define Z_IS_73_EQ_73(...) \, +#define Z_IS_73U_EQ_73(...) \, +#define Z_IS_73_EQ_73U(...) \, +#define Z_IS_73U_EQ_73U(...) \, +#define Z_IS_74_EQ_74(...) \, +#define Z_IS_74U_EQ_74(...) \, +#define Z_IS_74_EQ_74U(...) \, +#define Z_IS_74U_EQ_74U(...) \, +#define Z_IS_75_EQ_75(...) \, +#define Z_IS_75U_EQ_75(...) \, +#define Z_IS_75_EQ_75U(...) \, +#define Z_IS_75U_EQ_75U(...) \, +#define Z_IS_76_EQ_76(...) \, +#define Z_IS_76U_EQ_76(...) \, +#define Z_IS_76_EQ_76U(...) \, +#define Z_IS_76U_EQ_76U(...) \, +#define Z_IS_77_EQ_77(...) \, +#define Z_IS_77U_EQ_77(...) \, +#define Z_IS_77_EQ_77U(...) \, +#define Z_IS_77U_EQ_77U(...) \, +#define Z_IS_78_EQ_78(...) \, +#define Z_IS_78U_EQ_78(...) \, +#define Z_IS_78_EQ_78U(...) \, +#define Z_IS_78U_EQ_78U(...) \, +#define Z_IS_79_EQ_79(...) \, +#define Z_IS_79U_EQ_79(...) \, +#define Z_IS_79_EQ_79U(...) \, +#define Z_IS_79U_EQ_79U(...) \, +#define Z_IS_80_EQ_80(...) \, +#define Z_IS_80U_EQ_80(...) \, +#define Z_IS_80_EQ_80U(...) \, +#define Z_IS_80U_EQ_80U(...) \, +#define Z_IS_81_EQ_81(...) \, +#define Z_IS_81U_EQ_81(...) \, +#define Z_IS_81_EQ_81U(...) \, +#define Z_IS_81U_EQ_81U(...) \, +#define Z_IS_82_EQ_82(...) \, +#define Z_IS_82U_EQ_82(...) \, +#define Z_IS_82_EQ_82U(...) \, +#define Z_IS_82U_EQ_82U(...) \, +#define Z_IS_83_EQ_83(...) \, +#define Z_IS_83U_EQ_83(...) \, +#define Z_IS_83_EQ_83U(...) \, +#define Z_IS_83U_EQ_83U(...) \, +#define Z_IS_84_EQ_84(...) \, +#define Z_IS_84U_EQ_84(...) \, +#define Z_IS_84_EQ_84U(...) \, +#define Z_IS_84U_EQ_84U(...) \, +#define Z_IS_85_EQ_85(...) \, +#define Z_IS_85U_EQ_85(...) \, +#define Z_IS_85_EQ_85U(...) \, +#define Z_IS_85U_EQ_85U(...) \, +#define Z_IS_86_EQ_86(...) \, +#define Z_IS_86U_EQ_86(...) \, +#define Z_IS_86_EQ_86U(...) \, +#define Z_IS_86U_EQ_86U(...) \, +#define Z_IS_87_EQ_87(...) \, +#define Z_IS_87U_EQ_87(...) \, +#define Z_IS_87_EQ_87U(...) \, +#define Z_IS_87U_EQ_87U(...) \, +#define Z_IS_88_EQ_88(...) \, +#define Z_IS_88U_EQ_88(...) \, +#define Z_IS_88_EQ_88U(...) \, +#define Z_IS_88U_EQ_88U(...) \, +#define Z_IS_89_EQ_89(...) \, +#define Z_IS_89U_EQ_89(...) \, +#define Z_IS_89_EQ_89U(...) \, +#define Z_IS_89U_EQ_89U(...) \, +#define Z_IS_90_EQ_90(...) \, +#define Z_IS_90U_EQ_90(...) \, +#define Z_IS_90_EQ_90U(...) \, +#define Z_IS_90U_EQ_90U(...) \, +#define Z_IS_91_EQ_91(...) \, +#define Z_IS_91U_EQ_91(...) \, +#define Z_IS_91_EQ_91U(...) \, +#define Z_IS_91U_EQ_91U(...) \, +#define Z_IS_92_EQ_92(...) \, +#define Z_IS_92U_EQ_92(...) \, +#define Z_IS_92_EQ_92U(...) \, +#define Z_IS_92U_EQ_92U(...) \, +#define Z_IS_93_EQ_93(...) \, +#define Z_IS_93U_EQ_93(...) \, +#define Z_IS_93_EQ_93U(...) \, +#define Z_IS_93U_EQ_93U(...) \, +#define Z_IS_94_EQ_94(...) \, +#define Z_IS_94U_EQ_94(...) \, +#define Z_IS_94_EQ_94U(...) \, +#define Z_IS_94U_EQ_94U(...) \, +#define Z_IS_95_EQ_95(...) \, +#define Z_IS_95U_EQ_95(...) \, +#define Z_IS_95_EQ_95U(...) \, +#define Z_IS_95U_EQ_95U(...) \, +#define Z_IS_96_EQ_96(...) \, +#define Z_IS_96U_EQ_96(...) \, +#define Z_IS_96_EQ_96U(...) \, +#define Z_IS_96U_EQ_96U(...) \, +#define Z_IS_97_EQ_97(...) \, +#define Z_IS_97U_EQ_97(...) \, +#define Z_IS_97_EQ_97U(...) \, +#define Z_IS_97U_EQ_97U(...) \, +#define Z_IS_98_EQ_98(...) \, +#define Z_IS_98U_EQ_98(...) \, +#define Z_IS_98_EQ_98U(...) \, +#define Z_IS_98U_EQ_98U(...) \, +#define Z_IS_99_EQ_99(...) \, +#define Z_IS_99U_EQ_99(...) \, +#define Z_IS_99_EQ_99U(...) \, +#define Z_IS_99U_EQ_99U(...) \, +#define Z_IS_100_EQ_100(...) \, +#define Z_IS_100U_EQ_100(...) \, +#define Z_IS_100_EQ_100U(...) \, +#define Z_IS_100U_EQ_100U(...) \, +#define Z_IS_101_EQ_101(...) \, +#define Z_IS_101U_EQ_101(...) \, +#define Z_IS_101_EQ_101U(...) \, +#define Z_IS_101U_EQ_101U(...) \, +#define Z_IS_102_EQ_102(...) \, +#define Z_IS_102U_EQ_102(...) \, +#define Z_IS_102_EQ_102U(...) \, +#define Z_IS_102U_EQ_102U(...) \, +#define Z_IS_103_EQ_103(...) \, +#define Z_IS_103U_EQ_103(...) \, +#define Z_IS_103_EQ_103U(...) \, +#define Z_IS_103U_EQ_103U(...) \, +#define Z_IS_104_EQ_104(...) \, +#define Z_IS_104U_EQ_104(...) \, +#define Z_IS_104_EQ_104U(...) \, +#define Z_IS_104U_EQ_104U(...) \, +#define Z_IS_105_EQ_105(...) \, +#define Z_IS_105U_EQ_105(...) \, +#define Z_IS_105_EQ_105U(...) \, +#define Z_IS_105U_EQ_105U(...) \, +#define Z_IS_106_EQ_106(...) \, +#define Z_IS_106U_EQ_106(...) \, +#define Z_IS_106_EQ_106U(...) \, +#define Z_IS_106U_EQ_106U(...) \, +#define Z_IS_107_EQ_107(...) \, +#define Z_IS_107U_EQ_107(...) \, +#define Z_IS_107_EQ_107U(...) \, +#define Z_IS_107U_EQ_107U(...) \, +#define Z_IS_108_EQ_108(...) \, +#define Z_IS_108U_EQ_108(...) \, +#define Z_IS_108_EQ_108U(...) \, +#define Z_IS_108U_EQ_108U(...) \, +#define Z_IS_109_EQ_109(...) \, +#define Z_IS_109U_EQ_109(...) \, +#define Z_IS_109_EQ_109U(...) \, +#define Z_IS_109U_EQ_109U(...) \, +#define Z_IS_110_EQ_110(...) \, +#define Z_IS_110U_EQ_110(...) \, +#define Z_IS_110_EQ_110U(...) \, +#define Z_IS_110U_EQ_110U(...) \, +#define Z_IS_111_EQ_111(...) \, +#define Z_IS_111U_EQ_111(...) \, +#define Z_IS_111_EQ_111U(...) \, +#define Z_IS_111U_EQ_111U(...) \, +#define Z_IS_112_EQ_112(...) \, +#define Z_IS_112U_EQ_112(...) \, +#define Z_IS_112_EQ_112U(...) \, +#define Z_IS_112U_EQ_112U(...) \, +#define Z_IS_113_EQ_113(...) \, +#define Z_IS_113U_EQ_113(...) \, +#define Z_IS_113_EQ_113U(...) \, +#define Z_IS_113U_EQ_113U(...) \, +#define Z_IS_114_EQ_114(...) \, +#define Z_IS_114U_EQ_114(...) \, +#define Z_IS_114_EQ_114U(...) \, +#define Z_IS_114U_EQ_114U(...) \, +#define Z_IS_115_EQ_115(...) \, +#define Z_IS_115U_EQ_115(...) \, +#define Z_IS_115_EQ_115U(...) \, +#define Z_IS_115U_EQ_115U(...) \, +#define Z_IS_116_EQ_116(...) \, +#define Z_IS_116U_EQ_116(...) \, +#define Z_IS_116_EQ_116U(...) \, +#define Z_IS_116U_EQ_116U(...) \, +#define Z_IS_117_EQ_117(...) \, +#define Z_IS_117U_EQ_117(...) \, +#define Z_IS_117_EQ_117U(...) \, +#define Z_IS_117U_EQ_117U(...) \, +#define Z_IS_118_EQ_118(...) \, +#define Z_IS_118U_EQ_118(...) \, +#define Z_IS_118_EQ_118U(...) \, +#define Z_IS_118U_EQ_118U(...) \, +#define Z_IS_119_EQ_119(...) \, +#define Z_IS_119U_EQ_119(...) \, +#define Z_IS_119_EQ_119U(...) \, +#define Z_IS_119U_EQ_119U(...) \, +#define Z_IS_120_EQ_120(...) \, +#define Z_IS_120U_EQ_120(...) \, +#define Z_IS_120_EQ_120U(...) \, +#define Z_IS_120U_EQ_120U(...) \, +#define Z_IS_121_EQ_121(...) \, +#define Z_IS_121U_EQ_121(...) \, +#define Z_IS_121_EQ_121U(...) \, +#define Z_IS_121U_EQ_121U(...) \, +#define Z_IS_122_EQ_122(...) \, +#define Z_IS_122U_EQ_122(...) \, +#define Z_IS_122_EQ_122U(...) \, +#define Z_IS_122U_EQ_122U(...) \, +#define Z_IS_123_EQ_123(...) \, +#define Z_IS_123U_EQ_123(...) \, +#define Z_IS_123_EQ_123U(...) \, +#define Z_IS_123U_EQ_123U(...) \, +#define Z_IS_124_EQ_124(...) \, +#define Z_IS_124U_EQ_124(...) \, +#define Z_IS_124_EQ_124U(...) \, +#define Z_IS_124U_EQ_124U(...) \, +#define Z_IS_125_EQ_125(...) \, +#define Z_IS_125U_EQ_125(...) \, +#define Z_IS_125_EQ_125U(...) \, +#define Z_IS_125U_EQ_125U(...) \, +#define Z_IS_126_EQ_126(...) \, +#define Z_IS_126U_EQ_126(...) \, +#define Z_IS_126_EQ_126U(...) \, +#define Z_IS_126U_EQ_126U(...) \, +#define Z_IS_127_EQ_127(...) \, +#define Z_IS_127U_EQ_127(...) \, +#define Z_IS_127_EQ_127U(...) \, +#define Z_IS_127U_EQ_127U(...) \, +#define Z_IS_128_EQ_128(...) \, +#define Z_IS_128U_EQ_128(...) \, +#define Z_IS_128_EQ_128U(...) \, +#define Z_IS_128U_EQ_128U(...) \, +#define Z_IS_129_EQ_129(...) \, +#define Z_IS_129U_EQ_129(...) \, +#define Z_IS_129_EQ_129U(...) \, +#define Z_IS_129U_EQ_129U(...) \, +#define Z_IS_130_EQ_130(...) \, +#define Z_IS_130U_EQ_130(...) \, +#define Z_IS_130_EQ_130U(...) \, +#define Z_IS_130U_EQ_130U(...) \, +#define Z_IS_131_EQ_131(...) \, +#define Z_IS_131U_EQ_131(...) \, +#define Z_IS_131_EQ_131U(...) \, +#define Z_IS_131U_EQ_131U(...) \, +#define Z_IS_132_EQ_132(...) \, +#define Z_IS_132U_EQ_132(...) \, +#define Z_IS_132_EQ_132U(...) \, +#define Z_IS_132U_EQ_132U(...) \, +#define Z_IS_133_EQ_133(...) \, +#define Z_IS_133U_EQ_133(...) \, +#define Z_IS_133_EQ_133U(...) \, +#define Z_IS_133U_EQ_133U(...) \, +#define Z_IS_134_EQ_134(...) \, +#define Z_IS_134U_EQ_134(...) \, +#define Z_IS_134_EQ_134U(...) \, +#define Z_IS_134U_EQ_134U(...) \, +#define Z_IS_135_EQ_135(...) \, +#define Z_IS_135U_EQ_135(...) \, +#define Z_IS_135_EQ_135U(...) \, +#define Z_IS_135U_EQ_135U(...) \, +#define Z_IS_136_EQ_136(...) \, +#define Z_IS_136U_EQ_136(...) \, +#define Z_IS_136_EQ_136U(...) \, +#define Z_IS_136U_EQ_136U(...) \, +#define Z_IS_137_EQ_137(...) \, +#define Z_IS_137U_EQ_137(...) \, +#define Z_IS_137_EQ_137U(...) \, +#define Z_IS_137U_EQ_137U(...) \, +#define Z_IS_138_EQ_138(...) \, +#define Z_IS_138U_EQ_138(...) \, +#define Z_IS_138_EQ_138U(...) \, +#define Z_IS_138U_EQ_138U(...) \, +#define Z_IS_139_EQ_139(...) \, +#define Z_IS_139U_EQ_139(...) \, +#define Z_IS_139_EQ_139U(...) \, +#define Z_IS_139U_EQ_139U(...) \, +#define Z_IS_140_EQ_140(...) \, +#define Z_IS_140U_EQ_140(...) \, +#define Z_IS_140_EQ_140U(...) \, +#define Z_IS_140U_EQ_140U(...) \, +#define Z_IS_141_EQ_141(...) \, +#define Z_IS_141U_EQ_141(...) \, +#define Z_IS_141_EQ_141U(...) \, +#define Z_IS_141U_EQ_141U(...) \, +#define Z_IS_142_EQ_142(...) \, +#define Z_IS_142U_EQ_142(...) \, +#define Z_IS_142_EQ_142U(...) \, +#define Z_IS_142U_EQ_142U(...) \, +#define Z_IS_143_EQ_143(...) \, +#define Z_IS_143U_EQ_143(...) \, +#define Z_IS_143_EQ_143U(...) \, +#define Z_IS_143U_EQ_143U(...) \, +#define Z_IS_144_EQ_144(...) \, +#define Z_IS_144U_EQ_144(...) \, +#define Z_IS_144_EQ_144U(...) \, +#define Z_IS_144U_EQ_144U(...) \, +#define Z_IS_145_EQ_145(...) \, +#define Z_IS_145U_EQ_145(...) \, +#define Z_IS_145_EQ_145U(...) \, +#define Z_IS_145U_EQ_145U(...) \, +#define Z_IS_146_EQ_146(...) \, +#define Z_IS_146U_EQ_146(...) \, +#define Z_IS_146_EQ_146U(...) \, +#define Z_IS_146U_EQ_146U(...) \, +#define Z_IS_147_EQ_147(...) \, +#define Z_IS_147U_EQ_147(...) \, +#define Z_IS_147_EQ_147U(...) \, +#define Z_IS_147U_EQ_147U(...) \, +#define Z_IS_148_EQ_148(...) \, +#define Z_IS_148U_EQ_148(...) \, +#define Z_IS_148_EQ_148U(...) \, +#define Z_IS_148U_EQ_148U(...) \, +#define Z_IS_149_EQ_149(...) \, +#define Z_IS_149U_EQ_149(...) \, +#define Z_IS_149_EQ_149U(...) \, +#define Z_IS_149U_EQ_149U(...) \, +#define Z_IS_150_EQ_150(...) \, +#define Z_IS_150U_EQ_150(...) \, +#define Z_IS_150_EQ_150U(...) \, +#define Z_IS_150U_EQ_150U(...) \, +#define Z_IS_151_EQ_151(...) \, +#define Z_IS_151U_EQ_151(...) \, +#define Z_IS_151_EQ_151U(...) \, +#define Z_IS_151U_EQ_151U(...) \, +#define Z_IS_152_EQ_152(...) \, +#define Z_IS_152U_EQ_152(...) \, +#define Z_IS_152_EQ_152U(...) \, +#define Z_IS_152U_EQ_152U(...) \, +#define Z_IS_153_EQ_153(...) \, +#define Z_IS_153U_EQ_153(...) \, +#define Z_IS_153_EQ_153U(...) \, +#define Z_IS_153U_EQ_153U(...) \, +#define Z_IS_154_EQ_154(...) \, +#define Z_IS_154U_EQ_154(...) \, +#define Z_IS_154_EQ_154U(...) \, +#define Z_IS_154U_EQ_154U(...) \, +#define Z_IS_155_EQ_155(...) \, +#define Z_IS_155U_EQ_155(...) \, +#define Z_IS_155_EQ_155U(...) \, +#define Z_IS_155U_EQ_155U(...) \, +#define Z_IS_156_EQ_156(...) \, +#define Z_IS_156U_EQ_156(...) \, +#define Z_IS_156_EQ_156U(...) \, +#define Z_IS_156U_EQ_156U(...) \, +#define Z_IS_157_EQ_157(...) \, +#define Z_IS_157U_EQ_157(...) \, +#define Z_IS_157_EQ_157U(...) \, +#define Z_IS_157U_EQ_157U(...) \, +#define Z_IS_158_EQ_158(...) \, +#define Z_IS_158U_EQ_158(...) \, +#define Z_IS_158_EQ_158U(...) \, +#define Z_IS_158U_EQ_158U(...) \, +#define Z_IS_159_EQ_159(...) \, +#define Z_IS_159U_EQ_159(...) \, +#define Z_IS_159_EQ_159U(...) \, +#define Z_IS_159U_EQ_159U(...) \, +#define Z_IS_160_EQ_160(...) \, +#define Z_IS_160U_EQ_160(...) \, +#define Z_IS_160_EQ_160U(...) \, +#define Z_IS_160U_EQ_160U(...) \, +#define Z_IS_161_EQ_161(...) \, +#define Z_IS_161U_EQ_161(...) \, +#define Z_IS_161_EQ_161U(...) \, +#define Z_IS_161U_EQ_161U(...) \, +#define Z_IS_162_EQ_162(...) \, +#define Z_IS_162U_EQ_162(...) \, +#define Z_IS_162_EQ_162U(...) \, +#define Z_IS_162U_EQ_162U(...) \, +#define Z_IS_163_EQ_163(...) \, +#define Z_IS_163U_EQ_163(...) \, +#define Z_IS_163_EQ_163U(...) \, +#define Z_IS_163U_EQ_163U(...) \, +#define Z_IS_164_EQ_164(...) \, +#define Z_IS_164U_EQ_164(...) \, +#define Z_IS_164_EQ_164U(...) \, +#define Z_IS_164U_EQ_164U(...) \, +#define Z_IS_165_EQ_165(...) \, +#define Z_IS_165U_EQ_165(...) \, +#define Z_IS_165_EQ_165U(...) \, +#define Z_IS_165U_EQ_165U(...) \, +#define Z_IS_166_EQ_166(...) \, +#define Z_IS_166U_EQ_166(...) \, +#define Z_IS_166_EQ_166U(...) \, +#define Z_IS_166U_EQ_166U(...) \, +#define Z_IS_167_EQ_167(...) \, +#define Z_IS_167U_EQ_167(...) \, +#define Z_IS_167_EQ_167U(...) \, +#define Z_IS_167U_EQ_167U(...) \, +#define Z_IS_168_EQ_168(...) \, +#define Z_IS_168U_EQ_168(...) \, +#define Z_IS_168_EQ_168U(...) \, +#define Z_IS_168U_EQ_168U(...) \, +#define Z_IS_169_EQ_169(...) \, +#define Z_IS_169U_EQ_169(...) \, +#define Z_IS_169_EQ_169U(...) \, +#define Z_IS_169U_EQ_169U(...) \, +#define Z_IS_170_EQ_170(...) \, +#define Z_IS_170U_EQ_170(...) \, +#define Z_IS_170_EQ_170U(...) \, +#define Z_IS_170U_EQ_170U(...) \, +#define Z_IS_171_EQ_171(...) \, +#define Z_IS_171U_EQ_171(...) \, +#define Z_IS_171_EQ_171U(...) \, +#define Z_IS_171U_EQ_171U(...) \, +#define Z_IS_172_EQ_172(...) \, +#define Z_IS_172U_EQ_172(...) \, +#define Z_IS_172_EQ_172U(...) \, +#define Z_IS_172U_EQ_172U(...) \, +#define Z_IS_173_EQ_173(...) \, +#define Z_IS_173U_EQ_173(...) \, +#define Z_IS_173_EQ_173U(...) \, +#define Z_IS_173U_EQ_173U(...) \, +#define Z_IS_174_EQ_174(...) \, +#define Z_IS_174U_EQ_174(...) \, +#define Z_IS_174_EQ_174U(...) \, +#define Z_IS_174U_EQ_174U(...) \, +#define Z_IS_175_EQ_175(...) \, +#define Z_IS_175U_EQ_175(...) \, +#define Z_IS_175_EQ_175U(...) \, +#define Z_IS_175U_EQ_175U(...) \, +#define Z_IS_176_EQ_176(...) \, +#define Z_IS_176U_EQ_176(...) \, +#define Z_IS_176_EQ_176U(...) \, +#define Z_IS_176U_EQ_176U(...) \, +#define Z_IS_177_EQ_177(...) \, +#define Z_IS_177U_EQ_177(...) \, +#define Z_IS_177_EQ_177U(...) \, +#define Z_IS_177U_EQ_177U(...) \, +#define Z_IS_178_EQ_178(...) \, +#define Z_IS_178U_EQ_178(...) \, +#define Z_IS_178_EQ_178U(...) \, +#define Z_IS_178U_EQ_178U(...) \, +#define Z_IS_179_EQ_179(...) \, +#define Z_IS_179U_EQ_179(...) \, +#define Z_IS_179_EQ_179U(...) \, +#define Z_IS_179U_EQ_179U(...) \, +#define Z_IS_180_EQ_180(...) \, +#define Z_IS_180U_EQ_180(...) \, +#define Z_IS_180_EQ_180U(...) \, +#define Z_IS_180U_EQ_180U(...) \, +#define Z_IS_181_EQ_181(...) \, +#define Z_IS_181U_EQ_181(...) \, +#define Z_IS_181_EQ_181U(...) \, +#define Z_IS_181U_EQ_181U(...) \, +#define Z_IS_182_EQ_182(...) \, +#define Z_IS_182U_EQ_182(...) \, +#define Z_IS_182_EQ_182U(...) \, +#define Z_IS_182U_EQ_182U(...) \, +#define Z_IS_183_EQ_183(...) \, +#define Z_IS_183U_EQ_183(...) \, +#define Z_IS_183_EQ_183U(...) \, +#define Z_IS_183U_EQ_183U(...) \, +#define Z_IS_184_EQ_184(...) \, +#define Z_IS_184U_EQ_184(...) \, +#define Z_IS_184_EQ_184U(...) \, +#define Z_IS_184U_EQ_184U(...) \, +#define Z_IS_185_EQ_185(...) \, +#define Z_IS_185U_EQ_185(...) \, +#define Z_IS_185_EQ_185U(...) \, +#define Z_IS_185U_EQ_185U(...) \, +#define Z_IS_186_EQ_186(...) \, +#define Z_IS_186U_EQ_186(...) \, +#define Z_IS_186_EQ_186U(...) \, +#define Z_IS_186U_EQ_186U(...) \, +#define Z_IS_187_EQ_187(...) \, +#define Z_IS_187U_EQ_187(...) \, +#define Z_IS_187_EQ_187U(...) \, +#define Z_IS_187U_EQ_187U(...) \, +#define Z_IS_188_EQ_188(...) \, +#define Z_IS_188U_EQ_188(...) \, +#define Z_IS_188_EQ_188U(...) \, +#define Z_IS_188U_EQ_188U(...) \, +#define Z_IS_189_EQ_189(...) \, +#define Z_IS_189U_EQ_189(...) \, +#define Z_IS_189_EQ_189U(...) \, +#define Z_IS_189U_EQ_189U(...) \, +#define Z_IS_190_EQ_190(...) \, +#define Z_IS_190U_EQ_190(...) \, +#define Z_IS_190_EQ_190U(...) \, +#define Z_IS_190U_EQ_190U(...) \, +#define Z_IS_191_EQ_191(...) \, +#define Z_IS_191U_EQ_191(...) \, +#define Z_IS_191_EQ_191U(...) \, +#define Z_IS_191U_EQ_191U(...) \, +#define Z_IS_192_EQ_192(...) \, +#define Z_IS_192U_EQ_192(...) \, +#define Z_IS_192_EQ_192U(...) \, +#define Z_IS_192U_EQ_192U(...) \, +#define Z_IS_193_EQ_193(...) \, +#define Z_IS_193U_EQ_193(...) \, +#define Z_IS_193_EQ_193U(...) \, +#define Z_IS_193U_EQ_193U(...) \, +#define Z_IS_194_EQ_194(...) \, +#define Z_IS_194U_EQ_194(...) \, +#define Z_IS_194_EQ_194U(...) \, +#define Z_IS_194U_EQ_194U(...) \, +#define Z_IS_195_EQ_195(...) \, +#define Z_IS_195U_EQ_195(...) \, +#define Z_IS_195_EQ_195U(...) \, +#define Z_IS_195U_EQ_195U(...) \, +#define Z_IS_196_EQ_196(...) \, +#define Z_IS_196U_EQ_196(...) \, +#define Z_IS_196_EQ_196U(...) \, +#define Z_IS_196U_EQ_196U(...) \, +#define Z_IS_197_EQ_197(...) \, +#define Z_IS_197U_EQ_197(...) \, +#define Z_IS_197_EQ_197U(...) \, +#define Z_IS_197U_EQ_197U(...) \, +#define Z_IS_198_EQ_198(...) \, +#define Z_IS_198U_EQ_198(...) \, +#define Z_IS_198_EQ_198U(...) \, +#define Z_IS_198U_EQ_198U(...) \, +#define Z_IS_199_EQ_199(...) \, +#define Z_IS_199U_EQ_199(...) \, +#define Z_IS_199_EQ_199U(...) \, +#define Z_IS_199U_EQ_199U(...) \, +#define Z_IS_200_EQ_200(...) \, +#define Z_IS_200U_EQ_200(...) \, +#define Z_IS_200_EQ_200U(...) \, +#define Z_IS_200U_EQ_200U(...) \, +#define Z_IS_201_EQ_201(...) \, +#define Z_IS_201U_EQ_201(...) \, +#define Z_IS_201_EQ_201U(...) \, +#define Z_IS_201U_EQ_201U(...) \, +#define Z_IS_202_EQ_202(...) \, +#define Z_IS_202U_EQ_202(...) \, +#define Z_IS_202_EQ_202U(...) \, +#define Z_IS_202U_EQ_202U(...) \, +#define Z_IS_203_EQ_203(...) \, +#define Z_IS_203U_EQ_203(...) \, +#define Z_IS_203_EQ_203U(...) \, +#define Z_IS_203U_EQ_203U(...) \, +#define Z_IS_204_EQ_204(...) \, +#define Z_IS_204U_EQ_204(...) \, +#define Z_IS_204_EQ_204U(...) \, +#define Z_IS_204U_EQ_204U(...) \, +#define Z_IS_205_EQ_205(...) \, +#define Z_IS_205U_EQ_205(...) \, +#define Z_IS_205_EQ_205U(...) \, +#define Z_IS_205U_EQ_205U(...) \, +#define Z_IS_206_EQ_206(...) \, +#define Z_IS_206U_EQ_206(...) \, +#define Z_IS_206_EQ_206U(...) \, +#define Z_IS_206U_EQ_206U(...) \, +#define Z_IS_207_EQ_207(...) \, +#define Z_IS_207U_EQ_207(...) \, +#define Z_IS_207_EQ_207U(...) \, +#define Z_IS_207U_EQ_207U(...) \, +#define Z_IS_208_EQ_208(...) \, +#define Z_IS_208U_EQ_208(...) \, +#define Z_IS_208_EQ_208U(...) \, +#define Z_IS_208U_EQ_208U(...) \, +#define Z_IS_209_EQ_209(...) \, +#define Z_IS_209U_EQ_209(...) \, +#define Z_IS_209_EQ_209U(...) \, +#define Z_IS_209U_EQ_209U(...) \, +#define Z_IS_210_EQ_210(...) \, +#define Z_IS_210U_EQ_210(...) \, +#define Z_IS_210_EQ_210U(...) \, +#define Z_IS_210U_EQ_210U(...) \, +#define Z_IS_211_EQ_211(...) \, +#define Z_IS_211U_EQ_211(...) \, +#define Z_IS_211_EQ_211U(...) \, +#define Z_IS_211U_EQ_211U(...) \, +#define Z_IS_212_EQ_212(...) \, +#define Z_IS_212U_EQ_212(...) \, +#define Z_IS_212_EQ_212U(...) \, +#define Z_IS_212U_EQ_212U(...) \, +#define Z_IS_213_EQ_213(...) \, +#define Z_IS_213U_EQ_213(...) \, +#define Z_IS_213_EQ_213U(...) \, +#define Z_IS_213U_EQ_213U(...) \, +#define Z_IS_214_EQ_214(...) \, +#define Z_IS_214U_EQ_214(...) \, +#define Z_IS_214_EQ_214U(...) \, +#define Z_IS_214U_EQ_214U(...) \, +#define Z_IS_215_EQ_215(...) \, +#define Z_IS_215U_EQ_215(...) \, +#define Z_IS_215_EQ_215U(...) \, +#define Z_IS_215U_EQ_215U(...) \, +#define Z_IS_216_EQ_216(...) \, +#define Z_IS_216U_EQ_216(...) \, +#define Z_IS_216_EQ_216U(...) \, +#define Z_IS_216U_EQ_216U(...) \, +#define Z_IS_217_EQ_217(...) \, +#define Z_IS_217U_EQ_217(...) \, +#define Z_IS_217_EQ_217U(...) \, +#define Z_IS_217U_EQ_217U(...) \, +#define Z_IS_218_EQ_218(...) \, +#define Z_IS_218U_EQ_218(...) \, +#define Z_IS_218_EQ_218U(...) \, +#define Z_IS_218U_EQ_218U(...) \, +#define Z_IS_219_EQ_219(...) \, +#define Z_IS_219U_EQ_219(...) \, +#define Z_IS_219_EQ_219U(...) \, +#define Z_IS_219U_EQ_219U(...) \, +#define Z_IS_220_EQ_220(...) \, +#define Z_IS_220U_EQ_220(...) \, +#define Z_IS_220_EQ_220U(...) \, +#define Z_IS_220U_EQ_220U(...) \, +#define Z_IS_221_EQ_221(...) \, +#define Z_IS_221U_EQ_221(...) \, +#define Z_IS_221_EQ_221U(...) \, +#define Z_IS_221U_EQ_221U(...) \, +#define Z_IS_222_EQ_222(...) \, +#define Z_IS_222U_EQ_222(...) \, +#define Z_IS_222_EQ_222U(...) \, +#define Z_IS_222U_EQ_222U(...) \, +#define Z_IS_223_EQ_223(...) \, +#define Z_IS_223U_EQ_223(...) \, +#define Z_IS_223_EQ_223U(...) \, +#define Z_IS_223U_EQ_223U(...) \, +#define Z_IS_224_EQ_224(...) \, +#define Z_IS_224U_EQ_224(...) \, +#define Z_IS_224_EQ_224U(...) \, +#define Z_IS_224U_EQ_224U(...) \, +#define Z_IS_225_EQ_225(...) \, +#define Z_IS_225U_EQ_225(...) \, +#define Z_IS_225_EQ_225U(...) \, +#define Z_IS_225U_EQ_225U(...) \, +#define Z_IS_226_EQ_226(...) \, +#define Z_IS_226U_EQ_226(...) \, +#define Z_IS_226_EQ_226U(...) \, +#define Z_IS_226U_EQ_226U(...) \, +#define Z_IS_227_EQ_227(...) \, +#define Z_IS_227U_EQ_227(...) \, +#define Z_IS_227_EQ_227U(...) \, +#define Z_IS_227U_EQ_227U(...) \, +#define Z_IS_228_EQ_228(...) \, +#define Z_IS_228U_EQ_228(...) \, +#define Z_IS_228_EQ_228U(...) \, +#define Z_IS_228U_EQ_228U(...) \, +#define Z_IS_229_EQ_229(...) \, +#define Z_IS_229U_EQ_229(...) \, +#define Z_IS_229_EQ_229U(...) \, +#define Z_IS_229U_EQ_229U(...) \, +#define Z_IS_230_EQ_230(...) \, +#define Z_IS_230U_EQ_230(...) \, +#define Z_IS_230_EQ_230U(...) \, +#define Z_IS_230U_EQ_230U(...) \, +#define Z_IS_231_EQ_231(...) \, +#define Z_IS_231U_EQ_231(...) \, +#define Z_IS_231_EQ_231U(...) \, +#define Z_IS_231U_EQ_231U(...) \, +#define Z_IS_232_EQ_232(...) \, +#define Z_IS_232U_EQ_232(...) \, +#define Z_IS_232_EQ_232U(...) \, +#define Z_IS_232U_EQ_232U(...) \, +#define Z_IS_233_EQ_233(...) \, +#define Z_IS_233U_EQ_233(...) \, +#define Z_IS_233_EQ_233U(...) \, +#define Z_IS_233U_EQ_233U(...) \, +#define Z_IS_234_EQ_234(...) \, +#define Z_IS_234U_EQ_234(...) \, +#define Z_IS_234_EQ_234U(...) \, +#define Z_IS_234U_EQ_234U(...) \, +#define Z_IS_235_EQ_235(...) \, +#define Z_IS_235U_EQ_235(...) \, +#define Z_IS_235_EQ_235U(...) \, +#define Z_IS_235U_EQ_235U(...) \, +#define Z_IS_236_EQ_236(...) \, +#define Z_IS_236U_EQ_236(...) \, +#define Z_IS_236_EQ_236U(...) \, +#define Z_IS_236U_EQ_236U(...) \, +#define Z_IS_237_EQ_237(...) \, +#define Z_IS_237U_EQ_237(...) \, +#define Z_IS_237_EQ_237U(...) \, +#define Z_IS_237U_EQ_237U(...) \, +#define Z_IS_238_EQ_238(...) \, +#define Z_IS_238U_EQ_238(...) \, +#define Z_IS_238_EQ_238U(...) \, +#define Z_IS_238U_EQ_238U(...) \, +#define Z_IS_239_EQ_239(...) \, +#define Z_IS_239U_EQ_239(...) \, +#define Z_IS_239_EQ_239U(...) \, +#define Z_IS_239U_EQ_239U(...) \, +#define Z_IS_240_EQ_240(...) \, +#define Z_IS_240U_EQ_240(...) \, +#define Z_IS_240_EQ_240U(...) \, +#define Z_IS_240U_EQ_240U(...) \, +#define Z_IS_241_EQ_241(...) \, +#define Z_IS_241U_EQ_241(...) \, +#define Z_IS_241_EQ_241U(...) \, +#define Z_IS_241U_EQ_241U(...) \, +#define Z_IS_242_EQ_242(...) \, +#define Z_IS_242U_EQ_242(...) \, +#define Z_IS_242_EQ_242U(...) \, +#define Z_IS_242U_EQ_242U(...) \, +#define Z_IS_243_EQ_243(...) \, +#define Z_IS_243U_EQ_243(...) \, +#define Z_IS_243_EQ_243U(...) \, +#define Z_IS_243U_EQ_243U(...) \, +#define Z_IS_244_EQ_244(...) \, +#define Z_IS_244U_EQ_244(...) \, +#define Z_IS_244_EQ_244U(...) \, +#define Z_IS_244U_EQ_244U(...) \, +#define Z_IS_245_EQ_245(...) \, +#define Z_IS_245U_EQ_245(...) \, +#define Z_IS_245_EQ_245U(...) \, +#define Z_IS_245U_EQ_245U(...) \, +#define Z_IS_246_EQ_246(...) \, +#define Z_IS_246U_EQ_246(...) \, +#define Z_IS_246_EQ_246U(...) \, +#define Z_IS_246U_EQ_246U(...) \, +#define Z_IS_247_EQ_247(...) \, +#define Z_IS_247U_EQ_247(...) \, +#define Z_IS_247_EQ_247U(...) \, +#define Z_IS_247U_EQ_247U(...) \, +#define Z_IS_248_EQ_248(...) \, +#define Z_IS_248U_EQ_248(...) \, +#define Z_IS_248_EQ_248U(...) \, +#define Z_IS_248U_EQ_248U(...) \, +#define Z_IS_249_EQ_249(...) \, +#define Z_IS_249U_EQ_249(...) \, +#define Z_IS_249_EQ_249U(...) \, +#define Z_IS_249U_EQ_249U(...) \, +#define Z_IS_250_EQ_250(...) \, +#define Z_IS_250U_EQ_250(...) \, +#define Z_IS_250_EQ_250U(...) \, +#define Z_IS_250U_EQ_250U(...) \, +#define Z_IS_251_EQ_251(...) \, +#define Z_IS_251U_EQ_251(...) \, +#define Z_IS_251_EQ_251U(...) \, +#define Z_IS_251U_EQ_251U(...) \, +#define Z_IS_252_EQ_252(...) \, +#define Z_IS_252U_EQ_252(...) \, +#define Z_IS_252_EQ_252U(...) \, +#define Z_IS_252U_EQ_252U(...) \, +#define Z_IS_253_EQ_253(...) \, +#define Z_IS_253U_EQ_253(...) \, +#define Z_IS_253_EQ_253U(...) \, +#define Z_IS_253U_EQ_253U(...) \, +#define Z_IS_254_EQ_254(...) \, +#define Z_IS_254U_EQ_254(...) \, +#define Z_IS_254_EQ_254U(...) \, +#define Z_IS_254U_EQ_254U(...) \, +#define Z_IS_255_EQ_255(...) \, +#define Z_IS_255U_EQ_255(...) \, +#define Z_IS_255_EQ_255U(...) \, +#define Z_IS_255U_EQ_255U(...) \, +#define Z_IS_256_EQ_256(...) \, +#define Z_IS_256U_EQ_256(...) \, +#define Z_IS_256_EQ_256U(...) \, +#define Z_IS_256U_EQ_256U(...) \, +#define Z_IS_257_EQ_257(...) \, +#define Z_IS_257U_EQ_257(...) \, +#define Z_IS_257_EQ_257U(...) \, +#define Z_IS_257U_EQ_257U(...) \, +#define Z_IS_258_EQ_258(...) \, +#define Z_IS_258U_EQ_258(...) \, +#define Z_IS_258_EQ_258U(...) \, +#define Z_IS_258U_EQ_258U(...) \, +#define Z_IS_259_EQ_259(...) \, +#define Z_IS_259U_EQ_259(...) \, +#define Z_IS_259_EQ_259U(...) \, +#define Z_IS_259U_EQ_259U(...) \, +#define Z_IS_260_EQ_260(...) \, +#define Z_IS_260U_EQ_260(...) \, +#define Z_IS_260_EQ_260U(...) \, +#define Z_IS_260U_EQ_260U(...) \, +#define Z_IS_261_EQ_261(...) \, +#define Z_IS_261U_EQ_261(...) \, +#define Z_IS_261_EQ_261U(...) \, +#define Z_IS_261U_EQ_261U(...) \, +#define Z_IS_262_EQ_262(...) \, +#define Z_IS_262U_EQ_262(...) \, +#define Z_IS_262_EQ_262U(...) \, +#define Z_IS_262U_EQ_262U(...) \, +#define Z_IS_263_EQ_263(...) \, +#define Z_IS_263U_EQ_263(...) \, +#define Z_IS_263_EQ_263U(...) \, +#define Z_IS_263U_EQ_263U(...) \, +#define Z_IS_264_EQ_264(...) \, +#define Z_IS_264U_EQ_264(...) \, +#define Z_IS_264_EQ_264U(...) \, +#define Z_IS_264U_EQ_264U(...) \, +#define Z_IS_265_EQ_265(...) \, +#define Z_IS_265U_EQ_265(...) \, +#define Z_IS_265_EQ_265U(...) \, +#define Z_IS_265U_EQ_265U(...) \, +#define Z_IS_266_EQ_266(...) \, +#define Z_IS_266U_EQ_266(...) \, +#define Z_IS_266_EQ_266U(...) \, +#define Z_IS_266U_EQ_266U(...) \, +#define Z_IS_267_EQ_267(...) \, +#define Z_IS_267U_EQ_267(...) \, +#define Z_IS_267_EQ_267U(...) \, +#define Z_IS_267U_EQ_267U(...) \, +#define Z_IS_268_EQ_268(...) \, +#define Z_IS_268U_EQ_268(...) \, +#define Z_IS_268_EQ_268U(...) \, +#define Z_IS_268U_EQ_268U(...) \, +#define Z_IS_269_EQ_269(...) \, +#define Z_IS_269U_EQ_269(...) \, +#define Z_IS_269_EQ_269U(...) \, +#define Z_IS_269U_EQ_269U(...) \, +#define Z_IS_270_EQ_270(...) \, +#define Z_IS_270U_EQ_270(...) \, +#define Z_IS_270_EQ_270U(...) \, +#define Z_IS_270U_EQ_270U(...) \, +#define Z_IS_271_EQ_271(...) \, +#define Z_IS_271U_EQ_271(...) \, +#define Z_IS_271_EQ_271U(...) \, +#define Z_IS_271U_EQ_271U(...) \, +#define Z_IS_272_EQ_272(...) \, +#define Z_IS_272U_EQ_272(...) \, +#define Z_IS_272_EQ_272U(...) \, +#define Z_IS_272U_EQ_272U(...) \, +#define Z_IS_273_EQ_273(...) \, +#define Z_IS_273U_EQ_273(...) \, +#define Z_IS_273_EQ_273U(...) \, +#define Z_IS_273U_EQ_273U(...) \, +#define Z_IS_274_EQ_274(...) \, +#define Z_IS_274U_EQ_274(...) \, +#define Z_IS_274_EQ_274U(...) \, +#define Z_IS_274U_EQ_274U(...) \, +#define Z_IS_275_EQ_275(...) \, +#define Z_IS_275U_EQ_275(...) \, +#define Z_IS_275_EQ_275U(...) \, +#define Z_IS_275U_EQ_275U(...) \, +#define Z_IS_276_EQ_276(...) \, +#define Z_IS_276U_EQ_276(...) \, +#define Z_IS_276_EQ_276U(...) \, +#define Z_IS_276U_EQ_276U(...) \, +#define Z_IS_277_EQ_277(...) \, +#define Z_IS_277U_EQ_277(...) \, +#define Z_IS_277_EQ_277U(...) \, +#define Z_IS_277U_EQ_277U(...) \, +#define Z_IS_278_EQ_278(...) \, +#define Z_IS_278U_EQ_278(...) \, +#define Z_IS_278_EQ_278U(...) \, +#define Z_IS_278U_EQ_278U(...) \, +#define Z_IS_279_EQ_279(...) \, +#define Z_IS_279U_EQ_279(...) \, +#define Z_IS_279_EQ_279U(...) \, +#define Z_IS_279U_EQ_279U(...) \, +#define Z_IS_280_EQ_280(...) \, +#define Z_IS_280U_EQ_280(...) \, +#define Z_IS_280_EQ_280U(...) \, +#define Z_IS_280U_EQ_280U(...) \, +#define Z_IS_281_EQ_281(...) \, +#define Z_IS_281U_EQ_281(...) \, +#define Z_IS_281_EQ_281U(...) \, +#define Z_IS_281U_EQ_281U(...) \, +#define Z_IS_282_EQ_282(...) \, +#define Z_IS_282U_EQ_282(...) \, +#define Z_IS_282_EQ_282U(...) \, +#define Z_IS_282U_EQ_282U(...) \, +#define Z_IS_283_EQ_283(...) \, +#define Z_IS_283U_EQ_283(...) \, +#define Z_IS_283_EQ_283U(...) \, +#define Z_IS_283U_EQ_283U(...) \, +#define Z_IS_284_EQ_284(...) \, +#define Z_IS_284U_EQ_284(...) \, +#define Z_IS_284_EQ_284U(...) \, +#define Z_IS_284U_EQ_284U(...) \, +#define Z_IS_285_EQ_285(...) \, +#define Z_IS_285U_EQ_285(...) \, +#define Z_IS_285_EQ_285U(...) \, +#define Z_IS_285U_EQ_285U(...) \, +#define Z_IS_286_EQ_286(...) \, +#define Z_IS_286U_EQ_286(...) \, +#define Z_IS_286_EQ_286U(...) \, +#define Z_IS_286U_EQ_286U(...) \, +#define Z_IS_287_EQ_287(...) \, +#define Z_IS_287U_EQ_287(...) \, +#define Z_IS_287_EQ_287U(...) \, +#define Z_IS_287U_EQ_287U(...) \, +#define Z_IS_288_EQ_288(...) \, +#define Z_IS_288U_EQ_288(...) \, +#define Z_IS_288_EQ_288U(...) \, +#define Z_IS_288U_EQ_288U(...) \, +#define Z_IS_289_EQ_289(...) \, +#define Z_IS_289U_EQ_289(...) \, +#define Z_IS_289_EQ_289U(...) \, +#define Z_IS_289U_EQ_289U(...) \, +#define Z_IS_290_EQ_290(...) \, +#define Z_IS_290U_EQ_290(...) \, +#define Z_IS_290_EQ_290U(...) \, +#define Z_IS_290U_EQ_290U(...) \, +#define Z_IS_291_EQ_291(...) \, +#define Z_IS_291U_EQ_291(...) \, +#define Z_IS_291_EQ_291U(...) \, +#define Z_IS_291U_EQ_291U(...) \, +#define Z_IS_292_EQ_292(...) \, +#define Z_IS_292U_EQ_292(...) \, +#define Z_IS_292_EQ_292U(...) \, +#define Z_IS_292U_EQ_292U(...) \, +#define Z_IS_293_EQ_293(...) \, +#define Z_IS_293U_EQ_293(...) \, +#define Z_IS_293_EQ_293U(...) \, +#define Z_IS_293U_EQ_293U(...) \, +#define Z_IS_294_EQ_294(...) \, +#define Z_IS_294U_EQ_294(...) \, +#define Z_IS_294_EQ_294U(...) \, +#define Z_IS_294U_EQ_294U(...) \, +#define Z_IS_295_EQ_295(...) \, +#define Z_IS_295U_EQ_295(...) \, +#define Z_IS_295_EQ_295U(...) \, +#define Z_IS_295U_EQ_295U(...) \, +#define Z_IS_296_EQ_296(...) \, +#define Z_IS_296U_EQ_296(...) \, +#define Z_IS_296_EQ_296U(...) \, +#define Z_IS_296U_EQ_296U(...) \, +#define Z_IS_297_EQ_297(...) \, +#define Z_IS_297U_EQ_297(...) \, +#define Z_IS_297_EQ_297U(...) \, +#define Z_IS_297U_EQ_297U(...) \, +#define Z_IS_298_EQ_298(...) \, +#define Z_IS_298U_EQ_298(...) \, +#define Z_IS_298_EQ_298U(...) \, +#define Z_IS_298U_EQ_298U(...) \, +#define Z_IS_299_EQ_299(...) \, +#define Z_IS_299U_EQ_299(...) \, +#define Z_IS_299_EQ_299U(...) \, +#define Z_IS_299U_EQ_299U(...) \, +#define Z_IS_300_EQ_300(...) \, +#define Z_IS_300U_EQ_300(...) \, +#define Z_IS_300_EQ_300U(...) \, +#define Z_IS_300U_EQ_300U(...) \, +#define Z_IS_301_EQ_301(...) \, +#define Z_IS_301U_EQ_301(...) \, +#define Z_IS_301_EQ_301U(...) \, +#define Z_IS_301U_EQ_301U(...) \, +#define Z_IS_302_EQ_302(...) \, +#define Z_IS_302U_EQ_302(...) \, +#define Z_IS_302_EQ_302U(...) \, +#define Z_IS_302U_EQ_302U(...) \, +#define Z_IS_303_EQ_303(...) \, +#define Z_IS_303U_EQ_303(...) \, +#define Z_IS_303_EQ_303U(...) \, +#define Z_IS_303U_EQ_303U(...) \, +#define Z_IS_304_EQ_304(...) \, +#define Z_IS_304U_EQ_304(...) \, +#define Z_IS_304_EQ_304U(...) \, +#define Z_IS_304U_EQ_304U(...) \, +#define Z_IS_305_EQ_305(...) \, +#define Z_IS_305U_EQ_305(...) \, +#define Z_IS_305_EQ_305U(...) \, +#define Z_IS_305U_EQ_305U(...) \, +#define Z_IS_306_EQ_306(...) \, +#define Z_IS_306U_EQ_306(...) \, +#define Z_IS_306_EQ_306U(...) \, +#define Z_IS_306U_EQ_306U(...) \, +#define Z_IS_307_EQ_307(...) \, +#define Z_IS_307U_EQ_307(...) \, +#define Z_IS_307_EQ_307U(...) \, +#define Z_IS_307U_EQ_307U(...) \, +#define Z_IS_308_EQ_308(...) \, +#define Z_IS_308U_EQ_308(...) \, +#define Z_IS_308_EQ_308U(...) \, +#define Z_IS_308U_EQ_308U(...) \, +#define Z_IS_309_EQ_309(...) \, +#define Z_IS_309U_EQ_309(...) \, +#define Z_IS_309_EQ_309U(...) \, +#define Z_IS_309U_EQ_309U(...) \, +#define Z_IS_310_EQ_310(...) \, +#define Z_IS_310U_EQ_310(...) \, +#define Z_IS_310_EQ_310U(...) \, +#define Z_IS_310U_EQ_310U(...) \, +#define Z_IS_311_EQ_311(...) \, +#define Z_IS_311U_EQ_311(...) \, +#define Z_IS_311_EQ_311U(...) \, +#define Z_IS_311U_EQ_311U(...) \, +#define Z_IS_312_EQ_312(...) \, +#define Z_IS_312U_EQ_312(...) \, +#define Z_IS_312_EQ_312U(...) \, +#define Z_IS_312U_EQ_312U(...) \, +#define Z_IS_313_EQ_313(...) \, +#define Z_IS_313U_EQ_313(...) \, +#define Z_IS_313_EQ_313U(...) \, +#define Z_IS_313U_EQ_313U(...) \, +#define Z_IS_314_EQ_314(...) \, +#define Z_IS_314U_EQ_314(...) \, +#define Z_IS_314_EQ_314U(...) \, +#define Z_IS_314U_EQ_314U(...) \, +#define Z_IS_315_EQ_315(...) \, +#define Z_IS_315U_EQ_315(...) \, +#define Z_IS_315_EQ_315U(...) \, +#define Z_IS_315U_EQ_315U(...) \, +#define Z_IS_316_EQ_316(...) \, +#define Z_IS_316U_EQ_316(...) \, +#define Z_IS_316_EQ_316U(...) \, +#define Z_IS_316U_EQ_316U(...) \, +#define Z_IS_317_EQ_317(...) \, +#define Z_IS_317U_EQ_317(...) \, +#define Z_IS_317_EQ_317U(...) \, +#define Z_IS_317U_EQ_317U(...) \, +#define Z_IS_318_EQ_318(...) \, +#define Z_IS_318U_EQ_318(...) \, +#define Z_IS_318_EQ_318U(...) \, +#define Z_IS_318U_EQ_318U(...) \, +#define Z_IS_319_EQ_319(...) \, +#define Z_IS_319U_EQ_319(...) \, +#define Z_IS_319_EQ_319U(...) \, +#define Z_IS_319U_EQ_319U(...) \, +#define Z_IS_320_EQ_320(...) \, +#define Z_IS_320U_EQ_320(...) \, +#define Z_IS_320_EQ_320U(...) \, +#define Z_IS_320U_EQ_320U(...) \, +#define Z_IS_321_EQ_321(...) \, +#define Z_IS_321U_EQ_321(...) \, +#define Z_IS_321_EQ_321U(...) \, +#define Z_IS_321U_EQ_321U(...) \, +#define Z_IS_322_EQ_322(...) \, +#define Z_IS_322U_EQ_322(...) \, +#define Z_IS_322_EQ_322U(...) \, +#define Z_IS_322U_EQ_322U(...) \, +#define Z_IS_323_EQ_323(...) \, +#define Z_IS_323U_EQ_323(...) \, +#define Z_IS_323_EQ_323U(...) \, +#define Z_IS_323U_EQ_323U(...) \, +#define Z_IS_324_EQ_324(...) \, +#define Z_IS_324U_EQ_324(...) \, +#define Z_IS_324_EQ_324U(...) \, +#define Z_IS_324U_EQ_324U(...) \, +#define Z_IS_325_EQ_325(...) \, +#define Z_IS_325U_EQ_325(...) \, +#define Z_IS_325_EQ_325U(...) \, +#define Z_IS_325U_EQ_325U(...) \, +#define Z_IS_326_EQ_326(...) \, +#define Z_IS_326U_EQ_326(...) \, +#define Z_IS_326_EQ_326U(...) \, +#define Z_IS_326U_EQ_326U(...) \, +#define Z_IS_327_EQ_327(...) \, +#define Z_IS_327U_EQ_327(...) \, +#define Z_IS_327_EQ_327U(...) \, +#define Z_IS_327U_EQ_327U(...) \, +#define Z_IS_328_EQ_328(...) \, +#define Z_IS_328U_EQ_328(...) \, +#define Z_IS_328_EQ_328U(...) \, +#define Z_IS_328U_EQ_328U(...) \, +#define Z_IS_329_EQ_329(...) \, +#define Z_IS_329U_EQ_329(...) \, +#define Z_IS_329_EQ_329U(...) \, +#define Z_IS_329U_EQ_329U(...) \, +#define Z_IS_330_EQ_330(...) \, +#define Z_IS_330U_EQ_330(...) \, +#define Z_IS_330_EQ_330U(...) \, +#define Z_IS_330U_EQ_330U(...) \, +#define Z_IS_331_EQ_331(...) \, +#define Z_IS_331U_EQ_331(...) \, +#define Z_IS_331_EQ_331U(...) \, +#define Z_IS_331U_EQ_331U(...) \, +#define Z_IS_332_EQ_332(...) \, +#define Z_IS_332U_EQ_332(...) \, +#define Z_IS_332_EQ_332U(...) \, +#define Z_IS_332U_EQ_332U(...) \, +#define Z_IS_333_EQ_333(...) \, +#define Z_IS_333U_EQ_333(...) \, +#define Z_IS_333_EQ_333U(...) \, +#define Z_IS_333U_EQ_333U(...) \, +#define Z_IS_334_EQ_334(...) \, +#define Z_IS_334U_EQ_334(...) \, +#define Z_IS_334_EQ_334U(...) \, +#define Z_IS_334U_EQ_334U(...) \, +#define Z_IS_335_EQ_335(...) \, +#define Z_IS_335U_EQ_335(...) \, +#define Z_IS_335_EQ_335U(...) \, +#define Z_IS_335U_EQ_335U(...) \, +#define Z_IS_336_EQ_336(...) \, +#define Z_IS_336U_EQ_336(...) \, +#define Z_IS_336_EQ_336U(...) \, +#define Z_IS_336U_EQ_336U(...) \, +#define Z_IS_337_EQ_337(...) \, +#define Z_IS_337U_EQ_337(...) \, +#define Z_IS_337_EQ_337U(...) \, +#define Z_IS_337U_EQ_337U(...) \, +#define Z_IS_338_EQ_338(...) \, +#define Z_IS_338U_EQ_338(...) \, +#define Z_IS_338_EQ_338U(...) \, +#define Z_IS_338U_EQ_338U(...) \, +#define Z_IS_339_EQ_339(...) \, +#define Z_IS_339U_EQ_339(...) \, +#define Z_IS_339_EQ_339U(...) \, +#define Z_IS_339U_EQ_339U(...) \, +#define Z_IS_340_EQ_340(...) \, +#define Z_IS_340U_EQ_340(...) \, +#define Z_IS_340_EQ_340U(...) \, +#define Z_IS_340U_EQ_340U(...) \, +#define Z_IS_341_EQ_341(...) \, +#define Z_IS_341U_EQ_341(...) \, +#define Z_IS_341_EQ_341U(...) \, +#define Z_IS_341U_EQ_341U(...) \, +#define Z_IS_342_EQ_342(...) \, +#define Z_IS_342U_EQ_342(...) \, +#define Z_IS_342_EQ_342U(...) \, +#define Z_IS_342U_EQ_342U(...) \, +#define Z_IS_343_EQ_343(...) \, +#define Z_IS_343U_EQ_343(...) \, +#define Z_IS_343_EQ_343U(...) \, +#define Z_IS_343U_EQ_343U(...) \, +#define Z_IS_344_EQ_344(...) \, +#define Z_IS_344U_EQ_344(...) \, +#define Z_IS_344_EQ_344U(...) \, +#define Z_IS_344U_EQ_344U(...) \, +#define Z_IS_345_EQ_345(...) \, +#define Z_IS_345U_EQ_345(...) \, +#define Z_IS_345_EQ_345U(...) \, +#define Z_IS_345U_EQ_345U(...) \, +#define Z_IS_346_EQ_346(...) \, +#define Z_IS_346U_EQ_346(...) \, +#define Z_IS_346_EQ_346U(...) \, +#define Z_IS_346U_EQ_346U(...) \, +#define Z_IS_347_EQ_347(...) \, +#define Z_IS_347U_EQ_347(...) \, +#define Z_IS_347_EQ_347U(...) \, +#define Z_IS_347U_EQ_347U(...) \, +#define Z_IS_348_EQ_348(...) \, +#define Z_IS_348U_EQ_348(...) \, +#define Z_IS_348_EQ_348U(...) \, +#define Z_IS_348U_EQ_348U(...) \, +#define Z_IS_349_EQ_349(...) \, +#define Z_IS_349U_EQ_349(...) \, +#define Z_IS_349_EQ_349U(...) \, +#define Z_IS_349U_EQ_349U(...) \, +#define Z_IS_350_EQ_350(...) \, +#define Z_IS_350U_EQ_350(...) \, +#define Z_IS_350_EQ_350U(...) \, +#define Z_IS_350U_EQ_350U(...) \, +#define Z_IS_351_EQ_351(...) \, +#define Z_IS_351U_EQ_351(...) \, +#define Z_IS_351_EQ_351U(...) \, +#define Z_IS_351U_EQ_351U(...) \, +#define Z_IS_352_EQ_352(...) \, +#define Z_IS_352U_EQ_352(...) \, +#define Z_IS_352_EQ_352U(...) \, +#define Z_IS_352U_EQ_352U(...) \, +#define Z_IS_353_EQ_353(...) \, +#define Z_IS_353U_EQ_353(...) \, +#define Z_IS_353_EQ_353U(...) \, +#define Z_IS_353U_EQ_353U(...) \, +#define Z_IS_354_EQ_354(...) \, +#define Z_IS_354U_EQ_354(...) \, +#define Z_IS_354_EQ_354U(...) \, +#define Z_IS_354U_EQ_354U(...) \, +#define Z_IS_355_EQ_355(...) \, +#define Z_IS_355U_EQ_355(...) \, +#define Z_IS_355_EQ_355U(...) \, +#define Z_IS_355U_EQ_355U(...) \, +#define Z_IS_356_EQ_356(...) \, +#define Z_IS_356U_EQ_356(...) \, +#define Z_IS_356_EQ_356U(...) \, +#define Z_IS_356U_EQ_356U(...) \, +#define Z_IS_357_EQ_357(...) \, +#define Z_IS_357U_EQ_357(...) \, +#define Z_IS_357_EQ_357U(...) \, +#define Z_IS_357U_EQ_357U(...) \, +#define Z_IS_358_EQ_358(...) \, +#define Z_IS_358U_EQ_358(...) \, +#define Z_IS_358_EQ_358U(...) \, +#define Z_IS_358U_EQ_358U(...) \, +#define Z_IS_359_EQ_359(...) \, +#define Z_IS_359U_EQ_359(...) \, +#define Z_IS_359_EQ_359U(...) \, +#define Z_IS_359U_EQ_359U(...) \, +#define Z_IS_360_EQ_360(...) \, +#define Z_IS_360U_EQ_360(...) \, +#define Z_IS_360_EQ_360U(...) \, +#define Z_IS_360U_EQ_360U(...) \, +#define Z_IS_361_EQ_361(...) \, +#define Z_IS_361U_EQ_361(...) \, +#define Z_IS_361_EQ_361U(...) \, +#define Z_IS_361U_EQ_361U(...) \, +#define Z_IS_362_EQ_362(...) \, +#define Z_IS_362U_EQ_362(...) \, +#define Z_IS_362_EQ_362U(...) \, +#define Z_IS_362U_EQ_362U(...) \, +#define Z_IS_363_EQ_363(...) \, +#define Z_IS_363U_EQ_363(...) \, +#define Z_IS_363_EQ_363U(...) \, +#define Z_IS_363U_EQ_363U(...) \, +#define Z_IS_364_EQ_364(...) \, +#define Z_IS_364U_EQ_364(...) \, +#define Z_IS_364_EQ_364U(...) \, +#define Z_IS_364U_EQ_364U(...) \, +#define Z_IS_365_EQ_365(...) \, +#define Z_IS_365U_EQ_365(...) \, +#define Z_IS_365_EQ_365U(...) \, +#define Z_IS_365U_EQ_365U(...) \, +#define Z_IS_366_EQ_366(...) \, +#define Z_IS_366U_EQ_366(...) \, +#define Z_IS_366_EQ_366U(...) \, +#define Z_IS_366U_EQ_366U(...) \, +#define Z_IS_367_EQ_367(...) \, +#define Z_IS_367U_EQ_367(...) \, +#define Z_IS_367_EQ_367U(...) \, +#define Z_IS_367U_EQ_367U(...) \, +#define Z_IS_368_EQ_368(...) \, +#define Z_IS_368U_EQ_368(...) \, +#define Z_IS_368_EQ_368U(...) \, +#define Z_IS_368U_EQ_368U(...) \, +#define Z_IS_369_EQ_369(...) \, +#define Z_IS_369U_EQ_369(...) \, +#define Z_IS_369_EQ_369U(...) \, +#define Z_IS_369U_EQ_369U(...) \, +#define Z_IS_370_EQ_370(...) \, +#define Z_IS_370U_EQ_370(...) \, +#define Z_IS_370_EQ_370U(...) \, +#define Z_IS_370U_EQ_370U(...) \, +#define Z_IS_371_EQ_371(...) \, +#define Z_IS_371U_EQ_371(...) \, +#define Z_IS_371_EQ_371U(...) \, +#define Z_IS_371U_EQ_371U(...) \, +#define Z_IS_372_EQ_372(...) \, +#define Z_IS_372U_EQ_372(...) \, +#define Z_IS_372_EQ_372U(...) \, +#define Z_IS_372U_EQ_372U(...) \, +#define Z_IS_373_EQ_373(...) \, +#define Z_IS_373U_EQ_373(...) \, +#define Z_IS_373_EQ_373U(...) \, +#define Z_IS_373U_EQ_373U(...) \, +#define Z_IS_374_EQ_374(...) \, +#define Z_IS_374U_EQ_374(...) \, +#define Z_IS_374_EQ_374U(...) \, +#define Z_IS_374U_EQ_374U(...) \, +#define Z_IS_375_EQ_375(...) \, +#define Z_IS_375U_EQ_375(...) \, +#define Z_IS_375_EQ_375U(...) \, +#define Z_IS_375U_EQ_375U(...) \, +#define Z_IS_376_EQ_376(...) \, +#define Z_IS_376U_EQ_376(...) \, +#define Z_IS_376_EQ_376U(...) \, +#define Z_IS_376U_EQ_376U(...) \, +#define Z_IS_377_EQ_377(...) \, +#define Z_IS_377U_EQ_377(...) \, +#define Z_IS_377_EQ_377U(...) \, +#define Z_IS_377U_EQ_377U(...) \, +#define Z_IS_378_EQ_378(...) \, +#define Z_IS_378U_EQ_378(...) \, +#define Z_IS_378_EQ_378U(...) \, +#define Z_IS_378U_EQ_378U(...) \, +#define Z_IS_379_EQ_379(...) \, +#define Z_IS_379U_EQ_379(...) \, +#define Z_IS_379_EQ_379U(...) \, +#define Z_IS_379U_EQ_379U(...) \, +#define Z_IS_380_EQ_380(...) \, +#define Z_IS_380U_EQ_380(...) \, +#define Z_IS_380_EQ_380U(...) \, +#define Z_IS_380U_EQ_380U(...) \, +#define Z_IS_381_EQ_381(...) \, +#define Z_IS_381U_EQ_381(...) \, +#define Z_IS_381_EQ_381U(...) \, +#define Z_IS_381U_EQ_381U(...) \, +#define Z_IS_382_EQ_382(...) \, +#define Z_IS_382U_EQ_382(...) \, +#define Z_IS_382_EQ_382U(...) \, +#define Z_IS_382U_EQ_382U(...) \, +#define Z_IS_383_EQ_383(...) \, +#define Z_IS_383U_EQ_383(...) \, +#define Z_IS_383_EQ_383U(...) \, +#define Z_IS_383U_EQ_383U(...) \, +#define Z_IS_384_EQ_384(...) \, +#define Z_IS_384U_EQ_384(...) \, +#define Z_IS_384_EQ_384U(...) \, +#define Z_IS_384U_EQ_384U(...) \, +#define Z_IS_385_EQ_385(...) \, +#define Z_IS_385U_EQ_385(...) \, +#define Z_IS_385_EQ_385U(...) \, +#define Z_IS_385U_EQ_385U(...) \, +#define Z_IS_386_EQ_386(...) \, +#define Z_IS_386U_EQ_386(...) \, +#define Z_IS_386_EQ_386U(...) \, +#define Z_IS_386U_EQ_386U(...) \, +#define Z_IS_387_EQ_387(...) \, +#define Z_IS_387U_EQ_387(...) \, +#define Z_IS_387_EQ_387U(...) \, +#define Z_IS_387U_EQ_387U(...) \, +#define Z_IS_388_EQ_388(...) \, +#define Z_IS_388U_EQ_388(...) \, +#define Z_IS_388_EQ_388U(...) \, +#define Z_IS_388U_EQ_388U(...) \, +#define Z_IS_389_EQ_389(...) \, +#define Z_IS_389U_EQ_389(...) \, +#define Z_IS_389_EQ_389U(...) \, +#define Z_IS_389U_EQ_389U(...) \, +#define Z_IS_390_EQ_390(...) \, +#define Z_IS_390U_EQ_390(...) \, +#define Z_IS_390_EQ_390U(...) \, +#define Z_IS_390U_EQ_390U(...) \, +#define Z_IS_391_EQ_391(...) \, +#define Z_IS_391U_EQ_391(...) \, +#define Z_IS_391_EQ_391U(...) \, +#define Z_IS_391U_EQ_391U(...) \, +#define Z_IS_392_EQ_392(...) \, +#define Z_IS_392U_EQ_392(...) \, +#define Z_IS_392_EQ_392U(...) \, +#define Z_IS_392U_EQ_392U(...) \, +#define Z_IS_393_EQ_393(...) \, +#define Z_IS_393U_EQ_393(...) \, +#define Z_IS_393_EQ_393U(...) \, +#define Z_IS_393U_EQ_393U(...) \, +#define Z_IS_394_EQ_394(...) \, +#define Z_IS_394U_EQ_394(...) \, +#define Z_IS_394_EQ_394U(...) \, +#define Z_IS_394U_EQ_394U(...) \, +#define Z_IS_395_EQ_395(...) \, +#define Z_IS_395U_EQ_395(...) \, +#define Z_IS_395_EQ_395U(...) \, +#define Z_IS_395U_EQ_395U(...) \, +#define Z_IS_396_EQ_396(...) \, +#define Z_IS_396U_EQ_396(...) \, +#define Z_IS_396_EQ_396U(...) \, +#define Z_IS_396U_EQ_396U(...) \, +#define Z_IS_397_EQ_397(...) \, +#define Z_IS_397U_EQ_397(...) \, +#define Z_IS_397_EQ_397U(...) \, +#define Z_IS_397U_EQ_397U(...) \, +#define Z_IS_398_EQ_398(...) \, +#define Z_IS_398U_EQ_398(...) \, +#define Z_IS_398_EQ_398U(...) \, +#define Z_IS_398U_EQ_398U(...) \, +#define Z_IS_399_EQ_399(...) \, +#define Z_IS_399U_EQ_399(...) \, +#define Z_IS_399_EQ_399U(...) \, +#define Z_IS_399U_EQ_399U(...) \, +#define Z_IS_400_EQ_400(...) \, +#define Z_IS_400U_EQ_400(...) \, +#define Z_IS_400_EQ_400U(...) \, +#define Z_IS_400U_EQ_400U(...) \, +#define Z_IS_401_EQ_401(...) \, +#define Z_IS_401U_EQ_401(...) \, +#define Z_IS_401_EQ_401U(...) \, +#define Z_IS_401U_EQ_401U(...) \, +#define Z_IS_402_EQ_402(...) \, +#define Z_IS_402U_EQ_402(...) \, +#define Z_IS_402_EQ_402U(...) \, +#define Z_IS_402U_EQ_402U(...) \, +#define Z_IS_403_EQ_403(...) \, +#define Z_IS_403U_EQ_403(...) \, +#define Z_IS_403_EQ_403U(...) \, +#define Z_IS_403U_EQ_403U(...) \, +#define Z_IS_404_EQ_404(...) \, +#define Z_IS_404U_EQ_404(...) \, +#define Z_IS_404_EQ_404U(...) \, +#define Z_IS_404U_EQ_404U(...) \, +#define Z_IS_405_EQ_405(...) \, +#define Z_IS_405U_EQ_405(...) \, +#define Z_IS_405_EQ_405U(...) \, +#define Z_IS_405U_EQ_405U(...) \, +#define Z_IS_406_EQ_406(...) \, +#define Z_IS_406U_EQ_406(...) \, +#define Z_IS_406_EQ_406U(...) \, +#define Z_IS_406U_EQ_406U(...) \, +#define Z_IS_407_EQ_407(...) \, +#define Z_IS_407U_EQ_407(...) \, +#define Z_IS_407_EQ_407U(...) \, +#define Z_IS_407U_EQ_407U(...) \, +#define Z_IS_408_EQ_408(...) \, +#define Z_IS_408U_EQ_408(...) \, +#define Z_IS_408_EQ_408U(...) \, +#define Z_IS_408U_EQ_408U(...) \, +#define Z_IS_409_EQ_409(...) \, +#define Z_IS_409U_EQ_409(...) \, +#define Z_IS_409_EQ_409U(...) \, +#define Z_IS_409U_EQ_409U(...) \, +#define Z_IS_410_EQ_410(...) \, +#define Z_IS_410U_EQ_410(...) \, +#define Z_IS_410_EQ_410U(...) \, +#define Z_IS_410U_EQ_410U(...) \, +#define Z_IS_411_EQ_411(...) \, +#define Z_IS_411U_EQ_411(...) \, +#define Z_IS_411_EQ_411U(...) \, +#define Z_IS_411U_EQ_411U(...) \, +#define Z_IS_412_EQ_412(...) \, +#define Z_IS_412U_EQ_412(...) \, +#define Z_IS_412_EQ_412U(...) \, +#define Z_IS_412U_EQ_412U(...) \, +#define Z_IS_413_EQ_413(...) \, +#define Z_IS_413U_EQ_413(...) \, +#define Z_IS_413_EQ_413U(...) \, +#define Z_IS_413U_EQ_413U(...) \, +#define Z_IS_414_EQ_414(...) \, +#define Z_IS_414U_EQ_414(...) \, +#define Z_IS_414_EQ_414U(...) \, +#define Z_IS_414U_EQ_414U(...) \, +#define Z_IS_415_EQ_415(...) \, +#define Z_IS_415U_EQ_415(...) \, +#define Z_IS_415_EQ_415U(...) \, +#define Z_IS_415U_EQ_415U(...) \, +#define Z_IS_416_EQ_416(...) \, +#define Z_IS_416U_EQ_416(...) \, +#define Z_IS_416_EQ_416U(...) \, +#define Z_IS_416U_EQ_416U(...) \, +#define Z_IS_417_EQ_417(...) \, +#define Z_IS_417U_EQ_417(...) \, +#define Z_IS_417_EQ_417U(...) \, +#define Z_IS_417U_EQ_417U(...) \, +#define Z_IS_418_EQ_418(...) \, +#define Z_IS_418U_EQ_418(...) \, +#define Z_IS_418_EQ_418U(...) \, +#define Z_IS_418U_EQ_418U(...) \, +#define Z_IS_419_EQ_419(...) \, +#define Z_IS_419U_EQ_419(...) \, +#define Z_IS_419_EQ_419U(...) \, +#define Z_IS_419U_EQ_419U(...) \, +#define Z_IS_420_EQ_420(...) \, +#define Z_IS_420U_EQ_420(...) \, +#define Z_IS_420_EQ_420U(...) \, +#define Z_IS_420U_EQ_420U(...) \, +#define Z_IS_421_EQ_421(...) \, +#define Z_IS_421U_EQ_421(...) \, +#define Z_IS_421_EQ_421U(...) \, +#define Z_IS_421U_EQ_421U(...) \, +#define Z_IS_422_EQ_422(...) \, +#define Z_IS_422U_EQ_422(...) \, +#define Z_IS_422_EQ_422U(...) \, +#define Z_IS_422U_EQ_422U(...) \, +#define Z_IS_423_EQ_423(...) \, +#define Z_IS_423U_EQ_423(...) \, +#define Z_IS_423_EQ_423U(...) \, +#define Z_IS_423U_EQ_423U(...) \, +#define Z_IS_424_EQ_424(...) \, +#define Z_IS_424U_EQ_424(...) \, +#define Z_IS_424_EQ_424U(...) \, +#define Z_IS_424U_EQ_424U(...) \, +#define Z_IS_425_EQ_425(...) \, +#define Z_IS_425U_EQ_425(...) \, +#define Z_IS_425_EQ_425U(...) \, +#define Z_IS_425U_EQ_425U(...) \, +#define Z_IS_426_EQ_426(...) \, +#define Z_IS_426U_EQ_426(...) \, +#define Z_IS_426_EQ_426U(...) \, +#define Z_IS_426U_EQ_426U(...) \, +#define Z_IS_427_EQ_427(...) \, +#define Z_IS_427U_EQ_427(...) \, +#define Z_IS_427_EQ_427U(...) \, +#define Z_IS_427U_EQ_427U(...) \, +#define Z_IS_428_EQ_428(...) \, +#define Z_IS_428U_EQ_428(...) \, +#define Z_IS_428_EQ_428U(...) \, +#define Z_IS_428U_EQ_428U(...) \, +#define Z_IS_429_EQ_429(...) \, +#define Z_IS_429U_EQ_429(...) \, +#define Z_IS_429_EQ_429U(...) \, +#define Z_IS_429U_EQ_429U(...) \, +#define Z_IS_430_EQ_430(...) \, +#define Z_IS_430U_EQ_430(...) \, +#define Z_IS_430_EQ_430U(...) \, +#define Z_IS_430U_EQ_430U(...) \, +#define Z_IS_431_EQ_431(...) \, +#define Z_IS_431U_EQ_431(...) \, +#define Z_IS_431_EQ_431U(...) \, +#define Z_IS_431U_EQ_431U(...) \, +#define Z_IS_432_EQ_432(...) \, +#define Z_IS_432U_EQ_432(...) \, +#define Z_IS_432_EQ_432U(...) \, +#define Z_IS_432U_EQ_432U(...) \, +#define Z_IS_433_EQ_433(...) \, +#define Z_IS_433U_EQ_433(...) \, +#define Z_IS_433_EQ_433U(...) \, +#define Z_IS_433U_EQ_433U(...) \, +#define Z_IS_434_EQ_434(...) \, +#define Z_IS_434U_EQ_434(...) \, +#define Z_IS_434_EQ_434U(...) \, +#define Z_IS_434U_EQ_434U(...) \, +#define Z_IS_435_EQ_435(...) \, +#define Z_IS_435U_EQ_435(...) \, +#define Z_IS_435_EQ_435U(...) \, +#define Z_IS_435U_EQ_435U(...) \, +#define Z_IS_436_EQ_436(...) \, +#define Z_IS_436U_EQ_436(...) \, +#define Z_IS_436_EQ_436U(...) \, +#define Z_IS_436U_EQ_436U(...) \, +#define Z_IS_437_EQ_437(...) \, +#define Z_IS_437U_EQ_437(...) \, +#define Z_IS_437_EQ_437U(...) \, +#define Z_IS_437U_EQ_437U(...) \, +#define Z_IS_438_EQ_438(...) \, +#define Z_IS_438U_EQ_438(...) \, +#define Z_IS_438_EQ_438U(...) \, +#define Z_IS_438U_EQ_438U(...) \, +#define Z_IS_439_EQ_439(...) \, +#define Z_IS_439U_EQ_439(...) \, +#define Z_IS_439_EQ_439U(...) \, +#define Z_IS_439U_EQ_439U(...) \, +#define Z_IS_440_EQ_440(...) \, +#define Z_IS_440U_EQ_440(...) \, +#define Z_IS_440_EQ_440U(...) \, +#define Z_IS_440U_EQ_440U(...) \, +#define Z_IS_441_EQ_441(...) \, +#define Z_IS_441U_EQ_441(...) \, +#define Z_IS_441_EQ_441U(...) \, +#define Z_IS_441U_EQ_441U(...) \, +#define Z_IS_442_EQ_442(...) \, +#define Z_IS_442U_EQ_442(...) \, +#define Z_IS_442_EQ_442U(...) \, +#define Z_IS_442U_EQ_442U(...) \, +#define Z_IS_443_EQ_443(...) \, +#define Z_IS_443U_EQ_443(...) \, +#define Z_IS_443_EQ_443U(...) \, +#define Z_IS_443U_EQ_443U(...) \, +#define Z_IS_444_EQ_444(...) \, +#define Z_IS_444U_EQ_444(...) \, +#define Z_IS_444_EQ_444U(...) \, +#define Z_IS_444U_EQ_444U(...) \, +#define Z_IS_445_EQ_445(...) \, +#define Z_IS_445U_EQ_445(...) \, +#define Z_IS_445_EQ_445U(...) \, +#define Z_IS_445U_EQ_445U(...) \, +#define Z_IS_446_EQ_446(...) \, +#define Z_IS_446U_EQ_446(...) \, +#define Z_IS_446_EQ_446U(...) \, +#define Z_IS_446U_EQ_446U(...) \, +#define Z_IS_447_EQ_447(...) \, +#define Z_IS_447U_EQ_447(...) \, +#define Z_IS_447_EQ_447U(...) \, +#define Z_IS_447U_EQ_447U(...) \, +#define Z_IS_448_EQ_448(...) \, +#define Z_IS_448U_EQ_448(...) \, +#define Z_IS_448_EQ_448U(...) \, +#define Z_IS_448U_EQ_448U(...) \, +#define Z_IS_449_EQ_449(...) \, +#define Z_IS_449U_EQ_449(...) \, +#define Z_IS_449_EQ_449U(...) \, +#define Z_IS_449U_EQ_449U(...) \, +#define Z_IS_450_EQ_450(...) \, +#define Z_IS_450U_EQ_450(...) \, +#define Z_IS_450_EQ_450U(...) \, +#define Z_IS_450U_EQ_450U(...) \, +#define Z_IS_451_EQ_451(...) \, +#define Z_IS_451U_EQ_451(...) \, +#define Z_IS_451_EQ_451U(...) \, +#define Z_IS_451U_EQ_451U(...) \, +#define Z_IS_452_EQ_452(...) \, +#define Z_IS_452U_EQ_452(...) \, +#define Z_IS_452_EQ_452U(...) \, +#define Z_IS_452U_EQ_452U(...) \, +#define Z_IS_453_EQ_453(...) \, +#define Z_IS_453U_EQ_453(...) \, +#define Z_IS_453_EQ_453U(...) \, +#define Z_IS_453U_EQ_453U(...) \, +#define Z_IS_454_EQ_454(...) \, +#define Z_IS_454U_EQ_454(...) \, +#define Z_IS_454_EQ_454U(...) \, +#define Z_IS_454U_EQ_454U(...) \, +#define Z_IS_455_EQ_455(...) \, +#define Z_IS_455U_EQ_455(...) \, +#define Z_IS_455_EQ_455U(...) \, +#define Z_IS_455U_EQ_455U(...) \, +#define Z_IS_456_EQ_456(...) \, +#define Z_IS_456U_EQ_456(...) \, +#define Z_IS_456_EQ_456U(...) \, +#define Z_IS_456U_EQ_456U(...) \, +#define Z_IS_457_EQ_457(...) \, +#define Z_IS_457U_EQ_457(...) \, +#define Z_IS_457_EQ_457U(...) \, +#define Z_IS_457U_EQ_457U(...) \, +#define Z_IS_458_EQ_458(...) \, +#define Z_IS_458U_EQ_458(...) \, +#define Z_IS_458_EQ_458U(...) \, +#define Z_IS_458U_EQ_458U(...) \, +#define Z_IS_459_EQ_459(...) \, +#define Z_IS_459U_EQ_459(...) \, +#define Z_IS_459_EQ_459U(...) \, +#define Z_IS_459U_EQ_459U(...) \, +#define Z_IS_460_EQ_460(...) \, +#define Z_IS_460U_EQ_460(...) \, +#define Z_IS_460_EQ_460U(...) \, +#define Z_IS_460U_EQ_460U(...) \, +#define Z_IS_461_EQ_461(...) \, +#define Z_IS_461U_EQ_461(...) \, +#define Z_IS_461_EQ_461U(...) \, +#define Z_IS_461U_EQ_461U(...) \, +#define Z_IS_462_EQ_462(...) \, +#define Z_IS_462U_EQ_462(...) \, +#define Z_IS_462_EQ_462U(...) \, +#define Z_IS_462U_EQ_462U(...) \, +#define Z_IS_463_EQ_463(...) \, +#define Z_IS_463U_EQ_463(...) \, +#define Z_IS_463_EQ_463U(...) \, +#define Z_IS_463U_EQ_463U(...) \, +#define Z_IS_464_EQ_464(...) \, +#define Z_IS_464U_EQ_464(...) \, +#define Z_IS_464_EQ_464U(...) \, +#define Z_IS_464U_EQ_464U(...) \, +#define Z_IS_465_EQ_465(...) \, +#define Z_IS_465U_EQ_465(...) \, +#define Z_IS_465_EQ_465U(...) \, +#define Z_IS_465U_EQ_465U(...) \, +#define Z_IS_466_EQ_466(...) \, +#define Z_IS_466U_EQ_466(...) \, +#define Z_IS_466_EQ_466U(...) \, +#define Z_IS_466U_EQ_466U(...) \, +#define Z_IS_467_EQ_467(...) \, +#define Z_IS_467U_EQ_467(...) \, +#define Z_IS_467_EQ_467U(...) \, +#define Z_IS_467U_EQ_467U(...) \, +#define Z_IS_468_EQ_468(...) \, +#define Z_IS_468U_EQ_468(...) \, +#define Z_IS_468_EQ_468U(...) \, +#define Z_IS_468U_EQ_468U(...) \, +#define Z_IS_469_EQ_469(...) \, +#define Z_IS_469U_EQ_469(...) \, +#define Z_IS_469_EQ_469U(...) \, +#define Z_IS_469U_EQ_469U(...) \, +#define Z_IS_470_EQ_470(...) \, +#define Z_IS_470U_EQ_470(...) \, +#define Z_IS_470_EQ_470U(...) \, +#define Z_IS_470U_EQ_470U(...) \, +#define Z_IS_471_EQ_471(...) \, +#define Z_IS_471U_EQ_471(...) \, +#define Z_IS_471_EQ_471U(...) \, +#define Z_IS_471U_EQ_471U(...) \, +#define Z_IS_472_EQ_472(...) \, +#define Z_IS_472U_EQ_472(...) \, +#define Z_IS_472_EQ_472U(...) \, +#define Z_IS_472U_EQ_472U(...) \, +#define Z_IS_473_EQ_473(...) \, +#define Z_IS_473U_EQ_473(...) \, +#define Z_IS_473_EQ_473U(...) \, +#define Z_IS_473U_EQ_473U(...) \, +#define Z_IS_474_EQ_474(...) \, +#define Z_IS_474U_EQ_474(...) \, +#define Z_IS_474_EQ_474U(...) \, +#define Z_IS_474U_EQ_474U(...) \, +#define Z_IS_475_EQ_475(...) \, +#define Z_IS_475U_EQ_475(...) \, +#define Z_IS_475_EQ_475U(...) \, +#define Z_IS_475U_EQ_475U(...) \, +#define Z_IS_476_EQ_476(...) \, +#define Z_IS_476U_EQ_476(...) \, +#define Z_IS_476_EQ_476U(...) \, +#define Z_IS_476U_EQ_476U(...) \, +#define Z_IS_477_EQ_477(...) \, +#define Z_IS_477U_EQ_477(...) \, +#define Z_IS_477_EQ_477U(...) \, +#define Z_IS_477U_EQ_477U(...) \, +#define Z_IS_478_EQ_478(...) \, +#define Z_IS_478U_EQ_478(...) \, +#define Z_IS_478_EQ_478U(...) \, +#define Z_IS_478U_EQ_478U(...) \, +#define Z_IS_479_EQ_479(...) \, +#define Z_IS_479U_EQ_479(...) \, +#define Z_IS_479_EQ_479U(...) \, +#define Z_IS_479U_EQ_479U(...) \, +#define Z_IS_480_EQ_480(...) \, +#define Z_IS_480U_EQ_480(...) \, +#define Z_IS_480_EQ_480U(...) \, +#define Z_IS_480U_EQ_480U(...) \, +#define Z_IS_481_EQ_481(...) \, +#define Z_IS_481U_EQ_481(...) \, +#define Z_IS_481_EQ_481U(...) \, +#define Z_IS_481U_EQ_481U(...) \, +#define Z_IS_482_EQ_482(...) \, +#define Z_IS_482U_EQ_482(...) \, +#define Z_IS_482_EQ_482U(...) \, +#define Z_IS_482U_EQ_482U(...) \, +#define Z_IS_483_EQ_483(...) \, +#define Z_IS_483U_EQ_483(...) \, +#define Z_IS_483_EQ_483U(...) \, +#define Z_IS_483U_EQ_483U(...) \, +#define Z_IS_484_EQ_484(...) \, +#define Z_IS_484U_EQ_484(...) \, +#define Z_IS_484_EQ_484U(...) \, +#define Z_IS_484U_EQ_484U(...) \, +#define Z_IS_485_EQ_485(...) \, +#define Z_IS_485U_EQ_485(...) \, +#define Z_IS_485_EQ_485U(...) \, +#define Z_IS_485U_EQ_485U(...) \, +#define Z_IS_486_EQ_486(...) \, +#define Z_IS_486U_EQ_486(...) \, +#define Z_IS_486_EQ_486U(...) \, +#define Z_IS_486U_EQ_486U(...) \, +#define Z_IS_487_EQ_487(...) \, +#define Z_IS_487U_EQ_487(...) \, +#define Z_IS_487_EQ_487U(...) \, +#define Z_IS_487U_EQ_487U(...) \, +#define Z_IS_488_EQ_488(...) \, +#define Z_IS_488U_EQ_488(...) \, +#define Z_IS_488_EQ_488U(...) \, +#define Z_IS_488U_EQ_488U(...) \, +#define Z_IS_489_EQ_489(...) \, +#define Z_IS_489U_EQ_489(...) \, +#define Z_IS_489_EQ_489U(...) \, +#define Z_IS_489U_EQ_489U(...) \, +#define Z_IS_490_EQ_490(...) \, +#define Z_IS_490U_EQ_490(...) \, +#define Z_IS_490_EQ_490U(...) \, +#define Z_IS_490U_EQ_490U(...) \, +#define Z_IS_491_EQ_491(...) \, +#define Z_IS_491U_EQ_491(...) \, +#define Z_IS_491_EQ_491U(...) \, +#define Z_IS_491U_EQ_491U(...) \, +#define Z_IS_492_EQ_492(...) \, +#define Z_IS_492U_EQ_492(...) \, +#define Z_IS_492_EQ_492U(...) \, +#define Z_IS_492U_EQ_492U(...) \, +#define Z_IS_493_EQ_493(...) \, +#define Z_IS_493U_EQ_493(...) \, +#define Z_IS_493_EQ_493U(...) \, +#define Z_IS_493U_EQ_493U(...) \, +#define Z_IS_494_EQ_494(...) \, +#define Z_IS_494U_EQ_494(...) \, +#define Z_IS_494_EQ_494U(...) \, +#define Z_IS_494U_EQ_494U(...) \, +#define Z_IS_495_EQ_495(...) \, +#define Z_IS_495U_EQ_495(...) \, +#define Z_IS_495_EQ_495U(...) \, +#define Z_IS_495U_EQ_495U(...) \, +#define Z_IS_496_EQ_496(...) \, +#define Z_IS_496U_EQ_496(...) \, +#define Z_IS_496_EQ_496U(...) \, +#define Z_IS_496U_EQ_496U(...) \, +#define Z_IS_497_EQ_497(...) \, +#define Z_IS_497U_EQ_497(...) \, +#define Z_IS_497_EQ_497U(...) \, +#define Z_IS_497U_EQ_497U(...) \, +#define Z_IS_498_EQ_498(...) \, +#define Z_IS_498U_EQ_498(...) \, +#define Z_IS_498_EQ_498U(...) \, +#define Z_IS_498U_EQ_498U(...) \, +#define Z_IS_499_EQ_499(...) \, +#define Z_IS_499U_EQ_499(...) \, +#define Z_IS_499_EQ_499U(...) \, +#define Z_IS_499U_EQ_499U(...) \, +#define Z_IS_500_EQ_500(...) \, +#define Z_IS_500U_EQ_500(...) \, +#define Z_IS_500_EQ_500U(...) \, +#define Z_IS_500U_EQ_500U(...) \, +#define Z_IS_501_EQ_501(...) \, +#define Z_IS_501U_EQ_501(...) \, +#define Z_IS_501_EQ_501U(...) \, +#define Z_IS_501U_EQ_501U(...) \, +#define Z_IS_502_EQ_502(...) \, +#define Z_IS_502U_EQ_502(...) \, +#define Z_IS_502_EQ_502U(...) \, +#define Z_IS_502U_EQ_502U(...) \, +#define Z_IS_503_EQ_503(...) \, +#define Z_IS_503U_EQ_503(...) \, +#define Z_IS_503_EQ_503U(...) \, +#define Z_IS_503U_EQ_503U(...) \, +#define Z_IS_504_EQ_504(...) \, +#define Z_IS_504U_EQ_504(...) \, +#define Z_IS_504_EQ_504U(...) \, +#define Z_IS_504U_EQ_504U(...) \, +#define Z_IS_505_EQ_505(...) \, +#define Z_IS_505U_EQ_505(...) \, +#define Z_IS_505_EQ_505U(...) \, +#define Z_IS_505U_EQ_505U(...) \, +#define Z_IS_506_EQ_506(...) \, +#define Z_IS_506U_EQ_506(...) \, +#define Z_IS_506_EQ_506U(...) \, +#define Z_IS_506U_EQ_506U(...) \, +#define Z_IS_507_EQ_507(...) \, +#define Z_IS_507U_EQ_507(...) \, +#define Z_IS_507_EQ_507U(...) \, +#define Z_IS_507U_EQ_507U(...) \, +#define Z_IS_508_EQ_508(...) \, +#define Z_IS_508U_EQ_508(...) \, +#define Z_IS_508_EQ_508U(...) \, +#define Z_IS_508U_EQ_508U(...) \, +#define Z_IS_509_EQ_509(...) \, +#define Z_IS_509U_EQ_509(...) \, +#define Z_IS_509_EQ_509U(...) \, +#define Z_IS_509U_EQ_509U(...) \, +#define Z_IS_510_EQ_510(...) \, +#define Z_IS_510U_EQ_510(...) \, +#define Z_IS_510_EQ_510U(...) \, +#define Z_IS_510U_EQ_510U(...) \, +#define Z_IS_511_EQ_511(...) \, +#define Z_IS_511U_EQ_511(...) \, +#define Z_IS_511_EQ_511U(...) \, +#define Z_IS_511U_EQ_511U(...) \, +#define Z_IS_512_EQ_512(...) \, +#define Z_IS_512U_EQ_512(...) \, +#define Z_IS_512_EQ_512U(...) \, +#define Z_IS_512U_EQ_512U(...) \, +#define Z_IS_513_EQ_513(...) \, +#define Z_IS_513U_EQ_513(...) \, +#define Z_IS_513_EQ_513U(...) \, +#define Z_IS_513U_EQ_513U(...) \, +#define Z_IS_514_EQ_514(...) \, +#define Z_IS_514U_EQ_514(...) \, +#define Z_IS_514_EQ_514U(...) \, +#define Z_IS_514U_EQ_514U(...) \, +#define Z_IS_515_EQ_515(...) \, +#define Z_IS_515U_EQ_515(...) \, +#define Z_IS_515_EQ_515U(...) \, +#define Z_IS_515U_EQ_515U(...) \, +#define Z_IS_516_EQ_516(...) \, +#define Z_IS_516U_EQ_516(...) \, +#define Z_IS_516_EQ_516U(...) \, +#define Z_IS_516U_EQ_516U(...) \, +#define Z_IS_517_EQ_517(...) \, +#define Z_IS_517U_EQ_517(...) \, +#define Z_IS_517_EQ_517U(...) \, +#define Z_IS_517U_EQ_517U(...) \, +#define Z_IS_518_EQ_518(...) \, +#define Z_IS_518U_EQ_518(...) \, +#define Z_IS_518_EQ_518U(...) \, +#define Z_IS_518U_EQ_518U(...) \, +#define Z_IS_519_EQ_519(...) \, +#define Z_IS_519U_EQ_519(...) \, +#define Z_IS_519_EQ_519U(...) \, +#define Z_IS_519U_EQ_519U(...) \, +#define Z_IS_520_EQ_520(...) \, +#define Z_IS_520U_EQ_520(...) \, +#define Z_IS_520_EQ_520U(...) \, +#define Z_IS_520U_EQ_520U(...) \, +#define Z_IS_521_EQ_521(...) \, +#define Z_IS_521U_EQ_521(...) \, +#define Z_IS_521_EQ_521U(...) \, +#define Z_IS_521U_EQ_521U(...) \, +#define Z_IS_522_EQ_522(...) \, +#define Z_IS_522U_EQ_522(...) \, +#define Z_IS_522_EQ_522U(...) \, +#define Z_IS_522U_EQ_522U(...) \, +#define Z_IS_523_EQ_523(...) \, +#define Z_IS_523U_EQ_523(...) \, +#define Z_IS_523_EQ_523U(...) \, +#define Z_IS_523U_EQ_523U(...) \, +#define Z_IS_524_EQ_524(...) \, +#define Z_IS_524U_EQ_524(...) \, +#define Z_IS_524_EQ_524U(...) \, +#define Z_IS_524U_EQ_524U(...) \, +#define Z_IS_525_EQ_525(...) \, +#define Z_IS_525U_EQ_525(...) \, +#define Z_IS_525_EQ_525U(...) \, +#define Z_IS_525U_EQ_525U(...) \, +#define Z_IS_526_EQ_526(...) \, +#define Z_IS_526U_EQ_526(...) \, +#define Z_IS_526_EQ_526U(...) \, +#define Z_IS_526U_EQ_526U(...) \, +#define Z_IS_527_EQ_527(...) \, +#define Z_IS_527U_EQ_527(...) \, +#define Z_IS_527_EQ_527U(...) \, +#define Z_IS_527U_EQ_527U(...) \, +#define Z_IS_528_EQ_528(...) \, +#define Z_IS_528U_EQ_528(...) \, +#define Z_IS_528_EQ_528U(...) \, +#define Z_IS_528U_EQ_528U(...) \, +#define Z_IS_529_EQ_529(...) \, +#define Z_IS_529U_EQ_529(...) \, +#define Z_IS_529_EQ_529U(...) \, +#define Z_IS_529U_EQ_529U(...) \, +#define Z_IS_530_EQ_530(...) \, +#define Z_IS_530U_EQ_530(...) \, +#define Z_IS_530_EQ_530U(...) \, +#define Z_IS_530U_EQ_530U(...) \, +#define Z_IS_531_EQ_531(...) \, +#define Z_IS_531U_EQ_531(...) \, +#define Z_IS_531_EQ_531U(...) \, +#define Z_IS_531U_EQ_531U(...) \, +#define Z_IS_532_EQ_532(...) \, +#define Z_IS_532U_EQ_532(...) \, +#define Z_IS_532_EQ_532U(...) \, +#define Z_IS_532U_EQ_532U(...) \, +#define Z_IS_533_EQ_533(...) \, +#define Z_IS_533U_EQ_533(...) \, +#define Z_IS_533_EQ_533U(...) \, +#define Z_IS_533U_EQ_533U(...) \, +#define Z_IS_534_EQ_534(...) \, +#define Z_IS_534U_EQ_534(...) \, +#define Z_IS_534_EQ_534U(...) \, +#define Z_IS_534U_EQ_534U(...) \, +#define Z_IS_535_EQ_535(...) \, +#define Z_IS_535U_EQ_535(...) \, +#define Z_IS_535_EQ_535U(...) \, +#define Z_IS_535U_EQ_535U(...) \, +#define Z_IS_536_EQ_536(...) \, +#define Z_IS_536U_EQ_536(...) \, +#define Z_IS_536_EQ_536U(...) \, +#define Z_IS_536U_EQ_536U(...) \, +#define Z_IS_537_EQ_537(...) \, +#define Z_IS_537U_EQ_537(...) \, +#define Z_IS_537_EQ_537U(...) \, +#define Z_IS_537U_EQ_537U(...) \, +#define Z_IS_538_EQ_538(...) \, +#define Z_IS_538U_EQ_538(...) \, +#define Z_IS_538_EQ_538U(...) \, +#define Z_IS_538U_EQ_538U(...) \, +#define Z_IS_539_EQ_539(...) \, +#define Z_IS_539U_EQ_539(...) \, +#define Z_IS_539_EQ_539U(...) \, +#define Z_IS_539U_EQ_539U(...) \, +#define Z_IS_540_EQ_540(...) \, +#define Z_IS_540U_EQ_540(...) \, +#define Z_IS_540_EQ_540U(...) \, +#define Z_IS_540U_EQ_540U(...) \, +#define Z_IS_541_EQ_541(...) \, +#define Z_IS_541U_EQ_541(...) \, +#define Z_IS_541_EQ_541U(...) \, +#define Z_IS_541U_EQ_541U(...) \, +#define Z_IS_542_EQ_542(...) \, +#define Z_IS_542U_EQ_542(...) \, +#define Z_IS_542_EQ_542U(...) \, +#define Z_IS_542U_EQ_542U(...) \, +#define Z_IS_543_EQ_543(...) \, +#define Z_IS_543U_EQ_543(...) \, +#define Z_IS_543_EQ_543U(...) \, +#define Z_IS_543U_EQ_543U(...) \, +#define Z_IS_544_EQ_544(...) \, +#define Z_IS_544U_EQ_544(...) \, +#define Z_IS_544_EQ_544U(...) \, +#define Z_IS_544U_EQ_544U(...) \, +#define Z_IS_545_EQ_545(...) \, +#define Z_IS_545U_EQ_545(...) \, +#define Z_IS_545_EQ_545U(...) \, +#define Z_IS_545U_EQ_545U(...) \, +#define Z_IS_546_EQ_546(...) \, +#define Z_IS_546U_EQ_546(...) \, +#define Z_IS_546_EQ_546U(...) \, +#define Z_IS_546U_EQ_546U(...) \, +#define Z_IS_547_EQ_547(...) \, +#define Z_IS_547U_EQ_547(...) \, +#define Z_IS_547_EQ_547U(...) \, +#define Z_IS_547U_EQ_547U(...) \, +#define Z_IS_548_EQ_548(...) \, +#define Z_IS_548U_EQ_548(...) \, +#define Z_IS_548_EQ_548U(...) \, +#define Z_IS_548U_EQ_548U(...) \, +#define Z_IS_549_EQ_549(...) \, +#define Z_IS_549U_EQ_549(...) \, +#define Z_IS_549_EQ_549U(...) \, +#define Z_IS_549U_EQ_549U(...) \, +#define Z_IS_550_EQ_550(...) \, +#define Z_IS_550U_EQ_550(...) \, +#define Z_IS_550_EQ_550U(...) \, +#define Z_IS_550U_EQ_550U(...) \, +#define Z_IS_551_EQ_551(...) \, +#define Z_IS_551U_EQ_551(...) \, +#define Z_IS_551_EQ_551U(...) \, +#define Z_IS_551U_EQ_551U(...) \, +#define Z_IS_552_EQ_552(...) \, +#define Z_IS_552U_EQ_552(...) \, +#define Z_IS_552_EQ_552U(...) \, +#define Z_IS_552U_EQ_552U(...) \, +#define Z_IS_553_EQ_553(...) \, +#define Z_IS_553U_EQ_553(...) \, +#define Z_IS_553_EQ_553U(...) \, +#define Z_IS_553U_EQ_553U(...) \, +#define Z_IS_554_EQ_554(...) \, +#define Z_IS_554U_EQ_554(...) \, +#define Z_IS_554_EQ_554U(...) \, +#define Z_IS_554U_EQ_554U(...) \, +#define Z_IS_555_EQ_555(...) \, +#define Z_IS_555U_EQ_555(...) \, +#define Z_IS_555_EQ_555U(...) \, +#define Z_IS_555U_EQ_555U(...) \, +#define Z_IS_556_EQ_556(...) \, +#define Z_IS_556U_EQ_556(...) \, +#define Z_IS_556_EQ_556U(...) \, +#define Z_IS_556U_EQ_556U(...) \, +#define Z_IS_557_EQ_557(...) \, +#define Z_IS_557U_EQ_557(...) \, +#define Z_IS_557_EQ_557U(...) \, +#define Z_IS_557U_EQ_557U(...) \, +#define Z_IS_558_EQ_558(...) \, +#define Z_IS_558U_EQ_558(...) \, +#define Z_IS_558_EQ_558U(...) \, +#define Z_IS_558U_EQ_558U(...) \, +#define Z_IS_559_EQ_559(...) \, +#define Z_IS_559U_EQ_559(...) \, +#define Z_IS_559_EQ_559U(...) \, +#define Z_IS_559U_EQ_559U(...) \, +#define Z_IS_560_EQ_560(...) \, +#define Z_IS_560U_EQ_560(...) \, +#define Z_IS_560_EQ_560U(...) \, +#define Z_IS_560U_EQ_560U(...) \, +#define Z_IS_561_EQ_561(...) \, +#define Z_IS_561U_EQ_561(...) \, +#define Z_IS_561_EQ_561U(...) \, +#define Z_IS_561U_EQ_561U(...) \, +#define Z_IS_562_EQ_562(...) \, +#define Z_IS_562U_EQ_562(...) \, +#define Z_IS_562_EQ_562U(...) \, +#define Z_IS_562U_EQ_562U(...) \, +#define Z_IS_563_EQ_563(...) \, +#define Z_IS_563U_EQ_563(...) \, +#define Z_IS_563_EQ_563U(...) \, +#define Z_IS_563U_EQ_563U(...) \, +#define Z_IS_564_EQ_564(...) \, +#define Z_IS_564U_EQ_564(...) \, +#define Z_IS_564_EQ_564U(...) \, +#define Z_IS_564U_EQ_564U(...) \, +#define Z_IS_565_EQ_565(...) \, +#define Z_IS_565U_EQ_565(...) \, +#define Z_IS_565_EQ_565U(...) \, +#define Z_IS_565U_EQ_565U(...) \, +#define Z_IS_566_EQ_566(...) \, +#define Z_IS_566U_EQ_566(...) \, +#define Z_IS_566_EQ_566U(...) \, +#define Z_IS_566U_EQ_566U(...) \, +#define Z_IS_567_EQ_567(...) \, +#define Z_IS_567U_EQ_567(...) \, +#define Z_IS_567_EQ_567U(...) \, +#define Z_IS_567U_EQ_567U(...) \, +#define Z_IS_568_EQ_568(...) \, +#define Z_IS_568U_EQ_568(...) \, +#define Z_IS_568_EQ_568U(...) \, +#define Z_IS_568U_EQ_568U(...) \, +#define Z_IS_569_EQ_569(...) \, +#define Z_IS_569U_EQ_569(...) \, +#define Z_IS_569_EQ_569U(...) \, +#define Z_IS_569U_EQ_569U(...) \, +#define Z_IS_570_EQ_570(...) \, +#define Z_IS_570U_EQ_570(...) \, +#define Z_IS_570_EQ_570U(...) \, +#define Z_IS_570U_EQ_570U(...) \, +#define Z_IS_571_EQ_571(...) \, +#define Z_IS_571U_EQ_571(...) \, +#define Z_IS_571_EQ_571U(...) \, +#define Z_IS_571U_EQ_571U(...) \, +#define Z_IS_572_EQ_572(...) \, +#define Z_IS_572U_EQ_572(...) \, +#define Z_IS_572_EQ_572U(...) \, +#define Z_IS_572U_EQ_572U(...) \, +#define Z_IS_573_EQ_573(...) \, +#define Z_IS_573U_EQ_573(...) \, +#define Z_IS_573_EQ_573U(...) \, +#define Z_IS_573U_EQ_573U(...) \, +#define Z_IS_574_EQ_574(...) \, +#define Z_IS_574U_EQ_574(...) \, +#define Z_IS_574_EQ_574U(...) \, +#define Z_IS_574U_EQ_574U(...) \, +#define Z_IS_575_EQ_575(...) \, +#define Z_IS_575U_EQ_575(...) \, +#define Z_IS_575_EQ_575U(...) \, +#define Z_IS_575U_EQ_575U(...) \, +#define Z_IS_576_EQ_576(...) \, +#define Z_IS_576U_EQ_576(...) \, +#define Z_IS_576_EQ_576U(...) \, +#define Z_IS_576U_EQ_576U(...) \, +#define Z_IS_577_EQ_577(...) \, +#define Z_IS_577U_EQ_577(...) \, +#define Z_IS_577_EQ_577U(...) \, +#define Z_IS_577U_EQ_577U(...) \, +#define Z_IS_578_EQ_578(...) \, +#define Z_IS_578U_EQ_578(...) \, +#define Z_IS_578_EQ_578U(...) \, +#define Z_IS_578U_EQ_578U(...) \, +#define Z_IS_579_EQ_579(...) \, +#define Z_IS_579U_EQ_579(...) \, +#define Z_IS_579_EQ_579U(...) \, +#define Z_IS_579U_EQ_579U(...) \, +#define Z_IS_580_EQ_580(...) \, +#define Z_IS_580U_EQ_580(...) \, +#define Z_IS_580_EQ_580U(...) \, +#define Z_IS_580U_EQ_580U(...) \, +#define Z_IS_581_EQ_581(...) \, +#define Z_IS_581U_EQ_581(...) \, +#define Z_IS_581_EQ_581U(...) \, +#define Z_IS_581U_EQ_581U(...) \, +#define Z_IS_582_EQ_582(...) \, +#define Z_IS_582U_EQ_582(...) \, +#define Z_IS_582_EQ_582U(...) \, +#define Z_IS_582U_EQ_582U(...) \, +#define Z_IS_583_EQ_583(...) \, +#define Z_IS_583U_EQ_583(...) \, +#define Z_IS_583_EQ_583U(...) \, +#define Z_IS_583U_EQ_583U(...) \, +#define Z_IS_584_EQ_584(...) \, +#define Z_IS_584U_EQ_584(...) \, +#define Z_IS_584_EQ_584U(...) \, +#define Z_IS_584U_EQ_584U(...) \, +#define Z_IS_585_EQ_585(...) \, +#define Z_IS_585U_EQ_585(...) \, +#define Z_IS_585_EQ_585U(...) \, +#define Z_IS_585U_EQ_585U(...) \, +#define Z_IS_586_EQ_586(...) \, +#define Z_IS_586U_EQ_586(...) \, +#define Z_IS_586_EQ_586U(...) \, +#define Z_IS_586U_EQ_586U(...) \, +#define Z_IS_587_EQ_587(...) \, +#define Z_IS_587U_EQ_587(...) \, +#define Z_IS_587_EQ_587U(...) \, +#define Z_IS_587U_EQ_587U(...) \, +#define Z_IS_588_EQ_588(...) \, +#define Z_IS_588U_EQ_588(...) \, +#define Z_IS_588_EQ_588U(...) \, +#define Z_IS_588U_EQ_588U(...) \, +#define Z_IS_589_EQ_589(...) \, +#define Z_IS_589U_EQ_589(...) \, +#define Z_IS_589_EQ_589U(...) \, +#define Z_IS_589U_EQ_589U(...) \, +#define Z_IS_590_EQ_590(...) \, +#define Z_IS_590U_EQ_590(...) \, +#define Z_IS_590_EQ_590U(...) \, +#define Z_IS_590U_EQ_590U(...) \, +#define Z_IS_591_EQ_591(...) \, +#define Z_IS_591U_EQ_591(...) \, +#define Z_IS_591_EQ_591U(...) \, +#define Z_IS_591U_EQ_591U(...) \, +#define Z_IS_592_EQ_592(...) \, +#define Z_IS_592U_EQ_592(...) \, +#define Z_IS_592_EQ_592U(...) \, +#define Z_IS_592U_EQ_592U(...) \, +#define Z_IS_593_EQ_593(...) \, +#define Z_IS_593U_EQ_593(...) \, +#define Z_IS_593_EQ_593U(...) \, +#define Z_IS_593U_EQ_593U(...) \, +#define Z_IS_594_EQ_594(...) \, +#define Z_IS_594U_EQ_594(...) \, +#define Z_IS_594_EQ_594U(...) \, +#define Z_IS_594U_EQ_594U(...) \, +#define Z_IS_595_EQ_595(...) \, +#define Z_IS_595U_EQ_595(...) \, +#define Z_IS_595_EQ_595U(...) \, +#define Z_IS_595U_EQ_595U(...) \, +#define Z_IS_596_EQ_596(...) \, +#define Z_IS_596U_EQ_596(...) \, +#define Z_IS_596_EQ_596U(...) \, +#define Z_IS_596U_EQ_596U(...) \, +#define Z_IS_597_EQ_597(...) \, +#define Z_IS_597U_EQ_597(...) \, +#define Z_IS_597_EQ_597U(...) \, +#define Z_IS_597U_EQ_597U(...) \, +#define Z_IS_598_EQ_598(...) \, +#define Z_IS_598U_EQ_598(...) \, +#define Z_IS_598_EQ_598U(...) \, +#define Z_IS_598U_EQ_598U(...) \, +#define Z_IS_599_EQ_599(...) \, +#define Z_IS_599U_EQ_599(...) \, +#define Z_IS_599_EQ_599U(...) \, +#define Z_IS_599U_EQ_599U(...) \, +#define Z_IS_600_EQ_600(...) \, +#define Z_IS_600U_EQ_600(...) \, +#define Z_IS_600_EQ_600U(...) \, +#define Z_IS_600U_EQ_600U(...) \, +#define Z_IS_601_EQ_601(...) \, +#define Z_IS_601U_EQ_601(...) \, +#define Z_IS_601_EQ_601U(...) \, +#define Z_IS_601U_EQ_601U(...) \, +#define Z_IS_602_EQ_602(...) \, +#define Z_IS_602U_EQ_602(...) \, +#define Z_IS_602_EQ_602U(...) \, +#define Z_IS_602U_EQ_602U(...) \, +#define Z_IS_603_EQ_603(...) \, +#define Z_IS_603U_EQ_603(...) \, +#define Z_IS_603_EQ_603U(...) \, +#define Z_IS_603U_EQ_603U(...) \, +#define Z_IS_604_EQ_604(...) \, +#define Z_IS_604U_EQ_604(...) \, +#define Z_IS_604_EQ_604U(...) \, +#define Z_IS_604U_EQ_604U(...) \, +#define Z_IS_605_EQ_605(...) \, +#define Z_IS_605U_EQ_605(...) \, +#define Z_IS_605_EQ_605U(...) \, +#define Z_IS_605U_EQ_605U(...) \, +#define Z_IS_606_EQ_606(...) \, +#define Z_IS_606U_EQ_606(...) \, +#define Z_IS_606_EQ_606U(...) \, +#define Z_IS_606U_EQ_606U(...) \, +#define Z_IS_607_EQ_607(...) \, +#define Z_IS_607U_EQ_607(...) \, +#define Z_IS_607_EQ_607U(...) \, +#define Z_IS_607U_EQ_607U(...) \, +#define Z_IS_608_EQ_608(...) \, +#define Z_IS_608U_EQ_608(...) \, +#define Z_IS_608_EQ_608U(...) \, +#define Z_IS_608U_EQ_608U(...) \, +#define Z_IS_609_EQ_609(...) \, +#define Z_IS_609U_EQ_609(...) \, +#define Z_IS_609_EQ_609U(...) \, +#define Z_IS_609U_EQ_609U(...) \, +#define Z_IS_610_EQ_610(...) \, +#define Z_IS_610U_EQ_610(...) \, +#define Z_IS_610_EQ_610U(...) \, +#define Z_IS_610U_EQ_610U(...) \, +#define Z_IS_611_EQ_611(...) \, +#define Z_IS_611U_EQ_611(...) \, +#define Z_IS_611_EQ_611U(...) \, +#define Z_IS_611U_EQ_611U(...) \, +#define Z_IS_612_EQ_612(...) \, +#define Z_IS_612U_EQ_612(...) \, +#define Z_IS_612_EQ_612U(...) \, +#define Z_IS_612U_EQ_612U(...) \, +#define Z_IS_613_EQ_613(...) \, +#define Z_IS_613U_EQ_613(...) \, +#define Z_IS_613_EQ_613U(...) \, +#define Z_IS_613U_EQ_613U(...) \, +#define Z_IS_614_EQ_614(...) \, +#define Z_IS_614U_EQ_614(...) \, +#define Z_IS_614_EQ_614U(...) \, +#define Z_IS_614U_EQ_614U(...) \, +#define Z_IS_615_EQ_615(...) \, +#define Z_IS_615U_EQ_615(...) \, +#define Z_IS_615_EQ_615U(...) \, +#define Z_IS_615U_EQ_615U(...) \, +#define Z_IS_616_EQ_616(...) \, +#define Z_IS_616U_EQ_616(...) \, +#define Z_IS_616_EQ_616U(...) \, +#define Z_IS_616U_EQ_616U(...) \, +#define Z_IS_617_EQ_617(...) \, +#define Z_IS_617U_EQ_617(...) \, +#define Z_IS_617_EQ_617U(...) \, +#define Z_IS_617U_EQ_617U(...) \, +#define Z_IS_618_EQ_618(...) \, +#define Z_IS_618U_EQ_618(...) \, +#define Z_IS_618_EQ_618U(...) \, +#define Z_IS_618U_EQ_618U(...) \, +#define Z_IS_619_EQ_619(...) \, +#define Z_IS_619U_EQ_619(...) \, +#define Z_IS_619_EQ_619U(...) \, +#define Z_IS_619U_EQ_619U(...) \, +#define Z_IS_620_EQ_620(...) \, +#define Z_IS_620U_EQ_620(...) \, +#define Z_IS_620_EQ_620U(...) \, +#define Z_IS_620U_EQ_620U(...) \, +#define Z_IS_621_EQ_621(...) \, +#define Z_IS_621U_EQ_621(...) \, +#define Z_IS_621_EQ_621U(...) \, +#define Z_IS_621U_EQ_621U(...) \, +#define Z_IS_622_EQ_622(...) \, +#define Z_IS_622U_EQ_622(...) \, +#define Z_IS_622_EQ_622U(...) \, +#define Z_IS_622U_EQ_622U(...) \, +#define Z_IS_623_EQ_623(...) \, +#define Z_IS_623U_EQ_623(...) \, +#define Z_IS_623_EQ_623U(...) \, +#define Z_IS_623U_EQ_623U(...) \, +#define Z_IS_624_EQ_624(...) \, +#define Z_IS_624U_EQ_624(...) \, +#define Z_IS_624_EQ_624U(...) \, +#define Z_IS_624U_EQ_624U(...) \, +#define Z_IS_625_EQ_625(...) \, +#define Z_IS_625U_EQ_625(...) \, +#define Z_IS_625_EQ_625U(...) \, +#define Z_IS_625U_EQ_625U(...) \, +#define Z_IS_626_EQ_626(...) \, +#define Z_IS_626U_EQ_626(...) \, +#define Z_IS_626_EQ_626U(...) \, +#define Z_IS_626U_EQ_626U(...) \, +#define Z_IS_627_EQ_627(...) \, +#define Z_IS_627U_EQ_627(...) \, +#define Z_IS_627_EQ_627U(...) \, +#define Z_IS_627U_EQ_627U(...) \, +#define Z_IS_628_EQ_628(...) \, +#define Z_IS_628U_EQ_628(...) \, +#define Z_IS_628_EQ_628U(...) \, +#define Z_IS_628U_EQ_628U(...) \, +#define Z_IS_629_EQ_629(...) \, +#define Z_IS_629U_EQ_629(...) \, +#define Z_IS_629_EQ_629U(...) \, +#define Z_IS_629U_EQ_629U(...) \, +#define Z_IS_630_EQ_630(...) \, +#define Z_IS_630U_EQ_630(...) \, +#define Z_IS_630_EQ_630U(...) \, +#define Z_IS_630U_EQ_630U(...) \, +#define Z_IS_631_EQ_631(...) \, +#define Z_IS_631U_EQ_631(...) \, +#define Z_IS_631_EQ_631U(...) \, +#define Z_IS_631U_EQ_631U(...) \, +#define Z_IS_632_EQ_632(...) \, +#define Z_IS_632U_EQ_632(...) \, +#define Z_IS_632_EQ_632U(...) \, +#define Z_IS_632U_EQ_632U(...) \, +#define Z_IS_633_EQ_633(...) \, +#define Z_IS_633U_EQ_633(...) \, +#define Z_IS_633_EQ_633U(...) \, +#define Z_IS_633U_EQ_633U(...) \, +#define Z_IS_634_EQ_634(...) \, +#define Z_IS_634U_EQ_634(...) \, +#define Z_IS_634_EQ_634U(...) \, +#define Z_IS_634U_EQ_634U(...) \, +#define Z_IS_635_EQ_635(...) \, +#define Z_IS_635U_EQ_635(...) \, +#define Z_IS_635_EQ_635U(...) \, +#define Z_IS_635U_EQ_635U(...) \, +#define Z_IS_636_EQ_636(...) \, +#define Z_IS_636U_EQ_636(...) \, +#define Z_IS_636_EQ_636U(...) \, +#define Z_IS_636U_EQ_636U(...) \, +#define Z_IS_637_EQ_637(...) \, +#define Z_IS_637U_EQ_637(...) \, +#define Z_IS_637_EQ_637U(...) \, +#define Z_IS_637U_EQ_637U(...) \, +#define Z_IS_638_EQ_638(...) \, +#define Z_IS_638U_EQ_638(...) \, +#define Z_IS_638_EQ_638U(...) \, +#define Z_IS_638U_EQ_638U(...) \, +#define Z_IS_639_EQ_639(...) \, +#define Z_IS_639U_EQ_639(...) \, +#define Z_IS_639_EQ_639U(...) \, +#define Z_IS_639U_EQ_639U(...) \, +#define Z_IS_640_EQ_640(...) \, +#define Z_IS_640U_EQ_640(...) \, +#define Z_IS_640_EQ_640U(...) \, +#define Z_IS_640U_EQ_640U(...) \, +#define Z_IS_641_EQ_641(...) \, +#define Z_IS_641U_EQ_641(...) \, +#define Z_IS_641_EQ_641U(...) \, +#define Z_IS_641U_EQ_641U(...) \, +#define Z_IS_642_EQ_642(...) \, +#define Z_IS_642U_EQ_642(...) \, +#define Z_IS_642_EQ_642U(...) \, +#define Z_IS_642U_EQ_642U(...) \, +#define Z_IS_643_EQ_643(...) \, +#define Z_IS_643U_EQ_643(...) \, +#define Z_IS_643_EQ_643U(...) \, +#define Z_IS_643U_EQ_643U(...) \, +#define Z_IS_644_EQ_644(...) \, +#define Z_IS_644U_EQ_644(...) \, +#define Z_IS_644_EQ_644U(...) \, +#define Z_IS_644U_EQ_644U(...) \, +#define Z_IS_645_EQ_645(...) \, +#define Z_IS_645U_EQ_645(...) \, +#define Z_IS_645_EQ_645U(...) \, +#define Z_IS_645U_EQ_645U(...) \, +#define Z_IS_646_EQ_646(...) \, +#define Z_IS_646U_EQ_646(...) \, +#define Z_IS_646_EQ_646U(...) \, +#define Z_IS_646U_EQ_646U(...) \, +#define Z_IS_647_EQ_647(...) \, +#define Z_IS_647U_EQ_647(...) \, +#define Z_IS_647_EQ_647U(...) \, +#define Z_IS_647U_EQ_647U(...) \, +#define Z_IS_648_EQ_648(...) \, +#define Z_IS_648U_EQ_648(...) \, +#define Z_IS_648_EQ_648U(...) \, +#define Z_IS_648U_EQ_648U(...) \, +#define Z_IS_649_EQ_649(...) \, +#define Z_IS_649U_EQ_649(...) \, +#define Z_IS_649_EQ_649U(...) \, +#define Z_IS_649U_EQ_649U(...) \, +#define Z_IS_650_EQ_650(...) \, +#define Z_IS_650U_EQ_650(...) \, +#define Z_IS_650_EQ_650U(...) \, +#define Z_IS_650U_EQ_650U(...) \, +#define Z_IS_651_EQ_651(...) \, +#define Z_IS_651U_EQ_651(...) \, +#define Z_IS_651_EQ_651U(...) \, +#define Z_IS_651U_EQ_651U(...) \, +#define Z_IS_652_EQ_652(...) \, +#define Z_IS_652U_EQ_652(...) \, +#define Z_IS_652_EQ_652U(...) \, +#define Z_IS_652U_EQ_652U(...) \, +#define Z_IS_653_EQ_653(...) \, +#define Z_IS_653U_EQ_653(...) \, +#define Z_IS_653_EQ_653U(...) \, +#define Z_IS_653U_EQ_653U(...) \, +#define Z_IS_654_EQ_654(...) \, +#define Z_IS_654U_EQ_654(...) \, +#define Z_IS_654_EQ_654U(...) \, +#define Z_IS_654U_EQ_654U(...) \, +#define Z_IS_655_EQ_655(...) \, +#define Z_IS_655U_EQ_655(...) \, +#define Z_IS_655_EQ_655U(...) \, +#define Z_IS_655U_EQ_655U(...) \, +#define Z_IS_656_EQ_656(...) \, +#define Z_IS_656U_EQ_656(...) \, +#define Z_IS_656_EQ_656U(...) \, +#define Z_IS_656U_EQ_656U(...) \, +#define Z_IS_657_EQ_657(...) \, +#define Z_IS_657U_EQ_657(...) \, +#define Z_IS_657_EQ_657U(...) \, +#define Z_IS_657U_EQ_657U(...) \, +#define Z_IS_658_EQ_658(...) \, +#define Z_IS_658U_EQ_658(...) \, +#define Z_IS_658_EQ_658U(...) \, +#define Z_IS_658U_EQ_658U(...) \, +#define Z_IS_659_EQ_659(...) \, +#define Z_IS_659U_EQ_659(...) \, +#define Z_IS_659_EQ_659U(...) \, +#define Z_IS_659U_EQ_659U(...) \, +#define Z_IS_660_EQ_660(...) \, +#define Z_IS_660U_EQ_660(...) \, +#define Z_IS_660_EQ_660U(...) \, +#define Z_IS_660U_EQ_660U(...) \, +#define Z_IS_661_EQ_661(...) \, +#define Z_IS_661U_EQ_661(...) \, +#define Z_IS_661_EQ_661U(...) \, +#define Z_IS_661U_EQ_661U(...) \, +#define Z_IS_662_EQ_662(...) \, +#define Z_IS_662U_EQ_662(...) \, +#define Z_IS_662_EQ_662U(...) \, +#define Z_IS_662U_EQ_662U(...) \, +#define Z_IS_663_EQ_663(...) \, +#define Z_IS_663U_EQ_663(...) \, +#define Z_IS_663_EQ_663U(...) \, +#define Z_IS_663U_EQ_663U(...) \, +#define Z_IS_664_EQ_664(...) \, +#define Z_IS_664U_EQ_664(...) \, +#define Z_IS_664_EQ_664U(...) \, +#define Z_IS_664U_EQ_664U(...) \, +#define Z_IS_665_EQ_665(...) \, +#define Z_IS_665U_EQ_665(...) \, +#define Z_IS_665_EQ_665U(...) \, +#define Z_IS_665U_EQ_665U(...) \, +#define Z_IS_666_EQ_666(...) \, +#define Z_IS_666U_EQ_666(...) \, +#define Z_IS_666_EQ_666U(...) \, +#define Z_IS_666U_EQ_666U(...) \, +#define Z_IS_667_EQ_667(...) \, +#define Z_IS_667U_EQ_667(...) \, +#define Z_IS_667_EQ_667U(...) \, +#define Z_IS_667U_EQ_667U(...) \, +#define Z_IS_668_EQ_668(...) \, +#define Z_IS_668U_EQ_668(...) \, +#define Z_IS_668_EQ_668U(...) \, +#define Z_IS_668U_EQ_668U(...) \, +#define Z_IS_669_EQ_669(...) \, +#define Z_IS_669U_EQ_669(...) \, +#define Z_IS_669_EQ_669U(...) \, +#define Z_IS_669U_EQ_669U(...) \, +#define Z_IS_670_EQ_670(...) \, +#define Z_IS_670U_EQ_670(...) \, +#define Z_IS_670_EQ_670U(...) \, +#define Z_IS_670U_EQ_670U(...) \, +#define Z_IS_671_EQ_671(...) \, +#define Z_IS_671U_EQ_671(...) \, +#define Z_IS_671_EQ_671U(...) \, +#define Z_IS_671U_EQ_671U(...) \, +#define Z_IS_672_EQ_672(...) \, +#define Z_IS_672U_EQ_672(...) \, +#define Z_IS_672_EQ_672U(...) \, +#define Z_IS_672U_EQ_672U(...) \, +#define Z_IS_673_EQ_673(...) \, +#define Z_IS_673U_EQ_673(...) \, +#define Z_IS_673_EQ_673U(...) \, +#define Z_IS_673U_EQ_673U(...) \, +#define Z_IS_674_EQ_674(...) \, +#define Z_IS_674U_EQ_674(...) \, +#define Z_IS_674_EQ_674U(...) \, +#define Z_IS_674U_EQ_674U(...) \, +#define Z_IS_675_EQ_675(...) \, +#define Z_IS_675U_EQ_675(...) \, +#define Z_IS_675_EQ_675U(...) \, +#define Z_IS_675U_EQ_675U(...) \, +#define Z_IS_676_EQ_676(...) \, +#define Z_IS_676U_EQ_676(...) \, +#define Z_IS_676_EQ_676U(...) \, +#define Z_IS_676U_EQ_676U(...) \, +#define Z_IS_677_EQ_677(...) \, +#define Z_IS_677U_EQ_677(...) \, +#define Z_IS_677_EQ_677U(...) \, +#define Z_IS_677U_EQ_677U(...) \, +#define Z_IS_678_EQ_678(...) \, +#define Z_IS_678U_EQ_678(...) \, +#define Z_IS_678_EQ_678U(...) \, +#define Z_IS_678U_EQ_678U(...) \, +#define Z_IS_679_EQ_679(...) \, +#define Z_IS_679U_EQ_679(...) \, +#define Z_IS_679_EQ_679U(...) \, +#define Z_IS_679U_EQ_679U(...) \, +#define Z_IS_680_EQ_680(...) \, +#define Z_IS_680U_EQ_680(...) \, +#define Z_IS_680_EQ_680U(...) \, +#define Z_IS_680U_EQ_680U(...) \, +#define Z_IS_681_EQ_681(...) \, +#define Z_IS_681U_EQ_681(...) \, +#define Z_IS_681_EQ_681U(...) \, +#define Z_IS_681U_EQ_681U(...) \, +#define Z_IS_682_EQ_682(...) \, +#define Z_IS_682U_EQ_682(...) \, +#define Z_IS_682_EQ_682U(...) \, +#define Z_IS_682U_EQ_682U(...) \, +#define Z_IS_683_EQ_683(...) \, +#define Z_IS_683U_EQ_683(...) \, +#define Z_IS_683_EQ_683U(...) \, +#define Z_IS_683U_EQ_683U(...) \, +#define Z_IS_684_EQ_684(...) \, +#define Z_IS_684U_EQ_684(...) \, +#define Z_IS_684_EQ_684U(...) \, +#define Z_IS_684U_EQ_684U(...) \, +#define Z_IS_685_EQ_685(...) \, +#define Z_IS_685U_EQ_685(...) \, +#define Z_IS_685_EQ_685U(...) \, +#define Z_IS_685U_EQ_685U(...) \, +#define Z_IS_686_EQ_686(...) \, +#define Z_IS_686U_EQ_686(...) \, +#define Z_IS_686_EQ_686U(...) \, +#define Z_IS_686U_EQ_686U(...) \, +#define Z_IS_687_EQ_687(...) \, +#define Z_IS_687U_EQ_687(...) \, +#define Z_IS_687_EQ_687U(...) \, +#define Z_IS_687U_EQ_687U(...) \, +#define Z_IS_688_EQ_688(...) \, +#define Z_IS_688U_EQ_688(...) \, +#define Z_IS_688_EQ_688U(...) \, +#define Z_IS_688U_EQ_688U(...) \, +#define Z_IS_689_EQ_689(...) \, +#define Z_IS_689U_EQ_689(...) \, +#define Z_IS_689_EQ_689U(...) \, +#define Z_IS_689U_EQ_689U(...) \, +#define Z_IS_690_EQ_690(...) \, +#define Z_IS_690U_EQ_690(...) \, +#define Z_IS_690_EQ_690U(...) \, +#define Z_IS_690U_EQ_690U(...) \, +#define Z_IS_691_EQ_691(...) \, +#define Z_IS_691U_EQ_691(...) \, +#define Z_IS_691_EQ_691U(...) \, +#define Z_IS_691U_EQ_691U(...) \, +#define Z_IS_692_EQ_692(...) \, +#define Z_IS_692U_EQ_692(...) \, +#define Z_IS_692_EQ_692U(...) \, +#define Z_IS_692U_EQ_692U(...) \, +#define Z_IS_693_EQ_693(...) \, +#define Z_IS_693U_EQ_693(...) \, +#define Z_IS_693_EQ_693U(...) \, +#define Z_IS_693U_EQ_693U(...) \, +#define Z_IS_694_EQ_694(...) \, +#define Z_IS_694U_EQ_694(...) \, +#define Z_IS_694_EQ_694U(...) \, +#define Z_IS_694U_EQ_694U(...) \, +#define Z_IS_695_EQ_695(...) \, +#define Z_IS_695U_EQ_695(...) \, +#define Z_IS_695_EQ_695U(...) \, +#define Z_IS_695U_EQ_695U(...) \, +#define Z_IS_696_EQ_696(...) \, +#define Z_IS_696U_EQ_696(...) \, +#define Z_IS_696_EQ_696U(...) \, +#define Z_IS_696U_EQ_696U(...) \, +#define Z_IS_697_EQ_697(...) \, +#define Z_IS_697U_EQ_697(...) \, +#define Z_IS_697_EQ_697U(...) \, +#define Z_IS_697U_EQ_697U(...) \, +#define Z_IS_698_EQ_698(...) \, +#define Z_IS_698U_EQ_698(...) \, +#define Z_IS_698_EQ_698U(...) \, +#define Z_IS_698U_EQ_698U(...) \, +#define Z_IS_699_EQ_699(...) \, +#define Z_IS_699U_EQ_699(...) \, +#define Z_IS_699_EQ_699U(...) \, +#define Z_IS_699U_EQ_699U(...) \, +#define Z_IS_700_EQ_700(...) \, +#define Z_IS_700U_EQ_700(...) \, +#define Z_IS_700_EQ_700U(...) \, +#define Z_IS_700U_EQ_700U(...) \, +#define Z_IS_701_EQ_701(...) \, +#define Z_IS_701U_EQ_701(...) \, +#define Z_IS_701_EQ_701U(...) \, +#define Z_IS_701U_EQ_701U(...) \, +#define Z_IS_702_EQ_702(...) \, +#define Z_IS_702U_EQ_702(...) \, +#define Z_IS_702_EQ_702U(...) \, +#define Z_IS_702U_EQ_702U(...) \, +#define Z_IS_703_EQ_703(...) \, +#define Z_IS_703U_EQ_703(...) \, +#define Z_IS_703_EQ_703U(...) \, +#define Z_IS_703U_EQ_703U(...) \, +#define Z_IS_704_EQ_704(...) \, +#define Z_IS_704U_EQ_704(...) \, +#define Z_IS_704_EQ_704U(...) \, +#define Z_IS_704U_EQ_704U(...) \, +#define Z_IS_705_EQ_705(...) \, +#define Z_IS_705U_EQ_705(...) \, +#define Z_IS_705_EQ_705U(...) \, +#define Z_IS_705U_EQ_705U(...) \, +#define Z_IS_706_EQ_706(...) \, +#define Z_IS_706U_EQ_706(...) \, +#define Z_IS_706_EQ_706U(...) \, +#define Z_IS_706U_EQ_706U(...) \, +#define Z_IS_707_EQ_707(...) \, +#define Z_IS_707U_EQ_707(...) \, +#define Z_IS_707_EQ_707U(...) \, +#define Z_IS_707U_EQ_707U(...) \, +#define Z_IS_708_EQ_708(...) \, +#define Z_IS_708U_EQ_708(...) \, +#define Z_IS_708_EQ_708U(...) \, +#define Z_IS_708U_EQ_708U(...) \, +#define Z_IS_709_EQ_709(...) \, +#define Z_IS_709U_EQ_709(...) \, +#define Z_IS_709_EQ_709U(...) \, +#define Z_IS_709U_EQ_709U(...) \, +#define Z_IS_710_EQ_710(...) \, +#define Z_IS_710U_EQ_710(...) \, +#define Z_IS_710_EQ_710U(...) \, +#define Z_IS_710U_EQ_710U(...) \, +#define Z_IS_711_EQ_711(...) \, +#define Z_IS_711U_EQ_711(...) \, +#define Z_IS_711_EQ_711U(...) \, +#define Z_IS_711U_EQ_711U(...) \, +#define Z_IS_712_EQ_712(...) \, +#define Z_IS_712U_EQ_712(...) \, +#define Z_IS_712_EQ_712U(...) \, +#define Z_IS_712U_EQ_712U(...) \, +#define Z_IS_713_EQ_713(...) \, +#define Z_IS_713U_EQ_713(...) \, +#define Z_IS_713_EQ_713U(...) \, +#define Z_IS_713U_EQ_713U(...) \, +#define Z_IS_714_EQ_714(...) \, +#define Z_IS_714U_EQ_714(...) \, +#define Z_IS_714_EQ_714U(...) \, +#define Z_IS_714U_EQ_714U(...) \, +#define Z_IS_715_EQ_715(...) \, +#define Z_IS_715U_EQ_715(...) \, +#define Z_IS_715_EQ_715U(...) \, +#define Z_IS_715U_EQ_715U(...) \, +#define Z_IS_716_EQ_716(...) \, +#define Z_IS_716U_EQ_716(...) \, +#define Z_IS_716_EQ_716U(...) \, +#define Z_IS_716U_EQ_716U(...) \, +#define Z_IS_717_EQ_717(...) \, +#define Z_IS_717U_EQ_717(...) \, +#define Z_IS_717_EQ_717U(...) \, +#define Z_IS_717U_EQ_717U(...) \, +#define Z_IS_718_EQ_718(...) \, +#define Z_IS_718U_EQ_718(...) \, +#define Z_IS_718_EQ_718U(...) \, +#define Z_IS_718U_EQ_718U(...) \, +#define Z_IS_719_EQ_719(...) \, +#define Z_IS_719U_EQ_719(...) \, +#define Z_IS_719_EQ_719U(...) \, +#define Z_IS_719U_EQ_719U(...) \, +#define Z_IS_720_EQ_720(...) \, +#define Z_IS_720U_EQ_720(...) \, +#define Z_IS_720_EQ_720U(...) \, +#define Z_IS_720U_EQ_720U(...) \, +#define Z_IS_721_EQ_721(...) \, +#define Z_IS_721U_EQ_721(...) \, +#define Z_IS_721_EQ_721U(...) \, +#define Z_IS_721U_EQ_721U(...) \, +#define Z_IS_722_EQ_722(...) \, +#define Z_IS_722U_EQ_722(...) \, +#define Z_IS_722_EQ_722U(...) \, +#define Z_IS_722U_EQ_722U(...) \, +#define Z_IS_723_EQ_723(...) \, +#define Z_IS_723U_EQ_723(...) \, +#define Z_IS_723_EQ_723U(...) \, +#define Z_IS_723U_EQ_723U(...) \, +#define Z_IS_724_EQ_724(...) \, +#define Z_IS_724U_EQ_724(...) \, +#define Z_IS_724_EQ_724U(...) \, +#define Z_IS_724U_EQ_724U(...) \, +#define Z_IS_725_EQ_725(...) \, +#define Z_IS_725U_EQ_725(...) \, +#define Z_IS_725_EQ_725U(...) \, +#define Z_IS_725U_EQ_725U(...) \, +#define Z_IS_726_EQ_726(...) \, +#define Z_IS_726U_EQ_726(...) \, +#define Z_IS_726_EQ_726U(...) \, +#define Z_IS_726U_EQ_726U(...) \, +#define Z_IS_727_EQ_727(...) \, +#define Z_IS_727U_EQ_727(...) \, +#define Z_IS_727_EQ_727U(...) \, +#define Z_IS_727U_EQ_727U(...) \, +#define Z_IS_728_EQ_728(...) \, +#define Z_IS_728U_EQ_728(...) \, +#define Z_IS_728_EQ_728U(...) \, +#define Z_IS_728U_EQ_728U(...) \, +#define Z_IS_729_EQ_729(...) \, +#define Z_IS_729U_EQ_729(...) \, +#define Z_IS_729_EQ_729U(...) \, +#define Z_IS_729U_EQ_729U(...) \, +#define Z_IS_730_EQ_730(...) \, +#define Z_IS_730U_EQ_730(...) \, +#define Z_IS_730_EQ_730U(...) \, +#define Z_IS_730U_EQ_730U(...) \, +#define Z_IS_731_EQ_731(...) \, +#define Z_IS_731U_EQ_731(...) \, +#define Z_IS_731_EQ_731U(...) \, +#define Z_IS_731U_EQ_731U(...) \, +#define Z_IS_732_EQ_732(...) \, +#define Z_IS_732U_EQ_732(...) \, +#define Z_IS_732_EQ_732U(...) \, +#define Z_IS_732U_EQ_732U(...) \, +#define Z_IS_733_EQ_733(...) \, +#define Z_IS_733U_EQ_733(...) \, +#define Z_IS_733_EQ_733U(...) \, +#define Z_IS_733U_EQ_733U(...) \, +#define Z_IS_734_EQ_734(...) \, +#define Z_IS_734U_EQ_734(...) \, +#define Z_IS_734_EQ_734U(...) \, +#define Z_IS_734U_EQ_734U(...) \, +#define Z_IS_735_EQ_735(...) \, +#define Z_IS_735U_EQ_735(...) \, +#define Z_IS_735_EQ_735U(...) \, +#define Z_IS_735U_EQ_735U(...) \, +#define Z_IS_736_EQ_736(...) \, +#define Z_IS_736U_EQ_736(...) \, +#define Z_IS_736_EQ_736U(...) \, +#define Z_IS_736U_EQ_736U(...) \, +#define Z_IS_737_EQ_737(...) \, +#define Z_IS_737U_EQ_737(...) \, +#define Z_IS_737_EQ_737U(...) \, +#define Z_IS_737U_EQ_737U(...) \, +#define Z_IS_738_EQ_738(...) \, +#define Z_IS_738U_EQ_738(...) \, +#define Z_IS_738_EQ_738U(...) \, +#define Z_IS_738U_EQ_738U(...) \, +#define Z_IS_739_EQ_739(...) \, +#define Z_IS_739U_EQ_739(...) \, +#define Z_IS_739_EQ_739U(...) \, +#define Z_IS_739U_EQ_739U(...) \, +#define Z_IS_740_EQ_740(...) \, +#define Z_IS_740U_EQ_740(...) \, +#define Z_IS_740_EQ_740U(...) \, +#define Z_IS_740U_EQ_740U(...) \, +#define Z_IS_741_EQ_741(...) \, +#define Z_IS_741U_EQ_741(...) \, +#define Z_IS_741_EQ_741U(...) \, +#define Z_IS_741U_EQ_741U(...) \, +#define Z_IS_742_EQ_742(...) \, +#define Z_IS_742U_EQ_742(...) \, +#define Z_IS_742_EQ_742U(...) \, +#define Z_IS_742U_EQ_742U(...) \, +#define Z_IS_743_EQ_743(...) \, +#define Z_IS_743U_EQ_743(...) \, +#define Z_IS_743_EQ_743U(...) \, +#define Z_IS_743U_EQ_743U(...) \, +#define Z_IS_744_EQ_744(...) \, +#define Z_IS_744U_EQ_744(...) \, +#define Z_IS_744_EQ_744U(...) \, +#define Z_IS_744U_EQ_744U(...) \, +#define Z_IS_745_EQ_745(...) \, +#define Z_IS_745U_EQ_745(...) \, +#define Z_IS_745_EQ_745U(...) \, +#define Z_IS_745U_EQ_745U(...) \, +#define Z_IS_746_EQ_746(...) \, +#define Z_IS_746U_EQ_746(...) \, +#define Z_IS_746_EQ_746U(...) \, +#define Z_IS_746U_EQ_746U(...) \, +#define Z_IS_747_EQ_747(...) \, +#define Z_IS_747U_EQ_747(...) \, +#define Z_IS_747_EQ_747U(...) \, +#define Z_IS_747U_EQ_747U(...) \, +#define Z_IS_748_EQ_748(...) \, +#define Z_IS_748U_EQ_748(...) \, +#define Z_IS_748_EQ_748U(...) \, +#define Z_IS_748U_EQ_748U(...) \, +#define Z_IS_749_EQ_749(...) \, +#define Z_IS_749U_EQ_749(...) \, +#define Z_IS_749_EQ_749U(...) \, +#define Z_IS_749U_EQ_749U(...) \, +#define Z_IS_750_EQ_750(...) \, +#define Z_IS_750U_EQ_750(...) \, +#define Z_IS_750_EQ_750U(...) \, +#define Z_IS_750U_EQ_750U(...) \, +#define Z_IS_751_EQ_751(...) \, +#define Z_IS_751U_EQ_751(...) \, +#define Z_IS_751_EQ_751U(...) \, +#define Z_IS_751U_EQ_751U(...) \, +#define Z_IS_752_EQ_752(...) \, +#define Z_IS_752U_EQ_752(...) \, +#define Z_IS_752_EQ_752U(...) \, +#define Z_IS_752U_EQ_752U(...) \, +#define Z_IS_753_EQ_753(...) \, +#define Z_IS_753U_EQ_753(...) \, +#define Z_IS_753_EQ_753U(...) \, +#define Z_IS_753U_EQ_753U(...) \, +#define Z_IS_754_EQ_754(...) \, +#define Z_IS_754U_EQ_754(...) \, +#define Z_IS_754_EQ_754U(...) \, +#define Z_IS_754U_EQ_754U(...) \, +#define Z_IS_755_EQ_755(...) \, +#define Z_IS_755U_EQ_755(...) \, +#define Z_IS_755_EQ_755U(...) \, +#define Z_IS_755U_EQ_755U(...) \, +#define Z_IS_756_EQ_756(...) \, +#define Z_IS_756U_EQ_756(...) \, +#define Z_IS_756_EQ_756U(...) \, +#define Z_IS_756U_EQ_756U(...) \, +#define Z_IS_757_EQ_757(...) \, +#define Z_IS_757U_EQ_757(...) \, +#define Z_IS_757_EQ_757U(...) \, +#define Z_IS_757U_EQ_757U(...) \, +#define Z_IS_758_EQ_758(...) \, +#define Z_IS_758U_EQ_758(...) \, +#define Z_IS_758_EQ_758U(...) \, +#define Z_IS_758U_EQ_758U(...) \, +#define Z_IS_759_EQ_759(...) \, +#define Z_IS_759U_EQ_759(...) \, +#define Z_IS_759_EQ_759U(...) \, +#define Z_IS_759U_EQ_759U(...) \, +#define Z_IS_760_EQ_760(...) \, +#define Z_IS_760U_EQ_760(...) \, +#define Z_IS_760_EQ_760U(...) \, +#define Z_IS_760U_EQ_760U(...) \, +#define Z_IS_761_EQ_761(...) \, +#define Z_IS_761U_EQ_761(...) \, +#define Z_IS_761_EQ_761U(...) \, +#define Z_IS_761U_EQ_761U(...) \, +#define Z_IS_762_EQ_762(...) \, +#define Z_IS_762U_EQ_762(...) \, +#define Z_IS_762_EQ_762U(...) \, +#define Z_IS_762U_EQ_762U(...) \, +#define Z_IS_763_EQ_763(...) \, +#define Z_IS_763U_EQ_763(...) \, +#define Z_IS_763_EQ_763U(...) \, +#define Z_IS_763U_EQ_763U(...) \, +#define Z_IS_764_EQ_764(...) \, +#define Z_IS_764U_EQ_764(...) \, +#define Z_IS_764_EQ_764U(...) \, +#define Z_IS_764U_EQ_764U(...) \, +#define Z_IS_765_EQ_765(...) \, +#define Z_IS_765U_EQ_765(...) \, +#define Z_IS_765_EQ_765U(...) \, +#define Z_IS_765U_EQ_765U(...) \, +#define Z_IS_766_EQ_766(...) \, +#define Z_IS_766U_EQ_766(...) \, +#define Z_IS_766_EQ_766U(...) \, +#define Z_IS_766U_EQ_766U(...) \, +#define Z_IS_767_EQ_767(...) \, +#define Z_IS_767U_EQ_767(...) \, +#define Z_IS_767_EQ_767U(...) \, +#define Z_IS_767U_EQ_767U(...) \, +#define Z_IS_768_EQ_768(...) \, +#define Z_IS_768U_EQ_768(...) \, +#define Z_IS_768_EQ_768U(...) \, +#define Z_IS_768U_EQ_768U(...) \, +#define Z_IS_769_EQ_769(...) \, +#define Z_IS_769U_EQ_769(...) \, +#define Z_IS_769_EQ_769U(...) \, +#define Z_IS_769U_EQ_769U(...) \, +#define Z_IS_770_EQ_770(...) \, +#define Z_IS_770U_EQ_770(...) \, +#define Z_IS_770_EQ_770U(...) \, +#define Z_IS_770U_EQ_770U(...) \, +#define Z_IS_771_EQ_771(...) \, +#define Z_IS_771U_EQ_771(...) \, +#define Z_IS_771_EQ_771U(...) \, +#define Z_IS_771U_EQ_771U(...) \, +#define Z_IS_772_EQ_772(...) \, +#define Z_IS_772U_EQ_772(...) \, +#define Z_IS_772_EQ_772U(...) \, +#define Z_IS_772U_EQ_772U(...) \, +#define Z_IS_773_EQ_773(...) \, +#define Z_IS_773U_EQ_773(...) \, +#define Z_IS_773_EQ_773U(...) \, +#define Z_IS_773U_EQ_773U(...) \, +#define Z_IS_774_EQ_774(...) \, +#define Z_IS_774U_EQ_774(...) \, +#define Z_IS_774_EQ_774U(...) \, +#define Z_IS_774U_EQ_774U(...) \, +#define Z_IS_775_EQ_775(...) \, +#define Z_IS_775U_EQ_775(...) \, +#define Z_IS_775_EQ_775U(...) \, +#define Z_IS_775U_EQ_775U(...) \, +#define Z_IS_776_EQ_776(...) \, +#define Z_IS_776U_EQ_776(...) \, +#define Z_IS_776_EQ_776U(...) \, +#define Z_IS_776U_EQ_776U(...) \, +#define Z_IS_777_EQ_777(...) \, +#define Z_IS_777U_EQ_777(...) \, +#define Z_IS_777_EQ_777U(...) \, +#define Z_IS_777U_EQ_777U(...) \, +#define Z_IS_778_EQ_778(...) \, +#define Z_IS_778U_EQ_778(...) \, +#define Z_IS_778_EQ_778U(...) \, +#define Z_IS_778U_EQ_778U(...) \, +#define Z_IS_779_EQ_779(...) \, +#define Z_IS_779U_EQ_779(...) \, +#define Z_IS_779_EQ_779U(...) \, +#define Z_IS_779U_EQ_779U(...) \, +#define Z_IS_780_EQ_780(...) \, +#define Z_IS_780U_EQ_780(...) \, +#define Z_IS_780_EQ_780U(...) \, +#define Z_IS_780U_EQ_780U(...) \, +#define Z_IS_781_EQ_781(...) \, +#define Z_IS_781U_EQ_781(...) \, +#define Z_IS_781_EQ_781U(...) \, +#define Z_IS_781U_EQ_781U(...) \, +#define Z_IS_782_EQ_782(...) \, +#define Z_IS_782U_EQ_782(...) \, +#define Z_IS_782_EQ_782U(...) \, +#define Z_IS_782U_EQ_782U(...) \, +#define Z_IS_783_EQ_783(...) \, +#define Z_IS_783U_EQ_783(...) \, +#define Z_IS_783_EQ_783U(...) \, +#define Z_IS_783U_EQ_783U(...) \, +#define Z_IS_784_EQ_784(...) \, +#define Z_IS_784U_EQ_784(...) \, +#define Z_IS_784_EQ_784U(...) \, +#define Z_IS_784U_EQ_784U(...) \, +#define Z_IS_785_EQ_785(...) \, +#define Z_IS_785U_EQ_785(...) \, +#define Z_IS_785_EQ_785U(...) \, +#define Z_IS_785U_EQ_785U(...) \, +#define Z_IS_786_EQ_786(...) \, +#define Z_IS_786U_EQ_786(...) \, +#define Z_IS_786_EQ_786U(...) \, +#define Z_IS_786U_EQ_786U(...) \, +#define Z_IS_787_EQ_787(...) \, +#define Z_IS_787U_EQ_787(...) \, +#define Z_IS_787_EQ_787U(...) \, +#define Z_IS_787U_EQ_787U(...) \, +#define Z_IS_788_EQ_788(...) \, +#define Z_IS_788U_EQ_788(...) \, +#define Z_IS_788_EQ_788U(...) \, +#define Z_IS_788U_EQ_788U(...) \, +#define Z_IS_789_EQ_789(...) \, +#define Z_IS_789U_EQ_789(...) \, +#define Z_IS_789_EQ_789U(...) \, +#define Z_IS_789U_EQ_789U(...) \, +#define Z_IS_790_EQ_790(...) \, +#define Z_IS_790U_EQ_790(...) \, +#define Z_IS_790_EQ_790U(...) \, +#define Z_IS_790U_EQ_790U(...) \, +#define Z_IS_791_EQ_791(...) \, +#define Z_IS_791U_EQ_791(...) \, +#define Z_IS_791_EQ_791U(...) \, +#define Z_IS_791U_EQ_791U(...) \, +#define Z_IS_792_EQ_792(...) \, +#define Z_IS_792U_EQ_792(...) \, +#define Z_IS_792_EQ_792U(...) \, +#define Z_IS_792U_EQ_792U(...) \, +#define Z_IS_793_EQ_793(...) \, +#define Z_IS_793U_EQ_793(...) \, +#define Z_IS_793_EQ_793U(...) \, +#define Z_IS_793U_EQ_793U(...) \, +#define Z_IS_794_EQ_794(...) \, +#define Z_IS_794U_EQ_794(...) \, +#define Z_IS_794_EQ_794U(...) \, +#define Z_IS_794U_EQ_794U(...) \, +#define Z_IS_795_EQ_795(...) \, +#define Z_IS_795U_EQ_795(...) \, +#define Z_IS_795_EQ_795U(...) \, +#define Z_IS_795U_EQ_795U(...) \, +#define Z_IS_796_EQ_796(...) \, +#define Z_IS_796U_EQ_796(...) \, +#define Z_IS_796_EQ_796U(...) \, +#define Z_IS_796U_EQ_796U(...) \, +#define Z_IS_797_EQ_797(...) \, +#define Z_IS_797U_EQ_797(...) \, +#define Z_IS_797_EQ_797U(...) \, +#define Z_IS_797U_EQ_797U(...) \, +#define Z_IS_798_EQ_798(...) \, +#define Z_IS_798U_EQ_798(...) \, +#define Z_IS_798_EQ_798U(...) \, +#define Z_IS_798U_EQ_798U(...) \, +#define Z_IS_799_EQ_799(...) \, +#define Z_IS_799U_EQ_799(...) \, +#define Z_IS_799_EQ_799U(...) \, +#define Z_IS_799U_EQ_799U(...) \, +#define Z_IS_800_EQ_800(...) \, +#define Z_IS_800U_EQ_800(...) \, +#define Z_IS_800_EQ_800U(...) \, +#define Z_IS_800U_EQ_800U(...) \, +#define Z_IS_801_EQ_801(...) \, +#define Z_IS_801U_EQ_801(...) \, +#define Z_IS_801_EQ_801U(...) \, +#define Z_IS_801U_EQ_801U(...) \, +#define Z_IS_802_EQ_802(...) \, +#define Z_IS_802U_EQ_802(...) \, +#define Z_IS_802_EQ_802U(...) \, +#define Z_IS_802U_EQ_802U(...) \, +#define Z_IS_803_EQ_803(...) \, +#define Z_IS_803U_EQ_803(...) \, +#define Z_IS_803_EQ_803U(...) \, +#define Z_IS_803U_EQ_803U(...) \, +#define Z_IS_804_EQ_804(...) \, +#define Z_IS_804U_EQ_804(...) \, +#define Z_IS_804_EQ_804U(...) \, +#define Z_IS_804U_EQ_804U(...) \, +#define Z_IS_805_EQ_805(...) \, +#define Z_IS_805U_EQ_805(...) \, +#define Z_IS_805_EQ_805U(...) \, +#define Z_IS_805U_EQ_805U(...) \, +#define Z_IS_806_EQ_806(...) \, +#define Z_IS_806U_EQ_806(...) \, +#define Z_IS_806_EQ_806U(...) \, +#define Z_IS_806U_EQ_806U(...) \, +#define Z_IS_807_EQ_807(...) \, +#define Z_IS_807U_EQ_807(...) \, +#define Z_IS_807_EQ_807U(...) \, +#define Z_IS_807U_EQ_807U(...) \, +#define Z_IS_808_EQ_808(...) \, +#define Z_IS_808U_EQ_808(...) \, +#define Z_IS_808_EQ_808U(...) \, +#define Z_IS_808U_EQ_808U(...) \, +#define Z_IS_809_EQ_809(...) \, +#define Z_IS_809U_EQ_809(...) \, +#define Z_IS_809_EQ_809U(...) \, +#define Z_IS_809U_EQ_809U(...) \, +#define Z_IS_810_EQ_810(...) \, +#define Z_IS_810U_EQ_810(...) \, +#define Z_IS_810_EQ_810U(...) \, +#define Z_IS_810U_EQ_810U(...) \, +#define Z_IS_811_EQ_811(...) \, +#define Z_IS_811U_EQ_811(...) \, +#define Z_IS_811_EQ_811U(...) \, +#define Z_IS_811U_EQ_811U(...) \, +#define Z_IS_812_EQ_812(...) \, +#define Z_IS_812U_EQ_812(...) \, +#define Z_IS_812_EQ_812U(...) \, +#define Z_IS_812U_EQ_812U(...) \, +#define Z_IS_813_EQ_813(...) \, +#define Z_IS_813U_EQ_813(...) \, +#define Z_IS_813_EQ_813U(...) \, +#define Z_IS_813U_EQ_813U(...) \, +#define Z_IS_814_EQ_814(...) \, +#define Z_IS_814U_EQ_814(...) \, +#define Z_IS_814_EQ_814U(...) \, +#define Z_IS_814U_EQ_814U(...) \, +#define Z_IS_815_EQ_815(...) \, +#define Z_IS_815U_EQ_815(...) \, +#define Z_IS_815_EQ_815U(...) \, +#define Z_IS_815U_EQ_815U(...) \, +#define Z_IS_816_EQ_816(...) \, +#define Z_IS_816U_EQ_816(...) \, +#define Z_IS_816_EQ_816U(...) \, +#define Z_IS_816U_EQ_816U(...) \, +#define Z_IS_817_EQ_817(...) \, +#define Z_IS_817U_EQ_817(...) \, +#define Z_IS_817_EQ_817U(...) \, +#define Z_IS_817U_EQ_817U(...) \, +#define Z_IS_818_EQ_818(...) \, +#define Z_IS_818U_EQ_818(...) \, +#define Z_IS_818_EQ_818U(...) \, +#define Z_IS_818U_EQ_818U(...) \, +#define Z_IS_819_EQ_819(...) \, +#define Z_IS_819U_EQ_819(...) \, +#define Z_IS_819_EQ_819U(...) \, +#define Z_IS_819U_EQ_819U(...) \, +#define Z_IS_820_EQ_820(...) \, +#define Z_IS_820U_EQ_820(...) \, +#define Z_IS_820_EQ_820U(...) \, +#define Z_IS_820U_EQ_820U(...) \, +#define Z_IS_821_EQ_821(...) \, +#define Z_IS_821U_EQ_821(...) \, +#define Z_IS_821_EQ_821U(...) \, +#define Z_IS_821U_EQ_821U(...) \, +#define Z_IS_822_EQ_822(...) \, +#define Z_IS_822U_EQ_822(...) \, +#define Z_IS_822_EQ_822U(...) \, +#define Z_IS_822U_EQ_822U(...) \, +#define Z_IS_823_EQ_823(...) \, +#define Z_IS_823U_EQ_823(...) \, +#define Z_IS_823_EQ_823U(...) \, +#define Z_IS_823U_EQ_823U(...) \, +#define Z_IS_824_EQ_824(...) \, +#define Z_IS_824U_EQ_824(...) \, +#define Z_IS_824_EQ_824U(...) \, +#define Z_IS_824U_EQ_824U(...) \, +#define Z_IS_825_EQ_825(...) \, +#define Z_IS_825U_EQ_825(...) \, +#define Z_IS_825_EQ_825U(...) \, +#define Z_IS_825U_EQ_825U(...) \, +#define Z_IS_826_EQ_826(...) \, +#define Z_IS_826U_EQ_826(...) \, +#define Z_IS_826_EQ_826U(...) \, +#define Z_IS_826U_EQ_826U(...) \, +#define Z_IS_827_EQ_827(...) \, +#define Z_IS_827U_EQ_827(...) \, +#define Z_IS_827_EQ_827U(...) \, +#define Z_IS_827U_EQ_827U(...) \, +#define Z_IS_828_EQ_828(...) \, +#define Z_IS_828U_EQ_828(...) \, +#define Z_IS_828_EQ_828U(...) \, +#define Z_IS_828U_EQ_828U(...) \, +#define Z_IS_829_EQ_829(...) \, +#define Z_IS_829U_EQ_829(...) \, +#define Z_IS_829_EQ_829U(...) \, +#define Z_IS_829U_EQ_829U(...) \, +#define Z_IS_830_EQ_830(...) \, +#define Z_IS_830U_EQ_830(...) \, +#define Z_IS_830_EQ_830U(...) \, +#define Z_IS_830U_EQ_830U(...) \, +#define Z_IS_831_EQ_831(...) \, +#define Z_IS_831U_EQ_831(...) \, +#define Z_IS_831_EQ_831U(...) \, +#define Z_IS_831U_EQ_831U(...) \, +#define Z_IS_832_EQ_832(...) \, +#define Z_IS_832U_EQ_832(...) \, +#define Z_IS_832_EQ_832U(...) \, +#define Z_IS_832U_EQ_832U(...) \, +#define Z_IS_833_EQ_833(...) \, +#define Z_IS_833U_EQ_833(...) \, +#define Z_IS_833_EQ_833U(...) \, +#define Z_IS_833U_EQ_833U(...) \, +#define Z_IS_834_EQ_834(...) \, +#define Z_IS_834U_EQ_834(...) \, +#define Z_IS_834_EQ_834U(...) \, +#define Z_IS_834U_EQ_834U(...) \, +#define Z_IS_835_EQ_835(...) \, +#define Z_IS_835U_EQ_835(...) \, +#define Z_IS_835_EQ_835U(...) \, +#define Z_IS_835U_EQ_835U(...) \, +#define Z_IS_836_EQ_836(...) \, +#define Z_IS_836U_EQ_836(...) \, +#define Z_IS_836_EQ_836U(...) \, +#define Z_IS_836U_EQ_836U(...) \, +#define Z_IS_837_EQ_837(...) \, +#define Z_IS_837U_EQ_837(...) \, +#define Z_IS_837_EQ_837U(...) \, +#define Z_IS_837U_EQ_837U(...) \, +#define Z_IS_838_EQ_838(...) \, +#define Z_IS_838U_EQ_838(...) \, +#define Z_IS_838_EQ_838U(...) \, +#define Z_IS_838U_EQ_838U(...) \, +#define Z_IS_839_EQ_839(...) \, +#define Z_IS_839U_EQ_839(...) \, +#define Z_IS_839_EQ_839U(...) \, +#define Z_IS_839U_EQ_839U(...) \, +#define Z_IS_840_EQ_840(...) \, +#define Z_IS_840U_EQ_840(...) \, +#define Z_IS_840_EQ_840U(...) \, +#define Z_IS_840U_EQ_840U(...) \, +#define Z_IS_841_EQ_841(...) \, +#define Z_IS_841U_EQ_841(...) \, +#define Z_IS_841_EQ_841U(...) \, +#define Z_IS_841U_EQ_841U(...) \, +#define Z_IS_842_EQ_842(...) \, +#define Z_IS_842U_EQ_842(...) \, +#define Z_IS_842_EQ_842U(...) \, +#define Z_IS_842U_EQ_842U(...) \, +#define Z_IS_843_EQ_843(...) \, +#define Z_IS_843U_EQ_843(...) \, +#define Z_IS_843_EQ_843U(...) \, +#define Z_IS_843U_EQ_843U(...) \, +#define Z_IS_844_EQ_844(...) \, +#define Z_IS_844U_EQ_844(...) \, +#define Z_IS_844_EQ_844U(...) \, +#define Z_IS_844U_EQ_844U(...) \, +#define Z_IS_845_EQ_845(...) \, +#define Z_IS_845U_EQ_845(...) \, +#define Z_IS_845_EQ_845U(...) \, +#define Z_IS_845U_EQ_845U(...) \, +#define Z_IS_846_EQ_846(...) \, +#define Z_IS_846U_EQ_846(...) \, +#define Z_IS_846_EQ_846U(...) \, +#define Z_IS_846U_EQ_846U(...) \, +#define Z_IS_847_EQ_847(...) \, +#define Z_IS_847U_EQ_847(...) \, +#define Z_IS_847_EQ_847U(...) \, +#define Z_IS_847U_EQ_847U(...) \, +#define Z_IS_848_EQ_848(...) \, +#define Z_IS_848U_EQ_848(...) \, +#define Z_IS_848_EQ_848U(...) \, +#define Z_IS_848U_EQ_848U(...) \, +#define Z_IS_849_EQ_849(...) \, +#define Z_IS_849U_EQ_849(...) \, +#define Z_IS_849_EQ_849U(...) \, +#define Z_IS_849U_EQ_849U(...) \, +#define Z_IS_850_EQ_850(...) \, +#define Z_IS_850U_EQ_850(...) \, +#define Z_IS_850_EQ_850U(...) \, +#define Z_IS_850U_EQ_850U(...) \, +#define Z_IS_851_EQ_851(...) \, +#define Z_IS_851U_EQ_851(...) \, +#define Z_IS_851_EQ_851U(...) \, +#define Z_IS_851U_EQ_851U(...) \, +#define Z_IS_852_EQ_852(...) \, +#define Z_IS_852U_EQ_852(...) \, +#define Z_IS_852_EQ_852U(...) \, +#define Z_IS_852U_EQ_852U(...) \, +#define Z_IS_853_EQ_853(...) \, +#define Z_IS_853U_EQ_853(...) \, +#define Z_IS_853_EQ_853U(...) \, +#define Z_IS_853U_EQ_853U(...) \, +#define Z_IS_854_EQ_854(...) \, +#define Z_IS_854U_EQ_854(...) \, +#define Z_IS_854_EQ_854U(...) \, +#define Z_IS_854U_EQ_854U(...) \, +#define Z_IS_855_EQ_855(...) \, +#define Z_IS_855U_EQ_855(...) \, +#define Z_IS_855_EQ_855U(...) \, +#define Z_IS_855U_EQ_855U(...) \, +#define Z_IS_856_EQ_856(...) \, +#define Z_IS_856U_EQ_856(...) \, +#define Z_IS_856_EQ_856U(...) \, +#define Z_IS_856U_EQ_856U(...) \, +#define Z_IS_857_EQ_857(...) \, +#define Z_IS_857U_EQ_857(...) \, +#define Z_IS_857_EQ_857U(...) \, +#define Z_IS_857U_EQ_857U(...) \, +#define Z_IS_858_EQ_858(...) \, +#define Z_IS_858U_EQ_858(...) \, +#define Z_IS_858_EQ_858U(...) \, +#define Z_IS_858U_EQ_858U(...) \, +#define Z_IS_859_EQ_859(...) \, +#define Z_IS_859U_EQ_859(...) \, +#define Z_IS_859_EQ_859U(...) \, +#define Z_IS_859U_EQ_859U(...) \, +#define Z_IS_860_EQ_860(...) \, +#define Z_IS_860U_EQ_860(...) \, +#define Z_IS_860_EQ_860U(...) \, +#define Z_IS_860U_EQ_860U(...) \, +#define Z_IS_861_EQ_861(...) \, +#define Z_IS_861U_EQ_861(...) \, +#define Z_IS_861_EQ_861U(...) \, +#define Z_IS_861U_EQ_861U(...) \, +#define Z_IS_862_EQ_862(...) \, +#define Z_IS_862U_EQ_862(...) \, +#define Z_IS_862_EQ_862U(...) \, +#define Z_IS_862U_EQ_862U(...) \, +#define Z_IS_863_EQ_863(...) \, +#define Z_IS_863U_EQ_863(...) \, +#define Z_IS_863_EQ_863U(...) \, +#define Z_IS_863U_EQ_863U(...) \, +#define Z_IS_864_EQ_864(...) \, +#define Z_IS_864U_EQ_864(...) \, +#define Z_IS_864_EQ_864U(...) \, +#define Z_IS_864U_EQ_864U(...) \, +#define Z_IS_865_EQ_865(...) \, +#define Z_IS_865U_EQ_865(...) \, +#define Z_IS_865_EQ_865U(...) \, +#define Z_IS_865U_EQ_865U(...) \, +#define Z_IS_866_EQ_866(...) \, +#define Z_IS_866U_EQ_866(...) \, +#define Z_IS_866_EQ_866U(...) \, +#define Z_IS_866U_EQ_866U(...) \, +#define Z_IS_867_EQ_867(...) \, +#define Z_IS_867U_EQ_867(...) \, +#define Z_IS_867_EQ_867U(...) \, +#define Z_IS_867U_EQ_867U(...) \, +#define Z_IS_868_EQ_868(...) \, +#define Z_IS_868U_EQ_868(...) \, +#define Z_IS_868_EQ_868U(...) \, +#define Z_IS_868U_EQ_868U(...) \, +#define Z_IS_869_EQ_869(...) \, +#define Z_IS_869U_EQ_869(...) \, +#define Z_IS_869_EQ_869U(...) \, +#define Z_IS_869U_EQ_869U(...) \, +#define Z_IS_870_EQ_870(...) \, +#define Z_IS_870U_EQ_870(...) \, +#define Z_IS_870_EQ_870U(...) \, +#define Z_IS_870U_EQ_870U(...) \, +#define Z_IS_871_EQ_871(...) \, +#define Z_IS_871U_EQ_871(...) \, +#define Z_IS_871_EQ_871U(...) \, +#define Z_IS_871U_EQ_871U(...) \, +#define Z_IS_872_EQ_872(...) \, +#define Z_IS_872U_EQ_872(...) \, +#define Z_IS_872_EQ_872U(...) \, +#define Z_IS_872U_EQ_872U(...) \, +#define Z_IS_873_EQ_873(...) \, +#define Z_IS_873U_EQ_873(...) \, +#define Z_IS_873_EQ_873U(...) \, +#define Z_IS_873U_EQ_873U(...) \, +#define Z_IS_874_EQ_874(...) \, +#define Z_IS_874U_EQ_874(...) \, +#define Z_IS_874_EQ_874U(...) \, +#define Z_IS_874U_EQ_874U(...) \, +#define Z_IS_875_EQ_875(...) \, +#define Z_IS_875U_EQ_875(...) \, +#define Z_IS_875_EQ_875U(...) \, +#define Z_IS_875U_EQ_875U(...) \, +#define Z_IS_876_EQ_876(...) \, +#define Z_IS_876U_EQ_876(...) \, +#define Z_IS_876_EQ_876U(...) \, +#define Z_IS_876U_EQ_876U(...) \, +#define Z_IS_877_EQ_877(...) \, +#define Z_IS_877U_EQ_877(...) \, +#define Z_IS_877_EQ_877U(...) \, +#define Z_IS_877U_EQ_877U(...) \, +#define Z_IS_878_EQ_878(...) \, +#define Z_IS_878U_EQ_878(...) \, +#define Z_IS_878_EQ_878U(...) \, +#define Z_IS_878U_EQ_878U(...) \, +#define Z_IS_879_EQ_879(...) \, +#define Z_IS_879U_EQ_879(...) \, +#define Z_IS_879_EQ_879U(...) \, +#define Z_IS_879U_EQ_879U(...) \, +#define Z_IS_880_EQ_880(...) \, +#define Z_IS_880U_EQ_880(...) \, +#define Z_IS_880_EQ_880U(...) \, +#define Z_IS_880U_EQ_880U(...) \, +#define Z_IS_881_EQ_881(...) \, +#define Z_IS_881U_EQ_881(...) \, +#define Z_IS_881_EQ_881U(...) \, +#define Z_IS_881U_EQ_881U(...) \, +#define Z_IS_882_EQ_882(...) \, +#define Z_IS_882U_EQ_882(...) \, +#define Z_IS_882_EQ_882U(...) \, +#define Z_IS_882U_EQ_882U(...) \, +#define Z_IS_883_EQ_883(...) \, +#define Z_IS_883U_EQ_883(...) \, +#define Z_IS_883_EQ_883U(...) \, +#define Z_IS_883U_EQ_883U(...) \, +#define Z_IS_884_EQ_884(...) \, +#define Z_IS_884U_EQ_884(...) \, +#define Z_IS_884_EQ_884U(...) \, +#define Z_IS_884U_EQ_884U(...) \, +#define Z_IS_885_EQ_885(...) \, +#define Z_IS_885U_EQ_885(...) \, +#define Z_IS_885_EQ_885U(...) \, +#define Z_IS_885U_EQ_885U(...) \, +#define Z_IS_886_EQ_886(...) \, +#define Z_IS_886U_EQ_886(...) \, +#define Z_IS_886_EQ_886U(...) \, +#define Z_IS_886U_EQ_886U(...) \, +#define Z_IS_887_EQ_887(...) \, +#define Z_IS_887U_EQ_887(...) \, +#define Z_IS_887_EQ_887U(...) \, +#define Z_IS_887U_EQ_887U(...) \, +#define Z_IS_888_EQ_888(...) \, +#define Z_IS_888U_EQ_888(...) \, +#define Z_IS_888_EQ_888U(...) \, +#define Z_IS_888U_EQ_888U(...) \, +#define Z_IS_889_EQ_889(...) \, +#define Z_IS_889U_EQ_889(...) \, +#define Z_IS_889_EQ_889U(...) \, +#define Z_IS_889U_EQ_889U(...) \, +#define Z_IS_890_EQ_890(...) \, +#define Z_IS_890U_EQ_890(...) \, +#define Z_IS_890_EQ_890U(...) \, +#define Z_IS_890U_EQ_890U(...) \, +#define Z_IS_891_EQ_891(...) \, +#define Z_IS_891U_EQ_891(...) \, +#define Z_IS_891_EQ_891U(...) \, +#define Z_IS_891U_EQ_891U(...) \, +#define Z_IS_892_EQ_892(...) \, +#define Z_IS_892U_EQ_892(...) \, +#define Z_IS_892_EQ_892U(...) \, +#define Z_IS_892U_EQ_892U(...) \, +#define Z_IS_893_EQ_893(...) \, +#define Z_IS_893U_EQ_893(...) \, +#define Z_IS_893_EQ_893U(...) \, +#define Z_IS_893U_EQ_893U(...) \, +#define Z_IS_894_EQ_894(...) \, +#define Z_IS_894U_EQ_894(...) \, +#define Z_IS_894_EQ_894U(...) \, +#define Z_IS_894U_EQ_894U(...) \, +#define Z_IS_895_EQ_895(...) \, +#define Z_IS_895U_EQ_895(...) \, +#define Z_IS_895_EQ_895U(...) \, +#define Z_IS_895U_EQ_895U(...) \, +#define Z_IS_896_EQ_896(...) \, +#define Z_IS_896U_EQ_896(...) \, +#define Z_IS_896_EQ_896U(...) \, +#define Z_IS_896U_EQ_896U(...) \, +#define Z_IS_897_EQ_897(...) \, +#define Z_IS_897U_EQ_897(...) \, +#define Z_IS_897_EQ_897U(...) \, +#define Z_IS_897U_EQ_897U(...) \, +#define Z_IS_898_EQ_898(...) \, +#define Z_IS_898U_EQ_898(...) \, +#define Z_IS_898_EQ_898U(...) \, +#define Z_IS_898U_EQ_898U(...) \, +#define Z_IS_899_EQ_899(...) \, +#define Z_IS_899U_EQ_899(...) \, +#define Z_IS_899_EQ_899U(...) \, +#define Z_IS_899U_EQ_899U(...) \, +#define Z_IS_900_EQ_900(...) \, +#define Z_IS_900U_EQ_900(...) \, +#define Z_IS_900_EQ_900U(...) \, +#define Z_IS_900U_EQ_900U(...) \, +#define Z_IS_901_EQ_901(...) \, +#define Z_IS_901U_EQ_901(...) \, +#define Z_IS_901_EQ_901U(...) \, +#define Z_IS_901U_EQ_901U(...) \, +#define Z_IS_902_EQ_902(...) \, +#define Z_IS_902U_EQ_902(...) \, +#define Z_IS_902_EQ_902U(...) \, +#define Z_IS_902U_EQ_902U(...) \, +#define Z_IS_903_EQ_903(...) \, +#define Z_IS_903U_EQ_903(...) \, +#define Z_IS_903_EQ_903U(...) \, +#define Z_IS_903U_EQ_903U(...) \, +#define Z_IS_904_EQ_904(...) \, +#define Z_IS_904U_EQ_904(...) \, +#define Z_IS_904_EQ_904U(...) \, +#define Z_IS_904U_EQ_904U(...) \, +#define Z_IS_905_EQ_905(...) \, +#define Z_IS_905U_EQ_905(...) \, +#define Z_IS_905_EQ_905U(...) \, +#define Z_IS_905U_EQ_905U(...) \, +#define Z_IS_906_EQ_906(...) \, +#define Z_IS_906U_EQ_906(...) \, +#define Z_IS_906_EQ_906U(...) \, +#define Z_IS_906U_EQ_906U(...) \, +#define Z_IS_907_EQ_907(...) \, +#define Z_IS_907U_EQ_907(...) \, +#define Z_IS_907_EQ_907U(...) \, +#define Z_IS_907U_EQ_907U(...) \, +#define Z_IS_908_EQ_908(...) \, +#define Z_IS_908U_EQ_908(...) \, +#define Z_IS_908_EQ_908U(...) \, +#define Z_IS_908U_EQ_908U(...) \, +#define Z_IS_909_EQ_909(...) \, +#define Z_IS_909U_EQ_909(...) \, +#define Z_IS_909_EQ_909U(...) \, +#define Z_IS_909U_EQ_909U(...) \, +#define Z_IS_910_EQ_910(...) \, +#define Z_IS_910U_EQ_910(...) \, +#define Z_IS_910_EQ_910U(...) \, +#define Z_IS_910U_EQ_910U(...) \, +#define Z_IS_911_EQ_911(...) \, +#define Z_IS_911U_EQ_911(...) \, +#define Z_IS_911_EQ_911U(...) \, +#define Z_IS_911U_EQ_911U(...) \, +#define Z_IS_912_EQ_912(...) \, +#define Z_IS_912U_EQ_912(...) \, +#define Z_IS_912_EQ_912U(...) \, +#define Z_IS_912U_EQ_912U(...) \, +#define Z_IS_913_EQ_913(...) \, +#define Z_IS_913U_EQ_913(...) \, +#define Z_IS_913_EQ_913U(...) \, +#define Z_IS_913U_EQ_913U(...) \, +#define Z_IS_914_EQ_914(...) \, +#define Z_IS_914U_EQ_914(...) \, +#define Z_IS_914_EQ_914U(...) \, +#define Z_IS_914U_EQ_914U(...) \, +#define Z_IS_915_EQ_915(...) \, +#define Z_IS_915U_EQ_915(...) \, +#define Z_IS_915_EQ_915U(...) \, +#define Z_IS_915U_EQ_915U(...) \, +#define Z_IS_916_EQ_916(...) \, +#define Z_IS_916U_EQ_916(...) \, +#define Z_IS_916_EQ_916U(...) \, +#define Z_IS_916U_EQ_916U(...) \, +#define Z_IS_917_EQ_917(...) \, +#define Z_IS_917U_EQ_917(...) \, +#define Z_IS_917_EQ_917U(...) \, +#define Z_IS_917U_EQ_917U(...) \, +#define Z_IS_918_EQ_918(...) \, +#define Z_IS_918U_EQ_918(...) \, +#define Z_IS_918_EQ_918U(...) \, +#define Z_IS_918U_EQ_918U(...) \, +#define Z_IS_919_EQ_919(...) \, +#define Z_IS_919U_EQ_919(...) \, +#define Z_IS_919_EQ_919U(...) \, +#define Z_IS_919U_EQ_919U(...) \, +#define Z_IS_920_EQ_920(...) \, +#define Z_IS_920U_EQ_920(...) \, +#define Z_IS_920_EQ_920U(...) \, +#define Z_IS_920U_EQ_920U(...) \, +#define Z_IS_921_EQ_921(...) \, +#define Z_IS_921U_EQ_921(...) \, +#define Z_IS_921_EQ_921U(...) \, +#define Z_IS_921U_EQ_921U(...) \, +#define Z_IS_922_EQ_922(...) \, +#define Z_IS_922U_EQ_922(...) \, +#define Z_IS_922_EQ_922U(...) \, +#define Z_IS_922U_EQ_922U(...) \, +#define Z_IS_923_EQ_923(...) \, +#define Z_IS_923U_EQ_923(...) \, +#define Z_IS_923_EQ_923U(...) \, +#define Z_IS_923U_EQ_923U(...) \, +#define Z_IS_924_EQ_924(...) \, +#define Z_IS_924U_EQ_924(...) \, +#define Z_IS_924_EQ_924U(...) \, +#define Z_IS_924U_EQ_924U(...) \, +#define Z_IS_925_EQ_925(...) \, +#define Z_IS_925U_EQ_925(...) \, +#define Z_IS_925_EQ_925U(...) \, +#define Z_IS_925U_EQ_925U(...) \, +#define Z_IS_926_EQ_926(...) \, +#define Z_IS_926U_EQ_926(...) \, +#define Z_IS_926_EQ_926U(...) \, +#define Z_IS_926U_EQ_926U(...) \, +#define Z_IS_927_EQ_927(...) \, +#define Z_IS_927U_EQ_927(...) \, +#define Z_IS_927_EQ_927U(...) \, +#define Z_IS_927U_EQ_927U(...) \, +#define Z_IS_928_EQ_928(...) \, +#define Z_IS_928U_EQ_928(...) \, +#define Z_IS_928_EQ_928U(...) \, +#define Z_IS_928U_EQ_928U(...) \, +#define Z_IS_929_EQ_929(...) \, +#define Z_IS_929U_EQ_929(...) \, +#define Z_IS_929_EQ_929U(...) \, +#define Z_IS_929U_EQ_929U(...) \, +#define Z_IS_930_EQ_930(...) \, +#define Z_IS_930U_EQ_930(...) \, +#define Z_IS_930_EQ_930U(...) \, +#define Z_IS_930U_EQ_930U(...) \, +#define Z_IS_931_EQ_931(...) \, +#define Z_IS_931U_EQ_931(...) \, +#define Z_IS_931_EQ_931U(...) \, +#define Z_IS_931U_EQ_931U(...) \, +#define Z_IS_932_EQ_932(...) \, +#define Z_IS_932U_EQ_932(...) \, +#define Z_IS_932_EQ_932U(...) \, +#define Z_IS_932U_EQ_932U(...) \, +#define Z_IS_933_EQ_933(...) \, +#define Z_IS_933U_EQ_933(...) \, +#define Z_IS_933_EQ_933U(...) \, +#define Z_IS_933U_EQ_933U(...) \, +#define Z_IS_934_EQ_934(...) \, +#define Z_IS_934U_EQ_934(...) \, +#define Z_IS_934_EQ_934U(...) \, +#define Z_IS_934U_EQ_934U(...) \, +#define Z_IS_935_EQ_935(...) \, +#define Z_IS_935U_EQ_935(...) \, +#define Z_IS_935_EQ_935U(...) \, +#define Z_IS_935U_EQ_935U(...) \, +#define Z_IS_936_EQ_936(...) \, +#define Z_IS_936U_EQ_936(...) \, +#define Z_IS_936_EQ_936U(...) \, +#define Z_IS_936U_EQ_936U(...) \, +#define Z_IS_937_EQ_937(...) \, +#define Z_IS_937U_EQ_937(...) \, +#define Z_IS_937_EQ_937U(...) \, +#define Z_IS_937U_EQ_937U(...) \, +#define Z_IS_938_EQ_938(...) \, +#define Z_IS_938U_EQ_938(...) \, +#define Z_IS_938_EQ_938U(...) \, +#define Z_IS_938U_EQ_938U(...) \, +#define Z_IS_939_EQ_939(...) \, +#define Z_IS_939U_EQ_939(...) \, +#define Z_IS_939_EQ_939U(...) \, +#define Z_IS_939U_EQ_939U(...) \, +#define Z_IS_940_EQ_940(...) \, +#define Z_IS_940U_EQ_940(...) \, +#define Z_IS_940_EQ_940U(...) \, +#define Z_IS_940U_EQ_940U(...) \, +#define Z_IS_941_EQ_941(...) \, +#define Z_IS_941U_EQ_941(...) \, +#define Z_IS_941_EQ_941U(...) \, +#define Z_IS_941U_EQ_941U(...) \, +#define Z_IS_942_EQ_942(...) \, +#define Z_IS_942U_EQ_942(...) \, +#define Z_IS_942_EQ_942U(...) \, +#define Z_IS_942U_EQ_942U(...) \, +#define Z_IS_943_EQ_943(...) \, +#define Z_IS_943U_EQ_943(...) \, +#define Z_IS_943_EQ_943U(...) \, +#define Z_IS_943U_EQ_943U(...) \, +#define Z_IS_944_EQ_944(...) \, +#define Z_IS_944U_EQ_944(...) \, +#define Z_IS_944_EQ_944U(...) \, +#define Z_IS_944U_EQ_944U(...) \, +#define Z_IS_945_EQ_945(...) \, +#define Z_IS_945U_EQ_945(...) \, +#define Z_IS_945_EQ_945U(...) \, +#define Z_IS_945U_EQ_945U(...) \, +#define Z_IS_946_EQ_946(...) \, +#define Z_IS_946U_EQ_946(...) \, +#define Z_IS_946_EQ_946U(...) \, +#define Z_IS_946U_EQ_946U(...) \, +#define Z_IS_947_EQ_947(...) \, +#define Z_IS_947U_EQ_947(...) \, +#define Z_IS_947_EQ_947U(...) \, +#define Z_IS_947U_EQ_947U(...) \, +#define Z_IS_948_EQ_948(...) \, +#define Z_IS_948U_EQ_948(...) \, +#define Z_IS_948_EQ_948U(...) \, +#define Z_IS_948U_EQ_948U(...) \, +#define Z_IS_949_EQ_949(...) \, +#define Z_IS_949U_EQ_949(...) \, +#define Z_IS_949_EQ_949U(...) \, +#define Z_IS_949U_EQ_949U(...) \, +#define Z_IS_950_EQ_950(...) \, +#define Z_IS_950U_EQ_950(...) \, +#define Z_IS_950_EQ_950U(...) \, +#define Z_IS_950U_EQ_950U(...) \, +#define Z_IS_951_EQ_951(...) \, +#define Z_IS_951U_EQ_951(...) \, +#define Z_IS_951_EQ_951U(...) \, +#define Z_IS_951U_EQ_951U(...) \, +#define Z_IS_952_EQ_952(...) \, +#define Z_IS_952U_EQ_952(...) \, +#define Z_IS_952_EQ_952U(...) \, +#define Z_IS_952U_EQ_952U(...) \, +#define Z_IS_953_EQ_953(...) \, +#define Z_IS_953U_EQ_953(...) \, +#define Z_IS_953_EQ_953U(...) \, +#define Z_IS_953U_EQ_953U(...) \, +#define Z_IS_954_EQ_954(...) \, +#define Z_IS_954U_EQ_954(...) \, +#define Z_IS_954_EQ_954U(...) \, +#define Z_IS_954U_EQ_954U(...) \, +#define Z_IS_955_EQ_955(...) \, +#define Z_IS_955U_EQ_955(...) \, +#define Z_IS_955_EQ_955U(...) \, +#define Z_IS_955U_EQ_955U(...) \, +#define Z_IS_956_EQ_956(...) \, +#define Z_IS_956U_EQ_956(...) \, +#define Z_IS_956_EQ_956U(...) \, +#define Z_IS_956U_EQ_956U(...) \, +#define Z_IS_957_EQ_957(...) \, +#define Z_IS_957U_EQ_957(...) \, +#define Z_IS_957_EQ_957U(...) \, +#define Z_IS_957U_EQ_957U(...) \, +#define Z_IS_958_EQ_958(...) \, +#define Z_IS_958U_EQ_958(...) \, +#define Z_IS_958_EQ_958U(...) \, +#define Z_IS_958U_EQ_958U(...) \, +#define Z_IS_959_EQ_959(...) \, +#define Z_IS_959U_EQ_959(...) \, +#define Z_IS_959_EQ_959U(...) \, +#define Z_IS_959U_EQ_959U(...) \, +#define Z_IS_960_EQ_960(...) \, +#define Z_IS_960U_EQ_960(...) \, +#define Z_IS_960_EQ_960U(...) \, +#define Z_IS_960U_EQ_960U(...) \, +#define Z_IS_961_EQ_961(...) \, +#define Z_IS_961U_EQ_961(...) \, +#define Z_IS_961_EQ_961U(...) \, +#define Z_IS_961U_EQ_961U(...) \, +#define Z_IS_962_EQ_962(...) \, +#define Z_IS_962U_EQ_962(...) \, +#define Z_IS_962_EQ_962U(...) \, +#define Z_IS_962U_EQ_962U(...) \, +#define Z_IS_963_EQ_963(...) \, +#define Z_IS_963U_EQ_963(...) \, +#define Z_IS_963_EQ_963U(...) \, +#define Z_IS_963U_EQ_963U(...) \, +#define Z_IS_964_EQ_964(...) \, +#define Z_IS_964U_EQ_964(...) \, +#define Z_IS_964_EQ_964U(...) \, +#define Z_IS_964U_EQ_964U(...) \, +#define Z_IS_965_EQ_965(...) \, +#define Z_IS_965U_EQ_965(...) \, +#define Z_IS_965_EQ_965U(...) \, +#define Z_IS_965U_EQ_965U(...) \, +#define Z_IS_966_EQ_966(...) \, +#define Z_IS_966U_EQ_966(...) \, +#define Z_IS_966_EQ_966U(...) \, +#define Z_IS_966U_EQ_966U(...) \, +#define Z_IS_967_EQ_967(...) \, +#define Z_IS_967U_EQ_967(...) \, +#define Z_IS_967_EQ_967U(...) \, +#define Z_IS_967U_EQ_967U(...) \, +#define Z_IS_968_EQ_968(...) \, +#define Z_IS_968U_EQ_968(...) \, +#define Z_IS_968_EQ_968U(...) \, +#define Z_IS_968U_EQ_968U(...) \, +#define Z_IS_969_EQ_969(...) \, +#define Z_IS_969U_EQ_969(...) \, +#define Z_IS_969_EQ_969U(...) \, +#define Z_IS_969U_EQ_969U(...) \, +#define Z_IS_970_EQ_970(...) \, +#define Z_IS_970U_EQ_970(...) \, +#define Z_IS_970_EQ_970U(...) \, +#define Z_IS_970U_EQ_970U(...) \, +#define Z_IS_971_EQ_971(...) \, +#define Z_IS_971U_EQ_971(...) \, +#define Z_IS_971_EQ_971U(...) \, +#define Z_IS_971U_EQ_971U(...) \, +#define Z_IS_972_EQ_972(...) \, +#define Z_IS_972U_EQ_972(...) \, +#define Z_IS_972_EQ_972U(...) \, +#define Z_IS_972U_EQ_972U(...) \, +#define Z_IS_973_EQ_973(...) \, +#define Z_IS_973U_EQ_973(...) \, +#define Z_IS_973_EQ_973U(...) \, +#define Z_IS_973U_EQ_973U(...) \, +#define Z_IS_974_EQ_974(...) \, +#define Z_IS_974U_EQ_974(...) \, +#define Z_IS_974_EQ_974U(...) \, +#define Z_IS_974U_EQ_974U(...) \, +#define Z_IS_975_EQ_975(...) \, +#define Z_IS_975U_EQ_975(...) \, +#define Z_IS_975_EQ_975U(...) \, +#define Z_IS_975U_EQ_975U(...) \, +#define Z_IS_976_EQ_976(...) \, +#define Z_IS_976U_EQ_976(...) \, +#define Z_IS_976_EQ_976U(...) \, +#define Z_IS_976U_EQ_976U(...) \, +#define Z_IS_977_EQ_977(...) \, +#define Z_IS_977U_EQ_977(...) \, +#define Z_IS_977_EQ_977U(...) \, +#define Z_IS_977U_EQ_977U(...) \, +#define Z_IS_978_EQ_978(...) \, +#define Z_IS_978U_EQ_978(...) \, +#define Z_IS_978_EQ_978U(...) \, +#define Z_IS_978U_EQ_978U(...) \, +#define Z_IS_979_EQ_979(...) \, +#define Z_IS_979U_EQ_979(...) \, +#define Z_IS_979_EQ_979U(...) \, +#define Z_IS_979U_EQ_979U(...) \, +#define Z_IS_980_EQ_980(...) \, +#define Z_IS_980U_EQ_980(...) \, +#define Z_IS_980_EQ_980U(...) \, +#define Z_IS_980U_EQ_980U(...) \, +#define Z_IS_981_EQ_981(...) \, +#define Z_IS_981U_EQ_981(...) \, +#define Z_IS_981_EQ_981U(...) \, +#define Z_IS_981U_EQ_981U(...) \, +#define Z_IS_982_EQ_982(...) \, +#define Z_IS_982U_EQ_982(...) \, +#define Z_IS_982_EQ_982U(...) \, +#define Z_IS_982U_EQ_982U(...) \, +#define Z_IS_983_EQ_983(...) \, +#define Z_IS_983U_EQ_983(...) \, +#define Z_IS_983_EQ_983U(...) \, +#define Z_IS_983U_EQ_983U(...) \, +#define Z_IS_984_EQ_984(...) \, +#define Z_IS_984U_EQ_984(...) \, +#define Z_IS_984_EQ_984U(...) \, +#define Z_IS_984U_EQ_984U(...) \, +#define Z_IS_985_EQ_985(...) \, +#define Z_IS_985U_EQ_985(...) \, +#define Z_IS_985_EQ_985U(...) \, +#define Z_IS_985U_EQ_985U(...) \, +#define Z_IS_986_EQ_986(...) \, +#define Z_IS_986U_EQ_986(...) \, +#define Z_IS_986_EQ_986U(...) \, +#define Z_IS_986U_EQ_986U(...) \, +#define Z_IS_987_EQ_987(...) \, +#define Z_IS_987U_EQ_987(...) \, +#define Z_IS_987_EQ_987U(...) \, +#define Z_IS_987U_EQ_987U(...) \, +#define Z_IS_988_EQ_988(...) \, +#define Z_IS_988U_EQ_988(...) \, +#define Z_IS_988_EQ_988U(...) \, +#define Z_IS_988U_EQ_988U(...) \, +#define Z_IS_989_EQ_989(...) \, +#define Z_IS_989U_EQ_989(...) \, +#define Z_IS_989_EQ_989U(...) \, +#define Z_IS_989U_EQ_989U(...) \, +#define Z_IS_990_EQ_990(...) \, +#define Z_IS_990U_EQ_990(...) \, +#define Z_IS_990_EQ_990U(...) \, +#define Z_IS_990U_EQ_990U(...) \, +#define Z_IS_991_EQ_991(...) \, +#define Z_IS_991U_EQ_991(...) \, +#define Z_IS_991_EQ_991U(...) \, +#define Z_IS_991U_EQ_991U(...) \, +#define Z_IS_992_EQ_992(...) \, +#define Z_IS_992U_EQ_992(...) \, +#define Z_IS_992_EQ_992U(...) \, +#define Z_IS_992U_EQ_992U(...) \, +#define Z_IS_993_EQ_993(...) \, +#define Z_IS_993U_EQ_993(...) \, +#define Z_IS_993_EQ_993U(...) \, +#define Z_IS_993U_EQ_993U(...) \, +#define Z_IS_994_EQ_994(...) \, +#define Z_IS_994U_EQ_994(...) \, +#define Z_IS_994_EQ_994U(...) \, +#define Z_IS_994U_EQ_994U(...) \, +#define Z_IS_995_EQ_995(...) \, +#define Z_IS_995U_EQ_995(...) \, +#define Z_IS_995_EQ_995U(...) \, +#define Z_IS_995U_EQ_995U(...) \, +#define Z_IS_996_EQ_996(...) \, +#define Z_IS_996U_EQ_996(...) \, +#define Z_IS_996_EQ_996U(...) \, +#define Z_IS_996U_EQ_996U(...) \, +#define Z_IS_997_EQ_997(...) \, +#define Z_IS_997U_EQ_997(...) \, +#define Z_IS_997_EQ_997U(...) \, +#define Z_IS_997U_EQ_997U(...) \, +#define Z_IS_998_EQ_998(...) \, +#define Z_IS_998U_EQ_998(...) \, +#define Z_IS_998_EQ_998U(...) \, +#define Z_IS_998U_EQ_998U(...) \, +#define Z_IS_999_EQ_999(...) \, +#define Z_IS_999U_EQ_999(...) \, +#define Z_IS_999_EQ_999U(...) \, +#define Z_IS_999U_EQ_999U(...) \, +#define Z_IS_1000_EQ_1000(...) \, +#define Z_IS_1000U_EQ_1000(...) \, +#define Z_IS_1000_EQ_1000U(...) \, +#define Z_IS_1000U_EQ_1000U(...) \, +#define Z_IS_1001_EQ_1001(...) \, +#define Z_IS_1001U_EQ_1001(...) \, +#define Z_IS_1001_EQ_1001U(...) \, +#define Z_IS_1001U_EQ_1001U(...) \, +#define Z_IS_1002_EQ_1002(...) \, +#define Z_IS_1002U_EQ_1002(...) \, +#define Z_IS_1002_EQ_1002U(...) \, +#define Z_IS_1002U_EQ_1002U(...) \, +#define Z_IS_1003_EQ_1003(...) \, +#define Z_IS_1003U_EQ_1003(...) \, +#define Z_IS_1003_EQ_1003U(...) \, +#define Z_IS_1003U_EQ_1003U(...) \, +#define Z_IS_1004_EQ_1004(...) \, +#define Z_IS_1004U_EQ_1004(...) \, +#define Z_IS_1004_EQ_1004U(...) \, +#define Z_IS_1004U_EQ_1004U(...) \, +#define Z_IS_1005_EQ_1005(...) \, +#define Z_IS_1005U_EQ_1005(...) \, +#define Z_IS_1005_EQ_1005U(...) \, +#define Z_IS_1005U_EQ_1005U(...) \, +#define Z_IS_1006_EQ_1006(...) \, +#define Z_IS_1006U_EQ_1006(...) \, +#define Z_IS_1006_EQ_1006U(...) \, +#define Z_IS_1006U_EQ_1006U(...) \, +#define Z_IS_1007_EQ_1007(...) \, +#define Z_IS_1007U_EQ_1007(...) \, +#define Z_IS_1007_EQ_1007U(...) \, +#define Z_IS_1007U_EQ_1007U(...) \, +#define Z_IS_1008_EQ_1008(...) \, +#define Z_IS_1008U_EQ_1008(...) \, +#define Z_IS_1008_EQ_1008U(...) \, +#define Z_IS_1008U_EQ_1008U(...) \, +#define Z_IS_1009_EQ_1009(...) \, +#define Z_IS_1009U_EQ_1009(...) \, +#define Z_IS_1009_EQ_1009U(...) \, +#define Z_IS_1009U_EQ_1009U(...) \, +#define Z_IS_1010_EQ_1010(...) \, +#define Z_IS_1010U_EQ_1010(...) \, +#define Z_IS_1010_EQ_1010U(...) \, +#define Z_IS_1010U_EQ_1010U(...) \, +#define Z_IS_1011_EQ_1011(...) \, +#define Z_IS_1011U_EQ_1011(...) \, +#define Z_IS_1011_EQ_1011U(...) \, +#define Z_IS_1011U_EQ_1011U(...) \, +#define Z_IS_1012_EQ_1012(...) \, +#define Z_IS_1012U_EQ_1012(...) \, +#define Z_IS_1012_EQ_1012U(...) \, +#define Z_IS_1012U_EQ_1012U(...) \, +#define Z_IS_1013_EQ_1013(...) \, +#define Z_IS_1013U_EQ_1013(...) \, +#define Z_IS_1013_EQ_1013U(...) \, +#define Z_IS_1013U_EQ_1013U(...) \, +#define Z_IS_1014_EQ_1014(...) \, +#define Z_IS_1014U_EQ_1014(...) \, +#define Z_IS_1014_EQ_1014U(...) \, +#define Z_IS_1014U_EQ_1014U(...) \, +#define Z_IS_1015_EQ_1015(...) \, +#define Z_IS_1015U_EQ_1015(...) \, +#define Z_IS_1015_EQ_1015U(...) \, +#define Z_IS_1015U_EQ_1015U(...) \, +#define Z_IS_1016_EQ_1016(...) \, +#define Z_IS_1016U_EQ_1016(...) \, +#define Z_IS_1016_EQ_1016U(...) \, +#define Z_IS_1016U_EQ_1016U(...) \, +#define Z_IS_1017_EQ_1017(...) \, +#define Z_IS_1017U_EQ_1017(...) \, +#define Z_IS_1017_EQ_1017U(...) \, +#define Z_IS_1017U_EQ_1017U(...) \, +#define Z_IS_1018_EQ_1018(...) \, +#define Z_IS_1018U_EQ_1018(...) \, +#define Z_IS_1018_EQ_1018U(...) \, +#define Z_IS_1018U_EQ_1018U(...) \, +#define Z_IS_1019_EQ_1019(...) \, +#define Z_IS_1019U_EQ_1019(...) \, +#define Z_IS_1019_EQ_1019U(...) \, +#define Z_IS_1019U_EQ_1019U(...) \, +#define Z_IS_1020_EQ_1020(...) \, +#define Z_IS_1020U_EQ_1020(...) \, +#define Z_IS_1020_EQ_1020U(...) \, +#define Z_IS_1020U_EQ_1020U(...) \, +#define Z_IS_1021_EQ_1021(...) \, +#define Z_IS_1021U_EQ_1021(...) \, +#define Z_IS_1021_EQ_1021U(...) \, +#define Z_IS_1021U_EQ_1021U(...) \, +#define Z_IS_1022_EQ_1022(...) \, +#define Z_IS_1022U_EQ_1022(...) \, +#define Z_IS_1022_EQ_1022U(...) \, +#define Z_IS_1022U_EQ_1022U(...) \, +#define Z_IS_1023_EQ_1023(...) \, +#define Z_IS_1023U_EQ_1023(...) \, +#define Z_IS_1023_EQ_1023U(...) \, +#define Z_IS_1023U_EQ_1023U(...) \, +#define Z_IS_1024_EQ_1024(...) \, +#define Z_IS_1024U_EQ_1024(...) \, +#define Z_IS_1024_EQ_1024U(...) \, +#define Z_IS_1024U_EQ_1024U(...) \, +#define Z_IS_1025_EQ_1025(...) \, +#define Z_IS_1025U_EQ_1025(...) \, +#define Z_IS_1025_EQ_1025U(...) \, +#define Z_IS_1025U_EQ_1025U(...) \, +#define Z_IS_1026_EQ_1026(...) \, +#define Z_IS_1026U_EQ_1026(...) \, +#define Z_IS_1026_EQ_1026U(...) \, +#define Z_IS_1026U_EQ_1026U(...) \, +#define Z_IS_1027_EQ_1027(...) \, +#define Z_IS_1027U_EQ_1027(...) \, +#define Z_IS_1027_EQ_1027U(...) \, +#define Z_IS_1027U_EQ_1027U(...) \, +#define Z_IS_1028_EQ_1028(...) \, +#define Z_IS_1028U_EQ_1028(...) \, +#define Z_IS_1028_EQ_1028U(...) \, +#define Z_IS_1028U_EQ_1028U(...) \, +#define Z_IS_1029_EQ_1029(...) \, +#define Z_IS_1029U_EQ_1029(...) \, +#define Z_IS_1029_EQ_1029U(...) \, +#define Z_IS_1029U_EQ_1029U(...) \, +#define Z_IS_1030_EQ_1030(...) \, +#define Z_IS_1030U_EQ_1030(...) \, +#define Z_IS_1030_EQ_1030U(...) \, +#define Z_IS_1030U_EQ_1030U(...) \, +#define Z_IS_1031_EQ_1031(...) \, +#define Z_IS_1031U_EQ_1031(...) \, +#define Z_IS_1031_EQ_1031U(...) \, +#define Z_IS_1031U_EQ_1031U(...) \, +#define Z_IS_1032_EQ_1032(...) \, +#define Z_IS_1032U_EQ_1032(...) \, +#define Z_IS_1032_EQ_1032U(...) \, +#define Z_IS_1032U_EQ_1032U(...) \, +#define Z_IS_1033_EQ_1033(...) \, +#define Z_IS_1033U_EQ_1033(...) \, +#define Z_IS_1033_EQ_1033U(...) \, +#define Z_IS_1033U_EQ_1033U(...) \, +#define Z_IS_1034_EQ_1034(...) \, +#define Z_IS_1034U_EQ_1034(...) \, +#define Z_IS_1034_EQ_1034U(...) \, +#define Z_IS_1034U_EQ_1034U(...) \, +#define Z_IS_1035_EQ_1035(...) \, +#define Z_IS_1035U_EQ_1035(...) \, +#define Z_IS_1035_EQ_1035U(...) \, +#define Z_IS_1035U_EQ_1035U(...) \, +#define Z_IS_1036_EQ_1036(...) \, +#define Z_IS_1036U_EQ_1036(...) \, +#define Z_IS_1036_EQ_1036U(...) \, +#define Z_IS_1036U_EQ_1036U(...) \, +#define Z_IS_1037_EQ_1037(...) \, +#define Z_IS_1037U_EQ_1037(...) \, +#define Z_IS_1037_EQ_1037U(...) \, +#define Z_IS_1037U_EQ_1037U(...) \, +#define Z_IS_1038_EQ_1038(...) \, +#define Z_IS_1038U_EQ_1038(...) \, +#define Z_IS_1038_EQ_1038U(...) \, +#define Z_IS_1038U_EQ_1038U(...) \, +#define Z_IS_1039_EQ_1039(...) \, +#define Z_IS_1039U_EQ_1039(...) \, +#define Z_IS_1039_EQ_1039U(...) \, +#define Z_IS_1039U_EQ_1039U(...) \, +#define Z_IS_1040_EQ_1040(...) \, +#define Z_IS_1040U_EQ_1040(...) \, +#define Z_IS_1040_EQ_1040U(...) \, +#define Z_IS_1040U_EQ_1040U(...) \, +#define Z_IS_1041_EQ_1041(...) \, +#define Z_IS_1041U_EQ_1041(...) \, +#define Z_IS_1041_EQ_1041U(...) \, +#define Z_IS_1041U_EQ_1041U(...) \, +#define Z_IS_1042_EQ_1042(...) \, +#define Z_IS_1042U_EQ_1042(...) \, +#define Z_IS_1042_EQ_1042U(...) \, +#define Z_IS_1042U_EQ_1042U(...) \, +#define Z_IS_1043_EQ_1043(...) \, +#define Z_IS_1043U_EQ_1043(...) \, +#define Z_IS_1043_EQ_1043U(...) \, +#define Z_IS_1043U_EQ_1043U(...) \, +#define Z_IS_1044_EQ_1044(...) \, +#define Z_IS_1044U_EQ_1044(...) \, +#define Z_IS_1044_EQ_1044U(...) \, +#define Z_IS_1044U_EQ_1044U(...) \, +#define Z_IS_1045_EQ_1045(...) \, +#define Z_IS_1045U_EQ_1045(...) \, +#define Z_IS_1045_EQ_1045U(...) \, +#define Z_IS_1045U_EQ_1045U(...) \, +#define Z_IS_1046_EQ_1046(...) \, +#define Z_IS_1046U_EQ_1046(...) \, +#define Z_IS_1046_EQ_1046U(...) \, +#define Z_IS_1046U_EQ_1046U(...) \, +#define Z_IS_1047_EQ_1047(...) \, +#define Z_IS_1047U_EQ_1047(...) \, +#define Z_IS_1047_EQ_1047U(...) \, +#define Z_IS_1047U_EQ_1047U(...) \, +#define Z_IS_1048_EQ_1048(...) \, +#define Z_IS_1048U_EQ_1048(...) \, +#define Z_IS_1048_EQ_1048U(...) \, +#define Z_IS_1048U_EQ_1048U(...) \, +#define Z_IS_1049_EQ_1049(...) \, +#define Z_IS_1049U_EQ_1049(...) \, +#define Z_IS_1049_EQ_1049U(...) \, +#define Z_IS_1049U_EQ_1049U(...) \, +#define Z_IS_1050_EQ_1050(...) \, +#define Z_IS_1050U_EQ_1050(...) \, +#define Z_IS_1050_EQ_1050U(...) \, +#define Z_IS_1050U_EQ_1050U(...) \, +#define Z_IS_1051_EQ_1051(...) \, +#define Z_IS_1051U_EQ_1051(...) \, +#define Z_IS_1051_EQ_1051U(...) \, +#define Z_IS_1051U_EQ_1051U(...) \, +#define Z_IS_1052_EQ_1052(...) \, +#define Z_IS_1052U_EQ_1052(...) \, +#define Z_IS_1052_EQ_1052U(...) \, +#define Z_IS_1052U_EQ_1052U(...) \, +#define Z_IS_1053_EQ_1053(...) \, +#define Z_IS_1053U_EQ_1053(...) \, +#define Z_IS_1053_EQ_1053U(...) \, +#define Z_IS_1053U_EQ_1053U(...) \, +#define Z_IS_1054_EQ_1054(...) \, +#define Z_IS_1054U_EQ_1054(...) \, +#define Z_IS_1054_EQ_1054U(...) \, +#define Z_IS_1054U_EQ_1054U(...) \, +#define Z_IS_1055_EQ_1055(...) \, +#define Z_IS_1055U_EQ_1055(...) \, +#define Z_IS_1055_EQ_1055U(...) \, +#define Z_IS_1055U_EQ_1055U(...) \, +#define Z_IS_1056_EQ_1056(...) \, +#define Z_IS_1056U_EQ_1056(...) \, +#define Z_IS_1056_EQ_1056U(...) \, +#define Z_IS_1056U_EQ_1056U(...) \, +#define Z_IS_1057_EQ_1057(...) \, +#define Z_IS_1057U_EQ_1057(...) \, +#define Z_IS_1057_EQ_1057U(...) \, +#define Z_IS_1057U_EQ_1057U(...) \, +#define Z_IS_1058_EQ_1058(...) \, +#define Z_IS_1058U_EQ_1058(...) \, +#define Z_IS_1058_EQ_1058U(...) \, +#define Z_IS_1058U_EQ_1058U(...) \, +#define Z_IS_1059_EQ_1059(...) \, +#define Z_IS_1059U_EQ_1059(...) \, +#define Z_IS_1059_EQ_1059U(...) \, +#define Z_IS_1059U_EQ_1059U(...) \, +#define Z_IS_1060_EQ_1060(...) \, +#define Z_IS_1060U_EQ_1060(...) \, +#define Z_IS_1060_EQ_1060U(...) \, +#define Z_IS_1060U_EQ_1060U(...) \, +#define Z_IS_1061_EQ_1061(...) \, +#define Z_IS_1061U_EQ_1061(...) \, +#define Z_IS_1061_EQ_1061U(...) \, +#define Z_IS_1061U_EQ_1061U(...) \, +#define Z_IS_1062_EQ_1062(...) \, +#define Z_IS_1062U_EQ_1062(...) \, +#define Z_IS_1062_EQ_1062U(...) \, +#define Z_IS_1062U_EQ_1062U(...) \, +#define Z_IS_1063_EQ_1063(...) \, +#define Z_IS_1063U_EQ_1063(...) \, +#define Z_IS_1063_EQ_1063U(...) \, +#define Z_IS_1063U_EQ_1063U(...) \, +#define Z_IS_1064_EQ_1064(...) \, +#define Z_IS_1064U_EQ_1064(...) \, +#define Z_IS_1064_EQ_1064U(...) \, +#define Z_IS_1064U_EQ_1064U(...) \, +#define Z_IS_1065_EQ_1065(...) \, +#define Z_IS_1065U_EQ_1065(...) \, +#define Z_IS_1065_EQ_1065U(...) \, +#define Z_IS_1065U_EQ_1065U(...) \, +#define Z_IS_1066_EQ_1066(...) \, +#define Z_IS_1066U_EQ_1066(...) \, +#define Z_IS_1066_EQ_1066U(...) \, +#define Z_IS_1066U_EQ_1066U(...) \, +#define Z_IS_1067_EQ_1067(...) \, +#define Z_IS_1067U_EQ_1067(...) \, +#define Z_IS_1067_EQ_1067U(...) \, +#define Z_IS_1067U_EQ_1067U(...) \, +#define Z_IS_1068_EQ_1068(...) \, +#define Z_IS_1068U_EQ_1068(...) \, +#define Z_IS_1068_EQ_1068U(...) \, +#define Z_IS_1068U_EQ_1068U(...) \, +#define Z_IS_1069_EQ_1069(...) \, +#define Z_IS_1069U_EQ_1069(...) \, +#define Z_IS_1069_EQ_1069U(...) \, +#define Z_IS_1069U_EQ_1069U(...) \, +#define Z_IS_1070_EQ_1070(...) \, +#define Z_IS_1070U_EQ_1070(...) \, +#define Z_IS_1070_EQ_1070U(...) \, +#define Z_IS_1070U_EQ_1070U(...) \, +#define Z_IS_1071_EQ_1071(...) \, +#define Z_IS_1071U_EQ_1071(...) \, +#define Z_IS_1071_EQ_1071U(...) \, +#define Z_IS_1071U_EQ_1071U(...) \, +#define Z_IS_1072_EQ_1072(...) \, +#define Z_IS_1072U_EQ_1072(...) \, +#define Z_IS_1072_EQ_1072U(...) \, +#define Z_IS_1072U_EQ_1072U(...) \, +#define Z_IS_1073_EQ_1073(...) \, +#define Z_IS_1073U_EQ_1073(...) \, +#define Z_IS_1073_EQ_1073U(...) \, +#define Z_IS_1073U_EQ_1073U(...) \, +#define Z_IS_1074_EQ_1074(...) \, +#define Z_IS_1074U_EQ_1074(...) \, +#define Z_IS_1074_EQ_1074U(...) \, +#define Z_IS_1074U_EQ_1074U(...) \, +#define Z_IS_1075_EQ_1075(...) \, +#define Z_IS_1075U_EQ_1075(...) \, +#define Z_IS_1075_EQ_1075U(...) \, +#define Z_IS_1075U_EQ_1075U(...) \, +#define Z_IS_1076_EQ_1076(...) \, +#define Z_IS_1076U_EQ_1076(...) \, +#define Z_IS_1076_EQ_1076U(...) \, +#define Z_IS_1076U_EQ_1076U(...) \, +#define Z_IS_1077_EQ_1077(...) \, +#define Z_IS_1077U_EQ_1077(...) \, +#define Z_IS_1077_EQ_1077U(...) \, +#define Z_IS_1077U_EQ_1077U(...) \, +#define Z_IS_1078_EQ_1078(...) \, +#define Z_IS_1078U_EQ_1078(...) \, +#define Z_IS_1078_EQ_1078U(...) \, +#define Z_IS_1078U_EQ_1078U(...) \, +#define Z_IS_1079_EQ_1079(...) \, +#define Z_IS_1079U_EQ_1079(...) \, +#define Z_IS_1079_EQ_1079U(...) \, +#define Z_IS_1079U_EQ_1079U(...) \, +#define Z_IS_1080_EQ_1080(...) \, +#define Z_IS_1080U_EQ_1080(...) \, +#define Z_IS_1080_EQ_1080U(...) \, +#define Z_IS_1080U_EQ_1080U(...) \, +#define Z_IS_1081_EQ_1081(...) \, +#define Z_IS_1081U_EQ_1081(...) \, +#define Z_IS_1081_EQ_1081U(...) \, +#define Z_IS_1081U_EQ_1081U(...) \, +#define Z_IS_1082_EQ_1082(...) \, +#define Z_IS_1082U_EQ_1082(...) \, +#define Z_IS_1082_EQ_1082U(...) \, +#define Z_IS_1082U_EQ_1082U(...) \, +#define Z_IS_1083_EQ_1083(...) \, +#define Z_IS_1083U_EQ_1083(...) \, +#define Z_IS_1083_EQ_1083U(...) \, +#define Z_IS_1083U_EQ_1083U(...) \, +#define Z_IS_1084_EQ_1084(...) \, +#define Z_IS_1084U_EQ_1084(...) \, +#define Z_IS_1084_EQ_1084U(...) \, +#define Z_IS_1084U_EQ_1084U(...) \, +#define Z_IS_1085_EQ_1085(...) \, +#define Z_IS_1085U_EQ_1085(...) \, +#define Z_IS_1085_EQ_1085U(...) \, +#define Z_IS_1085U_EQ_1085U(...) \, +#define Z_IS_1086_EQ_1086(...) \, +#define Z_IS_1086U_EQ_1086(...) \, +#define Z_IS_1086_EQ_1086U(...) \, +#define Z_IS_1086U_EQ_1086U(...) \, +#define Z_IS_1087_EQ_1087(...) \, +#define Z_IS_1087U_EQ_1087(...) \, +#define Z_IS_1087_EQ_1087U(...) \, +#define Z_IS_1087U_EQ_1087U(...) \, +#define Z_IS_1088_EQ_1088(...) \, +#define Z_IS_1088U_EQ_1088(...) \, +#define Z_IS_1088_EQ_1088U(...) \, +#define Z_IS_1088U_EQ_1088U(...) \, +#define Z_IS_1089_EQ_1089(...) \, +#define Z_IS_1089U_EQ_1089(...) \, +#define Z_IS_1089_EQ_1089U(...) \, +#define Z_IS_1089U_EQ_1089U(...) \, +#define Z_IS_1090_EQ_1090(...) \, +#define Z_IS_1090U_EQ_1090(...) \, +#define Z_IS_1090_EQ_1090U(...) \, +#define Z_IS_1090U_EQ_1090U(...) \, +#define Z_IS_1091_EQ_1091(...) \, +#define Z_IS_1091U_EQ_1091(...) \, +#define Z_IS_1091_EQ_1091U(...) \, +#define Z_IS_1091U_EQ_1091U(...) \, +#define Z_IS_1092_EQ_1092(...) \, +#define Z_IS_1092U_EQ_1092(...) \, +#define Z_IS_1092_EQ_1092U(...) \, +#define Z_IS_1092U_EQ_1092U(...) \, +#define Z_IS_1093_EQ_1093(...) \, +#define Z_IS_1093U_EQ_1093(...) \, +#define Z_IS_1093_EQ_1093U(...) \, +#define Z_IS_1093U_EQ_1093U(...) \, +#define Z_IS_1094_EQ_1094(...) \, +#define Z_IS_1094U_EQ_1094(...) \, +#define Z_IS_1094_EQ_1094U(...) \, +#define Z_IS_1094U_EQ_1094U(...) \, +#define Z_IS_1095_EQ_1095(...) \, +#define Z_IS_1095U_EQ_1095(...) \, +#define Z_IS_1095_EQ_1095U(...) \, +#define Z_IS_1095U_EQ_1095U(...) \, +#define Z_IS_1096_EQ_1096(...) \, +#define Z_IS_1096U_EQ_1096(...) \, +#define Z_IS_1096_EQ_1096U(...) \, +#define Z_IS_1096U_EQ_1096U(...) \, +#define Z_IS_1097_EQ_1097(...) \, +#define Z_IS_1097U_EQ_1097(...) \, +#define Z_IS_1097_EQ_1097U(...) \, +#define Z_IS_1097U_EQ_1097U(...) \, +#define Z_IS_1098_EQ_1098(...) \, +#define Z_IS_1098U_EQ_1098(...) \, +#define Z_IS_1098_EQ_1098U(...) \, +#define Z_IS_1098U_EQ_1098U(...) \, +#define Z_IS_1099_EQ_1099(...) \, +#define Z_IS_1099U_EQ_1099(...) \, +#define Z_IS_1099_EQ_1099U(...) \, +#define Z_IS_1099U_EQ_1099U(...) \, +#define Z_IS_1100_EQ_1100(...) \, +#define Z_IS_1100U_EQ_1100(...) \, +#define Z_IS_1100_EQ_1100U(...) \, +#define Z_IS_1100U_EQ_1100U(...) \, +#define Z_IS_1101_EQ_1101(...) \, +#define Z_IS_1101U_EQ_1101(...) \, +#define Z_IS_1101_EQ_1101U(...) \, +#define Z_IS_1101U_EQ_1101U(...) \, +#define Z_IS_1102_EQ_1102(...) \, +#define Z_IS_1102U_EQ_1102(...) \, +#define Z_IS_1102_EQ_1102U(...) \, +#define Z_IS_1102U_EQ_1102U(...) \, +#define Z_IS_1103_EQ_1103(...) \, +#define Z_IS_1103U_EQ_1103(...) \, +#define Z_IS_1103_EQ_1103U(...) \, +#define Z_IS_1103U_EQ_1103U(...) \, +#define Z_IS_1104_EQ_1104(...) \, +#define Z_IS_1104U_EQ_1104(...) \, +#define Z_IS_1104_EQ_1104U(...) \, +#define Z_IS_1104U_EQ_1104U(...) \, +#define Z_IS_1105_EQ_1105(...) \, +#define Z_IS_1105U_EQ_1105(...) \, +#define Z_IS_1105_EQ_1105U(...) \, +#define Z_IS_1105U_EQ_1105U(...) \, +#define Z_IS_1106_EQ_1106(...) \, +#define Z_IS_1106U_EQ_1106(...) \, +#define Z_IS_1106_EQ_1106U(...) \, +#define Z_IS_1106U_EQ_1106U(...) \, +#define Z_IS_1107_EQ_1107(...) \, +#define Z_IS_1107U_EQ_1107(...) \, +#define Z_IS_1107_EQ_1107U(...) \, +#define Z_IS_1107U_EQ_1107U(...) \, +#define Z_IS_1108_EQ_1108(...) \, +#define Z_IS_1108U_EQ_1108(...) \, +#define Z_IS_1108_EQ_1108U(...) \, +#define Z_IS_1108U_EQ_1108U(...) \, +#define Z_IS_1109_EQ_1109(...) \, +#define Z_IS_1109U_EQ_1109(...) \, +#define Z_IS_1109_EQ_1109U(...) \, +#define Z_IS_1109U_EQ_1109U(...) \, +#define Z_IS_1110_EQ_1110(...) \, +#define Z_IS_1110U_EQ_1110(...) \, +#define Z_IS_1110_EQ_1110U(...) \, +#define Z_IS_1110U_EQ_1110U(...) \, +#define Z_IS_1111_EQ_1111(...) \, +#define Z_IS_1111U_EQ_1111(...) \, +#define Z_IS_1111_EQ_1111U(...) \, +#define Z_IS_1111U_EQ_1111U(...) \, +#define Z_IS_1112_EQ_1112(...) \, +#define Z_IS_1112U_EQ_1112(...) \, +#define Z_IS_1112_EQ_1112U(...) \, +#define Z_IS_1112U_EQ_1112U(...) \, +#define Z_IS_1113_EQ_1113(...) \, +#define Z_IS_1113U_EQ_1113(...) \, +#define Z_IS_1113_EQ_1113U(...) \, +#define Z_IS_1113U_EQ_1113U(...) \, +#define Z_IS_1114_EQ_1114(...) \, +#define Z_IS_1114U_EQ_1114(...) \, +#define Z_IS_1114_EQ_1114U(...) \, +#define Z_IS_1114U_EQ_1114U(...) \, +#define Z_IS_1115_EQ_1115(...) \, +#define Z_IS_1115U_EQ_1115(...) \, +#define Z_IS_1115_EQ_1115U(...) \, +#define Z_IS_1115U_EQ_1115U(...) \, +#define Z_IS_1116_EQ_1116(...) \, +#define Z_IS_1116U_EQ_1116(...) \, +#define Z_IS_1116_EQ_1116U(...) \, +#define Z_IS_1116U_EQ_1116U(...) \, +#define Z_IS_1117_EQ_1117(...) \, +#define Z_IS_1117U_EQ_1117(...) \, +#define Z_IS_1117_EQ_1117U(...) \, +#define Z_IS_1117U_EQ_1117U(...) \, +#define Z_IS_1118_EQ_1118(...) \, +#define Z_IS_1118U_EQ_1118(...) \, +#define Z_IS_1118_EQ_1118U(...) \, +#define Z_IS_1118U_EQ_1118U(...) \, +#define Z_IS_1119_EQ_1119(...) \, +#define Z_IS_1119U_EQ_1119(...) \, +#define Z_IS_1119_EQ_1119U(...) \, +#define Z_IS_1119U_EQ_1119U(...) \, +#define Z_IS_1120_EQ_1120(...) \, +#define Z_IS_1120U_EQ_1120(...) \, +#define Z_IS_1120_EQ_1120U(...) \, +#define Z_IS_1120U_EQ_1120U(...) \, +#define Z_IS_1121_EQ_1121(...) \, +#define Z_IS_1121U_EQ_1121(...) \, +#define Z_IS_1121_EQ_1121U(...) \, +#define Z_IS_1121U_EQ_1121U(...) \, +#define Z_IS_1122_EQ_1122(...) \, +#define Z_IS_1122U_EQ_1122(...) \, +#define Z_IS_1122_EQ_1122U(...) \, +#define Z_IS_1122U_EQ_1122U(...) \, +#define Z_IS_1123_EQ_1123(...) \, +#define Z_IS_1123U_EQ_1123(...) \, +#define Z_IS_1123_EQ_1123U(...) \, +#define Z_IS_1123U_EQ_1123U(...) \, +#define Z_IS_1124_EQ_1124(...) \, +#define Z_IS_1124U_EQ_1124(...) \, +#define Z_IS_1124_EQ_1124U(...) \, +#define Z_IS_1124U_EQ_1124U(...) \, +#define Z_IS_1125_EQ_1125(...) \, +#define Z_IS_1125U_EQ_1125(...) \, +#define Z_IS_1125_EQ_1125U(...) \, +#define Z_IS_1125U_EQ_1125U(...) \, +#define Z_IS_1126_EQ_1126(...) \, +#define Z_IS_1126U_EQ_1126(...) \, +#define Z_IS_1126_EQ_1126U(...) \, +#define Z_IS_1126U_EQ_1126U(...) \, +#define Z_IS_1127_EQ_1127(...) \, +#define Z_IS_1127U_EQ_1127(...) \, +#define Z_IS_1127_EQ_1127U(...) \, +#define Z_IS_1127U_EQ_1127U(...) \, +#define Z_IS_1128_EQ_1128(...) \, +#define Z_IS_1128U_EQ_1128(...) \, +#define Z_IS_1128_EQ_1128U(...) \, +#define Z_IS_1128U_EQ_1128U(...) \, +#define Z_IS_1129_EQ_1129(...) \, +#define Z_IS_1129U_EQ_1129(...) \, +#define Z_IS_1129_EQ_1129U(...) \, +#define Z_IS_1129U_EQ_1129U(...) \, +#define Z_IS_1130_EQ_1130(...) \, +#define Z_IS_1130U_EQ_1130(...) \, +#define Z_IS_1130_EQ_1130U(...) \, +#define Z_IS_1130U_EQ_1130U(...) \, +#define Z_IS_1131_EQ_1131(...) \, +#define Z_IS_1131U_EQ_1131(...) \, +#define Z_IS_1131_EQ_1131U(...) \, +#define Z_IS_1131U_EQ_1131U(...) \, +#define Z_IS_1132_EQ_1132(...) \, +#define Z_IS_1132U_EQ_1132(...) \, +#define Z_IS_1132_EQ_1132U(...) \, +#define Z_IS_1132U_EQ_1132U(...) \, +#define Z_IS_1133_EQ_1133(...) \, +#define Z_IS_1133U_EQ_1133(...) \, +#define Z_IS_1133_EQ_1133U(...) \, +#define Z_IS_1133U_EQ_1133U(...) \, +#define Z_IS_1134_EQ_1134(...) \, +#define Z_IS_1134U_EQ_1134(...) \, +#define Z_IS_1134_EQ_1134U(...) \, +#define Z_IS_1134U_EQ_1134U(...) \, +#define Z_IS_1135_EQ_1135(...) \, +#define Z_IS_1135U_EQ_1135(...) \, +#define Z_IS_1135_EQ_1135U(...) \, +#define Z_IS_1135U_EQ_1135U(...) \, +#define Z_IS_1136_EQ_1136(...) \, +#define Z_IS_1136U_EQ_1136(...) \, +#define Z_IS_1136_EQ_1136U(...) \, +#define Z_IS_1136U_EQ_1136U(...) \, +#define Z_IS_1137_EQ_1137(...) \, +#define Z_IS_1137U_EQ_1137(...) \, +#define Z_IS_1137_EQ_1137U(...) \, +#define Z_IS_1137U_EQ_1137U(...) \, +#define Z_IS_1138_EQ_1138(...) \, +#define Z_IS_1138U_EQ_1138(...) \, +#define Z_IS_1138_EQ_1138U(...) \, +#define Z_IS_1138U_EQ_1138U(...) \, +#define Z_IS_1139_EQ_1139(...) \, +#define Z_IS_1139U_EQ_1139(...) \, +#define Z_IS_1139_EQ_1139U(...) \, +#define Z_IS_1139U_EQ_1139U(...) \, +#define Z_IS_1140_EQ_1140(...) \, +#define Z_IS_1140U_EQ_1140(...) \, +#define Z_IS_1140_EQ_1140U(...) \, +#define Z_IS_1140U_EQ_1140U(...) \, +#define Z_IS_1141_EQ_1141(...) \, +#define Z_IS_1141U_EQ_1141(...) \, +#define Z_IS_1141_EQ_1141U(...) \, +#define Z_IS_1141U_EQ_1141U(...) \, +#define Z_IS_1142_EQ_1142(...) \, +#define Z_IS_1142U_EQ_1142(...) \, +#define Z_IS_1142_EQ_1142U(...) \, +#define Z_IS_1142U_EQ_1142U(...) \, +#define Z_IS_1143_EQ_1143(...) \, +#define Z_IS_1143U_EQ_1143(...) \, +#define Z_IS_1143_EQ_1143U(...) \, +#define Z_IS_1143U_EQ_1143U(...) \, +#define Z_IS_1144_EQ_1144(...) \, +#define Z_IS_1144U_EQ_1144(...) \, +#define Z_IS_1144_EQ_1144U(...) \, +#define Z_IS_1144U_EQ_1144U(...) \, +#define Z_IS_1145_EQ_1145(...) \, +#define Z_IS_1145U_EQ_1145(...) \, +#define Z_IS_1145_EQ_1145U(...) \, +#define Z_IS_1145U_EQ_1145U(...) \, +#define Z_IS_1146_EQ_1146(...) \, +#define Z_IS_1146U_EQ_1146(...) \, +#define Z_IS_1146_EQ_1146U(...) \, +#define Z_IS_1146U_EQ_1146U(...) \, +#define Z_IS_1147_EQ_1147(...) \, +#define Z_IS_1147U_EQ_1147(...) \, +#define Z_IS_1147_EQ_1147U(...) \, +#define Z_IS_1147U_EQ_1147U(...) \, +#define Z_IS_1148_EQ_1148(...) \, +#define Z_IS_1148U_EQ_1148(...) \, +#define Z_IS_1148_EQ_1148U(...) \, +#define Z_IS_1148U_EQ_1148U(...) \, +#define Z_IS_1149_EQ_1149(...) \, +#define Z_IS_1149U_EQ_1149(...) \, +#define Z_IS_1149_EQ_1149U(...) \, +#define Z_IS_1149U_EQ_1149U(...) \, +#define Z_IS_1150_EQ_1150(...) \, +#define Z_IS_1150U_EQ_1150(...) \, +#define Z_IS_1150_EQ_1150U(...) \, +#define Z_IS_1150U_EQ_1150U(...) \, +#define Z_IS_1151_EQ_1151(...) \, +#define Z_IS_1151U_EQ_1151(...) \, +#define Z_IS_1151_EQ_1151U(...) \, +#define Z_IS_1151U_EQ_1151U(...) \, +#define Z_IS_1152_EQ_1152(...) \, +#define Z_IS_1152U_EQ_1152(...) \, +#define Z_IS_1152_EQ_1152U(...) \, +#define Z_IS_1152U_EQ_1152U(...) \, +#define Z_IS_1153_EQ_1153(...) \, +#define Z_IS_1153U_EQ_1153(...) \, +#define Z_IS_1153_EQ_1153U(...) \, +#define Z_IS_1153U_EQ_1153U(...) \, +#define Z_IS_1154_EQ_1154(...) \, +#define Z_IS_1154U_EQ_1154(...) \, +#define Z_IS_1154_EQ_1154U(...) \, +#define Z_IS_1154U_EQ_1154U(...) \, +#define Z_IS_1155_EQ_1155(...) \, +#define Z_IS_1155U_EQ_1155(...) \, +#define Z_IS_1155_EQ_1155U(...) \, +#define Z_IS_1155U_EQ_1155U(...) \, +#define Z_IS_1156_EQ_1156(...) \, +#define Z_IS_1156U_EQ_1156(...) \, +#define Z_IS_1156_EQ_1156U(...) \, +#define Z_IS_1156U_EQ_1156U(...) \, +#define Z_IS_1157_EQ_1157(...) \, +#define Z_IS_1157U_EQ_1157(...) \, +#define Z_IS_1157_EQ_1157U(...) \, +#define Z_IS_1157U_EQ_1157U(...) \, +#define Z_IS_1158_EQ_1158(...) \, +#define Z_IS_1158U_EQ_1158(...) \, +#define Z_IS_1158_EQ_1158U(...) \, +#define Z_IS_1158U_EQ_1158U(...) \, +#define Z_IS_1159_EQ_1159(...) \, +#define Z_IS_1159U_EQ_1159(...) \, +#define Z_IS_1159_EQ_1159U(...) \, +#define Z_IS_1159U_EQ_1159U(...) \, +#define Z_IS_1160_EQ_1160(...) \, +#define Z_IS_1160U_EQ_1160(...) \, +#define Z_IS_1160_EQ_1160U(...) \, +#define Z_IS_1160U_EQ_1160U(...) \, +#define Z_IS_1161_EQ_1161(...) \, +#define Z_IS_1161U_EQ_1161(...) \, +#define Z_IS_1161_EQ_1161U(...) \, +#define Z_IS_1161U_EQ_1161U(...) \, +#define Z_IS_1162_EQ_1162(...) \, +#define Z_IS_1162U_EQ_1162(...) \, +#define Z_IS_1162_EQ_1162U(...) \, +#define Z_IS_1162U_EQ_1162U(...) \, +#define Z_IS_1163_EQ_1163(...) \, +#define Z_IS_1163U_EQ_1163(...) \, +#define Z_IS_1163_EQ_1163U(...) \, +#define Z_IS_1163U_EQ_1163U(...) \, +#define Z_IS_1164_EQ_1164(...) \, +#define Z_IS_1164U_EQ_1164(...) \, +#define Z_IS_1164_EQ_1164U(...) \, +#define Z_IS_1164U_EQ_1164U(...) \, +#define Z_IS_1165_EQ_1165(...) \, +#define Z_IS_1165U_EQ_1165(...) \, +#define Z_IS_1165_EQ_1165U(...) \, +#define Z_IS_1165U_EQ_1165U(...) \, +#define Z_IS_1166_EQ_1166(...) \, +#define Z_IS_1166U_EQ_1166(...) \, +#define Z_IS_1166_EQ_1166U(...) \, +#define Z_IS_1166U_EQ_1166U(...) \, +#define Z_IS_1167_EQ_1167(...) \, +#define Z_IS_1167U_EQ_1167(...) \, +#define Z_IS_1167_EQ_1167U(...) \, +#define Z_IS_1167U_EQ_1167U(...) \, +#define Z_IS_1168_EQ_1168(...) \, +#define Z_IS_1168U_EQ_1168(...) \, +#define Z_IS_1168_EQ_1168U(...) \, +#define Z_IS_1168U_EQ_1168U(...) \, +#define Z_IS_1169_EQ_1169(...) \, +#define Z_IS_1169U_EQ_1169(...) \, +#define Z_IS_1169_EQ_1169U(...) \, +#define Z_IS_1169U_EQ_1169U(...) \, +#define Z_IS_1170_EQ_1170(...) \, +#define Z_IS_1170U_EQ_1170(...) \, +#define Z_IS_1170_EQ_1170U(...) \, +#define Z_IS_1170U_EQ_1170U(...) \, +#define Z_IS_1171_EQ_1171(...) \, +#define Z_IS_1171U_EQ_1171(...) \, +#define Z_IS_1171_EQ_1171U(...) \, +#define Z_IS_1171U_EQ_1171U(...) \, +#define Z_IS_1172_EQ_1172(...) \, +#define Z_IS_1172U_EQ_1172(...) \, +#define Z_IS_1172_EQ_1172U(...) \, +#define Z_IS_1172U_EQ_1172U(...) \, +#define Z_IS_1173_EQ_1173(...) \, +#define Z_IS_1173U_EQ_1173(...) \, +#define Z_IS_1173_EQ_1173U(...) \, +#define Z_IS_1173U_EQ_1173U(...) \, +#define Z_IS_1174_EQ_1174(...) \, +#define Z_IS_1174U_EQ_1174(...) \, +#define Z_IS_1174_EQ_1174U(...) \, +#define Z_IS_1174U_EQ_1174U(...) \, +#define Z_IS_1175_EQ_1175(...) \, +#define Z_IS_1175U_EQ_1175(...) \, +#define Z_IS_1175_EQ_1175U(...) \, +#define Z_IS_1175U_EQ_1175U(...) \, +#define Z_IS_1176_EQ_1176(...) \, +#define Z_IS_1176U_EQ_1176(...) \, +#define Z_IS_1176_EQ_1176U(...) \, +#define Z_IS_1176U_EQ_1176U(...) \, +#define Z_IS_1177_EQ_1177(...) \, +#define Z_IS_1177U_EQ_1177(...) \, +#define Z_IS_1177_EQ_1177U(...) \, +#define Z_IS_1177U_EQ_1177U(...) \, +#define Z_IS_1178_EQ_1178(...) \, +#define Z_IS_1178U_EQ_1178(...) \, +#define Z_IS_1178_EQ_1178U(...) \, +#define Z_IS_1178U_EQ_1178U(...) \, +#define Z_IS_1179_EQ_1179(...) \, +#define Z_IS_1179U_EQ_1179(...) \, +#define Z_IS_1179_EQ_1179U(...) \, +#define Z_IS_1179U_EQ_1179U(...) \, +#define Z_IS_1180_EQ_1180(...) \, +#define Z_IS_1180U_EQ_1180(...) \, +#define Z_IS_1180_EQ_1180U(...) \, +#define Z_IS_1180U_EQ_1180U(...) \, +#define Z_IS_1181_EQ_1181(...) \, +#define Z_IS_1181U_EQ_1181(...) \, +#define Z_IS_1181_EQ_1181U(...) \, +#define Z_IS_1181U_EQ_1181U(...) \, +#define Z_IS_1182_EQ_1182(...) \, +#define Z_IS_1182U_EQ_1182(...) \, +#define Z_IS_1182_EQ_1182U(...) \, +#define Z_IS_1182U_EQ_1182U(...) \, +#define Z_IS_1183_EQ_1183(...) \, +#define Z_IS_1183U_EQ_1183(...) \, +#define Z_IS_1183_EQ_1183U(...) \, +#define Z_IS_1183U_EQ_1183U(...) \, +#define Z_IS_1184_EQ_1184(...) \, +#define Z_IS_1184U_EQ_1184(...) \, +#define Z_IS_1184_EQ_1184U(...) \, +#define Z_IS_1184U_EQ_1184U(...) \, +#define Z_IS_1185_EQ_1185(...) \, +#define Z_IS_1185U_EQ_1185(...) \, +#define Z_IS_1185_EQ_1185U(...) \, +#define Z_IS_1185U_EQ_1185U(...) \, +#define Z_IS_1186_EQ_1186(...) \, +#define Z_IS_1186U_EQ_1186(...) \, +#define Z_IS_1186_EQ_1186U(...) \, +#define Z_IS_1186U_EQ_1186U(...) \, +#define Z_IS_1187_EQ_1187(...) \, +#define Z_IS_1187U_EQ_1187(...) \, +#define Z_IS_1187_EQ_1187U(...) \, +#define Z_IS_1187U_EQ_1187U(...) \, +#define Z_IS_1188_EQ_1188(...) \, +#define Z_IS_1188U_EQ_1188(...) \, +#define Z_IS_1188_EQ_1188U(...) \, +#define Z_IS_1188U_EQ_1188U(...) \, +#define Z_IS_1189_EQ_1189(...) \, +#define Z_IS_1189U_EQ_1189(...) \, +#define Z_IS_1189_EQ_1189U(...) \, +#define Z_IS_1189U_EQ_1189U(...) \, +#define Z_IS_1190_EQ_1190(...) \, +#define Z_IS_1190U_EQ_1190(...) \, +#define Z_IS_1190_EQ_1190U(...) \, +#define Z_IS_1190U_EQ_1190U(...) \, +#define Z_IS_1191_EQ_1191(...) \, +#define Z_IS_1191U_EQ_1191(...) \, +#define Z_IS_1191_EQ_1191U(...) \, +#define Z_IS_1191U_EQ_1191U(...) \, +#define Z_IS_1192_EQ_1192(...) \, +#define Z_IS_1192U_EQ_1192(...) \, +#define Z_IS_1192_EQ_1192U(...) \, +#define Z_IS_1192U_EQ_1192U(...) \, +#define Z_IS_1193_EQ_1193(...) \, +#define Z_IS_1193U_EQ_1193(...) \, +#define Z_IS_1193_EQ_1193U(...) \, +#define Z_IS_1193U_EQ_1193U(...) \, +#define Z_IS_1194_EQ_1194(...) \, +#define Z_IS_1194U_EQ_1194(...) \, +#define Z_IS_1194_EQ_1194U(...) \, +#define Z_IS_1194U_EQ_1194U(...) \, +#define Z_IS_1195_EQ_1195(...) \, +#define Z_IS_1195U_EQ_1195(...) \, +#define Z_IS_1195_EQ_1195U(...) \, +#define Z_IS_1195U_EQ_1195U(...) \, +#define Z_IS_1196_EQ_1196(...) \, +#define Z_IS_1196U_EQ_1196(...) \, +#define Z_IS_1196_EQ_1196U(...) \, +#define Z_IS_1196U_EQ_1196U(...) \, +#define Z_IS_1197_EQ_1197(...) \, +#define Z_IS_1197U_EQ_1197(...) \, +#define Z_IS_1197_EQ_1197U(...) \, +#define Z_IS_1197U_EQ_1197U(...) \, +#define Z_IS_1198_EQ_1198(...) \, +#define Z_IS_1198U_EQ_1198(...) \, +#define Z_IS_1198_EQ_1198U(...) \, +#define Z_IS_1198U_EQ_1198U(...) \, +#define Z_IS_1199_EQ_1199(...) \, +#define Z_IS_1199U_EQ_1199(...) \, +#define Z_IS_1199_EQ_1199U(...) \, +#define Z_IS_1199U_EQ_1199U(...) \, +#define Z_IS_1200_EQ_1200(...) \, +#define Z_IS_1200U_EQ_1200(...) \, +#define Z_IS_1200_EQ_1200U(...) \, +#define Z_IS_1200U_EQ_1200U(...) \, +#define Z_IS_1201_EQ_1201(...) \, +#define Z_IS_1201U_EQ_1201(...) \, +#define Z_IS_1201_EQ_1201U(...) \, +#define Z_IS_1201U_EQ_1201U(...) \, +#define Z_IS_1202_EQ_1202(...) \, +#define Z_IS_1202U_EQ_1202(...) \, +#define Z_IS_1202_EQ_1202U(...) \, +#define Z_IS_1202U_EQ_1202U(...) \, +#define Z_IS_1203_EQ_1203(...) \, +#define Z_IS_1203U_EQ_1203(...) \, +#define Z_IS_1203_EQ_1203U(...) \, +#define Z_IS_1203U_EQ_1203U(...) \, +#define Z_IS_1204_EQ_1204(...) \, +#define Z_IS_1204U_EQ_1204(...) \, +#define Z_IS_1204_EQ_1204U(...) \, +#define Z_IS_1204U_EQ_1204U(...) \, +#define Z_IS_1205_EQ_1205(...) \, +#define Z_IS_1205U_EQ_1205(...) \, +#define Z_IS_1205_EQ_1205U(...) \, +#define Z_IS_1205U_EQ_1205U(...) \, +#define Z_IS_1206_EQ_1206(...) \, +#define Z_IS_1206U_EQ_1206(...) \, +#define Z_IS_1206_EQ_1206U(...) \, +#define Z_IS_1206U_EQ_1206U(...) \, +#define Z_IS_1207_EQ_1207(...) \, +#define Z_IS_1207U_EQ_1207(...) \, +#define Z_IS_1207_EQ_1207U(...) \, +#define Z_IS_1207U_EQ_1207U(...) \, +#define Z_IS_1208_EQ_1208(...) \, +#define Z_IS_1208U_EQ_1208(...) \, +#define Z_IS_1208_EQ_1208U(...) \, +#define Z_IS_1208U_EQ_1208U(...) \, +#define Z_IS_1209_EQ_1209(...) \, +#define Z_IS_1209U_EQ_1209(...) \, +#define Z_IS_1209_EQ_1209U(...) \, +#define Z_IS_1209U_EQ_1209U(...) \, +#define Z_IS_1210_EQ_1210(...) \, +#define Z_IS_1210U_EQ_1210(...) \, +#define Z_IS_1210_EQ_1210U(...) \, +#define Z_IS_1210U_EQ_1210U(...) \, +#define Z_IS_1211_EQ_1211(...) \, +#define Z_IS_1211U_EQ_1211(...) \, +#define Z_IS_1211_EQ_1211U(...) \, +#define Z_IS_1211U_EQ_1211U(...) \, +#define Z_IS_1212_EQ_1212(...) \, +#define Z_IS_1212U_EQ_1212(...) \, +#define Z_IS_1212_EQ_1212U(...) \, +#define Z_IS_1212U_EQ_1212U(...) \, +#define Z_IS_1213_EQ_1213(...) \, +#define Z_IS_1213U_EQ_1213(...) \, +#define Z_IS_1213_EQ_1213U(...) \, +#define Z_IS_1213U_EQ_1213U(...) \, +#define Z_IS_1214_EQ_1214(...) \, +#define Z_IS_1214U_EQ_1214(...) \, +#define Z_IS_1214_EQ_1214U(...) \, +#define Z_IS_1214U_EQ_1214U(...) \, +#define Z_IS_1215_EQ_1215(...) \, +#define Z_IS_1215U_EQ_1215(...) \, +#define Z_IS_1215_EQ_1215U(...) \, +#define Z_IS_1215U_EQ_1215U(...) \, +#define Z_IS_1216_EQ_1216(...) \, +#define Z_IS_1216U_EQ_1216(...) \, +#define Z_IS_1216_EQ_1216U(...) \, +#define Z_IS_1216U_EQ_1216U(...) \, +#define Z_IS_1217_EQ_1217(...) \, +#define Z_IS_1217U_EQ_1217(...) \, +#define Z_IS_1217_EQ_1217U(...) \, +#define Z_IS_1217U_EQ_1217U(...) \, +#define Z_IS_1218_EQ_1218(...) \, +#define Z_IS_1218U_EQ_1218(...) \, +#define Z_IS_1218_EQ_1218U(...) \, +#define Z_IS_1218U_EQ_1218U(...) \, +#define Z_IS_1219_EQ_1219(...) \, +#define Z_IS_1219U_EQ_1219(...) \, +#define Z_IS_1219_EQ_1219U(...) \, +#define Z_IS_1219U_EQ_1219U(...) \, +#define Z_IS_1220_EQ_1220(...) \, +#define Z_IS_1220U_EQ_1220(...) \, +#define Z_IS_1220_EQ_1220U(...) \, +#define Z_IS_1220U_EQ_1220U(...) \, +#define Z_IS_1221_EQ_1221(...) \, +#define Z_IS_1221U_EQ_1221(...) \, +#define Z_IS_1221_EQ_1221U(...) \, +#define Z_IS_1221U_EQ_1221U(...) \, +#define Z_IS_1222_EQ_1222(...) \, +#define Z_IS_1222U_EQ_1222(...) \, +#define Z_IS_1222_EQ_1222U(...) \, +#define Z_IS_1222U_EQ_1222U(...) \, +#define Z_IS_1223_EQ_1223(...) \, +#define Z_IS_1223U_EQ_1223(...) \, +#define Z_IS_1223_EQ_1223U(...) \, +#define Z_IS_1223U_EQ_1223U(...) \, +#define Z_IS_1224_EQ_1224(...) \, +#define Z_IS_1224U_EQ_1224(...) \, +#define Z_IS_1224_EQ_1224U(...) \, +#define Z_IS_1224U_EQ_1224U(...) \, +#define Z_IS_1225_EQ_1225(...) \, +#define Z_IS_1225U_EQ_1225(...) \, +#define Z_IS_1225_EQ_1225U(...) \, +#define Z_IS_1225U_EQ_1225U(...) \, +#define Z_IS_1226_EQ_1226(...) \, +#define Z_IS_1226U_EQ_1226(...) \, +#define Z_IS_1226_EQ_1226U(...) \, +#define Z_IS_1226U_EQ_1226U(...) \, +#define Z_IS_1227_EQ_1227(...) \, +#define Z_IS_1227U_EQ_1227(...) \, +#define Z_IS_1227_EQ_1227U(...) \, +#define Z_IS_1227U_EQ_1227U(...) \, +#define Z_IS_1228_EQ_1228(...) \, +#define Z_IS_1228U_EQ_1228(...) \, +#define Z_IS_1228_EQ_1228U(...) \, +#define Z_IS_1228U_EQ_1228U(...) \, +#define Z_IS_1229_EQ_1229(...) \, +#define Z_IS_1229U_EQ_1229(...) \, +#define Z_IS_1229_EQ_1229U(...) \, +#define Z_IS_1229U_EQ_1229U(...) \, +#define Z_IS_1230_EQ_1230(...) \, +#define Z_IS_1230U_EQ_1230(...) \, +#define Z_IS_1230_EQ_1230U(...) \, +#define Z_IS_1230U_EQ_1230U(...) \, +#define Z_IS_1231_EQ_1231(...) \, +#define Z_IS_1231U_EQ_1231(...) \, +#define Z_IS_1231_EQ_1231U(...) \, +#define Z_IS_1231U_EQ_1231U(...) \, +#define Z_IS_1232_EQ_1232(...) \, +#define Z_IS_1232U_EQ_1232(...) \, +#define Z_IS_1232_EQ_1232U(...) \, +#define Z_IS_1232U_EQ_1232U(...) \, +#define Z_IS_1233_EQ_1233(...) \, +#define Z_IS_1233U_EQ_1233(...) \, +#define Z_IS_1233_EQ_1233U(...) \, +#define Z_IS_1233U_EQ_1233U(...) \, +#define Z_IS_1234_EQ_1234(...) \, +#define Z_IS_1234U_EQ_1234(...) \, +#define Z_IS_1234_EQ_1234U(...) \, +#define Z_IS_1234U_EQ_1234U(...) \, +#define Z_IS_1235_EQ_1235(...) \, +#define Z_IS_1235U_EQ_1235(...) \, +#define Z_IS_1235_EQ_1235U(...) \, +#define Z_IS_1235U_EQ_1235U(...) \, +#define Z_IS_1236_EQ_1236(...) \, +#define Z_IS_1236U_EQ_1236(...) \, +#define Z_IS_1236_EQ_1236U(...) \, +#define Z_IS_1236U_EQ_1236U(...) \, +#define Z_IS_1237_EQ_1237(...) \, +#define Z_IS_1237U_EQ_1237(...) \, +#define Z_IS_1237_EQ_1237U(...) \, +#define Z_IS_1237U_EQ_1237U(...) \, +#define Z_IS_1238_EQ_1238(...) \, +#define Z_IS_1238U_EQ_1238(...) \, +#define Z_IS_1238_EQ_1238U(...) \, +#define Z_IS_1238U_EQ_1238U(...) \, +#define Z_IS_1239_EQ_1239(...) \, +#define Z_IS_1239U_EQ_1239(...) \, +#define Z_IS_1239_EQ_1239U(...) \, +#define Z_IS_1239U_EQ_1239U(...) \, +#define Z_IS_1240_EQ_1240(...) \, +#define Z_IS_1240U_EQ_1240(...) \, +#define Z_IS_1240_EQ_1240U(...) \, +#define Z_IS_1240U_EQ_1240U(...) \, +#define Z_IS_1241_EQ_1241(...) \, +#define Z_IS_1241U_EQ_1241(...) \, +#define Z_IS_1241_EQ_1241U(...) \, +#define Z_IS_1241U_EQ_1241U(...) \, +#define Z_IS_1242_EQ_1242(...) \, +#define Z_IS_1242U_EQ_1242(...) \, +#define Z_IS_1242_EQ_1242U(...) \, +#define Z_IS_1242U_EQ_1242U(...) \, +#define Z_IS_1243_EQ_1243(...) \, +#define Z_IS_1243U_EQ_1243(...) \, +#define Z_IS_1243_EQ_1243U(...) \, +#define Z_IS_1243U_EQ_1243U(...) \, +#define Z_IS_1244_EQ_1244(...) \, +#define Z_IS_1244U_EQ_1244(...) \, +#define Z_IS_1244_EQ_1244U(...) \, +#define Z_IS_1244U_EQ_1244U(...) \, +#define Z_IS_1245_EQ_1245(...) \, +#define Z_IS_1245U_EQ_1245(...) \, +#define Z_IS_1245_EQ_1245U(...) \, +#define Z_IS_1245U_EQ_1245U(...) \, +#define Z_IS_1246_EQ_1246(...) \, +#define Z_IS_1246U_EQ_1246(...) \, +#define Z_IS_1246_EQ_1246U(...) \, +#define Z_IS_1246U_EQ_1246U(...) \, +#define Z_IS_1247_EQ_1247(...) \, +#define Z_IS_1247U_EQ_1247(...) \, +#define Z_IS_1247_EQ_1247U(...) \, +#define Z_IS_1247U_EQ_1247U(...) \, +#define Z_IS_1248_EQ_1248(...) \, +#define Z_IS_1248U_EQ_1248(...) \, +#define Z_IS_1248_EQ_1248U(...) \, +#define Z_IS_1248U_EQ_1248U(...) \, +#define Z_IS_1249_EQ_1249(...) \, +#define Z_IS_1249U_EQ_1249(...) \, +#define Z_IS_1249_EQ_1249U(...) \, +#define Z_IS_1249U_EQ_1249U(...) \, +#define Z_IS_1250_EQ_1250(...) \, +#define Z_IS_1250U_EQ_1250(...) \, +#define Z_IS_1250_EQ_1250U(...) \, +#define Z_IS_1250U_EQ_1250U(...) \, +#define Z_IS_1251_EQ_1251(...) \, +#define Z_IS_1251U_EQ_1251(...) \, +#define Z_IS_1251_EQ_1251U(...) \, +#define Z_IS_1251U_EQ_1251U(...) \, +#define Z_IS_1252_EQ_1252(...) \, +#define Z_IS_1252U_EQ_1252(...) \, +#define Z_IS_1252_EQ_1252U(...) \, +#define Z_IS_1252U_EQ_1252U(...) \, +#define Z_IS_1253_EQ_1253(...) \, +#define Z_IS_1253U_EQ_1253(...) \, +#define Z_IS_1253_EQ_1253U(...) \, +#define Z_IS_1253U_EQ_1253U(...) \, +#define Z_IS_1254_EQ_1254(...) \, +#define Z_IS_1254U_EQ_1254(...) \, +#define Z_IS_1254_EQ_1254U(...) \, +#define Z_IS_1254U_EQ_1254U(...) \, +#define Z_IS_1255_EQ_1255(...) \, +#define Z_IS_1255U_EQ_1255(...) \, +#define Z_IS_1255_EQ_1255U(...) \, +#define Z_IS_1255U_EQ_1255U(...) \, +#define Z_IS_1256_EQ_1256(...) \, +#define Z_IS_1256U_EQ_1256(...) \, +#define Z_IS_1256_EQ_1256U(...) \, +#define Z_IS_1256U_EQ_1256U(...) \, +#define Z_IS_1257_EQ_1257(...) \, +#define Z_IS_1257U_EQ_1257(...) \, +#define Z_IS_1257_EQ_1257U(...) \, +#define Z_IS_1257U_EQ_1257U(...) \, +#define Z_IS_1258_EQ_1258(...) \, +#define Z_IS_1258U_EQ_1258(...) \, +#define Z_IS_1258_EQ_1258U(...) \, +#define Z_IS_1258U_EQ_1258U(...) \, +#define Z_IS_1259_EQ_1259(...) \, +#define Z_IS_1259U_EQ_1259(...) \, +#define Z_IS_1259_EQ_1259U(...) \, +#define Z_IS_1259U_EQ_1259U(...) \, +#define Z_IS_1260_EQ_1260(...) \, +#define Z_IS_1260U_EQ_1260(...) \, +#define Z_IS_1260_EQ_1260U(...) \, +#define Z_IS_1260U_EQ_1260U(...) \, +#define Z_IS_1261_EQ_1261(...) \, +#define Z_IS_1261U_EQ_1261(...) \, +#define Z_IS_1261_EQ_1261U(...) \, +#define Z_IS_1261U_EQ_1261U(...) \, +#define Z_IS_1262_EQ_1262(...) \, +#define Z_IS_1262U_EQ_1262(...) \, +#define Z_IS_1262_EQ_1262U(...) \, +#define Z_IS_1262U_EQ_1262U(...) \, +#define Z_IS_1263_EQ_1263(...) \, +#define Z_IS_1263U_EQ_1263(...) \, +#define Z_IS_1263_EQ_1263U(...) \, +#define Z_IS_1263U_EQ_1263U(...) \, +#define Z_IS_1264_EQ_1264(...) \, +#define Z_IS_1264U_EQ_1264(...) \, +#define Z_IS_1264_EQ_1264U(...) \, +#define Z_IS_1264U_EQ_1264U(...) \, +#define Z_IS_1265_EQ_1265(...) \, +#define Z_IS_1265U_EQ_1265(...) \, +#define Z_IS_1265_EQ_1265U(...) \, +#define Z_IS_1265U_EQ_1265U(...) \, +#define Z_IS_1266_EQ_1266(...) \, +#define Z_IS_1266U_EQ_1266(...) \, +#define Z_IS_1266_EQ_1266U(...) \, +#define Z_IS_1266U_EQ_1266U(...) \, +#define Z_IS_1267_EQ_1267(...) \, +#define Z_IS_1267U_EQ_1267(...) \, +#define Z_IS_1267_EQ_1267U(...) \, +#define Z_IS_1267U_EQ_1267U(...) \, +#define Z_IS_1268_EQ_1268(...) \, +#define Z_IS_1268U_EQ_1268(...) \, +#define Z_IS_1268_EQ_1268U(...) \, +#define Z_IS_1268U_EQ_1268U(...) \, +#define Z_IS_1269_EQ_1269(...) \, +#define Z_IS_1269U_EQ_1269(...) \, +#define Z_IS_1269_EQ_1269U(...) \, +#define Z_IS_1269U_EQ_1269U(...) \, +#define Z_IS_1270_EQ_1270(...) \, +#define Z_IS_1270U_EQ_1270(...) \, +#define Z_IS_1270_EQ_1270U(...) \, +#define Z_IS_1270U_EQ_1270U(...) \, +#define Z_IS_1271_EQ_1271(...) \, +#define Z_IS_1271U_EQ_1271(...) \, +#define Z_IS_1271_EQ_1271U(...) \, +#define Z_IS_1271U_EQ_1271U(...) \, +#define Z_IS_1272_EQ_1272(...) \, +#define Z_IS_1272U_EQ_1272(...) \, +#define Z_IS_1272_EQ_1272U(...) \, +#define Z_IS_1272U_EQ_1272U(...) \, +#define Z_IS_1273_EQ_1273(...) \, +#define Z_IS_1273U_EQ_1273(...) \, +#define Z_IS_1273_EQ_1273U(...) \, +#define Z_IS_1273U_EQ_1273U(...) \, +#define Z_IS_1274_EQ_1274(...) \, +#define Z_IS_1274U_EQ_1274(...) \, +#define Z_IS_1274_EQ_1274U(...) \, +#define Z_IS_1274U_EQ_1274U(...) \, +#define Z_IS_1275_EQ_1275(...) \, +#define Z_IS_1275U_EQ_1275(...) \, +#define Z_IS_1275_EQ_1275U(...) \, +#define Z_IS_1275U_EQ_1275U(...) \, +#define Z_IS_1276_EQ_1276(...) \, +#define Z_IS_1276U_EQ_1276(...) \, +#define Z_IS_1276_EQ_1276U(...) \, +#define Z_IS_1276U_EQ_1276U(...) \, +#define Z_IS_1277_EQ_1277(...) \, +#define Z_IS_1277U_EQ_1277(...) \, +#define Z_IS_1277_EQ_1277U(...) \, +#define Z_IS_1277U_EQ_1277U(...) \, +#define Z_IS_1278_EQ_1278(...) \, +#define Z_IS_1278U_EQ_1278(...) \, +#define Z_IS_1278_EQ_1278U(...) \, +#define Z_IS_1278U_EQ_1278U(...) \, +#define Z_IS_1279_EQ_1279(...) \, +#define Z_IS_1279U_EQ_1279(...) \, +#define Z_IS_1279_EQ_1279U(...) \, +#define Z_IS_1279U_EQ_1279U(...) \, +#define Z_IS_1280_EQ_1280(...) \, +#define Z_IS_1280U_EQ_1280(...) \, +#define Z_IS_1280_EQ_1280U(...) \, +#define Z_IS_1280U_EQ_1280U(...) \, +#define Z_IS_1281_EQ_1281(...) \, +#define Z_IS_1281U_EQ_1281(...) \, +#define Z_IS_1281_EQ_1281U(...) \, +#define Z_IS_1281U_EQ_1281U(...) \, +#define Z_IS_1282_EQ_1282(...) \, +#define Z_IS_1282U_EQ_1282(...) \, +#define Z_IS_1282_EQ_1282U(...) \, +#define Z_IS_1282U_EQ_1282U(...) \, +#define Z_IS_1283_EQ_1283(...) \, +#define Z_IS_1283U_EQ_1283(...) \, +#define Z_IS_1283_EQ_1283U(...) \, +#define Z_IS_1283U_EQ_1283U(...) \, +#define Z_IS_1284_EQ_1284(...) \, +#define Z_IS_1284U_EQ_1284(...) \, +#define Z_IS_1284_EQ_1284U(...) \, +#define Z_IS_1284U_EQ_1284U(...) \, +#define Z_IS_1285_EQ_1285(...) \, +#define Z_IS_1285U_EQ_1285(...) \, +#define Z_IS_1285_EQ_1285U(...) \, +#define Z_IS_1285U_EQ_1285U(...) \, +#define Z_IS_1286_EQ_1286(...) \, +#define Z_IS_1286U_EQ_1286(...) \, +#define Z_IS_1286_EQ_1286U(...) \, +#define Z_IS_1286U_EQ_1286U(...) \, +#define Z_IS_1287_EQ_1287(...) \, +#define Z_IS_1287U_EQ_1287(...) \, +#define Z_IS_1287_EQ_1287U(...) \, +#define Z_IS_1287U_EQ_1287U(...) \, +#define Z_IS_1288_EQ_1288(...) \, +#define Z_IS_1288U_EQ_1288(...) \, +#define Z_IS_1288_EQ_1288U(...) \, +#define Z_IS_1288U_EQ_1288U(...) \, +#define Z_IS_1289_EQ_1289(...) \, +#define Z_IS_1289U_EQ_1289(...) \, +#define Z_IS_1289_EQ_1289U(...) \, +#define Z_IS_1289U_EQ_1289U(...) \, +#define Z_IS_1290_EQ_1290(...) \, +#define Z_IS_1290U_EQ_1290(...) \, +#define Z_IS_1290_EQ_1290U(...) \, +#define Z_IS_1290U_EQ_1290U(...) \, +#define Z_IS_1291_EQ_1291(...) \, +#define Z_IS_1291U_EQ_1291(...) \, +#define Z_IS_1291_EQ_1291U(...) \, +#define Z_IS_1291U_EQ_1291U(...) \, +#define Z_IS_1292_EQ_1292(...) \, +#define Z_IS_1292U_EQ_1292(...) \, +#define Z_IS_1292_EQ_1292U(...) \, +#define Z_IS_1292U_EQ_1292U(...) \, +#define Z_IS_1293_EQ_1293(...) \, +#define Z_IS_1293U_EQ_1293(...) \, +#define Z_IS_1293_EQ_1293U(...) \, +#define Z_IS_1293U_EQ_1293U(...) \, +#define Z_IS_1294_EQ_1294(...) \, +#define Z_IS_1294U_EQ_1294(...) \, +#define Z_IS_1294_EQ_1294U(...) \, +#define Z_IS_1294U_EQ_1294U(...) \, +#define Z_IS_1295_EQ_1295(...) \, +#define Z_IS_1295U_EQ_1295(...) \, +#define Z_IS_1295_EQ_1295U(...) \, +#define Z_IS_1295U_EQ_1295U(...) \, +#define Z_IS_1296_EQ_1296(...) \, +#define Z_IS_1296U_EQ_1296(...) \, +#define Z_IS_1296_EQ_1296U(...) \, +#define Z_IS_1296U_EQ_1296U(...) \, +#define Z_IS_1297_EQ_1297(...) \, +#define Z_IS_1297U_EQ_1297(...) \, +#define Z_IS_1297_EQ_1297U(...) \, +#define Z_IS_1297U_EQ_1297U(...) \, +#define Z_IS_1298_EQ_1298(...) \, +#define Z_IS_1298U_EQ_1298(...) \, +#define Z_IS_1298_EQ_1298U(...) \, +#define Z_IS_1298U_EQ_1298U(...) \, +#define Z_IS_1299_EQ_1299(...) \, +#define Z_IS_1299U_EQ_1299(...) \, +#define Z_IS_1299_EQ_1299U(...) \, +#define Z_IS_1299U_EQ_1299U(...) \, +#define Z_IS_1300_EQ_1300(...) \, +#define Z_IS_1300U_EQ_1300(...) \, +#define Z_IS_1300_EQ_1300U(...) \, +#define Z_IS_1300U_EQ_1300U(...) \, +#define Z_IS_1301_EQ_1301(...) \, +#define Z_IS_1301U_EQ_1301(...) \, +#define Z_IS_1301_EQ_1301U(...) \, +#define Z_IS_1301U_EQ_1301U(...) \, +#define Z_IS_1302_EQ_1302(...) \, +#define Z_IS_1302U_EQ_1302(...) \, +#define Z_IS_1302_EQ_1302U(...) \, +#define Z_IS_1302U_EQ_1302U(...) \, +#define Z_IS_1303_EQ_1303(...) \, +#define Z_IS_1303U_EQ_1303(...) \, +#define Z_IS_1303_EQ_1303U(...) \, +#define Z_IS_1303U_EQ_1303U(...) \, +#define Z_IS_1304_EQ_1304(...) \, +#define Z_IS_1304U_EQ_1304(...) \, +#define Z_IS_1304_EQ_1304U(...) \, +#define Z_IS_1304U_EQ_1304U(...) \, +#define Z_IS_1305_EQ_1305(...) \, +#define Z_IS_1305U_EQ_1305(...) \, +#define Z_IS_1305_EQ_1305U(...) \, +#define Z_IS_1305U_EQ_1305U(...) \, +#define Z_IS_1306_EQ_1306(...) \, +#define Z_IS_1306U_EQ_1306(...) \, +#define Z_IS_1306_EQ_1306U(...) \, +#define Z_IS_1306U_EQ_1306U(...) \, +#define Z_IS_1307_EQ_1307(...) \, +#define Z_IS_1307U_EQ_1307(...) \, +#define Z_IS_1307_EQ_1307U(...) \, +#define Z_IS_1307U_EQ_1307U(...) \, +#define Z_IS_1308_EQ_1308(...) \, +#define Z_IS_1308U_EQ_1308(...) \, +#define Z_IS_1308_EQ_1308U(...) \, +#define Z_IS_1308U_EQ_1308U(...) \, +#define Z_IS_1309_EQ_1309(...) \, +#define Z_IS_1309U_EQ_1309(...) \, +#define Z_IS_1309_EQ_1309U(...) \, +#define Z_IS_1309U_EQ_1309U(...) \, +#define Z_IS_1310_EQ_1310(...) \, +#define Z_IS_1310U_EQ_1310(...) \, +#define Z_IS_1310_EQ_1310U(...) \, +#define Z_IS_1310U_EQ_1310U(...) \, +#define Z_IS_1311_EQ_1311(...) \, +#define Z_IS_1311U_EQ_1311(...) \, +#define Z_IS_1311_EQ_1311U(...) \, +#define Z_IS_1311U_EQ_1311U(...) \, +#define Z_IS_1312_EQ_1312(...) \, +#define Z_IS_1312U_EQ_1312(...) \, +#define Z_IS_1312_EQ_1312U(...) \, +#define Z_IS_1312U_EQ_1312U(...) \, +#define Z_IS_1313_EQ_1313(...) \, +#define Z_IS_1313U_EQ_1313(...) \, +#define Z_IS_1313_EQ_1313U(...) \, +#define Z_IS_1313U_EQ_1313U(...) \, +#define Z_IS_1314_EQ_1314(...) \, +#define Z_IS_1314U_EQ_1314(...) \, +#define Z_IS_1314_EQ_1314U(...) \, +#define Z_IS_1314U_EQ_1314U(...) \, +#define Z_IS_1315_EQ_1315(...) \, +#define Z_IS_1315U_EQ_1315(...) \, +#define Z_IS_1315_EQ_1315U(...) \, +#define Z_IS_1315U_EQ_1315U(...) \, +#define Z_IS_1316_EQ_1316(...) \, +#define Z_IS_1316U_EQ_1316(...) \, +#define Z_IS_1316_EQ_1316U(...) \, +#define Z_IS_1316U_EQ_1316U(...) \, +#define Z_IS_1317_EQ_1317(...) \, +#define Z_IS_1317U_EQ_1317(...) \, +#define Z_IS_1317_EQ_1317U(...) \, +#define Z_IS_1317U_EQ_1317U(...) \, +#define Z_IS_1318_EQ_1318(...) \, +#define Z_IS_1318U_EQ_1318(...) \, +#define Z_IS_1318_EQ_1318U(...) \, +#define Z_IS_1318U_EQ_1318U(...) \, +#define Z_IS_1319_EQ_1319(...) \, +#define Z_IS_1319U_EQ_1319(...) \, +#define Z_IS_1319_EQ_1319U(...) \, +#define Z_IS_1319U_EQ_1319U(...) \, +#define Z_IS_1320_EQ_1320(...) \, +#define Z_IS_1320U_EQ_1320(...) \, +#define Z_IS_1320_EQ_1320U(...) \, +#define Z_IS_1320U_EQ_1320U(...) \, +#define Z_IS_1321_EQ_1321(...) \, +#define Z_IS_1321U_EQ_1321(...) \, +#define Z_IS_1321_EQ_1321U(...) \, +#define Z_IS_1321U_EQ_1321U(...) \, +#define Z_IS_1322_EQ_1322(...) \, +#define Z_IS_1322U_EQ_1322(...) \, +#define Z_IS_1322_EQ_1322U(...) \, +#define Z_IS_1322U_EQ_1322U(...) \, +#define Z_IS_1323_EQ_1323(...) \, +#define Z_IS_1323U_EQ_1323(...) \, +#define Z_IS_1323_EQ_1323U(...) \, +#define Z_IS_1323U_EQ_1323U(...) \, +#define Z_IS_1324_EQ_1324(...) \, +#define Z_IS_1324U_EQ_1324(...) \, +#define Z_IS_1324_EQ_1324U(...) \, +#define Z_IS_1324U_EQ_1324U(...) \, +#define Z_IS_1325_EQ_1325(...) \, +#define Z_IS_1325U_EQ_1325(...) \, +#define Z_IS_1325_EQ_1325U(...) \, +#define Z_IS_1325U_EQ_1325U(...) \, +#define Z_IS_1326_EQ_1326(...) \, +#define Z_IS_1326U_EQ_1326(...) \, +#define Z_IS_1326_EQ_1326U(...) \, +#define Z_IS_1326U_EQ_1326U(...) \, +#define Z_IS_1327_EQ_1327(...) \, +#define Z_IS_1327U_EQ_1327(...) \, +#define Z_IS_1327_EQ_1327U(...) \, +#define Z_IS_1327U_EQ_1327U(...) \, +#define Z_IS_1328_EQ_1328(...) \, +#define Z_IS_1328U_EQ_1328(...) \, +#define Z_IS_1328_EQ_1328U(...) \, +#define Z_IS_1328U_EQ_1328U(...) \, +#define Z_IS_1329_EQ_1329(...) \, +#define Z_IS_1329U_EQ_1329(...) \, +#define Z_IS_1329_EQ_1329U(...) \, +#define Z_IS_1329U_EQ_1329U(...) \, +#define Z_IS_1330_EQ_1330(...) \, +#define Z_IS_1330U_EQ_1330(...) \, +#define Z_IS_1330_EQ_1330U(...) \, +#define Z_IS_1330U_EQ_1330U(...) \, +#define Z_IS_1331_EQ_1331(...) \, +#define Z_IS_1331U_EQ_1331(...) \, +#define Z_IS_1331_EQ_1331U(...) \, +#define Z_IS_1331U_EQ_1331U(...) \, +#define Z_IS_1332_EQ_1332(...) \, +#define Z_IS_1332U_EQ_1332(...) \, +#define Z_IS_1332_EQ_1332U(...) \, +#define Z_IS_1332U_EQ_1332U(...) \, +#define Z_IS_1333_EQ_1333(...) \, +#define Z_IS_1333U_EQ_1333(...) \, +#define Z_IS_1333_EQ_1333U(...) \, +#define Z_IS_1333U_EQ_1333U(...) \, +#define Z_IS_1334_EQ_1334(...) \, +#define Z_IS_1334U_EQ_1334(...) \, +#define Z_IS_1334_EQ_1334U(...) \, +#define Z_IS_1334U_EQ_1334U(...) \, +#define Z_IS_1335_EQ_1335(...) \, +#define Z_IS_1335U_EQ_1335(...) \, +#define Z_IS_1335_EQ_1335U(...) \, +#define Z_IS_1335U_EQ_1335U(...) \, +#define Z_IS_1336_EQ_1336(...) \, +#define Z_IS_1336U_EQ_1336(...) \, +#define Z_IS_1336_EQ_1336U(...) \, +#define Z_IS_1336U_EQ_1336U(...) \, +#define Z_IS_1337_EQ_1337(...) \, +#define Z_IS_1337U_EQ_1337(...) \, +#define Z_IS_1337_EQ_1337U(...) \, +#define Z_IS_1337U_EQ_1337U(...) \, +#define Z_IS_1338_EQ_1338(...) \, +#define Z_IS_1338U_EQ_1338(...) \, +#define Z_IS_1338_EQ_1338U(...) \, +#define Z_IS_1338U_EQ_1338U(...) \, +#define Z_IS_1339_EQ_1339(...) \, +#define Z_IS_1339U_EQ_1339(...) \, +#define Z_IS_1339_EQ_1339U(...) \, +#define Z_IS_1339U_EQ_1339U(...) \, +#define Z_IS_1340_EQ_1340(...) \, +#define Z_IS_1340U_EQ_1340(...) \, +#define Z_IS_1340_EQ_1340U(...) \, +#define Z_IS_1340U_EQ_1340U(...) \, +#define Z_IS_1341_EQ_1341(...) \, +#define Z_IS_1341U_EQ_1341(...) \, +#define Z_IS_1341_EQ_1341U(...) \, +#define Z_IS_1341U_EQ_1341U(...) \, +#define Z_IS_1342_EQ_1342(...) \, +#define Z_IS_1342U_EQ_1342(...) \, +#define Z_IS_1342_EQ_1342U(...) \, +#define Z_IS_1342U_EQ_1342U(...) \, +#define Z_IS_1343_EQ_1343(...) \, +#define Z_IS_1343U_EQ_1343(...) \, +#define Z_IS_1343_EQ_1343U(...) \, +#define Z_IS_1343U_EQ_1343U(...) \, +#define Z_IS_1344_EQ_1344(...) \, +#define Z_IS_1344U_EQ_1344(...) \, +#define Z_IS_1344_EQ_1344U(...) \, +#define Z_IS_1344U_EQ_1344U(...) \, +#define Z_IS_1345_EQ_1345(...) \, +#define Z_IS_1345U_EQ_1345(...) \, +#define Z_IS_1345_EQ_1345U(...) \, +#define Z_IS_1345U_EQ_1345U(...) \, +#define Z_IS_1346_EQ_1346(...) \, +#define Z_IS_1346U_EQ_1346(...) \, +#define Z_IS_1346_EQ_1346U(...) \, +#define Z_IS_1346U_EQ_1346U(...) \, +#define Z_IS_1347_EQ_1347(...) \, +#define Z_IS_1347U_EQ_1347(...) \, +#define Z_IS_1347_EQ_1347U(...) \, +#define Z_IS_1347U_EQ_1347U(...) \, +#define Z_IS_1348_EQ_1348(...) \, +#define Z_IS_1348U_EQ_1348(...) \, +#define Z_IS_1348_EQ_1348U(...) \, +#define Z_IS_1348U_EQ_1348U(...) \, +#define Z_IS_1349_EQ_1349(...) \, +#define Z_IS_1349U_EQ_1349(...) \, +#define Z_IS_1349_EQ_1349U(...) \, +#define Z_IS_1349U_EQ_1349U(...) \, +#define Z_IS_1350_EQ_1350(...) \, +#define Z_IS_1350U_EQ_1350(...) \, +#define Z_IS_1350_EQ_1350U(...) \, +#define Z_IS_1350U_EQ_1350U(...) \, +#define Z_IS_1351_EQ_1351(...) \, +#define Z_IS_1351U_EQ_1351(...) \, +#define Z_IS_1351_EQ_1351U(...) \, +#define Z_IS_1351U_EQ_1351U(...) \, +#define Z_IS_1352_EQ_1352(...) \, +#define Z_IS_1352U_EQ_1352(...) \, +#define Z_IS_1352_EQ_1352U(...) \, +#define Z_IS_1352U_EQ_1352U(...) \, +#define Z_IS_1353_EQ_1353(...) \, +#define Z_IS_1353U_EQ_1353(...) \, +#define Z_IS_1353_EQ_1353U(...) \, +#define Z_IS_1353U_EQ_1353U(...) \, +#define Z_IS_1354_EQ_1354(...) \, +#define Z_IS_1354U_EQ_1354(...) \, +#define Z_IS_1354_EQ_1354U(...) \, +#define Z_IS_1354U_EQ_1354U(...) \, +#define Z_IS_1355_EQ_1355(...) \, +#define Z_IS_1355U_EQ_1355(...) \, +#define Z_IS_1355_EQ_1355U(...) \, +#define Z_IS_1355U_EQ_1355U(...) \, +#define Z_IS_1356_EQ_1356(...) \, +#define Z_IS_1356U_EQ_1356(...) \, +#define Z_IS_1356_EQ_1356U(...) \, +#define Z_IS_1356U_EQ_1356U(...) \, +#define Z_IS_1357_EQ_1357(...) \, +#define Z_IS_1357U_EQ_1357(...) \, +#define Z_IS_1357_EQ_1357U(...) \, +#define Z_IS_1357U_EQ_1357U(...) \, +#define Z_IS_1358_EQ_1358(...) \, +#define Z_IS_1358U_EQ_1358(...) \, +#define Z_IS_1358_EQ_1358U(...) \, +#define Z_IS_1358U_EQ_1358U(...) \, +#define Z_IS_1359_EQ_1359(...) \, +#define Z_IS_1359U_EQ_1359(...) \, +#define Z_IS_1359_EQ_1359U(...) \, +#define Z_IS_1359U_EQ_1359U(...) \, +#define Z_IS_1360_EQ_1360(...) \, +#define Z_IS_1360U_EQ_1360(...) \, +#define Z_IS_1360_EQ_1360U(...) \, +#define Z_IS_1360U_EQ_1360U(...) \, +#define Z_IS_1361_EQ_1361(...) \, +#define Z_IS_1361U_EQ_1361(...) \, +#define Z_IS_1361_EQ_1361U(...) \, +#define Z_IS_1361U_EQ_1361U(...) \, +#define Z_IS_1362_EQ_1362(...) \, +#define Z_IS_1362U_EQ_1362(...) \, +#define Z_IS_1362_EQ_1362U(...) \, +#define Z_IS_1362U_EQ_1362U(...) \, +#define Z_IS_1363_EQ_1363(...) \, +#define Z_IS_1363U_EQ_1363(...) \, +#define Z_IS_1363_EQ_1363U(...) \, +#define Z_IS_1363U_EQ_1363U(...) \, +#define Z_IS_1364_EQ_1364(...) \, +#define Z_IS_1364U_EQ_1364(...) \, +#define Z_IS_1364_EQ_1364U(...) \, +#define Z_IS_1364U_EQ_1364U(...) \, +#define Z_IS_1365_EQ_1365(...) \, +#define Z_IS_1365U_EQ_1365(...) \, +#define Z_IS_1365_EQ_1365U(...) \, +#define Z_IS_1365U_EQ_1365U(...) \, +#define Z_IS_1366_EQ_1366(...) \, +#define Z_IS_1366U_EQ_1366(...) \, +#define Z_IS_1366_EQ_1366U(...) \, +#define Z_IS_1366U_EQ_1366U(...) \, +#define Z_IS_1367_EQ_1367(...) \, +#define Z_IS_1367U_EQ_1367(...) \, +#define Z_IS_1367_EQ_1367U(...) \, +#define Z_IS_1367U_EQ_1367U(...) \, +#define Z_IS_1368_EQ_1368(...) \, +#define Z_IS_1368U_EQ_1368(...) \, +#define Z_IS_1368_EQ_1368U(...) \, +#define Z_IS_1368U_EQ_1368U(...) \, +#define Z_IS_1369_EQ_1369(...) \, +#define Z_IS_1369U_EQ_1369(...) \, +#define Z_IS_1369_EQ_1369U(...) \, +#define Z_IS_1369U_EQ_1369U(...) \, +#define Z_IS_1370_EQ_1370(...) \, +#define Z_IS_1370U_EQ_1370(...) \, +#define Z_IS_1370_EQ_1370U(...) \, +#define Z_IS_1370U_EQ_1370U(...) \, +#define Z_IS_1371_EQ_1371(...) \, +#define Z_IS_1371U_EQ_1371(...) \, +#define Z_IS_1371_EQ_1371U(...) \, +#define Z_IS_1371U_EQ_1371U(...) \, +#define Z_IS_1372_EQ_1372(...) \, +#define Z_IS_1372U_EQ_1372(...) \, +#define Z_IS_1372_EQ_1372U(...) \, +#define Z_IS_1372U_EQ_1372U(...) \, +#define Z_IS_1373_EQ_1373(...) \, +#define Z_IS_1373U_EQ_1373(...) \, +#define Z_IS_1373_EQ_1373U(...) \, +#define Z_IS_1373U_EQ_1373U(...) \, +#define Z_IS_1374_EQ_1374(...) \, +#define Z_IS_1374U_EQ_1374(...) \, +#define Z_IS_1374_EQ_1374U(...) \, +#define Z_IS_1374U_EQ_1374U(...) \, +#define Z_IS_1375_EQ_1375(...) \, +#define Z_IS_1375U_EQ_1375(...) \, +#define Z_IS_1375_EQ_1375U(...) \, +#define Z_IS_1375U_EQ_1375U(...) \, +#define Z_IS_1376_EQ_1376(...) \, +#define Z_IS_1376U_EQ_1376(...) \, +#define Z_IS_1376_EQ_1376U(...) \, +#define Z_IS_1376U_EQ_1376U(...) \, +#define Z_IS_1377_EQ_1377(...) \, +#define Z_IS_1377U_EQ_1377(...) \, +#define Z_IS_1377_EQ_1377U(...) \, +#define Z_IS_1377U_EQ_1377U(...) \, +#define Z_IS_1378_EQ_1378(...) \, +#define Z_IS_1378U_EQ_1378(...) \, +#define Z_IS_1378_EQ_1378U(...) \, +#define Z_IS_1378U_EQ_1378U(...) \, +#define Z_IS_1379_EQ_1379(...) \, +#define Z_IS_1379U_EQ_1379(...) \, +#define Z_IS_1379_EQ_1379U(...) \, +#define Z_IS_1379U_EQ_1379U(...) \, +#define Z_IS_1380_EQ_1380(...) \, +#define Z_IS_1380U_EQ_1380(...) \, +#define Z_IS_1380_EQ_1380U(...) \, +#define Z_IS_1380U_EQ_1380U(...) \, +#define Z_IS_1381_EQ_1381(...) \, +#define Z_IS_1381U_EQ_1381(...) \, +#define Z_IS_1381_EQ_1381U(...) \, +#define Z_IS_1381U_EQ_1381U(...) \, +#define Z_IS_1382_EQ_1382(...) \, +#define Z_IS_1382U_EQ_1382(...) \, +#define Z_IS_1382_EQ_1382U(...) \, +#define Z_IS_1382U_EQ_1382U(...) \, +#define Z_IS_1383_EQ_1383(...) \, +#define Z_IS_1383U_EQ_1383(...) \, +#define Z_IS_1383_EQ_1383U(...) \, +#define Z_IS_1383U_EQ_1383U(...) \, +#define Z_IS_1384_EQ_1384(...) \, +#define Z_IS_1384U_EQ_1384(...) \, +#define Z_IS_1384_EQ_1384U(...) \, +#define Z_IS_1384U_EQ_1384U(...) \, +#define Z_IS_1385_EQ_1385(...) \, +#define Z_IS_1385U_EQ_1385(...) \, +#define Z_IS_1385_EQ_1385U(...) \, +#define Z_IS_1385U_EQ_1385U(...) \, +#define Z_IS_1386_EQ_1386(...) \, +#define Z_IS_1386U_EQ_1386(...) \, +#define Z_IS_1386_EQ_1386U(...) \, +#define Z_IS_1386U_EQ_1386U(...) \, +#define Z_IS_1387_EQ_1387(...) \, +#define Z_IS_1387U_EQ_1387(...) \, +#define Z_IS_1387_EQ_1387U(...) \, +#define Z_IS_1387U_EQ_1387U(...) \, +#define Z_IS_1388_EQ_1388(...) \, +#define Z_IS_1388U_EQ_1388(...) \, +#define Z_IS_1388_EQ_1388U(...) \, +#define Z_IS_1388U_EQ_1388U(...) \, +#define Z_IS_1389_EQ_1389(...) \, +#define Z_IS_1389U_EQ_1389(...) \, +#define Z_IS_1389_EQ_1389U(...) \, +#define Z_IS_1389U_EQ_1389U(...) \, +#define Z_IS_1390_EQ_1390(...) \, +#define Z_IS_1390U_EQ_1390(...) \, +#define Z_IS_1390_EQ_1390U(...) \, +#define Z_IS_1390U_EQ_1390U(...) \, +#define Z_IS_1391_EQ_1391(...) \, +#define Z_IS_1391U_EQ_1391(...) \, +#define Z_IS_1391_EQ_1391U(...) \, +#define Z_IS_1391U_EQ_1391U(...) \, +#define Z_IS_1392_EQ_1392(...) \, +#define Z_IS_1392U_EQ_1392(...) \, +#define Z_IS_1392_EQ_1392U(...) \, +#define Z_IS_1392U_EQ_1392U(...) \, +#define Z_IS_1393_EQ_1393(...) \, +#define Z_IS_1393U_EQ_1393(...) \, +#define Z_IS_1393_EQ_1393U(...) \, +#define Z_IS_1393U_EQ_1393U(...) \, +#define Z_IS_1394_EQ_1394(...) \, +#define Z_IS_1394U_EQ_1394(...) \, +#define Z_IS_1394_EQ_1394U(...) \, +#define Z_IS_1394U_EQ_1394U(...) \, +#define Z_IS_1395_EQ_1395(...) \, +#define Z_IS_1395U_EQ_1395(...) \, +#define Z_IS_1395_EQ_1395U(...) \, +#define Z_IS_1395U_EQ_1395U(...) \, +#define Z_IS_1396_EQ_1396(...) \, +#define Z_IS_1396U_EQ_1396(...) \, +#define Z_IS_1396_EQ_1396U(...) \, +#define Z_IS_1396U_EQ_1396U(...) \, +#define Z_IS_1397_EQ_1397(...) \, +#define Z_IS_1397U_EQ_1397(...) \, +#define Z_IS_1397_EQ_1397U(...) \, +#define Z_IS_1397U_EQ_1397U(...) \, +#define Z_IS_1398_EQ_1398(...) \, +#define Z_IS_1398U_EQ_1398(...) \, +#define Z_IS_1398_EQ_1398U(...) \, +#define Z_IS_1398U_EQ_1398U(...) \, +#define Z_IS_1399_EQ_1399(...) \, +#define Z_IS_1399U_EQ_1399(...) \, +#define Z_IS_1399_EQ_1399U(...) \, +#define Z_IS_1399U_EQ_1399U(...) \, +#define Z_IS_1400_EQ_1400(...) \, +#define Z_IS_1400U_EQ_1400(...) \, +#define Z_IS_1400_EQ_1400U(...) \, +#define Z_IS_1400U_EQ_1400U(...) \, +#define Z_IS_1401_EQ_1401(...) \, +#define Z_IS_1401U_EQ_1401(...) \, +#define Z_IS_1401_EQ_1401U(...) \, +#define Z_IS_1401U_EQ_1401U(...) \, +#define Z_IS_1402_EQ_1402(...) \, +#define Z_IS_1402U_EQ_1402(...) \, +#define Z_IS_1402_EQ_1402U(...) \, +#define Z_IS_1402U_EQ_1402U(...) \, +#define Z_IS_1403_EQ_1403(...) \, +#define Z_IS_1403U_EQ_1403(...) \, +#define Z_IS_1403_EQ_1403U(...) \, +#define Z_IS_1403U_EQ_1403U(...) \, +#define Z_IS_1404_EQ_1404(...) \, +#define Z_IS_1404U_EQ_1404(...) \, +#define Z_IS_1404_EQ_1404U(...) \, +#define Z_IS_1404U_EQ_1404U(...) \, +#define Z_IS_1405_EQ_1405(...) \, +#define Z_IS_1405U_EQ_1405(...) \, +#define Z_IS_1405_EQ_1405U(...) \, +#define Z_IS_1405U_EQ_1405U(...) \, +#define Z_IS_1406_EQ_1406(...) \, +#define Z_IS_1406U_EQ_1406(...) \, +#define Z_IS_1406_EQ_1406U(...) \, +#define Z_IS_1406U_EQ_1406U(...) \, +#define Z_IS_1407_EQ_1407(...) \, +#define Z_IS_1407U_EQ_1407(...) \, +#define Z_IS_1407_EQ_1407U(...) \, +#define Z_IS_1407U_EQ_1407U(...) \, +#define Z_IS_1408_EQ_1408(...) \, +#define Z_IS_1408U_EQ_1408(...) \, +#define Z_IS_1408_EQ_1408U(...) \, +#define Z_IS_1408U_EQ_1408U(...) \, +#define Z_IS_1409_EQ_1409(...) \, +#define Z_IS_1409U_EQ_1409(...) \, +#define Z_IS_1409_EQ_1409U(...) \, +#define Z_IS_1409U_EQ_1409U(...) \, +#define Z_IS_1410_EQ_1410(...) \, +#define Z_IS_1410U_EQ_1410(...) \, +#define Z_IS_1410_EQ_1410U(...) \, +#define Z_IS_1410U_EQ_1410U(...) \, +#define Z_IS_1411_EQ_1411(...) \, +#define Z_IS_1411U_EQ_1411(...) \, +#define Z_IS_1411_EQ_1411U(...) \, +#define Z_IS_1411U_EQ_1411U(...) \, +#define Z_IS_1412_EQ_1412(...) \, +#define Z_IS_1412U_EQ_1412(...) \, +#define Z_IS_1412_EQ_1412U(...) \, +#define Z_IS_1412U_EQ_1412U(...) \, +#define Z_IS_1413_EQ_1413(...) \, +#define Z_IS_1413U_EQ_1413(...) \, +#define Z_IS_1413_EQ_1413U(...) \, +#define Z_IS_1413U_EQ_1413U(...) \, +#define Z_IS_1414_EQ_1414(...) \, +#define Z_IS_1414U_EQ_1414(...) \, +#define Z_IS_1414_EQ_1414U(...) \, +#define Z_IS_1414U_EQ_1414U(...) \, +#define Z_IS_1415_EQ_1415(...) \, +#define Z_IS_1415U_EQ_1415(...) \, +#define Z_IS_1415_EQ_1415U(...) \, +#define Z_IS_1415U_EQ_1415U(...) \, +#define Z_IS_1416_EQ_1416(...) \, +#define Z_IS_1416U_EQ_1416(...) \, +#define Z_IS_1416_EQ_1416U(...) \, +#define Z_IS_1416U_EQ_1416U(...) \, +#define Z_IS_1417_EQ_1417(...) \, +#define Z_IS_1417U_EQ_1417(...) \, +#define Z_IS_1417_EQ_1417U(...) \, +#define Z_IS_1417U_EQ_1417U(...) \, +#define Z_IS_1418_EQ_1418(...) \, +#define Z_IS_1418U_EQ_1418(...) \, +#define Z_IS_1418_EQ_1418U(...) \, +#define Z_IS_1418U_EQ_1418U(...) \, +#define Z_IS_1419_EQ_1419(...) \, +#define Z_IS_1419U_EQ_1419(...) \, +#define Z_IS_1419_EQ_1419U(...) \, +#define Z_IS_1419U_EQ_1419U(...) \, +#define Z_IS_1420_EQ_1420(...) \, +#define Z_IS_1420U_EQ_1420(...) \, +#define Z_IS_1420_EQ_1420U(...) \, +#define Z_IS_1420U_EQ_1420U(...) \, +#define Z_IS_1421_EQ_1421(...) \, +#define Z_IS_1421U_EQ_1421(...) \, +#define Z_IS_1421_EQ_1421U(...) \, +#define Z_IS_1421U_EQ_1421U(...) \, +#define Z_IS_1422_EQ_1422(...) \, +#define Z_IS_1422U_EQ_1422(...) \, +#define Z_IS_1422_EQ_1422U(...) \, +#define Z_IS_1422U_EQ_1422U(...) \, +#define Z_IS_1423_EQ_1423(...) \, +#define Z_IS_1423U_EQ_1423(...) \, +#define Z_IS_1423_EQ_1423U(...) \, +#define Z_IS_1423U_EQ_1423U(...) \, +#define Z_IS_1424_EQ_1424(...) \, +#define Z_IS_1424U_EQ_1424(...) \, +#define Z_IS_1424_EQ_1424U(...) \, +#define Z_IS_1424U_EQ_1424U(...) \, +#define Z_IS_1425_EQ_1425(...) \, +#define Z_IS_1425U_EQ_1425(...) \, +#define Z_IS_1425_EQ_1425U(...) \, +#define Z_IS_1425U_EQ_1425U(...) \, +#define Z_IS_1426_EQ_1426(...) \, +#define Z_IS_1426U_EQ_1426(...) \, +#define Z_IS_1426_EQ_1426U(...) \, +#define Z_IS_1426U_EQ_1426U(...) \, +#define Z_IS_1427_EQ_1427(...) \, +#define Z_IS_1427U_EQ_1427(...) \, +#define Z_IS_1427_EQ_1427U(...) \, +#define Z_IS_1427U_EQ_1427U(...) \, +#define Z_IS_1428_EQ_1428(...) \, +#define Z_IS_1428U_EQ_1428(...) \, +#define Z_IS_1428_EQ_1428U(...) \, +#define Z_IS_1428U_EQ_1428U(...) \, +#define Z_IS_1429_EQ_1429(...) \, +#define Z_IS_1429U_EQ_1429(...) \, +#define Z_IS_1429_EQ_1429U(...) \, +#define Z_IS_1429U_EQ_1429U(...) \, +#define Z_IS_1430_EQ_1430(...) \, +#define Z_IS_1430U_EQ_1430(...) \, +#define Z_IS_1430_EQ_1430U(...) \, +#define Z_IS_1430U_EQ_1430U(...) \, +#define Z_IS_1431_EQ_1431(...) \, +#define Z_IS_1431U_EQ_1431(...) \, +#define Z_IS_1431_EQ_1431U(...) \, +#define Z_IS_1431U_EQ_1431U(...) \, +#define Z_IS_1432_EQ_1432(...) \, +#define Z_IS_1432U_EQ_1432(...) \, +#define Z_IS_1432_EQ_1432U(...) \, +#define Z_IS_1432U_EQ_1432U(...) \, +#define Z_IS_1433_EQ_1433(...) \, +#define Z_IS_1433U_EQ_1433(...) \, +#define Z_IS_1433_EQ_1433U(...) \, +#define Z_IS_1433U_EQ_1433U(...) \, +#define Z_IS_1434_EQ_1434(...) \, +#define Z_IS_1434U_EQ_1434(...) \, +#define Z_IS_1434_EQ_1434U(...) \, +#define Z_IS_1434U_EQ_1434U(...) \, +#define Z_IS_1435_EQ_1435(...) \, +#define Z_IS_1435U_EQ_1435(...) \, +#define Z_IS_1435_EQ_1435U(...) \, +#define Z_IS_1435U_EQ_1435U(...) \, +#define Z_IS_1436_EQ_1436(...) \, +#define Z_IS_1436U_EQ_1436(...) \, +#define Z_IS_1436_EQ_1436U(...) \, +#define Z_IS_1436U_EQ_1436U(...) \, +#define Z_IS_1437_EQ_1437(...) \, +#define Z_IS_1437U_EQ_1437(...) \, +#define Z_IS_1437_EQ_1437U(...) \, +#define Z_IS_1437U_EQ_1437U(...) \, +#define Z_IS_1438_EQ_1438(...) \, +#define Z_IS_1438U_EQ_1438(...) \, +#define Z_IS_1438_EQ_1438U(...) \, +#define Z_IS_1438U_EQ_1438U(...) \, +#define Z_IS_1439_EQ_1439(...) \, +#define Z_IS_1439U_EQ_1439(...) \, +#define Z_IS_1439_EQ_1439U(...) \, +#define Z_IS_1439U_EQ_1439U(...) \, +#define Z_IS_1440_EQ_1440(...) \, +#define Z_IS_1440U_EQ_1440(...) \, +#define Z_IS_1440_EQ_1440U(...) \, +#define Z_IS_1440U_EQ_1440U(...) \, +#define Z_IS_1441_EQ_1441(...) \, +#define Z_IS_1441U_EQ_1441(...) \, +#define Z_IS_1441_EQ_1441U(...) \, +#define Z_IS_1441U_EQ_1441U(...) \, +#define Z_IS_1442_EQ_1442(...) \, +#define Z_IS_1442U_EQ_1442(...) \, +#define Z_IS_1442_EQ_1442U(...) \, +#define Z_IS_1442U_EQ_1442U(...) \, +#define Z_IS_1443_EQ_1443(...) \, +#define Z_IS_1443U_EQ_1443(...) \, +#define Z_IS_1443_EQ_1443U(...) \, +#define Z_IS_1443U_EQ_1443U(...) \, +#define Z_IS_1444_EQ_1444(...) \, +#define Z_IS_1444U_EQ_1444(...) \, +#define Z_IS_1444_EQ_1444U(...) \, +#define Z_IS_1444U_EQ_1444U(...) \, +#define Z_IS_1445_EQ_1445(...) \, +#define Z_IS_1445U_EQ_1445(...) \, +#define Z_IS_1445_EQ_1445U(...) \, +#define Z_IS_1445U_EQ_1445U(...) \, +#define Z_IS_1446_EQ_1446(...) \, +#define Z_IS_1446U_EQ_1446(...) \, +#define Z_IS_1446_EQ_1446U(...) \, +#define Z_IS_1446U_EQ_1446U(...) \, +#define Z_IS_1447_EQ_1447(...) \, +#define Z_IS_1447U_EQ_1447(...) \, +#define Z_IS_1447_EQ_1447U(...) \, +#define Z_IS_1447U_EQ_1447U(...) \, +#define Z_IS_1448_EQ_1448(...) \, +#define Z_IS_1448U_EQ_1448(...) \, +#define Z_IS_1448_EQ_1448U(...) \, +#define Z_IS_1448U_EQ_1448U(...) \, +#define Z_IS_1449_EQ_1449(...) \, +#define Z_IS_1449U_EQ_1449(...) \, +#define Z_IS_1449_EQ_1449U(...) \, +#define Z_IS_1449U_EQ_1449U(...) \, +#define Z_IS_1450_EQ_1450(...) \, +#define Z_IS_1450U_EQ_1450(...) \, +#define Z_IS_1450_EQ_1450U(...) \, +#define Z_IS_1450U_EQ_1450U(...) \, +#define Z_IS_1451_EQ_1451(...) \, +#define Z_IS_1451U_EQ_1451(...) \, +#define Z_IS_1451_EQ_1451U(...) \, +#define Z_IS_1451U_EQ_1451U(...) \, +#define Z_IS_1452_EQ_1452(...) \, +#define Z_IS_1452U_EQ_1452(...) \, +#define Z_IS_1452_EQ_1452U(...) \, +#define Z_IS_1452U_EQ_1452U(...) \, +#define Z_IS_1453_EQ_1453(...) \, +#define Z_IS_1453U_EQ_1453(...) \, +#define Z_IS_1453_EQ_1453U(...) \, +#define Z_IS_1453U_EQ_1453U(...) \, +#define Z_IS_1454_EQ_1454(...) \, +#define Z_IS_1454U_EQ_1454(...) \, +#define Z_IS_1454_EQ_1454U(...) \, +#define Z_IS_1454U_EQ_1454U(...) \, +#define Z_IS_1455_EQ_1455(...) \, +#define Z_IS_1455U_EQ_1455(...) \, +#define Z_IS_1455_EQ_1455U(...) \, +#define Z_IS_1455U_EQ_1455U(...) \, +#define Z_IS_1456_EQ_1456(...) \, +#define Z_IS_1456U_EQ_1456(...) \, +#define Z_IS_1456_EQ_1456U(...) \, +#define Z_IS_1456U_EQ_1456U(...) \, +#define Z_IS_1457_EQ_1457(...) \, +#define Z_IS_1457U_EQ_1457(...) \, +#define Z_IS_1457_EQ_1457U(...) \, +#define Z_IS_1457U_EQ_1457U(...) \, +#define Z_IS_1458_EQ_1458(...) \, +#define Z_IS_1458U_EQ_1458(...) \, +#define Z_IS_1458_EQ_1458U(...) \, +#define Z_IS_1458U_EQ_1458U(...) \, +#define Z_IS_1459_EQ_1459(...) \, +#define Z_IS_1459U_EQ_1459(...) \, +#define Z_IS_1459_EQ_1459U(...) \, +#define Z_IS_1459U_EQ_1459U(...) \, +#define Z_IS_1460_EQ_1460(...) \, +#define Z_IS_1460U_EQ_1460(...) \, +#define Z_IS_1460_EQ_1460U(...) \, +#define Z_IS_1460U_EQ_1460U(...) \, +#define Z_IS_1461_EQ_1461(...) \, +#define Z_IS_1461U_EQ_1461(...) \, +#define Z_IS_1461_EQ_1461U(...) \, +#define Z_IS_1461U_EQ_1461U(...) \, +#define Z_IS_1462_EQ_1462(...) \, +#define Z_IS_1462U_EQ_1462(...) \, +#define Z_IS_1462_EQ_1462U(...) \, +#define Z_IS_1462U_EQ_1462U(...) \, +#define Z_IS_1463_EQ_1463(...) \, +#define Z_IS_1463U_EQ_1463(...) \, +#define Z_IS_1463_EQ_1463U(...) \, +#define Z_IS_1463U_EQ_1463U(...) \, +#define Z_IS_1464_EQ_1464(...) \, +#define Z_IS_1464U_EQ_1464(...) \, +#define Z_IS_1464_EQ_1464U(...) \, +#define Z_IS_1464U_EQ_1464U(...) \, +#define Z_IS_1465_EQ_1465(...) \, +#define Z_IS_1465U_EQ_1465(...) \, +#define Z_IS_1465_EQ_1465U(...) \, +#define Z_IS_1465U_EQ_1465U(...) \, +#define Z_IS_1466_EQ_1466(...) \, +#define Z_IS_1466U_EQ_1466(...) \, +#define Z_IS_1466_EQ_1466U(...) \, +#define Z_IS_1466U_EQ_1466U(...) \, +#define Z_IS_1467_EQ_1467(...) \, +#define Z_IS_1467U_EQ_1467(...) \, +#define Z_IS_1467_EQ_1467U(...) \, +#define Z_IS_1467U_EQ_1467U(...) \, +#define Z_IS_1468_EQ_1468(...) \, +#define Z_IS_1468U_EQ_1468(...) \, +#define Z_IS_1468_EQ_1468U(...) \, +#define Z_IS_1468U_EQ_1468U(...) \, +#define Z_IS_1469_EQ_1469(...) \, +#define Z_IS_1469U_EQ_1469(...) \, +#define Z_IS_1469_EQ_1469U(...) \, +#define Z_IS_1469U_EQ_1469U(...) \, +#define Z_IS_1470_EQ_1470(...) \, +#define Z_IS_1470U_EQ_1470(...) \, +#define Z_IS_1470_EQ_1470U(...) \, +#define Z_IS_1470U_EQ_1470U(...) \, +#define Z_IS_1471_EQ_1471(...) \, +#define Z_IS_1471U_EQ_1471(...) \, +#define Z_IS_1471_EQ_1471U(...) \, +#define Z_IS_1471U_EQ_1471U(...) \, +#define Z_IS_1472_EQ_1472(...) \, +#define Z_IS_1472U_EQ_1472(...) \, +#define Z_IS_1472_EQ_1472U(...) \, +#define Z_IS_1472U_EQ_1472U(...) \, +#define Z_IS_1473_EQ_1473(...) \, +#define Z_IS_1473U_EQ_1473(...) \, +#define Z_IS_1473_EQ_1473U(...) \, +#define Z_IS_1473U_EQ_1473U(...) \, +#define Z_IS_1474_EQ_1474(...) \, +#define Z_IS_1474U_EQ_1474(...) \, +#define Z_IS_1474_EQ_1474U(...) \, +#define Z_IS_1474U_EQ_1474U(...) \, +#define Z_IS_1475_EQ_1475(...) \, +#define Z_IS_1475U_EQ_1475(...) \, +#define Z_IS_1475_EQ_1475U(...) \, +#define Z_IS_1475U_EQ_1475U(...) \, +#define Z_IS_1476_EQ_1476(...) \, +#define Z_IS_1476U_EQ_1476(...) \, +#define Z_IS_1476_EQ_1476U(...) \, +#define Z_IS_1476U_EQ_1476U(...) \, +#define Z_IS_1477_EQ_1477(...) \, +#define Z_IS_1477U_EQ_1477(...) \, +#define Z_IS_1477_EQ_1477U(...) \, +#define Z_IS_1477U_EQ_1477U(...) \, +#define Z_IS_1478_EQ_1478(...) \, +#define Z_IS_1478U_EQ_1478(...) \, +#define Z_IS_1478_EQ_1478U(...) \, +#define Z_IS_1478U_EQ_1478U(...) \, +#define Z_IS_1479_EQ_1479(...) \, +#define Z_IS_1479U_EQ_1479(...) \, +#define Z_IS_1479_EQ_1479U(...) \, +#define Z_IS_1479U_EQ_1479U(...) \, +#define Z_IS_1480_EQ_1480(...) \, +#define Z_IS_1480U_EQ_1480(...) \, +#define Z_IS_1480_EQ_1480U(...) \, +#define Z_IS_1480U_EQ_1480U(...) \, +#define Z_IS_1481_EQ_1481(...) \, +#define Z_IS_1481U_EQ_1481(...) \, +#define Z_IS_1481_EQ_1481U(...) \, +#define Z_IS_1481U_EQ_1481U(...) \, +#define Z_IS_1482_EQ_1482(...) \, +#define Z_IS_1482U_EQ_1482(...) \, +#define Z_IS_1482_EQ_1482U(...) \, +#define Z_IS_1482U_EQ_1482U(...) \, +#define Z_IS_1483_EQ_1483(...) \, +#define Z_IS_1483U_EQ_1483(...) \, +#define Z_IS_1483_EQ_1483U(...) \, +#define Z_IS_1483U_EQ_1483U(...) \, +#define Z_IS_1484_EQ_1484(...) \, +#define Z_IS_1484U_EQ_1484(...) \, +#define Z_IS_1484_EQ_1484U(...) \, +#define Z_IS_1484U_EQ_1484U(...) \, +#define Z_IS_1485_EQ_1485(...) \, +#define Z_IS_1485U_EQ_1485(...) \, +#define Z_IS_1485_EQ_1485U(...) \, +#define Z_IS_1485U_EQ_1485U(...) \, +#define Z_IS_1486_EQ_1486(...) \, +#define Z_IS_1486U_EQ_1486(...) \, +#define Z_IS_1486_EQ_1486U(...) \, +#define Z_IS_1486U_EQ_1486U(...) \, +#define Z_IS_1487_EQ_1487(...) \, +#define Z_IS_1487U_EQ_1487(...) \, +#define Z_IS_1487_EQ_1487U(...) \, +#define Z_IS_1487U_EQ_1487U(...) \, +#define Z_IS_1488_EQ_1488(...) \, +#define Z_IS_1488U_EQ_1488(...) \, +#define Z_IS_1488_EQ_1488U(...) \, +#define Z_IS_1488U_EQ_1488U(...) \, +#define Z_IS_1489_EQ_1489(...) \, +#define Z_IS_1489U_EQ_1489(...) \, +#define Z_IS_1489_EQ_1489U(...) \, +#define Z_IS_1489U_EQ_1489U(...) \, +#define Z_IS_1490_EQ_1490(...) \, +#define Z_IS_1490U_EQ_1490(...) \, +#define Z_IS_1490_EQ_1490U(...) \, +#define Z_IS_1490U_EQ_1490U(...) \, +#define Z_IS_1491_EQ_1491(...) \, +#define Z_IS_1491U_EQ_1491(...) \, +#define Z_IS_1491_EQ_1491U(...) \, +#define Z_IS_1491U_EQ_1491U(...) \, +#define Z_IS_1492_EQ_1492(...) \, +#define Z_IS_1492U_EQ_1492(...) \, +#define Z_IS_1492_EQ_1492U(...) \, +#define Z_IS_1492U_EQ_1492U(...) \, +#define Z_IS_1493_EQ_1493(...) \, +#define Z_IS_1493U_EQ_1493(...) \, +#define Z_IS_1493_EQ_1493U(...) \, +#define Z_IS_1493U_EQ_1493U(...) \, +#define Z_IS_1494_EQ_1494(...) \, +#define Z_IS_1494U_EQ_1494(...) \, +#define Z_IS_1494_EQ_1494U(...) \, +#define Z_IS_1494U_EQ_1494U(...) \, +#define Z_IS_1495_EQ_1495(...) \, +#define Z_IS_1495U_EQ_1495(...) \, +#define Z_IS_1495_EQ_1495U(...) \, +#define Z_IS_1495U_EQ_1495U(...) \, +#define Z_IS_1496_EQ_1496(...) \, +#define Z_IS_1496U_EQ_1496(...) \, +#define Z_IS_1496_EQ_1496U(...) \, +#define Z_IS_1496U_EQ_1496U(...) \, +#define Z_IS_1497_EQ_1497(...) \, +#define Z_IS_1497U_EQ_1497(...) \, +#define Z_IS_1497_EQ_1497U(...) \, +#define Z_IS_1497U_EQ_1497U(...) \, +#define Z_IS_1498_EQ_1498(...) \, +#define Z_IS_1498U_EQ_1498(...) \, +#define Z_IS_1498_EQ_1498U(...) \, +#define Z_IS_1498U_EQ_1498U(...) \, +#define Z_IS_1499_EQ_1499(...) \, +#define Z_IS_1499U_EQ_1499(...) \, +#define Z_IS_1499_EQ_1499U(...) \, +#define Z_IS_1499U_EQ_1499U(...) \, +#define Z_IS_1500_EQ_1500(...) \, +#define Z_IS_1500U_EQ_1500(...) \, +#define Z_IS_1500_EQ_1500U(...) \, +#define Z_IS_1500U_EQ_1500U(...) \, +#define Z_IS_1501_EQ_1501(...) \, +#define Z_IS_1501U_EQ_1501(...) \, +#define Z_IS_1501_EQ_1501U(...) \, +#define Z_IS_1501U_EQ_1501U(...) \, +#define Z_IS_1502_EQ_1502(...) \, +#define Z_IS_1502U_EQ_1502(...) \, +#define Z_IS_1502_EQ_1502U(...) \, +#define Z_IS_1502U_EQ_1502U(...) \, +#define Z_IS_1503_EQ_1503(...) \, +#define Z_IS_1503U_EQ_1503(...) \, +#define Z_IS_1503_EQ_1503U(...) \, +#define Z_IS_1503U_EQ_1503U(...) \, +#define Z_IS_1504_EQ_1504(...) \, +#define Z_IS_1504U_EQ_1504(...) \, +#define Z_IS_1504_EQ_1504U(...) \, +#define Z_IS_1504U_EQ_1504U(...) \, +#define Z_IS_1505_EQ_1505(...) \, +#define Z_IS_1505U_EQ_1505(...) \, +#define Z_IS_1505_EQ_1505U(...) \, +#define Z_IS_1505U_EQ_1505U(...) \, +#define Z_IS_1506_EQ_1506(...) \, +#define Z_IS_1506U_EQ_1506(...) \, +#define Z_IS_1506_EQ_1506U(...) \, +#define Z_IS_1506U_EQ_1506U(...) \, +#define Z_IS_1507_EQ_1507(...) \, +#define Z_IS_1507U_EQ_1507(...) \, +#define Z_IS_1507_EQ_1507U(...) \, +#define Z_IS_1507U_EQ_1507U(...) \, +#define Z_IS_1508_EQ_1508(...) \, +#define Z_IS_1508U_EQ_1508(...) \, +#define Z_IS_1508_EQ_1508U(...) \, +#define Z_IS_1508U_EQ_1508U(...) \, +#define Z_IS_1509_EQ_1509(...) \, +#define Z_IS_1509U_EQ_1509(...) \, +#define Z_IS_1509_EQ_1509U(...) \, +#define Z_IS_1509U_EQ_1509U(...) \, +#define Z_IS_1510_EQ_1510(...) \, +#define Z_IS_1510U_EQ_1510(...) \, +#define Z_IS_1510_EQ_1510U(...) \, +#define Z_IS_1510U_EQ_1510U(...) \, +#define Z_IS_1511_EQ_1511(...) \, +#define Z_IS_1511U_EQ_1511(...) \, +#define Z_IS_1511_EQ_1511U(...) \, +#define Z_IS_1511U_EQ_1511U(...) \, +#define Z_IS_1512_EQ_1512(...) \, +#define Z_IS_1512U_EQ_1512(...) \, +#define Z_IS_1512_EQ_1512U(...) \, +#define Z_IS_1512U_EQ_1512U(...) \, +#define Z_IS_1513_EQ_1513(...) \, +#define Z_IS_1513U_EQ_1513(...) \, +#define Z_IS_1513_EQ_1513U(...) \, +#define Z_IS_1513U_EQ_1513U(...) \, +#define Z_IS_1514_EQ_1514(...) \, +#define Z_IS_1514U_EQ_1514(...) \, +#define Z_IS_1514_EQ_1514U(...) \, +#define Z_IS_1514U_EQ_1514U(...) \, +#define Z_IS_1515_EQ_1515(...) \, +#define Z_IS_1515U_EQ_1515(...) \, +#define Z_IS_1515_EQ_1515U(...) \, +#define Z_IS_1515U_EQ_1515U(...) \, +#define Z_IS_1516_EQ_1516(...) \, +#define Z_IS_1516U_EQ_1516(...) \, +#define Z_IS_1516_EQ_1516U(...) \, +#define Z_IS_1516U_EQ_1516U(...) \, +#define Z_IS_1517_EQ_1517(...) \, +#define Z_IS_1517U_EQ_1517(...) \, +#define Z_IS_1517_EQ_1517U(...) \, +#define Z_IS_1517U_EQ_1517U(...) \, +#define Z_IS_1518_EQ_1518(...) \, +#define Z_IS_1518U_EQ_1518(...) \, +#define Z_IS_1518_EQ_1518U(...) \, +#define Z_IS_1518U_EQ_1518U(...) \, +#define Z_IS_1519_EQ_1519(...) \, +#define Z_IS_1519U_EQ_1519(...) \, +#define Z_IS_1519_EQ_1519U(...) \, +#define Z_IS_1519U_EQ_1519U(...) \, +#define Z_IS_1520_EQ_1520(...) \, +#define Z_IS_1520U_EQ_1520(...) \, +#define Z_IS_1520_EQ_1520U(...) \, +#define Z_IS_1520U_EQ_1520U(...) \, +#define Z_IS_1521_EQ_1521(...) \, +#define Z_IS_1521U_EQ_1521(...) \, +#define Z_IS_1521_EQ_1521U(...) \, +#define Z_IS_1521U_EQ_1521U(...) \, +#define Z_IS_1522_EQ_1522(...) \, +#define Z_IS_1522U_EQ_1522(...) \, +#define Z_IS_1522_EQ_1522U(...) \, +#define Z_IS_1522U_EQ_1522U(...) \, +#define Z_IS_1523_EQ_1523(...) \, +#define Z_IS_1523U_EQ_1523(...) \, +#define Z_IS_1523_EQ_1523U(...) \, +#define Z_IS_1523U_EQ_1523U(...) \, +#define Z_IS_1524_EQ_1524(...) \, +#define Z_IS_1524U_EQ_1524(...) \, +#define Z_IS_1524_EQ_1524U(...) \, +#define Z_IS_1524U_EQ_1524U(...) \, +#define Z_IS_1525_EQ_1525(...) \, +#define Z_IS_1525U_EQ_1525(...) \, +#define Z_IS_1525_EQ_1525U(...) \, +#define Z_IS_1525U_EQ_1525U(...) \, +#define Z_IS_1526_EQ_1526(...) \, +#define Z_IS_1526U_EQ_1526(...) \, +#define Z_IS_1526_EQ_1526U(...) \, +#define Z_IS_1526U_EQ_1526U(...) \, +#define Z_IS_1527_EQ_1527(...) \, +#define Z_IS_1527U_EQ_1527(...) \, +#define Z_IS_1527_EQ_1527U(...) \, +#define Z_IS_1527U_EQ_1527U(...) \, +#define Z_IS_1528_EQ_1528(...) \, +#define Z_IS_1528U_EQ_1528(...) \, +#define Z_IS_1528_EQ_1528U(...) \, +#define Z_IS_1528U_EQ_1528U(...) \, +#define Z_IS_1529_EQ_1529(...) \, +#define Z_IS_1529U_EQ_1529(...) \, +#define Z_IS_1529_EQ_1529U(...) \, +#define Z_IS_1529U_EQ_1529U(...) \, +#define Z_IS_1530_EQ_1530(...) \, +#define Z_IS_1530U_EQ_1530(...) \, +#define Z_IS_1530_EQ_1530U(...) \, +#define Z_IS_1530U_EQ_1530U(...) \, +#define Z_IS_1531_EQ_1531(...) \, +#define Z_IS_1531U_EQ_1531(...) \, +#define Z_IS_1531_EQ_1531U(...) \, +#define Z_IS_1531U_EQ_1531U(...) \, +#define Z_IS_1532_EQ_1532(...) \, +#define Z_IS_1532U_EQ_1532(...) \, +#define Z_IS_1532_EQ_1532U(...) \, +#define Z_IS_1532U_EQ_1532U(...) \, +#define Z_IS_1533_EQ_1533(...) \, +#define Z_IS_1533U_EQ_1533(...) \, +#define Z_IS_1533_EQ_1533U(...) \, +#define Z_IS_1533U_EQ_1533U(...) \, +#define Z_IS_1534_EQ_1534(...) \, +#define Z_IS_1534U_EQ_1534(...) \, +#define Z_IS_1534_EQ_1534U(...) \, +#define Z_IS_1534U_EQ_1534U(...) \, +#define Z_IS_1535_EQ_1535(...) \, +#define Z_IS_1535U_EQ_1535(...) \, +#define Z_IS_1535_EQ_1535U(...) \, +#define Z_IS_1535U_EQ_1535U(...) \, +#define Z_IS_1536_EQ_1536(...) \, +#define Z_IS_1536U_EQ_1536(...) \, +#define Z_IS_1536_EQ_1536U(...) \, +#define Z_IS_1536U_EQ_1536U(...) \, +#define Z_IS_1537_EQ_1537(...) \, +#define Z_IS_1537U_EQ_1537(...) \, +#define Z_IS_1537_EQ_1537U(...) \, +#define Z_IS_1537U_EQ_1537U(...) \, +#define Z_IS_1538_EQ_1538(...) \, +#define Z_IS_1538U_EQ_1538(...) \, +#define Z_IS_1538_EQ_1538U(...) \, +#define Z_IS_1538U_EQ_1538U(...) \, +#define Z_IS_1539_EQ_1539(...) \, +#define Z_IS_1539U_EQ_1539(...) \, +#define Z_IS_1539_EQ_1539U(...) \, +#define Z_IS_1539U_EQ_1539U(...) \, +#define Z_IS_1540_EQ_1540(...) \, +#define Z_IS_1540U_EQ_1540(...) \, +#define Z_IS_1540_EQ_1540U(...) \, +#define Z_IS_1540U_EQ_1540U(...) \, +#define Z_IS_1541_EQ_1541(...) \, +#define Z_IS_1541U_EQ_1541(...) \, +#define Z_IS_1541_EQ_1541U(...) \, +#define Z_IS_1541U_EQ_1541U(...) \, +#define Z_IS_1542_EQ_1542(...) \, +#define Z_IS_1542U_EQ_1542(...) \, +#define Z_IS_1542_EQ_1542U(...) \, +#define Z_IS_1542U_EQ_1542U(...) \, +#define Z_IS_1543_EQ_1543(...) \, +#define Z_IS_1543U_EQ_1543(...) \, +#define Z_IS_1543_EQ_1543U(...) \, +#define Z_IS_1543U_EQ_1543U(...) \, +#define Z_IS_1544_EQ_1544(...) \, +#define Z_IS_1544U_EQ_1544(...) \, +#define Z_IS_1544_EQ_1544U(...) \, +#define Z_IS_1544U_EQ_1544U(...) \, +#define Z_IS_1545_EQ_1545(...) \, +#define Z_IS_1545U_EQ_1545(...) \, +#define Z_IS_1545_EQ_1545U(...) \, +#define Z_IS_1545U_EQ_1545U(...) \, +#define Z_IS_1546_EQ_1546(...) \, +#define Z_IS_1546U_EQ_1546(...) \, +#define Z_IS_1546_EQ_1546U(...) \, +#define Z_IS_1546U_EQ_1546U(...) \, +#define Z_IS_1547_EQ_1547(...) \, +#define Z_IS_1547U_EQ_1547(...) \, +#define Z_IS_1547_EQ_1547U(...) \, +#define Z_IS_1547U_EQ_1547U(...) \, +#define Z_IS_1548_EQ_1548(...) \, +#define Z_IS_1548U_EQ_1548(...) \, +#define Z_IS_1548_EQ_1548U(...) \, +#define Z_IS_1548U_EQ_1548U(...) \, +#define Z_IS_1549_EQ_1549(...) \, +#define Z_IS_1549U_EQ_1549(...) \, +#define Z_IS_1549_EQ_1549U(...) \, +#define Z_IS_1549U_EQ_1549U(...) \, +#define Z_IS_1550_EQ_1550(...) \, +#define Z_IS_1550U_EQ_1550(...) \, +#define Z_IS_1550_EQ_1550U(...) \, +#define Z_IS_1550U_EQ_1550U(...) \, +#define Z_IS_1551_EQ_1551(...) \, +#define Z_IS_1551U_EQ_1551(...) \, +#define Z_IS_1551_EQ_1551U(...) \, +#define Z_IS_1551U_EQ_1551U(...) \, +#define Z_IS_1552_EQ_1552(...) \, +#define Z_IS_1552U_EQ_1552(...) \, +#define Z_IS_1552_EQ_1552U(...) \, +#define Z_IS_1552U_EQ_1552U(...) \, +#define Z_IS_1553_EQ_1553(...) \, +#define Z_IS_1553U_EQ_1553(...) \, +#define Z_IS_1553_EQ_1553U(...) \, +#define Z_IS_1553U_EQ_1553U(...) \, +#define Z_IS_1554_EQ_1554(...) \, +#define Z_IS_1554U_EQ_1554(...) \, +#define Z_IS_1554_EQ_1554U(...) \, +#define Z_IS_1554U_EQ_1554U(...) \, +#define Z_IS_1555_EQ_1555(...) \, +#define Z_IS_1555U_EQ_1555(...) \, +#define Z_IS_1555_EQ_1555U(...) \, +#define Z_IS_1555U_EQ_1555U(...) \, +#define Z_IS_1556_EQ_1556(...) \, +#define Z_IS_1556U_EQ_1556(...) \, +#define Z_IS_1556_EQ_1556U(...) \, +#define Z_IS_1556U_EQ_1556U(...) \, +#define Z_IS_1557_EQ_1557(...) \, +#define Z_IS_1557U_EQ_1557(...) \, +#define Z_IS_1557_EQ_1557U(...) \, +#define Z_IS_1557U_EQ_1557U(...) \, +#define Z_IS_1558_EQ_1558(...) \, +#define Z_IS_1558U_EQ_1558(...) \, +#define Z_IS_1558_EQ_1558U(...) \, +#define Z_IS_1558U_EQ_1558U(...) \, +#define Z_IS_1559_EQ_1559(...) \, +#define Z_IS_1559U_EQ_1559(...) \, +#define Z_IS_1559_EQ_1559U(...) \, +#define Z_IS_1559U_EQ_1559U(...) \, +#define Z_IS_1560_EQ_1560(...) \, +#define Z_IS_1560U_EQ_1560(...) \, +#define Z_IS_1560_EQ_1560U(...) \, +#define Z_IS_1560U_EQ_1560U(...) \, +#define Z_IS_1561_EQ_1561(...) \, +#define Z_IS_1561U_EQ_1561(...) \, +#define Z_IS_1561_EQ_1561U(...) \, +#define Z_IS_1561U_EQ_1561U(...) \, +#define Z_IS_1562_EQ_1562(...) \, +#define Z_IS_1562U_EQ_1562(...) \, +#define Z_IS_1562_EQ_1562U(...) \, +#define Z_IS_1562U_EQ_1562U(...) \, +#define Z_IS_1563_EQ_1563(...) \, +#define Z_IS_1563U_EQ_1563(...) \, +#define Z_IS_1563_EQ_1563U(...) \, +#define Z_IS_1563U_EQ_1563U(...) \, +#define Z_IS_1564_EQ_1564(...) \, +#define Z_IS_1564U_EQ_1564(...) \, +#define Z_IS_1564_EQ_1564U(...) \, +#define Z_IS_1564U_EQ_1564U(...) \, +#define Z_IS_1565_EQ_1565(...) \, +#define Z_IS_1565U_EQ_1565(...) \, +#define Z_IS_1565_EQ_1565U(...) \, +#define Z_IS_1565U_EQ_1565U(...) \, +#define Z_IS_1566_EQ_1566(...) \, +#define Z_IS_1566U_EQ_1566(...) \, +#define Z_IS_1566_EQ_1566U(...) \, +#define Z_IS_1566U_EQ_1566U(...) \, +#define Z_IS_1567_EQ_1567(...) \, +#define Z_IS_1567U_EQ_1567(...) \, +#define Z_IS_1567_EQ_1567U(...) \, +#define Z_IS_1567U_EQ_1567U(...) \, +#define Z_IS_1568_EQ_1568(...) \, +#define Z_IS_1568U_EQ_1568(...) \, +#define Z_IS_1568_EQ_1568U(...) \, +#define Z_IS_1568U_EQ_1568U(...) \, +#define Z_IS_1569_EQ_1569(...) \, +#define Z_IS_1569U_EQ_1569(...) \, +#define Z_IS_1569_EQ_1569U(...) \, +#define Z_IS_1569U_EQ_1569U(...) \, +#define Z_IS_1570_EQ_1570(...) \, +#define Z_IS_1570U_EQ_1570(...) \, +#define Z_IS_1570_EQ_1570U(...) \, +#define Z_IS_1570U_EQ_1570U(...) \, +#define Z_IS_1571_EQ_1571(...) \, +#define Z_IS_1571U_EQ_1571(...) \, +#define Z_IS_1571_EQ_1571U(...) \, +#define Z_IS_1571U_EQ_1571U(...) \, +#define Z_IS_1572_EQ_1572(...) \, +#define Z_IS_1572U_EQ_1572(...) \, +#define Z_IS_1572_EQ_1572U(...) \, +#define Z_IS_1572U_EQ_1572U(...) \, +#define Z_IS_1573_EQ_1573(...) \, +#define Z_IS_1573U_EQ_1573(...) \, +#define Z_IS_1573_EQ_1573U(...) \, +#define Z_IS_1573U_EQ_1573U(...) \, +#define Z_IS_1574_EQ_1574(...) \, +#define Z_IS_1574U_EQ_1574(...) \, +#define Z_IS_1574_EQ_1574U(...) \, +#define Z_IS_1574U_EQ_1574U(...) \, +#define Z_IS_1575_EQ_1575(...) \, +#define Z_IS_1575U_EQ_1575(...) \, +#define Z_IS_1575_EQ_1575U(...) \, +#define Z_IS_1575U_EQ_1575U(...) \, +#define Z_IS_1576_EQ_1576(...) \, +#define Z_IS_1576U_EQ_1576(...) \, +#define Z_IS_1576_EQ_1576U(...) \, +#define Z_IS_1576U_EQ_1576U(...) \, +#define Z_IS_1577_EQ_1577(...) \, +#define Z_IS_1577U_EQ_1577(...) \, +#define Z_IS_1577_EQ_1577U(...) \, +#define Z_IS_1577U_EQ_1577U(...) \, +#define Z_IS_1578_EQ_1578(...) \, +#define Z_IS_1578U_EQ_1578(...) \, +#define Z_IS_1578_EQ_1578U(...) \, +#define Z_IS_1578U_EQ_1578U(...) \, +#define Z_IS_1579_EQ_1579(...) \, +#define Z_IS_1579U_EQ_1579(...) \, +#define Z_IS_1579_EQ_1579U(...) \, +#define Z_IS_1579U_EQ_1579U(...) \, +#define Z_IS_1580_EQ_1580(...) \, +#define Z_IS_1580U_EQ_1580(...) \, +#define Z_IS_1580_EQ_1580U(...) \, +#define Z_IS_1580U_EQ_1580U(...) \, +#define Z_IS_1581_EQ_1581(...) \, +#define Z_IS_1581U_EQ_1581(...) \, +#define Z_IS_1581_EQ_1581U(...) \, +#define Z_IS_1581U_EQ_1581U(...) \, +#define Z_IS_1582_EQ_1582(...) \, +#define Z_IS_1582U_EQ_1582(...) \, +#define Z_IS_1582_EQ_1582U(...) \, +#define Z_IS_1582U_EQ_1582U(...) \, +#define Z_IS_1583_EQ_1583(...) \, +#define Z_IS_1583U_EQ_1583(...) \, +#define Z_IS_1583_EQ_1583U(...) \, +#define Z_IS_1583U_EQ_1583U(...) \, +#define Z_IS_1584_EQ_1584(...) \, +#define Z_IS_1584U_EQ_1584(...) \, +#define Z_IS_1584_EQ_1584U(...) \, +#define Z_IS_1584U_EQ_1584U(...) \, +#define Z_IS_1585_EQ_1585(...) \, +#define Z_IS_1585U_EQ_1585(...) \, +#define Z_IS_1585_EQ_1585U(...) \, +#define Z_IS_1585U_EQ_1585U(...) \, +#define Z_IS_1586_EQ_1586(...) \, +#define Z_IS_1586U_EQ_1586(...) \, +#define Z_IS_1586_EQ_1586U(...) \, +#define Z_IS_1586U_EQ_1586U(...) \, +#define Z_IS_1587_EQ_1587(...) \, +#define Z_IS_1587U_EQ_1587(...) \, +#define Z_IS_1587_EQ_1587U(...) \, +#define Z_IS_1587U_EQ_1587U(...) \, +#define Z_IS_1588_EQ_1588(...) \, +#define Z_IS_1588U_EQ_1588(...) \, +#define Z_IS_1588_EQ_1588U(...) \, +#define Z_IS_1588U_EQ_1588U(...) \, +#define Z_IS_1589_EQ_1589(...) \, +#define Z_IS_1589U_EQ_1589(...) \, +#define Z_IS_1589_EQ_1589U(...) \, +#define Z_IS_1589U_EQ_1589U(...) \, +#define Z_IS_1590_EQ_1590(...) \, +#define Z_IS_1590U_EQ_1590(...) \, +#define Z_IS_1590_EQ_1590U(...) \, +#define Z_IS_1590U_EQ_1590U(...) \, +#define Z_IS_1591_EQ_1591(...) \, +#define Z_IS_1591U_EQ_1591(...) \, +#define Z_IS_1591_EQ_1591U(...) \, +#define Z_IS_1591U_EQ_1591U(...) \, +#define Z_IS_1592_EQ_1592(...) \, +#define Z_IS_1592U_EQ_1592(...) \, +#define Z_IS_1592_EQ_1592U(...) \, +#define Z_IS_1592U_EQ_1592U(...) \, +#define Z_IS_1593_EQ_1593(...) \, +#define Z_IS_1593U_EQ_1593(...) \, +#define Z_IS_1593_EQ_1593U(...) \, +#define Z_IS_1593U_EQ_1593U(...) \, +#define Z_IS_1594_EQ_1594(...) \, +#define Z_IS_1594U_EQ_1594(...) \, +#define Z_IS_1594_EQ_1594U(...) \, +#define Z_IS_1594U_EQ_1594U(...) \, +#define Z_IS_1595_EQ_1595(...) \, +#define Z_IS_1595U_EQ_1595(...) \, +#define Z_IS_1595_EQ_1595U(...) \, +#define Z_IS_1595U_EQ_1595U(...) \, +#define Z_IS_1596_EQ_1596(...) \, +#define Z_IS_1596U_EQ_1596(...) \, +#define Z_IS_1596_EQ_1596U(...) \, +#define Z_IS_1596U_EQ_1596U(...) \, +#define Z_IS_1597_EQ_1597(...) \, +#define Z_IS_1597U_EQ_1597(...) \, +#define Z_IS_1597_EQ_1597U(...) \, +#define Z_IS_1597U_EQ_1597U(...) \, +#define Z_IS_1598_EQ_1598(...) \, +#define Z_IS_1598U_EQ_1598(...) \, +#define Z_IS_1598_EQ_1598U(...) \, +#define Z_IS_1598U_EQ_1598U(...) \, +#define Z_IS_1599_EQ_1599(...) \, +#define Z_IS_1599U_EQ_1599(...) \, +#define Z_IS_1599_EQ_1599U(...) \, +#define Z_IS_1599U_EQ_1599U(...) \, +#define Z_IS_1600_EQ_1600(...) \, +#define Z_IS_1600U_EQ_1600(...) \, +#define Z_IS_1600_EQ_1600U(...) \, +#define Z_IS_1600U_EQ_1600U(...) \, +#define Z_IS_1601_EQ_1601(...) \, +#define Z_IS_1601U_EQ_1601(...) \, +#define Z_IS_1601_EQ_1601U(...) \, +#define Z_IS_1601U_EQ_1601U(...) \, +#define Z_IS_1602_EQ_1602(...) \, +#define Z_IS_1602U_EQ_1602(...) \, +#define Z_IS_1602_EQ_1602U(...) \, +#define Z_IS_1602U_EQ_1602U(...) \, +#define Z_IS_1603_EQ_1603(...) \, +#define Z_IS_1603U_EQ_1603(...) \, +#define Z_IS_1603_EQ_1603U(...) \, +#define Z_IS_1603U_EQ_1603U(...) \, +#define Z_IS_1604_EQ_1604(...) \, +#define Z_IS_1604U_EQ_1604(...) \, +#define Z_IS_1604_EQ_1604U(...) \, +#define Z_IS_1604U_EQ_1604U(...) \, +#define Z_IS_1605_EQ_1605(...) \, +#define Z_IS_1605U_EQ_1605(...) \, +#define Z_IS_1605_EQ_1605U(...) \, +#define Z_IS_1605U_EQ_1605U(...) \, +#define Z_IS_1606_EQ_1606(...) \, +#define Z_IS_1606U_EQ_1606(...) \, +#define Z_IS_1606_EQ_1606U(...) \, +#define Z_IS_1606U_EQ_1606U(...) \, +#define Z_IS_1607_EQ_1607(...) \, +#define Z_IS_1607U_EQ_1607(...) \, +#define Z_IS_1607_EQ_1607U(...) \, +#define Z_IS_1607U_EQ_1607U(...) \, +#define Z_IS_1608_EQ_1608(...) \, +#define Z_IS_1608U_EQ_1608(...) \, +#define Z_IS_1608_EQ_1608U(...) \, +#define Z_IS_1608U_EQ_1608U(...) \, +#define Z_IS_1609_EQ_1609(...) \, +#define Z_IS_1609U_EQ_1609(...) \, +#define Z_IS_1609_EQ_1609U(...) \, +#define Z_IS_1609U_EQ_1609U(...) \, +#define Z_IS_1610_EQ_1610(...) \, +#define Z_IS_1610U_EQ_1610(...) \, +#define Z_IS_1610_EQ_1610U(...) \, +#define Z_IS_1610U_EQ_1610U(...) \, +#define Z_IS_1611_EQ_1611(...) \, +#define Z_IS_1611U_EQ_1611(...) \, +#define Z_IS_1611_EQ_1611U(...) \, +#define Z_IS_1611U_EQ_1611U(...) \, +#define Z_IS_1612_EQ_1612(...) \, +#define Z_IS_1612U_EQ_1612(...) \, +#define Z_IS_1612_EQ_1612U(...) \, +#define Z_IS_1612U_EQ_1612U(...) \, +#define Z_IS_1613_EQ_1613(...) \, +#define Z_IS_1613U_EQ_1613(...) \, +#define Z_IS_1613_EQ_1613U(...) \, +#define Z_IS_1613U_EQ_1613U(...) \, +#define Z_IS_1614_EQ_1614(...) \, +#define Z_IS_1614U_EQ_1614(...) \, +#define Z_IS_1614_EQ_1614U(...) \, +#define Z_IS_1614U_EQ_1614U(...) \, +#define Z_IS_1615_EQ_1615(...) \, +#define Z_IS_1615U_EQ_1615(...) \, +#define Z_IS_1615_EQ_1615U(...) \, +#define Z_IS_1615U_EQ_1615U(...) \, +#define Z_IS_1616_EQ_1616(...) \, +#define Z_IS_1616U_EQ_1616(...) \, +#define Z_IS_1616_EQ_1616U(...) \, +#define Z_IS_1616U_EQ_1616U(...) \, +#define Z_IS_1617_EQ_1617(...) \, +#define Z_IS_1617U_EQ_1617(...) \, +#define Z_IS_1617_EQ_1617U(...) \, +#define Z_IS_1617U_EQ_1617U(...) \, +#define Z_IS_1618_EQ_1618(...) \, +#define Z_IS_1618U_EQ_1618(...) \, +#define Z_IS_1618_EQ_1618U(...) \, +#define Z_IS_1618U_EQ_1618U(...) \, +#define Z_IS_1619_EQ_1619(...) \, +#define Z_IS_1619U_EQ_1619(...) \, +#define Z_IS_1619_EQ_1619U(...) \, +#define Z_IS_1619U_EQ_1619U(...) \, +#define Z_IS_1620_EQ_1620(...) \, +#define Z_IS_1620U_EQ_1620(...) \, +#define Z_IS_1620_EQ_1620U(...) \, +#define Z_IS_1620U_EQ_1620U(...) \, +#define Z_IS_1621_EQ_1621(...) \, +#define Z_IS_1621U_EQ_1621(...) \, +#define Z_IS_1621_EQ_1621U(...) \, +#define Z_IS_1621U_EQ_1621U(...) \, +#define Z_IS_1622_EQ_1622(...) \, +#define Z_IS_1622U_EQ_1622(...) \, +#define Z_IS_1622_EQ_1622U(...) \, +#define Z_IS_1622U_EQ_1622U(...) \, +#define Z_IS_1623_EQ_1623(...) \, +#define Z_IS_1623U_EQ_1623(...) \, +#define Z_IS_1623_EQ_1623U(...) \, +#define Z_IS_1623U_EQ_1623U(...) \, +#define Z_IS_1624_EQ_1624(...) \, +#define Z_IS_1624U_EQ_1624(...) \, +#define Z_IS_1624_EQ_1624U(...) \, +#define Z_IS_1624U_EQ_1624U(...) \, +#define Z_IS_1625_EQ_1625(...) \, +#define Z_IS_1625U_EQ_1625(...) \, +#define Z_IS_1625_EQ_1625U(...) \, +#define Z_IS_1625U_EQ_1625U(...) \, +#define Z_IS_1626_EQ_1626(...) \, +#define Z_IS_1626U_EQ_1626(...) \, +#define Z_IS_1626_EQ_1626U(...) \, +#define Z_IS_1626U_EQ_1626U(...) \, +#define Z_IS_1627_EQ_1627(...) \, +#define Z_IS_1627U_EQ_1627(...) \, +#define Z_IS_1627_EQ_1627U(...) \, +#define Z_IS_1627U_EQ_1627U(...) \, +#define Z_IS_1628_EQ_1628(...) \, +#define Z_IS_1628U_EQ_1628(...) \, +#define Z_IS_1628_EQ_1628U(...) \, +#define Z_IS_1628U_EQ_1628U(...) \, +#define Z_IS_1629_EQ_1629(...) \, +#define Z_IS_1629U_EQ_1629(...) \, +#define Z_IS_1629_EQ_1629U(...) \, +#define Z_IS_1629U_EQ_1629U(...) \, +#define Z_IS_1630_EQ_1630(...) \, +#define Z_IS_1630U_EQ_1630(...) \, +#define Z_IS_1630_EQ_1630U(...) \, +#define Z_IS_1630U_EQ_1630U(...) \, +#define Z_IS_1631_EQ_1631(...) \, +#define Z_IS_1631U_EQ_1631(...) \, +#define Z_IS_1631_EQ_1631U(...) \, +#define Z_IS_1631U_EQ_1631U(...) \, +#define Z_IS_1632_EQ_1632(...) \, +#define Z_IS_1632U_EQ_1632(...) \, +#define Z_IS_1632_EQ_1632U(...) \, +#define Z_IS_1632U_EQ_1632U(...) \, +#define Z_IS_1633_EQ_1633(...) \, +#define Z_IS_1633U_EQ_1633(...) \, +#define Z_IS_1633_EQ_1633U(...) \, +#define Z_IS_1633U_EQ_1633U(...) \, +#define Z_IS_1634_EQ_1634(...) \, +#define Z_IS_1634U_EQ_1634(...) \, +#define Z_IS_1634_EQ_1634U(...) \, +#define Z_IS_1634U_EQ_1634U(...) \, +#define Z_IS_1635_EQ_1635(...) \, +#define Z_IS_1635U_EQ_1635(...) \, +#define Z_IS_1635_EQ_1635U(...) \, +#define Z_IS_1635U_EQ_1635U(...) \, +#define Z_IS_1636_EQ_1636(...) \, +#define Z_IS_1636U_EQ_1636(...) \, +#define Z_IS_1636_EQ_1636U(...) \, +#define Z_IS_1636U_EQ_1636U(...) \, +#define Z_IS_1637_EQ_1637(...) \, +#define Z_IS_1637U_EQ_1637(...) \, +#define Z_IS_1637_EQ_1637U(...) \, +#define Z_IS_1637U_EQ_1637U(...) \, +#define Z_IS_1638_EQ_1638(...) \, +#define Z_IS_1638U_EQ_1638(...) \, +#define Z_IS_1638_EQ_1638U(...) \, +#define Z_IS_1638U_EQ_1638U(...) \, +#define Z_IS_1639_EQ_1639(...) \, +#define Z_IS_1639U_EQ_1639(...) \, +#define Z_IS_1639_EQ_1639U(...) \, +#define Z_IS_1639U_EQ_1639U(...) \, +#define Z_IS_1640_EQ_1640(...) \, +#define Z_IS_1640U_EQ_1640(...) \, +#define Z_IS_1640_EQ_1640U(...) \, +#define Z_IS_1640U_EQ_1640U(...) \, +#define Z_IS_1641_EQ_1641(...) \, +#define Z_IS_1641U_EQ_1641(...) \, +#define Z_IS_1641_EQ_1641U(...) \, +#define Z_IS_1641U_EQ_1641U(...) \, +#define Z_IS_1642_EQ_1642(...) \, +#define Z_IS_1642U_EQ_1642(...) \, +#define Z_IS_1642_EQ_1642U(...) \, +#define Z_IS_1642U_EQ_1642U(...) \, +#define Z_IS_1643_EQ_1643(...) \, +#define Z_IS_1643U_EQ_1643(...) \, +#define Z_IS_1643_EQ_1643U(...) \, +#define Z_IS_1643U_EQ_1643U(...) \, +#define Z_IS_1644_EQ_1644(...) \, +#define Z_IS_1644U_EQ_1644(...) \, +#define Z_IS_1644_EQ_1644U(...) \, +#define Z_IS_1644U_EQ_1644U(...) \, +#define Z_IS_1645_EQ_1645(...) \, +#define Z_IS_1645U_EQ_1645(...) \, +#define Z_IS_1645_EQ_1645U(...) \, +#define Z_IS_1645U_EQ_1645U(...) \, +#define Z_IS_1646_EQ_1646(...) \, +#define Z_IS_1646U_EQ_1646(...) \, +#define Z_IS_1646_EQ_1646U(...) \, +#define Z_IS_1646U_EQ_1646U(...) \, +#define Z_IS_1647_EQ_1647(...) \, +#define Z_IS_1647U_EQ_1647(...) \, +#define Z_IS_1647_EQ_1647U(...) \, +#define Z_IS_1647U_EQ_1647U(...) \, +#define Z_IS_1648_EQ_1648(...) \, +#define Z_IS_1648U_EQ_1648(...) \, +#define Z_IS_1648_EQ_1648U(...) \, +#define Z_IS_1648U_EQ_1648U(...) \, +#define Z_IS_1649_EQ_1649(...) \, +#define Z_IS_1649U_EQ_1649(...) \, +#define Z_IS_1649_EQ_1649U(...) \, +#define Z_IS_1649U_EQ_1649U(...) \, +#define Z_IS_1650_EQ_1650(...) \, +#define Z_IS_1650U_EQ_1650(...) \, +#define Z_IS_1650_EQ_1650U(...) \, +#define Z_IS_1650U_EQ_1650U(...) \, +#define Z_IS_1651_EQ_1651(...) \, +#define Z_IS_1651U_EQ_1651(...) \, +#define Z_IS_1651_EQ_1651U(...) \, +#define Z_IS_1651U_EQ_1651U(...) \, +#define Z_IS_1652_EQ_1652(...) \, +#define Z_IS_1652U_EQ_1652(...) \, +#define Z_IS_1652_EQ_1652U(...) \, +#define Z_IS_1652U_EQ_1652U(...) \, +#define Z_IS_1653_EQ_1653(...) \, +#define Z_IS_1653U_EQ_1653(...) \, +#define Z_IS_1653_EQ_1653U(...) \, +#define Z_IS_1653U_EQ_1653U(...) \, +#define Z_IS_1654_EQ_1654(...) \, +#define Z_IS_1654U_EQ_1654(...) \, +#define Z_IS_1654_EQ_1654U(...) \, +#define Z_IS_1654U_EQ_1654U(...) \, +#define Z_IS_1655_EQ_1655(...) \, +#define Z_IS_1655U_EQ_1655(...) \, +#define Z_IS_1655_EQ_1655U(...) \, +#define Z_IS_1655U_EQ_1655U(...) \, +#define Z_IS_1656_EQ_1656(...) \, +#define Z_IS_1656U_EQ_1656(...) \, +#define Z_IS_1656_EQ_1656U(...) \, +#define Z_IS_1656U_EQ_1656U(...) \, +#define Z_IS_1657_EQ_1657(...) \, +#define Z_IS_1657U_EQ_1657(...) \, +#define Z_IS_1657_EQ_1657U(...) \, +#define Z_IS_1657U_EQ_1657U(...) \, +#define Z_IS_1658_EQ_1658(...) \, +#define Z_IS_1658U_EQ_1658(...) \, +#define Z_IS_1658_EQ_1658U(...) \, +#define Z_IS_1658U_EQ_1658U(...) \, +#define Z_IS_1659_EQ_1659(...) \, +#define Z_IS_1659U_EQ_1659(...) \, +#define Z_IS_1659_EQ_1659U(...) \, +#define Z_IS_1659U_EQ_1659U(...) \, +#define Z_IS_1660_EQ_1660(...) \, +#define Z_IS_1660U_EQ_1660(...) \, +#define Z_IS_1660_EQ_1660U(...) \, +#define Z_IS_1660U_EQ_1660U(...) \, +#define Z_IS_1661_EQ_1661(...) \, +#define Z_IS_1661U_EQ_1661(...) \, +#define Z_IS_1661_EQ_1661U(...) \, +#define Z_IS_1661U_EQ_1661U(...) \, +#define Z_IS_1662_EQ_1662(...) \, +#define Z_IS_1662U_EQ_1662(...) \, +#define Z_IS_1662_EQ_1662U(...) \, +#define Z_IS_1662U_EQ_1662U(...) \, +#define Z_IS_1663_EQ_1663(...) \, +#define Z_IS_1663U_EQ_1663(...) \, +#define Z_IS_1663_EQ_1663U(...) \, +#define Z_IS_1663U_EQ_1663U(...) \, +#define Z_IS_1664_EQ_1664(...) \, +#define Z_IS_1664U_EQ_1664(...) \, +#define Z_IS_1664_EQ_1664U(...) \, +#define Z_IS_1664U_EQ_1664U(...) \, +#define Z_IS_1665_EQ_1665(...) \, +#define Z_IS_1665U_EQ_1665(...) \, +#define Z_IS_1665_EQ_1665U(...) \, +#define Z_IS_1665U_EQ_1665U(...) \, +#define Z_IS_1666_EQ_1666(...) \, +#define Z_IS_1666U_EQ_1666(...) \, +#define Z_IS_1666_EQ_1666U(...) \, +#define Z_IS_1666U_EQ_1666U(...) \, +#define Z_IS_1667_EQ_1667(...) \, +#define Z_IS_1667U_EQ_1667(...) \, +#define Z_IS_1667_EQ_1667U(...) \, +#define Z_IS_1667U_EQ_1667U(...) \, +#define Z_IS_1668_EQ_1668(...) \, +#define Z_IS_1668U_EQ_1668(...) \, +#define Z_IS_1668_EQ_1668U(...) \, +#define Z_IS_1668U_EQ_1668U(...) \, +#define Z_IS_1669_EQ_1669(...) \, +#define Z_IS_1669U_EQ_1669(...) \, +#define Z_IS_1669_EQ_1669U(...) \, +#define Z_IS_1669U_EQ_1669U(...) \, +#define Z_IS_1670_EQ_1670(...) \, +#define Z_IS_1670U_EQ_1670(...) \, +#define Z_IS_1670_EQ_1670U(...) \, +#define Z_IS_1670U_EQ_1670U(...) \, +#define Z_IS_1671_EQ_1671(...) \, +#define Z_IS_1671U_EQ_1671(...) \, +#define Z_IS_1671_EQ_1671U(...) \, +#define Z_IS_1671U_EQ_1671U(...) \, +#define Z_IS_1672_EQ_1672(...) \, +#define Z_IS_1672U_EQ_1672(...) \, +#define Z_IS_1672_EQ_1672U(...) \, +#define Z_IS_1672U_EQ_1672U(...) \, +#define Z_IS_1673_EQ_1673(...) \, +#define Z_IS_1673U_EQ_1673(...) \, +#define Z_IS_1673_EQ_1673U(...) \, +#define Z_IS_1673U_EQ_1673U(...) \, +#define Z_IS_1674_EQ_1674(...) \, +#define Z_IS_1674U_EQ_1674(...) \, +#define Z_IS_1674_EQ_1674U(...) \, +#define Z_IS_1674U_EQ_1674U(...) \, +#define Z_IS_1675_EQ_1675(...) \, +#define Z_IS_1675U_EQ_1675(...) \, +#define Z_IS_1675_EQ_1675U(...) \, +#define Z_IS_1675U_EQ_1675U(...) \, +#define Z_IS_1676_EQ_1676(...) \, +#define Z_IS_1676U_EQ_1676(...) \, +#define Z_IS_1676_EQ_1676U(...) \, +#define Z_IS_1676U_EQ_1676U(...) \, +#define Z_IS_1677_EQ_1677(...) \, +#define Z_IS_1677U_EQ_1677(...) \, +#define Z_IS_1677_EQ_1677U(...) \, +#define Z_IS_1677U_EQ_1677U(...) \, +#define Z_IS_1678_EQ_1678(...) \, +#define Z_IS_1678U_EQ_1678(...) \, +#define Z_IS_1678_EQ_1678U(...) \, +#define Z_IS_1678U_EQ_1678U(...) \, +#define Z_IS_1679_EQ_1679(...) \, +#define Z_IS_1679U_EQ_1679(...) \, +#define Z_IS_1679_EQ_1679U(...) \, +#define Z_IS_1679U_EQ_1679U(...) \, +#define Z_IS_1680_EQ_1680(...) \, +#define Z_IS_1680U_EQ_1680(...) \, +#define Z_IS_1680_EQ_1680U(...) \, +#define Z_IS_1680U_EQ_1680U(...) \, +#define Z_IS_1681_EQ_1681(...) \, +#define Z_IS_1681U_EQ_1681(...) \, +#define Z_IS_1681_EQ_1681U(...) \, +#define Z_IS_1681U_EQ_1681U(...) \, +#define Z_IS_1682_EQ_1682(...) \, +#define Z_IS_1682U_EQ_1682(...) \, +#define Z_IS_1682_EQ_1682U(...) \, +#define Z_IS_1682U_EQ_1682U(...) \, +#define Z_IS_1683_EQ_1683(...) \, +#define Z_IS_1683U_EQ_1683(...) \, +#define Z_IS_1683_EQ_1683U(...) \, +#define Z_IS_1683U_EQ_1683U(...) \, +#define Z_IS_1684_EQ_1684(...) \, +#define Z_IS_1684U_EQ_1684(...) \, +#define Z_IS_1684_EQ_1684U(...) \, +#define Z_IS_1684U_EQ_1684U(...) \, +#define Z_IS_1685_EQ_1685(...) \, +#define Z_IS_1685U_EQ_1685(...) \, +#define Z_IS_1685_EQ_1685U(...) \, +#define Z_IS_1685U_EQ_1685U(...) \, +#define Z_IS_1686_EQ_1686(...) \, +#define Z_IS_1686U_EQ_1686(...) \, +#define Z_IS_1686_EQ_1686U(...) \, +#define Z_IS_1686U_EQ_1686U(...) \, +#define Z_IS_1687_EQ_1687(...) \, +#define Z_IS_1687U_EQ_1687(...) \, +#define Z_IS_1687_EQ_1687U(...) \, +#define Z_IS_1687U_EQ_1687U(...) \, +#define Z_IS_1688_EQ_1688(...) \, +#define Z_IS_1688U_EQ_1688(...) \, +#define Z_IS_1688_EQ_1688U(...) \, +#define Z_IS_1688U_EQ_1688U(...) \, +#define Z_IS_1689_EQ_1689(...) \, +#define Z_IS_1689U_EQ_1689(...) \, +#define Z_IS_1689_EQ_1689U(...) \, +#define Z_IS_1689U_EQ_1689U(...) \, +#define Z_IS_1690_EQ_1690(...) \, +#define Z_IS_1690U_EQ_1690(...) \, +#define Z_IS_1690_EQ_1690U(...) \, +#define Z_IS_1690U_EQ_1690U(...) \, +#define Z_IS_1691_EQ_1691(...) \, +#define Z_IS_1691U_EQ_1691(...) \, +#define Z_IS_1691_EQ_1691U(...) \, +#define Z_IS_1691U_EQ_1691U(...) \, +#define Z_IS_1692_EQ_1692(...) \, +#define Z_IS_1692U_EQ_1692(...) \, +#define Z_IS_1692_EQ_1692U(...) \, +#define Z_IS_1692U_EQ_1692U(...) \, +#define Z_IS_1693_EQ_1693(...) \, +#define Z_IS_1693U_EQ_1693(...) \, +#define Z_IS_1693_EQ_1693U(...) \, +#define Z_IS_1693U_EQ_1693U(...) \, +#define Z_IS_1694_EQ_1694(...) \, +#define Z_IS_1694U_EQ_1694(...) \, +#define Z_IS_1694_EQ_1694U(...) \, +#define Z_IS_1694U_EQ_1694U(...) \, +#define Z_IS_1695_EQ_1695(...) \, +#define Z_IS_1695U_EQ_1695(...) \, +#define Z_IS_1695_EQ_1695U(...) \, +#define Z_IS_1695U_EQ_1695U(...) \, +#define Z_IS_1696_EQ_1696(...) \, +#define Z_IS_1696U_EQ_1696(...) \, +#define Z_IS_1696_EQ_1696U(...) \, +#define Z_IS_1696U_EQ_1696U(...) \, +#define Z_IS_1697_EQ_1697(...) \, +#define Z_IS_1697U_EQ_1697(...) \, +#define Z_IS_1697_EQ_1697U(...) \, +#define Z_IS_1697U_EQ_1697U(...) \, +#define Z_IS_1698_EQ_1698(...) \, +#define Z_IS_1698U_EQ_1698(...) \, +#define Z_IS_1698_EQ_1698U(...) \, +#define Z_IS_1698U_EQ_1698U(...) \, +#define Z_IS_1699_EQ_1699(...) \, +#define Z_IS_1699U_EQ_1699(...) \, +#define Z_IS_1699_EQ_1699U(...) \, +#define Z_IS_1699U_EQ_1699U(...) \, +#define Z_IS_1700_EQ_1700(...) \, +#define Z_IS_1700U_EQ_1700(...) \, +#define Z_IS_1700_EQ_1700U(...) \, +#define Z_IS_1700U_EQ_1700U(...) \, +#define Z_IS_1701_EQ_1701(...) \, +#define Z_IS_1701U_EQ_1701(...) \, +#define Z_IS_1701_EQ_1701U(...) \, +#define Z_IS_1701U_EQ_1701U(...) \, +#define Z_IS_1702_EQ_1702(...) \, +#define Z_IS_1702U_EQ_1702(...) \, +#define Z_IS_1702_EQ_1702U(...) \, +#define Z_IS_1702U_EQ_1702U(...) \, +#define Z_IS_1703_EQ_1703(...) \, +#define Z_IS_1703U_EQ_1703(...) \, +#define Z_IS_1703_EQ_1703U(...) \, +#define Z_IS_1703U_EQ_1703U(...) \, +#define Z_IS_1704_EQ_1704(...) \, +#define Z_IS_1704U_EQ_1704(...) \, +#define Z_IS_1704_EQ_1704U(...) \, +#define Z_IS_1704U_EQ_1704U(...) \, +#define Z_IS_1705_EQ_1705(...) \, +#define Z_IS_1705U_EQ_1705(...) \, +#define Z_IS_1705_EQ_1705U(...) \, +#define Z_IS_1705U_EQ_1705U(...) \, +#define Z_IS_1706_EQ_1706(...) \, +#define Z_IS_1706U_EQ_1706(...) \, +#define Z_IS_1706_EQ_1706U(...) \, +#define Z_IS_1706U_EQ_1706U(...) \, +#define Z_IS_1707_EQ_1707(...) \, +#define Z_IS_1707U_EQ_1707(...) \, +#define Z_IS_1707_EQ_1707U(...) \, +#define Z_IS_1707U_EQ_1707U(...) \, +#define Z_IS_1708_EQ_1708(...) \, +#define Z_IS_1708U_EQ_1708(...) \, +#define Z_IS_1708_EQ_1708U(...) \, +#define Z_IS_1708U_EQ_1708U(...) \, +#define Z_IS_1709_EQ_1709(...) \, +#define Z_IS_1709U_EQ_1709(...) \, +#define Z_IS_1709_EQ_1709U(...) \, +#define Z_IS_1709U_EQ_1709U(...) \, +#define Z_IS_1710_EQ_1710(...) \, +#define Z_IS_1710U_EQ_1710(...) \, +#define Z_IS_1710_EQ_1710U(...) \, +#define Z_IS_1710U_EQ_1710U(...) \, +#define Z_IS_1711_EQ_1711(...) \, +#define Z_IS_1711U_EQ_1711(...) \, +#define Z_IS_1711_EQ_1711U(...) \, +#define Z_IS_1711U_EQ_1711U(...) \, +#define Z_IS_1712_EQ_1712(...) \, +#define Z_IS_1712U_EQ_1712(...) \, +#define Z_IS_1712_EQ_1712U(...) \, +#define Z_IS_1712U_EQ_1712U(...) \, +#define Z_IS_1713_EQ_1713(...) \, +#define Z_IS_1713U_EQ_1713(...) \, +#define Z_IS_1713_EQ_1713U(...) \, +#define Z_IS_1713U_EQ_1713U(...) \, +#define Z_IS_1714_EQ_1714(...) \, +#define Z_IS_1714U_EQ_1714(...) \, +#define Z_IS_1714_EQ_1714U(...) \, +#define Z_IS_1714U_EQ_1714U(...) \, +#define Z_IS_1715_EQ_1715(...) \, +#define Z_IS_1715U_EQ_1715(...) \, +#define Z_IS_1715_EQ_1715U(...) \, +#define Z_IS_1715U_EQ_1715U(...) \, +#define Z_IS_1716_EQ_1716(...) \, +#define Z_IS_1716U_EQ_1716(...) \, +#define Z_IS_1716_EQ_1716U(...) \, +#define Z_IS_1716U_EQ_1716U(...) \, +#define Z_IS_1717_EQ_1717(...) \, +#define Z_IS_1717U_EQ_1717(...) \, +#define Z_IS_1717_EQ_1717U(...) \, +#define Z_IS_1717U_EQ_1717U(...) \, +#define Z_IS_1718_EQ_1718(...) \, +#define Z_IS_1718U_EQ_1718(...) \, +#define Z_IS_1718_EQ_1718U(...) \, +#define Z_IS_1718U_EQ_1718U(...) \, +#define Z_IS_1719_EQ_1719(...) \, +#define Z_IS_1719U_EQ_1719(...) \, +#define Z_IS_1719_EQ_1719U(...) \, +#define Z_IS_1719U_EQ_1719U(...) \, +#define Z_IS_1720_EQ_1720(...) \, +#define Z_IS_1720U_EQ_1720(...) \, +#define Z_IS_1720_EQ_1720U(...) \, +#define Z_IS_1720U_EQ_1720U(...) \, +#define Z_IS_1721_EQ_1721(...) \, +#define Z_IS_1721U_EQ_1721(...) \, +#define Z_IS_1721_EQ_1721U(...) \, +#define Z_IS_1721U_EQ_1721U(...) \, +#define Z_IS_1722_EQ_1722(...) \, +#define Z_IS_1722U_EQ_1722(...) \, +#define Z_IS_1722_EQ_1722U(...) \, +#define Z_IS_1722U_EQ_1722U(...) \, +#define Z_IS_1723_EQ_1723(...) \, +#define Z_IS_1723U_EQ_1723(...) \, +#define Z_IS_1723_EQ_1723U(...) \, +#define Z_IS_1723U_EQ_1723U(...) \, +#define Z_IS_1724_EQ_1724(...) \, +#define Z_IS_1724U_EQ_1724(...) \, +#define Z_IS_1724_EQ_1724U(...) \, +#define Z_IS_1724U_EQ_1724U(...) \, +#define Z_IS_1725_EQ_1725(...) \, +#define Z_IS_1725U_EQ_1725(...) \, +#define Z_IS_1725_EQ_1725U(...) \, +#define Z_IS_1725U_EQ_1725U(...) \, +#define Z_IS_1726_EQ_1726(...) \, +#define Z_IS_1726U_EQ_1726(...) \, +#define Z_IS_1726_EQ_1726U(...) \, +#define Z_IS_1726U_EQ_1726U(...) \, +#define Z_IS_1727_EQ_1727(...) \, +#define Z_IS_1727U_EQ_1727(...) \, +#define Z_IS_1727_EQ_1727U(...) \, +#define Z_IS_1727U_EQ_1727U(...) \, +#define Z_IS_1728_EQ_1728(...) \, +#define Z_IS_1728U_EQ_1728(...) \, +#define Z_IS_1728_EQ_1728U(...) \, +#define Z_IS_1728U_EQ_1728U(...) \, +#define Z_IS_1729_EQ_1729(...) \, +#define Z_IS_1729U_EQ_1729(...) \, +#define Z_IS_1729_EQ_1729U(...) \, +#define Z_IS_1729U_EQ_1729U(...) \, +#define Z_IS_1730_EQ_1730(...) \, +#define Z_IS_1730U_EQ_1730(...) \, +#define Z_IS_1730_EQ_1730U(...) \, +#define Z_IS_1730U_EQ_1730U(...) \, +#define Z_IS_1731_EQ_1731(...) \, +#define Z_IS_1731U_EQ_1731(...) \, +#define Z_IS_1731_EQ_1731U(...) \, +#define Z_IS_1731U_EQ_1731U(...) \, +#define Z_IS_1732_EQ_1732(...) \, +#define Z_IS_1732U_EQ_1732(...) \, +#define Z_IS_1732_EQ_1732U(...) \, +#define Z_IS_1732U_EQ_1732U(...) \, +#define Z_IS_1733_EQ_1733(...) \, +#define Z_IS_1733U_EQ_1733(...) \, +#define Z_IS_1733_EQ_1733U(...) \, +#define Z_IS_1733U_EQ_1733U(...) \, +#define Z_IS_1734_EQ_1734(...) \, +#define Z_IS_1734U_EQ_1734(...) \, +#define Z_IS_1734_EQ_1734U(...) \, +#define Z_IS_1734U_EQ_1734U(...) \, +#define Z_IS_1735_EQ_1735(...) \, +#define Z_IS_1735U_EQ_1735(...) \, +#define Z_IS_1735_EQ_1735U(...) \, +#define Z_IS_1735U_EQ_1735U(...) \, +#define Z_IS_1736_EQ_1736(...) \, +#define Z_IS_1736U_EQ_1736(...) \, +#define Z_IS_1736_EQ_1736U(...) \, +#define Z_IS_1736U_EQ_1736U(...) \, +#define Z_IS_1737_EQ_1737(...) \, +#define Z_IS_1737U_EQ_1737(...) \, +#define Z_IS_1737_EQ_1737U(...) \, +#define Z_IS_1737U_EQ_1737U(...) \, +#define Z_IS_1738_EQ_1738(...) \, +#define Z_IS_1738U_EQ_1738(...) \, +#define Z_IS_1738_EQ_1738U(...) \, +#define Z_IS_1738U_EQ_1738U(...) \, +#define Z_IS_1739_EQ_1739(...) \, +#define Z_IS_1739U_EQ_1739(...) \, +#define Z_IS_1739_EQ_1739U(...) \, +#define Z_IS_1739U_EQ_1739U(...) \, +#define Z_IS_1740_EQ_1740(...) \, +#define Z_IS_1740U_EQ_1740(...) \, +#define Z_IS_1740_EQ_1740U(...) \, +#define Z_IS_1740U_EQ_1740U(...) \, +#define Z_IS_1741_EQ_1741(...) \, +#define Z_IS_1741U_EQ_1741(...) \, +#define Z_IS_1741_EQ_1741U(...) \, +#define Z_IS_1741U_EQ_1741U(...) \, +#define Z_IS_1742_EQ_1742(...) \, +#define Z_IS_1742U_EQ_1742(...) \, +#define Z_IS_1742_EQ_1742U(...) \, +#define Z_IS_1742U_EQ_1742U(...) \, +#define Z_IS_1743_EQ_1743(...) \, +#define Z_IS_1743U_EQ_1743(...) \, +#define Z_IS_1743_EQ_1743U(...) \, +#define Z_IS_1743U_EQ_1743U(...) \, +#define Z_IS_1744_EQ_1744(...) \, +#define Z_IS_1744U_EQ_1744(...) \, +#define Z_IS_1744_EQ_1744U(...) \, +#define Z_IS_1744U_EQ_1744U(...) \, +#define Z_IS_1745_EQ_1745(...) \, +#define Z_IS_1745U_EQ_1745(...) \, +#define Z_IS_1745_EQ_1745U(...) \, +#define Z_IS_1745U_EQ_1745U(...) \, +#define Z_IS_1746_EQ_1746(...) \, +#define Z_IS_1746U_EQ_1746(...) \, +#define Z_IS_1746_EQ_1746U(...) \, +#define Z_IS_1746U_EQ_1746U(...) \, +#define Z_IS_1747_EQ_1747(...) \, +#define Z_IS_1747U_EQ_1747(...) \, +#define Z_IS_1747_EQ_1747U(...) \, +#define Z_IS_1747U_EQ_1747U(...) \, +#define Z_IS_1748_EQ_1748(...) \, +#define Z_IS_1748U_EQ_1748(...) \, +#define Z_IS_1748_EQ_1748U(...) \, +#define Z_IS_1748U_EQ_1748U(...) \, +#define Z_IS_1749_EQ_1749(...) \, +#define Z_IS_1749U_EQ_1749(...) \, +#define Z_IS_1749_EQ_1749U(...) \, +#define Z_IS_1749U_EQ_1749U(...) \, +#define Z_IS_1750_EQ_1750(...) \, +#define Z_IS_1750U_EQ_1750(...) \, +#define Z_IS_1750_EQ_1750U(...) \, +#define Z_IS_1750U_EQ_1750U(...) \, +#define Z_IS_1751_EQ_1751(...) \, +#define Z_IS_1751U_EQ_1751(...) \, +#define Z_IS_1751_EQ_1751U(...) \, +#define Z_IS_1751U_EQ_1751U(...) \, +#define Z_IS_1752_EQ_1752(...) \, +#define Z_IS_1752U_EQ_1752(...) \, +#define Z_IS_1752_EQ_1752U(...) \, +#define Z_IS_1752U_EQ_1752U(...) \, +#define Z_IS_1753_EQ_1753(...) \, +#define Z_IS_1753U_EQ_1753(...) \, +#define Z_IS_1753_EQ_1753U(...) \, +#define Z_IS_1753U_EQ_1753U(...) \, +#define Z_IS_1754_EQ_1754(...) \, +#define Z_IS_1754U_EQ_1754(...) \, +#define Z_IS_1754_EQ_1754U(...) \, +#define Z_IS_1754U_EQ_1754U(...) \, +#define Z_IS_1755_EQ_1755(...) \, +#define Z_IS_1755U_EQ_1755(...) \, +#define Z_IS_1755_EQ_1755U(...) \, +#define Z_IS_1755U_EQ_1755U(...) \, +#define Z_IS_1756_EQ_1756(...) \, +#define Z_IS_1756U_EQ_1756(...) \, +#define Z_IS_1756_EQ_1756U(...) \, +#define Z_IS_1756U_EQ_1756U(...) \, +#define Z_IS_1757_EQ_1757(...) \, +#define Z_IS_1757U_EQ_1757(...) \, +#define Z_IS_1757_EQ_1757U(...) \, +#define Z_IS_1757U_EQ_1757U(...) \, +#define Z_IS_1758_EQ_1758(...) \, +#define Z_IS_1758U_EQ_1758(...) \, +#define Z_IS_1758_EQ_1758U(...) \, +#define Z_IS_1758U_EQ_1758U(...) \, +#define Z_IS_1759_EQ_1759(...) \, +#define Z_IS_1759U_EQ_1759(...) \, +#define Z_IS_1759_EQ_1759U(...) \, +#define Z_IS_1759U_EQ_1759U(...) \, +#define Z_IS_1760_EQ_1760(...) \, +#define Z_IS_1760U_EQ_1760(...) \, +#define Z_IS_1760_EQ_1760U(...) \, +#define Z_IS_1760U_EQ_1760U(...) \, +#define Z_IS_1761_EQ_1761(...) \, +#define Z_IS_1761U_EQ_1761(...) \, +#define Z_IS_1761_EQ_1761U(...) \, +#define Z_IS_1761U_EQ_1761U(...) \, +#define Z_IS_1762_EQ_1762(...) \, +#define Z_IS_1762U_EQ_1762(...) \, +#define Z_IS_1762_EQ_1762U(...) \, +#define Z_IS_1762U_EQ_1762U(...) \, +#define Z_IS_1763_EQ_1763(...) \, +#define Z_IS_1763U_EQ_1763(...) \, +#define Z_IS_1763_EQ_1763U(...) \, +#define Z_IS_1763U_EQ_1763U(...) \, +#define Z_IS_1764_EQ_1764(...) \, +#define Z_IS_1764U_EQ_1764(...) \, +#define Z_IS_1764_EQ_1764U(...) \, +#define Z_IS_1764U_EQ_1764U(...) \, +#define Z_IS_1765_EQ_1765(...) \, +#define Z_IS_1765U_EQ_1765(...) \, +#define Z_IS_1765_EQ_1765U(...) \, +#define Z_IS_1765U_EQ_1765U(...) \, +#define Z_IS_1766_EQ_1766(...) \, +#define Z_IS_1766U_EQ_1766(...) \, +#define Z_IS_1766_EQ_1766U(...) \, +#define Z_IS_1766U_EQ_1766U(...) \, +#define Z_IS_1767_EQ_1767(...) \, +#define Z_IS_1767U_EQ_1767(...) \, +#define Z_IS_1767_EQ_1767U(...) \, +#define Z_IS_1767U_EQ_1767U(...) \, +#define Z_IS_1768_EQ_1768(...) \, +#define Z_IS_1768U_EQ_1768(...) \, +#define Z_IS_1768_EQ_1768U(...) \, +#define Z_IS_1768U_EQ_1768U(...) \, +#define Z_IS_1769_EQ_1769(...) \, +#define Z_IS_1769U_EQ_1769(...) \, +#define Z_IS_1769_EQ_1769U(...) \, +#define Z_IS_1769U_EQ_1769U(...) \, +#define Z_IS_1770_EQ_1770(...) \, +#define Z_IS_1770U_EQ_1770(...) \, +#define Z_IS_1770_EQ_1770U(...) \, +#define Z_IS_1770U_EQ_1770U(...) \, +#define Z_IS_1771_EQ_1771(...) \, +#define Z_IS_1771U_EQ_1771(...) \, +#define Z_IS_1771_EQ_1771U(...) \, +#define Z_IS_1771U_EQ_1771U(...) \, +#define Z_IS_1772_EQ_1772(...) \, +#define Z_IS_1772U_EQ_1772(...) \, +#define Z_IS_1772_EQ_1772U(...) \, +#define Z_IS_1772U_EQ_1772U(...) \, +#define Z_IS_1773_EQ_1773(...) \, +#define Z_IS_1773U_EQ_1773(...) \, +#define Z_IS_1773_EQ_1773U(...) \, +#define Z_IS_1773U_EQ_1773U(...) \, +#define Z_IS_1774_EQ_1774(...) \, +#define Z_IS_1774U_EQ_1774(...) \, +#define Z_IS_1774_EQ_1774U(...) \, +#define Z_IS_1774U_EQ_1774U(...) \, +#define Z_IS_1775_EQ_1775(...) \, +#define Z_IS_1775U_EQ_1775(...) \, +#define Z_IS_1775_EQ_1775U(...) \, +#define Z_IS_1775U_EQ_1775U(...) \, +#define Z_IS_1776_EQ_1776(...) \, +#define Z_IS_1776U_EQ_1776(...) \, +#define Z_IS_1776_EQ_1776U(...) \, +#define Z_IS_1776U_EQ_1776U(...) \, +#define Z_IS_1777_EQ_1777(...) \, +#define Z_IS_1777U_EQ_1777(...) \, +#define Z_IS_1777_EQ_1777U(...) \, +#define Z_IS_1777U_EQ_1777U(...) \, +#define Z_IS_1778_EQ_1778(...) \, +#define Z_IS_1778U_EQ_1778(...) \, +#define Z_IS_1778_EQ_1778U(...) \, +#define Z_IS_1778U_EQ_1778U(...) \, +#define Z_IS_1779_EQ_1779(...) \, +#define Z_IS_1779U_EQ_1779(...) \, +#define Z_IS_1779_EQ_1779U(...) \, +#define Z_IS_1779U_EQ_1779U(...) \, +#define Z_IS_1780_EQ_1780(...) \, +#define Z_IS_1780U_EQ_1780(...) \, +#define Z_IS_1780_EQ_1780U(...) \, +#define Z_IS_1780U_EQ_1780U(...) \, +#define Z_IS_1781_EQ_1781(...) \, +#define Z_IS_1781U_EQ_1781(...) \, +#define Z_IS_1781_EQ_1781U(...) \, +#define Z_IS_1781U_EQ_1781U(...) \, +#define Z_IS_1782_EQ_1782(...) \, +#define Z_IS_1782U_EQ_1782(...) \, +#define Z_IS_1782_EQ_1782U(...) \, +#define Z_IS_1782U_EQ_1782U(...) \, +#define Z_IS_1783_EQ_1783(...) \, +#define Z_IS_1783U_EQ_1783(...) \, +#define Z_IS_1783_EQ_1783U(...) \, +#define Z_IS_1783U_EQ_1783U(...) \, +#define Z_IS_1784_EQ_1784(...) \, +#define Z_IS_1784U_EQ_1784(...) \, +#define Z_IS_1784_EQ_1784U(...) \, +#define Z_IS_1784U_EQ_1784U(...) \, +#define Z_IS_1785_EQ_1785(...) \, +#define Z_IS_1785U_EQ_1785(...) \, +#define Z_IS_1785_EQ_1785U(...) \, +#define Z_IS_1785U_EQ_1785U(...) \, +#define Z_IS_1786_EQ_1786(...) \, +#define Z_IS_1786U_EQ_1786(...) \, +#define Z_IS_1786_EQ_1786U(...) \, +#define Z_IS_1786U_EQ_1786U(...) \, +#define Z_IS_1787_EQ_1787(...) \, +#define Z_IS_1787U_EQ_1787(...) \, +#define Z_IS_1787_EQ_1787U(...) \, +#define Z_IS_1787U_EQ_1787U(...) \, +#define Z_IS_1788_EQ_1788(...) \, +#define Z_IS_1788U_EQ_1788(...) \, +#define Z_IS_1788_EQ_1788U(...) \, +#define Z_IS_1788U_EQ_1788U(...) \, +#define Z_IS_1789_EQ_1789(...) \, +#define Z_IS_1789U_EQ_1789(...) \, +#define Z_IS_1789_EQ_1789U(...) \, +#define Z_IS_1789U_EQ_1789U(...) \, +#define Z_IS_1790_EQ_1790(...) \, +#define Z_IS_1790U_EQ_1790(...) \, +#define Z_IS_1790_EQ_1790U(...) \, +#define Z_IS_1790U_EQ_1790U(...) \, +#define Z_IS_1791_EQ_1791(...) \, +#define Z_IS_1791U_EQ_1791(...) \, +#define Z_IS_1791_EQ_1791U(...) \, +#define Z_IS_1791U_EQ_1791U(...) \, +#define Z_IS_1792_EQ_1792(...) \, +#define Z_IS_1792U_EQ_1792(...) \, +#define Z_IS_1792_EQ_1792U(...) \, +#define Z_IS_1792U_EQ_1792U(...) \, +#define Z_IS_1793_EQ_1793(...) \, +#define Z_IS_1793U_EQ_1793(...) \, +#define Z_IS_1793_EQ_1793U(...) \, +#define Z_IS_1793U_EQ_1793U(...) \, +#define Z_IS_1794_EQ_1794(...) \, +#define Z_IS_1794U_EQ_1794(...) \, +#define Z_IS_1794_EQ_1794U(...) \, +#define Z_IS_1794U_EQ_1794U(...) \, +#define Z_IS_1795_EQ_1795(...) \, +#define Z_IS_1795U_EQ_1795(...) \, +#define Z_IS_1795_EQ_1795U(...) \, +#define Z_IS_1795U_EQ_1795U(...) \, +#define Z_IS_1796_EQ_1796(...) \, +#define Z_IS_1796U_EQ_1796(...) \, +#define Z_IS_1796_EQ_1796U(...) \, +#define Z_IS_1796U_EQ_1796U(...) \, +#define Z_IS_1797_EQ_1797(...) \, +#define Z_IS_1797U_EQ_1797(...) \, +#define Z_IS_1797_EQ_1797U(...) \, +#define Z_IS_1797U_EQ_1797U(...) \, +#define Z_IS_1798_EQ_1798(...) \, +#define Z_IS_1798U_EQ_1798(...) \, +#define Z_IS_1798_EQ_1798U(...) \, +#define Z_IS_1798U_EQ_1798U(...) \, +#define Z_IS_1799_EQ_1799(...) \, +#define Z_IS_1799U_EQ_1799(...) \, +#define Z_IS_1799_EQ_1799U(...) \, +#define Z_IS_1799U_EQ_1799U(...) \, +#define Z_IS_1800_EQ_1800(...) \, +#define Z_IS_1800U_EQ_1800(...) \, +#define Z_IS_1800_EQ_1800U(...) \, +#define Z_IS_1800U_EQ_1800U(...) \, +#define Z_IS_1801_EQ_1801(...) \, +#define Z_IS_1801U_EQ_1801(...) \, +#define Z_IS_1801_EQ_1801U(...) \, +#define Z_IS_1801U_EQ_1801U(...) \, +#define Z_IS_1802_EQ_1802(...) \, +#define Z_IS_1802U_EQ_1802(...) \, +#define Z_IS_1802_EQ_1802U(...) \, +#define Z_IS_1802U_EQ_1802U(...) \, +#define Z_IS_1803_EQ_1803(...) \, +#define Z_IS_1803U_EQ_1803(...) \, +#define Z_IS_1803_EQ_1803U(...) \, +#define Z_IS_1803U_EQ_1803U(...) \, +#define Z_IS_1804_EQ_1804(...) \, +#define Z_IS_1804U_EQ_1804(...) \, +#define Z_IS_1804_EQ_1804U(...) \, +#define Z_IS_1804U_EQ_1804U(...) \, +#define Z_IS_1805_EQ_1805(...) \, +#define Z_IS_1805U_EQ_1805(...) \, +#define Z_IS_1805_EQ_1805U(...) \, +#define Z_IS_1805U_EQ_1805U(...) \, +#define Z_IS_1806_EQ_1806(...) \, +#define Z_IS_1806U_EQ_1806(...) \, +#define Z_IS_1806_EQ_1806U(...) \, +#define Z_IS_1806U_EQ_1806U(...) \, +#define Z_IS_1807_EQ_1807(...) \, +#define Z_IS_1807U_EQ_1807(...) \, +#define Z_IS_1807_EQ_1807U(...) \, +#define Z_IS_1807U_EQ_1807U(...) \, +#define Z_IS_1808_EQ_1808(...) \, +#define Z_IS_1808U_EQ_1808(...) \, +#define Z_IS_1808_EQ_1808U(...) \, +#define Z_IS_1808U_EQ_1808U(...) \, +#define Z_IS_1809_EQ_1809(...) \, +#define Z_IS_1809U_EQ_1809(...) \, +#define Z_IS_1809_EQ_1809U(...) \, +#define Z_IS_1809U_EQ_1809U(...) \, +#define Z_IS_1810_EQ_1810(...) \, +#define Z_IS_1810U_EQ_1810(...) \, +#define Z_IS_1810_EQ_1810U(...) \, +#define Z_IS_1810U_EQ_1810U(...) \, +#define Z_IS_1811_EQ_1811(...) \, +#define Z_IS_1811U_EQ_1811(...) \, +#define Z_IS_1811_EQ_1811U(...) \, +#define Z_IS_1811U_EQ_1811U(...) \, +#define Z_IS_1812_EQ_1812(...) \, +#define Z_IS_1812U_EQ_1812(...) \, +#define Z_IS_1812_EQ_1812U(...) \, +#define Z_IS_1812U_EQ_1812U(...) \, +#define Z_IS_1813_EQ_1813(...) \, +#define Z_IS_1813U_EQ_1813(...) \, +#define Z_IS_1813_EQ_1813U(...) \, +#define Z_IS_1813U_EQ_1813U(...) \, +#define Z_IS_1814_EQ_1814(...) \, +#define Z_IS_1814U_EQ_1814(...) \, +#define Z_IS_1814_EQ_1814U(...) \, +#define Z_IS_1814U_EQ_1814U(...) \, +#define Z_IS_1815_EQ_1815(...) \, +#define Z_IS_1815U_EQ_1815(...) \, +#define Z_IS_1815_EQ_1815U(...) \, +#define Z_IS_1815U_EQ_1815U(...) \, +#define Z_IS_1816_EQ_1816(...) \, +#define Z_IS_1816U_EQ_1816(...) \, +#define Z_IS_1816_EQ_1816U(...) \, +#define Z_IS_1816U_EQ_1816U(...) \, +#define Z_IS_1817_EQ_1817(...) \, +#define Z_IS_1817U_EQ_1817(...) \, +#define Z_IS_1817_EQ_1817U(...) \, +#define Z_IS_1817U_EQ_1817U(...) \, +#define Z_IS_1818_EQ_1818(...) \, +#define Z_IS_1818U_EQ_1818(...) \, +#define Z_IS_1818_EQ_1818U(...) \, +#define Z_IS_1818U_EQ_1818U(...) \, +#define Z_IS_1819_EQ_1819(...) \, +#define Z_IS_1819U_EQ_1819(...) \, +#define Z_IS_1819_EQ_1819U(...) \, +#define Z_IS_1819U_EQ_1819U(...) \, +#define Z_IS_1820_EQ_1820(...) \, +#define Z_IS_1820U_EQ_1820(...) \, +#define Z_IS_1820_EQ_1820U(...) \, +#define Z_IS_1820U_EQ_1820U(...) \, +#define Z_IS_1821_EQ_1821(...) \, +#define Z_IS_1821U_EQ_1821(...) \, +#define Z_IS_1821_EQ_1821U(...) \, +#define Z_IS_1821U_EQ_1821U(...) \, +#define Z_IS_1822_EQ_1822(...) \, +#define Z_IS_1822U_EQ_1822(...) \, +#define Z_IS_1822_EQ_1822U(...) \, +#define Z_IS_1822U_EQ_1822U(...) \, +#define Z_IS_1823_EQ_1823(...) \, +#define Z_IS_1823U_EQ_1823(...) \, +#define Z_IS_1823_EQ_1823U(...) \, +#define Z_IS_1823U_EQ_1823U(...) \, +#define Z_IS_1824_EQ_1824(...) \, +#define Z_IS_1824U_EQ_1824(...) \, +#define Z_IS_1824_EQ_1824U(...) \, +#define Z_IS_1824U_EQ_1824U(...) \, +#define Z_IS_1825_EQ_1825(...) \, +#define Z_IS_1825U_EQ_1825(...) \, +#define Z_IS_1825_EQ_1825U(...) \, +#define Z_IS_1825U_EQ_1825U(...) \, +#define Z_IS_1826_EQ_1826(...) \, +#define Z_IS_1826U_EQ_1826(...) \, +#define Z_IS_1826_EQ_1826U(...) \, +#define Z_IS_1826U_EQ_1826U(...) \, +#define Z_IS_1827_EQ_1827(...) \, +#define Z_IS_1827U_EQ_1827(...) \, +#define Z_IS_1827_EQ_1827U(...) \, +#define Z_IS_1827U_EQ_1827U(...) \, +#define Z_IS_1828_EQ_1828(...) \, +#define Z_IS_1828U_EQ_1828(...) \, +#define Z_IS_1828_EQ_1828U(...) \, +#define Z_IS_1828U_EQ_1828U(...) \, +#define Z_IS_1829_EQ_1829(...) \, +#define Z_IS_1829U_EQ_1829(...) \, +#define Z_IS_1829_EQ_1829U(...) \, +#define Z_IS_1829U_EQ_1829U(...) \, +#define Z_IS_1830_EQ_1830(...) \, +#define Z_IS_1830U_EQ_1830(...) \, +#define Z_IS_1830_EQ_1830U(...) \, +#define Z_IS_1830U_EQ_1830U(...) \, +#define Z_IS_1831_EQ_1831(...) \, +#define Z_IS_1831U_EQ_1831(...) \, +#define Z_IS_1831_EQ_1831U(...) \, +#define Z_IS_1831U_EQ_1831U(...) \, +#define Z_IS_1832_EQ_1832(...) \, +#define Z_IS_1832U_EQ_1832(...) \, +#define Z_IS_1832_EQ_1832U(...) \, +#define Z_IS_1832U_EQ_1832U(...) \, +#define Z_IS_1833_EQ_1833(...) \, +#define Z_IS_1833U_EQ_1833(...) \, +#define Z_IS_1833_EQ_1833U(...) \, +#define Z_IS_1833U_EQ_1833U(...) \, +#define Z_IS_1834_EQ_1834(...) \, +#define Z_IS_1834U_EQ_1834(...) \, +#define Z_IS_1834_EQ_1834U(...) \, +#define Z_IS_1834U_EQ_1834U(...) \, +#define Z_IS_1835_EQ_1835(...) \, +#define Z_IS_1835U_EQ_1835(...) \, +#define Z_IS_1835_EQ_1835U(...) \, +#define Z_IS_1835U_EQ_1835U(...) \, +#define Z_IS_1836_EQ_1836(...) \, +#define Z_IS_1836U_EQ_1836(...) \, +#define Z_IS_1836_EQ_1836U(...) \, +#define Z_IS_1836U_EQ_1836U(...) \, +#define Z_IS_1837_EQ_1837(...) \, +#define Z_IS_1837U_EQ_1837(...) \, +#define Z_IS_1837_EQ_1837U(...) \, +#define Z_IS_1837U_EQ_1837U(...) \, +#define Z_IS_1838_EQ_1838(...) \, +#define Z_IS_1838U_EQ_1838(...) \, +#define Z_IS_1838_EQ_1838U(...) \, +#define Z_IS_1838U_EQ_1838U(...) \, +#define Z_IS_1839_EQ_1839(...) \, +#define Z_IS_1839U_EQ_1839(...) \, +#define Z_IS_1839_EQ_1839U(...) \, +#define Z_IS_1839U_EQ_1839U(...) \, +#define Z_IS_1840_EQ_1840(...) \, +#define Z_IS_1840U_EQ_1840(...) \, +#define Z_IS_1840_EQ_1840U(...) \, +#define Z_IS_1840U_EQ_1840U(...) \, +#define Z_IS_1841_EQ_1841(...) \, +#define Z_IS_1841U_EQ_1841(...) \, +#define Z_IS_1841_EQ_1841U(...) \, +#define Z_IS_1841U_EQ_1841U(...) \, +#define Z_IS_1842_EQ_1842(...) \, +#define Z_IS_1842U_EQ_1842(...) \, +#define Z_IS_1842_EQ_1842U(...) \, +#define Z_IS_1842U_EQ_1842U(...) \, +#define Z_IS_1843_EQ_1843(...) \, +#define Z_IS_1843U_EQ_1843(...) \, +#define Z_IS_1843_EQ_1843U(...) \, +#define Z_IS_1843U_EQ_1843U(...) \, +#define Z_IS_1844_EQ_1844(...) \, +#define Z_IS_1844U_EQ_1844(...) \, +#define Z_IS_1844_EQ_1844U(...) \, +#define Z_IS_1844U_EQ_1844U(...) \, +#define Z_IS_1845_EQ_1845(...) \, +#define Z_IS_1845U_EQ_1845(...) \, +#define Z_IS_1845_EQ_1845U(...) \, +#define Z_IS_1845U_EQ_1845U(...) \, +#define Z_IS_1846_EQ_1846(...) \, +#define Z_IS_1846U_EQ_1846(...) \, +#define Z_IS_1846_EQ_1846U(...) \, +#define Z_IS_1846U_EQ_1846U(...) \, +#define Z_IS_1847_EQ_1847(...) \, +#define Z_IS_1847U_EQ_1847(...) \, +#define Z_IS_1847_EQ_1847U(...) \, +#define Z_IS_1847U_EQ_1847U(...) \, +#define Z_IS_1848_EQ_1848(...) \, +#define Z_IS_1848U_EQ_1848(...) \, +#define Z_IS_1848_EQ_1848U(...) \, +#define Z_IS_1848U_EQ_1848U(...) \, +#define Z_IS_1849_EQ_1849(...) \, +#define Z_IS_1849U_EQ_1849(...) \, +#define Z_IS_1849_EQ_1849U(...) \, +#define Z_IS_1849U_EQ_1849U(...) \, +#define Z_IS_1850_EQ_1850(...) \, +#define Z_IS_1850U_EQ_1850(...) \, +#define Z_IS_1850_EQ_1850U(...) \, +#define Z_IS_1850U_EQ_1850U(...) \, +#define Z_IS_1851_EQ_1851(...) \, +#define Z_IS_1851U_EQ_1851(...) \, +#define Z_IS_1851_EQ_1851U(...) \, +#define Z_IS_1851U_EQ_1851U(...) \, +#define Z_IS_1852_EQ_1852(...) \, +#define Z_IS_1852U_EQ_1852(...) \, +#define Z_IS_1852_EQ_1852U(...) \, +#define Z_IS_1852U_EQ_1852U(...) \, +#define Z_IS_1853_EQ_1853(...) \, +#define Z_IS_1853U_EQ_1853(...) \, +#define Z_IS_1853_EQ_1853U(...) \, +#define Z_IS_1853U_EQ_1853U(...) \, +#define Z_IS_1854_EQ_1854(...) \, +#define Z_IS_1854U_EQ_1854(...) \, +#define Z_IS_1854_EQ_1854U(...) \, +#define Z_IS_1854U_EQ_1854U(...) \, +#define Z_IS_1855_EQ_1855(...) \, +#define Z_IS_1855U_EQ_1855(...) \, +#define Z_IS_1855_EQ_1855U(...) \, +#define Z_IS_1855U_EQ_1855U(...) \, +#define Z_IS_1856_EQ_1856(...) \, +#define Z_IS_1856U_EQ_1856(...) \, +#define Z_IS_1856_EQ_1856U(...) \, +#define Z_IS_1856U_EQ_1856U(...) \, +#define Z_IS_1857_EQ_1857(...) \, +#define Z_IS_1857U_EQ_1857(...) \, +#define Z_IS_1857_EQ_1857U(...) \, +#define Z_IS_1857U_EQ_1857U(...) \, +#define Z_IS_1858_EQ_1858(...) \, +#define Z_IS_1858U_EQ_1858(...) \, +#define Z_IS_1858_EQ_1858U(...) \, +#define Z_IS_1858U_EQ_1858U(...) \, +#define Z_IS_1859_EQ_1859(...) \, +#define Z_IS_1859U_EQ_1859(...) \, +#define Z_IS_1859_EQ_1859U(...) \, +#define Z_IS_1859U_EQ_1859U(...) \, +#define Z_IS_1860_EQ_1860(...) \, +#define Z_IS_1860U_EQ_1860(...) \, +#define Z_IS_1860_EQ_1860U(...) \, +#define Z_IS_1860U_EQ_1860U(...) \, +#define Z_IS_1861_EQ_1861(...) \, +#define Z_IS_1861U_EQ_1861(...) \, +#define Z_IS_1861_EQ_1861U(...) \, +#define Z_IS_1861U_EQ_1861U(...) \, +#define Z_IS_1862_EQ_1862(...) \, +#define Z_IS_1862U_EQ_1862(...) \, +#define Z_IS_1862_EQ_1862U(...) \, +#define Z_IS_1862U_EQ_1862U(...) \, +#define Z_IS_1863_EQ_1863(...) \, +#define Z_IS_1863U_EQ_1863(...) \, +#define Z_IS_1863_EQ_1863U(...) \, +#define Z_IS_1863U_EQ_1863U(...) \, +#define Z_IS_1864_EQ_1864(...) \, +#define Z_IS_1864U_EQ_1864(...) \, +#define Z_IS_1864_EQ_1864U(...) \, +#define Z_IS_1864U_EQ_1864U(...) \, +#define Z_IS_1865_EQ_1865(...) \, +#define Z_IS_1865U_EQ_1865(...) \, +#define Z_IS_1865_EQ_1865U(...) \, +#define Z_IS_1865U_EQ_1865U(...) \, +#define Z_IS_1866_EQ_1866(...) \, +#define Z_IS_1866U_EQ_1866(...) \, +#define Z_IS_1866_EQ_1866U(...) \, +#define Z_IS_1866U_EQ_1866U(...) \, +#define Z_IS_1867_EQ_1867(...) \, +#define Z_IS_1867U_EQ_1867(...) \, +#define Z_IS_1867_EQ_1867U(...) \, +#define Z_IS_1867U_EQ_1867U(...) \, +#define Z_IS_1868_EQ_1868(...) \, +#define Z_IS_1868U_EQ_1868(...) \, +#define Z_IS_1868_EQ_1868U(...) \, +#define Z_IS_1868U_EQ_1868U(...) \, +#define Z_IS_1869_EQ_1869(...) \, +#define Z_IS_1869U_EQ_1869(...) \, +#define Z_IS_1869_EQ_1869U(...) \, +#define Z_IS_1869U_EQ_1869U(...) \, +#define Z_IS_1870_EQ_1870(...) \, +#define Z_IS_1870U_EQ_1870(...) \, +#define Z_IS_1870_EQ_1870U(...) \, +#define Z_IS_1870U_EQ_1870U(...) \, +#define Z_IS_1871_EQ_1871(...) \, +#define Z_IS_1871U_EQ_1871(...) \, +#define Z_IS_1871_EQ_1871U(...) \, +#define Z_IS_1871U_EQ_1871U(...) \, +#define Z_IS_1872_EQ_1872(...) \, +#define Z_IS_1872U_EQ_1872(...) \, +#define Z_IS_1872_EQ_1872U(...) \, +#define Z_IS_1872U_EQ_1872U(...) \, +#define Z_IS_1873_EQ_1873(...) \, +#define Z_IS_1873U_EQ_1873(...) \, +#define Z_IS_1873_EQ_1873U(...) \, +#define Z_IS_1873U_EQ_1873U(...) \, +#define Z_IS_1874_EQ_1874(...) \, +#define Z_IS_1874U_EQ_1874(...) \, +#define Z_IS_1874_EQ_1874U(...) \, +#define Z_IS_1874U_EQ_1874U(...) \, +#define Z_IS_1875_EQ_1875(...) \, +#define Z_IS_1875U_EQ_1875(...) \, +#define Z_IS_1875_EQ_1875U(...) \, +#define Z_IS_1875U_EQ_1875U(...) \, +#define Z_IS_1876_EQ_1876(...) \, +#define Z_IS_1876U_EQ_1876(...) \, +#define Z_IS_1876_EQ_1876U(...) \, +#define Z_IS_1876U_EQ_1876U(...) \, +#define Z_IS_1877_EQ_1877(...) \, +#define Z_IS_1877U_EQ_1877(...) \, +#define Z_IS_1877_EQ_1877U(...) \, +#define Z_IS_1877U_EQ_1877U(...) \, +#define Z_IS_1878_EQ_1878(...) \, +#define Z_IS_1878U_EQ_1878(...) \, +#define Z_IS_1878_EQ_1878U(...) \, +#define Z_IS_1878U_EQ_1878U(...) \, +#define Z_IS_1879_EQ_1879(...) \, +#define Z_IS_1879U_EQ_1879(...) \, +#define Z_IS_1879_EQ_1879U(...) \, +#define Z_IS_1879U_EQ_1879U(...) \, +#define Z_IS_1880_EQ_1880(...) \, +#define Z_IS_1880U_EQ_1880(...) \, +#define Z_IS_1880_EQ_1880U(...) \, +#define Z_IS_1880U_EQ_1880U(...) \, +#define Z_IS_1881_EQ_1881(...) \, +#define Z_IS_1881U_EQ_1881(...) \, +#define Z_IS_1881_EQ_1881U(...) \, +#define Z_IS_1881U_EQ_1881U(...) \, +#define Z_IS_1882_EQ_1882(...) \, +#define Z_IS_1882U_EQ_1882(...) \, +#define Z_IS_1882_EQ_1882U(...) \, +#define Z_IS_1882U_EQ_1882U(...) \, +#define Z_IS_1883_EQ_1883(...) \, +#define Z_IS_1883U_EQ_1883(...) \, +#define Z_IS_1883_EQ_1883U(...) \, +#define Z_IS_1883U_EQ_1883U(...) \, +#define Z_IS_1884_EQ_1884(...) \, +#define Z_IS_1884U_EQ_1884(...) \, +#define Z_IS_1884_EQ_1884U(...) \, +#define Z_IS_1884U_EQ_1884U(...) \, +#define Z_IS_1885_EQ_1885(...) \, +#define Z_IS_1885U_EQ_1885(...) \, +#define Z_IS_1885_EQ_1885U(...) \, +#define Z_IS_1885U_EQ_1885U(...) \, +#define Z_IS_1886_EQ_1886(...) \, +#define Z_IS_1886U_EQ_1886(...) \, +#define Z_IS_1886_EQ_1886U(...) \, +#define Z_IS_1886U_EQ_1886U(...) \, +#define Z_IS_1887_EQ_1887(...) \, +#define Z_IS_1887U_EQ_1887(...) \, +#define Z_IS_1887_EQ_1887U(...) \, +#define Z_IS_1887U_EQ_1887U(...) \, +#define Z_IS_1888_EQ_1888(...) \, +#define Z_IS_1888U_EQ_1888(...) \, +#define Z_IS_1888_EQ_1888U(...) \, +#define Z_IS_1888U_EQ_1888U(...) \, +#define Z_IS_1889_EQ_1889(...) \, +#define Z_IS_1889U_EQ_1889(...) \, +#define Z_IS_1889_EQ_1889U(...) \, +#define Z_IS_1889U_EQ_1889U(...) \, +#define Z_IS_1890_EQ_1890(...) \, +#define Z_IS_1890U_EQ_1890(...) \, +#define Z_IS_1890_EQ_1890U(...) \, +#define Z_IS_1890U_EQ_1890U(...) \, +#define Z_IS_1891_EQ_1891(...) \, +#define Z_IS_1891U_EQ_1891(...) \, +#define Z_IS_1891_EQ_1891U(...) \, +#define Z_IS_1891U_EQ_1891U(...) \, +#define Z_IS_1892_EQ_1892(...) \, +#define Z_IS_1892U_EQ_1892(...) \, +#define Z_IS_1892_EQ_1892U(...) \, +#define Z_IS_1892U_EQ_1892U(...) \, +#define Z_IS_1893_EQ_1893(...) \, +#define Z_IS_1893U_EQ_1893(...) \, +#define Z_IS_1893_EQ_1893U(...) \, +#define Z_IS_1893U_EQ_1893U(...) \, +#define Z_IS_1894_EQ_1894(...) \, +#define Z_IS_1894U_EQ_1894(...) \, +#define Z_IS_1894_EQ_1894U(...) \, +#define Z_IS_1894U_EQ_1894U(...) \, +#define Z_IS_1895_EQ_1895(...) \, +#define Z_IS_1895U_EQ_1895(...) \, +#define Z_IS_1895_EQ_1895U(...) \, +#define Z_IS_1895U_EQ_1895U(...) \, +#define Z_IS_1896_EQ_1896(...) \, +#define Z_IS_1896U_EQ_1896(...) \, +#define Z_IS_1896_EQ_1896U(...) \, +#define Z_IS_1896U_EQ_1896U(...) \, +#define Z_IS_1897_EQ_1897(...) \, +#define Z_IS_1897U_EQ_1897(...) \, +#define Z_IS_1897_EQ_1897U(...) \, +#define Z_IS_1897U_EQ_1897U(...) \, +#define Z_IS_1898_EQ_1898(...) \, +#define Z_IS_1898U_EQ_1898(...) \, +#define Z_IS_1898_EQ_1898U(...) \, +#define Z_IS_1898U_EQ_1898U(...) \, +#define Z_IS_1899_EQ_1899(...) \, +#define Z_IS_1899U_EQ_1899(...) \, +#define Z_IS_1899_EQ_1899U(...) \, +#define Z_IS_1899U_EQ_1899U(...) \, +#define Z_IS_1900_EQ_1900(...) \, +#define Z_IS_1900U_EQ_1900(...) \, +#define Z_IS_1900_EQ_1900U(...) \, +#define Z_IS_1900U_EQ_1900U(...) \, +#define Z_IS_1901_EQ_1901(...) \, +#define Z_IS_1901U_EQ_1901(...) \, +#define Z_IS_1901_EQ_1901U(...) \, +#define Z_IS_1901U_EQ_1901U(...) \, +#define Z_IS_1902_EQ_1902(...) \, +#define Z_IS_1902U_EQ_1902(...) \, +#define Z_IS_1902_EQ_1902U(...) \, +#define Z_IS_1902U_EQ_1902U(...) \, +#define Z_IS_1903_EQ_1903(...) \, +#define Z_IS_1903U_EQ_1903(...) \, +#define Z_IS_1903_EQ_1903U(...) \, +#define Z_IS_1903U_EQ_1903U(...) \, +#define Z_IS_1904_EQ_1904(...) \, +#define Z_IS_1904U_EQ_1904(...) \, +#define Z_IS_1904_EQ_1904U(...) \, +#define Z_IS_1904U_EQ_1904U(...) \, +#define Z_IS_1905_EQ_1905(...) \, +#define Z_IS_1905U_EQ_1905(...) \, +#define Z_IS_1905_EQ_1905U(...) \, +#define Z_IS_1905U_EQ_1905U(...) \, +#define Z_IS_1906_EQ_1906(...) \, +#define Z_IS_1906U_EQ_1906(...) \, +#define Z_IS_1906_EQ_1906U(...) \, +#define Z_IS_1906U_EQ_1906U(...) \, +#define Z_IS_1907_EQ_1907(...) \, +#define Z_IS_1907U_EQ_1907(...) \, +#define Z_IS_1907_EQ_1907U(...) \, +#define Z_IS_1907U_EQ_1907U(...) \, +#define Z_IS_1908_EQ_1908(...) \, +#define Z_IS_1908U_EQ_1908(...) \, +#define Z_IS_1908_EQ_1908U(...) \, +#define Z_IS_1908U_EQ_1908U(...) \, +#define Z_IS_1909_EQ_1909(...) \, +#define Z_IS_1909U_EQ_1909(...) \, +#define Z_IS_1909_EQ_1909U(...) \, +#define Z_IS_1909U_EQ_1909U(...) \, +#define Z_IS_1910_EQ_1910(...) \, +#define Z_IS_1910U_EQ_1910(...) \, +#define Z_IS_1910_EQ_1910U(...) \, +#define Z_IS_1910U_EQ_1910U(...) \, +#define Z_IS_1911_EQ_1911(...) \, +#define Z_IS_1911U_EQ_1911(...) \, +#define Z_IS_1911_EQ_1911U(...) \, +#define Z_IS_1911U_EQ_1911U(...) \, +#define Z_IS_1912_EQ_1912(...) \, +#define Z_IS_1912U_EQ_1912(...) \, +#define Z_IS_1912_EQ_1912U(...) \, +#define Z_IS_1912U_EQ_1912U(...) \, +#define Z_IS_1913_EQ_1913(...) \, +#define Z_IS_1913U_EQ_1913(...) \, +#define Z_IS_1913_EQ_1913U(...) \, +#define Z_IS_1913U_EQ_1913U(...) \, +#define Z_IS_1914_EQ_1914(...) \, +#define Z_IS_1914U_EQ_1914(...) \, +#define Z_IS_1914_EQ_1914U(...) \, +#define Z_IS_1914U_EQ_1914U(...) \, +#define Z_IS_1915_EQ_1915(...) \, +#define Z_IS_1915U_EQ_1915(...) \, +#define Z_IS_1915_EQ_1915U(...) \, +#define Z_IS_1915U_EQ_1915U(...) \, +#define Z_IS_1916_EQ_1916(...) \, +#define Z_IS_1916U_EQ_1916(...) \, +#define Z_IS_1916_EQ_1916U(...) \, +#define Z_IS_1916U_EQ_1916U(...) \, +#define Z_IS_1917_EQ_1917(...) \, +#define Z_IS_1917U_EQ_1917(...) \, +#define Z_IS_1917_EQ_1917U(...) \, +#define Z_IS_1917U_EQ_1917U(...) \, +#define Z_IS_1918_EQ_1918(...) \, +#define Z_IS_1918U_EQ_1918(...) \, +#define Z_IS_1918_EQ_1918U(...) \, +#define Z_IS_1918U_EQ_1918U(...) \, +#define Z_IS_1919_EQ_1919(...) \, +#define Z_IS_1919U_EQ_1919(...) \, +#define Z_IS_1919_EQ_1919U(...) \, +#define Z_IS_1919U_EQ_1919U(...) \, +#define Z_IS_1920_EQ_1920(...) \, +#define Z_IS_1920U_EQ_1920(...) \, +#define Z_IS_1920_EQ_1920U(...) \, +#define Z_IS_1920U_EQ_1920U(...) \, +#define Z_IS_1921_EQ_1921(...) \, +#define Z_IS_1921U_EQ_1921(...) \, +#define Z_IS_1921_EQ_1921U(...) \, +#define Z_IS_1921U_EQ_1921U(...) \, +#define Z_IS_1922_EQ_1922(...) \, +#define Z_IS_1922U_EQ_1922(...) \, +#define Z_IS_1922_EQ_1922U(...) \, +#define Z_IS_1922U_EQ_1922U(...) \, +#define Z_IS_1923_EQ_1923(...) \, +#define Z_IS_1923U_EQ_1923(...) \, +#define Z_IS_1923_EQ_1923U(...) \, +#define Z_IS_1923U_EQ_1923U(...) \, +#define Z_IS_1924_EQ_1924(...) \, +#define Z_IS_1924U_EQ_1924(...) \, +#define Z_IS_1924_EQ_1924U(...) \, +#define Z_IS_1924U_EQ_1924U(...) \, +#define Z_IS_1925_EQ_1925(...) \, +#define Z_IS_1925U_EQ_1925(...) \, +#define Z_IS_1925_EQ_1925U(...) \, +#define Z_IS_1925U_EQ_1925U(...) \, +#define Z_IS_1926_EQ_1926(...) \, +#define Z_IS_1926U_EQ_1926(...) \, +#define Z_IS_1926_EQ_1926U(...) \, +#define Z_IS_1926U_EQ_1926U(...) \, +#define Z_IS_1927_EQ_1927(...) \, +#define Z_IS_1927U_EQ_1927(...) \, +#define Z_IS_1927_EQ_1927U(...) \, +#define Z_IS_1927U_EQ_1927U(...) \, +#define Z_IS_1928_EQ_1928(...) \, +#define Z_IS_1928U_EQ_1928(...) \, +#define Z_IS_1928_EQ_1928U(...) \, +#define Z_IS_1928U_EQ_1928U(...) \, +#define Z_IS_1929_EQ_1929(...) \, +#define Z_IS_1929U_EQ_1929(...) \, +#define Z_IS_1929_EQ_1929U(...) \, +#define Z_IS_1929U_EQ_1929U(...) \, +#define Z_IS_1930_EQ_1930(...) \, +#define Z_IS_1930U_EQ_1930(...) \, +#define Z_IS_1930_EQ_1930U(...) \, +#define Z_IS_1930U_EQ_1930U(...) \, +#define Z_IS_1931_EQ_1931(...) \, +#define Z_IS_1931U_EQ_1931(...) \, +#define Z_IS_1931_EQ_1931U(...) \, +#define Z_IS_1931U_EQ_1931U(...) \, +#define Z_IS_1932_EQ_1932(...) \, +#define Z_IS_1932U_EQ_1932(...) \, +#define Z_IS_1932_EQ_1932U(...) \, +#define Z_IS_1932U_EQ_1932U(...) \, +#define Z_IS_1933_EQ_1933(...) \, +#define Z_IS_1933U_EQ_1933(...) \, +#define Z_IS_1933_EQ_1933U(...) \, +#define Z_IS_1933U_EQ_1933U(...) \, +#define Z_IS_1934_EQ_1934(...) \, +#define Z_IS_1934U_EQ_1934(...) \, +#define Z_IS_1934_EQ_1934U(...) \, +#define Z_IS_1934U_EQ_1934U(...) \, +#define Z_IS_1935_EQ_1935(...) \, +#define Z_IS_1935U_EQ_1935(...) \, +#define Z_IS_1935_EQ_1935U(...) \, +#define Z_IS_1935U_EQ_1935U(...) \, +#define Z_IS_1936_EQ_1936(...) \, +#define Z_IS_1936U_EQ_1936(...) \, +#define Z_IS_1936_EQ_1936U(...) \, +#define Z_IS_1936U_EQ_1936U(...) \, +#define Z_IS_1937_EQ_1937(...) \, +#define Z_IS_1937U_EQ_1937(...) \, +#define Z_IS_1937_EQ_1937U(...) \, +#define Z_IS_1937U_EQ_1937U(...) \, +#define Z_IS_1938_EQ_1938(...) \, +#define Z_IS_1938U_EQ_1938(...) \, +#define Z_IS_1938_EQ_1938U(...) \, +#define Z_IS_1938U_EQ_1938U(...) \, +#define Z_IS_1939_EQ_1939(...) \, +#define Z_IS_1939U_EQ_1939(...) \, +#define Z_IS_1939_EQ_1939U(...) \, +#define Z_IS_1939U_EQ_1939U(...) \, +#define Z_IS_1940_EQ_1940(...) \, +#define Z_IS_1940U_EQ_1940(...) \, +#define Z_IS_1940_EQ_1940U(...) \, +#define Z_IS_1940U_EQ_1940U(...) \, +#define Z_IS_1941_EQ_1941(...) \, +#define Z_IS_1941U_EQ_1941(...) \, +#define Z_IS_1941_EQ_1941U(...) \, +#define Z_IS_1941U_EQ_1941U(...) \, +#define Z_IS_1942_EQ_1942(...) \, +#define Z_IS_1942U_EQ_1942(...) \, +#define Z_IS_1942_EQ_1942U(...) \, +#define Z_IS_1942U_EQ_1942U(...) \, +#define Z_IS_1943_EQ_1943(...) \, +#define Z_IS_1943U_EQ_1943(...) \, +#define Z_IS_1943_EQ_1943U(...) \, +#define Z_IS_1943U_EQ_1943U(...) \, +#define Z_IS_1944_EQ_1944(...) \, +#define Z_IS_1944U_EQ_1944(...) \, +#define Z_IS_1944_EQ_1944U(...) \, +#define Z_IS_1944U_EQ_1944U(...) \, +#define Z_IS_1945_EQ_1945(...) \, +#define Z_IS_1945U_EQ_1945(...) \, +#define Z_IS_1945_EQ_1945U(...) \, +#define Z_IS_1945U_EQ_1945U(...) \, +#define Z_IS_1946_EQ_1946(...) \, +#define Z_IS_1946U_EQ_1946(...) \, +#define Z_IS_1946_EQ_1946U(...) \, +#define Z_IS_1946U_EQ_1946U(...) \, +#define Z_IS_1947_EQ_1947(...) \, +#define Z_IS_1947U_EQ_1947(...) \, +#define Z_IS_1947_EQ_1947U(...) \, +#define Z_IS_1947U_EQ_1947U(...) \, +#define Z_IS_1948_EQ_1948(...) \, +#define Z_IS_1948U_EQ_1948(...) \, +#define Z_IS_1948_EQ_1948U(...) \, +#define Z_IS_1948U_EQ_1948U(...) \, +#define Z_IS_1949_EQ_1949(...) \, +#define Z_IS_1949U_EQ_1949(...) \, +#define Z_IS_1949_EQ_1949U(...) \, +#define Z_IS_1949U_EQ_1949U(...) \, +#define Z_IS_1950_EQ_1950(...) \, +#define Z_IS_1950U_EQ_1950(...) \, +#define Z_IS_1950_EQ_1950U(...) \, +#define Z_IS_1950U_EQ_1950U(...) \, +#define Z_IS_1951_EQ_1951(...) \, +#define Z_IS_1951U_EQ_1951(...) \, +#define Z_IS_1951_EQ_1951U(...) \, +#define Z_IS_1951U_EQ_1951U(...) \, +#define Z_IS_1952_EQ_1952(...) \, +#define Z_IS_1952U_EQ_1952(...) \, +#define Z_IS_1952_EQ_1952U(...) \, +#define Z_IS_1952U_EQ_1952U(...) \, +#define Z_IS_1953_EQ_1953(...) \, +#define Z_IS_1953U_EQ_1953(...) \, +#define Z_IS_1953_EQ_1953U(...) \, +#define Z_IS_1953U_EQ_1953U(...) \, +#define Z_IS_1954_EQ_1954(...) \, +#define Z_IS_1954U_EQ_1954(...) \, +#define Z_IS_1954_EQ_1954U(...) \, +#define Z_IS_1954U_EQ_1954U(...) \, +#define Z_IS_1955_EQ_1955(...) \, +#define Z_IS_1955U_EQ_1955(...) \, +#define Z_IS_1955_EQ_1955U(...) \, +#define Z_IS_1955U_EQ_1955U(...) \, +#define Z_IS_1956_EQ_1956(...) \, +#define Z_IS_1956U_EQ_1956(...) \, +#define Z_IS_1956_EQ_1956U(...) \, +#define Z_IS_1956U_EQ_1956U(...) \, +#define Z_IS_1957_EQ_1957(...) \, +#define Z_IS_1957U_EQ_1957(...) \, +#define Z_IS_1957_EQ_1957U(...) \, +#define Z_IS_1957U_EQ_1957U(...) \, +#define Z_IS_1958_EQ_1958(...) \, +#define Z_IS_1958U_EQ_1958(...) \, +#define Z_IS_1958_EQ_1958U(...) \, +#define Z_IS_1958U_EQ_1958U(...) \, +#define Z_IS_1959_EQ_1959(...) \, +#define Z_IS_1959U_EQ_1959(...) \, +#define Z_IS_1959_EQ_1959U(...) \, +#define Z_IS_1959U_EQ_1959U(...) \, +#define Z_IS_1960_EQ_1960(...) \, +#define Z_IS_1960U_EQ_1960(...) \, +#define Z_IS_1960_EQ_1960U(...) \, +#define Z_IS_1960U_EQ_1960U(...) \, +#define Z_IS_1961_EQ_1961(...) \, +#define Z_IS_1961U_EQ_1961(...) \, +#define Z_IS_1961_EQ_1961U(...) \, +#define Z_IS_1961U_EQ_1961U(...) \, +#define Z_IS_1962_EQ_1962(...) \, +#define Z_IS_1962U_EQ_1962(...) \, +#define Z_IS_1962_EQ_1962U(...) \, +#define Z_IS_1962U_EQ_1962U(...) \, +#define Z_IS_1963_EQ_1963(...) \, +#define Z_IS_1963U_EQ_1963(...) \, +#define Z_IS_1963_EQ_1963U(...) \, +#define Z_IS_1963U_EQ_1963U(...) \, +#define Z_IS_1964_EQ_1964(...) \, +#define Z_IS_1964U_EQ_1964(...) \, +#define Z_IS_1964_EQ_1964U(...) \, +#define Z_IS_1964U_EQ_1964U(...) \, +#define Z_IS_1965_EQ_1965(...) \, +#define Z_IS_1965U_EQ_1965(...) \, +#define Z_IS_1965_EQ_1965U(...) \, +#define Z_IS_1965U_EQ_1965U(...) \, +#define Z_IS_1966_EQ_1966(...) \, +#define Z_IS_1966U_EQ_1966(...) \, +#define Z_IS_1966_EQ_1966U(...) \, +#define Z_IS_1966U_EQ_1966U(...) \, +#define Z_IS_1967_EQ_1967(...) \, +#define Z_IS_1967U_EQ_1967(...) \, +#define Z_IS_1967_EQ_1967U(...) \, +#define Z_IS_1967U_EQ_1967U(...) \, +#define Z_IS_1968_EQ_1968(...) \, +#define Z_IS_1968U_EQ_1968(...) \, +#define Z_IS_1968_EQ_1968U(...) \, +#define Z_IS_1968U_EQ_1968U(...) \, +#define Z_IS_1969_EQ_1969(...) \, +#define Z_IS_1969U_EQ_1969(...) \, +#define Z_IS_1969_EQ_1969U(...) \, +#define Z_IS_1969U_EQ_1969U(...) \, +#define Z_IS_1970_EQ_1970(...) \, +#define Z_IS_1970U_EQ_1970(...) \, +#define Z_IS_1970_EQ_1970U(...) \, +#define Z_IS_1970U_EQ_1970U(...) \, +#define Z_IS_1971_EQ_1971(...) \, +#define Z_IS_1971U_EQ_1971(...) \, +#define Z_IS_1971_EQ_1971U(...) \, +#define Z_IS_1971U_EQ_1971U(...) \, +#define Z_IS_1972_EQ_1972(...) \, +#define Z_IS_1972U_EQ_1972(...) \, +#define Z_IS_1972_EQ_1972U(...) \, +#define Z_IS_1972U_EQ_1972U(...) \, +#define Z_IS_1973_EQ_1973(...) \, +#define Z_IS_1973U_EQ_1973(...) \, +#define Z_IS_1973_EQ_1973U(...) \, +#define Z_IS_1973U_EQ_1973U(...) \, +#define Z_IS_1974_EQ_1974(...) \, +#define Z_IS_1974U_EQ_1974(...) \, +#define Z_IS_1974_EQ_1974U(...) \, +#define Z_IS_1974U_EQ_1974U(...) \, +#define Z_IS_1975_EQ_1975(...) \, +#define Z_IS_1975U_EQ_1975(...) \, +#define Z_IS_1975_EQ_1975U(...) \, +#define Z_IS_1975U_EQ_1975U(...) \, +#define Z_IS_1976_EQ_1976(...) \, +#define Z_IS_1976U_EQ_1976(...) \, +#define Z_IS_1976_EQ_1976U(...) \, +#define Z_IS_1976U_EQ_1976U(...) \, +#define Z_IS_1977_EQ_1977(...) \, +#define Z_IS_1977U_EQ_1977(...) \, +#define Z_IS_1977_EQ_1977U(...) \, +#define Z_IS_1977U_EQ_1977U(...) \, +#define Z_IS_1978_EQ_1978(...) \, +#define Z_IS_1978U_EQ_1978(...) \, +#define Z_IS_1978_EQ_1978U(...) \, +#define Z_IS_1978U_EQ_1978U(...) \, +#define Z_IS_1979_EQ_1979(...) \, +#define Z_IS_1979U_EQ_1979(...) \, +#define Z_IS_1979_EQ_1979U(...) \, +#define Z_IS_1979U_EQ_1979U(...) \, +#define Z_IS_1980_EQ_1980(...) \, +#define Z_IS_1980U_EQ_1980(...) \, +#define Z_IS_1980_EQ_1980U(...) \, +#define Z_IS_1980U_EQ_1980U(...) \, +#define Z_IS_1981_EQ_1981(...) \, +#define Z_IS_1981U_EQ_1981(...) \, +#define Z_IS_1981_EQ_1981U(...) \, +#define Z_IS_1981U_EQ_1981U(...) \, +#define Z_IS_1982_EQ_1982(...) \, +#define Z_IS_1982U_EQ_1982(...) \, +#define Z_IS_1982_EQ_1982U(...) \, +#define Z_IS_1982U_EQ_1982U(...) \, +#define Z_IS_1983_EQ_1983(...) \, +#define Z_IS_1983U_EQ_1983(...) \, +#define Z_IS_1983_EQ_1983U(...) \, +#define Z_IS_1983U_EQ_1983U(...) \, +#define Z_IS_1984_EQ_1984(...) \, +#define Z_IS_1984U_EQ_1984(...) \, +#define Z_IS_1984_EQ_1984U(...) \, +#define Z_IS_1984U_EQ_1984U(...) \, +#define Z_IS_1985_EQ_1985(...) \, +#define Z_IS_1985U_EQ_1985(...) \, +#define Z_IS_1985_EQ_1985U(...) \, +#define Z_IS_1985U_EQ_1985U(...) \, +#define Z_IS_1986_EQ_1986(...) \, +#define Z_IS_1986U_EQ_1986(...) \, +#define Z_IS_1986_EQ_1986U(...) \, +#define Z_IS_1986U_EQ_1986U(...) \, +#define Z_IS_1987_EQ_1987(...) \, +#define Z_IS_1987U_EQ_1987(...) \, +#define Z_IS_1987_EQ_1987U(...) \, +#define Z_IS_1987U_EQ_1987U(...) \, +#define Z_IS_1988_EQ_1988(...) \, +#define Z_IS_1988U_EQ_1988(...) \, +#define Z_IS_1988_EQ_1988U(...) \, +#define Z_IS_1988U_EQ_1988U(...) \, +#define Z_IS_1989_EQ_1989(...) \, +#define Z_IS_1989U_EQ_1989(...) \, +#define Z_IS_1989_EQ_1989U(...) \, +#define Z_IS_1989U_EQ_1989U(...) \, +#define Z_IS_1990_EQ_1990(...) \, +#define Z_IS_1990U_EQ_1990(...) \, +#define Z_IS_1990_EQ_1990U(...) \, +#define Z_IS_1990U_EQ_1990U(...) \, +#define Z_IS_1991_EQ_1991(...) \, +#define Z_IS_1991U_EQ_1991(...) \, +#define Z_IS_1991_EQ_1991U(...) \, +#define Z_IS_1991U_EQ_1991U(...) \, +#define Z_IS_1992_EQ_1992(...) \, +#define Z_IS_1992U_EQ_1992(...) \, +#define Z_IS_1992_EQ_1992U(...) \, +#define Z_IS_1992U_EQ_1992U(...) \, +#define Z_IS_1993_EQ_1993(...) \, +#define Z_IS_1993U_EQ_1993(...) \, +#define Z_IS_1993_EQ_1993U(...) \, +#define Z_IS_1993U_EQ_1993U(...) \, +#define Z_IS_1994_EQ_1994(...) \, +#define Z_IS_1994U_EQ_1994(...) \, +#define Z_IS_1994_EQ_1994U(...) \, +#define Z_IS_1994U_EQ_1994U(...) \, +#define Z_IS_1995_EQ_1995(...) \, +#define Z_IS_1995U_EQ_1995(...) \, +#define Z_IS_1995_EQ_1995U(...) \, +#define Z_IS_1995U_EQ_1995U(...) \, +#define Z_IS_1996_EQ_1996(...) \, +#define Z_IS_1996U_EQ_1996(...) \, +#define Z_IS_1996_EQ_1996U(...) \, +#define Z_IS_1996U_EQ_1996U(...) \, +#define Z_IS_1997_EQ_1997(...) \, +#define Z_IS_1997U_EQ_1997(...) \, +#define Z_IS_1997_EQ_1997U(...) \, +#define Z_IS_1997U_EQ_1997U(...) \, +#define Z_IS_1998_EQ_1998(...) \, +#define Z_IS_1998U_EQ_1998(...) \, +#define Z_IS_1998_EQ_1998U(...) \, +#define Z_IS_1998U_EQ_1998U(...) \, +#define Z_IS_1999_EQ_1999(...) \, +#define Z_IS_1999U_EQ_1999(...) \, +#define Z_IS_1999_EQ_1999U(...) \, +#define Z_IS_1999U_EQ_1999U(...) \, +#define Z_IS_2000_EQ_2000(...) \, +#define Z_IS_2000U_EQ_2000(...) \, +#define Z_IS_2000_EQ_2000U(...) \, +#define Z_IS_2000U_EQ_2000U(...) \, +#define Z_IS_2001_EQ_2001(...) \, +#define Z_IS_2001U_EQ_2001(...) \, +#define Z_IS_2001_EQ_2001U(...) \, +#define Z_IS_2001U_EQ_2001U(...) \, +#define Z_IS_2002_EQ_2002(...) \, +#define Z_IS_2002U_EQ_2002(...) \, +#define Z_IS_2002_EQ_2002U(...) \, +#define Z_IS_2002U_EQ_2002U(...) \, +#define Z_IS_2003_EQ_2003(...) \, +#define Z_IS_2003U_EQ_2003(...) \, +#define Z_IS_2003_EQ_2003U(...) \, +#define Z_IS_2003U_EQ_2003U(...) \, +#define Z_IS_2004_EQ_2004(...) \, +#define Z_IS_2004U_EQ_2004(...) \, +#define Z_IS_2004_EQ_2004U(...) \, +#define Z_IS_2004U_EQ_2004U(...) \, +#define Z_IS_2005_EQ_2005(...) \, +#define Z_IS_2005U_EQ_2005(...) \, +#define Z_IS_2005_EQ_2005U(...) \, +#define Z_IS_2005U_EQ_2005U(...) \, +#define Z_IS_2006_EQ_2006(...) \, +#define Z_IS_2006U_EQ_2006(...) \, +#define Z_IS_2006_EQ_2006U(...) \, +#define Z_IS_2006U_EQ_2006U(...) \, +#define Z_IS_2007_EQ_2007(...) \, +#define Z_IS_2007U_EQ_2007(...) \, +#define Z_IS_2007_EQ_2007U(...) \, +#define Z_IS_2007U_EQ_2007U(...) \, +#define Z_IS_2008_EQ_2008(...) \, +#define Z_IS_2008U_EQ_2008(...) \, +#define Z_IS_2008_EQ_2008U(...) \, +#define Z_IS_2008U_EQ_2008U(...) \, +#define Z_IS_2009_EQ_2009(...) \, +#define Z_IS_2009U_EQ_2009(...) \, +#define Z_IS_2009_EQ_2009U(...) \, +#define Z_IS_2009U_EQ_2009U(...) \, +#define Z_IS_2010_EQ_2010(...) \, +#define Z_IS_2010U_EQ_2010(...) \, +#define Z_IS_2010_EQ_2010U(...) \, +#define Z_IS_2010U_EQ_2010U(...) \, +#define Z_IS_2011_EQ_2011(...) \, +#define Z_IS_2011U_EQ_2011(...) \, +#define Z_IS_2011_EQ_2011U(...) \, +#define Z_IS_2011U_EQ_2011U(...) \, +#define Z_IS_2012_EQ_2012(...) \, +#define Z_IS_2012U_EQ_2012(...) \, +#define Z_IS_2012_EQ_2012U(...) \, +#define Z_IS_2012U_EQ_2012U(...) \, +#define Z_IS_2013_EQ_2013(...) \, +#define Z_IS_2013U_EQ_2013(...) \, +#define Z_IS_2013_EQ_2013U(...) \, +#define Z_IS_2013U_EQ_2013U(...) \, +#define Z_IS_2014_EQ_2014(...) \, +#define Z_IS_2014U_EQ_2014(...) \, +#define Z_IS_2014_EQ_2014U(...) \, +#define Z_IS_2014U_EQ_2014U(...) \, +#define Z_IS_2015_EQ_2015(...) \, +#define Z_IS_2015U_EQ_2015(...) \, +#define Z_IS_2015_EQ_2015U(...) \, +#define Z_IS_2015U_EQ_2015U(...) \, +#define Z_IS_2016_EQ_2016(...) \, +#define Z_IS_2016U_EQ_2016(...) \, +#define Z_IS_2016_EQ_2016U(...) \, +#define Z_IS_2016U_EQ_2016U(...) \, +#define Z_IS_2017_EQ_2017(...) \, +#define Z_IS_2017U_EQ_2017(...) \, +#define Z_IS_2017_EQ_2017U(...) \, +#define Z_IS_2017U_EQ_2017U(...) \, +#define Z_IS_2018_EQ_2018(...) \, +#define Z_IS_2018U_EQ_2018(...) \, +#define Z_IS_2018_EQ_2018U(...) \, +#define Z_IS_2018U_EQ_2018U(...) \, +#define Z_IS_2019_EQ_2019(...) \, +#define Z_IS_2019U_EQ_2019(...) \, +#define Z_IS_2019_EQ_2019U(...) \, +#define Z_IS_2019U_EQ_2019U(...) \, +#define Z_IS_2020_EQ_2020(...) \, +#define Z_IS_2020U_EQ_2020(...) \, +#define Z_IS_2020_EQ_2020U(...) \, +#define Z_IS_2020U_EQ_2020U(...) \, +#define Z_IS_2021_EQ_2021(...) \, +#define Z_IS_2021U_EQ_2021(...) \, +#define Z_IS_2021_EQ_2021U(...) \, +#define Z_IS_2021U_EQ_2021U(...) \, +#define Z_IS_2022_EQ_2022(...) \, +#define Z_IS_2022U_EQ_2022(...) \, +#define Z_IS_2022_EQ_2022U(...) \, +#define Z_IS_2022U_EQ_2022U(...) \, +#define Z_IS_2023_EQ_2023(...) \, +#define Z_IS_2023U_EQ_2023(...) \, +#define Z_IS_2023_EQ_2023U(...) \, +#define Z_IS_2023U_EQ_2023U(...) \, +#define Z_IS_2024_EQ_2024(...) \, +#define Z_IS_2024U_EQ_2024(...) \, +#define Z_IS_2024_EQ_2024U(...) \, +#define Z_IS_2024U_EQ_2024U(...) \, +#define Z_IS_2025_EQ_2025(...) \, +#define Z_IS_2025U_EQ_2025(...) \, +#define Z_IS_2025_EQ_2025U(...) \, +#define Z_IS_2025U_EQ_2025U(...) \, +#define Z_IS_2026_EQ_2026(...) \, +#define Z_IS_2026U_EQ_2026(...) \, +#define Z_IS_2026_EQ_2026U(...) \, +#define Z_IS_2026U_EQ_2026U(...) \, +#define Z_IS_2027_EQ_2027(...) \, +#define Z_IS_2027U_EQ_2027(...) \, +#define Z_IS_2027_EQ_2027U(...) \, +#define Z_IS_2027U_EQ_2027U(...) \, +#define Z_IS_2028_EQ_2028(...) \, +#define Z_IS_2028U_EQ_2028(...) \, +#define Z_IS_2028_EQ_2028U(...) \, +#define Z_IS_2028U_EQ_2028U(...) \, +#define Z_IS_2029_EQ_2029(...) \, +#define Z_IS_2029U_EQ_2029(...) \, +#define Z_IS_2029_EQ_2029U(...) \, +#define Z_IS_2029U_EQ_2029U(...) \, +#define Z_IS_2030_EQ_2030(...) \, +#define Z_IS_2030U_EQ_2030(...) \, +#define Z_IS_2030_EQ_2030U(...) \, +#define Z_IS_2030U_EQ_2030U(...) \, +#define Z_IS_2031_EQ_2031(...) \, +#define Z_IS_2031U_EQ_2031(...) \, +#define Z_IS_2031_EQ_2031U(...) \, +#define Z_IS_2031U_EQ_2031U(...) \, +#define Z_IS_2032_EQ_2032(...) \, +#define Z_IS_2032U_EQ_2032(...) \, +#define Z_IS_2032_EQ_2032U(...) \, +#define Z_IS_2032U_EQ_2032U(...) \, +#define Z_IS_2033_EQ_2033(...) \, +#define Z_IS_2033U_EQ_2033(...) \, +#define Z_IS_2033_EQ_2033U(...) \, +#define Z_IS_2033U_EQ_2033U(...) \, +#define Z_IS_2034_EQ_2034(...) \, +#define Z_IS_2034U_EQ_2034(...) \, +#define Z_IS_2034_EQ_2034U(...) \, +#define Z_IS_2034U_EQ_2034U(...) \, +#define Z_IS_2035_EQ_2035(...) \, +#define Z_IS_2035U_EQ_2035(...) \, +#define Z_IS_2035_EQ_2035U(...) \, +#define Z_IS_2035U_EQ_2035U(...) \, +#define Z_IS_2036_EQ_2036(...) \, +#define Z_IS_2036U_EQ_2036(...) \, +#define Z_IS_2036_EQ_2036U(...) \, +#define Z_IS_2036U_EQ_2036U(...) \, +#define Z_IS_2037_EQ_2037(...) \, +#define Z_IS_2037U_EQ_2037(...) \, +#define Z_IS_2037_EQ_2037U(...) \, +#define Z_IS_2037U_EQ_2037U(...) \, +#define Z_IS_2038_EQ_2038(...) \, +#define Z_IS_2038U_EQ_2038(...) \, +#define Z_IS_2038_EQ_2038U(...) \, +#define Z_IS_2038U_EQ_2038U(...) \, +#define Z_IS_2039_EQ_2039(...) \, +#define Z_IS_2039U_EQ_2039(...) \, +#define Z_IS_2039_EQ_2039U(...) \, +#define Z_IS_2039U_EQ_2039U(...) \, +#define Z_IS_2040_EQ_2040(...) \, +#define Z_IS_2040U_EQ_2040(...) \, +#define Z_IS_2040_EQ_2040U(...) \, +#define Z_IS_2040U_EQ_2040U(...) \, +#define Z_IS_2041_EQ_2041(...) \, +#define Z_IS_2041U_EQ_2041(...) \, +#define Z_IS_2041_EQ_2041U(...) \, +#define Z_IS_2041U_EQ_2041U(...) \, +#define Z_IS_2042_EQ_2042(...) \, +#define Z_IS_2042U_EQ_2042(...) \, +#define Z_IS_2042_EQ_2042U(...) \, +#define Z_IS_2042U_EQ_2042U(...) \, +#define Z_IS_2043_EQ_2043(...) \, +#define Z_IS_2043U_EQ_2043(...) \, +#define Z_IS_2043_EQ_2043U(...) \, +#define Z_IS_2043U_EQ_2043U(...) \, +#define Z_IS_2044_EQ_2044(...) \, +#define Z_IS_2044U_EQ_2044(...) \, +#define Z_IS_2044_EQ_2044U(...) \, +#define Z_IS_2044U_EQ_2044U(...) \, +#define Z_IS_2045_EQ_2045(...) \, +#define Z_IS_2045U_EQ_2045(...) \, +#define Z_IS_2045_EQ_2045U(...) \, +#define Z_IS_2045U_EQ_2045U(...) \, +#define Z_IS_2046_EQ_2046(...) \, +#define Z_IS_2046U_EQ_2046(...) \, +#define Z_IS_2046_EQ_2046U(...) \, +#define Z_IS_2046U_EQ_2046U(...) \, +#define Z_IS_2047_EQ_2047(...) \, +#define Z_IS_2047U_EQ_2047(...) \, +#define Z_IS_2047_EQ_2047U(...) \, +#define Z_IS_2047U_EQ_2047U(...) \, +#define Z_IS_2048_EQ_2048(...) \, +#define Z_IS_2048U_EQ_2048(...) \, +#define Z_IS_2048_EQ_2048U(...) \, +#define Z_IS_2048U_EQ_2048U(...) \, +#define Z_IS_2049_EQ_2049(...) \, +#define Z_IS_2049U_EQ_2049(...) \, +#define Z_IS_2049_EQ_2049U(...) \, +#define Z_IS_2049U_EQ_2049U(...) \, +#define Z_IS_2050_EQ_2050(...) \, +#define Z_IS_2050U_EQ_2050(...) \, +#define Z_IS_2050_EQ_2050U(...) \, +#define Z_IS_2050U_EQ_2050U(...) \, +#define Z_IS_2051_EQ_2051(...) \, +#define Z_IS_2051U_EQ_2051(...) \, +#define Z_IS_2051_EQ_2051U(...) \, +#define Z_IS_2051U_EQ_2051U(...) \, +#define Z_IS_2052_EQ_2052(...) \, +#define Z_IS_2052U_EQ_2052(...) \, +#define Z_IS_2052_EQ_2052U(...) \, +#define Z_IS_2052U_EQ_2052U(...) \, +#define Z_IS_2053_EQ_2053(...) \, +#define Z_IS_2053U_EQ_2053(...) \, +#define Z_IS_2053_EQ_2053U(...) \, +#define Z_IS_2053U_EQ_2053U(...) \, +#define Z_IS_2054_EQ_2054(...) \, +#define Z_IS_2054U_EQ_2054(...) \, +#define Z_IS_2054_EQ_2054U(...) \, +#define Z_IS_2054U_EQ_2054U(...) \, +#define Z_IS_2055_EQ_2055(...) \, +#define Z_IS_2055U_EQ_2055(...) \, +#define Z_IS_2055_EQ_2055U(...) \, +#define Z_IS_2055U_EQ_2055U(...) \, +#define Z_IS_2056_EQ_2056(...) \, +#define Z_IS_2056U_EQ_2056(...) \, +#define Z_IS_2056_EQ_2056U(...) \, +#define Z_IS_2056U_EQ_2056U(...) \, +#define Z_IS_2057_EQ_2057(...) \, +#define Z_IS_2057U_EQ_2057(...) \, +#define Z_IS_2057_EQ_2057U(...) \, +#define Z_IS_2057U_EQ_2057U(...) \, +#define Z_IS_2058_EQ_2058(...) \, +#define Z_IS_2058U_EQ_2058(...) \, +#define Z_IS_2058_EQ_2058U(...) \, +#define Z_IS_2058U_EQ_2058U(...) \, +#define Z_IS_2059_EQ_2059(...) \, +#define Z_IS_2059U_EQ_2059(...) \, +#define Z_IS_2059_EQ_2059U(...) \, +#define Z_IS_2059U_EQ_2059U(...) \, +#define Z_IS_2060_EQ_2060(...) \, +#define Z_IS_2060U_EQ_2060(...) \, +#define Z_IS_2060_EQ_2060U(...) \, +#define Z_IS_2060U_EQ_2060U(...) \, +#define Z_IS_2061_EQ_2061(...) \, +#define Z_IS_2061U_EQ_2061(...) \, +#define Z_IS_2061_EQ_2061U(...) \, +#define Z_IS_2061U_EQ_2061U(...) \, +#define Z_IS_2062_EQ_2062(...) \, +#define Z_IS_2062U_EQ_2062(...) \, +#define Z_IS_2062_EQ_2062U(...) \, +#define Z_IS_2062U_EQ_2062U(...) \, +#define Z_IS_2063_EQ_2063(...) \, +#define Z_IS_2063U_EQ_2063(...) \, +#define Z_IS_2063_EQ_2063U(...) \, +#define Z_IS_2063U_EQ_2063U(...) \, +#define Z_IS_2064_EQ_2064(...) \, +#define Z_IS_2064U_EQ_2064(...) \, +#define Z_IS_2064_EQ_2064U(...) \, +#define Z_IS_2064U_EQ_2064U(...) \, +#define Z_IS_2065_EQ_2065(...) \, +#define Z_IS_2065U_EQ_2065(...) \, +#define Z_IS_2065_EQ_2065U(...) \, +#define Z_IS_2065U_EQ_2065U(...) \, +#define Z_IS_2066_EQ_2066(...) \, +#define Z_IS_2066U_EQ_2066(...) \, +#define Z_IS_2066_EQ_2066U(...) \, +#define Z_IS_2066U_EQ_2066U(...) \, +#define Z_IS_2067_EQ_2067(...) \, +#define Z_IS_2067U_EQ_2067(...) \, +#define Z_IS_2067_EQ_2067U(...) \, +#define Z_IS_2067U_EQ_2067U(...) \, +#define Z_IS_2068_EQ_2068(...) \, +#define Z_IS_2068U_EQ_2068(...) \, +#define Z_IS_2068_EQ_2068U(...) \, +#define Z_IS_2068U_EQ_2068U(...) \, +#define Z_IS_2069_EQ_2069(...) \, +#define Z_IS_2069U_EQ_2069(...) \, +#define Z_IS_2069_EQ_2069U(...) \, +#define Z_IS_2069U_EQ_2069U(...) \, +#define Z_IS_2070_EQ_2070(...) \, +#define Z_IS_2070U_EQ_2070(...) \, +#define Z_IS_2070_EQ_2070U(...) \, +#define Z_IS_2070U_EQ_2070U(...) \, +#define Z_IS_2071_EQ_2071(...) \, +#define Z_IS_2071U_EQ_2071(...) \, +#define Z_IS_2071_EQ_2071U(...) \, +#define Z_IS_2071U_EQ_2071U(...) \, +#define Z_IS_2072_EQ_2072(...) \, +#define Z_IS_2072U_EQ_2072(...) \, +#define Z_IS_2072_EQ_2072U(...) \, +#define Z_IS_2072U_EQ_2072U(...) \, +#define Z_IS_2073_EQ_2073(...) \, +#define Z_IS_2073U_EQ_2073(...) \, +#define Z_IS_2073_EQ_2073U(...) \, +#define Z_IS_2073U_EQ_2073U(...) \, +#define Z_IS_2074_EQ_2074(...) \, +#define Z_IS_2074U_EQ_2074(...) \, +#define Z_IS_2074_EQ_2074U(...) \, +#define Z_IS_2074U_EQ_2074U(...) \, +#define Z_IS_2075_EQ_2075(...) \, +#define Z_IS_2075U_EQ_2075(...) \, +#define Z_IS_2075_EQ_2075U(...) \, +#define Z_IS_2075U_EQ_2075U(...) \, +#define Z_IS_2076_EQ_2076(...) \, +#define Z_IS_2076U_EQ_2076(...) \, +#define Z_IS_2076_EQ_2076U(...) \, +#define Z_IS_2076U_EQ_2076U(...) \, +#define Z_IS_2077_EQ_2077(...) \, +#define Z_IS_2077U_EQ_2077(...) \, +#define Z_IS_2077_EQ_2077U(...) \, +#define Z_IS_2077U_EQ_2077U(...) \, +#define Z_IS_2078_EQ_2078(...) \, +#define Z_IS_2078U_EQ_2078(...) \, +#define Z_IS_2078_EQ_2078U(...) \, +#define Z_IS_2078U_EQ_2078U(...) \, +#define Z_IS_2079_EQ_2079(...) \, +#define Z_IS_2079U_EQ_2079(...) \, +#define Z_IS_2079_EQ_2079U(...) \, +#define Z_IS_2079U_EQ_2079U(...) \, +#define Z_IS_2080_EQ_2080(...) \, +#define Z_IS_2080U_EQ_2080(...) \, +#define Z_IS_2080_EQ_2080U(...) \, +#define Z_IS_2080U_EQ_2080U(...) \, +#define Z_IS_2081_EQ_2081(...) \, +#define Z_IS_2081U_EQ_2081(...) \, +#define Z_IS_2081_EQ_2081U(...) \, +#define Z_IS_2081U_EQ_2081U(...) \, +#define Z_IS_2082_EQ_2082(...) \, +#define Z_IS_2082U_EQ_2082(...) \, +#define Z_IS_2082_EQ_2082U(...) \, +#define Z_IS_2082U_EQ_2082U(...) \, +#define Z_IS_2083_EQ_2083(...) \, +#define Z_IS_2083U_EQ_2083(...) \, +#define Z_IS_2083_EQ_2083U(...) \, +#define Z_IS_2083U_EQ_2083U(...) \, +#define Z_IS_2084_EQ_2084(...) \, +#define Z_IS_2084U_EQ_2084(...) \, +#define Z_IS_2084_EQ_2084U(...) \, +#define Z_IS_2084U_EQ_2084U(...) \, +#define Z_IS_2085_EQ_2085(...) \, +#define Z_IS_2085U_EQ_2085(...) \, +#define Z_IS_2085_EQ_2085U(...) \, +#define Z_IS_2085U_EQ_2085U(...) \, +#define Z_IS_2086_EQ_2086(...) \, +#define Z_IS_2086U_EQ_2086(...) \, +#define Z_IS_2086_EQ_2086U(...) \, +#define Z_IS_2086U_EQ_2086U(...) \, +#define Z_IS_2087_EQ_2087(...) \, +#define Z_IS_2087U_EQ_2087(...) \, +#define Z_IS_2087_EQ_2087U(...) \, +#define Z_IS_2087U_EQ_2087U(...) \, +#define Z_IS_2088_EQ_2088(...) \, +#define Z_IS_2088U_EQ_2088(...) \, +#define Z_IS_2088_EQ_2088U(...) \, +#define Z_IS_2088U_EQ_2088U(...) \, +#define Z_IS_2089_EQ_2089(...) \, +#define Z_IS_2089U_EQ_2089(...) \, +#define Z_IS_2089_EQ_2089U(...) \, +#define Z_IS_2089U_EQ_2089U(...) \, +#define Z_IS_2090_EQ_2090(...) \, +#define Z_IS_2090U_EQ_2090(...) \, +#define Z_IS_2090_EQ_2090U(...) \, +#define Z_IS_2090U_EQ_2090U(...) \, +#define Z_IS_2091_EQ_2091(...) \, +#define Z_IS_2091U_EQ_2091(...) \, +#define Z_IS_2091_EQ_2091U(...) \, +#define Z_IS_2091U_EQ_2091U(...) \, +#define Z_IS_2092_EQ_2092(...) \, +#define Z_IS_2092U_EQ_2092(...) \, +#define Z_IS_2092_EQ_2092U(...) \, +#define Z_IS_2092U_EQ_2092U(...) \, +#define Z_IS_2093_EQ_2093(...) \, +#define Z_IS_2093U_EQ_2093(...) \, +#define Z_IS_2093_EQ_2093U(...) \, +#define Z_IS_2093U_EQ_2093U(...) \, +#define Z_IS_2094_EQ_2094(...) \, +#define Z_IS_2094U_EQ_2094(...) \, +#define Z_IS_2094_EQ_2094U(...) \, +#define Z_IS_2094U_EQ_2094U(...) \, +#define Z_IS_2095_EQ_2095(...) \, +#define Z_IS_2095U_EQ_2095(...) \, +#define Z_IS_2095_EQ_2095U(...) \, +#define Z_IS_2095U_EQ_2095U(...) \, +#define Z_IS_2096_EQ_2096(...) \, +#define Z_IS_2096U_EQ_2096(...) \, +#define Z_IS_2096_EQ_2096U(...) \, +#define Z_IS_2096U_EQ_2096U(...) \, +#define Z_IS_2097_EQ_2097(...) \, +#define Z_IS_2097U_EQ_2097(...) \, +#define Z_IS_2097_EQ_2097U(...) \, +#define Z_IS_2097U_EQ_2097U(...) \, +#define Z_IS_2098_EQ_2098(...) \, +#define Z_IS_2098U_EQ_2098(...) \, +#define Z_IS_2098_EQ_2098U(...) \, +#define Z_IS_2098U_EQ_2098U(...) \, +#define Z_IS_2099_EQ_2099(...) \, +#define Z_IS_2099U_EQ_2099(...) \, +#define Z_IS_2099_EQ_2099U(...) \, +#define Z_IS_2099U_EQ_2099U(...) \, +#define Z_IS_2100_EQ_2100(...) \, +#define Z_IS_2100U_EQ_2100(...) \, +#define Z_IS_2100_EQ_2100U(...) \, +#define Z_IS_2100U_EQ_2100U(...) \, +#define Z_IS_2101_EQ_2101(...) \, +#define Z_IS_2101U_EQ_2101(...) \, +#define Z_IS_2101_EQ_2101U(...) \, +#define Z_IS_2101U_EQ_2101U(...) \, +#define Z_IS_2102_EQ_2102(...) \, +#define Z_IS_2102U_EQ_2102(...) \, +#define Z_IS_2102_EQ_2102U(...) \, +#define Z_IS_2102U_EQ_2102U(...) \, +#define Z_IS_2103_EQ_2103(...) \, +#define Z_IS_2103U_EQ_2103(...) \, +#define Z_IS_2103_EQ_2103U(...) \, +#define Z_IS_2103U_EQ_2103U(...) \, +#define Z_IS_2104_EQ_2104(...) \, +#define Z_IS_2104U_EQ_2104(...) \, +#define Z_IS_2104_EQ_2104U(...) \, +#define Z_IS_2104U_EQ_2104U(...) \, +#define Z_IS_2105_EQ_2105(...) \, +#define Z_IS_2105U_EQ_2105(...) \, +#define Z_IS_2105_EQ_2105U(...) \, +#define Z_IS_2105U_EQ_2105U(...) \, +#define Z_IS_2106_EQ_2106(...) \, +#define Z_IS_2106U_EQ_2106(...) \, +#define Z_IS_2106_EQ_2106U(...) \, +#define Z_IS_2106U_EQ_2106U(...) \, +#define Z_IS_2107_EQ_2107(...) \, +#define Z_IS_2107U_EQ_2107(...) \, +#define Z_IS_2107_EQ_2107U(...) \, +#define Z_IS_2107U_EQ_2107U(...) \, +#define Z_IS_2108_EQ_2108(...) \, +#define Z_IS_2108U_EQ_2108(...) \, +#define Z_IS_2108_EQ_2108U(...) \, +#define Z_IS_2108U_EQ_2108U(...) \, +#define Z_IS_2109_EQ_2109(...) \, +#define Z_IS_2109U_EQ_2109(...) \, +#define Z_IS_2109_EQ_2109U(...) \, +#define Z_IS_2109U_EQ_2109U(...) \, +#define Z_IS_2110_EQ_2110(...) \, +#define Z_IS_2110U_EQ_2110(...) \, +#define Z_IS_2110_EQ_2110U(...) \, +#define Z_IS_2110U_EQ_2110U(...) \, +#define Z_IS_2111_EQ_2111(...) \, +#define Z_IS_2111U_EQ_2111(...) \, +#define Z_IS_2111_EQ_2111U(...) \, +#define Z_IS_2111U_EQ_2111U(...) \, +#define Z_IS_2112_EQ_2112(...) \, +#define Z_IS_2112U_EQ_2112(...) \, +#define Z_IS_2112_EQ_2112U(...) \, +#define Z_IS_2112U_EQ_2112U(...) \, +#define Z_IS_2113_EQ_2113(...) \, +#define Z_IS_2113U_EQ_2113(...) \, +#define Z_IS_2113_EQ_2113U(...) \, +#define Z_IS_2113U_EQ_2113U(...) \, +#define Z_IS_2114_EQ_2114(...) \, +#define Z_IS_2114U_EQ_2114(...) \, +#define Z_IS_2114_EQ_2114U(...) \, +#define Z_IS_2114U_EQ_2114U(...) \, +#define Z_IS_2115_EQ_2115(...) \, +#define Z_IS_2115U_EQ_2115(...) \, +#define Z_IS_2115_EQ_2115U(...) \, +#define Z_IS_2115U_EQ_2115U(...) \, +#define Z_IS_2116_EQ_2116(...) \, +#define Z_IS_2116U_EQ_2116(...) \, +#define Z_IS_2116_EQ_2116U(...) \, +#define Z_IS_2116U_EQ_2116U(...) \, +#define Z_IS_2117_EQ_2117(...) \, +#define Z_IS_2117U_EQ_2117(...) \, +#define Z_IS_2117_EQ_2117U(...) \, +#define Z_IS_2117U_EQ_2117U(...) \, +#define Z_IS_2118_EQ_2118(...) \, +#define Z_IS_2118U_EQ_2118(...) \, +#define Z_IS_2118_EQ_2118U(...) \, +#define Z_IS_2118U_EQ_2118U(...) \, +#define Z_IS_2119_EQ_2119(...) \, +#define Z_IS_2119U_EQ_2119(...) \, +#define Z_IS_2119_EQ_2119U(...) \, +#define Z_IS_2119U_EQ_2119U(...) \, +#define Z_IS_2120_EQ_2120(...) \, +#define Z_IS_2120U_EQ_2120(...) \, +#define Z_IS_2120_EQ_2120U(...) \, +#define Z_IS_2120U_EQ_2120U(...) \, +#define Z_IS_2121_EQ_2121(...) \, +#define Z_IS_2121U_EQ_2121(...) \, +#define Z_IS_2121_EQ_2121U(...) \, +#define Z_IS_2121U_EQ_2121U(...) \, +#define Z_IS_2122_EQ_2122(...) \, +#define Z_IS_2122U_EQ_2122(...) \, +#define Z_IS_2122_EQ_2122U(...) \, +#define Z_IS_2122U_EQ_2122U(...) \, +#define Z_IS_2123_EQ_2123(...) \, +#define Z_IS_2123U_EQ_2123(...) \, +#define Z_IS_2123_EQ_2123U(...) \, +#define Z_IS_2123U_EQ_2123U(...) \, +#define Z_IS_2124_EQ_2124(...) \, +#define Z_IS_2124U_EQ_2124(...) \, +#define Z_IS_2124_EQ_2124U(...) \, +#define Z_IS_2124U_EQ_2124U(...) \, +#define Z_IS_2125_EQ_2125(...) \, +#define Z_IS_2125U_EQ_2125(...) \, +#define Z_IS_2125_EQ_2125U(...) \, +#define Z_IS_2125U_EQ_2125U(...) \, +#define Z_IS_2126_EQ_2126(...) \, +#define Z_IS_2126U_EQ_2126(...) \, +#define Z_IS_2126_EQ_2126U(...) \, +#define Z_IS_2126U_EQ_2126U(...) \, +#define Z_IS_2127_EQ_2127(...) \, +#define Z_IS_2127U_EQ_2127(...) \, +#define Z_IS_2127_EQ_2127U(...) \, +#define Z_IS_2127U_EQ_2127U(...) \, +#define Z_IS_2128_EQ_2128(...) \, +#define Z_IS_2128U_EQ_2128(...) \, +#define Z_IS_2128_EQ_2128U(...) \, +#define Z_IS_2128U_EQ_2128U(...) \, +#define Z_IS_2129_EQ_2129(...) \, +#define Z_IS_2129U_EQ_2129(...) \, +#define Z_IS_2129_EQ_2129U(...) \, +#define Z_IS_2129U_EQ_2129U(...) \, +#define Z_IS_2130_EQ_2130(...) \, +#define Z_IS_2130U_EQ_2130(...) \, +#define Z_IS_2130_EQ_2130U(...) \, +#define Z_IS_2130U_EQ_2130U(...) \, +#define Z_IS_2131_EQ_2131(...) \, +#define Z_IS_2131U_EQ_2131(...) \, +#define Z_IS_2131_EQ_2131U(...) \, +#define Z_IS_2131U_EQ_2131U(...) \, +#define Z_IS_2132_EQ_2132(...) \, +#define Z_IS_2132U_EQ_2132(...) \, +#define Z_IS_2132_EQ_2132U(...) \, +#define Z_IS_2132U_EQ_2132U(...) \, +#define Z_IS_2133_EQ_2133(...) \, +#define Z_IS_2133U_EQ_2133(...) \, +#define Z_IS_2133_EQ_2133U(...) \, +#define Z_IS_2133U_EQ_2133U(...) \, +#define Z_IS_2134_EQ_2134(...) \, +#define Z_IS_2134U_EQ_2134(...) \, +#define Z_IS_2134_EQ_2134U(...) \, +#define Z_IS_2134U_EQ_2134U(...) \, +#define Z_IS_2135_EQ_2135(...) \, +#define Z_IS_2135U_EQ_2135(...) \, +#define Z_IS_2135_EQ_2135U(...) \, +#define Z_IS_2135U_EQ_2135U(...) \, +#define Z_IS_2136_EQ_2136(...) \, +#define Z_IS_2136U_EQ_2136(...) \, +#define Z_IS_2136_EQ_2136U(...) \, +#define Z_IS_2136U_EQ_2136U(...) \, +#define Z_IS_2137_EQ_2137(...) \, +#define Z_IS_2137U_EQ_2137(...) \, +#define Z_IS_2137_EQ_2137U(...) \, +#define Z_IS_2137U_EQ_2137U(...) \, +#define Z_IS_2138_EQ_2138(...) \, +#define Z_IS_2138U_EQ_2138(...) \, +#define Z_IS_2138_EQ_2138U(...) \, +#define Z_IS_2138U_EQ_2138U(...) \, +#define Z_IS_2139_EQ_2139(...) \, +#define Z_IS_2139U_EQ_2139(...) \, +#define Z_IS_2139_EQ_2139U(...) \, +#define Z_IS_2139U_EQ_2139U(...) \, +#define Z_IS_2140_EQ_2140(...) \, +#define Z_IS_2140U_EQ_2140(...) \, +#define Z_IS_2140_EQ_2140U(...) \, +#define Z_IS_2140U_EQ_2140U(...) \, +#define Z_IS_2141_EQ_2141(...) \, +#define Z_IS_2141U_EQ_2141(...) \, +#define Z_IS_2141_EQ_2141U(...) \, +#define Z_IS_2141U_EQ_2141U(...) \, +#define Z_IS_2142_EQ_2142(...) \, +#define Z_IS_2142U_EQ_2142(...) \, +#define Z_IS_2142_EQ_2142U(...) \, +#define Z_IS_2142U_EQ_2142U(...) \, +#define Z_IS_2143_EQ_2143(...) \, +#define Z_IS_2143U_EQ_2143(...) \, +#define Z_IS_2143_EQ_2143U(...) \, +#define Z_IS_2143U_EQ_2143U(...) \, +#define Z_IS_2144_EQ_2144(...) \, +#define Z_IS_2144U_EQ_2144(...) \, +#define Z_IS_2144_EQ_2144U(...) \, +#define Z_IS_2144U_EQ_2144U(...) \, +#define Z_IS_2145_EQ_2145(...) \, +#define Z_IS_2145U_EQ_2145(...) \, +#define Z_IS_2145_EQ_2145U(...) \, +#define Z_IS_2145U_EQ_2145U(...) \, +#define Z_IS_2146_EQ_2146(...) \, +#define Z_IS_2146U_EQ_2146(...) \, +#define Z_IS_2146_EQ_2146U(...) \, +#define Z_IS_2146U_EQ_2146U(...) \, +#define Z_IS_2147_EQ_2147(...) \, +#define Z_IS_2147U_EQ_2147(...) \, +#define Z_IS_2147_EQ_2147U(...) \, +#define Z_IS_2147U_EQ_2147U(...) \, +#define Z_IS_2148_EQ_2148(...) \, +#define Z_IS_2148U_EQ_2148(...) \, +#define Z_IS_2148_EQ_2148U(...) \, +#define Z_IS_2148U_EQ_2148U(...) \, +#define Z_IS_2149_EQ_2149(...) \, +#define Z_IS_2149U_EQ_2149(...) \, +#define Z_IS_2149_EQ_2149U(...) \, +#define Z_IS_2149U_EQ_2149U(...) \, +#define Z_IS_2150_EQ_2150(...) \, +#define Z_IS_2150U_EQ_2150(...) \, +#define Z_IS_2150_EQ_2150U(...) \, +#define Z_IS_2150U_EQ_2150U(...) \, +#define Z_IS_2151_EQ_2151(...) \, +#define Z_IS_2151U_EQ_2151(...) \, +#define Z_IS_2151_EQ_2151U(...) \, +#define Z_IS_2151U_EQ_2151U(...) \, +#define Z_IS_2152_EQ_2152(...) \, +#define Z_IS_2152U_EQ_2152(...) \, +#define Z_IS_2152_EQ_2152U(...) \, +#define Z_IS_2152U_EQ_2152U(...) \, +#define Z_IS_2153_EQ_2153(...) \, +#define Z_IS_2153U_EQ_2153(...) \, +#define Z_IS_2153_EQ_2153U(...) \, +#define Z_IS_2153U_EQ_2153U(...) \, +#define Z_IS_2154_EQ_2154(...) \, +#define Z_IS_2154U_EQ_2154(...) \, +#define Z_IS_2154_EQ_2154U(...) \, +#define Z_IS_2154U_EQ_2154U(...) \, +#define Z_IS_2155_EQ_2155(...) \, +#define Z_IS_2155U_EQ_2155(...) \, +#define Z_IS_2155_EQ_2155U(...) \, +#define Z_IS_2155U_EQ_2155U(...) \, +#define Z_IS_2156_EQ_2156(...) \, +#define Z_IS_2156U_EQ_2156(...) \, +#define Z_IS_2156_EQ_2156U(...) \, +#define Z_IS_2156U_EQ_2156U(...) \, +#define Z_IS_2157_EQ_2157(...) \, +#define Z_IS_2157U_EQ_2157(...) \, +#define Z_IS_2157_EQ_2157U(...) \, +#define Z_IS_2157U_EQ_2157U(...) \, +#define Z_IS_2158_EQ_2158(...) \, +#define Z_IS_2158U_EQ_2158(...) \, +#define Z_IS_2158_EQ_2158U(...) \, +#define Z_IS_2158U_EQ_2158U(...) \, +#define Z_IS_2159_EQ_2159(...) \, +#define Z_IS_2159U_EQ_2159(...) \, +#define Z_IS_2159_EQ_2159U(...) \, +#define Z_IS_2159U_EQ_2159U(...) \, +#define Z_IS_2160_EQ_2160(...) \, +#define Z_IS_2160U_EQ_2160(...) \, +#define Z_IS_2160_EQ_2160U(...) \, +#define Z_IS_2160U_EQ_2160U(...) \, +#define Z_IS_2161_EQ_2161(...) \, +#define Z_IS_2161U_EQ_2161(...) \, +#define Z_IS_2161_EQ_2161U(...) \, +#define Z_IS_2161U_EQ_2161U(...) \, +#define Z_IS_2162_EQ_2162(...) \, +#define Z_IS_2162U_EQ_2162(...) \, +#define Z_IS_2162_EQ_2162U(...) \, +#define Z_IS_2162U_EQ_2162U(...) \, +#define Z_IS_2163_EQ_2163(...) \, +#define Z_IS_2163U_EQ_2163(...) \, +#define Z_IS_2163_EQ_2163U(...) \, +#define Z_IS_2163U_EQ_2163U(...) \, +#define Z_IS_2164_EQ_2164(...) \, +#define Z_IS_2164U_EQ_2164(...) \, +#define Z_IS_2164_EQ_2164U(...) \, +#define Z_IS_2164U_EQ_2164U(...) \, +#define Z_IS_2165_EQ_2165(...) \, +#define Z_IS_2165U_EQ_2165(...) \, +#define Z_IS_2165_EQ_2165U(...) \, +#define Z_IS_2165U_EQ_2165U(...) \, +#define Z_IS_2166_EQ_2166(...) \, +#define Z_IS_2166U_EQ_2166(...) \, +#define Z_IS_2166_EQ_2166U(...) \, +#define Z_IS_2166U_EQ_2166U(...) \, +#define Z_IS_2167_EQ_2167(...) \, +#define Z_IS_2167U_EQ_2167(...) \, +#define Z_IS_2167_EQ_2167U(...) \, +#define Z_IS_2167U_EQ_2167U(...) \, +#define Z_IS_2168_EQ_2168(...) \, +#define Z_IS_2168U_EQ_2168(...) \, +#define Z_IS_2168_EQ_2168U(...) \, +#define Z_IS_2168U_EQ_2168U(...) \, +#define Z_IS_2169_EQ_2169(...) \, +#define Z_IS_2169U_EQ_2169(...) \, +#define Z_IS_2169_EQ_2169U(...) \, +#define Z_IS_2169U_EQ_2169U(...) \, +#define Z_IS_2170_EQ_2170(...) \, +#define Z_IS_2170U_EQ_2170(...) \, +#define Z_IS_2170_EQ_2170U(...) \, +#define Z_IS_2170U_EQ_2170U(...) \, +#define Z_IS_2171_EQ_2171(...) \, +#define Z_IS_2171U_EQ_2171(...) \, +#define Z_IS_2171_EQ_2171U(...) \, +#define Z_IS_2171U_EQ_2171U(...) \, +#define Z_IS_2172_EQ_2172(...) \, +#define Z_IS_2172U_EQ_2172(...) \, +#define Z_IS_2172_EQ_2172U(...) \, +#define Z_IS_2172U_EQ_2172U(...) \, +#define Z_IS_2173_EQ_2173(...) \, +#define Z_IS_2173U_EQ_2173(...) \, +#define Z_IS_2173_EQ_2173U(...) \, +#define Z_IS_2173U_EQ_2173U(...) \, +#define Z_IS_2174_EQ_2174(...) \, +#define Z_IS_2174U_EQ_2174(...) \, +#define Z_IS_2174_EQ_2174U(...) \, +#define Z_IS_2174U_EQ_2174U(...) \, +#define Z_IS_2175_EQ_2175(...) \, +#define Z_IS_2175U_EQ_2175(...) \, +#define Z_IS_2175_EQ_2175U(...) \, +#define Z_IS_2175U_EQ_2175U(...) \, +#define Z_IS_2176_EQ_2176(...) \, +#define Z_IS_2176U_EQ_2176(...) \, +#define Z_IS_2176_EQ_2176U(...) \, +#define Z_IS_2176U_EQ_2176U(...) \, +#define Z_IS_2177_EQ_2177(...) \, +#define Z_IS_2177U_EQ_2177(...) \, +#define Z_IS_2177_EQ_2177U(...) \, +#define Z_IS_2177U_EQ_2177U(...) \, +#define Z_IS_2178_EQ_2178(...) \, +#define Z_IS_2178U_EQ_2178(...) \, +#define Z_IS_2178_EQ_2178U(...) \, +#define Z_IS_2178U_EQ_2178U(...) \, +#define Z_IS_2179_EQ_2179(...) \, +#define Z_IS_2179U_EQ_2179(...) \, +#define Z_IS_2179_EQ_2179U(...) \, +#define Z_IS_2179U_EQ_2179U(...) \, +#define Z_IS_2180_EQ_2180(...) \, +#define Z_IS_2180U_EQ_2180(...) \, +#define Z_IS_2180_EQ_2180U(...) \, +#define Z_IS_2180U_EQ_2180U(...) \, +#define Z_IS_2181_EQ_2181(...) \, +#define Z_IS_2181U_EQ_2181(...) \, +#define Z_IS_2181_EQ_2181U(...) \, +#define Z_IS_2181U_EQ_2181U(...) \, +#define Z_IS_2182_EQ_2182(...) \, +#define Z_IS_2182U_EQ_2182(...) \, +#define Z_IS_2182_EQ_2182U(...) \, +#define Z_IS_2182U_EQ_2182U(...) \, +#define Z_IS_2183_EQ_2183(...) \, +#define Z_IS_2183U_EQ_2183(...) \, +#define Z_IS_2183_EQ_2183U(...) \, +#define Z_IS_2183U_EQ_2183U(...) \, +#define Z_IS_2184_EQ_2184(...) \, +#define Z_IS_2184U_EQ_2184(...) \, +#define Z_IS_2184_EQ_2184U(...) \, +#define Z_IS_2184U_EQ_2184U(...) \, +#define Z_IS_2185_EQ_2185(...) \, +#define Z_IS_2185U_EQ_2185(...) \, +#define Z_IS_2185_EQ_2185U(...) \, +#define Z_IS_2185U_EQ_2185U(...) \, +#define Z_IS_2186_EQ_2186(...) \, +#define Z_IS_2186U_EQ_2186(...) \, +#define Z_IS_2186_EQ_2186U(...) \, +#define Z_IS_2186U_EQ_2186U(...) \, +#define Z_IS_2187_EQ_2187(...) \, +#define Z_IS_2187U_EQ_2187(...) \, +#define Z_IS_2187_EQ_2187U(...) \, +#define Z_IS_2187U_EQ_2187U(...) \, +#define Z_IS_2188_EQ_2188(...) \, +#define Z_IS_2188U_EQ_2188(...) \, +#define Z_IS_2188_EQ_2188U(...) \, +#define Z_IS_2188U_EQ_2188U(...) \, +#define Z_IS_2189_EQ_2189(...) \, +#define Z_IS_2189U_EQ_2189(...) \, +#define Z_IS_2189_EQ_2189U(...) \, +#define Z_IS_2189U_EQ_2189U(...) \, +#define Z_IS_2190_EQ_2190(...) \, +#define Z_IS_2190U_EQ_2190(...) \, +#define Z_IS_2190_EQ_2190U(...) \, +#define Z_IS_2190U_EQ_2190U(...) \, +#define Z_IS_2191_EQ_2191(...) \, +#define Z_IS_2191U_EQ_2191(...) \, +#define Z_IS_2191_EQ_2191U(...) \, +#define Z_IS_2191U_EQ_2191U(...) \, +#define Z_IS_2192_EQ_2192(...) \, +#define Z_IS_2192U_EQ_2192(...) \, +#define Z_IS_2192_EQ_2192U(...) \, +#define Z_IS_2192U_EQ_2192U(...) \, +#define Z_IS_2193_EQ_2193(...) \, +#define Z_IS_2193U_EQ_2193(...) \, +#define Z_IS_2193_EQ_2193U(...) \, +#define Z_IS_2193U_EQ_2193U(...) \, +#define Z_IS_2194_EQ_2194(...) \, +#define Z_IS_2194U_EQ_2194(...) \, +#define Z_IS_2194_EQ_2194U(...) \, +#define Z_IS_2194U_EQ_2194U(...) \, +#define Z_IS_2195_EQ_2195(...) \, +#define Z_IS_2195U_EQ_2195(...) \, +#define Z_IS_2195_EQ_2195U(...) \, +#define Z_IS_2195U_EQ_2195U(...) \, +#define Z_IS_2196_EQ_2196(...) \, +#define Z_IS_2196U_EQ_2196(...) \, +#define Z_IS_2196_EQ_2196U(...) \, +#define Z_IS_2196U_EQ_2196U(...) \, +#define Z_IS_2197_EQ_2197(...) \, +#define Z_IS_2197U_EQ_2197(...) \, +#define Z_IS_2197_EQ_2197U(...) \, +#define Z_IS_2197U_EQ_2197U(...) \, +#define Z_IS_2198_EQ_2198(...) \, +#define Z_IS_2198U_EQ_2198(...) \, +#define Z_IS_2198_EQ_2198U(...) \, +#define Z_IS_2198U_EQ_2198U(...) \, +#define Z_IS_2199_EQ_2199(...) \, +#define Z_IS_2199U_EQ_2199(...) \, +#define Z_IS_2199_EQ_2199U(...) \, +#define Z_IS_2199U_EQ_2199U(...) \, +#define Z_IS_2200_EQ_2200(...) \, +#define Z_IS_2200U_EQ_2200(...) \, +#define Z_IS_2200_EQ_2200U(...) \, +#define Z_IS_2200U_EQ_2200U(...) \, +#define Z_IS_2201_EQ_2201(...) \, +#define Z_IS_2201U_EQ_2201(...) \, +#define Z_IS_2201_EQ_2201U(...) \, +#define Z_IS_2201U_EQ_2201U(...) \, +#define Z_IS_2202_EQ_2202(...) \, +#define Z_IS_2202U_EQ_2202(...) \, +#define Z_IS_2202_EQ_2202U(...) \, +#define Z_IS_2202U_EQ_2202U(...) \, +#define Z_IS_2203_EQ_2203(...) \, +#define Z_IS_2203U_EQ_2203(...) \, +#define Z_IS_2203_EQ_2203U(...) \, +#define Z_IS_2203U_EQ_2203U(...) \, +#define Z_IS_2204_EQ_2204(...) \, +#define Z_IS_2204U_EQ_2204(...) \, +#define Z_IS_2204_EQ_2204U(...) \, +#define Z_IS_2204U_EQ_2204U(...) \, +#define Z_IS_2205_EQ_2205(...) \, +#define Z_IS_2205U_EQ_2205(...) \, +#define Z_IS_2205_EQ_2205U(...) \, +#define Z_IS_2205U_EQ_2205U(...) \, +#define Z_IS_2206_EQ_2206(...) \, +#define Z_IS_2206U_EQ_2206(...) \, +#define Z_IS_2206_EQ_2206U(...) \, +#define Z_IS_2206U_EQ_2206U(...) \, +#define Z_IS_2207_EQ_2207(...) \, +#define Z_IS_2207U_EQ_2207(...) \, +#define Z_IS_2207_EQ_2207U(...) \, +#define Z_IS_2207U_EQ_2207U(...) \, +#define Z_IS_2208_EQ_2208(...) \, +#define Z_IS_2208U_EQ_2208(...) \, +#define Z_IS_2208_EQ_2208U(...) \, +#define Z_IS_2208U_EQ_2208U(...) \, +#define Z_IS_2209_EQ_2209(...) \, +#define Z_IS_2209U_EQ_2209(...) \, +#define Z_IS_2209_EQ_2209U(...) \, +#define Z_IS_2209U_EQ_2209U(...) \, +#define Z_IS_2210_EQ_2210(...) \, +#define Z_IS_2210U_EQ_2210(...) \, +#define Z_IS_2210_EQ_2210U(...) \, +#define Z_IS_2210U_EQ_2210U(...) \, +#define Z_IS_2211_EQ_2211(...) \, +#define Z_IS_2211U_EQ_2211(...) \, +#define Z_IS_2211_EQ_2211U(...) \, +#define Z_IS_2211U_EQ_2211U(...) \, +#define Z_IS_2212_EQ_2212(...) \, +#define Z_IS_2212U_EQ_2212(...) \, +#define Z_IS_2212_EQ_2212U(...) \, +#define Z_IS_2212U_EQ_2212U(...) \, +#define Z_IS_2213_EQ_2213(...) \, +#define Z_IS_2213U_EQ_2213(...) \, +#define Z_IS_2213_EQ_2213U(...) \, +#define Z_IS_2213U_EQ_2213U(...) \, +#define Z_IS_2214_EQ_2214(...) \, +#define Z_IS_2214U_EQ_2214(...) \, +#define Z_IS_2214_EQ_2214U(...) \, +#define Z_IS_2214U_EQ_2214U(...) \, +#define Z_IS_2215_EQ_2215(...) \, +#define Z_IS_2215U_EQ_2215(...) \, +#define Z_IS_2215_EQ_2215U(...) \, +#define Z_IS_2215U_EQ_2215U(...) \, +#define Z_IS_2216_EQ_2216(...) \, +#define Z_IS_2216U_EQ_2216(...) \, +#define Z_IS_2216_EQ_2216U(...) \, +#define Z_IS_2216U_EQ_2216U(...) \, +#define Z_IS_2217_EQ_2217(...) \, +#define Z_IS_2217U_EQ_2217(...) \, +#define Z_IS_2217_EQ_2217U(...) \, +#define Z_IS_2217U_EQ_2217U(...) \, +#define Z_IS_2218_EQ_2218(...) \, +#define Z_IS_2218U_EQ_2218(...) \, +#define Z_IS_2218_EQ_2218U(...) \, +#define Z_IS_2218U_EQ_2218U(...) \, +#define Z_IS_2219_EQ_2219(...) \, +#define Z_IS_2219U_EQ_2219(...) \, +#define Z_IS_2219_EQ_2219U(...) \, +#define Z_IS_2219U_EQ_2219U(...) \, +#define Z_IS_2220_EQ_2220(...) \, +#define Z_IS_2220U_EQ_2220(...) \, +#define Z_IS_2220_EQ_2220U(...) \, +#define Z_IS_2220U_EQ_2220U(...) \, +#define Z_IS_2221_EQ_2221(...) \, +#define Z_IS_2221U_EQ_2221(...) \, +#define Z_IS_2221_EQ_2221U(...) \, +#define Z_IS_2221U_EQ_2221U(...) \, +#define Z_IS_2222_EQ_2222(...) \, +#define Z_IS_2222U_EQ_2222(...) \, +#define Z_IS_2222_EQ_2222U(...) \, +#define Z_IS_2222U_EQ_2222U(...) \, +#define Z_IS_2223_EQ_2223(...) \, +#define Z_IS_2223U_EQ_2223(...) \, +#define Z_IS_2223_EQ_2223U(...) \, +#define Z_IS_2223U_EQ_2223U(...) \, +#define Z_IS_2224_EQ_2224(...) \, +#define Z_IS_2224U_EQ_2224(...) \, +#define Z_IS_2224_EQ_2224U(...) \, +#define Z_IS_2224U_EQ_2224U(...) \, +#define Z_IS_2225_EQ_2225(...) \, +#define Z_IS_2225U_EQ_2225(...) \, +#define Z_IS_2225_EQ_2225U(...) \, +#define Z_IS_2225U_EQ_2225U(...) \, +#define Z_IS_2226_EQ_2226(...) \, +#define Z_IS_2226U_EQ_2226(...) \, +#define Z_IS_2226_EQ_2226U(...) \, +#define Z_IS_2226U_EQ_2226U(...) \, +#define Z_IS_2227_EQ_2227(...) \, +#define Z_IS_2227U_EQ_2227(...) \, +#define Z_IS_2227_EQ_2227U(...) \, +#define Z_IS_2227U_EQ_2227U(...) \, +#define Z_IS_2228_EQ_2228(...) \, +#define Z_IS_2228U_EQ_2228(...) \, +#define Z_IS_2228_EQ_2228U(...) \, +#define Z_IS_2228U_EQ_2228U(...) \, +#define Z_IS_2229_EQ_2229(...) \, +#define Z_IS_2229U_EQ_2229(...) \, +#define Z_IS_2229_EQ_2229U(...) \, +#define Z_IS_2229U_EQ_2229U(...) \, +#define Z_IS_2230_EQ_2230(...) \, +#define Z_IS_2230U_EQ_2230(...) \, +#define Z_IS_2230_EQ_2230U(...) \, +#define Z_IS_2230U_EQ_2230U(...) \, +#define Z_IS_2231_EQ_2231(...) \, +#define Z_IS_2231U_EQ_2231(...) \, +#define Z_IS_2231_EQ_2231U(...) \, +#define Z_IS_2231U_EQ_2231U(...) \, +#define Z_IS_2232_EQ_2232(...) \, +#define Z_IS_2232U_EQ_2232(...) \, +#define Z_IS_2232_EQ_2232U(...) \, +#define Z_IS_2232U_EQ_2232U(...) \, +#define Z_IS_2233_EQ_2233(...) \, +#define Z_IS_2233U_EQ_2233(...) \, +#define Z_IS_2233_EQ_2233U(...) \, +#define Z_IS_2233U_EQ_2233U(...) \, +#define Z_IS_2234_EQ_2234(...) \, +#define Z_IS_2234U_EQ_2234(...) \, +#define Z_IS_2234_EQ_2234U(...) \, +#define Z_IS_2234U_EQ_2234U(...) \, +#define Z_IS_2235_EQ_2235(...) \, +#define Z_IS_2235U_EQ_2235(...) \, +#define Z_IS_2235_EQ_2235U(...) \, +#define Z_IS_2235U_EQ_2235U(...) \, +#define Z_IS_2236_EQ_2236(...) \, +#define Z_IS_2236U_EQ_2236(...) \, +#define Z_IS_2236_EQ_2236U(...) \, +#define Z_IS_2236U_EQ_2236U(...) \, +#define Z_IS_2237_EQ_2237(...) \, +#define Z_IS_2237U_EQ_2237(...) \, +#define Z_IS_2237_EQ_2237U(...) \, +#define Z_IS_2237U_EQ_2237U(...) \, +#define Z_IS_2238_EQ_2238(...) \, +#define Z_IS_2238U_EQ_2238(...) \, +#define Z_IS_2238_EQ_2238U(...) \, +#define Z_IS_2238U_EQ_2238U(...) \, +#define Z_IS_2239_EQ_2239(...) \, +#define Z_IS_2239U_EQ_2239(...) \, +#define Z_IS_2239_EQ_2239U(...) \, +#define Z_IS_2239U_EQ_2239U(...) \, +#define Z_IS_2240_EQ_2240(...) \, +#define Z_IS_2240U_EQ_2240(...) \, +#define Z_IS_2240_EQ_2240U(...) \, +#define Z_IS_2240U_EQ_2240U(...) \, +#define Z_IS_2241_EQ_2241(...) \, +#define Z_IS_2241U_EQ_2241(...) \, +#define Z_IS_2241_EQ_2241U(...) \, +#define Z_IS_2241U_EQ_2241U(...) \, +#define Z_IS_2242_EQ_2242(...) \, +#define Z_IS_2242U_EQ_2242(...) \, +#define Z_IS_2242_EQ_2242U(...) \, +#define Z_IS_2242U_EQ_2242U(...) \, +#define Z_IS_2243_EQ_2243(...) \, +#define Z_IS_2243U_EQ_2243(...) \, +#define Z_IS_2243_EQ_2243U(...) \, +#define Z_IS_2243U_EQ_2243U(...) \, +#define Z_IS_2244_EQ_2244(...) \, +#define Z_IS_2244U_EQ_2244(...) \, +#define Z_IS_2244_EQ_2244U(...) \, +#define Z_IS_2244U_EQ_2244U(...) \, +#define Z_IS_2245_EQ_2245(...) \, +#define Z_IS_2245U_EQ_2245(...) \, +#define Z_IS_2245_EQ_2245U(...) \, +#define Z_IS_2245U_EQ_2245U(...) \, +#define Z_IS_2246_EQ_2246(...) \, +#define Z_IS_2246U_EQ_2246(...) \, +#define Z_IS_2246_EQ_2246U(...) \, +#define Z_IS_2246U_EQ_2246U(...) \, +#define Z_IS_2247_EQ_2247(...) \, +#define Z_IS_2247U_EQ_2247(...) \, +#define Z_IS_2247_EQ_2247U(...) \, +#define Z_IS_2247U_EQ_2247U(...) \, +#define Z_IS_2248_EQ_2248(...) \, +#define Z_IS_2248U_EQ_2248(...) \, +#define Z_IS_2248_EQ_2248U(...) \, +#define Z_IS_2248U_EQ_2248U(...) \, +#define Z_IS_2249_EQ_2249(...) \, +#define Z_IS_2249U_EQ_2249(...) \, +#define Z_IS_2249_EQ_2249U(...) \, +#define Z_IS_2249U_EQ_2249U(...) \, +#define Z_IS_2250_EQ_2250(...) \, +#define Z_IS_2250U_EQ_2250(...) \, +#define Z_IS_2250_EQ_2250U(...) \, +#define Z_IS_2250U_EQ_2250U(...) \, +#define Z_IS_2251_EQ_2251(...) \, +#define Z_IS_2251U_EQ_2251(...) \, +#define Z_IS_2251_EQ_2251U(...) \, +#define Z_IS_2251U_EQ_2251U(...) \, +#define Z_IS_2252_EQ_2252(...) \, +#define Z_IS_2252U_EQ_2252(...) \, +#define Z_IS_2252_EQ_2252U(...) \, +#define Z_IS_2252U_EQ_2252U(...) \, +#define Z_IS_2253_EQ_2253(...) \, +#define Z_IS_2253U_EQ_2253(...) \, +#define Z_IS_2253_EQ_2253U(...) \, +#define Z_IS_2253U_EQ_2253U(...) \, +#define Z_IS_2254_EQ_2254(...) \, +#define Z_IS_2254U_EQ_2254(...) \, +#define Z_IS_2254_EQ_2254U(...) \, +#define Z_IS_2254U_EQ_2254U(...) \, +#define Z_IS_2255_EQ_2255(...) \, +#define Z_IS_2255U_EQ_2255(...) \, +#define Z_IS_2255_EQ_2255U(...) \, +#define Z_IS_2255U_EQ_2255U(...) \, +#define Z_IS_2256_EQ_2256(...) \, +#define Z_IS_2256U_EQ_2256(...) \, +#define Z_IS_2256_EQ_2256U(...) \, +#define Z_IS_2256U_EQ_2256U(...) \, +#define Z_IS_2257_EQ_2257(...) \, +#define Z_IS_2257U_EQ_2257(...) \, +#define Z_IS_2257_EQ_2257U(...) \, +#define Z_IS_2257U_EQ_2257U(...) \, +#define Z_IS_2258_EQ_2258(...) \, +#define Z_IS_2258U_EQ_2258(...) \, +#define Z_IS_2258_EQ_2258U(...) \, +#define Z_IS_2258U_EQ_2258U(...) \, +#define Z_IS_2259_EQ_2259(...) \, +#define Z_IS_2259U_EQ_2259(...) \, +#define Z_IS_2259_EQ_2259U(...) \, +#define Z_IS_2259U_EQ_2259U(...) \, +#define Z_IS_2260_EQ_2260(...) \, +#define Z_IS_2260U_EQ_2260(...) \, +#define Z_IS_2260_EQ_2260U(...) \, +#define Z_IS_2260U_EQ_2260U(...) \, +#define Z_IS_2261_EQ_2261(...) \, +#define Z_IS_2261U_EQ_2261(...) \, +#define Z_IS_2261_EQ_2261U(...) \, +#define Z_IS_2261U_EQ_2261U(...) \, +#define Z_IS_2262_EQ_2262(...) \, +#define Z_IS_2262U_EQ_2262(...) \, +#define Z_IS_2262_EQ_2262U(...) \, +#define Z_IS_2262U_EQ_2262U(...) \, +#define Z_IS_2263_EQ_2263(...) \, +#define Z_IS_2263U_EQ_2263(...) \, +#define Z_IS_2263_EQ_2263U(...) \, +#define Z_IS_2263U_EQ_2263U(...) \, +#define Z_IS_2264_EQ_2264(...) \, +#define Z_IS_2264U_EQ_2264(...) \, +#define Z_IS_2264_EQ_2264U(...) \, +#define Z_IS_2264U_EQ_2264U(...) \, +#define Z_IS_2265_EQ_2265(...) \, +#define Z_IS_2265U_EQ_2265(...) \, +#define Z_IS_2265_EQ_2265U(...) \, +#define Z_IS_2265U_EQ_2265U(...) \, +#define Z_IS_2266_EQ_2266(...) \, +#define Z_IS_2266U_EQ_2266(...) \, +#define Z_IS_2266_EQ_2266U(...) \, +#define Z_IS_2266U_EQ_2266U(...) \, +#define Z_IS_2267_EQ_2267(...) \, +#define Z_IS_2267U_EQ_2267(...) \, +#define Z_IS_2267_EQ_2267U(...) \, +#define Z_IS_2267U_EQ_2267U(...) \, +#define Z_IS_2268_EQ_2268(...) \, +#define Z_IS_2268U_EQ_2268(...) \, +#define Z_IS_2268_EQ_2268U(...) \, +#define Z_IS_2268U_EQ_2268U(...) \, +#define Z_IS_2269_EQ_2269(...) \, +#define Z_IS_2269U_EQ_2269(...) \, +#define Z_IS_2269_EQ_2269U(...) \, +#define Z_IS_2269U_EQ_2269U(...) \, +#define Z_IS_2270_EQ_2270(...) \, +#define Z_IS_2270U_EQ_2270(...) \, +#define Z_IS_2270_EQ_2270U(...) \, +#define Z_IS_2270U_EQ_2270U(...) \, +#define Z_IS_2271_EQ_2271(...) \, +#define Z_IS_2271U_EQ_2271(...) \, +#define Z_IS_2271_EQ_2271U(...) \, +#define Z_IS_2271U_EQ_2271U(...) \, +#define Z_IS_2272_EQ_2272(...) \, +#define Z_IS_2272U_EQ_2272(...) \, +#define Z_IS_2272_EQ_2272U(...) \, +#define Z_IS_2272U_EQ_2272U(...) \, +#define Z_IS_2273_EQ_2273(...) \, +#define Z_IS_2273U_EQ_2273(...) \, +#define Z_IS_2273_EQ_2273U(...) \, +#define Z_IS_2273U_EQ_2273U(...) \, +#define Z_IS_2274_EQ_2274(...) \, +#define Z_IS_2274U_EQ_2274(...) \, +#define Z_IS_2274_EQ_2274U(...) \, +#define Z_IS_2274U_EQ_2274U(...) \, +#define Z_IS_2275_EQ_2275(...) \, +#define Z_IS_2275U_EQ_2275(...) \, +#define Z_IS_2275_EQ_2275U(...) \, +#define Z_IS_2275U_EQ_2275U(...) \, +#define Z_IS_2276_EQ_2276(...) \, +#define Z_IS_2276U_EQ_2276(...) \, +#define Z_IS_2276_EQ_2276U(...) \, +#define Z_IS_2276U_EQ_2276U(...) \, +#define Z_IS_2277_EQ_2277(...) \, +#define Z_IS_2277U_EQ_2277(...) \, +#define Z_IS_2277_EQ_2277U(...) \, +#define Z_IS_2277U_EQ_2277U(...) \, +#define Z_IS_2278_EQ_2278(...) \, +#define Z_IS_2278U_EQ_2278(...) \, +#define Z_IS_2278_EQ_2278U(...) \, +#define Z_IS_2278U_EQ_2278U(...) \, +#define Z_IS_2279_EQ_2279(...) \, +#define Z_IS_2279U_EQ_2279(...) \, +#define Z_IS_2279_EQ_2279U(...) \, +#define Z_IS_2279U_EQ_2279U(...) \, +#define Z_IS_2280_EQ_2280(...) \, +#define Z_IS_2280U_EQ_2280(...) \, +#define Z_IS_2280_EQ_2280U(...) \, +#define Z_IS_2280U_EQ_2280U(...) \, +#define Z_IS_2281_EQ_2281(...) \, +#define Z_IS_2281U_EQ_2281(...) \, +#define Z_IS_2281_EQ_2281U(...) \, +#define Z_IS_2281U_EQ_2281U(...) \, +#define Z_IS_2282_EQ_2282(...) \, +#define Z_IS_2282U_EQ_2282(...) \, +#define Z_IS_2282_EQ_2282U(...) \, +#define Z_IS_2282U_EQ_2282U(...) \, +#define Z_IS_2283_EQ_2283(...) \, +#define Z_IS_2283U_EQ_2283(...) \, +#define Z_IS_2283_EQ_2283U(...) \, +#define Z_IS_2283U_EQ_2283U(...) \, +#define Z_IS_2284_EQ_2284(...) \, +#define Z_IS_2284U_EQ_2284(...) \, +#define Z_IS_2284_EQ_2284U(...) \, +#define Z_IS_2284U_EQ_2284U(...) \, +#define Z_IS_2285_EQ_2285(...) \, +#define Z_IS_2285U_EQ_2285(...) \, +#define Z_IS_2285_EQ_2285U(...) \, +#define Z_IS_2285U_EQ_2285U(...) \, +#define Z_IS_2286_EQ_2286(...) \, +#define Z_IS_2286U_EQ_2286(...) \, +#define Z_IS_2286_EQ_2286U(...) \, +#define Z_IS_2286U_EQ_2286U(...) \, +#define Z_IS_2287_EQ_2287(...) \, +#define Z_IS_2287U_EQ_2287(...) \, +#define Z_IS_2287_EQ_2287U(...) \, +#define Z_IS_2287U_EQ_2287U(...) \, +#define Z_IS_2288_EQ_2288(...) \, +#define Z_IS_2288U_EQ_2288(...) \, +#define Z_IS_2288_EQ_2288U(...) \, +#define Z_IS_2288U_EQ_2288U(...) \, +#define Z_IS_2289_EQ_2289(...) \, +#define Z_IS_2289U_EQ_2289(...) \, +#define Z_IS_2289_EQ_2289U(...) \, +#define Z_IS_2289U_EQ_2289U(...) \, +#define Z_IS_2290_EQ_2290(...) \, +#define Z_IS_2290U_EQ_2290(...) \, +#define Z_IS_2290_EQ_2290U(...) \, +#define Z_IS_2290U_EQ_2290U(...) \, +#define Z_IS_2291_EQ_2291(...) \, +#define Z_IS_2291U_EQ_2291(...) \, +#define Z_IS_2291_EQ_2291U(...) \, +#define Z_IS_2291U_EQ_2291U(...) \, +#define Z_IS_2292_EQ_2292(...) \, +#define Z_IS_2292U_EQ_2292(...) \, +#define Z_IS_2292_EQ_2292U(...) \, +#define Z_IS_2292U_EQ_2292U(...) \, +#define Z_IS_2293_EQ_2293(...) \, +#define Z_IS_2293U_EQ_2293(...) \, +#define Z_IS_2293_EQ_2293U(...) \, +#define Z_IS_2293U_EQ_2293U(...) \, +#define Z_IS_2294_EQ_2294(...) \, +#define Z_IS_2294U_EQ_2294(...) \, +#define Z_IS_2294_EQ_2294U(...) \, +#define Z_IS_2294U_EQ_2294U(...) \, +#define Z_IS_2295_EQ_2295(...) \, +#define Z_IS_2295U_EQ_2295(...) \, +#define Z_IS_2295_EQ_2295U(...) \, +#define Z_IS_2295U_EQ_2295U(...) \, +#define Z_IS_2296_EQ_2296(...) \, +#define Z_IS_2296U_EQ_2296(...) \, +#define Z_IS_2296_EQ_2296U(...) \, +#define Z_IS_2296U_EQ_2296U(...) \, +#define Z_IS_2297_EQ_2297(...) \, +#define Z_IS_2297U_EQ_2297(...) \, +#define Z_IS_2297_EQ_2297U(...) \, +#define Z_IS_2297U_EQ_2297U(...) \, +#define Z_IS_2298_EQ_2298(...) \, +#define Z_IS_2298U_EQ_2298(...) \, +#define Z_IS_2298_EQ_2298U(...) \, +#define Z_IS_2298U_EQ_2298U(...) \, +#define Z_IS_2299_EQ_2299(...) \, +#define Z_IS_2299U_EQ_2299(...) \, +#define Z_IS_2299_EQ_2299U(...) \, +#define Z_IS_2299U_EQ_2299U(...) \, +#define Z_IS_2300_EQ_2300(...) \, +#define Z_IS_2300U_EQ_2300(...) \, +#define Z_IS_2300_EQ_2300U(...) \, +#define Z_IS_2300U_EQ_2300U(...) \, +#define Z_IS_2301_EQ_2301(...) \, +#define Z_IS_2301U_EQ_2301(...) \, +#define Z_IS_2301_EQ_2301U(...) \, +#define Z_IS_2301U_EQ_2301U(...) \, +#define Z_IS_2302_EQ_2302(...) \, +#define Z_IS_2302U_EQ_2302(...) \, +#define Z_IS_2302_EQ_2302U(...) \, +#define Z_IS_2302U_EQ_2302U(...) \, +#define Z_IS_2303_EQ_2303(...) \, +#define Z_IS_2303U_EQ_2303(...) \, +#define Z_IS_2303_EQ_2303U(...) \, +#define Z_IS_2303U_EQ_2303U(...) \, +#define Z_IS_2304_EQ_2304(...) \, +#define Z_IS_2304U_EQ_2304(...) \, +#define Z_IS_2304_EQ_2304U(...) \, +#define Z_IS_2304U_EQ_2304U(...) \, +#define Z_IS_2305_EQ_2305(...) \, +#define Z_IS_2305U_EQ_2305(...) \, +#define Z_IS_2305_EQ_2305U(...) \, +#define Z_IS_2305U_EQ_2305U(...) \, +#define Z_IS_2306_EQ_2306(...) \, +#define Z_IS_2306U_EQ_2306(...) \, +#define Z_IS_2306_EQ_2306U(...) \, +#define Z_IS_2306U_EQ_2306U(...) \, +#define Z_IS_2307_EQ_2307(...) \, +#define Z_IS_2307U_EQ_2307(...) \, +#define Z_IS_2307_EQ_2307U(...) \, +#define Z_IS_2307U_EQ_2307U(...) \, +#define Z_IS_2308_EQ_2308(...) \, +#define Z_IS_2308U_EQ_2308(...) \, +#define Z_IS_2308_EQ_2308U(...) \, +#define Z_IS_2308U_EQ_2308U(...) \, +#define Z_IS_2309_EQ_2309(...) \, +#define Z_IS_2309U_EQ_2309(...) \, +#define Z_IS_2309_EQ_2309U(...) \, +#define Z_IS_2309U_EQ_2309U(...) \, +#define Z_IS_2310_EQ_2310(...) \, +#define Z_IS_2310U_EQ_2310(...) \, +#define Z_IS_2310_EQ_2310U(...) \, +#define Z_IS_2310U_EQ_2310U(...) \, +#define Z_IS_2311_EQ_2311(...) \, +#define Z_IS_2311U_EQ_2311(...) \, +#define Z_IS_2311_EQ_2311U(...) \, +#define Z_IS_2311U_EQ_2311U(...) \, +#define Z_IS_2312_EQ_2312(...) \, +#define Z_IS_2312U_EQ_2312(...) \, +#define Z_IS_2312_EQ_2312U(...) \, +#define Z_IS_2312U_EQ_2312U(...) \, +#define Z_IS_2313_EQ_2313(...) \, +#define Z_IS_2313U_EQ_2313(...) \, +#define Z_IS_2313_EQ_2313U(...) \, +#define Z_IS_2313U_EQ_2313U(...) \, +#define Z_IS_2314_EQ_2314(...) \, +#define Z_IS_2314U_EQ_2314(...) \, +#define Z_IS_2314_EQ_2314U(...) \, +#define Z_IS_2314U_EQ_2314U(...) \, +#define Z_IS_2315_EQ_2315(...) \, +#define Z_IS_2315U_EQ_2315(...) \, +#define Z_IS_2315_EQ_2315U(...) \, +#define Z_IS_2315U_EQ_2315U(...) \, +#define Z_IS_2316_EQ_2316(...) \, +#define Z_IS_2316U_EQ_2316(...) \, +#define Z_IS_2316_EQ_2316U(...) \, +#define Z_IS_2316U_EQ_2316U(...) \, +#define Z_IS_2317_EQ_2317(...) \, +#define Z_IS_2317U_EQ_2317(...) \, +#define Z_IS_2317_EQ_2317U(...) \, +#define Z_IS_2317U_EQ_2317U(...) \, +#define Z_IS_2318_EQ_2318(...) \, +#define Z_IS_2318U_EQ_2318(...) \, +#define Z_IS_2318_EQ_2318U(...) \, +#define Z_IS_2318U_EQ_2318U(...) \, +#define Z_IS_2319_EQ_2319(...) \, +#define Z_IS_2319U_EQ_2319(...) \, +#define Z_IS_2319_EQ_2319U(...) \, +#define Z_IS_2319U_EQ_2319U(...) \, +#define Z_IS_2320_EQ_2320(...) \, +#define Z_IS_2320U_EQ_2320(...) \, +#define Z_IS_2320_EQ_2320U(...) \, +#define Z_IS_2320U_EQ_2320U(...) \, +#define Z_IS_2321_EQ_2321(...) \, +#define Z_IS_2321U_EQ_2321(...) \, +#define Z_IS_2321_EQ_2321U(...) \, +#define Z_IS_2321U_EQ_2321U(...) \, +#define Z_IS_2322_EQ_2322(...) \, +#define Z_IS_2322U_EQ_2322(...) \, +#define Z_IS_2322_EQ_2322U(...) \, +#define Z_IS_2322U_EQ_2322U(...) \, +#define Z_IS_2323_EQ_2323(...) \, +#define Z_IS_2323U_EQ_2323(...) \, +#define Z_IS_2323_EQ_2323U(...) \, +#define Z_IS_2323U_EQ_2323U(...) \, +#define Z_IS_2324_EQ_2324(...) \, +#define Z_IS_2324U_EQ_2324(...) \, +#define Z_IS_2324_EQ_2324U(...) \, +#define Z_IS_2324U_EQ_2324U(...) \, +#define Z_IS_2325_EQ_2325(...) \, +#define Z_IS_2325U_EQ_2325(...) \, +#define Z_IS_2325_EQ_2325U(...) \, +#define Z_IS_2325U_EQ_2325U(...) \, +#define Z_IS_2326_EQ_2326(...) \, +#define Z_IS_2326U_EQ_2326(...) \, +#define Z_IS_2326_EQ_2326U(...) \, +#define Z_IS_2326U_EQ_2326U(...) \, +#define Z_IS_2327_EQ_2327(...) \, +#define Z_IS_2327U_EQ_2327(...) \, +#define Z_IS_2327_EQ_2327U(...) \, +#define Z_IS_2327U_EQ_2327U(...) \, +#define Z_IS_2328_EQ_2328(...) \, +#define Z_IS_2328U_EQ_2328(...) \, +#define Z_IS_2328_EQ_2328U(...) \, +#define Z_IS_2328U_EQ_2328U(...) \, +#define Z_IS_2329_EQ_2329(...) \, +#define Z_IS_2329U_EQ_2329(...) \, +#define Z_IS_2329_EQ_2329U(...) \, +#define Z_IS_2329U_EQ_2329U(...) \, +#define Z_IS_2330_EQ_2330(...) \, +#define Z_IS_2330U_EQ_2330(...) \, +#define Z_IS_2330_EQ_2330U(...) \, +#define Z_IS_2330U_EQ_2330U(...) \, +#define Z_IS_2331_EQ_2331(...) \, +#define Z_IS_2331U_EQ_2331(...) \, +#define Z_IS_2331_EQ_2331U(...) \, +#define Z_IS_2331U_EQ_2331U(...) \, +#define Z_IS_2332_EQ_2332(...) \, +#define Z_IS_2332U_EQ_2332(...) \, +#define Z_IS_2332_EQ_2332U(...) \, +#define Z_IS_2332U_EQ_2332U(...) \, +#define Z_IS_2333_EQ_2333(...) \, +#define Z_IS_2333U_EQ_2333(...) \, +#define Z_IS_2333_EQ_2333U(...) \, +#define Z_IS_2333U_EQ_2333U(...) \, +#define Z_IS_2334_EQ_2334(...) \, +#define Z_IS_2334U_EQ_2334(...) \, +#define Z_IS_2334_EQ_2334U(...) \, +#define Z_IS_2334U_EQ_2334U(...) \, +#define Z_IS_2335_EQ_2335(...) \, +#define Z_IS_2335U_EQ_2335(...) \, +#define Z_IS_2335_EQ_2335U(...) \, +#define Z_IS_2335U_EQ_2335U(...) \, +#define Z_IS_2336_EQ_2336(...) \, +#define Z_IS_2336U_EQ_2336(...) \, +#define Z_IS_2336_EQ_2336U(...) \, +#define Z_IS_2336U_EQ_2336U(...) \, +#define Z_IS_2337_EQ_2337(...) \, +#define Z_IS_2337U_EQ_2337(...) \, +#define Z_IS_2337_EQ_2337U(...) \, +#define Z_IS_2337U_EQ_2337U(...) \, +#define Z_IS_2338_EQ_2338(...) \, +#define Z_IS_2338U_EQ_2338(...) \, +#define Z_IS_2338_EQ_2338U(...) \, +#define Z_IS_2338U_EQ_2338U(...) \, +#define Z_IS_2339_EQ_2339(...) \, +#define Z_IS_2339U_EQ_2339(...) \, +#define Z_IS_2339_EQ_2339U(...) \, +#define Z_IS_2339U_EQ_2339U(...) \, +#define Z_IS_2340_EQ_2340(...) \, +#define Z_IS_2340U_EQ_2340(...) \, +#define Z_IS_2340_EQ_2340U(...) \, +#define Z_IS_2340U_EQ_2340U(...) \, +#define Z_IS_2341_EQ_2341(...) \, +#define Z_IS_2341U_EQ_2341(...) \, +#define Z_IS_2341_EQ_2341U(...) \, +#define Z_IS_2341U_EQ_2341U(...) \, +#define Z_IS_2342_EQ_2342(...) \, +#define Z_IS_2342U_EQ_2342(...) \, +#define Z_IS_2342_EQ_2342U(...) \, +#define Z_IS_2342U_EQ_2342U(...) \, +#define Z_IS_2343_EQ_2343(...) \, +#define Z_IS_2343U_EQ_2343(...) \, +#define Z_IS_2343_EQ_2343U(...) \, +#define Z_IS_2343U_EQ_2343U(...) \, +#define Z_IS_2344_EQ_2344(...) \, +#define Z_IS_2344U_EQ_2344(...) \, +#define Z_IS_2344_EQ_2344U(...) \, +#define Z_IS_2344U_EQ_2344U(...) \, +#define Z_IS_2345_EQ_2345(...) \, +#define Z_IS_2345U_EQ_2345(...) \, +#define Z_IS_2345_EQ_2345U(...) \, +#define Z_IS_2345U_EQ_2345U(...) \, +#define Z_IS_2346_EQ_2346(...) \, +#define Z_IS_2346U_EQ_2346(...) \, +#define Z_IS_2346_EQ_2346U(...) \, +#define Z_IS_2346U_EQ_2346U(...) \, +#define Z_IS_2347_EQ_2347(...) \, +#define Z_IS_2347U_EQ_2347(...) \, +#define Z_IS_2347_EQ_2347U(...) \, +#define Z_IS_2347U_EQ_2347U(...) \, +#define Z_IS_2348_EQ_2348(...) \, +#define Z_IS_2348U_EQ_2348(...) \, +#define Z_IS_2348_EQ_2348U(...) \, +#define Z_IS_2348U_EQ_2348U(...) \, +#define Z_IS_2349_EQ_2349(...) \, +#define Z_IS_2349U_EQ_2349(...) \, +#define Z_IS_2349_EQ_2349U(...) \, +#define Z_IS_2349U_EQ_2349U(...) \, +#define Z_IS_2350_EQ_2350(...) \, +#define Z_IS_2350U_EQ_2350(...) \, +#define Z_IS_2350_EQ_2350U(...) \, +#define Z_IS_2350U_EQ_2350U(...) \, +#define Z_IS_2351_EQ_2351(...) \, +#define Z_IS_2351U_EQ_2351(...) \, +#define Z_IS_2351_EQ_2351U(...) \, +#define Z_IS_2351U_EQ_2351U(...) \, +#define Z_IS_2352_EQ_2352(...) \, +#define Z_IS_2352U_EQ_2352(...) \, +#define Z_IS_2352_EQ_2352U(...) \, +#define Z_IS_2352U_EQ_2352U(...) \, +#define Z_IS_2353_EQ_2353(...) \, +#define Z_IS_2353U_EQ_2353(...) \, +#define Z_IS_2353_EQ_2353U(...) \, +#define Z_IS_2353U_EQ_2353U(...) \, +#define Z_IS_2354_EQ_2354(...) \, +#define Z_IS_2354U_EQ_2354(...) \, +#define Z_IS_2354_EQ_2354U(...) \, +#define Z_IS_2354U_EQ_2354U(...) \, +#define Z_IS_2355_EQ_2355(...) \, +#define Z_IS_2355U_EQ_2355(...) \, +#define Z_IS_2355_EQ_2355U(...) \, +#define Z_IS_2355U_EQ_2355U(...) \, +#define Z_IS_2356_EQ_2356(...) \, +#define Z_IS_2356U_EQ_2356(...) \, +#define Z_IS_2356_EQ_2356U(...) \, +#define Z_IS_2356U_EQ_2356U(...) \, +#define Z_IS_2357_EQ_2357(...) \, +#define Z_IS_2357U_EQ_2357(...) \, +#define Z_IS_2357_EQ_2357U(...) \, +#define Z_IS_2357U_EQ_2357U(...) \, +#define Z_IS_2358_EQ_2358(...) \, +#define Z_IS_2358U_EQ_2358(...) \, +#define Z_IS_2358_EQ_2358U(...) \, +#define Z_IS_2358U_EQ_2358U(...) \, +#define Z_IS_2359_EQ_2359(...) \, +#define Z_IS_2359U_EQ_2359(...) \, +#define Z_IS_2359_EQ_2359U(...) \, +#define Z_IS_2359U_EQ_2359U(...) \, +#define Z_IS_2360_EQ_2360(...) \, +#define Z_IS_2360U_EQ_2360(...) \, +#define Z_IS_2360_EQ_2360U(...) \, +#define Z_IS_2360U_EQ_2360U(...) \, +#define Z_IS_2361_EQ_2361(...) \, +#define Z_IS_2361U_EQ_2361(...) \, +#define Z_IS_2361_EQ_2361U(...) \, +#define Z_IS_2361U_EQ_2361U(...) \, +#define Z_IS_2362_EQ_2362(...) \, +#define Z_IS_2362U_EQ_2362(...) \, +#define Z_IS_2362_EQ_2362U(...) \, +#define Z_IS_2362U_EQ_2362U(...) \, +#define Z_IS_2363_EQ_2363(...) \, +#define Z_IS_2363U_EQ_2363(...) \, +#define Z_IS_2363_EQ_2363U(...) \, +#define Z_IS_2363U_EQ_2363U(...) \, +#define Z_IS_2364_EQ_2364(...) \, +#define Z_IS_2364U_EQ_2364(...) \, +#define Z_IS_2364_EQ_2364U(...) \, +#define Z_IS_2364U_EQ_2364U(...) \, +#define Z_IS_2365_EQ_2365(...) \, +#define Z_IS_2365U_EQ_2365(...) \, +#define Z_IS_2365_EQ_2365U(...) \, +#define Z_IS_2365U_EQ_2365U(...) \, +#define Z_IS_2366_EQ_2366(...) \, +#define Z_IS_2366U_EQ_2366(...) \, +#define Z_IS_2366_EQ_2366U(...) \, +#define Z_IS_2366U_EQ_2366U(...) \, +#define Z_IS_2367_EQ_2367(...) \, +#define Z_IS_2367U_EQ_2367(...) \, +#define Z_IS_2367_EQ_2367U(...) \, +#define Z_IS_2367U_EQ_2367U(...) \, +#define Z_IS_2368_EQ_2368(...) \, +#define Z_IS_2368U_EQ_2368(...) \, +#define Z_IS_2368_EQ_2368U(...) \, +#define Z_IS_2368U_EQ_2368U(...) \, +#define Z_IS_2369_EQ_2369(...) \, +#define Z_IS_2369U_EQ_2369(...) \, +#define Z_IS_2369_EQ_2369U(...) \, +#define Z_IS_2369U_EQ_2369U(...) \, +#define Z_IS_2370_EQ_2370(...) \, +#define Z_IS_2370U_EQ_2370(...) \, +#define Z_IS_2370_EQ_2370U(...) \, +#define Z_IS_2370U_EQ_2370U(...) \, +#define Z_IS_2371_EQ_2371(...) \, +#define Z_IS_2371U_EQ_2371(...) \, +#define Z_IS_2371_EQ_2371U(...) \, +#define Z_IS_2371U_EQ_2371U(...) \, +#define Z_IS_2372_EQ_2372(...) \, +#define Z_IS_2372U_EQ_2372(...) \, +#define Z_IS_2372_EQ_2372U(...) \, +#define Z_IS_2372U_EQ_2372U(...) \, +#define Z_IS_2373_EQ_2373(...) \, +#define Z_IS_2373U_EQ_2373(...) \, +#define Z_IS_2373_EQ_2373U(...) \, +#define Z_IS_2373U_EQ_2373U(...) \, +#define Z_IS_2374_EQ_2374(...) \, +#define Z_IS_2374U_EQ_2374(...) \, +#define Z_IS_2374_EQ_2374U(...) \, +#define Z_IS_2374U_EQ_2374U(...) \, +#define Z_IS_2375_EQ_2375(...) \, +#define Z_IS_2375U_EQ_2375(...) \, +#define Z_IS_2375_EQ_2375U(...) \, +#define Z_IS_2375U_EQ_2375U(...) \, +#define Z_IS_2376_EQ_2376(...) \, +#define Z_IS_2376U_EQ_2376(...) \, +#define Z_IS_2376_EQ_2376U(...) \, +#define Z_IS_2376U_EQ_2376U(...) \, +#define Z_IS_2377_EQ_2377(...) \, +#define Z_IS_2377U_EQ_2377(...) \, +#define Z_IS_2377_EQ_2377U(...) \, +#define Z_IS_2377U_EQ_2377U(...) \, +#define Z_IS_2378_EQ_2378(...) \, +#define Z_IS_2378U_EQ_2378(...) \, +#define Z_IS_2378_EQ_2378U(...) \, +#define Z_IS_2378U_EQ_2378U(...) \, +#define Z_IS_2379_EQ_2379(...) \, +#define Z_IS_2379U_EQ_2379(...) \, +#define Z_IS_2379_EQ_2379U(...) \, +#define Z_IS_2379U_EQ_2379U(...) \, +#define Z_IS_2380_EQ_2380(...) \, +#define Z_IS_2380U_EQ_2380(...) \, +#define Z_IS_2380_EQ_2380U(...) \, +#define Z_IS_2380U_EQ_2380U(...) \, +#define Z_IS_2381_EQ_2381(...) \, +#define Z_IS_2381U_EQ_2381(...) \, +#define Z_IS_2381_EQ_2381U(...) \, +#define Z_IS_2381U_EQ_2381U(...) \, +#define Z_IS_2382_EQ_2382(...) \, +#define Z_IS_2382U_EQ_2382(...) \, +#define Z_IS_2382_EQ_2382U(...) \, +#define Z_IS_2382U_EQ_2382U(...) \, +#define Z_IS_2383_EQ_2383(...) \, +#define Z_IS_2383U_EQ_2383(...) \, +#define Z_IS_2383_EQ_2383U(...) \, +#define Z_IS_2383U_EQ_2383U(...) \, +#define Z_IS_2384_EQ_2384(...) \, +#define Z_IS_2384U_EQ_2384(...) \, +#define Z_IS_2384_EQ_2384U(...) \, +#define Z_IS_2384U_EQ_2384U(...) \, +#define Z_IS_2385_EQ_2385(...) \, +#define Z_IS_2385U_EQ_2385(...) \, +#define Z_IS_2385_EQ_2385U(...) \, +#define Z_IS_2385U_EQ_2385U(...) \, +#define Z_IS_2386_EQ_2386(...) \, +#define Z_IS_2386U_EQ_2386(...) \, +#define Z_IS_2386_EQ_2386U(...) \, +#define Z_IS_2386U_EQ_2386U(...) \, +#define Z_IS_2387_EQ_2387(...) \, +#define Z_IS_2387U_EQ_2387(...) \, +#define Z_IS_2387_EQ_2387U(...) \, +#define Z_IS_2387U_EQ_2387U(...) \, +#define Z_IS_2388_EQ_2388(...) \, +#define Z_IS_2388U_EQ_2388(...) \, +#define Z_IS_2388_EQ_2388U(...) \, +#define Z_IS_2388U_EQ_2388U(...) \, +#define Z_IS_2389_EQ_2389(...) \, +#define Z_IS_2389U_EQ_2389(...) \, +#define Z_IS_2389_EQ_2389U(...) \, +#define Z_IS_2389U_EQ_2389U(...) \, +#define Z_IS_2390_EQ_2390(...) \, +#define Z_IS_2390U_EQ_2390(...) \, +#define Z_IS_2390_EQ_2390U(...) \, +#define Z_IS_2390U_EQ_2390U(...) \, +#define Z_IS_2391_EQ_2391(...) \, +#define Z_IS_2391U_EQ_2391(...) \, +#define Z_IS_2391_EQ_2391U(...) \, +#define Z_IS_2391U_EQ_2391U(...) \, +#define Z_IS_2392_EQ_2392(...) \, +#define Z_IS_2392U_EQ_2392(...) \, +#define Z_IS_2392_EQ_2392U(...) \, +#define Z_IS_2392U_EQ_2392U(...) \, +#define Z_IS_2393_EQ_2393(...) \, +#define Z_IS_2393U_EQ_2393(...) \, +#define Z_IS_2393_EQ_2393U(...) \, +#define Z_IS_2393U_EQ_2393U(...) \, +#define Z_IS_2394_EQ_2394(...) \, +#define Z_IS_2394U_EQ_2394(...) \, +#define Z_IS_2394_EQ_2394U(...) \, +#define Z_IS_2394U_EQ_2394U(...) \, +#define Z_IS_2395_EQ_2395(...) \, +#define Z_IS_2395U_EQ_2395(...) \, +#define Z_IS_2395_EQ_2395U(...) \, +#define Z_IS_2395U_EQ_2395U(...) \, +#define Z_IS_2396_EQ_2396(...) \, +#define Z_IS_2396U_EQ_2396(...) \, +#define Z_IS_2396_EQ_2396U(...) \, +#define Z_IS_2396U_EQ_2396U(...) \, +#define Z_IS_2397_EQ_2397(...) \, +#define Z_IS_2397U_EQ_2397(...) \, +#define Z_IS_2397_EQ_2397U(...) \, +#define Z_IS_2397U_EQ_2397U(...) \, +#define Z_IS_2398_EQ_2398(...) \, +#define Z_IS_2398U_EQ_2398(...) \, +#define Z_IS_2398_EQ_2398U(...) \, +#define Z_IS_2398U_EQ_2398U(...) \, +#define Z_IS_2399_EQ_2399(...) \, +#define Z_IS_2399U_EQ_2399(...) \, +#define Z_IS_2399_EQ_2399U(...) \, +#define Z_IS_2399U_EQ_2399U(...) \, +#define Z_IS_2400_EQ_2400(...) \, +#define Z_IS_2400U_EQ_2400(...) \, +#define Z_IS_2400_EQ_2400U(...) \, +#define Z_IS_2400U_EQ_2400U(...) \, +#define Z_IS_2401_EQ_2401(...) \, +#define Z_IS_2401U_EQ_2401(...) \, +#define Z_IS_2401_EQ_2401U(...) \, +#define Z_IS_2401U_EQ_2401U(...) \, +#define Z_IS_2402_EQ_2402(...) \, +#define Z_IS_2402U_EQ_2402(...) \, +#define Z_IS_2402_EQ_2402U(...) \, +#define Z_IS_2402U_EQ_2402U(...) \, +#define Z_IS_2403_EQ_2403(...) \, +#define Z_IS_2403U_EQ_2403(...) \, +#define Z_IS_2403_EQ_2403U(...) \, +#define Z_IS_2403U_EQ_2403U(...) \, +#define Z_IS_2404_EQ_2404(...) \, +#define Z_IS_2404U_EQ_2404(...) \, +#define Z_IS_2404_EQ_2404U(...) \, +#define Z_IS_2404U_EQ_2404U(...) \, +#define Z_IS_2405_EQ_2405(...) \, +#define Z_IS_2405U_EQ_2405(...) \, +#define Z_IS_2405_EQ_2405U(...) \, +#define Z_IS_2405U_EQ_2405U(...) \, +#define Z_IS_2406_EQ_2406(...) \, +#define Z_IS_2406U_EQ_2406(...) \, +#define Z_IS_2406_EQ_2406U(...) \, +#define Z_IS_2406U_EQ_2406U(...) \, +#define Z_IS_2407_EQ_2407(...) \, +#define Z_IS_2407U_EQ_2407(...) \, +#define Z_IS_2407_EQ_2407U(...) \, +#define Z_IS_2407U_EQ_2407U(...) \, +#define Z_IS_2408_EQ_2408(...) \, +#define Z_IS_2408U_EQ_2408(...) \, +#define Z_IS_2408_EQ_2408U(...) \, +#define Z_IS_2408U_EQ_2408U(...) \, +#define Z_IS_2409_EQ_2409(...) \, +#define Z_IS_2409U_EQ_2409(...) \, +#define Z_IS_2409_EQ_2409U(...) \, +#define Z_IS_2409U_EQ_2409U(...) \, +#define Z_IS_2410_EQ_2410(...) \, +#define Z_IS_2410U_EQ_2410(...) \, +#define Z_IS_2410_EQ_2410U(...) \, +#define Z_IS_2410U_EQ_2410U(...) \, +#define Z_IS_2411_EQ_2411(...) \, +#define Z_IS_2411U_EQ_2411(...) \, +#define Z_IS_2411_EQ_2411U(...) \, +#define Z_IS_2411U_EQ_2411U(...) \, +#define Z_IS_2412_EQ_2412(...) \, +#define Z_IS_2412U_EQ_2412(...) \, +#define Z_IS_2412_EQ_2412U(...) \, +#define Z_IS_2412U_EQ_2412U(...) \, +#define Z_IS_2413_EQ_2413(...) \, +#define Z_IS_2413U_EQ_2413(...) \, +#define Z_IS_2413_EQ_2413U(...) \, +#define Z_IS_2413U_EQ_2413U(...) \, +#define Z_IS_2414_EQ_2414(...) \, +#define Z_IS_2414U_EQ_2414(...) \, +#define Z_IS_2414_EQ_2414U(...) \, +#define Z_IS_2414U_EQ_2414U(...) \, +#define Z_IS_2415_EQ_2415(...) \, +#define Z_IS_2415U_EQ_2415(...) \, +#define Z_IS_2415_EQ_2415U(...) \, +#define Z_IS_2415U_EQ_2415U(...) \, +#define Z_IS_2416_EQ_2416(...) \, +#define Z_IS_2416U_EQ_2416(...) \, +#define Z_IS_2416_EQ_2416U(...) \, +#define Z_IS_2416U_EQ_2416U(...) \, +#define Z_IS_2417_EQ_2417(...) \, +#define Z_IS_2417U_EQ_2417(...) \, +#define Z_IS_2417_EQ_2417U(...) \, +#define Z_IS_2417U_EQ_2417U(...) \, +#define Z_IS_2418_EQ_2418(...) \, +#define Z_IS_2418U_EQ_2418(...) \, +#define Z_IS_2418_EQ_2418U(...) \, +#define Z_IS_2418U_EQ_2418U(...) \, +#define Z_IS_2419_EQ_2419(...) \, +#define Z_IS_2419U_EQ_2419(...) \, +#define Z_IS_2419_EQ_2419U(...) \, +#define Z_IS_2419U_EQ_2419U(...) \, +#define Z_IS_2420_EQ_2420(...) \, +#define Z_IS_2420U_EQ_2420(...) \, +#define Z_IS_2420_EQ_2420U(...) \, +#define Z_IS_2420U_EQ_2420U(...) \, +#define Z_IS_2421_EQ_2421(...) \, +#define Z_IS_2421U_EQ_2421(...) \, +#define Z_IS_2421_EQ_2421U(...) \, +#define Z_IS_2421U_EQ_2421U(...) \, +#define Z_IS_2422_EQ_2422(...) \, +#define Z_IS_2422U_EQ_2422(...) \, +#define Z_IS_2422_EQ_2422U(...) \, +#define Z_IS_2422U_EQ_2422U(...) \, +#define Z_IS_2423_EQ_2423(...) \, +#define Z_IS_2423U_EQ_2423(...) \, +#define Z_IS_2423_EQ_2423U(...) \, +#define Z_IS_2423U_EQ_2423U(...) \, +#define Z_IS_2424_EQ_2424(...) \, +#define Z_IS_2424U_EQ_2424(...) \, +#define Z_IS_2424_EQ_2424U(...) \, +#define Z_IS_2424U_EQ_2424U(...) \, +#define Z_IS_2425_EQ_2425(...) \, +#define Z_IS_2425U_EQ_2425(...) \, +#define Z_IS_2425_EQ_2425U(...) \, +#define Z_IS_2425U_EQ_2425U(...) \, +#define Z_IS_2426_EQ_2426(...) \, +#define Z_IS_2426U_EQ_2426(...) \, +#define Z_IS_2426_EQ_2426U(...) \, +#define Z_IS_2426U_EQ_2426U(...) \, +#define Z_IS_2427_EQ_2427(...) \, +#define Z_IS_2427U_EQ_2427(...) \, +#define Z_IS_2427_EQ_2427U(...) \, +#define Z_IS_2427U_EQ_2427U(...) \, +#define Z_IS_2428_EQ_2428(...) \, +#define Z_IS_2428U_EQ_2428(...) \, +#define Z_IS_2428_EQ_2428U(...) \, +#define Z_IS_2428U_EQ_2428U(...) \, +#define Z_IS_2429_EQ_2429(...) \, +#define Z_IS_2429U_EQ_2429(...) \, +#define Z_IS_2429_EQ_2429U(...) \, +#define Z_IS_2429U_EQ_2429U(...) \, +#define Z_IS_2430_EQ_2430(...) \, +#define Z_IS_2430U_EQ_2430(...) \, +#define Z_IS_2430_EQ_2430U(...) \, +#define Z_IS_2430U_EQ_2430U(...) \, +#define Z_IS_2431_EQ_2431(...) \, +#define Z_IS_2431U_EQ_2431(...) \, +#define Z_IS_2431_EQ_2431U(...) \, +#define Z_IS_2431U_EQ_2431U(...) \, +#define Z_IS_2432_EQ_2432(...) \, +#define Z_IS_2432U_EQ_2432(...) \, +#define Z_IS_2432_EQ_2432U(...) \, +#define Z_IS_2432U_EQ_2432U(...) \, +#define Z_IS_2433_EQ_2433(...) \, +#define Z_IS_2433U_EQ_2433(...) \, +#define Z_IS_2433_EQ_2433U(...) \, +#define Z_IS_2433U_EQ_2433U(...) \, +#define Z_IS_2434_EQ_2434(...) \, +#define Z_IS_2434U_EQ_2434(...) \, +#define Z_IS_2434_EQ_2434U(...) \, +#define Z_IS_2434U_EQ_2434U(...) \, +#define Z_IS_2435_EQ_2435(...) \, +#define Z_IS_2435U_EQ_2435(...) \, +#define Z_IS_2435_EQ_2435U(...) \, +#define Z_IS_2435U_EQ_2435U(...) \, +#define Z_IS_2436_EQ_2436(...) \, +#define Z_IS_2436U_EQ_2436(...) \, +#define Z_IS_2436_EQ_2436U(...) \, +#define Z_IS_2436U_EQ_2436U(...) \, +#define Z_IS_2437_EQ_2437(...) \, +#define Z_IS_2437U_EQ_2437(...) \, +#define Z_IS_2437_EQ_2437U(...) \, +#define Z_IS_2437U_EQ_2437U(...) \, +#define Z_IS_2438_EQ_2438(...) \, +#define Z_IS_2438U_EQ_2438(...) \, +#define Z_IS_2438_EQ_2438U(...) \, +#define Z_IS_2438U_EQ_2438U(...) \, +#define Z_IS_2439_EQ_2439(...) \, +#define Z_IS_2439U_EQ_2439(...) \, +#define Z_IS_2439_EQ_2439U(...) \, +#define Z_IS_2439U_EQ_2439U(...) \, +#define Z_IS_2440_EQ_2440(...) \, +#define Z_IS_2440U_EQ_2440(...) \, +#define Z_IS_2440_EQ_2440U(...) \, +#define Z_IS_2440U_EQ_2440U(...) \, +#define Z_IS_2441_EQ_2441(...) \, +#define Z_IS_2441U_EQ_2441(...) \, +#define Z_IS_2441_EQ_2441U(...) \, +#define Z_IS_2441U_EQ_2441U(...) \, +#define Z_IS_2442_EQ_2442(...) \, +#define Z_IS_2442U_EQ_2442(...) \, +#define Z_IS_2442_EQ_2442U(...) \, +#define Z_IS_2442U_EQ_2442U(...) \, +#define Z_IS_2443_EQ_2443(...) \, +#define Z_IS_2443U_EQ_2443(...) \, +#define Z_IS_2443_EQ_2443U(...) \, +#define Z_IS_2443U_EQ_2443U(...) \, +#define Z_IS_2444_EQ_2444(...) \, +#define Z_IS_2444U_EQ_2444(...) \, +#define Z_IS_2444_EQ_2444U(...) \, +#define Z_IS_2444U_EQ_2444U(...) \, +#define Z_IS_2445_EQ_2445(...) \, +#define Z_IS_2445U_EQ_2445(...) \, +#define Z_IS_2445_EQ_2445U(...) \, +#define Z_IS_2445U_EQ_2445U(...) \, +#define Z_IS_2446_EQ_2446(...) \, +#define Z_IS_2446U_EQ_2446(...) \, +#define Z_IS_2446_EQ_2446U(...) \, +#define Z_IS_2446U_EQ_2446U(...) \, +#define Z_IS_2447_EQ_2447(...) \, +#define Z_IS_2447U_EQ_2447(...) \, +#define Z_IS_2447_EQ_2447U(...) \, +#define Z_IS_2447U_EQ_2447U(...) \, +#define Z_IS_2448_EQ_2448(...) \, +#define Z_IS_2448U_EQ_2448(...) \, +#define Z_IS_2448_EQ_2448U(...) \, +#define Z_IS_2448U_EQ_2448U(...) \, +#define Z_IS_2449_EQ_2449(...) \, +#define Z_IS_2449U_EQ_2449(...) \, +#define Z_IS_2449_EQ_2449U(...) \, +#define Z_IS_2449U_EQ_2449U(...) \, +#define Z_IS_2450_EQ_2450(...) \, +#define Z_IS_2450U_EQ_2450(...) \, +#define Z_IS_2450_EQ_2450U(...) \, +#define Z_IS_2450U_EQ_2450U(...) \, +#define Z_IS_2451_EQ_2451(...) \, +#define Z_IS_2451U_EQ_2451(...) \, +#define Z_IS_2451_EQ_2451U(...) \, +#define Z_IS_2451U_EQ_2451U(...) \, +#define Z_IS_2452_EQ_2452(...) \, +#define Z_IS_2452U_EQ_2452(...) \, +#define Z_IS_2452_EQ_2452U(...) \, +#define Z_IS_2452U_EQ_2452U(...) \, +#define Z_IS_2453_EQ_2453(...) \, +#define Z_IS_2453U_EQ_2453(...) \, +#define Z_IS_2453_EQ_2453U(...) \, +#define Z_IS_2453U_EQ_2453U(...) \, +#define Z_IS_2454_EQ_2454(...) \, +#define Z_IS_2454U_EQ_2454(...) \, +#define Z_IS_2454_EQ_2454U(...) \, +#define Z_IS_2454U_EQ_2454U(...) \, +#define Z_IS_2455_EQ_2455(...) \, +#define Z_IS_2455U_EQ_2455(...) \, +#define Z_IS_2455_EQ_2455U(...) \, +#define Z_IS_2455U_EQ_2455U(...) \, +#define Z_IS_2456_EQ_2456(...) \, +#define Z_IS_2456U_EQ_2456(...) \, +#define Z_IS_2456_EQ_2456U(...) \, +#define Z_IS_2456U_EQ_2456U(...) \, +#define Z_IS_2457_EQ_2457(...) \, +#define Z_IS_2457U_EQ_2457(...) \, +#define Z_IS_2457_EQ_2457U(...) \, +#define Z_IS_2457U_EQ_2457U(...) \, +#define Z_IS_2458_EQ_2458(...) \, +#define Z_IS_2458U_EQ_2458(...) \, +#define Z_IS_2458_EQ_2458U(...) \, +#define Z_IS_2458U_EQ_2458U(...) \, +#define Z_IS_2459_EQ_2459(...) \, +#define Z_IS_2459U_EQ_2459(...) \, +#define Z_IS_2459_EQ_2459U(...) \, +#define Z_IS_2459U_EQ_2459U(...) \, +#define Z_IS_2460_EQ_2460(...) \, +#define Z_IS_2460U_EQ_2460(...) \, +#define Z_IS_2460_EQ_2460U(...) \, +#define Z_IS_2460U_EQ_2460U(...) \, +#define Z_IS_2461_EQ_2461(...) \, +#define Z_IS_2461U_EQ_2461(...) \, +#define Z_IS_2461_EQ_2461U(...) \, +#define Z_IS_2461U_EQ_2461U(...) \, +#define Z_IS_2462_EQ_2462(...) \, +#define Z_IS_2462U_EQ_2462(...) \, +#define Z_IS_2462_EQ_2462U(...) \, +#define Z_IS_2462U_EQ_2462U(...) \, +#define Z_IS_2463_EQ_2463(...) \, +#define Z_IS_2463U_EQ_2463(...) \, +#define Z_IS_2463_EQ_2463U(...) \, +#define Z_IS_2463U_EQ_2463U(...) \, +#define Z_IS_2464_EQ_2464(...) \, +#define Z_IS_2464U_EQ_2464(...) \, +#define Z_IS_2464_EQ_2464U(...) \, +#define Z_IS_2464U_EQ_2464U(...) \, +#define Z_IS_2465_EQ_2465(...) \, +#define Z_IS_2465U_EQ_2465(...) \, +#define Z_IS_2465_EQ_2465U(...) \, +#define Z_IS_2465U_EQ_2465U(...) \, +#define Z_IS_2466_EQ_2466(...) \, +#define Z_IS_2466U_EQ_2466(...) \, +#define Z_IS_2466_EQ_2466U(...) \, +#define Z_IS_2466U_EQ_2466U(...) \, +#define Z_IS_2467_EQ_2467(...) \, +#define Z_IS_2467U_EQ_2467(...) \, +#define Z_IS_2467_EQ_2467U(...) \, +#define Z_IS_2467U_EQ_2467U(...) \, +#define Z_IS_2468_EQ_2468(...) \, +#define Z_IS_2468U_EQ_2468(...) \, +#define Z_IS_2468_EQ_2468U(...) \, +#define Z_IS_2468U_EQ_2468U(...) \, +#define Z_IS_2469_EQ_2469(...) \, +#define Z_IS_2469U_EQ_2469(...) \, +#define Z_IS_2469_EQ_2469U(...) \, +#define Z_IS_2469U_EQ_2469U(...) \, +#define Z_IS_2470_EQ_2470(...) \, +#define Z_IS_2470U_EQ_2470(...) \, +#define Z_IS_2470_EQ_2470U(...) \, +#define Z_IS_2470U_EQ_2470U(...) \, +#define Z_IS_2471_EQ_2471(...) \, +#define Z_IS_2471U_EQ_2471(...) \, +#define Z_IS_2471_EQ_2471U(...) \, +#define Z_IS_2471U_EQ_2471U(...) \, +#define Z_IS_2472_EQ_2472(...) \, +#define Z_IS_2472U_EQ_2472(...) \, +#define Z_IS_2472_EQ_2472U(...) \, +#define Z_IS_2472U_EQ_2472U(...) \, +#define Z_IS_2473_EQ_2473(...) \, +#define Z_IS_2473U_EQ_2473(...) \, +#define Z_IS_2473_EQ_2473U(...) \, +#define Z_IS_2473U_EQ_2473U(...) \, +#define Z_IS_2474_EQ_2474(...) \, +#define Z_IS_2474U_EQ_2474(...) \, +#define Z_IS_2474_EQ_2474U(...) \, +#define Z_IS_2474U_EQ_2474U(...) \, +#define Z_IS_2475_EQ_2475(...) \, +#define Z_IS_2475U_EQ_2475(...) \, +#define Z_IS_2475_EQ_2475U(...) \, +#define Z_IS_2475U_EQ_2475U(...) \, +#define Z_IS_2476_EQ_2476(...) \, +#define Z_IS_2476U_EQ_2476(...) \, +#define Z_IS_2476_EQ_2476U(...) \, +#define Z_IS_2476U_EQ_2476U(...) \, +#define Z_IS_2477_EQ_2477(...) \, +#define Z_IS_2477U_EQ_2477(...) \, +#define Z_IS_2477_EQ_2477U(...) \, +#define Z_IS_2477U_EQ_2477U(...) \, +#define Z_IS_2478_EQ_2478(...) \, +#define Z_IS_2478U_EQ_2478(...) \, +#define Z_IS_2478_EQ_2478U(...) \, +#define Z_IS_2478U_EQ_2478U(...) \, +#define Z_IS_2479_EQ_2479(...) \, +#define Z_IS_2479U_EQ_2479(...) \, +#define Z_IS_2479_EQ_2479U(...) \, +#define Z_IS_2479U_EQ_2479U(...) \, +#define Z_IS_2480_EQ_2480(...) \, +#define Z_IS_2480U_EQ_2480(...) \, +#define Z_IS_2480_EQ_2480U(...) \, +#define Z_IS_2480U_EQ_2480U(...) \, +#define Z_IS_2481_EQ_2481(...) \, +#define Z_IS_2481U_EQ_2481(...) \, +#define Z_IS_2481_EQ_2481U(...) \, +#define Z_IS_2481U_EQ_2481U(...) \, +#define Z_IS_2482_EQ_2482(...) \, +#define Z_IS_2482U_EQ_2482(...) \, +#define Z_IS_2482_EQ_2482U(...) \, +#define Z_IS_2482U_EQ_2482U(...) \, +#define Z_IS_2483_EQ_2483(...) \, +#define Z_IS_2483U_EQ_2483(...) \, +#define Z_IS_2483_EQ_2483U(...) \, +#define Z_IS_2483U_EQ_2483U(...) \, +#define Z_IS_2484_EQ_2484(...) \, +#define Z_IS_2484U_EQ_2484(...) \, +#define Z_IS_2484_EQ_2484U(...) \, +#define Z_IS_2484U_EQ_2484U(...) \, +#define Z_IS_2485_EQ_2485(...) \, +#define Z_IS_2485U_EQ_2485(...) \, +#define Z_IS_2485_EQ_2485U(...) \, +#define Z_IS_2485U_EQ_2485U(...) \, +#define Z_IS_2486_EQ_2486(...) \, +#define Z_IS_2486U_EQ_2486(...) \, +#define Z_IS_2486_EQ_2486U(...) \, +#define Z_IS_2486U_EQ_2486U(...) \, +#define Z_IS_2487_EQ_2487(...) \, +#define Z_IS_2487U_EQ_2487(...) \, +#define Z_IS_2487_EQ_2487U(...) \, +#define Z_IS_2487U_EQ_2487U(...) \, +#define Z_IS_2488_EQ_2488(...) \, +#define Z_IS_2488U_EQ_2488(...) \, +#define Z_IS_2488_EQ_2488U(...) \, +#define Z_IS_2488U_EQ_2488U(...) \, +#define Z_IS_2489_EQ_2489(...) \, +#define Z_IS_2489U_EQ_2489(...) \, +#define Z_IS_2489_EQ_2489U(...) \, +#define Z_IS_2489U_EQ_2489U(...) \, +#define Z_IS_2490_EQ_2490(...) \, +#define Z_IS_2490U_EQ_2490(...) \, +#define Z_IS_2490_EQ_2490U(...) \, +#define Z_IS_2490U_EQ_2490U(...) \, +#define Z_IS_2491_EQ_2491(...) \, +#define Z_IS_2491U_EQ_2491(...) \, +#define Z_IS_2491_EQ_2491U(...) \, +#define Z_IS_2491U_EQ_2491U(...) \, +#define Z_IS_2492_EQ_2492(...) \, +#define Z_IS_2492U_EQ_2492(...) \, +#define Z_IS_2492_EQ_2492U(...) \, +#define Z_IS_2492U_EQ_2492U(...) \, +#define Z_IS_2493_EQ_2493(...) \, +#define Z_IS_2493U_EQ_2493(...) \, +#define Z_IS_2493_EQ_2493U(...) \, +#define Z_IS_2493U_EQ_2493U(...) \, +#define Z_IS_2494_EQ_2494(...) \, +#define Z_IS_2494U_EQ_2494(...) \, +#define Z_IS_2494_EQ_2494U(...) \, +#define Z_IS_2494U_EQ_2494U(...) \, +#define Z_IS_2495_EQ_2495(...) \, +#define Z_IS_2495U_EQ_2495(...) \, +#define Z_IS_2495_EQ_2495U(...) \, +#define Z_IS_2495U_EQ_2495U(...) \, +#define Z_IS_2496_EQ_2496(...) \, +#define Z_IS_2496U_EQ_2496(...) \, +#define Z_IS_2496_EQ_2496U(...) \, +#define Z_IS_2496U_EQ_2496U(...) \, +#define Z_IS_2497_EQ_2497(...) \, +#define Z_IS_2497U_EQ_2497(...) \, +#define Z_IS_2497_EQ_2497U(...) \, +#define Z_IS_2497U_EQ_2497U(...) \, +#define Z_IS_2498_EQ_2498(...) \, +#define Z_IS_2498U_EQ_2498(...) \, +#define Z_IS_2498_EQ_2498U(...) \, +#define Z_IS_2498U_EQ_2498U(...) \, +#define Z_IS_2499_EQ_2499(...) \, +#define Z_IS_2499U_EQ_2499(...) \, +#define Z_IS_2499_EQ_2499U(...) \, +#define Z_IS_2499U_EQ_2499U(...) \, +#define Z_IS_2500_EQ_2500(...) \, +#define Z_IS_2500U_EQ_2500(...) \, +#define Z_IS_2500_EQ_2500U(...) \, +#define Z_IS_2500U_EQ_2500U(...) \, +#define Z_IS_2501_EQ_2501(...) \, +#define Z_IS_2501U_EQ_2501(...) \, +#define Z_IS_2501_EQ_2501U(...) \, +#define Z_IS_2501U_EQ_2501U(...) \, +#define Z_IS_2502_EQ_2502(...) \, +#define Z_IS_2502U_EQ_2502(...) \, +#define Z_IS_2502_EQ_2502U(...) \, +#define Z_IS_2502U_EQ_2502U(...) \, +#define Z_IS_2503_EQ_2503(...) \, +#define Z_IS_2503U_EQ_2503(...) \, +#define Z_IS_2503_EQ_2503U(...) \, +#define Z_IS_2503U_EQ_2503U(...) \, +#define Z_IS_2504_EQ_2504(...) \, +#define Z_IS_2504U_EQ_2504(...) \, +#define Z_IS_2504_EQ_2504U(...) \, +#define Z_IS_2504U_EQ_2504U(...) \, +#define Z_IS_2505_EQ_2505(...) \, +#define Z_IS_2505U_EQ_2505(...) \, +#define Z_IS_2505_EQ_2505U(...) \, +#define Z_IS_2505U_EQ_2505U(...) \, +#define Z_IS_2506_EQ_2506(...) \, +#define Z_IS_2506U_EQ_2506(...) \, +#define Z_IS_2506_EQ_2506U(...) \, +#define Z_IS_2506U_EQ_2506U(...) \, +#define Z_IS_2507_EQ_2507(...) \, +#define Z_IS_2507U_EQ_2507(...) \, +#define Z_IS_2507_EQ_2507U(...) \, +#define Z_IS_2507U_EQ_2507U(...) \, +#define Z_IS_2508_EQ_2508(...) \, +#define Z_IS_2508U_EQ_2508(...) \, +#define Z_IS_2508_EQ_2508U(...) \, +#define Z_IS_2508U_EQ_2508U(...) \, +#define Z_IS_2509_EQ_2509(...) \, +#define Z_IS_2509U_EQ_2509(...) \, +#define Z_IS_2509_EQ_2509U(...) \, +#define Z_IS_2509U_EQ_2509U(...) \, +#define Z_IS_2510_EQ_2510(...) \, +#define Z_IS_2510U_EQ_2510(...) \, +#define Z_IS_2510_EQ_2510U(...) \, +#define Z_IS_2510U_EQ_2510U(...) \, +#define Z_IS_2511_EQ_2511(...) \, +#define Z_IS_2511U_EQ_2511(...) \, +#define Z_IS_2511_EQ_2511U(...) \, +#define Z_IS_2511U_EQ_2511U(...) \, +#define Z_IS_2512_EQ_2512(...) \, +#define Z_IS_2512U_EQ_2512(...) \, +#define Z_IS_2512_EQ_2512U(...) \, +#define Z_IS_2512U_EQ_2512U(...) \, +#define Z_IS_2513_EQ_2513(...) \, +#define Z_IS_2513U_EQ_2513(...) \, +#define Z_IS_2513_EQ_2513U(...) \, +#define Z_IS_2513U_EQ_2513U(...) \, +#define Z_IS_2514_EQ_2514(...) \, +#define Z_IS_2514U_EQ_2514(...) \, +#define Z_IS_2514_EQ_2514U(...) \, +#define Z_IS_2514U_EQ_2514U(...) \, +#define Z_IS_2515_EQ_2515(...) \, +#define Z_IS_2515U_EQ_2515(...) \, +#define Z_IS_2515_EQ_2515U(...) \, +#define Z_IS_2515U_EQ_2515U(...) \, +#define Z_IS_2516_EQ_2516(...) \, +#define Z_IS_2516U_EQ_2516(...) \, +#define Z_IS_2516_EQ_2516U(...) \, +#define Z_IS_2516U_EQ_2516U(...) \, +#define Z_IS_2517_EQ_2517(...) \, +#define Z_IS_2517U_EQ_2517(...) \, +#define Z_IS_2517_EQ_2517U(...) \, +#define Z_IS_2517U_EQ_2517U(...) \, +#define Z_IS_2518_EQ_2518(...) \, +#define Z_IS_2518U_EQ_2518(...) \, +#define Z_IS_2518_EQ_2518U(...) \, +#define Z_IS_2518U_EQ_2518U(...) \, +#define Z_IS_2519_EQ_2519(...) \, +#define Z_IS_2519U_EQ_2519(...) \, +#define Z_IS_2519_EQ_2519U(...) \, +#define Z_IS_2519U_EQ_2519U(...) \, +#define Z_IS_2520_EQ_2520(...) \, +#define Z_IS_2520U_EQ_2520(...) \, +#define Z_IS_2520_EQ_2520U(...) \, +#define Z_IS_2520U_EQ_2520U(...) \, +#define Z_IS_2521_EQ_2521(...) \, +#define Z_IS_2521U_EQ_2521(...) \, +#define Z_IS_2521_EQ_2521U(...) \, +#define Z_IS_2521U_EQ_2521U(...) \, +#define Z_IS_2522_EQ_2522(...) \, +#define Z_IS_2522U_EQ_2522(...) \, +#define Z_IS_2522_EQ_2522U(...) \, +#define Z_IS_2522U_EQ_2522U(...) \, +#define Z_IS_2523_EQ_2523(...) \, +#define Z_IS_2523U_EQ_2523(...) \, +#define Z_IS_2523_EQ_2523U(...) \, +#define Z_IS_2523U_EQ_2523U(...) \, +#define Z_IS_2524_EQ_2524(...) \, +#define Z_IS_2524U_EQ_2524(...) \, +#define Z_IS_2524_EQ_2524U(...) \, +#define Z_IS_2524U_EQ_2524U(...) \, +#define Z_IS_2525_EQ_2525(...) \, +#define Z_IS_2525U_EQ_2525(...) \, +#define Z_IS_2525_EQ_2525U(...) \, +#define Z_IS_2525U_EQ_2525U(...) \, +#define Z_IS_2526_EQ_2526(...) \, +#define Z_IS_2526U_EQ_2526(...) \, +#define Z_IS_2526_EQ_2526U(...) \, +#define Z_IS_2526U_EQ_2526U(...) \, +#define Z_IS_2527_EQ_2527(...) \, +#define Z_IS_2527U_EQ_2527(...) \, +#define Z_IS_2527_EQ_2527U(...) \, +#define Z_IS_2527U_EQ_2527U(...) \, +#define Z_IS_2528_EQ_2528(...) \, +#define Z_IS_2528U_EQ_2528(...) \, +#define Z_IS_2528_EQ_2528U(...) \, +#define Z_IS_2528U_EQ_2528U(...) \, +#define Z_IS_2529_EQ_2529(...) \, +#define Z_IS_2529U_EQ_2529(...) \, +#define Z_IS_2529_EQ_2529U(...) \, +#define Z_IS_2529U_EQ_2529U(...) \, +#define Z_IS_2530_EQ_2530(...) \, +#define Z_IS_2530U_EQ_2530(...) \, +#define Z_IS_2530_EQ_2530U(...) \, +#define Z_IS_2530U_EQ_2530U(...) \, +#define Z_IS_2531_EQ_2531(...) \, +#define Z_IS_2531U_EQ_2531(...) \, +#define Z_IS_2531_EQ_2531U(...) \, +#define Z_IS_2531U_EQ_2531U(...) \, +#define Z_IS_2532_EQ_2532(...) \, +#define Z_IS_2532U_EQ_2532(...) \, +#define Z_IS_2532_EQ_2532U(...) \, +#define Z_IS_2532U_EQ_2532U(...) \, +#define Z_IS_2533_EQ_2533(...) \, +#define Z_IS_2533U_EQ_2533(...) \, +#define Z_IS_2533_EQ_2533U(...) \, +#define Z_IS_2533U_EQ_2533U(...) \, +#define Z_IS_2534_EQ_2534(...) \, +#define Z_IS_2534U_EQ_2534(...) \, +#define Z_IS_2534_EQ_2534U(...) \, +#define Z_IS_2534U_EQ_2534U(...) \, +#define Z_IS_2535_EQ_2535(...) \, +#define Z_IS_2535U_EQ_2535(...) \, +#define Z_IS_2535_EQ_2535U(...) \, +#define Z_IS_2535U_EQ_2535U(...) \, +#define Z_IS_2536_EQ_2536(...) \, +#define Z_IS_2536U_EQ_2536(...) \, +#define Z_IS_2536_EQ_2536U(...) \, +#define Z_IS_2536U_EQ_2536U(...) \, +#define Z_IS_2537_EQ_2537(...) \, +#define Z_IS_2537U_EQ_2537(...) \, +#define Z_IS_2537_EQ_2537U(...) \, +#define Z_IS_2537U_EQ_2537U(...) \, +#define Z_IS_2538_EQ_2538(...) \, +#define Z_IS_2538U_EQ_2538(...) \, +#define Z_IS_2538_EQ_2538U(...) \, +#define Z_IS_2538U_EQ_2538U(...) \, +#define Z_IS_2539_EQ_2539(...) \, +#define Z_IS_2539U_EQ_2539(...) \, +#define Z_IS_2539_EQ_2539U(...) \, +#define Z_IS_2539U_EQ_2539U(...) \, +#define Z_IS_2540_EQ_2540(...) \, +#define Z_IS_2540U_EQ_2540(...) \, +#define Z_IS_2540_EQ_2540U(...) \, +#define Z_IS_2540U_EQ_2540U(...) \, +#define Z_IS_2541_EQ_2541(...) \, +#define Z_IS_2541U_EQ_2541(...) \, +#define Z_IS_2541_EQ_2541U(...) \, +#define Z_IS_2541U_EQ_2541U(...) \, +#define Z_IS_2542_EQ_2542(...) \, +#define Z_IS_2542U_EQ_2542(...) \, +#define Z_IS_2542_EQ_2542U(...) \, +#define Z_IS_2542U_EQ_2542U(...) \, +#define Z_IS_2543_EQ_2543(...) \, +#define Z_IS_2543U_EQ_2543(...) \, +#define Z_IS_2543_EQ_2543U(...) \, +#define Z_IS_2543U_EQ_2543U(...) \, +#define Z_IS_2544_EQ_2544(...) \, +#define Z_IS_2544U_EQ_2544(...) \, +#define Z_IS_2544_EQ_2544U(...) \, +#define Z_IS_2544U_EQ_2544U(...) \, +#define Z_IS_2545_EQ_2545(...) \, +#define Z_IS_2545U_EQ_2545(...) \, +#define Z_IS_2545_EQ_2545U(...) \, +#define Z_IS_2545U_EQ_2545U(...) \, +#define Z_IS_2546_EQ_2546(...) \, +#define Z_IS_2546U_EQ_2546(...) \, +#define Z_IS_2546_EQ_2546U(...) \, +#define Z_IS_2546U_EQ_2546U(...) \, +#define Z_IS_2547_EQ_2547(...) \, +#define Z_IS_2547U_EQ_2547(...) \, +#define Z_IS_2547_EQ_2547U(...) \, +#define Z_IS_2547U_EQ_2547U(...) \, +#define Z_IS_2548_EQ_2548(...) \, +#define Z_IS_2548U_EQ_2548(...) \, +#define Z_IS_2548_EQ_2548U(...) \, +#define Z_IS_2548U_EQ_2548U(...) \, +#define Z_IS_2549_EQ_2549(...) \, +#define Z_IS_2549U_EQ_2549(...) \, +#define Z_IS_2549_EQ_2549U(...) \, +#define Z_IS_2549U_EQ_2549U(...) \, +#define Z_IS_2550_EQ_2550(...) \, +#define Z_IS_2550U_EQ_2550(...) \, +#define Z_IS_2550_EQ_2550U(...) \, +#define Z_IS_2550U_EQ_2550U(...) \, +#define Z_IS_2551_EQ_2551(...) \, +#define Z_IS_2551U_EQ_2551(...) \, +#define Z_IS_2551_EQ_2551U(...) \, +#define Z_IS_2551U_EQ_2551U(...) \, +#define Z_IS_2552_EQ_2552(...) \, +#define Z_IS_2552U_EQ_2552(...) \, +#define Z_IS_2552_EQ_2552U(...) \, +#define Z_IS_2552U_EQ_2552U(...) \, +#define Z_IS_2553_EQ_2553(...) \, +#define Z_IS_2553U_EQ_2553(...) \, +#define Z_IS_2553_EQ_2553U(...) \, +#define Z_IS_2553U_EQ_2553U(...) \, +#define Z_IS_2554_EQ_2554(...) \, +#define Z_IS_2554U_EQ_2554(...) \, +#define Z_IS_2554_EQ_2554U(...) \, +#define Z_IS_2554U_EQ_2554U(...) \, +#define Z_IS_2555_EQ_2555(...) \, +#define Z_IS_2555U_EQ_2555(...) \, +#define Z_IS_2555_EQ_2555U(...) \, +#define Z_IS_2555U_EQ_2555U(...) \, +#define Z_IS_2556_EQ_2556(...) \, +#define Z_IS_2556U_EQ_2556(...) \, +#define Z_IS_2556_EQ_2556U(...) \, +#define Z_IS_2556U_EQ_2556U(...) \, +#define Z_IS_2557_EQ_2557(...) \, +#define Z_IS_2557U_EQ_2557(...) \, +#define Z_IS_2557_EQ_2557U(...) \, +#define Z_IS_2557U_EQ_2557U(...) \, +#define Z_IS_2558_EQ_2558(...) \, +#define Z_IS_2558U_EQ_2558(...) \, +#define Z_IS_2558_EQ_2558U(...) \, +#define Z_IS_2558U_EQ_2558U(...) \, +#define Z_IS_2559_EQ_2559(...) \, +#define Z_IS_2559U_EQ_2559(...) \, +#define Z_IS_2559_EQ_2559U(...) \, +#define Z_IS_2559U_EQ_2559U(...) \, +#define Z_IS_2560_EQ_2560(...) \, +#define Z_IS_2560U_EQ_2560(...) \, +#define Z_IS_2560_EQ_2560U(...) \, +#define Z_IS_2560U_EQ_2560U(...) \, +#define Z_IS_2561_EQ_2561(...) \, +#define Z_IS_2561U_EQ_2561(...) \, +#define Z_IS_2561_EQ_2561U(...) \, +#define Z_IS_2561U_EQ_2561U(...) \, +#define Z_IS_2562_EQ_2562(...) \, +#define Z_IS_2562U_EQ_2562(...) \, +#define Z_IS_2562_EQ_2562U(...) \, +#define Z_IS_2562U_EQ_2562U(...) \, +#define Z_IS_2563_EQ_2563(...) \, +#define Z_IS_2563U_EQ_2563(...) \, +#define Z_IS_2563_EQ_2563U(...) \, +#define Z_IS_2563U_EQ_2563U(...) \, +#define Z_IS_2564_EQ_2564(...) \, +#define Z_IS_2564U_EQ_2564(...) \, +#define Z_IS_2564_EQ_2564U(...) \, +#define Z_IS_2564U_EQ_2564U(...) \, +#define Z_IS_2565_EQ_2565(...) \, +#define Z_IS_2565U_EQ_2565(...) \, +#define Z_IS_2565_EQ_2565U(...) \, +#define Z_IS_2565U_EQ_2565U(...) \, +#define Z_IS_2566_EQ_2566(...) \, +#define Z_IS_2566U_EQ_2566(...) \, +#define Z_IS_2566_EQ_2566U(...) \, +#define Z_IS_2566U_EQ_2566U(...) \, +#define Z_IS_2567_EQ_2567(...) \, +#define Z_IS_2567U_EQ_2567(...) \, +#define Z_IS_2567_EQ_2567U(...) \, +#define Z_IS_2567U_EQ_2567U(...) \, +#define Z_IS_2568_EQ_2568(...) \, +#define Z_IS_2568U_EQ_2568(...) \, +#define Z_IS_2568_EQ_2568U(...) \, +#define Z_IS_2568U_EQ_2568U(...) \, +#define Z_IS_2569_EQ_2569(...) \, +#define Z_IS_2569U_EQ_2569(...) \, +#define Z_IS_2569_EQ_2569U(...) \, +#define Z_IS_2569U_EQ_2569U(...) \, +#define Z_IS_2570_EQ_2570(...) \, +#define Z_IS_2570U_EQ_2570(...) \, +#define Z_IS_2570_EQ_2570U(...) \, +#define Z_IS_2570U_EQ_2570U(...) \, +#define Z_IS_2571_EQ_2571(...) \, +#define Z_IS_2571U_EQ_2571(...) \, +#define Z_IS_2571_EQ_2571U(...) \, +#define Z_IS_2571U_EQ_2571U(...) \, +#define Z_IS_2572_EQ_2572(...) \, +#define Z_IS_2572U_EQ_2572(...) \, +#define Z_IS_2572_EQ_2572U(...) \, +#define Z_IS_2572U_EQ_2572U(...) \, +#define Z_IS_2573_EQ_2573(...) \, +#define Z_IS_2573U_EQ_2573(...) \, +#define Z_IS_2573_EQ_2573U(...) \, +#define Z_IS_2573U_EQ_2573U(...) \, +#define Z_IS_2574_EQ_2574(...) \, +#define Z_IS_2574U_EQ_2574(...) \, +#define Z_IS_2574_EQ_2574U(...) \, +#define Z_IS_2574U_EQ_2574U(...) \, +#define Z_IS_2575_EQ_2575(...) \, +#define Z_IS_2575U_EQ_2575(...) \, +#define Z_IS_2575_EQ_2575U(...) \, +#define Z_IS_2575U_EQ_2575U(...) \, +#define Z_IS_2576_EQ_2576(...) \, +#define Z_IS_2576U_EQ_2576(...) \, +#define Z_IS_2576_EQ_2576U(...) \, +#define Z_IS_2576U_EQ_2576U(...) \, +#define Z_IS_2577_EQ_2577(...) \, +#define Z_IS_2577U_EQ_2577(...) \, +#define Z_IS_2577_EQ_2577U(...) \, +#define Z_IS_2577U_EQ_2577U(...) \, +#define Z_IS_2578_EQ_2578(...) \, +#define Z_IS_2578U_EQ_2578(...) \, +#define Z_IS_2578_EQ_2578U(...) \, +#define Z_IS_2578U_EQ_2578U(...) \, +#define Z_IS_2579_EQ_2579(...) \, +#define Z_IS_2579U_EQ_2579(...) \, +#define Z_IS_2579_EQ_2579U(...) \, +#define Z_IS_2579U_EQ_2579U(...) \, +#define Z_IS_2580_EQ_2580(...) \, +#define Z_IS_2580U_EQ_2580(...) \, +#define Z_IS_2580_EQ_2580U(...) \, +#define Z_IS_2580U_EQ_2580U(...) \, +#define Z_IS_2581_EQ_2581(...) \, +#define Z_IS_2581U_EQ_2581(...) \, +#define Z_IS_2581_EQ_2581U(...) \, +#define Z_IS_2581U_EQ_2581U(...) \, +#define Z_IS_2582_EQ_2582(...) \, +#define Z_IS_2582U_EQ_2582(...) \, +#define Z_IS_2582_EQ_2582U(...) \, +#define Z_IS_2582U_EQ_2582U(...) \, +#define Z_IS_2583_EQ_2583(...) \, +#define Z_IS_2583U_EQ_2583(...) \, +#define Z_IS_2583_EQ_2583U(...) \, +#define Z_IS_2583U_EQ_2583U(...) \, +#define Z_IS_2584_EQ_2584(...) \, +#define Z_IS_2584U_EQ_2584(...) \, +#define Z_IS_2584_EQ_2584U(...) \, +#define Z_IS_2584U_EQ_2584U(...) \, +#define Z_IS_2585_EQ_2585(...) \, +#define Z_IS_2585U_EQ_2585(...) \, +#define Z_IS_2585_EQ_2585U(...) \, +#define Z_IS_2585U_EQ_2585U(...) \, +#define Z_IS_2586_EQ_2586(...) \, +#define Z_IS_2586U_EQ_2586(...) \, +#define Z_IS_2586_EQ_2586U(...) \, +#define Z_IS_2586U_EQ_2586U(...) \, +#define Z_IS_2587_EQ_2587(...) \, +#define Z_IS_2587U_EQ_2587(...) \, +#define Z_IS_2587_EQ_2587U(...) \, +#define Z_IS_2587U_EQ_2587U(...) \, +#define Z_IS_2588_EQ_2588(...) \, +#define Z_IS_2588U_EQ_2588(...) \, +#define Z_IS_2588_EQ_2588U(...) \, +#define Z_IS_2588U_EQ_2588U(...) \, +#define Z_IS_2589_EQ_2589(...) \, +#define Z_IS_2589U_EQ_2589(...) \, +#define Z_IS_2589_EQ_2589U(...) \, +#define Z_IS_2589U_EQ_2589U(...) \, +#define Z_IS_2590_EQ_2590(...) \, +#define Z_IS_2590U_EQ_2590(...) \, +#define Z_IS_2590_EQ_2590U(...) \, +#define Z_IS_2590U_EQ_2590U(...) \, +#define Z_IS_2591_EQ_2591(...) \, +#define Z_IS_2591U_EQ_2591(...) \, +#define Z_IS_2591_EQ_2591U(...) \, +#define Z_IS_2591U_EQ_2591U(...) \, +#define Z_IS_2592_EQ_2592(...) \, +#define Z_IS_2592U_EQ_2592(...) \, +#define Z_IS_2592_EQ_2592U(...) \, +#define Z_IS_2592U_EQ_2592U(...) \, +#define Z_IS_2593_EQ_2593(...) \, +#define Z_IS_2593U_EQ_2593(...) \, +#define Z_IS_2593_EQ_2593U(...) \, +#define Z_IS_2593U_EQ_2593U(...) \, +#define Z_IS_2594_EQ_2594(...) \, +#define Z_IS_2594U_EQ_2594(...) \, +#define Z_IS_2594_EQ_2594U(...) \, +#define Z_IS_2594U_EQ_2594U(...) \, +#define Z_IS_2595_EQ_2595(...) \, +#define Z_IS_2595U_EQ_2595(...) \, +#define Z_IS_2595_EQ_2595U(...) \, +#define Z_IS_2595U_EQ_2595U(...) \, +#define Z_IS_2596_EQ_2596(...) \, +#define Z_IS_2596U_EQ_2596(...) \, +#define Z_IS_2596_EQ_2596U(...) \, +#define Z_IS_2596U_EQ_2596U(...) \, +#define Z_IS_2597_EQ_2597(...) \, +#define Z_IS_2597U_EQ_2597(...) \, +#define Z_IS_2597_EQ_2597U(...) \, +#define Z_IS_2597U_EQ_2597U(...) \, +#define Z_IS_2598_EQ_2598(...) \, +#define Z_IS_2598U_EQ_2598(...) \, +#define Z_IS_2598_EQ_2598U(...) \, +#define Z_IS_2598U_EQ_2598U(...) \, +#define Z_IS_2599_EQ_2599(...) \, +#define Z_IS_2599U_EQ_2599(...) \, +#define Z_IS_2599_EQ_2599U(...) \, +#define Z_IS_2599U_EQ_2599U(...) \, +#define Z_IS_2600_EQ_2600(...) \, +#define Z_IS_2600U_EQ_2600(...) \, +#define Z_IS_2600_EQ_2600U(...) \, +#define Z_IS_2600U_EQ_2600U(...) \, +#define Z_IS_2601_EQ_2601(...) \, +#define Z_IS_2601U_EQ_2601(...) \, +#define Z_IS_2601_EQ_2601U(...) \, +#define Z_IS_2601U_EQ_2601U(...) \, +#define Z_IS_2602_EQ_2602(...) \, +#define Z_IS_2602U_EQ_2602(...) \, +#define Z_IS_2602_EQ_2602U(...) \, +#define Z_IS_2602U_EQ_2602U(...) \, +#define Z_IS_2603_EQ_2603(...) \, +#define Z_IS_2603U_EQ_2603(...) \, +#define Z_IS_2603_EQ_2603U(...) \, +#define Z_IS_2603U_EQ_2603U(...) \, +#define Z_IS_2604_EQ_2604(...) \, +#define Z_IS_2604U_EQ_2604(...) \, +#define Z_IS_2604_EQ_2604U(...) \, +#define Z_IS_2604U_EQ_2604U(...) \, +#define Z_IS_2605_EQ_2605(...) \, +#define Z_IS_2605U_EQ_2605(...) \, +#define Z_IS_2605_EQ_2605U(...) \, +#define Z_IS_2605U_EQ_2605U(...) \, +#define Z_IS_2606_EQ_2606(...) \, +#define Z_IS_2606U_EQ_2606(...) \, +#define Z_IS_2606_EQ_2606U(...) \, +#define Z_IS_2606U_EQ_2606U(...) \, +#define Z_IS_2607_EQ_2607(...) \, +#define Z_IS_2607U_EQ_2607(...) \, +#define Z_IS_2607_EQ_2607U(...) \, +#define Z_IS_2607U_EQ_2607U(...) \, +#define Z_IS_2608_EQ_2608(...) \, +#define Z_IS_2608U_EQ_2608(...) \, +#define Z_IS_2608_EQ_2608U(...) \, +#define Z_IS_2608U_EQ_2608U(...) \, +#define Z_IS_2609_EQ_2609(...) \, +#define Z_IS_2609U_EQ_2609(...) \, +#define Z_IS_2609_EQ_2609U(...) \, +#define Z_IS_2609U_EQ_2609U(...) \, +#define Z_IS_2610_EQ_2610(...) \, +#define Z_IS_2610U_EQ_2610(...) \, +#define Z_IS_2610_EQ_2610U(...) \, +#define Z_IS_2610U_EQ_2610U(...) \, +#define Z_IS_2611_EQ_2611(...) \, +#define Z_IS_2611U_EQ_2611(...) \, +#define Z_IS_2611_EQ_2611U(...) \, +#define Z_IS_2611U_EQ_2611U(...) \, +#define Z_IS_2612_EQ_2612(...) \, +#define Z_IS_2612U_EQ_2612(...) \, +#define Z_IS_2612_EQ_2612U(...) \, +#define Z_IS_2612U_EQ_2612U(...) \, +#define Z_IS_2613_EQ_2613(...) \, +#define Z_IS_2613U_EQ_2613(...) \, +#define Z_IS_2613_EQ_2613U(...) \, +#define Z_IS_2613U_EQ_2613U(...) \, +#define Z_IS_2614_EQ_2614(...) \, +#define Z_IS_2614U_EQ_2614(...) \, +#define Z_IS_2614_EQ_2614U(...) \, +#define Z_IS_2614U_EQ_2614U(...) \, +#define Z_IS_2615_EQ_2615(...) \, +#define Z_IS_2615U_EQ_2615(...) \, +#define Z_IS_2615_EQ_2615U(...) \, +#define Z_IS_2615U_EQ_2615U(...) \, +#define Z_IS_2616_EQ_2616(...) \, +#define Z_IS_2616U_EQ_2616(...) \, +#define Z_IS_2616_EQ_2616U(...) \, +#define Z_IS_2616U_EQ_2616U(...) \, +#define Z_IS_2617_EQ_2617(...) \, +#define Z_IS_2617U_EQ_2617(...) \, +#define Z_IS_2617_EQ_2617U(...) \, +#define Z_IS_2617U_EQ_2617U(...) \, +#define Z_IS_2618_EQ_2618(...) \, +#define Z_IS_2618U_EQ_2618(...) \, +#define Z_IS_2618_EQ_2618U(...) \, +#define Z_IS_2618U_EQ_2618U(...) \, +#define Z_IS_2619_EQ_2619(...) \, +#define Z_IS_2619U_EQ_2619(...) \, +#define Z_IS_2619_EQ_2619U(...) \, +#define Z_IS_2619U_EQ_2619U(...) \, +#define Z_IS_2620_EQ_2620(...) \, +#define Z_IS_2620U_EQ_2620(...) \, +#define Z_IS_2620_EQ_2620U(...) \, +#define Z_IS_2620U_EQ_2620U(...) \, +#define Z_IS_2621_EQ_2621(...) \, +#define Z_IS_2621U_EQ_2621(...) \, +#define Z_IS_2621_EQ_2621U(...) \, +#define Z_IS_2621U_EQ_2621U(...) \, +#define Z_IS_2622_EQ_2622(...) \, +#define Z_IS_2622U_EQ_2622(...) \, +#define Z_IS_2622_EQ_2622U(...) \, +#define Z_IS_2622U_EQ_2622U(...) \, +#define Z_IS_2623_EQ_2623(...) \, +#define Z_IS_2623U_EQ_2623(...) \, +#define Z_IS_2623_EQ_2623U(...) \, +#define Z_IS_2623U_EQ_2623U(...) \, +#define Z_IS_2624_EQ_2624(...) \, +#define Z_IS_2624U_EQ_2624(...) \, +#define Z_IS_2624_EQ_2624U(...) \, +#define Z_IS_2624U_EQ_2624U(...) \, +#define Z_IS_2625_EQ_2625(...) \, +#define Z_IS_2625U_EQ_2625(...) \, +#define Z_IS_2625_EQ_2625U(...) \, +#define Z_IS_2625U_EQ_2625U(...) \, +#define Z_IS_2626_EQ_2626(...) \, +#define Z_IS_2626U_EQ_2626(...) \, +#define Z_IS_2626_EQ_2626U(...) \, +#define Z_IS_2626U_EQ_2626U(...) \, +#define Z_IS_2627_EQ_2627(...) \, +#define Z_IS_2627U_EQ_2627(...) \, +#define Z_IS_2627_EQ_2627U(...) \, +#define Z_IS_2627U_EQ_2627U(...) \, +#define Z_IS_2628_EQ_2628(...) \, +#define Z_IS_2628U_EQ_2628(...) \, +#define Z_IS_2628_EQ_2628U(...) \, +#define Z_IS_2628U_EQ_2628U(...) \, +#define Z_IS_2629_EQ_2629(...) \, +#define Z_IS_2629U_EQ_2629(...) \, +#define Z_IS_2629_EQ_2629U(...) \, +#define Z_IS_2629U_EQ_2629U(...) \, +#define Z_IS_2630_EQ_2630(...) \, +#define Z_IS_2630U_EQ_2630(...) \, +#define Z_IS_2630_EQ_2630U(...) \, +#define Z_IS_2630U_EQ_2630U(...) \, +#define Z_IS_2631_EQ_2631(...) \, +#define Z_IS_2631U_EQ_2631(...) \, +#define Z_IS_2631_EQ_2631U(...) \, +#define Z_IS_2631U_EQ_2631U(...) \, +#define Z_IS_2632_EQ_2632(...) \, +#define Z_IS_2632U_EQ_2632(...) \, +#define Z_IS_2632_EQ_2632U(...) \, +#define Z_IS_2632U_EQ_2632U(...) \, +#define Z_IS_2633_EQ_2633(...) \, +#define Z_IS_2633U_EQ_2633(...) \, +#define Z_IS_2633_EQ_2633U(...) \, +#define Z_IS_2633U_EQ_2633U(...) \, +#define Z_IS_2634_EQ_2634(...) \, +#define Z_IS_2634U_EQ_2634(...) \, +#define Z_IS_2634_EQ_2634U(...) \, +#define Z_IS_2634U_EQ_2634U(...) \, +#define Z_IS_2635_EQ_2635(...) \, +#define Z_IS_2635U_EQ_2635(...) \, +#define Z_IS_2635_EQ_2635U(...) \, +#define Z_IS_2635U_EQ_2635U(...) \, +#define Z_IS_2636_EQ_2636(...) \, +#define Z_IS_2636U_EQ_2636(...) \, +#define Z_IS_2636_EQ_2636U(...) \, +#define Z_IS_2636U_EQ_2636U(...) \, +#define Z_IS_2637_EQ_2637(...) \, +#define Z_IS_2637U_EQ_2637(...) \, +#define Z_IS_2637_EQ_2637U(...) \, +#define Z_IS_2637U_EQ_2637U(...) \, +#define Z_IS_2638_EQ_2638(...) \, +#define Z_IS_2638U_EQ_2638(...) \, +#define Z_IS_2638_EQ_2638U(...) \, +#define Z_IS_2638U_EQ_2638U(...) \, +#define Z_IS_2639_EQ_2639(...) \, +#define Z_IS_2639U_EQ_2639(...) \, +#define Z_IS_2639_EQ_2639U(...) \, +#define Z_IS_2639U_EQ_2639U(...) \, +#define Z_IS_2640_EQ_2640(...) \, +#define Z_IS_2640U_EQ_2640(...) \, +#define Z_IS_2640_EQ_2640U(...) \, +#define Z_IS_2640U_EQ_2640U(...) \, +#define Z_IS_2641_EQ_2641(...) \, +#define Z_IS_2641U_EQ_2641(...) \, +#define Z_IS_2641_EQ_2641U(...) \, +#define Z_IS_2641U_EQ_2641U(...) \, +#define Z_IS_2642_EQ_2642(...) \, +#define Z_IS_2642U_EQ_2642(...) \, +#define Z_IS_2642_EQ_2642U(...) \, +#define Z_IS_2642U_EQ_2642U(...) \, +#define Z_IS_2643_EQ_2643(...) \, +#define Z_IS_2643U_EQ_2643(...) \, +#define Z_IS_2643_EQ_2643U(...) \, +#define Z_IS_2643U_EQ_2643U(...) \, +#define Z_IS_2644_EQ_2644(...) \, +#define Z_IS_2644U_EQ_2644(...) \, +#define Z_IS_2644_EQ_2644U(...) \, +#define Z_IS_2644U_EQ_2644U(...) \, +#define Z_IS_2645_EQ_2645(...) \, +#define Z_IS_2645U_EQ_2645(...) \, +#define Z_IS_2645_EQ_2645U(...) \, +#define Z_IS_2645U_EQ_2645U(...) \, +#define Z_IS_2646_EQ_2646(...) \, +#define Z_IS_2646U_EQ_2646(...) \, +#define Z_IS_2646_EQ_2646U(...) \, +#define Z_IS_2646U_EQ_2646U(...) \, +#define Z_IS_2647_EQ_2647(...) \, +#define Z_IS_2647U_EQ_2647(...) \, +#define Z_IS_2647_EQ_2647U(...) \, +#define Z_IS_2647U_EQ_2647U(...) \, +#define Z_IS_2648_EQ_2648(...) \, +#define Z_IS_2648U_EQ_2648(...) \, +#define Z_IS_2648_EQ_2648U(...) \, +#define Z_IS_2648U_EQ_2648U(...) \, +#define Z_IS_2649_EQ_2649(...) \, +#define Z_IS_2649U_EQ_2649(...) \, +#define Z_IS_2649_EQ_2649U(...) \, +#define Z_IS_2649U_EQ_2649U(...) \, +#define Z_IS_2650_EQ_2650(...) \, +#define Z_IS_2650U_EQ_2650(...) \, +#define Z_IS_2650_EQ_2650U(...) \, +#define Z_IS_2650U_EQ_2650U(...) \, +#define Z_IS_2651_EQ_2651(...) \, +#define Z_IS_2651U_EQ_2651(...) \, +#define Z_IS_2651_EQ_2651U(...) \, +#define Z_IS_2651U_EQ_2651U(...) \, +#define Z_IS_2652_EQ_2652(...) \, +#define Z_IS_2652U_EQ_2652(...) \, +#define Z_IS_2652_EQ_2652U(...) \, +#define Z_IS_2652U_EQ_2652U(...) \, +#define Z_IS_2653_EQ_2653(...) \, +#define Z_IS_2653U_EQ_2653(...) \, +#define Z_IS_2653_EQ_2653U(...) \, +#define Z_IS_2653U_EQ_2653U(...) \, +#define Z_IS_2654_EQ_2654(...) \, +#define Z_IS_2654U_EQ_2654(...) \, +#define Z_IS_2654_EQ_2654U(...) \, +#define Z_IS_2654U_EQ_2654U(...) \, +#define Z_IS_2655_EQ_2655(...) \, +#define Z_IS_2655U_EQ_2655(...) \, +#define Z_IS_2655_EQ_2655U(...) \, +#define Z_IS_2655U_EQ_2655U(...) \, +#define Z_IS_2656_EQ_2656(...) \, +#define Z_IS_2656U_EQ_2656(...) \, +#define Z_IS_2656_EQ_2656U(...) \, +#define Z_IS_2656U_EQ_2656U(...) \, +#define Z_IS_2657_EQ_2657(...) \, +#define Z_IS_2657U_EQ_2657(...) \, +#define Z_IS_2657_EQ_2657U(...) \, +#define Z_IS_2657U_EQ_2657U(...) \, +#define Z_IS_2658_EQ_2658(...) \, +#define Z_IS_2658U_EQ_2658(...) \, +#define Z_IS_2658_EQ_2658U(...) \, +#define Z_IS_2658U_EQ_2658U(...) \, +#define Z_IS_2659_EQ_2659(...) \, +#define Z_IS_2659U_EQ_2659(...) \, +#define Z_IS_2659_EQ_2659U(...) \, +#define Z_IS_2659U_EQ_2659U(...) \, +#define Z_IS_2660_EQ_2660(...) \, +#define Z_IS_2660U_EQ_2660(...) \, +#define Z_IS_2660_EQ_2660U(...) \, +#define Z_IS_2660U_EQ_2660U(...) \, +#define Z_IS_2661_EQ_2661(...) \, +#define Z_IS_2661U_EQ_2661(...) \, +#define Z_IS_2661_EQ_2661U(...) \, +#define Z_IS_2661U_EQ_2661U(...) \, +#define Z_IS_2662_EQ_2662(...) \, +#define Z_IS_2662U_EQ_2662(...) \, +#define Z_IS_2662_EQ_2662U(...) \, +#define Z_IS_2662U_EQ_2662U(...) \, +#define Z_IS_2663_EQ_2663(...) \, +#define Z_IS_2663U_EQ_2663(...) \, +#define Z_IS_2663_EQ_2663U(...) \, +#define Z_IS_2663U_EQ_2663U(...) \, +#define Z_IS_2664_EQ_2664(...) \, +#define Z_IS_2664U_EQ_2664(...) \, +#define Z_IS_2664_EQ_2664U(...) \, +#define Z_IS_2664U_EQ_2664U(...) \, +#define Z_IS_2665_EQ_2665(...) \, +#define Z_IS_2665U_EQ_2665(...) \, +#define Z_IS_2665_EQ_2665U(...) \, +#define Z_IS_2665U_EQ_2665U(...) \, +#define Z_IS_2666_EQ_2666(...) \, +#define Z_IS_2666U_EQ_2666(...) \, +#define Z_IS_2666_EQ_2666U(...) \, +#define Z_IS_2666U_EQ_2666U(...) \, +#define Z_IS_2667_EQ_2667(...) \, +#define Z_IS_2667U_EQ_2667(...) \, +#define Z_IS_2667_EQ_2667U(...) \, +#define Z_IS_2667U_EQ_2667U(...) \, +#define Z_IS_2668_EQ_2668(...) \, +#define Z_IS_2668U_EQ_2668(...) \, +#define Z_IS_2668_EQ_2668U(...) \, +#define Z_IS_2668U_EQ_2668U(...) \, +#define Z_IS_2669_EQ_2669(...) \, +#define Z_IS_2669U_EQ_2669(...) \, +#define Z_IS_2669_EQ_2669U(...) \, +#define Z_IS_2669U_EQ_2669U(...) \, +#define Z_IS_2670_EQ_2670(...) \, +#define Z_IS_2670U_EQ_2670(...) \, +#define Z_IS_2670_EQ_2670U(...) \, +#define Z_IS_2670U_EQ_2670U(...) \, +#define Z_IS_2671_EQ_2671(...) \, +#define Z_IS_2671U_EQ_2671(...) \, +#define Z_IS_2671_EQ_2671U(...) \, +#define Z_IS_2671U_EQ_2671U(...) \, +#define Z_IS_2672_EQ_2672(...) \, +#define Z_IS_2672U_EQ_2672(...) \, +#define Z_IS_2672_EQ_2672U(...) \, +#define Z_IS_2672U_EQ_2672U(...) \, +#define Z_IS_2673_EQ_2673(...) \, +#define Z_IS_2673U_EQ_2673(...) \, +#define Z_IS_2673_EQ_2673U(...) \, +#define Z_IS_2673U_EQ_2673U(...) \, +#define Z_IS_2674_EQ_2674(...) \, +#define Z_IS_2674U_EQ_2674(...) \, +#define Z_IS_2674_EQ_2674U(...) \, +#define Z_IS_2674U_EQ_2674U(...) \, +#define Z_IS_2675_EQ_2675(...) \, +#define Z_IS_2675U_EQ_2675(...) \, +#define Z_IS_2675_EQ_2675U(...) \, +#define Z_IS_2675U_EQ_2675U(...) \, +#define Z_IS_2676_EQ_2676(...) \, +#define Z_IS_2676U_EQ_2676(...) \, +#define Z_IS_2676_EQ_2676U(...) \, +#define Z_IS_2676U_EQ_2676U(...) \, +#define Z_IS_2677_EQ_2677(...) \, +#define Z_IS_2677U_EQ_2677(...) \, +#define Z_IS_2677_EQ_2677U(...) \, +#define Z_IS_2677U_EQ_2677U(...) \, +#define Z_IS_2678_EQ_2678(...) \, +#define Z_IS_2678U_EQ_2678(...) \, +#define Z_IS_2678_EQ_2678U(...) \, +#define Z_IS_2678U_EQ_2678U(...) \, +#define Z_IS_2679_EQ_2679(...) \, +#define Z_IS_2679U_EQ_2679(...) \, +#define Z_IS_2679_EQ_2679U(...) \, +#define Z_IS_2679U_EQ_2679U(...) \, +#define Z_IS_2680_EQ_2680(...) \, +#define Z_IS_2680U_EQ_2680(...) \, +#define Z_IS_2680_EQ_2680U(...) \, +#define Z_IS_2680U_EQ_2680U(...) \, +#define Z_IS_2681_EQ_2681(...) \, +#define Z_IS_2681U_EQ_2681(...) \, +#define Z_IS_2681_EQ_2681U(...) \, +#define Z_IS_2681U_EQ_2681U(...) \, +#define Z_IS_2682_EQ_2682(...) \, +#define Z_IS_2682U_EQ_2682(...) \, +#define Z_IS_2682_EQ_2682U(...) \, +#define Z_IS_2682U_EQ_2682U(...) \, +#define Z_IS_2683_EQ_2683(...) \, +#define Z_IS_2683U_EQ_2683(...) \, +#define Z_IS_2683_EQ_2683U(...) \, +#define Z_IS_2683U_EQ_2683U(...) \, +#define Z_IS_2684_EQ_2684(...) \, +#define Z_IS_2684U_EQ_2684(...) \, +#define Z_IS_2684_EQ_2684U(...) \, +#define Z_IS_2684U_EQ_2684U(...) \, +#define Z_IS_2685_EQ_2685(...) \, +#define Z_IS_2685U_EQ_2685(...) \, +#define Z_IS_2685_EQ_2685U(...) \, +#define Z_IS_2685U_EQ_2685U(...) \, +#define Z_IS_2686_EQ_2686(...) \, +#define Z_IS_2686U_EQ_2686(...) \, +#define Z_IS_2686_EQ_2686U(...) \, +#define Z_IS_2686U_EQ_2686U(...) \, +#define Z_IS_2687_EQ_2687(...) \, +#define Z_IS_2687U_EQ_2687(...) \, +#define Z_IS_2687_EQ_2687U(...) \, +#define Z_IS_2687U_EQ_2687U(...) \, +#define Z_IS_2688_EQ_2688(...) \, +#define Z_IS_2688U_EQ_2688(...) \, +#define Z_IS_2688_EQ_2688U(...) \, +#define Z_IS_2688U_EQ_2688U(...) \, +#define Z_IS_2689_EQ_2689(...) \, +#define Z_IS_2689U_EQ_2689(...) \, +#define Z_IS_2689_EQ_2689U(...) \, +#define Z_IS_2689U_EQ_2689U(...) \, +#define Z_IS_2690_EQ_2690(...) \, +#define Z_IS_2690U_EQ_2690(...) \, +#define Z_IS_2690_EQ_2690U(...) \, +#define Z_IS_2690U_EQ_2690U(...) \, +#define Z_IS_2691_EQ_2691(...) \, +#define Z_IS_2691U_EQ_2691(...) \, +#define Z_IS_2691_EQ_2691U(...) \, +#define Z_IS_2691U_EQ_2691U(...) \, +#define Z_IS_2692_EQ_2692(...) \, +#define Z_IS_2692U_EQ_2692(...) \, +#define Z_IS_2692_EQ_2692U(...) \, +#define Z_IS_2692U_EQ_2692U(...) \, +#define Z_IS_2693_EQ_2693(...) \, +#define Z_IS_2693U_EQ_2693(...) \, +#define Z_IS_2693_EQ_2693U(...) \, +#define Z_IS_2693U_EQ_2693U(...) \, +#define Z_IS_2694_EQ_2694(...) \, +#define Z_IS_2694U_EQ_2694(...) \, +#define Z_IS_2694_EQ_2694U(...) \, +#define Z_IS_2694U_EQ_2694U(...) \, +#define Z_IS_2695_EQ_2695(...) \, +#define Z_IS_2695U_EQ_2695(...) \, +#define Z_IS_2695_EQ_2695U(...) \, +#define Z_IS_2695U_EQ_2695U(...) \, +#define Z_IS_2696_EQ_2696(...) \, +#define Z_IS_2696U_EQ_2696(...) \, +#define Z_IS_2696_EQ_2696U(...) \, +#define Z_IS_2696U_EQ_2696U(...) \, +#define Z_IS_2697_EQ_2697(...) \, +#define Z_IS_2697U_EQ_2697(...) \, +#define Z_IS_2697_EQ_2697U(...) \, +#define Z_IS_2697U_EQ_2697U(...) \, +#define Z_IS_2698_EQ_2698(...) \, +#define Z_IS_2698U_EQ_2698(...) \, +#define Z_IS_2698_EQ_2698U(...) \, +#define Z_IS_2698U_EQ_2698U(...) \, +#define Z_IS_2699_EQ_2699(...) \, +#define Z_IS_2699U_EQ_2699(...) \, +#define Z_IS_2699_EQ_2699U(...) \, +#define Z_IS_2699U_EQ_2699U(...) \, +#define Z_IS_2700_EQ_2700(...) \, +#define Z_IS_2700U_EQ_2700(...) \, +#define Z_IS_2700_EQ_2700U(...) \, +#define Z_IS_2700U_EQ_2700U(...) \, +#define Z_IS_2701_EQ_2701(...) \, +#define Z_IS_2701U_EQ_2701(...) \, +#define Z_IS_2701_EQ_2701U(...) \, +#define Z_IS_2701U_EQ_2701U(...) \, +#define Z_IS_2702_EQ_2702(...) \, +#define Z_IS_2702U_EQ_2702(...) \, +#define Z_IS_2702_EQ_2702U(...) \, +#define Z_IS_2702U_EQ_2702U(...) \, +#define Z_IS_2703_EQ_2703(...) \, +#define Z_IS_2703U_EQ_2703(...) \, +#define Z_IS_2703_EQ_2703U(...) \, +#define Z_IS_2703U_EQ_2703U(...) \, +#define Z_IS_2704_EQ_2704(...) \, +#define Z_IS_2704U_EQ_2704(...) \, +#define Z_IS_2704_EQ_2704U(...) \, +#define Z_IS_2704U_EQ_2704U(...) \, +#define Z_IS_2705_EQ_2705(...) \, +#define Z_IS_2705U_EQ_2705(...) \, +#define Z_IS_2705_EQ_2705U(...) \, +#define Z_IS_2705U_EQ_2705U(...) \, +#define Z_IS_2706_EQ_2706(...) \, +#define Z_IS_2706U_EQ_2706(...) \, +#define Z_IS_2706_EQ_2706U(...) \, +#define Z_IS_2706U_EQ_2706U(...) \, +#define Z_IS_2707_EQ_2707(...) \, +#define Z_IS_2707U_EQ_2707(...) \, +#define Z_IS_2707_EQ_2707U(...) \, +#define Z_IS_2707U_EQ_2707U(...) \, +#define Z_IS_2708_EQ_2708(...) \, +#define Z_IS_2708U_EQ_2708(...) \, +#define Z_IS_2708_EQ_2708U(...) \, +#define Z_IS_2708U_EQ_2708U(...) \, +#define Z_IS_2709_EQ_2709(...) \, +#define Z_IS_2709U_EQ_2709(...) \, +#define Z_IS_2709_EQ_2709U(...) \, +#define Z_IS_2709U_EQ_2709U(...) \, +#define Z_IS_2710_EQ_2710(...) \, +#define Z_IS_2710U_EQ_2710(...) \, +#define Z_IS_2710_EQ_2710U(...) \, +#define Z_IS_2710U_EQ_2710U(...) \, +#define Z_IS_2711_EQ_2711(...) \, +#define Z_IS_2711U_EQ_2711(...) \, +#define Z_IS_2711_EQ_2711U(...) \, +#define Z_IS_2711U_EQ_2711U(...) \, +#define Z_IS_2712_EQ_2712(...) \, +#define Z_IS_2712U_EQ_2712(...) \, +#define Z_IS_2712_EQ_2712U(...) \, +#define Z_IS_2712U_EQ_2712U(...) \, +#define Z_IS_2713_EQ_2713(...) \, +#define Z_IS_2713U_EQ_2713(...) \, +#define Z_IS_2713_EQ_2713U(...) \, +#define Z_IS_2713U_EQ_2713U(...) \, +#define Z_IS_2714_EQ_2714(...) \, +#define Z_IS_2714U_EQ_2714(...) \, +#define Z_IS_2714_EQ_2714U(...) \, +#define Z_IS_2714U_EQ_2714U(...) \, +#define Z_IS_2715_EQ_2715(...) \, +#define Z_IS_2715U_EQ_2715(...) \, +#define Z_IS_2715_EQ_2715U(...) \, +#define Z_IS_2715U_EQ_2715U(...) \, +#define Z_IS_2716_EQ_2716(...) \, +#define Z_IS_2716U_EQ_2716(...) \, +#define Z_IS_2716_EQ_2716U(...) \, +#define Z_IS_2716U_EQ_2716U(...) \, +#define Z_IS_2717_EQ_2717(...) \, +#define Z_IS_2717U_EQ_2717(...) \, +#define Z_IS_2717_EQ_2717U(...) \, +#define Z_IS_2717U_EQ_2717U(...) \, +#define Z_IS_2718_EQ_2718(...) \, +#define Z_IS_2718U_EQ_2718(...) \, +#define Z_IS_2718_EQ_2718U(...) \, +#define Z_IS_2718U_EQ_2718U(...) \, +#define Z_IS_2719_EQ_2719(...) \, +#define Z_IS_2719U_EQ_2719(...) \, +#define Z_IS_2719_EQ_2719U(...) \, +#define Z_IS_2719U_EQ_2719U(...) \, +#define Z_IS_2720_EQ_2720(...) \, +#define Z_IS_2720U_EQ_2720(...) \, +#define Z_IS_2720_EQ_2720U(...) \, +#define Z_IS_2720U_EQ_2720U(...) \, +#define Z_IS_2721_EQ_2721(...) \, +#define Z_IS_2721U_EQ_2721(...) \, +#define Z_IS_2721_EQ_2721U(...) \, +#define Z_IS_2721U_EQ_2721U(...) \, +#define Z_IS_2722_EQ_2722(...) \, +#define Z_IS_2722U_EQ_2722(...) \, +#define Z_IS_2722_EQ_2722U(...) \, +#define Z_IS_2722U_EQ_2722U(...) \, +#define Z_IS_2723_EQ_2723(...) \, +#define Z_IS_2723U_EQ_2723(...) \, +#define Z_IS_2723_EQ_2723U(...) \, +#define Z_IS_2723U_EQ_2723U(...) \, +#define Z_IS_2724_EQ_2724(...) \, +#define Z_IS_2724U_EQ_2724(...) \, +#define Z_IS_2724_EQ_2724U(...) \, +#define Z_IS_2724U_EQ_2724U(...) \, +#define Z_IS_2725_EQ_2725(...) \, +#define Z_IS_2725U_EQ_2725(...) \, +#define Z_IS_2725_EQ_2725U(...) \, +#define Z_IS_2725U_EQ_2725U(...) \, +#define Z_IS_2726_EQ_2726(...) \, +#define Z_IS_2726U_EQ_2726(...) \, +#define Z_IS_2726_EQ_2726U(...) \, +#define Z_IS_2726U_EQ_2726U(...) \, +#define Z_IS_2727_EQ_2727(...) \, +#define Z_IS_2727U_EQ_2727(...) \, +#define Z_IS_2727_EQ_2727U(...) \, +#define Z_IS_2727U_EQ_2727U(...) \, +#define Z_IS_2728_EQ_2728(...) \, +#define Z_IS_2728U_EQ_2728(...) \, +#define Z_IS_2728_EQ_2728U(...) \, +#define Z_IS_2728U_EQ_2728U(...) \, +#define Z_IS_2729_EQ_2729(...) \, +#define Z_IS_2729U_EQ_2729(...) \, +#define Z_IS_2729_EQ_2729U(...) \, +#define Z_IS_2729U_EQ_2729U(...) \, +#define Z_IS_2730_EQ_2730(...) \, +#define Z_IS_2730U_EQ_2730(...) \, +#define Z_IS_2730_EQ_2730U(...) \, +#define Z_IS_2730U_EQ_2730U(...) \, +#define Z_IS_2731_EQ_2731(...) \, +#define Z_IS_2731U_EQ_2731(...) \, +#define Z_IS_2731_EQ_2731U(...) \, +#define Z_IS_2731U_EQ_2731U(...) \, +#define Z_IS_2732_EQ_2732(...) \, +#define Z_IS_2732U_EQ_2732(...) \, +#define Z_IS_2732_EQ_2732U(...) \, +#define Z_IS_2732U_EQ_2732U(...) \, +#define Z_IS_2733_EQ_2733(...) \, +#define Z_IS_2733U_EQ_2733(...) \, +#define Z_IS_2733_EQ_2733U(...) \, +#define Z_IS_2733U_EQ_2733U(...) \, +#define Z_IS_2734_EQ_2734(...) \, +#define Z_IS_2734U_EQ_2734(...) \, +#define Z_IS_2734_EQ_2734U(...) \, +#define Z_IS_2734U_EQ_2734U(...) \, +#define Z_IS_2735_EQ_2735(...) \, +#define Z_IS_2735U_EQ_2735(...) \, +#define Z_IS_2735_EQ_2735U(...) \, +#define Z_IS_2735U_EQ_2735U(...) \, +#define Z_IS_2736_EQ_2736(...) \, +#define Z_IS_2736U_EQ_2736(...) \, +#define Z_IS_2736_EQ_2736U(...) \, +#define Z_IS_2736U_EQ_2736U(...) \, +#define Z_IS_2737_EQ_2737(...) \, +#define Z_IS_2737U_EQ_2737(...) \, +#define Z_IS_2737_EQ_2737U(...) \, +#define Z_IS_2737U_EQ_2737U(...) \, +#define Z_IS_2738_EQ_2738(...) \, +#define Z_IS_2738U_EQ_2738(...) \, +#define Z_IS_2738_EQ_2738U(...) \, +#define Z_IS_2738U_EQ_2738U(...) \, +#define Z_IS_2739_EQ_2739(...) \, +#define Z_IS_2739U_EQ_2739(...) \, +#define Z_IS_2739_EQ_2739U(...) \, +#define Z_IS_2739U_EQ_2739U(...) \, +#define Z_IS_2740_EQ_2740(...) \, +#define Z_IS_2740U_EQ_2740(...) \, +#define Z_IS_2740_EQ_2740U(...) \, +#define Z_IS_2740U_EQ_2740U(...) \, +#define Z_IS_2741_EQ_2741(...) \, +#define Z_IS_2741U_EQ_2741(...) \, +#define Z_IS_2741_EQ_2741U(...) \, +#define Z_IS_2741U_EQ_2741U(...) \, +#define Z_IS_2742_EQ_2742(...) \, +#define Z_IS_2742U_EQ_2742(...) \, +#define Z_IS_2742_EQ_2742U(...) \, +#define Z_IS_2742U_EQ_2742U(...) \, +#define Z_IS_2743_EQ_2743(...) \, +#define Z_IS_2743U_EQ_2743(...) \, +#define Z_IS_2743_EQ_2743U(...) \, +#define Z_IS_2743U_EQ_2743U(...) \, +#define Z_IS_2744_EQ_2744(...) \, +#define Z_IS_2744U_EQ_2744(...) \, +#define Z_IS_2744_EQ_2744U(...) \, +#define Z_IS_2744U_EQ_2744U(...) \, +#define Z_IS_2745_EQ_2745(...) \, +#define Z_IS_2745U_EQ_2745(...) \, +#define Z_IS_2745_EQ_2745U(...) \, +#define Z_IS_2745U_EQ_2745U(...) \, +#define Z_IS_2746_EQ_2746(...) \, +#define Z_IS_2746U_EQ_2746(...) \, +#define Z_IS_2746_EQ_2746U(...) \, +#define Z_IS_2746U_EQ_2746U(...) \, +#define Z_IS_2747_EQ_2747(...) \, +#define Z_IS_2747U_EQ_2747(...) \, +#define Z_IS_2747_EQ_2747U(...) \, +#define Z_IS_2747U_EQ_2747U(...) \, +#define Z_IS_2748_EQ_2748(...) \, +#define Z_IS_2748U_EQ_2748(...) \, +#define Z_IS_2748_EQ_2748U(...) \, +#define Z_IS_2748U_EQ_2748U(...) \, +#define Z_IS_2749_EQ_2749(...) \, +#define Z_IS_2749U_EQ_2749(...) \, +#define Z_IS_2749_EQ_2749U(...) \, +#define Z_IS_2749U_EQ_2749U(...) \, +#define Z_IS_2750_EQ_2750(...) \, +#define Z_IS_2750U_EQ_2750(...) \, +#define Z_IS_2750_EQ_2750U(...) \, +#define Z_IS_2750U_EQ_2750U(...) \, +#define Z_IS_2751_EQ_2751(...) \, +#define Z_IS_2751U_EQ_2751(...) \, +#define Z_IS_2751_EQ_2751U(...) \, +#define Z_IS_2751U_EQ_2751U(...) \, +#define Z_IS_2752_EQ_2752(...) \, +#define Z_IS_2752U_EQ_2752(...) \, +#define Z_IS_2752_EQ_2752U(...) \, +#define Z_IS_2752U_EQ_2752U(...) \, +#define Z_IS_2753_EQ_2753(...) \, +#define Z_IS_2753U_EQ_2753(...) \, +#define Z_IS_2753_EQ_2753U(...) \, +#define Z_IS_2753U_EQ_2753U(...) \, +#define Z_IS_2754_EQ_2754(...) \, +#define Z_IS_2754U_EQ_2754(...) \, +#define Z_IS_2754_EQ_2754U(...) \, +#define Z_IS_2754U_EQ_2754U(...) \, +#define Z_IS_2755_EQ_2755(...) \, +#define Z_IS_2755U_EQ_2755(...) \, +#define Z_IS_2755_EQ_2755U(...) \, +#define Z_IS_2755U_EQ_2755U(...) \, +#define Z_IS_2756_EQ_2756(...) \, +#define Z_IS_2756U_EQ_2756(...) \, +#define Z_IS_2756_EQ_2756U(...) \, +#define Z_IS_2756U_EQ_2756U(...) \, +#define Z_IS_2757_EQ_2757(...) \, +#define Z_IS_2757U_EQ_2757(...) \, +#define Z_IS_2757_EQ_2757U(...) \, +#define Z_IS_2757U_EQ_2757U(...) \, +#define Z_IS_2758_EQ_2758(...) \, +#define Z_IS_2758U_EQ_2758(...) \, +#define Z_IS_2758_EQ_2758U(...) \, +#define Z_IS_2758U_EQ_2758U(...) \, +#define Z_IS_2759_EQ_2759(...) \, +#define Z_IS_2759U_EQ_2759(...) \, +#define Z_IS_2759_EQ_2759U(...) \, +#define Z_IS_2759U_EQ_2759U(...) \, +#define Z_IS_2760_EQ_2760(...) \, +#define Z_IS_2760U_EQ_2760(...) \, +#define Z_IS_2760_EQ_2760U(...) \, +#define Z_IS_2760U_EQ_2760U(...) \, +#define Z_IS_2761_EQ_2761(...) \, +#define Z_IS_2761U_EQ_2761(...) \, +#define Z_IS_2761_EQ_2761U(...) \, +#define Z_IS_2761U_EQ_2761U(...) \, +#define Z_IS_2762_EQ_2762(...) \, +#define Z_IS_2762U_EQ_2762(...) \, +#define Z_IS_2762_EQ_2762U(...) \, +#define Z_IS_2762U_EQ_2762U(...) \, +#define Z_IS_2763_EQ_2763(...) \, +#define Z_IS_2763U_EQ_2763(...) \, +#define Z_IS_2763_EQ_2763U(...) \, +#define Z_IS_2763U_EQ_2763U(...) \, +#define Z_IS_2764_EQ_2764(...) \, +#define Z_IS_2764U_EQ_2764(...) \, +#define Z_IS_2764_EQ_2764U(...) \, +#define Z_IS_2764U_EQ_2764U(...) \, +#define Z_IS_2765_EQ_2765(...) \, +#define Z_IS_2765U_EQ_2765(...) \, +#define Z_IS_2765_EQ_2765U(...) \, +#define Z_IS_2765U_EQ_2765U(...) \, +#define Z_IS_2766_EQ_2766(...) \, +#define Z_IS_2766U_EQ_2766(...) \, +#define Z_IS_2766_EQ_2766U(...) \, +#define Z_IS_2766U_EQ_2766U(...) \, +#define Z_IS_2767_EQ_2767(...) \, +#define Z_IS_2767U_EQ_2767(...) \, +#define Z_IS_2767_EQ_2767U(...) \, +#define Z_IS_2767U_EQ_2767U(...) \, +#define Z_IS_2768_EQ_2768(...) \, +#define Z_IS_2768U_EQ_2768(...) \, +#define Z_IS_2768_EQ_2768U(...) \, +#define Z_IS_2768U_EQ_2768U(...) \, +#define Z_IS_2769_EQ_2769(...) \, +#define Z_IS_2769U_EQ_2769(...) \, +#define Z_IS_2769_EQ_2769U(...) \, +#define Z_IS_2769U_EQ_2769U(...) \, +#define Z_IS_2770_EQ_2770(...) \, +#define Z_IS_2770U_EQ_2770(...) \, +#define Z_IS_2770_EQ_2770U(...) \, +#define Z_IS_2770U_EQ_2770U(...) \, +#define Z_IS_2771_EQ_2771(...) \, +#define Z_IS_2771U_EQ_2771(...) \, +#define Z_IS_2771_EQ_2771U(...) \, +#define Z_IS_2771U_EQ_2771U(...) \, +#define Z_IS_2772_EQ_2772(...) \, +#define Z_IS_2772U_EQ_2772(...) \, +#define Z_IS_2772_EQ_2772U(...) \, +#define Z_IS_2772U_EQ_2772U(...) \, +#define Z_IS_2773_EQ_2773(...) \, +#define Z_IS_2773U_EQ_2773(...) \, +#define Z_IS_2773_EQ_2773U(...) \, +#define Z_IS_2773U_EQ_2773U(...) \, +#define Z_IS_2774_EQ_2774(...) \, +#define Z_IS_2774U_EQ_2774(...) \, +#define Z_IS_2774_EQ_2774U(...) \, +#define Z_IS_2774U_EQ_2774U(...) \, +#define Z_IS_2775_EQ_2775(...) \, +#define Z_IS_2775U_EQ_2775(...) \, +#define Z_IS_2775_EQ_2775U(...) \, +#define Z_IS_2775U_EQ_2775U(...) \, +#define Z_IS_2776_EQ_2776(...) \, +#define Z_IS_2776U_EQ_2776(...) \, +#define Z_IS_2776_EQ_2776U(...) \, +#define Z_IS_2776U_EQ_2776U(...) \, +#define Z_IS_2777_EQ_2777(...) \, +#define Z_IS_2777U_EQ_2777(...) \, +#define Z_IS_2777_EQ_2777U(...) \, +#define Z_IS_2777U_EQ_2777U(...) \, +#define Z_IS_2778_EQ_2778(...) \, +#define Z_IS_2778U_EQ_2778(...) \, +#define Z_IS_2778_EQ_2778U(...) \, +#define Z_IS_2778U_EQ_2778U(...) \, +#define Z_IS_2779_EQ_2779(...) \, +#define Z_IS_2779U_EQ_2779(...) \, +#define Z_IS_2779_EQ_2779U(...) \, +#define Z_IS_2779U_EQ_2779U(...) \, +#define Z_IS_2780_EQ_2780(...) \, +#define Z_IS_2780U_EQ_2780(...) \, +#define Z_IS_2780_EQ_2780U(...) \, +#define Z_IS_2780U_EQ_2780U(...) \, +#define Z_IS_2781_EQ_2781(...) \, +#define Z_IS_2781U_EQ_2781(...) \, +#define Z_IS_2781_EQ_2781U(...) \, +#define Z_IS_2781U_EQ_2781U(...) \, +#define Z_IS_2782_EQ_2782(...) \, +#define Z_IS_2782U_EQ_2782(...) \, +#define Z_IS_2782_EQ_2782U(...) \, +#define Z_IS_2782U_EQ_2782U(...) \, +#define Z_IS_2783_EQ_2783(...) \, +#define Z_IS_2783U_EQ_2783(...) \, +#define Z_IS_2783_EQ_2783U(...) \, +#define Z_IS_2783U_EQ_2783U(...) \, +#define Z_IS_2784_EQ_2784(...) \, +#define Z_IS_2784U_EQ_2784(...) \, +#define Z_IS_2784_EQ_2784U(...) \, +#define Z_IS_2784U_EQ_2784U(...) \, +#define Z_IS_2785_EQ_2785(...) \, +#define Z_IS_2785U_EQ_2785(...) \, +#define Z_IS_2785_EQ_2785U(...) \, +#define Z_IS_2785U_EQ_2785U(...) \, +#define Z_IS_2786_EQ_2786(...) \, +#define Z_IS_2786U_EQ_2786(...) \, +#define Z_IS_2786_EQ_2786U(...) \, +#define Z_IS_2786U_EQ_2786U(...) \, +#define Z_IS_2787_EQ_2787(...) \, +#define Z_IS_2787U_EQ_2787(...) \, +#define Z_IS_2787_EQ_2787U(...) \, +#define Z_IS_2787U_EQ_2787U(...) \, +#define Z_IS_2788_EQ_2788(...) \, +#define Z_IS_2788U_EQ_2788(...) \, +#define Z_IS_2788_EQ_2788U(...) \, +#define Z_IS_2788U_EQ_2788U(...) \, +#define Z_IS_2789_EQ_2789(...) \, +#define Z_IS_2789U_EQ_2789(...) \, +#define Z_IS_2789_EQ_2789U(...) \, +#define Z_IS_2789U_EQ_2789U(...) \, +#define Z_IS_2790_EQ_2790(...) \, +#define Z_IS_2790U_EQ_2790(...) \, +#define Z_IS_2790_EQ_2790U(...) \, +#define Z_IS_2790U_EQ_2790U(...) \, +#define Z_IS_2791_EQ_2791(...) \, +#define Z_IS_2791U_EQ_2791(...) \, +#define Z_IS_2791_EQ_2791U(...) \, +#define Z_IS_2791U_EQ_2791U(...) \, +#define Z_IS_2792_EQ_2792(...) \, +#define Z_IS_2792U_EQ_2792(...) \, +#define Z_IS_2792_EQ_2792U(...) \, +#define Z_IS_2792U_EQ_2792U(...) \, +#define Z_IS_2793_EQ_2793(...) \, +#define Z_IS_2793U_EQ_2793(...) \, +#define Z_IS_2793_EQ_2793U(...) \, +#define Z_IS_2793U_EQ_2793U(...) \, +#define Z_IS_2794_EQ_2794(...) \, +#define Z_IS_2794U_EQ_2794(...) \, +#define Z_IS_2794_EQ_2794U(...) \, +#define Z_IS_2794U_EQ_2794U(...) \, +#define Z_IS_2795_EQ_2795(...) \, +#define Z_IS_2795U_EQ_2795(...) \, +#define Z_IS_2795_EQ_2795U(...) \, +#define Z_IS_2795U_EQ_2795U(...) \, +#define Z_IS_2796_EQ_2796(...) \, +#define Z_IS_2796U_EQ_2796(...) \, +#define Z_IS_2796_EQ_2796U(...) \, +#define Z_IS_2796U_EQ_2796U(...) \, +#define Z_IS_2797_EQ_2797(...) \, +#define Z_IS_2797U_EQ_2797(...) \, +#define Z_IS_2797_EQ_2797U(...) \, +#define Z_IS_2797U_EQ_2797U(...) \, +#define Z_IS_2798_EQ_2798(...) \, +#define Z_IS_2798U_EQ_2798(...) \, +#define Z_IS_2798_EQ_2798U(...) \, +#define Z_IS_2798U_EQ_2798U(...) \, +#define Z_IS_2799_EQ_2799(...) \, +#define Z_IS_2799U_EQ_2799(...) \, +#define Z_IS_2799_EQ_2799U(...) \, +#define Z_IS_2799U_EQ_2799U(...) \, +#define Z_IS_2800_EQ_2800(...) \, +#define Z_IS_2800U_EQ_2800(...) \, +#define Z_IS_2800_EQ_2800U(...) \, +#define Z_IS_2800U_EQ_2800U(...) \, +#define Z_IS_2801_EQ_2801(...) \, +#define Z_IS_2801U_EQ_2801(...) \, +#define Z_IS_2801_EQ_2801U(...) \, +#define Z_IS_2801U_EQ_2801U(...) \, +#define Z_IS_2802_EQ_2802(...) \, +#define Z_IS_2802U_EQ_2802(...) \, +#define Z_IS_2802_EQ_2802U(...) \, +#define Z_IS_2802U_EQ_2802U(...) \, +#define Z_IS_2803_EQ_2803(...) \, +#define Z_IS_2803U_EQ_2803(...) \, +#define Z_IS_2803_EQ_2803U(...) \, +#define Z_IS_2803U_EQ_2803U(...) \, +#define Z_IS_2804_EQ_2804(...) \, +#define Z_IS_2804U_EQ_2804(...) \, +#define Z_IS_2804_EQ_2804U(...) \, +#define Z_IS_2804U_EQ_2804U(...) \, +#define Z_IS_2805_EQ_2805(...) \, +#define Z_IS_2805U_EQ_2805(...) \, +#define Z_IS_2805_EQ_2805U(...) \, +#define Z_IS_2805U_EQ_2805U(...) \, +#define Z_IS_2806_EQ_2806(...) \, +#define Z_IS_2806U_EQ_2806(...) \, +#define Z_IS_2806_EQ_2806U(...) \, +#define Z_IS_2806U_EQ_2806U(...) \, +#define Z_IS_2807_EQ_2807(...) \, +#define Z_IS_2807U_EQ_2807(...) \, +#define Z_IS_2807_EQ_2807U(...) \, +#define Z_IS_2807U_EQ_2807U(...) \, +#define Z_IS_2808_EQ_2808(...) \, +#define Z_IS_2808U_EQ_2808(...) \, +#define Z_IS_2808_EQ_2808U(...) \, +#define Z_IS_2808U_EQ_2808U(...) \, +#define Z_IS_2809_EQ_2809(...) \, +#define Z_IS_2809U_EQ_2809(...) \, +#define Z_IS_2809_EQ_2809U(...) \, +#define Z_IS_2809U_EQ_2809U(...) \, +#define Z_IS_2810_EQ_2810(...) \, +#define Z_IS_2810U_EQ_2810(...) \, +#define Z_IS_2810_EQ_2810U(...) \, +#define Z_IS_2810U_EQ_2810U(...) \, +#define Z_IS_2811_EQ_2811(...) \, +#define Z_IS_2811U_EQ_2811(...) \, +#define Z_IS_2811_EQ_2811U(...) \, +#define Z_IS_2811U_EQ_2811U(...) \, +#define Z_IS_2812_EQ_2812(...) \, +#define Z_IS_2812U_EQ_2812(...) \, +#define Z_IS_2812_EQ_2812U(...) \, +#define Z_IS_2812U_EQ_2812U(...) \, +#define Z_IS_2813_EQ_2813(...) \, +#define Z_IS_2813U_EQ_2813(...) \, +#define Z_IS_2813_EQ_2813U(...) \, +#define Z_IS_2813U_EQ_2813U(...) \, +#define Z_IS_2814_EQ_2814(...) \, +#define Z_IS_2814U_EQ_2814(...) \, +#define Z_IS_2814_EQ_2814U(...) \, +#define Z_IS_2814U_EQ_2814U(...) \, +#define Z_IS_2815_EQ_2815(...) \, +#define Z_IS_2815U_EQ_2815(...) \, +#define Z_IS_2815_EQ_2815U(...) \, +#define Z_IS_2815U_EQ_2815U(...) \, +#define Z_IS_2816_EQ_2816(...) \, +#define Z_IS_2816U_EQ_2816(...) \, +#define Z_IS_2816_EQ_2816U(...) \, +#define Z_IS_2816U_EQ_2816U(...) \, +#define Z_IS_2817_EQ_2817(...) \, +#define Z_IS_2817U_EQ_2817(...) \, +#define Z_IS_2817_EQ_2817U(...) \, +#define Z_IS_2817U_EQ_2817U(...) \, +#define Z_IS_2818_EQ_2818(...) \, +#define Z_IS_2818U_EQ_2818(...) \, +#define Z_IS_2818_EQ_2818U(...) \, +#define Z_IS_2818U_EQ_2818U(...) \, +#define Z_IS_2819_EQ_2819(...) \, +#define Z_IS_2819U_EQ_2819(...) \, +#define Z_IS_2819_EQ_2819U(...) \, +#define Z_IS_2819U_EQ_2819U(...) \, +#define Z_IS_2820_EQ_2820(...) \, +#define Z_IS_2820U_EQ_2820(...) \, +#define Z_IS_2820_EQ_2820U(...) \, +#define Z_IS_2820U_EQ_2820U(...) \, +#define Z_IS_2821_EQ_2821(...) \, +#define Z_IS_2821U_EQ_2821(...) \, +#define Z_IS_2821_EQ_2821U(...) \, +#define Z_IS_2821U_EQ_2821U(...) \, +#define Z_IS_2822_EQ_2822(...) \, +#define Z_IS_2822U_EQ_2822(...) \, +#define Z_IS_2822_EQ_2822U(...) \, +#define Z_IS_2822U_EQ_2822U(...) \, +#define Z_IS_2823_EQ_2823(...) \, +#define Z_IS_2823U_EQ_2823(...) \, +#define Z_IS_2823_EQ_2823U(...) \, +#define Z_IS_2823U_EQ_2823U(...) \, +#define Z_IS_2824_EQ_2824(...) \, +#define Z_IS_2824U_EQ_2824(...) \, +#define Z_IS_2824_EQ_2824U(...) \, +#define Z_IS_2824U_EQ_2824U(...) \, +#define Z_IS_2825_EQ_2825(...) \, +#define Z_IS_2825U_EQ_2825(...) \, +#define Z_IS_2825_EQ_2825U(...) \, +#define Z_IS_2825U_EQ_2825U(...) \, +#define Z_IS_2826_EQ_2826(...) \, +#define Z_IS_2826U_EQ_2826(...) \, +#define Z_IS_2826_EQ_2826U(...) \, +#define Z_IS_2826U_EQ_2826U(...) \, +#define Z_IS_2827_EQ_2827(...) \, +#define Z_IS_2827U_EQ_2827(...) \, +#define Z_IS_2827_EQ_2827U(...) \, +#define Z_IS_2827U_EQ_2827U(...) \, +#define Z_IS_2828_EQ_2828(...) \, +#define Z_IS_2828U_EQ_2828(...) \, +#define Z_IS_2828_EQ_2828U(...) \, +#define Z_IS_2828U_EQ_2828U(...) \, +#define Z_IS_2829_EQ_2829(...) \, +#define Z_IS_2829U_EQ_2829(...) \, +#define Z_IS_2829_EQ_2829U(...) \, +#define Z_IS_2829U_EQ_2829U(...) \, +#define Z_IS_2830_EQ_2830(...) \, +#define Z_IS_2830U_EQ_2830(...) \, +#define Z_IS_2830_EQ_2830U(...) \, +#define Z_IS_2830U_EQ_2830U(...) \, +#define Z_IS_2831_EQ_2831(...) \, +#define Z_IS_2831U_EQ_2831(...) \, +#define Z_IS_2831_EQ_2831U(...) \, +#define Z_IS_2831U_EQ_2831U(...) \, +#define Z_IS_2832_EQ_2832(...) \, +#define Z_IS_2832U_EQ_2832(...) \, +#define Z_IS_2832_EQ_2832U(...) \, +#define Z_IS_2832U_EQ_2832U(...) \, +#define Z_IS_2833_EQ_2833(...) \, +#define Z_IS_2833U_EQ_2833(...) \, +#define Z_IS_2833_EQ_2833U(...) \, +#define Z_IS_2833U_EQ_2833U(...) \, +#define Z_IS_2834_EQ_2834(...) \, +#define Z_IS_2834U_EQ_2834(...) \, +#define Z_IS_2834_EQ_2834U(...) \, +#define Z_IS_2834U_EQ_2834U(...) \, +#define Z_IS_2835_EQ_2835(...) \, +#define Z_IS_2835U_EQ_2835(...) \, +#define Z_IS_2835_EQ_2835U(...) \, +#define Z_IS_2835U_EQ_2835U(...) \, +#define Z_IS_2836_EQ_2836(...) \, +#define Z_IS_2836U_EQ_2836(...) \, +#define Z_IS_2836_EQ_2836U(...) \, +#define Z_IS_2836U_EQ_2836U(...) \, +#define Z_IS_2837_EQ_2837(...) \, +#define Z_IS_2837U_EQ_2837(...) \, +#define Z_IS_2837_EQ_2837U(...) \, +#define Z_IS_2837U_EQ_2837U(...) \, +#define Z_IS_2838_EQ_2838(...) \, +#define Z_IS_2838U_EQ_2838(...) \, +#define Z_IS_2838_EQ_2838U(...) \, +#define Z_IS_2838U_EQ_2838U(...) \, +#define Z_IS_2839_EQ_2839(...) \, +#define Z_IS_2839U_EQ_2839(...) \, +#define Z_IS_2839_EQ_2839U(...) \, +#define Z_IS_2839U_EQ_2839U(...) \, +#define Z_IS_2840_EQ_2840(...) \, +#define Z_IS_2840U_EQ_2840(...) \, +#define Z_IS_2840_EQ_2840U(...) \, +#define Z_IS_2840U_EQ_2840U(...) \, +#define Z_IS_2841_EQ_2841(...) \, +#define Z_IS_2841U_EQ_2841(...) \, +#define Z_IS_2841_EQ_2841U(...) \, +#define Z_IS_2841U_EQ_2841U(...) \, +#define Z_IS_2842_EQ_2842(...) \, +#define Z_IS_2842U_EQ_2842(...) \, +#define Z_IS_2842_EQ_2842U(...) \, +#define Z_IS_2842U_EQ_2842U(...) \, +#define Z_IS_2843_EQ_2843(...) \, +#define Z_IS_2843U_EQ_2843(...) \, +#define Z_IS_2843_EQ_2843U(...) \, +#define Z_IS_2843U_EQ_2843U(...) \, +#define Z_IS_2844_EQ_2844(...) \, +#define Z_IS_2844U_EQ_2844(...) \, +#define Z_IS_2844_EQ_2844U(...) \, +#define Z_IS_2844U_EQ_2844U(...) \, +#define Z_IS_2845_EQ_2845(...) \, +#define Z_IS_2845U_EQ_2845(...) \, +#define Z_IS_2845_EQ_2845U(...) \, +#define Z_IS_2845U_EQ_2845U(...) \, +#define Z_IS_2846_EQ_2846(...) \, +#define Z_IS_2846U_EQ_2846(...) \, +#define Z_IS_2846_EQ_2846U(...) \, +#define Z_IS_2846U_EQ_2846U(...) \, +#define Z_IS_2847_EQ_2847(...) \, +#define Z_IS_2847U_EQ_2847(...) \, +#define Z_IS_2847_EQ_2847U(...) \, +#define Z_IS_2847U_EQ_2847U(...) \, +#define Z_IS_2848_EQ_2848(...) \, +#define Z_IS_2848U_EQ_2848(...) \, +#define Z_IS_2848_EQ_2848U(...) \, +#define Z_IS_2848U_EQ_2848U(...) \, +#define Z_IS_2849_EQ_2849(...) \, +#define Z_IS_2849U_EQ_2849(...) \, +#define Z_IS_2849_EQ_2849U(...) \, +#define Z_IS_2849U_EQ_2849U(...) \, +#define Z_IS_2850_EQ_2850(...) \, +#define Z_IS_2850U_EQ_2850(...) \, +#define Z_IS_2850_EQ_2850U(...) \, +#define Z_IS_2850U_EQ_2850U(...) \, +#define Z_IS_2851_EQ_2851(...) \, +#define Z_IS_2851U_EQ_2851(...) \, +#define Z_IS_2851_EQ_2851U(...) \, +#define Z_IS_2851U_EQ_2851U(...) \, +#define Z_IS_2852_EQ_2852(...) \, +#define Z_IS_2852U_EQ_2852(...) \, +#define Z_IS_2852_EQ_2852U(...) \, +#define Z_IS_2852U_EQ_2852U(...) \, +#define Z_IS_2853_EQ_2853(...) \, +#define Z_IS_2853U_EQ_2853(...) \, +#define Z_IS_2853_EQ_2853U(...) \, +#define Z_IS_2853U_EQ_2853U(...) \, +#define Z_IS_2854_EQ_2854(...) \, +#define Z_IS_2854U_EQ_2854(...) \, +#define Z_IS_2854_EQ_2854U(...) \, +#define Z_IS_2854U_EQ_2854U(...) \, +#define Z_IS_2855_EQ_2855(...) \, +#define Z_IS_2855U_EQ_2855(...) \, +#define Z_IS_2855_EQ_2855U(...) \, +#define Z_IS_2855U_EQ_2855U(...) \, +#define Z_IS_2856_EQ_2856(...) \, +#define Z_IS_2856U_EQ_2856(...) \, +#define Z_IS_2856_EQ_2856U(...) \, +#define Z_IS_2856U_EQ_2856U(...) \, +#define Z_IS_2857_EQ_2857(...) \, +#define Z_IS_2857U_EQ_2857(...) \, +#define Z_IS_2857_EQ_2857U(...) \, +#define Z_IS_2857U_EQ_2857U(...) \, +#define Z_IS_2858_EQ_2858(...) \, +#define Z_IS_2858U_EQ_2858(...) \, +#define Z_IS_2858_EQ_2858U(...) \, +#define Z_IS_2858U_EQ_2858U(...) \, +#define Z_IS_2859_EQ_2859(...) \, +#define Z_IS_2859U_EQ_2859(...) \, +#define Z_IS_2859_EQ_2859U(...) \, +#define Z_IS_2859U_EQ_2859U(...) \, +#define Z_IS_2860_EQ_2860(...) \, +#define Z_IS_2860U_EQ_2860(...) \, +#define Z_IS_2860_EQ_2860U(...) \, +#define Z_IS_2860U_EQ_2860U(...) \, +#define Z_IS_2861_EQ_2861(...) \, +#define Z_IS_2861U_EQ_2861(...) \, +#define Z_IS_2861_EQ_2861U(...) \, +#define Z_IS_2861U_EQ_2861U(...) \, +#define Z_IS_2862_EQ_2862(...) \, +#define Z_IS_2862U_EQ_2862(...) \, +#define Z_IS_2862_EQ_2862U(...) \, +#define Z_IS_2862U_EQ_2862U(...) \, +#define Z_IS_2863_EQ_2863(...) \, +#define Z_IS_2863U_EQ_2863(...) \, +#define Z_IS_2863_EQ_2863U(...) \, +#define Z_IS_2863U_EQ_2863U(...) \, +#define Z_IS_2864_EQ_2864(...) \, +#define Z_IS_2864U_EQ_2864(...) \, +#define Z_IS_2864_EQ_2864U(...) \, +#define Z_IS_2864U_EQ_2864U(...) \, +#define Z_IS_2865_EQ_2865(...) \, +#define Z_IS_2865U_EQ_2865(...) \, +#define Z_IS_2865_EQ_2865U(...) \, +#define Z_IS_2865U_EQ_2865U(...) \, +#define Z_IS_2866_EQ_2866(...) \, +#define Z_IS_2866U_EQ_2866(...) \, +#define Z_IS_2866_EQ_2866U(...) \, +#define Z_IS_2866U_EQ_2866U(...) \, +#define Z_IS_2867_EQ_2867(...) \, +#define Z_IS_2867U_EQ_2867(...) \, +#define Z_IS_2867_EQ_2867U(...) \, +#define Z_IS_2867U_EQ_2867U(...) \, +#define Z_IS_2868_EQ_2868(...) \, +#define Z_IS_2868U_EQ_2868(...) \, +#define Z_IS_2868_EQ_2868U(...) \, +#define Z_IS_2868U_EQ_2868U(...) \, +#define Z_IS_2869_EQ_2869(...) \, +#define Z_IS_2869U_EQ_2869(...) \, +#define Z_IS_2869_EQ_2869U(...) \, +#define Z_IS_2869U_EQ_2869U(...) \, +#define Z_IS_2870_EQ_2870(...) \, +#define Z_IS_2870U_EQ_2870(...) \, +#define Z_IS_2870_EQ_2870U(...) \, +#define Z_IS_2870U_EQ_2870U(...) \, +#define Z_IS_2871_EQ_2871(...) \, +#define Z_IS_2871U_EQ_2871(...) \, +#define Z_IS_2871_EQ_2871U(...) \, +#define Z_IS_2871U_EQ_2871U(...) \, +#define Z_IS_2872_EQ_2872(...) \, +#define Z_IS_2872U_EQ_2872(...) \, +#define Z_IS_2872_EQ_2872U(...) \, +#define Z_IS_2872U_EQ_2872U(...) \, +#define Z_IS_2873_EQ_2873(...) \, +#define Z_IS_2873U_EQ_2873(...) \, +#define Z_IS_2873_EQ_2873U(...) \, +#define Z_IS_2873U_EQ_2873U(...) \, +#define Z_IS_2874_EQ_2874(...) \, +#define Z_IS_2874U_EQ_2874(...) \, +#define Z_IS_2874_EQ_2874U(...) \, +#define Z_IS_2874U_EQ_2874U(...) \, +#define Z_IS_2875_EQ_2875(...) \, +#define Z_IS_2875U_EQ_2875(...) \, +#define Z_IS_2875_EQ_2875U(...) \, +#define Z_IS_2875U_EQ_2875U(...) \, +#define Z_IS_2876_EQ_2876(...) \, +#define Z_IS_2876U_EQ_2876(...) \, +#define Z_IS_2876_EQ_2876U(...) \, +#define Z_IS_2876U_EQ_2876U(...) \, +#define Z_IS_2877_EQ_2877(...) \, +#define Z_IS_2877U_EQ_2877(...) \, +#define Z_IS_2877_EQ_2877U(...) \, +#define Z_IS_2877U_EQ_2877U(...) \, +#define Z_IS_2878_EQ_2878(...) \, +#define Z_IS_2878U_EQ_2878(...) \, +#define Z_IS_2878_EQ_2878U(...) \, +#define Z_IS_2878U_EQ_2878U(...) \, +#define Z_IS_2879_EQ_2879(...) \, +#define Z_IS_2879U_EQ_2879(...) \, +#define Z_IS_2879_EQ_2879U(...) \, +#define Z_IS_2879U_EQ_2879U(...) \, +#define Z_IS_2880_EQ_2880(...) \, +#define Z_IS_2880U_EQ_2880(...) \, +#define Z_IS_2880_EQ_2880U(...) \, +#define Z_IS_2880U_EQ_2880U(...) \, +#define Z_IS_2881_EQ_2881(...) \, +#define Z_IS_2881U_EQ_2881(...) \, +#define Z_IS_2881_EQ_2881U(...) \, +#define Z_IS_2881U_EQ_2881U(...) \, +#define Z_IS_2882_EQ_2882(...) \, +#define Z_IS_2882U_EQ_2882(...) \, +#define Z_IS_2882_EQ_2882U(...) \, +#define Z_IS_2882U_EQ_2882U(...) \, +#define Z_IS_2883_EQ_2883(...) \, +#define Z_IS_2883U_EQ_2883(...) \, +#define Z_IS_2883_EQ_2883U(...) \, +#define Z_IS_2883U_EQ_2883U(...) \, +#define Z_IS_2884_EQ_2884(...) \, +#define Z_IS_2884U_EQ_2884(...) \, +#define Z_IS_2884_EQ_2884U(...) \, +#define Z_IS_2884U_EQ_2884U(...) \, +#define Z_IS_2885_EQ_2885(...) \, +#define Z_IS_2885U_EQ_2885(...) \, +#define Z_IS_2885_EQ_2885U(...) \, +#define Z_IS_2885U_EQ_2885U(...) \, +#define Z_IS_2886_EQ_2886(...) \, +#define Z_IS_2886U_EQ_2886(...) \, +#define Z_IS_2886_EQ_2886U(...) \, +#define Z_IS_2886U_EQ_2886U(...) \, +#define Z_IS_2887_EQ_2887(...) \, +#define Z_IS_2887U_EQ_2887(...) \, +#define Z_IS_2887_EQ_2887U(...) \, +#define Z_IS_2887U_EQ_2887U(...) \, +#define Z_IS_2888_EQ_2888(...) \, +#define Z_IS_2888U_EQ_2888(...) \, +#define Z_IS_2888_EQ_2888U(...) \, +#define Z_IS_2888U_EQ_2888U(...) \, +#define Z_IS_2889_EQ_2889(...) \, +#define Z_IS_2889U_EQ_2889(...) \, +#define Z_IS_2889_EQ_2889U(...) \, +#define Z_IS_2889U_EQ_2889U(...) \, +#define Z_IS_2890_EQ_2890(...) \, +#define Z_IS_2890U_EQ_2890(...) \, +#define Z_IS_2890_EQ_2890U(...) \, +#define Z_IS_2890U_EQ_2890U(...) \, +#define Z_IS_2891_EQ_2891(...) \, +#define Z_IS_2891U_EQ_2891(...) \, +#define Z_IS_2891_EQ_2891U(...) \, +#define Z_IS_2891U_EQ_2891U(...) \, +#define Z_IS_2892_EQ_2892(...) \, +#define Z_IS_2892U_EQ_2892(...) \, +#define Z_IS_2892_EQ_2892U(...) \, +#define Z_IS_2892U_EQ_2892U(...) \, +#define Z_IS_2893_EQ_2893(...) \, +#define Z_IS_2893U_EQ_2893(...) \, +#define Z_IS_2893_EQ_2893U(...) \, +#define Z_IS_2893U_EQ_2893U(...) \, +#define Z_IS_2894_EQ_2894(...) \, +#define Z_IS_2894U_EQ_2894(...) \, +#define Z_IS_2894_EQ_2894U(...) \, +#define Z_IS_2894U_EQ_2894U(...) \, +#define Z_IS_2895_EQ_2895(...) \, +#define Z_IS_2895U_EQ_2895(...) \, +#define Z_IS_2895_EQ_2895U(...) \, +#define Z_IS_2895U_EQ_2895U(...) \, +#define Z_IS_2896_EQ_2896(...) \, +#define Z_IS_2896U_EQ_2896(...) \, +#define Z_IS_2896_EQ_2896U(...) \, +#define Z_IS_2896U_EQ_2896U(...) \, +#define Z_IS_2897_EQ_2897(...) \, +#define Z_IS_2897U_EQ_2897(...) \, +#define Z_IS_2897_EQ_2897U(...) \, +#define Z_IS_2897U_EQ_2897U(...) \, +#define Z_IS_2898_EQ_2898(...) \, +#define Z_IS_2898U_EQ_2898(...) \, +#define Z_IS_2898_EQ_2898U(...) \, +#define Z_IS_2898U_EQ_2898U(...) \, +#define Z_IS_2899_EQ_2899(...) \, +#define Z_IS_2899U_EQ_2899(...) \, +#define Z_IS_2899_EQ_2899U(...) \, +#define Z_IS_2899U_EQ_2899U(...) \, +#define Z_IS_2900_EQ_2900(...) \, +#define Z_IS_2900U_EQ_2900(...) \, +#define Z_IS_2900_EQ_2900U(...) \, +#define Z_IS_2900U_EQ_2900U(...) \, +#define Z_IS_2901_EQ_2901(...) \, +#define Z_IS_2901U_EQ_2901(...) \, +#define Z_IS_2901_EQ_2901U(...) \, +#define Z_IS_2901U_EQ_2901U(...) \, +#define Z_IS_2902_EQ_2902(...) \, +#define Z_IS_2902U_EQ_2902(...) \, +#define Z_IS_2902_EQ_2902U(...) \, +#define Z_IS_2902U_EQ_2902U(...) \, +#define Z_IS_2903_EQ_2903(...) \, +#define Z_IS_2903U_EQ_2903(...) \, +#define Z_IS_2903_EQ_2903U(...) \, +#define Z_IS_2903U_EQ_2903U(...) \, +#define Z_IS_2904_EQ_2904(...) \, +#define Z_IS_2904U_EQ_2904(...) \, +#define Z_IS_2904_EQ_2904U(...) \, +#define Z_IS_2904U_EQ_2904U(...) \, +#define Z_IS_2905_EQ_2905(...) \, +#define Z_IS_2905U_EQ_2905(...) \, +#define Z_IS_2905_EQ_2905U(...) \, +#define Z_IS_2905U_EQ_2905U(...) \, +#define Z_IS_2906_EQ_2906(...) \, +#define Z_IS_2906U_EQ_2906(...) \, +#define Z_IS_2906_EQ_2906U(...) \, +#define Z_IS_2906U_EQ_2906U(...) \, +#define Z_IS_2907_EQ_2907(...) \, +#define Z_IS_2907U_EQ_2907(...) \, +#define Z_IS_2907_EQ_2907U(...) \, +#define Z_IS_2907U_EQ_2907U(...) \, +#define Z_IS_2908_EQ_2908(...) \, +#define Z_IS_2908U_EQ_2908(...) \, +#define Z_IS_2908_EQ_2908U(...) \, +#define Z_IS_2908U_EQ_2908U(...) \, +#define Z_IS_2909_EQ_2909(...) \, +#define Z_IS_2909U_EQ_2909(...) \, +#define Z_IS_2909_EQ_2909U(...) \, +#define Z_IS_2909U_EQ_2909U(...) \, +#define Z_IS_2910_EQ_2910(...) \, +#define Z_IS_2910U_EQ_2910(...) \, +#define Z_IS_2910_EQ_2910U(...) \, +#define Z_IS_2910U_EQ_2910U(...) \, +#define Z_IS_2911_EQ_2911(...) \, +#define Z_IS_2911U_EQ_2911(...) \, +#define Z_IS_2911_EQ_2911U(...) \, +#define Z_IS_2911U_EQ_2911U(...) \, +#define Z_IS_2912_EQ_2912(...) \, +#define Z_IS_2912U_EQ_2912(...) \, +#define Z_IS_2912_EQ_2912U(...) \, +#define Z_IS_2912U_EQ_2912U(...) \, +#define Z_IS_2913_EQ_2913(...) \, +#define Z_IS_2913U_EQ_2913(...) \, +#define Z_IS_2913_EQ_2913U(...) \, +#define Z_IS_2913U_EQ_2913U(...) \, +#define Z_IS_2914_EQ_2914(...) \, +#define Z_IS_2914U_EQ_2914(...) \, +#define Z_IS_2914_EQ_2914U(...) \, +#define Z_IS_2914U_EQ_2914U(...) \, +#define Z_IS_2915_EQ_2915(...) \, +#define Z_IS_2915U_EQ_2915(...) \, +#define Z_IS_2915_EQ_2915U(...) \, +#define Z_IS_2915U_EQ_2915U(...) \, +#define Z_IS_2916_EQ_2916(...) \, +#define Z_IS_2916U_EQ_2916(...) \, +#define Z_IS_2916_EQ_2916U(...) \, +#define Z_IS_2916U_EQ_2916U(...) \, +#define Z_IS_2917_EQ_2917(...) \, +#define Z_IS_2917U_EQ_2917(...) \, +#define Z_IS_2917_EQ_2917U(...) \, +#define Z_IS_2917U_EQ_2917U(...) \, +#define Z_IS_2918_EQ_2918(...) \, +#define Z_IS_2918U_EQ_2918(...) \, +#define Z_IS_2918_EQ_2918U(...) \, +#define Z_IS_2918U_EQ_2918U(...) \, +#define Z_IS_2919_EQ_2919(...) \, +#define Z_IS_2919U_EQ_2919(...) \, +#define Z_IS_2919_EQ_2919U(...) \, +#define Z_IS_2919U_EQ_2919U(...) \, +#define Z_IS_2920_EQ_2920(...) \, +#define Z_IS_2920U_EQ_2920(...) \, +#define Z_IS_2920_EQ_2920U(...) \, +#define Z_IS_2920U_EQ_2920U(...) \, +#define Z_IS_2921_EQ_2921(...) \, +#define Z_IS_2921U_EQ_2921(...) \, +#define Z_IS_2921_EQ_2921U(...) \, +#define Z_IS_2921U_EQ_2921U(...) \, +#define Z_IS_2922_EQ_2922(...) \, +#define Z_IS_2922U_EQ_2922(...) \, +#define Z_IS_2922_EQ_2922U(...) \, +#define Z_IS_2922U_EQ_2922U(...) \, +#define Z_IS_2923_EQ_2923(...) \, +#define Z_IS_2923U_EQ_2923(...) \, +#define Z_IS_2923_EQ_2923U(...) \, +#define Z_IS_2923U_EQ_2923U(...) \, +#define Z_IS_2924_EQ_2924(...) \, +#define Z_IS_2924U_EQ_2924(...) \, +#define Z_IS_2924_EQ_2924U(...) \, +#define Z_IS_2924U_EQ_2924U(...) \, +#define Z_IS_2925_EQ_2925(...) \, +#define Z_IS_2925U_EQ_2925(...) \, +#define Z_IS_2925_EQ_2925U(...) \, +#define Z_IS_2925U_EQ_2925U(...) \, +#define Z_IS_2926_EQ_2926(...) \, +#define Z_IS_2926U_EQ_2926(...) \, +#define Z_IS_2926_EQ_2926U(...) \, +#define Z_IS_2926U_EQ_2926U(...) \, +#define Z_IS_2927_EQ_2927(...) \, +#define Z_IS_2927U_EQ_2927(...) \, +#define Z_IS_2927_EQ_2927U(...) \, +#define Z_IS_2927U_EQ_2927U(...) \, +#define Z_IS_2928_EQ_2928(...) \, +#define Z_IS_2928U_EQ_2928(...) \, +#define Z_IS_2928_EQ_2928U(...) \, +#define Z_IS_2928U_EQ_2928U(...) \, +#define Z_IS_2929_EQ_2929(...) \, +#define Z_IS_2929U_EQ_2929(...) \, +#define Z_IS_2929_EQ_2929U(...) \, +#define Z_IS_2929U_EQ_2929U(...) \, +#define Z_IS_2930_EQ_2930(...) \, +#define Z_IS_2930U_EQ_2930(...) \, +#define Z_IS_2930_EQ_2930U(...) \, +#define Z_IS_2930U_EQ_2930U(...) \, +#define Z_IS_2931_EQ_2931(...) \, +#define Z_IS_2931U_EQ_2931(...) \, +#define Z_IS_2931_EQ_2931U(...) \, +#define Z_IS_2931U_EQ_2931U(...) \, +#define Z_IS_2932_EQ_2932(...) \, +#define Z_IS_2932U_EQ_2932(...) \, +#define Z_IS_2932_EQ_2932U(...) \, +#define Z_IS_2932U_EQ_2932U(...) \, +#define Z_IS_2933_EQ_2933(...) \, +#define Z_IS_2933U_EQ_2933(...) \, +#define Z_IS_2933_EQ_2933U(...) \, +#define Z_IS_2933U_EQ_2933U(...) \, +#define Z_IS_2934_EQ_2934(...) \, +#define Z_IS_2934U_EQ_2934(...) \, +#define Z_IS_2934_EQ_2934U(...) \, +#define Z_IS_2934U_EQ_2934U(...) \, +#define Z_IS_2935_EQ_2935(...) \, +#define Z_IS_2935U_EQ_2935(...) \, +#define Z_IS_2935_EQ_2935U(...) \, +#define Z_IS_2935U_EQ_2935U(...) \, +#define Z_IS_2936_EQ_2936(...) \, +#define Z_IS_2936U_EQ_2936(...) \, +#define Z_IS_2936_EQ_2936U(...) \, +#define Z_IS_2936U_EQ_2936U(...) \, +#define Z_IS_2937_EQ_2937(...) \, +#define Z_IS_2937U_EQ_2937(...) \, +#define Z_IS_2937_EQ_2937U(...) \, +#define Z_IS_2937U_EQ_2937U(...) \, +#define Z_IS_2938_EQ_2938(...) \, +#define Z_IS_2938U_EQ_2938(...) \, +#define Z_IS_2938_EQ_2938U(...) \, +#define Z_IS_2938U_EQ_2938U(...) \, +#define Z_IS_2939_EQ_2939(...) \, +#define Z_IS_2939U_EQ_2939(...) \, +#define Z_IS_2939_EQ_2939U(...) \, +#define Z_IS_2939U_EQ_2939U(...) \, +#define Z_IS_2940_EQ_2940(...) \, +#define Z_IS_2940U_EQ_2940(...) \, +#define Z_IS_2940_EQ_2940U(...) \, +#define Z_IS_2940U_EQ_2940U(...) \, +#define Z_IS_2941_EQ_2941(...) \, +#define Z_IS_2941U_EQ_2941(...) \, +#define Z_IS_2941_EQ_2941U(...) \, +#define Z_IS_2941U_EQ_2941U(...) \, +#define Z_IS_2942_EQ_2942(...) \, +#define Z_IS_2942U_EQ_2942(...) \, +#define Z_IS_2942_EQ_2942U(...) \, +#define Z_IS_2942U_EQ_2942U(...) \, +#define Z_IS_2943_EQ_2943(...) \, +#define Z_IS_2943U_EQ_2943(...) \, +#define Z_IS_2943_EQ_2943U(...) \, +#define Z_IS_2943U_EQ_2943U(...) \, +#define Z_IS_2944_EQ_2944(...) \, +#define Z_IS_2944U_EQ_2944(...) \, +#define Z_IS_2944_EQ_2944U(...) \, +#define Z_IS_2944U_EQ_2944U(...) \, +#define Z_IS_2945_EQ_2945(...) \, +#define Z_IS_2945U_EQ_2945(...) \, +#define Z_IS_2945_EQ_2945U(...) \, +#define Z_IS_2945U_EQ_2945U(...) \, +#define Z_IS_2946_EQ_2946(...) \, +#define Z_IS_2946U_EQ_2946(...) \, +#define Z_IS_2946_EQ_2946U(...) \, +#define Z_IS_2946U_EQ_2946U(...) \, +#define Z_IS_2947_EQ_2947(...) \, +#define Z_IS_2947U_EQ_2947(...) \, +#define Z_IS_2947_EQ_2947U(...) \, +#define Z_IS_2947U_EQ_2947U(...) \, +#define Z_IS_2948_EQ_2948(...) \, +#define Z_IS_2948U_EQ_2948(...) \, +#define Z_IS_2948_EQ_2948U(...) \, +#define Z_IS_2948U_EQ_2948U(...) \, +#define Z_IS_2949_EQ_2949(...) \, +#define Z_IS_2949U_EQ_2949(...) \, +#define Z_IS_2949_EQ_2949U(...) \, +#define Z_IS_2949U_EQ_2949U(...) \, +#define Z_IS_2950_EQ_2950(...) \, +#define Z_IS_2950U_EQ_2950(...) \, +#define Z_IS_2950_EQ_2950U(...) \, +#define Z_IS_2950U_EQ_2950U(...) \, +#define Z_IS_2951_EQ_2951(...) \, +#define Z_IS_2951U_EQ_2951(...) \, +#define Z_IS_2951_EQ_2951U(...) \, +#define Z_IS_2951U_EQ_2951U(...) \, +#define Z_IS_2952_EQ_2952(...) \, +#define Z_IS_2952U_EQ_2952(...) \, +#define Z_IS_2952_EQ_2952U(...) \, +#define Z_IS_2952U_EQ_2952U(...) \, +#define Z_IS_2953_EQ_2953(...) \, +#define Z_IS_2953U_EQ_2953(...) \, +#define Z_IS_2953_EQ_2953U(...) \, +#define Z_IS_2953U_EQ_2953U(...) \, +#define Z_IS_2954_EQ_2954(...) \, +#define Z_IS_2954U_EQ_2954(...) \, +#define Z_IS_2954_EQ_2954U(...) \, +#define Z_IS_2954U_EQ_2954U(...) \, +#define Z_IS_2955_EQ_2955(...) \, +#define Z_IS_2955U_EQ_2955(...) \, +#define Z_IS_2955_EQ_2955U(...) \, +#define Z_IS_2955U_EQ_2955U(...) \, +#define Z_IS_2956_EQ_2956(...) \, +#define Z_IS_2956U_EQ_2956(...) \, +#define Z_IS_2956_EQ_2956U(...) \, +#define Z_IS_2956U_EQ_2956U(...) \, +#define Z_IS_2957_EQ_2957(...) \, +#define Z_IS_2957U_EQ_2957(...) \, +#define Z_IS_2957_EQ_2957U(...) \, +#define Z_IS_2957U_EQ_2957U(...) \, +#define Z_IS_2958_EQ_2958(...) \, +#define Z_IS_2958U_EQ_2958(...) \, +#define Z_IS_2958_EQ_2958U(...) \, +#define Z_IS_2958U_EQ_2958U(...) \, +#define Z_IS_2959_EQ_2959(...) \, +#define Z_IS_2959U_EQ_2959(...) \, +#define Z_IS_2959_EQ_2959U(...) \, +#define Z_IS_2959U_EQ_2959U(...) \, +#define Z_IS_2960_EQ_2960(...) \, +#define Z_IS_2960U_EQ_2960(...) \, +#define Z_IS_2960_EQ_2960U(...) \, +#define Z_IS_2960U_EQ_2960U(...) \, +#define Z_IS_2961_EQ_2961(...) \, +#define Z_IS_2961U_EQ_2961(...) \, +#define Z_IS_2961_EQ_2961U(...) \, +#define Z_IS_2961U_EQ_2961U(...) \, +#define Z_IS_2962_EQ_2962(...) \, +#define Z_IS_2962U_EQ_2962(...) \, +#define Z_IS_2962_EQ_2962U(...) \, +#define Z_IS_2962U_EQ_2962U(...) \, +#define Z_IS_2963_EQ_2963(...) \, +#define Z_IS_2963U_EQ_2963(...) \, +#define Z_IS_2963_EQ_2963U(...) \, +#define Z_IS_2963U_EQ_2963U(...) \, +#define Z_IS_2964_EQ_2964(...) \, +#define Z_IS_2964U_EQ_2964(...) \, +#define Z_IS_2964_EQ_2964U(...) \, +#define Z_IS_2964U_EQ_2964U(...) \, +#define Z_IS_2965_EQ_2965(...) \, +#define Z_IS_2965U_EQ_2965(...) \, +#define Z_IS_2965_EQ_2965U(...) \, +#define Z_IS_2965U_EQ_2965U(...) \, +#define Z_IS_2966_EQ_2966(...) \, +#define Z_IS_2966U_EQ_2966(...) \, +#define Z_IS_2966_EQ_2966U(...) \, +#define Z_IS_2966U_EQ_2966U(...) \, +#define Z_IS_2967_EQ_2967(...) \, +#define Z_IS_2967U_EQ_2967(...) \, +#define Z_IS_2967_EQ_2967U(...) \, +#define Z_IS_2967U_EQ_2967U(...) \, +#define Z_IS_2968_EQ_2968(...) \, +#define Z_IS_2968U_EQ_2968(...) \, +#define Z_IS_2968_EQ_2968U(...) \, +#define Z_IS_2968U_EQ_2968U(...) \, +#define Z_IS_2969_EQ_2969(...) \, +#define Z_IS_2969U_EQ_2969(...) \, +#define Z_IS_2969_EQ_2969U(...) \, +#define Z_IS_2969U_EQ_2969U(...) \, +#define Z_IS_2970_EQ_2970(...) \, +#define Z_IS_2970U_EQ_2970(...) \, +#define Z_IS_2970_EQ_2970U(...) \, +#define Z_IS_2970U_EQ_2970U(...) \, +#define Z_IS_2971_EQ_2971(...) \, +#define Z_IS_2971U_EQ_2971(...) \, +#define Z_IS_2971_EQ_2971U(...) \, +#define Z_IS_2971U_EQ_2971U(...) \, +#define Z_IS_2972_EQ_2972(...) \, +#define Z_IS_2972U_EQ_2972(...) \, +#define Z_IS_2972_EQ_2972U(...) \, +#define Z_IS_2972U_EQ_2972U(...) \, +#define Z_IS_2973_EQ_2973(...) \, +#define Z_IS_2973U_EQ_2973(...) \, +#define Z_IS_2973_EQ_2973U(...) \, +#define Z_IS_2973U_EQ_2973U(...) \, +#define Z_IS_2974_EQ_2974(...) \, +#define Z_IS_2974U_EQ_2974(...) \, +#define Z_IS_2974_EQ_2974U(...) \, +#define Z_IS_2974U_EQ_2974U(...) \, +#define Z_IS_2975_EQ_2975(...) \, +#define Z_IS_2975U_EQ_2975(...) \, +#define Z_IS_2975_EQ_2975U(...) \, +#define Z_IS_2975U_EQ_2975U(...) \, +#define Z_IS_2976_EQ_2976(...) \, +#define Z_IS_2976U_EQ_2976(...) \, +#define Z_IS_2976_EQ_2976U(...) \, +#define Z_IS_2976U_EQ_2976U(...) \, +#define Z_IS_2977_EQ_2977(...) \, +#define Z_IS_2977U_EQ_2977(...) \, +#define Z_IS_2977_EQ_2977U(...) \, +#define Z_IS_2977U_EQ_2977U(...) \, +#define Z_IS_2978_EQ_2978(...) \, +#define Z_IS_2978U_EQ_2978(...) \, +#define Z_IS_2978_EQ_2978U(...) \, +#define Z_IS_2978U_EQ_2978U(...) \, +#define Z_IS_2979_EQ_2979(...) \, +#define Z_IS_2979U_EQ_2979(...) \, +#define Z_IS_2979_EQ_2979U(...) \, +#define Z_IS_2979U_EQ_2979U(...) \, +#define Z_IS_2980_EQ_2980(...) \, +#define Z_IS_2980U_EQ_2980(...) \, +#define Z_IS_2980_EQ_2980U(...) \, +#define Z_IS_2980U_EQ_2980U(...) \, +#define Z_IS_2981_EQ_2981(...) \, +#define Z_IS_2981U_EQ_2981(...) \, +#define Z_IS_2981_EQ_2981U(...) \, +#define Z_IS_2981U_EQ_2981U(...) \, +#define Z_IS_2982_EQ_2982(...) \, +#define Z_IS_2982U_EQ_2982(...) \, +#define Z_IS_2982_EQ_2982U(...) \, +#define Z_IS_2982U_EQ_2982U(...) \, +#define Z_IS_2983_EQ_2983(...) \, +#define Z_IS_2983U_EQ_2983(...) \, +#define Z_IS_2983_EQ_2983U(...) \, +#define Z_IS_2983U_EQ_2983U(...) \, +#define Z_IS_2984_EQ_2984(...) \, +#define Z_IS_2984U_EQ_2984(...) \, +#define Z_IS_2984_EQ_2984U(...) \, +#define Z_IS_2984U_EQ_2984U(...) \, +#define Z_IS_2985_EQ_2985(...) \, +#define Z_IS_2985U_EQ_2985(...) \, +#define Z_IS_2985_EQ_2985U(...) \, +#define Z_IS_2985U_EQ_2985U(...) \, +#define Z_IS_2986_EQ_2986(...) \, +#define Z_IS_2986U_EQ_2986(...) \, +#define Z_IS_2986_EQ_2986U(...) \, +#define Z_IS_2986U_EQ_2986U(...) \, +#define Z_IS_2987_EQ_2987(...) \, +#define Z_IS_2987U_EQ_2987(...) \, +#define Z_IS_2987_EQ_2987U(...) \, +#define Z_IS_2987U_EQ_2987U(...) \, +#define Z_IS_2988_EQ_2988(...) \, +#define Z_IS_2988U_EQ_2988(...) \, +#define Z_IS_2988_EQ_2988U(...) \, +#define Z_IS_2988U_EQ_2988U(...) \, +#define Z_IS_2989_EQ_2989(...) \, +#define Z_IS_2989U_EQ_2989(...) \, +#define Z_IS_2989_EQ_2989U(...) \, +#define Z_IS_2989U_EQ_2989U(...) \, +#define Z_IS_2990_EQ_2990(...) \, +#define Z_IS_2990U_EQ_2990(...) \, +#define Z_IS_2990_EQ_2990U(...) \, +#define Z_IS_2990U_EQ_2990U(...) \, +#define Z_IS_2991_EQ_2991(...) \, +#define Z_IS_2991U_EQ_2991(...) \, +#define Z_IS_2991_EQ_2991U(...) \, +#define Z_IS_2991U_EQ_2991U(...) \, +#define Z_IS_2992_EQ_2992(...) \, +#define Z_IS_2992U_EQ_2992(...) \, +#define Z_IS_2992_EQ_2992U(...) \, +#define Z_IS_2992U_EQ_2992U(...) \, +#define Z_IS_2993_EQ_2993(...) \, +#define Z_IS_2993U_EQ_2993(...) \, +#define Z_IS_2993_EQ_2993U(...) \, +#define Z_IS_2993U_EQ_2993U(...) \, +#define Z_IS_2994_EQ_2994(...) \, +#define Z_IS_2994U_EQ_2994(...) \, +#define Z_IS_2994_EQ_2994U(...) \, +#define Z_IS_2994U_EQ_2994U(...) \, +#define Z_IS_2995_EQ_2995(...) \, +#define Z_IS_2995U_EQ_2995(...) \, +#define Z_IS_2995_EQ_2995U(...) \, +#define Z_IS_2995U_EQ_2995U(...) \, +#define Z_IS_2996_EQ_2996(...) \, +#define Z_IS_2996U_EQ_2996(...) \, +#define Z_IS_2996_EQ_2996U(...) \, +#define Z_IS_2996U_EQ_2996U(...) \, +#define Z_IS_2997_EQ_2997(...) \, +#define Z_IS_2997U_EQ_2997(...) \, +#define Z_IS_2997_EQ_2997U(...) \, +#define Z_IS_2997U_EQ_2997U(...) \, +#define Z_IS_2998_EQ_2998(...) \, +#define Z_IS_2998U_EQ_2998(...) \, +#define Z_IS_2998_EQ_2998U(...) \, +#define Z_IS_2998U_EQ_2998U(...) \, +#define Z_IS_2999_EQ_2999(...) \, +#define Z_IS_2999U_EQ_2999(...) \, +#define Z_IS_2999_EQ_2999U(...) \, +#define Z_IS_2999U_EQ_2999U(...) \, +#define Z_IS_3000_EQ_3000(...) \, +#define Z_IS_3000U_EQ_3000(...) \, +#define Z_IS_3000_EQ_3000U(...) \, +#define Z_IS_3000U_EQ_3000U(...) \, +#define Z_IS_3001_EQ_3001(...) \, +#define Z_IS_3001U_EQ_3001(...) \, +#define Z_IS_3001_EQ_3001U(...) \, +#define Z_IS_3001U_EQ_3001U(...) \, +#define Z_IS_3002_EQ_3002(...) \, +#define Z_IS_3002U_EQ_3002(...) \, +#define Z_IS_3002_EQ_3002U(...) \, +#define Z_IS_3002U_EQ_3002U(...) \, +#define Z_IS_3003_EQ_3003(...) \, +#define Z_IS_3003U_EQ_3003(...) \, +#define Z_IS_3003_EQ_3003U(...) \, +#define Z_IS_3003U_EQ_3003U(...) \, +#define Z_IS_3004_EQ_3004(...) \, +#define Z_IS_3004U_EQ_3004(...) \, +#define Z_IS_3004_EQ_3004U(...) \, +#define Z_IS_3004U_EQ_3004U(...) \, +#define Z_IS_3005_EQ_3005(...) \, +#define Z_IS_3005U_EQ_3005(...) \, +#define Z_IS_3005_EQ_3005U(...) \, +#define Z_IS_3005U_EQ_3005U(...) \, +#define Z_IS_3006_EQ_3006(...) \, +#define Z_IS_3006U_EQ_3006(...) \, +#define Z_IS_3006_EQ_3006U(...) \, +#define Z_IS_3006U_EQ_3006U(...) \, +#define Z_IS_3007_EQ_3007(...) \, +#define Z_IS_3007U_EQ_3007(...) \, +#define Z_IS_3007_EQ_3007U(...) \, +#define Z_IS_3007U_EQ_3007U(...) \, +#define Z_IS_3008_EQ_3008(...) \, +#define Z_IS_3008U_EQ_3008(...) \, +#define Z_IS_3008_EQ_3008U(...) \, +#define Z_IS_3008U_EQ_3008U(...) \, +#define Z_IS_3009_EQ_3009(...) \, +#define Z_IS_3009U_EQ_3009(...) \, +#define Z_IS_3009_EQ_3009U(...) \, +#define Z_IS_3009U_EQ_3009U(...) \, +#define Z_IS_3010_EQ_3010(...) \, +#define Z_IS_3010U_EQ_3010(...) \, +#define Z_IS_3010_EQ_3010U(...) \, +#define Z_IS_3010U_EQ_3010U(...) \, +#define Z_IS_3011_EQ_3011(...) \, +#define Z_IS_3011U_EQ_3011(...) \, +#define Z_IS_3011_EQ_3011U(...) \, +#define Z_IS_3011U_EQ_3011U(...) \, +#define Z_IS_3012_EQ_3012(...) \, +#define Z_IS_3012U_EQ_3012(...) \, +#define Z_IS_3012_EQ_3012U(...) \, +#define Z_IS_3012U_EQ_3012U(...) \, +#define Z_IS_3013_EQ_3013(...) \, +#define Z_IS_3013U_EQ_3013(...) \, +#define Z_IS_3013_EQ_3013U(...) \, +#define Z_IS_3013U_EQ_3013U(...) \, +#define Z_IS_3014_EQ_3014(...) \, +#define Z_IS_3014U_EQ_3014(...) \, +#define Z_IS_3014_EQ_3014U(...) \, +#define Z_IS_3014U_EQ_3014U(...) \, +#define Z_IS_3015_EQ_3015(...) \, +#define Z_IS_3015U_EQ_3015(...) \, +#define Z_IS_3015_EQ_3015U(...) \, +#define Z_IS_3015U_EQ_3015U(...) \, +#define Z_IS_3016_EQ_3016(...) \, +#define Z_IS_3016U_EQ_3016(...) \, +#define Z_IS_3016_EQ_3016U(...) \, +#define Z_IS_3016U_EQ_3016U(...) \, +#define Z_IS_3017_EQ_3017(...) \, +#define Z_IS_3017U_EQ_3017(...) \, +#define Z_IS_3017_EQ_3017U(...) \, +#define Z_IS_3017U_EQ_3017U(...) \, +#define Z_IS_3018_EQ_3018(...) \, +#define Z_IS_3018U_EQ_3018(...) \, +#define Z_IS_3018_EQ_3018U(...) \, +#define Z_IS_3018U_EQ_3018U(...) \, +#define Z_IS_3019_EQ_3019(...) \, +#define Z_IS_3019U_EQ_3019(...) \, +#define Z_IS_3019_EQ_3019U(...) \, +#define Z_IS_3019U_EQ_3019U(...) \, +#define Z_IS_3020_EQ_3020(...) \, +#define Z_IS_3020U_EQ_3020(...) \, +#define Z_IS_3020_EQ_3020U(...) \, +#define Z_IS_3020U_EQ_3020U(...) \, +#define Z_IS_3021_EQ_3021(...) \, +#define Z_IS_3021U_EQ_3021(...) \, +#define Z_IS_3021_EQ_3021U(...) \, +#define Z_IS_3021U_EQ_3021U(...) \, +#define Z_IS_3022_EQ_3022(...) \, +#define Z_IS_3022U_EQ_3022(...) \, +#define Z_IS_3022_EQ_3022U(...) \, +#define Z_IS_3022U_EQ_3022U(...) \, +#define Z_IS_3023_EQ_3023(...) \, +#define Z_IS_3023U_EQ_3023(...) \, +#define Z_IS_3023_EQ_3023U(...) \, +#define Z_IS_3023U_EQ_3023U(...) \, +#define Z_IS_3024_EQ_3024(...) \, +#define Z_IS_3024U_EQ_3024(...) \, +#define Z_IS_3024_EQ_3024U(...) \, +#define Z_IS_3024U_EQ_3024U(...) \, +#define Z_IS_3025_EQ_3025(...) \, +#define Z_IS_3025U_EQ_3025(...) \, +#define Z_IS_3025_EQ_3025U(...) \, +#define Z_IS_3025U_EQ_3025U(...) \, +#define Z_IS_3026_EQ_3026(...) \, +#define Z_IS_3026U_EQ_3026(...) \, +#define Z_IS_3026_EQ_3026U(...) \, +#define Z_IS_3026U_EQ_3026U(...) \, +#define Z_IS_3027_EQ_3027(...) \, +#define Z_IS_3027U_EQ_3027(...) \, +#define Z_IS_3027_EQ_3027U(...) \, +#define Z_IS_3027U_EQ_3027U(...) \, +#define Z_IS_3028_EQ_3028(...) \, +#define Z_IS_3028U_EQ_3028(...) \, +#define Z_IS_3028_EQ_3028U(...) \, +#define Z_IS_3028U_EQ_3028U(...) \, +#define Z_IS_3029_EQ_3029(...) \, +#define Z_IS_3029U_EQ_3029(...) \, +#define Z_IS_3029_EQ_3029U(...) \, +#define Z_IS_3029U_EQ_3029U(...) \, +#define Z_IS_3030_EQ_3030(...) \, +#define Z_IS_3030U_EQ_3030(...) \, +#define Z_IS_3030_EQ_3030U(...) \, +#define Z_IS_3030U_EQ_3030U(...) \, +#define Z_IS_3031_EQ_3031(...) \, +#define Z_IS_3031U_EQ_3031(...) \, +#define Z_IS_3031_EQ_3031U(...) \, +#define Z_IS_3031U_EQ_3031U(...) \, +#define Z_IS_3032_EQ_3032(...) \, +#define Z_IS_3032U_EQ_3032(...) \, +#define Z_IS_3032_EQ_3032U(...) \, +#define Z_IS_3032U_EQ_3032U(...) \, +#define Z_IS_3033_EQ_3033(...) \, +#define Z_IS_3033U_EQ_3033(...) \, +#define Z_IS_3033_EQ_3033U(...) \, +#define Z_IS_3033U_EQ_3033U(...) \, +#define Z_IS_3034_EQ_3034(...) \, +#define Z_IS_3034U_EQ_3034(...) \, +#define Z_IS_3034_EQ_3034U(...) \, +#define Z_IS_3034U_EQ_3034U(...) \, +#define Z_IS_3035_EQ_3035(...) \, +#define Z_IS_3035U_EQ_3035(...) \, +#define Z_IS_3035_EQ_3035U(...) \, +#define Z_IS_3035U_EQ_3035U(...) \, +#define Z_IS_3036_EQ_3036(...) \, +#define Z_IS_3036U_EQ_3036(...) \, +#define Z_IS_3036_EQ_3036U(...) \, +#define Z_IS_3036U_EQ_3036U(...) \, +#define Z_IS_3037_EQ_3037(...) \, +#define Z_IS_3037U_EQ_3037(...) \, +#define Z_IS_3037_EQ_3037U(...) \, +#define Z_IS_3037U_EQ_3037U(...) \, +#define Z_IS_3038_EQ_3038(...) \, +#define Z_IS_3038U_EQ_3038(...) \, +#define Z_IS_3038_EQ_3038U(...) \, +#define Z_IS_3038U_EQ_3038U(...) \, +#define Z_IS_3039_EQ_3039(...) \, +#define Z_IS_3039U_EQ_3039(...) \, +#define Z_IS_3039_EQ_3039U(...) \, +#define Z_IS_3039U_EQ_3039U(...) \, +#define Z_IS_3040_EQ_3040(...) \, +#define Z_IS_3040U_EQ_3040(...) \, +#define Z_IS_3040_EQ_3040U(...) \, +#define Z_IS_3040U_EQ_3040U(...) \, +#define Z_IS_3041_EQ_3041(...) \, +#define Z_IS_3041U_EQ_3041(...) \, +#define Z_IS_3041_EQ_3041U(...) \, +#define Z_IS_3041U_EQ_3041U(...) \, +#define Z_IS_3042_EQ_3042(...) \, +#define Z_IS_3042U_EQ_3042(...) \, +#define Z_IS_3042_EQ_3042U(...) \, +#define Z_IS_3042U_EQ_3042U(...) \, +#define Z_IS_3043_EQ_3043(...) \, +#define Z_IS_3043U_EQ_3043(...) \, +#define Z_IS_3043_EQ_3043U(...) \, +#define Z_IS_3043U_EQ_3043U(...) \, +#define Z_IS_3044_EQ_3044(...) \, +#define Z_IS_3044U_EQ_3044(...) \, +#define Z_IS_3044_EQ_3044U(...) \, +#define Z_IS_3044U_EQ_3044U(...) \, +#define Z_IS_3045_EQ_3045(...) \, +#define Z_IS_3045U_EQ_3045(...) \, +#define Z_IS_3045_EQ_3045U(...) \, +#define Z_IS_3045U_EQ_3045U(...) \, +#define Z_IS_3046_EQ_3046(...) \, +#define Z_IS_3046U_EQ_3046(...) \, +#define Z_IS_3046_EQ_3046U(...) \, +#define Z_IS_3046U_EQ_3046U(...) \, +#define Z_IS_3047_EQ_3047(...) \, +#define Z_IS_3047U_EQ_3047(...) \, +#define Z_IS_3047_EQ_3047U(...) \, +#define Z_IS_3047U_EQ_3047U(...) \, +#define Z_IS_3048_EQ_3048(...) \, +#define Z_IS_3048U_EQ_3048(...) \, +#define Z_IS_3048_EQ_3048U(...) \, +#define Z_IS_3048U_EQ_3048U(...) \, +#define Z_IS_3049_EQ_3049(...) \, +#define Z_IS_3049U_EQ_3049(...) \, +#define Z_IS_3049_EQ_3049U(...) \, +#define Z_IS_3049U_EQ_3049U(...) \, +#define Z_IS_3050_EQ_3050(...) \, +#define Z_IS_3050U_EQ_3050(...) \, +#define Z_IS_3050_EQ_3050U(...) \, +#define Z_IS_3050U_EQ_3050U(...) \, +#define Z_IS_3051_EQ_3051(...) \, +#define Z_IS_3051U_EQ_3051(...) \, +#define Z_IS_3051_EQ_3051U(...) \, +#define Z_IS_3051U_EQ_3051U(...) \, +#define Z_IS_3052_EQ_3052(...) \, +#define Z_IS_3052U_EQ_3052(...) \, +#define Z_IS_3052_EQ_3052U(...) \, +#define Z_IS_3052U_EQ_3052U(...) \, +#define Z_IS_3053_EQ_3053(...) \, +#define Z_IS_3053U_EQ_3053(...) \, +#define Z_IS_3053_EQ_3053U(...) \, +#define Z_IS_3053U_EQ_3053U(...) \, +#define Z_IS_3054_EQ_3054(...) \, +#define Z_IS_3054U_EQ_3054(...) \, +#define Z_IS_3054_EQ_3054U(...) \, +#define Z_IS_3054U_EQ_3054U(...) \, +#define Z_IS_3055_EQ_3055(...) \, +#define Z_IS_3055U_EQ_3055(...) \, +#define Z_IS_3055_EQ_3055U(...) \, +#define Z_IS_3055U_EQ_3055U(...) \, +#define Z_IS_3056_EQ_3056(...) \, +#define Z_IS_3056U_EQ_3056(...) \, +#define Z_IS_3056_EQ_3056U(...) \, +#define Z_IS_3056U_EQ_3056U(...) \, +#define Z_IS_3057_EQ_3057(...) \, +#define Z_IS_3057U_EQ_3057(...) \, +#define Z_IS_3057_EQ_3057U(...) \, +#define Z_IS_3057U_EQ_3057U(...) \, +#define Z_IS_3058_EQ_3058(...) \, +#define Z_IS_3058U_EQ_3058(...) \, +#define Z_IS_3058_EQ_3058U(...) \, +#define Z_IS_3058U_EQ_3058U(...) \, +#define Z_IS_3059_EQ_3059(...) \, +#define Z_IS_3059U_EQ_3059(...) \, +#define Z_IS_3059_EQ_3059U(...) \, +#define Z_IS_3059U_EQ_3059U(...) \, +#define Z_IS_3060_EQ_3060(...) \, +#define Z_IS_3060U_EQ_3060(...) \, +#define Z_IS_3060_EQ_3060U(...) \, +#define Z_IS_3060U_EQ_3060U(...) \, +#define Z_IS_3061_EQ_3061(...) \, +#define Z_IS_3061U_EQ_3061(...) \, +#define Z_IS_3061_EQ_3061U(...) \, +#define Z_IS_3061U_EQ_3061U(...) \, +#define Z_IS_3062_EQ_3062(...) \, +#define Z_IS_3062U_EQ_3062(...) \, +#define Z_IS_3062_EQ_3062U(...) \, +#define Z_IS_3062U_EQ_3062U(...) \, +#define Z_IS_3063_EQ_3063(...) \, +#define Z_IS_3063U_EQ_3063(...) \, +#define Z_IS_3063_EQ_3063U(...) \, +#define Z_IS_3063U_EQ_3063U(...) \, +#define Z_IS_3064_EQ_3064(...) \, +#define Z_IS_3064U_EQ_3064(...) \, +#define Z_IS_3064_EQ_3064U(...) \, +#define Z_IS_3064U_EQ_3064U(...) \, +#define Z_IS_3065_EQ_3065(...) \, +#define Z_IS_3065U_EQ_3065(...) \, +#define Z_IS_3065_EQ_3065U(...) \, +#define Z_IS_3065U_EQ_3065U(...) \, +#define Z_IS_3066_EQ_3066(...) \, +#define Z_IS_3066U_EQ_3066(...) \, +#define Z_IS_3066_EQ_3066U(...) \, +#define Z_IS_3066U_EQ_3066U(...) \, +#define Z_IS_3067_EQ_3067(...) \, +#define Z_IS_3067U_EQ_3067(...) \, +#define Z_IS_3067_EQ_3067U(...) \, +#define Z_IS_3067U_EQ_3067U(...) \, +#define Z_IS_3068_EQ_3068(...) \, +#define Z_IS_3068U_EQ_3068(...) \, +#define Z_IS_3068_EQ_3068U(...) \, +#define Z_IS_3068U_EQ_3068U(...) \, +#define Z_IS_3069_EQ_3069(...) \, +#define Z_IS_3069U_EQ_3069(...) \, +#define Z_IS_3069_EQ_3069U(...) \, +#define Z_IS_3069U_EQ_3069U(...) \, +#define Z_IS_3070_EQ_3070(...) \, +#define Z_IS_3070U_EQ_3070(...) \, +#define Z_IS_3070_EQ_3070U(...) \, +#define Z_IS_3070U_EQ_3070U(...) \, +#define Z_IS_3071_EQ_3071(...) \, +#define Z_IS_3071U_EQ_3071(...) \, +#define Z_IS_3071_EQ_3071U(...) \, +#define Z_IS_3071U_EQ_3071U(...) \, +#define Z_IS_3072_EQ_3072(...) \, +#define Z_IS_3072U_EQ_3072(...) \, +#define Z_IS_3072_EQ_3072U(...) \, +#define Z_IS_3072U_EQ_3072U(...) \, +#define Z_IS_3073_EQ_3073(...) \, +#define Z_IS_3073U_EQ_3073(...) \, +#define Z_IS_3073_EQ_3073U(...) \, +#define Z_IS_3073U_EQ_3073U(...) \, +#define Z_IS_3074_EQ_3074(...) \, +#define Z_IS_3074U_EQ_3074(...) \, +#define Z_IS_3074_EQ_3074U(...) \, +#define Z_IS_3074U_EQ_3074U(...) \, +#define Z_IS_3075_EQ_3075(...) \, +#define Z_IS_3075U_EQ_3075(...) \, +#define Z_IS_3075_EQ_3075U(...) \, +#define Z_IS_3075U_EQ_3075U(...) \, +#define Z_IS_3076_EQ_3076(...) \, +#define Z_IS_3076U_EQ_3076(...) \, +#define Z_IS_3076_EQ_3076U(...) \, +#define Z_IS_3076U_EQ_3076U(...) \, +#define Z_IS_3077_EQ_3077(...) \, +#define Z_IS_3077U_EQ_3077(...) \, +#define Z_IS_3077_EQ_3077U(...) \, +#define Z_IS_3077U_EQ_3077U(...) \, +#define Z_IS_3078_EQ_3078(...) \, +#define Z_IS_3078U_EQ_3078(...) \, +#define Z_IS_3078_EQ_3078U(...) \, +#define Z_IS_3078U_EQ_3078U(...) \, +#define Z_IS_3079_EQ_3079(...) \, +#define Z_IS_3079U_EQ_3079(...) \, +#define Z_IS_3079_EQ_3079U(...) \, +#define Z_IS_3079U_EQ_3079U(...) \, +#define Z_IS_3080_EQ_3080(...) \, +#define Z_IS_3080U_EQ_3080(...) \, +#define Z_IS_3080_EQ_3080U(...) \, +#define Z_IS_3080U_EQ_3080U(...) \, +#define Z_IS_3081_EQ_3081(...) \, +#define Z_IS_3081U_EQ_3081(...) \, +#define Z_IS_3081_EQ_3081U(...) \, +#define Z_IS_3081U_EQ_3081U(...) \, +#define Z_IS_3082_EQ_3082(...) \, +#define Z_IS_3082U_EQ_3082(...) \, +#define Z_IS_3082_EQ_3082U(...) \, +#define Z_IS_3082U_EQ_3082U(...) \, +#define Z_IS_3083_EQ_3083(...) \, +#define Z_IS_3083U_EQ_3083(...) \, +#define Z_IS_3083_EQ_3083U(...) \, +#define Z_IS_3083U_EQ_3083U(...) \, +#define Z_IS_3084_EQ_3084(...) \, +#define Z_IS_3084U_EQ_3084(...) \, +#define Z_IS_3084_EQ_3084U(...) \, +#define Z_IS_3084U_EQ_3084U(...) \, +#define Z_IS_3085_EQ_3085(...) \, +#define Z_IS_3085U_EQ_3085(...) \, +#define Z_IS_3085_EQ_3085U(...) \, +#define Z_IS_3085U_EQ_3085U(...) \, +#define Z_IS_3086_EQ_3086(...) \, +#define Z_IS_3086U_EQ_3086(...) \, +#define Z_IS_3086_EQ_3086U(...) \, +#define Z_IS_3086U_EQ_3086U(...) \, +#define Z_IS_3087_EQ_3087(...) \, +#define Z_IS_3087U_EQ_3087(...) \, +#define Z_IS_3087_EQ_3087U(...) \, +#define Z_IS_3087U_EQ_3087U(...) \, +#define Z_IS_3088_EQ_3088(...) \, +#define Z_IS_3088U_EQ_3088(...) \, +#define Z_IS_3088_EQ_3088U(...) \, +#define Z_IS_3088U_EQ_3088U(...) \, +#define Z_IS_3089_EQ_3089(...) \, +#define Z_IS_3089U_EQ_3089(...) \, +#define Z_IS_3089_EQ_3089U(...) \, +#define Z_IS_3089U_EQ_3089U(...) \, +#define Z_IS_3090_EQ_3090(...) \, +#define Z_IS_3090U_EQ_3090(...) \, +#define Z_IS_3090_EQ_3090U(...) \, +#define Z_IS_3090U_EQ_3090U(...) \, +#define Z_IS_3091_EQ_3091(...) \, +#define Z_IS_3091U_EQ_3091(...) \, +#define Z_IS_3091_EQ_3091U(...) \, +#define Z_IS_3091U_EQ_3091U(...) \, +#define Z_IS_3092_EQ_3092(...) \, +#define Z_IS_3092U_EQ_3092(...) \, +#define Z_IS_3092_EQ_3092U(...) \, +#define Z_IS_3092U_EQ_3092U(...) \, +#define Z_IS_3093_EQ_3093(...) \, +#define Z_IS_3093U_EQ_3093(...) \, +#define Z_IS_3093_EQ_3093U(...) \, +#define Z_IS_3093U_EQ_3093U(...) \, +#define Z_IS_3094_EQ_3094(...) \, +#define Z_IS_3094U_EQ_3094(...) \, +#define Z_IS_3094_EQ_3094U(...) \, +#define Z_IS_3094U_EQ_3094U(...) \, +#define Z_IS_3095_EQ_3095(...) \, +#define Z_IS_3095U_EQ_3095(...) \, +#define Z_IS_3095_EQ_3095U(...) \, +#define Z_IS_3095U_EQ_3095U(...) \, +#define Z_IS_3096_EQ_3096(...) \, +#define Z_IS_3096U_EQ_3096(...) \, +#define Z_IS_3096_EQ_3096U(...) \, +#define Z_IS_3096U_EQ_3096U(...) \, +#define Z_IS_3097_EQ_3097(...) \, +#define Z_IS_3097U_EQ_3097(...) \, +#define Z_IS_3097_EQ_3097U(...) \, +#define Z_IS_3097U_EQ_3097U(...) \, +#define Z_IS_3098_EQ_3098(...) \, +#define Z_IS_3098U_EQ_3098(...) \, +#define Z_IS_3098_EQ_3098U(...) \, +#define Z_IS_3098U_EQ_3098U(...) \, +#define Z_IS_3099_EQ_3099(...) \, +#define Z_IS_3099U_EQ_3099(...) \, +#define Z_IS_3099_EQ_3099U(...) \, +#define Z_IS_3099U_EQ_3099U(...) \, +#define Z_IS_3100_EQ_3100(...) \, +#define Z_IS_3100U_EQ_3100(...) \, +#define Z_IS_3100_EQ_3100U(...) \, +#define Z_IS_3100U_EQ_3100U(...) \, +#define Z_IS_3101_EQ_3101(...) \, +#define Z_IS_3101U_EQ_3101(...) \, +#define Z_IS_3101_EQ_3101U(...) \, +#define Z_IS_3101U_EQ_3101U(...) \, +#define Z_IS_3102_EQ_3102(...) \, +#define Z_IS_3102U_EQ_3102(...) \, +#define Z_IS_3102_EQ_3102U(...) \, +#define Z_IS_3102U_EQ_3102U(...) \, +#define Z_IS_3103_EQ_3103(...) \, +#define Z_IS_3103U_EQ_3103(...) \, +#define Z_IS_3103_EQ_3103U(...) \, +#define Z_IS_3103U_EQ_3103U(...) \, +#define Z_IS_3104_EQ_3104(...) \, +#define Z_IS_3104U_EQ_3104(...) \, +#define Z_IS_3104_EQ_3104U(...) \, +#define Z_IS_3104U_EQ_3104U(...) \, +#define Z_IS_3105_EQ_3105(...) \, +#define Z_IS_3105U_EQ_3105(...) \, +#define Z_IS_3105_EQ_3105U(...) \, +#define Z_IS_3105U_EQ_3105U(...) \, +#define Z_IS_3106_EQ_3106(...) \, +#define Z_IS_3106U_EQ_3106(...) \, +#define Z_IS_3106_EQ_3106U(...) \, +#define Z_IS_3106U_EQ_3106U(...) \, +#define Z_IS_3107_EQ_3107(...) \, +#define Z_IS_3107U_EQ_3107(...) \, +#define Z_IS_3107_EQ_3107U(...) \, +#define Z_IS_3107U_EQ_3107U(...) \, +#define Z_IS_3108_EQ_3108(...) \, +#define Z_IS_3108U_EQ_3108(...) \, +#define Z_IS_3108_EQ_3108U(...) \, +#define Z_IS_3108U_EQ_3108U(...) \, +#define Z_IS_3109_EQ_3109(...) \, +#define Z_IS_3109U_EQ_3109(...) \, +#define Z_IS_3109_EQ_3109U(...) \, +#define Z_IS_3109U_EQ_3109U(...) \, +#define Z_IS_3110_EQ_3110(...) \, +#define Z_IS_3110U_EQ_3110(...) \, +#define Z_IS_3110_EQ_3110U(...) \, +#define Z_IS_3110U_EQ_3110U(...) \, +#define Z_IS_3111_EQ_3111(...) \, +#define Z_IS_3111U_EQ_3111(...) \, +#define Z_IS_3111_EQ_3111U(...) \, +#define Z_IS_3111U_EQ_3111U(...) \, +#define Z_IS_3112_EQ_3112(...) \, +#define Z_IS_3112U_EQ_3112(...) \, +#define Z_IS_3112_EQ_3112U(...) \, +#define Z_IS_3112U_EQ_3112U(...) \, +#define Z_IS_3113_EQ_3113(...) \, +#define Z_IS_3113U_EQ_3113(...) \, +#define Z_IS_3113_EQ_3113U(...) \, +#define Z_IS_3113U_EQ_3113U(...) \, +#define Z_IS_3114_EQ_3114(...) \, +#define Z_IS_3114U_EQ_3114(...) \, +#define Z_IS_3114_EQ_3114U(...) \, +#define Z_IS_3114U_EQ_3114U(...) \, +#define Z_IS_3115_EQ_3115(...) \, +#define Z_IS_3115U_EQ_3115(...) \, +#define Z_IS_3115_EQ_3115U(...) \, +#define Z_IS_3115U_EQ_3115U(...) \, +#define Z_IS_3116_EQ_3116(...) \, +#define Z_IS_3116U_EQ_3116(...) \, +#define Z_IS_3116_EQ_3116U(...) \, +#define Z_IS_3116U_EQ_3116U(...) \, +#define Z_IS_3117_EQ_3117(...) \, +#define Z_IS_3117U_EQ_3117(...) \, +#define Z_IS_3117_EQ_3117U(...) \, +#define Z_IS_3117U_EQ_3117U(...) \, +#define Z_IS_3118_EQ_3118(...) \, +#define Z_IS_3118U_EQ_3118(...) \, +#define Z_IS_3118_EQ_3118U(...) \, +#define Z_IS_3118U_EQ_3118U(...) \, +#define Z_IS_3119_EQ_3119(...) \, +#define Z_IS_3119U_EQ_3119(...) \, +#define Z_IS_3119_EQ_3119U(...) \, +#define Z_IS_3119U_EQ_3119U(...) \, +#define Z_IS_3120_EQ_3120(...) \, +#define Z_IS_3120U_EQ_3120(...) \, +#define Z_IS_3120_EQ_3120U(...) \, +#define Z_IS_3120U_EQ_3120U(...) \, +#define Z_IS_3121_EQ_3121(...) \, +#define Z_IS_3121U_EQ_3121(...) \, +#define Z_IS_3121_EQ_3121U(...) \, +#define Z_IS_3121U_EQ_3121U(...) \, +#define Z_IS_3122_EQ_3122(...) \, +#define Z_IS_3122U_EQ_3122(...) \, +#define Z_IS_3122_EQ_3122U(...) \, +#define Z_IS_3122U_EQ_3122U(...) \, +#define Z_IS_3123_EQ_3123(...) \, +#define Z_IS_3123U_EQ_3123(...) \, +#define Z_IS_3123_EQ_3123U(...) \, +#define Z_IS_3123U_EQ_3123U(...) \, +#define Z_IS_3124_EQ_3124(...) \, +#define Z_IS_3124U_EQ_3124(...) \, +#define Z_IS_3124_EQ_3124U(...) \, +#define Z_IS_3124U_EQ_3124U(...) \, +#define Z_IS_3125_EQ_3125(...) \, +#define Z_IS_3125U_EQ_3125(...) \, +#define Z_IS_3125_EQ_3125U(...) \, +#define Z_IS_3125U_EQ_3125U(...) \, +#define Z_IS_3126_EQ_3126(...) \, +#define Z_IS_3126U_EQ_3126(...) \, +#define Z_IS_3126_EQ_3126U(...) \, +#define Z_IS_3126U_EQ_3126U(...) \, +#define Z_IS_3127_EQ_3127(...) \, +#define Z_IS_3127U_EQ_3127(...) \, +#define Z_IS_3127_EQ_3127U(...) \, +#define Z_IS_3127U_EQ_3127U(...) \, +#define Z_IS_3128_EQ_3128(...) \, +#define Z_IS_3128U_EQ_3128(...) \, +#define Z_IS_3128_EQ_3128U(...) \, +#define Z_IS_3128U_EQ_3128U(...) \, +#define Z_IS_3129_EQ_3129(...) \, +#define Z_IS_3129U_EQ_3129(...) \, +#define Z_IS_3129_EQ_3129U(...) \, +#define Z_IS_3129U_EQ_3129U(...) \, +#define Z_IS_3130_EQ_3130(...) \, +#define Z_IS_3130U_EQ_3130(...) \, +#define Z_IS_3130_EQ_3130U(...) \, +#define Z_IS_3130U_EQ_3130U(...) \, +#define Z_IS_3131_EQ_3131(...) \, +#define Z_IS_3131U_EQ_3131(...) \, +#define Z_IS_3131_EQ_3131U(...) \, +#define Z_IS_3131U_EQ_3131U(...) \, +#define Z_IS_3132_EQ_3132(...) \, +#define Z_IS_3132U_EQ_3132(...) \, +#define Z_IS_3132_EQ_3132U(...) \, +#define Z_IS_3132U_EQ_3132U(...) \, +#define Z_IS_3133_EQ_3133(...) \, +#define Z_IS_3133U_EQ_3133(...) \, +#define Z_IS_3133_EQ_3133U(...) \, +#define Z_IS_3133U_EQ_3133U(...) \, +#define Z_IS_3134_EQ_3134(...) \, +#define Z_IS_3134U_EQ_3134(...) \, +#define Z_IS_3134_EQ_3134U(...) \, +#define Z_IS_3134U_EQ_3134U(...) \, +#define Z_IS_3135_EQ_3135(...) \, +#define Z_IS_3135U_EQ_3135(...) \, +#define Z_IS_3135_EQ_3135U(...) \, +#define Z_IS_3135U_EQ_3135U(...) \, +#define Z_IS_3136_EQ_3136(...) \, +#define Z_IS_3136U_EQ_3136(...) \, +#define Z_IS_3136_EQ_3136U(...) \, +#define Z_IS_3136U_EQ_3136U(...) \, +#define Z_IS_3137_EQ_3137(...) \, +#define Z_IS_3137U_EQ_3137(...) \, +#define Z_IS_3137_EQ_3137U(...) \, +#define Z_IS_3137U_EQ_3137U(...) \, +#define Z_IS_3138_EQ_3138(...) \, +#define Z_IS_3138U_EQ_3138(...) \, +#define Z_IS_3138_EQ_3138U(...) \, +#define Z_IS_3138U_EQ_3138U(...) \, +#define Z_IS_3139_EQ_3139(...) \, +#define Z_IS_3139U_EQ_3139(...) \, +#define Z_IS_3139_EQ_3139U(...) \, +#define Z_IS_3139U_EQ_3139U(...) \, +#define Z_IS_3140_EQ_3140(...) \, +#define Z_IS_3140U_EQ_3140(...) \, +#define Z_IS_3140_EQ_3140U(...) \, +#define Z_IS_3140U_EQ_3140U(...) \, +#define Z_IS_3141_EQ_3141(...) \, +#define Z_IS_3141U_EQ_3141(...) \, +#define Z_IS_3141_EQ_3141U(...) \, +#define Z_IS_3141U_EQ_3141U(...) \, +#define Z_IS_3142_EQ_3142(...) \, +#define Z_IS_3142U_EQ_3142(...) \, +#define Z_IS_3142_EQ_3142U(...) \, +#define Z_IS_3142U_EQ_3142U(...) \, +#define Z_IS_3143_EQ_3143(...) \, +#define Z_IS_3143U_EQ_3143(...) \, +#define Z_IS_3143_EQ_3143U(...) \, +#define Z_IS_3143U_EQ_3143U(...) \, +#define Z_IS_3144_EQ_3144(...) \, +#define Z_IS_3144U_EQ_3144(...) \, +#define Z_IS_3144_EQ_3144U(...) \, +#define Z_IS_3144U_EQ_3144U(...) \, +#define Z_IS_3145_EQ_3145(...) \, +#define Z_IS_3145U_EQ_3145(...) \, +#define Z_IS_3145_EQ_3145U(...) \, +#define Z_IS_3145U_EQ_3145U(...) \, +#define Z_IS_3146_EQ_3146(...) \, +#define Z_IS_3146U_EQ_3146(...) \, +#define Z_IS_3146_EQ_3146U(...) \, +#define Z_IS_3146U_EQ_3146U(...) \, +#define Z_IS_3147_EQ_3147(...) \, +#define Z_IS_3147U_EQ_3147(...) \, +#define Z_IS_3147_EQ_3147U(...) \, +#define Z_IS_3147U_EQ_3147U(...) \, +#define Z_IS_3148_EQ_3148(...) \, +#define Z_IS_3148U_EQ_3148(...) \, +#define Z_IS_3148_EQ_3148U(...) \, +#define Z_IS_3148U_EQ_3148U(...) \, +#define Z_IS_3149_EQ_3149(...) \, +#define Z_IS_3149U_EQ_3149(...) \, +#define Z_IS_3149_EQ_3149U(...) \, +#define Z_IS_3149U_EQ_3149U(...) \, +#define Z_IS_3150_EQ_3150(...) \, +#define Z_IS_3150U_EQ_3150(...) \, +#define Z_IS_3150_EQ_3150U(...) \, +#define Z_IS_3150U_EQ_3150U(...) \, +#define Z_IS_3151_EQ_3151(...) \, +#define Z_IS_3151U_EQ_3151(...) \, +#define Z_IS_3151_EQ_3151U(...) \, +#define Z_IS_3151U_EQ_3151U(...) \, +#define Z_IS_3152_EQ_3152(...) \, +#define Z_IS_3152U_EQ_3152(...) \, +#define Z_IS_3152_EQ_3152U(...) \, +#define Z_IS_3152U_EQ_3152U(...) \, +#define Z_IS_3153_EQ_3153(...) \, +#define Z_IS_3153U_EQ_3153(...) \, +#define Z_IS_3153_EQ_3153U(...) \, +#define Z_IS_3153U_EQ_3153U(...) \, +#define Z_IS_3154_EQ_3154(...) \, +#define Z_IS_3154U_EQ_3154(...) \, +#define Z_IS_3154_EQ_3154U(...) \, +#define Z_IS_3154U_EQ_3154U(...) \, +#define Z_IS_3155_EQ_3155(...) \, +#define Z_IS_3155U_EQ_3155(...) \, +#define Z_IS_3155_EQ_3155U(...) \, +#define Z_IS_3155U_EQ_3155U(...) \, +#define Z_IS_3156_EQ_3156(...) \, +#define Z_IS_3156U_EQ_3156(...) \, +#define Z_IS_3156_EQ_3156U(...) \, +#define Z_IS_3156U_EQ_3156U(...) \, +#define Z_IS_3157_EQ_3157(...) \, +#define Z_IS_3157U_EQ_3157(...) \, +#define Z_IS_3157_EQ_3157U(...) \, +#define Z_IS_3157U_EQ_3157U(...) \, +#define Z_IS_3158_EQ_3158(...) \, +#define Z_IS_3158U_EQ_3158(...) \, +#define Z_IS_3158_EQ_3158U(...) \, +#define Z_IS_3158U_EQ_3158U(...) \, +#define Z_IS_3159_EQ_3159(...) \, +#define Z_IS_3159U_EQ_3159(...) \, +#define Z_IS_3159_EQ_3159U(...) \, +#define Z_IS_3159U_EQ_3159U(...) \, +#define Z_IS_3160_EQ_3160(...) \, +#define Z_IS_3160U_EQ_3160(...) \, +#define Z_IS_3160_EQ_3160U(...) \, +#define Z_IS_3160U_EQ_3160U(...) \, +#define Z_IS_3161_EQ_3161(...) \, +#define Z_IS_3161U_EQ_3161(...) \, +#define Z_IS_3161_EQ_3161U(...) \, +#define Z_IS_3161U_EQ_3161U(...) \, +#define Z_IS_3162_EQ_3162(...) \, +#define Z_IS_3162U_EQ_3162(...) \, +#define Z_IS_3162_EQ_3162U(...) \, +#define Z_IS_3162U_EQ_3162U(...) \, +#define Z_IS_3163_EQ_3163(...) \, +#define Z_IS_3163U_EQ_3163(...) \, +#define Z_IS_3163_EQ_3163U(...) \, +#define Z_IS_3163U_EQ_3163U(...) \, +#define Z_IS_3164_EQ_3164(...) \, +#define Z_IS_3164U_EQ_3164(...) \, +#define Z_IS_3164_EQ_3164U(...) \, +#define Z_IS_3164U_EQ_3164U(...) \, +#define Z_IS_3165_EQ_3165(...) \, +#define Z_IS_3165U_EQ_3165(...) \, +#define Z_IS_3165_EQ_3165U(...) \, +#define Z_IS_3165U_EQ_3165U(...) \, +#define Z_IS_3166_EQ_3166(...) \, +#define Z_IS_3166U_EQ_3166(...) \, +#define Z_IS_3166_EQ_3166U(...) \, +#define Z_IS_3166U_EQ_3166U(...) \, +#define Z_IS_3167_EQ_3167(...) \, +#define Z_IS_3167U_EQ_3167(...) \, +#define Z_IS_3167_EQ_3167U(...) \, +#define Z_IS_3167U_EQ_3167U(...) \, +#define Z_IS_3168_EQ_3168(...) \, +#define Z_IS_3168U_EQ_3168(...) \, +#define Z_IS_3168_EQ_3168U(...) \, +#define Z_IS_3168U_EQ_3168U(...) \, +#define Z_IS_3169_EQ_3169(...) \, +#define Z_IS_3169U_EQ_3169(...) \, +#define Z_IS_3169_EQ_3169U(...) \, +#define Z_IS_3169U_EQ_3169U(...) \, +#define Z_IS_3170_EQ_3170(...) \, +#define Z_IS_3170U_EQ_3170(...) \, +#define Z_IS_3170_EQ_3170U(...) \, +#define Z_IS_3170U_EQ_3170U(...) \, +#define Z_IS_3171_EQ_3171(...) \, +#define Z_IS_3171U_EQ_3171(...) \, +#define Z_IS_3171_EQ_3171U(...) \, +#define Z_IS_3171U_EQ_3171U(...) \, +#define Z_IS_3172_EQ_3172(...) \, +#define Z_IS_3172U_EQ_3172(...) \, +#define Z_IS_3172_EQ_3172U(...) \, +#define Z_IS_3172U_EQ_3172U(...) \, +#define Z_IS_3173_EQ_3173(...) \, +#define Z_IS_3173U_EQ_3173(...) \, +#define Z_IS_3173_EQ_3173U(...) \, +#define Z_IS_3173U_EQ_3173U(...) \, +#define Z_IS_3174_EQ_3174(...) \, +#define Z_IS_3174U_EQ_3174(...) \, +#define Z_IS_3174_EQ_3174U(...) \, +#define Z_IS_3174U_EQ_3174U(...) \, +#define Z_IS_3175_EQ_3175(...) \, +#define Z_IS_3175U_EQ_3175(...) \, +#define Z_IS_3175_EQ_3175U(...) \, +#define Z_IS_3175U_EQ_3175U(...) \, +#define Z_IS_3176_EQ_3176(...) \, +#define Z_IS_3176U_EQ_3176(...) \, +#define Z_IS_3176_EQ_3176U(...) \, +#define Z_IS_3176U_EQ_3176U(...) \, +#define Z_IS_3177_EQ_3177(...) \, +#define Z_IS_3177U_EQ_3177(...) \, +#define Z_IS_3177_EQ_3177U(...) \, +#define Z_IS_3177U_EQ_3177U(...) \, +#define Z_IS_3178_EQ_3178(...) \, +#define Z_IS_3178U_EQ_3178(...) \, +#define Z_IS_3178_EQ_3178U(...) \, +#define Z_IS_3178U_EQ_3178U(...) \, +#define Z_IS_3179_EQ_3179(...) \, +#define Z_IS_3179U_EQ_3179(...) \, +#define Z_IS_3179_EQ_3179U(...) \, +#define Z_IS_3179U_EQ_3179U(...) \, +#define Z_IS_3180_EQ_3180(...) \, +#define Z_IS_3180U_EQ_3180(...) \, +#define Z_IS_3180_EQ_3180U(...) \, +#define Z_IS_3180U_EQ_3180U(...) \, +#define Z_IS_3181_EQ_3181(...) \, +#define Z_IS_3181U_EQ_3181(...) \, +#define Z_IS_3181_EQ_3181U(...) \, +#define Z_IS_3181U_EQ_3181U(...) \, +#define Z_IS_3182_EQ_3182(...) \, +#define Z_IS_3182U_EQ_3182(...) \, +#define Z_IS_3182_EQ_3182U(...) \, +#define Z_IS_3182U_EQ_3182U(...) \, +#define Z_IS_3183_EQ_3183(...) \, +#define Z_IS_3183U_EQ_3183(...) \, +#define Z_IS_3183_EQ_3183U(...) \, +#define Z_IS_3183U_EQ_3183U(...) \, +#define Z_IS_3184_EQ_3184(...) \, +#define Z_IS_3184U_EQ_3184(...) \, +#define Z_IS_3184_EQ_3184U(...) \, +#define Z_IS_3184U_EQ_3184U(...) \, +#define Z_IS_3185_EQ_3185(...) \, +#define Z_IS_3185U_EQ_3185(...) \, +#define Z_IS_3185_EQ_3185U(...) \, +#define Z_IS_3185U_EQ_3185U(...) \, +#define Z_IS_3186_EQ_3186(...) \, +#define Z_IS_3186U_EQ_3186(...) \, +#define Z_IS_3186_EQ_3186U(...) \, +#define Z_IS_3186U_EQ_3186U(...) \, +#define Z_IS_3187_EQ_3187(...) \, +#define Z_IS_3187U_EQ_3187(...) \, +#define Z_IS_3187_EQ_3187U(...) \, +#define Z_IS_3187U_EQ_3187U(...) \, +#define Z_IS_3188_EQ_3188(...) \, +#define Z_IS_3188U_EQ_3188(...) \, +#define Z_IS_3188_EQ_3188U(...) \, +#define Z_IS_3188U_EQ_3188U(...) \, +#define Z_IS_3189_EQ_3189(...) \, +#define Z_IS_3189U_EQ_3189(...) \, +#define Z_IS_3189_EQ_3189U(...) \, +#define Z_IS_3189U_EQ_3189U(...) \, +#define Z_IS_3190_EQ_3190(...) \, +#define Z_IS_3190U_EQ_3190(...) \, +#define Z_IS_3190_EQ_3190U(...) \, +#define Z_IS_3190U_EQ_3190U(...) \, +#define Z_IS_3191_EQ_3191(...) \, +#define Z_IS_3191U_EQ_3191(...) \, +#define Z_IS_3191_EQ_3191U(...) \, +#define Z_IS_3191U_EQ_3191U(...) \, +#define Z_IS_3192_EQ_3192(...) \, +#define Z_IS_3192U_EQ_3192(...) \, +#define Z_IS_3192_EQ_3192U(...) \, +#define Z_IS_3192U_EQ_3192U(...) \, +#define Z_IS_3193_EQ_3193(...) \, +#define Z_IS_3193U_EQ_3193(...) \, +#define Z_IS_3193_EQ_3193U(...) \, +#define Z_IS_3193U_EQ_3193U(...) \, +#define Z_IS_3194_EQ_3194(...) \, +#define Z_IS_3194U_EQ_3194(...) \, +#define Z_IS_3194_EQ_3194U(...) \, +#define Z_IS_3194U_EQ_3194U(...) \, +#define Z_IS_3195_EQ_3195(...) \, +#define Z_IS_3195U_EQ_3195(...) \, +#define Z_IS_3195_EQ_3195U(...) \, +#define Z_IS_3195U_EQ_3195U(...) \, +#define Z_IS_3196_EQ_3196(...) \, +#define Z_IS_3196U_EQ_3196(...) \, +#define Z_IS_3196_EQ_3196U(...) \, +#define Z_IS_3196U_EQ_3196U(...) \, +#define Z_IS_3197_EQ_3197(...) \, +#define Z_IS_3197U_EQ_3197(...) \, +#define Z_IS_3197_EQ_3197U(...) \, +#define Z_IS_3197U_EQ_3197U(...) \, +#define Z_IS_3198_EQ_3198(...) \, +#define Z_IS_3198U_EQ_3198(...) \, +#define Z_IS_3198_EQ_3198U(...) \, +#define Z_IS_3198U_EQ_3198U(...) \, +#define Z_IS_3199_EQ_3199(...) \, +#define Z_IS_3199U_EQ_3199(...) \, +#define Z_IS_3199_EQ_3199U(...) \, +#define Z_IS_3199U_EQ_3199U(...) \, +#define Z_IS_3200_EQ_3200(...) \, +#define Z_IS_3200U_EQ_3200(...) \, +#define Z_IS_3200_EQ_3200U(...) \, +#define Z_IS_3200U_EQ_3200U(...) \, +#define Z_IS_3201_EQ_3201(...) \, +#define Z_IS_3201U_EQ_3201(...) \, +#define Z_IS_3201_EQ_3201U(...) \, +#define Z_IS_3201U_EQ_3201U(...) \, +#define Z_IS_3202_EQ_3202(...) \, +#define Z_IS_3202U_EQ_3202(...) \, +#define Z_IS_3202_EQ_3202U(...) \, +#define Z_IS_3202U_EQ_3202U(...) \, +#define Z_IS_3203_EQ_3203(...) \, +#define Z_IS_3203U_EQ_3203(...) \, +#define Z_IS_3203_EQ_3203U(...) \, +#define Z_IS_3203U_EQ_3203U(...) \, +#define Z_IS_3204_EQ_3204(...) \, +#define Z_IS_3204U_EQ_3204(...) \, +#define Z_IS_3204_EQ_3204U(...) \, +#define Z_IS_3204U_EQ_3204U(...) \, +#define Z_IS_3205_EQ_3205(...) \, +#define Z_IS_3205U_EQ_3205(...) \, +#define Z_IS_3205_EQ_3205U(...) \, +#define Z_IS_3205U_EQ_3205U(...) \, +#define Z_IS_3206_EQ_3206(...) \, +#define Z_IS_3206U_EQ_3206(...) \, +#define Z_IS_3206_EQ_3206U(...) \, +#define Z_IS_3206U_EQ_3206U(...) \, +#define Z_IS_3207_EQ_3207(...) \, +#define Z_IS_3207U_EQ_3207(...) \, +#define Z_IS_3207_EQ_3207U(...) \, +#define Z_IS_3207U_EQ_3207U(...) \, +#define Z_IS_3208_EQ_3208(...) \, +#define Z_IS_3208U_EQ_3208(...) \, +#define Z_IS_3208_EQ_3208U(...) \, +#define Z_IS_3208U_EQ_3208U(...) \, +#define Z_IS_3209_EQ_3209(...) \, +#define Z_IS_3209U_EQ_3209(...) \, +#define Z_IS_3209_EQ_3209U(...) \, +#define Z_IS_3209U_EQ_3209U(...) \, +#define Z_IS_3210_EQ_3210(...) \, +#define Z_IS_3210U_EQ_3210(...) \, +#define Z_IS_3210_EQ_3210U(...) \, +#define Z_IS_3210U_EQ_3210U(...) \, +#define Z_IS_3211_EQ_3211(...) \, +#define Z_IS_3211U_EQ_3211(...) \, +#define Z_IS_3211_EQ_3211U(...) \, +#define Z_IS_3211U_EQ_3211U(...) \, +#define Z_IS_3212_EQ_3212(...) \, +#define Z_IS_3212U_EQ_3212(...) \, +#define Z_IS_3212_EQ_3212U(...) \, +#define Z_IS_3212U_EQ_3212U(...) \, +#define Z_IS_3213_EQ_3213(...) \, +#define Z_IS_3213U_EQ_3213(...) \, +#define Z_IS_3213_EQ_3213U(...) \, +#define Z_IS_3213U_EQ_3213U(...) \, +#define Z_IS_3214_EQ_3214(...) \, +#define Z_IS_3214U_EQ_3214(...) \, +#define Z_IS_3214_EQ_3214U(...) \, +#define Z_IS_3214U_EQ_3214U(...) \, +#define Z_IS_3215_EQ_3215(...) \, +#define Z_IS_3215U_EQ_3215(...) \, +#define Z_IS_3215_EQ_3215U(...) \, +#define Z_IS_3215U_EQ_3215U(...) \, +#define Z_IS_3216_EQ_3216(...) \, +#define Z_IS_3216U_EQ_3216(...) \, +#define Z_IS_3216_EQ_3216U(...) \, +#define Z_IS_3216U_EQ_3216U(...) \, +#define Z_IS_3217_EQ_3217(...) \, +#define Z_IS_3217U_EQ_3217(...) \, +#define Z_IS_3217_EQ_3217U(...) \, +#define Z_IS_3217U_EQ_3217U(...) \, +#define Z_IS_3218_EQ_3218(...) \, +#define Z_IS_3218U_EQ_3218(...) \, +#define Z_IS_3218_EQ_3218U(...) \, +#define Z_IS_3218U_EQ_3218U(...) \, +#define Z_IS_3219_EQ_3219(...) \, +#define Z_IS_3219U_EQ_3219(...) \, +#define Z_IS_3219_EQ_3219U(...) \, +#define Z_IS_3219U_EQ_3219U(...) \, +#define Z_IS_3220_EQ_3220(...) \, +#define Z_IS_3220U_EQ_3220(...) \, +#define Z_IS_3220_EQ_3220U(...) \, +#define Z_IS_3220U_EQ_3220U(...) \, +#define Z_IS_3221_EQ_3221(...) \, +#define Z_IS_3221U_EQ_3221(...) \, +#define Z_IS_3221_EQ_3221U(...) \, +#define Z_IS_3221U_EQ_3221U(...) \, +#define Z_IS_3222_EQ_3222(...) \, +#define Z_IS_3222U_EQ_3222(...) \, +#define Z_IS_3222_EQ_3222U(...) \, +#define Z_IS_3222U_EQ_3222U(...) \, +#define Z_IS_3223_EQ_3223(...) \, +#define Z_IS_3223U_EQ_3223(...) \, +#define Z_IS_3223_EQ_3223U(...) \, +#define Z_IS_3223U_EQ_3223U(...) \, +#define Z_IS_3224_EQ_3224(...) \, +#define Z_IS_3224U_EQ_3224(...) \, +#define Z_IS_3224_EQ_3224U(...) \, +#define Z_IS_3224U_EQ_3224U(...) \, +#define Z_IS_3225_EQ_3225(...) \, +#define Z_IS_3225U_EQ_3225(...) \, +#define Z_IS_3225_EQ_3225U(...) \, +#define Z_IS_3225U_EQ_3225U(...) \, +#define Z_IS_3226_EQ_3226(...) \, +#define Z_IS_3226U_EQ_3226(...) \, +#define Z_IS_3226_EQ_3226U(...) \, +#define Z_IS_3226U_EQ_3226U(...) \, +#define Z_IS_3227_EQ_3227(...) \, +#define Z_IS_3227U_EQ_3227(...) \, +#define Z_IS_3227_EQ_3227U(...) \, +#define Z_IS_3227U_EQ_3227U(...) \, +#define Z_IS_3228_EQ_3228(...) \, +#define Z_IS_3228U_EQ_3228(...) \, +#define Z_IS_3228_EQ_3228U(...) \, +#define Z_IS_3228U_EQ_3228U(...) \, +#define Z_IS_3229_EQ_3229(...) \, +#define Z_IS_3229U_EQ_3229(...) \, +#define Z_IS_3229_EQ_3229U(...) \, +#define Z_IS_3229U_EQ_3229U(...) \, +#define Z_IS_3230_EQ_3230(...) \, +#define Z_IS_3230U_EQ_3230(...) \, +#define Z_IS_3230_EQ_3230U(...) \, +#define Z_IS_3230U_EQ_3230U(...) \, +#define Z_IS_3231_EQ_3231(...) \, +#define Z_IS_3231U_EQ_3231(...) \, +#define Z_IS_3231_EQ_3231U(...) \, +#define Z_IS_3231U_EQ_3231U(...) \, +#define Z_IS_3232_EQ_3232(...) \, +#define Z_IS_3232U_EQ_3232(...) \, +#define Z_IS_3232_EQ_3232U(...) \, +#define Z_IS_3232U_EQ_3232U(...) \, +#define Z_IS_3233_EQ_3233(...) \, +#define Z_IS_3233U_EQ_3233(...) \, +#define Z_IS_3233_EQ_3233U(...) \, +#define Z_IS_3233U_EQ_3233U(...) \, +#define Z_IS_3234_EQ_3234(...) \, +#define Z_IS_3234U_EQ_3234(...) \, +#define Z_IS_3234_EQ_3234U(...) \, +#define Z_IS_3234U_EQ_3234U(...) \, +#define Z_IS_3235_EQ_3235(...) \, +#define Z_IS_3235U_EQ_3235(...) \, +#define Z_IS_3235_EQ_3235U(...) \, +#define Z_IS_3235U_EQ_3235U(...) \, +#define Z_IS_3236_EQ_3236(...) \, +#define Z_IS_3236U_EQ_3236(...) \, +#define Z_IS_3236_EQ_3236U(...) \, +#define Z_IS_3236U_EQ_3236U(...) \, +#define Z_IS_3237_EQ_3237(...) \, +#define Z_IS_3237U_EQ_3237(...) \, +#define Z_IS_3237_EQ_3237U(...) \, +#define Z_IS_3237U_EQ_3237U(...) \, +#define Z_IS_3238_EQ_3238(...) \, +#define Z_IS_3238U_EQ_3238(...) \, +#define Z_IS_3238_EQ_3238U(...) \, +#define Z_IS_3238U_EQ_3238U(...) \, +#define Z_IS_3239_EQ_3239(...) \, +#define Z_IS_3239U_EQ_3239(...) \, +#define Z_IS_3239_EQ_3239U(...) \, +#define Z_IS_3239U_EQ_3239U(...) \, +#define Z_IS_3240_EQ_3240(...) \, +#define Z_IS_3240U_EQ_3240(...) \, +#define Z_IS_3240_EQ_3240U(...) \, +#define Z_IS_3240U_EQ_3240U(...) \, +#define Z_IS_3241_EQ_3241(...) \, +#define Z_IS_3241U_EQ_3241(...) \, +#define Z_IS_3241_EQ_3241U(...) \, +#define Z_IS_3241U_EQ_3241U(...) \, +#define Z_IS_3242_EQ_3242(...) \, +#define Z_IS_3242U_EQ_3242(...) \, +#define Z_IS_3242_EQ_3242U(...) \, +#define Z_IS_3242U_EQ_3242U(...) \, +#define Z_IS_3243_EQ_3243(...) \, +#define Z_IS_3243U_EQ_3243(...) \, +#define Z_IS_3243_EQ_3243U(...) \, +#define Z_IS_3243U_EQ_3243U(...) \, +#define Z_IS_3244_EQ_3244(...) \, +#define Z_IS_3244U_EQ_3244(...) \, +#define Z_IS_3244_EQ_3244U(...) \, +#define Z_IS_3244U_EQ_3244U(...) \, +#define Z_IS_3245_EQ_3245(...) \, +#define Z_IS_3245U_EQ_3245(...) \, +#define Z_IS_3245_EQ_3245U(...) \, +#define Z_IS_3245U_EQ_3245U(...) \, +#define Z_IS_3246_EQ_3246(...) \, +#define Z_IS_3246U_EQ_3246(...) \, +#define Z_IS_3246_EQ_3246U(...) \, +#define Z_IS_3246U_EQ_3246U(...) \, +#define Z_IS_3247_EQ_3247(...) \, +#define Z_IS_3247U_EQ_3247(...) \, +#define Z_IS_3247_EQ_3247U(...) \, +#define Z_IS_3247U_EQ_3247U(...) \, +#define Z_IS_3248_EQ_3248(...) \, +#define Z_IS_3248U_EQ_3248(...) \, +#define Z_IS_3248_EQ_3248U(...) \, +#define Z_IS_3248U_EQ_3248U(...) \, +#define Z_IS_3249_EQ_3249(...) \, +#define Z_IS_3249U_EQ_3249(...) \, +#define Z_IS_3249_EQ_3249U(...) \, +#define Z_IS_3249U_EQ_3249U(...) \, +#define Z_IS_3250_EQ_3250(...) \, +#define Z_IS_3250U_EQ_3250(...) \, +#define Z_IS_3250_EQ_3250U(...) \, +#define Z_IS_3250U_EQ_3250U(...) \, +#define Z_IS_3251_EQ_3251(...) \, +#define Z_IS_3251U_EQ_3251(...) \, +#define Z_IS_3251_EQ_3251U(...) \, +#define Z_IS_3251U_EQ_3251U(...) \, +#define Z_IS_3252_EQ_3252(...) \, +#define Z_IS_3252U_EQ_3252(...) \, +#define Z_IS_3252_EQ_3252U(...) \, +#define Z_IS_3252U_EQ_3252U(...) \, +#define Z_IS_3253_EQ_3253(...) \, +#define Z_IS_3253U_EQ_3253(...) \, +#define Z_IS_3253_EQ_3253U(...) \, +#define Z_IS_3253U_EQ_3253U(...) \, +#define Z_IS_3254_EQ_3254(...) \, +#define Z_IS_3254U_EQ_3254(...) \, +#define Z_IS_3254_EQ_3254U(...) \, +#define Z_IS_3254U_EQ_3254U(...) \, +#define Z_IS_3255_EQ_3255(...) \, +#define Z_IS_3255U_EQ_3255(...) \, +#define Z_IS_3255_EQ_3255U(...) \, +#define Z_IS_3255U_EQ_3255U(...) \, +#define Z_IS_3256_EQ_3256(...) \, +#define Z_IS_3256U_EQ_3256(...) \, +#define Z_IS_3256_EQ_3256U(...) \, +#define Z_IS_3256U_EQ_3256U(...) \, +#define Z_IS_3257_EQ_3257(...) \, +#define Z_IS_3257U_EQ_3257(...) \, +#define Z_IS_3257_EQ_3257U(...) \, +#define Z_IS_3257U_EQ_3257U(...) \, +#define Z_IS_3258_EQ_3258(...) \, +#define Z_IS_3258U_EQ_3258(...) \, +#define Z_IS_3258_EQ_3258U(...) \, +#define Z_IS_3258U_EQ_3258U(...) \, +#define Z_IS_3259_EQ_3259(...) \, +#define Z_IS_3259U_EQ_3259(...) \, +#define Z_IS_3259_EQ_3259U(...) \, +#define Z_IS_3259U_EQ_3259U(...) \, +#define Z_IS_3260_EQ_3260(...) \, +#define Z_IS_3260U_EQ_3260(...) \, +#define Z_IS_3260_EQ_3260U(...) \, +#define Z_IS_3260U_EQ_3260U(...) \, +#define Z_IS_3261_EQ_3261(...) \, +#define Z_IS_3261U_EQ_3261(...) \, +#define Z_IS_3261_EQ_3261U(...) \, +#define Z_IS_3261U_EQ_3261U(...) \, +#define Z_IS_3262_EQ_3262(...) \, +#define Z_IS_3262U_EQ_3262(...) \, +#define Z_IS_3262_EQ_3262U(...) \, +#define Z_IS_3262U_EQ_3262U(...) \, +#define Z_IS_3263_EQ_3263(...) \, +#define Z_IS_3263U_EQ_3263(...) \, +#define Z_IS_3263_EQ_3263U(...) \, +#define Z_IS_3263U_EQ_3263U(...) \, +#define Z_IS_3264_EQ_3264(...) \, +#define Z_IS_3264U_EQ_3264(...) \, +#define Z_IS_3264_EQ_3264U(...) \, +#define Z_IS_3264U_EQ_3264U(...) \, +#define Z_IS_3265_EQ_3265(...) \, +#define Z_IS_3265U_EQ_3265(...) \, +#define Z_IS_3265_EQ_3265U(...) \, +#define Z_IS_3265U_EQ_3265U(...) \, +#define Z_IS_3266_EQ_3266(...) \, +#define Z_IS_3266U_EQ_3266(...) \, +#define Z_IS_3266_EQ_3266U(...) \, +#define Z_IS_3266U_EQ_3266U(...) \, +#define Z_IS_3267_EQ_3267(...) \, +#define Z_IS_3267U_EQ_3267(...) \, +#define Z_IS_3267_EQ_3267U(...) \, +#define Z_IS_3267U_EQ_3267U(...) \, +#define Z_IS_3268_EQ_3268(...) \, +#define Z_IS_3268U_EQ_3268(...) \, +#define Z_IS_3268_EQ_3268U(...) \, +#define Z_IS_3268U_EQ_3268U(...) \, +#define Z_IS_3269_EQ_3269(...) \, +#define Z_IS_3269U_EQ_3269(...) \, +#define Z_IS_3269_EQ_3269U(...) \, +#define Z_IS_3269U_EQ_3269U(...) \, +#define Z_IS_3270_EQ_3270(...) \, +#define Z_IS_3270U_EQ_3270(...) \, +#define Z_IS_3270_EQ_3270U(...) \, +#define Z_IS_3270U_EQ_3270U(...) \, +#define Z_IS_3271_EQ_3271(...) \, +#define Z_IS_3271U_EQ_3271(...) \, +#define Z_IS_3271_EQ_3271U(...) \, +#define Z_IS_3271U_EQ_3271U(...) \, +#define Z_IS_3272_EQ_3272(...) \, +#define Z_IS_3272U_EQ_3272(...) \, +#define Z_IS_3272_EQ_3272U(...) \, +#define Z_IS_3272U_EQ_3272U(...) \, +#define Z_IS_3273_EQ_3273(...) \, +#define Z_IS_3273U_EQ_3273(...) \, +#define Z_IS_3273_EQ_3273U(...) \, +#define Z_IS_3273U_EQ_3273U(...) \, +#define Z_IS_3274_EQ_3274(...) \, +#define Z_IS_3274U_EQ_3274(...) \, +#define Z_IS_3274_EQ_3274U(...) \, +#define Z_IS_3274U_EQ_3274U(...) \, +#define Z_IS_3275_EQ_3275(...) \, +#define Z_IS_3275U_EQ_3275(...) \, +#define Z_IS_3275_EQ_3275U(...) \, +#define Z_IS_3275U_EQ_3275U(...) \, +#define Z_IS_3276_EQ_3276(...) \, +#define Z_IS_3276U_EQ_3276(...) \, +#define Z_IS_3276_EQ_3276U(...) \, +#define Z_IS_3276U_EQ_3276U(...) \, +#define Z_IS_3277_EQ_3277(...) \, +#define Z_IS_3277U_EQ_3277(...) \, +#define Z_IS_3277_EQ_3277U(...) \, +#define Z_IS_3277U_EQ_3277U(...) \, +#define Z_IS_3278_EQ_3278(...) \, +#define Z_IS_3278U_EQ_3278(...) \, +#define Z_IS_3278_EQ_3278U(...) \, +#define Z_IS_3278U_EQ_3278U(...) \, +#define Z_IS_3279_EQ_3279(...) \, +#define Z_IS_3279U_EQ_3279(...) \, +#define Z_IS_3279_EQ_3279U(...) \, +#define Z_IS_3279U_EQ_3279U(...) \, +#define Z_IS_3280_EQ_3280(...) \, +#define Z_IS_3280U_EQ_3280(...) \, +#define Z_IS_3280_EQ_3280U(...) \, +#define Z_IS_3280U_EQ_3280U(...) \, +#define Z_IS_3281_EQ_3281(...) \, +#define Z_IS_3281U_EQ_3281(...) \, +#define Z_IS_3281_EQ_3281U(...) \, +#define Z_IS_3281U_EQ_3281U(...) \, +#define Z_IS_3282_EQ_3282(...) \, +#define Z_IS_3282U_EQ_3282(...) \, +#define Z_IS_3282_EQ_3282U(...) \, +#define Z_IS_3282U_EQ_3282U(...) \, +#define Z_IS_3283_EQ_3283(...) \, +#define Z_IS_3283U_EQ_3283(...) \, +#define Z_IS_3283_EQ_3283U(...) \, +#define Z_IS_3283U_EQ_3283U(...) \, +#define Z_IS_3284_EQ_3284(...) \, +#define Z_IS_3284U_EQ_3284(...) \, +#define Z_IS_3284_EQ_3284U(...) \, +#define Z_IS_3284U_EQ_3284U(...) \, +#define Z_IS_3285_EQ_3285(...) \, +#define Z_IS_3285U_EQ_3285(...) \, +#define Z_IS_3285_EQ_3285U(...) \, +#define Z_IS_3285U_EQ_3285U(...) \, +#define Z_IS_3286_EQ_3286(...) \, +#define Z_IS_3286U_EQ_3286(...) \, +#define Z_IS_3286_EQ_3286U(...) \, +#define Z_IS_3286U_EQ_3286U(...) \, +#define Z_IS_3287_EQ_3287(...) \, +#define Z_IS_3287U_EQ_3287(...) \, +#define Z_IS_3287_EQ_3287U(...) \, +#define Z_IS_3287U_EQ_3287U(...) \, +#define Z_IS_3288_EQ_3288(...) \, +#define Z_IS_3288U_EQ_3288(...) \, +#define Z_IS_3288_EQ_3288U(...) \, +#define Z_IS_3288U_EQ_3288U(...) \, +#define Z_IS_3289_EQ_3289(...) \, +#define Z_IS_3289U_EQ_3289(...) \, +#define Z_IS_3289_EQ_3289U(...) \, +#define Z_IS_3289U_EQ_3289U(...) \, +#define Z_IS_3290_EQ_3290(...) \, +#define Z_IS_3290U_EQ_3290(...) \, +#define Z_IS_3290_EQ_3290U(...) \, +#define Z_IS_3290U_EQ_3290U(...) \, +#define Z_IS_3291_EQ_3291(...) \, +#define Z_IS_3291U_EQ_3291(...) \, +#define Z_IS_3291_EQ_3291U(...) \, +#define Z_IS_3291U_EQ_3291U(...) \, +#define Z_IS_3292_EQ_3292(...) \, +#define Z_IS_3292U_EQ_3292(...) \, +#define Z_IS_3292_EQ_3292U(...) \, +#define Z_IS_3292U_EQ_3292U(...) \, +#define Z_IS_3293_EQ_3293(...) \, +#define Z_IS_3293U_EQ_3293(...) \, +#define Z_IS_3293_EQ_3293U(...) \, +#define Z_IS_3293U_EQ_3293U(...) \, +#define Z_IS_3294_EQ_3294(...) \, +#define Z_IS_3294U_EQ_3294(...) \, +#define Z_IS_3294_EQ_3294U(...) \, +#define Z_IS_3294U_EQ_3294U(...) \, +#define Z_IS_3295_EQ_3295(...) \, +#define Z_IS_3295U_EQ_3295(...) \, +#define Z_IS_3295_EQ_3295U(...) \, +#define Z_IS_3295U_EQ_3295U(...) \, +#define Z_IS_3296_EQ_3296(...) \, +#define Z_IS_3296U_EQ_3296(...) \, +#define Z_IS_3296_EQ_3296U(...) \, +#define Z_IS_3296U_EQ_3296U(...) \, +#define Z_IS_3297_EQ_3297(...) \, +#define Z_IS_3297U_EQ_3297(...) \, +#define Z_IS_3297_EQ_3297U(...) \, +#define Z_IS_3297U_EQ_3297U(...) \, +#define Z_IS_3298_EQ_3298(...) \, +#define Z_IS_3298U_EQ_3298(...) \, +#define Z_IS_3298_EQ_3298U(...) \, +#define Z_IS_3298U_EQ_3298U(...) \, +#define Z_IS_3299_EQ_3299(...) \, +#define Z_IS_3299U_EQ_3299(...) \, +#define Z_IS_3299_EQ_3299U(...) \, +#define Z_IS_3299U_EQ_3299U(...) \, +#define Z_IS_3300_EQ_3300(...) \, +#define Z_IS_3300U_EQ_3300(...) \, +#define Z_IS_3300_EQ_3300U(...) \, +#define Z_IS_3300U_EQ_3300U(...) \, +#define Z_IS_3301_EQ_3301(...) \, +#define Z_IS_3301U_EQ_3301(...) \, +#define Z_IS_3301_EQ_3301U(...) \, +#define Z_IS_3301U_EQ_3301U(...) \, +#define Z_IS_3302_EQ_3302(...) \, +#define Z_IS_3302U_EQ_3302(...) \, +#define Z_IS_3302_EQ_3302U(...) \, +#define Z_IS_3302U_EQ_3302U(...) \, +#define Z_IS_3303_EQ_3303(...) \, +#define Z_IS_3303U_EQ_3303(...) \, +#define Z_IS_3303_EQ_3303U(...) \, +#define Z_IS_3303U_EQ_3303U(...) \, +#define Z_IS_3304_EQ_3304(...) \, +#define Z_IS_3304U_EQ_3304(...) \, +#define Z_IS_3304_EQ_3304U(...) \, +#define Z_IS_3304U_EQ_3304U(...) \, +#define Z_IS_3305_EQ_3305(...) \, +#define Z_IS_3305U_EQ_3305(...) \, +#define Z_IS_3305_EQ_3305U(...) \, +#define Z_IS_3305U_EQ_3305U(...) \, +#define Z_IS_3306_EQ_3306(...) \, +#define Z_IS_3306U_EQ_3306(...) \, +#define Z_IS_3306_EQ_3306U(...) \, +#define Z_IS_3306U_EQ_3306U(...) \, +#define Z_IS_3307_EQ_3307(...) \, +#define Z_IS_3307U_EQ_3307(...) \, +#define Z_IS_3307_EQ_3307U(...) \, +#define Z_IS_3307U_EQ_3307U(...) \, +#define Z_IS_3308_EQ_3308(...) \, +#define Z_IS_3308U_EQ_3308(...) \, +#define Z_IS_3308_EQ_3308U(...) \, +#define Z_IS_3308U_EQ_3308U(...) \, +#define Z_IS_3309_EQ_3309(...) \, +#define Z_IS_3309U_EQ_3309(...) \, +#define Z_IS_3309_EQ_3309U(...) \, +#define Z_IS_3309U_EQ_3309U(...) \, +#define Z_IS_3310_EQ_3310(...) \, +#define Z_IS_3310U_EQ_3310(...) \, +#define Z_IS_3310_EQ_3310U(...) \, +#define Z_IS_3310U_EQ_3310U(...) \, +#define Z_IS_3311_EQ_3311(...) \, +#define Z_IS_3311U_EQ_3311(...) \, +#define Z_IS_3311_EQ_3311U(...) \, +#define Z_IS_3311U_EQ_3311U(...) \, +#define Z_IS_3312_EQ_3312(...) \, +#define Z_IS_3312U_EQ_3312(...) \, +#define Z_IS_3312_EQ_3312U(...) \, +#define Z_IS_3312U_EQ_3312U(...) \, +#define Z_IS_3313_EQ_3313(...) \, +#define Z_IS_3313U_EQ_3313(...) \, +#define Z_IS_3313_EQ_3313U(...) \, +#define Z_IS_3313U_EQ_3313U(...) \, +#define Z_IS_3314_EQ_3314(...) \, +#define Z_IS_3314U_EQ_3314(...) \, +#define Z_IS_3314_EQ_3314U(...) \, +#define Z_IS_3314U_EQ_3314U(...) \, +#define Z_IS_3315_EQ_3315(...) \, +#define Z_IS_3315U_EQ_3315(...) \, +#define Z_IS_3315_EQ_3315U(...) \, +#define Z_IS_3315U_EQ_3315U(...) \, +#define Z_IS_3316_EQ_3316(...) \, +#define Z_IS_3316U_EQ_3316(...) \, +#define Z_IS_3316_EQ_3316U(...) \, +#define Z_IS_3316U_EQ_3316U(...) \, +#define Z_IS_3317_EQ_3317(...) \, +#define Z_IS_3317U_EQ_3317(...) \, +#define Z_IS_3317_EQ_3317U(...) \, +#define Z_IS_3317U_EQ_3317U(...) \, +#define Z_IS_3318_EQ_3318(...) \, +#define Z_IS_3318U_EQ_3318(...) \, +#define Z_IS_3318_EQ_3318U(...) \, +#define Z_IS_3318U_EQ_3318U(...) \, +#define Z_IS_3319_EQ_3319(...) \, +#define Z_IS_3319U_EQ_3319(...) \, +#define Z_IS_3319_EQ_3319U(...) \, +#define Z_IS_3319U_EQ_3319U(...) \, +#define Z_IS_3320_EQ_3320(...) \, +#define Z_IS_3320U_EQ_3320(...) \, +#define Z_IS_3320_EQ_3320U(...) \, +#define Z_IS_3320U_EQ_3320U(...) \, +#define Z_IS_3321_EQ_3321(...) \, +#define Z_IS_3321U_EQ_3321(...) \, +#define Z_IS_3321_EQ_3321U(...) \, +#define Z_IS_3321U_EQ_3321U(...) \, +#define Z_IS_3322_EQ_3322(...) \, +#define Z_IS_3322U_EQ_3322(...) \, +#define Z_IS_3322_EQ_3322U(...) \, +#define Z_IS_3322U_EQ_3322U(...) \, +#define Z_IS_3323_EQ_3323(...) \, +#define Z_IS_3323U_EQ_3323(...) \, +#define Z_IS_3323_EQ_3323U(...) \, +#define Z_IS_3323U_EQ_3323U(...) \, +#define Z_IS_3324_EQ_3324(...) \, +#define Z_IS_3324U_EQ_3324(...) \, +#define Z_IS_3324_EQ_3324U(...) \, +#define Z_IS_3324U_EQ_3324U(...) \, +#define Z_IS_3325_EQ_3325(...) \, +#define Z_IS_3325U_EQ_3325(...) \, +#define Z_IS_3325_EQ_3325U(...) \, +#define Z_IS_3325U_EQ_3325U(...) \, +#define Z_IS_3326_EQ_3326(...) \, +#define Z_IS_3326U_EQ_3326(...) \, +#define Z_IS_3326_EQ_3326U(...) \, +#define Z_IS_3326U_EQ_3326U(...) \, +#define Z_IS_3327_EQ_3327(...) \, +#define Z_IS_3327U_EQ_3327(...) \, +#define Z_IS_3327_EQ_3327U(...) \, +#define Z_IS_3327U_EQ_3327U(...) \, +#define Z_IS_3328_EQ_3328(...) \, +#define Z_IS_3328U_EQ_3328(...) \, +#define Z_IS_3328_EQ_3328U(...) \, +#define Z_IS_3328U_EQ_3328U(...) \, +#define Z_IS_3329_EQ_3329(...) \, +#define Z_IS_3329U_EQ_3329(...) \, +#define Z_IS_3329_EQ_3329U(...) \, +#define Z_IS_3329U_EQ_3329U(...) \, +#define Z_IS_3330_EQ_3330(...) \, +#define Z_IS_3330U_EQ_3330(...) \, +#define Z_IS_3330_EQ_3330U(...) \, +#define Z_IS_3330U_EQ_3330U(...) \, +#define Z_IS_3331_EQ_3331(...) \, +#define Z_IS_3331U_EQ_3331(...) \, +#define Z_IS_3331_EQ_3331U(...) \, +#define Z_IS_3331U_EQ_3331U(...) \, +#define Z_IS_3332_EQ_3332(...) \, +#define Z_IS_3332U_EQ_3332(...) \, +#define Z_IS_3332_EQ_3332U(...) \, +#define Z_IS_3332U_EQ_3332U(...) \, +#define Z_IS_3333_EQ_3333(...) \, +#define Z_IS_3333U_EQ_3333(...) \, +#define Z_IS_3333_EQ_3333U(...) \, +#define Z_IS_3333U_EQ_3333U(...) \, +#define Z_IS_3334_EQ_3334(...) \, +#define Z_IS_3334U_EQ_3334(...) \, +#define Z_IS_3334_EQ_3334U(...) \, +#define Z_IS_3334U_EQ_3334U(...) \, +#define Z_IS_3335_EQ_3335(...) \, +#define Z_IS_3335U_EQ_3335(...) \, +#define Z_IS_3335_EQ_3335U(...) \, +#define Z_IS_3335U_EQ_3335U(...) \, +#define Z_IS_3336_EQ_3336(...) \, +#define Z_IS_3336U_EQ_3336(...) \, +#define Z_IS_3336_EQ_3336U(...) \, +#define Z_IS_3336U_EQ_3336U(...) \, +#define Z_IS_3337_EQ_3337(...) \, +#define Z_IS_3337U_EQ_3337(...) \, +#define Z_IS_3337_EQ_3337U(...) \, +#define Z_IS_3337U_EQ_3337U(...) \, +#define Z_IS_3338_EQ_3338(...) \, +#define Z_IS_3338U_EQ_3338(...) \, +#define Z_IS_3338_EQ_3338U(...) \, +#define Z_IS_3338U_EQ_3338U(...) \, +#define Z_IS_3339_EQ_3339(...) \, +#define Z_IS_3339U_EQ_3339(...) \, +#define Z_IS_3339_EQ_3339U(...) \, +#define Z_IS_3339U_EQ_3339U(...) \, +#define Z_IS_3340_EQ_3340(...) \, +#define Z_IS_3340U_EQ_3340(...) \, +#define Z_IS_3340_EQ_3340U(...) \, +#define Z_IS_3340U_EQ_3340U(...) \, +#define Z_IS_3341_EQ_3341(...) \, +#define Z_IS_3341U_EQ_3341(...) \, +#define Z_IS_3341_EQ_3341U(...) \, +#define Z_IS_3341U_EQ_3341U(...) \, +#define Z_IS_3342_EQ_3342(...) \, +#define Z_IS_3342U_EQ_3342(...) \, +#define Z_IS_3342_EQ_3342U(...) \, +#define Z_IS_3342U_EQ_3342U(...) \, +#define Z_IS_3343_EQ_3343(...) \, +#define Z_IS_3343U_EQ_3343(...) \, +#define Z_IS_3343_EQ_3343U(...) \, +#define Z_IS_3343U_EQ_3343U(...) \, +#define Z_IS_3344_EQ_3344(...) \, +#define Z_IS_3344U_EQ_3344(...) \, +#define Z_IS_3344_EQ_3344U(...) \, +#define Z_IS_3344U_EQ_3344U(...) \, +#define Z_IS_3345_EQ_3345(...) \, +#define Z_IS_3345U_EQ_3345(...) \, +#define Z_IS_3345_EQ_3345U(...) \, +#define Z_IS_3345U_EQ_3345U(...) \, +#define Z_IS_3346_EQ_3346(...) \, +#define Z_IS_3346U_EQ_3346(...) \, +#define Z_IS_3346_EQ_3346U(...) \, +#define Z_IS_3346U_EQ_3346U(...) \, +#define Z_IS_3347_EQ_3347(...) \, +#define Z_IS_3347U_EQ_3347(...) \, +#define Z_IS_3347_EQ_3347U(...) \, +#define Z_IS_3347U_EQ_3347U(...) \, +#define Z_IS_3348_EQ_3348(...) \, +#define Z_IS_3348U_EQ_3348(...) \, +#define Z_IS_3348_EQ_3348U(...) \, +#define Z_IS_3348U_EQ_3348U(...) \, +#define Z_IS_3349_EQ_3349(...) \, +#define Z_IS_3349U_EQ_3349(...) \, +#define Z_IS_3349_EQ_3349U(...) \, +#define Z_IS_3349U_EQ_3349U(...) \, +#define Z_IS_3350_EQ_3350(...) \, +#define Z_IS_3350U_EQ_3350(...) \, +#define Z_IS_3350_EQ_3350U(...) \, +#define Z_IS_3350U_EQ_3350U(...) \, +#define Z_IS_3351_EQ_3351(...) \, +#define Z_IS_3351U_EQ_3351(...) \, +#define Z_IS_3351_EQ_3351U(...) \, +#define Z_IS_3351U_EQ_3351U(...) \, +#define Z_IS_3352_EQ_3352(...) \, +#define Z_IS_3352U_EQ_3352(...) \, +#define Z_IS_3352_EQ_3352U(...) \, +#define Z_IS_3352U_EQ_3352U(...) \, +#define Z_IS_3353_EQ_3353(...) \, +#define Z_IS_3353U_EQ_3353(...) \, +#define Z_IS_3353_EQ_3353U(...) \, +#define Z_IS_3353U_EQ_3353U(...) \, +#define Z_IS_3354_EQ_3354(...) \, +#define Z_IS_3354U_EQ_3354(...) \, +#define Z_IS_3354_EQ_3354U(...) \, +#define Z_IS_3354U_EQ_3354U(...) \, +#define Z_IS_3355_EQ_3355(...) \, +#define Z_IS_3355U_EQ_3355(...) \, +#define Z_IS_3355_EQ_3355U(...) \, +#define Z_IS_3355U_EQ_3355U(...) \, +#define Z_IS_3356_EQ_3356(...) \, +#define Z_IS_3356U_EQ_3356(...) \, +#define Z_IS_3356_EQ_3356U(...) \, +#define Z_IS_3356U_EQ_3356U(...) \, +#define Z_IS_3357_EQ_3357(...) \, +#define Z_IS_3357U_EQ_3357(...) \, +#define Z_IS_3357_EQ_3357U(...) \, +#define Z_IS_3357U_EQ_3357U(...) \, +#define Z_IS_3358_EQ_3358(...) \, +#define Z_IS_3358U_EQ_3358(...) \, +#define Z_IS_3358_EQ_3358U(...) \, +#define Z_IS_3358U_EQ_3358U(...) \, +#define Z_IS_3359_EQ_3359(...) \, +#define Z_IS_3359U_EQ_3359(...) \, +#define Z_IS_3359_EQ_3359U(...) \, +#define Z_IS_3359U_EQ_3359U(...) \, +#define Z_IS_3360_EQ_3360(...) \, +#define Z_IS_3360U_EQ_3360(...) \, +#define Z_IS_3360_EQ_3360U(...) \, +#define Z_IS_3360U_EQ_3360U(...) \, +#define Z_IS_3361_EQ_3361(...) \, +#define Z_IS_3361U_EQ_3361(...) \, +#define Z_IS_3361_EQ_3361U(...) \, +#define Z_IS_3361U_EQ_3361U(...) \, +#define Z_IS_3362_EQ_3362(...) \, +#define Z_IS_3362U_EQ_3362(...) \, +#define Z_IS_3362_EQ_3362U(...) \, +#define Z_IS_3362U_EQ_3362U(...) \, +#define Z_IS_3363_EQ_3363(...) \, +#define Z_IS_3363U_EQ_3363(...) \, +#define Z_IS_3363_EQ_3363U(...) \, +#define Z_IS_3363U_EQ_3363U(...) \, +#define Z_IS_3364_EQ_3364(...) \, +#define Z_IS_3364U_EQ_3364(...) \, +#define Z_IS_3364_EQ_3364U(...) \, +#define Z_IS_3364U_EQ_3364U(...) \, +#define Z_IS_3365_EQ_3365(...) \, +#define Z_IS_3365U_EQ_3365(...) \, +#define Z_IS_3365_EQ_3365U(...) \, +#define Z_IS_3365U_EQ_3365U(...) \, +#define Z_IS_3366_EQ_3366(...) \, +#define Z_IS_3366U_EQ_3366(...) \, +#define Z_IS_3366_EQ_3366U(...) \, +#define Z_IS_3366U_EQ_3366U(...) \, +#define Z_IS_3367_EQ_3367(...) \, +#define Z_IS_3367U_EQ_3367(...) \, +#define Z_IS_3367_EQ_3367U(...) \, +#define Z_IS_3367U_EQ_3367U(...) \, +#define Z_IS_3368_EQ_3368(...) \, +#define Z_IS_3368U_EQ_3368(...) \, +#define Z_IS_3368_EQ_3368U(...) \, +#define Z_IS_3368U_EQ_3368U(...) \, +#define Z_IS_3369_EQ_3369(...) \, +#define Z_IS_3369U_EQ_3369(...) \, +#define Z_IS_3369_EQ_3369U(...) \, +#define Z_IS_3369U_EQ_3369U(...) \, +#define Z_IS_3370_EQ_3370(...) \, +#define Z_IS_3370U_EQ_3370(...) \, +#define Z_IS_3370_EQ_3370U(...) \, +#define Z_IS_3370U_EQ_3370U(...) \, +#define Z_IS_3371_EQ_3371(...) \, +#define Z_IS_3371U_EQ_3371(...) \, +#define Z_IS_3371_EQ_3371U(...) \, +#define Z_IS_3371U_EQ_3371U(...) \, +#define Z_IS_3372_EQ_3372(...) \, +#define Z_IS_3372U_EQ_3372(...) \, +#define Z_IS_3372_EQ_3372U(...) \, +#define Z_IS_3372U_EQ_3372U(...) \, +#define Z_IS_3373_EQ_3373(...) \, +#define Z_IS_3373U_EQ_3373(...) \, +#define Z_IS_3373_EQ_3373U(...) \, +#define Z_IS_3373U_EQ_3373U(...) \, +#define Z_IS_3374_EQ_3374(...) \, +#define Z_IS_3374U_EQ_3374(...) \, +#define Z_IS_3374_EQ_3374U(...) \, +#define Z_IS_3374U_EQ_3374U(...) \, +#define Z_IS_3375_EQ_3375(...) \, +#define Z_IS_3375U_EQ_3375(...) \, +#define Z_IS_3375_EQ_3375U(...) \, +#define Z_IS_3375U_EQ_3375U(...) \, +#define Z_IS_3376_EQ_3376(...) \, +#define Z_IS_3376U_EQ_3376(...) \, +#define Z_IS_3376_EQ_3376U(...) \, +#define Z_IS_3376U_EQ_3376U(...) \, +#define Z_IS_3377_EQ_3377(...) \, +#define Z_IS_3377U_EQ_3377(...) \, +#define Z_IS_3377_EQ_3377U(...) \, +#define Z_IS_3377U_EQ_3377U(...) \, +#define Z_IS_3378_EQ_3378(...) \, +#define Z_IS_3378U_EQ_3378(...) \, +#define Z_IS_3378_EQ_3378U(...) \, +#define Z_IS_3378U_EQ_3378U(...) \, +#define Z_IS_3379_EQ_3379(...) \, +#define Z_IS_3379U_EQ_3379(...) \, +#define Z_IS_3379_EQ_3379U(...) \, +#define Z_IS_3379U_EQ_3379U(...) \, +#define Z_IS_3380_EQ_3380(...) \, +#define Z_IS_3380U_EQ_3380(...) \, +#define Z_IS_3380_EQ_3380U(...) \, +#define Z_IS_3380U_EQ_3380U(...) \, +#define Z_IS_3381_EQ_3381(...) \, +#define Z_IS_3381U_EQ_3381(...) \, +#define Z_IS_3381_EQ_3381U(...) \, +#define Z_IS_3381U_EQ_3381U(...) \, +#define Z_IS_3382_EQ_3382(...) \, +#define Z_IS_3382U_EQ_3382(...) \, +#define Z_IS_3382_EQ_3382U(...) \, +#define Z_IS_3382U_EQ_3382U(...) \, +#define Z_IS_3383_EQ_3383(...) \, +#define Z_IS_3383U_EQ_3383(...) \, +#define Z_IS_3383_EQ_3383U(...) \, +#define Z_IS_3383U_EQ_3383U(...) \, +#define Z_IS_3384_EQ_3384(...) \, +#define Z_IS_3384U_EQ_3384(...) \, +#define Z_IS_3384_EQ_3384U(...) \, +#define Z_IS_3384U_EQ_3384U(...) \, +#define Z_IS_3385_EQ_3385(...) \, +#define Z_IS_3385U_EQ_3385(...) \, +#define Z_IS_3385_EQ_3385U(...) \, +#define Z_IS_3385U_EQ_3385U(...) \, +#define Z_IS_3386_EQ_3386(...) \, +#define Z_IS_3386U_EQ_3386(...) \, +#define Z_IS_3386_EQ_3386U(...) \, +#define Z_IS_3386U_EQ_3386U(...) \, +#define Z_IS_3387_EQ_3387(...) \, +#define Z_IS_3387U_EQ_3387(...) \, +#define Z_IS_3387_EQ_3387U(...) \, +#define Z_IS_3387U_EQ_3387U(...) \, +#define Z_IS_3388_EQ_3388(...) \, +#define Z_IS_3388U_EQ_3388(...) \, +#define Z_IS_3388_EQ_3388U(...) \, +#define Z_IS_3388U_EQ_3388U(...) \, +#define Z_IS_3389_EQ_3389(...) \, +#define Z_IS_3389U_EQ_3389(...) \, +#define Z_IS_3389_EQ_3389U(...) \, +#define Z_IS_3389U_EQ_3389U(...) \, +#define Z_IS_3390_EQ_3390(...) \, +#define Z_IS_3390U_EQ_3390(...) \, +#define Z_IS_3390_EQ_3390U(...) \, +#define Z_IS_3390U_EQ_3390U(...) \, +#define Z_IS_3391_EQ_3391(...) \, +#define Z_IS_3391U_EQ_3391(...) \, +#define Z_IS_3391_EQ_3391U(...) \, +#define Z_IS_3391U_EQ_3391U(...) \, +#define Z_IS_3392_EQ_3392(...) \, +#define Z_IS_3392U_EQ_3392(...) \, +#define Z_IS_3392_EQ_3392U(...) \, +#define Z_IS_3392U_EQ_3392U(...) \, +#define Z_IS_3393_EQ_3393(...) \, +#define Z_IS_3393U_EQ_3393(...) \, +#define Z_IS_3393_EQ_3393U(...) \, +#define Z_IS_3393U_EQ_3393U(...) \, +#define Z_IS_3394_EQ_3394(...) \, +#define Z_IS_3394U_EQ_3394(...) \, +#define Z_IS_3394_EQ_3394U(...) \, +#define Z_IS_3394U_EQ_3394U(...) \, +#define Z_IS_3395_EQ_3395(...) \, +#define Z_IS_3395U_EQ_3395(...) \, +#define Z_IS_3395_EQ_3395U(...) \, +#define Z_IS_3395U_EQ_3395U(...) \, +#define Z_IS_3396_EQ_3396(...) \, +#define Z_IS_3396U_EQ_3396(...) \, +#define Z_IS_3396_EQ_3396U(...) \, +#define Z_IS_3396U_EQ_3396U(...) \, +#define Z_IS_3397_EQ_3397(...) \, +#define Z_IS_3397U_EQ_3397(...) \, +#define Z_IS_3397_EQ_3397U(...) \, +#define Z_IS_3397U_EQ_3397U(...) \, +#define Z_IS_3398_EQ_3398(...) \, +#define Z_IS_3398U_EQ_3398(...) \, +#define Z_IS_3398_EQ_3398U(...) \, +#define Z_IS_3398U_EQ_3398U(...) \, +#define Z_IS_3399_EQ_3399(...) \, +#define Z_IS_3399U_EQ_3399(...) \, +#define Z_IS_3399_EQ_3399U(...) \, +#define Z_IS_3399U_EQ_3399U(...) \, +#define Z_IS_3400_EQ_3400(...) \, +#define Z_IS_3400U_EQ_3400(...) \, +#define Z_IS_3400_EQ_3400U(...) \, +#define Z_IS_3400U_EQ_3400U(...) \, +#define Z_IS_3401_EQ_3401(...) \, +#define Z_IS_3401U_EQ_3401(...) \, +#define Z_IS_3401_EQ_3401U(...) \, +#define Z_IS_3401U_EQ_3401U(...) \, +#define Z_IS_3402_EQ_3402(...) \, +#define Z_IS_3402U_EQ_3402(...) \, +#define Z_IS_3402_EQ_3402U(...) \, +#define Z_IS_3402U_EQ_3402U(...) \, +#define Z_IS_3403_EQ_3403(...) \, +#define Z_IS_3403U_EQ_3403(...) \, +#define Z_IS_3403_EQ_3403U(...) \, +#define Z_IS_3403U_EQ_3403U(...) \, +#define Z_IS_3404_EQ_3404(...) \, +#define Z_IS_3404U_EQ_3404(...) \, +#define Z_IS_3404_EQ_3404U(...) \, +#define Z_IS_3404U_EQ_3404U(...) \, +#define Z_IS_3405_EQ_3405(...) \, +#define Z_IS_3405U_EQ_3405(...) \, +#define Z_IS_3405_EQ_3405U(...) \, +#define Z_IS_3405U_EQ_3405U(...) \, +#define Z_IS_3406_EQ_3406(...) \, +#define Z_IS_3406U_EQ_3406(...) \, +#define Z_IS_3406_EQ_3406U(...) \, +#define Z_IS_3406U_EQ_3406U(...) \, +#define Z_IS_3407_EQ_3407(...) \, +#define Z_IS_3407U_EQ_3407(...) \, +#define Z_IS_3407_EQ_3407U(...) \, +#define Z_IS_3407U_EQ_3407U(...) \, +#define Z_IS_3408_EQ_3408(...) \, +#define Z_IS_3408U_EQ_3408(...) \, +#define Z_IS_3408_EQ_3408U(...) \, +#define Z_IS_3408U_EQ_3408U(...) \, +#define Z_IS_3409_EQ_3409(...) \, +#define Z_IS_3409U_EQ_3409(...) \, +#define Z_IS_3409_EQ_3409U(...) \, +#define Z_IS_3409U_EQ_3409U(...) \, +#define Z_IS_3410_EQ_3410(...) \, +#define Z_IS_3410U_EQ_3410(...) \, +#define Z_IS_3410_EQ_3410U(...) \, +#define Z_IS_3410U_EQ_3410U(...) \, +#define Z_IS_3411_EQ_3411(...) \, +#define Z_IS_3411U_EQ_3411(...) \, +#define Z_IS_3411_EQ_3411U(...) \, +#define Z_IS_3411U_EQ_3411U(...) \, +#define Z_IS_3412_EQ_3412(...) \, +#define Z_IS_3412U_EQ_3412(...) \, +#define Z_IS_3412_EQ_3412U(...) \, +#define Z_IS_3412U_EQ_3412U(...) \, +#define Z_IS_3413_EQ_3413(...) \, +#define Z_IS_3413U_EQ_3413(...) \, +#define Z_IS_3413_EQ_3413U(...) \, +#define Z_IS_3413U_EQ_3413U(...) \, +#define Z_IS_3414_EQ_3414(...) \, +#define Z_IS_3414U_EQ_3414(...) \, +#define Z_IS_3414_EQ_3414U(...) \, +#define Z_IS_3414U_EQ_3414U(...) \, +#define Z_IS_3415_EQ_3415(...) \, +#define Z_IS_3415U_EQ_3415(...) \, +#define Z_IS_3415_EQ_3415U(...) \, +#define Z_IS_3415U_EQ_3415U(...) \, +#define Z_IS_3416_EQ_3416(...) \, +#define Z_IS_3416U_EQ_3416(...) \, +#define Z_IS_3416_EQ_3416U(...) \, +#define Z_IS_3416U_EQ_3416U(...) \, +#define Z_IS_3417_EQ_3417(...) \, +#define Z_IS_3417U_EQ_3417(...) \, +#define Z_IS_3417_EQ_3417U(...) \, +#define Z_IS_3417U_EQ_3417U(...) \, +#define Z_IS_3418_EQ_3418(...) \, +#define Z_IS_3418U_EQ_3418(...) \, +#define Z_IS_3418_EQ_3418U(...) \, +#define Z_IS_3418U_EQ_3418U(...) \, +#define Z_IS_3419_EQ_3419(...) \, +#define Z_IS_3419U_EQ_3419(...) \, +#define Z_IS_3419_EQ_3419U(...) \, +#define Z_IS_3419U_EQ_3419U(...) \, +#define Z_IS_3420_EQ_3420(...) \, +#define Z_IS_3420U_EQ_3420(...) \, +#define Z_IS_3420_EQ_3420U(...) \, +#define Z_IS_3420U_EQ_3420U(...) \, +#define Z_IS_3421_EQ_3421(...) \, +#define Z_IS_3421U_EQ_3421(...) \, +#define Z_IS_3421_EQ_3421U(...) \, +#define Z_IS_3421U_EQ_3421U(...) \, +#define Z_IS_3422_EQ_3422(...) \, +#define Z_IS_3422U_EQ_3422(...) \, +#define Z_IS_3422_EQ_3422U(...) \, +#define Z_IS_3422U_EQ_3422U(...) \, +#define Z_IS_3423_EQ_3423(...) \, +#define Z_IS_3423U_EQ_3423(...) \, +#define Z_IS_3423_EQ_3423U(...) \, +#define Z_IS_3423U_EQ_3423U(...) \, +#define Z_IS_3424_EQ_3424(...) \, +#define Z_IS_3424U_EQ_3424(...) \, +#define Z_IS_3424_EQ_3424U(...) \, +#define Z_IS_3424U_EQ_3424U(...) \, +#define Z_IS_3425_EQ_3425(...) \, +#define Z_IS_3425U_EQ_3425(...) \, +#define Z_IS_3425_EQ_3425U(...) \, +#define Z_IS_3425U_EQ_3425U(...) \, +#define Z_IS_3426_EQ_3426(...) \, +#define Z_IS_3426U_EQ_3426(...) \, +#define Z_IS_3426_EQ_3426U(...) \, +#define Z_IS_3426U_EQ_3426U(...) \, +#define Z_IS_3427_EQ_3427(...) \, +#define Z_IS_3427U_EQ_3427(...) \, +#define Z_IS_3427_EQ_3427U(...) \, +#define Z_IS_3427U_EQ_3427U(...) \, +#define Z_IS_3428_EQ_3428(...) \, +#define Z_IS_3428U_EQ_3428(...) \, +#define Z_IS_3428_EQ_3428U(...) \, +#define Z_IS_3428U_EQ_3428U(...) \, +#define Z_IS_3429_EQ_3429(...) \, +#define Z_IS_3429U_EQ_3429(...) \, +#define Z_IS_3429_EQ_3429U(...) \, +#define Z_IS_3429U_EQ_3429U(...) \, +#define Z_IS_3430_EQ_3430(...) \, +#define Z_IS_3430U_EQ_3430(...) \, +#define Z_IS_3430_EQ_3430U(...) \, +#define Z_IS_3430U_EQ_3430U(...) \, +#define Z_IS_3431_EQ_3431(...) \, +#define Z_IS_3431U_EQ_3431(...) \, +#define Z_IS_3431_EQ_3431U(...) \, +#define Z_IS_3431U_EQ_3431U(...) \, +#define Z_IS_3432_EQ_3432(...) \, +#define Z_IS_3432U_EQ_3432(...) \, +#define Z_IS_3432_EQ_3432U(...) \, +#define Z_IS_3432U_EQ_3432U(...) \, +#define Z_IS_3433_EQ_3433(...) \, +#define Z_IS_3433U_EQ_3433(...) \, +#define Z_IS_3433_EQ_3433U(...) \, +#define Z_IS_3433U_EQ_3433U(...) \, +#define Z_IS_3434_EQ_3434(...) \, +#define Z_IS_3434U_EQ_3434(...) \, +#define Z_IS_3434_EQ_3434U(...) \, +#define Z_IS_3434U_EQ_3434U(...) \, +#define Z_IS_3435_EQ_3435(...) \, +#define Z_IS_3435U_EQ_3435(...) \, +#define Z_IS_3435_EQ_3435U(...) \, +#define Z_IS_3435U_EQ_3435U(...) \, +#define Z_IS_3436_EQ_3436(...) \, +#define Z_IS_3436U_EQ_3436(...) \, +#define Z_IS_3436_EQ_3436U(...) \, +#define Z_IS_3436U_EQ_3436U(...) \, +#define Z_IS_3437_EQ_3437(...) \, +#define Z_IS_3437U_EQ_3437(...) \, +#define Z_IS_3437_EQ_3437U(...) \, +#define Z_IS_3437U_EQ_3437U(...) \, +#define Z_IS_3438_EQ_3438(...) \, +#define Z_IS_3438U_EQ_3438(...) \, +#define Z_IS_3438_EQ_3438U(...) \, +#define Z_IS_3438U_EQ_3438U(...) \, +#define Z_IS_3439_EQ_3439(...) \, +#define Z_IS_3439U_EQ_3439(...) \, +#define Z_IS_3439_EQ_3439U(...) \, +#define Z_IS_3439U_EQ_3439U(...) \, +#define Z_IS_3440_EQ_3440(...) \, +#define Z_IS_3440U_EQ_3440(...) \, +#define Z_IS_3440_EQ_3440U(...) \, +#define Z_IS_3440U_EQ_3440U(...) \, +#define Z_IS_3441_EQ_3441(...) \, +#define Z_IS_3441U_EQ_3441(...) \, +#define Z_IS_3441_EQ_3441U(...) \, +#define Z_IS_3441U_EQ_3441U(...) \, +#define Z_IS_3442_EQ_3442(...) \, +#define Z_IS_3442U_EQ_3442(...) \, +#define Z_IS_3442_EQ_3442U(...) \, +#define Z_IS_3442U_EQ_3442U(...) \, +#define Z_IS_3443_EQ_3443(...) \, +#define Z_IS_3443U_EQ_3443(...) \, +#define Z_IS_3443_EQ_3443U(...) \, +#define Z_IS_3443U_EQ_3443U(...) \, +#define Z_IS_3444_EQ_3444(...) \, +#define Z_IS_3444U_EQ_3444(...) \, +#define Z_IS_3444_EQ_3444U(...) \, +#define Z_IS_3444U_EQ_3444U(...) \, +#define Z_IS_3445_EQ_3445(...) \, +#define Z_IS_3445U_EQ_3445(...) \, +#define Z_IS_3445_EQ_3445U(...) \, +#define Z_IS_3445U_EQ_3445U(...) \, +#define Z_IS_3446_EQ_3446(...) \, +#define Z_IS_3446U_EQ_3446(...) \, +#define Z_IS_3446_EQ_3446U(...) \, +#define Z_IS_3446U_EQ_3446U(...) \, +#define Z_IS_3447_EQ_3447(...) \, +#define Z_IS_3447U_EQ_3447(...) \, +#define Z_IS_3447_EQ_3447U(...) \, +#define Z_IS_3447U_EQ_3447U(...) \, +#define Z_IS_3448_EQ_3448(...) \, +#define Z_IS_3448U_EQ_3448(...) \, +#define Z_IS_3448_EQ_3448U(...) \, +#define Z_IS_3448U_EQ_3448U(...) \, +#define Z_IS_3449_EQ_3449(...) \, +#define Z_IS_3449U_EQ_3449(...) \, +#define Z_IS_3449_EQ_3449U(...) \, +#define Z_IS_3449U_EQ_3449U(...) \, +#define Z_IS_3450_EQ_3450(...) \, +#define Z_IS_3450U_EQ_3450(...) \, +#define Z_IS_3450_EQ_3450U(...) \, +#define Z_IS_3450U_EQ_3450U(...) \, +#define Z_IS_3451_EQ_3451(...) \, +#define Z_IS_3451U_EQ_3451(...) \, +#define Z_IS_3451_EQ_3451U(...) \, +#define Z_IS_3451U_EQ_3451U(...) \, +#define Z_IS_3452_EQ_3452(...) \, +#define Z_IS_3452U_EQ_3452(...) \, +#define Z_IS_3452_EQ_3452U(...) \, +#define Z_IS_3452U_EQ_3452U(...) \, +#define Z_IS_3453_EQ_3453(...) \, +#define Z_IS_3453U_EQ_3453(...) \, +#define Z_IS_3453_EQ_3453U(...) \, +#define Z_IS_3453U_EQ_3453U(...) \, +#define Z_IS_3454_EQ_3454(...) \, +#define Z_IS_3454U_EQ_3454(...) \, +#define Z_IS_3454_EQ_3454U(...) \, +#define Z_IS_3454U_EQ_3454U(...) \, +#define Z_IS_3455_EQ_3455(...) \, +#define Z_IS_3455U_EQ_3455(...) \, +#define Z_IS_3455_EQ_3455U(...) \, +#define Z_IS_3455U_EQ_3455U(...) \, +#define Z_IS_3456_EQ_3456(...) \, +#define Z_IS_3456U_EQ_3456(...) \, +#define Z_IS_3456_EQ_3456U(...) \, +#define Z_IS_3456U_EQ_3456U(...) \, +#define Z_IS_3457_EQ_3457(...) \, +#define Z_IS_3457U_EQ_3457(...) \, +#define Z_IS_3457_EQ_3457U(...) \, +#define Z_IS_3457U_EQ_3457U(...) \, +#define Z_IS_3458_EQ_3458(...) \, +#define Z_IS_3458U_EQ_3458(...) \, +#define Z_IS_3458_EQ_3458U(...) \, +#define Z_IS_3458U_EQ_3458U(...) \, +#define Z_IS_3459_EQ_3459(...) \, +#define Z_IS_3459U_EQ_3459(...) \, +#define Z_IS_3459_EQ_3459U(...) \, +#define Z_IS_3459U_EQ_3459U(...) \, +#define Z_IS_3460_EQ_3460(...) \, +#define Z_IS_3460U_EQ_3460(...) \, +#define Z_IS_3460_EQ_3460U(...) \, +#define Z_IS_3460U_EQ_3460U(...) \, +#define Z_IS_3461_EQ_3461(...) \, +#define Z_IS_3461U_EQ_3461(...) \, +#define Z_IS_3461_EQ_3461U(...) \, +#define Z_IS_3461U_EQ_3461U(...) \, +#define Z_IS_3462_EQ_3462(...) \, +#define Z_IS_3462U_EQ_3462(...) \, +#define Z_IS_3462_EQ_3462U(...) \, +#define Z_IS_3462U_EQ_3462U(...) \, +#define Z_IS_3463_EQ_3463(...) \, +#define Z_IS_3463U_EQ_3463(...) \, +#define Z_IS_3463_EQ_3463U(...) \, +#define Z_IS_3463U_EQ_3463U(...) \, +#define Z_IS_3464_EQ_3464(...) \, +#define Z_IS_3464U_EQ_3464(...) \, +#define Z_IS_3464_EQ_3464U(...) \, +#define Z_IS_3464U_EQ_3464U(...) \, +#define Z_IS_3465_EQ_3465(...) \, +#define Z_IS_3465U_EQ_3465(...) \, +#define Z_IS_3465_EQ_3465U(...) \, +#define Z_IS_3465U_EQ_3465U(...) \, +#define Z_IS_3466_EQ_3466(...) \, +#define Z_IS_3466U_EQ_3466(...) \, +#define Z_IS_3466_EQ_3466U(...) \, +#define Z_IS_3466U_EQ_3466U(...) \, +#define Z_IS_3467_EQ_3467(...) \, +#define Z_IS_3467U_EQ_3467(...) \, +#define Z_IS_3467_EQ_3467U(...) \, +#define Z_IS_3467U_EQ_3467U(...) \, +#define Z_IS_3468_EQ_3468(...) \, +#define Z_IS_3468U_EQ_3468(...) \, +#define Z_IS_3468_EQ_3468U(...) \, +#define Z_IS_3468U_EQ_3468U(...) \, +#define Z_IS_3469_EQ_3469(...) \, +#define Z_IS_3469U_EQ_3469(...) \, +#define Z_IS_3469_EQ_3469U(...) \, +#define Z_IS_3469U_EQ_3469U(...) \, +#define Z_IS_3470_EQ_3470(...) \, +#define Z_IS_3470U_EQ_3470(...) \, +#define Z_IS_3470_EQ_3470U(...) \, +#define Z_IS_3470U_EQ_3470U(...) \, +#define Z_IS_3471_EQ_3471(...) \, +#define Z_IS_3471U_EQ_3471(...) \, +#define Z_IS_3471_EQ_3471U(...) \, +#define Z_IS_3471U_EQ_3471U(...) \, +#define Z_IS_3472_EQ_3472(...) \, +#define Z_IS_3472U_EQ_3472(...) \, +#define Z_IS_3472_EQ_3472U(...) \, +#define Z_IS_3472U_EQ_3472U(...) \, +#define Z_IS_3473_EQ_3473(...) \, +#define Z_IS_3473U_EQ_3473(...) \, +#define Z_IS_3473_EQ_3473U(...) \, +#define Z_IS_3473U_EQ_3473U(...) \, +#define Z_IS_3474_EQ_3474(...) \, +#define Z_IS_3474U_EQ_3474(...) \, +#define Z_IS_3474_EQ_3474U(...) \, +#define Z_IS_3474U_EQ_3474U(...) \, +#define Z_IS_3475_EQ_3475(...) \, +#define Z_IS_3475U_EQ_3475(...) \, +#define Z_IS_3475_EQ_3475U(...) \, +#define Z_IS_3475U_EQ_3475U(...) \, +#define Z_IS_3476_EQ_3476(...) \, +#define Z_IS_3476U_EQ_3476(...) \, +#define Z_IS_3476_EQ_3476U(...) \, +#define Z_IS_3476U_EQ_3476U(...) \, +#define Z_IS_3477_EQ_3477(...) \, +#define Z_IS_3477U_EQ_3477(...) \, +#define Z_IS_3477_EQ_3477U(...) \, +#define Z_IS_3477U_EQ_3477U(...) \, +#define Z_IS_3478_EQ_3478(...) \, +#define Z_IS_3478U_EQ_3478(...) \, +#define Z_IS_3478_EQ_3478U(...) \, +#define Z_IS_3478U_EQ_3478U(...) \, +#define Z_IS_3479_EQ_3479(...) \, +#define Z_IS_3479U_EQ_3479(...) \, +#define Z_IS_3479_EQ_3479U(...) \, +#define Z_IS_3479U_EQ_3479U(...) \, +#define Z_IS_3480_EQ_3480(...) \, +#define Z_IS_3480U_EQ_3480(...) \, +#define Z_IS_3480_EQ_3480U(...) \, +#define Z_IS_3480U_EQ_3480U(...) \, +#define Z_IS_3481_EQ_3481(...) \, +#define Z_IS_3481U_EQ_3481(...) \, +#define Z_IS_3481_EQ_3481U(...) \, +#define Z_IS_3481U_EQ_3481U(...) \, +#define Z_IS_3482_EQ_3482(...) \, +#define Z_IS_3482U_EQ_3482(...) \, +#define Z_IS_3482_EQ_3482U(...) \, +#define Z_IS_3482U_EQ_3482U(...) \, +#define Z_IS_3483_EQ_3483(...) \, +#define Z_IS_3483U_EQ_3483(...) \, +#define Z_IS_3483_EQ_3483U(...) \, +#define Z_IS_3483U_EQ_3483U(...) \, +#define Z_IS_3484_EQ_3484(...) \, +#define Z_IS_3484U_EQ_3484(...) \, +#define Z_IS_3484_EQ_3484U(...) \, +#define Z_IS_3484U_EQ_3484U(...) \, +#define Z_IS_3485_EQ_3485(...) \, +#define Z_IS_3485U_EQ_3485(...) \, +#define Z_IS_3485_EQ_3485U(...) \, +#define Z_IS_3485U_EQ_3485U(...) \, +#define Z_IS_3486_EQ_3486(...) \, +#define Z_IS_3486U_EQ_3486(...) \, +#define Z_IS_3486_EQ_3486U(...) \, +#define Z_IS_3486U_EQ_3486U(...) \, +#define Z_IS_3487_EQ_3487(...) \, +#define Z_IS_3487U_EQ_3487(...) \, +#define Z_IS_3487_EQ_3487U(...) \, +#define Z_IS_3487U_EQ_3487U(...) \, +#define Z_IS_3488_EQ_3488(...) \, +#define Z_IS_3488U_EQ_3488(...) \, +#define Z_IS_3488_EQ_3488U(...) \, +#define Z_IS_3488U_EQ_3488U(...) \, +#define Z_IS_3489_EQ_3489(...) \, +#define Z_IS_3489U_EQ_3489(...) \, +#define Z_IS_3489_EQ_3489U(...) \, +#define Z_IS_3489U_EQ_3489U(...) \, +#define Z_IS_3490_EQ_3490(...) \, +#define Z_IS_3490U_EQ_3490(...) \, +#define Z_IS_3490_EQ_3490U(...) \, +#define Z_IS_3490U_EQ_3490U(...) \, +#define Z_IS_3491_EQ_3491(...) \, +#define Z_IS_3491U_EQ_3491(...) \, +#define Z_IS_3491_EQ_3491U(...) \, +#define Z_IS_3491U_EQ_3491U(...) \, +#define Z_IS_3492_EQ_3492(...) \, +#define Z_IS_3492U_EQ_3492(...) \, +#define Z_IS_3492_EQ_3492U(...) \, +#define Z_IS_3492U_EQ_3492U(...) \, +#define Z_IS_3493_EQ_3493(...) \, +#define Z_IS_3493U_EQ_3493(...) \, +#define Z_IS_3493_EQ_3493U(...) \, +#define Z_IS_3493U_EQ_3493U(...) \, +#define Z_IS_3494_EQ_3494(...) \, +#define Z_IS_3494U_EQ_3494(...) \, +#define Z_IS_3494_EQ_3494U(...) \, +#define Z_IS_3494U_EQ_3494U(...) \, +#define Z_IS_3495_EQ_3495(...) \, +#define Z_IS_3495U_EQ_3495(...) \, +#define Z_IS_3495_EQ_3495U(...) \, +#define Z_IS_3495U_EQ_3495U(...) \, +#define Z_IS_3496_EQ_3496(...) \, +#define Z_IS_3496U_EQ_3496(...) \, +#define Z_IS_3496_EQ_3496U(...) \, +#define Z_IS_3496U_EQ_3496U(...) \, +#define Z_IS_3497_EQ_3497(...) \, +#define Z_IS_3497U_EQ_3497(...) \, +#define Z_IS_3497_EQ_3497U(...) \, +#define Z_IS_3497U_EQ_3497U(...) \, +#define Z_IS_3498_EQ_3498(...) \, +#define Z_IS_3498U_EQ_3498(...) \, +#define Z_IS_3498_EQ_3498U(...) \, +#define Z_IS_3498U_EQ_3498U(...) \, +#define Z_IS_3499_EQ_3499(...) \, +#define Z_IS_3499U_EQ_3499(...) \, +#define Z_IS_3499_EQ_3499U(...) \, +#define Z_IS_3499U_EQ_3499U(...) \, +#define Z_IS_3500_EQ_3500(...) \, +#define Z_IS_3500U_EQ_3500(...) \, +#define Z_IS_3500_EQ_3500U(...) \, +#define Z_IS_3500U_EQ_3500U(...) \, +#define Z_IS_3501_EQ_3501(...) \, +#define Z_IS_3501U_EQ_3501(...) \, +#define Z_IS_3501_EQ_3501U(...) \, +#define Z_IS_3501U_EQ_3501U(...) \, +#define Z_IS_3502_EQ_3502(...) \, +#define Z_IS_3502U_EQ_3502(...) \, +#define Z_IS_3502_EQ_3502U(...) \, +#define Z_IS_3502U_EQ_3502U(...) \, +#define Z_IS_3503_EQ_3503(...) \, +#define Z_IS_3503U_EQ_3503(...) \, +#define Z_IS_3503_EQ_3503U(...) \, +#define Z_IS_3503U_EQ_3503U(...) \, +#define Z_IS_3504_EQ_3504(...) \, +#define Z_IS_3504U_EQ_3504(...) \, +#define Z_IS_3504_EQ_3504U(...) \, +#define Z_IS_3504U_EQ_3504U(...) \, +#define Z_IS_3505_EQ_3505(...) \, +#define Z_IS_3505U_EQ_3505(...) \, +#define Z_IS_3505_EQ_3505U(...) \, +#define Z_IS_3505U_EQ_3505U(...) \, +#define Z_IS_3506_EQ_3506(...) \, +#define Z_IS_3506U_EQ_3506(...) \, +#define Z_IS_3506_EQ_3506U(...) \, +#define Z_IS_3506U_EQ_3506U(...) \, +#define Z_IS_3507_EQ_3507(...) \, +#define Z_IS_3507U_EQ_3507(...) \, +#define Z_IS_3507_EQ_3507U(...) \, +#define Z_IS_3507U_EQ_3507U(...) \, +#define Z_IS_3508_EQ_3508(...) \, +#define Z_IS_3508U_EQ_3508(...) \, +#define Z_IS_3508_EQ_3508U(...) \, +#define Z_IS_3508U_EQ_3508U(...) \, +#define Z_IS_3509_EQ_3509(...) \, +#define Z_IS_3509U_EQ_3509(...) \, +#define Z_IS_3509_EQ_3509U(...) \, +#define Z_IS_3509U_EQ_3509U(...) \, +#define Z_IS_3510_EQ_3510(...) \, +#define Z_IS_3510U_EQ_3510(...) \, +#define Z_IS_3510_EQ_3510U(...) \, +#define Z_IS_3510U_EQ_3510U(...) \, +#define Z_IS_3511_EQ_3511(...) \, +#define Z_IS_3511U_EQ_3511(...) \, +#define Z_IS_3511_EQ_3511U(...) \, +#define Z_IS_3511U_EQ_3511U(...) \, +#define Z_IS_3512_EQ_3512(...) \, +#define Z_IS_3512U_EQ_3512(...) \, +#define Z_IS_3512_EQ_3512U(...) \, +#define Z_IS_3512U_EQ_3512U(...) \, +#define Z_IS_3513_EQ_3513(...) \, +#define Z_IS_3513U_EQ_3513(...) \, +#define Z_IS_3513_EQ_3513U(...) \, +#define Z_IS_3513U_EQ_3513U(...) \, +#define Z_IS_3514_EQ_3514(...) \, +#define Z_IS_3514U_EQ_3514(...) \, +#define Z_IS_3514_EQ_3514U(...) \, +#define Z_IS_3514U_EQ_3514U(...) \, +#define Z_IS_3515_EQ_3515(...) \, +#define Z_IS_3515U_EQ_3515(...) \, +#define Z_IS_3515_EQ_3515U(...) \, +#define Z_IS_3515U_EQ_3515U(...) \, +#define Z_IS_3516_EQ_3516(...) \, +#define Z_IS_3516U_EQ_3516(...) \, +#define Z_IS_3516_EQ_3516U(...) \, +#define Z_IS_3516U_EQ_3516U(...) \, +#define Z_IS_3517_EQ_3517(...) \, +#define Z_IS_3517U_EQ_3517(...) \, +#define Z_IS_3517_EQ_3517U(...) \, +#define Z_IS_3517U_EQ_3517U(...) \, +#define Z_IS_3518_EQ_3518(...) \, +#define Z_IS_3518U_EQ_3518(...) \, +#define Z_IS_3518_EQ_3518U(...) \, +#define Z_IS_3518U_EQ_3518U(...) \, +#define Z_IS_3519_EQ_3519(...) \, +#define Z_IS_3519U_EQ_3519(...) \, +#define Z_IS_3519_EQ_3519U(...) \, +#define Z_IS_3519U_EQ_3519U(...) \, +#define Z_IS_3520_EQ_3520(...) \, +#define Z_IS_3520U_EQ_3520(...) \, +#define Z_IS_3520_EQ_3520U(...) \, +#define Z_IS_3520U_EQ_3520U(...) \, +#define Z_IS_3521_EQ_3521(...) \, +#define Z_IS_3521U_EQ_3521(...) \, +#define Z_IS_3521_EQ_3521U(...) \, +#define Z_IS_3521U_EQ_3521U(...) \, +#define Z_IS_3522_EQ_3522(...) \, +#define Z_IS_3522U_EQ_3522(...) \, +#define Z_IS_3522_EQ_3522U(...) \, +#define Z_IS_3522U_EQ_3522U(...) \, +#define Z_IS_3523_EQ_3523(...) \, +#define Z_IS_3523U_EQ_3523(...) \, +#define Z_IS_3523_EQ_3523U(...) \, +#define Z_IS_3523U_EQ_3523U(...) \, +#define Z_IS_3524_EQ_3524(...) \, +#define Z_IS_3524U_EQ_3524(...) \, +#define Z_IS_3524_EQ_3524U(...) \, +#define Z_IS_3524U_EQ_3524U(...) \, +#define Z_IS_3525_EQ_3525(...) \, +#define Z_IS_3525U_EQ_3525(...) \, +#define Z_IS_3525_EQ_3525U(...) \, +#define Z_IS_3525U_EQ_3525U(...) \, +#define Z_IS_3526_EQ_3526(...) \, +#define Z_IS_3526U_EQ_3526(...) \, +#define Z_IS_3526_EQ_3526U(...) \, +#define Z_IS_3526U_EQ_3526U(...) \, +#define Z_IS_3527_EQ_3527(...) \, +#define Z_IS_3527U_EQ_3527(...) \, +#define Z_IS_3527_EQ_3527U(...) \, +#define Z_IS_3527U_EQ_3527U(...) \, +#define Z_IS_3528_EQ_3528(...) \, +#define Z_IS_3528U_EQ_3528(...) \, +#define Z_IS_3528_EQ_3528U(...) \, +#define Z_IS_3528U_EQ_3528U(...) \, +#define Z_IS_3529_EQ_3529(...) \, +#define Z_IS_3529U_EQ_3529(...) \, +#define Z_IS_3529_EQ_3529U(...) \, +#define Z_IS_3529U_EQ_3529U(...) \, +#define Z_IS_3530_EQ_3530(...) \, +#define Z_IS_3530U_EQ_3530(...) \, +#define Z_IS_3530_EQ_3530U(...) \, +#define Z_IS_3530U_EQ_3530U(...) \, +#define Z_IS_3531_EQ_3531(...) \, +#define Z_IS_3531U_EQ_3531(...) \, +#define Z_IS_3531_EQ_3531U(...) \, +#define Z_IS_3531U_EQ_3531U(...) \, +#define Z_IS_3532_EQ_3532(...) \, +#define Z_IS_3532U_EQ_3532(...) \, +#define Z_IS_3532_EQ_3532U(...) \, +#define Z_IS_3532U_EQ_3532U(...) \, +#define Z_IS_3533_EQ_3533(...) \, +#define Z_IS_3533U_EQ_3533(...) \, +#define Z_IS_3533_EQ_3533U(...) \, +#define Z_IS_3533U_EQ_3533U(...) \, +#define Z_IS_3534_EQ_3534(...) \, +#define Z_IS_3534U_EQ_3534(...) \, +#define Z_IS_3534_EQ_3534U(...) \, +#define Z_IS_3534U_EQ_3534U(...) \, +#define Z_IS_3535_EQ_3535(...) \, +#define Z_IS_3535U_EQ_3535(...) \, +#define Z_IS_3535_EQ_3535U(...) \, +#define Z_IS_3535U_EQ_3535U(...) \, +#define Z_IS_3536_EQ_3536(...) \, +#define Z_IS_3536U_EQ_3536(...) \, +#define Z_IS_3536_EQ_3536U(...) \, +#define Z_IS_3536U_EQ_3536U(...) \, +#define Z_IS_3537_EQ_3537(...) \, +#define Z_IS_3537U_EQ_3537(...) \, +#define Z_IS_3537_EQ_3537U(...) \, +#define Z_IS_3537U_EQ_3537U(...) \, +#define Z_IS_3538_EQ_3538(...) \, +#define Z_IS_3538U_EQ_3538(...) \, +#define Z_IS_3538_EQ_3538U(...) \, +#define Z_IS_3538U_EQ_3538U(...) \, +#define Z_IS_3539_EQ_3539(...) \, +#define Z_IS_3539U_EQ_3539(...) \, +#define Z_IS_3539_EQ_3539U(...) \, +#define Z_IS_3539U_EQ_3539U(...) \, +#define Z_IS_3540_EQ_3540(...) \, +#define Z_IS_3540U_EQ_3540(...) \, +#define Z_IS_3540_EQ_3540U(...) \, +#define Z_IS_3540U_EQ_3540U(...) \, +#define Z_IS_3541_EQ_3541(...) \, +#define Z_IS_3541U_EQ_3541(...) \, +#define Z_IS_3541_EQ_3541U(...) \, +#define Z_IS_3541U_EQ_3541U(...) \, +#define Z_IS_3542_EQ_3542(...) \, +#define Z_IS_3542U_EQ_3542(...) \, +#define Z_IS_3542_EQ_3542U(...) \, +#define Z_IS_3542U_EQ_3542U(...) \, +#define Z_IS_3543_EQ_3543(...) \, +#define Z_IS_3543U_EQ_3543(...) \, +#define Z_IS_3543_EQ_3543U(...) \, +#define Z_IS_3543U_EQ_3543U(...) \, +#define Z_IS_3544_EQ_3544(...) \, +#define Z_IS_3544U_EQ_3544(...) \, +#define Z_IS_3544_EQ_3544U(...) \, +#define Z_IS_3544U_EQ_3544U(...) \, +#define Z_IS_3545_EQ_3545(...) \, +#define Z_IS_3545U_EQ_3545(...) \, +#define Z_IS_3545_EQ_3545U(...) \, +#define Z_IS_3545U_EQ_3545U(...) \, +#define Z_IS_3546_EQ_3546(...) \, +#define Z_IS_3546U_EQ_3546(...) \, +#define Z_IS_3546_EQ_3546U(...) \, +#define Z_IS_3546U_EQ_3546U(...) \, +#define Z_IS_3547_EQ_3547(...) \, +#define Z_IS_3547U_EQ_3547(...) \, +#define Z_IS_3547_EQ_3547U(...) \, +#define Z_IS_3547U_EQ_3547U(...) \, +#define Z_IS_3548_EQ_3548(...) \, +#define Z_IS_3548U_EQ_3548(...) \, +#define Z_IS_3548_EQ_3548U(...) \, +#define Z_IS_3548U_EQ_3548U(...) \, +#define Z_IS_3549_EQ_3549(...) \, +#define Z_IS_3549U_EQ_3549(...) \, +#define Z_IS_3549_EQ_3549U(...) \, +#define Z_IS_3549U_EQ_3549U(...) \, +#define Z_IS_3550_EQ_3550(...) \, +#define Z_IS_3550U_EQ_3550(...) \, +#define Z_IS_3550_EQ_3550U(...) \, +#define Z_IS_3550U_EQ_3550U(...) \, +#define Z_IS_3551_EQ_3551(...) \, +#define Z_IS_3551U_EQ_3551(...) \, +#define Z_IS_3551_EQ_3551U(...) \, +#define Z_IS_3551U_EQ_3551U(...) \, +#define Z_IS_3552_EQ_3552(...) \, +#define Z_IS_3552U_EQ_3552(...) \, +#define Z_IS_3552_EQ_3552U(...) \, +#define Z_IS_3552U_EQ_3552U(...) \, +#define Z_IS_3553_EQ_3553(...) \, +#define Z_IS_3553U_EQ_3553(...) \, +#define Z_IS_3553_EQ_3553U(...) \, +#define Z_IS_3553U_EQ_3553U(...) \, +#define Z_IS_3554_EQ_3554(...) \, +#define Z_IS_3554U_EQ_3554(...) \, +#define Z_IS_3554_EQ_3554U(...) \, +#define Z_IS_3554U_EQ_3554U(...) \, +#define Z_IS_3555_EQ_3555(...) \, +#define Z_IS_3555U_EQ_3555(...) \, +#define Z_IS_3555_EQ_3555U(...) \, +#define Z_IS_3555U_EQ_3555U(...) \, +#define Z_IS_3556_EQ_3556(...) \, +#define Z_IS_3556U_EQ_3556(...) \, +#define Z_IS_3556_EQ_3556U(...) \, +#define Z_IS_3556U_EQ_3556U(...) \, +#define Z_IS_3557_EQ_3557(...) \, +#define Z_IS_3557U_EQ_3557(...) \, +#define Z_IS_3557_EQ_3557U(...) \, +#define Z_IS_3557U_EQ_3557U(...) \, +#define Z_IS_3558_EQ_3558(...) \, +#define Z_IS_3558U_EQ_3558(...) \, +#define Z_IS_3558_EQ_3558U(...) \, +#define Z_IS_3558U_EQ_3558U(...) \, +#define Z_IS_3559_EQ_3559(...) \, +#define Z_IS_3559U_EQ_3559(...) \, +#define Z_IS_3559_EQ_3559U(...) \, +#define Z_IS_3559U_EQ_3559U(...) \, +#define Z_IS_3560_EQ_3560(...) \, +#define Z_IS_3560U_EQ_3560(...) \, +#define Z_IS_3560_EQ_3560U(...) \, +#define Z_IS_3560U_EQ_3560U(...) \, +#define Z_IS_3561_EQ_3561(...) \, +#define Z_IS_3561U_EQ_3561(...) \, +#define Z_IS_3561_EQ_3561U(...) \, +#define Z_IS_3561U_EQ_3561U(...) \, +#define Z_IS_3562_EQ_3562(...) \, +#define Z_IS_3562U_EQ_3562(...) \, +#define Z_IS_3562_EQ_3562U(...) \, +#define Z_IS_3562U_EQ_3562U(...) \, +#define Z_IS_3563_EQ_3563(...) \, +#define Z_IS_3563U_EQ_3563(...) \, +#define Z_IS_3563_EQ_3563U(...) \, +#define Z_IS_3563U_EQ_3563U(...) \, +#define Z_IS_3564_EQ_3564(...) \, +#define Z_IS_3564U_EQ_3564(...) \, +#define Z_IS_3564_EQ_3564U(...) \, +#define Z_IS_3564U_EQ_3564U(...) \, +#define Z_IS_3565_EQ_3565(...) \, +#define Z_IS_3565U_EQ_3565(...) \, +#define Z_IS_3565_EQ_3565U(...) \, +#define Z_IS_3565U_EQ_3565U(...) \, +#define Z_IS_3566_EQ_3566(...) \, +#define Z_IS_3566U_EQ_3566(...) \, +#define Z_IS_3566_EQ_3566U(...) \, +#define Z_IS_3566U_EQ_3566U(...) \, +#define Z_IS_3567_EQ_3567(...) \, +#define Z_IS_3567U_EQ_3567(...) \, +#define Z_IS_3567_EQ_3567U(...) \, +#define Z_IS_3567U_EQ_3567U(...) \, +#define Z_IS_3568_EQ_3568(...) \, +#define Z_IS_3568U_EQ_3568(...) \, +#define Z_IS_3568_EQ_3568U(...) \, +#define Z_IS_3568U_EQ_3568U(...) \, +#define Z_IS_3569_EQ_3569(...) \, +#define Z_IS_3569U_EQ_3569(...) \, +#define Z_IS_3569_EQ_3569U(...) \, +#define Z_IS_3569U_EQ_3569U(...) \, +#define Z_IS_3570_EQ_3570(...) \, +#define Z_IS_3570U_EQ_3570(...) \, +#define Z_IS_3570_EQ_3570U(...) \, +#define Z_IS_3570U_EQ_3570U(...) \, +#define Z_IS_3571_EQ_3571(...) \, +#define Z_IS_3571U_EQ_3571(...) \, +#define Z_IS_3571_EQ_3571U(...) \, +#define Z_IS_3571U_EQ_3571U(...) \, +#define Z_IS_3572_EQ_3572(...) \, +#define Z_IS_3572U_EQ_3572(...) \, +#define Z_IS_3572_EQ_3572U(...) \, +#define Z_IS_3572U_EQ_3572U(...) \, +#define Z_IS_3573_EQ_3573(...) \, +#define Z_IS_3573U_EQ_3573(...) \, +#define Z_IS_3573_EQ_3573U(...) \, +#define Z_IS_3573U_EQ_3573U(...) \, +#define Z_IS_3574_EQ_3574(...) \, +#define Z_IS_3574U_EQ_3574(...) \, +#define Z_IS_3574_EQ_3574U(...) \, +#define Z_IS_3574U_EQ_3574U(...) \, +#define Z_IS_3575_EQ_3575(...) \, +#define Z_IS_3575U_EQ_3575(...) \, +#define Z_IS_3575_EQ_3575U(...) \, +#define Z_IS_3575U_EQ_3575U(...) \, +#define Z_IS_3576_EQ_3576(...) \, +#define Z_IS_3576U_EQ_3576(...) \, +#define Z_IS_3576_EQ_3576U(...) \, +#define Z_IS_3576U_EQ_3576U(...) \, +#define Z_IS_3577_EQ_3577(...) \, +#define Z_IS_3577U_EQ_3577(...) \, +#define Z_IS_3577_EQ_3577U(...) \, +#define Z_IS_3577U_EQ_3577U(...) \, +#define Z_IS_3578_EQ_3578(...) \, +#define Z_IS_3578U_EQ_3578(...) \, +#define Z_IS_3578_EQ_3578U(...) \, +#define Z_IS_3578U_EQ_3578U(...) \, +#define Z_IS_3579_EQ_3579(...) \, +#define Z_IS_3579U_EQ_3579(...) \, +#define Z_IS_3579_EQ_3579U(...) \, +#define Z_IS_3579U_EQ_3579U(...) \, +#define Z_IS_3580_EQ_3580(...) \, +#define Z_IS_3580U_EQ_3580(...) \, +#define Z_IS_3580_EQ_3580U(...) \, +#define Z_IS_3580U_EQ_3580U(...) \, +#define Z_IS_3581_EQ_3581(...) \, +#define Z_IS_3581U_EQ_3581(...) \, +#define Z_IS_3581_EQ_3581U(...) \, +#define Z_IS_3581U_EQ_3581U(...) \, +#define Z_IS_3582_EQ_3582(...) \, +#define Z_IS_3582U_EQ_3582(...) \, +#define Z_IS_3582_EQ_3582U(...) \, +#define Z_IS_3582U_EQ_3582U(...) \, +#define Z_IS_3583_EQ_3583(...) \, +#define Z_IS_3583U_EQ_3583(...) \, +#define Z_IS_3583_EQ_3583U(...) \, +#define Z_IS_3583U_EQ_3583U(...) \, +#define Z_IS_3584_EQ_3584(...) \, +#define Z_IS_3584U_EQ_3584(...) \, +#define Z_IS_3584_EQ_3584U(...) \, +#define Z_IS_3584U_EQ_3584U(...) \, +#define Z_IS_3585_EQ_3585(...) \, +#define Z_IS_3585U_EQ_3585(...) \, +#define Z_IS_3585_EQ_3585U(...) \, +#define Z_IS_3585U_EQ_3585U(...) \, +#define Z_IS_3586_EQ_3586(...) \, +#define Z_IS_3586U_EQ_3586(...) \, +#define Z_IS_3586_EQ_3586U(...) \, +#define Z_IS_3586U_EQ_3586U(...) \, +#define Z_IS_3587_EQ_3587(...) \, +#define Z_IS_3587U_EQ_3587(...) \, +#define Z_IS_3587_EQ_3587U(...) \, +#define Z_IS_3587U_EQ_3587U(...) \, +#define Z_IS_3588_EQ_3588(...) \, +#define Z_IS_3588U_EQ_3588(...) \, +#define Z_IS_3588_EQ_3588U(...) \, +#define Z_IS_3588U_EQ_3588U(...) \, +#define Z_IS_3589_EQ_3589(...) \, +#define Z_IS_3589U_EQ_3589(...) \, +#define Z_IS_3589_EQ_3589U(...) \, +#define Z_IS_3589U_EQ_3589U(...) \, +#define Z_IS_3590_EQ_3590(...) \, +#define Z_IS_3590U_EQ_3590(...) \, +#define Z_IS_3590_EQ_3590U(...) \, +#define Z_IS_3590U_EQ_3590U(...) \, +#define Z_IS_3591_EQ_3591(...) \, +#define Z_IS_3591U_EQ_3591(...) \, +#define Z_IS_3591_EQ_3591U(...) \, +#define Z_IS_3591U_EQ_3591U(...) \, +#define Z_IS_3592_EQ_3592(...) \, +#define Z_IS_3592U_EQ_3592(...) \, +#define Z_IS_3592_EQ_3592U(...) \, +#define Z_IS_3592U_EQ_3592U(...) \, +#define Z_IS_3593_EQ_3593(...) \, +#define Z_IS_3593U_EQ_3593(...) \, +#define Z_IS_3593_EQ_3593U(...) \, +#define Z_IS_3593U_EQ_3593U(...) \, +#define Z_IS_3594_EQ_3594(...) \, +#define Z_IS_3594U_EQ_3594(...) \, +#define Z_IS_3594_EQ_3594U(...) \, +#define Z_IS_3594U_EQ_3594U(...) \, +#define Z_IS_3595_EQ_3595(...) \, +#define Z_IS_3595U_EQ_3595(...) \, +#define Z_IS_3595_EQ_3595U(...) \, +#define Z_IS_3595U_EQ_3595U(...) \, +#define Z_IS_3596_EQ_3596(...) \, +#define Z_IS_3596U_EQ_3596(...) \, +#define Z_IS_3596_EQ_3596U(...) \, +#define Z_IS_3596U_EQ_3596U(...) \, +#define Z_IS_3597_EQ_3597(...) \, +#define Z_IS_3597U_EQ_3597(...) \, +#define Z_IS_3597_EQ_3597U(...) \, +#define Z_IS_3597U_EQ_3597U(...) \, +#define Z_IS_3598_EQ_3598(...) \, +#define Z_IS_3598U_EQ_3598(...) \, +#define Z_IS_3598_EQ_3598U(...) \, +#define Z_IS_3598U_EQ_3598U(...) \, +#define Z_IS_3599_EQ_3599(...) \, +#define Z_IS_3599U_EQ_3599(...) \, +#define Z_IS_3599_EQ_3599U(...) \, +#define Z_IS_3599U_EQ_3599U(...) \, +#define Z_IS_3600_EQ_3600(...) \, +#define Z_IS_3600U_EQ_3600(...) \, +#define Z_IS_3600_EQ_3600U(...) \, +#define Z_IS_3600U_EQ_3600U(...) \, +#define Z_IS_3601_EQ_3601(...) \, +#define Z_IS_3601U_EQ_3601(...) \, +#define Z_IS_3601_EQ_3601U(...) \, +#define Z_IS_3601U_EQ_3601U(...) \, +#define Z_IS_3602_EQ_3602(...) \, +#define Z_IS_3602U_EQ_3602(...) \, +#define Z_IS_3602_EQ_3602U(...) \, +#define Z_IS_3602U_EQ_3602U(...) \, +#define Z_IS_3603_EQ_3603(...) \, +#define Z_IS_3603U_EQ_3603(...) \, +#define Z_IS_3603_EQ_3603U(...) \, +#define Z_IS_3603U_EQ_3603U(...) \, +#define Z_IS_3604_EQ_3604(...) \, +#define Z_IS_3604U_EQ_3604(...) \, +#define Z_IS_3604_EQ_3604U(...) \, +#define Z_IS_3604U_EQ_3604U(...) \, +#define Z_IS_3605_EQ_3605(...) \, +#define Z_IS_3605U_EQ_3605(...) \, +#define Z_IS_3605_EQ_3605U(...) \, +#define Z_IS_3605U_EQ_3605U(...) \, +#define Z_IS_3606_EQ_3606(...) \, +#define Z_IS_3606U_EQ_3606(...) \, +#define Z_IS_3606_EQ_3606U(...) \, +#define Z_IS_3606U_EQ_3606U(...) \, +#define Z_IS_3607_EQ_3607(...) \, +#define Z_IS_3607U_EQ_3607(...) \, +#define Z_IS_3607_EQ_3607U(...) \, +#define Z_IS_3607U_EQ_3607U(...) \, +#define Z_IS_3608_EQ_3608(...) \, +#define Z_IS_3608U_EQ_3608(...) \, +#define Z_IS_3608_EQ_3608U(...) \, +#define Z_IS_3608U_EQ_3608U(...) \, +#define Z_IS_3609_EQ_3609(...) \, +#define Z_IS_3609U_EQ_3609(...) \, +#define Z_IS_3609_EQ_3609U(...) \, +#define Z_IS_3609U_EQ_3609U(...) \, +#define Z_IS_3610_EQ_3610(...) \, +#define Z_IS_3610U_EQ_3610(...) \, +#define Z_IS_3610_EQ_3610U(...) \, +#define Z_IS_3610U_EQ_3610U(...) \, +#define Z_IS_3611_EQ_3611(...) \, +#define Z_IS_3611U_EQ_3611(...) \, +#define Z_IS_3611_EQ_3611U(...) \, +#define Z_IS_3611U_EQ_3611U(...) \, +#define Z_IS_3612_EQ_3612(...) \, +#define Z_IS_3612U_EQ_3612(...) \, +#define Z_IS_3612_EQ_3612U(...) \, +#define Z_IS_3612U_EQ_3612U(...) \, +#define Z_IS_3613_EQ_3613(...) \, +#define Z_IS_3613U_EQ_3613(...) \, +#define Z_IS_3613_EQ_3613U(...) \, +#define Z_IS_3613U_EQ_3613U(...) \, +#define Z_IS_3614_EQ_3614(...) \, +#define Z_IS_3614U_EQ_3614(...) \, +#define Z_IS_3614_EQ_3614U(...) \, +#define Z_IS_3614U_EQ_3614U(...) \, +#define Z_IS_3615_EQ_3615(...) \, +#define Z_IS_3615U_EQ_3615(...) \, +#define Z_IS_3615_EQ_3615U(...) \, +#define Z_IS_3615U_EQ_3615U(...) \, +#define Z_IS_3616_EQ_3616(...) \, +#define Z_IS_3616U_EQ_3616(...) \, +#define Z_IS_3616_EQ_3616U(...) \, +#define Z_IS_3616U_EQ_3616U(...) \, +#define Z_IS_3617_EQ_3617(...) \, +#define Z_IS_3617U_EQ_3617(...) \, +#define Z_IS_3617_EQ_3617U(...) \, +#define Z_IS_3617U_EQ_3617U(...) \, +#define Z_IS_3618_EQ_3618(...) \, +#define Z_IS_3618U_EQ_3618(...) \, +#define Z_IS_3618_EQ_3618U(...) \, +#define Z_IS_3618U_EQ_3618U(...) \, +#define Z_IS_3619_EQ_3619(...) \, +#define Z_IS_3619U_EQ_3619(...) \, +#define Z_IS_3619_EQ_3619U(...) \, +#define Z_IS_3619U_EQ_3619U(...) \, +#define Z_IS_3620_EQ_3620(...) \, +#define Z_IS_3620U_EQ_3620(...) \, +#define Z_IS_3620_EQ_3620U(...) \, +#define Z_IS_3620U_EQ_3620U(...) \, +#define Z_IS_3621_EQ_3621(...) \, +#define Z_IS_3621U_EQ_3621(...) \, +#define Z_IS_3621_EQ_3621U(...) \, +#define Z_IS_3621U_EQ_3621U(...) \, +#define Z_IS_3622_EQ_3622(...) \, +#define Z_IS_3622U_EQ_3622(...) \, +#define Z_IS_3622_EQ_3622U(...) \, +#define Z_IS_3622U_EQ_3622U(...) \, +#define Z_IS_3623_EQ_3623(...) \, +#define Z_IS_3623U_EQ_3623(...) \, +#define Z_IS_3623_EQ_3623U(...) \, +#define Z_IS_3623U_EQ_3623U(...) \, +#define Z_IS_3624_EQ_3624(...) \, +#define Z_IS_3624U_EQ_3624(...) \, +#define Z_IS_3624_EQ_3624U(...) \, +#define Z_IS_3624U_EQ_3624U(...) \, +#define Z_IS_3625_EQ_3625(...) \, +#define Z_IS_3625U_EQ_3625(...) \, +#define Z_IS_3625_EQ_3625U(...) \, +#define Z_IS_3625U_EQ_3625U(...) \, +#define Z_IS_3626_EQ_3626(...) \, +#define Z_IS_3626U_EQ_3626(...) \, +#define Z_IS_3626_EQ_3626U(...) \, +#define Z_IS_3626U_EQ_3626U(...) \, +#define Z_IS_3627_EQ_3627(...) \, +#define Z_IS_3627U_EQ_3627(...) \, +#define Z_IS_3627_EQ_3627U(...) \, +#define Z_IS_3627U_EQ_3627U(...) \, +#define Z_IS_3628_EQ_3628(...) \, +#define Z_IS_3628U_EQ_3628(...) \, +#define Z_IS_3628_EQ_3628U(...) \, +#define Z_IS_3628U_EQ_3628U(...) \, +#define Z_IS_3629_EQ_3629(...) \, +#define Z_IS_3629U_EQ_3629(...) \, +#define Z_IS_3629_EQ_3629U(...) \, +#define Z_IS_3629U_EQ_3629U(...) \, +#define Z_IS_3630_EQ_3630(...) \, +#define Z_IS_3630U_EQ_3630(...) \, +#define Z_IS_3630_EQ_3630U(...) \, +#define Z_IS_3630U_EQ_3630U(...) \, +#define Z_IS_3631_EQ_3631(...) \, +#define Z_IS_3631U_EQ_3631(...) \, +#define Z_IS_3631_EQ_3631U(...) \, +#define Z_IS_3631U_EQ_3631U(...) \, +#define Z_IS_3632_EQ_3632(...) \, +#define Z_IS_3632U_EQ_3632(...) \, +#define Z_IS_3632_EQ_3632U(...) \, +#define Z_IS_3632U_EQ_3632U(...) \, +#define Z_IS_3633_EQ_3633(...) \, +#define Z_IS_3633U_EQ_3633(...) \, +#define Z_IS_3633_EQ_3633U(...) \, +#define Z_IS_3633U_EQ_3633U(...) \, +#define Z_IS_3634_EQ_3634(...) \, +#define Z_IS_3634U_EQ_3634(...) \, +#define Z_IS_3634_EQ_3634U(...) \, +#define Z_IS_3634U_EQ_3634U(...) \, +#define Z_IS_3635_EQ_3635(...) \, +#define Z_IS_3635U_EQ_3635(...) \, +#define Z_IS_3635_EQ_3635U(...) \, +#define Z_IS_3635U_EQ_3635U(...) \, +#define Z_IS_3636_EQ_3636(...) \, +#define Z_IS_3636U_EQ_3636(...) \, +#define Z_IS_3636_EQ_3636U(...) \, +#define Z_IS_3636U_EQ_3636U(...) \, +#define Z_IS_3637_EQ_3637(...) \, +#define Z_IS_3637U_EQ_3637(...) \, +#define Z_IS_3637_EQ_3637U(...) \, +#define Z_IS_3637U_EQ_3637U(...) \, +#define Z_IS_3638_EQ_3638(...) \, +#define Z_IS_3638U_EQ_3638(...) \, +#define Z_IS_3638_EQ_3638U(...) \, +#define Z_IS_3638U_EQ_3638U(...) \, +#define Z_IS_3639_EQ_3639(...) \, +#define Z_IS_3639U_EQ_3639(...) \, +#define Z_IS_3639_EQ_3639U(...) \, +#define Z_IS_3639U_EQ_3639U(...) \, +#define Z_IS_3640_EQ_3640(...) \, +#define Z_IS_3640U_EQ_3640(...) \, +#define Z_IS_3640_EQ_3640U(...) \, +#define Z_IS_3640U_EQ_3640U(...) \, +#define Z_IS_3641_EQ_3641(...) \, +#define Z_IS_3641U_EQ_3641(...) \, +#define Z_IS_3641_EQ_3641U(...) \, +#define Z_IS_3641U_EQ_3641U(...) \, +#define Z_IS_3642_EQ_3642(...) \, +#define Z_IS_3642U_EQ_3642(...) \, +#define Z_IS_3642_EQ_3642U(...) \, +#define Z_IS_3642U_EQ_3642U(...) \, +#define Z_IS_3643_EQ_3643(...) \, +#define Z_IS_3643U_EQ_3643(...) \, +#define Z_IS_3643_EQ_3643U(...) \, +#define Z_IS_3643U_EQ_3643U(...) \, +#define Z_IS_3644_EQ_3644(...) \, +#define Z_IS_3644U_EQ_3644(...) \, +#define Z_IS_3644_EQ_3644U(...) \, +#define Z_IS_3644U_EQ_3644U(...) \, +#define Z_IS_3645_EQ_3645(...) \, +#define Z_IS_3645U_EQ_3645(...) \, +#define Z_IS_3645_EQ_3645U(...) \, +#define Z_IS_3645U_EQ_3645U(...) \, +#define Z_IS_3646_EQ_3646(...) \, +#define Z_IS_3646U_EQ_3646(...) \, +#define Z_IS_3646_EQ_3646U(...) \, +#define Z_IS_3646U_EQ_3646U(...) \, +#define Z_IS_3647_EQ_3647(...) \, +#define Z_IS_3647U_EQ_3647(...) \, +#define Z_IS_3647_EQ_3647U(...) \, +#define Z_IS_3647U_EQ_3647U(...) \, +#define Z_IS_3648_EQ_3648(...) \, +#define Z_IS_3648U_EQ_3648(...) \, +#define Z_IS_3648_EQ_3648U(...) \, +#define Z_IS_3648U_EQ_3648U(...) \, +#define Z_IS_3649_EQ_3649(...) \, +#define Z_IS_3649U_EQ_3649(...) \, +#define Z_IS_3649_EQ_3649U(...) \, +#define Z_IS_3649U_EQ_3649U(...) \, +#define Z_IS_3650_EQ_3650(...) \, +#define Z_IS_3650U_EQ_3650(...) \, +#define Z_IS_3650_EQ_3650U(...) \, +#define Z_IS_3650U_EQ_3650U(...) \, +#define Z_IS_3651_EQ_3651(...) \, +#define Z_IS_3651U_EQ_3651(...) \, +#define Z_IS_3651_EQ_3651U(...) \, +#define Z_IS_3651U_EQ_3651U(...) \, +#define Z_IS_3652_EQ_3652(...) \, +#define Z_IS_3652U_EQ_3652(...) \, +#define Z_IS_3652_EQ_3652U(...) \, +#define Z_IS_3652U_EQ_3652U(...) \, +#define Z_IS_3653_EQ_3653(...) \, +#define Z_IS_3653U_EQ_3653(...) \, +#define Z_IS_3653_EQ_3653U(...) \, +#define Z_IS_3653U_EQ_3653U(...) \, +#define Z_IS_3654_EQ_3654(...) \, +#define Z_IS_3654U_EQ_3654(...) \, +#define Z_IS_3654_EQ_3654U(...) \, +#define Z_IS_3654U_EQ_3654U(...) \, +#define Z_IS_3655_EQ_3655(...) \, +#define Z_IS_3655U_EQ_3655(...) \, +#define Z_IS_3655_EQ_3655U(...) \, +#define Z_IS_3655U_EQ_3655U(...) \, +#define Z_IS_3656_EQ_3656(...) \, +#define Z_IS_3656U_EQ_3656(...) \, +#define Z_IS_3656_EQ_3656U(...) \, +#define Z_IS_3656U_EQ_3656U(...) \, +#define Z_IS_3657_EQ_3657(...) \, +#define Z_IS_3657U_EQ_3657(...) \, +#define Z_IS_3657_EQ_3657U(...) \, +#define Z_IS_3657U_EQ_3657U(...) \, +#define Z_IS_3658_EQ_3658(...) \, +#define Z_IS_3658U_EQ_3658(...) \, +#define Z_IS_3658_EQ_3658U(...) \, +#define Z_IS_3658U_EQ_3658U(...) \, +#define Z_IS_3659_EQ_3659(...) \, +#define Z_IS_3659U_EQ_3659(...) \, +#define Z_IS_3659_EQ_3659U(...) \, +#define Z_IS_3659U_EQ_3659U(...) \, +#define Z_IS_3660_EQ_3660(...) \, +#define Z_IS_3660U_EQ_3660(...) \, +#define Z_IS_3660_EQ_3660U(...) \, +#define Z_IS_3660U_EQ_3660U(...) \, +#define Z_IS_3661_EQ_3661(...) \, +#define Z_IS_3661U_EQ_3661(...) \, +#define Z_IS_3661_EQ_3661U(...) \, +#define Z_IS_3661U_EQ_3661U(...) \, +#define Z_IS_3662_EQ_3662(...) \, +#define Z_IS_3662U_EQ_3662(...) \, +#define Z_IS_3662_EQ_3662U(...) \, +#define Z_IS_3662U_EQ_3662U(...) \, +#define Z_IS_3663_EQ_3663(...) \, +#define Z_IS_3663U_EQ_3663(...) \, +#define Z_IS_3663_EQ_3663U(...) \, +#define Z_IS_3663U_EQ_3663U(...) \, +#define Z_IS_3664_EQ_3664(...) \, +#define Z_IS_3664U_EQ_3664(...) \, +#define Z_IS_3664_EQ_3664U(...) \, +#define Z_IS_3664U_EQ_3664U(...) \, +#define Z_IS_3665_EQ_3665(...) \, +#define Z_IS_3665U_EQ_3665(...) \, +#define Z_IS_3665_EQ_3665U(...) \, +#define Z_IS_3665U_EQ_3665U(...) \, +#define Z_IS_3666_EQ_3666(...) \, +#define Z_IS_3666U_EQ_3666(...) \, +#define Z_IS_3666_EQ_3666U(...) \, +#define Z_IS_3666U_EQ_3666U(...) \, +#define Z_IS_3667_EQ_3667(...) \, +#define Z_IS_3667U_EQ_3667(...) \, +#define Z_IS_3667_EQ_3667U(...) \, +#define Z_IS_3667U_EQ_3667U(...) \, +#define Z_IS_3668_EQ_3668(...) \, +#define Z_IS_3668U_EQ_3668(...) \, +#define Z_IS_3668_EQ_3668U(...) \, +#define Z_IS_3668U_EQ_3668U(...) \, +#define Z_IS_3669_EQ_3669(...) \, +#define Z_IS_3669U_EQ_3669(...) \, +#define Z_IS_3669_EQ_3669U(...) \, +#define Z_IS_3669U_EQ_3669U(...) \, +#define Z_IS_3670_EQ_3670(...) \, +#define Z_IS_3670U_EQ_3670(...) \, +#define Z_IS_3670_EQ_3670U(...) \, +#define Z_IS_3670U_EQ_3670U(...) \, +#define Z_IS_3671_EQ_3671(...) \, +#define Z_IS_3671U_EQ_3671(...) \, +#define Z_IS_3671_EQ_3671U(...) \, +#define Z_IS_3671U_EQ_3671U(...) \, +#define Z_IS_3672_EQ_3672(...) \, +#define Z_IS_3672U_EQ_3672(...) \, +#define Z_IS_3672_EQ_3672U(...) \, +#define Z_IS_3672U_EQ_3672U(...) \, +#define Z_IS_3673_EQ_3673(...) \, +#define Z_IS_3673U_EQ_3673(...) \, +#define Z_IS_3673_EQ_3673U(...) \, +#define Z_IS_3673U_EQ_3673U(...) \, +#define Z_IS_3674_EQ_3674(...) \, +#define Z_IS_3674U_EQ_3674(...) \, +#define Z_IS_3674_EQ_3674U(...) \, +#define Z_IS_3674U_EQ_3674U(...) \, +#define Z_IS_3675_EQ_3675(...) \, +#define Z_IS_3675U_EQ_3675(...) \, +#define Z_IS_3675_EQ_3675U(...) \, +#define Z_IS_3675U_EQ_3675U(...) \, +#define Z_IS_3676_EQ_3676(...) \, +#define Z_IS_3676U_EQ_3676(...) \, +#define Z_IS_3676_EQ_3676U(...) \, +#define Z_IS_3676U_EQ_3676U(...) \, +#define Z_IS_3677_EQ_3677(...) \, +#define Z_IS_3677U_EQ_3677(...) \, +#define Z_IS_3677_EQ_3677U(...) \, +#define Z_IS_3677U_EQ_3677U(...) \, +#define Z_IS_3678_EQ_3678(...) \, +#define Z_IS_3678U_EQ_3678(...) \, +#define Z_IS_3678_EQ_3678U(...) \, +#define Z_IS_3678U_EQ_3678U(...) \, +#define Z_IS_3679_EQ_3679(...) \, +#define Z_IS_3679U_EQ_3679(...) \, +#define Z_IS_3679_EQ_3679U(...) \, +#define Z_IS_3679U_EQ_3679U(...) \, +#define Z_IS_3680_EQ_3680(...) \, +#define Z_IS_3680U_EQ_3680(...) \, +#define Z_IS_3680_EQ_3680U(...) \, +#define Z_IS_3680U_EQ_3680U(...) \, +#define Z_IS_3681_EQ_3681(...) \, +#define Z_IS_3681U_EQ_3681(...) \, +#define Z_IS_3681_EQ_3681U(...) \, +#define Z_IS_3681U_EQ_3681U(...) \, +#define Z_IS_3682_EQ_3682(...) \, +#define Z_IS_3682U_EQ_3682(...) \, +#define Z_IS_3682_EQ_3682U(...) \, +#define Z_IS_3682U_EQ_3682U(...) \, +#define Z_IS_3683_EQ_3683(...) \, +#define Z_IS_3683U_EQ_3683(...) \, +#define Z_IS_3683_EQ_3683U(...) \, +#define Z_IS_3683U_EQ_3683U(...) \, +#define Z_IS_3684_EQ_3684(...) \, +#define Z_IS_3684U_EQ_3684(...) \, +#define Z_IS_3684_EQ_3684U(...) \, +#define Z_IS_3684U_EQ_3684U(...) \, +#define Z_IS_3685_EQ_3685(...) \, +#define Z_IS_3685U_EQ_3685(...) \, +#define Z_IS_3685_EQ_3685U(...) \, +#define Z_IS_3685U_EQ_3685U(...) \, +#define Z_IS_3686_EQ_3686(...) \, +#define Z_IS_3686U_EQ_3686(...) \, +#define Z_IS_3686_EQ_3686U(...) \, +#define Z_IS_3686U_EQ_3686U(...) \, +#define Z_IS_3687_EQ_3687(...) \, +#define Z_IS_3687U_EQ_3687(...) \, +#define Z_IS_3687_EQ_3687U(...) \, +#define Z_IS_3687U_EQ_3687U(...) \, +#define Z_IS_3688_EQ_3688(...) \, +#define Z_IS_3688U_EQ_3688(...) \, +#define Z_IS_3688_EQ_3688U(...) \, +#define Z_IS_3688U_EQ_3688U(...) \, +#define Z_IS_3689_EQ_3689(...) \, +#define Z_IS_3689U_EQ_3689(...) \, +#define Z_IS_3689_EQ_3689U(...) \, +#define Z_IS_3689U_EQ_3689U(...) \, +#define Z_IS_3690_EQ_3690(...) \, +#define Z_IS_3690U_EQ_3690(...) \, +#define Z_IS_3690_EQ_3690U(...) \, +#define Z_IS_3690U_EQ_3690U(...) \, +#define Z_IS_3691_EQ_3691(...) \, +#define Z_IS_3691U_EQ_3691(...) \, +#define Z_IS_3691_EQ_3691U(...) \, +#define Z_IS_3691U_EQ_3691U(...) \, +#define Z_IS_3692_EQ_3692(...) \, +#define Z_IS_3692U_EQ_3692(...) \, +#define Z_IS_3692_EQ_3692U(...) \, +#define Z_IS_3692U_EQ_3692U(...) \, +#define Z_IS_3693_EQ_3693(...) \, +#define Z_IS_3693U_EQ_3693(...) \, +#define Z_IS_3693_EQ_3693U(...) \, +#define Z_IS_3693U_EQ_3693U(...) \, +#define Z_IS_3694_EQ_3694(...) \, +#define Z_IS_3694U_EQ_3694(...) \, +#define Z_IS_3694_EQ_3694U(...) \, +#define Z_IS_3694U_EQ_3694U(...) \, +#define Z_IS_3695_EQ_3695(...) \, +#define Z_IS_3695U_EQ_3695(...) \, +#define Z_IS_3695_EQ_3695U(...) \, +#define Z_IS_3695U_EQ_3695U(...) \, +#define Z_IS_3696_EQ_3696(...) \, +#define Z_IS_3696U_EQ_3696(...) \, +#define Z_IS_3696_EQ_3696U(...) \, +#define Z_IS_3696U_EQ_3696U(...) \, +#define Z_IS_3697_EQ_3697(...) \, +#define Z_IS_3697U_EQ_3697(...) \, +#define Z_IS_3697_EQ_3697U(...) \, +#define Z_IS_3697U_EQ_3697U(...) \, +#define Z_IS_3698_EQ_3698(...) \, +#define Z_IS_3698U_EQ_3698(...) \, +#define Z_IS_3698_EQ_3698U(...) \, +#define Z_IS_3698U_EQ_3698U(...) \, +#define Z_IS_3699_EQ_3699(...) \, +#define Z_IS_3699U_EQ_3699(...) \, +#define Z_IS_3699_EQ_3699U(...) \, +#define Z_IS_3699U_EQ_3699U(...) \, +#define Z_IS_3700_EQ_3700(...) \, +#define Z_IS_3700U_EQ_3700(...) \, +#define Z_IS_3700_EQ_3700U(...) \, +#define Z_IS_3700U_EQ_3700U(...) \, +#define Z_IS_3701_EQ_3701(...) \, +#define Z_IS_3701U_EQ_3701(...) \, +#define Z_IS_3701_EQ_3701U(...) \, +#define Z_IS_3701U_EQ_3701U(...) \, +#define Z_IS_3702_EQ_3702(...) \, +#define Z_IS_3702U_EQ_3702(...) \, +#define Z_IS_3702_EQ_3702U(...) \, +#define Z_IS_3702U_EQ_3702U(...) \, +#define Z_IS_3703_EQ_3703(...) \, +#define Z_IS_3703U_EQ_3703(...) \, +#define Z_IS_3703_EQ_3703U(...) \, +#define Z_IS_3703U_EQ_3703U(...) \, +#define Z_IS_3704_EQ_3704(...) \, +#define Z_IS_3704U_EQ_3704(...) \, +#define Z_IS_3704_EQ_3704U(...) \, +#define Z_IS_3704U_EQ_3704U(...) \, +#define Z_IS_3705_EQ_3705(...) \, +#define Z_IS_3705U_EQ_3705(...) \, +#define Z_IS_3705_EQ_3705U(...) \, +#define Z_IS_3705U_EQ_3705U(...) \, +#define Z_IS_3706_EQ_3706(...) \, +#define Z_IS_3706U_EQ_3706(...) \, +#define Z_IS_3706_EQ_3706U(...) \, +#define Z_IS_3706U_EQ_3706U(...) \, +#define Z_IS_3707_EQ_3707(...) \, +#define Z_IS_3707U_EQ_3707(...) \, +#define Z_IS_3707_EQ_3707U(...) \, +#define Z_IS_3707U_EQ_3707U(...) \, +#define Z_IS_3708_EQ_3708(...) \, +#define Z_IS_3708U_EQ_3708(...) \, +#define Z_IS_3708_EQ_3708U(...) \, +#define Z_IS_3708U_EQ_3708U(...) \, +#define Z_IS_3709_EQ_3709(...) \, +#define Z_IS_3709U_EQ_3709(...) \, +#define Z_IS_3709_EQ_3709U(...) \, +#define Z_IS_3709U_EQ_3709U(...) \, +#define Z_IS_3710_EQ_3710(...) \, +#define Z_IS_3710U_EQ_3710(...) \, +#define Z_IS_3710_EQ_3710U(...) \, +#define Z_IS_3710U_EQ_3710U(...) \, +#define Z_IS_3711_EQ_3711(...) \, +#define Z_IS_3711U_EQ_3711(...) \, +#define Z_IS_3711_EQ_3711U(...) \, +#define Z_IS_3711U_EQ_3711U(...) \, +#define Z_IS_3712_EQ_3712(...) \, +#define Z_IS_3712U_EQ_3712(...) \, +#define Z_IS_3712_EQ_3712U(...) \, +#define Z_IS_3712U_EQ_3712U(...) \, +#define Z_IS_3713_EQ_3713(...) \, +#define Z_IS_3713U_EQ_3713(...) \, +#define Z_IS_3713_EQ_3713U(...) \, +#define Z_IS_3713U_EQ_3713U(...) \, +#define Z_IS_3714_EQ_3714(...) \, +#define Z_IS_3714U_EQ_3714(...) \, +#define Z_IS_3714_EQ_3714U(...) \, +#define Z_IS_3714U_EQ_3714U(...) \, +#define Z_IS_3715_EQ_3715(...) \, +#define Z_IS_3715U_EQ_3715(...) \, +#define Z_IS_3715_EQ_3715U(...) \, +#define Z_IS_3715U_EQ_3715U(...) \, +#define Z_IS_3716_EQ_3716(...) \, +#define Z_IS_3716U_EQ_3716(...) \, +#define Z_IS_3716_EQ_3716U(...) \, +#define Z_IS_3716U_EQ_3716U(...) \, +#define Z_IS_3717_EQ_3717(...) \, +#define Z_IS_3717U_EQ_3717(...) \, +#define Z_IS_3717_EQ_3717U(...) \, +#define Z_IS_3717U_EQ_3717U(...) \, +#define Z_IS_3718_EQ_3718(...) \, +#define Z_IS_3718U_EQ_3718(...) \, +#define Z_IS_3718_EQ_3718U(...) \, +#define Z_IS_3718U_EQ_3718U(...) \, +#define Z_IS_3719_EQ_3719(...) \, +#define Z_IS_3719U_EQ_3719(...) \, +#define Z_IS_3719_EQ_3719U(...) \, +#define Z_IS_3719U_EQ_3719U(...) \, +#define Z_IS_3720_EQ_3720(...) \, +#define Z_IS_3720U_EQ_3720(...) \, +#define Z_IS_3720_EQ_3720U(...) \, +#define Z_IS_3720U_EQ_3720U(...) \, +#define Z_IS_3721_EQ_3721(...) \, +#define Z_IS_3721U_EQ_3721(...) \, +#define Z_IS_3721_EQ_3721U(...) \, +#define Z_IS_3721U_EQ_3721U(...) \, +#define Z_IS_3722_EQ_3722(...) \, +#define Z_IS_3722U_EQ_3722(...) \, +#define Z_IS_3722_EQ_3722U(...) \, +#define Z_IS_3722U_EQ_3722U(...) \, +#define Z_IS_3723_EQ_3723(...) \, +#define Z_IS_3723U_EQ_3723(...) \, +#define Z_IS_3723_EQ_3723U(...) \, +#define Z_IS_3723U_EQ_3723U(...) \, +#define Z_IS_3724_EQ_3724(...) \, +#define Z_IS_3724U_EQ_3724(...) \, +#define Z_IS_3724_EQ_3724U(...) \, +#define Z_IS_3724U_EQ_3724U(...) \, +#define Z_IS_3725_EQ_3725(...) \, +#define Z_IS_3725U_EQ_3725(...) \, +#define Z_IS_3725_EQ_3725U(...) \, +#define Z_IS_3725U_EQ_3725U(...) \, +#define Z_IS_3726_EQ_3726(...) \, +#define Z_IS_3726U_EQ_3726(...) \, +#define Z_IS_3726_EQ_3726U(...) \, +#define Z_IS_3726U_EQ_3726U(...) \, +#define Z_IS_3727_EQ_3727(...) \, +#define Z_IS_3727U_EQ_3727(...) \, +#define Z_IS_3727_EQ_3727U(...) \, +#define Z_IS_3727U_EQ_3727U(...) \, +#define Z_IS_3728_EQ_3728(...) \, +#define Z_IS_3728U_EQ_3728(...) \, +#define Z_IS_3728_EQ_3728U(...) \, +#define Z_IS_3728U_EQ_3728U(...) \, +#define Z_IS_3729_EQ_3729(...) \, +#define Z_IS_3729U_EQ_3729(...) \, +#define Z_IS_3729_EQ_3729U(...) \, +#define Z_IS_3729U_EQ_3729U(...) \, +#define Z_IS_3730_EQ_3730(...) \, +#define Z_IS_3730U_EQ_3730(...) \, +#define Z_IS_3730_EQ_3730U(...) \, +#define Z_IS_3730U_EQ_3730U(...) \, +#define Z_IS_3731_EQ_3731(...) \, +#define Z_IS_3731U_EQ_3731(...) \, +#define Z_IS_3731_EQ_3731U(...) \, +#define Z_IS_3731U_EQ_3731U(...) \, +#define Z_IS_3732_EQ_3732(...) \, +#define Z_IS_3732U_EQ_3732(...) \, +#define Z_IS_3732_EQ_3732U(...) \, +#define Z_IS_3732U_EQ_3732U(...) \, +#define Z_IS_3733_EQ_3733(...) \, +#define Z_IS_3733U_EQ_3733(...) \, +#define Z_IS_3733_EQ_3733U(...) \, +#define Z_IS_3733U_EQ_3733U(...) \, +#define Z_IS_3734_EQ_3734(...) \, +#define Z_IS_3734U_EQ_3734(...) \, +#define Z_IS_3734_EQ_3734U(...) \, +#define Z_IS_3734U_EQ_3734U(...) \, +#define Z_IS_3735_EQ_3735(...) \, +#define Z_IS_3735U_EQ_3735(...) \, +#define Z_IS_3735_EQ_3735U(...) \, +#define Z_IS_3735U_EQ_3735U(...) \, +#define Z_IS_3736_EQ_3736(...) \, +#define Z_IS_3736U_EQ_3736(...) \, +#define Z_IS_3736_EQ_3736U(...) \, +#define Z_IS_3736U_EQ_3736U(...) \, +#define Z_IS_3737_EQ_3737(...) \, +#define Z_IS_3737U_EQ_3737(...) \, +#define Z_IS_3737_EQ_3737U(...) \, +#define Z_IS_3737U_EQ_3737U(...) \, +#define Z_IS_3738_EQ_3738(...) \, +#define Z_IS_3738U_EQ_3738(...) \, +#define Z_IS_3738_EQ_3738U(...) \, +#define Z_IS_3738U_EQ_3738U(...) \, +#define Z_IS_3739_EQ_3739(...) \, +#define Z_IS_3739U_EQ_3739(...) \, +#define Z_IS_3739_EQ_3739U(...) \, +#define Z_IS_3739U_EQ_3739U(...) \, +#define Z_IS_3740_EQ_3740(...) \, +#define Z_IS_3740U_EQ_3740(...) \, +#define Z_IS_3740_EQ_3740U(...) \, +#define Z_IS_3740U_EQ_3740U(...) \, +#define Z_IS_3741_EQ_3741(...) \, +#define Z_IS_3741U_EQ_3741(...) \, +#define Z_IS_3741_EQ_3741U(...) \, +#define Z_IS_3741U_EQ_3741U(...) \, +#define Z_IS_3742_EQ_3742(...) \, +#define Z_IS_3742U_EQ_3742(...) \, +#define Z_IS_3742_EQ_3742U(...) \, +#define Z_IS_3742U_EQ_3742U(...) \, +#define Z_IS_3743_EQ_3743(...) \, +#define Z_IS_3743U_EQ_3743(...) \, +#define Z_IS_3743_EQ_3743U(...) \, +#define Z_IS_3743U_EQ_3743U(...) \, +#define Z_IS_3744_EQ_3744(...) \, +#define Z_IS_3744U_EQ_3744(...) \, +#define Z_IS_3744_EQ_3744U(...) \, +#define Z_IS_3744U_EQ_3744U(...) \, +#define Z_IS_3745_EQ_3745(...) \, +#define Z_IS_3745U_EQ_3745(...) \, +#define Z_IS_3745_EQ_3745U(...) \, +#define Z_IS_3745U_EQ_3745U(...) \, +#define Z_IS_3746_EQ_3746(...) \, +#define Z_IS_3746U_EQ_3746(...) \, +#define Z_IS_3746_EQ_3746U(...) \, +#define Z_IS_3746U_EQ_3746U(...) \, +#define Z_IS_3747_EQ_3747(...) \, +#define Z_IS_3747U_EQ_3747(...) \, +#define Z_IS_3747_EQ_3747U(...) \, +#define Z_IS_3747U_EQ_3747U(...) \, +#define Z_IS_3748_EQ_3748(...) \, +#define Z_IS_3748U_EQ_3748(...) \, +#define Z_IS_3748_EQ_3748U(...) \, +#define Z_IS_3748U_EQ_3748U(...) \, +#define Z_IS_3749_EQ_3749(...) \, +#define Z_IS_3749U_EQ_3749(...) \, +#define Z_IS_3749_EQ_3749U(...) \, +#define Z_IS_3749U_EQ_3749U(...) \, +#define Z_IS_3750_EQ_3750(...) \, +#define Z_IS_3750U_EQ_3750(...) \, +#define Z_IS_3750_EQ_3750U(...) \, +#define Z_IS_3750U_EQ_3750U(...) \, +#define Z_IS_3751_EQ_3751(...) \, +#define Z_IS_3751U_EQ_3751(...) \, +#define Z_IS_3751_EQ_3751U(...) \, +#define Z_IS_3751U_EQ_3751U(...) \, +#define Z_IS_3752_EQ_3752(...) \, +#define Z_IS_3752U_EQ_3752(...) \, +#define Z_IS_3752_EQ_3752U(...) \, +#define Z_IS_3752U_EQ_3752U(...) \, +#define Z_IS_3753_EQ_3753(...) \, +#define Z_IS_3753U_EQ_3753(...) \, +#define Z_IS_3753_EQ_3753U(...) \, +#define Z_IS_3753U_EQ_3753U(...) \, +#define Z_IS_3754_EQ_3754(...) \, +#define Z_IS_3754U_EQ_3754(...) \, +#define Z_IS_3754_EQ_3754U(...) \, +#define Z_IS_3754U_EQ_3754U(...) \, +#define Z_IS_3755_EQ_3755(...) \, +#define Z_IS_3755U_EQ_3755(...) \, +#define Z_IS_3755_EQ_3755U(...) \, +#define Z_IS_3755U_EQ_3755U(...) \, +#define Z_IS_3756_EQ_3756(...) \, +#define Z_IS_3756U_EQ_3756(...) \, +#define Z_IS_3756_EQ_3756U(...) \, +#define Z_IS_3756U_EQ_3756U(...) \, +#define Z_IS_3757_EQ_3757(...) \, +#define Z_IS_3757U_EQ_3757(...) \, +#define Z_IS_3757_EQ_3757U(...) \, +#define Z_IS_3757U_EQ_3757U(...) \, +#define Z_IS_3758_EQ_3758(...) \, +#define Z_IS_3758U_EQ_3758(...) \, +#define Z_IS_3758_EQ_3758U(...) \, +#define Z_IS_3758U_EQ_3758U(...) \, +#define Z_IS_3759_EQ_3759(...) \, +#define Z_IS_3759U_EQ_3759(...) \, +#define Z_IS_3759_EQ_3759U(...) \, +#define Z_IS_3759U_EQ_3759U(...) \, +#define Z_IS_3760_EQ_3760(...) \, +#define Z_IS_3760U_EQ_3760(...) \, +#define Z_IS_3760_EQ_3760U(...) \, +#define Z_IS_3760U_EQ_3760U(...) \, +#define Z_IS_3761_EQ_3761(...) \, +#define Z_IS_3761U_EQ_3761(...) \, +#define Z_IS_3761_EQ_3761U(...) \, +#define Z_IS_3761U_EQ_3761U(...) \, +#define Z_IS_3762_EQ_3762(...) \, +#define Z_IS_3762U_EQ_3762(...) \, +#define Z_IS_3762_EQ_3762U(...) \, +#define Z_IS_3762U_EQ_3762U(...) \, +#define Z_IS_3763_EQ_3763(...) \, +#define Z_IS_3763U_EQ_3763(...) \, +#define Z_IS_3763_EQ_3763U(...) \, +#define Z_IS_3763U_EQ_3763U(...) \, +#define Z_IS_3764_EQ_3764(...) \, +#define Z_IS_3764U_EQ_3764(...) \, +#define Z_IS_3764_EQ_3764U(...) \, +#define Z_IS_3764U_EQ_3764U(...) \, +#define Z_IS_3765_EQ_3765(...) \, +#define Z_IS_3765U_EQ_3765(...) \, +#define Z_IS_3765_EQ_3765U(...) \, +#define Z_IS_3765U_EQ_3765U(...) \, +#define Z_IS_3766_EQ_3766(...) \, +#define Z_IS_3766U_EQ_3766(...) \, +#define Z_IS_3766_EQ_3766U(...) \, +#define Z_IS_3766U_EQ_3766U(...) \, +#define Z_IS_3767_EQ_3767(...) \, +#define Z_IS_3767U_EQ_3767(...) \, +#define Z_IS_3767_EQ_3767U(...) \, +#define Z_IS_3767U_EQ_3767U(...) \, +#define Z_IS_3768_EQ_3768(...) \, +#define Z_IS_3768U_EQ_3768(...) \, +#define Z_IS_3768_EQ_3768U(...) \, +#define Z_IS_3768U_EQ_3768U(...) \, +#define Z_IS_3769_EQ_3769(...) \, +#define Z_IS_3769U_EQ_3769(...) \, +#define Z_IS_3769_EQ_3769U(...) \, +#define Z_IS_3769U_EQ_3769U(...) \, +#define Z_IS_3770_EQ_3770(...) \, +#define Z_IS_3770U_EQ_3770(...) \, +#define Z_IS_3770_EQ_3770U(...) \, +#define Z_IS_3770U_EQ_3770U(...) \, +#define Z_IS_3771_EQ_3771(...) \, +#define Z_IS_3771U_EQ_3771(...) \, +#define Z_IS_3771_EQ_3771U(...) \, +#define Z_IS_3771U_EQ_3771U(...) \, +#define Z_IS_3772_EQ_3772(...) \, +#define Z_IS_3772U_EQ_3772(...) \, +#define Z_IS_3772_EQ_3772U(...) \, +#define Z_IS_3772U_EQ_3772U(...) \, +#define Z_IS_3773_EQ_3773(...) \, +#define Z_IS_3773U_EQ_3773(...) \, +#define Z_IS_3773_EQ_3773U(...) \, +#define Z_IS_3773U_EQ_3773U(...) \, +#define Z_IS_3774_EQ_3774(...) \, +#define Z_IS_3774U_EQ_3774(...) \, +#define Z_IS_3774_EQ_3774U(...) \, +#define Z_IS_3774U_EQ_3774U(...) \, +#define Z_IS_3775_EQ_3775(...) \, +#define Z_IS_3775U_EQ_3775(...) \, +#define Z_IS_3775_EQ_3775U(...) \, +#define Z_IS_3775U_EQ_3775U(...) \, +#define Z_IS_3776_EQ_3776(...) \, +#define Z_IS_3776U_EQ_3776(...) \, +#define Z_IS_3776_EQ_3776U(...) \, +#define Z_IS_3776U_EQ_3776U(...) \, +#define Z_IS_3777_EQ_3777(...) \, +#define Z_IS_3777U_EQ_3777(...) \, +#define Z_IS_3777_EQ_3777U(...) \, +#define Z_IS_3777U_EQ_3777U(...) \, +#define Z_IS_3778_EQ_3778(...) \, +#define Z_IS_3778U_EQ_3778(...) \, +#define Z_IS_3778_EQ_3778U(...) \, +#define Z_IS_3778U_EQ_3778U(...) \, +#define Z_IS_3779_EQ_3779(...) \, +#define Z_IS_3779U_EQ_3779(...) \, +#define Z_IS_3779_EQ_3779U(...) \, +#define Z_IS_3779U_EQ_3779U(...) \, +#define Z_IS_3780_EQ_3780(...) \, +#define Z_IS_3780U_EQ_3780(...) \, +#define Z_IS_3780_EQ_3780U(...) \, +#define Z_IS_3780U_EQ_3780U(...) \, +#define Z_IS_3781_EQ_3781(...) \, +#define Z_IS_3781U_EQ_3781(...) \, +#define Z_IS_3781_EQ_3781U(...) \, +#define Z_IS_3781U_EQ_3781U(...) \, +#define Z_IS_3782_EQ_3782(...) \, +#define Z_IS_3782U_EQ_3782(...) \, +#define Z_IS_3782_EQ_3782U(...) \, +#define Z_IS_3782U_EQ_3782U(...) \, +#define Z_IS_3783_EQ_3783(...) \, +#define Z_IS_3783U_EQ_3783(...) \, +#define Z_IS_3783_EQ_3783U(...) \, +#define Z_IS_3783U_EQ_3783U(...) \, +#define Z_IS_3784_EQ_3784(...) \, +#define Z_IS_3784U_EQ_3784(...) \, +#define Z_IS_3784_EQ_3784U(...) \, +#define Z_IS_3784U_EQ_3784U(...) \, +#define Z_IS_3785_EQ_3785(...) \, +#define Z_IS_3785U_EQ_3785(...) \, +#define Z_IS_3785_EQ_3785U(...) \, +#define Z_IS_3785U_EQ_3785U(...) \, +#define Z_IS_3786_EQ_3786(...) \, +#define Z_IS_3786U_EQ_3786(...) \, +#define Z_IS_3786_EQ_3786U(...) \, +#define Z_IS_3786U_EQ_3786U(...) \, +#define Z_IS_3787_EQ_3787(...) \, +#define Z_IS_3787U_EQ_3787(...) \, +#define Z_IS_3787_EQ_3787U(...) \, +#define Z_IS_3787U_EQ_3787U(...) \, +#define Z_IS_3788_EQ_3788(...) \, +#define Z_IS_3788U_EQ_3788(...) \, +#define Z_IS_3788_EQ_3788U(...) \, +#define Z_IS_3788U_EQ_3788U(...) \, +#define Z_IS_3789_EQ_3789(...) \, +#define Z_IS_3789U_EQ_3789(...) \, +#define Z_IS_3789_EQ_3789U(...) \, +#define Z_IS_3789U_EQ_3789U(...) \, +#define Z_IS_3790_EQ_3790(...) \, +#define Z_IS_3790U_EQ_3790(...) \, +#define Z_IS_3790_EQ_3790U(...) \, +#define Z_IS_3790U_EQ_3790U(...) \, +#define Z_IS_3791_EQ_3791(...) \, +#define Z_IS_3791U_EQ_3791(...) \, +#define Z_IS_3791_EQ_3791U(...) \, +#define Z_IS_3791U_EQ_3791U(...) \, +#define Z_IS_3792_EQ_3792(...) \, +#define Z_IS_3792U_EQ_3792(...) \, +#define Z_IS_3792_EQ_3792U(...) \, +#define Z_IS_3792U_EQ_3792U(...) \, +#define Z_IS_3793_EQ_3793(...) \, +#define Z_IS_3793U_EQ_3793(...) \, +#define Z_IS_3793_EQ_3793U(...) \, +#define Z_IS_3793U_EQ_3793U(...) \, +#define Z_IS_3794_EQ_3794(...) \, +#define Z_IS_3794U_EQ_3794(...) \, +#define Z_IS_3794_EQ_3794U(...) \, +#define Z_IS_3794U_EQ_3794U(...) \, +#define Z_IS_3795_EQ_3795(...) \, +#define Z_IS_3795U_EQ_3795(...) \, +#define Z_IS_3795_EQ_3795U(...) \, +#define Z_IS_3795U_EQ_3795U(...) \, +#define Z_IS_3796_EQ_3796(...) \, +#define Z_IS_3796U_EQ_3796(...) \, +#define Z_IS_3796_EQ_3796U(...) \, +#define Z_IS_3796U_EQ_3796U(...) \, +#define Z_IS_3797_EQ_3797(...) \, +#define Z_IS_3797U_EQ_3797(...) \, +#define Z_IS_3797_EQ_3797U(...) \, +#define Z_IS_3797U_EQ_3797U(...) \, +#define Z_IS_3798_EQ_3798(...) \, +#define Z_IS_3798U_EQ_3798(...) \, +#define Z_IS_3798_EQ_3798U(...) \, +#define Z_IS_3798U_EQ_3798U(...) \, +#define Z_IS_3799_EQ_3799(...) \, +#define Z_IS_3799U_EQ_3799(...) \, +#define Z_IS_3799_EQ_3799U(...) \, +#define Z_IS_3799U_EQ_3799U(...) \, +#define Z_IS_3800_EQ_3800(...) \, +#define Z_IS_3800U_EQ_3800(...) \, +#define Z_IS_3800_EQ_3800U(...) \, +#define Z_IS_3800U_EQ_3800U(...) \, +#define Z_IS_3801_EQ_3801(...) \, +#define Z_IS_3801U_EQ_3801(...) \, +#define Z_IS_3801_EQ_3801U(...) \, +#define Z_IS_3801U_EQ_3801U(...) \, +#define Z_IS_3802_EQ_3802(...) \, +#define Z_IS_3802U_EQ_3802(...) \, +#define Z_IS_3802_EQ_3802U(...) \, +#define Z_IS_3802U_EQ_3802U(...) \, +#define Z_IS_3803_EQ_3803(...) \, +#define Z_IS_3803U_EQ_3803(...) \, +#define Z_IS_3803_EQ_3803U(...) \, +#define Z_IS_3803U_EQ_3803U(...) \, +#define Z_IS_3804_EQ_3804(...) \, +#define Z_IS_3804U_EQ_3804(...) \, +#define Z_IS_3804_EQ_3804U(...) \, +#define Z_IS_3804U_EQ_3804U(...) \, +#define Z_IS_3805_EQ_3805(...) \, +#define Z_IS_3805U_EQ_3805(...) \, +#define Z_IS_3805_EQ_3805U(...) \, +#define Z_IS_3805U_EQ_3805U(...) \, +#define Z_IS_3806_EQ_3806(...) \, +#define Z_IS_3806U_EQ_3806(...) \, +#define Z_IS_3806_EQ_3806U(...) \, +#define Z_IS_3806U_EQ_3806U(...) \, +#define Z_IS_3807_EQ_3807(...) \, +#define Z_IS_3807U_EQ_3807(...) \, +#define Z_IS_3807_EQ_3807U(...) \, +#define Z_IS_3807U_EQ_3807U(...) \, +#define Z_IS_3808_EQ_3808(...) \, +#define Z_IS_3808U_EQ_3808(...) \, +#define Z_IS_3808_EQ_3808U(...) \, +#define Z_IS_3808U_EQ_3808U(...) \, +#define Z_IS_3809_EQ_3809(...) \, +#define Z_IS_3809U_EQ_3809(...) \, +#define Z_IS_3809_EQ_3809U(...) \, +#define Z_IS_3809U_EQ_3809U(...) \, +#define Z_IS_3810_EQ_3810(...) \, +#define Z_IS_3810U_EQ_3810(...) \, +#define Z_IS_3810_EQ_3810U(...) \, +#define Z_IS_3810U_EQ_3810U(...) \, +#define Z_IS_3811_EQ_3811(...) \, +#define Z_IS_3811U_EQ_3811(...) \, +#define Z_IS_3811_EQ_3811U(...) \, +#define Z_IS_3811U_EQ_3811U(...) \, +#define Z_IS_3812_EQ_3812(...) \, +#define Z_IS_3812U_EQ_3812(...) \, +#define Z_IS_3812_EQ_3812U(...) \, +#define Z_IS_3812U_EQ_3812U(...) \, +#define Z_IS_3813_EQ_3813(...) \, +#define Z_IS_3813U_EQ_3813(...) \, +#define Z_IS_3813_EQ_3813U(...) \, +#define Z_IS_3813U_EQ_3813U(...) \, +#define Z_IS_3814_EQ_3814(...) \, +#define Z_IS_3814U_EQ_3814(...) \, +#define Z_IS_3814_EQ_3814U(...) \, +#define Z_IS_3814U_EQ_3814U(...) \, +#define Z_IS_3815_EQ_3815(...) \, +#define Z_IS_3815U_EQ_3815(...) \, +#define Z_IS_3815_EQ_3815U(...) \, +#define Z_IS_3815U_EQ_3815U(...) \, +#define Z_IS_3816_EQ_3816(...) \, +#define Z_IS_3816U_EQ_3816(...) \, +#define Z_IS_3816_EQ_3816U(...) \, +#define Z_IS_3816U_EQ_3816U(...) \, +#define Z_IS_3817_EQ_3817(...) \, +#define Z_IS_3817U_EQ_3817(...) \, +#define Z_IS_3817_EQ_3817U(...) \, +#define Z_IS_3817U_EQ_3817U(...) \, +#define Z_IS_3818_EQ_3818(...) \, +#define Z_IS_3818U_EQ_3818(...) \, +#define Z_IS_3818_EQ_3818U(...) \, +#define Z_IS_3818U_EQ_3818U(...) \, +#define Z_IS_3819_EQ_3819(...) \, +#define Z_IS_3819U_EQ_3819(...) \, +#define Z_IS_3819_EQ_3819U(...) \, +#define Z_IS_3819U_EQ_3819U(...) \, +#define Z_IS_3820_EQ_3820(...) \, +#define Z_IS_3820U_EQ_3820(...) \, +#define Z_IS_3820_EQ_3820U(...) \, +#define Z_IS_3820U_EQ_3820U(...) \, +#define Z_IS_3821_EQ_3821(...) \, +#define Z_IS_3821U_EQ_3821(...) \, +#define Z_IS_3821_EQ_3821U(...) \, +#define Z_IS_3821U_EQ_3821U(...) \, +#define Z_IS_3822_EQ_3822(...) \, +#define Z_IS_3822U_EQ_3822(...) \, +#define Z_IS_3822_EQ_3822U(...) \, +#define Z_IS_3822U_EQ_3822U(...) \, +#define Z_IS_3823_EQ_3823(...) \, +#define Z_IS_3823U_EQ_3823(...) \, +#define Z_IS_3823_EQ_3823U(...) \, +#define Z_IS_3823U_EQ_3823U(...) \, +#define Z_IS_3824_EQ_3824(...) \, +#define Z_IS_3824U_EQ_3824(...) \, +#define Z_IS_3824_EQ_3824U(...) \, +#define Z_IS_3824U_EQ_3824U(...) \, +#define Z_IS_3825_EQ_3825(...) \, +#define Z_IS_3825U_EQ_3825(...) \, +#define Z_IS_3825_EQ_3825U(...) \, +#define Z_IS_3825U_EQ_3825U(...) \, +#define Z_IS_3826_EQ_3826(...) \, +#define Z_IS_3826U_EQ_3826(...) \, +#define Z_IS_3826_EQ_3826U(...) \, +#define Z_IS_3826U_EQ_3826U(...) \, +#define Z_IS_3827_EQ_3827(...) \, +#define Z_IS_3827U_EQ_3827(...) \, +#define Z_IS_3827_EQ_3827U(...) \, +#define Z_IS_3827U_EQ_3827U(...) \, +#define Z_IS_3828_EQ_3828(...) \, +#define Z_IS_3828U_EQ_3828(...) \, +#define Z_IS_3828_EQ_3828U(...) \, +#define Z_IS_3828U_EQ_3828U(...) \, +#define Z_IS_3829_EQ_3829(...) \, +#define Z_IS_3829U_EQ_3829(...) \, +#define Z_IS_3829_EQ_3829U(...) \, +#define Z_IS_3829U_EQ_3829U(...) \, +#define Z_IS_3830_EQ_3830(...) \, +#define Z_IS_3830U_EQ_3830(...) \, +#define Z_IS_3830_EQ_3830U(...) \, +#define Z_IS_3830U_EQ_3830U(...) \, +#define Z_IS_3831_EQ_3831(...) \, +#define Z_IS_3831U_EQ_3831(...) \, +#define Z_IS_3831_EQ_3831U(...) \, +#define Z_IS_3831U_EQ_3831U(...) \, +#define Z_IS_3832_EQ_3832(...) \, +#define Z_IS_3832U_EQ_3832(...) \, +#define Z_IS_3832_EQ_3832U(...) \, +#define Z_IS_3832U_EQ_3832U(...) \, +#define Z_IS_3833_EQ_3833(...) \, +#define Z_IS_3833U_EQ_3833(...) \, +#define Z_IS_3833_EQ_3833U(...) \, +#define Z_IS_3833U_EQ_3833U(...) \, +#define Z_IS_3834_EQ_3834(...) \, +#define Z_IS_3834U_EQ_3834(...) \, +#define Z_IS_3834_EQ_3834U(...) \, +#define Z_IS_3834U_EQ_3834U(...) \, +#define Z_IS_3835_EQ_3835(...) \, +#define Z_IS_3835U_EQ_3835(...) \, +#define Z_IS_3835_EQ_3835U(...) \, +#define Z_IS_3835U_EQ_3835U(...) \, +#define Z_IS_3836_EQ_3836(...) \, +#define Z_IS_3836U_EQ_3836(...) \, +#define Z_IS_3836_EQ_3836U(...) \, +#define Z_IS_3836U_EQ_3836U(...) \, +#define Z_IS_3837_EQ_3837(...) \, +#define Z_IS_3837U_EQ_3837(...) \, +#define Z_IS_3837_EQ_3837U(...) \, +#define Z_IS_3837U_EQ_3837U(...) \, +#define Z_IS_3838_EQ_3838(...) \, +#define Z_IS_3838U_EQ_3838(...) \, +#define Z_IS_3838_EQ_3838U(...) \, +#define Z_IS_3838U_EQ_3838U(...) \, +#define Z_IS_3839_EQ_3839(...) \, +#define Z_IS_3839U_EQ_3839(...) \, +#define Z_IS_3839_EQ_3839U(...) \, +#define Z_IS_3839U_EQ_3839U(...) \, +#define Z_IS_3840_EQ_3840(...) \, +#define Z_IS_3840U_EQ_3840(...) \, +#define Z_IS_3840_EQ_3840U(...) \, +#define Z_IS_3840U_EQ_3840U(...) \, +#define Z_IS_3841_EQ_3841(...) \, +#define Z_IS_3841U_EQ_3841(...) \, +#define Z_IS_3841_EQ_3841U(...) \, +#define Z_IS_3841U_EQ_3841U(...) \, +#define Z_IS_3842_EQ_3842(...) \, +#define Z_IS_3842U_EQ_3842(...) \, +#define Z_IS_3842_EQ_3842U(...) \, +#define Z_IS_3842U_EQ_3842U(...) \, +#define Z_IS_3843_EQ_3843(...) \, +#define Z_IS_3843U_EQ_3843(...) \, +#define Z_IS_3843_EQ_3843U(...) \, +#define Z_IS_3843U_EQ_3843U(...) \, +#define Z_IS_3844_EQ_3844(...) \, +#define Z_IS_3844U_EQ_3844(...) \, +#define Z_IS_3844_EQ_3844U(...) \, +#define Z_IS_3844U_EQ_3844U(...) \, +#define Z_IS_3845_EQ_3845(...) \, +#define Z_IS_3845U_EQ_3845(...) \, +#define Z_IS_3845_EQ_3845U(...) \, +#define Z_IS_3845U_EQ_3845U(...) \, +#define Z_IS_3846_EQ_3846(...) \, +#define Z_IS_3846U_EQ_3846(...) \, +#define Z_IS_3846_EQ_3846U(...) \, +#define Z_IS_3846U_EQ_3846U(...) \, +#define Z_IS_3847_EQ_3847(...) \, +#define Z_IS_3847U_EQ_3847(...) \, +#define Z_IS_3847_EQ_3847U(...) \, +#define Z_IS_3847U_EQ_3847U(...) \, +#define Z_IS_3848_EQ_3848(...) \, +#define Z_IS_3848U_EQ_3848(...) \, +#define Z_IS_3848_EQ_3848U(...) \, +#define Z_IS_3848U_EQ_3848U(...) \, +#define Z_IS_3849_EQ_3849(...) \, +#define Z_IS_3849U_EQ_3849(...) \, +#define Z_IS_3849_EQ_3849U(...) \, +#define Z_IS_3849U_EQ_3849U(...) \, +#define Z_IS_3850_EQ_3850(...) \, +#define Z_IS_3850U_EQ_3850(...) \, +#define Z_IS_3850_EQ_3850U(...) \, +#define Z_IS_3850U_EQ_3850U(...) \, +#define Z_IS_3851_EQ_3851(...) \, +#define Z_IS_3851U_EQ_3851(...) \, +#define Z_IS_3851_EQ_3851U(...) \, +#define Z_IS_3851U_EQ_3851U(...) \, +#define Z_IS_3852_EQ_3852(...) \, +#define Z_IS_3852U_EQ_3852(...) \, +#define Z_IS_3852_EQ_3852U(...) \, +#define Z_IS_3852U_EQ_3852U(...) \, +#define Z_IS_3853_EQ_3853(...) \, +#define Z_IS_3853U_EQ_3853(...) \, +#define Z_IS_3853_EQ_3853U(...) \, +#define Z_IS_3853U_EQ_3853U(...) \, +#define Z_IS_3854_EQ_3854(...) \, +#define Z_IS_3854U_EQ_3854(...) \, +#define Z_IS_3854_EQ_3854U(...) \, +#define Z_IS_3854U_EQ_3854U(...) \, +#define Z_IS_3855_EQ_3855(...) \, +#define Z_IS_3855U_EQ_3855(...) \, +#define Z_IS_3855_EQ_3855U(...) \, +#define Z_IS_3855U_EQ_3855U(...) \, +#define Z_IS_3856_EQ_3856(...) \, +#define Z_IS_3856U_EQ_3856(...) \, +#define Z_IS_3856_EQ_3856U(...) \, +#define Z_IS_3856U_EQ_3856U(...) \, +#define Z_IS_3857_EQ_3857(...) \, +#define Z_IS_3857U_EQ_3857(...) \, +#define Z_IS_3857_EQ_3857U(...) \, +#define Z_IS_3857U_EQ_3857U(...) \, +#define Z_IS_3858_EQ_3858(...) \, +#define Z_IS_3858U_EQ_3858(...) \, +#define Z_IS_3858_EQ_3858U(...) \, +#define Z_IS_3858U_EQ_3858U(...) \, +#define Z_IS_3859_EQ_3859(...) \, +#define Z_IS_3859U_EQ_3859(...) \, +#define Z_IS_3859_EQ_3859U(...) \, +#define Z_IS_3859U_EQ_3859U(...) \, +#define Z_IS_3860_EQ_3860(...) \, +#define Z_IS_3860U_EQ_3860(...) \, +#define Z_IS_3860_EQ_3860U(...) \, +#define Z_IS_3860U_EQ_3860U(...) \, +#define Z_IS_3861_EQ_3861(...) \, +#define Z_IS_3861U_EQ_3861(...) \, +#define Z_IS_3861_EQ_3861U(...) \, +#define Z_IS_3861U_EQ_3861U(...) \, +#define Z_IS_3862_EQ_3862(...) \, +#define Z_IS_3862U_EQ_3862(...) \, +#define Z_IS_3862_EQ_3862U(...) \, +#define Z_IS_3862U_EQ_3862U(...) \, +#define Z_IS_3863_EQ_3863(...) \, +#define Z_IS_3863U_EQ_3863(...) \, +#define Z_IS_3863_EQ_3863U(...) \, +#define Z_IS_3863U_EQ_3863U(...) \, +#define Z_IS_3864_EQ_3864(...) \, +#define Z_IS_3864U_EQ_3864(...) \, +#define Z_IS_3864_EQ_3864U(...) \, +#define Z_IS_3864U_EQ_3864U(...) \, +#define Z_IS_3865_EQ_3865(...) \, +#define Z_IS_3865U_EQ_3865(...) \, +#define Z_IS_3865_EQ_3865U(...) \, +#define Z_IS_3865U_EQ_3865U(...) \, +#define Z_IS_3866_EQ_3866(...) \, +#define Z_IS_3866U_EQ_3866(...) \, +#define Z_IS_3866_EQ_3866U(...) \, +#define Z_IS_3866U_EQ_3866U(...) \, +#define Z_IS_3867_EQ_3867(...) \, +#define Z_IS_3867U_EQ_3867(...) \, +#define Z_IS_3867_EQ_3867U(...) \, +#define Z_IS_3867U_EQ_3867U(...) \, +#define Z_IS_3868_EQ_3868(...) \, +#define Z_IS_3868U_EQ_3868(...) \, +#define Z_IS_3868_EQ_3868U(...) \, +#define Z_IS_3868U_EQ_3868U(...) \, +#define Z_IS_3869_EQ_3869(...) \, +#define Z_IS_3869U_EQ_3869(...) \, +#define Z_IS_3869_EQ_3869U(...) \, +#define Z_IS_3869U_EQ_3869U(...) \, +#define Z_IS_3870_EQ_3870(...) \, +#define Z_IS_3870U_EQ_3870(...) \, +#define Z_IS_3870_EQ_3870U(...) \, +#define Z_IS_3870U_EQ_3870U(...) \, +#define Z_IS_3871_EQ_3871(...) \, +#define Z_IS_3871U_EQ_3871(...) \, +#define Z_IS_3871_EQ_3871U(...) \, +#define Z_IS_3871U_EQ_3871U(...) \, +#define Z_IS_3872_EQ_3872(...) \, +#define Z_IS_3872U_EQ_3872(...) \, +#define Z_IS_3872_EQ_3872U(...) \, +#define Z_IS_3872U_EQ_3872U(...) \, +#define Z_IS_3873_EQ_3873(...) \, +#define Z_IS_3873U_EQ_3873(...) \, +#define Z_IS_3873_EQ_3873U(...) \, +#define Z_IS_3873U_EQ_3873U(...) \, +#define Z_IS_3874_EQ_3874(...) \, +#define Z_IS_3874U_EQ_3874(...) \, +#define Z_IS_3874_EQ_3874U(...) \, +#define Z_IS_3874U_EQ_3874U(...) \, +#define Z_IS_3875_EQ_3875(...) \, +#define Z_IS_3875U_EQ_3875(...) \, +#define Z_IS_3875_EQ_3875U(...) \, +#define Z_IS_3875U_EQ_3875U(...) \, +#define Z_IS_3876_EQ_3876(...) \, +#define Z_IS_3876U_EQ_3876(...) \, +#define Z_IS_3876_EQ_3876U(...) \, +#define Z_IS_3876U_EQ_3876U(...) \, +#define Z_IS_3877_EQ_3877(...) \, +#define Z_IS_3877U_EQ_3877(...) \, +#define Z_IS_3877_EQ_3877U(...) \, +#define Z_IS_3877U_EQ_3877U(...) \, +#define Z_IS_3878_EQ_3878(...) \, +#define Z_IS_3878U_EQ_3878(...) \, +#define Z_IS_3878_EQ_3878U(...) \, +#define Z_IS_3878U_EQ_3878U(...) \, +#define Z_IS_3879_EQ_3879(...) \, +#define Z_IS_3879U_EQ_3879(...) \, +#define Z_IS_3879_EQ_3879U(...) \, +#define Z_IS_3879U_EQ_3879U(...) \, +#define Z_IS_3880_EQ_3880(...) \, +#define Z_IS_3880U_EQ_3880(...) \, +#define Z_IS_3880_EQ_3880U(...) \, +#define Z_IS_3880U_EQ_3880U(...) \, +#define Z_IS_3881_EQ_3881(...) \, +#define Z_IS_3881U_EQ_3881(...) \, +#define Z_IS_3881_EQ_3881U(...) \, +#define Z_IS_3881U_EQ_3881U(...) \, +#define Z_IS_3882_EQ_3882(...) \, +#define Z_IS_3882U_EQ_3882(...) \, +#define Z_IS_3882_EQ_3882U(...) \, +#define Z_IS_3882U_EQ_3882U(...) \, +#define Z_IS_3883_EQ_3883(...) \, +#define Z_IS_3883U_EQ_3883(...) \, +#define Z_IS_3883_EQ_3883U(...) \, +#define Z_IS_3883U_EQ_3883U(...) \, +#define Z_IS_3884_EQ_3884(...) \, +#define Z_IS_3884U_EQ_3884(...) \, +#define Z_IS_3884_EQ_3884U(...) \, +#define Z_IS_3884U_EQ_3884U(...) \, +#define Z_IS_3885_EQ_3885(...) \, +#define Z_IS_3885U_EQ_3885(...) \, +#define Z_IS_3885_EQ_3885U(...) \, +#define Z_IS_3885U_EQ_3885U(...) \, +#define Z_IS_3886_EQ_3886(...) \, +#define Z_IS_3886U_EQ_3886(...) \, +#define Z_IS_3886_EQ_3886U(...) \, +#define Z_IS_3886U_EQ_3886U(...) \, +#define Z_IS_3887_EQ_3887(...) \, +#define Z_IS_3887U_EQ_3887(...) \, +#define Z_IS_3887_EQ_3887U(...) \, +#define Z_IS_3887U_EQ_3887U(...) \, +#define Z_IS_3888_EQ_3888(...) \, +#define Z_IS_3888U_EQ_3888(...) \, +#define Z_IS_3888_EQ_3888U(...) \, +#define Z_IS_3888U_EQ_3888U(...) \, +#define Z_IS_3889_EQ_3889(...) \, +#define Z_IS_3889U_EQ_3889(...) \, +#define Z_IS_3889_EQ_3889U(...) \, +#define Z_IS_3889U_EQ_3889U(...) \, +#define Z_IS_3890_EQ_3890(...) \, +#define Z_IS_3890U_EQ_3890(...) \, +#define Z_IS_3890_EQ_3890U(...) \, +#define Z_IS_3890U_EQ_3890U(...) \, +#define Z_IS_3891_EQ_3891(...) \, +#define Z_IS_3891U_EQ_3891(...) \, +#define Z_IS_3891_EQ_3891U(...) \, +#define Z_IS_3891U_EQ_3891U(...) \, +#define Z_IS_3892_EQ_3892(...) \, +#define Z_IS_3892U_EQ_3892(...) \, +#define Z_IS_3892_EQ_3892U(...) \, +#define Z_IS_3892U_EQ_3892U(...) \, +#define Z_IS_3893_EQ_3893(...) \, +#define Z_IS_3893U_EQ_3893(...) \, +#define Z_IS_3893_EQ_3893U(...) \, +#define Z_IS_3893U_EQ_3893U(...) \, +#define Z_IS_3894_EQ_3894(...) \, +#define Z_IS_3894U_EQ_3894(...) \, +#define Z_IS_3894_EQ_3894U(...) \, +#define Z_IS_3894U_EQ_3894U(...) \, +#define Z_IS_3895_EQ_3895(...) \, +#define Z_IS_3895U_EQ_3895(...) \, +#define Z_IS_3895_EQ_3895U(...) \, +#define Z_IS_3895U_EQ_3895U(...) \, +#define Z_IS_3896_EQ_3896(...) \, +#define Z_IS_3896U_EQ_3896(...) \, +#define Z_IS_3896_EQ_3896U(...) \, +#define Z_IS_3896U_EQ_3896U(...) \, +#define Z_IS_3897_EQ_3897(...) \, +#define Z_IS_3897U_EQ_3897(...) \, +#define Z_IS_3897_EQ_3897U(...) \, +#define Z_IS_3897U_EQ_3897U(...) \, +#define Z_IS_3898_EQ_3898(...) \, +#define Z_IS_3898U_EQ_3898(...) \, +#define Z_IS_3898_EQ_3898U(...) \, +#define Z_IS_3898U_EQ_3898U(...) \, +#define Z_IS_3899_EQ_3899(...) \, +#define Z_IS_3899U_EQ_3899(...) \, +#define Z_IS_3899_EQ_3899U(...) \, +#define Z_IS_3899U_EQ_3899U(...) \, +#define Z_IS_3900_EQ_3900(...) \, +#define Z_IS_3900U_EQ_3900(...) \, +#define Z_IS_3900_EQ_3900U(...) \, +#define Z_IS_3900U_EQ_3900U(...) \, +#define Z_IS_3901_EQ_3901(...) \, +#define Z_IS_3901U_EQ_3901(...) \, +#define Z_IS_3901_EQ_3901U(...) \, +#define Z_IS_3901U_EQ_3901U(...) \, +#define Z_IS_3902_EQ_3902(...) \, +#define Z_IS_3902U_EQ_3902(...) \, +#define Z_IS_3902_EQ_3902U(...) \, +#define Z_IS_3902U_EQ_3902U(...) \, +#define Z_IS_3903_EQ_3903(...) \, +#define Z_IS_3903U_EQ_3903(...) \, +#define Z_IS_3903_EQ_3903U(...) \, +#define Z_IS_3903U_EQ_3903U(...) \, +#define Z_IS_3904_EQ_3904(...) \, +#define Z_IS_3904U_EQ_3904(...) \, +#define Z_IS_3904_EQ_3904U(...) \, +#define Z_IS_3904U_EQ_3904U(...) \, +#define Z_IS_3905_EQ_3905(...) \, +#define Z_IS_3905U_EQ_3905(...) \, +#define Z_IS_3905_EQ_3905U(...) \, +#define Z_IS_3905U_EQ_3905U(...) \, +#define Z_IS_3906_EQ_3906(...) \, +#define Z_IS_3906U_EQ_3906(...) \, +#define Z_IS_3906_EQ_3906U(...) \, +#define Z_IS_3906U_EQ_3906U(...) \, +#define Z_IS_3907_EQ_3907(...) \, +#define Z_IS_3907U_EQ_3907(...) \, +#define Z_IS_3907_EQ_3907U(...) \, +#define Z_IS_3907U_EQ_3907U(...) \, +#define Z_IS_3908_EQ_3908(...) \, +#define Z_IS_3908U_EQ_3908(...) \, +#define Z_IS_3908_EQ_3908U(...) \, +#define Z_IS_3908U_EQ_3908U(...) \, +#define Z_IS_3909_EQ_3909(...) \, +#define Z_IS_3909U_EQ_3909(...) \, +#define Z_IS_3909_EQ_3909U(...) \, +#define Z_IS_3909U_EQ_3909U(...) \, +#define Z_IS_3910_EQ_3910(...) \, +#define Z_IS_3910U_EQ_3910(...) \, +#define Z_IS_3910_EQ_3910U(...) \, +#define Z_IS_3910U_EQ_3910U(...) \, +#define Z_IS_3911_EQ_3911(...) \, +#define Z_IS_3911U_EQ_3911(...) \, +#define Z_IS_3911_EQ_3911U(...) \, +#define Z_IS_3911U_EQ_3911U(...) \, +#define Z_IS_3912_EQ_3912(...) \, +#define Z_IS_3912U_EQ_3912(...) \, +#define Z_IS_3912_EQ_3912U(...) \, +#define Z_IS_3912U_EQ_3912U(...) \, +#define Z_IS_3913_EQ_3913(...) \, +#define Z_IS_3913U_EQ_3913(...) \, +#define Z_IS_3913_EQ_3913U(...) \, +#define Z_IS_3913U_EQ_3913U(...) \, +#define Z_IS_3914_EQ_3914(...) \, +#define Z_IS_3914U_EQ_3914(...) \, +#define Z_IS_3914_EQ_3914U(...) \, +#define Z_IS_3914U_EQ_3914U(...) \, +#define Z_IS_3915_EQ_3915(...) \, +#define Z_IS_3915U_EQ_3915(...) \, +#define Z_IS_3915_EQ_3915U(...) \, +#define Z_IS_3915U_EQ_3915U(...) \, +#define Z_IS_3916_EQ_3916(...) \, +#define Z_IS_3916U_EQ_3916(...) \, +#define Z_IS_3916_EQ_3916U(...) \, +#define Z_IS_3916U_EQ_3916U(...) \, +#define Z_IS_3917_EQ_3917(...) \, +#define Z_IS_3917U_EQ_3917(...) \, +#define Z_IS_3917_EQ_3917U(...) \, +#define Z_IS_3917U_EQ_3917U(...) \, +#define Z_IS_3918_EQ_3918(...) \, +#define Z_IS_3918U_EQ_3918(...) \, +#define Z_IS_3918_EQ_3918U(...) \, +#define Z_IS_3918U_EQ_3918U(...) \, +#define Z_IS_3919_EQ_3919(...) \, +#define Z_IS_3919U_EQ_3919(...) \, +#define Z_IS_3919_EQ_3919U(...) \, +#define Z_IS_3919U_EQ_3919U(...) \, +#define Z_IS_3920_EQ_3920(...) \, +#define Z_IS_3920U_EQ_3920(...) \, +#define Z_IS_3920_EQ_3920U(...) \, +#define Z_IS_3920U_EQ_3920U(...) \, +#define Z_IS_3921_EQ_3921(...) \, +#define Z_IS_3921U_EQ_3921(...) \, +#define Z_IS_3921_EQ_3921U(...) \, +#define Z_IS_3921U_EQ_3921U(...) \, +#define Z_IS_3922_EQ_3922(...) \, +#define Z_IS_3922U_EQ_3922(...) \, +#define Z_IS_3922_EQ_3922U(...) \, +#define Z_IS_3922U_EQ_3922U(...) \, +#define Z_IS_3923_EQ_3923(...) \, +#define Z_IS_3923U_EQ_3923(...) \, +#define Z_IS_3923_EQ_3923U(...) \, +#define Z_IS_3923U_EQ_3923U(...) \, +#define Z_IS_3924_EQ_3924(...) \, +#define Z_IS_3924U_EQ_3924(...) \, +#define Z_IS_3924_EQ_3924U(...) \, +#define Z_IS_3924U_EQ_3924U(...) \, +#define Z_IS_3925_EQ_3925(...) \, +#define Z_IS_3925U_EQ_3925(...) \, +#define Z_IS_3925_EQ_3925U(...) \, +#define Z_IS_3925U_EQ_3925U(...) \, +#define Z_IS_3926_EQ_3926(...) \, +#define Z_IS_3926U_EQ_3926(...) \, +#define Z_IS_3926_EQ_3926U(...) \, +#define Z_IS_3926U_EQ_3926U(...) \, +#define Z_IS_3927_EQ_3927(...) \, +#define Z_IS_3927U_EQ_3927(...) \, +#define Z_IS_3927_EQ_3927U(...) \, +#define Z_IS_3927U_EQ_3927U(...) \, +#define Z_IS_3928_EQ_3928(...) \, +#define Z_IS_3928U_EQ_3928(...) \, +#define Z_IS_3928_EQ_3928U(...) \, +#define Z_IS_3928U_EQ_3928U(...) \, +#define Z_IS_3929_EQ_3929(...) \, +#define Z_IS_3929U_EQ_3929(...) \, +#define Z_IS_3929_EQ_3929U(...) \, +#define Z_IS_3929U_EQ_3929U(...) \, +#define Z_IS_3930_EQ_3930(...) \, +#define Z_IS_3930U_EQ_3930(...) \, +#define Z_IS_3930_EQ_3930U(...) \, +#define Z_IS_3930U_EQ_3930U(...) \, +#define Z_IS_3931_EQ_3931(...) \, +#define Z_IS_3931U_EQ_3931(...) \, +#define Z_IS_3931_EQ_3931U(...) \, +#define Z_IS_3931U_EQ_3931U(...) \, +#define Z_IS_3932_EQ_3932(...) \, +#define Z_IS_3932U_EQ_3932(...) \, +#define Z_IS_3932_EQ_3932U(...) \, +#define Z_IS_3932U_EQ_3932U(...) \, +#define Z_IS_3933_EQ_3933(...) \, +#define Z_IS_3933U_EQ_3933(...) \, +#define Z_IS_3933_EQ_3933U(...) \, +#define Z_IS_3933U_EQ_3933U(...) \, +#define Z_IS_3934_EQ_3934(...) \, +#define Z_IS_3934U_EQ_3934(...) \, +#define Z_IS_3934_EQ_3934U(...) \, +#define Z_IS_3934U_EQ_3934U(...) \, +#define Z_IS_3935_EQ_3935(...) \, +#define Z_IS_3935U_EQ_3935(...) \, +#define Z_IS_3935_EQ_3935U(...) \, +#define Z_IS_3935U_EQ_3935U(...) \, +#define Z_IS_3936_EQ_3936(...) \, +#define Z_IS_3936U_EQ_3936(...) \, +#define Z_IS_3936_EQ_3936U(...) \, +#define Z_IS_3936U_EQ_3936U(...) \, +#define Z_IS_3937_EQ_3937(...) \, +#define Z_IS_3937U_EQ_3937(...) \, +#define Z_IS_3937_EQ_3937U(...) \, +#define Z_IS_3937U_EQ_3937U(...) \, +#define Z_IS_3938_EQ_3938(...) \, +#define Z_IS_3938U_EQ_3938(...) \, +#define Z_IS_3938_EQ_3938U(...) \, +#define Z_IS_3938U_EQ_3938U(...) \, +#define Z_IS_3939_EQ_3939(...) \, +#define Z_IS_3939U_EQ_3939(...) \, +#define Z_IS_3939_EQ_3939U(...) \, +#define Z_IS_3939U_EQ_3939U(...) \, +#define Z_IS_3940_EQ_3940(...) \, +#define Z_IS_3940U_EQ_3940(...) \, +#define Z_IS_3940_EQ_3940U(...) \, +#define Z_IS_3940U_EQ_3940U(...) \, +#define Z_IS_3941_EQ_3941(...) \, +#define Z_IS_3941U_EQ_3941(...) \, +#define Z_IS_3941_EQ_3941U(...) \, +#define Z_IS_3941U_EQ_3941U(...) \, +#define Z_IS_3942_EQ_3942(...) \, +#define Z_IS_3942U_EQ_3942(...) \, +#define Z_IS_3942_EQ_3942U(...) \, +#define Z_IS_3942U_EQ_3942U(...) \, +#define Z_IS_3943_EQ_3943(...) \, +#define Z_IS_3943U_EQ_3943(...) \, +#define Z_IS_3943_EQ_3943U(...) \, +#define Z_IS_3943U_EQ_3943U(...) \, +#define Z_IS_3944_EQ_3944(...) \, +#define Z_IS_3944U_EQ_3944(...) \, +#define Z_IS_3944_EQ_3944U(...) \, +#define Z_IS_3944U_EQ_3944U(...) \, +#define Z_IS_3945_EQ_3945(...) \, +#define Z_IS_3945U_EQ_3945(...) \, +#define Z_IS_3945_EQ_3945U(...) \, +#define Z_IS_3945U_EQ_3945U(...) \, +#define Z_IS_3946_EQ_3946(...) \, +#define Z_IS_3946U_EQ_3946(...) \, +#define Z_IS_3946_EQ_3946U(...) \, +#define Z_IS_3946U_EQ_3946U(...) \, +#define Z_IS_3947_EQ_3947(...) \, +#define Z_IS_3947U_EQ_3947(...) \, +#define Z_IS_3947_EQ_3947U(...) \, +#define Z_IS_3947U_EQ_3947U(...) \, +#define Z_IS_3948_EQ_3948(...) \, +#define Z_IS_3948U_EQ_3948(...) \, +#define Z_IS_3948_EQ_3948U(...) \, +#define Z_IS_3948U_EQ_3948U(...) \, +#define Z_IS_3949_EQ_3949(...) \, +#define Z_IS_3949U_EQ_3949(...) \, +#define Z_IS_3949_EQ_3949U(...) \, +#define Z_IS_3949U_EQ_3949U(...) \, +#define Z_IS_3950_EQ_3950(...) \, +#define Z_IS_3950U_EQ_3950(...) \, +#define Z_IS_3950_EQ_3950U(...) \, +#define Z_IS_3950U_EQ_3950U(...) \, +#define Z_IS_3951_EQ_3951(...) \, +#define Z_IS_3951U_EQ_3951(...) \, +#define Z_IS_3951_EQ_3951U(...) \, +#define Z_IS_3951U_EQ_3951U(...) \, +#define Z_IS_3952_EQ_3952(...) \, +#define Z_IS_3952U_EQ_3952(...) \, +#define Z_IS_3952_EQ_3952U(...) \, +#define Z_IS_3952U_EQ_3952U(...) \, +#define Z_IS_3953_EQ_3953(...) \, +#define Z_IS_3953U_EQ_3953(...) \, +#define Z_IS_3953_EQ_3953U(...) \, +#define Z_IS_3953U_EQ_3953U(...) \, +#define Z_IS_3954_EQ_3954(...) \, +#define Z_IS_3954U_EQ_3954(...) \, +#define Z_IS_3954_EQ_3954U(...) \, +#define Z_IS_3954U_EQ_3954U(...) \, +#define Z_IS_3955_EQ_3955(...) \, +#define Z_IS_3955U_EQ_3955(...) \, +#define Z_IS_3955_EQ_3955U(...) \, +#define Z_IS_3955U_EQ_3955U(...) \, +#define Z_IS_3956_EQ_3956(...) \, +#define Z_IS_3956U_EQ_3956(...) \, +#define Z_IS_3956_EQ_3956U(...) \, +#define Z_IS_3956U_EQ_3956U(...) \, +#define Z_IS_3957_EQ_3957(...) \, +#define Z_IS_3957U_EQ_3957(...) \, +#define Z_IS_3957_EQ_3957U(...) \, +#define Z_IS_3957U_EQ_3957U(...) \, +#define Z_IS_3958_EQ_3958(...) \, +#define Z_IS_3958U_EQ_3958(...) \, +#define Z_IS_3958_EQ_3958U(...) \, +#define Z_IS_3958U_EQ_3958U(...) \, +#define Z_IS_3959_EQ_3959(...) \, +#define Z_IS_3959U_EQ_3959(...) \, +#define Z_IS_3959_EQ_3959U(...) \, +#define Z_IS_3959U_EQ_3959U(...) \, +#define Z_IS_3960_EQ_3960(...) \, +#define Z_IS_3960U_EQ_3960(...) \, +#define Z_IS_3960_EQ_3960U(...) \, +#define Z_IS_3960U_EQ_3960U(...) \, +#define Z_IS_3961_EQ_3961(...) \, +#define Z_IS_3961U_EQ_3961(...) \, +#define Z_IS_3961_EQ_3961U(...) \, +#define Z_IS_3961U_EQ_3961U(...) \, +#define Z_IS_3962_EQ_3962(...) \, +#define Z_IS_3962U_EQ_3962(...) \, +#define Z_IS_3962_EQ_3962U(...) \, +#define Z_IS_3962U_EQ_3962U(...) \, +#define Z_IS_3963_EQ_3963(...) \, +#define Z_IS_3963U_EQ_3963(...) \, +#define Z_IS_3963_EQ_3963U(...) \, +#define Z_IS_3963U_EQ_3963U(...) \, +#define Z_IS_3964_EQ_3964(...) \, +#define Z_IS_3964U_EQ_3964(...) \, +#define Z_IS_3964_EQ_3964U(...) \, +#define Z_IS_3964U_EQ_3964U(...) \, +#define Z_IS_3965_EQ_3965(...) \, +#define Z_IS_3965U_EQ_3965(...) \, +#define Z_IS_3965_EQ_3965U(...) \, +#define Z_IS_3965U_EQ_3965U(...) \, +#define Z_IS_3966_EQ_3966(...) \, +#define Z_IS_3966U_EQ_3966(...) \, +#define Z_IS_3966_EQ_3966U(...) \, +#define Z_IS_3966U_EQ_3966U(...) \, +#define Z_IS_3967_EQ_3967(...) \, +#define Z_IS_3967U_EQ_3967(...) \, +#define Z_IS_3967_EQ_3967U(...) \, +#define Z_IS_3967U_EQ_3967U(...) \, +#define Z_IS_3968_EQ_3968(...) \, +#define Z_IS_3968U_EQ_3968(...) \, +#define Z_IS_3968_EQ_3968U(...) \, +#define Z_IS_3968U_EQ_3968U(...) \, +#define Z_IS_3969_EQ_3969(...) \, +#define Z_IS_3969U_EQ_3969(...) \, +#define Z_IS_3969_EQ_3969U(...) \, +#define Z_IS_3969U_EQ_3969U(...) \, +#define Z_IS_3970_EQ_3970(...) \, +#define Z_IS_3970U_EQ_3970(...) \, +#define Z_IS_3970_EQ_3970U(...) \, +#define Z_IS_3970U_EQ_3970U(...) \, +#define Z_IS_3971_EQ_3971(...) \, +#define Z_IS_3971U_EQ_3971(...) \, +#define Z_IS_3971_EQ_3971U(...) \, +#define Z_IS_3971U_EQ_3971U(...) \, +#define Z_IS_3972_EQ_3972(...) \, +#define Z_IS_3972U_EQ_3972(...) \, +#define Z_IS_3972_EQ_3972U(...) \, +#define Z_IS_3972U_EQ_3972U(...) \, +#define Z_IS_3973_EQ_3973(...) \, +#define Z_IS_3973U_EQ_3973(...) \, +#define Z_IS_3973_EQ_3973U(...) \, +#define Z_IS_3973U_EQ_3973U(...) \, +#define Z_IS_3974_EQ_3974(...) \, +#define Z_IS_3974U_EQ_3974(...) \, +#define Z_IS_3974_EQ_3974U(...) \, +#define Z_IS_3974U_EQ_3974U(...) \, +#define Z_IS_3975_EQ_3975(...) \, +#define Z_IS_3975U_EQ_3975(...) \, +#define Z_IS_3975_EQ_3975U(...) \, +#define Z_IS_3975U_EQ_3975U(...) \, +#define Z_IS_3976_EQ_3976(...) \, +#define Z_IS_3976U_EQ_3976(...) \, +#define Z_IS_3976_EQ_3976U(...) \, +#define Z_IS_3976U_EQ_3976U(...) \, +#define Z_IS_3977_EQ_3977(...) \, +#define Z_IS_3977U_EQ_3977(...) \, +#define Z_IS_3977_EQ_3977U(...) \, +#define Z_IS_3977U_EQ_3977U(...) \, +#define Z_IS_3978_EQ_3978(...) \, +#define Z_IS_3978U_EQ_3978(...) \, +#define Z_IS_3978_EQ_3978U(...) \, +#define Z_IS_3978U_EQ_3978U(...) \, +#define Z_IS_3979_EQ_3979(...) \, +#define Z_IS_3979U_EQ_3979(...) \, +#define Z_IS_3979_EQ_3979U(...) \, +#define Z_IS_3979U_EQ_3979U(...) \, +#define Z_IS_3980_EQ_3980(...) \, +#define Z_IS_3980U_EQ_3980(...) \, +#define Z_IS_3980_EQ_3980U(...) \, +#define Z_IS_3980U_EQ_3980U(...) \, +#define Z_IS_3981_EQ_3981(...) \, +#define Z_IS_3981U_EQ_3981(...) \, +#define Z_IS_3981_EQ_3981U(...) \, +#define Z_IS_3981U_EQ_3981U(...) \, +#define Z_IS_3982_EQ_3982(...) \, +#define Z_IS_3982U_EQ_3982(...) \, +#define Z_IS_3982_EQ_3982U(...) \, +#define Z_IS_3982U_EQ_3982U(...) \, +#define Z_IS_3983_EQ_3983(...) \, +#define Z_IS_3983U_EQ_3983(...) \, +#define Z_IS_3983_EQ_3983U(...) \, +#define Z_IS_3983U_EQ_3983U(...) \, +#define Z_IS_3984_EQ_3984(...) \, +#define Z_IS_3984U_EQ_3984(...) \, +#define Z_IS_3984_EQ_3984U(...) \, +#define Z_IS_3984U_EQ_3984U(...) \, +#define Z_IS_3985_EQ_3985(...) \, +#define Z_IS_3985U_EQ_3985(...) \, +#define Z_IS_3985_EQ_3985U(...) \, +#define Z_IS_3985U_EQ_3985U(...) \, +#define Z_IS_3986_EQ_3986(...) \, +#define Z_IS_3986U_EQ_3986(...) \, +#define Z_IS_3986_EQ_3986U(...) \, +#define Z_IS_3986U_EQ_3986U(...) \, +#define Z_IS_3987_EQ_3987(...) \, +#define Z_IS_3987U_EQ_3987(...) \, +#define Z_IS_3987_EQ_3987U(...) \, +#define Z_IS_3987U_EQ_3987U(...) \, +#define Z_IS_3988_EQ_3988(...) \, +#define Z_IS_3988U_EQ_3988(...) \, +#define Z_IS_3988_EQ_3988U(...) \, +#define Z_IS_3988U_EQ_3988U(...) \, +#define Z_IS_3989_EQ_3989(...) \, +#define Z_IS_3989U_EQ_3989(...) \, +#define Z_IS_3989_EQ_3989U(...) \, +#define Z_IS_3989U_EQ_3989U(...) \, +#define Z_IS_3990_EQ_3990(...) \, +#define Z_IS_3990U_EQ_3990(...) \, +#define Z_IS_3990_EQ_3990U(...) \, +#define Z_IS_3990U_EQ_3990U(...) \, +#define Z_IS_3991_EQ_3991(...) \, +#define Z_IS_3991U_EQ_3991(...) \, +#define Z_IS_3991_EQ_3991U(...) \, +#define Z_IS_3991U_EQ_3991U(...) \, +#define Z_IS_3992_EQ_3992(...) \, +#define Z_IS_3992U_EQ_3992(...) \, +#define Z_IS_3992_EQ_3992U(...) \, +#define Z_IS_3992U_EQ_3992U(...) \, +#define Z_IS_3993_EQ_3993(...) \, +#define Z_IS_3993U_EQ_3993(...) \, +#define Z_IS_3993_EQ_3993U(...) \, +#define Z_IS_3993U_EQ_3993U(...) \, +#define Z_IS_3994_EQ_3994(...) \, +#define Z_IS_3994U_EQ_3994(...) \, +#define Z_IS_3994_EQ_3994U(...) \, +#define Z_IS_3994U_EQ_3994U(...) \, +#define Z_IS_3995_EQ_3995(...) \, +#define Z_IS_3995U_EQ_3995(...) \, +#define Z_IS_3995_EQ_3995U(...) \, +#define Z_IS_3995U_EQ_3995U(...) \, +#define Z_IS_3996_EQ_3996(...) \, +#define Z_IS_3996U_EQ_3996(...) \, +#define Z_IS_3996_EQ_3996U(...) \, +#define Z_IS_3996U_EQ_3996U(...) \, +#define Z_IS_3997_EQ_3997(...) \, +#define Z_IS_3997U_EQ_3997(...) \, +#define Z_IS_3997_EQ_3997U(...) \, +#define Z_IS_3997U_EQ_3997U(...) \, +#define Z_IS_3998_EQ_3998(...) \, +#define Z_IS_3998U_EQ_3998(...) \, +#define Z_IS_3998_EQ_3998U(...) \, +#define Z_IS_3998U_EQ_3998U(...) \, +#define Z_IS_3999_EQ_3999(...) \, +#define Z_IS_3999U_EQ_3999(...) \, +#define Z_IS_3999_EQ_3999U(...) \, +#define Z_IS_3999U_EQ_3999U(...) \, +#define Z_IS_4000_EQ_4000(...) \, +#define Z_IS_4000U_EQ_4000(...) \, +#define Z_IS_4000_EQ_4000U(...) \, +#define Z_IS_4000U_EQ_4000U(...) \, +#define Z_IS_4001_EQ_4001(...) \, +#define Z_IS_4001U_EQ_4001(...) \, +#define Z_IS_4001_EQ_4001U(...) \, +#define Z_IS_4001U_EQ_4001U(...) \, +#define Z_IS_4002_EQ_4002(...) \, +#define Z_IS_4002U_EQ_4002(...) \, +#define Z_IS_4002_EQ_4002U(...) \, +#define Z_IS_4002U_EQ_4002U(...) \, +#define Z_IS_4003_EQ_4003(...) \, +#define Z_IS_4003U_EQ_4003(...) \, +#define Z_IS_4003_EQ_4003U(...) \, +#define Z_IS_4003U_EQ_4003U(...) \, +#define Z_IS_4004_EQ_4004(...) \, +#define Z_IS_4004U_EQ_4004(...) \, +#define Z_IS_4004_EQ_4004U(...) \, +#define Z_IS_4004U_EQ_4004U(...) \, +#define Z_IS_4005_EQ_4005(...) \, +#define Z_IS_4005U_EQ_4005(...) \, +#define Z_IS_4005_EQ_4005U(...) \, +#define Z_IS_4005U_EQ_4005U(...) \, +#define Z_IS_4006_EQ_4006(...) \, +#define Z_IS_4006U_EQ_4006(...) \, +#define Z_IS_4006_EQ_4006U(...) \, +#define Z_IS_4006U_EQ_4006U(...) \, +#define Z_IS_4007_EQ_4007(...) \, +#define Z_IS_4007U_EQ_4007(...) \, +#define Z_IS_4007_EQ_4007U(...) \, +#define Z_IS_4007U_EQ_4007U(...) \, +#define Z_IS_4008_EQ_4008(...) \, +#define Z_IS_4008U_EQ_4008(...) \, +#define Z_IS_4008_EQ_4008U(...) \, +#define Z_IS_4008U_EQ_4008U(...) \, +#define Z_IS_4009_EQ_4009(...) \, +#define Z_IS_4009U_EQ_4009(...) \, +#define Z_IS_4009_EQ_4009U(...) \, +#define Z_IS_4009U_EQ_4009U(...) \, +#define Z_IS_4010_EQ_4010(...) \, +#define Z_IS_4010U_EQ_4010(...) \, +#define Z_IS_4010_EQ_4010U(...) \, +#define Z_IS_4010U_EQ_4010U(...) \, +#define Z_IS_4011_EQ_4011(...) \, +#define Z_IS_4011U_EQ_4011(...) \, +#define Z_IS_4011_EQ_4011U(...) \, +#define Z_IS_4011U_EQ_4011U(...) \, +#define Z_IS_4012_EQ_4012(...) \, +#define Z_IS_4012U_EQ_4012(...) \, +#define Z_IS_4012_EQ_4012U(...) \, +#define Z_IS_4012U_EQ_4012U(...) \, +#define Z_IS_4013_EQ_4013(...) \, +#define Z_IS_4013U_EQ_4013(...) \, +#define Z_IS_4013_EQ_4013U(...) \, +#define Z_IS_4013U_EQ_4013U(...) \, +#define Z_IS_4014_EQ_4014(...) \, +#define Z_IS_4014U_EQ_4014(...) \, +#define Z_IS_4014_EQ_4014U(...) \, +#define Z_IS_4014U_EQ_4014U(...) \, +#define Z_IS_4015_EQ_4015(...) \, +#define Z_IS_4015U_EQ_4015(...) \, +#define Z_IS_4015_EQ_4015U(...) \, +#define Z_IS_4015U_EQ_4015U(...) \, +#define Z_IS_4016_EQ_4016(...) \, +#define Z_IS_4016U_EQ_4016(...) \, +#define Z_IS_4016_EQ_4016U(...) \, +#define Z_IS_4016U_EQ_4016U(...) \, +#define Z_IS_4017_EQ_4017(...) \, +#define Z_IS_4017U_EQ_4017(...) \, +#define Z_IS_4017_EQ_4017U(...) \, +#define Z_IS_4017U_EQ_4017U(...) \, +#define Z_IS_4018_EQ_4018(...) \, +#define Z_IS_4018U_EQ_4018(...) \, +#define Z_IS_4018_EQ_4018U(...) \, +#define Z_IS_4018U_EQ_4018U(...) \, +#define Z_IS_4019_EQ_4019(...) \, +#define Z_IS_4019U_EQ_4019(...) \, +#define Z_IS_4019_EQ_4019U(...) \, +#define Z_IS_4019U_EQ_4019U(...) \, +#define Z_IS_4020_EQ_4020(...) \, +#define Z_IS_4020U_EQ_4020(...) \, +#define Z_IS_4020_EQ_4020U(...) \, +#define Z_IS_4020U_EQ_4020U(...) \, +#define Z_IS_4021_EQ_4021(...) \, +#define Z_IS_4021U_EQ_4021(...) \, +#define Z_IS_4021_EQ_4021U(...) \, +#define Z_IS_4021U_EQ_4021U(...) \, +#define Z_IS_4022_EQ_4022(...) \, +#define Z_IS_4022U_EQ_4022(...) \, +#define Z_IS_4022_EQ_4022U(...) \, +#define Z_IS_4022U_EQ_4022U(...) \, +#define Z_IS_4023_EQ_4023(...) \, +#define Z_IS_4023U_EQ_4023(...) \, +#define Z_IS_4023_EQ_4023U(...) \, +#define Z_IS_4023U_EQ_4023U(...) \, +#define Z_IS_4024_EQ_4024(...) \, +#define Z_IS_4024U_EQ_4024(...) \, +#define Z_IS_4024_EQ_4024U(...) \, +#define Z_IS_4024U_EQ_4024U(...) \, +#define Z_IS_4025_EQ_4025(...) \, +#define Z_IS_4025U_EQ_4025(...) \, +#define Z_IS_4025_EQ_4025U(...) \, +#define Z_IS_4025U_EQ_4025U(...) \, +#define Z_IS_4026_EQ_4026(...) \, +#define Z_IS_4026U_EQ_4026(...) \, +#define Z_IS_4026_EQ_4026U(...) \, +#define Z_IS_4026U_EQ_4026U(...) \, +#define Z_IS_4027_EQ_4027(...) \, +#define Z_IS_4027U_EQ_4027(...) \, +#define Z_IS_4027_EQ_4027U(...) \, +#define Z_IS_4027U_EQ_4027U(...) \, +#define Z_IS_4028_EQ_4028(...) \, +#define Z_IS_4028U_EQ_4028(...) \, +#define Z_IS_4028_EQ_4028U(...) \, +#define Z_IS_4028U_EQ_4028U(...) \, +#define Z_IS_4029_EQ_4029(...) \, +#define Z_IS_4029U_EQ_4029(...) \, +#define Z_IS_4029_EQ_4029U(...) \, +#define Z_IS_4029U_EQ_4029U(...) \, +#define Z_IS_4030_EQ_4030(...) \, +#define Z_IS_4030U_EQ_4030(...) \, +#define Z_IS_4030_EQ_4030U(...) \, +#define Z_IS_4030U_EQ_4030U(...) \, +#define Z_IS_4031_EQ_4031(...) \, +#define Z_IS_4031U_EQ_4031(...) \, +#define Z_IS_4031_EQ_4031U(...) \, +#define Z_IS_4031U_EQ_4031U(...) \, +#define Z_IS_4032_EQ_4032(...) \, +#define Z_IS_4032U_EQ_4032(...) \, +#define Z_IS_4032_EQ_4032U(...) \, +#define Z_IS_4032U_EQ_4032U(...) \, +#define Z_IS_4033_EQ_4033(...) \, +#define Z_IS_4033U_EQ_4033(...) \, +#define Z_IS_4033_EQ_4033U(...) \, +#define Z_IS_4033U_EQ_4033U(...) \, +#define Z_IS_4034_EQ_4034(...) \, +#define Z_IS_4034U_EQ_4034(...) \, +#define Z_IS_4034_EQ_4034U(...) \, +#define Z_IS_4034U_EQ_4034U(...) \, +#define Z_IS_4035_EQ_4035(...) \, +#define Z_IS_4035U_EQ_4035(...) \, +#define Z_IS_4035_EQ_4035U(...) \, +#define Z_IS_4035U_EQ_4035U(...) \, +#define Z_IS_4036_EQ_4036(...) \, +#define Z_IS_4036U_EQ_4036(...) \, +#define Z_IS_4036_EQ_4036U(...) \, +#define Z_IS_4036U_EQ_4036U(...) \, +#define Z_IS_4037_EQ_4037(...) \, +#define Z_IS_4037U_EQ_4037(...) \, +#define Z_IS_4037_EQ_4037U(...) \, +#define Z_IS_4037U_EQ_4037U(...) \, +#define Z_IS_4038_EQ_4038(...) \, +#define Z_IS_4038U_EQ_4038(...) \, +#define Z_IS_4038_EQ_4038U(...) \, +#define Z_IS_4038U_EQ_4038U(...) \, +#define Z_IS_4039_EQ_4039(...) \, +#define Z_IS_4039U_EQ_4039(...) \, +#define Z_IS_4039_EQ_4039U(...) \, +#define Z_IS_4039U_EQ_4039U(...) \, +#define Z_IS_4040_EQ_4040(...) \, +#define Z_IS_4040U_EQ_4040(...) \, +#define Z_IS_4040_EQ_4040U(...) \, +#define Z_IS_4040U_EQ_4040U(...) \, +#define Z_IS_4041_EQ_4041(...) \, +#define Z_IS_4041U_EQ_4041(...) \, +#define Z_IS_4041_EQ_4041U(...) \, +#define Z_IS_4041U_EQ_4041U(...) \, +#define Z_IS_4042_EQ_4042(...) \, +#define Z_IS_4042U_EQ_4042(...) \, +#define Z_IS_4042_EQ_4042U(...) \, +#define Z_IS_4042U_EQ_4042U(...) \, +#define Z_IS_4043_EQ_4043(...) \, +#define Z_IS_4043U_EQ_4043(...) \, +#define Z_IS_4043_EQ_4043U(...) \, +#define Z_IS_4043U_EQ_4043U(...) \, +#define Z_IS_4044_EQ_4044(...) \, +#define Z_IS_4044U_EQ_4044(...) \, +#define Z_IS_4044_EQ_4044U(...) \, +#define Z_IS_4044U_EQ_4044U(...) \, +#define Z_IS_4045_EQ_4045(...) \, +#define Z_IS_4045U_EQ_4045(...) \, +#define Z_IS_4045_EQ_4045U(...) \, +#define Z_IS_4045U_EQ_4045U(...) \, +#define Z_IS_4046_EQ_4046(...) \, +#define Z_IS_4046U_EQ_4046(...) \, +#define Z_IS_4046_EQ_4046U(...) \, +#define Z_IS_4046U_EQ_4046U(...) \, +#define Z_IS_4047_EQ_4047(...) \, +#define Z_IS_4047U_EQ_4047(...) \, +#define Z_IS_4047_EQ_4047U(...) \, +#define Z_IS_4047U_EQ_4047U(...) \, +#define Z_IS_4048_EQ_4048(...) \, +#define Z_IS_4048U_EQ_4048(...) \, +#define Z_IS_4048_EQ_4048U(...) \, +#define Z_IS_4048U_EQ_4048U(...) \, +#define Z_IS_4049_EQ_4049(...) \, +#define Z_IS_4049U_EQ_4049(...) \, +#define Z_IS_4049_EQ_4049U(...) \, +#define Z_IS_4049U_EQ_4049U(...) \, +#define Z_IS_4050_EQ_4050(...) \, +#define Z_IS_4050U_EQ_4050(...) \, +#define Z_IS_4050_EQ_4050U(...) \, +#define Z_IS_4050U_EQ_4050U(...) \, +#define Z_IS_4051_EQ_4051(...) \, +#define Z_IS_4051U_EQ_4051(...) \, +#define Z_IS_4051_EQ_4051U(...) \, +#define Z_IS_4051U_EQ_4051U(...) \, +#define Z_IS_4052_EQ_4052(...) \, +#define Z_IS_4052U_EQ_4052(...) \, +#define Z_IS_4052_EQ_4052U(...) \, +#define Z_IS_4052U_EQ_4052U(...) \, +#define Z_IS_4053_EQ_4053(...) \, +#define Z_IS_4053U_EQ_4053(...) \, +#define Z_IS_4053_EQ_4053U(...) \, +#define Z_IS_4053U_EQ_4053U(...) \, +#define Z_IS_4054_EQ_4054(...) \, +#define Z_IS_4054U_EQ_4054(...) \, +#define Z_IS_4054_EQ_4054U(...) \, +#define Z_IS_4054U_EQ_4054U(...) \, +#define Z_IS_4055_EQ_4055(...) \, +#define Z_IS_4055U_EQ_4055(...) \, +#define Z_IS_4055_EQ_4055U(...) \, +#define Z_IS_4055U_EQ_4055U(...) \, +#define Z_IS_4056_EQ_4056(...) \, +#define Z_IS_4056U_EQ_4056(...) \, +#define Z_IS_4056_EQ_4056U(...) \, +#define Z_IS_4056U_EQ_4056U(...) \, +#define Z_IS_4057_EQ_4057(...) \, +#define Z_IS_4057U_EQ_4057(...) \, +#define Z_IS_4057_EQ_4057U(...) \, +#define Z_IS_4057U_EQ_4057U(...) \, +#define Z_IS_4058_EQ_4058(...) \, +#define Z_IS_4058U_EQ_4058(...) \, +#define Z_IS_4058_EQ_4058U(...) \, +#define Z_IS_4058U_EQ_4058U(...) \, +#define Z_IS_4059_EQ_4059(...) \, +#define Z_IS_4059U_EQ_4059(...) \, +#define Z_IS_4059_EQ_4059U(...) \, +#define Z_IS_4059U_EQ_4059U(...) \, +#define Z_IS_4060_EQ_4060(...) \, +#define Z_IS_4060U_EQ_4060(...) \, +#define Z_IS_4060_EQ_4060U(...) \, +#define Z_IS_4060U_EQ_4060U(...) \, +#define Z_IS_4061_EQ_4061(...) \, +#define Z_IS_4061U_EQ_4061(...) \, +#define Z_IS_4061_EQ_4061U(...) \, +#define Z_IS_4061U_EQ_4061U(...) \, +#define Z_IS_4062_EQ_4062(...) \, +#define Z_IS_4062U_EQ_4062(...) \, +#define Z_IS_4062_EQ_4062U(...) \, +#define Z_IS_4062U_EQ_4062U(...) \, +#define Z_IS_4063_EQ_4063(...) \, +#define Z_IS_4063U_EQ_4063(...) \, +#define Z_IS_4063_EQ_4063U(...) \, +#define Z_IS_4063U_EQ_4063U(...) \, +#define Z_IS_4064_EQ_4064(...) \, +#define Z_IS_4064U_EQ_4064(...) \, +#define Z_IS_4064_EQ_4064U(...) \, +#define Z_IS_4064U_EQ_4064U(...) \, +#define Z_IS_4065_EQ_4065(...) \, +#define Z_IS_4065U_EQ_4065(...) \, +#define Z_IS_4065_EQ_4065U(...) \, +#define Z_IS_4065U_EQ_4065U(...) \, +#define Z_IS_4066_EQ_4066(...) \, +#define Z_IS_4066U_EQ_4066(...) \, +#define Z_IS_4066_EQ_4066U(...) \, +#define Z_IS_4066U_EQ_4066U(...) \, +#define Z_IS_4067_EQ_4067(...) \, +#define Z_IS_4067U_EQ_4067(...) \, +#define Z_IS_4067_EQ_4067U(...) \, +#define Z_IS_4067U_EQ_4067U(...) \, +#define Z_IS_4068_EQ_4068(...) \, +#define Z_IS_4068U_EQ_4068(...) \, +#define Z_IS_4068_EQ_4068U(...) \, +#define Z_IS_4068U_EQ_4068U(...) \, +#define Z_IS_4069_EQ_4069(...) \, +#define Z_IS_4069U_EQ_4069(...) \, +#define Z_IS_4069_EQ_4069U(...) \, +#define Z_IS_4069U_EQ_4069U(...) \, +#define Z_IS_4070_EQ_4070(...) \, +#define Z_IS_4070U_EQ_4070(...) \, +#define Z_IS_4070_EQ_4070U(...) \, +#define Z_IS_4070U_EQ_4070U(...) \, +#define Z_IS_4071_EQ_4071(...) \, +#define Z_IS_4071U_EQ_4071(...) \, +#define Z_IS_4071_EQ_4071U(...) \, +#define Z_IS_4071U_EQ_4071U(...) \, +#define Z_IS_4072_EQ_4072(...) \, +#define Z_IS_4072U_EQ_4072(...) \, +#define Z_IS_4072_EQ_4072U(...) \, +#define Z_IS_4072U_EQ_4072U(...) \, +#define Z_IS_4073_EQ_4073(...) \, +#define Z_IS_4073U_EQ_4073(...) \, +#define Z_IS_4073_EQ_4073U(...) \, +#define Z_IS_4073U_EQ_4073U(...) \, +#define Z_IS_4074_EQ_4074(...) \, +#define Z_IS_4074U_EQ_4074(...) \, +#define Z_IS_4074_EQ_4074U(...) \, +#define Z_IS_4074U_EQ_4074U(...) \, +#define Z_IS_4075_EQ_4075(...) \, +#define Z_IS_4075U_EQ_4075(...) \, +#define Z_IS_4075_EQ_4075U(...) \, +#define Z_IS_4075U_EQ_4075U(...) \, +#define Z_IS_4076_EQ_4076(...) \, +#define Z_IS_4076U_EQ_4076(...) \, +#define Z_IS_4076_EQ_4076U(...) \, +#define Z_IS_4076U_EQ_4076U(...) \, +#define Z_IS_4077_EQ_4077(...) \, +#define Z_IS_4077U_EQ_4077(...) \, +#define Z_IS_4077_EQ_4077U(...) \, +#define Z_IS_4077U_EQ_4077U(...) \, +#define Z_IS_4078_EQ_4078(...) \, +#define Z_IS_4078U_EQ_4078(...) \, +#define Z_IS_4078_EQ_4078U(...) \, +#define Z_IS_4078U_EQ_4078U(...) \, +#define Z_IS_4079_EQ_4079(...) \, +#define Z_IS_4079U_EQ_4079(...) \, +#define Z_IS_4079_EQ_4079U(...) \, +#define Z_IS_4079U_EQ_4079U(...) \, +#define Z_IS_4080_EQ_4080(...) \, +#define Z_IS_4080U_EQ_4080(...) \, +#define Z_IS_4080_EQ_4080U(...) \, +#define Z_IS_4080U_EQ_4080U(...) \, +#define Z_IS_4081_EQ_4081(...) \, +#define Z_IS_4081U_EQ_4081(...) \, +#define Z_IS_4081_EQ_4081U(...) \, +#define Z_IS_4081U_EQ_4081U(...) \, +#define Z_IS_4082_EQ_4082(...) \, +#define Z_IS_4082U_EQ_4082(...) \, +#define Z_IS_4082_EQ_4082U(...) \, +#define Z_IS_4082U_EQ_4082U(...) \, +#define Z_IS_4083_EQ_4083(...) \, +#define Z_IS_4083U_EQ_4083(...) \, +#define Z_IS_4083_EQ_4083U(...) \, +#define Z_IS_4083U_EQ_4083U(...) \, +#define Z_IS_4084_EQ_4084(...) \, +#define Z_IS_4084U_EQ_4084(...) \, +#define Z_IS_4084_EQ_4084U(...) \, +#define Z_IS_4084U_EQ_4084U(...) \, +#define Z_IS_4085_EQ_4085(...) \, +#define Z_IS_4085U_EQ_4085(...) \, +#define Z_IS_4085_EQ_4085U(...) \, +#define Z_IS_4085U_EQ_4085U(...) \, +#define Z_IS_4086_EQ_4086(...) \, +#define Z_IS_4086U_EQ_4086(...) \, +#define Z_IS_4086_EQ_4086U(...) \, +#define Z_IS_4086U_EQ_4086U(...) \, +#define Z_IS_4087_EQ_4087(...) \, +#define Z_IS_4087U_EQ_4087(...) \, +#define Z_IS_4087_EQ_4087U(...) \, +#define Z_IS_4087U_EQ_4087U(...) \, +#define Z_IS_4088_EQ_4088(...) \, +#define Z_IS_4088U_EQ_4088(...) \, +#define Z_IS_4088_EQ_4088U(...) \, +#define Z_IS_4088U_EQ_4088U(...) \, +#define Z_IS_4089_EQ_4089(...) \, +#define Z_IS_4089U_EQ_4089(...) \, +#define Z_IS_4089_EQ_4089U(...) \, +#define Z_IS_4089U_EQ_4089U(...) \, +#define Z_IS_4090_EQ_4090(...) \, +#define Z_IS_4090U_EQ_4090(...) \, +#define Z_IS_4090_EQ_4090U(...) \, +#define Z_IS_4090U_EQ_4090U(...) \, +#define Z_IS_4091_EQ_4091(...) \, +#define Z_IS_4091U_EQ_4091(...) \, +#define Z_IS_4091_EQ_4091U(...) \, +#define Z_IS_4091U_EQ_4091U(...) \, +#define Z_IS_4092_EQ_4092(...) \, +#define Z_IS_4092U_EQ_4092(...) \, +#define Z_IS_4092_EQ_4092U(...) \, +#define Z_IS_4092U_EQ_4092U(...) \, +#define Z_IS_4093_EQ_4093(...) \, +#define Z_IS_4093U_EQ_4093(...) \, +#define Z_IS_4093_EQ_4093U(...) \, +#define Z_IS_4093U_EQ_4093U(...) \, +#define Z_IS_4094_EQ_4094(...) \, +#define Z_IS_4094U_EQ_4094(...) \, +#define Z_IS_4094_EQ_4094U(...) \, +#define Z_IS_4094U_EQ_4094U(...) \, +#define Z_IS_4095_EQ_4095(...) \, +#define Z_IS_4095U_EQ_4095(...) \, +#define Z_IS_4095_EQ_4095U(...) \, +#define Z_IS_4095U_EQ_4095U(...) \, +#define Z_IS_4096_EQ_4096(...) \, +#define Z_IS_4096U_EQ_4096(...) \, +#define Z_IS_4096_EQ_4096U(...) \, +#define Z_IS_4096U_EQ_4096U(...) \, + +#endif /* ZEPHYR_INCLUDE_SYS_UTIL_INTERNAL_IS_EQ_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/sys/util_internal_util_dec.h b/components/bt/esp_ble_audio/include/zephyr/sys/util_internal_util_dec.h new file mode 100644 index 0000000000..8bdca33744 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/sys/util_internal_util_dec.h @@ -0,0 +1,4122 @@ +/* + * SPDX-FileCopyrightText: 2011-2014, Wind River Systems, Inc. + * SPDX-FileCopyrightText: 2020, Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @cond INTERNAL_HIDDEN + */ + +#ifndef ZEPHYR_INCLUDE_SYS_UTIL_INTERNAL_H_ +#error "This header should not be used directly, please include util_internal.h instead" +#endif /* ZEPHYR_INCLUDE_SYS_UTIL_INTERNAL_H_ */ + +#ifndef ZEPHYR_INCLUDE_SYS_UTIL_INTERNAL_UTIL_DEC_H_ +#define ZEPHYR_INCLUDE_SYS_UTIL_INTERNAL_UTIL_DEC_H_ + +#define Z_UTIL_DEC_0 0 +#define Z_UTIL_DEC_1 0 +#define Z_UTIL_DEC_2 1 +#define Z_UTIL_DEC_3 2 +#define Z_UTIL_DEC_4 3 +#define Z_UTIL_DEC_5 4 +#define Z_UTIL_DEC_6 5 +#define Z_UTIL_DEC_7 6 +#define Z_UTIL_DEC_8 7 +#define Z_UTIL_DEC_9 8 +#define Z_UTIL_DEC_10 9 +#define Z_UTIL_DEC_11 10 +#define Z_UTIL_DEC_12 11 +#define Z_UTIL_DEC_13 12 +#define Z_UTIL_DEC_14 13 +#define Z_UTIL_DEC_15 14 +#define Z_UTIL_DEC_16 15 +#define Z_UTIL_DEC_17 16 +#define Z_UTIL_DEC_18 17 +#define Z_UTIL_DEC_19 18 +#define Z_UTIL_DEC_20 19 +#define Z_UTIL_DEC_21 20 +#define Z_UTIL_DEC_22 21 +#define Z_UTIL_DEC_23 22 +#define Z_UTIL_DEC_24 23 +#define Z_UTIL_DEC_25 24 +#define Z_UTIL_DEC_26 25 +#define Z_UTIL_DEC_27 26 +#define Z_UTIL_DEC_28 27 +#define Z_UTIL_DEC_29 28 +#define Z_UTIL_DEC_30 29 +#define Z_UTIL_DEC_31 30 +#define Z_UTIL_DEC_32 31 +#define Z_UTIL_DEC_33 32 +#define Z_UTIL_DEC_34 33 +#define Z_UTIL_DEC_35 34 +#define Z_UTIL_DEC_36 35 +#define Z_UTIL_DEC_37 36 +#define Z_UTIL_DEC_38 37 +#define Z_UTIL_DEC_39 38 +#define Z_UTIL_DEC_40 39 +#define Z_UTIL_DEC_41 40 +#define Z_UTIL_DEC_42 41 +#define Z_UTIL_DEC_43 42 +#define Z_UTIL_DEC_44 43 +#define Z_UTIL_DEC_45 44 +#define Z_UTIL_DEC_46 45 +#define Z_UTIL_DEC_47 46 +#define Z_UTIL_DEC_48 47 +#define Z_UTIL_DEC_49 48 +#define Z_UTIL_DEC_50 49 +#define Z_UTIL_DEC_51 50 +#define Z_UTIL_DEC_52 51 +#define Z_UTIL_DEC_53 52 +#define Z_UTIL_DEC_54 53 +#define Z_UTIL_DEC_55 54 +#define Z_UTIL_DEC_56 55 +#define Z_UTIL_DEC_57 56 +#define Z_UTIL_DEC_58 57 +#define Z_UTIL_DEC_59 58 +#define Z_UTIL_DEC_60 59 +#define Z_UTIL_DEC_61 60 +#define Z_UTIL_DEC_62 61 +#define Z_UTIL_DEC_63 62 +#define Z_UTIL_DEC_64 63 +#define Z_UTIL_DEC_65 64 +#define Z_UTIL_DEC_66 65 +#define Z_UTIL_DEC_67 66 +#define Z_UTIL_DEC_68 67 +#define Z_UTIL_DEC_69 68 +#define Z_UTIL_DEC_70 69 +#define Z_UTIL_DEC_71 70 +#define Z_UTIL_DEC_72 71 +#define Z_UTIL_DEC_73 72 +#define Z_UTIL_DEC_74 73 +#define Z_UTIL_DEC_75 74 +#define Z_UTIL_DEC_76 75 +#define Z_UTIL_DEC_77 76 +#define Z_UTIL_DEC_78 77 +#define Z_UTIL_DEC_79 78 +#define Z_UTIL_DEC_80 79 +#define Z_UTIL_DEC_81 80 +#define Z_UTIL_DEC_82 81 +#define Z_UTIL_DEC_83 82 +#define Z_UTIL_DEC_84 83 +#define Z_UTIL_DEC_85 84 +#define Z_UTIL_DEC_86 85 +#define Z_UTIL_DEC_87 86 +#define Z_UTIL_DEC_88 87 +#define Z_UTIL_DEC_89 88 +#define Z_UTIL_DEC_90 89 +#define Z_UTIL_DEC_91 90 +#define Z_UTIL_DEC_92 91 +#define Z_UTIL_DEC_93 92 +#define Z_UTIL_DEC_94 93 +#define Z_UTIL_DEC_95 94 +#define Z_UTIL_DEC_96 95 +#define Z_UTIL_DEC_97 96 +#define Z_UTIL_DEC_98 97 +#define Z_UTIL_DEC_99 98 +#define Z_UTIL_DEC_100 99 +#define Z_UTIL_DEC_101 100 +#define Z_UTIL_DEC_102 101 +#define Z_UTIL_DEC_103 102 +#define Z_UTIL_DEC_104 103 +#define Z_UTIL_DEC_105 104 +#define Z_UTIL_DEC_106 105 +#define Z_UTIL_DEC_107 106 +#define Z_UTIL_DEC_108 107 +#define Z_UTIL_DEC_109 108 +#define Z_UTIL_DEC_110 109 +#define Z_UTIL_DEC_111 110 +#define Z_UTIL_DEC_112 111 +#define Z_UTIL_DEC_113 112 +#define Z_UTIL_DEC_114 113 +#define Z_UTIL_DEC_115 114 +#define Z_UTIL_DEC_116 115 +#define Z_UTIL_DEC_117 116 +#define Z_UTIL_DEC_118 117 +#define Z_UTIL_DEC_119 118 +#define Z_UTIL_DEC_120 119 +#define Z_UTIL_DEC_121 120 +#define Z_UTIL_DEC_122 121 +#define Z_UTIL_DEC_123 122 +#define Z_UTIL_DEC_124 123 +#define Z_UTIL_DEC_125 124 +#define Z_UTIL_DEC_126 125 +#define Z_UTIL_DEC_127 126 +#define Z_UTIL_DEC_128 127 +#define Z_UTIL_DEC_129 128 +#define Z_UTIL_DEC_130 129 +#define Z_UTIL_DEC_131 130 +#define Z_UTIL_DEC_132 131 +#define Z_UTIL_DEC_133 132 +#define Z_UTIL_DEC_134 133 +#define Z_UTIL_DEC_135 134 +#define Z_UTIL_DEC_136 135 +#define Z_UTIL_DEC_137 136 +#define Z_UTIL_DEC_138 137 +#define Z_UTIL_DEC_139 138 +#define Z_UTIL_DEC_140 139 +#define Z_UTIL_DEC_141 140 +#define Z_UTIL_DEC_142 141 +#define Z_UTIL_DEC_143 142 +#define Z_UTIL_DEC_144 143 +#define Z_UTIL_DEC_145 144 +#define Z_UTIL_DEC_146 145 +#define Z_UTIL_DEC_147 146 +#define Z_UTIL_DEC_148 147 +#define Z_UTIL_DEC_149 148 +#define Z_UTIL_DEC_150 149 +#define Z_UTIL_DEC_151 150 +#define Z_UTIL_DEC_152 151 +#define Z_UTIL_DEC_153 152 +#define Z_UTIL_DEC_154 153 +#define Z_UTIL_DEC_155 154 +#define Z_UTIL_DEC_156 155 +#define Z_UTIL_DEC_157 156 +#define Z_UTIL_DEC_158 157 +#define Z_UTIL_DEC_159 158 +#define Z_UTIL_DEC_160 159 +#define Z_UTIL_DEC_161 160 +#define Z_UTIL_DEC_162 161 +#define Z_UTIL_DEC_163 162 +#define Z_UTIL_DEC_164 163 +#define Z_UTIL_DEC_165 164 +#define Z_UTIL_DEC_166 165 +#define Z_UTIL_DEC_167 166 +#define Z_UTIL_DEC_168 167 +#define Z_UTIL_DEC_169 168 +#define Z_UTIL_DEC_170 169 +#define Z_UTIL_DEC_171 170 +#define Z_UTIL_DEC_172 171 +#define Z_UTIL_DEC_173 172 +#define Z_UTIL_DEC_174 173 +#define Z_UTIL_DEC_175 174 +#define Z_UTIL_DEC_176 175 +#define Z_UTIL_DEC_177 176 +#define Z_UTIL_DEC_178 177 +#define Z_UTIL_DEC_179 178 +#define Z_UTIL_DEC_180 179 +#define Z_UTIL_DEC_181 180 +#define Z_UTIL_DEC_182 181 +#define Z_UTIL_DEC_183 182 +#define Z_UTIL_DEC_184 183 +#define Z_UTIL_DEC_185 184 +#define Z_UTIL_DEC_186 185 +#define Z_UTIL_DEC_187 186 +#define Z_UTIL_DEC_188 187 +#define Z_UTIL_DEC_189 188 +#define Z_UTIL_DEC_190 189 +#define Z_UTIL_DEC_191 190 +#define Z_UTIL_DEC_192 191 +#define Z_UTIL_DEC_193 192 +#define Z_UTIL_DEC_194 193 +#define Z_UTIL_DEC_195 194 +#define Z_UTIL_DEC_196 195 +#define Z_UTIL_DEC_197 196 +#define Z_UTIL_DEC_198 197 +#define Z_UTIL_DEC_199 198 +#define Z_UTIL_DEC_200 199 +#define Z_UTIL_DEC_201 200 +#define Z_UTIL_DEC_202 201 +#define Z_UTIL_DEC_203 202 +#define Z_UTIL_DEC_204 203 +#define Z_UTIL_DEC_205 204 +#define Z_UTIL_DEC_206 205 +#define Z_UTIL_DEC_207 206 +#define Z_UTIL_DEC_208 207 +#define Z_UTIL_DEC_209 208 +#define Z_UTIL_DEC_210 209 +#define Z_UTIL_DEC_211 210 +#define Z_UTIL_DEC_212 211 +#define Z_UTIL_DEC_213 212 +#define Z_UTIL_DEC_214 213 +#define Z_UTIL_DEC_215 214 +#define Z_UTIL_DEC_216 215 +#define Z_UTIL_DEC_217 216 +#define Z_UTIL_DEC_218 217 +#define Z_UTIL_DEC_219 218 +#define Z_UTIL_DEC_220 219 +#define Z_UTIL_DEC_221 220 +#define Z_UTIL_DEC_222 221 +#define Z_UTIL_DEC_223 222 +#define Z_UTIL_DEC_224 223 +#define Z_UTIL_DEC_225 224 +#define Z_UTIL_DEC_226 225 +#define Z_UTIL_DEC_227 226 +#define Z_UTIL_DEC_228 227 +#define Z_UTIL_DEC_229 228 +#define Z_UTIL_DEC_230 229 +#define Z_UTIL_DEC_231 230 +#define Z_UTIL_DEC_232 231 +#define Z_UTIL_DEC_233 232 +#define Z_UTIL_DEC_234 233 +#define Z_UTIL_DEC_235 234 +#define Z_UTIL_DEC_236 235 +#define Z_UTIL_DEC_237 236 +#define Z_UTIL_DEC_238 237 +#define Z_UTIL_DEC_239 238 +#define Z_UTIL_DEC_240 239 +#define Z_UTIL_DEC_241 240 +#define Z_UTIL_DEC_242 241 +#define Z_UTIL_DEC_243 242 +#define Z_UTIL_DEC_244 243 +#define Z_UTIL_DEC_245 244 +#define Z_UTIL_DEC_246 245 +#define Z_UTIL_DEC_247 246 +#define Z_UTIL_DEC_248 247 +#define Z_UTIL_DEC_249 248 +#define Z_UTIL_DEC_250 249 +#define Z_UTIL_DEC_251 250 +#define Z_UTIL_DEC_252 251 +#define Z_UTIL_DEC_253 252 +#define Z_UTIL_DEC_254 253 +#define Z_UTIL_DEC_255 254 +#define Z_UTIL_DEC_256 255 +#define Z_UTIL_DEC_257 256 +#define Z_UTIL_DEC_258 257 +#define Z_UTIL_DEC_259 258 +#define Z_UTIL_DEC_260 259 +#define Z_UTIL_DEC_261 260 +#define Z_UTIL_DEC_262 261 +#define Z_UTIL_DEC_263 262 +#define Z_UTIL_DEC_264 263 +#define Z_UTIL_DEC_265 264 +#define Z_UTIL_DEC_266 265 +#define Z_UTIL_DEC_267 266 +#define Z_UTIL_DEC_268 267 +#define Z_UTIL_DEC_269 268 +#define Z_UTIL_DEC_270 269 +#define Z_UTIL_DEC_271 270 +#define Z_UTIL_DEC_272 271 +#define Z_UTIL_DEC_273 272 +#define Z_UTIL_DEC_274 273 +#define Z_UTIL_DEC_275 274 +#define Z_UTIL_DEC_276 275 +#define Z_UTIL_DEC_277 276 +#define Z_UTIL_DEC_278 277 +#define Z_UTIL_DEC_279 278 +#define Z_UTIL_DEC_280 279 +#define Z_UTIL_DEC_281 280 +#define Z_UTIL_DEC_282 281 +#define Z_UTIL_DEC_283 282 +#define Z_UTIL_DEC_284 283 +#define Z_UTIL_DEC_285 284 +#define Z_UTIL_DEC_286 285 +#define Z_UTIL_DEC_287 286 +#define Z_UTIL_DEC_288 287 +#define Z_UTIL_DEC_289 288 +#define Z_UTIL_DEC_290 289 +#define Z_UTIL_DEC_291 290 +#define Z_UTIL_DEC_292 291 +#define Z_UTIL_DEC_293 292 +#define Z_UTIL_DEC_294 293 +#define Z_UTIL_DEC_295 294 +#define Z_UTIL_DEC_296 295 +#define Z_UTIL_DEC_297 296 +#define Z_UTIL_DEC_298 297 +#define Z_UTIL_DEC_299 298 +#define Z_UTIL_DEC_300 299 +#define Z_UTIL_DEC_301 300 +#define Z_UTIL_DEC_302 301 +#define Z_UTIL_DEC_303 302 +#define Z_UTIL_DEC_304 303 +#define Z_UTIL_DEC_305 304 +#define Z_UTIL_DEC_306 305 +#define Z_UTIL_DEC_307 306 +#define Z_UTIL_DEC_308 307 +#define Z_UTIL_DEC_309 308 +#define Z_UTIL_DEC_310 309 +#define Z_UTIL_DEC_311 310 +#define Z_UTIL_DEC_312 311 +#define Z_UTIL_DEC_313 312 +#define Z_UTIL_DEC_314 313 +#define Z_UTIL_DEC_315 314 +#define Z_UTIL_DEC_316 315 +#define Z_UTIL_DEC_317 316 +#define Z_UTIL_DEC_318 317 +#define Z_UTIL_DEC_319 318 +#define Z_UTIL_DEC_320 319 +#define Z_UTIL_DEC_321 320 +#define Z_UTIL_DEC_322 321 +#define Z_UTIL_DEC_323 322 +#define Z_UTIL_DEC_324 323 +#define Z_UTIL_DEC_325 324 +#define Z_UTIL_DEC_326 325 +#define Z_UTIL_DEC_327 326 +#define Z_UTIL_DEC_328 327 +#define Z_UTIL_DEC_329 328 +#define Z_UTIL_DEC_330 329 +#define Z_UTIL_DEC_331 330 +#define Z_UTIL_DEC_332 331 +#define Z_UTIL_DEC_333 332 +#define Z_UTIL_DEC_334 333 +#define Z_UTIL_DEC_335 334 +#define Z_UTIL_DEC_336 335 +#define Z_UTIL_DEC_337 336 +#define Z_UTIL_DEC_338 337 +#define Z_UTIL_DEC_339 338 +#define Z_UTIL_DEC_340 339 +#define Z_UTIL_DEC_341 340 +#define Z_UTIL_DEC_342 341 +#define Z_UTIL_DEC_343 342 +#define Z_UTIL_DEC_344 343 +#define Z_UTIL_DEC_345 344 +#define Z_UTIL_DEC_346 345 +#define Z_UTIL_DEC_347 346 +#define Z_UTIL_DEC_348 347 +#define Z_UTIL_DEC_349 348 +#define Z_UTIL_DEC_350 349 +#define Z_UTIL_DEC_351 350 +#define Z_UTIL_DEC_352 351 +#define Z_UTIL_DEC_353 352 +#define Z_UTIL_DEC_354 353 +#define Z_UTIL_DEC_355 354 +#define Z_UTIL_DEC_356 355 +#define Z_UTIL_DEC_357 356 +#define Z_UTIL_DEC_358 357 +#define Z_UTIL_DEC_359 358 +#define Z_UTIL_DEC_360 359 +#define Z_UTIL_DEC_361 360 +#define Z_UTIL_DEC_362 361 +#define Z_UTIL_DEC_363 362 +#define Z_UTIL_DEC_364 363 +#define Z_UTIL_DEC_365 364 +#define Z_UTIL_DEC_366 365 +#define Z_UTIL_DEC_367 366 +#define Z_UTIL_DEC_368 367 +#define Z_UTIL_DEC_369 368 +#define Z_UTIL_DEC_370 369 +#define Z_UTIL_DEC_371 370 +#define Z_UTIL_DEC_372 371 +#define Z_UTIL_DEC_373 372 +#define Z_UTIL_DEC_374 373 +#define Z_UTIL_DEC_375 374 +#define Z_UTIL_DEC_376 375 +#define Z_UTIL_DEC_377 376 +#define Z_UTIL_DEC_378 377 +#define Z_UTIL_DEC_379 378 +#define Z_UTIL_DEC_380 379 +#define Z_UTIL_DEC_381 380 +#define Z_UTIL_DEC_382 381 +#define Z_UTIL_DEC_383 382 +#define Z_UTIL_DEC_384 383 +#define Z_UTIL_DEC_385 384 +#define Z_UTIL_DEC_386 385 +#define Z_UTIL_DEC_387 386 +#define Z_UTIL_DEC_388 387 +#define Z_UTIL_DEC_389 388 +#define Z_UTIL_DEC_390 389 +#define Z_UTIL_DEC_391 390 +#define Z_UTIL_DEC_392 391 +#define Z_UTIL_DEC_393 392 +#define Z_UTIL_DEC_394 393 +#define Z_UTIL_DEC_395 394 +#define Z_UTIL_DEC_396 395 +#define Z_UTIL_DEC_397 396 +#define Z_UTIL_DEC_398 397 +#define Z_UTIL_DEC_399 398 +#define Z_UTIL_DEC_400 399 +#define Z_UTIL_DEC_401 400 +#define Z_UTIL_DEC_402 401 +#define Z_UTIL_DEC_403 402 +#define Z_UTIL_DEC_404 403 +#define Z_UTIL_DEC_405 404 +#define Z_UTIL_DEC_406 405 +#define Z_UTIL_DEC_407 406 +#define Z_UTIL_DEC_408 407 +#define Z_UTIL_DEC_409 408 +#define Z_UTIL_DEC_410 409 +#define Z_UTIL_DEC_411 410 +#define Z_UTIL_DEC_412 411 +#define Z_UTIL_DEC_413 412 +#define Z_UTIL_DEC_414 413 +#define Z_UTIL_DEC_415 414 +#define Z_UTIL_DEC_416 415 +#define Z_UTIL_DEC_417 416 +#define Z_UTIL_DEC_418 417 +#define Z_UTIL_DEC_419 418 +#define Z_UTIL_DEC_420 419 +#define Z_UTIL_DEC_421 420 +#define Z_UTIL_DEC_422 421 +#define Z_UTIL_DEC_423 422 +#define Z_UTIL_DEC_424 423 +#define Z_UTIL_DEC_425 424 +#define Z_UTIL_DEC_426 425 +#define Z_UTIL_DEC_427 426 +#define Z_UTIL_DEC_428 427 +#define Z_UTIL_DEC_429 428 +#define Z_UTIL_DEC_430 429 +#define Z_UTIL_DEC_431 430 +#define Z_UTIL_DEC_432 431 +#define Z_UTIL_DEC_433 432 +#define Z_UTIL_DEC_434 433 +#define Z_UTIL_DEC_435 434 +#define Z_UTIL_DEC_436 435 +#define Z_UTIL_DEC_437 436 +#define Z_UTIL_DEC_438 437 +#define Z_UTIL_DEC_439 438 +#define Z_UTIL_DEC_440 439 +#define Z_UTIL_DEC_441 440 +#define Z_UTIL_DEC_442 441 +#define Z_UTIL_DEC_443 442 +#define Z_UTIL_DEC_444 443 +#define Z_UTIL_DEC_445 444 +#define Z_UTIL_DEC_446 445 +#define Z_UTIL_DEC_447 446 +#define Z_UTIL_DEC_448 447 +#define Z_UTIL_DEC_449 448 +#define Z_UTIL_DEC_450 449 +#define Z_UTIL_DEC_451 450 +#define Z_UTIL_DEC_452 451 +#define Z_UTIL_DEC_453 452 +#define Z_UTIL_DEC_454 453 +#define Z_UTIL_DEC_455 454 +#define Z_UTIL_DEC_456 455 +#define Z_UTIL_DEC_457 456 +#define Z_UTIL_DEC_458 457 +#define Z_UTIL_DEC_459 458 +#define Z_UTIL_DEC_460 459 +#define Z_UTIL_DEC_461 460 +#define Z_UTIL_DEC_462 461 +#define Z_UTIL_DEC_463 462 +#define Z_UTIL_DEC_464 463 +#define Z_UTIL_DEC_465 464 +#define Z_UTIL_DEC_466 465 +#define Z_UTIL_DEC_467 466 +#define Z_UTIL_DEC_468 467 +#define Z_UTIL_DEC_469 468 +#define Z_UTIL_DEC_470 469 +#define Z_UTIL_DEC_471 470 +#define Z_UTIL_DEC_472 471 +#define Z_UTIL_DEC_473 472 +#define Z_UTIL_DEC_474 473 +#define Z_UTIL_DEC_475 474 +#define Z_UTIL_DEC_476 475 +#define Z_UTIL_DEC_477 476 +#define Z_UTIL_DEC_478 477 +#define Z_UTIL_DEC_479 478 +#define Z_UTIL_DEC_480 479 +#define Z_UTIL_DEC_481 480 +#define Z_UTIL_DEC_482 481 +#define Z_UTIL_DEC_483 482 +#define Z_UTIL_DEC_484 483 +#define Z_UTIL_DEC_485 484 +#define Z_UTIL_DEC_486 485 +#define Z_UTIL_DEC_487 486 +#define Z_UTIL_DEC_488 487 +#define Z_UTIL_DEC_489 488 +#define Z_UTIL_DEC_490 489 +#define Z_UTIL_DEC_491 490 +#define Z_UTIL_DEC_492 491 +#define Z_UTIL_DEC_493 492 +#define Z_UTIL_DEC_494 493 +#define Z_UTIL_DEC_495 494 +#define Z_UTIL_DEC_496 495 +#define Z_UTIL_DEC_497 496 +#define Z_UTIL_DEC_498 497 +#define Z_UTIL_DEC_499 498 +#define Z_UTIL_DEC_500 499 +#define Z_UTIL_DEC_501 500 +#define Z_UTIL_DEC_502 501 +#define Z_UTIL_DEC_503 502 +#define Z_UTIL_DEC_504 503 +#define Z_UTIL_DEC_505 504 +#define Z_UTIL_DEC_506 505 +#define Z_UTIL_DEC_507 506 +#define Z_UTIL_DEC_508 507 +#define Z_UTIL_DEC_509 508 +#define Z_UTIL_DEC_510 509 +#define Z_UTIL_DEC_511 510 +#define Z_UTIL_DEC_512 511 +#define Z_UTIL_DEC_513 512 +#define Z_UTIL_DEC_514 513 +#define Z_UTIL_DEC_515 514 +#define Z_UTIL_DEC_516 515 +#define Z_UTIL_DEC_517 516 +#define Z_UTIL_DEC_518 517 +#define Z_UTIL_DEC_519 518 +#define Z_UTIL_DEC_520 519 +#define Z_UTIL_DEC_521 520 +#define Z_UTIL_DEC_522 521 +#define Z_UTIL_DEC_523 522 +#define Z_UTIL_DEC_524 523 +#define Z_UTIL_DEC_525 524 +#define Z_UTIL_DEC_526 525 +#define Z_UTIL_DEC_527 526 +#define Z_UTIL_DEC_528 527 +#define Z_UTIL_DEC_529 528 +#define Z_UTIL_DEC_530 529 +#define Z_UTIL_DEC_531 530 +#define Z_UTIL_DEC_532 531 +#define Z_UTIL_DEC_533 532 +#define Z_UTIL_DEC_534 533 +#define Z_UTIL_DEC_535 534 +#define Z_UTIL_DEC_536 535 +#define Z_UTIL_DEC_537 536 +#define Z_UTIL_DEC_538 537 +#define Z_UTIL_DEC_539 538 +#define Z_UTIL_DEC_540 539 +#define Z_UTIL_DEC_541 540 +#define Z_UTIL_DEC_542 541 +#define Z_UTIL_DEC_543 542 +#define Z_UTIL_DEC_544 543 +#define Z_UTIL_DEC_545 544 +#define Z_UTIL_DEC_546 545 +#define Z_UTIL_DEC_547 546 +#define Z_UTIL_DEC_548 547 +#define Z_UTIL_DEC_549 548 +#define Z_UTIL_DEC_550 549 +#define Z_UTIL_DEC_551 550 +#define Z_UTIL_DEC_552 551 +#define Z_UTIL_DEC_553 552 +#define Z_UTIL_DEC_554 553 +#define Z_UTIL_DEC_555 554 +#define Z_UTIL_DEC_556 555 +#define Z_UTIL_DEC_557 556 +#define Z_UTIL_DEC_558 557 +#define Z_UTIL_DEC_559 558 +#define Z_UTIL_DEC_560 559 +#define Z_UTIL_DEC_561 560 +#define Z_UTIL_DEC_562 561 +#define Z_UTIL_DEC_563 562 +#define Z_UTIL_DEC_564 563 +#define Z_UTIL_DEC_565 564 +#define Z_UTIL_DEC_566 565 +#define Z_UTIL_DEC_567 566 +#define Z_UTIL_DEC_568 567 +#define Z_UTIL_DEC_569 568 +#define Z_UTIL_DEC_570 569 +#define Z_UTIL_DEC_571 570 +#define Z_UTIL_DEC_572 571 +#define Z_UTIL_DEC_573 572 +#define Z_UTIL_DEC_574 573 +#define Z_UTIL_DEC_575 574 +#define Z_UTIL_DEC_576 575 +#define Z_UTIL_DEC_577 576 +#define Z_UTIL_DEC_578 577 +#define Z_UTIL_DEC_579 578 +#define Z_UTIL_DEC_580 579 +#define Z_UTIL_DEC_581 580 +#define Z_UTIL_DEC_582 581 +#define Z_UTIL_DEC_583 582 +#define Z_UTIL_DEC_584 583 +#define Z_UTIL_DEC_585 584 +#define Z_UTIL_DEC_586 585 +#define Z_UTIL_DEC_587 586 +#define Z_UTIL_DEC_588 587 +#define Z_UTIL_DEC_589 588 +#define Z_UTIL_DEC_590 589 +#define Z_UTIL_DEC_591 590 +#define Z_UTIL_DEC_592 591 +#define Z_UTIL_DEC_593 592 +#define Z_UTIL_DEC_594 593 +#define Z_UTIL_DEC_595 594 +#define Z_UTIL_DEC_596 595 +#define Z_UTIL_DEC_597 596 +#define Z_UTIL_DEC_598 597 +#define Z_UTIL_DEC_599 598 +#define Z_UTIL_DEC_600 599 +#define Z_UTIL_DEC_601 600 +#define Z_UTIL_DEC_602 601 +#define Z_UTIL_DEC_603 602 +#define Z_UTIL_DEC_604 603 +#define Z_UTIL_DEC_605 604 +#define Z_UTIL_DEC_606 605 +#define Z_UTIL_DEC_607 606 +#define Z_UTIL_DEC_608 607 +#define Z_UTIL_DEC_609 608 +#define Z_UTIL_DEC_610 609 +#define Z_UTIL_DEC_611 610 +#define Z_UTIL_DEC_612 611 +#define Z_UTIL_DEC_613 612 +#define Z_UTIL_DEC_614 613 +#define Z_UTIL_DEC_615 614 +#define Z_UTIL_DEC_616 615 +#define Z_UTIL_DEC_617 616 +#define Z_UTIL_DEC_618 617 +#define Z_UTIL_DEC_619 618 +#define Z_UTIL_DEC_620 619 +#define Z_UTIL_DEC_621 620 +#define Z_UTIL_DEC_622 621 +#define Z_UTIL_DEC_623 622 +#define Z_UTIL_DEC_624 623 +#define Z_UTIL_DEC_625 624 +#define Z_UTIL_DEC_626 625 +#define Z_UTIL_DEC_627 626 +#define Z_UTIL_DEC_628 627 +#define Z_UTIL_DEC_629 628 +#define Z_UTIL_DEC_630 629 +#define Z_UTIL_DEC_631 630 +#define Z_UTIL_DEC_632 631 +#define Z_UTIL_DEC_633 632 +#define Z_UTIL_DEC_634 633 +#define Z_UTIL_DEC_635 634 +#define Z_UTIL_DEC_636 635 +#define Z_UTIL_DEC_637 636 +#define Z_UTIL_DEC_638 637 +#define Z_UTIL_DEC_639 638 +#define Z_UTIL_DEC_640 639 +#define Z_UTIL_DEC_641 640 +#define Z_UTIL_DEC_642 641 +#define Z_UTIL_DEC_643 642 +#define Z_UTIL_DEC_644 643 +#define Z_UTIL_DEC_645 644 +#define Z_UTIL_DEC_646 645 +#define Z_UTIL_DEC_647 646 +#define Z_UTIL_DEC_648 647 +#define Z_UTIL_DEC_649 648 +#define Z_UTIL_DEC_650 649 +#define Z_UTIL_DEC_651 650 +#define Z_UTIL_DEC_652 651 +#define Z_UTIL_DEC_653 652 +#define Z_UTIL_DEC_654 653 +#define Z_UTIL_DEC_655 654 +#define Z_UTIL_DEC_656 655 +#define Z_UTIL_DEC_657 656 +#define Z_UTIL_DEC_658 657 +#define Z_UTIL_DEC_659 658 +#define Z_UTIL_DEC_660 659 +#define Z_UTIL_DEC_661 660 +#define Z_UTIL_DEC_662 661 +#define Z_UTIL_DEC_663 662 +#define Z_UTIL_DEC_664 663 +#define Z_UTIL_DEC_665 664 +#define Z_UTIL_DEC_666 665 +#define Z_UTIL_DEC_667 666 +#define Z_UTIL_DEC_668 667 +#define Z_UTIL_DEC_669 668 +#define Z_UTIL_DEC_670 669 +#define Z_UTIL_DEC_671 670 +#define Z_UTIL_DEC_672 671 +#define Z_UTIL_DEC_673 672 +#define Z_UTIL_DEC_674 673 +#define Z_UTIL_DEC_675 674 +#define Z_UTIL_DEC_676 675 +#define Z_UTIL_DEC_677 676 +#define Z_UTIL_DEC_678 677 +#define Z_UTIL_DEC_679 678 +#define Z_UTIL_DEC_680 679 +#define Z_UTIL_DEC_681 680 +#define Z_UTIL_DEC_682 681 +#define Z_UTIL_DEC_683 682 +#define Z_UTIL_DEC_684 683 +#define Z_UTIL_DEC_685 684 +#define Z_UTIL_DEC_686 685 +#define Z_UTIL_DEC_687 686 +#define Z_UTIL_DEC_688 687 +#define Z_UTIL_DEC_689 688 +#define Z_UTIL_DEC_690 689 +#define Z_UTIL_DEC_691 690 +#define Z_UTIL_DEC_692 691 +#define Z_UTIL_DEC_693 692 +#define Z_UTIL_DEC_694 693 +#define Z_UTIL_DEC_695 694 +#define Z_UTIL_DEC_696 695 +#define Z_UTIL_DEC_697 696 +#define Z_UTIL_DEC_698 697 +#define Z_UTIL_DEC_699 698 +#define Z_UTIL_DEC_700 699 +#define Z_UTIL_DEC_701 700 +#define Z_UTIL_DEC_702 701 +#define Z_UTIL_DEC_703 702 +#define Z_UTIL_DEC_704 703 +#define Z_UTIL_DEC_705 704 +#define Z_UTIL_DEC_706 705 +#define Z_UTIL_DEC_707 706 +#define Z_UTIL_DEC_708 707 +#define Z_UTIL_DEC_709 708 +#define Z_UTIL_DEC_710 709 +#define Z_UTIL_DEC_711 710 +#define Z_UTIL_DEC_712 711 +#define Z_UTIL_DEC_713 712 +#define Z_UTIL_DEC_714 713 +#define Z_UTIL_DEC_715 714 +#define Z_UTIL_DEC_716 715 +#define Z_UTIL_DEC_717 716 +#define Z_UTIL_DEC_718 717 +#define Z_UTIL_DEC_719 718 +#define Z_UTIL_DEC_720 719 +#define Z_UTIL_DEC_721 720 +#define Z_UTIL_DEC_722 721 +#define Z_UTIL_DEC_723 722 +#define Z_UTIL_DEC_724 723 +#define Z_UTIL_DEC_725 724 +#define Z_UTIL_DEC_726 725 +#define Z_UTIL_DEC_727 726 +#define Z_UTIL_DEC_728 727 +#define Z_UTIL_DEC_729 728 +#define Z_UTIL_DEC_730 729 +#define Z_UTIL_DEC_731 730 +#define Z_UTIL_DEC_732 731 +#define Z_UTIL_DEC_733 732 +#define Z_UTIL_DEC_734 733 +#define Z_UTIL_DEC_735 734 +#define Z_UTIL_DEC_736 735 +#define Z_UTIL_DEC_737 736 +#define Z_UTIL_DEC_738 737 +#define Z_UTIL_DEC_739 738 +#define Z_UTIL_DEC_740 739 +#define Z_UTIL_DEC_741 740 +#define Z_UTIL_DEC_742 741 +#define Z_UTIL_DEC_743 742 +#define Z_UTIL_DEC_744 743 +#define Z_UTIL_DEC_745 744 +#define Z_UTIL_DEC_746 745 +#define Z_UTIL_DEC_747 746 +#define Z_UTIL_DEC_748 747 +#define Z_UTIL_DEC_749 748 +#define Z_UTIL_DEC_750 749 +#define Z_UTIL_DEC_751 750 +#define Z_UTIL_DEC_752 751 +#define Z_UTIL_DEC_753 752 +#define Z_UTIL_DEC_754 753 +#define Z_UTIL_DEC_755 754 +#define Z_UTIL_DEC_756 755 +#define Z_UTIL_DEC_757 756 +#define Z_UTIL_DEC_758 757 +#define Z_UTIL_DEC_759 758 +#define Z_UTIL_DEC_760 759 +#define Z_UTIL_DEC_761 760 +#define Z_UTIL_DEC_762 761 +#define Z_UTIL_DEC_763 762 +#define Z_UTIL_DEC_764 763 +#define Z_UTIL_DEC_765 764 +#define Z_UTIL_DEC_766 765 +#define Z_UTIL_DEC_767 766 +#define Z_UTIL_DEC_768 767 +#define Z_UTIL_DEC_769 768 +#define Z_UTIL_DEC_770 769 +#define Z_UTIL_DEC_771 770 +#define Z_UTIL_DEC_772 771 +#define Z_UTIL_DEC_773 772 +#define Z_UTIL_DEC_774 773 +#define Z_UTIL_DEC_775 774 +#define Z_UTIL_DEC_776 775 +#define Z_UTIL_DEC_777 776 +#define Z_UTIL_DEC_778 777 +#define Z_UTIL_DEC_779 778 +#define Z_UTIL_DEC_780 779 +#define Z_UTIL_DEC_781 780 +#define Z_UTIL_DEC_782 781 +#define Z_UTIL_DEC_783 782 +#define Z_UTIL_DEC_784 783 +#define Z_UTIL_DEC_785 784 +#define Z_UTIL_DEC_786 785 +#define Z_UTIL_DEC_787 786 +#define Z_UTIL_DEC_788 787 +#define Z_UTIL_DEC_789 788 +#define Z_UTIL_DEC_790 789 +#define Z_UTIL_DEC_791 790 +#define Z_UTIL_DEC_792 791 +#define Z_UTIL_DEC_793 792 +#define Z_UTIL_DEC_794 793 +#define Z_UTIL_DEC_795 794 +#define Z_UTIL_DEC_796 795 +#define Z_UTIL_DEC_797 796 +#define Z_UTIL_DEC_798 797 +#define Z_UTIL_DEC_799 798 +#define Z_UTIL_DEC_800 799 +#define Z_UTIL_DEC_801 800 +#define Z_UTIL_DEC_802 801 +#define Z_UTIL_DEC_803 802 +#define Z_UTIL_DEC_804 803 +#define Z_UTIL_DEC_805 804 +#define Z_UTIL_DEC_806 805 +#define Z_UTIL_DEC_807 806 +#define Z_UTIL_DEC_808 807 +#define Z_UTIL_DEC_809 808 +#define Z_UTIL_DEC_810 809 +#define Z_UTIL_DEC_811 810 +#define Z_UTIL_DEC_812 811 +#define Z_UTIL_DEC_813 812 +#define Z_UTIL_DEC_814 813 +#define Z_UTIL_DEC_815 814 +#define Z_UTIL_DEC_816 815 +#define Z_UTIL_DEC_817 816 +#define Z_UTIL_DEC_818 817 +#define Z_UTIL_DEC_819 818 +#define Z_UTIL_DEC_820 819 +#define Z_UTIL_DEC_821 820 +#define Z_UTIL_DEC_822 821 +#define Z_UTIL_DEC_823 822 +#define Z_UTIL_DEC_824 823 +#define Z_UTIL_DEC_825 824 +#define Z_UTIL_DEC_826 825 +#define Z_UTIL_DEC_827 826 +#define Z_UTIL_DEC_828 827 +#define Z_UTIL_DEC_829 828 +#define Z_UTIL_DEC_830 829 +#define Z_UTIL_DEC_831 830 +#define Z_UTIL_DEC_832 831 +#define Z_UTIL_DEC_833 832 +#define Z_UTIL_DEC_834 833 +#define Z_UTIL_DEC_835 834 +#define Z_UTIL_DEC_836 835 +#define Z_UTIL_DEC_837 836 +#define Z_UTIL_DEC_838 837 +#define Z_UTIL_DEC_839 838 +#define Z_UTIL_DEC_840 839 +#define Z_UTIL_DEC_841 840 +#define Z_UTIL_DEC_842 841 +#define Z_UTIL_DEC_843 842 +#define Z_UTIL_DEC_844 843 +#define Z_UTIL_DEC_845 844 +#define Z_UTIL_DEC_846 845 +#define Z_UTIL_DEC_847 846 +#define Z_UTIL_DEC_848 847 +#define Z_UTIL_DEC_849 848 +#define Z_UTIL_DEC_850 849 +#define Z_UTIL_DEC_851 850 +#define Z_UTIL_DEC_852 851 +#define Z_UTIL_DEC_853 852 +#define Z_UTIL_DEC_854 853 +#define Z_UTIL_DEC_855 854 +#define Z_UTIL_DEC_856 855 +#define Z_UTIL_DEC_857 856 +#define Z_UTIL_DEC_858 857 +#define Z_UTIL_DEC_859 858 +#define Z_UTIL_DEC_860 859 +#define Z_UTIL_DEC_861 860 +#define Z_UTIL_DEC_862 861 +#define Z_UTIL_DEC_863 862 +#define Z_UTIL_DEC_864 863 +#define Z_UTIL_DEC_865 864 +#define Z_UTIL_DEC_866 865 +#define Z_UTIL_DEC_867 866 +#define Z_UTIL_DEC_868 867 +#define Z_UTIL_DEC_869 868 +#define Z_UTIL_DEC_870 869 +#define Z_UTIL_DEC_871 870 +#define Z_UTIL_DEC_872 871 +#define Z_UTIL_DEC_873 872 +#define Z_UTIL_DEC_874 873 +#define Z_UTIL_DEC_875 874 +#define Z_UTIL_DEC_876 875 +#define Z_UTIL_DEC_877 876 +#define Z_UTIL_DEC_878 877 +#define Z_UTIL_DEC_879 878 +#define Z_UTIL_DEC_880 879 +#define Z_UTIL_DEC_881 880 +#define Z_UTIL_DEC_882 881 +#define Z_UTIL_DEC_883 882 +#define Z_UTIL_DEC_884 883 +#define Z_UTIL_DEC_885 884 +#define Z_UTIL_DEC_886 885 +#define Z_UTIL_DEC_887 886 +#define Z_UTIL_DEC_888 887 +#define Z_UTIL_DEC_889 888 +#define Z_UTIL_DEC_890 889 +#define Z_UTIL_DEC_891 890 +#define Z_UTIL_DEC_892 891 +#define Z_UTIL_DEC_893 892 +#define Z_UTIL_DEC_894 893 +#define Z_UTIL_DEC_895 894 +#define Z_UTIL_DEC_896 895 +#define Z_UTIL_DEC_897 896 +#define Z_UTIL_DEC_898 897 +#define Z_UTIL_DEC_899 898 +#define Z_UTIL_DEC_900 899 +#define Z_UTIL_DEC_901 900 +#define Z_UTIL_DEC_902 901 +#define Z_UTIL_DEC_903 902 +#define Z_UTIL_DEC_904 903 +#define Z_UTIL_DEC_905 904 +#define Z_UTIL_DEC_906 905 +#define Z_UTIL_DEC_907 906 +#define Z_UTIL_DEC_908 907 +#define Z_UTIL_DEC_909 908 +#define Z_UTIL_DEC_910 909 +#define Z_UTIL_DEC_911 910 +#define Z_UTIL_DEC_912 911 +#define Z_UTIL_DEC_913 912 +#define Z_UTIL_DEC_914 913 +#define Z_UTIL_DEC_915 914 +#define Z_UTIL_DEC_916 915 +#define Z_UTIL_DEC_917 916 +#define Z_UTIL_DEC_918 917 +#define Z_UTIL_DEC_919 918 +#define Z_UTIL_DEC_920 919 +#define Z_UTIL_DEC_921 920 +#define Z_UTIL_DEC_922 921 +#define Z_UTIL_DEC_923 922 +#define Z_UTIL_DEC_924 923 +#define Z_UTIL_DEC_925 924 +#define Z_UTIL_DEC_926 925 +#define Z_UTIL_DEC_927 926 +#define Z_UTIL_DEC_928 927 +#define Z_UTIL_DEC_929 928 +#define Z_UTIL_DEC_930 929 +#define Z_UTIL_DEC_931 930 +#define Z_UTIL_DEC_932 931 +#define Z_UTIL_DEC_933 932 +#define Z_UTIL_DEC_934 933 +#define Z_UTIL_DEC_935 934 +#define Z_UTIL_DEC_936 935 +#define Z_UTIL_DEC_937 936 +#define Z_UTIL_DEC_938 937 +#define Z_UTIL_DEC_939 938 +#define Z_UTIL_DEC_940 939 +#define Z_UTIL_DEC_941 940 +#define Z_UTIL_DEC_942 941 +#define Z_UTIL_DEC_943 942 +#define Z_UTIL_DEC_944 943 +#define Z_UTIL_DEC_945 944 +#define Z_UTIL_DEC_946 945 +#define Z_UTIL_DEC_947 946 +#define Z_UTIL_DEC_948 947 +#define Z_UTIL_DEC_949 948 +#define Z_UTIL_DEC_950 949 +#define Z_UTIL_DEC_951 950 +#define Z_UTIL_DEC_952 951 +#define Z_UTIL_DEC_953 952 +#define Z_UTIL_DEC_954 953 +#define Z_UTIL_DEC_955 954 +#define Z_UTIL_DEC_956 955 +#define Z_UTIL_DEC_957 956 +#define Z_UTIL_DEC_958 957 +#define Z_UTIL_DEC_959 958 +#define Z_UTIL_DEC_960 959 +#define Z_UTIL_DEC_961 960 +#define Z_UTIL_DEC_962 961 +#define Z_UTIL_DEC_963 962 +#define Z_UTIL_DEC_964 963 +#define Z_UTIL_DEC_965 964 +#define Z_UTIL_DEC_966 965 +#define Z_UTIL_DEC_967 966 +#define Z_UTIL_DEC_968 967 +#define Z_UTIL_DEC_969 968 +#define Z_UTIL_DEC_970 969 +#define Z_UTIL_DEC_971 970 +#define Z_UTIL_DEC_972 971 +#define Z_UTIL_DEC_973 972 +#define Z_UTIL_DEC_974 973 +#define Z_UTIL_DEC_975 974 +#define Z_UTIL_DEC_976 975 +#define Z_UTIL_DEC_977 976 +#define Z_UTIL_DEC_978 977 +#define Z_UTIL_DEC_979 978 +#define Z_UTIL_DEC_980 979 +#define Z_UTIL_DEC_981 980 +#define Z_UTIL_DEC_982 981 +#define Z_UTIL_DEC_983 982 +#define Z_UTIL_DEC_984 983 +#define Z_UTIL_DEC_985 984 +#define Z_UTIL_DEC_986 985 +#define Z_UTIL_DEC_987 986 +#define Z_UTIL_DEC_988 987 +#define Z_UTIL_DEC_989 988 +#define Z_UTIL_DEC_990 989 +#define Z_UTIL_DEC_991 990 +#define Z_UTIL_DEC_992 991 +#define Z_UTIL_DEC_993 992 +#define Z_UTIL_DEC_994 993 +#define Z_UTIL_DEC_995 994 +#define Z_UTIL_DEC_996 995 +#define Z_UTIL_DEC_997 996 +#define Z_UTIL_DEC_998 997 +#define Z_UTIL_DEC_999 998 +#define Z_UTIL_DEC_1000 999 +#define Z_UTIL_DEC_1001 1000 +#define Z_UTIL_DEC_1002 1001 +#define Z_UTIL_DEC_1003 1002 +#define Z_UTIL_DEC_1004 1003 +#define Z_UTIL_DEC_1005 1004 +#define Z_UTIL_DEC_1006 1005 +#define Z_UTIL_DEC_1007 1006 +#define Z_UTIL_DEC_1008 1007 +#define Z_UTIL_DEC_1009 1008 +#define Z_UTIL_DEC_1010 1009 +#define Z_UTIL_DEC_1011 1010 +#define Z_UTIL_DEC_1012 1011 +#define Z_UTIL_DEC_1013 1012 +#define Z_UTIL_DEC_1014 1013 +#define Z_UTIL_DEC_1015 1014 +#define Z_UTIL_DEC_1016 1015 +#define Z_UTIL_DEC_1017 1016 +#define Z_UTIL_DEC_1018 1017 +#define Z_UTIL_DEC_1019 1018 +#define Z_UTIL_DEC_1020 1019 +#define Z_UTIL_DEC_1021 1020 +#define Z_UTIL_DEC_1022 1021 +#define Z_UTIL_DEC_1023 1022 +#define Z_UTIL_DEC_1024 1023 +#define Z_UTIL_DEC_1025 1024 +#define Z_UTIL_DEC_1026 1025 +#define Z_UTIL_DEC_1027 1026 +#define Z_UTIL_DEC_1028 1027 +#define Z_UTIL_DEC_1029 1028 +#define Z_UTIL_DEC_1030 1029 +#define Z_UTIL_DEC_1031 1030 +#define Z_UTIL_DEC_1032 1031 +#define Z_UTIL_DEC_1033 1032 +#define Z_UTIL_DEC_1034 1033 +#define Z_UTIL_DEC_1035 1034 +#define Z_UTIL_DEC_1036 1035 +#define Z_UTIL_DEC_1037 1036 +#define Z_UTIL_DEC_1038 1037 +#define Z_UTIL_DEC_1039 1038 +#define Z_UTIL_DEC_1040 1039 +#define Z_UTIL_DEC_1041 1040 +#define Z_UTIL_DEC_1042 1041 +#define Z_UTIL_DEC_1043 1042 +#define Z_UTIL_DEC_1044 1043 +#define Z_UTIL_DEC_1045 1044 +#define Z_UTIL_DEC_1046 1045 +#define Z_UTIL_DEC_1047 1046 +#define Z_UTIL_DEC_1048 1047 +#define Z_UTIL_DEC_1049 1048 +#define Z_UTIL_DEC_1050 1049 +#define Z_UTIL_DEC_1051 1050 +#define Z_UTIL_DEC_1052 1051 +#define Z_UTIL_DEC_1053 1052 +#define Z_UTIL_DEC_1054 1053 +#define Z_UTIL_DEC_1055 1054 +#define Z_UTIL_DEC_1056 1055 +#define Z_UTIL_DEC_1057 1056 +#define Z_UTIL_DEC_1058 1057 +#define Z_UTIL_DEC_1059 1058 +#define Z_UTIL_DEC_1060 1059 +#define Z_UTIL_DEC_1061 1060 +#define Z_UTIL_DEC_1062 1061 +#define Z_UTIL_DEC_1063 1062 +#define Z_UTIL_DEC_1064 1063 +#define Z_UTIL_DEC_1065 1064 +#define Z_UTIL_DEC_1066 1065 +#define Z_UTIL_DEC_1067 1066 +#define Z_UTIL_DEC_1068 1067 +#define Z_UTIL_DEC_1069 1068 +#define Z_UTIL_DEC_1070 1069 +#define Z_UTIL_DEC_1071 1070 +#define Z_UTIL_DEC_1072 1071 +#define Z_UTIL_DEC_1073 1072 +#define Z_UTIL_DEC_1074 1073 +#define Z_UTIL_DEC_1075 1074 +#define Z_UTIL_DEC_1076 1075 +#define Z_UTIL_DEC_1077 1076 +#define Z_UTIL_DEC_1078 1077 +#define Z_UTIL_DEC_1079 1078 +#define Z_UTIL_DEC_1080 1079 +#define Z_UTIL_DEC_1081 1080 +#define Z_UTIL_DEC_1082 1081 +#define Z_UTIL_DEC_1083 1082 +#define Z_UTIL_DEC_1084 1083 +#define Z_UTIL_DEC_1085 1084 +#define Z_UTIL_DEC_1086 1085 +#define Z_UTIL_DEC_1087 1086 +#define Z_UTIL_DEC_1088 1087 +#define Z_UTIL_DEC_1089 1088 +#define Z_UTIL_DEC_1090 1089 +#define Z_UTIL_DEC_1091 1090 +#define Z_UTIL_DEC_1092 1091 +#define Z_UTIL_DEC_1093 1092 +#define Z_UTIL_DEC_1094 1093 +#define Z_UTIL_DEC_1095 1094 +#define Z_UTIL_DEC_1096 1095 +#define Z_UTIL_DEC_1097 1096 +#define Z_UTIL_DEC_1098 1097 +#define Z_UTIL_DEC_1099 1098 +#define Z_UTIL_DEC_1100 1099 +#define Z_UTIL_DEC_1101 1100 +#define Z_UTIL_DEC_1102 1101 +#define Z_UTIL_DEC_1103 1102 +#define Z_UTIL_DEC_1104 1103 +#define Z_UTIL_DEC_1105 1104 +#define Z_UTIL_DEC_1106 1105 +#define Z_UTIL_DEC_1107 1106 +#define Z_UTIL_DEC_1108 1107 +#define Z_UTIL_DEC_1109 1108 +#define Z_UTIL_DEC_1110 1109 +#define Z_UTIL_DEC_1111 1110 +#define Z_UTIL_DEC_1112 1111 +#define Z_UTIL_DEC_1113 1112 +#define Z_UTIL_DEC_1114 1113 +#define Z_UTIL_DEC_1115 1114 +#define Z_UTIL_DEC_1116 1115 +#define Z_UTIL_DEC_1117 1116 +#define Z_UTIL_DEC_1118 1117 +#define Z_UTIL_DEC_1119 1118 +#define Z_UTIL_DEC_1120 1119 +#define Z_UTIL_DEC_1121 1120 +#define Z_UTIL_DEC_1122 1121 +#define Z_UTIL_DEC_1123 1122 +#define Z_UTIL_DEC_1124 1123 +#define Z_UTIL_DEC_1125 1124 +#define Z_UTIL_DEC_1126 1125 +#define Z_UTIL_DEC_1127 1126 +#define Z_UTIL_DEC_1128 1127 +#define Z_UTIL_DEC_1129 1128 +#define Z_UTIL_DEC_1130 1129 +#define Z_UTIL_DEC_1131 1130 +#define Z_UTIL_DEC_1132 1131 +#define Z_UTIL_DEC_1133 1132 +#define Z_UTIL_DEC_1134 1133 +#define Z_UTIL_DEC_1135 1134 +#define Z_UTIL_DEC_1136 1135 +#define Z_UTIL_DEC_1137 1136 +#define Z_UTIL_DEC_1138 1137 +#define Z_UTIL_DEC_1139 1138 +#define Z_UTIL_DEC_1140 1139 +#define Z_UTIL_DEC_1141 1140 +#define Z_UTIL_DEC_1142 1141 +#define Z_UTIL_DEC_1143 1142 +#define Z_UTIL_DEC_1144 1143 +#define Z_UTIL_DEC_1145 1144 +#define Z_UTIL_DEC_1146 1145 +#define Z_UTIL_DEC_1147 1146 +#define Z_UTIL_DEC_1148 1147 +#define Z_UTIL_DEC_1149 1148 +#define Z_UTIL_DEC_1150 1149 +#define Z_UTIL_DEC_1151 1150 +#define Z_UTIL_DEC_1152 1151 +#define Z_UTIL_DEC_1153 1152 +#define Z_UTIL_DEC_1154 1153 +#define Z_UTIL_DEC_1155 1154 +#define Z_UTIL_DEC_1156 1155 +#define Z_UTIL_DEC_1157 1156 +#define Z_UTIL_DEC_1158 1157 +#define Z_UTIL_DEC_1159 1158 +#define Z_UTIL_DEC_1160 1159 +#define Z_UTIL_DEC_1161 1160 +#define Z_UTIL_DEC_1162 1161 +#define Z_UTIL_DEC_1163 1162 +#define Z_UTIL_DEC_1164 1163 +#define Z_UTIL_DEC_1165 1164 +#define Z_UTIL_DEC_1166 1165 +#define Z_UTIL_DEC_1167 1166 +#define Z_UTIL_DEC_1168 1167 +#define Z_UTIL_DEC_1169 1168 +#define Z_UTIL_DEC_1170 1169 +#define Z_UTIL_DEC_1171 1170 +#define Z_UTIL_DEC_1172 1171 +#define Z_UTIL_DEC_1173 1172 +#define Z_UTIL_DEC_1174 1173 +#define Z_UTIL_DEC_1175 1174 +#define Z_UTIL_DEC_1176 1175 +#define Z_UTIL_DEC_1177 1176 +#define Z_UTIL_DEC_1178 1177 +#define Z_UTIL_DEC_1179 1178 +#define Z_UTIL_DEC_1180 1179 +#define Z_UTIL_DEC_1181 1180 +#define Z_UTIL_DEC_1182 1181 +#define Z_UTIL_DEC_1183 1182 +#define Z_UTIL_DEC_1184 1183 +#define Z_UTIL_DEC_1185 1184 +#define Z_UTIL_DEC_1186 1185 +#define Z_UTIL_DEC_1187 1186 +#define Z_UTIL_DEC_1188 1187 +#define Z_UTIL_DEC_1189 1188 +#define Z_UTIL_DEC_1190 1189 +#define Z_UTIL_DEC_1191 1190 +#define Z_UTIL_DEC_1192 1191 +#define Z_UTIL_DEC_1193 1192 +#define Z_UTIL_DEC_1194 1193 +#define Z_UTIL_DEC_1195 1194 +#define Z_UTIL_DEC_1196 1195 +#define Z_UTIL_DEC_1197 1196 +#define Z_UTIL_DEC_1198 1197 +#define Z_UTIL_DEC_1199 1198 +#define Z_UTIL_DEC_1200 1199 +#define Z_UTIL_DEC_1201 1200 +#define Z_UTIL_DEC_1202 1201 +#define Z_UTIL_DEC_1203 1202 +#define Z_UTIL_DEC_1204 1203 +#define Z_UTIL_DEC_1205 1204 +#define Z_UTIL_DEC_1206 1205 +#define Z_UTIL_DEC_1207 1206 +#define Z_UTIL_DEC_1208 1207 +#define Z_UTIL_DEC_1209 1208 +#define Z_UTIL_DEC_1210 1209 +#define Z_UTIL_DEC_1211 1210 +#define Z_UTIL_DEC_1212 1211 +#define Z_UTIL_DEC_1213 1212 +#define Z_UTIL_DEC_1214 1213 +#define Z_UTIL_DEC_1215 1214 +#define Z_UTIL_DEC_1216 1215 +#define Z_UTIL_DEC_1217 1216 +#define Z_UTIL_DEC_1218 1217 +#define Z_UTIL_DEC_1219 1218 +#define Z_UTIL_DEC_1220 1219 +#define Z_UTIL_DEC_1221 1220 +#define Z_UTIL_DEC_1222 1221 +#define Z_UTIL_DEC_1223 1222 +#define Z_UTIL_DEC_1224 1223 +#define Z_UTIL_DEC_1225 1224 +#define Z_UTIL_DEC_1226 1225 +#define Z_UTIL_DEC_1227 1226 +#define Z_UTIL_DEC_1228 1227 +#define Z_UTIL_DEC_1229 1228 +#define Z_UTIL_DEC_1230 1229 +#define Z_UTIL_DEC_1231 1230 +#define Z_UTIL_DEC_1232 1231 +#define Z_UTIL_DEC_1233 1232 +#define Z_UTIL_DEC_1234 1233 +#define Z_UTIL_DEC_1235 1234 +#define Z_UTIL_DEC_1236 1235 +#define Z_UTIL_DEC_1237 1236 +#define Z_UTIL_DEC_1238 1237 +#define Z_UTIL_DEC_1239 1238 +#define Z_UTIL_DEC_1240 1239 +#define Z_UTIL_DEC_1241 1240 +#define Z_UTIL_DEC_1242 1241 +#define Z_UTIL_DEC_1243 1242 +#define Z_UTIL_DEC_1244 1243 +#define Z_UTIL_DEC_1245 1244 +#define Z_UTIL_DEC_1246 1245 +#define Z_UTIL_DEC_1247 1246 +#define Z_UTIL_DEC_1248 1247 +#define Z_UTIL_DEC_1249 1248 +#define Z_UTIL_DEC_1250 1249 +#define Z_UTIL_DEC_1251 1250 +#define Z_UTIL_DEC_1252 1251 +#define Z_UTIL_DEC_1253 1252 +#define Z_UTIL_DEC_1254 1253 +#define Z_UTIL_DEC_1255 1254 +#define Z_UTIL_DEC_1256 1255 +#define Z_UTIL_DEC_1257 1256 +#define Z_UTIL_DEC_1258 1257 +#define Z_UTIL_DEC_1259 1258 +#define Z_UTIL_DEC_1260 1259 +#define Z_UTIL_DEC_1261 1260 +#define Z_UTIL_DEC_1262 1261 +#define Z_UTIL_DEC_1263 1262 +#define Z_UTIL_DEC_1264 1263 +#define Z_UTIL_DEC_1265 1264 +#define Z_UTIL_DEC_1266 1265 +#define Z_UTIL_DEC_1267 1266 +#define Z_UTIL_DEC_1268 1267 +#define Z_UTIL_DEC_1269 1268 +#define Z_UTIL_DEC_1270 1269 +#define Z_UTIL_DEC_1271 1270 +#define Z_UTIL_DEC_1272 1271 +#define Z_UTIL_DEC_1273 1272 +#define Z_UTIL_DEC_1274 1273 +#define Z_UTIL_DEC_1275 1274 +#define Z_UTIL_DEC_1276 1275 +#define Z_UTIL_DEC_1277 1276 +#define Z_UTIL_DEC_1278 1277 +#define Z_UTIL_DEC_1279 1278 +#define Z_UTIL_DEC_1280 1279 +#define Z_UTIL_DEC_1281 1280 +#define Z_UTIL_DEC_1282 1281 +#define Z_UTIL_DEC_1283 1282 +#define Z_UTIL_DEC_1284 1283 +#define Z_UTIL_DEC_1285 1284 +#define Z_UTIL_DEC_1286 1285 +#define Z_UTIL_DEC_1287 1286 +#define Z_UTIL_DEC_1288 1287 +#define Z_UTIL_DEC_1289 1288 +#define Z_UTIL_DEC_1290 1289 +#define Z_UTIL_DEC_1291 1290 +#define Z_UTIL_DEC_1292 1291 +#define Z_UTIL_DEC_1293 1292 +#define Z_UTIL_DEC_1294 1293 +#define Z_UTIL_DEC_1295 1294 +#define Z_UTIL_DEC_1296 1295 +#define Z_UTIL_DEC_1297 1296 +#define Z_UTIL_DEC_1298 1297 +#define Z_UTIL_DEC_1299 1298 +#define Z_UTIL_DEC_1300 1299 +#define Z_UTIL_DEC_1301 1300 +#define Z_UTIL_DEC_1302 1301 +#define Z_UTIL_DEC_1303 1302 +#define Z_UTIL_DEC_1304 1303 +#define Z_UTIL_DEC_1305 1304 +#define Z_UTIL_DEC_1306 1305 +#define Z_UTIL_DEC_1307 1306 +#define Z_UTIL_DEC_1308 1307 +#define Z_UTIL_DEC_1309 1308 +#define Z_UTIL_DEC_1310 1309 +#define Z_UTIL_DEC_1311 1310 +#define Z_UTIL_DEC_1312 1311 +#define Z_UTIL_DEC_1313 1312 +#define Z_UTIL_DEC_1314 1313 +#define Z_UTIL_DEC_1315 1314 +#define Z_UTIL_DEC_1316 1315 +#define Z_UTIL_DEC_1317 1316 +#define Z_UTIL_DEC_1318 1317 +#define Z_UTIL_DEC_1319 1318 +#define Z_UTIL_DEC_1320 1319 +#define Z_UTIL_DEC_1321 1320 +#define Z_UTIL_DEC_1322 1321 +#define Z_UTIL_DEC_1323 1322 +#define Z_UTIL_DEC_1324 1323 +#define Z_UTIL_DEC_1325 1324 +#define Z_UTIL_DEC_1326 1325 +#define Z_UTIL_DEC_1327 1326 +#define Z_UTIL_DEC_1328 1327 +#define Z_UTIL_DEC_1329 1328 +#define Z_UTIL_DEC_1330 1329 +#define Z_UTIL_DEC_1331 1330 +#define Z_UTIL_DEC_1332 1331 +#define Z_UTIL_DEC_1333 1332 +#define Z_UTIL_DEC_1334 1333 +#define Z_UTIL_DEC_1335 1334 +#define Z_UTIL_DEC_1336 1335 +#define Z_UTIL_DEC_1337 1336 +#define Z_UTIL_DEC_1338 1337 +#define Z_UTIL_DEC_1339 1338 +#define Z_UTIL_DEC_1340 1339 +#define Z_UTIL_DEC_1341 1340 +#define Z_UTIL_DEC_1342 1341 +#define Z_UTIL_DEC_1343 1342 +#define Z_UTIL_DEC_1344 1343 +#define Z_UTIL_DEC_1345 1344 +#define Z_UTIL_DEC_1346 1345 +#define Z_UTIL_DEC_1347 1346 +#define Z_UTIL_DEC_1348 1347 +#define Z_UTIL_DEC_1349 1348 +#define Z_UTIL_DEC_1350 1349 +#define Z_UTIL_DEC_1351 1350 +#define Z_UTIL_DEC_1352 1351 +#define Z_UTIL_DEC_1353 1352 +#define Z_UTIL_DEC_1354 1353 +#define Z_UTIL_DEC_1355 1354 +#define Z_UTIL_DEC_1356 1355 +#define Z_UTIL_DEC_1357 1356 +#define Z_UTIL_DEC_1358 1357 +#define Z_UTIL_DEC_1359 1358 +#define Z_UTIL_DEC_1360 1359 +#define Z_UTIL_DEC_1361 1360 +#define Z_UTIL_DEC_1362 1361 +#define Z_UTIL_DEC_1363 1362 +#define Z_UTIL_DEC_1364 1363 +#define Z_UTIL_DEC_1365 1364 +#define Z_UTIL_DEC_1366 1365 +#define Z_UTIL_DEC_1367 1366 +#define Z_UTIL_DEC_1368 1367 +#define Z_UTIL_DEC_1369 1368 +#define Z_UTIL_DEC_1370 1369 +#define Z_UTIL_DEC_1371 1370 +#define Z_UTIL_DEC_1372 1371 +#define Z_UTIL_DEC_1373 1372 +#define Z_UTIL_DEC_1374 1373 +#define Z_UTIL_DEC_1375 1374 +#define Z_UTIL_DEC_1376 1375 +#define Z_UTIL_DEC_1377 1376 +#define Z_UTIL_DEC_1378 1377 +#define Z_UTIL_DEC_1379 1378 +#define Z_UTIL_DEC_1380 1379 +#define Z_UTIL_DEC_1381 1380 +#define Z_UTIL_DEC_1382 1381 +#define Z_UTIL_DEC_1383 1382 +#define Z_UTIL_DEC_1384 1383 +#define Z_UTIL_DEC_1385 1384 +#define Z_UTIL_DEC_1386 1385 +#define Z_UTIL_DEC_1387 1386 +#define Z_UTIL_DEC_1388 1387 +#define Z_UTIL_DEC_1389 1388 +#define Z_UTIL_DEC_1390 1389 +#define Z_UTIL_DEC_1391 1390 +#define Z_UTIL_DEC_1392 1391 +#define Z_UTIL_DEC_1393 1392 +#define Z_UTIL_DEC_1394 1393 +#define Z_UTIL_DEC_1395 1394 +#define Z_UTIL_DEC_1396 1395 +#define Z_UTIL_DEC_1397 1396 +#define Z_UTIL_DEC_1398 1397 +#define Z_UTIL_DEC_1399 1398 +#define Z_UTIL_DEC_1400 1399 +#define Z_UTIL_DEC_1401 1400 +#define Z_UTIL_DEC_1402 1401 +#define Z_UTIL_DEC_1403 1402 +#define Z_UTIL_DEC_1404 1403 +#define Z_UTIL_DEC_1405 1404 +#define Z_UTIL_DEC_1406 1405 +#define Z_UTIL_DEC_1407 1406 +#define Z_UTIL_DEC_1408 1407 +#define Z_UTIL_DEC_1409 1408 +#define Z_UTIL_DEC_1410 1409 +#define Z_UTIL_DEC_1411 1410 +#define Z_UTIL_DEC_1412 1411 +#define Z_UTIL_DEC_1413 1412 +#define Z_UTIL_DEC_1414 1413 +#define Z_UTIL_DEC_1415 1414 +#define Z_UTIL_DEC_1416 1415 +#define Z_UTIL_DEC_1417 1416 +#define Z_UTIL_DEC_1418 1417 +#define Z_UTIL_DEC_1419 1418 +#define Z_UTIL_DEC_1420 1419 +#define Z_UTIL_DEC_1421 1420 +#define Z_UTIL_DEC_1422 1421 +#define Z_UTIL_DEC_1423 1422 +#define Z_UTIL_DEC_1424 1423 +#define Z_UTIL_DEC_1425 1424 +#define Z_UTIL_DEC_1426 1425 +#define Z_UTIL_DEC_1427 1426 +#define Z_UTIL_DEC_1428 1427 +#define Z_UTIL_DEC_1429 1428 +#define Z_UTIL_DEC_1430 1429 +#define Z_UTIL_DEC_1431 1430 +#define Z_UTIL_DEC_1432 1431 +#define Z_UTIL_DEC_1433 1432 +#define Z_UTIL_DEC_1434 1433 +#define Z_UTIL_DEC_1435 1434 +#define Z_UTIL_DEC_1436 1435 +#define Z_UTIL_DEC_1437 1436 +#define Z_UTIL_DEC_1438 1437 +#define Z_UTIL_DEC_1439 1438 +#define Z_UTIL_DEC_1440 1439 +#define Z_UTIL_DEC_1441 1440 +#define Z_UTIL_DEC_1442 1441 +#define Z_UTIL_DEC_1443 1442 +#define Z_UTIL_DEC_1444 1443 +#define Z_UTIL_DEC_1445 1444 +#define Z_UTIL_DEC_1446 1445 +#define Z_UTIL_DEC_1447 1446 +#define Z_UTIL_DEC_1448 1447 +#define Z_UTIL_DEC_1449 1448 +#define Z_UTIL_DEC_1450 1449 +#define Z_UTIL_DEC_1451 1450 +#define Z_UTIL_DEC_1452 1451 +#define Z_UTIL_DEC_1453 1452 +#define Z_UTIL_DEC_1454 1453 +#define Z_UTIL_DEC_1455 1454 +#define Z_UTIL_DEC_1456 1455 +#define Z_UTIL_DEC_1457 1456 +#define Z_UTIL_DEC_1458 1457 +#define Z_UTIL_DEC_1459 1458 +#define Z_UTIL_DEC_1460 1459 +#define Z_UTIL_DEC_1461 1460 +#define Z_UTIL_DEC_1462 1461 +#define Z_UTIL_DEC_1463 1462 +#define Z_UTIL_DEC_1464 1463 +#define Z_UTIL_DEC_1465 1464 +#define Z_UTIL_DEC_1466 1465 +#define Z_UTIL_DEC_1467 1466 +#define Z_UTIL_DEC_1468 1467 +#define Z_UTIL_DEC_1469 1468 +#define Z_UTIL_DEC_1470 1469 +#define Z_UTIL_DEC_1471 1470 +#define Z_UTIL_DEC_1472 1471 +#define Z_UTIL_DEC_1473 1472 +#define Z_UTIL_DEC_1474 1473 +#define Z_UTIL_DEC_1475 1474 +#define Z_UTIL_DEC_1476 1475 +#define Z_UTIL_DEC_1477 1476 +#define Z_UTIL_DEC_1478 1477 +#define Z_UTIL_DEC_1479 1478 +#define Z_UTIL_DEC_1480 1479 +#define Z_UTIL_DEC_1481 1480 +#define Z_UTIL_DEC_1482 1481 +#define Z_UTIL_DEC_1483 1482 +#define Z_UTIL_DEC_1484 1483 +#define Z_UTIL_DEC_1485 1484 +#define Z_UTIL_DEC_1486 1485 +#define Z_UTIL_DEC_1487 1486 +#define Z_UTIL_DEC_1488 1487 +#define Z_UTIL_DEC_1489 1488 +#define Z_UTIL_DEC_1490 1489 +#define Z_UTIL_DEC_1491 1490 +#define Z_UTIL_DEC_1492 1491 +#define Z_UTIL_DEC_1493 1492 +#define Z_UTIL_DEC_1494 1493 +#define Z_UTIL_DEC_1495 1494 +#define Z_UTIL_DEC_1496 1495 +#define Z_UTIL_DEC_1497 1496 +#define Z_UTIL_DEC_1498 1497 +#define Z_UTIL_DEC_1499 1498 +#define Z_UTIL_DEC_1500 1499 +#define Z_UTIL_DEC_1501 1500 +#define Z_UTIL_DEC_1502 1501 +#define Z_UTIL_DEC_1503 1502 +#define Z_UTIL_DEC_1504 1503 +#define Z_UTIL_DEC_1505 1504 +#define Z_UTIL_DEC_1506 1505 +#define Z_UTIL_DEC_1507 1506 +#define Z_UTIL_DEC_1508 1507 +#define Z_UTIL_DEC_1509 1508 +#define Z_UTIL_DEC_1510 1509 +#define Z_UTIL_DEC_1511 1510 +#define Z_UTIL_DEC_1512 1511 +#define Z_UTIL_DEC_1513 1512 +#define Z_UTIL_DEC_1514 1513 +#define Z_UTIL_DEC_1515 1514 +#define Z_UTIL_DEC_1516 1515 +#define Z_UTIL_DEC_1517 1516 +#define Z_UTIL_DEC_1518 1517 +#define Z_UTIL_DEC_1519 1518 +#define Z_UTIL_DEC_1520 1519 +#define Z_UTIL_DEC_1521 1520 +#define Z_UTIL_DEC_1522 1521 +#define Z_UTIL_DEC_1523 1522 +#define Z_UTIL_DEC_1524 1523 +#define Z_UTIL_DEC_1525 1524 +#define Z_UTIL_DEC_1526 1525 +#define Z_UTIL_DEC_1527 1526 +#define Z_UTIL_DEC_1528 1527 +#define Z_UTIL_DEC_1529 1528 +#define Z_UTIL_DEC_1530 1529 +#define Z_UTIL_DEC_1531 1530 +#define Z_UTIL_DEC_1532 1531 +#define Z_UTIL_DEC_1533 1532 +#define Z_UTIL_DEC_1534 1533 +#define Z_UTIL_DEC_1535 1534 +#define Z_UTIL_DEC_1536 1535 +#define Z_UTIL_DEC_1537 1536 +#define Z_UTIL_DEC_1538 1537 +#define Z_UTIL_DEC_1539 1538 +#define Z_UTIL_DEC_1540 1539 +#define Z_UTIL_DEC_1541 1540 +#define Z_UTIL_DEC_1542 1541 +#define Z_UTIL_DEC_1543 1542 +#define Z_UTIL_DEC_1544 1543 +#define Z_UTIL_DEC_1545 1544 +#define Z_UTIL_DEC_1546 1545 +#define Z_UTIL_DEC_1547 1546 +#define Z_UTIL_DEC_1548 1547 +#define Z_UTIL_DEC_1549 1548 +#define Z_UTIL_DEC_1550 1549 +#define Z_UTIL_DEC_1551 1550 +#define Z_UTIL_DEC_1552 1551 +#define Z_UTIL_DEC_1553 1552 +#define Z_UTIL_DEC_1554 1553 +#define Z_UTIL_DEC_1555 1554 +#define Z_UTIL_DEC_1556 1555 +#define Z_UTIL_DEC_1557 1556 +#define Z_UTIL_DEC_1558 1557 +#define Z_UTIL_DEC_1559 1558 +#define Z_UTIL_DEC_1560 1559 +#define Z_UTIL_DEC_1561 1560 +#define Z_UTIL_DEC_1562 1561 +#define Z_UTIL_DEC_1563 1562 +#define Z_UTIL_DEC_1564 1563 +#define Z_UTIL_DEC_1565 1564 +#define Z_UTIL_DEC_1566 1565 +#define Z_UTIL_DEC_1567 1566 +#define Z_UTIL_DEC_1568 1567 +#define Z_UTIL_DEC_1569 1568 +#define Z_UTIL_DEC_1570 1569 +#define Z_UTIL_DEC_1571 1570 +#define Z_UTIL_DEC_1572 1571 +#define Z_UTIL_DEC_1573 1572 +#define Z_UTIL_DEC_1574 1573 +#define Z_UTIL_DEC_1575 1574 +#define Z_UTIL_DEC_1576 1575 +#define Z_UTIL_DEC_1577 1576 +#define Z_UTIL_DEC_1578 1577 +#define Z_UTIL_DEC_1579 1578 +#define Z_UTIL_DEC_1580 1579 +#define Z_UTIL_DEC_1581 1580 +#define Z_UTIL_DEC_1582 1581 +#define Z_UTIL_DEC_1583 1582 +#define Z_UTIL_DEC_1584 1583 +#define Z_UTIL_DEC_1585 1584 +#define Z_UTIL_DEC_1586 1585 +#define Z_UTIL_DEC_1587 1586 +#define Z_UTIL_DEC_1588 1587 +#define Z_UTIL_DEC_1589 1588 +#define Z_UTIL_DEC_1590 1589 +#define Z_UTIL_DEC_1591 1590 +#define Z_UTIL_DEC_1592 1591 +#define Z_UTIL_DEC_1593 1592 +#define Z_UTIL_DEC_1594 1593 +#define Z_UTIL_DEC_1595 1594 +#define Z_UTIL_DEC_1596 1595 +#define Z_UTIL_DEC_1597 1596 +#define Z_UTIL_DEC_1598 1597 +#define Z_UTIL_DEC_1599 1598 +#define Z_UTIL_DEC_1600 1599 +#define Z_UTIL_DEC_1601 1600 +#define Z_UTIL_DEC_1602 1601 +#define Z_UTIL_DEC_1603 1602 +#define Z_UTIL_DEC_1604 1603 +#define Z_UTIL_DEC_1605 1604 +#define Z_UTIL_DEC_1606 1605 +#define Z_UTIL_DEC_1607 1606 +#define Z_UTIL_DEC_1608 1607 +#define Z_UTIL_DEC_1609 1608 +#define Z_UTIL_DEC_1610 1609 +#define Z_UTIL_DEC_1611 1610 +#define Z_UTIL_DEC_1612 1611 +#define Z_UTIL_DEC_1613 1612 +#define Z_UTIL_DEC_1614 1613 +#define Z_UTIL_DEC_1615 1614 +#define Z_UTIL_DEC_1616 1615 +#define Z_UTIL_DEC_1617 1616 +#define Z_UTIL_DEC_1618 1617 +#define Z_UTIL_DEC_1619 1618 +#define Z_UTIL_DEC_1620 1619 +#define Z_UTIL_DEC_1621 1620 +#define Z_UTIL_DEC_1622 1621 +#define Z_UTIL_DEC_1623 1622 +#define Z_UTIL_DEC_1624 1623 +#define Z_UTIL_DEC_1625 1624 +#define Z_UTIL_DEC_1626 1625 +#define Z_UTIL_DEC_1627 1626 +#define Z_UTIL_DEC_1628 1627 +#define Z_UTIL_DEC_1629 1628 +#define Z_UTIL_DEC_1630 1629 +#define Z_UTIL_DEC_1631 1630 +#define Z_UTIL_DEC_1632 1631 +#define Z_UTIL_DEC_1633 1632 +#define Z_UTIL_DEC_1634 1633 +#define Z_UTIL_DEC_1635 1634 +#define Z_UTIL_DEC_1636 1635 +#define Z_UTIL_DEC_1637 1636 +#define Z_UTIL_DEC_1638 1637 +#define Z_UTIL_DEC_1639 1638 +#define Z_UTIL_DEC_1640 1639 +#define Z_UTIL_DEC_1641 1640 +#define Z_UTIL_DEC_1642 1641 +#define Z_UTIL_DEC_1643 1642 +#define Z_UTIL_DEC_1644 1643 +#define Z_UTIL_DEC_1645 1644 +#define Z_UTIL_DEC_1646 1645 +#define Z_UTIL_DEC_1647 1646 +#define Z_UTIL_DEC_1648 1647 +#define Z_UTIL_DEC_1649 1648 +#define Z_UTIL_DEC_1650 1649 +#define Z_UTIL_DEC_1651 1650 +#define Z_UTIL_DEC_1652 1651 +#define Z_UTIL_DEC_1653 1652 +#define Z_UTIL_DEC_1654 1653 +#define Z_UTIL_DEC_1655 1654 +#define Z_UTIL_DEC_1656 1655 +#define Z_UTIL_DEC_1657 1656 +#define Z_UTIL_DEC_1658 1657 +#define Z_UTIL_DEC_1659 1658 +#define Z_UTIL_DEC_1660 1659 +#define Z_UTIL_DEC_1661 1660 +#define Z_UTIL_DEC_1662 1661 +#define Z_UTIL_DEC_1663 1662 +#define Z_UTIL_DEC_1664 1663 +#define Z_UTIL_DEC_1665 1664 +#define Z_UTIL_DEC_1666 1665 +#define Z_UTIL_DEC_1667 1666 +#define Z_UTIL_DEC_1668 1667 +#define Z_UTIL_DEC_1669 1668 +#define Z_UTIL_DEC_1670 1669 +#define Z_UTIL_DEC_1671 1670 +#define Z_UTIL_DEC_1672 1671 +#define Z_UTIL_DEC_1673 1672 +#define Z_UTIL_DEC_1674 1673 +#define Z_UTIL_DEC_1675 1674 +#define Z_UTIL_DEC_1676 1675 +#define Z_UTIL_DEC_1677 1676 +#define Z_UTIL_DEC_1678 1677 +#define Z_UTIL_DEC_1679 1678 +#define Z_UTIL_DEC_1680 1679 +#define Z_UTIL_DEC_1681 1680 +#define Z_UTIL_DEC_1682 1681 +#define Z_UTIL_DEC_1683 1682 +#define Z_UTIL_DEC_1684 1683 +#define Z_UTIL_DEC_1685 1684 +#define Z_UTIL_DEC_1686 1685 +#define Z_UTIL_DEC_1687 1686 +#define Z_UTIL_DEC_1688 1687 +#define Z_UTIL_DEC_1689 1688 +#define Z_UTIL_DEC_1690 1689 +#define Z_UTIL_DEC_1691 1690 +#define Z_UTIL_DEC_1692 1691 +#define Z_UTIL_DEC_1693 1692 +#define Z_UTIL_DEC_1694 1693 +#define Z_UTIL_DEC_1695 1694 +#define Z_UTIL_DEC_1696 1695 +#define Z_UTIL_DEC_1697 1696 +#define Z_UTIL_DEC_1698 1697 +#define Z_UTIL_DEC_1699 1698 +#define Z_UTIL_DEC_1700 1699 +#define Z_UTIL_DEC_1701 1700 +#define Z_UTIL_DEC_1702 1701 +#define Z_UTIL_DEC_1703 1702 +#define Z_UTIL_DEC_1704 1703 +#define Z_UTIL_DEC_1705 1704 +#define Z_UTIL_DEC_1706 1705 +#define Z_UTIL_DEC_1707 1706 +#define Z_UTIL_DEC_1708 1707 +#define Z_UTIL_DEC_1709 1708 +#define Z_UTIL_DEC_1710 1709 +#define Z_UTIL_DEC_1711 1710 +#define Z_UTIL_DEC_1712 1711 +#define Z_UTIL_DEC_1713 1712 +#define Z_UTIL_DEC_1714 1713 +#define Z_UTIL_DEC_1715 1714 +#define Z_UTIL_DEC_1716 1715 +#define Z_UTIL_DEC_1717 1716 +#define Z_UTIL_DEC_1718 1717 +#define Z_UTIL_DEC_1719 1718 +#define Z_UTIL_DEC_1720 1719 +#define Z_UTIL_DEC_1721 1720 +#define Z_UTIL_DEC_1722 1721 +#define Z_UTIL_DEC_1723 1722 +#define Z_UTIL_DEC_1724 1723 +#define Z_UTIL_DEC_1725 1724 +#define Z_UTIL_DEC_1726 1725 +#define Z_UTIL_DEC_1727 1726 +#define Z_UTIL_DEC_1728 1727 +#define Z_UTIL_DEC_1729 1728 +#define Z_UTIL_DEC_1730 1729 +#define Z_UTIL_DEC_1731 1730 +#define Z_UTIL_DEC_1732 1731 +#define Z_UTIL_DEC_1733 1732 +#define Z_UTIL_DEC_1734 1733 +#define Z_UTIL_DEC_1735 1734 +#define Z_UTIL_DEC_1736 1735 +#define Z_UTIL_DEC_1737 1736 +#define Z_UTIL_DEC_1738 1737 +#define Z_UTIL_DEC_1739 1738 +#define Z_UTIL_DEC_1740 1739 +#define Z_UTIL_DEC_1741 1740 +#define Z_UTIL_DEC_1742 1741 +#define Z_UTIL_DEC_1743 1742 +#define Z_UTIL_DEC_1744 1743 +#define Z_UTIL_DEC_1745 1744 +#define Z_UTIL_DEC_1746 1745 +#define Z_UTIL_DEC_1747 1746 +#define Z_UTIL_DEC_1748 1747 +#define Z_UTIL_DEC_1749 1748 +#define Z_UTIL_DEC_1750 1749 +#define Z_UTIL_DEC_1751 1750 +#define Z_UTIL_DEC_1752 1751 +#define Z_UTIL_DEC_1753 1752 +#define Z_UTIL_DEC_1754 1753 +#define Z_UTIL_DEC_1755 1754 +#define Z_UTIL_DEC_1756 1755 +#define Z_UTIL_DEC_1757 1756 +#define Z_UTIL_DEC_1758 1757 +#define Z_UTIL_DEC_1759 1758 +#define Z_UTIL_DEC_1760 1759 +#define Z_UTIL_DEC_1761 1760 +#define Z_UTIL_DEC_1762 1761 +#define Z_UTIL_DEC_1763 1762 +#define Z_UTIL_DEC_1764 1763 +#define Z_UTIL_DEC_1765 1764 +#define Z_UTIL_DEC_1766 1765 +#define Z_UTIL_DEC_1767 1766 +#define Z_UTIL_DEC_1768 1767 +#define Z_UTIL_DEC_1769 1768 +#define Z_UTIL_DEC_1770 1769 +#define Z_UTIL_DEC_1771 1770 +#define Z_UTIL_DEC_1772 1771 +#define Z_UTIL_DEC_1773 1772 +#define Z_UTIL_DEC_1774 1773 +#define Z_UTIL_DEC_1775 1774 +#define Z_UTIL_DEC_1776 1775 +#define Z_UTIL_DEC_1777 1776 +#define Z_UTIL_DEC_1778 1777 +#define Z_UTIL_DEC_1779 1778 +#define Z_UTIL_DEC_1780 1779 +#define Z_UTIL_DEC_1781 1780 +#define Z_UTIL_DEC_1782 1781 +#define Z_UTIL_DEC_1783 1782 +#define Z_UTIL_DEC_1784 1783 +#define Z_UTIL_DEC_1785 1784 +#define Z_UTIL_DEC_1786 1785 +#define Z_UTIL_DEC_1787 1786 +#define Z_UTIL_DEC_1788 1787 +#define Z_UTIL_DEC_1789 1788 +#define Z_UTIL_DEC_1790 1789 +#define Z_UTIL_DEC_1791 1790 +#define Z_UTIL_DEC_1792 1791 +#define Z_UTIL_DEC_1793 1792 +#define Z_UTIL_DEC_1794 1793 +#define Z_UTIL_DEC_1795 1794 +#define Z_UTIL_DEC_1796 1795 +#define Z_UTIL_DEC_1797 1796 +#define Z_UTIL_DEC_1798 1797 +#define Z_UTIL_DEC_1799 1798 +#define Z_UTIL_DEC_1800 1799 +#define Z_UTIL_DEC_1801 1800 +#define Z_UTIL_DEC_1802 1801 +#define Z_UTIL_DEC_1803 1802 +#define Z_UTIL_DEC_1804 1803 +#define Z_UTIL_DEC_1805 1804 +#define Z_UTIL_DEC_1806 1805 +#define Z_UTIL_DEC_1807 1806 +#define Z_UTIL_DEC_1808 1807 +#define Z_UTIL_DEC_1809 1808 +#define Z_UTIL_DEC_1810 1809 +#define Z_UTIL_DEC_1811 1810 +#define Z_UTIL_DEC_1812 1811 +#define Z_UTIL_DEC_1813 1812 +#define Z_UTIL_DEC_1814 1813 +#define Z_UTIL_DEC_1815 1814 +#define Z_UTIL_DEC_1816 1815 +#define Z_UTIL_DEC_1817 1816 +#define Z_UTIL_DEC_1818 1817 +#define Z_UTIL_DEC_1819 1818 +#define Z_UTIL_DEC_1820 1819 +#define Z_UTIL_DEC_1821 1820 +#define Z_UTIL_DEC_1822 1821 +#define Z_UTIL_DEC_1823 1822 +#define Z_UTIL_DEC_1824 1823 +#define Z_UTIL_DEC_1825 1824 +#define Z_UTIL_DEC_1826 1825 +#define Z_UTIL_DEC_1827 1826 +#define Z_UTIL_DEC_1828 1827 +#define Z_UTIL_DEC_1829 1828 +#define Z_UTIL_DEC_1830 1829 +#define Z_UTIL_DEC_1831 1830 +#define Z_UTIL_DEC_1832 1831 +#define Z_UTIL_DEC_1833 1832 +#define Z_UTIL_DEC_1834 1833 +#define Z_UTIL_DEC_1835 1834 +#define Z_UTIL_DEC_1836 1835 +#define Z_UTIL_DEC_1837 1836 +#define Z_UTIL_DEC_1838 1837 +#define Z_UTIL_DEC_1839 1838 +#define Z_UTIL_DEC_1840 1839 +#define Z_UTIL_DEC_1841 1840 +#define Z_UTIL_DEC_1842 1841 +#define Z_UTIL_DEC_1843 1842 +#define Z_UTIL_DEC_1844 1843 +#define Z_UTIL_DEC_1845 1844 +#define Z_UTIL_DEC_1846 1845 +#define Z_UTIL_DEC_1847 1846 +#define Z_UTIL_DEC_1848 1847 +#define Z_UTIL_DEC_1849 1848 +#define Z_UTIL_DEC_1850 1849 +#define Z_UTIL_DEC_1851 1850 +#define Z_UTIL_DEC_1852 1851 +#define Z_UTIL_DEC_1853 1852 +#define Z_UTIL_DEC_1854 1853 +#define Z_UTIL_DEC_1855 1854 +#define Z_UTIL_DEC_1856 1855 +#define Z_UTIL_DEC_1857 1856 +#define Z_UTIL_DEC_1858 1857 +#define Z_UTIL_DEC_1859 1858 +#define Z_UTIL_DEC_1860 1859 +#define Z_UTIL_DEC_1861 1860 +#define Z_UTIL_DEC_1862 1861 +#define Z_UTIL_DEC_1863 1862 +#define Z_UTIL_DEC_1864 1863 +#define Z_UTIL_DEC_1865 1864 +#define Z_UTIL_DEC_1866 1865 +#define Z_UTIL_DEC_1867 1866 +#define Z_UTIL_DEC_1868 1867 +#define Z_UTIL_DEC_1869 1868 +#define Z_UTIL_DEC_1870 1869 +#define Z_UTIL_DEC_1871 1870 +#define Z_UTIL_DEC_1872 1871 +#define Z_UTIL_DEC_1873 1872 +#define Z_UTIL_DEC_1874 1873 +#define Z_UTIL_DEC_1875 1874 +#define Z_UTIL_DEC_1876 1875 +#define Z_UTIL_DEC_1877 1876 +#define Z_UTIL_DEC_1878 1877 +#define Z_UTIL_DEC_1879 1878 +#define Z_UTIL_DEC_1880 1879 +#define Z_UTIL_DEC_1881 1880 +#define Z_UTIL_DEC_1882 1881 +#define Z_UTIL_DEC_1883 1882 +#define Z_UTIL_DEC_1884 1883 +#define Z_UTIL_DEC_1885 1884 +#define Z_UTIL_DEC_1886 1885 +#define Z_UTIL_DEC_1887 1886 +#define Z_UTIL_DEC_1888 1887 +#define Z_UTIL_DEC_1889 1888 +#define Z_UTIL_DEC_1890 1889 +#define Z_UTIL_DEC_1891 1890 +#define Z_UTIL_DEC_1892 1891 +#define Z_UTIL_DEC_1893 1892 +#define Z_UTIL_DEC_1894 1893 +#define Z_UTIL_DEC_1895 1894 +#define Z_UTIL_DEC_1896 1895 +#define Z_UTIL_DEC_1897 1896 +#define Z_UTIL_DEC_1898 1897 +#define Z_UTIL_DEC_1899 1898 +#define Z_UTIL_DEC_1900 1899 +#define Z_UTIL_DEC_1901 1900 +#define Z_UTIL_DEC_1902 1901 +#define Z_UTIL_DEC_1903 1902 +#define Z_UTIL_DEC_1904 1903 +#define Z_UTIL_DEC_1905 1904 +#define Z_UTIL_DEC_1906 1905 +#define Z_UTIL_DEC_1907 1906 +#define Z_UTIL_DEC_1908 1907 +#define Z_UTIL_DEC_1909 1908 +#define Z_UTIL_DEC_1910 1909 +#define Z_UTIL_DEC_1911 1910 +#define Z_UTIL_DEC_1912 1911 +#define Z_UTIL_DEC_1913 1912 +#define Z_UTIL_DEC_1914 1913 +#define Z_UTIL_DEC_1915 1914 +#define Z_UTIL_DEC_1916 1915 +#define Z_UTIL_DEC_1917 1916 +#define Z_UTIL_DEC_1918 1917 +#define Z_UTIL_DEC_1919 1918 +#define Z_UTIL_DEC_1920 1919 +#define Z_UTIL_DEC_1921 1920 +#define Z_UTIL_DEC_1922 1921 +#define Z_UTIL_DEC_1923 1922 +#define Z_UTIL_DEC_1924 1923 +#define Z_UTIL_DEC_1925 1924 +#define Z_UTIL_DEC_1926 1925 +#define Z_UTIL_DEC_1927 1926 +#define Z_UTIL_DEC_1928 1927 +#define Z_UTIL_DEC_1929 1928 +#define Z_UTIL_DEC_1930 1929 +#define Z_UTIL_DEC_1931 1930 +#define Z_UTIL_DEC_1932 1931 +#define Z_UTIL_DEC_1933 1932 +#define Z_UTIL_DEC_1934 1933 +#define Z_UTIL_DEC_1935 1934 +#define Z_UTIL_DEC_1936 1935 +#define Z_UTIL_DEC_1937 1936 +#define Z_UTIL_DEC_1938 1937 +#define Z_UTIL_DEC_1939 1938 +#define Z_UTIL_DEC_1940 1939 +#define Z_UTIL_DEC_1941 1940 +#define Z_UTIL_DEC_1942 1941 +#define Z_UTIL_DEC_1943 1942 +#define Z_UTIL_DEC_1944 1943 +#define Z_UTIL_DEC_1945 1944 +#define Z_UTIL_DEC_1946 1945 +#define Z_UTIL_DEC_1947 1946 +#define Z_UTIL_DEC_1948 1947 +#define Z_UTIL_DEC_1949 1948 +#define Z_UTIL_DEC_1950 1949 +#define Z_UTIL_DEC_1951 1950 +#define Z_UTIL_DEC_1952 1951 +#define Z_UTIL_DEC_1953 1952 +#define Z_UTIL_DEC_1954 1953 +#define Z_UTIL_DEC_1955 1954 +#define Z_UTIL_DEC_1956 1955 +#define Z_UTIL_DEC_1957 1956 +#define Z_UTIL_DEC_1958 1957 +#define Z_UTIL_DEC_1959 1958 +#define Z_UTIL_DEC_1960 1959 +#define Z_UTIL_DEC_1961 1960 +#define Z_UTIL_DEC_1962 1961 +#define Z_UTIL_DEC_1963 1962 +#define Z_UTIL_DEC_1964 1963 +#define Z_UTIL_DEC_1965 1964 +#define Z_UTIL_DEC_1966 1965 +#define Z_UTIL_DEC_1967 1966 +#define Z_UTIL_DEC_1968 1967 +#define Z_UTIL_DEC_1969 1968 +#define Z_UTIL_DEC_1970 1969 +#define Z_UTIL_DEC_1971 1970 +#define Z_UTIL_DEC_1972 1971 +#define Z_UTIL_DEC_1973 1972 +#define Z_UTIL_DEC_1974 1973 +#define Z_UTIL_DEC_1975 1974 +#define Z_UTIL_DEC_1976 1975 +#define Z_UTIL_DEC_1977 1976 +#define Z_UTIL_DEC_1978 1977 +#define Z_UTIL_DEC_1979 1978 +#define Z_UTIL_DEC_1980 1979 +#define Z_UTIL_DEC_1981 1980 +#define Z_UTIL_DEC_1982 1981 +#define Z_UTIL_DEC_1983 1982 +#define Z_UTIL_DEC_1984 1983 +#define Z_UTIL_DEC_1985 1984 +#define Z_UTIL_DEC_1986 1985 +#define Z_UTIL_DEC_1987 1986 +#define Z_UTIL_DEC_1988 1987 +#define Z_UTIL_DEC_1989 1988 +#define Z_UTIL_DEC_1990 1989 +#define Z_UTIL_DEC_1991 1990 +#define Z_UTIL_DEC_1992 1991 +#define Z_UTIL_DEC_1993 1992 +#define Z_UTIL_DEC_1994 1993 +#define Z_UTIL_DEC_1995 1994 +#define Z_UTIL_DEC_1996 1995 +#define Z_UTIL_DEC_1997 1996 +#define Z_UTIL_DEC_1998 1997 +#define Z_UTIL_DEC_1999 1998 +#define Z_UTIL_DEC_2000 1999 +#define Z_UTIL_DEC_2001 2000 +#define Z_UTIL_DEC_2002 2001 +#define Z_UTIL_DEC_2003 2002 +#define Z_UTIL_DEC_2004 2003 +#define Z_UTIL_DEC_2005 2004 +#define Z_UTIL_DEC_2006 2005 +#define Z_UTIL_DEC_2007 2006 +#define Z_UTIL_DEC_2008 2007 +#define Z_UTIL_DEC_2009 2008 +#define Z_UTIL_DEC_2010 2009 +#define Z_UTIL_DEC_2011 2010 +#define Z_UTIL_DEC_2012 2011 +#define Z_UTIL_DEC_2013 2012 +#define Z_UTIL_DEC_2014 2013 +#define Z_UTIL_DEC_2015 2014 +#define Z_UTIL_DEC_2016 2015 +#define Z_UTIL_DEC_2017 2016 +#define Z_UTIL_DEC_2018 2017 +#define Z_UTIL_DEC_2019 2018 +#define Z_UTIL_DEC_2020 2019 +#define Z_UTIL_DEC_2021 2020 +#define Z_UTIL_DEC_2022 2021 +#define Z_UTIL_DEC_2023 2022 +#define Z_UTIL_DEC_2024 2023 +#define Z_UTIL_DEC_2025 2024 +#define Z_UTIL_DEC_2026 2025 +#define Z_UTIL_DEC_2027 2026 +#define Z_UTIL_DEC_2028 2027 +#define Z_UTIL_DEC_2029 2028 +#define Z_UTIL_DEC_2030 2029 +#define Z_UTIL_DEC_2031 2030 +#define Z_UTIL_DEC_2032 2031 +#define Z_UTIL_DEC_2033 2032 +#define Z_UTIL_DEC_2034 2033 +#define Z_UTIL_DEC_2035 2034 +#define Z_UTIL_DEC_2036 2035 +#define Z_UTIL_DEC_2037 2036 +#define Z_UTIL_DEC_2038 2037 +#define Z_UTIL_DEC_2039 2038 +#define Z_UTIL_DEC_2040 2039 +#define Z_UTIL_DEC_2041 2040 +#define Z_UTIL_DEC_2042 2041 +#define Z_UTIL_DEC_2043 2042 +#define Z_UTIL_DEC_2044 2043 +#define Z_UTIL_DEC_2045 2044 +#define Z_UTIL_DEC_2046 2045 +#define Z_UTIL_DEC_2047 2046 +#define Z_UTIL_DEC_2048 2047 +#define Z_UTIL_DEC_2049 2048 +#define Z_UTIL_DEC_2050 2049 +#define Z_UTIL_DEC_2051 2050 +#define Z_UTIL_DEC_2052 2051 +#define Z_UTIL_DEC_2053 2052 +#define Z_UTIL_DEC_2054 2053 +#define Z_UTIL_DEC_2055 2054 +#define Z_UTIL_DEC_2056 2055 +#define Z_UTIL_DEC_2057 2056 +#define Z_UTIL_DEC_2058 2057 +#define Z_UTIL_DEC_2059 2058 +#define Z_UTIL_DEC_2060 2059 +#define Z_UTIL_DEC_2061 2060 +#define Z_UTIL_DEC_2062 2061 +#define Z_UTIL_DEC_2063 2062 +#define Z_UTIL_DEC_2064 2063 +#define Z_UTIL_DEC_2065 2064 +#define Z_UTIL_DEC_2066 2065 +#define Z_UTIL_DEC_2067 2066 +#define Z_UTIL_DEC_2068 2067 +#define Z_UTIL_DEC_2069 2068 +#define Z_UTIL_DEC_2070 2069 +#define Z_UTIL_DEC_2071 2070 +#define Z_UTIL_DEC_2072 2071 +#define Z_UTIL_DEC_2073 2072 +#define Z_UTIL_DEC_2074 2073 +#define Z_UTIL_DEC_2075 2074 +#define Z_UTIL_DEC_2076 2075 +#define Z_UTIL_DEC_2077 2076 +#define Z_UTIL_DEC_2078 2077 +#define Z_UTIL_DEC_2079 2078 +#define Z_UTIL_DEC_2080 2079 +#define Z_UTIL_DEC_2081 2080 +#define Z_UTIL_DEC_2082 2081 +#define Z_UTIL_DEC_2083 2082 +#define Z_UTIL_DEC_2084 2083 +#define Z_UTIL_DEC_2085 2084 +#define Z_UTIL_DEC_2086 2085 +#define Z_UTIL_DEC_2087 2086 +#define Z_UTIL_DEC_2088 2087 +#define Z_UTIL_DEC_2089 2088 +#define Z_UTIL_DEC_2090 2089 +#define Z_UTIL_DEC_2091 2090 +#define Z_UTIL_DEC_2092 2091 +#define Z_UTIL_DEC_2093 2092 +#define Z_UTIL_DEC_2094 2093 +#define Z_UTIL_DEC_2095 2094 +#define Z_UTIL_DEC_2096 2095 +#define Z_UTIL_DEC_2097 2096 +#define Z_UTIL_DEC_2098 2097 +#define Z_UTIL_DEC_2099 2098 +#define Z_UTIL_DEC_2100 2099 +#define Z_UTIL_DEC_2101 2100 +#define Z_UTIL_DEC_2102 2101 +#define Z_UTIL_DEC_2103 2102 +#define Z_UTIL_DEC_2104 2103 +#define Z_UTIL_DEC_2105 2104 +#define Z_UTIL_DEC_2106 2105 +#define Z_UTIL_DEC_2107 2106 +#define Z_UTIL_DEC_2108 2107 +#define Z_UTIL_DEC_2109 2108 +#define Z_UTIL_DEC_2110 2109 +#define Z_UTIL_DEC_2111 2110 +#define Z_UTIL_DEC_2112 2111 +#define Z_UTIL_DEC_2113 2112 +#define Z_UTIL_DEC_2114 2113 +#define Z_UTIL_DEC_2115 2114 +#define Z_UTIL_DEC_2116 2115 +#define Z_UTIL_DEC_2117 2116 +#define Z_UTIL_DEC_2118 2117 +#define Z_UTIL_DEC_2119 2118 +#define Z_UTIL_DEC_2120 2119 +#define Z_UTIL_DEC_2121 2120 +#define Z_UTIL_DEC_2122 2121 +#define Z_UTIL_DEC_2123 2122 +#define Z_UTIL_DEC_2124 2123 +#define Z_UTIL_DEC_2125 2124 +#define Z_UTIL_DEC_2126 2125 +#define Z_UTIL_DEC_2127 2126 +#define Z_UTIL_DEC_2128 2127 +#define Z_UTIL_DEC_2129 2128 +#define Z_UTIL_DEC_2130 2129 +#define Z_UTIL_DEC_2131 2130 +#define Z_UTIL_DEC_2132 2131 +#define Z_UTIL_DEC_2133 2132 +#define Z_UTIL_DEC_2134 2133 +#define Z_UTIL_DEC_2135 2134 +#define Z_UTIL_DEC_2136 2135 +#define Z_UTIL_DEC_2137 2136 +#define Z_UTIL_DEC_2138 2137 +#define Z_UTIL_DEC_2139 2138 +#define Z_UTIL_DEC_2140 2139 +#define Z_UTIL_DEC_2141 2140 +#define Z_UTIL_DEC_2142 2141 +#define Z_UTIL_DEC_2143 2142 +#define Z_UTIL_DEC_2144 2143 +#define Z_UTIL_DEC_2145 2144 +#define Z_UTIL_DEC_2146 2145 +#define Z_UTIL_DEC_2147 2146 +#define Z_UTIL_DEC_2148 2147 +#define Z_UTIL_DEC_2149 2148 +#define Z_UTIL_DEC_2150 2149 +#define Z_UTIL_DEC_2151 2150 +#define Z_UTIL_DEC_2152 2151 +#define Z_UTIL_DEC_2153 2152 +#define Z_UTIL_DEC_2154 2153 +#define Z_UTIL_DEC_2155 2154 +#define Z_UTIL_DEC_2156 2155 +#define Z_UTIL_DEC_2157 2156 +#define Z_UTIL_DEC_2158 2157 +#define Z_UTIL_DEC_2159 2158 +#define Z_UTIL_DEC_2160 2159 +#define Z_UTIL_DEC_2161 2160 +#define Z_UTIL_DEC_2162 2161 +#define Z_UTIL_DEC_2163 2162 +#define Z_UTIL_DEC_2164 2163 +#define Z_UTIL_DEC_2165 2164 +#define Z_UTIL_DEC_2166 2165 +#define Z_UTIL_DEC_2167 2166 +#define Z_UTIL_DEC_2168 2167 +#define Z_UTIL_DEC_2169 2168 +#define Z_UTIL_DEC_2170 2169 +#define Z_UTIL_DEC_2171 2170 +#define Z_UTIL_DEC_2172 2171 +#define Z_UTIL_DEC_2173 2172 +#define Z_UTIL_DEC_2174 2173 +#define Z_UTIL_DEC_2175 2174 +#define Z_UTIL_DEC_2176 2175 +#define Z_UTIL_DEC_2177 2176 +#define Z_UTIL_DEC_2178 2177 +#define Z_UTIL_DEC_2179 2178 +#define Z_UTIL_DEC_2180 2179 +#define Z_UTIL_DEC_2181 2180 +#define Z_UTIL_DEC_2182 2181 +#define Z_UTIL_DEC_2183 2182 +#define Z_UTIL_DEC_2184 2183 +#define Z_UTIL_DEC_2185 2184 +#define Z_UTIL_DEC_2186 2185 +#define Z_UTIL_DEC_2187 2186 +#define Z_UTIL_DEC_2188 2187 +#define Z_UTIL_DEC_2189 2188 +#define Z_UTIL_DEC_2190 2189 +#define Z_UTIL_DEC_2191 2190 +#define Z_UTIL_DEC_2192 2191 +#define Z_UTIL_DEC_2193 2192 +#define Z_UTIL_DEC_2194 2193 +#define Z_UTIL_DEC_2195 2194 +#define Z_UTIL_DEC_2196 2195 +#define Z_UTIL_DEC_2197 2196 +#define Z_UTIL_DEC_2198 2197 +#define Z_UTIL_DEC_2199 2198 +#define Z_UTIL_DEC_2200 2199 +#define Z_UTIL_DEC_2201 2200 +#define Z_UTIL_DEC_2202 2201 +#define Z_UTIL_DEC_2203 2202 +#define Z_UTIL_DEC_2204 2203 +#define Z_UTIL_DEC_2205 2204 +#define Z_UTIL_DEC_2206 2205 +#define Z_UTIL_DEC_2207 2206 +#define Z_UTIL_DEC_2208 2207 +#define Z_UTIL_DEC_2209 2208 +#define Z_UTIL_DEC_2210 2209 +#define Z_UTIL_DEC_2211 2210 +#define Z_UTIL_DEC_2212 2211 +#define Z_UTIL_DEC_2213 2212 +#define Z_UTIL_DEC_2214 2213 +#define Z_UTIL_DEC_2215 2214 +#define Z_UTIL_DEC_2216 2215 +#define Z_UTIL_DEC_2217 2216 +#define Z_UTIL_DEC_2218 2217 +#define Z_UTIL_DEC_2219 2218 +#define Z_UTIL_DEC_2220 2219 +#define Z_UTIL_DEC_2221 2220 +#define Z_UTIL_DEC_2222 2221 +#define Z_UTIL_DEC_2223 2222 +#define Z_UTIL_DEC_2224 2223 +#define Z_UTIL_DEC_2225 2224 +#define Z_UTIL_DEC_2226 2225 +#define Z_UTIL_DEC_2227 2226 +#define Z_UTIL_DEC_2228 2227 +#define Z_UTIL_DEC_2229 2228 +#define Z_UTIL_DEC_2230 2229 +#define Z_UTIL_DEC_2231 2230 +#define Z_UTIL_DEC_2232 2231 +#define Z_UTIL_DEC_2233 2232 +#define Z_UTIL_DEC_2234 2233 +#define Z_UTIL_DEC_2235 2234 +#define Z_UTIL_DEC_2236 2235 +#define Z_UTIL_DEC_2237 2236 +#define Z_UTIL_DEC_2238 2237 +#define Z_UTIL_DEC_2239 2238 +#define Z_UTIL_DEC_2240 2239 +#define Z_UTIL_DEC_2241 2240 +#define Z_UTIL_DEC_2242 2241 +#define Z_UTIL_DEC_2243 2242 +#define Z_UTIL_DEC_2244 2243 +#define Z_UTIL_DEC_2245 2244 +#define Z_UTIL_DEC_2246 2245 +#define Z_UTIL_DEC_2247 2246 +#define Z_UTIL_DEC_2248 2247 +#define Z_UTIL_DEC_2249 2248 +#define Z_UTIL_DEC_2250 2249 +#define Z_UTIL_DEC_2251 2250 +#define Z_UTIL_DEC_2252 2251 +#define Z_UTIL_DEC_2253 2252 +#define Z_UTIL_DEC_2254 2253 +#define Z_UTIL_DEC_2255 2254 +#define Z_UTIL_DEC_2256 2255 +#define Z_UTIL_DEC_2257 2256 +#define Z_UTIL_DEC_2258 2257 +#define Z_UTIL_DEC_2259 2258 +#define Z_UTIL_DEC_2260 2259 +#define Z_UTIL_DEC_2261 2260 +#define Z_UTIL_DEC_2262 2261 +#define Z_UTIL_DEC_2263 2262 +#define Z_UTIL_DEC_2264 2263 +#define Z_UTIL_DEC_2265 2264 +#define Z_UTIL_DEC_2266 2265 +#define Z_UTIL_DEC_2267 2266 +#define Z_UTIL_DEC_2268 2267 +#define Z_UTIL_DEC_2269 2268 +#define Z_UTIL_DEC_2270 2269 +#define Z_UTIL_DEC_2271 2270 +#define Z_UTIL_DEC_2272 2271 +#define Z_UTIL_DEC_2273 2272 +#define Z_UTIL_DEC_2274 2273 +#define Z_UTIL_DEC_2275 2274 +#define Z_UTIL_DEC_2276 2275 +#define Z_UTIL_DEC_2277 2276 +#define Z_UTIL_DEC_2278 2277 +#define Z_UTIL_DEC_2279 2278 +#define Z_UTIL_DEC_2280 2279 +#define Z_UTIL_DEC_2281 2280 +#define Z_UTIL_DEC_2282 2281 +#define Z_UTIL_DEC_2283 2282 +#define Z_UTIL_DEC_2284 2283 +#define Z_UTIL_DEC_2285 2284 +#define Z_UTIL_DEC_2286 2285 +#define Z_UTIL_DEC_2287 2286 +#define Z_UTIL_DEC_2288 2287 +#define Z_UTIL_DEC_2289 2288 +#define Z_UTIL_DEC_2290 2289 +#define Z_UTIL_DEC_2291 2290 +#define Z_UTIL_DEC_2292 2291 +#define Z_UTIL_DEC_2293 2292 +#define Z_UTIL_DEC_2294 2293 +#define Z_UTIL_DEC_2295 2294 +#define Z_UTIL_DEC_2296 2295 +#define Z_UTIL_DEC_2297 2296 +#define Z_UTIL_DEC_2298 2297 +#define Z_UTIL_DEC_2299 2298 +#define Z_UTIL_DEC_2300 2299 +#define Z_UTIL_DEC_2301 2300 +#define Z_UTIL_DEC_2302 2301 +#define Z_UTIL_DEC_2303 2302 +#define Z_UTIL_DEC_2304 2303 +#define Z_UTIL_DEC_2305 2304 +#define Z_UTIL_DEC_2306 2305 +#define Z_UTIL_DEC_2307 2306 +#define Z_UTIL_DEC_2308 2307 +#define Z_UTIL_DEC_2309 2308 +#define Z_UTIL_DEC_2310 2309 +#define Z_UTIL_DEC_2311 2310 +#define Z_UTIL_DEC_2312 2311 +#define Z_UTIL_DEC_2313 2312 +#define Z_UTIL_DEC_2314 2313 +#define Z_UTIL_DEC_2315 2314 +#define Z_UTIL_DEC_2316 2315 +#define Z_UTIL_DEC_2317 2316 +#define Z_UTIL_DEC_2318 2317 +#define Z_UTIL_DEC_2319 2318 +#define Z_UTIL_DEC_2320 2319 +#define Z_UTIL_DEC_2321 2320 +#define Z_UTIL_DEC_2322 2321 +#define Z_UTIL_DEC_2323 2322 +#define Z_UTIL_DEC_2324 2323 +#define Z_UTIL_DEC_2325 2324 +#define Z_UTIL_DEC_2326 2325 +#define Z_UTIL_DEC_2327 2326 +#define Z_UTIL_DEC_2328 2327 +#define Z_UTIL_DEC_2329 2328 +#define Z_UTIL_DEC_2330 2329 +#define Z_UTIL_DEC_2331 2330 +#define Z_UTIL_DEC_2332 2331 +#define Z_UTIL_DEC_2333 2332 +#define Z_UTIL_DEC_2334 2333 +#define Z_UTIL_DEC_2335 2334 +#define Z_UTIL_DEC_2336 2335 +#define Z_UTIL_DEC_2337 2336 +#define Z_UTIL_DEC_2338 2337 +#define Z_UTIL_DEC_2339 2338 +#define Z_UTIL_DEC_2340 2339 +#define Z_UTIL_DEC_2341 2340 +#define Z_UTIL_DEC_2342 2341 +#define Z_UTIL_DEC_2343 2342 +#define Z_UTIL_DEC_2344 2343 +#define Z_UTIL_DEC_2345 2344 +#define Z_UTIL_DEC_2346 2345 +#define Z_UTIL_DEC_2347 2346 +#define Z_UTIL_DEC_2348 2347 +#define Z_UTIL_DEC_2349 2348 +#define Z_UTIL_DEC_2350 2349 +#define Z_UTIL_DEC_2351 2350 +#define Z_UTIL_DEC_2352 2351 +#define Z_UTIL_DEC_2353 2352 +#define Z_UTIL_DEC_2354 2353 +#define Z_UTIL_DEC_2355 2354 +#define Z_UTIL_DEC_2356 2355 +#define Z_UTIL_DEC_2357 2356 +#define Z_UTIL_DEC_2358 2357 +#define Z_UTIL_DEC_2359 2358 +#define Z_UTIL_DEC_2360 2359 +#define Z_UTIL_DEC_2361 2360 +#define Z_UTIL_DEC_2362 2361 +#define Z_UTIL_DEC_2363 2362 +#define Z_UTIL_DEC_2364 2363 +#define Z_UTIL_DEC_2365 2364 +#define Z_UTIL_DEC_2366 2365 +#define Z_UTIL_DEC_2367 2366 +#define Z_UTIL_DEC_2368 2367 +#define Z_UTIL_DEC_2369 2368 +#define Z_UTIL_DEC_2370 2369 +#define Z_UTIL_DEC_2371 2370 +#define Z_UTIL_DEC_2372 2371 +#define Z_UTIL_DEC_2373 2372 +#define Z_UTIL_DEC_2374 2373 +#define Z_UTIL_DEC_2375 2374 +#define Z_UTIL_DEC_2376 2375 +#define Z_UTIL_DEC_2377 2376 +#define Z_UTIL_DEC_2378 2377 +#define Z_UTIL_DEC_2379 2378 +#define Z_UTIL_DEC_2380 2379 +#define Z_UTIL_DEC_2381 2380 +#define Z_UTIL_DEC_2382 2381 +#define Z_UTIL_DEC_2383 2382 +#define Z_UTIL_DEC_2384 2383 +#define Z_UTIL_DEC_2385 2384 +#define Z_UTIL_DEC_2386 2385 +#define Z_UTIL_DEC_2387 2386 +#define Z_UTIL_DEC_2388 2387 +#define Z_UTIL_DEC_2389 2388 +#define Z_UTIL_DEC_2390 2389 +#define Z_UTIL_DEC_2391 2390 +#define Z_UTIL_DEC_2392 2391 +#define Z_UTIL_DEC_2393 2392 +#define Z_UTIL_DEC_2394 2393 +#define Z_UTIL_DEC_2395 2394 +#define Z_UTIL_DEC_2396 2395 +#define Z_UTIL_DEC_2397 2396 +#define Z_UTIL_DEC_2398 2397 +#define Z_UTIL_DEC_2399 2398 +#define Z_UTIL_DEC_2400 2399 +#define Z_UTIL_DEC_2401 2400 +#define Z_UTIL_DEC_2402 2401 +#define Z_UTIL_DEC_2403 2402 +#define Z_UTIL_DEC_2404 2403 +#define Z_UTIL_DEC_2405 2404 +#define Z_UTIL_DEC_2406 2405 +#define Z_UTIL_DEC_2407 2406 +#define Z_UTIL_DEC_2408 2407 +#define Z_UTIL_DEC_2409 2408 +#define Z_UTIL_DEC_2410 2409 +#define Z_UTIL_DEC_2411 2410 +#define Z_UTIL_DEC_2412 2411 +#define Z_UTIL_DEC_2413 2412 +#define Z_UTIL_DEC_2414 2413 +#define Z_UTIL_DEC_2415 2414 +#define Z_UTIL_DEC_2416 2415 +#define Z_UTIL_DEC_2417 2416 +#define Z_UTIL_DEC_2418 2417 +#define Z_UTIL_DEC_2419 2418 +#define Z_UTIL_DEC_2420 2419 +#define Z_UTIL_DEC_2421 2420 +#define Z_UTIL_DEC_2422 2421 +#define Z_UTIL_DEC_2423 2422 +#define Z_UTIL_DEC_2424 2423 +#define Z_UTIL_DEC_2425 2424 +#define Z_UTIL_DEC_2426 2425 +#define Z_UTIL_DEC_2427 2426 +#define Z_UTIL_DEC_2428 2427 +#define Z_UTIL_DEC_2429 2428 +#define Z_UTIL_DEC_2430 2429 +#define Z_UTIL_DEC_2431 2430 +#define Z_UTIL_DEC_2432 2431 +#define Z_UTIL_DEC_2433 2432 +#define Z_UTIL_DEC_2434 2433 +#define Z_UTIL_DEC_2435 2434 +#define Z_UTIL_DEC_2436 2435 +#define Z_UTIL_DEC_2437 2436 +#define Z_UTIL_DEC_2438 2437 +#define Z_UTIL_DEC_2439 2438 +#define Z_UTIL_DEC_2440 2439 +#define Z_UTIL_DEC_2441 2440 +#define Z_UTIL_DEC_2442 2441 +#define Z_UTIL_DEC_2443 2442 +#define Z_UTIL_DEC_2444 2443 +#define Z_UTIL_DEC_2445 2444 +#define Z_UTIL_DEC_2446 2445 +#define Z_UTIL_DEC_2447 2446 +#define Z_UTIL_DEC_2448 2447 +#define Z_UTIL_DEC_2449 2448 +#define Z_UTIL_DEC_2450 2449 +#define Z_UTIL_DEC_2451 2450 +#define Z_UTIL_DEC_2452 2451 +#define Z_UTIL_DEC_2453 2452 +#define Z_UTIL_DEC_2454 2453 +#define Z_UTIL_DEC_2455 2454 +#define Z_UTIL_DEC_2456 2455 +#define Z_UTIL_DEC_2457 2456 +#define Z_UTIL_DEC_2458 2457 +#define Z_UTIL_DEC_2459 2458 +#define Z_UTIL_DEC_2460 2459 +#define Z_UTIL_DEC_2461 2460 +#define Z_UTIL_DEC_2462 2461 +#define Z_UTIL_DEC_2463 2462 +#define Z_UTIL_DEC_2464 2463 +#define Z_UTIL_DEC_2465 2464 +#define Z_UTIL_DEC_2466 2465 +#define Z_UTIL_DEC_2467 2466 +#define Z_UTIL_DEC_2468 2467 +#define Z_UTIL_DEC_2469 2468 +#define Z_UTIL_DEC_2470 2469 +#define Z_UTIL_DEC_2471 2470 +#define Z_UTIL_DEC_2472 2471 +#define Z_UTIL_DEC_2473 2472 +#define Z_UTIL_DEC_2474 2473 +#define Z_UTIL_DEC_2475 2474 +#define Z_UTIL_DEC_2476 2475 +#define Z_UTIL_DEC_2477 2476 +#define Z_UTIL_DEC_2478 2477 +#define Z_UTIL_DEC_2479 2478 +#define Z_UTIL_DEC_2480 2479 +#define Z_UTIL_DEC_2481 2480 +#define Z_UTIL_DEC_2482 2481 +#define Z_UTIL_DEC_2483 2482 +#define Z_UTIL_DEC_2484 2483 +#define Z_UTIL_DEC_2485 2484 +#define Z_UTIL_DEC_2486 2485 +#define Z_UTIL_DEC_2487 2486 +#define Z_UTIL_DEC_2488 2487 +#define Z_UTIL_DEC_2489 2488 +#define Z_UTIL_DEC_2490 2489 +#define Z_UTIL_DEC_2491 2490 +#define Z_UTIL_DEC_2492 2491 +#define Z_UTIL_DEC_2493 2492 +#define Z_UTIL_DEC_2494 2493 +#define Z_UTIL_DEC_2495 2494 +#define Z_UTIL_DEC_2496 2495 +#define Z_UTIL_DEC_2497 2496 +#define Z_UTIL_DEC_2498 2497 +#define Z_UTIL_DEC_2499 2498 +#define Z_UTIL_DEC_2500 2499 +#define Z_UTIL_DEC_2501 2500 +#define Z_UTIL_DEC_2502 2501 +#define Z_UTIL_DEC_2503 2502 +#define Z_UTIL_DEC_2504 2503 +#define Z_UTIL_DEC_2505 2504 +#define Z_UTIL_DEC_2506 2505 +#define Z_UTIL_DEC_2507 2506 +#define Z_UTIL_DEC_2508 2507 +#define Z_UTIL_DEC_2509 2508 +#define Z_UTIL_DEC_2510 2509 +#define Z_UTIL_DEC_2511 2510 +#define Z_UTIL_DEC_2512 2511 +#define Z_UTIL_DEC_2513 2512 +#define Z_UTIL_DEC_2514 2513 +#define Z_UTIL_DEC_2515 2514 +#define Z_UTIL_DEC_2516 2515 +#define Z_UTIL_DEC_2517 2516 +#define Z_UTIL_DEC_2518 2517 +#define Z_UTIL_DEC_2519 2518 +#define Z_UTIL_DEC_2520 2519 +#define Z_UTIL_DEC_2521 2520 +#define Z_UTIL_DEC_2522 2521 +#define Z_UTIL_DEC_2523 2522 +#define Z_UTIL_DEC_2524 2523 +#define Z_UTIL_DEC_2525 2524 +#define Z_UTIL_DEC_2526 2525 +#define Z_UTIL_DEC_2527 2526 +#define Z_UTIL_DEC_2528 2527 +#define Z_UTIL_DEC_2529 2528 +#define Z_UTIL_DEC_2530 2529 +#define Z_UTIL_DEC_2531 2530 +#define Z_UTIL_DEC_2532 2531 +#define Z_UTIL_DEC_2533 2532 +#define Z_UTIL_DEC_2534 2533 +#define Z_UTIL_DEC_2535 2534 +#define Z_UTIL_DEC_2536 2535 +#define Z_UTIL_DEC_2537 2536 +#define Z_UTIL_DEC_2538 2537 +#define Z_UTIL_DEC_2539 2538 +#define Z_UTIL_DEC_2540 2539 +#define Z_UTIL_DEC_2541 2540 +#define Z_UTIL_DEC_2542 2541 +#define Z_UTIL_DEC_2543 2542 +#define Z_UTIL_DEC_2544 2543 +#define Z_UTIL_DEC_2545 2544 +#define Z_UTIL_DEC_2546 2545 +#define Z_UTIL_DEC_2547 2546 +#define Z_UTIL_DEC_2548 2547 +#define Z_UTIL_DEC_2549 2548 +#define Z_UTIL_DEC_2550 2549 +#define Z_UTIL_DEC_2551 2550 +#define Z_UTIL_DEC_2552 2551 +#define Z_UTIL_DEC_2553 2552 +#define Z_UTIL_DEC_2554 2553 +#define Z_UTIL_DEC_2555 2554 +#define Z_UTIL_DEC_2556 2555 +#define Z_UTIL_DEC_2557 2556 +#define Z_UTIL_DEC_2558 2557 +#define Z_UTIL_DEC_2559 2558 +#define Z_UTIL_DEC_2560 2559 +#define Z_UTIL_DEC_2561 2560 +#define Z_UTIL_DEC_2562 2561 +#define Z_UTIL_DEC_2563 2562 +#define Z_UTIL_DEC_2564 2563 +#define Z_UTIL_DEC_2565 2564 +#define Z_UTIL_DEC_2566 2565 +#define Z_UTIL_DEC_2567 2566 +#define Z_UTIL_DEC_2568 2567 +#define Z_UTIL_DEC_2569 2568 +#define Z_UTIL_DEC_2570 2569 +#define Z_UTIL_DEC_2571 2570 +#define Z_UTIL_DEC_2572 2571 +#define Z_UTIL_DEC_2573 2572 +#define Z_UTIL_DEC_2574 2573 +#define Z_UTIL_DEC_2575 2574 +#define Z_UTIL_DEC_2576 2575 +#define Z_UTIL_DEC_2577 2576 +#define Z_UTIL_DEC_2578 2577 +#define Z_UTIL_DEC_2579 2578 +#define Z_UTIL_DEC_2580 2579 +#define Z_UTIL_DEC_2581 2580 +#define Z_UTIL_DEC_2582 2581 +#define Z_UTIL_DEC_2583 2582 +#define Z_UTIL_DEC_2584 2583 +#define Z_UTIL_DEC_2585 2584 +#define Z_UTIL_DEC_2586 2585 +#define Z_UTIL_DEC_2587 2586 +#define Z_UTIL_DEC_2588 2587 +#define Z_UTIL_DEC_2589 2588 +#define Z_UTIL_DEC_2590 2589 +#define Z_UTIL_DEC_2591 2590 +#define Z_UTIL_DEC_2592 2591 +#define Z_UTIL_DEC_2593 2592 +#define Z_UTIL_DEC_2594 2593 +#define Z_UTIL_DEC_2595 2594 +#define Z_UTIL_DEC_2596 2595 +#define Z_UTIL_DEC_2597 2596 +#define Z_UTIL_DEC_2598 2597 +#define Z_UTIL_DEC_2599 2598 +#define Z_UTIL_DEC_2600 2599 +#define Z_UTIL_DEC_2601 2600 +#define Z_UTIL_DEC_2602 2601 +#define Z_UTIL_DEC_2603 2602 +#define Z_UTIL_DEC_2604 2603 +#define Z_UTIL_DEC_2605 2604 +#define Z_UTIL_DEC_2606 2605 +#define Z_UTIL_DEC_2607 2606 +#define Z_UTIL_DEC_2608 2607 +#define Z_UTIL_DEC_2609 2608 +#define Z_UTIL_DEC_2610 2609 +#define Z_UTIL_DEC_2611 2610 +#define Z_UTIL_DEC_2612 2611 +#define Z_UTIL_DEC_2613 2612 +#define Z_UTIL_DEC_2614 2613 +#define Z_UTIL_DEC_2615 2614 +#define Z_UTIL_DEC_2616 2615 +#define Z_UTIL_DEC_2617 2616 +#define Z_UTIL_DEC_2618 2617 +#define Z_UTIL_DEC_2619 2618 +#define Z_UTIL_DEC_2620 2619 +#define Z_UTIL_DEC_2621 2620 +#define Z_UTIL_DEC_2622 2621 +#define Z_UTIL_DEC_2623 2622 +#define Z_UTIL_DEC_2624 2623 +#define Z_UTIL_DEC_2625 2624 +#define Z_UTIL_DEC_2626 2625 +#define Z_UTIL_DEC_2627 2626 +#define Z_UTIL_DEC_2628 2627 +#define Z_UTIL_DEC_2629 2628 +#define Z_UTIL_DEC_2630 2629 +#define Z_UTIL_DEC_2631 2630 +#define Z_UTIL_DEC_2632 2631 +#define Z_UTIL_DEC_2633 2632 +#define Z_UTIL_DEC_2634 2633 +#define Z_UTIL_DEC_2635 2634 +#define Z_UTIL_DEC_2636 2635 +#define Z_UTIL_DEC_2637 2636 +#define Z_UTIL_DEC_2638 2637 +#define Z_UTIL_DEC_2639 2638 +#define Z_UTIL_DEC_2640 2639 +#define Z_UTIL_DEC_2641 2640 +#define Z_UTIL_DEC_2642 2641 +#define Z_UTIL_DEC_2643 2642 +#define Z_UTIL_DEC_2644 2643 +#define Z_UTIL_DEC_2645 2644 +#define Z_UTIL_DEC_2646 2645 +#define Z_UTIL_DEC_2647 2646 +#define Z_UTIL_DEC_2648 2647 +#define Z_UTIL_DEC_2649 2648 +#define Z_UTIL_DEC_2650 2649 +#define Z_UTIL_DEC_2651 2650 +#define Z_UTIL_DEC_2652 2651 +#define Z_UTIL_DEC_2653 2652 +#define Z_UTIL_DEC_2654 2653 +#define Z_UTIL_DEC_2655 2654 +#define Z_UTIL_DEC_2656 2655 +#define Z_UTIL_DEC_2657 2656 +#define Z_UTIL_DEC_2658 2657 +#define Z_UTIL_DEC_2659 2658 +#define Z_UTIL_DEC_2660 2659 +#define Z_UTIL_DEC_2661 2660 +#define Z_UTIL_DEC_2662 2661 +#define Z_UTIL_DEC_2663 2662 +#define Z_UTIL_DEC_2664 2663 +#define Z_UTIL_DEC_2665 2664 +#define Z_UTIL_DEC_2666 2665 +#define Z_UTIL_DEC_2667 2666 +#define Z_UTIL_DEC_2668 2667 +#define Z_UTIL_DEC_2669 2668 +#define Z_UTIL_DEC_2670 2669 +#define Z_UTIL_DEC_2671 2670 +#define Z_UTIL_DEC_2672 2671 +#define Z_UTIL_DEC_2673 2672 +#define Z_UTIL_DEC_2674 2673 +#define Z_UTIL_DEC_2675 2674 +#define Z_UTIL_DEC_2676 2675 +#define Z_UTIL_DEC_2677 2676 +#define Z_UTIL_DEC_2678 2677 +#define Z_UTIL_DEC_2679 2678 +#define Z_UTIL_DEC_2680 2679 +#define Z_UTIL_DEC_2681 2680 +#define Z_UTIL_DEC_2682 2681 +#define Z_UTIL_DEC_2683 2682 +#define Z_UTIL_DEC_2684 2683 +#define Z_UTIL_DEC_2685 2684 +#define Z_UTIL_DEC_2686 2685 +#define Z_UTIL_DEC_2687 2686 +#define Z_UTIL_DEC_2688 2687 +#define Z_UTIL_DEC_2689 2688 +#define Z_UTIL_DEC_2690 2689 +#define Z_UTIL_DEC_2691 2690 +#define Z_UTIL_DEC_2692 2691 +#define Z_UTIL_DEC_2693 2692 +#define Z_UTIL_DEC_2694 2693 +#define Z_UTIL_DEC_2695 2694 +#define Z_UTIL_DEC_2696 2695 +#define Z_UTIL_DEC_2697 2696 +#define Z_UTIL_DEC_2698 2697 +#define Z_UTIL_DEC_2699 2698 +#define Z_UTIL_DEC_2700 2699 +#define Z_UTIL_DEC_2701 2700 +#define Z_UTIL_DEC_2702 2701 +#define Z_UTIL_DEC_2703 2702 +#define Z_UTIL_DEC_2704 2703 +#define Z_UTIL_DEC_2705 2704 +#define Z_UTIL_DEC_2706 2705 +#define Z_UTIL_DEC_2707 2706 +#define Z_UTIL_DEC_2708 2707 +#define Z_UTIL_DEC_2709 2708 +#define Z_UTIL_DEC_2710 2709 +#define Z_UTIL_DEC_2711 2710 +#define Z_UTIL_DEC_2712 2711 +#define Z_UTIL_DEC_2713 2712 +#define Z_UTIL_DEC_2714 2713 +#define Z_UTIL_DEC_2715 2714 +#define Z_UTIL_DEC_2716 2715 +#define Z_UTIL_DEC_2717 2716 +#define Z_UTIL_DEC_2718 2717 +#define Z_UTIL_DEC_2719 2718 +#define Z_UTIL_DEC_2720 2719 +#define Z_UTIL_DEC_2721 2720 +#define Z_UTIL_DEC_2722 2721 +#define Z_UTIL_DEC_2723 2722 +#define Z_UTIL_DEC_2724 2723 +#define Z_UTIL_DEC_2725 2724 +#define Z_UTIL_DEC_2726 2725 +#define Z_UTIL_DEC_2727 2726 +#define Z_UTIL_DEC_2728 2727 +#define Z_UTIL_DEC_2729 2728 +#define Z_UTIL_DEC_2730 2729 +#define Z_UTIL_DEC_2731 2730 +#define Z_UTIL_DEC_2732 2731 +#define Z_UTIL_DEC_2733 2732 +#define Z_UTIL_DEC_2734 2733 +#define Z_UTIL_DEC_2735 2734 +#define Z_UTIL_DEC_2736 2735 +#define Z_UTIL_DEC_2737 2736 +#define Z_UTIL_DEC_2738 2737 +#define Z_UTIL_DEC_2739 2738 +#define Z_UTIL_DEC_2740 2739 +#define Z_UTIL_DEC_2741 2740 +#define Z_UTIL_DEC_2742 2741 +#define Z_UTIL_DEC_2743 2742 +#define Z_UTIL_DEC_2744 2743 +#define Z_UTIL_DEC_2745 2744 +#define Z_UTIL_DEC_2746 2745 +#define Z_UTIL_DEC_2747 2746 +#define Z_UTIL_DEC_2748 2747 +#define Z_UTIL_DEC_2749 2748 +#define Z_UTIL_DEC_2750 2749 +#define Z_UTIL_DEC_2751 2750 +#define Z_UTIL_DEC_2752 2751 +#define Z_UTIL_DEC_2753 2752 +#define Z_UTIL_DEC_2754 2753 +#define Z_UTIL_DEC_2755 2754 +#define Z_UTIL_DEC_2756 2755 +#define Z_UTIL_DEC_2757 2756 +#define Z_UTIL_DEC_2758 2757 +#define Z_UTIL_DEC_2759 2758 +#define Z_UTIL_DEC_2760 2759 +#define Z_UTIL_DEC_2761 2760 +#define Z_UTIL_DEC_2762 2761 +#define Z_UTIL_DEC_2763 2762 +#define Z_UTIL_DEC_2764 2763 +#define Z_UTIL_DEC_2765 2764 +#define Z_UTIL_DEC_2766 2765 +#define Z_UTIL_DEC_2767 2766 +#define Z_UTIL_DEC_2768 2767 +#define Z_UTIL_DEC_2769 2768 +#define Z_UTIL_DEC_2770 2769 +#define Z_UTIL_DEC_2771 2770 +#define Z_UTIL_DEC_2772 2771 +#define Z_UTIL_DEC_2773 2772 +#define Z_UTIL_DEC_2774 2773 +#define Z_UTIL_DEC_2775 2774 +#define Z_UTIL_DEC_2776 2775 +#define Z_UTIL_DEC_2777 2776 +#define Z_UTIL_DEC_2778 2777 +#define Z_UTIL_DEC_2779 2778 +#define Z_UTIL_DEC_2780 2779 +#define Z_UTIL_DEC_2781 2780 +#define Z_UTIL_DEC_2782 2781 +#define Z_UTIL_DEC_2783 2782 +#define Z_UTIL_DEC_2784 2783 +#define Z_UTIL_DEC_2785 2784 +#define Z_UTIL_DEC_2786 2785 +#define Z_UTIL_DEC_2787 2786 +#define Z_UTIL_DEC_2788 2787 +#define Z_UTIL_DEC_2789 2788 +#define Z_UTIL_DEC_2790 2789 +#define Z_UTIL_DEC_2791 2790 +#define Z_UTIL_DEC_2792 2791 +#define Z_UTIL_DEC_2793 2792 +#define Z_UTIL_DEC_2794 2793 +#define Z_UTIL_DEC_2795 2794 +#define Z_UTIL_DEC_2796 2795 +#define Z_UTIL_DEC_2797 2796 +#define Z_UTIL_DEC_2798 2797 +#define Z_UTIL_DEC_2799 2798 +#define Z_UTIL_DEC_2800 2799 +#define Z_UTIL_DEC_2801 2800 +#define Z_UTIL_DEC_2802 2801 +#define Z_UTIL_DEC_2803 2802 +#define Z_UTIL_DEC_2804 2803 +#define Z_UTIL_DEC_2805 2804 +#define Z_UTIL_DEC_2806 2805 +#define Z_UTIL_DEC_2807 2806 +#define Z_UTIL_DEC_2808 2807 +#define Z_UTIL_DEC_2809 2808 +#define Z_UTIL_DEC_2810 2809 +#define Z_UTIL_DEC_2811 2810 +#define Z_UTIL_DEC_2812 2811 +#define Z_UTIL_DEC_2813 2812 +#define Z_UTIL_DEC_2814 2813 +#define Z_UTIL_DEC_2815 2814 +#define Z_UTIL_DEC_2816 2815 +#define Z_UTIL_DEC_2817 2816 +#define Z_UTIL_DEC_2818 2817 +#define Z_UTIL_DEC_2819 2818 +#define Z_UTIL_DEC_2820 2819 +#define Z_UTIL_DEC_2821 2820 +#define Z_UTIL_DEC_2822 2821 +#define Z_UTIL_DEC_2823 2822 +#define Z_UTIL_DEC_2824 2823 +#define Z_UTIL_DEC_2825 2824 +#define Z_UTIL_DEC_2826 2825 +#define Z_UTIL_DEC_2827 2826 +#define Z_UTIL_DEC_2828 2827 +#define Z_UTIL_DEC_2829 2828 +#define Z_UTIL_DEC_2830 2829 +#define Z_UTIL_DEC_2831 2830 +#define Z_UTIL_DEC_2832 2831 +#define Z_UTIL_DEC_2833 2832 +#define Z_UTIL_DEC_2834 2833 +#define Z_UTIL_DEC_2835 2834 +#define Z_UTIL_DEC_2836 2835 +#define Z_UTIL_DEC_2837 2836 +#define Z_UTIL_DEC_2838 2837 +#define Z_UTIL_DEC_2839 2838 +#define Z_UTIL_DEC_2840 2839 +#define Z_UTIL_DEC_2841 2840 +#define Z_UTIL_DEC_2842 2841 +#define Z_UTIL_DEC_2843 2842 +#define Z_UTIL_DEC_2844 2843 +#define Z_UTIL_DEC_2845 2844 +#define Z_UTIL_DEC_2846 2845 +#define Z_UTIL_DEC_2847 2846 +#define Z_UTIL_DEC_2848 2847 +#define Z_UTIL_DEC_2849 2848 +#define Z_UTIL_DEC_2850 2849 +#define Z_UTIL_DEC_2851 2850 +#define Z_UTIL_DEC_2852 2851 +#define Z_UTIL_DEC_2853 2852 +#define Z_UTIL_DEC_2854 2853 +#define Z_UTIL_DEC_2855 2854 +#define Z_UTIL_DEC_2856 2855 +#define Z_UTIL_DEC_2857 2856 +#define Z_UTIL_DEC_2858 2857 +#define Z_UTIL_DEC_2859 2858 +#define Z_UTIL_DEC_2860 2859 +#define Z_UTIL_DEC_2861 2860 +#define Z_UTIL_DEC_2862 2861 +#define Z_UTIL_DEC_2863 2862 +#define Z_UTIL_DEC_2864 2863 +#define Z_UTIL_DEC_2865 2864 +#define Z_UTIL_DEC_2866 2865 +#define Z_UTIL_DEC_2867 2866 +#define Z_UTIL_DEC_2868 2867 +#define Z_UTIL_DEC_2869 2868 +#define Z_UTIL_DEC_2870 2869 +#define Z_UTIL_DEC_2871 2870 +#define Z_UTIL_DEC_2872 2871 +#define Z_UTIL_DEC_2873 2872 +#define Z_UTIL_DEC_2874 2873 +#define Z_UTIL_DEC_2875 2874 +#define Z_UTIL_DEC_2876 2875 +#define Z_UTIL_DEC_2877 2876 +#define Z_UTIL_DEC_2878 2877 +#define Z_UTIL_DEC_2879 2878 +#define Z_UTIL_DEC_2880 2879 +#define Z_UTIL_DEC_2881 2880 +#define Z_UTIL_DEC_2882 2881 +#define Z_UTIL_DEC_2883 2882 +#define Z_UTIL_DEC_2884 2883 +#define Z_UTIL_DEC_2885 2884 +#define Z_UTIL_DEC_2886 2885 +#define Z_UTIL_DEC_2887 2886 +#define Z_UTIL_DEC_2888 2887 +#define Z_UTIL_DEC_2889 2888 +#define Z_UTIL_DEC_2890 2889 +#define Z_UTIL_DEC_2891 2890 +#define Z_UTIL_DEC_2892 2891 +#define Z_UTIL_DEC_2893 2892 +#define Z_UTIL_DEC_2894 2893 +#define Z_UTIL_DEC_2895 2894 +#define Z_UTIL_DEC_2896 2895 +#define Z_UTIL_DEC_2897 2896 +#define Z_UTIL_DEC_2898 2897 +#define Z_UTIL_DEC_2899 2898 +#define Z_UTIL_DEC_2900 2899 +#define Z_UTIL_DEC_2901 2900 +#define Z_UTIL_DEC_2902 2901 +#define Z_UTIL_DEC_2903 2902 +#define Z_UTIL_DEC_2904 2903 +#define Z_UTIL_DEC_2905 2904 +#define Z_UTIL_DEC_2906 2905 +#define Z_UTIL_DEC_2907 2906 +#define Z_UTIL_DEC_2908 2907 +#define Z_UTIL_DEC_2909 2908 +#define Z_UTIL_DEC_2910 2909 +#define Z_UTIL_DEC_2911 2910 +#define Z_UTIL_DEC_2912 2911 +#define Z_UTIL_DEC_2913 2912 +#define Z_UTIL_DEC_2914 2913 +#define Z_UTIL_DEC_2915 2914 +#define Z_UTIL_DEC_2916 2915 +#define Z_UTIL_DEC_2917 2916 +#define Z_UTIL_DEC_2918 2917 +#define Z_UTIL_DEC_2919 2918 +#define Z_UTIL_DEC_2920 2919 +#define Z_UTIL_DEC_2921 2920 +#define Z_UTIL_DEC_2922 2921 +#define Z_UTIL_DEC_2923 2922 +#define Z_UTIL_DEC_2924 2923 +#define Z_UTIL_DEC_2925 2924 +#define Z_UTIL_DEC_2926 2925 +#define Z_UTIL_DEC_2927 2926 +#define Z_UTIL_DEC_2928 2927 +#define Z_UTIL_DEC_2929 2928 +#define Z_UTIL_DEC_2930 2929 +#define Z_UTIL_DEC_2931 2930 +#define Z_UTIL_DEC_2932 2931 +#define Z_UTIL_DEC_2933 2932 +#define Z_UTIL_DEC_2934 2933 +#define Z_UTIL_DEC_2935 2934 +#define Z_UTIL_DEC_2936 2935 +#define Z_UTIL_DEC_2937 2936 +#define Z_UTIL_DEC_2938 2937 +#define Z_UTIL_DEC_2939 2938 +#define Z_UTIL_DEC_2940 2939 +#define Z_UTIL_DEC_2941 2940 +#define Z_UTIL_DEC_2942 2941 +#define Z_UTIL_DEC_2943 2942 +#define Z_UTIL_DEC_2944 2943 +#define Z_UTIL_DEC_2945 2944 +#define Z_UTIL_DEC_2946 2945 +#define Z_UTIL_DEC_2947 2946 +#define Z_UTIL_DEC_2948 2947 +#define Z_UTIL_DEC_2949 2948 +#define Z_UTIL_DEC_2950 2949 +#define Z_UTIL_DEC_2951 2950 +#define Z_UTIL_DEC_2952 2951 +#define Z_UTIL_DEC_2953 2952 +#define Z_UTIL_DEC_2954 2953 +#define Z_UTIL_DEC_2955 2954 +#define Z_UTIL_DEC_2956 2955 +#define Z_UTIL_DEC_2957 2956 +#define Z_UTIL_DEC_2958 2957 +#define Z_UTIL_DEC_2959 2958 +#define Z_UTIL_DEC_2960 2959 +#define Z_UTIL_DEC_2961 2960 +#define Z_UTIL_DEC_2962 2961 +#define Z_UTIL_DEC_2963 2962 +#define Z_UTIL_DEC_2964 2963 +#define Z_UTIL_DEC_2965 2964 +#define Z_UTIL_DEC_2966 2965 +#define Z_UTIL_DEC_2967 2966 +#define Z_UTIL_DEC_2968 2967 +#define Z_UTIL_DEC_2969 2968 +#define Z_UTIL_DEC_2970 2969 +#define Z_UTIL_DEC_2971 2970 +#define Z_UTIL_DEC_2972 2971 +#define Z_UTIL_DEC_2973 2972 +#define Z_UTIL_DEC_2974 2973 +#define Z_UTIL_DEC_2975 2974 +#define Z_UTIL_DEC_2976 2975 +#define Z_UTIL_DEC_2977 2976 +#define Z_UTIL_DEC_2978 2977 +#define Z_UTIL_DEC_2979 2978 +#define Z_UTIL_DEC_2980 2979 +#define Z_UTIL_DEC_2981 2980 +#define Z_UTIL_DEC_2982 2981 +#define Z_UTIL_DEC_2983 2982 +#define Z_UTIL_DEC_2984 2983 +#define Z_UTIL_DEC_2985 2984 +#define Z_UTIL_DEC_2986 2985 +#define Z_UTIL_DEC_2987 2986 +#define Z_UTIL_DEC_2988 2987 +#define Z_UTIL_DEC_2989 2988 +#define Z_UTIL_DEC_2990 2989 +#define Z_UTIL_DEC_2991 2990 +#define Z_UTIL_DEC_2992 2991 +#define Z_UTIL_DEC_2993 2992 +#define Z_UTIL_DEC_2994 2993 +#define Z_UTIL_DEC_2995 2994 +#define Z_UTIL_DEC_2996 2995 +#define Z_UTIL_DEC_2997 2996 +#define Z_UTIL_DEC_2998 2997 +#define Z_UTIL_DEC_2999 2998 +#define Z_UTIL_DEC_3000 2999 +#define Z_UTIL_DEC_3001 3000 +#define Z_UTIL_DEC_3002 3001 +#define Z_UTIL_DEC_3003 3002 +#define Z_UTIL_DEC_3004 3003 +#define Z_UTIL_DEC_3005 3004 +#define Z_UTIL_DEC_3006 3005 +#define Z_UTIL_DEC_3007 3006 +#define Z_UTIL_DEC_3008 3007 +#define Z_UTIL_DEC_3009 3008 +#define Z_UTIL_DEC_3010 3009 +#define Z_UTIL_DEC_3011 3010 +#define Z_UTIL_DEC_3012 3011 +#define Z_UTIL_DEC_3013 3012 +#define Z_UTIL_DEC_3014 3013 +#define Z_UTIL_DEC_3015 3014 +#define Z_UTIL_DEC_3016 3015 +#define Z_UTIL_DEC_3017 3016 +#define Z_UTIL_DEC_3018 3017 +#define Z_UTIL_DEC_3019 3018 +#define Z_UTIL_DEC_3020 3019 +#define Z_UTIL_DEC_3021 3020 +#define Z_UTIL_DEC_3022 3021 +#define Z_UTIL_DEC_3023 3022 +#define Z_UTIL_DEC_3024 3023 +#define Z_UTIL_DEC_3025 3024 +#define Z_UTIL_DEC_3026 3025 +#define Z_UTIL_DEC_3027 3026 +#define Z_UTIL_DEC_3028 3027 +#define Z_UTIL_DEC_3029 3028 +#define Z_UTIL_DEC_3030 3029 +#define Z_UTIL_DEC_3031 3030 +#define Z_UTIL_DEC_3032 3031 +#define Z_UTIL_DEC_3033 3032 +#define Z_UTIL_DEC_3034 3033 +#define Z_UTIL_DEC_3035 3034 +#define Z_UTIL_DEC_3036 3035 +#define Z_UTIL_DEC_3037 3036 +#define Z_UTIL_DEC_3038 3037 +#define Z_UTIL_DEC_3039 3038 +#define Z_UTIL_DEC_3040 3039 +#define Z_UTIL_DEC_3041 3040 +#define Z_UTIL_DEC_3042 3041 +#define Z_UTIL_DEC_3043 3042 +#define Z_UTIL_DEC_3044 3043 +#define Z_UTIL_DEC_3045 3044 +#define Z_UTIL_DEC_3046 3045 +#define Z_UTIL_DEC_3047 3046 +#define Z_UTIL_DEC_3048 3047 +#define Z_UTIL_DEC_3049 3048 +#define Z_UTIL_DEC_3050 3049 +#define Z_UTIL_DEC_3051 3050 +#define Z_UTIL_DEC_3052 3051 +#define Z_UTIL_DEC_3053 3052 +#define Z_UTIL_DEC_3054 3053 +#define Z_UTIL_DEC_3055 3054 +#define Z_UTIL_DEC_3056 3055 +#define Z_UTIL_DEC_3057 3056 +#define Z_UTIL_DEC_3058 3057 +#define Z_UTIL_DEC_3059 3058 +#define Z_UTIL_DEC_3060 3059 +#define Z_UTIL_DEC_3061 3060 +#define Z_UTIL_DEC_3062 3061 +#define Z_UTIL_DEC_3063 3062 +#define Z_UTIL_DEC_3064 3063 +#define Z_UTIL_DEC_3065 3064 +#define Z_UTIL_DEC_3066 3065 +#define Z_UTIL_DEC_3067 3066 +#define Z_UTIL_DEC_3068 3067 +#define Z_UTIL_DEC_3069 3068 +#define Z_UTIL_DEC_3070 3069 +#define Z_UTIL_DEC_3071 3070 +#define Z_UTIL_DEC_3072 3071 +#define Z_UTIL_DEC_3073 3072 +#define Z_UTIL_DEC_3074 3073 +#define Z_UTIL_DEC_3075 3074 +#define Z_UTIL_DEC_3076 3075 +#define Z_UTIL_DEC_3077 3076 +#define Z_UTIL_DEC_3078 3077 +#define Z_UTIL_DEC_3079 3078 +#define Z_UTIL_DEC_3080 3079 +#define Z_UTIL_DEC_3081 3080 +#define Z_UTIL_DEC_3082 3081 +#define Z_UTIL_DEC_3083 3082 +#define Z_UTIL_DEC_3084 3083 +#define Z_UTIL_DEC_3085 3084 +#define Z_UTIL_DEC_3086 3085 +#define Z_UTIL_DEC_3087 3086 +#define Z_UTIL_DEC_3088 3087 +#define Z_UTIL_DEC_3089 3088 +#define Z_UTIL_DEC_3090 3089 +#define Z_UTIL_DEC_3091 3090 +#define Z_UTIL_DEC_3092 3091 +#define Z_UTIL_DEC_3093 3092 +#define Z_UTIL_DEC_3094 3093 +#define Z_UTIL_DEC_3095 3094 +#define Z_UTIL_DEC_3096 3095 +#define Z_UTIL_DEC_3097 3096 +#define Z_UTIL_DEC_3098 3097 +#define Z_UTIL_DEC_3099 3098 +#define Z_UTIL_DEC_3100 3099 +#define Z_UTIL_DEC_3101 3100 +#define Z_UTIL_DEC_3102 3101 +#define Z_UTIL_DEC_3103 3102 +#define Z_UTIL_DEC_3104 3103 +#define Z_UTIL_DEC_3105 3104 +#define Z_UTIL_DEC_3106 3105 +#define Z_UTIL_DEC_3107 3106 +#define Z_UTIL_DEC_3108 3107 +#define Z_UTIL_DEC_3109 3108 +#define Z_UTIL_DEC_3110 3109 +#define Z_UTIL_DEC_3111 3110 +#define Z_UTIL_DEC_3112 3111 +#define Z_UTIL_DEC_3113 3112 +#define Z_UTIL_DEC_3114 3113 +#define Z_UTIL_DEC_3115 3114 +#define Z_UTIL_DEC_3116 3115 +#define Z_UTIL_DEC_3117 3116 +#define Z_UTIL_DEC_3118 3117 +#define Z_UTIL_DEC_3119 3118 +#define Z_UTIL_DEC_3120 3119 +#define Z_UTIL_DEC_3121 3120 +#define Z_UTIL_DEC_3122 3121 +#define Z_UTIL_DEC_3123 3122 +#define Z_UTIL_DEC_3124 3123 +#define Z_UTIL_DEC_3125 3124 +#define Z_UTIL_DEC_3126 3125 +#define Z_UTIL_DEC_3127 3126 +#define Z_UTIL_DEC_3128 3127 +#define Z_UTIL_DEC_3129 3128 +#define Z_UTIL_DEC_3130 3129 +#define Z_UTIL_DEC_3131 3130 +#define Z_UTIL_DEC_3132 3131 +#define Z_UTIL_DEC_3133 3132 +#define Z_UTIL_DEC_3134 3133 +#define Z_UTIL_DEC_3135 3134 +#define Z_UTIL_DEC_3136 3135 +#define Z_UTIL_DEC_3137 3136 +#define Z_UTIL_DEC_3138 3137 +#define Z_UTIL_DEC_3139 3138 +#define Z_UTIL_DEC_3140 3139 +#define Z_UTIL_DEC_3141 3140 +#define Z_UTIL_DEC_3142 3141 +#define Z_UTIL_DEC_3143 3142 +#define Z_UTIL_DEC_3144 3143 +#define Z_UTIL_DEC_3145 3144 +#define Z_UTIL_DEC_3146 3145 +#define Z_UTIL_DEC_3147 3146 +#define Z_UTIL_DEC_3148 3147 +#define Z_UTIL_DEC_3149 3148 +#define Z_UTIL_DEC_3150 3149 +#define Z_UTIL_DEC_3151 3150 +#define Z_UTIL_DEC_3152 3151 +#define Z_UTIL_DEC_3153 3152 +#define Z_UTIL_DEC_3154 3153 +#define Z_UTIL_DEC_3155 3154 +#define Z_UTIL_DEC_3156 3155 +#define Z_UTIL_DEC_3157 3156 +#define Z_UTIL_DEC_3158 3157 +#define Z_UTIL_DEC_3159 3158 +#define Z_UTIL_DEC_3160 3159 +#define Z_UTIL_DEC_3161 3160 +#define Z_UTIL_DEC_3162 3161 +#define Z_UTIL_DEC_3163 3162 +#define Z_UTIL_DEC_3164 3163 +#define Z_UTIL_DEC_3165 3164 +#define Z_UTIL_DEC_3166 3165 +#define Z_UTIL_DEC_3167 3166 +#define Z_UTIL_DEC_3168 3167 +#define Z_UTIL_DEC_3169 3168 +#define Z_UTIL_DEC_3170 3169 +#define Z_UTIL_DEC_3171 3170 +#define Z_UTIL_DEC_3172 3171 +#define Z_UTIL_DEC_3173 3172 +#define Z_UTIL_DEC_3174 3173 +#define Z_UTIL_DEC_3175 3174 +#define Z_UTIL_DEC_3176 3175 +#define Z_UTIL_DEC_3177 3176 +#define Z_UTIL_DEC_3178 3177 +#define Z_UTIL_DEC_3179 3178 +#define Z_UTIL_DEC_3180 3179 +#define Z_UTIL_DEC_3181 3180 +#define Z_UTIL_DEC_3182 3181 +#define Z_UTIL_DEC_3183 3182 +#define Z_UTIL_DEC_3184 3183 +#define Z_UTIL_DEC_3185 3184 +#define Z_UTIL_DEC_3186 3185 +#define Z_UTIL_DEC_3187 3186 +#define Z_UTIL_DEC_3188 3187 +#define Z_UTIL_DEC_3189 3188 +#define Z_UTIL_DEC_3190 3189 +#define Z_UTIL_DEC_3191 3190 +#define Z_UTIL_DEC_3192 3191 +#define Z_UTIL_DEC_3193 3192 +#define Z_UTIL_DEC_3194 3193 +#define Z_UTIL_DEC_3195 3194 +#define Z_UTIL_DEC_3196 3195 +#define Z_UTIL_DEC_3197 3196 +#define Z_UTIL_DEC_3198 3197 +#define Z_UTIL_DEC_3199 3198 +#define Z_UTIL_DEC_3200 3199 +#define Z_UTIL_DEC_3201 3200 +#define Z_UTIL_DEC_3202 3201 +#define Z_UTIL_DEC_3203 3202 +#define Z_UTIL_DEC_3204 3203 +#define Z_UTIL_DEC_3205 3204 +#define Z_UTIL_DEC_3206 3205 +#define Z_UTIL_DEC_3207 3206 +#define Z_UTIL_DEC_3208 3207 +#define Z_UTIL_DEC_3209 3208 +#define Z_UTIL_DEC_3210 3209 +#define Z_UTIL_DEC_3211 3210 +#define Z_UTIL_DEC_3212 3211 +#define Z_UTIL_DEC_3213 3212 +#define Z_UTIL_DEC_3214 3213 +#define Z_UTIL_DEC_3215 3214 +#define Z_UTIL_DEC_3216 3215 +#define Z_UTIL_DEC_3217 3216 +#define Z_UTIL_DEC_3218 3217 +#define Z_UTIL_DEC_3219 3218 +#define Z_UTIL_DEC_3220 3219 +#define Z_UTIL_DEC_3221 3220 +#define Z_UTIL_DEC_3222 3221 +#define Z_UTIL_DEC_3223 3222 +#define Z_UTIL_DEC_3224 3223 +#define Z_UTIL_DEC_3225 3224 +#define Z_UTIL_DEC_3226 3225 +#define Z_UTIL_DEC_3227 3226 +#define Z_UTIL_DEC_3228 3227 +#define Z_UTIL_DEC_3229 3228 +#define Z_UTIL_DEC_3230 3229 +#define Z_UTIL_DEC_3231 3230 +#define Z_UTIL_DEC_3232 3231 +#define Z_UTIL_DEC_3233 3232 +#define Z_UTIL_DEC_3234 3233 +#define Z_UTIL_DEC_3235 3234 +#define Z_UTIL_DEC_3236 3235 +#define Z_UTIL_DEC_3237 3236 +#define Z_UTIL_DEC_3238 3237 +#define Z_UTIL_DEC_3239 3238 +#define Z_UTIL_DEC_3240 3239 +#define Z_UTIL_DEC_3241 3240 +#define Z_UTIL_DEC_3242 3241 +#define Z_UTIL_DEC_3243 3242 +#define Z_UTIL_DEC_3244 3243 +#define Z_UTIL_DEC_3245 3244 +#define Z_UTIL_DEC_3246 3245 +#define Z_UTIL_DEC_3247 3246 +#define Z_UTIL_DEC_3248 3247 +#define Z_UTIL_DEC_3249 3248 +#define Z_UTIL_DEC_3250 3249 +#define Z_UTIL_DEC_3251 3250 +#define Z_UTIL_DEC_3252 3251 +#define Z_UTIL_DEC_3253 3252 +#define Z_UTIL_DEC_3254 3253 +#define Z_UTIL_DEC_3255 3254 +#define Z_UTIL_DEC_3256 3255 +#define Z_UTIL_DEC_3257 3256 +#define Z_UTIL_DEC_3258 3257 +#define Z_UTIL_DEC_3259 3258 +#define Z_UTIL_DEC_3260 3259 +#define Z_UTIL_DEC_3261 3260 +#define Z_UTIL_DEC_3262 3261 +#define Z_UTIL_DEC_3263 3262 +#define Z_UTIL_DEC_3264 3263 +#define Z_UTIL_DEC_3265 3264 +#define Z_UTIL_DEC_3266 3265 +#define Z_UTIL_DEC_3267 3266 +#define Z_UTIL_DEC_3268 3267 +#define Z_UTIL_DEC_3269 3268 +#define Z_UTIL_DEC_3270 3269 +#define Z_UTIL_DEC_3271 3270 +#define Z_UTIL_DEC_3272 3271 +#define Z_UTIL_DEC_3273 3272 +#define Z_UTIL_DEC_3274 3273 +#define Z_UTIL_DEC_3275 3274 +#define Z_UTIL_DEC_3276 3275 +#define Z_UTIL_DEC_3277 3276 +#define Z_UTIL_DEC_3278 3277 +#define Z_UTIL_DEC_3279 3278 +#define Z_UTIL_DEC_3280 3279 +#define Z_UTIL_DEC_3281 3280 +#define Z_UTIL_DEC_3282 3281 +#define Z_UTIL_DEC_3283 3282 +#define Z_UTIL_DEC_3284 3283 +#define Z_UTIL_DEC_3285 3284 +#define Z_UTIL_DEC_3286 3285 +#define Z_UTIL_DEC_3287 3286 +#define Z_UTIL_DEC_3288 3287 +#define Z_UTIL_DEC_3289 3288 +#define Z_UTIL_DEC_3290 3289 +#define Z_UTIL_DEC_3291 3290 +#define Z_UTIL_DEC_3292 3291 +#define Z_UTIL_DEC_3293 3292 +#define Z_UTIL_DEC_3294 3293 +#define Z_UTIL_DEC_3295 3294 +#define Z_UTIL_DEC_3296 3295 +#define Z_UTIL_DEC_3297 3296 +#define Z_UTIL_DEC_3298 3297 +#define Z_UTIL_DEC_3299 3298 +#define Z_UTIL_DEC_3300 3299 +#define Z_UTIL_DEC_3301 3300 +#define Z_UTIL_DEC_3302 3301 +#define Z_UTIL_DEC_3303 3302 +#define Z_UTIL_DEC_3304 3303 +#define Z_UTIL_DEC_3305 3304 +#define Z_UTIL_DEC_3306 3305 +#define Z_UTIL_DEC_3307 3306 +#define Z_UTIL_DEC_3308 3307 +#define Z_UTIL_DEC_3309 3308 +#define Z_UTIL_DEC_3310 3309 +#define Z_UTIL_DEC_3311 3310 +#define Z_UTIL_DEC_3312 3311 +#define Z_UTIL_DEC_3313 3312 +#define Z_UTIL_DEC_3314 3313 +#define Z_UTIL_DEC_3315 3314 +#define Z_UTIL_DEC_3316 3315 +#define Z_UTIL_DEC_3317 3316 +#define Z_UTIL_DEC_3318 3317 +#define Z_UTIL_DEC_3319 3318 +#define Z_UTIL_DEC_3320 3319 +#define Z_UTIL_DEC_3321 3320 +#define Z_UTIL_DEC_3322 3321 +#define Z_UTIL_DEC_3323 3322 +#define Z_UTIL_DEC_3324 3323 +#define Z_UTIL_DEC_3325 3324 +#define Z_UTIL_DEC_3326 3325 +#define Z_UTIL_DEC_3327 3326 +#define Z_UTIL_DEC_3328 3327 +#define Z_UTIL_DEC_3329 3328 +#define Z_UTIL_DEC_3330 3329 +#define Z_UTIL_DEC_3331 3330 +#define Z_UTIL_DEC_3332 3331 +#define Z_UTIL_DEC_3333 3332 +#define Z_UTIL_DEC_3334 3333 +#define Z_UTIL_DEC_3335 3334 +#define Z_UTIL_DEC_3336 3335 +#define Z_UTIL_DEC_3337 3336 +#define Z_UTIL_DEC_3338 3337 +#define Z_UTIL_DEC_3339 3338 +#define Z_UTIL_DEC_3340 3339 +#define Z_UTIL_DEC_3341 3340 +#define Z_UTIL_DEC_3342 3341 +#define Z_UTIL_DEC_3343 3342 +#define Z_UTIL_DEC_3344 3343 +#define Z_UTIL_DEC_3345 3344 +#define Z_UTIL_DEC_3346 3345 +#define Z_UTIL_DEC_3347 3346 +#define Z_UTIL_DEC_3348 3347 +#define Z_UTIL_DEC_3349 3348 +#define Z_UTIL_DEC_3350 3349 +#define Z_UTIL_DEC_3351 3350 +#define Z_UTIL_DEC_3352 3351 +#define Z_UTIL_DEC_3353 3352 +#define Z_UTIL_DEC_3354 3353 +#define Z_UTIL_DEC_3355 3354 +#define Z_UTIL_DEC_3356 3355 +#define Z_UTIL_DEC_3357 3356 +#define Z_UTIL_DEC_3358 3357 +#define Z_UTIL_DEC_3359 3358 +#define Z_UTIL_DEC_3360 3359 +#define Z_UTIL_DEC_3361 3360 +#define Z_UTIL_DEC_3362 3361 +#define Z_UTIL_DEC_3363 3362 +#define Z_UTIL_DEC_3364 3363 +#define Z_UTIL_DEC_3365 3364 +#define Z_UTIL_DEC_3366 3365 +#define Z_UTIL_DEC_3367 3366 +#define Z_UTIL_DEC_3368 3367 +#define Z_UTIL_DEC_3369 3368 +#define Z_UTIL_DEC_3370 3369 +#define Z_UTIL_DEC_3371 3370 +#define Z_UTIL_DEC_3372 3371 +#define Z_UTIL_DEC_3373 3372 +#define Z_UTIL_DEC_3374 3373 +#define Z_UTIL_DEC_3375 3374 +#define Z_UTIL_DEC_3376 3375 +#define Z_UTIL_DEC_3377 3376 +#define Z_UTIL_DEC_3378 3377 +#define Z_UTIL_DEC_3379 3378 +#define Z_UTIL_DEC_3380 3379 +#define Z_UTIL_DEC_3381 3380 +#define Z_UTIL_DEC_3382 3381 +#define Z_UTIL_DEC_3383 3382 +#define Z_UTIL_DEC_3384 3383 +#define Z_UTIL_DEC_3385 3384 +#define Z_UTIL_DEC_3386 3385 +#define Z_UTIL_DEC_3387 3386 +#define Z_UTIL_DEC_3388 3387 +#define Z_UTIL_DEC_3389 3388 +#define Z_UTIL_DEC_3390 3389 +#define Z_UTIL_DEC_3391 3390 +#define Z_UTIL_DEC_3392 3391 +#define Z_UTIL_DEC_3393 3392 +#define Z_UTIL_DEC_3394 3393 +#define Z_UTIL_DEC_3395 3394 +#define Z_UTIL_DEC_3396 3395 +#define Z_UTIL_DEC_3397 3396 +#define Z_UTIL_DEC_3398 3397 +#define Z_UTIL_DEC_3399 3398 +#define Z_UTIL_DEC_3400 3399 +#define Z_UTIL_DEC_3401 3400 +#define Z_UTIL_DEC_3402 3401 +#define Z_UTIL_DEC_3403 3402 +#define Z_UTIL_DEC_3404 3403 +#define Z_UTIL_DEC_3405 3404 +#define Z_UTIL_DEC_3406 3405 +#define Z_UTIL_DEC_3407 3406 +#define Z_UTIL_DEC_3408 3407 +#define Z_UTIL_DEC_3409 3408 +#define Z_UTIL_DEC_3410 3409 +#define Z_UTIL_DEC_3411 3410 +#define Z_UTIL_DEC_3412 3411 +#define Z_UTIL_DEC_3413 3412 +#define Z_UTIL_DEC_3414 3413 +#define Z_UTIL_DEC_3415 3414 +#define Z_UTIL_DEC_3416 3415 +#define Z_UTIL_DEC_3417 3416 +#define Z_UTIL_DEC_3418 3417 +#define Z_UTIL_DEC_3419 3418 +#define Z_UTIL_DEC_3420 3419 +#define Z_UTIL_DEC_3421 3420 +#define Z_UTIL_DEC_3422 3421 +#define Z_UTIL_DEC_3423 3422 +#define Z_UTIL_DEC_3424 3423 +#define Z_UTIL_DEC_3425 3424 +#define Z_UTIL_DEC_3426 3425 +#define Z_UTIL_DEC_3427 3426 +#define Z_UTIL_DEC_3428 3427 +#define Z_UTIL_DEC_3429 3428 +#define Z_UTIL_DEC_3430 3429 +#define Z_UTIL_DEC_3431 3430 +#define Z_UTIL_DEC_3432 3431 +#define Z_UTIL_DEC_3433 3432 +#define Z_UTIL_DEC_3434 3433 +#define Z_UTIL_DEC_3435 3434 +#define Z_UTIL_DEC_3436 3435 +#define Z_UTIL_DEC_3437 3436 +#define Z_UTIL_DEC_3438 3437 +#define Z_UTIL_DEC_3439 3438 +#define Z_UTIL_DEC_3440 3439 +#define Z_UTIL_DEC_3441 3440 +#define Z_UTIL_DEC_3442 3441 +#define Z_UTIL_DEC_3443 3442 +#define Z_UTIL_DEC_3444 3443 +#define Z_UTIL_DEC_3445 3444 +#define Z_UTIL_DEC_3446 3445 +#define Z_UTIL_DEC_3447 3446 +#define Z_UTIL_DEC_3448 3447 +#define Z_UTIL_DEC_3449 3448 +#define Z_UTIL_DEC_3450 3449 +#define Z_UTIL_DEC_3451 3450 +#define Z_UTIL_DEC_3452 3451 +#define Z_UTIL_DEC_3453 3452 +#define Z_UTIL_DEC_3454 3453 +#define Z_UTIL_DEC_3455 3454 +#define Z_UTIL_DEC_3456 3455 +#define Z_UTIL_DEC_3457 3456 +#define Z_UTIL_DEC_3458 3457 +#define Z_UTIL_DEC_3459 3458 +#define Z_UTIL_DEC_3460 3459 +#define Z_UTIL_DEC_3461 3460 +#define Z_UTIL_DEC_3462 3461 +#define Z_UTIL_DEC_3463 3462 +#define Z_UTIL_DEC_3464 3463 +#define Z_UTIL_DEC_3465 3464 +#define Z_UTIL_DEC_3466 3465 +#define Z_UTIL_DEC_3467 3466 +#define Z_UTIL_DEC_3468 3467 +#define Z_UTIL_DEC_3469 3468 +#define Z_UTIL_DEC_3470 3469 +#define Z_UTIL_DEC_3471 3470 +#define Z_UTIL_DEC_3472 3471 +#define Z_UTIL_DEC_3473 3472 +#define Z_UTIL_DEC_3474 3473 +#define Z_UTIL_DEC_3475 3474 +#define Z_UTIL_DEC_3476 3475 +#define Z_UTIL_DEC_3477 3476 +#define Z_UTIL_DEC_3478 3477 +#define Z_UTIL_DEC_3479 3478 +#define Z_UTIL_DEC_3480 3479 +#define Z_UTIL_DEC_3481 3480 +#define Z_UTIL_DEC_3482 3481 +#define Z_UTIL_DEC_3483 3482 +#define Z_UTIL_DEC_3484 3483 +#define Z_UTIL_DEC_3485 3484 +#define Z_UTIL_DEC_3486 3485 +#define Z_UTIL_DEC_3487 3486 +#define Z_UTIL_DEC_3488 3487 +#define Z_UTIL_DEC_3489 3488 +#define Z_UTIL_DEC_3490 3489 +#define Z_UTIL_DEC_3491 3490 +#define Z_UTIL_DEC_3492 3491 +#define Z_UTIL_DEC_3493 3492 +#define Z_UTIL_DEC_3494 3493 +#define Z_UTIL_DEC_3495 3494 +#define Z_UTIL_DEC_3496 3495 +#define Z_UTIL_DEC_3497 3496 +#define Z_UTIL_DEC_3498 3497 +#define Z_UTIL_DEC_3499 3498 +#define Z_UTIL_DEC_3500 3499 +#define Z_UTIL_DEC_3501 3500 +#define Z_UTIL_DEC_3502 3501 +#define Z_UTIL_DEC_3503 3502 +#define Z_UTIL_DEC_3504 3503 +#define Z_UTIL_DEC_3505 3504 +#define Z_UTIL_DEC_3506 3505 +#define Z_UTIL_DEC_3507 3506 +#define Z_UTIL_DEC_3508 3507 +#define Z_UTIL_DEC_3509 3508 +#define Z_UTIL_DEC_3510 3509 +#define Z_UTIL_DEC_3511 3510 +#define Z_UTIL_DEC_3512 3511 +#define Z_UTIL_DEC_3513 3512 +#define Z_UTIL_DEC_3514 3513 +#define Z_UTIL_DEC_3515 3514 +#define Z_UTIL_DEC_3516 3515 +#define Z_UTIL_DEC_3517 3516 +#define Z_UTIL_DEC_3518 3517 +#define Z_UTIL_DEC_3519 3518 +#define Z_UTIL_DEC_3520 3519 +#define Z_UTIL_DEC_3521 3520 +#define Z_UTIL_DEC_3522 3521 +#define Z_UTIL_DEC_3523 3522 +#define Z_UTIL_DEC_3524 3523 +#define Z_UTIL_DEC_3525 3524 +#define Z_UTIL_DEC_3526 3525 +#define Z_UTIL_DEC_3527 3526 +#define Z_UTIL_DEC_3528 3527 +#define Z_UTIL_DEC_3529 3528 +#define Z_UTIL_DEC_3530 3529 +#define Z_UTIL_DEC_3531 3530 +#define Z_UTIL_DEC_3532 3531 +#define Z_UTIL_DEC_3533 3532 +#define Z_UTIL_DEC_3534 3533 +#define Z_UTIL_DEC_3535 3534 +#define Z_UTIL_DEC_3536 3535 +#define Z_UTIL_DEC_3537 3536 +#define Z_UTIL_DEC_3538 3537 +#define Z_UTIL_DEC_3539 3538 +#define Z_UTIL_DEC_3540 3539 +#define Z_UTIL_DEC_3541 3540 +#define Z_UTIL_DEC_3542 3541 +#define Z_UTIL_DEC_3543 3542 +#define Z_UTIL_DEC_3544 3543 +#define Z_UTIL_DEC_3545 3544 +#define Z_UTIL_DEC_3546 3545 +#define Z_UTIL_DEC_3547 3546 +#define Z_UTIL_DEC_3548 3547 +#define Z_UTIL_DEC_3549 3548 +#define Z_UTIL_DEC_3550 3549 +#define Z_UTIL_DEC_3551 3550 +#define Z_UTIL_DEC_3552 3551 +#define Z_UTIL_DEC_3553 3552 +#define Z_UTIL_DEC_3554 3553 +#define Z_UTIL_DEC_3555 3554 +#define Z_UTIL_DEC_3556 3555 +#define Z_UTIL_DEC_3557 3556 +#define Z_UTIL_DEC_3558 3557 +#define Z_UTIL_DEC_3559 3558 +#define Z_UTIL_DEC_3560 3559 +#define Z_UTIL_DEC_3561 3560 +#define Z_UTIL_DEC_3562 3561 +#define Z_UTIL_DEC_3563 3562 +#define Z_UTIL_DEC_3564 3563 +#define Z_UTIL_DEC_3565 3564 +#define Z_UTIL_DEC_3566 3565 +#define Z_UTIL_DEC_3567 3566 +#define Z_UTIL_DEC_3568 3567 +#define Z_UTIL_DEC_3569 3568 +#define Z_UTIL_DEC_3570 3569 +#define Z_UTIL_DEC_3571 3570 +#define Z_UTIL_DEC_3572 3571 +#define Z_UTIL_DEC_3573 3572 +#define Z_UTIL_DEC_3574 3573 +#define Z_UTIL_DEC_3575 3574 +#define Z_UTIL_DEC_3576 3575 +#define Z_UTIL_DEC_3577 3576 +#define Z_UTIL_DEC_3578 3577 +#define Z_UTIL_DEC_3579 3578 +#define Z_UTIL_DEC_3580 3579 +#define Z_UTIL_DEC_3581 3580 +#define Z_UTIL_DEC_3582 3581 +#define Z_UTIL_DEC_3583 3582 +#define Z_UTIL_DEC_3584 3583 +#define Z_UTIL_DEC_3585 3584 +#define Z_UTIL_DEC_3586 3585 +#define Z_UTIL_DEC_3587 3586 +#define Z_UTIL_DEC_3588 3587 +#define Z_UTIL_DEC_3589 3588 +#define Z_UTIL_DEC_3590 3589 +#define Z_UTIL_DEC_3591 3590 +#define Z_UTIL_DEC_3592 3591 +#define Z_UTIL_DEC_3593 3592 +#define Z_UTIL_DEC_3594 3593 +#define Z_UTIL_DEC_3595 3594 +#define Z_UTIL_DEC_3596 3595 +#define Z_UTIL_DEC_3597 3596 +#define Z_UTIL_DEC_3598 3597 +#define Z_UTIL_DEC_3599 3598 +#define Z_UTIL_DEC_3600 3599 +#define Z_UTIL_DEC_3601 3600 +#define Z_UTIL_DEC_3602 3601 +#define Z_UTIL_DEC_3603 3602 +#define Z_UTIL_DEC_3604 3603 +#define Z_UTIL_DEC_3605 3604 +#define Z_UTIL_DEC_3606 3605 +#define Z_UTIL_DEC_3607 3606 +#define Z_UTIL_DEC_3608 3607 +#define Z_UTIL_DEC_3609 3608 +#define Z_UTIL_DEC_3610 3609 +#define Z_UTIL_DEC_3611 3610 +#define Z_UTIL_DEC_3612 3611 +#define Z_UTIL_DEC_3613 3612 +#define Z_UTIL_DEC_3614 3613 +#define Z_UTIL_DEC_3615 3614 +#define Z_UTIL_DEC_3616 3615 +#define Z_UTIL_DEC_3617 3616 +#define Z_UTIL_DEC_3618 3617 +#define Z_UTIL_DEC_3619 3618 +#define Z_UTIL_DEC_3620 3619 +#define Z_UTIL_DEC_3621 3620 +#define Z_UTIL_DEC_3622 3621 +#define Z_UTIL_DEC_3623 3622 +#define Z_UTIL_DEC_3624 3623 +#define Z_UTIL_DEC_3625 3624 +#define Z_UTIL_DEC_3626 3625 +#define Z_UTIL_DEC_3627 3626 +#define Z_UTIL_DEC_3628 3627 +#define Z_UTIL_DEC_3629 3628 +#define Z_UTIL_DEC_3630 3629 +#define Z_UTIL_DEC_3631 3630 +#define Z_UTIL_DEC_3632 3631 +#define Z_UTIL_DEC_3633 3632 +#define Z_UTIL_DEC_3634 3633 +#define Z_UTIL_DEC_3635 3634 +#define Z_UTIL_DEC_3636 3635 +#define Z_UTIL_DEC_3637 3636 +#define Z_UTIL_DEC_3638 3637 +#define Z_UTIL_DEC_3639 3638 +#define Z_UTIL_DEC_3640 3639 +#define Z_UTIL_DEC_3641 3640 +#define Z_UTIL_DEC_3642 3641 +#define Z_UTIL_DEC_3643 3642 +#define Z_UTIL_DEC_3644 3643 +#define Z_UTIL_DEC_3645 3644 +#define Z_UTIL_DEC_3646 3645 +#define Z_UTIL_DEC_3647 3646 +#define Z_UTIL_DEC_3648 3647 +#define Z_UTIL_DEC_3649 3648 +#define Z_UTIL_DEC_3650 3649 +#define Z_UTIL_DEC_3651 3650 +#define Z_UTIL_DEC_3652 3651 +#define Z_UTIL_DEC_3653 3652 +#define Z_UTIL_DEC_3654 3653 +#define Z_UTIL_DEC_3655 3654 +#define Z_UTIL_DEC_3656 3655 +#define Z_UTIL_DEC_3657 3656 +#define Z_UTIL_DEC_3658 3657 +#define Z_UTIL_DEC_3659 3658 +#define Z_UTIL_DEC_3660 3659 +#define Z_UTIL_DEC_3661 3660 +#define Z_UTIL_DEC_3662 3661 +#define Z_UTIL_DEC_3663 3662 +#define Z_UTIL_DEC_3664 3663 +#define Z_UTIL_DEC_3665 3664 +#define Z_UTIL_DEC_3666 3665 +#define Z_UTIL_DEC_3667 3666 +#define Z_UTIL_DEC_3668 3667 +#define Z_UTIL_DEC_3669 3668 +#define Z_UTIL_DEC_3670 3669 +#define Z_UTIL_DEC_3671 3670 +#define Z_UTIL_DEC_3672 3671 +#define Z_UTIL_DEC_3673 3672 +#define Z_UTIL_DEC_3674 3673 +#define Z_UTIL_DEC_3675 3674 +#define Z_UTIL_DEC_3676 3675 +#define Z_UTIL_DEC_3677 3676 +#define Z_UTIL_DEC_3678 3677 +#define Z_UTIL_DEC_3679 3678 +#define Z_UTIL_DEC_3680 3679 +#define Z_UTIL_DEC_3681 3680 +#define Z_UTIL_DEC_3682 3681 +#define Z_UTIL_DEC_3683 3682 +#define Z_UTIL_DEC_3684 3683 +#define Z_UTIL_DEC_3685 3684 +#define Z_UTIL_DEC_3686 3685 +#define Z_UTIL_DEC_3687 3686 +#define Z_UTIL_DEC_3688 3687 +#define Z_UTIL_DEC_3689 3688 +#define Z_UTIL_DEC_3690 3689 +#define Z_UTIL_DEC_3691 3690 +#define Z_UTIL_DEC_3692 3691 +#define Z_UTIL_DEC_3693 3692 +#define Z_UTIL_DEC_3694 3693 +#define Z_UTIL_DEC_3695 3694 +#define Z_UTIL_DEC_3696 3695 +#define Z_UTIL_DEC_3697 3696 +#define Z_UTIL_DEC_3698 3697 +#define Z_UTIL_DEC_3699 3698 +#define Z_UTIL_DEC_3700 3699 +#define Z_UTIL_DEC_3701 3700 +#define Z_UTIL_DEC_3702 3701 +#define Z_UTIL_DEC_3703 3702 +#define Z_UTIL_DEC_3704 3703 +#define Z_UTIL_DEC_3705 3704 +#define Z_UTIL_DEC_3706 3705 +#define Z_UTIL_DEC_3707 3706 +#define Z_UTIL_DEC_3708 3707 +#define Z_UTIL_DEC_3709 3708 +#define Z_UTIL_DEC_3710 3709 +#define Z_UTIL_DEC_3711 3710 +#define Z_UTIL_DEC_3712 3711 +#define Z_UTIL_DEC_3713 3712 +#define Z_UTIL_DEC_3714 3713 +#define Z_UTIL_DEC_3715 3714 +#define Z_UTIL_DEC_3716 3715 +#define Z_UTIL_DEC_3717 3716 +#define Z_UTIL_DEC_3718 3717 +#define Z_UTIL_DEC_3719 3718 +#define Z_UTIL_DEC_3720 3719 +#define Z_UTIL_DEC_3721 3720 +#define Z_UTIL_DEC_3722 3721 +#define Z_UTIL_DEC_3723 3722 +#define Z_UTIL_DEC_3724 3723 +#define Z_UTIL_DEC_3725 3724 +#define Z_UTIL_DEC_3726 3725 +#define Z_UTIL_DEC_3727 3726 +#define Z_UTIL_DEC_3728 3727 +#define Z_UTIL_DEC_3729 3728 +#define Z_UTIL_DEC_3730 3729 +#define Z_UTIL_DEC_3731 3730 +#define Z_UTIL_DEC_3732 3731 +#define Z_UTIL_DEC_3733 3732 +#define Z_UTIL_DEC_3734 3733 +#define Z_UTIL_DEC_3735 3734 +#define Z_UTIL_DEC_3736 3735 +#define Z_UTIL_DEC_3737 3736 +#define Z_UTIL_DEC_3738 3737 +#define Z_UTIL_DEC_3739 3738 +#define Z_UTIL_DEC_3740 3739 +#define Z_UTIL_DEC_3741 3740 +#define Z_UTIL_DEC_3742 3741 +#define Z_UTIL_DEC_3743 3742 +#define Z_UTIL_DEC_3744 3743 +#define Z_UTIL_DEC_3745 3744 +#define Z_UTIL_DEC_3746 3745 +#define Z_UTIL_DEC_3747 3746 +#define Z_UTIL_DEC_3748 3747 +#define Z_UTIL_DEC_3749 3748 +#define Z_UTIL_DEC_3750 3749 +#define Z_UTIL_DEC_3751 3750 +#define Z_UTIL_DEC_3752 3751 +#define Z_UTIL_DEC_3753 3752 +#define Z_UTIL_DEC_3754 3753 +#define Z_UTIL_DEC_3755 3754 +#define Z_UTIL_DEC_3756 3755 +#define Z_UTIL_DEC_3757 3756 +#define Z_UTIL_DEC_3758 3757 +#define Z_UTIL_DEC_3759 3758 +#define Z_UTIL_DEC_3760 3759 +#define Z_UTIL_DEC_3761 3760 +#define Z_UTIL_DEC_3762 3761 +#define Z_UTIL_DEC_3763 3762 +#define Z_UTIL_DEC_3764 3763 +#define Z_UTIL_DEC_3765 3764 +#define Z_UTIL_DEC_3766 3765 +#define Z_UTIL_DEC_3767 3766 +#define Z_UTIL_DEC_3768 3767 +#define Z_UTIL_DEC_3769 3768 +#define Z_UTIL_DEC_3770 3769 +#define Z_UTIL_DEC_3771 3770 +#define Z_UTIL_DEC_3772 3771 +#define Z_UTIL_DEC_3773 3772 +#define Z_UTIL_DEC_3774 3773 +#define Z_UTIL_DEC_3775 3774 +#define Z_UTIL_DEC_3776 3775 +#define Z_UTIL_DEC_3777 3776 +#define Z_UTIL_DEC_3778 3777 +#define Z_UTIL_DEC_3779 3778 +#define Z_UTIL_DEC_3780 3779 +#define Z_UTIL_DEC_3781 3780 +#define Z_UTIL_DEC_3782 3781 +#define Z_UTIL_DEC_3783 3782 +#define Z_UTIL_DEC_3784 3783 +#define Z_UTIL_DEC_3785 3784 +#define Z_UTIL_DEC_3786 3785 +#define Z_UTIL_DEC_3787 3786 +#define Z_UTIL_DEC_3788 3787 +#define Z_UTIL_DEC_3789 3788 +#define Z_UTIL_DEC_3790 3789 +#define Z_UTIL_DEC_3791 3790 +#define Z_UTIL_DEC_3792 3791 +#define Z_UTIL_DEC_3793 3792 +#define Z_UTIL_DEC_3794 3793 +#define Z_UTIL_DEC_3795 3794 +#define Z_UTIL_DEC_3796 3795 +#define Z_UTIL_DEC_3797 3796 +#define Z_UTIL_DEC_3798 3797 +#define Z_UTIL_DEC_3799 3798 +#define Z_UTIL_DEC_3800 3799 +#define Z_UTIL_DEC_3801 3800 +#define Z_UTIL_DEC_3802 3801 +#define Z_UTIL_DEC_3803 3802 +#define Z_UTIL_DEC_3804 3803 +#define Z_UTIL_DEC_3805 3804 +#define Z_UTIL_DEC_3806 3805 +#define Z_UTIL_DEC_3807 3806 +#define Z_UTIL_DEC_3808 3807 +#define Z_UTIL_DEC_3809 3808 +#define Z_UTIL_DEC_3810 3809 +#define Z_UTIL_DEC_3811 3810 +#define Z_UTIL_DEC_3812 3811 +#define Z_UTIL_DEC_3813 3812 +#define Z_UTIL_DEC_3814 3813 +#define Z_UTIL_DEC_3815 3814 +#define Z_UTIL_DEC_3816 3815 +#define Z_UTIL_DEC_3817 3816 +#define Z_UTIL_DEC_3818 3817 +#define Z_UTIL_DEC_3819 3818 +#define Z_UTIL_DEC_3820 3819 +#define Z_UTIL_DEC_3821 3820 +#define Z_UTIL_DEC_3822 3821 +#define Z_UTIL_DEC_3823 3822 +#define Z_UTIL_DEC_3824 3823 +#define Z_UTIL_DEC_3825 3824 +#define Z_UTIL_DEC_3826 3825 +#define Z_UTIL_DEC_3827 3826 +#define Z_UTIL_DEC_3828 3827 +#define Z_UTIL_DEC_3829 3828 +#define Z_UTIL_DEC_3830 3829 +#define Z_UTIL_DEC_3831 3830 +#define Z_UTIL_DEC_3832 3831 +#define Z_UTIL_DEC_3833 3832 +#define Z_UTIL_DEC_3834 3833 +#define Z_UTIL_DEC_3835 3834 +#define Z_UTIL_DEC_3836 3835 +#define Z_UTIL_DEC_3837 3836 +#define Z_UTIL_DEC_3838 3837 +#define Z_UTIL_DEC_3839 3838 +#define Z_UTIL_DEC_3840 3839 +#define Z_UTIL_DEC_3841 3840 +#define Z_UTIL_DEC_3842 3841 +#define Z_UTIL_DEC_3843 3842 +#define Z_UTIL_DEC_3844 3843 +#define Z_UTIL_DEC_3845 3844 +#define Z_UTIL_DEC_3846 3845 +#define Z_UTIL_DEC_3847 3846 +#define Z_UTIL_DEC_3848 3847 +#define Z_UTIL_DEC_3849 3848 +#define Z_UTIL_DEC_3850 3849 +#define Z_UTIL_DEC_3851 3850 +#define Z_UTIL_DEC_3852 3851 +#define Z_UTIL_DEC_3853 3852 +#define Z_UTIL_DEC_3854 3853 +#define Z_UTIL_DEC_3855 3854 +#define Z_UTIL_DEC_3856 3855 +#define Z_UTIL_DEC_3857 3856 +#define Z_UTIL_DEC_3858 3857 +#define Z_UTIL_DEC_3859 3858 +#define Z_UTIL_DEC_3860 3859 +#define Z_UTIL_DEC_3861 3860 +#define Z_UTIL_DEC_3862 3861 +#define Z_UTIL_DEC_3863 3862 +#define Z_UTIL_DEC_3864 3863 +#define Z_UTIL_DEC_3865 3864 +#define Z_UTIL_DEC_3866 3865 +#define Z_UTIL_DEC_3867 3866 +#define Z_UTIL_DEC_3868 3867 +#define Z_UTIL_DEC_3869 3868 +#define Z_UTIL_DEC_3870 3869 +#define Z_UTIL_DEC_3871 3870 +#define Z_UTIL_DEC_3872 3871 +#define Z_UTIL_DEC_3873 3872 +#define Z_UTIL_DEC_3874 3873 +#define Z_UTIL_DEC_3875 3874 +#define Z_UTIL_DEC_3876 3875 +#define Z_UTIL_DEC_3877 3876 +#define Z_UTIL_DEC_3878 3877 +#define Z_UTIL_DEC_3879 3878 +#define Z_UTIL_DEC_3880 3879 +#define Z_UTIL_DEC_3881 3880 +#define Z_UTIL_DEC_3882 3881 +#define Z_UTIL_DEC_3883 3882 +#define Z_UTIL_DEC_3884 3883 +#define Z_UTIL_DEC_3885 3884 +#define Z_UTIL_DEC_3886 3885 +#define Z_UTIL_DEC_3887 3886 +#define Z_UTIL_DEC_3888 3887 +#define Z_UTIL_DEC_3889 3888 +#define Z_UTIL_DEC_3890 3889 +#define Z_UTIL_DEC_3891 3890 +#define Z_UTIL_DEC_3892 3891 +#define Z_UTIL_DEC_3893 3892 +#define Z_UTIL_DEC_3894 3893 +#define Z_UTIL_DEC_3895 3894 +#define Z_UTIL_DEC_3896 3895 +#define Z_UTIL_DEC_3897 3896 +#define Z_UTIL_DEC_3898 3897 +#define Z_UTIL_DEC_3899 3898 +#define Z_UTIL_DEC_3900 3899 +#define Z_UTIL_DEC_3901 3900 +#define Z_UTIL_DEC_3902 3901 +#define Z_UTIL_DEC_3903 3902 +#define Z_UTIL_DEC_3904 3903 +#define Z_UTIL_DEC_3905 3904 +#define Z_UTIL_DEC_3906 3905 +#define Z_UTIL_DEC_3907 3906 +#define Z_UTIL_DEC_3908 3907 +#define Z_UTIL_DEC_3909 3908 +#define Z_UTIL_DEC_3910 3909 +#define Z_UTIL_DEC_3911 3910 +#define Z_UTIL_DEC_3912 3911 +#define Z_UTIL_DEC_3913 3912 +#define Z_UTIL_DEC_3914 3913 +#define Z_UTIL_DEC_3915 3914 +#define Z_UTIL_DEC_3916 3915 +#define Z_UTIL_DEC_3917 3916 +#define Z_UTIL_DEC_3918 3917 +#define Z_UTIL_DEC_3919 3918 +#define Z_UTIL_DEC_3920 3919 +#define Z_UTIL_DEC_3921 3920 +#define Z_UTIL_DEC_3922 3921 +#define Z_UTIL_DEC_3923 3922 +#define Z_UTIL_DEC_3924 3923 +#define Z_UTIL_DEC_3925 3924 +#define Z_UTIL_DEC_3926 3925 +#define Z_UTIL_DEC_3927 3926 +#define Z_UTIL_DEC_3928 3927 +#define Z_UTIL_DEC_3929 3928 +#define Z_UTIL_DEC_3930 3929 +#define Z_UTIL_DEC_3931 3930 +#define Z_UTIL_DEC_3932 3931 +#define Z_UTIL_DEC_3933 3932 +#define Z_UTIL_DEC_3934 3933 +#define Z_UTIL_DEC_3935 3934 +#define Z_UTIL_DEC_3936 3935 +#define Z_UTIL_DEC_3937 3936 +#define Z_UTIL_DEC_3938 3937 +#define Z_UTIL_DEC_3939 3938 +#define Z_UTIL_DEC_3940 3939 +#define Z_UTIL_DEC_3941 3940 +#define Z_UTIL_DEC_3942 3941 +#define Z_UTIL_DEC_3943 3942 +#define Z_UTIL_DEC_3944 3943 +#define Z_UTIL_DEC_3945 3944 +#define Z_UTIL_DEC_3946 3945 +#define Z_UTIL_DEC_3947 3946 +#define Z_UTIL_DEC_3948 3947 +#define Z_UTIL_DEC_3949 3948 +#define Z_UTIL_DEC_3950 3949 +#define Z_UTIL_DEC_3951 3950 +#define Z_UTIL_DEC_3952 3951 +#define Z_UTIL_DEC_3953 3952 +#define Z_UTIL_DEC_3954 3953 +#define Z_UTIL_DEC_3955 3954 +#define Z_UTIL_DEC_3956 3955 +#define Z_UTIL_DEC_3957 3956 +#define Z_UTIL_DEC_3958 3957 +#define Z_UTIL_DEC_3959 3958 +#define Z_UTIL_DEC_3960 3959 +#define Z_UTIL_DEC_3961 3960 +#define Z_UTIL_DEC_3962 3961 +#define Z_UTIL_DEC_3963 3962 +#define Z_UTIL_DEC_3964 3963 +#define Z_UTIL_DEC_3965 3964 +#define Z_UTIL_DEC_3966 3965 +#define Z_UTIL_DEC_3967 3966 +#define Z_UTIL_DEC_3968 3967 +#define Z_UTIL_DEC_3969 3968 +#define Z_UTIL_DEC_3970 3969 +#define Z_UTIL_DEC_3971 3970 +#define Z_UTIL_DEC_3972 3971 +#define Z_UTIL_DEC_3973 3972 +#define Z_UTIL_DEC_3974 3973 +#define Z_UTIL_DEC_3975 3974 +#define Z_UTIL_DEC_3976 3975 +#define Z_UTIL_DEC_3977 3976 +#define Z_UTIL_DEC_3978 3977 +#define Z_UTIL_DEC_3979 3978 +#define Z_UTIL_DEC_3980 3979 +#define Z_UTIL_DEC_3981 3980 +#define Z_UTIL_DEC_3982 3981 +#define Z_UTIL_DEC_3983 3982 +#define Z_UTIL_DEC_3984 3983 +#define Z_UTIL_DEC_3985 3984 +#define Z_UTIL_DEC_3986 3985 +#define Z_UTIL_DEC_3987 3986 +#define Z_UTIL_DEC_3988 3987 +#define Z_UTIL_DEC_3989 3988 +#define Z_UTIL_DEC_3990 3989 +#define Z_UTIL_DEC_3991 3990 +#define Z_UTIL_DEC_3992 3991 +#define Z_UTIL_DEC_3993 3992 +#define Z_UTIL_DEC_3994 3993 +#define Z_UTIL_DEC_3995 3994 +#define Z_UTIL_DEC_3996 3995 +#define Z_UTIL_DEC_3997 3996 +#define Z_UTIL_DEC_3998 3997 +#define Z_UTIL_DEC_3999 3998 +#define Z_UTIL_DEC_4000 3999 +#define Z_UTIL_DEC_4001 4000 +#define Z_UTIL_DEC_4002 4001 +#define Z_UTIL_DEC_4003 4002 +#define Z_UTIL_DEC_4004 4003 +#define Z_UTIL_DEC_4005 4004 +#define Z_UTIL_DEC_4006 4005 +#define Z_UTIL_DEC_4007 4006 +#define Z_UTIL_DEC_4008 4007 +#define Z_UTIL_DEC_4009 4008 +#define Z_UTIL_DEC_4010 4009 +#define Z_UTIL_DEC_4011 4010 +#define Z_UTIL_DEC_4012 4011 +#define Z_UTIL_DEC_4013 4012 +#define Z_UTIL_DEC_4014 4013 +#define Z_UTIL_DEC_4015 4014 +#define Z_UTIL_DEC_4016 4015 +#define Z_UTIL_DEC_4017 4016 +#define Z_UTIL_DEC_4018 4017 +#define Z_UTIL_DEC_4019 4018 +#define Z_UTIL_DEC_4020 4019 +#define Z_UTIL_DEC_4021 4020 +#define Z_UTIL_DEC_4022 4021 +#define Z_UTIL_DEC_4023 4022 +#define Z_UTIL_DEC_4024 4023 +#define Z_UTIL_DEC_4025 4024 +#define Z_UTIL_DEC_4026 4025 +#define Z_UTIL_DEC_4027 4026 +#define Z_UTIL_DEC_4028 4027 +#define Z_UTIL_DEC_4029 4028 +#define Z_UTIL_DEC_4030 4029 +#define Z_UTIL_DEC_4031 4030 +#define Z_UTIL_DEC_4032 4031 +#define Z_UTIL_DEC_4033 4032 +#define Z_UTIL_DEC_4034 4033 +#define Z_UTIL_DEC_4035 4034 +#define Z_UTIL_DEC_4036 4035 +#define Z_UTIL_DEC_4037 4036 +#define Z_UTIL_DEC_4038 4037 +#define Z_UTIL_DEC_4039 4038 +#define Z_UTIL_DEC_4040 4039 +#define Z_UTIL_DEC_4041 4040 +#define Z_UTIL_DEC_4042 4041 +#define Z_UTIL_DEC_4043 4042 +#define Z_UTIL_DEC_4044 4043 +#define Z_UTIL_DEC_4045 4044 +#define Z_UTIL_DEC_4046 4045 +#define Z_UTIL_DEC_4047 4046 +#define Z_UTIL_DEC_4048 4047 +#define Z_UTIL_DEC_4049 4048 +#define Z_UTIL_DEC_4050 4049 +#define Z_UTIL_DEC_4051 4050 +#define Z_UTIL_DEC_4052 4051 +#define Z_UTIL_DEC_4053 4052 +#define Z_UTIL_DEC_4054 4053 +#define Z_UTIL_DEC_4055 4054 +#define Z_UTIL_DEC_4056 4055 +#define Z_UTIL_DEC_4057 4056 +#define Z_UTIL_DEC_4058 4057 +#define Z_UTIL_DEC_4059 4058 +#define Z_UTIL_DEC_4060 4059 +#define Z_UTIL_DEC_4061 4060 +#define Z_UTIL_DEC_4062 4061 +#define Z_UTIL_DEC_4063 4062 +#define Z_UTIL_DEC_4064 4063 +#define Z_UTIL_DEC_4065 4064 +#define Z_UTIL_DEC_4066 4065 +#define Z_UTIL_DEC_4067 4066 +#define Z_UTIL_DEC_4068 4067 +#define Z_UTIL_DEC_4069 4068 +#define Z_UTIL_DEC_4070 4069 +#define Z_UTIL_DEC_4071 4070 +#define Z_UTIL_DEC_4072 4071 +#define Z_UTIL_DEC_4073 4072 +#define Z_UTIL_DEC_4074 4073 +#define Z_UTIL_DEC_4075 4074 +#define Z_UTIL_DEC_4076 4075 +#define Z_UTIL_DEC_4077 4076 +#define Z_UTIL_DEC_4078 4077 +#define Z_UTIL_DEC_4079 4078 +#define Z_UTIL_DEC_4080 4079 +#define Z_UTIL_DEC_4081 4080 +#define Z_UTIL_DEC_4082 4081 +#define Z_UTIL_DEC_4083 4082 +#define Z_UTIL_DEC_4084 4083 +#define Z_UTIL_DEC_4085 4084 +#define Z_UTIL_DEC_4086 4085 +#define Z_UTIL_DEC_4087 4086 +#define Z_UTIL_DEC_4088 4087 +#define Z_UTIL_DEC_4089 4088 +#define Z_UTIL_DEC_4090 4089 +#define Z_UTIL_DEC_4091 4090 +#define Z_UTIL_DEC_4092 4091 +#define Z_UTIL_DEC_4093 4092 +#define Z_UTIL_DEC_4094 4093 +#define Z_UTIL_DEC_4095 4094 +#define Z_UTIL_DEC_4096 4095 + +#endif /* ZEPHYR_INCLUDE_SYS_UTIL_INTERNAL_UTIL_DEC_H_ */ + +/** + * INTERNAL_HIDDEN @endcond + */ diff --git a/components/bt/esp_ble_audio/include/zephyr/sys/util_internal_util_inc.h b/components/bt/esp_ble_audio/include/zephyr/sys/util_internal_util_inc.h new file mode 100644 index 0000000000..e2dfc4d2b9 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/sys/util_internal_util_inc.h @@ -0,0 +1,4122 @@ +/* + * SPDX-FileCopyrightText: 2011-2014, Wind River Systems, Inc. + * SPDX-FileCopyrightText: 2020, Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @cond INTERNAL_HIDDEN + */ + +#ifndef ZEPHYR_INCLUDE_SYS_UTIL_INTERNAL_H_ +#error "This header should not be used directly, please include util_internal.h instead" +#endif /* ZEPHYR_INCLUDE_SYS_UTIL_INTERNAL_H_ */ + +#ifndef ZEPHYR_INCLUDE_SYS_UTIL_INTERNAL_UTIL_INC_H_ +#define ZEPHYR_INCLUDE_SYS_UTIL_INTERNAL_UTIL_INC_H_ + +#define Z_UTIL_INC_0 1 +#define Z_UTIL_INC_1 2 +#define Z_UTIL_INC_2 3 +#define Z_UTIL_INC_3 4 +#define Z_UTIL_INC_4 5 +#define Z_UTIL_INC_5 6 +#define Z_UTIL_INC_6 7 +#define Z_UTIL_INC_7 8 +#define Z_UTIL_INC_8 9 +#define Z_UTIL_INC_9 10 +#define Z_UTIL_INC_10 11 +#define Z_UTIL_INC_11 12 +#define Z_UTIL_INC_12 13 +#define Z_UTIL_INC_13 14 +#define Z_UTIL_INC_14 15 +#define Z_UTIL_INC_15 16 +#define Z_UTIL_INC_16 17 +#define Z_UTIL_INC_17 18 +#define Z_UTIL_INC_18 19 +#define Z_UTIL_INC_19 20 +#define Z_UTIL_INC_20 21 +#define Z_UTIL_INC_21 22 +#define Z_UTIL_INC_22 23 +#define Z_UTIL_INC_23 24 +#define Z_UTIL_INC_24 25 +#define Z_UTIL_INC_25 26 +#define Z_UTIL_INC_26 27 +#define Z_UTIL_INC_27 28 +#define Z_UTIL_INC_28 29 +#define Z_UTIL_INC_29 30 +#define Z_UTIL_INC_30 31 +#define Z_UTIL_INC_31 32 +#define Z_UTIL_INC_32 33 +#define Z_UTIL_INC_33 34 +#define Z_UTIL_INC_34 35 +#define Z_UTIL_INC_35 36 +#define Z_UTIL_INC_36 37 +#define Z_UTIL_INC_37 38 +#define Z_UTIL_INC_38 39 +#define Z_UTIL_INC_39 40 +#define Z_UTIL_INC_40 41 +#define Z_UTIL_INC_41 42 +#define Z_UTIL_INC_42 43 +#define Z_UTIL_INC_43 44 +#define Z_UTIL_INC_44 45 +#define Z_UTIL_INC_45 46 +#define Z_UTIL_INC_46 47 +#define Z_UTIL_INC_47 48 +#define Z_UTIL_INC_48 49 +#define Z_UTIL_INC_49 50 +#define Z_UTIL_INC_50 51 +#define Z_UTIL_INC_51 52 +#define Z_UTIL_INC_52 53 +#define Z_UTIL_INC_53 54 +#define Z_UTIL_INC_54 55 +#define Z_UTIL_INC_55 56 +#define Z_UTIL_INC_56 57 +#define Z_UTIL_INC_57 58 +#define Z_UTIL_INC_58 59 +#define Z_UTIL_INC_59 60 +#define Z_UTIL_INC_60 61 +#define Z_UTIL_INC_61 62 +#define Z_UTIL_INC_62 63 +#define Z_UTIL_INC_63 64 +#define Z_UTIL_INC_64 65 +#define Z_UTIL_INC_65 66 +#define Z_UTIL_INC_66 67 +#define Z_UTIL_INC_67 68 +#define Z_UTIL_INC_68 69 +#define Z_UTIL_INC_69 70 +#define Z_UTIL_INC_70 71 +#define Z_UTIL_INC_71 72 +#define Z_UTIL_INC_72 73 +#define Z_UTIL_INC_73 74 +#define Z_UTIL_INC_74 75 +#define Z_UTIL_INC_75 76 +#define Z_UTIL_INC_76 77 +#define Z_UTIL_INC_77 78 +#define Z_UTIL_INC_78 79 +#define Z_UTIL_INC_79 80 +#define Z_UTIL_INC_80 81 +#define Z_UTIL_INC_81 82 +#define Z_UTIL_INC_82 83 +#define Z_UTIL_INC_83 84 +#define Z_UTIL_INC_84 85 +#define Z_UTIL_INC_85 86 +#define Z_UTIL_INC_86 87 +#define Z_UTIL_INC_87 88 +#define Z_UTIL_INC_88 89 +#define Z_UTIL_INC_89 90 +#define Z_UTIL_INC_90 91 +#define Z_UTIL_INC_91 92 +#define Z_UTIL_INC_92 93 +#define Z_UTIL_INC_93 94 +#define Z_UTIL_INC_94 95 +#define Z_UTIL_INC_95 96 +#define Z_UTIL_INC_96 97 +#define Z_UTIL_INC_97 98 +#define Z_UTIL_INC_98 99 +#define Z_UTIL_INC_99 100 +#define Z_UTIL_INC_100 101 +#define Z_UTIL_INC_101 102 +#define Z_UTIL_INC_102 103 +#define Z_UTIL_INC_103 104 +#define Z_UTIL_INC_104 105 +#define Z_UTIL_INC_105 106 +#define Z_UTIL_INC_106 107 +#define Z_UTIL_INC_107 108 +#define Z_UTIL_INC_108 109 +#define Z_UTIL_INC_109 110 +#define Z_UTIL_INC_110 111 +#define Z_UTIL_INC_111 112 +#define Z_UTIL_INC_112 113 +#define Z_UTIL_INC_113 114 +#define Z_UTIL_INC_114 115 +#define Z_UTIL_INC_115 116 +#define Z_UTIL_INC_116 117 +#define Z_UTIL_INC_117 118 +#define Z_UTIL_INC_118 119 +#define Z_UTIL_INC_119 120 +#define Z_UTIL_INC_120 121 +#define Z_UTIL_INC_121 122 +#define Z_UTIL_INC_122 123 +#define Z_UTIL_INC_123 124 +#define Z_UTIL_INC_124 125 +#define Z_UTIL_INC_125 126 +#define Z_UTIL_INC_126 127 +#define Z_UTIL_INC_127 128 +#define Z_UTIL_INC_128 129 +#define Z_UTIL_INC_129 130 +#define Z_UTIL_INC_130 131 +#define Z_UTIL_INC_131 132 +#define Z_UTIL_INC_132 133 +#define Z_UTIL_INC_133 134 +#define Z_UTIL_INC_134 135 +#define Z_UTIL_INC_135 136 +#define Z_UTIL_INC_136 137 +#define Z_UTIL_INC_137 138 +#define Z_UTIL_INC_138 139 +#define Z_UTIL_INC_139 140 +#define Z_UTIL_INC_140 141 +#define Z_UTIL_INC_141 142 +#define Z_UTIL_INC_142 143 +#define Z_UTIL_INC_143 144 +#define Z_UTIL_INC_144 145 +#define Z_UTIL_INC_145 146 +#define Z_UTIL_INC_146 147 +#define Z_UTIL_INC_147 148 +#define Z_UTIL_INC_148 149 +#define Z_UTIL_INC_149 150 +#define Z_UTIL_INC_150 151 +#define Z_UTIL_INC_151 152 +#define Z_UTIL_INC_152 153 +#define Z_UTIL_INC_153 154 +#define Z_UTIL_INC_154 155 +#define Z_UTIL_INC_155 156 +#define Z_UTIL_INC_156 157 +#define Z_UTIL_INC_157 158 +#define Z_UTIL_INC_158 159 +#define Z_UTIL_INC_159 160 +#define Z_UTIL_INC_160 161 +#define Z_UTIL_INC_161 162 +#define Z_UTIL_INC_162 163 +#define Z_UTIL_INC_163 164 +#define Z_UTIL_INC_164 165 +#define Z_UTIL_INC_165 166 +#define Z_UTIL_INC_166 167 +#define Z_UTIL_INC_167 168 +#define Z_UTIL_INC_168 169 +#define Z_UTIL_INC_169 170 +#define Z_UTIL_INC_170 171 +#define Z_UTIL_INC_171 172 +#define Z_UTIL_INC_172 173 +#define Z_UTIL_INC_173 174 +#define Z_UTIL_INC_174 175 +#define Z_UTIL_INC_175 176 +#define Z_UTIL_INC_176 177 +#define Z_UTIL_INC_177 178 +#define Z_UTIL_INC_178 179 +#define Z_UTIL_INC_179 180 +#define Z_UTIL_INC_180 181 +#define Z_UTIL_INC_181 182 +#define Z_UTIL_INC_182 183 +#define Z_UTIL_INC_183 184 +#define Z_UTIL_INC_184 185 +#define Z_UTIL_INC_185 186 +#define Z_UTIL_INC_186 187 +#define Z_UTIL_INC_187 188 +#define Z_UTIL_INC_188 189 +#define Z_UTIL_INC_189 190 +#define Z_UTIL_INC_190 191 +#define Z_UTIL_INC_191 192 +#define Z_UTIL_INC_192 193 +#define Z_UTIL_INC_193 194 +#define Z_UTIL_INC_194 195 +#define Z_UTIL_INC_195 196 +#define Z_UTIL_INC_196 197 +#define Z_UTIL_INC_197 198 +#define Z_UTIL_INC_198 199 +#define Z_UTIL_INC_199 200 +#define Z_UTIL_INC_200 201 +#define Z_UTIL_INC_201 202 +#define Z_UTIL_INC_202 203 +#define Z_UTIL_INC_203 204 +#define Z_UTIL_INC_204 205 +#define Z_UTIL_INC_205 206 +#define Z_UTIL_INC_206 207 +#define Z_UTIL_INC_207 208 +#define Z_UTIL_INC_208 209 +#define Z_UTIL_INC_209 210 +#define Z_UTIL_INC_210 211 +#define Z_UTIL_INC_211 212 +#define Z_UTIL_INC_212 213 +#define Z_UTIL_INC_213 214 +#define Z_UTIL_INC_214 215 +#define Z_UTIL_INC_215 216 +#define Z_UTIL_INC_216 217 +#define Z_UTIL_INC_217 218 +#define Z_UTIL_INC_218 219 +#define Z_UTIL_INC_219 220 +#define Z_UTIL_INC_220 221 +#define Z_UTIL_INC_221 222 +#define Z_UTIL_INC_222 223 +#define Z_UTIL_INC_223 224 +#define Z_UTIL_INC_224 225 +#define Z_UTIL_INC_225 226 +#define Z_UTIL_INC_226 227 +#define Z_UTIL_INC_227 228 +#define Z_UTIL_INC_228 229 +#define Z_UTIL_INC_229 230 +#define Z_UTIL_INC_230 231 +#define Z_UTIL_INC_231 232 +#define Z_UTIL_INC_232 233 +#define Z_UTIL_INC_233 234 +#define Z_UTIL_INC_234 235 +#define Z_UTIL_INC_235 236 +#define Z_UTIL_INC_236 237 +#define Z_UTIL_INC_237 238 +#define Z_UTIL_INC_238 239 +#define Z_UTIL_INC_239 240 +#define Z_UTIL_INC_240 241 +#define Z_UTIL_INC_241 242 +#define Z_UTIL_INC_242 243 +#define Z_UTIL_INC_243 244 +#define Z_UTIL_INC_244 245 +#define Z_UTIL_INC_245 246 +#define Z_UTIL_INC_246 247 +#define Z_UTIL_INC_247 248 +#define Z_UTIL_INC_248 249 +#define Z_UTIL_INC_249 250 +#define Z_UTIL_INC_250 251 +#define Z_UTIL_INC_251 252 +#define Z_UTIL_INC_252 253 +#define Z_UTIL_INC_253 254 +#define Z_UTIL_INC_254 255 +#define Z_UTIL_INC_255 256 +#define Z_UTIL_INC_256 257 +#define Z_UTIL_INC_257 258 +#define Z_UTIL_INC_258 259 +#define Z_UTIL_INC_259 260 +#define Z_UTIL_INC_260 261 +#define Z_UTIL_INC_261 262 +#define Z_UTIL_INC_262 263 +#define Z_UTIL_INC_263 264 +#define Z_UTIL_INC_264 265 +#define Z_UTIL_INC_265 266 +#define Z_UTIL_INC_266 267 +#define Z_UTIL_INC_267 268 +#define Z_UTIL_INC_268 269 +#define Z_UTIL_INC_269 270 +#define Z_UTIL_INC_270 271 +#define Z_UTIL_INC_271 272 +#define Z_UTIL_INC_272 273 +#define Z_UTIL_INC_273 274 +#define Z_UTIL_INC_274 275 +#define Z_UTIL_INC_275 276 +#define Z_UTIL_INC_276 277 +#define Z_UTIL_INC_277 278 +#define Z_UTIL_INC_278 279 +#define Z_UTIL_INC_279 280 +#define Z_UTIL_INC_280 281 +#define Z_UTIL_INC_281 282 +#define Z_UTIL_INC_282 283 +#define Z_UTIL_INC_283 284 +#define Z_UTIL_INC_284 285 +#define Z_UTIL_INC_285 286 +#define Z_UTIL_INC_286 287 +#define Z_UTIL_INC_287 288 +#define Z_UTIL_INC_288 289 +#define Z_UTIL_INC_289 290 +#define Z_UTIL_INC_290 291 +#define Z_UTIL_INC_291 292 +#define Z_UTIL_INC_292 293 +#define Z_UTIL_INC_293 294 +#define Z_UTIL_INC_294 295 +#define Z_UTIL_INC_295 296 +#define Z_UTIL_INC_296 297 +#define Z_UTIL_INC_297 298 +#define Z_UTIL_INC_298 299 +#define Z_UTIL_INC_299 300 +#define Z_UTIL_INC_300 301 +#define Z_UTIL_INC_301 302 +#define Z_UTIL_INC_302 303 +#define Z_UTIL_INC_303 304 +#define Z_UTIL_INC_304 305 +#define Z_UTIL_INC_305 306 +#define Z_UTIL_INC_306 307 +#define Z_UTIL_INC_307 308 +#define Z_UTIL_INC_308 309 +#define Z_UTIL_INC_309 310 +#define Z_UTIL_INC_310 311 +#define Z_UTIL_INC_311 312 +#define Z_UTIL_INC_312 313 +#define Z_UTIL_INC_313 314 +#define Z_UTIL_INC_314 315 +#define Z_UTIL_INC_315 316 +#define Z_UTIL_INC_316 317 +#define Z_UTIL_INC_317 318 +#define Z_UTIL_INC_318 319 +#define Z_UTIL_INC_319 320 +#define Z_UTIL_INC_320 321 +#define Z_UTIL_INC_321 322 +#define Z_UTIL_INC_322 323 +#define Z_UTIL_INC_323 324 +#define Z_UTIL_INC_324 325 +#define Z_UTIL_INC_325 326 +#define Z_UTIL_INC_326 327 +#define Z_UTIL_INC_327 328 +#define Z_UTIL_INC_328 329 +#define Z_UTIL_INC_329 330 +#define Z_UTIL_INC_330 331 +#define Z_UTIL_INC_331 332 +#define Z_UTIL_INC_332 333 +#define Z_UTIL_INC_333 334 +#define Z_UTIL_INC_334 335 +#define Z_UTIL_INC_335 336 +#define Z_UTIL_INC_336 337 +#define Z_UTIL_INC_337 338 +#define Z_UTIL_INC_338 339 +#define Z_UTIL_INC_339 340 +#define Z_UTIL_INC_340 341 +#define Z_UTIL_INC_341 342 +#define Z_UTIL_INC_342 343 +#define Z_UTIL_INC_343 344 +#define Z_UTIL_INC_344 345 +#define Z_UTIL_INC_345 346 +#define Z_UTIL_INC_346 347 +#define Z_UTIL_INC_347 348 +#define Z_UTIL_INC_348 349 +#define Z_UTIL_INC_349 350 +#define Z_UTIL_INC_350 351 +#define Z_UTIL_INC_351 352 +#define Z_UTIL_INC_352 353 +#define Z_UTIL_INC_353 354 +#define Z_UTIL_INC_354 355 +#define Z_UTIL_INC_355 356 +#define Z_UTIL_INC_356 357 +#define Z_UTIL_INC_357 358 +#define Z_UTIL_INC_358 359 +#define Z_UTIL_INC_359 360 +#define Z_UTIL_INC_360 361 +#define Z_UTIL_INC_361 362 +#define Z_UTIL_INC_362 363 +#define Z_UTIL_INC_363 364 +#define Z_UTIL_INC_364 365 +#define Z_UTIL_INC_365 366 +#define Z_UTIL_INC_366 367 +#define Z_UTIL_INC_367 368 +#define Z_UTIL_INC_368 369 +#define Z_UTIL_INC_369 370 +#define Z_UTIL_INC_370 371 +#define Z_UTIL_INC_371 372 +#define Z_UTIL_INC_372 373 +#define Z_UTIL_INC_373 374 +#define Z_UTIL_INC_374 375 +#define Z_UTIL_INC_375 376 +#define Z_UTIL_INC_376 377 +#define Z_UTIL_INC_377 378 +#define Z_UTIL_INC_378 379 +#define Z_UTIL_INC_379 380 +#define Z_UTIL_INC_380 381 +#define Z_UTIL_INC_381 382 +#define Z_UTIL_INC_382 383 +#define Z_UTIL_INC_383 384 +#define Z_UTIL_INC_384 385 +#define Z_UTIL_INC_385 386 +#define Z_UTIL_INC_386 387 +#define Z_UTIL_INC_387 388 +#define Z_UTIL_INC_388 389 +#define Z_UTIL_INC_389 390 +#define Z_UTIL_INC_390 391 +#define Z_UTIL_INC_391 392 +#define Z_UTIL_INC_392 393 +#define Z_UTIL_INC_393 394 +#define Z_UTIL_INC_394 395 +#define Z_UTIL_INC_395 396 +#define Z_UTIL_INC_396 397 +#define Z_UTIL_INC_397 398 +#define Z_UTIL_INC_398 399 +#define Z_UTIL_INC_399 400 +#define Z_UTIL_INC_400 401 +#define Z_UTIL_INC_401 402 +#define Z_UTIL_INC_402 403 +#define Z_UTIL_INC_403 404 +#define Z_UTIL_INC_404 405 +#define Z_UTIL_INC_405 406 +#define Z_UTIL_INC_406 407 +#define Z_UTIL_INC_407 408 +#define Z_UTIL_INC_408 409 +#define Z_UTIL_INC_409 410 +#define Z_UTIL_INC_410 411 +#define Z_UTIL_INC_411 412 +#define Z_UTIL_INC_412 413 +#define Z_UTIL_INC_413 414 +#define Z_UTIL_INC_414 415 +#define Z_UTIL_INC_415 416 +#define Z_UTIL_INC_416 417 +#define Z_UTIL_INC_417 418 +#define Z_UTIL_INC_418 419 +#define Z_UTIL_INC_419 420 +#define Z_UTIL_INC_420 421 +#define Z_UTIL_INC_421 422 +#define Z_UTIL_INC_422 423 +#define Z_UTIL_INC_423 424 +#define Z_UTIL_INC_424 425 +#define Z_UTIL_INC_425 426 +#define Z_UTIL_INC_426 427 +#define Z_UTIL_INC_427 428 +#define Z_UTIL_INC_428 429 +#define Z_UTIL_INC_429 430 +#define Z_UTIL_INC_430 431 +#define Z_UTIL_INC_431 432 +#define Z_UTIL_INC_432 433 +#define Z_UTIL_INC_433 434 +#define Z_UTIL_INC_434 435 +#define Z_UTIL_INC_435 436 +#define Z_UTIL_INC_436 437 +#define Z_UTIL_INC_437 438 +#define Z_UTIL_INC_438 439 +#define Z_UTIL_INC_439 440 +#define Z_UTIL_INC_440 441 +#define Z_UTIL_INC_441 442 +#define Z_UTIL_INC_442 443 +#define Z_UTIL_INC_443 444 +#define Z_UTIL_INC_444 445 +#define Z_UTIL_INC_445 446 +#define Z_UTIL_INC_446 447 +#define Z_UTIL_INC_447 448 +#define Z_UTIL_INC_448 449 +#define Z_UTIL_INC_449 450 +#define Z_UTIL_INC_450 451 +#define Z_UTIL_INC_451 452 +#define Z_UTIL_INC_452 453 +#define Z_UTIL_INC_453 454 +#define Z_UTIL_INC_454 455 +#define Z_UTIL_INC_455 456 +#define Z_UTIL_INC_456 457 +#define Z_UTIL_INC_457 458 +#define Z_UTIL_INC_458 459 +#define Z_UTIL_INC_459 460 +#define Z_UTIL_INC_460 461 +#define Z_UTIL_INC_461 462 +#define Z_UTIL_INC_462 463 +#define Z_UTIL_INC_463 464 +#define Z_UTIL_INC_464 465 +#define Z_UTIL_INC_465 466 +#define Z_UTIL_INC_466 467 +#define Z_UTIL_INC_467 468 +#define Z_UTIL_INC_468 469 +#define Z_UTIL_INC_469 470 +#define Z_UTIL_INC_470 471 +#define Z_UTIL_INC_471 472 +#define Z_UTIL_INC_472 473 +#define Z_UTIL_INC_473 474 +#define Z_UTIL_INC_474 475 +#define Z_UTIL_INC_475 476 +#define Z_UTIL_INC_476 477 +#define Z_UTIL_INC_477 478 +#define Z_UTIL_INC_478 479 +#define Z_UTIL_INC_479 480 +#define Z_UTIL_INC_480 481 +#define Z_UTIL_INC_481 482 +#define Z_UTIL_INC_482 483 +#define Z_UTIL_INC_483 484 +#define Z_UTIL_INC_484 485 +#define Z_UTIL_INC_485 486 +#define Z_UTIL_INC_486 487 +#define Z_UTIL_INC_487 488 +#define Z_UTIL_INC_488 489 +#define Z_UTIL_INC_489 490 +#define Z_UTIL_INC_490 491 +#define Z_UTIL_INC_491 492 +#define Z_UTIL_INC_492 493 +#define Z_UTIL_INC_493 494 +#define Z_UTIL_INC_494 495 +#define Z_UTIL_INC_495 496 +#define Z_UTIL_INC_496 497 +#define Z_UTIL_INC_497 498 +#define Z_UTIL_INC_498 499 +#define Z_UTIL_INC_499 500 +#define Z_UTIL_INC_500 501 +#define Z_UTIL_INC_501 502 +#define Z_UTIL_INC_502 503 +#define Z_UTIL_INC_503 504 +#define Z_UTIL_INC_504 505 +#define Z_UTIL_INC_505 506 +#define Z_UTIL_INC_506 507 +#define Z_UTIL_INC_507 508 +#define Z_UTIL_INC_508 509 +#define Z_UTIL_INC_509 510 +#define Z_UTIL_INC_510 511 +#define Z_UTIL_INC_511 512 +#define Z_UTIL_INC_512 513 +#define Z_UTIL_INC_513 514 +#define Z_UTIL_INC_514 515 +#define Z_UTIL_INC_515 516 +#define Z_UTIL_INC_516 517 +#define Z_UTIL_INC_517 518 +#define Z_UTIL_INC_518 519 +#define Z_UTIL_INC_519 520 +#define Z_UTIL_INC_520 521 +#define Z_UTIL_INC_521 522 +#define Z_UTIL_INC_522 523 +#define Z_UTIL_INC_523 524 +#define Z_UTIL_INC_524 525 +#define Z_UTIL_INC_525 526 +#define Z_UTIL_INC_526 527 +#define Z_UTIL_INC_527 528 +#define Z_UTIL_INC_528 529 +#define Z_UTIL_INC_529 530 +#define Z_UTIL_INC_530 531 +#define Z_UTIL_INC_531 532 +#define Z_UTIL_INC_532 533 +#define Z_UTIL_INC_533 534 +#define Z_UTIL_INC_534 535 +#define Z_UTIL_INC_535 536 +#define Z_UTIL_INC_536 537 +#define Z_UTIL_INC_537 538 +#define Z_UTIL_INC_538 539 +#define Z_UTIL_INC_539 540 +#define Z_UTIL_INC_540 541 +#define Z_UTIL_INC_541 542 +#define Z_UTIL_INC_542 543 +#define Z_UTIL_INC_543 544 +#define Z_UTIL_INC_544 545 +#define Z_UTIL_INC_545 546 +#define Z_UTIL_INC_546 547 +#define Z_UTIL_INC_547 548 +#define Z_UTIL_INC_548 549 +#define Z_UTIL_INC_549 550 +#define Z_UTIL_INC_550 551 +#define Z_UTIL_INC_551 552 +#define Z_UTIL_INC_552 553 +#define Z_UTIL_INC_553 554 +#define Z_UTIL_INC_554 555 +#define Z_UTIL_INC_555 556 +#define Z_UTIL_INC_556 557 +#define Z_UTIL_INC_557 558 +#define Z_UTIL_INC_558 559 +#define Z_UTIL_INC_559 560 +#define Z_UTIL_INC_560 561 +#define Z_UTIL_INC_561 562 +#define Z_UTIL_INC_562 563 +#define Z_UTIL_INC_563 564 +#define Z_UTIL_INC_564 565 +#define Z_UTIL_INC_565 566 +#define Z_UTIL_INC_566 567 +#define Z_UTIL_INC_567 568 +#define Z_UTIL_INC_568 569 +#define Z_UTIL_INC_569 570 +#define Z_UTIL_INC_570 571 +#define Z_UTIL_INC_571 572 +#define Z_UTIL_INC_572 573 +#define Z_UTIL_INC_573 574 +#define Z_UTIL_INC_574 575 +#define Z_UTIL_INC_575 576 +#define Z_UTIL_INC_576 577 +#define Z_UTIL_INC_577 578 +#define Z_UTIL_INC_578 579 +#define Z_UTIL_INC_579 580 +#define Z_UTIL_INC_580 581 +#define Z_UTIL_INC_581 582 +#define Z_UTIL_INC_582 583 +#define Z_UTIL_INC_583 584 +#define Z_UTIL_INC_584 585 +#define Z_UTIL_INC_585 586 +#define Z_UTIL_INC_586 587 +#define Z_UTIL_INC_587 588 +#define Z_UTIL_INC_588 589 +#define Z_UTIL_INC_589 590 +#define Z_UTIL_INC_590 591 +#define Z_UTIL_INC_591 592 +#define Z_UTIL_INC_592 593 +#define Z_UTIL_INC_593 594 +#define Z_UTIL_INC_594 595 +#define Z_UTIL_INC_595 596 +#define Z_UTIL_INC_596 597 +#define Z_UTIL_INC_597 598 +#define Z_UTIL_INC_598 599 +#define Z_UTIL_INC_599 600 +#define Z_UTIL_INC_600 601 +#define Z_UTIL_INC_601 602 +#define Z_UTIL_INC_602 603 +#define Z_UTIL_INC_603 604 +#define Z_UTIL_INC_604 605 +#define Z_UTIL_INC_605 606 +#define Z_UTIL_INC_606 607 +#define Z_UTIL_INC_607 608 +#define Z_UTIL_INC_608 609 +#define Z_UTIL_INC_609 610 +#define Z_UTIL_INC_610 611 +#define Z_UTIL_INC_611 612 +#define Z_UTIL_INC_612 613 +#define Z_UTIL_INC_613 614 +#define Z_UTIL_INC_614 615 +#define Z_UTIL_INC_615 616 +#define Z_UTIL_INC_616 617 +#define Z_UTIL_INC_617 618 +#define Z_UTIL_INC_618 619 +#define Z_UTIL_INC_619 620 +#define Z_UTIL_INC_620 621 +#define Z_UTIL_INC_621 622 +#define Z_UTIL_INC_622 623 +#define Z_UTIL_INC_623 624 +#define Z_UTIL_INC_624 625 +#define Z_UTIL_INC_625 626 +#define Z_UTIL_INC_626 627 +#define Z_UTIL_INC_627 628 +#define Z_UTIL_INC_628 629 +#define Z_UTIL_INC_629 630 +#define Z_UTIL_INC_630 631 +#define Z_UTIL_INC_631 632 +#define Z_UTIL_INC_632 633 +#define Z_UTIL_INC_633 634 +#define Z_UTIL_INC_634 635 +#define Z_UTIL_INC_635 636 +#define Z_UTIL_INC_636 637 +#define Z_UTIL_INC_637 638 +#define Z_UTIL_INC_638 639 +#define Z_UTIL_INC_639 640 +#define Z_UTIL_INC_640 641 +#define Z_UTIL_INC_641 642 +#define Z_UTIL_INC_642 643 +#define Z_UTIL_INC_643 644 +#define Z_UTIL_INC_644 645 +#define Z_UTIL_INC_645 646 +#define Z_UTIL_INC_646 647 +#define Z_UTIL_INC_647 648 +#define Z_UTIL_INC_648 649 +#define Z_UTIL_INC_649 650 +#define Z_UTIL_INC_650 651 +#define Z_UTIL_INC_651 652 +#define Z_UTIL_INC_652 653 +#define Z_UTIL_INC_653 654 +#define Z_UTIL_INC_654 655 +#define Z_UTIL_INC_655 656 +#define Z_UTIL_INC_656 657 +#define Z_UTIL_INC_657 658 +#define Z_UTIL_INC_658 659 +#define Z_UTIL_INC_659 660 +#define Z_UTIL_INC_660 661 +#define Z_UTIL_INC_661 662 +#define Z_UTIL_INC_662 663 +#define Z_UTIL_INC_663 664 +#define Z_UTIL_INC_664 665 +#define Z_UTIL_INC_665 666 +#define Z_UTIL_INC_666 667 +#define Z_UTIL_INC_667 668 +#define Z_UTIL_INC_668 669 +#define Z_UTIL_INC_669 670 +#define Z_UTIL_INC_670 671 +#define Z_UTIL_INC_671 672 +#define Z_UTIL_INC_672 673 +#define Z_UTIL_INC_673 674 +#define Z_UTIL_INC_674 675 +#define Z_UTIL_INC_675 676 +#define Z_UTIL_INC_676 677 +#define Z_UTIL_INC_677 678 +#define Z_UTIL_INC_678 679 +#define Z_UTIL_INC_679 680 +#define Z_UTIL_INC_680 681 +#define Z_UTIL_INC_681 682 +#define Z_UTIL_INC_682 683 +#define Z_UTIL_INC_683 684 +#define Z_UTIL_INC_684 685 +#define Z_UTIL_INC_685 686 +#define Z_UTIL_INC_686 687 +#define Z_UTIL_INC_687 688 +#define Z_UTIL_INC_688 689 +#define Z_UTIL_INC_689 690 +#define Z_UTIL_INC_690 691 +#define Z_UTIL_INC_691 692 +#define Z_UTIL_INC_692 693 +#define Z_UTIL_INC_693 694 +#define Z_UTIL_INC_694 695 +#define Z_UTIL_INC_695 696 +#define Z_UTIL_INC_696 697 +#define Z_UTIL_INC_697 698 +#define Z_UTIL_INC_698 699 +#define Z_UTIL_INC_699 700 +#define Z_UTIL_INC_700 701 +#define Z_UTIL_INC_701 702 +#define Z_UTIL_INC_702 703 +#define Z_UTIL_INC_703 704 +#define Z_UTIL_INC_704 705 +#define Z_UTIL_INC_705 706 +#define Z_UTIL_INC_706 707 +#define Z_UTIL_INC_707 708 +#define Z_UTIL_INC_708 709 +#define Z_UTIL_INC_709 710 +#define Z_UTIL_INC_710 711 +#define Z_UTIL_INC_711 712 +#define Z_UTIL_INC_712 713 +#define Z_UTIL_INC_713 714 +#define Z_UTIL_INC_714 715 +#define Z_UTIL_INC_715 716 +#define Z_UTIL_INC_716 717 +#define Z_UTIL_INC_717 718 +#define Z_UTIL_INC_718 719 +#define Z_UTIL_INC_719 720 +#define Z_UTIL_INC_720 721 +#define Z_UTIL_INC_721 722 +#define Z_UTIL_INC_722 723 +#define Z_UTIL_INC_723 724 +#define Z_UTIL_INC_724 725 +#define Z_UTIL_INC_725 726 +#define Z_UTIL_INC_726 727 +#define Z_UTIL_INC_727 728 +#define Z_UTIL_INC_728 729 +#define Z_UTIL_INC_729 730 +#define Z_UTIL_INC_730 731 +#define Z_UTIL_INC_731 732 +#define Z_UTIL_INC_732 733 +#define Z_UTIL_INC_733 734 +#define Z_UTIL_INC_734 735 +#define Z_UTIL_INC_735 736 +#define Z_UTIL_INC_736 737 +#define Z_UTIL_INC_737 738 +#define Z_UTIL_INC_738 739 +#define Z_UTIL_INC_739 740 +#define Z_UTIL_INC_740 741 +#define Z_UTIL_INC_741 742 +#define Z_UTIL_INC_742 743 +#define Z_UTIL_INC_743 744 +#define Z_UTIL_INC_744 745 +#define Z_UTIL_INC_745 746 +#define Z_UTIL_INC_746 747 +#define Z_UTIL_INC_747 748 +#define Z_UTIL_INC_748 749 +#define Z_UTIL_INC_749 750 +#define Z_UTIL_INC_750 751 +#define Z_UTIL_INC_751 752 +#define Z_UTIL_INC_752 753 +#define Z_UTIL_INC_753 754 +#define Z_UTIL_INC_754 755 +#define Z_UTIL_INC_755 756 +#define Z_UTIL_INC_756 757 +#define Z_UTIL_INC_757 758 +#define Z_UTIL_INC_758 759 +#define Z_UTIL_INC_759 760 +#define Z_UTIL_INC_760 761 +#define Z_UTIL_INC_761 762 +#define Z_UTIL_INC_762 763 +#define Z_UTIL_INC_763 764 +#define Z_UTIL_INC_764 765 +#define Z_UTIL_INC_765 766 +#define Z_UTIL_INC_766 767 +#define Z_UTIL_INC_767 768 +#define Z_UTIL_INC_768 769 +#define Z_UTIL_INC_769 770 +#define Z_UTIL_INC_770 771 +#define Z_UTIL_INC_771 772 +#define Z_UTIL_INC_772 773 +#define Z_UTIL_INC_773 774 +#define Z_UTIL_INC_774 775 +#define Z_UTIL_INC_775 776 +#define Z_UTIL_INC_776 777 +#define Z_UTIL_INC_777 778 +#define Z_UTIL_INC_778 779 +#define Z_UTIL_INC_779 780 +#define Z_UTIL_INC_780 781 +#define Z_UTIL_INC_781 782 +#define Z_UTIL_INC_782 783 +#define Z_UTIL_INC_783 784 +#define Z_UTIL_INC_784 785 +#define Z_UTIL_INC_785 786 +#define Z_UTIL_INC_786 787 +#define Z_UTIL_INC_787 788 +#define Z_UTIL_INC_788 789 +#define Z_UTIL_INC_789 790 +#define Z_UTIL_INC_790 791 +#define Z_UTIL_INC_791 792 +#define Z_UTIL_INC_792 793 +#define Z_UTIL_INC_793 794 +#define Z_UTIL_INC_794 795 +#define Z_UTIL_INC_795 796 +#define Z_UTIL_INC_796 797 +#define Z_UTIL_INC_797 798 +#define Z_UTIL_INC_798 799 +#define Z_UTIL_INC_799 800 +#define Z_UTIL_INC_800 801 +#define Z_UTIL_INC_801 802 +#define Z_UTIL_INC_802 803 +#define Z_UTIL_INC_803 804 +#define Z_UTIL_INC_804 805 +#define Z_UTIL_INC_805 806 +#define Z_UTIL_INC_806 807 +#define Z_UTIL_INC_807 808 +#define Z_UTIL_INC_808 809 +#define Z_UTIL_INC_809 810 +#define Z_UTIL_INC_810 811 +#define Z_UTIL_INC_811 812 +#define Z_UTIL_INC_812 813 +#define Z_UTIL_INC_813 814 +#define Z_UTIL_INC_814 815 +#define Z_UTIL_INC_815 816 +#define Z_UTIL_INC_816 817 +#define Z_UTIL_INC_817 818 +#define Z_UTIL_INC_818 819 +#define Z_UTIL_INC_819 820 +#define Z_UTIL_INC_820 821 +#define Z_UTIL_INC_821 822 +#define Z_UTIL_INC_822 823 +#define Z_UTIL_INC_823 824 +#define Z_UTIL_INC_824 825 +#define Z_UTIL_INC_825 826 +#define Z_UTIL_INC_826 827 +#define Z_UTIL_INC_827 828 +#define Z_UTIL_INC_828 829 +#define Z_UTIL_INC_829 830 +#define Z_UTIL_INC_830 831 +#define Z_UTIL_INC_831 832 +#define Z_UTIL_INC_832 833 +#define Z_UTIL_INC_833 834 +#define Z_UTIL_INC_834 835 +#define Z_UTIL_INC_835 836 +#define Z_UTIL_INC_836 837 +#define Z_UTIL_INC_837 838 +#define Z_UTIL_INC_838 839 +#define Z_UTIL_INC_839 840 +#define Z_UTIL_INC_840 841 +#define Z_UTIL_INC_841 842 +#define Z_UTIL_INC_842 843 +#define Z_UTIL_INC_843 844 +#define Z_UTIL_INC_844 845 +#define Z_UTIL_INC_845 846 +#define Z_UTIL_INC_846 847 +#define Z_UTIL_INC_847 848 +#define Z_UTIL_INC_848 849 +#define Z_UTIL_INC_849 850 +#define Z_UTIL_INC_850 851 +#define Z_UTIL_INC_851 852 +#define Z_UTIL_INC_852 853 +#define Z_UTIL_INC_853 854 +#define Z_UTIL_INC_854 855 +#define Z_UTIL_INC_855 856 +#define Z_UTIL_INC_856 857 +#define Z_UTIL_INC_857 858 +#define Z_UTIL_INC_858 859 +#define Z_UTIL_INC_859 860 +#define Z_UTIL_INC_860 861 +#define Z_UTIL_INC_861 862 +#define Z_UTIL_INC_862 863 +#define Z_UTIL_INC_863 864 +#define Z_UTIL_INC_864 865 +#define Z_UTIL_INC_865 866 +#define Z_UTIL_INC_866 867 +#define Z_UTIL_INC_867 868 +#define Z_UTIL_INC_868 869 +#define Z_UTIL_INC_869 870 +#define Z_UTIL_INC_870 871 +#define Z_UTIL_INC_871 872 +#define Z_UTIL_INC_872 873 +#define Z_UTIL_INC_873 874 +#define Z_UTIL_INC_874 875 +#define Z_UTIL_INC_875 876 +#define Z_UTIL_INC_876 877 +#define Z_UTIL_INC_877 878 +#define Z_UTIL_INC_878 879 +#define Z_UTIL_INC_879 880 +#define Z_UTIL_INC_880 881 +#define Z_UTIL_INC_881 882 +#define Z_UTIL_INC_882 883 +#define Z_UTIL_INC_883 884 +#define Z_UTIL_INC_884 885 +#define Z_UTIL_INC_885 886 +#define Z_UTIL_INC_886 887 +#define Z_UTIL_INC_887 888 +#define Z_UTIL_INC_888 889 +#define Z_UTIL_INC_889 890 +#define Z_UTIL_INC_890 891 +#define Z_UTIL_INC_891 892 +#define Z_UTIL_INC_892 893 +#define Z_UTIL_INC_893 894 +#define Z_UTIL_INC_894 895 +#define Z_UTIL_INC_895 896 +#define Z_UTIL_INC_896 897 +#define Z_UTIL_INC_897 898 +#define Z_UTIL_INC_898 899 +#define Z_UTIL_INC_899 900 +#define Z_UTIL_INC_900 901 +#define Z_UTIL_INC_901 902 +#define Z_UTIL_INC_902 903 +#define Z_UTIL_INC_903 904 +#define Z_UTIL_INC_904 905 +#define Z_UTIL_INC_905 906 +#define Z_UTIL_INC_906 907 +#define Z_UTIL_INC_907 908 +#define Z_UTIL_INC_908 909 +#define Z_UTIL_INC_909 910 +#define Z_UTIL_INC_910 911 +#define Z_UTIL_INC_911 912 +#define Z_UTIL_INC_912 913 +#define Z_UTIL_INC_913 914 +#define Z_UTIL_INC_914 915 +#define Z_UTIL_INC_915 916 +#define Z_UTIL_INC_916 917 +#define Z_UTIL_INC_917 918 +#define Z_UTIL_INC_918 919 +#define Z_UTIL_INC_919 920 +#define Z_UTIL_INC_920 921 +#define Z_UTIL_INC_921 922 +#define Z_UTIL_INC_922 923 +#define Z_UTIL_INC_923 924 +#define Z_UTIL_INC_924 925 +#define Z_UTIL_INC_925 926 +#define Z_UTIL_INC_926 927 +#define Z_UTIL_INC_927 928 +#define Z_UTIL_INC_928 929 +#define Z_UTIL_INC_929 930 +#define Z_UTIL_INC_930 931 +#define Z_UTIL_INC_931 932 +#define Z_UTIL_INC_932 933 +#define Z_UTIL_INC_933 934 +#define Z_UTIL_INC_934 935 +#define Z_UTIL_INC_935 936 +#define Z_UTIL_INC_936 937 +#define Z_UTIL_INC_937 938 +#define Z_UTIL_INC_938 939 +#define Z_UTIL_INC_939 940 +#define Z_UTIL_INC_940 941 +#define Z_UTIL_INC_941 942 +#define Z_UTIL_INC_942 943 +#define Z_UTIL_INC_943 944 +#define Z_UTIL_INC_944 945 +#define Z_UTIL_INC_945 946 +#define Z_UTIL_INC_946 947 +#define Z_UTIL_INC_947 948 +#define Z_UTIL_INC_948 949 +#define Z_UTIL_INC_949 950 +#define Z_UTIL_INC_950 951 +#define Z_UTIL_INC_951 952 +#define Z_UTIL_INC_952 953 +#define Z_UTIL_INC_953 954 +#define Z_UTIL_INC_954 955 +#define Z_UTIL_INC_955 956 +#define Z_UTIL_INC_956 957 +#define Z_UTIL_INC_957 958 +#define Z_UTIL_INC_958 959 +#define Z_UTIL_INC_959 960 +#define Z_UTIL_INC_960 961 +#define Z_UTIL_INC_961 962 +#define Z_UTIL_INC_962 963 +#define Z_UTIL_INC_963 964 +#define Z_UTIL_INC_964 965 +#define Z_UTIL_INC_965 966 +#define Z_UTIL_INC_966 967 +#define Z_UTIL_INC_967 968 +#define Z_UTIL_INC_968 969 +#define Z_UTIL_INC_969 970 +#define Z_UTIL_INC_970 971 +#define Z_UTIL_INC_971 972 +#define Z_UTIL_INC_972 973 +#define Z_UTIL_INC_973 974 +#define Z_UTIL_INC_974 975 +#define Z_UTIL_INC_975 976 +#define Z_UTIL_INC_976 977 +#define Z_UTIL_INC_977 978 +#define Z_UTIL_INC_978 979 +#define Z_UTIL_INC_979 980 +#define Z_UTIL_INC_980 981 +#define Z_UTIL_INC_981 982 +#define Z_UTIL_INC_982 983 +#define Z_UTIL_INC_983 984 +#define Z_UTIL_INC_984 985 +#define Z_UTIL_INC_985 986 +#define Z_UTIL_INC_986 987 +#define Z_UTIL_INC_987 988 +#define Z_UTIL_INC_988 989 +#define Z_UTIL_INC_989 990 +#define Z_UTIL_INC_990 991 +#define Z_UTIL_INC_991 992 +#define Z_UTIL_INC_992 993 +#define Z_UTIL_INC_993 994 +#define Z_UTIL_INC_994 995 +#define Z_UTIL_INC_995 996 +#define Z_UTIL_INC_996 997 +#define Z_UTIL_INC_997 998 +#define Z_UTIL_INC_998 999 +#define Z_UTIL_INC_999 1000 +#define Z_UTIL_INC_1000 1001 +#define Z_UTIL_INC_1001 1002 +#define Z_UTIL_INC_1002 1003 +#define Z_UTIL_INC_1003 1004 +#define Z_UTIL_INC_1004 1005 +#define Z_UTIL_INC_1005 1006 +#define Z_UTIL_INC_1006 1007 +#define Z_UTIL_INC_1007 1008 +#define Z_UTIL_INC_1008 1009 +#define Z_UTIL_INC_1009 1010 +#define Z_UTIL_INC_1010 1011 +#define Z_UTIL_INC_1011 1012 +#define Z_UTIL_INC_1012 1013 +#define Z_UTIL_INC_1013 1014 +#define Z_UTIL_INC_1014 1015 +#define Z_UTIL_INC_1015 1016 +#define Z_UTIL_INC_1016 1017 +#define Z_UTIL_INC_1017 1018 +#define Z_UTIL_INC_1018 1019 +#define Z_UTIL_INC_1019 1020 +#define Z_UTIL_INC_1020 1021 +#define Z_UTIL_INC_1021 1022 +#define Z_UTIL_INC_1022 1023 +#define Z_UTIL_INC_1023 1024 +#define Z_UTIL_INC_1024 1025 +#define Z_UTIL_INC_1025 1026 +#define Z_UTIL_INC_1026 1027 +#define Z_UTIL_INC_1027 1028 +#define Z_UTIL_INC_1028 1029 +#define Z_UTIL_INC_1029 1030 +#define Z_UTIL_INC_1030 1031 +#define Z_UTIL_INC_1031 1032 +#define Z_UTIL_INC_1032 1033 +#define Z_UTIL_INC_1033 1034 +#define Z_UTIL_INC_1034 1035 +#define Z_UTIL_INC_1035 1036 +#define Z_UTIL_INC_1036 1037 +#define Z_UTIL_INC_1037 1038 +#define Z_UTIL_INC_1038 1039 +#define Z_UTIL_INC_1039 1040 +#define Z_UTIL_INC_1040 1041 +#define Z_UTIL_INC_1041 1042 +#define Z_UTIL_INC_1042 1043 +#define Z_UTIL_INC_1043 1044 +#define Z_UTIL_INC_1044 1045 +#define Z_UTIL_INC_1045 1046 +#define Z_UTIL_INC_1046 1047 +#define Z_UTIL_INC_1047 1048 +#define Z_UTIL_INC_1048 1049 +#define Z_UTIL_INC_1049 1050 +#define Z_UTIL_INC_1050 1051 +#define Z_UTIL_INC_1051 1052 +#define Z_UTIL_INC_1052 1053 +#define Z_UTIL_INC_1053 1054 +#define Z_UTIL_INC_1054 1055 +#define Z_UTIL_INC_1055 1056 +#define Z_UTIL_INC_1056 1057 +#define Z_UTIL_INC_1057 1058 +#define Z_UTIL_INC_1058 1059 +#define Z_UTIL_INC_1059 1060 +#define Z_UTIL_INC_1060 1061 +#define Z_UTIL_INC_1061 1062 +#define Z_UTIL_INC_1062 1063 +#define Z_UTIL_INC_1063 1064 +#define Z_UTIL_INC_1064 1065 +#define Z_UTIL_INC_1065 1066 +#define Z_UTIL_INC_1066 1067 +#define Z_UTIL_INC_1067 1068 +#define Z_UTIL_INC_1068 1069 +#define Z_UTIL_INC_1069 1070 +#define Z_UTIL_INC_1070 1071 +#define Z_UTIL_INC_1071 1072 +#define Z_UTIL_INC_1072 1073 +#define Z_UTIL_INC_1073 1074 +#define Z_UTIL_INC_1074 1075 +#define Z_UTIL_INC_1075 1076 +#define Z_UTIL_INC_1076 1077 +#define Z_UTIL_INC_1077 1078 +#define Z_UTIL_INC_1078 1079 +#define Z_UTIL_INC_1079 1080 +#define Z_UTIL_INC_1080 1081 +#define Z_UTIL_INC_1081 1082 +#define Z_UTIL_INC_1082 1083 +#define Z_UTIL_INC_1083 1084 +#define Z_UTIL_INC_1084 1085 +#define Z_UTIL_INC_1085 1086 +#define Z_UTIL_INC_1086 1087 +#define Z_UTIL_INC_1087 1088 +#define Z_UTIL_INC_1088 1089 +#define Z_UTIL_INC_1089 1090 +#define Z_UTIL_INC_1090 1091 +#define Z_UTIL_INC_1091 1092 +#define Z_UTIL_INC_1092 1093 +#define Z_UTIL_INC_1093 1094 +#define Z_UTIL_INC_1094 1095 +#define Z_UTIL_INC_1095 1096 +#define Z_UTIL_INC_1096 1097 +#define Z_UTIL_INC_1097 1098 +#define Z_UTIL_INC_1098 1099 +#define Z_UTIL_INC_1099 1100 +#define Z_UTIL_INC_1100 1101 +#define Z_UTIL_INC_1101 1102 +#define Z_UTIL_INC_1102 1103 +#define Z_UTIL_INC_1103 1104 +#define Z_UTIL_INC_1104 1105 +#define Z_UTIL_INC_1105 1106 +#define Z_UTIL_INC_1106 1107 +#define Z_UTIL_INC_1107 1108 +#define Z_UTIL_INC_1108 1109 +#define Z_UTIL_INC_1109 1110 +#define Z_UTIL_INC_1110 1111 +#define Z_UTIL_INC_1111 1112 +#define Z_UTIL_INC_1112 1113 +#define Z_UTIL_INC_1113 1114 +#define Z_UTIL_INC_1114 1115 +#define Z_UTIL_INC_1115 1116 +#define Z_UTIL_INC_1116 1117 +#define Z_UTIL_INC_1117 1118 +#define Z_UTIL_INC_1118 1119 +#define Z_UTIL_INC_1119 1120 +#define Z_UTIL_INC_1120 1121 +#define Z_UTIL_INC_1121 1122 +#define Z_UTIL_INC_1122 1123 +#define Z_UTIL_INC_1123 1124 +#define Z_UTIL_INC_1124 1125 +#define Z_UTIL_INC_1125 1126 +#define Z_UTIL_INC_1126 1127 +#define Z_UTIL_INC_1127 1128 +#define Z_UTIL_INC_1128 1129 +#define Z_UTIL_INC_1129 1130 +#define Z_UTIL_INC_1130 1131 +#define Z_UTIL_INC_1131 1132 +#define Z_UTIL_INC_1132 1133 +#define Z_UTIL_INC_1133 1134 +#define Z_UTIL_INC_1134 1135 +#define Z_UTIL_INC_1135 1136 +#define Z_UTIL_INC_1136 1137 +#define Z_UTIL_INC_1137 1138 +#define Z_UTIL_INC_1138 1139 +#define Z_UTIL_INC_1139 1140 +#define Z_UTIL_INC_1140 1141 +#define Z_UTIL_INC_1141 1142 +#define Z_UTIL_INC_1142 1143 +#define Z_UTIL_INC_1143 1144 +#define Z_UTIL_INC_1144 1145 +#define Z_UTIL_INC_1145 1146 +#define Z_UTIL_INC_1146 1147 +#define Z_UTIL_INC_1147 1148 +#define Z_UTIL_INC_1148 1149 +#define Z_UTIL_INC_1149 1150 +#define Z_UTIL_INC_1150 1151 +#define Z_UTIL_INC_1151 1152 +#define Z_UTIL_INC_1152 1153 +#define Z_UTIL_INC_1153 1154 +#define Z_UTIL_INC_1154 1155 +#define Z_UTIL_INC_1155 1156 +#define Z_UTIL_INC_1156 1157 +#define Z_UTIL_INC_1157 1158 +#define Z_UTIL_INC_1158 1159 +#define Z_UTIL_INC_1159 1160 +#define Z_UTIL_INC_1160 1161 +#define Z_UTIL_INC_1161 1162 +#define Z_UTIL_INC_1162 1163 +#define Z_UTIL_INC_1163 1164 +#define Z_UTIL_INC_1164 1165 +#define Z_UTIL_INC_1165 1166 +#define Z_UTIL_INC_1166 1167 +#define Z_UTIL_INC_1167 1168 +#define Z_UTIL_INC_1168 1169 +#define Z_UTIL_INC_1169 1170 +#define Z_UTIL_INC_1170 1171 +#define Z_UTIL_INC_1171 1172 +#define Z_UTIL_INC_1172 1173 +#define Z_UTIL_INC_1173 1174 +#define Z_UTIL_INC_1174 1175 +#define Z_UTIL_INC_1175 1176 +#define Z_UTIL_INC_1176 1177 +#define Z_UTIL_INC_1177 1178 +#define Z_UTIL_INC_1178 1179 +#define Z_UTIL_INC_1179 1180 +#define Z_UTIL_INC_1180 1181 +#define Z_UTIL_INC_1181 1182 +#define Z_UTIL_INC_1182 1183 +#define Z_UTIL_INC_1183 1184 +#define Z_UTIL_INC_1184 1185 +#define Z_UTIL_INC_1185 1186 +#define Z_UTIL_INC_1186 1187 +#define Z_UTIL_INC_1187 1188 +#define Z_UTIL_INC_1188 1189 +#define Z_UTIL_INC_1189 1190 +#define Z_UTIL_INC_1190 1191 +#define Z_UTIL_INC_1191 1192 +#define Z_UTIL_INC_1192 1193 +#define Z_UTIL_INC_1193 1194 +#define Z_UTIL_INC_1194 1195 +#define Z_UTIL_INC_1195 1196 +#define Z_UTIL_INC_1196 1197 +#define Z_UTIL_INC_1197 1198 +#define Z_UTIL_INC_1198 1199 +#define Z_UTIL_INC_1199 1200 +#define Z_UTIL_INC_1200 1201 +#define Z_UTIL_INC_1201 1202 +#define Z_UTIL_INC_1202 1203 +#define Z_UTIL_INC_1203 1204 +#define Z_UTIL_INC_1204 1205 +#define Z_UTIL_INC_1205 1206 +#define Z_UTIL_INC_1206 1207 +#define Z_UTIL_INC_1207 1208 +#define Z_UTIL_INC_1208 1209 +#define Z_UTIL_INC_1209 1210 +#define Z_UTIL_INC_1210 1211 +#define Z_UTIL_INC_1211 1212 +#define Z_UTIL_INC_1212 1213 +#define Z_UTIL_INC_1213 1214 +#define Z_UTIL_INC_1214 1215 +#define Z_UTIL_INC_1215 1216 +#define Z_UTIL_INC_1216 1217 +#define Z_UTIL_INC_1217 1218 +#define Z_UTIL_INC_1218 1219 +#define Z_UTIL_INC_1219 1220 +#define Z_UTIL_INC_1220 1221 +#define Z_UTIL_INC_1221 1222 +#define Z_UTIL_INC_1222 1223 +#define Z_UTIL_INC_1223 1224 +#define Z_UTIL_INC_1224 1225 +#define Z_UTIL_INC_1225 1226 +#define Z_UTIL_INC_1226 1227 +#define Z_UTIL_INC_1227 1228 +#define Z_UTIL_INC_1228 1229 +#define Z_UTIL_INC_1229 1230 +#define Z_UTIL_INC_1230 1231 +#define Z_UTIL_INC_1231 1232 +#define Z_UTIL_INC_1232 1233 +#define Z_UTIL_INC_1233 1234 +#define Z_UTIL_INC_1234 1235 +#define Z_UTIL_INC_1235 1236 +#define Z_UTIL_INC_1236 1237 +#define Z_UTIL_INC_1237 1238 +#define Z_UTIL_INC_1238 1239 +#define Z_UTIL_INC_1239 1240 +#define Z_UTIL_INC_1240 1241 +#define Z_UTIL_INC_1241 1242 +#define Z_UTIL_INC_1242 1243 +#define Z_UTIL_INC_1243 1244 +#define Z_UTIL_INC_1244 1245 +#define Z_UTIL_INC_1245 1246 +#define Z_UTIL_INC_1246 1247 +#define Z_UTIL_INC_1247 1248 +#define Z_UTIL_INC_1248 1249 +#define Z_UTIL_INC_1249 1250 +#define Z_UTIL_INC_1250 1251 +#define Z_UTIL_INC_1251 1252 +#define Z_UTIL_INC_1252 1253 +#define Z_UTIL_INC_1253 1254 +#define Z_UTIL_INC_1254 1255 +#define Z_UTIL_INC_1255 1256 +#define Z_UTIL_INC_1256 1257 +#define Z_UTIL_INC_1257 1258 +#define Z_UTIL_INC_1258 1259 +#define Z_UTIL_INC_1259 1260 +#define Z_UTIL_INC_1260 1261 +#define Z_UTIL_INC_1261 1262 +#define Z_UTIL_INC_1262 1263 +#define Z_UTIL_INC_1263 1264 +#define Z_UTIL_INC_1264 1265 +#define Z_UTIL_INC_1265 1266 +#define Z_UTIL_INC_1266 1267 +#define Z_UTIL_INC_1267 1268 +#define Z_UTIL_INC_1268 1269 +#define Z_UTIL_INC_1269 1270 +#define Z_UTIL_INC_1270 1271 +#define Z_UTIL_INC_1271 1272 +#define Z_UTIL_INC_1272 1273 +#define Z_UTIL_INC_1273 1274 +#define Z_UTIL_INC_1274 1275 +#define Z_UTIL_INC_1275 1276 +#define Z_UTIL_INC_1276 1277 +#define Z_UTIL_INC_1277 1278 +#define Z_UTIL_INC_1278 1279 +#define Z_UTIL_INC_1279 1280 +#define Z_UTIL_INC_1280 1281 +#define Z_UTIL_INC_1281 1282 +#define Z_UTIL_INC_1282 1283 +#define Z_UTIL_INC_1283 1284 +#define Z_UTIL_INC_1284 1285 +#define Z_UTIL_INC_1285 1286 +#define Z_UTIL_INC_1286 1287 +#define Z_UTIL_INC_1287 1288 +#define Z_UTIL_INC_1288 1289 +#define Z_UTIL_INC_1289 1290 +#define Z_UTIL_INC_1290 1291 +#define Z_UTIL_INC_1291 1292 +#define Z_UTIL_INC_1292 1293 +#define Z_UTIL_INC_1293 1294 +#define Z_UTIL_INC_1294 1295 +#define Z_UTIL_INC_1295 1296 +#define Z_UTIL_INC_1296 1297 +#define Z_UTIL_INC_1297 1298 +#define Z_UTIL_INC_1298 1299 +#define Z_UTIL_INC_1299 1300 +#define Z_UTIL_INC_1300 1301 +#define Z_UTIL_INC_1301 1302 +#define Z_UTIL_INC_1302 1303 +#define Z_UTIL_INC_1303 1304 +#define Z_UTIL_INC_1304 1305 +#define Z_UTIL_INC_1305 1306 +#define Z_UTIL_INC_1306 1307 +#define Z_UTIL_INC_1307 1308 +#define Z_UTIL_INC_1308 1309 +#define Z_UTIL_INC_1309 1310 +#define Z_UTIL_INC_1310 1311 +#define Z_UTIL_INC_1311 1312 +#define Z_UTIL_INC_1312 1313 +#define Z_UTIL_INC_1313 1314 +#define Z_UTIL_INC_1314 1315 +#define Z_UTIL_INC_1315 1316 +#define Z_UTIL_INC_1316 1317 +#define Z_UTIL_INC_1317 1318 +#define Z_UTIL_INC_1318 1319 +#define Z_UTIL_INC_1319 1320 +#define Z_UTIL_INC_1320 1321 +#define Z_UTIL_INC_1321 1322 +#define Z_UTIL_INC_1322 1323 +#define Z_UTIL_INC_1323 1324 +#define Z_UTIL_INC_1324 1325 +#define Z_UTIL_INC_1325 1326 +#define Z_UTIL_INC_1326 1327 +#define Z_UTIL_INC_1327 1328 +#define Z_UTIL_INC_1328 1329 +#define Z_UTIL_INC_1329 1330 +#define Z_UTIL_INC_1330 1331 +#define Z_UTIL_INC_1331 1332 +#define Z_UTIL_INC_1332 1333 +#define Z_UTIL_INC_1333 1334 +#define Z_UTIL_INC_1334 1335 +#define Z_UTIL_INC_1335 1336 +#define Z_UTIL_INC_1336 1337 +#define Z_UTIL_INC_1337 1338 +#define Z_UTIL_INC_1338 1339 +#define Z_UTIL_INC_1339 1340 +#define Z_UTIL_INC_1340 1341 +#define Z_UTIL_INC_1341 1342 +#define Z_UTIL_INC_1342 1343 +#define Z_UTIL_INC_1343 1344 +#define Z_UTIL_INC_1344 1345 +#define Z_UTIL_INC_1345 1346 +#define Z_UTIL_INC_1346 1347 +#define Z_UTIL_INC_1347 1348 +#define Z_UTIL_INC_1348 1349 +#define Z_UTIL_INC_1349 1350 +#define Z_UTIL_INC_1350 1351 +#define Z_UTIL_INC_1351 1352 +#define Z_UTIL_INC_1352 1353 +#define Z_UTIL_INC_1353 1354 +#define Z_UTIL_INC_1354 1355 +#define Z_UTIL_INC_1355 1356 +#define Z_UTIL_INC_1356 1357 +#define Z_UTIL_INC_1357 1358 +#define Z_UTIL_INC_1358 1359 +#define Z_UTIL_INC_1359 1360 +#define Z_UTIL_INC_1360 1361 +#define Z_UTIL_INC_1361 1362 +#define Z_UTIL_INC_1362 1363 +#define Z_UTIL_INC_1363 1364 +#define Z_UTIL_INC_1364 1365 +#define Z_UTIL_INC_1365 1366 +#define Z_UTIL_INC_1366 1367 +#define Z_UTIL_INC_1367 1368 +#define Z_UTIL_INC_1368 1369 +#define Z_UTIL_INC_1369 1370 +#define Z_UTIL_INC_1370 1371 +#define Z_UTIL_INC_1371 1372 +#define Z_UTIL_INC_1372 1373 +#define Z_UTIL_INC_1373 1374 +#define Z_UTIL_INC_1374 1375 +#define Z_UTIL_INC_1375 1376 +#define Z_UTIL_INC_1376 1377 +#define Z_UTIL_INC_1377 1378 +#define Z_UTIL_INC_1378 1379 +#define Z_UTIL_INC_1379 1380 +#define Z_UTIL_INC_1380 1381 +#define Z_UTIL_INC_1381 1382 +#define Z_UTIL_INC_1382 1383 +#define Z_UTIL_INC_1383 1384 +#define Z_UTIL_INC_1384 1385 +#define Z_UTIL_INC_1385 1386 +#define Z_UTIL_INC_1386 1387 +#define Z_UTIL_INC_1387 1388 +#define Z_UTIL_INC_1388 1389 +#define Z_UTIL_INC_1389 1390 +#define Z_UTIL_INC_1390 1391 +#define Z_UTIL_INC_1391 1392 +#define Z_UTIL_INC_1392 1393 +#define Z_UTIL_INC_1393 1394 +#define Z_UTIL_INC_1394 1395 +#define Z_UTIL_INC_1395 1396 +#define Z_UTIL_INC_1396 1397 +#define Z_UTIL_INC_1397 1398 +#define Z_UTIL_INC_1398 1399 +#define Z_UTIL_INC_1399 1400 +#define Z_UTIL_INC_1400 1401 +#define Z_UTIL_INC_1401 1402 +#define Z_UTIL_INC_1402 1403 +#define Z_UTIL_INC_1403 1404 +#define Z_UTIL_INC_1404 1405 +#define Z_UTIL_INC_1405 1406 +#define Z_UTIL_INC_1406 1407 +#define Z_UTIL_INC_1407 1408 +#define Z_UTIL_INC_1408 1409 +#define Z_UTIL_INC_1409 1410 +#define Z_UTIL_INC_1410 1411 +#define Z_UTIL_INC_1411 1412 +#define Z_UTIL_INC_1412 1413 +#define Z_UTIL_INC_1413 1414 +#define Z_UTIL_INC_1414 1415 +#define Z_UTIL_INC_1415 1416 +#define Z_UTIL_INC_1416 1417 +#define Z_UTIL_INC_1417 1418 +#define Z_UTIL_INC_1418 1419 +#define Z_UTIL_INC_1419 1420 +#define Z_UTIL_INC_1420 1421 +#define Z_UTIL_INC_1421 1422 +#define Z_UTIL_INC_1422 1423 +#define Z_UTIL_INC_1423 1424 +#define Z_UTIL_INC_1424 1425 +#define Z_UTIL_INC_1425 1426 +#define Z_UTIL_INC_1426 1427 +#define Z_UTIL_INC_1427 1428 +#define Z_UTIL_INC_1428 1429 +#define Z_UTIL_INC_1429 1430 +#define Z_UTIL_INC_1430 1431 +#define Z_UTIL_INC_1431 1432 +#define Z_UTIL_INC_1432 1433 +#define Z_UTIL_INC_1433 1434 +#define Z_UTIL_INC_1434 1435 +#define Z_UTIL_INC_1435 1436 +#define Z_UTIL_INC_1436 1437 +#define Z_UTIL_INC_1437 1438 +#define Z_UTIL_INC_1438 1439 +#define Z_UTIL_INC_1439 1440 +#define Z_UTIL_INC_1440 1441 +#define Z_UTIL_INC_1441 1442 +#define Z_UTIL_INC_1442 1443 +#define Z_UTIL_INC_1443 1444 +#define Z_UTIL_INC_1444 1445 +#define Z_UTIL_INC_1445 1446 +#define Z_UTIL_INC_1446 1447 +#define Z_UTIL_INC_1447 1448 +#define Z_UTIL_INC_1448 1449 +#define Z_UTIL_INC_1449 1450 +#define Z_UTIL_INC_1450 1451 +#define Z_UTIL_INC_1451 1452 +#define Z_UTIL_INC_1452 1453 +#define Z_UTIL_INC_1453 1454 +#define Z_UTIL_INC_1454 1455 +#define Z_UTIL_INC_1455 1456 +#define Z_UTIL_INC_1456 1457 +#define Z_UTIL_INC_1457 1458 +#define Z_UTIL_INC_1458 1459 +#define Z_UTIL_INC_1459 1460 +#define Z_UTIL_INC_1460 1461 +#define Z_UTIL_INC_1461 1462 +#define Z_UTIL_INC_1462 1463 +#define Z_UTIL_INC_1463 1464 +#define Z_UTIL_INC_1464 1465 +#define Z_UTIL_INC_1465 1466 +#define Z_UTIL_INC_1466 1467 +#define Z_UTIL_INC_1467 1468 +#define Z_UTIL_INC_1468 1469 +#define Z_UTIL_INC_1469 1470 +#define Z_UTIL_INC_1470 1471 +#define Z_UTIL_INC_1471 1472 +#define Z_UTIL_INC_1472 1473 +#define Z_UTIL_INC_1473 1474 +#define Z_UTIL_INC_1474 1475 +#define Z_UTIL_INC_1475 1476 +#define Z_UTIL_INC_1476 1477 +#define Z_UTIL_INC_1477 1478 +#define Z_UTIL_INC_1478 1479 +#define Z_UTIL_INC_1479 1480 +#define Z_UTIL_INC_1480 1481 +#define Z_UTIL_INC_1481 1482 +#define Z_UTIL_INC_1482 1483 +#define Z_UTIL_INC_1483 1484 +#define Z_UTIL_INC_1484 1485 +#define Z_UTIL_INC_1485 1486 +#define Z_UTIL_INC_1486 1487 +#define Z_UTIL_INC_1487 1488 +#define Z_UTIL_INC_1488 1489 +#define Z_UTIL_INC_1489 1490 +#define Z_UTIL_INC_1490 1491 +#define Z_UTIL_INC_1491 1492 +#define Z_UTIL_INC_1492 1493 +#define Z_UTIL_INC_1493 1494 +#define Z_UTIL_INC_1494 1495 +#define Z_UTIL_INC_1495 1496 +#define Z_UTIL_INC_1496 1497 +#define Z_UTIL_INC_1497 1498 +#define Z_UTIL_INC_1498 1499 +#define Z_UTIL_INC_1499 1500 +#define Z_UTIL_INC_1500 1501 +#define Z_UTIL_INC_1501 1502 +#define Z_UTIL_INC_1502 1503 +#define Z_UTIL_INC_1503 1504 +#define Z_UTIL_INC_1504 1505 +#define Z_UTIL_INC_1505 1506 +#define Z_UTIL_INC_1506 1507 +#define Z_UTIL_INC_1507 1508 +#define Z_UTIL_INC_1508 1509 +#define Z_UTIL_INC_1509 1510 +#define Z_UTIL_INC_1510 1511 +#define Z_UTIL_INC_1511 1512 +#define Z_UTIL_INC_1512 1513 +#define Z_UTIL_INC_1513 1514 +#define Z_UTIL_INC_1514 1515 +#define Z_UTIL_INC_1515 1516 +#define Z_UTIL_INC_1516 1517 +#define Z_UTIL_INC_1517 1518 +#define Z_UTIL_INC_1518 1519 +#define Z_UTIL_INC_1519 1520 +#define Z_UTIL_INC_1520 1521 +#define Z_UTIL_INC_1521 1522 +#define Z_UTIL_INC_1522 1523 +#define Z_UTIL_INC_1523 1524 +#define Z_UTIL_INC_1524 1525 +#define Z_UTIL_INC_1525 1526 +#define Z_UTIL_INC_1526 1527 +#define Z_UTIL_INC_1527 1528 +#define Z_UTIL_INC_1528 1529 +#define Z_UTIL_INC_1529 1530 +#define Z_UTIL_INC_1530 1531 +#define Z_UTIL_INC_1531 1532 +#define Z_UTIL_INC_1532 1533 +#define Z_UTIL_INC_1533 1534 +#define Z_UTIL_INC_1534 1535 +#define Z_UTIL_INC_1535 1536 +#define Z_UTIL_INC_1536 1537 +#define Z_UTIL_INC_1537 1538 +#define Z_UTIL_INC_1538 1539 +#define Z_UTIL_INC_1539 1540 +#define Z_UTIL_INC_1540 1541 +#define Z_UTIL_INC_1541 1542 +#define Z_UTIL_INC_1542 1543 +#define Z_UTIL_INC_1543 1544 +#define Z_UTIL_INC_1544 1545 +#define Z_UTIL_INC_1545 1546 +#define Z_UTIL_INC_1546 1547 +#define Z_UTIL_INC_1547 1548 +#define Z_UTIL_INC_1548 1549 +#define Z_UTIL_INC_1549 1550 +#define Z_UTIL_INC_1550 1551 +#define Z_UTIL_INC_1551 1552 +#define Z_UTIL_INC_1552 1553 +#define Z_UTIL_INC_1553 1554 +#define Z_UTIL_INC_1554 1555 +#define Z_UTIL_INC_1555 1556 +#define Z_UTIL_INC_1556 1557 +#define Z_UTIL_INC_1557 1558 +#define Z_UTIL_INC_1558 1559 +#define Z_UTIL_INC_1559 1560 +#define Z_UTIL_INC_1560 1561 +#define Z_UTIL_INC_1561 1562 +#define Z_UTIL_INC_1562 1563 +#define Z_UTIL_INC_1563 1564 +#define Z_UTIL_INC_1564 1565 +#define Z_UTIL_INC_1565 1566 +#define Z_UTIL_INC_1566 1567 +#define Z_UTIL_INC_1567 1568 +#define Z_UTIL_INC_1568 1569 +#define Z_UTIL_INC_1569 1570 +#define Z_UTIL_INC_1570 1571 +#define Z_UTIL_INC_1571 1572 +#define Z_UTIL_INC_1572 1573 +#define Z_UTIL_INC_1573 1574 +#define Z_UTIL_INC_1574 1575 +#define Z_UTIL_INC_1575 1576 +#define Z_UTIL_INC_1576 1577 +#define Z_UTIL_INC_1577 1578 +#define Z_UTIL_INC_1578 1579 +#define Z_UTIL_INC_1579 1580 +#define Z_UTIL_INC_1580 1581 +#define Z_UTIL_INC_1581 1582 +#define Z_UTIL_INC_1582 1583 +#define Z_UTIL_INC_1583 1584 +#define Z_UTIL_INC_1584 1585 +#define Z_UTIL_INC_1585 1586 +#define Z_UTIL_INC_1586 1587 +#define Z_UTIL_INC_1587 1588 +#define Z_UTIL_INC_1588 1589 +#define Z_UTIL_INC_1589 1590 +#define Z_UTIL_INC_1590 1591 +#define Z_UTIL_INC_1591 1592 +#define Z_UTIL_INC_1592 1593 +#define Z_UTIL_INC_1593 1594 +#define Z_UTIL_INC_1594 1595 +#define Z_UTIL_INC_1595 1596 +#define Z_UTIL_INC_1596 1597 +#define Z_UTIL_INC_1597 1598 +#define Z_UTIL_INC_1598 1599 +#define Z_UTIL_INC_1599 1600 +#define Z_UTIL_INC_1600 1601 +#define Z_UTIL_INC_1601 1602 +#define Z_UTIL_INC_1602 1603 +#define Z_UTIL_INC_1603 1604 +#define Z_UTIL_INC_1604 1605 +#define Z_UTIL_INC_1605 1606 +#define Z_UTIL_INC_1606 1607 +#define Z_UTIL_INC_1607 1608 +#define Z_UTIL_INC_1608 1609 +#define Z_UTIL_INC_1609 1610 +#define Z_UTIL_INC_1610 1611 +#define Z_UTIL_INC_1611 1612 +#define Z_UTIL_INC_1612 1613 +#define Z_UTIL_INC_1613 1614 +#define Z_UTIL_INC_1614 1615 +#define Z_UTIL_INC_1615 1616 +#define Z_UTIL_INC_1616 1617 +#define Z_UTIL_INC_1617 1618 +#define Z_UTIL_INC_1618 1619 +#define Z_UTIL_INC_1619 1620 +#define Z_UTIL_INC_1620 1621 +#define Z_UTIL_INC_1621 1622 +#define Z_UTIL_INC_1622 1623 +#define Z_UTIL_INC_1623 1624 +#define Z_UTIL_INC_1624 1625 +#define Z_UTIL_INC_1625 1626 +#define Z_UTIL_INC_1626 1627 +#define Z_UTIL_INC_1627 1628 +#define Z_UTIL_INC_1628 1629 +#define Z_UTIL_INC_1629 1630 +#define Z_UTIL_INC_1630 1631 +#define Z_UTIL_INC_1631 1632 +#define Z_UTIL_INC_1632 1633 +#define Z_UTIL_INC_1633 1634 +#define Z_UTIL_INC_1634 1635 +#define Z_UTIL_INC_1635 1636 +#define Z_UTIL_INC_1636 1637 +#define Z_UTIL_INC_1637 1638 +#define Z_UTIL_INC_1638 1639 +#define Z_UTIL_INC_1639 1640 +#define Z_UTIL_INC_1640 1641 +#define Z_UTIL_INC_1641 1642 +#define Z_UTIL_INC_1642 1643 +#define Z_UTIL_INC_1643 1644 +#define Z_UTIL_INC_1644 1645 +#define Z_UTIL_INC_1645 1646 +#define Z_UTIL_INC_1646 1647 +#define Z_UTIL_INC_1647 1648 +#define Z_UTIL_INC_1648 1649 +#define Z_UTIL_INC_1649 1650 +#define Z_UTIL_INC_1650 1651 +#define Z_UTIL_INC_1651 1652 +#define Z_UTIL_INC_1652 1653 +#define Z_UTIL_INC_1653 1654 +#define Z_UTIL_INC_1654 1655 +#define Z_UTIL_INC_1655 1656 +#define Z_UTIL_INC_1656 1657 +#define Z_UTIL_INC_1657 1658 +#define Z_UTIL_INC_1658 1659 +#define Z_UTIL_INC_1659 1660 +#define Z_UTIL_INC_1660 1661 +#define Z_UTIL_INC_1661 1662 +#define Z_UTIL_INC_1662 1663 +#define Z_UTIL_INC_1663 1664 +#define Z_UTIL_INC_1664 1665 +#define Z_UTIL_INC_1665 1666 +#define Z_UTIL_INC_1666 1667 +#define Z_UTIL_INC_1667 1668 +#define Z_UTIL_INC_1668 1669 +#define Z_UTIL_INC_1669 1670 +#define Z_UTIL_INC_1670 1671 +#define Z_UTIL_INC_1671 1672 +#define Z_UTIL_INC_1672 1673 +#define Z_UTIL_INC_1673 1674 +#define Z_UTIL_INC_1674 1675 +#define Z_UTIL_INC_1675 1676 +#define Z_UTIL_INC_1676 1677 +#define Z_UTIL_INC_1677 1678 +#define Z_UTIL_INC_1678 1679 +#define Z_UTIL_INC_1679 1680 +#define Z_UTIL_INC_1680 1681 +#define Z_UTIL_INC_1681 1682 +#define Z_UTIL_INC_1682 1683 +#define Z_UTIL_INC_1683 1684 +#define Z_UTIL_INC_1684 1685 +#define Z_UTIL_INC_1685 1686 +#define Z_UTIL_INC_1686 1687 +#define Z_UTIL_INC_1687 1688 +#define Z_UTIL_INC_1688 1689 +#define Z_UTIL_INC_1689 1690 +#define Z_UTIL_INC_1690 1691 +#define Z_UTIL_INC_1691 1692 +#define Z_UTIL_INC_1692 1693 +#define Z_UTIL_INC_1693 1694 +#define Z_UTIL_INC_1694 1695 +#define Z_UTIL_INC_1695 1696 +#define Z_UTIL_INC_1696 1697 +#define Z_UTIL_INC_1697 1698 +#define Z_UTIL_INC_1698 1699 +#define Z_UTIL_INC_1699 1700 +#define Z_UTIL_INC_1700 1701 +#define Z_UTIL_INC_1701 1702 +#define Z_UTIL_INC_1702 1703 +#define Z_UTIL_INC_1703 1704 +#define Z_UTIL_INC_1704 1705 +#define Z_UTIL_INC_1705 1706 +#define Z_UTIL_INC_1706 1707 +#define Z_UTIL_INC_1707 1708 +#define Z_UTIL_INC_1708 1709 +#define Z_UTIL_INC_1709 1710 +#define Z_UTIL_INC_1710 1711 +#define Z_UTIL_INC_1711 1712 +#define Z_UTIL_INC_1712 1713 +#define Z_UTIL_INC_1713 1714 +#define Z_UTIL_INC_1714 1715 +#define Z_UTIL_INC_1715 1716 +#define Z_UTIL_INC_1716 1717 +#define Z_UTIL_INC_1717 1718 +#define Z_UTIL_INC_1718 1719 +#define Z_UTIL_INC_1719 1720 +#define Z_UTIL_INC_1720 1721 +#define Z_UTIL_INC_1721 1722 +#define Z_UTIL_INC_1722 1723 +#define Z_UTIL_INC_1723 1724 +#define Z_UTIL_INC_1724 1725 +#define Z_UTIL_INC_1725 1726 +#define Z_UTIL_INC_1726 1727 +#define Z_UTIL_INC_1727 1728 +#define Z_UTIL_INC_1728 1729 +#define Z_UTIL_INC_1729 1730 +#define Z_UTIL_INC_1730 1731 +#define Z_UTIL_INC_1731 1732 +#define Z_UTIL_INC_1732 1733 +#define Z_UTIL_INC_1733 1734 +#define Z_UTIL_INC_1734 1735 +#define Z_UTIL_INC_1735 1736 +#define Z_UTIL_INC_1736 1737 +#define Z_UTIL_INC_1737 1738 +#define Z_UTIL_INC_1738 1739 +#define Z_UTIL_INC_1739 1740 +#define Z_UTIL_INC_1740 1741 +#define Z_UTIL_INC_1741 1742 +#define Z_UTIL_INC_1742 1743 +#define Z_UTIL_INC_1743 1744 +#define Z_UTIL_INC_1744 1745 +#define Z_UTIL_INC_1745 1746 +#define Z_UTIL_INC_1746 1747 +#define Z_UTIL_INC_1747 1748 +#define Z_UTIL_INC_1748 1749 +#define Z_UTIL_INC_1749 1750 +#define Z_UTIL_INC_1750 1751 +#define Z_UTIL_INC_1751 1752 +#define Z_UTIL_INC_1752 1753 +#define Z_UTIL_INC_1753 1754 +#define Z_UTIL_INC_1754 1755 +#define Z_UTIL_INC_1755 1756 +#define Z_UTIL_INC_1756 1757 +#define Z_UTIL_INC_1757 1758 +#define Z_UTIL_INC_1758 1759 +#define Z_UTIL_INC_1759 1760 +#define Z_UTIL_INC_1760 1761 +#define Z_UTIL_INC_1761 1762 +#define Z_UTIL_INC_1762 1763 +#define Z_UTIL_INC_1763 1764 +#define Z_UTIL_INC_1764 1765 +#define Z_UTIL_INC_1765 1766 +#define Z_UTIL_INC_1766 1767 +#define Z_UTIL_INC_1767 1768 +#define Z_UTIL_INC_1768 1769 +#define Z_UTIL_INC_1769 1770 +#define Z_UTIL_INC_1770 1771 +#define Z_UTIL_INC_1771 1772 +#define Z_UTIL_INC_1772 1773 +#define Z_UTIL_INC_1773 1774 +#define Z_UTIL_INC_1774 1775 +#define Z_UTIL_INC_1775 1776 +#define Z_UTIL_INC_1776 1777 +#define Z_UTIL_INC_1777 1778 +#define Z_UTIL_INC_1778 1779 +#define Z_UTIL_INC_1779 1780 +#define Z_UTIL_INC_1780 1781 +#define Z_UTIL_INC_1781 1782 +#define Z_UTIL_INC_1782 1783 +#define Z_UTIL_INC_1783 1784 +#define Z_UTIL_INC_1784 1785 +#define Z_UTIL_INC_1785 1786 +#define Z_UTIL_INC_1786 1787 +#define Z_UTIL_INC_1787 1788 +#define Z_UTIL_INC_1788 1789 +#define Z_UTIL_INC_1789 1790 +#define Z_UTIL_INC_1790 1791 +#define Z_UTIL_INC_1791 1792 +#define Z_UTIL_INC_1792 1793 +#define Z_UTIL_INC_1793 1794 +#define Z_UTIL_INC_1794 1795 +#define Z_UTIL_INC_1795 1796 +#define Z_UTIL_INC_1796 1797 +#define Z_UTIL_INC_1797 1798 +#define Z_UTIL_INC_1798 1799 +#define Z_UTIL_INC_1799 1800 +#define Z_UTIL_INC_1800 1801 +#define Z_UTIL_INC_1801 1802 +#define Z_UTIL_INC_1802 1803 +#define Z_UTIL_INC_1803 1804 +#define Z_UTIL_INC_1804 1805 +#define Z_UTIL_INC_1805 1806 +#define Z_UTIL_INC_1806 1807 +#define Z_UTIL_INC_1807 1808 +#define Z_UTIL_INC_1808 1809 +#define Z_UTIL_INC_1809 1810 +#define Z_UTIL_INC_1810 1811 +#define Z_UTIL_INC_1811 1812 +#define Z_UTIL_INC_1812 1813 +#define Z_UTIL_INC_1813 1814 +#define Z_UTIL_INC_1814 1815 +#define Z_UTIL_INC_1815 1816 +#define Z_UTIL_INC_1816 1817 +#define Z_UTIL_INC_1817 1818 +#define Z_UTIL_INC_1818 1819 +#define Z_UTIL_INC_1819 1820 +#define Z_UTIL_INC_1820 1821 +#define Z_UTIL_INC_1821 1822 +#define Z_UTIL_INC_1822 1823 +#define Z_UTIL_INC_1823 1824 +#define Z_UTIL_INC_1824 1825 +#define Z_UTIL_INC_1825 1826 +#define Z_UTIL_INC_1826 1827 +#define Z_UTIL_INC_1827 1828 +#define Z_UTIL_INC_1828 1829 +#define Z_UTIL_INC_1829 1830 +#define Z_UTIL_INC_1830 1831 +#define Z_UTIL_INC_1831 1832 +#define Z_UTIL_INC_1832 1833 +#define Z_UTIL_INC_1833 1834 +#define Z_UTIL_INC_1834 1835 +#define Z_UTIL_INC_1835 1836 +#define Z_UTIL_INC_1836 1837 +#define Z_UTIL_INC_1837 1838 +#define Z_UTIL_INC_1838 1839 +#define Z_UTIL_INC_1839 1840 +#define Z_UTIL_INC_1840 1841 +#define Z_UTIL_INC_1841 1842 +#define Z_UTIL_INC_1842 1843 +#define Z_UTIL_INC_1843 1844 +#define Z_UTIL_INC_1844 1845 +#define Z_UTIL_INC_1845 1846 +#define Z_UTIL_INC_1846 1847 +#define Z_UTIL_INC_1847 1848 +#define Z_UTIL_INC_1848 1849 +#define Z_UTIL_INC_1849 1850 +#define Z_UTIL_INC_1850 1851 +#define Z_UTIL_INC_1851 1852 +#define Z_UTIL_INC_1852 1853 +#define Z_UTIL_INC_1853 1854 +#define Z_UTIL_INC_1854 1855 +#define Z_UTIL_INC_1855 1856 +#define Z_UTIL_INC_1856 1857 +#define Z_UTIL_INC_1857 1858 +#define Z_UTIL_INC_1858 1859 +#define Z_UTIL_INC_1859 1860 +#define Z_UTIL_INC_1860 1861 +#define Z_UTIL_INC_1861 1862 +#define Z_UTIL_INC_1862 1863 +#define Z_UTIL_INC_1863 1864 +#define Z_UTIL_INC_1864 1865 +#define Z_UTIL_INC_1865 1866 +#define Z_UTIL_INC_1866 1867 +#define Z_UTIL_INC_1867 1868 +#define Z_UTIL_INC_1868 1869 +#define Z_UTIL_INC_1869 1870 +#define Z_UTIL_INC_1870 1871 +#define Z_UTIL_INC_1871 1872 +#define Z_UTIL_INC_1872 1873 +#define Z_UTIL_INC_1873 1874 +#define Z_UTIL_INC_1874 1875 +#define Z_UTIL_INC_1875 1876 +#define Z_UTIL_INC_1876 1877 +#define Z_UTIL_INC_1877 1878 +#define Z_UTIL_INC_1878 1879 +#define Z_UTIL_INC_1879 1880 +#define Z_UTIL_INC_1880 1881 +#define Z_UTIL_INC_1881 1882 +#define Z_UTIL_INC_1882 1883 +#define Z_UTIL_INC_1883 1884 +#define Z_UTIL_INC_1884 1885 +#define Z_UTIL_INC_1885 1886 +#define Z_UTIL_INC_1886 1887 +#define Z_UTIL_INC_1887 1888 +#define Z_UTIL_INC_1888 1889 +#define Z_UTIL_INC_1889 1890 +#define Z_UTIL_INC_1890 1891 +#define Z_UTIL_INC_1891 1892 +#define Z_UTIL_INC_1892 1893 +#define Z_UTIL_INC_1893 1894 +#define Z_UTIL_INC_1894 1895 +#define Z_UTIL_INC_1895 1896 +#define Z_UTIL_INC_1896 1897 +#define Z_UTIL_INC_1897 1898 +#define Z_UTIL_INC_1898 1899 +#define Z_UTIL_INC_1899 1900 +#define Z_UTIL_INC_1900 1901 +#define Z_UTIL_INC_1901 1902 +#define Z_UTIL_INC_1902 1903 +#define Z_UTIL_INC_1903 1904 +#define Z_UTIL_INC_1904 1905 +#define Z_UTIL_INC_1905 1906 +#define Z_UTIL_INC_1906 1907 +#define Z_UTIL_INC_1907 1908 +#define Z_UTIL_INC_1908 1909 +#define Z_UTIL_INC_1909 1910 +#define Z_UTIL_INC_1910 1911 +#define Z_UTIL_INC_1911 1912 +#define Z_UTIL_INC_1912 1913 +#define Z_UTIL_INC_1913 1914 +#define Z_UTIL_INC_1914 1915 +#define Z_UTIL_INC_1915 1916 +#define Z_UTIL_INC_1916 1917 +#define Z_UTIL_INC_1917 1918 +#define Z_UTIL_INC_1918 1919 +#define Z_UTIL_INC_1919 1920 +#define Z_UTIL_INC_1920 1921 +#define Z_UTIL_INC_1921 1922 +#define Z_UTIL_INC_1922 1923 +#define Z_UTIL_INC_1923 1924 +#define Z_UTIL_INC_1924 1925 +#define Z_UTIL_INC_1925 1926 +#define Z_UTIL_INC_1926 1927 +#define Z_UTIL_INC_1927 1928 +#define Z_UTIL_INC_1928 1929 +#define Z_UTIL_INC_1929 1930 +#define Z_UTIL_INC_1930 1931 +#define Z_UTIL_INC_1931 1932 +#define Z_UTIL_INC_1932 1933 +#define Z_UTIL_INC_1933 1934 +#define Z_UTIL_INC_1934 1935 +#define Z_UTIL_INC_1935 1936 +#define Z_UTIL_INC_1936 1937 +#define Z_UTIL_INC_1937 1938 +#define Z_UTIL_INC_1938 1939 +#define Z_UTIL_INC_1939 1940 +#define Z_UTIL_INC_1940 1941 +#define Z_UTIL_INC_1941 1942 +#define Z_UTIL_INC_1942 1943 +#define Z_UTIL_INC_1943 1944 +#define Z_UTIL_INC_1944 1945 +#define Z_UTIL_INC_1945 1946 +#define Z_UTIL_INC_1946 1947 +#define Z_UTIL_INC_1947 1948 +#define Z_UTIL_INC_1948 1949 +#define Z_UTIL_INC_1949 1950 +#define Z_UTIL_INC_1950 1951 +#define Z_UTIL_INC_1951 1952 +#define Z_UTIL_INC_1952 1953 +#define Z_UTIL_INC_1953 1954 +#define Z_UTIL_INC_1954 1955 +#define Z_UTIL_INC_1955 1956 +#define Z_UTIL_INC_1956 1957 +#define Z_UTIL_INC_1957 1958 +#define Z_UTIL_INC_1958 1959 +#define Z_UTIL_INC_1959 1960 +#define Z_UTIL_INC_1960 1961 +#define Z_UTIL_INC_1961 1962 +#define Z_UTIL_INC_1962 1963 +#define Z_UTIL_INC_1963 1964 +#define Z_UTIL_INC_1964 1965 +#define Z_UTIL_INC_1965 1966 +#define Z_UTIL_INC_1966 1967 +#define Z_UTIL_INC_1967 1968 +#define Z_UTIL_INC_1968 1969 +#define Z_UTIL_INC_1969 1970 +#define Z_UTIL_INC_1970 1971 +#define Z_UTIL_INC_1971 1972 +#define Z_UTIL_INC_1972 1973 +#define Z_UTIL_INC_1973 1974 +#define Z_UTIL_INC_1974 1975 +#define Z_UTIL_INC_1975 1976 +#define Z_UTIL_INC_1976 1977 +#define Z_UTIL_INC_1977 1978 +#define Z_UTIL_INC_1978 1979 +#define Z_UTIL_INC_1979 1980 +#define Z_UTIL_INC_1980 1981 +#define Z_UTIL_INC_1981 1982 +#define Z_UTIL_INC_1982 1983 +#define Z_UTIL_INC_1983 1984 +#define Z_UTIL_INC_1984 1985 +#define Z_UTIL_INC_1985 1986 +#define Z_UTIL_INC_1986 1987 +#define Z_UTIL_INC_1987 1988 +#define Z_UTIL_INC_1988 1989 +#define Z_UTIL_INC_1989 1990 +#define Z_UTIL_INC_1990 1991 +#define Z_UTIL_INC_1991 1992 +#define Z_UTIL_INC_1992 1993 +#define Z_UTIL_INC_1993 1994 +#define Z_UTIL_INC_1994 1995 +#define Z_UTIL_INC_1995 1996 +#define Z_UTIL_INC_1996 1997 +#define Z_UTIL_INC_1997 1998 +#define Z_UTIL_INC_1998 1999 +#define Z_UTIL_INC_1999 2000 +#define Z_UTIL_INC_2000 2001 +#define Z_UTIL_INC_2001 2002 +#define Z_UTIL_INC_2002 2003 +#define Z_UTIL_INC_2003 2004 +#define Z_UTIL_INC_2004 2005 +#define Z_UTIL_INC_2005 2006 +#define Z_UTIL_INC_2006 2007 +#define Z_UTIL_INC_2007 2008 +#define Z_UTIL_INC_2008 2009 +#define Z_UTIL_INC_2009 2010 +#define Z_UTIL_INC_2010 2011 +#define Z_UTIL_INC_2011 2012 +#define Z_UTIL_INC_2012 2013 +#define Z_UTIL_INC_2013 2014 +#define Z_UTIL_INC_2014 2015 +#define Z_UTIL_INC_2015 2016 +#define Z_UTIL_INC_2016 2017 +#define Z_UTIL_INC_2017 2018 +#define Z_UTIL_INC_2018 2019 +#define Z_UTIL_INC_2019 2020 +#define Z_UTIL_INC_2020 2021 +#define Z_UTIL_INC_2021 2022 +#define Z_UTIL_INC_2022 2023 +#define Z_UTIL_INC_2023 2024 +#define Z_UTIL_INC_2024 2025 +#define Z_UTIL_INC_2025 2026 +#define Z_UTIL_INC_2026 2027 +#define Z_UTIL_INC_2027 2028 +#define Z_UTIL_INC_2028 2029 +#define Z_UTIL_INC_2029 2030 +#define Z_UTIL_INC_2030 2031 +#define Z_UTIL_INC_2031 2032 +#define Z_UTIL_INC_2032 2033 +#define Z_UTIL_INC_2033 2034 +#define Z_UTIL_INC_2034 2035 +#define Z_UTIL_INC_2035 2036 +#define Z_UTIL_INC_2036 2037 +#define Z_UTIL_INC_2037 2038 +#define Z_UTIL_INC_2038 2039 +#define Z_UTIL_INC_2039 2040 +#define Z_UTIL_INC_2040 2041 +#define Z_UTIL_INC_2041 2042 +#define Z_UTIL_INC_2042 2043 +#define Z_UTIL_INC_2043 2044 +#define Z_UTIL_INC_2044 2045 +#define Z_UTIL_INC_2045 2046 +#define Z_UTIL_INC_2046 2047 +#define Z_UTIL_INC_2047 2048 +#define Z_UTIL_INC_2048 2049 +#define Z_UTIL_INC_2049 2050 +#define Z_UTIL_INC_2050 2051 +#define Z_UTIL_INC_2051 2052 +#define Z_UTIL_INC_2052 2053 +#define Z_UTIL_INC_2053 2054 +#define Z_UTIL_INC_2054 2055 +#define Z_UTIL_INC_2055 2056 +#define Z_UTIL_INC_2056 2057 +#define Z_UTIL_INC_2057 2058 +#define Z_UTIL_INC_2058 2059 +#define Z_UTIL_INC_2059 2060 +#define Z_UTIL_INC_2060 2061 +#define Z_UTIL_INC_2061 2062 +#define Z_UTIL_INC_2062 2063 +#define Z_UTIL_INC_2063 2064 +#define Z_UTIL_INC_2064 2065 +#define Z_UTIL_INC_2065 2066 +#define Z_UTIL_INC_2066 2067 +#define Z_UTIL_INC_2067 2068 +#define Z_UTIL_INC_2068 2069 +#define Z_UTIL_INC_2069 2070 +#define Z_UTIL_INC_2070 2071 +#define Z_UTIL_INC_2071 2072 +#define Z_UTIL_INC_2072 2073 +#define Z_UTIL_INC_2073 2074 +#define Z_UTIL_INC_2074 2075 +#define Z_UTIL_INC_2075 2076 +#define Z_UTIL_INC_2076 2077 +#define Z_UTIL_INC_2077 2078 +#define Z_UTIL_INC_2078 2079 +#define Z_UTIL_INC_2079 2080 +#define Z_UTIL_INC_2080 2081 +#define Z_UTIL_INC_2081 2082 +#define Z_UTIL_INC_2082 2083 +#define Z_UTIL_INC_2083 2084 +#define Z_UTIL_INC_2084 2085 +#define Z_UTIL_INC_2085 2086 +#define Z_UTIL_INC_2086 2087 +#define Z_UTIL_INC_2087 2088 +#define Z_UTIL_INC_2088 2089 +#define Z_UTIL_INC_2089 2090 +#define Z_UTIL_INC_2090 2091 +#define Z_UTIL_INC_2091 2092 +#define Z_UTIL_INC_2092 2093 +#define Z_UTIL_INC_2093 2094 +#define Z_UTIL_INC_2094 2095 +#define Z_UTIL_INC_2095 2096 +#define Z_UTIL_INC_2096 2097 +#define Z_UTIL_INC_2097 2098 +#define Z_UTIL_INC_2098 2099 +#define Z_UTIL_INC_2099 2100 +#define Z_UTIL_INC_2100 2101 +#define Z_UTIL_INC_2101 2102 +#define Z_UTIL_INC_2102 2103 +#define Z_UTIL_INC_2103 2104 +#define Z_UTIL_INC_2104 2105 +#define Z_UTIL_INC_2105 2106 +#define Z_UTIL_INC_2106 2107 +#define Z_UTIL_INC_2107 2108 +#define Z_UTIL_INC_2108 2109 +#define Z_UTIL_INC_2109 2110 +#define Z_UTIL_INC_2110 2111 +#define Z_UTIL_INC_2111 2112 +#define Z_UTIL_INC_2112 2113 +#define Z_UTIL_INC_2113 2114 +#define Z_UTIL_INC_2114 2115 +#define Z_UTIL_INC_2115 2116 +#define Z_UTIL_INC_2116 2117 +#define Z_UTIL_INC_2117 2118 +#define Z_UTIL_INC_2118 2119 +#define Z_UTIL_INC_2119 2120 +#define Z_UTIL_INC_2120 2121 +#define Z_UTIL_INC_2121 2122 +#define Z_UTIL_INC_2122 2123 +#define Z_UTIL_INC_2123 2124 +#define Z_UTIL_INC_2124 2125 +#define Z_UTIL_INC_2125 2126 +#define Z_UTIL_INC_2126 2127 +#define Z_UTIL_INC_2127 2128 +#define Z_UTIL_INC_2128 2129 +#define Z_UTIL_INC_2129 2130 +#define Z_UTIL_INC_2130 2131 +#define Z_UTIL_INC_2131 2132 +#define Z_UTIL_INC_2132 2133 +#define Z_UTIL_INC_2133 2134 +#define Z_UTIL_INC_2134 2135 +#define Z_UTIL_INC_2135 2136 +#define Z_UTIL_INC_2136 2137 +#define Z_UTIL_INC_2137 2138 +#define Z_UTIL_INC_2138 2139 +#define Z_UTIL_INC_2139 2140 +#define Z_UTIL_INC_2140 2141 +#define Z_UTIL_INC_2141 2142 +#define Z_UTIL_INC_2142 2143 +#define Z_UTIL_INC_2143 2144 +#define Z_UTIL_INC_2144 2145 +#define Z_UTIL_INC_2145 2146 +#define Z_UTIL_INC_2146 2147 +#define Z_UTIL_INC_2147 2148 +#define Z_UTIL_INC_2148 2149 +#define Z_UTIL_INC_2149 2150 +#define Z_UTIL_INC_2150 2151 +#define Z_UTIL_INC_2151 2152 +#define Z_UTIL_INC_2152 2153 +#define Z_UTIL_INC_2153 2154 +#define Z_UTIL_INC_2154 2155 +#define Z_UTIL_INC_2155 2156 +#define Z_UTIL_INC_2156 2157 +#define Z_UTIL_INC_2157 2158 +#define Z_UTIL_INC_2158 2159 +#define Z_UTIL_INC_2159 2160 +#define Z_UTIL_INC_2160 2161 +#define Z_UTIL_INC_2161 2162 +#define Z_UTIL_INC_2162 2163 +#define Z_UTIL_INC_2163 2164 +#define Z_UTIL_INC_2164 2165 +#define Z_UTIL_INC_2165 2166 +#define Z_UTIL_INC_2166 2167 +#define Z_UTIL_INC_2167 2168 +#define Z_UTIL_INC_2168 2169 +#define Z_UTIL_INC_2169 2170 +#define Z_UTIL_INC_2170 2171 +#define Z_UTIL_INC_2171 2172 +#define Z_UTIL_INC_2172 2173 +#define Z_UTIL_INC_2173 2174 +#define Z_UTIL_INC_2174 2175 +#define Z_UTIL_INC_2175 2176 +#define Z_UTIL_INC_2176 2177 +#define Z_UTIL_INC_2177 2178 +#define Z_UTIL_INC_2178 2179 +#define Z_UTIL_INC_2179 2180 +#define Z_UTIL_INC_2180 2181 +#define Z_UTIL_INC_2181 2182 +#define Z_UTIL_INC_2182 2183 +#define Z_UTIL_INC_2183 2184 +#define Z_UTIL_INC_2184 2185 +#define Z_UTIL_INC_2185 2186 +#define Z_UTIL_INC_2186 2187 +#define Z_UTIL_INC_2187 2188 +#define Z_UTIL_INC_2188 2189 +#define Z_UTIL_INC_2189 2190 +#define Z_UTIL_INC_2190 2191 +#define Z_UTIL_INC_2191 2192 +#define Z_UTIL_INC_2192 2193 +#define Z_UTIL_INC_2193 2194 +#define Z_UTIL_INC_2194 2195 +#define Z_UTIL_INC_2195 2196 +#define Z_UTIL_INC_2196 2197 +#define Z_UTIL_INC_2197 2198 +#define Z_UTIL_INC_2198 2199 +#define Z_UTIL_INC_2199 2200 +#define Z_UTIL_INC_2200 2201 +#define Z_UTIL_INC_2201 2202 +#define Z_UTIL_INC_2202 2203 +#define Z_UTIL_INC_2203 2204 +#define Z_UTIL_INC_2204 2205 +#define Z_UTIL_INC_2205 2206 +#define Z_UTIL_INC_2206 2207 +#define Z_UTIL_INC_2207 2208 +#define Z_UTIL_INC_2208 2209 +#define Z_UTIL_INC_2209 2210 +#define Z_UTIL_INC_2210 2211 +#define Z_UTIL_INC_2211 2212 +#define Z_UTIL_INC_2212 2213 +#define Z_UTIL_INC_2213 2214 +#define Z_UTIL_INC_2214 2215 +#define Z_UTIL_INC_2215 2216 +#define Z_UTIL_INC_2216 2217 +#define Z_UTIL_INC_2217 2218 +#define Z_UTIL_INC_2218 2219 +#define Z_UTIL_INC_2219 2220 +#define Z_UTIL_INC_2220 2221 +#define Z_UTIL_INC_2221 2222 +#define Z_UTIL_INC_2222 2223 +#define Z_UTIL_INC_2223 2224 +#define Z_UTIL_INC_2224 2225 +#define Z_UTIL_INC_2225 2226 +#define Z_UTIL_INC_2226 2227 +#define Z_UTIL_INC_2227 2228 +#define Z_UTIL_INC_2228 2229 +#define Z_UTIL_INC_2229 2230 +#define Z_UTIL_INC_2230 2231 +#define Z_UTIL_INC_2231 2232 +#define Z_UTIL_INC_2232 2233 +#define Z_UTIL_INC_2233 2234 +#define Z_UTIL_INC_2234 2235 +#define Z_UTIL_INC_2235 2236 +#define Z_UTIL_INC_2236 2237 +#define Z_UTIL_INC_2237 2238 +#define Z_UTIL_INC_2238 2239 +#define Z_UTIL_INC_2239 2240 +#define Z_UTIL_INC_2240 2241 +#define Z_UTIL_INC_2241 2242 +#define Z_UTIL_INC_2242 2243 +#define Z_UTIL_INC_2243 2244 +#define Z_UTIL_INC_2244 2245 +#define Z_UTIL_INC_2245 2246 +#define Z_UTIL_INC_2246 2247 +#define Z_UTIL_INC_2247 2248 +#define Z_UTIL_INC_2248 2249 +#define Z_UTIL_INC_2249 2250 +#define Z_UTIL_INC_2250 2251 +#define Z_UTIL_INC_2251 2252 +#define Z_UTIL_INC_2252 2253 +#define Z_UTIL_INC_2253 2254 +#define Z_UTIL_INC_2254 2255 +#define Z_UTIL_INC_2255 2256 +#define Z_UTIL_INC_2256 2257 +#define Z_UTIL_INC_2257 2258 +#define Z_UTIL_INC_2258 2259 +#define Z_UTIL_INC_2259 2260 +#define Z_UTIL_INC_2260 2261 +#define Z_UTIL_INC_2261 2262 +#define Z_UTIL_INC_2262 2263 +#define Z_UTIL_INC_2263 2264 +#define Z_UTIL_INC_2264 2265 +#define Z_UTIL_INC_2265 2266 +#define Z_UTIL_INC_2266 2267 +#define Z_UTIL_INC_2267 2268 +#define Z_UTIL_INC_2268 2269 +#define Z_UTIL_INC_2269 2270 +#define Z_UTIL_INC_2270 2271 +#define Z_UTIL_INC_2271 2272 +#define Z_UTIL_INC_2272 2273 +#define Z_UTIL_INC_2273 2274 +#define Z_UTIL_INC_2274 2275 +#define Z_UTIL_INC_2275 2276 +#define Z_UTIL_INC_2276 2277 +#define Z_UTIL_INC_2277 2278 +#define Z_UTIL_INC_2278 2279 +#define Z_UTIL_INC_2279 2280 +#define Z_UTIL_INC_2280 2281 +#define Z_UTIL_INC_2281 2282 +#define Z_UTIL_INC_2282 2283 +#define Z_UTIL_INC_2283 2284 +#define Z_UTIL_INC_2284 2285 +#define Z_UTIL_INC_2285 2286 +#define Z_UTIL_INC_2286 2287 +#define Z_UTIL_INC_2287 2288 +#define Z_UTIL_INC_2288 2289 +#define Z_UTIL_INC_2289 2290 +#define Z_UTIL_INC_2290 2291 +#define Z_UTIL_INC_2291 2292 +#define Z_UTIL_INC_2292 2293 +#define Z_UTIL_INC_2293 2294 +#define Z_UTIL_INC_2294 2295 +#define Z_UTIL_INC_2295 2296 +#define Z_UTIL_INC_2296 2297 +#define Z_UTIL_INC_2297 2298 +#define Z_UTIL_INC_2298 2299 +#define Z_UTIL_INC_2299 2300 +#define Z_UTIL_INC_2300 2301 +#define Z_UTIL_INC_2301 2302 +#define Z_UTIL_INC_2302 2303 +#define Z_UTIL_INC_2303 2304 +#define Z_UTIL_INC_2304 2305 +#define Z_UTIL_INC_2305 2306 +#define Z_UTIL_INC_2306 2307 +#define Z_UTIL_INC_2307 2308 +#define Z_UTIL_INC_2308 2309 +#define Z_UTIL_INC_2309 2310 +#define Z_UTIL_INC_2310 2311 +#define Z_UTIL_INC_2311 2312 +#define Z_UTIL_INC_2312 2313 +#define Z_UTIL_INC_2313 2314 +#define Z_UTIL_INC_2314 2315 +#define Z_UTIL_INC_2315 2316 +#define Z_UTIL_INC_2316 2317 +#define Z_UTIL_INC_2317 2318 +#define Z_UTIL_INC_2318 2319 +#define Z_UTIL_INC_2319 2320 +#define Z_UTIL_INC_2320 2321 +#define Z_UTIL_INC_2321 2322 +#define Z_UTIL_INC_2322 2323 +#define Z_UTIL_INC_2323 2324 +#define Z_UTIL_INC_2324 2325 +#define Z_UTIL_INC_2325 2326 +#define Z_UTIL_INC_2326 2327 +#define Z_UTIL_INC_2327 2328 +#define Z_UTIL_INC_2328 2329 +#define Z_UTIL_INC_2329 2330 +#define Z_UTIL_INC_2330 2331 +#define Z_UTIL_INC_2331 2332 +#define Z_UTIL_INC_2332 2333 +#define Z_UTIL_INC_2333 2334 +#define Z_UTIL_INC_2334 2335 +#define Z_UTIL_INC_2335 2336 +#define Z_UTIL_INC_2336 2337 +#define Z_UTIL_INC_2337 2338 +#define Z_UTIL_INC_2338 2339 +#define Z_UTIL_INC_2339 2340 +#define Z_UTIL_INC_2340 2341 +#define Z_UTIL_INC_2341 2342 +#define Z_UTIL_INC_2342 2343 +#define Z_UTIL_INC_2343 2344 +#define Z_UTIL_INC_2344 2345 +#define Z_UTIL_INC_2345 2346 +#define Z_UTIL_INC_2346 2347 +#define Z_UTIL_INC_2347 2348 +#define Z_UTIL_INC_2348 2349 +#define Z_UTIL_INC_2349 2350 +#define Z_UTIL_INC_2350 2351 +#define Z_UTIL_INC_2351 2352 +#define Z_UTIL_INC_2352 2353 +#define Z_UTIL_INC_2353 2354 +#define Z_UTIL_INC_2354 2355 +#define Z_UTIL_INC_2355 2356 +#define Z_UTIL_INC_2356 2357 +#define Z_UTIL_INC_2357 2358 +#define Z_UTIL_INC_2358 2359 +#define Z_UTIL_INC_2359 2360 +#define Z_UTIL_INC_2360 2361 +#define Z_UTIL_INC_2361 2362 +#define Z_UTIL_INC_2362 2363 +#define Z_UTIL_INC_2363 2364 +#define Z_UTIL_INC_2364 2365 +#define Z_UTIL_INC_2365 2366 +#define Z_UTIL_INC_2366 2367 +#define Z_UTIL_INC_2367 2368 +#define Z_UTIL_INC_2368 2369 +#define Z_UTIL_INC_2369 2370 +#define Z_UTIL_INC_2370 2371 +#define Z_UTIL_INC_2371 2372 +#define Z_UTIL_INC_2372 2373 +#define Z_UTIL_INC_2373 2374 +#define Z_UTIL_INC_2374 2375 +#define Z_UTIL_INC_2375 2376 +#define Z_UTIL_INC_2376 2377 +#define Z_UTIL_INC_2377 2378 +#define Z_UTIL_INC_2378 2379 +#define Z_UTIL_INC_2379 2380 +#define Z_UTIL_INC_2380 2381 +#define Z_UTIL_INC_2381 2382 +#define Z_UTIL_INC_2382 2383 +#define Z_UTIL_INC_2383 2384 +#define Z_UTIL_INC_2384 2385 +#define Z_UTIL_INC_2385 2386 +#define Z_UTIL_INC_2386 2387 +#define Z_UTIL_INC_2387 2388 +#define Z_UTIL_INC_2388 2389 +#define Z_UTIL_INC_2389 2390 +#define Z_UTIL_INC_2390 2391 +#define Z_UTIL_INC_2391 2392 +#define Z_UTIL_INC_2392 2393 +#define Z_UTIL_INC_2393 2394 +#define Z_UTIL_INC_2394 2395 +#define Z_UTIL_INC_2395 2396 +#define Z_UTIL_INC_2396 2397 +#define Z_UTIL_INC_2397 2398 +#define Z_UTIL_INC_2398 2399 +#define Z_UTIL_INC_2399 2400 +#define Z_UTIL_INC_2400 2401 +#define Z_UTIL_INC_2401 2402 +#define Z_UTIL_INC_2402 2403 +#define Z_UTIL_INC_2403 2404 +#define Z_UTIL_INC_2404 2405 +#define Z_UTIL_INC_2405 2406 +#define Z_UTIL_INC_2406 2407 +#define Z_UTIL_INC_2407 2408 +#define Z_UTIL_INC_2408 2409 +#define Z_UTIL_INC_2409 2410 +#define Z_UTIL_INC_2410 2411 +#define Z_UTIL_INC_2411 2412 +#define Z_UTIL_INC_2412 2413 +#define Z_UTIL_INC_2413 2414 +#define Z_UTIL_INC_2414 2415 +#define Z_UTIL_INC_2415 2416 +#define Z_UTIL_INC_2416 2417 +#define Z_UTIL_INC_2417 2418 +#define Z_UTIL_INC_2418 2419 +#define Z_UTIL_INC_2419 2420 +#define Z_UTIL_INC_2420 2421 +#define Z_UTIL_INC_2421 2422 +#define Z_UTIL_INC_2422 2423 +#define Z_UTIL_INC_2423 2424 +#define Z_UTIL_INC_2424 2425 +#define Z_UTIL_INC_2425 2426 +#define Z_UTIL_INC_2426 2427 +#define Z_UTIL_INC_2427 2428 +#define Z_UTIL_INC_2428 2429 +#define Z_UTIL_INC_2429 2430 +#define Z_UTIL_INC_2430 2431 +#define Z_UTIL_INC_2431 2432 +#define Z_UTIL_INC_2432 2433 +#define Z_UTIL_INC_2433 2434 +#define Z_UTIL_INC_2434 2435 +#define Z_UTIL_INC_2435 2436 +#define Z_UTIL_INC_2436 2437 +#define Z_UTIL_INC_2437 2438 +#define Z_UTIL_INC_2438 2439 +#define Z_UTIL_INC_2439 2440 +#define Z_UTIL_INC_2440 2441 +#define Z_UTIL_INC_2441 2442 +#define Z_UTIL_INC_2442 2443 +#define Z_UTIL_INC_2443 2444 +#define Z_UTIL_INC_2444 2445 +#define Z_UTIL_INC_2445 2446 +#define Z_UTIL_INC_2446 2447 +#define Z_UTIL_INC_2447 2448 +#define Z_UTIL_INC_2448 2449 +#define Z_UTIL_INC_2449 2450 +#define Z_UTIL_INC_2450 2451 +#define Z_UTIL_INC_2451 2452 +#define Z_UTIL_INC_2452 2453 +#define Z_UTIL_INC_2453 2454 +#define Z_UTIL_INC_2454 2455 +#define Z_UTIL_INC_2455 2456 +#define Z_UTIL_INC_2456 2457 +#define Z_UTIL_INC_2457 2458 +#define Z_UTIL_INC_2458 2459 +#define Z_UTIL_INC_2459 2460 +#define Z_UTIL_INC_2460 2461 +#define Z_UTIL_INC_2461 2462 +#define Z_UTIL_INC_2462 2463 +#define Z_UTIL_INC_2463 2464 +#define Z_UTIL_INC_2464 2465 +#define Z_UTIL_INC_2465 2466 +#define Z_UTIL_INC_2466 2467 +#define Z_UTIL_INC_2467 2468 +#define Z_UTIL_INC_2468 2469 +#define Z_UTIL_INC_2469 2470 +#define Z_UTIL_INC_2470 2471 +#define Z_UTIL_INC_2471 2472 +#define Z_UTIL_INC_2472 2473 +#define Z_UTIL_INC_2473 2474 +#define Z_UTIL_INC_2474 2475 +#define Z_UTIL_INC_2475 2476 +#define Z_UTIL_INC_2476 2477 +#define Z_UTIL_INC_2477 2478 +#define Z_UTIL_INC_2478 2479 +#define Z_UTIL_INC_2479 2480 +#define Z_UTIL_INC_2480 2481 +#define Z_UTIL_INC_2481 2482 +#define Z_UTIL_INC_2482 2483 +#define Z_UTIL_INC_2483 2484 +#define Z_UTIL_INC_2484 2485 +#define Z_UTIL_INC_2485 2486 +#define Z_UTIL_INC_2486 2487 +#define Z_UTIL_INC_2487 2488 +#define Z_UTIL_INC_2488 2489 +#define Z_UTIL_INC_2489 2490 +#define Z_UTIL_INC_2490 2491 +#define Z_UTIL_INC_2491 2492 +#define Z_UTIL_INC_2492 2493 +#define Z_UTIL_INC_2493 2494 +#define Z_UTIL_INC_2494 2495 +#define Z_UTIL_INC_2495 2496 +#define Z_UTIL_INC_2496 2497 +#define Z_UTIL_INC_2497 2498 +#define Z_UTIL_INC_2498 2499 +#define Z_UTIL_INC_2499 2500 +#define Z_UTIL_INC_2500 2501 +#define Z_UTIL_INC_2501 2502 +#define Z_UTIL_INC_2502 2503 +#define Z_UTIL_INC_2503 2504 +#define Z_UTIL_INC_2504 2505 +#define Z_UTIL_INC_2505 2506 +#define Z_UTIL_INC_2506 2507 +#define Z_UTIL_INC_2507 2508 +#define Z_UTIL_INC_2508 2509 +#define Z_UTIL_INC_2509 2510 +#define Z_UTIL_INC_2510 2511 +#define Z_UTIL_INC_2511 2512 +#define Z_UTIL_INC_2512 2513 +#define Z_UTIL_INC_2513 2514 +#define Z_UTIL_INC_2514 2515 +#define Z_UTIL_INC_2515 2516 +#define Z_UTIL_INC_2516 2517 +#define Z_UTIL_INC_2517 2518 +#define Z_UTIL_INC_2518 2519 +#define Z_UTIL_INC_2519 2520 +#define Z_UTIL_INC_2520 2521 +#define Z_UTIL_INC_2521 2522 +#define Z_UTIL_INC_2522 2523 +#define Z_UTIL_INC_2523 2524 +#define Z_UTIL_INC_2524 2525 +#define Z_UTIL_INC_2525 2526 +#define Z_UTIL_INC_2526 2527 +#define Z_UTIL_INC_2527 2528 +#define Z_UTIL_INC_2528 2529 +#define Z_UTIL_INC_2529 2530 +#define Z_UTIL_INC_2530 2531 +#define Z_UTIL_INC_2531 2532 +#define Z_UTIL_INC_2532 2533 +#define Z_UTIL_INC_2533 2534 +#define Z_UTIL_INC_2534 2535 +#define Z_UTIL_INC_2535 2536 +#define Z_UTIL_INC_2536 2537 +#define Z_UTIL_INC_2537 2538 +#define Z_UTIL_INC_2538 2539 +#define Z_UTIL_INC_2539 2540 +#define Z_UTIL_INC_2540 2541 +#define Z_UTIL_INC_2541 2542 +#define Z_UTIL_INC_2542 2543 +#define Z_UTIL_INC_2543 2544 +#define Z_UTIL_INC_2544 2545 +#define Z_UTIL_INC_2545 2546 +#define Z_UTIL_INC_2546 2547 +#define Z_UTIL_INC_2547 2548 +#define Z_UTIL_INC_2548 2549 +#define Z_UTIL_INC_2549 2550 +#define Z_UTIL_INC_2550 2551 +#define Z_UTIL_INC_2551 2552 +#define Z_UTIL_INC_2552 2553 +#define Z_UTIL_INC_2553 2554 +#define Z_UTIL_INC_2554 2555 +#define Z_UTIL_INC_2555 2556 +#define Z_UTIL_INC_2556 2557 +#define Z_UTIL_INC_2557 2558 +#define Z_UTIL_INC_2558 2559 +#define Z_UTIL_INC_2559 2560 +#define Z_UTIL_INC_2560 2561 +#define Z_UTIL_INC_2561 2562 +#define Z_UTIL_INC_2562 2563 +#define Z_UTIL_INC_2563 2564 +#define Z_UTIL_INC_2564 2565 +#define Z_UTIL_INC_2565 2566 +#define Z_UTIL_INC_2566 2567 +#define Z_UTIL_INC_2567 2568 +#define Z_UTIL_INC_2568 2569 +#define Z_UTIL_INC_2569 2570 +#define Z_UTIL_INC_2570 2571 +#define Z_UTIL_INC_2571 2572 +#define Z_UTIL_INC_2572 2573 +#define Z_UTIL_INC_2573 2574 +#define Z_UTIL_INC_2574 2575 +#define Z_UTIL_INC_2575 2576 +#define Z_UTIL_INC_2576 2577 +#define Z_UTIL_INC_2577 2578 +#define Z_UTIL_INC_2578 2579 +#define Z_UTIL_INC_2579 2580 +#define Z_UTIL_INC_2580 2581 +#define Z_UTIL_INC_2581 2582 +#define Z_UTIL_INC_2582 2583 +#define Z_UTIL_INC_2583 2584 +#define Z_UTIL_INC_2584 2585 +#define Z_UTIL_INC_2585 2586 +#define Z_UTIL_INC_2586 2587 +#define Z_UTIL_INC_2587 2588 +#define Z_UTIL_INC_2588 2589 +#define Z_UTIL_INC_2589 2590 +#define Z_UTIL_INC_2590 2591 +#define Z_UTIL_INC_2591 2592 +#define Z_UTIL_INC_2592 2593 +#define Z_UTIL_INC_2593 2594 +#define Z_UTIL_INC_2594 2595 +#define Z_UTIL_INC_2595 2596 +#define Z_UTIL_INC_2596 2597 +#define Z_UTIL_INC_2597 2598 +#define Z_UTIL_INC_2598 2599 +#define Z_UTIL_INC_2599 2600 +#define Z_UTIL_INC_2600 2601 +#define Z_UTIL_INC_2601 2602 +#define Z_UTIL_INC_2602 2603 +#define Z_UTIL_INC_2603 2604 +#define Z_UTIL_INC_2604 2605 +#define Z_UTIL_INC_2605 2606 +#define Z_UTIL_INC_2606 2607 +#define Z_UTIL_INC_2607 2608 +#define Z_UTIL_INC_2608 2609 +#define Z_UTIL_INC_2609 2610 +#define Z_UTIL_INC_2610 2611 +#define Z_UTIL_INC_2611 2612 +#define Z_UTIL_INC_2612 2613 +#define Z_UTIL_INC_2613 2614 +#define Z_UTIL_INC_2614 2615 +#define Z_UTIL_INC_2615 2616 +#define Z_UTIL_INC_2616 2617 +#define Z_UTIL_INC_2617 2618 +#define Z_UTIL_INC_2618 2619 +#define Z_UTIL_INC_2619 2620 +#define Z_UTIL_INC_2620 2621 +#define Z_UTIL_INC_2621 2622 +#define Z_UTIL_INC_2622 2623 +#define Z_UTIL_INC_2623 2624 +#define Z_UTIL_INC_2624 2625 +#define Z_UTIL_INC_2625 2626 +#define Z_UTIL_INC_2626 2627 +#define Z_UTIL_INC_2627 2628 +#define Z_UTIL_INC_2628 2629 +#define Z_UTIL_INC_2629 2630 +#define Z_UTIL_INC_2630 2631 +#define Z_UTIL_INC_2631 2632 +#define Z_UTIL_INC_2632 2633 +#define Z_UTIL_INC_2633 2634 +#define Z_UTIL_INC_2634 2635 +#define Z_UTIL_INC_2635 2636 +#define Z_UTIL_INC_2636 2637 +#define Z_UTIL_INC_2637 2638 +#define Z_UTIL_INC_2638 2639 +#define Z_UTIL_INC_2639 2640 +#define Z_UTIL_INC_2640 2641 +#define Z_UTIL_INC_2641 2642 +#define Z_UTIL_INC_2642 2643 +#define Z_UTIL_INC_2643 2644 +#define Z_UTIL_INC_2644 2645 +#define Z_UTIL_INC_2645 2646 +#define Z_UTIL_INC_2646 2647 +#define Z_UTIL_INC_2647 2648 +#define Z_UTIL_INC_2648 2649 +#define Z_UTIL_INC_2649 2650 +#define Z_UTIL_INC_2650 2651 +#define Z_UTIL_INC_2651 2652 +#define Z_UTIL_INC_2652 2653 +#define Z_UTIL_INC_2653 2654 +#define Z_UTIL_INC_2654 2655 +#define Z_UTIL_INC_2655 2656 +#define Z_UTIL_INC_2656 2657 +#define Z_UTIL_INC_2657 2658 +#define Z_UTIL_INC_2658 2659 +#define Z_UTIL_INC_2659 2660 +#define Z_UTIL_INC_2660 2661 +#define Z_UTIL_INC_2661 2662 +#define Z_UTIL_INC_2662 2663 +#define Z_UTIL_INC_2663 2664 +#define Z_UTIL_INC_2664 2665 +#define Z_UTIL_INC_2665 2666 +#define Z_UTIL_INC_2666 2667 +#define Z_UTIL_INC_2667 2668 +#define Z_UTIL_INC_2668 2669 +#define Z_UTIL_INC_2669 2670 +#define Z_UTIL_INC_2670 2671 +#define Z_UTIL_INC_2671 2672 +#define Z_UTIL_INC_2672 2673 +#define Z_UTIL_INC_2673 2674 +#define Z_UTIL_INC_2674 2675 +#define Z_UTIL_INC_2675 2676 +#define Z_UTIL_INC_2676 2677 +#define Z_UTIL_INC_2677 2678 +#define Z_UTIL_INC_2678 2679 +#define Z_UTIL_INC_2679 2680 +#define Z_UTIL_INC_2680 2681 +#define Z_UTIL_INC_2681 2682 +#define Z_UTIL_INC_2682 2683 +#define Z_UTIL_INC_2683 2684 +#define Z_UTIL_INC_2684 2685 +#define Z_UTIL_INC_2685 2686 +#define Z_UTIL_INC_2686 2687 +#define Z_UTIL_INC_2687 2688 +#define Z_UTIL_INC_2688 2689 +#define Z_UTIL_INC_2689 2690 +#define Z_UTIL_INC_2690 2691 +#define Z_UTIL_INC_2691 2692 +#define Z_UTIL_INC_2692 2693 +#define Z_UTIL_INC_2693 2694 +#define Z_UTIL_INC_2694 2695 +#define Z_UTIL_INC_2695 2696 +#define Z_UTIL_INC_2696 2697 +#define Z_UTIL_INC_2697 2698 +#define Z_UTIL_INC_2698 2699 +#define Z_UTIL_INC_2699 2700 +#define Z_UTIL_INC_2700 2701 +#define Z_UTIL_INC_2701 2702 +#define Z_UTIL_INC_2702 2703 +#define Z_UTIL_INC_2703 2704 +#define Z_UTIL_INC_2704 2705 +#define Z_UTIL_INC_2705 2706 +#define Z_UTIL_INC_2706 2707 +#define Z_UTIL_INC_2707 2708 +#define Z_UTIL_INC_2708 2709 +#define Z_UTIL_INC_2709 2710 +#define Z_UTIL_INC_2710 2711 +#define Z_UTIL_INC_2711 2712 +#define Z_UTIL_INC_2712 2713 +#define Z_UTIL_INC_2713 2714 +#define Z_UTIL_INC_2714 2715 +#define Z_UTIL_INC_2715 2716 +#define Z_UTIL_INC_2716 2717 +#define Z_UTIL_INC_2717 2718 +#define Z_UTIL_INC_2718 2719 +#define Z_UTIL_INC_2719 2720 +#define Z_UTIL_INC_2720 2721 +#define Z_UTIL_INC_2721 2722 +#define Z_UTIL_INC_2722 2723 +#define Z_UTIL_INC_2723 2724 +#define Z_UTIL_INC_2724 2725 +#define Z_UTIL_INC_2725 2726 +#define Z_UTIL_INC_2726 2727 +#define Z_UTIL_INC_2727 2728 +#define Z_UTIL_INC_2728 2729 +#define Z_UTIL_INC_2729 2730 +#define Z_UTIL_INC_2730 2731 +#define Z_UTIL_INC_2731 2732 +#define Z_UTIL_INC_2732 2733 +#define Z_UTIL_INC_2733 2734 +#define Z_UTIL_INC_2734 2735 +#define Z_UTIL_INC_2735 2736 +#define Z_UTIL_INC_2736 2737 +#define Z_UTIL_INC_2737 2738 +#define Z_UTIL_INC_2738 2739 +#define Z_UTIL_INC_2739 2740 +#define Z_UTIL_INC_2740 2741 +#define Z_UTIL_INC_2741 2742 +#define Z_UTIL_INC_2742 2743 +#define Z_UTIL_INC_2743 2744 +#define Z_UTIL_INC_2744 2745 +#define Z_UTIL_INC_2745 2746 +#define Z_UTIL_INC_2746 2747 +#define Z_UTIL_INC_2747 2748 +#define Z_UTIL_INC_2748 2749 +#define Z_UTIL_INC_2749 2750 +#define Z_UTIL_INC_2750 2751 +#define Z_UTIL_INC_2751 2752 +#define Z_UTIL_INC_2752 2753 +#define Z_UTIL_INC_2753 2754 +#define Z_UTIL_INC_2754 2755 +#define Z_UTIL_INC_2755 2756 +#define Z_UTIL_INC_2756 2757 +#define Z_UTIL_INC_2757 2758 +#define Z_UTIL_INC_2758 2759 +#define Z_UTIL_INC_2759 2760 +#define Z_UTIL_INC_2760 2761 +#define Z_UTIL_INC_2761 2762 +#define Z_UTIL_INC_2762 2763 +#define Z_UTIL_INC_2763 2764 +#define Z_UTIL_INC_2764 2765 +#define Z_UTIL_INC_2765 2766 +#define Z_UTIL_INC_2766 2767 +#define Z_UTIL_INC_2767 2768 +#define Z_UTIL_INC_2768 2769 +#define Z_UTIL_INC_2769 2770 +#define Z_UTIL_INC_2770 2771 +#define Z_UTIL_INC_2771 2772 +#define Z_UTIL_INC_2772 2773 +#define Z_UTIL_INC_2773 2774 +#define Z_UTIL_INC_2774 2775 +#define Z_UTIL_INC_2775 2776 +#define Z_UTIL_INC_2776 2777 +#define Z_UTIL_INC_2777 2778 +#define Z_UTIL_INC_2778 2779 +#define Z_UTIL_INC_2779 2780 +#define Z_UTIL_INC_2780 2781 +#define Z_UTIL_INC_2781 2782 +#define Z_UTIL_INC_2782 2783 +#define Z_UTIL_INC_2783 2784 +#define Z_UTIL_INC_2784 2785 +#define Z_UTIL_INC_2785 2786 +#define Z_UTIL_INC_2786 2787 +#define Z_UTIL_INC_2787 2788 +#define Z_UTIL_INC_2788 2789 +#define Z_UTIL_INC_2789 2790 +#define Z_UTIL_INC_2790 2791 +#define Z_UTIL_INC_2791 2792 +#define Z_UTIL_INC_2792 2793 +#define Z_UTIL_INC_2793 2794 +#define Z_UTIL_INC_2794 2795 +#define Z_UTIL_INC_2795 2796 +#define Z_UTIL_INC_2796 2797 +#define Z_UTIL_INC_2797 2798 +#define Z_UTIL_INC_2798 2799 +#define Z_UTIL_INC_2799 2800 +#define Z_UTIL_INC_2800 2801 +#define Z_UTIL_INC_2801 2802 +#define Z_UTIL_INC_2802 2803 +#define Z_UTIL_INC_2803 2804 +#define Z_UTIL_INC_2804 2805 +#define Z_UTIL_INC_2805 2806 +#define Z_UTIL_INC_2806 2807 +#define Z_UTIL_INC_2807 2808 +#define Z_UTIL_INC_2808 2809 +#define Z_UTIL_INC_2809 2810 +#define Z_UTIL_INC_2810 2811 +#define Z_UTIL_INC_2811 2812 +#define Z_UTIL_INC_2812 2813 +#define Z_UTIL_INC_2813 2814 +#define Z_UTIL_INC_2814 2815 +#define Z_UTIL_INC_2815 2816 +#define Z_UTIL_INC_2816 2817 +#define Z_UTIL_INC_2817 2818 +#define Z_UTIL_INC_2818 2819 +#define Z_UTIL_INC_2819 2820 +#define Z_UTIL_INC_2820 2821 +#define Z_UTIL_INC_2821 2822 +#define Z_UTIL_INC_2822 2823 +#define Z_UTIL_INC_2823 2824 +#define Z_UTIL_INC_2824 2825 +#define Z_UTIL_INC_2825 2826 +#define Z_UTIL_INC_2826 2827 +#define Z_UTIL_INC_2827 2828 +#define Z_UTIL_INC_2828 2829 +#define Z_UTIL_INC_2829 2830 +#define Z_UTIL_INC_2830 2831 +#define Z_UTIL_INC_2831 2832 +#define Z_UTIL_INC_2832 2833 +#define Z_UTIL_INC_2833 2834 +#define Z_UTIL_INC_2834 2835 +#define Z_UTIL_INC_2835 2836 +#define Z_UTIL_INC_2836 2837 +#define Z_UTIL_INC_2837 2838 +#define Z_UTIL_INC_2838 2839 +#define Z_UTIL_INC_2839 2840 +#define Z_UTIL_INC_2840 2841 +#define Z_UTIL_INC_2841 2842 +#define Z_UTIL_INC_2842 2843 +#define Z_UTIL_INC_2843 2844 +#define Z_UTIL_INC_2844 2845 +#define Z_UTIL_INC_2845 2846 +#define Z_UTIL_INC_2846 2847 +#define Z_UTIL_INC_2847 2848 +#define Z_UTIL_INC_2848 2849 +#define Z_UTIL_INC_2849 2850 +#define Z_UTIL_INC_2850 2851 +#define Z_UTIL_INC_2851 2852 +#define Z_UTIL_INC_2852 2853 +#define Z_UTIL_INC_2853 2854 +#define Z_UTIL_INC_2854 2855 +#define Z_UTIL_INC_2855 2856 +#define Z_UTIL_INC_2856 2857 +#define Z_UTIL_INC_2857 2858 +#define Z_UTIL_INC_2858 2859 +#define Z_UTIL_INC_2859 2860 +#define Z_UTIL_INC_2860 2861 +#define Z_UTIL_INC_2861 2862 +#define Z_UTIL_INC_2862 2863 +#define Z_UTIL_INC_2863 2864 +#define Z_UTIL_INC_2864 2865 +#define Z_UTIL_INC_2865 2866 +#define Z_UTIL_INC_2866 2867 +#define Z_UTIL_INC_2867 2868 +#define Z_UTIL_INC_2868 2869 +#define Z_UTIL_INC_2869 2870 +#define Z_UTIL_INC_2870 2871 +#define Z_UTIL_INC_2871 2872 +#define Z_UTIL_INC_2872 2873 +#define Z_UTIL_INC_2873 2874 +#define Z_UTIL_INC_2874 2875 +#define Z_UTIL_INC_2875 2876 +#define Z_UTIL_INC_2876 2877 +#define Z_UTIL_INC_2877 2878 +#define Z_UTIL_INC_2878 2879 +#define Z_UTIL_INC_2879 2880 +#define Z_UTIL_INC_2880 2881 +#define Z_UTIL_INC_2881 2882 +#define Z_UTIL_INC_2882 2883 +#define Z_UTIL_INC_2883 2884 +#define Z_UTIL_INC_2884 2885 +#define Z_UTIL_INC_2885 2886 +#define Z_UTIL_INC_2886 2887 +#define Z_UTIL_INC_2887 2888 +#define Z_UTIL_INC_2888 2889 +#define Z_UTIL_INC_2889 2890 +#define Z_UTIL_INC_2890 2891 +#define Z_UTIL_INC_2891 2892 +#define Z_UTIL_INC_2892 2893 +#define Z_UTIL_INC_2893 2894 +#define Z_UTIL_INC_2894 2895 +#define Z_UTIL_INC_2895 2896 +#define Z_UTIL_INC_2896 2897 +#define Z_UTIL_INC_2897 2898 +#define Z_UTIL_INC_2898 2899 +#define Z_UTIL_INC_2899 2900 +#define Z_UTIL_INC_2900 2901 +#define Z_UTIL_INC_2901 2902 +#define Z_UTIL_INC_2902 2903 +#define Z_UTIL_INC_2903 2904 +#define Z_UTIL_INC_2904 2905 +#define Z_UTIL_INC_2905 2906 +#define Z_UTIL_INC_2906 2907 +#define Z_UTIL_INC_2907 2908 +#define Z_UTIL_INC_2908 2909 +#define Z_UTIL_INC_2909 2910 +#define Z_UTIL_INC_2910 2911 +#define Z_UTIL_INC_2911 2912 +#define Z_UTIL_INC_2912 2913 +#define Z_UTIL_INC_2913 2914 +#define Z_UTIL_INC_2914 2915 +#define Z_UTIL_INC_2915 2916 +#define Z_UTIL_INC_2916 2917 +#define Z_UTIL_INC_2917 2918 +#define Z_UTIL_INC_2918 2919 +#define Z_UTIL_INC_2919 2920 +#define Z_UTIL_INC_2920 2921 +#define Z_UTIL_INC_2921 2922 +#define Z_UTIL_INC_2922 2923 +#define Z_UTIL_INC_2923 2924 +#define Z_UTIL_INC_2924 2925 +#define Z_UTIL_INC_2925 2926 +#define Z_UTIL_INC_2926 2927 +#define Z_UTIL_INC_2927 2928 +#define Z_UTIL_INC_2928 2929 +#define Z_UTIL_INC_2929 2930 +#define Z_UTIL_INC_2930 2931 +#define Z_UTIL_INC_2931 2932 +#define Z_UTIL_INC_2932 2933 +#define Z_UTIL_INC_2933 2934 +#define Z_UTIL_INC_2934 2935 +#define Z_UTIL_INC_2935 2936 +#define Z_UTIL_INC_2936 2937 +#define Z_UTIL_INC_2937 2938 +#define Z_UTIL_INC_2938 2939 +#define Z_UTIL_INC_2939 2940 +#define Z_UTIL_INC_2940 2941 +#define Z_UTIL_INC_2941 2942 +#define Z_UTIL_INC_2942 2943 +#define Z_UTIL_INC_2943 2944 +#define Z_UTIL_INC_2944 2945 +#define Z_UTIL_INC_2945 2946 +#define Z_UTIL_INC_2946 2947 +#define Z_UTIL_INC_2947 2948 +#define Z_UTIL_INC_2948 2949 +#define Z_UTIL_INC_2949 2950 +#define Z_UTIL_INC_2950 2951 +#define Z_UTIL_INC_2951 2952 +#define Z_UTIL_INC_2952 2953 +#define Z_UTIL_INC_2953 2954 +#define Z_UTIL_INC_2954 2955 +#define Z_UTIL_INC_2955 2956 +#define Z_UTIL_INC_2956 2957 +#define Z_UTIL_INC_2957 2958 +#define Z_UTIL_INC_2958 2959 +#define Z_UTIL_INC_2959 2960 +#define Z_UTIL_INC_2960 2961 +#define Z_UTIL_INC_2961 2962 +#define Z_UTIL_INC_2962 2963 +#define Z_UTIL_INC_2963 2964 +#define Z_UTIL_INC_2964 2965 +#define Z_UTIL_INC_2965 2966 +#define Z_UTIL_INC_2966 2967 +#define Z_UTIL_INC_2967 2968 +#define Z_UTIL_INC_2968 2969 +#define Z_UTIL_INC_2969 2970 +#define Z_UTIL_INC_2970 2971 +#define Z_UTIL_INC_2971 2972 +#define Z_UTIL_INC_2972 2973 +#define Z_UTIL_INC_2973 2974 +#define Z_UTIL_INC_2974 2975 +#define Z_UTIL_INC_2975 2976 +#define Z_UTIL_INC_2976 2977 +#define Z_UTIL_INC_2977 2978 +#define Z_UTIL_INC_2978 2979 +#define Z_UTIL_INC_2979 2980 +#define Z_UTIL_INC_2980 2981 +#define Z_UTIL_INC_2981 2982 +#define Z_UTIL_INC_2982 2983 +#define Z_UTIL_INC_2983 2984 +#define Z_UTIL_INC_2984 2985 +#define Z_UTIL_INC_2985 2986 +#define Z_UTIL_INC_2986 2987 +#define Z_UTIL_INC_2987 2988 +#define Z_UTIL_INC_2988 2989 +#define Z_UTIL_INC_2989 2990 +#define Z_UTIL_INC_2990 2991 +#define Z_UTIL_INC_2991 2992 +#define Z_UTIL_INC_2992 2993 +#define Z_UTIL_INC_2993 2994 +#define Z_UTIL_INC_2994 2995 +#define Z_UTIL_INC_2995 2996 +#define Z_UTIL_INC_2996 2997 +#define Z_UTIL_INC_2997 2998 +#define Z_UTIL_INC_2998 2999 +#define Z_UTIL_INC_2999 3000 +#define Z_UTIL_INC_3000 3001 +#define Z_UTIL_INC_3001 3002 +#define Z_UTIL_INC_3002 3003 +#define Z_UTIL_INC_3003 3004 +#define Z_UTIL_INC_3004 3005 +#define Z_UTIL_INC_3005 3006 +#define Z_UTIL_INC_3006 3007 +#define Z_UTIL_INC_3007 3008 +#define Z_UTIL_INC_3008 3009 +#define Z_UTIL_INC_3009 3010 +#define Z_UTIL_INC_3010 3011 +#define Z_UTIL_INC_3011 3012 +#define Z_UTIL_INC_3012 3013 +#define Z_UTIL_INC_3013 3014 +#define Z_UTIL_INC_3014 3015 +#define Z_UTIL_INC_3015 3016 +#define Z_UTIL_INC_3016 3017 +#define Z_UTIL_INC_3017 3018 +#define Z_UTIL_INC_3018 3019 +#define Z_UTIL_INC_3019 3020 +#define Z_UTIL_INC_3020 3021 +#define Z_UTIL_INC_3021 3022 +#define Z_UTIL_INC_3022 3023 +#define Z_UTIL_INC_3023 3024 +#define Z_UTIL_INC_3024 3025 +#define Z_UTIL_INC_3025 3026 +#define Z_UTIL_INC_3026 3027 +#define Z_UTIL_INC_3027 3028 +#define Z_UTIL_INC_3028 3029 +#define Z_UTIL_INC_3029 3030 +#define Z_UTIL_INC_3030 3031 +#define Z_UTIL_INC_3031 3032 +#define Z_UTIL_INC_3032 3033 +#define Z_UTIL_INC_3033 3034 +#define Z_UTIL_INC_3034 3035 +#define Z_UTIL_INC_3035 3036 +#define Z_UTIL_INC_3036 3037 +#define Z_UTIL_INC_3037 3038 +#define Z_UTIL_INC_3038 3039 +#define Z_UTIL_INC_3039 3040 +#define Z_UTIL_INC_3040 3041 +#define Z_UTIL_INC_3041 3042 +#define Z_UTIL_INC_3042 3043 +#define Z_UTIL_INC_3043 3044 +#define Z_UTIL_INC_3044 3045 +#define Z_UTIL_INC_3045 3046 +#define Z_UTIL_INC_3046 3047 +#define Z_UTIL_INC_3047 3048 +#define Z_UTIL_INC_3048 3049 +#define Z_UTIL_INC_3049 3050 +#define Z_UTIL_INC_3050 3051 +#define Z_UTIL_INC_3051 3052 +#define Z_UTIL_INC_3052 3053 +#define Z_UTIL_INC_3053 3054 +#define Z_UTIL_INC_3054 3055 +#define Z_UTIL_INC_3055 3056 +#define Z_UTIL_INC_3056 3057 +#define Z_UTIL_INC_3057 3058 +#define Z_UTIL_INC_3058 3059 +#define Z_UTIL_INC_3059 3060 +#define Z_UTIL_INC_3060 3061 +#define Z_UTIL_INC_3061 3062 +#define Z_UTIL_INC_3062 3063 +#define Z_UTIL_INC_3063 3064 +#define Z_UTIL_INC_3064 3065 +#define Z_UTIL_INC_3065 3066 +#define Z_UTIL_INC_3066 3067 +#define Z_UTIL_INC_3067 3068 +#define Z_UTIL_INC_3068 3069 +#define Z_UTIL_INC_3069 3070 +#define Z_UTIL_INC_3070 3071 +#define Z_UTIL_INC_3071 3072 +#define Z_UTIL_INC_3072 3073 +#define Z_UTIL_INC_3073 3074 +#define Z_UTIL_INC_3074 3075 +#define Z_UTIL_INC_3075 3076 +#define Z_UTIL_INC_3076 3077 +#define Z_UTIL_INC_3077 3078 +#define Z_UTIL_INC_3078 3079 +#define Z_UTIL_INC_3079 3080 +#define Z_UTIL_INC_3080 3081 +#define Z_UTIL_INC_3081 3082 +#define Z_UTIL_INC_3082 3083 +#define Z_UTIL_INC_3083 3084 +#define Z_UTIL_INC_3084 3085 +#define Z_UTIL_INC_3085 3086 +#define Z_UTIL_INC_3086 3087 +#define Z_UTIL_INC_3087 3088 +#define Z_UTIL_INC_3088 3089 +#define Z_UTIL_INC_3089 3090 +#define Z_UTIL_INC_3090 3091 +#define Z_UTIL_INC_3091 3092 +#define Z_UTIL_INC_3092 3093 +#define Z_UTIL_INC_3093 3094 +#define Z_UTIL_INC_3094 3095 +#define Z_UTIL_INC_3095 3096 +#define Z_UTIL_INC_3096 3097 +#define Z_UTIL_INC_3097 3098 +#define Z_UTIL_INC_3098 3099 +#define Z_UTIL_INC_3099 3100 +#define Z_UTIL_INC_3100 3101 +#define Z_UTIL_INC_3101 3102 +#define Z_UTIL_INC_3102 3103 +#define Z_UTIL_INC_3103 3104 +#define Z_UTIL_INC_3104 3105 +#define Z_UTIL_INC_3105 3106 +#define Z_UTIL_INC_3106 3107 +#define Z_UTIL_INC_3107 3108 +#define Z_UTIL_INC_3108 3109 +#define Z_UTIL_INC_3109 3110 +#define Z_UTIL_INC_3110 3111 +#define Z_UTIL_INC_3111 3112 +#define Z_UTIL_INC_3112 3113 +#define Z_UTIL_INC_3113 3114 +#define Z_UTIL_INC_3114 3115 +#define Z_UTIL_INC_3115 3116 +#define Z_UTIL_INC_3116 3117 +#define Z_UTIL_INC_3117 3118 +#define Z_UTIL_INC_3118 3119 +#define Z_UTIL_INC_3119 3120 +#define Z_UTIL_INC_3120 3121 +#define Z_UTIL_INC_3121 3122 +#define Z_UTIL_INC_3122 3123 +#define Z_UTIL_INC_3123 3124 +#define Z_UTIL_INC_3124 3125 +#define Z_UTIL_INC_3125 3126 +#define Z_UTIL_INC_3126 3127 +#define Z_UTIL_INC_3127 3128 +#define Z_UTIL_INC_3128 3129 +#define Z_UTIL_INC_3129 3130 +#define Z_UTIL_INC_3130 3131 +#define Z_UTIL_INC_3131 3132 +#define Z_UTIL_INC_3132 3133 +#define Z_UTIL_INC_3133 3134 +#define Z_UTIL_INC_3134 3135 +#define Z_UTIL_INC_3135 3136 +#define Z_UTIL_INC_3136 3137 +#define Z_UTIL_INC_3137 3138 +#define Z_UTIL_INC_3138 3139 +#define Z_UTIL_INC_3139 3140 +#define Z_UTIL_INC_3140 3141 +#define Z_UTIL_INC_3141 3142 +#define Z_UTIL_INC_3142 3143 +#define Z_UTIL_INC_3143 3144 +#define Z_UTIL_INC_3144 3145 +#define Z_UTIL_INC_3145 3146 +#define Z_UTIL_INC_3146 3147 +#define Z_UTIL_INC_3147 3148 +#define Z_UTIL_INC_3148 3149 +#define Z_UTIL_INC_3149 3150 +#define Z_UTIL_INC_3150 3151 +#define Z_UTIL_INC_3151 3152 +#define Z_UTIL_INC_3152 3153 +#define Z_UTIL_INC_3153 3154 +#define Z_UTIL_INC_3154 3155 +#define Z_UTIL_INC_3155 3156 +#define Z_UTIL_INC_3156 3157 +#define Z_UTIL_INC_3157 3158 +#define Z_UTIL_INC_3158 3159 +#define Z_UTIL_INC_3159 3160 +#define Z_UTIL_INC_3160 3161 +#define Z_UTIL_INC_3161 3162 +#define Z_UTIL_INC_3162 3163 +#define Z_UTIL_INC_3163 3164 +#define Z_UTIL_INC_3164 3165 +#define Z_UTIL_INC_3165 3166 +#define Z_UTIL_INC_3166 3167 +#define Z_UTIL_INC_3167 3168 +#define Z_UTIL_INC_3168 3169 +#define Z_UTIL_INC_3169 3170 +#define Z_UTIL_INC_3170 3171 +#define Z_UTIL_INC_3171 3172 +#define Z_UTIL_INC_3172 3173 +#define Z_UTIL_INC_3173 3174 +#define Z_UTIL_INC_3174 3175 +#define Z_UTIL_INC_3175 3176 +#define Z_UTIL_INC_3176 3177 +#define Z_UTIL_INC_3177 3178 +#define Z_UTIL_INC_3178 3179 +#define Z_UTIL_INC_3179 3180 +#define Z_UTIL_INC_3180 3181 +#define Z_UTIL_INC_3181 3182 +#define Z_UTIL_INC_3182 3183 +#define Z_UTIL_INC_3183 3184 +#define Z_UTIL_INC_3184 3185 +#define Z_UTIL_INC_3185 3186 +#define Z_UTIL_INC_3186 3187 +#define Z_UTIL_INC_3187 3188 +#define Z_UTIL_INC_3188 3189 +#define Z_UTIL_INC_3189 3190 +#define Z_UTIL_INC_3190 3191 +#define Z_UTIL_INC_3191 3192 +#define Z_UTIL_INC_3192 3193 +#define Z_UTIL_INC_3193 3194 +#define Z_UTIL_INC_3194 3195 +#define Z_UTIL_INC_3195 3196 +#define Z_UTIL_INC_3196 3197 +#define Z_UTIL_INC_3197 3198 +#define Z_UTIL_INC_3198 3199 +#define Z_UTIL_INC_3199 3200 +#define Z_UTIL_INC_3200 3201 +#define Z_UTIL_INC_3201 3202 +#define Z_UTIL_INC_3202 3203 +#define Z_UTIL_INC_3203 3204 +#define Z_UTIL_INC_3204 3205 +#define Z_UTIL_INC_3205 3206 +#define Z_UTIL_INC_3206 3207 +#define Z_UTIL_INC_3207 3208 +#define Z_UTIL_INC_3208 3209 +#define Z_UTIL_INC_3209 3210 +#define Z_UTIL_INC_3210 3211 +#define Z_UTIL_INC_3211 3212 +#define Z_UTIL_INC_3212 3213 +#define Z_UTIL_INC_3213 3214 +#define Z_UTIL_INC_3214 3215 +#define Z_UTIL_INC_3215 3216 +#define Z_UTIL_INC_3216 3217 +#define Z_UTIL_INC_3217 3218 +#define Z_UTIL_INC_3218 3219 +#define Z_UTIL_INC_3219 3220 +#define Z_UTIL_INC_3220 3221 +#define Z_UTIL_INC_3221 3222 +#define Z_UTIL_INC_3222 3223 +#define Z_UTIL_INC_3223 3224 +#define Z_UTIL_INC_3224 3225 +#define Z_UTIL_INC_3225 3226 +#define Z_UTIL_INC_3226 3227 +#define Z_UTIL_INC_3227 3228 +#define Z_UTIL_INC_3228 3229 +#define Z_UTIL_INC_3229 3230 +#define Z_UTIL_INC_3230 3231 +#define Z_UTIL_INC_3231 3232 +#define Z_UTIL_INC_3232 3233 +#define Z_UTIL_INC_3233 3234 +#define Z_UTIL_INC_3234 3235 +#define Z_UTIL_INC_3235 3236 +#define Z_UTIL_INC_3236 3237 +#define Z_UTIL_INC_3237 3238 +#define Z_UTIL_INC_3238 3239 +#define Z_UTIL_INC_3239 3240 +#define Z_UTIL_INC_3240 3241 +#define Z_UTIL_INC_3241 3242 +#define Z_UTIL_INC_3242 3243 +#define Z_UTIL_INC_3243 3244 +#define Z_UTIL_INC_3244 3245 +#define Z_UTIL_INC_3245 3246 +#define Z_UTIL_INC_3246 3247 +#define Z_UTIL_INC_3247 3248 +#define Z_UTIL_INC_3248 3249 +#define Z_UTIL_INC_3249 3250 +#define Z_UTIL_INC_3250 3251 +#define Z_UTIL_INC_3251 3252 +#define Z_UTIL_INC_3252 3253 +#define Z_UTIL_INC_3253 3254 +#define Z_UTIL_INC_3254 3255 +#define Z_UTIL_INC_3255 3256 +#define Z_UTIL_INC_3256 3257 +#define Z_UTIL_INC_3257 3258 +#define Z_UTIL_INC_3258 3259 +#define Z_UTIL_INC_3259 3260 +#define Z_UTIL_INC_3260 3261 +#define Z_UTIL_INC_3261 3262 +#define Z_UTIL_INC_3262 3263 +#define Z_UTIL_INC_3263 3264 +#define Z_UTIL_INC_3264 3265 +#define Z_UTIL_INC_3265 3266 +#define Z_UTIL_INC_3266 3267 +#define Z_UTIL_INC_3267 3268 +#define Z_UTIL_INC_3268 3269 +#define Z_UTIL_INC_3269 3270 +#define Z_UTIL_INC_3270 3271 +#define Z_UTIL_INC_3271 3272 +#define Z_UTIL_INC_3272 3273 +#define Z_UTIL_INC_3273 3274 +#define Z_UTIL_INC_3274 3275 +#define Z_UTIL_INC_3275 3276 +#define Z_UTIL_INC_3276 3277 +#define Z_UTIL_INC_3277 3278 +#define Z_UTIL_INC_3278 3279 +#define Z_UTIL_INC_3279 3280 +#define Z_UTIL_INC_3280 3281 +#define Z_UTIL_INC_3281 3282 +#define Z_UTIL_INC_3282 3283 +#define Z_UTIL_INC_3283 3284 +#define Z_UTIL_INC_3284 3285 +#define Z_UTIL_INC_3285 3286 +#define Z_UTIL_INC_3286 3287 +#define Z_UTIL_INC_3287 3288 +#define Z_UTIL_INC_3288 3289 +#define Z_UTIL_INC_3289 3290 +#define Z_UTIL_INC_3290 3291 +#define Z_UTIL_INC_3291 3292 +#define Z_UTIL_INC_3292 3293 +#define Z_UTIL_INC_3293 3294 +#define Z_UTIL_INC_3294 3295 +#define Z_UTIL_INC_3295 3296 +#define Z_UTIL_INC_3296 3297 +#define Z_UTIL_INC_3297 3298 +#define Z_UTIL_INC_3298 3299 +#define Z_UTIL_INC_3299 3300 +#define Z_UTIL_INC_3300 3301 +#define Z_UTIL_INC_3301 3302 +#define Z_UTIL_INC_3302 3303 +#define Z_UTIL_INC_3303 3304 +#define Z_UTIL_INC_3304 3305 +#define Z_UTIL_INC_3305 3306 +#define Z_UTIL_INC_3306 3307 +#define Z_UTIL_INC_3307 3308 +#define Z_UTIL_INC_3308 3309 +#define Z_UTIL_INC_3309 3310 +#define Z_UTIL_INC_3310 3311 +#define Z_UTIL_INC_3311 3312 +#define Z_UTIL_INC_3312 3313 +#define Z_UTIL_INC_3313 3314 +#define Z_UTIL_INC_3314 3315 +#define Z_UTIL_INC_3315 3316 +#define Z_UTIL_INC_3316 3317 +#define Z_UTIL_INC_3317 3318 +#define Z_UTIL_INC_3318 3319 +#define Z_UTIL_INC_3319 3320 +#define Z_UTIL_INC_3320 3321 +#define Z_UTIL_INC_3321 3322 +#define Z_UTIL_INC_3322 3323 +#define Z_UTIL_INC_3323 3324 +#define Z_UTIL_INC_3324 3325 +#define Z_UTIL_INC_3325 3326 +#define Z_UTIL_INC_3326 3327 +#define Z_UTIL_INC_3327 3328 +#define Z_UTIL_INC_3328 3329 +#define Z_UTIL_INC_3329 3330 +#define Z_UTIL_INC_3330 3331 +#define Z_UTIL_INC_3331 3332 +#define Z_UTIL_INC_3332 3333 +#define Z_UTIL_INC_3333 3334 +#define Z_UTIL_INC_3334 3335 +#define Z_UTIL_INC_3335 3336 +#define Z_UTIL_INC_3336 3337 +#define Z_UTIL_INC_3337 3338 +#define Z_UTIL_INC_3338 3339 +#define Z_UTIL_INC_3339 3340 +#define Z_UTIL_INC_3340 3341 +#define Z_UTIL_INC_3341 3342 +#define Z_UTIL_INC_3342 3343 +#define Z_UTIL_INC_3343 3344 +#define Z_UTIL_INC_3344 3345 +#define Z_UTIL_INC_3345 3346 +#define Z_UTIL_INC_3346 3347 +#define Z_UTIL_INC_3347 3348 +#define Z_UTIL_INC_3348 3349 +#define Z_UTIL_INC_3349 3350 +#define Z_UTIL_INC_3350 3351 +#define Z_UTIL_INC_3351 3352 +#define Z_UTIL_INC_3352 3353 +#define Z_UTIL_INC_3353 3354 +#define Z_UTIL_INC_3354 3355 +#define Z_UTIL_INC_3355 3356 +#define Z_UTIL_INC_3356 3357 +#define Z_UTIL_INC_3357 3358 +#define Z_UTIL_INC_3358 3359 +#define Z_UTIL_INC_3359 3360 +#define Z_UTIL_INC_3360 3361 +#define Z_UTIL_INC_3361 3362 +#define Z_UTIL_INC_3362 3363 +#define Z_UTIL_INC_3363 3364 +#define Z_UTIL_INC_3364 3365 +#define Z_UTIL_INC_3365 3366 +#define Z_UTIL_INC_3366 3367 +#define Z_UTIL_INC_3367 3368 +#define Z_UTIL_INC_3368 3369 +#define Z_UTIL_INC_3369 3370 +#define Z_UTIL_INC_3370 3371 +#define Z_UTIL_INC_3371 3372 +#define Z_UTIL_INC_3372 3373 +#define Z_UTIL_INC_3373 3374 +#define Z_UTIL_INC_3374 3375 +#define Z_UTIL_INC_3375 3376 +#define Z_UTIL_INC_3376 3377 +#define Z_UTIL_INC_3377 3378 +#define Z_UTIL_INC_3378 3379 +#define Z_UTIL_INC_3379 3380 +#define Z_UTIL_INC_3380 3381 +#define Z_UTIL_INC_3381 3382 +#define Z_UTIL_INC_3382 3383 +#define Z_UTIL_INC_3383 3384 +#define Z_UTIL_INC_3384 3385 +#define Z_UTIL_INC_3385 3386 +#define Z_UTIL_INC_3386 3387 +#define Z_UTIL_INC_3387 3388 +#define Z_UTIL_INC_3388 3389 +#define Z_UTIL_INC_3389 3390 +#define Z_UTIL_INC_3390 3391 +#define Z_UTIL_INC_3391 3392 +#define Z_UTIL_INC_3392 3393 +#define Z_UTIL_INC_3393 3394 +#define Z_UTIL_INC_3394 3395 +#define Z_UTIL_INC_3395 3396 +#define Z_UTIL_INC_3396 3397 +#define Z_UTIL_INC_3397 3398 +#define Z_UTIL_INC_3398 3399 +#define Z_UTIL_INC_3399 3400 +#define Z_UTIL_INC_3400 3401 +#define Z_UTIL_INC_3401 3402 +#define Z_UTIL_INC_3402 3403 +#define Z_UTIL_INC_3403 3404 +#define Z_UTIL_INC_3404 3405 +#define Z_UTIL_INC_3405 3406 +#define Z_UTIL_INC_3406 3407 +#define Z_UTIL_INC_3407 3408 +#define Z_UTIL_INC_3408 3409 +#define Z_UTIL_INC_3409 3410 +#define Z_UTIL_INC_3410 3411 +#define Z_UTIL_INC_3411 3412 +#define Z_UTIL_INC_3412 3413 +#define Z_UTIL_INC_3413 3414 +#define Z_UTIL_INC_3414 3415 +#define Z_UTIL_INC_3415 3416 +#define Z_UTIL_INC_3416 3417 +#define Z_UTIL_INC_3417 3418 +#define Z_UTIL_INC_3418 3419 +#define Z_UTIL_INC_3419 3420 +#define Z_UTIL_INC_3420 3421 +#define Z_UTIL_INC_3421 3422 +#define Z_UTIL_INC_3422 3423 +#define Z_UTIL_INC_3423 3424 +#define Z_UTIL_INC_3424 3425 +#define Z_UTIL_INC_3425 3426 +#define Z_UTIL_INC_3426 3427 +#define Z_UTIL_INC_3427 3428 +#define Z_UTIL_INC_3428 3429 +#define Z_UTIL_INC_3429 3430 +#define Z_UTIL_INC_3430 3431 +#define Z_UTIL_INC_3431 3432 +#define Z_UTIL_INC_3432 3433 +#define Z_UTIL_INC_3433 3434 +#define Z_UTIL_INC_3434 3435 +#define Z_UTIL_INC_3435 3436 +#define Z_UTIL_INC_3436 3437 +#define Z_UTIL_INC_3437 3438 +#define Z_UTIL_INC_3438 3439 +#define Z_UTIL_INC_3439 3440 +#define Z_UTIL_INC_3440 3441 +#define Z_UTIL_INC_3441 3442 +#define Z_UTIL_INC_3442 3443 +#define Z_UTIL_INC_3443 3444 +#define Z_UTIL_INC_3444 3445 +#define Z_UTIL_INC_3445 3446 +#define Z_UTIL_INC_3446 3447 +#define Z_UTIL_INC_3447 3448 +#define Z_UTIL_INC_3448 3449 +#define Z_UTIL_INC_3449 3450 +#define Z_UTIL_INC_3450 3451 +#define Z_UTIL_INC_3451 3452 +#define Z_UTIL_INC_3452 3453 +#define Z_UTIL_INC_3453 3454 +#define Z_UTIL_INC_3454 3455 +#define Z_UTIL_INC_3455 3456 +#define Z_UTIL_INC_3456 3457 +#define Z_UTIL_INC_3457 3458 +#define Z_UTIL_INC_3458 3459 +#define Z_UTIL_INC_3459 3460 +#define Z_UTIL_INC_3460 3461 +#define Z_UTIL_INC_3461 3462 +#define Z_UTIL_INC_3462 3463 +#define Z_UTIL_INC_3463 3464 +#define Z_UTIL_INC_3464 3465 +#define Z_UTIL_INC_3465 3466 +#define Z_UTIL_INC_3466 3467 +#define Z_UTIL_INC_3467 3468 +#define Z_UTIL_INC_3468 3469 +#define Z_UTIL_INC_3469 3470 +#define Z_UTIL_INC_3470 3471 +#define Z_UTIL_INC_3471 3472 +#define Z_UTIL_INC_3472 3473 +#define Z_UTIL_INC_3473 3474 +#define Z_UTIL_INC_3474 3475 +#define Z_UTIL_INC_3475 3476 +#define Z_UTIL_INC_3476 3477 +#define Z_UTIL_INC_3477 3478 +#define Z_UTIL_INC_3478 3479 +#define Z_UTIL_INC_3479 3480 +#define Z_UTIL_INC_3480 3481 +#define Z_UTIL_INC_3481 3482 +#define Z_UTIL_INC_3482 3483 +#define Z_UTIL_INC_3483 3484 +#define Z_UTIL_INC_3484 3485 +#define Z_UTIL_INC_3485 3486 +#define Z_UTIL_INC_3486 3487 +#define Z_UTIL_INC_3487 3488 +#define Z_UTIL_INC_3488 3489 +#define Z_UTIL_INC_3489 3490 +#define Z_UTIL_INC_3490 3491 +#define Z_UTIL_INC_3491 3492 +#define Z_UTIL_INC_3492 3493 +#define Z_UTIL_INC_3493 3494 +#define Z_UTIL_INC_3494 3495 +#define Z_UTIL_INC_3495 3496 +#define Z_UTIL_INC_3496 3497 +#define Z_UTIL_INC_3497 3498 +#define Z_UTIL_INC_3498 3499 +#define Z_UTIL_INC_3499 3500 +#define Z_UTIL_INC_3500 3501 +#define Z_UTIL_INC_3501 3502 +#define Z_UTIL_INC_3502 3503 +#define Z_UTIL_INC_3503 3504 +#define Z_UTIL_INC_3504 3505 +#define Z_UTIL_INC_3505 3506 +#define Z_UTIL_INC_3506 3507 +#define Z_UTIL_INC_3507 3508 +#define Z_UTIL_INC_3508 3509 +#define Z_UTIL_INC_3509 3510 +#define Z_UTIL_INC_3510 3511 +#define Z_UTIL_INC_3511 3512 +#define Z_UTIL_INC_3512 3513 +#define Z_UTIL_INC_3513 3514 +#define Z_UTIL_INC_3514 3515 +#define Z_UTIL_INC_3515 3516 +#define Z_UTIL_INC_3516 3517 +#define Z_UTIL_INC_3517 3518 +#define Z_UTIL_INC_3518 3519 +#define Z_UTIL_INC_3519 3520 +#define Z_UTIL_INC_3520 3521 +#define Z_UTIL_INC_3521 3522 +#define Z_UTIL_INC_3522 3523 +#define Z_UTIL_INC_3523 3524 +#define Z_UTIL_INC_3524 3525 +#define Z_UTIL_INC_3525 3526 +#define Z_UTIL_INC_3526 3527 +#define Z_UTIL_INC_3527 3528 +#define Z_UTIL_INC_3528 3529 +#define Z_UTIL_INC_3529 3530 +#define Z_UTIL_INC_3530 3531 +#define Z_UTIL_INC_3531 3532 +#define Z_UTIL_INC_3532 3533 +#define Z_UTIL_INC_3533 3534 +#define Z_UTIL_INC_3534 3535 +#define Z_UTIL_INC_3535 3536 +#define Z_UTIL_INC_3536 3537 +#define Z_UTIL_INC_3537 3538 +#define Z_UTIL_INC_3538 3539 +#define Z_UTIL_INC_3539 3540 +#define Z_UTIL_INC_3540 3541 +#define Z_UTIL_INC_3541 3542 +#define Z_UTIL_INC_3542 3543 +#define Z_UTIL_INC_3543 3544 +#define Z_UTIL_INC_3544 3545 +#define Z_UTIL_INC_3545 3546 +#define Z_UTIL_INC_3546 3547 +#define Z_UTIL_INC_3547 3548 +#define Z_UTIL_INC_3548 3549 +#define Z_UTIL_INC_3549 3550 +#define Z_UTIL_INC_3550 3551 +#define Z_UTIL_INC_3551 3552 +#define Z_UTIL_INC_3552 3553 +#define Z_UTIL_INC_3553 3554 +#define Z_UTIL_INC_3554 3555 +#define Z_UTIL_INC_3555 3556 +#define Z_UTIL_INC_3556 3557 +#define Z_UTIL_INC_3557 3558 +#define Z_UTIL_INC_3558 3559 +#define Z_UTIL_INC_3559 3560 +#define Z_UTIL_INC_3560 3561 +#define Z_UTIL_INC_3561 3562 +#define Z_UTIL_INC_3562 3563 +#define Z_UTIL_INC_3563 3564 +#define Z_UTIL_INC_3564 3565 +#define Z_UTIL_INC_3565 3566 +#define Z_UTIL_INC_3566 3567 +#define Z_UTIL_INC_3567 3568 +#define Z_UTIL_INC_3568 3569 +#define Z_UTIL_INC_3569 3570 +#define Z_UTIL_INC_3570 3571 +#define Z_UTIL_INC_3571 3572 +#define Z_UTIL_INC_3572 3573 +#define Z_UTIL_INC_3573 3574 +#define Z_UTIL_INC_3574 3575 +#define Z_UTIL_INC_3575 3576 +#define Z_UTIL_INC_3576 3577 +#define Z_UTIL_INC_3577 3578 +#define Z_UTIL_INC_3578 3579 +#define Z_UTIL_INC_3579 3580 +#define Z_UTIL_INC_3580 3581 +#define Z_UTIL_INC_3581 3582 +#define Z_UTIL_INC_3582 3583 +#define Z_UTIL_INC_3583 3584 +#define Z_UTIL_INC_3584 3585 +#define Z_UTIL_INC_3585 3586 +#define Z_UTIL_INC_3586 3587 +#define Z_UTIL_INC_3587 3588 +#define Z_UTIL_INC_3588 3589 +#define Z_UTIL_INC_3589 3590 +#define Z_UTIL_INC_3590 3591 +#define Z_UTIL_INC_3591 3592 +#define Z_UTIL_INC_3592 3593 +#define Z_UTIL_INC_3593 3594 +#define Z_UTIL_INC_3594 3595 +#define Z_UTIL_INC_3595 3596 +#define Z_UTIL_INC_3596 3597 +#define Z_UTIL_INC_3597 3598 +#define Z_UTIL_INC_3598 3599 +#define Z_UTIL_INC_3599 3600 +#define Z_UTIL_INC_3600 3601 +#define Z_UTIL_INC_3601 3602 +#define Z_UTIL_INC_3602 3603 +#define Z_UTIL_INC_3603 3604 +#define Z_UTIL_INC_3604 3605 +#define Z_UTIL_INC_3605 3606 +#define Z_UTIL_INC_3606 3607 +#define Z_UTIL_INC_3607 3608 +#define Z_UTIL_INC_3608 3609 +#define Z_UTIL_INC_3609 3610 +#define Z_UTIL_INC_3610 3611 +#define Z_UTIL_INC_3611 3612 +#define Z_UTIL_INC_3612 3613 +#define Z_UTIL_INC_3613 3614 +#define Z_UTIL_INC_3614 3615 +#define Z_UTIL_INC_3615 3616 +#define Z_UTIL_INC_3616 3617 +#define Z_UTIL_INC_3617 3618 +#define Z_UTIL_INC_3618 3619 +#define Z_UTIL_INC_3619 3620 +#define Z_UTIL_INC_3620 3621 +#define Z_UTIL_INC_3621 3622 +#define Z_UTIL_INC_3622 3623 +#define Z_UTIL_INC_3623 3624 +#define Z_UTIL_INC_3624 3625 +#define Z_UTIL_INC_3625 3626 +#define Z_UTIL_INC_3626 3627 +#define Z_UTIL_INC_3627 3628 +#define Z_UTIL_INC_3628 3629 +#define Z_UTIL_INC_3629 3630 +#define Z_UTIL_INC_3630 3631 +#define Z_UTIL_INC_3631 3632 +#define Z_UTIL_INC_3632 3633 +#define Z_UTIL_INC_3633 3634 +#define Z_UTIL_INC_3634 3635 +#define Z_UTIL_INC_3635 3636 +#define Z_UTIL_INC_3636 3637 +#define Z_UTIL_INC_3637 3638 +#define Z_UTIL_INC_3638 3639 +#define Z_UTIL_INC_3639 3640 +#define Z_UTIL_INC_3640 3641 +#define Z_UTIL_INC_3641 3642 +#define Z_UTIL_INC_3642 3643 +#define Z_UTIL_INC_3643 3644 +#define Z_UTIL_INC_3644 3645 +#define Z_UTIL_INC_3645 3646 +#define Z_UTIL_INC_3646 3647 +#define Z_UTIL_INC_3647 3648 +#define Z_UTIL_INC_3648 3649 +#define Z_UTIL_INC_3649 3650 +#define Z_UTIL_INC_3650 3651 +#define Z_UTIL_INC_3651 3652 +#define Z_UTIL_INC_3652 3653 +#define Z_UTIL_INC_3653 3654 +#define Z_UTIL_INC_3654 3655 +#define Z_UTIL_INC_3655 3656 +#define Z_UTIL_INC_3656 3657 +#define Z_UTIL_INC_3657 3658 +#define Z_UTIL_INC_3658 3659 +#define Z_UTIL_INC_3659 3660 +#define Z_UTIL_INC_3660 3661 +#define Z_UTIL_INC_3661 3662 +#define Z_UTIL_INC_3662 3663 +#define Z_UTIL_INC_3663 3664 +#define Z_UTIL_INC_3664 3665 +#define Z_UTIL_INC_3665 3666 +#define Z_UTIL_INC_3666 3667 +#define Z_UTIL_INC_3667 3668 +#define Z_UTIL_INC_3668 3669 +#define Z_UTIL_INC_3669 3670 +#define Z_UTIL_INC_3670 3671 +#define Z_UTIL_INC_3671 3672 +#define Z_UTIL_INC_3672 3673 +#define Z_UTIL_INC_3673 3674 +#define Z_UTIL_INC_3674 3675 +#define Z_UTIL_INC_3675 3676 +#define Z_UTIL_INC_3676 3677 +#define Z_UTIL_INC_3677 3678 +#define Z_UTIL_INC_3678 3679 +#define Z_UTIL_INC_3679 3680 +#define Z_UTIL_INC_3680 3681 +#define Z_UTIL_INC_3681 3682 +#define Z_UTIL_INC_3682 3683 +#define Z_UTIL_INC_3683 3684 +#define Z_UTIL_INC_3684 3685 +#define Z_UTIL_INC_3685 3686 +#define Z_UTIL_INC_3686 3687 +#define Z_UTIL_INC_3687 3688 +#define Z_UTIL_INC_3688 3689 +#define Z_UTIL_INC_3689 3690 +#define Z_UTIL_INC_3690 3691 +#define Z_UTIL_INC_3691 3692 +#define Z_UTIL_INC_3692 3693 +#define Z_UTIL_INC_3693 3694 +#define Z_UTIL_INC_3694 3695 +#define Z_UTIL_INC_3695 3696 +#define Z_UTIL_INC_3696 3697 +#define Z_UTIL_INC_3697 3698 +#define Z_UTIL_INC_3698 3699 +#define Z_UTIL_INC_3699 3700 +#define Z_UTIL_INC_3700 3701 +#define Z_UTIL_INC_3701 3702 +#define Z_UTIL_INC_3702 3703 +#define Z_UTIL_INC_3703 3704 +#define Z_UTIL_INC_3704 3705 +#define Z_UTIL_INC_3705 3706 +#define Z_UTIL_INC_3706 3707 +#define Z_UTIL_INC_3707 3708 +#define Z_UTIL_INC_3708 3709 +#define Z_UTIL_INC_3709 3710 +#define Z_UTIL_INC_3710 3711 +#define Z_UTIL_INC_3711 3712 +#define Z_UTIL_INC_3712 3713 +#define Z_UTIL_INC_3713 3714 +#define Z_UTIL_INC_3714 3715 +#define Z_UTIL_INC_3715 3716 +#define Z_UTIL_INC_3716 3717 +#define Z_UTIL_INC_3717 3718 +#define Z_UTIL_INC_3718 3719 +#define Z_UTIL_INC_3719 3720 +#define Z_UTIL_INC_3720 3721 +#define Z_UTIL_INC_3721 3722 +#define Z_UTIL_INC_3722 3723 +#define Z_UTIL_INC_3723 3724 +#define Z_UTIL_INC_3724 3725 +#define Z_UTIL_INC_3725 3726 +#define Z_UTIL_INC_3726 3727 +#define Z_UTIL_INC_3727 3728 +#define Z_UTIL_INC_3728 3729 +#define Z_UTIL_INC_3729 3730 +#define Z_UTIL_INC_3730 3731 +#define Z_UTIL_INC_3731 3732 +#define Z_UTIL_INC_3732 3733 +#define Z_UTIL_INC_3733 3734 +#define Z_UTIL_INC_3734 3735 +#define Z_UTIL_INC_3735 3736 +#define Z_UTIL_INC_3736 3737 +#define Z_UTIL_INC_3737 3738 +#define Z_UTIL_INC_3738 3739 +#define Z_UTIL_INC_3739 3740 +#define Z_UTIL_INC_3740 3741 +#define Z_UTIL_INC_3741 3742 +#define Z_UTIL_INC_3742 3743 +#define Z_UTIL_INC_3743 3744 +#define Z_UTIL_INC_3744 3745 +#define Z_UTIL_INC_3745 3746 +#define Z_UTIL_INC_3746 3747 +#define Z_UTIL_INC_3747 3748 +#define Z_UTIL_INC_3748 3749 +#define Z_UTIL_INC_3749 3750 +#define Z_UTIL_INC_3750 3751 +#define Z_UTIL_INC_3751 3752 +#define Z_UTIL_INC_3752 3753 +#define Z_UTIL_INC_3753 3754 +#define Z_UTIL_INC_3754 3755 +#define Z_UTIL_INC_3755 3756 +#define Z_UTIL_INC_3756 3757 +#define Z_UTIL_INC_3757 3758 +#define Z_UTIL_INC_3758 3759 +#define Z_UTIL_INC_3759 3760 +#define Z_UTIL_INC_3760 3761 +#define Z_UTIL_INC_3761 3762 +#define Z_UTIL_INC_3762 3763 +#define Z_UTIL_INC_3763 3764 +#define Z_UTIL_INC_3764 3765 +#define Z_UTIL_INC_3765 3766 +#define Z_UTIL_INC_3766 3767 +#define Z_UTIL_INC_3767 3768 +#define Z_UTIL_INC_3768 3769 +#define Z_UTIL_INC_3769 3770 +#define Z_UTIL_INC_3770 3771 +#define Z_UTIL_INC_3771 3772 +#define Z_UTIL_INC_3772 3773 +#define Z_UTIL_INC_3773 3774 +#define Z_UTIL_INC_3774 3775 +#define Z_UTIL_INC_3775 3776 +#define Z_UTIL_INC_3776 3777 +#define Z_UTIL_INC_3777 3778 +#define Z_UTIL_INC_3778 3779 +#define Z_UTIL_INC_3779 3780 +#define Z_UTIL_INC_3780 3781 +#define Z_UTIL_INC_3781 3782 +#define Z_UTIL_INC_3782 3783 +#define Z_UTIL_INC_3783 3784 +#define Z_UTIL_INC_3784 3785 +#define Z_UTIL_INC_3785 3786 +#define Z_UTIL_INC_3786 3787 +#define Z_UTIL_INC_3787 3788 +#define Z_UTIL_INC_3788 3789 +#define Z_UTIL_INC_3789 3790 +#define Z_UTIL_INC_3790 3791 +#define Z_UTIL_INC_3791 3792 +#define Z_UTIL_INC_3792 3793 +#define Z_UTIL_INC_3793 3794 +#define Z_UTIL_INC_3794 3795 +#define Z_UTIL_INC_3795 3796 +#define Z_UTIL_INC_3796 3797 +#define Z_UTIL_INC_3797 3798 +#define Z_UTIL_INC_3798 3799 +#define Z_UTIL_INC_3799 3800 +#define Z_UTIL_INC_3800 3801 +#define Z_UTIL_INC_3801 3802 +#define Z_UTIL_INC_3802 3803 +#define Z_UTIL_INC_3803 3804 +#define Z_UTIL_INC_3804 3805 +#define Z_UTIL_INC_3805 3806 +#define Z_UTIL_INC_3806 3807 +#define Z_UTIL_INC_3807 3808 +#define Z_UTIL_INC_3808 3809 +#define Z_UTIL_INC_3809 3810 +#define Z_UTIL_INC_3810 3811 +#define Z_UTIL_INC_3811 3812 +#define Z_UTIL_INC_3812 3813 +#define Z_UTIL_INC_3813 3814 +#define Z_UTIL_INC_3814 3815 +#define Z_UTIL_INC_3815 3816 +#define Z_UTIL_INC_3816 3817 +#define Z_UTIL_INC_3817 3818 +#define Z_UTIL_INC_3818 3819 +#define Z_UTIL_INC_3819 3820 +#define Z_UTIL_INC_3820 3821 +#define Z_UTIL_INC_3821 3822 +#define Z_UTIL_INC_3822 3823 +#define Z_UTIL_INC_3823 3824 +#define Z_UTIL_INC_3824 3825 +#define Z_UTIL_INC_3825 3826 +#define Z_UTIL_INC_3826 3827 +#define Z_UTIL_INC_3827 3828 +#define Z_UTIL_INC_3828 3829 +#define Z_UTIL_INC_3829 3830 +#define Z_UTIL_INC_3830 3831 +#define Z_UTIL_INC_3831 3832 +#define Z_UTIL_INC_3832 3833 +#define Z_UTIL_INC_3833 3834 +#define Z_UTIL_INC_3834 3835 +#define Z_UTIL_INC_3835 3836 +#define Z_UTIL_INC_3836 3837 +#define Z_UTIL_INC_3837 3838 +#define Z_UTIL_INC_3838 3839 +#define Z_UTIL_INC_3839 3840 +#define Z_UTIL_INC_3840 3841 +#define Z_UTIL_INC_3841 3842 +#define Z_UTIL_INC_3842 3843 +#define Z_UTIL_INC_3843 3844 +#define Z_UTIL_INC_3844 3845 +#define Z_UTIL_INC_3845 3846 +#define Z_UTIL_INC_3846 3847 +#define Z_UTIL_INC_3847 3848 +#define Z_UTIL_INC_3848 3849 +#define Z_UTIL_INC_3849 3850 +#define Z_UTIL_INC_3850 3851 +#define Z_UTIL_INC_3851 3852 +#define Z_UTIL_INC_3852 3853 +#define Z_UTIL_INC_3853 3854 +#define Z_UTIL_INC_3854 3855 +#define Z_UTIL_INC_3855 3856 +#define Z_UTIL_INC_3856 3857 +#define Z_UTIL_INC_3857 3858 +#define Z_UTIL_INC_3858 3859 +#define Z_UTIL_INC_3859 3860 +#define Z_UTIL_INC_3860 3861 +#define Z_UTIL_INC_3861 3862 +#define Z_UTIL_INC_3862 3863 +#define Z_UTIL_INC_3863 3864 +#define Z_UTIL_INC_3864 3865 +#define Z_UTIL_INC_3865 3866 +#define Z_UTIL_INC_3866 3867 +#define Z_UTIL_INC_3867 3868 +#define Z_UTIL_INC_3868 3869 +#define Z_UTIL_INC_3869 3870 +#define Z_UTIL_INC_3870 3871 +#define Z_UTIL_INC_3871 3872 +#define Z_UTIL_INC_3872 3873 +#define Z_UTIL_INC_3873 3874 +#define Z_UTIL_INC_3874 3875 +#define Z_UTIL_INC_3875 3876 +#define Z_UTIL_INC_3876 3877 +#define Z_UTIL_INC_3877 3878 +#define Z_UTIL_INC_3878 3879 +#define Z_UTIL_INC_3879 3880 +#define Z_UTIL_INC_3880 3881 +#define Z_UTIL_INC_3881 3882 +#define Z_UTIL_INC_3882 3883 +#define Z_UTIL_INC_3883 3884 +#define Z_UTIL_INC_3884 3885 +#define Z_UTIL_INC_3885 3886 +#define Z_UTIL_INC_3886 3887 +#define Z_UTIL_INC_3887 3888 +#define Z_UTIL_INC_3888 3889 +#define Z_UTIL_INC_3889 3890 +#define Z_UTIL_INC_3890 3891 +#define Z_UTIL_INC_3891 3892 +#define Z_UTIL_INC_3892 3893 +#define Z_UTIL_INC_3893 3894 +#define Z_UTIL_INC_3894 3895 +#define Z_UTIL_INC_3895 3896 +#define Z_UTIL_INC_3896 3897 +#define Z_UTIL_INC_3897 3898 +#define Z_UTIL_INC_3898 3899 +#define Z_UTIL_INC_3899 3900 +#define Z_UTIL_INC_3900 3901 +#define Z_UTIL_INC_3901 3902 +#define Z_UTIL_INC_3902 3903 +#define Z_UTIL_INC_3903 3904 +#define Z_UTIL_INC_3904 3905 +#define Z_UTIL_INC_3905 3906 +#define Z_UTIL_INC_3906 3907 +#define Z_UTIL_INC_3907 3908 +#define Z_UTIL_INC_3908 3909 +#define Z_UTIL_INC_3909 3910 +#define Z_UTIL_INC_3910 3911 +#define Z_UTIL_INC_3911 3912 +#define Z_UTIL_INC_3912 3913 +#define Z_UTIL_INC_3913 3914 +#define Z_UTIL_INC_3914 3915 +#define Z_UTIL_INC_3915 3916 +#define Z_UTIL_INC_3916 3917 +#define Z_UTIL_INC_3917 3918 +#define Z_UTIL_INC_3918 3919 +#define Z_UTIL_INC_3919 3920 +#define Z_UTIL_INC_3920 3921 +#define Z_UTIL_INC_3921 3922 +#define Z_UTIL_INC_3922 3923 +#define Z_UTIL_INC_3923 3924 +#define Z_UTIL_INC_3924 3925 +#define Z_UTIL_INC_3925 3926 +#define Z_UTIL_INC_3926 3927 +#define Z_UTIL_INC_3927 3928 +#define Z_UTIL_INC_3928 3929 +#define Z_UTIL_INC_3929 3930 +#define Z_UTIL_INC_3930 3931 +#define Z_UTIL_INC_3931 3932 +#define Z_UTIL_INC_3932 3933 +#define Z_UTIL_INC_3933 3934 +#define Z_UTIL_INC_3934 3935 +#define Z_UTIL_INC_3935 3936 +#define Z_UTIL_INC_3936 3937 +#define Z_UTIL_INC_3937 3938 +#define Z_UTIL_INC_3938 3939 +#define Z_UTIL_INC_3939 3940 +#define Z_UTIL_INC_3940 3941 +#define Z_UTIL_INC_3941 3942 +#define Z_UTIL_INC_3942 3943 +#define Z_UTIL_INC_3943 3944 +#define Z_UTIL_INC_3944 3945 +#define Z_UTIL_INC_3945 3946 +#define Z_UTIL_INC_3946 3947 +#define Z_UTIL_INC_3947 3948 +#define Z_UTIL_INC_3948 3949 +#define Z_UTIL_INC_3949 3950 +#define Z_UTIL_INC_3950 3951 +#define Z_UTIL_INC_3951 3952 +#define Z_UTIL_INC_3952 3953 +#define Z_UTIL_INC_3953 3954 +#define Z_UTIL_INC_3954 3955 +#define Z_UTIL_INC_3955 3956 +#define Z_UTIL_INC_3956 3957 +#define Z_UTIL_INC_3957 3958 +#define Z_UTIL_INC_3958 3959 +#define Z_UTIL_INC_3959 3960 +#define Z_UTIL_INC_3960 3961 +#define Z_UTIL_INC_3961 3962 +#define Z_UTIL_INC_3962 3963 +#define Z_UTIL_INC_3963 3964 +#define Z_UTIL_INC_3964 3965 +#define Z_UTIL_INC_3965 3966 +#define Z_UTIL_INC_3966 3967 +#define Z_UTIL_INC_3967 3968 +#define Z_UTIL_INC_3968 3969 +#define Z_UTIL_INC_3969 3970 +#define Z_UTIL_INC_3970 3971 +#define Z_UTIL_INC_3971 3972 +#define Z_UTIL_INC_3972 3973 +#define Z_UTIL_INC_3973 3974 +#define Z_UTIL_INC_3974 3975 +#define Z_UTIL_INC_3975 3976 +#define Z_UTIL_INC_3976 3977 +#define Z_UTIL_INC_3977 3978 +#define Z_UTIL_INC_3978 3979 +#define Z_UTIL_INC_3979 3980 +#define Z_UTIL_INC_3980 3981 +#define Z_UTIL_INC_3981 3982 +#define Z_UTIL_INC_3982 3983 +#define Z_UTIL_INC_3983 3984 +#define Z_UTIL_INC_3984 3985 +#define Z_UTIL_INC_3985 3986 +#define Z_UTIL_INC_3986 3987 +#define Z_UTIL_INC_3987 3988 +#define Z_UTIL_INC_3988 3989 +#define Z_UTIL_INC_3989 3990 +#define Z_UTIL_INC_3990 3991 +#define Z_UTIL_INC_3991 3992 +#define Z_UTIL_INC_3992 3993 +#define Z_UTIL_INC_3993 3994 +#define Z_UTIL_INC_3994 3995 +#define Z_UTIL_INC_3995 3996 +#define Z_UTIL_INC_3996 3997 +#define Z_UTIL_INC_3997 3998 +#define Z_UTIL_INC_3998 3999 +#define Z_UTIL_INC_3999 4000 +#define Z_UTIL_INC_4000 4001 +#define Z_UTIL_INC_4001 4002 +#define Z_UTIL_INC_4002 4003 +#define Z_UTIL_INC_4003 4004 +#define Z_UTIL_INC_4004 4005 +#define Z_UTIL_INC_4005 4006 +#define Z_UTIL_INC_4006 4007 +#define Z_UTIL_INC_4007 4008 +#define Z_UTIL_INC_4008 4009 +#define Z_UTIL_INC_4009 4010 +#define Z_UTIL_INC_4010 4011 +#define Z_UTIL_INC_4011 4012 +#define Z_UTIL_INC_4012 4013 +#define Z_UTIL_INC_4013 4014 +#define Z_UTIL_INC_4014 4015 +#define Z_UTIL_INC_4015 4016 +#define Z_UTIL_INC_4016 4017 +#define Z_UTIL_INC_4017 4018 +#define Z_UTIL_INC_4018 4019 +#define Z_UTIL_INC_4019 4020 +#define Z_UTIL_INC_4020 4021 +#define Z_UTIL_INC_4021 4022 +#define Z_UTIL_INC_4022 4023 +#define Z_UTIL_INC_4023 4024 +#define Z_UTIL_INC_4024 4025 +#define Z_UTIL_INC_4025 4026 +#define Z_UTIL_INC_4026 4027 +#define Z_UTIL_INC_4027 4028 +#define Z_UTIL_INC_4028 4029 +#define Z_UTIL_INC_4029 4030 +#define Z_UTIL_INC_4030 4031 +#define Z_UTIL_INC_4031 4032 +#define Z_UTIL_INC_4032 4033 +#define Z_UTIL_INC_4033 4034 +#define Z_UTIL_INC_4034 4035 +#define Z_UTIL_INC_4035 4036 +#define Z_UTIL_INC_4036 4037 +#define Z_UTIL_INC_4037 4038 +#define Z_UTIL_INC_4038 4039 +#define Z_UTIL_INC_4039 4040 +#define Z_UTIL_INC_4040 4041 +#define Z_UTIL_INC_4041 4042 +#define Z_UTIL_INC_4042 4043 +#define Z_UTIL_INC_4043 4044 +#define Z_UTIL_INC_4044 4045 +#define Z_UTIL_INC_4045 4046 +#define Z_UTIL_INC_4046 4047 +#define Z_UTIL_INC_4047 4048 +#define Z_UTIL_INC_4048 4049 +#define Z_UTIL_INC_4049 4050 +#define Z_UTIL_INC_4050 4051 +#define Z_UTIL_INC_4051 4052 +#define Z_UTIL_INC_4052 4053 +#define Z_UTIL_INC_4053 4054 +#define Z_UTIL_INC_4054 4055 +#define Z_UTIL_INC_4055 4056 +#define Z_UTIL_INC_4056 4057 +#define Z_UTIL_INC_4057 4058 +#define Z_UTIL_INC_4058 4059 +#define Z_UTIL_INC_4059 4060 +#define Z_UTIL_INC_4060 4061 +#define Z_UTIL_INC_4061 4062 +#define Z_UTIL_INC_4062 4063 +#define Z_UTIL_INC_4063 4064 +#define Z_UTIL_INC_4064 4065 +#define Z_UTIL_INC_4065 4066 +#define Z_UTIL_INC_4066 4067 +#define Z_UTIL_INC_4067 4068 +#define Z_UTIL_INC_4068 4069 +#define Z_UTIL_INC_4069 4070 +#define Z_UTIL_INC_4070 4071 +#define Z_UTIL_INC_4071 4072 +#define Z_UTIL_INC_4072 4073 +#define Z_UTIL_INC_4073 4074 +#define Z_UTIL_INC_4074 4075 +#define Z_UTIL_INC_4075 4076 +#define Z_UTIL_INC_4076 4077 +#define Z_UTIL_INC_4077 4078 +#define Z_UTIL_INC_4078 4079 +#define Z_UTIL_INC_4079 4080 +#define Z_UTIL_INC_4080 4081 +#define Z_UTIL_INC_4081 4082 +#define Z_UTIL_INC_4082 4083 +#define Z_UTIL_INC_4083 4084 +#define Z_UTIL_INC_4084 4085 +#define Z_UTIL_INC_4085 4086 +#define Z_UTIL_INC_4086 4087 +#define Z_UTIL_INC_4087 4088 +#define Z_UTIL_INC_4088 4089 +#define Z_UTIL_INC_4089 4090 +#define Z_UTIL_INC_4090 4091 +#define Z_UTIL_INC_4091 4092 +#define Z_UTIL_INC_4092 4093 +#define Z_UTIL_INC_4093 4094 +#define Z_UTIL_INC_4094 4095 +#define Z_UTIL_INC_4095 4096 +#define Z_UTIL_INC_4096 4097 + +#endif /* ZEPHYR_INCLUDE_SYS_UTIL_INTERNAL_UTIL_INC_H_ */ + +/** + * INTERNAL_HIDDEN @endcond + */ diff --git a/components/bt/esp_ble_audio/include/zephyr/sys/util_internal_util_x2.h b/components/bt/esp_ble_audio/include/zephyr/sys/util_internal_util_x2.h new file mode 100644 index 0000000000..fb2b770a3f --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/sys/util_internal_util_x2.h @@ -0,0 +1,4121 @@ +/* + * SPDX-FileCopyrightText: 2011-2014, Wind River Systems, Inc. + * SPDX-FileCopyrightText: 2020, Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @cond INTERNAL_HIDDEN + */ + +#ifndef ZEPHYR_INCLUDE_SYS_UTIL_INTERNAL_H_ +#error "This header should not be used directly, please include util_internal.h instead" +#endif /* ZEPHYR_INCLUDE_SYS_UTIL_INTERNAL_H_ */ + +#ifndef ZEPHYR_INCLUDE_SYS_UTIL_INTERNAL_UTIL_X2_H_ +#define ZEPHYR_INCLUDE_SYS_UTIL_INTERNAL_UTIL_X2_H_ + +#define Z_UTIL_X2_0 0 +#define Z_UTIL_X2_1 2 +#define Z_UTIL_X2_2 4 +#define Z_UTIL_X2_3 6 +#define Z_UTIL_X2_4 8 +#define Z_UTIL_X2_5 10 +#define Z_UTIL_X2_6 12 +#define Z_UTIL_X2_7 14 +#define Z_UTIL_X2_8 16 +#define Z_UTIL_X2_9 18 +#define Z_UTIL_X2_10 20 +#define Z_UTIL_X2_11 22 +#define Z_UTIL_X2_12 24 +#define Z_UTIL_X2_13 26 +#define Z_UTIL_X2_14 28 +#define Z_UTIL_X2_15 30 +#define Z_UTIL_X2_16 32 +#define Z_UTIL_X2_17 34 +#define Z_UTIL_X2_18 36 +#define Z_UTIL_X2_19 38 +#define Z_UTIL_X2_20 40 +#define Z_UTIL_X2_21 42 +#define Z_UTIL_X2_22 44 +#define Z_UTIL_X2_23 46 +#define Z_UTIL_X2_24 48 +#define Z_UTIL_X2_25 50 +#define Z_UTIL_X2_26 52 +#define Z_UTIL_X2_27 54 +#define Z_UTIL_X2_28 56 +#define Z_UTIL_X2_29 58 +#define Z_UTIL_X2_30 60 +#define Z_UTIL_X2_31 62 +#define Z_UTIL_X2_32 64 +#define Z_UTIL_X2_33 66 +#define Z_UTIL_X2_34 68 +#define Z_UTIL_X2_35 70 +#define Z_UTIL_X2_36 72 +#define Z_UTIL_X2_37 74 +#define Z_UTIL_X2_38 76 +#define Z_UTIL_X2_39 78 +#define Z_UTIL_X2_40 80 +#define Z_UTIL_X2_41 82 +#define Z_UTIL_X2_42 84 +#define Z_UTIL_X2_43 86 +#define Z_UTIL_X2_44 88 +#define Z_UTIL_X2_45 90 +#define Z_UTIL_X2_46 92 +#define Z_UTIL_X2_47 94 +#define Z_UTIL_X2_48 96 +#define Z_UTIL_X2_49 98 +#define Z_UTIL_X2_50 100 +#define Z_UTIL_X2_51 102 +#define Z_UTIL_X2_52 104 +#define Z_UTIL_X2_53 106 +#define Z_UTIL_X2_54 108 +#define Z_UTIL_X2_55 110 +#define Z_UTIL_X2_56 112 +#define Z_UTIL_X2_57 114 +#define Z_UTIL_X2_58 116 +#define Z_UTIL_X2_59 118 +#define Z_UTIL_X2_60 120 +#define Z_UTIL_X2_61 122 +#define Z_UTIL_X2_62 124 +#define Z_UTIL_X2_63 126 +#define Z_UTIL_X2_64 128 +#define Z_UTIL_X2_65 130 +#define Z_UTIL_X2_66 132 +#define Z_UTIL_X2_67 134 +#define Z_UTIL_X2_68 136 +#define Z_UTIL_X2_69 138 +#define Z_UTIL_X2_70 140 +#define Z_UTIL_X2_71 142 +#define Z_UTIL_X2_72 144 +#define Z_UTIL_X2_73 146 +#define Z_UTIL_X2_74 148 +#define Z_UTIL_X2_75 150 +#define Z_UTIL_X2_76 152 +#define Z_UTIL_X2_77 154 +#define Z_UTIL_X2_78 156 +#define Z_UTIL_X2_79 158 +#define Z_UTIL_X2_80 160 +#define Z_UTIL_X2_81 162 +#define Z_UTIL_X2_82 164 +#define Z_UTIL_X2_83 166 +#define Z_UTIL_X2_84 168 +#define Z_UTIL_X2_85 170 +#define Z_UTIL_X2_86 172 +#define Z_UTIL_X2_87 174 +#define Z_UTIL_X2_88 176 +#define Z_UTIL_X2_89 178 +#define Z_UTIL_X2_90 180 +#define Z_UTIL_X2_91 182 +#define Z_UTIL_X2_92 184 +#define Z_UTIL_X2_93 186 +#define Z_UTIL_X2_94 188 +#define Z_UTIL_X2_95 190 +#define Z_UTIL_X2_96 192 +#define Z_UTIL_X2_97 194 +#define Z_UTIL_X2_98 196 +#define Z_UTIL_X2_99 198 +#define Z_UTIL_X2_100 200 +#define Z_UTIL_X2_101 202 +#define Z_UTIL_X2_102 204 +#define Z_UTIL_X2_103 206 +#define Z_UTIL_X2_104 208 +#define Z_UTIL_X2_105 210 +#define Z_UTIL_X2_106 212 +#define Z_UTIL_X2_107 214 +#define Z_UTIL_X2_108 216 +#define Z_UTIL_X2_109 218 +#define Z_UTIL_X2_110 220 +#define Z_UTIL_X2_111 222 +#define Z_UTIL_X2_112 224 +#define Z_UTIL_X2_113 226 +#define Z_UTIL_X2_114 228 +#define Z_UTIL_X2_115 230 +#define Z_UTIL_X2_116 232 +#define Z_UTIL_X2_117 234 +#define Z_UTIL_X2_118 236 +#define Z_UTIL_X2_119 238 +#define Z_UTIL_X2_120 240 +#define Z_UTIL_X2_121 242 +#define Z_UTIL_X2_122 244 +#define Z_UTIL_X2_123 246 +#define Z_UTIL_X2_124 248 +#define Z_UTIL_X2_125 250 +#define Z_UTIL_X2_126 252 +#define Z_UTIL_X2_127 254 +#define Z_UTIL_X2_128 256 +#define Z_UTIL_X2_129 258 +#define Z_UTIL_X2_130 260 +#define Z_UTIL_X2_131 262 +#define Z_UTIL_X2_132 264 +#define Z_UTIL_X2_133 266 +#define Z_UTIL_X2_134 268 +#define Z_UTIL_X2_135 270 +#define Z_UTIL_X2_136 272 +#define Z_UTIL_X2_137 274 +#define Z_UTIL_X2_138 276 +#define Z_UTIL_X2_139 278 +#define Z_UTIL_X2_140 280 +#define Z_UTIL_X2_141 282 +#define Z_UTIL_X2_142 284 +#define Z_UTIL_X2_143 286 +#define Z_UTIL_X2_144 288 +#define Z_UTIL_X2_145 290 +#define Z_UTIL_X2_146 292 +#define Z_UTIL_X2_147 294 +#define Z_UTIL_X2_148 296 +#define Z_UTIL_X2_149 298 +#define Z_UTIL_X2_150 300 +#define Z_UTIL_X2_151 302 +#define Z_UTIL_X2_152 304 +#define Z_UTIL_X2_153 306 +#define Z_UTIL_X2_154 308 +#define Z_UTIL_X2_155 310 +#define Z_UTIL_X2_156 312 +#define Z_UTIL_X2_157 314 +#define Z_UTIL_X2_158 316 +#define Z_UTIL_X2_159 318 +#define Z_UTIL_X2_160 320 +#define Z_UTIL_X2_161 322 +#define Z_UTIL_X2_162 324 +#define Z_UTIL_X2_163 326 +#define Z_UTIL_X2_164 328 +#define Z_UTIL_X2_165 330 +#define Z_UTIL_X2_166 332 +#define Z_UTIL_X2_167 334 +#define Z_UTIL_X2_168 336 +#define Z_UTIL_X2_169 338 +#define Z_UTIL_X2_170 340 +#define Z_UTIL_X2_171 342 +#define Z_UTIL_X2_172 344 +#define Z_UTIL_X2_173 346 +#define Z_UTIL_X2_174 348 +#define Z_UTIL_X2_175 350 +#define Z_UTIL_X2_176 352 +#define Z_UTIL_X2_177 354 +#define Z_UTIL_X2_178 356 +#define Z_UTIL_X2_179 358 +#define Z_UTIL_X2_180 360 +#define Z_UTIL_X2_181 362 +#define Z_UTIL_X2_182 364 +#define Z_UTIL_X2_183 366 +#define Z_UTIL_X2_184 368 +#define Z_UTIL_X2_185 370 +#define Z_UTIL_X2_186 372 +#define Z_UTIL_X2_187 374 +#define Z_UTIL_X2_188 376 +#define Z_UTIL_X2_189 378 +#define Z_UTIL_X2_190 380 +#define Z_UTIL_X2_191 382 +#define Z_UTIL_X2_192 384 +#define Z_UTIL_X2_193 386 +#define Z_UTIL_X2_194 388 +#define Z_UTIL_X2_195 390 +#define Z_UTIL_X2_196 392 +#define Z_UTIL_X2_197 394 +#define Z_UTIL_X2_198 396 +#define Z_UTIL_X2_199 398 +#define Z_UTIL_X2_200 400 +#define Z_UTIL_X2_201 402 +#define Z_UTIL_X2_202 404 +#define Z_UTIL_X2_203 406 +#define Z_UTIL_X2_204 408 +#define Z_UTIL_X2_205 410 +#define Z_UTIL_X2_206 412 +#define Z_UTIL_X2_207 414 +#define Z_UTIL_X2_208 416 +#define Z_UTIL_X2_209 418 +#define Z_UTIL_X2_210 420 +#define Z_UTIL_X2_211 422 +#define Z_UTIL_X2_212 424 +#define Z_UTIL_X2_213 426 +#define Z_UTIL_X2_214 428 +#define Z_UTIL_X2_215 430 +#define Z_UTIL_X2_216 432 +#define Z_UTIL_X2_217 434 +#define Z_UTIL_X2_218 436 +#define Z_UTIL_X2_219 438 +#define Z_UTIL_X2_220 440 +#define Z_UTIL_X2_221 442 +#define Z_UTIL_X2_222 444 +#define Z_UTIL_X2_223 446 +#define Z_UTIL_X2_224 448 +#define Z_UTIL_X2_225 450 +#define Z_UTIL_X2_226 452 +#define Z_UTIL_X2_227 454 +#define Z_UTIL_X2_228 456 +#define Z_UTIL_X2_229 458 +#define Z_UTIL_X2_230 460 +#define Z_UTIL_X2_231 462 +#define Z_UTIL_X2_232 464 +#define Z_UTIL_X2_233 466 +#define Z_UTIL_X2_234 468 +#define Z_UTIL_X2_235 470 +#define Z_UTIL_X2_236 472 +#define Z_UTIL_X2_237 474 +#define Z_UTIL_X2_238 476 +#define Z_UTIL_X2_239 478 +#define Z_UTIL_X2_240 480 +#define Z_UTIL_X2_241 482 +#define Z_UTIL_X2_242 484 +#define Z_UTIL_X2_243 486 +#define Z_UTIL_X2_244 488 +#define Z_UTIL_X2_245 490 +#define Z_UTIL_X2_246 492 +#define Z_UTIL_X2_247 494 +#define Z_UTIL_X2_248 496 +#define Z_UTIL_X2_249 498 +#define Z_UTIL_X2_250 500 +#define Z_UTIL_X2_251 502 +#define Z_UTIL_X2_252 504 +#define Z_UTIL_X2_253 506 +#define Z_UTIL_X2_254 508 +#define Z_UTIL_X2_255 510 +#define Z_UTIL_X2_256 512 +#define Z_UTIL_X2_257 514 +#define Z_UTIL_X2_258 516 +#define Z_UTIL_X2_259 518 +#define Z_UTIL_X2_260 520 +#define Z_UTIL_X2_261 522 +#define Z_UTIL_X2_262 524 +#define Z_UTIL_X2_263 526 +#define Z_UTIL_X2_264 528 +#define Z_UTIL_X2_265 530 +#define Z_UTIL_X2_266 532 +#define Z_UTIL_X2_267 534 +#define Z_UTIL_X2_268 536 +#define Z_UTIL_X2_269 538 +#define Z_UTIL_X2_270 540 +#define Z_UTIL_X2_271 542 +#define Z_UTIL_X2_272 544 +#define Z_UTIL_X2_273 546 +#define Z_UTIL_X2_274 548 +#define Z_UTIL_X2_275 550 +#define Z_UTIL_X2_276 552 +#define Z_UTIL_X2_277 554 +#define Z_UTIL_X2_278 556 +#define Z_UTIL_X2_279 558 +#define Z_UTIL_X2_280 560 +#define Z_UTIL_X2_281 562 +#define Z_UTIL_X2_282 564 +#define Z_UTIL_X2_283 566 +#define Z_UTIL_X2_284 568 +#define Z_UTIL_X2_285 570 +#define Z_UTIL_X2_286 572 +#define Z_UTIL_X2_287 574 +#define Z_UTIL_X2_288 576 +#define Z_UTIL_X2_289 578 +#define Z_UTIL_X2_290 580 +#define Z_UTIL_X2_291 582 +#define Z_UTIL_X2_292 584 +#define Z_UTIL_X2_293 586 +#define Z_UTIL_X2_294 588 +#define Z_UTIL_X2_295 590 +#define Z_UTIL_X2_296 592 +#define Z_UTIL_X2_297 594 +#define Z_UTIL_X2_298 596 +#define Z_UTIL_X2_299 598 +#define Z_UTIL_X2_300 600 +#define Z_UTIL_X2_301 602 +#define Z_UTIL_X2_302 604 +#define Z_UTIL_X2_303 606 +#define Z_UTIL_X2_304 608 +#define Z_UTIL_X2_305 610 +#define Z_UTIL_X2_306 612 +#define Z_UTIL_X2_307 614 +#define Z_UTIL_X2_308 616 +#define Z_UTIL_X2_309 618 +#define Z_UTIL_X2_310 620 +#define Z_UTIL_X2_311 622 +#define Z_UTIL_X2_312 624 +#define Z_UTIL_X2_313 626 +#define Z_UTIL_X2_314 628 +#define Z_UTIL_X2_315 630 +#define Z_UTIL_X2_316 632 +#define Z_UTIL_X2_317 634 +#define Z_UTIL_X2_318 636 +#define Z_UTIL_X2_319 638 +#define Z_UTIL_X2_320 640 +#define Z_UTIL_X2_321 642 +#define Z_UTIL_X2_322 644 +#define Z_UTIL_X2_323 646 +#define Z_UTIL_X2_324 648 +#define Z_UTIL_X2_325 650 +#define Z_UTIL_X2_326 652 +#define Z_UTIL_X2_327 654 +#define Z_UTIL_X2_328 656 +#define Z_UTIL_X2_329 658 +#define Z_UTIL_X2_330 660 +#define Z_UTIL_X2_331 662 +#define Z_UTIL_X2_332 664 +#define Z_UTIL_X2_333 666 +#define Z_UTIL_X2_334 668 +#define Z_UTIL_X2_335 670 +#define Z_UTIL_X2_336 672 +#define Z_UTIL_X2_337 674 +#define Z_UTIL_X2_338 676 +#define Z_UTIL_X2_339 678 +#define Z_UTIL_X2_340 680 +#define Z_UTIL_X2_341 682 +#define Z_UTIL_X2_342 684 +#define Z_UTIL_X2_343 686 +#define Z_UTIL_X2_344 688 +#define Z_UTIL_X2_345 690 +#define Z_UTIL_X2_346 692 +#define Z_UTIL_X2_347 694 +#define Z_UTIL_X2_348 696 +#define Z_UTIL_X2_349 698 +#define Z_UTIL_X2_350 700 +#define Z_UTIL_X2_351 702 +#define Z_UTIL_X2_352 704 +#define Z_UTIL_X2_353 706 +#define Z_UTIL_X2_354 708 +#define Z_UTIL_X2_355 710 +#define Z_UTIL_X2_356 712 +#define Z_UTIL_X2_357 714 +#define Z_UTIL_X2_358 716 +#define Z_UTIL_X2_359 718 +#define Z_UTIL_X2_360 720 +#define Z_UTIL_X2_361 722 +#define Z_UTIL_X2_362 724 +#define Z_UTIL_X2_363 726 +#define Z_UTIL_X2_364 728 +#define Z_UTIL_X2_365 730 +#define Z_UTIL_X2_366 732 +#define Z_UTIL_X2_367 734 +#define Z_UTIL_X2_368 736 +#define Z_UTIL_X2_369 738 +#define Z_UTIL_X2_370 740 +#define Z_UTIL_X2_371 742 +#define Z_UTIL_X2_372 744 +#define Z_UTIL_X2_373 746 +#define Z_UTIL_X2_374 748 +#define Z_UTIL_X2_375 750 +#define Z_UTIL_X2_376 752 +#define Z_UTIL_X2_377 754 +#define Z_UTIL_X2_378 756 +#define Z_UTIL_X2_379 758 +#define Z_UTIL_X2_380 760 +#define Z_UTIL_X2_381 762 +#define Z_UTIL_X2_382 764 +#define Z_UTIL_X2_383 766 +#define Z_UTIL_X2_384 768 +#define Z_UTIL_X2_385 770 +#define Z_UTIL_X2_386 772 +#define Z_UTIL_X2_387 774 +#define Z_UTIL_X2_388 776 +#define Z_UTIL_X2_389 778 +#define Z_UTIL_X2_390 780 +#define Z_UTIL_X2_391 782 +#define Z_UTIL_X2_392 784 +#define Z_UTIL_X2_393 786 +#define Z_UTIL_X2_394 788 +#define Z_UTIL_X2_395 790 +#define Z_UTIL_X2_396 792 +#define Z_UTIL_X2_397 794 +#define Z_UTIL_X2_398 796 +#define Z_UTIL_X2_399 798 +#define Z_UTIL_X2_400 800 +#define Z_UTIL_X2_401 802 +#define Z_UTIL_X2_402 804 +#define Z_UTIL_X2_403 806 +#define Z_UTIL_X2_404 808 +#define Z_UTIL_X2_405 810 +#define Z_UTIL_X2_406 812 +#define Z_UTIL_X2_407 814 +#define Z_UTIL_X2_408 816 +#define Z_UTIL_X2_409 818 +#define Z_UTIL_X2_410 820 +#define Z_UTIL_X2_411 822 +#define Z_UTIL_X2_412 824 +#define Z_UTIL_X2_413 826 +#define Z_UTIL_X2_414 828 +#define Z_UTIL_X2_415 830 +#define Z_UTIL_X2_416 832 +#define Z_UTIL_X2_417 834 +#define Z_UTIL_X2_418 836 +#define Z_UTIL_X2_419 838 +#define Z_UTIL_X2_420 840 +#define Z_UTIL_X2_421 842 +#define Z_UTIL_X2_422 844 +#define Z_UTIL_X2_423 846 +#define Z_UTIL_X2_424 848 +#define Z_UTIL_X2_425 850 +#define Z_UTIL_X2_426 852 +#define Z_UTIL_X2_427 854 +#define Z_UTIL_X2_428 856 +#define Z_UTIL_X2_429 858 +#define Z_UTIL_X2_430 860 +#define Z_UTIL_X2_431 862 +#define Z_UTIL_X2_432 864 +#define Z_UTIL_X2_433 866 +#define Z_UTIL_X2_434 868 +#define Z_UTIL_X2_435 870 +#define Z_UTIL_X2_436 872 +#define Z_UTIL_X2_437 874 +#define Z_UTIL_X2_438 876 +#define Z_UTIL_X2_439 878 +#define Z_UTIL_X2_440 880 +#define Z_UTIL_X2_441 882 +#define Z_UTIL_X2_442 884 +#define Z_UTIL_X2_443 886 +#define Z_UTIL_X2_444 888 +#define Z_UTIL_X2_445 890 +#define Z_UTIL_X2_446 892 +#define Z_UTIL_X2_447 894 +#define Z_UTIL_X2_448 896 +#define Z_UTIL_X2_449 898 +#define Z_UTIL_X2_450 900 +#define Z_UTIL_X2_451 902 +#define Z_UTIL_X2_452 904 +#define Z_UTIL_X2_453 906 +#define Z_UTIL_X2_454 908 +#define Z_UTIL_X2_455 910 +#define Z_UTIL_X2_456 912 +#define Z_UTIL_X2_457 914 +#define Z_UTIL_X2_458 916 +#define Z_UTIL_X2_459 918 +#define Z_UTIL_X2_460 920 +#define Z_UTIL_X2_461 922 +#define Z_UTIL_X2_462 924 +#define Z_UTIL_X2_463 926 +#define Z_UTIL_X2_464 928 +#define Z_UTIL_X2_465 930 +#define Z_UTIL_X2_466 932 +#define Z_UTIL_X2_467 934 +#define Z_UTIL_X2_468 936 +#define Z_UTIL_X2_469 938 +#define Z_UTIL_X2_470 940 +#define Z_UTIL_X2_471 942 +#define Z_UTIL_X2_472 944 +#define Z_UTIL_X2_473 946 +#define Z_UTIL_X2_474 948 +#define Z_UTIL_X2_475 950 +#define Z_UTIL_X2_476 952 +#define Z_UTIL_X2_477 954 +#define Z_UTIL_X2_478 956 +#define Z_UTIL_X2_479 958 +#define Z_UTIL_X2_480 960 +#define Z_UTIL_X2_481 962 +#define Z_UTIL_X2_482 964 +#define Z_UTIL_X2_483 966 +#define Z_UTIL_X2_484 968 +#define Z_UTIL_X2_485 970 +#define Z_UTIL_X2_486 972 +#define Z_UTIL_X2_487 974 +#define Z_UTIL_X2_488 976 +#define Z_UTIL_X2_489 978 +#define Z_UTIL_X2_490 980 +#define Z_UTIL_X2_491 982 +#define Z_UTIL_X2_492 984 +#define Z_UTIL_X2_493 986 +#define Z_UTIL_X2_494 988 +#define Z_UTIL_X2_495 990 +#define Z_UTIL_X2_496 992 +#define Z_UTIL_X2_497 994 +#define Z_UTIL_X2_498 996 +#define Z_UTIL_X2_499 998 +#define Z_UTIL_X2_500 1000 +#define Z_UTIL_X2_501 1002 +#define Z_UTIL_X2_502 1004 +#define Z_UTIL_X2_503 1006 +#define Z_UTIL_X2_504 1008 +#define Z_UTIL_X2_505 1010 +#define Z_UTIL_X2_506 1012 +#define Z_UTIL_X2_507 1014 +#define Z_UTIL_X2_508 1016 +#define Z_UTIL_X2_509 1018 +#define Z_UTIL_X2_510 1020 +#define Z_UTIL_X2_511 1022 +#define Z_UTIL_X2_512 1024 +#define Z_UTIL_X2_513 1026 +#define Z_UTIL_X2_514 1028 +#define Z_UTIL_X2_515 1030 +#define Z_UTIL_X2_516 1032 +#define Z_UTIL_X2_517 1034 +#define Z_UTIL_X2_518 1036 +#define Z_UTIL_X2_519 1038 +#define Z_UTIL_X2_520 1040 +#define Z_UTIL_X2_521 1042 +#define Z_UTIL_X2_522 1044 +#define Z_UTIL_X2_523 1046 +#define Z_UTIL_X2_524 1048 +#define Z_UTIL_X2_525 1050 +#define Z_UTIL_X2_526 1052 +#define Z_UTIL_X2_527 1054 +#define Z_UTIL_X2_528 1056 +#define Z_UTIL_X2_529 1058 +#define Z_UTIL_X2_530 1060 +#define Z_UTIL_X2_531 1062 +#define Z_UTIL_X2_532 1064 +#define Z_UTIL_X2_533 1066 +#define Z_UTIL_X2_534 1068 +#define Z_UTIL_X2_535 1070 +#define Z_UTIL_X2_536 1072 +#define Z_UTIL_X2_537 1074 +#define Z_UTIL_X2_538 1076 +#define Z_UTIL_X2_539 1078 +#define Z_UTIL_X2_540 1080 +#define Z_UTIL_X2_541 1082 +#define Z_UTIL_X2_542 1084 +#define Z_UTIL_X2_543 1086 +#define Z_UTIL_X2_544 1088 +#define Z_UTIL_X2_545 1090 +#define Z_UTIL_X2_546 1092 +#define Z_UTIL_X2_547 1094 +#define Z_UTIL_X2_548 1096 +#define Z_UTIL_X2_549 1098 +#define Z_UTIL_X2_550 1100 +#define Z_UTIL_X2_551 1102 +#define Z_UTIL_X2_552 1104 +#define Z_UTIL_X2_553 1106 +#define Z_UTIL_X2_554 1108 +#define Z_UTIL_X2_555 1110 +#define Z_UTIL_X2_556 1112 +#define Z_UTIL_X2_557 1114 +#define Z_UTIL_X2_558 1116 +#define Z_UTIL_X2_559 1118 +#define Z_UTIL_X2_560 1120 +#define Z_UTIL_X2_561 1122 +#define Z_UTIL_X2_562 1124 +#define Z_UTIL_X2_563 1126 +#define Z_UTIL_X2_564 1128 +#define Z_UTIL_X2_565 1130 +#define Z_UTIL_X2_566 1132 +#define Z_UTIL_X2_567 1134 +#define Z_UTIL_X2_568 1136 +#define Z_UTIL_X2_569 1138 +#define Z_UTIL_X2_570 1140 +#define Z_UTIL_X2_571 1142 +#define Z_UTIL_X2_572 1144 +#define Z_UTIL_X2_573 1146 +#define Z_UTIL_X2_574 1148 +#define Z_UTIL_X2_575 1150 +#define Z_UTIL_X2_576 1152 +#define Z_UTIL_X2_577 1154 +#define Z_UTIL_X2_578 1156 +#define Z_UTIL_X2_579 1158 +#define Z_UTIL_X2_580 1160 +#define Z_UTIL_X2_581 1162 +#define Z_UTIL_X2_582 1164 +#define Z_UTIL_X2_583 1166 +#define Z_UTIL_X2_584 1168 +#define Z_UTIL_X2_585 1170 +#define Z_UTIL_X2_586 1172 +#define Z_UTIL_X2_587 1174 +#define Z_UTIL_X2_588 1176 +#define Z_UTIL_X2_589 1178 +#define Z_UTIL_X2_590 1180 +#define Z_UTIL_X2_591 1182 +#define Z_UTIL_X2_592 1184 +#define Z_UTIL_X2_593 1186 +#define Z_UTIL_X2_594 1188 +#define Z_UTIL_X2_595 1190 +#define Z_UTIL_X2_596 1192 +#define Z_UTIL_X2_597 1194 +#define Z_UTIL_X2_598 1196 +#define Z_UTIL_X2_599 1198 +#define Z_UTIL_X2_600 1200 +#define Z_UTIL_X2_601 1202 +#define Z_UTIL_X2_602 1204 +#define Z_UTIL_X2_603 1206 +#define Z_UTIL_X2_604 1208 +#define Z_UTIL_X2_605 1210 +#define Z_UTIL_X2_606 1212 +#define Z_UTIL_X2_607 1214 +#define Z_UTIL_X2_608 1216 +#define Z_UTIL_X2_609 1218 +#define Z_UTIL_X2_610 1220 +#define Z_UTIL_X2_611 1222 +#define Z_UTIL_X2_612 1224 +#define Z_UTIL_X2_613 1226 +#define Z_UTIL_X2_614 1228 +#define Z_UTIL_X2_615 1230 +#define Z_UTIL_X2_616 1232 +#define Z_UTIL_X2_617 1234 +#define Z_UTIL_X2_618 1236 +#define Z_UTIL_X2_619 1238 +#define Z_UTIL_X2_620 1240 +#define Z_UTIL_X2_621 1242 +#define Z_UTIL_X2_622 1244 +#define Z_UTIL_X2_623 1246 +#define Z_UTIL_X2_624 1248 +#define Z_UTIL_X2_625 1250 +#define Z_UTIL_X2_626 1252 +#define Z_UTIL_X2_627 1254 +#define Z_UTIL_X2_628 1256 +#define Z_UTIL_X2_629 1258 +#define Z_UTIL_X2_630 1260 +#define Z_UTIL_X2_631 1262 +#define Z_UTIL_X2_632 1264 +#define Z_UTIL_X2_633 1266 +#define Z_UTIL_X2_634 1268 +#define Z_UTIL_X2_635 1270 +#define Z_UTIL_X2_636 1272 +#define Z_UTIL_X2_637 1274 +#define Z_UTIL_X2_638 1276 +#define Z_UTIL_X2_639 1278 +#define Z_UTIL_X2_640 1280 +#define Z_UTIL_X2_641 1282 +#define Z_UTIL_X2_642 1284 +#define Z_UTIL_X2_643 1286 +#define Z_UTIL_X2_644 1288 +#define Z_UTIL_X2_645 1290 +#define Z_UTIL_X2_646 1292 +#define Z_UTIL_X2_647 1294 +#define Z_UTIL_X2_648 1296 +#define Z_UTIL_X2_649 1298 +#define Z_UTIL_X2_650 1300 +#define Z_UTIL_X2_651 1302 +#define Z_UTIL_X2_652 1304 +#define Z_UTIL_X2_653 1306 +#define Z_UTIL_X2_654 1308 +#define Z_UTIL_X2_655 1310 +#define Z_UTIL_X2_656 1312 +#define Z_UTIL_X2_657 1314 +#define Z_UTIL_X2_658 1316 +#define Z_UTIL_X2_659 1318 +#define Z_UTIL_X2_660 1320 +#define Z_UTIL_X2_661 1322 +#define Z_UTIL_X2_662 1324 +#define Z_UTIL_X2_663 1326 +#define Z_UTIL_X2_664 1328 +#define Z_UTIL_X2_665 1330 +#define Z_UTIL_X2_666 1332 +#define Z_UTIL_X2_667 1334 +#define Z_UTIL_X2_668 1336 +#define Z_UTIL_X2_669 1338 +#define Z_UTIL_X2_670 1340 +#define Z_UTIL_X2_671 1342 +#define Z_UTIL_X2_672 1344 +#define Z_UTIL_X2_673 1346 +#define Z_UTIL_X2_674 1348 +#define Z_UTIL_X2_675 1350 +#define Z_UTIL_X2_676 1352 +#define Z_UTIL_X2_677 1354 +#define Z_UTIL_X2_678 1356 +#define Z_UTIL_X2_679 1358 +#define Z_UTIL_X2_680 1360 +#define Z_UTIL_X2_681 1362 +#define Z_UTIL_X2_682 1364 +#define Z_UTIL_X2_683 1366 +#define Z_UTIL_X2_684 1368 +#define Z_UTIL_X2_685 1370 +#define Z_UTIL_X2_686 1372 +#define Z_UTIL_X2_687 1374 +#define Z_UTIL_X2_688 1376 +#define Z_UTIL_X2_689 1378 +#define Z_UTIL_X2_690 1380 +#define Z_UTIL_X2_691 1382 +#define Z_UTIL_X2_692 1384 +#define Z_UTIL_X2_693 1386 +#define Z_UTIL_X2_694 1388 +#define Z_UTIL_X2_695 1390 +#define Z_UTIL_X2_696 1392 +#define Z_UTIL_X2_697 1394 +#define Z_UTIL_X2_698 1396 +#define Z_UTIL_X2_699 1398 +#define Z_UTIL_X2_700 1400 +#define Z_UTIL_X2_701 1402 +#define Z_UTIL_X2_702 1404 +#define Z_UTIL_X2_703 1406 +#define Z_UTIL_X2_704 1408 +#define Z_UTIL_X2_705 1410 +#define Z_UTIL_X2_706 1412 +#define Z_UTIL_X2_707 1414 +#define Z_UTIL_X2_708 1416 +#define Z_UTIL_X2_709 1418 +#define Z_UTIL_X2_710 1420 +#define Z_UTIL_X2_711 1422 +#define Z_UTIL_X2_712 1424 +#define Z_UTIL_X2_713 1426 +#define Z_UTIL_X2_714 1428 +#define Z_UTIL_X2_715 1430 +#define Z_UTIL_X2_716 1432 +#define Z_UTIL_X2_717 1434 +#define Z_UTIL_X2_718 1436 +#define Z_UTIL_X2_719 1438 +#define Z_UTIL_X2_720 1440 +#define Z_UTIL_X2_721 1442 +#define Z_UTIL_X2_722 1444 +#define Z_UTIL_X2_723 1446 +#define Z_UTIL_X2_724 1448 +#define Z_UTIL_X2_725 1450 +#define Z_UTIL_X2_726 1452 +#define Z_UTIL_X2_727 1454 +#define Z_UTIL_X2_728 1456 +#define Z_UTIL_X2_729 1458 +#define Z_UTIL_X2_730 1460 +#define Z_UTIL_X2_731 1462 +#define Z_UTIL_X2_732 1464 +#define Z_UTIL_X2_733 1466 +#define Z_UTIL_X2_734 1468 +#define Z_UTIL_X2_735 1470 +#define Z_UTIL_X2_736 1472 +#define Z_UTIL_X2_737 1474 +#define Z_UTIL_X2_738 1476 +#define Z_UTIL_X2_739 1478 +#define Z_UTIL_X2_740 1480 +#define Z_UTIL_X2_741 1482 +#define Z_UTIL_X2_742 1484 +#define Z_UTIL_X2_743 1486 +#define Z_UTIL_X2_744 1488 +#define Z_UTIL_X2_745 1490 +#define Z_UTIL_X2_746 1492 +#define Z_UTIL_X2_747 1494 +#define Z_UTIL_X2_748 1496 +#define Z_UTIL_X2_749 1498 +#define Z_UTIL_X2_750 1500 +#define Z_UTIL_X2_751 1502 +#define Z_UTIL_X2_752 1504 +#define Z_UTIL_X2_753 1506 +#define Z_UTIL_X2_754 1508 +#define Z_UTIL_X2_755 1510 +#define Z_UTIL_X2_756 1512 +#define Z_UTIL_X2_757 1514 +#define Z_UTIL_X2_758 1516 +#define Z_UTIL_X2_759 1518 +#define Z_UTIL_X2_760 1520 +#define Z_UTIL_X2_761 1522 +#define Z_UTIL_X2_762 1524 +#define Z_UTIL_X2_763 1526 +#define Z_UTIL_X2_764 1528 +#define Z_UTIL_X2_765 1530 +#define Z_UTIL_X2_766 1532 +#define Z_UTIL_X2_767 1534 +#define Z_UTIL_X2_768 1536 +#define Z_UTIL_X2_769 1538 +#define Z_UTIL_X2_770 1540 +#define Z_UTIL_X2_771 1542 +#define Z_UTIL_X2_772 1544 +#define Z_UTIL_X2_773 1546 +#define Z_UTIL_X2_774 1548 +#define Z_UTIL_X2_775 1550 +#define Z_UTIL_X2_776 1552 +#define Z_UTIL_X2_777 1554 +#define Z_UTIL_X2_778 1556 +#define Z_UTIL_X2_779 1558 +#define Z_UTIL_X2_780 1560 +#define Z_UTIL_X2_781 1562 +#define Z_UTIL_X2_782 1564 +#define Z_UTIL_X2_783 1566 +#define Z_UTIL_X2_784 1568 +#define Z_UTIL_X2_785 1570 +#define Z_UTIL_X2_786 1572 +#define Z_UTIL_X2_787 1574 +#define Z_UTIL_X2_788 1576 +#define Z_UTIL_X2_789 1578 +#define Z_UTIL_X2_790 1580 +#define Z_UTIL_X2_791 1582 +#define Z_UTIL_X2_792 1584 +#define Z_UTIL_X2_793 1586 +#define Z_UTIL_X2_794 1588 +#define Z_UTIL_X2_795 1590 +#define Z_UTIL_X2_796 1592 +#define Z_UTIL_X2_797 1594 +#define Z_UTIL_X2_798 1596 +#define Z_UTIL_X2_799 1598 +#define Z_UTIL_X2_800 1600 +#define Z_UTIL_X2_801 1602 +#define Z_UTIL_X2_802 1604 +#define Z_UTIL_X2_803 1606 +#define Z_UTIL_X2_804 1608 +#define Z_UTIL_X2_805 1610 +#define Z_UTIL_X2_806 1612 +#define Z_UTIL_X2_807 1614 +#define Z_UTIL_X2_808 1616 +#define Z_UTIL_X2_809 1618 +#define Z_UTIL_X2_810 1620 +#define Z_UTIL_X2_811 1622 +#define Z_UTIL_X2_812 1624 +#define Z_UTIL_X2_813 1626 +#define Z_UTIL_X2_814 1628 +#define Z_UTIL_X2_815 1630 +#define Z_UTIL_X2_816 1632 +#define Z_UTIL_X2_817 1634 +#define Z_UTIL_X2_818 1636 +#define Z_UTIL_X2_819 1638 +#define Z_UTIL_X2_820 1640 +#define Z_UTIL_X2_821 1642 +#define Z_UTIL_X2_822 1644 +#define Z_UTIL_X2_823 1646 +#define Z_UTIL_X2_824 1648 +#define Z_UTIL_X2_825 1650 +#define Z_UTIL_X2_826 1652 +#define Z_UTIL_X2_827 1654 +#define Z_UTIL_X2_828 1656 +#define Z_UTIL_X2_829 1658 +#define Z_UTIL_X2_830 1660 +#define Z_UTIL_X2_831 1662 +#define Z_UTIL_X2_832 1664 +#define Z_UTIL_X2_833 1666 +#define Z_UTIL_X2_834 1668 +#define Z_UTIL_X2_835 1670 +#define Z_UTIL_X2_836 1672 +#define Z_UTIL_X2_837 1674 +#define Z_UTIL_X2_838 1676 +#define Z_UTIL_X2_839 1678 +#define Z_UTIL_X2_840 1680 +#define Z_UTIL_X2_841 1682 +#define Z_UTIL_X2_842 1684 +#define Z_UTIL_X2_843 1686 +#define Z_UTIL_X2_844 1688 +#define Z_UTIL_X2_845 1690 +#define Z_UTIL_X2_846 1692 +#define Z_UTIL_X2_847 1694 +#define Z_UTIL_X2_848 1696 +#define Z_UTIL_X2_849 1698 +#define Z_UTIL_X2_850 1700 +#define Z_UTIL_X2_851 1702 +#define Z_UTIL_X2_852 1704 +#define Z_UTIL_X2_853 1706 +#define Z_UTIL_X2_854 1708 +#define Z_UTIL_X2_855 1710 +#define Z_UTIL_X2_856 1712 +#define Z_UTIL_X2_857 1714 +#define Z_UTIL_X2_858 1716 +#define Z_UTIL_X2_859 1718 +#define Z_UTIL_X2_860 1720 +#define Z_UTIL_X2_861 1722 +#define Z_UTIL_X2_862 1724 +#define Z_UTIL_X2_863 1726 +#define Z_UTIL_X2_864 1728 +#define Z_UTIL_X2_865 1730 +#define Z_UTIL_X2_866 1732 +#define Z_UTIL_X2_867 1734 +#define Z_UTIL_X2_868 1736 +#define Z_UTIL_X2_869 1738 +#define Z_UTIL_X2_870 1740 +#define Z_UTIL_X2_871 1742 +#define Z_UTIL_X2_872 1744 +#define Z_UTIL_X2_873 1746 +#define Z_UTIL_X2_874 1748 +#define Z_UTIL_X2_875 1750 +#define Z_UTIL_X2_876 1752 +#define Z_UTIL_X2_877 1754 +#define Z_UTIL_X2_878 1756 +#define Z_UTIL_X2_879 1758 +#define Z_UTIL_X2_880 1760 +#define Z_UTIL_X2_881 1762 +#define Z_UTIL_X2_882 1764 +#define Z_UTIL_X2_883 1766 +#define Z_UTIL_X2_884 1768 +#define Z_UTIL_X2_885 1770 +#define Z_UTIL_X2_886 1772 +#define Z_UTIL_X2_887 1774 +#define Z_UTIL_X2_888 1776 +#define Z_UTIL_X2_889 1778 +#define Z_UTIL_X2_890 1780 +#define Z_UTIL_X2_891 1782 +#define Z_UTIL_X2_892 1784 +#define Z_UTIL_X2_893 1786 +#define Z_UTIL_X2_894 1788 +#define Z_UTIL_X2_895 1790 +#define Z_UTIL_X2_896 1792 +#define Z_UTIL_X2_897 1794 +#define Z_UTIL_X2_898 1796 +#define Z_UTIL_X2_899 1798 +#define Z_UTIL_X2_900 1800 +#define Z_UTIL_X2_901 1802 +#define Z_UTIL_X2_902 1804 +#define Z_UTIL_X2_903 1806 +#define Z_UTIL_X2_904 1808 +#define Z_UTIL_X2_905 1810 +#define Z_UTIL_X2_906 1812 +#define Z_UTIL_X2_907 1814 +#define Z_UTIL_X2_908 1816 +#define Z_UTIL_X2_909 1818 +#define Z_UTIL_X2_910 1820 +#define Z_UTIL_X2_911 1822 +#define Z_UTIL_X2_912 1824 +#define Z_UTIL_X2_913 1826 +#define Z_UTIL_X2_914 1828 +#define Z_UTIL_X2_915 1830 +#define Z_UTIL_X2_916 1832 +#define Z_UTIL_X2_917 1834 +#define Z_UTIL_X2_918 1836 +#define Z_UTIL_X2_919 1838 +#define Z_UTIL_X2_920 1840 +#define Z_UTIL_X2_921 1842 +#define Z_UTIL_X2_922 1844 +#define Z_UTIL_X2_923 1846 +#define Z_UTIL_X2_924 1848 +#define Z_UTIL_X2_925 1850 +#define Z_UTIL_X2_926 1852 +#define Z_UTIL_X2_927 1854 +#define Z_UTIL_X2_928 1856 +#define Z_UTIL_X2_929 1858 +#define Z_UTIL_X2_930 1860 +#define Z_UTIL_X2_931 1862 +#define Z_UTIL_X2_932 1864 +#define Z_UTIL_X2_933 1866 +#define Z_UTIL_X2_934 1868 +#define Z_UTIL_X2_935 1870 +#define Z_UTIL_X2_936 1872 +#define Z_UTIL_X2_937 1874 +#define Z_UTIL_X2_938 1876 +#define Z_UTIL_X2_939 1878 +#define Z_UTIL_X2_940 1880 +#define Z_UTIL_X2_941 1882 +#define Z_UTIL_X2_942 1884 +#define Z_UTIL_X2_943 1886 +#define Z_UTIL_X2_944 1888 +#define Z_UTIL_X2_945 1890 +#define Z_UTIL_X2_946 1892 +#define Z_UTIL_X2_947 1894 +#define Z_UTIL_X2_948 1896 +#define Z_UTIL_X2_949 1898 +#define Z_UTIL_X2_950 1900 +#define Z_UTIL_X2_951 1902 +#define Z_UTIL_X2_952 1904 +#define Z_UTIL_X2_953 1906 +#define Z_UTIL_X2_954 1908 +#define Z_UTIL_X2_955 1910 +#define Z_UTIL_X2_956 1912 +#define Z_UTIL_X2_957 1914 +#define Z_UTIL_X2_958 1916 +#define Z_UTIL_X2_959 1918 +#define Z_UTIL_X2_960 1920 +#define Z_UTIL_X2_961 1922 +#define Z_UTIL_X2_962 1924 +#define Z_UTIL_X2_963 1926 +#define Z_UTIL_X2_964 1928 +#define Z_UTIL_X2_965 1930 +#define Z_UTIL_X2_966 1932 +#define Z_UTIL_X2_967 1934 +#define Z_UTIL_X2_968 1936 +#define Z_UTIL_X2_969 1938 +#define Z_UTIL_X2_970 1940 +#define Z_UTIL_X2_971 1942 +#define Z_UTIL_X2_972 1944 +#define Z_UTIL_X2_973 1946 +#define Z_UTIL_X2_974 1948 +#define Z_UTIL_X2_975 1950 +#define Z_UTIL_X2_976 1952 +#define Z_UTIL_X2_977 1954 +#define Z_UTIL_X2_978 1956 +#define Z_UTIL_X2_979 1958 +#define Z_UTIL_X2_980 1960 +#define Z_UTIL_X2_981 1962 +#define Z_UTIL_X2_982 1964 +#define Z_UTIL_X2_983 1966 +#define Z_UTIL_X2_984 1968 +#define Z_UTIL_X2_985 1970 +#define Z_UTIL_X2_986 1972 +#define Z_UTIL_X2_987 1974 +#define Z_UTIL_X2_988 1976 +#define Z_UTIL_X2_989 1978 +#define Z_UTIL_X2_990 1980 +#define Z_UTIL_X2_991 1982 +#define Z_UTIL_X2_992 1984 +#define Z_UTIL_X2_993 1986 +#define Z_UTIL_X2_994 1988 +#define Z_UTIL_X2_995 1990 +#define Z_UTIL_X2_996 1992 +#define Z_UTIL_X2_997 1994 +#define Z_UTIL_X2_998 1996 +#define Z_UTIL_X2_999 1998 +#define Z_UTIL_X2_1000 2000 +#define Z_UTIL_X2_1001 2002 +#define Z_UTIL_X2_1002 2004 +#define Z_UTIL_X2_1003 2006 +#define Z_UTIL_X2_1004 2008 +#define Z_UTIL_X2_1005 2010 +#define Z_UTIL_X2_1006 2012 +#define Z_UTIL_X2_1007 2014 +#define Z_UTIL_X2_1008 2016 +#define Z_UTIL_X2_1009 2018 +#define Z_UTIL_X2_1010 2020 +#define Z_UTIL_X2_1011 2022 +#define Z_UTIL_X2_1012 2024 +#define Z_UTIL_X2_1013 2026 +#define Z_UTIL_X2_1014 2028 +#define Z_UTIL_X2_1015 2030 +#define Z_UTIL_X2_1016 2032 +#define Z_UTIL_X2_1017 2034 +#define Z_UTIL_X2_1018 2036 +#define Z_UTIL_X2_1019 2038 +#define Z_UTIL_X2_1020 2040 +#define Z_UTIL_X2_1021 2042 +#define Z_UTIL_X2_1022 2044 +#define Z_UTIL_X2_1023 2046 +#define Z_UTIL_X2_1024 2048 +#define Z_UTIL_X2_1025 2050 +#define Z_UTIL_X2_1026 2052 +#define Z_UTIL_X2_1027 2054 +#define Z_UTIL_X2_1028 2056 +#define Z_UTIL_X2_1029 2058 +#define Z_UTIL_X2_1030 2060 +#define Z_UTIL_X2_1031 2062 +#define Z_UTIL_X2_1032 2064 +#define Z_UTIL_X2_1033 2066 +#define Z_UTIL_X2_1034 2068 +#define Z_UTIL_X2_1035 2070 +#define Z_UTIL_X2_1036 2072 +#define Z_UTIL_X2_1037 2074 +#define Z_UTIL_X2_1038 2076 +#define Z_UTIL_X2_1039 2078 +#define Z_UTIL_X2_1040 2080 +#define Z_UTIL_X2_1041 2082 +#define Z_UTIL_X2_1042 2084 +#define Z_UTIL_X2_1043 2086 +#define Z_UTIL_X2_1044 2088 +#define Z_UTIL_X2_1045 2090 +#define Z_UTIL_X2_1046 2092 +#define Z_UTIL_X2_1047 2094 +#define Z_UTIL_X2_1048 2096 +#define Z_UTIL_X2_1049 2098 +#define Z_UTIL_X2_1050 2100 +#define Z_UTIL_X2_1051 2102 +#define Z_UTIL_X2_1052 2104 +#define Z_UTIL_X2_1053 2106 +#define Z_UTIL_X2_1054 2108 +#define Z_UTIL_X2_1055 2110 +#define Z_UTIL_X2_1056 2112 +#define Z_UTIL_X2_1057 2114 +#define Z_UTIL_X2_1058 2116 +#define Z_UTIL_X2_1059 2118 +#define Z_UTIL_X2_1060 2120 +#define Z_UTIL_X2_1061 2122 +#define Z_UTIL_X2_1062 2124 +#define Z_UTIL_X2_1063 2126 +#define Z_UTIL_X2_1064 2128 +#define Z_UTIL_X2_1065 2130 +#define Z_UTIL_X2_1066 2132 +#define Z_UTIL_X2_1067 2134 +#define Z_UTIL_X2_1068 2136 +#define Z_UTIL_X2_1069 2138 +#define Z_UTIL_X2_1070 2140 +#define Z_UTIL_X2_1071 2142 +#define Z_UTIL_X2_1072 2144 +#define Z_UTIL_X2_1073 2146 +#define Z_UTIL_X2_1074 2148 +#define Z_UTIL_X2_1075 2150 +#define Z_UTIL_X2_1076 2152 +#define Z_UTIL_X2_1077 2154 +#define Z_UTIL_X2_1078 2156 +#define Z_UTIL_X2_1079 2158 +#define Z_UTIL_X2_1080 2160 +#define Z_UTIL_X2_1081 2162 +#define Z_UTIL_X2_1082 2164 +#define Z_UTIL_X2_1083 2166 +#define Z_UTIL_X2_1084 2168 +#define Z_UTIL_X2_1085 2170 +#define Z_UTIL_X2_1086 2172 +#define Z_UTIL_X2_1087 2174 +#define Z_UTIL_X2_1088 2176 +#define Z_UTIL_X2_1089 2178 +#define Z_UTIL_X2_1090 2180 +#define Z_UTIL_X2_1091 2182 +#define Z_UTIL_X2_1092 2184 +#define Z_UTIL_X2_1093 2186 +#define Z_UTIL_X2_1094 2188 +#define Z_UTIL_X2_1095 2190 +#define Z_UTIL_X2_1096 2192 +#define Z_UTIL_X2_1097 2194 +#define Z_UTIL_X2_1098 2196 +#define Z_UTIL_X2_1099 2198 +#define Z_UTIL_X2_1100 2200 +#define Z_UTIL_X2_1101 2202 +#define Z_UTIL_X2_1102 2204 +#define Z_UTIL_X2_1103 2206 +#define Z_UTIL_X2_1104 2208 +#define Z_UTIL_X2_1105 2210 +#define Z_UTIL_X2_1106 2212 +#define Z_UTIL_X2_1107 2214 +#define Z_UTIL_X2_1108 2216 +#define Z_UTIL_X2_1109 2218 +#define Z_UTIL_X2_1110 2220 +#define Z_UTIL_X2_1111 2222 +#define Z_UTIL_X2_1112 2224 +#define Z_UTIL_X2_1113 2226 +#define Z_UTIL_X2_1114 2228 +#define Z_UTIL_X2_1115 2230 +#define Z_UTIL_X2_1116 2232 +#define Z_UTIL_X2_1117 2234 +#define Z_UTIL_X2_1118 2236 +#define Z_UTIL_X2_1119 2238 +#define Z_UTIL_X2_1120 2240 +#define Z_UTIL_X2_1121 2242 +#define Z_UTIL_X2_1122 2244 +#define Z_UTIL_X2_1123 2246 +#define Z_UTIL_X2_1124 2248 +#define Z_UTIL_X2_1125 2250 +#define Z_UTIL_X2_1126 2252 +#define Z_UTIL_X2_1127 2254 +#define Z_UTIL_X2_1128 2256 +#define Z_UTIL_X2_1129 2258 +#define Z_UTIL_X2_1130 2260 +#define Z_UTIL_X2_1131 2262 +#define Z_UTIL_X2_1132 2264 +#define Z_UTIL_X2_1133 2266 +#define Z_UTIL_X2_1134 2268 +#define Z_UTIL_X2_1135 2270 +#define Z_UTIL_X2_1136 2272 +#define Z_UTIL_X2_1137 2274 +#define Z_UTIL_X2_1138 2276 +#define Z_UTIL_X2_1139 2278 +#define Z_UTIL_X2_1140 2280 +#define Z_UTIL_X2_1141 2282 +#define Z_UTIL_X2_1142 2284 +#define Z_UTIL_X2_1143 2286 +#define Z_UTIL_X2_1144 2288 +#define Z_UTIL_X2_1145 2290 +#define Z_UTIL_X2_1146 2292 +#define Z_UTIL_X2_1147 2294 +#define Z_UTIL_X2_1148 2296 +#define Z_UTIL_X2_1149 2298 +#define Z_UTIL_X2_1150 2300 +#define Z_UTIL_X2_1151 2302 +#define Z_UTIL_X2_1152 2304 +#define Z_UTIL_X2_1153 2306 +#define Z_UTIL_X2_1154 2308 +#define Z_UTIL_X2_1155 2310 +#define Z_UTIL_X2_1156 2312 +#define Z_UTIL_X2_1157 2314 +#define Z_UTIL_X2_1158 2316 +#define Z_UTIL_X2_1159 2318 +#define Z_UTIL_X2_1160 2320 +#define Z_UTIL_X2_1161 2322 +#define Z_UTIL_X2_1162 2324 +#define Z_UTIL_X2_1163 2326 +#define Z_UTIL_X2_1164 2328 +#define Z_UTIL_X2_1165 2330 +#define Z_UTIL_X2_1166 2332 +#define Z_UTIL_X2_1167 2334 +#define Z_UTIL_X2_1168 2336 +#define Z_UTIL_X2_1169 2338 +#define Z_UTIL_X2_1170 2340 +#define Z_UTIL_X2_1171 2342 +#define Z_UTIL_X2_1172 2344 +#define Z_UTIL_X2_1173 2346 +#define Z_UTIL_X2_1174 2348 +#define Z_UTIL_X2_1175 2350 +#define Z_UTIL_X2_1176 2352 +#define Z_UTIL_X2_1177 2354 +#define Z_UTIL_X2_1178 2356 +#define Z_UTIL_X2_1179 2358 +#define Z_UTIL_X2_1180 2360 +#define Z_UTIL_X2_1181 2362 +#define Z_UTIL_X2_1182 2364 +#define Z_UTIL_X2_1183 2366 +#define Z_UTIL_X2_1184 2368 +#define Z_UTIL_X2_1185 2370 +#define Z_UTIL_X2_1186 2372 +#define Z_UTIL_X2_1187 2374 +#define Z_UTIL_X2_1188 2376 +#define Z_UTIL_X2_1189 2378 +#define Z_UTIL_X2_1190 2380 +#define Z_UTIL_X2_1191 2382 +#define Z_UTIL_X2_1192 2384 +#define Z_UTIL_X2_1193 2386 +#define Z_UTIL_X2_1194 2388 +#define Z_UTIL_X2_1195 2390 +#define Z_UTIL_X2_1196 2392 +#define Z_UTIL_X2_1197 2394 +#define Z_UTIL_X2_1198 2396 +#define Z_UTIL_X2_1199 2398 +#define Z_UTIL_X2_1200 2400 +#define Z_UTIL_X2_1201 2402 +#define Z_UTIL_X2_1202 2404 +#define Z_UTIL_X2_1203 2406 +#define Z_UTIL_X2_1204 2408 +#define Z_UTIL_X2_1205 2410 +#define Z_UTIL_X2_1206 2412 +#define Z_UTIL_X2_1207 2414 +#define Z_UTIL_X2_1208 2416 +#define Z_UTIL_X2_1209 2418 +#define Z_UTIL_X2_1210 2420 +#define Z_UTIL_X2_1211 2422 +#define Z_UTIL_X2_1212 2424 +#define Z_UTIL_X2_1213 2426 +#define Z_UTIL_X2_1214 2428 +#define Z_UTIL_X2_1215 2430 +#define Z_UTIL_X2_1216 2432 +#define Z_UTIL_X2_1217 2434 +#define Z_UTIL_X2_1218 2436 +#define Z_UTIL_X2_1219 2438 +#define Z_UTIL_X2_1220 2440 +#define Z_UTIL_X2_1221 2442 +#define Z_UTIL_X2_1222 2444 +#define Z_UTIL_X2_1223 2446 +#define Z_UTIL_X2_1224 2448 +#define Z_UTIL_X2_1225 2450 +#define Z_UTIL_X2_1226 2452 +#define Z_UTIL_X2_1227 2454 +#define Z_UTIL_X2_1228 2456 +#define Z_UTIL_X2_1229 2458 +#define Z_UTIL_X2_1230 2460 +#define Z_UTIL_X2_1231 2462 +#define Z_UTIL_X2_1232 2464 +#define Z_UTIL_X2_1233 2466 +#define Z_UTIL_X2_1234 2468 +#define Z_UTIL_X2_1235 2470 +#define Z_UTIL_X2_1236 2472 +#define Z_UTIL_X2_1237 2474 +#define Z_UTIL_X2_1238 2476 +#define Z_UTIL_X2_1239 2478 +#define Z_UTIL_X2_1240 2480 +#define Z_UTIL_X2_1241 2482 +#define Z_UTIL_X2_1242 2484 +#define Z_UTIL_X2_1243 2486 +#define Z_UTIL_X2_1244 2488 +#define Z_UTIL_X2_1245 2490 +#define Z_UTIL_X2_1246 2492 +#define Z_UTIL_X2_1247 2494 +#define Z_UTIL_X2_1248 2496 +#define Z_UTIL_X2_1249 2498 +#define Z_UTIL_X2_1250 2500 +#define Z_UTIL_X2_1251 2502 +#define Z_UTIL_X2_1252 2504 +#define Z_UTIL_X2_1253 2506 +#define Z_UTIL_X2_1254 2508 +#define Z_UTIL_X2_1255 2510 +#define Z_UTIL_X2_1256 2512 +#define Z_UTIL_X2_1257 2514 +#define Z_UTIL_X2_1258 2516 +#define Z_UTIL_X2_1259 2518 +#define Z_UTIL_X2_1260 2520 +#define Z_UTIL_X2_1261 2522 +#define Z_UTIL_X2_1262 2524 +#define Z_UTIL_X2_1263 2526 +#define Z_UTIL_X2_1264 2528 +#define Z_UTIL_X2_1265 2530 +#define Z_UTIL_X2_1266 2532 +#define Z_UTIL_X2_1267 2534 +#define Z_UTIL_X2_1268 2536 +#define Z_UTIL_X2_1269 2538 +#define Z_UTIL_X2_1270 2540 +#define Z_UTIL_X2_1271 2542 +#define Z_UTIL_X2_1272 2544 +#define Z_UTIL_X2_1273 2546 +#define Z_UTIL_X2_1274 2548 +#define Z_UTIL_X2_1275 2550 +#define Z_UTIL_X2_1276 2552 +#define Z_UTIL_X2_1277 2554 +#define Z_UTIL_X2_1278 2556 +#define Z_UTIL_X2_1279 2558 +#define Z_UTIL_X2_1280 2560 +#define Z_UTIL_X2_1281 2562 +#define Z_UTIL_X2_1282 2564 +#define Z_UTIL_X2_1283 2566 +#define Z_UTIL_X2_1284 2568 +#define Z_UTIL_X2_1285 2570 +#define Z_UTIL_X2_1286 2572 +#define Z_UTIL_X2_1287 2574 +#define Z_UTIL_X2_1288 2576 +#define Z_UTIL_X2_1289 2578 +#define Z_UTIL_X2_1290 2580 +#define Z_UTIL_X2_1291 2582 +#define Z_UTIL_X2_1292 2584 +#define Z_UTIL_X2_1293 2586 +#define Z_UTIL_X2_1294 2588 +#define Z_UTIL_X2_1295 2590 +#define Z_UTIL_X2_1296 2592 +#define Z_UTIL_X2_1297 2594 +#define Z_UTIL_X2_1298 2596 +#define Z_UTIL_X2_1299 2598 +#define Z_UTIL_X2_1300 2600 +#define Z_UTIL_X2_1301 2602 +#define Z_UTIL_X2_1302 2604 +#define Z_UTIL_X2_1303 2606 +#define Z_UTIL_X2_1304 2608 +#define Z_UTIL_X2_1305 2610 +#define Z_UTIL_X2_1306 2612 +#define Z_UTIL_X2_1307 2614 +#define Z_UTIL_X2_1308 2616 +#define Z_UTIL_X2_1309 2618 +#define Z_UTIL_X2_1310 2620 +#define Z_UTIL_X2_1311 2622 +#define Z_UTIL_X2_1312 2624 +#define Z_UTIL_X2_1313 2626 +#define Z_UTIL_X2_1314 2628 +#define Z_UTIL_X2_1315 2630 +#define Z_UTIL_X2_1316 2632 +#define Z_UTIL_X2_1317 2634 +#define Z_UTIL_X2_1318 2636 +#define Z_UTIL_X2_1319 2638 +#define Z_UTIL_X2_1320 2640 +#define Z_UTIL_X2_1321 2642 +#define Z_UTIL_X2_1322 2644 +#define Z_UTIL_X2_1323 2646 +#define Z_UTIL_X2_1324 2648 +#define Z_UTIL_X2_1325 2650 +#define Z_UTIL_X2_1326 2652 +#define Z_UTIL_X2_1327 2654 +#define Z_UTIL_X2_1328 2656 +#define Z_UTIL_X2_1329 2658 +#define Z_UTIL_X2_1330 2660 +#define Z_UTIL_X2_1331 2662 +#define Z_UTIL_X2_1332 2664 +#define Z_UTIL_X2_1333 2666 +#define Z_UTIL_X2_1334 2668 +#define Z_UTIL_X2_1335 2670 +#define Z_UTIL_X2_1336 2672 +#define Z_UTIL_X2_1337 2674 +#define Z_UTIL_X2_1338 2676 +#define Z_UTIL_X2_1339 2678 +#define Z_UTIL_X2_1340 2680 +#define Z_UTIL_X2_1341 2682 +#define Z_UTIL_X2_1342 2684 +#define Z_UTIL_X2_1343 2686 +#define Z_UTIL_X2_1344 2688 +#define Z_UTIL_X2_1345 2690 +#define Z_UTIL_X2_1346 2692 +#define Z_UTIL_X2_1347 2694 +#define Z_UTIL_X2_1348 2696 +#define Z_UTIL_X2_1349 2698 +#define Z_UTIL_X2_1350 2700 +#define Z_UTIL_X2_1351 2702 +#define Z_UTIL_X2_1352 2704 +#define Z_UTIL_X2_1353 2706 +#define Z_UTIL_X2_1354 2708 +#define Z_UTIL_X2_1355 2710 +#define Z_UTIL_X2_1356 2712 +#define Z_UTIL_X2_1357 2714 +#define Z_UTIL_X2_1358 2716 +#define Z_UTIL_X2_1359 2718 +#define Z_UTIL_X2_1360 2720 +#define Z_UTIL_X2_1361 2722 +#define Z_UTIL_X2_1362 2724 +#define Z_UTIL_X2_1363 2726 +#define Z_UTIL_X2_1364 2728 +#define Z_UTIL_X2_1365 2730 +#define Z_UTIL_X2_1366 2732 +#define Z_UTIL_X2_1367 2734 +#define Z_UTIL_X2_1368 2736 +#define Z_UTIL_X2_1369 2738 +#define Z_UTIL_X2_1370 2740 +#define Z_UTIL_X2_1371 2742 +#define Z_UTIL_X2_1372 2744 +#define Z_UTIL_X2_1373 2746 +#define Z_UTIL_X2_1374 2748 +#define Z_UTIL_X2_1375 2750 +#define Z_UTIL_X2_1376 2752 +#define Z_UTIL_X2_1377 2754 +#define Z_UTIL_X2_1378 2756 +#define Z_UTIL_X2_1379 2758 +#define Z_UTIL_X2_1380 2760 +#define Z_UTIL_X2_1381 2762 +#define Z_UTIL_X2_1382 2764 +#define Z_UTIL_X2_1383 2766 +#define Z_UTIL_X2_1384 2768 +#define Z_UTIL_X2_1385 2770 +#define Z_UTIL_X2_1386 2772 +#define Z_UTIL_X2_1387 2774 +#define Z_UTIL_X2_1388 2776 +#define Z_UTIL_X2_1389 2778 +#define Z_UTIL_X2_1390 2780 +#define Z_UTIL_X2_1391 2782 +#define Z_UTIL_X2_1392 2784 +#define Z_UTIL_X2_1393 2786 +#define Z_UTIL_X2_1394 2788 +#define Z_UTIL_X2_1395 2790 +#define Z_UTIL_X2_1396 2792 +#define Z_UTIL_X2_1397 2794 +#define Z_UTIL_X2_1398 2796 +#define Z_UTIL_X2_1399 2798 +#define Z_UTIL_X2_1400 2800 +#define Z_UTIL_X2_1401 2802 +#define Z_UTIL_X2_1402 2804 +#define Z_UTIL_X2_1403 2806 +#define Z_UTIL_X2_1404 2808 +#define Z_UTIL_X2_1405 2810 +#define Z_UTIL_X2_1406 2812 +#define Z_UTIL_X2_1407 2814 +#define Z_UTIL_X2_1408 2816 +#define Z_UTIL_X2_1409 2818 +#define Z_UTIL_X2_1410 2820 +#define Z_UTIL_X2_1411 2822 +#define Z_UTIL_X2_1412 2824 +#define Z_UTIL_X2_1413 2826 +#define Z_UTIL_X2_1414 2828 +#define Z_UTIL_X2_1415 2830 +#define Z_UTIL_X2_1416 2832 +#define Z_UTIL_X2_1417 2834 +#define Z_UTIL_X2_1418 2836 +#define Z_UTIL_X2_1419 2838 +#define Z_UTIL_X2_1420 2840 +#define Z_UTIL_X2_1421 2842 +#define Z_UTIL_X2_1422 2844 +#define Z_UTIL_X2_1423 2846 +#define Z_UTIL_X2_1424 2848 +#define Z_UTIL_X2_1425 2850 +#define Z_UTIL_X2_1426 2852 +#define Z_UTIL_X2_1427 2854 +#define Z_UTIL_X2_1428 2856 +#define Z_UTIL_X2_1429 2858 +#define Z_UTIL_X2_1430 2860 +#define Z_UTIL_X2_1431 2862 +#define Z_UTIL_X2_1432 2864 +#define Z_UTIL_X2_1433 2866 +#define Z_UTIL_X2_1434 2868 +#define Z_UTIL_X2_1435 2870 +#define Z_UTIL_X2_1436 2872 +#define Z_UTIL_X2_1437 2874 +#define Z_UTIL_X2_1438 2876 +#define Z_UTIL_X2_1439 2878 +#define Z_UTIL_X2_1440 2880 +#define Z_UTIL_X2_1441 2882 +#define Z_UTIL_X2_1442 2884 +#define Z_UTIL_X2_1443 2886 +#define Z_UTIL_X2_1444 2888 +#define Z_UTIL_X2_1445 2890 +#define Z_UTIL_X2_1446 2892 +#define Z_UTIL_X2_1447 2894 +#define Z_UTIL_X2_1448 2896 +#define Z_UTIL_X2_1449 2898 +#define Z_UTIL_X2_1450 2900 +#define Z_UTIL_X2_1451 2902 +#define Z_UTIL_X2_1452 2904 +#define Z_UTIL_X2_1453 2906 +#define Z_UTIL_X2_1454 2908 +#define Z_UTIL_X2_1455 2910 +#define Z_UTIL_X2_1456 2912 +#define Z_UTIL_X2_1457 2914 +#define Z_UTIL_X2_1458 2916 +#define Z_UTIL_X2_1459 2918 +#define Z_UTIL_X2_1460 2920 +#define Z_UTIL_X2_1461 2922 +#define Z_UTIL_X2_1462 2924 +#define Z_UTIL_X2_1463 2926 +#define Z_UTIL_X2_1464 2928 +#define Z_UTIL_X2_1465 2930 +#define Z_UTIL_X2_1466 2932 +#define Z_UTIL_X2_1467 2934 +#define Z_UTIL_X2_1468 2936 +#define Z_UTIL_X2_1469 2938 +#define Z_UTIL_X2_1470 2940 +#define Z_UTIL_X2_1471 2942 +#define Z_UTIL_X2_1472 2944 +#define Z_UTIL_X2_1473 2946 +#define Z_UTIL_X2_1474 2948 +#define Z_UTIL_X2_1475 2950 +#define Z_UTIL_X2_1476 2952 +#define Z_UTIL_X2_1477 2954 +#define Z_UTIL_X2_1478 2956 +#define Z_UTIL_X2_1479 2958 +#define Z_UTIL_X2_1480 2960 +#define Z_UTIL_X2_1481 2962 +#define Z_UTIL_X2_1482 2964 +#define Z_UTIL_X2_1483 2966 +#define Z_UTIL_X2_1484 2968 +#define Z_UTIL_X2_1485 2970 +#define Z_UTIL_X2_1486 2972 +#define Z_UTIL_X2_1487 2974 +#define Z_UTIL_X2_1488 2976 +#define Z_UTIL_X2_1489 2978 +#define Z_UTIL_X2_1490 2980 +#define Z_UTIL_X2_1491 2982 +#define Z_UTIL_X2_1492 2984 +#define Z_UTIL_X2_1493 2986 +#define Z_UTIL_X2_1494 2988 +#define Z_UTIL_X2_1495 2990 +#define Z_UTIL_X2_1496 2992 +#define Z_UTIL_X2_1497 2994 +#define Z_UTIL_X2_1498 2996 +#define Z_UTIL_X2_1499 2998 +#define Z_UTIL_X2_1500 3000 +#define Z_UTIL_X2_1501 3002 +#define Z_UTIL_X2_1502 3004 +#define Z_UTIL_X2_1503 3006 +#define Z_UTIL_X2_1504 3008 +#define Z_UTIL_X2_1505 3010 +#define Z_UTIL_X2_1506 3012 +#define Z_UTIL_X2_1507 3014 +#define Z_UTIL_X2_1508 3016 +#define Z_UTIL_X2_1509 3018 +#define Z_UTIL_X2_1510 3020 +#define Z_UTIL_X2_1511 3022 +#define Z_UTIL_X2_1512 3024 +#define Z_UTIL_X2_1513 3026 +#define Z_UTIL_X2_1514 3028 +#define Z_UTIL_X2_1515 3030 +#define Z_UTIL_X2_1516 3032 +#define Z_UTIL_X2_1517 3034 +#define Z_UTIL_X2_1518 3036 +#define Z_UTIL_X2_1519 3038 +#define Z_UTIL_X2_1520 3040 +#define Z_UTIL_X2_1521 3042 +#define Z_UTIL_X2_1522 3044 +#define Z_UTIL_X2_1523 3046 +#define Z_UTIL_X2_1524 3048 +#define Z_UTIL_X2_1525 3050 +#define Z_UTIL_X2_1526 3052 +#define Z_UTIL_X2_1527 3054 +#define Z_UTIL_X2_1528 3056 +#define Z_UTIL_X2_1529 3058 +#define Z_UTIL_X2_1530 3060 +#define Z_UTIL_X2_1531 3062 +#define Z_UTIL_X2_1532 3064 +#define Z_UTIL_X2_1533 3066 +#define Z_UTIL_X2_1534 3068 +#define Z_UTIL_X2_1535 3070 +#define Z_UTIL_X2_1536 3072 +#define Z_UTIL_X2_1537 3074 +#define Z_UTIL_X2_1538 3076 +#define Z_UTIL_X2_1539 3078 +#define Z_UTIL_X2_1540 3080 +#define Z_UTIL_X2_1541 3082 +#define Z_UTIL_X2_1542 3084 +#define Z_UTIL_X2_1543 3086 +#define Z_UTIL_X2_1544 3088 +#define Z_UTIL_X2_1545 3090 +#define Z_UTIL_X2_1546 3092 +#define Z_UTIL_X2_1547 3094 +#define Z_UTIL_X2_1548 3096 +#define Z_UTIL_X2_1549 3098 +#define Z_UTIL_X2_1550 3100 +#define Z_UTIL_X2_1551 3102 +#define Z_UTIL_X2_1552 3104 +#define Z_UTIL_X2_1553 3106 +#define Z_UTIL_X2_1554 3108 +#define Z_UTIL_X2_1555 3110 +#define Z_UTIL_X2_1556 3112 +#define Z_UTIL_X2_1557 3114 +#define Z_UTIL_X2_1558 3116 +#define Z_UTIL_X2_1559 3118 +#define Z_UTIL_X2_1560 3120 +#define Z_UTIL_X2_1561 3122 +#define Z_UTIL_X2_1562 3124 +#define Z_UTIL_X2_1563 3126 +#define Z_UTIL_X2_1564 3128 +#define Z_UTIL_X2_1565 3130 +#define Z_UTIL_X2_1566 3132 +#define Z_UTIL_X2_1567 3134 +#define Z_UTIL_X2_1568 3136 +#define Z_UTIL_X2_1569 3138 +#define Z_UTIL_X2_1570 3140 +#define Z_UTIL_X2_1571 3142 +#define Z_UTIL_X2_1572 3144 +#define Z_UTIL_X2_1573 3146 +#define Z_UTIL_X2_1574 3148 +#define Z_UTIL_X2_1575 3150 +#define Z_UTIL_X2_1576 3152 +#define Z_UTIL_X2_1577 3154 +#define Z_UTIL_X2_1578 3156 +#define Z_UTIL_X2_1579 3158 +#define Z_UTIL_X2_1580 3160 +#define Z_UTIL_X2_1581 3162 +#define Z_UTIL_X2_1582 3164 +#define Z_UTIL_X2_1583 3166 +#define Z_UTIL_X2_1584 3168 +#define Z_UTIL_X2_1585 3170 +#define Z_UTIL_X2_1586 3172 +#define Z_UTIL_X2_1587 3174 +#define Z_UTIL_X2_1588 3176 +#define Z_UTIL_X2_1589 3178 +#define Z_UTIL_X2_1590 3180 +#define Z_UTIL_X2_1591 3182 +#define Z_UTIL_X2_1592 3184 +#define Z_UTIL_X2_1593 3186 +#define Z_UTIL_X2_1594 3188 +#define Z_UTIL_X2_1595 3190 +#define Z_UTIL_X2_1596 3192 +#define Z_UTIL_X2_1597 3194 +#define Z_UTIL_X2_1598 3196 +#define Z_UTIL_X2_1599 3198 +#define Z_UTIL_X2_1600 3200 +#define Z_UTIL_X2_1601 3202 +#define Z_UTIL_X2_1602 3204 +#define Z_UTIL_X2_1603 3206 +#define Z_UTIL_X2_1604 3208 +#define Z_UTIL_X2_1605 3210 +#define Z_UTIL_X2_1606 3212 +#define Z_UTIL_X2_1607 3214 +#define Z_UTIL_X2_1608 3216 +#define Z_UTIL_X2_1609 3218 +#define Z_UTIL_X2_1610 3220 +#define Z_UTIL_X2_1611 3222 +#define Z_UTIL_X2_1612 3224 +#define Z_UTIL_X2_1613 3226 +#define Z_UTIL_X2_1614 3228 +#define Z_UTIL_X2_1615 3230 +#define Z_UTIL_X2_1616 3232 +#define Z_UTIL_X2_1617 3234 +#define Z_UTIL_X2_1618 3236 +#define Z_UTIL_X2_1619 3238 +#define Z_UTIL_X2_1620 3240 +#define Z_UTIL_X2_1621 3242 +#define Z_UTIL_X2_1622 3244 +#define Z_UTIL_X2_1623 3246 +#define Z_UTIL_X2_1624 3248 +#define Z_UTIL_X2_1625 3250 +#define Z_UTIL_X2_1626 3252 +#define Z_UTIL_X2_1627 3254 +#define Z_UTIL_X2_1628 3256 +#define Z_UTIL_X2_1629 3258 +#define Z_UTIL_X2_1630 3260 +#define Z_UTIL_X2_1631 3262 +#define Z_UTIL_X2_1632 3264 +#define Z_UTIL_X2_1633 3266 +#define Z_UTIL_X2_1634 3268 +#define Z_UTIL_X2_1635 3270 +#define Z_UTIL_X2_1636 3272 +#define Z_UTIL_X2_1637 3274 +#define Z_UTIL_X2_1638 3276 +#define Z_UTIL_X2_1639 3278 +#define Z_UTIL_X2_1640 3280 +#define Z_UTIL_X2_1641 3282 +#define Z_UTIL_X2_1642 3284 +#define Z_UTIL_X2_1643 3286 +#define Z_UTIL_X2_1644 3288 +#define Z_UTIL_X2_1645 3290 +#define Z_UTIL_X2_1646 3292 +#define Z_UTIL_X2_1647 3294 +#define Z_UTIL_X2_1648 3296 +#define Z_UTIL_X2_1649 3298 +#define Z_UTIL_X2_1650 3300 +#define Z_UTIL_X2_1651 3302 +#define Z_UTIL_X2_1652 3304 +#define Z_UTIL_X2_1653 3306 +#define Z_UTIL_X2_1654 3308 +#define Z_UTIL_X2_1655 3310 +#define Z_UTIL_X2_1656 3312 +#define Z_UTIL_X2_1657 3314 +#define Z_UTIL_X2_1658 3316 +#define Z_UTIL_X2_1659 3318 +#define Z_UTIL_X2_1660 3320 +#define Z_UTIL_X2_1661 3322 +#define Z_UTIL_X2_1662 3324 +#define Z_UTIL_X2_1663 3326 +#define Z_UTIL_X2_1664 3328 +#define Z_UTIL_X2_1665 3330 +#define Z_UTIL_X2_1666 3332 +#define Z_UTIL_X2_1667 3334 +#define Z_UTIL_X2_1668 3336 +#define Z_UTIL_X2_1669 3338 +#define Z_UTIL_X2_1670 3340 +#define Z_UTIL_X2_1671 3342 +#define Z_UTIL_X2_1672 3344 +#define Z_UTIL_X2_1673 3346 +#define Z_UTIL_X2_1674 3348 +#define Z_UTIL_X2_1675 3350 +#define Z_UTIL_X2_1676 3352 +#define Z_UTIL_X2_1677 3354 +#define Z_UTIL_X2_1678 3356 +#define Z_UTIL_X2_1679 3358 +#define Z_UTIL_X2_1680 3360 +#define Z_UTIL_X2_1681 3362 +#define Z_UTIL_X2_1682 3364 +#define Z_UTIL_X2_1683 3366 +#define Z_UTIL_X2_1684 3368 +#define Z_UTIL_X2_1685 3370 +#define Z_UTIL_X2_1686 3372 +#define Z_UTIL_X2_1687 3374 +#define Z_UTIL_X2_1688 3376 +#define Z_UTIL_X2_1689 3378 +#define Z_UTIL_X2_1690 3380 +#define Z_UTIL_X2_1691 3382 +#define Z_UTIL_X2_1692 3384 +#define Z_UTIL_X2_1693 3386 +#define Z_UTIL_X2_1694 3388 +#define Z_UTIL_X2_1695 3390 +#define Z_UTIL_X2_1696 3392 +#define Z_UTIL_X2_1697 3394 +#define Z_UTIL_X2_1698 3396 +#define Z_UTIL_X2_1699 3398 +#define Z_UTIL_X2_1700 3400 +#define Z_UTIL_X2_1701 3402 +#define Z_UTIL_X2_1702 3404 +#define Z_UTIL_X2_1703 3406 +#define Z_UTIL_X2_1704 3408 +#define Z_UTIL_X2_1705 3410 +#define Z_UTIL_X2_1706 3412 +#define Z_UTIL_X2_1707 3414 +#define Z_UTIL_X2_1708 3416 +#define Z_UTIL_X2_1709 3418 +#define Z_UTIL_X2_1710 3420 +#define Z_UTIL_X2_1711 3422 +#define Z_UTIL_X2_1712 3424 +#define Z_UTIL_X2_1713 3426 +#define Z_UTIL_X2_1714 3428 +#define Z_UTIL_X2_1715 3430 +#define Z_UTIL_X2_1716 3432 +#define Z_UTIL_X2_1717 3434 +#define Z_UTIL_X2_1718 3436 +#define Z_UTIL_X2_1719 3438 +#define Z_UTIL_X2_1720 3440 +#define Z_UTIL_X2_1721 3442 +#define Z_UTIL_X2_1722 3444 +#define Z_UTIL_X2_1723 3446 +#define Z_UTIL_X2_1724 3448 +#define Z_UTIL_X2_1725 3450 +#define Z_UTIL_X2_1726 3452 +#define Z_UTIL_X2_1727 3454 +#define Z_UTIL_X2_1728 3456 +#define Z_UTIL_X2_1729 3458 +#define Z_UTIL_X2_1730 3460 +#define Z_UTIL_X2_1731 3462 +#define Z_UTIL_X2_1732 3464 +#define Z_UTIL_X2_1733 3466 +#define Z_UTIL_X2_1734 3468 +#define Z_UTIL_X2_1735 3470 +#define Z_UTIL_X2_1736 3472 +#define Z_UTIL_X2_1737 3474 +#define Z_UTIL_X2_1738 3476 +#define Z_UTIL_X2_1739 3478 +#define Z_UTIL_X2_1740 3480 +#define Z_UTIL_X2_1741 3482 +#define Z_UTIL_X2_1742 3484 +#define Z_UTIL_X2_1743 3486 +#define Z_UTIL_X2_1744 3488 +#define Z_UTIL_X2_1745 3490 +#define Z_UTIL_X2_1746 3492 +#define Z_UTIL_X2_1747 3494 +#define Z_UTIL_X2_1748 3496 +#define Z_UTIL_X2_1749 3498 +#define Z_UTIL_X2_1750 3500 +#define Z_UTIL_X2_1751 3502 +#define Z_UTIL_X2_1752 3504 +#define Z_UTIL_X2_1753 3506 +#define Z_UTIL_X2_1754 3508 +#define Z_UTIL_X2_1755 3510 +#define Z_UTIL_X2_1756 3512 +#define Z_UTIL_X2_1757 3514 +#define Z_UTIL_X2_1758 3516 +#define Z_UTIL_X2_1759 3518 +#define Z_UTIL_X2_1760 3520 +#define Z_UTIL_X2_1761 3522 +#define Z_UTIL_X2_1762 3524 +#define Z_UTIL_X2_1763 3526 +#define Z_UTIL_X2_1764 3528 +#define Z_UTIL_X2_1765 3530 +#define Z_UTIL_X2_1766 3532 +#define Z_UTIL_X2_1767 3534 +#define Z_UTIL_X2_1768 3536 +#define Z_UTIL_X2_1769 3538 +#define Z_UTIL_X2_1770 3540 +#define Z_UTIL_X2_1771 3542 +#define Z_UTIL_X2_1772 3544 +#define Z_UTIL_X2_1773 3546 +#define Z_UTIL_X2_1774 3548 +#define Z_UTIL_X2_1775 3550 +#define Z_UTIL_X2_1776 3552 +#define Z_UTIL_X2_1777 3554 +#define Z_UTIL_X2_1778 3556 +#define Z_UTIL_X2_1779 3558 +#define Z_UTIL_X2_1780 3560 +#define Z_UTIL_X2_1781 3562 +#define Z_UTIL_X2_1782 3564 +#define Z_UTIL_X2_1783 3566 +#define Z_UTIL_X2_1784 3568 +#define Z_UTIL_X2_1785 3570 +#define Z_UTIL_X2_1786 3572 +#define Z_UTIL_X2_1787 3574 +#define Z_UTIL_X2_1788 3576 +#define Z_UTIL_X2_1789 3578 +#define Z_UTIL_X2_1790 3580 +#define Z_UTIL_X2_1791 3582 +#define Z_UTIL_X2_1792 3584 +#define Z_UTIL_X2_1793 3586 +#define Z_UTIL_X2_1794 3588 +#define Z_UTIL_X2_1795 3590 +#define Z_UTIL_X2_1796 3592 +#define Z_UTIL_X2_1797 3594 +#define Z_UTIL_X2_1798 3596 +#define Z_UTIL_X2_1799 3598 +#define Z_UTIL_X2_1800 3600 +#define Z_UTIL_X2_1801 3602 +#define Z_UTIL_X2_1802 3604 +#define Z_UTIL_X2_1803 3606 +#define Z_UTIL_X2_1804 3608 +#define Z_UTIL_X2_1805 3610 +#define Z_UTIL_X2_1806 3612 +#define Z_UTIL_X2_1807 3614 +#define Z_UTIL_X2_1808 3616 +#define Z_UTIL_X2_1809 3618 +#define Z_UTIL_X2_1810 3620 +#define Z_UTIL_X2_1811 3622 +#define Z_UTIL_X2_1812 3624 +#define Z_UTIL_X2_1813 3626 +#define Z_UTIL_X2_1814 3628 +#define Z_UTIL_X2_1815 3630 +#define Z_UTIL_X2_1816 3632 +#define Z_UTIL_X2_1817 3634 +#define Z_UTIL_X2_1818 3636 +#define Z_UTIL_X2_1819 3638 +#define Z_UTIL_X2_1820 3640 +#define Z_UTIL_X2_1821 3642 +#define Z_UTIL_X2_1822 3644 +#define Z_UTIL_X2_1823 3646 +#define Z_UTIL_X2_1824 3648 +#define Z_UTIL_X2_1825 3650 +#define Z_UTIL_X2_1826 3652 +#define Z_UTIL_X2_1827 3654 +#define Z_UTIL_X2_1828 3656 +#define Z_UTIL_X2_1829 3658 +#define Z_UTIL_X2_1830 3660 +#define Z_UTIL_X2_1831 3662 +#define Z_UTIL_X2_1832 3664 +#define Z_UTIL_X2_1833 3666 +#define Z_UTIL_X2_1834 3668 +#define Z_UTIL_X2_1835 3670 +#define Z_UTIL_X2_1836 3672 +#define Z_UTIL_X2_1837 3674 +#define Z_UTIL_X2_1838 3676 +#define Z_UTIL_X2_1839 3678 +#define Z_UTIL_X2_1840 3680 +#define Z_UTIL_X2_1841 3682 +#define Z_UTIL_X2_1842 3684 +#define Z_UTIL_X2_1843 3686 +#define Z_UTIL_X2_1844 3688 +#define Z_UTIL_X2_1845 3690 +#define Z_UTIL_X2_1846 3692 +#define Z_UTIL_X2_1847 3694 +#define Z_UTIL_X2_1848 3696 +#define Z_UTIL_X2_1849 3698 +#define Z_UTIL_X2_1850 3700 +#define Z_UTIL_X2_1851 3702 +#define Z_UTIL_X2_1852 3704 +#define Z_UTIL_X2_1853 3706 +#define Z_UTIL_X2_1854 3708 +#define Z_UTIL_X2_1855 3710 +#define Z_UTIL_X2_1856 3712 +#define Z_UTIL_X2_1857 3714 +#define Z_UTIL_X2_1858 3716 +#define Z_UTIL_X2_1859 3718 +#define Z_UTIL_X2_1860 3720 +#define Z_UTIL_X2_1861 3722 +#define Z_UTIL_X2_1862 3724 +#define Z_UTIL_X2_1863 3726 +#define Z_UTIL_X2_1864 3728 +#define Z_UTIL_X2_1865 3730 +#define Z_UTIL_X2_1866 3732 +#define Z_UTIL_X2_1867 3734 +#define Z_UTIL_X2_1868 3736 +#define Z_UTIL_X2_1869 3738 +#define Z_UTIL_X2_1870 3740 +#define Z_UTIL_X2_1871 3742 +#define Z_UTIL_X2_1872 3744 +#define Z_UTIL_X2_1873 3746 +#define Z_UTIL_X2_1874 3748 +#define Z_UTIL_X2_1875 3750 +#define Z_UTIL_X2_1876 3752 +#define Z_UTIL_X2_1877 3754 +#define Z_UTIL_X2_1878 3756 +#define Z_UTIL_X2_1879 3758 +#define Z_UTIL_X2_1880 3760 +#define Z_UTIL_X2_1881 3762 +#define Z_UTIL_X2_1882 3764 +#define Z_UTIL_X2_1883 3766 +#define Z_UTIL_X2_1884 3768 +#define Z_UTIL_X2_1885 3770 +#define Z_UTIL_X2_1886 3772 +#define Z_UTIL_X2_1887 3774 +#define Z_UTIL_X2_1888 3776 +#define Z_UTIL_X2_1889 3778 +#define Z_UTIL_X2_1890 3780 +#define Z_UTIL_X2_1891 3782 +#define Z_UTIL_X2_1892 3784 +#define Z_UTIL_X2_1893 3786 +#define Z_UTIL_X2_1894 3788 +#define Z_UTIL_X2_1895 3790 +#define Z_UTIL_X2_1896 3792 +#define Z_UTIL_X2_1897 3794 +#define Z_UTIL_X2_1898 3796 +#define Z_UTIL_X2_1899 3798 +#define Z_UTIL_X2_1900 3800 +#define Z_UTIL_X2_1901 3802 +#define Z_UTIL_X2_1902 3804 +#define Z_UTIL_X2_1903 3806 +#define Z_UTIL_X2_1904 3808 +#define Z_UTIL_X2_1905 3810 +#define Z_UTIL_X2_1906 3812 +#define Z_UTIL_X2_1907 3814 +#define Z_UTIL_X2_1908 3816 +#define Z_UTIL_X2_1909 3818 +#define Z_UTIL_X2_1910 3820 +#define Z_UTIL_X2_1911 3822 +#define Z_UTIL_X2_1912 3824 +#define Z_UTIL_X2_1913 3826 +#define Z_UTIL_X2_1914 3828 +#define Z_UTIL_X2_1915 3830 +#define Z_UTIL_X2_1916 3832 +#define Z_UTIL_X2_1917 3834 +#define Z_UTIL_X2_1918 3836 +#define Z_UTIL_X2_1919 3838 +#define Z_UTIL_X2_1920 3840 +#define Z_UTIL_X2_1921 3842 +#define Z_UTIL_X2_1922 3844 +#define Z_UTIL_X2_1923 3846 +#define Z_UTIL_X2_1924 3848 +#define Z_UTIL_X2_1925 3850 +#define Z_UTIL_X2_1926 3852 +#define Z_UTIL_X2_1927 3854 +#define Z_UTIL_X2_1928 3856 +#define Z_UTIL_X2_1929 3858 +#define Z_UTIL_X2_1930 3860 +#define Z_UTIL_X2_1931 3862 +#define Z_UTIL_X2_1932 3864 +#define Z_UTIL_X2_1933 3866 +#define Z_UTIL_X2_1934 3868 +#define Z_UTIL_X2_1935 3870 +#define Z_UTIL_X2_1936 3872 +#define Z_UTIL_X2_1937 3874 +#define Z_UTIL_X2_1938 3876 +#define Z_UTIL_X2_1939 3878 +#define Z_UTIL_X2_1940 3880 +#define Z_UTIL_X2_1941 3882 +#define Z_UTIL_X2_1942 3884 +#define Z_UTIL_X2_1943 3886 +#define Z_UTIL_X2_1944 3888 +#define Z_UTIL_X2_1945 3890 +#define Z_UTIL_X2_1946 3892 +#define Z_UTIL_X2_1947 3894 +#define Z_UTIL_X2_1948 3896 +#define Z_UTIL_X2_1949 3898 +#define Z_UTIL_X2_1950 3900 +#define Z_UTIL_X2_1951 3902 +#define Z_UTIL_X2_1952 3904 +#define Z_UTIL_X2_1953 3906 +#define Z_UTIL_X2_1954 3908 +#define Z_UTIL_X2_1955 3910 +#define Z_UTIL_X2_1956 3912 +#define Z_UTIL_X2_1957 3914 +#define Z_UTIL_X2_1958 3916 +#define Z_UTIL_X2_1959 3918 +#define Z_UTIL_X2_1960 3920 +#define Z_UTIL_X2_1961 3922 +#define Z_UTIL_X2_1962 3924 +#define Z_UTIL_X2_1963 3926 +#define Z_UTIL_X2_1964 3928 +#define Z_UTIL_X2_1965 3930 +#define Z_UTIL_X2_1966 3932 +#define Z_UTIL_X2_1967 3934 +#define Z_UTIL_X2_1968 3936 +#define Z_UTIL_X2_1969 3938 +#define Z_UTIL_X2_1970 3940 +#define Z_UTIL_X2_1971 3942 +#define Z_UTIL_X2_1972 3944 +#define Z_UTIL_X2_1973 3946 +#define Z_UTIL_X2_1974 3948 +#define Z_UTIL_X2_1975 3950 +#define Z_UTIL_X2_1976 3952 +#define Z_UTIL_X2_1977 3954 +#define Z_UTIL_X2_1978 3956 +#define Z_UTIL_X2_1979 3958 +#define Z_UTIL_X2_1980 3960 +#define Z_UTIL_X2_1981 3962 +#define Z_UTIL_X2_1982 3964 +#define Z_UTIL_X2_1983 3966 +#define Z_UTIL_X2_1984 3968 +#define Z_UTIL_X2_1985 3970 +#define Z_UTIL_X2_1986 3972 +#define Z_UTIL_X2_1987 3974 +#define Z_UTIL_X2_1988 3976 +#define Z_UTIL_X2_1989 3978 +#define Z_UTIL_X2_1990 3980 +#define Z_UTIL_X2_1991 3982 +#define Z_UTIL_X2_1992 3984 +#define Z_UTIL_X2_1993 3986 +#define Z_UTIL_X2_1994 3988 +#define Z_UTIL_X2_1995 3990 +#define Z_UTIL_X2_1996 3992 +#define Z_UTIL_X2_1997 3994 +#define Z_UTIL_X2_1998 3996 +#define Z_UTIL_X2_1999 3998 +#define Z_UTIL_X2_2000 4000 +#define Z_UTIL_X2_2001 4002 +#define Z_UTIL_X2_2002 4004 +#define Z_UTIL_X2_2003 4006 +#define Z_UTIL_X2_2004 4008 +#define Z_UTIL_X2_2005 4010 +#define Z_UTIL_X2_2006 4012 +#define Z_UTIL_X2_2007 4014 +#define Z_UTIL_X2_2008 4016 +#define Z_UTIL_X2_2009 4018 +#define Z_UTIL_X2_2010 4020 +#define Z_UTIL_X2_2011 4022 +#define Z_UTIL_X2_2012 4024 +#define Z_UTIL_X2_2013 4026 +#define Z_UTIL_X2_2014 4028 +#define Z_UTIL_X2_2015 4030 +#define Z_UTIL_X2_2016 4032 +#define Z_UTIL_X2_2017 4034 +#define Z_UTIL_X2_2018 4036 +#define Z_UTIL_X2_2019 4038 +#define Z_UTIL_X2_2020 4040 +#define Z_UTIL_X2_2021 4042 +#define Z_UTIL_X2_2022 4044 +#define Z_UTIL_X2_2023 4046 +#define Z_UTIL_X2_2024 4048 +#define Z_UTIL_X2_2025 4050 +#define Z_UTIL_X2_2026 4052 +#define Z_UTIL_X2_2027 4054 +#define Z_UTIL_X2_2028 4056 +#define Z_UTIL_X2_2029 4058 +#define Z_UTIL_X2_2030 4060 +#define Z_UTIL_X2_2031 4062 +#define Z_UTIL_X2_2032 4064 +#define Z_UTIL_X2_2033 4066 +#define Z_UTIL_X2_2034 4068 +#define Z_UTIL_X2_2035 4070 +#define Z_UTIL_X2_2036 4072 +#define Z_UTIL_X2_2037 4074 +#define Z_UTIL_X2_2038 4076 +#define Z_UTIL_X2_2039 4078 +#define Z_UTIL_X2_2040 4080 +#define Z_UTIL_X2_2041 4082 +#define Z_UTIL_X2_2042 4084 +#define Z_UTIL_X2_2043 4086 +#define Z_UTIL_X2_2044 4088 +#define Z_UTIL_X2_2045 4090 +#define Z_UTIL_X2_2046 4092 +#define Z_UTIL_X2_2047 4094 +#define Z_UTIL_X2_2048 4096 +#define Z_UTIL_X2_2049 4098 +#define Z_UTIL_X2_2050 4100 +#define Z_UTIL_X2_2051 4102 +#define Z_UTIL_X2_2052 4104 +#define Z_UTIL_X2_2053 4106 +#define Z_UTIL_X2_2054 4108 +#define Z_UTIL_X2_2055 4110 +#define Z_UTIL_X2_2056 4112 +#define Z_UTIL_X2_2057 4114 +#define Z_UTIL_X2_2058 4116 +#define Z_UTIL_X2_2059 4118 +#define Z_UTIL_X2_2060 4120 +#define Z_UTIL_X2_2061 4122 +#define Z_UTIL_X2_2062 4124 +#define Z_UTIL_X2_2063 4126 +#define Z_UTIL_X2_2064 4128 +#define Z_UTIL_X2_2065 4130 +#define Z_UTIL_X2_2066 4132 +#define Z_UTIL_X2_2067 4134 +#define Z_UTIL_X2_2068 4136 +#define Z_UTIL_X2_2069 4138 +#define Z_UTIL_X2_2070 4140 +#define Z_UTIL_X2_2071 4142 +#define Z_UTIL_X2_2072 4144 +#define Z_UTIL_X2_2073 4146 +#define Z_UTIL_X2_2074 4148 +#define Z_UTIL_X2_2075 4150 +#define Z_UTIL_X2_2076 4152 +#define Z_UTIL_X2_2077 4154 +#define Z_UTIL_X2_2078 4156 +#define Z_UTIL_X2_2079 4158 +#define Z_UTIL_X2_2080 4160 +#define Z_UTIL_X2_2081 4162 +#define Z_UTIL_X2_2082 4164 +#define Z_UTIL_X2_2083 4166 +#define Z_UTIL_X2_2084 4168 +#define Z_UTIL_X2_2085 4170 +#define Z_UTIL_X2_2086 4172 +#define Z_UTIL_X2_2087 4174 +#define Z_UTIL_X2_2088 4176 +#define Z_UTIL_X2_2089 4178 +#define Z_UTIL_X2_2090 4180 +#define Z_UTIL_X2_2091 4182 +#define Z_UTIL_X2_2092 4184 +#define Z_UTIL_X2_2093 4186 +#define Z_UTIL_X2_2094 4188 +#define Z_UTIL_X2_2095 4190 +#define Z_UTIL_X2_2096 4192 +#define Z_UTIL_X2_2097 4194 +#define Z_UTIL_X2_2098 4196 +#define Z_UTIL_X2_2099 4198 +#define Z_UTIL_X2_2100 4200 +#define Z_UTIL_X2_2101 4202 +#define Z_UTIL_X2_2102 4204 +#define Z_UTIL_X2_2103 4206 +#define Z_UTIL_X2_2104 4208 +#define Z_UTIL_X2_2105 4210 +#define Z_UTIL_X2_2106 4212 +#define Z_UTIL_X2_2107 4214 +#define Z_UTIL_X2_2108 4216 +#define Z_UTIL_X2_2109 4218 +#define Z_UTIL_X2_2110 4220 +#define Z_UTIL_X2_2111 4222 +#define Z_UTIL_X2_2112 4224 +#define Z_UTIL_X2_2113 4226 +#define Z_UTIL_X2_2114 4228 +#define Z_UTIL_X2_2115 4230 +#define Z_UTIL_X2_2116 4232 +#define Z_UTIL_X2_2117 4234 +#define Z_UTIL_X2_2118 4236 +#define Z_UTIL_X2_2119 4238 +#define Z_UTIL_X2_2120 4240 +#define Z_UTIL_X2_2121 4242 +#define Z_UTIL_X2_2122 4244 +#define Z_UTIL_X2_2123 4246 +#define Z_UTIL_X2_2124 4248 +#define Z_UTIL_X2_2125 4250 +#define Z_UTIL_X2_2126 4252 +#define Z_UTIL_X2_2127 4254 +#define Z_UTIL_X2_2128 4256 +#define Z_UTIL_X2_2129 4258 +#define Z_UTIL_X2_2130 4260 +#define Z_UTIL_X2_2131 4262 +#define Z_UTIL_X2_2132 4264 +#define Z_UTIL_X2_2133 4266 +#define Z_UTIL_X2_2134 4268 +#define Z_UTIL_X2_2135 4270 +#define Z_UTIL_X2_2136 4272 +#define Z_UTIL_X2_2137 4274 +#define Z_UTIL_X2_2138 4276 +#define Z_UTIL_X2_2139 4278 +#define Z_UTIL_X2_2140 4280 +#define Z_UTIL_X2_2141 4282 +#define Z_UTIL_X2_2142 4284 +#define Z_UTIL_X2_2143 4286 +#define Z_UTIL_X2_2144 4288 +#define Z_UTIL_X2_2145 4290 +#define Z_UTIL_X2_2146 4292 +#define Z_UTIL_X2_2147 4294 +#define Z_UTIL_X2_2148 4296 +#define Z_UTIL_X2_2149 4298 +#define Z_UTIL_X2_2150 4300 +#define Z_UTIL_X2_2151 4302 +#define Z_UTIL_X2_2152 4304 +#define Z_UTIL_X2_2153 4306 +#define Z_UTIL_X2_2154 4308 +#define Z_UTIL_X2_2155 4310 +#define Z_UTIL_X2_2156 4312 +#define Z_UTIL_X2_2157 4314 +#define Z_UTIL_X2_2158 4316 +#define Z_UTIL_X2_2159 4318 +#define Z_UTIL_X2_2160 4320 +#define Z_UTIL_X2_2161 4322 +#define Z_UTIL_X2_2162 4324 +#define Z_UTIL_X2_2163 4326 +#define Z_UTIL_X2_2164 4328 +#define Z_UTIL_X2_2165 4330 +#define Z_UTIL_X2_2166 4332 +#define Z_UTIL_X2_2167 4334 +#define Z_UTIL_X2_2168 4336 +#define Z_UTIL_X2_2169 4338 +#define Z_UTIL_X2_2170 4340 +#define Z_UTIL_X2_2171 4342 +#define Z_UTIL_X2_2172 4344 +#define Z_UTIL_X2_2173 4346 +#define Z_UTIL_X2_2174 4348 +#define Z_UTIL_X2_2175 4350 +#define Z_UTIL_X2_2176 4352 +#define Z_UTIL_X2_2177 4354 +#define Z_UTIL_X2_2178 4356 +#define Z_UTIL_X2_2179 4358 +#define Z_UTIL_X2_2180 4360 +#define Z_UTIL_X2_2181 4362 +#define Z_UTIL_X2_2182 4364 +#define Z_UTIL_X2_2183 4366 +#define Z_UTIL_X2_2184 4368 +#define Z_UTIL_X2_2185 4370 +#define Z_UTIL_X2_2186 4372 +#define Z_UTIL_X2_2187 4374 +#define Z_UTIL_X2_2188 4376 +#define Z_UTIL_X2_2189 4378 +#define Z_UTIL_X2_2190 4380 +#define Z_UTIL_X2_2191 4382 +#define Z_UTIL_X2_2192 4384 +#define Z_UTIL_X2_2193 4386 +#define Z_UTIL_X2_2194 4388 +#define Z_UTIL_X2_2195 4390 +#define Z_UTIL_X2_2196 4392 +#define Z_UTIL_X2_2197 4394 +#define Z_UTIL_X2_2198 4396 +#define Z_UTIL_X2_2199 4398 +#define Z_UTIL_X2_2200 4400 +#define Z_UTIL_X2_2201 4402 +#define Z_UTIL_X2_2202 4404 +#define Z_UTIL_X2_2203 4406 +#define Z_UTIL_X2_2204 4408 +#define Z_UTIL_X2_2205 4410 +#define Z_UTIL_X2_2206 4412 +#define Z_UTIL_X2_2207 4414 +#define Z_UTIL_X2_2208 4416 +#define Z_UTIL_X2_2209 4418 +#define Z_UTIL_X2_2210 4420 +#define Z_UTIL_X2_2211 4422 +#define Z_UTIL_X2_2212 4424 +#define Z_UTIL_X2_2213 4426 +#define Z_UTIL_X2_2214 4428 +#define Z_UTIL_X2_2215 4430 +#define Z_UTIL_X2_2216 4432 +#define Z_UTIL_X2_2217 4434 +#define Z_UTIL_X2_2218 4436 +#define Z_UTIL_X2_2219 4438 +#define Z_UTIL_X2_2220 4440 +#define Z_UTIL_X2_2221 4442 +#define Z_UTIL_X2_2222 4444 +#define Z_UTIL_X2_2223 4446 +#define Z_UTIL_X2_2224 4448 +#define Z_UTIL_X2_2225 4450 +#define Z_UTIL_X2_2226 4452 +#define Z_UTIL_X2_2227 4454 +#define Z_UTIL_X2_2228 4456 +#define Z_UTIL_X2_2229 4458 +#define Z_UTIL_X2_2230 4460 +#define Z_UTIL_X2_2231 4462 +#define Z_UTIL_X2_2232 4464 +#define Z_UTIL_X2_2233 4466 +#define Z_UTIL_X2_2234 4468 +#define Z_UTIL_X2_2235 4470 +#define Z_UTIL_X2_2236 4472 +#define Z_UTIL_X2_2237 4474 +#define Z_UTIL_X2_2238 4476 +#define Z_UTIL_X2_2239 4478 +#define Z_UTIL_X2_2240 4480 +#define Z_UTIL_X2_2241 4482 +#define Z_UTIL_X2_2242 4484 +#define Z_UTIL_X2_2243 4486 +#define Z_UTIL_X2_2244 4488 +#define Z_UTIL_X2_2245 4490 +#define Z_UTIL_X2_2246 4492 +#define Z_UTIL_X2_2247 4494 +#define Z_UTIL_X2_2248 4496 +#define Z_UTIL_X2_2249 4498 +#define Z_UTIL_X2_2250 4500 +#define Z_UTIL_X2_2251 4502 +#define Z_UTIL_X2_2252 4504 +#define Z_UTIL_X2_2253 4506 +#define Z_UTIL_X2_2254 4508 +#define Z_UTIL_X2_2255 4510 +#define Z_UTIL_X2_2256 4512 +#define Z_UTIL_X2_2257 4514 +#define Z_UTIL_X2_2258 4516 +#define Z_UTIL_X2_2259 4518 +#define Z_UTIL_X2_2260 4520 +#define Z_UTIL_X2_2261 4522 +#define Z_UTIL_X2_2262 4524 +#define Z_UTIL_X2_2263 4526 +#define Z_UTIL_X2_2264 4528 +#define Z_UTIL_X2_2265 4530 +#define Z_UTIL_X2_2266 4532 +#define Z_UTIL_X2_2267 4534 +#define Z_UTIL_X2_2268 4536 +#define Z_UTIL_X2_2269 4538 +#define Z_UTIL_X2_2270 4540 +#define Z_UTIL_X2_2271 4542 +#define Z_UTIL_X2_2272 4544 +#define Z_UTIL_X2_2273 4546 +#define Z_UTIL_X2_2274 4548 +#define Z_UTIL_X2_2275 4550 +#define Z_UTIL_X2_2276 4552 +#define Z_UTIL_X2_2277 4554 +#define Z_UTIL_X2_2278 4556 +#define Z_UTIL_X2_2279 4558 +#define Z_UTIL_X2_2280 4560 +#define Z_UTIL_X2_2281 4562 +#define Z_UTIL_X2_2282 4564 +#define Z_UTIL_X2_2283 4566 +#define Z_UTIL_X2_2284 4568 +#define Z_UTIL_X2_2285 4570 +#define Z_UTIL_X2_2286 4572 +#define Z_UTIL_X2_2287 4574 +#define Z_UTIL_X2_2288 4576 +#define Z_UTIL_X2_2289 4578 +#define Z_UTIL_X2_2290 4580 +#define Z_UTIL_X2_2291 4582 +#define Z_UTIL_X2_2292 4584 +#define Z_UTIL_X2_2293 4586 +#define Z_UTIL_X2_2294 4588 +#define Z_UTIL_X2_2295 4590 +#define Z_UTIL_X2_2296 4592 +#define Z_UTIL_X2_2297 4594 +#define Z_UTIL_X2_2298 4596 +#define Z_UTIL_X2_2299 4598 +#define Z_UTIL_X2_2300 4600 +#define Z_UTIL_X2_2301 4602 +#define Z_UTIL_X2_2302 4604 +#define Z_UTIL_X2_2303 4606 +#define Z_UTIL_X2_2304 4608 +#define Z_UTIL_X2_2305 4610 +#define Z_UTIL_X2_2306 4612 +#define Z_UTIL_X2_2307 4614 +#define Z_UTIL_X2_2308 4616 +#define Z_UTIL_X2_2309 4618 +#define Z_UTIL_X2_2310 4620 +#define Z_UTIL_X2_2311 4622 +#define Z_UTIL_X2_2312 4624 +#define Z_UTIL_X2_2313 4626 +#define Z_UTIL_X2_2314 4628 +#define Z_UTIL_X2_2315 4630 +#define Z_UTIL_X2_2316 4632 +#define Z_UTIL_X2_2317 4634 +#define Z_UTIL_X2_2318 4636 +#define Z_UTIL_X2_2319 4638 +#define Z_UTIL_X2_2320 4640 +#define Z_UTIL_X2_2321 4642 +#define Z_UTIL_X2_2322 4644 +#define Z_UTIL_X2_2323 4646 +#define Z_UTIL_X2_2324 4648 +#define Z_UTIL_X2_2325 4650 +#define Z_UTIL_X2_2326 4652 +#define Z_UTIL_X2_2327 4654 +#define Z_UTIL_X2_2328 4656 +#define Z_UTIL_X2_2329 4658 +#define Z_UTIL_X2_2330 4660 +#define Z_UTIL_X2_2331 4662 +#define Z_UTIL_X2_2332 4664 +#define Z_UTIL_X2_2333 4666 +#define Z_UTIL_X2_2334 4668 +#define Z_UTIL_X2_2335 4670 +#define Z_UTIL_X2_2336 4672 +#define Z_UTIL_X2_2337 4674 +#define Z_UTIL_X2_2338 4676 +#define Z_UTIL_X2_2339 4678 +#define Z_UTIL_X2_2340 4680 +#define Z_UTIL_X2_2341 4682 +#define Z_UTIL_X2_2342 4684 +#define Z_UTIL_X2_2343 4686 +#define Z_UTIL_X2_2344 4688 +#define Z_UTIL_X2_2345 4690 +#define Z_UTIL_X2_2346 4692 +#define Z_UTIL_X2_2347 4694 +#define Z_UTIL_X2_2348 4696 +#define Z_UTIL_X2_2349 4698 +#define Z_UTIL_X2_2350 4700 +#define Z_UTIL_X2_2351 4702 +#define Z_UTIL_X2_2352 4704 +#define Z_UTIL_X2_2353 4706 +#define Z_UTIL_X2_2354 4708 +#define Z_UTIL_X2_2355 4710 +#define Z_UTIL_X2_2356 4712 +#define Z_UTIL_X2_2357 4714 +#define Z_UTIL_X2_2358 4716 +#define Z_UTIL_X2_2359 4718 +#define Z_UTIL_X2_2360 4720 +#define Z_UTIL_X2_2361 4722 +#define Z_UTIL_X2_2362 4724 +#define Z_UTIL_X2_2363 4726 +#define Z_UTIL_X2_2364 4728 +#define Z_UTIL_X2_2365 4730 +#define Z_UTIL_X2_2366 4732 +#define Z_UTIL_X2_2367 4734 +#define Z_UTIL_X2_2368 4736 +#define Z_UTIL_X2_2369 4738 +#define Z_UTIL_X2_2370 4740 +#define Z_UTIL_X2_2371 4742 +#define Z_UTIL_X2_2372 4744 +#define Z_UTIL_X2_2373 4746 +#define Z_UTIL_X2_2374 4748 +#define Z_UTIL_X2_2375 4750 +#define Z_UTIL_X2_2376 4752 +#define Z_UTIL_X2_2377 4754 +#define Z_UTIL_X2_2378 4756 +#define Z_UTIL_X2_2379 4758 +#define Z_UTIL_X2_2380 4760 +#define Z_UTIL_X2_2381 4762 +#define Z_UTIL_X2_2382 4764 +#define Z_UTIL_X2_2383 4766 +#define Z_UTIL_X2_2384 4768 +#define Z_UTIL_X2_2385 4770 +#define Z_UTIL_X2_2386 4772 +#define Z_UTIL_X2_2387 4774 +#define Z_UTIL_X2_2388 4776 +#define Z_UTIL_X2_2389 4778 +#define Z_UTIL_X2_2390 4780 +#define Z_UTIL_X2_2391 4782 +#define Z_UTIL_X2_2392 4784 +#define Z_UTIL_X2_2393 4786 +#define Z_UTIL_X2_2394 4788 +#define Z_UTIL_X2_2395 4790 +#define Z_UTIL_X2_2396 4792 +#define Z_UTIL_X2_2397 4794 +#define Z_UTIL_X2_2398 4796 +#define Z_UTIL_X2_2399 4798 +#define Z_UTIL_X2_2400 4800 +#define Z_UTIL_X2_2401 4802 +#define Z_UTIL_X2_2402 4804 +#define Z_UTIL_X2_2403 4806 +#define Z_UTIL_X2_2404 4808 +#define Z_UTIL_X2_2405 4810 +#define Z_UTIL_X2_2406 4812 +#define Z_UTIL_X2_2407 4814 +#define Z_UTIL_X2_2408 4816 +#define Z_UTIL_X2_2409 4818 +#define Z_UTIL_X2_2410 4820 +#define Z_UTIL_X2_2411 4822 +#define Z_UTIL_X2_2412 4824 +#define Z_UTIL_X2_2413 4826 +#define Z_UTIL_X2_2414 4828 +#define Z_UTIL_X2_2415 4830 +#define Z_UTIL_X2_2416 4832 +#define Z_UTIL_X2_2417 4834 +#define Z_UTIL_X2_2418 4836 +#define Z_UTIL_X2_2419 4838 +#define Z_UTIL_X2_2420 4840 +#define Z_UTIL_X2_2421 4842 +#define Z_UTIL_X2_2422 4844 +#define Z_UTIL_X2_2423 4846 +#define Z_UTIL_X2_2424 4848 +#define Z_UTIL_X2_2425 4850 +#define Z_UTIL_X2_2426 4852 +#define Z_UTIL_X2_2427 4854 +#define Z_UTIL_X2_2428 4856 +#define Z_UTIL_X2_2429 4858 +#define Z_UTIL_X2_2430 4860 +#define Z_UTIL_X2_2431 4862 +#define Z_UTIL_X2_2432 4864 +#define Z_UTIL_X2_2433 4866 +#define Z_UTIL_X2_2434 4868 +#define Z_UTIL_X2_2435 4870 +#define Z_UTIL_X2_2436 4872 +#define Z_UTIL_X2_2437 4874 +#define Z_UTIL_X2_2438 4876 +#define Z_UTIL_X2_2439 4878 +#define Z_UTIL_X2_2440 4880 +#define Z_UTIL_X2_2441 4882 +#define Z_UTIL_X2_2442 4884 +#define Z_UTIL_X2_2443 4886 +#define Z_UTIL_X2_2444 4888 +#define Z_UTIL_X2_2445 4890 +#define Z_UTIL_X2_2446 4892 +#define Z_UTIL_X2_2447 4894 +#define Z_UTIL_X2_2448 4896 +#define Z_UTIL_X2_2449 4898 +#define Z_UTIL_X2_2450 4900 +#define Z_UTIL_X2_2451 4902 +#define Z_UTIL_X2_2452 4904 +#define Z_UTIL_X2_2453 4906 +#define Z_UTIL_X2_2454 4908 +#define Z_UTIL_X2_2455 4910 +#define Z_UTIL_X2_2456 4912 +#define Z_UTIL_X2_2457 4914 +#define Z_UTIL_X2_2458 4916 +#define Z_UTIL_X2_2459 4918 +#define Z_UTIL_X2_2460 4920 +#define Z_UTIL_X2_2461 4922 +#define Z_UTIL_X2_2462 4924 +#define Z_UTIL_X2_2463 4926 +#define Z_UTIL_X2_2464 4928 +#define Z_UTIL_X2_2465 4930 +#define Z_UTIL_X2_2466 4932 +#define Z_UTIL_X2_2467 4934 +#define Z_UTIL_X2_2468 4936 +#define Z_UTIL_X2_2469 4938 +#define Z_UTIL_X2_2470 4940 +#define Z_UTIL_X2_2471 4942 +#define Z_UTIL_X2_2472 4944 +#define Z_UTIL_X2_2473 4946 +#define Z_UTIL_X2_2474 4948 +#define Z_UTIL_X2_2475 4950 +#define Z_UTIL_X2_2476 4952 +#define Z_UTIL_X2_2477 4954 +#define Z_UTIL_X2_2478 4956 +#define Z_UTIL_X2_2479 4958 +#define Z_UTIL_X2_2480 4960 +#define Z_UTIL_X2_2481 4962 +#define Z_UTIL_X2_2482 4964 +#define Z_UTIL_X2_2483 4966 +#define Z_UTIL_X2_2484 4968 +#define Z_UTIL_X2_2485 4970 +#define Z_UTIL_X2_2486 4972 +#define Z_UTIL_X2_2487 4974 +#define Z_UTIL_X2_2488 4976 +#define Z_UTIL_X2_2489 4978 +#define Z_UTIL_X2_2490 4980 +#define Z_UTIL_X2_2491 4982 +#define Z_UTIL_X2_2492 4984 +#define Z_UTIL_X2_2493 4986 +#define Z_UTIL_X2_2494 4988 +#define Z_UTIL_X2_2495 4990 +#define Z_UTIL_X2_2496 4992 +#define Z_UTIL_X2_2497 4994 +#define Z_UTIL_X2_2498 4996 +#define Z_UTIL_X2_2499 4998 +#define Z_UTIL_X2_2500 5000 +#define Z_UTIL_X2_2501 5002 +#define Z_UTIL_X2_2502 5004 +#define Z_UTIL_X2_2503 5006 +#define Z_UTIL_X2_2504 5008 +#define Z_UTIL_X2_2505 5010 +#define Z_UTIL_X2_2506 5012 +#define Z_UTIL_X2_2507 5014 +#define Z_UTIL_X2_2508 5016 +#define Z_UTIL_X2_2509 5018 +#define Z_UTIL_X2_2510 5020 +#define Z_UTIL_X2_2511 5022 +#define Z_UTIL_X2_2512 5024 +#define Z_UTIL_X2_2513 5026 +#define Z_UTIL_X2_2514 5028 +#define Z_UTIL_X2_2515 5030 +#define Z_UTIL_X2_2516 5032 +#define Z_UTIL_X2_2517 5034 +#define Z_UTIL_X2_2518 5036 +#define Z_UTIL_X2_2519 5038 +#define Z_UTIL_X2_2520 5040 +#define Z_UTIL_X2_2521 5042 +#define Z_UTIL_X2_2522 5044 +#define Z_UTIL_X2_2523 5046 +#define Z_UTIL_X2_2524 5048 +#define Z_UTIL_X2_2525 5050 +#define Z_UTIL_X2_2526 5052 +#define Z_UTIL_X2_2527 5054 +#define Z_UTIL_X2_2528 5056 +#define Z_UTIL_X2_2529 5058 +#define Z_UTIL_X2_2530 5060 +#define Z_UTIL_X2_2531 5062 +#define Z_UTIL_X2_2532 5064 +#define Z_UTIL_X2_2533 5066 +#define Z_UTIL_X2_2534 5068 +#define Z_UTIL_X2_2535 5070 +#define Z_UTIL_X2_2536 5072 +#define Z_UTIL_X2_2537 5074 +#define Z_UTIL_X2_2538 5076 +#define Z_UTIL_X2_2539 5078 +#define Z_UTIL_X2_2540 5080 +#define Z_UTIL_X2_2541 5082 +#define Z_UTIL_X2_2542 5084 +#define Z_UTIL_X2_2543 5086 +#define Z_UTIL_X2_2544 5088 +#define Z_UTIL_X2_2545 5090 +#define Z_UTIL_X2_2546 5092 +#define Z_UTIL_X2_2547 5094 +#define Z_UTIL_X2_2548 5096 +#define Z_UTIL_X2_2549 5098 +#define Z_UTIL_X2_2550 5100 +#define Z_UTIL_X2_2551 5102 +#define Z_UTIL_X2_2552 5104 +#define Z_UTIL_X2_2553 5106 +#define Z_UTIL_X2_2554 5108 +#define Z_UTIL_X2_2555 5110 +#define Z_UTIL_X2_2556 5112 +#define Z_UTIL_X2_2557 5114 +#define Z_UTIL_X2_2558 5116 +#define Z_UTIL_X2_2559 5118 +#define Z_UTIL_X2_2560 5120 +#define Z_UTIL_X2_2561 5122 +#define Z_UTIL_X2_2562 5124 +#define Z_UTIL_X2_2563 5126 +#define Z_UTIL_X2_2564 5128 +#define Z_UTIL_X2_2565 5130 +#define Z_UTIL_X2_2566 5132 +#define Z_UTIL_X2_2567 5134 +#define Z_UTIL_X2_2568 5136 +#define Z_UTIL_X2_2569 5138 +#define Z_UTIL_X2_2570 5140 +#define Z_UTIL_X2_2571 5142 +#define Z_UTIL_X2_2572 5144 +#define Z_UTIL_X2_2573 5146 +#define Z_UTIL_X2_2574 5148 +#define Z_UTIL_X2_2575 5150 +#define Z_UTIL_X2_2576 5152 +#define Z_UTIL_X2_2577 5154 +#define Z_UTIL_X2_2578 5156 +#define Z_UTIL_X2_2579 5158 +#define Z_UTIL_X2_2580 5160 +#define Z_UTIL_X2_2581 5162 +#define Z_UTIL_X2_2582 5164 +#define Z_UTIL_X2_2583 5166 +#define Z_UTIL_X2_2584 5168 +#define Z_UTIL_X2_2585 5170 +#define Z_UTIL_X2_2586 5172 +#define Z_UTIL_X2_2587 5174 +#define Z_UTIL_X2_2588 5176 +#define Z_UTIL_X2_2589 5178 +#define Z_UTIL_X2_2590 5180 +#define Z_UTIL_X2_2591 5182 +#define Z_UTIL_X2_2592 5184 +#define Z_UTIL_X2_2593 5186 +#define Z_UTIL_X2_2594 5188 +#define Z_UTIL_X2_2595 5190 +#define Z_UTIL_X2_2596 5192 +#define Z_UTIL_X2_2597 5194 +#define Z_UTIL_X2_2598 5196 +#define Z_UTIL_X2_2599 5198 +#define Z_UTIL_X2_2600 5200 +#define Z_UTIL_X2_2601 5202 +#define Z_UTIL_X2_2602 5204 +#define Z_UTIL_X2_2603 5206 +#define Z_UTIL_X2_2604 5208 +#define Z_UTIL_X2_2605 5210 +#define Z_UTIL_X2_2606 5212 +#define Z_UTIL_X2_2607 5214 +#define Z_UTIL_X2_2608 5216 +#define Z_UTIL_X2_2609 5218 +#define Z_UTIL_X2_2610 5220 +#define Z_UTIL_X2_2611 5222 +#define Z_UTIL_X2_2612 5224 +#define Z_UTIL_X2_2613 5226 +#define Z_UTIL_X2_2614 5228 +#define Z_UTIL_X2_2615 5230 +#define Z_UTIL_X2_2616 5232 +#define Z_UTIL_X2_2617 5234 +#define Z_UTIL_X2_2618 5236 +#define Z_UTIL_X2_2619 5238 +#define Z_UTIL_X2_2620 5240 +#define Z_UTIL_X2_2621 5242 +#define Z_UTIL_X2_2622 5244 +#define Z_UTIL_X2_2623 5246 +#define Z_UTIL_X2_2624 5248 +#define Z_UTIL_X2_2625 5250 +#define Z_UTIL_X2_2626 5252 +#define Z_UTIL_X2_2627 5254 +#define Z_UTIL_X2_2628 5256 +#define Z_UTIL_X2_2629 5258 +#define Z_UTIL_X2_2630 5260 +#define Z_UTIL_X2_2631 5262 +#define Z_UTIL_X2_2632 5264 +#define Z_UTIL_X2_2633 5266 +#define Z_UTIL_X2_2634 5268 +#define Z_UTIL_X2_2635 5270 +#define Z_UTIL_X2_2636 5272 +#define Z_UTIL_X2_2637 5274 +#define Z_UTIL_X2_2638 5276 +#define Z_UTIL_X2_2639 5278 +#define Z_UTIL_X2_2640 5280 +#define Z_UTIL_X2_2641 5282 +#define Z_UTIL_X2_2642 5284 +#define Z_UTIL_X2_2643 5286 +#define Z_UTIL_X2_2644 5288 +#define Z_UTIL_X2_2645 5290 +#define Z_UTIL_X2_2646 5292 +#define Z_UTIL_X2_2647 5294 +#define Z_UTIL_X2_2648 5296 +#define Z_UTIL_X2_2649 5298 +#define Z_UTIL_X2_2650 5300 +#define Z_UTIL_X2_2651 5302 +#define Z_UTIL_X2_2652 5304 +#define Z_UTIL_X2_2653 5306 +#define Z_UTIL_X2_2654 5308 +#define Z_UTIL_X2_2655 5310 +#define Z_UTIL_X2_2656 5312 +#define Z_UTIL_X2_2657 5314 +#define Z_UTIL_X2_2658 5316 +#define Z_UTIL_X2_2659 5318 +#define Z_UTIL_X2_2660 5320 +#define Z_UTIL_X2_2661 5322 +#define Z_UTIL_X2_2662 5324 +#define Z_UTIL_X2_2663 5326 +#define Z_UTIL_X2_2664 5328 +#define Z_UTIL_X2_2665 5330 +#define Z_UTIL_X2_2666 5332 +#define Z_UTIL_X2_2667 5334 +#define Z_UTIL_X2_2668 5336 +#define Z_UTIL_X2_2669 5338 +#define Z_UTIL_X2_2670 5340 +#define Z_UTIL_X2_2671 5342 +#define Z_UTIL_X2_2672 5344 +#define Z_UTIL_X2_2673 5346 +#define Z_UTIL_X2_2674 5348 +#define Z_UTIL_X2_2675 5350 +#define Z_UTIL_X2_2676 5352 +#define Z_UTIL_X2_2677 5354 +#define Z_UTIL_X2_2678 5356 +#define Z_UTIL_X2_2679 5358 +#define Z_UTIL_X2_2680 5360 +#define Z_UTIL_X2_2681 5362 +#define Z_UTIL_X2_2682 5364 +#define Z_UTIL_X2_2683 5366 +#define Z_UTIL_X2_2684 5368 +#define Z_UTIL_X2_2685 5370 +#define Z_UTIL_X2_2686 5372 +#define Z_UTIL_X2_2687 5374 +#define Z_UTIL_X2_2688 5376 +#define Z_UTIL_X2_2689 5378 +#define Z_UTIL_X2_2690 5380 +#define Z_UTIL_X2_2691 5382 +#define Z_UTIL_X2_2692 5384 +#define Z_UTIL_X2_2693 5386 +#define Z_UTIL_X2_2694 5388 +#define Z_UTIL_X2_2695 5390 +#define Z_UTIL_X2_2696 5392 +#define Z_UTIL_X2_2697 5394 +#define Z_UTIL_X2_2698 5396 +#define Z_UTIL_X2_2699 5398 +#define Z_UTIL_X2_2700 5400 +#define Z_UTIL_X2_2701 5402 +#define Z_UTIL_X2_2702 5404 +#define Z_UTIL_X2_2703 5406 +#define Z_UTIL_X2_2704 5408 +#define Z_UTIL_X2_2705 5410 +#define Z_UTIL_X2_2706 5412 +#define Z_UTIL_X2_2707 5414 +#define Z_UTIL_X2_2708 5416 +#define Z_UTIL_X2_2709 5418 +#define Z_UTIL_X2_2710 5420 +#define Z_UTIL_X2_2711 5422 +#define Z_UTIL_X2_2712 5424 +#define Z_UTIL_X2_2713 5426 +#define Z_UTIL_X2_2714 5428 +#define Z_UTIL_X2_2715 5430 +#define Z_UTIL_X2_2716 5432 +#define Z_UTIL_X2_2717 5434 +#define Z_UTIL_X2_2718 5436 +#define Z_UTIL_X2_2719 5438 +#define Z_UTIL_X2_2720 5440 +#define Z_UTIL_X2_2721 5442 +#define Z_UTIL_X2_2722 5444 +#define Z_UTIL_X2_2723 5446 +#define Z_UTIL_X2_2724 5448 +#define Z_UTIL_X2_2725 5450 +#define Z_UTIL_X2_2726 5452 +#define Z_UTIL_X2_2727 5454 +#define Z_UTIL_X2_2728 5456 +#define Z_UTIL_X2_2729 5458 +#define Z_UTIL_X2_2730 5460 +#define Z_UTIL_X2_2731 5462 +#define Z_UTIL_X2_2732 5464 +#define Z_UTIL_X2_2733 5466 +#define Z_UTIL_X2_2734 5468 +#define Z_UTIL_X2_2735 5470 +#define Z_UTIL_X2_2736 5472 +#define Z_UTIL_X2_2737 5474 +#define Z_UTIL_X2_2738 5476 +#define Z_UTIL_X2_2739 5478 +#define Z_UTIL_X2_2740 5480 +#define Z_UTIL_X2_2741 5482 +#define Z_UTIL_X2_2742 5484 +#define Z_UTIL_X2_2743 5486 +#define Z_UTIL_X2_2744 5488 +#define Z_UTIL_X2_2745 5490 +#define Z_UTIL_X2_2746 5492 +#define Z_UTIL_X2_2747 5494 +#define Z_UTIL_X2_2748 5496 +#define Z_UTIL_X2_2749 5498 +#define Z_UTIL_X2_2750 5500 +#define Z_UTIL_X2_2751 5502 +#define Z_UTIL_X2_2752 5504 +#define Z_UTIL_X2_2753 5506 +#define Z_UTIL_X2_2754 5508 +#define Z_UTIL_X2_2755 5510 +#define Z_UTIL_X2_2756 5512 +#define Z_UTIL_X2_2757 5514 +#define Z_UTIL_X2_2758 5516 +#define Z_UTIL_X2_2759 5518 +#define Z_UTIL_X2_2760 5520 +#define Z_UTIL_X2_2761 5522 +#define Z_UTIL_X2_2762 5524 +#define Z_UTIL_X2_2763 5526 +#define Z_UTIL_X2_2764 5528 +#define Z_UTIL_X2_2765 5530 +#define Z_UTIL_X2_2766 5532 +#define Z_UTIL_X2_2767 5534 +#define Z_UTIL_X2_2768 5536 +#define Z_UTIL_X2_2769 5538 +#define Z_UTIL_X2_2770 5540 +#define Z_UTIL_X2_2771 5542 +#define Z_UTIL_X2_2772 5544 +#define Z_UTIL_X2_2773 5546 +#define Z_UTIL_X2_2774 5548 +#define Z_UTIL_X2_2775 5550 +#define Z_UTIL_X2_2776 5552 +#define Z_UTIL_X2_2777 5554 +#define Z_UTIL_X2_2778 5556 +#define Z_UTIL_X2_2779 5558 +#define Z_UTIL_X2_2780 5560 +#define Z_UTIL_X2_2781 5562 +#define Z_UTIL_X2_2782 5564 +#define Z_UTIL_X2_2783 5566 +#define Z_UTIL_X2_2784 5568 +#define Z_UTIL_X2_2785 5570 +#define Z_UTIL_X2_2786 5572 +#define Z_UTIL_X2_2787 5574 +#define Z_UTIL_X2_2788 5576 +#define Z_UTIL_X2_2789 5578 +#define Z_UTIL_X2_2790 5580 +#define Z_UTIL_X2_2791 5582 +#define Z_UTIL_X2_2792 5584 +#define Z_UTIL_X2_2793 5586 +#define Z_UTIL_X2_2794 5588 +#define Z_UTIL_X2_2795 5590 +#define Z_UTIL_X2_2796 5592 +#define Z_UTIL_X2_2797 5594 +#define Z_UTIL_X2_2798 5596 +#define Z_UTIL_X2_2799 5598 +#define Z_UTIL_X2_2800 5600 +#define Z_UTIL_X2_2801 5602 +#define Z_UTIL_X2_2802 5604 +#define Z_UTIL_X2_2803 5606 +#define Z_UTIL_X2_2804 5608 +#define Z_UTIL_X2_2805 5610 +#define Z_UTIL_X2_2806 5612 +#define Z_UTIL_X2_2807 5614 +#define Z_UTIL_X2_2808 5616 +#define Z_UTIL_X2_2809 5618 +#define Z_UTIL_X2_2810 5620 +#define Z_UTIL_X2_2811 5622 +#define Z_UTIL_X2_2812 5624 +#define Z_UTIL_X2_2813 5626 +#define Z_UTIL_X2_2814 5628 +#define Z_UTIL_X2_2815 5630 +#define Z_UTIL_X2_2816 5632 +#define Z_UTIL_X2_2817 5634 +#define Z_UTIL_X2_2818 5636 +#define Z_UTIL_X2_2819 5638 +#define Z_UTIL_X2_2820 5640 +#define Z_UTIL_X2_2821 5642 +#define Z_UTIL_X2_2822 5644 +#define Z_UTIL_X2_2823 5646 +#define Z_UTIL_X2_2824 5648 +#define Z_UTIL_X2_2825 5650 +#define Z_UTIL_X2_2826 5652 +#define Z_UTIL_X2_2827 5654 +#define Z_UTIL_X2_2828 5656 +#define Z_UTIL_X2_2829 5658 +#define Z_UTIL_X2_2830 5660 +#define Z_UTIL_X2_2831 5662 +#define Z_UTIL_X2_2832 5664 +#define Z_UTIL_X2_2833 5666 +#define Z_UTIL_X2_2834 5668 +#define Z_UTIL_X2_2835 5670 +#define Z_UTIL_X2_2836 5672 +#define Z_UTIL_X2_2837 5674 +#define Z_UTIL_X2_2838 5676 +#define Z_UTIL_X2_2839 5678 +#define Z_UTIL_X2_2840 5680 +#define Z_UTIL_X2_2841 5682 +#define Z_UTIL_X2_2842 5684 +#define Z_UTIL_X2_2843 5686 +#define Z_UTIL_X2_2844 5688 +#define Z_UTIL_X2_2845 5690 +#define Z_UTIL_X2_2846 5692 +#define Z_UTIL_X2_2847 5694 +#define Z_UTIL_X2_2848 5696 +#define Z_UTIL_X2_2849 5698 +#define Z_UTIL_X2_2850 5700 +#define Z_UTIL_X2_2851 5702 +#define Z_UTIL_X2_2852 5704 +#define Z_UTIL_X2_2853 5706 +#define Z_UTIL_X2_2854 5708 +#define Z_UTIL_X2_2855 5710 +#define Z_UTIL_X2_2856 5712 +#define Z_UTIL_X2_2857 5714 +#define Z_UTIL_X2_2858 5716 +#define Z_UTIL_X2_2859 5718 +#define Z_UTIL_X2_2860 5720 +#define Z_UTIL_X2_2861 5722 +#define Z_UTIL_X2_2862 5724 +#define Z_UTIL_X2_2863 5726 +#define Z_UTIL_X2_2864 5728 +#define Z_UTIL_X2_2865 5730 +#define Z_UTIL_X2_2866 5732 +#define Z_UTIL_X2_2867 5734 +#define Z_UTIL_X2_2868 5736 +#define Z_UTIL_X2_2869 5738 +#define Z_UTIL_X2_2870 5740 +#define Z_UTIL_X2_2871 5742 +#define Z_UTIL_X2_2872 5744 +#define Z_UTIL_X2_2873 5746 +#define Z_UTIL_X2_2874 5748 +#define Z_UTIL_X2_2875 5750 +#define Z_UTIL_X2_2876 5752 +#define Z_UTIL_X2_2877 5754 +#define Z_UTIL_X2_2878 5756 +#define Z_UTIL_X2_2879 5758 +#define Z_UTIL_X2_2880 5760 +#define Z_UTIL_X2_2881 5762 +#define Z_UTIL_X2_2882 5764 +#define Z_UTIL_X2_2883 5766 +#define Z_UTIL_X2_2884 5768 +#define Z_UTIL_X2_2885 5770 +#define Z_UTIL_X2_2886 5772 +#define Z_UTIL_X2_2887 5774 +#define Z_UTIL_X2_2888 5776 +#define Z_UTIL_X2_2889 5778 +#define Z_UTIL_X2_2890 5780 +#define Z_UTIL_X2_2891 5782 +#define Z_UTIL_X2_2892 5784 +#define Z_UTIL_X2_2893 5786 +#define Z_UTIL_X2_2894 5788 +#define Z_UTIL_X2_2895 5790 +#define Z_UTIL_X2_2896 5792 +#define Z_UTIL_X2_2897 5794 +#define Z_UTIL_X2_2898 5796 +#define Z_UTIL_X2_2899 5798 +#define Z_UTIL_X2_2900 5800 +#define Z_UTIL_X2_2901 5802 +#define Z_UTIL_X2_2902 5804 +#define Z_UTIL_X2_2903 5806 +#define Z_UTIL_X2_2904 5808 +#define Z_UTIL_X2_2905 5810 +#define Z_UTIL_X2_2906 5812 +#define Z_UTIL_X2_2907 5814 +#define Z_UTIL_X2_2908 5816 +#define Z_UTIL_X2_2909 5818 +#define Z_UTIL_X2_2910 5820 +#define Z_UTIL_X2_2911 5822 +#define Z_UTIL_X2_2912 5824 +#define Z_UTIL_X2_2913 5826 +#define Z_UTIL_X2_2914 5828 +#define Z_UTIL_X2_2915 5830 +#define Z_UTIL_X2_2916 5832 +#define Z_UTIL_X2_2917 5834 +#define Z_UTIL_X2_2918 5836 +#define Z_UTIL_X2_2919 5838 +#define Z_UTIL_X2_2920 5840 +#define Z_UTIL_X2_2921 5842 +#define Z_UTIL_X2_2922 5844 +#define Z_UTIL_X2_2923 5846 +#define Z_UTIL_X2_2924 5848 +#define Z_UTIL_X2_2925 5850 +#define Z_UTIL_X2_2926 5852 +#define Z_UTIL_X2_2927 5854 +#define Z_UTIL_X2_2928 5856 +#define Z_UTIL_X2_2929 5858 +#define Z_UTIL_X2_2930 5860 +#define Z_UTIL_X2_2931 5862 +#define Z_UTIL_X2_2932 5864 +#define Z_UTIL_X2_2933 5866 +#define Z_UTIL_X2_2934 5868 +#define Z_UTIL_X2_2935 5870 +#define Z_UTIL_X2_2936 5872 +#define Z_UTIL_X2_2937 5874 +#define Z_UTIL_X2_2938 5876 +#define Z_UTIL_X2_2939 5878 +#define Z_UTIL_X2_2940 5880 +#define Z_UTIL_X2_2941 5882 +#define Z_UTIL_X2_2942 5884 +#define Z_UTIL_X2_2943 5886 +#define Z_UTIL_X2_2944 5888 +#define Z_UTIL_X2_2945 5890 +#define Z_UTIL_X2_2946 5892 +#define Z_UTIL_X2_2947 5894 +#define Z_UTIL_X2_2948 5896 +#define Z_UTIL_X2_2949 5898 +#define Z_UTIL_X2_2950 5900 +#define Z_UTIL_X2_2951 5902 +#define Z_UTIL_X2_2952 5904 +#define Z_UTIL_X2_2953 5906 +#define Z_UTIL_X2_2954 5908 +#define Z_UTIL_X2_2955 5910 +#define Z_UTIL_X2_2956 5912 +#define Z_UTIL_X2_2957 5914 +#define Z_UTIL_X2_2958 5916 +#define Z_UTIL_X2_2959 5918 +#define Z_UTIL_X2_2960 5920 +#define Z_UTIL_X2_2961 5922 +#define Z_UTIL_X2_2962 5924 +#define Z_UTIL_X2_2963 5926 +#define Z_UTIL_X2_2964 5928 +#define Z_UTIL_X2_2965 5930 +#define Z_UTIL_X2_2966 5932 +#define Z_UTIL_X2_2967 5934 +#define Z_UTIL_X2_2968 5936 +#define Z_UTIL_X2_2969 5938 +#define Z_UTIL_X2_2970 5940 +#define Z_UTIL_X2_2971 5942 +#define Z_UTIL_X2_2972 5944 +#define Z_UTIL_X2_2973 5946 +#define Z_UTIL_X2_2974 5948 +#define Z_UTIL_X2_2975 5950 +#define Z_UTIL_X2_2976 5952 +#define Z_UTIL_X2_2977 5954 +#define Z_UTIL_X2_2978 5956 +#define Z_UTIL_X2_2979 5958 +#define Z_UTIL_X2_2980 5960 +#define Z_UTIL_X2_2981 5962 +#define Z_UTIL_X2_2982 5964 +#define Z_UTIL_X2_2983 5966 +#define Z_UTIL_X2_2984 5968 +#define Z_UTIL_X2_2985 5970 +#define Z_UTIL_X2_2986 5972 +#define Z_UTIL_X2_2987 5974 +#define Z_UTIL_X2_2988 5976 +#define Z_UTIL_X2_2989 5978 +#define Z_UTIL_X2_2990 5980 +#define Z_UTIL_X2_2991 5982 +#define Z_UTIL_X2_2992 5984 +#define Z_UTIL_X2_2993 5986 +#define Z_UTIL_X2_2994 5988 +#define Z_UTIL_X2_2995 5990 +#define Z_UTIL_X2_2996 5992 +#define Z_UTIL_X2_2997 5994 +#define Z_UTIL_X2_2998 5996 +#define Z_UTIL_X2_2999 5998 +#define Z_UTIL_X2_3000 6000 +#define Z_UTIL_X2_3001 6002 +#define Z_UTIL_X2_3002 6004 +#define Z_UTIL_X2_3003 6006 +#define Z_UTIL_X2_3004 6008 +#define Z_UTIL_X2_3005 6010 +#define Z_UTIL_X2_3006 6012 +#define Z_UTIL_X2_3007 6014 +#define Z_UTIL_X2_3008 6016 +#define Z_UTIL_X2_3009 6018 +#define Z_UTIL_X2_3010 6020 +#define Z_UTIL_X2_3011 6022 +#define Z_UTIL_X2_3012 6024 +#define Z_UTIL_X2_3013 6026 +#define Z_UTIL_X2_3014 6028 +#define Z_UTIL_X2_3015 6030 +#define Z_UTIL_X2_3016 6032 +#define Z_UTIL_X2_3017 6034 +#define Z_UTIL_X2_3018 6036 +#define Z_UTIL_X2_3019 6038 +#define Z_UTIL_X2_3020 6040 +#define Z_UTIL_X2_3021 6042 +#define Z_UTIL_X2_3022 6044 +#define Z_UTIL_X2_3023 6046 +#define Z_UTIL_X2_3024 6048 +#define Z_UTIL_X2_3025 6050 +#define Z_UTIL_X2_3026 6052 +#define Z_UTIL_X2_3027 6054 +#define Z_UTIL_X2_3028 6056 +#define Z_UTIL_X2_3029 6058 +#define Z_UTIL_X2_3030 6060 +#define Z_UTIL_X2_3031 6062 +#define Z_UTIL_X2_3032 6064 +#define Z_UTIL_X2_3033 6066 +#define Z_UTIL_X2_3034 6068 +#define Z_UTIL_X2_3035 6070 +#define Z_UTIL_X2_3036 6072 +#define Z_UTIL_X2_3037 6074 +#define Z_UTIL_X2_3038 6076 +#define Z_UTIL_X2_3039 6078 +#define Z_UTIL_X2_3040 6080 +#define Z_UTIL_X2_3041 6082 +#define Z_UTIL_X2_3042 6084 +#define Z_UTIL_X2_3043 6086 +#define Z_UTIL_X2_3044 6088 +#define Z_UTIL_X2_3045 6090 +#define Z_UTIL_X2_3046 6092 +#define Z_UTIL_X2_3047 6094 +#define Z_UTIL_X2_3048 6096 +#define Z_UTIL_X2_3049 6098 +#define Z_UTIL_X2_3050 6100 +#define Z_UTIL_X2_3051 6102 +#define Z_UTIL_X2_3052 6104 +#define Z_UTIL_X2_3053 6106 +#define Z_UTIL_X2_3054 6108 +#define Z_UTIL_X2_3055 6110 +#define Z_UTIL_X2_3056 6112 +#define Z_UTIL_X2_3057 6114 +#define Z_UTIL_X2_3058 6116 +#define Z_UTIL_X2_3059 6118 +#define Z_UTIL_X2_3060 6120 +#define Z_UTIL_X2_3061 6122 +#define Z_UTIL_X2_3062 6124 +#define Z_UTIL_X2_3063 6126 +#define Z_UTIL_X2_3064 6128 +#define Z_UTIL_X2_3065 6130 +#define Z_UTIL_X2_3066 6132 +#define Z_UTIL_X2_3067 6134 +#define Z_UTIL_X2_3068 6136 +#define Z_UTIL_X2_3069 6138 +#define Z_UTIL_X2_3070 6140 +#define Z_UTIL_X2_3071 6142 +#define Z_UTIL_X2_3072 6144 +#define Z_UTIL_X2_3073 6146 +#define Z_UTIL_X2_3074 6148 +#define Z_UTIL_X2_3075 6150 +#define Z_UTIL_X2_3076 6152 +#define Z_UTIL_X2_3077 6154 +#define Z_UTIL_X2_3078 6156 +#define Z_UTIL_X2_3079 6158 +#define Z_UTIL_X2_3080 6160 +#define Z_UTIL_X2_3081 6162 +#define Z_UTIL_X2_3082 6164 +#define Z_UTIL_X2_3083 6166 +#define Z_UTIL_X2_3084 6168 +#define Z_UTIL_X2_3085 6170 +#define Z_UTIL_X2_3086 6172 +#define Z_UTIL_X2_3087 6174 +#define Z_UTIL_X2_3088 6176 +#define Z_UTIL_X2_3089 6178 +#define Z_UTIL_X2_3090 6180 +#define Z_UTIL_X2_3091 6182 +#define Z_UTIL_X2_3092 6184 +#define Z_UTIL_X2_3093 6186 +#define Z_UTIL_X2_3094 6188 +#define Z_UTIL_X2_3095 6190 +#define Z_UTIL_X2_3096 6192 +#define Z_UTIL_X2_3097 6194 +#define Z_UTIL_X2_3098 6196 +#define Z_UTIL_X2_3099 6198 +#define Z_UTIL_X2_3100 6200 +#define Z_UTIL_X2_3101 6202 +#define Z_UTIL_X2_3102 6204 +#define Z_UTIL_X2_3103 6206 +#define Z_UTIL_X2_3104 6208 +#define Z_UTIL_X2_3105 6210 +#define Z_UTIL_X2_3106 6212 +#define Z_UTIL_X2_3107 6214 +#define Z_UTIL_X2_3108 6216 +#define Z_UTIL_X2_3109 6218 +#define Z_UTIL_X2_3110 6220 +#define Z_UTIL_X2_3111 6222 +#define Z_UTIL_X2_3112 6224 +#define Z_UTIL_X2_3113 6226 +#define Z_UTIL_X2_3114 6228 +#define Z_UTIL_X2_3115 6230 +#define Z_UTIL_X2_3116 6232 +#define Z_UTIL_X2_3117 6234 +#define Z_UTIL_X2_3118 6236 +#define Z_UTIL_X2_3119 6238 +#define Z_UTIL_X2_3120 6240 +#define Z_UTIL_X2_3121 6242 +#define Z_UTIL_X2_3122 6244 +#define Z_UTIL_X2_3123 6246 +#define Z_UTIL_X2_3124 6248 +#define Z_UTIL_X2_3125 6250 +#define Z_UTIL_X2_3126 6252 +#define Z_UTIL_X2_3127 6254 +#define Z_UTIL_X2_3128 6256 +#define Z_UTIL_X2_3129 6258 +#define Z_UTIL_X2_3130 6260 +#define Z_UTIL_X2_3131 6262 +#define Z_UTIL_X2_3132 6264 +#define Z_UTIL_X2_3133 6266 +#define Z_UTIL_X2_3134 6268 +#define Z_UTIL_X2_3135 6270 +#define Z_UTIL_X2_3136 6272 +#define Z_UTIL_X2_3137 6274 +#define Z_UTIL_X2_3138 6276 +#define Z_UTIL_X2_3139 6278 +#define Z_UTIL_X2_3140 6280 +#define Z_UTIL_X2_3141 6282 +#define Z_UTIL_X2_3142 6284 +#define Z_UTIL_X2_3143 6286 +#define Z_UTIL_X2_3144 6288 +#define Z_UTIL_X2_3145 6290 +#define Z_UTIL_X2_3146 6292 +#define Z_UTIL_X2_3147 6294 +#define Z_UTIL_X2_3148 6296 +#define Z_UTIL_X2_3149 6298 +#define Z_UTIL_X2_3150 6300 +#define Z_UTIL_X2_3151 6302 +#define Z_UTIL_X2_3152 6304 +#define Z_UTIL_X2_3153 6306 +#define Z_UTIL_X2_3154 6308 +#define Z_UTIL_X2_3155 6310 +#define Z_UTIL_X2_3156 6312 +#define Z_UTIL_X2_3157 6314 +#define Z_UTIL_X2_3158 6316 +#define Z_UTIL_X2_3159 6318 +#define Z_UTIL_X2_3160 6320 +#define Z_UTIL_X2_3161 6322 +#define Z_UTIL_X2_3162 6324 +#define Z_UTIL_X2_3163 6326 +#define Z_UTIL_X2_3164 6328 +#define Z_UTIL_X2_3165 6330 +#define Z_UTIL_X2_3166 6332 +#define Z_UTIL_X2_3167 6334 +#define Z_UTIL_X2_3168 6336 +#define Z_UTIL_X2_3169 6338 +#define Z_UTIL_X2_3170 6340 +#define Z_UTIL_X2_3171 6342 +#define Z_UTIL_X2_3172 6344 +#define Z_UTIL_X2_3173 6346 +#define Z_UTIL_X2_3174 6348 +#define Z_UTIL_X2_3175 6350 +#define Z_UTIL_X2_3176 6352 +#define Z_UTIL_X2_3177 6354 +#define Z_UTIL_X2_3178 6356 +#define Z_UTIL_X2_3179 6358 +#define Z_UTIL_X2_3180 6360 +#define Z_UTIL_X2_3181 6362 +#define Z_UTIL_X2_3182 6364 +#define Z_UTIL_X2_3183 6366 +#define Z_UTIL_X2_3184 6368 +#define Z_UTIL_X2_3185 6370 +#define Z_UTIL_X2_3186 6372 +#define Z_UTIL_X2_3187 6374 +#define Z_UTIL_X2_3188 6376 +#define Z_UTIL_X2_3189 6378 +#define Z_UTIL_X2_3190 6380 +#define Z_UTIL_X2_3191 6382 +#define Z_UTIL_X2_3192 6384 +#define Z_UTIL_X2_3193 6386 +#define Z_UTIL_X2_3194 6388 +#define Z_UTIL_X2_3195 6390 +#define Z_UTIL_X2_3196 6392 +#define Z_UTIL_X2_3197 6394 +#define Z_UTIL_X2_3198 6396 +#define Z_UTIL_X2_3199 6398 +#define Z_UTIL_X2_3200 6400 +#define Z_UTIL_X2_3201 6402 +#define Z_UTIL_X2_3202 6404 +#define Z_UTIL_X2_3203 6406 +#define Z_UTIL_X2_3204 6408 +#define Z_UTIL_X2_3205 6410 +#define Z_UTIL_X2_3206 6412 +#define Z_UTIL_X2_3207 6414 +#define Z_UTIL_X2_3208 6416 +#define Z_UTIL_X2_3209 6418 +#define Z_UTIL_X2_3210 6420 +#define Z_UTIL_X2_3211 6422 +#define Z_UTIL_X2_3212 6424 +#define Z_UTIL_X2_3213 6426 +#define Z_UTIL_X2_3214 6428 +#define Z_UTIL_X2_3215 6430 +#define Z_UTIL_X2_3216 6432 +#define Z_UTIL_X2_3217 6434 +#define Z_UTIL_X2_3218 6436 +#define Z_UTIL_X2_3219 6438 +#define Z_UTIL_X2_3220 6440 +#define Z_UTIL_X2_3221 6442 +#define Z_UTIL_X2_3222 6444 +#define Z_UTIL_X2_3223 6446 +#define Z_UTIL_X2_3224 6448 +#define Z_UTIL_X2_3225 6450 +#define Z_UTIL_X2_3226 6452 +#define Z_UTIL_X2_3227 6454 +#define Z_UTIL_X2_3228 6456 +#define Z_UTIL_X2_3229 6458 +#define Z_UTIL_X2_3230 6460 +#define Z_UTIL_X2_3231 6462 +#define Z_UTIL_X2_3232 6464 +#define Z_UTIL_X2_3233 6466 +#define Z_UTIL_X2_3234 6468 +#define Z_UTIL_X2_3235 6470 +#define Z_UTIL_X2_3236 6472 +#define Z_UTIL_X2_3237 6474 +#define Z_UTIL_X2_3238 6476 +#define Z_UTIL_X2_3239 6478 +#define Z_UTIL_X2_3240 6480 +#define Z_UTIL_X2_3241 6482 +#define Z_UTIL_X2_3242 6484 +#define Z_UTIL_X2_3243 6486 +#define Z_UTIL_X2_3244 6488 +#define Z_UTIL_X2_3245 6490 +#define Z_UTIL_X2_3246 6492 +#define Z_UTIL_X2_3247 6494 +#define Z_UTIL_X2_3248 6496 +#define Z_UTIL_X2_3249 6498 +#define Z_UTIL_X2_3250 6500 +#define Z_UTIL_X2_3251 6502 +#define Z_UTIL_X2_3252 6504 +#define Z_UTIL_X2_3253 6506 +#define Z_UTIL_X2_3254 6508 +#define Z_UTIL_X2_3255 6510 +#define Z_UTIL_X2_3256 6512 +#define Z_UTIL_X2_3257 6514 +#define Z_UTIL_X2_3258 6516 +#define Z_UTIL_X2_3259 6518 +#define Z_UTIL_X2_3260 6520 +#define Z_UTIL_X2_3261 6522 +#define Z_UTIL_X2_3262 6524 +#define Z_UTIL_X2_3263 6526 +#define Z_UTIL_X2_3264 6528 +#define Z_UTIL_X2_3265 6530 +#define Z_UTIL_X2_3266 6532 +#define Z_UTIL_X2_3267 6534 +#define Z_UTIL_X2_3268 6536 +#define Z_UTIL_X2_3269 6538 +#define Z_UTIL_X2_3270 6540 +#define Z_UTIL_X2_3271 6542 +#define Z_UTIL_X2_3272 6544 +#define Z_UTIL_X2_3273 6546 +#define Z_UTIL_X2_3274 6548 +#define Z_UTIL_X2_3275 6550 +#define Z_UTIL_X2_3276 6552 +#define Z_UTIL_X2_3277 6554 +#define Z_UTIL_X2_3278 6556 +#define Z_UTIL_X2_3279 6558 +#define Z_UTIL_X2_3280 6560 +#define Z_UTIL_X2_3281 6562 +#define Z_UTIL_X2_3282 6564 +#define Z_UTIL_X2_3283 6566 +#define Z_UTIL_X2_3284 6568 +#define Z_UTIL_X2_3285 6570 +#define Z_UTIL_X2_3286 6572 +#define Z_UTIL_X2_3287 6574 +#define Z_UTIL_X2_3288 6576 +#define Z_UTIL_X2_3289 6578 +#define Z_UTIL_X2_3290 6580 +#define Z_UTIL_X2_3291 6582 +#define Z_UTIL_X2_3292 6584 +#define Z_UTIL_X2_3293 6586 +#define Z_UTIL_X2_3294 6588 +#define Z_UTIL_X2_3295 6590 +#define Z_UTIL_X2_3296 6592 +#define Z_UTIL_X2_3297 6594 +#define Z_UTIL_X2_3298 6596 +#define Z_UTIL_X2_3299 6598 +#define Z_UTIL_X2_3300 6600 +#define Z_UTIL_X2_3301 6602 +#define Z_UTIL_X2_3302 6604 +#define Z_UTIL_X2_3303 6606 +#define Z_UTIL_X2_3304 6608 +#define Z_UTIL_X2_3305 6610 +#define Z_UTIL_X2_3306 6612 +#define Z_UTIL_X2_3307 6614 +#define Z_UTIL_X2_3308 6616 +#define Z_UTIL_X2_3309 6618 +#define Z_UTIL_X2_3310 6620 +#define Z_UTIL_X2_3311 6622 +#define Z_UTIL_X2_3312 6624 +#define Z_UTIL_X2_3313 6626 +#define Z_UTIL_X2_3314 6628 +#define Z_UTIL_X2_3315 6630 +#define Z_UTIL_X2_3316 6632 +#define Z_UTIL_X2_3317 6634 +#define Z_UTIL_X2_3318 6636 +#define Z_UTIL_X2_3319 6638 +#define Z_UTIL_X2_3320 6640 +#define Z_UTIL_X2_3321 6642 +#define Z_UTIL_X2_3322 6644 +#define Z_UTIL_X2_3323 6646 +#define Z_UTIL_X2_3324 6648 +#define Z_UTIL_X2_3325 6650 +#define Z_UTIL_X2_3326 6652 +#define Z_UTIL_X2_3327 6654 +#define Z_UTIL_X2_3328 6656 +#define Z_UTIL_X2_3329 6658 +#define Z_UTIL_X2_3330 6660 +#define Z_UTIL_X2_3331 6662 +#define Z_UTIL_X2_3332 6664 +#define Z_UTIL_X2_3333 6666 +#define Z_UTIL_X2_3334 6668 +#define Z_UTIL_X2_3335 6670 +#define Z_UTIL_X2_3336 6672 +#define Z_UTIL_X2_3337 6674 +#define Z_UTIL_X2_3338 6676 +#define Z_UTIL_X2_3339 6678 +#define Z_UTIL_X2_3340 6680 +#define Z_UTIL_X2_3341 6682 +#define Z_UTIL_X2_3342 6684 +#define Z_UTIL_X2_3343 6686 +#define Z_UTIL_X2_3344 6688 +#define Z_UTIL_X2_3345 6690 +#define Z_UTIL_X2_3346 6692 +#define Z_UTIL_X2_3347 6694 +#define Z_UTIL_X2_3348 6696 +#define Z_UTIL_X2_3349 6698 +#define Z_UTIL_X2_3350 6700 +#define Z_UTIL_X2_3351 6702 +#define Z_UTIL_X2_3352 6704 +#define Z_UTIL_X2_3353 6706 +#define Z_UTIL_X2_3354 6708 +#define Z_UTIL_X2_3355 6710 +#define Z_UTIL_X2_3356 6712 +#define Z_UTIL_X2_3357 6714 +#define Z_UTIL_X2_3358 6716 +#define Z_UTIL_X2_3359 6718 +#define Z_UTIL_X2_3360 6720 +#define Z_UTIL_X2_3361 6722 +#define Z_UTIL_X2_3362 6724 +#define Z_UTIL_X2_3363 6726 +#define Z_UTIL_X2_3364 6728 +#define Z_UTIL_X2_3365 6730 +#define Z_UTIL_X2_3366 6732 +#define Z_UTIL_X2_3367 6734 +#define Z_UTIL_X2_3368 6736 +#define Z_UTIL_X2_3369 6738 +#define Z_UTIL_X2_3370 6740 +#define Z_UTIL_X2_3371 6742 +#define Z_UTIL_X2_3372 6744 +#define Z_UTIL_X2_3373 6746 +#define Z_UTIL_X2_3374 6748 +#define Z_UTIL_X2_3375 6750 +#define Z_UTIL_X2_3376 6752 +#define Z_UTIL_X2_3377 6754 +#define Z_UTIL_X2_3378 6756 +#define Z_UTIL_X2_3379 6758 +#define Z_UTIL_X2_3380 6760 +#define Z_UTIL_X2_3381 6762 +#define Z_UTIL_X2_3382 6764 +#define Z_UTIL_X2_3383 6766 +#define Z_UTIL_X2_3384 6768 +#define Z_UTIL_X2_3385 6770 +#define Z_UTIL_X2_3386 6772 +#define Z_UTIL_X2_3387 6774 +#define Z_UTIL_X2_3388 6776 +#define Z_UTIL_X2_3389 6778 +#define Z_UTIL_X2_3390 6780 +#define Z_UTIL_X2_3391 6782 +#define Z_UTIL_X2_3392 6784 +#define Z_UTIL_X2_3393 6786 +#define Z_UTIL_X2_3394 6788 +#define Z_UTIL_X2_3395 6790 +#define Z_UTIL_X2_3396 6792 +#define Z_UTIL_X2_3397 6794 +#define Z_UTIL_X2_3398 6796 +#define Z_UTIL_X2_3399 6798 +#define Z_UTIL_X2_3400 6800 +#define Z_UTIL_X2_3401 6802 +#define Z_UTIL_X2_3402 6804 +#define Z_UTIL_X2_3403 6806 +#define Z_UTIL_X2_3404 6808 +#define Z_UTIL_X2_3405 6810 +#define Z_UTIL_X2_3406 6812 +#define Z_UTIL_X2_3407 6814 +#define Z_UTIL_X2_3408 6816 +#define Z_UTIL_X2_3409 6818 +#define Z_UTIL_X2_3410 6820 +#define Z_UTIL_X2_3411 6822 +#define Z_UTIL_X2_3412 6824 +#define Z_UTIL_X2_3413 6826 +#define Z_UTIL_X2_3414 6828 +#define Z_UTIL_X2_3415 6830 +#define Z_UTIL_X2_3416 6832 +#define Z_UTIL_X2_3417 6834 +#define Z_UTIL_X2_3418 6836 +#define Z_UTIL_X2_3419 6838 +#define Z_UTIL_X2_3420 6840 +#define Z_UTIL_X2_3421 6842 +#define Z_UTIL_X2_3422 6844 +#define Z_UTIL_X2_3423 6846 +#define Z_UTIL_X2_3424 6848 +#define Z_UTIL_X2_3425 6850 +#define Z_UTIL_X2_3426 6852 +#define Z_UTIL_X2_3427 6854 +#define Z_UTIL_X2_3428 6856 +#define Z_UTIL_X2_3429 6858 +#define Z_UTIL_X2_3430 6860 +#define Z_UTIL_X2_3431 6862 +#define Z_UTIL_X2_3432 6864 +#define Z_UTIL_X2_3433 6866 +#define Z_UTIL_X2_3434 6868 +#define Z_UTIL_X2_3435 6870 +#define Z_UTIL_X2_3436 6872 +#define Z_UTIL_X2_3437 6874 +#define Z_UTIL_X2_3438 6876 +#define Z_UTIL_X2_3439 6878 +#define Z_UTIL_X2_3440 6880 +#define Z_UTIL_X2_3441 6882 +#define Z_UTIL_X2_3442 6884 +#define Z_UTIL_X2_3443 6886 +#define Z_UTIL_X2_3444 6888 +#define Z_UTIL_X2_3445 6890 +#define Z_UTIL_X2_3446 6892 +#define Z_UTIL_X2_3447 6894 +#define Z_UTIL_X2_3448 6896 +#define Z_UTIL_X2_3449 6898 +#define Z_UTIL_X2_3450 6900 +#define Z_UTIL_X2_3451 6902 +#define Z_UTIL_X2_3452 6904 +#define Z_UTIL_X2_3453 6906 +#define Z_UTIL_X2_3454 6908 +#define Z_UTIL_X2_3455 6910 +#define Z_UTIL_X2_3456 6912 +#define Z_UTIL_X2_3457 6914 +#define Z_UTIL_X2_3458 6916 +#define Z_UTIL_X2_3459 6918 +#define Z_UTIL_X2_3460 6920 +#define Z_UTIL_X2_3461 6922 +#define Z_UTIL_X2_3462 6924 +#define Z_UTIL_X2_3463 6926 +#define Z_UTIL_X2_3464 6928 +#define Z_UTIL_X2_3465 6930 +#define Z_UTIL_X2_3466 6932 +#define Z_UTIL_X2_3467 6934 +#define Z_UTIL_X2_3468 6936 +#define Z_UTIL_X2_3469 6938 +#define Z_UTIL_X2_3470 6940 +#define Z_UTIL_X2_3471 6942 +#define Z_UTIL_X2_3472 6944 +#define Z_UTIL_X2_3473 6946 +#define Z_UTIL_X2_3474 6948 +#define Z_UTIL_X2_3475 6950 +#define Z_UTIL_X2_3476 6952 +#define Z_UTIL_X2_3477 6954 +#define Z_UTIL_X2_3478 6956 +#define Z_UTIL_X2_3479 6958 +#define Z_UTIL_X2_3480 6960 +#define Z_UTIL_X2_3481 6962 +#define Z_UTIL_X2_3482 6964 +#define Z_UTIL_X2_3483 6966 +#define Z_UTIL_X2_3484 6968 +#define Z_UTIL_X2_3485 6970 +#define Z_UTIL_X2_3486 6972 +#define Z_UTIL_X2_3487 6974 +#define Z_UTIL_X2_3488 6976 +#define Z_UTIL_X2_3489 6978 +#define Z_UTIL_X2_3490 6980 +#define Z_UTIL_X2_3491 6982 +#define Z_UTIL_X2_3492 6984 +#define Z_UTIL_X2_3493 6986 +#define Z_UTIL_X2_3494 6988 +#define Z_UTIL_X2_3495 6990 +#define Z_UTIL_X2_3496 6992 +#define Z_UTIL_X2_3497 6994 +#define Z_UTIL_X2_3498 6996 +#define Z_UTIL_X2_3499 6998 +#define Z_UTIL_X2_3500 7000 +#define Z_UTIL_X2_3501 7002 +#define Z_UTIL_X2_3502 7004 +#define Z_UTIL_X2_3503 7006 +#define Z_UTIL_X2_3504 7008 +#define Z_UTIL_X2_3505 7010 +#define Z_UTIL_X2_3506 7012 +#define Z_UTIL_X2_3507 7014 +#define Z_UTIL_X2_3508 7016 +#define Z_UTIL_X2_3509 7018 +#define Z_UTIL_X2_3510 7020 +#define Z_UTIL_X2_3511 7022 +#define Z_UTIL_X2_3512 7024 +#define Z_UTIL_X2_3513 7026 +#define Z_UTIL_X2_3514 7028 +#define Z_UTIL_X2_3515 7030 +#define Z_UTIL_X2_3516 7032 +#define Z_UTIL_X2_3517 7034 +#define Z_UTIL_X2_3518 7036 +#define Z_UTIL_X2_3519 7038 +#define Z_UTIL_X2_3520 7040 +#define Z_UTIL_X2_3521 7042 +#define Z_UTIL_X2_3522 7044 +#define Z_UTIL_X2_3523 7046 +#define Z_UTIL_X2_3524 7048 +#define Z_UTIL_X2_3525 7050 +#define Z_UTIL_X2_3526 7052 +#define Z_UTIL_X2_3527 7054 +#define Z_UTIL_X2_3528 7056 +#define Z_UTIL_X2_3529 7058 +#define Z_UTIL_X2_3530 7060 +#define Z_UTIL_X2_3531 7062 +#define Z_UTIL_X2_3532 7064 +#define Z_UTIL_X2_3533 7066 +#define Z_UTIL_X2_3534 7068 +#define Z_UTIL_X2_3535 7070 +#define Z_UTIL_X2_3536 7072 +#define Z_UTIL_X2_3537 7074 +#define Z_UTIL_X2_3538 7076 +#define Z_UTIL_X2_3539 7078 +#define Z_UTIL_X2_3540 7080 +#define Z_UTIL_X2_3541 7082 +#define Z_UTIL_X2_3542 7084 +#define Z_UTIL_X2_3543 7086 +#define Z_UTIL_X2_3544 7088 +#define Z_UTIL_X2_3545 7090 +#define Z_UTIL_X2_3546 7092 +#define Z_UTIL_X2_3547 7094 +#define Z_UTIL_X2_3548 7096 +#define Z_UTIL_X2_3549 7098 +#define Z_UTIL_X2_3550 7100 +#define Z_UTIL_X2_3551 7102 +#define Z_UTIL_X2_3552 7104 +#define Z_UTIL_X2_3553 7106 +#define Z_UTIL_X2_3554 7108 +#define Z_UTIL_X2_3555 7110 +#define Z_UTIL_X2_3556 7112 +#define Z_UTIL_X2_3557 7114 +#define Z_UTIL_X2_3558 7116 +#define Z_UTIL_X2_3559 7118 +#define Z_UTIL_X2_3560 7120 +#define Z_UTIL_X2_3561 7122 +#define Z_UTIL_X2_3562 7124 +#define Z_UTIL_X2_3563 7126 +#define Z_UTIL_X2_3564 7128 +#define Z_UTIL_X2_3565 7130 +#define Z_UTIL_X2_3566 7132 +#define Z_UTIL_X2_3567 7134 +#define Z_UTIL_X2_3568 7136 +#define Z_UTIL_X2_3569 7138 +#define Z_UTIL_X2_3570 7140 +#define Z_UTIL_X2_3571 7142 +#define Z_UTIL_X2_3572 7144 +#define Z_UTIL_X2_3573 7146 +#define Z_UTIL_X2_3574 7148 +#define Z_UTIL_X2_3575 7150 +#define Z_UTIL_X2_3576 7152 +#define Z_UTIL_X2_3577 7154 +#define Z_UTIL_X2_3578 7156 +#define Z_UTIL_X2_3579 7158 +#define Z_UTIL_X2_3580 7160 +#define Z_UTIL_X2_3581 7162 +#define Z_UTIL_X2_3582 7164 +#define Z_UTIL_X2_3583 7166 +#define Z_UTIL_X2_3584 7168 +#define Z_UTIL_X2_3585 7170 +#define Z_UTIL_X2_3586 7172 +#define Z_UTIL_X2_3587 7174 +#define Z_UTIL_X2_3588 7176 +#define Z_UTIL_X2_3589 7178 +#define Z_UTIL_X2_3590 7180 +#define Z_UTIL_X2_3591 7182 +#define Z_UTIL_X2_3592 7184 +#define Z_UTIL_X2_3593 7186 +#define Z_UTIL_X2_3594 7188 +#define Z_UTIL_X2_3595 7190 +#define Z_UTIL_X2_3596 7192 +#define Z_UTIL_X2_3597 7194 +#define Z_UTIL_X2_3598 7196 +#define Z_UTIL_X2_3599 7198 +#define Z_UTIL_X2_3600 7200 +#define Z_UTIL_X2_3601 7202 +#define Z_UTIL_X2_3602 7204 +#define Z_UTIL_X2_3603 7206 +#define Z_UTIL_X2_3604 7208 +#define Z_UTIL_X2_3605 7210 +#define Z_UTIL_X2_3606 7212 +#define Z_UTIL_X2_3607 7214 +#define Z_UTIL_X2_3608 7216 +#define Z_UTIL_X2_3609 7218 +#define Z_UTIL_X2_3610 7220 +#define Z_UTIL_X2_3611 7222 +#define Z_UTIL_X2_3612 7224 +#define Z_UTIL_X2_3613 7226 +#define Z_UTIL_X2_3614 7228 +#define Z_UTIL_X2_3615 7230 +#define Z_UTIL_X2_3616 7232 +#define Z_UTIL_X2_3617 7234 +#define Z_UTIL_X2_3618 7236 +#define Z_UTIL_X2_3619 7238 +#define Z_UTIL_X2_3620 7240 +#define Z_UTIL_X2_3621 7242 +#define Z_UTIL_X2_3622 7244 +#define Z_UTIL_X2_3623 7246 +#define Z_UTIL_X2_3624 7248 +#define Z_UTIL_X2_3625 7250 +#define Z_UTIL_X2_3626 7252 +#define Z_UTIL_X2_3627 7254 +#define Z_UTIL_X2_3628 7256 +#define Z_UTIL_X2_3629 7258 +#define Z_UTIL_X2_3630 7260 +#define Z_UTIL_X2_3631 7262 +#define Z_UTIL_X2_3632 7264 +#define Z_UTIL_X2_3633 7266 +#define Z_UTIL_X2_3634 7268 +#define Z_UTIL_X2_3635 7270 +#define Z_UTIL_X2_3636 7272 +#define Z_UTIL_X2_3637 7274 +#define Z_UTIL_X2_3638 7276 +#define Z_UTIL_X2_3639 7278 +#define Z_UTIL_X2_3640 7280 +#define Z_UTIL_X2_3641 7282 +#define Z_UTIL_X2_3642 7284 +#define Z_UTIL_X2_3643 7286 +#define Z_UTIL_X2_3644 7288 +#define Z_UTIL_X2_3645 7290 +#define Z_UTIL_X2_3646 7292 +#define Z_UTIL_X2_3647 7294 +#define Z_UTIL_X2_3648 7296 +#define Z_UTIL_X2_3649 7298 +#define Z_UTIL_X2_3650 7300 +#define Z_UTIL_X2_3651 7302 +#define Z_UTIL_X2_3652 7304 +#define Z_UTIL_X2_3653 7306 +#define Z_UTIL_X2_3654 7308 +#define Z_UTIL_X2_3655 7310 +#define Z_UTIL_X2_3656 7312 +#define Z_UTIL_X2_3657 7314 +#define Z_UTIL_X2_3658 7316 +#define Z_UTIL_X2_3659 7318 +#define Z_UTIL_X2_3660 7320 +#define Z_UTIL_X2_3661 7322 +#define Z_UTIL_X2_3662 7324 +#define Z_UTIL_X2_3663 7326 +#define Z_UTIL_X2_3664 7328 +#define Z_UTIL_X2_3665 7330 +#define Z_UTIL_X2_3666 7332 +#define Z_UTIL_X2_3667 7334 +#define Z_UTIL_X2_3668 7336 +#define Z_UTIL_X2_3669 7338 +#define Z_UTIL_X2_3670 7340 +#define Z_UTIL_X2_3671 7342 +#define Z_UTIL_X2_3672 7344 +#define Z_UTIL_X2_3673 7346 +#define Z_UTIL_X2_3674 7348 +#define Z_UTIL_X2_3675 7350 +#define Z_UTIL_X2_3676 7352 +#define Z_UTIL_X2_3677 7354 +#define Z_UTIL_X2_3678 7356 +#define Z_UTIL_X2_3679 7358 +#define Z_UTIL_X2_3680 7360 +#define Z_UTIL_X2_3681 7362 +#define Z_UTIL_X2_3682 7364 +#define Z_UTIL_X2_3683 7366 +#define Z_UTIL_X2_3684 7368 +#define Z_UTIL_X2_3685 7370 +#define Z_UTIL_X2_3686 7372 +#define Z_UTIL_X2_3687 7374 +#define Z_UTIL_X2_3688 7376 +#define Z_UTIL_X2_3689 7378 +#define Z_UTIL_X2_3690 7380 +#define Z_UTIL_X2_3691 7382 +#define Z_UTIL_X2_3692 7384 +#define Z_UTIL_X2_3693 7386 +#define Z_UTIL_X2_3694 7388 +#define Z_UTIL_X2_3695 7390 +#define Z_UTIL_X2_3696 7392 +#define Z_UTIL_X2_3697 7394 +#define Z_UTIL_X2_3698 7396 +#define Z_UTIL_X2_3699 7398 +#define Z_UTIL_X2_3700 7400 +#define Z_UTIL_X2_3701 7402 +#define Z_UTIL_X2_3702 7404 +#define Z_UTIL_X2_3703 7406 +#define Z_UTIL_X2_3704 7408 +#define Z_UTIL_X2_3705 7410 +#define Z_UTIL_X2_3706 7412 +#define Z_UTIL_X2_3707 7414 +#define Z_UTIL_X2_3708 7416 +#define Z_UTIL_X2_3709 7418 +#define Z_UTIL_X2_3710 7420 +#define Z_UTIL_X2_3711 7422 +#define Z_UTIL_X2_3712 7424 +#define Z_UTIL_X2_3713 7426 +#define Z_UTIL_X2_3714 7428 +#define Z_UTIL_X2_3715 7430 +#define Z_UTIL_X2_3716 7432 +#define Z_UTIL_X2_3717 7434 +#define Z_UTIL_X2_3718 7436 +#define Z_UTIL_X2_3719 7438 +#define Z_UTIL_X2_3720 7440 +#define Z_UTIL_X2_3721 7442 +#define Z_UTIL_X2_3722 7444 +#define Z_UTIL_X2_3723 7446 +#define Z_UTIL_X2_3724 7448 +#define Z_UTIL_X2_3725 7450 +#define Z_UTIL_X2_3726 7452 +#define Z_UTIL_X2_3727 7454 +#define Z_UTIL_X2_3728 7456 +#define Z_UTIL_X2_3729 7458 +#define Z_UTIL_X2_3730 7460 +#define Z_UTIL_X2_3731 7462 +#define Z_UTIL_X2_3732 7464 +#define Z_UTIL_X2_3733 7466 +#define Z_UTIL_X2_3734 7468 +#define Z_UTIL_X2_3735 7470 +#define Z_UTIL_X2_3736 7472 +#define Z_UTIL_X2_3737 7474 +#define Z_UTIL_X2_3738 7476 +#define Z_UTIL_X2_3739 7478 +#define Z_UTIL_X2_3740 7480 +#define Z_UTIL_X2_3741 7482 +#define Z_UTIL_X2_3742 7484 +#define Z_UTIL_X2_3743 7486 +#define Z_UTIL_X2_3744 7488 +#define Z_UTIL_X2_3745 7490 +#define Z_UTIL_X2_3746 7492 +#define Z_UTIL_X2_3747 7494 +#define Z_UTIL_X2_3748 7496 +#define Z_UTIL_X2_3749 7498 +#define Z_UTIL_X2_3750 7500 +#define Z_UTIL_X2_3751 7502 +#define Z_UTIL_X2_3752 7504 +#define Z_UTIL_X2_3753 7506 +#define Z_UTIL_X2_3754 7508 +#define Z_UTIL_X2_3755 7510 +#define Z_UTIL_X2_3756 7512 +#define Z_UTIL_X2_3757 7514 +#define Z_UTIL_X2_3758 7516 +#define Z_UTIL_X2_3759 7518 +#define Z_UTIL_X2_3760 7520 +#define Z_UTIL_X2_3761 7522 +#define Z_UTIL_X2_3762 7524 +#define Z_UTIL_X2_3763 7526 +#define Z_UTIL_X2_3764 7528 +#define Z_UTIL_X2_3765 7530 +#define Z_UTIL_X2_3766 7532 +#define Z_UTIL_X2_3767 7534 +#define Z_UTIL_X2_3768 7536 +#define Z_UTIL_X2_3769 7538 +#define Z_UTIL_X2_3770 7540 +#define Z_UTIL_X2_3771 7542 +#define Z_UTIL_X2_3772 7544 +#define Z_UTIL_X2_3773 7546 +#define Z_UTIL_X2_3774 7548 +#define Z_UTIL_X2_3775 7550 +#define Z_UTIL_X2_3776 7552 +#define Z_UTIL_X2_3777 7554 +#define Z_UTIL_X2_3778 7556 +#define Z_UTIL_X2_3779 7558 +#define Z_UTIL_X2_3780 7560 +#define Z_UTIL_X2_3781 7562 +#define Z_UTIL_X2_3782 7564 +#define Z_UTIL_X2_3783 7566 +#define Z_UTIL_X2_3784 7568 +#define Z_UTIL_X2_3785 7570 +#define Z_UTIL_X2_3786 7572 +#define Z_UTIL_X2_3787 7574 +#define Z_UTIL_X2_3788 7576 +#define Z_UTIL_X2_3789 7578 +#define Z_UTIL_X2_3790 7580 +#define Z_UTIL_X2_3791 7582 +#define Z_UTIL_X2_3792 7584 +#define Z_UTIL_X2_3793 7586 +#define Z_UTIL_X2_3794 7588 +#define Z_UTIL_X2_3795 7590 +#define Z_UTIL_X2_3796 7592 +#define Z_UTIL_X2_3797 7594 +#define Z_UTIL_X2_3798 7596 +#define Z_UTIL_X2_3799 7598 +#define Z_UTIL_X2_3800 7600 +#define Z_UTIL_X2_3801 7602 +#define Z_UTIL_X2_3802 7604 +#define Z_UTIL_X2_3803 7606 +#define Z_UTIL_X2_3804 7608 +#define Z_UTIL_X2_3805 7610 +#define Z_UTIL_X2_3806 7612 +#define Z_UTIL_X2_3807 7614 +#define Z_UTIL_X2_3808 7616 +#define Z_UTIL_X2_3809 7618 +#define Z_UTIL_X2_3810 7620 +#define Z_UTIL_X2_3811 7622 +#define Z_UTIL_X2_3812 7624 +#define Z_UTIL_X2_3813 7626 +#define Z_UTIL_X2_3814 7628 +#define Z_UTIL_X2_3815 7630 +#define Z_UTIL_X2_3816 7632 +#define Z_UTIL_X2_3817 7634 +#define Z_UTIL_X2_3818 7636 +#define Z_UTIL_X2_3819 7638 +#define Z_UTIL_X2_3820 7640 +#define Z_UTIL_X2_3821 7642 +#define Z_UTIL_X2_3822 7644 +#define Z_UTIL_X2_3823 7646 +#define Z_UTIL_X2_3824 7648 +#define Z_UTIL_X2_3825 7650 +#define Z_UTIL_X2_3826 7652 +#define Z_UTIL_X2_3827 7654 +#define Z_UTIL_X2_3828 7656 +#define Z_UTIL_X2_3829 7658 +#define Z_UTIL_X2_3830 7660 +#define Z_UTIL_X2_3831 7662 +#define Z_UTIL_X2_3832 7664 +#define Z_UTIL_X2_3833 7666 +#define Z_UTIL_X2_3834 7668 +#define Z_UTIL_X2_3835 7670 +#define Z_UTIL_X2_3836 7672 +#define Z_UTIL_X2_3837 7674 +#define Z_UTIL_X2_3838 7676 +#define Z_UTIL_X2_3839 7678 +#define Z_UTIL_X2_3840 7680 +#define Z_UTIL_X2_3841 7682 +#define Z_UTIL_X2_3842 7684 +#define Z_UTIL_X2_3843 7686 +#define Z_UTIL_X2_3844 7688 +#define Z_UTIL_X2_3845 7690 +#define Z_UTIL_X2_3846 7692 +#define Z_UTIL_X2_3847 7694 +#define Z_UTIL_X2_3848 7696 +#define Z_UTIL_X2_3849 7698 +#define Z_UTIL_X2_3850 7700 +#define Z_UTIL_X2_3851 7702 +#define Z_UTIL_X2_3852 7704 +#define Z_UTIL_X2_3853 7706 +#define Z_UTIL_X2_3854 7708 +#define Z_UTIL_X2_3855 7710 +#define Z_UTIL_X2_3856 7712 +#define Z_UTIL_X2_3857 7714 +#define Z_UTIL_X2_3858 7716 +#define Z_UTIL_X2_3859 7718 +#define Z_UTIL_X2_3860 7720 +#define Z_UTIL_X2_3861 7722 +#define Z_UTIL_X2_3862 7724 +#define Z_UTIL_X2_3863 7726 +#define Z_UTIL_X2_3864 7728 +#define Z_UTIL_X2_3865 7730 +#define Z_UTIL_X2_3866 7732 +#define Z_UTIL_X2_3867 7734 +#define Z_UTIL_X2_3868 7736 +#define Z_UTIL_X2_3869 7738 +#define Z_UTIL_X2_3870 7740 +#define Z_UTIL_X2_3871 7742 +#define Z_UTIL_X2_3872 7744 +#define Z_UTIL_X2_3873 7746 +#define Z_UTIL_X2_3874 7748 +#define Z_UTIL_X2_3875 7750 +#define Z_UTIL_X2_3876 7752 +#define Z_UTIL_X2_3877 7754 +#define Z_UTIL_X2_3878 7756 +#define Z_UTIL_X2_3879 7758 +#define Z_UTIL_X2_3880 7760 +#define Z_UTIL_X2_3881 7762 +#define Z_UTIL_X2_3882 7764 +#define Z_UTIL_X2_3883 7766 +#define Z_UTIL_X2_3884 7768 +#define Z_UTIL_X2_3885 7770 +#define Z_UTIL_X2_3886 7772 +#define Z_UTIL_X2_3887 7774 +#define Z_UTIL_X2_3888 7776 +#define Z_UTIL_X2_3889 7778 +#define Z_UTIL_X2_3890 7780 +#define Z_UTIL_X2_3891 7782 +#define Z_UTIL_X2_3892 7784 +#define Z_UTIL_X2_3893 7786 +#define Z_UTIL_X2_3894 7788 +#define Z_UTIL_X2_3895 7790 +#define Z_UTIL_X2_3896 7792 +#define Z_UTIL_X2_3897 7794 +#define Z_UTIL_X2_3898 7796 +#define Z_UTIL_X2_3899 7798 +#define Z_UTIL_X2_3900 7800 +#define Z_UTIL_X2_3901 7802 +#define Z_UTIL_X2_3902 7804 +#define Z_UTIL_X2_3903 7806 +#define Z_UTIL_X2_3904 7808 +#define Z_UTIL_X2_3905 7810 +#define Z_UTIL_X2_3906 7812 +#define Z_UTIL_X2_3907 7814 +#define Z_UTIL_X2_3908 7816 +#define Z_UTIL_X2_3909 7818 +#define Z_UTIL_X2_3910 7820 +#define Z_UTIL_X2_3911 7822 +#define Z_UTIL_X2_3912 7824 +#define Z_UTIL_X2_3913 7826 +#define Z_UTIL_X2_3914 7828 +#define Z_UTIL_X2_3915 7830 +#define Z_UTIL_X2_3916 7832 +#define Z_UTIL_X2_3917 7834 +#define Z_UTIL_X2_3918 7836 +#define Z_UTIL_X2_3919 7838 +#define Z_UTIL_X2_3920 7840 +#define Z_UTIL_X2_3921 7842 +#define Z_UTIL_X2_3922 7844 +#define Z_UTIL_X2_3923 7846 +#define Z_UTIL_X2_3924 7848 +#define Z_UTIL_X2_3925 7850 +#define Z_UTIL_X2_3926 7852 +#define Z_UTIL_X2_3927 7854 +#define Z_UTIL_X2_3928 7856 +#define Z_UTIL_X2_3929 7858 +#define Z_UTIL_X2_3930 7860 +#define Z_UTIL_X2_3931 7862 +#define Z_UTIL_X2_3932 7864 +#define Z_UTIL_X2_3933 7866 +#define Z_UTIL_X2_3934 7868 +#define Z_UTIL_X2_3935 7870 +#define Z_UTIL_X2_3936 7872 +#define Z_UTIL_X2_3937 7874 +#define Z_UTIL_X2_3938 7876 +#define Z_UTIL_X2_3939 7878 +#define Z_UTIL_X2_3940 7880 +#define Z_UTIL_X2_3941 7882 +#define Z_UTIL_X2_3942 7884 +#define Z_UTIL_X2_3943 7886 +#define Z_UTIL_X2_3944 7888 +#define Z_UTIL_X2_3945 7890 +#define Z_UTIL_X2_3946 7892 +#define Z_UTIL_X2_3947 7894 +#define Z_UTIL_X2_3948 7896 +#define Z_UTIL_X2_3949 7898 +#define Z_UTIL_X2_3950 7900 +#define Z_UTIL_X2_3951 7902 +#define Z_UTIL_X2_3952 7904 +#define Z_UTIL_X2_3953 7906 +#define Z_UTIL_X2_3954 7908 +#define Z_UTIL_X2_3955 7910 +#define Z_UTIL_X2_3956 7912 +#define Z_UTIL_X2_3957 7914 +#define Z_UTIL_X2_3958 7916 +#define Z_UTIL_X2_3959 7918 +#define Z_UTIL_X2_3960 7920 +#define Z_UTIL_X2_3961 7922 +#define Z_UTIL_X2_3962 7924 +#define Z_UTIL_X2_3963 7926 +#define Z_UTIL_X2_3964 7928 +#define Z_UTIL_X2_3965 7930 +#define Z_UTIL_X2_3966 7932 +#define Z_UTIL_X2_3967 7934 +#define Z_UTIL_X2_3968 7936 +#define Z_UTIL_X2_3969 7938 +#define Z_UTIL_X2_3970 7940 +#define Z_UTIL_X2_3971 7942 +#define Z_UTIL_X2_3972 7944 +#define Z_UTIL_X2_3973 7946 +#define Z_UTIL_X2_3974 7948 +#define Z_UTIL_X2_3975 7950 +#define Z_UTIL_X2_3976 7952 +#define Z_UTIL_X2_3977 7954 +#define Z_UTIL_X2_3978 7956 +#define Z_UTIL_X2_3979 7958 +#define Z_UTIL_X2_3980 7960 +#define Z_UTIL_X2_3981 7962 +#define Z_UTIL_X2_3982 7964 +#define Z_UTIL_X2_3983 7966 +#define Z_UTIL_X2_3984 7968 +#define Z_UTIL_X2_3985 7970 +#define Z_UTIL_X2_3986 7972 +#define Z_UTIL_X2_3987 7974 +#define Z_UTIL_X2_3988 7976 +#define Z_UTIL_X2_3989 7978 +#define Z_UTIL_X2_3990 7980 +#define Z_UTIL_X2_3991 7982 +#define Z_UTIL_X2_3992 7984 +#define Z_UTIL_X2_3993 7986 +#define Z_UTIL_X2_3994 7988 +#define Z_UTIL_X2_3995 7990 +#define Z_UTIL_X2_3996 7992 +#define Z_UTIL_X2_3997 7994 +#define Z_UTIL_X2_3998 7996 +#define Z_UTIL_X2_3999 7998 +#define Z_UTIL_X2_4000 8000 +#define Z_UTIL_X2_4001 8002 +#define Z_UTIL_X2_4002 8004 +#define Z_UTIL_X2_4003 8006 +#define Z_UTIL_X2_4004 8008 +#define Z_UTIL_X2_4005 8010 +#define Z_UTIL_X2_4006 8012 +#define Z_UTIL_X2_4007 8014 +#define Z_UTIL_X2_4008 8016 +#define Z_UTIL_X2_4009 8018 +#define Z_UTIL_X2_4010 8020 +#define Z_UTIL_X2_4011 8022 +#define Z_UTIL_X2_4012 8024 +#define Z_UTIL_X2_4013 8026 +#define Z_UTIL_X2_4014 8028 +#define Z_UTIL_X2_4015 8030 +#define Z_UTIL_X2_4016 8032 +#define Z_UTIL_X2_4017 8034 +#define Z_UTIL_X2_4018 8036 +#define Z_UTIL_X2_4019 8038 +#define Z_UTIL_X2_4020 8040 +#define Z_UTIL_X2_4021 8042 +#define Z_UTIL_X2_4022 8044 +#define Z_UTIL_X2_4023 8046 +#define Z_UTIL_X2_4024 8048 +#define Z_UTIL_X2_4025 8050 +#define Z_UTIL_X2_4026 8052 +#define Z_UTIL_X2_4027 8054 +#define Z_UTIL_X2_4028 8056 +#define Z_UTIL_X2_4029 8058 +#define Z_UTIL_X2_4030 8060 +#define Z_UTIL_X2_4031 8062 +#define Z_UTIL_X2_4032 8064 +#define Z_UTIL_X2_4033 8066 +#define Z_UTIL_X2_4034 8068 +#define Z_UTIL_X2_4035 8070 +#define Z_UTIL_X2_4036 8072 +#define Z_UTIL_X2_4037 8074 +#define Z_UTIL_X2_4038 8076 +#define Z_UTIL_X2_4039 8078 +#define Z_UTIL_X2_4040 8080 +#define Z_UTIL_X2_4041 8082 +#define Z_UTIL_X2_4042 8084 +#define Z_UTIL_X2_4043 8086 +#define Z_UTIL_X2_4044 8088 +#define Z_UTIL_X2_4045 8090 +#define Z_UTIL_X2_4046 8092 +#define Z_UTIL_X2_4047 8094 +#define Z_UTIL_X2_4048 8096 +#define Z_UTIL_X2_4049 8098 +#define Z_UTIL_X2_4050 8100 +#define Z_UTIL_X2_4051 8102 +#define Z_UTIL_X2_4052 8104 +#define Z_UTIL_X2_4053 8106 +#define Z_UTIL_X2_4054 8108 +#define Z_UTIL_X2_4055 8110 +#define Z_UTIL_X2_4056 8112 +#define Z_UTIL_X2_4057 8114 +#define Z_UTIL_X2_4058 8116 +#define Z_UTIL_X2_4059 8118 +#define Z_UTIL_X2_4060 8120 +#define Z_UTIL_X2_4061 8122 +#define Z_UTIL_X2_4062 8124 +#define Z_UTIL_X2_4063 8126 +#define Z_UTIL_X2_4064 8128 +#define Z_UTIL_X2_4065 8130 +#define Z_UTIL_X2_4066 8132 +#define Z_UTIL_X2_4067 8134 +#define Z_UTIL_X2_4068 8136 +#define Z_UTIL_X2_4069 8138 +#define Z_UTIL_X2_4070 8140 +#define Z_UTIL_X2_4071 8142 +#define Z_UTIL_X2_4072 8144 +#define Z_UTIL_X2_4073 8146 +#define Z_UTIL_X2_4074 8148 +#define Z_UTIL_X2_4075 8150 +#define Z_UTIL_X2_4076 8152 +#define Z_UTIL_X2_4077 8154 +#define Z_UTIL_X2_4078 8156 +#define Z_UTIL_X2_4079 8158 +#define Z_UTIL_X2_4080 8160 +#define Z_UTIL_X2_4081 8162 +#define Z_UTIL_X2_4082 8164 +#define Z_UTIL_X2_4083 8166 +#define Z_UTIL_X2_4084 8168 +#define Z_UTIL_X2_4085 8170 +#define Z_UTIL_X2_4086 8172 +#define Z_UTIL_X2_4087 8174 +#define Z_UTIL_X2_4088 8176 +#define Z_UTIL_X2_4089 8178 +#define Z_UTIL_X2_4090 8180 +#define Z_UTIL_X2_4091 8182 +#define Z_UTIL_X2_4092 8184 +#define Z_UTIL_X2_4093 8186 +#define Z_UTIL_X2_4094 8188 +#define Z_UTIL_X2_4095 8190 + +#endif /* ZEPHYR_INCLUDE_SYS_UTIL_INTERNAL_UTIL_X2_H_ */ + +/** + * INTERNAL_HIDDEN @endcond + */ diff --git a/components/bt/esp_ble_audio/include/zephyr/sys/util_listify.h b/components/bt/esp_ble_audio/include/zephyr/sys/util_listify.h new file mode 100644 index 0000000000..a8627f91a1 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/sys/util_listify.h @@ -0,0 +1,16400 @@ +/* + * SPDX-FileCopyrightText: 2021 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_SYS_UTIL_LOOPS_H_ +#error "This header should not be used directly, please include util_loops.h instead" +#endif /* ZEPHYR_INCLUDE_SYS_UTIL_LOOPS_H_ */ + +#ifndef ZEPHYR_INCLUDE_SYS_UTIL_LISTIFY_H_ +#define ZEPHYR_INCLUDE_SYS_UTIL_LISTIFY_H_ + +#define Z_UTIL_LISTIFY_0(F, sep, ...) + +#define Z_UTIL_LISTIFY_1(F, sep, ...) \ + F(0, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2(F, sep, ...) \ + Z_UTIL_LISTIFY_1(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3(F, sep, ...) \ + Z_UTIL_LISTIFY_2(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4(F, sep, ...) \ + Z_UTIL_LISTIFY_3(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_5(F, sep, ...) \ + Z_UTIL_LISTIFY_4(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_6(F, sep, ...) \ + Z_UTIL_LISTIFY_5(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(5, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_7(F, sep, ...) \ + Z_UTIL_LISTIFY_6(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(6, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_8(F, sep, ...) \ + Z_UTIL_LISTIFY_7(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(7, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_9(F, sep, ...) \ + Z_UTIL_LISTIFY_8(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(8, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_10(F, sep, ...) \ + Z_UTIL_LISTIFY_9(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(9, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_11(F, sep, ...) \ + Z_UTIL_LISTIFY_10(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(10, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_12(F, sep, ...) \ + Z_UTIL_LISTIFY_11(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(11, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_13(F, sep, ...) \ + Z_UTIL_LISTIFY_12(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(12, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_14(F, sep, ...) \ + Z_UTIL_LISTIFY_13(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(13, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_15(F, sep, ...) \ + Z_UTIL_LISTIFY_14(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(14, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_16(F, sep, ...) \ + Z_UTIL_LISTIFY_15(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(15, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_17(F, sep, ...) \ + Z_UTIL_LISTIFY_16(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(16, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_18(F, sep, ...) \ + Z_UTIL_LISTIFY_17(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(17, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_19(F, sep, ...) \ + Z_UTIL_LISTIFY_18(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(18, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_20(F, sep, ...) \ + Z_UTIL_LISTIFY_19(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(19, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_21(F, sep, ...) \ + Z_UTIL_LISTIFY_20(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(20, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_22(F, sep, ...) \ + Z_UTIL_LISTIFY_21(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(21, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_23(F, sep, ...) \ + Z_UTIL_LISTIFY_22(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(22, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_24(F, sep, ...) \ + Z_UTIL_LISTIFY_23(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(23, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_25(F, sep, ...) \ + Z_UTIL_LISTIFY_24(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(24, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_26(F, sep, ...) \ + Z_UTIL_LISTIFY_25(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(25, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_27(F, sep, ...) \ + Z_UTIL_LISTIFY_26(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(26, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_28(F, sep, ...) \ + Z_UTIL_LISTIFY_27(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(27, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_29(F, sep, ...) \ + Z_UTIL_LISTIFY_28(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(28, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_30(F, sep, ...) \ + Z_UTIL_LISTIFY_29(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(29, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_31(F, sep, ...) \ + Z_UTIL_LISTIFY_30(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(30, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_32(F, sep, ...) \ + Z_UTIL_LISTIFY_31(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(31, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_33(F, sep, ...) \ + Z_UTIL_LISTIFY_32(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(32, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_34(F, sep, ...) \ + Z_UTIL_LISTIFY_33(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(33, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_35(F, sep, ...) \ + Z_UTIL_LISTIFY_34(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(34, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_36(F, sep, ...) \ + Z_UTIL_LISTIFY_35(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(35, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_37(F, sep, ...) \ + Z_UTIL_LISTIFY_36(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(36, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_38(F, sep, ...) \ + Z_UTIL_LISTIFY_37(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(37, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_39(F, sep, ...) \ + Z_UTIL_LISTIFY_38(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(38, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_40(F, sep, ...) \ + Z_UTIL_LISTIFY_39(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(39, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_41(F, sep, ...) \ + Z_UTIL_LISTIFY_40(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(40, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_42(F, sep, ...) \ + Z_UTIL_LISTIFY_41(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(41, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_43(F, sep, ...) \ + Z_UTIL_LISTIFY_42(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(42, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_44(F, sep, ...) \ + Z_UTIL_LISTIFY_43(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(43, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_45(F, sep, ...) \ + Z_UTIL_LISTIFY_44(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(44, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_46(F, sep, ...) \ + Z_UTIL_LISTIFY_45(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(45, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_47(F, sep, ...) \ + Z_UTIL_LISTIFY_46(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(46, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_48(F, sep, ...) \ + Z_UTIL_LISTIFY_47(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(47, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_49(F, sep, ...) \ + Z_UTIL_LISTIFY_48(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(48, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_50(F, sep, ...) \ + Z_UTIL_LISTIFY_49(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(49, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_51(F, sep, ...) \ + Z_UTIL_LISTIFY_50(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(50, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_52(F, sep, ...) \ + Z_UTIL_LISTIFY_51(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(51, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_53(F, sep, ...) \ + Z_UTIL_LISTIFY_52(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(52, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_54(F, sep, ...) \ + Z_UTIL_LISTIFY_53(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(53, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_55(F, sep, ...) \ + Z_UTIL_LISTIFY_54(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(54, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_56(F, sep, ...) \ + Z_UTIL_LISTIFY_55(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(55, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_57(F, sep, ...) \ + Z_UTIL_LISTIFY_56(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(56, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_58(F, sep, ...) \ + Z_UTIL_LISTIFY_57(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(57, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_59(F, sep, ...) \ + Z_UTIL_LISTIFY_58(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(58, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_60(F, sep, ...) \ + Z_UTIL_LISTIFY_59(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(59, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_61(F, sep, ...) \ + Z_UTIL_LISTIFY_60(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(60, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_62(F, sep, ...) \ + Z_UTIL_LISTIFY_61(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(61, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_63(F, sep, ...) \ + Z_UTIL_LISTIFY_62(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(62, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_64(F, sep, ...) \ + Z_UTIL_LISTIFY_63(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(63, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_65(F, sep, ...) \ + Z_UTIL_LISTIFY_64(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(64, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_66(F, sep, ...) \ + Z_UTIL_LISTIFY_65(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(65, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_67(F, sep, ...) \ + Z_UTIL_LISTIFY_66(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(66, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_68(F, sep, ...) \ + Z_UTIL_LISTIFY_67(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(67, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_69(F, sep, ...) \ + Z_UTIL_LISTIFY_68(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(68, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_70(F, sep, ...) \ + Z_UTIL_LISTIFY_69(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(69, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_71(F, sep, ...) \ + Z_UTIL_LISTIFY_70(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(70, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_72(F, sep, ...) \ + Z_UTIL_LISTIFY_71(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(71, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_73(F, sep, ...) \ + Z_UTIL_LISTIFY_72(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(72, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_74(F, sep, ...) \ + Z_UTIL_LISTIFY_73(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(73, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_75(F, sep, ...) \ + Z_UTIL_LISTIFY_74(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(74, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_76(F, sep, ...) \ + Z_UTIL_LISTIFY_75(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(75, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_77(F, sep, ...) \ + Z_UTIL_LISTIFY_76(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(76, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_78(F, sep, ...) \ + Z_UTIL_LISTIFY_77(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(77, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_79(F, sep, ...) \ + Z_UTIL_LISTIFY_78(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(78, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_80(F, sep, ...) \ + Z_UTIL_LISTIFY_79(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(79, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_81(F, sep, ...) \ + Z_UTIL_LISTIFY_80(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(80, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_82(F, sep, ...) \ + Z_UTIL_LISTIFY_81(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(81, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_83(F, sep, ...) \ + Z_UTIL_LISTIFY_82(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(82, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_84(F, sep, ...) \ + Z_UTIL_LISTIFY_83(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(83, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_85(F, sep, ...) \ + Z_UTIL_LISTIFY_84(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(84, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_86(F, sep, ...) \ + Z_UTIL_LISTIFY_85(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(85, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_87(F, sep, ...) \ + Z_UTIL_LISTIFY_86(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(86, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_88(F, sep, ...) \ + Z_UTIL_LISTIFY_87(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(87, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_89(F, sep, ...) \ + Z_UTIL_LISTIFY_88(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(88, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_90(F, sep, ...) \ + Z_UTIL_LISTIFY_89(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(89, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_91(F, sep, ...) \ + Z_UTIL_LISTIFY_90(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(90, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_92(F, sep, ...) \ + Z_UTIL_LISTIFY_91(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(91, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_93(F, sep, ...) \ + Z_UTIL_LISTIFY_92(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(92, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_94(F, sep, ...) \ + Z_UTIL_LISTIFY_93(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(93, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_95(F, sep, ...) \ + Z_UTIL_LISTIFY_94(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(94, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_96(F, sep, ...) \ + Z_UTIL_LISTIFY_95(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(95, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_97(F, sep, ...) \ + Z_UTIL_LISTIFY_96(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(96, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_98(F, sep, ...) \ + Z_UTIL_LISTIFY_97(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(97, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_99(F, sep, ...) \ + Z_UTIL_LISTIFY_98(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(98, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_100(F, sep, ...) \ + Z_UTIL_LISTIFY_99(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(99, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_101(F, sep, ...) \ + Z_UTIL_LISTIFY_100(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(100, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_102(F, sep, ...) \ + Z_UTIL_LISTIFY_101(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(101, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_103(F, sep, ...) \ + Z_UTIL_LISTIFY_102(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(102, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_104(F, sep, ...) \ + Z_UTIL_LISTIFY_103(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(103, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_105(F, sep, ...) \ + Z_UTIL_LISTIFY_104(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(104, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_106(F, sep, ...) \ + Z_UTIL_LISTIFY_105(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(105, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_107(F, sep, ...) \ + Z_UTIL_LISTIFY_106(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(106, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_108(F, sep, ...) \ + Z_UTIL_LISTIFY_107(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(107, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_109(F, sep, ...) \ + Z_UTIL_LISTIFY_108(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(108, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_110(F, sep, ...) \ + Z_UTIL_LISTIFY_109(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(109, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_111(F, sep, ...) \ + Z_UTIL_LISTIFY_110(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(110, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_112(F, sep, ...) \ + Z_UTIL_LISTIFY_111(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(111, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_113(F, sep, ...) \ + Z_UTIL_LISTIFY_112(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(112, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_114(F, sep, ...) \ + Z_UTIL_LISTIFY_113(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(113, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_115(F, sep, ...) \ + Z_UTIL_LISTIFY_114(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(114, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_116(F, sep, ...) \ + Z_UTIL_LISTIFY_115(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(115, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_117(F, sep, ...) \ + Z_UTIL_LISTIFY_116(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(116, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_118(F, sep, ...) \ + Z_UTIL_LISTIFY_117(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(117, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_119(F, sep, ...) \ + Z_UTIL_LISTIFY_118(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(118, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_120(F, sep, ...) \ + Z_UTIL_LISTIFY_119(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(119, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_121(F, sep, ...) \ + Z_UTIL_LISTIFY_120(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(120, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_122(F, sep, ...) \ + Z_UTIL_LISTIFY_121(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(121, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_123(F, sep, ...) \ + Z_UTIL_LISTIFY_122(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(122, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_124(F, sep, ...) \ + Z_UTIL_LISTIFY_123(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(123, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_125(F, sep, ...) \ + Z_UTIL_LISTIFY_124(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(124, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_126(F, sep, ...) \ + Z_UTIL_LISTIFY_125(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(125, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_127(F, sep, ...) \ + Z_UTIL_LISTIFY_126(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(126, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_128(F, sep, ...) \ + Z_UTIL_LISTIFY_127(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(127, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_129(F, sep, ...) \ + Z_UTIL_LISTIFY_128(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(128, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_130(F, sep, ...) \ + Z_UTIL_LISTIFY_129(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(129, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_131(F, sep, ...) \ + Z_UTIL_LISTIFY_130(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(130, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_132(F, sep, ...) \ + Z_UTIL_LISTIFY_131(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(131, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_133(F, sep, ...) \ + Z_UTIL_LISTIFY_132(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(132, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_134(F, sep, ...) \ + Z_UTIL_LISTIFY_133(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(133, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_135(F, sep, ...) \ + Z_UTIL_LISTIFY_134(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(134, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_136(F, sep, ...) \ + Z_UTIL_LISTIFY_135(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(135, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_137(F, sep, ...) \ + Z_UTIL_LISTIFY_136(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(136, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_138(F, sep, ...) \ + Z_UTIL_LISTIFY_137(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(137, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_139(F, sep, ...) \ + Z_UTIL_LISTIFY_138(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(138, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_140(F, sep, ...) \ + Z_UTIL_LISTIFY_139(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(139, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_141(F, sep, ...) \ + Z_UTIL_LISTIFY_140(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(140, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_142(F, sep, ...) \ + Z_UTIL_LISTIFY_141(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(141, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_143(F, sep, ...) \ + Z_UTIL_LISTIFY_142(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(142, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_144(F, sep, ...) \ + Z_UTIL_LISTIFY_143(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(143, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_145(F, sep, ...) \ + Z_UTIL_LISTIFY_144(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(144, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_146(F, sep, ...) \ + Z_UTIL_LISTIFY_145(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(145, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_147(F, sep, ...) \ + Z_UTIL_LISTIFY_146(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(146, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_148(F, sep, ...) \ + Z_UTIL_LISTIFY_147(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(147, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_149(F, sep, ...) \ + Z_UTIL_LISTIFY_148(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(148, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_150(F, sep, ...) \ + Z_UTIL_LISTIFY_149(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(149, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_151(F, sep, ...) \ + Z_UTIL_LISTIFY_150(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(150, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_152(F, sep, ...) \ + Z_UTIL_LISTIFY_151(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(151, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_153(F, sep, ...) \ + Z_UTIL_LISTIFY_152(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(152, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_154(F, sep, ...) \ + Z_UTIL_LISTIFY_153(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(153, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_155(F, sep, ...) \ + Z_UTIL_LISTIFY_154(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(154, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_156(F, sep, ...) \ + Z_UTIL_LISTIFY_155(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(155, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_157(F, sep, ...) \ + Z_UTIL_LISTIFY_156(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(156, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_158(F, sep, ...) \ + Z_UTIL_LISTIFY_157(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(157, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_159(F, sep, ...) \ + Z_UTIL_LISTIFY_158(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(158, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_160(F, sep, ...) \ + Z_UTIL_LISTIFY_159(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(159, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_161(F, sep, ...) \ + Z_UTIL_LISTIFY_160(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(160, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_162(F, sep, ...) \ + Z_UTIL_LISTIFY_161(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(161, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_163(F, sep, ...) \ + Z_UTIL_LISTIFY_162(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(162, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_164(F, sep, ...) \ + Z_UTIL_LISTIFY_163(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(163, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_165(F, sep, ...) \ + Z_UTIL_LISTIFY_164(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(164, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_166(F, sep, ...) \ + Z_UTIL_LISTIFY_165(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(165, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_167(F, sep, ...) \ + Z_UTIL_LISTIFY_166(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(166, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_168(F, sep, ...) \ + Z_UTIL_LISTIFY_167(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(167, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_169(F, sep, ...) \ + Z_UTIL_LISTIFY_168(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(168, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_170(F, sep, ...) \ + Z_UTIL_LISTIFY_169(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(169, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_171(F, sep, ...) \ + Z_UTIL_LISTIFY_170(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(170, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_172(F, sep, ...) \ + Z_UTIL_LISTIFY_171(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(171, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_173(F, sep, ...) \ + Z_UTIL_LISTIFY_172(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(172, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_174(F, sep, ...) \ + Z_UTIL_LISTIFY_173(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(173, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_175(F, sep, ...) \ + Z_UTIL_LISTIFY_174(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(174, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_176(F, sep, ...) \ + Z_UTIL_LISTIFY_175(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(175, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_177(F, sep, ...) \ + Z_UTIL_LISTIFY_176(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(176, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_178(F, sep, ...) \ + Z_UTIL_LISTIFY_177(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(177, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_179(F, sep, ...) \ + Z_UTIL_LISTIFY_178(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(178, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_180(F, sep, ...) \ + Z_UTIL_LISTIFY_179(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(179, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_181(F, sep, ...) \ + Z_UTIL_LISTIFY_180(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(180, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_182(F, sep, ...) \ + Z_UTIL_LISTIFY_181(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(181, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_183(F, sep, ...) \ + Z_UTIL_LISTIFY_182(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(182, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_184(F, sep, ...) \ + Z_UTIL_LISTIFY_183(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(183, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_185(F, sep, ...) \ + Z_UTIL_LISTIFY_184(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(184, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_186(F, sep, ...) \ + Z_UTIL_LISTIFY_185(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(185, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_187(F, sep, ...) \ + Z_UTIL_LISTIFY_186(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(186, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_188(F, sep, ...) \ + Z_UTIL_LISTIFY_187(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(187, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_189(F, sep, ...) \ + Z_UTIL_LISTIFY_188(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(188, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_190(F, sep, ...) \ + Z_UTIL_LISTIFY_189(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(189, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_191(F, sep, ...) \ + Z_UTIL_LISTIFY_190(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(190, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_192(F, sep, ...) \ + Z_UTIL_LISTIFY_191(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(191, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_193(F, sep, ...) \ + Z_UTIL_LISTIFY_192(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(192, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_194(F, sep, ...) \ + Z_UTIL_LISTIFY_193(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(193, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_195(F, sep, ...) \ + Z_UTIL_LISTIFY_194(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(194, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_196(F, sep, ...) \ + Z_UTIL_LISTIFY_195(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(195, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_197(F, sep, ...) \ + Z_UTIL_LISTIFY_196(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(196, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_198(F, sep, ...) \ + Z_UTIL_LISTIFY_197(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(197, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_199(F, sep, ...) \ + Z_UTIL_LISTIFY_198(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(198, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_200(F, sep, ...) \ + Z_UTIL_LISTIFY_199(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(199, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_201(F, sep, ...) \ + Z_UTIL_LISTIFY_200(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(200, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_202(F, sep, ...) \ + Z_UTIL_LISTIFY_201(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(201, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_203(F, sep, ...) \ + Z_UTIL_LISTIFY_202(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(202, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_204(F, sep, ...) \ + Z_UTIL_LISTIFY_203(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(203, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_205(F, sep, ...) \ + Z_UTIL_LISTIFY_204(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(204, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_206(F, sep, ...) \ + Z_UTIL_LISTIFY_205(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(205, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_207(F, sep, ...) \ + Z_UTIL_LISTIFY_206(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(206, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_208(F, sep, ...) \ + Z_UTIL_LISTIFY_207(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(207, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_209(F, sep, ...) \ + Z_UTIL_LISTIFY_208(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(208, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_210(F, sep, ...) \ + Z_UTIL_LISTIFY_209(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(209, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_211(F, sep, ...) \ + Z_UTIL_LISTIFY_210(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(210, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_212(F, sep, ...) \ + Z_UTIL_LISTIFY_211(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(211, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_213(F, sep, ...) \ + Z_UTIL_LISTIFY_212(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(212, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_214(F, sep, ...) \ + Z_UTIL_LISTIFY_213(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(213, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_215(F, sep, ...) \ + Z_UTIL_LISTIFY_214(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(214, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_216(F, sep, ...) \ + Z_UTIL_LISTIFY_215(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(215, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_217(F, sep, ...) \ + Z_UTIL_LISTIFY_216(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(216, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_218(F, sep, ...) \ + Z_UTIL_LISTIFY_217(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(217, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_219(F, sep, ...) \ + Z_UTIL_LISTIFY_218(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(218, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_220(F, sep, ...) \ + Z_UTIL_LISTIFY_219(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(219, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_221(F, sep, ...) \ + Z_UTIL_LISTIFY_220(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(220, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_222(F, sep, ...) \ + Z_UTIL_LISTIFY_221(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(221, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_223(F, sep, ...) \ + Z_UTIL_LISTIFY_222(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(222, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_224(F, sep, ...) \ + Z_UTIL_LISTIFY_223(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(223, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_225(F, sep, ...) \ + Z_UTIL_LISTIFY_224(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(224, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_226(F, sep, ...) \ + Z_UTIL_LISTIFY_225(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(225, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_227(F, sep, ...) \ + Z_UTIL_LISTIFY_226(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(226, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_228(F, sep, ...) \ + Z_UTIL_LISTIFY_227(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(227, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_229(F, sep, ...) \ + Z_UTIL_LISTIFY_228(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(228, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_230(F, sep, ...) \ + Z_UTIL_LISTIFY_229(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(229, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_231(F, sep, ...) \ + Z_UTIL_LISTIFY_230(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(230, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_232(F, sep, ...) \ + Z_UTIL_LISTIFY_231(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(231, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_233(F, sep, ...) \ + Z_UTIL_LISTIFY_232(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(232, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_234(F, sep, ...) \ + Z_UTIL_LISTIFY_233(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(233, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_235(F, sep, ...) \ + Z_UTIL_LISTIFY_234(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(234, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_236(F, sep, ...) \ + Z_UTIL_LISTIFY_235(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(235, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_237(F, sep, ...) \ + Z_UTIL_LISTIFY_236(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(236, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_238(F, sep, ...) \ + Z_UTIL_LISTIFY_237(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(237, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_239(F, sep, ...) \ + Z_UTIL_LISTIFY_238(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(238, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_240(F, sep, ...) \ + Z_UTIL_LISTIFY_239(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(239, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_241(F, sep, ...) \ + Z_UTIL_LISTIFY_240(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(240, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_242(F, sep, ...) \ + Z_UTIL_LISTIFY_241(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(241, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_243(F, sep, ...) \ + Z_UTIL_LISTIFY_242(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(242, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_244(F, sep, ...) \ + Z_UTIL_LISTIFY_243(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(243, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_245(F, sep, ...) \ + Z_UTIL_LISTIFY_244(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(244, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_246(F, sep, ...) \ + Z_UTIL_LISTIFY_245(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(245, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_247(F, sep, ...) \ + Z_UTIL_LISTIFY_246(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(246, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_248(F, sep, ...) \ + Z_UTIL_LISTIFY_247(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(247, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_249(F, sep, ...) \ + Z_UTIL_LISTIFY_248(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(248, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_250(F, sep, ...) \ + Z_UTIL_LISTIFY_249(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(249, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_251(F, sep, ...) \ + Z_UTIL_LISTIFY_250(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(250, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_252(F, sep, ...) \ + Z_UTIL_LISTIFY_251(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(251, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_253(F, sep, ...) \ + Z_UTIL_LISTIFY_252(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(252, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_254(F, sep, ...) \ + Z_UTIL_LISTIFY_253(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(253, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_255(F, sep, ...) \ + Z_UTIL_LISTIFY_254(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(254, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_256(F, sep, ...) \ + Z_UTIL_LISTIFY_255(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(255, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_257(F, sep, ...) \ + Z_UTIL_LISTIFY_256(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(256, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_258(F, sep, ...) \ + Z_UTIL_LISTIFY_257(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(257, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_259(F, sep, ...) \ + Z_UTIL_LISTIFY_258(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(258, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_260(F, sep, ...) \ + Z_UTIL_LISTIFY_259(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(259, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_261(F, sep, ...) \ + Z_UTIL_LISTIFY_260(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(260, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_262(F, sep, ...) \ + Z_UTIL_LISTIFY_261(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(261, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_263(F, sep, ...) \ + Z_UTIL_LISTIFY_262(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(262, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_264(F, sep, ...) \ + Z_UTIL_LISTIFY_263(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(263, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_265(F, sep, ...) \ + Z_UTIL_LISTIFY_264(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(264, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_266(F, sep, ...) \ + Z_UTIL_LISTIFY_265(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(265, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_267(F, sep, ...) \ + Z_UTIL_LISTIFY_266(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(266, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_268(F, sep, ...) \ + Z_UTIL_LISTIFY_267(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(267, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_269(F, sep, ...) \ + Z_UTIL_LISTIFY_268(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(268, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_270(F, sep, ...) \ + Z_UTIL_LISTIFY_269(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(269, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_271(F, sep, ...) \ + Z_UTIL_LISTIFY_270(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(270, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_272(F, sep, ...) \ + Z_UTIL_LISTIFY_271(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(271, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_273(F, sep, ...) \ + Z_UTIL_LISTIFY_272(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(272, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_274(F, sep, ...) \ + Z_UTIL_LISTIFY_273(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(273, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_275(F, sep, ...) \ + Z_UTIL_LISTIFY_274(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(274, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_276(F, sep, ...) \ + Z_UTIL_LISTIFY_275(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(275, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_277(F, sep, ...) \ + Z_UTIL_LISTIFY_276(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(276, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_278(F, sep, ...) \ + Z_UTIL_LISTIFY_277(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(277, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_279(F, sep, ...) \ + Z_UTIL_LISTIFY_278(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(278, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_280(F, sep, ...) \ + Z_UTIL_LISTIFY_279(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(279, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_281(F, sep, ...) \ + Z_UTIL_LISTIFY_280(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(280, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_282(F, sep, ...) \ + Z_UTIL_LISTIFY_281(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(281, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_283(F, sep, ...) \ + Z_UTIL_LISTIFY_282(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(282, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_284(F, sep, ...) \ + Z_UTIL_LISTIFY_283(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(283, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_285(F, sep, ...) \ + Z_UTIL_LISTIFY_284(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(284, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_286(F, sep, ...) \ + Z_UTIL_LISTIFY_285(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(285, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_287(F, sep, ...) \ + Z_UTIL_LISTIFY_286(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(286, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_288(F, sep, ...) \ + Z_UTIL_LISTIFY_287(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(287, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_289(F, sep, ...) \ + Z_UTIL_LISTIFY_288(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(288, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_290(F, sep, ...) \ + Z_UTIL_LISTIFY_289(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(289, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_291(F, sep, ...) \ + Z_UTIL_LISTIFY_290(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(290, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_292(F, sep, ...) \ + Z_UTIL_LISTIFY_291(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(291, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_293(F, sep, ...) \ + Z_UTIL_LISTIFY_292(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(292, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_294(F, sep, ...) \ + Z_UTIL_LISTIFY_293(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(293, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_295(F, sep, ...) \ + Z_UTIL_LISTIFY_294(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(294, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_296(F, sep, ...) \ + Z_UTIL_LISTIFY_295(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(295, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_297(F, sep, ...) \ + Z_UTIL_LISTIFY_296(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(296, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_298(F, sep, ...) \ + Z_UTIL_LISTIFY_297(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(297, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_299(F, sep, ...) \ + Z_UTIL_LISTIFY_298(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(298, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_300(F, sep, ...) \ + Z_UTIL_LISTIFY_299(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(299, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_301(F, sep, ...) \ + Z_UTIL_LISTIFY_300(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(300, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_302(F, sep, ...) \ + Z_UTIL_LISTIFY_301(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(301, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_303(F, sep, ...) \ + Z_UTIL_LISTIFY_302(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(302, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_304(F, sep, ...) \ + Z_UTIL_LISTIFY_303(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(303, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_305(F, sep, ...) \ + Z_UTIL_LISTIFY_304(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(304, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_306(F, sep, ...) \ + Z_UTIL_LISTIFY_305(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(305, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_307(F, sep, ...) \ + Z_UTIL_LISTIFY_306(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(306, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_308(F, sep, ...) \ + Z_UTIL_LISTIFY_307(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(307, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_309(F, sep, ...) \ + Z_UTIL_LISTIFY_308(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(308, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_310(F, sep, ...) \ + Z_UTIL_LISTIFY_309(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(309, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_311(F, sep, ...) \ + Z_UTIL_LISTIFY_310(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(310, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_312(F, sep, ...) \ + Z_UTIL_LISTIFY_311(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(311, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_313(F, sep, ...) \ + Z_UTIL_LISTIFY_312(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(312, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_314(F, sep, ...) \ + Z_UTIL_LISTIFY_313(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(313, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_315(F, sep, ...) \ + Z_UTIL_LISTIFY_314(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(314, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_316(F, sep, ...) \ + Z_UTIL_LISTIFY_315(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(315, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_317(F, sep, ...) \ + Z_UTIL_LISTIFY_316(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(316, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_318(F, sep, ...) \ + Z_UTIL_LISTIFY_317(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(317, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_319(F, sep, ...) \ + Z_UTIL_LISTIFY_318(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(318, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_320(F, sep, ...) \ + Z_UTIL_LISTIFY_319(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(319, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_321(F, sep, ...) \ + Z_UTIL_LISTIFY_320(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(320, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_322(F, sep, ...) \ + Z_UTIL_LISTIFY_321(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(321, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_323(F, sep, ...) \ + Z_UTIL_LISTIFY_322(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(322, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_324(F, sep, ...) \ + Z_UTIL_LISTIFY_323(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(323, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_325(F, sep, ...) \ + Z_UTIL_LISTIFY_324(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(324, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_326(F, sep, ...) \ + Z_UTIL_LISTIFY_325(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(325, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_327(F, sep, ...) \ + Z_UTIL_LISTIFY_326(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(326, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_328(F, sep, ...) \ + Z_UTIL_LISTIFY_327(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(327, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_329(F, sep, ...) \ + Z_UTIL_LISTIFY_328(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(328, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_330(F, sep, ...) \ + Z_UTIL_LISTIFY_329(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(329, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_331(F, sep, ...) \ + Z_UTIL_LISTIFY_330(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(330, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_332(F, sep, ...) \ + Z_UTIL_LISTIFY_331(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(331, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_333(F, sep, ...) \ + Z_UTIL_LISTIFY_332(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(332, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_334(F, sep, ...) \ + Z_UTIL_LISTIFY_333(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(333, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_335(F, sep, ...) \ + Z_UTIL_LISTIFY_334(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(334, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_336(F, sep, ...) \ + Z_UTIL_LISTIFY_335(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(335, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_337(F, sep, ...) \ + Z_UTIL_LISTIFY_336(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(336, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_338(F, sep, ...) \ + Z_UTIL_LISTIFY_337(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(337, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_339(F, sep, ...) \ + Z_UTIL_LISTIFY_338(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(338, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_340(F, sep, ...) \ + Z_UTIL_LISTIFY_339(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(339, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_341(F, sep, ...) \ + Z_UTIL_LISTIFY_340(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(340, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_342(F, sep, ...) \ + Z_UTIL_LISTIFY_341(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(341, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_343(F, sep, ...) \ + Z_UTIL_LISTIFY_342(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(342, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_344(F, sep, ...) \ + Z_UTIL_LISTIFY_343(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(343, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_345(F, sep, ...) \ + Z_UTIL_LISTIFY_344(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(344, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_346(F, sep, ...) \ + Z_UTIL_LISTIFY_345(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(345, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_347(F, sep, ...) \ + Z_UTIL_LISTIFY_346(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(346, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_348(F, sep, ...) \ + Z_UTIL_LISTIFY_347(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(347, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_349(F, sep, ...) \ + Z_UTIL_LISTIFY_348(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(348, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_350(F, sep, ...) \ + Z_UTIL_LISTIFY_349(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(349, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_351(F, sep, ...) \ + Z_UTIL_LISTIFY_350(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(350, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_352(F, sep, ...) \ + Z_UTIL_LISTIFY_351(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(351, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_353(F, sep, ...) \ + Z_UTIL_LISTIFY_352(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(352, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_354(F, sep, ...) \ + Z_UTIL_LISTIFY_353(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(353, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_355(F, sep, ...) \ + Z_UTIL_LISTIFY_354(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(354, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_356(F, sep, ...) \ + Z_UTIL_LISTIFY_355(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(355, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_357(F, sep, ...) \ + Z_UTIL_LISTIFY_356(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(356, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_358(F, sep, ...) \ + Z_UTIL_LISTIFY_357(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(357, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_359(F, sep, ...) \ + Z_UTIL_LISTIFY_358(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(358, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_360(F, sep, ...) \ + Z_UTIL_LISTIFY_359(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(359, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_361(F, sep, ...) \ + Z_UTIL_LISTIFY_360(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(360, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_362(F, sep, ...) \ + Z_UTIL_LISTIFY_361(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(361, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_363(F, sep, ...) \ + Z_UTIL_LISTIFY_362(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(362, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_364(F, sep, ...) \ + Z_UTIL_LISTIFY_363(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(363, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_365(F, sep, ...) \ + Z_UTIL_LISTIFY_364(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(364, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_366(F, sep, ...) \ + Z_UTIL_LISTIFY_365(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(365, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_367(F, sep, ...) \ + Z_UTIL_LISTIFY_366(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(366, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_368(F, sep, ...) \ + Z_UTIL_LISTIFY_367(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(367, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_369(F, sep, ...) \ + Z_UTIL_LISTIFY_368(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(368, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_370(F, sep, ...) \ + Z_UTIL_LISTIFY_369(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(369, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_371(F, sep, ...) \ + Z_UTIL_LISTIFY_370(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(370, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_372(F, sep, ...) \ + Z_UTIL_LISTIFY_371(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(371, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_373(F, sep, ...) \ + Z_UTIL_LISTIFY_372(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(372, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_374(F, sep, ...) \ + Z_UTIL_LISTIFY_373(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(373, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_375(F, sep, ...) \ + Z_UTIL_LISTIFY_374(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(374, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_376(F, sep, ...) \ + Z_UTIL_LISTIFY_375(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(375, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_377(F, sep, ...) \ + Z_UTIL_LISTIFY_376(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(376, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_378(F, sep, ...) \ + Z_UTIL_LISTIFY_377(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(377, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_379(F, sep, ...) \ + Z_UTIL_LISTIFY_378(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(378, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_380(F, sep, ...) \ + Z_UTIL_LISTIFY_379(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(379, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_381(F, sep, ...) \ + Z_UTIL_LISTIFY_380(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(380, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_382(F, sep, ...) \ + Z_UTIL_LISTIFY_381(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(381, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_383(F, sep, ...) \ + Z_UTIL_LISTIFY_382(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(382, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_384(F, sep, ...) \ + Z_UTIL_LISTIFY_383(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(383, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_385(F, sep, ...) \ + Z_UTIL_LISTIFY_384(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(384, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_386(F, sep, ...) \ + Z_UTIL_LISTIFY_385(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(385, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_387(F, sep, ...) \ + Z_UTIL_LISTIFY_386(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(386, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_388(F, sep, ...) \ + Z_UTIL_LISTIFY_387(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(387, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_389(F, sep, ...) \ + Z_UTIL_LISTIFY_388(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(388, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_390(F, sep, ...) \ + Z_UTIL_LISTIFY_389(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(389, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_391(F, sep, ...) \ + Z_UTIL_LISTIFY_390(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(390, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_392(F, sep, ...) \ + Z_UTIL_LISTIFY_391(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(391, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_393(F, sep, ...) \ + Z_UTIL_LISTIFY_392(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(392, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_394(F, sep, ...) \ + Z_UTIL_LISTIFY_393(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(393, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_395(F, sep, ...) \ + Z_UTIL_LISTIFY_394(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(394, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_396(F, sep, ...) \ + Z_UTIL_LISTIFY_395(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(395, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_397(F, sep, ...) \ + Z_UTIL_LISTIFY_396(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(396, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_398(F, sep, ...) \ + Z_UTIL_LISTIFY_397(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(397, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_399(F, sep, ...) \ + Z_UTIL_LISTIFY_398(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(398, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_400(F, sep, ...) \ + Z_UTIL_LISTIFY_399(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(399, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_401(F, sep, ...) \ + Z_UTIL_LISTIFY_400(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(400, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_402(F, sep, ...) \ + Z_UTIL_LISTIFY_401(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(401, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_403(F, sep, ...) \ + Z_UTIL_LISTIFY_402(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(402, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_404(F, sep, ...) \ + Z_UTIL_LISTIFY_403(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(403, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_405(F, sep, ...) \ + Z_UTIL_LISTIFY_404(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(404, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_406(F, sep, ...) \ + Z_UTIL_LISTIFY_405(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(405, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_407(F, sep, ...) \ + Z_UTIL_LISTIFY_406(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(406, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_408(F, sep, ...) \ + Z_UTIL_LISTIFY_407(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(407, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_409(F, sep, ...) \ + Z_UTIL_LISTIFY_408(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(408, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_410(F, sep, ...) \ + Z_UTIL_LISTIFY_409(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(409, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_411(F, sep, ...) \ + Z_UTIL_LISTIFY_410(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(410, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_412(F, sep, ...) \ + Z_UTIL_LISTIFY_411(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(411, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_413(F, sep, ...) \ + Z_UTIL_LISTIFY_412(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(412, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_414(F, sep, ...) \ + Z_UTIL_LISTIFY_413(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(413, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_415(F, sep, ...) \ + Z_UTIL_LISTIFY_414(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(414, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_416(F, sep, ...) \ + Z_UTIL_LISTIFY_415(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(415, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_417(F, sep, ...) \ + Z_UTIL_LISTIFY_416(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(416, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_418(F, sep, ...) \ + Z_UTIL_LISTIFY_417(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(417, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_419(F, sep, ...) \ + Z_UTIL_LISTIFY_418(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(418, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_420(F, sep, ...) \ + Z_UTIL_LISTIFY_419(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(419, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_421(F, sep, ...) \ + Z_UTIL_LISTIFY_420(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(420, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_422(F, sep, ...) \ + Z_UTIL_LISTIFY_421(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(421, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_423(F, sep, ...) \ + Z_UTIL_LISTIFY_422(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(422, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_424(F, sep, ...) \ + Z_UTIL_LISTIFY_423(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(423, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_425(F, sep, ...) \ + Z_UTIL_LISTIFY_424(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(424, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_426(F, sep, ...) \ + Z_UTIL_LISTIFY_425(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(425, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_427(F, sep, ...) \ + Z_UTIL_LISTIFY_426(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(426, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_428(F, sep, ...) \ + Z_UTIL_LISTIFY_427(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(427, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_429(F, sep, ...) \ + Z_UTIL_LISTIFY_428(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(428, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_430(F, sep, ...) \ + Z_UTIL_LISTIFY_429(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(429, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_431(F, sep, ...) \ + Z_UTIL_LISTIFY_430(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(430, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_432(F, sep, ...) \ + Z_UTIL_LISTIFY_431(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(431, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_433(F, sep, ...) \ + Z_UTIL_LISTIFY_432(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(432, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_434(F, sep, ...) \ + Z_UTIL_LISTIFY_433(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(433, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_435(F, sep, ...) \ + Z_UTIL_LISTIFY_434(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(434, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_436(F, sep, ...) \ + Z_UTIL_LISTIFY_435(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(435, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_437(F, sep, ...) \ + Z_UTIL_LISTIFY_436(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(436, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_438(F, sep, ...) \ + Z_UTIL_LISTIFY_437(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(437, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_439(F, sep, ...) \ + Z_UTIL_LISTIFY_438(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(438, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_440(F, sep, ...) \ + Z_UTIL_LISTIFY_439(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(439, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_441(F, sep, ...) \ + Z_UTIL_LISTIFY_440(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(440, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_442(F, sep, ...) \ + Z_UTIL_LISTIFY_441(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(441, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_443(F, sep, ...) \ + Z_UTIL_LISTIFY_442(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(442, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_444(F, sep, ...) \ + Z_UTIL_LISTIFY_443(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(443, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_445(F, sep, ...) \ + Z_UTIL_LISTIFY_444(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(444, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_446(F, sep, ...) \ + Z_UTIL_LISTIFY_445(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(445, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_447(F, sep, ...) \ + Z_UTIL_LISTIFY_446(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(446, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_448(F, sep, ...) \ + Z_UTIL_LISTIFY_447(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(447, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_449(F, sep, ...) \ + Z_UTIL_LISTIFY_448(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(448, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_450(F, sep, ...) \ + Z_UTIL_LISTIFY_449(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(449, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_451(F, sep, ...) \ + Z_UTIL_LISTIFY_450(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(450, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_452(F, sep, ...) \ + Z_UTIL_LISTIFY_451(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(451, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_453(F, sep, ...) \ + Z_UTIL_LISTIFY_452(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(452, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_454(F, sep, ...) \ + Z_UTIL_LISTIFY_453(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(453, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_455(F, sep, ...) \ + Z_UTIL_LISTIFY_454(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(454, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_456(F, sep, ...) \ + Z_UTIL_LISTIFY_455(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(455, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_457(F, sep, ...) \ + Z_UTIL_LISTIFY_456(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(456, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_458(F, sep, ...) \ + Z_UTIL_LISTIFY_457(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(457, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_459(F, sep, ...) \ + Z_UTIL_LISTIFY_458(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(458, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_460(F, sep, ...) \ + Z_UTIL_LISTIFY_459(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(459, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_461(F, sep, ...) \ + Z_UTIL_LISTIFY_460(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(460, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_462(F, sep, ...) \ + Z_UTIL_LISTIFY_461(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(461, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_463(F, sep, ...) \ + Z_UTIL_LISTIFY_462(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(462, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_464(F, sep, ...) \ + Z_UTIL_LISTIFY_463(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(463, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_465(F, sep, ...) \ + Z_UTIL_LISTIFY_464(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(464, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_466(F, sep, ...) \ + Z_UTIL_LISTIFY_465(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(465, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_467(F, sep, ...) \ + Z_UTIL_LISTIFY_466(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(466, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_468(F, sep, ...) \ + Z_UTIL_LISTIFY_467(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(467, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_469(F, sep, ...) \ + Z_UTIL_LISTIFY_468(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(468, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_470(F, sep, ...) \ + Z_UTIL_LISTIFY_469(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(469, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_471(F, sep, ...) \ + Z_UTIL_LISTIFY_470(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(470, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_472(F, sep, ...) \ + Z_UTIL_LISTIFY_471(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(471, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_473(F, sep, ...) \ + Z_UTIL_LISTIFY_472(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(472, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_474(F, sep, ...) \ + Z_UTIL_LISTIFY_473(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(473, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_475(F, sep, ...) \ + Z_UTIL_LISTIFY_474(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(474, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_476(F, sep, ...) \ + Z_UTIL_LISTIFY_475(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(475, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_477(F, sep, ...) \ + Z_UTIL_LISTIFY_476(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(476, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_478(F, sep, ...) \ + Z_UTIL_LISTIFY_477(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(477, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_479(F, sep, ...) \ + Z_UTIL_LISTIFY_478(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(478, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_480(F, sep, ...) \ + Z_UTIL_LISTIFY_479(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(479, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_481(F, sep, ...) \ + Z_UTIL_LISTIFY_480(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(480, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_482(F, sep, ...) \ + Z_UTIL_LISTIFY_481(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(481, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_483(F, sep, ...) \ + Z_UTIL_LISTIFY_482(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(482, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_484(F, sep, ...) \ + Z_UTIL_LISTIFY_483(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(483, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_485(F, sep, ...) \ + Z_UTIL_LISTIFY_484(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(484, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_486(F, sep, ...) \ + Z_UTIL_LISTIFY_485(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(485, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_487(F, sep, ...) \ + Z_UTIL_LISTIFY_486(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(486, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_488(F, sep, ...) \ + Z_UTIL_LISTIFY_487(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(487, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_489(F, sep, ...) \ + Z_UTIL_LISTIFY_488(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(488, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_490(F, sep, ...) \ + Z_UTIL_LISTIFY_489(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(489, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_491(F, sep, ...) \ + Z_UTIL_LISTIFY_490(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(490, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_492(F, sep, ...) \ + Z_UTIL_LISTIFY_491(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(491, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_493(F, sep, ...) \ + Z_UTIL_LISTIFY_492(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(492, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_494(F, sep, ...) \ + Z_UTIL_LISTIFY_493(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(493, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_495(F, sep, ...) \ + Z_UTIL_LISTIFY_494(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(494, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_496(F, sep, ...) \ + Z_UTIL_LISTIFY_495(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(495, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_497(F, sep, ...) \ + Z_UTIL_LISTIFY_496(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(496, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_498(F, sep, ...) \ + Z_UTIL_LISTIFY_497(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(497, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_499(F, sep, ...) \ + Z_UTIL_LISTIFY_498(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(498, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_500(F, sep, ...) \ + Z_UTIL_LISTIFY_499(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(499, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_501(F, sep, ...) \ + Z_UTIL_LISTIFY_500(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(500, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_502(F, sep, ...) \ + Z_UTIL_LISTIFY_501(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(501, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_503(F, sep, ...) \ + Z_UTIL_LISTIFY_502(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(502, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_504(F, sep, ...) \ + Z_UTIL_LISTIFY_503(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(503, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_505(F, sep, ...) \ + Z_UTIL_LISTIFY_504(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(504, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_506(F, sep, ...) \ + Z_UTIL_LISTIFY_505(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(505, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_507(F, sep, ...) \ + Z_UTIL_LISTIFY_506(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(506, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_508(F, sep, ...) \ + Z_UTIL_LISTIFY_507(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(507, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_509(F, sep, ...) \ + Z_UTIL_LISTIFY_508(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(508, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_510(F, sep, ...) \ + Z_UTIL_LISTIFY_509(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(509, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_511(F, sep, ...) \ + Z_UTIL_LISTIFY_510(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(510, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_512(F, sep, ...) \ + Z_UTIL_LISTIFY_511(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(511, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_513(F, sep, ...) \ + Z_UTIL_LISTIFY_512(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(512, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_514(F, sep, ...) \ + Z_UTIL_LISTIFY_513(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(513, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_515(F, sep, ...) \ + Z_UTIL_LISTIFY_514(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(514, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_516(F, sep, ...) \ + Z_UTIL_LISTIFY_515(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(515, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_517(F, sep, ...) \ + Z_UTIL_LISTIFY_516(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(516, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_518(F, sep, ...) \ + Z_UTIL_LISTIFY_517(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(517, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_519(F, sep, ...) \ + Z_UTIL_LISTIFY_518(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(518, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_520(F, sep, ...) \ + Z_UTIL_LISTIFY_519(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(519, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_521(F, sep, ...) \ + Z_UTIL_LISTIFY_520(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(520, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_522(F, sep, ...) \ + Z_UTIL_LISTIFY_521(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(521, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_523(F, sep, ...) \ + Z_UTIL_LISTIFY_522(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(522, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_524(F, sep, ...) \ + Z_UTIL_LISTIFY_523(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(523, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_525(F, sep, ...) \ + Z_UTIL_LISTIFY_524(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(524, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_526(F, sep, ...) \ + Z_UTIL_LISTIFY_525(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(525, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_527(F, sep, ...) \ + Z_UTIL_LISTIFY_526(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(526, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_528(F, sep, ...) \ + Z_UTIL_LISTIFY_527(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(527, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_529(F, sep, ...) \ + Z_UTIL_LISTIFY_528(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(528, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_530(F, sep, ...) \ + Z_UTIL_LISTIFY_529(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(529, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_531(F, sep, ...) \ + Z_UTIL_LISTIFY_530(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(530, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_532(F, sep, ...) \ + Z_UTIL_LISTIFY_531(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(531, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_533(F, sep, ...) \ + Z_UTIL_LISTIFY_532(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(532, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_534(F, sep, ...) \ + Z_UTIL_LISTIFY_533(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(533, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_535(F, sep, ...) \ + Z_UTIL_LISTIFY_534(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(534, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_536(F, sep, ...) \ + Z_UTIL_LISTIFY_535(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(535, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_537(F, sep, ...) \ + Z_UTIL_LISTIFY_536(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(536, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_538(F, sep, ...) \ + Z_UTIL_LISTIFY_537(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(537, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_539(F, sep, ...) \ + Z_UTIL_LISTIFY_538(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(538, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_540(F, sep, ...) \ + Z_UTIL_LISTIFY_539(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(539, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_541(F, sep, ...) \ + Z_UTIL_LISTIFY_540(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(540, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_542(F, sep, ...) \ + Z_UTIL_LISTIFY_541(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(541, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_543(F, sep, ...) \ + Z_UTIL_LISTIFY_542(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(542, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_544(F, sep, ...) \ + Z_UTIL_LISTIFY_543(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(543, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_545(F, sep, ...) \ + Z_UTIL_LISTIFY_544(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(544, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_546(F, sep, ...) \ + Z_UTIL_LISTIFY_545(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(545, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_547(F, sep, ...) \ + Z_UTIL_LISTIFY_546(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(546, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_548(F, sep, ...) \ + Z_UTIL_LISTIFY_547(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(547, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_549(F, sep, ...) \ + Z_UTIL_LISTIFY_548(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(548, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_550(F, sep, ...) \ + Z_UTIL_LISTIFY_549(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(549, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_551(F, sep, ...) \ + Z_UTIL_LISTIFY_550(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(550, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_552(F, sep, ...) \ + Z_UTIL_LISTIFY_551(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(551, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_553(F, sep, ...) \ + Z_UTIL_LISTIFY_552(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(552, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_554(F, sep, ...) \ + Z_UTIL_LISTIFY_553(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(553, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_555(F, sep, ...) \ + Z_UTIL_LISTIFY_554(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(554, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_556(F, sep, ...) \ + Z_UTIL_LISTIFY_555(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(555, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_557(F, sep, ...) \ + Z_UTIL_LISTIFY_556(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(556, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_558(F, sep, ...) \ + Z_UTIL_LISTIFY_557(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(557, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_559(F, sep, ...) \ + Z_UTIL_LISTIFY_558(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(558, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_560(F, sep, ...) \ + Z_UTIL_LISTIFY_559(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(559, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_561(F, sep, ...) \ + Z_UTIL_LISTIFY_560(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(560, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_562(F, sep, ...) \ + Z_UTIL_LISTIFY_561(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(561, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_563(F, sep, ...) \ + Z_UTIL_LISTIFY_562(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(562, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_564(F, sep, ...) \ + Z_UTIL_LISTIFY_563(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(563, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_565(F, sep, ...) \ + Z_UTIL_LISTIFY_564(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(564, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_566(F, sep, ...) \ + Z_UTIL_LISTIFY_565(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(565, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_567(F, sep, ...) \ + Z_UTIL_LISTIFY_566(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(566, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_568(F, sep, ...) \ + Z_UTIL_LISTIFY_567(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(567, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_569(F, sep, ...) \ + Z_UTIL_LISTIFY_568(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(568, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_570(F, sep, ...) \ + Z_UTIL_LISTIFY_569(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(569, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_571(F, sep, ...) \ + Z_UTIL_LISTIFY_570(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(570, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_572(F, sep, ...) \ + Z_UTIL_LISTIFY_571(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(571, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_573(F, sep, ...) \ + Z_UTIL_LISTIFY_572(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(572, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_574(F, sep, ...) \ + Z_UTIL_LISTIFY_573(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(573, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_575(F, sep, ...) \ + Z_UTIL_LISTIFY_574(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(574, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_576(F, sep, ...) \ + Z_UTIL_LISTIFY_575(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(575, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_577(F, sep, ...) \ + Z_UTIL_LISTIFY_576(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(576, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_578(F, sep, ...) \ + Z_UTIL_LISTIFY_577(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(577, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_579(F, sep, ...) \ + Z_UTIL_LISTIFY_578(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(578, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_580(F, sep, ...) \ + Z_UTIL_LISTIFY_579(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(579, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_581(F, sep, ...) \ + Z_UTIL_LISTIFY_580(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(580, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_582(F, sep, ...) \ + Z_UTIL_LISTIFY_581(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(581, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_583(F, sep, ...) \ + Z_UTIL_LISTIFY_582(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(582, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_584(F, sep, ...) \ + Z_UTIL_LISTIFY_583(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(583, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_585(F, sep, ...) \ + Z_UTIL_LISTIFY_584(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(584, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_586(F, sep, ...) \ + Z_UTIL_LISTIFY_585(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(585, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_587(F, sep, ...) \ + Z_UTIL_LISTIFY_586(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(586, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_588(F, sep, ...) \ + Z_UTIL_LISTIFY_587(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(587, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_589(F, sep, ...) \ + Z_UTIL_LISTIFY_588(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(588, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_590(F, sep, ...) \ + Z_UTIL_LISTIFY_589(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(589, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_591(F, sep, ...) \ + Z_UTIL_LISTIFY_590(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(590, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_592(F, sep, ...) \ + Z_UTIL_LISTIFY_591(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(591, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_593(F, sep, ...) \ + Z_UTIL_LISTIFY_592(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(592, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_594(F, sep, ...) \ + Z_UTIL_LISTIFY_593(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(593, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_595(F, sep, ...) \ + Z_UTIL_LISTIFY_594(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(594, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_596(F, sep, ...) \ + Z_UTIL_LISTIFY_595(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(595, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_597(F, sep, ...) \ + Z_UTIL_LISTIFY_596(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(596, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_598(F, sep, ...) \ + Z_UTIL_LISTIFY_597(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(597, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_599(F, sep, ...) \ + Z_UTIL_LISTIFY_598(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(598, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_600(F, sep, ...) \ + Z_UTIL_LISTIFY_599(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(599, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_601(F, sep, ...) \ + Z_UTIL_LISTIFY_600(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(600, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_602(F, sep, ...) \ + Z_UTIL_LISTIFY_601(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(601, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_603(F, sep, ...) \ + Z_UTIL_LISTIFY_602(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(602, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_604(F, sep, ...) \ + Z_UTIL_LISTIFY_603(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(603, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_605(F, sep, ...) \ + Z_UTIL_LISTIFY_604(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(604, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_606(F, sep, ...) \ + Z_UTIL_LISTIFY_605(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(605, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_607(F, sep, ...) \ + Z_UTIL_LISTIFY_606(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(606, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_608(F, sep, ...) \ + Z_UTIL_LISTIFY_607(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(607, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_609(F, sep, ...) \ + Z_UTIL_LISTIFY_608(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(608, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_610(F, sep, ...) \ + Z_UTIL_LISTIFY_609(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(609, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_611(F, sep, ...) \ + Z_UTIL_LISTIFY_610(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(610, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_612(F, sep, ...) \ + Z_UTIL_LISTIFY_611(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(611, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_613(F, sep, ...) \ + Z_UTIL_LISTIFY_612(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(612, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_614(F, sep, ...) \ + Z_UTIL_LISTIFY_613(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(613, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_615(F, sep, ...) \ + Z_UTIL_LISTIFY_614(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(614, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_616(F, sep, ...) \ + Z_UTIL_LISTIFY_615(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(615, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_617(F, sep, ...) \ + Z_UTIL_LISTIFY_616(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(616, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_618(F, sep, ...) \ + Z_UTIL_LISTIFY_617(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(617, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_619(F, sep, ...) \ + Z_UTIL_LISTIFY_618(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(618, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_620(F, sep, ...) \ + Z_UTIL_LISTIFY_619(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(619, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_621(F, sep, ...) \ + Z_UTIL_LISTIFY_620(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(620, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_622(F, sep, ...) \ + Z_UTIL_LISTIFY_621(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(621, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_623(F, sep, ...) \ + Z_UTIL_LISTIFY_622(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(622, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_624(F, sep, ...) \ + Z_UTIL_LISTIFY_623(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(623, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_625(F, sep, ...) \ + Z_UTIL_LISTIFY_624(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(624, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_626(F, sep, ...) \ + Z_UTIL_LISTIFY_625(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(625, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_627(F, sep, ...) \ + Z_UTIL_LISTIFY_626(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(626, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_628(F, sep, ...) \ + Z_UTIL_LISTIFY_627(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(627, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_629(F, sep, ...) \ + Z_UTIL_LISTIFY_628(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(628, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_630(F, sep, ...) \ + Z_UTIL_LISTIFY_629(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(629, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_631(F, sep, ...) \ + Z_UTIL_LISTIFY_630(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(630, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_632(F, sep, ...) \ + Z_UTIL_LISTIFY_631(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(631, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_633(F, sep, ...) \ + Z_UTIL_LISTIFY_632(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(632, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_634(F, sep, ...) \ + Z_UTIL_LISTIFY_633(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(633, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_635(F, sep, ...) \ + Z_UTIL_LISTIFY_634(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(634, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_636(F, sep, ...) \ + Z_UTIL_LISTIFY_635(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(635, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_637(F, sep, ...) \ + Z_UTIL_LISTIFY_636(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(636, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_638(F, sep, ...) \ + Z_UTIL_LISTIFY_637(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(637, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_639(F, sep, ...) \ + Z_UTIL_LISTIFY_638(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(638, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_640(F, sep, ...) \ + Z_UTIL_LISTIFY_639(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(639, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_641(F, sep, ...) \ + Z_UTIL_LISTIFY_640(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(640, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_642(F, sep, ...) \ + Z_UTIL_LISTIFY_641(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(641, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_643(F, sep, ...) \ + Z_UTIL_LISTIFY_642(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(642, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_644(F, sep, ...) \ + Z_UTIL_LISTIFY_643(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(643, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_645(F, sep, ...) \ + Z_UTIL_LISTIFY_644(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(644, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_646(F, sep, ...) \ + Z_UTIL_LISTIFY_645(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(645, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_647(F, sep, ...) \ + Z_UTIL_LISTIFY_646(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(646, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_648(F, sep, ...) \ + Z_UTIL_LISTIFY_647(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(647, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_649(F, sep, ...) \ + Z_UTIL_LISTIFY_648(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(648, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_650(F, sep, ...) \ + Z_UTIL_LISTIFY_649(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(649, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_651(F, sep, ...) \ + Z_UTIL_LISTIFY_650(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(650, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_652(F, sep, ...) \ + Z_UTIL_LISTIFY_651(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(651, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_653(F, sep, ...) \ + Z_UTIL_LISTIFY_652(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(652, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_654(F, sep, ...) \ + Z_UTIL_LISTIFY_653(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(653, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_655(F, sep, ...) \ + Z_UTIL_LISTIFY_654(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(654, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_656(F, sep, ...) \ + Z_UTIL_LISTIFY_655(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(655, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_657(F, sep, ...) \ + Z_UTIL_LISTIFY_656(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(656, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_658(F, sep, ...) \ + Z_UTIL_LISTIFY_657(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(657, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_659(F, sep, ...) \ + Z_UTIL_LISTIFY_658(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(658, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_660(F, sep, ...) \ + Z_UTIL_LISTIFY_659(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(659, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_661(F, sep, ...) \ + Z_UTIL_LISTIFY_660(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(660, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_662(F, sep, ...) \ + Z_UTIL_LISTIFY_661(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(661, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_663(F, sep, ...) \ + Z_UTIL_LISTIFY_662(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(662, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_664(F, sep, ...) \ + Z_UTIL_LISTIFY_663(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(663, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_665(F, sep, ...) \ + Z_UTIL_LISTIFY_664(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(664, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_666(F, sep, ...) \ + Z_UTIL_LISTIFY_665(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(665, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_667(F, sep, ...) \ + Z_UTIL_LISTIFY_666(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(666, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_668(F, sep, ...) \ + Z_UTIL_LISTIFY_667(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(667, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_669(F, sep, ...) \ + Z_UTIL_LISTIFY_668(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(668, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_670(F, sep, ...) \ + Z_UTIL_LISTIFY_669(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(669, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_671(F, sep, ...) \ + Z_UTIL_LISTIFY_670(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(670, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_672(F, sep, ...) \ + Z_UTIL_LISTIFY_671(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(671, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_673(F, sep, ...) \ + Z_UTIL_LISTIFY_672(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(672, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_674(F, sep, ...) \ + Z_UTIL_LISTIFY_673(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(673, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_675(F, sep, ...) \ + Z_UTIL_LISTIFY_674(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(674, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_676(F, sep, ...) \ + Z_UTIL_LISTIFY_675(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(675, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_677(F, sep, ...) \ + Z_UTIL_LISTIFY_676(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(676, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_678(F, sep, ...) \ + Z_UTIL_LISTIFY_677(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(677, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_679(F, sep, ...) \ + Z_UTIL_LISTIFY_678(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(678, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_680(F, sep, ...) \ + Z_UTIL_LISTIFY_679(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(679, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_681(F, sep, ...) \ + Z_UTIL_LISTIFY_680(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(680, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_682(F, sep, ...) \ + Z_UTIL_LISTIFY_681(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(681, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_683(F, sep, ...) \ + Z_UTIL_LISTIFY_682(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(682, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_684(F, sep, ...) \ + Z_UTIL_LISTIFY_683(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(683, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_685(F, sep, ...) \ + Z_UTIL_LISTIFY_684(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(684, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_686(F, sep, ...) \ + Z_UTIL_LISTIFY_685(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(685, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_687(F, sep, ...) \ + Z_UTIL_LISTIFY_686(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(686, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_688(F, sep, ...) \ + Z_UTIL_LISTIFY_687(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(687, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_689(F, sep, ...) \ + Z_UTIL_LISTIFY_688(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(688, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_690(F, sep, ...) \ + Z_UTIL_LISTIFY_689(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(689, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_691(F, sep, ...) \ + Z_UTIL_LISTIFY_690(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(690, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_692(F, sep, ...) \ + Z_UTIL_LISTIFY_691(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(691, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_693(F, sep, ...) \ + Z_UTIL_LISTIFY_692(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(692, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_694(F, sep, ...) \ + Z_UTIL_LISTIFY_693(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(693, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_695(F, sep, ...) \ + Z_UTIL_LISTIFY_694(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(694, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_696(F, sep, ...) \ + Z_UTIL_LISTIFY_695(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(695, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_697(F, sep, ...) \ + Z_UTIL_LISTIFY_696(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(696, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_698(F, sep, ...) \ + Z_UTIL_LISTIFY_697(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(697, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_699(F, sep, ...) \ + Z_UTIL_LISTIFY_698(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(698, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_700(F, sep, ...) \ + Z_UTIL_LISTIFY_699(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(699, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_701(F, sep, ...) \ + Z_UTIL_LISTIFY_700(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(700, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_702(F, sep, ...) \ + Z_UTIL_LISTIFY_701(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(701, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_703(F, sep, ...) \ + Z_UTIL_LISTIFY_702(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(702, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_704(F, sep, ...) \ + Z_UTIL_LISTIFY_703(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(703, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_705(F, sep, ...) \ + Z_UTIL_LISTIFY_704(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(704, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_706(F, sep, ...) \ + Z_UTIL_LISTIFY_705(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(705, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_707(F, sep, ...) \ + Z_UTIL_LISTIFY_706(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(706, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_708(F, sep, ...) \ + Z_UTIL_LISTIFY_707(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(707, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_709(F, sep, ...) \ + Z_UTIL_LISTIFY_708(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(708, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_710(F, sep, ...) \ + Z_UTIL_LISTIFY_709(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(709, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_711(F, sep, ...) \ + Z_UTIL_LISTIFY_710(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(710, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_712(F, sep, ...) \ + Z_UTIL_LISTIFY_711(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(711, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_713(F, sep, ...) \ + Z_UTIL_LISTIFY_712(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(712, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_714(F, sep, ...) \ + Z_UTIL_LISTIFY_713(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(713, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_715(F, sep, ...) \ + Z_UTIL_LISTIFY_714(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(714, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_716(F, sep, ...) \ + Z_UTIL_LISTIFY_715(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(715, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_717(F, sep, ...) \ + Z_UTIL_LISTIFY_716(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(716, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_718(F, sep, ...) \ + Z_UTIL_LISTIFY_717(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(717, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_719(F, sep, ...) \ + Z_UTIL_LISTIFY_718(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(718, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_720(F, sep, ...) \ + Z_UTIL_LISTIFY_719(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(719, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_721(F, sep, ...) \ + Z_UTIL_LISTIFY_720(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(720, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_722(F, sep, ...) \ + Z_UTIL_LISTIFY_721(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(721, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_723(F, sep, ...) \ + Z_UTIL_LISTIFY_722(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(722, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_724(F, sep, ...) \ + Z_UTIL_LISTIFY_723(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(723, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_725(F, sep, ...) \ + Z_UTIL_LISTIFY_724(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(724, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_726(F, sep, ...) \ + Z_UTIL_LISTIFY_725(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(725, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_727(F, sep, ...) \ + Z_UTIL_LISTIFY_726(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(726, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_728(F, sep, ...) \ + Z_UTIL_LISTIFY_727(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(727, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_729(F, sep, ...) \ + Z_UTIL_LISTIFY_728(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(728, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_730(F, sep, ...) \ + Z_UTIL_LISTIFY_729(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(729, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_731(F, sep, ...) \ + Z_UTIL_LISTIFY_730(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(730, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_732(F, sep, ...) \ + Z_UTIL_LISTIFY_731(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(731, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_733(F, sep, ...) \ + Z_UTIL_LISTIFY_732(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(732, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_734(F, sep, ...) \ + Z_UTIL_LISTIFY_733(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(733, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_735(F, sep, ...) \ + Z_UTIL_LISTIFY_734(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(734, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_736(F, sep, ...) \ + Z_UTIL_LISTIFY_735(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(735, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_737(F, sep, ...) \ + Z_UTIL_LISTIFY_736(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(736, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_738(F, sep, ...) \ + Z_UTIL_LISTIFY_737(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(737, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_739(F, sep, ...) \ + Z_UTIL_LISTIFY_738(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(738, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_740(F, sep, ...) \ + Z_UTIL_LISTIFY_739(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(739, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_741(F, sep, ...) \ + Z_UTIL_LISTIFY_740(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(740, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_742(F, sep, ...) \ + Z_UTIL_LISTIFY_741(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(741, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_743(F, sep, ...) \ + Z_UTIL_LISTIFY_742(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(742, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_744(F, sep, ...) \ + Z_UTIL_LISTIFY_743(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(743, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_745(F, sep, ...) \ + Z_UTIL_LISTIFY_744(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(744, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_746(F, sep, ...) \ + Z_UTIL_LISTIFY_745(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(745, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_747(F, sep, ...) \ + Z_UTIL_LISTIFY_746(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(746, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_748(F, sep, ...) \ + Z_UTIL_LISTIFY_747(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(747, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_749(F, sep, ...) \ + Z_UTIL_LISTIFY_748(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(748, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_750(F, sep, ...) \ + Z_UTIL_LISTIFY_749(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(749, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_751(F, sep, ...) \ + Z_UTIL_LISTIFY_750(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(750, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_752(F, sep, ...) \ + Z_UTIL_LISTIFY_751(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(751, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_753(F, sep, ...) \ + Z_UTIL_LISTIFY_752(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(752, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_754(F, sep, ...) \ + Z_UTIL_LISTIFY_753(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(753, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_755(F, sep, ...) \ + Z_UTIL_LISTIFY_754(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(754, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_756(F, sep, ...) \ + Z_UTIL_LISTIFY_755(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(755, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_757(F, sep, ...) \ + Z_UTIL_LISTIFY_756(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(756, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_758(F, sep, ...) \ + Z_UTIL_LISTIFY_757(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(757, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_759(F, sep, ...) \ + Z_UTIL_LISTIFY_758(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(758, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_760(F, sep, ...) \ + Z_UTIL_LISTIFY_759(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(759, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_761(F, sep, ...) \ + Z_UTIL_LISTIFY_760(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(760, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_762(F, sep, ...) \ + Z_UTIL_LISTIFY_761(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(761, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_763(F, sep, ...) \ + Z_UTIL_LISTIFY_762(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(762, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_764(F, sep, ...) \ + Z_UTIL_LISTIFY_763(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(763, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_765(F, sep, ...) \ + Z_UTIL_LISTIFY_764(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(764, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_766(F, sep, ...) \ + Z_UTIL_LISTIFY_765(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(765, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_767(F, sep, ...) \ + Z_UTIL_LISTIFY_766(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(766, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_768(F, sep, ...) \ + Z_UTIL_LISTIFY_767(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(767, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_769(F, sep, ...) \ + Z_UTIL_LISTIFY_768(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(768, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_770(F, sep, ...) \ + Z_UTIL_LISTIFY_769(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(769, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_771(F, sep, ...) \ + Z_UTIL_LISTIFY_770(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(770, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_772(F, sep, ...) \ + Z_UTIL_LISTIFY_771(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(771, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_773(F, sep, ...) \ + Z_UTIL_LISTIFY_772(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(772, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_774(F, sep, ...) \ + Z_UTIL_LISTIFY_773(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(773, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_775(F, sep, ...) \ + Z_UTIL_LISTIFY_774(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(774, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_776(F, sep, ...) \ + Z_UTIL_LISTIFY_775(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(775, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_777(F, sep, ...) \ + Z_UTIL_LISTIFY_776(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(776, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_778(F, sep, ...) \ + Z_UTIL_LISTIFY_777(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(777, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_779(F, sep, ...) \ + Z_UTIL_LISTIFY_778(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(778, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_780(F, sep, ...) \ + Z_UTIL_LISTIFY_779(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(779, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_781(F, sep, ...) \ + Z_UTIL_LISTIFY_780(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(780, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_782(F, sep, ...) \ + Z_UTIL_LISTIFY_781(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(781, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_783(F, sep, ...) \ + Z_UTIL_LISTIFY_782(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(782, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_784(F, sep, ...) \ + Z_UTIL_LISTIFY_783(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(783, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_785(F, sep, ...) \ + Z_UTIL_LISTIFY_784(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(784, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_786(F, sep, ...) \ + Z_UTIL_LISTIFY_785(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(785, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_787(F, sep, ...) \ + Z_UTIL_LISTIFY_786(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(786, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_788(F, sep, ...) \ + Z_UTIL_LISTIFY_787(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(787, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_789(F, sep, ...) \ + Z_UTIL_LISTIFY_788(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(788, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_790(F, sep, ...) \ + Z_UTIL_LISTIFY_789(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(789, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_791(F, sep, ...) \ + Z_UTIL_LISTIFY_790(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(790, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_792(F, sep, ...) \ + Z_UTIL_LISTIFY_791(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(791, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_793(F, sep, ...) \ + Z_UTIL_LISTIFY_792(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(792, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_794(F, sep, ...) \ + Z_UTIL_LISTIFY_793(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(793, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_795(F, sep, ...) \ + Z_UTIL_LISTIFY_794(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(794, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_796(F, sep, ...) \ + Z_UTIL_LISTIFY_795(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(795, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_797(F, sep, ...) \ + Z_UTIL_LISTIFY_796(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(796, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_798(F, sep, ...) \ + Z_UTIL_LISTIFY_797(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(797, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_799(F, sep, ...) \ + Z_UTIL_LISTIFY_798(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(798, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_800(F, sep, ...) \ + Z_UTIL_LISTIFY_799(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(799, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_801(F, sep, ...) \ + Z_UTIL_LISTIFY_800(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(800, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_802(F, sep, ...) \ + Z_UTIL_LISTIFY_801(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(801, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_803(F, sep, ...) \ + Z_UTIL_LISTIFY_802(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(802, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_804(F, sep, ...) \ + Z_UTIL_LISTIFY_803(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(803, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_805(F, sep, ...) \ + Z_UTIL_LISTIFY_804(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(804, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_806(F, sep, ...) \ + Z_UTIL_LISTIFY_805(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(805, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_807(F, sep, ...) \ + Z_UTIL_LISTIFY_806(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(806, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_808(F, sep, ...) \ + Z_UTIL_LISTIFY_807(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(807, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_809(F, sep, ...) \ + Z_UTIL_LISTIFY_808(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(808, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_810(F, sep, ...) \ + Z_UTIL_LISTIFY_809(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(809, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_811(F, sep, ...) \ + Z_UTIL_LISTIFY_810(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(810, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_812(F, sep, ...) \ + Z_UTIL_LISTIFY_811(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(811, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_813(F, sep, ...) \ + Z_UTIL_LISTIFY_812(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(812, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_814(F, sep, ...) \ + Z_UTIL_LISTIFY_813(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(813, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_815(F, sep, ...) \ + Z_UTIL_LISTIFY_814(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(814, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_816(F, sep, ...) \ + Z_UTIL_LISTIFY_815(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(815, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_817(F, sep, ...) \ + Z_UTIL_LISTIFY_816(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(816, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_818(F, sep, ...) \ + Z_UTIL_LISTIFY_817(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(817, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_819(F, sep, ...) \ + Z_UTIL_LISTIFY_818(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(818, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_820(F, sep, ...) \ + Z_UTIL_LISTIFY_819(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(819, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_821(F, sep, ...) \ + Z_UTIL_LISTIFY_820(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(820, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_822(F, sep, ...) \ + Z_UTIL_LISTIFY_821(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(821, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_823(F, sep, ...) \ + Z_UTIL_LISTIFY_822(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(822, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_824(F, sep, ...) \ + Z_UTIL_LISTIFY_823(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(823, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_825(F, sep, ...) \ + Z_UTIL_LISTIFY_824(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(824, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_826(F, sep, ...) \ + Z_UTIL_LISTIFY_825(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(825, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_827(F, sep, ...) \ + Z_UTIL_LISTIFY_826(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(826, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_828(F, sep, ...) \ + Z_UTIL_LISTIFY_827(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(827, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_829(F, sep, ...) \ + Z_UTIL_LISTIFY_828(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(828, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_830(F, sep, ...) \ + Z_UTIL_LISTIFY_829(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(829, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_831(F, sep, ...) \ + Z_UTIL_LISTIFY_830(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(830, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_832(F, sep, ...) \ + Z_UTIL_LISTIFY_831(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(831, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_833(F, sep, ...) \ + Z_UTIL_LISTIFY_832(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(832, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_834(F, sep, ...) \ + Z_UTIL_LISTIFY_833(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(833, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_835(F, sep, ...) \ + Z_UTIL_LISTIFY_834(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(834, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_836(F, sep, ...) \ + Z_UTIL_LISTIFY_835(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(835, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_837(F, sep, ...) \ + Z_UTIL_LISTIFY_836(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(836, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_838(F, sep, ...) \ + Z_UTIL_LISTIFY_837(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(837, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_839(F, sep, ...) \ + Z_UTIL_LISTIFY_838(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(838, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_840(F, sep, ...) \ + Z_UTIL_LISTIFY_839(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(839, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_841(F, sep, ...) \ + Z_UTIL_LISTIFY_840(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(840, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_842(F, sep, ...) \ + Z_UTIL_LISTIFY_841(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(841, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_843(F, sep, ...) \ + Z_UTIL_LISTIFY_842(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(842, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_844(F, sep, ...) \ + Z_UTIL_LISTIFY_843(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(843, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_845(F, sep, ...) \ + Z_UTIL_LISTIFY_844(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(844, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_846(F, sep, ...) \ + Z_UTIL_LISTIFY_845(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(845, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_847(F, sep, ...) \ + Z_UTIL_LISTIFY_846(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(846, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_848(F, sep, ...) \ + Z_UTIL_LISTIFY_847(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(847, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_849(F, sep, ...) \ + Z_UTIL_LISTIFY_848(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(848, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_850(F, sep, ...) \ + Z_UTIL_LISTIFY_849(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(849, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_851(F, sep, ...) \ + Z_UTIL_LISTIFY_850(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(850, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_852(F, sep, ...) \ + Z_UTIL_LISTIFY_851(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(851, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_853(F, sep, ...) \ + Z_UTIL_LISTIFY_852(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(852, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_854(F, sep, ...) \ + Z_UTIL_LISTIFY_853(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(853, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_855(F, sep, ...) \ + Z_UTIL_LISTIFY_854(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(854, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_856(F, sep, ...) \ + Z_UTIL_LISTIFY_855(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(855, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_857(F, sep, ...) \ + Z_UTIL_LISTIFY_856(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(856, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_858(F, sep, ...) \ + Z_UTIL_LISTIFY_857(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(857, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_859(F, sep, ...) \ + Z_UTIL_LISTIFY_858(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(858, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_860(F, sep, ...) \ + Z_UTIL_LISTIFY_859(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(859, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_861(F, sep, ...) \ + Z_UTIL_LISTIFY_860(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(860, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_862(F, sep, ...) \ + Z_UTIL_LISTIFY_861(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(861, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_863(F, sep, ...) \ + Z_UTIL_LISTIFY_862(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(862, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_864(F, sep, ...) \ + Z_UTIL_LISTIFY_863(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(863, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_865(F, sep, ...) \ + Z_UTIL_LISTIFY_864(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(864, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_866(F, sep, ...) \ + Z_UTIL_LISTIFY_865(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(865, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_867(F, sep, ...) \ + Z_UTIL_LISTIFY_866(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(866, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_868(F, sep, ...) \ + Z_UTIL_LISTIFY_867(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(867, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_869(F, sep, ...) \ + Z_UTIL_LISTIFY_868(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(868, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_870(F, sep, ...) \ + Z_UTIL_LISTIFY_869(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(869, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_871(F, sep, ...) \ + Z_UTIL_LISTIFY_870(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(870, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_872(F, sep, ...) \ + Z_UTIL_LISTIFY_871(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(871, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_873(F, sep, ...) \ + Z_UTIL_LISTIFY_872(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(872, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_874(F, sep, ...) \ + Z_UTIL_LISTIFY_873(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(873, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_875(F, sep, ...) \ + Z_UTIL_LISTIFY_874(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(874, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_876(F, sep, ...) \ + Z_UTIL_LISTIFY_875(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(875, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_877(F, sep, ...) \ + Z_UTIL_LISTIFY_876(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(876, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_878(F, sep, ...) \ + Z_UTIL_LISTIFY_877(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(877, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_879(F, sep, ...) \ + Z_UTIL_LISTIFY_878(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(878, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_880(F, sep, ...) \ + Z_UTIL_LISTIFY_879(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(879, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_881(F, sep, ...) \ + Z_UTIL_LISTIFY_880(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(880, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_882(F, sep, ...) \ + Z_UTIL_LISTIFY_881(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(881, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_883(F, sep, ...) \ + Z_UTIL_LISTIFY_882(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(882, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_884(F, sep, ...) \ + Z_UTIL_LISTIFY_883(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(883, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_885(F, sep, ...) \ + Z_UTIL_LISTIFY_884(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(884, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_886(F, sep, ...) \ + Z_UTIL_LISTIFY_885(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(885, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_887(F, sep, ...) \ + Z_UTIL_LISTIFY_886(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(886, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_888(F, sep, ...) \ + Z_UTIL_LISTIFY_887(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(887, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_889(F, sep, ...) \ + Z_UTIL_LISTIFY_888(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(888, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_890(F, sep, ...) \ + Z_UTIL_LISTIFY_889(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(889, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_891(F, sep, ...) \ + Z_UTIL_LISTIFY_890(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(890, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_892(F, sep, ...) \ + Z_UTIL_LISTIFY_891(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(891, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_893(F, sep, ...) \ + Z_UTIL_LISTIFY_892(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(892, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_894(F, sep, ...) \ + Z_UTIL_LISTIFY_893(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(893, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_895(F, sep, ...) \ + Z_UTIL_LISTIFY_894(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(894, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_896(F, sep, ...) \ + Z_UTIL_LISTIFY_895(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(895, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_897(F, sep, ...) \ + Z_UTIL_LISTIFY_896(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(896, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_898(F, sep, ...) \ + Z_UTIL_LISTIFY_897(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(897, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_899(F, sep, ...) \ + Z_UTIL_LISTIFY_898(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(898, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_900(F, sep, ...) \ + Z_UTIL_LISTIFY_899(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(899, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_901(F, sep, ...) \ + Z_UTIL_LISTIFY_900(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(900, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_902(F, sep, ...) \ + Z_UTIL_LISTIFY_901(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(901, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_903(F, sep, ...) \ + Z_UTIL_LISTIFY_902(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(902, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_904(F, sep, ...) \ + Z_UTIL_LISTIFY_903(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(903, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_905(F, sep, ...) \ + Z_UTIL_LISTIFY_904(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(904, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_906(F, sep, ...) \ + Z_UTIL_LISTIFY_905(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(905, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_907(F, sep, ...) \ + Z_UTIL_LISTIFY_906(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(906, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_908(F, sep, ...) \ + Z_UTIL_LISTIFY_907(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(907, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_909(F, sep, ...) \ + Z_UTIL_LISTIFY_908(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(908, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_910(F, sep, ...) \ + Z_UTIL_LISTIFY_909(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(909, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_911(F, sep, ...) \ + Z_UTIL_LISTIFY_910(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(910, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_912(F, sep, ...) \ + Z_UTIL_LISTIFY_911(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(911, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_913(F, sep, ...) \ + Z_UTIL_LISTIFY_912(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(912, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_914(F, sep, ...) \ + Z_UTIL_LISTIFY_913(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(913, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_915(F, sep, ...) \ + Z_UTIL_LISTIFY_914(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(914, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_916(F, sep, ...) \ + Z_UTIL_LISTIFY_915(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(915, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_917(F, sep, ...) \ + Z_UTIL_LISTIFY_916(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(916, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_918(F, sep, ...) \ + Z_UTIL_LISTIFY_917(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(917, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_919(F, sep, ...) \ + Z_UTIL_LISTIFY_918(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(918, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_920(F, sep, ...) \ + Z_UTIL_LISTIFY_919(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(919, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_921(F, sep, ...) \ + Z_UTIL_LISTIFY_920(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(920, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_922(F, sep, ...) \ + Z_UTIL_LISTIFY_921(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(921, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_923(F, sep, ...) \ + Z_UTIL_LISTIFY_922(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(922, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_924(F, sep, ...) \ + Z_UTIL_LISTIFY_923(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(923, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_925(F, sep, ...) \ + Z_UTIL_LISTIFY_924(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(924, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_926(F, sep, ...) \ + Z_UTIL_LISTIFY_925(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(925, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_927(F, sep, ...) \ + Z_UTIL_LISTIFY_926(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(926, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_928(F, sep, ...) \ + Z_UTIL_LISTIFY_927(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(927, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_929(F, sep, ...) \ + Z_UTIL_LISTIFY_928(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(928, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_930(F, sep, ...) \ + Z_UTIL_LISTIFY_929(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(929, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_931(F, sep, ...) \ + Z_UTIL_LISTIFY_930(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(930, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_932(F, sep, ...) \ + Z_UTIL_LISTIFY_931(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(931, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_933(F, sep, ...) \ + Z_UTIL_LISTIFY_932(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(932, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_934(F, sep, ...) \ + Z_UTIL_LISTIFY_933(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(933, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_935(F, sep, ...) \ + Z_UTIL_LISTIFY_934(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(934, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_936(F, sep, ...) \ + Z_UTIL_LISTIFY_935(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(935, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_937(F, sep, ...) \ + Z_UTIL_LISTIFY_936(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(936, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_938(F, sep, ...) \ + Z_UTIL_LISTIFY_937(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(937, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_939(F, sep, ...) \ + Z_UTIL_LISTIFY_938(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(938, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_940(F, sep, ...) \ + Z_UTIL_LISTIFY_939(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(939, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_941(F, sep, ...) \ + Z_UTIL_LISTIFY_940(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(940, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_942(F, sep, ...) \ + Z_UTIL_LISTIFY_941(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(941, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_943(F, sep, ...) \ + Z_UTIL_LISTIFY_942(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(942, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_944(F, sep, ...) \ + Z_UTIL_LISTIFY_943(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(943, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_945(F, sep, ...) \ + Z_UTIL_LISTIFY_944(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(944, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_946(F, sep, ...) \ + Z_UTIL_LISTIFY_945(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(945, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_947(F, sep, ...) \ + Z_UTIL_LISTIFY_946(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(946, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_948(F, sep, ...) \ + Z_UTIL_LISTIFY_947(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(947, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_949(F, sep, ...) \ + Z_UTIL_LISTIFY_948(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(948, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_950(F, sep, ...) \ + Z_UTIL_LISTIFY_949(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(949, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_951(F, sep, ...) \ + Z_UTIL_LISTIFY_950(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(950, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_952(F, sep, ...) \ + Z_UTIL_LISTIFY_951(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(951, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_953(F, sep, ...) \ + Z_UTIL_LISTIFY_952(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(952, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_954(F, sep, ...) \ + Z_UTIL_LISTIFY_953(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(953, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_955(F, sep, ...) \ + Z_UTIL_LISTIFY_954(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(954, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_956(F, sep, ...) \ + Z_UTIL_LISTIFY_955(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(955, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_957(F, sep, ...) \ + Z_UTIL_LISTIFY_956(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(956, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_958(F, sep, ...) \ + Z_UTIL_LISTIFY_957(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(957, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_959(F, sep, ...) \ + Z_UTIL_LISTIFY_958(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(958, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_960(F, sep, ...) \ + Z_UTIL_LISTIFY_959(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(959, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_961(F, sep, ...) \ + Z_UTIL_LISTIFY_960(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(960, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_962(F, sep, ...) \ + Z_UTIL_LISTIFY_961(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(961, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_963(F, sep, ...) \ + Z_UTIL_LISTIFY_962(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(962, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_964(F, sep, ...) \ + Z_UTIL_LISTIFY_963(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(963, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_965(F, sep, ...) \ + Z_UTIL_LISTIFY_964(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(964, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_966(F, sep, ...) \ + Z_UTIL_LISTIFY_965(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(965, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_967(F, sep, ...) \ + Z_UTIL_LISTIFY_966(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(966, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_968(F, sep, ...) \ + Z_UTIL_LISTIFY_967(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(967, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_969(F, sep, ...) \ + Z_UTIL_LISTIFY_968(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(968, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_970(F, sep, ...) \ + Z_UTIL_LISTIFY_969(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(969, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_971(F, sep, ...) \ + Z_UTIL_LISTIFY_970(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(970, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_972(F, sep, ...) \ + Z_UTIL_LISTIFY_971(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(971, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_973(F, sep, ...) \ + Z_UTIL_LISTIFY_972(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(972, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_974(F, sep, ...) \ + Z_UTIL_LISTIFY_973(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(973, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_975(F, sep, ...) \ + Z_UTIL_LISTIFY_974(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(974, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_976(F, sep, ...) \ + Z_UTIL_LISTIFY_975(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(975, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_977(F, sep, ...) \ + Z_UTIL_LISTIFY_976(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(976, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_978(F, sep, ...) \ + Z_UTIL_LISTIFY_977(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(977, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_979(F, sep, ...) \ + Z_UTIL_LISTIFY_978(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(978, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_980(F, sep, ...) \ + Z_UTIL_LISTIFY_979(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(979, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_981(F, sep, ...) \ + Z_UTIL_LISTIFY_980(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(980, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_982(F, sep, ...) \ + Z_UTIL_LISTIFY_981(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(981, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_983(F, sep, ...) \ + Z_UTIL_LISTIFY_982(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(982, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_984(F, sep, ...) \ + Z_UTIL_LISTIFY_983(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(983, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_985(F, sep, ...) \ + Z_UTIL_LISTIFY_984(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(984, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_986(F, sep, ...) \ + Z_UTIL_LISTIFY_985(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(985, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_987(F, sep, ...) \ + Z_UTIL_LISTIFY_986(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(986, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_988(F, sep, ...) \ + Z_UTIL_LISTIFY_987(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(987, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_989(F, sep, ...) \ + Z_UTIL_LISTIFY_988(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(988, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_990(F, sep, ...) \ + Z_UTIL_LISTIFY_989(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(989, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_991(F, sep, ...) \ + Z_UTIL_LISTIFY_990(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(990, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_992(F, sep, ...) \ + Z_UTIL_LISTIFY_991(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(991, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_993(F, sep, ...) \ + Z_UTIL_LISTIFY_992(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(992, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_994(F, sep, ...) \ + Z_UTIL_LISTIFY_993(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(993, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_995(F, sep, ...) \ + Z_UTIL_LISTIFY_994(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(994, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_996(F, sep, ...) \ + Z_UTIL_LISTIFY_995(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(995, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_997(F, sep, ...) \ + Z_UTIL_LISTIFY_996(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(996, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_998(F, sep, ...) \ + Z_UTIL_LISTIFY_997(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(997, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_999(F, sep, ...) \ + Z_UTIL_LISTIFY_998(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(998, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1000(F, sep, ...) \ + Z_UTIL_LISTIFY_999(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(999, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1001(F, sep, ...) \ + Z_UTIL_LISTIFY_1000(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1000, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1002(F, sep, ...) \ + Z_UTIL_LISTIFY_1001(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1001, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1003(F, sep, ...) \ + Z_UTIL_LISTIFY_1002(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1002, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1004(F, sep, ...) \ + Z_UTIL_LISTIFY_1003(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1003, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1005(F, sep, ...) \ + Z_UTIL_LISTIFY_1004(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1004, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1006(F, sep, ...) \ + Z_UTIL_LISTIFY_1005(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1005, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1007(F, sep, ...) \ + Z_UTIL_LISTIFY_1006(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1006, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1008(F, sep, ...) \ + Z_UTIL_LISTIFY_1007(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1007, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1009(F, sep, ...) \ + Z_UTIL_LISTIFY_1008(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1008, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1010(F, sep, ...) \ + Z_UTIL_LISTIFY_1009(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1009, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1011(F, sep, ...) \ + Z_UTIL_LISTIFY_1010(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1010, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1012(F, sep, ...) \ + Z_UTIL_LISTIFY_1011(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1011, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1013(F, sep, ...) \ + Z_UTIL_LISTIFY_1012(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1012, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1014(F, sep, ...) \ + Z_UTIL_LISTIFY_1013(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1013, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1015(F, sep, ...) \ + Z_UTIL_LISTIFY_1014(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1014, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1016(F, sep, ...) \ + Z_UTIL_LISTIFY_1015(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1015, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1017(F, sep, ...) \ + Z_UTIL_LISTIFY_1016(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1016, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1018(F, sep, ...) \ + Z_UTIL_LISTIFY_1017(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1017, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1019(F, sep, ...) \ + Z_UTIL_LISTIFY_1018(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1018, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1020(F, sep, ...) \ + Z_UTIL_LISTIFY_1019(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1019, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1021(F, sep, ...) \ + Z_UTIL_LISTIFY_1020(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1020, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1022(F, sep, ...) \ + Z_UTIL_LISTIFY_1021(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1021, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1023(F, sep, ...) \ + Z_UTIL_LISTIFY_1022(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1022, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1024(F, sep, ...) \ + Z_UTIL_LISTIFY_1023(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1023, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1025(F, sep, ...) \ + Z_UTIL_LISTIFY_1024(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1024, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1026(F, sep, ...) \ + Z_UTIL_LISTIFY_1025(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1025, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1027(F, sep, ...) \ + Z_UTIL_LISTIFY_1026(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1026, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1028(F, sep, ...) \ + Z_UTIL_LISTIFY_1027(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1027, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1029(F, sep, ...) \ + Z_UTIL_LISTIFY_1028(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1028, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1030(F, sep, ...) \ + Z_UTIL_LISTIFY_1029(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1029, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1031(F, sep, ...) \ + Z_UTIL_LISTIFY_1030(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1030, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1032(F, sep, ...) \ + Z_UTIL_LISTIFY_1031(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1031, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1033(F, sep, ...) \ + Z_UTIL_LISTIFY_1032(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1032, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1034(F, sep, ...) \ + Z_UTIL_LISTIFY_1033(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1033, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1035(F, sep, ...) \ + Z_UTIL_LISTIFY_1034(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1034, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1036(F, sep, ...) \ + Z_UTIL_LISTIFY_1035(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1035, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1037(F, sep, ...) \ + Z_UTIL_LISTIFY_1036(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1036, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1038(F, sep, ...) \ + Z_UTIL_LISTIFY_1037(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1037, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1039(F, sep, ...) \ + Z_UTIL_LISTIFY_1038(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1038, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1040(F, sep, ...) \ + Z_UTIL_LISTIFY_1039(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1039, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1041(F, sep, ...) \ + Z_UTIL_LISTIFY_1040(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1040, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1042(F, sep, ...) \ + Z_UTIL_LISTIFY_1041(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1041, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1043(F, sep, ...) \ + Z_UTIL_LISTIFY_1042(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1042, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1044(F, sep, ...) \ + Z_UTIL_LISTIFY_1043(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1043, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1045(F, sep, ...) \ + Z_UTIL_LISTIFY_1044(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1044, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1046(F, sep, ...) \ + Z_UTIL_LISTIFY_1045(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1045, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1047(F, sep, ...) \ + Z_UTIL_LISTIFY_1046(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1046, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1048(F, sep, ...) \ + Z_UTIL_LISTIFY_1047(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1047, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1049(F, sep, ...) \ + Z_UTIL_LISTIFY_1048(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1048, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1050(F, sep, ...) \ + Z_UTIL_LISTIFY_1049(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1049, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1051(F, sep, ...) \ + Z_UTIL_LISTIFY_1050(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1050, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1052(F, sep, ...) \ + Z_UTIL_LISTIFY_1051(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1051, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1053(F, sep, ...) \ + Z_UTIL_LISTIFY_1052(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1052, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1054(F, sep, ...) \ + Z_UTIL_LISTIFY_1053(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1053, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1055(F, sep, ...) \ + Z_UTIL_LISTIFY_1054(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1054, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1056(F, sep, ...) \ + Z_UTIL_LISTIFY_1055(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1055, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1057(F, sep, ...) \ + Z_UTIL_LISTIFY_1056(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1056, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1058(F, sep, ...) \ + Z_UTIL_LISTIFY_1057(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1057, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1059(F, sep, ...) \ + Z_UTIL_LISTIFY_1058(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1058, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1060(F, sep, ...) \ + Z_UTIL_LISTIFY_1059(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1059, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1061(F, sep, ...) \ + Z_UTIL_LISTIFY_1060(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1060, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1062(F, sep, ...) \ + Z_UTIL_LISTIFY_1061(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1061, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1063(F, sep, ...) \ + Z_UTIL_LISTIFY_1062(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1062, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1064(F, sep, ...) \ + Z_UTIL_LISTIFY_1063(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1063, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1065(F, sep, ...) \ + Z_UTIL_LISTIFY_1064(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1064, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1066(F, sep, ...) \ + Z_UTIL_LISTIFY_1065(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1065, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1067(F, sep, ...) \ + Z_UTIL_LISTIFY_1066(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1066, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1068(F, sep, ...) \ + Z_UTIL_LISTIFY_1067(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1067, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1069(F, sep, ...) \ + Z_UTIL_LISTIFY_1068(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1068, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1070(F, sep, ...) \ + Z_UTIL_LISTIFY_1069(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1069, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1071(F, sep, ...) \ + Z_UTIL_LISTIFY_1070(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1070, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1072(F, sep, ...) \ + Z_UTIL_LISTIFY_1071(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1071, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1073(F, sep, ...) \ + Z_UTIL_LISTIFY_1072(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1072, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1074(F, sep, ...) \ + Z_UTIL_LISTIFY_1073(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1073, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1075(F, sep, ...) \ + Z_UTIL_LISTIFY_1074(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1074, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1076(F, sep, ...) \ + Z_UTIL_LISTIFY_1075(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1075, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1077(F, sep, ...) \ + Z_UTIL_LISTIFY_1076(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1076, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1078(F, sep, ...) \ + Z_UTIL_LISTIFY_1077(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1077, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1079(F, sep, ...) \ + Z_UTIL_LISTIFY_1078(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1078, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1080(F, sep, ...) \ + Z_UTIL_LISTIFY_1079(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1079, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1081(F, sep, ...) \ + Z_UTIL_LISTIFY_1080(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1080, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1082(F, sep, ...) \ + Z_UTIL_LISTIFY_1081(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1081, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1083(F, sep, ...) \ + Z_UTIL_LISTIFY_1082(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1082, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1084(F, sep, ...) \ + Z_UTIL_LISTIFY_1083(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1083, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1085(F, sep, ...) \ + Z_UTIL_LISTIFY_1084(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1084, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1086(F, sep, ...) \ + Z_UTIL_LISTIFY_1085(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1085, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1087(F, sep, ...) \ + Z_UTIL_LISTIFY_1086(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1086, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1088(F, sep, ...) \ + Z_UTIL_LISTIFY_1087(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1087, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1089(F, sep, ...) \ + Z_UTIL_LISTIFY_1088(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1088, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1090(F, sep, ...) \ + Z_UTIL_LISTIFY_1089(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1089, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1091(F, sep, ...) \ + Z_UTIL_LISTIFY_1090(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1090, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1092(F, sep, ...) \ + Z_UTIL_LISTIFY_1091(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1091, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1093(F, sep, ...) \ + Z_UTIL_LISTIFY_1092(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1092, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1094(F, sep, ...) \ + Z_UTIL_LISTIFY_1093(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1093, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1095(F, sep, ...) \ + Z_UTIL_LISTIFY_1094(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1094, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1096(F, sep, ...) \ + Z_UTIL_LISTIFY_1095(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1095, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1097(F, sep, ...) \ + Z_UTIL_LISTIFY_1096(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1096, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1098(F, sep, ...) \ + Z_UTIL_LISTIFY_1097(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1097, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1099(F, sep, ...) \ + Z_UTIL_LISTIFY_1098(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1098, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1100(F, sep, ...) \ + Z_UTIL_LISTIFY_1099(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1099, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1101(F, sep, ...) \ + Z_UTIL_LISTIFY_1100(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1100, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1102(F, sep, ...) \ + Z_UTIL_LISTIFY_1101(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1101, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1103(F, sep, ...) \ + Z_UTIL_LISTIFY_1102(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1102, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1104(F, sep, ...) \ + Z_UTIL_LISTIFY_1103(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1103, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1105(F, sep, ...) \ + Z_UTIL_LISTIFY_1104(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1104, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1106(F, sep, ...) \ + Z_UTIL_LISTIFY_1105(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1105, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1107(F, sep, ...) \ + Z_UTIL_LISTIFY_1106(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1106, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1108(F, sep, ...) \ + Z_UTIL_LISTIFY_1107(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1107, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1109(F, sep, ...) \ + Z_UTIL_LISTIFY_1108(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1108, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1110(F, sep, ...) \ + Z_UTIL_LISTIFY_1109(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1109, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1111(F, sep, ...) \ + Z_UTIL_LISTIFY_1110(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1110, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1112(F, sep, ...) \ + Z_UTIL_LISTIFY_1111(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1111, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1113(F, sep, ...) \ + Z_UTIL_LISTIFY_1112(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1112, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1114(F, sep, ...) \ + Z_UTIL_LISTIFY_1113(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1113, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1115(F, sep, ...) \ + Z_UTIL_LISTIFY_1114(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1114, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1116(F, sep, ...) \ + Z_UTIL_LISTIFY_1115(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1115, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1117(F, sep, ...) \ + Z_UTIL_LISTIFY_1116(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1116, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1118(F, sep, ...) \ + Z_UTIL_LISTIFY_1117(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1117, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1119(F, sep, ...) \ + Z_UTIL_LISTIFY_1118(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1118, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1120(F, sep, ...) \ + Z_UTIL_LISTIFY_1119(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1119, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1121(F, sep, ...) \ + Z_UTIL_LISTIFY_1120(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1120, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1122(F, sep, ...) \ + Z_UTIL_LISTIFY_1121(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1121, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1123(F, sep, ...) \ + Z_UTIL_LISTIFY_1122(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1122, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1124(F, sep, ...) \ + Z_UTIL_LISTIFY_1123(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1123, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1125(F, sep, ...) \ + Z_UTIL_LISTIFY_1124(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1124, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1126(F, sep, ...) \ + Z_UTIL_LISTIFY_1125(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1125, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1127(F, sep, ...) \ + Z_UTIL_LISTIFY_1126(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1126, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1128(F, sep, ...) \ + Z_UTIL_LISTIFY_1127(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1127, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1129(F, sep, ...) \ + Z_UTIL_LISTIFY_1128(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1128, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1130(F, sep, ...) \ + Z_UTIL_LISTIFY_1129(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1129, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1131(F, sep, ...) \ + Z_UTIL_LISTIFY_1130(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1130, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1132(F, sep, ...) \ + Z_UTIL_LISTIFY_1131(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1131, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1133(F, sep, ...) \ + Z_UTIL_LISTIFY_1132(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1132, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1134(F, sep, ...) \ + Z_UTIL_LISTIFY_1133(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1133, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1135(F, sep, ...) \ + Z_UTIL_LISTIFY_1134(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1134, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1136(F, sep, ...) \ + Z_UTIL_LISTIFY_1135(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1135, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1137(F, sep, ...) \ + Z_UTIL_LISTIFY_1136(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1136, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1138(F, sep, ...) \ + Z_UTIL_LISTIFY_1137(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1137, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1139(F, sep, ...) \ + Z_UTIL_LISTIFY_1138(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1138, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1140(F, sep, ...) \ + Z_UTIL_LISTIFY_1139(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1139, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1141(F, sep, ...) \ + Z_UTIL_LISTIFY_1140(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1140, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1142(F, sep, ...) \ + Z_UTIL_LISTIFY_1141(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1141, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1143(F, sep, ...) \ + Z_UTIL_LISTIFY_1142(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1142, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1144(F, sep, ...) \ + Z_UTIL_LISTIFY_1143(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1143, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1145(F, sep, ...) \ + Z_UTIL_LISTIFY_1144(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1144, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1146(F, sep, ...) \ + Z_UTIL_LISTIFY_1145(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1145, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1147(F, sep, ...) \ + Z_UTIL_LISTIFY_1146(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1146, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1148(F, sep, ...) \ + Z_UTIL_LISTIFY_1147(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1147, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1149(F, sep, ...) \ + Z_UTIL_LISTIFY_1148(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1148, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1150(F, sep, ...) \ + Z_UTIL_LISTIFY_1149(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1149, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1151(F, sep, ...) \ + Z_UTIL_LISTIFY_1150(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1150, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1152(F, sep, ...) \ + Z_UTIL_LISTIFY_1151(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1151, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1153(F, sep, ...) \ + Z_UTIL_LISTIFY_1152(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1152, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1154(F, sep, ...) \ + Z_UTIL_LISTIFY_1153(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1153, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1155(F, sep, ...) \ + Z_UTIL_LISTIFY_1154(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1154, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1156(F, sep, ...) \ + Z_UTIL_LISTIFY_1155(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1155, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1157(F, sep, ...) \ + Z_UTIL_LISTIFY_1156(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1156, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1158(F, sep, ...) \ + Z_UTIL_LISTIFY_1157(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1157, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1159(F, sep, ...) \ + Z_UTIL_LISTIFY_1158(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1158, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1160(F, sep, ...) \ + Z_UTIL_LISTIFY_1159(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1159, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1161(F, sep, ...) \ + Z_UTIL_LISTIFY_1160(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1160, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1162(F, sep, ...) \ + Z_UTIL_LISTIFY_1161(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1161, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1163(F, sep, ...) \ + Z_UTIL_LISTIFY_1162(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1162, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1164(F, sep, ...) \ + Z_UTIL_LISTIFY_1163(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1163, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1165(F, sep, ...) \ + Z_UTIL_LISTIFY_1164(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1164, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1166(F, sep, ...) \ + Z_UTIL_LISTIFY_1165(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1165, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1167(F, sep, ...) \ + Z_UTIL_LISTIFY_1166(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1166, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1168(F, sep, ...) \ + Z_UTIL_LISTIFY_1167(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1167, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1169(F, sep, ...) \ + Z_UTIL_LISTIFY_1168(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1168, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1170(F, sep, ...) \ + Z_UTIL_LISTIFY_1169(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1169, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1171(F, sep, ...) \ + Z_UTIL_LISTIFY_1170(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1170, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1172(F, sep, ...) \ + Z_UTIL_LISTIFY_1171(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1171, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1173(F, sep, ...) \ + Z_UTIL_LISTIFY_1172(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1172, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1174(F, sep, ...) \ + Z_UTIL_LISTIFY_1173(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1173, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1175(F, sep, ...) \ + Z_UTIL_LISTIFY_1174(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1174, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1176(F, sep, ...) \ + Z_UTIL_LISTIFY_1175(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1175, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1177(F, sep, ...) \ + Z_UTIL_LISTIFY_1176(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1176, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1178(F, sep, ...) \ + Z_UTIL_LISTIFY_1177(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1177, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1179(F, sep, ...) \ + Z_UTIL_LISTIFY_1178(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1178, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1180(F, sep, ...) \ + Z_UTIL_LISTIFY_1179(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1179, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1181(F, sep, ...) \ + Z_UTIL_LISTIFY_1180(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1180, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1182(F, sep, ...) \ + Z_UTIL_LISTIFY_1181(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1181, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1183(F, sep, ...) \ + Z_UTIL_LISTIFY_1182(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1182, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1184(F, sep, ...) \ + Z_UTIL_LISTIFY_1183(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1183, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1185(F, sep, ...) \ + Z_UTIL_LISTIFY_1184(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1184, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1186(F, sep, ...) \ + Z_UTIL_LISTIFY_1185(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1185, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1187(F, sep, ...) \ + Z_UTIL_LISTIFY_1186(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1186, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1188(F, sep, ...) \ + Z_UTIL_LISTIFY_1187(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1187, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1189(F, sep, ...) \ + Z_UTIL_LISTIFY_1188(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1188, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1190(F, sep, ...) \ + Z_UTIL_LISTIFY_1189(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1189, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1191(F, sep, ...) \ + Z_UTIL_LISTIFY_1190(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1190, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1192(F, sep, ...) \ + Z_UTIL_LISTIFY_1191(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1191, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1193(F, sep, ...) \ + Z_UTIL_LISTIFY_1192(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1192, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1194(F, sep, ...) \ + Z_UTIL_LISTIFY_1193(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1193, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1195(F, sep, ...) \ + Z_UTIL_LISTIFY_1194(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1194, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1196(F, sep, ...) \ + Z_UTIL_LISTIFY_1195(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1195, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1197(F, sep, ...) \ + Z_UTIL_LISTIFY_1196(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1196, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1198(F, sep, ...) \ + Z_UTIL_LISTIFY_1197(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1197, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1199(F, sep, ...) \ + Z_UTIL_LISTIFY_1198(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1198, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1200(F, sep, ...) \ + Z_UTIL_LISTIFY_1199(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1199, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1201(F, sep, ...) \ + Z_UTIL_LISTIFY_1200(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1200, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1202(F, sep, ...) \ + Z_UTIL_LISTIFY_1201(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1201, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1203(F, sep, ...) \ + Z_UTIL_LISTIFY_1202(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1202, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1204(F, sep, ...) \ + Z_UTIL_LISTIFY_1203(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1203, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1205(F, sep, ...) \ + Z_UTIL_LISTIFY_1204(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1204, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1206(F, sep, ...) \ + Z_UTIL_LISTIFY_1205(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1205, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1207(F, sep, ...) \ + Z_UTIL_LISTIFY_1206(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1206, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1208(F, sep, ...) \ + Z_UTIL_LISTIFY_1207(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1207, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1209(F, sep, ...) \ + Z_UTIL_LISTIFY_1208(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1208, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1210(F, sep, ...) \ + Z_UTIL_LISTIFY_1209(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1209, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1211(F, sep, ...) \ + Z_UTIL_LISTIFY_1210(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1210, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1212(F, sep, ...) \ + Z_UTIL_LISTIFY_1211(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1211, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1213(F, sep, ...) \ + Z_UTIL_LISTIFY_1212(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1212, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1214(F, sep, ...) \ + Z_UTIL_LISTIFY_1213(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1213, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1215(F, sep, ...) \ + Z_UTIL_LISTIFY_1214(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1214, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1216(F, sep, ...) \ + Z_UTIL_LISTIFY_1215(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1215, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1217(F, sep, ...) \ + Z_UTIL_LISTIFY_1216(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1216, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1218(F, sep, ...) \ + Z_UTIL_LISTIFY_1217(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1217, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1219(F, sep, ...) \ + Z_UTIL_LISTIFY_1218(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1218, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1220(F, sep, ...) \ + Z_UTIL_LISTIFY_1219(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1219, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1221(F, sep, ...) \ + Z_UTIL_LISTIFY_1220(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1220, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1222(F, sep, ...) \ + Z_UTIL_LISTIFY_1221(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1221, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1223(F, sep, ...) \ + Z_UTIL_LISTIFY_1222(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1222, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1224(F, sep, ...) \ + Z_UTIL_LISTIFY_1223(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1223, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1225(F, sep, ...) \ + Z_UTIL_LISTIFY_1224(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1224, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1226(F, sep, ...) \ + Z_UTIL_LISTIFY_1225(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1225, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1227(F, sep, ...) \ + Z_UTIL_LISTIFY_1226(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1226, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1228(F, sep, ...) \ + Z_UTIL_LISTIFY_1227(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1227, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1229(F, sep, ...) \ + Z_UTIL_LISTIFY_1228(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1228, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1230(F, sep, ...) \ + Z_UTIL_LISTIFY_1229(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1229, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1231(F, sep, ...) \ + Z_UTIL_LISTIFY_1230(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1230, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1232(F, sep, ...) \ + Z_UTIL_LISTIFY_1231(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1231, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1233(F, sep, ...) \ + Z_UTIL_LISTIFY_1232(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1232, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1234(F, sep, ...) \ + Z_UTIL_LISTIFY_1233(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1233, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1235(F, sep, ...) \ + Z_UTIL_LISTIFY_1234(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1234, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1236(F, sep, ...) \ + Z_UTIL_LISTIFY_1235(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1235, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1237(F, sep, ...) \ + Z_UTIL_LISTIFY_1236(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1236, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1238(F, sep, ...) \ + Z_UTIL_LISTIFY_1237(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1237, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1239(F, sep, ...) \ + Z_UTIL_LISTIFY_1238(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1238, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1240(F, sep, ...) \ + Z_UTIL_LISTIFY_1239(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1239, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1241(F, sep, ...) \ + Z_UTIL_LISTIFY_1240(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1240, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1242(F, sep, ...) \ + Z_UTIL_LISTIFY_1241(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1241, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1243(F, sep, ...) \ + Z_UTIL_LISTIFY_1242(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1242, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1244(F, sep, ...) \ + Z_UTIL_LISTIFY_1243(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1243, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1245(F, sep, ...) \ + Z_UTIL_LISTIFY_1244(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1244, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1246(F, sep, ...) \ + Z_UTIL_LISTIFY_1245(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1245, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1247(F, sep, ...) \ + Z_UTIL_LISTIFY_1246(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1246, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1248(F, sep, ...) \ + Z_UTIL_LISTIFY_1247(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1247, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1249(F, sep, ...) \ + Z_UTIL_LISTIFY_1248(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1248, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1250(F, sep, ...) \ + Z_UTIL_LISTIFY_1249(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1249, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1251(F, sep, ...) \ + Z_UTIL_LISTIFY_1250(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1250, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1252(F, sep, ...) \ + Z_UTIL_LISTIFY_1251(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1251, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1253(F, sep, ...) \ + Z_UTIL_LISTIFY_1252(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1252, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1254(F, sep, ...) \ + Z_UTIL_LISTIFY_1253(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1253, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1255(F, sep, ...) \ + Z_UTIL_LISTIFY_1254(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1254, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1256(F, sep, ...) \ + Z_UTIL_LISTIFY_1255(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1255, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1257(F, sep, ...) \ + Z_UTIL_LISTIFY_1256(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1256, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1258(F, sep, ...) \ + Z_UTIL_LISTIFY_1257(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1257, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1259(F, sep, ...) \ + Z_UTIL_LISTIFY_1258(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1258, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1260(F, sep, ...) \ + Z_UTIL_LISTIFY_1259(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1259, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1261(F, sep, ...) \ + Z_UTIL_LISTIFY_1260(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1260, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1262(F, sep, ...) \ + Z_UTIL_LISTIFY_1261(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1261, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1263(F, sep, ...) \ + Z_UTIL_LISTIFY_1262(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1262, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1264(F, sep, ...) \ + Z_UTIL_LISTIFY_1263(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1263, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1265(F, sep, ...) \ + Z_UTIL_LISTIFY_1264(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1264, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1266(F, sep, ...) \ + Z_UTIL_LISTIFY_1265(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1265, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1267(F, sep, ...) \ + Z_UTIL_LISTIFY_1266(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1266, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1268(F, sep, ...) \ + Z_UTIL_LISTIFY_1267(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1267, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1269(F, sep, ...) \ + Z_UTIL_LISTIFY_1268(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1268, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1270(F, sep, ...) \ + Z_UTIL_LISTIFY_1269(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1269, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1271(F, sep, ...) \ + Z_UTIL_LISTIFY_1270(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1270, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1272(F, sep, ...) \ + Z_UTIL_LISTIFY_1271(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1271, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1273(F, sep, ...) \ + Z_UTIL_LISTIFY_1272(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1272, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1274(F, sep, ...) \ + Z_UTIL_LISTIFY_1273(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1273, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1275(F, sep, ...) \ + Z_UTIL_LISTIFY_1274(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1274, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1276(F, sep, ...) \ + Z_UTIL_LISTIFY_1275(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1275, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1277(F, sep, ...) \ + Z_UTIL_LISTIFY_1276(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1276, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1278(F, sep, ...) \ + Z_UTIL_LISTIFY_1277(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1277, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1279(F, sep, ...) \ + Z_UTIL_LISTIFY_1278(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1278, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1280(F, sep, ...) \ + Z_UTIL_LISTIFY_1279(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1279, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1281(F, sep, ...) \ + Z_UTIL_LISTIFY_1280(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1280, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1282(F, sep, ...) \ + Z_UTIL_LISTIFY_1281(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1281, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1283(F, sep, ...) \ + Z_UTIL_LISTIFY_1282(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1282, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1284(F, sep, ...) \ + Z_UTIL_LISTIFY_1283(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1283, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1285(F, sep, ...) \ + Z_UTIL_LISTIFY_1284(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1284, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1286(F, sep, ...) \ + Z_UTIL_LISTIFY_1285(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1285, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1287(F, sep, ...) \ + Z_UTIL_LISTIFY_1286(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1286, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1288(F, sep, ...) \ + Z_UTIL_LISTIFY_1287(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1287, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1289(F, sep, ...) \ + Z_UTIL_LISTIFY_1288(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1288, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1290(F, sep, ...) \ + Z_UTIL_LISTIFY_1289(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1289, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1291(F, sep, ...) \ + Z_UTIL_LISTIFY_1290(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1290, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1292(F, sep, ...) \ + Z_UTIL_LISTIFY_1291(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1291, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1293(F, sep, ...) \ + Z_UTIL_LISTIFY_1292(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1292, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1294(F, sep, ...) \ + Z_UTIL_LISTIFY_1293(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1293, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1295(F, sep, ...) \ + Z_UTIL_LISTIFY_1294(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1294, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1296(F, sep, ...) \ + Z_UTIL_LISTIFY_1295(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1295, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1297(F, sep, ...) \ + Z_UTIL_LISTIFY_1296(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1296, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1298(F, sep, ...) \ + Z_UTIL_LISTIFY_1297(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1297, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1299(F, sep, ...) \ + Z_UTIL_LISTIFY_1298(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1298, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1300(F, sep, ...) \ + Z_UTIL_LISTIFY_1299(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1299, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1301(F, sep, ...) \ + Z_UTIL_LISTIFY_1300(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1300, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1302(F, sep, ...) \ + Z_UTIL_LISTIFY_1301(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1301, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1303(F, sep, ...) \ + Z_UTIL_LISTIFY_1302(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1302, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1304(F, sep, ...) \ + Z_UTIL_LISTIFY_1303(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1303, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1305(F, sep, ...) \ + Z_UTIL_LISTIFY_1304(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1304, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1306(F, sep, ...) \ + Z_UTIL_LISTIFY_1305(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1305, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1307(F, sep, ...) \ + Z_UTIL_LISTIFY_1306(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1306, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1308(F, sep, ...) \ + Z_UTIL_LISTIFY_1307(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1307, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1309(F, sep, ...) \ + Z_UTIL_LISTIFY_1308(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1308, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1310(F, sep, ...) \ + Z_UTIL_LISTIFY_1309(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1309, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1311(F, sep, ...) \ + Z_UTIL_LISTIFY_1310(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1310, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1312(F, sep, ...) \ + Z_UTIL_LISTIFY_1311(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1311, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1313(F, sep, ...) \ + Z_UTIL_LISTIFY_1312(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1312, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1314(F, sep, ...) \ + Z_UTIL_LISTIFY_1313(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1313, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1315(F, sep, ...) \ + Z_UTIL_LISTIFY_1314(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1314, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1316(F, sep, ...) \ + Z_UTIL_LISTIFY_1315(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1315, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1317(F, sep, ...) \ + Z_UTIL_LISTIFY_1316(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1316, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1318(F, sep, ...) \ + Z_UTIL_LISTIFY_1317(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1317, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1319(F, sep, ...) \ + Z_UTIL_LISTIFY_1318(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1318, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1320(F, sep, ...) \ + Z_UTIL_LISTIFY_1319(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1319, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1321(F, sep, ...) \ + Z_UTIL_LISTIFY_1320(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1320, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1322(F, sep, ...) \ + Z_UTIL_LISTIFY_1321(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1321, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1323(F, sep, ...) \ + Z_UTIL_LISTIFY_1322(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1322, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1324(F, sep, ...) \ + Z_UTIL_LISTIFY_1323(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1323, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1325(F, sep, ...) \ + Z_UTIL_LISTIFY_1324(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1324, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1326(F, sep, ...) \ + Z_UTIL_LISTIFY_1325(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1325, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1327(F, sep, ...) \ + Z_UTIL_LISTIFY_1326(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1326, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1328(F, sep, ...) \ + Z_UTIL_LISTIFY_1327(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1327, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1329(F, sep, ...) \ + Z_UTIL_LISTIFY_1328(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1328, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1330(F, sep, ...) \ + Z_UTIL_LISTIFY_1329(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1329, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1331(F, sep, ...) \ + Z_UTIL_LISTIFY_1330(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1330, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1332(F, sep, ...) \ + Z_UTIL_LISTIFY_1331(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1331, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1333(F, sep, ...) \ + Z_UTIL_LISTIFY_1332(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1332, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1334(F, sep, ...) \ + Z_UTIL_LISTIFY_1333(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1333, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1335(F, sep, ...) \ + Z_UTIL_LISTIFY_1334(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1334, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1336(F, sep, ...) \ + Z_UTIL_LISTIFY_1335(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1335, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1337(F, sep, ...) \ + Z_UTIL_LISTIFY_1336(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1336, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1338(F, sep, ...) \ + Z_UTIL_LISTIFY_1337(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1337, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1339(F, sep, ...) \ + Z_UTIL_LISTIFY_1338(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1338, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1340(F, sep, ...) \ + Z_UTIL_LISTIFY_1339(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1339, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1341(F, sep, ...) \ + Z_UTIL_LISTIFY_1340(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1340, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1342(F, sep, ...) \ + Z_UTIL_LISTIFY_1341(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1341, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1343(F, sep, ...) \ + Z_UTIL_LISTIFY_1342(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1342, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1344(F, sep, ...) \ + Z_UTIL_LISTIFY_1343(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1343, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1345(F, sep, ...) \ + Z_UTIL_LISTIFY_1344(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1344, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1346(F, sep, ...) \ + Z_UTIL_LISTIFY_1345(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1345, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1347(F, sep, ...) \ + Z_UTIL_LISTIFY_1346(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1346, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1348(F, sep, ...) \ + Z_UTIL_LISTIFY_1347(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1347, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1349(F, sep, ...) \ + Z_UTIL_LISTIFY_1348(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1348, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1350(F, sep, ...) \ + Z_UTIL_LISTIFY_1349(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1349, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1351(F, sep, ...) \ + Z_UTIL_LISTIFY_1350(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1350, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1352(F, sep, ...) \ + Z_UTIL_LISTIFY_1351(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1351, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1353(F, sep, ...) \ + Z_UTIL_LISTIFY_1352(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1352, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1354(F, sep, ...) \ + Z_UTIL_LISTIFY_1353(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1353, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1355(F, sep, ...) \ + Z_UTIL_LISTIFY_1354(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1354, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1356(F, sep, ...) \ + Z_UTIL_LISTIFY_1355(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1355, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1357(F, sep, ...) \ + Z_UTIL_LISTIFY_1356(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1356, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1358(F, sep, ...) \ + Z_UTIL_LISTIFY_1357(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1357, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1359(F, sep, ...) \ + Z_UTIL_LISTIFY_1358(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1358, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1360(F, sep, ...) \ + Z_UTIL_LISTIFY_1359(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1359, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1361(F, sep, ...) \ + Z_UTIL_LISTIFY_1360(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1360, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1362(F, sep, ...) \ + Z_UTIL_LISTIFY_1361(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1361, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1363(F, sep, ...) \ + Z_UTIL_LISTIFY_1362(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1362, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1364(F, sep, ...) \ + Z_UTIL_LISTIFY_1363(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1363, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1365(F, sep, ...) \ + Z_UTIL_LISTIFY_1364(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1364, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1366(F, sep, ...) \ + Z_UTIL_LISTIFY_1365(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1365, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1367(F, sep, ...) \ + Z_UTIL_LISTIFY_1366(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1366, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1368(F, sep, ...) \ + Z_UTIL_LISTIFY_1367(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1367, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1369(F, sep, ...) \ + Z_UTIL_LISTIFY_1368(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1368, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1370(F, sep, ...) \ + Z_UTIL_LISTIFY_1369(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1369, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1371(F, sep, ...) \ + Z_UTIL_LISTIFY_1370(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1370, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1372(F, sep, ...) \ + Z_UTIL_LISTIFY_1371(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1371, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1373(F, sep, ...) \ + Z_UTIL_LISTIFY_1372(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1372, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1374(F, sep, ...) \ + Z_UTIL_LISTIFY_1373(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1373, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1375(F, sep, ...) \ + Z_UTIL_LISTIFY_1374(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1374, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1376(F, sep, ...) \ + Z_UTIL_LISTIFY_1375(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1375, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1377(F, sep, ...) \ + Z_UTIL_LISTIFY_1376(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1376, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1378(F, sep, ...) \ + Z_UTIL_LISTIFY_1377(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1377, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1379(F, sep, ...) \ + Z_UTIL_LISTIFY_1378(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1378, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1380(F, sep, ...) \ + Z_UTIL_LISTIFY_1379(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1379, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1381(F, sep, ...) \ + Z_UTIL_LISTIFY_1380(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1380, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1382(F, sep, ...) \ + Z_UTIL_LISTIFY_1381(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1381, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1383(F, sep, ...) \ + Z_UTIL_LISTIFY_1382(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1382, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1384(F, sep, ...) \ + Z_UTIL_LISTIFY_1383(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1383, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1385(F, sep, ...) \ + Z_UTIL_LISTIFY_1384(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1384, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1386(F, sep, ...) \ + Z_UTIL_LISTIFY_1385(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1385, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1387(F, sep, ...) \ + Z_UTIL_LISTIFY_1386(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1386, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1388(F, sep, ...) \ + Z_UTIL_LISTIFY_1387(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1387, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1389(F, sep, ...) \ + Z_UTIL_LISTIFY_1388(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1388, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1390(F, sep, ...) \ + Z_UTIL_LISTIFY_1389(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1389, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1391(F, sep, ...) \ + Z_UTIL_LISTIFY_1390(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1390, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1392(F, sep, ...) \ + Z_UTIL_LISTIFY_1391(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1391, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1393(F, sep, ...) \ + Z_UTIL_LISTIFY_1392(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1392, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1394(F, sep, ...) \ + Z_UTIL_LISTIFY_1393(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1393, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1395(F, sep, ...) \ + Z_UTIL_LISTIFY_1394(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1394, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1396(F, sep, ...) \ + Z_UTIL_LISTIFY_1395(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1395, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1397(F, sep, ...) \ + Z_UTIL_LISTIFY_1396(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1396, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1398(F, sep, ...) \ + Z_UTIL_LISTIFY_1397(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1397, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1399(F, sep, ...) \ + Z_UTIL_LISTIFY_1398(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1398, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1400(F, sep, ...) \ + Z_UTIL_LISTIFY_1399(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1399, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1401(F, sep, ...) \ + Z_UTIL_LISTIFY_1400(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1400, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1402(F, sep, ...) \ + Z_UTIL_LISTIFY_1401(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1401, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1403(F, sep, ...) \ + Z_UTIL_LISTIFY_1402(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1402, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1404(F, sep, ...) \ + Z_UTIL_LISTIFY_1403(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1403, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1405(F, sep, ...) \ + Z_UTIL_LISTIFY_1404(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1404, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1406(F, sep, ...) \ + Z_UTIL_LISTIFY_1405(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1405, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1407(F, sep, ...) \ + Z_UTIL_LISTIFY_1406(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1406, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1408(F, sep, ...) \ + Z_UTIL_LISTIFY_1407(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1407, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1409(F, sep, ...) \ + Z_UTIL_LISTIFY_1408(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1408, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1410(F, sep, ...) \ + Z_UTIL_LISTIFY_1409(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1409, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1411(F, sep, ...) \ + Z_UTIL_LISTIFY_1410(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1410, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1412(F, sep, ...) \ + Z_UTIL_LISTIFY_1411(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1411, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1413(F, sep, ...) \ + Z_UTIL_LISTIFY_1412(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1412, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1414(F, sep, ...) \ + Z_UTIL_LISTIFY_1413(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1413, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1415(F, sep, ...) \ + Z_UTIL_LISTIFY_1414(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1414, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1416(F, sep, ...) \ + Z_UTIL_LISTIFY_1415(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1415, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1417(F, sep, ...) \ + Z_UTIL_LISTIFY_1416(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1416, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1418(F, sep, ...) \ + Z_UTIL_LISTIFY_1417(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1417, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1419(F, sep, ...) \ + Z_UTIL_LISTIFY_1418(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1418, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1420(F, sep, ...) \ + Z_UTIL_LISTIFY_1419(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1419, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1421(F, sep, ...) \ + Z_UTIL_LISTIFY_1420(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1420, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1422(F, sep, ...) \ + Z_UTIL_LISTIFY_1421(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1421, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1423(F, sep, ...) \ + Z_UTIL_LISTIFY_1422(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1422, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1424(F, sep, ...) \ + Z_UTIL_LISTIFY_1423(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1423, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1425(F, sep, ...) \ + Z_UTIL_LISTIFY_1424(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1424, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1426(F, sep, ...) \ + Z_UTIL_LISTIFY_1425(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1425, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1427(F, sep, ...) \ + Z_UTIL_LISTIFY_1426(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1426, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1428(F, sep, ...) \ + Z_UTIL_LISTIFY_1427(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1427, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1429(F, sep, ...) \ + Z_UTIL_LISTIFY_1428(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1428, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1430(F, sep, ...) \ + Z_UTIL_LISTIFY_1429(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1429, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1431(F, sep, ...) \ + Z_UTIL_LISTIFY_1430(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1430, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1432(F, sep, ...) \ + Z_UTIL_LISTIFY_1431(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1431, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1433(F, sep, ...) \ + Z_UTIL_LISTIFY_1432(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1432, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1434(F, sep, ...) \ + Z_UTIL_LISTIFY_1433(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1433, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1435(F, sep, ...) \ + Z_UTIL_LISTIFY_1434(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1434, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1436(F, sep, ...) \ + Z_UTIL_LISTIFY_1435(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1435, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1437(F, sep, ...) \ + Z_UTIL_LISTIFY_1436(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1436, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1438(F, sep, ...) \ + Z_UTIL_LISTIFY_1437(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1437, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1439(F, sep, ...) \ + Z_UTIL_LISTIFY_1438(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1438, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1440(F, sep, ...) \ + Z_UTIL_LISTIFY_1439(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1439, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1441(F, sep, ...) \ + Z_UTIL_LISTIFY_1440(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1440, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1442(F, sep, ...) \ + Z_UTIL_LISTIFY_1441(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1441, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1443(F, sep, ...) \ + Z_UTIL_LISTIFY_1442(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1442, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1444(F, sep, ...) \ + Z_UTIL_LISTIFY_1443(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1443, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1445(F, sep, ...) \ + Z_UTIL_LISTIFY_1444(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1444, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1446(F, sep, ...) \ + Z_UTIL_LISTIFY_1445(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1445, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1447(F, sep, ...) \ + Z_UTIL_LISTIFY_1446(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1446, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1448(F, sep, ...) \ + Z_UTIL_LISTIFY_1447(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1447, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1449(F, sep, ...) \ + Z_UTIL_LISTIFY_1448(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1448, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1450(F, sep, ...) \ + Z_UTIL_LISTIFY_1449(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1449, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1451(F, sep, ...) \ + Z_UTIL_LISTIFY_1450(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1450, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1452(F, sep, ...) \ + Z_UTIL_LISTIFY_1451(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1451, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1453(F, sep, ...) \ + Z_UTIL_LISTIFY_1452(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1452, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1454(F, sep, ...) \ + Z_UTIL_LISTIFY_1453(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1453, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1455(F, sep, ...) \ + Z_UTIL_LISTIFY_1454(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1454, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1456(F, sep, ...) \ + Z_UTIL_LISTIFY_1455(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1455, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1457(F, sep, ...) \ + Z_UTIL_LISTIFY_1456(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1456, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1458(F, sep, ...) \ + Z_UTIL_LISTIFY_1457(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1457, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1459(F, sep, ...) \ + Z_UTIL_LISTIFY_1458(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1458, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1460(F, sep, ...) \ + Z_UTIL_LISTIFY_1459(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1459, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1461(F, sep, ...) \ + Z_UTIL_LISTIFY_1460(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1460, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1462(F, sep, ...) \ + Z_UTIL_LISTIFY_1461(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1461, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1463(F, sep, ...) \ + Z_UTIL_LISTIFY_1462(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1462, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1464(F, sep, ...) \ + Z_UTIL_LISTIFY_1463(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1463, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1465(F, sep, ...) \ + Z_UTIL_LISTIFY_1464(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1464, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1466(F, sep, ...) \ + Z_UTIL_LISTIFY_1465(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1465, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1467(F, sep, ...) \ + Z_UTIL_LISTIFY_1466(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1466, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1468(F, sep, ...) \ + Z_UTIL_LISTIFY_1467(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1467, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1469(F, sep, ...) \ + Z_UTIL_LISTIFY_1468(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1468, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1470(F, sep, ...) \ + Z_UTIL_LISTIFY_1469(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1469, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1471(F, sep, ...) \ + Z_UTIL_LISTIFY_1470(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1470, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1472(F, sep, ...) \ + Z_UTIL_LISTIFY_1471(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1471, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1473(F, sep, ...) \ + Z_UTIL_LISTIFY_1472(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1472, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1474(F, sep, ...) \ + Z_UTIL_LISTIFY_1473(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1473, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1475(F, sep, ...) \ + Z_UTIL_LISTIFY_1474(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1474, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1476(F, sep, ...) \ + Z_UTIL_LISTIFY_1475(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1475, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1477(F, sep, ...) \ + Z_UTIL_LISTIFY_1476(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1476, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1478(F, sep, ...) \ + Z_UTIL_LISTIFY_1477(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1477, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1479(F, sep, ...) \ + Z_UTIL_LISTIFY_1478(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1478, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1480(F, sep, ...) \ + Z_UTIL_LISTIFY_1479(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1479, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1481(F, sep, ...) \ + Z_UTIL_LISTIFY_1480(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1480, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1482(F, sep, ...) \ + Z_UTIL_LISTIFY_1481(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1481, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1483(F, sep, ...) \ + Z_UTIL_LISTIFY_1482(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1482, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1484(F, sep, ...) \ + Z_UTIL_LISTIFY_1483(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1483, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1485(F, sep, ...) \ + Z_UTIL_LISTIFY_1484(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1484, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1486(F, sep, ...) \ + Z_UTIL_LISTIFY_1485(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1485, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1487(F, sep, ...) \ + Z_UTIL_LISTIFY_1486(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1486, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1488(F, sep, ...) \ + Z_UTIL_LISTIFY_1487(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1487, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1489(F, sep, ...) \ + Z_UTIL_LISTIFY_1488(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1488, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1490(F, sep, ...) \ + Z_UTIL_LISTIFY_1489(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1489, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1491(F, sep, ...) \ + Z_UTIL_LISTIFY_1490(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1490, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1492(F, sep, ...) \ + Z_UTIL_LISTIFY_1491(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1491, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1493(F, sep, ...) \ + Z_UTIL_LISTIFY_1492(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1492, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1494(F, sep, ...) \ + Z_UTIL_LISTIFY_1493(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1493, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1495(F, sep, ...) \ + Z_UTIL_LISTIFY_1494(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1494, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1496(F, sep, ...) \ + Z_UTIL_LISTIFY_1495(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1495, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1497(F, sep, ...) \ + Z_UTIL_LISTIFY_1496(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1496, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1498(F, sep, ...) \ + Z_UTIL_LISTIFY_1497(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1497, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1499(F, sep, ...) \ + Z_UTIL_LISTIFY_1498(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1498, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1500(F, sep, ...) \ + Z_UTIL_LISTIFY_1499(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1499, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1501(F, sep, ...) \ + Z_UTIL_LISTIFY_1500(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1500, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1502(F, sep, ...) \ + Z_UTIL_LISTIFY_1501(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1501, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1503(F, sep, ...) \ + Z_UTIL_LISTIFY_1502(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1502, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1504(F, sep, ...) \ + Z_UTIL_LISTIFY_1503(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1503, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1505(F, sep, ...) \ + Z_UTIL_LISTIFY_1504(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1504, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1506(F, sep, ...) \ + Z_UTIL_LISTIFY_1505(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1505, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1507(F, sep, ...) \ + Z_UTIL_LISTIFY_1506(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1506, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1508(F, sep, ...) \ + Z_UTIL_LISTIFY_1507(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1507, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1509(F, sep, ...) \ + Z_UTIL_LISTIFY_1508(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1508, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1510(F, sep, ...) \ + Z_UTIL_LISTIFY_1509(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1509, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1511(F, sep, ...) \ + Z_UTIL_LISTIFY_1510(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1510, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1512(F, sep, ...) \ + Z_UTIL_LISTIFY_1511(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1511, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1513(F, sep, ...) \ + Z_UTIL_LISTIFY_1512(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1512, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1514(F, sep, ...) \ + Z_UTIL_LISTIFY_1513(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1513, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1515(F, sep, ...) \ + Z_UTIL_LISTIFY_1514(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1514, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1516(F, sep, ...) \ + Z_UTIL_LISTIFY_1515(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1515, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1517(F, sep, ...) \ + Z_UTIL_LISTIFY_1516(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1516, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1518(F, sep, ...) \ + Z_UTIL_LISTIFY_1517(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1517, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1519(F, sep, ...) \ + Z_UTIL_LISTIFY_1518(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1518, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1520(F, sep, ...) \ + Z_UTIL_LISTIFY_1519(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1519, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1521(F, sep, ...) \ + Z_UTIL_LISTIFY_1520(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1520, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1522(F, sep, ...) \ + Z_UTIL_LISTIFY_1521(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1521, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1523(F, sep, ...) \ + Z_UTIL_LISTIFY_1522(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1522, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1524(F, sep, ...) \ + Z_UTIL_LISTIFY_1523(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1523, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1525(F, sep, ...) \ + Z_UTIL_LISTIFY_1524(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1524, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1526(F, sep, ...) \ + Z_UTIL_LISTIFY_1525(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1525, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1527(F, sep, ...) \ + Z_UTIL_LISTIFY_1526(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1526, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1528(F, sep, ...) \ + Z_UTIL_LISTIFY_1527(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1527, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1529(F, sep, ...) \ + Z_UTIL_LISTIFY_1528(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1528, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1530(F, sep, ...) \ + Z_UTIL_LISTIFY_1529(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1529, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1531(F, sep, ...) \ + Z_UTIL_LISTIFY_1530(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1530, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1532(F, sep, ...) \ + Z_UTIL_LISTIFY_1531(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1531, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1533(F, sep, ...) \ + Z_UTIL_LISTIFY_1532(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1532, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1534(F, sep, ...) \ + Z_UTIL_LISTIFY_1533(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1533, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1535(F, sep, ...) \ + Z_UTIL_LISTIFY_1534(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1534, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1536(F, sep, ...) \ + Z_UTIL_LISTIFY_1535(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1535, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1537(F, sep, ...) \ + Z_UTIL_LISTIFY_1536(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1536, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1538(F, sep, ...) \ + Z_UTIL_LISTIFY_1537(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1537, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1539(F, sep, ...) \ + Z_UTIL_LISTIFY_1538(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1538, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1540(F, sep, ...) \ + Z_UTIL_LISTIFY_1539(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1539, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1541(F, sep, ...) \ + Z_UTIL_LISTIFY_1540(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1540, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1542(F, sep, ...) \ + Z_UTIL_LISTIFY_1541(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1541, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1543(F, sep, ...) \ + Z_UTIL_LISTIFY_1542(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1542, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1544(F, sep, ...) \ + Z_UTIL_LISTIFY_1543(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1543, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1545(F, sep, ...) \ + Z_UTIL_LISTIFY_1544(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1544, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1546(F, sep, ...) \ + Z_UTIL_LISTIFY_1545(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1545, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1547(F, sep, ...) \ + Z_UTIL_LISTIFY_1546(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1546, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1548(F, sep, ...) \ + Z_UTIL_LISTIFY_1547(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1547, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1549(F, sep, ...) \ + Z_UTIL_LISTIFY_1548(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1548, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1550(F, sep, ...) \ + Z_UTIL_LISTIFY_1549(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1549, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1551(F, sep, ...) \ + Z_UTIL_LISTIFY_1550(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1550, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1552(F, sep, ...) \ + Z_UTIL_LISTIFY_1551(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1551, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1553(F, sep, ...) \ + Z_UTIL_LISTIFY_1552(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1552, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1554(F, sep, ...) \ + Z_UTIL_LISTIFY_1553(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1553, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1555(F, sep, ...) \ + Z_UTIL_LISTIFY_1554(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1554, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1556(F, sep, ...) \ + Z_UTIL_LISTIFY_1555(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1555, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1557(F, sep, ...) \ + Z_UTIL_LISTIFY_1556(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1556, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1558(F, sep, ...) \ + Z_UTIL_LISTIFY_1557(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1557, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1559(F, sep, ...) \ + Z_UTIL_LISTIFY_1558(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1558, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1560(F, sep, ...) \ + Z_UTIL_LISTIFY_1559(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1559, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1561(F, sep, ...) \ + Z_UTIL_LISTIFY_1560(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1560, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1562(F, sep, ...) \ + Z_UTIL_LISTIFY_1561(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1561, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1563(F, sep, ...) \ + Z_UTIL_LISTIFY_1562(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1562, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1564(F, sep, ...) \ + Z_UTIL_LISTIFY_1563(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1563, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1565(F, sep, ...) \ + Z_UTIL_LISTIFY_1564(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1564, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1566(F, sep, ...) \ + Z_UTIL_LISTIFY_1565(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1565, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1567(F, sep, ...) \ + Z_UTIL_LISTIFY_1566(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1566, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1568(F, sep, ...) \ + Z_UTIL_LISTIFY_1567(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1567, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1569(F, sep, ...) \ + Z_UTIL_LISTIFY_1568(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1568, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1570(F, sep, ...) \ + Z_UTIL_LISTIFY_1569(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1569, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1571(F, sep, ...) \ + Z_UTIL_LISTIFY_1570(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1570, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1572(F, sep, ...) \ + Z_UTIL_LISTIFY_1571(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1571, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1573(F, sep, ...) \ + Z_UTIL_LISTIFY_1572(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1572, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1574(F, sep, ...) \ + Z_UTIL_LISTIFY_1573(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1573, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1575(F, sep, ...) \ + Z_UTIL_LISTIFY_1574(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1574, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1576(F, sep, ...) \ + Z_UTIL_LISTIFY_1575(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1575, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1577(F, sep, ...) \ + Z_UTIL_LISTIFY_1576(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1576, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1578(F, sep, ...) \ + Z_UTIL_LISTIFY_1577(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1577, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1579(F, sep, ...) \ + Z_UTIL_LISTIFY_1578(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1578, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1580(F, sep, ...) \ + Z_UTIL_LISTIFY_1579(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1579, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1581(F, sep, ...) \ + Z_UTIL_LISTIFY_1580(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1580, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1582(F, sep, ...) \ + Z_UTIL_LISTIFY_1581(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1581, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1583(F, sep, ...) \ + Z_UTIL_LISTIFY_1582(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1582, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1584(F, sep, ...) \ + Z_UTIL_LISTIFY_1583(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1583, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1585(F, sep, ...) \ + Z_UTIL_LISTIFY_1584(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1584, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1586(F, sep, ...) \ + Z_UTIL_LISTIFY_1585(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1585, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1587(F, sep, ...) \ + Z_UTIL_LISTIFY_1586(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1586, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1588(F, sep, ...) \ + Z_UTIL_LISTIFY_1587(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1587, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1589(F, sep, ...) \ + Z_UTIL_LISTIFY_1588(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1588, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1590(F, sep, ...) \ + Z_UTIL_LISTIFY_1589(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1589, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1591(F, sep, ...) \ + Z_UTIL_LISTIFY_1590(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1590, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1592(F, sep, ...) \ + Z_UTIL_LISTIFY_1591(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1591, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1593(F, sep, ...) \ + Z_UTIL_LISTIFY_1592(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1592, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1594(F, sep, ...) \ + Z_UTIL_LISTIFY_1593(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1593, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1595(F, sep, ...) \ + Z_UTIL_LISTIFY_1594(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1594, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1596(F, sep, ...) \ + Z_UTIL_LISTIFY_1595(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1595, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1597(F, sep, ...) \ + Z_UTIL_LISTIFY_1596(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1596, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1598(F, sep, ...) \ + Z_UTIL_LISTIFY_1597(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1597, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1599(F, sep, ...) \ + Z_UTIL_LISTIFY_1598(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1598, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1600(F, sep, ...) \ + Z_UTIL_LISTIFY_1599(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1599, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1601(F, sep, ...) \ + Z_UTIL_LISTIFY_1600(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1600, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1602(F, sep, ...) \ + Z_UTIL_LISTIFY_1601(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1601, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1603(F, sep, ...) \ + Z_UTIL_LISTIFY_1602(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1602, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1604(F, sep, ...) \ + Z_UTIL_LISTIFY_1603(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1603, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1605(F, sep, ...) \ + Z_UTIL_LISTIFY_1604(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1604, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1606(F, sep, ...) \ + Z_UTIL_LISTIFY_1605(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1605, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1607(F, sep, ...) \ + Z_UTIL_LISTIFY_1606(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1606, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1608(F, sep, ...) \ + Z_UTIL_LISTIFY_1607(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1607, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1609(F, sep, ...) \ + Z_UTIL_LISTIFY_1608(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1608, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1610(F, sep, ...) \ + Z_UTIL_LISTIFY_1609(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1609, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1611(F, sep, ...) \ + Z_UTIL_LISTIFY_1610(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1610, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1612(F, sep, ...) \ + Z_UTIL_LISTIFY_1611(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1611, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1613(F, sep, ...) \ + Z_UTIL_LISTIFY_1612(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1612, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1614(F, sep, ...) \ + Z_UTIL_LISTIFY_1613(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1613, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1615(F, sep, ...) \ + Z_UTIL_LISTIFY_1614(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1614, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1616(F, sep, ...) \ + Z_UTIL_LISTIFY_1615(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1615, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1617(F, sep, ...) \ + Z_UTIL_LISTIFY_1616(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1616, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1618(F, sep, ...) \ + Z_UTIL_LISTIFY_1617(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1617, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1619(F, sep, ...) \ + Z_UTIL_LISTIFY_1618(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1618, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1620(F, sep, ...) \ + Z_UTIL_LISTIFY_1619(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1619, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1621(F, sep, ...) \ + Z_UTIL_LISTIFY_1620(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1620, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1622(F, sep, ...) \ + Z_UTIL_LISTIFY_1621(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1621, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1623(F, sep, ...) \ + Z_UTIL_LISTIFY_1622(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1622, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1624(F, sep, ...) \ + Z_UTIL_LISTIFY_1623(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1623, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1625(F, sep, ...) \ + Z_UTIL_LISTIFY_1624(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1624, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1626(F, sep, ...) \ + Z_UTIL_LISTIFY_1625(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1625, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1627(F, sep, ...) \ + Z_UTIL_LISTIFY_1626(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1626, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1628(F, sep, ...) \ + Z_UTIL_LISTIFY_1627(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1627, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1629(F, sep, ...) \ + Z_UTIL_LISTIFY_1628(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1628, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1630(F, sep, ...) \ + Z_UTIL_LISTIFY_1629(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1629, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1631(F, sep, ...) \ + Z_UTIL_LISTIFY_1630(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1630, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1632(F, sep, ...) \ + Z_UTIL_LISTIFY_1631(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1631, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1633(F, sep, ...) \ + Z_UTIL_LISTIFY_1632(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1632, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1634(F, sep, ...) \ + Z_UTIL_LISTIFY_1633(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1633, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1635(F, sep, ...) \ + Z_UTIL_LISTIFY_1634(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1634, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1636(F, sep, ...) \ + Z_UTIL_LISTIFY_1635(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1635, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1637(F, sep, ...) \ + Z_UTIL_LISTIFY_1636(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1636, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1638(F, sep, ...) \ + Z_UTIL_LISTIFY_1637(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1637, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1639(F, sep, ...) \ + Z_UTIL_LISTIFY_1638(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1638, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1640(F, sep, ...) \ + Z_UTIL_LISTIFY_1639(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1639, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1641(F, sep, ...) \ + Z_UTIL_LISTIFY_1640(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1640, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1642(F, sep, ...) \ + Z_UTIL_LISTIFY_1641(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1641, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1643(F, sep, ...) \ + Z_UTIL_LISTIFY_1642(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1642, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1644(F, sep, ...) \ + Z_UTIL_LISTIFY_1643(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1643, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1645(F, sep, ...) \ + Z_UTIL_LISTIFY_1644(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1644, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1646(F, sep, ...) \ + Z_UTIL_LISTIFY_1645(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1645, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1647(F, sep, ...) \ + Z_UTIL_LISTIFY_1646(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1646, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1648(F, sep, ...) \ + Z_UTIL_LISTIFY_1647(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1647, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1649(F, sep, ...) \ + Z_UTIL_LISTIFY_1648(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1648, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1650(F, sep, ...) \ + Z_UTIL_LISTIFY_1649(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1649, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1651(F, sep, ...) \ + Z_UTIL_LISTIFY_1650(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1650, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1652(F, sep, ...) \ + Z_UTIL_LISTIFY_1651(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1651, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1653(F, sep, ...) \ + Z_UTIL_LISTIFY_1652(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1652, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1654(F, sep, ...) \ + Z_UTIL_LISTIFY_1653(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1653, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1655(F, sep, ...) \ + Z_UTIL_LISTIFY_1654(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1654, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1656(F, sep, ...) \ + Z_UTIL_LISTIFY_1655(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1655, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1657(F, sep, ...) \ + Z_UTIL_LISTIFY_1656(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1656, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1658(F, sep, ...) \ + Z_UTIL_LISTIFY_1657(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1657, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1659(F, sep, ...) \ + Z_UTIL_LISTIFY_1658(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1658, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1660(F, sep, ...) \ + Z_UTIL_LISTIFY_1659(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1659, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1661(F, sep, ...) \ + Z_UTIL_LISTIFY_1660(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1660, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1662(F, sep, ...) \ + Z_UTIL_LISTIFY_1661(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1661, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1663(F, sep, ...) \ + Z_UTIL_LISTIFY_1662(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1662, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1664(F, sep, ...) \ + Z_UTIL_LISTIFY_1663(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1663, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1665(F, sep, ...) \ + Z_UTIL_LISTIFY_1664(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1664, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1666(F, sep, ...) \ + Z_UTIL_LISTIFY_1665(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1665, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1667(F, sep, ...) \ + Z_UTIL_LISTIFY_1666(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1666, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1668(F, sep, ...) \ + Z_UTIL_LISTIFY_1667(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1667, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1669(F, sep, ...) \ + Z_UTIL_LISTIFY_1668(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1668, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1670(F, sep, ...) \ + Z_UTIL_LISTIFY_1669(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1669, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1671(F, sep, ...) \ + Z_UTIL_LISTIFY_1670(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1670, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1672(F, sep, ...) \ + Z_UTIL_LISTIFY_1671(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1671, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1673(F, sep, ...) \ + Z_UTIL_LISTIFY_1672(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1672, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1674(F, sep, ...) \ + Z_UTIL_LISTIFY_1673(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1673, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1675(F, sep, ...) \ + Z_UTIL_LISTIFY_1674(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1674, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1676(F, sep, ...) \ + Z_UTIL_LISTIFY_1675(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1675, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1677(F, sep, ...) \ + Z_UTIL_LISTIFY_1676(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1676, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1678(F, sep, ...) \ + Z_UTIL_LISTIFY_1677(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1677, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1679(F, sep, ...) \ + Z_UTIL_LISTIFY_1678(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1678, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1680(F, sep, ...) \ + Z_UTIL_LISTIFY_1679(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1679, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1681(F, sep, ...) \ + Z_UTIL_LISTIFY_1680(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1680, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1682(F, sep, ...) \ + Z_UTIL_LISTIFY_1681(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1681, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1683(F, sep, ...) \ + Z_UTIL_LISTIFY_1682(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1682, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1684(F, sep, ...) \ + Z_UTIL_LISTIFY_1683(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1683, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1685(F, sep, ...) \ + Z_UTIL_LISTIFY_1684(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1684, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1686(F, sep, ...) \ + Z_UTIL_LISTIFY_1685(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1685, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1687(F, sep, ...) \ + Z_UTIL_LISTIFY_1686(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1686, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1688(F, sep, ...) \ + Z_UTIL_LISTIFY_1687(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1687, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1689(F, sep, ...) \ + Z_UTIL_LISTIFY_1688(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1688, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1690(F, sep, ...) \ + Z_UTIL_LISTIFY_1689(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1689, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1691(F, sep, ...) \ + Z_UTIL_LISTIFY_1690(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1690, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1692(F, sep, ...) \ + Z_UTIL_LISTIFY_1691(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1691, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1693(F, sep, ...) \ + Z_UTIL_LISTIFY_1692(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1692, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1694(F, sep, ...) \ + Z_UTIL_LISTIFY_1693(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1693, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1695(F, sep, ...) \ + Z_UTIL_LISTIFY_1694(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1694, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1696(F, sep, ...) \ + Z_UTIL_LISTIFY_1695(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1695, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1697(F, sep, ...) \ + Z_UTIL_LISTIFY_1696(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1696, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1698(F, sep, ...) \ + Z_UTIL_LISTIFY_1697(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1697, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1699(F, sep, ...) \ + Z_UTIL_LISTIFY_1698(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1698, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1700(F, sep, ...) \ + Z_UTIL_LISTIFY_1699(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1699, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1701(F, sep, ...) \ + Z_UTIL_LISTIFY_1700(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1700, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1702(F, sep, ...) \ + Z_UTIL_LISTIFY_1701(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1701, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1703(F, sep, ...) \ + Z_UTIL_LISTIFY_1702(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1702, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1704(F, sep, ...) \ + Z_UTIL_LISTIFY_1703(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1703, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1705(F, sep, ...) \ + Z_UTIL_LISTIFY_1704(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1704, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1706(F, sep, ...) \ + Z_UTIL_LISTIFY_1705(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1705, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1707(F, sep, ...) \ + Z_UTIL_LISTIFY_1706(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1706, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1708(F, sep, ...) \ + Z_UTIL_LISTIFY_1707(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1707, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1709(F, sep, ...) \ + Z_UTIL_LISTIFY_1708(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1708, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1710(F, sep, ...) \ + Z_UTIL_LISTIFY_1709(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1709, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1711(F, sep, ...) \ + Z_UTIL_LISTIFY_1710(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1710, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1712(F, sep, ...) \ + Z_UTIL_LISTIFY_1711(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1711, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1713(F, sep, ...) \ + Z_UTIL_LISTIFY_1712(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1712, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1714(F, sep, ...) \ + Z_UTIL_LISTIFY_1713(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1713, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1715(F, sep, ...) \ + Z_UTIL_LISTIFY_1714(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1714, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1716(F, sep, ...) \ + Z_UTIL_LISTIFY_1715(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1715, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1717(F, sep, ...) \ + Z_UTIL_LISTIFY_1716(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1716, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1718(F, sep, ...) \ + Z_UTIL_LISTIFY_1717(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1717, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1719(F, sep, ...) \ + Z_UTIL_LISTIFY_1718(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1718, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1720(F, sep, ...) \ + Z_UTIL_LISTIFY_1719(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1719, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1721(F, sep, ...) \ + Z_UTIL_LISTIFY_1720(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1720, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1722(F, sep, ...) \ + Z_UTIL_LISTIFY_1721(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1721, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1723(F, sep, ...) \ + Z_UTIL_LISTIFY_1722(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1722, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1724(F, sep, ...) \ + Z_UTIL_LISTIFY_1723(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1723, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1725(F, sep, ...) \ + Z_UTIL_LISTIFY_1724(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1724, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1726(F, sep, ...) \ + Z_UTIL_LISTIFY_1725(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1725, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1727(F, sep, ...) \ + Z_UTIL_LISTIFY_1726(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1726, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1728(F, sep, ...) \ + Z_UTIL_LISTIFY_1727(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1727, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1729(F, sep, ...) \ + Z_UTIL_LISTIFY_1728(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1728, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1730(F, sep, ...) \ + Z_UTIL_LISTIFY_1729(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1729, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1731(F, sep, ...) \ + Z_UTIL_LISTIFY_1730(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1730, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1732(F, sep, ...) \ + Z_UTIL_LISTIFY_1731(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1731, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1733(F, sep, ...) \ + Z_UTIL_LISTIFY_1732(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1732, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1734(F, sep, ...) \ + Z_UTIL_LISTIFY_1733(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1733, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1735(F, sep, ...) \ + Z_UTIL_LISTIFY_1734(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1734, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1736(F, sep, ...) \ + Z_UTIL_LISTIFY_1735(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1735, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1737(F, sep, ...) \ + Z_UTIL_LISTIFY_1736(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1736, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1738(F, sep, ...) \ + Z_UTIL_LISTIFY_1737(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1737, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1739(F, sep, ...) \ + Z_UTIL_LISTIFY_1738(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1738, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1740(F, sep, ...) \ + Z_UTIL_LISTIFY_1739(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1739, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1741(F, sep, ...) \ + Z_UTIL_LISTIFY_1740(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1740, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1742(F, sep, ...) \ + Z_UTIL_LISTIFY_1741(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1741, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1743(F, sep, ...) \ + Z_UTIL_LISTIFY_1742(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1742, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1744(F, sep, ...) \ + Z_UTIL_LISTIFY_1743(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1743, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1745(F, sep, ...) \ + Z_UTIL_LISTIFY_1744(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1744, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1746(F, sep, ...) \ + Z_UTIL_LISTIFY_1745(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1745, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1747(F, sep, ...) \ + Z_UTIL_LISTIFY_1746(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1746, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1748(F, sep, ...) \ + Z_UTIL_LISTIFY_1747(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1747, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1749(F, sep, ...) \ + Z_UTIL_LISTIFY_1748(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1748, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1750(F, sep, ...) \ + Z_UTIL_LISTIFY_1749(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1749, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1751(F, sep, ...) \ + Z_UTIL_LISTIFY_1750(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1750, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1752(F, sep, ...) \ + Z_UTIL_LISTIFY_1751(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1751, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1753(F, sep, ...) \ + Z_UTIL_LISTIFY_1752(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1752, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1754(F, sep, ...) \ + Z_UTIL_LISTIFY_1753(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1753, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1755(F, sep, ...) \ + Z_UTIL_LISTIFY_1754(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1754, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1756(F, sep, ...) \ + Z_UTIL_LISTIFY_1755(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1755, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1757(F, sep, ...) \ + Z_UTIL_LISTIFY_1756(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1756, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1758(F, sep, ...) \ + Z_UTIL_LISTIFY_1757(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1757, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1759(F, sep, ...) \ + Z_UTIL_LISTIFY_1758(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1758, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1760(F, sep, ...) \ + Z_UTIL_LISTIFY_1759(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1759, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1761(F, sep, ...) \ + Z_UTIL_LISTIFY_1760(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1760, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1762(F, sep, ...) \ + Z_UTIL_LISTIFY_1761(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1761, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1763(F, sep, ...) \ + Z_UTIL_LISTIFY_1762(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1762, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1764(F, sep, ...) \ + Z_UTIL_LISTIFY_1763(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1763, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1765(F, sep, ...) \ + Z_UTIL_LISTIFY_1764(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1764, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1766(F, sep, ...) \ + Z_UTIL_LISTIFY_1765(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1765, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1767(F, sep, ...) \ + Z_UTIL_LISTIFY_1766(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1766, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1768(F, sep, ...) \ + Z_UTIL_LISTIFY_1767(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1767, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1769(F, sep, ...) \ + Z_UTIL_LISTIFY_1768(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1768, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1770(F, sep, ...) \ + Z_UTIL_LISTIFY_1769(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1769, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1771(F, sep, ...) \ + Z_UTIL_LISTIFY_1770(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1770, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1772(F, sep, ...) \ + Z_UTIL_LISTIFY_1771(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1771, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1773(F, sep, ...) \ + Z_UTIL_LISTIFY_1772(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1772, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1774(F, sep, ...) \ + Z_UTIL_LISTIFY_1773(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1773, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1775(F, sep, ...) \ + Z_UTIL_LISTIFY_1774(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1774, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1776(F, sep, ...) \ + Z_UTIL_LISTIFY_1775(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1775, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1777(F, sep, ...) \ + Z_UTIL_LISTIFY_1776(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1776, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1778(F, sep, ...) \ + Z_UTIL_LISTIFY_1777(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1777, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1779(F, sep, ...) \ + Z_UTIL_LISTIFY_1778(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1778, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1780(F, sep, ...) \ + Z_UTIL_LISTIFY_1779(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1779, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1781(F, sep, ...) \ + Z_UTIL_LISTIFY_1780(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1780, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1782(F, sep, ...) \ + Z_UTIL_LISTIFY_1781(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1781, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1783(F, sep, ...) \ + Z_UTIL_LISTIFY_1782(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1782, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1784(F, sep, ...) \ + Z_UTIL_LISTIFY_1783(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1783, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1785(F, sep, ...) \ + Z_UTIL_LISTIFY_1784(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1784, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1786(F, sep, ...) \ + Z_UTIL_LISTIFY_1785(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1785, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1787(F, sep, ...) \ + Z_UTIL_LISTIFY_1786(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1786, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1788(F, sep, ...) \ + Z_UTIL_LISTIFY_1787(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1787, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1789(F, sep, ...) \ + Z_UTIL_LISTIFY_1788(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1788, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1790(F, sep, ...) \ + Z_UTIL_LISTIFY_1789(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1789, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1791(F, sep, ...) \ + Z_UTIL_LISTIFY_1790(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1790, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1792(F, sep, ...) \ + Z_UTIL_LISTIFY_1791(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1791, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1793(F, sep, ...) \ + Z_UTIL_LISTIFY_1792(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1792, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1794(F, sep, ...) \ + Z_UTIL_LISTIFY_1793(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1793, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1795(F, sep, ...) \ + Z_UTIL_LISTIFY_1794(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1794, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1796(F, sep, ...) \ + Z_UTIL_LISTIFY_1795(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1795, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1797(F, sep, ...) \ + Z_UTIL_LISTIFY_1796(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1796, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1798(F, sep, ...) \ + Z_UTIL_LISTIFY_1797(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1797, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1799(F, sep, ...) \ + Z_UTIL_LISTIFY_1798(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1798, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1800(F, sep, ...) \ + Z_UTIL_LISTIFY_1799(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1799, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1801(F, sep, ...) \ + Z_UTIL_LISTIFY_1800(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1800, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1802(F, sep, ...) \ + Z_UTIL_LISTIFY_1801(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1801, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1803(F, sep, ...) \ + Z_UTIL_LISTIFY_1802(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1802, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1804(F, sep, ...) \ + Z_UTIL_LISTIFY_1803(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1803, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1805(F, sep, ...) \ + Z_UTIL_LISTIFY_1804(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1804, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1806(F, sep, ...) \ + Z_UTIL_LISTIFY_1805(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1805, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1807(F, sep, ...) \ + Z_UTIL_LISTIFY_1806(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1806, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1808(F, sep, ...) \ + Z_UTIL_LISTIFY_1807(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1807, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1809(F, sep, ...) \ + Z_UTIL_LISTIFY_1808(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1808, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1810(F, sep, ...) \ + Z_UTIL_LISTIFY_1809(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1809, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1811(F, sep, ...) \ + Z_UTIL_LISTIFY_1810(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1810, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1812(F, sep, ...) \ + Z_UTIL_LISTIFY_1811(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1811, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1813(F, sep, ...) \ + Z_UTIL_LISTIFY_1812(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1812, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1814(F, sep, ...) \ + Z_UTIL_LISTIFY_1813(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1813, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1815(F, sep, ...) \ + Z_UTIL_LISTIFY_1814(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1814, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1816(F, sep, ...) \ + Z_UTIL_LISTIFY_1815(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1815, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1817(F, sep, ...) \ + Z_UTIL_LISTIFY_1816(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1816, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1818(F, sep, ...) \ + Z_UTIL_LISTIFY_1817(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1817, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1819(F, sep, ...) \ + Z_UTIL_LISTIFY_1818(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1818, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1820(F, sep, ...) \ + Z_UTIL_LISTIFY_1819(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1819, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1821(F, sep, ...) \ + Z_UTIL_LISTIFY_1820(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1820, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1822(F, sep, ...) \ + Z_UTIL_LISTIFY_1821(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1821, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1823(F, sep, ...) \ + Z_UTIL_LISTIFY_1822(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1822, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1824(F, sep, ...) \ + Z_UTIL_LISTIFY_1823(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1823, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1825(F, sep, ...) \ + Z_UTIL_LISTIFY_1824(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1824, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1826(F, sep, ...) \ + Z_UTIL_LISTIFY_1825(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1825, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1827(F, sep, ...) \ + Z_UTIL_LISTIFY_1826(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1826, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1828(F, sep, ...) \ + Z_UTIL_LISTIFY_1827(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1827, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1829(F, sep, ...) \ + Z_UTIL_LISTIFY_1828(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1828, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1830(F, sep, ...) \ + Z_UTIL_LISTIFY_1829(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1829, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1831(F, sep, ...) \ + Z_UTIL_LISTIFY_1830(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1830, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1832(F, sep, ...) \ + Z_UTIL_LISTIFY_1831(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1831, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1833(F, sep, ...) \ + Z_UTIL_LISTIFY_1832(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1832, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1834(F, sep, ...) \ + Z_UTIL_LISTIFY_1833(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1833, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1835(F, sep, ...) \ + Z_UTIL_LISTIFY_1834(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1834, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1836(F, sep, ...) \ + Z_UTIL_LISTIFY_1835(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1835, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1837(F, sep, ...) \ + Z_UTIL_LISTIFY_1836(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1836, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1838(F, sep, ...) \ + Z_UTIL_LISTIFY_1837(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1837, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1839(F, sep, ...) \ + Z_UTIL_LISTIFY_1838(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1838, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1840(F, sep, ...) \ + Z_UTIL_LISTIFY_1839(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1839, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1841(F, sep, ...) \ + Z_UTIL_LISTIFY_1840(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1840, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1842(F, sep, ...) \ + Z_UTIL_LISTIFY_1841(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1841, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1843(F, sep, ...) \ + Z_UTIL_LISTIFY_1842(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1842, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1844(F, sep, ...) \ + Z_UTIL_LISTIFY_1843(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1843, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1845(F, sep, ...) \ + Z_UTIL_LISTIFY_1844(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1844, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1846(F, sep, ...) \ + Z_UTIL_LISTIFY_1845(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1845, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1847(F, sep, ...) \ + Z_UTIL_LISTIFY_1846(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1846, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1848(F, sep, ...) \ + Z_UTIL_LISTIFY_1847(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1847, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1849(F, sep, ...) \ + Z_UTIL_LISTIFY_1848(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1848, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1850(F, sep, ...) \ + Z_UTIL_LISTIFY_1849(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1849, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1851(F, sep, ...) \ + Z_UTIL_LISTIFY_1850(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1850, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1852(F, sep, ...) \ + Z_UTIL_LISTIFY_1851(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1851, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1853(F, sep, ...) \ + Z_UTIL_LISTIFY_1852(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1852, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1854(F, sep, ...) \ + Z_UTIL_LISTIFY_1853(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1853, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1855(F, sep, ...) \ + Z_UTIL_LISTIFY_1854(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1854, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1856(F, sep, ...) \ + Z_UTIL_LISTIFY_1855(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1855, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1857(F, sep, ...) \ + Z_UTIL_LISTIFY_1856(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1856, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1858(F, sep, ...) \ + Z_UTIL_LISTIFY_1857(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1857, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1859(F, sep, ...) \ + Z_UTIL_LISTIFY_1858(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1858, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1860(F, sep, ...) \ + Z_UTIL_LISTIFY_1859(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1859, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1861(F, sep, ...) \ + Z_UTIL_LISTIFY_1860(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1860, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1862(F, sep, ...) \ + Z_UTIL_LISTIFY_1861(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1861, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1863(F, sep, ...) \ + Z_UTIL_LISTIFY_1862(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1862, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1864(F, sep, ...) \ + Z_UTIL_LISTIFY_1863(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1863, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1865(F, sep, ...) \ + Z_UTIL_LISTIFY_1864(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1864, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1866(F, sep, ...) \ + Z_UTIL_LISTIFY_1865(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1865, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1867(F, sep, ...) \ + Z_UTIL_LISTIFY_1866(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1866, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1868(F, sep, ...) \ + Z_UTIL_LISTIFY_1867(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1867, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1869(F, sep, ...) \ + Z_UTIL_LISTIFY_1868(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1868, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1870(F, sep, ...) \ + Z_UTIL_LISTIFY_1869(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1869, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1871(F, sep, ...) \ + Z_UTIL_LISTIFY_1870(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1870, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1872(F, sep, ...) \ + Z_UTIL_LISTIFY_1871(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1871, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1873(F, sep, ...) \ + Z_UTIL_LISTIFY_1872(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1872, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1874(F, sep, ...) \ + Z_UTIL_LISTIFY_1873(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1873, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1875(F, sep, ...) \ + Z_UTIL_LISTIFY_1874(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1874, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1876(F, sep, ...) \ + Z_UTIL_LISTIFY_1875(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1875, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1877(F, sep, ...) \ + Z_UTIL_LISTIFY_1876(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1876, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1878(F, sep, ...) \ + Z_UTIL_LISTIFY_1877(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1877, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1879(F, sep, ...) \ + Z_UTIL_LISTIFY_1878(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1878, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1880(F, sep, ...) \ + Z_UTIL_LISTIFY_1879(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1879, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1881(F, sep, ...) \ + Z_UTIL_LISTIFY_1880(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1880, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1882(F, sep, ...) \ + Z_UTIL_LISTIFY_1881(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1881, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1883(F, sep, ...) \ + Z_UTIL_LISTIFY_1882(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1882, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1884(F, sep, ...) \ + Z_UTIL_LISTIFY_1883(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1883, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1885(F, sep, ...) \ + Z_UTIL_LISTIFY_1884(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1884, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1886(F, sep, ...) \ + Z_UTIL_LISTIFY_1885(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1885, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1887(F, sep, ...) \ + Z_UTIL_LISTIFY_1886(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1886, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1888(F, sep, ...) \ + Z_UTIL_LISTIFY_1887(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1887, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1889(F, sep, ...) \ + Z_UTIL_LISTIFY_1888(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1888, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1890(F, sep, ...) \ + Z_UTIL_LISTIFY_1889(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1889, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1891(F, sep, ...) \ + Z_UTIL_LISTIFY_1890(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1890, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1892(F, sep, ...) \ + Z_UTIL_LISTIFY_1891(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1891, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1893(F, sep, ...) \ + Z_UTIL_LISTIFY_1892(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1892, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1894(F, sep, ...) \ + Z_UTIL_LISTIFY_1893(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1893, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1895(F, sep, ...) \ + Z_UTIL_LISTIFY_1894(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1894, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1896(F, sep, ...) \ + Z_UTIL_LISTIFY_1895(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1895, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1897(F, sep, ...) \ + Z_UTIL_LISTIFY_1896(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1896, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1898(F, sep, ...) \ + Z_UTIL_LISTIFY_1897(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1897, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1899(F, sep, ...) \ + Z_UTIL_LISTIFY_1898(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1898, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1900(F, sep, ...) \ + Z_UTIL_LISTIFY_1899(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1899, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1901(F, sep, ...) \ + Z_UTIL_LISTIFY_1900(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1900, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1902(F, sep, ...) \ + Z_UTIL_LISTIFY_1901(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1901, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1903(F, sep, ...) \ + Z_UTIL_LISTIFY_1902(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1902, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1904(F, sep, ...) \ + Z_UTIL_LISTIFY_1903(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1903, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1905(F, sep, ...) \ + Z_UTIL_LISTIFY_1904(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1904, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1906(F, sep, ...) \ + Z_UTIL_LISTIFY_1905(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1905, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1907(F, sep, ...) \ + Z_UTIL_LISTIFY_1906(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1906, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1908(F, sep, ...) \ + Z_UTIL_LISTIFY_1907(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1907, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1909(F, sep, ...) \ + Z_UTIL_LISTIFY_1908(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1908, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1910(F, sep, ...) \ + Z_UTIL_LISTIFY_1909(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1909, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1911(F, sep, ...) \ + Z_UTIL_LISTIFY_1910(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1910, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1912(F, sep, ...) \ + Z_UTIL_LISTIFY_1911(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1911, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1913(F, sep, ...) \ + Z_UTIL_LISTIFY_1912(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1912, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1914(F, sep, ...) \ + Z_UTIL_LISTIFY_1913(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1913, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1915(F, sep, ...) \ + Z_UTIL_LISTIFY_1914(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1914, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1916(F, sep, ...) \ + Z_UTIL_LISTIFY_1915(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1915, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1917(F, sep, ...) \ + Z_UTIL_LISTIFY_1916(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1916, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1918(F, sep, ...) \ + Z_UTIL_LISTIFY_1917(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1917, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1919(F, sep, ...) \ + Z_UTIL_LISTIFY_1918(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1918, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1920(F, sep, ...) \ + Z_UTIL_LISTIFY_1919(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1919, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1921(F, sep, ...) \ + Z_UTIL_LISTIFY_1920(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1920, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1922(F, sep, ...) \ + Z_UTIL_LISTIFY_1921(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1921, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1923(F, sep, ...) \ + Z_UTIL_LISTIFY_1922(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1922, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1924(F, sep, ...) \ + Z_UTIL_LISTIFY_1923(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1923, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1925(F, sep, ...) \ + Z_UTIL_LISTIFY_1924(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1924, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1926(F, sep, ...) \ + Z_UTIL_LISTIFY_1925(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1925, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1927(F, sep, ...) \ + Z_UTIL_LISTIFY_1926(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1926, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1928(F, sep, ...) \ + Z_UTIL_LISTIFY_1927(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1927, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1929(F, sep, ...) \ + Z_UTIL_LISTIFY_1928(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1928, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1930(F, sep, ...) \ + Z_UTIL_LISTIFY_1929(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1929, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1931(F, sep, ...) \ + Z_UTIL_LISTIFY_1930(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1930, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1932(F, sep, ...) \ + Z_UTIL_LISTIFY_1931(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1931, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1933(F, sep, ...) \ + Z_UTIL_LISTIFY_1932(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1932, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1934(F, sep, ...) \ + Z_UTIL_LISTIFY_1933(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1933, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1935(F, sep, ...) \ + Z_UTIL_LISTIFY_1934(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1934, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1936(F, sep, ...) \ + Z_UTIL_LISTIFY_1935(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1935, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1937(F, sep, ...) \ + Z_UTIL_LISTIFY_1936(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1936, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1938(F, sep, ...) \ + Z_UTIL_LISTIFY_1937(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1937, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1939(F, sep, ...) \ + Z_UTIL_LISTIFY_1938(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1938, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1940(F, sep, ...) \ + Z_UTIL_LISTIFY_1939(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1939, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1941(F, sep, ...) \ + Z_UTIL_LISTIFY_1940(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1940, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1942(F, sep, ...) \ + Z_UTIL_LISTIFY_1941(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1941, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1943(F, sep, ...) \ + Z_UTIL_LISTIFY_1942(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1942, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1944(F, sep, ...) \ + Z_UTIL_LISTIFY_1943(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1943, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1945(F, sep, ...) \ + Z_UTIL_LISTIFY_1944(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1944, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1946(F, sep, ...) \ + Z_UTIL_LISTIFY_1945(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1945, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1947(F, sep, ...) \ + Z_UTIL_LISTIFY_1946(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1946, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1948(F, sep, ...) \ + Z_UTIL_LISTIFY_1947(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1947, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1949(F, sep, ...) \ + Z_UTIL_LISTIFY_1948(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1948, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1950(F, sep, ...) \ + Z_UTIL_LISTIFY_1949(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1949, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1951(F, sep, ...) \ + Z_UTIL_LISTIFY_1950(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1950, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1952(F, sep, ...) \ + Z_UTIL_LISTIFY_1951(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1951, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1953(F, sep, ...) \ + Z_UTIL_LISTIFY_1952(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1952, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1954(F, sep, ...) \ + Z_UTIL_LISTIFY_1953(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1953, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1955(F, sep, ...) \ + Z_UTIL_LISTIFY_1954(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1954, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1956(F, sep, ...) \ + Z_UTIL_LISTIFY_1955(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1955, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1957(F, sep, ...) \ + Z_UTIL_LISTIFY_1956(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1956, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1958(F, sep, ...) \ + Z_UTIL_LISTIFY_1957(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1957, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1959(F, sep, ...) \ + Z_UTIL_LISTIFY_1958(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1958, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1960(F, sep, ...) \ + Z_UTIL_LISTIFY_1959(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1959, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1961(F, sep, ...) \ + Z_UTIL_LISTIFY_1960(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1960, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1962(F, sep, ...) \ + Z_UTIL_LISTIFY_1961(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1961, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1963(F, sep, ...) \ + Z_UTIL_LISTIFY_1962(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1962, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1964(F, sep, ...) \ + Z_UTIL_LISTIFY_1963(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1963, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1965(F, sep, ...) \ + Z_UTIL_LISTIFY_1964(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1964, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1966(F, sep, ...) \ + Z_UTIL_LISTIFY_1965(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1965, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1967(F, sep, ...) \ + Z_UTIL_LISTIFY_1966(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1966, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1968(F, sep, ...) \ + Z_UTIL_LISTIFY_1967(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1967, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1969(F, sep, ...) \ + Z_UTIL_LISTIFY_1968(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1968, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1970(F, sep, ...) \ + Z_UTIL_LISTIFY_1969(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1969, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1971(F, sep, ...) \ + Z_UTIL_LISTIFY_1970(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1970, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1972(F, sep, ...) \ + Z_UTIL_LISTIFY_1971(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1971, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1973(F, sep, ...) \ + Z_UTIL_LISTIFY_1972(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1972, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1974(F, sep, ...) \ + Z_UTIL_LISTIFY_1973(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1973, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1975(F, sep, ...) \ + Z_UTIL_LISTIFY_1974(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1974, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1976(F, sep, ...) \ + Z_UTIL_LISTIFY_1975(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1975, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1977(F, sep, ...) \ + Z_UTIL_LISTIFY_1976(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1976, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1978(F, sep, ...) \ + Z_UTIL_LISTIFY_1977(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1977, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1979(F, sep, ...) \ + Z_UTIL_LISTIFY_1978(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1978, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1980(F, sep, ...) \ + Z_UTIL_LISTIFY_1979(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1979, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1981(F, sep, ...) \ + Z_UTIL_LISTIFY_1980(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1980, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1982(F, sep, ...) \ + Z_UTIL_LISTIFY_1981(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1981, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1983(F, sep, ...) \ + Z_UTIL_LISTIFY_1982(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1982, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1984(F, sep, ...) \ + Z_UTIL_LISTIFY_1983(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1983, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1985(F, sep, ...) \ + Z_UTIL_LISTIFY_1984(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1984, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1986(F, sep, ...) \ + Z_UTIL_LISTIFY_1985(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1985, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1987(F, sep, ...) \ + Z_UTIL_LISTIFY_1986(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1986, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1988(F, sep, ...) \ + Z_UTIL_LISTIFY_1987(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1987, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1989(F, sep, ...) \ + Z_UTIL_LISTIFY_1988(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1988, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1990(F, sep, ...) \ + Z_UTIL_LISTIFY_1989(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1989, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1991(F, sep, ...) \ + Z_UTIL_LISTIFY_1990(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1990, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1992(F, sep, ...) \ + Z_UTIL_LISTIFY_1991(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1991, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1993(F, sep, ...) \ + Z_UTIL_LISTIFY_1992(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1992, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1994(F, sep, ...) \ + Z_UTIL_LISTIFY_1993(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1993, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1995(F, sep, ...) \ + Z_UTIL_LISTIFY_1994(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1994, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1996(F, sep, ...) \ + Z_UTIL_LISTIFY_1995(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1995, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1997(F, sep, ...) \ + Z_UTIL_LISTIFY_1996(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1996, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1998(F, sep, ...) \ + Z_UTIL_LISTIFY_1997(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1997, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_1999(F, sep, ...) \ + Z_UTIL_LISTIFY_1998(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1998, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2000(F, sep, ...) \ + Z_UTIL_LISTIFY_1999(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(1999, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2001(F, sep, ...) \ + Z_UTIL_LISTIFY_2000(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2000, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2002(F, sep, ...) \ + Z_UTIL_LISTIFY_2001(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2001, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2003(F, sep, ...) \ + Z_UTIL_LISTIFY_2002(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2002, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2004(F, sep, ...) \ + Z_UTIL_LISTIFY_2003(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2003, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2005(F, sep, ...) \ + Z_UTIL_LISTIFY_2004(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2004, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2006(F, sep, ...) \ + Z_UTIL_LISTIFY_2005(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2005, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2007(F, sep, ...) \ + Z_UTIL_LISTIFY_2006(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2006, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2008(F, sep, ...) \ + Z_UTIL_LISTIFY_2007(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2007, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2009(F, sep, ...) \ + Z_UTIL_LISTIFY_2008(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2008, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2010(F, sep, ...) \ + Z_UTIL_LISTIFY_2009(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2009, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2011(F, sep, ...) \ + Z_UTIL_LISTIFY_2010(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2010, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2012(F, sep, ...) \ + Z_UTIL_LISTIFY_2011(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2011, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2013(F, sep, ...) \ + Z_UTIL_LISTIFY_2012(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2012, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2014(F, sep, ...) \ + Z_UTIL_LISTIFY_2013(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2013, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2015(F, sep, ...) \ + Z_UTIL_LISTIFY_2014(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2014, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2016(F, sep, ...) \ + Z_UTIL_LISTIFY_2015(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2015, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2017(F, sep, ...) \ + Z_UTIL_LISTIFY_2016(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2016, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2018(F, sep, ...) \ + Z_UTIL_LISTIFY_2017(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2017, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2019(F, sep, ...) \ + Z_UTIL_LISTIFY_2018(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2018, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2020(F, sep, ...) \ + Z_UTIL_LISTIFY_2019(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2019, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2021(F, sep, ...) \ + Z_UTIL_LISTIFY_2020(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2020, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2022(F, sep, ...) \ + Z_UTIL_LISTIFY_2021(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2021, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2023(F, sep, ...) \ + Z_UTIL_LISTIFY_2022(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2022, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2024(F, sep, ...) \ + Z_UTIL_LISTIFY_2023(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2023, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2025(F, sep, ...) \ + Z_UTIL_LISTIFY_2024(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2024, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2026(F, sep, ...) \ + Z_UTIL_LISTIFY_2025(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2025, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2027(F, sep, ...) \ + Z_UTIL_LISTIFY_2026(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2026, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2028(F, sep, ...) \ + Z_UTIL_LISTIFY_2027(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2027, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2029(F, sep, ...) \ + Z_UTIL_LISTIFY_2028(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2028, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2030(F, sep, ...) \ + Z_UTIL_LISTIFY_2029(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2029, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2031(F, sep, ...) \ + Z_UTIL_LISTIFY_2030(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2030, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2032(F, sep, ...) \ + Z_UTIL_LISTIFY_2031(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2031, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2033(F, sep, ...) \ + Z_UTIL_LISTIFY_2032(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2032, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2034(F, sep, ...) \ + Z_UTIL_LISTIFY_2033(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2033, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2035(F, sep, ...) \ + Z_UTIL_LISTIFY_2034(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2034, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2036(F, sep, ...) \ + Z_UTIL_LISTIFY_2035(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2035, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2037(F, sep, ...) \ + Z_UTIL_LISTIFY_2036(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2036, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2038(F, sep, ...) \ + Z_UTIL_LISTIFY_2037(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2037, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2039(F, sep, ...) \ + Z_UTIL_LISTIFY_2038(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2038, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2040(F, sep, ...) \ + Z_UTIL_LISTIFY_2039(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2039, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2041(F, sep, ...) \ + Z_UTIL_LISTIFY_2040(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2040, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2042(F, sep, ...) \ + Z_UTIL_LISTIFY_2041(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2041, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2043(F, sep, ...) \ + Z_UTIL_LISTIFY_2042(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2042, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2044(F, sep, ...) \ + Z_UTIL_LISTIFY_2043(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2043, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2045(F, sep, ...) \ + Z_UTIL_LISTIFY_2044(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2044, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2046(F, sep, ...) \ + Z_UTIL_LISTIFY_2045(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2045, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2047(F, sep, ...) \ + Z_UTIL_LISTIFY_2046(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2046, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2048(F, sep, ...) \ + Z_UTIL_LISTIFY_2047(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2047, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2049(F, sep, ...) \ + Z_UTIL_LISTIFY_2048(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2048, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2050(F, sep, ...) \ + Z_UTIL_LISTIFY_2049(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2049, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2051(F, sep, ...) \ + Z_UTIL_LISTIFY_2050(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2050, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2052(F, sep, ...) \ + Z_UTIL_LISTIFY_2051(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2051, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2053(F, sep, ...) \ + Z_UTIL_LISTIFY_2052(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2052, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2054(F, sep, ...) \ + Z_UTIL_LISTIFY_2053(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2053, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2055(F, sep, ...) \ + Z_UTIL_LISTIFY_2054(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2054, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2056(F, sep, ...) \ + Z_UTIL_LISTIFY_2055(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2055, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2057(F, sep, ...) \ + Z_UTIL_LISTIFY_2056(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2056, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2058(F, sep, ...) \ + Z_UTIL_LISTIFY_2057(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2057, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2059(F, sep, ...) \ + Z_UTIL_LISTIFY_2058(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2058, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2060(F, sep, ...) \ + Z_UTIL_LISTIFY_2059(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2059, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2061(F, sep, ...) \ + Z_UTIL_LISTIFY_2060(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2060, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2062(F, sep, ...) \ + Z_UTIL_LISTIFY_2061(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2061, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2063(F, sep, ...) \ + Z_UTIL_LISTIFY_2062(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2062, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2064(F, sep, ...) \ + Z_UTIL_LISTIFY_2063(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2063, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2065(F, sep, ...) \ + Z_UTIL_LISTIFY_2064(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2064, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2066(F, sep, ...) \ + Z_UTIL_LISTIFY_2065(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2065, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2067(F, sep, ...) \ + Z_UTIL_LISTIFY_2066(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2066, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2068(F, sep, ...) \ + Z_UTIL_LISTIFY_2067(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2067, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2069(F, sep, ...) \ + Z_UTIL_LISTIFY_2068(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2068, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2070(F, sep, ...) \ + Z_UTIL_LISTIFY_2069(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2069, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2071(F, sep, ...) \ + Z_UTIL_LISTIFY_2070(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2070, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2072(F, sep, ...) \ + Z_UTIL_LISTIFY_2071(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2071, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2073(F, sep, ...) \ + Z_UTIL_LISTIFY_2072(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2072, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2074(F, sep, ...) \ + Z_UTIL_LISTIFY_2073(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2073, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2075(F, sep, ...) \ + Z_UTIL_LISTIFY_2074(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2074, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2076(F, sep, ...) \ + Z_UTIL_LISTIFY_2075(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2075, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2077(F, sep, ...) \ + Z_UTIL_LISTIFY_2076(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2076, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2078(F, sep, ...) \ + Z_UTIL_LISTIFY_2077(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2077, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2079(F, sep, ...) \ + Z_UTIL_LISTIFY_2078(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2078, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2080(F, sep, ...) \ + Z_UTIL_LISTIFY_2079(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2079, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2081(F, sep, ...) \ + Z_UTIL_LISTIFY_2080(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2080, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2082(F, sep, ...) \ + Z_UTIL_LISTIFY_2081(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2081, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2083(F, sep, ...) \ + Z_UTIL_LISTIFY_2082(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2082, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2084(F, sep, ...) \ + Z_UTIL_LISTIFY_2083(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2083, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2085(F, sep, ...) \ + Z_UTIL_LISTIFY_2084(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2084, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2086(F, sep, ...) \ + Z_UTIL_LISTIFY_2085(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2085, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2087(F, sep, ...) \ + Z_UTIL_LISTIFY_2086(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2086, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2088(F, sep, ...) \ + Z_UTIL_LISTIFY_2087(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2087, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2089(F, sep, ...) \ + Z_UTIL_LISTIFY_2088(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2088, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2090(F, sep, ...) \ + Z_UTIL_LISTIFY_2089(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2089, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2091(F, sep, ...) \ + Z_UTIL_LISTIFY_2090(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2090, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2092(F, sep, ...) \ + Z_UTIL_LISTIFY_2091(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2091, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2093(F, sep, ...) \ + Z_UTIL_LISTIFY_2092(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2092, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2094(F, sep, ...) \ + Z_UTIL_LISTIFY_2093(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2093, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2095(F, sep, ...) \ + Z_UTIL_LISTIFY_2094(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2094, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2096(F, sep, ...) \ + Z_UTIL_LISTIFY_2095(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2095, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2097(F, sep, ...) \ + Z_UTIL_LISTIFY_2096(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2096, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2098(F, sep, ...) \ + Z_UTIL_LISTIFY_2097(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2097, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2099(F, sep, ...) \ + Z_UTIL_LISTIFY_2098(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2098, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2100(F, sep, ...) \ + Z_UTIL_LISTIFY_2099(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2099, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2101(F, sep, ...) \ + Z_UTIL_LISTIFY_2100(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2100, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2102(F, sep, ...) \ + Z_UTIL_LISTIFY_2101(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2101, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2103(F, sep, ...) \ + Z_UTIL_LISTIFY_2102(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2102, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2104(F, sep, ...) \ + Z_UTIL_LISTIFY_2103(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2103, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2105(F, sep, ...) \ + Z_UTIL_LISTIFY_2104(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2104, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2106(F, sep, ...) \ + Z_UTIL_LISTIFY_2105(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2105, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2107(F, sep, ...) \ + Z_UTIL_LISTIFY_2106(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2106, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2108(F, sep, ...) \ + Z_UTIL_LISTIFY_2107(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2107, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2109(F, sep, ...) \ + Z_UTIL_LISTIFY_2108(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2108, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2110(F, sep, ...) \ + Z_UTIL_LISTIFY_2109(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2109, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2111(F, sep, ...) \ + Z_UTIL_LISTIFY_2110(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2110, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2112(F, sep, ...) \ + Z_UTIL_LISTIFY_2111(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2111, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2113(F, sep, ...) \ + Z_UTIL_LISTIFY_2112(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2112, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2114(F, sep, ...) \ + Z_UTIL_LISTIFY_2113(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2113, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2115(F, sep, ...) \ + Z_UTIL_LISTIFY_2114(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2114, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2116(F, sep, ...) \ + Z_UTIL_LISTIFY_2115(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2115, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2117(F, sep, ...) \ + Z_UTIL_LISTIFY_2116(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2116, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2118(F, sep, ...) \ + Z_UTIL_LISTIFY_2117(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2117, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2119(F, sep, ...) \ + Z_UTIL_LISTIFY_2118(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2118, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2120(F, sep, ...) \ + Z_UTIL_LISTIFY_2119(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2119, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2121(F, sep, ...) \ + Z_UTIL_LISTIFY_2120(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2120, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2122(F, sep, ...) \ + Z_UTIL_LISTIFY_2121(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2121, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2123(F, sep, ...) \ + Z_UTIL_LISTIFY_2122(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2122, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2124(F, sep, ...) \ + Z_UTIL_LISTIFY_2123(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2123, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2125(F, sep, ...) \ + Z_UTIL_LISTIFY_2124(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2124, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2126(F, sep, ...) \ + Z_UTIL_LISTIFY_2125(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2125, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2127(F, sep, ...) \ + Z_UTIL_LISTIFY_2126(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2126, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2128(F, sep, ...) \ + Z_UTIL_LISTIFY_2127(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2127, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2129(F, sep, ...) \ + Z_UTIL_LISTIFY_2128(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2128, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2130(F, sep, ...) \ + Z_UTIL_LISTIFY_2129(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2129, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2131(F, sep, ...) \ + Z_UTIL_LISTIFY_2130(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2130, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2132(F, sep, ...) \ + Z_UTIL_LISTIFY_2131(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2131, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2133(F, sep, ...) \ + Z_UTIL_LISTIFY_2132(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2132, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2134(F, sep, ...) \ + Z_UTIL_LISTIFY_2133(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2133, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2135(F, sep, ...) \ + Z_UTIL_LISTIFY_2134(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2134, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2136(F, sep, ...) \ + Z_UTIL_LISTIFY_2135(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2135, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2137(F, sep, ...) \ + Z_UTIL_LISTIFY_2136(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2136, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2138(F, sep, ...) \ + Z_UTIL_LISTIFY_2137(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2137, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2139(F, sep, ...) \ + Z_UTIL_LISTIFY_2138(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2138, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2140(F, sep, ...) \ + Z_UTIL_LISTIFY_2139(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2139, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2141(F, sep, ...) \ + Z_UTIL_LISTIFY_2140(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2140, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2142(F, sep, ...) \ + Z_UTIL_LISTIFY_2141(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2141, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2143(F, sep, ...) \ + Z_UTIL_LISTIFY_2142(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2142, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2144(F, sep, ...) \ + Z_UTIL_LISTIFY_2143(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2143, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2145(F, sep, ...) \ + Z_UTIL_LISTIFY_2144(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2144, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2146(F, sep, ...) \ + Z_UTIL_LISTIFY_2145(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2145, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2147(F, sep, ...) \ + Z_UTIL_LISTIFY_2146(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2146, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2148(F, sep, ...) \ + Z_UTIL_LISTIFY_2147(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2147, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2149(F, sep, ...) \ + Z_UTIL_LISTIFY_2148(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2148, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2150(F, sep, ...) \ + Z_UTIL_LISTIFY_2149(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2149, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2151(F, sep, ...) \ + Z_UTIL_LISTIFY_2150(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2150, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2152(F, sep, ...) \ + Z_UTIL_LISTIFY_2151(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2151, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2153(F, sep, ...) \ + Z_UTIL_LISTIFY_2152(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2152, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2154(F, sep, ...) \ + Z_UTIL_LISTIFY_2153(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2153, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2155(F, sep, ...) \ + Z_UTIL_LISTIFY_2154(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2154, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2156(F, sep, ...) \ + Z_UTIL_LISTIFY_2155(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2155, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2157(F, sep, ...) \ + Z_UTIL_LISTIFY_2156(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2156, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2158(F, sep, ...) \ + Z_UTIL_LISTIFY_2157(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2157, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2159(F, sep, ...) \ + Z_UTIL_LISTIFY_2158(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2158, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2160(F, sep, ...) \ + Z_UTIL_LISTIFY_2159(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2159, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2161(F, sep, ...) \ + Z_UTIL_LISTIFY_2160(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2160, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2162(F, sep, ...) \ + Z_UTIL_LISTIFY_2161(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2161, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2163(F, sep, ...) \ + Z_UTIL_LISTIFY_2162(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2162, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2164(F, sep, ...) \ + Z_UTIL_LISTIFY_2163(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2163, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2165(F, sep, ...) \ + Z_UTIL_LISTIFY_2164(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2164, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2166(F, sep, ...) \ + Z_UTIL_LISTIFY_2165(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2165, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2167(F, sep, ...) \ + Z_UTIL_LISTIFY_2166(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2166, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2168(F, sep, ...) \ + Z_UTIL_LISTIFY_2167(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2167, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2169(F, sep, ...) \ + Z_UTIL_LISTIFY_2168(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2168, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2170(F, sep, ...) \ + Z_UTIL_LISTIFY_2169(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2169, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2171(F, sep, ...) \ + Z_UTIL_LISTIFY_2170(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2170, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2172(F, sep, ...) \ + Z_UTIL_LISTIFY_2171(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2171, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2173(F, sep, ...) \ + Z_UTIL_LISTIFY_2172(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2172, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2174(F, sep, ...) \ + Z_UTIL_LISTIFY_2173(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2173, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2175(F, sep, ...) \ + Z_UTIL_LISTIFY_2174(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2174, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2176(F, sep, ...) \ + Z_UTIL_LISTIFY_2175(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2175, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2177(F, sep, ...) \ + Z_UTIL_LISTIFY_2176(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2176, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2178(F, sep, ...) \ + Z_UTIL_LISTIFY_2177(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2177, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2179(F, sep, ...) \ + Z_UTIL_LISTIFY_2178(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2178, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2180(F, sep, ...) \ + Z_UTIL_LISTIFY_2179(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2179, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2181(F, sep, ...) \ + Z_UTIL_LISTIFY_2180(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2180, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2182(F, sep, ...) \ + Z_UTIL_LISTIFY_2181(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2181, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2183(F, sep, ...) \ + Z_UTIL_LISTIFY_2182(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2182, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2184(F, sep, ...) \ + Z_UTIL_LISTIFY_2183(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2183, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2185(F, sep, ...) \ + Z_UTIL_LISTIFY_2184(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2184, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2186(F, sep, ...) \ + Z_UTIL_LISTIFY_2185(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2185, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2187(F, sep, ...) \ + Z_UTIL_LISTIFY_2186(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2186, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2188(F, sep, ...) \ + Z_UTIL_LISTIFY_2187(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2187, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2189(F, sep, ...) \ + Z_UTIL_LISTIFY_2188(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2188, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2190(F, sep, ...) \ + Z_UTIL_LISTIFY_2189(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2189, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2191(F, sep, ...) \ + Z_UTIL_LISTIFY_2190(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2190, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2192(F, sep, ...) \ + Z_UTIL_LISTIFY_2191(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2191, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2193(F, sep, ...) \ + Z_UTIL_LISTIFY_2192(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2192, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2194(F, sep, ...) \ + Z_UTIL_LISTIFY_2193(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2193, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2195(F, sep, ...) \ + Z_UTIL_LISTIFY_2194(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2194, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2196(F, sep, ...) \ + Z_UTIL_LISTIFY_2195(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2195, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2197(F, sep, ...) \ + Z_UTIL_LISTIFY_2196(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2196, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2198(F, sep, ...) \ + Z_UTIL_LISTIFY_2197(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2197, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2199(F, sep, ...) \ + Z_UTIL_LISTIFY_2198(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2198, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2200(F, sep, ...) \ + Z_UTIL_LISTIFY_2199(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2199, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2201(F, sep, ...) \ + Z_UTIL_LISTIFY_2200(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2200, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2202(F, sep, ...) \ + Z_UTIL_LISTIFY_2201(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2201, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2203(F, sep, ...) \ + Z_UTIL_LISTIFY_2202(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2202, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2204(F, sep, ...) \ + Z_UTIL_LISTIFY_2203(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2203, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2205(F, sep, ...) \ + Z_UTIL_LISTIFY_2204(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2204, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2206(F, sep, ...) \ + Z_UTIL_LISTIFY_2205(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2205, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2207(F, sep, ...) \ + Z_UTIL_LISTIFY_2206(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2206, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2208(F, sep, ...) \ + Z_UTIL_LISTIFY_2207(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2207, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2209(F, sep, ...) \ + Z_UTIL_LISTIFY_2208(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2208, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2210(F, sep, ...) \ + Z_UTIL_LISTIFY_2209(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2209, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2211(F, sep, ...) \ + Z_UTIL_LISTIFY_2210(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2210, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2212(F, sep, ...) \ + Z_UTIL_LISTIFY_2211(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2211, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2213(F, sep, ...) \ + Z_UTIL_LISTIFY_2212(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2212, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2214(F, sep, ...) \ + Z_UTIL_LISTIFY_2213(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2213, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2215(F, sep, ...) \ + Z_UTIL_LISTIFY_2214(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2214, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2216(F, sep, ...) \ + Z_UTIL_LISTIFY_2215(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2215, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2217(F, sep, ...) \ + Z_UTIL_LISTIFY_2216(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2216, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2218(F, sep, ...) \ + Z_UTIL_LISTIFY_2217(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2217, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2219(F, sep, ...) \ + Z_UTIL_LISTIFY_2218(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2218, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2220(F, sep, ...) \ + Z_UTIL_LISTIFY_2219(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2219, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2221(F, sep, ...) \ + Z_UTIL_LISTIFY_2220(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2220, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2222(F, sep, ...) \ + Z_UTIL_LISTIFY_2221(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2221, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2223(F, sep, ...) \ + Z_UTIL_LISTIFY_2222(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2222, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2224(F, sep, ...) \ + Z_UTIL_LISTIFY_2223(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2223, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2225(F, sep, ...) \ + Z_UTIL_LISTIFY_2224(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2224, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2226(F, sep, ...) \ + Z_UTIL_LISTIFY_2225(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2225, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2227(F, sep, ...) \ + Z_UTIL_LISTIFY_2226(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2226, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2228(F, sep, ...) \ + Z_UTIL_LISTIFY_2227(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2227, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2229(F, sep, ...) \ + Z_UTIL_LISTIFY_2228(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2228, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2230(F, sep, ...) \ + Z_UTIL_LISTIFY_2229(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2229, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2231(F, sep, ...) \ + Z_UTIL_LISTIFY_2230(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2230, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2232(F, sep, ...) \ + Z_UTIL_LISTIFY_2231(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2231, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2233(F, sep, ...) \ + Z_UTIL_LISTIFY_2232(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2232, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2234(F, sep, ...) \ + Z_UTIL_LISTIFY_2233(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2233, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2235(F, sep, ...) \ + Z_UTIL_LISTIFY_2234(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2234, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2236(F, sep, ...) \ + Z_UTIL_LISTIFY_2235(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2235, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2237(F, sep, ...) \ + Z_UTIL_LISTIFY_2236(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2236, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2238(F, sep, ...) \ + Z_UTIL_LISTIFY_2237(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2237, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2239(F, sep, ...) \ + Z_UTIL_LISTIFY_2238(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2238, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2240(F, sep, ...) \ + Z_UTIL_LISTIFY_2239(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2239, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2241(F, sep, ...) \ + Z_UTIL_LISTIFY_2240(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2240, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2242(F, sep, ...) \ + Z_UTIL_LISTIFY_2241(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2241, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2243(F, sep, ...) \ + Z_UTIL_LISTIFY_2242(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2242, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2244(F, sep, ...) \ + Z_UTIL_LISTIFY_2243(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2243, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2245(F, sep, ...) \ + Z_UTIL_LISTIFY_2244(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2244, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2246(F, sep, ...) \ + Z_UTIL_LISTIFY_2245(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2245, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2247(F, sep, ...) \ + Z_UTIL_LISTIFY_2246(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2246, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2248(F, sep, ...) \ + Z_UTIL_LISTIFY_2247(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2247, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2249(F, sep, ...) \ + Z_UTIL_LISTIFY_2248(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2248, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2250(F, sep, ...) \ + Z_UTIL_LISTIFY_2249(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2249, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2251(F, sep, ...) \ + Z_UTIL_LISTIFY_2250(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2250, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2252(F, sep, ...) \ + Z_UTIL_LISTIFY_2251(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2251, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2253(F, sep, ...) \ + Z_UTIL_LISTIFY_2252(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2252, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2254(F, sep, ...) \ + Z_UTIL_LISTIFY_2253(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2253, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2255(F, sep, ...) \ + Z_UTIL_LISTIFY_2254(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2254, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2256(F, sep, ...) \ + Z_UTIL_LISTIFY_2255(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2255, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2257(F, sep, ...) \ + Z_UTIL_LISTIFY_2256(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2256, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2258(F, sep, ...) \ + Z_UTIL_LISTIFY_2257(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2257, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2259(F, sep, ...) \ + Z_UTIL_LISTIFY_2258(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2258, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2260(F, sep, ...) \ + Z_UTIL_LISTIFY_2259(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2259, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2261(F, sep, ...) \ + Z_UTIL_LISTIFY_2260(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2260, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2262(F, sep, ...) \ + Z_UTIL_LISTIFY_2261(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2261, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2263(F, sep, ...) \ + Z_UTIL_LISTIFY_2262(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2262, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2264(F, sep, ...) \ + Z_UTIL_LISTIFY_2263(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2263, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2265(F, sep, ...) \ + Z_UTIL_LISTIFY_2264(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2264, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2266(F, sep, ...) \ + Z_UTIL_LISTIFY_2265(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2265, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2267(F, sep, ...) \ + Z_UTIL_LISTIFY_2266(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2266, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2268(F, sep, ...) \ + Z_UTIL_LISTIFY_2267(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2267, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2269(F, sep, ...) \ + Z_UTIL_LISTIFY_2268(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2268, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2270(F, sep, ...) \ + Z_UTIL_LISTIFY_2269(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2269, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2271(F, sep, ...) \ + Z_UTIL_LISTIFY_2270(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2270, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2272(F, sep, ...) \ + Z_UTIL_LISTIFY_2271(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2271, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2273(F, sep, ...) \ + Z_UTIL_LISTIFY_2272(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2272, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2274(F, sep, ...) \ + Z_UTIL_LISTIFY_2273(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2273, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2275(F, sep, ...) \ + Z_UTIL_LISTIFY_2274(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2274, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2276(F, sep, ...) \ + Z_UTIL_LISTIFY_2275(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2275, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2277(F, sep, ...) \ + Z_UTIL_LISTIFY_2276(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2276, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2278(F, sep, ...) \ + Z_UTIL_LISTIFY_2277(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2277, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2279(F, sep, ...) \ + Z_UTIL_LISTIFY_2278(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2278, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2280(F, sep, ...) \ + Z_UTIL_LISTIFY_2279(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2279, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2281(F, sep, ...) \ + Z_UTIL_LISTIFY_2280(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2280, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2282(F, sep, ...) \ + Z_UTIL_LISTIFY_2281(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2281, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2283(F, sep, ...) \ + Z_UTIL_LISTIFY_2282(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2282, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2284(F, sep, ...) \ + Z_UTIL_LISTIFY_2283(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2283, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2285(F, sep, ...) \ + Z_UTIL_LISTIFY_2284(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2284, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2286(F, sep, ...) \ + Z_UTIL_LISTIFY_2285(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2285, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2287(F, sep, ...) \ + Z_UTIL_LISTIFY_2286(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2286, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2288(F, sep, ...) \ + Z_UTIL_LISTIFY_2287(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2287, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2289(F, sep, ...) \ + Z_UTIL_LISTIFY_2288(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2288, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2290(F, sep, ...) \ + Z_UTIL_LISTIFY_2289(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2289, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2291(F, sep, ...) \ + Z_UTIL_LISTIFY_2290(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2290, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2292(F, sep, ...) \ + Z_UTIL_LISTIFY_2291(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2291, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2293(F, sep, ...) \ + Z_UTIL_LISTIFY_2292(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2292, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2294(F, sep, ...) \ + Z_UTIL_LISTIFY_2293(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2293, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2295(F, sep, ...) \ + Z_UTIL_LISTIFY_2294(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2294, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2296(F, sep, ...) \ + Z_UTIL_LISTIFY_2295(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2295, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2297(F, sep, ...) \ + Z_UTIL_LISTIFY_2296(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2296, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2298(F, sep, ...) \ + Z_UTIL_LISTIFY_2297(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2297, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2299(F, sep, ...) \ + Z_UTIL_LISTIFY_2298(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2298, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2300(F, sep, ...) \ + Z_UTIL_LISTIFY_2299(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2299, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2301(F, sep, ...) \ + Z_UTIL_LISTIFY_2300(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2300, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2302(F, sep, ...) \ + Z_UTIL_LISTIFY_2301(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2301, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2303(F, sep, ...) \ + Z_UTIL_LISTIFY_2302(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2302, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2304(F, sep, ...) \ + Z_UTIL_LISTIFY_2303(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2303, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2305(F, sep, ...) \ + Z_UTIL_LISTIFY_2304(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2304, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2306(F, sep, ...) \ + Z_UTIL_LISTIFY_2305(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2305, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2307(F, sep, ...) \ + Z_UTIL_LISTIFY_2306(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2306, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2308(F, sep, ...) \ + Z_UTIL_LISTIFY_2307(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2307, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2309(F, sep, ...) \ + Z_UTIL_LISTIFY_2308(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2308, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2310(F, sep, ...) \ + Z_UTIL_LISTIFY_2309(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2309, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2311(F, sep, ...) \ + Z_UTIL_LISTIFY_2310(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2310, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2312(F, sep, ...) \ + Z_UTIL_LISTIFY_2311(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2311, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2313(F, sep, ...) \ + Z_UTIL_LISTIFY_2312(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2312, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2314(F, sep, ...) \ + Z_UTIL_LISTIFY_2313(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2313, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2315(F, sep, ...) \ + Z_UTIL_LISTIFY_2314(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2314, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2316(F, sep, ...) \ + Z_UTIL_LISTIFY_2315(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2315, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2317(F, sep, ...) \ + Z_UTIL_LISTIFY_2316(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2316, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2318(F, sep, ...) \ + Z_UTIL_LISTIFY_2317(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2317, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2319(F, sep, ...) \ + Z_UTIL_LISTIFY_2318(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2318, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2320(F, sep, ...) \ + Z_UTIL_LISTIFY_2319(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2319, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2321(F, sep, ...) \ + Z_UTIL_LISTIFY_2320(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2320, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2322(F, sep, ...) \ + Z_UTIL_LISTIFY_2321(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2321, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2323(F, sep, ...) \ + Z_UTIL_LISTIFY_2322(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2322, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2324(F, sep, ...) \ + Z_UTIL_LISTIFY_2323(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2323, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2325(F, sep, ...) \ + Z_UTIL_LISTIFY_2324(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2324, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2326(F, sep, ...) \ + Z_UTIL_LISTIFY_2325(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2325, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2327(F, sep, ...) \ + Z_UTIL_LISTIFY_2326(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2326, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2328(F, sep, ...) \ + Z_UTIL_LISTIFY_2327(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2327, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2329(F, sep, ...) \ + Z_UTIL_LISTIFY_2328(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2328, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2330(F, sep, ...) \ + Z_UTIL_LISTIFY_2329(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2329, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2331(F, sep, ...) \ + Z_UTIL_LISTIFY_2330(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2330, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2332(F, sep, ...) \ + Z_UTIL_LISTIFY_2331(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2331, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2333(F, sep, ...) \ + Z_UTIL_LISTIFY_2332(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2332, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2334(F, sep, ...) \ + Z_UTIL_LISTIFY_2333(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2333, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2335(F, sep, ...) \ + Z_UTIL_LISTIFY_2334(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2334, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2336(F, sep, ...) \ + Z_UTIL_LISTIFY_2335(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2335, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2337(F, sep, ...) \ + Z_UTIL_LISTIFY_2336(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2336, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2338(F, sep, ...) \ + Z_UTIL_LISTIFY_2337(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2337, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2339(F, sep, ...) \ + Z_UTIL_LISTIFY_2338(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2338, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2340(F, sep, ...) \ + Z_UTIL_LISTIFY_2339(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2339, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2341(F, sep, ...) \ + Z_UTIL_LISTIFY_2340(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2340, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2342(F, sep, ...) \ + Z_UTIL_LISTIFY_2341(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2341, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2343(F, sep, ...) \ + Z_UTIL_LISTIFY_2342(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2342, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2344(F, sep, ...) \ + Z_UTIL_LISTIFY_2343(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2343, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2345(F, sep, ...) \ + Z_UTIL_LISTIFY_2344(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2344, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2346(F, sep, ...) \ + Z_UTIL_LISTIFY_2345(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2345, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2347(F, sep, ...) \ + Z_UTIL_LISTIFY_2346(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2346, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2348(F, sep, ...) \ + Z_UTIL_LISTIFY_2347(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2347, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2349(F, sep, ...) \ + Z_UTIL_LISTIFY_2348(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2348, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2350(F, sep, ...) \ + Z_UTIL_LISTIFY_2349(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2349, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2351(F, sep, ...) \ + Z_UTIL_LISTIFY_2350(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2350, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2352(F, sep, ...) \ + Z_UTIL_LISTIFY_2351(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2351, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2353(F, sep, ...) \ + Z_UTIL_LISTIFY_2352(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2352, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2354(F, sep, ...) \ + Z_UTIL_LISTIFY_2353(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2353, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2355(F, sep, ...) \ + Z_UTIL_LISTIFY_2354(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2354, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2356(F, sep, ...) \ + Z_UTIL_LISTIFY_2355(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2355, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2357(F, sep, ...) \ + Z_UTIL_LISTIFY_2356(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2356, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2358(F, sep, ...) \ + Z_UTIL_LISTIFY_2357(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2357, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2359(F, sep, ...) \ + Z_UTIL_LISTIFY_2358(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2358, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2360(F, sep, ...) \ + Z_UTIL_LISTIFY_2359(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2359, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2361(F, sep, ...) \ + Z_UTIL_LISTIFY_2360(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2360, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2362(F, sep, ...) \ + Z_UTIL_LISTIFY_2361(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2361, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2363(F, sep, ...) \ + Z_UTIL_LISTIFY_2362(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2362, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2364(F, sep, ...) \ + Z_UTIL_LISTIFY_2363(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2363, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2365(F, sep, ...) \ + Z_UTIL_LISTIFY_2364(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2364, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2366(F, sep, ...) \ + Z_UTIL_LISTIFY_2365(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2365, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2367(F, sep, ...) \ + Z_UTIL_LISTIFY_2366(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2366, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2368(F, sep, ...) \ + Z_UTIL_LISTIFY_2367(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2367, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2369(F, sep, ...) \ + Z_UTIL_LISTIFY_2368(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2368, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2370(F, sep, ...) \ + Z_UTIL_LISTIFY_2369(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2369, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2371(F, sep, ...) \ + Z_UTIL_LISTIFY_2370(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2370, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2372(F, sep, ...) \ + Z_UTIL_LISTIFY_2371(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2371, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2373(F, sep, ...) \ + Z_UTIL_LISTIFY_2372(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2372, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2374(F, sep, ...) \ + Z_UTIL_LISTIFY_2373(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2373, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2375(F, sep, ...) \ + Z_UTIL_LISTIFY_2374(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2374, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2376(F, sep, ...) \ + Z_UTIL_LISTIFY_2375(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2375, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2377(F, sep, ...) \ + Z_UTIL_LISTIFY_2376(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2376, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2378(F, sep, ...) \ + Z_UTIL_LISTIFY_2377(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2377, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2379(F, sep, ...) \ + Z_UTIL_LISTIFY_2378(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2378, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2380(F, sep, ...) \ + Z_UTIL_LISTIFY_2379(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2379, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2381(F, sep, ...) \ + Z_UTIL_LISTIFY_2380(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2380, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2382(F, sep, ...) \ + Z_UTIL_LISTIFY_2381(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2381, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2383(F, sep, ...) \ + Z_UTIL_LISTIFY_2382(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2382, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2384(F, sep, ...) \ + Z_UTIL_LISTIFY_2383(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2383, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2385(F, sep, ...) \ + Z_UTIL_LISTIFY_2384(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2384, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2386(F, sep, ...) \ + Z_UTIL_LISTIFY_2385(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2385, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2387(F, sep, ...) \ + Z_UTIL_LISTIFY_2386(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2386, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2388(F, sep, ...) \ + Z_UTIL_LISTIFY_2387(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2387, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2389(F, sep, ...) \ + Z_UTIL_LISTIFY_2388(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2388, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2390(F, sep, ...) \ + Z_UTIL_LISTIFY_2389(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2389, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2391(F, sep, ...) \ + Z_UTIL_LISTIFY_2390(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2390, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2392(F, sep, ...) \ + Z_UTIL_LISTIFY_2391(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2391, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2393(F, sep, ...) \ + Z_UTIL_LISTIFY_2392(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2392, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2394(F, sep, ...) \ + Z_UTIL_LISTIFY_2393(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2393, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2395(F, sep, ...) \ + Z_UTIL_LISTIFY_2394(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2394, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2396(F, sep, ...) \ + Z_UTIL_LISTIFY_2395(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2395, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2397(F, sep, ...) \ + Z_UTIL_LISTIFY_2396(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2396, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2398(F, sep, ...) \ + Z_UTIL_LISTIFY_2397(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2397, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2399(F, sep, ...) \ + Z_UTIL_LISTIFY_2398(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2398, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2400(F, sep, ...) \ + Z_UTIL_LISTIFY_2399(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2399, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2401(F, sep, ...) \ + Z_UTIL_LISTIFY_2400(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2400, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2402(F, sep, ...) \ + Z_UTIL_LISTIFY_2401(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2401, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2403(F, sep, ...) \ + Z_UTIL_LISTIFY_2402(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2402, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2404(F, sep, ...) \ + Z_UTIL_LISTIFY_2403(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2403, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2405(F, sep, ...) \ + Z_UTIL_LISTIFY_2404(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2404, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2406(F, sep, ...) \ + Z_UTIL_LISTIFY_2405(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2405, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2407(F, sep, ...) \ + Z_UTIL_LISTIFY_2406(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2406, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2408(F, sep, ...) \ + Z_UTIL_LISTIFY_2407(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2407, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2409(F, sep, ...) \ + Z_UTIL_LISTIFY_2408(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2408, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2410(F, sep, ...) \ + Z_UTIL_LISTIFY_2409(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2409, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2411(F, sep, ...) \ + Z_UTIL_LISTIFY_2410(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2410, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2412(F, sep, ...) \ + Z_UTIL_LISTIFY_2411(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2411, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2413(F, sep, ...) \ + Z_UTIL_LISTIFY_2412(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2412, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2414(F, sep, ...) \ + Z_UTIL_LISTIFY_2413(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2413, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2415(F, sep, ...) \ + Z_UTIL_LISTIFY_2414(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2414, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2416(F, sep, ...) \ + Z_UTIL_LISTIFY_2415(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2415, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2417(F, sep, ...) \ + Z_UTIL_LISTIFY_2416(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2416, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2418(F, sep, ...) \ + Z_UTIL_LISTIFY_2417(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2417, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2419(F, sep, ...) \ + Z_UTIL_LISTIFY_2418(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2418, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2420(F, sep, ...) \ + Z_UTIL_LISTIFY_2419(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2419, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2421(F, sep, ...) \ + Z_UTIL_LISTIFY_2420(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2420, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2422(F, sep, ...) \ + Z_UTIL_LISTIFY_2421(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2421, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2423(F, sep, ...) \ + Z_UTIL_LISTIFY_2422(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2422, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2424(F, sep, ...) \ + Z_UTIL_LISTIFY_2423(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2423, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2425(F, sep, ...) \ + Z_UTIL_LISTIFY_2424(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2424, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2426(F, sep, ...) \ + Z_UTIL_LISTIFY_2425(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2425, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2427(F, sep, ...) \ + Z_UTIL_LISTIFY_2426(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2426, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2428(F, sep, ...) \ + Z_UTIL_LISTIFY_2427(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2427, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2429(F, sep, ...) \ + Z_UTIL_LISTIFY_2428(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2428, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2430(F, sep, ...) \ + Z_UTIL_LISTIFY_2429(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2429, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2431(F, sep, ...) \ + Z_UTIL_LISTIFY_2430(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2430, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2432(F, sep, ...) \ + Z_UTIL_LISTIFY_2431(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2431, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2433(F, sep, ...) \ + Z_UTIL_LISTIFY_2432(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2432, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2434(F, sep, ...) \ + Z_UTIL_LISTIFY_2433(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2433, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2435(F, sep, ...) \ + Z_UTIL_LISTIFY_2434(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2434, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2436(F, sep, ...) \ + Z_UTIL_LISTIFY_2435(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2435, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2437(F, sep, ...) \ + Z_UTIL_LISTIFY_2436(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2436, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2438(F, sep, ...) \ + Z_UTIL_LISTIFY_2437(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2437, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2439(F, sep, ...) \ + Z_UTIL_LISTIFY_2438(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2438, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2440(F, sep, ...) \ + Z_UTIL_LISTIFY_2439(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2439, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2441(F, sep, ...) \ + Z_UTIL_LISTIFY_2440(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2440, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2442(F, sep, ...) \ + Z_UTIL_LISTIFY_2441(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2441, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2443(F, sep, ...) \ + Z_UTIL_LISTIFY_2442(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2442, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2444(F, sep, ...) \ + Z_UTIL_LISTIFY_2443(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2443, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2445(F, sep, ...) \ + Z_UTIL_LISTIFY_2444(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2444, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2446(F, sep, ...) \ + Z_UTIL_LISTIFY_2445(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2445, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2447(F, sep, ...) \ + Z_UTIL_LISTIFY_2446(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2446, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2448(F, sep, ...) \ + Z_UTIL_LISTIFY_2447(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2447, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2449(F, sep, ...) \ + Z_UTIL_LISTIFY_2448(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2448, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2450(F, sep, ...) \ + Z_UTIL_LISTIFY_2449(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2449, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2451(F, sep, ...) \ + Z_UTIL_LISTIFY_2450(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2450, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2452(F, sep, ...) \ + Z_UTIL_LISTIFY_2451(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2451, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2453(F, sep, ...) \ + Z_UTIL_LISTIFY_2452(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2452, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2454(F, sep, ...) \ + Z_UTIL_LISTIFY_2453(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2453, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2455(F, sep, ...) \ + Z_UTIL_LISTIFY_2454(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2454, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2456(F, sep, ...) \ + Z_UTIL_LISTIFY_2455(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2455, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2457(F, sep, ...) \ + Z_UTIL_LISTIFY_2456(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2456, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2458(F, sep, ...) \ + Z_UTIL_LISTIFY_2457(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2457, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2459(F, sep, ...) \ + Z_UTIL_LISTIFY_2458(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2458, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2460(F, sep, ...) \ + Z_UTIL_LISTIFY_2459(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2459, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2461(F, sep, ...) \ + Z_UTIL_LISTIFY_2460(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2460, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2462(F, sep, ...) \ + Z_UTIL_LISTIFY_2461(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2461, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2463(F, sep, ...) \ + Z_UTIL_LISTIFY_2462(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2462, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2464(F, sep, ...) \ + Z_UTIL_LISTIFY_2463(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2463, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2465(F, sep, ...) \ + Z_UTIL_LISTIFY_2464(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2464, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2466(F, sep, ...) \ + Z_UTIL_LISTIFY_2465(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2465, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2467(F, sep, ...) \ + Z_UTIL_LISTIFY_2466(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2466, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2468(F, sep, ...) \ + Z_UTIL_LISTIFY_2467(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2467, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2469(F, sep, ...) \ + Z_UTIL_LISTIFY_2468(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2468, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2470(F, sep, ...) \ + Z_UTIL_LISTIFY_2469(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2469, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2471(F, sep, ...) \ + Z_UTIL_LISTIFY_2470(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2470, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2472(F, sep, ...) \ + Z_UTIL_LISTIFY_2471(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2471, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2473(F, sep, ...) \ + Z_UTIL_LISTIFY_2472(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2472, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2474(F, sep, ...) \ + Z_UTIL_LISTIFY_2473(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2473, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2475(F, sep, ...) \ + Z_UTIL_LISTIFY_2474(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2474, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2476(F, sep, ...) \ + Z_UTIL_LISTIFY_2475(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2475, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2477(F, sep, ...) \ + Z_UTIL_LISTIFY_2476(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2476, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2478(F, sep, ...) \ + Z_UTIL_LISTIFY_2477(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2477, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2479(F, sep, ...) \ + Z_UTIL_LISTIFY_2478(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2478, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2480(F, sep, ...) \ + Z_UTIL_LISTIFY_2479(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2479, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2481(F, sep, ...) \ + Z_UTIL_LISTIFY_2480(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2480, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2482(F, sep, ...) \ + Z_UTIL_LISTIFY_2481(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2481, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2483(F, sep, ...) \ + Z_UTIL_LISTIFY_2482(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2482, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2484(F, sep, ...) \ + Z_UTIL_LISTIFY_2483(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2483, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2485(F, sep, ...) \ + Z_UTIL_LISTIFY_2484(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2484, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2486(F, sep, ...) \ + Z_UTIL_LISTIFY_2485(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2485, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2487(F, sep, ...) \ + Z_UTIL_LISTIFY_2486(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2486, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2488(F, sep, ...) \ + Z_UTIL_LISTIFY_2487(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2487, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2489(F, sep, ...) \ + Z_UTIL_LISTIFY_2488(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2488, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2490(F, sep, ...) \ + Z_UTIL_LISTIFY_2489(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2489, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2491(F, sep, ...) \ + Z_UTIL_LISTIFY_2490(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2490, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2492(F, sep, ...) \ + Z_UTIL_LISTIFY_2491(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2491, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2493(F, sep, ...) \ + Z_UTIL_LISTIFY_2492(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2492, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2494(F, sep, ...) \ + Z_UTIL_LISTIFY_2493(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2493, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2495(F, sep, ...) \ + Z_UTIL_LISTIFY_2494(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2494, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2496(F, sep, ...) \ + Z_UTIL_LISTIFY_2495(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2495, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2497(F, sep, ...) \ + Z_UTIL_LISTIFY_2496(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2496, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2498(F, sep, ...) \ + Z_UTIL_LISTIFY_2497(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2497, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2499(F, sep, ...) \ + Z_UTIL_LISTIFY_2498(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2498, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2500(F, sep, ...) \ + Z_UTIL_LISTIFY_2499(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2499, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2501(F, sep, ...) \ + Z_UTIL_LISTIFY_2500(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2500, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2502(F, sep, ...) \ + Z_UTIL_LISTIFY_2501(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2501, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2503(F, sep, ...) \ + Z_UTIL_LISTIFY_2502(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2502, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2504(F, sep, ...) \ + Z_UTIL_LISTIFY_2503(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2503, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2505(F, sep, ...) \ + Z_UTIL_LISTIFY_2504(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2504, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2506(F, sep, ...) \ + Z_UTIL_LISTIFY_2505(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2505, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2507(F, sep, ...) \ + Z_UTIL_LISTIFY_2506(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2506, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2508(F, sep, ...) \ + Z_UTIL_LISTIFY_2507(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2507, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2509(F, sep, ...) \ + Z_UTIL_LISTIFY_2508(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2508, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2510(F, sep, ...) \ + Z_UTIL_LISTIFY_2509(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2509, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2511(F, sep, ...) \ + Z_UTIL_LISTIFY_2510(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2510, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2512(F, sep, ...) \ + Z_UTIL_LISTIFY_2511(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2511, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2513(F, sep, ...) \ + Z_UTIL_LISTIFY_2512(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2512, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2514(F, sep, ...) \ + Z_UTIL_LISTIFY_2513(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2513, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2515(F, sep, ...) \ + Z_UTIL_LISTIFY_2514(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2514, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2516(F, sep, ...) \ + Z_UTIL_LISTIFY_2515(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2515, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2517(F, sep, ...) \ + Z_UTIL_LISTIFY_2516(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2516, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2518(F, sep, ...) \ + Z_UTIL_LISTIFY_2517(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2517, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2519(F, sep, ...) \ + Z_UTIL_LISTIFY_2518(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2518, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2520(F, sep, ...) \ + Z_UTIL_LISTIFY_2519(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2519, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2521(F, sep, ...) \ + Z_UTIL_LISTIFY_2520(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2520, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2522(F, sep, ...) \ + Z_UTIL_LISTIFY_2521(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2521, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2523(F, sep, ...) \ + Z_UTIL_LISTIFY_2522(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2522, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2524(F, sep, ...) \ + Z_UTIL_LISTIFY_2523(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2523, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2525(F, sep, ...) \ + Z_UTIL_LISTIFY_2524(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2524, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2526(F, sep, ...) \ + Z_UTIL_LISTIFY_2525(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2525, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2527(F, sep, ...) \ + Z_UTIL_LISTIFY_2526(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2526, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2528(F, sep, ...) \ + Z_UTIL_LISTIFY_2527(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2527, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2529(F, sep, ...) \ + Z_UTIL_LISTIFY_2528(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2528, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2530(F, sep, ...) \ + Z_UTIL_LISTIFY_2529(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2529, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2531(F, sep, ...) \ + Z_UTIL_LISTIFY_2530(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2530, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2532(F, sep, ...) \ + Z_UTIL_LISTIFY_2531(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2531, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2533(F, sep, ...) \ + Z_UTIL_LISTIFY_2532(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2532, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2534(F, sep, ...) \ + Z_UTIL_LISTIFY_2533(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2533, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2535(F, sep, ...) \ + Z_UTIL_LISTIFY_2534(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2534, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2536(F, sep, ...) \ + Z_UTIL_LISTIFY_2535(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2535, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2537(F, sep, ...) \ + Z_UTIL_LISTIFY_2536(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2536, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2538(F, sep, ...) \ + Z_UTIL_LISTIFY_2537(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2537, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2539(F, sep, ...) \ + Z_UTIL_LISTIFY_2538(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2538, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2540(F, sep, ...) \ + Z_UTIL_LISTIFY_2539(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2539, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2541(F, sep, ...) \ + Z_UTIL_LISTIFY_2540(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2540, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2542(F, sep, ...) \ + Z_UTIL_LISTIFY_2541(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2541, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2543(F, sep, ...) \ + Z_UTIL_LISTIFY_2542(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2542, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2544(F, sep, ...) \ + Z_UTIL_LISTIFY_2543(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2543, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2545(F, sep, ...) \ + Z_UTIL_LISTIFY_2544(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2544, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2546(F, sep, ...) \ + Z_UTIL_LISTIFY_2545(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2545, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2547(F, sep, ...) \ + Z_UTIL_LISTIFY_2546(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2546, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2548(F, sep, ...) \ + Z_UTIL_LISTIFY_2547(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2547, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2549(F, sep, ...) \ + Z_UTIL_LISTIFY_2548(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2548, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2550(F, sep, ...) \ + Z_UTIL_LISTIFY_2549(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2549, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2551(F, sep, ...) \ + Z_UTIL_LISTIFY_2550(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2550, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2552(F, sep, ...) \ + Z_UTIL_LISTIFY_2551(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2551, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2553(F, sep, ...) \ + Z_UTIL_LISTIFY_2552(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2552, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2554(F, sep, ...) \ + Z_UTIL_LISTIFY_2553(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2553, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2555(F, sep, ...) \ + Z_UTIL_LISTIFY_2554(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2554, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2556(F, sep, ...) \ + Z_UTIL_LISTIFY_2555(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2555, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2557(F, sep, ...) \ + Z_UTIL_LISTIFY_2556(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2556, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2558(F, sep, ...) \ + Z_UTIL_LISTIFY_2557(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2557, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2559(F, sep, ...) \ + Z_UTIL_LISTIFY_2558(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2558, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2560(F, sep, ...) \ + Z_UTIL_LISTIFY_2559(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2559, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2561(F, sep, ...) \ + Z_UTIL_LISTIFY_2560(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2560, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2562(F, sep, ...) \ + Z_UTIL_LISTIFY_2561(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2561, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2563(F, sep, ...) \ + Z_UTIL_LISTIFY_2562(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2562, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2564(F, sep, ...) \ + Z_UTIL_LISTIFY_2563(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2563, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2565(F, sep, ...) \ + Z_UTIL_LISTIFY_2564(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2564, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2566(F, sep, ...) \ + Z_UTIL_LISTIFY_2565(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2565, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2567(F, sep, ...) \ + Z_UTIL_LISTIFY_2566(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2566, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2568(F, sep, ...) \ + Z_UTIL_LISTIFY_2567(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2567, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2569(F, sep, ...) \ + Z_UTIL_LISTIFY_2568(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2568, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2570(F, sep, ...) \ + Z_UTIL_LISTIFY_2569(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2569, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2571(F, sep, ...) \ + Z_UTIL_LISTIFY_2570(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2570, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2572(F, sep, ...) \ + Z_UTIL_LISTIFY_2571(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2571, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2573(F, sep, ...) \ + Z_UTIL_LISTIFY_2572(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2572, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2574(F, sep, ...) \ + Z_UTIL_LISTIFY_2573(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2573, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2575(F, sep, ...) \ + Z_UTIL_LISTIFY_2574(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2574, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2576(F, sep, ...) \ + Z_UTIL_LISTIFY_2575(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2575, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2577(F, sep, ...) \ + Z_UTIL_LISTIFY_2576(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2576, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2578(F, sep, ...) \ + Z_UTIL_LISTIFY_2577(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2577, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2579(F, sep, ...) \ + Z_UTIL_LISTIFY_2578(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2578, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2580(F, sep, ...) \ + Z_UTIL_LISTIFY_2579(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2579, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2581(F, sep, ...) \ + Z_UTIL_LISTIFY_2580(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2580, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2582(F, sep, ...) \ + Z_UTIL_LISTIFY_2581(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2581, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2583(F, sep, ...) \ + Z_UTIL_LISTIFY_2582(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2582, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2584(F, sep, ...) \ + Z_UTIL_LISTIFY_2583(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2583, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2585(F, sep, ...) \ + Z_UTIL_LISTIFY_2584(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2584, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2586(F, sep, ...) \ + Z_UTIL_LISTIFY_2585(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2585, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2587(F, sep, ...) \ + Z_UTIL_LISTIFY_2586(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2586, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2588(F, sep, ...) \ + Z_UTIL_LISTIFY_2587(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2587, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2589(F, sep, ...) \ + Z_UTIL_LISTIFY_2588(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2588, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2590(F, sep, ...) \ + Z_UTIL_LISTIFY_2589(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2589, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2591(F, sep, ...) \ + Z_UTIL_LISTIFY_2590(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2590, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2592(F, sep, ...) \ + Z_UTIL_LISTIFY_2591(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2591, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2593(F, sep, ...) \ + Z_UTIL_LISTIFY_2592(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2592, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2594(F, sep, ...) \ + Z_UTIL_LISTIFY_2593(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2593, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2595(F, sep, ...) \ + Z_UTIL_LISTIFY_2594(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2594, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2596(F, sep, ...) \ + Z_UTIL_LISTIFY_2595(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2595, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2597(F, sep, ...) \ + Z_UTIL_LISTIFY_2596(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2596, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2598(F, sep, ...) \ + Z_UTIL_LISTIFY_2597(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2597, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2599(F, sep, ...) \ + Z_UTIL_LISTIFY_2598(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2598, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2600(F, sep, ...) \ + Z_UTIL_LISTIFY_2599(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2599, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2601(F, sep, ...) \ + Z_UTIL_LISTIFY_2600(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2600, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2602(F, sep, ...) \ + Z_UTIL_LISTIFY_2601(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2601, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2603(F, sep, ...) \ + Z_UTIL_LISTIFY_2602(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2602, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2604(F, sep, ...) \ + Z_UTIL_LISTIFY_2603(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2603, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2605(F, sep, ...) \ + Z_UTIL_LISTIFY_2604(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2604, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2606(F, sep, ...) \ + Z_UTIL_LISTIFY_2605(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2605, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2607(F, sep, ...) \ + Z_UTIL_LISTIFY_2606(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2606, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2608(F, sep, ...) \ + Z_UTIL_LISTIFY_2607(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2607, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2609(F, sep, ...) \ + Z_UTIL_LISTIFY_2608(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2608, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2610(F, sep, ...) \ + Z_UTIL_LISTIFY_2609(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2609, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2611(F, sep, ...) \ + Z_UTIL_LISTIFY_2610(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2610, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2612(F, sep, ...) \ + Z_UTIL_LISTIFY_2611(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2611, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2613(F, sep, ...) \ + Z_UTIL_LISTIFY_2612(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2612, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2614(F, sep, ...) \ + Z_UTIL_LISTIFY_2613(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2613, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2615(F, sep, ...) \ + Z_UTIL_LISTIFY_2614(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2614, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2616(F, sep, ...) \ + Z_UTIL_LISTIFY_2615(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2615, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2617(F, sep, ...) \ + Z_UTIL_LISTIFY_2616(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2616, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2618(F, sep, ...) \ + Z_UTIL_LISTIFY_2617(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2617, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2619(F, sep, ...) \ + Z_UTIL_LISTIFY_2618(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2618, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2620(F, sep, ...) \ + Z_UTIL_LISTIFY_2619(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2619, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2621(F, sep, ...) \ + Z_UTIL_LISTIFY_2620(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2620, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2622(F, sep, ...) \ + Z_UTIL_LISTIFY_2621(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2621, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2623(F, sep, ...) \ + Z_UTIL_LISTIFY_2622(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2622, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2624(F, sep, ...) \ + Z_UTIL_LISTIFY_2623(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2623, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2625(F, sep, ...) \ + Z_UTIL_LISTIFY_2624(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2624, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2626(F, sep, ...) \ + Z_UTIL_LISTIFY_2625(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2625, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2627(F, sep, ...) \ + Z_UTIL_LISTIFY_2626(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2626, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2628(F, sep, ...) \ + Z_UTIL_LISTIFY_2627(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2627, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2629(F, sep, ...) \ + Z_UTIL_LISTIFY_2628(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2628, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2630(F, sep, ...) \ + Z_UTIL_LISTIFY_2629(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2629, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2631(F, sep, ...) \ + Z_UTIL_LISTIFY_2630(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2630, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2632(F, sep, ...) \ + Z_UTIL_LISTIFY_2631(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2631, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2633(F, sep, ...) \ + Z_UTIL_LISTIFY_2632(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2632, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2634(F, sep, ...) \ + Z_UTIL_LISTIFY_2633(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2633, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2635(F, sep, ...) \ + Z_UTIL_LISTIFY_2634(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2634, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2636(F, sep, ...) \ + Z_UTIL_LISTIFY_2635(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2635, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2637(F, sep, ...) \ + Z_UTIL_LISTIFY_2636(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2636, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2638(F, sep, ...) \ + Z_UTIL_LISTIFY_2637(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2637, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2639(F, sep, ...) \ + Z_UTIL_LISTIFY_2638(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2638, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2640(F, sep, ...) \ + Z_UTIL_LISTIFY_2639(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2639, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2641(F, sep, ...) \ + Z_UTIL_LISTIFY_2640(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2640, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2642(F, sep, ...) \ + Z_UTIL_LISTIFY_2641(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2641, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2643(F, sep, ...) \ + Z_UTIL_LISTIFY_2642(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2642, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2644(F, sep, ...) \ + Z_UTIL_LISTIFY_2643(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2643, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2645(F, sep, ...) \ + Z_UTIL_LISTIFY_2644(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2644, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2646(F, sep, ...) \ + Z_UTIL_LISTIFY_2645(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2645, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2647(F, sep, ...) \ + Z_UTIL_LISTIFY_2646(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2646, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2648(F, sep, ...) \ + Z_UTIL_LISTIFY_2647(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2647, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2649(F, sep, ...) \ + Z_UTIL_LISTIFY_2648(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2648, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2650(F, sep, ...) \ + Z_UTIL_LISTIFY_2649(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2649, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2651(F, sep, ...) \ + Z_UTIL_LISTIFY_2650(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2650, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2652(F, sep, ...) \ + Z_UTIL_LISTIFY_2651(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2651, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2653(F, sep, ...) \ + Z_UTIL_LISTIFY_2652(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2652, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2654(F, sep, ...) \ + Z_UTIL_LISTIFY_2653(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2653, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2655(F, sep, ...) \ + Z_UTIL_LISTIFY_2654(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2654, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2656(F, sep, ...) \ + Z_UTIL_LISTIFY_2655(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2655, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2657(F, sep, ...) \ + Z_UTIL_LISTIFY_2656(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2656, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2658(F, sep, ...) \ + Z_UTIL_LISTIFY_2657(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2657, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2659(F, sep, ...) \ + Z_UTIL_LISTIFY_2658(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2658, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2660(F, sep, ...) \ + Z_UTIL_LISTIFY_2659(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2659, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2661(F, sep, ...) \ + Z_UTIL_LISTIFY_2660(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2660, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2662(F, sep, ...) \ + Z_UTIL_LISTIFY_2661(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2661, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2663(F, sep, ...) \ + Z_UTIL_LISTIFY_2662(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2662, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2664(F, sep, ...) \ + Z_UTIL_LISTIFY_2663(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2663, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2665(F, sep, ...) \ + Z_UTIL_LISTIFY_2664(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2664, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2666(F, sep, ...) \ + Z_UTIL_LISTIFY_2665(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2665, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2667(F, sep, ...) \ + Z_UTIL_LISTIFY_2666(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2666, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2668(F, sep, ...) \ + Z_UTIL_LISTIFY_2667(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2667, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2669(F, sep, ...) \ + Z_UTIL_LISTIFY_2668(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2668, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2670(F, sep, ...) \ + Z_UTIL_LISTIFY_2669(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2669, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2671(F, sep, ...) \ + Z_UTIL_LISTIFY_2670(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2670, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2672(F, sep, ...) \ + Z_UTIL_LISTIFY_2671(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2671, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2673(F, sep, ...) \ + Z_UTIL_LISTIFY_2672(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2672, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2674(F, sep, ...) \ + Z_UTIL_LISTIFY_2673(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2673, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2675(F, sep, ...) \ + Z_UTIL_LISTIFY_2674(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2674, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2676(F, sep, ...) \ + Z_UTIL_LISTIFY_2675(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2675, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2677(F, sep, ...) \ + Z_UTIL_LISTIFY_2676(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2676, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2678(F, sep, ...) \ + Z_UTIL_LISTIFY_2677(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2677, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2679(F, sep, ...) \ + Z_UTIL_LISTIFY_2678(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2678, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2680(F, sep, ...) \ + Z_UTIL_LISTIFY_2679(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2679, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2681(F, sep, ...) \ + Z_UTIL_LISTIFY_2680(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2680, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2682(F, sep, ...) \ + Z_UTIL_LISTIFY_2681(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2681, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2683(F, sep, ...) \ + Z_UTIL_LISTIFY_2682(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2682, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2684(F, sep, ...) \ + Z_UTIL_LISTIFY_2683(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2683, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2685(F, sep, ...) \ + Z_UTIL_LISTIFY_2684(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2684, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2686(F, sep, ...) \ + Z_UTIL_LISTIFY_2685(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2685, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2687(F, sep, ...) \ + Z_UTIL_LISTIFY_2686(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2686, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2688(F, sep, ...) \ + Z_UTIL_LISTIFY_2687(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2687, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2689(F, sep, ...) \ + Z_UTIL_LISTIFY_2688(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2688, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2690(F, sep, ...) \ + Z_UTIL_LISTIFY_2689(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2689, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2691(F, sep, ...) \ + Z_UTIL_LISTIFY_2690(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2690, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2692(F, sep, ...) \ + Z_UTIL_LISTIFY_2691(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2691, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2693(F, sep, ...) \ + Z_UTIL_LISTIFY_2692(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2692, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2694(F, sep, ...) \ + Z_UTIL_LISTIFY_2693(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2693, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2695(F, sep, ...) \ + Z_UTIL_LISTIFY_2694(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2694, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2696(F, sep, ...) \ + Z_UTIL_LISTIFY_2695(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2695, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2697(F, sep, ...) \ + Z_UTIL_LISTIFY_2696(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2696, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2698(F, sep, ...) \ + Z_UTIL_LISTIFY_2697(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2697, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2699(F, sep, ...) \ + Z_UTIL_LISTIFY_2698(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2698, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2700(F, sep, ...) \ + Z_UTIL_LISTIFY_2699(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2699, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2701(F, sep, ...) \ + Z_UTIL_LISTIFY_2700(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2700, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2702(F, sep, ...) \ + Z_UTIL_LISTIFY_2701(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2701, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2703(F, sep, ...) \ + Z_UTIL_LISTIFY_2702(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2702, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2704(F, sep, ...) \ + Z_UTIL_LISTIFY_2703(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2703, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2705(F, sep, ...) \ + Z_UTIL_LISTIFY_2704(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2704, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2706(F, sep, ...) \ + Z_UTIL_LISTIFY_2705(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2705, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2707(F, sep, ...) \ + Z_UTIL_LISTIFY_2706(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2706, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2708(F, sep, ...) \ + Z_UTIL_LISTIFY_2707(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2707, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2709(F, sep, ...) \ + Z_UTIL_LISTIFY_2708(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2708, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2710(F, sep, ...) \ + Z_UTIL_LISTIFY_2709(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2709, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2711(F, sep, ...) \ + Z_UTIL_LISTIFY_2710(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2710, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2712(F, sep, ...) \ + Z_UTIL_LISTIFY_2711(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2711, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2713(F, sep, ...) \ + Z_UTIL_LISTIFY_2712(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2712, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2714(F, sep, ...) \ + Z_UTIL_LISTIFY_2713(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2713, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2715(F, sep, ...) \ + Z_UTIL_LISTIFY_2714(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2714, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2716(F, sep, ...) \ + Z_UTIL_LISTIFY_2715(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2715, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2717(F, sep, ...) \ + Z_UTIL_LISTIFY_2716(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2716, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2718(F, sep, ...) \ + Z_UTIL_LISTIFY_2717(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2717, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2719(F, sep, ...) \ + Z_UTIL_LISTIFY_2718(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2718, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2720(F, sep, ...) \ + Z_UTIL_LISTIFY_2719(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2719, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2721(F, sep, ...) \ + Z_UTIL_LISTIFY_2720(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2720, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2722(F, sep, ...) \ + Z_UTIL_LISTIFY_2721(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2721, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2723(F, sep, ...) \ + Z_UTIL_LISTIFY_2722(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2722, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2724(F, sep, ...) \ + Z_UTIL_LISTIFY_2723(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2723, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2725(F, sep, ...) \ + Z_UTIL_LISTIFY_2724(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2724, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2726(F, sep, ...) \ + Z_UTIL_LISTIFY_2725(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2725, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2727(F, sep, ...) \ + Z_UTIL_LISTIFY_2726(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2726, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2728(F, sep, ...) \ + Z_UTIL_LISTIFY_2727(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2727, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2729(F, sep, ...) \ + Z_UTIL_LISTIFY_2728(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2728, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2730(F, sep, ...) \ + Z_UTIL_LISTIFY_2729(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2729, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2731(F, sep, ...) \ + Z_UTIL_LISTIFY_2730(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2730, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2732(F, sep, ...) \ + Z_UTIL_LISTIFY_2731(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2731, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2733(F, sep, ...) \ + Z_UTIL_LISTIFY_2732(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2732, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2734(F, sep, ...) \ + Z_UTIL_LISTIFY_2733(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2733, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2735(F, sep, ...) \ + Z_UTIL_LISTIFY_2734(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2734, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2736(F, sep, ...) \ + Z_UTIL_LISTIFY_2735(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2735, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2737(F, sep, ...) \ + Z_UTIL_LISTIFY_2736(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2736, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2738(F, sep, ...) \ + Z_UTIL_LISTIFY_2737(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2737, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2739(F, sep, ...) \ + Z_UTIL_LISTIFY_2738(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2738, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2740(F, sep, ...) \ + Z_UTIL_LISTIFY_2739(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2739, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2741(F, sep, ...) \ + Z_UTIL_LISTIFY_2740(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2740, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2742(F, sep, ...) \ + Z_UTIL_LISTIFY_2741(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2741, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2743(F, sep, ...) \ + Z_UTIL_LISTIFY_2742(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2742, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2744(F, sep, ...) \ + Z_UTIL_LISTIFY_2743(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2743, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2745(F, sep, ...) \ + Z_UTIL_LISTIFY_2744(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2744, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2746(F, sep, ...) \ + Z_UTIL_LISTIFY_2745(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2745, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2747(F, sep, ...) \ + Z_UTIL_LISTIFY_2746(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2746, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2748(F, sep, ...) \ + Z_UTIL_LISTIFY_2747(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2747, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2749(F, sep, ...) \ + Z_UTIL_LISTIFY_2748(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2748, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2750(F, sep, ...) \ + Z_UTIL_LISTIFY_2749(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2749, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2751(F, sep, ...) \ + Z_UTIL_LISTIFY_2750(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2750, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2752(F, sep, ...) \ + Z_UTIL_LISTIFY_2751(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2751, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2753(F, sep, ...) \ + Z_UTIL_LISTIFY_2752(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2752, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2754(F, sep, ...) \ + Z_UTIL_LISTIFY_2753(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2753, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2755(F, sep, ...) \ + Z_UTIL_LISTIFY_2754(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2754, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2756(F, sep, ...) \ + Z_UTIL_LISTIFY_2755(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2755, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2757(F, sep, ...) \ + Z_UTIL_LISTIFY_2756(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2756, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2758(F, sep, ...) \ + Z_UTIL_LISTIFY_2757(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2757, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2759(F, sep, ...) \ + Z_UTIL_LISTIFY_2758(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2758, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2760(F, sep, ...) \ + Z_UTIL_LISTIFY_2759(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2759, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2761(F, sep, ...) \ + Z_UTIL_LISTIFY_2760(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2760, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2762(F, sep, ...) \ + Z_UTIL_LISTIFY_2761(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2761, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2763(F, sep, ...) \ + Z_UTIL_LISTIFY_2762(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2762, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2764(F, sep, ...) \ + Z_UTIL_LISTIFY_2763(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2763, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2765(F, sep, ...) \ + Z_UTIL_LISTIFY_2764(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2764, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2766(F, sep, ...) \ + Z_UTIL_LISTIFY_2765(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2765, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2767(F, sep, ...) \ + Z_UTIL_LISTIFY_2766(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2766, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2768(F, sep, ...) \ + Z_UTIL_LISTIFY_2767(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2767, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2769(F, sep, ...) \ + Z_UTIL_LISTIFY_2768(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2768, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2770(F, sep, ...) \ + Z_UTIL_LISTIFY_2769(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2769, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2771(F, sep, ...) \ + Z_UTIL_LISTIFY_2770(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2770, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2772(F, sep, ...) \ + Z_UTIL_LISTIFY_2771(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2771, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2773(F, sep, ...) \ + Z_UTIL_LISTIFY_2772(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2772, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2774(F, sep, ...) \ + Z_UTIL_LISTIFY_2773(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2773, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2775(F, sep, ...) \ + Z_UTIL_LISTIFY_2774(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2774, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2776(F, sep, ...) \ + Z_UTIL_LISTIFY_2775(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2775, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2777(F, sep, ...) \ + Z_UTIL_LISTIFY_2776(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2776, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2778(F, sep, ...) \ + Z_UTIL_LISTIFY_2777(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2777, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2779(F, sep, ...) \ + Z_UTIL_LISTIFY_2778(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2778, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2780(F, sep, ...) \ + Z_UTIL_LISTIFY_2779(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2779, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2781(F, sep, ...) \ + Z_UTIL_LISTIFY_2780(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2780, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2782(F, sep, ...) \ + Z_UTIL_LISTIFY_2781(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2781, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2783(F, sep, ...) \ + Z_UTIL_LISTIFY_2782(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2782, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2784(F, sep, ...) \ + Z_UTIL_LISTIFY_2783(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2783, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2785(F, sep, ...) \ + Z_UTIL_LISTIFY_2784(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2784, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2786(F, sep, ...) \ + Z_UTIL_LISTIFY_2785(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2785, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2787(F, sep, ...) \ + Z_UTIL_LISTIFY_2786(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2786, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2788(F, sep, ...) \ + Z_UTIL_LISTIFY_2787(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2787, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2789(F, sep, ...) \ + Z_UTIL_LISTIFY_2788(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2788, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2790(F, sep, ...) \ + Z_UTIL_LISTIFY_2789(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2789, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2791(F, sep, ...) \ + Z_UTIL_LISTIFY_2790(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2790, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2792(F, sep, ...) \ + Z_UTIL_LISTIFY_2791(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2791, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2793(F, sep, ...) \ + Z_UTIL_LISTIFY_2792(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2792, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2794(F, sep, ...) \ + Z_UTIL_LISTIFY_2793(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2793, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2795(F, sep, ...) \ + Z_UTIL_LISTIFY_2794(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2794, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2796(F, sep, ...) \ + Z_UTIL_LISTIFY_2795(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2795, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2797(F, sep, ...) \ + Z_UTIL_LISTIFY_2796(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2796, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2798(F, sep, ...) \ + Z_UTIL_LISTIFY_2797(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2797, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2799(F, sep, ...) \ + Z_UTIL_LISTIFY_2798(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2798, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2800(F, sep, ...) \ + Z_UTIL_LISTIFY_2799(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2799, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2801(F, sep, ...) \ + Z_UTIL_LISTIFY_2800(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2800, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2802(F, sep, ...) \ + Z_UTIL_LISTIFY_2801(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2801, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2803(F, sep, ...) \ + Z_UTIL_LISTIFY_2802(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2802, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2804(F, sep, ...) \ + Z_UTIL_LISTIFY_2803(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2803, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2805(F, sep, ...) \ + Z_UTIL_LISTIFY_2804(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2804, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2806(F, sep, ...) \ + Z_UTIL_LISTIFY_2805(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2805, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2807(F, sep, ...) \ + Z_UTIL_LISTIFY_2806(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2806, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2808(F, sep, ...) \ + Z_UTIL_LISTIFY_2807(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2807, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2809(F, sep, ...) \ + Z_UTIL_LISTIFY_2808(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2808, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2810(F, sep, ...) \ + Z_UTIL_LISTIFY_2809(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2809, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2811(F, sep, ...) \ + Z_UTIL_LISTIFY_2810(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2810, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2812(F, sep, ...) \ + Z_UTIL_LISTIFY_2811(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2811, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2813(F, sep, ...) \ + Z_UTIL_LISTIFY_2812(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2812, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2814(F, sep, ...) \ + Z_UTIL_LISTIFY_2813(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2813, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2815(F, sep, ...) \ + Z_UTIL_LISTIFY_2814(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2814, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2816(F, sep, ...) \ + Z_UTIL_LISTIFY_2815(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2815, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2817(F, sep, ...) \ + Z_UTIL_LISTIFY_2816(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2816, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2818(F, sep, ...) \ + Z_UTIL_LISTIFY_2817(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2817, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2819(F, sep, ...) \ + Z_UTIL_LISTIFY_2818(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2818, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2820(F, sep, ...) \ + Z_UTIL_LISTIFY_2819(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2819, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2821(F, sep, ...) \ + Z_UTIL_LISTIFY_2820(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2820, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2822(F, sep, ...) \ + Z_UTIL_LISTIFY_2821(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2821, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2823(F, sep, ...) \ + Z_UTIL_LISTIFY_2822(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2822, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2824(F, sep, ...) \ + Z_UTIL_LISTIFY_2823(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2823, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2825(F, sep, ...) \ + Z_UTIL_LISTIFY_2824(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2824, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2826(F, sep, ...) \ + Z_UTIL_LISTIFY_2825(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2825, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2827(F, sep, ...) \ + Z_UTIL_LISTIFY_2826(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2826, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2828(F, sep, ...) \ + Z_UTIL_LISTIFY_2827(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2827, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2829(F, sep, ...) \ + Z_UTIL_LISTIFY_2828(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2828, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2830(F, sep, ...) \ + Z_UTIL_LISTIFY_2829(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2829, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2831(F, sep, ...) \ + Z_UTIL_LISTIFY_2830(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2830, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2832(F, sep, ...) \ + Z_UTIL_LISTIFY_2831(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2831, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2833(F, sep, ...) \ + Z_UTIL_LISTIFY_2832(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2832, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2834(F, sep, ...) \ + Z_UTIL_LISTIFY_2833(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2833, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2835(F, sep, ...) \ + Z_UTIL_LISTIFY_2834(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2834, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2836(F, sep, ...) \ + Z_UTIL_LISTIFY_2835(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2835, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2837(F, sep, ...) \ + Z_UTIL_LISTIFY_2836(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2836, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2838(F, sep, ...) \ + Z_UTIL_LISTIFY_2837(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2837, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2839(F, sep, ...) \ + Z_UTIL_LISTIFY_2838(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2838, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2840(F, sep, ...) \ + Z_UTIL_LISTIFY_2839(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2839, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2841(F, sep, ...) \ + Z_UTIL_LISTIFY_2840(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2840, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2842(F, sep, ...) \ + Z_UTIL_LISTIFY_2841(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2841, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2843(F, sep, ...) \ + Z_UTIL_LISTIFY_2842(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2842, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2844(F, sep, ...) \ + Z_UTIL_LISTIFY_2843(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2843, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2845(F, sep, ...) \ + Z_UTIL_LISTIFY_2844(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2844, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2846(F, sep, ...) \ + Z_UTIL_LISTIFY_2845(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2845, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2847(F, sep, ...) \ + Z_UTIL_LISTIFY_2846(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2846, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2848(F, sep, ...) \ + Z_UTIL_LISTIFY_2847(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2847, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2849(F, sep, ...) \ + Z_UTIL_LISTIFY_2848(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2848, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2850(F, sep, ...) \ + Z_UTIL_LISTIFY_2849(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2849, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2851(F, sep, ...) \ + Z_UTIL_LISTIFY_2850(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2850, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2852(F, sep, ...) \ + Z_UTIL_LISTIFY_2851(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2851, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2853(F, sep, ...) \ + Z_UTIL_LISTIFY_2852(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2852, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2854(F, sep, ...) \ + Z_UTIL_LISTIFY_2853(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2853, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2855(F, sep, ...) \ + Z_UTIL_LISTIFY_2854(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2854, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2856(F, sep, ...) \ + Z_UTIL_LISTIFY_2855(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2855, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2857(F, sep, ...) \ + Z_UTIL_LISTIFY_2856(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2856, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2858(F, sep, ...) \ + Z_UTIL_LISTIFY_2857(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2857, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2859(F, sep, ...) \ + Z_UTIL_LISTIFY_2858(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2858, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2860(F, sep, ...) \ + Z_UTIL_LISTIFY_2859(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2859, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2861(F, sep, ...) \ + Z_UTIL_LISTIFY_2860(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2860, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2862(F, sep, ...) \ + Z_UTIL_LISTIFY_2861(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2861, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2863(F, sep, ...) \ + Z_UTIL_LISTIFY_2862(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2862, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2864(F, sep, ...) \ + Z_UTIL_LISTIFY_2863(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2863, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2865(F, sep, ...) \ + Z_UTIL_LISTIFY_2864(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2864, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2866(F, sep, ...) \ + Z_UTIL_LISTIFY_2865(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2865, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2867(F, sep, ...) \ + Z_UTIL_LISTIFY_2866(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2866, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2868(F, sep, ...) \ + Z_UTIL_LISTIFY_2867(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2867, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2869(F, sep, ...) \ + Z_UTIL_LISTIFY_2868(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2868, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2870(F, sep, ...) \ + Z_UTIL_LISTIFY_2869(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2869, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2871(F, sep, ...) \ + Z_UTIL_LISTIFY_2870(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2870, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2872(F, sep, ...) \ + Z_UTIL_LISTIFY_2871(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2871, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2873(F, sep, ...) \ + Z_UTIL_LISTIFY_2872(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2872, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2874(F, sep, ...) \ + Z_UTIL_LISTIFY_2873(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2873, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2875(F, sep, ...) \ + Z_UTIL_LISTIFY_2874(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2874, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2876(F, sep, ...) \ + Z_UTIL_LISTIFY_2875(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2875, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2877(F, sep, ...) \ + Z_UTIL_LISTIFY_2876(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2876, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2878(F, sep, ...) \ + Z_UTIL_LISTIFY_2877(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2877, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2879(F, sep, ...) \ + Z_UTIL_LISTIFY_2878(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2878, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2880(F, sep, ...) \ + Z_UTIL_LISTIFY_2879(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2879, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2881(F, sep, ...) \ + Z_UTIL_LISTIFY_2880(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2880, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2882(F, sep, ...) \ + Z_UTIL_LISTIFY_2881(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2881, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2883(F, sep, ...) \ + Z_UTIL_LISTIFY_2882(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2882, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2884(F, sep, ...) \ + Z_UTIL_LISTIFY_2883(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2883, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2885(F, sep, ...) \ + Z_UTIL_LISTIFY_2884(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2884, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2886(F, sep, ...) \ + Z_UTIL_LISTIFY_2885(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2885, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2887(F, sep, ...) \ + Z_UTIL_LISTIFY_2886(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2886, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2888(F, sep, ...) \ + Z_UTIL_LISTIFY_2887(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2887, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2889(F, sep, ...) \ + Z_UTIL_LISTIFY_2888(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2888, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2890(F, sep, ...) \ + Z_UTIL_LISTIFY_2889(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2889, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2891(F, sep, ...) \ + Z_UTIL_LISTIFY_2890(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2890, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2892(F, sep, ...) \ + Z_UTIL_LISTIFY_2891(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2891, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2893(F, sep, ...) \ + Z_UTIL_LISTIFY_2892(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2892, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2894(F, sep, ...) \ + Z_UTIL_LISTIFY_2893(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2893, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2895(F, sep, ...) \ + Z_UTIL_LISTIFY_2894(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2894, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2896(F, sep, ...) \ + Z_UTIL_LISTIFY_2895(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2895, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2897(F, sep, ...) \ + Z_UTIL_LISTIFY_2896(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2896, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2898(F, sep, ...) \ + Z_UTIL_LISTIFY_2897(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2897, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2899(F, sep, ...) \ + Z_UTIL_LISTIFY_2898(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2898, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2900(F, sep, ...) \ + Z_UTIL_LISTIFY_2899(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2899, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2901(F, sep, ...) \ + Z_UTIL_LISTIFY_2900(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2900, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2902(F, sep, ...) \ + Z_UTIL_LISTIFY_2901(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2901, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2903(F, sep, ...) \ + Z_UTIL_LISTIFY_2902(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2902, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2904(F, sep, ...) \ + Z_UTIL_LISTIFY_2903(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2903, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2905(F, sep, ...) \ + Z_UTIL_LISTIFY_2904(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2904, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2906(F, sep, ...) \ + Z_UTIL_LISTIFY_2905(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2905, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2907(F, sep, ...) \ + Z_UTIL_LISTIFY_2906(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2906, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2908(F, sep, ...) \ + Z_UTIL_LISTIFY_2907(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2907, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2909(F, sep, ...) \ + Z_UTIL_LISTIFY_2908(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2908, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2910(F, sep, ...) \ + Z_UTIL_LISTIFY_2909(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2909, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2911(F, sep, ...) \ + Z_UTIL_LISTIFY_2910(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2910, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2912(F, sep, ...) \ + Z_UTIL_LISTIFY_2911(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2911, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2913(F, sep, ...) \ + Z_UTIL_LISTIFY_2912(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2912, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2914(F, sep, ...) \ + Z_UTIL_LISTIFY_2913(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2913, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2915(F, sep, ...) \ + Z_UTIL_LISTIFY_2914(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2914, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2916(F, sep, ...) \ + Z_UTIL_LISTIFY_2915(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2915, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2917(F, sep, ...) \ + Z_UTIL_LISTIFY_2916(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2916, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2918(F, sep, ...) \ + Z_UTIL_LISTIFY_2917(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2917, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2919(F, sep, ...) \ + Z_UTIL_LISTIFY_2918(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2918, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2920(F, sep, ...) \ + Z_UTIL_LISTIFY_2919(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2919, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2921(F, sep, ...) \ + Z_UTIL_LISTIFY_2920(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2920, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2922(F, sep, ...) \ + Z_UTIL_LISTIFY_2921(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2921, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2923(F, sep, ...) \ + Z_UTIL_LISTIFY_2922(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2922, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2924(F, sep, ...) \ + Z_UTIL_LISTIFY_2923(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2923, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2925(F, sep, ...) \ + Z_UTIL_LISTIFY_2924(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2924, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2926(F, sep, ...) \ + Z_UTIL_LISTIFY_2925(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2925, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2927(F, sep, ...) \ + Z_UTIL_LISTIFY_2926(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2926, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2928(F, sep, ...) \ + Z_UTIL_LISTIFY_2927(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2927, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2929(F, sep, ...) \ + Z_UTIL_LISTIFY_2928(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2928, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2930(F, sep, ...) \ + Z_UTIL_LISTIFY_2929(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2929, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2931(F, sep, ...) \ + Z_UTIL_LISTIFY_2930(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2930, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2932(F, sep, ...) \ + Z_UTIL_LISTIFY_2931(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2931, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2933(F, sep, ...) \ + Z_UTIL_LISTIFY_2932(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2932, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2934(F, sep, ...) \ + Z_UTIL_LISTIFY_2933(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2933, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2935(F, sep, ...) \ + Z_UTIL_LISTIFY_2934(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2934, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2936(F, sep, ...) \ + Z_UTIL_LISTIFY_2935(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2935, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2937(F, sep, ...) \ + Z_UTIL_LISTIFY_2936(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2936, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2938(F, sep, ...) \ + Z_UTIL_LISTIFY_2937(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2937, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2939(F, sep, ...) \ + Z_UTIL_LISTIFY_2938(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2938, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2940(F, sep, ...) \ + Z_UTIL_LISTIFY_2939(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2939, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2941(F, sep, ...) \ + Z_UTIL_LISTIFY_2940(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2940, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2942(F, sep, ...) \ + Z_UTIL_LISTIFY_2941(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2941, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2943(F, sep, ...) \ + Z_UTIL_LISTIFY_2942(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2942, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2944(F, sep, ...) \ + Z_UTIL_LISTIFY_2943(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2943, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2945(F, sep, ...) \ + Z_UTIL_LISTIFY_2944(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2944, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2946(F, sep, ...) \ + Z_UTIL_LISTIFY_2945(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2945, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2947(F, sep, ...) \ + Z_UTIL_LISTIFY_2946(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2946, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2948(F, sep, ...) \ + Z_UTIL_LISTIFY_2947(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2947, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2949(F, sep, ...) \ + Z_UTIL_LISTIFY_2948(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2948, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2950(F, sep, ...) \ + Z_UTIL_LISTIFY_2949(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2949, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2951(F, sep, ...) \ + Z_UTIL_LISTIFY_2950(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2950, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2952(F, sep, ...) \ + Z_UTIL_LISTIFY_2951(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2951, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2953(F, sep, ...) \ + Z_UTIL_LISTIFY_2952(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2952, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2954(F, sep, ...) \ + Z_UTIL_LISTIFY_2953(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2953, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2955(F, sep, ...) \ + Z_UTIL_LISTIFY_2954(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2954, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2956(F, sep, ...) \ + Z_UTIL_LISTIFY_2955(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2955, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2957(F, sep, ...) \ + Z_UTIL_LISTIFY_2956(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2956, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2958(F, sep, ...) \ + Z_UTIL_LISTIFY_2957(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2957, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2959(F, sep, ...) \ + Z_UTIL_LISTIFY_2958(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2958, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2960(F, sep, ...) \ + Z_UTIL_LISTIFY_2959(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2959, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2961(F, sep, ...) \ + Z_UTIL_LISTIFY_2960(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2960, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2962(F, sep, ...) \ + Z_UTIL_LISTIFY_2961(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2961, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2963(F, sep, ...) \ + Z_UTIL_LISTIFY_2962(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2962, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2964(F, sep, ...) \ + Z_UTIL_LISTIFY_2963(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2963, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2965(F, sep, ...) \ + Z_UTIL_LISTIFY_2964(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2964, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2966(F, sep, ...) \ + Z_UTIL_LISTIFY_2965(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2965, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2967(F, sep, ...) \ + Z_UTIL_LISTIFY_2966(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2966, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2968(F, sep, ...) \ + Z_UTIL_LISTIFY_2967(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2967, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2969(F, sep, ...) \ + Z_UTIL_LISTIFY_2968(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2968, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2970(F, sep, ...) \ + Z_UTIL_LISTIFY_2969(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2969, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2971(F, sep, ...) \ + Z_UTIL_LISTIFY_2970(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2970, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2972(F, sep, ...) \ + Z_UTIL_LISTIFY_2971(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2971, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2973(F, sep, ...) \ + Z_UTIL_LISTIFY_2972(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2972, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2974(F, sep, ...) \ + Z_UTIL_LISTIFY_2973(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2973, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2975(F, sep, ...) \ + Z_UTIL_LISTIFY_2974(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2974, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2976(F, sep, ...) \ + Z_UTIL_LISTIFY_2975(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2975, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2977(F, sep, ...) \ + Z_UTIL_LISTIFY_2976(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2976, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2978(F, sep, ...) \ + Z_UTIL_LISTIFY_2977(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2977, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2979(F, sep, ...) \ + Z_UTIL_LISTIFY_2978(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2978, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2980(F, sep, ...) \ + Z_UTIL_LISTIFY_2979(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2979, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2981(F, sep, ...) \ + Z_UTIL_LISTIFY_2980(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2980, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2982(F, sep, ...) \ + Z_UTIL_LISTIFY_2981(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2981, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2983(F, sep, ...) \ + Z_UTIL_LISTIFY_2982(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2982, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2984(F, sep, ...) \ + Z_UTIL_LISTIFY_2983(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2983, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2985(F, sep, ...) \ + Z_UTIL_LISTIFY_2984(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2984, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2986(F, sep, ...) \ + Z_UTIL_LISTIFY_2985(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2985, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2987(F, sep, ...) \ + Z_UTIL_LISTIFY_2986(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2986, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2988(F, sep, ...) \ + Z_UTIL_LISTIFY_2987(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2987, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2989(F, sep, ...) \ + Z_UTIL_LISTIFY_2988(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2988, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2990(F, sep, ...) \ + Z_UTIL_LISTIFY_2989(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2989, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2991(F, sep, ...) \ + Z_UTIL_LISTIFY_2990(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2990, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2992(F, sep, ...) \ + Z_UTIL_LISTIFY_2991(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2991, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2993(F, sep, ...) \ + Z_UTIL_LISTIFY_2992(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2992, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2994(F, sep, ...) \ + Z_UTIL_LISTIFY_2993(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2993, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2995(F, sep, ...) \ + Z_UTIL_LISTIFY_2994(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2994, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2996(F, sep, ...) \ + Z_UTIL_LISTIFY_2995(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2995, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2997(F, sep, ...) \ + Z_UTIL_LISTIFY_2996(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2996, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2998(F, sep, ...) \ + Z_UTIL_LISTIFY_2997(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2997, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_2999(F, sep, ...) \ + Z_UTIL_LISTIFY_2998(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2998, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3000(F, sep, ...) \ + Z_UTIL_LISTIFY_2999(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(2999, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3001(F, sep, ...) \ + Z_UTIL_LISTIFY_3000(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3000, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3002(F, sep, ...) \ + Z_UTIL_LISTIFY_3001(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3001, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3003(F, sep, ...) \ + Z_UTIL_LISTIFY_3002(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3002, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3004(F, sep, ...) \ + Z_UTIL_LISTIFY_3003(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3003, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3005(F, sep, ...) \ + Z_UTIL_LISTIFY_3004(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3004, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3006(F, sep, ...) \ + Z_UTIL_LISTIFY_3005(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3005, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3007(F, sep, ...) \ + Z_UTIL_LISTIFY_3006(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3006, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3008(F, sep, ...) \ + Z_UTIL_LISTIFY_3007(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3007, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3009(F, sep, ...) \ + Z_UTIL_LISTIFY_3008(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3008, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3010(F, sep, ...) \ + Z_UTIL_LISTIFY_3009(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3009, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3011(F, sep, ...) \ + Z_UTIL_LISTIFY_3010(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3010, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3012(F, sep, ...) \ + Z_UTIL_LISTIFY_3011(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3011, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3013(F, sep, ...) \ + Z_UTIL_LISTIFY_3012(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3012, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3014(F, sep, ...) \ + Z_UTIL_LISTIFY_3013(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3013, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3015(F, sep, ...) \ + Z_UTIL_LISTIFY_3014(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3014, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3016(F, sep, ...) \ + Z_UTIL_LISTIFY_3015(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3015, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3017(F, sep, ...) \ + Z_UTIL_LISTIFY_3016(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3016, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3018(F, sep, ...) \ + Z_UTIL_LISTIFY_3017(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3017, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3019(F, sep, ...) \ + Z_UTIL_LISTIFY_3018(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3018, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3020(F, sep, ...) \ + Z_UTIL_LISTIFY_3019(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3019, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3021(F, sep, ...) \ + Z_UTIL_LISTIFY_3020(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3020, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3022(F, sep, ...) \ + Z_UTIL_LISTIFY_3021(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3021, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3023(F, sep, ...) \ + Z_UTIL_LISTIFY_3022(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3022, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3024(F, sep, ...) \ + Z_UTIL_LISTIFY_3023(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3023, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3025(F, sep, ...) \ + Z_UTIL_LISTIFY_3024(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3024, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3026(F, sep, ...) \ + Z_UTIL_LISTIFY_3025(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3025, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3027(F, sep, ...) \ + Z_UTIL_LISTIFY_3026(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3026, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3028(F, sep, ...) \ + Z_UTIL_LISTIFY_3027(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3027, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3029(F, sep, ...) \ + Z_UTIL_LISTIFY_3028(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3028, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3030(F, sep, ...) \ + Z_UTIL_LISTIFY_3029(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3029, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3031(F, sep, ...) \ + Z_UTIL_LISTIFY_3030(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3030, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3032(F, sep, ...) \ + Z_UTIL_LISTIFY_3031(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3031, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3033(F, sep, ...) \ + Z_UTIL_LISTIFY_3032(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3032, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3034(F, sep, ...) \ + Z_UTIL_LISTIFY_3033(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3033, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3035(F, sep, ...) \ + Z_UTIL_LISTIFY_3034(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3034, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3036(F, sep, ...) \ + Z_UTIL_LISTIFY_3035(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3035, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3037(F, sep, ...) \ + Z_UTIL_LISTIFY_3036(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3036, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3038(F, sep, ...) \ + Z_UTIL_LISTIFY_3037(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3037, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3039(F, sep, ...) \ + Z_UTIL_LISTIFY_3038(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3038, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3040(F, sep, ...) \ + Z_UTIL_LISTIFY_3039(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3039, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3041(F, sep, ...) \ + Z_UTIL_LISTIFY_3040(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3040, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3042(F, sep, ...) \ + Z_UTIL_LISTIFY_3041(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3041, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3043(F, sep, ...) \ + Z_UTIL_LISTIFY_3042(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3042, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3044(F, sep, ...) \ + Z_UTIL_LISTIFY_3043(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3043, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3045(F, sep, ...) \ + Z_UTIL_LISTIFY_3044(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3044, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3046(F, sep, ...) \ + Z_UTIL_LISTIFY_3045(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3045, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3047(F, sep, ...) \ + Z_UTIL_LISTIFY_3046(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3046, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3048(F, sep, ...) \ + Z_UTIL_LISTIFY_3047(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3047, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3049(F, sep, ...) \ + Z_UTIL_LISTIFY_3048(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3048, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3050(F, sep, ...) \ + Z_UTIL_LISTIFY_3049(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3049, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3051(F, sep, ...) \ + Z_UTIL_LISTIFY_3050(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3050, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3052(F, sep, ...) \ + Z_UTIL_LISTIFY_3051(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3051, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3053(F, sep, ...) \ + Z_UTIL_LISTIFY_3052(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3052, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3054(F, sep, ...) \ + Z_UTIL_LISTIFY_3053(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3053, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3055(F, sep, ...) \ + Z_UTIL_LISTIFY_3054(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3054, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3056(F, sep, ...) \ + Z_UTIL_LISTIFY_3055(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3055, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3057(F, sep, ...) \ + Z_UTIL_LISTIFY_3056(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3056, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3058(F, sep, ...) \ + Z_UTIL_LISTIFY_3057(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3057, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3059(F, sep, ...) \ + Z_UTIL_LISTIFY_3058(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3058, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3060(F, sep, ...) \ + Z_UTIL_LISTIFY_3059(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3059, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3061(F, sep, ...) \ + Z_UTIL_LISTIFY_3060(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3060, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3062(F, sep, ...) \ + Z_UTIL_LISTIFY_3061(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3061, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3063(F, sep, ...) \ + Z_UTIL_LISTIFY_3062(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3062, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3064(F, sep, ...) \ + Z_UTIL_LISTIFY_3063(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3063, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3065(F, sep, ...) \ + Z_UTIL_LISTIFY_3064(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3064, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3066(F, sep, ...) \ + Z_UTIL_LISTIFY_3065(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3065, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3067(F, sep, ...) \ + Z_UTIL_LISTIFY_3066(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3066, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3068(F, sep, ...) \ + Z_UTIL_LISTIFY_3067(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3067, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3069(F, sep, ...) \ + Z_UTIL_LISTIFY_3068(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3068, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3070(F, sep, ...) \ + Z_UTIL_LISTIFY_3069(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3069, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3071(F, sep, ...) \ + Z_UTIL_LISTIFY_3070(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3070, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3072(F, sep, ...) \ + Z_UTIL_LISTIFY_3071(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3071, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3073(F, sep, ...) \ + Z_UTIL_LISTIFY_3072(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3072, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3074(F, sep, ...) \ + Z_UTIL_LISTIFY_3073(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3073, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3075(F, sep, ...) \ + Z_UTIL_LISTIFY_3074(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3074, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3076(F, sep, ...) \ + Z_UTIL_LISTIFY_3075(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3075, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3077(F, sep, ...) \ + Z_UTIL_LISTIFY_3076(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3076, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3078(F, sep, ...) \ + Z_UTIL_LISTIFY_3077(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3077, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3079(F, sep, ...) \ + Z_UTIL_LISTIFY_3078(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3078, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3080(F, sep, ...) \ + Z_UTIL_LISTIFY_3079(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3079, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3081(F, sep, ...) \ + Z_UTIL_LISTIFY_3080(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3080, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3082(F, sep, ...) \ + Z_UTIL_LISTIFY_3081(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3081, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3083(F, sep, ...) \ + Z_UTIL_LISTIFY_3082(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3082, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3084(F, sep, ...) \ + Z_UTIL_LISTIFY_3083(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3083, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3085(F, sep, ...) \ + Z_UTIL_LISTIFY_3084(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3084, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3086(F, sep, ...) \ + Z_UTIL_LISTIFY_3085(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3085, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3087(F, sep, ...) \ + Z_UTIL_LISTIFY_3086(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3086, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3088(F, sep, ...) \ + Z_UTIL_LISTIFY_3087(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3087, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3089(F, sep, ...) \ + Z_UTIL_LISTIFY_3088(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3088, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3090(F, sep, ...) \ + Z_UTIL_LISTIFY_3089(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3089, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3091(F, sep, ...) \ + Z_UTIL_LISTIFY_3090(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3090, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3092(F, sep, ...) \ + Z_UTIL_LISTIFY_3091(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3091, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3093(F, sep, ...) \ + Z_UTIL_LISTIFY_3092(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3092, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3094(F, sep, ...) \ + Z_UTIL_LISTIFY_3093(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3093, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3095(F, sep, ...) \ + Z_UTIL_LISTIFY_3094(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3094, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3096(F, sep, ...) \ + Z_UTIL_LISTIFY_3095(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3095, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3097(F, sep, ...) \ + Z_UTIL_LISTIFY_3096(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3096, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3098(F, sep, ...) \ + Z_UTIL_LISTIFY_3097(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3097, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3099(F, sep, ...) \ + Z_UTIL_LISTIFY_3098(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3098, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3100(F, sep, ...) \ + Z_UTIL_LISTIFY_3099(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3099, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3101(F, sep, ...) \ + Z_UTIL_LISTIFY_3100(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3100, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3102(F, sep, ...) \ + Z_UTIL_LISTIFY_3101(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3101, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3103(F, sep, ...) \ + Z_UTIL_LISTIFY_3102(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3102, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3104(F, sep, ...) \ + Z_UTIL_LISTIFY_3103(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3103, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3105(F, sep, ...) \ + Z_UTIL_LISTIFY_3104(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3104, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3106(F, sep, ...) \ + Z_UTIL_LISTIFY_3105(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3105, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3107(F, sep, ...) \ + Z_UTIL_LISTIFY_3106(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3106, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3108(F, sep, ...) \ + Z_UTIL_LISTIFY_3107(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3107, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3109(F, sep, ...) \ + Z_UTIL_LISTIFY_3108(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3108, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3110(F, sep, ...) \ + Z_UTIL_LISTIFY_3109(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3109, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3111(F, sep, ...) \ + Z_UTIL_LISTIFY_3110(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3110, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3112(F, sep, ...) \ + Z_UTIL_LISTIFY_3111(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3111, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3113(F, sep, ...) \ + Z_UTIL_LISTIFY_3112(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3112, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3114(F, sep, ...) \ + Z_UTIL_LISTIFY_3113(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3113, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3115(F, sep, ...) \ + Z_UTIL_LISTIFY_3114(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3114, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3116(F, sep, ...) \ + Z_UTIL_LISTIFY_3115(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3115, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3117(F, sep, ...) \ + Z_UTIL_LISTIFY_3116(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3116, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3118(F, sep, ...) \ + Z_UTIL_LISTIFY_3117(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3117, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3119(F, sep, ...) \ + Z_UTIL_LISTIFY_3118(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3118, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3120(F, sep, ...) \ + Z_UTIL_LISTIFY_3119(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3119, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3121(F, sep, ...) \ + Z_UTIL_LISTIFY_3120(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3120, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3122(F, sep, ...) \ + Z_UTIL_LISTIFY_3121(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3121, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3123(F, sep, ...) \ + Z_UTIL_LISTIFY_3122(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3122, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3124(F, sep, ...) \ + Z_UTIL_LISTIFY_3123(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3123, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3125(F, sep, ...) \ + Z_UTIL_LISTIFY_3124(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3124, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3126(F, sep, ...) \ + Z_UTIL_LISTIFY_3125(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3125, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3127(F, sep, ...) \ + Z_UTIL_LISTIFY_3126(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3126, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3128(F, sep, ...) \ + Z_UTIL_LISTIFY_3127(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3127, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3129(F, sep, ...) \ + Z_UTIL_LISTIFY_3128(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3128, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3130(F, sep, ...) \ + Z_UTIL_LISTIFY_3129(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3129, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3131(F, sep, ...) \ + Z_UTIL_LISTIFY_3130(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3130, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3132(F, sep, ...) \ + Z_UTIL_LISTIFY_3131(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3131, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3133(F, sep, ...) \ + Z_UTIL_LISTIFY_3132(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3132, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3134(F, sep, ...) \ + Z_UTIL_LISTIFY_3133(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3133, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3135(F, sep, ...) \ + Z_UTIL_LISTIFY_3134(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3134, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3136(F, sep, ...) \ + Z_UTIL_LISTIFY_3135(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3135, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3137(F, sep, ...) \ + Z_UTIL_LISTIFY_3136(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3136, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3138(F, sep, ...) \ + Z_UTIL_LISTIFY_3137(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3137, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3139(F, sep, ...) \ + Z_UTIL_LISTIFY_3138(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3138, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3140(F, sep, ...) \ + Z_UTIL_LISTIFY_3139(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3139, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3141(F, sep, ...) \ + Z_UTIL_LISTIFY_3140(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3140, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3142(F, sep, ...) \ + Z_UTIL_LISTIFY_3141(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3141, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3143(F, sep, ...) \ + Z_UTIL_LISTIFY_3142(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3142, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3144(F, sep, ...) \ + Z_UTIL_LISTIFY_3143(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3143, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3145(F, sep, ...) \ + Z_UTIL_LISTIFY_3144(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3144, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3146(F, sep, ...) \ + Z_UTIL_LISTIFY_3145(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3145, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3147(F, sep, ...) \ + Z_UTIL_LISTIFY_3146(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3146, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3148(F, sep, ...) \ + Z_UTIL_LISTIFY_3147(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3147, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3149(F, sep, ...) \ + Z_UTIL_LISTIFY_3148(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3148, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3150(F, sep, ...) \ + Z_UTIL_LISTIFY_3149(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3149, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3151(F, sep, ...) \ + Z_UTIL_LISTIFY_3150(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3150, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3152(F, sep, ...) \ + Z_UTIL_LISTIFY_3151(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3151, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3153(F, sep, ...) \ + Z_UTIL_LISTIFY_3152(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3152, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3154(F, sep, ...) \ + Z_UTIL_LISTIFY_3153(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3153, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3155(F, sep, ...) \ + Z_UTIL_LISTIFY_3154(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3154, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3156(F, sep, ...) \ + Z_UTIL_LISTIFY_3155(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3155, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3157(F, sep, ...) \ + Z_UTIL_LISTIFY_3156(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3156, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3158(F, sep, ...) \ + Z_UTIL_LISTIFY_3157(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3157, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3159(F, sep, ...) \ + Z_UTIL_LISTIFY_3158(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3158, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3160(F, sep, ...) \ + Z_UTIL_LISTIFY_3159(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3159, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3161(F, sep, ...) \ + Z_UTIL_LISTIFY_3160(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3160, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3162(F, sep, ...) \ + Z_UTIL_LISTIFY_3161(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3161, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3163(F, sep, ...) \ + Z_UTIL_LISTIFY_3162(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3162, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3164(F, sep, ...) \ + Z_UTIL_LISTIFY_3163(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3163, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3165(F, sep, ...) \ + Z_UTIL_LISTIFY_3164(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3164, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3166(F, sep, ...) \ + Z_UTIL_LISTIFY_3165(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3165, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3167(F, sep, ...) \ + Z_UTIL_LISTIFY_3166(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3166, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3168(F, sep, ...) \ + Z_UTIL_LISTIFY_3167(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3167, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3169(F, sep, ...) \ + Z_UTIL_LISTIFY_3168(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3168, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3170(F, sep, ...) \ + Z_UTIL_LISTIFY_3169(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3169, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3171(F, sep, ...) \ + Z_UTIL_LISTIFY_3170(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3170, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3172(F, sep, ...) \ + Z_UTIL_LISTIFY_3171(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3171, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3173(F, sep, ...) \ + Z_UTIL_LISTIFY_3172(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3172, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3174(F, sep, ...) \ + Z_UTIL_LISTIFY_3173(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3173, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3175(F, sep, ...) \ + Z_UTIL_LISTIFY_3174(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3174, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3176(F, sep, ...) \ + Z_UTIL_LISTIFY_3175(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3175, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3177(F, sep, ...) \ + Z_UTIL_LISTIFY_3176(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3176, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3178(F, sep, ...) \ + Z_UTIL_LISTIFY_3177(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3177, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3179(F, sep, ...) \ + Z_UTIL_LISTIFY_3178(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3178, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3180(F, sep, ...) \ + Z_UTIL_LISTIFY_3179(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3179, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3181(F, sep, ...) \ + Z_UTIL_LISTIFY_3180(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3180, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3182(F, sep, ...) \ + Z_UTIL_LISTIFY_3181(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3181, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3183(F, sep, ...) \ + Z_UTIL_LISTIFY_3182(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3182, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3184(F, sep, ...) \ + Z_UTIL_LISTIFY_3183(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3183, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3185(F, sep, ...) \ + Z_UTIL_LISTIFY_3184(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3184, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3186(F, sep, ...) \ + Z_UTIL_LISTIFY_3185(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3185, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3187(F, sep, ...) \ + Z_UTIL_LISTIFY_3186(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3186, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3188(F, sep, ...) \ + Z_UTIL_LISTIFY_3187(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3187, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3189(F, sep, ...) \ + Z_UTIL_LISTIFY_3188(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3188, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3190(F, sep, ...) \ + Z_UTIL_LISTIFY_3189(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3189, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3191(F, sep, ...) \ + Z_UTIL_LISTIFY_3190(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3190, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3192(F, sep, ...) \ + Z_UTIL_LISTIFY_3191(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3191, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3193(F, sep, ...) \ + Z_UTIL_LISTIFY_3192(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3192, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3194(F, sep, ...) \ + Z_UTIL_LISTIFY_3193(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3193, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3195(F, sep, ...) \ + Z_UTIL_LISTIFY_3194(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3194, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3196(F, sep, ...) \ + Z_UTIL_LISTIFY_3195(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3195, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3197(F, sep, ...) \ + Z_UTIL_LISTIFY_3196(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3196, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3198(F, sep, ...) \ + Z_UTIL_LISTIFY_3197(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3197, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3199(F, sep, ...) \ + Z_UTIL_LISTIFY_3198(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3198, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3200(F, sep, ...) \ + Z_UTIL_LISTIFY_3199(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3199, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3201(F, sep, ...) \ + Z_UTIL_LISTIFY_3200(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3200, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3202(F, sep, ...) \ + Z_UTIL_LISTIFY_3201(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3201, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3203(F, sep, ...) \ + Z_UTIL_LISTIFY_3202(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3202, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3204(F, sep, ...) \ + Z_UTIL_LISTIFY_3203(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3203, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3205(F, sep, ...) \ + Z_UTIL_LISTIFY_3204(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3204, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3206(F, sep, ...) \ + Z_UTIL_LISTIFY_3205(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3205, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3207(F, sep, ...) \ + Z_UTIL_LISTIFY_3206(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3206, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3208(F, sep, ...) \ + Z_UTIL_LISTIFY_3207(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3207, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3209(F, sep, ...) \ + Z_UTIL_LISTIFY_3208(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3208, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3210(F, sep, ...) \ + Z_UTIL_LISTIFY_3209(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3209, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3211(F, sep, ...) \ + Z_UTIL_LISTIFY_3210(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3210, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3212(F, sep, ...) \ + Z_UTIL_LISTIFY_3211(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3211, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3213(F, sep, ...) \ + Z_UTIL_LISTIFY_3212(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3212, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3214(F, sep, ...) \ + Z_UTIL_LISTIFY_3213(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3213, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3215(F, sep, ...) \ + Z_UTIL_LISTIFY_3214(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3214, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3216(F, sep, ...) \ + Z_UTIL_LISTIFY_3215(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3215, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3217(F, sep, ...) \ + Z_UTIL_LISTIFY_3216(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3216, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3218(F, sep, ...) \ + Z_UTIL_LISTIFY_3217(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3217, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3219(F, sep, ...) \ + Z_UTIL_LISTIFY_3218(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3218, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3220(F, sep, ...) \ + Z_UTIL_LISTIFY_3219(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3219, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3221(F, sep, ...) \ + Z_UTIL_LISTIFY_3220(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3220, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3222(F, sep, ...) \ + Z_UTIL_LISTIFY_3221(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3221, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3223(F, sep, ...) \ + Z_UTIL_LISTIFY_3222(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3222, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3224(F, sep, ...) \ + Z_UTIL_LISTIFY_3223(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3223, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3225(F, sep, ...) \ + Z_UTIL_LISTIFY_3224(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3224, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3226(F, sep, ...) \ + Z_UTIL_LISTIFY_3225(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3225, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3227(F, sep, ...) \ + Z_UTIL_LISTIFY_3226(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3226, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3228(F, sep, ...) \ + Z_UTIL_LISTIFY_3227(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3227, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3229(F, sep, ...) \ + Z_UTIL_LISTIFY_3228(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3228, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3230(F, sep, ...) \ + Z_UTIL_LISTIFY_3229(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3229, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3231(F, sep, ...) \ + Z_UTIL_LISTIFY_3230(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3230, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3232(F, sep, ...) \ + Z_UTIL_LISTIFY_3231(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3231, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3233(F, sep, ...) \ + Z_UTIL_LISTIFY_3232(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3232, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3234(F, sep, ...) \ + Z_UTIL_LISTIFY_3233(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3233, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3235(F, sep, ...) \ + Z_UTIL_LISTIFY_3234(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3234, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3236(F, sep, ...) \ + Z_UTIL_LISTIFY_3235(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3235, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3237(F, sep, ...) \ + Z_UTIL_LISTIFY_3236(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3236, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3238(F, sep, ...) \ + Z_UTIL_LISTIFY_3237(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3237, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3239(F, sep, ...) \ + Z_UTIL_LISTIFY_3238(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3238, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3240(F, sep, ...) \ + Z_UTIL_LISTIFY_3239(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3239, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3241(F, sep, ...) \ + Z_UTIL_LISTIFY_3240(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3240, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3242(F, sep, ...) \ + Z_UTIL_LISTIFY_3241(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3241, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3243(F, sep, ...) \ + Z_UTIL_LISTIFY_3242(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3242, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3244(F, sep, ...) \ + Z_UTIL_LISTIFY_3243(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3243, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3245(F, sep, ...) \ + Z_UTIL_LISTIFY_3244(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3244, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3246(F, sep, ...) \ + Z_UTIL_LISTIFY_3245(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3245, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3247(F, sep, ...) \ + Z_UTIL_LISTIFY_3246(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3246, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3248(F, sep, ...) \ + Z_UTIL_LISTIFY_3247(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3247, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3249(F, sep, ...) \ + Z_UTIL_LISTIFY_3248(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3248, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3250(F, sep, ...) \ + Z_UTIL_LISTIFY_3249(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3249, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3251(F, sep, ...) \ + Z_UTIL_LISTIFY_3250(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3250, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3252(F, sep, ...) \ + Z_UTIL_LISTIFY_3251(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3251, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3253(F, sep, ...) \ + Z_UTIL_LISTIFY_3252(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3252, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3254(F, sep, ...) \ + Z_UTIL_LISTIFY_3253(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3253, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3255(F, sep, ...) \ + Z_UTIL_LISTIFY_3254(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3254, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3256(F, sep, ...) \ + Z_UTIL_LISTIFY_3255(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3255, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3257(F, sep, ...) \ + Z_UTIL_LISTIFY_3256(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3256, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3258(F, sep, ...) \ + Z_UTIL_LISTIFY_3257(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3257, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3259(F, sep, ...) \ + Z_UTIL_LISTIFY_3258(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3258, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3260(F, sep, ...) \ + Z_UTIL_LISTIFY_3259(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3259, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3261(F, sep, ...) \ + Z_UTIL_LISTIFY_3260(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3260, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3262(F, sep, ...) \ + Z_UTIL_LISTIFY_3261(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3261, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3263(F, sep, ...) \ + Z_UTIL_LISTIFY_3262(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3262, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3264(F, sep, ...) \ + Z_UTIL_LISTIFY_3263(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3263, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3265(F, sep, ...) \ + Z_UTIL_LISTIFY_3264(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3264, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3266(F, sep, ...) \ + Z_UTIL_LISTIFY_3265(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3265, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3267(F, sep, ...) \ + Z_UTIL_LISTIFY_3266(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3266, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3268(F, sep, ...) \ + Z_UTIL_LISTIFY_3267(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3267, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3269(F, sep, ...) \ + Z_UTIL_LISTIFY_3268(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3268, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3270(F, sep, ...) \ + Z_UTIL_LISTIFY_3269(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3269, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3271(F, sep, ...) \ + Z_UTIL_LISTIFY_3270(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3270, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3272(F, sep, ...) \ + Z_UTIL_LISTIFY_3271(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3271, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3273(F, sep, ...) \ + Z_UTIL_LISTIFY_3272(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3272, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3274(F, sep, ...) \ + Z_UTIL_LISTIFY_3273(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3273, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3275(F, sep, ...) \ + Z_UTIL_LISTIFY_3274(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3274, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3276(F, sep, ...) \ + Z_UTIL_LISTIFY_3275(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3275, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3277(F, sep, ...) \ + Z_UTIL_LISTIFY_3276(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3276, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3278(F, sep, ...) \ + Z_UTIL_LISTIFY_3277(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3277, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3279(F, sep, ...) \ + Z_UTIL_LISTIFY_3278(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3278, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3280(F, sep, ...) \ + Z_UTIL_LISTIFY_3279(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3279, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3281(F, sep, ...) \ + Z_UTIL_LISTIFY_3280(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3280, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3282(F, sep, ...) \ + Z_UTIL_LISTIFY_3281(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3281, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3283(F, sep, ...) \ + Z_UTIL_LISTIFY_3282(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3282, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3284(F, sep, ...) \ + Z_UTIL_LISTIFY_3283(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3283, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3285(F, sep, ...) \ + Z_UTIL_LISTIFY_3284(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3284, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3286(F, sep, ...) \ + Z_UTIL_LISTIFY_3285(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3285, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3287(F, sep, ...) \ + Z_UTIL_LISTIFY_3286(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3286, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3288(F, sep, ...) \ + Z_UTIL_LISTIFY_3287(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3287, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3289(F, sep, ...) \ + Z_UTIL_LISTIFY_3288(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3288, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3290(F, sep, ...) \ + Z_UTIL_LISTIFY_3289(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3289, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3291(F, sep, ...) \ + Z_UTIL_LISTIFY_3290(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3290, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3292(F, sep, ...) \ + Z_UTIL_LISTIFY_3291(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3291, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3293(F, sep, ...) \ + Z_UTIL_LISTIFY_3292(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3292, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3294(F, sep, ...) \ + Z_UTIL_LISTIFY_3293(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3293, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3295(F, sep, ...) \ + Z_UTIL_LISTIFY_3294(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3294, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3296(F, sep, ...) \ + Z_UTIL_LISTIFY_3295(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3295, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3297(F, sep, ...) \ + Z_UTIL_LISTIFY_3296(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3296, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3298(F, sep, ...) \ + Z_UTIL_LISTIFY_3297(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3297, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3299(F, sep, ...) \ + Z_UTIL_LISTIFY_3298(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3298, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3300(F, sep, ...) \ + Z_UTIL_LISTIFY_3299(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3299, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3301(F, sep, ...) \ + Z_UTIL_LISTIFY_3300(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3300, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3302(F, sep, ...) \ + Z_UTIL_LISTIFY_3301(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3301, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3303(F, sep, ...) \ + Z_UTIL_LISTIFY_3302(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3302, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3304(F, sep, ...) \ + Z_UTIL_LISTIFY_3303(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3303, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3305(F, sep, ...) \ + Z_UTIL_LISTIFY_3304(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3304, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3306(F, sep, ...) \ + Z_UTIL_LISTIFY_3305(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3305, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3307(F, sep, ...) \ + Z_UTIL_LISTIFY_3306(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3306, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3308(F, sep, ...) \ + Z_UTIL_LISTIFY_3307(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3307, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3309(F, sep, ...) \ + Z_UTIL_LISTIFY_3308(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3308, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3310(F, sep, ...) \ + Z_UTIL_LISTIFY_3309(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3309, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3311(F, sep, ...) \ + Z_UTIL_LISTIFY_3310(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3310, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3312(F, sep, ...) \ + Z_UTIL_LISTIFY_3311(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3311, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3313(F, sep, ...) \ + Z_UTIL_LISTIFY_3312(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3312, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3314(F, sep, ...) \ + Z_UTIL_LISTIFY_3313(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3313, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3315(F, sep, ...) \ + Z_UTIL_LISTIFY_3314(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3314, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3316(F, sep, ...) \ + Z_UTIL_LISTIFY_3315(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3315, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3317(F, sep, ...) \ + Z_UTIL_LISTIFY_3316(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3316, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3318(F, sep, ...) \ + Z_UTIL_LISTIFY_3317(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3317, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3319(F, sep, ...) \ + Z_UTIL_LISTIFY_3318(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3318, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3320(F, sep, ...) \ + Z_UTIL_LISTIFY_3319(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3319, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3321(F, sep, ...) \ + Z_UTIL_LISTIFY_3320(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3320, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3322(F, sep, ...) \ + Z_UTIL_LISTIFY_3321(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3321, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3323(F, sep, ...) \ + Z_UTIL_LISTIFY_3322(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3322, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3324(F, sep, ...) \ + Z_UTIL_LISTIFY_3323(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3323, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3325(F, sep, ...) \ + Z_UTIL_LISTIFY_3324(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3324, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3326(F, sep, ...) \ + Z_UTIL_LISTIFY_3325(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3325, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3327(F, sep, ...) \ + Z_UTIL_LISTIFY_3326(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3326, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3328(F, sep, ...) \ + Z_UTIL_LISTIFY_3327(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3327, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3329(F, sep, ...) \ + Z_UTIL_LISTIFY_3328(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3328, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3330(F, sep, ...) \ + Z_UTIL_LISTIFY_3329(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3329, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3331(F, sep, ...) \ + Z_UTIL_LISTIFY_3330(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3330, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3332(F, sep, ...) \ + Z_UTIL_LISTIFY_3331(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3331, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3333(F, sep, ...) \ + Z_UTIL_LISTIFY_3332(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3332, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3334(F, sep, ...) \ + Z_UTIL_LISTIFY_3333(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3333, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3335(F, sep, ...) \ + Z_UTIL_LISTIFY_3334(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3334, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3336(F, sep, ...) \ + Z_UTIL_LISTIFY_3335(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3335, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3337(F, sep, ...) \ + Z_UTIL_LISTIFY_3336(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3336, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3338(F, sep, ...) \ + Z_UTIL_LISTIFY_3337(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3337, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3339(F, sep, ...) \ + Z_UTIL_LISTIFY_3338(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3338, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3340(F, sep, ...) \ + Z_UTIL_LISTIFY_3339(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3339, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3341(F, sep, ...) \ + Z_UTIL_LISTIFY_3340(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3340, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3342(F, sep, ...) \ + Z_UTIL_LISTIFY_3341(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3341, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3343(F, sep, ...) \ + Z_UTIL_LISTIFY_3342(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3342, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3344(F, sep, ...) \ + Z_UTIL_LISTIFY_3343(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3343, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3345(F, sep, ...) \ + Z_UTIL_LISTIFY_3344(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3344, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3346(F, sep, ...) \ + Z_UTIL_LISTIFY_3345(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3345, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3347(F, sep, ...) \ + Z_UTIL_LISTIFY_3346(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3346, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3348(F, sep, ...) \ + Z_UTIL_LISTIFY_3347(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3347, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3349(F, sep, ...) \ + Z_UTIL_LISTIFY_3348(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3348, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3350(F, sep, ...) \ + Z_UTIL_LISTIFY_3349(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3349, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3351(F, sep, ...) \ + Z_UTIL_LISTIFY_3350(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3350, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3352(F, sep, ...) \ + Z_UTIL_LISTIFY_3351(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3351, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3353(F, sep, ...) \ + Z_UTIL_LISTIFY_3352(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3352, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3354(F, sep, ...) \ + Z_UTIL_LISTIFY_3353(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3353, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3355(F, sep, ...) \ + Z_UTIL_LISTIFY_3354(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3354, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3356(F, sep, ...) \ + Z_UTIL_LISTIFY_3355(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3355, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3357(F, sep, ...) \ + Z_UTIL_LISTIFY_3356(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3356, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3358(F, sep, ...) \ + Z_UTIL_LISTIFY_3357(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3357, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3359(F, sep, ...) \ + Z_UTIL_LISTIFY_3358(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3358, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3360(F, sep, ...) \ + Z_UTIL_LISTIFY_3359(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3359, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3361(F, sep, ...) \ + Z_UTIL_LISTIFY_3360(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3360, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3362(F, sep, ...) \ + Z_UTIL_LISTIFY_3361(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3361, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3363(F, sep, ...) \ + Z_UTIL_LISTIFY_3362(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3362, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3364(F, sep, ...) \ + Z_UTIL_LISTIFY_3363(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3363, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3365(F, sep, ...) \ + Z_UTIL_LISTIFY_3364(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3364, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3366(F, sep, ...) \ + Z_UTIL_LISTIFY_3365(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3365, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3367(F, sep, ...) \ + Z_UTIL_LISTIFY_3366(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3366, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3368(F, sep, ...) \ + Z_UTIL_LISTIFY_3367(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3367, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3369(F, sep, ...) \ + Z_UTIL_LISTIFY_3368(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3368, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3370(F, sep, ...) \ + Z_UTIL_LISTIFY_3369(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3369, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3371(F, sep, ...) \ + Z_UTIL_LISTIFY_3370(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3370, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3372(F, sep, ...) \ + Z_UTIL_LISTIFY_3371(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3371, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3373(F, sep, ...) \ + Z_UTIL_LISTIFY_3372(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3372, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3374(F, sep, ...) \ + Z_UTIL_LISTIFY_3373(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3373, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3375(F, sep, ...) \ + Z_UTIL_LISTIFY_3374(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3374, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3376(F, sep, ...) \ + Z_UTIL_LISTIFY_3375(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3375, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3377(F, sep, ...) \ + Z_UTIL_LISTIFY_3376(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3376, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3378(F, sep, ...) \ + Z_UTIL_LISTIFY_3377(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3377, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3379(F, sep, ...) \ + Z_UTIL_LISTIFY_3378(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3378, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3380(F, sep, ...) \ + Z_UTIL_LISTIFY_3379(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3379, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3381(F, sep, ...) \ + Z_UTIL_LISTIFY_3380(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3380, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3382(F, sep, ...) \ + Z_UTIL_LISTIFY_3381(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3381, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3383(F, sep, ...) \ + Z_UTIL_LISTIFY_3382(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3382, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3384(F, sep, ...) \ + Z_UTIL_LISTIFY_3383(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3383, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3385(F, sep, ...) \ + Z_UTIL_LISTIFY_3384(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3384, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3386(F, sep, ...) \ + Z_UTIL_LISTIFY_3385(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3385, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3387(F, sep, ...) \ + Z_UTIL_LISTIFY_3386(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3386, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3388(F, sep, ...) \ + Z_UTIL_LISTIFY_3387(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3387, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3389(F, sep, ...) \ + Z_UTIL_LISTIFY_3388(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3388, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3390(F, sep, ...) \ + Z_UTIL_LISTIFY_3389(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3389, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3391(F, sep, ...) \ + Z_UTIL_LISTIFY_3390(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3390, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3392(F, sep, ...) \ + Z_UTIL_LISTIFY_3391(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3391, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3393(F, sep, ...) \ + Z_UTIL_LISTIFY_3392(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3392, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3394(F, sep, ...) \ + Z_UTIL_LISTIFY_3393(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3393, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3395(F, sep, ...) \ + Z_UTIL_LISTIFY_3394(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3394, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3396(F, sep, ...) \ + Z_UTIL_LISTIFY_3395(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3395, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3397(F, sep, ...) \ + Z_UTIL_LISTIFY_3396(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3396, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3398(F, sep, ...) \ + Z_UTIL_LISTIFY_3397(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3397, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3399(F, sep, ...) \ + Z_UTIL_LISTIFY_3398(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3398, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3400(F, sep, ...) \ + Z_UTIL_LISTIFY_3399(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3399, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3401(F, sep, ...) \ + Z_UTIL_LISTIFY_3400(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3400, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3402(F, sep, ...) \ + Z_UTIL_LISTIFY_3401(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3401, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3403(F, sep, ...) \ + Z_UTIL_LISTIFY_3402(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3402, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3404(F, sep, ...) \ + Z_UTIL_LISTIFY_3403(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3403, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3405(F, sep, ...) \ + Z_UTIL_LISTIFY_3404(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3404, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3406(F, sep, ...) \ + Z_UTIL_LISTIFY_3405(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3405, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3407(F, sep, ...) \ + Z_UTIL_LISTIFY_3406(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3406, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3408(F, sep, ...) \ + Z_UTIL_LISTIFY_3407(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3407, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3409(F, sep, ...) \ + Z_UTIL_LISTIFY_3408(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3408, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3410(F, sep, ...) \ + Z_UTIL_LISTIFY_3409(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3409, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3411(F, sep, ...) \ + Z_UTIL_LISTIFY_3410(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3410, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3412(F, sep, ...) \ + Z_UTIL_LISTIFY_3411(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3411, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3413(F, sep, ...) \ + Z_UTIL_LISTIFY_3412(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3412, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3414(F, sep, ...) \ + Z_UTIL_LISTIFY_3413(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3413, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3415(F, sep, ...) \ + Z_UTIL_LISTIFY_3414(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3414, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3416(F, sep, ...) \ + Z_UTIL_LISTIFY_3415(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3415, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3417(F, sep, ...) \ + Z_UTIL_LISTIFY_3416(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3416, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3418(F, sep, ...) \ + Z_UTIL_LISTIFY_3417(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3417, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3419(F, sep, ...) \ + Z_UTIL_LISTIFY_3418(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3418, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3420(F, sep, ...) \ + Z_UTIL_LISTIFY_3419(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3419, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3421(F, sep, ...) \ + Z_UTIL_LISTIFY_3420(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3420, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3422(F, sep, ...) \ + Z_UTIL_LISTIFY_3421(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3421, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3423(F, sep, ...) \ + Z_UTIL_LISTIFY_3422(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3422, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3424(F, sep, ...) \ + Z_UTIL_LISTIFY_3423(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3423, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3425(F, sep, ...) \ + Z_UTIL_LISTIFY_3424(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3424, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3426(F, sep, ...) \ + Z_UTIL_LISTIFY_3425(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3425, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3427(F, sep, ...) \ + Z_UTIL_LISTIFY_3426(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3426, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3428(F, sep, ...) \ + Z_UTIL_LISTIFY_3427(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3427, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3429(F, sep, ...) \ + Z_UTIL_LISTIFY_3428(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3428, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3430(F, sep, ...) \ + Z_UTIL_LISTIFY_3429(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3429, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3431(F, sep, ...) \ + Z_UTIL_LISTIFY_3430(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3430, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3432(F, sep, ...) \ + Z_UTIL_LISTIFY_3431(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3431, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3433(F, sep, ...) \ + Z_UTIL_LISTIFY_3432(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3432, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3434(F, sep, ...) \ + Z_UTIL_LISTIFY_3433(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3433, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3435(F, sep, ...) \ + Z_UTIL_LISTIFY_3434(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3434, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3436(F, sep, ...) \ + Z_UTIL_LISTIFY_3435(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3435, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3437(F, sep, ...) \ + Z_UTIL_LISTIFY_3436(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3436, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3438(F, sep, ...) \ + Z_UTIL_LISTIFY_3437(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3437, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3439(F, sep, ...) \ + Z_UTIL_LISTIFY_3438(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3438, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3440(F, sep, ...) \ + Z_UTIL_LISTIFY_3439(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3439, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3441(F, sep, ...) \ + Z_UTIL_LISTIFY_3440(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3440, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3442(F, sep, ...) \ + Z_UTIL_LISTIFY_3441(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3441, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3443(F, sep, ...) \ + Z_UTIL_LISTIFY_3442(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3442, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3444(F, sep, ...) \ + Z_UTIL_LISTIFY_3443(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3443, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3445(F, sep, ...) \ + Z_UTIL_LISTIFY_3444(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3444, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3446(F, sep, ...) \ + Z_UTIL_LISTIFY_3445(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3445, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3447(F, sep, ...) \ + Z_UTIL_LISTIFY_3446(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3446, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3448(F, sep, ...) \ + Z_UTIL_LISTIFY_3447(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3447, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3449(F, sep, ...) \ + Z_UTIL_LISTIFY_3448(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3448, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3450(F, sep, ...) \ + Z_UTIL_LISTIFY_3449(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3449, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3451(F, sep, ...) \ + Z_UTIL_LISTIFY_3450(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3450, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3452(F, sep, ...) \ + Z_UTIL_LISTIFY_3451(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3451, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3453(F, sep, ...) \ + Z_UTIL_LISTIFY_3452(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3452, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3454(F, sep, ...) \ + Z_UTIL_LISTIFY_3453(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3453, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3455(F, sep, ...) \ + Z_UTIL_LISTIFY_3454(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3454, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3456(F, sep, ...) \ + Z_UTIL_LISTIFY_3455(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3455, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3457(F, sep, ...) \ + Z_UTIL_LISTIFY_3456(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3456, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3458(F, sep, ...) \ + Z_UTIL_LISTIFY_3457(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3457, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3459(F, sep, ...) \ + Z_UTIL_LISTIFY_3458(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3458, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3460(F, sep, ...) \ + Z_UTIL_LISTIFY_3459(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3459, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3461(F, sep, ...) \ + Z_UTIL_LISTIFY_3460(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3460, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3462(F, sep, ...) \ + Z_UTIL_LISTIFY_3461(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3461, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3463(F, sep, ...) \ + Z_UTIL_LISTIFY_3462(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3462, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3464(F, sep, ...) \ + Z_UTIL_LISTIFY_3463(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3463, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3465(F, sep, ...) \ + Z_UTIL_LISTIFY_3464(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3464, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3466(F, sep, ...) \ + Z_UTIL_LISTIFY_3465(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3465, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3467(F, sep, ...) \ + Z_UTIL_LISTIFY_3466(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3466, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3468(F, sep, ...) \ + Z_UTIL_LISTIFY_3467(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3467, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3469(F, sep, ...) \ + Z_UTIL_LISTIFY_3468(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3468, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3470(F, sep, ...) \ + Z_UTIL_LISTIFY_3469(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3469, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3471(F, sep, ...) \ + Z_UTIL_LISTIFY_3470(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3470, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3472(F, sep, ...) \ + Z_UTIL_LISTIFY_3471(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3471, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3473(F, sep, ...) \ + Z_UTIL_LISTIFY_3472(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3472, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3474(F, sep, ...) \ + Z_UTIL_LISTIFY_3473(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3473, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3475(F, sep, ...) \ + Z_UTIL_LISTIFY_3474(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3474, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3476(F, sep, ...) \ + Z_UTIL_LISTIFY_3475(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3475, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3477(F, sep, ...) \ + Z_UTIL_LISTIFY_3476(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3476, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3478(F, sep, ...) \ + Z_UTIL_LISTIFY_3477(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3477, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3479(F, sep, ...) \ + Z_UTIL_LISTIFY_3478(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3478, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3480(F, sep, ...) \ + Z_UTIL_LISTIFY_3479(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3479, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3481(F, sep, ...) \ + Z_UTIL_LISTIFY_3480(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3480, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3482(F, sep, ...) \ + Z_UTIL_LISTIFY_3481(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3481, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3483(F, sep, ...) \ + Z_UTIL_LISTIFY_3482(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3482, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3484(F, sep, ...) \ + Z_UTIL_LISTIFY_3483(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3483, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3485(F, sep, ...) \ + Z_UTIL_LISTIFY_3484(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3484, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3486(F, sep, ...) \ + Z_UTIL_LISTIFY_3485(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3485, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3487(F, sep, ...) \ + Z_UTIL_LISTIFY_3486(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3486, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3488(F, sep, ...) \ + Z_UTIL_LISTIFY_3487(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3487, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3489(F, sep, ...) \ + Z_UTIL_LISTIFY_3488(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3488, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3490(F, sep, ...) \ + Z_UTIL_LISTIFY_3489(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3489, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3491(F, sep, ...) \ + Z_UTIL_LISTIFY_3490(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3490, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3492(F, sep, ...) \ + Z_UTIL_LISTIFY_3491(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3491, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3493(F, sep, ...) \ + Z_UTIL_LISTIFY_3492(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3492, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3494(F, sep, ...) \ + Z_UTIL_LISTIFY_3493(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3493, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3495(F, sep, ...) \ + Z_UTIL_LISTIFY_3494(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3494, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3496(F, sep, ...) \ + Z_UTIL_LISTIFY_3495(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3495, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3497(F, sep, ...) \ + Z_UTIL_LISTIFY_3496(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3496, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3498(F, sep, ...) \ + Z_UTIL_LISTIFY_3497(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3497, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3499(F, sep, ...) \ + Z_UTIL_LISTIFY_3498(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3498, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3500(F, sep, ...) \ + Z_UTIL_LISTIFY_3499(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3499, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3501(F, sep, ...) \ + Z_UTIL_LISTIFY_3500(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3500, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3502(F, sep, ...) \ + Z_UTIL_LISTIFY_3501(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3501, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3503(F, sep, ...) \ + Z_UTIL_LISTIFY_3502(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3502, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3504(F, sep, ...) \ + Z_UTIL_LISTIFY_3503(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3503, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3505(F, sep, ...) \ + Z_UTIL_LISTIFY_3504(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3504, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3506(F, sep, ...) \ + Z_UTIL_LISTIFY_3505(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3505, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3507(F, sep, ...) \ + Z_UTIL_LISTIFY_3506(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3506, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3508(F, sep, ...) \ + Z_UTIL_LISTIFY_3507(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3507, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3509(F, sep, ...) \ + Z_UTIL_LISTIFY_3508(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3508, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3510(F, sep, ...) \ + Z_UTIL_LISTIFY_3509(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3509, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3511(F, sep, ...) \ + Z_UTIL_LISTIFY_3510(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3510, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3512(F, sep, ...) \ + Z_UTIL_LISTIFY_3511(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3511, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3513(F, sep, ...) \ + Z_UTIL_LISTIFY_3512(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3512, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3514(F, sep, ...) \ + Z_UTIL_LISTIFY_3513(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3513, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3515(F, sep, ...) \ + Z_UTIL_LISTIFY_3514(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3514, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3516(F, sep, ...) \ + Z_UTIL_LISTIFY_3515(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3515, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3517(F, sep, ...) \ + Z_UTIL_LISTIFY_3516(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3516, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3518(F, sep, ...) \ + Z_UTIL_LISTIFY_3517(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3517, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3519(F, sep, ...) \ + Z_UTIL_LISTIFY_3518(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3518, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3520(F, sep, ...) \ + Z_UTIL_LISTIFY_3519(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3519, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3521(F, sep, ...) \ + Z_UTIL_LISTIFY_3520(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3520, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3522(F, sep, ...) \ + Z_UTIL_LISTIFY_3521(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3521, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3523(F, sep, ...) \ + Z_UTIL_LISTIFY_3522(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3522, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3524(F, sep, ...) \ + Z_UTIL_LISTIFY_3523(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3523, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3525(F, sep, ...) \ + Z_UTIL_LISTIFY_3524(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3524, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3526(F, sep, ...) \ + Z_UTIL_LISTIFY_3525(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3525, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3527(F, sep, ...) \ + Z_UTIL_LISTIFY_3526(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3526, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3528(F, sep, ...) \ + Z_UTIL_LISTIFY_3527(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3527, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3529(F, sep, ...) \ + Z_UTIL_LISTIFY_3528(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3528, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3530(F, sep, ...) \ + Z_UTIL_LISTIFY_3529(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3529, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3531(F, sep, ...) \ + Z_UTIL_LISTIFY_3530(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3530, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3532(F, sep, ...) \ + Z_UTIL_LISTIFY_3531(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3531, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3533(F, sep, ...) \ + Z_UTIL_LISTIFY_3532(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3532, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3534(F, sep, ...) \ + Z_UTIL_LISTIFY_3533(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3533, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3535(F, sep, ...) \ + Z_UTIL_LISTIFY_3534(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3534, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3536(F, sep, ...) \ + Z_UTIL_LISTIFY_3535(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3535, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3537(F, sep, ...) \ + Z_UTIL_LISTIFY_3536(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3536, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3538(F, sep, ...) \ + Z_UTIL_LISTIFY_3537(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3537, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3539(F, sep, ...) \ + Z_UTIL_LISTIFY_3538(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3538, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3540(F, sep, ...) \ + Z_UTIL_LISTIFY_3539(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3539, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3541(F, sep, ...) \ + Z_UTIL_LISTIFY_3540(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3540, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3542(F, sep, ...) \ + Z_UTIL_LISTIFY_3541(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3541, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3543(F, sep, ...) \ + Z_UTIL_LISTIFY_3542(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3542, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3544(F, sep, ...) \ + Z_UTIL_LISTIFY_3543(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3543, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3545(F, sep, ...) \ + Z_UTIL_LISTIFY_3544(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3544, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3546(F, sep, ...) \ + Z_UTIL_LISTIFY_3545(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3545, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3547(F, sep, ...) \ + Z_UTIL_LISTIFY_3546(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3546, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3548(F, sep, ...) \ + Z_UTIL_LISTIFY_3547(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3547, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3549(F, sep, ...) \ + Z_UTIL_LISTIFY_3548(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3548, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3550(F, sep, ...) \ + Z_UTIL_LISTIFY_3549(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3549, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3551(F, sep, ...) \ + Z_UTIL_LISTIFY_3550(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3550, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3552(F, sep, ...) \ + Z_UTIL_LISTIFY_3551(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3551, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3553(F, sep, ...) \ + Z_UTIL_LISTIFY_3552(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3552, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3554(F, sep, ...) \ + Z_UTIL_LISTIFY_3553(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3553, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3555(F, sep, ...) \ + Z_UTIL_LISTIFY_3554(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3554, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3556(F, sep, ...) \ + Z_UTIL_LISTIFY_3555(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3555, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3557(F, sep, ...) \ + Z_UTIL_LISTIFY_3556(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3556, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3558(F, sep, ...) \ + Z_UTIL_LISTIFY_3557(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3557, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3559(F, sep, ...) \ + Z_UTIL_LISTIFY_3558(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3558, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3560(F, sep, ...) \ + Z_UTIL_LISTIFY_3559(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3559, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3561(F, sep, ...) \ + Z_UTIL_LISTIFY_3560(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3560, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3562(F, sep, ...) \ + Z_UTIL_LISTIFY_3561(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3561, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3563(F, sep, ...) \ + Z_UTIL_LISTIFY_3562(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3562, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3564(F, sep, ...) \ + Z_UTIL_LISTIFY_3563(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3563, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3565(F, sep, ...) \ + Z_UTIL_LISTIFY_3564(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3564, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3566(F, sep, ...) \ + Z_UTIL_LISTIFY_3565(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3565, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3567(F, sep, ...) \ + Z_UTIL_LISTIFY_3566(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3566, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3568(F, sep, ...) \ + Z_UTIL_LISTIFY_3567(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3567, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3569(F, sep, ...) \ + Z_UTIL_LISTIFY_3568(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3568, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3570(F, sep, ...) \ + Z_UTIL_LISTIFY_3569(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3569, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3571(F, sep, ...) \ + Z_UTIL_LISTIFY_3570(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3570, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3572(F, sep, ...) \ + Z_UTIL_LISTIFY_3571(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3571, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3573(F, sep, ...) \ + Z_UTIL_LISTIFY_3572(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3572, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3574(F, sep, ...) \ + Z_UTIL_LISTIFY_3573(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3573, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3575(F, sep, ...) \ + Z_UTIL_LISTIFY_3574(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3574, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3576(F, sep, ...) \ + Z_UTIL_LISTIFY_3575(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3575, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3577(F, sep, ...) \ + Z_UTIL_LISTIFY_3576(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3576, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3578(F, sep, ...) \ + Z_UTIL_LISTIFY_3577(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3577, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3579(F, sep, ...) \ + Z_UTIL_LISTIFY_3578(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3578, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3580(F, sep, ...) \ + Z_UTIL_LISTIFY_3579(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3579, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3581(F, sep, ...) \ + Z_UTIL_LISTIFY_3580(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3580, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3582(F, sep, ...) \ + Z_UTIL_LISTIFY_3581(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3581, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3583(F, sep, ...) \ + Z_UTIL_LISTIFY_3582(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3582, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3584(F, sep, ...) \ + Z_UTIL_LISTIFY_3583(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3583, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3585(F, sep, ...) \ + Z_UTIL_LISTIFY_3584(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3584, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3586(F, sep, ...) \ + Z_UTIL_LISTIFY_3585(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3585, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3587(F, sep, ...) \ + Z_UTIL_LISTIFY_3586(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3586, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3588(F, sep, ...) \ + Z_UTIL_LISTIFY_3587(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3587, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3589(F, sep, ...) \ + Z_UTIL_LISTIFY_3588(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3588, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3590(F, sep, ...) \ + Z_UTIL_LISTIFY_3589(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3589, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3591(F, sep, ...) \ + Z_UTIL_LISTIFY_3590(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3590, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3592(F, sep, ...) \ + Z_UTIL_LISTIFY_3591(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3591, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3593(F, sep, ...) \ + Z_UTIL_LISTIFY_3592(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3592, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3594(F, sep, ...) \ + Z_UTIL_LISTIFY_3593(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3593, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3595(F, sep, ...) \ + Z_UTIL_LISTIFY_3594(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3594, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3596(F, sep, ...) \ + Z_UTIL_LISTIFY_3595(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3595, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3597(F, sep, ...) \ + Z_UTIL_LISTIFY_3596(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3596, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3598(F, sep, ...) \ + Z_UTIL_LISTIFY_3597(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3597, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3599(F, sep, ...) \ + Z_UTIL_LISTIFY_3598(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3598, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3600(F, sep, ...) \ + Z_UTIL_LISTIFY_3599(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3599, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3601(F, sep, ...) \ + Z_UTIL_LISTIFY_3600(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3600, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3602(F, sep, ...) \ + Z_UTIL_LISTIFY_3601(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3601, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3603(F, sep, ...) \ + Z_UTIL_LISTIFY_3602(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3602, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3604(F, sep, ...) \ + Z_UTIL_LISTIFY_3603(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3603, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3605(F, sep, ...) \ + Z_UTIL_LISTIFY_3604(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3604, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3606(F, sep, ...) \ + Z_UTIL_LISTIFY_3605(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3605, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3607(F, sep, ...) \ + Z_UTIL_LISTIFY_3606(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3606, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3608(F, sep, ...) \ + Z_UTIL_LISTIFY_3607(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3607, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3609(F, sep, ...) \ + Z_UTIL_LISTIFY_3608(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3608, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3610(F, sep, ...) \ + Z_UTIL_LISTIFY_3609(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3609, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3611(F, sep, ...) \ + Z_UTIL_LISTIFY_3610(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3610, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3612(F, sep, ...) \ + Z_UTIL_LISTIFY_3611(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3611, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3613(F, sep, ...) \ + Z_UTIL_LISTIFY_3612(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3612, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3614(F, sep, ...) \ + Z_UTIL_LISTIFY_3613(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3613, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3615(F, sep, ...) \ + Z_UTIL_LISTIFY_3614(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3614, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3616(F, sep, ...) \ + Z_UTIL_LISTIFY_3615(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3615, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3617(F, sep, ...) \ + Z_UTIL_LISTIFY_3616(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3616, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3618(F, sep, ...) \ + Z_UTIL_LISTIFY_3617(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3617, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3619(F, sep, ...) \ + Z_UTIL_LISTIFY_3618(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3618, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3620(F, sep, ...) \ + Z_UTIL_LISTIFY_3619(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3619, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3621(F, sep, ...) \ + Z_UTIL_LISTIFY_3620(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3620, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3622(F, sep, ...) \ + Z_UTIL_LISTIFY_3621(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3621, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3623(F, sep, ...) \ + Z_UTIL_LISTIFY_3622(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3622, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3624(F, sep, ...) \ + Z_UTIL_LISTIFY_3623(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3623, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3625(F, sep, ...) \ + Z_UTIL_LISTIFY_3624(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3624, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3626(F, sep, ...) \ + Z_UTIL_LISTIFY_3625(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3625, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3627(F, sep, ...) \ + Z_UTIL_LISTIFY_3626(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3626, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3628(F, sep, ...) \ + Z_UTIL_LISTIFY_3627(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3627, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3629(F, sep, ...) \ + Z_UTIL_LISTIFY_3628(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3628, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3630(F, sep, ...) \ + Z_UTIL_LISTIFY_3629(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3629, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3631(F, sep, ...) \ + Z_UTIL_LISTIFY_3630(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3630, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3632(F, sep, ...) \ + Z_UTIL_LISTIFY_3631(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3631, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3633(F, sep, ...) \ + Z_UTIL_LISTIFY_3632(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3632, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3634(F, sep, ...) \ + Z_UTIL_LISTIFY_3633(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3633, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3635(F, sep, ...) \ + Z_UTIL_LISTIFY_3634(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3634, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3636(F, sep, ...) \ + Z_UTIL_LISTIFY_3635(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3635, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3637(F, sep, ...) \ + Z_UTIL_LISTIFY_3636(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3636, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3638(F, sep, ...) \ + Z_UTIL_LISTIFY_3637(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3637, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3639(F, sep, ...) \ + Z_UTIL_LISTIFY_3638(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3638, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3640(F, sep, ...) \ + Z_UTIL_LISTIFY_3639(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3639, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3641(F, sep, ...) \ + Z_UTIL_LISTIFY_3640(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3640, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3642(F, sep, ...) \ + Z_UTIL_LISTIFY_3641(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3641, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3643(F, sep, ...) \ + Z_UTIL_LISTIFY_3642(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3642, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3644(F, sep, ...) \ + Z_UTIL_LISTIFY_3643(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3643, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3645(F, sep, ...) \ + Z_UTIL_LISTIFY_3644(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3644, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3646(F, sep, ...) \ + Z_UTIL_LISTIFY_3645(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3645, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3647(F, sep, ...) \ + Z_UTIL_LISTIFY_3646(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3646, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3648(F, sep, ...) \ + Z_UTIL_LISTIFY_3647(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3647, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3649(F, sep, ...) \ + Z_UTIL_LISTIFY_3648(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3648, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3650(F, sep, ...) \ + Z_UTIL_LISTIFY_3649(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3649, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3651(F, sep, ...) \ + Z_UTIL_LISTIFY_3650(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3650, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3652(F, sep, ...) \ + Z_UTIL_LISTIFY_3651(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3651, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3653(F, sep, ...) \ + Z_UTIL_LISTIFY_3652(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3652, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3654(F, sep, ...) \ + Z_UTIL_LISTIFY_3653(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3653, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3655(F, sep, ...) \ + Z_UTIL_LISTIFY_3654(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3654, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3656(F, sep, ...) \ + Z_UTIL_LISTIFY_3655(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3655, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3657(F, sep, ...) \ + Z_UTIL_LISTIFY_3656(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3656, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3658(F, sep, ...) \ + Z_UTIL_LISTIFY_3657(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3657, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3659(F, sep, ...) \ + Z_UTIL_LISTIFY_3658(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3658, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3660(F, sep, ...) \ + Z_UTIL_LISTIFY_3659(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3659, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3661(F, sep, ...) \ + Z_UTIL_LISTIFY_3660(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3660, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3662(F, sep, ...) \ + Z_UTIL_LISTIFY_3661(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3661, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3663(F, sep, ...) \ + Z_UTIL_LISTIFY_3662(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3662, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3664(F, sep, ...) \ + Z_UTIL_LISTIFY_3663(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3663, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3665(F, sep, ...) \ + Z_UTIL_LISTIFY_3664(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3664, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3666(F, sep, ...) \ + Z_UTIL_LISTIFY_3665(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3665, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3667(F, sep, ...) \ + Z_UTIL_LISTIFY_3666(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3666, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3668(F, sep, ...) \ + Z_UTIL_LISTIFY_3667(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3667, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3669(F, sep, ...) \ + Z_UTIL_LISTIFY_3668(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3668, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3670(F, sep, ...) \ + Z_UTIL_LISTIFY_3669(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3669, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3671(F, sep, ...) \ + Z_UTIL_LISTIFY_3670(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3670, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3672(F, sep, ...) \ + Z_UTIL_LISTIFY_3671(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3671, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3673(F, sep, ...) \ + Z_UTIL_LISTIFY_3672(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3672, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3674(F, sep, ...) \ + Z_UTIL_LISTIFY_3673(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3673, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3675(F, sep, ...) \ + Z_UTIL_LISTIFY_3674(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3674, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3676(F, sep, ...) \ + Z_UTIL_LISTIFY_3675(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3675, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3677(F, sep, ...) \ + Z_UTIL_LISTIFY_3676(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3676, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3678(F, sep, ...) \ + Z_UTIL_LISTIFY_3677(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3677, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3679(F, sep, ...) \ + Z_UTIL_LISTIFY_3678(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3678, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3680(F, sep, ...) \ + Z_UTIL_LISTIFY_3679(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3679, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3681(F, sep, ...) \ + Z_UTIL_LISTIFY_3680(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3680, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3682(F, sep, ...) \ + Z_UTIL_LISTIFY_3681(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3681, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3683(F, sep, ...) \ + Z_UTIL_LISTIFY_3682(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3682, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3684(F, sep, ...) \ + Z_UTIL_LISTIFY_3683(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3683, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3685(F, sep, ...) \ + Z_UTIL_LISTIFY_3684(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3684, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3686(F, sep, ...) \ + Z_UTIL_LISTIFY_3685(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3685, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3687(F, sep, ...) \ + Z_UTIL_LISTIFY_3686(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3686, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3688(F, sep, ...) \ + Z_UTIL_LISTIFY_3687(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3687, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3689(F, sep, ...) \ + Z_UTIL_LISTIFY_3688(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3688, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3690(F, sep, ...) \ + Z_UTIL_LISTIFY_3689(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3689, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3691(F, sep, ...) \ + Z_UTIL_LISTIFY_3690(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3690, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3692(F, sep, ...) \ + Z_UTIL_LISTIFY_3691(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3691, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3693(F, sep, ...) \ + Z_UTIL_LISTIFY_3692(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3692, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3694(F, sep, ...) \ + Z_UTIL_LISTIFY_3693(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3693, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3695(F, sep, ...) \ + Z_UTIL_LISTIFY_3694(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3694, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3696(F, sep, ...) \ + Z_UTIL_LISTIFY_3695(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3695, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3697(F, sep, ...) \ + Z_UTIL_LISTIFY_3696(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3696, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3698(F, sep, ...) \ + Z_UTIL_LISTIFY_3697(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3697, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3699(F, sep, ...) \ + Z_UTIL_LISTIFY_3698(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3698, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3700(F, sep, ...) \ + Z_UTIL_LISTIFY_3699(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3699, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3701(F, sep, ...) \ + Z_UTIL_LISTIFY_3700(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3700, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3702(F, sep, ...) \ + Z_UTIL_LISTIFY_3701(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3701, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3703(F, sep, ...) \ + Z_UTIL_LISTIFY_3702(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3702, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3704(F, sep, ...) \ + Z_UTIL_LISTIFY_3703(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3703, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3705(F, sep, ...) \ + Z_UTIL_LISTIFY_3704(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3704, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3706(F, sep, ...) \ + Z_UTIL_LISTIFY_3705(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3705, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3707(F, sep, ...) \ + Z_UTIL_LISTIFY_3706(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3706, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3708(F, sep, ...) \ + Z_UTIL_LISTIFY_3707(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3707, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3709(F, sep, ...) \ + Z_UTIL_LISTIFY_3708(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3708, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3710(F, sep, ...) \ + Z_UTIL_LISTIFY_3709(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3709, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3711(F, sep, ...) \ + Z_UTIL_LISTIFY_3710(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3710, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3712(F, sep, ...) \ + Z_UTIL_LISTIFY_3711(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3711, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3713(F, sep, ...) \ + Z_UTIL_LISTIFY_3712(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3712, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3714(F, sep, ...) \ + Z_UTIL_LISTIFY_3713(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3713, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3715(F, sep, ...) \ + Z_UTIL_LISTIFY_3714(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3714, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3716(F, sep, ...) \ + Z_UTIL_LISTIFY_3715(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3715, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3717(F, sep, ...) \ + Z_UTIL_LISTIFY_3716(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3716, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3718(F, sep, ...) \ + Z_UTIL_LISTIFY_3717(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3717, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3719(F, sep, ...) \ + Z_UTIL_LISTIFY_3718(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3718, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3720(F, sep, ...) \ + Z_UTIL_LISTIFY_3719(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3719, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3721(F, sep, ...) \ + Z_UTIL_LISTIFY_3720(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3720, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3722(F, sep, ...) \ + Z_UTIL_LISTIFY_3721(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3721, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3723(F, sep, ...) \ + Z_UTIL_LISTIFY_3722(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3722, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3724(F, sep, ...) \ + Z_UTIL_LISTIFY_3723(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3723, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3725(F, sep, ...) \ + Z_UTIL_LISTIFY_3724(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3724, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3726(F, sep, ...) \ + Z_UTIL_LISTIFY_3725(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3725, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3727(F, sep, ...) \ + Z_UTIL_LISTIFY_3726(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3726, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3728(F, sep, ...) \ + Z_UTIL_LISTIFY_3727(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3727, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3729(F, sep, ...) \ + Z_UTIL_LISTIFY_3728(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3728, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3730(F, sep, ...) \ + Z_UTIL_LISTIFY_3729(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3729, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3731(F, sep, ...) \ + Z_UTIL_LISTIFY_3730(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3730, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3732(F, sep, ...) \ + Z_UTIL_LISTIFY_3731(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3731, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3733(F, sep, ...) \ + Z_UTIL_LISTIFY_3732(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3732, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3734(F, sep, ...) \ + Z_UTIL_LISTIFY_3733(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3733, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3735(F, sep, ...) \ + Z_UTIL_LISTIFY_3734(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3734, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3736(F, sep, ...) \ + Z_UTIL_LISTIFY_3735(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3735, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3737(F, sep, ...) \ + Z_UTIL_LISTIFY_3736(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3736, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3738(F, sep, ...) \ + Z_UTIL_LISTIFY_3737(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3737, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3739(F, sep, ...) \ + Z_UTIL_LISTIFY_3738(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3738, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3740(F, sep, ...) \ + Z_UTIL_LISTIFY_3739(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3739, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3741(F, sep, ...) \ + Z_UTIL_LISTIFY_3740(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3740, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3742(F, sep, ...) \ + Z_UTIL_LISTIFY_3741(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3741, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3743(F, sep, ...) \ + Z_UTIL_LISTIFY_3742(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3742, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3744(F, sep, ...) \ + Z_UTIL_LISTIFY_3743(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3743, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3745(F, sep, ...) \ + Z_UTIL_LISTIFY_3744(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3744, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3746(F, sep, ...) \ + Z_UTIL_LISTIFY_3745(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3745, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3747(F, sep, ...) \ + Z_UTIL_LISTIFY_3746(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3746, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3748(F, sep, ...) \ + Z_UTIL_LISTIFY_3747(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3747, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3749(F, sep, ...) \ + Z_UTIL_LISTIFY_3748(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3748, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3750(F, sep, ...) \ + Z_UTIL_LISTIFY_3749(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3749, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3751(F, sep, ...) \ + Z_UTIL_LISTIFY_3750(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3750, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3752(F, sep, ...) \ + Z_UTIL_LISTIFY_3751(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3751, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3753(F, sep, ...) \ + Z_UTIL_LISTIFY_3752(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3752, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3754(F, sep, ...) \ + Z_UTIL_LISTIFY_3753(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3753, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3755(F, sep, ...) \ + Z_UTIL_LISTIFY_3754(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3754, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3756(F, sep, ...) \ + Z_UTIL_LISTIFY_3755(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3755, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3757(F, sep, ...) \ + Z_UTIL_LISTIFY_3756(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3756, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3758(F, sep, ...) \ + Z_UTIL_LISTIFY_3757(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3757, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3759(F, sep, ...) \ + Z_UTIL_LISTIFY_3758(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3758, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3760(F, sep, ...) \ + Z_UTIL_LISTIFY_3759(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3759, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3761(F, sep, ...) \ + Z_UTIL_LISTIFY_3760(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3760, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3762(F, sep, ...) \ + Z_UTIL_LISTIFY_3761(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3761, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3763(F, sep, ...) \ + Z_UTIL_LISTIFY_3762(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3762, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3764(F, sep, ...) \ + Z_UTIL_LISTIFY_3763(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3763, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3765(F, sep, ...) \ + Z_UTIL_LISTIFY_3764(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3764, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3766(F, sep, ...) \ + Z_UTIL_LISTIFY_3765(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3765, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3767(F, sep, ...) \ + Z_UTIL_LISTIFY_3766(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3766, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3768(F, sep, ...) \ + Z_UTIL_LISTIFY_3767(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3767, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3769(F, sep, ...) \ + Z_UTIL_LISTIFY_3768(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3768, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3770(F, sep, ...) \ + Z_UTIL_LISTIFY_3769(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3769, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3771(F, sep, ...) \ + Z_UTIL_LISTIFY_3770(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3770, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3772(F, sep, ...) \ + Z_UTIL_LISTIFY_3771(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3771, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3773(F, sep, ...) \ + Z_UTIL_LISTIFY_3772(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3772, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3774(F, sep, ...) \ + Z_UTIL_LISTIFY_3773(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3773, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3775(F, sep, ...) \ + Z_UTIL_LISTIFY_3774(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3774, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3776(F, sep, ...) \ + Z_UTIL_LISTIFY_3775(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3775, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3777(F, sep, ...) \ + Z_UTIL_LISTIFY_3776(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3776, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3778(F, sep, ...) \ + Z_UTIL_LISTIFY_3777(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3777, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3779(F, sep, ...) \ + Z_UTIL_LISTIFY_3778(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3778, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3780(F, sep, ...) \ + Z_UTIL_LISTIFY_3779(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3779, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3781(F, sep, ...) \ + Z_UTIL_LISTIFY_3780(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3780, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3782(F, sep, ...) \ + Z_UTIL_LISTIFY_3781(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3781, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3783(F, sep, ...) \ + Z_UTIL_LISTIFY_3782(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3782, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3784(F, sep, ...) \ + Z_UTIL_LISTIFY_3783(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3783, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3785(F, sep, ...) \ + Z_UTIL_LISTIFY_3784(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3784, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3786(F, sep, ...) \ + Z_UTIL_LISTIFY_3785(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3785, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3787(F, sep, ...) \ + Z_UTIL_LISTIFY_3786(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3786, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3788(F, sep, ...) \ + Z_UTIL_LISTIFY_3787(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3787, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3789(F, sep, ...) \ + Z_UTIL_LISTIFY_3788(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3788, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3790(F, sep, ...) \ + Z_UTIL_LISTIFY_3789(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3789, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3791(F, sep, ...) \ + Z_UTIL_LISTIFY_3790(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3790, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3792(F, sep, ...) \ + Z_UTIL_LISTIFY_3791(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3791, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3793(F, sep, ...) \ + Z_UTIL_LISTIFY_3792(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3792, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3794(F, sep, ...) \ + Z_UTIL_LISTIFY_3793(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3793, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3795(F, sep, ...) \ + Z_UTIL_LISTIFY_3794(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3794, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3796(F, sep, ...) \ + Z_UTIL_LISTIFY_3795(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3795, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3797(F, sep, ...) \ + Z_UTIL_LISTIFY_3796(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3796, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3798(F, sep, ...) \ + Z_UTIL_LISTIFY_3797(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3797, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3799(F, sep, ...) \ + Z_UTIL_LISTIFY_3798(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3798, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3800(F, sep, ...) \ + Z_UTIL_LISTIFY_3799(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3799, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3801(F, sep, ...) \ + Z_UTIL_LISTIFY_3800(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3800, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3802(F, sep, ...) \ + Z_UTIL_LISTIFY_3801(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3801, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3803(F, sep, ...) \ + Z_UTIL_LISTIFY_3802(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3802, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3804(F, sep, ...) \ + Z_UTIL_LISTIFY_3803(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3803, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3805(F, sep, ...) \ + Z_UTIL_LISTIFY_3804(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3804, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3806(F, sep, ...) \ + Z_UTIL_LISTIFY_3805(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3805, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3807(F, sep, ...) \ + Z_UTIL_LISTIFY_3806(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3806, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3808(F, sep, ...) \ + Z_UTIL_LISTIFY_3807(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3807, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3809(F, sep, ...) \ + Z_UTIL_LISTIFY_3808(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3808, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3810(F, sep, ...) \ + Z_UTIL_LISTIFY_3809(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3809, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3811(F, sep, ...) \ + Z_UTIL_LISTIFY_3810(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3810, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3812(F, sep, ...) \ + Z_UTIL_LISTIFY_3811(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3811, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3813(F, sep, ...) \ + Z_UTIL_LISTIFY_3812(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3812, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3814(F, sep, ...) \ + Z_UTIL_LISTIFY_3813(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3813, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3815(F, sep, ...) \ + Z_UTIL_LISTIFY_3814(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3814, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3816(F, sep, ...) \ + Z_UTIL_LISTIFY_3815(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3815, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3817(F, sep, ...) \ + Z_UTIL_LISTIFY_3816(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3816, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3818(F, sep, ...) \ + Z_UTIL_LISTIFY_3817(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3817, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3819(F, sep, ...) \ + Z_UTIL_LISTIFY_3818(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3818, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3820(F, sep, ...) \ + Z_UTIL_LISTIFY_3819(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3819, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3821(F, sep, ...) \ + Z_UTIL_LISTIFY_3820(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3820, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3822(F, sep, ...) \ + Z_UTIL_LISTIFY_3821(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3821, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3823(F, sep, ...) \ + Z_UTIL_LISTIFY_3822(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3822, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3824(F, sep, ...) \ + Z_UTIL_LISTIFY_3823(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3823, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3825(F, sep, ...) \ + Z_UTIL_LISTIFY_3824(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3824, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3826(F, sep, ...) \ + Z_UTIL_LISTIFY_3825(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3825, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3827(F, sep, ...) \ + Z_UTIL_LISTIFY_3826(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3826, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3828(F, sep, ...) \ + Z_UTIL_LISTIFY_3827(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3827, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3829(F, sep, ...) \ + Z_UTIL_LISTIFY_3828(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3828, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3830(F, sep, ...) \ + Z_UTIL_LISTIFY_3829(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3829, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3831(F, sep, ...) \ + Z_UTIL_LISTIFY_3830(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3830, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3832(F, sep, ...) \ + Z_UTIL_LISTIFY_3831(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3831, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3833(F, sep, ...) \ + Z_UTIL_LISTIFY_3832(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3832, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3834(F, sep, ...) \ + Z_UTIL_LISTIFY_3833(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3833, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3835(F, sep, ...) \ + Z_UTIL_LISTIFY_3834(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3834, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3836(F, sep, ...) \ + Z_UTIL_LISTIFY_3835(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3835, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3837(F, sep, ...) \ + Z_UTIL_LISTIFY_3836(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3836, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3838(F, sep, ...) \ + Z_UTIL_LISTIFY_3837(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3837, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3839(F, sep, ...) \ + Z_UTIL_LISTIFY_3838(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3838, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3840(F, sep, ...) \ + Z_UTIL_LISTIFY_3839(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3839, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3841(F, sep, ...) \ + Z_UTIL_LISTIFY_3840(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3840, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3842(F, sep, ...) \ + Z_UTIL_LISTIFY_3841(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3841, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3843(F, sep, ...) \ + Z_UTIL_LISTIFY_3842(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3842, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3844(F, sep, ...) \ + Z_UTIL_LISTIFY_3843(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3843, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3845(F, sep, ...) \ + Z_UTIL_LISTIFY_3844(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3844, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3846(F, sep, ...) \ + Z_UTIL_LISTIFY_3845(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3845, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3847(F, sep, ...) \ + Z_UTIL_LISTIFY_3846(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3846, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3848(F, sep, ...) \ + Z_UTIL_LISTIFY_3847(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3847, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3849(F, sep, ...) \ + Z_UTIL_LISTIFY_3848(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3848, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3850(F, sep, ...) \ + Z_UTIL_LISTIFY_3849(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3849, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3851(F, sep, ...) \ + Z_UTIL_LISTIFY_3850(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3850, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3852(F, sep, ...) \ + Z_UTIL_LISTIFY_3851(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3851, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3853(F, sep, ...) \ + Z_UTIL_LISTIFY_3852(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3852, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3854(F, sep, ...) \ + Z_UTIL_LISTIFY_3853(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3853, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3855(F, sep, ...) \ + Z_UTIL_LISTIFY_3854(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3854, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3856(F, sep, ...) \ + Z_UTIL_LISTIFY_3855(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3855, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3857(F, sep, ...) \ + Z_UTIL_LISTIFY_3856(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3856, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3858(F, sep, ...) \ + Z_UTIL_LISTIFY_3857(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3857, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3859(F, sep, ...) \ + Z_UTIL_LISTIFY_3858(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3858, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3860(F, sep, ...) \ + Z_UTIL_LISTIFY_3859(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3859, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3861(F, sep, ...) \ + Z_UTIL_LISTIFY_3860(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3860, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3862(F, sep, ...) \ + Z_UTIL_LISTIFY_3861(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3861, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3863(F, sep, ...) \ + Z_UTIL_LISTIFY_3862(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3862, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3864(F, sep, ...) \ + Z_UTIL_LISTIFY_3863(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3863, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3865(F, sep, ...) \ + Z_UTIL_LISTIFY_3864(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3864, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3866(F, sep, ...) \ + Z_UTIL_LISTIFY_3865(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3865, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3867(F, sep, ...) \ + Z_UTIL_LISTIFY_3866(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3866, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3868(F, sep, ...) \ + Z_UTIL_LISTIFY_3867(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3867, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3869(F, sep, ...) \ + Z_UTIL_LISTIFY_3868(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3868, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3870(F, sep, ...) \ + Z_UTIL_LISTIFY_3869(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3869, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3871(F, sep, ...) \ + Z_UTIL_LISTIFY_3870(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3870, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3872(F, sep, ...) \ + Z_UTIL_LISTIFY_3871(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3871, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3873(F, sep, ...) \ + Z_UTIL_LISTIFY_3872(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3872, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3874(F, sep, ...) \ + Z_UTIL_LISTIFY_3873(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3873, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3875(F, sep, ...) \ + Z_UTIL_LISTIFY_3874(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3874, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3876(F, sep, ...) \ + Z_UTIL_LISTIFY_3875(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3875, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3877(F, sep, ...) \ + Z_UTIL_LISTIFY_3876(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3876, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3878(F, sep, ...) \ + Z_UTIL_LISTIFY_3877(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3877, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3879(F, sep, ...) \ + Z_UTIL_LISTIFY_3878(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3878, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3880(F, sep, ...) \ + Z_UTIL_LISTIFY_3879(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3879, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3881(F, sep, ...) \ + Z_UTIL_LISTIFY_3880(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3880, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3882(F, sep, ...) \ + Z_UTIL_LISTIFY_3881(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3881, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3883(F, sep, ...) \ + Z_UTIL_LISTIFY_3882(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3882, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3884(F, sep, ...) \ + Z_UTIL_LISTIFY_3883(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3883, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3885(F, sep, ...) \ + Z_UTIL_LISTIFY_3884(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3884, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3886(F, sep, ...) \ + Z_UTIL_LISTIFY_3885(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3885, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3887(F, sep, ...) \ + Z_UTIL_LISTIFY_3886(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3886, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3888(F, sep, ...) \ + Z_UTIL_LISTIFY_3887(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3887, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3889(F, sep, ...) \ + Z_UTIL_LISTIFY_3888(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3888, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3890(F, sep, ...) \ + Z_UTIL_LISTIFY_3889(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3889, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3891(F, sep, ...) \ + Z_UTIL_LISTIFY_3890(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3890, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3892(F, sep, ...) \ + Z_UTIL_LISTIFY_3891(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3891, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3893(F, sep, ...) \ + Z_UTIL_LISTIFY_3892(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3892, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3894(F, sep, ...) \ + Z_UTIL_LISTIFY_3893(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3893, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3895(F, sep, ...) \ + Z_UTIL_LISTIFY_3894(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3894, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3896(F, sep, ...) \ + Z_UTIL_LISTIFY_3895(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3895, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3897(F, sep, ...) \ + Z_UTIL_LISTIFY_3896(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3896, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3898(F, sep, ...) \ + Z_UTIL_LISTIFY_3897(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3897, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3899(F, sep, ...) \ + Z_UTIL_LISTIFY_3898(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3898, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3900(F, sep, ...) \ + Z_UTIL_LISTIFY_3899(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3899, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3901(F, sep, ...) \ + Z_UTIL_LISTIFY_3900(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3900, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3902(F, sep, ...) \ + Z_UTIL_LISTIFY_3901(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3901, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3903(F, sep, ...) \ + Z_UTIL_LISTIFY_3902(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3902, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3904(F, sep, ...) \ + Z_UTIL_LISTIFY_3903(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3903, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3905(F, sep, ...) \ + Z_UTIL_LISTIFY_3904(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3904, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3906(F, sep, ...) \ + Z_UTIL_LISTIFY_3905(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3905, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3907(F, sep, ...) \ + Z_UTIL_LISTIFY_3906(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3906, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3908(F, sep, ...) \ + Z_UTIL_LISTIFY_3907(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3907, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3909(F, sep, ...) \ + Z_UTIL_LISTIFY_3908(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3908, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3910(F, sep, ...) \ + Z_UTIL_LISTIFY_3909(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3909, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3911(F, sep, ...) \ + Z_UTIL_LISTIFY_3910(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3910, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3912(F, sep, ...) \ + Z_UTIL_LISTIFY_3911(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3911, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3913(F, sep, ...) \ + Z_UTIL_LISTIFY_3912(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3912, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3914(F, sep, ...) \ + Z_UTIL_LISTIFY_3913(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3913, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3915(F, sep, ...) \ + Z_UTIL_LISTIFY_3914(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3914, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3916(F, sep, ...) \ + Z_UTIL_LISTIFY_3915(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3915, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3917(F, sep, ...) \ + Z_UTIL_LISTIFY_3916(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3916, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3918(F, sep, ...) \ + Z_UTIL_LISTIFY_3917(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3917, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3919(F, sep, ...) \ + Z_UTIL_LISTIFY_3918(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3918, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3920(F, sep, ...) \ + Z_UTIL_LISTIFY_3919(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3919, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3921(F, sep, ...) \ + Z_UTIL_LISTIFY_3920(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3920, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3922(F, sep, ...) \ + Z_UTIL_LISTIFY_3921(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3921, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3923(F, sep, ...) \ + Z_UTIL_LISTIFY_3922(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3922, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3924(F, sep, ...) \ + Z_UTIL_LISTIFY_3923(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3923, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3925(F, sep, ...) \ + Z_UTIL_LISTIFY_3924(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3924, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3926(F, sep, ...) \ + Z_UTIL_LISTIFY_3925(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3925, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3927(F, sep, ...) \ + Z_UTIL_LISTIFY_3926(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3926, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3928(F, sep, ...) \ + Z_UTIL_LISTIFY_3927(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3927, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3929(F, sep, ...) \ + Z_UTIL_LISTIFY_3928(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3928, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3930(F, sep, ...) \ + Z_UTIL_LISTIFY_3929(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3929, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3931(F, sep, ...) \ + Z_UTIL_LISTIFY_3930(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3930, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3932(F, sep, ...) \ + Z_UTIL_LISTIFY_3931(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3931, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3933(F, sep, ...) \ + Z_UTIL_LISTIFY_3932(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3932, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3934(F, sep, ...) \ + Z_UTIL_LISTIFY_3933(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3933, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3935(F, sep, ...) \ + Z_UTIL_LISTIFY_3934(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3934, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3936(F, sep, ...) \ + Z_UTIL_LISTIFY_3935(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3935, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3937(F, sep, ...) \ + Z_UTIL_LISTIFY_3936(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3936, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3938(F, sep, ...) \ + Z_UTIL_LISTIFY_3937(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3937, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3939(F, sep, ...) \ + Z_UTIL_LISTIFY_3938(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3938, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3940(F, sep, ...) \ + Z_UTIL_LISTIFY_3939(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3939, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3941(F, sep, ...) \ + Z_UTIL_LISTIFY_3940(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3940, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3942(F, sep, ...) \ + Z_UTIL_LISTIFY_3941(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3941, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3943(F, sep, ...) \ + Z_UTIL_LISTIFY_3942(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3942, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3944(F, sep, ...) \ + Z_UTIL_LISTIFY_3943(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3943, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3945(F, sep, ...) \ + Z_UTIL_LISTIFY_3944(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3944, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3946(F, sep, ...) \ + Z_UTIL_LISTIFY_3945(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3945, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3947(F, sep, ...) \ + Z_UTIL_LISTIFY_3946(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3946, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3948(F, sep, ...) \ + Z_UTIL_LISTIFY_3947(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3947, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3949(F, sep, ...) \ + Z_UTIL_LISTIFY_3948(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3948, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3950(F, sep, ...) \ + Z_UTIL_LISTIFY_3949(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3949, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3951(F, sep, ...) \ + Z_UTIL_LISTIFY_3950(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3950, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3952(F, sep, ...) \ + Z_UTIL_LISTIFY_3951(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3951, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3953(F, sep, ...) \ + Z_UTIL_LISTIFY_3952(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3952, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3954(F, sep, ...) \ + Z_UTIL_LISTIFY_3953(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3953, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3955(F, sep, ...) \ + Z_UTIL_LISTIFY_3954(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3954, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3956(F, sep, ...) \ + Z_UTIL_LISTIFY_3955(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3955, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3957(F, sep, ...) \ + Z_UTIL_LISTIFY_3956(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3956, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3958(F, sep, ...) \ + Z_UTIL_LISTIFY_3957(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3957, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3959(F, sep, ...) \ + Z_UTIL_LISTIFY_3958(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3958, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3960(F, sep, ...) \ + Z_UTIL_LISTIFY_3959(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3959, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3961(F, sep, ...) \ + Z_UTIL_LISTIFY_3960(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3960, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3962(F, sep, ...) \ + Z_UTIL_LISTIFY_3961(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3961, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3963(F, sep, ...) \ + Z_UTIL_LISTIFY_3962(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3962, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3964(F, sep, ...) \ + Z_UTIL_LISTIFY_3963(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3963, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3965(F, sep, ...) \ + Z_UTIL_LISTIFY_3964(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3964, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3966(F, sep, ...) \ + Z_UTIL_LISTIFY_3965(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3965, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3967(F, sep, ...) \ + Z_UTIL_LISTIFY_3966(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3966, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3968(F, sep, ...) \ + Z_UTIL_LISTIFY_3967(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3967, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3969(F, sep, ...) \ + Z_UTIL_LISTIFY_3968(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3968, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3970(F, sep, ...) \ + Z_UTIL_LISTIFY_3969(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3969, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3971(F, sep, ...) \ + Z_UTIL_LISTIFY_3970(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3970, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3972(F, sep, ...) \ + Z_UTIL_LISTIFY_3971(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3971, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3973(F, sep, ...) \ + Z_UTIL_LISTIFY_3972(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3972, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3974(F, sep, ...) \ + Z_UTIL_LISTIFY_3973(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3973, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3975(F, sep, ...) \ + Z_UTIL_LISTIFY_3974(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3974, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3976(F, sep, ...) \ + Z_UTIL_LISTIFY_3975(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3975, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3977(F, sep, ...) \ + Z_UTIL_LISTIFY_3976(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3976, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3978(F, sep, ...) \ + Z_UTIL_LISTIFY_3977(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3977, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3979(F, sep, ...) \ + Z_UTIL_LISTIFY_3978(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3978, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3980(F, sep, ...) \ + Z_UTIL_LISTIFY_3979(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3979, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3981(F, sep, ...) \ + Z_UTIL_LISTIFY_3980(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3980, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3982(F, sep, ...) \ + Z_UTIL_LISTIFY_3981(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3981, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3983(F, sep, ...) \ + Z_UTIL_LISTIFY_3982(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3982, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3984(F, sep, ...) \ + Z_UTIL_LISTIFY_3983(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3983, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3985(F, sep, ...) \ + Z_UTIL_LISTIFY_3984(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3984, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3986(F, sep, ...) \ + Z_UTIL_LISTIFY_3985(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3985, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3987(F, sep, ...) \ + Z_UTIL_LISTIFY_3986(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3986, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3988(F, sep, ...) \ + Z_UTIL_LISTIFY_3987(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3987, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3989(F, sep, ...) \ + Z_UTIL_LISTIFY_3988(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3988, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3990(F, sep, ...) \ + Z_UTIL_LISTIFY_3989(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3989, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3991(F, sep, ...) \ + Z_UTIL_LISTIFY_3990(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3990, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3992(F, sep, ...) \ + Z_UTIL_LISTIFY_3991(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3991, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3993(F, sep, ...) \ + Z_UTIL_LISTIFY_3992(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3992, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3994(F, sep, ...) \ + Z_UTIL_LISTIFY_3993(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3993, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3995(F, sep, ...) \ + Z_UTIL_LISTIFY_3994(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3994, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3996(F, sep, ...) \ + Z_UTIL_LISTIFY_3995(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3995, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3997(F, sep, ...) \ + Z_UTIL_LISTIFY_3996(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3996, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3998(F, sep, ...) \ + Z_UTIL_LISTIFY_3997(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3997, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_3999(F, sep, ...) \ + Z_UTIL_LISTIFY_3998(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3998, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4000(F, sep, ...) \ + Z_UTIL_LISTIFY_3999(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(3999, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4001(F, sep, ...) \ + Z_UTIL_LISTIFY_4000(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4000, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4002(F, sep, ...) \ + Z_UTIL_LISTIFY_4001(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4001, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4003(F, sep, ...) \ + Z_UTIL_LISTIFY_4002(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4002, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4004(F, sep, ...) \ + Z_UTIL_LISTIFY_4003(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4003, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4005(F, sep, ...) \ + Z_UTIL_LISTIFY_4004(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4004, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4006(F, sep, ...) \ + Z_UTIL_LISTIFY_4005(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4005, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4007(F, sep, ...) \ + Z_UTIL_LISTIFY_4006(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4006, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4008(F, sep, ...) \ + Z_UTIL_LISTIFY_4007(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4007, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4009(F, sep, ...) \ + Z_UTIL_LISTIFY_4008(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4008, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4010(F, sep, ...) \ + Z_UTIL_LISTIFY_4009(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4009, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4011(F, sep, ...) \ + Z_UTIL_LISTIFY_4010(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4010, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4012(F, sep, ...) \ + Z_UTIL_LISTIFY_4011(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4011, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4013(F, sep, ...) \ + Z_UTIL_LISTIFY_4012(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4012, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4014(F, sep, ...) \ + Z_UTIL_LISTIFY_4013(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4013, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4015(F, sep, ...) \ + Z_UTIL_LISTIFY_4014(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4014, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4016(F, sep, ...) \ + Z_UTIL_LISTIFY_4015(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4015, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4017(F, sep, ...) \ + Z_UTIL_LISTIFY_4016(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4016, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4018(F, sep, ...) \ + Z_UTIL_LISTIFY_4017(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4017, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4019(F, sep, ...) \ + Z_UTIL_LISTIFY_4018(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4018, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4020(F, sep, ...) \ + Z_UTIL_LISTIFY_4019(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4019, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4021(F, sep, ...) \ + Z_UTIL_LISTIFY_4020(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4020, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4022(F, sep, ...) \ + Z_UTIL_LISTIFY_4021(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4021, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4023(F, sep, ...) \ + Z_UTIL_LISTIFY_4022(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4022, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4024(F, sep, ...) \ + Z_UTIL_LISTIFY_4023(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4023, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4025(F, sep, ...) \ + Z_UTIL_LISTIFY_4024(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4024, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4026(F, sep, ...) \ + Z_UTIL_LISTIFY_4025(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4025, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4027(F, sep, ...) \ + Z_UTIL_LISTIFY_4026(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4026, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4028(F, sep, ...) \ + Z_UTIL_LISTIFY_4027(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4027, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4029(F, sep, ...) \ + Z_UTIL_LISTIFY_4028(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4028, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4030(F, sep, ...) \ + Z_UTIL_LISTIFY_4029(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4029, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4031(F, sep, ...) \ + Z_UTIL_LISTIFY_4030(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4030, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4032(F, sep, ...) \ + Z_UTIL_LISTIFY_4031(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4031, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4033(F, sep, ...) \ + Z_UTIL_LISTIFY_4032(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4032, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4034(F, sep, ...) \ + Z_UTIL_LISTIFY_4033(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4033, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4035(F, sep, ...) \ + Z_UTIL_LISTIFY_4034(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4034, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4036(F, sep, ...) \ + Z_UTIL_LISTIFY_4035(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4035, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4037(F, sep, ...) \ + Z_UTIL_LISTIFY_4036(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4036, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4038(F, sep, ...) \ + Z_UTIL_LISTIFY_4037(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4037, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4039(F, sep, ...) \ + Z_UTIL_LISTIFY_4038(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4038, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4040(F, sep, ...) \ + Z_UTIL_LISTIFY_4039(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4039, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4041(F, sep, ...) \ + Z_UTIL_LISTIFY_4040(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4040, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4042(F, sep, ...) \ + Z_UTIL_LISTIFY_4041(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4041, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4043(F, sep, ...) \ + Z_UTIL_LISTIFY_4042(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4042, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4044(F, sep, ...) \ + Z_UTIL_LISTIFY_4043(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4043, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4045(F, sep, ...) \ + Z_UTIL_LISTIFY_4044(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4044, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4046(F, sep, ...) \ + Z_UTIL_LISTIFY_4045(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4045, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4047(F, sep, ...) \ + Z_UTIL_LISTIFY_4046(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4046, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4048(F, sep, ...) \ + Z_UTIL_LISTIFY_4047(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4047, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4049(F, sep, ...) \ + Z_UTIL_LISTIFY_4048(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4048, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4050(F, sep, ...) \ + Z_UTIL_LISTIFY_4049(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4049, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4051(F, sep, ...) \ + Z_UTIL_LISTIFY_4050(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4050, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4052(F, sep, ...) \ + Z_UTIL_LISTIFY_4051(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4051, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4053(F, sep, ...) \ + Z_UTIL_LISTIFY_4052(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4052, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4054(F, sep, ...) \ + Z_UTIL_LISTIFY_4053(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4053, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4055(F, sep, ...) \ + Z_UTIL_LISTIFY_4054(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4054, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4056(F, sep, ...) \ + Z_UTIL_LISTIFY_4055(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4055, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4057(F, sep, ...) \ + Z_UTIL_LISTIFY_4056(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4056, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4058(F, sep, ...) \ + Z_UTIL_LISTIFY_4057(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4057, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4059(F, sep, ...) \ + Z_UTIL_LISTIFY_4058(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4058, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4060(F, sep, ...) \ + Z_UTIL_LISTIFY_4059(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4059, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4061(F, sep, ...) \ + Z_UTIL_LISTIFY_4060(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4060, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4062(F, sep, ...) \ + Z_UTIL_LISTIFY_4061(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4061, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4063(F, sep, ...) \ + Z_UTIL_LISTIFY_4062(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4062, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4064(F, sep, ...) \ + Z_UTIL_LISTIFY_4063(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4063, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4065(F, sep, ...) \ + Z_UTIL_LISTIFY_4064(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4064, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4066(F, sep, ...) \ + Z_UTIL_LISTIFY_4065(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4065, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4067(F, sep, ...) \ + Z_UTIL_LISTIFY_4066(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4066, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4068(F, sep, ...) \ + Z_UTIL_LISTIFY_4067(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4067, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4069(F, sep, ...) \ + Z_UTIL_LISTIFY_4068(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4068, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4070(F, sep, ...) \ + Z_UTIL_LISTIFY_4069(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4069, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4071(F, sep, ...) \ + Z_UTIL_LISTIFY_4070(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4070, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4072(F, sep, ...) \ + Z_UTIL_LISTIFY_4071(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4071, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4073(F, sep, ...) \ + Z_UTIL_LISTIFY_4072(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4072, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4074(F, sep, ...) \ + Z_UTIL_LISTIFY_4073(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4073, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4075(F, sep, ...) \ + Z_UTIL_LISTIFY_4074(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4074, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4076(F, sep, ...) \ + Z_UTIL_LISTIFY_4075(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4075, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4077(F, sep, ...) \ + Z_UTIL_LISTIFY_4076(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4076, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4078(F, sep, ...) \ + Z_UTIL_LISTIFY_4077(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4077, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4079(F, sep, ...) \ + Z_UTIL_LISTIFY_4078(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4078, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4080(F, sep, ...) \ + Z_UTIL_LISTIFY_4079(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4079, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4081(F, sep, ...) \ + Z_UTIL_LISTIFY_4080(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4080, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4082(F, sep, ...) \ + Z_UTIL_LISTIFY_4081(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4081, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4083(F, sep, ...) \ + Z_UTIL_LISTIFY_4082(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4082, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4084(F, sep, ...) \ + Z_UTIL_LISTIFY_4083(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4083, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4085(F, sep, ...) \ + Z_UTIL_LISTIFY_4084(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4084, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4086(F, sep, ...) \ + Z_UTIL_LISTIFY_4085(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4085, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4087(F, sep, ...) \ + Z_UTIL_LISTIFY_4086(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4086, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4088(F, sep, ...) \ + Z_UTIL_LISTIFY_4087(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4087, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4089(F, sep, ...) \ + Z_UTIL_LISTIFY_4088(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4088, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4090(F, sep, ...) \ + Z_UTIL_LISTIFY_4089(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4089, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4091(F, sep, ...) \ + Z_UTIL_LISTIFY_4090(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4090, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4092(F, sep, ...) \ + Z_UTIL_LISTIFY_4091(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4091, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4093(F, sep, ...) \ + Z_UTIL_LISTIFY_4092(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4092, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4094(F, sep, ...) \ + Z_UTIL_LISTIFY_4093(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4093, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4095(F, sep, ...) \ + Z_UTIL_LISTIFY_4094(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4094, __VA_ARGS__) + +#define Z_UTIL_LISTIFY_4096(F, sep, ...) \ + Z_UTIL_LISTIFY_4095(F, sep, __VA_ARGS__) __DEBRACKET sep \ + F(4095, __VA_ARGS__) + +#endif /* ZEPHYR_INCLUDE_SYS_UTIL_LISTIFY_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/sys/util_loops.h b/components/bt/esp_ble_audio/include/zephyr/sys/util_loops.h new file mode 100644 index 0000000000..5a6eee8e0d --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/sys/util_loops.h @@ -0,0 +1,1085 @@ +/* + * SPDX-FileCopyrightText: 2021 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Internals for looping macros + * + * Repetitive or obscure helper macros needed by sys/util.h. + */ + +#ifndef ZEPHYR_INCLUDE_SYS_UTIL_LOOPS_H_ +#define ZEPHYR_INCLUDE_SYS_UTIL_LOOPS_H_ + +#define Z_FOR_LOOP_GET_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, \ + _12, _13, _14, _15, _16, _17, _18, _19, _20, \ + _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, _34, _35, _36, _37, _38, \ + _39, _40, _41, _42, _43, _44, _45, _46, _47, \ + _48, _49, _50, _51, _52, _53, _54, _55, _56, \ + _57, _58, _59, _60, _61, _62, _63, _64, N, ...) N + +#define Z_FOR_LOOP_0(z_call, sep, fixed_arg0, fixed_arg1, ...) + +#define Z_FOR_LOOP_1(z_call, sep, fixed_arg0, fixed_arg1, x) \ + z_call(0, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_2(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_1(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(1, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_3(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_2(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(2, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_4(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_3(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(3, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_5(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_4(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(4, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_6(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_5(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(5, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_7(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_6(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(6, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_8(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_7(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(7, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_9(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_8(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(8, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_10(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_9(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(9, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_11(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_10(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(10, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_12(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_11(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(11, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_13(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_12(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(12, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_14(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_13(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(13, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_15(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_14(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(14, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_16(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_15(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(15, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_17(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_16(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(16, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_18(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_17(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(17, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_19(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_18(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(18, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_20(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_19(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(19, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_21(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_20(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(20, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_22(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_21(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(21, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_23(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_22(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(22, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_24(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_23(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(23, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_25(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_24(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(24, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_26(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_25(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(25, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_27(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_26(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(26, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_28(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_27(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(27, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_29(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_28(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(28, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_30(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_29(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(29, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_31(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_30(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(30, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_32(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_31(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(31, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_33(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_32(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(32, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_34(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_33(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(33, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_35(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_34(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(34, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_36(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_35(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(35, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_37(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_36(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(36, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_38(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_37(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(37, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_39(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_38(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(38, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_40(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_39(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(39, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_41(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_40(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(40, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_42(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_41(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(41, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_43(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_42(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(42, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_44(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_43(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(43, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_45(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_44(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(44, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_46(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_45(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(45, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_47(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_46(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(46, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_48(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_47(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(47, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_49(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_48(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(48, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_50(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_49(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(49, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_51(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_50(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(50, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_52(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_51(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(51, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_53(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_52(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(52, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_54(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_53(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(53, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_55(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_54(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(54, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_56(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_55(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(55, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_57(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_56(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(56, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_58(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_57(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(57, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_59(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_58(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(58, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_60(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_59(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(59, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_61(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_60(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(60, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_62(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_61(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(61, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_63(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_62(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(62, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_LOOP_64(z_call, sep, fixed_arg0, fixed_arg1, x, ...) \ + Z_FOR_LOOP_63(z_call, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) \ + __DEBRACKET sep \ + z_call(63, x, fixed_arg0, fixed_arg1) + +#define Z_FOR_EACH_ENGINE(x, sep, fixed_arg0, fixed_arg1, ...) \ + Z_FOR_LOOP_GET_ARG(__VA_ARGS__, \ + Z_FOR_LOOP_64, \ + Z_FOR_LOOP_63, \ + Z_FOR_LOOP_62, \ + Z_FOR_LOOP_61, \ + Z_FOR_LOOP_60, \ + Z_FOR_LOOP_59, \ + Z_FOR_LOOP_58, \ + Z_FOR_LOOP_57, \ + Z_FOR_LOOP_56, \ + Z_FOR_LOOP_55, \ + Z_FOR_LOOP_54, \ + Z_FOR_LOOP_53, \ + Z_FOR_LOOP_52, \ + Z_FOR_LOOP_51, \ + Z_FOR_LOOP_50, \ + Z_FOR_LOOP_49, \ + Z_FOR_LOOP_48, \ + Z_FOR_LOOP_47, \ + Z_FOR_LOOP_46, \ + Z_FOR_LOOP_45, \ + Z_FOR_LOOP_44, \ + Z_FOR_LOOP_43, \ + Z_FOR_LOOP_42, \ + Z_FOR_LOOP_41, \ + Z_FOR_LOOP_40, \ + Z_FOR_LOOP_39, \ + Z_FOR_LOOP_38, \ + Z_FOR_LOOP_37, \ + Z_FOR_LOOP_36, \ + Z_FOR_LOOP_35, \ + Z_FOR_LOOP_34, \ + Z_FOR_LOOP_33, \ + Z_FOR_LOOP_32, \ + Z_FOR_LOOP_31, \ + Z_FOR_LOOP_30, \ + Z_FOR_LOOP_29, \ + Z_FOR_LOOP_28, \ + Z_FOR_LOOP_27, \ + Z_FOR_LOOP_26, \ + Z_FOR_LOOP_25, \ + Z_FOR_LOOP_24, \ + Z_FOR_LOOP_23, \ + Z_FOR_LOOP_22, \ + Z_FOR_LOOP_21, \ + Z_FOR_LOOP_20, \ + Z_FOR_LOOP_19, \ + Z_FOR_LOOP_18, \ + Z_FOR_LOOP_17, \ + Z_FOR_LOOP_16, \ + Z_FOR_LOOP_15, \ + Z_FOR_LOOP_14, \ + Z_FOR_LOOP_13, \ + Z_FOR_LOOP_12, \ + Z_FOR_LOOP_11, \ + Z_FOR_LOOP_10, \ + Z_FOR_LOOP_9, \ + Z_FOR_LOOP_8, \ + Z_FOR_LOOP_7, \ + Z_FOR_LOOP_6, \ + Z_FOR_LOOP_5, \ + Z_FOR_LOOP_4, \ + Z_FOR_LOOP_3, \ + Z_FOR_LOOP_2, \ + Z_FOR_LOOP_1, \ + Z_FOR_LOOP_0)(x, sep, fixed_arg0, fixed_arg1, __VA_ARGS__) + +#define Z_GET_ARG_1(_0, ...) _0 + +#define Z_GET_ARG_2(_0, _1, ...) _1 + +#define Z_GET_ARG_3(_0, _1, _2, ...) _2 + +#define Z_GET_ARG_4(_0, _1, _2, _3, ...) _3 + +#define Z_GET_ARG_5(_0, _1, _2, _3, _4, ...) _4 + +#define Z_GET_ARG_6(_0, _1, _2, _3, _4, _5, ...) _5 + +#define Z_GET_ARG_7(_0, _1, _2, _3, _4, _5, _6, ...) _6 + +#define Z_GET_ARG_8(_0, _1, _2, _3, _4, _5, _6, _7, ...) _7 + +#define Z_GET_ARG_9(_0, _1, _2, _3, _4, _5, _6, _7, _8, ...) _8 + +#define Z_GET_ARG_10(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, ...) _9 + +#define Z_GET_ARG_11(_0, _1, _2, _3, _4, _5, \ + _6, _7, _8, _9, _10, ...) _10 + +#define Z_GET_ARG_12(_0, _1, _2, _3, _4, _5, _6,\ + _7, _8, _9, _10, _11, ...) _11 + +#define Z_GET_ARG_13(_0, _1, _2, _3, _4, _5, _6, \ + _7, _8, _9, _10, _11, _12, ...) _12 + +#define Z_GET_ARG_14(_0, _1, _2, _3, _4, _5, _6, \ + _7, _8, _9, _10, _11, _12, _13, ...) _13 + +#define Z_GET_ARG_15(_0, _1, _2, _3, _4, _5, _6, _7, \ + _8, _9, _10, _11, _12, _13, _14, ...) _14 + +#define Z_GET_ARG_16(_0, _1, _2, _3, _4, _5, _6, _7, \ + _8, _9, _10, _11, _12, _13, _14, _15, ...) _15 + +#define Z_GET_ARG_17(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, ...) _16 + +#define Z_GET_ARG_18(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, ...) _17 + +#define Z_GET_ARG_19(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, ...) _18 + +#define Z_GET_ARG_20(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + ...) _19 + +#define Z_GET_ARG_21(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, ...) _20 + +#define Z_GET_ARG_22(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, ...) _21 + +#define Z_GET_ARG_23(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, ...) _22 + +#define Z_GET_ARG_24(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, ...) _23 + +#define Z_GET_ARG_25(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, ...) _24 + +#define Z_GET_ARG_26(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, ...) _25 + +#define Z_GET_ARG_27(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, ...) _26 + +#define Z_GET_ARG_28(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, ...) _27 + +#define Z_GET_ARG_29(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + ...) _28 + +#define Z_GET_ARG_30(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, ...) _29 + +#define Z_GET_ARG_31(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, ...) _30 + +#define Z_GET_ARG_32(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, ...) _31 + +#define Z_GET_ARG_33(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, ...) _32 + +#define Z_GET_ARG_34(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, ...) _33 + +#define Z_GET_ARG_35(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, ...) _34 + +#define Z_GET_ARG_36(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, ...) _35 + +#define Z_GET_ARG_37(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, ...) _36 + +#define Z_GET_ARG_38(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, ...) _37 + +#define Z_GET_ARG_39(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, ...) _38 + +#define Z_GET_ARG_40(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, ...) _39 + +#define Z_GET_ARG_41(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, ...) _40 + +#define Z_GET_ARG_42(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, ...) _41 + +#define Z_GET_ARG_43(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, ...) _42 + +#define Z_GET_ARG_44(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, ...) _43 + +#define Z_GET_ARG_45(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, ...) _44 + +#define Z_GET_ARG_46(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, ...) _45 + +#define Z_GET_ARG_47(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, ...) _46 + +#define Z_GET_ARG_48(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, ...) _47 + +#define Z_GET_ARG_49(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, ...) _48 + +#define Z_GET_ARG_50(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, _49, ...) _49 + +#define Z_GET_ARG_51(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, _49, _50, ...) _50 + +#define Z_GET_ARG_52(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, _49, _50, _51, ...) _51 + +#define Z_GET_ARG_53(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, _49, _50, _51, _52, ...) _52 + +#define Z_GET_ARG_54(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, _49, _50, _51, _52, _53, ...) _53 + +#define Z_GET_ARG_55(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, _49, _50, _51, _52, _53, _54, ...) _54 + +#define Z_GET_ARG_56(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, _49, _50, _51, _52, _53, _54, _55, ...) _55 + +#define Z_GET_ARG_57(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, _49, _50, _51, _52, _53, _54, _55, \ + _56, ...) _56 + +#define Z_GET_ARG_58(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, _49, _50, _51, _52, _53, _54, _55, \ + _56, _57, ...) _57 + +#define Z_GET_ARG_59(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, _49, _50, _51, _52, _53, _54, _55, \ + _56, _57, _58, ...) _58 + +#define Z_GET_ARG_60(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, _49, _50, _51, _52, _53, _54, _55, \ + _56, _57, _58, _59, ...) _59 + +#define Z_GET_ARG_61(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, _49, _50, _51, _52, _53, _54, _55, \ + _56, _57, _58, _59, _60, ...) _60 + +#define Z_GET_ARG_62(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, _49, _50, _51, _52, _53, _54, _55, \ + _56, _57, _58, _59, _60, _61, ...) _61 + +#define Z_GET_ARG_63(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, _49, _50, _51, _52, _53, _54, _55, \ + _56, _57, _58, _59, _60, _61, _62, ...) _62 + +#define Z_GET_ARG_64(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, _49, _50, _51, _52, _53, _54, _55, \ + _56, _57, _58, _59, _60, _61, _62, _63, ...) _63 + +#define Z_GET_ARGS_LESS_0(...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_1(_0, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_2(_0, _1, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_3(_0, _1, _2, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_4(_0, _1, _2, _3, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_5(_0, _1, _2, _3, _4, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_6(_0, _1, _2, _3, _4, _5, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_7(_0, _1, _2, _3, _4, _5, _6, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_8(_0, _1, _2, _3, _4, _5, \ + _6, _7, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_9(_0, _1, _2, _3, _4, _5, \ + _6, _7, _8, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_10(_0, _1, _2, _3, _4, _5, \ + _6, _7, _8, _9, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_11(_0, _1, _2, _3, _4, _5, \ + _6, _7, _8, _9, _10, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_12(_0, _1, _2, _3, _4, _5, _6,\ + _7, _8, _9, _10, _11, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_13(_0, _1, _2, _3, _4, _5, _6, \ + _7, _8, _9, _10, _11, _12, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_14(_0, _1, _2, _3, _4, _5, _6, \ + _7, _8, _9, _10, _11, _12, _13, \ + ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_15(_0, _1, _2, _3, _4, _5, _6, _7, \ + _8, _9, _10, _11, _12, _13, _14, \ + ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_16(_0, _1, _2, _3, _4, _5, _6, _7, \ + _8, _9, _10, _11, _12, _13, _14, _15, ...) \ + __VA_ARGS__ + +#define Z_GET_ARGS_LESS_17(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_18(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, ...) \ + __VA_ARGS__ + +#define Z_GET_ARGS_LESS_19(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, ...) \ + __VA_ARGS__ + +#define Z_GET_ARGS_LESS_20(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_21(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_22(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_23(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_24(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_25(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_26(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_27(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, ...) \ + __VA_ARGS__ + +#define Z_GET_ARGS_LESS_28(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, \ + ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_29(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_30(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_31(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_32(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_33(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_34(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_35(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_36(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_37(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_38(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_39(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_40(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_41(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_42(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_43(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_44(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_45(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_46(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_47(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_48(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_49(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_50(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, _49, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_51(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, _49, _50, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_52(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, _49, _50, _51, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_53(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, _49, _50, _51, _52, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_54(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, _49, _50, _51, _52, _53, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_55(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, _49, _50, _51, _52, _53, _54, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_56(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, _49, _50, _51, _52, _53, _54, _55, \ + ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_57(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, _49, _50, _51, _52, _53, _54, _55, \ + _56, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_58(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, _49, _50, _51, _52, _53, _54, _55, \ + _56, _57, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_59(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, _49, _50, _51, _52, _53, _54, _55, \ + _56, _57, _58, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_60(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, _49, _50, _51, _52, _53, _54, _55, \ + _56, _57, _58, _59, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_61(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, _49, _50, _51, _52, _53, _54, _55, \ + _56, _57, _58, _59, _60, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_62(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, _49, _50, _51, _52, _53, _54, _55, \ + _56, _57, _58, _59, _60, _61, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_63(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, _49, _50, _51, _52, _53, _54, _55, \ + _56, _57, _58, _59, _60, _61, _62, ...) __VA_ARGS__ + +#define Z_GET_ARGS_LESS_64(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, \ + _29, _30, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, _49, _50, _51, _52, _53, _54, _55, \ + _56, _57, _58, _59, _60, _61, _62, _63, ...) __VA_ARGS__ + +#define Z_FOR_EACH_IDX_FIXED_ARG_EXEC(idx, x, fixed_arg0, fixed_arg1) \ + fixed_arg0(idx, x, fixed_arg1) + +#define Z_FOR_EACH_IDX_FIXED_ARG(F, sep, fixed_arg, ...) \ + Z_FOR_EACH_ENGINE(Z_FOR_EACH_IDX_FIXED_ARG_EXEC, sep, \ + F, fixed_arg, __VA_ARGS__) + +#define Z_FOR_EACH_FIXED_ARG_EXEC(idx, x, fixed_arg0, fixed_arg1) \ + fixed_arg0(x, fixed_arg1) + +#define Z_FOR_EACH_FIXED_ARG(F, sep, fixed_arg, ...) \ + Z_FOR_EACH_ENGINE(Z_FOR_EACH_FIXED_ARG_EXEC, sep, \ + F, fixed_arg, __VA_ARGS__) + +#define Z_FOR_EACH_IDX_EXEC(idx, x, fixed_arg0, fixed_arg1) \ + fixed_arg0(idx, x) + +#define Z_FOR_EACH_IDX(F, sep, ...) \ + Z_FOR_EACH_ENGINE(Z_FOR_EACH_IDX_EXEC, sep, F, _, __VA_ARGS__) + +#define Z_FOR_EACH_EXEC(idx, x, fixed_arg0, fixed_arg1) \ + fixed_arg0(x) + +#define Z_FOR_EACH(F, sep, ...) \ + Z_FOR_EACH_ENGINE(Z_FOR_EACH_EXEC, sep, F, _, __VA_ARGS__) + +#define Z_BYPASS(x) x + +/* Set of UTIL_LISTIFY particles */ +#include "util_listify.h" + +#endif /* ZEPHYR_INCLUDE_SYS_UTIL_LOOPS_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/sys/util_macro.h b/components/bt/esp_ble_audio/include/zephyr/sys/util_macro.h new file mode 100644 index 0000000000..e8542688a1 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/sys/util_macro.h @@ -0,0 +1,733 @@ +/* + * SPDX-FileCopyrightText: 2011-2014 Wind River Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Macro utilities + * + * Macro utilities are the public interface for C/C++ code and device tree + * related implementation. In general, C/C++ will include + * instead this file directly. For device tree implementation, this file + * should be include instead + */ + +#ifndef ZEPHYR_INCLUDE_SYS_UTIL_MACROS_H_ +#define ZEPHYR_INCLUDE_SYS_UTIL_MACROS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup sys-util + * @{ + */ + +/* + * Most of the eldritch implementation details for all the macrobatics + * below (APIs like IS_ENABLED(), COND_CODE_1(), etc.) are hidden away + * in this file. + */ +#include + +#ifndef BIT +#if defined(_ASMLANGUAGE) +#define BIT(n) (1 << (n)) +#else +/** + * @brief Unsigned integer with bit position @p n set (signed in + * assembly language). + */ +#define BIT(n) (1UL << (n)) +#endif +#endif + +#ifndef BIT64 +/** @brief 64-bit unsigned integer with bit position @p _n set. */ +#define BIT64(_n) (1ULL << (_n)) +#endif + +/** + * @brief Set or clear a bit depending on a boolean value + * + * The argument @p var is a variable whose value is written to as a + * side effect. + * + * @param var Variable to be altered + * @param bit Bit number + * @param set if 0, clears @p bit in @p var; any other value sets @p bit + */ +#define WRITE_BIT(var, bit, set) \ + ((var) = (set) ? ((var) | BIT(bit)) : ((var) & ~BIT(bit))) + +/** + * @brief Bit mask with bits 0 through n-1 (inclusive) set, + * or 0 if @p n is 0. + */ +#define BIT_MASK(n) (BIT(n) - 1UL) + +/** + * @brief 64-bit bit mask with bits 0 through n-1 (inclusive) set, + * or 0 if @p n is 0. + */ +#define BIT64_MASK(n) (BIT64(n) - 1ULL) + +/** @brief Check if a @p x is a power of two */ +#define IS_POWER_OF_TWO(x) (((x) != 0U) && (((x) & ((x) - 1U)) == 0U)) + +/** + * @brief Check if bits are set continuously from the specified bit + * + * The macro is not dependent on the bit-width. + * + * @param m Check whether the bits are set continuously or not. + * @param s Specify the lowest bit for that is continuously set bits. + */ +#define IS_SHIFTED_BIT_MASK(m, s) (!(((m) >> (s)) & (((m) >> (s)) + 1U))) + +/** + * @brief Check if bits are set continuously from the LSB. + * + * @param m Check whether the bits are set continuously from LSB. + */ +#define IS_BIT_MASK(m) IS_SHIFTED_BIT_MASK(m, 0) + +/** + * @brief Check if bit is set in a value + * + * @param value Value that contain checked bit + * @param bit Bit number + */ +#define IS_BIT_SET(value, bit) ((((value) >> (bit)) & (0x1)) != 0) + +/** @brief Extract the Least Significant Bit from @p value. */ +#define LSB_GET(value) ((value) & -(value)) + +/** + * @brief Extract a bitfield element from @p value corresponding to + * the field mask @p mask. + */ +#define FIELD_GET(mask, value) (((value) & (mask)) / LSB_GET(mask)) + +/** + * @brief Prepare a bitfield element using @p value with @p mask representing + * its field position and width. The result should be combined + * with other fields using a logical OR. + */ +#define FIELD_PREP(mask, value) (((value) * LSB_GET(mask)) & (mask)) + +/** + * @brief Check for macro definition in compiler-visible expressions + * + * This trick was pioneered in Linux as the config_enabled() macro. It + * has the effect of taking a macro value that may be defined to "1" + * or may not be defined at all and turning it into a literal + * expression that can be handled by the C compiler instead of just + * the preprocessor. It is often used with a @p CONFIG_FOO macro which + * may be defined to 1 via Kconfig, or left undefined. + * + * That is, it works similarly to \#if defined(CONFIG_FOO) + * except that its expansion is a C expression. Thus, much \#ifdef + * usage can be replaced with equivalents like: + * + * if (IS_ENABLED(CONFIG_FOO)) { + * do_something_with_foo + * } + * + * This is cleaner since the compiler can generate errors and warnings + * for @p do_something_with_foo even when @p CONFIG_FOO is undefined. + * + * Note: Use of IS_ENABLED in a \#if statement is discouraged + * as it doesn't provide any benefit vs plain \#if defined() + * + * @param config_macro Macro to check + * @return 1 if @p config_macro is defined to 1, 0 otherwise (including + * if @p config_macro is not defined) + */ +#define IS_ENABLED(config_macro) Z_IS_ENABLED1(config_macro) +/* INTERNAL: the first pass above is just to expand any existing + * macros, we need the macro value to be e.g. a literal "1" at + * expansion time in the next macro, not "(1)", etc... Standard + * recursive expansion does not work. + */ + +/** + * @brief Insert code depending on whether @p _flag expands to 1 or not. + * + * This relies on similar tricks as IS_ENABLED(), but as the result of + * @p _flag expansion, results in either @p _if_1_code or @p + * _else_code is expanded. + * + * To prevent the preprocessor from treating commas as argument + * separators, the @p _if_1_code and @p _else_code expressions must be + * inside brackets/parentheses: (). These are stripped away + * during macro expansion. + * + * Example: + * + * COND_CODE_1(CONFIG_FLAG, (uint32_t x;), (there_is_no_flag();)) + * + * If @p CONFIG_FLAG is defined to 1, this expands to: + * + * uint32_t x; + * + * It expands to there_is_no_flag(); otherwise. + * + * This could be used as an alternative to: + * + * #if defined(CONFIG_FLAG) && (CONFIG_FLAG == 1) + * #define MAYBE_DECLARE(x) uint32_t x + * #else + * #define MAYBE_DECLARE(x) there_is_no_flag() + * #endif + * + * MAYBE_DECLARE(x); + * + * However, the advantage of COND_CODE_1() is that code is resolved in + * place where it is used, while the @p \#if method defines @p + * MAYBE_DECLARE on two lines and requires it to be invoked again on a + * separate line. This makes COND_CODE_1() more concise and also + * sometimes more useful when used within another macro's expansion. + * + * @note @p _flag can be the result of preprocessor expansion, e.g. + * an expression involving NUM_VA_ARGS_LESS_1(...). + * However, @p _if_1_code is only expanded if @p _flag expands + * to the integer literal 1. Integer expressions that evaluate + * to 1, e.g. after doing some arithmetic, will not work. + * + * @param _flag evaluated flag + * @param _if_1_code result if @p _flag expands to 1; must be in parentheses + * @param _else_code result otherwise; must be in parentheses + */ +#define COND_CODE_1(_flag, _if_1_code, _else_code) \ + Z_COND_CODE_1(_flag, _if_1_code, _else_code) + +/** + * @brief Like COND_CODE_1() except tests if @p _flag is 0. + * + * This is like COND_CODE_1(), except that it tests whether @p _flag + * expands to the integer literal 0. It expands to @p _if_0_code if + * so, and @p _else_code otherwise; both of these must be enclosed in + * parentheses. + * + * @param _flag evaluated flag + * @param _if_0_code result if @p _flag expands to 0; must be in parentheses + * @param _else_code result otherwise; must be in parentheses + * @see COND_CODE_1() + */ +#define COND_CODE_0(_flag, _if_0_code, _else_code) \ + Z_COND_CODE_0(_flag, _if_0_code, _else_code) + +/** + * @brief Insert code if @p _flag is defined and equals 1. + * + * Like COND_CODE_1(), this expands to @p _code if @p _flag is defined to 1; + * it expands to nothing otherwise. + * + * Example: + * + * IF_ENABLED(CONFIG_FLAG, (uint32_t foo;)) + * + * If @p CONFIG_FLAG is defined to 1, this expands to: + * + * uint32_t foo; + * + * and to nothing otherwise. + * + * It can be considered as a more compact alternative to: + * + * #if defined(CONFIG_FLAG) && (CONFIG_FLAG == 1) + * uint32_t foo; + * #endif + * + * @param _flag evaluated flag + * @param _code result if @p _flag expands to 1; must be in parentheses + */ +#define IF_ENABLED(_flag, _code) \ + COND_CODE_1(_flag, _code, ()) + +/** + * @brief Insert code if @p _flag is not defined as 1. + * + * This expands to nothing if @p _flag is defined and equal to 1; + * it expands to @p _code otherwise. + * + * Example: + * + * IF_DISABLED(CONFIG_FLAG, (uint32_t foo;)) + * + * If @p CONFIG_FLAG isn't defined or different than 1, this expands to: + * + * uint32_t foo; + * + * and to nothing otherwise. + * + * IF_DISABLED does the opposite of IF_ENABLED. + * + * @param _flag evaluated flag + * @param _code result if @p _flag does not expand to 1; must be in parentheses + */ +#define IF_DISABLED(_flag, _code) \ + COND_CODE_1(_flag, (), _code) + +/** + * @brief Check if a macro has a replacement expression + * + * If @p a is a macro defined to a nonempty value, this will return + * true, otherwise it will return false. It only works with defined + * macros, so an additional @p \#ifdef test may be needed in some cases. + * + * This macro may be used with COND_CODE_1() and COND_CODE_0() while + * processing `__VA_ARGS__` to avoid processing empty arguments. + * + * Example: + * + * #define EMPTY + * #define NON_EMPTY 1 + * #undef UNDEFINED + * IS_EMPTY(EMPTY) + * IS_EMPTY(NON_EMPTY) + * IS_EMPTY(UNDEFINED) + * #if defined(EMPTY) && IS_EMPTY(EMPTY) == true + * some_conditional_code + * #endif + * + * In above examples, the invocations of IS_EMPTY(...) return @p true, + * @p false, and @p true; @p some_conditional_code is included. + * + * @param ... macro to check for emptiness (may be `__VA_ARGS__`) + */ +#define IS_EMPTY(...) Z_IS_EMPTY_(__VA_ARGS__) + +/** + * @brief Like a == b, but does evaluation and + * short-circuiting at C preprocessor time. + * + * This however only works for integer literal from 0 to 4096 (literals with U suffix, + * e.g. 0U are also included). + * + * Examples: + * + * IS_EQ(1, 1) -> 1 + * IS_EQ(1U, 1U) -> 1 + * IS_EQ(1U, 1) -> 1 + * IS_EQ(1, 1U) -> 1 + * IS_EQ(1, 0) -> 0 + * + * @param a Integer literal (can be with U suffix) + * @param b Integer literal + * + */ +#define IS_EQ(a, b) Z_IS_EQ(a, b) + +/** + * @brief Remove empty arguments from list. + * + * During macro expansion, `__VA_ARGS__` and other preprocessor + * generated lists may contain empty elements, e.g.: + * + * #define LIST ,a,b,,d, + * + * Using EMPTY to show each empty element, LIST contains: + * + * EMPTY, a, b, EMPTY, d + * + * When processing such lists, e.g. using FOR_EACH(), all empty elements + * will be processed, and may require filtering out. + * To make that process easier, it is enough to invoke LIST_DROP_EMPTY + * which will remove all empty elements. + * + * Example: + * + * LIST_DROP_EMPTY(LIST) + * + * expands to: + * + * a, b, d + * + * @param ... list to be processed + */ +#define LIST_DROP_EMPTY(...) \ + Z_LIST_DROP_FIRST(FOR_EACH(Z_LIST_NO_EMPTIES, (), __VA_ARGS__)) + +/** + * @brief Macro with an empty expansion + * + * This trivial definition is provided for readability when a macro + * should expand to an empty result, which e.g. is sometimes needed to + * silence checkpatch. + * + * Example: + * + * #define LIST_ITEM(n) , item##n + * + * The above would cause checkpatch to complain, but: + * + * #define LIST_ITEM(n) EMPTY, item##n + * + * would not. + */ +#define EMPTY + +/** + * @brief Macro that expands to its argument + * + * This is useful in macros like @c FOR_EACH() when there is no + * transformation required on the list elements. + * + * @param V any value + */ +#define IDENTITY(V) V + +/** + * @brief Get nth argument from argument list. + * + * @param N Argument index to fetch. Counter from 1. + * @param ... Variable list of arguments from which one argument is returned. + * + * @return Nth argument. + */ +#define GET_ARG_N(N, ...) UTIL_CAT(Z_GET_ARG_, N)(__VA_ARGS__) + +/** + * @brief Strips n first arguments from the argument list. + * + * @param N Number of arguments to discard. + * @param ... Variable list of arguments. + * + * @return argument list without N first arguments. + */ +#define GET_ARGS_LESS_N(N, ...) UTIL_CAT(Z_GET_ARGS_LESS_, N)(__VA_ARGS__) + +/** + * @brief Like a || b, but does evaluation and + * short-circuiting at C preprocessor time. + * + * This is not the same as the binary @p || operator; in particular, + * @p a should expand to an integer literal 0 or 1. However, @p b + * can be any value. + * + * This can be useful when @p b is an expression that would cause a + * build error when @p a is 1. + */ +#define UTIL_OR(a, b) COND_CODE_1(UTIL_BOOL(a), (a), (b)) + +/** + * @brief Like a && b, but does evaluation and + * short-circuiting at C preprocessor time. + * + * This is not the same as the binary @p &&, however; in particular, + * @p a should expand to an integer literal 0 or 1. However, @p b + * can be any value. + * + * This can be useful when @p b is an expression that would cause a + * build error when @p a is 0. + */ +#define UTIL_AND(a, b) COND_CODE_1(UTIL_BOOL(a), (b), (0)) + +/** + * @brief UTIL_INC(x) for an integer literal x from 0 to 4095 expands to an + * integer literal whose value is x+1. + * + * @see UTIL_DEC(x) + */ +#define UTIL_INC(x) UTIL_PRIMITIVE_CAT(Z_UTIL_INC_, x) + +/** + * @brief UTIL_DEC(x) for an integer literal x from 0 to 4095 expands to an + * integer literal whose value is x-1. + * + * @see UTIL_INC(x) + */ +#define UTIL_DEC(x) UTIL_PRIMITIVE_CAT(Z_UTIL_DEC_, x) + +/** + * @brief UTIL_X2(y) for an integer literal y from 0 to 4095 expands to an + * integer literal whose value is 2y. + */ +#define UTIL_X2(y) UTIL_PRIMITIVE_CAT(Z_UTIL_X2_, y) + +/** + * @brief Generates a sequence of code with configurable separator. + * + * Example: + * + * #define FOO(i, _) MY_PWM ## i + * { LISTIFY(PWM_COUNT, FOO, (,)) } + * + * The above two lines expand to: + * + * { MY_PWM0 , MY_PWM1 } + * + * @param LEN The length of the sequence. Must be an integer literal less + * than 4095. + * @param F A macro function that accepts at least two arguments: + * F(i, ...). @p F is called repeatedly in the expansion. + * Its first argument @p i is the index in the sequence, and + * the variable list of arguments passed to LISTIFY are passed + * through to @p F. + * + * @param sep Separator (e.g. comma or semicolon). Must be in parentheses; + * this is required to enable providing a comma as separator. + * + * @note Calling LISTIFY with undefined arguments has undefined + * behavior. + */ +#define LISTIFY(LEN, F, sep, ...) UTIL_CAT(Z_UTIL_LISTIFY_, LEN)(F, sep, __VA_ARGS__) + +/** + * @brief Call a macro @p F on each provided argument with a given + * separator between each call. + * + * Example: + * + * #define F(x) int a##x + * FOR_EACH(F, (;), 4, 5, 6); + * + * This expands to: + * + * int a4; + * int a5; + * int a6; + * + * @param F Macro to invoke + * @param sep Separator (e.g. comma or semicolon). Must be in parentheses; + * this is required to enable providing a comma as separator. + * @param ... Variable argument list. The macro @p F is invoked as + * F(element) for each element in the list. + */ +#define FOR_EACH(F, sep, ...) \ + Z_FOR_EACH(F, sep, REVERSE_ARGS(__VA_ARGS__)) + +/** + * @brief Like FOR_EACH(), but with a terminator instead of a separator, + * and drops empty elements from the argument list + * + * The @p sep argument to FOR_EACH(F, (sep), a, b) is a + * separator which is placed between calls to @p F, like this: + * + * FOR_EACH(F, (sep), a, b) // F(a) sep F(b) + * // ^^^ no sep here! + * + * By contrast, the @p term argument to FOR_EACH_NONEMPTY_TERM(F, (term), + * a, b) is added after each time @p F appears in the expansion: + * + * FOR_EACH_NONEMPTY_TERM(F, (term), a, b) // F(a) term F(b) term + * // ^^^^ + * + * Further, any empty elements are dropped: + * + * FOR_EACH_NONEMPTY_TERM(F, (term), a, EMPTY, b) // F(a) term F(b) term + * + * This is more convenient in some cases, because FOR_EACH_NONEMPTY_TERM() + * expands to nothing when given an empty argument list, and it's + * often cumbersome to write a macro @p F that does the right thing + * even when given an empty argument. + * + * One example is when `__VA_ARGS__` may or may not be empty, + * and the results are embedded in a larger initializer: + * + * #define SQUARE(x) ((x)*(x)) + * + * int my_array[] = { + * FOR_EACH_NONEMPTY_TERM(SQUARE, (,), FOO(...)) + * FOR_EACH_NONEMPTY_TERM(SQUARE, (,), BAR(...)) + * FOR_EACH_NONEMPTY_TERM(SQUARE, (,), BAZ(...)) + * }; + * + * This is more convenient than: + * + * 1. figuring out whether the @p FOO, @p BAR, and @p BAZ expansions + * are empty and adding a comma manually (or not) between FOR_EACH() + * calls + * 2. rewriting SQUARE so it reacts appropriately when "x" is empty + * (which would be necessary if e.g. @p FOO expands to nothing) + * + * @param F Macro to invoke on each nonempty element of the variable + * arguments + * @param term Terminator (e.g. comma or semicolon) placed after each + * invocation of F. Must be in parentheses; this is required + * to enable providing a comma as separator. + * @param ... Variable argument list. The macro @p F is invoked as + * F(element) for each nonempty element in the list. + */ +#define FOR_EACH_NONEMPTY_TERM(F, term, ...) \ + COND_CODE_0( \ + /* are there zero non-empty arguments ? */ \ + NUM_VA_ARGS_LESS_1(LIST_DROP_EMPTY(__VA_ARGS__, _)), \ + /* if so, expand to nothing */ \ + (), \ + /* otherwise, expand to: */ \ + (/* FOR_EACH() on nonempty elements, */ \ + FOR_EACH(F, term, LIST_DROP_EMPTY(__VA_ARGS__)) \ + /* plus a final terminator */ \ + __DEBRACKET term \ + )) + +/** + * @brief Call macro @p F on each provided argument, with the argument's index + * as an additional parameter. + * + * This is like FOR_EACH(), except @p F should be a macro which takes two + * arguments: F(index, variable_arg). + * + * Example: + * + * #define F(idx, x) int a##idx = x + * FOR_EACH_IDX(F, (;), 4, 5, 6); + * + * This expands to: + * + * int a0 = 4; + * int a1 = 5; + * int a2 = 6; + * + * @param F Macro to invoke + * @param sep Separator (e.g. comma or semicolon). Must be in parentheses; + * this is required to enable providing a comma as separator. + * @param ... Variable argument list. The macro @p F is invoked as + * F(index, element) for each element in the list. + */ +#define FOR_EACH_IDX(F, sep, ...) \ + Z_FOR_EACH_IDX(F, sep, REVERSE_ARGS(__VA_ARGS__)) + +/** + * @brief Call macro @p F on each provided argument, with an additional fixed + * argument as a parameter. + * + * This is like FOR_EACH(), except @p F should be a macro which takes two + * arguments: F(variable_arg, fixed_arg). + * + * Example: + * + * static void func(int val, void *dev); + * FOR_EACH_FIXED_ARG(func, (;), dev, 4, 5, 6); + * + * This expands to: + * + * func(4, dev); + * func(5, dev); + * func(6, dev); + * + * @param F Macro to invoke + * @param sep Separator (e.g. comma or semicolon). Must be in parentheses; + * this is required to enable providing a comma as separator. + * @param fixed_arg Fixed argument passed to @p F as the second macro parameter. + * @param ... Variable argument list. The macro @p F is invoked as + * F(element, fixed_arg) for each element in the list. + */ +#define FOR_EACH_FIXED_ARG(F, sep, fixed_arg, ...) \ + Z_FOR_EACH_FIXED_ARG(F, sep, fixed_arg, REVERSE_ARGS(__VA_ARGS__)) + +/** + * @brief Calls macro @p F for each variable argument with an index and fixed + * argument + * + * This is like the combination of FOR_EACH_IDX() with FOR_EACH_FIXED_ARG(). + * + * Example: + * + * #define F(idx, x, fixed_arg) int fixed_arg##idx = x + * FOR_EACH_IDX_FIXED_ARG(F, (;), a, 4, 5, 6); + * + * This expands to: + * + * int a0 = 4; + * int a1 = 5; + * int a2 = 6; + * + * @param F Macro to invoke + * @param sep Separator (e.g. comma or semicolon). Must be in parentheses; + * This is required to enable providing a comma as separator. + * @param fixed_arg Fixed argument passed to @p F as the third macro parameter. + * @param ... Variable list of arguments. The macro @p F is invoked as + * F(index, element, fixed_arg) for each element in + * the list. + */ +#define FOR_EACH_IDX_FIXED_ARG(F, sep, fixed_arg, ...) \ + Z_FOR_EACH_IDX_FIXED_ARG(F, sep, fixed_arg, REVERSE_ARGS(__VA_ARGS__)) + +/** @brief Reverse arguments order. + * + * @param ... Variable argument list. + */ +#define REVERSE_ARGS(...) \ + Z_FOR_EACH_ENGINE(Z_FOR_EACH_EXEC, (,), Z_BYPASS, _, __VA_ARGS__) + +/** + * @brief Number of arguments in the variable arguments list minus one. + * + * @note Supports up to 64 arguments. + * + * @param ... List of arguments + * @return Number of variadic arguments in the argument list, minus one + */ +#define NUM_VA_ARGS_LESS_1(...) \ + NUM_VA_ARGS_LESS_1_IMPL(__VA_ARGS__, 63, 62, 61, \ + 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, \ + 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, \ + 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, \ + 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, \ + 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, \ + 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, ~) + +/** + * @brief Number of arguments in the variable arguments list. + * + * @note Supports up to 63 arguments. + * + * @param ... List of arguments + * @return Number of variadic arguments in the argument list + */ +#define NUM_VA_ARGS(...) \ + COND_CODE_1(IS_EMPTY(__VA_ARGS__), (0), (UTIL_INC(NUM_VA_ARGS_LESS_1(__VA_ARGS__)))) + +/** + * @brief Mapping macro that pastes results together + * + * This is similar to FOR_EACH() in that it invokes a macro repeatedly + * on each element of `__VA_ARGS__`. However, unlike FOR_EACH(), + * MACRO_MAP_CAT() pastes the results together into a single token. + * + * For example, with this macro FOO: + * + * #define FOO(x) item_##x##_ + * + * MACRO_MAP_CAT(FOO, a, b, c), expands to the token: + * + * item_a_item_b_item_c_ + * + * @param ... Macro to expand on each argument, followed by its + * arguments. (The macro should take exactly one argument.) + * @return The results of expanding the macro on each argument, all pasted + * together + */ +#define MACRO_MAP_CAT(...) MACRO_MAP_CAT_(__VA_ARGS__) + +/** + * @brief Mapping macro that pastes a fixed number of results together + * + * Similar to @ref MACRO_MAP_CAT(), but expects a fixed number of + * arguments. If more arguments are given than are expected, the rest + * are ignored. + * + * @param N Number of arguments to map + * @param ... Macro to expand on each argument, followed by its + * arguments. (The macro should take exactly one argument.) + * @return The results of expanding the macro on each argument, all pasted + * together + */ +#define MACRO_MAP_CAT_N(N, ...) MACRO_MAP_CAT_N_(N, __VA_ARGS__) + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_SYS_UTIL_MACROS_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/sys/util_utf8.h b/components/bt/esp_ble_audio/include/zephyr/sys/util_utf8.h new file mode 100644 index 0000000000..d4a60ef6b3 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/sys/util_utf8.h @@ -0,0 +1,93 @@ +/* + * SPDX-FileCopyrightText: The Zephyr Project Contributors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief UTF-8 utilities + * + * Misc UTF-8 utilities. + */ + +#ifndef ZEPHYR_INCLUDE_SYS_UTIL_UFT8_H_ +#define ZEPHYR_INCLUDE_SYS_UTIL_UFT8_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup sys-util + * @{ + */ + +/** + * @brief Properly truncate a NULL-terminated UTF-8 string + * + * Take a NULL-terminated UTF-8 string and ensure that if the string has been + * truncated (by setting the NULL terminator) earlier by other means, that + * the string ends with a properly formatted UTF-8 character (1-4 bytes). + * + * Example: + * + * @code{.c} + * char test_str[] = "€€€"; + * char trunc_utf8[8]; + * + * printf("Original : %s\n", test_str); // €€€ + * strncpy(trunc_utf8, test_str, sizeof(trunc_utf8)); + * trunc_utf8[sizeof(trunc_utf8) - 1] = '\0'; + * printf("Bad : %s\n", trunc_utf8); // €€� + * utf8_trunc(trunc_utf8); + * printf("Truncated: %s\n", trunc_utf8); // €€ + * @endcode + * + * @param utf8_str NULL-terminated string + * + * @return Pointer to the @p utf8_str + */ +char *utf8_trunc(char *utf8_str); + +/** + * @brief Copies a UTF-8 encoded string from @p src to @p dst + * + * The resulting @p dst will always be NULL terminated if @p n is larger than 0, + * and the @p dst string will always be properly UTF-8 truncated. + * + * @param dst The destination of the UTF-8 string. + * @param src The source string + * @param n The size of the @p dst buffer. Maximum number of characters copied + * is @p n - 1. If 0 nothing will be done, and the @p dst will not be + * NULL terminated. + * + * @return Pointer to the @p dst + */ +char *utf8_lcpy(char *dst, const char *src, size_t n); + +/** + * @brief Counts the characters in a UTF-8 encoded string @p s + * + * Counts the number of UTF-8 characters (code points) in a null-terminated string. + * This function steps through each UTF-8 sequence by checking leading byte patterns. + * It does not fully validate UTF-8 correctness, only counts characters. + * + * @param s The input string + * + * @return Number of UTF-8 characters in @p s on success or (negative) error code + * otherwise. + */ +int utf8_count_chars(const char *s); + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_SYS_UTIL_UFT8_H_ */ diff --git a/components/bt/esp_ble_audio/include/zephyr/toolchain.h b/components/bt/esp_ble_audio/include/zephyr/toolchain.h new file mode 100644 index 0000000000..7c7d6c2570 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/toolchain.h @@ -0,0 +1,68 @@ +/* + * SPDX-FileCopyrightText: 2010-2014 Wind River Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "esp_compiler.h" + +#include +#include + +#define SYS_INIT(init_fn, level, prio) int init_fn ## _v2(void) { return init_fn(); } + +#ifndef BUILD_ASSERT +#define BUILD_ASSERT(EXPR, MSG...) _Static_assert(EXPR, ## MSG) +#endif + +#ifndef _DO_CONCAT +#define _DO_CONCAT(x, y) x ## y +#endif + +#ifndef _CONCAT +#define _CONCAT(x, y) _DO_CONCAT(x, y) +#endif + +#ifndef ARG_UNUSED +#define ARG_UNUSED(x) (void)(x) +#endif + +#ifndef __fallthrough +#define __fallthrough __attribute__((fallthrough)) +#endif + +#ifndef __packed +#define __packed __attribute__((__packed__)) +#endif + +#ifndef _LIB_ONLY +#define _LIB_ONLY /* Used to mark functions only used by BLE Audio LIB */ +#endif + +#ifndef _IDF_ONLY +#define _IDF_ONLY /* Used to mark functions only used by BLE Audio IDF */ +#endif + +#ifndef _LIB_IDF +#define _LIB_IDF /* Used to mark functions used by BLE Audio LIB and IDF */ +#endif + +#ifndef _NOT_USED +#define _NOT_USED /* Used to mark functions currently not used */ +#endif + +static inline unsigned int find_msb_set(uint32_t op) +{ + if (op == 0) { + return 0; + } + + return 32 - __builtin_clz(op); +} + +static inline unsigned int find_lsb_set(uint32_t op) +{ + return __builtin_ffs(op); +} diff --git a/components/bt/esp_ble_audio/include/zephyr/types.h b/components/bt/esp_ble_audio/include/zephyr/types.h new file mode 100644 index 0000000000..db3a916887 --- /dev/null +++ b/components/bt/esp_ble_audio/include/zephyr/types.h @@ -0,0 +1,6 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +/* Dummy file just for compiling */ diff --git a/components/bt/esp_ble_audio/lib/include/audio.h b/components/bt/esp_ble_audio/lib/include/audio.h new file mode 100644 index 0000000000..74400982d7 --- /dev/null +++ b/components/bt/esp_ble_audio/lib/include/audio.h @@ -0,0 +1,384 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef LIB_AUDIO_H_ +#define LIB_AUDIO_H_ + +#include +#include + +#include "sdkconfig.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct lib_ext_cfgs; +struct lib_ext_funcs; +struct lib_funcs; + +extern int lib_ext_structs_check(const uint16_t *ext_structs, size_t size_structs); +extern int lib_ext_cfgs_set(const struct lib_ext_cfgs *ext_cfgs, size_t size_cfgs); +extern int lib_ext_funcs_set(const struct lib_ext_funcs *ext_funcs, size_t size_funcs); +extern int lib_funcs_set(const struct lib_funcs *funcs, size_t size_funcs); +#if 0 +extern void lib_dymem_size_init(void); +#endif +extern const char *lib_ext_commit_get(void); + +struct bt_aics; +struct bt_gatt_service; + +extern struct bt_aics *lib_aics_insts_get(void); +extern void *lib_aics_svc_get(struct bt_aics *aics); +extern int lib_aics_init(void); +extern int lib_aics_client_init(void); + +extern int lib_bap_base_init(void); +extern int lib_bap_iso_init(void); +extern int lib_bap_stream_init(void); + +extern struct bt_gatt_service *lib_ascs_svc_get(void); +extern int lib_ascs_init(void); + +extern struct bt_gatt_service *lib_bap_bass_svc_get(void); +extern int lib_bap_broadcast_assistant_init(void); +extern int lib_bap_broadcast_sink_init(void); +extern int lib_bap_broadcast_source_init(void); +extern int lib_bap_scan_delegator_init(void); +extern int lib_bap_unicast_client_init(void); +extern int lib_bap_unicast_server_init(void); + +extern struct bt_gatt_service *lib_pacs_svc_get(void); +extern int lib_pacs_init(void); + +extern struct bt_gatt_service *lib_cas_svc_get(void); + +extern int lib_cap_common_init(void); +extern int lib_cap_stream_init(void); +extern int lib_cap_initiator_init(void); +extern int lib_cap_acceptor_init(void); +extern int lib_cap_commander_init(void); + +extern int lib_ccid_init(void); + +extern int lib_ccp_call_control_client_init(void); +extern int lib_ccp_call_control_server_init(void); + +extern int lib_codec_init(void); + +extern int lib_csip_set_coordinator_init(void); +extern void *lib_csip_set_member_svc_get(const void *svc_inst); +extern int lib_csip_set_member_init(void); + +extern int lib_gmap_client_init(void); +extern struct bt_gatt_service *lib_gmas_svc_get(void); + +extern struct bt_gatt_service *lib_has_svc_get(void); +extern int lib_has_init(void); +extern int lib_has_client_init(void); + +extern int lib_mcc_init(void); +extern struct bt_gatt_service *lib_mcs_svc_get(void); +extern int lib_mcs_init(void); + +extern int lib_media_proxy_init(void); + +extern int lib_micp_mic_ctlr_init(void); +extern struct bt_gatt_service *lib_mics_svc_get(void); +extern int lib_micp_mic_dev_init(void); + +extern int lib_mpl_init(void); + +extern int lib_pbp_init(void); + +extern int lib_tbs_client_init(void); +extern struct bt_gatt_service *lib_gtbs_svc_get(void); +extern struct bt_gatt_service *lib_tbs_server_list_get(void); +extern int lib_tbs_init(void); + +extern struct bt_gatt_service *lib_tmas_svc_get(void); +extern int lib_tmap_init(void); + +extern int lib_vcp_vol_ctlr_init(void); +extern struct bt_gatt_service *lib_vcs_svc_get(void); +extern int lib_vcp_vol_rend_init(void); + +struct bt_vocs; +struct bt_vocs_server; + +extern int lib_vocs_client_init(void); +extern struct bt_vocs_server *lib_vocs_insts_get(void); +extern void *lib_vocs_svc_get(struct bt_vocs *vocs); +extern int lib_vocs_init(void); + +struct bt_conn; +struct bt_gatt_attr; +struct bt_gatt_discover_params; + +struct bt_iso_recv_info; + +struct bt_audio_codec_cfg; + +struct bt_aics; + +struct bt_bap_ep; +struct bt_bap_stream; +enum bt_bap_ascs_reason; +enum bt_bap_ascs_rsp_code; +struct bt_bap_qos_cfg_pref; +struct bt_bap_unicast_client_cb; +struct bt_bap_scan_delegator_recv_state; + +enum bt_cap_common_subproc_type; +enum bt_cap_common_proc_type; +struct bt_cap_stream; +struct bt_cap_broadcast_source; + +struct bt_ots; +struct bt_ots_client; + +struct bt_micp_mic_dev_register_param; + +struct mpl_search; + +struct bt_tbs_instance; + +struct bt_vcp_vol_ctlr; +struct bt_vcp_included; +struct bt_vcp_vol_rend_register_param; + +struct bt_vocs_client; + +#if CONFIG_BT_AICS_CLIENT +extern int lib_aics_client_state_get(struct bt_aics *inst); +extern int lib_aics_client_gain_setting_get(struct bt_aics *inst); +extern int lib_aics_client_type_get(struct bt_aics *inst); +extern int lib_aics_client_status_get(struct bt_aics *inst); +extern int lib_aics_client_unmute(struct bt_aics *inst); +extern int lib_aics_client_mute(struct bt_aics *inst); +extern int lib_aics_client_manual_gain_set(struct bt_aics *inst); +extern int lib_aics_client_automatic_gain_set(struct bt_aics *inst); +extern int lib_aics_client_gain_set(struct bt_aics *inst, int8_t gain); +extern int lib_aics_client_description_get(struct bt_aics *inst); +extern int lib_aics_client_description_set(struct bt_aics *inst, const char *description); +#endif /* CONFIG_BT_AICS_CLIENT */ + +#if CONFIG_BT_BAP_BROADCAST_SINK +extern bool lib_bap_broadcast_sink_has_ep(const struct bt_bap_ep *ep); +#endif /* CONFIG_BT_BAP_BROADCAST_SINK */ + +#if CONFIG_BT_BAP_BROADCAST_SOURCE +extern bool lib_bap_broadcast_source_has_ep(const struct bt_bap_ep *ep); +#endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */ + +#if CONFIG_BT_BAP_UNICAST_CLIENT +extern bool lib_bap_unicast_client_has_ep(const struct bt_bap_ep *ep); +extern int lib_bap_unicast_client_register_cb(struct bt_bap_unicast_client_cb *cb); +extern int lib_bap_unicast_client_config(struct bt_bap_stream *stream, + const struct bt_audio_codec_cfg *codec_cfg); +extern int lib_bap_unicast_client_metadata(struct bt_bap_stream *stream, + const uint8_t meta[], size_t meta_len); +extern int lib_bap_unicast_client_connect(struct bt_bap_stream *stream); +extern int lib_bap_unicast_client_start(struct bt_bap_stream *stream); +extern int lib_bap_unicast_client_disable(struct bt_bap_stream *stream); +extern int lib_bap_unicast_client_release(struct bt_bap_stream *stream); +#endif /* CONFIG_BT_BAP_UNICAST_CLIENT */ + +#if CONFIG_BT_BAP_UNICAST_SERVER +extern bool lib_bap_unicast_server_has_ep(const struct bt_bap_ep *ep); +extern int lib_bap_unicast_server_reconfig(struct bt_bap_stream *stream, + const struct bt_audio_codec_cfg *codec_cfg); +extern int lib_bap_unicast_server_start(struct bt_bap_stream *stream); +extern int lib_bap_unicast_server_metadata(struct bt_bap_stream *stream, + const uint8_t meta[], size_t meta_len); +extern int lib_bap_unicast_server_disable(struct bt_bap_stream *stream); +extern int lib_bap_unicast_server_release(struct bt_bap_stream *stream); +#endif /* CONFIG_BT_BAP_UNICAST_SERVER */ + +#if CONFIG_BT_CAP_ACCEPTOR +extern bool lib_cap_acceptor_ccids_exist(const struct bt_conn *conn, const uint8_t ccids[], + uint8_t ccid_cnt); +#endif /* CONFIG_BT_CAP_ACCEPTOR */ + +#if CONFIG_BT_CAP_INITIATOR_UNICAST +extern void lib_cap_common_set_subproc(enum bt_cap_common_subproc_type subproc_type); +extern bool lib_cap_common_proc_is_type(enum bt_cap_common_proc_type proc_type); +extern bool lib_cap_common_subproc_is_type(enum bt_cap_common_subproc_type subproc_type); +extern void lib_cap_initiator_cp_cb(struct bt_cap_stream *cap_stream, + enum bt_bap_ascs_rsp_code rsp_code, + enum bt_bap_ascs_reason reason); +extern void lib_cap_initiator_codec_configured(struct bt_cap_stream *cap_stream); +extern void lib_cap_initiator_qos_configured(struct bt_cap_stream *cap_stream); +extern void lib_cap_initiator_enabled(struct bt_cap_stream *cap_stream); +extern void lib_cap_initiator_connected(struct bt_cap_stream *cap_stream); +extern void lib_cap_initiator_started(struct bt_cap_stream *cap_stream); +extern void lib_cap_initiator_metadata_updated(struct bt_cap_stream *cap_stream); +extern void lib_cap_initiator_disabled(struct bt_cap_stream *cap_stream); +extern void lib_cap_initiator_stopped(struct bt_cap_stream *cap_stream); +extern void lib_cap_initiator_released(struct bt_cap_stream *cap_stream); +#endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */ + +#if CONFIG_BT_CAP_HANDOVER +extern bool lib_cap_common_handover_is_active(void); +extern bool lib_cap_handover_is_handover_broadcast_source(const struct bt_cap_broadcast_source *cap_broadcast_source); +extern void lib_cap_handover_complete(void); +extern void lib_cap_handover_unicast_proc_complete(void); +extern void lib_cap_handover_broadcast_source_stopped(uint8_t reason); +extern void lib_cap_handover_unicast_to_broadcast_reception_start(void); +extern int lib_cap_handover_broadcast_reception_stopped(void); +extern void lib_cap_handover_receive_state_updated(const struct bt_conn *conn, + const struct bt_bap_scan_delegator_recv_state *state); +#endif /* CONFIG_BT_CAP_HANDOVER */ + +#if CONFIG_BT_CAP && CONFIG_BT_BAP_UNICAST +extern void lib_cap_stream_configured_cb(struct bt_bap_stream *bap_stream, + const struct bt_bap_qos_cfg_pref *pref); +extern void lib_cap_stream_qos_set_cb(struct bt_bap_stream *bap_stream); +extern void lib_cap_stream_enabled_cb(struct bt_bap_stream *bap_stream); +extern void lib_cap_stream_metadata_updated_cb(struct bt_bap_stream *bap_stream); +extern void lib_cap_stream_disabled_cb(struct bt_bap_stream *bap_stream); +extern void lib_cap_stream_released_cb(struct bt_bap_stream *bap_stream); +#endif /* CONFIG_BT_CAP && CONFIG_BT_BAP_UNICAST */ + +#if CONFIG_BT_CAP && CONFIG_BT_AUDIO_RX +extern void lib_cap_stream_recv_cb(struct bt_bap_stream *bap_stream, + const struct bt_iso_recv_info *info, + const uint8_t *data, uint16_t len); +#endif /* CONFIG_BT_CAP && CONFIG_BT_AUDIO_RX */ + +#if CONFIG_BT_CAP && CONFIG_BT_AUDIO_TX +extern void lib_cap_stream_sent_cb(struct bt_bap_stream *bap_stream, void *user_data); +#endif /* CONFIG_BT_CAP && CONFIG_BT_AUDIO_TX */ + +#if CONFIG_BT_MCC_OTS +extern void lib_mcc_on_obj_selected(struct bt_ots_client *otc_inst, + struct bt_conn *conn, int result); +extern int lib_mcc_on_icon_content(struct bt_ots_client *otc_inst, + struct bt_conn *conn, + uint32_t offset, uint32_t len, + uint8_t *data_p, bool is_complete); +extern void lib_mcc_on_object_metadata(struct bt_ots_client *otc_inst, + struct bt_conn *conn, int err, + uint8_t metadata_read); +#endif /* CONFIG_BT_MCC_OTS */ + +#if CONFIG_BT_MCS && CONFIG_BT_OTS +extern struct bt_ots *lib_mcs_get_ots(void); +extern void lib_mcs_media_proxy_sctrl_current_track_id_cb(uint64_t id); +extern void lib_mcs_media_proxy_sctrl_next_track_id_cb(uint64_t id); +extern void lib_mcs_media_proxy_sctrl_parent_group_id_cb(uint64_t id); +extern void lib_mcs_media_proxy_sctrl_current_group_id_cb(uint64_t id); +extern void lib_mcs_media_proxy_sctrl_search_cb(uint8_t result_code); +extern void lib_mcs_media_proxy_sctrl_search_results_id_cb(uint64_t id); +extern void lib_mcs_svc_inc_init(void); +extern void lib_mcs_chrc_icon_obj_id_init(void); +extern void lib_mcs_chrc_track_segments_obj_id_init(void); +extern void lib_mcs_chrc_current_track_obj_id_init(void); +extern void lib_mcs_chrc_next_track_obj_id_init(void); +extern void lib_mcs_chrc_parent_group_obj_id_init(void); +extern void lib_mcs_chrc_current_group_obj_id_init(void); +extern void lib_mcs_chrc_search_control_point_init(void); +extern void lib_mcs_chrc_search_results_obj_id_init(void); +#endif /* CONFIG_BT_MCS && CONFIG_BT_OTS */ + +#if CONFIG_BT_MPL_OBJECTS +extern uint64_t lib_media_proxy_sctrl_get_icon_id(void); +extern uint64_t lib_media_proxy_sctrl_get_track_segments_id(void); +extern uint64_t lib_media_proxy_sctrl_get_current_track_id(void); +extern void lib_media_proxy_sctrl_set_current_track_id(uint64_t id); +extern uint64_t lib_media_proxy_sctrl_get_next_track_id(void); +extern void lib_media_proxy_sctrl_set_next_track_id(uint64_t id); +extern uint64_t lib_media_proxy_sctrl_get_parent_group_id(void); +extern uint64_t lib_media_proxy_sctrl_get_current_group_id(void); +extern void lib_media_proxy_sctrl_set_current_group_id(uint64_t id); +extern void lib_media_proxy_sctrl_send_search(const struct mpl_search *search); +extern uint64_t lib_media_proxy_sctrl_get_search_results_id(void); +extern void lib_media_proxy_pl_current_track_id_cb(uint64_t id); +extern void lib_media_proxy_pl_next_track_id_cb(uint64_t id); +extern void lib_media_proxy_pl_parent_group_id_cb(uint64_t id); +extern void lib_media_proxy_pl_current_group_id_cb(uint64_t id); +extern void lib_media_proxy_pl_search_cb(uint8_t result_code); +extern void lib_media_proxy_pl_search_results_id_cb(uint64_t id); +#endif /* CONFIG_BT_MPL_OBJECTS */ + +#if CONFIG_BT_MICP_MIC_CTLR_AICS +extern uint8_t lib_micp_discover_include_func(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params); +extern int lib_micp_mic_ctrl_aics_init(void); +#endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */ + +#if CONFIG_BT_MICP_MIC_DEV_AICS +extern int lib_micp_mic_dev_prepare_aics_inst(struct bt_micp_mic_dev_register_param *param); +#endif /* CONFIG_BT_MICP_MIC_DEV_AICS */ + +#if CONFIG_BT_MPL_OBJECTS +extern uint64_t lib_mpl_get_icon_id(void); +extern uint64_t lib_mpl_get_track_segments_id(void); +extern uint64_t lib_mpl_get_current_track_id(void); +extern void lib_mpl_set_current_track_id(uint64_t id); +extern uint64_t lib_mpl_get_next_track_id(void); +extern void lib_mpl_set_next_track_id(uint64_t id); +extern uint64_t lib_mpl_get_parent_group_id(void); +extern uint64_t lib_mpl_get_current_group_id(void); +extern void lib_mpl_set_current_group_id(uint64_t id); +extern void lib_mpl_send_search(const struct mpl_search *search); +extern uint64_t lib_mpl_get_search_results_id(void); +#endif /* CONFIG_BT_MPL_OBJECTS */ + +#if CONFIG_BT_TBS_CLIENT_TBS +extern int lib_tbs_client_primary_discover_tbs(struct bt_conn *conn); +#endif /* CONFIG_BT_TBS_CLIENT_TBS */ + +#if CONFIG_BT_TBS_CLIENT_GTBS +extern int lib_tbs_client_primary_discover_gtbs(struct bt_conn *conn); +#endif /* CONFIG_BT_TBS_CLIENT_GTBS */ + +#if CONFIG_BT_TBS_CLIENT_CCID +extern struct bt_tbs_instance *lib_tbs_client_get_by_ccid(const struct bt_conn *conn, + uint8_t ccid); +#endif /* CONFIG_BT_TBS_CLIENT_CCID */ + +#if CONFIG_BT_VCP_VOL_CTLR_AICS +extern void lib_vcp_vol_ctlr_aics_init(void); +#endif /* CONFIG_BT_VCP_VOL_CTLR_AICS */ + +#if CONFIG_BT_VCP_VOL_CTLR_VOCS +extern void lib_vcp_vol_ctlr_vocs_init(void); +#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */ + +#if CONFIG_BT_VCP_VOL_CTLR_AICS || CONFIG_BT_VCP_VOL_CTLR_VOCS +extern uint8_t lib_vcp_vol_ctlr_vcs_discover_include_func(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params); + +extern int lib_vcp_vol_ctlr_included_get(struct bt_vcp_vol_ctlr *vol_ctlr, + struct bt_vcp_included *included); +#endif /* CONFIG_BT_VCP_VOL_CTLR_AICS || CONFIG_BT_VCP_VOL_CTLR_VOCS */ + +#if (CONFIG_BT_VCP_VOL_REND_AICS_INSTANCE_COUNT > 0) +extern int lib_vcp_vol_rend_prepare_aics_inst(struct bt_vcp_vol_rend_register_param *param); +#endif /* (CONFIG_BT_VCP_VOL_REND_AICS_INSTANCE_COUNT > 0) */ + +#if (CONFIG_BT_VCP_VOL_REND_VOCS_INSTANCE_COUNT > 0) +extern int lib_vcp_vol_rend_prepare_vocs_inst(struct bt_vcp_vol_rend_register_param *param); +#endif /* (CONFIG_BT_VCP_VOL_REND_VOCS_INSTANCE_COUNT > 0) */ + +#if CONFIG_BT_VOCS_CLIENT +extern int lib_vocs_client_state_get(struct bt_vocs_client *inst); +extern int lib_vocs_client_state_set(struct bt_vocs_client *inst, int16_t offset); +extern int lib_vocs_client_location_get(struct bt_vocs_client *inst); +extern int lib_vocs_client_location_set(struct bt_vocs_client *inst, uint32_t location); +extern int lib_vocs_client_description_get(struct bt_vocs_client *inst); +extern int lib_vocs_client_description_set(struct bt_vocs_client *inst, const char *description); +#endif /* CONFIG_BT_VOCS_CLIENT */ + +#ifdef __cplusplus +} +#endif + +#endif /* LIB_AUDIO_H_ */ diff --git a/components/bt/esp_ble_audio/lib/lib b/components/bt/esp_ble_audio/lib/lib new file mode 160000 index 0000000000..8e7fe18acf --- /dev/null +++ b/components/bt/esp_ble_audio/lib/lib @@ -0,0 +1 @@ +Subproject commit 8e7fe18acf4c3b7d4a74d6a1c6abc6b40941c20e diff --git a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in index 11c9fd899a..a721d4311f 100644 --- a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in @@ -1195,6 +1195,14 @@ config SOC_BLE_SUPPORTED bool default y +config SOC_BLE_ISO_SUPPORTED + bool + default y + +config SOC_BLE_AUDIO_SUPPORTED + bool + default y + config SOC_ESP_NIMBLE_CONTROLLER bool default y @@ -1231,10 +1239,6 @@ config SOC_BLE_PERIODIC_ADV_WITH_RESPONSE bool default y -config SOC_BLE_ISO_SUPPORTED - bool - default y - config SOC_USB_OTG_PERIPH_NUM int default 1 diff --git a/components/soc/esp32h4/include/soc/soc_caps.h b/components/soc/esp32h4/include/soc/soc_caps.h index 2f863a9ef9..101126959a 100644 --- a/components/soc/esp32h4/include/soc/soc_caps.h +++ b/components/soc/esp32h4/include/soc/soc_caps.h @@ -528,6 +528,8 @@ /*---------------------------------- Bluetooth CAPS ----------------------------------*/ #define SOC_BLE_SUPPORTED (1) /*!< Support Bluetooth Low Energy hardware */ // #define SOC_BLE_MESH_SUPPORTED (1) /*!< Support BLE MESH */ +#define SOC_BLE_ISO_SUPPORTED (1) /*!< Support BLE ISO */ +#define SOC_BLE_AUDIO_SUPPORTED (1) /*!< Support BLE Audio */ #define SOC_ESP_NIMBLE_CONTROLLER (1) /*!< Support BLE EMBEDDED controller V1 */ #define SOC_BLE_50_SUPPORTED (1) /*!< Support Bluetooth 5.0 */ #define SOC_BLE_DEVICE_PRIVACY_SUPPORTED (1) /*!< Support BLE device privacy mode */ @@ -537,7 +539,6 @@ #define SOC_BLE_CTE_SUPPORTED (1) /*!< Support Bluetooth LE Constant Tone Extension (CTE) */ #define SOC_BLE_SUBRATE_SUPPORTED (1) /*!< Support Bluetooth LE Connection Subrating */ #define SOC_BLE_PERIODIC_ADV_WITH_RESPONSE (1) /*!< Support Bluetooth LE Periodic Advertising with Response (PAwR) */ -#define SOC_BLE_ISO_SUPPORTED (1) /*!< Support Bluetooth ISO */ /*-------------------------- USB CAPS ----------------------------------------*/ #define SOC_USB_OTG_PERIPH_NUM (1U) diff --git a/docs/conf_common.py b/docs/conf_common.py index 71b07ab5b7..8fd1a29960 100644 --- a/docs/conf_common.py +++ b/docs/conf_common.py @@ -64,6 +64,15 @@ BLE_MESH_DOCS = [ 'api-reference/bluetooth/esp-ble-mesh.rst', ] +BLE_ISO_DOCS = [ + 'api-reference/bluetooth/esp-ble-iso.rst', +] + +BLE_AUDIO_DOCS = [ + 'api-reference/bluetooth/esp-ble-audio.rst', + 'api-guides/ble/ble-audio.rst', +] + CLASSIC_BT_DOCS = [ 'api-guides/classic-bt/index.rst', 'api-guides/classic-bt/overview.rst', @@ -343,6 +352,8 @@ conditional_include_dict = { 'SOC_BT_SUPPORTED': BT_DOCS, 'SOC_BLE_SUPPORTED': BLE_DOCS, 'SOC_BLE_MESH_SUPPORTED': BLE_MESH_DOCS, + 'SOC_BLE_ISO_SUPPORTED': BLE_ISO_DOCS, + 'SOC_BLE_AUDIO_SUPPORTED': BLE_AUDIO_DOCS, 'SOC_BLUFI_SUPPORTED': BLUFI_DOCS, 'SOC_WIFI_SUPPORTED': WIFI_DOCS, 'SOC_BT_CLASSIC_SUPPORTED': CLASSIC_BT_DOCS, diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile index 037bac5b38..d674b6ac14 100644 --- a/docs/doxygen/Doxyfile +++ b/docs/doxygen/Doxyfile @@ -55,6 +55,30 @@ INPUT = \ $(PROJECT_PATH)/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_sensor_model_api.h \ $(PROJECT_PATH)/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_time_scene_model_api.h \ $(PROJECT_PATH)/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_mbt_model_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_aics_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_bap_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_bap_lc3_preset_defs.h \ + $(PROJECT_PATH)/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_cap_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_ccp_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_codec_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_common_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_csip_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_defs.h \ + $(PROJECT_PATH)/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_gmap_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_gmap_lc3_preset_defs.h \ + $(PROJECT_PATH)/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_has_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_lc3_defs.h \ + $(PROJECT_PATH)/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_mcc_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_mcs_defs.h \ + $(PROJECT_PATH)/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_media_proxy_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_micp_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_pacs_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_pbp_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_tbs_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_tmap_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_vcp_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_audio/api/audio/include/esp_ble_audio_vocs_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_audio/api/iso/include/esp_ble_iso_common_api.h \ $(PROJECT_PATH)/components/bt/host/bluedroid/api/include/api/esp_a2dp_api.h \ $(PROJECT_PATH)/components/bt/host/bluedroid/api/include/api/esp_avrc_api.h \ $(PROJECT_PATH)/components/bt/host/bluedroid/api/include/api/esp_bt_defs.h \ diff --git a/docs/en/COPYRIGHT.rst b/docs/en/COPYRIGHT.rst index 928d7b2ebe..d38746ed42 100644 --- a/docs/en/COPYRIGHT.rst +++ b/docs/en/COPYRIGHT.rst @@ -55,6 +55,8 @@ These third party libraries can be included into the application (firmware) prod * :component:`BLE Mesh ` is adapted from Zephyr Project, Copyright (C) 2017-2018 Intel Corporation and licensed under Apache License 2.0. +* :component:`BLE Audio ` is adapted from Zephyr Project, Copyright (C) 2017-2018 Intel Corporation and licensed under Apache License 2.0. + * `mynewt-nimble`_, Copyright (C) 2015-2018 The Apache Software Foundation, is licensed under Apache License 2.0 as described in :component_file:`LICENSE file `. * `TLSF allocator `_, Copyright (C) 2006-2016 Matthew Conte, and licensed under the BSD 3-clause license. diff --git a/docs/en/api-guides/ble/ble-audio.rst b/docs/en/api-guides/ble/ble-audio.rst new file mode 100644 index 0000000000..c923cbdb67 --- /dev/null +++ b/docs/en/api-guides/ble/ble-audio.rst @@ -0,0 +1,497 @@ +LE Audio Architecture Guide +============================ + +:link_to_translation:`zh_CN:[中文]` + +This document introduces the Bluetooth LE Audio architecture: its profiles, services, the roles they define, and the dependency relationships among them. It is intended as a conceptual reference to help you choose the right set of profiles for your application before working with the :doc:`ESP-BLE-AUDIO API reference <../../api-reference/bluetooth/esp-ble-audio>`. + + +Overview +-------- + +Bluetooth LE Audio is a suite of specifications introduced in Bluetooth Core Specification 5.2. It enables high-quality, low-power audio over Bluetooth LE using the following key additions to the standard: + +- **LE Isochronous Channels (ISO)** — A new controller-level transport for time-synchronized, low-latency data streams, supporting both connected (CIS) and connectionless (BIS) modes. +- **LC3 Codec** — The Low Complexity Communication Codec, which provides better audio quality at lower bitrates compared to SBC. +- **Generic Audio Framework (GAF)** — A layered set of profiles and services that standardize audio stream setup, volume control, media control, call control, and device coordination. + +LE Audio supports two fundamental audio scenarios: + +- **Unicast Audio** — Bidirectional or unidirectional audio between two connected devices over Connected Isochronous Streams (CIS). Typical use cases: TWS earbuds, hearing aids, headsets, telephony. +- **Broadcast Audio (Auracast™)** — Unidirectional audio from one broadcaster to any number of receivers over Broadcast Isochronous Streams (BIS). Typical use cases: public venue audio, accessibility assistive listening, group TV listening. + + +Architecture Overview +--------------------- + +The LE Audio architecture is organized into three tiers: + +1. **LE Isochronous Channels** — The transport layer, providing CIS (connected) and BIS (broadcast) streams. +2. **Generic Audio Framework (GAF)** — The core specification suite, organized into four functional layers: stream control, content control, rendering/capture control, and transition/coordination control. +3. **Use-Case Specific Profiles** — Higher-level profiles (HAP, TMAP, GMAP, PBP) that select and configure specific GAF components for a target use case. + +.. code-block:: none + + ┌──────────────────────────────────────────────────────────────────────┐ + │ Use-Case Specific Profiles │ + │ HAP TMAP GMAP PBP │ + ├──────────────────────────────────────────────────────────────────────┤ + │ Generic Audio Framework (GAF) │ + │ ┌───────────────────────────────────────────────────────────────┐ │ + │ │ Transition & CAP + CAS │ │ + │ │ Coordination Control CSIP + CSIS │ │ + │ ├───────────────────────────────────────────────────────────────┤ │ + │ │ Rendering & VCP (VCS, VOCS, AICS) │ │ + │ │ Capture Control MICP (MICS, AICS) │ │ + │ ├───────────────────────────────────────────────────────────────┤ │ + │ │ Content Control MCP + MCS/GMCS │ │ + │ │ CCP + TBS/GTBS │ │ + │ ├───────────────────────────────────────────────────────────────┤ │ + │ │ Stream Control BAP (PACS, ASCS, BASS) │ │ + │ └───────────────────────────────────────────────────────────────┘ │ + ├──────────────────────────────────────────────────────────────────────┤ + │ LE Isochronous Channels (CIS / BIS) │ + └──────────────────────────────────────────────────────────────────────┘ + +Each GAF layer depends only on the layers below it. Use-case profiles select a subset of GAF layers and add role-specific constraints on top. The sections below describe each component in detail. + + +LE Isochronous Channels +----------------------- + +LE Isochronous Channels are a feature of the Bluetooth controller, defined in the Bluetooth Core Specification. They provide the time-synchronized, low-latency data transport that LE Audio relies on. + +.. list-table:: + :header-rows: 1 + :widths: 15 15 70 + + * - Type + - Abbreviation + - Description + * - Connected Isochronous Stream + - CIS + - Bidirectional isochronous link between two devices; requires a prior ACL connection. Multiple CIS instances can be grouped into a Connected Isochronous Group (CIG) for synchronized playback (e.g., left and right earbuds). + * - Broadcast Isochronous Stream + - BIS + - Unidirectional isochronous stream from a Broadcaster to any number of Synchronized Receivers, without a prior connection. Multiple BIS instances belong to a Broadcast Isochronous Group (BIG). + +ESP-IDF provides direct access to CIS and BIS via the :doc:`ESP-BLE-ISO API <../../api-reference/bluetooth/esp-ble-iso>`. When using LE Audio profiles (BAP and above), the ISO layer is managed automatically by the profile stack. + + +Generic Audio Framework +----------------------- + +The Generic Audio Framework (GAF) is the core of LE Audio. It defines four functional layers, described below from the bottom up. + + +Stream Control Layer +^^^^^^^^^^^^^^^^^^^^ + +The stream control layer is responsible for discovering audio capabilities, setting up audio streams (codec configuration and QoS), and managing the lifecycle of CIS and BIS connections. + +**Basic Audio Profile (BAP)** + +BAP is the foundational profile for all LE Audio streaming. It defines the following roles: + +- **Unicast Client** — Discovers ASEs on a remote Unicast Server, initiates codec configuration, QoS negotiation, and stream control (enable, connect, start, disable, release). +- **Unicast Server** — Exposes audio endpoints (ASEs) via ASCS and responds to client-initiated stream control procedures. +- **Broadcast Source** — Creates a BIG, configures BIS streams, and sends audio data. +- **Broadcast Sink** — Scans for and synchronizes to a Broadcast Source, receives BIS audio data. +- **Broadcast Assistant** — Scans for Broadcast Sources on behalf of a low-power Scan Delegator and writes the results to BASS on the delegator. +- **Scan Delegator** — Exposes BASS and delegates BIS scanning to a Broadcast Assistant. + +BAP depends on three GATT services: + +.. list-table:: + :header-rows: 1 + :widths: 35 65 + + * - Service + - Role + * - Published Audio Capabilities Service (PACS) + - Exposes the device's supported codecs, codec configurations, and available audio contexts. Present on both Unicast Server and Broadcast Sink. + * - Audio Stream Control Service (ASCS) + - Exposes one or more Audio Stream Endpoints (ASEs), each representing a sink or source data path. Present on the Unicast Server only. + * - Broadcast Audio Scan Service (BASS) + - Used by the Scan Delegator to expose receive state; written by the Broadcast Assistant with Broadcast Source information. Present on the Scan Delegator only. + + +Content Control Layer +^^^^^^^^^^^^^^^^^^^^^ + +The content control layer provides standardized control over the media content and telephony activity that is being rendered by the audio stream. + +**Media Control Profile (MCP) and Media Control Service (MCS)** + +MCP defines a **Media Control Server** (which exposes a media player via MCS) and a **Media Control Client** (which discovers and controls the player). MCS exposes media state (playing/paused/stopped), playback position, track metadata, and control point operations (play, pause, next track, seek, etc.). + +MCS comes in two forms: + +- **MCS** — Per-player instance, for devices with multiple concurrent media players. +- **Generic MCS (GMCS)** — A single mandatory instance that provides access to the currently active player, used by clients that do not need per-player granularity. + +MCP can optionally depend on the **Object Transfer Profile (OTP)** and **Object Transfer Service (OTS)** for transferring media objects (track names, icons, object metadata) when the device supports it. + +**Call Control Profile (CCP) and Telephone Bearer Service (TBS)** + +CCP defines a **Call Control Server** (which exposes one or more telephone bearers via TBS) and a **Call Control Client** (which discovers and controls calls). TBS exposes call state, call URI schemes, incoming/outgoing call control, signal strength, and provider name. + +TBS comes in two forms: + +- **TBS** — Per-bearer instance for devices with multiple telephony bearers (e.g., separate SIM cards or VoIP applications). +- **Generic TBS (GTBS)** — A single mandatory instance that provides a unified view of all bearers. + + +Rendering and Capture Control Layer +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The rendering and capture control layer provides standardized control over the audio output level and audio input gain of a device, independent of the content being played. + +**Volume Control Profile (VCP)** + +VCP defines a **Volume Renderer** (which exposes volume state and accepts remote control) and a **Volume Controller** (which discovers and controls the renderer). VCP depends on the following GATT services: + +.. list-table:: + :header-rows: 1 + :widths: 35 15 50 + + * - Service + - Required + - Description + * - Volume Control Service (VCS) + - Mandatory + - Exposes volume setting (0–255), mute state, and a volume control point for absolute or relative volume changes. + * - Volume Offset Control Service (VOCS) + - Optional + - Allows per-output volume offset adjustment (e.g., different offsets for left and right channel outputs). A VCS may include one or more VOCS instances. + * - Audio Input Control Service (AICS) + - Optional + - Allows control of audio input gain and mute state for one audio input (e.g., microphone). A VCS may include one or more AICS instances. + +**Microphone Control Profile (MICP)** + +MICP defines a **Microphone Device** (which exposes microphone state) and a **Microphone Controller** (which discovers and mutes/unmutes it). MICP depends on the following GATT services: + +.. list-table:: + :header-rows: 1 + :widths: 35 15 50 + + * - Service + - Required + - Description + * - Microphone Control Service (MICS) + - Mandatory + - Exposes the microphone mute state and a mute control point. Present on the Microphone Device. + * - Audio Input Control Service (AICS) + - Optional + - Allows control of audio input gain for specific inputs. A MICS may include one or more AICS instances. + +.. note:: + + AICS is a shared service: it can be included by both VCS (as part of VCP) and MICS (as part of MICP), each as independent instances with separate handles. + + +Transition and Coordination Control Layer +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The transition and coordination control layer is the top of the GAF. It coordinates audio procedures across multiple devices acting as a group (e.g., a pair of TWS earbuds, or a room of speakers). + +**Common Audio Profile (CAP)** + +CAP is the top-level profile that defines how a single initiating device can coordinate audio operations (stream setup, volume control, microphone control) across one or more target devices. It defines three roles: + +- **CAP Acceptor** — A device that accepts audio streams and volume/microphone control from a CAP Initiator or Commander. A CAP Acceptor shall support BAP Unicast Server or BAP Broadcast Sink (or both), and VCP Volume Renderer. MICP Microphone Device is optional. +- **CAP Initiator** — A device that discovers CAP Acceptors and initiates unicast or broadcast audio procedures using BAP, VCP, and MICP on one or more acceptors simultaneously. +- **CAP Commander** — A device that issues coordinated volume and microphone control commands to one or more CAP Acceptors without managing audio streams directly. + +CAP depends on the **Common Audio Service (CAS)**, a mandatory GATT service on every CAP Acceptor. CAS is used for coordinated set member announcement and provides a stable discovery anchor for the CAP Initiator/Commander. + +CAP also uses **CSIP** (described below) to identify and address the members of a coordinated set as a group. + +**Coordinated Set Identification Profile (CSIP)** + +CSIP defines how a group of devices (a "coordinated set") can be discovered and identified as belonging together. A common example is a left/right earbud pair: each earbud is a **CSIP Set Member** and a phone or source device is a **CSIP Set Coordinator**. + +CSIP depends on the **Coordinated Set Identification Service (CSIS)**, which exposes: + +- A **Set Identity Resolving Key (SIRK)** — Used by the Set Coordinator to match devices belonging to the same set, even across re-advertisements. +- **Set Size** — The number of members in the set. +- **Member Rank** — The rank of this device within the set (used for ordered operations). + + +Use-Case Specific Profiles +--------------------------- + +Use-case specific profiles sit on top of the GAF. Each profile selects a specific subset of GAF profiles, defines role-specific configuration constraints (e.g., codec parameters, QoS settings), and may add its own small GATT service for role advertisement. + +**Hearing Access Profile (HAP)** + +HAP targets hearing aid devices. It adds the concept of **hearing aid presets**: named audio configurations (e.g., "Outdoor", "Restaurant") that the user can select. HAP defines: + +- **Hearing Aid** — Implements all GAF roles needed for audio reception, volume control, and (for binaural hearing aid pairs) coordinated set membership. +- **Hearing Aid Unicast Client** — Discovers hearing aids, controls presets, and manages unicast audio streams. + +HAP depends on the **Hearing Access Service (HAS)** for preset read/write operations and on BAP, PACS, VCP, MICP, and CSIP from the GAF. + +**Telephony and Media Audio Profile (TMAP)** + +TMAP defines interoperability configurations for telephony and media use cases. It defines six roles: + +.. list-table:: + :header-rows: 1 + :widths: 20 20 60 + + * - Role + - Abbreviation + - Description + * - Call Gateway + - CG + - Controls calls on a remote CT using CCP/TBS. Sends and receives bidirectional audio over CIS. + * - Call Terminal + - CT + - Exposes calls via TBS; receives and sends bidirectional audio over CIS. + * - Unicast Media Sender + - UMS + - Sends unidirectional media audio to one or more UMRs over CIS. Acts as BAP Unicast Client and MCP server. + * - Unicast Media Receiver + - UMR + - Receives media audio from a UMS over CIS. Acts as BAP Unicast Server and VCP Volume Renderer. + * - Broadcast Media Sender + - BMS + - Sends media audio to any number of BMRs over BIS. Acts as BAP Broadcast Source. + * - Broadcast Media Receiver + - BMR + - Receives media audio from a BMS over BIS. Acts as BAP Broadcast Sink. + +TMAP advertises its roles via the **Telephony and Media Audio Service (TMAS)**, a small GATT service containing a single TMAP Role characteristic. This allows a remote device to discover which TMAP roles the local device supports before establishing a connection. TMAP itself does not define new audio transport mechanisms; it delegates entirely to BAP (for stream setup), VCP (for volume), MCP/MCS (for media control in UMS/UMR), and CCP/TBS (for call control in CG/CT). + +**Gaming Audio Profile (GMAP)** + +GMAP targets gaming audio products with parameters tuned for lower transport latency and fewer retransmissions. It defines four roles: + +.. list-table:: + :header-rows: 1 + :widths: 20 20 60 + + * - Role + - Abbreviation + - Description + * - Unicast Game Gateway + - UGG + - Sends game audio to UGTs and optionally receives voice audio back. Acts as BAP Unicast Client. + * - Unicast Game Terminal + - UGT + - Receives game audio from a UGG and optionally sends voice audio back. Acts as BAP Unicast Server. + * - Broadcast Game Sender + - BGS + - Sends game audio over BIS. Acts as BAP Broadcast Source. + * - Broadcast Game Receiver + - BGR + - Receives game audio over BIS. Acts as BAP Broadcast Sink. + +GMAP advertises roles via the **Gaming Audio Service (GMAS)** and depends on BAP for stream setup and VCP for volume control. + +**Public Broadcast Profile (PBP)** + +PBP standardizes the metadata format used by a public broadcast source so that any compatible receiver can discover and synchronize to it without prior pairing. It defines: + +- **Public Broadcast Source** — Advertises Auracast™ audio streams with standardized extended advertising data including the Broadcast Audio Announcement and Public Broadcast Announcement. Delegates to BAP Broadcast Source for BIS setup. +- **Public Broadcast Sink** — Scans for PBP sources, reads the announcement metadata to determine audio quality and content, and synchronizes to the BIG. Delegates to BAP Broadcast Sink. + +PBP depends entirely on BAP for the underlying broadcast transport; it does not define a new GATT service. + + +Profile and Service Dependency Reference +----------------------------------------- + +The following tables summarize the dependencies between profiles and services in the ESP-IDF LE Audio implementation. + +Profile-to-Service Dependencies +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. list-table:: + :header-rows: 1 + :widths: 22 20 58 + + * - Profile + - Depends on (Services) + - Notes + * - BAP + - PACS, ASCS, BASS + - PACS on Unicast Server and Broadcast Sink; ASCS on Unicast Server only; BASS on Scan Delegator only. + * - VCP + - VCS (mandatory), VOCS (optional), AICS (optional) + - VOCS and AICS are sub-included services within VCS; each may have multiple instances. + * - MICP + - MICS (mandatory), AICS (optional) + - AICS is a sub-included service within MICS. + * - CAP + - CAS (mandatory) + - CAS must be present on every CAP Acceptor. CAP also uses BAP, VCP, MICP, and CSIP procedures. + * - CSIP + - CSIS (mandatory) + - CSIS on the Set Member device. + * - MCP + - MCS / GMCS (mandatory), OTS (optional) + - GMCS is the single mandatory generic instance; per-player MCS instances are optional. OTS is used when media objects are available. + * - CCP + - TBS / GTBS (mandatory) + - GTBS is the single mandatory generic instance; per-bearer TBS instances are optional. + * - HAP + - HAS (mandatory) + - HAS for preset control. HAP also mandates BAP, PACS, VCP, MICP, and CSIP (for binaural sets). + * - TMAP + - TMAS (mandatory) + - TMAS contains only the TMAP Role characteristic. TMAP delegates stream and control operations to BAP, VCP, MCP, and CCP. + * - GMAP + - GMAS (mandatory) + - GMAS contains only the GMAP Role characteristic. GMAP delegates to BAP and VCP. + * - PBP + - None (no dedicated service) + - PBP uses BAP Broadcast Source/Sink and standardized extended advertising metadata only. + + +Profile-to-Profile Dependencies +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. list-table:: + :header-rows: 1 + :widths: 22 22 56 + + * - Profile + - Depends on (Profiles) + - Notes + * - CAP Initiator / Commander + - BAP, VCP, MICP, CSIP + - Uses BAP for stream setup, VCP and MICP for rendering/capture control, CSIP to address a coordinated set of Acceptors. + * - HAP + - BAP, VCP, MICP, CSIP, CAP + - CAP Acceptor role is mandatory on Hearing Aid devices. CSIP is required for binaural hearing aid pairs. + * - TMAP CG / CT + - BAP (unicast), VCP, CCP + - CG also acts as MCP server (media proxy) in some implementations. + * - TMAP UMS / UMR + - BAP (unicast), VCP, MCP + - — + * - TMAP BMS / BMR + - BAP (broadcast), VCP + - — + * - GMAP UGG / UGT + - BAP (unicast), VCP + - — + * - GMAP BGS / BGR + - BAP (broadcast), VCP + - — + * - PBP Source / Sink + - BAP (broadcast) + - — + + +Typical Use-Case Profiles +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The table below maps common product types to the profiles they require. + +.. list-table:: + :header-rows: 1 + :widths: 30 70 + + * - Product Type + - Required Profiles / Roles + * - TWS Earbuds (receiver side) + - CAP Acceptor, BAP Unicast Server, VCP Volume Renderer, CSIP Set Member, MICP Microphone Device (if mic present) + * - Phone / Audio Source + - CAP Initiator, BAP Unicast Client, VCP Volume Controller, CSIP Set Coordinator + * - Hearing Aid + - HAP Hearing Aid, CAP Acceptor, BAP Unicast Server, VCP Volume Renderer, CSIP Set Member (for binaural pair) + * - TV / Broadcast Source + - BAP Broadcast Source, PBP Public Broadcast Source (for Auracast™) + * - Hearing Loop Receiver + - BAP Broadcast Sink, PBP Public Broadcast Sink + * - Telephony Headset + - TMAP CT + UMR (or CG + UMS for gateway side), VCP, CCP + * - Gaming Headset + - GMAP UGT (receiver), BAP Unicast Server, VCP Volume Renderer + * - Media Sender (audio bar) + - TMAP UMS (or BMS for broadcast), BAP, MCP/MCS server, VCP + + +ESP-IDF Implementation +----------------------- + +ESP-IDF provides two API components for LE Audio: + +- :doc:`ESP-BLE-ISO <../../api-reference/bluetooth/esp-ble-iso>` — Direct access to LE Isochronous Channels (CIS/BIS) for applications that manage their own ISO data paths. +- :doc:`ESP-BLE-AUDIO <../../api-reference/bluetooth/esp-ble-audio>` — High-level LE Audio profile and service APIs covering the full GAF stack (BAP, CAP, VCP, MICP, CSIP, MCP, CCP, HAP, GMAP, TMAP, PBP) and codec support (LC3). + +For most applications, ESP-BLE-AUDIO is the correct starting point. ESP-BLE-ISO is intended for advanced use cases that require direct ISO control below the profile layer. + +Feature Support +^^^^^^^^^^^^^^^ + +The table below lists the LE Audio profiles and services currently supported in ESP-IDF. + +.. list-table:: + :header-rows: 1 + :widths: 28 12 60 + + * - Profile / Service + - Supported + - Notes + * - LE Isochronous Channels (CIS / BIS) + - Yes + - Direct ISO access via :doc:`ESP-BLE-ISO <../../api-reference/bluetooth/esp-ble-iso>`. + * - BAP + - Yes + - All six BAP roles: Unicast Client, Unicast Server, Broadcast Source, Broadcast Sink, Broadcast Assistant, Scan Delegator. + * - PACS + - Yes + - Used by BAP Unicast Server and Broadcast Sink. + * - ASCS + - Yes + - Used by BAP Unicast Server. + * - BASS + - Yes + - Used by BAP Scan Delegator and Broadcast Assistant. + * - CAP + - Yes + - All three CAP roles: Acceptor, Initiator, Commander. + * - CAS + - Yes + - Mandatory service on CAP Acceptors. + * - CSIP / CSIS + - Yes + - Set Member and Set Coordinator roles. + * - VCP / VCS + - Yes + - Volume Renderer and Volume Controller roles. + * - VOCS + - Yes + - Per-output volume offset control; included in VCS as an optional sub-service. + * - AICS + - Yes + - Audio input control; included in VCS and MICS as an optional sub-service. + * - MICP / MICS + - Yes + - Microphone Device and Microphone Controller roles. + * - MCP / MCS + - Partial + - Media Control Server and Media Control Client roles are supported. OTP/OTS-based media object transfer is not currently supported. + * - CCP / TBS + - Yes + - Call Control Server and Call Control Client roles, including GTBS and per-bearer TBS. + * - HAP / HAS + - Yes + - Hearing Aid and Hearing Aid Unicast Client roles, including preset read/write via HAS. + * - TMAP / TMAS + - Yes + - All six TMAP roles: CG, CT, UMS, UMR, BMS, BMR. + * - GMAP / GMAS + - Yes + - All four GMAP roles: UGG, UGT, BGS, BGR. + * - PBP + - Yes + - Public Broadcast Source and Public Broadcast Sink roles. + * - OTP / OTS + - No + - Object Transfer Profile/Service (used by MCP/MCS for media object transfer) is not currently supported. diff --git a/docs/en/api-guides/ble/index.rst b/docs/en/api-guides/ble/index.rst index 1663f253f9..2d32cda331 100644 --- a/docs/en/api-guides/ble/index.rst +++ b/docs/en/api-guides/ble/index.rst @@ -46,3 +46,4 @@ Profile :SOC_BLE_MESH_SUPPORTED: ../esp-ble-mesh/ble-mesh-index :SOC_BLUFI_SUPPORTED: blufi + :SOC_BLE_AUDIO_SUPPORTED: ble-audio diff --git a/docs/en/api-guides/ble/overview.rst b/docs/en/api-guides/ble/overview.rst index 5a3d7204f3..dd2b008b99 100644 --- a/docs/en/api-guides/ble/overview.rst +++ b/docs/en/api-guides/ble/overview.rst @@ -58,48 +58,64 @@ The table below shows whether the Bluetooth LE modules are supported in a specif - ESP-Bluedroid - ESP-NimBLE - ESP-BLE-MESH + - ESP-BLE-ISO + - ESP-BLE-AUDIO - BluFi * - ESP32 - Y - Y - Y - Y + - \– + - \– - Y * - ESP32-S3 - Y - Y - Y - Y + - \– + - \– - Y * - ESP32-C2 - Y - Y - Y - \– + - \– + - \– - Y * - ESP32-C3 - Y - Y - Y - Y + - \– + - \– - Y * - ESP32-C5 - Y - Y - Y - Y + - \– + - \– - Y * - ESP32-C6 - Y - Y - Y - Y + - \– + - \– - Y * - ESP32-C61 - Y - Y - Y - Y + - \– + - \– - Y * - ESP32-H2 - Y @@ -107,6 +123,16 @@ The table below shows whether the Bluetooth LE modules are supported in a specif - Y - Y - \– + - \– + - \– + * - ESP32-H4 + - Y + - Y + - Y + - Y + - Y + - Y + - \– The following sections briefly describe each layer and provide quick links to the related documents and application examples. diff --git a/docs/en/api-reference/bluetooth/esp-ble-audio.rst b/docs/en/api-reference/bluetooth/esp-ble-audio.rst new file mode 100644 index 0000000000..aae2c30e8e --- /dev/null +++ b/docs/en/api-reference/bluetooth/esp-ble-audio.rst @@ -0,0 +1,241 @@ +ESP-BLE-AUDIO +============= + +ESP-BLE-AUDIO provides APIs for Bluetooth LE Audio, enabling time-synchronized audio over BLE using the Bluetooth Core Specification LE Audio architecture. Applications can implement unicast (one-to-one) and broadcast audio scenarios, including hearing aids, headsets, speakers, and broadcast sources/sinks. + +The LE Audio stack is built on the **Bluetooth Core** and the **LC3** codec. The **generic audio framework** includes the Common Audio Profile (CAP), Common Audio Service (CAS), and the profiles and services below. **Use case specific profiles** (HAP, GMAP, TMAP, PBP) sit on top of the generic framework. LE Audio runs over the LE Isochronous Channels (CIS/BIS) supported by :doc:`esp-ble-iso`. + +.. warning:: + + This is a **preview release**. The ESP-BLE-AUDIO APIs, data structures, and configuration parameters are subject to change in future releases. Breaking changes — such as renamed or restructured types, modified function signatures, or removed fields — may be introduced without prior notice. + +**Generic audio framework** + +* **Common Audio Profile (CAP)** — Top-level profile for coordinating audio procedures across single or multiple devices. +* **Common Audio Service (CAS)** — GATT service companion to CAP; used for coordinated set member announcement. +* **Basic Audio Profile (BAP)** — Unicast and broadcast stream setup, codec configuration, and stream control. +* **Published Audio Capabilities Service (PACS)** — Advertising and negotiating audio capabilities. +* **Audio Stream Control Service (ASCS)** — Exposes sink/source audio endpoints on a BAP Unicast Server; used by the Unicast Client to configure and control streams. +* **Broadcast Audio Scan Service (BASS)** — Allows a Broadcast Assistant to offload BIS scanning from a low-power Scan Delegator. +* **Volume Control Profile (VCP)** — Volume control (VCS, VOCS, AICS). +* **Volume Offset Control Service (VOCS)** — Per-output volume offset. +* **Audio Input Control Service (AICS)** — Audio input (microphone) state and gain. +* **Microphone Control Profile (MICP)** — Microphone mute and gain (MICS). +* **Coordinated Set Identification Profile (CSIP)** — Set member identification for coordinated sets (e.g., left/right earbuds). +* **Media Control Profile (MCP)** — Media control (MCS). +* **Media Control Service (MCS)** — Media control service. +* **Call Control Profile (CCP)** — Call/telephony control (TBS). +* **Telephone Bearer Service (TBS)** — Telephony bearer and in-call control. +* **Media Proxy** — Media proxy service (Zephyr implementation component; not a Bluetooth SIG specification). + +**Use case specific profiles** + +* **Hearing Access Profile (HAP)** — Hearing aid presets and presets control. +* **Gaming Audio Profile (GMAP)** — Gaming audio (e.g. Unicast Game Gateway/Terminal, Broadcast Game Sender/Receiver). +* **Telephony and Media Audio Profile (TMAP)** — Interoperability configurations for telephony and media audio use cases. +* **Public Broadcast Profile (PBP)** — Discovery and subscription to public broadcast streams. + +Application Examples +-------------------- + +* **BAP (Basic Audio Profile)** + + * :example:`bluetooth/esp_ble_audio/bap/broadcast_sink` demonstrates how to act as a BAP Broadcast Sink that synchronizes to a broadcast source and receives BIS audio streams. + * :example:`bluetooth/esp_ble_audio/bap/broadcast_source` demonstrates how to act as a BAP Broadcast Source that creates a BIG and sends broadcast audio over BIS. + * :example:`bluetooth/esp_ble_audio/bap/unicast_client` demonstrates how to discover and connect to a unicast server and establish BAP unicast streams. + * :example:`bluetooth/esp_ble_audio/bap/unicast_server` demonstrates how to advertise and accept unicast connections and serve BAP unicast streams. + +* **CAP (Common Audio Profile)** + + * :example:`bluetooth/esp_ble_audio/cap/acceptor` demonstrates how to act as a CAP Acceptor for unicast and broadcast flows. + * :example:`bluetooth/esp_ble_audio/cap/initiator` demonstrates how to act as a CAP Initiator for unicast and broadcast flows. + +* **TMAP (Telephony and Media Audio Profile)** + + * :example:`bluetooth/esp_ble_audio/tmap/bmr` demonstrates the TMAP Broadcast Media Receiver (BMR) role that receives broadcast audio from a BMS. + * :example:`bluetooth/esp_ble_audio/tmap/bms` demonstrates the TMAP Broadcast Media Sender (BMS) role that sends broadcast audio. + * :example:`bluetooth/esp_ble_audio/tmap/central` demonstrates the TMAP Call Gateway (CG) and Unicast Media Sender (UMS) roles. + * :example:`bluetooth/esp_ble_audio/tmap/peripheral` demonstrates the TMAP Call Terminal (CT) and Unicast Media Receiver (UMR) roles. + +API Reference +------------- + +ESP-BLE-AUDIO APIs are divided into the following parts: + +* `Definitions `_ + + * `General Definitions`_ + * `LC3 Codec Definitions`_ + * `MCS Definitions`_ + * `BAP LC3 Preset Definitions`_ + * `GMAP LC3 Preset Definitions`_ + +* `API `_ + + * `Common API`_ + * `Codec API`_ + * `Common Audio Profile (CAP)`_ + * `Call Control Profile (CCP)`_ + * `Basic Audio Profile (BAP)`_ + * `Published Audio Capabilities (PACS)`_ + * `Gaming Audio Profile (GMAP)`_ + * `Volume Control Profile (VCP)`_ + * `Volume Offset Control Service (VOCS)`_ + * `Audio Input Control Service (AICS)`_ + * `Microphone Control Profile (MICP)`_ + * `Hearing Access Profile (HAP)`_ + * `Coordinated Set Identification Profile (CSIP)`_ + * `Telephone Bearer Service (TBS)`_ + * `Media Control Client (MCC)`_ + * `Media Proxy`_ + * `Telephony and Media Audio Profile (TMAP)`_ + * `Public Broadcast Profile (PBP)`_ + +ESP-BLE-AUDIO Definitions +------------------------- + +This section contains common definitions, constants, and types used across LE Audio. + + +General Definitions +^^^^^^^^^^^^^^^^^^^ + +.. include-build-file:: inc/esp_ble_audio_defs.inc + + +LC3 Codec Definitions +^^^^^^^^^^^^^^^^^^^^^ + +.. include-build-file:: inc/esp_ble_audio_lc3_defs.inc + + +MCS Definitions +^^^^^^^^^^^^^^^ + +.. include-build-file:: inc/esp_ble_audio_mcs_defs.inc + + +BAP LC3 Preset Definitions +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. include-build-file:: inc/esp_ble_audio_bap_lc3_preset_defs.inc + + +GMAP LC3 Preset Definitions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. include-build-file:: inc/esp_ble_audio_gmap_lc3_preset_defs.inc + + +ESP-BLE-AUDIO API +----------------- + +This section contains LE Audio APIs: common helpers, codec, Common Audio Profile (CAP), Call Control Profile (CCP), and all profile/service APIs. + + +Common API +^^^^^^^^^^ + +.. include-build-file:: inc/esp_ble_audio_common_api.inc + + +Codec API +^^^^^^^^^ + +.. include-build-file:: inc/esp_ble_audio_codec_api.inc + + +Common Audio Profile (CAP) +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. include-build-file:: inc/esp_ble_audio_cap_api.inc + + +Call Control Profile (CCP) +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. include-build-file:: inc/esp_ble_audio_ccp_api.inc + + +Basic Audio Profile (BAP) +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. include-build-file:: inc/esp_ble_audio_bap_api.inc + + +Published Audio Capabilities (PACS) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. include-build-file:: inc/esp_ble_audio_pacs_api.inc + + +Gaming Audio Profile (GMAP) +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. include-build-file:: inc/esp_ble_audio_gmap_api.inc + + +Volume Control Profile (VCP) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. include-build-file:: inc/esp_ble_audio_vcp_api.inc + + +Volume Offset Control Service (VOCS) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. include-build-file:: inc/esp_ble_audio_vocs_api.inc + + +Audio Input Control Service (AICS) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. include-build-file:: inc/esp_ble_audio_aics_api.inc + + +Microphone Control Profile (MICP) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. include-build-file:: inc/esp_ble_audio_micp_api.inc + + +Hearing Access Profile (HAP) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. include-build-file:: inc/esp_ble_audio_has_api.inc + + +Coordinated Set Identification Profile (CSIP) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. include-build-file:: inc/esp_ble_audio_csip_api.inc + + +Telephone Bearer Service (TBS) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. include-build-file:: inc/esp_ble_audio_tbs_api.inc + + +Media Control Client (MCC) +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. include-build-file:: inc/esp_ble_audio_mcc_api.inc + + +Media Proxy +^^^^^^^^^^^ + +.. include-build-file:: inc/esp_ble_audio_media_proxy_api.inc + + +Telephony and Media Audio Profile (TMAP) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. include-build-file:: inc/esp_ble_audio_tmap_api.inc + + +Public Broadcast Profile (PBP) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. include-build-file:: inc/esp_ble_audio_pbp_api.inc diff --git a/docs/en/api-reference/bluetooth/esp-ble-iso.rst b/docs/en/api-reference/bluetooth/esp-ble-iso.rst new file mode 100644 index 0000000000..0468e681b1 --- /dev/null +++ b/docs/en/api-reference/bluetooth/esp-ble-iso.rst @@ -0,0 +1,41 @@ +ESP-BLE-ISO +=========== + +ESP-BLE-ISO provides APIs for Bluetooth LE Isochronous Channels, enabling time-synchronized, connection-oriented (CIS) and connectionless (BIS) streaming. The implementation is built on the Bluetooth controller ISO support and is intended for use with the :doc:`esp-ble-audio` component. + +**Channel types** + +* **Connected Isochronous Streams (CIS)** — Bidirectional isochronous links between two devices; requires a prior ACL connection to be established. Used for time-synchronized unicast audio (e.g., LE Audio). +* **Broadcast Isochronous Streams (BIS)** — Unidirectional isochronous streams from a Broadcaster to one or more Synchronized Receivers, without a prior connection. Used for broadcast audio and group listening. + +With these APIs you can create or join Connected ISO Groups (CIG), create or synchronize to Broadcast ISO Groups (BIG), set up ISO data paths, and send or receive isochronous data (e.g., LC3 audio). For higher-level LE Audio profiles and codec APIs, see :doc:`esp-ble-audio`. + +.. warning:: + + This is a **preview release**. The ESP-BLE-ISO APIs, data structures, and configuration parameters are subject to change in future releases. Breaking changes — such as renamed or restructured types, modified function signatures, or removed fields — may be introduced without prior notice. + +Application Examples +-------------------- + +* **BIG (Broadcast Isochronous Group)** + - :example:`bluetooth/esp_ble_iso/big_broadcaster` demonstrates how to create a BIG and send isochronous data over BIS. + - :example:`bluetooth/esp_ble_iso/big_receiver` demonstrates how to synchronize to a BIG and receive isochronous data from BIS. +* **CIS (Connected Isochronous Stream)** + - :example:`bluetooth/esp_ble_iso/cis_central` demonstrates how to act as a CIS Central that creates a CIG/CIS and sends isochronous data. + - :example:`bluetooth/esp_ble_iso/cis_peripheral` demonstrates how to act as a CIS Peripheral that accepts a CIS and receives isochronous data. + + +API Reference +------------- + +ESP-BLE-ISO APIs are divided into the following parts: + +* `ESP-BLE-ISO Common API`_ + + +ESP-BLE-ISO Common API +---------------------- + +This section contains macros, type definitions, and functions from ``esp_ble_iso_common_api.h``: BIS index and data path macros, controller delay and interval limits, CIG/BIG parameters and structures, ISO server and channel operations, data path setup, BIG create/sync/terminate, and GAP event types and ISO common initialization. + +.. include-build-file:: inc/esp_ble_iso_common_api.inc diff --git a/docs/en/api-reference/bluetooth/index.rst b/docs/en/api-reference/bluetooth/index.rst index e2fb8a2e7f..e0ec323dcf 100644 --- a/docs/en/api-reference/bluetooth/index.rst +++ b/docs/en/api-reference/bluetooth/index.rst @@ -65,6 +65,28 @@ For additional details and API reference from the upstream documentation, refer esp-ble-mesh +.. only:: SOC_BLE_ISO_SUPPORTED + + **ESP-BLE-ISO API** + + Bluetooth LE Isochronous Channels (CIS/BIS) for LE Audio and time-synchronized streaming. + + .. toctree:: + :maxdepth: 1 + + esp-ble-iso + +.. only:: SOC_BLE_AUDIO_SUPPORTED + + **ESP-BLE-AUDIO API** + + Bluetooth LE Audio profiles and services (BAP, PACS, VCP, HAS, CSIP, etc.). + + .. toctree:: + :maxdepth: 1 + + esp-ble-audio + ---- Examples and Tutorials diff --git a/docs/zh_CN/COPYRIGHT.rst b/docs/zh_CN/COPYRIGHT.rst index 22878c506e..8e6d612221 100644 --- a/docs/zh_CN/COPYRIGHT.rst +++ b/docs/zh_CN/COPYRIGHT.rst @@ -55,6 +55,8 @@ * :component:`BLE Mesh ` 改编自 Zephyr 项目,版权归 2017-2018 英特尔公司所有,并根据 Apache License 2.0 进行许可。 +* :component:`BLE Audio ` 改编自 Zephyr 项目,版权归 2017-2018 英特尔公司所有,并根据 Apache License 2.0 进行许可。 + * `mynewt-nimble`_,版权归 2015-2018 Apache 软件基金会所有,根据 :component_file:`LICENSE 文件 ` 中描述的 Apache License 2.0 进行许可。 * `TLSF 分配器 `_,版权归 2006-2016 Matthew Conte 所有,并根据三条款 BSD 许可证进行许可。 diff --git a/docs/zh_CN/api-guides/ble/ble-audio.rst b/docs/zh_CN/api-guides/ble/ble-audio.rst new file mode 100644 index 0000000000..8a43c37671 --- /dev/null +++ b/docs/zh_CN/api-guides/ble/ble-audio.rst @@ -0,0 +1,498 @@ +LE Audio 架构指南 +================== + +:link_to_translation:`en:[English]` + +本文介绍低功耗蓝牙 LE Audio 的架构:各规范(Profile)、服务(Service)的定义、它们所包含的角色,以及彼此之间的依赖关系。在使用 :doc:`ESP-BLE-AUDIO API 参考 <../../api-reference/bluetooth/esp-ble-audio>` 进行开发之前,建议先阅读本文,以便选择适合应用场景的规范组合。 + + +概述 +---- + +低功耗蓝牙 LE Audio 是蓝牙核心规范 5.2 引入的一套规范,支持在低功耗蓝牙上传输高质量音频,具备以下核心特性: + +- **LE 等时通道(ISO)** — 控制器层的新传输机制,提供时间同步、低延迟的数据流,支持已连接(CIS)和无连接(BIS)两种模式。 +- **LC3 编解码器** — 低复杂度通信编解码器(Low Complexity Communication Codec),与 SBC 相比,在更低比特率下提供更好的音频质量。 +- **通用音频框架(GAF)** — 一套分层的规范和服务,标准化了音频流建立、音量控制、媒体控制、通话控制和设备协调等功能。 + +LE Audio 支持两种基本音频场景: + +- **单播音频(Unicast Audio)** — 通过连接等时流(CIS)在两个已连接设备之间进行双向或单向音频传输。典型应用:TWS 耳机、助听器、耳麦、电话通信。 +- **广播音频(Broadcast Audio,Auracast™)** — 通过广播等时流(BIS),由一个广播源向任意数量的接收端进行单向音频传输。典型应用:公共场所音频、无障碍辅助收听、群组电视收听。 + + +架构概览 +-------- + +LE Audio 架构分为三个层次: + +1. **LE 等时通道** — 传输层,提供 CIS(已连接)和 BIS(广播)流。 +2. **通用音频框架(GAF)** — 核心规范套件,分为四个功能层:流控制、内容控制、渲染/采集控制和过渡/协调控制。 +3. **特定用例规范** — 更高层的规范(HAP、TMAP、GMAP、PBP),针对特定使用场景选择并配置相应的 GAF 组件。 + +.. code-block:: none + + ┌──────────────────────────────────────────────────────────────────────┐ + │ 特定用例规范 │ + │ HAP TMAP GMAP PBP │ + ├──────────────────────────────────────────────────────────────────────┤ + │ 通用音频框架(GAF) │ + │ ┌───────────────────────────────────────────────────────────────┐ │ + │ │ 过渡与协调控制层 CAP + CAS │ │ + │ │ CSIP + CSIS │ │ + │ ├───────────────────────────────────────────────────────────────┤ │ + │ │ 渲染与采集控制层 VCP(VCS、VOCS、AICS) │ │ + │ │ MICP(MICS、AICS) │ │ + │ ├───────────────────────────────────────────────────────────────┤ │ + │ │ 内容控制层 MCP + MCS/GMCS │ │ + │ │ CCP + TBS/GTBS │ │ + │ ├───────────────────────────────────────────────────────────────┤ │ + │ │ 流控制层 BAP(PACS、ASCS、BASS) │ │ + │ └───────────────────────────────────────────────────────────────┘ │ + ├──────────────────────────────────────────────────────────────────────┤ + │ LE 等时通道(CIS / BIS) │ + └──────────────────────────────────────────────────────────────────────┘ + +GAF 各层仅依赖其下方的层。特定用例规范选择 GAF 层的子集,并在其之上添加角色特定的约束。以下各节将详细介绍每个组件。 + + +LE 等时通道 +----------- + +LE 等时通道是蓝牙核心规范中定义的控制器层特性,为 LE Audio 提供时间同步、低延迟的数据传输。 + +.. list-table:: + :header-rows: 1 + :widths: 20 15 65 + + * - 类型 + - 缩写 + - 说明 + * - 连接等时流 + - CIS + - 两个设备之间的双向等时链路,需要先建立 ACL 连接。多个 CIS 实例可组成一个连接等时组(CIG),用于同步播放(例如左右耳机)。 + * - 广播等时流 + - BIS + - 从广播方向任意数量的同步接收方进行的单向等时流,无需事先建立连接。多个 BIS 实例属于一个广播等时组(BIG)。 + +ESP-IDF 通过 :doc:`ESP-BLE-ISO API <../../api-reference/bluetooth/esp-ble-iso>` 提供对 CIS 和 BIS 的直接访问。使用 LE Audio 规范(BAP 及更高层)时,ISO 层由规范栈自动管理。 + + +通用音频框架(GAF) +------------------- + +通用音频框架(GAF)是 LE Audio 的核心,定义了四个功能层,下文从下至上依次介绍。 + + +流控制层 +^^^^^^^^ + +流控制层负责发现音频能力、建立音频流(编解码器配置和 QoS)以及管理 CIS 和 BIS 连接的生命周期。 + +**基本音频规范(BAP)** + +BAP 是所有 LE Audio 流传输的基础规范,定义了以下角色: + +- **单播客户端(Unicast Client)** — 发现远端单播服务器上的 ASE,发起编解码器配置、QoS 协商和流控制(使能、连接、开始、禁用、释放)。 +- **单播服务器(Unicast Server)** — 通过 ASCS 暴露音频端点(ASE),响应客户端发起的流控制流程。 +- **广播源(Broadcast Source)** — 创建 BIG,配置 BIS 流,发送音频数据。 +- **广播接收端(Broadcast Sink)** — 扫描并同步至广播源,接收 BIS 音频数据。 +- **广播助手(Broadcast Assistant)** — 代替低功耗的扫描委托设备扫描广播源,并将结果写入委托设备上的 BASS。 +- **扫描委托设备(Scan Delegator)** — 暴露 BASS,将 BIS 扫描委托给广播助手。 + +BAP 依赖三个 GATT 服务: + +.. list-table:: + :header-rows: 1 + :widths: 40 60 + + * - 服务 + - 说明 + * - 已发布音频能力服务(PACS) + - 暴露设备支持的编解码器、编解码器配置和可用音频上下文。存在于单播服务器和广播接收端。 + * - 音频流控制服务(ASCS) + - 暴露一个或多个音频流端点(ASE),每个 ASE 代表一个接收或发送数据路径。仅存在于单播服务器。 + * - 广播音频扫描服务(BASS) + - 由扫描委托设备暴露,用于记录接收状态;由广播助手写入广播源信息。仅存在于扫描委托设备。 + + +内容控制层 +^^^^^^^^^^ + +内容控制层提供对音频流所传输的媒体内容和通话活动的标准化控制。 + +**媒体控制规范(MCP)与媒体控制服务(MCS)** + +MCP 定义了 **媒体控制服务器**\ (通过 MCS 暴露媒体播放器)和 **媒体控制客户端**\ (发现并控制播放器)。MCS 暴露媒体状态(播放中/暂停/停止)、播放位置、曲目元数据以及控制点操作(播放、暂停、下一曲、跳转等)。 + +MCS 有两种形式: + +- **MCS** — 针对拥有多个并发媒体播放器的设备,每个播放器一个实例。 +- **通用 MCS(GMCS)** — 单一必选实例,提供对当前活跃播放器的访问,适用于无需按播放器区分的客户端。 + +当设备支持媒体对象传输时,MCP 可选依赖 **对象传输规范(OTP)** 和 **对象传输服务(OTS)**,用于传输媒体对象(曲目名称、图标、对象元数据等)。 + +**通话控制规范(CCP)与电话承载服务(TBS)** + +CCP 定义了 **通话控制服务器**\ (通过 TBS 暴露一个或多个电话承载)和 **通话控制客户端**\ (发现并控制通话)。TBS 暴露通话状态、通话 URI 方案、来电/去电控制、信号强度和运营商名称。 + +TBS 有两种形式: + +- **TBS** — 针对拥有多个电话承载(例如多张 SIM 卡或 VoIP 应用)的设备,每个承载一个实例。 +- **通用 TBS(GTBS)** — 单一必选实例,提供所有承载的统一视图。 + + +渲染与采集控制层 +^^^^^^^^^^^^^^^^ + +渲染与采集控制层提供对设备音频输出音量和音频输入增益的标准化控制,独立于所播放的内容。 + +**音量控制规范(VCP)** + +VCP 定义了 **音量渲染器(Volume Renderer)**\ (暴露音量状态,接受远程控制)和 **音量控制器(Volume Controller)**\ (发现并控制渲染器)。VCP 依赖以下 GATT 服务: + +.. list-table:: + :header-rows: 1 + :widths: 35 15 50 + + * - 服务 + - 是否必选 + - 说明 + * - 音量控制服务(VCS) + - 必选 + - 暴露音量设置(0–255)、静音状态以及绝对或相对音量控制点。 + * - 音量偏移控制服务(VOCS) + - 可选 + - 支持对每路输出进行音量偏移调整(例如左右声道输出分别设置偏移)。一个 VCS 可包含一个或多个 VOCS 实例。 + * - 音频输入控制服务(AICS) + - 可选 + - 支持对一路音频输入(例如麦克风)的增益和静音状态进行控制。一个 VCS 可包含一个或多个 AICS 实例。 + +**麦克风控制规范(MICP)** + +MICP 定义了 **麦克风设备(Microphone Device)**\ (暴露麦克风状态)和 **麦克风控制器(Microphone Controller)**\ (发现并控制静音/取消静音)。MICP 依赖以下 GATT 服务: + +.. list-table:: + :header-rows: 1 + :widths: 35 15 50 + + * - 服务 + - 是否必选 + - 说明 + * - 麦克风控制服务(MICS) + - 必选 + - 暴露麦克风静音状态和静音控制点,存在于麦克风设备端。 + * - 音频输入控制服务(AICS) + - 可选 + - 支持对特定输入的音频输入增益进行控制。一个 MICS 可包含一个或多个 AICS 实例。 + +.. note:: + + AICS 是共用服务:VCS(作为 VCP 的一部分)和 MICS(作为 MICP 的一部分)均可包含 AICS,每者各自拥有独立的实例和句柄。 + + +过渡与协调控制层 +^^^^^^^^^^^^^^^^ + +过渡与协调控制层位于 GAF 的最顶层,负责协调作为一个群组运行的多台设备(例如一对 TWS 耳机或一个房间内的多个扬声器)的音频操作。 + +**通用音频规范(CAP)** + +CAP 是最高层规范,定义了单个发起设备如何协调一台或多台目标设备执行音频操作(流建立、音量控制、麦克风控制)。它定义了三个角色: + +- **CAP 接受端(CAP Acceptor)** — 接受来自 CAP 发起端或指挥端的音频流和音量/麦克风控制的设备。CAP 接受端须支持 BAP 单播服务器或 BAP 广播接收端(或两者兼具),以及 VCP 音量渲染器。MICP 麦克风设备为可选。 +- **CAP 发起端(CAP Initiator)** — 发现 CAP 接受端,并使用 BAP、VCP 和 MICP 同时对一个或多个接受端发起单播或广播音频流程的设备。 +- **CAP 指挥端(CAP Commander)** — 向一个或多个 CAP 接受端下发协调的音量和麦克风控制指令,但不直接管理音频流的设备。 + +CAP 依赖 **通用音频服务(CAS)**,这是每个 CAP 接受端上的必选 GATT 服务,用于协调集成员通告,为 CAP 发起端/指挥端提供稳定的发现锚点。 + +CAP 还使用 **CSIP**\ (见下文)对协调集的成员进行识别和集体寻址。 + +**协调集标识规范(CSIP)** + +CSIP 定义了如何发现并识别一组设备("协调集")属于同一整体。典型示例是左右耳机对:每个耳机是一个 **CSIP 集成员(Set Member)**,手机或音源设备是一个 **CSIP 集协调器(Set Coordinator)**。 + +CSIP 依赖 **协调集标识服务(CSIS)**,该服务暴露: + +- **集身份解析密钥(SIRK)** — 用于集协调器匹配属于同一集的设备,即使在重新通告后也有效。 +- **集规模(Set Size)** — 集中的成员数量。 +- **成员排名(Member Rank)** — 该设备在集中的排名(用于有序操作)。 + + +特定用例规范 +------------ + +特定用例规范位于 GAF 之上,每个规范选择一部分 GAF 规范,定义针对特定角色的配置约束(例如编解码器参数、QoS 设置),并可添加自己的小型 GATT 服务用于角色通告。 + +**听力访问规范(HAP)** + +HAP 面向助听器设备,增加了 **听力预设(Hearing Aid Preset)** 的概念:用户可命名的音频配置(例如"室外"、"餐厅"),可在不同场景间切换。HAP 定义了: + +- **助听器(Hearing Aid)** — 实现音频接收、音量控制以及(双耳助听器对)协调集成员所需的全部 GAF 角色。 +- **助听器单播客户端(Hearing Aid Unicast Client)** — 发现助听器、控制预设,并管理单播音频流。 + +HAP 依赖 **听力访问服务(HAS)** 进行预设读写操作,同时依赖 GAF 中的 BAP、PACS、VCP、MICP 和 CSIP。 + +**电话和媒体音频规范(TMAP)** + +TMAP 为电话和媒体场景定义互操作配置,包含六个角色: + +.. list-table:: + :header-rows: 1 + :widths: 20 10 70 + + * - 角色 + - 缩写 + - 说明 + * - 通话网关 + - CG + - 使用 CCP/TBS 控制远端 CT 上的通话,通过 CIS 收发双向音频。 + * - 通话终端 + - CT + - 通过 TBS 暴露通话,通过 CIS 收发双向音频。 + * - 单播媒体发送方 + - UMS + - 通过 CIS 向一个或多个 UMR 发送单向媒体音频,充当 BAP 单播客户端和 MCP 服务器。 + * - 单播媒体接收方 + - UMR + - 通过 CIS 接收来自 UMS 的媒体音频,充当 BAP 单播服务器和 VCP 音量渲染器。 + * - 广播媒体发送方 + - BMS + - 通过 BIS 向任意数量的 BMR 发送媒体音频,充当 BAP 广播源。 + * - 广播媒体接收方 + - BMR + - 通过 BIS 接收来自 BMS 的媒体音频,充当 BAP 广播接收端。 + +TMAP 通过 **电话和媒体音频服务(TMAS)** 通告其角色,该服务是一个包含单一 TMAP 角色特征的小型 GATT 服务,允许远端设备在建立连接前发现本地设备支持的 TMAP 角色。TMAP 本身不定义新的音频传输机制,完全委托给 BAP(流建立)、VCP(音量)、MCP/MCS(UMS/UMR 的媒体控制)和 CCP/TBS(CG/CT 的通话控制)。 + +**游戏音频规范(GMAP)** + +GMAP 面向游戏音频产品,采用针对更低传输延迟和更少重传优化的参数。它定义了四个角色: + +.. list-table:: + :header-rows: 1 + :widths: 22 10 68 + + * - 角色 + - 缩写 + - 说明 + * - 单播游戏网关 + - UGG + - 向 UGT 发送游戏音频,可选接收语音音频,充当 BAP 单播客户端。 + * - 单播游戏终端 + - UGT + - 接收来自 UGG 的游戏音频,可选发送语音音频,充当 BAP 单播服务器。 + * - 广播游戏发送方 + - BGS + - 通过 BIS 发送游戏音频,充当 BAP 广播源。 + * - 广播游戏接收方 + - BGR + - 通过 BIS 接收游戏音频,充当 BAP 广播接收端。 + +GMAP 通过 **游戏音频服务(GMAS)** 通告角色,依赖 BAP 进行流建立,依赖 VCP 进行音量控制。 + +**公共广播规范(PBP)** + +PBP 为公共广播源的元数据格式提供标准化定义,使任何兼容的接收方无需配对即可发现并同步该广播流。它定义了: + +- **公共广播源(Public Broadcast Source)** — 通过标准化扩展通告数据(包含 Broadcast Audio Announcement 和 Public Broadcast Announcement)通告 Auracast™ 音频流,委托 BAP 广播源进行 BIS 建立。 +- **公共广播接收端(Public Broadcast Sink)** — 扫描 PBP 源,读取通告元数据以确定音频质量和内容,并同步至 BIG,委托 BAP 广播接收端实现。 + +PBP 完全依赖 BAP 提供底层广播传输,不定义新的 GATT 服务。 + + +规范与服务依赖关系参考 +----------------------- + +以下表格汇总了 ESP-IDF LE Audio 实现中规范与服务之间的依赖关系。 + + +规范对服务的依赖 +^^^^^^^^^^^^^^^^ + +.. list-table:: + :header-rows: 1 + :widths: 22 22 56 + + * - 规范 + - 依赖服务 + - 说明 + * - BAP + - PACS、ASCS、BASS + - PACS 存在于单播服务器和广播接收端;ASCS 仅存在于单播服务器;BASS 仅存在于扫描委托设备。 + * - VCP + - VCS(必选)、VOCS(可选)、AICS(可选) + - VOCS 和 AICS 是 VCS 的子包含服务,每类可有多个实例。 + * - MICP + - MICS(必选)、AICS(可选) + - AICS 是 MICS 的子包含服务。 + * - CAP + - CAS(必选) + - CAS 必须存在于每个 CAP 接受端。CAP 还调用 BAP、VCP、MICP 和 CSIP 的流程。 + * - CSIP + - CSIS(必选) + - CSIS 位于集成员设备上。 + * - MCP + - MCS / GMCS(必选)、OTS(可选) + - GMCS 是唯一必选的通用实例;按播放器的 MCS 实例为可选。OTS 在设备支持媒体对象时使用。 + * - CCP + - TBS / GTBS(必选) + - GTBS 是唯一必选的通用实例;按承载的 TBS 实例为可选。 + * - HAP + - HAS(必选) + - HAS 用于预设控制。HAP 还要求 GAF 中的 BAP、PACS、VCP、MICP 和 CSIP(双耳设备)。 + * - TMAP + - TMAS(必选) + - TMAS 仅包含 TMAP 角色特征。TMAP 将流和控制操作委托给 BAP、VCP、MCP 和 CCP。 + * - GMAP + - GMAS(必选) + - GMAS 仅包含 GMAP 角色特征。GMAP 将操作委托给 BAP 和 VCP。 + * - PBP + - 无(无专用服务) + - PBP 仅使用 BAP 广播源/接收端和标准化扩展通告元数据。 + + +规范对规范的依赖 +^^^^^^^^^^^^^^^^ + +.. list-table:: + :header-rows: 1 + :widths: 25 25 50 + + * - 规范 + - 依赖规范 + - 说明 + * - CAP 发起端 / 指挥端 + - BAP、VCP、MICP、CSIP + - 使用 BAP 建立流,使用 VCP 和 MICP 进行渲染/采集控制,使用 CSIP 寻址协调集成员。 + * - HAP + - BAP、VCP、MICP、CSIP、CAP + - 助听器设备上 CAP 接受端角色为强制要求;双耳助听器对需要 CSIP。 + * - TMAP CG / CT + - BAP(单播)、VCP、CCP + - CG 在部分实现中还充当 MCP 服务器(媒体代理)。 + * - TMAP UMS / UMR + - BAP(单播)、VCP、MCP + - — + * - TMAP BMS / BMR + - BAP(广播)、VCP + - — + * - GMAP UGG / UGT + - BAP(单播)、VCP + - — + * - GMAP BGS / BGR + - BAP(广播)、VCP + - — + * - PBP 源 / 接收端 + - BAP(广播) + - — + + +典型用例所需规范 +^^^^^^^^^^^^^^^^ + +下表将常见产品类型映射到所需的规范和角色。 + +.. list-table:: + :header-rows: 1 + :widths: 30 70 + + * - 产品类型 + - 所需规范 / 角色 + * - TWS 耳机(接收端) + - CAP 接受端、BAP 单播服务器、VCP 音量渲染器、CSIP 集成员、MICP 麦克风设备(如有麦克风) + * - 手机 / 音源设备 + - CAP 发起端、BAP 单播客户端、VCP 音量控制器、CSIP 集协调器 + * - 助听器 + - HAP 助听器、CAP 接受端、BAP 单播服务器、VCP 音量渲染器、CSIP 集成员(双耳对) + * - 电视 / 广播源 + - BAP 广播源、PBP 公共广播源(Auracast™) + * - 听力环路接收端 + - BAP 广播接收端、PBP 公共广播接收端 + * - 电话耳麦 + - TMAP CT + UMR(或网关侧的 CG + UMS)、VCP、CCP + * - 游戏耳机 + - GMAP UGT(接收端)、BAP 单播服务器、VCP 音量渲染器 + * - 媒体发送端(音响) + - TMAP UMS(或广播场景的 BMS)、BAP、MCP/MCS 服务器、VCP + + +ESP-IDF 实现 +-------------- + +ESP-IDF 为 LE Audio 提供两个 API 组件: + +- :doc:`ESP-BLE-ISO <../../api-reference/bluetooth/esp-ble-iso>` — 直接访问 LE 等时通道(CIS/BIS),适用于需要自行管理 ISO 数据路径的应用。 +- :doc:`ESP-BLE-AUDIO <../../api-reference/bluetooth/esp-ble-audio>` — 高层 LE Audio 规范和服务 API,覆盖完整 GAF 栈(BAP、CAP、VCP、MICP、CSIP、MCP、CCP、HAP、GMAP、TMAP、PBP)及编解码器支持(LC3)。 + +对于大多数应用,ESP-BLE-AUDIO 是正确的起点。ESP-BLE-ISO 适用于需要在规范层之下直接控制 ISO 的高级场景。 + +功能支持 +^^^^^^^^ + +下表列出了 ESP-IDF 中当前支持的 LE Audio 规范和服务。 + +.. list-table:: + :header-rows: 1 + :widths: 28 12 60 + + * - 规范 / 服务 + - 支持状态 + - 说明 + * - LE 等时通道(CIS / BIS) + - 支持 + - 通过 :doc:`ESP-BLE-ISO <../../api-reference/bluetooth/esp-ble-iso>` 直接访问 ISO。 + * - BAP + - 支持 + - 全部六个 BAP 角色:单播客户端、单播服务器、广播源、广播接收端、广播助手、扫描委托端。 + * - PACS + - 支持 + - 用于 BAP 单播服务器和广播接收端。 + * - ASCS + - 支持 + - 用于 BAP 单播服务器。 + * - BASS + - 支持 + - 用于 BAP 扫描委托端和广播助手。 + * - CAP + - 支持 + - 全部三个 CAP 角色:接受端、发起端、指挥端。 + * - CAS + - 支持 + - 每个 CAP 接受端上的必选服务。 + * - CSIP / CSIS + - 支持 + - 集成员和集协调器角色。 + * - VCP / VCS + - 支持 + - 音量渲染器和音量控制器角色。 + * - VOCS + - 支持 + - 每路输出的音量偏移控制;作为可选子服务包含在 VCS 中。 + * - AICS + - 支持 + - 音频输入控制;作为可选子服务包含在 VCS 和 MICS 中。 + * - MICP / MICS + - 支持 + - 麦克风设备和麦克风控制器角色。 + * - MCP / MCS + - 部分支持 + - 媒体控制服务器和媒体控制客户端角色已支持。基于 OTP/OTS 的媒体对象传输暂不支持。 + * - CCP / TBS + - 支持 + - 通话控制服务器和通话控制客户端角色,包括 GTBS 和每承载方 TBS。 + * - HAP / HAS + - 支持 + - 助听器和助听器单播客户端角色,包括通过 HAS 进行预设读写。 + * - TMAP / TMAS + - 支持 + - 全部六个 TMAP 角色:CG、CT、UMS、UMR、BMS、BMR。 + * - GMAP / GMAS + - 支持 + - 全部四个 GMAP 角色:UGG、UGT、BGS、BGR。 + * - PBP + - 支持 + - 公共广播源和公共广播接收端角色。 + * - OTP / OTS + - 不支持 + - 对象传输规范/服务(MCP/MCS 用于媒体对象传输)暂不支持。 diff --git a/docs/zh_CN/api-guides/ble/index.rst b/docs/zh_CN/api-guides/ble/index.rst index 79c7db0f7e..48d301e2ff 100644 --- a/docs/zh_CN/api-guides/ble/index.rst +++ b/docs/zh_CN/api-guides/ble/index.rst @@ -46,3 +46,4 @@ :SOC_BLE_MESH_SUPPORTED: ../esp-ble-mesh/ble-mesh-index :SOC_BLUFI_SUPPORTED: blufi + :SOC_BLE_AUDIO_SUPPORTED: ble-audio diff --git a/docs/zh_CN/api-guides/ble/overview.rst b/docs/zh_CN/api-guides/ble/overview.rst index 7df7468edc..5b1a66e963 100644 --- a/docs/zh_CN/api-guides/ble/overview.rst +++ b/docs/zh_CN/api-guides/ble/overview.rst @@ -58,48 +58,64 @@ ESP-IDF 中的低功耗蓝牙协议栈是一个分层架构,可在 {IDF_TARGET - ESP-Bluedroid - ESP-NimBLE - ESP-BLE-MESH + - ESP-BLE-ISO + - ESP-BLE-AUDIO - BluFi * - ESP32 - Y - Y - Y - Y + - \– + - \– - Y * - ESP32-S3 - Y - Y - Y - Y + - \– + - \– - Y * - ESP32-C2 - Y - Y - Y - \– + - \– + - \– - Y * - ESP32-C3 - Y - Y - Y - Y + - \– + - \– - Y * - ESP32-C5 - Y - Y - Y - Y + - \– + - \– - Y * - ESP32-C6 - Y - Y - Y - Y + - \– + - \– - Y * - ESP32-C61 - Y - Y - Y - Y + - \– + - \– - Y * - ESP32-H2 - Y @@ -107,6 +123,16 @@ ESP-IDF 中的低功耗蓝牙协议栈是一个分层架构,可在 {IDF_TARGET - Y - Y - \– + - \– + - \– + * - ESP32-H4 + - Y + - Y + - Y + - Y + - Y + - Y + - \– 以下各节简要介绍了每个层,并提供了相关文档和应用示例的快速链接。 diff --git a/docs/zh_CN/api-reference/bluetooth/esp-ble-audio.rst b/docs/zh_CN/api-reference/bluetooth/esp-ble-audio.rst new file mode 100644 index 0000000000..d063189ff5 --- /dev/null +++ b/docs/zh_CN/api-reference/bluetooth/esp-ble-audio.rst @@ -0,0 +1 @@ +.. include:: ../../../en/api-reference/bluetooth/esp-ble-audio.rst diff --git a/docs/zh_CN/api-reference/bluetooth/esp-ble-iso.rst b/docs/zh_CN/api-reference/bluetooth/esp-ble-iso.rst new file mode 100644 index 0000000000..1220a2edaf --- /dev/null +++ b/docs/zh_CN/api-reference/bluetooth/esp-ble-iso.rst @@ -0,0 +1 @@ +.. include:: ../../../en/api-reference/bluetooth/esp-ble-iso.rst diff --git a/docs/zh_CN/api-reference/bluetooth/index.rst b/docs/zh_CN/api-reference/bluetooth/index.rst index 0f68a7bb81..8c3f4a35cf 100644 --- a/docs/zh_CN/api-reference/bluetooth/index.rst +++ b/docs/zh_CN/api-reference/bluetooth/index.rst @@ -65,6 +65,28 @@ ESP-IDF 默认的主机协议栈,支持经典蓝牙和低功耗蓝牙。 esp-ble-mesh +.. only:: SOC_BLE_ISO_SUPPORTED + + **ESP-BLE-ISO API** + + 低功耗蓝牙等时通道(CIS/BIS),用于 LE Audio 及时间同步流传输。 + + .. toctree:: + :maxdepth: 1 + + esp-ble-iso + +.. only:: SOC_BLE_AUDIO_SUPPORTED + + **ESP-BLE-AUDIO API** + + 低功耗蓝牙 LE Audio 配置与服务(BAP、PACS、VCP、HAS、CSIP 等)。 + + .. toctree:: + :maxdepth: 1 + + esp-ble-audio + ---- 示例与教程 diff --git a/examples/bluetooth/.build-test-rules.yml b/examples/bluetooth/.build-test-rules.yml index e3ec6a675e..131fac3547 100644 --- a/examples/bluetooth/.build-test-rules.yml +++ b/examples/bluetooth/.build-test-rules.yml @@ -162,6 +162,24 @@ examples/bluetooth/blufi: - esp_console - esp_wifi +examples/bluetooth/esp_ble_audio: + <<: *bt_default_depends + enable: + - if: SOC_BLE_AUDIO_SUPPORTED == 1 and IDF_TARGET == "esp32H4" + temporary: true + reason: BLE Audio examples only supported on ESP32-H4 + depends_filepatterns: + - examples/bluetooth/esp_ble_audio/common_components/**/* + +examples/bluetooth/esp_ble_iso: + <<: *bt_default_depends + enable: + - if: SOC_BLE_ISO_SUPPORTED == 1 and IDF_TARGET == "esp32H4" + temporary: true + reason: BLE ISO examples only supported on ESP32-H4 + depends_filepatterns: + - examples/bluetooth/esp_ble_iso/common_components/**/* + examples/bluetooth/esp_ble_mesh: <<: *bt_default_depends disable: diff --git a/examples/bluetooth/esp_ble_audio/bap/broadcast_sink/CMakeLists.txt b/examples/bluetooth/esp_ble_audio/bap/broadcast_sink/CMakeLists.txt new file mode 100644 index 0000000000..0554ec2944 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/bap/broadcast_sink/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.22) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +idf_build_set_property(MINIMAL_BUILD ON) +project(bap_broadcast_sink) diff --git a/examples/bluetooth/esp_ble_audio/bap/broadcast_sink/README.md b/examples/bluetooth/esp_ble_audio/bap/broadcast_sink/README.md new file mode 100644 index 0000000000..22156e7fac --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/bap/broadcast_sink/README.md @@ -0,0 +1,72 @@ +| Supported Targets | ESP32-H4 | +| ----------------- | -------- | + +# BAP Broadcast Sink Example + +(See the README.md file in the upper level `examples` directory for more information about examples.) + +This example demonstrates the **Basic Audio Profile (BAP) Broadcast Sink** functionality. It scans for BAP Broadcast Sources (advertising with the Broadcast Audio service data), establishes periodic advertising synchronization with the first matching source, creates a BAP Broadcast Sink, and synchronizes to the BIG to receive broadcast audio streams. It listens until the source stops or sync is lost. The scan filters by the hardcoded source name (`BAP Broadcast Source`). Optionally, you can run in a mode where a Broadcast Assistant (e.g. a phone app) controls when to sync via the Scan Delegator. + +The implementation uses the NimBLE host stack with ISO and BAP support, ESP-BLE-ISO, and ESP-BLE-AUDIO APIs (PACS, BAP broadcast sink, scan delegator). It is intended for chips that support BLE 5.2 ISO and LE Audio (e.g. ESP32-H4). Sink capabilities are registered with LC3 (16 kHz and 24 kHz, 10 ms frame duration, 1 channel). For encrypted broadcasts, the broadcast code is hardcoded as `1234` in the source, or can be provided by a Broadcast Assistant. + +## Requirements + +* A board with Bluetooth LE 5.2, ISO, and LE Audio support (e.g. ESP32-H4) +* A BAP Broadcast Source (e.g. another device or sample running as broadcast source) that is advertising and sending broadcast audio + +## How to Use Example + +Before project configuration and build, set the correct chip target: + +```bash +idf.py set-target esp32h4 +``` + +### Configure the Project + +Open the project configuration menu: + +```bash +idf.py menuconfig +``` + +In the **Example: Broadcast Sink** menu: + +* **Whether to wait for a Broadcast Assistant**: If enabled, the device advertises connectable and waits for a Broadcast Assistant to connect and send PA sync, broadcast code, and BIS sync requests via the Scan Delegator; the sink then syncs according to those requests. + +### Build and Flash + +Run the following to build, flash and monitor: + +```bash +idf.py -p PORT flash monitor +``` + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the [Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF. + +## Example Flow + +1. **Initialization**: NVS, Bluetooth stack, and LE Audio common layer (`esp_ble_audio_common_init`). Register PACS with sink capabilities (LC3), register BAP scan delegator callbacks and broadcast sink callbacks, then start the audio stack. Set device name if needed. +2. **Scanning**: Start extended scanning. On scan report, look for Broadcast Audio service data (UUID + broadcast ID). Filter by the hardcoded target device name (`BAP Broadcast Source`). When a matching advertiser with periodic advertising is found and not already syncing, create periodic advertising synchronization. +3. **PA sync**: When periodic sync is established, create a BAP Broadcast Sink (`esp_ble_audio_bap_broadcast_sink_create`) for that sync handle and broadcast ID. +4. **BASE and syncable**: When the BASE is received, the sink gets subgroup count and BIS index bitfield. When BIGInfo indicates the sink is syncable, call `esp_ble_audio_bap_broadcast_sink_sync` with the chosen BIS bitfield and broadcast code (from menuconfig or from the scan delegator). Streams are bound to the registered stream array. +5. **Streams**: As each BIS stream starts, the stream started callback runs; when all requested streams have started, the sink is considered running. Incoming audio data is delivered in the stream receive callback; the example counts valid, error, and lost packets per stream and logs periodically. When streams stop or PA sync is lost, the sink is cleaned up. + +## Example Output + +``` +I (xxx) BAP_BSNK: Broadcast source PA synced, creating Broadcast Sink +I (xxx) BAP_BSNK: Received BASE with 1 subgroups from broadcast sink 0x... +I (xxx) BAP_BSNK: Broadcast sink (0x...) is syncable, BIG not encrypted +I (xxx) BAP_BSNK: Stream 0x... started (1/1) +I (xxx) BAP_BSNK: Received 1000(1000/0/0) ISO data packets (stream 0x...) +... +``` + +If PA sync is lost: + +``` +I (xxx) BAP_BSNK: PA sync lost, reason ... +``` diff --git a/examples/bluetooth/esp_ble_audio/bap/broadcast_sink/main/CMakeLists.txt b/examples/bluetooth/esp_ble_audio/bap/broadcast_sink/main/CMakeLists.txt new file mode 100644 index 0000000000..721967052c --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/bap/broadcast_sink/main/CMakeLists.txt @@ -0,0 +1,4 @@ +set(srcs "main.c") + +idf_component_register(SRCS "${srcs}" + REQUIRES bt nvs_flash) diff --git a/examples/bluetooth/esp_ble_audio/bap/broadcast_sink/main/Kconfig.projbuild b/examples/bluetooth/esp_ble_audio/bap/broadcast_sink/main/Kconfig.projbuild new file mode 100644 index 0000000000..2b4dbdac84 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/bap/broadcast_sink/main/Kconfig.projbuild @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2022 Nordic Semiconductor ASA +# SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 + +menu "Example: Broadcast Sink" + + config EXAMPLE_SCAN_OFFLOAD + bool "Whether to wait for a Broadcast Assistant" + select BT_NIMBLE_PERIODIC_ADV_SYNC_TRANSFER + help + If set to true, the example will start advertising connectable + for Broadcast Assistants. + +endmenu diff --git a/examples/bluetooth/esp_ble_audio/bap/broadcast_sink/main/idf_component.yml b/examples/bluetooth/esp_ble_audio/bap/broadcast_sink/main/idf_component.yml new file mode 100644 index 0000000000..bb02c0922a --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/bap/broadcast_sink/main/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + example_init: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_audio/common_components/example_init + example_utils: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_audio/common_components/example_utils diff --git a/examples/bluetooth/esp_ble_audio/bap/broadcast_sink/main/main.c b/examples/bluetooth/esp_ble_audio/bap/broadcast_sink/main/main.c new file mode 100644 index 0000000000..fe4189df43 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/bap/broadcast_sink/main/main.c @@ -0,0 +1,637 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include "esp_log.h" +#include "nvs_flash.h" +#include "esp_system.h" + +#include "host/ble_hs.h" +#include "services/gap/ble_svc_gap.h" + +#include "esp_ble_audio_lc3_defs.h" +#include "esp_ble_audio_bap_api.h" +#include "esp_ble_audio_pacs_api.h" + +#include "ble_audio_example_init.h" +#include "ble_audio_example_utils.h" + +#define TAG "BAP_BSNK" + +#define TARGET_DEVICE_NAME "BAP Broadcast Source" +#define TARGET_DEVICE_NAME_LEN (sizeof(TARGET_DEVICE_NAME) - 1) + +#define TARGET_BROADCAST_CODE "1234" + +#define SCAN_INTERVAL 160 /* 100ms */ +#define SCAN_WINDOW 160 /* 100ms */ + +#define PA_SYNC_SKIP 0 +#define PA_SYNC_TIMEOUT 1000 /* 1000 * 10ms = 10s */ +#define PA_SYNC_HANDLE_INIT UINT16_MAX + +#define CONN_HANDLE_INIT UINT16_MAX + +#define SINK_CONTEXT (ESP_BLE_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | \ + ESP_BLE_AUDIO_CONTEXT_TYPE_MEDIA) + +static struct broadcast_sink_stream { + esp_ble_audio_bap_stream_t stream; + example_audio_rx_metrics_t rx_metrics; +} streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT]; + +static esp_ble_audio_bap_stream_t *streams_p[ARRAY_SIZE(streams)]; + +static const esp_ble_audio_bap_scan_delegator_recv_state_t *req_recv_state; +static esp_ble_audio_bap_broadcast_sink_t *broadcast_sink; +static uint16_t sync_handle = PA_SYNC_HANDLE_INIT; +static bool pa_syncing; + +static uint16_t conn_handle = CONN_HANDLE_INIT; +static volatile bool stream_started; +static volatile bool base_received; +static uint32_t bis_index_bitfield; + +static const uint32_t bis_index_mask = BIT_MASK(ARRAY_SIZE(streams) + 1); +static uint8_t sink_broadcast_code[ESP_BLE_ISO_BROADCAST_CODE_SIZE]; +static uint32_t broadcaster_broadcast_id; +static uint32_t requested_bis_sync; + +static volatile uint8_t stream_count; +static volatile uint8_t stream_count_started; +static volatile uint8_t stream_count_stopped; + +static uint8_t codec_data[] = + ESP_BLE_AUDIO_CODEC_CAP_LC3_DATA( + ESP_BLE_AUDIO_CODEC_CAP_FREQ_16KHZ | \ + ESP_BLE_AUDIO_CODEC_CAP_FREQ_24KHZ, /* Sampling frequency 16kHz/24kHz */ + ESP_BLE_AUDIO_CODEC_CAP_DURATION_10, /* Frame duration 10ms */ + ESP_BLE_AUDIO_CODEC_CAP_CHAN_COUNT_SUPPORT(1), /* Supported channels 1 */ + 40, /* Minimum 40 octets per frame */ + 60, /* Maximum 60 octets per frame */ + 1); /* Maximum 1 codec frame per SDU */ + +static uint8_t codec_meta[] = + ESP_BLE_AUDIO_CODEC_CAP_LC3_META(SINK_CONTEXT); + +static const esp_ble_audio_codec_cap_t codec_cap = + ESP_BLE_AUDIO_CODEC_CAP_LC3(codec_data, codec_meta); + +static esp_ble_audio_pacs_cap_t cap = { + .codec_cap = &codec_cap, +}; + +static void ext_scan_start(void) +{ + struct ble_gap_disc_params params = {0}; + uint8_t own_addr_type; + int err; + + err = ble_hs_id_infer_auto(0, &own_addr_type); + if (err) { + ESP_LOGE(TAG, "Failed to determine own addr type, err %d", err); + return; + } + + params.passive = 1; + params.itvl = SCAN_INTERVAL; + params.window = SCAN_WINDOW; + + err = ble_gap_disc(own_addr_type, BLE_HS_FOREVER, ¶ms, + example_audio_gap_event_cb, NULL); + if (err) { + ESP_LOGE(TAG, "Failed to start scanning, err %d", err); + return; + } + + ESP_LOGI(TAG, "Extended scan started"); +} + +static int pa_sync_create(const bt_addr_le_t *addr, uint8_t adv_sid) +{ + struct ble_gap_periodic_sync_params params = {0}; + ble_addr_t sync_addr = {0}; + + sync_addr.type = addr->type; + memcpy(sync_addr.val, addr->a.val, sizeof(sync_addr.val)); + params.skip = PA_SYNC_SKIP; + params.sync_timeout = PA_SYNC_TIMEOUT; + + return ble_gap_periodic_adv_sync_create(&sync_addr, adv_sid, ¶ms, + example_audio_gap_event_cb, NULL); +} + +static int pa_sync_terminate(void) +{ + int err; + + err = ble_gap_periodic_adv_sync_terminate(sync_handle); + if (err) { + ESP_LOGE(TAG, "Failed to terminate PA sync, err %d", err); + return err; + } + + ESP_LOGI(TAG, "PA sync terminated"); + + return 0; +} + +static void recv_state_updated_cb(esp_ble_conn_t *conn, + const esp_ble_audio_bap_scan_delegator_recv_state_t *recv_state) +{ + ESP_LOGI(TAG, "Receive state updated, pa_sync 0x%02x encrypt 0x%02x", + recv_state->pa_sync_state, recv_state->encrypt_state); + + for (uint8_t i = 0; i < recv_state->num_subgroups; i++) { + ESP_LOGI(TAG, "subgroup %d bis_sync 0x%08lx", i, recv_state->subgroups[i].bis_sync); + } + + if (recv_state->pa_sync_state == ESP_BLE_AUDIO_BAP_PA_STATE_SYNCED) { + req_recv_state = recv_state; + } +} + +static int pa_sync_req_cb(esp_ble_conn_t *conn, + const esp_ble_audio_bap_scan_delegator_recv_state_t *recv_state, + bool past_available, uint16_t pa_interval) +{ + ESP_LOGI(TAG, "Received request to sync to PA (PAST %savailable): %u", + past_available ? "" : "not ", + recv_state->pa_sync_state); + + req_recv_state = recv_state; + + if (recv_state->pa_sync_state == ESP_BLE_AUDIO_BAP_PA_STATE_SYNCED || + recv_state->pa_sync_state == ESP_BLE_AUDIO_BAP_PA_STATE_INFO_REQ || + sync_handle != PA_SYNC_HANDLE_INIT) { + /* Already syncing */ + ESP_LOGW(TAG, "Rejecting PA sync request"); + return -EALREADY; + } + + if (past_available) { + ESP_LOGW(TAG, "Currently not support PAST"); + return -ENOTSUP; + } + + return 0; +} + +static int pa_sync_term_req_cb(esp_ble_conn_t *conn, + const esp_ble_audio_bap_scan_delegator_recv_state_t *recv_state) +{ + int err; + + ESP_LOGI(TAG, "Received request to terminate PA sync"); + + for (uint8_t i = 0; i < recv_state->num_subgroups; i++) { + ESP_LOGI(TAG, "subgroup %d bis_sync 0x%08lx", i, recv_state->subgroups[i].bis_sync); + } + + req_recv_state = recv_state; + + err = pa_sync_terminate(); + if (err) { + return -EIO; + } + + sync_handle = PA_SYNC_HANDLE_INIT; + + return 0; +} + +static void broadcast_code_cb(esp_ble_conn_t *conn, + const esp_ble_audio_bap_scan_delegator_recv_state_t *recv_state, + const uint8_t broadcast_code[ESP_BLE_ISO_BROADCAST_CODE_SIZE]) +{ + ESP_LOGI(TAG, "Broadcast code received for %p", recv_state); + + req_recv_state = recv_state; + + memcpy(sink_broadcast_code, broadcast_code, ESP_BLE_ISO_BROADCAST_CODE_SIZE); +} + +static int bis_sync_req_cb(esp_ble_conn_t *conn, + const esp_ble_audio_bap_scan_delegator_recv_state_t *recv_state, + const uint32_t bis_sync_req[CONFIG_BT_BAP_BASS_MAX_SUBGROUPS]) +{ + /* Bit field indicating from which subgroup(s) BIS sync is requested */ + uint32_t requested_subgroup_sync = 0; + esp_err_t err; + + requested_bis_sync = 0; + + assert(bis_sync_req); + + for (uint8_t subgroup = 0; subgroup < recv_state->num_subgroups && + subgroup < CONFIG_BT_BAP_BASS_MAX_SUBGROUPS; subgroup++) { + if (bis_sync_req[subgroup]) { + if (requested_bis_sync == 0) { + requested_bis_sync = bis_sync_req[subgroup]; + } else { + if (requested_bis_sync != ESP_BLE_AUDIO_BAP_BIS_SYNC_NO_PREF && + bis_sync_req[subgroup] != ESP_BLE_AUDIO_BAP_BIS_SYNC_NO_PREF) { + /* Spec a little bit unclear. Here we choose to say that BIS sync + * request from more than 1 subgroup is not possible unless sync + * value is 0 or ESP_BLE_AUDIO_BAP_BIS_SYNC_NO_PREF. + */ + ESP_LOGE(TAG, "Unsupported BIS sync request from more than 1 subgroup"); + return -EINVAL; + } + } + + requested_subgroup_sync |= BIT(subgroup); + } + } + + ESP_LOGI(TAG, "BIS sync req for %p: BIS indexes 0x%08x (subgroup indexes 0x%08x), " + "broadcast id: 0x%06x, (%s)", recv_state, requested_bis_sync, + requested_subgroup_sync, recv_state->broadcast_id, + stream_started ? "Stream started" : "Stream not started"); + + if (stream_started && requested_bis_sync == 0) { + /* The stream stopped callback will be called as part of this, and + * we do not need to wait for any events from the controller. Thus, + * when this returns, the `stream_started` is back to false. + */ + err = esp_ble_audio_bap_broadcast_sink_stop(broadcast_sink); + if (err) { + ESP_LOGE(TAG, "Failed to stop broadcast sink, err %d", err); + return -EIO; + } + + err = esp_ble_audio_bap_broadcast_sink_delete(broadcast_sink); + if (err) { + ESP_LOGE(TAG, "Failed to delete broadcast sink, err %d", err); + return -EIO; + } + + broadcast_sink = NULL; + } + + return 0; +} + +static esp_ble_audio_bap_scan_delegator_cb_t scan_delegator_cbs = { + .recv_state_updated = recv_state_updated_cb, + .pa_sync_req = pa_sync_req_cb, + .pa_sync_term_req = pa_sync_term_req_cb, + .broadcast_code = broadcast_code_cb, + .bis_sync_req = bis_sync_req_cb, +}; + +static void base_recv_cb(esp_ble_audio_bap_broadcast_sink_t *sink, + const esp_ble_audio_bap_base_t *base, + size_t base_size) +{ + uint32_t base_bis_index_bitfield = 0; + uint8_t base_subgroup_count; + esp_err_t err; + + if (base_received) { + return; + } + + err = esp_ble_audio_bap_base_get_subgroup_count(base, &base_subgroup_count); + if (err) { + ESP_LOGE(TAG, "Failed to get subgroup count"); + return; + } + + ESP_LOGI(TAG, "Received BASE with %d subgroups from broadcast sink %p", + base_subgroup_count, sink); + + err = esp_ble_audio_bap_base_get_bis_indexes(base, &base_bis_index_bitfield); + if (err) { + ESP_LOGE(TAG, "Failed to get BIS indexes, err %d", err); + return; + } + + bis_index_bitfield = (base_bis_index_bitfield & bis_index_mask); + + ESP_LOGI(TAG, "bis_index_bitfield = 0x%08lx", bis_index_bitfield); + + if (conn_handle == CONN_HANDLE_INIT) { + /* No broadcast assistant requesting anything */ + requested_bis_sync = ESP_BLE_AUDIO_BAP_BIS_SYNC_NO_PREF; + } + + base_received = true; +} + +static void syncable_cb(esp_ble_audio_bap_broadcast_sink_t *sink, + const esp_ble_iso_biginfo_t *biginfo) +{ + uint32_t sync_bitfield; + esp_err_t err; + + ESP_LOGI(TAG, "Broadcast sink (%p) is syncable, BIG %s", + sink, biginfo->encryption ? "encrypted" : "not encrypted"); + + sync_bitfield = (bis_index_bitfield & requested_bis_sync); + if (sync_bitfield == 0) { + ESP_LOGW(TAG, "No matching BIS indexes, skipping sync"); + return; + } + + stream_count = 0; + stream_count_started = 0; + stream_count_stopped = 0; + + for (size_t i = 0; i < ESP_BLE_ISO_MAX_GROUP_ISO_COUNT; i++) { + if (sync_bitfield & BIT(i)) { + stream_count++; + } + } + + ESP_LOGI(TAG, "Syncing to broadcast with bitfield:"); + ESP_LOGI(TAG, "0x%08x = 0x%08x (bis_index) & 0x%08x (req_bis_sync), stream_count %u", + sync_bitfield, bis_index_bitfield, requested_bis_sync, stream_count); + + if (biginfo->encryption) { + memset(sink_broadcast_code, 0, ESP_BLE_ISO_BROADCAST_CODE_SIZE); + memcpy(sink_broadcast_code, TARGET_BROADCAST_CODE, + MIN(ESP_BLE_ISO_BROADCAST_CODE_SIZE, strlen(TARGET_BROADCAST_CODE))); + } + + err = esp_ble_audio_bap_broadcast_sink_sync(broadcast_sink, sync_bitfield, + streams_p, sink_broadcast_code); + if (err) { + ESP_LOGE(TAG, "Failed to sync to broadcast source, err %d", err); + return; + } +} + +static esp_ble_audio_bap_broadcast_sink_cb_t broadcast_sink_cbs = { + .base_recv = base_recv_cb, + .syncable = syncable_cb, +}; + +static void stream_started_cb(esp_ble_audio_bap_stream_t *stream) +{ + struct broadcast_sink_stream *sink_stream = CONTAINER_OF(stream, + struct broadcast_sink_stream, + stream); + + ESP_LOGI(TAG, "Stream %p started (%u/%u)", stream, stream_count_started, stream_count); + + example_audio_rx_metrics_reset(&sink_stream->rx_metrics); + + if (++stream_count_started == stream_count) { + stream_started = true; + } +} + +static void stream_stopped_cb(esp_ble_audio_bap_stream_t *stream, uint8_t reason) +{ + esp_err_t err; + + ESP_LOGI(TAG, "Stream %p stopped with reason 0x%02x (%u/%u)", + stream, reason, stream_count_stopped, stream_count); + + if (++stream_count_stopped == stream_count) { + stream_started = false; + + err = esp_ble_audio_bap_broadcast_sink_delete(broadcast_sink); + if (err) { + ESP_LOGE(TAG, "Failed to delete broadcast sink, err %d", err); + return; + } + + broadcast_sink = NULL; + } +} + +static void stream_recv_cb(esp_ble_audio_bap_stream_t *stream, + const esp_ble_iso_recv_info_t *info, + const uint8_t *data, uint16_t len) +{ + struct broadcast_sink_stream *sink_stream = CONTAINER_OF(stream, + struct broadcast_sink_stream, + stream); + + sink_stream->rx_metrics.last_sdu_len = len; + example_audio_rx_metrics_on_recv(info, &sink_stream->rx_metrics, + TAG, "stream", stream); +} + +static esp_ble_audio_bap_stream_ops_t stream_ops = { + .started = stream_started_cb, + .stopped = stream_stopped_cb, + .recv = stream_recv_cb, +}; + +struct scan_recv_data { + bool target_matched; + bool broadcast_id_found; + uint32_t broadcast_id; +}; + +static bool data_cb(uint8_t type, const uint8_t *data, + uint8_t data_len, void *user_data) +{ + struct scan_recv_data *sr = user_data; + uint16_t uuid; + + switch (type) { + case EXAMPLE_AD_TYPE_NAME_SHORTENED: + case EXAMPLE_AD_TYPE_NAME_COMPLETE: + case EXAMPLE_AD_TYPE_BROADCAST_NAME: + sr->target_matched = (data_len == TARGET_DEVICE_NAME_LEN) && + !memcmp(data, TARGET_DEVICE_NAME, TARGET_DEVICE_NAME_LEN); + if (!sr->target_matched) { + return false; + } + return true; + case EXAMPLE_AD_TYPE_SERVICE_DATA16: + if (data_len < ESP_BLE_AUDIO_UUID_SIZE_16 + ESP_BLE_AUDIO_BROADCAST_ID_SIZE) { + return true; + } + uuid = sys_get_le16(data); + if (uuid != ESP_BLE_AUDIO_UUID_BROADCAST_AUDIO_VAL) { + return true; + } + sr->broadcast_id = sys_get_le24(data + ESP_BLE_AUDIO_UUID_SIZE_16); + sr->broadcast_id_found = true; + return true; + default: + return true; + } +} + +static void ext_scan_recv(esp_ble_audio_gap_app_event_t *event) +{ + struct scan_recv_data sr = {0}; + bt_addr_le_t addr; + int err; + + /* Periodic advertising interval. 0 if no periodic advertising. */ + if (event->ext_scan_recv.per_adv_itvl == 0) { + return; + } + + esp_ble_audio_data_parse(event->ext_scan_recv.data, + event->ext_scan_recv.data_len, + data_cb, &sr); + + if (!sr.target_matched || !sr.broadcast_id_found) { + return; + } + + if (pa_syncing == false && req_recv_state == NULL) { + broadcaster_broadcast_id = sr.broadcast_id; + + addr.type = event->ext_scan_recv.addr.type; + memcpy(addr.a.val, event->ext_scan_recv.addr.val, sizeof(addr.a.val)); + + err = pa_sync_create(&addr, event->ext_scan_recv.sid); + if (err) { + ESP_LOGE(TAG, "Failed to create PA sync, err %d", err); + return; + } + + pa_syncing = true; + } +} + +static void pa_sync(esp_ble_audio_gap_app_event_t *event) +{ + esp_err_t err; + + pa_syncing = false; + + if (event->pa_sync.status) { + ESP_LOGE(TAG, "PA sync failed, status %d", event->pa_sync.status); + return; + } + + sync_handle = event->pa_sync.sync_handle; + + ESP_LOGI(TAG, "Broadcast source PA synced, creating Broadcast Sink"); + + err = esp_ble_audio_bap_broadcast_sink_create(event->pa_sync.sync_handle, + broadcaster_broadcast_id, + &broadcast_sink); + if (err) { + ESP_LOGE(TAG, "Failed to create broadcast sink, err %d", err); + return; + } +} + +static void pa_sync_lost(esp_ble_audio_gap_app_event_t *event) +{ + ESP_LOGI(TAG, "PA sync lost: sync_handle 0x%04x reason 0x%02x", + event->pa_sync_lost.sync_handle, event->pa_sync_lost.reason); + + if (sync_handle == event->pa_sync_lost.sync_handle) { + sync_handle = PA_SYNC_HANDLE_INIT; + pa_syncing = false; + base_received = false; + stream_started = false; + stream_count = 0; + stream_count_started = 0; + stream_count_stopped = 0; + + if (broadcast_sink != NULL) { + esp_ble_audio_bap_broadcast_sink_delete(broadcast_sink); + broadcast_sink = NULL; + } + + ext_scan_start(); + } +} + +static void iso_gap_app_cb(esp_ble_audio_gap_app_event_t *event) +{ + switch (event->type) { + case ESP_BLE_AUDIO_GAP_EVENT_EXT_SCAN_RECV: + ext_scan_recv(event); + break; + case ESP_BLE_AUDIO_GAP_EVENT_PA_SYNC: + pa_sync(event); + break; + case ESP_BLE_AUDIO_GAP_EVENT_PA_SYNC_LOST: + pa_sync_lost(event); + break; + default: + break; + } +} + +void app_main(void) +{ + const esp_ble_audio_pacs_register_param_t pacs_param = { + .snk_pac = true, + .snk_loc = true, + }; + esp_ble_audio_init_info_t info = { + .gap_cb = iso_gap_app_cb, + }; + esp_err_t err; + + /* Initialize NVS — it is used to store PHY calibration data */ + err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK(err); + + err = bluetooth_init(); + if (err) { + ESP_LOGE(TAG, "Failed to initialize BLE, err %d", err); + return; + } + + err = esp_ble_audio_common_init(&info); + if (err) { + ESP_LOGE(TAG, "Failed to initialize audio, err %d", err); + return; + } + + err = esp_ble_audio_pacs_register(&pacs_param); + if (err) { + ESP_LOGE(TAG, "Failed to register pacs, err %d", err); + return; + } + + for (size_t i = 0; i < ARRAY_SIZE(streams); i++) { + streams[i].stream.ops = &stream_ops; + streams_p[i] = &streams[i].stream; + } + + err = esp_ble_audio_pacs_cap_register(ESP_BLE_AUDIO_DIR_SINK, &cap); + if (err) { + ESP_LOGE(TAG, "Failed to register pacs capabilities, err %d", err); + return; + } + + err = esp_ble_audio_bap_scan_delegator_register(&scan_delegator_cbs); + if (err) { + ESP_LOGE(TAG, "Failed to register scan delegator, err %d", err); + return; + } + + err = esp_ble_audio_bap_broadcast_sink_register_cb(&broadcast_sink_cbs); + if (err) { + ESP_LOGE(TAG, "Failed to register broadcast sink callbacks, err %d", err); + return; + } + + err = esp_ble_audio_common_start(NULL); + if (err) { + ESP_LOGE(TAG, "Failed to start audio, err %d", err); + return; + } + + ext_scan_start(); +} diff --git a/examples/bluetooth/esp_ble_audio/bap/broadcast_sink/sdkconfig.defaults b/examples/bluetooth/esp_ble_audio/bap/broadcast_sink/sdkconfig.defaults new file mode 100644 index 0000000000..b7ad3b2846 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/bap/broadcast_sink/sdkconfig.defaults @@ -0,0 +1,27 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration +# + +CONFIG_BT_ENABLED=y +CONFIG_BT_BLUEDROID_ENABLED=n +CONFIG_BT_NIMBLE_ENABLED=y +CONFIG_BT_NIMBLE_EXT_ADV=y +CONFIG_BT_NIMBLE_MAX_CCCDS=20 +CONFIG_BT_NIMBLE_ISO=y +CONFIG_BT_NIMBLE_LOG_LEVEL_WARNING=y + +CONFIG_BT_ISO_MAX_CHAN=2 + +CONFIG_BT_BAP_BROADCAST_SINK=y +CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT=2 +CONFIG_BT_BAP_SCAN_DELEGATOR=y +CONFIG_BT_PAC_SNK_NOTIFIABLE=y +CONFIG_BT_PAC_SNK_LOC_WRITEABLE=y +CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE=y +CONFIG_BT_PAC_SRC_NOTIFIABLE=y +CONFIG_BT_PAC_SRC_LOC_WRITEABLE=y +CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE=y +CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE=y +CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE=30 + +CONFIG_FREERTOS_HZ=1000 diff --git a/examples/bluetooth/esp_ble_audio/bap/broadcast_sink/sdkconfig.defaults.esp32h4 b/examples/bluetooth/esp_ble_audio/bap/broadcast_sink/sdkconfig.defaults.esp32h4 new file mode 100644 index 0000000000..5920ce3f85 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/bap/broadcast_sink/sdkconfig.defaults.esp32h4 @@ -0,0 +1,6 @@ +# Override some defaults so BT stack is enabled +# by default in this example + +CONFIG_IDF_TARGET="esp32h4" + +CONFIG_BT_LE_ISO_SUPPORT=y diff --git a/examples/bluetooth/esp_ble_audio/bap/broadcast_source/CMakeLists.txt b/examples/bluetooth/esp_ble_audio/bap/broadcast_source/CMakeLists.txt new file mode 100644 index 0000000000..41f25dcab8 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/bap/broadcast_source/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.22) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +idf_build_set_property(MINIMAL_BUILD ON) +project(bap_broadcast_source) diff --git a/examples/bluetooth/esp_ble_audio/bap/broadcast_source/README.md b/examples/bluetooth/esp_ble_audio/bap/broadcast_source/README.md new file mode 100644 index 0000000000..3d5e55cf31 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/bap/broadcast_source/README.md @@ -0,0 +1,61 @@ +| Supported Targets | ESP32-H4 | +| ----------------- | -------- | + +# BAP Broadcast Source Example + +(See the README.md file in the upper level `examples` directory for more information about examples.) + +This example demonstrates the **Basic Audio Profile (BAP) Broadcast Source** functionality. It starts extended advertising with the Broadcast Audio service data (UUID and Broadcast ID) and device name, periodic advertising with the Broadcast Audio Source Endpoint (BASE), then starts the BAP Broadcast Source so that BIGInfo and (mock) audio data are sent over the BIG. Sinks such as the [broadcast_sink](../broadcast_sink) example can discover this source, establish periodic sync, and synchronize to the BIG to receive the streams. + +The implementation uses the NimBLE host stack with ISO and BAP support, ESP-BLE-ISO, and ESP-BLE-AUDIO APIs (BAP broadcast source create/start, stream send, LC3 presets). It is intended for chips that support BLE 5.2 ISO and LE Audio (e.g. ESP32-H4). The source is configured with the LC3 16_2_1 broadcast preset, a hardcoded broadcast ID (`0x123456`), and a hardcoded broadcast code (`1234`) for encrypted broadcasts. These values can be changed by editing the source code constants. + +## Requirements + +* A board with Bluetooth LE 5.2, ISO, and LE Audio support (e.g. ESP32-H4) +* Optionally, a device running the [broadcast_sink](../broadcast_sink) example to receive and play the broadcast streams + +## How to Use Example + +Before project configuration and build, set the correct chip target: + +```bash +idf.py set-target esp32h4 +``` + +### Build and Flash + +Run the following to build, flash and monitor: + +```bash +idf.py -p PORT flash monitor +``` + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the [Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF. + +## Example Flow + +1. **Initialization**: NVS, Bluetooth stack, and LE Audio common layer (`esp_ble_audio_common_init`). No PACS or GAP callback needed for the source role. +2. **Broadcast source setup**: Register broadcast source callbacks (started/stopped). Configure subgroups and streams using the selected LC3 preset (codec config, QoS, channel allocation). Create the BAP Broadcast Source (`esp_ble_audio_bap_broadcast_source_create`) with optional encryption and sequential packing. Register stream callbacks (started, stopped, sent) for each stream. +3. **Extended and periodic advertising**: Set extended advertising data: Broadcast Audio UUID + Broadcast ID (static or random) + complete device name. Set periodic advertising data: Broadcast Audio UUID + encoded BASE from the broadcast source. Start periodic advertising then extended advertising. +4. **Start BIG**: Add the advertising set for BIG and start the BAP Broadcast Source (`esp_ble_audio_bap_broadcast_source_start`) with the same adv handle. BIGInfo is sent in the periodic advertising; BIS streams are created. +5. **Stream and send**: When each BIS stream starts, the stream started callback allocates an SDU buffer and starts a periodic TX scheduler based on `k_work_delayable`. The scheduler posts work items to the ISO task at the stream QoS interval to send mock audio data; sent and drift are reported in the stream sent callback. When a stream stops, resources are freed and the scheduler is stopped. Note that the scheduler timer resolution is in milliseconds, which may not match the exact SDU interval for all configurations. + +## Example Output + +``` +I (xxx) BAP_BSRC: Creating broadcast source with 1 subgroups & 2 streams per subgroup +I (xxx) BAP_BSRC: Extended adv instance 0 started +I (xxx) BAP_BSRC: Broadcast source 0x... started +I (xxx) BAP_BSRC: Stream 0x... started +I (xxx) BAP_BSRC: Transmitted 1000 ISO data packets (stream 0x...) +... +``` + +If the broadcast source stops (e.g. stream stopped): + +``` +I (xxx) BAP_BSRC: Stream 0x... stopped, reason 0x... +I (xxx) BAP_BSRC: Broadcast source 0x... stopped, reason 0x... +``` diff --git a/examples/bluetooth/esp_ble_audio/bap/broadcast_source/main/CMakeLists.txt b/examples/bluetooth/esp_ble_audio/bap/broadcast_source/main/CMakeLists.txt new file mode 100644 index 0000000000..721967052c --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/bap/broadcast_source/main/CMakeLists.txt @@ -0,0 +1,4 @@ +set(srcs "main.c") + +idf_component_register(SRCS "${srcs}" + REQUIRES bt nvs_flash) diff --git a/examples/bluetooth/esp_ble_audio/bap/broadcast_source/main/idf_component.yml b/examples/bluetooth/esp_ble_audio/bap/broadcast_source/main/idf_component.yml new file mode 100644 index 0000000000..bb02c0922a --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/bap/broadcast_source/main/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + example_init: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_audio/common_components/example_init + example_utils: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_audio/common_components/example_utils diff --git a/examples/bluetooth/esp_ble_audio/bap/broadcast_source/main/main.c b/examples/bluetooth/esp_ble_audio/bap/broadcast_source/main/main.c new file mode 100644 index 0000000000..3b31ad45bc --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/bap/broadcast_source/main/main.c @@ -0,0 +1,539 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "esp_log.h" +#include "nvs_flash.h" +#include "esp_system.h" +#include "esp_random.h" +#include "esp_timer.h" + +#include "host/ble_hs.h" +#include "services/gap/ble_svc_gap.h" + +#include "esp_ble_audio_lc3_defs.h" +#include "esp_ble_audio_bap_api.h" +#include "esp_ble_audio_pacs_api.h" +#include "esp_ble_audio_bap_lc3_preset_defs.h" + +#include "ble_audio_example_init.h" +#include "ble_audio_example_utils.h" + +#define TAG "BAP_BSRC" + +ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_16_2_1_DEFINE(preset_active, + ESP_BLE_AUDIO_LOCATION_FRONT_LEFT | + ESP_BLE_AUDIO_LOCATION_FRONT_RIGHT, + ESP_BLE_AUDIO_CONTEXT_TYPE_UNSPECIFIED); + +#define LOCAL_DEVICE_NAME "BAP Broadcast Source" +#define LOCAL_DEVICE_NAME_LEN (sizeof(LOCAL_DEVICE_NAME) - 1) + +#define LOCAL_BROADCAST_CODE "1234" /* Maximum length is 16 */ +#define LOCAL_BROADCAST_ID 0x123456 + +#define ADV_HANDLE 0x00 +#define ADV_SID 0 +#define ADV_TX_POWER 127 +#define ADV_ADDRESS BLE_OWN_ADDR_PUBLIC +#define ADV_PRIMARY_PHY BLE_HCI_LE_PHY_1M +#define ADV_SECONDARY_PHY BLE_HCI_LE_PHY_2M +#define ADV_INTERVAL BLE_GAP_ADV_ITVL_MS(200) + +#define PER_ADV_INTERVAL BLE_GAP_ADV_ITVL_MS(100) + +#define STREAM_COUNT CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT +#define SUBGROUP_COUNT CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT + +static struct broadcast_source_stream { + esp_ble_audio_bap_stream_t stream; + uint16_t seq_num; + uint8_t *data; + example_audio_tx_scheduler_t scheduler; +} streams[STREAM_COUNT]; + +static esp_ble_audio_bap_broadcast_source_t *broadcast_source; + +static void broadcast_source_tx(struct broadcast_source_stream *source_stream); + +static void stream_started_cb(esp_ble_audio_bap_stream_t *stream) +{ + struct broadcast_source_stream *source_stream = CONTAINER_OF(stream, + struct broadcast_source_stream, + stream); + esp_err_t err; + + ESP_LOGI(TAG, "Stream %p started", stream); + + if (source_stream->stream.qos == NULL || source_stream->stream.qos->sdu == 0) { + ESP_LOGE(TAG, "Invalid stream qos"); + return; + } + + if (source_stream->data == NULL) { + source_stream->data = calloc(1, source_stream->stream.qos->sdu); + if (source_stream->data == NULL) { + ESP_LOGE(TAG, "Failed to alloc tx buffer, sdu %u", source_stream->stream.qos->sdu); + return; + } + } + + source_stream->seq_num = 0; + example_audio_tx_scheduler_reset(&source_stream->scheduler); + + /* Note: esp timer is not accurate enough */ + err = example_audio_tx_scheduler_start(&source_stream->scheduler, preset_active.qos.interval); + if (err) { + ESP_LOGE(TAG, "Failed to start tx scheduler, err %d", err); + return; + } + + broadcast_source_tx(source_stream); +} + +static void stream_stopped_cb(esp_ble_audio_bap_stream_t *stream, uint8_t reason) +{ + struct broadcast_source_stream *source_stream = CONTAINER_OF(stream, + struct broadcast_source_stream, + stream); + esp_err_t err; + + ESP_LOGI(TAG, "Stream %p stopped, reason 0x%02x", stream, reason); + + err = example_audio_tx_scheduler_stop(&source_stream->scheduler); + if (err) { + ESP_LOGE(TAG, "Failed to stop tx scheduler, err %d", err); + } +} + +static void stream_disconnected_cb(esp_ble_audio_bap_stream_t *stream, uint8_t reason) +{ + struct broadcast_source_stream *source_stream = CONTAINER_OF(stream, + struct broadcast_source_stream, + stream); + esp_err_t err; + + ESP_LOGI(TAG, "Stream %p disconnected, reason 0x%02x", stream, reason); + + err = example_audio_tx_scheduler_stop(&source_stream->scheduler); + if (err) { + ESP_LOGE(TAG, "Failed to stop tx scheduler, err %d", err); + } +} + +static void stream_sent_cb(esp_ble_audio_bap_stream_t *stream, void *user_data) +{ + struct broadcast_source_stream *source_stream = CONTAINER_OF(stream, + struct broadcast_source_stream, + stream); + + example_audio_tx_scheduler_on_sent(&source_stream->scheduler, user_data, TAG, "stream", stream); +} + +static esp_ble_audio_bap_stream_ops_t stream_ops = { + .started = stream_started_cb, + .stopped = stream_stopped_cb, + .sent = stream_sent_cb, + .disconnected = stream_disconnected_cb, +}; + +static bool stream_is_streaming(const esp_ble_audio_bap_stream_t *stream) +{ + esp_ble_audio_bap_ep_info_t ep_info = {0}; + + if (stream->ep == NULL) { + return false; + } + + if (esp_ble_audio_bap_ep_get_info(stream->ep, &ep_info)) { + return false; + } + + return (ep_info.state == ESP_BLE_AUDIO_BAP_EP_STATE_STREAMING); +} + +static void broadcast_source_tx(struct broadcast_source_stream *source_stream) +{ + esp_err_t err; + + if (!stream_is_streaming(&source_stream->stream)) { + return; + } + + if (source_stream->stream.qos == NULL || source_stream->stream.qos->sdu == 0) { + ESP_LOGE(TAG, "Invalid stream qos"); + return; + } + + if (source_stream->data == NULL) { + ESP_LOGE(TAG, "Tx buffer unavailable, sdu %u", source_stream->stream.qos->sdu); + return; + } + + memset(source_stream->data, (uint8_t)source_stream->seq_num, source_stream->stream.qos->sdu); + + err = esp_ble_audio_bap_stream_send(&source_stream->stream, + source_stream->data, + source_stream->stream.qos->sdu, + source_stream->seq_num); + if (err) { + ESP_LOGD(TAG, "Failed to broadcast data on stream %p, err %d", + &source_stream->stream, err); + return; + } + + source_stream->seq_num++; +} + +static void tx_scheduler_cb(void *arg) +{ + struct broadcast_source_stream *source_stream = arg; + + if (source_stream == NULL) { + return; + } + + broadcast_source_tx(source_stream); +} + +static void source_started_cb(esp_ble_audio_bap_broadcast_source_t *source) +{ + ESP_LOGI(TAG, "Broadcast source %p started", source); +} + +static void source_stopped_cb(esp_ble_audio_bap_broadcast_source_t *source, uint8_t reason) +{ + ESP_LOGI(TAG, "Broadcast source %p stopped, reason 0x%02x", source, reason); + + for (size_t i = 0; i < ARRAY_SIZE(streams); i++) { + if (streams[i].data != NULL) { + free(streams[i].data); + streams[i].data = NULL; + } + } +} + +static esp_err_t broadcast_source_setup(void) +{ + esp_ble_audio_bap_broadcast_source_subgroup_param_t subgroup_param[SUBGROUP_COUNT]; + esp_ble_audio_bap_broadcast_source_stream_param_t stream_params[STREAM_COUNT]; + esp_ble_audio_bap_broadcast_source_param_t create_param = {0}; + size_t streams_per_subgroup; + uint8_t left[] = { + ESP_BLE_AUDIO_CODEC_DATA(ESP_BLE_AUDIO_CODEC_CFG_CHAN_ALLOC, + EXAMPLE_BYTES_LIST_LE32(ESP_BLE_AUDIO_LOCATION_FRONT_LEFT)) + }; + uint8_t right[] = { + ESP_BLE_AUDIO_CODEC_DATA(ESP_BLE_AUDIO_CODEC_CFG_CHAN_ALLOC, + EXAMPLE_BYTES_LIST_LE32(ESP_BLE_AUDIO_LOCATION_FRONT_RIGHT)) + }; + static esp_ble_audio_bap_broadcast_source_cb_t broadcast_source_cb = { + .started = source_started_cb, + .stopped = source_stopped_cb, + }; + esp_err_t err; + + err = esp_ble_audio_bap_broadcast_source_register_cb(&broadcast_source_cb); + if (err) { + ESP_LOGE(TAG, "Failed to register broadcast source callbacks, err %d", err); + return err; + } + + streams_per_subgroup = ARRAY_SIZE(stream_params) / ARRAY_SIZE(subgroup_param); + + for (size_t i = 0; i < ARRAY_SIZE(subgroup_param); i++) { + subgroup_param[i].params_count = streams_per_subgroup; + subgroup_param[i].params = stream_params + i * streams_per_subgroup; + subgroup_param[i].codec_cfg = &preset_active.codec_cfg; + } + + for (size_t i = 0; i < ARRAY_SIZE(stream_params); i++) { + stream_params[i].stream = &streams[i].stream; + stream_params[i].data = (i == 0 ? left : right); + stream_params[i].data_len = (i == 0 ? sizeof(left) : sizeof(right)); + + esp_ble_audio_bap_stream_cb_register(stream_params[i].stream, &stream_ops); + } + + create_param.params_count = ARRAY_SIZE(subgroup_param); + create_param.params = subgroup_param; + create_param.qos = &preset_active.qos; + create_param.encryption = (strlen(LOCAL_BROADCAST_CODE) > 0); + create_param.packing = ESP_BLE_ISO_PACKING_SEQUENTIAL; + + if (create_param.encryption) { + memcpy(create_param.broadcast_code, LOCAL_BROADCAST_CODE, strlen(LOCAL_BROADCAST_CODE)); + } + + ESP_LOGI(TAG, "Creating broadcast source with %u subgroups & %u streams per subgroup", + ARRAY_SIZE(subgroup_param), streams_per_subgroup); + + err = esp_ble_audio_bap_broadcast_source_create(&create_param, &broadcast_source); + if (err) { + ESP_LOGE(TAG, "Failed to create broadcast source, err %d", err); + return err; + } + + return 0; +} + +static uint8_t *ext_adv_data_get(uint8_t *data_len) +{ + uint32_t broadcast_id; + uint8_t *data; + + broadcast_id = LOCAL_BROADCAST_ID; + + /* - Broadcast Audio Announcement Service UUID (2 octets) and + * Broadcast ID (3 octets) + * - Complete Device Name + */ + *data_len = 7 + 2 + LOCAL_DEVICE_NAME_LEN; + + data = calloc(1, *data_len); + if (data == NULL) { + return NULL; + } + + data[0] = 0x06; /* 1 + 2 + 3 */ + data[1] = EXAMPLE_AD_TYPE_SERVICE_DATA16; + data[2] = (ESP_BLE_AUDIO_UUID_BROADCAST_AUDIO_VAL & 0xFF); + data[3] = ((ESP_BLE_AUDIO_UUID_BROADCAST_AUDIO_VAL >> 8) & 0xFF); + data[4] = (broadcast_id & 0xFF); + data[5] = ((broadcast_id >> 8) & 0xFF); + data[6] = ((broadcast_id >> 16) & 0xFF); + + data[7] = LOCAL_DEVICE_NAME_LEN + 1; + data[8] = EXAMPLE_AD_TYPE_NAME_COMPLETE; + memcpy(data + 9, LOCAL_DEVICE_NAME, LOCAL_DEVICE_NAME_LEN); + + return data; +} + +static uint8_t *per_adv_data_get(uint8_t *data_len) +{ + NET_BUF_SIMPLE_DEFINE(base_buf, 128); + uint8_t *data; + esp_err_t err; + + /* Broadcast Audio Announcement Service UUID (2 octets) and + * Broadcast Audio Source Endpoint (BASE) + */ + + err = esp_ble_audio_bap_broadcast_source_get_base(broadcast_source, &base_buf); + if (err) { + ESP_LOGE(TAG, "Failed to get encoded BASE, err %d", err); + return NULL; + } + + *data_len = 2 + base_buf.len; + + data = calloc(1, *data_len); + if (data == NULL) { + return NULL; + } + + /* base_buf.len has included the UUID length (2 octets) */ + data[0] = 1 + base_buf.len; + data[1] = EXAMPLE_AD_TYPE_SERVICE_DATA16; + memcpy(data + 2, base_buf.data, base_buf.len); + + return data; +} + +static int ext_adv_start(void) +{ + struct ble_gap_periodic_adv_params per_params = {0}; + struct ble_gap_ext_adv_params ext_params = {0}; + struct os_mbuf *data = NULL; + uint8_t *ext_data = NULL; + uint8_t *per_data = NULL; + uint8_t data_len = 0; + int err; + + ext_params.connectable = 0; + ext_params.scannable = 0; + ext_params.legacy_pdu = 0; + ext_params.own_addr_type = ADV_ADDRESS; + ext_params.primary_phy = ADV_PRIMARY_PHY; + ext_params.secondary_phy = ADV_SECONDARY_PHY; + ext_params.tx_power = ADV_TX_POWER; + ext_params.sid = ADV_SID; + ext_params.itvl_min = ADV_INTERVAL; + ext_params.itvl_max = ADV_INTERVAL; + + err = ble_gap_ext_adv_configure(ADV_HANDLE, &ext_params, NULL, + example_audio_gap_event_cb, NULL); + if (err) { + ESP_LOGE(TAG, "Failed to configure ext adv params, err %d", err); + goto end; + } + + ext_data = ext_adv_data_get(&data_len); + if (ext_data == NULL) { + err = -ENOMEM; + goto end; + } + + data = os_msys_get_pkthdr(data_len, 0); + if (data == NULL) { + ESP_LOGE(TAG, "Failed to get ext adv mbuf"); + err = -ENOMEM; + goto end; + } + + err = os_mbuf_append(data, ext_data, data_len); + if (err) { + ESP_LOGE(TAG, "Failed to append ext adv data, err %d", err); + os_mbuf_free_chain(data); + goto end; + } + + err = ble_gap_ext_adv_set_data(ADV_HANDLE, data); + if (err) { + ESP_LOGE(TAG, "Failed to set ext adv data, err %d", err); + goto end; + } + + per_params.include_tx_power = 0; + per_params.itvl_min = PER_ADV_INTERVAL; + per_params.itvl_max = PER_ADV_INTERVAL; + + err = ble_gap_periodic_adv_configure(ADV_HANDLE, &per_params); + if (err) { + ESP_LOGE(TAG, "Failed to configure per adv params, err %d", err); + goto end; + } + + per_data = per_adv_data_get(&data_len); + if (per_data == NULL) { + err = -ENOMEM; + goto end; + } + + data = os_msys_get_pkthdr(data_len, 0); + if (data == NULL) { + ESP_LOGE(TAG, "Failed to get per adv mbuf"); + err = -ENOMEM; + goto end; + } + + err = os_mbuf_append(data, per_data, data_len); + if (err) { + ESP_LOGE(TAG, "Failed to append per adv data, err %d", err); + os_mbuf_free_chain(data); + goto end; + } + + err = ble_gap_periodic_adv_set_data(ADV_HANDLE, data); + if (err) { + ESP_LOGE(TAG, "Failed to set per adv data, err %d", err); + goto end; + } + + err = ble_gap_periodic_adv_start(ADV_HANDLE); + if (err) { + ESP_LOGE(TAG, "Failed to start per advertising, err %d", err); + goto end; + } + + err = ble_gap_ext_adv_start(ADV_HANDLE, 0, 0); + if (err) { + ESP_LOGE(TAG, "Failed to start ext advertising, err %d", err); + goto end; + } + + ESP_LOGI(TAG, "Extended adv instance %u started", ADV_HANDLE); + +end: + if (ext_data) { + free(ext_data); + } + if (per_data) { + free(per_data); + } + return err; +} + +static void broadcast_start(void) +{ + esp_ble_audio_bap_broadcast_adv_info_t info = { + .adv_handle = ADV_HANDLE, + }; + int err; + + err = esp_ble_audio_bap_broadcast_adv_add(&info); + if (err) { + ESP_LOGE(TAG, "Failed to add adv for broadcast source, err %d", err); + return; + } + + err = esp_ble_audio_bap_broadcast_source_start(broadcast_source, ADV_HANDLE); + if (err) { + ESP_LOGE(TAG, "Failed to start broadcast source, err %d", err); + return; + } +} + +void app_main(void) +{ + esp_err_t err; + + /* Initialize NVS — it is used to store PHY calibration data */ + err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK(err); + + err = bluetooth_init(); + if (err) { + ESP_LOGE(TAG, "Failed to initialize BLE, err %d", err); + return; + } + + err = esp_ble_audio_common_init(NULL); + if (err) { + ESP_LOGE(TAG, "Failed to initialize audio, err %d", err); + return; + } + + err = broadcast_source_setup(); + if (err) { + return; + } + + err = esp_ble_audio_common_start(NULL); + if (err) { + ESP_LOGE(TAG, "Failed to start audio, err %d", err); + return; + } + + for (size_t i = 0; i < ARRAY_SIZE(streams); i++) { + err = example_audio_tx_scheduler_init(&streams[i].scheduler, + tx_scheduler_cb, + &streams[i]); + if (err) { + ESP_LOGE(TAG, "Failed to initialize tx scheduler[%u], err %d", i, err); + return; + } + } + + err = ext_adv_start(); + if (err) { + return; + } + + broadcast_start(); +} diff --git a/examples/bluetooth/esp_ble_audio/bap/broadcast_source/sdkconfig.defaults b/examples/bluetooth/esp_ble_audio/bap/broadcast_source/sdkconfig.defaults new file mode 100644 index 0000000000..9ba26040ec --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/bap/broadcast_source/sdkconfig.defaults @@ -0,0 +1,16 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration +# + +CONFIG_BT_ENABLED=y +CONFIG_BT_BLUEDROID_ENABLED=n +CONFIG_BT_NIMBLE_ENABLED=y +CONFIG_BT_NIMBLE_EXT_ADV=y +CONFIG_BT_NIMBLE_ISO=y +CONFIG_BT_NIMBLE_LOG_LEVEL_WARNING=y + +CONFIG_BT_ISO_MAX_CHAN=2 + +CONFIG_BT_BAP_BROADCAST_SOURCE=y + +CONFIG_FREERTOS_HZ=1000 diff --git a/examples/bluetooth/esp_ble_audio/bap/broadcast_source/sdkconfig.defaults.esp32h4 b/examples/bluetooth/esp_ble_audio/bap/broadcast_source/sdkconfig.defaults.esp32h4 new file mode 100644 index 0000000000..5920ce3f85 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/bap/broadcast_source/sdkconfig.defaults.esp32h4 @@ -0,0 +1,6 @@ +# Override some defaults so BT stack is enabled +# by default in this example + +CONFIG_IDF_TARGET="esp32h4" + +CONFIG_BT_LE_ISO_SUPPORT=y diff --git a/examples/bluetooth/esp_ble_audio/bap/unicast_client/CMakeLists.txt b/examples/bluetooth/esp_ble_audio/bap/unicast_client/CMakeLists.txt new file mode 100644 index 0000000000..d856d71ae3 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/bap/unicast_client/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.22) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +idf_build_set_property(MINIMAL_BUILD ON) +project(bap_unicast_client) diff --git a/examples/bluetooth/esp_ble_audio/bap/unicast_client/README.md b/examples/bluetooth/esp_ble_audio/bap/unicast_client/README.md new file mode 100644 index 0000000000..4ed16316a8 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/bap/unicast_client/README.md @@ -0,0 +1,64 @@ +| Supported Targets | ESP32-H4 | +| ----------------- | -------- | + +# BAP Unicast Client Example + +(See the README.md file in the upper level `examples` directory for more information about examples.) + +This example demonstrates the **Basic Audio Profile (BAP) Unicast Client** functionality. It scans for a BAP Unicast Server (advertising with the ASCS service data), connects to it, performs GATT service discovery and MTU exchange, then discovers sink and source ASEs, configures streams with an LC3 unicast preset, sets QoS, enables and connects the streams, and establishes unicast audio. For source (TX) streams the client starts the stream and can send audio data; sink streams are started by the server. Run it together with the [unicast_server](../unicast_server) example on another device as the peer. + +The implementation uses the NimBLE host stack with ISO and BAP support, ESP-BLE-ISO, and ESP-BLE-AUDIO APIs (BAP unicast client discover, config, QoS, enable, connect, start; stream send). It is intended for chips that support BLE 5.2 ISO and LE Audio (e.g. ESP32-H4). The client uses the LC3 16_2_1 unicast preset and initiates pairing after the ACL connection. + +## Requirements + +* A board with Bluetooth LE 5.2, ISO, and LE Audio support (e.g. ESP32-H4) +* Another device running the [unicast_server](../unicast_server) example, which advertises with ASCS and acts as BAP Unicast Server + +## How to Use Example + +Before project configuration and build, set the correct chip target: + +```bash +idf.py set-target esp32h4 +``` + +### Build and Flash + +Run the following to build, flash and monitor: + +```bash +idf.py -p PORT flash monitor +``` + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the [Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF. + +## Example Flow + +1. **Initialization**: NVS, Bluetooth stack, and LE Audio common layer (`esp_ble_audio_common_init`) with GAP and GATT callbacks. Register stream ops for sink and source streams, register BAP unicast client callbacks, then start the audio stack. +2. **Scanning**: Start passive extended scanning. On scan report, parse advertising for connectable packets containing the ASCS (Audio Stream Control Service) service data; when found, initiate an ACL connection to that device. +3. **Connection and security**: On ACL connection, initiate pairing. After MTU exchange and GATT service discovery complete, start BAP discovery (sinks first, then sources). +4. **Discovery**: Discover sink ASEs then source ASEs on the server. For each discovered endpoint, the endpoint callback records the EP; when source discovery completes, start configuring streams. +5. **Configure, QoS, enable**: For each sink and source stream, configure with the LC3 16_2_1 codec config. When all streams are configured, create a unicast group, set QoS for the group, then enable each stream with metadata. When all streams are enabled, connect each stream. +6. **Connect and start**: When each stream is connected, connect the next; when all are connected, start the source (TX) streams. Sink streams are started by the server. When a TX stream is started, it is registered for sending; the example can then send audio on that stream. + +## Example Output + +``` +I (xxx) BAP_UCL: Unicast server found, type ... +I (xxx) BAP_UCL: connection established, status 0 +I (xxx) BAP_UCL: Sink #0: ep 0x... +I (xxx) BAP_UCL: Source #0: ep 0x... +I (xxx) BAP_UCL: Discover sinks complete +I (xxx) BAP_UCL: Discover sources complete +I (xxx) BAP_UCL: Sink stream[0] configured +I (xxx) BAP_UCL: Source stream[0] configured +I (xxx) BAP_UCL: Stream 0x... QoS set +I (xxx) BAP_UCL: Stream 0x... enabled +I (xxx) BAP_UCL: Stream 0x... connected +I (xxx) BAP_UCL: Stream 0x... started +... +``` + +If connection or discovery fails, relevant error messages are logged. diff --git a/examples/bluetooth/esp_ble_audio/bap/unicast_client/main/CMakeLists.txt b/examples/bluetooth/esp_ble_audio/bap/unicast_client/main/CMakeLists.txt new file mode 100644 index 0000000000..3b4506801d --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/bap/unicast_client/main/CMakeLists.txt @@ -0,0 +1,5 @@ +set(srcs "stream_tx.c" + "main.c") + +idf_component_register(SRCS "${srcs}" + REQUIRES bt nvs_flash) diff --git a/examples/bluetooth/esp_ble_audio/bap/unicast_client/main/idf_component.yml b/examples/bluetooth/esp_ble_audio/bap/unicast_client/main/idf_component.yml new file mode 100644 index 0000000000..bb02c0922a --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/bap/unicast_client/main/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + example_init: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_audio/common_components/example_init + example_utils: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_audio/common_components/example_utils diff --git a/examples/bluetooth/esp_ble_audio/bap/unicast_client/main/main.c b/examples/bluetooth/esp_ble_audio/bap/unicast_client/main/main.c new file mode 100644 index 0000000000..eb314e35d9 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/bap/unicast_client/main/main.c @@ -0,0 +1,1383 @@ +/* + * SPDX-FileCopyrightText: 2021-2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "nvs_flash.h" +#include "esp_system.h" + +#include "host/ble_gap.h" +#include "services/gap/ble_svc_gap.h" + +#include "stream_tx.h" + +#define TARGET_DEVICE_NAME "BAP Unicast Server" +#define TARGET_DEVICE_NAME_LEN (sizeof(TARGET_DEVICE_NAME) - 1) + +#define SCAN_INTERVAL 160 /* 100ms */ +#define SCAN_WINDOW 160 /* 100ms */ + +#define INIT_SCAN_INTERVAL 16 /* 10ms */ +#define INIT_SCAN_WINDOW 16 /* 10ms */ +#define CONN_INTERVAL 64 /* 64 * 1.25 = 80ms */ +#define CONN_LATENCY 0 +#define CONN_TIMEOUT 500 /* 500 * 10ms = 5s */ +#define CONN_MAX_CE_LEN 0xFFFF +#define CONN_MIN_CE_LEN 0xFFFF +#define CONN_DURATION 10000 /* 10s */ +#define CONN_HANDLE_INIT 0xFFFF + +#define ASCS_RSP_NONE (0b00) +#define ASCS_RSP_SUCCESS (0b01) +#define ASCS_RSP_FAILURE (0b10) +#define ASCS_RSP_CONNECT (0b11) + +static uint16_t default_conn_handle = CONN_HANDLE_INIT; +static bool disc_completed; +static bool disc_cancelled; +static bool mtu_exchanged; + +ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_16_2_1_DEFINE(unicast_preset, + ESP_BLE_AUDIO_LOCATION_FRONT_LEFT, + ESP_BLE_AUDIO_CONTEXT_TYPE_UNSPECIFIED); + +static struct audio_sink { + uint8_t configured : 2; + uint8_t qos_set : 2; + uint8_t enabled : 2; + uint8_t connected : 2; + esp_ble_audio_bap_stream_t stream; + esp_ble_audio_bap_ep_t *ep; +} sinks[CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT]; + +static struct audio_source { + uint8_t configured : 2; + uint8_t qos_set : 2; + uint8_t enabled : 2; + uint8_t connected : 2; + esp_ble_audio_bap_stream_t stream; + esp_ble_audio_bap_ep_t *ep; +} sources[CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT]; + +static esp_ble_audio_bap_stream_t *streams[CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT + + CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT]; + +static esp_ble_audio_bap_unicast_group_t *unicast_group; + +static size_t configured_sink_stream_count; +static size_t configured_source_stream_count; +#define configured_stream_count (configured_sink_stream_count + configured_source_stream_count) + +static struct stream_pair_state { + esp_ble_audio_bap_stream_t *sink_stream; + esp_ble_audio_bap_stream_t *source_stream; +} stream_pairs[MAX(ARRAY_SIZE(sinks), ARRAY_SIZE(sources))]; +static size_t stream_pair_count; + +static int ext_scan_start(void); + +static void reset_stream_pair_state(void) +{ + stream_pair_count = 0; + + for (size_t i = 0; i < ARRAY_SIZE(stream_pairs); i++) { + stream_pairs[i].sink_stream = NULL; + stream_pairs[i].source_stream = NULL; + } +} + +static void update_stream_pair_state(void) +{ + stream_pair_count = MAX(configured_sink_stream_count, configured_source_stream_count); + + for (size_t i = 0; i < ARRAY_SIZE(stream_pairs); i++) { + stream_pairs[i].sink_stream = NULL; + stream_pairs[i].source_stream = NULL; + } + + for (size_t i = 0; i < stream_pair_count; i++) { + if (i < configured_sink_stream_count) { + stream_pairs[i].sink_stream = streams[i]; + } else { + stream_pairs[i].sink_stream = NULL; + } + + if (i < configured_source_stream_count) { + stream_pairs[i].source_stream = streams[i + configured_sink_stream_count]; + } else { + stream_pairs[i].source_stream = NULL; + } + } +} + +static int get_stream_pair_index(const esp_ble_audio_bap_stream_t *stream) +{ + if (stream == NULL) { + return -1; + } + + for (size_t i = 0; i < stream_pair_count; i++) { + if (stream_pairs[i].sink_stream == stream || + stream_pairs[i].source_stream == stream) { + return (int)i; + } + } + + return -1; +} + +static esp_ble_audio_bap_stream_t *get_paired_stream(const esp_ble_audio_bap_stream_t *stream) +{ + int pair_index = get_stream_pair_index(stream); + + if (pair_index < 0) { + return NULL; + } + + if (stream_pairs[pair_index].sink_stream == stream) { + return stream_pairs[pair_index].source_stream; + } + + if (stream_pairs[pair_index].source_stream == stream) { + return stream_pairs[pair_index].sink_stream; + } + + return NULL; +} + +static bool streams_are_same_pair(const esp_ble_audio_bap_stream_t *stream_a, + const esp_ble_audio_bap_stream_t *stream_b) +{ + int pair_a = get_stream_pair_index(stream_a); + int pair_b = get_stream_pair_index(stream_b); + + return pair_a >= 0 && pair_b >= 0 && pair_a == pair_b; +} + +static void reset_stream_state(void) +{ + configured_sink_stream_count = 0; + configured_source_stream_count = 0; + + reset_stream_pair_state(); + + for (size_t i = 0; i < ARRAY_SIZE(sinks); i++) { + sinks[i].configured = ASCS_RSP_NONE; + sinks[i].qos_set = ASCS_RSP_NONE; + sinks[i].enabled = ASCS_RSP_NONE; + sinks[i].connected = ASCS_RSP_NONE; + sinks[i].ep = NULL; + } + + for (size_t i = 0; i < ARRAY_SIZE(sources); i++) { + sources[i].configured = ASCS_RSP_NONE; + sources[i].qos_set = ASCS_RSP_NONE; + sources[i].enabled = ASCS_RSP_NONE; + sources[i].connected = ASCS_RSP_NONE; + sources[i].ep = NULL; + } + + for (size_t i = 0; i < ARRAY_SIZE(streams); i++) { + streams[i] = NULL; + } +} + +static bool stream_is_sink(const esp_ble_audio_bap_stream_t *stream) +{ + for (size_t i = 0; i < ARRAY_SIZE(sinks); i++) { + if (&sinks[i].stream == stream) { + return true; + } + } + + return false; +} + +static int discover_sinks(void) +{ + int err; + + err = esp_ble_audio_bap_unicast_client_discover(default_conn_handle, ESP_BLE_AUDIO_DIR_SINK); + if (err) { + ESP_LOGE(TAG, "Failed to discover sinks, err %d", err); + return err; + } + + ESP_LOGI(TAG, "Discovering sinks"); + + return 0; +} + +static int discover_sources(void) +{ + int err; + + err = esp_ble_audio_bap_unicast_client_discover(default_conn_handle, ESP_BLE_AUDIO_DIR_SOURCE); + if (err) { + ESP_LOGE(TAG, "Failed to discover sources, err %d", err); + return err; + } + + return 0; +} + +static bool configure_stream(void) +{ + int err; + + for (size_t i = 0; i < ARRAY_SIZE(sinks); i++) { + if (sinks[i].ep == NULL || sinks[i].configured != ASCS_RSP_NONE) { + continue; + } + + err = esp_ble_audio_bap_stream_config(default_conn_handle, + &sinks[i].stream, sinks[i].ep, + &unicast_preset.codec_cfg); + if (err) { + ESP_LOGE(TAG, "Failed to configure sink stream[%u], err %d", i, err); + + sinks[i].configured = ASCS_RSP_FAILURE; + /* Try to configure the next sink stream */ + continue; + } + + return false; + } + + for (size_t i = 0; i < ARRAY_SIZE(sources); i++) { + if (sources[i].ep == NULL || sources[i].configured != ASCS_RSP_NONE) { + continue; + } + + err = esp_ble_audio_bap_stream_config(default_conn_handle, + &sources[i].stream, sources[i].ep, + &unicast_preset.codec_cfg); + if (err) { + ESP_LOGE(TAG, "Failed to configure source stream[%u], err %d", i, err); + + sources[i].configured = ASCS_RSP_FAILURE; + /* Try to configure the next source stream */ + continue; + } + + return false; + } + + return true; +} + +static void stream_configured(esp_ble_audio_bap_stream_t *stream, bool success) +{ + for (size_t i = 0; i < ARRAY_SIZE(sinks); i++) { + if (sinks[i].configured == ASCS_RSP_NONE && + &sinks[i].stream == stream) { + if (success) { + ESP_LOGI(TAG, "Sink stream[%u] configure succeeded", i); + sinks[i].configured = ASCS_RSP_SUCCESS; + configured_sink_stream_count++; + } else { + ESP_LOGE(TAG, "Sink stream[%u] configure failed", i); + sinks[i].configured = ASCS_RSP_FAILURE; + } + return; + } + } + + for (size_t i = 0; i < ARRAY_SIZE(sources); i++) { + if (sources[i].configured == ASCS_RSP_NONE && + &sources[i].stream == stream) { + if (success) { + ESP_LOGI(TAG, "Source stream[%u] configure succeeded", i); + sources[i].configured = ASCS_RSP_SUCCESS; + configured_source_stream_count++; + } else { + ESP_LOGE(TAG, "Source stream[%u] configure failed", i); + sources[i].configured = ASCS_RSP_FAILURE; + } + return; + } + } + + ESP_LOGW(TAG, "No matching stream found for configured stream %p", stream); +} + +static int create_group(void) +{ + const size_t params_count = MAX(configured_sink_stream_count, configured_source_stream_count); + esp_ble_audio_bap_unicast_group_stream_param_t stream_params[configured_stream_count]; + esp_ble_audio_bap_unicast_group_stream_pair_param_t pair_params[params_count]; + esp_ble_audio_bap_unicast_group_param_t group_param = {0}; + int err; + + for (size_t i = 0; i < configured_stream_count; i++) { + stream_params[i].stream = streams[i]; + stream_params[i].qos = &unicast_preset.qos; + } + + update_stream_pair_state(); + + for (size_t i = 0; i < params_count; i++) { + if (i < configured_sink_stream_count) { + pair_params[i].tx_param = &stream_params[i]; + } else { + pair_params[i].tx_param = NULL; + } + + if (i < configured_source_stream_count) { + pair_params[i].rx_param = &stream_params[i + configured_sink_stream_count]; + } else { + pair_params[i].rx_param = NULL; + } + + ESP_LOGI(TAG, "Stream pair[%u]: sink %p source %p", i, + stream_pairs[i].sink_stream, stream_pairs[i].source_stream); + } + + group_param.params = pair_params; + group_param.params_count = params_count; + group_param.packing = ESP_BLE_ISO_PACKING_SEQUENTIAL; + + err = esp_ble_audio_bap_unicast_group_create(&group_param, &unicast_group); + if (err) { + ESP_LOGE(TAG, "Failed to create unicast group, err %d", err); + return err; + } + + ESP_LOGI(TAG, "Created unicast group"); + + return 0; +} + +static int set_stream_qos(void) +{ + int err; + + err = esp_ble_audio_bap_stream_qos(default_conn_handle, unicast_group); + if (err) { + ESP_LOGE(TAG, "Failed to setup QoS, err %d", err); + return err; + } + + return 0; +} + +static void stream_qos_set(esp_ble_audio_bap_stream_t *stream, bool success) +{ + for (size_t i = 0; i < ARRAY_SIZE(sinks); i++) { + if (sinks[i].configured == ASCS_RSP_SUCCESS && + sinks[i].qos_set == ASCS_RSP_NONE && + &sinks[i].stream == stream) { + if (success) { + ESP_LOGI(TAG, "Sink stream[%u] QoS set", i); + sinks[i].qos_set = ASCS_RSP_SUCCESS; + } else { + ESP_LOGE(TAG, "Sink stream[%u] QoS set failed", i); + sinks[i].qos_set = ASCS_RSP_FAILURE; + } + return; + } + } + + for (size_t i = 0; i < ARRAY_SIZE(sources); i++) { + if (sources[i].configured == ASCS_RSP_SUCCESS && + sources[i].qos_set == ASCS_RSP_NONE && + &sources[i].stream == stream) { + if (success) { + ESP_LOGI(TAG, "Source stream[%u] QoS set", i); + sources[i].qos_set = ASCS_RSP_SUCCESS; + } else { + ESP_LOGE(TAG, "Source stream[%u] QoS set failed", i); + sources[i].qos_set = ASCS_RSP_FAILURE; + } + return; + } + } + + ESP_LOGW(TAG, "No matching stream found for QoS set stream %p", stream); +} + +static bool is_all_stream_qos_set(void) +{ + for (size_t i = 0; i < ARRAY_SIZE(sinks); i++) { + if (sinks[i].configured == ASCS_RSP_SUCCESS && + sinks[i].qos_set == ASCS_RSP_NONE) { + return false; + } + } + + for (size_t i = 0; i < ARRAY_SIZE(sources); i++) { + if (sources[i].configured == ASCS_RSP_SUCCESS && + sources[i].qos_set == ASCS_RSP_NONE) { + return false; + } + } + + return true; +} + +static bool enable_stream(void) +{ + int err; + + for (size_t i = 0; i < ARRAY_SIZE(sinks); i++) { + if (sinks[i].configured == ASCS_RSP_SUCCESS && + sinks[i].qos_set == ASCS_RSP_SUCCESS && + sinks[i].enabled == ASCS_RSP_NONE) { + err = esp_ble_audio_bap_stream_enable(&sinks[i].stream, + unicast_preset.codec_cfg.meta, + unicast_preset.codec_cfg.meta_len); + if (err) { + ESP_LOGE(TAG, "Failed to enable sink stream[%u], err %d", i, err); + + sinks[i].enabled = ASCS_RSP_FAILURE; + /* Try to enable the next sink stream */ + continue; + } + + return false; + } + } + + for (size_t i = 0; i < ARRAY_SIZE(sources); i++) { + if (sources[i].configured == ASCS_RSP_SUCCESS && + sources[i].qos_set == ASCS_RSP_SUCCESS && + sources[i].enabled == ASCS_RSP_NONE) { + err = esp_ble_audio_bap_stream_enable(&sources[i].stream, + unicast_preset.codec_cfg.meta, + unicast_preset.codec_cfg.meta_len); + if (err) { + ESP_LOGE(TAG, "Failed to enable source stream[%u], err %d", i, err); + + sources[i].enabled = ASCS_RSP_FAILURE; + /* Try to enable the next source stream */ + continue; + } + + return false; + } + } + + return true; +} + +static void stream_enabled(esp_ble_audio_bap_stream_t *stream, bool success) +{ + for (size_t i = 0; i < ARRAY_SIZE(sinks); i++) { + if (sinks[i].configured == ASCS_RSP_SUCCESS && + sinks[i].qos_set == ASCS_RSP_SUCCESS && + sinks[i].enabled == ASCS_RSP_NONE && + &sinks[i].stream == stream) { + if (success) { + ESP_LOGI(TAG, "Sink stream[%u] enabled", i); + sinks[i].enabled = ASCS_RSP_SUCCESS; + } else { + ESP_LOGE(TAG, "Sink stream[%u] enabled failed", i); + sinks[i].enabled = ASCS_RSP_FAILURE; + } + return; + } + } + + for (size_t i = 0; i < ARRAY_SIZE(sources); i++) { + if (sources[i].configured == ASCS_RSP_SUCCESS && + sources[i].qos_set == ASCS_RSP_SUCCESS && + sources[i].enabled == ASCS_RSP_NONE && + &sources[i].stream == stream) { + if (success) { + ESP_LOGI(TAG, "Source stream[%u] enabled", i); + sources[i].enabled = ASCS_RSP_SUCCESS; + } else { + ESP_LOGE(TAG, "Source stream[%u] enabled failed", i); + sources[i].enabled = ASCS_RSP_FAILURE; + } + return; + } + } + + ESP_LOGW(TAG, "No matching stream found for enabled stream %p", stream); +} + +static int connect_stream(void) +{ + int err; + + for (size_t i = 0; i < stream_pair_count; i++) { + esp_ble_audio_bap_stream_t *sink_stream = stream_pairs[i].sink_stream; + esp_ble_audio_bap_stream_t *source_stream = stream_pairs[i].source_stream; + esp_ble_audio_bap_stream_t *stream = NULL; + bool sink_ready = false; + bool source_ready = false; + int sink_index = -1; + int source_index = -1; + + for (size_t j = 0; j < ARRAY_SIZE(sinks); j++) { + if (&sinks[j].stream == sink_stream) { + sink_index = (int)j; + sink_ready = (sinks[j].configured == ASCS_RSP_SUCCESS && + sinks[j].qos_set == ASCS_RSP_SUCCESS && + sinks[j].enabled == ASCS_RSP_SUCCESS && + sinks[j].connected == ASCS_RSP_NONE); + break; + } + } + + for (size_t j = 0; j < ARRAY_SIZE(sources); j++) { + if (&sources[j].stream == source_stream) { + source_index = (int)j; + source_ready = (sources[j].configured == ASCS_RSP_SUCCESS && + sources[j].qos_set == ASCS_RSP_SUCCESS && + sources[j].enabled == ASCS_RSP_SUCCESS && + sources[j].connected == ASCS_RSP_NONE); + break; + } + } + + if (!sink_ready && !source_ready) { + continue; + } + + stream = sink_ready ? sink_stream : source_stream; + + err = esp_ble_audio_bap_stream_connect(stream); + if (err) { + ESP_LOGE(TAG, "Failed to connect stream pair[%u], err %d", i, err); + + if (sink_ready) { + sinks[sink_index].connected = ASCS_RSP_FAILURE; + } + if (source_ready) { + sources[source_index].connected = ASCS_RSP_FAILURE; + } + continue; + } + + if (sink_ready) { + sinks[sink_index].connected = ASCS_RSP_CONNECT; + } + if (source_ready) { + sources[source_index].connected = ASCS_RSP_CONNECT; + } + + ESP_LOGI(TAG, "Connecting stream pair[%u], sink %p source %p", i, sink_stream, source_stream); + return false; + } + + return true; +} + +static bool stream_is_connecting(const esp_ble_audio_bap_stream_t *stream) +{ + if (stream == NULL) { + return false; + } + + for (size_t i = 0; i < ARRAY_SIZE(sinks); i++) { + if (&sinks[i].stream == stream) { + return sinks[i].connected == ASCS_RSP_CONNECT; + } + } + + for (size_t i = 0; i < ARRAY_SIZE(sources); i++) { + if (&sources[i].stream == stream) { + return sources[i].connected == ASCS_RSP_CONNECT; + } + } + + return false; +} + +static void stream_connected(esp_ble_audio_bap_stream_t *stream, bool success) +{ + uint8_t state = success ? ASCS_RSP_SUCCESS : ASCS_RSP_FAILURE; + + for (size_t i = 0; i < ARRAY_SIZE(sinks); i++) { + if (sinks[i].configured == ASCS_RSP_SUCCESS && + sinks[i].qos_set == ASCS_RSP_SUCCESS && + sinks[i].enabled == ASCS_RSP_SUCCESS && + sinks[i].connected == ASCS_RSP_CONNECT && + &sinks[i].stream == stream) { + if (success) { + ESP_LOGI(TAG, "Sink stream[%u] connect succeeded", i); + sinks[i].connected = state; + } else { + ESP_LOGE(TAG, "Sink stream[%u] connect failed", i); + sinks[i].connected = state; + } + return; + } + } + + for (size_t i = 0; i < ARRAY_SIZE(sources); i++) { + if (sources[i].configured == ASCS_RSP_SUCCESS && + sources[i].qos_set == ASCS_RSP_SUCCESS && + sources[i].enabled == ASCS_RSP_SUCCESS && + sources[i].connected == ASCS_RSP_CONNECT && + &sources[i].stream == stream) { + if (success) { + ESP_LOGI(TAG, "Source stream[%u] connect succeeded", i); + sources[i].connected = state; + } else { + ESP_LOGE(TAG, "Source stream[%u] connect failed", i); + sources[i].connected = state; + } + return; + } + } + + ESP_LOGW(TAG, "No matching stream found for connected stream %p", stream); +} + +static int start_stream(void) +{ + esp_err_t err; + + /* Note: sink streams are started by the unicast server */ + + ESP_LOGI(TAG, "Starting source streams"); + + for (size_t i = 0; i < ARRAY_SIZE(sources); i++) { + if (sources[i].configured == ASCS_RSP_SUCCESS && + sources[i].qos_set == ASCS_RSP_SUCCESS && + sources[i].enabled == ASCS_RSP_SUCCESS && + sources[i].connected == ASCS_RSP_SUCCESS) { + err = esp_ble_audio_bap_stream_start(&sources[i].stream); + if (err) { + ESP_LOGE(TAG, "Failed to start stream[%u], err %d", i, err); + } + } + } + + return 0; +} + +static void stream_configured_cb(esp_ble_audio_bap_stream_t *stream, + const esp_ble_audio_bap_qos_cfg_pref_t *pref) +{ + ESP_LOGI(TAG, "Stream %p configured", stream); + + example_print_qos_pref(pref); +} + +static void stream_qos_set_cb(esp_ble_audio_bap_stream_t *stream) +{ + ESP_LOGI(TAG, "Stream %p QoS set", stream); +} + +static void stream_enabled_cb(esp_ble_audio_bap_stream_t *stream) +{ + ESP_LOGI(TAG, "Stream %p enabled", stream); +} + +static void stream_connected_cb(esp_ble_audio_bap_stream_t *stream) +{ + esp_ble_audio_bap_stream_t *paired_stream; + int pair_index; + bool ret; + + ESP_LOGI(TAG, "Stream %p connected", stream); + + pair_index = get_stream_pair_index(stream); + paired_stream = get_paired_stream(stream); + if (pair_index >= 0) { + ESP_LOGI(TAG, "Stream %p in pair[%d], paired stream %p, same_pair %u", + stream, pair_index, paired_stream, + streams_are_same_pair(stream, paired_stream)); + } else { + ESP_LOGW(TAG, "Failed to find stream pair for stream %p", stream); + } + + stream_connected(stream, true); + + if (streams_are_same_pair(stream, paired_stream) && + stream_is_connecting(paired_stream)) { + ESP_LOGI(TAG, "Waiting paired stream %p connected before next pair", paired_stream); + return; + } + + ret = connect_stream(); + if (ret == false) { + return; + } + + start_stream(); +} + +static void stream_disconnected_cb(esp_ble_audio_bap_stream_t *stream, uint8_t reason) +{ + ESP_LOGI(TAG, "Stream %p disconnected, reason 0x%02x", stream, reason); + + /* Reset the connected state to allow reconnection */ + for (size_t i = 0; i < ARRAY_SIZE(sinks); i++) { + if (&sinks[i].stream == stream) { + (void)stream_tx_unregister(stream); + sinks[i].connected = ASCS_RSP_NONE; + return; + } + } + + for (size_t i = 0; i < ARRAY_SIZE(sources); i++) { + if (&sources[i].stream == stream) { + sources[i].connected = ASCS_RSP_NONE; + return; + } + } + + ESP_LOGW(TAG, "No matching stream found for disconnected stream %p", stream); +} + +static void stream_started_cb(esp_ble_audio_bap_stream_t *stream) +{ + int err; + + ESP_LOGI(TAG, "Stream %p started", stream); + + if (stream_is_sink(stream)) { + err = stream_tx_register(stream); + if (err) { + ESP_LOGE(TAG, "Failed to register stream %p for TX, err %d", stream, err); + } + } +} + +static void stream_metadata_updated_cb(esp_ble_audio_bap_stream_t *stream) +{ + ESP_LOGI(TAG, "Stream %p metadata updated", stream); +} + +static void stream_disabled_cb(esp_ble_audio_bap_stream_t *stream) +{ + ESP_LOGI(TAG, "Stream %p disabled", stream); +} + +static void stream_stopped_cb(esp_ble_audio_bap_stream_t *stream, uint8_t reason) +{ + ESP_LOGI(TAG, "Stream %p stopped, reason 0x%02x", stream, reason); + + if (stream_is_sink(stream)) { + (void)stream_tx_unregister(stream); + } +} + +static void stream_released_cb(esp_ble_audio_bap_stream_t *stream) +{ + ESP_LOGI(TAG, "Stream %p released", stream); +} + +static void stream_sent_cb(esp_ble_audio_bap_stream_t *stream, void *user_data) +{ + stream_tx_sent(stream, user_data); +} + +static esp_ble_audio_bap_stream_ops_t stream_ops = { + .configured = stream_configured_cb, + .qos_set = stream_qos_set_cb, + .enabled = stream_enabled_cb, + .started = stream_started_cb, + .metadata_updated = stream_metadata_updated_cb, + .disabled = stream_disabled_cb, + .stopped = stream_stopped_cb, + .released = stream_released_cb, + .sent = stream_sent_cb, + .connected = stream_connected_cb, + .disconnected = stream_disconnected_cb, +}; + +static void location_cb(esp_ble_conn_t *conn, + esp_ble_audio_dir_t dir, + esp_ble_audio_location_t loc) +{ + ESP_LOGI(TAG, "Location, dir %u loc 0x%08lx", dir, loc); +} + +static void available_contexts_cb(esp_ble_conn_t *conn, + esp_ble_audio_context_t snk_ctx, + esp_ble_audio_context_t src_ctx) +{ + ESP_LOGI(TAG, "Available contexts, sink 0x%04x source 0x%04x", snk_ctx, src_ctx); +} + +static void config_cb(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_bap_ascs_rsp_code_t rsp_code, + esp_ble_audio_bap_ascs_reason_t reason) +{ + uint8_t stream_count; + bool ret; + int err; + + ESP_LOGI(TAG, "Config, stream %p rsp_code 0x%02x reason 0x%02x", stream, rsp_code, reason); + + stream_configured(stream, rsp_code == ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_SUCCESS); + + ret = configure_stream(); + if (ret == false) { + return; + } + + if (configured_stream_count == 0) { + ESP_LOGW(TAG, "No streams were configured"); + return; + } + + stream_count = 0; + + for (size_t i = 0; i < ARRAY_SIZE(sinks); i++) { + if (sinks[i].configured == ASCS_RSP_SUCCESS) { + streams[stream_count++] = &sinks[i].stream; + } + } + + for (size_t i = 0; i < ARRAY_SIZE(sources); i++) { + if (sources[i].configured == ASCS_RSP_SUCCESS) { + streams[stream_count++] = &sources[i].stream; + } + } + + err = create_group(); + if (err) { + return; + } + + err = set_stream_qos(); + if (err) { + return; + } +} + +static void qos_cb(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_bap_ascs_rsp_code_t rsp_code, + esp_ble_audio_bap_ascs_reason_t reason) +{ + ESP_LOGI(TAG, "Qos, stream %p rsp_code 0x%02x reason 0x%02x", stream, rsp_code, reason); + + stream_qos_set(stream, rsp_code == ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_SUCCESS); + + if (is_all_stream_qos_set()) { + enable_stream(); + } +} + +static void enable_cb(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_bap_ascs_rsp_code_t rsp_code, + esp_ble_audio_bap_ascs_reason_t reason) +{ + bool ret; + + ESP_LOGI(TAG, "Enable, stream %p rsp_code 0x%02x reason 0x%02x", stream, rsp_code, reason); + + stream_enabled(stream, rsp_code == ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_SUCCESS); + + ret = enable_stream(); + if (ret == false) { + return; + } + + connect_stream(); +} + +static void start_cb(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_bap_ascs_rsp_code_t rsp_code, + esp_ble_audio_bap_ascs_reason_t reason) +{ + ESP_LOGI(TAG, "Start, stream %p rsp_code 0x%02x reason 0x%02x", stream, rsp_code, reason); +} + +static void stop_cb(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_bap_ascs_rsp_code_t rsp_code, + esp_ble_audio_bap_ascs_reason_t reason) +{ + ESP_LOGI(TAG, "Stop, stream %p rsp_code 0x%02x reason 0x%02x", stream, rsp_code, reason); +} + +static void disable_cb(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_bap_ascs_rsp_code_t rsp_code, + esp_ble_audio_bap_ascs_reason_t reason) +{ + ESP_LOGI(TAG, "Disable, stream %p rsp_code 0x%02x reason 0x%02x", stream, rsp_code, reason); +} + +static void metadata_cb(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_bap_ascs_rsp_code_t rsp_code, + esp_ble_audio_bap_ascs_reason_t reason) +{ + ESP_LOGI(TAG, "Metadata, stream %p rsp_code 0x%02x reason 0x%02x", stream, rsp_code, reason); +} + +static void release_cb(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_bap_ascs_rsp_code_t rsp_code, + esp_ble_audio_bap_ascs_reason_t reason) +{ + ESP_LOGI(TAG, "Release, stream %p rsp_code 0x%02x reason 0x%02x", stream, rsp_code, reason); +} + +static void pac_record_cb(esp_ble_conn_t *conn, + esp_ble_audio_dir_t dir, + const esp_ble_audio_codec_cap_t *codec_cap) +{ + if (codec_cap == NULL) { + return; + } + + example_print_codec_cap(codec_cap); +} + +static void endpoint_cb(esp_ble_conn_t *conn, + esp_ble_audio_dir_t dir, + esp_ble_audio_bap_ep_t *ep) +{ + if (dir == ESP_BLE_AUDIO_DIR_SOURCE) { + for (size_t i = 0; i < ARRAY_SIZE(sources); i++) { + if (sources[i].ep == NULL) { + ESP_LOGI(TAG, "Source #%u: ep %p", i, ep); + sources[i].ep = ep; + return; + } + } + + ESP_LOGW(TAG, "Could not add source ep"); + } else if (dir == ESP_BLE_AUDIO_DIR_SINK) { + for (size_t i = 0; i < ARRAY_SIZE(sinks); i++) { + if (sinks[i].ep == NULL) { + ESP_LOGI(TAG, "Sink #%u: ep %p", i, ep); + sinks[i].ep = ep; + return; + } + } + + ESP_LOGW(TAG, "Could not add sink ep"); + } +} + +static void discover_cb(esp_ble_conn_t *conn, int err, esp_ble_audio_dir_t dir) +{ + if (conn->handle != default_conn_handle) { + return; + } + + if (dir == ESP_BLE_AUDIO_DIR_SINK) { + if (err) { + ESP_LOGE(TAG, "Discovery sinks failed, err %d", err); + } else { + ESP_LOGI(TAG, "Discover sinks complete"); + + discover_sources(); + } + } else if (dir == ESP_BLE_AUDIO_DIR_SOURCE) { + if (err) { + ESP_LOGE(TAG, "Discovery sources failed, err %d", err); + } else { + ESP_LOGI(TAG, "Discover sources complete"); + + configure_stream(); + } + } +} + +static esp_ble_audio_bap_unicast_client_cb_t unicast_client_cbs = { + .location = location_cb, + .available_contexts = available_contexts_cb, + .config = config_cb, + .qos = qos_cb, + .enable = enable_cb, + .start = start_cb, + .stop = stop_cb, + .disable = disable_cb, + .metadata = metadata_cb, + .release = release_cb, + .pac_record = pac_record_cb, + .endpoint = endpoint_cb, + .discover = discover_cb, +}; + +static int conn_create(ble_addr_t *dst) +{ + struct ble_gap_conn_params params = {0}; + uint8_t own_addr_type = 0; + int err; + + err = ble_hs_id_infer_auto(0, &own_addr_type); + if (err) { + ESP_LOGE(TAG, "Failed to determine address type, err %d", err); + return err; + } + + err = ble_gap_disc_cancel(); + if (err) { + ESP_LOGE(TAG, "Failed to stop scanning, err %d", err); + return err; + } + + disc_cancelled = true; + + params.scan_itvl = INIT_SCAN_INTERVAL; + params.scan_window = INIT_SCAN_WINDOW; + params.itvl_min = CONN_INTERVAL; + params.itvl_max = CONN_INTERVAL; + params.latency = CONN_LATENCY; + params.supervision_timeout = CONN_TIMEOUT; + params.max_ce_len = CONN_MAX_CE_LEN; + params.min_ce_len = CONN_MIN_CE_LEN; + + return ble_gap_connect(own_addr_type, dst, CONN_DURATION, ¶ms, + example_audio_gap_event_cb, NULL); +} + +static int pairing_start(uint16_t conn_handle) +{ + return ble_gap_security_initiate(conn_handle); +} + +static int exchange_mtu(uint16_t conn_handle) +{ + return ble_gattc_exchange_mtu(conn_handle, NULL, NULL); +} + +struct unicast_server_adv_data { + bool target_matched; + bool ascs_found; + uint8_t announcement_type; + uint32_t audio_contexts; + uint8_t meta_len; +}; + +static bool scan_data_cb(uint8_t type, const uint8_t *data, + uint8_t data_len, void *user_data) +{ + struct unicast_server_adv_data *adv = user_data; + uint8_t announcement_type; + uint32_t audio_contexts; + uint16_t uuid_val; + uint8_t meta_len; + size_t min_size; + + switch (type) { + case EXAMPLE_AD_TYPE_NAME_COMPLETE: + adv->target_matched = (data_len == TARGET_DEVICE_NAME_LEN) && + !memcmp(data, TARGET_DEVICE_NAME, TARGET_DEVICE_NAME_LEN); + if (!adv->target_matched) { + return false; + } + return true; + case EXAMPLE_AD_TYPE_SERVICE_DATA16: + break; + default: + return true; + } + + if (data_len < sizeof(uuid_val)) { + ESP_LOGW(TAG, "AD invalid size %u", data_len); + return true; + } + + uuid_val = sys_get_le16(data); + + if (uuid_val != ESP_BLE_AUDIO_UUID_ASCS_VAL) { + return true; + } + + min_size = sizeof(uuid_val) + sizeof(announcement_type) + + sizeof(audio_contexts) + sizeof(meta_len); + if (data_len < min_size) { + ESP_LOGW(TAG, "AD invalid size %u", data_len); + return false; + } + + announcement_type = data[2]; + audio_contexts = sys_get_le32(data + 3); + meta_len = data[7]; + + adv->announcement_type = announcement_type; + adv->audio_contexts = audio_contexts; + adv->meta_len = meta_len; + adv->ascs_found = true; + + return true; +} + +static void ext_scan_recv(esp_ble_audio_gap_app_event_t *event) +{ + struct unicast_server_adv_data adv = {0}; + ble_addr_t dst = {0}; + int err; + + if (default_conn_handle != CONN_HANDLE_INIT) { + return; + } + + /* Check if the advertising is connectable and if ASCS is supported */ + if (event->ext_scan_recv.event_type & EXAMPLE_ADV_PROP_CONNECTABLE) { + esp_ble_audio_data_parse(event->ext_scan_recv.data, + event->ext_scan_recv.data_len, + scan_data_cb, &adv); + } + + if (!adv.target_matched || !adv.ascs_found) { + return; + } + + ESP_LOGI(TAG, "Unicast server found, type %u, contexts 0x%08x, meta_len %u", + adv.announcement_type, adv.audio_contexts, adv.meta_len); + + dst.type = event->ext_scan_recv.addr.type; + memcpy(dst.val, event->ext_scan_recv.addr.val, sizeof(dst.val)); + + err = conn_create(&dst); + if (err) { + ESP_LOGE(TAG, "Failed to create conn, err %d", err); + + if (disc_cancelled) { + disc_cancelled = false; + ext_scan_start(); + } + } +} + +static void acl_connect(esp_ble_audio_gap_app_event_t *event) +{ + int err; + + if (event->acl_connect.status) { + ESP_LOGE(TAG, "connection failed, status %d", event->acl_connect.status); + return; + } + + ESP_LOGI(TAG, "Conn established:"); + ESP_LOGI(TAG, "conn_handle 0x%04x status 0x%02x role %u peer %02x:%02x:%02x:%02x:%02x:%02x", + event->acl_connect.conn_handle, event->acl_connect.status, + event->acl_connect.role, event->acl_connect.dst.val[5], + event->acl_connect.dst.val[4], event->acl_connect.dst.val[3], + event->acl_connect.dst.val[2], event->acl_connect.dst.val[1], + event->acl_connect.dst.val[0]); + + err = pairing_start(event->acl_connect.conn_handle); + if (err) { + ESP_LOGE(TAG, "Failed to initiate security, err %d", err); + return; + } + + default_conn_handle = event->acl_connect.conn_handle; +} + +static void acl_disconnect(esp_ble_audio_gap_app_event_t *event) +{ + ESP_LOGI(TAG, "Conn terminated: conn_handle 0x%04x reason 0x%02x", + event->acl_disconnect.conn_handle, event->acl_disconnect.reason); + + default_conn_handle = CONN_HANDLE_INIT; + disc_completed = false; + disc_cancelled = false; + mtu_exchanged = false; + + reset_stream_state(); + + if (unicast_group != NULL) { + esp_ble_audio_bap_unicast_group_delete(unicast_group); + unicast_group = NULL; + } + + ext_scan_start(); +} + +static void security_change(esp_ble_iso_gap_app_event_t *event) +{ + int err; + + if (event->security_change.status) { + ESP_LOGE(TAG, "security change failed, status %d", event->security_change.status); + return; + } + + ESP_LOGI(TAG, "Security change:"); + ESP_LOGI(TAG, "conn_handle 0x%04x status 0x%02x role %u sec_level %u bonded %u " + "peer %02x:%02x:%02x:%02x:%02x:%02x", + event->security_change.conn_handle, event->security_change.status, + event->security_change.role, event->security_change.sec_level, + event->security_change.bonded, event->security_change.dst.val[5], + event->security_change.dst.val[4], event->security_change.dst.val[3], + event->security_change.dst.val[2], event->security_change.dst.val[1], + event->security_change.dst.val[0]); + + err = exchange_mtu(event->security_change.conn_handle); + if (err) { + ESP_LOGE(TAG, "Failed to exchange MTU, err %d", err); + return; + } +} + +static void iso_gap_app_cb(esp_ble_audio_gap_app_event_t *event) +{ + switch (event->type) { + case ESP_BLE_AUDIO_GAP_EVENT_EXT_SCAN_RECV: + ext_scan_recv(event); + break; + case ESP_BLE_AUDIO_GAP_EVENT_ACL_CONNECT: + acl_connect(event); + break; + case ESP_BLE_AUDIO_GAP_EVENT_ACL_DISCONNECT: + acl_disconnect(event); + break; + case ESP_BLE_AUDIO_GAP_EVENT_SECURITY_CHANGE: + security_change(event); + break; + default: + break; + } +} + +static void gatt_mtu_change(esp_ble_audio_gatt_app_event_t *event) +{ + int err; + + ESP_LOGI(TAG, "gatt mtu change, conn_handle %u, mtu %u", + event->gatt_mtu_change.conn_handle, event->gatt_mtu_change.mtu); + + if (event->gatt_mtu_change.mtu < ESP_BLE_AUDIO_ATT_MTU_MIN) { + ESP_LOGW(TAG, "Invalid new mtu %u, shall be at least %u", + event->gatt_mtu_change.mtu, ESP_BLE_AUDIO_ATT_MTU_MIN); + return; + } + + err = esp_ble_audio_gattc_disc_start(event->gatt_mtu_change.conn_handle); + if (err) { + ESP_LOGE(TAG, "Failed to start svc disc, err %d", err); + return; + } + + ESP_LOGI(TAG, "Start discovering gatt services"); + + /* Note: + * MTU exchanged event may arrived after discover completed event. + */ + mtu_exchanged = true; + + if (disc_completed) { + (void)discover_sinks(); + } +} + +static void gattc_disc_cmpl(esp_ble_audio_gatt_app_event_t *event) +{ + ESP_LOGI(TAG, "gattc disc cmpl, status %u, conn_handle %u", + event->gattc_disc_cmpl.status, event->gattc_disc_cmpl.conn_handle); + + if (event->gattc_disc_cmpl.status) { + ESP_LOGE(TAG, "gattc disc failed, status %u", event->gattc_disc_cmpl.status); + return; + } + + /* Note: + * Discover completed event may arrived before MTU exchanged event. + */ + disc_completed = true; + + if (mtu_exchanged) { + (void)discover_sinks(); + } +} + +static void iso_gatt_app_cb(esp_ble_audio_gatt_app_event_t *event) +{ + switch (event->type) { + case ESP_BLE_AUDIO_GATT_EVENT_GATT_MTU_CHANGE: + gatt_mtu_change(event); + break; + case ESP_BLE_AUDIO_GATT_EVENT_GATTC_DISC_CMPL: + gattc_disc_cmpl(event); + break; + default: + break; + } +} + +static int ext_scan_start(void) +{ + struct ble_gap_disc_params params = {0}; + uint8_t own_addr_type; + int err; + + err = ble_hs_id_infer_auto(0, &own_addr_type); + if (err) { + ESP_LOGE(TAG, "Failed to determine own addr type, err %d", err); + return err; + } + + params.passive = 1; + params.itvl = SCAN_INTERVAL; + params.window = SCAN_WINDOW; + + err = ble_gap_disc(own_addr_type, BLE_HS_FOREVER, ¶ms, + example_audio_gap_event_cb, NULL); + if (err) { + ESP_LOGE(TAG, "Failed to start scanning, err %d", err); + return err; + } + + ESP_LOGI(TAG, "Extended scan started"); + return 0; +} + +void app_main(void) +{ + esp_ble_audio_init_info_t info = { + .gap_cb = iso_gap_app_cb, + .gatt_cb = iso_gatt_app_cb, + }; + esp_err_t err; + + /* Initialize NVS — it is used to store PHY calibration data */ + err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK(err); + + err = bluetooth_init(); + if (err) { + ESP_LOGE(TAG, "Failed to initialize BLE, err %d", err); + return; + } + + err = esp_ble_audio_common_init(&info); + if (err) { + ESP_LOGE(TAG, "Failed to initialize audio, err %d", err); + return; + } + + for (size_t i = 0; i < ARRAY_SIZE(sinks); i++) { + sinks[i].stream.ops = &stream_ops; + } + + for (size_t i = 0; i < ARRAY_SIZE(sources); i++) { + sources[i].stream.ops = &stream_ops; + } + + reset_stream_state(); + + stream_tx_init(); + + err = esp_ble_audio_bap_unicast_client_register_cb(&unicast_client_cbs); + if (err) { + ESP_LOGE(TAG, "Failed to register client callbacks, err %d", err); + return; + } + + err = esp_ble_audio_common_start(NULL); + if (err) { + ESP_LOGE(TAG, "Failed to start audio, err %d", err); + return; + } + + err = ble_svc_gap_device_name_set("BAP Unicast Client"); + if (err) { + ESP_LOGE(TAG, "Failed to set device name, err %d", err); + return; + } + + ext_scan_start(); +} diff --git a/examples/bluetooth/esp_ble_audio/bap/unicast_client/main/stream_tx.c b/examples/bluetooth/esp_ble_audio/bap/unicast_client/main/stream_tx.c new file mode 100644 index 0000000000..347c491341 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/bap/unicast_client/main/stream_tx.c @@ -0,0 +1,185 @@ +/* + * SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include "stream_tx.h" + +static struct tx_stream tx_streams[CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT]; + +static bool stream_is_streaming(const esp_ble_audio_bap_stream_t *stream) +{ + esp_ble_audio_bap_ep_info_t ep_info = {0}; + int err; + + /* No-op if stream is not configured */ + if (stream->ep == NULL) { + return false; + } + + err = esp_ble_audio_bap_ep_get_info(stream->ep, &ep_info); + if (err) { + return false; + } + + return (ep_info.state == ESP_BLE_AUDIO_BAP_EP_STATE_STREAMING); +} + +static void stream_tx_send(struct tx_stream *tx_stream) +{ + int err; + + if (tx_stream == NULL || tx_stream->stream == NULL) { + return; + } + + if (stream_is_streaming(tx_stream->stream) == false) { + return; + } + + if (tx_stream->stream->qos == NULL || tx_stream->stream->qos->sdu == 0) { + ESP_LOGE(TAG, "Invalid stream qos"); + return; + } + + if (tx_stream->data == NULL) { + ESP_LOGE(TAG, "TX buffer unavailable, SDU %u (stream %p)", + tx_stream->stream->qos->sdu, tx_stream->stream); + return; + } + + memset(tx_stream->data, (uint8_t)tx_stream->seq_num, + tx_stream->stream->qos->sdu); + + err = esp_ble_audio_bap_stream_send(tx_stream->stream, + tx_stream->data, + tx_stream->stream->qos->sdu, + tx_stream->seq_num); + if (err) { + ESP_LOGD(TAG, "Failed to transmit data on stream %p, err %d", + tx_stream->stream, err); + return; + } + + tx_stream->seq_num++; +} + +void stream_tx_sent(esp_ble_audio_bap_stream_t *stream, void *user_data) +{ + for (size_t i = 0; i < ARRAY_SIZE(tx_streams); i++) { + if (tx_streams[i].stream == stream) { + example_audio_tx_scheduler_on_sent(&tx_streams[i].scheduler, user_data, + TAG, "stream", stream); + break; + } + } +} + +static void tx_scheduler_cb(void *arg) +{ + struct tx_stream *tx_stream = arg; + + stream_tx_send(tx_stream); +} + +int stream_tx_register(esp_ble_audio_bap_stream_t *stream) +{ + int err; + + if (stream == NULL) { + return -EINVAL; + } + + for (size_t i = 0; i < ARRAY_SIZE(tx_streams); i++) { + if (tx_streams[i].stream == NULL) { + ESP_LOGI(TAG, "Registered stream %p for TX", stream); + + if (stream->qos == NULL || stream->qos->sdu == 0) { + ESP_LOGE(TAG, "Invalid stream qos"); + return -EINVAL; + } + + if (tx_streams[i].data == NULL) { + tx_streams[i].data = calloc(1, stream->qos->sdu); + if (tx_streams[i].data == NULL) { + ESP_LOGE(TAG, "Failed to alloc TX buffer, SDU %u (stream %p)", + stream->qos->sdu, stream); + return -ENOMEM; + } + } + + tx_streams[i].stream = stream; + tx_streams[i].seq_num = 0; + example_audio_tx_scheduler_reset(&tx_streams[i].scheduler); + + err = example_audio_tx_scheduler_start(&tx_streams[i].scheduler, + stream->qos->interval); + if (err) { + ESP_LOGE(TAG, "Failed to start tx scheduler, err %d", err); + tx_streams[i].stream = NULL; + return err; + } + + stream_tx_send(&tx_streams[i]); + return 0; + } + } + + ESP_LOGE(TAG, "No free TX stream slot"); + + return -ENOMEM; +} + +int stream_tx_unregister(esp_ble_audio_bap_stream_t *stream) +{ + int err; + + if (stream == NULL) { + return -EINVAL; + } + + for (size_t i = 0; i < ARRAY_SIZE(tx_streams); i++) { + if (tx_streams[i].stream == stream) { + ESP_LOGI(TAG, "Unregistered stream %p for TX", stream); + + err = example_audio_tx_scheduler_stop(&tx_streams[i].scheduler); + if (err) { + ESP_LOGE(TAG, "Failed to stop tx scheduler, err %d", err); + return err; + } + + tx_streams[i].stream = NULL; + if (tx_streams[i].data != NULL) { + free(tx_streams[i].data); + tx_streams[i].data = NULL; + } + + return 0; + } + } + + return -ENODATA; +} + +void stream_tx_init(void) +{ + int err; + + for (size_t i = 0; i < ARRAY_SIZE(tx_streams); i++) { + err = example_audio_tx_scheduler_init(&tx_streams[i].scheduler, + tx_scheduler_cb, + &tx_streams[i]); + if (err) { + ESP_LOGE(TAG, "Failed to init tx scheduler[%u], err %d", i, err); + return; + } + } +} diff --git a/examples/bluetooth/esp_ble_audio/bap/unicast_client/main/stream_tx.h b/examples/bluetooth/esp_ble_audio/bap/unicast_client/main/stream_tx.h new file mode 100644 index 0000000000..11c7ae96ca --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/bap/unicast_client/main/stream_tx.h @@ -0,0 +1,38 @@ +/* + * SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "esp_log.h" + +#include "sdkconfig.h" + +#include "esp_ble_audio_lc3_defs.h" +#include "esp_ble_audio_bap_api.h" +#include "esp_ble_audio_pacs_api.h" +#include "esp_ble_audio_bap_lc3_preset_defs.h" +#include "esp_ble_audio_common_api.h" + +#include "ble_audio_example_init.h" +#include "ble_audio_example_utils.h" + +#define TAG "BAP_UCL" + +struct tx_stream { + esp_ble_audio_bap_stream_t *stream; + uint16_t seq_num; + uint8_t *data; + example_audio_tx_scheduler_t scheduler; +}; + +void stream_tx_sent(esp_ble_audio_bap_stream_t *stream, void *user_data); + +int stream_tx_register(esp_ble_audio_bap_stream_t *stream); + +int stream_tx_unregister(esp_ble_audio_bap_stream_t *stream); + +void stream_tx_init(void); diff --git a/examples/bluetooth/esp_ble_audio/bap/unicast_client/sdkconfig.defaults b/examples/bluetooth/esp_ble_audio/bap/unicast_client/sdkconfig.defaults new file mode 100644 index 0000000000..358a3896ea --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/bap/unicast_client/sdkconfig.defaults @@ -0,0 +1,19 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration +# + +CONFIG_BT_ENABLED=y +CONFIG_BT_BLUEDROID_ENABLED=n +CONFIG_BT_NIMBLE_ENABLED=y +CONFIG_BT_NIMBLE_EXT_ADV=y +CONFIG_BT_NIMBLE_MAX_CONNECTIONS=1 +CONFIG_BT_NIMBLE_MAX_CCCDS=20 +CONFIG_BT_NIMBLE_ISO=y +CONFIG_BT_NIMBLE_LOG_LEVEL_WARNING=y + +CONFIG_BT_ISO_MAX_CHAN=2 + +CONFIG_BT_BAP_UNICAST_CLIENT=y +CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT=2 + +CONFIG_FREERTOS_HZ=1000 diff --git a/examples/bluetooth/esp_ble_audio/bap/unicast_client/sdkconfig.defaults.esp32h4 b/examples/bluetooth/esp_ble_audio/bap/unicast_client/sdkconfig.defaults.esp32h4 new file mode 100644 index 0000000000..5920ce3f85 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/bap/unicast_client/sdkconfig.defaults.esp32h4 @@ -0,0 +1,6 @@ +# Override some defaults so BT stack is enabled +# by default in this example + +CONFIG_IDF_TARGET="esp32h4" + +CONFIG_BT_LE_ISO_SUPPORT=y diff --git a/examples/bluetooth/esp_ble_audio/bap/unicast_server/CMakeLists.txt b/examples/bluetooth/esp_ble_audio/bap/unicast_server/CMakeLists.txt new file mode 100644 index 0000000000..3b79514ada --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/bap/unicast_server/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.22) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +idf_build_set_property(MINIMAL_BUILD ON) +project(bap_unicast_server) diff --git a/examples/bluetooth/esp_ble_audio/bap/unicast_server/README.md b/examples/bluetooth/esp_ble_audio/bap/unicast_server/README.md new file mode 100644 index 0000000000..d70c3d5a54 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/bap/unicast_server/README.md @@ -0,0 +1,61 @@ +| Supported Targets | ESP32-H4 | +| ----------------- | -------- | + +# BAP Unicast Server Example + +(See the README.md file in the upper level `examples` directory for more information about examples.) + +This example demonstrates the **Basic Audio Profile (BAP) Unicast Server** functionality. It starts connectable extended advertising with the ASCS (Audio Stream Control Service) UUID and service data (targeted announcement, sink and source audio contexts), then waits for a BAP Unicast Client to connect. After connection, the server responds to client requests: codec configuration, QoS, enable, and start. The server starts sink (RX) streams when the client enables them; source (TX) streams are started by the client. The server receives audio on sink streams and can send on source streams. Run it together with the [unicast_client](../unicast_client) example on another device as the client. + +The implementation uses the NimBLE host stack with ISO and BAP support, ESP-BLE-ISO, and ESP-BLE-AUDIO APIs (PACS, BAP unicast server register and callbacks, stream start, stream recv). It is intended for chips that support BLE 5.2 ISO and LE Audio (e.g. ESP32-H4). PACS advertises sink and source capabilities with LC3 (any frequency, 10 ms frame, up to 2 channels, various contexts). The number of sink and source ASEs is set via `CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT` and `CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT`. + +## Requirements + +* A board with Bluetooth LE 5.2, ISO, and LE Audio support (e.g. ESP32-H4) +* Another device running the [unicast_client](../unicast_client) example, which scans for ASCS and connects to this server + +## How to Use Example + +Before project configuration and build, set the correct chip target: + +```bash +idf.py set-target esp32h4 +``` + +### Build and Flash + +Run the following to build, flash and monitor: + +```bash +idf.py -p PORT flash monitor +``` + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the [Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF. + +## Example Flow + +1. **Initialization**: NVS, Bluetooth stack, and LE Audio common layer (`esp_ble_audio_common_init`) with GAP and GATT callbacks. Register PACS (sink and source PAC and location), register the BAP unicast server (sink and source ASE counts), register unicast server callbacks (config, reconfig, QoS, enable, start, metadata, disable, stop, release), register PACS capabilities (LC3 sink and source), register stream callbacks for sink and source streams, set PACS location and supported/available contexts, then start the audio stack and set the device name. +2. **Advertising**: Start connectable extended advertising with flags, ASCS UUID, ASCS service data (targeted, sink/source contexts), and device name `bap_unicast_server`. +3. **Client connection**: When a client connects, ACL and optional security change are handled. On MTU exchange the server may start GATT service discovery (as needed for the stack). +4. **ASCS operations**: The client discovers ASEs, then sends codec config, QoS, enable, and start. The server allocates a stream per config (sink or source), returns QoS preference, validates enable (codec params), and on start resets stream counters. For sink streams, when the client enables the stream the server calls `esp_ble_audio_bap_stream_start`; for source streams the client starts them. +5. **Streaming**: When a sink stream is started, received ISO SDUs are delivered in the stream recv callback; the example counts valid, error, and lost packets and logs periodically. Source streams can send audio when started by the client. + +## Example Output + +``` +I (xxx) BAP_USR: Extended adv instance 0 started +I (xxx) BAP_USR: connection established, status 0 +I (xxx) BAP_USR: ASE Codec Config: conn 0x... ep 0x... dir ... +I (xxx) BAP_USR: Stream 0x... enabled +I (xxx) BAP_USR: Stream 0x... started +I (xxx) BAP_USR: Received 1000(1000/0/0) ISO data packets (stream 0x...) +... +``` + +If the client disconnects: + +``` +I (xxx) BAP_USR: connection disconnected, reason 0x... +``` diff --git a/examples/bluetooth/esp_ble_audio/bap/unicast_server/main/CMakeLists.txt b/examples/bluetooth/esp_ble_audio/bap/unicast_server/main/CMakeLists.txt new file mode 100644 index 0000000000..721967052c --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/bap/unicast_server/main/CMakeLists.txt @@ -0,0 +1,4 @@ +set(srcs "main.c") + +idf_component_register(SRCS "${srcs}" + REQUIRES bt nvs_flash) diff --git a/examples/bluetooth/esp_ble_audio/bap/unicast_server/main/idf_component.yml b/examples/bluetooth/esp_ble_audio/bap/unicast_server/main/idf_component.yml new file mode 100644 index 0000000000..bb02c0922a --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/bap/unicast_server/main/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + example_init: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_audio/common_components/example_init + example_utils: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_audio/common_components/example_utils diff --git a/examples/bluetooth/esp_ble_audio/bap/unicast_server/main/main.c b/examples/bluetooth/esp_ble_audio/bap/unicast_server/main/main.c new file mode 100644 index 0000000000..03f37cc038 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/bap/unicast_server/main/main.c @@ -0,0 +1,781 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include "esp_log.h" +#include "nvs_flash.h" +#include "esp_system.h" +#include "esp_timer.h" + +#include "host/ble_hs.h" +#include "services/gap/ble_svc_gap.h" + +#include "esp_ble_audio_lc3_defs.h" +#include "esp_ble_audio_bap_api.h" +#include "esp_ble_audio_pacs_api.h" + +#include "ble_audio_example_init.h" +#include "ble_audio_example_utils.h" + +#define TAG "BAP_USR" + +#define LOCAL_DEVICE_NAME "BAP Unicast Server" +#define LOCAL_DEVICE_NAME_LEN (sizeof(LOCAL_DEVICE_NAME) - 1) + +#define ADV_HANDLE 0x00 +#define ADV_SID 0 +#define ADV_TX_POWER 127 +#define ADV_ADDRESS BLE_OWN_ADDR_PUBLIC +#define ADV_PRIMARY_PHY BLE_HCI_LE_PHY_1M +#define ADV_SECONDARY_PHY BLE_HCI_LE_PHY_2M +#define ADV_INTERVAL BLE_GAP_ADV_ITVL_MS(200) + +#define SINK_LOCATION (ESP_BLE_AUDIO_LOCATION_FRONT_LEFT | \ + ESP_BLE_AUDIO_LOCATION_FRONT_RIGHT) + +#define SOURCE_LOCATION (ESP_BLE_AUDIO_LOCATION_FRONT_LEFT | \ + ESP_BLE_AUDIO_LOCATION_FRONT_RIGHT) + +#define SINK_CONTEXT (ESP_BLE_AUDIO_CONTEXT_TYPE_UNSPECIFIED | \ + ESP_BLE_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | \ + ESP_BLE_AUDIO_CONTEXT_TYPE_MEDIA) + +#define SOURCE_CONTEXT (ESP_BLE_AUDIO_CONTEXT_TYPE_UNSPECIFIED | \ + ESP_BLE_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | \ + ESP_BLE_AUDIO_CONTEXT_TYPE_MEDIA) + +static uint8_t codec_data[] = + ESP_BLE_AUDIO_CODEC_CAP_LC3_DATA( + ESP_BLE_AUDIO_CODEC_CAP_FREQ_ANY, /* Sampling frequency Any */ + ESP_BLE_AUDIO_CODEC_CAP_DURATION_10, /* Frame duration 10ms */ + ESP_BLE_AUDIO_CODEC_CAP_CHAN_COUNT_SUPPORT(2), /* Supported channels 2 */ + 40, /* Minimum 40 octets per frame */ + 120, /* Maximum 120 octets per frame */ + 2); /* Maximum 2 codec frames per SDU */ + +static uint8_t codec_meta[] = + ESP_BLE_AUDIO_CODEC_CAP_LC3_META(SINK_CONTEXT | SOURCE_CONTEXT); + +static const esp_ble_audio_codec_cap_t codec_cap = + ESP_BLE_AUDIO_CODEC_CAP_LC3(codec_data, codec_meta); + +static esp_ble_audio_pacs_cap_t cap_sink = { + .codec_cap = &codec_cap, +}; + +static esp_ble_audio_pacs_cap_t cap_source = { + .codec_cap = &codec_cap, +}; + +static esp_ble_audio_bap_unicast_server_register_param_t param = { + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT, + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT +}; + +static struct unicast_server_sink_stream { + esp_ble_audio_bap_stream_t stream; + + /* RX */ + example_audio_rx_metrics_t rx_metrics; +} sink_streams[CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT]; + +static struct unicast_server_stream { + esp_ble_audio_bap_stream_t stream; + + /* TX */ + uint16_t seq_num; + uint16_t max_sdu; + uint32_t send_count; +} source_streams[CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT]; + +static size_t configured_source_stream_count; + +static const esp_ble_audio_bap_qos_cfg_pref_t qos_pref = + ESP_BLE_AUDIO_BAP_QOS_CFG_PREF(true, /* Unframed PDUs supported */ + ESP_BLE_ISO_PHY_2M, /* Preferred Target PHY */ + 2, /* Preferred Retransmission number */ + 10, /* Preferred Maximum Transport Latency (msec) */ + 20000, /* Minimum Presentation Delay (usec) */ + 40000, /* Maximum Presentation Delay (usec) */ + 20000, /* Preferred Minimum Presentation Delay (usec) */ + 40000); /* Preferred Maximum Presentation Delay (usec) */ + +static uint8_t ext_adv_data[3 + 4 + 10 + 2 + LOCAL_DEVICE_NAME_LEN]; + +static esp_ble_audio_dir_t stream_dir(const esp_ble_audio_bap_stream_t *stream) +{ + for (size_t i = 0; i < ARRAY_SIZE(source_streams); i++) { + if (stream == &source_streams[i].stream) { + return ESP_BLE_AUDIO_DIR_SOURCE; + } + } + + for (size_t i = 0; i < ARRAY_SIZE(sink_streams); i++) { + if (stream == &sink_streams[i].stream) { + return ESP_BLE_AUDIO_DIR_SINK; + } + } + + assert(0 && "Invalid stream"); +} + +static esp_ble_audio_bap_stream_t *stream_alloc(esp_ble_audio_dir_t dir) +{ + if (dir == ESP_BLE_AUDIO_DIR_SOURCE) { + for (size_t i = 0; i < ARRAY_SIZE(source_streams); i++) { + esp_ble_audio_bap_stream_t *stream = &source_streams[i].stream; + + if (stream->conn == NULL) { + return stream; + } + } + } else { + for (size_t i = 0; i < ARRAY_SIZE(sink_streams); i++) { + esp_ble_audio_bap_stream_t *stream = &sink_streams[i].stream; + + if (stream->conn == NULL) { + return stream; + } + } + } + + return NULL; +} + +static int config_cb(esp_ble_conn_t *conn, + const esp_ble_audio_bap_ep_t *ep, + esp_ble_audio_dir_t dir, + const esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_bap_stream_t **stream, + esp_ble_audio_bap_qos_cfg_pref_t *const pref, + esp_ble_audio_bap_ascs_rsp_t *rsp) +{ + ESP_LOGI(TAG, "Config: conn %p ep %p dir %u", conn, ep, dir); + + example_print_codec_cfg(codec_cfg); + + *stream = stream_alloc(dir); + if (*stream == NULL) { + ESP_LOGI(TAG, "No streams available"); + + *rsp = ESP_BLE_AUDIO_BAP_ASCS_RSP(ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_NO_MEM, + ESP_BLE_AUDIO_BAP_ASCS_REASON_NONE); + return -ENOMEM; + } + + ESP_LOGI(TAG, "Config stream %p", *stream); + + if (dir == ESP_BLE_AUDIO_DIR_SOURCE) { + configured_source_stream_count++; + } + + *pref = qos_pref; + + return 0; +} + +static int reconfig_cb(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_dir_t dir, + const esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_bap_qos_cfg_pref_t *const pref, + esp_ble_audio_bap_ascs_rsp_t *rsp) +{ + ESP_LOGI(TAG, "Reconfig: stream %p dir %u", stream, dir); + + example_print_codec_cfg(codec_cfg); + + *rsp = ESP_BLE_AUDIO_BAP_ASCS_RSP(ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_CONF_UNSUPPORTED, + ESP_BLE_AUDIO_BAP_ASCS_REASON_NONE); + + /* We only support one QoS at the moment, reject changes */ + return -ENOEXEC; +} + +static int qos_cb(esp_ble_audio_bap_stream_t *stream, + const esp_ble_audio_bap_qos_cfg_t *qos, + esp_ble_audio_bap_ascs_rsp_t *rsp) +{ + ESP_LOGI(TAG, "QoS: stream %p qos %p", stream, qos); + + example_print_qos(qos); + + for (size_t i = 0; i < ARRAY_SIZE(source_streams); i++) { + if (stream == &source_streams[i].stream) { + source_streams[i].max_sdu = qos->sdu; + break; + } + } + + return 0; +} + +static int enable_cb(esp_ble_audio_bap_stream_t *stream, + const uint8_t meta[], size_t meta_len, + esp_ble_audio_bap_ascs_rsp_t *rsp) +{ + esp_ble_audio_codec_cfg_frame_dur_t frame_dur; + esp_ble_audio_codec_cfg_freq_t freq; + uint32_t frame_dur_us; + uint8_t frame_blocks; + uint32_t freq_hz; + esp_err_t err; + + err = esp_ble_audio_codec_cfg_get_freq(stream->codec_cfg, &freq); + if (err) { + ESP_LOGE(TAG, "Error: Codec frequency not set"); + + *rsp = ESP_BLE_AUDIO_BAP_ASCS_RSP(ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_CONF_INVALID, + ESP_BLE_AUDIO_BAP_ASCS_REASON_CODEC_DATA); + return err; + } + + err = esp_ble_audio_codec_cfg_freq_to_freq_hz(freq, &freq_hz); + if (err) { + ESP_LOGE(TAG, "Failed to get frequency hz"); + + *rsp = ESP_BLE_AUDIO_BAP_ASCS_RSP(ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_CONF_INVALID, + ESP_BLE_AUDIO_BAP_ASCS_REASON_CODEC_DATA); + return err; + } + + err = esp_ble_audio_codec_cfg_get_frame_dur(stream->codec_cfg, &frame_dur); + if (err) { + ESP_LOGE(TAG, "Error: Frame duration not set"); + + *rsp = ESP_BLE_AUDIO_BAP_ASCS_RSP(ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_CONF_INVALID, + ESP_BLE_AUDIO_BAP_ASCS_REASON_CODEC_DATA); + return err; + } + + err = esp_ble_audio_codec_cfg_frame_dur_to_frame_dur_us(frame_dur, &frame_dur_us); + if (err) { + ESP_LOGE(TAG, "Failed to get frame duration us"); + + *rsp = ESP_BLE_AUDIO_BAP_ASCS_RSP(ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_CONF_INVALID, + ESP_BLE_AUDIO_BAP_ASCS_REASON_CODEC_DATA); + return err; + } + + err = esp_ble_audio_codec_cfg_get_frame_blocks_per_sdu(stream->codec_cfg, &frame_blocks, true); + if (err) { + ESP_LOGE(TAG, "Error: Frame blocks per SDU not set"); + + *rsp = ESP_BLE_AUDIO_BAP_ASCS_RSP(ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_CONF_INVALID, + ESP_BLE_AUDIO_BAP_ASCS_REASON_CODEC_DATA); + return err; + } + + ESP_LOGI(TAG, "Enable: stream %p meta_len %u codec %u %u %u", + stream, meta_len, freq_hz, frame_dur_us, frame_blocks); + + *rsp = ESP_BLE_AUDIO_BAP_ASCS_RSP(ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_SUCCESS, + ESP_BLE_AUDIO_BAP_ASCS_REASON_CODEC_DATA); + return 0; +} + +static int start_cb(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_bap_ascs_rsp_t *rsp) +{ + ESP_LOGI(TAG, "Start: stream %p", stream); + + for (size_t i = 0; i < ARRAY_SIZE(source_streams); i++) { + if (stream == &source_streams[i].stream) { + source_streams[i].seq_num = 0; + source_streams[i].send_count = 0; + break; + } + } + + return 0; +} + +static bool data_cb(uint8_t type, const uint8_t *data, + uint8_t data_len, void *user_data) +{ + esp_ble_audio_bap_ascs_rsp_t *rsp = user_data; + + if (ESP_BLE_AUDIO_METADATA_TYPE_IS_KNOWN(type) == false) { + ESP_LOGW(TAG, "Invalid metadata type %u or length %u", type, data_len); + + *rsp = ESP_BLE_AUDIO_BAP_ASCS_RSP(ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_METADATA_REJECTED, + type); + return false; + } + + return true; +} + +static int metadata_cb(esp_ble_audio_bap_stream_t *stream, + const uint8_t meta[], size_t meta_len, + esp_ble_audio_bap_ascs_rsp_t *rsp) +{ + esp_err_t err; + + ESP_LOGI(TAG, "Metadata: stream %p meta_len %u", stream, meta_len); + + err = esp_ble_audio_data_parse(meta, meta_len, data_cb, rsp); + if (err) { + return -EIO; + } + + return 0; +} + +static int disable_cb(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_bap_ascs_rsp_t *rsp) +{ + ESP_LOGI(TAG, "Disable: stream %p", stream); + return 0; +} + +static int stop_cb(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_bap_ascs_rsp_t *rsp) +{ + ESP_LOGI(TAG, "Stop: stream %p", stream); + return 0; +} + +static int release_cb(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_bap_ascs_rsp_t *rsp) +{ + ESP_LOGI(TAG, "Release: stream %p", stream); + + if (stream_dir(stream) == ESP_BLE_AUDIO_DIR_SOURCE && + configured_source_stream_count > 0) { + configured_source_stream_count--; + } + + return 0; +} + +static const esp_ble_audio_bap_unicast_server_cb_t unicast_server_cb = { + .config = config_cb, + .reconfig = reconfig_cb, + .qos = qos_cb, + .enable = enable_cb, + .start = start_cb, + .metadata = metadata_cb, + .disable = disable_cb, + .stop = stop_cb, + .release = release_cb, +}; + +static void stream_enabled_cb(esp_ble_audio_bap_stream_t *stream) +{ + esp_err_t err; + + ESP_LOGI(TAG, "Stream %p enabled", stream); + + /* The unicast server is responsible for starting sink ASEs + * after the client has enabled them. + */ + if (stream_dir(stream) == ESP_BLE_AUDIO_DIR_SINK) { + err = esp_ble_audio_bap_stream_start(stream); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to start stream %p, err %d", stream, err); + } + } +} + +static void stream_started_cb(esp_ble_audio_bap_stream_t *stream) +{ + ESP_LOGI(TAG, "Stream %p started", stream); + + if (stream_dir(stream) == ESP_BLE_AUDIO_DIR_SOURCE) { + struct unicast_server_stream *source_stream = + CONTAINER_OF(stream, struct unicast_server_stream, stream); + + /* Reset TX counters */ + source_stream->seq_num = 0; + source_stream->send_count = 0; + } else if (stream_dir(stream) == ESP_BLE_AUDIO_DIR_SINK) { + struct unicast_server_sink_stream *sink_stream = + CONTAINER_OF(stream, struct unicast_server_sink_stream, stream); + + /* Reset RX counters */ + example_audio_rx_metrics_reset(&sink_stream->rx_metrics); + } +} + +static void stream_stopped_cb(esp_ble_audio_bap_stream_t *stream, uint8_t reason) +{ + ESP_LOGI(TAG, "Stream %p stopped, reason 0x%02x", stream, reason); +} + +static void stream_recv_cb(esp_ble_audio_bap_stream_t *stream, + const esp_ble_iso_recv_info_t *info, + const uint8_t *data, uint16_t len) +{ + if (stream_dir(stream) == ESP_BLE_AUDIO_DIR_SINK) { + struct unicast_server_sink_stream *sink_stream = + CONTAINER_OF(stream, struct unicast_server_sink_stream, stream); + + sink_stream->rx_metrics.last_sdu_len = len; + example_audio_rx_metrics_on_recv(info, &sink_stream->rx_metrics, + TAG, "stream", stream); + } +} + +static esp_ble_audio_bap_stream_ops_t stream_ops = { + .enabled = stream_enabled_cb, + .started = stream_started_cb, + .stopped = stream_stopped_cb, + .recv = stream_recv_cb, +}; + +static int set_pacs_location(void) +{ + esp_err_t err; + + if (IS_ENABLED(CONFIG_BT_PAC_SNK_LOC)) { + err = esp_ble_audio_pacs_set_location(ESP_BLE_AUDIO_DIR_SINK, SINK_LOCATION); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to set sink location (err %d)", err); + return -1; + } + } + + if (IS_ENABLED(CONFIG_BT_PAC_SRC_LOC)) { + err = esp_ble_audio_pacs_set_location(ESP_BLE_AUDIO_DIR_SOURCE, SOURCE_LOCATION); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to set source location (err %d)", err); + return -1; + } + } + + ESP_LOGI(TAG, "Location successfully set"); + + return 0; +} + +static int set_pacs_supported_contexts(void) +{ + esp_err_t err; + + if (IS_ENABLED(CONFIG_BT_PAC_SNK)) { + err = esp_ble_audio_pacs_set_supported_contexts(ESP_BLE_AUDIO_DIR_SINK, SINK_CONTEXT); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to set sink supported contexts (err %d)", err); + return -1; + } + } + + if (IS_ENABLED(CONFIG_BT_PAC_SRC)) { + err = esp_ble_audio_pacs_set_supported_contexts(ESP_BLE_AUDIO_DIR_SOURCE, SOURCE_CONTEXT); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to set source supported contexts (err %d)", err); + return -1; + } + } + + ESP_LOGI(TAG, "Supported contexts successfully set"); + + return 0; +} + +static int set_pacs_available_contexts(void) +{ + esp_err_t err; + + if (IS_ENABLED(CONFIG_BT_PAC_SNK)) { + err = esp_ble_audio_pacs_set_available_contexts(ESP_BLE_AUDIO_DIR_SINK, SINK_CONTEXT); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to set sink available contexts (err %d)", err); + return -1; + } + } + + if (IS_ENABLED(CONFIG_BT_PAC_SRC)) { + err = esp_ble_audio_pacs_set_available_contexts(ESP_BLE_AUDIO_DIR_SOURCE, SOURCE_CONTEXT); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to set source available contexts (err %d)", err); + return -1; + } + } + + ESP_LOGI(TAG, "Available contexts successfully set"); + + return 0; +} + +static void build_adv_data(void) +{ + size_t idx = 0; + + /* Flags */ + ext_adv_data[idx++] = 0x02; + ext_adv_data[idx++] = EXAMPLE_AD_TYPE_FLAGS; + ext_adv_data[idx++] = EXAMPLE_AD_FLAGS_GENERAL | EXAMPLE_AD_FLAGS_NO_BREDR; + + /* Incomplete List of 16-bit Service UUIDs */ + ext_adv_data[idx++] = 0x03; + ext_adv_data[idx++] = EXAMPLE_AD_TYPE_UUID16_SOME; + ext_adv_data[idx++] = (ESP_BLE_AUDIO_UUID_ASCS_VAL & 0xFF); + ext_adv_data[idx++] = ((ESP_BLE_AUDIO_UUID_ASCS_VAL >> 8) & 0xFF); + + /* Service Data - 16-bit UUID */ + ext_adv_data[idx++] = 0x09; + ext_adv_data[idx++] = EXAMPLE_AD_TYPE_SERVICE_DATA16; + ext_adv_data[idx++] = (ESP_BLE_AUDIO_UUID_ASCS_VAL & 0xFF); + ext_adv_data[idx++] = ((ESP_BLE_AUDIO_UUID_ASCS_VAL >> 8) & 0xFF); + ext_adv_data[idx++] = ESP_BLE_AUDIO_UNICAST_ANNOUNCEMENT_TARGETED; + ext_adv_data[idx++] = (SINK_CONTEXT & 0xFF); + ext_adv_data[idx++] = ((SINK_CONTEXT >> 8) & 0xFF); + ext_adv_data[idx++] = (SOURCE_CONTEXT & 0xFF); + ext_adv_data[idx++] = ((SOURCE_CONTEXT >> 8) & 0xFF); + ext_adv_data[idx++] = 0x00; /* Metadata length */ + + /* Complete Device Name */ + ext_adv_data[idx++] = LOCAL_DEVICE_NAME_LEN + 1; + ext_adv_data[idx++] = EXAMPLE_AD_TYPE_NAME_COMPLETE; + memcpy(&ext_adv_data[idx], LOCAL_DEVICE_NAME, LOCAL_DEVICE_NAME_LEN); +} + +static void ext_adv_start(void) +{ + struct ble_gap_ext_adv_params ext_params = {0}; + struct os_mbuf *data = NULL; + int err; + + build_adv_data(); + + ext_params.connectable = 1; + ext_params.scannable = 0; + ext_params.legacy_pdu = 0; + ext_params.own_addr_type = ADV_ADDRESS; + ext_params.primary_phy = ADV_PRIMARY_PHY; + ext_params.secondary_phy = ADV_SECONDARY_PHY; + ext_params.tx_power = ADV_TX_POWER; + ext_params.sid = ADV_SID; + ext_params.itvl_min = ADV_INTERVAL; + ext_params.itvl_max = ADV_INTERVAL; + + err = ble_gap_ext_adv_configure(ADV_HANDLE, &ext_params, NULL, + example_audio_gap_event_cb, NULL); + if (err) { + ESP_LOGE(TAG, "Failed to configure ext adv params, err %d", err); + return; + } + + data = os_msys_get_pkthdr(sizeof(ext_adv_data), 0); + if (data == NULL) { + ESP_LOGE(TAG, "Failed to get ext adv mbuf"); + return; + } + + err = os_mbuf_append(data, ext_adv_data, sizeof(ext_adv_data)); + if (err) { + ESP_LOGE(TAG, "Failed to append ext adv data, err %d", err); + os_mbuf_free_chain(data); + return; + } + + err = ble_gap_ext_adv_set_data(ADV_HANDLE, data); + if (err) { + ESP_LOGE(TAG, "Failed to set ext adv data, err %d", err); + return; + } + + err = ble_gap_ext_adv_start(ADV_HANDLE, 0, 0); + if (err) { + ESP_LOGE(TAG, "Failed to start ext advertising, err %d", err); + return; + } + + ESP_LOGI(TAG, "Extended adv instance %u started", ADV_HANDLE); +} + +static void acl_connect(esp_ble_audio_gap_app_event_t *event) +{ + if (event->acl_connect.status) { + ESP_LOGE(TAG, "connection failed, status %d", event->acl_connect.status); + return; + } + + ESP_LOGI(TAG, "Conn established:"); + ESP_LOGI(TAG, "conn_handle 0x%04x status 0x%02x role %u peer %02x:%02x:%02x:%02x:%02x:%02x", + event->acl_connect.conn_handle, event->acl_connect.status, + event->acl_connect.role, event->acl_connect.dst.val[5], + event->acl_connect.dst.val[4], event->acl_connect.dst.val[3], + event->acl_connect.dst.val[2], event->acl_connect.dst.val[1], + event->acl_connect.dst.val[0]); +} + +static void acl_disconnect(esp_ble_audio_gap_app_event_t *event) +{ + ESP_LOGI(TAG, "Conn terminated: conn_handle 0x%04x reason 0x%02x", + event->acl_disconnect.conn_handle, event->acl_disconnect.reason); + + ext_adv_start(); +} + +static void iso_gap_app_cb(esp_ble_audio_gap_app_event_t *event) +{ + switch (event->type) { + case ESP_BLE_AUDIO_GAP_EVENT_ACL_CONNECT: + acl_connect(event); + break; + case ESP_BLE_AUDIO_GAP_EVENT_ACL_DISCONNECT: + acl_disconnect(event); + break; + default: + break; + } +} + +static void gatt_mtu_change(esp_ble_audio_gatt_app_event_t *event) +{ + int err; + + ESP_LOGI(TAG, "gatt mtu change, conn_handle %u, mtu %u", + event->gatt_mtu_change.conn_handle, event->gatt_mtu_change.mtu); + + if (event->gatt_mtu_change.mtu < ESP_BLE_AUDIO_ATT_MTU_MIN) { + ESP_LOGW(TAG, "Invalid new mtu %u, shall be at least %u", + event->gatt_mtu_change.mtu, ESP_BLE_AUDIO_ATT_MTU_MIN); + return; + } + + /* This function only needs to be invoked when: + * - The device is a Peripheral (Link Layer role); + * - The device works as a GATT client. + */ + err = esp_ble_audio_gattc_disc_start(event->gatt_mtu_change.conn_handle); + if (err) { + ESP_LOGE(TAG, "Failed to start svc disc, err %d", err); + return; + } + + ESP_LOGI(TAG, "Start discovering gatt services"); +} + +static void gattc_disc_cmpl(esp_ble_audio_gatt_app_event_t *event) +{ + ESP_LOGI(TAG, "gattc disc cmpl, status %u, conn_handle %u", + event->gattc_disc_cmpl.status, event->gattc_disc_cmpl.conn_handle); +} + +static void iso_gatt_app_cb(esp_ble_audio_gatt_app_event_t *event) +{ + switch (event->type) { + case ESP_BLE_AUDIO_GATT_EVENT_GATT_MTU_CHANGE: + gatt_mtu_change(event); + break; + case ESP_BLE_AUDIO_GATT_EVENT_GATTC_DISC_CMPL: + gattc_disc_cmpl(event); + break; + default: + break; + } +} + +void app_main(void) +{ + const esp_ble_audio_pacs_register_param_t pacs_param = { + .snk_pac = true, + .snk_loc = true, + .src_pac = true, + .src_loc = true, + }; + esp_ble_audio_init_info_t info = { + .gap_cb = iso_gap_app_cb, + .gatt_cb = iso_gatt_app_cb, + }; + esp_err_t err; + + /* Initialize NVS — it is used to store PHY calibration data */ + err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK(err); + + err = bluetooth_init(); + if (err) { + ESP_LOGE(TAG, "Failed to initialize BLE, err %d", err); + return; + } + + err = esp_ble_audio_common_init(&info); + if (err) { + ESP_LOGE(TAG, "Failed to initialize audio, err %d", err); + return; + } + + err = esp_ble_audio_pacs_register(&pacs_param); + if (err) { + ESP_LOGE(TAG, "Failed to register pacs, err %d", err); + return; + } + + err = esp_ble_audio_bap_unicast_server_register(¶m); + if (err) { + ESP_LOGE(TAG, "Failed to register unicast server, err %d", err); + return; + } + + err = esp_ble_audio_bap_unicast_server_register_cb(&unicast_server_cb); + if (err) { + ESP_LOGE(TAG, "Failed to register unicast server callbacks, err %d", err); + return; + } + + err = esp_ble_audio_pacs_cap_register(ESP_BLE_AUDIO_DIR_SINK, &cap_sink); + if (err) { + ESP_LOGE(TAG, "Failed to register pacs capabilities, err %d", err); + return; + } + + err = esp_ble_audio_pacs_cap_register(ESP_BLE_AUDIO_DIR_SOURCE, &cap_source); + if (err) { + ESP_LOGE(TAG, "Failed to register pacs capabilities, err %d", err); + return; + } + + for (size_t i = 0; i < ARRAY_SIZE(sink_streams); i++) { + esp_ble_audio_bap_stream_cb_register(&sink_streams[i].stream, &stream_ops); + } + + for (size_t i = 0; i < ARRAY_SIZE(source_streams); i++) { + esp_ble_audio_bap_stream_cb_register(&source_streams[i].stream, &stream_ops); + } + + err = set_pacs_location(); + if (err) { + return; + } + + err = set_pacs_supported_contexts(); + if (err) { + return; + } + + err = set_pacs_available_contexts(); + if (err) { + return; + } + + err = esp_ble_audio_common_start(NULL); + if (err) { + ESP_LOGE(TAG, "Failed to start audio, err %d", err); + return; + } + + err = ble_svc_gap_device_name_set(LOCAL_DEVICE_NAME); + if (err) { + ESP_LOGE(TAG, "Failed to set device name, err %d", err); + return; + } + + ext_adv_start(); +} diff --git a/examples/bluetooth/esp_ble_audio/bap/unicast_server/sdkconfig.defaults b/examples/bluetooth/esp_ble_audio/bap/unicast_server/sdkconfig.defaults new file mode 100644 index 0000000000..a81ac77b51 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/bap/unicast_server/sdkconfig.defaults @@ -0,0 +1,26 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration +# + +CONFIG_BT_ENABLED=y +CONFIG_BT_BLUEDROID_ENABLED=n +CONFIG_BT_NIMBLE_ENABLED=y +CONFIG_BT_NIMBLE_EXT_ADV=y +CONFIG_BT_NIMBLE_MAX_CONNECTIONS=1 +CONFIG_BT_NIMBLE_MAX_CCCDS=20 +CONFIG_BT_NIMBLE_ISO=y +CONFIG_BT_NIMBLE_LOG_LEVEL_WARNING=y + +CONFIG_BT_ISO_MAX_CHAN=2 + +CONFIG_BT_ASCS_MAX_ACTIVE_ASES=4 +CONFIG_BT_BAP_UNICAST_SERVER=y +CONFIG_BT_PAC_SNK_NOTIFIABLE=y +CONFIG_BT_PAC_SNK_LOC_WRITEABLE=y +CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE=y +CONFIG_BT_PAC_SRC_NOTIFIABLE=y +CONFIG_BT_PAC_SRC_LOC_WRITEABLE=y +CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE=y +CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE=y + +CONFIG_FREERTOS_HZ=1000 diff --git a/examples/bluetooth/esp_ble_audio/bap/unicast_server/sdkconfig.defaults.esp32h4 b/examples/bluetooth/esp_ble_audio/bap/unicast_server/sdkconfig.defaults.esp32h4 new file mode 100644 index 0000000000..5920ce3f85 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/bap/unicast_server/sdkconfig.defaults.esp32h4 @@ -0,0 +1,6 @@ +# Override some defaults so BT stack is enabled +# by default in this example + +CONFIG_IDF_TARGET="esp32h4" + +CONFIG_BT_LE_ISO_SUPPORT=y diff --git a/examples/bluetooth/esp_ble_audio/cap/acceptor/CMakeLists.txt b/examples/bluetooth/esp_ble_audio/cap/acceptor/CMakeLists.txt new file mode 100644 index 0000000000..c3c1300d8d --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/cap/acceptor/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.22) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +idf_build_set_property(MINIMAL_BUILD ON) +project(cap_acceptor) diff --git a/examples/bluetooth/esp_ble_audio/cap/acceptor/README.md b/examples/bluetooth/esp_ble_audio/cap/acceptor/README.md new file mode 100644 index 0000000000..f6fa9c8d5a --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/cap/acceptor/README.md @@ -0,0 +1,76 @@ +| Supported Targets | ESP32-H4 | +| ----------------- | -------- | + +# CAP Acceptor Example + +(See the README.md file in the upper level `examples` directory for more information about examples.) + +This example demonstrates the **Common Audio Profile (CAP) Acceptor** functionality. It advertises so that a CAP Initiator can connect and set up available audio streams. The acceptor operates in one of two mutually exclusive modes selected at build time: as a **BAP Unicast Server** (unicast mode, for use with a CAP Initiator) or as a **BAP Broadcast Sink** (broadcast mode). In broadcast mode, it can be configured to scan for broadcast sources by itself, or to wait for a Broadcast Assistant to connect and direct the sync. Run it together with the [initiator](../initiator) example on another device as the CAP Initiator. + +The implementation uses the NimBLE host stack with ISO and LE Audio support, ESP-BLE-AUDIO (PACS, CAP acceptor, BAP unicast server, BAP broadcast sink, BAP scan delegator). Advertising includes the CAS (Common Audio Service) UUID and service data; when unicast is enabled it also advertises ASCS with targeted announcement and sink/source contexts; when broadcast is enabled it can include BASS (Broadcast Assistant) service data. PACS advertises LC3 sink and source capabilities (e.g. 7.5 ms / 10 ms frame, stereo, multiple contexts). The example supports optional Kconfig: unicast, broadcast, self-scan for broadcast sources, device name, and (when self-scan) target broadcast device name and broadcast code. + +## Requirements + +* A board with Bluetooth LE 5.2, ISO, and LE Audio support (e.g. ESP32-H4) +* Optionally, another device running the [initiator](../initiator) example as CAP Initiator (for unicast and/or as Broadcast Assistant) + +## How to Use Example + +Before project configuration and build, set the correct chip target: + +```bash +idf.py set-target esp32h4 +``` + +### Configure the Project + +Open the configuration menu to select the mode: + +```bash +idf.py menuconfig +``` + +Under **Example: CAP Acceptor**, select one of: + +* **Unicast** — act as a BAP Unicast Server; start connectable advertising for a CAP Initiator +* **Broadcast** — act as a BAP Broadcast Sink; receive broadcast audio. When this mode is selected, you can additionally enable: + * **Scan for Broadcast Sources without Broadcast Assistant** — start scanning for broadcast sources independently, without waiting for a Broadcast Assistant to connect + +### Build and Flash + +Run the following to build, flash and monitor: + +```bash +idf.py -p PORT flash monitor +``` + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the [Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF. + +## Example Flow + +1. **Initialization**: NVS, Bluetooth stack, and LE Audio common layer (`esp_ble_audio_common_init`) with GAP and GATT callbacks. Register PACS (sink and source PAC and location), register sink and source capabilities (LC3), set PACS location and supported/available contexts (`init_cap_acceptor`). In unicast mode, initialize the CAP acceptor unicast part (BAP unicast server, stream alloc/release). In broadcast mode, initialize the CAP acceptor broadcast part (BAP broadcast sink, scan delegator). Start the audio stack and set the device name. +2. **Scan (optional)**: In broadcast mode with self-scan enabled, start scanning for broadcast sources before or in addition to advertising. +3. **Advertising**: Start connectable extended advertising with flags, CAS service data, and additionally ASCS service data in unicast mode or BASS service data in broadcast mode, plus device name (`cap_acceptor`). +4. **Initiator connection (unicast mode)**: When a CAP Initiator connects, the peer connection handle is stored. On MTU exchange the acceptor may start GATT service discovery. The initiator discovers ASEs and sets up unicast streams; the acceptor allocates streams and reports stream released when appropriate. +5. **Broadcast (broadcast mode)**: On PA sync events the acceptor syncs to the broadcast stream; on PA sync lost it handles disconnection. With self-scan, scan results are processed to sync to the chosen broadcast source. + +## Example Output + +``` +I (xxx) CAP_ACC: Extended adv instance 0 started +I (xxx) CAP_ACC: connection established, status 0 +I (xxx) CAP_ACC: gatt mtu change, conn_handle 1, mtu ... +... +I (xxx) CAP_ACC: PA synced, handle 0x... status 0x00 +... +I (xxx) CAP_ACC: Sink stream released +``` + +If the connection is lost: + +``` +I (xxx) CAP_ACC: connection disconnected, reason 0x... +I (xxx) CAP_ACC: PA sync lost, handle 0x... reason ... +``` diff --git a/examples/bluetooth/esp_ble_audio/cap/acceptor/main/CMakeLists.txt b/examples/bluetooth/esp_ble_audio/cap/acceptor/main/CMakeLists.txt new file mode 100644 index 0000000000..fa2da09904 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/cap/acceptor/main/CMakeLists.txt @@ -0,0 +1,12 @@ +set(srcs "main.c") + +if(CONFIG_EXAMPLE_UNICAST) + list(APPEND srcs "cap_acceptor_unicast.c") +endif() + +if(CONFIG_EXAMPLE_BROADCAST) + list(APPEND srcs "cap_acceptor_broadcast.c") +endif() + +idf_component_register(SRCS "${srcs}" + REQUIRES bt nvs_flash) diff --git a/examples/bluetooth/esp_ble_audio/cap/acceptor/main/Kconfig.projbuild b/examples/bluetooth/esp_ble_audio/cap/acceptor/main/Kconfig.projbuild new file mode 100644 index 0000000000..599bcbb96f --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/cap/acceptor/main/Kconfig.projbuild @@ -0,0 +1,35 @@ +# SPDX-FileCopyrightText: 2022 Nordic Semiconductor ASA +# SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 + +menu "Example: CAP Acceptor" + + choice EXAMPLE_CAP_ACCEPTOR_MODE + prompt "CAP Acceptor mode" + default EXAMPLE_UNICAST + help + Select exactly one CAP acceptor mode. + + config EXAMPLE_UNICAST + bool "Unicast" + help + If selected, the sample will start advertising connectable + for Broadcast Assistants. + + config EXAMPLE_BROADCAST + bool "Broadcast" + help + If selected, the sample will start advertising syncable + audio streams. + + endchoice + + if EXAMPLE_BROADCAST + config EXAMPLE_SCAN_SELF + bool "Scan for Broadcast Sources without Broadcast Assistant" + help + If set to true, the sample will start scanning for Broadcast + Sources without waiting for a Broadcast Assistant to connect. + endif + +endmenu diff --git a/examples/bluetooth/esp_ble_audio/cap/acceptor/main/cap_acceptor.h b/examples/bluetooth/esp_ble_audio/cap/acceptor/main/cap_acceptor.h new file mode 100644 index 0000000000..a2ad0940f0 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/cap/acceptor/main/cap_acceptor.h @@ -0,0 +1,60 @@ +/* + * SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_log.h" + +#include "sdkconfig.h" + +#include "host/ble_hs.h" +#include "services/gap/ble_svc_gap.h" + +#include "esp_ble_audio_lc3_defs.h" +#include "esp_ble_audio_cap_api.h" +#include "esp_ble_audio_pacs_api.h" + +#include "ble_audio_example_init.h" +#include "ble_audio_example_utils.h" + +#define TAG "CAP_ACC" + +#define CONN_HANDLE_INIT 0xFFFF + +#define SINK_CONTEXT (ESP_BLE_AUDIO_CONTEXT_TYPE_UNSPECIFIED | \ + ESP_BLE_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | \ + ESP_BLE_AUDIO_CONTEXT_TYPE_MEDIA | \ + ESP_BLE_AUDIO_CONTEXT_TYPE_GAME | \ + ESP_BLE_AUDIO_CONTEXT_TYPE_INSTRUCTIONAL) +#define SOURCE_CONTEXT (ESP_BLE_AUDIO_CONTEXT_TYPE_UNSPECIFIED | \ + ESP_BLE_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | \ + ESP_BLE_AUDIO_CONTEXT_TYPE_MEDIA | \ + ESP_BLE_AUDIO_CONTEXT_TYPE_GAME) + +struct peer_config { + esp_ble_audio_cap_stream_t source_stream; + esp_ble_audio_cap_stream_t sink_stream; + uint16_t conn_handle; +}; + +int cap_acceptor_unicast_init(struct peer_config *peer); + +int cap_acceptor_broadcast_init(void); + +esp_ble_audio_cap_stream_t *stream_alloc(esp_ble_audio_dir_t dir); + +void stream_released(const esp_ble_audio_cap_stream_t *cap_stream); + +#if CONFIG_EXAMPLE_BROADCAST +#if CONFIG_EXAMPLE_SCAN_SELF +int check_start_scan(void); + +void broadcast_scan_recv(esp_ble_audio_gap_app_event_t *event); +#endif /* CONFIG_EXAMPLE_SCAN_SELF */ + +void broadcast_pa_synced(esp_ble_audio_gap_app_event_t *event); + +void broadcast_pa_lost(esp_ble_audio_gap_app_event_t *event); +#endif /* CONFIG_EXAMPLE_BROADCAST */ diff --git a/examples/bluetooth/esp_ble_audio/cap/acceptor/main/cap_acceptor_broadcast.c b/examples/bluetooth/esp_ble_audio/cap/acceptor/main/cap_acceptor_broadcast.c new file mode 100644 index 0000000000..05aa7ef3e5 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/cap/acceptor/main/cap_acceptor_broadcast.c @@ -0,0 +1,707 @@ +/* + * SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include "cap_acceptor.h" + +#if CONFIG_EXAMPLE_SCAN_SELF +#define TARGET_DEVICE_NAME "CAP Broadcast Source" +#define TARGET_DEVICE_NAME_LEN (sizeof(TARGET_DEVICE_NAME) - 1) +#define TARGET_BROADCAST_CODE "1234" + +#define SCAN_INTERVAL 160 /* 100ms */ +#define SCAN_WINDOW 160 /* 100ms */ +#endif /* CONFIG_EXAMPLE_SCAN_SELF */ + +#define PA_SYNC_SKIP 0 +#define PA_SYNC_TIMEOUT 1000 /* 1000 * 10ms = 10s */ +#define PA_SYNC_HANDLE_INIT UINT16_MAX + +enum broadcast_flag { + FLAG_BROADCAST_SYNC_REQUESTED, + FLAG_BROADCAST_CODE_REQUIRED, + FLAG_BROADCAST_CODE_RECEIVED, + FLAG_BROADCAST_SYNCABLE, + FLAG_BROADCAST_SYNCING, + FLAG_BROADCAST_SYNCED, + FLAG_BASE_RECEIVED, + FLAG_PA_SYNCING, + FLAG_PA_SYNCED, + FLAG_SCANNING, + FLAG_NUM, +}; +ATOMIC_DEFINE(flags, FLAG_NUM); + +static struct broadcast_sink { + const esp_ble_audio_bap_scan_delegator_recv_state_t *recv_state; + uint8_t broadcast_code[ESP_BLE_ISO_BROADCAST_CODE_SIZE]; + esp_ble_audio_bap_broadcast_sink_t *sink; + esp_ble_audio_cap_stream_t cap_stream; + uint8_t received_base[UINT8_MAX]; + uint32_t requested_bis_sync; + uint32_t broadcast_id; + uint16_t sync_handle; +} broadcast_sink = { + .sync_handle = PA_SYNC_HANDLE_INIT, +}; + +static example_audio_rx_metrics_t rx_metrics; + +static int pa_sync_create(const bt_addr_le_t *addr, uint8_t adv_sid) +{ + struct ble_gap_periodic_sync_params params = {0}; + ble_addr_t sync_addr = {0}; + + sync_addr.type = addr->type; + memcpy(sync_addr.val, addr->a.val, sizeof(sync_addr.val)); + params.skip = PA_SYNC_SKIP; + params.sync_timeout = PA_SYNC_TIMEOUT; + + return ble_gap_periodic_adv_sync_create(&sync_addr, adv_sid, ¶ms, + example_audio_gap_event_cb, NULL); +} + +static int pa_sync_terminate(void) +{ + int err; + + err = ble_gap_periodic_adv_sync_terminate(broadcast_sink.sync_handle); + if (err) { + ESP_LOGE(TAG, "Failed to terminate PA sync, err %d", err); + } + + return err; +} + +#if CONFIG_EXAMPLE_SCAN_SELF +static int ext_scan_start(void) +{ + struct ble_gap_disc_params params = {0}; + uint8_t own_addr_type; + int err; + + err = ble_hs_id_infer_auto(0, &own_addr_type); + if (err) { + ESP_LOGE(TAG, "Failed to determine own addr type, err %d", err); + return err; + } + + params.passive = 1; + params.itvl = SCAN_INTERVAL; + params.window = SCAN_WINDOW; + + err = ble_gap_disc(own_addr_type, BLE_HS_FOREVER, ¶ms, + example_audio_gap_event_cb, NULL); + if (err) { + ESP_LOGE(TAG, "Failed to start scanning, err %d", err); + return err; + } + + ESP_LOGI(TAG, "Extended scan started"); + return 0; +} + +static int ext_scan_stop(void) +{ + return ble_gap_disc_cancel(); +} + +int check_start_scan(void) +{ + int err; + + if (atomic_test_bit(flags, FLAG_SCANNING)) { + ESP_LOGW(TAG, "FLAG_SCANNING"); + return -EALREADY; + } + + if (atomic_test_bit(flags, FLAG_PA_SYNCED)) { + ESP_LOGW(TAG, "FLAG_PA_SYNCED"); + return -EALREADY; + } + + if (atomic_test_bit(flags, FLAG_BROADCAST_SYNCED)) { + ESP_LOGW(TAG, "FLAG_BROADCAST_SYNCED"); + return -EALREADY; + } + + err = ext_scan_start(); + if (err) { + return err; + } + + atomic_set_bit(flags, FLAG_SCANNING); + + return 0; +} +#endif /* CONFIG_EXAMPLE_SCAN_SELF */ + +static void broadcast_stream_started_cb(esp_ble_audio_bap_stream_t *stream) +{ + ESP_LOGI(TAG, "Broadcast stream %p started", stream); + + example_audio_rx_metrics_reset(&rx_metrics); + + atomic_clear_bit(flags, FLAG_BROADCAST_SYNCING); + atomic_set_bit(flags, FLAG_BROADCAST_SYNCED); +} + +static void broadcast_stream_stopped_cb(esp_ble_audio_bap_stream_t *stream, uint8_t reason) +{ + ESP_LOGI(TAG, "Broadcast stream %p stopped, reason 0x%02x", stream, reason); + + atomic_clear_bit(flags, FLAG_BROADCAST_SYNCING); + atomic_clear_bit(flags, FLAG_BROADCAST_SYNCED); + +#if CONFIG_EXAMPLE_SCAN_SELF + check_start_scan(); +#endif /* CONFIG_EXAMPLE_SCAN_SELF */ +} + +static void broadcast_stream_recv_cb(esp_ble_audio_bap_stream_t *stream, + const esp_ble_iso_recv_info_t *info, + const uint8_t *data, uint16_t len) +{ + + rx_metrics.last_sdu_len = len; + example_audio_rx_metrics_on_recv(info, &rx_metrics, TAG, "stream", stream); +} + +static int create_broadcast_sink(void) +{ + int err; + + if (broadcast_sink.sink) { + return -EALREADY; + } + + ESP_LOGI(TAG, "Creating broadcast sink for broadcast ID 0x%06X", + broadcast_sink.broadcast_id); + + err = esp_ble_audio_bap_broadcast_sink_create(broadcast_sink.sync_handle, + broadcast_sink.broadcast_id, + &broadcast_sink.sink); + if (err) { + ESP_LOGE(TAG, "Failed to create broadcast sink, err %d", err); + return err; + } + + return 0; +} + +static void check_sync_broadcast(void) +{ + esp_ble_audio_bap_stream_t *sync_stream = &broadcast_sink.cap_stream.bap_stream; + uint32_t sync_bitfield; + int err; + + if (atomic_test_bit(flags, FLAG_BASE_RECEIVED) == false) { + ESP_LOGI(TAG, "FLAG_BASE_RECEIVED"); + return; + } + + if (atomic_test_bit(flags, FLAG_BROADCAST_SYNCABLE) == false) { + ESP_LOGI(TAG, "FLAG_BROADCAST_SYNCABLE"); + return; + } + + if (atomic_test_bit(flags, FLAG_BROADCAST_CODE_REQUIRED) && + atomic_test_bit(flags, FLAG_BROADCAST_CODE_RECEIVED) == false) { + ESP_LOGI(TAG, "FLAG_BROADCAST_CODE_REQUIRED"); + return; + } + + if (atomic_test_bit(flags, FLAG_BROADCAST_SYNC_REQUESTED) == false) { + ESP_LOGI(TAG, "FLAG_BROADCAST_SYNC_REQUESTED"); + return; + } + + if (atomic_test_bit(flags, FLAG_PA_SYNCED) == false) { + ESP_LOGI(TAG, "FLAG_PA_SYNCED"); + return; + } + + if (atomic_test_bit(flags, FLAG_BROADCAST_SYNCED) || + atomic_test_bit(flags, FLAG_BROADCAST_SYNCING)) { + ESP_LOGI(TAG, "FLAG_BROADCAST_SYNCED"); + return; + } + + if (broadcast_sink.requested_bis_sync == ESP_BLE_AUDIO_BAP_BIS_SYNC_NO_PREF) { + uint32_t base_bis; + + /* Get the first BIS index from the BASE */ + err = esp_ble_audio_bap_base_get_bis_indexes( + (esp_ble_audio_bap_base_t *)broadcast_sink.received_base, &base_bis); + if (err) { + ESP_LOGE(TAG, "Failed to get BIS indexes from BASE, err %d", err); + return; + } + + sync_bitfield = 0; + + for (uint8_t i = ESP_BLE_ISO_BIS_INDEX_MIN; i <= ESP_BLE_ISO_BIS_INDEX_MAX; i++) { + if (base_bis & ESP_BLE_ISO_BIS_INDEX_BIT(i)) { + sync_bitfield = ESP_BLE_ISO_BIS_INDEX_BIT(i); + break; + } + } + + if (sync_bitfield == 0) { + ESP_LOGE(TAG, "No valid BIS index found in BASE"); + return; + } + } else { + sync_bitfield = broadcast_sink.requested_bis_sync; + } + + ESP_LOGI(TAG, "Syncing to broadcast with bitfield 0x%08X", sync_bitfield); + + /* Sync the BIG */ + err = esp_ble_audio_bap_broadcast_sink_sync(broadcast_sink.sink, + sync_bitfield, &sync_stream, + broadcast_sink.broadcast_code); + if (err) { + ESP_LOGE(TAG, "Failed to sync the broadcast sink, err %d", err); + return; + } + + atomic_set_bit(flags, FLAG_BROADCAST_SYNCING); +} + +static void base_recv_cb(esp_ble_audio_bap_broadcast_sink_t *sink, + const esp_ble_audio_bap_base_t *base, + size_t base_size) +{ + if (base_size > sizeof(broadcast_sink.received_base)) { + ESP_LOGE(TAG, "Too large BASE (%u > %u)", + base_size, sizeof(broadcast_sink.received_base)); + return; + } + + memcpy(broadcast_sink.received_base, base, base_size); + + if (!atomic_test_and_set_bit(flags, FLAG_BASE_RECEIVED)) { + ESP_LOGI(TAG, "BASE received"); + + check_sync_broadcast(); + } +} + +static void syncable_cb(esp_ble_audio_bap_broadcast_sink_t *sink, + const esp_ble_iso_biginfo_t *biginfo) +{ + if (biginfo->encryption == false) { + atomic_clear_bit(flags, FLAG_BROADCAST_CODE_REQUIRED); + } else { + atomic_set_bit(flags, FLAG_BROADCAST_CODE_REQUIRED); + +#if CONFIG_EXAMPLE_SCAN_SELF + /* If self-scanning is enabled, local broadcast code will be used */ + memset(broadcast_sink.broadcast_code, 0, ESP_BLE_ISO_BROADCAST_CODE_SIZE); + memcpy(broadcast_sink.broadcast_code, TARGET_BROADCAST_CODE, + MIN(ESP_BLE_ISO_BROADCAST_CODE_SIZE, strlen(TARGET_BROADCAST_CODE))); + + atomic_set_bit(flags, FLAG_BROADCAST_CODE_RECEIVED); +#endif /* CONFIG_EXAMPLE_SCAN_SELF */ + } + + if (!atomic_test_and_set_bit(flags, FLAG_BROADCAST_SYNCABLE)) { + ESP_LOGI(TAG, "BIGInfo received"); + + check_sync_broadcast(); + } +} + +static int pa_sync_without_past(const bt_addr_le_t *addr, uint8_t adv_sid) +{ + int err; + + err = pa_sync_create(addr, adv_sid); + if (err) { + ESP_LOGE(TAG, "Failed to create PA sync without past, err %d", err); + } + + return err; +} + +static void recv_state_updated_cb(esp_ble_conn_t *conn, + const esp_ble_audio_bap_scan_delegator_recv_state_t *recv_state) +{ + ESP_LOGI(TAG, "Receive state updated, pa_sync 0x%02x encrypt 0x%02x", + recv_state->pa_sync_state, recv_state->encrypt_state); + + for (uint8_t i = 0; i < recv_state->num_subgroups; i++) { + ESP_LOGI(TAG, "subgroup %d bis_sync: 0x%08x", i, recv_state->subgroups[i].bis_sync); + } + + if (recv_state->pa_sync_state == ESP_BLE_AUDIO_BAP_PA_STATE_SYNCED) { + broadcast_sink.recv_state = recv_state; + } +} + +static int pa_sync_req_cb(esp_ble_conn_t *conn, + const esp_ble_audio_bap_scan_delegator_recv_state_t *recv_state, + bool past_available, uint16_t pa_interval) +{ + int err; + + ESP_LOGI(TAG, "Received request to sync to PA (PAST %savailble): %u", + past_available ? "" : "not ", recv_state->pa_sync_state); + + broadcast_sink.recv_state = recv_state; + + if (recv_state->pa_sync_state == ESP_BLE_AUDIO_BAP_PA_STATE_SYNCED || + recv_state->pa_sync_state == ESP_BLE_AUDIO_BAP_PA_STATE_INFO_REQ || + broadcast_sink.sync_handle != PA_SYNC_HANDLE_INIT) { + /* Already syncing */ + ESP_LOGW(TAG, "Rejecting PA sync request"); + return -EALREADY; + } + + if (past_available) { + ESP_LOGW(TAG, "Currently not support PAST"); + return -ENOTSUP; + } else { + err = pa_sync_without_past(&recv_state->addr, recv_state->adv_sid); + if (err) { + return err; + } + + ESP_LOGI(TAG, "Syncing without PAST"); + } + + broadcast_sink.broadcast_id = recv_state->broadcast_id; + atomic_set_bit(flags, FLAG_PA_SYNCING); + + return 0; +} + +static int pa_sync_term_req_cb(esp_ble_conn_t *conn, + const esp_ble_audio_bap_scan_delegator_recv_state_t *recv_state) +{ + int err; + + ESP_LOGI(TAG, "Received request to terminate PA sync"); + + broadcast_sink.recv_state = recv_state; + + err = pa_sync_terminate(); + if (err) { + return -EIO; + } + + broadcast_sink.sync_handle = PA_SYNC_HANDLE_INIT; + + return 0; +} + +static void broadcast_code_cb(esp_ble_conn_t *conn, + const esp_ble_audio_bap_scan_delegator_recv_state_t *recv_state, + const uint8_t broadcast_code[ESP_BLE_ISO_BROADCAST_CODE_SIZE]) +{ + ESP_LOGI(TAG, "Broadcast code received for %p", recv_state); + + broadcast_sink.recv_state = recv_state; + + memcpy(broadcast_sink.broadcast_code, broadcast_code, + ESP_BLE_ISO_BROADCAST_CODE_SIZE); + + atomic_set_bit(flags, FLAG_BROADCAST_CODE_RECEIVED); +} + +static uint32_t get_req_bis_sync(const uint32_t bis_sync_req[CONFIG_BT_BAP_BASS_MAX_SUBGROUPS]) +{ + uint32_t bis_sync = 0; + + for (size_t i = 0; i < CONFIG_BT_BAP_BASS_MAX_SUBGROUPS; i++) { + bis_sync |= bis_sync_req[i]; + } + + return bis_sync; +} + +static int bis_sync_req_cb(esp_ble_conn_t *conn, + const esp_ble_audio_bap_scan_delegator_recv_state_t *recv_state, + const uint32_t bis_sync_req[CONFIG_BT_BAP_BASS_MAX_SUBGROUPS]) +{ + const uint32_t new_bis_sync_req = get_req_bis_sync(bis_sync_req); + esp_err_t err; + + ESP_LOGI(TAG, "BIS sync request received for %p: 0x%08lx", recv_state, bis_sync_req[0]); + + if (new_bis_sync_req != ESP_BLE_AUDIO_BAP_BIS_SYNC_NO_PREF && + __builtin_popcount(new_bis_sync_req) > 1) { + ESP_LOGW(TAG, "Rejecting BIS sync request for 0x%08lx as we do not support that", + new_bis_sync_req); + return -ENOTSUP; + } + + if (broadcast_sink.requested_bis_sync == new_bis_sync_req) { + return 0; /* no op */ + } + + if (atomic_test_bit(flags, FLAG_BROADCAST_SYNCED)) { + /* If the BIS sync request is received while we are already + * synced, it means that the requested BIS sync has changed. + */ + + /* The stream stopped callback will be called as part of this, + * and we do not need to wait for any events from the controller. + * Thus, when this returns, the broadcast sink is stopped. + */ + err = esp_ble_audio_bap_broadcast_sink_stop(broadcast_sink.sink); + if (err) { + ESP_LOGE(TAG, "Failed to stop Broadcast Sink, err %d", err); + return -EIO; + } + + err = esp_ble_audio_bap_broadcast_sink_delete(broadcast_sink.sink); + if (err) { + ESP_LOGE(TAG, "Failed to delete Broadcast Sink, err %d", err); + return -EIO; + } + + broadcast_sink.sink = NULL; + + atomic_clear_bit(flags, FLAG_BROADCAST_SYNCED); + } + + broadcast_sink.requested_bis_sync = new_bis_sync_req; + + if (broadcast_sink.requested_bis_sync != 0) { + atomic_set_bit(flags, FLAG_BROADCAST_SYNC_REQUESTED); + + check_sync_broadcast(); + } else { + atomic_clear_bit(flags, FLAG_BROADCAST_SYNC_REQUESTED); + } + + return 0; +} + +#if CONFIG_EXAMPLE_SCAN_SELF +struct scan_recv_data { + bool target_matched; + bool broadcast_id_found; + uint32_t broadcast_id; +}; + +static bool data_cb(uint8_t type, const uint8_t *data, + uint8_t data_len, void *user_data) +{ + struct scan_recv_data *sr = user_data; + uint16_t uuid; + + switch (type) { + case EXAMPLE_AD_TYPE_NAME_SHORTENED: + case EXAMPLE_AD_TYPE_NAME_COMPLETE: + case EXAMPLE_AD_TYPE_BROADCAST_NAME: + sr->target_matched = (data_len == TARGET_DEVICE_NAME_LEN) && + !memcmp(data, TARGET_DEVICE_NAME, TARGET_DEVICE_NAME_LEN); + if (!sr->target_matched) { + return false; + } + return true; + case EXAMPLE_AD_TYPE_SERVICE_DATA16: + if (data_len < ESP_BLE_AUDIO_UUID_SIZE_16 + ESP_BLE_AUDIO_BROADCAST_ID_SIZE) { + return true; + } + uuid = sys_get_le16(data); + if (uuid != ESP_BLE_AUDIO_UUID_BROADCAST_AUDIO_VAL) { + return true; + } + sr->broadcast_id = sys_get_le24(data + ESP_BLE_AUDIO_UUID_SIZE_16); + sr->broadcast_id_found = true; + return true; + default: + return true; + } +} + +void broadcast_scan_recv(esp_ble_audio_gap_app_event_t *event) +{ + struct scan_recv_data sr = {0}; + bt_addr_le_t addr; + int err; + + /* Periodic advertising interval. 0 if no periodic advertising. */ + if (event->ext_scan_recv.per_adv_itvl == 0) { + return; + } + + esp_ble_audio_data_parse(event->ext_scan_recv.data, + event->ext_scan_recv.data_len, + data_cb, &sr); + + if (!sr.target_matched || !sr.broadcast_id_found) { + return; + } + + if (atomic_test_bit(flags, FLAG_PA_SYNCING) == false && + broadcast_sink.recv_state == NULL) { + /* Since we are scanning ourselves, we consider this as + * broadcast sync has been requested. + */ + broadcast_sink.requested_bis_sync = ESP_BLE_AUDIO_BAP_BIS_SYNC_NO_PREF; + broadcast_sink.broadcast_id = sr.broadcast_id; + + addr.type = event->ext_scan_recv.addr.type; + memcpy(addr.a.val, event->ext_scan_recv.addr.val, sizeof(addr.a.val)); + + err = pa_sync_create(&addr, event->ext_scan_recv.sid); + if (err) { + ESP_LOGE(TAG, "Failed to create PA sync, err %d", err); + return; + } + + ESP_LOGI(TAG, "Syncing without PAST from scan"); + + atomic_set_bit(flags, FLAG_PA_SYNCING); + atomic_set_bit(flags, FLAG_BROADCAST_SYNC_REQUESTED); + } +} +#endif /* CONFIG_EXAMPLE_SCAN_SELF */ + +void broadcast_pa_synced(esp_ble_audio_gap_app_event_t *event) +{ + bt_addr_le_t addr = {0}; + int err; + + addr.type = event->pa_sync.addr.type; + memcpy(addr.a.val, event->pa_sync.addr.val, sizeof(addr.a.val)); + + if (broadcast_sink.sync_handle == PA_SYNC_HANDLE_INIT || + (broadcast_sink.recv_state && + broadcast_sink.recv_state->addr.type == addr.type && + memcmp(broadcast_sink.recv_state->addr.a.val, addr.a.val, sizeof(addr.a.val)) == 0 && + broadcast_sink.recv_state->adv_sid == event->pa_sync.sid)) { + ESP_LOGI(TAG, "PA sync %u synced for broadcast sink", event->pa_sync.sync_handle); + + if (broadcast_sink.sync_handle == PA_SYNC_HANDLE_INIT) { + broadcast_sink.sync_handle = event->pa_sync.sync_handle; + } + + atomic_set_bit(flags, FLAG_PA_SYNCED); + atomic_clear_bit(flags, FLAG_PA_SYNCING); + +#if CONFIG_EXAMPLE_SCAN_SELF + err = ext_scan_stop(); + if (err) { + ESP_LOGE(TAG, "Failed to stop scanning, err %d", err); + /* Continue anyway - scan stop failure should not block sink creation */ + } else { + atomic_clear_bit(flags, FLAG_SCANNING); + } +#endif /* CONFIG_EXAMPLE_SCAN_SELF */ + + err = create_broadcast_sink(); + if (err && err != -EALREADY) { + ESP_LOGE(TAG, "Failed to create broadcast sink, err %d", err); + return; + } + + check_sync_broadcast(); + } +} + +void broadcast_pa_lost(esp_ble_audio_gap_app_event_t *event) +{ + esp_err_t err; + + if (event->pa_sync_lost.sync_handle != broadcast_sink.sync_handle) { + return; + } + + if (broadcast_sink.recv_state) { + err = esp_ble_audio_bap_scan_delegator_set_pa_state(broadcast_sink.recv_state->src_id, + ESP_BLE_AUDIO_BAP_PA_STATE_NOT_SYNCED); + if (err) { + ESP_LOGE(TAG, "Failed to set PA state to ESP_BLE_AUDIO_BAP_PA_STATE_NOT_SYNCED, err %d", err); + } + + err = esp_ble_audio_bap_scan_delegator_rem_src(broadcast_sink.recv_state->src_id); + if (err) { + ESP_LOGE(TAG, "Failed to remove receive state source, err %d", err); + } + + if (broadcast_sink.sink) { + err = esp_ble_audio_bap_broadcast_sink_delete(broadcast_sink.sink); + if (err) { + ESP_LOGE(TAG, "Failed to delete broadcast sink, err %d", err); + } + } + } + + broadcast_sink.recv_state = NULL; + broadcast_sink.sink = NULL; + broadcast_sink.requested_bis_sync = 0; + broadcast_sink.sync_handle = PA_SYNC_HANDLE_INIT; + + atomic_clear_bit(flags, FLAG_BROADCAST_SYNCABLE); + atomic_clear_bit(flags, FLAG_BROADCAST_SYNCING); + atomic_clear_bit(flags, FLAG_BROADCAST_SYNCED); + atomic_clear_bit(flags, FLAG_PA_SYNCED); + atomic_clear_bit(flags, FLAG_PA_SYNCING); + atomic_clear_bit(flags, FLAG_BASE_RECEIVED); + atomic_clear_bit(flags, FLAG_BROADCAST_CODE_REQUIRED); + atomic_clear_bit(flags, FLAG_BROADCAST_CODE_RECEIVED); + atomic_clear_bit(flags, FLAG_BROADCAST_SYNC_REQUESTED); + +#if CONFIG_EXAMPLE_SCAN_SELF + check_start_scan(); +#endif /* CONFIG_EXAMPLE_SCAN_SELF */ +} + +int cap_acceptor_broadcast_init(void) +{ + static bool cbs_registered; + int err; + + if (cbs_registered == false) { + static esp_ble_audio_bap_scan_delegator_cb_t scan_delegator_cbs = { + .recv_state_updated = recv_state_updated_cb, + .pa_sync_req = pa_sync_req_cb, + .pa_sync_term_req = pa_sync_term_req_cb, + .broadcast_code = broadcast_code_cb, + .bis_sync_req = bis_sync_req_cb, + }; + static esp_ble_audio_bap_broadcast_sink_cb_t broadcast_sink_cbs = { + .base_recv = base_recv_cb, + .syncable = syncable_cb, + }; + static esp_ble_audio_bap_stream_ops_t broadcast_stream_ops = { + .started = broadcast_stream_started_cb, + .stopped = broadcast_stream_stopped_cb, + .recv = broadcast_stream_recv_cb, + }; + + err = esp_ble_audio_bap_scan_delegator_register(&scan_delegator_cbs); + if (err) { + ESP_LOGE(TAG, "Failed to register scan delegator callbacks, err %d", err); + return err; + } + + err = esp_ble_audio_bap_broadcast_sink_register_cb(&broadcast_sink_cbs); + if (err) { + ESP_LOGE(TAG, "Failed to register broadcast sink callbacks, err %d", err); + return err; + } + + esp_ble_audio_cap_stream_ops_register(&broadcast_sink.cap_stream, + &broadcast_stream_ops); + + cbs_registered = true; + } + + return 0; +} diff --git a/examples/bluetooth/esp_ble_audio/cap/acceptor/main/cap_acceptor_unicast.c b/examples/bluetooth/esp_ble_audio/cap/acceptor/main/cap_acceptor_unicast.c new file mode 100644 index 0000000000..c1453cecd5 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/cap/acceptor/main/cap_acceptor_unicast.c @@ -0,0 +1,476 @@ +/* + * SPDX-FileCopyrightText: 2021-2024 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2023 NXP + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "cap_acceptor.h" + +static const esp_ble_audio_bap_qos_cfg_pref_t qos_pref = + ESP_BLE_AUDIO_BAP_QOS_CFG_PREF(true, /* Unframed PDUs supported */ + ESP_BLE_ISO_PHY_2M, /* Preferred Target PHY */ + 2, /* Preferred Retransmission number */ + 20, /* Preferred Maximum Transport Latency (msec) */ + 20000, /* Minimum Presentation Delay (usec) */ + 40000, /* Maximum Presentation Delay (usec) */ + 20000, /* Preferred Minimum Presentation Delay (usec) */ + 40000); /* Preferred Maximum Presentation Delay (usec) */ + +static example_audio_rx_metrics_t rx_metrics; + +static example_audio_tx_scheduler_t tx_scheduler; +static uint16_t tx_seq_num; +static uint8_t *iso_data; + +static void unicast_server_tx(void); + +static void tx_scheduler_cb(void *arg) +{ + (void)arg; + unicast_server_tx(); +} + +static int config_cb(esp_ble_conn_t *conn, + const esp_ble_audio_bap_ep_t *ep, + esp_ble_audio_dir_t dir, + const esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_bap_stream_t **stream, + esp_ble_audio_bap_qos_cfg_pref_t *const pref, + esp_ble_audio_bap_ascs_rsp_t *rsp) +{ + esp_ble_audio_cap_stream_t *cap_stream; + + ESP_LOGI(TAG, "Config: conn %p ep %p dir %u", conn, ep, dir); + + example_print_codec_cfg(codec_cfg); + + cap_stream = stream_alloc(dir); + if (cap_stream == NULL) { + ESP_LOGE(TAG, "No streams available"); + + *rsp = ESP_BLE_AUDIO_BAP_ASCS_RSP(ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_NO_MEM, + ESP_BLE_AUDIO_BAP_ASCS_REASON_NONE); + return -ENOMEM; + } + + *stream = &cap_stream->bap_stream; + + ESP_LOGI(TAG, "Config stream %p", *stream); + + *pref = qos_pref; + + return 0; +} + +static int reconfig_cb(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_dir_t dir, + const esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_bap_qos_cfg_pref_t *const pref, + esp_ble_audio_bap_ascs_rsp_t *rsp) +{ + ESP_LOGI(TAG, "Reconfig: stream %p dir %u", stream, dir); + + example_print_codec_cfg(codec_cfg); + + *pref = qos_pref; + + return 0; +} + +static int qos_cb(esp_ble_audio_bap_stream_t *stream, + const esp_ble_audio_bap_qos_cfg_t *qos, + esp_ble_audio_bap_ascs_rsp_t *rsp) +{ + ESP_LOGI(TAG, "QoS: stream %p qos %p", stream, qos); + + example_print_qos(qos); + + return 0; +} + +static int enable_cb(esp_ble_audio_bap_stream_t *stream, + const uint8_t meta[], size_t meta_len, + esp_ble_audio_bap_ascs_rsp_t *rsp) +{ + ESP_LOGI(TAG, "Enable: stream %p meta_len %u", stream, meta_len); + return 0; +} + +static int start_cb(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_bap_ascs_rsp_t *rsp) +{ + ESP_LOGI(TAG, "Start: stream %p", stream); + return 0; +} + +struct data_func_param { + esp_ble_audio_bap_ascs_rsp_t *rsp; + bool stream_context_present; +}; + +static bool data_func_cb(uint8_t type, const uint8_t *data, + uint8_t data_len, void *user_data) +{ + struct data_func_param *func_param = (struct data_func_param *)user_data; + + if (type == ESP_BLE_AUDIO_METADATA_TYPE_STREAM_CONTEXT) { + func_param->stream_context_present = true; + } + + return true; +} + +static int metadata_cb(esp_ble_audio_bap_stream_t *stream, + const uint8_t meta[], size_t meta_len, + esp_ble_audio_bap_ascs_rsp_t *rsp) +{ + struct data_func_param func_param = { + .rsp = rsp, + .stream_context_present = false, + }; + esp_err_t err; + + ESP_LOGI(TAG, "Metadata: stream %p meta_len %u", stream, meta_len); + + err = esp_ble_audio_data_parse(meta, meta_len, data_func_cb, &func_param); + if (err) { + *rsp = ESP_BLE_AUDIO_BAP_ASCS_RSP(ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_METADATA_REJECTED, + ESP_BLE_AUDIO_BAP_ASCS_REASON_NONE); + return -EIO; + } + + if (func_param.stream_context_present == false) { + ESP_LOGE(TAG, "Stream audio context not present"); + + *rsp = ESP_BLE_AUDIO_BAP_ASCS_RSP(ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_METADATA_REJECTED, + ESP_BLE_AUDIO_BAP_ASCS_REASON_NONE); + return -EINVAL; + } + + return 0; +} + +static int disable_cb(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_bap_ascs_rsp_t *rsp) +{ + ESP_LOGI(TAG, "Disable: stream %p", stream); + return 0; +} + +static int stop_cb(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_bap_ascs_rsp_t *rsp) +{ + ESP_LOGI(TAG, "Stop: stream %p", stream); + return 0; +} + +static int release_cb(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_bap_ascs_rsp_t *rsp) +{ + ESP_LOGI(TAG, "Release: stream %p", stream); + return 0; +} + +static const esp_ble_audio_bap_unicast_server_cb_t unicast_server_cb = { + .config = config_cb, + .reconfig = reconfig_cb, + .qos = qos_cb, + .enable = enable_cb, + .start = start_cb, + .metadata = metadata_cb, + .disable = disable_cb, + .stop = stop_cb, + .release = release_cb, +}; + +static void unicast_stream_configured_cb(esp_ble_audio_bap_stream_t *stream, + const esp_ble_audio_bap_qos_cfg_pref_t *pref) +{ + ESP_LOGI(TAG, "Unicast stream %p configured", stream); + + example_print_qos_pref(pref); +} + +static void unicast_stream_qos_set_cb(esp_ble_audio_bap_stream_t *stream) +{ + ESP_LOGI(TAG, "Unicast stream %p QoS set", stream); +} + +static void unicast_stream_enabled_cb(esp_ble_audio_bap_stream_t *stream) +{ + esp_ble_audio_bap_ep_info_t ep_info = {0}; + esp_err_t err; + + ESP_LOGI(TAG, "Unicast stream %p enabled", stream); + + err = esp_ble_audio_bap_ep_get_info(stream->ep, &ep_info); + if (err) { + ESP_LOGE(TAG, "Failed to get ep info, err %d", err); + return; + } + + ESP_LOGI(TAG, "id 0x%02x dir 0x%02x can_send %u can_recv %u", + ep_info.id, ep_info.dir, ep_info.can_send, ep_info.can_recv); + + if (ep_info.dir == ESP_BLE_AUDIO_DIR_SINK) { + /* Automatically do the receiver start ready operation */ + err = esp_ble_audio_bap_stream_start(stream); + if (err) { + ESP_LOGE(TAG, "Failed to start stream, err %d", err); + return; + } + } +} + +static void unicast_stream_started_cb(esp_ble_audio_bap_stream_t *stream) +{ + esp_ble_audio_bap_ep_info_t ep_info = {0}; + esp_err_t err; + + ESP_LOGI(TAG, "Unicast stream %p started", stream); + + example_audio_rx_metrics_reset(&rx_metrics); + + err = esp_ble_audio_bap_ep_get_info(stream->ep, &ep_info); + if (err) { + ESP_LOGE(TAG, "Failed to get ep info, err %d", err); + return; + } + + ESP_LOGI(TAG, "id 0x%02x dir 0x%02x can_send %u can_recv %u", + ep_info.id, ep_info.dir, ep_info.can_send, ep_info.can_recv); + + if (ep_info.dir == ESP_BLE_AUDIO_DIR_SOURCE) { + if (stream->qos == NULL || stream->qos->sdu == 0) { + ESP_LOGE(TAG, "Invalid stream qos"); + return; + } + + if (iso_data == NULL) { + iso_data = calloc(1, stream->qos->sdu); + if (iso_data == NULL) { + ESP_LOGE(TAG, "Failed to alloc TX buffer, SDU %u", stream->qos->sdu); + return; + } + } + + tx_seq_num = 0; + example_audio_tx_scheduler_reset(&tx_scheduler); + + err = example_audio_tx_scheduler_start(&tx_scheduler, stream->qos->interval); + if (err) { + ESP_LOGE(TAG, "Failed to start tx scheduler, err %d", err); + return; + } + + unicast_server_tx(); + } +} + +static void unicast_stream_metadata_updated_cb(esp_ble_audio_bap_stream_t *stream) +{ + ESP_LOGI(TAG, "Unicast stream %p metadata updated", stream); +} + +static void unicast_stream_disabled_cb(esp_ble_audio_bap_stream_t *stream) +{ + ESP_LOGI(TAG, "Unicast stream %p disabled", stream); +} + +static void unicast_stream_stopped_cb(esp_ble_audio_bap_stream_t *stream, uint8_t reason) +{ + esp_ble_audio_bap_ep_info_t ep_info = {0}; + esp_err_t err; + + ESP_LOGI(TAG, "Unicast stream %p stopped, reason 0x%02x", stream, reason); + + err = esp_ble_audio_bap_ep_get_info(stream->ep, &ep_info); + if (err) { + ESP_LOGE(TAG, "Failed to get ep info, err %d", err); + return; + } + + ESP_LOGI(TAG, "id 0x%02x dir 0x%02x can_send %u can_recv %u", + ep_info.id, ep_info.dir, ep_info.can_send, ep_info.can_recv); + + if (ep_info.dir == ESP_BLE_AUDIO_DIR_SOURCE) { + err = example_audio_tx_scheduler_stop(&tx_scheduler); + if (err) { + ESP_LOGE(TAG, "Failed to stop tx scheduler, err %d", err); + } + + if (iso_data != NULL) { + free(iso_data); + iso_data = NULL; + } + } +} + +static void unicast_stream_disconnected_cb(esp_ble_audio_bap_stream_t *stream, uint8_t reason) +{ + esp_ble_audio_bap_ep_info_t ep_info = {0}; + esp_err_t err; + + ESP_LOGI(TAG, "Unicast stream %p disconnected, reason 0x%02x", stream, reason); + + err = esp_ble_audio_bap_ep_get_info(stream->ep, &ep_info); + if (err) { + ESP_LOGE(TAG, "Failed to get ep info, err %d", err); + return; + } + + if (ep_info.dir == ESP_BLE_AUDIO_DIR_SOURCE) { + err = example_audio_tx_scheduler_stop(&tx_scheduler); + if (err) { + ESP_LOGE(TAG, "Failed to stop tx scheduler, err %d", err); + } + + if (iso_data != NULL) { + free(iso_data); + iso_data = NULL; + } + } +} + +static void unicast_stream_released_cb(esp_ble_audio_bap_stream_t *stream) +{ + esp_ble_audio_cap_stream_t *cap_stream = CONTAINER_OF(stream, + esp_ble_audio_cap_stream_t, + bap_stream); + + ESP_LOGI(TAG, "Unicast stream %p released", stream); + + stream_released(cap_stream); +} + +static void unicast_stream_recv_cb(esp_ble_audio_bap_stream_t *stream, + const esp_ble_iso_recv_info_t *info, + const uint8_t *data, uint16_t len) +{ + rx_metrics.last_sdu_len = len; + example_audio_rx_metrics_on_recv(info, &rx_metrics, TAG, "stream", stream); +} + +static void unicast_stream_sent_cb(esp_ble_audio_bap_stream_t *stream, void *user_data) +{ + example_audio_tx_scheduler_on_sent(&tx_scheduler, user_data, TAG, "stream", stream); +} + +static esp_ble_audio_bap_stream_ops_t unicast_stream_ops = { + .configured = unicast_stream_configured_cb, + .qos_set = unicast_stream_qos_set_cb, + .enabled = unicast_stream_enabled_cb, + .started = unicast_stream_started_cb, + .metadata_updated = unicast_stream_metadata_updated_cb, + .disabled = unicast_stream_disabled_cb, + .stopped = unicast_stream_stopped_cb, + .released = unicast_stream_released_cb, + .recv = unicast_stream_recv_cb, + .sent = unicast_stream_sent_cb, + .disconnected = unicast_stream_disconnected_cb, +}; + +static void unicast_server_tx(void) +{ + esp_ble_audio_bap_ep_info_t ep_info = {0}; + esp_ble_audio_cap_stream_t *cap_stream; + esp_ble_audio_bap_stream_t *bap_stream; + esp_err_t err; + + cap_stream = stream_alloc(ESP_BLE_AUDIO_DIR_SOURCE); + assert(cap_stream); + bap_stream = &cap_stream->bap_stream; + + if (bap_stream->ep == NULL) { + return; + } + + err = esp_ble_audio_bap_ep_get_info(bap_stream->ep, &ep_info); + if (err) { + return; + } + + if (ep_info.state != ESP_BLE_AUDIO_BAP_EP_STATE_STREAMING) { + return; + } + + if (bap_stream->qos == NULL || bap_stream->qos->sdu == 0) { + ESP_LOGE(TAG, "Invalid stream qos"); + return; + } + + if (iso_data == NULL) { + ESP_LOGE(TAG, "TX buffer unavailable, SDU %u", bap_stream->qos->sdu); + return; + } + + memset(iso_data, (uint8_t)tx_seq_num, bap_stream->qos->sdu); + + err = esp_ble_audio_cap_stream_send(cap_stream, iso_data, + bap_stream->qos->sdu, + tx_seq_num); + if (err) { + ESP_LOGD(TAG, "Failed to transmit data on streams, err %d", err); + return; + } + + tx_seq_num++; +} + +int cap_acceptor_unicast_init(struct peer_config *peer) +{ + static bool cbs_registered; + esp_err_t err; + + if (cbs_registered == false) { + esp_ble_audio_bap_unicast_server_register_param_t param = { + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT, + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT + }; + + err = esp_ble_audio_bap_unicast_server_register(¶m); + if (err) { + ESP_LOGE(TAG, "Failed to register BAP unicast server, err %d", err); + return -1; + } + + err = esp_ble_audio_bap_unicast_server_register_cb(&unicast_server_cb); + if (err) { + ESP_LOGE(TAG, "Failed to register BAP unicast server callbacks, err %d", err); + return -1; + } + + cbs_registered = true; + } + + err = esp_ble_audio_cap_stream_ops_register(&peer->source_stream, &unicast_stream_ops); + if (err) { + ESP_LOGE(TAG, "Failed to register source stream ops, err %d", err); + return -1; + } + + err = esp_ble_audio_cap_stream_ops_register(&peer->sink_stream, &unicast_stream_ops); + if (err) { + ESP_LOGE(TAG, "Failed to register sink stream ops, err %d", err); + return -1; + } + + err = example_audio_tx_scheduler_init(&tx_scheduler, + tx_scheduler_cb, + NULL); + if (err) { + ESP_LOGE(TAG, "Failed to initialize tx scheduler, err %d", err); + return -1; + } + + return 0; +} diff --git a/examples/bluetooth/esp_ble_audio/cap/acceptor/main/idf_component.yml b/examples/bluetooth/esp_ble_audio/cap/acceptor/main/idf_component.yml new file mode 100644 index 0000000000..bb02c0922a --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/cap/acceptor/main/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + example_init: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_audio/common_components/example_init + example_utils: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_audio/common_components/example_utils diff --git a/examples/bluetooth/esp_ble_audio/cap/acceptor/main/main.c b/examples/bluetooth/esp_ble_audio/cap/acceptor/main/main.c new file mode 100644 index 0000000000..312ccc3732 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/cap/acceptor/main/main.c @@ -0,0 +1,429 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include "nvs_flash.h" +#include "esp_system.h" +#include "esp_timer.h" + +#include "cap_acceptor.h" + +#define ADV_HANDLE 0x00 +#define ADV_SID 0 +#define ADV_TX_POWER 127 +#define ADV_ADDRESS BLE_OWN_ADDR_PUBLIC +#define ADV_PRIMARY_PHY BLE_HCI_LE_PHY_1M +#define ADV_SECONDARY_PHY BLE_HCI_LE_PHY_2M +#define ADV_INTERVAL BLE_GAP_ADV_ITVL_MS(200) + +static uint8_t codec_data[] = + ESP_BLE_AUDIO_CODEC_CAP_LC3_DATA( + ESP_BLE_AUDIO_CODEC_CAP_FREQ_ANY, /* Sampling frequency Any */ + ESP_BLE_AUDIO_CODEC_CAP_DURATION_7_5 | \ + ESP_BLE_AUDIO_CODEC_CAP_DURATION_10, /* Frame duration 7.5ms/10ms */ + ESP_BLE_AUDIO_CODEC_CAP_CHAN_COUNT_SUPPORT(2), /* Supported channels 2 */ + 30, /* Minimum 30 octets per frame */ + 155, /* Maximum 155 octets per frame */ + 2); /* Maximum 2 codec frames per SDU */ + +static uint8_t codec_meta[] = + ESP_BLE_AUDIO_CODEC_CAP_LC3_META(SINK_CONTEXT | SOURCE_CONTEXT); + +static const esp_ble_audio_codec_cap_t codec_cap = + ESP_BLE_AUDIO_CODEC_CAP_LC3(codec_data, codec_meta); + +static esp_ble_audio_pacs_cap_t sink_cap = { + .codec_cap = &codec_cap, +}; + +static esp_ble_audio_pacs_cap_t source_cap = { + .codec_cap = &codec_cap, +}; + +static struct peer_config peer = { + .conn_handle = CONN_HANDLE_INIT, +}; + +static uint8_t ext_adv_data[] = { + /* Flags */ + 0x02, EXAMPLE_AD_TYPE_FLAGS, (EXAMPLE_AD_FLAGS_GENERAL | EXAMPLE_AD_FLAGS_NO_BREDR), + /* Incomplete List of 16-bit Service UUIDs */ + 0x05, EXAMPLE_AD_TYPE_UUID16_SOME, (ESP_BLE_AUDIO_UUID_ASCS_VAL & 0xFF), + ((ESP_BLE_AUDIO_UUID_ASCS_VAL >> 8) & 0xFF), + (ESP_BLE_AUDIO_UUID_CAS_VAL & 0xFF), + ((ESP_BLE_AUDIO_UUID_CAS_VAL >> 8) & 0xFF), + /* Service Data - 16-bit UUID */ + 0x04, EXAMPLE_AD_TYPE_SERVICE_DATA16, (ESP_BLE_AUDIO_UUID_CAS_VAL & 0xFF), + ((ESP_BLE_AUDIO_UUID_CAS_VAL >> 8) & 0xFF), + ESP_BLE_AUDIO_UNICAST_ANNOUNCEMENT_TARGETED, +#if CONFIG_EXAMPLE_UNICAST + /* Service Data - 16-bit UUID */ + 0x09, EXAMPLE_AD_TYPE_SERVICE_DATA16, (ESP_BLE_AUDIO_UUID_ASCS_VAL & 0xFF), + ((ESP_BLE_AUDIO_UUID_ASCS_VAL >> 8) & 0xFF), + ESP_BLE_AUDIO_UNICAST_ANNOUNCEMENT_TARGETED, + (SINK_CONTEXT & 0xFF), + ((SINK_CONTEXT >> 8) & 0xFF), + (SOURCE_CONTEXT & 0xFF), + ((SOURCE_CONTEXT >> 8) & 0xFF), + 0x00, /* Metadata length */ +#endif /* CONFIG_EXAMPLE_UNICAST */ +#if CONFIG_EXAMPLE_BROADCAST + /* Service Data - 16-bit UUID */ + 0x03, EXAMPLE_AD_TYPE_SERVICE_DATA16, (ESP_BLE_AUDIO_UUID_BASS_VAL & 0xFF), + ((ESP_BLE_AUDIO_UUID_BASS_VAL >> 8) & 0xFF), +#endif /* CONFIG_EXAMPLE_BROADCAST */ + /* Complete Device Name */ + 0x0d, EXAMPLE_AD_TYPE_NAME_COMPLETE, 'c', 'a', 'p', '_', 'a', 'c', 'c', 'e', 'p', 't', 'o', 'r', +}; + +static void ext_adv_start(void) +{ + struct ble_gap_ext_adv_params ext_params = {0}; + struct os_mbuf *data = NULL; + int err; + + ext_params.connectable = 1; + ext_params.scannable = 0; + ext_params.legacy_pdu = 0; + ext_params.own_addr_type = ADV_ADDRESS; + ext_params.primary_phy = ADV_PRIMARY_PHY; + ext_params.secondary_phy = ADV_SECONDARY_PHY; + ext_params.tx_power = ADV_TX_POWER; + ext_params.sid = ADV_SID; + ext_params.itvl_min = ADV_INTERVAL; + ext_params.itvl_max = ADV_INTERVAL; + + err = ble_gap_ext_adv_configure(ADV_HANDLE, &ext_params, NULL, + example_audio_gap_event_cb, NULL); + if (err) { + ESP_LOGE(TAG, "Failed to configure ext adv params, err %d", err); + return; + } + + data = os_msys_get_pkthdr(sizeof(ext_adv_data), 0); + if (data == NULL) { + ESP_LOGE(TAG, "Failed to get ext adv mbuf"); + return; + } + + err = os_mbuf_append(data, ext_adv_data, sizeof(ext_adv_data)); + if (err) { + ESP_LOGE(TAG, "Failed to append ext adv data, err %d", err); + os_mbuf_free_chain(data); + return; + } + + err = ble_gap_ext_adv_set_data(ADV_HANDLE, data); + if (err) { + ESP_LOGE(TAG, "Failed to set ext adv data, err %d", err); + return; + } + + err = ble_gap_ext_adv_start(ADV_HANDLE, 0, 0); + if (err) { + ESP_LOGE(TAG, "Failed to start ext advertising, err %d", err); + return; + } + + ESP_LOGI(TAG, "Extended adv instance %u started", ADV_HANDLE); +} + +esp_ble_audio_cap_stream_t *stream_alloc(esp_ble_audio_dir_t dir) +{ + if (dir == ESP_BLE_AUDIO_DIR_SINK) { + return &peer.sink_stream; + } + + if (dir == ESP_BLE_AUDIO_DIR_SOURCE) { + return &peer.source_stream; + } + + return NULL; +} + +void stream_released(const esp_ble_audio_cap_stream_t *cap_stream) +{ + if (cap_stream == &peer.source_stream) { + ESP_LOGI(TAG, "Source stream released"); + } else if (cap_stream == &peer.sink_stream) { + ESP_LOGI(TAG, "Sink stream released"); + } +} + +static int register_pac(esp_ble_audio_dir_t dir, + esp_ble_audio_context_t context, + esp_ble_audio_pacs_cap_t *cap) +{ + esp_err_t err; + + err = esp_ble_audio_pacs_cap_register(dir, cap); + if (err) { + ESP_LOGE(TAG, "Failed to register pacs capabilities, err %d", err); + return err; + } + + /* Note: + * If using ESP_BLE_AUDIO_LOCATION_MONO_AUDIO, Samsung S24 will not perform + * the BAP unicast related procedures. + */ + err = esp_ble_audio_pacs_set_location(dir, (ESP_BLE_AUDIO_LOCATION_FRONT_LEFT | + ESP_BLE_AUDIO_LOCATION_FRONT_RIGHT)); + if (err) { + ESP_LOGE(TAG, "Failed to set pacs location, err %d", err); + return err; + } + + err = esp_ble_audio_pacs_set_supported_contexts(dir, context); + if (err) { + ESP_LOGE(TAG, "Failed to set supported contexts, err %d", err); + return err; + } + + err = esp_ble_audio_pacs_set_available_contexts(dir, context); + if (err) { + ESP_LOGE(TAG, "Failed to set available contexts, err %d", err); + return err; + } + + return 0; +} + +static int init_cap_acceptor(void) +{ + const esp_ble_audio_pacs_register_param_t pacs_param = { + .snk_pac = true, + .snk_loc = true, + .src_pac = true, + .src_loc = true, + }; + int err; + + err = esp_ble_audio_pacs_register(&pacs_param); + if (err) { + ESP_LOGE(TAG, "Failed to register pacs, err %d", err); + return -1; + } + + err = register_pac(ESP_BLE_AUDIO_DIR_SINK, SINK_CONTEXT, &sink_cap); + if (err) { + ESP_LOGE(TAG, "Failed to register sink capabilities, err %d", err); + return -1; + } + + err = register_pac(ESP_BLE_AUDIO_DIR_SOURCE, SOURCE_CONTEXT, &source_cap); + if (err) { + ESP_LOGE(TAG, "Failed to register source capabilities, err %d", err); + return -1; + } + + return 0; +} + +#if CONFIG_EXAMPLE_BROADCAST +#if CONFIG_EXAMPLE_SCAN_SELF +static void ext_scan_recv(esp_ble_audio_gap_app_event_t *event) +{ + broadcast_scan_recv(event); +} +#endif /* CONFIG_EXAMPLE_SCAN_SELF */ + +static void pa_sync(esp_ble_audio_gap_app_event_t *event) +{ + if (event->pa_sync.status) { + ESP_LOGE(TAG, "PA sync failed, status %d", event->pa_sync.status); + return; + } + + broadcast_pa_synced(event); +} + +static void pa_sync_lost(esp_ble_audio_gap_app_event_t *event) +{ + ESP_LOGI(TAG, "PA sync lost: sync_handle 0x%04x reason 0x%02x", + event->pa_sync_lost.sync_handle, event->pa_sync_lost.reason); + + broadcast_pa_lost(event); +} +#endif /* CONFIG_EXAMPLE_BROADCAST */ + +static void acl_connect(esp_ble_audio_gap_app_event_t *event) +{ + if (event->acl_connect.status) { + ESP_LOGE(TAG, "connection failed, status %d", event->acl_connect.status); + return; + } + + ESP_LOGI(TAG, "Conn established:"); + ESP_LOGI(TAG, "conn_handle 0x%04x status 0x%02x role %u peer %02x:%02x:%02x:%02x:%02x:%02x", + event->acl_connect.conn_handle, event->acl_connect.status, + event->acl_connect.role, event->acl_connect.dst.val[5], + event->acl_connect.dst.val[4], event->acl_connect.dst.val[3], + event->acl_connect.dst.val[2], event->acl_connect.dst.val[1], + event->acl_connect.dst.val[0]); + + peer.conn_handle = event->acl_connect.conn_handle; +} + +static void acl_disconnect(esp_ble_audio_gap_app_event_t *event) +{ + ESP_LOGI(TAG, "Conn terminated: conn_handle 0x%04x reason 0x%02x", + event->acl_disconnect.conn_handle, event->acl_disconnect.reason); + + peer.conn_handle = CONN_HANDLE_INIT; + + ext_adv_start(); +} + +static void iso_gap_app_cb(esp_ble_audio_gap_app_event_t *event) +{ + switch (event->type) { +#if CONFIG_EXAMPLE_BROADCAST +#if CONFIG_EXAMPLE_SCAN_SELF + case ESP_BLE_AUDIO_GAP_EVENT_EXT_SCAN_RECV: + ext_scan_recv(event); + break; +#endif /* CONFIG_EXAMPLE_SCAN_SELF */ + case ESP_BLE_AUDIO_GAP_EVENT_PA_SYNC: + pa_sync(event); + break; + case ESP_BLE_AUDIO_GAP_EVENT_PA_SYNC_LOST: + pa_sync_lost(event); + break; +#endif /* CONFIG_EXAMPLE_BROADCAST */ + case ESP_BLE_AUDIO_GAP_EVENT_ACL_CONNECT: + acl_connect(event); + break; + case ESP_BLE_AUDIO_GAP_EVENT_ACL_DISCONNECT: + acl_disconnect(event); + break; + default: + break; + } +} + +static void gatt_mtu_change(esp_ble_audio_gatt_app_event_t *event) +{ + int err; + + ESP_LOGI(TAG, "gatt mtu change, conn_handle %u, mtu %u", + event->gatt_mtu_change.conn_handle, event->gatt_mtu_change.mtu); + + if (event->gatt_mtu_change.mtu < ESP_BLE_AUDIO_ATT_MTU_MIN) { + ESP_LOGW(TAG, "Invalid new mtu %u, shall be at least %u", + event->gatt_mtu_change.mtu, ESP_BLE_AUDIO_ATT_MTU_MIN); + return; + } + + /* This function only needs to be invoked when: + * - The device is a Peripheral (Link Layer role); + * - The device works as a GATT client. + */ + err = esp_ble_audio_gattc_disc_start(event->gatt_mtu_change.conn_handle); + if (err) { + ESP_LOGE(TAG, "Failed to start svc disc, err %d", err); + return; + } + + ESP_LOGI(TAG, "Start discovering gatt services"); +} + +static void gattc_disc_cmpl(esp_ble_audio_gatt_app_event_t *event) +{ + ESP_LOGI(TAG, "gattc disc cmpl, status %u, conn_handle %u", + event->gattc_disc_cmpl.status, event->gattc_disc_cmpl.conn_handle); +} + +static void iso_gatt_app_cb(esp_ble_audio_gatt_app_event_t *event) +{ + switch (event->type) { + case ESP_BLE_AUDIO_GATT_EVENT_GATT_MTU_CHANGE: + gatt_mtu_change(event); + break; + case ESP_BLE_AUDIO_GATT_EVENT_GATTC_DISC_CMPL: + gattc_disc_cmpl(event); + break; + default: + break; + } +} + +void app_main(void) +{ + esp_ble_audio_init_info_t info = { + .gap_cb = iso_gap_app_cb, + .gatt_cb = iso_gatt_app_cb, + }; + esp_err_t err; + + /* Initialize NVS — it is used to store PHY calibration data */ + err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK(err); + + err = bluetooth_init(); + if (err) { + ESP_LOGE(TAG, "Failed to initialize BLE, err %d", err); + return; + } + + err = esp_ble_audio_common_init(&info); + if (err) { + ESP_LOGE(TAG, "Failed to initialize audio, err %d", err); + return; + } + + err = init_cap_acceptor(); + if (err) { + return; + } + +#if CONFIG_EXAMPLE_UNICAST + err = cap_acceptor_unicast_init(&peer); + if (err) { + return; + } +#endif /* CONFIG_EXAMPLE_UNICAST */ + +#if CONFIG_EXAMPLE_BROADCAST + err = cap_acceptor_broadcast_init(); + if (err) { + return; + } +#endif /* CONFIG_EXAMPLE_BROADCAST */ + + err = esp_ble_audio_common_start(NULL); + if (err) { + ESP_LOGE(TAG, "Failed to start audio, err %d", err); + return; + } + + err = ble_svc_gap_device_name_set("CAP Acceptor"); + if (err) { + ESP_LOGE(TAG, "Failed to set device name, err %d", err); + return; + } + +#if CONFIG_EXAMPLE_SCAN_SELF + err = check_start_scan(); + if (err) { + return; + } +#endif /* CONFIG_EXAMPLE_SCAN_SELF */ + + /* Advertising will be used by Unicast Server and + * Broadcast Sink when self-scanning is disabled. + */ + ext_adv_start(); +} diff --git a/examples/bluetooth/esp_ble_audio/cap/acceptor/sdkconfig.defaults b/examples/bluetooth/esp_ble_audio/cap/acceptor/sdkconfig.defaults new file mode 100644 index 0000000000..269d8a9964 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/cap/acceptor/sdkconfig.defaults @@ -0,0 +1,32 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration +# + +CONFIG_BT_ENABLED=y +CONFIG_BT_BLUEDROID_ENABLED=n +CONFIG_BT_NIMBLE_ENABLED=y +CONFIG_BT_NIMBLE_EXT_ADV=y +CONFIG_BT_NIMBLE_MAX_CONNECTIONS=1 +CONFIG_BT_NIMBLE_MAX_CCCDS=20 +CONFIG_BT_NIMBLE_ISO=y +CONFIG_BT_NIMBLE_LOG_LEVEL_WARNING=y + +CONFIG_BT_ISO_MAX_CHAN=2 + +CONFIG_BT_CAP_ACCEPTOR=y +CONFIG_BT_BAP_UNICAST_SERVER=y +CONFIG_BT_BAP_BROADCAST_SINK=y +CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT=2 +CONFIG_BT_BAP_SCAN_DELEGATOR=y +CONFIG_BT_PAC_SNK_NOTIFIABLE=y +CONFIG_BT_PAC_SNK_LOC_WRITEABLE=y +CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE=y +CONFIG_BT_PAC_SRC_NOTIFIABLE=y +CONFIG_BT_PAC_SRC_LOC_WRITEABLE=y +CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE=y +CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE=y +CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE=30 + +CONFIG_EXAMPLE_UNICAST=y + +CONFIG_FREERTOS_HZ=1000 diff --git a/examples/bluetooth/esp_ble_audio/cap/acceptor/sdkconfig.defaults.esp32h4 b/examples/bluetooth/esp_ble_audio/cap/acceptor/sdkconfig.defaults.esp32h4 new file mode 100644 index 0000000000..5920ce3f85 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/cap/acceptor/sdkconfig.defaults.esp32h4 @@ -0,0 +1,6 @@ +# Override some defaults so BT stack is enabled +# by default in this example + +CONFIG_IDF_TARGET="esp32h4" + +CONFIG_BT_LE_ISO_SUPPORT=y diff --git a/examples/bluetooth/esp_ble_audio/cap/initiator/CMakeLists.txt b/examples/bluetooth/esp_ble_audio/cap/initiator/CMakeLists.txt new file mode 100644 index 0000000000..55114f71c3 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/cap/initiator/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.22) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +idf_build_set_property(MINIMAL_BUILD ON) +project(cap_initiator) diff --git a/examples/bluetooth/esp_ble_audio/cap/initiator/README.md b/examples/bluetooth/esp_ble_audio/cap/initiator/README.md new file mode 100644 index 0000000000..229095e266 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/cap/initiator/README.md @@ -0,0 +1,73 @@ +| Supported Targets | ESP32-H4 | +| ----------------- | -------- | + +# CAP Initiator Example + +(See the README.md file in the upper level `examples` directory for more information about examples.) + +This example demonstrates the **Common Audio Profile (CAP) Initiator** functionality. It operates in one of two mutually exclusive modes selected at build time: **unicast** or **broadcast**. In unicast mode, the initiator scans for connectable advertising that includes the CAS/ASCS service data, connects to the acceptor, performs service discovery and MTU exchange, discovers sink and source ASEs, configures streams with an LC3 16_2_1 unicast preset, sets QoS, enables and connects the streams, then starts the streams and can send or receive audio. In broadcast mode, the initiator starts extended and periodic advertising with the Broadcast Audio Announcement service data and BASE, so that Broadcast Sinks (e.g. the [acceptor](../acceptor) in broadcast mode) can sync. Run it together with the [acceptor](../acceptor) example on another device as the CAP Acceptor. + +The implementation uses the NimBLE host stack with ISO and BAP support, ESP-BLE-AUDIO (CAP initiator, BAP unicast client, BAP broadcast source). Unicast uses the LC3 16_2_1 preset and initiates pairing after connection. Broadcast uses an LC3 16_2_1 broadcast preset with a hardcoded broadcast ID. The device name is hardcoded as `CAP Initiator`. + +## Requirements + +* A board with Bluetooth LE 5.2, ISO, and LE Audio support (e.g. ESP32-H4) +* For unicast or as Broadcast Assistant: another device running the [acceptor](../acceptor) example (advertising as CAP Acceptor) + +## How to Use Example + +Before project configuration and build, set the correct chip target: + +```bash +idf.py set-target esp32h4 +``` + +### Configure the Project + +Open the configuration menu to select the mode: + +```bash +idf.py menuconfig +``` + +Under **Example: CAP Initiator**, select one of: + +* **Unicast** — scan for a CAP Acceptor and set up unicast audio streams after connection +* **Broadcast** — act as a Broadcast Source; start extended and periodic advertising so that Broadcast Sinks can sync + +### Build and Flash + +Run the following to build, flash and monitor: + +```bash +idf.py -p PORT flash monitor +``` + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the [Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF. + +## Example Flow + +1. **Initialization**: NVS, Bluetooth stack, and LE Audio common layer (`esp_ble_audio_common_init`) with GAP and GATT callbacks (unicast mode). In unicast mode, initialize the CAP initiator unicast part (BAP unicast client, CAP unicast group, stream callbacks). In broadcast mode, initialize the CAP initiator broadcast part (broadcast source, stream ops). Register the TX module for sending audio. Start the audio stack and set the device name (`CAP Initiator`). +2. **Unicast mode**: Start extended scanning. On scan result with connectable advertising and CAS/ASCS service data, connect to the acceptor. On connection, start pairing. On MTU exchange, start GATT service discovery. After discovery, discover ASEs, configure codec (LC3 16_2_1), set QoS, enable and connect streams, then start streams; the initiator registers the TX stream for sending and can receive on sink streams. +3. **Broadcast mode**: Start extended and periodic advertising with Broadcast Audio Announcement UUID, hardcoded broadcast ID, and BASE. When the broadcast stream is started, register it for TX and send audio. Sinks (e.g. acceptor in broadcast mode) can sync to this broadcast. +4. **Stream lifecycle**: Stream started/stopped callbacks register/unregister streams with the TX module; sent callbacks log periodic packet counts. + +## Example Output + +``` +I (xxx) CAP_INI: connection established, status 0 +I (xxx) CAP_INI: Configured stream 0x... +I (xxx) CAP_INI: Started stream 0x... +... +I (xxx) CAP_INI: Started broadcast stream 0x... +I (xxx) CAP_INI: Sent 1000 HCI ISO data packets +... +``` + +If the connection is lost: + +``` +I (xxx) CAP_INI: connection disconnected, reason 0x... +``` diff --git a/examples/bluetooth/esp_ble_audio/cap/initiator/main/CMakeLists.txt b/examples/bluetooth/esp_ble_audio/cap/initiator/main/CMakeLists.txt new file mode 100644 index 0000000000..199c52d646 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/cap/initiator/main/CMakeLists.txt @@ -0,0 +1,13 @@ +set(srcs "cap_initiator_tx.c" + "main.c") + +if(CONFIG_EXAMPLE_UNICAST) + list(APPEND srcs "cap_initiator_unicast.c") +endif() + +if(CONFIG_EXAMPLE_BROADCAST) + list(APPEND srcs "cap_initiator_broadcast.c") +endif() + +idf_component_register(SRCS "${srcs}" + REQUIRES bt nvs_flash) diff --git a/examples/bluetooth/esp_ble_audio/cap/initiator/main/Kconfig.projbuild b/examples/bluetooth/esp_ble_audio/cap/initiator/main/Kconfig.projbuild new file mode 100644 index 0000000000..472a311c6e --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/cap/initiator/main/Kconfig.projbuild @@ -0,0 +1,27 @@ +# SPDX-FileCopyrightText: 2022 Nordic Semiconductor ASA +# SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 + +menu "Example: CAP Initiator" + + choice EXAMPLE_CAP_INITIATOR_MODE + prompt "CAP Initiator mode" + default EXAMPLE_UNICAST + help + Select exactly one CAP initiator mode. + + config EXAMPLE_UNICAST + bool "Unicast" + help + If selected, the sample will start advertising connectable + for Broadcast Assistants. + + config EXAMPLE_BROADCAST + bool "Broadcast" + help + If selected, the sample will start advertising syncable + audio streams. + + endchoice + +endmenu diff --git a/examples/bluetooth/esp_ble_audio/cap/initiator/main/cap_initiator.h b/examples/bluetooth/esp_ble_audio/cap/initiator/main/cap_initiator.h new file mode 100644 index 0000000000..fc2220d274 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/cap/initiator/main/cap_initiator.h @@ -0,0 +1,53 @@ +/* + * SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_log.h" + +#include "sdkconfig.h" + +#include "host/ble_hs.h" +#include "services/gap/ble_svc_gap.h" + +#include "esp_ble_audio_lc3_defs.h" +#include "esp_ble_audio_bap_api.h" +#include "esp_ble_audio_cap_api.h" +#include "esp_ble_audio_pacs_api.h" +#include "esp_ble_audio_bap_lc3_preset_defs.h" + +#include "ble_audio_example_init.h" +#include "ble_audio_example_utils.h" + +#define TAG "CAP_INI" + +#define CONN_HANDLE_INIT 0xFFFF + +struct tx_stream { + esp_ble_audio_cap_stream_t *stream; + uint16_t seq_num; + uint8_t *data; + example_audio_tx_scheduler_t scheduler; +}; + +void cap_initiator_unicast_gap_cb(esp_ble_audio_gap_app_event_t *event); + +void cap_initiator_unicast_gatt_cb(esp_ble_audio_gatt_app_event_t *event); + +int cap_initiator_unicast_start(void); + +int cap_initiator_unicast_init(void); + +int cap_initiator_broadcast_start(void); + +int cap_initiator_broadcast_init(void); + +void cap_initiator_tx_stream_sent(esp_ble_audio_bap_stream_t *stream, void *user_data); + +int cap_initiator_tx_register_stream(esp_ble_audio_cap_stream_t *cap_stream); + +int cap_initiator_tx_unregister_stream(esp_ble_audio_cap_stream_t *cap_stream); + +void cap_initiator_tx_init(void); diff --git a/examples/bluetooth/esp_ble_audio/cap/initiator/main/cap_initiator_broadcast.c b/examples/bluetooth/esp_ble_audio/cap/initiator/main/cap_initiator_broadcast.c new file mode 100644 index 0000000000..a5ed29034f --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/cap/initiator/main/cap_initiator_broadcast.c @@ -0,0 +1,325 @@ +/* + * SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include "cap_initiator.h" + +#define ADV_HANDLE 0x00 +#define ADV_SID 0 +#define ADV_TX_POWER 127 +#define ADV_ADDRESS BLE_OWN_ADDR_PUBLIC +#define ADV_PRIMARY_PHY BLE_HCI_LE_PHY_1M +#define ADV_SECONDARY_PHY BLE_HCI_LE_PHY_2M +#define ADV_INTERVAL BLE_GAP_ADV_ITVL_MS(200) + +#define PER_ADV_INTERVAL BLE_GAP_ADV_ITVL_MS(100) + +#define LOCAL_DEVICE_NAME "CAP Broadcast Source" +#define LOCAL_BROADCAST_ID 0x123456 + +ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_16_2_1_DEFINE(broadcast_preset_16_2_1, + ESP_BLE_AUDIO_LOCATION_MONO_AUDIO, + ESP_BLE_AUDIO_CONTEXT_TYPE_UNSPECIFIED); + +static esp_ble_audio_cap_broadcast_source_t *broadcast_source; +static esp_ble_audio_cap_stream_t broadcast_stream; + +static void broadcast_stream_started_cb(esp_ble_audio_bap_stream_t *stream) +{ + esp_ble_audio_cap_stream_t *cap_stream; + int err; + + ESP_LOGI(TAG, "Broadcast stream %p started", stream); + + cap_stream = CONTAINER_OF(stream, esp_ble_audio_cap_stream_t, bap_stream); + + err = cap_initiator_tx_register_stream(cap_stream); + if (err) { + ESP_LOGE(TAG, "Failed to register stream %p for TX, err %d", stream, err); + } +} + +static void broadcast_stream_stopped_cb(esp_ble_audio_bap_stream_t *stream, uint8_t reason) +{ + esp_ble_audio_cap_stream_t *cap_stream; + + ESP_LOGI(TAG, "Broadcast stream %p stopped, reason 0x%02x", stream, reason); + + cap_stream = CONTAINER_OF(stream, esp_ble_audio_cap_stream_t, bap_stream); + + (void)cap_initiator_tx_unregister_stream(cap_stream); +} + +static void broadcast_stream_disconnected_cb(esp_ble_audio_bap_stream_t *stream, uint8_t reason) +{ + esp_ble_audio_cap_stream_t *cap_stream; + + ESP_LOGI(TAG, "Broadcast stream %p disconnected, reason 0x%02x", stream, reason); + + cap_stream = CONTAINER_OF(stream, esp_ble_audio_cap_stream_t, bap_stream); + + (void)cap_initiator_tx_unregister_stream(cap_stream); +} + +static void broadcast_stream_sent_cb(esp_ble_audio_bap_stream_t *stream, void *user_data) +{ + cap_initiator_tx_stream_sent(stream, user_data); +} + +static esp_ble_audio_bap_stream_ops_t broadcast_stream_ops = { + .started = broadcast_stream_started_cb, + .stopped = broadcast_stream_stopped_cb, + .sent = broadcast_stream_sent_cb, + .disconnected = broadcast_stream_disconnected_cb, +}; + +static uint8_t *ext_adv_data_get(uint8_t *data_len) +{ + uint32_t broadcast_id; + uint8_t *data; + + broadcast_id = LOCAL_BROADCAST_ID; + + /* - Broadcast Audio Announcement Service UUID (2 octets) + * - Broadcast ID (3 octets) + * - Complete Device Name + */ + *data_len = 7 + 2 + strlen(LOCAL_DEVICE_NAME); + + data = calloc(1, *data_len); + if (data == NULL) { + return NULL; + } + + data[0] = 0x06; /* 1 + 2 + 3 */ + data[1] = EXAMPLE_AD_TYPE_SERVICE_DATA16; + data[2] = (ESP_BLE_AUDIO_UUID_BROADCAST_AUDIO_VAL & 0xFF); + data[3] = ((ESP_BLE_AUDIO_UUID_BROADCAST_AUDIO_VAL >> 8) & 0xFF); + data[4] = (broadcast_id & 0xFF); + data[5] = ((broadcast_id >> 8) & 0xFF); + data[6] = ((broadcast_id >> 16) & 0xFF); + + data[7] = strlen(LOCAL_DEVICE_NAME) + 1; + data[8] = EXAMPLE_AD_TYPE_NAME_COMPLETE; + memcpy(data + 9, LOCAL_DEVICE_NAME, strlen(LOCAL_DEVICE_NAME)); + + return data; +} + +static uint8_t *per_adv_data_get(uint8_t *data_len) +{ + NET_BUF_SIMPLE_DEFINE(base_buf, 128); + uint8_t *data; + esp_err_t err; + + /* Broadcast Audio Announcement Service UUID (2 octets) and + * Broadcast Audio Source Endpoint (BASE) + */ + + err = esp_ble_audio_cap_initiator_broadcast_get_base(broadcast_source, &base_buf); + if (err) { + ESP_LOGE(TAG, "Failed to get encoded BASE, err %d", err); + return NULL; + } + + *data_len = 2 + base_buf.len; + + data = calloc(1, *data_len); + if (data == NULL) { + return NULL; + } + + /* base_buf.len has included the UUID length (2 octets) */ + data[0] = 1 + base_buf.len; + data[1] = EXAMPLE_AD_TYPE_SERVICE_DATA16; + memcpy(data + 2, base_buf.data, base_buf.len); + + return data; +} + +static int ext_adv_start(void) +{ + struct ble_gap_periodic_adv_params per_params = {0}; + struct ble_gap_ext_adv_params ext_params = {0}; + struct os_mbuf *data = NULL; + uint8_t *ext_data = NULL; + uint8_t *per_data = NULL; + uint8_t data_len = 0; + int err; + + ext_params.connectable = 0; + ext_params.scannable = 0; + ext_params.legacy_pdu = 0; + ext_params.own_addr_type = ADV_ADDRESS; + ext_params.primary_phy = ADV_PRIMARY_PHY; + ext_params.secondary_phy = ADV_SECONDARY_PHY; + ext_params.tx_power = ADV_TX_POWER; + ext_params.sid = ADV_SID; + ext_params.itvl_min = ADV_INTERVAL; + ext_params.itvl_max = ADV_INTERVAL; + + err = ble_gap_ext_adv_configure(ADV_HANDLE, &ext_params, NULL, + example_audio_gap_event_cb, NULL); + if (err) { + ESP_LOGE(TAG, "Failed to configure ext adv params, err %d", err); + goto end; + } + + ext_data = ext_adv_data_get(&data_len); + if (ext_data == NULL) { + err = -ENOMEM; + goto end; + } + + data = os_msys_get_pkthdr(data_len, 0); + if (data == NULL) { + ESP_LOGE(TAG, "Failed to get ext adv mbuf"); + err = -ENOMEM; + goto end; + } + + err = os_mbuf_append(data, ext_data, data_len); + if (err) { + ESP_LOGE(TAG, "Failed to append ext adv data, err %d", err); + os_mbuf_free_chain(data); + goto end; + } + + err = ble_gap_ext_adv_set_data(ADV_HANDLE, data); + if (err) { + ESP_LOGE(TAG, "Failed to set ext adv data, err %d", err); + goto end; + } + + per_params.include_tx_power = 0; + per_params.itvl_min = PER_ADV_INTERVAL; + per_params.itvl_max = PER_ADV_INTERVAL; + + err = ble_gap_periodic_adv_configure(ADV_HANDLE, &per_params); + if (err) { + ESP_LOGE(TAG, "Failed to configure per adv params, err %d", err); + goto end; + } + + per_data = per_adv_data_get(&data_len); + if (per_data == NULL) { + err = -ENOMEM; + goto end; + } + + data = os_msys_get_pkthdr(data_len, 0); + if (data == NULL) { + ESP_LOGE(TAG, "Failed to get per adv mbuf"); + err = -ENOMEM; + goto end; + } + + err = os_mbuf_append(data, per_data, data_len); + if (err) { + ESP_LOGE(TAG, "Failed to append per adv data, err %d", err); + os_mbuf_free_chain(data); + goto end; + } + + err = ble_gap_periodic_adv_set_data(ADV_HANDLE, data); + if (err) { + ESP_LOGE(TAG, "Failed to set per adv data, err %d", err); + goto end; + } + + err = ble_gap_periodic_adv_start(ADV_HANDLE); + if (err) { + ESP_LOGE(TAG, "Failed to start per advertising, err %d", err); + goto end; + } + + err = ble_gap_ext_adv_start(ADV_HANDLE, 0, 0); + if (err) { + ESP_LOGE(TAG, "Failed to start ext advertising, err %d", err); + goto end; + } + + ESP_LOGI(TAG, "Extended adv instance %u started", ADV_HANDLE); + +end: + if (ext_data) { + free(ext_data); + } + if (per_data) { + free(per_data); + } + return err; +} + +int cap_initiator_broadcast_start(void) +{ + esp_ble_audio_cap_initiator_broadcast_stream_param_t stream_params = { + .stream = &broadcast_stream, + }; + esp_ble_audio_cap_initiator_broadcast_subgroup_param_t subgroup_param = { + .codec_cfg = &broadcast_preset_16_2_1.codec_cfg, + .stream_params = &stream_params, + .stream_count = 1, + }; + const esp_ble_audio_cap_initiator_broadcast_create_param_t create_param = { + .qos = &broadcast_preset_16_2_1.qos, + .subgroup_params = &subgroup_param, + .subgroup_count = 1, + }; + esp_ble_audio_bap_broadcast_adv_info_t info = { + .adv_handle = ADV_HANDLE, + }; + int err; + + ESP_LOGI(TAG, "Creating broadcast source"); + + err = esp_ble_audio_cap_initiator_broadcast_audio_create(&create_param, &broadcast_source); + if (err) { + ESP_LOGE(TAG, "Failed to create broadcast source, err %d", err); + return err; + } + + err = ext_adv_start(); + if (err) { + goto end; + } + + err = esp_ble_audio_bap_broadcast_adv_add(&info); + if (err) { + ESP_LOGE(TAG, "Failed to add adv for broadcast source, err %d", err); + goto end; + } + + err = esp_ble_audio_cap_initiator_broadcast_audio_start(broadcast_source, ADV_HANDLE); + if (err) { + ESP_LOGE(TAG, "Failed to start broadcast source, err %d", err); + goto end; + } + + return 0; + +end: + err = esp_ble_audio_cap_initiator_broadcast_audio_delete(broadcast_source); + if (err) { + ESP_LOGE(TAG, "Failed to delete broadcast source, err %d", err); + } + return err; +} + +int cap_initiator_broadcast_init(void) +{ + esp_ble_audio_cap_stream_ops_register(&broadcast_stream, &broadcast_stream_ops); + + ESP_LOGI(TAG, "CAP initiator broadcast initialized"); + + return 0; +} diff --git a/examples/bluetooth/esp_ble_audio/cap/initiator/main/cap_initiator_tx.c b/examples/bluetooth/esp_ble_audio/cap/initiator/main/cap_initiator_tx.c new file mode 100644 index 0000000000..8ae26d69b5 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/cap/initiator/main/cap_initiator_tx.c @@ -0,0 +1,184 @@ +/* + * SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "cap_initiator.h" + +static struct tx_stream tx_streams[IS_ENABLED(CONFIG_EXAMPLE_UNICAST) + IS_ENABLED(CONFIG_EXAMPLE_BROADCAST)]; + +static bool cap_stream_is_streaming(const esp_ble_audio_cap_stream_t *cap_stream) +{ + esp_ble_audio_bap_ep_info_t ep_info = {0}; + int err; + + if (cap_stream == NULL) { + return false; + } + + if (cap_stream->bap_stream.ep == NULL) { + return false; + } + + err = esp_ble_audio_bap_ep_get_info(cap_stream->bap_stream.ep, &ep_info); + if (err) { + return false; + } + + return (ep_info.state == ESP_BLE_AUDIO_BAP_EP_STATE_STREAMING); +} + +static void cap_initiator_tx_send(struct tx_stream *tx_stream) +{ + int err; + + if (tx_stream == NULL || tx_stream->stream == NULL) { + return; + } + + if (cap_stream_is_streaming(tx_stream->stream) == false) { + return; + } + + if (tx_stream->stream->bap_stream.qos == NULL || + tx_stream->stream->bap_stream.qos->sdu == 0) { + ESP_LOGE(TAG, "Invalid stream qos"); + return; + } + + if (tx_stream->data == NULL) { + ESP_LOGE(TAG, "TX buffer unavailable, SDU %u (stream %p)", + tx_stream->stream->bap_stream.qos->sdu, &tx_stream->stream->bap_stream); + return; + } + + memset(tx_stream->data, (uint8_t)tx_stream->seq_num, tx_stream->stream->bap_stream.qos->sdu); + + err = esp_ble_audio_cap_stream_send(tx_stream->stream, tx_stream->data, + tx_stream->stream->bap_stream.qos->sdu, + tx_stream->seq_num); + if (err) { + ESP_LOGD(TAG, "Failed to transmit data on stream %p, err %d", + &tx_stream->stream->bap_stream, err); + return; + } + + tx_stream->seq_num++; +} + +void cap_initiator_tx_stream_sent(esp_ble_audio_bap_stream_t *stream, void *user_data) +{ + for (size_t i = 0; i < ARRAY_SIZE(tx_streams); i++) { + if (tx_streams[i].stream && &tx_streams[i].stream->bap_stream == stream) { + example_audio_tx_scheduler_on_sent(&tx_streams[i].scheduler, user_data, TAG, "stream", stream); + break; + } + } +} + +static void tx_scheduler_cb(void *arg) +{ + struct tx_stream *tx_stream = arg; + + cap_initiator_tx_send(tx_stream); +} + +int cap_initiator_tx_register_stream(esp_ble_audio_cap_stream_t *cap_stream) +{ + int err; + + if (cap_stream == NULL) { + return -EINVAL; + } + + for (size_t i = 0; i < ARRAY_SIZE(tx_streams); i++) { + if (tx_streams[i].stream == NULL) { + if (cap_stream->bap_stream.qos == NULL || cap_stream->bap_stream.qos->sdu == 0) { + ESP_LOGE(TAG, "Invalid stream qos"); + return -EINVAL; + } + + if (tx_streams[i].data == NULL) { + tx_streams[i].data = calloc(1, cap_stream->bap_stream.qos->sdu); + if (tx_streams[i].data == NULL) { + ESP_LOGE(TAG, "Failed to alloc TX buffer, SDU %u (stream %p)", + cap_stream->bap_stream.qos->sdu, &cap_stream->bap_stream); + return -ENOMEM; + } + } + + tx_streams[i].stream = cap_stream; + tx_streams[i].seq_num = 0; + example_audio_tx_scheduler_reset(&tx_streams[i].scheduler); + + err = example_audio_tx_scheduler_start(&tx_streams[i].scheduler, cap_stream->bap_stream.qos->interval); + if (err) { + ESP_LOGE(TAG, "Failed to start tx scheduler, err %d", err); + tx_streams[i].stream = NULL; + return err; + } + + cap_initiator_tx_send(&tx_streams[i]); + return 0; + } + } + + ESP_LOGE(TAG, "No free TX stream slot"); + + return -ENOMEM; +} + +int cap_initiator_tx_unregister_stream(esp_ble_audio_cap_stream_t *cap_stream) +{ + int err; + + if (cap_stream == NULL) { + return -EINVAL; + } + + for (size_t i = 0; i < ARRAY_SIZE(tx_streams); i++) { + if (tx_streams[i].stream == cap_stream) { + err = example_audio_tx_scheduler_stop(&tx_streams[i].scheduler); + if (err) { + ESP_LOGE(TAG, "Failed to stop tx scheduler, err %d", err); + return err; + } + + tx_streams[i].stream = NULL; + if (tx_streams[i].data != NULL) { + free(tx_streams[i].data); + tx_streams[i].data = NULL; + } + + return 0; + } + } + + return -ENODATA; +} + +void cap_initiator_tx_init(void) +{ + int err; + + memset(tx_streams, 0, sizeof(tx_streams)); + + for (size_t i = 0; i < ARRAY_SIZE(tx_streams); i++) { + err = example_audio_tx_scheduler_init(&tx_streams[i].scheduler, + tx_scheduler_cb, + &tx_streams[i]); + if (err) { + ESP_LOGE(TAG, "Failed to initialize tx scheduler[%u], err %d", i, err); + return; + } + } +} diff --git a/examples/bluetooth/esp_ble_audio/cap/initiator/main/cap_initiator_unicast.c b/examples/bluetooth/esp_ble_audio/cap/initiator/main/cap_initiator_unicast.c new file mode 100644 index 0000000000..5b41001ae2 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/cap/initiator/main/cap_initiator_unicast.c @@ -0,0 +1,728 @@ +/* + * SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include "cap_initiator.h" + +#define SCAN_INTERVAL 160 /* 100ms */ +#define SCAN_WINDOW 160 /* 100ms */ + +#define INIT_SCAN_INTERVAL 16 /* 10ms */ +#define INIT_SCAN_WINDOW 16 /* 10ms */ +#define CONN_INTERVAL 64 /* 64 * 1.25 = 80ms */ +#define CONN_LATENCY 0 +#define CONN_TIMEOUT 500 /* 500 * 10ms = 5s */ +#define CONN_MAX_CE_LEN 0xFFFF +#define CONN_MIN_CE_LEN 0xFFFF +#define CONN_DURATION 10000 /* 10s */ + +ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_16_2_1_DEFINE(unicast_preset_16_2_1, + ESP_BLE_AUDIO_LOCATION_MONO_AUDIO, + ESP_BLE_AUDIO_CONTEXT_TYPE_UNSPECIFIED); +static esp_ble_audio_cap_unicast_group_t *unicast_group; + +static struct peer_config { + esp_ble_audio_cap_stream_t source_stream; + esp_ble_audio_cap_stream_t sink_stream; + esp_ble_audio_bap_ep_t *source_ep; + esp_ble_audio_bap_ep_t *sink_ep; + + esp_ble_conn_t *conn; + uint16_t conn_handle; + bool disc_completed; + bool disc_cancelled; + bool mtu_exchanged; +} peer = { + .conn_handle = CONN_HANDLE_INIT, +}; + +static example_audio_rx_metrics_t rx_metrics; + +static bool is_tx_stream(esp_ble_audio_bap_stream_t *stream) +{ + esp_ble_audio_bap_ep_info_t ep_info = {0}; + esp_err_t err; + + err = esp_ble_audio_bap_ep_get_info(stream->ep, &ep_info); + if (err) { + ESP_LOGE(TAG, "Failed to get ep info, err %d", err); + return false; + } + + return (ep_info.dir == ESP_BLE_AUDIO_DIR_SINK); +} + +static void unicast_stream_configured_cb(esp_ble_audio_bap_stream_t *stream, + const esp_ble_audio_bap_qos_cfg_pref_t *pref) +{ + ESP_LOGI(TAG, "Unicast stream %p configured", stream); + + example_print_qos_pref(pref); +} + +static void unicast_stream_qos_set_cb(esp_ble_audio_bap_stream_t *stream) +{ + ESP_LOGI(TAG, "Unicast stream %p QoS set", stream); +} + +static void unicast_stream_enabled_cb(esp_ble_audio_bap_stream_t *stream) +{ + ESP_LOGI(TAG, "Unicast stream %p enabled", stream); +} + +static void unicast_stream_started_cb(esp_ble_audio_bap_stream_t *stream) +{ + esp_ble_audio_cap_stream_t *cap_stream; + int err; + + ESP_LOGI(TAG, "Unicast stream %p started", stream); + + example_audio_rx_metrics_reset(&rx_metrics); + + if (is_tx_stream(stream)) { + cap_stream = CONTAINER_OF(stream, esp_ble_audio_cap_stream_t, bap_stream); + + err = cap_initiator_tx_register_stream(cap_stream); + if (err) { + ESP_LOGE(TAG, "Failed to register stream %p for TX, err %d", stream, err); + } + } +} + +static void unicast_stream_metadata_updated_cb(esp_ble_audio_bap_stream_t *stream) +{ + ESP_LOGI(TAG, "Unicast stream %p metadata updated", stream); +} + +static void unicast_stream_disabled_cb(esp_ble_audio_bap_stream_t *stream) +{ + ESP_LOGI(TAG, "Unicast stream %p disabled", stream); +} + +static void unicast_stream_stopped_cb(esp_ble_audio_bap_stream_t *stream, uint8_t reason) +{ + esp_ble_audio_cap_stream_t *cap_stream; + + ESP_LOGI(TAG, "Unicast stream %p stopped, reason 0x%02x", stream, reason); + + if (is_tx_stream(stream)) { + cap_stream = CONTAINER_OF(stream, esp_ble_audio_cap_stream_t, bap_stream); + + (void)cap_initiator_tx_unregister_stream(cap_stream); + } +} + +static void unicast_stream_disconnected_cb(esp_ble_audio_bap_stream_t *stream, uint8_t reason) +{ + esp_ble_audio_cap_stream_t *cap_stream; + + ESP_LOGI(TAG, "Unicast stream %p disconnected, reason 0x%02x", stream, reason); + + if (is_tx_stream(stream)) { + cap_stream = CONTAINER_OF(stream, esp_ble_audio_cap_stream_t, bap_stream); + + (void)cap_initiator_tx_unregister_stream(cap_stream); + } +} + +static void unicast_stream_released_cb(esp_ble_audio_bap_stream_t *stream) +{ + if (stream == &peer.source_stream.bap_stream) { + ESP_LOGI(TAG, "Unicast source stream %p released", stream); + } else if (stream == &peer.sink_stream.bap_stream) { + ESP_LOGI(TAG, "Unicast sink stream %p released", stream); + } +} + +static void unicast_stream_recv_cb(esp_ble_audio_bap_stream_t *stream, + const esp_ble_iso_recv_info_t *info, + const uint8_t *data, uint16_t len) +{ + rx_metrics.last_sdu_len = len; + example_audio_rx_metrics_on_recv(info, &rx_metrics, TAG, "stream", stream); +} + +static void unicast_stream_sent_cb(esp_ble_audio_bap_stream_t *stream, void *user_data) +{ + cap_initiator_tx_stream_sent(stream, user_data); +} + +static esp_ble_audio_bap_stream_ops_t unicast_stream_ops = { + .configured = unicast_stream_configured_cb, + .qos_set = unicast_stream_qos_set_cb, + .enabled = unicast_stream_enabled_cb, + .started = unicast_stream_started_cb, + .metadata_updated = unicast_stream_metadata_updated_cb, + .disabled = unicast_stream_disabled_cb, + .stopped = unicast_stream_stopped_cb, + .released = unicast_stream_released_cb, + .recv = unicast_stream_recv_cb, + .sent = unicast_stream_sent_cb, + .disconnected = unicast_stream_disconnected_cb, +}; + +static int discover_cas(void) +{ + int err; + + err = esp_ble_audio_cap_initiator_unicast_discover(peer.conn_handle); + if (err) { + ESP_LOGE(TAG, "Failed to discover CAS, err %d", err); + return err; + } + + ESP_LOGI(TAG, "Discovering CAS"); + + return 0; +} + +static int discover_sinks(void) +{ + int err; + + esp_ble_audio_cap_stream_ops_register(&peer.sink_stream, &unicast_stream_ops); + + err = esp_ble_audio_bap_unicast_client_discover(peer.conn_handle, ESP_BLE_AUDIO_DIR_SINK); + if (err) { + ESP_LOGE(TAG, "Failed to discover sinks, err %d", err); + return err; + } + + ESP_LOGI(TAG, "Discovering sinks"); + + return 0; +} + +static int discover_sources(void) +{ + int err; + + esp_ble_audio_cap_stream_ops_register(&peer.source_stream, &unicast_stream_ops); + + err = esp_ble_audio_bap_unicast_client_discover(peer.conn_handle, ESP_BLE_AUDIO_DIR_SOURCE); + if (err) { + ESP_LOGE(TAG, "Failed to discover sources, err %d", err); + return err; + } + + ESP_LOGI(TAG, "Discovering source ASEs"); + + return 0; +} + +static int unicast_group_create(void) +{ + esp_ble_audio_cap_unicast_group_stream_param_t source_stream_param = { + .qos_cfg = &unicast_preset_16_2_1.qos, + .stream = &peer.source_stream, + }; + esp_ble_audio_cap_unicast_group_stream_param_t sink_stream_param = { + .qos_cfg = &unicast_preset_16_2_1.qos, + .stream = &peer.sink_stream, + }; + esp_ble_audio_cap_unicast_group_stream_pair_param_t pair_params = {0}; + esp_ble_audio_cap_unicast_group_param_t group_param = {0}; + int err; + + if (peer.source_ep) { + pair_params.rx_param = &source_stream_param; + } + + if (peer.sink_ep) { + pair_params.tx_param = &sink_stream_param; + } + + group_param.params_count = 1; + group_param.params = &pair_params; + + err = esp_ble_audio_cap_unicast_group_create(&group_param, &unicast_group); + if (err) { + ESP_LOGE(TAG, "Failed to create unicast group, err %d", err); + return err; + } + + ESP_LOGI(TAG, "Created unicast group"); + + return 0; +} + +int unicast_group_delete(void) +{ + int err; + + if (unicast_group == NULL) { + return 0; + } + + err = esp_ble_audio_cap_unicast_group_delete(unicast_group); + if (err) { + ESP_LOGE(TAG, "Failed to delete unicast group, err %d", err); + return err; + } + + unicast_group = NULL; + + ESP_LOGI(TAG, "Deleted unicast group"); + + return 0; +} + +static int unicast_audio_start(void) +{ + esp_ble_audio_cap_unicast_audio_start_stream_param_t stream_param[2] = {0}; + esp_ble_audio_cap_unicast_audio_start_param_t param = {0}; + int err; + + if (peer.sink_ep) { + stream_param[param.count].member.member = peer.conn; + stream_param[param.count].stream = &peer.sink_stream; + stream_param[param.count].ep = peer.sink_ep; + stream_param[param.count].codec_cfg = &unicast_preset_16_2_1.codec_cfg; + param.count++; + } + + if (peer.source_ep) { + stream_param[param.count].member.member = peer.conn; + stream_param[param.count].stream = &peer.source_stream; + stream_param[param.count].ep = peer.source_ep; + stream_param[param.count].codec_cfg = &unicast_preset_16_2_1.codec_cfg; + param.count++; + } + + if (param.count == 0) { + ESP_LOGW(TAG, "No endpoints available, skip starting unicast audio"); + return 0; + } + + param.type = ESP_BLE_AUDIO_CAP_SET_TYPE_AD_HOC; + param.stream_params = stream_param; + + err = esp_ble_audio_cap_initiator_unicast_audio_start(¶m); + if (err) { + ESP_LOGE(TAG, "Failed to start unicast audio, err %d", err); + return err; + } + + ESP_LOGI(TAG, "Starting unicast streams"); + + return 0; +} + +static void discover_cb(esp_ble_conn_t *conn, int err, esp_ble_audio_dir_t dir) +{ + if (conn->handle != peer.conn_handle) { + return; + } + + peer.conn = conn; + + if (dir == ESP_BLE_AUDIO_DIR_SINK) { + if (err) { + ESP_LOGE(TAG, "Discovery sinks failed, err %d", err); + } else { + ESP_LOGI(TAG, "Discover sinks complete"); + + discover_sources(); + } + } else if (dir == ESP_BLE_AUDIO_DIR_SOURCE) { + if (err) { + ESP_LOGE(TAG, "Discovery sources failed, err %d", err); + } else { + ESP_LOGI(TAG, "Discover sources complete"); + + err = unicast_group_create(); + if (err) { + return; + } + + err = unicast_audio_start(); + if (err) { + unicast_group_delete(); + return; + } + } + } +} + +static void pac_record_cb(esp_ble_conn_t *conn, + esp_ble_audio_dir_t dir, + const esp_ble_audio_codec_cap_t *codec_cap) +{ + example_print_codec_cap(codec_cap); +} + +static void endpoint_cb(esp_ble_conn_t *conn, + esp_ble_audio_dir_t dir, + esp_ble_audio_bap_ep_t *ep) +{ + if (dir == ESP_BLE_AUDIO_DIR_SOURCE) { + if (peer.source_ep == NULL) { + ESP_LOGI(TAG, "Source ep: %p", ep); + peer.source_ep = ep; + } + } else if (dir == ESP_BLE_AUDIO_DIR_SINK) { + if (peer.sink_ep == NULL) { + ESP_LOGI(TAG, "Sink ep: %p", ep); + peer.sink_ep = ep; + } + } +} + +static esp_ble_audio_bap_unicast_client_cb_t unicast_client_cbs = { + .discover = discover_cb, + .pac_record = pac_record_cb, + .endpoint = endpoint_cb, +}; + +static void unicast_discovery_complete_cb(esp_ble_conn_t *conn, int err, + const esp_ble_audio_csip_set_coordinator_set_member_t *member, + const esp_ble_audio_csip_set_coordinator_csis_inst_t *csis_inst) +{ + if (err) { + ESP_LOGE(TAG, "Unicast discovery completed, err %d", err); + return; + } + + if (IS_ENABLED(CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER)) { + if (csis_inst == NULL) { + ESP_LOGW(TAG, "Failed to discover CAS CSIS"); + return; + } + + ESP_LOGI(TAG, "Found CAS with CSIS %p", csis_inst); + + /* TODO: Do set member discovery */ + } else { + ESP_LOGI(TAG, "Found CAS"); + } + + (void)discover_sinks(); +} + +static void unicast_start_complete_cb(int err, esp_ble_conn_t *conn) +{ + if (err) { + ESP_LOGE(TAG, "Unicast start completed, err %d", err); + } else { + ESP_LOGI(TAG, "Unicast start completed"); + } +} + +static esp_ble_audio_cap_initiator_cb_t cap_cb = { + .unicast_discovery_complete = unicast_discovery_complete_cb, + .unicast_start_complete = unicast_start_complete_cb, +}; + +static int conn_create(ble_addr_t *dst) +{ + struct ble_gap_conn_params params = {0}; + uint8_t own_addr_type = 0; + int err; + + err = ble_hs_id_infer_auto(0, &own_addr_type); + if (err) { + ESP_LOGE(TAG, "Failed to determine address type, err %d", err); + return err; + } + + err = ble_gap_disc_cancel(); + if (err) { + ESP_LOGE(TAG, "Failed to stop scanning, err %d", err); + return err; + } + + peer.disc_cancelled = true; + + params.scan_itvl = INIT_SCAN_INTERVAL; + params.scan_window = INIT_SCAN_WINDOW; + params.itvl_min = CONN_INTERVAL; + params.itvl_max = CONN_INTERVAL; + params.latency = CONN_LATENCY; + params.supervision_timeout = CONN_TIMEOUT; + params.max_ce_len = CONN_MAX_CE_LEN; + params.min_ce_len = CONN_MIN_CE_LEN; + + return ble_gap_connect(own_addr_type, dst, CONN_DURATION, ¶ms, + example_audio_gap_event_cb, NULL); +} + +static int pairing_start(uint16_t conn_handle) +{ + return ble_gap_security_initiate(conn_handle); +} + +static int exchange_mtu(uint16_t conn_handle) +{ + return ble_gattc_exchange_mtu(conn_handle, NULL, NULL); +} + +static bool check_and_connect(uint8_t type, const uint8_t *data, + uint8_t data_len, void *user_data) +{ + esp_ble_audio_gap_app_event_t *event; + ble_addr_t dst = {0}; + uint16_t uuid_val; + int err; + + event = user_data; + assert(event); + + if (type != EXAMPLE_AD_TYPE_SERVICE_DATA16) { + return true; /* Continue parsing to next AD data type */ + } + + if (data_len < sizeof(uuid_val)) { + ESP_LOGW(TAG, "Invalid ad size %u (cas uuid)", data_len); + return true; /* Continue parsing to next AD data type */ + } + + uuid_val = sys_get_le16(data); + + if (uuid_val != ESP_BLE_AUDIO_UUID_CAS_VAL) { + /* We are looking for the TMAS service data */ + return true; /* Continue parsing to next AD data type */ + } + + ESP_LOGI(TAG, "Found CAS in peer adv data!"); + + dst.type = event->ext_scan_recv.addr.type; + memcpy(dst.val, event->ext_scan_recv.addr.val, sizeof(dst.val)); + + err = conn_create(&dst); + if (err) { + ESP_LOGE(TAG, "Failed to create conn, err %d", err); + + if (peer.disc_cancelled) { + peer.disc_cancelled = false; + cap_initiator_unicast_start(); + } + } + + return false; /* Stop parsing */ +} + +static void ext_scan_recv(esp_ble_audio_gap_app_event_t *event) +{ + if (peer.conn_handle != CONN_HANDLE_INIT) { + return; + } + + /* Check if the advertising is connectable and if TMAS is supported */ + if (event->ext_scan_recv.event_type & EXAMPLE_ADV_PROP_CONNECTABLE) { + esp_ble_audio_data_parse(event->ext_scan_recv.data, + event->ext_scan_recv.data_len, + check_and_connect, (void *)event); + } +} + +static void acl_connect(esp_ble_audio_gap_app_event_t *event) +{ + int err; + + if (event->acl_connect.status) { + ESP_LOGE(TAG, "connection failed, status %d", event->acl_connect.status); + return; + } + + ESP_LOGI(TAG, "Conn established:"); + ESP_LOGI(TAG, "conn_handle 0x%04x status 0x%02x role %u peer %02x:%02x:%02x:%02x:%02x:%02x", + event->acl_connect.conn_handle, event->acl_connect.status, + event->acl_connect.role, event->acl_connect.dst.val[5], + event->acl_connect.dst.val[4], event->acl_connect.dst.val[3], + event->acl_connect.dst.val[2], event->acl_connect.dst.val[1], + event->acl_connect.dst.val[0]); + + err = pairing_start(event->acl_connect.conn_handle); + if (err) { + ESP_LOGE(TAG, "Failed to initiate security, err %d", err); + return; + } + + peer.conn_handle = event->acl_connect.conn_handle; +} + +static void acl_disconnect(esp_ble_audio_gap_app_event_t *event) +{ + ESP_LOGI(TAG, "Conn terminated: conn_handle 0x%04x reason 0x%02x", + event->acl_disconnect.conn_handle, event->acl_disconnect.reason); + + peer.conn_handle = CONN_HANDLE_INIT; + peer.conn = NULL; + peer.source_ep = NULL; + peer.sink_ep = NULL; + peer.disc_completed = false; + peer.disc_cancelled = false; + peer.mtu_exchanged = false; + + unicast_group_delete(); + + cap_initiator_unicast_start(); +} + +static void security_change(esp_ble_iso_gap_app_event_t *event) +{ + int err; + + if (event->security_change.status) { + ESP_LOGE(TAG, "security change failed, status %d", event->security_change.status); + return; + } + + ESP_LOGI(TAG, "Security change:"); + ESP_LOGI(TAG, "conn_handle 0x%04x status 0x%02x role %u sec_level %u bonded %u " + "peer %02x:%02x:%02x:%02x:%02x:%02x", + event->security_change.conn_handle, event->security_change.status, + event->security_change.role, event->security_change.sec_level, + event->security_change.bonded, event->security_change.dst.val[5], + event->security_change.dst.val[4], event->security_change.dst.val[3], + event->security_change.dst.val[2], event->security_change.dst.val[1], + event->security_change.dst.val[0]); + + err = exchange_mtu(event->security_change.conn_handle); + if (err) { + ESP_LOGE(TAG, "Failed to exchange MTU, err %d", err); + return; + } +} + +void cap_initiator_unicast_gap_cb(esp_ble_audio_gap_app_event_t *event) +{ + switch (event->type) { + case ESP_BLE_AUDIO_GAP_EVENT_EXT_SCAN_RECV: + ext_scan_recv(event); + break; + case ESP_BLE_AUDIO_GAP_EVENT_ACL_CONNECT: + acl_connect(event); + break; + case ESP_BLE_AUDIO_GAP_EVENT_ACL_DISCONNECT: + acl_disconnect(event); + break; + case ESP_BLE_AUDIO_GAP_EVENT_SECURITY_CHANGE: + security_change(event); + break; + default: + break; + } +} + +static void gatt_mtu_change(esp_ble_audio_gatt_app_event_t *event) +{ + int err; + + ESP_LOGI(TAG, "gatt mtu change, conn_handle %u, mtu %u", + event->gatt_mtu_change.conn_handle, event->gatt_mtu_change.mtu); + + if (event->gatt_mtu_change.mtu < ESP_BLE_AUDIO_ATT_MTU_MIN) { + ESP_LOGW(TAG, "Invalid new mtu %u, shall be at least %u", + event->gatt_mtu_change.mtu, ESP_BLE_AUDIO_ATT_MTU_MIN); + return; + } + + err = esp_ble_audio_gattc_disc_start(event->gatt_mtu_change.conn_handle); + if (err) { + ESP_LOGE(TAG, "Failed to start svc disc, err %d", err); + return; + } + + ESP_LOGI(TAG, "Start discovering gatt services"); + + /* Note: + * MTU exchanged event may arrived after discover completed event. + */ + peer.mtu_exchanged = true; + + if (peer.disc_completed) { + (void)discover_cas(); + } +} + +static void gattc_disc_cmpl(esp_ble_audio_gatt_app_event_t *event) +{ + ESP_LOGI(TAG, "gattc disc cmpl, status %u, conn_handle %u", + event->gattc_disc_cmpl.status, event->gattc_disc_cmpl.conn_handle); + + if (event->gattc_disc_cmpl.status) { + ESP_LOGE(TAG, "gattc disc failed, status %u", event->gattc_disc_cmpl.status); + return; + } + + /* Note: + * Discover completed event may arrived before MTU exchanged event. + */ + peer.disc_completed = true; + + if (peer.mtu_exchanged) { + (void)discover_cas(); + } +} + +void cap_initiator_unicast_gatt_cb(esp_ble_audio_gatt_app_event_t *event) +{ + switch (event->type) { + case ESP_BLE_AUDIO_GATT_EVENT_GATT_MTU_CHANGE: + gatt_mtu_change(event); + break; + case ESP_BLE_AUDIO_GATT_EVENT_GATTC_DISC_CMPL: + gattc_disc_cmpl(event); + break; + default: + break; + } +} + +int cap_initiator_unicast_start(void) +{ + struct ble_gap_disc_params params = {0}; + uint8_t own_addr_type; + int err; + + err = ble_hs_id_infer_auto(0, &own_addr_type); + if (err) { + ESP_LOGE(TAG, "Failed to determine own addr type, err %d", err); + return err; + } + + params.passive = 1; + params.itvl = SCAN_INTERVAL; + params.window = SCAN_WINDOW; + + err = ble_gap_disc(own_addr_type, BLE_HS_FOREVER, ¶ms, + example_audio_gap_event_cb, NULL); + if (err) { + ESP_LOGE(TAG, "Failed to start scanning, err %d", err); + return err; + } + + ESP_LOGI(TAG, "Extended scan started"); + return 0; +} + +int cap_initiator_unicast_init(void) +{ + int err; + + err = esp_ble_audio_cap_initiator_register_cb(&cap_cb); + if (err) { + ESP_LOGE(TAG, "Failed to register CAP callbacks, err %d", err); + return err; + } + + err = esp_ble_audio_bap_unicast_client_register_cb(&unicast_client_cbs); + if (err) { + ESP_LOGE(TAG, "Failed to register BAP unicast client callbacks, err %d", err); + return err; + } + + ESP_LOGI(TAG, "CAP initiator unicast initialized"); + + return 0; +} diff --git a/examples/bluetooth/esp_ble_audio/cap/initiator/main/idf_component.yml b/examples/bluetooth/esp_ble_audio/cap/initiator/main/idf_component.yml new file mode 100644 index 0000000000..bb02c0922a --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/cap/initiator/main/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + example_init: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_audio/common_components/example_init + example_utils: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_audio/common_components/example_utils diff --git a/examples/bluetooth/esp_ble_audio/cap/initiator/main/main.c b/examples/bluetooth/esp_ble_audio/cap/initiator/main/main.c new file mode 100644 index 0000000000..676e2fb819 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/cap/initiator/main/main.c @@ -0,0 +1,90 @@ +/* + * SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include "nvs_flash.h" +#include "esp_system.h" + +#include "cap_initiator.h" + +void app_main(void) +{ + esp_ble_audio_init_info_t info = { +#if CONFIG_EXAMPLE_UNICAST + .gap_cb = cap_initiator_unicast_gap_cb, + .gatt_cb = cap_initiator_unicast_gatt_cb, +#endif /* CONFIG_EXAMPLE_UNICAST */ + }; + esp_err_t err; + + /* Initialize NVS — it is used to store PHY calibration data */ + err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK(err); + + err = bluetooth_init(); + if (err) { + ESP_LOGE(TAG, "Failed to initialize BLE, err %d", err); + return; + } + + err = esp_ble_audio_common_init(&info); + if (err) { + ESP_LOGE(TAG, "Failed to initialize audio, err %d", err); + return; + } + +#if CONFIG_EXAMPLE_UNICAST + err = cap_initiator_unicast_init(); + if (err) { + return; + } +#endif /* CONFIG_EXAMPLE_UNICAST */ + +#if CONFIG_EXAMPLE_BROADCAST + err = cap_initiator_broadcast_init(); + if (err) { + return; + } +#endif /* CONFIG_EXAMPLE_BROADCAST */ + + cap_initiator_tx_init(); + + err = esp_ble_audio_common_start(NULL); + if (err) { + ESP_LOGE(TAG, "Failed to start audio, err %d", err); + return; + } + + err = ble_svc_gap_device_name_set("CAP Initiator"); + if (err) { + ESP_LOGE(TAG, "Failed to set device name, err %d", err); + return; + } + +#if CONFIG_EXAMPLE_UNICAST + err = cap_initiator_unicast_start(); + if (err) { + return; + } +#endif /* CONFIG_EXAMPLE_UNICAST */ + +#if CONFIG_EXAMPLE_BROADCAST + err = cap_initiator_broadcast_start(); + if (err) { + return; + } +#endif /* CONFIG_EXAMPLE_BROADCAST */ +} diff --git a/examples/bluetooth/esp_ble_audio/cap/initiator/sdkconfig.defaults b/examples/bluetooth/esp_ble_audio/cap/initiator/sdkconfig.defaults new file mode 100644 index 0000000000..dee60d5a22 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/cap/initiator/sdkconfig.defaults @@ -0,0 +1,24 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration +# + +CONFIG_BT_ENABLED=y +CONFIG_BT_BLUEDROID_ENABLED=n +CONFIG_BT_NIMBLE_ENABLED=y +CONFIG_BT_NIMBLE_EXT_ADV=y +CONFIG_BT_NIMBLE_MAX_CONNECTIONS=1 +CONFIG_BT_NIMBLE_MAX_CCCDS=20 +CONFIG_BT_NIMBLE_ISO=y +CONFIG_BT_NIMBLE_LOG_LEVEL_WARNING=y + +CONFIG_BT_ISO_MAX_CHAN=2 + +CONFIG_BT_CAP_INITIATOR=y +CONFIG_BT_BAP_UNICAST_CLIENT=y +CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT=2 +CONFIG_BT_BAP_BROADCAST_SOURCE=y +CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT=2 + +CONFIG_EXAMPLE_UNICAST=y + +CONFIG_FREERTOS_HZ=1000 diff --git a/examples/bluetooth/esp_ble_audio/cap/initiator/sdkconfig.defaults.esp32h4 b/examples/bluetooth/esp_ble_audio/cap/initiator/sdkconfig.defaults.esp32h4 new file mode 100644 index 0000000000..5920ce3f85 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/cap/initiator/sdkconfig.defaults.esp32h4 @@ -0,0 +1,6 @@ +# Override some defaults so BT stack is enabled +# by default in this example + +CONFIG_IDF_TARGET="esp32h4" + +CONFIG_BT_LE_ISO_SUPPORT=y diff --git a/examples/bluetooth/esp_ble_audio/common_components/example_init/CMakeLists.txt b/examples/bluetooth/esp_ble_audio/common_components/example_init/CMakeLists.txt new file mode 100644 index 0000000000..a274023961 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/common_components/example_init/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "ble_audio_example_init.c" + INCLUDE_DIRS "." + REQUIRES bt) diff --git a/examples/bluetooth/esp_ble_audio/common_components/example_init/ble_audio_example_init.c b/examples/bluetooth/esp_ble_audio/common_components/example_init/ble_audio_example_init.c new file mode 100644 index 0000000000..1607ee4b62 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/common_components/example_init/ble_audio_example_init.c @@ -0,0 +1,123 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "esp_log.h" +#include "sdkconfig.h" + +#include "nimble/nimble_port.h" +#include "nimble/nimble_port_freertos.h" + +#include "host/ble_hs.h" +#include "host/ble_gap.h" +#include "host/ble_gatt.h" +#include "host/util/util.h" + +#include "services/gap/ble_svc_gap.h" +#include "services/gatt/ble_svc_gatt.h" + +#define TAG "INIT" + +static SemaphoreHandle_t example_audio_sem; + +void ble_store_config_init(void); + +static void example_audio_gatt_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg) +{ + char buf[BLE_UUID_STR_LEN]; + + switch (ctxt->op) { + case BLE_GATT_REGISTER_OP_SVC: + ESP_LOGI(TAG, "Register svc %s, handle %u", + ble_uuid_to_str(ctxt->svc.svc_def->uuid, buf), + ctxt->svc.handle); + break; + + case BLE_GATT_REGISTER_OP_CHR: + ESP_LOGI(TAG, "Register chr %s, handles %u/%u", + ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf), + ctxt->chr.def_handle, ctxt->chr.val_handle); + break; + + case BLE_GATT_REGISTER_OP_DSC: + ESP_LOGI(TAG, "Register dsc %s, handle %u", + ble_uuid_to_str(ctxt->dsc.dsc_def->uuid, buf), ctxt->dsc.handle); + break; + + default: + assert(0); + break; + } +} + +static void example_audio_on_reset(int reason) +{ + ESP_LOGI(TAG, "Resetting state; reason=%d", reason); +} + +static void example_audio_on_sync(void) +{ + int rc; + + rc = ble_hs_util_ensure_addr(0); + assert(rc == 0); + + xSemaphoreGive(example_audio_sem); +} + +static void example_audio_host_task(void *param) +{ + ESP_LOGI(TAG, "BLE Host Task Started"); + + /* This function will return only when nimble_port_stop() is executed */ + nimble_port_run(); + + nimble_port_freertos_deinit(); +} + +esp_err_t bluetooth_init(void) +{ + esp_err_t ret; + + example_audio_sem = xSemaphoreCreateBinary(); + if (example_audio_sem == NULL) { + ESP_LOGE(TAG, "Failed to create audio semaphore"); + return ESP_FAIL; + } + + ret = nimble_port_init(); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to init nimble %d ", ret); + vSemaphoreDelete(example_audio_sem); + example_audio_sem = NULL; + return ret; + } + + /* Initialize the NimBLE host configuration */ + ble_hs_cfg.gatts_register_cb = example_audio_gatt_register_cb; + ble_hs_cfg.reset_cb = example_audio_on_reset; + ble_hs_cfg.sync_cb = example_audio_on_sync; + ble_hs_cfg.store_status_cb = ble_store_util_status_rr; +#if 0 + ble_hs_cfg.sm_our_key_dist = 1; + ble_hs_cfg.sm_their_key_dist = 1; + ble_hs_cfg.sm_sc = 1; + ble_hs_cfg.sm_mitm = 0; + ble_hs_cfg.sm_bonding = 1; + ble_hs_cfg.sm_io_cap = BLE_SM_IO_CAP_NO_IO; +#endif + + /* XXX Need to have template for store */ + ble_store_config_init(); + + nimble_port_freertos_init(example_audio_host_task); + + xSemaphoreTake(example_audio_sem, portMAX_DELAY); + + return ESP_OK; +} diff --git a/examples/bluetooth/esp_ble_audio/common_components/example_init/ble_audio_example_init.h b/examples/bluetooth/esp_ble_audio/common_components/example_init/ble_audio_example_init.h new file mode 100644 index 0000000000..65a57cf8e0 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/common_components/example_init/ble_audio_example_init.h @@ -0,0 +1,14 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef BLE_AUDIO_EXAMPLE_INIT_H_ +#define BLE_AUDIO_EXAMPLE_INIT_H_ + +#include "esp_err.h" + +esp_err_t bluetooth_init(void); + +#endif /* BLE_AUDIO_EXAMPLE_INIT_H_ */ diff --git a/examples/bluetooth/esp_ble_audio/common_components/example_utils/CMakeLists.txt b/examples/bluetooth/esp_ble_audio/common_components/example_utils/CMakeLists.txt new file mode 100644 index 0000000000..1afb90778a --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/common_components/example_utils/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "ble_audio_example_utils.c" + INCLUDE_DIRS "." + REQUIRES bt esp_timer freertos) diff --git a/examples/bluetooth/esp_ble_audio/common_components/example_utils/ble_audio_example_utils.c b/examples/bluetooth/esp_ble_audio/common_components/example_utils/ble_audio_example_utils.c new file mode 100644 index 0000000000..993740d23f --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/common_components/example_utils/ble_audio_example_utils.c @@ -0,0 +1,344 @@ +/* + * SPDX-FileCopyrightText: 2021-2024 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2024 Demant A/S + * SPDX-FileCopyrightText: 2015-2016 Intel Corporation + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include "esp_log.h" + +#include "ble_audio_example_utils.h" + +#include "esp_ble_audio_common_api.h" + +#define TAG "UTILS" + +#define LOG_GREEN "\033[0;" "32" "m" +#define LOG_RESET "\033[0m" + +int example_audio_gap_event_cb(struct ble_gap_event *event, void *arg) +{ + if (event->type == BLE_GAP_EVENT_EXT_DISC || + event->type == BLE_GAP_EVENT_PERIODIC_SYNC || + event->type == BLE_GAP_EVENT_PERIODIC_REPORT || + event->type == BLE_GAP_EVENT_PERIODIC_SYNC_LOST || + event->type == BLE_GAP_EVENT_CONNECT || + event->type == BLE_GAP_EVENT_DISCONNECT || + event->type == BLE_GAP_EVENT_ENC_CHANGE) { + esp_ble_audio_gap_app_post_event(event->type, event); + } else if (event->type == BLE_GAP_EVENT_MTU || + event->type == BLE_GAP_EVENT_NOTIFY_RX || + event->type == BLE_GAP_EVENT_NOTIFY_TX || + event->type == BLE_GAP_EVENT_SUBSCRIBE) { + esp_ble_audio_gatt_app_post_event(event->type, event); + } + + return 0; +} + +static void print_hex(const uint8_t *ptr, size_t len) +{ + while (len--) { + printf(LOG_GREEN "%02x" LOG_RESET, *ptr++); + } +} + +static bool print_cb(uint8_t type, const uint8_t *data, + uint8_t data_len, void *user_data) +{ + const char *str = (const char *)user_data; + + printf(LOG_GREEN "I (%lu) %s: %s, type 0x%02x len %u data " LOG_RESET, + esp_log_timestamp(), TAG, str, type, data_len); + print_hex(data, data_len); + printf("\n"); + + return true; +} + +void example_print_codec_cfg(const esp_ble_audio_codec_cfg_t *codec_cfg) +{ + esp_err_t err; + + ESP_LOGI(TAG, "codec_cfg, id 0x%02x cid 0x%04x vid 0x%04x count %u", + codec_cfg->id, codec_cfg->cid, + codec_cfg->vid, codec_cfg->data_len); + + if (codec_cfg->id == ESP_BLE_ISO_CODING_FORMAT_LC3) { + esp_ble_audio_codec_cfg_frame_dur_t frame_dur; + esp_ble_audio_location_t chan_allocation; + esp_ble_audio_codec_cfg_freq_t freq; + uint16_t octets_per_frame; + uint32_t frame_dur_us; + uint8_t frame_blocks; + uint32_t freq_hz; + + /* LC3 uses the generic LTV format - other codecs might do as well */ + + err = esp_ble_audio_data_parse(codec_cfg->data, codec_cfg->data_len, print_cb, "data"); + if (err) { + ESP_LOGE(TAG, "Failed to parse codec_cfg data"); + return; + } + + err = esp_ble_audio_codec_cfg_get_freq(codec_cfg, &freq); + if (err) { + ESP_LOGE(TAG, "Failed to get frequency"); + return; + } + + err = esp_ble_audio_codec_cfg_freq_to_freq_hz(freq, &freq_hz); + if (err) { + ESP_LOGE(TAG, "Failed to get frequency hz"); + return; + } + + ESP_LOGI(TAG, "Frequency: %lu Hz", freq_hz); + + err = esp_ble_audio_codec_cfg_get_frame_dur(codec_cfg, &frame_dur); + if (err) { + ESP_LOGE(TAG, "Failed to get frame duration"); + return; + } + + err = esp_ble_audio_codec_cfg_frame_dur_to_frame_dur_us(frame_dur, &frame_dur_us); + if (err) { + ESP_LOGE(TAG, "Failed to get frame duration us"); + return; + } + + ESP_LOGI(TAG, "Frame Duration: %lu us", frame_dur_us); + + err = esp_ble_audio_codec_cfg_get_chan_allocation(codec_cfg, &chan_allocation, false); + if (err) { + ESP_LOGE(TAG, "Failed to get channel allocation"); + return; + } + + ESP_LOGI(TAG, "Channel allocation: 0x%08lx", chan_allocation); + + err = esp_ble_audio_codec_cfg_get_octets_per_frame(codec_cfg, &octets_per_frame); + if (err) { + ESP_LOGE(TAG, "Failed to get octets per frame"); + return; + } + + ESP_LOGI(TAG, "Octets per frame: %u", octets_per_frame); + + err = esp_ble_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, &frame_blocks, true); + if (err) { + ESP_LOGE(TAG, "Failed to get frame blocks per sdu"); + return; + } + + ESP_LOGI(TAG, "Frames per SDU: %u", frame_blocks); + } else { + print_hex(codec_cfg->data, codec_cfg->data_len); + } + + err = esp_ble_audio_data_parse(codec_cfg->meta, codec_cfg->meta_len, print_cb, "meta"); + if (err) { + ESP_LOGE(TAG, "Failed to parse codec_cfg meta"); + return; + } +} + +void example_print_codec_cap(const esp_ble_audio_codec_cap_t *codec_cap) +{ + esp_err_t err; + + ESP_LOGI(TAG, "codec_cap, id 0x%02x cid 0x%04x vid 0x%04x count %u", + codec_cap->id, codec_cap->cid, + codec_cap->vid, codec_cap->data_len); + + if (codec_cap->id == ESP_BLE_ISO_CODING_FORMAT_LC3) { + err = esp_ble_audio_data_parse(codec_cap->data, codec_cap->data_len, print_cb, "data"); + if (err) { + ESP_LOGE(TAG, "Failed to parse codec_cap data"); + return; + } + } else { + printf(LOG_GREEN "I (%lu) %s: data: " LOG_RESET, esp_log_timestamp(), TAG); + print_hex(codec_cap->data, codec_cap->data_len); + printf("\n"); + } + + err = esp_ble_audio_data_parse(codec_cap->meta, codec_cap->meta_len, print_cb, "meta"); + if (err) { + ESP_LOGE(TAG, "Failed to parse codec_cap meta"); + return; + } +} + +void example_print_qos(const esp_ble_audio_bap_qos_cfg_t *qos) +{ + ESP_LOGI(TAG, "QoS: interval %u framing 0x%02x phy 0x%02x", qos->interval, qos->framing, qos->phy); + ESP_LOGI(TAG, " sdu %u rtn %u latency %u pd %u", qos->sdu, qos->rtn, qos->latency, qos->pd); +} + +void example_print_qos_pref(const esp_ble_audio_bap_qos_cfg_pref_t *pref) +{ + ESP_LOGI(TAG, "QoS pref: unframed %s, phy %u, rtn %u, latency %u", + pref->unframed_supported ? "supported" : "not supported", + pref->phy, pref->rtn, pref->latency); + ESP_LOGI(TAG, " pd_min %u, pd_max %u", + pref->pd_min, pref->pd_max); + ESP_LOGI(TAG, " pref_pd_min %u, pref_pd_max %u", + pref->pref_pd_min, pref->pref_pd_max); +} + +bool example_is_substring(const char *substr, const char *str) +{ + const size_t sub_str_len = strlen(substr); + const size_t str_len = strlen(str); + + if (sub_str_len > str_len) { + return false; + } + + for (size_t pos = 0; pos < str_len; pos++) { + if (pos + sub_str_len > str_len) { + return false; + } + + if (strncasecmp(substr, &str[pos], sub_str_len) == 0) { + return true; + } + } + + return false; +} + +static void example_audio_tx_work_handler(struct k_work *work) +{ + example_audio_tx_scheduler_t *scheduler = work->user_data; + size_t count; + + assert(scheduler); + assert(scheduler->cb); + + count = 1 + scheduler->drift; + scheduler->drift = 0; + + for (size_t i = 0; i < count; i++) { + scheduler->cb(scheduler->arg); + } +} + +int example_audio_tx_scheduler_init(example_audio_tx_scheduler_t *scheduler, + example_audio_tx_send_cb_t cb, + void *arg) +{ + assert(scheduler); + assert(cb); + + memset(scheduler, 0, sizeof(*scheduler)); + scheduler->cb = cb; + scheduler->arg = arg; + + k_work_init_delayable(&scheduler->timer, example_audio_tx_work_handler); + scheduler->timer.work.user_data = scheduler; + + return 0; +} + +void example_audio_tx_scheduler_reset(example_audio_tx_scheduler_t *scheduler) +{ + assert(scheduler); + + scheduler->drift = 0; + scheduler->count = 0; +} + +int example_audio_tx_scheduler_start(example_audio_tx_scheduler_t *scheduler, + uint64_t period_us) +{ + assert(scheduler); + assert(period_us > 0); + + return k_work_schedule_periodic(&scheduler->timer, (uint32_t)(period_us / 1000)); +} + +int example_audio_tx_scheduler_stop(example_audio_tx_scheduler_t *scheduler) +{ + assert(scheduler); + + return k_work_cancel_delayable(&scheduler->timer); +} + +void example_audio_tx_scheduler_on_sent(example_audio_tx_scheduler_t *scheduler, + const esp_ble_iso_tx_cb_info_t *info, + const char *tag, + const char *obj_name, + const void *obj) +{ + size_t drift_count = 0; + + assert(scheduler); + assert(info); + + for (size_t i = 0; i < info->pkt_cnt; i++) { + if (info->pkt[i].drift) { + drift_count++; + } + } + + scheduler->drift += drift_count; + scheduler->count++; + + if (scheduler->count % 1000 == 0) { + ESP_LOGI(tag, "Transmitted %u ISO data packets (%s %p)", + scheduler->count, (obj_name ? obj_name : ""), obj); + } +} + +void example_audio_rx_metrics_reset(example_audio_rx_metrics_t *metrics) +{ + assert(metrics); + + metrics->recv_count = 0; + metrics->valid_count = 0; + metrics->error_count = 0; + metrics->lost_count = 0; + metrics->null_sdu_count = 0; + metrics->last_sdu_len = 0; +} + +void example_audio_rx_metrics_on_recv(const esp_ble_iso_recv_info_t *info, + example_audio_rx_metrics_t *metrics, + const char *tag, + const char *obj_name, + const void *obj) +{ + assert(info); + assert(metrics); + + if (info->flags & ESP_BLE_ISO_FLAGS_ERROR) { + metrics->error_count++; + } + + if (info->flags & ESP_BLE_ISO_FLAGS_LOST) { + metrics->lost_count++; + } + + if (info->flags & ESP_BLE_ISO_FLAGS_VALID) { + metrics->valid_count++; + if (metrics->last_sdu_len == 0) { + metrics->null_sdu_count++; + } + } + + metrics->recv_count++; + + if (metrics->recv_count % 1000 == 0) { + ESP_LOGI(tag, "Received %u ISO data packets (%s %p)", + metrics->recv_count, (obj_name ? obj_name : ""), obj); + } +} diff --git a/examples/bluetooth/esp_ble_audio/common_components/example_utils/ble_audio_example_utils.h b/examples/bluetooth/esp_ble_audio/common_components/example_utils/ble_audio_example_utils.h new file mode 100644 index 0000000000..d083222ab7 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/common_components/example_utils/ble_audio_example_utils.h @@ -0,0 +1,118 @@ +/* + * SPDX-FileCopyrightText: 2021-2024 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2024 Demant A/S + * SPDX-FileCopyrightText: 2015-2016 Intel Corporation + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef BLE_AUDIO_EXAMPLE_UTILS_H_ +#define BLE_AUDIO_EXAMPLE_UTILS_H_ + +#include +#include + +#include "sdkconfig.h" + +#include "esp_err.h" + +#include "zephyr/kernel.h" + +#include "host/ble_gap.h" +#include "host/ble_hs_adv.h" + +#include "esp_ble_audio_bap_api.h" + +#define EXAMPLE_AD_TYPE_FLAGS BT_DATA_FLAGS +#define EXAMPLE_AD_TYPE_UUID16_SOME BT_DATA_UUID16_SOME +#define EXAMPLE_AD_TYPE_UUID16_ALL BT_DATA_UUID16_ALL +#define EXAMPLE_AD_TYPE_NAME_SHORTENED BT_DATA_NAME_SHORTENED +#define EXAMPLE_AD_TYPE_NAME_COMPLETE BT_DATA_NAME_COMPLETE +#define EXAMPLE_AD_TYPE_SERVICE_DATA16 BT_DATA_SVC_DATA16 +#define EXAMPLE_AD_TYPE_GAP_APPEARANCE BT_DATA_GAP_APPEARANCE +#define EXAMPLE_AD_TYPE_CSIS_RSI BT_DATA_CSIS_RSI +#define EXAMPLE_AD_TYPE_BROADCAST_NAME BT_DATA_BROADCAST_NAME + +#define EXAMPLE_AD_FLAGS_LIMITED BT_LE_AD_LIMITED +#define EXAMPLE_AD_FLAGS_GENERAL BT_LE_AD_GENERAL +#define EXAMPLE_AD_FLAGS_NO_BREDR BT_LE_AD_NO_BREDR + +#define EXAMPLE_ADV_PROP_CONNECTABLE BT_GAP_ADV_PROP_CONNECTABLE +#define EXAMPLE_ADV_PROP_SCANNABLE BT_GAP_ADV_PROP_SCANNABLE +#define EXAMPLE_ADV_PROP_DIRECTED BT_GAP_ADV_PROP_DIRECTED +#define EXAMPLE_ADV_PROP_SCAN_RESPONSE BT_GAP_ADV_PROP_SCAN_RESPONSE +#define EXAMPLE_ADV_PROP_EXT_ADV BT_GAP_ADV_PROP_EXT_ADV + +#define EXAMPLE_BYTES_LIST_LE16 BT_BYTES_LIST_LE16 +#define EXAMPLE_BYTES_LIST_LE24 BT_BYTES_LIST_LE24 +#define EXAMPLE_BYTES_LIST_LE32 BT_BYTES_LIST_LE32 +#define EXAMPLE_BYTES_LIST_LE40 BT_BYTES_LIST_LE40 +#define EXAMPLE_BYTES_LIST_LE48 BT_BYTES_LIST_LE48 +#define EXAMPLE_BYTES_LIST_LE64 BT_BYTES_LIST_LE64 + +int example_audio_gap_event_cb(struct ble_gap_event *event, void *arg); + +void example_print_codec_cfg(const esp_ble_audio_codec_cfg_t *codec_cfg); + +void example_print_codec_cap(const esp_ble_audio_codec_cap_t *codec_cap); + +void example_print_qos(const esp_ble_audio_bap_qos_cfg_t *qos); + +void example_print_qos_pref(const esp_ble_audio_bap_qos_cfg_pref_t *pref); + +bool example_is_substring(const char *substr, const char *str); + +/** + * @brief TX scheduler for periodic audio data transmission. + * + * Uses k_work_delayable to schedule send callbacks in the ISO task context, + * ensuring thread safety without mutexes since both the timer handler and + * BLE audio callbacks execute in the same task. + */ +typedef void (*example_audio_tx_send_cb_t)(void *ctx); + +typedef struct { + struct k_work_delayable timer; + size_t drift; + uint32_t count; + /* Called periodically in ISO task context to transmit data */ + example_audio_tx_send_cb_t cb; + void *arg; +} example_audio_tx_scheduler_t; + +typedef struct { + uint32_t recv_count; + uint32_t valid_count; + uint32_t error_count; + uint32_t lost_count; + uint32_t null_sdu_count; + uint16_t last_sdu_len; +} example_audio_rx_metrics_t; + +int example_audio_tx_scheduler_init(example_audio_tx_scheduler_t *scheduler, + example_audio_tx_send_cb_t cb, + void *arg); + +void example_audio_tx_scheduler_reset(example_audio_tx_scheduler_t *scheduler); + +int example_audio_tx_scheduler_start(example_audio_tx_scheduler_t *scheduler, + uint64_t period_us); + +int example_audio_tx_scheduler_stop(example_audio_tx_scheduler_t *scheduler); + +void example_audio_tx_scheduler_on_sent(example_audio_tx_scheduler_t *scheduler, + const esp_ble_iso_tx_cb_info_t *info, + const char *tag, + const char *obj_name, + const void *obj); + +void example_audio_rx_metrics_reset(example_audio_rx_metrics_t *metrics); + +void example_audio_rx_metrics_on_recv(const esp_ble_iso_recv_info_t *info, + example_audio_rx_metrics_t *metrics, + const char *tag, + const char *obj_name, + const void *obj); + +#endif /* BLE_AUDIO_EXAMPLE_UTILS_H_ */ diff --git a/examples/bluetooth/esp_ble_audio/tmap/bmr/CMakeLists.txt b/examples/bluetooth/esp_ble_audio/tmap/bmr/CMakeLists.txt new file mode 100644 index 0000000000..cd833f18d2 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/bmr/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.22) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +idf_build_set_property(MINIMAL_BUILD ON) +project(tmap_bmr) diff --git a/examples/bluetooth/esp_ble_audio/tmap/bmr/README.md b/examples/bluetooth/esp_ble_audio/tmap/bmr/README.md new file mode 100644 index 0000000000..9e9bfc4990 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/bmr/README.md @@ -0,0 +1,62 @@ +| Supported Targets | ESP32-H4 | +| ----------------- | -------- | + +# TMAP Broadcast Media Receiver (BMR) Example + +(See the README.md file in the upper level `examples` directory for more information about examples.) + +This example implements the **Telephone and Media Audio Profile (TMAP) Broadcast Media Receiver (BMR)** role. The BMR scans for broadcast sources that advertise both the Broadcast Audio service (broadcast ID) and the TMAP role TMAS with **BMS (Broadcast Media Sender)**. When such a source is found, it establishes periodic advertising sync, creates a BAP Broadcast Sink, and synchronizes to the BIG to receive broadcast audio. It also registers as a **VCP Volume Renderer** (Volume Control Profile) for local volume and mute. The BMR can work with a TMAP BMS or any BAP Broadcast Source that includes the TMAP BMS role in advertising (e.g. a device running the [broadcast_source](../../bap/broadcast_source) or [CAP initiator](../../cap/initiator) in broadcast mode, if configured as BMS). + +The implementation uses the NimBLE host stack with ISO and LE Audio support, ESP-BLE-AUDIO (TMAP BMR role, VCP volume renderer, PACS sink, BAP broadcast sink, BAP scan delegator). PACS advertises LC3 sink capability (e.g. 48 kHz, 10 ms, mono, media context). After startup the device starts scanning; on matching scan results it creates PA sync, then creates the broadcast sink and syncs to the BIS streams; received audio is counted in the stream recv callback. + +## Requirements + +* A board with Bluetooth LE 5.2, ISO, and LE Audio support (e.g. ESP32-H4) +* A broadcast source that advertises as TMAP BMS (Broadcast Media Sender) and sends broadcast audio (e.g. another board running a broadcast source example with TMAP BMS role) + +## How to Use Example + +Before project configuration and build, set the correct chip target: + +```bash +idf.py set-target esp32h4 +``` + +### Build and Flash + +Run the following to build, flash and monitor: + +```bash +idf.py -p PORT flash monitor +``` + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the [Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF. + +## Example Flow + +1. **Initialization**: NVS, Bluetooth stack, and LE Audio common layer (`esp_ble_audio_common_init`) with GAP callback. Register TMAP role BMR (`esp_ble_audio_tmap_register(ESP_BLE_AUDIO_TMAP_ROLE_BMR)`). Register VCP Volume Renderer (volume step, mute, volume, state/flags callbacks). Initialize BAP broadcast sink: register PACS (sink only), register broadcast sink callbacks (base_recv, syncable), register PACS sink capability (LC3), register scan delegator callbacks, set stream ops (started, stopped, recv). Start the audio stack. +2. **Scanning**: Start extended scanning. On scan result, parse for Broadcast Audio UUID (broadcast ID) and TMAS with BMS role; if both found and not already syncing, create periodic advertising sync with the source. +3. **PA sync**: When PA sync is established, stop scanning, create the BAP broadcast sink for the sync handle and broadcast ID. When BASE is received (base_recv), extract BIS indexes; when syncable callback is invoked, sync to the BIG with the chosen BIS and stream pointers. +4. **Streaming**: When streams start, reset packet counters. Received ISO SDUs are delivered in the stream recv callback; the example counts valid, error, lost, and zero-length SDU and logs periodically. +5. **VCP**: The Volume Renderer exposes volume and mute state; VCS state/flags callbacks log volume and mute changes when queried. + +## Example Output + +``` +I (xxx) TMAP_BMR: Found TMAP BMS +I (xxx) TMAP_BMR: PA synced, handle 0x... status 0x00 +I (xxx) TMAP_BMR: PA sync ... synced with broadcast ID 0x... +I (xxx) TMAP_BMR: Broadcast source PA synced, waiting for BASE +I (xxx) TMAP_BMR: BASE received, creating broadcast sink +I (xxx) TMAP_BMR: Stream 0x... started +I (xxx) TMAP_BMR: Received 1000(...) ISO data packets (stream 0x...) +... +``` + +If PA sync is lost: + +``` +I (xxx) TMAP_BMR: PA sync lost, handle 0x... reason ... +``` diff --git a/examples/bluetooth/esp_ble_audio/tmap/bmr/main/CMakeLists.txt b/examples/bluetooth/esp_ble_audio/tmap/bmr/main/CMakeLists.txt new file mode 100644 index 0000000000..befc7314e9 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/bmr/main/CMakeLists.txt @@ -0,0 +1,6 @@ +set(srcs "bap_broadcast_sink.c" + "vcp_vol_renderer.c" + "main.c") + +idf_component_register(SRCS "${srcs}" + REQUIRES bt nvs_flash) diff --git a/examples/bluetooth/esp_ble_audio/tmap/bmr/main/bap_broadcast_sink.c b/examples/bluetooth/esp_ble_audio/tmap/bmr/main/bap_broadcast_sink.c new file mode 100644 index 0000000000..41b6c45873 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/bmr/main/bap_broadcast_sink.c @@ -0,0 +1,350 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2023 NXP + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "tmap_bmr.h" + +#define SCAN_INTERVAL 160 /* 100ms */ +#define SCAN_WINDOW 160 /* 100ms */ + +#define PA_SYNC_SKIP 0 +#define PA_SYNC_TIMEOUT 1000 /* 1000 * 10ms = 10s */ +#define PA_SYNC_HANDLE_INIT UINT16_MAX + +static uint16_t sync_handle = PA_SYNC_HANDLE_INIT; +static bool pa_syncing; + +static bool tmap_bms_found; + +static esp_ble_audio_bap_broadcast_sink_t *broadcast_sink; +static uint32_t bcast_id; + +static esp_ble_audio_bap_stream_t streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT]; +static esp_ble_audio_bap_stream_t *streams_p[ARRAY_SIZE(streams)]; + +static uint8_t codec_data[] = + ESP_BLE_AUDIO_CODEC_CAP_LC3_DATA( + ESP_BLE_AUDIO_CODEC_CAP_FREQ_48KHZ, /* Sampling frequency 48kHz */ + ESP_BLE_AUDIO_CODEC_CAP_DURATION_10, /* Frame duration 10ms */ + ESP_BLE_AUDIO_CODEC_CAP_CHAN_COUNT_SUPPORT(1), /* Supported channels 1 */ + 40, /* Minimum 40 octets per frame */ + 60, /* Maximum 60 octets per frame */ + 1); /* Maximum 1 codec frame per SDU */ + +static uint8_t codec_meta[] = + ESP_BLE_AUDIO_CODEC_CAP_LC3_META(ESP_BLE_AUDIO_CONTEXT_TYPE_MEDIA); + +static const esp_ble_audio_codec_cap_t codec = + ESP_BLE_AUDIO_CODEC_CAP_LC3(codec_data, codec_meta); + +/* Create a mask for the maximum BIS we can sync to using the number of + * streams we have. + * We add an additional 1 since the bis indexes start from 1 and not 0. + */ +static const uint32_t bis_index_mask = BIT_MASK(ARRAY_SIZE(streams) + 1); +static uint32_t bis_index_bitfield; + +static example_audio_rx_metrics_t rx_metrics; + +static void stream_started_cb(esp_ble_audio_bap_stream_t *stream) +{ + ESP_LOGI(TAG, "Stream %p started", stream); + + example_audio_rx_metrics_reset(&rx_metrics); +} + +static void stream_stopped_cb(esp_ble_audio_bap_stream_t *stream, uint8_t reason) +{ + ESP_LOGI(TAG, "Stream %p stopped, reason 0x%02x", stream, reason); +} + +static void stream_recv_cb(esp_ble_audio_bap_stream_t *stream, + const esp_ble_iso_recv_info_t *info, + const uint8_t *data, uint16_t len) +{ + + rx_metrics.last_sdu_len = len; + example_audio_rx_metrics_on_recv(info, &rx_metrics, TAG, "stream", stream); +} + +static esp_ble_audio_bap_stream_ops_t stream_ops = { + .started = stream_started_cb, + .stopped = stream_stopped_cb, + .recv = stream_recv_cb +}; + +static esp_ble_audio_pacs_cap_t cap = { + .codec_cap = &codec, +}; + +static void base_recv_cb(esp_ble_audio_bap_broadcast_sink_t *sink, + const esp_ble_audio_bap_base_t *base, + size_t base_size) +{ + uint32_t base_bis_index_bitfield = 0; + int err; + + assert(base); + + err = esp_ble_audio_bap_base_get_bis_indexes(base, &base_bis_index_bitfield); + if (err) { + ESP_LOGE(TAG, "Failed to get bis indexes from BASE, err %d", err); + return; + } + + bis_index_bitfield = (base_bis_index_bitfield & bis_index_mask); +} + +static void syncable_cb(esp_ble_audio_bap_broadcast_sink_t *sink, + const esp_ble_iso_biginfo_t *biginfo) +{ + int err; + + ESP_LOGI(TAG, "BASE received, creating broadcast sink"); + + err = esp_ble_audio_bap_broadcast_sink_sync(broadcast_sink, + bis_index_bitfield, + streams_p, NULL); + if (err) { + ESP_LOGE(TAG, "Failed to sync to broadcast source, err %d", err); + return; + } +} + +static esp_ble_audio_bap_broadcast_sink_cb_t broadcast_sink_cbs = { + .base_recv = base_recv_cb, + .syncable = syncable_cb, +}; + +static esp_ble_audio_bap_scan_delegator_cb_t scan_delegator_cbs; + +static void sync_broadcast_pa(const bt_addr_le_t *addr, + uint8_t adv_sid, + uint32_t broadcast_id) +{ + struct ble_gap_periodic_sync_params params = {0}; + ble_addr_t sync_addr = {0}; + int err; + + sync_addr.type = addr->type; + memcpy(sync_addr.val, addr->a.val, sizeof(sync_addr.val)); + params.skip = PA_SYNC_SKIP; + params.sync_timeout = PA_SYNC_TIMEOUT; + + err = ble_gap_periodic_adv_sync_create(&sync_addr, adv_sid, ¶ms, + example_audio_gap_event_cb, NULL); + if (err) { + ESP_LOGE(TAG, "Failed to create PA sync, err %d", err); + return; + } + + bcast_id = broadcast_id; + pa_syncing = true; /* Mark PA sync as in progress */ +} + +static bool scan_check_and_sync_broadcast(uint8_t type, const uint8_t *data, + uint8_t data_len, void *user_data) +{ + uint32_t *broadcast_id = user_data; + uint16_t tmap_role; + uint16_t uuid_val; + + if (type != EXAMPLE_AD_TYPE_SERVICE_DATA16) { + return true; + } + + if (data_len < sizeof(uuid_val)) { + ESP_LOGW(TAG, "Invalid ad size %u (uuid)", data_len); + return true; + } + + uuid_val = sys_get_le16(data); + + if (uuid_val == ESP_BLE_AUDIO_UUID_BROADCAST_AUDIO_VAL) { + if (data_len < sizeof(uuid_val) + 3) { + ESP_LOGW(TAG, "Invalid ad size %u (Broadcast ID)", data_len); + return true; + } + + *broadcast_id = sys_get_le24(data + sizeof(uuid_val)); + return true; + } + + if (uuid_val != ESP_BLE_AUDIO_UUID_TMAS_VAL) { + return true; + } + + if (data_len < sizeof(uuid_val) + sizeof(tmap_role)) { + ESP_LOGW(TAG, "Invalid ad size %u (tmap role)", data_len); + return false; /* Stop parsing */ + } + + tmap_role = sys_get_le16(data + sizeof(uuid_val)); + + if (tmap_role & ESP_BLE_AUDIO_TMAP_ROLE_BMS) { + ESP_LOGI(TAG, "Found TMAP BMS"); + + tmap_bms_found = true; + return true; + } + + return false; /* Stop parsing */ +} + +void bap_broadcast_scan_recv(esp_ble_audio_gap_app_event_t *event) +{ + uint32_t broadcast_id; + bt_addr_le_t addr; + + if ((event->ext_scan_recv.event_type & EXAMPLE_ADV_PROP_CONNECTABLE) || + event->ext_scan_recv.per_adv_itvl == 0) { + return; + } + + tmap_bms_found = false; + + broadcast_id = ESP_BLE_AUDIO_BAP_INVALID_BROADCAST_ID; + + esp_ble_audio_data_parse(event->ext_scan_recv.data, + event->ext_scan_recv.data_len, + scan_check_and_sync_broadcast, + (void *)&broadcast_id); + + if (broadcast_id != ESP_BLE_AUDIO_BAP_INVALID_BROADCAST_ID && + tmap_bms_found && + pa_syncing == false) { + addr.type = event->ext_scan_recv.addr.type; + memcpy(addr.a.val, event->ext_scan_recv.addr.val, sizeof(addr.a.val)); + + sync_broadcast_pa(&addr, event->ext_scan_recv.sid, broadcast_id); + } +} + +void bap_broadcast_pa_sync(esp_ble_audio_gap_app_event_t *event) +{ + int err; + + pa_syncing = false; /* Mark PA sync as completed */ + + if (event->pa_sync.status) { + ESP_LOGE(TAG, "PA sync failed, status %d", event->pa_sync.status); + return; + } + + ESP_LOGI(TAG, "PA sync %u synced with broadcast ID 0x%06x", + event->pa_sync.sync_handle, bcast_id); + + err = ble_gap_disc_cancel(); + if (err) { + ESP_LOGE(TAG, "Failed to stop scanning, err %d", err); + return; + } + + ESP_LOGI(TAG, "Broadcast source PA synced, waiting for BASE"); + + err = esp_ble_audio_bap_broadcast_sink_create(event->pa_sync.sync_handle, + bcast_id, &broadcast_sink); + if (err) { + ESP_LOGE(TAG, "Failed to create broadcast sink, err %d", err); + return; + } + + sync_handle = event->pa_sync.sync_handle; +} + +void bap_broadcast_pa_lost(esp_ble_audio_gap_app_event_t *event) +{ + if (sync_handle == event->pa_sync_lost.sync_handle) { + ESP_LOGI(TAG, "PA sync %u lost with reason %u", + sync_handle, event->pa_sync_lost.reason); + + sync_handle = PA_SYNC_HANDLE_INIT; + + if (broadcast_sink != NULL) { + esp_ble_audio_bap_broadcast_sink_delete(broadcast_sink); + broadcast_sink = NULL; + } + + bap_broadcast_sink_scan(); + } +} + +int bap_broadcast_sink_scan(void) +{ + struct ble_gap_disc_params params = {0}; + uint8_t own_addr_type; + int err; + + err = ble_hs_id_infer_auto(0, &own_addr_type); + if (err) { + ESP_LOGE(TAG, "Failed to determine own addr type, err %d", err); + return err; + } + + params.passive = 1; + params.itvl = SCAN_INTERVAL; + params.window = SCAN_WINDOW; + + err = ble_gap_disc(own_addr_type, BLE_HS_FOREVER, ¶ms, + example_audio_gap_event_cb, NULL); + if (err) { + ESP_LOGE(TAG, "Failed to start scanning, err %d", err); + return err; + } + + ESP_LOGI(TAG, "Extended scan started"); + return 0; +} + +int bap_broadcast_sink_init(void) +{ + const esp_ble_audio_pacs_register_param_t pacs_param = { + .snk_pac = true, + .snk_loc = true, + }; + int err; + + err = esp_ble_audio_pacs_register(&pacs_param); + if (err) { + ESP_LOGE(TAG, "Failed to register pacs, err %d", err); + return err; + } + + err = esp_ble_audio_bap_broadcast_sink_register_cb(&broadcast_sink_cbs); + if (err) { + ESP_LOGE(TAG, "Failed to register broadcast sink cb, err %d", err); + return err; + } + + err = esp_ble_audio_pacs_cap_register(ESP_BLE_AUDIO_DIR_SINK, &cap); + if (err) { + ESP_LOGE(TAG, "Failed to register pacs capabilities, err %d", err); + return err; + } + + err = esp_ble_audio_bap_scan_delegator_register(&scan_delegator_cbs); + if (err) { + ESP_LOGE(TAG, "Failed to register scan delegator, err %d", err); + return err; + } + + for (size_t i = 0; i < ARRAY_SIZE(streams); i++) { + streams[i].ops = &stream_ops; + } + + for (size_t i = 0; i < ARRAY_SIZE(streams_p); i++) { + streams_p[i] = &streams[i]; + } + + ESP_LOGI(TAG, "BAP broadcast sink initialized"); + + return 0; +} diff --git a/examples/bluetooth/esp_ble_audio/tmap/bmr/main/idf_component.yml b/examples/bluetooth/esp_ble_audio/tmap/bmr/main/idf_component.yml new file mode 100644 index 0000000000..bb02c0922a --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/bmr/main/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + example_init: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_audio/common_components/example_init + example_utils: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_audio/common_components/example_utils diff --git a/examples/bluetooth/esp_ble_audio/tmap/bmr/main/main.c b/examples/bluetooth/esp_ble_audio/tmap/bmr/main/main.c new file mode 100644 index 0000000000..0f4bb8681b --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/bmr/main/main.c @@ -0,0 +1,115 @@ +/* + * SPDX-FileCopyrightText: 2023 NXP + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include "nvs_flash.h" +#include "esp_system.h" + +#include "tmap_bmr.h" + +static void ext_scan_recv(esp_ble_audio_gap_app_event_t *event) +{ + bap_broadcast_scan_recv(event); +} + +static void pa_sync(esp_ble_audio_gap_app_event_t *event) +{ + ESP_LOGI(TAG, "PA synced:"); + ESP_LOGI(TAG, "sync_handle 0x%04x status 0x%02x addr %02x:%02x:%02x:%02x:%02x:%02x " + "sid %u adv_phy %u per_adv_itvl 0x%04x adv_ca %u", + event->pa_sync.sync_handle, event->pa_sync.status, + event->pa_sync.addr.val[5], event->pa_sync.addr.val[4], + event->pa_sync.addr.val[3], event->pa_sync.addr.val[2], + event->pa_sync.addr.val[1], event->pa_sync.addr.val[0], + event->pa_sync.sid, event->pa_sync.adv_phy, + event->pa_sync.per_adv_itvl, event->pa_sync.adv_ca); + + bap_broadcast_pa_sync(event); +} + +static void pa_sync_lost(esp_ble_audio_gap_app_event_t *event) +{ + ESP_LOGI(TAG, "PA sync lost: sync_handle 0x%04x reason 0x%02x", + event->pa_sync_lost.sync_handle, event->pa_sync_lost.reason); + + bap_broadcast_pa_lost(event); +} + +static void iso_gap_app_cb(esp_ble_audio_gap_app_event_t *event) +{ + switch (event->type) { + case ESP_BLE_AUDIO_GAP_EVENT_EXT_SCAN_RECV: + ext_scan_recv(event); + break; + case ESP_BLE_AUDIO_GAP_EVENT_PA_SYNC: + pa_sync(event); + break; + case ESP_BLE_AUDIO_GAP_EVENT_PA_SYNC_LOST: + pa_sync_lost(event); + break; + default: + break; + } +} + +void app_main(void) +{ + esp_ble_audio_init_info_t init_info = { + .gap_cb = iso_gap_app_cb, + .gatt_cb = NULL, + }; + esp_err_t err; + + /* Initialize NVS — it is used to store PHY calibration data */ + err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK(err); + + err = bluetooth_init(); + if (err) { + ESP_LOGE(TAG, "Failed to initialize BLE, err %d", err); + return; + } + + err = esp_ble_audio_common_init(&init_info); + if (err) { + ESP_LOGE(TAG, "Failed to initialize audio, err %d", err); + return; + } + + err = esp_ble_audio_tmap_register(ESP_BLE_AUDIO_TMAP_ROLE_BMR); + if (err) { + ESP_LOGE(TAG, "Failed to register TMAP, err %d", err); + return; + } + + err = vcp_vol_renderer_init(); + if (err) { + return; + } + + err = bap_broadcast_sink_init(); + if (err) { + return; + } + + err = esp_ble_audio_common_start(NULL); + if (err) { + ESP_LOGE(TAG, "Failed to start audio, err %d", err); + return; + } + + bap_broadcast_sink_scan(); +} diff --git a/examples/bluetooth/esp_ble_audio/tmap/bmr/main/tmap_bmr.h b/examples/bluetooth/esp_ble_audio/tmap/bmr/main/tmap_bmr.h new file mode 100644 index 0000000000..24f0de9302 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/bmr/main/tmap_bmr.h @@ -0,0 +1,35 @@ +/* + * SPDX-FileCopyrightText: 2023 NXP + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_log.h" + +#include "sdkconfig.h" + +#include "host/ble_hs.h" + +#include "esp_ble_audio_bap_api.h" +#include "esp_ble_audio_cap_api.h" +#include "esp_ble_audio_pacs_api.h" +#include "esp_ble_audio_tmap_api.h" +#include "esp_ble_audio_bap_lc3_preset_defs.h" + +#include "ble_audio_example_init.h" +#include "ble_audio_example_utils.h" + +#define TAG "TMAP_BMR" + +int vcp_vol_renderer_init(void); + +void bap_broadcast_scan_recv(esp_ble_audio_gap_app_event_t *event); + +void bap_broadcast_pa_sync(esp_ble_audio_gap_app_event_t *event); + +void bap_broadcast_pa_lost(esp_ble_audio_gap_app_event_t *event); + +int bap_broadcast_sink_scan(void); + +int bap_broadcast_sink_init(void); diff --git a/examples/bluetooth/esp_ble_audio/tmap/bmr/main/vcp_vol_renderer.c b/examples/bluetooth/esp_ble_audio/tmap/bmr/main/vcp_vol_renderer.c new file mode 100644 index 0000000000..12cf614bf8 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/bmr/main/vcp_vol_renderer.c @@ -0,0 +1,72 @@ +/* + * SPDX-FileCopyrightText: 2020 Bose Corporation + * SPDX-FileCopyrightText: 2020-2024 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2022 Codecoup + * SPDX-FileCopyrightText: 2023 NXP + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include "nvs_flash.h" +#include "esp_system.h" + +#include "tmap_bmr.h" + +static esp_ble_audio_vcp_included_t vcp_included; + +static void vcs_state_cb(esp_ble_conn_t *conn, int err, uint8_t volume, uint8_t mute) +{ + if (err) { + ESP_LOGE(TAG, "Failed to get VCS state, err %d", err); + } else { + ESP_LOGI(TAG, "VCS volume %u, mute %u", volume, mute); + } +} + +static void vcs_flags_cb(esp_ble_conn_t *conn, int err, uint8_t flags) +{ + if (err) { + ESP_LOGE(TAG, "Failed to get VCS flags, err %d", err); + } else { + ESP_LOGI(TAG, "VCS flags 0x%02x", flags); + } +} + +static esp_ble_audio_vcp_vol_rend_cb_t vcp_cbs = { + .state = vcs_state_cb, + .flags = vcs_flags_cb, +}; + +int vcp_vol_renderer_init(void) +{ + esp_ble_audio_vcp_vol_rend_register_param_t vcp_register_param = {0}; + int err; + + vcp_register_param.step = 1; + vcp_register_param.mute = ESP_BLE_AUDIO_VCP_STATE_UNMUTED; + vcp_register_param.volume = 10; + vcp_register_param.cb = &vcp_cbs; + + err = esp_ble_audio_vcp_vol_rend_register(&vcp_register_param); + if (err) { + ESP_LOGE(TAG, "Failed to register VCP renderer, err %d", err); + return err; + } + + err = esp_ble_audio_vcp_vol_rend_included_get(&vcp_included); + if (err) { + ESP_LOGE(TAG, "Failed to get VCP renderer included service, err %d", err); + return err; + } + + ESP_LOGI(TAG, "VCP volume renderer initialized"); + + return 0; +} diff --git a/examples/bluetooth/esp_ble_audio/tmap/bmr/sdkconfig.defaults b/examples/bluetooth/esp_ble_audio/tmap/bmr/sdkconfig.defaults new file mode 100644 index 0000000000..c7a2951ee4 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/bmr/sdkconfig.defaults @@ -0,0 +1,23 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration +# + +CONFIG_BT_ENABLED=y +CONFIG_BT_BLUEDROID_ENABLED=n +CONFIG_BT_NIMBLE_ENABLED=y +CONFIG_BT_NIMBLE_EXT_ADV=y +CONFIG_BT_NIMBLE_MAX_CONNECTIONS=1 +CONFIG_BT_NIMBLE_MAX_CCCDS=30 +CONFIG_BT_NIMBLE_ISO=y +CONFIG_BT_NIMBLE_LOG_LEVEL_WARNING=y + +CONFIG_BT_ISO_MAX_CHAN=2 + +CONFIG_BT_TMAP=y +CONFIG_BT_CAP_ACCEPTOR=y +CONFIG_BT_BAP_SCAN_DELEGATOR=y +CONFIG_BT_BAP_BROADCAST_SINK=y +CONFIG_BT_VCP_VOL_REND=y +CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE=30 + +CONFIG_FREERTOS_HZ=1000 diff --git a/examples/bluetooth/esp_ble_audio/tmap/bmr/sdkconfig.defaults.esp32h4 b/examples/bluetooth/esp_ble_audio/tmap/bmr/sdkconfig.defaults.esp32h4 new file mode 100644 index 0000000000..5920ce3f85 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/bmr/sdkconfig.defaults.esp32h4 @@ -0,0 +1,6 @@ +# Override some defaults so BT stack is enabled +# by default in this example + +CONFIG_IDF_TARGET="esp32h4" + +CONFIG_BT_LE_ISO_SUPPORT=y diff --git a/examples/bluetooth/esp_ble_audio/tmap/bms/CMakeLists.txt b/examples/bluetooth/esp_ble_audio/tmap/bms/CMakeLists.txt new file mode 100644 index 0000000000..042daa47b0 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/bms/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.22) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +idf_build_set_property(MINIMAL_BUILD ON) +project(tmap_bms) diff --git a/examples/bluetooth/esp_ble_audio/tmap/bms/README.md b/examples/bluetooth/esp_ble_audio/tmap/bms/README.md new file mode 100644 index 0000000000..89ae223509 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/bms/README.md @@ -0,0 +1,58 @@ +| Supported Targets | ESP32-H4 | +| ----------------- | -------- | + +# TMAP Broadcast Media Sender (BMS) Example + +(See the README.md file in the upper level `examples` directory for more information about examples.) + +This example implements the **Telephone and Media Audio Profile (TMAP) Broadcast Media Sender (BMS)** role. The BMS acts as a BAP Broadcast Source: it starts non-connectable extended advertising and periodic advertising. Extended advertising includes the **TMAS (Telephone and Media Audio Service)** UUID with the **BMS** role and the Broadcast Audio Announcement service (broadcast ID and device name); periodic advertising carries the BASE (Broadcast Audio Source Endpoint). After creating the broadcast source and starting the BIG, it sends broadcast audio on the BIS at the configured interval. TMAP BMR receivers (e.g. the [bmr](../bmr) example) that scan for both TMAS BMS and Broadcast Audio will discover and sync to this source. + +The implementation uses the NimBLE host stack with ISO and BAP support, ESP-BLE-AUDIO (TMAP BMS role, CAP initiator broadcast). It creates a single subgroup with one stream using the LC3 48_2_1 broadcast preset (48 kHz, stereo, media context). A periodic TX scheduler (based on `k_work_delayable`) drives ISO SDU transmission in the ISO task context; the stream sent callback logs packet counts and drift. All parameters (broadcast ID, broadcast code, device name) are hardcoded in the source and can be changed by editing the source code constants. + +## Requirements + +* A board with Bluetooth LE 5.2, ISO, and LE Audio support (e.g. ESP32-H4) +* Optionally, a TMAP BMR or BAP Broadcast Sink (e.g. the [bmr](../bmr) example) to receive the broadcast stream + +## How to Use Example + +Before project configuration and build, set the correct chip target: + +```bash +idf.py set-target esp32h4 +``` + +### Build and Flash + +Run the following to build, flash and monitor: + +```bash +idf.py -p PORT flash monitor +``` + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the [Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF. + +## Example Flow + +1. **Initialization**: NVS, Bluetooth stack, and LE Audio common layer (`esp_ble_audio_common_init`). Register TMAP role BMS (`esp_ble_audio_tmap_register(ESP_BLE_AUDIO_TMAP_ROLE_BMS)`). Initialize CAP initiator broadcast: register stream ops (started, stopped, sent), create broadcast audio TX scheduler. +2. **Setup**: Create the broadcast source with one subgroup and one stream (LC3 48_2_1 preset), build extended adv data (TMAS + BMS role, Broadcast Audio UUID + broadcast ID, device name) and periodic adv data (BASE). Start periodic and extended advertising, add the ext adv to the BIG, then start the broadcast audio. The stream started callback starts the periodic TX scheduler and sends the first SDU. +3. **Streaming**: The TX scheduler, based on `k_work_delayable`, fires at the stream QoS interval in the ISO task context and sends ISO SDUs; the sent callback counts packets and logs periodically. Drift and untransmitted packets are reported in the callback. Note that the scheduler timer resolution is in milliseconds, which may not match the exact SDU interval for all configurations. +4. **Optional**: `cap_initiator_update` updates broadcast metadata; `cap_initiator_stop` stops and deletes the broadcast source. + +## Example Output + +``` +I (xxx) TMAP_BMS: Creating broadcast source +I (xxx) TMAP_BMS: Extended adv instance 0 started +I (xxx) TMAP_BMS: Stream 0x... started +I (xxx) TMAP_BMS: Transmitted 1000 ISO data packets (stream 0x...) +... +``` + +If the controller reports drift or untransmitted packets: + +``` +W (xxx) TMAP_BMS: ISO data packets ... drifted and ... not txd +``` diff --git a/examples/bluetooth/esp_ble_audio/tmap/bms/main/CMakeLists.txt b/examples/bluetooth/esp_ble_audio/tmap/bms/main/CMakeLists.txt new file mode 100644 index 0000000000..176dda4b21 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/bms/main/CMakeLists.txt @@ -0,0 +1,5 @@ +set(srcs "cap_initiator.c" + "main.c") + +idf_component_register(SRCS "${srcs}" + REQUIRES bt nvs_flash) diff --git a/examples/bluetooth/esp_ble_audio/tmap/bms/main/cap_initiator.c b/examples/bluetooth/esp_ble_audio/tmap/bms/main/cap_initiator.c new file mode 100644 index 0000000000..334f783dc7 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/bms/main/cap_initiator.c @@ -0,0 +1,527 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2023 NXP + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include "esp_timer.h" +#include "esp_random.h" + +#include "tmap_bms.h" + +#define ADV_HANDLE 0x00 +#define ADV_SID 0 +#define ADV_TX_POWER 127 +#define ADV_ADDRESS BLE_OWN_ADDR_PUBLIC +#define ADV_PRIMARY_PHY BLE_HCI_LE_PHY_1M +#define ADV_SECONDARY_PHY BLE_HCI_LE_PHY_2M +#define ADV_INTERVAL BLE_GAP_ADV_ITVL_MS(200) + +#define PER_ADV_INTERVAL BLE_GAP_ADV_ITVL_MS(100) + +#define LOCAL_DEVICE_NAME "TMAP Broadcast Source" +#define LOCAL_BROADCAST_ID 0x123456 + +static esp_ble_audio_cap_initiator_broadcast_subgroup_param_t subgroup_param; +static esp_ble_audio_cap_initiator_broadcast_stream_param_t stream_params; +static esp_ble_audio_cap_initiator_broadcast_create_param_t create_param; +static esp_ble_audio_cap_broadcast_source_t *broadcast_source; +static esp_ble_audio_cap_stream_t broadcast_stream; + +static uint8_t bis_codec_data[] = { + ESP_BLE_AUDIO_CODEC_DATA(ESP_BLE_AUDIO_CODEC_CFG_FREQ, + EXAMPLE_BYTES_LIST_LE16(ESP_BLE_AUDIO_CODEC_CFG_FREQ_48KHZ)) +}; + +static uint8_t new_metadata[] = { + ESP_BLE_AUDIO_CODEC_DATA(ESP_BLE_AUDIO_METADATA_TYPE_STREAM_CONTEXT, + EXAMPLE_BYTES_LIST_LE16(ESP_BLE_AUDIO_CONTEXT_TYPE_MEDIA)) +}; + +ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_48_2_1_DEFINE(broadcast_preset_48_2_1, + ESP_BLE_AUDIO_LOCATION_FRONT_LEFT, + ESP_BLE_AUDIO_CONTEXT_TYPE_MEDIA); + +static example_audio_tx_scheduler_t tx_scheduler; +static uint16_t tx_seq_num; +static uint8_t *iso_data; + +static void broadcast_audio_tx(void) +{ + uint16_t sdu_len; + int err; + + if (iso_data == NULL) { + return; + } + + if (broadcast_stream.bap_stream.qos == NULL || broadcast_stream.bap_stream.qos->sdu == 0) { + ESP_LOGE(TAG, "Invalid stream qos"); + return; + } + + sdu_len = broadcast_stream.bap_stream.qos->sdu; + + memset(iso_data, (uint8_t)tx_seq_num, sdu_len); + + err = esp_ble_audio_cap_stream_send(&broadcast_stream, + iso_data, sdu_len, + tx_seq_num); + if (err) { + ESP_LOGD(TAG, "Failed to transmit data on streams, err %d", err); + return; + } + + tx_seq_num++; +} + +static void broadcast_started_cb(esp_ble_audio_bap_stream_t *stream) +{ + esp_err_t err; + + ESP_LOGI(TAG, "Stream %p started", stream); + + if (stream->qos == NULL || stream->qos->sdu == 0) { + ESP_LOGE(TAG, "Invalid stream qos"); + return; + } + + if (iso_data == NULL) { + iso_data = calloc(1, stream->qos->sdu); + if (iso_data == NULL) { + ESP_LOGE(TAG, "Failed to alloc TX buffer, SDU %u", stream->qos->sdu); + return; + } + } + + tx_seq_num = 0; + example_audio_tx_scheduler_reset(&tx_scheduler); + + /* Note: esp timer is not accurate enough */ + err = example_audio_tx_scheduler_start(&tx_scheduler, stream->qos->interval); + if (err) { + ESP_LOGE(TAG, "Failed to start tx scheduler, err %d", err); + return; + } + + broadcast_audio_tx(); +} + +static void broadcast_stopped_cb(esp_ble_audio_bap_stream_t *stream, uint8_t reason) +{ + esp_err_t err; + + ESP_LOGI(TAG, "Stream %p stopped, reason 0x%02x", stream, reason); + + err = example_audio_tx_scheduler_stop(&tx_scheduler); + if (err) { + ESP_LOGE(TAG, "Failed to stop tx scheduler, err %d", err); + } + + if (iso_data != NULL) { + free(iso_data); + iso_data = NULL; + } +} + +static void broadcast_disconnected_cb(esp_ble_audio_bap_stream_t *stream, uint8_t reason) +{ + esp_err_t err; + + ESP_LOGI(TAG, "Stream %p disconnected, reason 0x%02x", stream, reason); + + err = example_audio_tx_scheduler_stop(&tx_scheduler); + if (err) { + ESP_LOGE(TAG, "Failed to stop tx scheduler, err %d", err); + } + + if (iso_data != NULL) { + free(iso_data); + iso_data = NULL; + } +} + +static void broadcast_sent_cb(esp_ble_audio_bap_stream_t *stream, void *user_data) +{ + example_audio_tx_scheduler_on_sent(&tx_scheduler, user_data, TAG, "stream", stream); +} + +static esp_ble_audio_bap_stream_ops_t broadcast_stream_ops = { + .started = broadcast_started_cb, + .stopped = broadcast_stopped_cb, + .sent = broadcast_sent_cb, + .disconnected = broadcast_disconnected_cb, +}; + +static uint8_t *ext_adv_data_get(uint8_t *data_len) +{ + uint32_t broadcast_id; + uint8_t *data; + + broadcast_id = LOCAL_BROADCAST_ID; + + /* - TMAP UUID (2 octets) + * - TMAP Role (2 octets) + * - Broadcast Audio Announcement Service UUID (2 octets) + * - Broadcast ID (3 octets) + * - Complete Device Name + */ + *data_len = 6 + 7 + 2 + strlen(LOCAL_DEVICE_NAME); + + data = calloc(1, *data_len); + if (data == NULL) { + return NULL; + } + + data[0] = 0x05; /* 1 + 2 + 2 */ + data[1] = EXAMPLE_AD_TYPE_SERVICE_DATA16; + data[2] = (ESP_BLE_AUDIO_UUID_TMAS_VAL & 0xFF); + data[3] = ((ESP_BLE_AUDIO_UUID_TMAS_VAL >> 8) & 0xFF); + data[4] = (ESP_BLE_AUDIO_TMAP_ROLE_BMS & 0xFF); + data[5] = ((ESP_BLE_AUDIO_TMAP_ROLE_BMS >> 8) & 0xFF); + + data[6] = 0x06; /* 1 + 2 + 3 */ + data[7] = EXAMPLE_AD_TYPE_SERVICE_DATA16; + data[8] = (ESP_BLE_AUDIO_UUID_BROADCAST_AUDIO_VAL & 0xFF); + data[9] = ((ESP_BLE_AUDIO_UUID_BROADCAST_AUDIO_VAL >> 8) & 0xFF); + data[10] = (broadcast_id & 0xFF); + data[11] = ((broadcast_id >> 8) & 0xFF); + data[12] = ((broadcast_id >> 16) & 0xFF); + + data[13] = strlen(LOCAL_DEVICE_NAME) + 1; + data[14] = EXAMPLE_AD_TYPE_NAME_COMPLETE; + memcpy(data + 15, LOCAL_DEVICE_NAME, strlen(LOCAL_DEVICE_NAME)); + + return data; +} + +static uint8_t *per_adv_data_get(uint8_t *data_len) +{ + NET_BUF_SIMPLE_DEFINE(base_buf, 128); + uint8_t *data; + esp_err_t err; + + /* Broadcast Audio Announcement Service UUID (2 octets) and + * Broadcast Audio Source Endpoint (BASE) + */ + + err = esp_ble_audio_cap_initiator_broadcast_get_base(broadcast_source, &base_buf); + if (err) { + ESP_LOGE(TAG, "Failed to get encoded BASE, err %d", err); + return NULL; + } + + *data_len = 2 + base_buf.len; + + data = calloc(1, *data_len); + if (data == NULL) { + return NULL; + } + + /* base_buf.len has included the UUID length (2 octets) */ + data[0] = 1 + base_buf.len; + data[1] = EXAMPLE_AD_TYPE_SERVICE_DATA16; + memcpy(data + 2, base_buf.data, base_buf.len); + + return data; +} + +static int ext_adv_start(void) +{ + struct ble_gap_periodic_adv_params per_params = {0}; + struct ble_gap_ext_adv_params ext_params = {0}; + struct os_mbuf *data = NULL; + uint8_t *ext_data = NULL; + uint8_t *per_data = NULL; + uint8_t data_len = 0; + int err; + + ext_params.connectable = 0; + ext_params.scannable = 0; + ext_params.legacy_pdu = 0; + ext_params.own_addr_type = ADV_ADDRESS; + ext_params.primary_phy = ADV_PRIMARY_PHY; + ext_params.secondary_phy = ADV_SECONDARY_PHY; + ext_params.tx_power = ADV_TX_POWER; + ext_params.sid = ADV_SID; + ext_params.itvl_min = ADV_INTERVAL; + ext_params.itvl_max = ADV_INTERVAL; + + err = ble_gap_ext_adv_configure(ADV_HANDLE, &ext_params, NULL, + example_audio_gap_event_cb, NULL); + if (err) { + ESP_LOGE(TAG, "Failed to configure ext adv params, err %d", err); + goto end; + } + + ext_data = ext_adv_data_get(&data_len); + if (ext_data == NULL) { + err = -ENOMEM; + goto end; + } + + data = os_msys_get_pkthdr(data_len, 0); + if (data == NULL) { + ESP_LOGE(TAG, "Failed to get ext adv mbuf"); + err = -ENOMEM; + goto end; + } + + err = os_mbuf_append(data, ext_data, data_len); + if (err) { + ESP_LOGE(TAG, "Failed to append ext adv data, err %d", err); + os_mbuf_free_chain(data); + goto end; + } + + err = ble_gap_ext_adv_set_data(ADV_HANDLE, data); + if (err) { + ESP_LOGE(TAG, "Failed to set ext adv data, err %d", err); + goto end; + } + + per_params.include_tx_power = 0; + per_params.itvl_min = PER_ADV_INTERVAL; + per_params.itvl_max = PER_ADV_INTERVAL; + + err = ble_gap_periodic_adv_configure(ADV_HANDLE, &per_params); + if (err) { + ESP_LOGE(TAG, "Failed to configure per adv params, err %d", err); + goto end; + } + + per_data = per_adv_data_get(&data_len); + if (per_data == NULL) { + err = -ENOMEM; + goto end; + } + + data = os_msys_get_pkthdr(data_len, 0); + if (data == NULL) { + ESP_LOGE(TAG, "Failed to get per adv mbuf"); + err = -ENOMEM; + goto end; + } + + err = os_mbuf_append(data, per_data, data_len); + if (err) { + ESP_LOGE(TAG, "Failed to append per adv data, err %d", err); + os_mbuf_free_chain(data); + goto end; + } + + err = ble_gap_periodic_adv_set_data(ADV_HANDLE, data); + if (err) { + ESP_LOGE(TAG, "Failed to set per adv data, err %d", err); + goto end; + } + + err = ble_gap_periodic_adv_start(ADV_HANDLE); + if (err) { + ESP_LOGE(TAG, "Failed to start per advertising, err %d", err); + goto end; + } + + err = ble_gap_ext_adv_start(ADV_HANDLE, 0, 0); + if (err) { + ESP_LOGE(TAG, "Failed to start ext advertising, err %d", err); + goto end; + } + + ESP_LOGI(TAG, "Extended adv instance %u started", ADV_HANDLE); + +end: + if (ext_data) { + free(ext_data); + } + if (per_data) { + free(per_data); + } + return err; +} + +static int ext_adv_stop(void) +{ + int err; + + err = ble_gap_periodic_adv_stop(ADV_HANDLE); + if (err) { + ESP_LOGE(TAG, "Failed to stop per advertising, err %d", err); + } + + err = ble_gap_ext_adv_stop(ADV_HANDLE); + if (err) { + ESP_LOGE(TAG, "Failed to stop ext advertising, err %d", err); + } + + if (err == 0) { + ESP_LOGI(TAG, "Extended adv instance %u stopped", ADV_HANDLE); + } + + return err; +} + +int cap_initiator_setup(void) +{ + esp_ble_audio_bap_broadcast_adv_info_t info = { + .adv_handle = ADV_HANDLE, + }; + bool adv_started = false; + bool adv_added = false; + int err; + + stream_params.stream = &broadcast_stream; + stream_params.data_len = ARRAY_SIZE(bis_codec_data); + stream_params.data = bis_codec_data; + + subgroup_param.stream_count = 1; + subgroup_param.stream_params = &stream_params; + subgroup_param.codec_cfg = &broadcast_preset_48_2_1.codec_cfg; + + create_param.subgroup_count = 1; + create_param.subgroup_params = &subgroup_param; + create_param.qos = &broadcast_preset_48_2_1.qos; + create_param.packing = ESP_BLE_ISO_PACKING_SEQUENTIAL; + create_param.encryption = false; + + ESP_LOGI(TAG, "Creating broadcast source"); + + err = esp_ble_audio_cap_initiator_broadcast_audio_create(&create_param, &broadcast_source); + if (err) { + ESP_LOGE(TAG, "Failed to create broadcast source, err %d", err); + return err; + } + + err = ext_adv_start(); + if (err) { + goto end; + } + + adv_started = true; + + err = esp_ble_audio_bap_broadcast_adv_add(&info); + if (err) { + ESP_LOGE(TAG, "Failed to add adv for broadcast source, err %d", err); + goto end; + } + + adv_added = true; + + err = esp_ble_audio_cap_initiator_broadcast_audio_start(broadcast_source, ADV_HANDLE); + if (err) { + ESP_LOGE(TAG, "Failed to start broadcast source, err %d", err); + goto end; + } + + ESP_LOGI(TAG, "CAP initiator setup"); + + return 0; + +end: + if (adv_added) { + err = esp_ble_audio_bap_broadcast_adv_delete(&info); + if (err) { + ESP_LOGE(TAG, "Failed to delete adv for broadcast source, err %d", err); + } + } + + if (adv_started) { + ext_adv_stop(); + } + + esp_ble_audio_cap_initiator_broadcast_audio_delete(broadcast_source); + broadcast_source = NULL; + + if (iso_data != NULL) { + free(iso_data); + iso_data = NULL; + } + + return err; +} + +int cap_initiator_update(void) +{ + int err; + + err = esp_ble_audio_cap_initiator_broadcast_audio_update(broadcast_source, + new_metadata, + ARRAY_SIZE(new_metadata)); + if (err) { + ESP_LOGE(TAG, "Failed to update broadcast source metadata, err %d", err); + } + + return err; +} + +int cap_initiator_stop(void) +{ + esp_ble_audio_bap_broadcast_adv_info_t info = { + .adv_handle = ADV_HANDLE, + }; + int err; + + err = esp_ble_audio_cap_initiator_broadcast_audio_stop(broadcast_source); + if (err) { + ESP_LOGE(TAG, "Failed to stop broadcast source, err %d", err); + return err; + } + + err = esp_ble_audio_cap_initiator_broadcast_audio_delete(broadcast_source); + if (err) { + ESP_LOGE(TAG, "Failed to delete broadcast source, err %d", err); + return err; + } + + broadcast_source = NULL; + + err = esp_ble_audio_bap_broadcast_adv_delete(&info); + if (err) { + ESP_LOGE(TAG, "Failed to delete adv for broadcast source, err %d", err); + return err; + } + + err = ext_adv_stop(); + if (err) { + return err; + } + + if (iso_data != NULL) { + free(iso_data); + iso_data = NULL; + } + + return 0; +} + +static void tx_scheduler_cb(void *arg) +{ + (void)arg; + broadcast_audio_tx(); +} + +int cap_initiator_init(void) +{ + esp_err_t err; + + esp_ble_audio_cap_stream_ops_register(&broadcast_stream, &broadcast_stream_ops); + + err = example_audio_tx_scheduler_init(&tx_scheduler, + tx_scheduler_cb, + NULL); + if (err) { + ESP_LOGE(TAG, "Failed to init tx scheduler, err %d", err); + return err; + } + + ESP_LOGI(TAG, "CAP initiator initialized"); + + return 0; +} diff --git a/examples/bluetooth/esp_ble_audio/tmap/bms/main/idf_component.yml b/examples/bluetooth/esp_ble_audio/tmap/bms/main/idf_component.yml new file mode 100644 index 0000000000..bb02c0922a --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/bms/main/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + example_init: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_audio/common_components/example_init + example_utils: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_audio/common_components/example_utils diff --git a/examples/bluetooth/esp_ble_audio/tmap/bms/main/main.c b/examples/bluetooth/esp_ble_audio/tmap/bms/main/main.c new file mode 100644 index 0000000000..9625371764 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/bms/main/main.c @@ -0,0 +1,65 @@ +/* + * SPDX-FileCopyrightText: 2023 NXP + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include "nvs_flash.h" +#include "esp_system.h" + +#include "tmap_bms.h" + +void app_main(void) +{ + esp_ble_audio_init_info_t init_info = { + .gap_cb = NULL, + .gatt_cb = NULL, + }; + esp_err_t err; + + /* Initialize NVS — it is used to store PHY calibration data */ + err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK(err); + + err = bluetooth_init(); + if (err) { + ESP_LOGE(TAG, "Failed to initialize BLE, err %d", err); + return; + } + + err = esp_ble_audio_common_init(&init_info); + if (err) { + ESP_LOGE(TAG, "Failed to initialize audio, err %d", err); + return; + } + + err = esp_ble_audio_tmap_register(ESP_BLE_AUDIO_TMAP_ROLE_BMS); + if (err) { + ESP_LOGE(TAG, "Failed to register TMAP, err %d", err); + return; + } + + err = cap_initiator_init(); + if (err) { + return; + } + + err = esp_ble_audio_common_start(NULL); + if (err) { + ESP_LOGE(TAG, "Failed to start audio, err %d", err); + return; + } + + cap_initiator_setup(); +} diff --git a/examples/bluetooth/esp_ble_audio/tmap/bms/main/tmap_bms.h b/examples/bluetooth/esp_ble_audio/tmap/bms/main/tmap_bms.h new file mode 100644 index 0000000000..127ecf61c2 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/bms/main/tmap_bms.h @@ -0,0 +1,29 @@ +/* + * SPDX-FileCopyrightText: 2023 NXP + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_log.h" + +#include "sdkconfig.h" + +#include "host/ble_hs.h" + +#include "esp_ble_audio_cap_api.h" +#include "esp_ble_audio_tmap_api.h" +#include "esp_ble_audio_bap_lc3_preset_defs.h" + +#include "ble_audio_example_init.h" +#include "ble_audio_example_utils.h" + +#define TAG "TMAP_BMS" + +int cap_initiator_setup(void); + +int cap_initiator_update(void); + +int cap_initiator_stop(void); + +int cap_initiator_init(void); diff --git a/examples/bluetooth/esp_ble_audio/tmap/bms/sdkconfig.defaults b/examples/bluetooth/esp_ble_audio/tmap/bms/sdkconfig.defaults new file mode 100644 index 0000000000..30d1000697 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/bms/sdkconfig.defaults @@ -0,0 +1,20 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration +# + +CONFIG_BT_ENABLED=y +CONFIG_BT_BLUEDROID_ENABLED=n +CONFIG_BT_NIMBLE_ENABLED=y +CONFIG_BT_NIMBLE_EXT_ADV=y +CONFIG_BT_NIMBLE_MAX_CONNECTIONS=1 +CONFIG_BT_NIMBLE_MAX_CCCDS=30 +CONFIG_BT_NIMBLE_ISO=y +CONFIG_BT_NIMBLE_LOG_LEVEL_WARNING=y + +CONFIG_BT_ISO_MAX_CHAN=2 + +CONFIG_BT_TMAP=y +CONFIG_BT_CAP_INITIATOR=y +CONFIG_BT_BAP_BROADCAST_SOURCE=y + +CONFIG_FREERTOS_HZ=1000 diff --git a/examples/bluetooth/esp_ble_audio/tmap/bms/sdkconfig.defaults.esp32h4 b/examples/bluetooth/esp_ble_audio/tmap/bms/sdkconfig.defaults.esp32h4 new file mode 100644 index 0000000000..5920ce3f85 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/bms/sdkconfig.defaults.esp32h4 @@ -0,0 +1,6 @@ +# Override some defaults so BT stack is enabled +# by default in this example + +CONFIG_IDF_TARGET="esp32h4" + +CONFIG_BT_LE_ISO_SUPPORT=y diff --git a/examples/bluetooth/esp_ble_audio/tmap/central/CMakeLists.txt b/examples/bluetooth/esp_ble_audio/tmap/central/CMakeLists.txt new file mode 100644 index 0000000000..ed05f82547 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/central/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.22) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +idf_build_set_property(MINIMAL_BUILD ON) +project(tmap_central) diff --git a/examples/bluetooth/esp_ble_audio/tmap/central/README.md b/examples/bluetooth/esp_ble_audio/tmap/central/README.md new file mode 100644 index 0000000000..6c845bcd29 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/central/README.md @@ -0,0 +1,64 @@ +| Supported Targets | ESP32-H4 | +| ----------------- | -------- | + +# TMAP Central Example + +(See the README.md file in the upper level `examples` directory for more information about examples.) + +This example implements the **Telephone and Media Audio Profile (TMAP) Central** roles: **Call Gateway (CG)** and **Unicast Media Sender (UMS)**. The central scans for devices that advertise the TMAS (Telephone and Media Audio Service) with the **UMR (Unicast Media Receiver)** role, connects to the first such device, performs pairing, MTU exchange, and GATT service discovery, then runs TMAP discovery and VCP discovery. After TMAP discovery completes, it sets up unicast audio streams (CAP initiator): discovers ASEs, configures codec (e.g. LC3 48_2_1), sets QoS, enables and connects streams, then starts them and sends audio to the peer’s sink. It also acts as **VCP Volume Controller** (volume/mute on the peer), **MCP server** (Media Control Profile / media proxy), and **CCP server** (Call Control Profile with TBS – Telephone Bearer Service) for call originate/terminate. Run it with a device that advertises TMAP UMR (e.g. a TMAP peripheral or CAP acceptor with unicast). + +The implementation uses the NimBLE host stack with ISO and LE Audio support, ESP-BLE-AUDIO (TMAP CG+UMS, CAP initiator unicast client, VCP volume controller, TBS, CSIP set coordinator, MCP/MCS/MCC, media proxy). Optional Kconfig: device name. + +## Requirements + +* A board with Bluetooth LE 5.2, ISO, and LE Audio support (e.g. ESP32-H4) +* A device advertising TMAP UMR (Unicast Media Receiver), e.g. a CAP Acceptor or TMAP peripheral with unicast + +## How to Use Example + +Before project configuration and build, set the correct chip target: + +```bash +idf.py set-target esp32h4 +``` + +### Build and Flash + +Run the following to build, flash and monitor: + +```bash +idf.py -p PORT flash monitor +``` + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the [Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF. + +## Example Flow + +1. **Initialization**: NVS, Bluetooth stack, and LE Audio common layer (`esp_ble_audio_common_init`) with GAP and GATT callbacks. Register TMAP roles CG and UMS (`esp_ble_audio_tmap_register(ESP_BLE_AUDIO_TMAP_ROLE_CG | ESP_BLE_AUDIO_TMAP_ROLE_UMS)`). Initialize CAP initiator (unicast client, stream callbacks, TX timer). Initialize VCP volume controller. Initialize MCP server (media proxy). Initialize CCP server (TBS bearer, originate/terminate callbacks). Start the audio stack and set the device name. +2. **Scanning**: Start extended scanning. On scan result with connectable advertising, parse for TMAS with UMR role; when found, stop scan and connect to the peer. +3. **Connection**: On ACL connect, store connection handle and initiate pairing. On MTU change, start GATT service discovery. On discovery complete (and when MTU has been exchanged), start TMAP discovery and VCP discovery. +4. **TMAP discovery complete**: Call `cap_initiator_setup()` to create the unicast group, discover ASEs, configure codec, set QoS, enable and connect streams, then start streams. +5. **Unicast streaming**: When a sink-direction stream (TX from central to peer) is started, a periodic TX scheduler based on `k_work_delayable` runs in the ISO task context and sends ISO SDUs at the stream QoS interval; the sent callback logs packet counts. Source streams (RX) can be used to receive audio from the peer. Note that the scheduler timer resolution is in milliseconds, which may not match the exact SDU interval for all configurations. +6. **VCP**: After VCP discovery, the example can send mute/volume commands; state and flags callbacks log volume and mute. + +## Example Output + +``` +I (xxx) TMAP_CEN: Found TMAS in peer adv data! +I (xxx) TMAP_CEN: connection established, status 0 +I (xxx) TMAP_CEN: gatt mtu change, conn_handle 1, mtu ... +I (xxx) TMAP_CEN: gattc disc cmpl, status 0, conn_handle 1 +I (xxx) TMAP_CEN: TMAP discovery done +I (xxx) TMAP_CEN: Configured stream 0x... +I (xxx) TMAP_CEN: Unicast stream 0x... started +I (xxx) TMAP_CEN: Transmitted 1000 ISO data packets (stream 0x...) +... +``` + +If the connection is lost: + +``` +I (xxx) TMAP_CEN: connection disconnected, reason 0x... +``` diff --git a/examples/bluetooth/esp_ble_audio/tmap/central/main/CMakeLists.txt b/examples/bluetooth/esp_ble_audio/tmap/central/main/CMakeLists.txt new file mode 100644 index 0000000000..f8c704047c --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/central/main/CMakeLists.txt @@ -0,0 +1,8 @@ +set(srcs "cap_initiator.c" + "ccp_server.c" + "mcp_server.c" + "vcp_vol_ctlr.c" + "main.c") + +idf_component_register(SRCS "${srcs}" + REQUIRES bt nvs_flash) diff --git a/examples/bluetooth/esp_ble_audio/tmap/central/main/cap_initiator.c b/examples/bluetooth/esp_ble_audio/tmap/central/main/cap_initiator.c new file mode 100644 index 0000000000..24c265dfae --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/central/main/cap_initiator.c @@ -0,0 +1,602 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2023 NXP + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "esp_timer.h" + +#include "esp_ble_audio_bap_lc3_preset_defs.h" + +#include "tmap_central.h" + +static esp_ble_audio_cap_stream_t unicast_sink_streams[CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT]; +static esp_ble_audio_cap_stream_t unicast_source_streams[CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT]; +static esp_ble_audio_bap_ep_t *unicast_sink_eps[CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT]; +static esp_ble_audio_bap_ep_t *unicast_source_eps[CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT]; + +static esp_ble_audio_cap_unicast_group_t *unicast_group; + +static example_audio_tx_scheduler_t tx_scheduler; +static uint16_t tx_seq_num; +static uint8_t *iso_data; + +static void unicast_audio_tx(void); + +ESP_BLE_AUDIO_BAP_LC3_UNICAST_PRESET_48_2_1_DEFINE(unicast_preset_48_2_1, + ESP_BLE_AUDIO_LOCATION_FRONT_LEFT, + ESP_BLE_AUDIO_CONTEXT_TYPE_MEDIA); + +static void unicast_stream_configured_cb(esp_ble_audio_bap_stream_t *stream, + const esp_ble_audio_bap_qos_cfg_pref_t *pref) +{ + ESP_LOGI(TAG, "Unicast stream %p configured", stream); +} + +static void unicast_stream_qos_set_cb(esp_ble_audio_bap_stream_t *stream) +{ + ESP_LOGI(TAG, "Unicast stream %p QoS set", stream); +} + +static void unicast_stream_enabled_cb(esp_ble_audio_bap_stream_t *stream) +{ + ESP_LOGI(TAG, "Unicast stream %p enabled", stream); +} + +static void unicast_stream_started_cb(esp_ble_audio_bap_stream_t *stream) +{ + esp_ble_audio_bap_ep_info_t ep_info = {0}; + esp_err_t err; + + ESP_LOGI(TAG, "Unicast stream %p started", stream); + + err = esp_ble_audio_bap_ep_get_info(stream->ep, &ep_info); + if (err) { + ESP_LOGE(TAG, "Failed to get ep info, err %d", err); + return; + } + + /* Note: + * For a BAP Unicast Client, this is considered outgoing audio (TX). + */ + if (ep_info.dir == ESP_BLE_AUDIO_DIR_SINK) { + if (stream->qos == NULL || stream->qos->sdu == 0) { + ESP_LOGE(TAG, "Invalid stream qos"); + return; + } + + if (iso_data == NULL) { + iso_data = calloc(1, stream->qos->sdu); + if (iso_data == NULL) { + ESP_LOGE(TAG, "Failed to alloc TX buffer, SDU %u", stream->qos->sdu); + return; + } + } + + assert(stream->qos->interval); + + ESP_LOGI(TAG, "Streaming, interval %u, length %u", stream->qos->interval, stream->qos->sdu); + + tx_seq_num = 0; + example_audio_tx_scheduler_reset(&tx_scheduler); + + /* Note: esp timer is not accurate enough */ + err = example_audio_tx_scheduler_start(&tx_scheduler, stream->qos->interval); + if (err) { + ESP_LOGE(TAG, "Failed to start tx scheduler, err %d", err); + return; + } + + unicast_audio_tx(); + } +} + +static void unicast_stream_metadata_updated_cb(esp_ble_audio_bap_stream_t *stream) +{ + ESP_LOGI(TAG, "Unicast stream %p metadata updated", stream); +} + +static void unicast_stream_disabled_cb(esp_ble_audio_bap_stream_t *stream) +{ + ESP_LOGI(TAG, "Unicast stream %p disabled", stream); +} + +static void unicast_stream_stopped_cb(esp_ble_audio_bap_stream_t *stream, uint8_t reason) +{ + esp_ble_audio_bap_ep_info_t ep_info = {0}; + esp_err_t err; + + ESP_LOGI(TAG, "Unicast stream %p stopped, reason 0x%02x", stream, reason); + + err = esp_ble_audio_bap_ep_get_info(stream->ep, &ep_info); + if (err) { + ESP_LOGE(TAG, "Failed to get ep info, err %d", err); + return; + } + + if (ep_info.dir == ESP_BLE_AUDIO_DIR_SINK) { + err = example_audio_tx_scheduler_stop(&tx_scheduler); + if (err) { + ESP_LOGE(TAG, "Failed to stop tx scheduler, err %d", err); + } + + if (iso_data != NULL) { + free(iso_data); + iso_data = NULL; + } + } +} + +static void unicast_stream_released_cb(esp_ble_audio_bap_stream_t *stream) +{ + ESP_LOGI(TAG, "Unicast stream %p released", stream); +} + +static void unicast_stream_sent_cb(esp_ble_audio_bap_stream_t *stream, void *user_data) +{ + example_audio_tx_scheduler_on_sent(&tx_scheduler, user_data, TAG, "stream", stream); +} + +static void unicast_stream_connected_cb(esp_ble_audio_bap_stream_t *stream) +{ + ESP_LOGI(TAG, "Unicast stream %p connected", stream); +} + +static void unicast_stream_disconnected_cb(esp_ble_audio_bap_stream_t *stream, uint8_t reason) +{ + esp_ble_audio_bap_ep_info_t ep_info = {0}; + esp_err_t err; + + ESP_LOGI(TAG, "Unicast stream %p disconnected, reason 0x%02x", stream, reason); + + err = esp_ble_audio_bap_ep_get_info(stream->ep, &ep_info); + if (err) { + ESP_LOGE(TAG, "Failed to get ep info, err %d", err); + return; + } + + if (ep_info.dir == ESP_BLE_AUDIO_DIR_SINK) { + err = example_audio_tx_scheduler_stop(&tx_scheduler); + if (err) { + ESP_LOGE(TAG, "Failed to stop tx scheduler, err %d", err); + } + + if (iso_data != NULL) { + free(iso_data); + iso_data = NULL; + } + } +} + +static esp_ble_audio_bap_stream_ops_t unicast_stream_ops = { + .configured = unicast_stream_configured_cb, + .qos_set = unicast_stream_qos_set_cb, + .enabled = unicast_stream_enabled_cb, + .started = unicast_stream_started_cb, + .metadata_updated = unicast_stream_metadata_updated_cb, + .disabled = unicast_stream_disabled_cb, + .stopped = unicast_stream_stopped_cb, + .released = unicast_stream_released_cb, + .sent = unicast_stream_sent_cb, + .connected = unicast_stream_connected_cb, + .disconnected = unicast_stream_disconnected_cb, +}; + +static void unicast_discovery_complete_cb(esp_ble_conn_t *conn, int err, + const esp_ble_audio_csip_set_coordinator_set_member_t *member, + const esp_ble_audio_csip_set_coordinator_csis_inst_t *csis_inst) +{ + if (err) { + ESP_LOGE(TAG, "Unicast discovery completed, err %d", err); + return; + } + + if (default_conn_handle_get() != conn->handle) { + ESP_LOGE(TAG, "%s, not connected", __func__); + return; + } + + if (IS_ENABLED(CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER)) { + if (csis_inst == NULL) { + ESP_LOGW(TAG, "Failed to discover CAS CSIS"); + return; + } + + ESP_LOGI(TAG, "Found CAS with CSIS %p", csis_inst); + } else { + ESP_LOGI(TAG, "Found CAS"); + } + + err = esp_ble_audio_bap_unicast_client_discover(conn->handle, ESP_BLE_AUDIO_DIR_SINK); + if (err) { + ESP_LOGE(TAG, "Failed to discover sink, err %d", err); + } +} + +static void unicast_start_complete_cb(int err, esp_ble_conn_t *conn) +{ + if (err) { + ESP_LOGE(TAG, "Unicast start completed, err %d", err); + } else { + ESP_LOGI(TAG, "Unicast start completed"); + } +} + +static void unicast_update_complete_cb(int err, esp_ble_conn_t *conn) +{ + if (err) { + ESP_LOGE(TAG, "Unicast update completed, err %d", err); + } else { + ESP_LOGI(TAG, "Unicast update completed"); + } +} + +static void unicast_stop_complete_cb(int err, esp_ble_conn_t *conn) +{ + if (err) { + ESP_LOGE(TAG, "Unicast stop completed, err %d", err); + } else { + ESP_LOGI(TAG, "Unicast stop completed"); + } +} + +static esp_ble_audio_cap_initiator_cb_t cap_cb = { + .unicast_discovery_complete = unicast_discovery_complete_cb, + .unicast_start_complete = unicast_start_complete_cb, + .unicast_update_complete = unicast_update_complete_cb, + .unicast_stop_complete = unicast_stop_complete_cb, +}; + +static int unicast_group_create(void) +{ + esp_ble_audio_cap_unicast_group_stream_param_t group_stream_params = {0}; + esp_ble_audio_cap_unicast_group_stream_pair_param_t pair_params = {0}; + esp_ble_audio_cap_unicast_group_param_t group_param = {0}; + int err; + + if (unicast_group != NULL) { + return 0; + } + + group_stream_params.qos_cfg = &unicast_preset_48_2_1.qos; + group_stream_params.stream = &unicast_sink_streams[0]; + + pair_params.tx_param = &group_stream_params; + pair_params.rx_param = NULL; + + group_param.packing = ESP_BLE_ISO_PACKING_SEQUENTIAL; + group_param.params_count = 1; + group_param.params = &pair_params; + + err = esp_ble_audio_cap_unicast_group_create(&group_param, &unicast_group); + if (err) { + ESP_LOGE(TAG, "Failed to create unicast group, err %d", err); + return err; + } + + ESP_LOGI(TAG, "Created unicast group"); + + return 0; +} + +int unicast_group_delete(void) +{ + int err; + + if (unicast_group == NULL) { + return 0; + } + + err = esp_ble_audio_cap_unicast_group_delete(unicast_group); + if (err) { + ESP_LOGE(TAG, "Failed to delete unicast group, err %d", err); + return err; + } + + unicast_group = NULL; + + ESP_LOGI(TAG, "Deleted unicast group"); + + return 0; +} + +static int unicast_audio_start(esp_ble_conn_t *conn) +{ + esp_ble_audio_cap_unicast_audio_start_stream_param_t stream_param = {0}; + esp_ble_audio_cap_unicast_audio_start_param_t param = {0}; + int err; + + if (unicast_sink_eps[0] == NULL) { + ESP_LOGE(TAG, "No sink endpoint available"); + return -ENODEV; + } + + stream_param.member.member = conn; + stream_param.stream = &unicast_sink_streams[0]; + stream_param.ep = unicast_sink_eps[0]; + stream_param.codec_cfg = &unicast_preset_48_2_1.codec_cfg; + + param.type = ESP_BLE_AUDIO_CAP_SET_TYPE_AD_HOC; + param.count = 1; + param.stream_params = &stream_param; + + err = esp_ble_audio_cap_initiator_unicast_audio_start(¶m); + if (err) { + ESP_LOGE(TAG, "Failed to start unicast audio, err %d", err); + return err; + } + + ESP_LOGI(TAG, "Started unicast audio"); + + return 0; +} + +static void location_cb(esp_ble_conn_t *conn, + esp_ble_audio_dir_t dir, + esp_ble_audio_location_t loc) +{ + ESP_LOGI(TAG, "Location, dir %u loc 0x%08lx", dir, loc); +} + +static void available_contexts_cb(esp_ble_conn_t *conn, + esp_ble_audio_context_t snk_ctx, + esp_ble_audio_context_t src_ctx) +{ + ESP_LOGI(TAG, "Available contexts, sink 0x%04x source 0x%04x", snk_ctx, src_ctx); +} + +static void config_cb(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_bap_ascs_rsp_code_t rsp_code, + esp_ble_audio_bap_ascs_reason_t reason) +{ + ESP_LOGI(TAG, "Config, stream %p rsp_code %u reason %u", stream, rsp_code, reason); +} + +static void qos_cb(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_bap_ascs_rsp_code_t rsp_code, + esp_ble_audio_bap_ascs_reason_t reason) +{ + ESP_LOGI(TAG, "Qos, stream %p rsp_code %u reason %u", stream, rsp_code, reason); +} + +static void enable_cb(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_bap_ascs_rsp_code_t rsp_code, + esp_ble_audio_bap_ascs_reason_t reason) +{ + ESP_LOGI(TAG, "Enable, stream %p rsp_code %u reason %u", stream, rsp_code, reason); +} + +static void start_cb(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_bap_ascs_rsp_code_t rsp_code, + esp_ble_audio_bap_ascs_reason_t reason) +{ + ESP_LOGI(TAG, "Start, stream %p rsp_code %u reason %u", stream, rsp_code, reason); +} + +static void stop_cb(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_bap_ascs_rsp_code_t rsp_code, + esp_ble_audio_bap_ascs_reason_t reason) +{ + ESP_LOGI(TAG, "Stop, stream %p rsp_code %u reason %u", stream, rsp_code, reason); +} + +static void disable_cb(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_bap_ascs_rsp_code_t rsp_code, + esp_ble_audio_bap_ascs_reason_t reason) +{ + ESP_LOGI(TAG, "Disable, stream %p rsp_code %u reason %u", stream, rsp_code, reason); +} + +static void metadata_cb(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_bap_ascs_rsp_code_t rsp_code, + esp_ble_audio_bap_ascs_reason_t reason) +{ + ESP_LOGI(TAG, "Metadata, stream %p rsp_code %u reason %u", stream, rsp_code, reason); +} + +static void release_cb(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_bap_ascs_rsp_code_t rsp_code, + esp_ble_audio_bap_ascs_reason_t reason) +{ + ESP_LOGI(TAG, "Release, stream %p rsp_code %u reason %u", stream, rsp_code, reason); +} + +static void discover_cb(esp_ble_conn_t *conn, int err, esp_ble_audio_dir_t dir) +{ + if (err) { + ESP_LOGE(TAG, "Discovery failed, err %d", err); + return; + } + + if (default_conn_handle_get() != conn->handle) { + ESP_LOGE(TAG, "%s, not connected", __func__); + return; + } + + if (dir == ESP_BLE_AUDIO_DIR_SINK) { + ESP_LOGI(TAG, "Sink discover complete"); + + err = esp_ble_audio_bap_unicast_client_discover(conn->handle, ESP_BLE_AUDIO_DIR_SOURCE); + if (err) { + ESP_LOGE(TAG, "Failed to discover source, err %d", err); + return; + } + } else if (dir == ESP_BLE_AUDIO_DIR_SOURCE) { + ESP_LOGI(TAG, "Source discover complete"); + + err = unicast_group_create(); + if (err) { + return; + } + + err = unicast_audio_start(conn); + if (err) { + unicast_group_delete(); + return; + } + } +} + +static void pac_record_cb(esp_ble_conn_t *conn, esp_ble_audio_dir_t dir, + const esp_ble_audio_codec_cap_t *codec_cap) +{ + example_print_codec_cap(codec_cap); +} + +static void endpoint_cb(esp_ble_conn_t *conn, + esp_ble_audio_dir_t dir, + esp_ble_audio_bap_ep_t *ep) +{ + if (dir == ESP_BLE_AUDIO_DIR_SOURCE) { + for (size_t i = 0; i < ARRAY_SIZE(unicast_source_eps); i++) { + if (unicast_source_eps[i] == NULL) { + ESP_LOGI(TAG, "Source #%zu: ep %p", i, ep); + unicast_source_eps[i] = ep; + return; + } + } + } else if (dir == ESP_BLE_AUDIO_DIR_SINK) { + for (size_t i = 0; i < ARRAY_SIZE(unicast_sink_eps); i++) { + if (unicast_sink_eps[i] == NULL) { + ESP_LOGI(TAG, "Sink #%zu: ep %p", i, ep); + unicast_sink_eps[i] = ep; + return; + } + } + } + + ESP_LOGW(TAG, "Unhandled endpoint %p, dir %u", ep, dir); +} + +static esp_ble_audio_bap_unicast_client_cb_t unicast_client_cbs = { + .location = location_cb, + .available_contexts = available_contexts_cb, + .config = config_cb, + .qos = qos_cb, + .enable = enable_cb, + .start = start_cb, + .stop = stop_cb, + .disable = disable_cb, + .metadata = metadata_cb, + .release = release_cb, + .pac_record = pac_record_cb, + .endpoint = endpoint_cb, + .discover = discover_cb, +}; + +static void unicast_audio_tx(void) +{ + esp_ble_audio_bap_ep_info_t ep_info = {0}; + esp_ble_audio_cap_stream_t *cap_stream; + esp_ble_audio_bap_stream_t *bap_stream; + esp_err_t err; + + cap_stream = &unicast_sink_streams[0]; + bap_stream = &unicast_sink_streams[0].bap_stream; + + if (bap_stream->ep == NULL) { + return; + } + + err = esp_ble_audio_bap_ep_get_info(bap_stream->ep, &ep_info); + if (err) { + return; + } + + if (ep_info.state != ESP_BLE_AUDIO_BAP_EP_STATE_STREAMING) { + return; + } + + if (bap_stream->qos == NULL || bap_stream->qos->sdu == 0) { + ESP_LOGE(TAG, "Invalid stream qos"); + return; + } + + if (iso_data == NULL) { + ESP_LOGE(TAG, "TX buffer unavailable, SDU %u", bap_stream->qos->sdu); + return; + } + + memset(iso_data, (uint8_t)tx_seq_num, bap_stream->qos->sdu); + + err = esp_ble_audio_cap_stream_send(cap_stream, iso_data, + bap_stream->qos->sdu, + tx_seq_num); + if (err) { + ESP_LOGD(TAG, "Failed to transmit data on streams, err %d", err); + return; + } + + tx_seq_num++; +} + +static void tx_scheduler_cb(void *arg) +{ + (void)arg; + unicast_audio_tx(); +} + +int cap_initiator_init(void) +{ + int err; + + err = esp_ble_audio_cap_initiator_register_cb(&cap_cb); + if (err) { + ESP_LOGE(TAG, "Failed to register CAP callbacks (err %d)", err); + return err; + } + + err = esp_ble_audio_bap_unicast_client_register_cb(&unicast_client_cbs); + if (err) { + ESP_LOGE(TAG, "Failed to register BAP unicast client callbacks (err %d)", err); + return err; + } + + for (size_t i = 0; i < ARRAY_SIZE(unicast_sink_streams); i++) { + esp_ble_audio_cap_stream_ops_register(&unicast_sink_streams[i], &unicast_stream_ops); + } + + for (size_t i = 0; i < ARRAY_SIZE(unicast_source_streams); i++) { + esp_ble_audio_cap_stream_ops_register(&unicast_source_streams[i], &unicast_stream_ops); + } + + err = example_audio_tx_scheduler_init(&tx_scheduler, + tx_scheduler_cb, + NULL); + if (err) { + ESP_LOGE(TAG, "Failed to init tx scheduler, err %d", err); + return err; + } + + ESP_LOGI(TAG, "CAP initiator initialized"); + + return 0; +} + +int cap_initiator_setup(void) +{ + uint16_t conn_handle; + int err; + + conn_handle = default_conn_handle_get(); + if (conn_handle == CONN_HANDLE_INIT) { + ESP_LOGE(TAG, "%s, not connected", __func__); + return -ENOTCONN; + } + + err = esp_ble_audio_cap_initiator_unicast_discover(conn_handle); + if (err) { + ESP_LOGE(TAG, "Failed to discover CAS, err %d", err); + return err; + } + + ESP_LOGI(TAG, "CAP initiator setup"); + + return 0; +} diff --git a/examples/bluetooth/esp_ble_audio/tmap/central/main/ccp_server.c b/examples/bluetooth/esp_ble_audio/tmap/central/main/ccp_server.c new file mode 100644 index 0000000000..d396b5bc7d --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/central/main/ccp_server.c @@ -0,0 +1,63 @@ +/* + * SPDX-FileCopyrightText: 2023 NXP + * SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "tmap_central.h" + +static bool tbs_originate_call_cb(esp_ble_conn_t *conn, + uint8_t call_index, + const char *caller_id) +{ + ESP_LOGI(TAG, "CCP: Placing call to remote with id %u to %s", + call_index, caller_id); + + return true; +} + +static void tbs_terminate_call_cb(esp_ble_conn_t *conn, + uint8_t call_index, + uint8_t reason) +{ + ESP_LOGI(TAG, "CCP: Call terminated for id %u with reason %u", + call_index, reason); +} + +static esp_ble_audio_tbs_cb_t tbs_cbs = { + .originate_call = tbs_originate_call_cb, + .terminate_call = tbs_terminate_call_cb, +}; + +int ccp_server_init(void) +{ + const esp_ble_audio_tbs_register_param_t gtbs_param = { + .provider_name = "Generic TBS", + .uci = "un000", + .uri_schemes_supported = "tel,wechat", + .gtbs = true, + .authorization_required = false, + .technology = ESP_BLE_AUDIO_TBS_TECHNOLOGY_5G, + .supported_features = CONFIG_BT_TBS_SUPPORTED_FEATURES, + }; + uint8_t bearer_index; + int err; + + esp_ble_audio_tbs_register_cb(&tbs_cbs); + + err = esp_ble_audio_tbs_register_bearer(>bs_param, &bearer_index); + if (err) { + ESP_LOGE(TAG, "Failed to register gtbs bearer (err %d)", err); + return err; + } + + ESP_LOGI(TAG, "Registered gtbs bearer %u", bearer_index); + + return 0; +} diff --git a/examples/bluetooth/esp_ble_audio/tmap/central/main/idf_component.yml b/examples/bluetooth/esp_ble_audio/tmap/central/main/idf_component.yml new file mode 100644 index 0000000000..bb02c0922a --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/central/main/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + example_init: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_audio/common_components/example_init + example_utils: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_audio/common_components/example_utils diff --git a/examples/bluetooth/esp_ble_audio/tmap/central/main/main.c b/examples/bluetooth/esp_ble_audio/tmap/central/main/main.c new file mode 100644 index 0000000000..880848a0f2 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/central/main/main.c @@ -0,0 +1,446 @@ +/* + * SPDX-FileCopyrightText: 2023 NXP + * SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "nvs_flash.h" +#include "esp_system.h" +#include "esp_timer.h" + +#include "host/ble_hs.h" +#include "services/gap/ble_svc_gap.h" + +#include "tmap_central.h" + +#include "ble_audio_example_init.h" +#include "ble_audio_example_utils.h" + +#define SCAN_INTERVAL 160 /* 100ms */ +#define SCAN_WINDOW 160 /* 100ms */ + +#define INIT_SCAN_INTERVAL 16 /* 10ms */ +#define INIT_SCAN_WINDOW 16 /* 10ms */ +#define CONN_INTERVAL 64 /* 64 * 1.25 = 80ms */ +#define CONN_LATENCY 0 +#define CONN_TIMEOUT 500 /* 500 * 10ms = 5s */ +#define CONN_MAX_CE_LEN 0xFFFF +#define CONN_MIN_CE_LEN 0xFFFF +#define CONN_DURATION 10000 /* 10s */ + +static uint16_t default_conn_handle = CONN_HANDLE_INIT; +static bool disc_completed; +static bool disc_cancelled; +static bool mtu_exchanged; + +uint16_t default_conn_handle_get(void) +{ + return default_conn_handle; +} + +static void tmap_discovery_complete(esp_ble_audio_tmap_role_t role, + esp_ble_conn_t *conn, int err) +{ + if (err) { + ESP_LOGE(TAG, "TMAP discovery completed, err %d", err); + return; + } + + if (conn->handle != default_conn_handle) { + return; + } + + ESP_LOGI(TAG, "TMAP discovery done"); + + err = cap_initiator_setup(); + if (err) { + return; + } +} + +static esp_ble_audio_tmap_cb_t tmap_callbacks = { + .discovery_complete = tmap_discovery_complete, +}; + +static void ext_scan_start(void) +{ + struct ble_gap_disc_params params = {0}; + uint8_t own_addr_type; + int err; + + err = ble_hs_id_infer_auto(0, &own_addr_type); + if (err) { + ESP_LOGE(TAG, "Failed to determine own addr type, err %d", err); + return; + } + + params.passive = 1; + params.itvl = SCAN_INTERVAL; + params.window = SCAN_WINDOW; + + err = ble_gap_disc(own_addr_type, BLE_HS_FOREVER, ¶ms, + example_audio_gap_event_cb, NULL); + if (err) { + ESP_LOGE(TAG, "Failed to start scanning, err %d", err); + return; + } + + ESP_LOGI(TAG, "Extended scan started"); +} + +static int conn_create(ble_addr_t *dst) +{ + struct ble_gap_conn_params params = {0}; + uint8_t own_addr_type = 0; + int err; + + err = ble_hs_id_infer_auto(0, &own_addr_type); + if (err) { + ESP_LOGE(TAG, "Failed to determine address type, err %d", err); + return err; + } + + err = ble_gap_disc_cancel(); + if (err) { + ESP_LOGE(TAG, "Failed to stop scanning, err %d", err); + return err; + } + + disc_cancelled = true; + + params.scan_itvl = INIT_SCAN_INTERVAL; + params.scan_window = INIT_SCAN_WINDOW; + params.itvl_min = CONN_INTERVAL; + params.itvl_max = CONN_INTERVAL; + params.latency = CONN_LATENCY; + params.supervision_timeout = CONN_TIMEOUT; + params.max_ce_len = CONN_MAX_CE_LEN; + params.min_ce_len = CONN_MIN_CE_LEN; + + return ble_gap_connect(own_addr_type, dst, CONN_DURATION, ¶ms, + example_audio_gap_event_cb, NULL); +} + +static int pairing_start(uint16_t conn_handle) +{ + return ble_gap_security_initiate(conn_handle); +} + +static int exchange_mtu(uint16_t conn_handle) +{ + return ble_gattc_exchange_mtu(conn_handle, NULL, NULL); +} + +static bool check_and_connect(uint8_t type, const uint8_t *data, + uint8_t data_len, void *user_data) +{ + esp_ble_audio_gap_app_event_t *event; + ble_addr_t dst = {0}; + uint16_t tmap_role; + uint16_t uuid_val; + int err; + + event = user_data; + assert(event); + + if (type != EXAMPLE_AD_TYPE_SERVICE_DATA16) { + return true; /* Continue parsing to next AD data type */ + } + + if (data_len < sizeof(uuid_val)) { + ESP_LOGW(TAG, "Invalid ad size %u (tmap uuid)", data_len); + return true; /* Continue parsing to next AD data type */ + } + + uuid_val = sys_get_le16(data); + + if (uuid_val != ESP_BLE_AUDIO_UUID_TMAS_VAL) { + /* We are looking for the TMAS service data */ + return true; /* Continue parsing to next AD data type */ + } + + ESP_LOGI(TAG, "Found TMAS in peer adv data!"); + + if (data_len < sizeof(uuid_val) + sizeof(tmap_role)) { + ESP_LOGW(TAG, "Invalid ad size %u (tmap role)", data_len); + return false; /* Stop parsing */ + } + + tmap_role = sys_get_le16(data + sizeof(uuid_val)); + + if ((tmap_role & ESP_BLE_AUDIO_TMAP_ROLE_UMR) == 0) { + ESP_LOGW(TAG, "No TMAS UMR support!"); + return false; /* Stop parsing */ + } + + dst.type = event->ext_scan_recv.addr.type; + memcpy(dst.val, event->ext_scan_recv.addr.val, sizeof(dst.val)); + + err = conn_create(&dst); + if (err) { + ESP_LOGE(TAG, "Failed to create conn, err %d", err); + + if (disc_cancelled) { + disc_cancelled = false; + ext_scan_start(); + } + } + + return false; /* Stop parsing */ +} + +static void ext_scan_recv(esp_ble_audio_gap_app_event_t *event) +{ + if (default_conn_handle != CONN_HANDLE_INIT) { + return; + } + + /* Check if the advertising is connectable and if TMAS is supported */ + if (event->ext_scan_recv.event_type & EXAMPLE_ADV_PROP_CONNECTABLE) { + esp_ble_audio_data_parse(event->ext_scan_recv.data, + event->ext_scan_recv.data_len, + check_and_connect, (void *)event); + } +} + +static void acl_connect(esp_ble_audio_gap_app_event_t *event) +{ + int err; + + if (event->acl_connect.status) { + ESP_LOGE(TAG, "connection failed, status %d", event->acl_connect.status); + return; + } + + ESP_LOGI(TAG, "Conn established:"); + ESP_LOGI(TAG, "conn_handle 0x%04x status 0x%02x role %u peer %02x:%02x:%02x:%02x:%02x:%02x", + event->acl_connect.conn_handle, event->acl_connect.status, + event->acl_connect.role, event->acl_connect.dst.val[5], + event->acl_connect.dst.val[4], event->acl_connect.dst.val[3], + event->acl_connect.dst.val[2], event->acl_connect.dst.val[1], + event->acl_connect.dst.val[0]); + + err = pairing_start(event->acl_connect.conn_handle); + if (err) { + ESP_LOGE(TAG, "Failed to initiate security, err %d", err); + return; + } + + default_conn_handle = event->acl_connect.conn_handle; +} + +static void acl_disconnect(esp_ble_audio_gap_app_event_t *event) +{ + ESP_LOGI(TAG, "Conn terminated: conn_handle 0x%04x reason 0x%02x", + event->acl_disconnect.conn_handle, event->acl_disconnect.reason); + + default_conn_handle = CONN_HANDLE_INIT; + disc_completed = false; + disc_cancelled = false; + mtu_exchanged = false; + + unicast_group_delete(); + + ext_scan_start(); +} + +static void security_change(esp_ble_iso_gap_app_event_t *event) +{ + int err; + + if (event->security_change.status) { + ESP_LOGE(TAG, "security change failed, status %d", event->security_change.status); + return; + } + + ESP_LOGI(TAG, "Security change:"); + ESP_LOGI(TAG, "conn_handle 0x%04x status 0x%02x role %u sec_level %u bonded %u " + "peer %02x:%02x:%02x:%02x:%02x:%02x", + event->security_change.conn_handle, event->security_change.status, + event->security_change.role, event->security_change.sec_level, + event->security_change.bonded, event->security_change.dst.val[5], + event->security_change.dst.val[4], event->security_change.dst.val[3], + event->security_change.dst.val[2], event->security_change.dst.val[1], + event->security_change.dst.val[0]); + + err = exchange_mtu(event->security_change.conn_handle); + if (err) { + ESP_LOGE(TAG, "Failed to exchange MTU, err %d", err); + return; + } +} + +static void iso_gap_app_cb(esp_ble_audio_gap_app_event_t *event) +{ + switch (event->type) { + case ESP_BLE_AUDIO_GAP_EVENT_EXT_SCAN_RECV: + ext_scan_recv(event); + break; + case ESP_BLE_AUDIO_GAP_EVENT_ACL_CONNECT: + acl_connect(event); + break; + case ESP_BLE_AUDIO_GAP_EVENT_ACL_DISCONNECT: + acl_disconnect(event); + break; + case ESP_BLE_AUDIO_GAP_EVENT_SECURITY_CHANGE: + security_change(event); + break; + default: + break; + } +} + +static void gatt_mtu_change(esp_ble_audio_gatt_app_event_t *event) +{ + esp_err_t err; + + ESP_LOGI(TAG, "gatt mtu change, conn_handle %u, mtu %u", + event->gatt_mtu_change.conn_handle, event->gatt_mtu_change.mtu); + + if (event->gatt_mtu_change.mtu < ESP_BLE_AUDIO_ATT_MTU_MIN) { + ESP_LOGW(TAG, "Invalid new mtu %u, shall be at least %u", + event->gatt_mtu_change.mtu, ESP_BLE_AUDIO_ATT_MTU_MIN); + return; + } + + err = esp_ble_audio_gattc_disc_start(event->gatt_mtu_change.conn_handle); + if (err) { + ESP_LOGE(TAG, "Failed to start svc disc, err %d", err); + return; + } + + ESP_LOGI(TAG, "Start discovering gatt services"); + + /* Note: + * MTU exchanged event may arrived after discover completed event. + */ + mtu_exchanged = true; + + if (disc_completed) { + err = esp_ble_audio_tmap_discover(default_conn_handle, &tmap_callbacks); + if (err) { + ESP_LOGE(TAG, "Failed to discover tmap, err %d", err); + return; + } + + vcp_vol_ctlr_discover(); + } +} + +static void gattc_disc_cmpl(esp_ble_audio_gatt_app_event_t *event) +{ + esp_err_t err; + + ESP_LOGI(TAG, "gattc disc cmpl, status %u, conn_handle %u", + event->gattc_disc_cmpl.status, event->gattc_disc_cmpl.conn_handle); + + if (event->gattc_disc_cmpl.status) { + ESP_LOGE(TAG, "gattc disc failed, status %u", event->gattc_disc_cmpl.status); + return; + } + + /* Note: + * Discover completed event may arrived before MTU exchanged event. + */ + disc_completed = true; + + if (mtu_exchanged) { + err = esp_ble_audio_tmap_discover(default_conn_handle, &tmap_callbacks); + if (err) { + ESP_LOGE(TAG, "Failed to discover tmap, err %d", err); + return; + } + + vcp_vol_ctlr_discover(); + } +} + +static void iso_gatt_app_cb(esp_ble_audio_gatt_app_event_t *event) +{ + switch (event->type) { + case ESP_BLE_AUDIO_GATT_EVENT_GATT_MTU_CHANGE: + gatt_mtu_change(event); + break; + case ESP_BLE_AUDIO_GATT_EVENT_GATTC_DISC_CMPL: + gattc_disc_cmpl(event); + break; + default: + break; + } +} + +void app_main(void) +{ + esp_ble_audio_start_info_t start_info = {0}; + esp_ble_audio_init_info_t init_info = { + .gap_cb = iso_gap_app_cb, + .gatt_cb = iso_gatt_app_cb, + }; + esp_err_t err; + + /* Initialize NVS — it is used to store PHY calibration data */ + err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK(err); + + err = bluetooth_init(); + if (err) { + ESP_LOGE(TAG, "Failed to initialize BLE, err %d", err); + return; + } + + err = esp_ble_audio_common_init(&init_info); + if (err) { + ESP_LOGE(TAG, "Failed to initialize audio, err %d", err); + return; + } + + err = esp_ble_audio_tmap_register(ESP_BLE_AUDIO_TMAP_ROLE_CG | ESP_BLE_AUDIO_TMAP_ROLE_UMS); + if (err) { + ESP_LOGE(TAG, "Failed to register tmap, err %d", err); + return; + } + + err = cap_initiator_init(); + if (err) { + return; + } + + err = vcp_vol_ctlr_init(); + if (err) { + return; + } + + err = mcp_server_init(); + if (err) { + return; + } + + err = ccp_server_init(); + if (err) { + return; + } + + err = esp_ble_audio_common_start(&start_info); + if (err) { + ESP_LOGE(TAG, "Failed to start audio, err %d", err); + return; + } + + err = ble_svc_gap_device_name_set("TMAP Central"); + if (err) { + ESP_LOGE(TAG, "Failed to set device name, err %d", err); + return; + } + + ext_scan_start(); +} diff --git a/examples/bluetooth/esp_ble_audio/tmap/central/main/mcp_server.c b/examples/bluetooth/esp_ble_audio/tmap/central/main/mcp_server.c new file mode 100644 index 0000000000..1cbc88de6e --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/central/main/mcp_server.c @@ -0,0 +1,26 @@ +/* + * SPDX-FileCopyrightText: 2023 NXP + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "tmap_central.h" + +int mcp_server_init(void) +{ + int err; + + err = esp_ble_audio_media_proxy_pl_init(); + if (err) { + ESP_LOGE(TAG, "Failed to init media proxy pl (err %d)", err); + return err; + } + + ESP_LOGI(TAG, "MCP server initialized"); + + return 0; +} diff --git a/examples/bluetooth/esp_ble_audio/tmap/central/main/tmap_central.h b/examples/bluetooth/esp_ble_audio/tmap/central/main/tmap_central.h new file mode 100644 index 0000000000..7da6ee3cce --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/central/main/tmap_central.h @@ -0,0 +1,50 @@ +/* + * SPDX-FileCopyrightText: 2023 NXP + * SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "esp_log.h" + +#include "sdkconfig.h" + +#include "esp_ble_audio_lc3_defs.h" +#include "esp_ble_audio_aics_api.h" +#include "esp_ble_audio_cap_api.h" +#include "esp_ble_audio_pacs_api.h" +#include "esp_ble_audio_vcp_api.h" +#include "esp_ble_audio_tbs_api.h" +#include "esp_ble_audio_tmap_api.h" +#include "esp_ble_audio_csip_api.h" +#include "esp_ble_audio_mcs_defs.h" +#include "esp_ble_audio_mcc_api.h" +#include "esp_ble_audio_media_proxy_api.h" +#include "esp_ble_audio_vocs_api.h" +#include "esp_ble_audio_tbs_api.h" + +#include "ble_audio_example_utils.h" + +#define TAG "TMAP_CEN" + +#define CONN_HANDLE_INIT 0xFFFF + +uint16_t default_conn_handle_get(void); + +int mcp_server_init(void); + +int ccp_server_init(void); + +int vcp_vol_ctlr_init(void); + +int vcp_vol_ctlr_discover(void); + +int cap_initiator_init(void); + +int cap_initiator_setup(void); + +int unicast_group_delete(void); diff --git a/examples/bluetooth/esp_ble_audio/tmap/central/main/vcp_vol_ctlr.c b/examples/bluetooth/esp_ble_audio/tmap/central/main/vcp_vol_ctlr.c new file mode 100644 index 0000000000..6ba7febb6f --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/central/main/vcp_vol_ctlr.c @@ -0,0 +1,110 @@ +/* + * SPDX-FileCopyrightText: 2023 NXP + * SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "tmap_central.h" + +static esp_ble_audio_vcp_vol_ctlr_t *vcp_vol_ctlr; + +static void vcs_discover_cb(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr, int err, + uint8_t vocs_count, uint8_t aics_count) +{ + if (err) { + ESP_LOGE(TAG, "VCP discovery cb failed, err %d", err); + return; + } + + ESP_LOGI(TAG, "VCP discovery done, %p %p", vol_ctlr, vcp_vol_ctlr); + + err = esp_ble_audio_vcp_vol_ctlr_mute(vol_ctlr); + if (err) { + ESP_LOGE(TAG, "Failed to send mute command, err %d", err); + } +} + +static void vcs_write_cb(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr, int err) +{ + if (err) { + ESP_LOGE(TAG, "VCP write cb failed, err %d", err); + } else { + ESP_LOGI(TAG, "VCP write cb done"); + } +} + +static void vcs_state_cb(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr, + int err, uint8_t volume, uint8_t mute) +{ + if (err) { + ESP_LOGE(TAG, "VCP state cb failed, err %d", err); + } else { + ESP_LOGI(TAG, "VCP state cb done, volume %u mute %u", volume, mute); + } +} + +static void vcs_flags_cb(esp_ble_audio_vcp_vol_ctlr_t *vol_ctlr, + int err, uint8_t flags) +{ + if (err) { + ESP_LOGE(TAG, "VCP flags cb failed, err %d", err); + } else { + ESP_LOGI(TAG, "VCP flags cb done, flags 0x%02x", flags); + } +} + +static esp_ble_audio_vcp_vol_ctlr_cb_t vcp_cbs = { + .discover = vcs_discover_cb, + .vol_down = vcs_write_cb, + .vol_up = vcs_write_cb, + .mute = vcs_write_cb, + .unmute = vcs_write_cb, + .vol_down_unmute = vcs_write_cb, + .vol_up_unmute = vcs_write_cb, + .vol_set = vcs_write_cb, + .state = vcs_state_cb, + .flags = vcs_flags_cb, +}; + +int vcp_vol_ctlr_discover(void) +{ + uint16_t conn_handle; + int err; + + conn_handle = default_conn_handle_get(); + if (conn_handle == CONN_HANDLE_INIT) { + ESP_LOGE(TAG, "%s, not connected", __func__); + return -ENOTCONN; + } + + err = esp_ble_audio_vcp_vol_ctlr_discover(conn_handle, &vcp_vol_ctlr); + if (err) { + ESP_LOGE(TAG, "Failed to discover vcp vol ctlr, err %d", err); + return err; + } + + ESP_LOGI(TAG, "VCP volume controller discovering"); + + return 0; +} + +int vcp_vol_ctlr_init(void) +{ + int err; + + err = esp_ble_audio_vcp_vol_ctlr_cb_register(&vcp_cbs); + if (err) { + ESP_LOGE(TAG, "Failed to register vcp vol ctlr cb, err %d", err); + return err; + } + + ESP_LOGI(TAG, "VCP volume controller initialized"); + + return 0; +} diff --git a/examples/bluetooth/esp_ble_audio/tmap/central/sdkconfig.defaults b/examples/bluetooth/esp_ble_audio/tmap/central/sdkconfig.defaults new file mode 100644 index 0000000000..1d7ff95251 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/central/sdkconfig.defaults @@ -0,0 +1,31 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration +# + +CONFIG_BT_ENABLED=y +CONFIG_BT_BLUEDROID_ENABLED=n +CONFIG_BT_NIMBLE_ENABLED=y +CONFIG_BT_NIMBLE_EXT_ADV=y +CONFIG_BT_NIMBLE_MAX_CONNECTIONS=1 +CONFIG_BT_NIMBLE_MAX_CCCDS=40 +CONFIG_BT_NIMBLE_ISO=y +CONFIG_BT_NIMBLE_LOG_LEVEL_WARNING=y + +CONFIG_BT_ISO_MAX_CHAN=2 + +CONFIG_BT_TMAP=y +CONFIG_BT_CAP_INITIATOR=y +CONFIG_BT_CAP_COMMANDER=y +CONFIG_BT_CSIP_SET_COORDINATOR=y +CONFIG_BT_BAP_UNICAST_CLIENT=y +CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT=2 +CONFIG_BT_VCP_VOL_CTLR=y +CONFIG_BT_MPL=y +CONFIG_BT_MCS=y +CONFIG_BT_MCTL=y +CONFIG_BT_MCTL_LOCAL_PLAYER_CONTROL=y +CONFIG_BT_MCTL_LOCAL_PLAYER_REMOTE_CONTROL=y +CONFIG_BT_TBS=y +CONFIG_BT_TBS_SUPPORTED_FEATURES=3 + +CONFIG_FREERTOS_HZ=1000 diff --git a/examples/bluetooth/esp_ble_audio/tmap/central/sdkconfig.defaults.esp32h4 b/examples/bluetooth/esp_ble_audio/tmap/central/sdkconfig.defaults.esp32h4 new file mode 100644 index 0000000000..5920ce3f85 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/central/sdkconfig.defaults.esp32h4 @@ -0,0 +1,6 @@ +# Override some defaults so BT stack is enabled +# by default in this example + +CONFIG_IDF_TARGET="esp32h4" + +CONFIG_BT_LE_ISO_SUPPORT=y diff --git a/examples/bluetooth/esp_ble_audio/tmap/peripheral/CMakeLists.txt b/examples/bluetooth/esp_ble_audio/tmap/peripheral/CMakeLists.txt new file mode 100644 index 0000000000..274d206d88 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/peripheral/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.22) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +idf_build_set_property(MINIMAL_BUILD ON) +project(tmap_peripheral) diff --git a/examples/bluetooth/esp_ble_audio/tmap/peripheral/README.md b/examples/bluetooth/esp_ble_audio/tmap/peripheral/README.md new file mode 100644 index 0000000000..5f8704bc78 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/peripheral/README.md @@ -0,0 +1,78 @@ +| Supported Targets | ESP32-H4 | +| ----------------- | -------- | + +# TMAP Peripheral Example + +(See the README.md file in the upper level `examples` directory for more information about examples.) + +This example implements the **Telephone and Media Audio Profile (TMAP) Peripheral** roles: **Call Terminal (CT)** and **Unicast Media Receiver (UMR)**. The peripheral advertises connectable extended advertising with ASCS, CAS, and **TMAS (Telephone and Media Audio Service)** with **UMR and CT** roles, plus targeted unicast announcement (sink/source contexts) and device name; optionally CSIS RSI when built as a set member (e.g. duo earbuds). A TMAP Central (e.g. the [central](../central) example) that scans for TMAS UMR will discover and connect to this device. After connection, the central performs TMAP discovery; the peripheral also runs TMAP discovery to detect peer roles (CG/UMS), then discovers TBS (Telephone Bearer Service) on the central for call control. The peripheral acts as **BAP Unicast Server** (responds to codec config, QoS, enable, start; receives/sends unicast audio), **VCP Volume Renderer** (local volume/mute), **TBS client** (originate/terminate calls via central), and **MCP controller** (Media Control). Run it together with the [central](../central) example on another device as the TMAP Central. + +The implementation uses the NimBLE host stack with ISO and LE Audio support, ESP-BLE-AUDIO (TMAP CT+UMR, CAP acceptor, BAP unicast server, VCP volume renderer, TBS client, optional CSIP set member, MCP/MCC). Optional Kconfig: earbuds type (single / duo with set member), device rank, earbud location, device name. + +## Requirements + +* A board with Bluetooth LE 5.2, ISO, and LE Audio support (e.g. ESP32-H4) +* Another device running the [central](../central) example as TMAP Central (CG + UMS) + +## How to Use Example + +Before project configuration and build, set the correct chip target: + +```bash +idf.py set-target esp32h4 +``` + +### Configure the Project + +Open the configuration menu to set earbuds type, location, and device name: + +```bash +idf.py menuconfig +``` + +Under **Example: TMAP Peripheral (CT & UMR)** you can set: + +* **Earbuds type** — Single ear headset or Duo headset (duo enables CSIP set member and adds RSI to advertising) +* **Device rank in set** — Rank of this device in set (when duo is selected) +* **Earbud Location** — Left Ear or Right Ear + +### Build and Flash + +Run the following to build, flash and monitor: + +```bash +idf.py -p PORT flash monitor +``` + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the [Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF. + +## Example Flow + +1. **Initialization**: NVS, Bluetooth stack, and LE Audio common layer (`esp_ble_audio_common_init`) with GAP and GATT callbacks. Register TMAP roles CT and UMR (`esp_ble_audio_tmap_register(ESP_BLE_AUDIO_TMAP_ROLE_CT | ESP_BLE_AUDIO_TMAP_ROLE_UMR)`). Optionally initialize CSIP set member and generate RSI for advertising. Initialize VCP volume renderer. Initialize BAP unicast server (PACS, ASCS callbacks, stream ops). Initialize CCP call control (TBS client). Initialize MCP controller. Start the audio stack (with optional CSIS instance when set member) and set the device name. +2. **Advertising**: Start connectable extended advertising with flags, appearance (earbud), ASCS/CAS/TMAS UUIDs, ASCS targeted + contexts, CAS targeted, TMAS with UMR|CT, device name, and optionally CSIS RSI. +3. **Central connection**: When the central connects, store the connection handle. On MTU change, start GATT service discovery. On discovery complete, start TMAP discovery (`tmap_discover_tmas`). +4. **TMAP discovery complete**: Store whether the peer is CG and/or UMS; start TBS discovery on the central (`ccp_discover_tbs`). The central will then run CAP initiator setup and configure unicast streams. +5. **Unicast**: The central configures and starts streams; the peripheral handles ASCS config/QoS/enable/start, starts sink streams when enabled, and receives/sends audio on stream callbacks. +6. **Call control**: The peripheral (TBS client) can originate or terminate calls via the central’s TBS (CCP server); discover and URI list read complete in callbacks. + +## Example Output + +``` +I (xxx) TMAP_PER: Extended adv instance 0 started +I (xxx) TMAP_PER: connection established, status 0 +I (xxx) TMAP_PER: gatt mtu change, conn_handle 1, mtu ... +I (xxx) TMAP_PER: gattc disc cmpl, status 0, conn_handle 1 +I (xxx) TMAP_PER: TMAP discovery done +I (xxx) TMAP_PER: CCP: Discovered GTBS +... +I (xxx) TMAP_PER: Stream 0x... started +... +``` + +If the connection is lost: + +``` +I (xxx) TMAP_PER: connection disconnected, reason 0x... +``` diff --git a/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/CMakeLists.txt b/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/CMakeLists.txt new file mode 100644 index 0000000000..4403c811e8 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/CMakeLists.txt @@ -0,0 +1,14 @@ +set(srcs "bap_unicast_sr.c" + "button.c" + "ccp_call_ctrl.c" + "mcp_ctlr.c" + "tmap_ct_umr.c" + "vcp_vol_renderer.c" + "main.c") + +if(CONFIG_EXAMPLE_TMAP_PER_DUO) + list(APPEND srcs "csip_set_member.c") +endif() + +idf_component_register(SRCS "${srcs}" + REQUIRES bt nvs_flash) diff --git a/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/Kconfig.projbuild b/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/Kconfig.projbuild new file mode 100644 index 0000000000..3da7e894c2 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/Kconfig.projbuild @@ -0,0 +1,44 @@ +# SPDX-FileCopyrightText: 2022 Nordic Semiconductor ASA +# SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 + +menu "Example: TMAP Peripheral (CT & UMR)" + + config EXAMPLE_TMAP_PER_SET_RANK + int "Device rank in set" + depends on EXAMPLE_TMAP_PER_DUO + range 1 2 + help + Rank of this device in set. + + choice EXAMPLE_TMAP_PER_TYPE_CHOICE + + prompt "Earbuds type" + help + Select the Earbuds Type to compile. + + config EXAMPLE_TMAP_PER_SINGLE + bool "Single ear headset" + + config EXAMPLE_TMAP_PER_DUO + bool "Duo headset" + select BT_CSIP_SET_MEMBER + select BT_CAP_ACCEPTOR_SET_MEMBER + + endchoice + + choice EXAMPLE_TMAP_PER_LOCATION + + prompt "Earbud Location" + help + Select the Earbud location. + + config EXAMPLE_TMAP_PER_LEFT + bool "Left Ear" + + config EXAMPLE_TMAP_PER_RIGHT + bool "Right Ear" + + endchoice + +endmenu diff --git a/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/bap_unicast_sr.c b/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/bap_unicast_sr.c new file mode 100644 index 0000000000..f0416f9a7f --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/bap_unicast_sr.c @@ -0,0 +1,517 @@ +/* + * SPDX-FileCopyrightText: 2021-2024 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2022 Codecoup + * SPDX-FileCopyrightText: 2023 NXP + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include "tmap_peripheral.h" + +static uint8_t codec_data[] = + ESP_BLE_AUDIO_CODEC_CAP_LC3_DATA( + ESP_BLE_AUDIO_CODEC_CAP_FREQ_16KHZ | \ + ESP_BLE_AUDIO_CODEC_CAP_FREQ_32KHZ | \ + ESP_BLE_AUDIO_CODEC_CAP_FREQ_48KHZ, /* Sampling frequency 16kHz/32kHz/48kHz */ + ESP_BLE_AUDIO_CODEC_CAP_DURATION_7_5 | \ + ESP_BLE_AUDIO_CODEC_CAP_DURATION_10, /* Frame duration 7.5ms/10ms */ + ESP_BLE_AUDIO_CODEC_CAP_CHAN_COUNT_SUPPORT(1), /* Supported channels 1 */ + 30, /* Minimum 30 octets per frame */ + 155, /* Maximum 155 octets per frame */ + 1); /* Maximum 1 codec frame per SDU */ + +static uint8_t codec_meta[] = + ESP_BLE_AUDIO_CODEC_CAP_LC3_META(SINK_CONTEXT | SOURCE_CONTEXT); + +static const esp_ble_audio_codec_cap_t lc3_codec_cap = + ESP_BLE_AUDIO_CODEC_CAP_LC3(codec_data, codec_meta); + +static esp_ble_audio_pacs_cap_t cap = { + .codec_cap = &lc3_codec_cap, +}; + +static esp_ble_audio_bap_stream_t streams[CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT + \ + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT]; + +static struct audio_sink { + esp_ble_audio_bap_stream_t *stream; + example_audio_rx_metrics_t rx_metrics; +} sink_streams[CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT]; + +static size_t configured_sink_stream_count; + +static struct audio_source { + esp_ble_audio_bap_stream_t *stream; + uint16_t seq_num; +} source_streams[CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT]; + +static size_t configured_source_stream_count; + +static const esp_ble_audio_bap_qos_cfg_pref_t qos_pref = + ESP_BLE_AUDIO_BAP_QOS_CFG_PREF(true, /* Unframed PDUs supported */ + ESP_BLE_ISO_PHY_2M, /* Preferred Target PHY */ + 2, /* Preferred Retransmission number */ + 10, /* Preferred Maximum Transport Latency (msec) */ + 20000, /* Minimum Presentation Delay (usec) */ + 40000, /* Maximum Presentation Delay (usec) */ + 20000, /* Preferred Minimum Presentation Delay (usec) */ + 40000); /* Preferred Maximum Presentation Delay (usec) */ + +static esp_ble_audio_bap_stream_t *stream_alloc(void) +{ + for (size_t i = 0; i < ARRAY_SIZE(streams); i++) { + esp_ble_audio_bap_stream_t *stream = &streams[i]; + + if (stream->conn == NULL) { + return stream; + } + } + + return NULL; +} + +static int config_cb(esp_ble_conn_t *conn, + const esp_ble_audio_bap_ep_t *ep, + esp_ble_audio_dir_t dir, + const esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_bap_stream_t **stream, + esp_ble_audio_bap_qos_cfg_pref_t *const pref, + esp_ble_audio_bap_ascs_rsp_t *rsp) +{ + bool stream_exist = false; + + ESP_LOGI(TAG, "Config: conn %p ep %p dir %u", conn, ep, dir); + + example_print_codec_cfg(codec_cfg); + + *stream = stream_alloc(); + if (*stream == NULL) { + ESP_LOGE(TAG, "No streams available"); + + *rsp = ESP_BLE_AUDIO_BAP_ASCS_RSP(ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_NO_MEM, + ESP_BLE_AUDIO_BAP_ASCS_REASON_NONE); + return -ENOMEM; + } + + ESP_LOGI(TAG, "Config stream %p", *stream); + + if (dir == ESP_BLE_AUDIO_DIR_SINK) { + for (size_t i = 0; i < ARRAY_SIZE(sink_streams); i++) { + if (sink_streams[i].stream == *stream) { + stream_exist = true; + break; + } + } + + if (stream_exist == false) { + if (configured_sink_stream_count >= ARRAY_SIZE(sink_streams)) { + ESP_LOGE(TAG, "No more sink stream available"); + + *rsp = ESP_BLE_AUDIO_BAP_ASCS_RSP(ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_NO_MEM, + ESP_BLE_AUDIO_BAP_ASCS_REASON_NONE); + return -ENOMEM; + } + + sink_streams[configured_sink_stream_count++].stream = *stream; + } + } else if (dir == ESP_BLE_AUDIO_DIR_SOURCE) { + for (size_t i = 0; i < ARRAY_SIZE(source_streams); i++) { + if (source_streams[i].stream == *stream) { + stream_exist = true; + break; + } + } + + if (stream_exist == false) { + if (configured_source_stream_count >= ARRAY_SIZE(source_streams)) { + ESP_LOGE(TAG, "No more source stream available"); + + *rsp = ESP_BLE_AUDIO_BAP_ASCS_RSP(ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_NO_MEM, + ESP_BLE_AUDIO_BAP_ASCS_REASON_NONE); + return -ENOMEM; + } + + source_streams[configured_source_stream_count++].stream = *stream; + } + } else { + assert(0); + } + + *pref = qos_pref; + + return 0; +} + +static int reconfig_cb(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_dir_t dir, + const esp_ble_audio_codec_cfg_t *codec_cfg, + esp_ble_audio_bap_qos_cfg_pref_t *const pref, + esp_ble_audio_bap_ascs_rsp_t *rsp) +{ + ESP_LOGI(TAG, "Reconfig: stream %p", stream); + + example_print_codec_cfg(codec_cfg); + + *pref = qos_pref; + + return 0; +} + +static int qos_cb(esp_ble_audio_bap_stream_t *stream, + const esp_ble_audio_bap_qos_cfg_t *qos, + esp_ble_audio_bap_ascs_rsp_t *rsp) +{ + ESP_LOGI(TAG, "QoS: stream %p qos %p", stream, qos); + + example_print_qos(qos); + + return 0; +} + +static int enable_cb(esp_ble_audio_bap_stream_t *stream, + const uint8_t meta[], size_t meta_len, + esp_ble_audio_bap_ascs_rsp_t *rsp) +{ + ESP_LOGI(TAG, "Enable: stream %p meta_len %u", stream, meta_len); + return 0; +} + +static int start_cb(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_bap_ascs_rsp_t *rsp) +{ + ESP_LOGI(TAG, "Start: stream %p", stream); + return 0; +} + +struct data_func_param { + esp_ble_audio_bap_ascs_rsp_t *rsp; + + bool stream_context_present; + bool rejected; +}; + +static bool data_func_cb(uint8_t type, const uint8_t *data, + uint8_t data_len, void *user_data) +{ + struct data_func_param *func_param = (struct data_func_param *)user_data; + + if (!ESP_BLE_AUDIO_METADATA_TYPE_IS_KNOWN(type)) { + ESP_LOGE(TAG, "Invalid metadata type %u or length %u", type, data_len); + + *func_param->rsp = ESP_BLE_AUDIO_BAP_ASCS_RSP(ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_METADATA_REJECTED, + type); + func_param->rejected = true; + return false; + } + + if (type == ESP_BLE_AUDIO_METADATA_TYPE_STREAM_CONTEXT) { + func_param->stream_context_present = true; + } + + if (type == ESP_BLE_AUDIO_METADATA_TYPE_CCID_LIST) { + for (uint8_t i = 0; i < data_len; i++) { + const uint8_t ccid = data[i]; + +#if CONFIG_BT_TBS_CLIENT_CCID + uint16_t conn_handle = default_conn_handle_get(); + + if (conn_handle == CONN_HANDLE_INIT) { + ESP_LOGE(TAG, "%s, not connected", __func__); + + *func_param->rsp = ESP_BLE_AUDIO_BAP_ASCS_RSP(ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_METADATA_REJECTED, + ESP_BLE_AUDIO_BAP_ASCS_REASON_NONE); + func_param->rejected = true; + return false; + } + + if (esp_ble_audio_tbs_client_get_by_ccid(conn_handle, ccid) == NULL) { + ESP_LOGW(TAG, "CCID %u is unknown", ccid); + + *func_param->rsp = ESP_BLE_AUDIO_BAP_ASCS_RSP(ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_METADATA_REJECTED, + ESP_BLE_AUDIO_BAP_ASCS_REASON_NONE); + func_param->rejected = true; + return false; + } +#else /* CONFIG_BT_TBS_CLIENT_CCID */ + ESP_LOGW(TAG, "CCID %u is unknown", ccid); + + *func_param->rsp = ESP_BLE_AUDIO_BAP_ASCS_RSP(ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_METADATA_REJECTED, + ESP_BLE_AUDIO_BAP_ASCS_REASON_NONE); + func_param->rejected = true; + return false; +#endif /* CONFIG_BT_TBS_CLIENT_CCID */ + } + } + + func_param->rejected = false; + return true; +} + +static int metadata_cb(esp_ble_audio_bap_stream_t *stream, + const uint8_t meta[], size_t meta_len, + esp_ble_audio_bap_ascs_rsp_t *rsp) +{ + struct data_func_param func_param = { + .rsp = rsp, + .stream_context_present = false, + .rejected = false, + }; + esp_err_t err; + + ESP_LOGI(TAG, "Metadata: stream %p meta_len %u", stream, meta_len); + + err = esp_ble_audio_data_parse(meta, meta_len, data_func_cb, &func_param); + if (err) { + return -EIO; + } + + if (func_param.rejected) { + /* The rsp is already set by data_func_cb */ + return -EINVAL; + } + + if (func_param.stream_context_present == false) { + ESP_LOGE(TAG, "Stream audio context not present on peer!"); + + *rsp = ESP_BLE_AUDIO_BAP_ASCS_RSP(ESP_BLE_AUDIO_BAP_ASCS_RSP_CODE_METADATA_REJECTED, + ESP_BLE_AUDIO_BAP_ASCS_REASON_NONE); + return -EINVAL; + } + + return 0; +} + +static int disable_cb(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_bap_ascs_rsp_t *rsp) +{ + ESP_LOGI(TAG, "Disable: stream %p", stream); + return 0; +} + +static int stop_cb(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_bap_ascs_rsp_t *rsp) +{ + ESP_LOGI(TAG, "Stop: stream %p", stream); + return 0; +} + +static int release_cb(esp_ble_audio_bap_stream_t *stream, + esp_ble_audio_bap_ascs_rsp_t *rsp) +{ + ESP_LOGI(TAG, "Release: stream %p", stream); + + for (size_t i = 0; i < ARRAY_SIZE(sink_streams); i++) { + if (sink_streams[i].stream == stream) { + memset(&sink_streams[i], 0, sizeof(sink_streams[i])); + if (configured_sink_stream_count > 0) { + configured_sink_stream_count--; + } + return 0; + } + } + + for (size_t i = 0; i < ARRAY_SIZE(source_streams); i++) { + if (source_streams[i].stream == stream) { + memset(&source_streams[i], 0, sizeof(source_streams[i])); + if (configured_source_stream_count > 0) { + configured_source_stream_count--; + } + return 0; + } + } + + ESP_LOGW(TAG, "Stream %p not found", stream); + return -ENODEV; +} + +static const esp_ble_audio_bap_unicast_server_cb_t unicast_server_cb = { + .config = config_cb, + .reconfig = reconfig_cb, + .qos = qos_cb, + .enable = enable_cb, + .start = start_cb, + .metadata = metadata_cb, + .disable = disable_cb, + .stop = stop_cb, + .release = release_cb, +}; + +static void stream_enabled(esp_ble_audio_bap_stream_t *stream) +{ + esp_ble_audio_bap_ep_info_t ep_info = {0}; + int err; + + ESP_LOGI(TAG, "Stream %p enabled", stream); + + err = esp_ble_audio_bap_ep_get_info(stream->ep, &ep_info); + if (err) { + ESP_LOGE(TAG, "Failed to get ep info, err %d", err); + return; + } + + /* The unicast server is responsible for starting the sink streams */ + if (ep_info.dir == ESP_BLE_AUDIO_DIR_SINK) { + /* Automatically do the receiver start ready operation */ + err = esp_ble_audio_bap_stream_start(stream); + if (err) { + ESP_LOGE(TAG, "Failed to start stream %p, err %d", stream, err); + return; + } + } +} + +static void stream_started(esp_ble_audio_bap_stream_t *stream) +{ + ESP_LOGI(TAG, "Stream %p started", stream); + + for (size_t i = 0; i < ARRAY_SIZE(sink_streams); i++) { + if (sink_streams[i].stream == stream) { + example_audio_rx_metrics_reset(&sink_streams[i].rx_metrics); + break; + } + } +} + +static void stream_stopped(esp_ble_audio_bap_stream_t *stream, uint8_t reason) +{ + ESP_LOGI(TAG, "Stream %p stopped, reason 0x%02x", stream, reason); +} + +static void stream_recv(esp_ble_audio_bap_stream_t *stream, + const esp_ble_iso_recv_info_t *info, + const uint8_t *data, uint16_t len) +{ + + for (size_t i = 0; i < ARRAY_SIZE(sink_streams); i++) { + if (sink_streams[i].stream == stream) { + struct audio_sink *sink_stream = CONTAINER_OF(&sink_streams[i].stream, + struct audio_sink, + stream); + + sink_stream->rx_metrics.last_sdu_len = len; + example_audio_rx_metrics_on_recv(info, &sink_stream->rx_metrics, + TAG, "stream", stream); + break; + } + } +} + +static esp_ble_audio_bap_stream_ops_t stream_ops = { + .enabled = stream_enabled, + .started = stream_started, + .stopped = stream_stopped, + .recv = stream_recv, +}; + +static esp_ble_audio_bap_unicast_server_register_param_t param = { + CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT, + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT +}; + +int bap_unicast_sr_init(void) +{ + const esp_ble_audio_pacs_register_param_t pacs_param = { + .snk_pac = true, + .snk_loc = true, + .src_pac = true, + .src_loc = true, + }; + esp_ble_audio_location_t location; + int err; + + location = 0; + + err = esp_ble_audio_pacs_register(&pacs_param); + if (err) { + ESP_LOGE(TAG, "Failed to register pacs, err %d", err); + return err; + } + + err = esp_ble_audio_bap_unicast_server_register(¶m); + if (err) { + ESP_LOGE(TAG, "Failed to register Unicast Server params, err %d", err); + return err; + } + + err = esp_ble_audio_bap_unicast_server_register_cb(&unicast_server_cb); + if (err) { + ESP_LOGE(TAG, "Failed to register Unicast Server callbacks, err %d", err); + return err; + } + +#if CONFIG_EXAMPLE_TMAP_PER_LEFT + location |= ESP_BLE_AUDIO_LOCATION_FRONT_LEFT; +#endif /* CONFIG_EXAMPLE_TMAP_PER_LEFT */ +#if CONFIG_EXAMPLE_TMAP_PER_RIGHT + location |= ESP_BLE_AUDIO_LOCATION_FRONT_RIGHT; +#endif /* CONFIG_EXAMPLE_TMAP_PER_RIGHT */ + +#if CONFIG_BT_PAC_SNK + /* Register CT required capabilities */ + err = esp_ble_audio_pacs_cap_register(ESP_BLE_AUDIO_DIR_SINK, &cap); + if (err) { + ESP_LOGE(TAG, "Failed to register pacs capabilities, err %d", err); + return err; + } + + err = esp_ble_audio_pacs_set_location(ESP_BLE_AUDIO_DIR_SINK, location); + if (err) { + ESP_LOGE(TAG, "Failed to set pacs location, err %d", err); + return err; + } + + err = esp_ble_audio_pacs_set_supported_contexts(ESP_BLE_AUDIO_DIR_SINK, SINK_CONTEXT); + if (err) { + ESP_LOGE(TAG, "Failed to set pacs supported contexts, err %d", err); + return err; + } + + err = esp_ble_audio_pacs_set_available_contexts(ESP_BLE_AUDIO_DIR_SINK, SINK_CONTEXT); + if (err) { + ESP_LOGE(TAG, "Failed to set pacs available contexts, err %d", err); + return err; + } +#endif /* CONFIG_BT_PAC_SNK */ + +#if CONFIG_BT_PAC_SRC + /* Register CT required capabilities */ + err = esp_ble_audio_pacs_cap_register(ESP_BLE_AUDIO_DIR_SOURCE, &cap); + if (err) { + ESP_LOGE(TAG, "Failed to register pacs capabilities, err %d", err); + return err; + } + + err = esp_ble_audio_pacs_set_location(ESP_BLE_AUDIO_DIR_SOURCE, location); + if (err) { + ESP_LOGE(TAG, "Failed to set pacs location, err %d", err); + return err; + } + + err = esp_ble_audio_pacs_set_supported_contexts(ESP_BLE_AUDIO_DIR_SOURCE, SOURCE_CONTEXT); + if (err) { + ESP_LOGE(TAG, "Failed to set pacs supported contexts, err %d", err); + return err; + } + + err = esp_ble_audio_pacs_set_available_contexts(ESP_BLE_AUDIO_DIR_SOURCE, SOURCE_CONTEXT); + if (err) { + ESP_LOGE(TAG, "Failed to set pacs available contexts, err %d", err); + return err; + } +#endif /* CONFIG_BT_PAC_SRC */ + + for (size_t i = 0; i < ARRAY_SIZE(streams); i++) { + esp_ble_audio_bap_stream_cb_register(&streams[i], &stream_ops); + } + + ESP_LOGI(TAG, "BAP unicast server initialized"); + + return 0; +} diff --git a/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/button.c b/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/button.c new file mode 100644 index 0000000000..ecc41d49b4 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/button.c @@ -0,0 +1,49 @@ +/* + * SPDX-FileCopyrightText: 2023 NXP + * SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "tmap_peripheral.h" + +void initiate_call(void) +{ + if (tmap_peer_is_cg() == false) { + ESP_LOGE(TAG, "Peer not support Call Gateway"); + return; + } + + ccp_originate_call(); +} + +void terminate_call(void) +{ + if (tmap_peer_is_cg() == false) { + ESP_LOGE(TAG, "Peer not support Call Gateway"); + return; + } + + ccp_terminate_call(); +} + +void play_media(void) +{ + if (tmap_peer_is_ums() == false) { + ESP_LOGE(TAG, "Peer not support Unicast Media Sender"); + return; + } + + mcp_send_cmd(ESP_BLE_AUDIO_MCS_OPC_PLAY); +} + +void pause_media(void) +{ + if (tmap_peer_is_ums() == false) { + ESP_LOGE(TAG, "Peer not support Unicast Media Sender"); + return; + } + + mcp_send_cmd(ESP_BLE_AUDIO_MCS_OPC_PAUSE); +} diff --git a/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/ccp_call_ctrl.c b/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/ccp_call_ctrl.c new file mode 100644 index 0000000000..6005ec69db --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/ccp_call_ctrl.c @@ -0,0 +1,221 @@ +/* + * SPDX-FileCopyrightText: 2020-2024 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2022 Codecoup + * SPDX-FileCopyrightText: 2023 NXP + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include "tmap_peripheral.h" + +#define URI_SEPARATOR ":" +#define CALLER_ID "friend" + +static uint8_t new_call_index; +static char remote_uri[CONFIG_BT_TBS_MAX_URI_LENGTH]; + +static void discover_cb(esp_ble_conn_t *conn, + int err, + uint8_t tbs_count, + bool gtbs_found) +{ + if (err) { + ESP_LOGE(TAG, "Discover GTBS failed, err %d", err); + return; + } + + ESP_LOGI(TAG, "Discovered GTBS"); + + if (gtbs_found == false) { + ESP_LOGE(TAG, "No GTBS found"); + return; + } + + /* Read Bearer URI Schemes Supported List Characteristic */ + err = esp_ble_audio_tbs_client_read_uri_list(default_conn_handle_get(), + ESP_BLE_AUDIO_TBS_GTBS_INDEX); + if (err) { + ESP_LOGE(TAG, "Failed to read URI list, err %d", err); + } +} + +static void originate_call_cb(esp_ble_conn_t *conn, + int err, + uint8_t inst_index, + uint8_t call_index) +{ + if (err) { + ESP_LOGE(TAG, "Originate call failed, err %d", err); + return; + } + + ESP_LOGI(TAG, "Call %u originated", call_index); + + if (inst_index != ESP_BLE_AUDIO_TBS_GTBS_INDEX) { + ESP_LOGW(TAG, "Unexpected instance index %u", inst_index); + return; + } + + new_call_index = call_index; +} + +static void terminate_call_cb(esp_ble_conn_t *conn, + int err, + uint8_t inst_index, + uint8_t call_index) +{ + if (err) { + ESP_LOGE(TAG, "Terminate call failed, err %d", err); + return; + } + + ESP_LOGI(TAG, "Call %u terminated", call_index); + + if (inst_index != ESP_BLE_AUDIO_TBS_GTBS_INDEX) { + ESP_LOGW(TAG, "Unexpected instance index %u", inst_index); + return; + } +} + +static void read_uri_schemes_string_cb(esp_ble_conn_t *conn, + int err, + uint8_t inst_index, + const char *value) +{ + size_t i; + + if (err) { + ESP_LOGE(TAG, "Read URI schemes string failed, err %d", err); + return; + } + + if (inst_index != ESP_BLE_AUDIO_TBS_GTBS_INDEX) { + ESP_LOGW(TAG, "Unexpected instance index %u", inst_index); + return; + } + + /* Save first remote URI + * + * First search for the first comma (separator), and use that to determine the end of the + * first (or only) URI. Then use that length to copy the URI to `remote_uri` for later use. + */ + for (i = 0; i < strlen(value); i++) { + if (value[i] == ',') { + break; + } + } + + if (i >= sizeof(remote_uri)) { + ESP_LOGW(TAG, "Cannot store URI of length %u: %s", i, value); + return; + } + + strncpy(remote_uri, value, i); + remote_uri[i] = '\0'; + + ESP_LOGI(TAG, "Discovered remote URI %s", remote_uri); + + /* CCP related GATT procedures done, start MCP discovery */ + mcp_discover_mcs(); +} + +static esp_ble_audio_tbs_client_cb_t tbs_client_cb = { + .discover = discover_cb, + .uri_list = read_uri_schemes_string_cb, + .originate_call = originate_call_cb, + .terminate_call = terminate_call_cb, +}; + +int ccp_call_ctrl_init(void) +{ + int err; + + err = esp_ble_audio_tbs_client_register_cb(&tbs_client_cb); + if (err) { + ESP_LOGE(TAG, "Failed to register TBS client, err %d", err); + return err; + } + + ESP_LOGI(TAG, "CCP call controller initialized"); + + return err; +} + +int ccp_discover_tbs(void) +{ + uint16_t conn_handle; + int err; + + conn_handle = default_conn_handle_get(); + if (conn_handle == CONN_HANDLE_INIT) { + ESP_LOGE(TAG, "%s, not connected", __func__); + return -ENOTCONN; + } + + err = esp_ble_audio_tbs_client_discover(conn_handle); + if (err) { + ESP_LOGE(TAG, "Failed to discover TBS, err %d", err); + return err; + } + + return err; +} + +int ccp_originate_call(void) +{ + char uri[CONFIG_BT_TBS_MAX_URI_LENGTH] = {0}; + uint16_t conn_handle; + int uri_len; + int err; + + conn_handle = default_conn_handle_get(); + if (conn_handle == CONN_HANDLE_INIT) { + ESP_LOGE(TAG, "%s, not connected", __func__); + return -ENOTCONN; + } + + uri_len = snprintf(uri, sizeof(uri), "%s%s%s", remote_uri, URI_SEPARATOR, CALLER_ID); + if (uri_len < 0 || uri_len >= sizeof(uri)) { + ESP_LOGE(TAG, "Invalid URI length %d", uri_len); + return -EINVAL; + } + + err = esp_ble_audio_tbs_client_originate_call(conn_handle, + ESP_BLE_AUDIO_TBS_GTBS_INDEX, + uri); + if (err) { + ESP_LOGE(TAG, "Failed to originate TBS call, err %d", err); + return err; + } + + return 0; +} + +int ccp_terminate_call(void) +{ + uint16_t conn_handle; + int err; + + conn_handle = default_conn_handle_get(); + if (conn_handle == CONN_HANDLE_INIT) { + ESP_LOGE(TAG, "%s, not connected", __func__); + return -ENOTCONN; + } + + err = esp_ble_audio_tbs_client_terminate_call(conn_handle, + ESP_BLE_AUDIO_TBS_GTBS_INDEX, + new_call_index); + if (err) { + ESP_LOGE(TAG, "Failed to terminate TBS call, err %d", err); + return err; + } + + return 0; +} diff --git a/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/csip_set_member.c b/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/csip_set_member.c new file mode 100644 index 0000000000..bd8b20009c --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/csip_set_member.c @@ -0,0 +1,92 @@ +/* + * SPDX-FileCopyrightText: 2022 Codecoup + * SPDX-FileCopyrightText: 2023 NXP + * SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include "host/ble_hs.h" + +#include "tmap_peripheral.h" + +#define CSIP_SIRK_DEBUG { 0xcd, 0xcc, 0x72, 0xdd, 0x86, 0x8c, 0xcd, 0xce, \ + 0x22, 0xfd, 0xa1, 0x21, 0x09, 0x7d, 0x7d, 0x45 } + +static esp_ble_audio_csip_set_member_svc_inst_t *svc_inst; + +static void csip_lock_changed_cb(esp_ble_conn_t *conn, + esp_ble_audio_csip_set_member_svc_inst_t *inst, + bool locked) +{ + ESP_LOGI(TAG, "Client %p %s the lock", conn, locked ? "locked" : "released"); +} + +static uint8_t sirk_read_req_cb(esp_ble_conn_t *conn, + esp_ble_audio_csip_set_member_svc_inst_t *inst) +{ + return ESP_BLE_AUDIO_CSIP_READ_SIRK_REQ_RSP_ACCEPT; +} + +static esp_ble_audio_csip_set_member_cb_t csip_cb = { + .lock_changed = csip_lock_changed_cb, + .sirk_read_req = sirk_read_req_cb, +}; + +int csip_set_member_init(void) +{ + esp_ble_audio_csip_set_member_register_param_t param = { + .set_size = 2, + .rank = CONFIG_EXAMPLE_TMAP_PER_SET_RANK, + .lockable = false, + .sirk = CSIP_SIRK_DEBUG, + .cb = &csip_cb, + }; + int err; + + err = esp_ble_audio_cap_acceptor_register(¶m, &svc_inst); + if (err) { + ESP_LOGE(TAG, "Failed to register cap acceptor, err %d", err); + return err; + } + + ESP_LOGI(TAG, "CSIP set member initialized"); + + return 0; +} + +int csip_generate_rsi(uint8_t rsi[ESP_BLE_AUDIO_CSIP_RSI_SIZE]) +{ + char rsi_str[13]; + int err; + + if (svc_inst == NULL) { + ESP_LOGE(TAG, "CSIS service instant not exists"); + return -1; + } + + err = esp_ble_audio_csip_set_member_generate_rsi(svc_inst, rsi); + if (err) { + ESP_LOGE(TAG, "Failed to generate RSI, err %d", err); + return err; + } + + snprintf(rsi_str, ARRAY_SIZE(rsi_str), "%02x%02x%02x%02x%02x%02x", + rsi[0], rsi[1], rsi[2], rsi[3], rsi[4], rsi[5]); + + ESP_LOGI(TAG, "PRSI: 0x%s", rsi_str); + + return 0; +} + +void *csip_svc_inst_get(void) +{ + return svc_inst; +} diff --git a/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/idf_component.yml b/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/idf_component.yml new file mode 100644 index 0000000000..bb02c0922a --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + example_init: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_audio/common_components/example_init + example_utils: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_audio/common_components/example_utils diff --git a/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/main.c b/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/main.c new file mode 100644 index 0000000000..0fce9a7b73 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/main.c @@ -0,0 +1,380 @@ +/* + * SPDX-FileCopyrightText: 2023 NXP + * SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include "nvs_flash.h" +#include "esp_system.h" +#include "esp_timer.h" + +#include "host/ble_hs.h" +#include "services/gap/ble_svc_gap.h" + +#include "tmap_peripheral.h" + +#include "ble_audio_example_init.h" +#include "ble_audio_example_utils.h" + +#define ADV_HANDLE 0x00 +#define ADV_SID 0 +#define ADV_TX_POWER 127 +#define ADV_ADDRESS BLE_OWN_ADDR_PUBLIC +#define ADV_PRIMARY_PHY BLE_HCI_LE_PHY_1M +#define ADV_SECONDARY_PHY BLE_HCI_LE_PHY_2M +#define ADV_INTERVAL BLE_GAP_ADV_ITVL_MS(200) + +static uint8_t general_adv_data[] = { + /* Flags */ + 0x02, EXAMPLE_AD_TYPE_FLAGS, (EXAMPLE_AD_FLAGS_GENERAL | EXAMPLE_AD_FLAGS_NO_BREDR), + /* Appearance */ + 0x03, EXAMPLE_AD_TYPE_GAP_APPEARANCE, (ESP_BLE_AUDIO_APPEARANCE_WEARABLE_AUDIO_DEVICE_EARBUD & 0xFF), + ((ESP_BLE_AUDIO_APPEARANCE_WEARABLE_AUDIO_DEVICE_EARBUD >> 8) & 0xFF), + /* Incomplete List of 16-bit Service UUIDs */ + 0x07, EXAMPLE_AD_TYPE_UUID16_SOME, (ESP_BLE_AUDIO_UUID_ASCS_VAL & 0xFF), + ((ESP_BLE_AUDIO_UUID_ASCS_VAL >> 8) & 0xFF), + (ESP_BLE_AUDIO_UUID_CAS_VAL & 0xFF), + ((ESP_BLE_AUDIO_UUID_CAS_VAL >> 8) & 0xFF), + (ESP_BLE_AUDIO_UUID_TMAS_VAL & 0xFF), + ((ESP_BLE_AUDIO_UUID_TMAS_VAL >> 8) & 0xFF), +}; + +static uint8_t unicast_server_adv_data[] = { + /* Target Announcement - 16-bit UUID */ + 0x09, EXAMPLE_AD_TYPE_SERVICE_DATA16, (ESP_BLE_AUDIO_UUID_ASCS_VAL & 0xFF), + ((ESP_BLE_AUDIO_UUID_ASCS_VAL >> 8) & 0xFF), + ESP_BLE_AUDIO_UNICAST_ANNOUNCEMENT_TARGETED, + (SINK_CONTEXT & 0xFF), + ((SINK_CONTEXT >> 8) & 0xFF), + (SOURCE_CONTEXT & 0xFF), + ((SOURCE_CONTEXT >> 8) & 0xFF), + 0x00, /* Metadata length */ +}; + +static const uint8_t cap_adv_data[] = { + /* CAS Service Data - 16-bit UUID */ + 0x04, EXAMPLE_AD_TYPE_SERVICE_DATA16, (ESP_BLE_AUDIO_UUID_CAS_VAL & 0xFF), + ((ESP_BLE_AUDIO_UUID_CAS_VAL >> 8) & 0xFF), + ESP_BLE_AUDIO_UNICAST_ANNOUNCEMENT_TARGETED, +}; + +static uint8_t tmap_adv_data[] = { + /* TMAS Service Data - 16-bit UUID */ + 0x05, EXAMPLE_AD_TYPE_SERVICE_DATA16, (ESP_BLE_AUDIO_UUID_TMAS_VAL & 0xFF), + ((ESP_BLE_AUDIO_UUID_TMAS_VAL >> 8) & 0xFF), + ((ESP_BLE_AUDIO_TMAP_ROLE_UMR | \ + ESP_BLE_AUDIO_TMAP_ROLE_CT) & 0xFF), + (((ESP_BLE_AUDIO_TMAP_ROLE_UMR | \ + ESP_BLE_AUDIO_TMAP_ROLE_CT) >> 8) & 0xFF), +}; + +static uint8_t dev_name_adv_data[] = { + /* Complete Device Name */ + 0x10, EXAMPLE_AD_TYPE_NAME_COMPLETE, 't', 'm', 'a', 'p', '_', + 'p', 'e', 'r', 'i', 'p', 'h', 'e', 'r', 'a', 'l', +}; + +#if CONFIG_BT_CSIP_SET_MEMBER +static uint8_t csis_rsi[ESP_BLE_AUDIO_CSIP_RSI_SIZE]; + +#define ADV_DATA_LEN (sizeof(general_adv_data) + \ + 2 + sizeof(csis_rsi) + \ + sizeof(tmap_adv_data) + \ + sizeof(cap_adv_data) + \ + sizeof(unicast_server_adv_data) + \ + sizeof(dev_name_adv_data)) +#else /* CONFIG_BT_CSIP_SET_MEMBER */ +#define ADV_DATA_LEN (sizeof(general_adv_data) + \ + sizeof(tmap_adv_data) + \ + sizeof(cap_adv_data) + \ + sizeof(unicast_server_adv_data) + \ + sizeof(dev_name_adv_data)) +#endif /* CONFIG_BT_CSIP_SET_MEMBER */ + +static uint8_t ext_adv_data[ADV_DATA_LEN]; + +static uint16_t default_conn_handle = CONN_HANDLE_INIT; + +uint16_t default_conn_handle_get(void) +{ + return default_conn_handle; +} + +static int set_ext_adv_data(void) +{ + uint16_t data_len = 0; + + memcpy(ext_adv_data, general_adv_data, sizeof(general_adv_data)); + data_len += sizeof(general_adv_data); + +#if CONFIG_BT_CSIP_SET_MEMBER + ext_adv_data[data_len] = 1 + sizeof(csis_rsi); + ext_adv_data[data_len + 1] = EXAMPLE_AD_TYPE_CSIS_RSI; + memcpy(ext_adv_data + data_len + 2, csis_rsi, sizeof(csis_rsi)); + data_len += (2 + sizeof(csis_rsi)); +#endif /* CONFIG_BT_CSIP_SET_MEMBER */ + + memcpy(ext_adv_data + data_len, tmap_adv_data, sizeof(tmap_adv_data)); + data_len += sizeof(tmap_adv_data); + + memcpy(ext_adv_data + data_len, cap_adv_data, sizeof(cap_adv_data)); + data_len += sizeof(cap_adv_data); + + memcpy(ext_adv_data + data_len, unicast_server_adv_data, sizeof(unicast_server_adv_data)); + data_len += sizeof(unicast_server_adv_data); + + memcpy(ext_adv_data + data_len, dev_name_adv_data, sizeof(dev_name_adv_data)); + data_len += sizeof(dev_name_adv_data); + + if (data_len != sizeof(ext_adv_data)) { + ESP_LOGE(TAG, "Mismatch ext adv data length %u, expected %u", + data_len, sizeof(ext_adv_data)); + return -1; + } + + return 0; +} + +static void ext_adv_start(void) +{ + struct ble_gap_ext_adv_params ext_params = {0}; + struct os_mbuf *data = NULL; + int err; + + ext_params.connectable = 1; + ext_params.scannable = 0; + ext_params.legacy_pdu = 0; + ext_params.own_addr_type = ADV_ADDRESS; + ext_params.primary_phy = ADV_PRIMARY_PHY; + ext_params.secondary_phy = ADV_SECONDARY_PHY; + ext_params.tx_power = ADV_TX_POWER; + ext_params.sid = ADV_SID; + ext_params.itvl_min = ADV_INTERVAL; + ext_params.itvl_max = ADV_INTERVAL; + + err = ble_gap_ext_adv_configure(ADV_HANDLE, &ext_params, NULL, + example_audio_gap_event_cb, NULL); + if (err) { + ESP_LOGE(TAG, "Failed to configure ext adv params, err %d", err); + return; + } + + err = set_ext_adv_data(); + if (err) { + return; + } + + data = os_msys_get_pkthdr(sizeof(ext_adv_data), 0); + if (data == NULL) { + ESP_LOGE(TAG, "Failed to get ext adv mbuf"); + return; + } + + err = os_mbuf_append(data, ext_adv_data, sizeof(ext_adv_data)); + if (err) { + ESP_LOGE(TAG, "Failed to append ext adv data, err %d", err); + os_mbuf_free_chain(data); + return; + } + + err = ble_gap_ext_adv_set_data(ADV_HANDLE, data); + if (err) { + ESP_LOGE(TAG, "Failed to set ext adv data, err %d", err); + return; + } + + err = ble_gap_ext_adv_start(ADV_HANDLE, 0, 0); + if (err) { + ESP_LOGE(TAG, "Failed to start ext advertising, err %d", err); + return; + } + + ESP_LOGI(TAG, "Extended adv instance %u started", ADV_HANDLE); +} + +static void acl_connect(esp_ble_audio_gap_app_event_t *event) +{ + if (event->acl_connect.status) { + ESP_LOGE(TAG, "connection failed, status %d", event->acl_connect.status); + return; + } + + ESP_LOGI(TAG, "Conn established:"); + ESP_LOGI(TAG, "conn_handle 0x%04x status 0x%02x role %u peer %02x:%02x:%02x:%02x:%02x:%02x", + event->acl_connect.conn_handle, event->acl_connect.status, + event->acl_connect.role, event->acl_connect.dst.val[5], + event->acl_connect.dst.val[4], event->acl_connect.dst.val[3], + event->acl_connect.dst.val[2], event->acl_connect.dst.val[1], + event->acl_connect.dst.val[0]); + + default_conn_handle = event->acl_connect.conn_handle; +} + +static void acl_disconnect(esp_ble_audio_gap_app_event_t *event) +{ + ESP_LOGI(TAG, "Conn terminated: conn_handle 0x%04x reason 0x%02x", + event->acl_disconnect.conn_handle, event->acl_disconnect.reason); + + default_conn_handle = CONN_HANDLE_INIT; + + ext_adv_start(); +} + +static void iso_gap_app_cb(esp_ble_audio_gap_app_event_t *event) +{ + switch (event->type) { + case ESP_BLE_AUDIO_GAP_EVENT_ACL_CONNECT: + acl_connect(event); + break; + case ESP_BLE_AUDIO_GAP_EVENT_ACL_DISCONNECT: + acl_disconnect(event); + break; + default: + break; + } +} + +static void gatt_mtu_change(esp_ble_audio_gatt_app_event_t *event) +{ + int err; + + ESP_LOGI(TAG, "gatt mtu change, conn_handle %u, mtu %u", + event->gatt_mtu_change.conn_handle, event->gatt_mtu_change.mtu); + + if (event->gatt_mtu_change.mtu < ESP_BLE_AUDIO_ATT_MTU_MIN) { + ESP_LOGW(TAG, "Invalid new mtu %u, shall be at least %u", + event->gatt_mtu_change.mtu, ESP_BLE_AUDIO_ATT_MTU_MIN); + return; + } + + /* This function only needs to be invoked when: + * - The device is a Peripheral (Link Layer role); + * - The device works as a GATT client. + */ + err = esp_ble_audio_gattc_disc_start(event->gatt_mtu_change.conn_handle); + if (err) { + ESP_LOGE(TAG, "Failed to start svc disc, err %d", err); + return; + } + + ESP_LOGI(TAG, "Start discovering gatt services"); +} + +static void gattc_disc_cmpl(esp_ble_audio_gatt_app_event_t *event) +{ + ESP_LOGI(TAG, "gattc disc cmpl, status %u, conn_handle %u", + event->gattc_disc_cmpl.status, event->gattc_disc_cmpl.conn_handle); + + if (event->gattc_disc_cmpl.status) { + ESP_LOGE(TAG, "gattc disc failed, status %u", event->gattc_disc_cmpl.status); + return; + } + + tmap_discover_tmas(); +} + +static void iso_gatt_app_cb(esp_ble_audio_gatt_app_event_t *event) +{ + switch (event->type) { + case ESP_BLE_AUDIO_GATT_EVENT_GATT_MTU_CHANGE: + gatt_mtu_change(event); + break; + case ESP_BLE_AUDIO_GATT_EVENT_GATTC_DISC_CMPL: + gattc_disc_cmpl(event); + break; + default: + break; + } +} + +void app_main(void) +{ + esp_ble_audio_start_info_t start_info = {0}; + esp_ble_audio_init_info_t init_info = { + .gap_cb = iso_gap_app_cb, + .gatt_cb = iso_gatt_app_cb, + }; + esp_err_t err; + + /* Initialize NVS — it is used to store PHY calibration data */ + err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK(err); + + err = bluetooth_init(); + if (err) { + ESP_LOGE(TAG, "Failed to initialize BLE, err %d", err); + return; + } + + err = esp_ble_audio_common_init(&init_info); + if (err) { + ESP_LOGE(TAG, "Failed to initialize audio, err %d", err); + return; + } + + err = tmap_ct_umr_init(); + if (err) { + return; + } + +#if CONFIG_BT_CSIP_SET_MEMBER + err = csip_set_member_init(); + if (err) { + return; + } + + err = csip_generate_rsi(csis_rsi); + if (err) { + return; + } + + start_info.csis_insts[0].svc_inst = csip_svc_inst_get(); + start_info.csis_insts[0].included_by_cas = true; +#endif /* CONFIG_BT_CSIP_SET_MEMBER */ + + err = vcp_vol_renderer_init(); + if (err) { + return; + } + + err = bap_unicast_sr_init(); + if (err) { + return; + } + + err = ccp_call_ctrl_init(); + if (err) { + return; + } + + err = mcp_ctlr_init(); + if (err) { + return; + } + + err = esp_ble_audio_common_start(&start_info); + if (err) { + ESP_LOGE(TAG, "Failed to start audio, err %d", err); + return; + } + + err = ble_svc_gap_device_name_set("TMAP Peripheral"); + if (err) { + ESP_LOGE(TAG, "Failed to set device name, err %d", err); + return; + } + + ext_adv_start(); +} diff --git a/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/mcp_ctlr.c b/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/mcp_ctlr.c new file mode 100644 index 0000000000..1a3eb55af7 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/mcp_ctlr.c @@ -0,0 +1,349 @@ +/* + * SPDX-FileCopyrightText: 2023 NXP + * SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include "tmap_peripheral.h" + +static uint16_t conn_handle = CONN_HANDLE_INIT; +static bool is_remote_read; + +static void discover_mcs_cb(esp_ble_conn_t *conn, int err) +{ + if (err) { + ESP_LOGE(TAG, "Discover MCS failed, err %d", err); + return; + } + + ESP_LOGI(TAG, "Discover MCS succeeded"); + + if (is_remote_read == false) { + err = esp_ble_audio_mcc_read_player_name(conn_handle); + if (err) { + ESP_LOGE(TAG, "Read player name failed, err %d", err); + } + } +} + +static void read_player_name_cb(esp_ble_conn_t *conn, int err, const char *name) +{ + if (err) { + ESP_LOGE(TAG, "Read player name failed, err %d", err); + return; + } + + ESP_LOGI(TAG, "Read player name succeeded, name %s", name); + + if (is_remote_read == false) { + err = esp_ble_audio_mcc_read_track_title(conn_handle); + if (err) { + ESP_LOGE(TAG, "Read track title failed, err %d", err); + } + } +} + +static void track_changed_ntf_cb(esp_ble_conn_t *conn, int err) +{ + if (err) { + ESP_LOGE(TAG, "Invalid track changed ntf received, err %d", err); + return; + } + + ESP_LOGI(TAG, "Track changed ntf received"); +} + +static void read_track_title_cb(esp_ble_conn_t *conn, int err, const char *title) +{ + if (err) { + ESP_LOGE(TAG, "Read track title failed, err %d", err); + return; + } + + ESP_LOGI(TAG, "Read track title succeeded, title %s", title); + + if (is_remote_read == false) { + err = esp_ble_audio_mcc_read_track_duration(conn_handle); + if (err) { + ESP_LOGE(TAG, "Read track duration failed, err %d", err); + } + } +} + +static void read_track_duration_cb(esp_ble_conn_t *conn, int err, int32_t dur) +{ + if (err) { + ESP_LOGE(TAG, "Read track duration failed, err %d", err); + return; + } + + ESP_LOGI(TAG, "Read track duration succeeded, dur %ld", dur); + + if (is_remote_read == false) { + err = esp_ble_audio_mcc_read_track_position(conn_handle); + if (err) { + ESP_LOGE(TAG, "Read track position failed, err %d", err); + } + } +} + +static void read_track_position_cb(esp_ble_conn_t *conn, int err, int32_t pos) +{ + if (err) { + ESP_LOGE(TAG, "Read track position failed, err %d", err); + return; + } + + ESP_LOGI(TAG, "Read track position succeeded, pos %ld", pos); + + if (is_remote_read == false) { + err = esp_ble_audio_mcc_read_playback_speed(conn_handle); + if (err) { + ESP_LOGE(TAG, "Read playback speed failed, err %d", err); + } + } +} + +static void set_track_position_cb(esp_ble_conn_t *conn, int err, int32_t pos) +{ + if (err) { + ESP_LOGE(TAG, "Set track position failed, err %d", err); + return; + } + + ESP_LOGI(TAG, "Set track position succeeded, pos %ld", pos); +} + +static void read_playback_speed_cb(esp_ble_conn_t *conn, int err, int8_t speed) +{ + if (err) { + ESP_LOGE(TAG, "Read track playback speed failed, err %d", err); + return; + } + + ESP_LOGI(TAG, "Read track playback speed succeeded, speed %d", speed); + + if (is_remote_read == false) { + err = esp_ble_audio_mcc_read_seeking_speed(conn_handle); + if (err) { + ESP_LOGE(TAG, "Read seeking speed failed, err %d", err); + } + } +} + +static void set_playback_speed_cb(esp_ble_conn_t *conn, int err, int8_t speed) +{ + if (err) { + ESP_LOGE(TAG, "Set track playback speed failed, err %d", err); + return; + } + + ESP_LOGI(TAG, "Set track playback speed succeeded, speed %d", speed); +} + +static void read_seeking_speed_cb(esp_ble_conn_t *conn, int err, int8_t speed) +{ + if (err) { + ESP_LOGE(TAG, "Read seeking playback speed failed, err %d", err); + return; + } + + ESP_LOGI(TAG, "Read seeking playback speed succeeded, speed %d", speed); + + if (is_remote_read == false) { + err = esp_ble_audio_mcc_read_playing_order(conn_handle); + if (err) { + ESP_LOGE(TAG, "Read playing order failed, err %d", err); + } + } +} + +static void read_playing_order_cb(esp_ble_conn_t *conn, int err, uint8_t order) +{ + if (err) { + ESP_LOGE(TAG, "Read playing order failed, err %d", err); + return; + } + + ESP_LOGI(TAG, "Read playing order succeeded, order %u", order); + + if (is_remote_read == false) { + err = esp_ble_audio_mcc_read_playing_orders_supported(conn_handle); + if (err) { + ESP_LOGE(TAG, "Read playing orders supported failed, err %d", err); + } + } +} + +static void set_playing_order_cb(esp_ble_conn_t *conn, int err, uint8_t order) +{ + if (err) { + ESP_LOGE(TAG, "Set playing order failed, err %d", err); + return; + } + + ESP_LOGI(TAG, "Set playing order succeeded, order %u", order); +} + +static void read_playing_orders_supported_cb(esp_ble_conn_t *conn, int err, uint16_t orders) +{ + if (err) { + ESP_LOGE(TAG, "Read playing orders supported failed, err %d", err); + return; + } + + ESP_LOGI(TAG, "Read playing orders supported succeeded, orders 0x%04x", orders); + + if (is_remote_read == false) { + err = esp_ble_audio_mcc_read_media_state(conn_handle); + if (err) { + ESP_LOGE(TAG, "Read media state failed, err %d", err); + } + } +} + +static void read_media_state_cb(esp_ble_conn_t *conn, int err, uint8_t state) +{ + if (err) { + ESP_LOGE(TAG, "Read media state failed, err %d", err); + return; + } + + ESP_LOGI(TAG, "Read media state succeeded, state %u", state); + + if (is_remote_read == false) { + err = esp_ble_audio_mcc_read_opcodes_supported(conn_handle); + if (err) { + ESP_LOGE(TAG, "Read opcodes supported failed, err %d", err); + } + } +} + +static void send_cmd_cb(esp_ble_conn_t *conn, int err, const struct mpl_cmd *cmd) +{ + if (err) { + ESP_LOGE(TAG, "Send command failed, err %d, cmd %p", err, cmd); + return; + } + + ESP_LOGI(TAG, "Send command succeeded, cmd %p", cmd); +} + +static void cmd_ntf_cb(esp_ble_conn_t *conn, int err, const struct mpl_cmd_ntf *ntf) +{ + if (err) { + ESP_LOGE(TAG, "Invalid command ntf received, err %d, ntf %p", err, ntf); + return; + } + + ESP_LOGI(TAG, "Command ntf received, ntf %p", ntf); +} + +static void read_opcodes_supported_cb(esp_ble_conn_t *conn, int err, uint32_t opcodes) +{ + if (err) { + ESP_LOGE(TAG, "Read opcodes supported failed, err %d", err); + return; + } + + ESP_LOGI(TAG, "Read opcodes supported succeeded, opcodes 0x%08lx", opcodes); + + if (is_remote_read == false) { + err = esp_ble_audio_mcc_read_content_control_id(conn_handle); + if (err) { + ESP_LOGE(TAG, "Read content control id failed, err %d", err); + } + } +} + +static void read_content_control_id_cb(esp_ble_conn_t *conn, int err, uint8_t ccid) +{ + if (err) { + ESP_LOGE(TAG, "Read content control id failed, err %d", err); + return; + } + + ESP_LOGI(TAG, "Read content control id succeeded, ccid %u", ccid); + + is_remote_read = true; +} + +static esp_ble_audio_mcc_cb_t mcc_cb = { + .discover_mcs = discover_mcs_cb, + .read_player_name = read_player_name_cb, + .track_changed_ntf = track_changed_ntf_cb, + .read_track_title = read_track_title_cb, + .read_track_duration = read_track_duration_cb, + .read_track_position = read_track_position_cb, + .set_track_position = set_track_position_cb, + .read_playback_speed = read_playback_speed_cb, + .set_playback_speed = set_playback_speed_cb, + .read_seeking_speed = read_seeking_speed_cb, + .read_playing_order = read_playing_order_cb, + .set_playing_order = set_playing_order_cb, + .read_playing_orders_supported = read_playing_orders_supported_cb, + .read_media_state = read_media_state_cb, + .send_cmd = send_cmd_cb, + .cmd_ntf = cmd_ntf_cb, + .read_opcodes_supported = read_opcodes_supported_cb, + .read_content_control_id = read_content_control_id_cb, +}; + +int mcp_ctlr_init(void) +{ + int err; + + err = esp_ble_audio_mcc_init(&mcc_cb); + if (err) { + ESP_LOGE(TAG, "Failed to init MCC, err %d", err); + return err; + } + + ESP_LOGI(TAG, "MCP controller initialized"); + + return 0; +} + +int mcp_discover_mcs(void) +{ + int err; + + conn_handle = default_conn_handle_get(); + if (conn_handle == CONN_HANDLE_INIT) { + ESP_LOGE(TAG, "%s, not connected", __func__); + return -ENOTCONN; + } + + err = esp_ble_audio_mcc_discover_mcs(conn_handle, true); + if (err) { + ESP_LOGE(TAG, "Failed to discover MCS, err %d", err); + return err; + } + + return 0; +} + +int mcp_send_cmd(uint8_t mcp_opcode) +{ + esp_ble_audio_mpl_cmd_t cmd = { + .opcode = mcp_opcode, + .use_param = false, + }; + int err; + + err = esp_ble_audio_mcc_send_cmd(conn_handle, &cmd); + if (err) { + ESP_LOGE(TAG, "Failed to send MCP command, err %d", err); + return err; + } + + return 0; +} diff --git a/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/tmap_ct_umr.c b/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/tmap_ct_umr.c new file mode 100644 index 0000000000..dbe64b9d8f --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/tmap_ct_umr.c @@ -0,0 +1,88 @@ +/* + * SPDX-FileCopyrightText: 2023 NXP + * SPDX-FileCopyrightText: 2024 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include "tmap_peripheral.h" + +static bool peer_is_cg; +static bool peer_is_ums; + +bool tmap_peer_is_cg(void) +{ + return peer_is_cg; +} + +bool tmap_peer_is_ums(void) +{ + return peer_is_ums; +} + +static void tmap_discovery_complete(esp_ble_audio_tmap_role_t peer_role, + esp_ble_conn_t *conn, int err) +{ + if (conn->handle != default_conn_handle_get()) { + return; + } + + if (err) { + ESP_LOGE(TAG, "Failed to discovery TMAS, err %d", err); + return; + } + + peer_is_cg = ((peer_role & ESP_BLE_AUDIO_TMAP_ROLE_CG) != 0); + peer_is_ums = ((peer_role & ESP_BLE_AUDIO_TMAP_ROLE_UMS) != 0); + + ESP_LOGI(TAG, "TMAP discovery done"); + + /* TMAP related GATT procedures done, start MCP discovery */ + ccp_discover_tbs(); +} + +static esp_ble_audio_tmap_cb_t tmap_callbacks = { + .discovery_complete = tmap_discovery_complete, +}; + +int tmap_ct_umr_init(void) +{ + int err; + + err = esp_ble_audio_tmap_register(ESP_BLE_AUDIO_TMAP_ROLE_CT | ESP_BLE_AUDIO_TMAP_ROLE_UMR); + if (err) { + ESP_LOGE(TAG, "Failed to register TMAP role, err %d", err); + return err; + } + + ESP_LOGI(TAG, "TMAP CT UMR initialized"); + + return 0; +} + +int tmap_discover_tmas(void) +{ + uint16_t conn_handle; + int err; + + conn_handle = default_conn_handle_get(); + if (conn_handle == CONN_HANDLE_INIT) { + ESP_LOGE(TAG, "%s, not connected", __func__); + return -ENOTCONN; + } + + err = esp_ble_audio_tmap_discover(conn_handle, &tmap_callbacks); + if (err) { + ESP_LOGE(TAG, "Failed to discover TMAS, err %d", err); + return err; + } + + return 0; +} diff --git a/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/tmap_peripheral.h b/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/tmap_peripheral.h new file mode 100644 index 0000000000..e159262e56 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/tmap_peripheral.h @@ -0,0 +1,75 @@ +/* + * SPDX-FileCopyrightText: 2023 NXP + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_log.h" + +#include "sdkconfig.h" + +#include "esp_ble_audio_lc3_defs.h" +#include "esp_ble_audio_aics_api.h" +#include "esp_ble_audio_cap_api.h" +#include "esp_ble_audio_pacs_api.h" +#include "esp_ble_audio_vcp_api.h" +#include "esp_ble_audio_tbs_api.h" +#include "esp_ble_audio_tmap_api.h" +#include "esp_ble_audio_csip_api.h" +#include "esp_ble_audio_mcs_defs.h" +#include "esp_ble_audio_mcc_api.h" +#include "esp_ble_audio_media_proxy_api.h" +#include "esp_ble_audio_vocs_api.h" + +#include "ble_audio_example_utils.h" + +#define TAG "TMAP_PER" + +#define CONN_HANDLE_INIT 0xFFFF + +#define SINK_CONTEXT (ESP_BLE_AUDIO_CONTEXT_TYPE_UNSPECIFIED | \ + ESP_BLE_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | \ + ESP_BLE_AUDIO_CONTEXT_TYPE_MEDIA | \ + ESP_BLE_AUDIO_CONTEXT_TYPE_GAME | \ + ESP_BLE_AUDIO_CONTEXT_TYPE_INSTRUCTIONAL) + +#define SOURCE_CONTEXT (ESP_BLE_AUDIO_CONTEXT_TYPE_UNSPECIFIED | \ + ESP_BLE_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | \ + ESP_BLE_AUDIO_CONTEXT_TYPE_MEDIA | \ + ESP_BLE_AUDIO_CONTEXT_TYPE_GAME | \ + ESP_BLE_AUDIO_CONTEXT_TYPE_INSTRUCTIONAL) + +uint16_t default_conn_handle_get(void); + +int vcp_vol_renderer_init(void); + +int csip_set_member_init(void); + +int csip_generate_rsi(uint8_t rsi[ESP_BLE_AUDIO_CSIP_RSI_SIZE]); + +void *csip_svc_inst_get(void); + +int bap_unicast_sr_init(void); + +int ccp_call_ctrl_init(void); + +int ccp_discover_tbs(void); + +int ccp_originate_call(void); + +int ccp_terminate_call(void); + +int mcp_ctlr_init(void); + +int mcp_discover_mcs(void); + +int mcp_send_cmd(uint8_t mcp_opcode); + +bool tmap_peer_is_cg(void); + +bool tmap_peer_is_ums(void); + +int tmap_ct_umr_init(void); + +int tmap_discover_tmas(void); diff --git a/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/vcp_vol_renderer.c b/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/vcp_vol_renderer.c new file mode 100644 index 0000000000..64d0884e00 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/peripheral/main/vcp_vol_renderer.c @@ -0,0 +1,202 @@ +/* + * SPDX-FileCopyrightText: 2020 Bose Corporation + * SPDX-FileCopyrightText: 2020-2024 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2022 Codecoup + * SPDX-FileCopyrightText: 2023 NXP + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include "tmap_peripheral.h" + +#define VOCS_INST_COUNT CONFIG_BT_VCP_VOL_REND_VOCS_INSTANCE_COUNT +#define AICS_INST_COUNT CONFIG_BT_VCP_VOL_REND_AICS_INSTANCE_COUNT + +#define VOCS_OUTPUT_DESC_SIZE CONFIG_BT_VOCS_MAX_OUTPUT_DESCRIPTION_SIZE +#define AICS_INPUT_DESC_SIZE CONFIG_BT_AICS_MAX_INPUT_DESCRIPTION_SIZE + +static esp_ble_audio_vcp_included_t vcp_included; + +static void vcs_state_cb(esp_ble_conn_t *conn, int err, uint8_t volume, uint8_t mute) +{ + if (err) { + ESP_LOGE(TAG, "Failed to get VCS state, err %d", err); + } else { + ESP_LOGI(TAG, "VCS volume %u, mute %u", volume, mute); + } +} + +static void vcs_flags_cb(esp_ble_conn_t *conn, int err, uint8_t flags) +{ + if (err) { + ESP_LOGE(TAG, "Failed to get VCS flags, err %d", err); + } else { + ESP_LOGI(TAG, "VCS flags 0x%02x", flags); + } +} + +static void aics_state_cb(esp_ble_audio_aics_t *inst, + int err, int8_t gain, + uint8_t mute, uint8_t mode) +{ + if (err) { + ESP_LOGE(TAG, "AICS state get failed (%d) for inst %p", err, inst); + } else { + ESP_LOGI(TAG, "AICS inst %p state gain %d, mute %u, mode %u", + inst, gain, mute, mode); + } +} + +static void aics_gain_setting_cb(esp_ble_audio_aics_t *inst, + int err, uint8_t units, + int8_t minimum, int8_t maximum) +{ + if (err) { + ESP_LOGE(TAG, "AICS gain settings get failed (%d) for inst %p", err, inst); + } else { + ESP_LOGI(TAG, "AICS inst %p gain settings units %u, min %d, max %d", + inst, units, minimum, maximum); + } +} + +static void aics_input_type_cb(esp_ble_audio_aics_t *inst, int err, uint8_t input_type) +{ + if (err) { + ESP_LOGE(TAG, "AICS input type get failed (%d) for inst %p", err, inst); + } else { + ESP_LOGI(TAG, "AICS inst %p input type %u", inst, input_type); + } +} + +static void aics_status_cb(esp_ble_audio_aics_t *inst, int err, bool active) +{ + if (err) { + ESP_LOGE(TAG, "AICS status get failed (%d) for inst %p", err, inst); + } else { + ESP_LOGI(TAG, "AICS inst %p status %s", inst, active ? "active" : "inactive"); + } +} +static void aics_description_cb(esp_ble_audio_aics_t *inst, int err, char *description) +{ + if (err) { + ESP_LOGE(TAG, "AICS description get failed (%d) for inst %p", err, inst); + } else { + ESP_LOGI(TAG, "AICS inst %p description %s", inst, description); + } +} +static void vocs_state_cb(esp_ble_audio_vocs_t *inst, int err, int16_t offset) +{ + if (err) { + ESP_LOGE(TAG, "VOCS state get failed (%d) for inst %p", err, inst); + } else { + ESP_LOGI(TAG, "VOCS inst %p offset %d", inst, offset); + } +} + +static void vocs_location_cb(esp_ble_audio_vocs_t *inst, int err, uint32_t location) +{ + if (err) { + ESP_LOGE(TAG, "VOCS location get failed (%d) for inst %p", err, inst); + } else { + ESP_LOGI(TAG, "VOCS inst %p location %u", inst, location); + } +} + +static void vocs_description_cb(esp_ble_audio_vocs_t *inst, int err, char *description) +{ + if (err) { + ESP_LOGE(TAG, "VOCS description get failed (%d) for inst %p", err, inst); + } else { + ESP_LOGI(TAG, "VOCS inst %p description %s", inst, description); + } +} + +static esp_ble_audio_vcp_vol_rend_cb_t vcp_cbs = { + .state = vcs_state_cb, + .flags = vcs_flags_cb, +}; + +static esp_ble_audio_aics_cb_t aics_cbs = { + .state = aics_state_cb, + .gain_setting = aics_gain_setting_cb, + .type = aics_input_type_cb, + .status = aics_status_cb, + .description = aics_description_cb +}; + +static esp_ble_audio_vocs_cb_t vocs_cbs = { + .state = vocs_state_cb, + .location = vocs_location_cb, + .description = vocs_description_cb +}; + +int vcp_vol_renderer_init(void) +{ + esp_ble_audio_vocs_register_param_t vocs_param[VOCS_INST_COUNT] = {0}; + esp_ble_audio_aics_register_param_t aics_param[AICS_INST_COUNT] = {0}; + esp_ble_audio_vcp_vol_rend_register_param_t vcp_register_param = {0}; + char output_desc[VOCS_INST_COUNT][VOCS_OUTPUT_DESC_SIZE]; + char input_desc[AICS_INST_COUNT][AICS_INPUT_DESC_SIZE]; + int err; + + vcp_register_param.vocs_param = vocs_param; + vcp_register_param.aics_param = aics_param; + + for (size_t i = 0; i < VOCS_INST_COUNT; i++) { + vcp_register_param.vocs_param[i].location_writable = true; + snprintf(output_desc[i], sizeof(output_desc[i]), "Output %d", i + 1); + vcp_register_param.vocs_param[i].output_desc = output_desc[i]; + vcp_register_param.vocs_param[i].desc_writable = true; + vcp_register_param.vocs_param[i].cb = &vocs_cbs; + } + + for (size_t i = 0; i < AICS_INST_COUNT; i++) { + vcp_register_param.aics_param[i].gain_mode = ESP_BLE_AUDIO_AICS_MODE_MANUAL; + vcp_register_param.aics_param[i].units = 1; + vcp_register_param.aics_param[i].min_gain = -100; + vcp_register_param.aics_param[i].max_gain = 100; + vcp_register_param.aics_param[i].type = ESP_BLE_AUDIO_AICS_INPUT_TYPE_UNSPECIFIED; + vcp_register_param.aics_param[i].status = true; + vcp_register_param.aics_param[i].desc_writable = true; + snprintf(input_desc[i], sizeof(input_desc[i]), "Input %d", i + 1); + vcp_register_param.aics_param[i].description = input_desc[i]; + vcp_register_param.aics_param[i].cb = &aics_cbs; + } + + vcp_register_param.step = 1; + vcp_register_param.mute = ESP_BLE_AUDIO_VCP_STATE_UNMUTED; + vcp_register_param.volume = 10; + vcp_register_param.cb = &vcp_cbs; + + err = esp_ble_audio_vcp_vol_rend_register(&vcp_register_param); + if (err) { + ESP_LOGE(TAG, "Failed to register VCP renderer, err %d", err); + return err; + } + + err = esp_ble_audio_vcp_vol_rend_included_get(&vcp_included); + if (err) { + ESP_LOGE(TAG, "Failed to get VCP renderer included service, err %d", err); + return err; + } + + ESP_LOGI(TAG, "vcp vol renderer, vocs_cnt %u aics_cnt %u", + vcp_included.vocs_cnt, vcp_included.aics_cnt); + for (size_t i = 0; i < vcp_included.vocs_cnt; i++) { + ESP_LOGI(TAG, "vcp vol renderer, vocs_%u %p", i, vcp_included.vocs[i]); + } + for (size_t i = 0; i < vcp_included.aics_cnt; i++) { + ESP_LOGI(TAG, "vcp vol renderer, aics_%u %p", i, vcp_included.aics[i]); + } + + ESP_LOGI(TAG, "VCP volume renderer initialized"); + + return 0; +} diff --git a/examples/bluetooth/esp_ble_audio/tmap/peripheral/sdkconfig.defaults b/examples/bluetooth/esp_ble_audio/tmap/peripheral/sdkconfig.defaults new file mode 100644 index 0000000000..ae13965b05 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/peripheral/sdkconfig.defaults @@ -0,0 +1,41 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration +# + +CONFIG_BT_ENABLED=y +CONFIG_BT_BLUEDROID_ENABLED=n +CONFIG_BT_NIMBLE_ENABLED=y +CONFIG_BT_NIMBLE_EXT_ADV=y +CONFIG_BT_NIMBLE_MAX_CONNECTIONS=1 +CONFIG_BT_NIMBLE_MAX_CCCDS=30 +CONFIG_BT_NIMBLE_ISO=y +CONFIG_BT_NIMBLE_LOG_LEVEL_WARNING=y + +CONFIG_BT_ISO_MAX_CHAN=2 + +CONFIG_BT_TMAP=y +CONFIG_BT_CAP_ACCEPTOR=y +CONFIG_BT_BAP_UNICAST_SERVER=y +CONFIG_BT_PAC_SNK_NOTIFIABLE=y +CONFIG_BT_PAC_SNK_LOC_WRITEABLE=y +CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE=y +CONFIG_BT_PAC_SRC_NOTIFIABLE=y +CONFIG_BT_PAC_SRC_LOC_WRITEABLE=y +CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE=y +CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE=y +CONFIG_BT_VOCS_MAX_INSTANCE_COUNT=1 +CONFIG_BT_AICS_MAX_INSTANCE_COUNT=1 +CONFIG_BT_VCP_VOL_REND=y +CONFIG_BT_VCP_VOL_REND_VOCS_INSTANCE_COUNT=1 +CONFIG_BT_VCP_VOL_REND_AICS_INSTANCE_COUNT=1 +CONFIG_BT_VCP_VOL_REND_VOL_FLAGS_NOTIFIABLE=y +CONFIG_BT_MCC=y +CONFIG_BT_TBS_CLIENT_GTBS=y +CONFIG_BT_TBS_CLIENT_TBS=y +CONFIG_BT_TBS_CLIENT_ORIGINATE_CALL=y +CONFIG_BT_TBS_CLIENT_TERMINATE_CALL=y +CONFIG_BT_TBS_CLIENT_BEARER_URI_SCHEMES_SUPPORTED_LIST=y + +CONFIG_EXAMPLE_TMAP_PER_DUO=y + +CONFIG_FREERTOS_HZ=1000 diff --git a/examples/bluetooth/esp_ble_audio/tmap/peripheral/sdkconfig.defaults.esp32h4 b/examples/bluetooth/esp_ble_audio/tmap/peripheral/sdkconfig.defaults.esp32h4 new file mode 100644 index 0000000000..5920ce3f85 --- /dev/null +++ b/examples/bluetooth/esp_ble_audio/tmap/peripheral/sdkconfig.defaults.esp32h4 @@ -0,0 +1,6 @@ +# Override some defaults so BT stack is enabled +# by default in this example + +CONFIG_IDF_TARGET="esp32h4" + +CONFIG_BT_LE_ISO_SUPPORT=y diff --git a/examples/bluetooth/esp_ble_iso/big_broadcaster/CMakeLists.txt b/examples/bluetooth/esp_ble_iso/big_broadcaster/CMakeLists.txt new file mode 100644 index 0000000000..e43ddd782d --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/big_broadcaster/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.22) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +idf_build_set_property(MINIMAL_BUILD ON) +project(big_broadcaster) diff --git a/examples/bluetooth/esp_ble_iso/big_broadcaster/README.md b/examples/bluetooth/esp_ble_iso/big_broadcaster/README.md new file mode 100644 index 0000000000..179000fb04 --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/big_broadcaster/README.md @@ -0,0 +1,52 @@ +| Supported Targets | ESP32-H4 | +| ----------------- | -------- | + +# BLE BIG Broadcaster Example + +(See the README.md file in the upper level `examples` directory for more information about examples.) + +This example demonstrates the **Bluetooth LE Isochronous Broadcaster** functionality. It acts as a Broadcast Isochronous Stream (BIS) source: it starts extended advertising and periodic advertising, creates a Broadcast Isochronous Group (BIG), and sends isochronous data on the BIS channels. Receivers can synchronize to this BIG using the [big_receiver](../big_receiver) example. + +The implementation uses the NimBLE host stack with ISO support and the ESP-BLE-ISO APIs (CIG/BIG, data path, channel operations). It is intended for chips that support BLE 5.2 ISO (e.g. ESP32-H4). The advertised device name is hardcoded as `BIG Broadcaster` and the broadcast code is hardcoded as `1234`; these can be changed by editing the source code constants. + +## Requirements + +* A board with Bluetooth LE 5.2 and ISO support (e.g. ESP32-H4) +* Optionally, a second device running the [big_receiver](../big_receiver) example to receive and sync to the BIG + +## How to Use Example + +Before project configuration and build, set the correct chip target: + +```bash +idf.py set-target esp32h4 +``` + +### Build and Flash + +Run the following to build, flash and monitor: + +```bash +idf.py -p PORT flash monitor +``` + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the [Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF. + +## Example Flow + +1. **Initialization**: NVS, Bluetooth stack (NimBLE), and ISO common layer (`esp_ble_iso_common_init`). +2. **Extended and periodic advertising**: Configure and start extended advertising with a fixed interval; attach periodic advertising with name `BIG Broadcaster` for receivers to discover. +3. **Create BIG**: Register the advertising set for BIG, then create a BIG with two BIS channels (hardcoded as `BIS_ISO_CHAN_COUNT` in the source; `CONFIG_BT_ISO_MAX_CHAN` must be >= 2), SDU interval 10 ms, latency 10 ms, sequential packing, unframed, and encryption with the hardcoded broadcast code `1234`. The [big_receiver](../big_receiver) must use the same broadcast code. +4. **Send ISO data**: Once all BIS channels are connected and their data paths are set up, a periodic TX scheduler based on `k_work_delayable` sends the same SDU on all BIS channels at the configured interval in the ISO task context; sequence numbers and drift handling are applied. Note that the scheduler timer resolution is in milliseconds, which may not match the exact SDU interval for all configurations. + +## Example Output + +``` +I (xxx) BIG_BRD: Extended adv instance 0 started +I (xxx) BIG_BRD: ISO channel 0x0001 connected +I (xxx) BIG_BRD: ISO channel 0x0002 connected +I (xxx) BIG_BRD: Transmitted 1000 ISO data packets (chan 0x...) +... +``` diff --git a/examples/bluetooth/esp_ble_iso/big_broadcaster/main/CMakeLists.txt b/examples/bluetooth/esp_ble_iso/big_broadcaster/main/CMakeLists.txt new file mode 100644 index 0000000000..721967052c --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/big_broadcaster/main/CMakeLists.txt @@ -0,0 +1,4 @@ +set(srcs "main.c") + +idf_component_register(SRCS "${srcs}" + REQUIRES bt nvs_flash) diff --git a/examples/bluetooth/esp_ble_iso/big_broadcaster/main/idf_component.yml b/examples/bluetooth/esp_ble_iso/big_broadcaster/main/idf_component.yml new file mode 100644 index 0000000000..fff7f2843b --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/big_broadcaster/main/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + example_init: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_iso/common_components/example_init + example_utils: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_iso/common_components/example_utils diff --git a/examples/bluetooth/esp_ble_iso/big_broadcaster/main/main.c b/examples/bluetooth/esp_ble_iso/big_broadcaster/main/main.c new file mode 100644 index 0000000000..e74dd16544 --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/big_broadcaster/main/main.c @@ -0,0 +1,411 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "esp_log.h" +#include "nvs_flash.h" +#include "esp_timer.h" + +#include "host/ble_gap.h" + +#include "esp_ble_iso_common_api.h" + +#include "ble_iso_example_init.h" +#include "ble_iso_example_utils.h" + +#define TAG "BIG_BRD" + +#define LOCAL_DEVICE_NAME "BIG Broadcaster" +#define LOCAL_DEVICE_NAME_LEN (sizeof(LOCAL_DEVICE_NAME) - 1) + +#define LOCAL_BROADCAST_CODE "1234" /* Maximum length is 16 */ + +#define ADV_HANDLE 0 +#define ADV_SID 0 +#define ADV_TX_POWER 127 +#define ADV_ADDRESS BLE_OWN_ADDR_PUBLIC +#define ADV_PRIMARY_PHY BLE_HCI_LE_PHY_1M +#define ADV_SECONDARY_PHY BLE_HCI_LE_PHY_2M +#define ADV_INTERVAL BLE_GAP_ADV_ITVL_MS(200) + +#define PER_ADV_INTERVAL BLE_GAP_ADV_ITVL_MS(100) + +#define BIG_SDU_INTERVAL_US 10000 /* 10ms */ +#define BIG_LATENCY_MS 10 /* 10ms */ +#define BIG_PHY ESP_BLE_ISO_PHY_2M +#define BIG_RTN 2 +#define BIG_PACKING 0 /* 0 - sequential, 1 - interleaved */ +#define BIG_FRAMING 0 /* 0 - unframed, 1 - framed */ +#define BIS_ISO_CHAN_COUNT 2 /* Use exactly 2 BIS channels */ +#define BIS_SDU_SIZE 120 +#define BIG_ENCRYPTION true + +/* CONFIG_BT_ISO_MAX_CHAN must be >= 2 */ +_Static_assert(CONFIG_BT_ISO_MAX_CHAN >= BIS_ISO_CHAN_COUNT, + "CONFIG_BT_ISO_MAX_CHAN must be >= BIS_ISO_CHAN_COUNT"); + +static uint8_t ext_adv_data[3 + 2 + LOCAL_DEVICE_NAME_LEN]; +static uint8_t per_adv_data[LOCAL_DEVICE_NAME_LEN]; + +static esp_ble_iso_big_t *out_big; + +static size_t connected_bis_count; + +static struct iso_chan_tx { + int chan_idx; + uint16_t seq_num; + uint8_t data[BIS_SDU_SIZE]; + example_iso_tx_scheduler_t scheduler; +} chan_tx[BIS_ISO_CHAN_COUNT]; + +static void iso_chan_send(int chan_idx); +static int bis_chan_index_get(const esp_ble_iso_chan_t *chan); + +static void iso_connected_cb(esp_ble_iso_chan_t *chan) +{ + const esp_ble_iso_chan_path_t data_path = { + .pid = ESP_BLE_ISO_DATA_PATH_HCI, + .format = ESP_BLE_ISO_CODING_FORMAT_TRANSPARENT, + }; + esp_err_t err; + + ESP_LOGI(TAG, "ISO channel %p connected", chan); + + err = esp_ble_iso_setup_data_path(chan, ESP_BLE_ISO_DATA_PATH_DIR_INPUT, &data_path); + if (err) { + ESP_LOGE(TAG, "Failed to setup ISO data path, err %d", err); + return; + } + + connected_bis_count++; + + if (connected_bis_count < BIS_ISO_CHAN_COUNT) { + ESP_LOGI(TAG, "Waiting for all BIS channels (%u/%u)", + connected_bis_count, BIS_ISO_CHAN_COUNT); + return; + } + + ESP_LOGI(TAG, "All %u BIS channels connected, starting TX", BIS_ISO_CHAN_COUNT); + + /* Note: esp timer is not accurate enough */ + for (size_t i = 0; i < BIS_ISO_CHAN_COUNT; i++) { + chan_tx[i].seq_num = 0; + example_iso_tx_scheduler_reset(&chan_tx[i].scheduler); + + err = example_iso_tx_scheduler_start(&chan_tx[i].scheduler, BIG_SDU_INTERVAL_US); + if (err) { + ESP_LOGE(TAG, "Failed to start tx scheduler[%u], err %d", i, err); + continue; + } + + iso_chan_send((int)i); + } +} + +static void iso_disconnected_cb(esp_ble_iso_chan_t *chan, uint8_t reason) +{ + ESP_LOGI(TAG, "ISO channel %p disconnected, reason 0x%02x", chan, reason); + + if (connected_bis_count > 0) { + connected_bis_count--; + } + + if (connected_bis_count == 0) { + esp_err_t err; + + ESP_LOGI(TAG, "All BIS channels disconnected, TX stopped"); + + for (size_t i = 0; i < BIS_ISO_CHAN_COUNT; i++) { + err = example_iso_tx_scheduler_stop(&chan_tx[i].scheduler); + if (err) { + ESP_LOGE(TAG, "Failed to stop tx scheduler[%u], err %d", i, err); + } + } + + out_big = NULL; + } +} + +static void iso_sent_cb(esp_ble_iso_chan_t *chan, void *user_data) +{ + int chan_idx = bis_chan_index_get(chan); + + if (chan_idx < 0) { + ESP_LOGW(TAG, "Unknown BIS channel %p", chan); + return; + } + + example_iso_tx_scheduler_on_sent(&chan_tx[chan_idx].scheduler, + user_data, TAG, "chan", chan); +} + +static esp_ble_iso_chan_ops_t iso_ops = { + .connected = iso_connected_cb, + .disconnected = iso_disconnected_cb, + .sent = iso_sent_cb, +}; + +static esp_ble_iso_chan_io_qos_t iso_tx_qos = { + .sdu = BIS_SDU_SIZE, + .rtn = BIG_RTN, + .phy = BIG_PHY, +}; + +static esp_ble_iso_chan_qos_t bis_iso_qos = { + .tx = &iso_tx_qos, +}; + +static esp_ble_iso_chan_t bis_iso_chan[] = { + { .ops = &iso_ops, .qos = &bis_iso_qos, }, + { .ops = &iso_ops, .qos = &bis_iso_qos, }, +}; + +static esp_ble_iso_chan_t *bis[] = { + &bis_iso_chan[0], + &bis_iso_chan[1], +}; + +static int bis_chan_index_get(const esp_ble_iso_chan_t *chan) +{ + for (size_t i = 0; i < BIS_ISO_CHAN_COUNT; i++) { + if (chan == &bis_iso_chan[i]) { + return (int)i; + } + } + + return -1; +} + +static void build_adv_data(void) +{ + ext_adv_data[0] = 0x02; + ext_adv_data[1] = EXAMPLE_AD_TYPE_FLAGS; + ext_adv_data[2] = EXAMPLE_AD_FLAGS_GENERAL | EXAMPLE_AD_FLAGS_NO_BREDR; + ext_adv_data[3] = (uint8_t)(LOCAL_DEVICE_NAME_LEN + 1); /* AD type + name */ + ext_adv_data[4] = EXAMPLE_AD_TYPE_NAME_COMPLETE; + memcpy(&ext_adv_data[5], LOCAL_DEVICE_NAME, LOCAL_DEVICE_NAME_LEN); + + memcpy(per_adv_data, LOCAL_DEVICE_NAME, LOCAL_DEVICE_NAME_LEN); +} + +static int ext_adv_start(void) +{ + struct ble_gap_periodic_adv_params per_params = {0}; + struct ble_gap_ext_adv_params ext_params = {0}; + struct os_mbuf *data = NULL; + int err; + + build_adv_data(); + + ext_params.connectable = 0; + ext_params.scannable = 0; + ext_params.legacy_pdu = 0; + ext_params.own_addr_type = ADV_ADDRESS; + ext_params.primary_phy = ADV_PRIMARY_PHY; + ext_params.secondary_phy = ADV_SECONDARY_PHY; + ext_params.tx_power = ADV_TX_POWER; + ext_params.sid = ADV_SID; + ext_params.itvl_min = ADV_INTERVAL; + ext_params.itvl_max = ADV_INTERVAL; + + err = ble_gap_ext_adv_configure(ADV_HANDLE, &ext_params, NULL, + example_iso_gap_event_cb, NULL); + if (err) { + ESP_LOGE(TAG, "Failed to configure ext adv params, err %d", err); + return err; + } + + data = os_msys_get_pkthdr(sizeof(ext_adv_data), 0); + if (data == NULL) { + ESP_LOGE(TAG, "Failed to get ext adv mbuf"); + return -1; + } + + err = os_mbuf_append(data, ext_adv_data, sizeof(ext_adv_data)); + if (err) { + ESP_LOGE(TAG, "Failed to append ext adv data, err %d", err); + os_mbuf_free_chain(data); + return err; + } + + err = ble_gap_ext_adv_set_data(ADV_HANDLE, data); + if (err) { + ESP_LOGE(TAG, "Failed to set ext adv data, err %d", err); + return err; + } + + per_params.include_tx_power = 0; + per_params.itvl_min = PER_ADV_INTERVAL; + per_params.itvl_max = PER_ADV_INTERVAL; + + err = ble_gap_periodic_adv_configure(ADV_HANDLE, &per_params); + if (err) { + ESP_LOGE(TAG, "Failed to configure per adv params, err %d", err); + return err; + } + + data = os_msys_get_pkthdr(sizeof(per_adv_data), 0); + if (data == NULL) { + ESP_LOGE(TAG, "Failed to get per adv mbuf"); + return -1; + } + + err = os_mbuf_append(data, per_adv_data, sizeof(per_adv_data)); + if (err) { + ESP_LOGE(TAG, "Failed to append per adv data, err %d", err); + os_mbuf_free_chain(data); + return err; + } + + err = ble_gap_periodic_adv_set_data(ADV_HANDLE, data); + if (err) { + ESP_LOGE(TAG, "Failed to set per adv data, err %d", err); + return err; + } + + err = ble_gap_periodic_adv_start(ADV_HANDLE); + if (err) { + ESP_LOGE(TAG, "Failed to start per adv, err %d", err); + return err; + } + + err = ble_gap_ext_adv_start(ADV_HANDLE, 0, 0); + if (err) { + ESP_LOGE(TAG, "Failed to start ext adv, err %d", err); + return err; + } + + ESP_LOGI(TAG, "Extended adv instance %u started", ADV_HANDLE); + + return 0; +} + +static void big_create(void) +{ + esp_ble_iso_big_create_param_t param = {0}; + esp_ble_iso_ext_adv_info_t info = { + .adv_handle = ADV_HANDLE, + }; + size_t bcode_len = 0; + int err; + + err = esp_ble_iso_big_ext_adv_add(&info); + if (err) { + ESP_LOGE(TAG, "Failed to add ext adv for BIG, err %d", err); + return; + } + + param.bis_channels = bis; + param.num_bis = BIS_ISO_CHAN_COUNT; + param.interval = BIG_SDU_INTERVAL_US; + param.latency = BIG_LATENCY_MS; + param.packing = BIG_PACKING; + param.framing = BIG_FRAMING; + param.encryption = BIG_ENCRYPTION; + if (param.encryption) { + memset(param.bcode, 0, ESP_BLE_ISO_BROADCAST_CODE_SIZE); + + bcode_len = strlen(LOCAL_BROADCAST_CODE); + if (bcode_len > 0) { + memcpy(param.bcode, LOCAL_BROADCAST_CODE, + MIN((size_t)ESP_BLE_ISO_BROADCAST_CODE_SIZE, bcode_len)); + } + } + + err = esp_ble_iso_big_create(ADV_HANDLE, ¶m, &out_big); + if (err) { + ESP_LOGE(TAG, "Failed to create BIG, err %d", err); + return; + } +} + +static void iso_chan_send(int chan_idx) +{ + int err; + + if (chan_idx < 0 || chan_idx >= BIS_ISO_CHAN_COUNT) { + return; + } + + if (bis_iso_chan[chan_idx].iso == NULL) { + ESP_LOGW(TAG, "No channel to transmit data, %u", chan_idx); + return; + } + + memset(chan_tx[chan_idx].data, + (int)chan_tx[chan_idx].seq_num, + sizeof(chan_tx[chan_idx].data)); + + err = esp_ble_iso_chan_send(&bis_iso_chan[chan_idx], + chan_tx[chan_idx].data, + sizeof(chan_tx[chan_idx].data), + chan_tx[chan_idx].seq_num); + if (err) { + ESP_LOGD(TAG, "Failed to transmit data on channel 0x%04x", + bis_iso_chan[chan_idx].iso->handle); + return; + } + + chan_tx[chan_idx].seq_num++; +} + +static void tx_scheduler_cb(void *arg) +{ + struct iso_chan_tx *tx = arg; + + if (tx == NULL) { + return; + } + + iso_chan_send(tx->chan_idx); +} + +void app_main(void) +{ + esp_ble_iso_init_info_t info = {0}; + esp_err_t err; + + /* Initialize NVS — it is used to store PHY calibration data */ + err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK(err); + + err = bluetooth_init(); + if (err) { + ESP_LOGE(TAG, "Failed to initialize BLE, err %d", err); + return; + } + + err = esp_ble_iso_common_init(&info); + if (err) { + ESP_LOGE(TAG, "Failed to initialize ISO, err %d", err); + return; + } + + for (size_t i = 0; i < BIS_ISO_CHAN_COUNT; i++) { + chan_tx[i].chan_idx = (int)i; + err = example_iso_tx_scheduler_init(&chan_tx[i].scheduler, + tx_scheduler_cb, + &chan_tx[i]); + if (err) { + ESP_LOGE(TAG, "Failed to init tx scheduler[%u], err %d", i, err); + return; + } + } + + err = ext_adv_start(); + if (err) { + return; + } + + big_create(); +} diff --git a/examples/bluetooth/esp_ble_iso/big_broadcaster/sdkconfig.defaults b/examples/bluetooth/esp_ble_iso/big_broadcaster/sdkconfig.defaults new file mode 100644 index 0000000000..d5aeca2558 --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/big_broadcaster/sdkconfig.defaults @@ -0,0 +1,15 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration +# + +CONFIG_BT_ENABLED=y +CONFIG_BT_BLUEDROID_ENABLED=n +CONFIG_BT_NIMBLE_ENABLED=y +CONFIG_BT_NIMBLE_EXT_ADV=y +CONFIG_BT_NIMBLE_ISO=y +CONFIG_BT_NIMBLE_LOG_LEVEL_WARNING=y + +CONFIG_BT_ISO_BROADCASTER=y +CONFIG_BT_ISO_MAX_CHAN=2 + +CONFIG_FREERTOS_HZ=1000 diff --git a/examples/bluetooth/esp_ble_iso/big_broadcaster/sdkconfig.defaults.esp32h4 b/examples/bluetooth/esp_ble_iso/big_broadcaster/sdkconfig.defaults.esp32h4 new file mode 100644 index 0000000000..5920ce3f85 --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/big_broadcaster/sdkconfig.defaults.esp32h4 @@ -0,0 +1,6 @@ +# Override some defaults so BT stack is enabled +# by default in this example + +CONFIG_IDF_TARGET="esp32h4" + +CONFIG_BT_LE_ISO_SUPPORT=y diff --git a/examples/bluetooth/esp_ble_iso/big_receiver/CMakeLists.txt b/examples/bluetooth/esp_ble_iso/big_receiver/CMakeLists.txt new file mode 100644 index 0000000000..cedce28630 --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/big_receiver/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.22) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +idf_build_set_property(MINIMAL_BUILD ON) +project(big_receiver) diff --git a/examples/bluetooth/esp_ble_iso/big_receiver/README.md b/examples/bluetooth/esp_ble_iso/big_receiver/README.md new file mode 100644 index 0000000000..31872282a2 --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/big_receiver/README.md @@ -0,0 +1,59 @@ +| Supported Targets | ESP32-H4 | +| ----------------- | -------- | + +# BLE BIG Receiver Example + +(See the README.md file in the upper level `examples` directory for more information about examples.) + +This example demonstrates the **Bluetooth LE Synchronized Receiver** functionality. It acts as a BIS (Broadcast Isochronous Stream) sink: it scans for extended advertising, establishes periodic advertising synchronization with a broadcaster, receives BIGInfo from the periodic advertising, and synchronizes to the BIG to receive isochronous data on the BIS channels. Use it together with the [big_broadcaster](../big_broadcaster) example on another device as the source. + +The implementation uses the NimBLE host stack with ISO support and the ESP-BLE-ISO APIs (periodic sync, BIG sync, data path, channel operations). It is intended for chips that support BLE 5.2 ISO (e.g. ESP32-H4). The target broadcaster name is hardcoded as `BIG Broadcaster` and the broadcast code is hardcoded as `1234`; these must match the [big_broadcaster](../big_broadcaster) defaults. + +## Requirements + +* A board with Bluetooth LE 5.2 and ISO support (e.g. ESP32-H4) +* Another device running the [big_broadcaster](../big_broadcaster) example, which performs periodic advertising and creates the BIG + +## How to Use Example + +Before project configuration and build, set the correct chip target: + +```bash +idf.py set-target esp32h4 +``` + +### Build and Flash + +Run the following to build, flash and monitor: + +```bash +idf.py -p PORT flash monitor +``` + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the [Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF. + +## Example Flow + +1. **Initialization**: NVS, Bluetooth stack (NimBLE), and ISO common layer (`esp_ble_iso_common_init`) with GAP callback for scan, periodic sync, and BIGInfo events. +2. **Extended scan**: Start passive extended scanning. On extended scan report, parse advertising data for the complete local name. +3. **Periodic advertising sync**: When the advertised name matches the hardcoded target name `BIG Broadcaster` and the advertiser has periodic advertising, create a periodic advertising synchronization to that advertiser. +4. **BIGInfo and BIG sync**: When BIGInfo is received in the periodic advertising, create a BIG sync (`esp_ble_iso_big_sync`) with two BIS channels (hardcoded in this example; must match the [big_broadcaster](../big_broadcaster)) and the hardcoded broadcast code `1234`. +5. **Receive ISO data**: When each BIS channel is connected, set up the output data path. Incoming ISO SDUs are reported in the receive callback; the example counts valid, error, and lost packets and logs periodically. + +## Example Output + +``` +I (xxx) BIG_SNC: Extended scan started +I (xxx) BIG_SNC: ISO channel 0x0001 connected +I (xxx) BIG_SNC: ISO channel 0x0002 connected +I (xxx) BIG_SNC: Received 1000(1000/0/0) ISO data packets (chan 0x...) +... +``` + +If periodic sync is lost: + +``` +I (xxx) BIG_SNC: PA sync lost, reason ... +``` diff --git a/examples/bluetooth/esp_ble_iso/big_receiver/main/CMakeLists.txt b/examples/bluetooth/esp_ble_iso/big_receiver/main/CMakeLists.txt new file mode 100644 index 0000000000..721967052c --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/big_receiver/main/CMakeLists.txt @@ -0,0 +1,4 @@ +set(srcs "main.c") + +idf_component_register(SRCS "${srcs}" + REQUIRES bt nvs_flash) diff --git a/examples/bluetooth/esp_ble_iso/big_receiver/main/idf_component.yml b/examples/bluetooth/esp_ble_iso/big_receiver/main/idf_component.yml new file mode 100644 index 0000000000..fff7f2843b --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/big_receiver/main/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + example_init: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_iso/common_components/example_init + example_utils: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_iso/common_components/example_utils diff --git a/examples/bluetooth/esp_ble_iso/big_receiver/main/main.c b/examples/bluetooth/esp_ble_iso/big_receiver/main/main.c new file mode 100644 index 0000000000..72fe834ab9 --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/big_receiver/main/main.c @@ -0,0 +1,320 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "esp_log.h" +#include "nvs_flash.h" +#include "esp_system.h" + +#include "host/ble_gap.h" + +#include "esp_ble_iso_common_api.h" + +#include "ble_iso_example_init.h" +#include "ble_iso_example_utils.h" + +#define TAG "BIG_SNC" + +#define TARGET_DEVICE_NAME "BIG Broadcaster" +#define TARGET_DEVICE_NAME_LEN (sizeof(TARGET_DEVICE_NAME) - 1) + +#define TARGET_BROADCAST_CODE "1234" + +#define SCAN_INTERVAL 160 /* 100ms */ +#define SCAN_WINDOW 160 /* 100ms */ + +#define PA_SYNC_SKIP 0 +#define PA_SYNC_TIMEOUT 1000 /* 1000 * 10ms = 10s */ + +#define BIS_ISO_CHAN_COUNT 2 /* Use exactly 2 BIS channels */ +#define BIG_SYNC_TIMEOUT 100 /* 100 * 10ms = 1s */ + +/* CONFIG_BT_ISO_MAX_CHAN must be >= 2 */ +_Static_assert(CONFIG_BT_ISO_MAX_CHAN >= BIS_ISO_CHAN_COUNT, + "CONFIG_BT_ISO_MAX_CHAN must be >= BIS_ISO_CHAN_COUNT"); + +static bool per_adv_synced; +static bool big_synced; + +static esp_ble_iso_big_t *out_big; + +/* Per-BIS counters, indexed by BIS channel. */ +static example_iso_rx_metrics_t rx_metrics[BIS_ISO_CHAN_COUNT]; + +static int bis_chan_index_get(const esp_ble_iso_chan_t *chan); + +static void iso_connected_cb(esp_ble_iso_chan_t *chan) +{ + const esp_ble_iso_chan_path_t data_path = { + .pid = ESP_BLE_ISO_DATA_PATH_HCI, + .format = ESP_BLE_ISO_CODING_FORMAT_TRANSPARENT, + }; + esp_err_t err; + + ESP_LOGI(TAG, "ISO channel %p connected", chan); + + err = esp_ble_iso_setup_data_path(chan, ESP_BLE_ISO_DATA_PATH_DIR_OUTPUT, &data_path); + if (err) { + ESP_LOGE(TAG, "Failed to setup ISO data path, err %d", err); + return; + } +} + +static void iso_disconnected_cb(esp_ble_iso_chan_t *chan, uint8_t reason) +{ + ESP_LOGI(TAG, "ISO channel %p disconnected, reason 0x%02x", chan, reason); + + big_synced = false; + out_big = NULL; + + for (size_t i = 0; i < BIS_ISO_CHAN_COUNT; i++) { + example_iso_rx_metrics_reset(&rx_metrics[i]); + } +} + +static void iso_recv_cb(esp_ble_iso_chan_t *chan, + const esp_ble_iso_recv_info_t *info, + const uint8_t *data, uint16_t len) +{ + int chan_idx = bis_chan_index_get(chan); + + if (chan_idx < 0) { + ESP_LOGW(TAG, "Unknown BIS channel %p", chan); + return; + } + + rx_metrics[chan_idx].last_sdu_len = len; + example_iso_rx_metrics_on_recv(info, &rx_metrics[chan_idx], TAG, "chan", chan); +} + +static esp_ble_iso_chan_ops_t iso_ops = { + .connected = iso_connected_cb, + .disconnected = iso_disconnected_cb, + .recv = iso_recv_cb, +}; + +static esp_ble_iso_chan_io_qos_t iso_rx_qos[BIS_ISO_CHAN_COUNT]; + +static esp_ble_iso_chan_qos_t bis_iso_qos[] = { + { .rx = &iso_rx_qos[0], }, + { .rx = &iso_rx_qos[1], }, +}; + +static esp_ble_iso_chan_t bis_iso_chan[] = { + { .ops = &iso_ops, .qos = &bis_iso_qos[0], }, + { .ops = &iso_ops, .qos = &bis_iso_qos[1], }, +}; + +static esp_ble_iso_chan_t *bis[] = { + &bis_iso_chan[0], + &bis_iso_chan[1], +}; + +static int bis_chan_index_get(const esp_ble_iso_chan_t *chan) +{ + for (size_t i = 0; i < BIS_ISO_CHAN_COUNT; i++) { + if (chan == &bis_iso_chan[i]) { + return (int)i; + } + } + + return -1; +} + +static void ext_scan_start(void) +{ + struct ble_gap_disc_params params = {0}; + uint8_t own_addr_type; + int err; + + err = ble_hs_id_infer_auto(0, &own_addr_type); + if (err) { + ESP_LOGE(TAG, "Failed to determine own addr type, err %d", err); + return; + } + + params.passive = 1; + params.itvl = SCAN_INTERVAL; + params.window = SCAN_WINDOW; + + err = ble_gap_disc(own_addr_type, BLE_HS_FOREVER, ¶ms, + example_iso_gap_event_cb, NULL); + if (err) { + ESP_LOGE(TAG, "Failed to start scanning, err %d", err); + return; + } + + ESP_LOGI(TAG, "Extended scan started"); +} + +static int pa_sync_create(uint8_t addr_type, uint8_t addr[6], uint8_t sid) +{ + struct ble_gap_periodic_sync_params params = {0}; + ble_addr_t sync_addr = {0}; + + sync_addr.type = addr_type; + memcpy(sync_addr.val, addr, sizeof(sync_addr.val)); + params.skip = PA_SYNC_SKIP; + params.sync_timeout = PA_SYNC_TIMEOUT; + + return ble_gap_periodic_adv_sync_create(&sync_addr, sid, ¶ms, + example_iso_gap_event_cb, NULL); +} + +static bool data_cb(uint8_t type, const uint8_t *data, + uint8_t data_len, void *user_data) +{ + bool *target_matched = user_data; + + assert(target_matched); + + switch (type) { + case EXAMPLE_AD_TYPE_NAME_COMPLETE: + *target_matched = (data_len == TARGET_DEVICE_NAME_LEN) && + !memcmp(data, TARGET_DEVICE_NAME, TARGET_DEVICE_NAME_LEN); + return false; + default: + return true; + } +} + +static void ext_scan_recv(esp_ble_iso_gap_app_event_t *event) +{ + bool target_matched = false; + int err; + + esp_ble_iso_data_parse(event->ext_scan_recv.data, + event->ext_scan_recv.data_len, + data_cb, &target_matched); + + /* Periodic advertising interval. 0 if no periodic advertising. */ + if (!target_matched || event->ext_scan_recv.per_adv_itvl == 0) { + return; + } + + if (per_adv_synced == false) { + err = pa_sync_create(event->ext_scan_recv.addr.type, + event->ext_scan_recv.addr.val, + event->ext_scan_recv.sid); + if (err) { + ESP_LOGE(TAG, "Failed to create PA sync, err %d", err); + return; + } + + per_adv_synced = true; + } +} + +static void pa_sync(esp_ble_iso_gap_app_event_t *event) +{ + if (event->pa_sync.status) { + ESP_LOGE(TAG, "PA sync failed, status %d", event->pa_sync.status); + per_adv_synced = false; + return; + } + + ESP_LOGI(TAG, "PA sync established:"); + ESP_LOGI(TAG, "sync_handle 0x%04x status 0x%02x addr %02x:%02x:%02x:%02x:%02x:%02x " + "sid %u adv_phy %u per_adv_itvl 0x%04x adv_ca %u", + event->pa_sync.sync_handle, event->pa_sync.status, + event->pa_sync.addr.val[5], event->pa_sync.addr.val[4], + event->pa_sync.addr.val[3], event->pa_sync.addr.val[2], + event->pa_sync.addr.val[1], event->pa_sync.addr.val[0], + event->pa_sync.sid, event->pa_sync.adv_phy, + event->pa_sync.per_adv_itvl, event->pa_sync.adv_ca); +} + +static void pa_sync_lost(esp_ble_iso_gap_app_event_t *event) +{ + ESP_LOGI(TAG, "PA sync lost: sync_handle 0x%04x reason 0x%02x", + event->pa_sync_lost.sync_handle, event->pa_sync_lost.reason); + + per_adv_synced = false; + big_synced = false; + out_big = NULL; + + ext_scan_start(); +} + +static void biginfo_recv(esp_ble_iso_gap_app_event_t *event) +{ + esp_ble_iso_big_sync_param_t param = {0}; + int err; + + if (big_synced == false) { + param.bis_channels = bis; + param.num_bis = BIS_ISO_CHAN_COUNT; + param.bis_bitfield = BIT_MASK(BIS_ISO_CHAN_COUNT); + param.mse = event->biginfo_recv.nse; + param.sync_timeout = BIG_SYNC_TIMEOUT; + param.encryption = event->biginfo_recv.encryption; + if (param.encryption) { + memcpy(param.bcode, TARGET_BROADCAST_CODE, + MIN(ESP_BLE_ISO_BROADCAST_CODE_SIZE, strlen(TARGET_BROADCAST_CODE))); + } + + err = esp_ble_iso_big_sync(event->biginfo_recv.sync_handle, ¶m, &out_big); + if (err) { + ESP_LOGE(TAG, "Failed to create BIG sync, err %d", err); + return; + } + + big_synced = true; + } +} + +static void iso_gap_app_cb(esp_ble_iso_gap_app_event_t *event) +{ + switch (event->type) { + case ESP_BLE_ISO_GAP_EVENT_EXT_SCAN_RECV: + ext_scan_recv(event); + break; + case ESP_BLE_ISO_GAP_EVENT_PA_SYNC: + pa_sync(event); + break; + case ESP_BLE_ISO_GAP_EVENT_PA_SYNC_LOST: + pa_sync_lost(event); + break; + case ESP_BLE_ISO_GAP_EVENT_BIGINFO_RECV: + biginfo_recv(event); + break; + default: + break; + } +} + +void app_main(void) +{ + esp_ble_iso_init_info_t info = { + .gap_cb = iso_gap_app_cb, + }; + esp_err_t err; + + /* Initialize NVS — it is used to store PHY calibration data */ + err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK(err); + + err = bluetooth_init(); + if (err) { + ESP_LOGE(TAG, "Failed to initialize BLE, err %d", err); + return; + } + + err = esp_ble_iso_common_init(&info); + if (err) { + ESP_LOGE(TAG, "Failed to initialize ISO, err %d", err); + return; + } + + ext_scan_start(); +} diff --git a/examples/bluetooth/esp_ble_iso/big_receiver/sdkconfig.defaults b/examples/bluetooth/esp_ble_iso/big_receiver/sdkconfig.defaults new file mode 100644 index 0000000000..022dd160c7 --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/big_receiver/sdkconfig.defaults @@ -0,0 +1,15 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration +# + +CONFIG_BT_ENABLED=y +CONFIG_BT_BLUEDROID_ENABLED=n +CONFIG_BT_NIMBLE_ENABLED=y +CONFIG_BT_NIMBLE_EXT_ADV=y +CONFIG_BT_NIMBLE_ISO=y +CONFIG_BT_NIMBLE_LOG_LEVEL_WARNING=y + +CONFIG_BT_ISO_SYNC_RECEIVER=y +CONFIG_BT_ISO_MAX_CHAN=2 + +CONFIG_FREERTOS_HZ=1000 diff --git a/examples/bluetooth/esp_ble_iso/big_receiver/sdkconfig.defaults.esp32h4 b/examples/bluetooth/esp_ble_iso/big_receiver/sdkconfig.defaults.esp32h4 new file mode 100644 index 0000000000..5920ce3f85 --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/big_receiver/sdkconfig.defaults.esp32h4 @@ -0,0 +1,6 @@ +# Override some defaults so BT stack is enabled +# by default in this example + +CONFIG_IDF_TARGET="esp32h4" + +CONFIG_BT_LE_ISO_SUPPORT=y diff --git a/examples/bluetooth/esp_ble_iso/cis_central/CMakeLists.txt b/examples/bluetooth/esp_ble_iso/cis_central/CMakeLists.txt new file mode 100644 index 0000000000..881c7ee288 --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/cis_central/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.22) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +idf_build_set_property(MINIMAL_BUILD ON) +project(cis_central) diff --git a/examples/bluetooth/esp_ble_iso/cis_central/README.md b/examples/bluetooth/esp_ble_iso/cis_central/README.md new file mode 100644 index 0000000000..b8a38b48a3 --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/cis_central/README.md @@ -0,0 +1,55 @@ +| Supported Targets | ESP32-H4 | +| ----------------- | -------- | + +# BLE CIS Central Example + +(See the README.md file in the upper level `examples` directory for more information about examples.) + +This example demonstrates how to use a **Connected Isochronous Stream (CIS)** as a central. It scans for a peripheral, establishes an ACL connection, creates a Connected Isochronous Group (CIG) and a CIS to the peer, and then sends isochronous data over the CIS every 10 ms. Run it together with the [cis_peripheral](../cis_peripheral) example on another device as the peer. + +The implementation uses the NimBLE host stack with ISO support and the ESP-BLE-ISO APIs (CIG create, CIS connect, data path, channel send). It is intended for chips that support BLE 5.2 ISO (e.g. ESP32-H4). The target peripheral name is hardcoded as `CIS Peripheral` and the connection security level is hardcoded as `ESP_BLE_ISO_SECURITY_MITM` (Level 3: encryption and authentication); the central initiates pairing after the ACL connection. + +## Requirements + +* A board with Bluetooth LE 5.2 and ISO support (e.g. ESP32-H4) +* Another device running the [cis_peripheral](../cis_peripheral) example, which advertises and accepts the ACL and CIS + +## How to Use Example + +Before project configuration and build, set the correct chip target: + +```bash +idf.py set-target esp32h4 +``` + +### Build and Flash + +Run the following to build, flash and monitor: + +```bash +idf.py -p PORT flash monitor +``` + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the [Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF. + +## Example Flow + +1. **Initialization**: NVS, Bluetooth stack (NimBLE), and ISO common layer (`esp_ble_iso_common_init`) with GAP callback for scan, ACL, and security events. +2. **Extended scan**: Start passive extended scanning. On scan report, parse the complete local name; when it matches the hardcoded target name `CIS Peripheral`, initiate an ACL connection to that device. +3. **ACL connection**: On connection established, initiate pairing (security level is hardcoded as `ESP_BLE_ISO_SECURITY_MITM`); the CIG and CIS are created after security is established. +4. **Security**: On security change (after pairing), create the CIG and CIS. +5. **CIG and CIS**: Create a CIG with one CIS (10 ms latency each direction, 10 ms SDU interval, sequential packing, unframed), then connect the CIS over the ACL handle. +6. **Send ISO data**: When the CIS is connected and the input data path is set up, a periodic TX scheduler based on `k_work_delayable` sends an SDU on the CIS every 10 ms in the ISO task context; sequence numbers and drift handling are applied. Note that the scheduler timer resolution is in milliseconds, which may not match the exact SDU interval for all configurations. + +## Example Output + +``` +I (xxx) CIS_CEN: connection established, handle 0 status 0x00 +I (xxx) CIS_CEN: ISO channel 0x... connected +I (xxx) CIS_CEN: Transmitted 1000 ISO data packets (chan 0x...) +... +``` + +If connection or security fails, relevant status or error messages are logged. diff --git a/examples/bluetooth/esp_ble_iso/cis_central/main/CMakeLists.txt b/examples/bluetooth/esp_ble_iso/cis_central/main/CMakeLists.txt new file mode 100644 index 0000000000..721967052c --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/cis_central/main/CMakeLists.txt @@ -0,0 +1,4 @@ +set(srcs "main.c") + +idf_component_register(SRCS "${srcs}" + REQUIRES bt nvs_flash) diff --git a/examples/bluetooth/esp_ble_iso/cis_central/main/idf_component.yml b/examples/bluetooth/esp_ble_iso/cis_central/main/idf_component.yml new file mode 100644 index 0000000000..fff7f2843b --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/cis_central/main/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + example_init: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_iso/common_components/example_init + example_utils: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_iso/common_components/example_utils diff --git a/examples/bluetooth/esp_ble_iso/cis_central/main/main.c b/examples/bluetooth/esp_ble_iso/cis_central/main/main.c new file mode 100644 index 0000000000..e4cdc11dc3 --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/cis_central/main/main.c @@ -0,0 +1,425 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "esp_log.h" +#include "nvs_flash.h" +#include "esp_system.h" +#include "esp_timer.h" + +#include "host/ble_gap.h" +#include "services/gap/ble_svc_gap.h" + +#include "esp_ble_iso_common_api.h" + +#include "ble_iso_example_init.h" +#include "ble_iso_example_utils.h" + +#define TAG "CIS_CEN" + +#define LOCAL_DEVICE_NAME "CIS Central" + +#define TARGET_DEVICE_NAME "CIS Peripheral" +#define TARGET_DEVICE_NAME_LEN (sizeof(TARGET_DEVICE_NAME) - 1) + +#define SCAN_INTERVAL 160 /* 100ms */ +#define SCAN_WINDOW 160 /* 100ms */ + +#define INIT_SCAN_INTERVAL 16 /* 10ms */ +#define INIT_SCAN_WINDOW 16 /* 10ms */ +#define CONN_INTERVAL 64 /* 64 * 1.25 = 80ms */ +#define CONN_LATENCY 0 +#define CONN_TIMEOUT 500 /* 500 * 10ms = 5s */ +#define CONN_MAX_CE_LEN 0xFFFF +#define CONN_MIN_CE_LEN 0xFFFF +#define CONN_DURATION 10000 /* 10s */ + +#define SECURITY_LEVEL ESP_BLE_ISO_SECURITY_MITM + +#define CIG_LATENCY_MS 10 /* 10ms */ +#define CIG_SDU_INTERVAL_US 10000 /* 10ms */ +#define CIG_SCA ESP_BLE_ISO_SCA_UNKNOWN +#define CIG_PACKING 0 /* 0 - sequential, 1 - interleaved */ +#define CIG_FRAMING 0 /* 0 - unframed, 1 - framed */ +#define CIS_PHY ESP_BLE_ISO_PHY_2M +#define CIS_RTN 2 +#define CIS_SDU_SIZE 120 + +static bool acl_connected; + +static uint16_t iso_seq_num; +static uint8_t iso_data[CIS_SDU_SIZE]; + +static esp_ble_iso_cig_t *out_cig; + +static example_iso_tx_scheduler_t tx_scheduler; + +static void iso_chan_send(void); + +static void iso_connected_cb(esp_ble_iso_chan_t *chan) +{ + const esp_ble_iso_chan_path_t data_path = { + .pid = ESP_BLE_ISO_DATA_PATH_HCI, + .format = ESP_BLE_ISO_CODING_FORMAT_TRANSPARENT, + }; + esp_err_t err; + + ESP_LOGI(TAG, "ISO channel %p connected", chan); + + err = esp_ble_iso_setup_data_path(chan, ESP_BLE_ISO_DATA_PATH_DIR_INPUT, &data_path); + if (err) { + ESP_LOGE(TAG, "Failed to setup ISO data path, err %d", err); + return; + } + + iso_seq_num = 0; + example_iso_tx_scheduler_reset(&tx_scheduler); + + /* Note: esp timer is not accurate enough */ + err = example_iso_tx_scheduler_start(&tx_scheduler, CIG_SDU_INTERVAL_US); + if (err) { + ESP_LOGE(TAG, "Failed to start tx scheduler, err %d", err); + return; + } + + iso_chan_send(); +} + +static void iso_disconnected_cb(esp_ble_iso_chan_t *chan, uint8_t reason) +{ + esp_err_t err; + + ESP_LOGI(TAG, "ISO channel %p disconnected, reason 0x%02x", chan, reason); + + err = example_iso_tx_scheduler_stop(&tx_scheduler); + if (err) { + ESP_LOGE(TAG, "Failed to stop tx scheduler, err %d", err); + } +} + +static void iso_sent_cb(esp_ble_iso_chan_t *chan, void *user_data) +{ + example_iso_tx_scheduler_on_sent(&tx_scheduler, user_data, TAG, "chan", chan); +} + +static esp_ble_iso_chan_ops_t iso_ops = { + .connected = iso_connected_cb, + .disconnected = iso_disconnected_cb, + .sent = iso_sent_cb, +}; + +static esp_ble_iso_chan_io_qos_t iso_tx_qos = { + .sdu = CIS_SDU_SIZE, + .phy = CIS_PHY, + .rtn = CIS_RTN, +}; + +static esp_ble_iso_chan_qos_t iso_qos = { + .tx = &iso_tx_qos, + .rx = NULL, +}; + +static esp_ble_iso_chan_t iso_chan = { + .ops = &iso_ops, + .qos = &iso_qos, + .required_sec_level = SECURITY_LEVEL, +}; + +static void create_cig_and_cis(uint16_t acl_handle) +{ + esp_ble_iso_connect_param_t connect_param = {0}; + esp_ble_iso_cig_param_t cig_param = {0}; + esp_ble_iso_chan_t *channels[1] = {0}; + int err; + + if (out_cig) { + goto connect; + } + + channels[0] = &iso_chan; + + cig_param.cis_channels = channels; + cig_param.num_cis = ARRAY_SIZE(channels); + cig_param.sca = CIG_SCA; + cig_param.packing = CIG_PACKING; + cig_param.framing = CIG_FRAMING; + cig_param.c_to_p_latency = CIG_LATENCY_MS; + cig_param.p_to_c_latency = CIG_LATENCY_MS; + cig_param.c_to_p_interval = CIG_SDU_INTERVAL_US; + cig_param.p_to_c_interval = CIG_SDU_INTERVAL_US; + + err = esp_ble_iso_cig_create(&cig_param, &out_cig); + if (err) { + ESP_LOGE(TAG, "Failed to create CIG, err %d", err); + return; + } + +connect: + connect_param.iso_chan = &iso_chan; + + err = esp_ble_iso_chan_connect(&connect_param, acl_handle, 1); + if (err) { + ESP_LOGE(TAG, "Failed to create CIS, err %d", err); + return; + } +} + +static void iso_chan_send(void) +{ + int err; + + memset(iso_data, (uint8_t)iso_seq_num, sizeof(iso_data)); + + err = esp_ble_iso_chan_send(&iso_chan, + iso_data, + sizeof(iso_data), + iso_seq_num); + if (err) { + ESP_LOGD(TAG, "Failed to transmit data on channel %p", &iso_chan); + return; + } + + iso_seq_num++; +} + +static void tx_scheduler_cb(void *arg) +{ + (void)arg; + iso_chan_send(); +} + +static void ext_scan_start(void) +{ + struct ble_gap_disc_params params = {0}; + uint8_t own_addr_type; + int err; + + err = ble_hs_id_infer_auto(0, &own_addr_type); + if (err) { + ESP_LOGE(TAG, "Failed to determine address type, err %d", err); + return; + } + + params.passive = 1; + params.itvl = SCAN_INTERVAL; + params.window = SCAN_WINDOW; + + err = ble_gap_disc(own_addr_type, BLE_HS_FOREVER, ¶ms, + example_iso_gap_event_cb, NULL); + if (err) { + ESP_LOGE(TAG, "Failed to start scanning, err %d", err); + return; + } + + ESP_LOGI(TAG, "Extended scan started"); +} + +static int conn_create(uint8_t addr_type, uint8_t addr[6]) +{ + struct ble_gap_conn_params params = {0}; + uint8_t own_addr_type = 0; + ble_addr_t dst = {0}; + int err; + + err = ble_gap_disc_cancel(); + if (err) { + ESP_LOGE(TAG, "Failed to stop scanning, err %d", err); + return err; + } + + err = ble_hs_id_infer_auto(0, &own_addr_type); + if (err) { + ESP_LOGE(TAG, "Failed to determine address type, err %d", err); + return err; + } + + params.scan_itvl = INIT_SCAN_INTERVAL; + params.scan_window = INIT_SCAN_WINDOW; + params.itvl_min = CONN_INTERVAL; + params.itvl_max = CONN_INTERVAL; + params.latency = CONN_LATENCY; + params.supervision_timeout = CONN_TIMEOUT; + params.max_ce_len = CONN_MAX_CE_LEN; + params.min_ce_len = CONN_MIN_CE_LEN; + + dst.type = addr_type; + memcpy(dst.val, addr, sizeof(dst.val)); + + return ble_gap_connect(own_addr_type, &dst, CONN_DURATION, ¶ms, + example_iso_gap_event_cb, NULL); +} + +static int pairing_start(uint16_t conn_handle) +{ + return ble_gap_security_initiate(conn_handle); +} + +static bool data_cb(uint8_t type, const uint8_t *data, + uint8_t data_len, void *user_data) +{ + bool *target_matched = user_data; + + assert(target_matched); + + switch (type) { + case EXAMPLE_AD_TYPE_NAME_COMPLETE: + *target_matched = (data_len == TARGET_DEVICE_NAME_LEN) && + !memcmp(data, TARGET_DEVICE_NAME, TARGET_DEVICE_NAME_LEN); + return false; + default: + return true; + } +} + +static void ext_scan_recv(esp_ble_iso_gap_app_event_t *event) +{ + bool target_matched = false; + int err; + + esp_ble_iso_data_parse(event->ext_scan_recv.data, + event->ext_scan_recv.data_len, + data_cb, &target_matched); + + /* Skip if target not found or ACL already connected */ + if (!target_matched || acl_connected) { + return; + } + + err = conn_create(event->ext_scan_recv.addr.type, event->ext_scan_recv.addr.val); + if (err) { + ESP_LOGE(TAG, "Failed to create connection, err %d", err); + return; + } + + acl_connected = true; +} + +static void acl_connect(esp_ble_iso_gap_app_event_t *event) +{ + int err; + + if (event->acl_connect.status) { + ESP_LOGE(TAG, "connection failed, status %d", event->acl_connect.status); + acl_connected = false; + return; + } + + ESP_LOGI(TAG, "Conn established:"); + ESP_LOGI(TAG, "conn_handle 0x%04x status 0x%02x role %u peer %02x:%02x:%02x:%02x:%02x:%02x", + event->acl_connect.conn_handle, event->acl_connect.status, + event->acl_connect.role, event->acl_connect.dst.val[5], + event->acl_connect.dst.val[4], event->acl_connect.dst.val[3], + event->acl_connect.dst.val[2], event->acl_connect.dst.val[1], + event->acl_connect.dst.val[0]); + + if (iso_chan.required_sec_level == ESP_BLE_ISO_SECURITY_NO_MITM || + iso_chan.required_sec_level == ESP_BLE_ISO_SECURITY_MITM) { + err = pairing_start(event->acl_connect.conn_handle); + if (err) { + ESP_LOGE(TAG, "Failed to initiate security, err %d", err); + } + return; + } + + create_cig_and_cis(event->acl_connect.conn_handle); +} + +static void acl_disconnect(esp_ble_iso_gap_app_event_t *event) +{ + ESP_LOGI(TAG, "Conn terminated: conn_handle 0x%04x reason 0x%02x", + event->acl_disconnect.conn_handle, event->acl_disconnect.reason); + + acl_connected = false; + + ext_scan_start(); +} + +static void security_change(esp_ble_iso_gap_app_event_t *event) +{ + if (event->security_change.status) { + ESP_LOGE(TAG, "security change failed, status %d", event->security_change.status); + return; + } + + ESP_LOGI(TAG, "Security change:"); + ESP_LOGI(TAG, "conn_handle 0x%04x status 0x%02x role %u sec_level %u bonded %u " + "peer %02x:%02x:%02x:%02x:%02x:%02x", + event->security_change.conn_handle, event->security_change.status, + event->security_change.role, event->security_change.sec_level, + event->security_change.bonded, event->security_change.dst.val[5], + event->security_change.dst.val[4], event->security_change.dst.val[3], + event->security_change.dst.val[2], event->security_change.dst.val[1], + event->security_change.dst.val[0]); + + create_cig_and_cis(event->security_change.conn_handle); +} + +static void iso_gap_app_cb(esp_ble_iso_gap_app_event_t *event) +{ + switch (event->type) { + case ESP_BLE_ISO_GAP_EVENT_EXT_SCAN_RECV: + ext_scan_recv(event); + break; + case ESP_BLE_ISO_GAP_EVENT_ACL_CONNECT: + acl_connect(event); + break; + case ESP_BLE_ISO_GAP_EVENT_ACL_DISCONNECT: + acl_disconnect(event); + break; + case ESP_BLE_ISO_GAP_EVENT_SECURITY_CHANGE: + security_change(event); + break; + default: + break; + } +} + +void app_main(void) +{ + esp_ble_iso_init_info_t info = { + .gap_cb = iso_gap_app_cb, + }; + esp_err_t err; + + /* Initialize NVS — it is used to store PHY calibration data */ + err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK(err); + + err = bluetooth_init(); + if (err) { + ESP_LOGE(TAG, "Failed to initialize BLE, err %d", err); + return; + } + + err = esp_ble_iso_common_init(&info); + if (err) { + ESP_LOGE(TAG, "Failed to initialize ISO, err %d", err); + return; + } + + err = ble_svc_gap_device_name_set(LOCAL_DEVICE_NAME); + if (err) { + ESP_LOGE(TAG, "Failed to set device name, err %d", err); + return; + } + + err = example_iso_tx_scheduler_init(&tx_scheduler, + tx_scheduler_cb, + NULL); + if (err) { + ESP_LOGE(TAG, "Failed to init tx scheduler, err %d", err); + return; + } + + ext_scan_start(); +} diff --git a/examples/bluetooth/esp_ble_iso/cis_central/sdkconfig.defaults b/examples/bluetooth/esp_ble_iso/cis_central/sdkconfig.defaults new file mode 100644 index 0000000000..aa6d8e1bb0 --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/cis_central/sdkconfig.defaults @@ -0,0 +1,15 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration +# + +CONFIG_BT_ENABLED=y +CONFIG_BT_BLUEDROID_ENABLED=n +CONFIG_BT_NIMBLE_ENABLED=y +CONFIG_BT_NIMBLE_EXT_ADV=y +CONFIG_BT_NIMBLE_MAX_CONNECTIONS=1 +CONFIG_BT_NIMBLE_ISO=y +CONFIG_BT_NIMBLE_LOG_LEVEL_WARNING=y + +CONFIG_BT_ISO_CENTRAL=y + +CONFIG_FREERTOS_HZ=1000 diff --git a/examples/bluetooth/esp_ble_iso/cis_central/sdkconfig.defaults.esp32h4 b/examples/bluetooth/esp_ble_iso/cis_central/sdkconfig.defaults.esp32h4 new file mode 100644 index 0000000000..5920ce3f85 --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/cis_central/sdkconfig.defaults.esp32h4 @@ -0,0 +1,6 @@ +# Override some defaults so BT stack is enabled +# by default in this example + +CONFIG_IDF_TARGET="esp32h4" + +CONFIG_BT_LE_ISO_SUPPORT=y diff --git a/examples/bluetooth/esp_ble_iso/cis_peripheral/CMakeLists.txt b/examples/bluetooth/esp_ble_iso/cis_peripheral/CMakeLists.txt new file mode 100644 index 0000000000..ad36de7d19 --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/cis_peripheral/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.22) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +idf_build_set_property(MINIMAL_BUILD ON) +project(cis_peripheral) diff --git a/examples/bluetooth/esp_ble_iso/cis_peripheral/README.md b/examples/bluetooth/esp_ble_iso/cis_peripheral/README.md new file mode 100644 index 0000000000..880ef4c663 --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/cis_peripheral/README.md @@ -0,0 +1,56 @@ +| Supported Targets | ESP32-H4 | +| ----------------- | -------- | + +# BLE CIS Peripheral Example + +(See the README.md file in the upper level `examples` directory for more information about examples.) + +This example demonstrates how to use a **Connected Isochronous Stream (CIS)** as a peripheral. It starts connectable extended advertising with the name `CIS Peripheral`, waits for a central to connect and set up an isochronous channel, and then receives and counts isochronous data on the CIS. Run it together with the [cis_central](../cis_central) example on another device as the central. + +The implementation uses the NimBLE host stack with ISO support and the ESP-BLE-ISO APIs (ISO server register, accept callback, data path, channel receive). It is intended for chips that support BLE 5.2 ISO (e.g. ESP32-H4). The connection security level is hardcoded as `ESP_BLE_ISO_SECURITY_MITM` (Level 3: encryption and authentication); it must match the [cis_central](../cis_central) side for pairing to succeed. + +## Requirements + +* A board with Bluetooth LE 5.2 and ISO support (e.g. ESP32-H4) +* Another device running the [cis_central](../cis_central) example, which scans, connects, and creates the CIS + +## How to Use Example + +Before project configuration and build, set the correct chip target: + +```bash +idf.py set-target esp32h4 +``` + +### Build and Flash + +Run the following to build, flash and monitor: + +```bash +idf.py -p PORT flash monitor +``` + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the [Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF. + +## Example Flow + +1. **Initialization**: NVS, Bluetooth stack (NimBLE), and ISO common layer (`esp_ble_iso_common_init`) with GAP callback for ACL and security events. +2. **ISO server**: Register an ISO server with an accept callback and the configured security level. When a central requests a CIS, the accept callback returns the single CIS channel. +3. **Extended advertising**: Start connectable extended advertising with the local name `CIS Peripheral` so the central can discover and connect. +4. **ACL connection**: When the central connects, the connection and optional pairing/security change are handled; the central then creates the CIG and CIS. +5. **CIS connected**: When the CIS is connected, set up the output data path (receive direction). Incoming ISO SDUs are delivered in the receive callback; the example counts valid, error, and lost packets and logs periodically. + +## Example Output + +``` +I (xxx) CIS_PER: Extended adv instance 0 started +I (xxx) CIS_PER: connection established, handle 0 status 0x00 +I (xxx) CIS_PER: Incoming request from 0x0000 +I (xxx) CIS_PER: ISO channel 0x... connected +I (xxx) CIS_PER: Received 1000(1000/0/0) ISO data packets (chan 0x...) +... +``` + +If connection or security fails, relevant status or error messages are logged. diff --git a/examples/bluetooth/esp_ble_iso/cis_peripheral/main/CMakeLists.txt b/examples/bluetooth/esp_ble_iso/cis_peripheral/main/CMakeLists.txt new file mode 100644 index 0000000000..721967052c --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/cis_peripheral/main/CMakeLists.txt @@ -0,0 +1,4 @@ +set(srcs "main.c") + +idf_component_register(SRCS "${srcs}" + REQUIRES bt nvs_flash) diff --git a/examples/bluetooth/esp_ble_iso/cis_peripheral/main/idf_component.yml b/examples/bluetooth/esp_ble_iso/cis_peripheral/main/idf_component.yml new file mode 100644 index 0000000000..fff7f2843b --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/cis_peripheral/main/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + example_init: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_iso/common_components/example_init + example_utils: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_iso/common_components/example_utils diff --git a/examples/bluetooth/esp_ble_iso/cis_peripheral/main/main.c b/examples/bluetooth/esp_ble_iso/cis_peripheral/main/main.c new file mode 100644 index 0000000000..173f38de0f --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/cis_peripheral/main/main.c @@ -0,0 +1,272 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include "esp_log.h" +#include "nvs_flash.h" +#include "esp_system.h" + +#include "host/ble_gap.h" +#include "services/gap/ble_svc_gap.h" + +#include "esp_ble_iso_common_api.h" + +#include "ble_iso_example_init.h" +#include "ble_iso_example_utils.h" + +#define TAG "CIS_PER" + +#define LOCAL_DEVICE_NAME "CIS Peripheral" +#define LOCAL_DEVICE_NAME_LEN (sizeof(LOCAL_DEVICE_NAME) - 1) + +#define ADV_HANDLE 0 +#define ADV_SID 0 +#define ADV_TX_POWER 127 +#define ADV_ADDRESS BLE_OWN_ADDR_PUBLIC +#define ADV_PRIMARY_PHY BLE_HCI_LE_PHY_1M +#define ADV_SECONDARY_PHY BLE_HCI_LE_PHY_2M +#define ADV_INTERVAL BLE_GAP_ADV_ITVL_MS(200) + +#define SECURITY_LEVEL ESP_BLE_ISO_SECURITY_MITM + +#define CIS_SDU_SIZE 120 + +static uint8_t ext_adv_data[3 + 2 + LOCAL_DEVICE_NAME_LEN]; + +static example_iso_rx_metrics_t rx_metrics; + +static void iso_connected_cb(esp_ble_iso_chan_t *chan) +{ + const esp_ble_iso_chan_path_t data_path = { + .pid = ESP_BLE_ISO_DATA_PATH_HCI, + .format = ESP_BLE_ISO_CODING_FORMAT_TRANSPARENT, + }; + esp_err_t err; + + ESP_LOGI(TAG, "ISO channel %p connected", chan); + + err = esp_ble_iso_setup_data_path(chan, ESP_BLE_ISO_DATA_PATH_DIR_OUTPUT, &data_path); + if (err) { + ESP_LOGE(TAG, "Failed to setup ISO data path, err %d", err); + return; + } + + example_iso_rx_metrics_reset(&rx_metrics); +} + +static void iso_disconnected_cb(esp_ble_iso_chan_t *chan, uint8_t reason) +{ + ESP_LOGI(TAG, "ISO channel %p disconnected, reason 0x%02x", chan, reason); +} + +static void iso_recv_cb(esp_ble_iso_chan_t *chan, + const esp_ble_iso_recv_info_t *info, + const uint8_t *data, uint16_t len) +{ + + rx_metrics.last_sdu_len = len; + example_iso_rx_metrics_on_recv(info, &rx_metrics, TAG, "chan", chan); +} + +static esp_ble_iso_chan_ops_t iso_ops = { + .connected = iso_connected_cb, + .disconnected = iso_disconnected_cb, + .recv = iso_recv_cb, +}; + +static esp_ble_iso_chan_io_qos_t iso_rx = { + .sdu = CIS_SDU_SIZE, +}; + +static esp_ble_iso_chan_qos_t iso_qos = { + .rx = &iso_rx, + .tx = NULL, +}; + +static esp_ble_iso_chan_t iso_chan = { + .ops = &iso_ops, + .qos = &iso_qos, +}; + +static int iso_accept(const esp_ble_iso_accept_info_t *info, + esp_ble_iso_chan_t **chan) +{ + ESP_LOGI(TAG, "Incoming request from 0x%04x", info->acl->handle); + + if (iso_chan.iso) { + ESP_LOGE(TAG, "No channels available"); + return -ENOMEM; + } + + *chan = &iso_chan; + + return 0; +} + +static esp_ble_iso_server_t iso_server = { + .sec_level = SECURITY_LEVEL, + .accept = iso_accept, +}; + +static void build_adv_data(void) +{ + ext_adv_data[0] = 0x02; + ext_adv_data[1] = EXAMPLE_AD_TYPE_FLAGS; + ext_adv_data[2] = EXAMPLE_AD_FLAGS_GENERAL | EXAMPLE_AD_FLAGS_NO_BREDR; + ext_adv_data[3] = (uint8_t)(LOCAL_DEVICE_NAME_LEN + 1); + ext_adv_data[4] = EXAMPLE_AD_TYPE_NAME_COMPLETE; + memcpy(&ext_adv_data[5], LOCAL_DEVICE_NAME, LOCAL_DEVICE_NAME_LEN); +} + +static void ext_adv_start(void) +{ + struct ble_gap_ext_adv_params ext_params = {0}; + struct os_mbuf *data = NULL; + int err; + + build_adv_data(); + + ext_params.connectable = 1; + ext_params.scannable = 0; + ext_params.legacy_pdu = 0; + ext_params.own_addr_type = ADV_ADDRESS; + ext_params.primary_phy = ADV_PRIMARY_PHY; + ext_params.secondary_phy = ADV_SECONDARY_PHY; + ext_params.tx_power = ADV_TX_POWER; + ext_params.sid = ADV_SID; + ext_params.itvl_min = ADV_INTERVAL; + ext_params.itvl_max = ADV_INTERVAL; + + err = ble_gap_ext_adv_configure(ADV_HANDLE, &ext_params, NULL, + example_iso_gap_event_cb, NULL); + if (err) { + ESP_LOGE(TAG, "Failed to configure ext adv params, err %d", err); + return; + } + + data = os_msys_get_pkthdr(sizeof(ext_adv_data), 0); + if (data == NULL) { + ESP_LOGE(TAG, "Failed to get ext adv mbuf"); + return; + } + + err = os_mbuf_append(data, ext_adv_data, sizeof(ext_adv_data)); + if (err) { + ESP_LOGE(TAG, "Failed to append ext adv data, err %d", err); + os_mbuf_free_chain(data); + return; + } + + err = ble_gap_ext_adv_set_data(ADV_HANDLE, data); + if (err) { + ESP_LOGE(TAG, "Failed to set ext adv data, err %d", err); + return; + } + + err = ble_gap_ext_adv_start(ADV_HANDLE, 0, 0); + if (err) { + ESP_LOGE(TAG, "Failed to start ext advertising, err %d", err); + return; + } + + ESP_LOGI(TAG, "Extended adv instance %u started", ADV_HANDLE); +} + +static void acl_connect(esp_ble_iso_gap_app_event_t *event) +{ + ESP_LOGI(TAG, "Conn established:"); + ESP_LOGI(TAG, "conn_handle 0x%04x status 0x%02x role %u peer %02x:%02x:%02x:%02x:%02x:%02x", + event->acl_connect.conn_handle, event->acl_connect.status, + event->acl_connect.role, event->acl_connect.dst.val[5], + event->acl_connect.dst.val[4], event->acl_connect.dst.val[3], + event->acl_connect.dst.val[2], event->acl_connect.dst.val[1], + event->acl_connect.dst.val[0]); +} + +static void acl_disconnect(esp_ble_iso_gap_app_event_t *event) +{ + ESP_LOGI(TAG, "Conn terminated: conn_handle 0x%04x reason 0x%02x", + event->acl_disconnect.conn_handle, event->acl_disconnect.reason); + + ext_adv_start(); +} + +static void security_change(esp_ble_iso_gap_app_event_t *event) +{ + ESP_LOGI(TAG, "Security change:"); + ESP_LOGI(TAG, "conn_handle 0x%04x status 0x%02x role %u sec_level %u bonded %u " + "peer %02x:%02x:%02x:%02x:%02x:%02x", + event->security_change.conn_handle, event->security_change.status, + event->security_change.role, event->security_change.sec_level, + event->security_change.bonded, event->security_change.dst.val[5], + event->security_change.dst.val[4], event->security_change.dst.val[3], + event->security_change.dst.val[2], event->security_change.dst.val[1], + event->security_change.dst.val[0]); +} + +static void iso_gap_app_cb(esp_ble_iso_gap_app_event_t *event) +{ + switch (event->type) { + case ESP_BLE_ISO_GAP_EVENT_ACL_CONNECT: + acl_connect(event); + break; + case ESP_BLE_ISO_GAP_EVENT_ACL_DISCONNECT: + acl_disconnect(event); + break; + case ESP_BLE_ISO_GAP_EVENT_SECURITY_CHANGE: + security_change(event); + break; + default: + break; + } +} + +void app_main(void) +{ + esp_ble_iso_init_info_t info = { + .gap_cb = iso_gap_app_cb, + }; + esp_err_t err; + + /* Initialize NVS — it is used to store PHY calibration data */ + err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK(err); + + err = bluetooth_init(); + if (err) { + ESP_LOGE(TAG, "Failed to initialize BLE, err %d", err); + return; + } + + err = esp_ble_iso_common_init(&info); + if (err) { + ESP_LOGE(TAG, "Failed to initialize ISO, err %d", err); + return; + } + + err = esp_ble_iso_server_register(&iso_server); + if (err) { + ESP_LOGE(TAG, "Failed to register ISO server, err %d", err); + return; + } + + err = ble_svc_gap_device_name_set(LOCAL_DEVICE_NAME); + if (err) { + ESP_LOGE(TAG, "Failed to set device name, err %d", err); + return; + } + + ext_adv_start(); +} diff --git a/examples/bluetooth/esp_ble_iso/cis_peripheral/sdkconfig.defaults b/examples/bluetooth/esp_ble_iso/cis_peripheral/sdkconfig.defaults new file mode 100644 index 0000000000..36afc5e930 --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/cis_peripheral/sdkconfig.defaults @@ -0,0 +1,15 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration +# + +CONFIG_BT_ENABLED=y +CONFIG_BT_BLUEDROID_ENABLED=n +CONFIG_BT_NIMBLE_ENABLED=y +CONFIG_BT_NIMBLE_EXT_ADV=y +CONFIG_BT_NIMBLE_MAX_CONNECTIONS=1 +CONFIG_BT_NIMBLE_ISO=y +CONFIG_BT_NIMBLE_LOG_LEVEL_WARNING=y + +CONFIG_BT_ISO_PERIPHERAL=y + +CONFIG_FREERTOS_HZ=1000 diff --git a/examples/bluetooth/esp_ble_iso/cis_peripheral/sdkconfig.defaults.esp32h4 b/examples/bluetooth/esp_ble_iso/cis_peripheral/sdkconfig.defaults.esp32h4 new file mode 100644 index 0000000000..5920ce3f85 --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/cis_peripheral/sdkconfig.defaults.esp32h4 @@ -0,0 +1,6 @@ +# Override some defaults so BT stack is enabled +# by default in this example + +CONFIG_IDF_TARGET="esp32h4" + +CONFIG_BT_LE_ISO_SUPPORT=y diff --git a/examples/bluetooth/esp_ble_iso/common_components/example_init/CMakeLists.txt b/examples/bluetooth/esp_ble_iso/common_components/example_init/CMakeLists.txt new file mode 100644 index 0000000000..6797268444 --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/common_components/example_init/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "ble_iso_example_init.c" + INCLUDE_DIRS "." + REQUIRES bt) diff --git a/examples/bluetooth/esp_ble_iso/common_components/example_init/ble_iso_example_init.c b/examples/bluetooth/esp_ble_iso/common_components/example_init/ble_iso_example_init.c new file mode 100644 index 0000000000..5a81fce8d8 --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/common_components/example_init/ble_iso_example_init.c @@ -0,0 +1,95 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "esp_log.h" +#include "sdkconfig.h" + +#include "nimble/nimble_port.h" +#include "nimble/nimble_port_freertos.h" + +#include "host/ble_hs.h" +#include "host/ble_gap.h" +#include "host/ble_gatt.h" +#include "host/util/util.h" + +#include "services/gap/ble_svc_gap.h" +#include "services/gatt/ble_svc_gatt.h" + +#define TAG "INIT" + +static SemaphoreHandle_t example_iso_sem; + +void ble_store_config_init(void); + +static void example_iso_on_reset(int reason) +{ + ESP_LOGI(TAG, "Resetting state; reason=%d", reason); +} + +static void example_iso_on_sync(void) +{ + int rc; + + rc = ble_hs_util_ensure_addr(0); + assert(rc == 0); + + xSemaphoreGive(example_iso_sem); +} + +static void example_iso_host_task(void *param) +{ + ESP_LOGI(TAG, "BLE Host Task Started"); + + /* This function will return only when nimble_port_stop() is executed */ + nimble_port_run(); + + nimble_port_freertos_deinit(); +} + +esp_err_t bluetooth_init(void) +{ + esp_err_t ret; + + example_iso_sem = xSemaphoreCreateBinary(); + if (example_iso_sem == NULL) { + ESP_LOGE(TAG, "Failed to create iso semaphore"); + return ESP_FAIL; + } + + ret = nimble_port_init(); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to init nimble %d ", ret); + vSemaphoreDelete(example_iso_sem); + example_iso_sem = NULL; + return ret; + } + + /* Initialize the NimBLE host configuration */ + ble_hs_cfg.reset_cb = example_iso_on_reset; + ble_hs_cfg.sync_cb = example_iso_on_sync; + ble_hs_cfg.store_status_cb = ble_store_util_status_rr; +#if 0 + ble_hs_cfg.gatts_register_cb = NULL; + ble_hs_cfg.sm_our_key_dist = 1; + ble_hs_cfg.sm_their_key_dist = 1; + ble_hs_cfg.sm_sc = 1; + ble_hs_cfg.sm_mitm = 0; + ble_hs_cfg.sm_bonding = 1; + ble_hs_cfg.sm_io_cap = BLE_SM_IO_CAP_NO_IO; +#endif + + /* XXX Need to have template for store */ + ble_store_config_init(); + + nimble_port_freertos_init(example_iso_host_task); + + xSemaphoreTake(example_iso_sem, portMAX_DELAY); + + return ESP_OK; +} diff --git a/examples/bluetooth/esp_ble_iso/common_components/example_init/ble_iso_example_init.h b/examples/bluetooth/esp_ble_iso/common_components/example_init/ble_iso_example_init.h new file mode 100644 index 0000000000..340ee3330a --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/common_components/example_init/ble_iso_example_init.h @@ -0,0 +1,14 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef BLE_ISO_EXAMPLE_INIT_H_ +#define BLE_ISO_EXAMPLE_INIT_H_ + +#include "esp_err.h" + +esp_err_t bluetooth_init(void); + +#endif /* BLE_ISO_EXAMPLE_INIT_H_ */ diff --git a/examples/bluetooth/esp_ble_iso/common_components/example_utils/CMakeLists.txt b/examples/bluetooth/esp_ble_iso/common_components/example_utils/CMakeLists.txt new file mode 100644 index 0000000000..1c502745ca --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/common_components/example_utils/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "ble_iso_example_utils.c" + INCLUDE_DIRS "." + REQUIRES bt esp_timer freertos) diff --git a/examples/bluetooth/esp_ble_iso/common_components/example_utils/ble_iso_example_utils.c b/examples/bluetooth/esp_ble_iso/common_components/example_utils/ble_iso_example_utils.c new file mode 100644 index 0000000000..ecc8369a4a --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/common_components/example_utils/ble_iso_example_utils.c @@ -0,0 +1,162 @@ +/* + * SPDX-FileCopyrightText: 2017-2021 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2015-2016 Intel Corporation + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include "esp_log.h" + +#include "ble_iso_example_utils.h" + +#include "esp_ble_iso_common_api.h" + +#define TAG "UTILS" + +int example_iso_gap_event_cb(struct ble_gap_event *event, void *arg) +{ + if (event->type == BLE_GAP_EVENT_EXT_DISC || + event->type == BLE_GAP_EVENT_PERIODIC_SYNC || + event->type == BLE_GAP_EVENT_PERIODIC_REPORT || + event->type == BLE_GAP_EVENT_PERIODIC_SYNC_LOST || + event->type == BLE_GAP_EVENT_CONNECT || + event->type == BLE_GAP_EVENT_DISCONNECT || + event->type == BLE_GAP_EVENT_ENC_CHANGE) { + esp_ble_iso_gap_app_post_event(event->type, event); + } + + return 0; +} + +static void example_iso_tx_work_handler(struct k_work *work) +{ + example_iso_tx_scheduler_t *scheduler = work->user_data; + size_t count; + + assert(scheduler); + assert(scheduler->cb); + + count = 1 + scheduler->drift; + scheduler->drift = 0; + + for (size_t i = 0; i < count; i++) { + scheduler->cb(scheduler->arg); + } +} + +int example_iso_tx_scheduler_init(example_iso_tx_scheduler_t *scheduler, + example_iso_tx_send_cb_t cb, + void *arg) +{ + assert(scheduler); + assert(cb); + + memset(scheduler, 0, sizeof(*scheduler)); + scheduler->cb = cb; + scheduler->arg = arg; + + k_work_init_delayable(&scheduler->timer, example_iso_tx_work_handler); + scheduler->timer.work.user_data = scheduler; + + return 0; +} + +void example_iso_tx_scheduler_reset(example_iso_tx_scheduler_t *scheduler) +{ + assert(scheduler); + + scheduler->drift = 0; + scheduler->count = 0; +} + +int example_iso_tx_scheduler_start(example_iso_tx_scheduler_t *scheduler, + uint64_t period_us) +{ + assert(scheduler); + assert(period_us > 0); + + return k_work_schedule_periodic(&scheduler->timer, (uint32_t)(period_us / 1000)); +} + +int example_iso_tx_scheduler_stop(example_iso_tx_scheduler_t *scheduler) +{ + assert(scheduler); + + return k_work_cancel_delayable(&scheduler->timer); +} + +void example_iso_tx_scheduler_on_sent(example_iso_tx_scheduler_t *scheduler, + const esp_ble_iso_tx_cb_info_t *info, + const char *tag, + const char *obj_name, + const void *obj) +{ + size_t drift_count = 0; + + assert(scheduler); + assert(info); + + for (size_t i = 0; i < info->pkt_cnt; i++) { + if (info->pkt[i].drift) { + drift_count++; + } + } + + scheduler->drift += drift_count; + scheduler->count++; + + if (scheduler->count % 1000 == 0) { + ESP_LOGI(tag, "Transmitted %u ISO data packets (%s %p)", + scheduler->count, (obj_name ? obj_name : ""), obj); + } +} + +void example_iso_rx_metrics_reset(example_iso_rx_metrics_t *metrics) +{ + assert(metrics); + + metrics->recv_count = 0; + metrics->valid_count = 0; + metrics->error_count = 0; + metrics->lost_count = 0; + metrics->null_sdu_count = 0; + metrics->last_sdu_len = 0; +} + +void example_iso_rx_metrics_on_recv(const esp_ble_iso_recv_info_t *info, + example_iso_rx_metrics_t *metrics, + const char *tag, + const char *obj_name, + const void *obj) +{ + assert(info); + assert(metrics); + + if (info->flags & ESP_BLE_ISO_FLAGS_ERROR) { + metrics->error_count++; + } + + if (info->flags & ESP_BLE_ISO_FLAGS_LOST) { + metrics->lost_count++; + } + + if (info->flags & ESP_BLE_ISO_FLAGS_VALID) { + metrics->valid_count++; + if (metrics->last_sdu_len == 0) { + metrics->null_sdu_count++; + } + } + + metrics->recv_count++; + + if (metrics->recv_count % 1000 == 0) { + ESP_LOGI(tag, "Received %u ISO data packets (%s %p)", + metrics->recv_count, (obj_name ? obj_name : ""), obj); + } +} diff --git a/examples/bluetooth/esp_ble_iso/common_components/example_utils/ble_iso_example_utils.h b/examples/bluetooth/esp_ble_iso/common_components/example_utils/ble_iso_example_utils.h new file mode 100644 index 0000000000..d62e05ab28 --- /dev/null +++ b/examples/bluetooth/esp_ble_iso/common_components/example_utils/ble_iso_example_utils.h @@ -0,0 +1,107 @@ +/* + * SPDX-FileCopyrightText: 2017-2021 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2015-2016 Intel Corporation + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef BLE_ISO_EXAMPLE_UTILS_H_ +#define BLE_ISO_EXAMPLE_UTILS_H_ + +#include +#include + +#include "sdkconfig.h" + +#include "esp_err.h" + +#include "zephyr/kernel.h" + +#include "host/ble_gap.h" +#include "host/ble_hs_adv.h" + +#include "esp_ble_iso_common_api.h" + +#define EXAMPLE_AD_TYPE_FLAGS BT_DATA_FLAGS +#define EXAMPLE_AD_TYPE_UUID16_SOME BT_DATA_UUID16_SOME +#define EXAMPLE_AD_TYPE_UUID16_ALL BT_DATA_UUID16_ALL +#define EXAMPLE_AD_TYPE_NAME_SHORTENED BT_DATA_NAME_SHORTENED +#define EXAMPLE_AD_TYPE_NAME_COMPLETE BT_DATA_NAME_COMPLETE +#define EXAMPLE_AD_TYPE_SERVICE_DATA16 BT_DATA_SVC_DATA16 +#define EXAMPLE_AD_TYPE_GAP_APPEARANCE BT_DATA_GAP_APPEARANCE +#define EXAMPLE_AD_TYPE_CSIS_RSI BT_DATA_CSIS_RSI +#define EXAMPLE_AD_TYPE_BROADCAST_NAME BT_DATA_BROADCAST_NAME + +#define EXAMPLE_AD_FLAGS_LIMITED BT_LE_AD_LIMITED +#define EXAMPLE_AD_FLAGS_GENERAL BT_LE_AD_GENERAL +#define EXAMPLE_AD_FLAGS_NO_BREDR BT_LE_AD_NO_BREDR + +#define EXAMPLE_ADV_PROP_CONNECTABLE BT_GAP_ADV_PROP_CONNECTABLE +#define EXAMPLE_ADV_PROP_SCANNABLE BT_GAP_ADV_PROP_SCANNABLE +#define EXAMPLE_ADV_PROP_DIRECTED BT_GAP_ADV_PROP_DIRECTED +#define EXAMPLE_ADV_PROP_SCAN_RESPONSE BT_GAP_ADV_PROP_SCAN_RESPONSE +#define EXAMPLE_ADV_PROP_EXT_ADV BT_GAP_ADV_PROP_EXT_ADV + +#define EXAMPLE_BYTES_LIST_LE16 BT_BYTES_LIST_LE16 +#define EXAMPLE_BYTES_LIST_LE24 BT_BYTES_LIST_LE24 +#define EXAMPLE_BYTES_LIST_LE32 BT_BYTES_LIST_LE32 +#define EXAMPLE_BYTES_LIST_LE40 BT_BYTES_LIST_LE40 +#define EXAMPLE_BYTES_LIST_LE48 BT_BYTES_LIST_LE48 +#define EXAMPLE_BYTES_LIST_LE64 BT_BYTES_LIST_LE64 + +int example_iso_gap_event_cb(struct ble_gap_event *event, void *arg); + +/** + * @brief TX scheduler for periodic ISO data transmission. + * + * Uses k_work_delayable to schedule send callbacks in the ISO task context, + * ensuring thread safety without mutexes since both the timer handler and + * BLE/ISO callbacks execute in the same task. + */ +typedef void (*example_iso_tx_send_cb_t)(void *ctx); + +typedef struct { + struct k_work_delayable timer; + size_t drift; + uint32_t count; + /* Called periodically in ISO task context to transmit data */ + example_iso_tx_send_cb_t cb; + void *arg; +} example_iso_tx_scheduler_t; + +typedef struct { + uint32_t recv_count; + uint32_t valid_count; + uint32_t error_count; + uint32_t lost_count; + uint32_t null_sdu_count; + uint16_t last_sdu_len; +} example_iso_rx_metrics_t; + +int example_iso_tx_scheduler_init(example_iso_tx_scheduler_t *scheduler, + example_iso_tx_send_cb_t cb, + void *arg); + +void example_iso_tx_scheduler_reset(example_iso_tx_scheduler_t *scheduler); + +int example_iso_tx_scheduler_start(example_iso_tx_scheduler_t *scheduler, + uint64_t period_us); + +int example_iso_tx_scheduler_stop(example_iso_tx_scheduler_t *scheduler); + +void example_iso_tx_scheduler_on_sent(example_iso_tx_scheduler_t *scheduler, + const esp_ble_iso_tx_cb_info_t *info, + const char *tag, + const char *obj_name, + const void *obj); + +void example_iso_rx_metrics_reset(example_iso_rx_metrics_t *metrics); + +void example_iso_rx_metrics_on_recv(const esp_ble_iso_recv_info_t *info, + example_iso_rx_metrics_t *metrics, + const char *tag, + const char *obj_name, + const void *obj); + +#endif /* BLE_ISO_EXAMPLE_UTILS_H_ */ diff --git a/tools/ci/astyle-rules.yml b/tools/ci/astyle-rules.yml index f2f51aa946..7282d46a6f 100644 --- a/tools/ci/astyle-rules.yml +++ b/tools/ci/astyle-rules.yml @@ -15,6 +15,7 @@ submodules: - "/components/bt/controller/lib_esp32h2/esp32h2-bt-lib/" - "/components/bt/host/nimble/nimble/" - "/components/bt/esp_ble_mesh/lib/lib/" + - "/components/bt/esp_ble_audio/lib/lib/" - "/components/cmock/CMock/" - "/components/esp_coex/lib/" - "/components/esp_phy/lib/"