APIs

AD Data Parser API {#sec:ad_parser_api}

ad_parser.h : AD Data (Advertisements and EIR) Parser

typedef struct ad_context {
     const uint8_t * data;
     uint8_t   offset;
     uint8_t   length;
} ad_context_t;

// Advertising or Scan Response data iterator
void ad_iterator_init(ad_context_t *context, uint8_t ad_len, const uint8_t * ad_data);
bool ad_iterator_has_more(const ad_context_t * context);
void ad_iterator_next(ad_context_t * context);

// Access functions
uint8_t         ad_iterator_get_data_type(const ad_context_t * context);
uint8_t         ad_iterator_get_data_len(const ad_context_t * context);
const uint8_t * ad_iterator_get_data(const ad_context_t * context);

// convenience function on complete advertisements
bool ad_data_contains_uuid16(uint8_t ad_len, const uint8_t * ad_data, uint16_t uuid16);
bool ad_data_contains_uuid128(uint8_t ad_len, const uint8_t * ad_data, const uint8_t * uuid128);

ATT Database Engine API {#sec:att_db_api}

att_db.h

// map ATT ERROR CODES on to att_read_callback length
#define ATT_READ_ERROR_CODE_OFFSET       0xfe00u

// custom BTstack ATT Response Pending for att_read_callback
#define ATT_READ_RESPONSE_PENDING                 0xffffu

// internally used to signal write response pending
#define ATT_INTERNAL_WRITE_RESPONSE_PENDING       0xfffeu

/**
 * @brief ATT Client Read Callback for Dynamic Data
 * - if buffer == NULL, don't copy data, just return size of value
 * - if buffer != NULL, copy data and return number bytes copied
 * If ENABLE_ATT_DELAYED_READ_RESPONSE is defined, you may return ATT_READ_RESPONSE_PENDING if data isn't available yet
 * @param con_handle of hci le connection
 * @param attribute_handle to be read
 * @param offset defines start of attribute value
 * @param buffer 
 * @param buffer_size
 * @return size of value if buffer is NULL, otherwise number of bytes copied
 */
typedef uint16_t (*att_read_callback_t)(hci_con_handle_t con_handle, uint16_t attribute_handle, uint16_t offset, uint8_t * buffer, uint16_t buffer_size);

/**
 * @brief ATT Client Write Callback for Dynamic Data
 * Each Prepared Write Request triggers a callback with transaction mode ATT_TRANSACTION_MODE_ACTIVE.
 * On Execute Write, the callback will be called with ATT_TRANSACTION_MODE_VALIDATE and allows to validate all queued writes and return an application error.
 * If none of the registered callbacks return an error for ATT_TRANSACTION_MODE_VALIDATE and the callback will be called with ATT_TRANSACTION_MODE_EXECUTE.
 * Otherwise, all callbacks will be called with ATT_TRANSACTION_MODE_CANCEL.
 *
 * If the additional validation step is not needed, just return 0 for all callbacks with transaction mode ATT_TRANSACTION_MODE_VALIDATE.
 *
 * @param con_handle of hci le connection
 * @param attribute_handle to be written
 * @param transaction - ATT_TRANSACTION_MODE_NONE for regular writes. For prepared writes: ATT_TRANSACTION_MODE_ACTIVE, ATT_TRANSACTION_MODE_VALIDATE, ATT_TRANSACTION_MODE_EXECUTE, ATT_TRANSACTION_MODE_CANCEL
 * @param offset into the value - used for queued writes and long attributes
 * @param buffer 
 * @param buffer_size
 * @param signature used for signed write commmands
 * @return 0 if write was ok, ATT_ERROR_PREPARE_QUEUE_FULL if no space in queue, ATT_ERROR_INVALID_OFFSET if offset is larger than max buffer
 */
typedef int (*att_write_callback_t)(hci_con_handle_t con_handle, uint16_t attribute_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size);

// Read & Write Callbacks for handle range
typedef struct att_service_handler {
    btstack_linked_item_t * item;
    att_read_callback_t read_callback;
    att_write_callback_t write_callback;
    btstack_packet_handler_t packet_handler;
    uint16_t start_handle;
    uint16_t end_handle;
    uint8_t flags;
} att_service_handler_t;

// MARK: ATT Operations

/**
 * @brief setup ATT database
 * @param db
 */
void att_set_db(uint8_t const * db);

/*
 * @brief set callback for read of dynamic attributes
 * @param callback
 */
void att_set_read_callback(att_read_callback_t callback);

/**
 * @brief set callback for write of dynamic attributes
 * @param callback
 */
void att_set_write_callback(att_write_callback_t callback);

/**
 * @brief debug helper, dump ATT database to stdout using log_info
 */
void att_dump_attributes(void);

/**
 * @brief process ATT request against database and put response into response buffer
 * @param att_connection used for mtu and security properties
 * @param request_buffer, request_len: ATT request from clinet
 * @param response_buffer for result
 * @return len of data in response buffer. 0 = no response, 
 *          ATT_READ_RESPONSE_PENDING if it was returned at least once for dynamic data (requires ENABLE_ATT_DELAYED_READ_RESPONSE)
 */
uint16_t att_handle_request(att_connection_t * att_connection,
                            uint8_t * request_buffer,
                            uint16_t request_len,
                            uint8_t * response_buffer);

/**
 * @brief setup value notification in response buffer for a given handle and value
 * @param att_connection
 * @param attribute_handle
 * @param value
 * @param value_len
 * @param response_buffer for notification
 */
uint16_t att_prepare_handle_value_notification(att_connection_t * att_connection,
                                               uint16_t attribute_handle,
                                               const uint8_t *value,
                                               uint16_t value_len, 
                                               uint8_t * response_buffer);

/**
 * @brief setup value notification in response buffer for multiple handles and values
 * @param att_connection
 * @param attribute_handle
 * @param value
 * @param value_len
 * @param response_buffer for notification
 */
uint16_t att_prepare_handle_value_multiple_notification(att_connection_t * att_connection,
                                                        uint8_t num_attributes,
                                                        const uint16_t * attribute_handles,
                                                        const uint8_t ** values_data,
                                                        const uint16_t * values_len,
                                                        uint8_t * response_buffer);

/**
 * @brief setup value indication in response buffer for a given handle and value
 * @param att_connection
 * @param attribute_handle
 * @param value
 * @param value_len
 * @param response_buffer for indication
 */
uint16_t att_prepare_handle_value_indication(att_connection_t * att_connection,
                                             uint16_t attribute_handle,
                                             const uint8_t *value,
                                             uint16_t value_len, 
                                             uint8_t * response_buffer);

/**
 * @brief transcation queue of prepared writes, e.g., after disconnect
 * @return att_connection
 */
void att_clear_transaction_queue(att_connection_t * att_connection);

// att_read_callback helpers for a various data types

/**
 * @brief Handle read of blob like data for att_read_callback
 * @param blob of data
 * @param blob_size of blob
 * @param offset from att_read_callback
 * @param buffer from att_read_callback
 * @param buffer_size from att_read_callback
 * @return value size for buffer == 0 and num bytes copied otherwise
 */
uint16_t att_read_callback_handle_blob(const uint8_t * blob, uint16_t blob_size, uint16_t offset, uint8_t * buffer, uint16_t buffer_size);

/**
 * @brief Handle read of little endian unsigned 32 bit value for att_read_callback
 * @param value
 * @param offset from att_read_callback
 * @param buffer from att_read_callback
 * @param buffer_size from att_read_callback
 * @return value size for buffer == 0 and num bytes copied otherwise
 */
uint16_t att_read_callback_handle_little_endian_32(uint32_t value, uint16_t offset, uint8_t * buffer, uint16_t buffer_size);

/**
 * @brief Handle read of little endian unsigned 16 bit value for att_read_callback
 * @param value
 * @param offset from att_read_callback
 * @param buffer from att_read_callback
 * @param buffer_size from att_read_callback
 * @return value size for buffer == 0 and num bytes copied otherwise
 */
uint16_t att_read_callback_handle_little_endian_16(uint16_t value, uint16_t offset, uint8_t * buffer, uint16_t buffer_size);

/**
 * @brief Handle read of single byte for att_read_callback
 * @param blob of data
 * @param blob_size of blob
 * @param offset from att_read_callback
 * @param buffer from att_read_callback
 * @param buffer_size from att_read_callback
 * @return value size for buffer == 0 and num bytes copied otherwise
 */
uint16_t att_read_callback_handle_byte(uint8_t value, uint16_t offset, uint8_t * buffer, uint16_t buffer_size);


// experimental client API
/**
 * @brief Get UUID for handle
 * @param attribute_handle
 * @return 0 if not found
 */
uint16_t att_uuid_for_handle(uint16_t attribute_handle);

/**
 * @brief Get const value for handle
 * @param attribute_handle
 * @param out_value_len  output variable that hold value len
 * @return value 
 */

const uint8_t * gatt_server_get_const_value_for_handle(uint16_t attribute_handle, uint16_t * out_value_len);

// experimental GATT Server API

/**
 * @brief Get handle range for primary service.
 * @param uuid16
 * @param start_handle
 * @param end_handle
 * @return false if not found
 */
bool gatt_server_get_handle_range_for_service_with_uuid16(uint16_t uuid16, uint16_t * start_handle, uint16_t * end_handle);

/**
 * @brief Get handle range for included service.
 * @param start_handle
 * @param end_handle
 * @param uuid16
 * @param out_included_service_handle
 * @param out_included_service_start_handle
 * @param out_included_service_end_handle
 * @return false if not found
 */
bool gatt_server_get_included_service_with_uuid16(uint16_t start_handle, uint16_t end_handle, uint16_t uuid16, 
    uint16_t * out_included_service_handle, uint16_t * out_included_service_start_handle, uint16_t * out_included_service_end_handle);

/**
 * @brief Get value handle for characteristic.
 * @param start_handle
 * @param end_handle
 * @param uuid16
 * @return 0 if not found
 */
uint16_t gatt_server_get_value_handle_for_characteristic_with_uuid16(uint16_t start_handle, uint16_t end_handle, uint16_t uuid16);

/**
 * @brief Get descriptor handle for characteristic.
 * @param start_handle
 * @param end_handle
 * @param characteristic_uuid16
 * @param descriptor_uuid16
 * @return 0 if not found
 */
uint16_t gatt_server_get_descriptor_handle_for_characteristic_with_uuid16(uint16_t start_handle, uint16_t end_handle, uint16_t characteristic_uuid16, uint16_t descriptor_uuid16);

/**
 * @brief Get client configuration handle for characteristic.
 * @param start_handle
 * @param end_handle
 * @param characteristic_uuid16
 * @return 0 if not found
 */
uint16_t gatt_server_get_client_configuration_handle_for_characteristic_with_uuid16(uint16_t start_handle, uint16_t end_handle, uint16_t characteristic_uuid16);

/**
 * @brief Get server configuration handle for characteristic.
 * @param start_handle
 * @param end_handle
 * @param characteristic_uuid16
 * @param descriptor_uuid16
 * @return 0 if not found
 */
uint16_t gatt_server_get_server_configuration_handle_for_characteristic_with_uuid16(uint16_t start_handle, uint16_t end_handle, uint16_t characteristic_uuid16);


/**
 * @brief Get handle range for primary service.
 * @param uuid128
 * @param start_handle
 * @param end_handle
 * @return false if not found
 */
bool gatt_server_get_handle_range_for_service_with_uuid128(const uint8_t * uuid128, uint16_t * start_handle, uint16_t * end_handle);

/**
 * @brief Get value handle.
 * @param start_handle
 * @param end_handle
 * @param uuid128
 * @return 0 if not found
 */
uint16_t gatt_server_get_value_handle_for_characteristic_with_uuid128(uint16_t start_handle, uint16_t end_handle, const uint8_t * uuid128);

/**
 * @brief Get client configuration handle.
 * @param start_handle
 * @param end_handle
 * @param uuid128
 * @return 0 if not found
 */
uint16_t gatt_server_get_client_configuration_handle_for_characteristic_with_uuid128(uint16_t start_handle, uint16_t end_handle, const uint8_t * uuid128);

Runtine ATT Database Setup API {#sec:att_db_util_api}

att_db_util.h : Helper to construct ATT DB at runtime (BTstack GATT Compiler is not used).

/**
 * @brief Init ATT DB storage
 */
void att_db_util_init(void);

/**
 * @brief Add primary service for 16-bit UUID
 * @param uuid16
 * @return attribute handle for the new service definition
 */
uint16_t att_db_util_add_service_uuid16(uint16_t uuid16);

/**
 * @brief Add primary service for 128-bit UUID
 * @param uuid128
 * @return attribute handle for the new service definition
 */
uint16_t att_db_util_add_service_uuid128(const uint8_t * uuid128);

/**
 * @brief Add secondary service for 16-bit UUID
 * @param uuid16
 * @return attribute handle for the new service definition
 */
uint16_t att_db_util_add_secondary_service_uuid16(uint16_t uuid16);

/**
 * @brief Add secondary service for 128-bit UUID
 * @param uuid128
 * @return attribute handle for the new service definition
 */
uint16_t att_db_util_add_secondary_service_uuid128(const uint8_t * uuid128);

/**
 * @brief Add included service with 16-bit UUID
 * @param start_group_handle
 * @param end_group_handle
 * @param uuid16
 * @return attribute handle for the new service definition
 */
uint16_t att_db_util_add_included_service_uuid16(uint16_t start_group_handle, uint16_t  end_group_handle, uint16_t uuid16);

/**
 * @brief Add Characteristic with 16-bit UUID, properties, and data
 * @param uuid16
 * @param properties        - see ATT_PROPERTY_* in src/bluetooth.h
 * @param read_permissions  - see ATT_SECURITY_* in src/bluetooth.h
 * @param write_permissions - see ATT_SECURITY_* in src/bluetooth.h
 * @param data returned in read operations if ATT_PROPERTY_DYNAMIC is not specified
 * @param data_len
 * @return attribute handle of the new characteristic value declaration
 * @note If properties contains ATT_PROPERTY_NOTIFY or ATT_PROPERTY_INDICATE flags, a Client Configuration Characteristic Descriptor (CCCD)
 *       is created as well. The attribute value handle of the CCCD is the attribute value handle plus 1
 */
uint16_t att_db_util_add_characteristic_uuid16(uint16_t uuid16, uint16_t properties, uint8_t read_permission, uint8_t write_permission, uint8_t * data, uint16_t data_len);

/**
 * @brief Add Characteristic with 128-bit UUID, properties, and data
 * @param uuid128
 * @param properties        - see ATT_PROPERTY_* in src/bluetooth.h
 * @param read_permissions  - see ATT_SECURITY_* in src/bluetooth.h
 * @param write_permissions - see ATT_SECURITY_* in src/bluetooth.h
 * @param data returned in read operations if ATT_PROPERTY_DYNAMIC is not specified
 * @param data_len
 * @return attribute handle of the new characteristic value declaration
 * @note If properties contains ATT_PROPERTY_NOTIFY or ATT_PROPERTY_INDICATE flags, a Client Configuration Characteristic Descriptor (CCCD)
 *       is created as well. The attribute value handle of the CCCD is the attribute value handle plus 1
 */
uint16_t att_db_util_add_characteristic_uuid128(const uint8_t * uuid128, uint16_t properties, uint8_t read_permission, uint8_t write_permission, uint8_t * data, uint16_t data_len);

/**
* @brief Add descriptor with 16-bit UUID, properties, and data
* @param uuid16
* @param properties        - see ATT_PROPERTY_* in src/bluetooth.h
* @param read_permissions  - see ATT_SECURITY_* in src/bluetooth.h
* @param write_permissions - see ATT_SECURITY_* in src/bluetooth.h
* @param data returned in read operations if ATT_PROPERTY_DYNAMIC is not specified
* @param data_len
* @return attribute handle of the new characteristic descriptor declaration
*/
uint16_t att_db_util_add_descriptor_uuid16(uint16_t uuid16, uint16_t properties, uint8_t read_permission, uint8_t write_permission, uint8_t * data, uint16_t data_len);

/**
* @brief Add descriptor with 128-bit UUID, properties, and data
* @param uuid128
* @param properties        - see ATT_PROPERTY_* in src/bluetooth.h
* @param read_permissions  - see ATT_SECURITY_* in src/bluetooth.h
* @param write_permissions - see ATT_SECURITY_* in src/bluetooth.h
* @param data returned in read operations if ATT_PROPERTY_DYNAMIC is not specified
* @param data_len
* @return attribute handle of the new characteristic descriptor declaration
*/
uint16_t att_db_util_add_descriptor_uuid128(const uint8_t * uuid128, uint16_t properties, uint8_t read_permission, uint8_t write_permission, uint8_t * data, uint16_t data_len);

/**
 * @brief Get address of constructed ATT DB
 */
uint8_t * att_db_util_get_address(void);

/**
 * @brief Get size of constructed ATT DB 
 */
uint16_t att_db_util_get_size(void);

/**
 * @brief Get number of bytes that are included in GATT Database Hash
 */
uint16_t att_db_util_hash_len(void);

/**
 * @brief init generator for GATT Database Hash
 */
void att_db_util_hash_init(void);

/**
 * @brief get next byte from generator for GATT Database Hash
 */
uint8_t att_db_util_hash_get_next(void);

/**
 * @brief Calculate GATT Database Hash using crypto engine
 * @param request
 * @param db_hash
 * @param callback
 * @param callback_arg
 */
void att_db_util_hash_calc(btstack_crypto_aes128_cmac_t * request, uint8_t * db_hash, void (* callback)(void * arg), void * callback_arg);

ATT Dispatch API {#sec:att_dispatch_api}

att_dispatch.h : Dispatcher for independent implementation of ATT client and server.

ATT Server API {#sec:att_server_api}

att_server.h

/*
 * @brief setup ATT server
 * @param db attribute database created by compile-gatt.py
 * @param read_callback, see att_db.h, can be NULL
 * @param write_callback, see attl.h, can be NULL
 */
void att_server_init(uint8_t const * db, att_read_callback_t read_callback, att_write_callback_t write_callback);

/**
 * @brief Enable support for Enhanced ATT bearer
 * @note Requires ENABLE_GATT_OVER_EATT
 * @param num_eatt_bearers
 * @param storage_buffer
 * @param storage_size
 * @return
 */
uint8_t att_server_eatt_init(uint8_t num_eatt_bearers, uint8_t * storage_buffer, uint16_t storage_size);

/*
 * @brief register packet handler for ATT server events:
 *        - ATT_EVENT_CAN_SEND_NOW
 *        - ATT_EVENT_HANDLE_VALUE_INDICATION_COMPLETE
 *        - ATT_EVENT_MTU_EXCHANGE_COMPLETE 
 * @param handler
 */
void att_server_register_packet_handler(btstack_packet_handler_t handler);

/**
 * @brief register read/write callbacks for specific handle range
 * @param att_service_handler_t
 */
void att_server_register_service_handler(att_service_handler_t * handler);

/**
 * @brief Request callback when sending is possible
 * @note callback might happend during call to this function
 * @param callback_registration to point to callback function and context information
 * @param con_handle
 * @return 0 if ok, error otherwise
 */
uint8_t att_server_register_can_send_now_callback(btstack_context_callback_registration_t * callback_registration, hci_con_handle_t con_handle);

/**
 * @brief Return ATT MTU
 * @param con_handle
 * @return mtu if ok, 0 otherwise
 */
uint16_t att_server_get_mtu(hci_con_handle_t con_handle);

/**
 * @brief Request callback when sending notifcation is possible
 * @note callback might happend during call to this function
 * @param callback_registration to point to callback function and context information
 * @param con_handle
 * @return ERROR_CODE_SUCCESS if ok, ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if handle unknown, and ERROR_CODE_COMMAND_DISALLOWED if callback already registered
 */
uint8_t att_server_request_to_send_notification(btstack_context_callback_registration_t * callback_registration, hci_con_handle_t con_handle);

/**
 * @brief Request callback when sending indication is possible
 * @note callback might happend during call to this function
 * @param callback_registration to point to callback function and context information
 * @param con_handle
 * @return ERROR_CODE_SUCCESS if ok, ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if handle unknown, and ERROR_CODE_COMMAND_DISALLOWED if callback already registered
 */
uint8_t att_server_request_to_send_indication(btstack_context_callback_registration_t * callback_registration, hci_con_handle_t con_handle);

/**
 * @brief notify client about attribute value change
 * @param con_handle
 * @param attribute_handle
 * @param value
 * @param value_len
 * @return 0 if ok, error otherwise
 */
uint8_t att_server_notify(hci_con_handle_t con_handle, uint16_t attribute_handle, const uint8_t *value, uint16_t value_len);

/**
 * @brief notify client about multiple attribute value changes
 * @param con_handle
 * @param num_attributes
 * @param attribute_handles[]
 * @param values_data[]
 * @param values_len[]
 * @return 0 if ok, error otherwise
 */
uint8_t att_server_multiple_notify(hci_con_handle_t con_handle, uint8_t num_attributes,
                                   const uint16_t * attribute_handles, const uint8_t ** values_data, const uint16_t * values_len);

/**
 * @brief indicate value change to client. client is supposed to reply with an indication_response
 * @param con_handle
 * @param attribute_handle
 * @param value
 * @param value_len
 * @return 0 if ok, error otherwise
 */
uint8_t att_server_indicate(hci_con_handle_t con_handle, uint16_t attribute_handle, const uint8_t *value, uint16_t value_len);

#ifdef ENABLE_ATT_DELAYED_RESPONSE
/**
 * @brief response ready - called after returning ATT_READ__RESPONSE_PENDING in an att_read_callback or
 * ATT_ERROR_WRITE_REQUEST_PENDING IN att_write_callback before to trigger callback again and complete the transaction
 * @nore The ATT Server will retry handling the current ATT request
 * @param con_handle
 * @return 0 if ok, error otherwise
 */
uint8_t att_server_response_ready(hci_con_handle_t con_handle);
#endif

/**
 * De-Init ATT Server 
 */
void att_server_deinit(void);

// the following functions will be removed soon

/**
 * @brief tests if a notification or indication can be send right now
 * @param con_handle
 * @return 1, if packet can be sent
 */
int  att_server_can_send_packet_now(hci_con_handle_t con_handle);

/**
 * @brief Request emission of ATT_EVENT_CAN_SEND_NOW as soon as possible
 * @note ATT_EVENT_CAN_SEND_NOW might be emitted during call to this function
 *       so packet handler should be ready to handle it
 * @param con_handle
 */
void att_server_request_can_send_now_event(hci_con_handle_t con_handle);
// end of deprecated functions

ANCS Client API {#sec:ancs_client_api}

ancs_client.h

void ancs_client_init(void);
void ancs_client_register_callback(btstack_packet_handler_t callback);
const char * ancs_client_attribute_name_for_id(int id);

Battery Service Client API {#sec:battery_service_client_api}

battery_service_client.h

/**
 * @brief Initialize Battery Service. 
 */
void battery_service_client_init(void);

/**
 * @brief Connect to Battery Services of remote device. The client will try to register for notifications. 
 * If notifications are not supported by remote Battery Service, the client will poll battery level
 * If poll_interval_ms is 0, polling is disabled, and only notifications will be received.
 * In either case, the battery level is received via GATTSERVICE_SUBEVENT_BATTERY_SERVICE_LEVEL event.
 * The battery level is reported as percentage, i.e. 100 = full and it is valid if the ATTT status is equal to ATT_ERROR_SUCCESS, 
 * see ATT errors (see bluetooth.h) for other values.
 *   
 * For manual polling, see battery_service_client_read_battery_level below.
 *
 * Event GATTSERVICE_SUBEVENT_BATTERY_SERVICE_CONNECTED is emitted with status ERROR_CODE_SUCCESS on success, otherwise
 * GATT_CLIENT_IN_WRONG_STATE, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE if no battery service is found, or ATT errors (see bluetooth.h). 
 * This event event also returns number of battery instances found on remote server, as well as poll bitmap that indicates which indexes 
 * of services require polling, i.e. they do not support notification on battery level change,
 *
 * @param con_handle
 * @param packet_handler
 * @param poll_interval_ms or 0 to disable polling
 * @param battery_service_cid
 * @return status ERROR_CODE_SUCCESS on success, otherwise ERROR_CODE_COMMAND_DISALLOWED if there is already a client associated with con_handle, or BTSTACK_MEMORY_ALLOC_FAILED 
 */
uint8_t battery_service_client_connect(hci_con_handle_t con_handle, btstack_packet_handler_t packet_handler, uint32_t poll_interval_ms, uint16_t * battery_service_cid);

/**
 * @brief Read battery level for service with given index. Event GATTSERVICE_SUBEVENT_BATTERY_SERVICE_LEVEL is 
 * received with battery level (unit is in percentage, i.e. 100 = full). The battery level is valid if the ATTT status 
 * is equal to ATT_ERROR_SUCCESS, see ATT errors (see bluetooth.h) for other values.
 * @param battery_service_cid
 * @param service_index
 * @return status
 */
uint8_t battery_service_client_read_battery_level(uint16_t battery_service_cid, uint8_t service_index);

/**
 * @brief Disconnect from Battery Service.
 * @param battery_service_cid
 * @return status
 */
uint8_t battery_service_client_disconnect(uint16_t battery_service_cid);

/**
 * @brief De-initialize Battery Service. 
 */
void battery_service_client_deinit(void);

Battery Service Server API {#sec:battery_service_server_api}

battery_service_server.h

/**
 * @brief Init Battery Service Server with ATT DB
 * @param battery_value in range 0-100
 */
void battery_service_server_init(uint8_t battery_value);

/**
 * @brief Update battery value
 * @note triggers notifications if subscribed
 * @param battery_value in range 0-100
 */
void battery_service_server_set_battery_value(uint8_t battery_value);

Bond Management Service Server API {#sec:bond_management_service_server_api}

bond_management_service_server.h

#define BOND_MANAGEMENT_CONTROL_POINT_OPCODE_NOT_SUPPORTED 0x80
#define BOND_MANAGEMENT_OPERATION_FAILED 0x81

#define BMF_DELETE_ACTIVE_BOND_CLASSIC_AND_LE                   0x00001
#define BMF_DELETE_ACTIVE_BOND_CLASSIC_AND_LE_WITH_AUTH         0x00002
#define BMF_DELETE_ACTIVE_BOND_CLASSIC                          0x00004
#define BMF_DELETE_ACTIVE_BOND_CLASSIC_WITH_AUTH                0x00008
#define BMF_DELETE_ACTIVE_BOND_LE                               0x00010
#define BMF_DELETE_ACTIVE_BOND_LE_WITH_AUTH                     0x00020
#define BMF_DELETE_ALL_BONDS_CLASSIC_AND_LE                     0x00040
#define BMF_DELETE_ALL_BONDS_CLASSIC_AND_LE_WITH_AUTH           0x00080
#define BMF_DELETE_ALL_BONDS_CLASSIC                            0x00100
#define BMF_DELETE_ALL_BONDS_CLASSIC_WITH_AUTH                  0x00200
#define BMF_DELETE_ALL_BONDS_LE                                 0x00400
#define BMF_DELETE_ALL_BONDS_LE_WITH_AUTH                       0x00800
#define BMF_DELETE_ALL_BUT_ACTIVE_BOND_CLASSIC_AND_LE           0x01000
#define BMF_DELETE_ALL_BUT_ACTIVE_BOND_CLASSIC_AND_LE_WITH_AUTH 0x02000
#define BMF_DELETE_ALL_BUT_ACTIVE_BOND_CLASSIC                  0x04000
#define BMF_DELETE_ALL_BUT_ACTIVE_BOND_CLASSIC_WITH_AUTH        0x08000
#define BMF_DELETE_ALL_BUT_ACTIVE_BOND_LE                       0x10000
#define BMF_DELETE_ALL_BUT_ACTIVE_BOND_LE_WITH_AUT              0x20000

typedef enum {
    BOND_MANAGEMENT_CMD_DELETE_ACTIVE_BOND_CLASSIC_AND_LE = 0x01,
    BOND_MANAGEMENT_CMD_DELETE_ACTIVE_BOND_CLASSIC,
    BOND_MANAGEMENT_CMD_DELETE_ACTIVE_BOND_LE,
    BOND_MANAGEMENT_CMD_DELETE_ALL_BONDS_CLASSIC_AND_LE,
    BOND_MANAGEMENT_CMD_DELETE_ALL_BONDS_CLASSIC,
    BOND_MANAGEMENT_CMD_DELETE_ALL_BONDS_LE,
    BOND_MANAGEMENT_CMD_DELETE_ALL_BUT_ACTIVE_BOND_CLASSIC_AND_LE,
    BOND_MANAGEMENT_CMD_DELETE_ALL_BUT_ACTIVE_BOND_CLASSIC,
    BOND_MANAGEMENT_CMD_DELETE_ALL_BUT_ACTIVE_BOND_LE
} bond_management_cmd_t;

/**
 * @brief Init Bond Management Service with ATT DB
 * @param supported_features
 */
void bond_management_service_server_init(uint32_t supported_features);

/**
 * @brief Set authorisation string
 * @note String is not copied
 * @param authorisation_string
 */
void bond_management_service_server_set_authorisation_string(const char * authorisation_string);

Cycling Power Service Server API {#sec:cycling_power_service_server_api}

cycling_power_service_server.h

#define CYCLING_POWER_MANUFACTURER_SPECIFIC_DATA_MAX_SIZE   16

typedef enum {
    CP_PEDAL_POWER_BALANCE_REFERENCE_UNKNOWN = 0,
    CP_PEDAL_POWER_BALANCE_REFERENCE_LEFT,
    CP_PEDAL_POWER_BALANCE_REFERENCE_NOT_SUPPORTED
} cycling_power_pedal_power_balance_reference_t;

typedef enum {
    CP_TORQUE_SOURCE_WHEEL = 0,
    CP_TORQUE_SOURCE_CRANK,
    CP_TORQUE_SOURCE_NOT_SUPPORTED
} cycling_power_torque_source_t;

typedef enum {
    CP_SENSOR_MEASUREMENT_CONTEXT_FORCE = 0,
    CP_SENSOR_MEASUREMENT_CONTEXT_TORQUE
} cycling_power_sensor_measurement_context_t;

typedef enum {
    CP_DISTRIBUTED_SYSTEM_UNSPECIFIED = 0,
    CP_DISTRIBUTED_SYSTEM_NOT_SUPPORTED,
    CP_DISTRIBUTED_SYSTEM_SUPPORTED
} cycling_power_distributed_system_t;

typedef enum {
    CP_MEASUREMENT_FLAG_PEDAL_POWER_BALANCE_PRESENT = 0,
    CP_MEASUREMENT_FLAG_PEDAL_POWER_BALANCE_REFERENCE, // 0 - unknown, 1 - left
    CP_MEASUREMENT_FLAG_ACCUMULATED_TORQUE_PRESENT,
    CP_MEASUREMENT_FLAG_ACCUMULATED_TORQUE_SOURCE, // 0 - wheel based, 1 - crank based
    CP_MEASUREMENT_FLAG_WHEEL_REVOLUTION_DATA_PRESENT,
    CP_MEASUREMENT_FLAG_CRANK_REVOLUTION_DATA_PRESENT,
    CP_MEASUREMENT_FLAG_EXTREME_FORCE_MAGNITUDES_PRESENT,
    CP_MEASUREMENT_FLAG_EXTREME_TORQUE_MAGNITUDES_PRESENT,
    CP_MEASUREMENT_FLAG_EXTREME_ANGLES_PRESENT,
    CP_MEASUREMENT_FLAG_TOP_DEAD_SPOT_ANGLE_PRESENT,
    CP_MEASUREMENT_FLAG_BOTTOM_DEAD_SPOT_ANGLE_PRESENT,
    CP_MEASUREMENT_FLAG_ACCUMULATED_ENERGY_PRESENT,
    CP_MEASUREMENT_FLAG_OFFSET_COMPENSATION_INDICATOR,
    CP_MEASUREMENT_FLAG_RESERVED
} cycling_power_measurement_flag_t;

typedef enum {
    CP_INSTANTANEOUS_MEASUREMENT_DIRECTION_UNKNOWN = 0,
    CP_INSTANTANEOUS_MEASUREMENT_DIRECTION_TANGENTIAL_COMPONENT,
    CP_INSTANTANEOUS_MEASUREMENT_DIRECTION_RADIAL_COMPONENT,
    CP_INSTANTANEOUS_MEASUREMENT_DIRECTION_LATERAL_COMPONENT
} cycling_power_instantaneous_measurement_direction_t;

typedef enum {
    CP_VECTOR_FLAG_CRANK_REVOLUTION_DATA_PRESENT = 0,
    CP_VECTOR_FLAG_FIRST_CRANK_MEASUREMENT_ANGLE_PRESENT, 
    CP_VECTOR_FLAG_INSTANTANEOUS_FORCE_MAGNITUDE_ARRAY_PRESENT,
    CP_VECTOR_FLAG_INSTANTANEOUS_TORQUE_MAGNITUDE_ARRAY_PRESENT,
    CP_VECTOR_FLAG_INSTANTANEOUS_MEASUREMENT_DIRECTION = 4, // 2 bit
    CP_VECTOR_FLAG_RESERVED = 6
} cycling_power_vector_flag_t;

typedef enum {
    CP_SENSOR_LOCATION_OTHER,
    CP_SENSOR_LOCATION_TOP_OF_SHOE,
    CP_SENSOR_LOCATION_IN_SHOE,
    CP_SENSOR_LOCATION_HIP,
    CP_SENSOR_LOCATION_FRONT_WHEEL,
    CP_SENSOR_LOCATION_LEFT_CRANK,
    CP_SENSOR_LOCATION_RIGHT_CRANK,
    CP_SENSOR_LOCATION_LEFT_PEDAL,
    CP_SENSOR_LOCATION_RIGHT_PEDAL,
    CP_SENSOR_LOCATION_FRONT_HUB,
    CP_SENSOR_LOCATION_REAR_DROPOUT,
    CP_SENSOR_LOCATION_CHAINSTAY,
    CP_SENSOR_LOCATION_REAR_WHEEL,
    CP_SENSOR_LOCATION_REAR_HUB,
    CP_SENSOR_LOCATION_CHEST,
    CP_SENSOR_LOCATION_SPIDER,
    CP_SENSOR_LOCATION_CHAIN_RING,
    CP_SENSOR_LOCATION_RESERVED
} cycling_power_sensor_location_t;

typedef enum {
    CP_FEATURE_FLAG_PEDAL_POWER_BALANCE_SUPPORTED = 0,
    CP_FEATURE_FLAG_ACCUMULATED_TORQUE_SUPPORTED,
    CP_FEATURE_FLAG_WHEEL_REVOLUTION_DATA_SUPPORTED,
    CP_FEATURE_FLAG_CRANK_REVOLUTION_DATA_SUPPORTED,
    CP_FEATURE_FLAG_EXTREME_MAGNITUDES_SUPPORTED,
    CP_FEATURE_FLAG_EXTREME_ANGLES_SUPPORTED,
    CP_FEATURE_FLAG_TOP_AND_BOTTOM_DEAD_SPOT_ANGLE_SUPPORTED,
    CP_FEATURE_FLAG_ACCUMULATED_ENERGY_SUPPORTED,
    CP_FEATURE_FLAG_OFFSET_COMPENSATION_INDICATOR_SUPPORTED,
    CP_FEATURE_FLAG_OFFSET_COMPENSATION_SUPPORTED,
    CP_FEATURE_FLAG_CYCLING_POWER_MEASUREMENT_CHARACTERISTIC_CONTENT_MASKING_SUPPORTED,
    CP_FEATURE_FLAG_MULTIPLE_SENSOR_LOCATIONS_SUPPORTED,
    CP_FEATURE_FLAG_CRANK_LENGTH_ADJUSTMENT_SUPPORTED,
    CP_FEATURE_FLAG_CHAIN_LENGTH_ADJUSTMENT_SUPPORTED,
    CP_FEATURE_FLAG_CHAIN_WEIGHT_ADJUSTMENT_SUPPORTED,
    CP_FEATURE_FLAG_SPAN_LENGTH_ADJUSTMENT_SUPPORTED,
    CP_FEATURE_FLAG_SENSOR_MEASUREMENT_CONTEXT, // 0-force based, 1-torque based
    CP_FEATURE_FLAG_INSTANTANEOUS_MEASUREMENT_DIRECTION_SUPPORTED,
    CP_FEATURE_FLAG_FACTORY_CALIBRATION_DATE_SUPPORTED,
    CP_FEATURE_FLAG_ENHANCED_OFFSET_COMPENSATION_SUPPORTED,
    CP_FEATURE_FLAG_DISTRIBUTED_SYSTEM_SUPPORT = 20,  // 0-unspecified, 1-not for use in distr. system, 2-used in distr. system, 3-reserved
    CP_FEATURE_FLAG_RESERVED = 22
} cycling_power_feature_flag_t;

typedef enum {
    CP_CALIBRATION_STATUS_INCORRECT_CALIBRATION_POSITION = 0x01,  
    CP_CALIBRATION_STATUS_MANUFACTURER_SPECIFIC_ERROR_FOLLOWS = 0xFF
} cycling_power_calibration_status_t;


/**
 * @brief Init Server with ATT DB
 *
 * @param feature_flags
 * @param pedal_power_balance_reference
 * @param torque_source
 * @param supported_sensor_locations
 * @param num_supported_sensor_locations
 * @param current_sensor_location
 */
void cycling_power_service_server_init(uint32_t feature_flags,
                                       cycling_power_pedal_power_balance_reference_t pedal_power_balance_reference, cycling_power_torque_source_t torque_source,
                                       cycling_power_sensor_location_t * supported_sensor_locations, uint16_t num_supported_sensor_locations,
                                       cycling_power_sensor_location_t current_sensor_location);

/**
 * @brief Setup measurement as advertisement data
 * @param adv_interval
 * @param adv_buffer
 * @param adv_size
 * @return
 */
int cycling_power_get_measurement_adv(uint16_t adv_interval, uint8_t * adv_buffer, uint16_t adv_size);

/**
 * @brief Register callback for the calibration and broadcast updates.
 *
 * @param callback
 */
void cycling_power_service_server_packet_handler(btstack_packet_handler_t callback);

/**
 * @brief Report calibration done.
 * @param measurement_type
 * @param calibrated_value
 */
void  cycling_power_server_calibration_done(cycling_power_sensor_measurement_context_t measurement_type, uint16_t calibrated_value);

/**
 * @brief Report enhanced calibration done.
 *
 * @param measurement_type
 * @param calibrated_value
 * @param manufacturer_company_id
 * @param num_manufacturer_specific_data
 * @param manufacturer_specific_data
 */
void cycling_power_server_enhanced_calibration_done(cycling_power_sensor_measurement_context_t measurement_type,
                                                    uint16_t calibrated_value, uint16_t manufacturer_company_id,
                                                    uint8_t num_manufacturer_specific_data, uint8_t * manufacturer_specific_data);

/**
 * @brief Set factory calibration date.
 * @param date
 * @return 1 if successful
 */
int  cycling_power_service_server_set_factory_calibration_date(gatt_date_time_t date);

/**
 * @brief Set sampling rate.
 * @param sampling_rate_Hz
 */
void cycling_power_service_server_set_sampling_rate(uint8_t sampling_rate_Hz);

/**
 * @brief Accumulate torque value.
 * @param torque_Nm
 */
void cycling_power_service_server_add_torque(int16_t torque_Nm);

/**
 * @brief Accumulate wheel revolution value and set the time of the last measurement.
 * @param wheel_revolution
 * @param wheel_event_time_s  unit: seconds
 */
void cycling_power_service_server_add_wheel_revolution(int32_t wheel_revolution, uint16_t wheel_event_time_s);

/**
 * @brief Accumulate crank revolution value and set the time of the last measurement.
 * @param crank_revolution
 * @param crank_event_time_s  unit: seconds
 */
void cycling_power_service_server_add_crank_revolution(uint16_t crank_revolution, uint16_t crank_event_time_s);

/**
 * @brief Accumulate energy.
 * @param energy_kJ  unit: kilo Joule
 */
void cycling_power_service_add_energy(uint16_t energy_kJ);

/**
 * @brief Set the value of the power. The Instantaneous Power field represents either
 * the total power the user is producing or a part of the total power depending on the
 * type of sensor (e.g., single sensor or distributed power sensor system).
 *
 * @param instantaneous_power_W  unit: watt
 */
void cycling_power_service_server_set_instantaneous_power(int16_t instantaneous_power_W);

/**
 * @brief Set the pedal power balance value. The Pedal Power Balance field represents the ratio between
 * the total amount of power measured by the sensor and a reference (either unknown or left).
 *
 * @param pedal_power_balance_percentage
 */
void cycling_power_service_server_set_pedal_power_balance(uint8_t pedal_power_balance_percentage);

/**
 * @brief Set the minimum and maximum force value measured in a single crank revolution.
 *
 * This, so called, Extreme Force Magnitude field pair will be included in the Cycling Power Measurement
 * characteristic only if the device supports the Extreme Magnitudes feature and
 * the Sensor Measurement Context of the Cycling Power Feature characteristic is set to 0 (Force-based).
 *
 * @param min_force_magnitude_N  unit: newton
 * @param max_force_magnitude_N  unit: newton
 */
void cycling_power_service_server_set_force_magnitude(int16_t min_force_magnitude_N, int16_t max_force_magnitude_N);

/**
 * @brief Set the minimum and maximum torque value measured in a single crank revolution.
 *
 * This, so called, Extreme Torque Magnitude field pair will be included in the Cycling Power Measurement
 * characteristic only if the device supports the Extreme Magnitudes feature and
 * the Sensor Measurement Context of the Cycling Power Feature characteristic is set to 1 (Torque-based).
 *
 * @param min_torque_magnitude_Nm  unit: newton meter
 * @param max_torque_magnitude_Nm  unit: newton meter
 */
void cycling_power_service_server_set_torque_magnitude(int16_t min_torque_magnitude_Nm, int16_t max_torque_magnitude_Nm);

/**
 * @brief Set the minimum and maximum angle of the crank measured in a single crank revolution (unit: degree).
 *
 * This, so called, Extreme Angles Magnitude field pair will be included in the Cycling Power Measurement
 * characteristic only if the device supports the Extreme Angles feature.
 *
 * @param min_angle_degree
 * @param max_angle_degree
 */
void cycling_power_service_server_set_angle(uint16_t min_angle_degree, uint16_t max_angle_degree);

/**
 * @brief Set the value of the crank angle measured when the value of the Instantaneous Power value becomes positive.
 *
 * This field will be included in the Cycling Power Measurement characteristic
 * only if the device supports the Top and Bottom Dead Spot Angles feature.
 *
 * @param top_dead_spot_angle_degree
 */
void cycling_power_service_server_set_top_dead_spot_angle(uint16_t top_dead_spot_angle_degree);

/**
 * @brief Set the value of the crank angle measured when the value of the Instantaneous Power value becomes negative.
 *
 * This field will be included in the Cycling Power Measurement characteristic
 * only if the device supports the Top and Bottom Dead Spot Angles feature.
 *
 * @param bottom_dead_spot_angle_degree
 */
void cycling_power_service_server_set_bottom_dead_spot_angle(uint16_t bottom_dead_spot_angle_degree);

/**
 * @brief Set the raw sensor force magnitude measurements.
 *
 * @param force_magnitude_count
 * @param force_magnitude_N_array  unit: newton
 */
void cycling_power_service_server_set_force_magnitude_values(int force_magnitude_count, int16_t * force_magnitude_N_array);

/**
 * @brief Set the raw sensor torque magnitude measurements.
 *
 * @param force_magnitude_count
 * @param force_magnitude_N_array  unit: newton meter
 */
void cycling_power_service_server_set_torque_magnitude_values(int torque_magnitude_count, int16_t * torque_magnitude_Nm_array);

/**
 * @brief Set the instantaneous measurement direction. The field describes
 * the direction of the Instantaneous Magnitude values the Server measures
 * (e.g., Unknown, Tangential Component, Radial Component, or Lateral Component).
 *
 * @param direction
 */
void cycling_power_service_server_set_instantaneous_measurement_direction(cycling_power_instantaneous_measurement_direction_t direction);

/**
 * Set first crank measurement angle. The value will be present only in the first packet of
 * the Cycling Power Vector notification.
 *
 * @param first_crank_measurement_angle_degree
 */
void cycling_power_service_server_set_first_crank_measurement_angle(uint16_t first_crank_measurement_angle_degree);

/**
 * Get measurement flags bitmask.
 * @return measurement_flags_bitmask, see cycling_power_measurement_flag_t
 */
uint16_t cycling_power_service_measurement_flags(void);

/**
 * Get vector flags bitmask.
 * @return vector_flags_bitmask, see cycling_power_vector_flag_t
 */
uint8_t  cycling_power_service_vector_flags(void);

/**
 * @brief Trigger notification if subscribed
 */
void cycling_power_service_server_update_values(void);

Cycling Speed and Cadence Service Server API {#sec:cycling_speed_and_cadence_service_server_api}

cycling_speed_and_cadence_service_server.h

typedef enum {
    CSC_SERVICE_SENSOR_LOCATION_OTHER = 0,
    CSC_SERVICE_SENSOR_LOCATION_TOP_OF_SHOE,
    CSC_SERVICE_SENSOR_LOCATION_IN_SHOE,
    CSC_SERVICE_SENSOR_LOCATION_HIP,
    CSC_SERVICE_SENSOR_LOCATION_FRONT_WHEEL,
    CSC_SERVICE_SENSOR_LOCATION_LEFT_CRANK,
    CSC_SERVICE_SENSOR_LOCATION_RIGHT_CRANK,
    CSC_SERVICE_SENSOR_LOCATION_LEFT_PEDAL,
    CSC_SERVICE_SENSOR_LOCATION_RIGHT_PEDAL,
    CSC_SERVICE_SENSOR_LOCATION_FRONT_HUB,
    CSC_SERVICE_SENSOR_LOCATION_REAR_DROPOUT,
    CSC_SERVICE_SENSOR_LOCATION_CHAINSTAY,
    CSC_SERVICE_SENSOR_LOCATION_REAR_WHEEL,
    CSC_SERVICE_SENSOR_LOCATION_REAR_HUB,
    CSC_SERVICE_SENSOR_LOCATION_CHEST,
    CSC_SERVICE_SENSOR_LOCATION_SPIDER,
    CSC_SERVICE_SENSOR_LOCATION_CHAIN_RING,
    CSC_SERVICE_SENSOR_LOCATION_RESERVED
} cycling_speed_and_cadence_sensor_location_t;

typedef enum {
    CSC_FLAG_WHEEL_REVOLUTION_DATA_SUPPORTED = 0,
    CSC_FLAG_CRANK_REVOLUTION_DATA_SUPPORTED,
    CSC_FLAG_MULTIPLE_SENSOR_LOCATIONS_SUPPORTED
} csc_feature_flag_bit_t;

typedef enum {
    CSC_OPCODE_IDLE = 0,
    CSC_OPCODE_SET_CUMULATIVE_VALUE = 1,
    CSC_OPCODE_START_SENSOR_CALIBRATION,
    CSC_OPCODE_UPDATE_SENSOR_LOCATION,
    CSC_OPCODE_REQUEST_SUPPORTED_SENSOR_LOCATIONS,
    CSC_OPCODE_RESPONSE_CODE = 16
} csc_opcode_t;

/**
 * @brief Init Server with ATT DB
 */
void cycling_speed_and_cadence_service_server_init(uint32_t supported_sensor_locations, 
    uint8_t multiple_sensor_locations_supported, uint8_t wheel_revolution_data_supported, uint8_t crank_revolution_data_supported);

/**
 * @brief Update heart rate (unit: beats per minute)
 * @note triggers notifications if subscribed
 */
void cycling_speed_and_cadence_service_server_update_values(int32_t wheel_revolutions, uint16_t last_wheel_event_time, uint16_t crank_revolutions, uint16_t last_crank_event_time);

Device Information Service Client API {#sec:device_information_service_client_api}

device_information_service_client.h

/**
 * @brief Initialize Device Information Service. 
 */
void device_information_service_client_init(void);

/**
 * @brief Query Device Information Service. The client will query the remote service and emit events: 
 *
 * - GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_MANUFACTURER_NAME
 * - GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_MODEL_NUMBER     
 * - GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_SERIAL_NUMBER    
 * - GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_HARDWARE_REVISION
 * - GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_FIRMWARE_REVISION
 * - GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_SOFTWARE_REVISION
 * - GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_SYSTEM_ID        
 * - GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_IEEE_REGULATORY_CERTIFICATION
 * - GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_PNP_ID  
 *
 * Event GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_DONE is received when all queries are done, of if service was not found.
 * The status field of this event indicated ATT errors (see bluetooth.h). 
 *
 * @param con_handle
 * @param packet_handler
 * @return status ERROR_CODE_SUCCESS on success, otherwise GATT_CLIENT_IN_WRONG_STATE if query is already in progress
 */
uint8_t device_information_service_client_query(hci_con_handle_t con_handle, btstack_packet_handler_t packet_handler);


/**
 * @brief De-initialize Device Information Service. 
 */
void device_information_service_client_deinit(void);

Device Information Service Server API {#sec:device_information_service_server_api}

device_information_service_server.h

/**
 * @text Th eDevice Information Service allows to query manufacturer and/or 
 * vendor information about a device.
 * 
 * To use with your application, add `#import <device_information_service.gatt>` to your .gatt file. 
 *
 * *Note*: instead of calling all setters, you can create a local copy of the .gatt file and remove
 * all Characteristics that are not relevant for your application and define all fixed values in the .gatt file.
 */

/**
 * @brief Init Device Information Service Server with ATT DB
 * @param battery_value in range 0-100
 */
void device_information_service_server_init(void);

/**
 * @brief Set Manufacturer Name
 * @param manufacturer_name
 */
void device_information_service_server_set_manufacturer_name(const char * manufacturer_name);

/**
 * @brief Set Model Number
 * @param model_number
 */
void device_information_service_server_set_model_number(const char * model_number);

/**
 * @brief Set Serial Number
 * @param serial_number
 */
void device_information_service_server_set_serial_number(const char * serial_number);

/**
 * @brief Set Hardware Revision
 * @param hardware_revision
 */
void device_information_service_server_set_hardware_revision(const char * hardware_revision);

/**
 * @brief Set Firmware Revision
 * @param firmware_revision
 */
void device_information_service_server_set_firmware_revision(const char * firmware_revision);

/**
 * @brief Set Software Revision
 * @param software_revision
 */
void device_information_service_server_set_software_revision(const char * software_revision);

/**
 * @brief Set System ID
 * @param manufacturer_identifier uint40
 * @param organizationally_unique_identifier uint24
 */
void device_information_service_server_set_system_id(uint64_t manufacturer_identifier, uint32_t organizationally_unique_identifier);

/**
 * @brief Set IEEE 11073-20601 regulatory certification data list
 * @note: format duint16. duint16 is two uint16 values concatenated together.
 * @param value_a
 * @param value_b
 */
void device_information_service_server_set_ieee_regulatory_certification(uint16_t value_a, uint16_t value_b);

/**
 * @brief Set PnP ID
 * @param vendor_source_id
 * @param vendor_id
 * @param product_id
 * @Param product_versoin
 */
void device_information_service_server_set_pnp_id(uint8_t vendor_source_id, uint16_t vendor_id, uint16_t product_id, uint16_t product_version);

Heart Rate Service Server API {#sec:heart_rate_service_server_api}

heart_rate_service_server.h

typedef enum {
    HEART_RATE_SERVICE_BODY_SENSOR_LOCATION_OTHER = 0,
    HEART_RATE_SERVICE_BODY_SENSOR_LOCATION_CHEST,
    HEART_RATE_SERVICE_BODY_SENSOR_LOCATION_WRIST,
    HEART_RATE_SERVICE_BODY_SENSOR_LOCATION_FINGER,
    HEART_RATE_SERVICE_BODY_SENSOR_LOCATION_HAND,
    HEART_RATE_SERVICE_BODY_SENSOR_LOCATION_EAR_LOBE,
    HEART_RATE_SERVICE_BODY_SENSOR_LOCATION_FOOT
} heart_rate_service_body_sensor_location_t;

typedef enum {
    HEART_RATE_SERVICE_SENSOR_CONTACT_UNKNOWN = 0,
    HEART_RATE_SERVICE_SENSOR_CONTACT_UNSUPPORTED,
    HEART_RATE_SERVICE_SENSOR_CONTACT_NO_CONTACT,
    HEART_RATE_SERVICE_SENSOR_CONTACT_HAVE_CONTACT
} heart_rate_service_sensor_contact_status_t;


/**
 * @brief Init Battery Service Server with ATT DB
 * @param body_sensor_location
 * @param energy_expended_supported
 */
void heart_rate_service_server_init(heart_rate_service_body_sensor_location_t body_sensor_location, int energy_expended_supported);


/**
 * @brief Add Energy Expended to the internal accumulator.
 * @param energy_expended_kJ   energy expended in kilo Joules since the last update
 */
void heart_rate_service_add_energy_expended(uint16_t energy_expended_kJ);

/**
 * @brief Update heart rate (unit: beats per minute)
 * @note triggers notifications if subscribed
 * @param heart_rate_bpm        beats per minute
 * @param contact    
 * @param rr_interval_count 
 * @param rr_intervals      resolution in 1/1024 seconds
 */
void heart_rate_service_server_update_heart_rate_values(uint16_t heart_rate_bpm, 
    heart_rate_service_sensor_contact_status_t contact, int rr_interval_count, uint16_t * rr_intervals);

HID Service Client API {#sec:hids_client_api}

hids_client.h

/**
 * @brief Initialize HID Service Client. The HID Descriptor storage is shared between all connections.
 *
 * @param hid_descriptor_storage
 * @param hid_descriptor_storage_len
 */
void hids_client_init(uint8_t * hid_descriptor_storage, uint16_t hid_descriptor_storage_len);

/**
 * @brief Connect to HID Services of remote device. Event GATTSERVICE_SUBEVENT_HID_SERVICE_CONNECTED will be emitted
 * after all remote HID services and characteristics are found, and notifications for all input reports are enabled.
 * Status code can be ERROR_CODE_SUCCES if at least one HID service is found, otherwise either ATT errors or 
 * ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE if no service or report map or report are found.
 * It also contains the number of individual HIDS Services. 
 *
 * @param con_handle
 * @param packet_handler
 * @param protocol_mode see hid_protocol_mode_t in btstack_hid.h
 * @param hids_cid (out) to use for other functions
 * @return status ERROR_CODE_SUCCESS on success, otherwise ERROR_CODE_COMMAND_DISALLOWED if there is already a client
 *         associated with con_handle, or BTSTACK_MEMORY_ALLOC_FAILED.
 */
uint8_t hids_client_connect(hci_con_handle_t con_handle, btstack_packet_handler_t packet_handler, hid_protocol_mode_t protocol_mode, uint16_t * hids_cid);

/**
 * @brief Send HID report. Event GATTSERVICE_SUBEVENT_HID_REPORT_WRITTEN is emitted.
 *
 * @param hids_cid
 * @param report_id
 * @param report_type
 * @param report
 * @param report_len
 * @return status ERROR_CODE_SUCCESS on success, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, 
 * ERROR_CODE_COMMAND_DISALLOWED if client is in wrong state, 
 * ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE if no report with given type and ID is found, or
 * ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE if report length exceeds MTU.
 */
uint8_t hids_client_send_write_report(uint16_t hids_cid, uint8_t report_id, hid_report_type_t report_type, const uint8_t * report, uint8_t report_len);

/**
 * @brief Get HID report. Event GATTSERVICE_SUBEVENT_HID_REPORT is emitted.
 *
 * @param hids_cid
 * @param report_id
 * @param report_type
 * @return status ERROR_CODE_SUCCESS on success, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, 
 * ERROR_CODE_COMMAND_DISALLOWED if client is in wrong state, 
 * ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE if no report with given type and ID is found, or
 * ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE if report length exceeds MTU.
 */
uint8_t hids_client_send_get_report(uint16_t hids_cid, uint8_t report_id, hid_report_type_t report_type);

/**
 * @brief Get HID Information. Event GATTSERVICE_SUBEVENT_HID_INFORMATION is emitted.
 *
 * @param hids_cid
 * @param service_index
 * @return status ERROR_CODE_SUCCESS on success, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, 
 * ERROR_CODE_COMMAND_DISALLOWED if client is in wrong state, or
 * ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE if no report with given type and ID is found.
 */
uint8_t hids_client_get_hid_information(uint16_t hids_cid, uint8_t service_index);

/**
 * @brief Get Protocol Mode. Event GATTSERVICE_SUBEVENT_HID_PROTOCOL_MODE is emitted.
 *
 * @param hids_cid
 * @param service_index
 * @return status ERROR_CODE_SUCCESS on success, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, 
 * ERROR_CODE_COMMAND_DISALLOWED if client is in wrong state, or
 * ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE if no report with given type and ID is found.
 */
uint8_t hids_client_get_protocol_mode(uint16_t hids_cid, uint8_t service_index);

/**
 * @brief Set Protocol Mode.
 *
 * @param hids_cid
 * @param service_index
 * @param protocol_mode
 * @return status ERROR_CODE_SUCCESS on success, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, 
 * ERROR_CODE_COMMAND_DISALLOWED if client is in wrong state, or
 * ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE if no report with given type and ID is found.
 */
uint8_t hids_client_send_set_protocol_mode(uint16_t hids_cid, uint8_t service_index, hid_protocol_mode_t protocol_mode);

/**
 * @brief Send Suspend to remote HID service.
 *
 * @param hids_cid
 * @param service_index
 * @return status ERROR_CODE_SUCCESS on success, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, 
 * ERROR_CODE_COMMAND_DISALLOWED if client is in wrong state, or
 * ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE if no report with given type and ID is found.
 */
uint8_t hids_client_send_suspend(uint16_t hids_cid, uint8_t service_index);

/**
 * @brief Send Exit Suspend to remote HID service.
 *
 * @param hids_cid
 * @param service_index
 * @return status ERROR_CODE_SUCCESS on success, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, 
 * ERROR_CODE_COMMAND_DISALLOWED if client is in wrong state, or
 * ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE if no report with given type and ID is found.
 */
uint8_t hids_client_send_exit_suspend(uint16_t hids_cid, uint8_t service_index);

/**
 * @brief Enable all notifications. Event GATTSERVICE_SUBEVENT_HID_SERVICE_REPORTS_NOTIFICATION reports current configuration.
 *
 * @param hids_cid
 * @return status ERROR_CODE_SUCCESS on success, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, or
 * ERROR_CODE_COMMAND_DISALLOWED if client is in wrong state.
 */
uint8_t hids_client_enable_notifications(uint16_t hids_cid);

/**
 * @brief Disable all notifications. Event GATTSERVICE_SUBEVENT_HID_SERVICE_REPORTS_NOTIFICATION reports current configuration.
 *
 * @param hids_cid
 * @return status ERROR_CODE_SUCCESS on success, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, or
 * ERROR_CODE_COMMAND_DISALLOWED if client is in wrong state.
 */
uint8_t hids_client_disable_notifications(uint16_t hids_cid);

/**
 * @brief Disconnect from HID Service.
 *
 * @param hids_cid
 * @return status ERROR_CODE_SUCCESS on success, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER
 */
uint8_t hids_client_disconnect(uint16_t hids_cid);

/*
 * @brief Get descriptor data. For services in boot mode without a Report Map, a default HID Descriptor for Keyboard/Mouse is provided.
 *
 * @param hid_cid
 * @return data
 */
const uint8_t * hids_client_descriptor_storage_get_descriptor_data(uint16_t hids_cid, uint8_t service_index);

/*
 * @brief Get descriptor length
 *
 * @param hid_cid
 * @return length
 */
uint16_t hids_client_descriptor_storage_get_descriptor_len(uint16_t hids_cid, uint8_t service_index);

/**
 * @brief De-initialize HID Service Client. 
 *
 */
void hids_client_deinit(void);

HID Service Server API {#sec:hids_device_api}

hids_device.h

typedef struct {
    uint16_t value_handle;
    uint16_t client_configuration_handle;
    uint16_t client_configuration_value;

    hid_report_type_t type;
    uint8_t id;
    uint8_t size;
} hids_device_report_t;

/**
 * @text Implementation of the GATT HIDS Device
 * To use with your application, add '#import <hids.gatt>' to your .gatt file
 */

/**
 * @brief Set up HIDS Device with single INPUT, OUTPUT and FEATURE report 
 */
void hids_device_init(uint8_t hid_country_code, const uint8_t * hid_descriptor, uint16_t hid_descriptor_size);

/**
 * @brief Set up HIDS Device for multiple instances of INPUT, OUTPUT and FEATURE reports
 */
void hids_device_init_with_storage(uint8_t hid_country_code, const uint8_t * hid_descriptor, uint16_t hid_descriptor_size, 
    uint16_t num_reports, hids_device_report_t * report_storage);

/**
 * @brief Register callback for the HIDS Device client.
 * @param callback
 */
void hids_device_register_packet_handler(btstack_packet_handler_t callback);

/**
 * @brief Register report callback for Get Report operation
 * @param callback
 */
void hids_device_register_get_report_callback(void (*callback)(hci_con_handle_t con_handle, hid_report_type_t report_type, uint16_t report_id, uint16_t max_report_size, uint8_t * out_report));

/**
 * @brief Request can send now event to send HID Report
 * Generates an HIDS_SUBEVENT_CAN_SEND_NOW subevent
 * @param hid_cid
 */
void hids_device_request_can_send_now_event(hci_con_handle_t con_handle);

/**
 * @brief Send HID Input Report for Report ID
 * @param con_handle
 * @param report_id
 * @param report
 * @param report_len
 * @returns status
 */
uint8_t hids_device_send_input_report_for_id(hci_con_handle_t con_handle, uint16_t report_id, const uint8_t * report, uint16_t report_len);

/**
 * @brief Send HID Input Report for first Input Report
 * @param con_handle
 * @param report
 * @param report_len
 * @returns status
 */
uint8_t hids_device_send_input_report(hci_con_handle_t con_handle, const uint8_t * report, uint16_t report_len);

/**
 * @brief Send HID Boot Mouse Input Report
 * @param con_handle
 * @param report
 * @param report_len
 * @returns status
 */
uint8_t hids_device_send_boot_mouse_input_report(hci_con_handle_t con_handle, const uint8_t * report, uint16_t report_len);

/**
 * @brief Send HID Boot Mouse Input Report
 * @param con_handle
 * @param report
 * @param report_len
 * @returns status
 */
uint8_t hids_device_send_boot_keyboard_input_report(hci_con_handle_t con_handle, const uint8_t * report, uint16_t report_len);

Nordic SPP Service Server API {#sec:nordic_spp_service_server_api}

nordic_spp_service_server.h

/**
 * @text The Nordic SPP Service is implementation of the Nordic SPP-like profile.
 *
 * To use with your application, add `#import <nordic_spp_service.gatt>` to your .gatt file
 * and call all functions below. All strings and blobs need to stay valid after calling the functions.
 */

/**
 * @brief Init Nordic SPP Service Server with ATT DB
 * @param packet_handler for events and tx data from peer as RFCOMM_DATA_PACKET
 */
void nordic_spp_service_server_init(btstack_packet_handler_t packet_handler);

/** 
 * @brief Queue send request. When called, one packet can be send via nordic_spp_service_send below
 * @param request
 * @param con_handle
 */
void nordic_spp_service_server_request_can_send_now(btstack_context_callback_registration_t * request, hci_con_handle_t con_handle);

/**
 * @brief Send data
 * @param con_handle
 * @param data
 * @param size
 */
int nordic_spp_service_server_send(hci_con_handle_t con_handle, const uint8_t * data, uint16_t size);

Scan Parameters Service Client API {#sec:scan_parameters_service_client_api}

scan_parameters_service_client.h

/**
 * @brief Initialize Scan Parameters Service. 
 */
void scan_parameters_service_client_init(void);

/**
 * @brief Set Scan Parameters Service. It will update all connected devices.
 * @param scan_interval
 * @param scan_window
 */
void scan_parameters_service_client_set(uint16_t scan_interval, uint16_t scan_window);

/**
 * @brief Connect to Scan Parameters Service of remote device. 
 *
 * The GATTSERVICE_SUBEVENT_SCAN_PARAMETERS_SERVICE_CONNECTED event completes the request. 
 * Its status is set to ERROR_CODE_SUCCESS if remote service and SCAN_INTERVAL_WINDOW characteristic are found. 
 * Other status codes of this event:
 * - GATT_CLIENT_IN_WRONG_STATE: client in wrong state
 * - ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE: service or characteristic not found
 * - ATT errors, see bluetooth.h
 *
 * @param con_handle
 * @param packet_handler
 * @param scan_parameters_cid
 * @return status ERROR_CODE_SUCCESS on success, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if client with con_handle not found
 */
uint8_t scan_parameters_service_client_connect(hci_con_handle_t con_handle,  btstack_packet_handler_t packet_handler, uint16_t * scan_parameters_cid);

/**
 * @brief Enable notifications
 * @param scan_parameters_cid
 * @return status ERROR_CODE_SUCCESS on success, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if client with con_handle is not found
 */
uint8_t scan_parameters_service_client_enable_notifications(uint16_t scan_parameters_cid);

/**
 * @brief Disconnect from Scan Parameters Service.
 * @param scan_parameters_cid
 * @return status ERROR_CODE_SUCCESS on success, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if client with con_handle is not found
 */
uint8_t scan_parameters_service_client_disconnect(uint16_t scan_parameters_cid);


/**
 * @brief De-initialize Scan Parameters Service. 
 */
void scan_parameters_service_client_deinit(void);

Scan Parameters Service Server API {#sec:scan_parameters_service_server_api}

scan_parameters_service_server.h

/**
 * @text The Scan Parameters Service enables a remote GATT Client to store the LE scan parameters it is using locally. These parameters can be utilized by the application to optimize power consumption and/or reconnection latency.
 *
 * To use with your application, add `#import <scan_parameters_service.gatt>` to your .gatt file
 * and call all functions below. All strings and blobs need to stay valid after calling the functions.
 */

/**
 * @brief Init Scan Parameters Service Server with ATT DB
 * @param packet_handler 
 */
void scan_parameters_service_server_init(btstack_packet_handler_t packet_handler);

/** 
 * @brief Request scan parameters from Scan Parameters Client.
 */
void scan_parameters_service_server_request_scan_parameters(void);

TX Power Service Server API {#sec:tx_power_service_server_api}

tx_power_service_server.h

/**
 * @brief Init TX Power Service Server with ATT DB
 * @param tx_power_level
 */
void tx_power_service_server_init(int8_t tx_power_level);

/**
 * @brief Update TX power level
 * @param tx_power_level_dBm range [-100,20]
 */
void tx_power_service_server_set_level(int8_t tx_power_level_dBm);

u-blox SPP Service Server API {#sec:ublox_spp_service_server_api}

ublox_spp_service_server.h

/**
 * @text The u-blox SPP Service is implementation of the u-Blox SPP-like profile.
 *
 * To use with your application, add `#import <ublox_spp_service.gatt>` to your .gatt file
 * and call all functions below. All strings and blobs need to stay valid after calling the functions.
 */

/**
 * @brief Init ublox SPP Service Server with ATT DB
 * @param packet_handler for events and tx data from peer as RFCOMM_DATA_PACKET
 */
void ublox_spp_service_server_init(btstack_packet_handler_t packet_handler);

/** 
 * @brief Queue send request. When called, one packet can be send via ublox_spp_service_send below
 * @param request
 * @param con_handle
 */
void ublox_spp_service_server_request_can_send_now(btstack_context_callback_registration_t * request, hci_con_handle_t con_handle);

/**
 * @brief Send data
 * @param con_handle
 * @param data
 * @param size
 */
int ublox_spp_service_server_send(hci_con_handle_t con_handle, const uint8_t * data, uint16_t size);

GATT Client API {#sec:gatt_client_api}

gatt_client.h

typedef struct {
    uint16_t start_group_handle;
    uint16_t end_group_handle;
    uint16_t uuid16;
    uint8_t  uuid128[16];
} gatt_client_service_t;

typedef struct {
    uint16_t start_handle;
    uint16_t value_handle;
    uint16_t end_handle;
    uint16_t properties;
    uint16_t uuid16;
    uint8_t  uuid128[16];
} gatt_client_characteristic_t;

typedef struct {
    uint16_t handle;
    uint16_t uuid16;
    uint8_t  uuid128[16];
} gatt_client_characteristic_descriptor_t;

/** 
 * @brief Set up GATT client.
 */
void gatt_client_init(void);

/**
 * @brief Set minimum required security level for GATT Client
 * @note  The Bluetooth specification makes the GATT Server responsible to check for security.
 *        This allows an attacker to spoof an existing device with a GATT Servers, but skip the authentication part.
 *        If your application is exchanging sensitive data with a remote device, you would need to manually check
 *        the security level before sending/receive such data.
 *        With level > 0, the GATT Client triggers authentication for all GATT Requests and defers any exchange
 *        until the required security level is established.
 *        gatt_client_request_can_write_without_response_event does not trigger authentication
 *        gatt_client_request_to_write_without_response does not trigger authentication
 *  @pram level, default LEVEL_0 (no encryption required)
 */
void gatt_client_set_required_security_level(gap_security_level_t level);

/**
 * @brief Connect to remote GATT Server over Classic (BR/EDR) Connection
 *        GATT_EVENT_CONNECTED with status and con_handle for other API functions
 *        is emitted on connection complete.
 * @note requires ENABLE_GATT_OVER_CLASSIC.
 * @param addr
 * @return status
 */
uint8_t gatt_client_classic_connect(btstack_packet_handler_t callback, bd_addr_t addr);

/**
 * @brief Disconnect o Classic (BR/EDR) connection to a remote GATT Server
 * @note requires ENABLE_GATT_OVER_CLASSIC
 * @param con_handle
 * @return status
 */
uint8_t gatt_client_classic_disconnect(btstack_packet_handler_t callback, hci_con_handle_t con_handle);

/**
 * @brief Setup Enhanced LE Bearer with up to 5 channels on existing LE connection
 * @param callback for GATT_EVENT_CONNECTED and GATT_EVENT_DISCONNECTED events
 * @param con_handle
 * @param num_channels
 * @param storage_buffer for L2CAP connection
 * @param storage_size - each channel requires (2 * ATT MTU) + 10 bytes
 * @return
 */
uint8_t gatt_client_le_enhanced_connect(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint8_t num_channels, uint8_t * storage_buffer, uint16_t storage_size);

/**
 * @brief MTU is available after the first query has completed. If status is equal to ERROR_CODE_SUCCESS, it returns the real value, 
 * otherwise the default value ATT_DEFAULT_MTU (see bluetooth.h). 
 * @param  con_handle   
 * @param  mtu
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER                  if no HCI connection for con_handle is found 
 *                BTSTACK_MEMORY_ALLOC_FAILED                               if no GATT client for con_handle could be allocated 
 *                GATT_CLIENT_IN_WRONG_STATE                                if MTU is not exchanged and MTU auto-exchange is disabled
 *                ERROR_CODE_SUCCESS                                        if query is successfully registered
 */
uint8_t gatt_client_get_mtu(hci_con_handle_t con_handle, uint16_t * mtu);

/**
 * @brief Sets whether a MTU Exchange Request shall be automatically send before the 
 * first attribute read request is send. Default is enabled.
 * @param enabled   
 */
void gatt_client_mtu_enable_auto_negotiation(uint8_t enabled);

/**
 * @brief Sends a MTU Exchange Request, this allows for the client to exchange MTU 
 * when gatt_client_mtu_enable_auto_negotiation is disabled.
 * @param  callback   
 * @param  con_handle
 */
void gatt_client_send_mtu_negotiation(btstack_packet_handler_t callback, hci_con_handle_t con_handle);

/** 
 * @brief Returns 1 if the GATT client is ready to receive a query. It is used with daemon. 
 * @param  con_handle
 * @return is_ready_status     0 - if no GATT client for con_handle is found, or is not ready, otherwise 1
 */
int gatt_client_is_ready(hci_con_handle_t con_handle);

/** 
 * @brief Discovers all primary services. 
 * For each found service a GATT_EVENT_SERVICE_QUERY_RESULT event will be emitted.
 * The GATT_EVENT_QUERY_COMPLETE event marks the end of discovery. 
 * @param  callback   
 * @param  con_handle
 * @return status BTSTACK_MEMORY_ALLOC_FAILED, if no GATT client for con_handle is found 
 *                GATT_CLIENT_IN_WRONG_STATE , if GATT client is not ready
 *                ERROR_CODE_SUCCESS         , if query is successfully registered
 */
uint8_t gatt_client_discover_primary_services(btstack_packet_handler_t callback, hci_con_handle_t con_handle);

/** 
 * @brief Discovers all secondary services. 
 * For each found service a GATT_EVENT_SERVICE_QUERY_RESULT event will be emitted.
 * The GATT_EVENT_QUERY_COMPLETE event marks the end of discovery. 
 * @param  callback   
 * @param  con_handle
 * @return status BTSTACK_MEMORY_ALLOC_FAILED, if no GATT client for con_handle is found 
 *                GATT_CLIENT_IN_WRONG_STATE , if GATT client is not ready
 *                ERROR_CODE_SUCCESS         , if query is successfully registered
 */
uint8_t gatt_client_discover_secondary_services(btstack_packet_handler_t callback, hci_con_handle_t con_handle);

/** 
 * @brief Discovers a specific primary service given its UUID. This service may exist multiple times. 
 * For each found service a GATT_EVENT_SERVICE_QUERY_RESULT event will be emitted.
 * The GATT_EVENT_QUERY_COMPLETE event marks the end of discovery. 
 * @param callback   
 * @param con_handle
 * @param uuid16
 * @return status BTSTACK_MEMORY_ALLOC_FAILED, if no GATT client for con_handle is found 
 *                GATT_CLIENT_IN_WRONG_STATE , if GATT client is not ready
 *                ERROR_CODE_SUCCESS         , if query is successfully registered  
 */
uint8_t gatt_client_discover_primary_services_by_uuid16(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t uuid16);

/** 
 * @brief Discovers a specific primary service given its UUID. This service may exist multiple times. 
 * For each found service a GATT_EVENT_SERVICE_QUERY_RESULT event will be emitted.
 * The GATT_EVENT_QUERY_COMPLETE event marks the end of discovery. 
 * @param  callback   
 * @param  con_handle
 * @param  uuid128
 * @return status BTSTACK_MEMORY_ALLOC_FAILED, if no GATT client for con_handle is found 
 *                GATT_CLIENT_IN_WRONG_STATE , if GATT client is not ready
 *                ERROR_CODE_SUCCESS         , if query is successfully registered  
 */
uint8_t gatt_client_discover_primary_services_by_uuid128(btstack_packet_handler_t callback, hci_con_handle_t con_handle, const uint8_t * uuid128);

/** 
 * @brief Finds included services within the specified service. 
 * For each found included service a GATT_EVENT_INCLUDED_SERVICE_QUERY_RESULT event will be emitted. 
 * The GATT_EVENT_QUERY_COMPLETE event marks the end of discovery. 
 * Information about included service type (primary/secondary) can be retrieved either by sending 
 * an ATT find information request for the returned start group handle 
 * (returning the handle and the UUID for primary or secondary service) or by comparing the service 
 * to the list of all primary services. 
 * @param  callback   
 * @param  con_handle
 * @param  service
 * @return status BTSTACK_MEMORY_ALLOC_FAILED, if no GATT client for con_handle is found 
 *                GATT_CLIENT_IN_WRONG_STATE , if GATT client is not ready
 *                ERROR_CODE_SUCCESS         , if query is successfully registered  
 */
uint8_t gatt_client_find_included_services_for_service(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_service_t * service);

/** 
 * @brief Discovers all characteristics within the specified service. 
 * For each found characteristic a GATT_EVENT_CHARACTERISTIC_QUERY_RESULT event will be emited. 
 * The GATT_EVENT_QUERY_COMPLETE event marks the end of discovery.
 * @param  callback   
 * @param  con_handle
 * @param  service
 * @return status BTSTACK_MEMORY_ALLOC_FAILED, if no GATT client for con_handle is found 
 *                GATT_CLIENT_IN_WRONG_STATE , if GATT client is not ready
 *                ERROR_CODE_SUCCESS         , if query is successfully registered 
 */
uint8_t gatt_client_discover_characteristics_for_service(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_service_t * service);

/** 
 * @brief The following four functions are used to discover all characteristics within 
 * the specified service or handle range, and return those that match the given UUID. 
 * 
 * For each found characteristic a GATT_EVENT_CHARACTERISTIC_QUERY_RESULT event will emitted. 
 * The GATT_EVENT_QUERY_COMPLETE event marks the end of discovery.
 * @param  callback   
 * @param  con_handle
 * @param  start_handle
 * @param  end_handle
 * @param  uuid16
 * @return status BTSTACK_MEMORY_ALLOC_FAILED, if no GATT client for con_handle is found 
 *                GATT_CLIENT_IN_WRONG_STATE , if GATT client is not ready
 *                ERROR_CODE_SUCCESS         , if query is successfully registered 
 */
uint8_t gatt_client_discover_characteristics_for_handle_range_by_uuid16(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t start_handle, uint16_t end_handle, uint16_t uuid16);

/** 
 * @brief The following four functions are used to discover all characteristics within the 
 * specified service or handle range, and return those that match the given UUID. 
 * For each found characteristic a GATT_EVENT_CHARACTERISTIC_QUERY_RESULT event will emitted. 
 * The GATT_EVENT_QUERY_COMPLETE event marks the end of discovery.
 * @param  callback   
 * @param  con_handle
 * @param  start_handle
 * @param  end_handle
 * @param  uuid128
 * @return status BTSTACK_MEMORY_ALLOC_FAILED, if no GATT client for con_handle is found 
 *                GATT_CLIENT_IN_WRONG_STATE , if GATT client is not ready
 *                ERROR_CODE_SUCCESS         , if query is successfully registered 
 */
uint8_t gatt_client_discover_characteristics_for_handle_range_by_uuid128(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t start_handle, uint16_t end_handle, const uint8_t * uuid128);

/** 
 * @brief The following four functions are used to discover all characteristics within the 
 * specified service or handle range, and return those that match the given UUID. 
 * For each found characteristic a GATT_EVENT_CHARACTERISTIC_QUERY_RESULT event will emitted. 
 * The GATT_EVENT_QUERY_COMPLETE event marks the end of discovery.
 * @param  callback   
 * @param  con_handle
 * @param  service
 * @param  uuid16
 * @return status BTSTACK_MEMORY_ALLOC_FAILED, if no GATT client for con_handle is found 
 *                GATT_CLIENT_IN_WRONG_STATE , if GATT client is not ready
 *                ERROR_CODE_SUCCESS         , if query is successfully registered 
 */
uint8_t gatt_client_discover_characteristics_for_service_by_uuid16(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_service_t * service, uint16_t uuid16);

/** 
 * @brief The following four functions are used to discover all characteristics within the 
 * specified service or handle range, and return those that match the given UUID. 
 * For each found characteristic a GATT_EVENT_CHARACTERISTIC_QUERY_RESULT event will emitted. 
 * The GATT_EVENT_QUERY_COMPLETE event marks the end of discovery.
 * @param  callback   
 * @param  con_handle
 * @param  service
 * @param  uuid128
 * @return status BTSTACK_MEMORY_ALLOC_FAILED, if no GATT client for con_handle is found 
 *                GATT_CLIENT_IN_WRONG_STATE , if GATT client is not ready
 *                ERROR_CODE_SUCCESS         , if query is successfully registered 
 */
uint8_t gatt_client_discover_characteristics_for_service_by_uuid128(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_service_t * service, const uint8_t * uuid128);

/** 
 * @brief Discovers attribute handle and UUID of a characteristic descriptor within the specified characteristic. 
 * For each found descriptor a GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT event will be emitted.
 * 
 * The GATT_EVENT_QUERY_COMPLETE event marks the end of discovery.
 * @param  callback   
 * @param  con_handle
 * @param  characteristic 
 * @return status BTSTACK_MEMORY_ALLOC_FAILED, if no GATT client for con_handle is found 
 *                GATT_CLIENT_IN_WRONG_STATE , if GATT client is not ready
 *                ERROR_CODE_SUCCESS         , if query is successfully registered 
 */
uint8_t gatt_client_discover_characteristic_descriptors(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_t * characteristic);

/** 
 * @brief Reads the characteristic value using the characteristic's value handle. 
 * If the characteristic value is found a GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT event will be emitted.
 * The GATT_EVENT_QUERY_COMPLETE event marks the end of read.
 * @param  callback   
 * @param  con_handle
 * @param  characteristic 
 * @return status BTSTACK_MEMORY_ALLOC_FAILED, if no GATT client for con_handle is found 
 *                GATT_CLIENT_IN_WRONG_STATE , if GATT client is not ready
 *                ERROR_CODE_SUCCESS         , if query is successfully registered 
 */
uint8_t gatt_client_read_value_of_characteristic(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_t * characteristic);

/** 
 * @brief Reads the characteristic value using the characteristic's value handle. 
 * If the characteristic value is found a GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT event will be emitted.
 * The GATT_EVENT_QUERY_COMPLETE event marks the end of read.
 * @param  callback   
 * @param  con_handle
 * @param  value_handle 
 * @return status BTSTACK_MEMORY_ALLOC_FAILED, if no GATT client for con_handle is found 
 *                GATT_CLIENT_IN_WRONG_STATE , if GATT client is not ready
 *                ERROR_CODE_SUCCESS         , if query is successfully registered 
 */
uint8_t gatt_client_read_value_of_characteristic_using_value_handle(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle);

/**
 * @brief Reads the characteric value of all characteristics with the uuid. 
 * For each characteristic value found a GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT event will be emitted.
 * The GATT_EVENT_QUERY_COMPLETE event marks the end of read.
 * @param  callback   
 * @param  con_handle
 * @param  start_handle
 * @param  end_handle
 * @param  uuid16
 * @return status BTSTACK_MEMORY_ALLOC_FAILED, if no GATT client for con_handle is found 
 *                GATT_CLIENT_IN_WRONG_STATE , if GATT client is not ready
 *                ERROR_CODE_SUCCESS         , if query is successfully registered 
 */
uint8_t gatt_client_read_value_of_characteristics_by_uuid16(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t start_handle, uint16_t end_handle, uint16_t uuid16);

/**
 * @brief Reads the characteric value of all characteristics with the uuid. 
 * For each characteristic value found a GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT event will be emitted.
 * The GATT_EVENT_QUERY_COMPLETE event marks the end of read.
 * @param  callback   
 * @param  con_handle
 * @param  start_handle
 * @param  end_handle
 * @param  uuid128
 * @return status BTSTACK_MEMORY_ALLOC_FAILED, if no GATT client for con_handle is found 
 *                GATT_CLIENT_IN_WRONG_STATE , if GATT client is not ready
 *                ERROR_CODE_SUCCESS         , if query is successfully registered 
 */
uint8_t gatt_client_read_value_of_characteristics_by_uuid128(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t start_handle, uint16_t end_handle, const uint8_t * uuid128);

/** 
 * @brief Reads the long characteristic value using the characteristic's value handle. 
 * The value will be returned in several blobs. 
 * For each blob, a GATT_EVENT_LONG_CHARACTERISTIC_VALUE_QUERY_RESULT event with updated value offset will be emitted.
 * The GATT_EVENT_QUERY_COMPLETE event marks the end of read.
 * @param  callback   
 * @param  con_handle
 * @param  characteristic 
 * @return status BTSTACK_MEMORY_ALLOC_FAILED, if no GATT client for con_handle is found 
 *                GATT_CLIENT_IN_WRONG_STATE , if GATT client is not ready
 *                ERROR_CODE_SUCCESS         , if query is successfully registered 
 */
uint8_t gatt_client_read_long_value_of_characteristic(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_t * characteristic);

/** 
 * @brief Reads the long characteristic value using the characteristic's value handle. 
 * The value will be returned in several blobs. 
 * For each blob, a GATT_EVENT_LONG_CHARACTERISTIC_VALUE_QUERY_RESULT event with updated value offset will be emitted.
 * The GATT_EVENT_QUERY_COMPLETE event marks the end of read.
 * @param  callback   
 * @param  con_handle
 * @param  value_handle 
 * @return status BTSTACK_MEMORY_ALLOC_FAILED, if no GATT client for con_handle is found 
 *                GATT_CLIENT_IN_WRONG_STATE , if GATT client is not ready
 *                ERROR_CODE_SUCCESS         , if query is successfully registered 
 */
uint8_t gatt_client_read_long_value_of_characteristic_using_value_handle(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle);

/** 
 * @brief Reads the long characteristic value using the characteristic's value handle. 
 * The value will be returned in several blobs. 
 * For each blob, a GATT_EVENT_LONG_CHARACTERISTIC_VALUE_QUERY_RESULT event with updated value offset will be emitted.
 * The GATT_EVENT_QUERY_COMPLETE event marks the end of read.
 * @param  callback   
 * @param  con_handle
 * @param  value_handle
 * @param  offset 
 * @return status BTSTACK_MEMORY_ALLOC_FAILED, if no GATT client for con_handle is found 
 *                GATT_CLIENT_IN_WRONG_STATE , if GATT client is not ready
 *                ERROR_CODE_SUCCESS         , if query is successfully registered 
 */
uint8_t gatt_client_read_long_value_of_characteristic_using_value_handle_with_offset(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle, uint16_t offset);

/*
 * @brief Read multiple characteristic values.
 * The all results are emitted via single GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT event, 
 * followed by the GATT_EVENT_QUERY_COMPLETE event, which marks the end of read.
 * @param  callback   
 * @param  con_handle
 * @param  num_value_handles 
 * @param  value_handles list of handles 
 * @return status BTSTACK_MEMORY_ALLOC_FAILED, if no GATT client for con_handle is found 
 *                GATT_CLIENT_IN_WRONG_STATE , if GATT client is not ready
 *                ERROR_CODE_SUCCESS         , if query is successfully registered 
 */
uint8_t gatt_client_read_multiple_characteristic_values(btstack_packet_handler_t callback, hci_con_handle_t con_handle, int num_value_handles, uint16_t * value_handles);

/*
 * @brief Read multiple varaible characteristic values. Only supported over LE Enhanced Bearer
 * The all results are emitted via single GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT event,
 * followed by the GATT_EVENT_QUERY_COMPLETE event, which marks the end of read.
 * @param  callback
 * @param  con_handle
 * @param  num_value_handles
 * @param  value_handles list of handles
 * @return status BTSTACK_MEMORY_ALLOC_FAILED, if no GATT client for con_handle is found
 *                GATT_CLIENT_IN_WRONG_STATE , if GATT client is not ready
 *                ERROR_CODE_SUCCESS         , if query is successfully registered
 */
uint8_t gatt_client_read_multiple_variable_characteristic_values(btstack_packet_handler_t callback, hci_con_handle_t con_handle, int num_value_handles, uint16_t * value_handles);

/**
 * @brief Writes the characteristic value using the characteristic's value handle without 
 * an acknowledgment that the write was successfully performed.
 * @param  con_handle   
 * @param  value_handle
 * @param  value_length
 * @param  value is copied on success and does not need to be retained
 * @return status BTSTACK_MEMORY_ALLOC_FAILED, if no GATT client for con_handle is found 
 *                GATT_CLIENT_IN_WRONG_STATE , if GATT client is not ready
 *                BTSTACK_ACL_BUFFERS_FULL   , if L2CAP cannot send, there are no free ACL slots
 *                ERROR_CODE_SUCCESS         , if query is successfully registered 
 */
uint8_t gatt_client_write_value_of_characteristic_without_response(hci_con_handle_t con_handle, uint16_t value_handle, uint16_t value_length, uint8_t * value);

/** 
 * @brief Writes the authenticated characteristic value using the characteristic's value handle 
 * without an acknowledgment that the write was successfully performed.
 * @note GATT_EVENT_QUERY_COMPLETE is emitted with ATT_ERROR_SUCCESS for success,
 * or ATT_ERROR_BONDING_INFORMATION_MISSING if there is no bonding information stored.
 * @param  callback   
 * @param  con_handle
 * @param  value_handle
 * @param  message_len
 * @param  message is not copied, make sure memory is accessible until write is done
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER                  if no HCI connection for con_handle is found 
 *                BTSTACK_MEMORY_ALLOC_FAILED                               if no GATT client for con_handle could be allocated 
 *                GATT_CLIENT_IN_WRONG_STATE                                if GATT client is not ready
 *                ERROR_CODE_SUCCESS                                        if query is successfully registered
 */
uint8_t gatt_client_signed_write_without_response(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle, uint16_t message_len, uint8_t * message);

/** 
 * @brief Writes the characteristic value using the characteristic's value handle. 
 * The GATT_EVENT_QUERY_COMPLETE event marks the end of write. 
 * The write is successfully performed, if the event's att_status field is set to 
 * ATT_ERROR_SUCCESS (see bluetooth.h for ATT_ERROR codes).
 * @param  callback   
 * @param  con_handle
 * @param  value_handle
 * @param  value_length
 * @param  value is not copied, make sure memory is accessible until write is done, i.e. GATT_EVENT_QUERY_COMPLETE is received
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER                  if no HCI connection for con_handle is found 
 *                BTSTACK_MEMORY_ALLOC_FAILED                               if no GATT client for con_handle could be allocated 
 *                GATT_CLIENT_IN_WRONG_STATE                                if GATT client is not ready
 *                ERROR_CODE_SUCCESS                                        if query is successfully registered
 */
uint8_t gatt_client_write_value_of_characteristic(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle, uint16_t value_length, uint8_t * value);

/** 
 * @brief Writes the characteristic value using the characteristic's value handle. 
 * The GATT_EVENT_QUERY_COMPLETE event marks the end of write. 
 * The write is successfully performed if the event's att_status field is set to ATT_ERROR_SUCCESS (see bluetooth.h for ATT_ERROR codes).
 * @param  callback   
 * @param  con_handle
 * @param  value_handle
 * @param  value_length
 * @param  value is not copied, make sure memory is accessible until write is done, i.e. GATT_EVENT_QUERY_COMPLETE is received
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER                  if no HCI connection for con_handle is found 
 *                BTSTACK_MEMORY_ALLOC_FAILED                               if no GATT client for con_handle could be allocated 
 *                GATT_CLIENT_IN_WRONG_STATE                                if GATT client is not ready
 *                ERROR_CODE_SUCCESS                                        if query is successfully registered
 */
uint8_t gatt_client_write_long_value_of_characteristic(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle, uint16_t value_length, uint8_t * value);

/** 
 * @brief Writes the characteristic value using the characteristic's value handle. 
 * The GATT_EVENT_QUERY_COMPLETE event marks the end of write. 
 * The write is successfully performed if the event's att_status field is set to ATT_ERROR_SUCCESS (see bluetooth.h for ATT_ERROR codes).
 * @param  callback   
 * @param  con_handle
 * @param  value_handle
 * @param  offset of value
 * @param  value_length
 * @param  value is not copied, make sure memory is accessible until write is done, i.e. GATT_EVENT_QUERY_COMPLETE is received
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER                  if no HCI connection for con_handle is found 
 *                BTSTACK_MEMORY_ALLOC_FAILED                               if no GATT client for con_handle could be allocated 
 *                GATT_CLIENT_IN_WRONG_STATE                                if GATT client is not ready
 *                ERROR_CODE_SUCCESS                                        if query is successfully registered
 */
uint8_t gatt_client_write_long_value_of_characteristic_with_offset(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle, uint16_t offset, uint16_t value_length, uint8_t * value);

/** 
 * @brief Writes of the long characteristic value using the characteristic's value handle. 
 * It uses server response to validate that the write was correctly received. 
 * The GATT_EVENT_QUERY_COMPLETE EVENT marks the end of write.
 * The write is successfully performed, if the event's att_status field is set to ATT_ERROR_SUCCESS (see bluetooth.h for ATT_ERROR codes). 
 * @param  callback   
 * @param  con_handle
 * @param  value_handle
 * @param  value_length
 * @param  value is not copied, make sure memory is accessible until write is done, i.e. GATT_EVENT_QUERY_COMPLETE is received
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER                  if no HCI connection for con_handle is found 
 *                BTSTACK_MEMORY_ALLOC_FAILED                               if no GATT client for con_handle could be allocated 
 *                GATT_CLIENT_IN_WRONG_STATE                                if GATT client is not ready
 *                ERROR_CODE_SUCCESS                                        if query is successfully registered
 */
uint8_t gatt_client_reliable_write_long_value_of_characteristic(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle, uint16_t value_length, uint8_t * value);

/** 
 * @brief Reads the characteristic descriptor using its handle. 
 * If the characteristic descriptor is found, a GATT_EVENT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT event will be emitted.
 * The GATT_EVENT_QUERY_COMPLETE event marks the end of read.
 * @param  callback   
 * @param  con_handle
 * @param  descriptor
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER                  if no HCI connection for con_handle is found 
 *                BTSTACK_MEMORY_ALLOC_FAILED                               if no GATT client for con_handle could be allocated 
 *                GATT_CLIENT_IN_WRONG_STATE                                if GATT client is not ready
 *                ERROR_CODE_SUCCESS                                        if query is successfully registered
 */
uint8_t gatt_client_read_characteristic_descriptor(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_descriptor_t * descriptor);

/** 
 * @brief Reads the characteristic descriptor using its handle. 
 * If the characteristic descriptor is found, a GATT_EVENT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT event will be emitted.
 * The GATT_EVENT_QUERY_COMPLETE event marks the end of read.
 * @param  callback   
 * @param  con_handle
 * @param  descriptor
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER                  if no HCI connection for con_handle is found 
 *                BTSTACK_MEMORY_ALLOC_FAILED                               if no GATT client for con_handle could be allocated 
 *                GATT_CLIENT_IN_WRONG_STATE                                if GATT client is not ready
 *                ERROR_CODE_SUCCESS                                        if query is successfully registered
 */
uint8_t gatt_client_read_characteristic_descriptor_using_descriptor_handle(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t descriptor_handle);

/** 
 * @brief Reads the long characteristic descriptor using its handle. It will be returned in several blobs. 
 * For each blob, a GATT_EVENT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT event will be emitted.
 * The GATT_EVENT_QUERY_COMPLETE event marks the end of read.
 * @param  callback   
 * @param  con_handle
 * @param  descriptor
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER                  if no HCI connection for con_handle is found 
 *                BTSTACK_MEMORY_ALLOC_FAILED                               if no GATT client for con_handle could be allocated 
 *                GATT_CLIENT_IN_WRONG_STATE                                if GATT client is not ready
 *                ERROR_CODE_SUCCESS                                        if query is successfully registered
 */
uint8_t gatt_client_read_long_characteristic_descriptor(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_descriptor_t * descriptor);

/** 
 * @brief Reads the long characteristic descriptor using its handle. It will be returned in several blobs. 
 * For each blob, a GATT_EVENT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT event will be emitted.
 * The GATT_EVENT_QUERY_COMPLETE event marks the end of read.
 * @param  callback   
 * @param  con_handle
 * @param  descriptor_handle
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER                  if no HCI connection for con_handle is found 
 *                BTSTACK_MEMORY_ALLOC_FAILED                               if no GATT client for con_handle could be allocated 
 *                GATT_CLIENT_IN_WRONG_STATE                                if GATT client is not ready
 *                ERROR_CODE_SUCCESS                                        if query is successfully registered
 */
uint8_t gatt_client_read_long_characteristic_descriptor_using_descriptor_handle(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t descriptor_handle);

/** 
 * @brief Reads the long characteristic descriptor using its handle. It will be returned in several blobs. 
 * For each blob, a GATT_EVENT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT event will be emitted.
 * The GATT_EVENT_QUERY_COMPLETE event marks the end of read.
 * @param  callback   
 * @param  con_handle
 * @param  descriptor_handle
 * @param  offset
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER                  if no HCI connection for con_handle is found 
 *                BTSTACK_MEMORY_ALLOC_FAILED                               if no GATT client for con_handle could be allocated 
 *                GATT_CLIENT_IN_WRONG_STATE                                if GATT client is not ready
 *                ERROR_CODE_SUCCESS                                        if query is successfully registered
 */
uint8_t gatt_client_read_long_characteristic_descriptor_using_descriptor_handle_with_offset(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t descriptor_handle, uint16_t offset);

/** 
 * @brief Writes the characteristic descriptor using its handle. 
 * The GATT_EVENT_QUERY_COMPLETE event marks the end of write. 
 * The write is successfully performed if the event's att_status field is set to ATT_ERROR_SUCCESS (see bluetooth.h for ATT_ERROR codes).
 * @param  callback   
 * @param  con_handle
 * @param  descriptor
 * @param  value_length
 * @param  value is not copied, make sure memory is accessible until write is done, i.e. GATT_EVENT_QUERY_COMPLETE is received
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER                  if no HCI connection for con_handle is found 
 *                BTSTACK_MEMORY_ALLOC_FAILED                               if no GATT client for con_handle could be allocated 
 *                GATT_CLIENT_IN_WRONG_STATE                                if GATT client is not ready
 *                ERROR_CODE_SUCCESS                                        if query is successfully registered
 */
uint8_t gatt_client_write_characteristic_descriptor(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_descriptor_t * descriptor, uint16_t value_length, uint8_t * value);

/** 
 * @brief Writes the characteristic descriptor using its handle. 
 * The GATT_EVENT_QUERY_COMPLETE event marks the end of write. 
 * The write is successfully performed if the event's att_status field is set to ATT_ERROR_SUCCESS (see bluetooth.h for ATT_ERROR codes).
 * @param  callback   
 * @param  con_handle
 * @param  descriptor_handle
 * @param  value_length
 * @param  value is not copied, make sure memory is accessible until write is done, i.e. GATT_EVENT_QUERY_COMPLETE is received
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER                  if no HCI connection for con_handle is found 
 *                BTSTACK_MEMORY_ALLOC_FAILED                               if no GATT client for con_handle could be allocated 
 *                GATT_CLIENT_IN_WRONG_STATE                                if GATT client is not ready
 *                ERROR_CODE_SUCCESS                                        if query is successfully registered
 */
uint8_t gatt_client_write_characteristic_descriptor_using_descriptor_handle(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t descriptor_handle, uint16_t value_length, uint8_t * value);

/** 
 * @brief Writes the characteristic descriptor using its handle. 
 * The GATT_EVENT_QUERY_COMPLETE event marks the end of write. 
 * The write is successfully performed if the event's att_status field is set to ATT_ERROR_SUCCESS (see bluetooth.h for ATT_ERROR codes).
 * @param  callback   
 * @param  con_handle
 * @param  descriptor
 * @param  value_length
 * @param  value is not copied, make sure memory is accessible until write is done, i.e. GATT_EVENT_QUERY_COMPLETE is received
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER                  if no HCI connection for con_handle is found 
 *                BTSTACK_MEMORY_ALLOC_FAILED                               if no GATT client for con_handle could be allocated 
 *                GATT_CLIENT_IN_WRONG_STATE                                if GATT client is not ready
 *                ERROR_CODE_SUCCESS                                        if query is successfully registered
 */
uint8_t gatt_client_write_long_characteristic_descriptor(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_descriptor_t * descriptor, uint16_t value_length, uint8_t * value);

/** 
 * @brief Writes the characteristic descriptor using its handle. 
 * The GATT_EVENT_QUERY_COMPLETE event marks the end of write. 
 * The write is successfully performed if the event's att_status field is set to ATT_ERROR_SUCCESS (see bluetooth.h for ATT_ERROR codes).
 * @param  callback   
 * @param  con_handle
 * @param  descriptor_handle
 * @param  value_length
 * @param  value is not copied, make sure memory is accessible until write is done, i.e. GATT_EVENT_QUERY_COMPLETE is received
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER                  if no HCI connection for con_handle is found 
 *                BTSTACK_MEMORY_ALLOC_FAILED                               if no GATT client for con_handle could be allocated 
 *                GATT_CLIENT_IN_WRONG_STATE                                if GATT client is not ready
 *                ERROR_CODE_SUCCESS                                        if query is successfully registered
 */
uint8_t gatt_client_write_long_characteristic_descriptor_using_descriptor_handle(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t descriptor_handle, uint16_t value_length, uint8_t * value);

/** 
 * @brief Writes the characteristic descriptor using its handle. 
 * The GATT_EVENT_QUERY_COMPLETE event marks the end of write. 
 * The write is successfully performed if the event's att_status field is set to ATT_ERROR_SUCCESS (see bluetooth.h for ATT_ERROR codes).
 * @param  callback   
 * @param  con_handle
 * @param  descriptor_handle
 * @param  offset of value
 * @param  value_length
 * @param  value is not copied, make sure memory is accessible until write is done, i.e. GATT_EVENT_QUERY_COMPLETE is received
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER                  if no HCI connection for con_handle is found 
 *                BTSTACK_MEMORY_ALLOC_FAILED                               if no GATT client for con_handle could be allocated 
 *                GATT_CLIENT_IN_WRONG_STATE                                if GATT client is not ready
 *                ERROR_CODE_SUCCESS                                        if query is successfully registered
 */
uint8_t gatt_client_write_long_characteristic_descriptor_using_descriptor_handle_with_offset(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t descriptor_handle, uint16_t offset, uint16_t value_length, uint8_t * value);

/** 
 * @brief Writes the client characteristic configuration of the specified characteristic. 
 * It is used to subscribe for notifications or indications of the characteristic value. 
 * For notifications or indications specify: GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION
 * resp. GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_INDICATION as configuration value.
 * The GATT_EVENT_QUERY_COMPLETE event marks the end of write. 
 * The write is successfully performed if the event's att_status field is set to ATT_ERROR_SUCCESS (see bluetooth.h for ATT_ERROR codes).
 * @param  callback
 * @param  con_handle
 * @param  characteristic
 * @param  configuration                                                    GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_INDICATION
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER                  if no HCI connection for con_handle is found 
 *                BTSTACK_MEMORY_ALLOC_FAILED                               if no GATT client for con_handle could be allocated 
 *                GATT_CLIENT_IN_WRONG_STATE                                if GATT client is not ready
 *                GATT_CLIENT_CHARACTERISTIC_NOTIFICATION_NOT_SUPPORTED     if configuring notification, but characteristic has no notification property set
 *                GATT_CLIENT_CHARACTERISTIC_INDICATION_NOT_SUPPORTED       if configuring indication, but characteristic has no indication property set
 *                ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE         if configuration is invalid
 *                ERROR_CODE_SUCCESS                                        if query is successfully registered
 */
uint8_t gatt_client_write_client_characteristic_configuration(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_t * characteristic, uint16_t configuration);

/**
 * @brief Register for notifications and indications of a characteristic enabled by 
 * the gatt_client_write_client_characteristic_configuration function.
 * @param notification struct used to store registration
 * @param callback
 * @param con_handle or GATT_CLIENT_ANY_CONNECTION to receive updates from all connected devices
 * @param characteristic or NULL to receive updates for all characteristics
 */
void gatt_client_listen_for_characteristic_value_updates(gatt_client_notification_t * notification, btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_t * characteristic);

/**
 * @brief Stop listening to characteristic value updates registered with
 * the gatt_client_listen_for_characteristic_value_updates function.
 * @param notification struct used in gatt_client_listen_for_characteristic_value_updates
 */
void gatt_client_stop_listening_for_characteristic_value_updates(gatt_client_notification_t * notification);

/**
 * @brief Transactional write. It can be called as many times as it is needed to write the characteristics within the same transaction. 
 * Call the gatt_client_execute_write function to commit the transaction.
 * @param  callback   
 * @param  con_handle
 * @param  attribute_handle
 * @param  offset of value
 * @param  value_length
 * @param  value is not copied, make sure memory is accessible until write is done, i.e. GATT_EVENT_QUERY_COMPLETE is received
 */
uint8_t gatt_client_prepare_write(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t attribute_handle, uint16_t offset, uint16_t value_length, uint8_t * value);

/**
 * @brief Commit transactional write. GATT_EVENT_QUERY_COMPLETE is received.
 * @param  callback   
 * @param  con_handle
 * @return status
 */
uint8_t gatt_client_execute_write(btstack_packet_handler_t callback, hci_con_handle_t con_handle);

/**
 * @brief Abort transactional write. GATT_EVENT_QUERY_COMPLETE is received.
 * @param  callback   
 * @param  con_handle
 * @return status
 */
uint8_t gatt_client_cancel_write(btstack_packet_handler_t callback, hci_con_handle_t con_handle);

/**
 * @brief Request callback when regular gatt query can be sent
 * @note callback might happen during call to this function
 * @param callback_registration to point to callback function and context information
 * @param con_handle
 * @return ERROR_CODE_SUCCESS if ok, ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if handle unknown, and ERROR_CODE_COMMAND_DISALLOWED if callback already registered
 */
uint8_t gatt_client_request_to_send_gatt_query(btstack_context_callback_registration_t * callback_registration, hci_con_handle_t con_handle);

/**
 * @brief Request callback when writing characteristic value without response is possible
 * @note callback might happen during call to this function
 * @param callback_registration to point to callback function and context information
 * @param con_handle
 * @return ERROR_CODE_SUCCESS if ok, ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if handle unknown, and ERROR_CODE_COMMAND_DISALLOWED if callback already registered
 */
uint8_t gatt_client_request_to_write_without_response(btstack_context_callback_registration_t * callback_registration, hci_con_handle_t con_handle);


// the following functions are marked as deprecated and will be removed eventually
/**
 * @brief Requests GATT_EVENT_CAN_WRITE_WITHOUT_RESPONSE that guarantees
 * a single successful gatt_client_write_value_of_characteristic_without_response call.
 * @deprecated please use gatt_client_request_to_write_without_response instead
 * @param  callback
 * @param  con_handle
 * @return status
 */
uint8_t gatt_client_request_can_write_without_response_event(btstack_packet_handler_t callback, hci_con_handle_t con_handle);

Device Database API {#sec:le_device_db_api}

le_device_db.h

/**
 * @brief init
 */
void le_device_db_init(void);


/**
 * @brief sets local bd addr. allows for db per Bluetooth controller
 * @param bd_addr
 */
void le_device_db_set_local_bd_addr(bd_addr_t bd_addr);

/**
 * @brief add device to db
 * @param addr_type, address of the device
 * @param irk of the device
 * @return index if successful, -1 otherwise
 */
int le_device_db_add(int addr_type, bd_addr_t addr, sm_key_t irk);

/**
 * @brief get number of devices in db
 * @return number of device in db
 */
int le_device_db_count(void);

/**
 * @brief get max number of devices in db for enumeration
 * @return max number of device in db
 */
int le_device_db_max_count(void);

/**
 * @brief get device information: addr type and address needed to identify device
 * @param index
 * @param addr_type, address of the device as output
 * @param irk of the device
 */
void le_device_db_info(int index, int * addr_type, bd_addr_t addr, sm_key_t irk);


/**
 * @brief set remote encryption info
 * @brief index
 * @brief ediv 
 * @brief rand
 * @brief ltk
 * @brief key size
 * @brief authenticated
 * @brief authorized
 * @breif secure_connection
 */
void le_device_db_encryption_set(int index, uint16_t ediv, uint8_t rand[8], sm_key_t ltk, int key_size, int authenticated, int authorized, int secure_connection);

/**
 * @brief get remote encryption info
 * @brief index
 * @brief ediv 
 * @brief rand
 * @brief ltk
 * @brief key size
 * @brief authenticated
 * @brief authorized
 * @breif secure_connection
 */
void le_device_db_encryption_get(int index, uint16_t * ediv, uint8_t rand[8], sm_key_t ltk,  int * key_size, int * authenticated, int * authorized, int * secure_connection);

#ifdef ENABLE_LE_SIGNED_WRITE

/**
 * @brief set local signing key for this device
 * @param index
 * @param signing key as input
 */
void le_device_db_local_csrk_set(int index, sm_key_t csrk);

/**
 * @brief get local signing key for this device
 * @param index
 * @param signing key as output
 */
void le_device_db_local_csrk_get(int index, sm_key_t csrk);

/**
 * @brief set remote signing key for this device
 * @param index
 * @param signing key as input
 */
void le_device_db_remote_csrk_set(int index, sm_key_t csrk);

/**
 * @brief get remote signing key for this device
 * @param index
 * @param signing key as output
 */
void le_device_db_remote_csrk_get(int index, sm_key_t csrk);

/**
 * @brief query last used/seen signing counter
 * @param index
 * @return next expected counter, 0 after devices was added
 */
uint32_t le_device_db_remote_counter_get(int index);

/**
 * @brief update signing counter
 * @param index
 * @param counter to store
 */
void le_device_db_remote_counter_set(int index, uint32_t counter);

/**
 * @brief query last used/seen signing counter
 * @param index
 * @return next expected counter, 0 after devices was added
 */
uint32_t le_device_db_local_counter_get(int index);

/**
 * @brief update signing counter
 * @param index
 * @param counter to store
 */
void le_device_db_local_counter_set(int index, uint32_t counter);

#endif

/**
 * @brief free device
 * @param index
 */
void le_device_db_remove(int index);

void le_device_db_dump(void);

Device Database TLV API {#sec:le_device_db_tlv_api}

le_device_db_tlv.h

/**
 * @brief configure le device db for use with btstack tlv instance
 * @param btstack_tlv_impl to use
 * @param btstack_tlv_context
 */

void le_device_db_tlv_configure(const btstack_tlv_t * btstack_tlv_impl, void * btstack_tlv_context);

Security Manager API {#sec:sm_api}

sm.h

/**
 * @brief Initializes the Security Manager, connects to L2CAP
 */
void sm_init(void);

/**
 * @brief Set secret ER key for key generation as described in Core V4.0, Vol 3, Part G, 5.2.2
 * @note If not set and btstack_tlv is configured, ER key is generated and stored in TLV by SM
 * @param er key
 */
void sm_set_er(sm_key_t er);

/**
 * @brief Set secret IR key for key generation as described in Core V4.0, Vol 3, Part G, 5.2.2
 * @note If not set and btstack_tlv is configured, IR key is generated and stored in TLV by SM
 * @param ir key
 */
void sm_set_ir(sm_key_t ir);

/**
 * @brief Registers OOB Data Callback. The callback should set the oob_data and return 1 if OOB data is availble
 * @param get_oob_data_callback
 */
void sm_register_oob_data_callback( int (*get_oob_data_callback)(uint8_t address_type, bd_addr_t addr, uint8_t * oob_data));

/**
 * @brief Add event packet handler. 
 * @param callback_handler
 */
void sm_add_event_handler(btstack_packet_callback_registration_t * callback_handler);

/**
 * @brief Remove event packet handler.
 * @param callback_handler
 */
void sm_remove_event_handler(btstack_packet_callback_registration_t * callback_handler);

/**
 * @brief Limit the STK generation methods. Bonding is stopped if the resulting one isn't in the list
 * @param OR combination of SM_STK_GENERATION_METHOD_ 
 */
void sm_set_accepted_stk_generation_methods(uint8_t accepted_stk_generation_methods);

/**
 * @brief Set the accepted encryption key size range. Bonding is stopped if the result isn't within the range
 * @param min_size (default 7)
 * @param max_size (default 16)
 */
void sm_set_encryption_key_size_range(uint8_t min_size, uint8_t max_size);

/**
 * @brief Sets the requested authentication requirements, bonding yes/no, MITM yes/no, SC yes/no, keypress yes/no
 * @param OR combination of SM_AUTHREQ_ flags
 */
void sm_set_authentication_requirements(uint8_t auth_req);

/**
 * @brief Sets the available IO Capabilities
 * @param IO_CAPABILITY_
 */
void sm_set_io_capabilities(io_capability_t io_capability);

/**
 * @brief Enable/disable Secure Connections Mode only
 * @param enable secure connections only mode
 */
void sm_set_secure_connections_only_mode(bool enable);

/**
 * @brief Let Peripheral request an encrypted connection right after connecting
 * @param enable
 * @note Not used normally. Bonding is triggered by access to protected attributes in ATT Server
 */
void sm_set_request_security(bool enable);

/** 
 * @brief Trigger Security Request
 * @deprecated please use sm_request_pairing instead
 */
void sm_send_security_request(hci_con_handle_t con_handle);

/**
 * @brief Decline bonding triggered by event before
 * @param con_handle
 */
void sm_bonding_decline(hci_con_handle_t con_handle);

/**
 * @brief Confirm Just Works bonding 
 * @param con_handle
 */
void sm_just_works_confirm(hci_con_handle_t con_handle);

/**
 * @brief Confirm value from SM_EVENT_NUMERIC_COMPARISON_REQUEST for Numeric Comparison bonding 
 * @param con_handle
 */
void sm_numeric_comparison_confirm(hci_con_handle_t con_handle);

/**
 * @brief Reports passkey input by user
 * @param con_handle
 * @param passkey in [0..999999]
 */
void sm_passkey_input(hci_con_handle_t con_handle, uint32_t passkey);

/**
 * @brief Send keypress notification for keyboard only devices
 * @param con_handle
 * @param action see SM_KEYPRESS_* in bluetooth.h
 */
void sm_keypress_notification(hci_con_handle_t con_handle, uint8_t action);

/**
 * @brief Used by att_server.c and gatt_client.c to request user authentication
 * @param con_handle
 */
void sm_request_pairing(hci_con_handle_t con_handle);

/**
 * @brief Report user authorization decline.
 * @param con_handle
 */
void sm_authorization_decline(hci_con_handle_t con_handle);

/**
 * @brief Report user authorization grant.
 * @param con_handle
 */
void sm_authorization_grant(hci_con_handle_t con_handle);

/**
 * @brief Support for signed writes, used by att_server.
 * @return ready
 */
int sm_cmac_ready(void);

/**
 * @brief Support for signed writes, used by att_server.
 * @note Message is in little endian to allows passing in ATT PDU without flipping. 
 * @note signing data: [opcode, attribute_handle, message, sign_counter]
 * @note calculated hash in done_callback is big endian and has 16 byte. 
 * @param key
 * @param opcde
 * @param attribute_handle
 * @param message_len
 * @param message
 * @param sign_counter
 */
void sm_cmac_signed_write_start(const sm_key_t key, uint8_t opcode, uint16_t attribute_handle, uint16_t message_len, const uint8_t * message, uint32_t sign_counter, void (*done_callback)(uint8_t * hash));

/**
 * @brief Match address against bonded devices
 * @param address_type
 * @param address
 * @return 0 if successfully added to lookup queue
 * @note Triggers SM_IDENTITY_RESOLVING_* events
 */
int sm_address_resolution_lookup(uint8_t address_type, bd_addr_t address);

/**
 * @brief Get Identity Resolving state
 * @param con_handle
 * @return irk_lookup_state_t
 * @note return IRK_LOOKUP_IDLE if connection does not exist
 */
irk_lookup_state_t sm_identity_resolving_state(hci_con_handle_t con_handle);

/**
 * @brief Identify device in LE Device DB.
 * @param con_handle
 * @return index from le_device_db or -1 if not found/identified
 */
int sm_le_device_index(hci_con_handle_t con_handle);

/**
 * @brief Get LTK for encrypted connection
 * @param con_handle
 * @param ltk buffer to store long term key
 * @return ERROR_CODE_SUCCESS ok
 *         ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if no connection for this con handle exists
 *         ERROR_CODE_PIN_OR_KEY_MISSING if connection is not encrypted
 */
uint8_t sm_get_ltk(hci_con_handle_t con_handle, sm_key_t ltk);

/**
 * @brief Use fixec passkey for Legacy and SC instead of generating a random number
 * @note Can be used to improve security over Just Works if no keyboard or displary are present and 
 *       individual random passkey can be printed on the device during production
 * @param passkey
 */
void sm_use_fixed_passkey_in_display_role(uint32_t passkey);

/**
 * @brief Allow connection re-encryption in Peripheral (Responder) role for LE Legacy Pairing 
 *       without entry for Central device stored in LE Device DB
 * @note BTstack in Peripheral Role (Responder) supports LE Legacy Pairing without a persistent LE Device DB as
 *       the LTK is reconstructed from a local secret IRK and EDIV + Random stored on Central (Initiator) device
 *       On the downside, it's not really possible to delete a pairing if this is enabled.
 * @param allow encryption using reconstructed LTK without stored entry (Default: 1)
 */
void sm_allow_ltk_reconstruction_without_le_device_db_entry(int allow);

/**
 * @brief Generate OOB data for LE Secure Connections
 * @note This generates a 128 bit random number ra and then calculates Ca = f4(PKa, PKa, ra, 0)
 *       New OOB data should be generated for each pairing. Ra is used for subsequent OOB pairings
 * @param callback
 * @return status
 */
uint8_t sm_generate_sc_oob_data(void (*callback)(const uint8_t * confirm_value, const uint8_t * random_value));

/**
 * @brief Registers OOB Data Callback for LE Secure Conections. The callback should set all arguments and return 1 if OOB data is availble
 * @note the oob_sc_local_random usually is the random_value returend by sm_generate_sc_oob_data
 * @param get_oob_data_callback
 */
void sm_register_sc_oob_data_callback( int (*get_sc_oob_data_callback)(uint8_t address_type, bd_addr_t addr, uint8_t * oob_sc_peer_confirm, uint8_t * oob_sc_peer_random));

/**
 * @bbrief Register LTK Callback that allows to provide a custom LTK on re-encryption. The callback returns true if LTK was modified
 * @param get_ltk_callback
 */
void sm_register_ltk_callback( bool (*get_ltk_callback)(hci_con_handle_t con_handle, uint8_t address_type, bd_addr_t addr, uint8_t * ltk));

Audio Interface API {#sec:btstack_audio_api}

btstack_audio.h : Abstraction layer for 16-bit audio playback and recording within BTstack.

Most embedded implementations, e.g. the one for ESP32, use a single I2S interface which requires that the sample rate is the same for sink and source roles

typedef struct {

    /**
     * @brief Setup audio codec for specified samplerate and number of channels
     * @param Channels (1=mono, 2=stereo)
     * @param Sample rate
     * @param Playback callback
     * @return 1 on success
     */
    int (*init)(uint8_t channels,
                uint32_t samplerate, 
                void (*playback) (int16_t * buffer, uint16_t num_samples));

    /**
     * @brief Get the current playback sample rate, may differ from the
     *        specified sample rate
     */
    uint32_t (*get_samplerate)(void);

    /**
     * @brief Set volume
     * @param Volume 0..127
     */
    void (*set_volume)(uint8_t volume);

    /**
     * @brief Start stream
     */
    void (*start_stream)(void);

    /** 
     * @brief Stop stream
     */
    void (*stop_stream)(void);

    /**
     * @brief Close audio codec
     */
    void (*close)(void);

} btstack_audio_sink_t;


typedef struct {

    /**
     * @brief Setup audio codec for specified samplerate and number of channels
     * @param Channels (1=mono, 2=stereo)
     * @param Sample rate
     * @param Recording callback
     * @return 1 on success
     */
    int (*init)(uint8_t channels,
                uint32_t samplerate, 
                void (*recording)(const int16_t * buffer, uint16_t num_samples));

    /**
     * @brief Get the current recording sample rate, may differ from the
     *        specified sameple rate
     */
    uint32_t (*get_samplerate)(void);

    /**
     * @brief Set Gain
     * @param Gain 0..127
     */
    void (*set_gain)(uint8_t gain);

    /**
     * @brief Start stream
     */
    void (*start_stream)(void);

    /** 
     * @brief Stop stream
     */
    void (*stop_stream)(void);

    /**
     * @brief Close audio codec
     */
    void (*close)(void);

} btstack_audio_source_t;


/**
 * @brief Get BTstack Audio Sink Instance
 * @return btstack_audio_sink implementation
 */
const btstack_audio_sink_t * btstack_audio_sink_get_instance(void);

/**
 * @brief Get BTstack Audio Source Instance
 * @return btstack_audio_source implementation
 */
const btstack_audio_source_t * btstack_audio_source_get_instance(void);


/**
 * @brief Get BTstack Audio Sink Instance
 * @param btstack_audio_sink implementation
 */
void btstack_audio_sink_set_instance(const btstack_audio_sink_t * audio_sink_impl);

/**
 * @brief Get BTstack Audio Source Instance
 * @param btstack_audio_source implementation
 */
void btstack_audio_source_set_instance(const btstack_audio_source_t * audio_source_impl);


// common implementations
const btstack_audio_sink_t *   btstack_audio_portaudio_sink_get_instance(void);
const btstack_audio_source_t * btstack_audio_portaudio_source_get_instance(void);

const btstack_audio_sink_t *   btstack_audio_embedded_sink_get_instance(void);
const btstack_audio_source_t * btstack_audio_embedded_source_get_instance(void);

const btstack_audio_sink_t *    btstack_audio_esp32_sink_get_instance(void);
const btstack_audio_source_t *  btstack_audio_esp32_source_get_instance(void);

// platform-specific extension
void btstack_audio_portaudio_sink_set_device(const char * device_name);
void btstack_audio_portaudio_source_set_device(const char * device_name);

base64 Decoder API {#sec:btstack_base64_decoder_api}

btstack_base64_decoder.h

#define BTSTACK_BASE64_DECODER_MORE     -1
#define BTSTACK_BASE64_DECODER_COMPLETE -2
#define BTSTACK_BASE64_DECODER_INVALID  -3
#define BTSTACK_BASE64_DECODER_FULL     -4

/**
 * @brief Initialize base64 decoder
 * @param context
 */
void btstack_base64_decoder_init(btstack_base64_decoder_t * context);

/**
 * @brief Decode single byte
 * @brief context
 * @return value, or BTSTACK_BASE64_DECODER_MORE, BTSTACK_BASE64_DECODER_COMPLETE, BTSTACK_BASE64_DECODER_INVALID
 */
int  btstack_base64_decoder_process_byte(btstack_base64_decoder_t * context, uint8_t c);

/**
 * @brief Decode block
 * @brief input_data base64 encoded message
 * @brief input_size
 * @breif output_buffer
 * @brief output_max_size
 * @return output_size or BTSTACK_BASE64_DECODER_INVALID, BTSTACK_BASE64_DECODER_FULL
 */
int btstack_base64_decoder_process_block(const uint8_t * input_data, uint32_t input_size, uint8_t * output_buffer, uint32_t output_max_size);

Chipset Driver API {#sec:btstack_chipset_api}

btstack_chipset.h : The API implements custom chipset initialization and support of proprietary extensions to set UART baud rate, Bluetooth Address, and similar.

typedef struct {
    /**
     * chipset driver name
     */
    const char * name;

    /**
     * init driver
     * allows to reset init script index
     * @param transport_config
     */
    void (*init)(const void * transport_config);

    /**
     * support custom init sequences after RESET command
     * @param  hci_cmd_buffer to store generated command
     * @return result see btstack_chipset_result_t
     */
    btstack_chipset_result_t (*next_command)(uint8_t * hci_cmd_buffer);

    /**
     * provide UART Baud Rate change command.
     * @param baudrate
     * @param hci_cmd_buffer to store generated command
     */
    void (*set_baudrate_command)(uint32_t baudrate, uint8_t *hci_cmd_buffer);

    /** provide Set BD Addr command
     * @param baudrate
     * @param hci_cmd_buffer to store generated command
     */
    void (*set_bd_addr_command)(bd_addr_t addr, uint8_t *hci_cmd_buffer);

} btstack_chipset_t;

Bluetooth Power Control API {#sec:btstack_control_api}

btstack_control.h : The Bluetooth Hardware Control API allows HCI to manage Bluetooth chipsets via direct hardware controls.

typedef struct {
    void (*init) (const void *config);
    int  (*on)   (void);  // <-- turn BT module on and configure
    int  (*off)  (void);  // <-- turn BT module off
    int  (*sleep)(void);  // <-- put BT module to sleep    - only to be called after ON
    int  (*wake) (void);  // <-- wake BT module from sleep - only to be called after SLEEP
    void (*register_for_power_notifications)(void (*cb)(POWER_NOTIFICATION_t event));
} btstack_control_t;

Debug Messages API {#sec:btstack_debug_api}

btstack_debug.h : Allow to funnel debug and error messages.

/** 
 * @brief Log Security Manager key via log_info
 * @param name
 * @param key to log
 */
void log_info_key(const char * name, sm_key_t key);

/**
 * @brief Hexdump via log_info
 * @param data
 * @param size
 */
void log_info_hexdump(const void *data, int size);

/**
 * @brief Hexdump via log_debug 
 * @param data
 * @param size
 */
void log_debug_hexdump(const void *data, int size);

EM9304 SPI API {#sec:btstack_em9304_spi_api}

btstack_em9304_spi.h : BTstack's Hardware Abstraction Layer for EM9304 connected via SPI with additional RDY Interrupt line.

#include <stdint.h>
typedef struct {

    /**
     * @brief Open SPI
     */
    int (*open)(void);

    /**
     * @brief Close SPI
     */
    int (*close)(void);

    /**
     * @brief Check if full duplex operation via transceive is supported
     * @return 1 if supported
     */
    int  (*get_fullduplex_support)(void);

    /**
     * @brief Set callback for RDY
     * @param callback or NULL to disable callback
     */
    void (*set_ready_callback)(void (*callback)(void));

    /**
     * @brief Set callback for transfer complete
     * @param callback
     */
    void (*set_transfer_done_callback)(void (*callback)(void));

    /**
     * @brief Set Chip Selet
     * @param enable
     */
    void (*set_chip_select)(int enable);

    /**
     * @brief Poll READY state
     */
    int (*get_ready)(void);

    /**
     * @brief Transmit and Receive bytes via SPI
     * @param tx_data buffer to transmit
     * @param rx_data buffer to receive into
     * @param len 
     */
    void (*transceive)(const uint8_t * tx_data, uint8_t * rx_data, uint16_t len);

    /**
     * @brief Transmit bytes via SPI
     * @param tx_data buffer to transmit
     * @param len 
     */
    void (*transmit)(const uint8_t * tx_data, uint16_t len);

    /**
     * @brief Receive bytes via SPI
     * @param rx_data buffer to receive into
     * @param len 
     */
    void (*receive)(uint8_t * rx_data, uint16_t len);

} btstack_em9304_spi_t;

/**
 * @brief Get EM9304 SPI instance
 */
const btstack_em9304_spi_t * btstack_em9304_spi_embedded_instance(void);

Finite State Machine (FSM) API {#sec:btstack_fsm_api}

btstack_fsm.h

/*
 * @brief Request the transition from the current state to the given new state
 * @param me the current state machine
 * @param target the new state to transit to
 * @result transition status
 */
btstack_fsm_state_t btstack_fsm_transit(btstack_fsm_t * const me, btstack_fsm_state_handler_t target);

/*
 * @brief Constructs a new state hierarchical machine machine, with storage for maximum hierarchy depth.
 * @param me the current state machine
 * @param initial the initial state
 */
void btstack_fsm_constructor(btstack_fsm_t * const me, btstack_fsm_state_handler_t initial);

/*
 * @brief Takes the initial transition of the state machine and sending it a BTSTACK_HSM_INIT_SIG
 * @param me the current state machine
 * @param e event
 */
void btstack_fsm_init(btstack_fsm_t * const me, btstack_fsm_event_t const * const e);

/*
 * @brief Dispatches the given event to the state machine, if a transition is requested, leave the old states and enter the new on.
 *        Handling entering/exiting all states on the way.
 * @param me the current state machine
 * @param e event
 */
btstack_fsm_state_t btstack_fsm_dispatch(btstack_fsm_t * const me, btstack_fsm_event_t const * const e);

/*
 * @brief Dispatches the given event to the state machine until it was handled.
 * @param me the current state machine
 * @param e event
 */
void btstack_fsm_dispatch_until(btstack_fsm_t * const me, btstack_fsm_event_t const * const e);

Human Interface Device (HID) API {#sec:btstack_hid_api}

btstack_hid.h

/*
 * @brief Get boot descriptor data
 * @result data
 */
const uint8_t * btstack_hid_get_boot_descriptor_data(void);

/*
 * @brief Get boot descriptor length
 * @result length
 */
uint16_t btstack_hid_get_boot_descriptor_len(void);

HID Parser API {#sec:btstack_hid_parser_api}

btstack_hid_parser.h : Single-pass HID Report Parser: HID Report is directly parsed without preprocessing HID Descriptor to minimize memory.

/**
 * @brief Initialize HID Parser.
 * @param parser state 
 * @param hid_descriptor
 * @param hid_descriptor_len
 * @param hid_report_type
 * @param hid_report
 * @param hid_report_len
 */
void btstack_hid_parser_init(btstack_hid_parser_t * parser, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len, hid_report_type_t hid_report_type, const uint8_t * hid_report, uint16_t hid_report_len);

/**
 * @brief Checks if more fields are available
 * @param parser
 */
bool btstack_hid_parser_has_more(btstack_hid_parser_t * parser);

/**
 * @brief Get next field
 * @param parser
 * @param usage_page
 * @param usage
 * @param value provided in HID report
 */
void btstack_hid_parser_get_field(btstack_hid_parser_t * parser, uint16_t * usage_page, uint16_t * usage, int32_t * value);

/**
 * @brief Parses descriptor item
 * @param item
 * @param hid_descriptor
 * @param hid_descriptor_len
 * @return true if item has been parsed successfully
 */
bool btstack_hid_parse_descriptor_item(hid_descriptor_item_t * item, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len);

/**
 * @brief Parses descriptor and returns report size for given report ID and report type
 * @param report_id
 * @param report_type
 * @param hid_descriptor_len
 * @param hid_descriptor
 * @return report size in bytes or 0 on parsing error
 */
int btstack_hid_get_report_size_for_id(int report_id, hid_report_type_t report_type, uint16_t hid_descriptor_len, const uint8_t * hid_descriptor);

/**
 * @brief Parses descriptor and returns status for given report ID
 * @param report_id
 * @param hid_descriptor_len
 * @param hid_descriptor
 * @return status for report id
 */
hid_report_id_status_t btstack_hid_id_valid(int report_id, uint16_t hid_descriptor_len, const uint8_t * hid_descriptor);

/**
 * @brief Parses descriptor and returns true if report ID found
 * @param hid_descriptor_len
 * @param hid_descriptor
 * @return true if report ID declared in descriptor
 */
bool btstack_hid_report_id_declared(uint16_t hid_descriptor_len, const uint8_t * hid_descriptor);

Hierarchical State Machine (HSM) API {#sec:btstack_hsm_api}

btstack_hsm.h

/*
 * @brief Request the transition from the current state to the given new state
 * @param me the current state machine
 * @param target the new state to transit to
 * @result transition status
 */
btstack_hsm_state_t btstack_hsm_transit(btstack_hsm_t * const me, btstack_hsm_state_handler_t const target);

/*
 * @brief Specifies the upper state in a state hierarchy
 * @param me the current state machine
 * @param target the next parent state in the hierarchy
 * @result transition status
 */
btstack_hsm_state_t btstack_hsm_super(btstack_hsm_t * const me, btstack_hsm_state_handler_t const target);

/*
 * @brief Placeholder state to mark the top most state in a state hierarchy, the root state. Ignores all events.
 * @param me the current state machine
 * @param e event
 * @result ignored status
 */
btstack_hsm_state_t btstack_hsm_top(btstack_hsm_t * const me, btstack_hsm_event_t const * const e);

/*
 * @brief Constructs a new state hierarchical machine machine, with storage for maximum hierarchy depth.
 * @param me the current state machine
 * @param initial the initial state
 * @param array of btstack_hsm_state_handler_t elements with the same number of elements as the maximum number of nested state machines.
 * @param The number of nested state machines.
 */
void btstack_hsm_constructor(btstack_hsm_t * const me, btstack_hsm_state_handler_t initial, btstack_hsm_state_handler_t path[], int8_t depth);

/*
 * @brief Takes the initial transition of the state machine and sending it a BTSTACK_HSM_INIT_SIG
 * @param me the current state machine
 * @param e event
 */
void btstack_hsm_init(btstack_hsm_t * const me, btstack_hsm_event_t const * const e);

/*
 * @brief Dispatches the given event to the state machine, if a transition is requested, leave the old states and enter the new on.
 *        Honoring the hierarchy and handling entering/exiting all states on the way.
 * @param me the current state machine
 * @param e event
 */
btstack_hsm_state_t btstack_hsm_dispatch(btstack_hsm_t * const me, btstack_hsm_event_t const * const e);

LC3 Interface API {#sec:btstack_lc3_api}

btstack_lc3.h : Interface for LC3 implementations

typedef enum {
    BTSTACK_LC3_FRAME_DURATION_10000US,
    BTSTACK_LC3_FRAME_DURATION_7500US
} btstack_lc3_frame_duration_t;

typedef struct {

    /**
     * Configure Decoder
     * @param context
     * @param sample_rate
     * @param frame_duration
     * @param octets_per_frame
     * @return status
     */
    uint8_t (*configure)(void * context, uint32_t sample_rate, btstack_lc3_frame_duration_t frame_duration, uint16_t octets_per_frame);

    /**
     * Decode LC3 Frame into signed 16-bit samples
     * @param context
     * @param bytes
     * @param BFI Bad Frame Indication flags
     * @param pcm_out buffer for decoded PCM samples
     * @param stride count between two consecutive samples
     * @param BEC_detect Bit Error Detected flag
     * @return status
     */
     uint8_t (*decode_signed_16)(void * context, const uint8_t *bytes, uint8_t BFI,
                       int16_t* pcm_out, uint16_t stride, uint8_t * BEC_detect);

    /**
     * Decode LC3 Frame into signed 24-bit samples, sign-extended to 32-bit
     * @param context
     * @param bytes
     * @param BFI Bad Frame Indication flags
     * @param pcm_out buffer for decoded PCM samples
     * @param stride count between two consecutive samples
     * @param BEC_detect Bit Error Detected flag
     * @return status
     */
    uint8_t (*decode_signed_24)(void * context, const uint8_t *bytes, uint8_t BFI,
                                int32_t* pcm_out, uint16_t stride, uint8_t * BEC_detect);

} btstack_lc3_decoder_t;

typedef struct {
    /**
     * Configure Decoder
     * @param context
     * @param sample_rate
     * @param frame_duration
     * @param octets_per_frame
     * @return status
     */
    uint8_t (*configure)(void * context, uint32_t sample_rate, btstack_lc3_frame_duration_t frame_duration, uint16_t octets_per_frame);

    /**
     * Encode LC3 Frame with 16-bit signed PCM samples
     * @param context
     * @param pcm_in buffer for decoded PCM samples
     * @param stride count between two consecutive samples
     * @param bytes
     * @return status
     */
    uint8_t (*encode_signed_16)(void * context, const int16_t* pcm_in, uint16_t stride, uint8_t *bytes);

    /**
     * Encode LC3 Frame with 24-bit signed PCM samples, sign-extended to 32 bit
     * @param context
     * @param pcm_in buffer for decoded PCM samples
     * @param stride count between two consecutive samples
     * @param bytes
     * @return status
     */
    uint8_t (*encode_signed_24)(void * context, const int32_t* pcm_in, uint16_t stride, uint8_t *bytes);

} btstack_lc3_encoder_t;

/**
 * @brief Map enum to ISO Interval in us
 * @param frame_duration enum
 * @return frame_duratoin in us or 0 for invalid frame_duration enum
 */
uint16_t btstack_lc3_frame_duration_in_us(btstack_lc3_frame_duration_t frame_duration);

/**
 * @bbrief Calculate number of samples per ISO Interval
 * @param sample_rate
 * @param frame_duration
 * @return
 */
uint16_t btstack_lc3_samples_per_frame(uint32_t sample_rate, btstack_lc3_frame_duration_t frame_duration);

LC3 Google Adapter API {#sec:btstack_lc3_google_api}

btstack_lc3_google.h

typedef struct {
    lc3_decoder_mem_48k_t           decoder_mem;
    lc3_decoder_t                   decoder;    // pointer
    uint32_t                        sample_rate;
    btstack_lc3_frame_duration_t    frame_duration;
    uint16_t                        octets_per_frame;
} btstack_lc3_decoder_google_t;

typedef struct {
    lc3_encoder_mem_48k_t           encoder_mem;
    lc3_encoder_t                   encoder;    // pointer
    uint32_t                        sample_rate;
    btstack_lc3_frame_duration_t    frame_duration;
    uint16_t                        octets_per_frame;
} btstack_lc3_encoder_google_t;

/**
 * Init LC3 Decoder Instance
 * @param context for EHIMA LC3 decoder
 */
const btstack_lc3_decoder_t * btstack_lc3_decoder_google_init_instance(btstack_lc3_decoder_google_t * context);

/**
 * Init LC3 Decoder Instance
 * @param context for EHIMA LC3 decoder
 */
const btstack_lc3_encoder_t * btstack_lc3_encoder_google_init_instance(btstack_lc3_encoder_google_t * context);

Adapter for Fraunhofer LC3plus Coddec API {#sec:btstack_lc3plus_fraunhofer_api}

btstack_lc3plus_fraunhofer.h : only uses suitable subset for lc3 testing

typedef struct {
    btstack_lc3_frame_duration_t    frame_duration;
    uint16_t                        octets_per_frame;
    uint16_t                        samples_per_frame;
    uint32_t                        sample_rate;
    // decoder must be 4-byte aligned
    uint8_t                         decoder[LC3PLUS_DEC_MAX_SIZE];
} btstack_lc3plus_fraunhofer_decoder_t;

typedef struct {
    btstack_lc3_frame_duration_t    frame_duration;
    uint16_t                        octets_per_frame;
    uint32_t                        sample_rate;
    // encoder must be 4-byte aligned
    uint8_t                         encoder[LC3PLUS_ENC_MAX_SIZE];
} btstack_lc3plus_fraunhofer_encoder_t;

/**
 * Init LC3 Decoder Instance
 * @param context for Fraunhofer LC3plus decoder
 */
const btstack_lc3_decoder_t * btstack_lc3plus_fraunhofer_decoder_init_instance(btstack_lc3plus_fraunhofer_decoder_t * context);

/**
 * Init LC3 Encoder Instance
 * @param context for Fraunhofer LC3plus encoder
 */
const btstack_lc3_encoder_t * btstack_lc3plus_fraunhofer_encoder_init_instance(btstack_lc3plus_fraunhofer_encoder_t * context);

Linked List API {#sec:btstack_linked_list_api}

btstack_linked_list.h

typedef struct btstack_linked_item {
    struct btstack_linked_item *next; // <-- next element in list, or NULL
} btstack_linked_item_t;

typedef btstack_linked_item_t * btstack_linked_list_t;

typedef struct {
    int advance_on_next;
    btstack_linked_item_t * prev;   // points to the item before the current one
    btstack_linked_item_t * curr;   // points to the current item (to detect item removal)
} btstack_linked_list_iterator_t;


/**
 * @brief Test if list is empty.
 * @param list
 * @return true if list is empty
 */
bool btstack_linked_list_empty(btstack_linked_list_t * list);

/**
 * @brief Add item to list as first element.
 * @param list
 * @param item
 * @return true if item was added, false if item already in list
 */
bool btstack_linked_list_add(btstack_linked_list_t * list, btstack_linked_item_t *item);

/**
 * @brief Add item to list as last element.
 * @param list
 * @param item
 * @return true if item was added, false if item already in list
 */
bool btstack_linked_list_add_tail(btstack_linked_list_t * list, btstack_linked_item_t *item);

/**
 * @brief Pop (get + remove) first element.
 * @param list
 * @return first element or NULL if list is empty
 */
btstack_linked_item_t * btstack_linked_list_pop(btstack_linked_list_t * list);

/**
 * @brief Remove item from list
 * @param list
 * @param item
 * @return true if item was removed, false if it is no't in list
 */
bool btstack_linked_list_remove(btstack_linked_list_t * list, btstack_linked_item_t *item);

/**
 * @brief Get first element.
 * @param list
 * @return first element or NULL if list is empty
 */
btstack_linked_item_t * btstack_linked_list_get_first_item(btstack_linked_list_t * list);

/**
 * @brief Get last element.
 * @param list
 * @return first element or NULL if list is empty
 */
btstack_linked_item_t * btstack_linked_list_get_last_item(btstack_linked_list_t * list);

/**
 * @brief Counts number of items in list
 * @return number of items in list
 */
int btstack_linked_list_count(btstack_linked_list_t * list);



/**
 * @brief Initialize Linked List Iterator
 * @note robust against removal of current element by btstack_linked_list_remove
 * @param it iterator context
 * @param list
 */
void btstack_linked_list_iterator_init(btstack_linked_list_iterator_t * it, btstack_linked_list_t * list);

/**
 * @brief Has next element
 * @param it iterator context
 * @return true if next element is available
 */
bool btstack_linked_list_iterator_has_next(btstack_linked_list_iterator_t * it);

/**
 * @brief Get next list eleemnt
 * @param it iterator context
 * @return list element
 */
btstack_linked_item_t * btstack_linked_list_iterator_next(btstack_linked_list_iterator_t * it);

/**
 * @brief Remove current list element from list
 * @param it iterator context
 */
void btstack_linked_list_iterator_remove(btstack_linked_list_iterator_t * it);

Linked Queue API {#sec:btstack_linked_queue_api}

btstack_linked_queue.h

typedef struct {
    btstack_linked_item_t * head;
    btstack_linked_item_t * tail;
} btstack_linked_queue_t;

/**
 * @brief Tests if queue is empty
 * @return true if emtpy
 */
bool btstack_linked_queue_empty(btstack_linked_queue_t * queue);

/**
 * @brief Append item to queue
 * @param queue
 * @param item
 */
void btstack_linked_queue_enqueue(btstack_linked_queue_t * queue, btstack_linked_item_t * item);

/**
 * @brief Pop next item from queue
 * @param queue
 * @return item or NULL if queue empty
 */
btstack_linked_item_t * btstack_linked_queue_dequeue(btstack_linked_queue_t * queue);

/**
 * @brief Get first item from queue
 * @param queue
 * @return item or NULL if queue empty
 */
btstack_linked_item_t * btstack_linked_queue_first(btstack_linked_queue_t * queue);

Network Interface API {#sec:btstack_network_api}

btstack_network.h

/**
 * @brief Initialize network interface
 * @param send_packet_callback
 */
void btstack_network_init(void (*send_packet_callback)(const uint8_t * packet, uint16_t size));

/**
 * @brief Bring up network interfacd
 * @param network_address
 * @return 0 if ok
 */
int  btstack_network_up(bd_addr_t network_address);

/**
 * @brief Shut down network interfacd
 * @param network_address
 * @return 0 if ok
 */
int  btstack_network_down(void);

/** 
 * @brief Receive packet on network interface, e.g., forward packet to TCP/IP stack 
 * @param packet
 * @param size
 */
void btstack_network_process_packet(const uint8_t * packet, uint16_t size);

/** 
 * @brief Notify network interface that packet from send_packet_callback was sent and the next packet can be delivered.
 */
void btstack_network_packet_sent(void);

/**
 * @brief Get network name after network was activated
 * @note e.g. tapX on Linux, might not be useful on all platforms
 * @return network name
 */
const char * btstack_network_get_name(void);

Lienar Resampling API {#sec:btstack_resample_api}

btstack_resample.h : Linear resampling for 16-bit audio code samples using 16 bit/16 bit fixed point math.

/**
 * @brief Init resample context
 * @param num_channels
 * @return btstack_audio implementation
 */
void btstack_resample_init(btstack_resample_t * context, int num_channels);

/**
 * @brief Set resampling factor
 * @param factor as fixed point value, identity is 0x10000
 */
void btstack_resample_set_factor(btstack_resample_t * context, uint32_t factor);

/**
 * @brief Process block of input samples
 * @note size of output buffer is not checked
 * @param input_buffer
 * @param num_frames
 * @param output_buffer
 * @return number destination frames
 */
uint16_t btstack_resample_block(btstack_resample_t * context, const int16_t * input_buffer, uint32_t num_frames, int16_t * output_buffer);

Ring Buffer API {#sec:btstack_ring_buffer_api}

btstack_ring_buffer.h

/**
 * Init ring buffer
 * @param ring_buffer object
 * @param storage
 * @param storage_size in bytes
 */
void btstack_ring_buffer_init(btstack_ring_buffer_t * ring_buffer, uint8_t * storage, uint32_t storage_size);

/**
 * Reset ring buffer to initial state (empty)
 * @param ring_buffer object
 */
void btstack_ring_buffer_reset(btstack_ring_buffer_t * ring_buffer);

/**
 * Check if ring buffer is empty
 * @param ring_buffer object
 * @return TRUE if empty
 */
int btstack_ring_buffer_empty(btstack_ring_buffer_t * ring_buffer);

/**
 * Get number of bytes available for read
 * @param ring_buffer object
 * @return number of bytes available for read
 */
uint32_t btstack_ring_buffer_bytes_available(btstack_ring_buffer_t * ring_buffer);

/**
 * Get free space available for write
 * @param ring_buffer object
 * @return number of bytes available for write
 */
uint32_t btstack_ring_buffer_bytes_free(btstack_ring_buffer_t * ring_buffer);

/**
 * Write bytes into ring buffer
 * @param ring_buffer object
 * @param data to store
 * @param data_length
 * @return 0 if ok, ERROR_CODE_MEMORY_CAPACITY_EXCEEDED if not enough space in buffer
 */
int btstack_ring_buffer_write(btstack_ring_buffer_t * ring_buffer, uint8_t * data, uint32_t data_length);

/**
 * Read from ring buffer
 * @param ring_buffer object
 * @param buffer to store read data
 * @param length to read
 * @param number_of_bytes_read
 */
void btstack_ring_buffer_read(btstack_ring_buffer_t * ring_buffer, uint8_t * buffer, uint32_t length, uint32_t * number_of_bytes_read);

Sample rate compensation API {#sec:btstack_sample_rate_compensation_api}

btstack_sample_rate_compensation.h : Prevents buffer over/under-run at the audio receiver by compensating for varying/different playback/receiving sample rates.

Intended to measure the L2CAP packet sample rate and with the provided playback sample rate calculates a compensation ratio which compensates for drift between playback and reception.

Requires the audio interface to provide the current playback sample rate.

#define FLOAT_TO_Q15(a)   ((signed)((a)*(UINT16_C(1)<<15)+0.5f))
#define FLOAT_TO_Q8(a)    ((signed)((a)*(UINT16_C(1)<<8)+0.5f))
#define FLOAT_TO_Q7(a)    ((signed)((a)*(UINT16_C(1)<<7)+0.5f))

#define Q16_TO_FLOAT(a)   ((float)(a)/(UINT32_C(1)<<16))
#define Q15_TO_FLOAT(a)   ((float)(a)/(UINT32_C(1)<<15))
#define Q8_TO_FLOAT(a)    ((float)(a)/(UINT32_C(1)<<8))
#define Q7_TO_FLOAT(a)    ((float)(a)/(UINT32_C(1)<<7))

//#define DEBUG_RATIO_CALCULATION

typedef struct {
    uint32_t count;         // 17bit are usable to count samples, recommended for max 96kHz
    uint32_t last;          // time stamp of last measurement
    uint32_t rate_state;    // unsigned Q17.8
    uint32_t ratio_state;   // unsigned Q16.16
    uint32_t constant_playback_sample_rate; // playback sample rate if no real one is available
#ifdef DEBUG_RATIO_CALCULATION
    double sample_rate;
    double ratio;
#endif
} btstack_sample_rate_compensation_t;

/**
 * @brief Initialize sample rate compensation
 * @param self pointer to current instance
 * @param time stamp at which to start sample rate measurement
 */
void btstack_sample_rate_compensation_init( btstack_sample_rate_compensation_t *self, uint32_t timestamp_ms, uint32_t sample_rate, uint32_t ratioQ15 );

/**
 * @brief reset sample rate compensation
 * @param self pointer to current instance
 * @param time stamp at which to start sample rate measurement
 */
void btstack_sample_rate_compensation_reset( btstack_sample_rate_compensation_t *self, uint32_t timestamp_ms );

/**
 * @brief update sample rate compensation with the current playback sample rate decoded samples
 * @param self pointer to current instance
 * @param time stamp for current samples
 * @param samples for current time stamp
 * @param playback sample rate
 */
uint32_t btstack_sample_rate_compensation_update( btstack_sample_rate_compensation_t *self, uint32_t timestamp_ms, uint32_t samples, uint32_t playback_sample_rate );

SCO Transport API {#sec:btstack_sco_transport_api}

btstack_sco_transport.h : Hardware abstraction for PCM/I2S Inteface used for HSP/HFP profiles.

typedef struct {

    /**
     * register packet handler for SCO HCI packets
     */
    void (*register_packet_handler)(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size));

    /**
     * open transport
     * @param con_handle of SCO connection
     * @param sco_format
     */
    void (*open)(hci_con_handle_t con_handle, sco_format_t sco_format);

    /**
     * send SCO packet
     */
    void (*send_packet)(const uint8_t *buffer, uint16_t length);

    /**
     * close transport
     * @param con_handle of SCO connection
     */
    void (*close)(hci_con_handle_t con_handle);

} btstack_sco_transport_t;

SLIP encoder/decoder API {#sec:btstack_slip_api}

btstack_slip.h

// ENCODER

/**
 * @brief Initialise SLIP encoder with data
 * @param data
 * @param len
 */
void btstack_slip_encoder_start(const uint8_t * data, uint16_t len);

/**
 * @brief Check if encoder has data ready
 * @return True if data ready
 */
int  btstack_slip_encoder_has_data(void);

/** 
 * @brief Get next byte from encoder 
 * @return Next bytes from encoder
 */
uint8_t btstack_slip_encoder_get_byte(void);

// DECODER

/**
 * @brief Initialise SLIP decoder with buffer
 * @param buffer to store received data
 * @param max_size of buffer
 */
void btstack_slip_decoder_init(uint8_t * buffer, uint16_t max_size);

/**
 * @brief Process received byte
 * @param input
 */

void btstack_slip_decoder_process(uint8_t input);

/**
 * @brief Get size of decoded frame
 * @return size of frame. Size = 0 => frame not complete
 */

uint16_t btstack_slip_decoder_frame_size(void);

Tag-Value-Length Persistent Storage (TLV) API {#sec:btstack_tlv_api}

btstack_tlv.h : Inteface for BTstack's Tag Value Length Persistent Storage implementations used to store pairing/bonding data.

typedef struct {

    /**
     * Get Value for Tag
     * @param context
     * @param tag
     * @param buffer
     * @param buffer_size
     * @return size of value
     */
    int (*get_tag)(void * context, uint32_t tag, uint8_t * buffer, uint32_t buffer_size);

    /**
     * Store Tag 
     * @param context
     * @param tag
     * @param data
     * @param data_size
     * @return 0 on success
     */
    int (*store_tag)(void * context, uint32_t tag, const uint8_t * data, uint32_t data_size);

    /**
     * Delete Tag
     *  @note it is not expected that delete operation fails, please use at least log_error in case of errors
     * @param context
     * @param tag
     */
    void (*delete_tag)(void * context,  uint32_t tag);

} btstack_tlv_t;

/** 
 * @brief Make TLV implementation available to BTstack components via Singleton
 * @note Usually called by port after BD_ADDR was retrieved from Bluetooth Controller
 * @param tlv_impl
 * @param tlv_context
 */
void btstack_tlv_set_instance(const btstack_tlv_t * tlv_impl, void * tlv_context);

/**
 * @brief Get current TLV implementation. Used for bonding information, but can be used by application, too.
 * @param tlv_impl
 * @param tlv_context
 */
void btstack_tlv_get_instance(const btstack_tlv_t ** tlv_impl, void ** tlv_context);

Empty TLV Instance API {#sec:btstack_tlv_none_api}

btstack_tlv_none.h : Empty implementation for BTstack's Tag Value Length Persistent Storage implementations No keys are stored. Can be used as placeholder during porting to new platform.

/**
 * Init Tag Length Value Store
 * @param context btstack_tlv_none_t 
 * @param hal_flash_bank_impl    of hal_flash_bank interface
 * @Param hal_flash_bank_context of hal_flash_bank_interface
 */
const btstack_tlv_t * btstack_tlv_none_init_instance(void);

UART API {#sec:btstack_uart_api}

btstack_uart.h : Common types for UART transports

typedef struct {
    /**
     * init transport
     * @param uart_config
     */
    int (*init)(const btstack_uart_config_t * uart_config);

    /**
     * open transport connection
     */
    int (*open)(void);

    /**
     * close transport connection
     */
    int (*close)(void);

    /**
     * set callback for block received. NULL disables callback
     */
    void (*set_block_received)(void (*block_handler)(void));

    /**
     * set callback for sent. NULL disables callback
     */
    void (*set_block_sent)(void (*block_handler)(void));

    /**
     * set baudrate
     */
    int (*set_baudrate)(uint32_t baudrate);

    /**
     * set parity
     */
    int  (*set_parity)(int parity);

    /**
     * set flowcontrol
     */
    int  (*set_flowcontrol)(int flowcontrol);

    /**
     * receive block
     */
    void (*receive_block)(uint8_t *buffer, uint16_t len);

    /**
     * send block
     */
    void (*send_block)(const uint8_t *buffer, uint16_t length);


    /** Support for different Sleep Modes in TI's H4 eHCILL and in H5 - can be set to NULL if not used */

    /**
     * query supported wakeup mechanisms
     * @return supported_sleep_modes mask
     */
     int (*get_supported_sleep_modes)(void);

    /**
     * set UART sleep mode - allows to turn off UART and it's clocks to save energy
     * Supported sleep modes:
     * - off: UART active, RTS low if receive_block was called and block not read yet
     * - RTS high, wake on CTS: RTS should be high. On CTS pulse, UART gets enabled again and RTS goes to low
     * - RTS low, wake on RX: data on RX will trigger UART enable, bytes might get lost
     */
    void (*set_sleep)(btstack_uart_sleep_mode_t sleep_mode);

    /** 
     * set wakeup handler - needed to notify hci transport of wakeup requests by Bluetooth controller
     * Called upon CTS pulse or RX data. See sleep modes.
     */
    void (*set_wakeup_handler)(void (*wakeup_handler)(void));


    /** Support for HCI H5 Transport Mode - can be set to NULL for H4 */

    /**
     * H5/SLIP only: set callback for frame received. NULL disables callback
     */
    void (*set_frame_received)(void (*frame_handler)(uint16_t frame_size));

    /**
     * H5/SLIP only: set callback for frame sent. NULL disables callback
     */
    void (*set_frame_sent)(void (*block_handler)(void));

    /**
     * H5/SLIP only: receive SLIP frame
     */
    void (*receive_frame)(uint8_t *buffer, uint16_t len);

    /**
     * H5/SLIP only: send SLIP frame
     */
    void (*send_frame)(const uint8_t *buffer, uint16_t length);

} btstack_uart_t;

UART Block API {#sec:btstack_uart_block_api}

btstack_uart_block.h : Compatibility layer for ports that use btstack_uart_block_t

typedef btstack_uart_t btstack_uart_block_t;

// existing block-only implementations
const btstack_uart_block_t * btstack_uart_block_windows_instance(void);
const btstack_uart_block_t * btstack_uart_block_embedded_instance(void);
const btstack_uart_block_t * btstack_uart_block_freertos_instance(void);

// mapper for extended implementation
static inline const btstack_uart_block_t * btstack_uart_block_posix_instance(void){
    return (const btstack_uart_block_t *) btstack_uart_posix_instance();
}
/* API_STOP */

#if defined __cplusplus
}
#endif

#endif

UART SLIP Wrapper API {#sec:btstack_uart_slip_wrapper_api}

btstack_uart_slip_wrapper.h : Compatibility layer to use new H5 implementation with btstack_uart.h implementations without SLIP support. Using this compatibility layer caused increased processing as it uses single byte UART reads.

If you're using H5, please consider implement the H5/SLIP functions in your btstack_uart.h or hal_uart_dma.h implementation.

/**
 * @brief Initialize SLIP wrapper for existing btstack_uart_block_t instance without SLIP support
 * @param uart_block_without_slip
 * @return btstack_uart_t instance with SLIP support for use with hci_trasnport_h5
 */
const btstack_uart_t * btstack_uart_slip_wrapper_instance(const btstack_uart_t * uart_without_slip);

General Utility Functions API {#sec:btstack_util_api}

btstack_util.h

/**
 * @brief Minimum function for uint32_t
 * @param a
 * @param b
 * @return value
 */
uint32_t btstack_min(uint32_t a, uint32_t b);

/**
 * @brief Maximum function for uint32_t
 * @param a
 * @param b
 * @return value
 */
uint32_t btstack_max(uint32_t a, uint32_t b);

/**
 * @brief Calculate delta between two uint32_t points in time
 * @return time_a - time_b - result > 0 if time_a is newer than time_b
 */
int32_t btstack_time_delta(uint32_t time_a, uint32_t time_b);

/**
 * @brief Calculate delta between two uint16_t points in time
 * @return time_a - time_b - result > 0 if time_a is newer than time_b
 */
int16_t btstack_time16_delta(uint16_t time_a, uint16_t time_b);

/** 
 * @brief Read 16/24/32 bit little endian value from buffer
 * @param buffer
 * @param position in buffer
 * @return value
 */
uint16_t little_endian_read_16(const uint8_t * buffer, int position);
uint32_t little_endian_read_24(const uint8_t * buffer, int position);
uint32_t little_endian_read_32(const uint8_t * buffer, int position);

/** 
 * @brief Write 16/32 bit little endian value into buffer
 * @param buffer
 * @param position in buffer
 * @param value
 */
void little_endian_store_16(uint8_t * buffer, uint16_t position, uint16_t value);
void little_endian_store_24(uint8_t * buffer, uint16_t position, uint32_t value);
void little_endian_store_32(uint8_t * buffer, uint16_t position, uint32_t value);

/** 
 * @brief Read 16/24/32 bit big endian value from buffer
 * @param buffer
 * @param position in buffer
 * @return value
 */
uint32_t big_endian_read_16(const uint8_t * buffer, int position);
uint32_t big_endian_read_24(const uint8_t * buffer, int position);
uint32_t big_endian_read_32(const uint8_t * buffer, int position);

/** 
 * @brief Write 16/32 bit big endian value into buffer
 * @param buffer
 * @param position in buffer
 * @param value
 */
void big_endian_store_16(uint8_t * buffer, uint16_t position, uint16_t value);
void big_endian_store_24(uint8_t * buffer, uint16_t position, uint32_t value);
void big_endian_store_32(uint8_t * buffer, uint16_t position, uint32_t value);


/**
 * @brief Swap bytes in 16 bit integer
 */
static inline uint16_t btstack_flip_16(uint16_t value){
    return (uint16_t)((value & 0xffu) << 8) | (value >> 8);
}

/** 
 * @brief Check for big endian system
 * @return 1 if on big endian
 */
static inline int btstack_is_big_endian(void){
    uint16_t sample = 0x0100;
    return (int) *(uint8_t*) &sample;
}

/** 
 * @brief Check for little endian system
 * @return 1 if on little endian
 */
static inline int btstack_is_little_endian(void){
    uint16_t sample = 0x0001;
    return (int) *(uint8_t*) &sample;
}

/**
 * @brief Copy from source to destination and reverse byte order
 * @param src
 * @param dest
 * @param len
 */
void reverse_bytes(const uint8_t * src, uint8_t * dest, int len);

/**
 * @brief Wrapper around reverse_bytes for common buffer sizes
 * @param src
 * @param dest
 */
void reverse_24 (const uint8_t * src, uint8_t * dest);
void reverse_48 (const uint8_t * src, uint8_t * dest);
void reverse_56 (const uint8_t * src, uint8_t * dest);
void reverse_64 (const uint8_t * src, uint8_t * dest);
void reverse_128(const uint8_t * src, uint8_t * dest);
void reverse_256(const uint8_t * src, uint8_t * dest);

void reverse_bd_addr(const bd_addr_t src, bd_addr_t dest);

/**
 * @brief Check if all bytes in buffer are zero
 * @param buffer
 * @param size
 * @return true if all bytes is buffer are zero
 */
bool btstack_is_null(const uint8_t * buffer, uint16_t size);

/**
 * @brief Check if all bytes in a bd_addr_t are zero
 * @param addr
 * @return true if all bytes in addr are zero
 */
bool btstack_is_null_bd_addr( const bd_addr_t addr );

/** 
 * @brief ASCII character for 4-bit nibble
 * @return character
 */
char char_for_nibble(uint8_t nibble);

/**
 * @brif 4-bit nibble from ASCII character
 * @return value
 */
int nibble_for_char(char c);

/**
 * @brief Compare two Bluetooth addresses
 * @param a
 * @param b
 * @return 0 if equal
 */
int bd_addr_cmp(const bd_addr_t a, const bd_addr_t b);

/**
 * @brief Copy Bluetooth address
 * @param dest
 * @param src
 */
void bd_addr_copy(bd_addr_t dest, const bd_addr_t src);

/**
 * @brief Use printf to write hexdump as single line of data
 */
void printf_hexdump(const void * data, int size);

/**
 * @brief Create human readable representation for UUID128
 * @note uses fixed global buffer
 * @return pointer to UUID128 string
 */
char * uuid128_to_str(const uint8_t * uuid);

/**
 * @brief Create human readable represenationt of Bluetooth address
 * @note uses fixed global buffer
 * @param delimiter
 * @return pointer to Bluetooth address string
 */
char * bd_addr_to_str_with_delimiter(const bd_addr_t addr, char delimiter);

/**
 * @brief Create human readable represenationt of Bluetooth address
 * @note uses fixed global buffer
 * @return pointer to Bluetooth address string
 */
char * bd_addr_to_str(const bd_addr_t addr);

/**
 * @brief Replace address placeholder '00:00:00:00:00:00' with Bluetooth address
 * @param buffer
 * @param size
 * @param address
 */
void btstack_replace_bd_addr_placeholder(uint8_t * buffer, uint16_t size, const bd_addr_t address);

/** 
 * @brief Parse Bluetooth address
 * @param address_string
 * @param buffer for parsed address
 * @return 1 if string was parsed successfully
 */
int sscanf_bd_addr(const char * addr_string, bd_addr_t addr);

/**
 * @brief Constructs UUID128 from 16 or 32 bit UUID using Bluetooth base UUID
 * @param uuid128 output buffer
 * @param short_uuid
 */
void uuid_add_bluetooth_prefix(uint8_t * uuid128, uint32_t short_uuid);

/**
 * @brief Checks if UUID128 has Bluetooth base UUID prefix
 * @param uui128 to test
 * @return true if it can be expressed as UUID32
 */
bool uuid_has_bluetooth_prefix(const uint8_t * uuid128);

/**
 * @brief Parse unsigned number 
 * @param str to parse
 * @return value
 */
uint32_t btstack_atoi(const char * str);

/**
 * @brief Return number of digits of a uint32 number
 * @param uint32_number
 * @return num_digits
 */
int string_len_for_uint32(uint32_t i);

/**
 * @brief Return number of set bits in a uint32 number
 * @param uint32_number
 * @return num_set_bits
 */
int count_set_bits_uint32(uint32_t x);

/**
 * @brief Check CRC8 using ETSI TS 101 369 V6.3.0.
 * @note Only used by RFCOMM
 * @param data
 * @param len
 * @param check_sum
 */
uint8_t btstack_crc8_check(uint8_t * data, uint16_t len, uint8_t check_sum);

/**
 * @brief Calculate CRC8 using ETSI TS 101 369 V6.3.0. 
 * @note Only used by RFCOMM
 * @param data
 * @param len
 */
uint8_t btstack_crc8_calc(uint8_t * data, uint16_t len);


/**
 * @brief Calculate the initial CRC32 value using ISO 3309 (HDLC), polynomial (normal) 0x04c11db7
 * @note Used by OTS Service. 
 * 
 * @return  The initial crc value.
 */
uint32_t btstack_crc32_init(void);

/**
 * @brief Update the CRC32 value with new data.
 *
 * @param crc      The current crc value.
 * @param data     Pointer to a buffer of \a data_len bytes.
 * @param data_len Number of bytes in the \a data buffer.
 * @return             The updated crc value.
 */
uint32_t btstack_crc32_update(uint32_t crc, const uint8_t * data, uint32_t data_len);

/**
 * @brief Calculate the final CRC32 value.
 *
 * @param crc  The current crc value.
 * @return     The final crc value.
 */
uint32_t btstack_crc32_finalize(uint32_t crc);

/**
 * @brief Get next cid
 * @param current_cid
 * @return next cid skiping 0
 */
uint16_t btstack_next_cid_ignoring_zero(uint16_t current_cid);

/**
 * @brief Copy string (up to dst_size-1 characters) from src into dst buffer with terminating '\0'
 * @note replaces strncpy + dst[dst_size-1] = '\0'
 * @param dst
 * @param dst_size
 * @param src
 * @retun bytes_copied including trailing 0
 */
uint16_t btstack_strcpy(char * dst, uint16_t dst_size, const char * src);

/**
 * @brief Append src string to string in dst buffer with terminating '\0'
 * @note max total string length will be dst_size-1 characters
 * @param dst
 * @param dst_size
 * @param src
 */
void btstack_strcat(char * dst, uint16_t dst_size, const char * src);

/**
 * Returns the number of leading 0-bits in x, starting at the most significant bit position.
 * If x is 0, the result is undefined.
 * @note maps to __builtin_clz for gcc and clang
 * @param value
 * @return number of leading 0-bits
 */
uint8_t btstack_clz(uint32_t value);

/**
 * @brief Copy chunk of data into a virtual buffer backed by a physical buffer.
 * Used to provide chunk of data of larger buffer that is constructed on the fly, e.g. serializing data struct
 * 
 * For example, copy field2 to buffer, with buffer_offset = 11
 * 
 *           field1  field2  field3     field4        field5  filed6
 * struct:  -------|-------|----------|-------------|-------|--------------
 * buffer:             ------------------       
 * result:             ----|         
 * 
 * When also copying field3 and field4 to buffer, with buffer_offset = 11
 * 
 *           field1  field2  field3     field4        field5  filed6
 * struct:  -------|-------|----------|-------------|-------|--------------
 * buffer:             ------------------       
 * result:             ----|----------|--         
 *
 * @param field_data
 * @param field_len
 * @param field_offset  position of field in complete data block
 * @param buffer_data
 * @param buffer_len
 * @param buffer_offset position of buffer in complete data block
 * @return bytes_copied number of bytes actually stored in buffer
 */
uint16_t btstack_virtual_memcpy(
    const uint8_t * field_data, uint16_t field_len, uint16_t field_offset, 
    uint8_t * buffer, uint16_t buffer_size, uint16_t buffer_offset);

A2DP Sink API {#sec:a2dp_sink_api}

a2dp_sink.h : Audio/Video Distribution Transport Protocol A2DP Sink is a device that accepts streamed media data.

/**
 * @brief Create A2DP Sink service record. 
 * @param service
 * @param service_record_handle
 * @param supported_features 16-bit bitmap, see AVDTP_SINK_SF_* values in avdtp.h
 * @param service_name or NULL for default value. Provide "" (empty string) to skip attribute
 * @param service_provider_name or NULL for default value. Provide "" (empty string) to skip attribute
 */
void a2dp_sink_create_sdp_record(uint8_t * service, uint32_t service_record_handle, uint16_t supported_features, const char * service_name, const char * service_provider_name);

/**
 * @brief Initialize up A2DP Sink device.
 */
void a2dp_sink_init(void);

/**
 * @brief Create a stream endpoint of type SINK, and register media codec by specifying its capabilities and the default configuration.
 * @param media_type                see avdtp_media_type_t values in avdtp.h (audio, video or multimedia)
 * @param media_codec_type          see avdtp_media_codec_type_t values in avdtp.h 
 * @param codec_capabilities        media codec capabilities as defined in A2DP spec, section 4 - Audio Codec Interoperability Requirements.
 * @param codec_capabilities_len    media codec capabilities length
 * @param codec_configuration       default media codec configuration
 * @param codec_configuration_len   media codec configuration length 
 *
 * @return local_stream_endpoint    
 */
avdtp_stream_endpoint_t *  a2dp_sink_create_stream_endpoint(avdtp_media_type_t media_type, avdtp_media_codec_type_t media_codec_type,
                                                            const uint8_t *codec_capabilities, uint16_t codec_capabilities_len,
                                                            uint8_t * codec_configuration, uint16_t codec_configuration_len);

/**
 *  @brief Unregister stream endpoint and free it's memory
 *  @param stream_endpoint created by a2dp_sink_create_stream_endpoint
 */
void a2dp_sink_finalize_stream_endpoint(avdtp_stream_endpoint_t * stream_endpoint);

/**
 * @brief Register callback for the A2DP Sink client. It will receive following subevents of HCI_EVENT_A2DP_META HCI event type: 
 * - A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION:     indicates from remote chosen SBC media codec configuration 
 * - A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION:   indicates from remote chosen other then SBC media codec configuration 
 * - A2DP_SUBEVENT_STREAM_ESTABLISHED:                          received when stream to a remote device is established
 * - A2DP_SUBEVENT_STREAM_STARTED:                              received when stream is started
 * - A2DP_SUBEVENT_STREAM_SUSPENDED:                            received when stream is paused
 * - A2DP_SUBEVENT_STREAM_STOPED:                               received when stream is aborted or stopped
 * - A2DP_SUBEVENT_STREAM_RELEASED:                             received when stream is released
 * - A2DP_SUBEVENT_SIGNALING_CONNECTION_RELEASED:               received when signaling channel is disconnected
 *
 * @param callback
 */
void a2dp_sink_register_packet_handler(btstack_packet_handler_t callback);

/**
 * @brief Register media handler for the A2DP Sink client. 
 * @param callback
 * @param packet
 * @param size
 */
void a2dp_sink_register_media_handler(void (*callback)(uint8_t local_seid, uint8_t *packet, uint16_t size));

/**
 * @brief Establish stream.
 * @param remote
 * @param out_a2dp_cid      Assigned A2DP channel identifier used for furhter A2DP commands.
 */
uint8_t a2dp_sink_establish_stream(bd_addr_t remote, uint16_t * out_a2dp_cid);

#ifdef ENABLE_AVDTP_ACCEPTOR_EXPLICIT_START_STREAM_CONFIRMATION
/**
 * @brief Accept starting the stream on A2DP_SUBEVENT_START_STREAM_REQUESTED event.
 * @param a2dp_cid      A2DP channel identifier.   
 * @param local_seid        ID of a local stream endpoint.
 */
uint8_t a2dp_sink_start_stream_accept(uint16_t a2dp_cid, uint8_t local_seid);

/**
 * @brief Reject starting the stream on A2DP_SUBEVENT_START_STREAM_REQUESTED event.
 * @param a2dp_cid      A2DP channel identifier.
 * @param local_seid        ID of a local stream endpoint.
 */
uint8_t a2dp_sink_start_stream_reject(uint16_t a2dp_cid, uint8_t local_seid);
#endif

/**
 * @brief Release stream and disconnect from remote.
 * @param a2dp_cid          A2DP channel identifier.
 */
void a2dp_sink_disconnect(uint16_t a2dp_cid);

/**
 * @brief Select and configure SBC endpoint
 * @param a2dp_cid          A2DP channel identifier.
 * @param local_seid        ID of a local stream endpoint.
 * @param remote_seid       ID of a remote stream endpoint.
 * @param configuration     SBC Configuration
 * @return status
 */
uint8_t a2dp_sink_set_config_sbc(uint16_t a2dp_cid, uint8_t local_seid, uint8_t remote_seid, const avdtp_configuration_sbc_t * configuration);

/**
 * @brief Select and configure MPEG AUDIO endpoint
 * @param a2dp_cid          A2DP channel identifier.
 * @param local_seid        ID of a local stream endpoint.
 * @param remote_seid       ID of a remote stream endpoint.
 * @param configuration     MPEG AUDIO Configuration
 * @return status
 */
uint8_t a2dp_sink_set_config_mpeg_audio(uint16_t a2dp_cid, uint8_t local_seid, uint8_t remote_seid, const avdtp_configuration_mpeg_audio_t * configuration);

/**
 * @brief Select and configure MPEG AAC endpoint
 * @param a2dp_cid          A2DP channel identifier.
 * @param local_seid        ID of a local stream endpoint.
 * @param remote_seid       ID of a remote stream endpoint.
 * @param configuration     MPEG AAC Configuration
 * @return status
 */
uint8_t a2dp_sink_set_config_mpeg_aac(uint16_t a2dp_cid,  uint8_t local_seid,  uint8_t remote_seid, const avdtp_configuration_mpeg_aac_t * configuration);

/**
 * @brief Select and configure ATRAC endpoint
 * @param a2dp_cid          A2DP channel identifier.
 * @param local_seid        ID of a local stream endpoint.
 * @param remote_seid       ID of a remote stream endpoint.
 * @param configuration     ATRAC Configuration
 * @return status
 */
uint8_t a2dp_sink_set_config_atrac(uint16_t a2dp_cid,  uint8_t local_seid, uint8_t remote_seid, const avdtp_configuration_atrac_t * configuration);

/**
 * @brief Select and configure Non-A2DP endpoint. Bytes 0-3 of codec information contain Vendor ID, bytes 4-5 contain Vendor Specific Codec ID (little endian)
 * @param a2dp_cid          A2DP channel identifier.
 * @param local_seid        ID of a local stream endpoint.
 * @param remote_seid       ID of a remote stream endpoint.
 * @param media_codec_information
 * @param media_codec_information_len
 * @return status
 */
uint8_t a2dp_sink_set_config_other(uint16_t a2dp_cid,  uint8_t local_seid, uint8_t remote_seid, const uint8_t * media_codec_information, uint8_t media_codec_information_len);

/**
 * @brief Register media configuration validator. Can reject insuitable configuration or report stream endpoint as currently busy
 * @note validator has to return AVDTP error codes like: AVDTP_ERROR_CODE_SEP_IN_USE or AVDTP_ERROR_CODE_UNSUPPORTED_CONFIGURATION
 *       the callback receives the media configuration in the same format as the existing A2dP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION
 *       and similar
 * @param callback
 */
void a2dp_sink_register_media_config_validator(uint8_t (*callback)(const avdtp_stream_endpoint_t * stream_endpoint, const uint8_t * event, uint16_t size));

/**
 * @brief De-Init A2DP Sink device.
 */
void a2dp_sink_deinit(void);

A2DP Source API {#sec:a2dp_source_api}

a2dp_source.h : Audio/Video Distribution Transport Protocol A2DP Source is a device that streames media data.

/**
 * @brief Create A2DP Source service record. 
 * @param service
 * @param service_record_handle
 * @param supported_features 16-bit bitmap, see AVDTP_SOURCE_SF_* values in avdtp.h
 * @param service_name or NULL for default value. Provide "" (empty string) to skip attribute
 * @param service_provider_name or NULL for default value. Provide "" (empty string) to skip attribute
 */
void a2dp_source_create_sdp_record(uint8_t * service, uint32_t service_record_handle, uint16_t supported_features, const char * service_name, const char * service_provider_name);

/**
 * @brief Initialize up A2DP Source device.
 */
void a2dp_source_init(void);

/**
 * @brief Create a stream endpoint of type SOURCE, and register media codec by specifying its capabilities and the default configuration.
 * @param media_type                See avdtp_media_type_t values in avdtp.h (audio, video or multimedia).
 * @param media_codec_type          See avdtp_media_codec_type_t values in avdtp.h 
 * @param codec_capabilities        Media codec capabilities as defined in A2DP spec, section 4 - Audio Codec Interoperability Requirements.
 * @param codec_capabilities_len    Media codec capabilities length.
 * @param codec_configuration       Default media codec configuration.
 * @param codec_configuration_len   Media codec configuration length. 
 *
 * @return local_stream_endpoint                
 */
avdtp_stream_endpoint_t * a2dp_source_create_stream_endpoint(avdtp_media_type_t media_type, avdtp_media_codec_type_t media_codec_type,
                                                             const uint8_t *codec_capabilities, uint16_t codec_capabilities_len,
                                                             uint8_t * codec_configuration, uint16_t codec_configuration_len);

/**
 *  @brief Unregister stream endpoint and free it's memory
 *  @param stream_endpoint created by a2dp_source_create_stream_endpoint
 */
void a2dp_source_finalize_stream_endpoint(avdtp_stream_endpoint_t * stream_endpoint);

/**
 * @brief Register callback for the A2DP Source client. It will receive following subevents of HCI_EVENT_A2DP_META HCI event type: 
 * - A2DP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW:         Indicates that the next media packet can be sent.
 *
 * - A2DP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED             Received when signaling connection with a remote is established.
 * - A2DP_SUBEVENT_SIGNALING_CONNECTION_RELEASED                Received when signaling connection with a remote is released
 * - A2DP_SUBEVENT_STREAM_ESTABLISHED                           Received when stream to a remote device is established.
 * - A2DP_SUBEVENT_STREAM_STARTED                               Received when stream is started.
 * - A2DP_SUBEVENT_STREAM_SUSPENDED                             Received when stream is paused.
 * - A2DP_SUBEVENT_STREAM_STOPED                                received when stream is aborted or stopped.
 * - A2DP_SUBEVENT_STREAM_RELEASED                              Received when stream is released.
 * - A2DP_SUBEVENT_SIGNALING_DELAY_REPORTING_CAPABILITY         Currently the only capability that is passed to client
 * - A2DP_SUBEVENT_SIGNALING_CAPABILITIES_DONE                  Signals that all capabilities are reported
 * - A2DP_SUBEVENT_SIGNALING_DELAY_REPORT                       Delay report
 * - A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION      SBC configuration
 * - A2DP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW          Signals that a media packet can be sent
 * - A2DP_SUBEVENT_COMMAND_REJECTED                             Command reject
 * @param callback
 */
void a2dp_source_register_packet_handler(btstack_packet_handler_t callback);

/**
 * @brief Open stream.
 * @param remote_addr
 * @param avdtp_cid         Assigned A2DP channel identifier used for further A2DP commands.
 */
uint8_t a2dp_source_establish_stream(bd_addr_t remote_addr, uint16_t *avdtp_cid);

    /**
     * @brief Reconfigure stream.
     * @param local_seid          ID assigned to a local stream endpoint
     * @param sampling_frequency  New sampling frequency to use. Cannot be called while stream is active
     */
uint8_t a2dp_source_reconfigure_stream_sampling_frequency(uint16_t a2dp_cid, uint32_t sampling_frequency);

/**
 * @brief Start stream.
 * @param a2dp_cid          A2DP channel identifier.
 * @param local_seid        ID of a local stream endpoint.
 */
uint8_t a2dp_source_start_stream(uint16_t a2dp_cid, uint8_t local_seid);

/**
 * @brief Pause stream.
 * @param a2dp_cid          A2DP channel identifier.
 * @param local_seid        ID of a local stream endpoint.
 */
uint8_t a2dp_source_pause_stream(uint16_t a2dp_cid, uint8_t local_seid);

/**
 * @brief Release stream and disconnect from remote. 
 * @param a2dp_cid          A2DP channel identifier.
 */
uint8_t a2dp_source_disconnect(uint16_t a2dp_cid);

/**
 * @brief Request to send a media packet. Packet can be then sent on reception of A2DP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW event.
 * @param a2dp_cid          A2DP channel identifier.
 * @param local_seid        ID of a local stream endpoint.
 */
void a2dp_source_stream_endpoint_request_can_send_now(uint16_t a2dp_cid, uint8_t local_seid);

/**
 * @brief Return maximal media payload size, does not include media header.
 * @param a2dp_cid          A2DP channel identifier.
 * @param local_seid        ID of a local stream endpoint.
 * @return max_media_payload_size_without_media_header
 */
int a2dp_max_media_payload_size(uint16_t a2dp_cid, uint8_t local_seid);

/**
 * @brief Send media payload.
 * @param a2dp_cid          A2DP channel identifier.
 * @param local_seid        ID of a local stream endpoint.
 * @param marker
 * @param timestamp         in sample rate units
 * @param payload
 * @param payload_size
 * @param marker
 * @return status
 */
uint8_t a2dp_source_stream_send_media_payload_rtp(uint16_t a2dp_cid, uint8_t local_seid, uint8_t marker, uint32_t timestamp,
                                          uint8_t *payload, uint16_t payload_size);

/**
 * @brief Send media packet
 * @param a2dp_cid          A2DP channel identifier.
 * @param local_seid        ID of a local stream endpoint.
 * @param packet
 * @param size
 * @return status
 */
uint8_t a2dp_source_stream_send_media_packet(uint16_t a2dp_cid, uint8_t local_seid, const uint8_t * packet, uint16_t size);

/**
 * @brief Select and configure SBC endpoint
 * @param a2dp_cid          A2DP channel identifier.
 * @param local_seid        ID of a local stream endpoint.
 * @param remote_seid       ID of a remote stream endpoint.
 * @param configuration     SBC Configuration
 * @return status
 */
uint8_t a2dp_source_set_config_sbc(uint16_t a2dp_cid, uint8_t local_seid, uint8_t remote_seid, const avdtp_configuration_sbc_t * configuration);

/**
 * @brief Select and configure MPEG AUDIO endpoint
 * @param a2dp_cid          A2DP channel identifier.
 * @param local_seid        ID of a local stream endpoint.
 * @param remote_seid       ID of a remote stream endpoint.
 * @param configuration     MPEG AUDIO Configuration
 * @return status
 */
uint8_t a2dp_source_set_config_mpeg_audio(uint16_t a2dp_cid, uint8_t local_seid, uint8_t remote_seid, const avdtp_configuration_mpeg_audio_t * configuration);

/**
 * @brief Select and configure MPEG AAC endpoint
 * @param a2dp_cid          A2DP channel identifier.
 * @param local_seid        ID of a local stream endpoint.
 * @param remote_seid       ID of a remote stream endpoint.
 * @param configuration     MPEG AAC Configuration
 * @return status
 */
uint8_t a2dp_source_set_config_mpeg_aac(uint16_t a2dp_cid,  uint8_t local_seid,  uint8_t remote_seid, const avdtp_configuration_mpeg_aac_t * configuration);

/**
 * @brief Select and configure ATRAC endpoint
 * @param a2dp_cid          A2DP channel identifier.
 * @param local_seid        ID of a local stream endpoint.
 * @param remote_seid       ID of a remote stream endpoint.
 * @param configuration     ATRAC Configuration
 * @return status
 */
uint8_t a2dp_source_set_config_atrac(uint16_t a2dp_cid,  uint8_t local_seid, uint8_t remote_seid, const avdtp_configuration_atrac_t * configuration);

/**
 * @brief Select and configure Non-A2DP endpoint. Bytes 0-3 of codec information contain Vendor ID, bytes 4-5 contain Vendor Specific Codec ID (little endian)
 * @param a2dp_cid          A2DP channel identifier.
 * @param local_seid        ID of a local stream endpoint.
 * @param remote_seid       ID of a remote stream endpoint.
 * @param media_codec_information
 * @param media_codec_information_len
 * @return status
 */
uint8_t a2dp_source_set_config_other(uint16_t a2dp_cid,  uint8_t local_seid, uint8_t remote_seid, const uint8_t * media_codec_information, uint8_t media_codec_information_len);

/**
 * @brief Register media configuration validator. Can reject insuitable configuration or report stream endpoint as currently busy
 * @note validator has to return AVDTP error codes like: AVDTP_ERROR_CODE_SEP_IN_USE or AVDTP_ERROR_CODE_UNSUPPORTED_CONFIGURATION
 *       the callback receives the media configuration in the same format as the existing A2dP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION
 *       and similar
 * @param callback
 */
void a2dp_source_register_media_config_validator(uint8_t (*callback)(const avdtp_stream_endpoint_t * stream_endpoint, const uint8_t * event, uint16_t size));

/**
 * @brief De-Init A2DP Source device.
 */
void a2dp_source_deinit(void);

AVDTP Sink API {#sec:avdtp_sink_api}

avdtp_sink.h : Audio/Video Distribution Transport Protocol (AVDTP) Sink is a device that accepts streamed media data.

/**
 * @brief Set up AVDTP Sink device.
 */
void avdtp_sink_init(void);

// returns avdtp_stream_endpoint_t *
avdtp_stream_endpoint_t * avdtp_sink_create_stream_endpoint(avdtp_sep_type_t sep_type, avdtp_media_type_t media_type);

/**
 *  @brief Unregister stream endpoint and free it's memory
 *  @param stream_endpoint created by avdtp_sink_create_stream_endpoint
 */
void avdtp_sink_finalize_stream_endpoint(avdtp_stream_endpoint_t * stream_endpoint);

void avdtp_sink_register_media_transport_category(uint8_t seid);
void avdtp_sink_register_reporting_category(uint8_t seid);
void avdtp_sink_register_delay_reporting_category(uint8_t seid);
void avdtp_sink_register_recovery_category(uint8_t seid, uint8_t maximum_recovery_window_size, uint8_t maximum_number_media_packets);
void avdtp_sink_register_header_compression_category(uint8_t seid, uint8_t back_ch, uint8_t media, uint8_t recovery);
void avdtp_sink_register_multiplexing_category(uint8_t seid, uint8_t fragmentation);

void avdtp_sink_register_media_codec_category(uint8_t seid, avdtp_media_type_t media_type, avdtp_media_codec_type_t media_codec_type, const uint8_t *media_codec_info, uint16_t media_codec_info_len);
void avdtp_sink_register_content_protection_category(uint8_t seid, uint16_t cp_type, const uint8_t * cp_type_value, uint8_t cp_type_value_len);

/**
 * @brief Register callback for the AVDTP Sink client. 
 * @param callback
 */
void avdtp_sink_register_packet_handler(btstack_packet_handler_t callback);

/**
 * @brief Connect to device with a bluetooth address. (and perform configuration?)
 * @param bd_addr
 * @param avdtp_cid Assigned avdtp cid
 */
uint8_t avdtp_sink_connect(bd_addr_t bd_addr, uint16_t * avdtp_cid);

void avdtp_sink_register_media_handler(void (*callback)(uint8_t local_seid, uint8_t *packet, uint16_t size));
/**
 * @brief Disconnect from device with connection handle. 
 * @param avdtp_cid
 */
uint8_t avdtp_sink_disconnect(uint16_t avdtp_cid);

/**
 * @brief Discover stream endpoints
 * @param avdtp_cid
 */
uint8_t avdtp_sink_discover_stream_endpoints(uint16_t avdtp_cid);

/**
 * @brief Get capabilities
 * @param avdtp_cid
 */
uint8_t avdtp_sink_get_capabilities(uint16_t avdtp_cid, uint8_t acp_seid);

/**
 * @brief Get all capabilities
 * @param avdtp_cid
 */
uint8_t avdtp_sink_get_all_capabilities(uint16_t avdtp_cid, uint8_t acp_seid);

/**
 * @brief Set configuration
 * @param avdtp_cid
 */
uint8_t avdtp_sink_set_configuration(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration);

/**
 * @brief Reconfigure stream
 * @param avdtp_cid
 * @param seid
 */
uint8_t avdtp_sink_reconfigure(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration);

/**
 * @brief Get configuration
 * @param avdtp_cid
 */
uint8_t avdtp_sink_get_configuration(uint16_t avdtp_cid, uint8_t acp_seid);


/**
 * @brief Open stream
 * @param avdtp_cid
 * @param seid
 */
uint8_t avdtp_sink_open_stream(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid);


/**
 * @brief Start stream
 * @param local_seid
 */
uint8_t avdtp_sink_start_stream(uint16_t avdtp_cid, uint8_t local_seid);

/**
 * @brief Abort stream
 * @param local_seid
 */
uint8_t avdtp_sink_abort_stream(uint16_t avdtp_cid, uint8_t local_seid);

/**
 * @brief Start stream
 * @param local_seid
 */
uint8_t avdtp_sink_stop_stream(uint16_t avdtp_cid, uint8_t local_seid);

/**
 * @brief Suspend stream
 * @param local_seid
 */
uint8_t avdtp_sink_suspend(uint16_t avdtp_cid, uint8_t local_seid);

/**
 * @brief Report delay
 * @param local_seid
 * @param delay_100us
 */
uint8_t avdtp_sink_delay_report(uint16_t avdtp_cid, uint8_t local_seid, uint16_t delay_100us);

/**
 * @brief Register media configuration validator. Can reject insuitable configuration or report stream endpoint as currently busy
 * @note validator has to return AVDTP error codes like: AVDTP_ERROR_CODE_SEP_IN_USE or AVDTP_ERROR_CODE_UNSUPPORTED_CONFIGURATION
 *       the callback receives the media configuration in the same format as the existing AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION
 *       and similar
 * @param callback
 */
void avdtp_sink_register_media_config_validator(uint8_t (*callback)(const avdtp_stream_endpoint_t * stream_endpoint, const uint8_t * event, uint16_t size));

/**
 * @brief De-Init AVDTP Sink.
 */
void avdtp_sink_deinit(void);

// AVDTP_SI_DELAYREPORT

AVDTP Source API {#sec:avdtp_source_api}

avdtp_source.h : Audio/Video Distribution Transport Protocol (AVDTP) Source is a device that streames media data.

/**
 * @brief Register media transport category with local stream endpoint identified by seid
 * @param seid
 */
void avdtp_source_register_media_transport_category(uint8_t seid);

/**
 * @brief Register reporting category with local stream endpoint identified by seid
 * @param seid
 */
void avdtp_source_register_reporting_category(uint8_t seid);

/**
 * @brief Register delay reporting category with local stream endpoint identified by seid
 * @param seid
 */
void avdtp_source_register_delay_reporting_category(uint8_t seid);

/**
 * @brief Register recovery category with local stream endpoint identified by seid
 * @param seid
 * @param maximum_recovery_window_size
 * @param maximum_number_media_packets
 */
void avdtp_source_register_recovery_category(uint8_t seid, uint8_t maximum_recovery_window_size, uint8_t maximum_number_media_packets);

/**
 * @brief Register content protection category with local stream endpoint identified by seid
 * @param seid
 * @param cp_type
 * @param cp_type_value
 * @param cp_type_value_len
 */
void avdtp_source_register_content_protection_category(uint8_t seid, uint16_t cp_type, const uint8_t * cp_type_value, uint8_t cp_type_value_len);

/**
 * @brief Register header compression category with local stream endpoint identified by seid
 * @param seid
 * @param back_ch
 * @param media
 * @param recovery
 */
void avdtp_source_register_header_compression_category(uint8_t seid, uint8_t back_ch, uint8_t media, uint8_t recovery);

/**
 * @brief Register media codec category with local stream endpoint identified by seid
 * @param seid
 * @param media_type
 * @param media_codec_type
 * @param media_codec_info
 * @param media_codec_info_len
 */
void avdtp_source_register_media_codec_category(uint8_t seid, avdtp_media_type_t media_type, avdtp_media_codec_type_t media_codec_type, const uint8_t *media_codec_info, uint16_t media_codec_info_len);

/**
 * @brief Register multiplexing category with local stream endpoint identified by seid
 * @param seid
 * @param fragmentation
 */
void avdtp_source_register_multiplexing_category(uint8_t seid, uint8_t fragmentation);

/**
 * @brief Initialize up AVDTP Source device.
 */
void avdtp_source_init(void);

/**
 * @brief Register callback for the AVDTP Source client. See btstack_defines.h for AVDTP_SUBEVENT_* events
 *
 * @param callback
 */
void avdtp_source_register_packet_handler(btstack_packet_handler_t callback);

/**
 * @brief Connect to device with a bluetooth address. (and perform configuration?)
 * @param bd_addr
 * @param avdtp_cid Assigned avdtp cid
 * @return status ERROR_CODE_SUCCESS if succesful, otherwise BTSTACK_MEMORY_ALLOC_FAILED, SDP_QUERY_BUSY
 */
uint8_t avdtp_source_connect(bd_addr_t bd_addr, uint16_t * avdtp_cid);

/**
 * @brief Disconnect from device with connection handle. 
 * @param avdtp_cid
 * @return status ERROR_CODE_SUCCESS if succesful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER
 */
uint8_t avdtp_source_disconnect(uint16_t avdtp_cid);

/**
 * @brief Discover stream endpoints
 * @param avdtp_cid
 * @return status ERROR_CODE_SUCCESS if succesful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, ERROR_CODE_COMMAND_DISALLOWED
 */
uint8_t avdtp_source_discover_stream_endpoints(uint16_t avdtp_cid);

/**
 * @brief Get capabilities
 * @param avdtp_cid
 * @return status ERROR_CODE_SUCCESS if succesful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, ERROR_CODE_COMMAND_DISALLOWED
 */
uint8_t avdtp_source_get_capabilities(uint16_t avdtp_cid, uint8_t acp_seid);

/**
 * @brief Get all capabilities
 * @param avdtp_cid
 * @return status ERROR_CODE_SUCCESS if succesful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, ERROR_CODE_COMMAND_DISALLOWED
 */
uint8_t avdtp_source_get_all_capabilities(uint16_t avdtp_cid, uint8_t acp_seid);

/**
 * @brief Set configuration
 * @param avdtp_cid
 * @return status ERROR_CODE_SUCCESS if succesful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, ERROR_CODE_COMMAND_DISALLOWED
 */
uint8_t avdtp_source_set_configuration(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration);

/**
 * @brief Reconfigure stream
 * @param avdtp_cid
 * @param seid
 * @return status ERROR_CODE_SUCCESS if succesful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, ERROR_CODE_COMMAND_DISALLOWED
 */
uint8_t avdtp_source_reconfigure(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration);

/**
 * @brief Get configuration
 * @param avdtp_cid
 * @return status ERROR_CODE_SUCCESS if succesful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, ERROR_CODE_COMMAND_DISALLOWED
 */
uint8_t avdtp_source_get_configuration(uint16_t avdtp_cid, uint8_t acp_seid);


/**
 * @brief Open stream
 * @param avdtp_cid
 * @param seid
 * @return status ERROR_CODE_SUCCESS if succesful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, ERROR_CODE_COMMAND_DISALLOWED
 */
uint8_t avdtp_source_open_stream(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid);

/**
 * @brief Start stream
 * @param local_seid
* @return status ERROR_CODE_SUCCESS if succesful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, ERROR_CODE_COMMAND_DISALLOWED
 */
uint8_t avdtp_source_start_stream(uint16_t avdtp_cid, uint8_t local_seid);

/**
 * @brief Abort stream
 * @param local_seid
 * @return status ERROR_CODE_SUCCESS if succesful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, ERROR_CODE_COMMAND_DISALLOWED
 */
uint8_t avdtp_source_abort_stream(uint16_t avdtp_cid, uint8_t local_seid);

/**
 * @brief Start stream
 * @param local_seid
 * @return status ERROR_CODE_SUCCESS if succesful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, ERROR_CODE_COMMAND_DISALLOWED 
 */
uint8_t avdtp_source_stop_stream(uint16_t avdtp_cid, uint8_t local_seid);

/**
 * @brief Suspend stream
 * @param local_seid
 * @return status ERROR_CODE_SUCCESS if succesful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, ERROR_CODE_COMMAND_DISALLOWED 
 */
uint8_t avdtp_source_suspend(uint16_t avdtp_cid, uint8_t local_seid);

/**
 * @brief Create stream endpoint
 * @param sep_type          AVDTP_SOURCE or AVDTP_SINK, see avdtp.h
 * @param media_type        AVDTP_AUDIO, AVDTP_VIDEO or AVDTP_MULTIMEDIA, see avdtp.h
 * @return pointer to newly created stream endpoint, or NULL if allocation failed
 */
avdtp_stream_endpoint_t * avdtp_source_create_stream_endpoint(avdtp_sep_type_t sep_type, avdtp_media_type_t media_type);

/**
 *  @brief Unregister stream endpoint and free it's memory
 *  @param stream_endpoint created by avdtp_sink_create_stream_endpoint
 */
void avdtp_source_finalize_stream_endpoint(avdtp_stream_endpoint_t * stream_endpoint);

/**
 * @brief Send media packet
 * @param avdtp_cid         AVDTP channel identifier.
 * @param local_seid        ID of a local stream endpoint.
 * @param packet
 * @param size
 * @return status
 */
uint8_t avdtp_source_stream_send_media_packet(uint16_t avdtp_cid, uint8_t local_seid, const uint8_t * packet, uint16_t size);

/**
 * @brief Send media payload including RTP header
 * @param avdtp_cid         AVDTP channel identifier.
 * @param local_seid        ID of a local stream endpoint.
 * @param marker
 * @param timestamp         in sample rate units
 * @param payload
 * @param size
 * @return status
 */
uint8_t avdtp_source_stream_send_media_payload_rtp(uint16_t avdtp_cid, uint8_t local_seid, uint8_t marker, uint32_t timestamp,
                                           const uint8_t *payload, uint16_t size);

/**
 * @brief Request to send a media packet. Packet can be then sent on reception of AVDTP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW event.
 * @param avdtp_cid         AVDTP channel identifier.
 * @param local_seid        ID of a local stream endpoint.
 */
void avdtp_source_stream_endpoint_request_can_send_now(uint16_t avddp_cid, uint8_t local_seid);

/**
 * @brief Return maximal media payload size, does not include media header.
 * @param avdtp_cid         AVDTP channel identifier.
 * @param local_seid        ID of a local stream endpoint.
 */
int avdtp_max_media_payload_size(uint16_t avdtp_cid, uint8_t local_seid);

/**
 * @brief Register media configuration validator. Can reject insuitable configuration or report stream endpoint as currently busy
 * @note validator has to return AVDTP error codes like: AVDTP_ERROR_CODE_SEP_IN_USE or AVDTP_ERROR_CODE_UNSUPPORTED_CONFIGURATION
 *       the callback receives the media configuration in the same format as the existing AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION
 *       and similar
 * @param callback
 */
void avdtp_source_register_media_config_validator(uint8_t (*callback)(const avdtp_stream_endpoint_t * stream_endpoint, const uint8_t * event, uint16_t size));

/**
 * @brief De-Init AVDTP Source.
 */
void avdtp_source_deinit(void);

AVRCP Browsing API {#sec:avrcp_browsing_api}

avrcp_browsing.h

/**
 * @brief Set up AVRCP Browsing service
 */
void avrcp_browsing_init(void);

/**
 * @brief Register callback for the AVRCP Browsing Controller client. 
 * @param callback
 */
void avrcp_browsing_register_packet_handler(btstack_packet_handler_t callback);

/**
 * @brief   Connect to AVRCP Browsing service on a remote device, emits AVRCP_SUBEVENT_BROWSING_CONNECTION_ESTABLISHED with status
 * @param   remote_addr
 * @param   ertm_buffer
 * @param   ertm_buffer_size
 * @param   ertm_config
 * @param   avrcp_browsing_cid  outgoing parameter, valid if status == ERROR_CODE_SUCCESS
 * @return status     
 */
uint8_t avrcp_browsing_connect(bd_addr_t remote_addr, uint8_t * ertm_buffer, uint32_t ertm_buffer_size, l2cap_ertm_config_t * ertm_config, uint16_t * avrcp_browsing_cid);

/**
 * @brief Configure incoming connection for Browsing Service.
 * @param avrcp_browsing_cid
 * @param ertm_buffer
 * @param ertm_buffer_size
 * @param ertm_config
 * @return status
 */
uint8_t avrcp_browsing_configure_incoming_connection(uint16_t avrcp_browsing_cid, uint8_t * ertm_buffer, uint32_t ertm_buffer_size, l2cap_ertm_config_t * ertm_config);

/**
 * @brief Decline incoming connection Browsing Service.
 * @param avrcp_browsing_cid
 * @return status
 */
uint8_t avrcp_browsing_decline_incoming_connection(uint16_t avrcp_browsing_cid);

/**
 * @brief   Disconnect from AVRCP Browsing service
 * @param   avrcp_browsing_cid
 * @return status
 */
uint8_t avrcp_browsing_disconnect(uint16_t avrcp_browsing_cid);

/**
 * @brief De-Init AVRCP Browsing
 */
void avrcp_browsing_deinit(void);

AVRCP Browsing Controller API {#sec:avrcp_browsing_controller_api}

avrcp_browsing_controller.h

typedef enum {
    AVRCP_BROWSING_MEDIA_PLAYER_ITEM = 0x01,
    AVRCP_BROWSING_FOLDER_ITEM,
    AVRCP_BROWSING_MEDIA_ELEMENT_ITEM,
    AVRCP_BROWSING_MEDIA_ROOT_FOLDER,
    AVRCP_BROWSING_MEDIA_ELEMENT_ITEM_ATTRIBUTE
} avrcp_browsing_item_type_t;

typedef enum {
    AVRCP_BROWSING_MEDIA_PLAYER_MAJOR_TYPE_AUDIO = 1,
    AVRCP_BROWSING_MEDIA_PLAYER_MAJOR_TYPE_VIDEO = 2,
    AVRCP_BROWSING_MEDIA_PLAYER_MAJOR_TYPE_BROADCASTING_AUDIO = 4,
    AVRCP_BROWSING_MEDIA_PLAYER_MAJOR_TYPE_BROADCASTING_VIDEO = 8
} avrcp_browsing_media_player_major_type_t;

typedef enum {
    AVRCP_BROWSING_MEDIA_PLAYER_SUBTYPE_AUDIO_BOOK = 1,
    AVRCP_BROWSING_MEDIA_PLAYER_SUBTYPE_POADCAST   = 2
} avrcp_browsing_media_player_subtype_t;

typedef enum {
    AVRCP_BROWSING_MEDIA_PLAYER_STATUS_STOPPED = 0,
    AVRCP_BROWSING_MEDIA_PLAYER_STATUS_PLAYING,
    AVRCP_BROWSING_MEDIA_PLAYER_STATUS_PAUSED,
    AVRCP_BROWSING_MEDIA_PLAYER_STATUS_FWD_SEEK,
    AVRCP_BROWSING_MEDIA_PLAYER_STATUS_REV_SEEK,
    AVRCP_BROWSING_MEDIA_PLAYER_STATUS_ERROR = 0xFF
} avrcp_browsing_media_player_status_t;

typedef enum {
    AVRCP_BROWSING_FOLDER_TYPE_MIXED = 0x00,
    AVRCP_BROWSING_FOLDER_TYPE_TITLES,
    AVRCP_BROWSING_FOLDER_TYPE_ALBUMS,
    AVRCP_BROWSING_FOLDER_TYPE_ARTISTS,
    AVRCP_BROWSING_FOLDER_TYPE_GENRES,
    AVRCP_BROWSING_FOLDER_TYPE_PLAYLISTS,
    AVRCP_BROWSING_FOLDER_TYPE_YEARS
} avrcp_browsing_folder_type_t;

typedef enum {
    AVRCP_BROWSING_MEDIA_TYPE_AUDIO = 0x00,
    AVRCP_BROWSING_MEDIA_TYPE_VIDEO
} avrcp_browsing_media_type_t;

/**
 * @brief Set up AVRCP Browsing Controller device.
 */
void avrcp_browsing_controller_init(void);

/**
 * @brief Register callback for the AVRCP Browsing Controller client. 
 * @param callback
 */
void avrcp_browsing_controller_register_packet_handler(btstack_packet_handler_t callback);

/**
 * @brief Retrieve a list of media players.
 * @param avrcp_browsing_cid
 * @param start_item
 * @param end_item
 * @param attr_bitmap Use AVRCP_MEDIA_ATTR_ALL for all, and AVRCP_MEDIA_ATTR_NONE for none. Otherwise, see avrcp_media_attribute_id_t for the bitmap position of attrs. 
 **/
uint8_t avrcp_browsing_controller_get_media_players(uint16_t avrcp_browsing_cid, uint32_t start_item, uint32_t end_item, uint32_t attr_bitmap);

/**
 * @brief Retrieve a list of folders and media items of the browsed player.
 * @param avrcp_browsing_cid
 * @param start_item
 * @param end_item
 * @param attr_bitmap Use AVRCP_MEDIA_ATTR_ALL for all, and AVRCP_MEDIA_ATTR_NONE for none. Otherwise, see avrcp_media_attribute_id_t for the bitmap position of attrs. 
 **/
uint8_t avrcp_browsing_controller_browse_file_system(uint16_t avrcp_browsing_cid, uint32_t start_item, uint32_t end_item, uint32_t attr_bitmap);

/**
 * @brief Retrieve a list of media items of the browsed player.
 * @param avrcp_browsing_cid
 * @param start_item
 * @param end_item
 * @param attr_bitmap Use AVRCP_MEDIA_ATTR_ALL for all, and AVRCP_MEDIA_ATTR_NONE for none. Otherwise, see avrcp_media_attribute_id_t for the bitmap position of attrs. 
 **/
uint8_t avrcp_browsing_controller_browse_media(uint16_t avrcp_browsing_cid, uint32_t start_item, uint32_t end_item, uint32_t attr_bitmap);

/**
 * @brief Retrieve a list of folders and media items of the addressed player.
 * @param avrcp_browsing_cid
 * @param start_item
 * @param end_item
 * @param attr_bitmap Use AVRCP_MEDIA_ATTR_ALL for all, and AVRCP_MEDIA_ATTR_NONE for none. Otherwise, see avrcp_media_attribute_id_t for the bitmap position of attrs. 
 **/
uint8_t avrcp_browsing_controller_browse_now_playing_list(uint16_t avrcp_browsing_cid, uint32_t start_item, uint32_t end_item, uint32_t attr_bitmap);

/** 
 * @brief Set browsed player. Calling this command is required prior to browsing the player's file system. Some players may support browsing only when set as the Addressed Player.
 * @param avrcp_browsing_cid
 * @param browsed_player_id
 */
uint8_t avrcp_browsing_controller_set_browsed_player(uint16_t avrcp_browsing_cid, uint16_t browsed_player_id);

/** 
 * @brief Get total num attributes
 * @param avrcp_browsing_cid
 * @param scope 
 */
uint8_t avrcp_browsing_controller_get_total_nr_items_for_scope(uint16_t avrcp_browsing_cid, avrcp_browsing_scope_t scope);

/**
 * @brief Navigate one level up or down in thhe virtual filesystem. Requires that s browsed player is set.
 * @param avrcp_browsing_cid
 * @param direction     0-folder up, 1-folder down    
 * @param folder_uid    8 bytes long
 **/
uint8_t avrcp_browsing_controller_change_path(uint16_t avrcp_browsing_cid, uint8_t direction, uint8_t * folder_uid);
uint8_t avrcp_browsing_controller_go_up_one_level(uint16_t avrcp_browsing_cid);
uint8_t avrcp_browsing_controller_go_down_one_level(uint16_t avrcp_browsing_cid, uint8_t * folder_uid);


/**
 * @brief Retrives metadata information (title, artist, album, ...) about a media element with given uid. 
 * @param avrcp_browsing_cid
 * @param uid            media element uid 
 * @param uid_counter    Used to detect change to the media database on target device. A TG device that supports the UID Counter shall update the value of the counter on each change to the media database.
 * @param attr_bitmap    0x00000000 - retrieve all, chek avrcp_media_attribute_id_t in avrcp.h for detailed bit position description.
 * @param scope          check avrcp_browsing_scope_t in avrcp.h
 **/
uint8_t avrcp_browsing_controller_get_item_attributes_for_scope(uint16_t avrcp_browsing_cid, uint8_t * uid, uint16_t uid_counter, uint32_t attr_bitmap, avrcp_browsing_scope_t scope);

/**
 * @brief Searches are performed from the current folder in the Browsed Players virtual filesystem. The search applies to the current folder and all folders below that.
 * @param avrcp_browsing_cid
 * @param search_str_len
 * @param search_str
 * @return status 
 **/
uint8_t avrcp_browsing_controller_search(uint16_t avrcp_browsing_cid, uint16_t search_str_len, char * search_str);

/**
 * @brief De-Init AVRCP Browsing Controller
 */
void avrcp_browsing_controller_deinit(void);

AVRCP Browsing Target API {#sec:avrcp_browsing_target_api}

avrcp_browsing_target.h

/**
 * @brief Set up AVRCP Browsing Controller device.
 */
void avrcp_browsing_target_init(void);

/**
 * @brief Register callback for the AVRCP Browsing Controller client. 
 * @param callback
 */
void avrcp_browsing_target_register_packet_handler(btstack_packet_handler_t callback);

/**
 * @brief Accept set browsed player
 * @param browsing_cid
 * @param uid_counter
 * @param browsed_player_id
 * @param response
 * @param response_size
 */
uint8_t avrcp_browsing_target_send_accept_set_browsed_player(uint16_t browsing_cid, uint16_t uid_counter, uint16_t browsed_player_id, uint8_t * response, uint16_t response_len);

/**
 * @brief Reject set browsed player
 * @param browsing_cid
 * @param status
 */
uint8_t avrcp_browsing_target_send_reject_set_browsed_player(uint16_t browsing_cid, avrcp_status_code_t status);

/**
 * @brief Send answer to get folder items query on event AVRCP_SUBEVENT_BROWSING_GET_FOLDER_ITEMS. The first byte of this event defines the scope of the query, see avrcp_browsing_scope_t.
 * @param browsing_cid
 * @param uid_counter
 * @param attr_list
 * @param attr_list_size
 */
uint8_t avrcp_browsing_target_send_get_folder_items_response(uint16_t browsing_cid, uint16_t uid_counter, uint8_t * attr_list, uint16_t attr_list_size);

/**
 * @brief Send answer to get total number of items query on event AVRCP_SUBEVENT_BROWSING_GET_TOTAL_NUM_ITEMS. The first byte of this event defines the scope of the query, see avrcp_browsing_scope_t.
 * @param browsing_cid
 * @param uid_counter
 * @param total_num_items
 */
uint8_t avrcp_browsing_target_send_get_total_num_items_response(uint16_t browsing_cid, uint16_t uid_counter, uint32_t total_num_items);

/**
 * @brief De-Init AVRCP Browsing Controller
 */
void avrcp_browsing_target_deinit(void);

AVRCP Controller API {#sec:avrcp_controller_api}

avrcp_controller.h

typedef enum {
    AVRCP_CONTROLLER_SUPPORTED_FEATURE_CATEGORY_PLAYER_OR_RECORDER = 0,
    AVRCP_CONTROLLER_SUPPORTED_FEATURE_CATEGORY_MONITOR_OR_AMPLIFIER,
    AVRCP_CONTROLLER_SUPPORTED_FEATURE_CATEGORY_TUNER,
    AVRCP_CONTROLLER_SUPPORTED_FEATURE_CATEGORY_MENU,
    AVRCP_CONTROLLER_SUPPORTED_FEATURE_RESERVED_4,
    AVRCP_CONTROLLER_SUPPORTED_FEATURE_RESERVED_5,
    AVRCP_CONTROLLER_SUPPORTED_FEATURE_BROWSING,
    AVRCP_CONTROLLER_SUPPORTED_FEATURE_COVER_ART_GET_IMAGE_PROPERTIES,
    AVRCP_CONTROLLER_SUPPORTED_FEATURE_COVER_ART_GET_IMAGE,
    AVRCP_CONTROLLER_SUPPORTED_FEATURE_COVER_ART_GET_LINKED_THUMBNAIL
} avrcp_controller_supported_feature_t;

/**
 * @brief AVRCP Controller service record. 
 * @param service
 * @param service_record_handle
 * @param supported_features 16-bit bitmap, see AVRCP_FEATURE_MASK_* in avrcp.h
 * @param service_name or NULL for default value. Provide "" (empty string) to skip attribute
 * @param service_provider_name or NULL for default value. Provide "" (empty string) to skip attribute
 */
void avrcp_controller_create_sdp_record(uint8_t * service, uint32_t service_record_handle, uint16_t supported_features, const char * service_name, const char * service_provider_name);

/**
 * @brief Set up AVRCP Controller service.
 */
void avrcp_controller_init(void);

/**
 * @brief Register callback for the AVRCP Controller client. 
 * @param callback
 */
void avrcp_controller_register_packet_handler(btstack_packet_handler_t callback);

/**
 * @brief Set max num fragments in whuch message can be transmited.
 * @param avrcp_cid
 * @param max_num_fragments
 * @return status
 */
uint8_t avrcp_controller_set_max_num_fragments(uint16_t avrcp_cid, uint8_t max_num_fragments);


/**
 * @brief Unit info.
 * @param avrcp_cid
 * @return status
 */
uint8_t avrcp_controller_unit_info(uint16_t avrcp_cid);

/**
 * @brief Subunit info.
 * @param avrcp_cid
 * @return status
 */
uint8_t avrcp_controller_subunit_info(uint16_t avrcp_cid);

/**
 * @brief Get capabilities.
 * @param avrcp_cid
 * @return status
 */
uint8_t avrcp_controller_get_supported_company_ids(uint16_t avrcp_cid);

/**
 * @brief Get supported Events.
 * @param avrcp_cid
 * @return status
 */
uint8_t avrcp_controller_get_supported_events(uint16_t avrcp_cid);


/**
 * @brief Start continuous cmd (play, pause, volume up, ...). Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status.
 * @param avrcp_cid
 * @return status
 */
uint8_t avrcp_controller_start_press_and_hold_cmd(uint16_t avrcp_cid, avrcp_operation_id_t operation_id);

/**
 * @brief Stops continuous cmd (play, pause, volume up, ...). Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status.
 * @param avrcp_cid
 * @return status
 */
uint8_t avrcp_controller_release_press_and_hold_cmd(uint16_t avrcp_cid);

/**
 * @brief Play. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status.
 * @param avrcp_cid
 * @return status
 */
uint8_t avrcp_controller_play(uint16_t avrcp_cid);
uint8_t avrcp_controller_press_and_hold_play(uint16_t avrcp_cid);

/**
 * @brief Stop. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status.
 * @param avrcp_cid
 * @return status
 */
uint8_t avrcp_controller_stop(uint16_t avrcp_cid);
uint8_t avrcp_controller_press_and_hold_stop(uint16_t avrcp_cid);

/**
 * @brief Pause. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status.
 * @param avrcp_cid
 * @return status
 */
uint8_t avrcp_controller_pause(uint16_t avrcp_cid);
uint8_t avrcp_controller_press_and_hold_pause(uint16_t avrcp_cid);

/**
 * @brief Single step - fast forward. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status.
 * @param avrcp_cid
 * @return status
 */
uint8_t avrcp_controller_fast_forward(uint16_t avrcp_cid);
uint8_t avrcp_controller_press_and_hold_fast_forward(uint16_t avrcp_cid);


/**
 * @brief Single step rewind. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status.
 * @param avrcp_cid
 * @return status
 */
uint8_t avrcp_controller_rewind(uint16_t avrcp_cid);
uint8_t avrcp_controller_press_and_hold_rewind(uint16_t avrcp_cid);

/**
 * @brief Forward. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status.
 * @param avrcp_cid
 * @return status
 */
uint8_t avrcp_controller_forward(uint16_t avrcp_cid); 
uint8_t avrcp_controller_press_and_hold_forward(uint16_t avrcp_cid);

/**
 * @brief Backward. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status.
 * @param avrcp_cid
 * @return status
 */
uint8_t avrcp_controller_backward(uint16_t avrcp_cid);
uint8_t avrcp_controller_press_and_hold_backward(uint16_t avrcp_cid);

/**
 * @brief Turns the volume to high. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status.
 * @param avrcp_cid
 * @return status
 */
uint8_t avrcp_controller_volume_up(uint16_t avrcp_cid);
uint8_t avrcp_controller_press_and_hold_volume_up(uint16_t avrcp_cid);
/**
 * @brief Turns the volume to low. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status.
 * @param avrcp_cid
 * @return status
 */
uint8_t avrcp_controller_volume_down(uint16_t avrcp_cid);
uint8_t avrcp_controller_press_and_hold_volume_down(uint16_t avrcp_cid);

/**
 * @brief Puts the sound out. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status.
 * @param avrcp_cid
 * @return status
 */
uint8_t avrcp_controller_mute(uint16_t avrcp_cid);
uint8_t avrcp_controller_press_and_hold_mute(uint16_t avrcp_cid);

/**
 * @brief Get play status. Returns event of type AVRCP_SUBEVENT_PLAY_STATUS (length, position, play_status).
 * If TG does not support SongLength And SongPosition on TG, then TG shall return 0xFFFFFFFF.
 * @param avrcp_cid
 * @return status
 */
uint8_t avrcp_controller_get_play_status(uint16_t avrcp_cid);

/**
 * @brief Enable notification. Response via AVRCP_SUBEVENT_NOTIFICATION_STATE.
 * @param avrcp_cid
 * @param event_id
 * @return status
 */
uint8_t avrcp_controller_enable_notification(uint16_t avrcp_cid, avrcp_notification_event_id_t event_id);

/**
 * @brief Disable notification. Response via AVRCP_SUBEVENT_NOTIFICATION_STATE.
 * @param avrcp_cid
 * @param event_id
 * @return status
 */
uint8_t avrcp_controller_disable_notification(uint16_t avrcp_cid, avrcp_notification_event_id_t event_id);

/**
 * @brief Get info on now playing media using subset of attribute IDs
 * @param avrcp_cid
 * @return status
 */
uint8_t avrcp_controller_get_element_attributes(uint16_t avrcp_cid, uint8_t num_attributes, avrcp_media_attribute_id_t * attributes);

/**
 * @brief Get info on now playing media using all IDs.
 * @param avrcp_cid
 * @return status
 */
uint8_t avrcp_controller_get_now_playing_info(uint16_t avrcp_cid);

/**
 * @brief Get info on now playing media using specific media attribute ID.
 * @param media_attribute_id
 * @param avrcp_cid
 * @return status
 */
uint8_t avrcp_controller_get_now_playing_info_for_media_attribute_id(uint16_t avrcp_cid, avrcp_media_attribute_id_t media_attribute_id);

/**
 * @brief Set absolute volume 0-127 (corresponds to 0-100%). Response via AVRCP_SUBEVENT_SET_ABSOLUTE_VOLUME_RESPONSE
 * @param avrcp_cid
 * @return status
 */
uint8_t avrcp_controller_set_absolute_volume(uint16_t avrcp_cid, uint8_t volume);


/**
 * @brief Skip to next playing media. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status.
 * @param avrcp_cid
 * @return status
 */
uint8_t avrcp_controller_skip(uint16_t avrcp_cid);

/**
 * @brief Query repeat and shuffle mode. Response via AVRCP_SUBEVENT_SHUFFLE_AND_REPEAT_MODE.
 * @param avrcp_cid
 * @return status
 */
uint8_t avrcp_controller_query_shuffle_and_repeat_modes(uint16_t avrcp_cid);

/**
 * @brief Set shuffle mode. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status.
 * @param avrcp_cid
 * @return status
 */
uint8_t avrcp_controller_set_shuffle_mode(uint16_t avrcp_cid, avrcp_shuffle_mode_t mode);

/**
 * @brief Set repeat mode. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status.
 * @param avrcp_cid
 * @return status
 */
uint8_t avrcp_controller_set_repeat_mode(uint16_t avrcp_cid, avrcp_repeat_mode_t mode);

/**
 * @brief The PlayItem command starts playing an item indicated by the UID. It is routed to the Addressed Player.
 * @param avrcp_cid
 * @param uid
 * @param uid_counter
 * @param scope
 **/
uint8_t avrcp_controller_play_item_for_scope(uint16_t avrcp_cid, uint8_t * uid, uint16_t uid_counter, avrcp_browsing_scope_t scope);

/**
 * @brief Adds an item indicated by the UID to the Now Playing queue.
 * @param avrcp_cid
 * @param uid
 * @param uid_counter
 * @param scope
 **/
uint8_t avrcp_controller_add_item_from_scope_to_now_playing_list(uint16_t avrcp_cid, uint8_t * uid, uint16_t uid_counter, avrcp_browsing_scope_t scope);

/** 
 * @brief Set addressed player.  
 * @param avrcp_cid
 * @param addressed_player_id
 */
uint8_t avrcp_controller_set_addressed_player(uint16_t avrcp_cid, uint16_t addressed_player_id);

/** 
 * @brief Send custom command
 * @param avrcp_cid
 * @param command_type
 * @param subunit_type
 * @param subunit_id
 * @param pdu_id
 * @param company_id
 * @param data
 * @param data_len
 */
uint8_t avrcp_controller_send_custom_command(uint16_t avrcp_cid, 
    avrcp_command_type_t command_type, 
    avrcp_subunit_type_t subunit_type, avrcp_subunit_id_t subunit_id, 
    avrcp_pdu_id_t pdu_id, uint32_t company_id, 
    const uint8_t * data, uint16_t data_len);

/**
 * @brief De-Init AVRCP Controller
 */
void avrcp_controller_deinit(void);

AVRCP Cover Art Client API {#sec:avrcp_cover_art_client_api}

avrcp_cover_art_client.h

/**
 * @brief Set up AVRCP Cover Art client
 */
void avrcp_cover_art_client_init(void);

/**
 * @brief   Connect to AVRCP Cover Art service on a remote device, emits AVRCP_SUBEVENT_COVER_ART_CONNECTION_ESTABLISHED with status
 * @param   packet_handler
 * @param   remote_addr
 * @param   ertm_buffer
 * @param   ertm_buffer_size
 * @param   ertm_config
 * @param   avrcp_cover_art_cid  outgoing parameter, valid if status == ERROR_CODE_SUCCESS
 * @return status     
 */
uint8_t
avrcp_cover_art_client_connect(avrcp_cover_art_client_t *cover_art_client, btstack_packet_handler_t packet_handler,
                               bd_addr_t remote_addr, uint8_t *ertm_buffer, uint32_t ertm_buffer_size,
                               const l2cap_ertm_config_t *ertm_config, uint16_t *avrcp_cover_art_cid);

/**
 * @brief Request cover art thumbnail for cover with a given image handle retrieved via
 *        - avrcp_controller_get_now_playing_info or
 *        - avrcp_controller_get_element_attributes(... AVRCP_MEDIA_ATTR_DEFAULT_COVER_ART ...)
 * @param avrcp_cover_art_cid
 * @param image_handle
 * @return status
 */
uint8_t avrcp_cover_art_client_get_linked_thumbnail(uint16_t avrcp_cover_art_cid, const char * image_handle);

/**
 * @brief Request cover art image for given image handle retrieved via
 *        - avrcp_controller_get_now_playing_info or
 *        - avrcp_controller_get_element_attributes(... AVRCP_MEDIA_ATTR_DEFAULT_COVER_ART ...)
 *        and given image descriptor
 * @param avrcp_cover_art_cid
 * @param image_handle
 * @param image_descriptor
 * @return status
 */
uint8_t avrcp_cover_art_client_get_image(uint16_t avrcp_cover_art_cid, const char * image_handle, const char * image_descriptor);

/**
 * @brief Request image properties for given image handle retrieved via
 *        - avrcp_controller_get_now_playing_info or
 *        - avrcp_controller_get_element_attributes(... AVRCP_MEDIA_ATTR_DEFAULT_COVER_ART ...)
 * @param avrcp_cover_art_cid
 * @param image_handle
 * @return status
 */
uint8_t avrcp_cover_art_client_get_image_properties(uint16_t avrcp_cover_art_cid, const char * image_handle);

/**
 * @brief   Disconnect from AVRCP Cover Art service
 * @param   avrcp_cover_art_cid
 * @return status
 */
uint8_t avrcp_cover_art_client_disconnect(uint16_t avrcp_cover_art_cid);

/**
 * @brief De-Init AVRCP Cover Art Client
 */
void avrcp_cover_art_client_deinit(void);

AVRCP Media Item Iterator API {#sec:avrcp_media_item_iterator_api}

avrcp_media_item_iterator.h

typedef struct avrcp_media_item_context {
     const uint8_t * data;
     uint16_t   offset;
     uint16_t   length;
} avrcp_media_item_context_t;

// Media item data iterator
void avrcp_media_item_iterator_init(avrcp_media_item_context_t *context, uint16_t avrcp_media_item_len, const uint8_t * avrcp_media_item_data);
int  avrcp_media_item_iterator_has_more(const avrcp_media_item_context_t * context);
void avrcp_media_item_iterator_next(avrcp_media_item_context_t * context);

// Access functions
uint32_t          avrcp_media_item_iterator_get_attr_id(const avrcp_media_item_context_t * context);
uint16_t         avrcp_media_item_iterator_get_attr_charset(const avrcp_media_item_context_t * context);
uint16_t         avrcp_media_item_iterator_get_attr_value_len(const avrcp_media_item_context_t * context);
const uint8_t *  avrcp_media_item_iterator_get_attr_value(const avrcp_media_item_context_t * context);

AVRCP Target API {#sec:avrcp_target_api}

avrcp_target.h

typedef enum {
    AVRCP_TARGET_SUPPORTED_FEATURE_CATEGORY_PLAYER_OR_RECORDER = 0,
    AVRCP_TARGET_SUPPORTED_FEATURE_CATEGORY_MONITOR_OR_AMPLIFIER,
    AVRCP_TARGET_SUPPORTED_FEATURE_CATEGORY_TUNER,
    AVRCP_TARGET_SUPPORTED_FEATURE_CATEGORY_MENU,
    AVRCP_TARGET_SUPPORTED_FEATURE_PLAYER_APPLICATION_SETTINGS, // AVRCP_TARGET_SUPPORTED_FEATURE_CATEGORY_PLAYER_OR_RECORDER must be 1 for this feature to be set
    AVRCP_TARGET_SUPPORTED_FEATURE_GROUP_NAVIGATION,            // AVRCP_TARGET_SUPPORTED_FEATURE_CATEGORY_PLAYER_OR_RECORDER must be 1 for this feature to be set
    AVRCP_TARGET_SUPPORTED_FEATURE_BROWSING,
    AVRCP_TARGET_SUPPORTED_FEATURE_MULTIPLE_MEDIA_PLAYER_APPLICATIONS,
    AVRCP_TARGET_SUPPORTED_FEATURE_COVER_ART,
} avrcp_target_supported_feature_t;

/**
 * @brief AVRCP Target service record. 
 * @param service
 * @param service_record_handle
 * @param supported_features 16-bit bitmap, see AVRCP_FEATURE_MASK_* in avrcp.h
 * @param service_name or NULL for default value. Provide "" (empty string) to skip attribute
 * @param service_provider_name or NULL for default value. Provide "" (empty string) to skip attribute
 */
void    avrcp_target_create_sdp_record(uint8_t * service, uint32_t service_record_handle, uint16_t supported_features, const char * service_name, const char * service_provider_name);

/**
 * @brief Set up AVRCP Target service.
 */
void    avrcp_target_init(void);

/**
 * @brief Register callback for the AVRCP Target client. 
 * @param callback
 */
void    avrcp_target_register_packet_handler(btstack_packet_handler_t callback);

/**
 * @brief Select Player that is controlled by Controller
 * @param callback
 * @note Callback should return if selected player is valid
 */
void avrcp_target_register_set_addressed_player_handler(bool (*callback)(uint16_t player_id));

/**
 * @brief Register a list of Company IDs supported by target. 
 * @param avrcp_cid
 * @param num_companies
 * @param companies
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection is not found, otherwise ERROR_CODE_SUCCESS
 */
uint8_t avrcp_target_support_companies(uint16_t avrcp_cid, uint8_t num_companies, const uint32_t *companies);

/**
 * @brief Register event ID supported by target.
 * @param avrcp_cid
 * @param event_id 
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection is not found, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE for unsupported event id, otherwise ERROR_CODE_SUCCESS, 
 */
uint8_t avrcp_target_support_event(uint16_t avrcp_cid, avrcp_notification_event_id_t event_id);

/**
 * @brief Send a play status.
 * @note  The avrcp_target_packet_handler will receive AVRCP_SUBEVENT_PLAY_STATUS_QUERY event. Use this function to respond.
 * @param avrcp_cid
 * @param song_length_ms
 * @param song_position_ms
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection is not found, otherwise ERROR_CODE_SUCCESS
 */
uint8_t avrcp_target_play_status(uint16_t avrcp_cid, uint32_t song_length_ms, uint32_t song_position_ms, avrcp_playback_status_t status);

/**
 * @brief Set Now Playing Info that is send to Controller if notifications are enabled
 * @param avrcp_cid
 * @param current_track
 * @param total_tracks
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection is not found, ERROR_CODE_COMMAND_DISALLOWED if no track is provided, otherwise ERROR_CODE_SUCCESS
 */
uint8_t avrcp_target_set_now_playing_info(uint16_t avrcp_cid, const avrcp_track_t * current_track, uint16_t total_tracks);

/**
 * @brief Set Playing status and send to Controller
 * @param avrcp_cid
 * @param playback_status
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection is not found, otherwise ERROR_CODE_SUCCESS
 */
uint8_t avrcp_target_set_playback_status(uint16_t avrcp_cid, avrcp_playback_status_t playback_status);

/**
 * @brief Set Unit Info
 * @param avrcp_cid
 * @param unit_type
 * @param company_id
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection is not found, otherwise ERROR_CODE_SUCCESS
 */
uint8_t avrcp_target_set_unit_info(uint16_t avrcp_cid, avrcp_subunit_type_t unit_type, uint32_t company_id);

/**
 * @brief Set Subunit Info
 * @param avrcp_cid
 * @param subunit_type
 * @param subunit_info_data
 * @param subunit_info_data_size
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection is not found, otherwise ERROR_CODE_SUCCESS
 */
uint8_t avrcp_target_set_subunit_info(uint16_t avrcp_cid, avrcp_subunit_type_t subunit_type, const uint8_t * subunit_info_data, uint16_t subunit_info_data_size);

/**
 * @brief Send Playing Content Changed Notification if enabled
 * @param avrcp_cid
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection is not found, otherwise ERROR_CODE_SUCCESS
 */
uint8_t avrcp_target_playing_content_changed(uint16_t avrcp_cid);

/**
 * @brief Send Addressed Player Changed Notification if enabled
 * @param avrcp_cid
 * @param player_id
 * @param uid_counter
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection is not found, otherwise ERROR_CODE_SUCCESS
 */
uint8_t avrcp_target_addressed_player_changed(uint16_t avrcp_cid, uint16_t player_id, uint16_t uid_counter);

/**
 * @brief Set Battery Status Changed and send notification if enabled
 * @param avrcp_cid
 * @param battery_status
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection is not found, otherwise ERROR_CODE_SUCCESS
 */
uint8_t avrcp_target_battery_status_changed(uint16_t avrcp_cid, avrcp_battery_status_t battery_status);

/**
 * @brief Overwrite the absolute volume requested by controller with the actual absolute volume. 
 * This function can only be called on AVRCP_SUBEVENT_NOTIFICATION_VOLUME_CHANGED event, which indicates a set absolute volume request by controller. 
 * If the absolute volume requested by controller does not match the granularity of volume control the TG provides, you can use this function to adjust the actual value.
 *
 * @param avrcp_cid
 * @param absolute_volume
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection is not found, otherwise ERROR_CODE_SUCCESS
 */
uint8_t avrcp_target_adjust_absolute_volume(uint16_t avrcp_cid, uint8_t absolute_volume);


/**
 * @brief Set Absolute Volume and send notification if enabled 
 * @param avrcp_cid
 * @param absolute_volume
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection is not found, otherwise ERROR_CODE_SUCCESS
 */
uint8_t avrcp_target_volume_changed(uint16_t avrcp_cid, uint8_t absolute_volume);

/**
 * @brief Set Track and send notification if enabled
 * @param avrcp_cid
 * @param trackID
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection is not found, otherwise ERROR_CODE_SUCCESS
 */
uint8_t avrcp_target_track_changed(uint16_t avrcp_cid, uint8_t * trackID);

/**
 * @brief Send Operation Rejected message
 * @param avrcp_cid
 * @param opid
 * @param operands_length
 * @param operand
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection is not found, otherwise ERROR_CODE_SUCCESS
 */
uint8_t avrcp_target_operation_rejected(uint16_t avrcp_cid, avrcp_operation_id_t opid, uint8_t operands_length, uint8_t operand);

/**
 * @brief Send Operation Accepted message
 * @param avrcp_cid
 * @param opid
 * @param operands_length
 * @param operand
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection is not found, otherwise ERROR_CODE_SUCCESS
 */
uint8_t avrcp_target_operation_accepted(uint16_t avrcp_cid, avrcp_operation_id_t opid, uint8_t operands_length, uint8_t operand);

/**
 * @brief Send Operation Not Implemented message
 * @param avrcp_cid
 * @param opid
 * @param operands_length
 * @param operand
 * @return status ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection is not found, otherwise ERROR_CODE_SUCCESS
 */
uint8_t avrcp_target_operation_not_implemented(uint16_t avrcp_cid, avrcp_operation_id_t opid, uint8_t operands_length, uint8_t operand);

/**
 * @brief De-Init AVRCP Browsing Target
 */
void avrcp_target_deinit(void);

BNEP API {#sec:bnep_api}

bnep.h

/**
 * @brief Set up BNEP.
 */
void bnep_init(void);

/**
 * @brief Check if a data packet can be send out.
 */
int bnep_can_send_packet_now(uint16_t bnep_cid);

/** 
 * @brief Request emission of BNEP_CAN_SEND_NOW as soon as possible
 * @note BNEP_CAN_SEND_NOW might be emitted during call to this function
 *       so packet handler should be ready to handle it
 * @param bnep_cid
 */
void bnep_request_can_send_now_event(uint16_t bnep_cid);

/**
 * @brief Send a data packet.
 */
int bnep_send(uint16_t bnep_cid, uint8_t *packet, uint16_t len);

/**
 * @brief Set the network protocol filter.
 */
int bnep_set_net_type_filter(uint16_t bnep_cid, bnep_net_filter_t *filter, uint16_t len);

/**
 * @brief Set the multicast address filter.
 */
int bnep_set_multicast_filter(uint16_t bnep_cid, bnep_multi_filter_t *filter, uint16_t len);

/**
 * @brief Set security level required for incoming connections, need to be called before registering services.
 * @deprecated use gap_set_security_level instead
 */
void bnep_set_required_security_level(gap_security_level_t security_level);

/**
 * @brief Creates BNEP connection (channel) to a given server on a remote device with baseband address. A new baseband connection will be initiated if necessary. 
 */
int bnep_connect(btstack_packet_handler_t packet_handler, bd_addr_t addr, uint16_t l2cap_psm, uint16_t uuid_src, uint16_t uuid_dest);

/**
 * @brief Disconnects BNEP channel with given identifier. 
 */
void bnep_disconnect(bd_addr_t addr);

/**
 * @brief Registers BNEP service, set a maximum frame size and assigns a packet handler. On embedded systems, use NULL for connection parameter. 
 */
uint8_t bnep_register_service(btstack_packet_handler_t packet_handler, uint16_t service_uuid, uint16_t max_frame_size);

/**
 * @brief Unregister BNEP service.
 */
void bnep_unregister_service(uint16_t service_uuid);

/**
 * @brief De-Init BNEP
 */
void bnep_deinit(void);

btstack_link_key_db.h : Interface to provide link key storage.

typedef struct {

    // management

    /**
     * @brief Open the Link Key DB
     */
    void (*open)(void);

    /**
     * @brief Sets BD Addr of local Bluetooth Controller.
     * @note Only needed if Bluetooth Controller can be swapped, e.g. USB Dongles on desktop systems
     */
    void (*set_local_bd_addr)(bd_addr_t bd_addr);

    /**
     * @brief Close the Link Key DB
     */
    void (*close)(void);

    // get/set/delete link key

    /**
     * @brief Get Link Key for given address
     * @param addr to lookup
     * @param link_key (out)
     * @param type (out)
     * @return 1 on success
     */
    int  (*get_link_key)(bd_addr_t bd_addr, link_key_t link_key, link_key_type_t * type);

    /**
     * @brief Update/Store Link key
     * @brief addr
     * @brief link_key
     * @brief type of link key
     */
    void (*put_link_key)(bd_addr_t bd_addr, link_key_t link_key, link_key_type_t type);

    /**
     * @brief Delete Link Keys
     * @brief addr
     */
    void (*delete_link_key)(bd_addr_t bd_addr);

    // iterator: it's allowed to delete

    /**
     * @brief Setup iterator
     * @param it
     * @return 1 on success
     */
    int (*iterator_init)(btstack_link_key_iterator_t * it);

    /**
     * @brief Get next Link Key
     * @param it
     * @brief addr
     * @brief link_key
     * @brief type of link key
     * @return 1, if valid link key found
     */
    int  (*iterator_get_next)(btstack_link_key_iterator_t * it, bd_addr_t bd_addr, link_key_t link_key, link_key_type_t * type);

    /**
     * @brief Frees resources allocated by iterator_init
     * @note Must be called after iteration to free resources
     * @param it
     */
    void (*iterator_done)(btstack_link_key_iterator_t * it);

} btstack_link_key_db_t;

btstack_link_key_db_memory.h

/*
 * @brief
 */
const btstack_link_key_db_t * btstack_link_key_db_memory_instance(void);

typedef struct {
    btstack_linked_item_t item;
    bd_addr_t bd_addr;
    link_key_t link_key;
    link_key_type_t link_key_type;
} btstack_link_key_db_memory_entry_t;

btstack_link_key_db_static.h : Static Link Key Storage implementation to use during development/porting: - Link keys have to be manually added to this file to make them usable + Link keys are preserved on reflash in constrast to the program flash based link key store

/*
 * @brief
 */
const btstack_link_key_db_t * btstack_link_key_db_static_instance(void);

btstack_link_key_db_tlv.h : Interface to provide link key storage via BTstack's TLV storage.

/**
 * Init Link Key DB using TLV
 * @param btstack_tlv_impl of btstack_tlv interface
 * @Param btstack_tlv_context of btstack_tlv_interface
 */
const btstack_link_key_db_t * btstack_link_key_db_tlv_get_instance(const btstack_tlv_t * btstack_tlv_impl, void * btstack_tlv_context);

Device ID Server API {#sec:device_id_server_api}

device_id_server.h : Create Device ID SDP Records.

/**
 * @brief Create SDP record for Device ID service
 * @param service buffer - needs to large enough
 * @param service_record_handle
 * @param vendor_id_source usually DEVICE_ID_VENDOR_ID_SOURCE_BLUETOOTH or DEVICE_ID_VENDOR_ID_SOURCE_USB
 * @param vendor_id
 * @param product_it
 * @param version
 */
void device_id_create_sdp_record(uint8_t *service, uint32_t service_record_handle, uint16_t vendor_id_source, uint16_t vendor_id, uint16_t product_id, uint16_t version);

GATT SDP API {#sec:gatt_sdp_api}

gatt_sdp.h

/** 
 * @brief Creates SDP record forG ATT service in provided empty buffer.
 * @note Make sure the buffer is big enough.
 *
 * @param service is an empty buffer to store service record
 * @param service_record_handle for new service
 * @param gatt_start_handle
 * @param gatt_end_handle
 */
void gatt_create_sdp_record(uint8_t *service, uint32_t service_record_handle, uint16_t gatt_start_handle, uint16_t gatt_end_handle);

GOEP Client API {#sec:goep_client_api}

goep_client.h : Communicate with remote OBEX server - General Object Exchange

typedef struct {
    btstack_linked_item_t item;

    uint16_t         cid;

    goep_client_state_t     state;
    bd_addr_t        bd_addr;
    uint16_t         uuid;
    hci_con_handle_t con_handle;
    uint8_t          incoming;

    btstack_packet_handler_t client_handler;
    btstack_context_callback_registration_t sdp_query_request;

    uint8_t          rfcomm_port;
    uint16_t         l2cap_psm;
    uint16_t         bearer_cid;
    uint16_t         bearer_mtu;

    uint16_t         record_index;

    // cached higher layer information PBAP + MAP
    uint32_t         profile_supported_features;
    uint8_t          map_mas_instance_id;
    uint8_t          map_supported_message_types;

    // needed to select one of multiple MAS Instances
    struct {
        uint32_t supported_features;
        uint8_t  instance_id;
        uint8_t  supported_message_types;
        uint8_t  rfcomm_port;
#ifdef ENABLE_GOEP_L2CAP
        uint16_t l2cap_psm;
#endif
    } mas_info;

    uint8_t          obex_opcode;
    uint32_t         obex_connection_id;
    int              obex_connection_id_set;

#ifdef ENABLE_GOEP_L2CAP
    l2cap_ertm_config_t ertm_config;
    uint16_t            ertm_buffer_size;
    uint8_t           * ertm_buffer;
#endif
} goep_client_t;


// remote does not expose PBAP features in SDP record
#define PBAP_FEATURES_NOT_PRESENT ((uint32_t) -1)
#define MAP_FEATURES_NOT_PRESENT ((uint32_t) -1)
#define PROFILE_FEATURES_NOT_PRESENT ((uint32_t) -1)

/**
 * Setup GOEP Client
 */
void goep_client_init(void);

/**
 * @brief Connect to a GEOP server with specified UUID on a remote device.
 * @param goep_client
 * @param l2cap_ertm_config
 * @param l2cap_ertm_buffer_size
 * @param l2cap_ertm_buffer
 * @param handler
 * @param addr
 * @param uuid
 * @param instance_id e.g. used to connect to different MAP Access Servers, default: 0
 * @param out_cid
 * @return
 */
uint8_t
goep_client_connect(goep_client_t *goep_client, l2cap_ertm_config_t *l2cap_ertm_config, uint8_t *l2cap_ertm_buffer,
                    uint16_t l2cap_ertm_buffer_size, btstack_packet_handler_t handler, bd_addr_t addr, uint16_t uuid,
                    uint8_t instance_id, uint16_t *out_cid);

/**
 * @brief Connect to a GEOP server over L2CAP with specified PSM on a remote device.
 * @note In contrast to goep_client_connect which searches for a OBEX service with a given UUID, this
 *       function only supports GOEP v2.0 (L2CAP) to a specified L2CAP PSM
 * @param goep_client
 * @param l2cap_ertm_config
 * @param l2cap_ertm_buffer_size
 * @param l2cap_ertm_buffer
 * @param handler
 * @param addr
 * @param l2cap_psm
 * @param out_cid
 * @return
 */
uint8_t
goep_client_connect_l2cap(goep_client_t *goep_client, l2cap_ertm_config_t *l2cap_ertm_config, uint8_t *l2cap_ertm_buffer,
                    uint16_t l2cap_ertm_buffer_size, btstack_packet_handler_t handler, bd_addr_t addr, uint16_t l2cap_psm,
                    uint16_t *out_cid);

/*
 * @brief Connect to a GEOP server with specified UUID on a remote device.
 * @note This functions uses a single goep_client_t instance and only allows for a single goep connection
 *       Please use goep_client_connect instead
 * @param handler 
 * @param addr
 * @param uuid
 * @param out_cid to use for further commands
 * @result status
*/
uint8_t goep_client_create_connection(btstack_packet_handler_t handler, bd_addr_t addr, uint16_t uuid, uint16_t * out_cid);

/** 
 * @brief Disconnects GOEP connection with given identifier.
 * @param goep_cid
 * @return status
 */
uint8_t goep_client_disconnect(uint16_t goep_cid);

/** 
 * @brief Request emission of GOEP_SUBEVENT_CAN_SEND_NOW as soon as possible
 * @note GOEP_SUBEVENT_CAN_SEND_NOW might be emitted during call to this function
 *       so packet handler should be ready to handle it
 * @param goep_cid
 */
void goep_client_request_can_send_now(uint16_t goep_cid);

/**
 * @brief Get Opcode from last created request, needed for parsing of OBEX response packet
 * @param goep_cid
 * @return opcode
 */
uint8_t goep_client_get_request_opcode(uint16_t goep_cid);

/**
 * @brief Get PBAP Supported Features found in SDP record during connect
 */
uint32_t goep_client_get_pbap_supported_features(uint16_t goep_cid);

/**
 * @brief Get MAP Supported Features found in SDP record during connect
 */
uint32_t goep_client_get_map_supported_features(uint16_t goep_cid);

/**
 * @brief Get MAP MAS Instance ID found in SDP record during connect
 */
uint8_t goep_client_get_map_mas_instance_id(uint16_t goep_cid);

/**
 * @brief Get MAP MAS Supported Message Types found in SDP record during connect
 */
uint8_t goep_client_get_map_supported_message_types(uint16_t goep_cid);

/**
 * @brief Check if GOEP 2.0 or higher features can be used
 * @return true if GOEP Version 2.0 or higher
 */
bool goep_client_version_20_or_higher(uint16_t goep_cid);

/**
 * @brief Set Connection ID used for newly created requests
 * @param goep_cid
 */
void goep_client_set_connection_id(uint16_t goep_cid, uint32_t connection_id);

/**
 * @brief Start Connect request
 * @param goep_cid
 * @param obex_version_number
 * @param flags
 * @param maximum_obex_packet_length
 */
void goep_client_request_create_connect(uint16_t goep_cid, uint8_t obex_version_number, uint8_t flags, uint16_t maximum_obex_packet_length);

/**
 * @brief Start Disconnect request
 * @param goep_cid
 */
void goep_client_request_create_disconnect(uint16_t goep_cid);

/**
 * @brief Create Get request
 * @param goep_cid
 */
void goep_client_request_create_get(uint16_t goep_cid);

/**
 * @brief Create Abort request
 * @param goep_cid
 */
void goep_client_request_create_abort(uint16_t goep_cid);

/**
 * @brief Start Set Path request
 * @param goep_cid
 */
void goep_client_request_create_set_path(uint16_t goep_cid, uint8_t flags);

/**
 * @brief Create Put request
 * @param goep_cid
 */
void goep_client_request_create_put(uint16_t goep_cid);

/**
 * @brief Get max size of body data that can be added to current response with goep_client_body_add_static
 * @param goep_cid
 * @param data
 * @param length
 * @return size in bytes or 0
 */
uint16_t goep_client_request_get_max_body_size(uint16_t goep_cid);

/**
 * @brief Add SRM Enable
 * @param goep_cid
 */
void goep_client_header_add_srm_enable(uint16_t goep_cid);

/**
 * @brief Add header with single byte value (8 bit)
 * @param goep_cid
 * @param header_type
 * @param value
 */
void goep_client_header_add_byte(uint16_t goep_cid, uint8_t header_type, uint8_t value);

/**
 * @brief Add header with word value (32 bit)
 * @param goep_cid
 * @param header_type
 * @param value
 */
void goep_client_header_add_word(uint16_t goep_cid, uint8_t header_type, uint32_t value);

/**
 * @brief Add header with variable size
 * @param goep_cid
 * @param header_type
 * @param header_data
 * @param header_data_length
 */
void goep_client_header_add_variable(uint16_t goep_cid, uint8_t header_type, const uint8_t * header_data, uint16_t header_data_length);

/**
 * @brief Add name header to current request
 * @param goep_cid
 * @param name
 */
void goep_client_header_add_name(uint16_t goep_cid, const char * name);

/**
 * @brief Add name header to current request
 * @param goep_cid
 * @param name
 * @param name_len
 */
void goep_client_header_add_name_prefix(uint16_t goep_cid, const char * name, uint16_t name_len);

/**
 * @brief Add string encoded as unicode to current request
 * @param goep_cid
 * @param name
 * @param name_len
 */
void goep_client_header_add_unicode_prefix(uint16_t goep_cid, uint8_t header_id, const char * name, uint16_t name_len);

/**
 * @brief Add target header to current request
 * @param goep_cid
 * @param target
 * @param length of target
 */
void goep_client_header_add_target(uint16_t goep_cid, const uint8_t * target, uint16_t length);

/**
 * @brief Add type header to current request
 * @param goep_cid
 * @param type
 */
void goep_client_header_add_type(uint16_t goep_cid, const char * type);

/**
 * @brief Add count header to current request
 * @param goep_cid
 * @param count
 */
void goep_client_header_add_count(uint16_t goep_cid, uint32_t count);

/**
 * @brief Add length header to current request
 * @param goep_cid
 * @param length
 */
void goep_client_header_add_length(uint16_t goep_cid, uint32_t length);

/**
 * @brief Add application parameters header to current request
 * @param goep_cid
 * @param data 
 * @param lenght of application parameters
 */
void goep_client_header_add_application_parameters(uint16_t goep_cid, const uint8_t * data, uint16_t length);

/**
 * @brief Add application parameters header to current request
 * @param goep_cid
 * @param data
 * @param lenght of challenge response
 */
void goep_client_header_add_challenge_response(uint16_t goep_cid, const uint8_t * data, uint16_t length);

/**
 * @brief Add body
 * @param goep_cid
 * @param data
 * @param lenght 
 */
void goep_client_body_add_static(uint16_t goep_cid, const uint8_t * data, uint32_t length);

/**
 * @brief Query remaining buffer size
 * @param goep_cid
 * @return size
 */
uint16_t goep_client_body_get_outgoing_buffer_len(uint16_t goep_cid);

/**
 * @brief Add body
 * @param goep_cid
 * @param data
 * @param length
 * @param ret_length
 */
void goep_client_body_fillup_static(uint16_t goep_cid, const uint8_t * data, uint32_t length, uint32_t * ret_length);

/**
 * @brief Execute prepared request
 * @param goep_cid
 * @param daa 
 */
int goep_client_execute(uint16_t goep_cid);

/**
 * @brief Execute prepared request with final bit
 * @param goep_cid
 * @param final
 */
int goep_client_execute_with_final_bit(uint16_t goep_cid, bool final);

/**
 * @brief De-Init GOEP Client
 */
void goep_client_deinit(void);

HFP Audio Gateway (AG) API {#sec:hfp_ag_api}

hfp_ag.h

typedef struct {
    uint8_t type;
    const char * number;
} hfp_phone_number_t;

/**
 * @brief Create HFP Audio Gateway (AG) SDP service record. 
 * @param service
 * @param rfcomm_channel_nr
 * @param name or NULL for default value. Provide "" (empty string) to skip attribute
 * @param ability_to_reject_call
 * @param supported_features 32-bit bitmap, see HFP_AGSF_* values in hfp.h
 * @param codecs_nr
 * @param codecs
 */
void hfp_ag_create_sdp_record_with_codecs(uint8_t * service, uint32_t service_record_handle, int rfcomm_channel_nr,
                                          const char * name, uint8_t ability_to_reject_call, uint16_t supported_features,
                                          uint8_t codecs_nr, const uint8_t * codecs);

/**
 * @brief Set up HFP Audio Gateway (AG) device without additional supported features.
 * @param rfcomm_channel_nr
 */
void hfp_ag_init(uint8_t rfcomm_channel_nr);

/**
 * @brief Set codecs. 
 * @param codecs_nr
 * @param codecs
 */
void hfp_ag_init_codecs(uint8_t codecs_nr, const uint8_t * codecs);

/**
 * @brief Set supported features.
 * @param supported_features 32-bit bitmap, see HFP_AGSF_* values in hfp.h
 */
void hfp_ag_init_supported_features(uint32_t supported_features);

/**
 * @brief Set AG indicators. 
 * @param indicators_nr
 * @param indicators
 */
void hfp_ag_init_ag_indicators(int ag_indicators_nr, const hfp_ag_indicator_t * ag_indicators);

/**
 * @brief Set HF indicators. 
 * @param indicators_nr
 * @param indicators
 */
void hfp_ag_init_hf_indicators(int hf_indicators_nr, const hfp_generic_status_indicator_t * hf_indicators);

/**
 * @brief Set Call Hold services. 
 * @param indicators_nr
 * @param indicators
 */
void hfp_ag_init_call_hold_services(int call_hold_services_nr, const char * call_hold_services[]);


/**
 * @brief Register callback for the HFP Audio Gateway (AG) client. 
 * @param callback
 */
void hfp_ag_register_packet_handler(btstack_packet_handler_t callback);

/**
 * @brief Register custom AT command.
 * @param hfp_custom_at_command (with 'AT+' prefix)
 */
void hfp_ag_register_custom_at_command(hfp_custom_at_command_t * custom_at_command);

/**
 * @brief Enable/Disable in-band ring tone.
 *
 * @param use_in_band_ring_tone
 */
void hfp_ag_set_use_in_band_ring_tone(int use_in_band_ring_tone);


// actions used by local device / user

/**
 * @brief Establish RFCOMM connection, and perform service level connection agreement:
 * - exchange of supported features
 * - report Audio Gateway (AG) indicators and their status 
 * - enable indicator status update in the AG
 * - accept the information about available codecs in the Hands-Free (HF), if sent
 * - report own information describing the call hold and multiparty services, if possible
 * - report which HF indicators are enabled on the AG, if possible
 * The status of SLC connection establishment is reported via
 * HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED.
 *
 * @param  bd_addr of HF
 * @return status ERROR_CODE_SUCCESS if successful, otherwise:
 *                  - ERROR_CODE_COMMAND_DISALLOWED if connection already exists or connection in wrong state, or
 *                  - BTSTACK_MEMORY_ALLOC_FAILED 
 *
 */
uint8_t hfp_ag_establish_service_level_connection(bd_addr_t bd_addr);

/**
 * @brief Release the RFCOMM channel and the audio connection between the HF and the AG. 
 * If the audio connection exists, it will be released.
 * The status of releasing the SLC connection is reported via
 * HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED.
 *
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_ag_release_service_level_connection(hci_con_handle_t acl_handle);

/**
 * @brief Establish audio connection.
 * The status of Audio connection establishment is reported via HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE.
 *
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_ag_establish_audio_connection(hci_con_handle_t acl_handle);

/**
 * @brief Release audio connection.
 * The status of releasing the Audio connection is reported via HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE.
 * 
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_ag_release_audio_connection(hci_con_handle_t acl_handle);

/**
 * @brief Put the current call on hold, if it exists, and accept incoming call. 
 */
void hfp_ag_answer_incoming_call(void);

/**
 * @brief Join held call with active call.
 */
void hfp_ag_join_held_call(void);

/**
 * @brief Reject incoming call, if exists, or terminate active call.
 */
void hfp_ag_terminate_call(void);

/**
 * @brief Put incoming call on hold.
 */
void hfp_ag_hold_incoming_call(void);

/**
 * @brief Accept the held incoming call.
 */
void hfp_ag_accept_held_incoming_call(void);

/**
 * @brief Reject the held incoming call.
 */
void hfp_ag_reject_held_incoming_call(void);

/**
 * @brief Set microphone gain. 
 *
 * @param acl_handle
 * @param gain Valid range: [0,15]
 * @return status ERROR_CODE_SUCCESS if successful, otherwise:
 *              - ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist, or
 *              - ERROR_CODE_COMMAND_DISALLOWED if invalid gain range
 */
uint8_t hfp_ag_set_microphone_gain(hci_con_handle_t acl_handle, int gain);

/**
 * @brief Set speaker gain.
 *
 * @param acl_handle
 * @param gain Valid range: [0,15]
 * @return status ERROR_CODE_SUCCESS if successful, otherwise:
 *              - ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist, or
 *              - ERROR_CODE_COMMAND_DISALLOWED if invalid gain range
 */
uint8_t hfp_ag_set_speaker_gain(hci_con_handle_t acl_handle, int gain);

/**
 * @brief Set battery level.
 *
 * @param battery_level Valid range: [0,5]
 * @return status ERROR_CODE_SUCCESS if successful, otherwise:
 *              - ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist, or
 *              - ERROR_CODE_COMMAND_DISALLOWED if invalid battery level range
 */
uint8_t hfp_ag_set_battery_level(int battery_level);

/**
 * @brief Clear last dialed number.
 */
void hfp_ag_clear_last_dialed_number(void);

/**
 * @brief Set last dialed number.
 */
void hfp_ag_set_last_dialed_number(const char * number);

/**
 * @brief Notify the HF that an incoming call is waiting 
 * during an ongoing call. The notification will be sent only if the HF has
 * has previously enabled the "Call Waiting notification" in the AG. 
 *
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise:
 *              - ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist, or
 *              - ERROR_CODE_COMMAND_DISALLOWED if call waiting notification is not enabled
 */
uint8_t hfp_ag_notify_incoming_call_waiting(hci_con_handle_t acl_handle);

// Voice Recognition

/**
 * @brief Activate voice recognition and emit HFP_SUBEVENT_VOICE_RECOGNITION_ACTIVATED event with status ERROR_CODE_SUCCESS 
 * if successful. Prerequisite is established SLC.
 *
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise:
 *              - ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist, or
 *              - ERROR_CODE_COMMAND_DISALLOWED if feature HFP_(HF/AG)SF_VOICE_RECOGNITION_FUNCTION is not supported by HF and AG, or already activated
 */
uint8_t hfp_ag_activate_voice_recognition(hci_con_handle_t acl_handle);

/**
 * @brief Deactivate voice recognition and emit HFP_SUBEVENT_VOICE_RECOGNITION_DEACTIVATED event with status ERROR_CODE_SUCCESS 
 * if successful. Prerequisite is established SLC.
 *
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise:
 *              - ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist, or
 *              - ERROR_CODE_COMMAND_DISALLOWED if feature HFP_(HF/AG)SF_VOICE_RECOGNITION_FUNCTION is not supported by HF and AG, or already deactivated
 */
uint8_t hfp_ag_deactivate_voice_recognition(hci_con_handle_t acl_handle);

/**
 * @brief Notify HF that sound will be played and HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_AG_IS_STARTING_SOUND event with status ERROR_CODE_SUCCESS 
 * if successful, otherwise ERROR_CODE_COMMAND_DISALLOWED.
 *
 * @param acl_handle
 * @param activate
 * @return status ERROR_CODE_SUCCESS if successful, otherwise:
 *              - ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist, or
 *              - ERROR_CODE_COMMAND_DISALLOWED if feature HFP_(HF/AG)SF_ENHANCED_VOICE_RECOGNITION_STATUS is not supported by HF and AG
 */
uint8_t hfp_ag_enhanced_voice_recognition_report_sending_audio(hci_con_handle_t acl_handle);

/**
 * @brief Notify HF that AG is ready for input and emit HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_AG_READY_TO_ACCEPT_AUDIO_INPUT event with status ERROR_CODE_SUCCESS 
 * if successful, otherwise ERROR_CODE_COMMAND_DISALLOWED.
 *
 * @param acl_handle
 * @param activate
 * @return status ERROR_CODE_SUCCESS if successful, otherwise:
 *              - ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist, or
 *              - ERROR_CODE_COMMAND_DISALLOWED if feature HFP_(HF/AG)SF_ENHANCED_VOICE_RECOGNITION_STATUS is not supported by HF and AG
 */
uint8_t hfp_ag_enhanced_voice_recognition_report_ready_for_audio(hci_con_handle_t acl_handle);

/**
 * @brief Notify that AG is processing input and emit HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_AG_IS_PROCESSING_AUDIO_INPUT event with status ERROR_CODE_SUCCESS 
 * if successful, otherwise ERROR_CODE_COMMAND_DISALLOWED.
 *
 * @param acl_handle
 * @param activate
 * @return status ERROR_CODE_SUCCESS if successful, otherwise:
 *              - ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist, or
 *              - ERROR_CODE_COMMAND_DISALLOWED if feature HFP_(HF/AG)SF_ENHANCED_VOICE_RECOGNITION_STATUS is not supported by HF and AG
 */
uint8_t hfp_ag_enhanced_voice_recognition_report_processing_input(hci_con_handle_t acl_handle);

/**
 * @brief Send enhanced audio recognition message and HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_AG_MESSAGE_SENT event with status ERROR_CODE_SUCCESS 
 * if successful, otherwise ERROR_CODE_COMMAND_DISALLOWED.
 *
 * @param acl_handle
 * @param activate
 * @return status ERROR_CODE_SUCCESS if successful, otherwise:
 *              - ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist, 
                - ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE if the message size exceeds the HFP_MAX_VR_TEXT_SIZE, or the command does not fit into a single packet frame,
 *              - ERROR_CODE_COMMAND_DISALLOWED if HF and AG do not support features: HFP_(HF/AG)SF_ENHANCED_VOICE_RECOGNITION_STATUS and HFP_(HF/AG)SF_VOICE_RECOGNITION_TEXT
 */
uint8_t hfp_ag_enhanced_voice_recognition_send_message(hci_con_handle_t acl_handle, hfp_voice_recognition_state_t state, hfp_voice_recognition_message_t msg);

/**
 * @brief Send a phone number back to the HF.
 *
 * @param acl_handle
 * @param phone_number
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_ag_send_phone_number_for_voice_tag(hci_con_handle_t acl_handle, const char * phone_number);

/**
 * @brief Reject sending a phone number to the HF.
 *
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_ag_reject_phone_number_for_voice_tag(hci_con_handle_t acl_handle);

/**
 * @brief Store phone number with initiated call.
 * @param type
 * @param number
 */
void hfp_ag_set_clip(uint8_t type, const char * number);


// Cellular Actions

/**
 * @brief Pass the accept incoming call event to the AG.
 */
void hfp_ag_incoming_call(void);

/**
 * @brief Outgoing call initiated
 */
void hfp_ag_outgoing_call_initiated(void);

/**
 * @brief Pass the reject outgoing call event to the AG.
 */
void hfp_ag_outgoing_call_rejected(void);

/**
 * @brief Pass the accept outgoing call event to the AG.
 */
void hfp_ag_outgoing_call_accepted(void);

/**
 * @brief Pass the outgoing call ringing event to the AG.
 */
void hfp_ag_outgoing_call_ringing(void);

/**
 * @brief Pass the outgoing call established event to the AG.
 */
void hfp_ag_outgoing_call_established(void);

/**
 * @brief Pass the call dropped event to the AG.
 */
void hfp_ag_call_dropped(void);

/**
 * @brief Set network registration status.  
 * @param status 0 - not registered, 1 - registered 
 * @return status ERROR_CODE_SUCCESS if successful, otherwise:
 *              - ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist, or
 *              - ERROR_CODE_COMMAND_DISALLOWED if invalid registration status
 */
uint8_t hfp_ag_set_registration_status(int registration_status);

/**
 * @brief Set network signal strength.
 *
 * @param signal_strength [0-5]
 * @return status ERROR_CODE_SUCCESS if successful, otherwise:
 *              - ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist, or
 *              - ERROR_CODE_COMMAND_DISALLOWED if invalid signal strength range
 */
uint8_t hfp_ag_set_signal_strength(int signal_strength);

/**
 * @brief Set roaming status.
 *
 * @param roaming_status 0 - no roaming, 1 - roaming active
 * @return status ERROR_CODE_SUCCESS if successful, otherwise:
 *              - ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist, or
 *              - ERROR_CODE_COMMAND_DISALLOWED if invalid roaming status
 */
uint8_t hfp_ag_set_roaming_status(int roaming_status);

/**
 * @brief Set subcriber number information, e.g. the phone number 
 * @param numbers
 * @param numbers_count
 */
void hfp_ag_set_subcriber_number_information(hfp_phone_number_t * numbers, int numbers_count);

/**
 * @brief Called by cellular unit after a DTMF code was transmitted, so that the next one can be emitted.
 *
 * @param acl_handle 
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_ag_send_dtmf_code_done(hci_con_handle_t acl_handle);

/**
 * @brief Report Extended Audio Gateway Error result codes in the AG.
 * Whenever there is an error relating to the functionality of the AG as a 
 * result of AT command, the AG shall send +CME ERROR:
 * - +CME ERROR: 0  - AG failure
 * - +CME ERROR: 1  - no connection to phone 
 * - +CME ERROR: 3  - operation not allowed 
 * - +CME ERROR: 4  - operation not supported 
 * - +CME ERROR: 5  - PH-SIM PIN required 
 * - +CME ERROR: 10 - SIM not inserted 
 * - +CME ERROR: 11 - SIM PIN required 
 * - +CME ERROR: 12 - SIM PUK required 
 * - +CME ERROR: 13 - SIM failure
 * - +CME ERROR: 14 - SIM busy
 * - +CME ERROR: 16 - incorrect password 
 * - +CME ERROR: 17 - SIM PIN2 required 
 * - +CME ERROR: 18 - SIM PUK2 required 
 * - +CME ERROR: 20 - memory full
 * - +CME ERROR: 21 - invalid index
 * - +CME ERROR: 23 - memory failure
 * - +CME ERROR: 24 - text string too long
 * - +CME ERROR: 25 - invalid characters in text string
 * - +CME ERROR: 26 - dial string too long
 * - +CME ERROR: 27 - invalid characters in dial string
 * - +CME ERROR: 30 - no network service
 * - +CME ERROR: 31 - network Timeout.
 * - +CME ERROR: 32 - network not allowed – Emergency calls only
 *
 * @param acl_handle
 * @param error
 * @return status ERROR_CODE_SUCCESS if successful, otherwise:
 *              - ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist, or
 *              - ERROR_CODE_COMMAND_DISALLOWED if extended audio gateway error report is disabled
 */
uint8_t hfp_ag_report_extended_audio_gateway_error_result_code(hci_con_handle_t acl_handle, hfp_cme_error_t error);

/**
 * @brief Send unsolicited result code (most likely a response to a vendor-specific command not part of standard HFP).
 * @note  Emits HFP_SUBEVENT_CUSTOM_AT_MESSAGE_SENT when result code was sent
 *
 * @param unsolicited_result_code to send
 * @return status ERROR_CODE_SUCCESS if successful, otherwise:
 *              - ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist, or
 *              - ERROR_CODE_COMMAND_DISALLOWED if extended audio gateway error report is disabled
 */
uint8_t hfp_ag_send_unsolicited_result_code(hci_con_handle_t acl_handle, const char * unsolicited_result_code);

/**
 * @brief Send result code for AT command received via HFP_SUBEVENT_CUSTOM_AT_COMMAND
 * @note  Emits HFP_SUBEVENT_COMPLETE when result code was sent
 *
 * @param ok for OK, or ERROR
 * @return status ERROR_CODE_SUCCESS if successful, otherwise:
 *              - ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist, or
 *              - ERROR_CODE_COMMAND_DISALLOWED if extended audio gateway error report is disabled
 */
uint8_t hfp_ag_send_command_result_code(hci_con_handle_t acl_handle, bool ok);

/**
 * @brief De-Init HFP AG
 */
void hfp_ag_deinit(void);

/**
 * @brief Create HFP Audio Gateway (AG) SDP service record.
 * @deprecated Use hfp_ag_create_sdp_record_with_codecs instead
 * @param service
 * @param rfcomm_channel_nr
 * @param name
 * @param ability_to_reject_call
 * @param suported_features 32-bit bitmap, see HFP_AGSF_* values in hfp.h
 * @param wide_band_speech supported
 */
void hfp_ag_create_sdp_record(uint8_t * service, uint32_t service_record_handle, int rfcomm_channel_nr, const char * name, uint8_t ability_to_reject_call, uint16_t supported_features, int wide_band_speech);

HFP Audio Encoder API {#sec:hfp_codec_api}

hfp_codec.h : @brief Create SCO packet with H2 Synchronization Header and encoded audio samples

typedef struct hfp_codec hfp_codec_t;

#ifdef ENABLE_HFP_WIDE_BAND_SPEECH
/**
 * @brief Initialize HFP Audio Codec for mSBC
 * @param hfp_codec
 * @param msbc_encoder_context for msbc encoder
 * @return status
 */
void hfp_codec_init_msbc_with_codec(hfp_codec_t * hfp_codec, const btstack_sbc_encoder_t * sbc_encoder, void * sbc_encoder_context);

/**
 * @brief Initialize HFP Audio Codec for mSBC
 * @deprecated Please use hfp_codec_init_msbc_with_codec
 * @param hfp_codec
 * @param msbc_encoder_context for msbc encoder
 * @return status
 */
void hfp_codec_init_msbc(hfp_codec_t * hfp_codec, btstack_sbc_encoder_state_t * msbc_encoder_context);
#endif

#ifdef ENABLE_HFP_SUPER_WIDE_BAND_SPEECH
/**
 * @brief Initialize HFP Audio Codec for LC3-SWB
 * @param hfp_codec
 * @param lc3_encoder
 * @param lc3_encoder_context for lc3_encoder
 * @return status
 */
void hfp_codec_init_lc3_swb(hfp_codec_t * hfp_codec, const btstack_lc3_encoder_t * lc3_encoder, void * lc3_encoder_context);
#endif

/**
 * @brief Get number of audio samples per HFP SCO frame
 * @param hfp_codec
 * @return num audio samples per 7.5ms SCO packet
 */
uint16_t hfp_codec_num_audio_samples_per_frame(const hfp_codec_t * hfp_codec);

/**
 * @brief Checks if next frame can be encoded
 * @param hfp_codec
 */
bool hfp_codec_can_encode_audio_frame_now(const hfp_codec_t * hfp_codec);

/**
 * Get number of bytes ready for sending
 * @param hfp_codec
 * @return num bytes ready for current packet
 */
uint16_t hfp_codec_num_bytes_available(const hfp_codec_t * hfp_codec);

/**
 * Encode audio samples for HFP SCO packet
 * @param hfp_codec
 * @param pcm_samples - complete audio frame of hfp_msbc_num_audio_samples_per_frame int16 samples
 */
void hfp_codec_encode_audio_frame(hfp_codec_t * hfp_codec, int16_t * pcm_samples);

/**
 * Read from stream into SCO packet buffer
 * @param hfp_codec
 * @param buffer to store stream
 * @param size num bytes to read from stream
 */
void hfp_codec_read_from_stream(hfp_codec_t * hfp_codec, uint8_t * buffer, uint16_t size);

/**
 * @param hfp_codec
 */
void hfp_codec_deinit(hfp_codec_t * hfp_codec);

HFP GSM Model API {#sec:hfp_gsm_model_api}

hfp_gsm_model.h

typedef struct {
    bool used_slot;
    hfp_enhanced_call_status_t enhanced_status;
    hfp_enhanced_call_dir_t direction;
    hfp_enhanced_call_mode_t mode;
    hfp_enhanced_call_mpty_t mpty;
    // TODO: sort on drop call, so that index corresponds to table index
    int index;
    uint8_t clip_type;
    char    clip_number[25];
} hfp_gsm_call_t;

hfp_callheld_status_t hfp_gsm_callheld_status(void);
hfp_call_status_t hfp_gsm_call_status(void);
hfp_callsetup_status_t hfp_gsm_callsetup_status(void);

int hfp_gsm_get_number_of_calls(void);
char * hfp_gsm_last_dialed_number(void);
void hfp_gsm_clear_last_dialed_number(void);
void hfp_gsm_set_last_dialed_number(const char* number);

hfp_gsm_call_t * hfp_gsm_call(int index);

int hfp_gsm_call_possible(void);

uint8_t hfp_gsm_clip_type(void);
char *  hfp_gsm_clip_number(void);

void hfp_gsm_init(void);
void hfp_gsm_deinit(void);

void hfp_gsm_handler(hfp_ag_call_event_t event, uint8_t index, uint8_t type, const char * number);

HFP Hands-Free (HF) API {#sec:hfp_hf_api}

hfp_hf.h

/**
 * @brief Create HFP Hands-Free (HF) SDP service record.
 * @param service
 * @param rfcomm_channel_nr
 * @param name or NULL for default value. Provide "" (empty string) to skip attribute
 * @param supported_features 32-bit bitmap, see HFP_HFSF_* values in hfp.h
 * @param codecs_nr  number of codecs in codecs argument
 * @param codecs
 */
void hfp_hf_create_sdp_record_with_codecs(uint8_t * service, uint32_t service_record_handle, int rfcomm_channel_nr,
                                           const char * name, uint16_t supported_features, uint8_t codecs_nr, const uint8_t * codecs);

/**
 * @brief Set up HFP Hands-Free (HF) device without additional supported features. 
 * @param rfcomm_channel_nr
 * @return status ERROR_CODE_SUCCESS if successful, otherwise:
 *                  - L2CAP_SERVICE_ALREADY_REGISTERED, 
 *                  - RFCOMM_SERVICE_ALREADY_REGISTERED or 
 *                  - BTSTACK_MEMORY_ALLOC_FAILED if allocation of any of RFCOMM or L2CAP services failed 
 */
uint8_t hfp_hf_init(uint8_t rfcomm_channel_nr);

/**
 * @brief Set codecs. 
 * @param codecs_nr  number of codecs in codecs argument
 * @param codecs
 */
void hfp_hf_init_codecs(uint8_t codecs_nr, const uint8_t * codecs);

/**
 * @brief Set supported features.
 * @param supported_features 32-bit bitmap, see HFP_HFSF_* values in hfp.h
 */
void hfp_hf_init_supported_features(uint32_t supported_features);

/**
 * @brief Set HF indicators. 
 * @param indicators_nr
 * @param indicators
 */
void hfp_hf_init_hf_indicators(int indicators_nr, const uint16_t * indicators);


/**
 * @brief Register callback for the HFP Hands-Free (HF) client. 
 * @param callback
 */
void hfp_hf_register_packet_handler(btstack_packet_handler_t callback);

/**
 * @brief Set microphone gain used during SLC for Volume Synchronization.
 *
 * @param gain Valid range: [0,15]
 * @return status ERROR_CODE_SUCCESS if successful, otherwise:
 *              - ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS if invalid gain range
 */
uint8_t hfp_hf_set_default_microphone_gain(uint8_t gain);

/**
 * @brief Set speaker gain used during SLC for Volume Synchronization.
 *
 * @param gain Valid range: [0,15]
 * @return status ERROR_CODE_SUCCESS if successful, otherwise:
 *              - ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS if invalid gain range
 */
uint8_t hfp_hf_set_default_speaker_gain(uint8_t gain);

/**
 * @brief Establish RFCOMM connection with the AG with given Bluetooth address, 
 * and perform service level connection (SLC) agreement:
 * - exchange supported features
 * - retrieve Audio Gateway (AG) indicators and their status 
 * - enable indicator status update in the AG
 * - notify the AG about its own available codecs, if possible
 * - retrieve the AG information describing the call hold and multiparty services, if possible
 * - retrieve which HF indicators are enabled on the AG, if possible
 * The status of SLC connection establishment is reported via
 * HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED.
 *
 * @param bd_addr Bluetooth address of the AG
 * @return status ERROR_CODE_SUCCESS if successful, otherwise:
 *              - ERROR_CODE_COMMAND_DISALLOWED if connection already exists, or
 *              - BTSTACK_MEMORY_ALLOC_FAILED 
 */
uint8_t hfp_hf_establish_service_level_connection(bd_addr_t bd_addr);

/**
 * @brief Release the RFCOMM channel and the audio connection between the HF and the AG. 
 * The status of releasing the SLC connection is reported via
 * HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED.
 *
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_hf_release_service_level_connection(hci_con_handle_t acl_handle);

/**
 * @brief Enable status update for all indicators in the AG.
 * The status field of the HFP_SUBEVENT_COMPLETE reports if the command was accepted.
 * The status of an AG indicator is reported via HFP_SUBEVENT_AG_INDICATOR_STATUS_CHANGED.
 *
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_hf_enable_status_update_for_all_ag_indicators(hci_con_handle_t acl_handle);

/**
 * @brief Disable status update for all indicators in the AG.
 * The status field of the HFP_SUBEVENT_COMPLETE reports if the command was accepted.
 *
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_hf_disable_status_update_for_all_ag_indicators(hci_con_handle_t acl_handle);

/**
 * @brief Enable or disable status update for the individual indicators in the AG using bitmap.
 * The status field of the HFP_SUBEVENT_COMPLETE reports if the command was accepted.
 * The status of an AG indicator is reported via HFP_SUBEVENT_AG_INDICATOR_STATUS_CHANGED.
 * 
 * @param acl_handle
 * @param indicators_status_bitmap 32-bit bitmap, 0 - indicator is disabled, 1 - indicator is enabled
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_hf_set_status_update_for_individual_ag_indicators(hci_con_handle_t acl_handle, uint32_t indicators_status_bitmap);

/**
 * @brief Query the name of the currently selected Network operator by AG. 
 * 
 * The name is restricted to max 16 characters. The result is reported via 
 * HFP_SUBEVENT_NETWORK_OPERATOR_CHANGED subtype 
 * containing network operator mode, format and name.
 * If no operator is selected, format and operator are omitted.
 * 
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise:
 *              - ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist, or
 *              - ERROR_CODE_COMMAND_DISALLOWED if connection in wrong state
 */
uint8_t hfp_hf_query_operator_selection(hci_con_handle_t acl_handle);

/**
 * @brief Enable Extended Audio Gateway Error result codes in the AG.
 * Whenever there is an error relating to the functionality of the AG as a 
 * result of AT command, the AG shall send +CME ERROR. This error is reported via 
 * HFP_SUBEVENT_EXTENDED_AUDIO_GATEWAY_ERROR, see hfp_cme_error_t in hfp.h
 *
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_hf_enable_report_extended_audio_gateway_error_result_code(hci_con_handle_t acl_handle);

/**
 * @brief Disable Extended Audio Gateway Error result codes in the AG.
 *
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
 uint8_t hfp_hf_disable_report_extended_audio_gateway_error_result_code(hci_con_handle_t acl_handle);

/**
 * @brief Establish audio connection. 
 * The status of audio connection establishment is reported via HFP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED.
 * 
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise:
 *              - ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist, or
 *              - ERROR_CODE_COMMAND_DISALLOWED if connection in wrong state
 */
uint8_t hfp_hf_establish_audio_connection(hci_con_handle_t acl_handle);

/**
 * @brief Release audio connection.
 * The status of releasing of the audio connection is reported via
 * HFP_SUBEVENT_AUDIO_CONNECTION_RELEASED.
 *
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_hf_release_audio_connection(hci_con_handle_t acl_handle);

/**
 * @brief Answer incoming call.
 * 
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise:
 *              - ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist, or
 *              - ERROR_CODE_COMMAND_DISALLOWED if answering incoming call with wrong callsetup status
 */
uint8_t hfp_hf_answer_incoming_call(hci_con_handle_t acl_handle);

/**
 * @brief Reject incoming call.
 * 
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_hf_reject_incoming_call(hci_con_handle_t acl_handle);

/**
 * @brief Release all held calls or sets User Determined User Busy (UDUB) for a waiting call.
 *
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_hf_user_busy(hci_con_handle_t acl_handle);

/**
 * @brief Release all active calls (if any exist) and accepts the other (held or waiting) call.
 * 
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_hf_end_active_and_accept_other(hci_con_handle_t acl_handle);

/**
 * @brief Place all active calls (if any exist) on hold and accepts the other (held or waiting) call.
 *
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_hf_swap_calls(hci_con_handle_t acl_handle);

/**
 * @brief Add a held call to the conversation.
 *
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_hf_join_held_call(hci_con_handle_t acl_handle);

/**
 * @brief Connect the two calls and disconnects the subscriber from both calls (Explicit Call Transfer).
 * 
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_hf_connect_calls(hci_con_handle_t acl_handle);

/**
 * @brief Terminate an incoming or an outgoing call. HFP_SUBEVENT_CALL_TERMINATED is sent upon call termination.
 * 
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_hf_terminate_call(hci_con_handle_t acl_handle);

/**
 * @brief Terminate all held calls.
 *
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_hf_terminate_held_calls(hci_con_handle_t acl_handle);

/**
 * @brief Initiate outgoing voice call by providing the destination phone number to the AG. 
 *
 * @param acl_handle
 * @param number
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_hf_dial_number(hci_con_handle_t acl_handle, char * number);

/**
 * @brief Initiate outgoing voice call using the memory dialing feature of the AG.
 *
 * @param acl_handle
 * @param memory_id
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_hf_dial_memory(hci_con_handle_t acl_handle, int memory_id);

/**
 * @brief Initiate outgoing voice call by recalling the last number dialed by the AG.
 *
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_hf_redial_last_number(hci_con_handle_t acl_handle);

/**
 * @brief Enable the “Call Waiting notification” function in the AG. 
 * The AG shall send the corresponding result code to the HF whenever 
 * an incoming call is waiting during an ongoing call. In that event,
 * the HFP_SUBEVENT_CALL_WAITING_NOTIFICATION is emitted.
 *
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_hf_activate_call_waiting_notification(hci_con_handle_t acl_handle);

/**
 * @brief Disable the “Call Waiting notification” function in the AG.
 *
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_hf_deactivate_call_waiting_notification(hci_con_handle_t acl_handle);

/**
 * @brief Enable the “Calling Line Identification notification” function in the AG. 
 * The AG shall issue the corresponding result code just after every RING indication,
 * when the HF is alerted in an incoming call. In that event,
 * the HFP_SUBEVENT_CALLING_LINE_INDETIFICATION_NOTIFICATION is emitted.
 * @param acl_handle
 */
uint8_t hfp_hf_activate_calling_line_notification(hci_con_handle_t acl_handle);

/**
 * @brief Disable the “Calling Line Identification notification” function in the AG.
 *
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_hf_deactivate_calling_line_notification(hci_con_handle_t acl_handle);


/**
 * @brief Deactivate echo canceling (EC) and noise reduction (NR) in the AG and emit 
 * HFP_SUBEVENT_ECHO_CANCELING_NOISE_REDUCTION_DEACTIVATE with status ERROR_CODE_SUCCESS if AG supports EC and AG.
 * If the AG supports its own embedded echo canceling and/or noise reduction function, 
 * it shall have EC and NR activated until this function is called.
 *
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise:
 *              - ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist, or 
 *              - ERROR_CODE_COMMAND_DISALLOWED if HFP_(HF/AG)SF_EC_NR_FUNCTION feature is not supported by AG and HF
 */
uint8_t hfp_hf_deactivate_echo_canceling_and_noise_reduction(hci_con_handle_t acl_handle);

/**
 * @brief Activate voice recognition and emit HFP_SUBEVENT_VOICE_RECOGNITION_ACTIVATED event with status ERROR_CODE_SUCCESS 
 * if successful, otherwise ERROR_CODE_COMMAND_DISALLOWED. Prerequisite is established SLC.
 *
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise:
 *              - ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist, or
 *              - ERROR_CODE_COMMAND_DISALLOWED if feature HFP_(HF/AG)SF_VOICE_RECOGNITION_FUNCTION is not supported by HF and AG, or already activated
 */
uint8_t hfp_hf_activate_voice_recognition(hci_con_handle_t acl_handle);

/**
 * @brief Dectivate voice recognition and emit HFP_SUBEVENT_VOICE_RECOGNITION_DEACTIVATED event with status ERROR_CODE_SUCCESS 
 * if successful, otherwise ERROR_CODE_COMMAND_DISALLOWED. Prerequisite is established SLC.
 *
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise:
 *              - ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist, or
 *              - ERROR_CODE_COMMAND_DISALLOWED if feature HFP_(HF/AG)SF_VOICE_RECOGNITION_FUNCTION is not supported by HF and AG, or already activated
 */
uint8_t hfp_hf_deactivate_voice_recognition(hci_con_handle_t acl_handle);


/**
 * @brief Indicate that the HF is ready to accept audio. Prerequisite is established voice recognition session.
 * The HF may call this function during an ongoing AVR (Audio Voice Recognition) session to terminate audio output from 
 * the AG (if there is any) and prepare the AG for new audio input.
 *
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise:
 *              - ERROR_CODE_COMMAND_DISALLOWED if feature HFP_(HF/AG)SF_ENHANCED_VOICE_RECOGNITION_STATUS is not supported by HF and AG, or wrong VRA status
 */
uint8_t hfp_hf_enhanced_voice_recognition_report_ready_for_audio(hci_con_handle_t acl_handle);


/**
 * @brief Set microphone gain. 
 *
 * @param acl_handle
 * @param gain Valid range: [0,15]
 * @return status ERROR_CODE_SUCCESS if successful, otherwise:
 *              - ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist, or
 *              - ERROR_CODE_COMMAND_DISALLOWED if invalid gain range
 */
uint8_t hfp_hf_set_microphone_gain(hci_con_handle_t acl_handle, int gain);

/**
 * @brief Set speaker gain.
 *
 * @param acl_handle
 * @param gain Valid range: [0,15]
 * @return status ERROR_CODE_SUCCESS if successful, otherwise:
 *              - ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist, or
 *              - ERROR_CODE_COMMAND_DISALLOWED if invalid gain range
 */
uint8_t hfp_hf_set_speaker_gain(hci_con_handle_t acl_handle, int gain);

/**
 * @brief Instruct the AG to transmit a DTMF code.
 *
 * @param acl_handle
 * @param dtmf_code
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_hf_send_dtmf_code(hci_con_handle_t acl_handle, char code);

/**
 * @brief Read numbers from the AG for the purpose of creating 
 * a unique voice tag and storing the number and its linked voice
 * tag in the HF’s memory. 
 * The number is reported via HFP_SUBEVENT_NUMBER_FOR_VOICE_TAG.
 *
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_hf_request_phone_number_for_voice_tag(hci_con_handle_t acl_handle);

/**
 * @brief Query the list of current calls in AG. 
 * The result is received via HFP_SUBEVENT_ENHANCED_CALL_STATUS.
 *
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_hf_query_current_call_status(hci_con_handle_t acl_handle);

/**
 * @brief Release a call with index in the AG.
 *
 * @param acl_handle
 * @param index
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_hf_release_call_with_index(hci_con_handle_t acl_handle, int index);

/**
 * @brief Place all parties of a multiparty call on hold with the 
 * exception of the specified call.
 *
 * @param acl_handle
 * @param index
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_hf_private_consultation_with_call(hci_con_handle_t acl_handle, int index);

/**
 * @brief Query the status of the “Response and Hold” state of the AG.
 * The result is reported via HFP_SUBEVENT_RESPONSE_AND_HOLD_STATUS.
 *
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_hf_rrh_query_status(hci_con_handle_t acl_handle);

/**
 * @brief Put an incoming call on hold in the AG.
 *
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_hf_rrh_hold_call(hci_con_handle_t acl_handle);

/**
 * @brief Accept held incoming call in the AG.
 *
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_hf_rrh_accept_held_call(hci_con_handle_t acl_handle);

/**
 * @brief Reject held incoming call in the AG.
 *
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_hf_rrh_reject_held_call(hci_con_handle_t acl_handle);

/**
 * @brief Query the AG subscriber number. The result is reported via HFP_SUBEVENT_SUBSCRIBER_NUMBER_INFORMATION.
 *
 * @param acl_handle
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_hf_query_subscriber_number(hci_con_handle_t acl_handle);

/**
 * @brief Set HF indicator.
 *
 * @param acl_handle
 * @param assigned_number
 * @param value
 * @return status ERROR_CODE_SUCCESS if successful, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist
 */
uint8_t hfp_hf_set_hf_indicator(hci_con_handle_t acl_handle, int assigned_number, int value);

/**
 * @brief Tests if in-band ringtone is active on AG (requires SLC)
 *
 * @param acl_handler
 * @return 0 if unknown acl_handle or in-band ring-tone disabled, otherwise 1
 */
int hfp_hf_in_band_ringtone_active(hci_con_handle_t acl_handle);

/**
 * @brief Send AT command (most likely a vendor-specific command not part of standard HFP).
 * @note  Result (OK/ERROR) is reported via HFP_SUBEVENT_CUSTOM_AT_MESSAGE_SENT
 *        To receive potential unsolicited result code, add ENABLE_HFP_AT_MESSAGES to get all message via HFP_SUBEVENT_AT_MESSAGE_RECEIVED
 *
 * @param acl_handle
 * @param at_command to send
 * @return status ERROR_CODE_SUCCESS if successful, otherwise:
 *              - ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist, or
 *              - ERROR_CODE_COMMAND_DISALLOWED if extended audio gateway error report is disabled
 */
uint8_t hfp_hf_send_at_command(hci_con_handle_t acl_handle, const char * at_command);

/**
 * @brief Register custom AT command.
 * @param hfp_custom_at_command (with '+' prefix)
 */
void hfp_hf_register_custom_at_command(hfp_custom_at_command_t * custom_at_command);

/**
 * @brief De-Init HFP HF
 */
void hfp_hf_deinit(void);

/**
 * @brief Create HFP Hands-Free (HF) SDP service record.
 * @deprecated Use hfp_hf_create_sdp_record_with_codecs instead
 * @param service
 * @param rfcomm_channel_nr
 * @param name
 * @param suported_features 32-bit bitmap, see HFP_HFSF_* values in hfp.h
 * @param wide_band_speech supported
 */
void hfp_hf_create_sdp_record(uint8_t * service, uint32_t service_record_handle, int rfcomm_channel_nr, const char * name, uint16_t supported_features, int wide_band_speech);

HFP mSBC Encoder API {#sec:hfp_msbc_api}

hfp_msbc.h

/**
 *
 */
void hfp_msbc_init(void);

/**
 *
 */
int  hfp_msbc_num_audio_samples_per_frame(void);

/**
 *
 */
int  hfp_msbc_can_encode_audio_frame_now(void);

/**
 * @param pcm_samples - complete audio frame of hfp_msbc_num_audio_samples_per_frame int16 samples
 */
void hfp_msbc_encode_audio_frame(int16_t * pcm_samples);

/**
 *
 */
int  hfp_msbc_num_bytes_in_stream(void);

/**
 *
 * @param buffer to store stream
 * @param size num bytes to read from stream
 */
void hfp_msbc_read_from_stream(uint8_t * buffer, int size);

/**
 * @brief De-Init HFP mSBC Codec
 */
void hfp_msbc_deinit(void);

HID Device API {#sec:hid_device_api}

hid_device.h

typedef struct {
    uint16_t        hid_device_subclass;
    uint8_t         hid_country_code;
    uint8_t         hid_virtual_cable;
    uint8_t         hid_remote_wake;
    uint8_t         hid_reconnect_initiate;
    bool            hid_normally_connectable;
    bool            hid_boot_device;
    uint16_t        hid_ssr_host_max_latency; 
    uint16_t        hid_ssr_host_min_timeout;
    uint16_t        hid_supervision_timeout;
    const uint8_t * hid_descriptor;
    uint16_t        hid_descriptor_size;
    const char *    device_name;
} hid_sdp_record_t;

/**
 * @brief Create HID Device SDP service record. 
 * @param service Empty buffer in which a new service record will be stored.
 * @param have_remote_audio_control 
 * @param service
 * @param service_record_handle
 * @param params
 */
void hid_create_sdp_record(uint8_t * service, uint32_t service_record_handle, const hid_sdp_record_t * params);

/**
 * @brief Set up HID Device 
 * @param boot_protocol_mode_supported
 * @param hid_descriptor_len
 * @param hid_descriptor
 */
void hid_device_init(bool boot_protocol_mode_supported, uint16_t hid_descriptor_len, const uint8_t * hid_descriptor);

/**
 * @brief Register callback for the HID Device client. 
 * @param callback
 */
void hid_device_register_packet_handler(btstack_packet_handler_t callback);

/**
 * @brief Register get report callback for the HID Device client. 
 * @param callback
 */
void hid_device_register_report_request_callback(int (*callback)(uint16_t hid_cid, hid_report_type_t report_type, uint16_t report_id, int * out_report_size, uint8_t * out_report));

/**
 * @brief Register set report callback for the HID Device client. 
 * @param callback
 */
void hid_device_register_set_report_callback(void (*callback)(uint16_t hid_cid, hid_report_type_t report_type, int report_size, uint8_t * report));

/**
 * @brief Register callback to receive report data for the HID Device client. 
 * @param callback
 */
void hid_device_register_report_data_callback(void (*callback)(uint16_t cid, hid_report_type_t report_type, uint16_t report_id, int report_size, uint8_t * report));

/*
 * @brief Create HID connection to HID Host
 * @param addr
 * @param hid_cid to use for other commands
 * @result status
 */
uint8_t hid_device_connect(bd_addr_t addr, uint16_t * hid_cid);

/*
 * @brief Disconnect from HID Host
 * @param hid_cid
 */
void hid_device_disconnect(uint16_t hid_cid);

/**
 * @brief Request can send now event to send HID Report
 * Generates an HID_SUBEVENT_CAN_SEND_NOW subevent
 * @param hid_cid
 */
void hid_device_request_can_send_now_event(uint16_t hid_cid);

/**
 * @brief Send HID message on interrupt channel
 * @param hid_cid
 */
void hid_device_send_interrupt_message(uint16_t hid_cid, const uint8_t * message, uint16_t message_len);

/**
 * @brief Send HID message on control channel
 * @param hid_cid
 */
void hid_device_send_control_message(uint16_t hid_cid, const uint8_t * message, uint16_t message_len);

/**
 * @brief Retutn 1 if boot protocol mode active
 * @param hid_cid
 */
int hid_device_in_boot_protocol_mode(uint16_t hid_cid);

/**
 * @brief De-Init HID Device
 */
void hid_device_deinit(void);

HID Host API {#sec:hid_host_api}

hid_host.h

/**
 * @brief Set up HID Host 
 * @param hid_descriptor_storage
 * @param hid_descriptor_storage_len
 */
void hid_host_init(uint8_t * hid_descriptor_storage, uint16_t hid_descriptor_storage_len);

/**
 * @brief Register callback for the HID Host. 
 * @param callback
 */
void hid_host_register_packet_handler(btstack_packet_handler_t callback);

/*
 * @brief Create HID connection to HID Device and emit HID_SUBEVENT_CONNECTION_OPENED event with status code, 
 * followed by HID_SUBEVENT_DESCRIPTOR_AVAILABLE that informs if the HID Descriptor was found. In the case of incoming
 * connection, i.e. HID Device initiating the connection, the HID_SUBEVENT_DESCRIPTOR_AVAILABLE is delayed, and the reports 
 * may already come via HID_SUBEVENT_REPORT event. It is up to the application code if 
 * these reports should be buffered or ignored until the descriptor is available.
 * @note  HID_PROTOCOL_MODE_REPORT_WITH_FALLBACK_TO_BOOT will try ti set up REPORT mode, but fallback to BOOT mode if necessary. 
 * @note  HID_SUBEVENT_DESCRIPTOR_AVAILABLE possible status values are:
 * - ERROR_CODE_SUCCESS if descriptor available, 
 * - ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE if not, and 
 * - ERROR_CODE_MEMORY_CAPACITY_EXCEEDED if descriptor is larger then the available space
 * @param remote_addr
 * @param protocol_mode see hid_protocol_mode_t in btstack_hid.h
 * @param hid_cid to use for other commands
 * @result status ERROR_CODE_SUCCESS on success, otherwise ERROR_CODE_COMMAND_DISALLOWED, BTSTACK_MEMORY_ALLOC_FAILED
 */
uint8_t hid_host_connect(bd_addr_t remote_addr, hid_protocol_mode_t protocol_mode, uint16_t * hid_cid);


/*
 * @brief Accept incoming HID connection, this should be called upon receiving HID_SUBEVENT_INCOMING_CONNECTION event.
 * @param hid_cid
 * @param protocol_mode see hid_protocol_mode_t in btstack_hid.h
 * @result status ERROR_CODE_SUCCESS on success, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, ERROR_CODE_COMMAND_DISALLOWED
 */
uint8_t hid_host_accept_connection(uint16_t hid_cid, hid_protocol_mode_t protocol_mode);

/*
 * @brief Decline incoming HID connection, this should be called upon receiving HID_SUBEVENT_INCOMING_CONNECTION event.
 * @param hid_cid
 * @result status ERROR_CODE_SUCCESS on success, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, ERROR_CODE_COMMAND_DISALLOWED
 */
uint8_t hid_host_decline_connection(uint16_t hid_cid);

/*
 * @brief Disconnect from HID Device and emit HID_SUBEVENT_CONNECTION_CLOSED event.
 * @param hid_cid
 */
void hid_host_disconnect(uint16_t hid_cid);

// Control messages:

/*
 * @brief Send SUSPEND control signal to connected HID Device. A Bluetooth HID Device which receives a SUSPEND control signal
 * may optionally disconnect from the Bluetooth HID Host.
 * @param hid_cid
 * @result status ERROR_CODE_SUCCESS on success, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, ERROR_CODE_COMMAND_DISALLOWED
 */
uint8_t hid_host_send_suspend(uint16_t hid_cid);

/*
 * @brief Order connected HID Device to exit suspend mode. 
 * The Bluetooth HID Device shall send a report to the Bluetooth HID Host.
 * @param hid_cid
 * @result status ERROR_CODE_SUCCESS on success, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, ERROR_CODE_COMMAND_DISALLOWED
 */
uint8_t hid_host_send_exit_suspend(uint16_t hid_cid);

/*
 * @brief Unplug connected HID Device. 
 * @note This is the only command that can be also received from HID Device. It will be indicated by receiving 
 * HID_SUBEVENT_VIRTUAL_CABLE_UNPLUG event, as well as disconnecting HID Host from device.
 * @param hid_cid
 * @result status ERROR_CODE_SUCCESS on success, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, ERROR_CODE_COMMAND_DISALLOWED
 */
uint8_t hid_host_send_virtual_cable_unplug(uint16_t hid_cid);

/*
 * @brief Set Protocol Mode on the Bluetooth HID Device and emit HID_SUBEVENT_SET_PROTOCOL_RESPONSE event with handshake_status, see hid_handshake_param_type_t
 * @param hid_cid
 * @param protocol_mode see hid_protocol_mode_t in btstack_hid.h
 * @result status ERROR_CODE_SUCCESS on success, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, ERROR_CODE_COMMAND_DISALLOWED
 */
uint8_t hid_host_send_set_protocol_mode(uint16_t hid_cid, hid_protocol_mode_t protocol_mode);

/*
 * @brief Retrieve the Protocol Mode of the Bluetooth HID Device and emit HID_SUBEVENT_GET_PROTOCOL_RESPONSE with handshake_status, see hid_handshake_param_type_t
 * @param hid_cid
 * @param protocol_mode see hid_protocol_mode_t in btstack_hid.h
 * @result status ERROR_CODE_SUCCESS on success, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, ERROR_CODE_COMMAND_DISALLOWED
 */
uint8_t hid_host_send_get_protocol(uint16_t hid_cid);

/*

 * @brief Send report to a Bluetooth HID Device and emit HID_SUBEVENT_SET_REPORT_RESPONSE with handshake_status, see hid_handshake_param_type_t. The Bluetooth HID Host shall send complete reports.
 * @param hid_cid
 * @param report_type see hid_report_type_t in btstack_hid.h
 * @param report_id
 * @param report
 * @param report_len
 * @result status ERROR_CODE_SUCCESS on success, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, ERROR_CODE_COMMAND_DISALLOWED
 */
uint8_t hid_host_send_set_report(uint16_t hid_cid, hid_report_type_t report_type, uint8_t report_id, const uint8_t * report, uint8_t report_len);

/*
 * @brief Request a HID report from the Bluetooth HID Device and emit HID_SUBEVENT_GET_REPORT_RESPONSE event with with handshake_status, see hid_handshake_param_type_t. 
 * Polling Bluetooth HID Devices using the GET_REPORT transfer is costly in terms of time and overhead, 
 * and should be avoided whenever possible. The GET_REPORT transfer is typically only used by applications 
 * to determine the initial state of a Bluetooth HID Device. If the state of a report changes frequently, 
 * then the report should be reported over the more efficient Interrupt channel, see hid_host_send_report.
 * @param hid_cid
 * @param report_type see hid_report_type_t in btstack_hid.h
 * @param report_id
 * @result status ERROR_CODE_SUCCESS on success, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, ERROR_CODE_COMMAND_DISALLOWED
 */
uint8_t hid_host_send_get_report(uint16_t hid_cid, hid_report_type_t report_type, uint8_t report_id);

/**
 * @brief Send HID output report on interrupt channel.
 * @param hid_cid
 * @param report_id
 * @param report
 * @param report_len
 * @result status ERROR_CODE_SUCCESS on success, otherwise ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, ERROR_CODE_COMMAND_DISALLOWED
 */
uint8_t hid_host_send_report(uint16_t hid_cid, uint8_t report_id, const uint8_t * report, uint8_t report_len);

/*
 * @brief Get descriptor data
 * @param hid_cid
 * @result data
 */
const uint8_t * hid_descriptor_storage_get_descriptor_data(uint16_t hid_cid);

/*
 * @brief Get descriptor length
 * @param hid_cid
 * @result length
 */
uint16_t hid_descriptor_storage_get_descriptor_len(uint16_t hid_cid);

/**
 * @brief De-Init HID Device
 */
void hid_host_deinit(void);

HSP Audio Gateway API {#sec:hsp_ag_api}

hsp_ag.h

/**
 * @brief Set up HSP AG.
 * @param rfcomm_channel_nr
 */
void hsp_ag_init(uint8_t rfcomm_channel_nr);

/**
 * @brief Create HSP Audio Gateway (AG) SDP service record. 
 * @param service Empty buffer in which a new service record will be stored.
 * @param service_record_handle
 * @param rfcomm_channel_nr
 * @param name
 */
void hsp_ag_create_sdp_record(uint8_t * service, uint32_t service_record_handle, int rfcomm_channel_nr, const char * name);

/**
 * @brief Register packet handler to receive HSP AG events.

 * The HSP AG event has type HCI_EVENT_HSP_META with following subtypes:  
 * - HSP_SUBEVENT_RFCOMM_CONNECTION_COMPLETE
 * - HSP_SUBEVENT_RFCOMM_DISCONNECTION_COMPLETE
 * - HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE    
 * - HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE                       
 * - HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED      
 * - HSP_SUBEVENT_SPEAKER_GAIN_CHANGED         
 * - HSP_SUBEVENT_HS_COMMAND      
 *
 * @param callback 
 */
void hsp_ag_register_packet_handler(btstack_packet_handler_t callback);

/**
 * @brief Connect to HSP Headset.
 *
 * Perform SDP query for an RFCOMM service on a remote device, 
 * and establish an RFCOMM connection if such service is found. Reception of the  
 * HSP_SUBEVENT_RFCOMM_CONNECTION_COMPLETE with status 0
 * indicates if the connection is successfully established. 
 *
 * @param bd_addr
 */
void hsp_ag_connect(bd_addr_t bd_addr);

/**
 * @brief Disconnect from HSP Headset
 *
 * Reception of the HSP_SUBEVENT_RFCOMM_DISCONNECTION_COMPLETE with status 0
 * indicates if the connection is successfully released. 
 * @param bd_addr
 */
void hsp_ag_disconnect(void);


/**
 * @brief Establish audio connection.
 * 
 * Reception of the HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE with status 0
 * indicates if the audio connection is successfully established. 
 * @param bd_addr
 */
void hsp_ag_establish_audio_connection(void);

/**
 * @brief Release audio connection.
 *
 * Reception of the HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE with status 0
 * indicates if the connection is successfully released. 
 * @param bd_addr
 */
void hsp_ag_release_audio_connection(void);

/**
 * @brief Set microphone gain. 
 * @param gain Valid range: [0,15]
 */
void hsp_ag_set_microphone_gain(uint8_t gain);

/**
 * @brief Set speaker gain. 
 * @param gain Valid range: [0,15]
 */
void hsp_ag_set_speaker_gain(uint8_t gain);

/**
 * @brief Start ringing because of incoming call.
 */
void hsp_ag_start_ringing(void);

/**
 * @brief Stop ringing (e.g. call was terminated).
 */
void hsp_ag_stop_ringing(void);

/**
 * @brief Enable custom AT commands.
 * 
 * Custom commands are disabled by default. 
 * When enabled, custom AT commands are received via the HSP_SUBEVENT_HS_COMMAND.
 * @param enable
 */
void hsp_ag_enable_custom_commands(int enable);

/**
 * @brief Send a custom AT command to HSP Headset.
 *
 * On HSP_SUBEVENT_AG_INDICATION, the client needs to respond
 * with this function with the result to the custom command.
 * @param result 
 */
int hsp_ag_send_result(char * result);

/**
 * @brief Set packet types used for outgoing SCO connection requests
 * @param common single packet_types: SCO_PACKET_TYPES_*
 */
void hsp_ag_set_sco_packet_types(uint16_t packet_types);

/**
 * @brief De-Init HSP AG
 */
void hsp_ag_deinit(void);

HSP Headset API {#sec:hsp_hs_api}

hsp_hs.h

/**
 * @brief Set up HSP HS.
 * @param rfcomm_channel_nr
 */
void hsp_hs_init(uint8_t rfcomm_channel_nr);

/**
 * @brief Create HSP Headset (HS) SDP service record. 
 * @param service Empty buffer in which a new service record will be stored.
 * @param rfcomm_channel_nr
 * @param name
 * @param have_remote_audio_control 
 */
void hsp_hs_create_sdp_record(uint8_t * service, uint32_t service_record_handle, int rfcomm_channel_nr, const char * name, uint8_t have_remote_audio_control);

/**
 * @brief Register packet handler to receive HSP HS events.
 *
 * The HSP HS event has type HCI_EVENT_HSP_META with following subtypes:                      
 * - HSP_SUBEVENT_RFCOMM_CONNECTION_COMPLETE
 * - HSP_SUBEVENT_RFCOMM_DISCONNECTION_COMPLETE
 * - HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE    
 * - HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE 
 * - HSP_SUBEVENT_RING                         
 * - HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED      
 * - HSP_SUBEVENT_SPEAKER_GAIN_CHANGED         
 * - HSP_SUBEVENT_AG_INDICATION     
 *
 * @param callback 
 */
void hsp_hs_register_packet_handler(btstack_packet_handler_t callback);

/**
 * @brief Connect to HSP Audio Gateway.
 *
 * Perform SDP query for an RFCOMM service on a remote device, 
 * and establish an RFCOMM connection if such service is found. Reception of the  
 * HSP_SUBEVENT_RFCOMM_CONNECTION_COMPLETE with status 0
 * indicates if the connection is successfully established. 
 *
 * @param bd_addr
 */
void hsp_hs_connect(bd_addr_t bd_addr);

/**
 * @brief Disconnect from HSP Audio Gateway
 *
 * Releases the RFCOMM channel. Reception of the  
 * HSP_SUBEVENT_RFCOMM_DISCONNECTION_COMPLETE with status 0
 * indicates if the connection is successfully released. 
 * @param bd_addr
 */
void hsp_hs_disconnect(void);


/**
 * @brief Send button press action. Toggle establish/release of audio connection. 
 */
void hsp_hs_send_button_press(void);

/**
 * @brief Triger establishing audio connection.
 * 
 * Reception of the HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE with status 0
 * indicates if the audio connection is successfully established. 
 * @param bd_addr
 */
void hsp_hs_establish_audio_connection(void);

/**
 * @brief Trigger releasing audio connection.
 *
 * Reception of the HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE with status 0
 * indicates if the connection is successfully released. 
 * @param bd_addr
 */
void hsp_hs_release_audio_connection(void);

/**
 * @brief Set microphone gain. 
 * 
 * The new gain value will be confirmed by the HSP Audio Gateway. 
 * A HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED event will be received.
 * @param gain Valid range: [0,15]
 */
void hsp_hs_set_microphone_gain(uint8_t gain);

/**
 * @brief Set speaker gain. 
 * 
 * The new gain value will be confirmed by the HSP Audio Gateway. 
 * A HSP_SUBEVENT_SPEAKER_GAIN_CHANGED event will be received.
 * @param gain - valid range: [0,15]
 */
void hsp_hs_set_speaker_gain(uint8_t gain);



/**
 * @brief Enable custom indications.
 * 
 * Custom indications are disabled by default. 
 * When enabled, custom indications are received via the HSP_SUBEVENT_AG_INDICATION.
 * @param enable
 */
void hsp_hs_enable_custom_indications(int enable);

/**
 * @brief Send answer to custom indication.
 *
 * On HSP_SUBEVENT_AG_INDICATION, the client needs to respond
 * with this function with the result to the custom indication
 * @param result 
 */
int hsp_hs_send_result(const char * result);

/**
 * @brief Set packet types used for incoming SCO connection requests
 * @param common single packet_types: SCO_PACKET_TYPES_*
 */
void hsp_hs_set_sco_packet_types(uint16_t packet_types);

/**
 * @brief De-Init HSP AG
 */
void hsp_hs_deinit(void);

Personal Area Network (PAN) API {#sec:pan_api}

pan.h

/** 
 * @brief Creates SDP record for PANU BNEP service in provided empty buffer.
 * @note Make sure the buffer is big enough.
 *
 * @param service is an empty buffer to store service record
 * @param service_record_handle for new service
 * @param network_packet_types array of types terminated by a 0x0000 entry
 * @param name if NULL, the default service name will be assigned
 * @param description if NULL, the default service description will be assigned
 * @param security_desc 
 */
void pan_create_panu_sdp_record(uint8_t *service, uint32_t service_record_handle, uint16_t * network_packet_types, const char *name,
    const char *description, security_description_t security_desc);

/** 
 * @brief Creates SDP record for GN BNEP service in provided empty buffer.
 * @note Make sure the buffer is big enough.
 *
 * @param service is an empty buffer to store service record
 * @param service_record_handle for new service
 * @param network_packet_types array of types terminated by a 0x0000 entry
 * @param name if NULL, the default service name will be assigned
 * @param description if NULL, the default service description will be assigned
 * @param security_desc 
 * @param IPv4Subnet is optional subnet definition, e.g. "10.0.0.0/8"
 * @param IPv6Subnet is optional subnet definition given in the standard IETF format with the absolute attribute IDs
 */
void pan_create_gn_sdp_record(uint8_t *service, uint32_t service_record_handle, uint16_t * network_packet_types, const char *name,
    const char *description, security_description_t security_desc, const char *IPv4Subnet,
    const char *IPv6Subnet);

/** 
 * @brief Creates SDP record for NAP BNEP service in provided empty buffer.
 * @note Make sure the buffer is big enough.
 *
 * @param service is an empty buffer to store service record
 * @param service_record_handle for new service
 * @param name if NULL, the default service name will be assigned
 * @param network_packet_types array of types terminated by a 0x0000 entry
 * @param description if NULL, the default service description will be assigned
 * @param security_desc 
 * @param net_access_type type of available network access
 * @param max_net_access_rate based on net_access_type measured in byte/s
 * @param IPv4Subnet is optional subnet definition, e.g. "10.0.0.0/8"
 * @param IPv6Subnet is optional subnet definition given in the standard IETF format with the absolute attribute IDs
 */
void pan_create_nap_sdp_record(uint8_t *service, uint32_t service_record_handle, uint16_t * network_packet_types, const char *name,
    const char *description, security_description_t security_desc, net_access_type_t net_access_type,
    uint32_t max_net_access_rate, const char *IPv4Subnet, const char *IPv6Subnet);

PBAP Client API {#sec:pbap_api}

pbap.h

// PBAP Supported Features

#define PBAP_SUPPORTED_FEATURES_DOWNLOAD                        (1<<0)
#define PBAP_SUPPORTED_FEATURES_BROWSING                        (1<<1)
#define PBAP_SUPPORTED_FEATURES_DATABASE_IDENTIFIER             (1<<2)
#define PBAP_SUPPORTED_FEATURES_FOLDER_VERSION_COUNTERS         (1<<3)
#define PBAP_SUPPORTED_FEATURES_VCARD_SELECTING                 (1<<4)
#define PBAP_SUPPORTED_FEATURES_ENHANCED_MISSED_CALLS           (1<<5)
#define PBAP_SUPPORTED_FEATURES_X_BT_UCI_VCARD_PROPERTY         (1<<6)
#define PBAP_SUPPORTED_FEATURES_X_BT_UID_VCARD_PROPERTY         (1<<7)
#define PBAP_SUPPORTED_FEATURES_CONTACT_REFERENCING             (1<<8)
#define PBAP_SUPPORTED_FEATURES_DEFAULT_CONTACT_IMAGE_FORMAT    (1<<9)

// PBAP Property Mask - also used for vCardSelector
#define PBAP_PROPERTY_MASK_VERSION              (1<< 0) // vCard Version
#define PBAP_PROPERTY_MASK_FN                   (1<< 1) // Formatted Name
#define PBAP_PROPERTY_MASK_N                    (1<< 2) // Structured Presentation of Name
#define PBAP_PROPERTY_MASK_PHOTO                (1<< 3) // Associated Image or Photo
#define PBAP_PROPERTY_MASK_BDAY                 (1<< 4) // Birthday
#define PBAP_PROPERTY_MASK_ADR                  (1<< 5) // Delivery Address
#define PBAP_PROPERTY_MASK_LABEL                (1<< 6) // Delivery
#define PBAP_PROPERTY_MASK_TEL                  (1<< 7) // Telephone Number
#define PBAP_PROPERTY_MASK_EMAIL                (1<< 8) // Electronic Mail Address
#define PBAP_PROPERTY_MASK_MAILER               (1<< 9) // Electronic Mail
#define PBAP_PROPERTY_MASK_TZ                   (1<<10) // Time Zone
#define PBAP_PROPERTY_MASK_GEO                  (1<<11) // Geographic Position
#define PBAP_PROPERTY_MASK_TITLE                (1<<12) // Job
#define PBAP_PROPERTY_MASK_ROLE                 (1<<13) // Role within the Organization
#define PBAP_PROPERTY_MASK_LOGO                 (1<<14) // Organization Logo
#define PBAP_PROPERTY_MASK_AGENT                (1<<15) // vCard of Person Representing
#define PBAP_PROPERTY_MASK_ORG                  (1<<16) // Name of Organization
#define PBAP_PROPERTY_MASK_NOTE                 (1<<17) // Comments
#define PBAP_PROPERTY_MASK_REV                  (1<<18) // Revision
#define PBAP_PROPERTY_MASK_SOUND                (1<<19) // Pronunciation of Name
#define PBAP_PROPERTY_MASK_URL                  (1<<20) // Uniform Resource Locator
#define PBAP_PROPERTY_MASK_UID                  (1<<21) // Unique ID
#define PBAP_PROPERTY_MASK_KEY                  (1<<22) // Public Encryption Key
#define PBAP_PROPERTY_MASK_NICKNAME             (1<<23) // Nickname
#define PBAP_PROPERTY_MASK_CATEGORIES           (1<<24) // Categories
#define PBAP_PROPERTY_MASK_PROID                (1<<25) // Product ID
#define PBAP_PROPERTY_MASK_CLASS                (1<<26) // Class information
#define PBAP_PROPERTY_MASK_SORT_STRING          (1<<27) // String used for sorting operations
#define PBAP_PROPERTY_MASK_X_IRMC_CALL_DATETIME (1<<28) // Time stamp
#define PBAP_PROPERTY_MASK_X_BT_SPEEDDIALKEY    (1<<29) // Speed-dial shortcut
#define PBAP_PROPERTY_MASK_X_BT_UCI             (1<<30) // Uniform Caller Identifier
#define PBAP_PROPERTY_MASK_X_BT_UID             (1<<31) // Bluetooth Contact Unique Identifier

// PBAP vCardSelectorOperator
#define PBAP_VCARD_SELECTOR_OPERATOR_OR          0
#define PBAP_VCARD_SELECTOR_OPERATOR_AND         1

// PBAP Format
typedef enum {
    PBAP_FORMAT_VCARD_21 = 0,
    PBAP_FORMAT_VCRAD_30
} pbap_format_vcard_t;

// PBAP Object Types
typedef enum {
    PBAP_OBJECT_TYPE_INVALID = 0,
    PBAP_OBJECT_TYPE_PHONEBOOOK,
    PBAP_OBJECT_TYPE_VCARD_LISTING,
    PBAP_OBJECT_TYPE_VCARD,
} pbap_object_type_t;

// PBAP Phonebooks
typedef enum {
    PBAP_PHONEBOOK_INVALID = 0,
    PBAP_PHONEBOOK_TELECOM_CCH,
    PBAP_PHONEBOOK_TELECOM_FAV,
    PBAP_PHONEBOOK_TELECOM_ICH,
    PBAP_PHONEBOOK_TELECOM_MCH,
    PBAP_PHONEBOOK_TELECOM_OCH,
    PBAP_PHONEBOOK_TELECOM_PB,
    PBAP_PHONEBOOK_TELECOM_SPD,
    PBAP_PHONEBOOK_SIM_TELECOM_CCH,
    PBAP_PHONEBOOK_SIM_TELECOM_ICH,
    PBAP_PHONEBOOK_SIM_TELECOM_MCH,
    PBAP_PHONEBOOK_SIM_TELECOM_OCH,
    PBAP_PHONEBOOK_SIM_TELECOM_PB
} pbap_phonebook_t;

// lengths
#define PBAP_DATABASE_IDENTIFIER_LEN 16
#define PBAP_FOLDER_VERSION_LEN 16

PBAP Client API {#sec:pbap_client_api}

pbap_client.h

/**
 * Setup PhoneBook Access Client
 */
void pbap_client_init(void);

/**
 * @brief Create PBAP connection to a Phone Book Server (PSE) server on a remote device. 
 * If the server requires authentication, a PBAP_SUBEVENT_AUTHENTICATION_REQUEST is emitted, which
 * can be answered with pbap_authentication_password(..).
 * The status of PBAP connection establishment is reported via PBAP_SUBEVENT_CONNECTION_OPENED event, 
 * i.e. on success status field is set to ERROR_CODE_SUCCESS.
 *    
 * @param handler 
 * @param addr
 * @param out_cid to use for further commands
 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_MEMORY_ALLOC_FAILED if PBAP or GOEP connection already exists.  
 */
uint8_t pbap_connect(btstack_packet_handler_t handler, bd_addr_t addr, uint16_t * out_cid);

/**
 * @brief Provide password for OBEX Authentication after receiving PBAP_SUBEVENT_AUTHENTICATION_REQUEST.
 * The status of PBAP connection establishment is reported via PBAP_SUBEVENT_CONNECTION_OPENED event, 
 * i.e. on success status field is set to ERROR_CODE_SUCCESS.
 * 
 * @param pbap_cid
 * @param password (null terminated string) - not copied, needs to stay valid until connection completed
 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state.
 */
uint8_t pbap_authentication_password(uint16_t pbap_cid, const char * password);

/** 
 * @brief Disconnects PBAP connection with given identifier.
 * Event PBAP_SUBEVENT_CONNECTION_CLOSED indicates that PBAP connection is closed.
 *
 * @param pbap_cid
 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state.
 */
uint8_t pbap_disconnect(uint16_t pbap_cid);

/** 
 * @brief Set current folder on PSE. The status is reported via PBAP_SUBEVENT_OPERATION_COMPLETED event. 
 * 
 * @param pbap_cid
 * @param path - note: path is not copied
 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state.
 */
uint8_t pbap_set_phonebook(uint16_t pbap_cid, const char * path);

/**
 * @brief Set vCard Selector for get/pull phonebook. No event is emitted.
 * 
 * @param pbap_cid
 * @param vcard_selector - combination of PBAP_PROPERTY_MASK_* properties
 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state.
 */
uint8_t pbap_set_vcard_selector(uint16_t pbap_cid, uint32_t vcard_selector);

/**
 * @brief Set vCard Selector for get/pull phonebook. No event is emitted.
 * 
 * @param pbap_cid
 * @param vcard_selector_operator - PBAP_VCARD_SELECTOR_OPERATOR_OR (default) or PBAP_VCARD_SELECTOR_OPERATOR_AND
 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state.
 */
uint8_t pbap_set_vcard_selector_operator(uint16_t pbap_cid, int vcard_selector_operator);

/**
 * @brief Set Property Selector. No event is emitted.
 * @param pbap_cid
 * @param property_selector - combination of PBAP_PROPERTY_MASK_* properties
 * @return
 */
uint8_t pbap_set_property_selector(uint16_t pbap_cid, uint32_t property_selector);

/**
 * @brief Get size of phone book from PSE. The result is reported via PBAP_SUBEVENT_PHONEBOOK_SIZE event. 
 * 
 * @param pbap_cid
 * @param path - note: path is not copied, common path 'telecom/pb.vcf'
 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state.
 */
uint8_t pbap_get_phonebook_size(uint16_t pbap_cid, const char * path);

/**
 * @brief Pull phone book from PSE. The result is reported via registered packet handler (see pbap_connect function),
 * with packet type set to PBAP_DATA_PACKET. Event PBAP_SUBEVENT_OPERATION_COMPLETED marks the end of the phone book. 
 * 
 * @param pbap_cid
 * @param path - note: path is not copied, common path 'telecom/pb.vcf'
 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state.
 */
uint8_t pbap_pull_phonebook(uint16_t pbap_cid, const char * path);

/**
 * @brief Pull vCard listing. vCard data is emitted via PBAP_SUBEVENT_CARD_RESULT event. 
 * Event PBAP_SUBEVENT_OPERATION_COMPLETED marks the end of vCard listing.
 *
 * @param pbap_cid
 * @param path
 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state.
 */
uint8_t pbap_pull_vcard_listing(uint16_t pbap_cid, const char * path);

/**
 * @brief Pull vCard entry. The result is reported via callback (see pbap_connect function),
 * with packet type set to PBAP_DATA_PACKET.
 * Event PBAP_SUBEVENT_OPERATION_COMPLETED marks the end of the vCard entry.
 * 
 * @param pbap_cid
 * @param path
 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state.
 */
uint8_t pbap_pull_vcard_entry(uint16_t pbap_cid, const char * path);

/**
 * @brief Lookup contact(s) by phone number. vCard data is emitted via PBAP_SUBEVENT_CARD_RESULT event. 
 * Event PBAP_SUBEVENT_OPERATION_COMPLETED marks the end of the lookup.
 *
 * @param pbap_cid
 * @param phone_number
 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state.
 */
uint8_t pbap_lookup_by_number(uint16_t pbap_cid, const char * phone_number);

/**
 * @brief Abort current operation. No event is emitted.
 * 
 * @param pbap_cid
 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state.
 */
uint8_t pbap_abort(uint16_t pbap_cid);


/**
 * @brief Set flow control mode - default is off. No event is emitted.
 * @note When enabled, pbap_next_packet needs to be called after a packet was processed to receive the next one
 *
 * @param pbap_cid
 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state.
 */
uint8_t pbap_set_flow_control_mode(uint16_t pbap_cid, int enable);

/**
 * @brief Trigger next packet from PSE when Flow Control Mode is enabled.
 * @param pbap_cid
 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state.
 */
uint8_t pbap_next_packet(uint16_t pbap_cid);

/**
 * @brief De-Init PBAP Client
 */
void pbap_client_deinit(void);

RFCOMM API {#sec:rfcomm_api}

rfcomm.h

/** 
 * @brief Set up RFCOMM.
 */
void rfcomm_init(void);

/** 
 * @brief Set security level required for incoming connections, need to be called before registering services.
 * @deprecated use gap_set_security_level instead
 */
void rfcomm_set_required_security_level(gap_security_level_t security_level);

/* 
 * @brief Create RFCOMM connection to a given server channel on a remote deivce.
 * This channel will automatically provide enough credits to the remote side.
 * @param addr
 * @param server_channel
 * @param out_cid
 * @result status
 */
uint8_t rfcomm_create_channel(btstack_packet_handler_t packet_handler, bd_addr_t addr, uint8_t server_channel, uint16_t * out_cid);

/* 
 * @brief Create RFCOMM connection to a given server channel on a remote deivce.
 * This channel will use explicit credit management. During channel establishment, an initial  amount of credits is provided.
 * @param addr
 * @param server_channel
 * @param initial_credits
 * @param out_cid
 * @result status
 */
uint8_t rfcomm_create_channel_with_initial_credits(btstack_packet_handler_t packet_handler, bd_addr_t addr, uint8_t server_channel, uint8_t initial_credits, uint16_t * out_cid);

/** 
 * @brief Disconnects RFCOMM channel with given identifier.
 * @return status
 */
uint8_t rfcomm_disconnect(uint16_t rfcomm_cid);

/** 
 * @brief Registers RFCOMM service for a server channel and a maximum frame size, and assigns a packet handler.
 * This channel provides credits automatically to the remote side -> no flow control
 * @param packet handler for all channels of this service
 * @param channel 
 * @param max_frame_size
 * @return status ERROR_CODE_SUCCESS if successful, otherwise L2CAP_SERVICE_ALREADY_REGISTERED or BTSTACK_MEMORY_ALLOC_FAILED
 */
uint8_t rfcomm_register_service(btstack_packet_handler_t packet_handler, uint8_t channel, uint16_t max_frame_size);

/** 
 * @brief Registers RFCOMM service for a server channel and a maximum frame size, and assigns a packet handler. 
 * This channel will use explicit credit management. During channel establishment, an initial amount of credits is provided.
 * @param packet handler for all channels of this service
 * @param channel 
 * @param max_frame_size
 * @param initial_credits
 * @return status ERROR_CODE_SUCCESS if successful, otherwise L2CAP_SERVICE_ALREADY_REGISTERED or BTSTACK_MEMORY_ALLOC_FAILED
 */
uint8_t rfcomm_register_service_with_initial_credits(btstack_packet_handler_t packet_handler, uint8_t channel, uint16_t max_frame_size, uint8_t initial_credits);

/** 
 * @brief Unregister RFCOMM service.
 */
void rfcomm_unregister_service(uint8_t service_channel);

/** 
 * @brief Accepts incoming RFCOMM connection.
 * @return status
 */
uint8_t rfcomm_accept_connection(uint16_t rfcomm_cid);

/** 
 * @brief Deny incoming RFCOMM connection.
 * @return status
 */
uint8_t rfcomm_decline_connection(uint16_t rfcomm_cid);

/** 
 * @brief Grant more incoming credits to the remote side for the given RFCOMM channel identifier.
 * @return status
 */
uint8_t rfcomm_grant_credits(uint16_t rfcomm_cid, uint8_t credits);

/** 
 * @brief Checks if RFCOMM can send packet. 
 * @param rfcomm_cid
 * @result true if can send now
 */
bool rfcomm_can_send_packet_now(uint16_t rfcomm_cid);

/** 
 * @brief Request emission of RFCOMM_EVENT_CAN_SEND_NOW as soon as possible
 * @note RFCOMM_EVENT_CAN_SEND_NOW might be emitted during call to this function
 *       so packet handler should be ready to handle it
 * @param rfcomm_cid
 * @prarm status
 */
uint8_t rfcomm_request_can_send_now_event(uint16_t rfcomm_cid);

/** 
 * @brief Sends RFCOMM data packet to the RFCOMM channel with given identifier.
 * @param rfcomm_cid
 * @return status
 */
uint8_t rfcomm_send(uint16_t rfcomm_cid, uint8_t *data, uint16_t len);

/** 
 * @brief Sends Local Line Status, see LINE_STATUS_..
 * @param rfcomm_cid
 * @param line_status
 * @return status
 */
uint8_t rfcomm_send_local_line_status(uint16_t rfcomm_cid, uint8_t line_status);

/** 
 * @brief Send local modem status. see MODEM_STAUS_..
 * @param rfcomm_cid
 * @param modem_status
 * @return status
 */
uint8_t rfcomm_send_modem_status(uint16_t rfcomm_cid, uint8_t modem_status);

/** 
 * @brief Configure remote port 
 * @param rfcomm_cid
 * @param baud_rate
 * @param data_bits
 * @param stop_bits
 * @param parity
 * @param flow_control
 * @return status
 */
uint8_t rfcomm_send_port_configuration(uint16_t rfcomm_cid, rpn_baud_t baud_rate, rpn_data_bits_t data_bits, rpn_stop_bits_t stop_bits, rpn_parity_t parity, uint8_t flow_control);

/** 
 * @brief Query remote port 
 * @param rfcomm_cid
 * @return status
 */
uint8_t rfcomm_query_port_configuration(uint16_t rfcomm_cid);

/** 
 * @brief Query max frame size
 * @param rfcomm_cid
 * @return max frame size
 */
uint16_t rfcomm_get_max_frame_size(uint16_t rfcomm_cid);

/** 
 * @brief Reserve packet buffer to allow to create RFCOMM packet in place
 * @note Must only be called after a 'can send now' check or event
 * @note Asserts if packet buffer is already reserved
 *
 * if (rfcomm_can_send_packet_now(cid)){
 *     rfcomm_reserve_packet_buffer();
 *     uint8_t * buffer = rfcomm_get_outgoing_buffer();
 *     uint16_t buffer_size = rfcomm_get_max_frame_size(cid);
 *     .. setup data in buffer with len ..
 *     rfcomm_send_prepared(cid, len)
 * }
 */
void rfcomm_reserve_packet_buffer(void);

/**
 * @brief Get outgoing buffer
 * @return pointer to outgoing rfcomm buffer
 */
uint8_t * rfcomm_get_outgoing_buffer(void);

/**
 * @brief Send packet prepared in outgoing buffer
 * @note This releases the outgoing rfcomm buffer
 * @param rfcomm_cid
 * @param len
 * @return status
 */
uint8_t rfcomm_send_prepared(uint16_t rfcomm_cid, uint16_t len);

/**
 * @brief Release outgoing buffer in case rfcomm_send_prepared was not called
*/
void rfcomm_release_packet_buffer(void);

/**
 * @brief Enable L2CAP ERTM mode for RFCOMM. request callback is used to provide ERTM buffer. released callback returns buffer
 *
 * @note on request_callback, the app must set the ertm_config, buffer, size fields to enable ERTM for the current connection
 * @note if buffer is not set, BASIC mode will be used instead
 *
 * @note released_callback provides ertm_id from earlier request to match request and release
 *
 * @param request_callback
 * @param released_callback
 */
void rfcomm_enable_l2cap_ertm(void request_callback(rfcomm_ertm_request_t * request), void released_callback(uint16_t ertm_id));


// Event getters for RFCOMM_EVENT_PORT_CONFIGURATION

/**
 * @brief Get field rfcomm_cid from event RFCOMM_EVENT_PORT_CONFIGURATION
 * @param event packet
 * @return rfcomm_cid
 */
static inline uint16_t rfcomm_event_port_configuration_get_rfcomm_cid(const uint8_t * event){
    return little_endian_read_16(event, 2);
}

/**
 * @brief Get field local from event RFCOMM_EVENT_PORT_CONFIGURATION
 * @param event packet
 * @return remote - false for local port, true for remote port
 */
static inline bool rfcomm_event_port_configuration_get_remote(const uint8_t * event){
    return event[4] != 0;
}

/**
 * @brief Get field baud_rate from event RFCOMM_EVENT_PORT_CONFIGURATION
 * @param event packet
 * @return baud_rate
 */

static inline rpn_baud_t rfcomm_event_port_configuration_get_baud_rate(const uint8_t * event){
    return (rpn_baud_t) event[5];
}

/**
 * @brief Get field data_bits from event RFCOMM_EVENT_PORT_CONFIGURATION
 * @param event packet
 * @return data_bits
 */

static inline rpn_data_bits_t rfcomm_event_port_configuration_get_data_bits(const uint8_t * event){
    return (rpn_data_bits_t) (event[6] & 3);
}
/**
 * @brief Get field stop_bits from event RFCOMM_EVENT_PORT_CONFIGURATION
 * @param event packet
 * @return stop_bits
 */
static inline rpn_stop_bits_t rfcomm_event_port_configuration_get_stop_bits(const uint8_t * event){
    return (rpn_stop_bits_t) ((event[6] >> 2) & 1);
}

/**
 * @brief Get field parity from event RFCOMM_EVENT_PORT_CONFIGURATION
 * @param event packet
 * @return parity
 */
static inline rpn_parity_t rfcomm_event_port_configuration_get_parity(const uint8_t * event){
    return (rpn_parity_t) ((event[6] >> 3) & 7);
}

/**
 * @brief Get field flow_control from event RFCOMM_EVENT_PORT_CONFIGURATION
 * @param event packet
 * @return flow_control
 */

static inline uint8_t rfcomm_event_port_configuration_get_flow_control(const uint8_t * event){
    return event[7] & 0x3f;
}

/**
 * @brief Get field xon from event RFCOMM_EVENT_PORT_CONFIGURATION
 * @param event packet
 * @return xon
 */
static inline uint8_t rfcomm_event_port_configuration_get_xon(const uint8_t * event){
    return event[8];
}

/**
 * @brief Get field xoff from event RFCOMM_EVENT_PORT_CONFIGURATION
 * @param event packet
 * @return xoff
 */
static inline uint8_t rfcomm_event_port_configuration_get_xoff(const uint8_t * event){
    return event[9];
}

/**
 * @brief De-Init RFCOMM
 */
void rfcomm_deinit(void);

SDP Client API {#sec:sdp_client_api}

sdp_client.h

typedef struct de_state {
    uint8_t  in_state_GET_DE_HEADER_LENGTH ;
    uint32_t addon_header_bytes;
    uint32_t de_size;
    uint32_t de_offset;
} de_state_t;

void de_state_init(de_state_t * state);
int  de_state_size(uint8_t eventByte, de_state_t *de_state);

/**
 * @brief SDP Client Init
 */
void sdp_client_init(void);

/** 
 * @brief Checks if the SDP Client is ready
 * @deprecated Please use sdp_client_register_query_callback instead
 * @return true when no query is active
 */
bool sdp_client_ready(void);

/**
 * @brief Requests a callback, when the SDP Client is ready and can be used
 * @note The callback might happens before sdp_client_register_query_callback has returned
 * @param callback_registration
 */
uint8_t sdp_client_register_query_callback(btstack_context_callback_registration_t * callback_registration);

/** 
 * @brief Queries the SDP service of the remote device given a service search pattern and a list of attribute IDs. 
 * The remote data is handled by the SDP parser. The SDP parser delivers attribute values and done event via the callback.
 * @param callback for attributes values and done event
 * @param remote address
 * @param des_service_search_pattern 
 * @param des_attribute_id_list
 */
uint8_t sdp_client_query(btstack_packet_handler_t callback, bd_addr_t remote, const uint8_t * des_service_search_pattern, const uint8_t * des_attribute_id_list);

/*
 * @brief Searches SDP records on a remote device for all services with a given UUID.
 * @note calls sdp_client_query with service search pattern based on uuid16
 */
uint8_t sdp_client_query_uuid16(btstack_packet_handler_t callback, bd_addr_t remote, uint16_t uuid16);

/*
 * @brief Searches SDP records on a remote device for all services with a given UUID.
 * @note calls sdp_client_query with service search pattern based on uuid128
 */
uint8_t sdp_client_query_uuid128(btstack_packet_handler_t callback, bd_addr_t remote, const uint8_t* uuid128);


/** 
 * @brief Retrieves all attribute IDs of a SDP record specified by its service record handle and a list of attribute IDs. 
 * The remote data is handled by the SDP parser. The SDP parser delivers attribute values and done event via the callback.
 * @note only provided if ENABLE_SDP_EXTRA_QUERIES is defined
 * @param callback for attributes values and done event 
 * @param remote address
 * @param search_service_record_handle 
 * @param des_attributeIDList
 */
uint8_t sdp_client_service_attribute_search(btstack_packet_handler_t callback, bd_addr_t remote, uint32_t search_service_record_handle, const uint8_t * des_attributeIDList);

/** 
 * @brief Query the list of SDP records that match a given service search pattern. 
 * The remote data is handled by the SDP parser. The SDP parser delivers attribute values and done event via the callback.
 * @note only provided if ENABLE_SDP_EXTRA_QUERIES is defined
 * @param callback for attributes values and done event
 * @param remote address
 * @param des_service_search_pattern 
 */
uint8_t sdp_client_service_search(btstack_packet_handler_t callback, bd_addr_t remote, const uint8_t * des_service_search_pattern);

#ifdef ENABLE_SDP_EXTRA_QUERIES
void sdp_client_parse_service_record_handle_list(uint8_t* packet, uint16_t total_count, uint16_t current_count);
#endif

/**
 * @brief De-Init SDP Client
 */
void sdp_client_deinit(void);

SDP Client RFCOMM API {#sec:sdp_client_rfcomm_api}

sdp_client_rfcomm.h

/** 
 * @brief Searches SDP records on a remote device for RFCOMM services with a given 16-bit UUID anywhere.
 * @note calls sdp_service_search_pattern_for_uuid16 that uses global buffer
 * @param callback handler
 * @param remote BD_ADDR
 * @param uuid16
 */
 uint8_t sdp_client_query_rfcomm_channel_and_name_for_uuid(btstack_packet_handler_t callback, bd_addr_t remote, uint16_t uuid16);

/**
 * @brief Searches SDP records on a remote device for RFCOMM services with a given 16-bit UUID in its ServiceClassIDList
 * @note calls sdp_service_search_pattern_for_uuid16 that uses global buffer
 * @param callback handler
 * @param remote BD_ADDR
 * @param uuid16
 */
uint8_t sdp_client_query_rfcomm_channel_and_name_for_service_class_uuid(btstack_packet_handler_t callback, bd_addr_t remote, uint16_t uuid16);

/**
 * @brief Searches SDP records on a remote device for RFCOMM services with a given 128-bit UUID anywhere
 * @note calls sdp_service_search_pattern_for_uuid128 that uses global buffer
 * @param callback handler
 * @param remote BD_ADDR
 * @param uuid128
 */
uint8_t sdp_client_query_rfcomm_channel_and_name_for_uuid128(btstack_packet_handler_t callback, bd_addr_t remote, const uint8_t * uuid128);

/** 
 * @brief Searches SDP records on a remote device for RFCOMM services with a given service search pattern.
 */
uint8_t sdp_client_query_rfcomm_channel_and_name_for_search_pattern(btstack_packet_handler_t callback, bd_addr_t remote, const uint8_t * des_serviceSearchPattern);

SDP Server API {#sec:sdp_server_api}

sdp_server.h

/** 
 * @brief Set up SDP Server.
 */
void sdp_init(void);

/**
 * @brief Register Service Record with database using ServiceRecordHandle stored in record
 * @pre AttributeIDs are in ascending order
 * @pre ServiceRecordHandle is first attribute and valid
 * @param record is not copied!
 * @result status
 */
uint8_t sdp_register_service(const uint8_t * record);

/** 
 * @brief Unregister service record internally.
 */
void sdp_unregister_service(uint32_t service_record_handle);

/**
 * @brief gets service record handle from record
 * @resutl service record handle or 0
 */
uint32_t sdp_get_service_record_handle(const uint8_t * record);

/**
 * @brief Finds an unused valid service record handle
 * @result handle
 */
uint32_t sdp_create_service_record_handle(void);

/**
 * @brief gets record for handle
 * @result record
 */

uint8_t * sdp_get_record_for_handle(uint32_t handle);

/**
 * @brief De-Init SDP Server
 */
void sdp_deinit(void);

SDP Utils API {#sec:sdp_util_api}

sdp_util.h

// OFFSETS FOR LOCALIZED ATTRIBUTES - BLUETOOTH_ATTRIBUTE_LANGUAGE_BASE_ATTRIBUTE_ID_LIST
#define SDP_Offset_ServiceName        0x0000
#define SDP_Offset_ServiceDescription 0x0001
#define SDP_Offset_ProviderName       0x0002

typedef enum {
    DE_NIL = 0,
    DE_UINT,
    DE_INT,
    DE_UUID,
    DE_STRING,
    DE_BOOL,
    DE_DES,
    DE_DEA,
    DE_URL
} de_type_t;

typedef enum {
    DE_SIZE_8 = 0,
    DE_SIZE_16,
    DE_SIZE_32,
    DE_SIZE_64,
    DE_SIZE_128,
    DE_SIZE_VAR_8,
    DE_SIZE_VAR_16,
    DE_SIZE_VAR_32
} de_size_t;

// MARK: DateElement
void      de_dump_data_element(const uint8_t * record);
uint32_t  de_get_len(const uint8_t * header);


// @note returned "string" is not NULL terminated
const uint8_t * de_get_string(const uint8_t * element);

de_size_t de_get_size_type(const uint8_t * header);
de_type_t de_get_element_type(const uint8_t * header);
uint32_t  de_get_header_size(const uint8_t * header);
// returns true if uint16 was read
bool      de_element_get_uint16(const uint8_t * element, uint16_t * value);
uint32_t  de_get_data_size(const uint8_t * header);
uint32_t  de_get_uuid32(const uint8_t * element);
// returns true if uint16 was read
bool      de_get_normalized_uuid(uint8_t *uuid128, const uint8_t *element);

void      de_create_sequence(uint8_t * header);
void      de_store_descriptor_with_len(uint8_t * header, de_type_t type, de_size_t size, uint32_t len);
uint8_t * de_push_sequence(uint8_t *sequence);
void      de_pop_sequence(uint8_t * parent, uint8_t * child);
void      de_add_number(uint8_t *sequence, de_type_t type, de_size_t size, uint32_t value);
void      de_add_data(uint8_t *sequence, de_type_t type, uint16_t size, uint8_t *data);
void      de_add_uuid128(uint8_t * sequence, uint8_t * uuid);

// returns data element  len if date element is smaller than size
uint32_t de_get_len_safe(const uint8_t * header, uint32_t size);

// MARK: DES iterator
typedef struct {
    uint8_t * element;
    uint16_t pos;
    uint16_t length;
} des_iterator_t;

bool      des_iterator_init(des_iterator_t * it, uint8_t * element);
bool      des_iterator_has_more(des_iterator_t * it);
de_type_t des_iterator_get_type (des_iterator_t * it);
uint16_t  des_iterator_get_size (des_iterator_t * it);
uint8_t * des_iterator_get_element(des_iterator_t * it);
void      des_iterator_next(des_iterator_t * it);

// MARK: SDP
uint16_t  sdp_append_attributes_in_attributeIDList(uint8_t *record, uint8_t *attributeIDList, uint16_t startOffset, uint16_t maxBytes, uint8_t *buffer);
uint8_t * sdp_get_attribute_value_for_attribute_id(uint8_t * record, uint16_t attributeID);
bool      sdp_set_attribute_value_for_attribute_id(uint8_t * record, uint16_t attributeID, uint32_t value);
bool      sdp_record_matches_service_search_pattern(uint8_t *record, uint8_t *serviceSearchPattern);
uint16_t  sdp_get_filtered_size(uint8_t *record, uint8_t *attributeIDList);
bool      sdp_filter_attributes_in_attributeIDList(uint8_t *record, uint8_t *attributeIDList, uint16_t startOffset, uint16_t maxBytes, uint16_t *usedBytes, uint8_t *buffer);
bool      sdp_attribute_list_contains_id(uint8_t *attributeIDList, uint16_t attributeID);

/*
 * @brief Returns service search pattern for given UUID-16
 * @note Uses fixed buffer
 */
uint8_t* sdp_service_search_pattern_for_uuid16(uint16_t uuid16);

/*
 * @brief Returns service search pattern for given UUID-128
 * @note Uses fixed buffer
 */
uint8_t* sdp_service_search_pattern_for_uuid128(const uint8_t * uuid128);

SPP Server API {#sec:spp_server_api}

spp_server.h : Create SPP SDP Records.

/**
 * @brief Create SDP record for SPP service with official SPP Service Class
 * @param service buffer - needs to large enough
 * @param service_record_handle
 * @param rfcomm_channel
 * @param name or NULL for default value. Provide "" (empty string) to skip attribute
 */
void spp_create_sdp_record(uint8_t *service, uint32_t service_record_handle, int rfcomm_channel, const char *name);

/**
 * @brief Create SDP record for SPP service with custom service UUID (e.g. for use with Android)
 * @param service buffer - needs to large enough
 * @param service_record_handle
 * @param service_uuid128 buffer
 * @param rfcomm_channel
 * @param name
 */
void spp_create_custom_sdp_record(uint8_t *service, uint32_t service_record_handle, const uint8_t * service_uuid128, int rfcomm_channel, const char *name);

Genral Access Profile (GAP) API {#sec:gap_api}

gap.h

// Classic + LE

/**
 * @brief Read RSSI
 * @param con_handle
 * @events: GAP_EVENT_RSSI_MEASUREMENT
 */
int gap_read_rssi(hci_con_handle_t con_handle);


/**
 * @brief Gets local address.
 */
void gap_local_bd_addr(bd_addr_t address_buffer);

/**
 * @brief Disconnect connection with handle
 * @param handle
 * @return status
 */
uint8_t gap_disconnect(hci_con_handle_t handle);

/**
 * @brief Get connection type
 * @param con_handle
 * @result connection_type
 */
gap_connection_type_t gap_get_connection_type(hci_con_handle_t connection_handle);

/**
 * @brief Get HCI connection role
 * @param con_handle
 * @result hci_role_t HCI_ROLE_MASTER / HCI_ROLE_SLAVE / HCI_ROLE_INVALID (if connection does not exist)
 */
hci_role_t gap_get_role(hci_con_handle_t connection_handle);

// Classic

/**
 * @brief Request role switch
 * @note this only requests the role switch. A HCI_EVENT_ROLE_CHANGE is emitted and its status field will indicate if the switch was succesful
 * @param addr
 * @param hci_role_t HCI_ROLE_MASTER / HCI_ROLE_SLAVE
 * @result status
 */
uint8_t gap_request_role(const bd_addr_t addr, hci_role_t role);

/**
 * @brief Sets local name.
 * @note Default name is 'BTstack 00:00:00:00:00:00'
 * @note '00:00:00:00:00:00' in local_name will be replaced with actual bd addr
 * @param name is not copied, make sure memory stays valid
 */
void gap_set_local_name(const char * local_name);

/**
 * @brief Set Extended Inquiry Response data
 * @note If not set, local name will be used for EIR data (see gap_set_local_name)
 * @note '00:00:00:00:00:00' in local_name will be replaced with actual bd addr
 * @param eir_data size HCI_EXTENDED_INQUIRY_RESPONSE_DATA_LEN (240) bytes, is not copied make sure memory stays valid
 */
void gap_set_extended_inquiry_response(const uint8_t * data);

/**
 * @brief Set class of device
 */
void gap_set_class_of_device(uint32_t class_of_device);

/**
 * @brief Set default link policy settings for all classic ACL links
 * @param default_link_policy_settings - see LM_LINK_POLICY_* in bluetooth.h
 * @note common value: LM_LINK_POLICY_ENABLE_ROLE_SWITCH | LM_LINK_POLICY_ENABLE_SNIFF_MODE to enable role switch and sniff mode
 */
void gap_set_default_link_policy_settings(uint16_t default_link_policy_settings);

/**
 * @brief Set Allow Role Switch param for outgoing classic ACL links
 * @param allow_role_switch - true: allow remote device to request role switch, false: stay master
 */
void gap_set_allow_role_switch(bool allow_role_switch);

/**
 * @brief Set  link supervision timeout for outgoing classic ACL links
 * @param default_link_supervision_timeout * 0.625 ms, default 0x7d00 = 20 seconds, 0 = no link supervision timeout
 */
void gap_set_link_supervision_timeout(uint16_t link_supervision_timeout);

/**
 * @brief Enable link watchdog. If no ACL packet is sent within timeout_ms, the link will get disconnected
 * note: current implementation uses the automatic flush timeout controller feature with a max timeout of 1.28s
 * @param timeout_ms
 */
void gap_enable_link_watchdog(uint16_t timeout_ms);

/**
 * @brief Enable/disable bonding. Default is enabled.
 * @param enabled
 */
void gap_set_bondable_mode(int enabled);

/**  
 * @brief Get bondable mode.
 * @return 1 if bondable
 */
int gap_get_bondable_mode(void);

/**
 * @brief Set security mode for all outgoing and incoming connections. Default: GAP_SECURITY_MODE_4
 * @param security_mode is GAP_SECURITY_MODE_2 or GAP_SECURITY_MODE_4
 * @return status ERROR_CODE_SUCCESS or ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE
 */
uint8_t gap_set_security_mode(gap_security_mode_t security_mode);

/**
 * @brief Get security mode
 * @return security_mode
 */
gap_security_mode_t gap_get_security_mode(void);

/**
 * @brief Set security level for all outgoing and incoming connections. Default: LEVEL_2
 * @param security_level
 * @note has to be called before services or profiles are initialized
 */
void gap_set_security_level(gap_security_level_t security_level);

/**
 * @brief Get security level
 * @return security_level
 */
gap_security_level_t gap_get_security_level(void);

/**
 * @brief Set Secure Connections Only Mode for BR/EDR (Classic) Default: false
 * @param enable
 */
void gap_set_secure_connections_only_mode(bool enable);

/**
 * @breif Get Secure Connections Only Mode
 * @param enabled
 */
bool gap_get_secure_connections_only_mode(void);

/**
 * @brief Set minimal security level for registered services
 * @param security_level
 * @note Called by L2CAP based on registered services
 */
void gap_set_minimal_service_security_level(gap_security_level_t security_level);

/**
 * @brief Register filter for rejecting classic connections. Callback will return 1 accept connection, 0 on reject.
 */
void gap_register_classic_connection_filter(int (*accept_callback)(bd_addr_t addr, hci_link_type_t link_type));

/* Configure Secure Simple Pairing */

/**
 * @brief Enable will enable SSP during init. Default: true
 */
void gap_ssp_set_enable(int enable);

/**
 * @brief Set IO Capability. BTstack will return capability to SSP requests
 */
void gap_ssp_set_io_capability(int ssp_io_capability);

/**
 * @brief Set Authentication Requirements using during SSP
 */
void gap_ssp_set_authentication_requirement(int authentication_requirement);

/**
 * @brief Enable/disable Secure Connections. Default: true if supported by Controller
 */
void gap_secure_connections_enable(bool enable);

/**
 * @brief Query if Secure Connections can be used for Classic connections.
 * @note Requires gap_secure_connections_enable == true and Controller to support it
 */
bool gap_secure_connections_active(void);

/**
 * @brief If set, BTstack will confirm a numeric comparison and enter '000000' if requested.
 */
void gap_ssp_set_auto_accept(int auto_accept);

/**
 * @brief Set required encryption key size for GAP Levels 1-3 on classic connections.
 * @note If you need to reduce the required encryption key size, please consider enabling
 *       ENABLE_MUTUAL_AUTHENTICATION_FOR_LEGACY_SECURE_CONNECTIONS to prevent BIAS attacks.
 *       However, the re-authentication for Legacy Secure Connections can cause a link loss
 *       in some Controller combinations.
 * @param encryption_key_size in bytes. Valid 7..16, default: 16
 */
void gap_set_required_encryption_key_size(uint8_t encryption_key_size);

/**
 * @brief Start dedicated bonding with device. Disconnect after bonding.
 * @param device
 * @param request MITM protection
 * @return error, if max num acl connections active
 * @result GAP_DEDICATED_BONDING_COMPLETE
 */
int gap_dedicated_bonding(bd_addr_t device, int mitm_protection_required);

gap_security_level_t gap_security_level_for_link_key_type(link_key_type_t link_key_type);

/**
 * @brief map link keys to secure connection yes/no
 */
bool gap_secure_connection_for_link_key_type(link_key_type_t link_key_type);

/**
 * @brief map link keys to authenticated
 */
bool gap_authenticated_for_link_key_type(link_key_type_t link_key_type);

gap_security_level_t gap_security_level(hci_con_handle_t con_handle);

void gap_request_security_level(hci_con_handle_t con_handle, gap_security_level_t level);

bool gap_mitm_protection_required_for_security_level(gap_security_level_t level);

/**
 * @brief Set Page Scan Type
 * @param page_scan_interval * 0.625 ms, range: 0x0012..0x1000, default: 0x0800
 * @param page_scan_windows  * 0.625 ms, range: 0x0011..page_scan_interval, default: 0x0012
 */
void gap_set_page_scan_activity(uint16_t page_scan_interval, uint16_t page_scan_window);

/**
 * @brief Set Page Scan Type
 * @param page_scan_mode
 */
void gap_set_page_scan_type(page_scan_type_t page_scan_type);

/**
 * @brief Set Page Timeout
 * @param page_timeout * 0.625 ms, range: 0x0001..0xffff, default: 0x6000 (ca 15 seconds)
 */
void gap_set_page_timeout(uint16_t page_timeout);

// LE

/**
 * @brief Set parameters for LE Scan
 * @param scan_type 0 = passive, 1 = active
 * @param scan_interval range 0x0004..0x4000, unit 0.625 ms
 * @param scan_window range 0x0004..0x4000, unit 0.625 ms
 * @param scanning_filter_policy 0 = all devices, 1 = all from whitelist
 */
void gap_set_scan_params(uint8_t scan_type, uint16_t scan_interval, uint16_t scan_window, uint8_t scanning_filter_policy);

/**
 * @brief Set parameters for LE Scan
 * @deprecated Use gap_set_scan_params instead
 */
void gap_set_scan_parameters(uint8_t scan_type, uint16_t scan_interval, uint16_t scan_window);

/**
 * @brief Set duplicate filter for LE Scan
 * @param enabled if enabled, only one advertisements per BD_ADDR is reported, default: false
 */
void gap_set_scan_duplicate_filter(bool enabled);

/**
 * @brief Set PHYs for LE Scan
 * @param phy bitmask: 1 = LE 1M PHY, 4 = LE Coded PHY
 */
void gap_set_scan_phys(uint8_t phys);

/**
 * @brief Start LE Scan 
 */
void gap_start_scan(void);

/**
 * @brief Stop LE Scan
 */
void gap_stop_scan(void);

/**
 * @brief Enable privacy by using random addresses
 * @param random_address_type to use (incl. OFF)
 */
void gap_random_address_set_mode(gap_random_address_type_t random_address_type);

/**
 * @brief Get privacy mode
 */
gap_random_address_type_t gap_random_address_get_mode(void);

/**
 * @brief Sets update period for random address
 * @param period_ms in ms
 */
 void gap_random_address_set_update_period(int period_ms);

/** 
 * @brief Sets a fixed random address for advertising
 * @param addr
 * @note Sets random address mode to type static
 */
void gap_random_address_set(const bd_addr_t addr);

/**
 * @brief Set Advertisement Data
 * @param advertising_data_length
 * @param advertising_data (max 31 octets)
 * @note data is not copied, pointer has to stay valid
 * @note '00:00:00:00:00:00' in advertising_data will be replaced with actual bd addr
 */
void gap_advertisements_set_data(uint8_t advertising_data_length, uint8_t * advertising_data);

/**
 * @brief Set Advertisement Parameters
 * @param adv_int_min
 * @param adv_int_max
 * @param adv_type
 * @param direct_address_type
 * @param direct_address
 * @param channel_map
 * @param filter_policy
 * @note own_address_type is used from gap_random_address_set_mode
 */
void gap_advertisements_set_params(uint16_t adv_int_min, uint16_t adv_int_max, uint8_t adv_type,
    uint8_t direct_address_typ, bd_addr_t direct_address, uint8_t channel_map, uint8_t filter_policy);

/** 
 * @brief Enable/Disable Advertisements. OFF by default.
 * @param enabled
 */
void gap_advertisements_enable(int enabled);

/** 
 * @brief Set Scan Response Data
 *
 * @note For scan response data, scannable undirected advertising (ADV_SCAN_IND) need to be used
 *
 * @param advertising_data_length
 * @param advertising_data (max 31 octets)
 * @note data is not copied, pointer has to stay valid
 * @note '00:00:00:00:00:00' in scan_response_data will be replaced with actual bd addr
 */
void gap_scan_response_set_data(uint8_t scan_response_data_length, uint8_t * scan_response_data);


/**
 * @brief Set update interval for resolvable private addresses generated by the Controller
 * @param update_s timeout for updates in seconds
 * @return status
 */
uint8_t gap_extended_advertising_set_resolvable_private_address_update(uint16_t update_s);

/**
 * @brief Provide storage for new advertising set and setup on Controller
 * @note Using RPA as own_address_type requires ENABLE_LE_ENHANCED_CONNECTION_COMPLETE_EVENT is required for pairing
 * @param storage to use by stack, needs to stay valid until adv set is removed with gap_extended_advertising_remove
 * @param advertising_parameters
 * @param out_advertising_handle to use with other adv config commands
 * @return status
 * @events: GAP_SUBEVENT_ADVERTISING_SET_INSTALLED
 */
uint8_t gap_extended_advertising_setup(le_advertising_set_t * storage, const le_extended_advertising_parameters_t * advertising_parameters, uint8_t * out_advertising_handle);

/**
 * @param Set advertising params for advertising set
 * @note Using RPA as own_address_type requires ENABLE_LE_ENHANCED_CONNECTION_COMPLETE_EVENT is required for pairing
 * @param advertising_handle
 * @param advertising_parameters
 * @return status
 */
uint8_t gap_extended_advertising_set_params(uint8_t advertising_handle, const le_extended_advertising_parameters_t * advertising_parameters);

/**
 * @param Get advertising params for advertising set, e.g. to update params
 * @param advertising_handle
 * @param advertising_parameters
 * @return status
 */
uint8_t gap_extended_advertising_get_params(uint8_t advertising_handle, le_extended_advertising_parameters_t * advertising_parameters);

/**
 * @param Set periodic advertising params for advertising set
 * @param advertising_handle
 * @param advertising_parameters
 * @return status
 */
uint8_t gap_periodic_advertising_set_params(uint8_t advertising_handle, const le_periodic_advertising_parameters_t * advertising_parameters);

/**
 * @param Get params for periodic advertising set, e.g. to update params
 * @param advertising_handle
 * @param advertising_parameters
 * @return status
 */
uint8_t gap_periodic_advertising_get_params(uint8_t advertising_handle, le_periodic_advertising_parameters_t * advertising_parameters);

/**
 * @param Set random addrress for advertising set
 * @param advertising_handle
 * @param random_address
 * @return status
 */
uint8_t gap_extended_advertising_set_random_address(uint8_t advertising_handle, bd_addr_t random_address);

/**
 * @brief Set Advertising Data for a advertisement set
 * @param advertising_handle
 * @param advertising_data_length
 * @param advertising_data
 * @return status
 */
uint8_t gap_extended_advertising_set_adv_data(uint8_t advertising_handle, uint16_t advertising_data_length, const uint8_t * advertising_data);

/**
 * @brief Set Scan Response Data for a advertisement set
 * @param advertising_handle
 * @param scan_response_data_length
 * @param scan_response_data
 * @return status
 */
uint8_t gap_extended_advertising_set_scan_response_data(uint8_t advertising_handle, uint16_t scan_response_data_length, const uint8_t * scan_response_data);

/**
 * @brief Set data for periodic advertisement set
 * @param advertising_handle
 * @param periodic_data_length
 * @param periodic_data
 * @return status
 */
uint8_t gap_periodic_advertising_set_data(uint8_t advertising_handle, uint16_t periodic_data_length, const uint8_t * periodic_data);

/**
 * @brief Start advertising advertising set
 * @param advertising_handle
 * @param timeout in 10ms, or 0 == no timeout
 * @param num_extended_advertising_events Controller shall send, or 0 == no max number
 * @return status
 */
uint8_t gap_extended_advertising_start(uint8_t advertising_handle, uint16_t timeout, uint8_t num_extended_advertising_events);

/**
 * @brief Stop advertising
 * @param advertising_handle
 * @return status
 */
uint8_t gap_extended_advertising_stop(uint8_t advertising_handle);

/**
 * @brief Start periodic advertising for given advertising set
 * @param advertising_handle
 * @param include_adi
 * @return status
 */
uint8_t gap_periodic_advertising_start(uint8_t advertising_handle, bool include_adi);

/**
 * @brief Stop periodic advertising for given advertising set
 * @param advertising_handle
 * @return status
 */
uint8_t gap_periodic_advertising_stop(uint8_t advertising_handle);

/**
 * @brief Set Default Periodic Advertising Sync Transfer Parameters
 * @note The parameters are used for all subsequent connections over the LE transport.
 *       If mode != 0, an HCI_LE_Periodic_Advertising_Sync_Transfer_Received event will be emitted by the Controller
 * @param mode 0 = ignore (default), 1 = periodic advertising events disabled
 *             2 = periodic advertising events enabled with duplicate filtering
 *             3 = periodic advertising events enabled with duplicate filtering
 * @param skip The number of periodic advertising packets that can be skipped after a successful receive
 * @param sync_timeout Range: 0x000A to 0x4000, Time = N*10 ms, Time Range: 100 ms to 163.84 s
 * @param cte_type  bit 0 = Do not sync to packets with an AoA Constant Tone Extension
 *                  bit 1 = Do not sync to packets with an AoD Constant Tone Extension with 1 μs slots
 *                  bit 2 = Do not sync to packets with an AoD Constant Tone Extension with 2 μs slots
 *                  bit 3 = Do not sync to packets without a Constant Tone Extension
 * @return status
 */
uint8_t gap_periodic_advertising_sync_transfer_set_default_parameters(uint8_t mode, uint16_t skip, uint16_t sync_timeout, uint8_t cte_type);

/**
 * @brief Send Periodic Advertising Sync Transfer to connected device
 * @param con_handle of connected device
 * @param service_data 16-bit data to transfer to remote host
 * @param sync_handle of synchronized periodic advertising train to transfer
 * @return status
 */
uint8_t gap_periodic_advertising_sync_transfer_send(hci_con_handle_t con_handle, uint16_t service_data, hci_con_handle_t sync_handle);

/**
 * @brief Send Periodic Advertising Set Info Transfer to connected device
 * @param con_handle of connected device
 * @param service_data 16-bit data to transfer to remote host
 * @param advertising_handle of local periodic advertising train to transfer
 * @return status
 */
uint8_t gap_periodic_advertising_set_info_transfer_send(hci_con_handle_t con_handle, uint16_t service_data, uint8_t advertising_handle);

/**
 * @brief Remove advertising set from Controller
 * @param advertising_handle
 * @return status
 * @events GAP_SUBEVENT_ADVERTISING_SET_REMOVED
 */
uint8_t gap_extended_advertising_remove(uint8_t advertising_handle);

/**
 * @brief Create Broadcast Isochronous Group (BIG)
 * @param storage to use by stack, needs to stay valid until adv set is removed with gap_big_terminate
 * @param big_params
 * @return status
 * @events GAP_SUBEVENT_BIG_CREATED unless interrupted by call to gap_big_terminate
 */
uint8_t gap_big_create(le_audio_big_t * storage, le_audio_big_params_t * big_params);

/**
 * @brief Terminate Broadcast Isochronous Group (BIG)
 * @param big_handle
 * @return status
 * @events GAP_SUBEVENT_BIG_TERMINATED
 */
uint8_t gap_big_terminate(uint8_t big_handle);

/**
 * @brief Synchronize to Broadcast Isochronous Group (BIG)
 * @param storage to use by stack, needs to stay valid until adv set is removed with gap_big_terminate
 * @param big_sync_params
 * @return status
 * @events GAP_SUBEVENT_BIG_SYNC_CREATED unless interrupted by call to gap_big_sync_terminate
 */
uint8_t gap_big_sync_create(le_audio_big_sync_t * storage, le_audio_big_sync_params_t * big_sync_params);

/**
 * @brief Stop synchronizing to Broadcast Isochronous Group (BIG). Triggers GAP_SUBEVENT_BIG_SYNC_STOPPED
 * @note Also used to stop synchronizing before BIG Sync was established
 * @param big_handle
 * @return status
 * @events GAP_SUBEVENT_BIG_SYNC_STOPPED
 */
uint8_t gap_big_sync_terminate(uint8_t big_handle);

/**
 * @brief Create Connected Isochronous Group (CIG)
 * @param storage to use by stack, needs to stay valid until CIG removed with gap_cig_remove
 * @param cig_params
 * @return status
 * @events GAP_SUBEVENT_CIG_CREATED unless interrupted by call to gap_cig_remove
 */
uint8_t gap_cig_create(le_audio_cig_t * storage, le_audio_cig_params_t * cig_params);

/**
 * @brief Remove Connected Isochronous Group (CIG)
 * @param cig_id
 * @return status
 * @events GAP_SUBEVENT_CIG_TERMINATED
 */
uint8_t gap_cig_remove(uint8_t cig_id);

/**
 * @brief Create Connected Isochronous Streams (CIS)
 * @note number of CIS from cig_params in gap_cig_create is used
 * @param cig_id
 * @param cis_con_handles array of CIS Connection Handles
 * @param acl_con_handles array of ACL Connection Handles
 * @return status
 * @events GAP_SUBEVENT_CIS_CREATED unless interrupted by call to gap_cig_remove
 */
uint8_t gap_cis_create(uint8_t cig_id, hci_con_handle_t cis_con_handles [], hci_con_handle_t acl_con_handles []);

/**
 * @brief Accept Connected Isochronous Stream (CIS)
 * @param cis_con_handle
 * @return status
 * @events GAP_SUBEVENT_CIS_CREATED
 */
uint8_t gap_cis_accept(hci_con_handle_t cis_con_handle);

/**
 * @brief Reject Connected Isochronous Stream (CIS)
 * @param cis_con_handle
 * @return status
 * @events GAP_SUBEVENT_CIS_CREATED
 */
uint8_t gap_cis_reject(hci_con_handle_t cis_con_handle);

/**
 * @brief Set connection parameters for outgoing connections and connection parameter updates
 * @param conn_scan_interval (unit: 0.625 msec), default: 60 ms
 * @param conn_scan_window (unit: 0.625 msec), default: 30 ms
 * @param conn_interval_min (unit: 1.25ms), default: 10 ms
 * @param conn_interval_max (unit: 1.25ms), default: 30 ms
 * @param conn_latency, default: 4
 * @param supervision_timeout (unit: 10ms), default: 720 ms
 * @param min_ce_length (unit: 0.625ms), default: 10 ms
 * @param max_ce_length (unit: 0.625ms), default: 30 ms
 */
void gap_set_connection_parameters(uint16_t conn_scan_interval, uint16_t conn_scan_window, 
    uint16_t conn_interval_min, uint16_t conn_interval_max, uint16_t conn_latency,
    uint16_t supervision_timeout, uint16_t min_ce_length, uint16_t max_ce_length);

/**
 * @brief Set initiating PHYs for outgoing connections
 * @param phy bitmask: 1 = LE 1M PHY, 2 = LE 2M PHY, 4 = LE Coded PHY
 */
void gap_set_connection_phys(uint8_t phys);

/**
 * @brief Request an update of the connection parameter for a given LE connection
 * @param handle
 * @param conn_interval_min (unit: 1.25ms)
 * @param conn_interval_max (unit: 1.25ms)
 * @param conn_latency
 * @param supervision_timeout (unit: 10ms)
 * @return 0 if ok
 */
int gap_request_connection_parameter_update(hci_con_handle_t con_handle, uint16_t conn_interval_min,
    uint16_t conn_interval_max, uint16_t conn_latency, uint16_t supervision_timeout);

/**
 * @brief Updates the connection parameters for a given LE connection
 * @param handle
 * @param conn_interval_min (unit: 1.25ms)
 * @param conn_interval_max (unit: 1.25ms)
 * @param conn_latency
 * @param supervision_timeout (unit: 10ms)
 * @return 0 if ok
 */
int gap_update_connection_parameters(hci_con_handle_t con_handle, uint16_t conn_interval_min,
    uint16_t conn_interval_max, uint16_t conn_latency, uint16_t supervision_timeout);

/**
 * @brief Set accepted connection parameter range
 * @param range
 */
void gap_get_connection_parameter_range(le_connection_parameter_range_t * range);

/**
 * @brief Get accepted connection parameter range
 * @param range
 */
void gap_set_connection_parameter_range(le_connection_parameter_range_t * range);

/**
 * @brief Test if connection parameters are inside in existing rage
 * @param conn_interval_min (unit: 1.25ms)
 * @param conn_interval_max (unit: 1.25ms)
 * @param conn_latency
 * @param supervision_timeout (unit: 10ms)
 * @return 1 if included
 */
int gap_connection_parameter_range_included(le_connection_parameter_range_t * existing_range, uint16_t le_conn_interval_min, uint16_t le_conn_interval_max, uint16_t le_conn_latency, uint16_t le_supervision_timeout);

/**
 * @brief Set max number of connections in LE Peripheral role (if Bluetooth Controller supports it)
 * @note: default: 1
 * @param max_peripheral_connections
 */
void gap_set_max_number_peripheral_connections(int max_peripheral_connections);

/**
 * @brief Add Device to Whitelist
 * @param address_typ
 * @param address
 * @return status
 */
uint8_t gap_whitelist_add(bd_addr_type_t address_type, const bd_addr_t address);

/**
 * @brief Remove Device from Whitelist
 * @param address_typ
 * @param address
 * @return status
 */
uint8_t gap_whitelist_remove(bd_addr_type_t address_type, const bd_addr_t address);

/**
 * @brief Clear Whitelist
 * @return status
 */
uint8_t gap_whitelist_clear(void);

/**
 * @brief Connect to remote LE device
 * @return status
 */
uint8_t gap_connect(const bd_addr_t addr, bd_addr_type_t addr_type);

/**
 * @brief Connect with Whitelist
 * @note Explicit whitelist management and this connect with whitelist replace deprecated gap_auto_connection_* functions
 * @return status
 */
uint8_t gap_connect_with_whitelist(void);

/**
 * @brief Cancel connection process initiated by gap_connect
 * @return status
 */
uint8_t gap_connect_cancel(void);

/**
 * @brief Auto Connection Establishment - Start Connecting to device
 * @deprecated Please setup Whitelist with gap_whitelist_* and start connecting with gap_connect_with_whitelist
 * @param address_type
 * @param address
 * @return status
 */
uint8_t gap_auto_connection_start(bd_addr_type_t address_type, const bd_addr_t address);

/**
 * @brief Auto Connection Establishment - Stop Connecting to device
 * @deprecated Please setup Whitelist with gap_whitelist_* and start connecting with gap_connect_with_whitelist
 * @param address_type
 * @param address
 * @return status
 */
uint8_t gap_auto_connection_stop(bd_addr_type_t address_type, const bd_addr_t address);

/**
 * @brief Auto Connection Establishment - Stop everything
 * @deprecated Please setup Whitelist with gap_whitelist_* and start connecting with gap_connect_with_whitelist
 * @note  Convenience function to stop all active auto connection attempts
 * @return status
 */
uint8_t gap_auto_connection_stop_all(void);

/**
 * @brief Set LE PHY
 * @param con_handle
 * @param all_phys 0 = set rx/tx, 1 = set only rx, 2 = set only tx
 * @param tx_phys 1 = 1M, 2 = 2M, 4 = Coded
 * @param rx_phys 1 = 1M, 2 = 2M, 4 = Coded
 * @param phy_options 0 = no preferred coding for Coded, 1 = S=2 coding (500 kbit), 2 = S=8 coding (125 kbit)
 * @return status
 */
uint8_t gap_le_set_phy(hci_con_handle_t con_handle, uint8_t all_phys, uint8_t tx_phys, uint8_t rx_phys, uint16_t phy_options);

/**
 * @brief Get connection interval
 * @param con_handle
 * @return connection interval, otherwise 0 if error 
 */
uint16_t gap_le_connection_interval(hci_con_handle_t con_handle);

/**
 *
 * @brief Get encryption key size.
 * @param con_handle
 * @return 0 if not encrypted, 7-16 otherwise
 */
uint8_t gap_encryption_key_size(hci_con_handle_t con_handle);

/**
 * @brief Get authentication property.
 * @param con_handle
 * @return true if bonded with OOB/Passkey (AND MITM protection)
 */
bool gap_authenticated(hci_con_handle_t con_handle);

/**
 * @brief Get secure connection property
 * @param con_handle
 * @return true if bonded usiung LE Secure Connections
 */
bool gap_secure_connection(hci_con_handle_t con_handle);

/**
 * @brief Queries authorization state.
 * @param con_handle
 * @return authorization_state for the current session
 */
authorization_state_t gap_authorization_state(hci_con_handle_t con_handle);

/**
 * @brief Get bonded property (BR/EDR/LE)
 * @note LE: has to be called after identity resolving is complete
 * @param con_handle
 * @return true if bonded
 */
bool gap_bonded(hci_con_handle_t con_handle);

// Classic
#ifdef ENABLE_CLASSIC

/**
 * @brief Override page scan mode. Page scan mode enabled by l2cap when services are registered
 * @note Might be used to reduce power consumption while Bluetooth module stays powered but no (new)
 *       connections are expected
 */
void gap_connectable_control(uint8_t enable);

/**
 * @brief Allows to control if device is discoverable. OFF by default.
 */
void gap_discoverable_control(uint8_t enable);

/**
 * @brief Deletes link key for remote device with baseband address.
 * @param addr
 * @note On most desktop ports, the Link Key DB uses a TLV and there is one TLV storage per
 *       Controller resp. its Bluetooth Address. As the Bluetooth Address is retrieved during
 *       power up, this function only works, when the stack is in working state for these ports.
 */
void gap_drop_link_key_for_bd_addr(bd_addr_t addr);

/**
 * @brief Delete all stored link keys
 * @note On most desktop ports, the Link Key DB uses a TLV and there is one TLV storage per
 *       Controller resp. its Bluetooth Address. As the Bluetooth Address is retrieved during
 *       power up, this function only works, when the stack is in working state for these ports.
 */
void gap_delete_all_link_keys(void);

/** 
 * @brief Store link key for remote device with baseband address
 * @param addr
 * @param link_key
 * @param link_key_type
 * @note On most desktop ports, the Link Key DB uses a TLV and there is one TLV storage per
 *       Controller resp. its Bluetooth Address. As the Bluetooth Address is retrieved during
 *       power up, this function only works, when the stack is in working state for these ports.
 */
void gap_store_link_key_for_bd_addr(bd_addr_t addr, link_key_t link_key, link_key_type_t type);

/**
 * @brief Get link for remote device with basband address
 * @param addr
 * @param link_key (out) is stored here
 * @param link_key_type (out) is stored here
 * @note On most desktop ports, the Link Key DB uses a TLV and there is one TLV storage per
 *       Controller resp. its Bluetooth Address. As the Bluetooth Address is retrieved during
 *       power up, this function only works, when the stack is in working state for these ports.
 */
bool gap_get_link_key_for_bd_addr(bd_addr_t addr, link_key_t link_key, link_key_type_t * type);

/**
 * @brief Setup Link Key iterator
 * @param it
 * @return 1 on success
 * @note On most desktop ports, the Link Key DB uses a TLV and there is one TLV storage per
 *       Controller resp. its Bluetooth Address. As the Bluetooth Address is retrieved during
 *       power up, this function only works, when the stack is in working state for these ports.
 */
int gap_link_key_iterator_init(btstack_link_key_iterator_t * it);

/**
 * @brief Get next Link Key
 * @param it
 * @brief addr
 * @brief link_key
 * @brief type of link key
 * @return 1, if valid link key found
 * @see note on gap_link_key_iterator_init
 */
int gap_link_key_iterator_get_next(btstack_link_key_iterator_t * it, bd_addr_t bd_addr, link_key_t link_key, link_key_type_t * type);

/**
 * @brief Frees resources allocated by iterator_init
 * @note Must be called after iteration to free resources
 * @param it
 * @see note on gap_link_key_iterator_init
 */
void gap_link_key_iterator_done(btstack_link_key_iterator_t * it);

/**
 * @brief Start GAP Classic Inquiry
 * @param duration in 1.28s units
 * @return status
 * @events: GAP_EVENT_INQUIRY_RESULT, GAP_EVENT_INQUIRY_COMPLETE
 */
int gap_inquiry_start(uint8_t duration_in_1280ms_units);

/**
 * @brief Start GAP Classic Periodic Inquiry
 * @param duration in 1.28s units
 * @param max_period_length between consecutive inquiries in 1.28s units
 * @param min_period_length between consecutive inquiries in 1.28s units
 * @return status
 * @events: GAP_EVENT_INQUIRY_RESULT, GAP_EVENT_INQUIRY_COMPLETE
 */
uint8_t gap_inquiry_periodic_start(uint8_t duration, uint16_t max_period_length, uint16_t min_period_length);

/**
 * @brief Stop GAP Classic Inquiry (regular or periodic)
 * @return 0 if ok
 * @events GAP_EVENT_INQUIRY_COMPLETE
 */
int gap_inquiry_stop(void);

/**
 * @brief Set LAP for GAP Classic Inquiry
 * @param lap GAP_IAC_GENERAL_INQUIRY (default), GAP_IAC_LIMITED_INQUIRY
 */
void gap_inquiry_set_lap(uint32_t lap);

/**
 * @brief Set Inquiry Scan Activity
 * @param inquiry_scan_interval range: 0x0012 to 0x1000; only even values are valid, Time = N * 0.625 ms
 * @param inquiry_scan_window range: 0x0011 to 0x1000; Time = N * 0.625 ms
 */
void gap_inquiry_set_scan_activity(uint16_t inquiry_scan_interval, uint16_t inquiry_scan_window);

/**
 * @brief Set Inquiry Transmit Power Level
 * @param tx_power range: -70 to 20 dBm
 */
void gap_inquiry_set_transmit_power_level(int8_t tx_power);

/**
 * @brief Remote Name Request
 * @param addr
 * @param page_scan_repetition_mode
 * @param clock_offset only used when bit 15 is set - pass 0 if not known
 * @events HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE
 */
int gap_remote_name_request(const bd_addr_t addr, uint8_t page_scan_repetition_mode, uint16_t clock_offset);

/**
 * @brief Legacy Pairing Pin Code Response
 * @note data is not copied, pointer has to stay valid
 * @param addr
 * @param pin
 * @return 0 if ok
 */
int gap_pin_code_response(const bd_addr_t addr, const char * pin);

/**
 * @brief Legacy Pairing Pin Code Response for binary data / non-strings
 * @note data is not copied, pointer has to stay valid
 * @param addr
 * @param pin_data
 * @param pin_len
 * @return 0 if ok
 */
int gap_pin_code_response_binary(const bd_addr_t addr, const uint8_t * pin_data, uint8_t pin_len);

/**
 * @brief Abort Legacy Pairing
 * @param addr
 * @param pin
 * @return 0 if ok
 */
int gap_pin_code_negative(bd_addr_t addr);

/**
 * @brief SSP Passkey Response
 * @param addr
 * @param passkey [0..999999]
 * @return 0 if ok
 */
int gap_ssp_passkey_response(const bd_addr_t addr, uint32_t passkey);

/**
 * @brief Abort SSP Passkey Entry/Pairing
 * @param addr
 * @param pin
 * @return 0 if ok
 */
int gap_ssp_passkey_negative(const bd_addr_t addr);

/**
 * @brief Accept SSP Numeric Comparison
 * @param addr
 * @param passkey
 * @return 0 if ok
 */
int gap_ssp_confirmation_response(const bd_addr_t addr);

/**
 * @brief Abort SSP Numeric Comparison/Pairing
 * @param addr
 * @param pin
 * @return 0 if ok
 */
int gap_ssp_confirmation_negative(const bd_addr_t addr);

/**
 * @brief Generate new OOB data
 * @note OOB data will be provided in GAP_EVENT_LOCAL_OOB_DATA and be used in future pairing procedures
 */
void gap_ssp_generate_oob_data(void);

/**
 * @brief Report Remote OOB Data
 * @note Pairing Hash and Randomizer are expected in big-endian byte format
 * @param bd_addr
 * @param c_192 Simple Pairing Hash C derived from P-192 public key
 * @param r_192 Simple Pairing Randomizer derived from P-192 public key
 * @param c_256 Simple Pairing Hash C derived from P-256 public key
 * @param r_256 Simple Pairing Randomizer derived from P-256 public key
 * @return status
 */
uint8_t gap_ssp_remote_oob_data(const bd_addr_t addr, const uint8_t * c_192, const uint8_t * r_192, const uint8_t * c_256, const uint8_t * r_256);

/**
 * Send SSP IO Capabilities Reply
 * @note IO Capabilities (Negative) Reply is sent automatically unless ENABLE_EXPLICIT_IO_CAPABILITIES_REPLY
 * @param addr
 * @return status
 */
uint8_t gap_ssp_io_capabilities_response(const bd_addr_t addr);

/**
 * Send SSP IO Capabilities Negative Reply
 * @note IO Capabilities (Negative) Reply is sent automatically unless ENABLE_EXPLICIT_IO_CAPABILITIES_REPLY
 * @param addr
 * @return status
 */
uint8_t gap_ssp_io_capabilities_negative(const bd_addr_t addr);

/**
 * Send Link Key Reponse
 * @note Link Key (Negative) Reply is sent automatically unless ENABLE_EXPLICIT_LINK_KEY_RESPONSE
 * @param addr
 * @param link_key
 * @param type or INVALID_LINK_KEY if link key not available
 * @return status
 */
 uint8_t gap_send_link_key_response(const bd_addr_t addr, link_key_t link_key, link_key_type_t type);

/**
 * @brief Enter Sniff mode
 * @param con_handle
 * @param sniff_min_interval range: 0x0002 to 0xFFFE; only even values are valid, Time = N * 0.625 ms
 * @param sniff_max_interval range: 0x0002 to 0xFFFE; only even values are valid, Time = N * 0.625 ms
 * @param sniff_attempt Number of Baseband receive slots for sniff attempt.
 * @param sniff_timeout Number of Baseband receive slots for sniff timeout.
 * @return status
 */
uint8_t gap_sniff_mode_enter(hci_con_handle_t con_handle, uint16_t sniff_min_interval, uint16_t sniff_max_interval, uint16_t sniff_attempt, uint16_t sniff_timeout);

/**
 * @brief Exit Sniff mode
 * @param con_handle
 * @return status
 */
uint8_t gap_sniff_mode_exit(hci_con_handle_t con_handle);

/**
 * @brief Configure Sniff Subrating
 * @param con_handle
 * @param max_latency range: 0x0002 to 0xFFFE; Time = N * 0.625 ms
 * @param min_remote_timeout range:  0x0002 to 0xFFFE; Time = N * 0.625 ms
 * @param min_local_timeout range:  0x0002 to 0xFFFE; Time = N * 0.625 ms
 * @return status
 */
uint8_t gap_sniff_subrating_configure(hci_con_handle_t con_handle, uint16_t max_latency, uint16_t min_remote_timeout, uint16_t min_local_timeout);

/**
 * @Brief Set QoS
 * @param con_handle
 * @param service_type
 * @param token_rate
 * @param peak_bandwidth
 * @param latency
 * @param delay_variation
 * @return status
 */
uint8_t gap_qos_set(hci_con_handle_t con_handle, hci_service_type_t service_type, uint32_t token_rate, uint32_t peak_bandwidth, uint32_t latency, uint32_t delay_variation);

#endif

// LE

/**
 * @brief Get own addr type and address used for LE for next scan/advertisement/connect operation
 */
void gap_le_get_own_address(uint8_t * addr_type, bd_addr_t addr);

/**
 * @brief Get own addr type and address used for LE advertisements (Peripheral)
 */
void gap_le_get_own_advertisements_address(uint8_t * addr_type, bd_addr_t addr);

/**
 * @brief Get own addr type and address used for LE Extended Advertisiing (Peripheral)
 */
void gap_le_get_own_advertising_set_address(uint8_t * addr_type, bd_addr_t addr, uint8_t advertising_handle);

/**
 * @brief Get own addr type and address used for LE connections (Central)
 */
void gap_le_get_own_connection_address(uint8_t * addr_type, bd_addr_t addr);

/**
 * @brief Get state of connection re-encryption for bonded devices when in central role
 * @note used by gatt_client and att_server to wait for re-encryption
 * @param con_handle
 * @return 1 if security setup is active
 */
bool gap_reconnect_security_setup_active(hci_con_handle_t con_handle);

/**
 * @brief Delete bonding information for remote device
 * @note On most desktop ports, the LE Device DB uses a TLV and there is one TLV storage per
 *       Controller resp. its Bluetooth Address. As the Bluetooth Address is retrieved during
 *       power up, this function only works, when the stack is in working state for these ports.
 * @param address_type
 * @param address
 */
void gap_delete_bonding(bd_addr_type_t address_type, bd_addr_t address);

/**
 * LE Privacy 1.2 - requires support by Controller and ENABLE_LE_RESOLVING_LIST to be defined
 */

/**
 * Set Privacy Mode for use in Resolving List. Default: LE_PRIVACY_MODE_DEVICE
 * @note Only applies for new devices added to resolving list, please call before startup
 * @param privacy_mode
 */
void gap_set_peer_privacy_mode(le_privacy_mode_t privacy_mode );

/**
 * @brief Load LE Device DB entries into Controller Resolving List to allow filtering on
 *        bonded devies with resolvable private addresses
 * @return EROOR_CODE_SUCCESS if supported by Controller
 */
uint8_t gap_load_resolving_list_from_le_device_db(void);

typedef enum {
    GAP_PRIVACY_CLIENT_STATE_IDLE,
    GAP_PRIVACY_CLIENT_STATE_PENDING,
    GAP_PRIVACY_CLIENT_STATE_READY
} gap_privacy_client_state_t;

struct gap_privacy_client {
    btstack_linked_item_t * next;
    void (*callback)(struct gap_privacy_client * client, bd_addr_t random_addr);
    gap_privacy_client_state_t state;
};
typedef struct gap_privacy_client gap_privacy_client_t;

/**
 * @brief Register callback that gets executed during random address update
 * @note gap_privacy_client_ready needs to be called after callback is received
 * @param client
 * @return status
 */
void gap_privacy_client_register(gap_privacy_client_t * client);

/**
 * @brief Acknowledge upcoming random address change
 * @param client
 * @return status
 */
void gap_privacy_client_ready(gap_privacy_client_t * client);

/**
 * @brief Unregister callback from random address updates
 * @param client
 * @return status
 */
void gap_privacy_client_unregister(gap_privacy_client_t * client);

/**
 * @brief Get local persistent IRK
 */
const uint8_t * gap_get_persistent_irk(void);

Host Controler Interface (HCI) API {#sec:hci_api}

hci.h

// HCI init and configuration


/**
 * @brief Set up HCI. Needs to be called before any other function.
 */
void hci_init(const hci_transport_t *transport, const void *config);

/**
 * @brief Configure Bluetooth chipset driver. Has to be called before power on, or right after receiving the local version information.
 */
void hci_set_chipset(const btstack_chipset_t *chipset_driver);

/**
 * @brief Enable custom init for chipset driver to send HCI commands before HCI Reset
 */
void hci_enable_custom_pre_init(void);

/**
 * @brief Configure Bluetooth hardware control. Has to be called before power on.
 * @[aram hardware_control implementation
 */
void hci_set_control(const btstack_control_t *hardware_control);

#ifdef HAVE_SCO_TRANSPORT
/**
 * @brief Set SCO Transport implementation for SCO over PCM mode
 * @param sco_transport that sends SCO over I2S or PCM interface
 */
void hci_set_sco_transport(const btstack_sco_transport_t *sco_transport);
#endif

#ifdef ENABLE_CLASSIC
/**
 * @brief Configure Bluetooth hardware control. Has to be called before power on.
 */
void hci_set_link_key_db(btstack_link_key_db_t const * link_key_db);
#endif

/**
 * @brief Set callback for Bluetooth Hardware Error
 */
void hci_set_hardware_error_callback(void (*fn)(uint8_t error));

/**
 * @brief Set Public BD ADDR - passed on to Bluetooth chipset during init if supported in bt_control_h
 */
void hci_set_bd_addr(bd_addr_t addr);

/**
 * @brief Configure Voice Setting for use with SCO data in HSP/HFP
 */
void hci_set_sco_voice_setting(uint16_t voice_setting);

/**
 * @brief Get SCO Voice Setting
 * @return current voice setting
 */
uint16_t hci_get_sco_voice_setting(void);

/**
 * @brief Set number of ISO packets to buffer for BIS/CIS
 * @param num_packets (default = 1)
 */
void hci_set_num_iso_packets_to_queue(uint8_t num_packets);

/**
 * @brief Set inquiry mode: standard, with RSSI, with RSSI + Extended Inquiry Results. Has to be called before power on.
 * @param inquriy_mode see bluetooth_defines.h
 */
void hci_set_inquiry_mode(inquiry_mode_t inquriy_mode);

/**
 * @brief Requests the change of BTstack power mode.
 * @param power_mode
 * @return 0 if success, otherwise error
 */
int  hci_power_control(HCI_POWER_MODE power_mode);

/**
 * @brief Shutdown HCI
 */
void hci_close(void);


// Callback registration


/**
 * @brief Add event packet handler. 
 */
void hci_add_event_handler(btstack_packet_callback_registration_t * callback_handler);

/**
 * @brief Remove event packet handler.
 */
void hci_remove_event_handler(btstack_packet_callback_registration_t * callback_handler);

/**
 * @brief Registers a packet handler for ACL data. Used by L2CAP
 */
void hci_register_acl_packet_handler(btstack_packet_handler_t handler);

/**
 * @brief Registers a packet handler for SCO data. Used for HSP and HFP profiles.
 */
void hci_register_sco_packet_handler(btstack_packet_handler_t handler);

/**
 * @brief Registers a packet handler for ISO data. Used for LE Audio profiles
 */
void hci_register_iso_packet_handler(btstack_packet_handler_t handler);

// Sending HCI Commands

/** 
 * @brief Check if CMD packet can be sent to controller
 * @return true if command can be sent
 */
bool hci_can_send_command_packet_now(void);

/**
 * @brief Creates and sends HCI command packets based on a template and a list of parameters. Will return error if outgoing data buffer is occupied.
 * @return status
 */
uint8_t hci_send_cmd(const hci_cmd_t * cmd, ...);


// Sending SCO Packets

/** @brief Get SCO payload length for existing SCO connection and current SCO Voice setting
 *  @note  Using SCO packets of the exact length is required for USB transfer in general and some H4 controllers as well
 *  @param sco_con_handle
 *  @return Length of SCO payload in bytes (not audio frames) incl. 3 byte header
 */
uint16_t hci_get_sco_packet_length_for_connection(hci_con_handle_t sco_con_handle);

/** @brief Get SCO packet length for one of the existing SCO connections and current SCO Voice setting
 *  @deprecated Please use hci_get_sco_packet_length_for_connection instead
 *  @note  Using SCO packets of the exact length is required for USB transfer
 *  @return Length of SCO packets in bytes (not audio frames) incl. 3 byte header
 */
uint16_t hci_get_sco_packet_length(void);

/**
 * @brief Request emission of HCI_EVENT_SCO_CAN_SEND_NOW as soon as possible
 * @note HCI_EVENT_SCO_CAN_SEND_NOW might be emitted during call to this function
 *       so packet handler should be ready to handle it
 */
void hci_request_sco_can_send_now_event(void);

/**
 * @brief Check HCI packet buffer and if SCO packet can be sent to controller
 * @return true if sco packet can be sent
 */
bool hci_can_send_sco_packet_now(void);

/**
 * @brief Check if SCO packet can be sent to controller
 * @return true if sco packet can be sent
 */
bool hci_can_send_prepared_sco_packet_now(void);

/**
 * @brief Send SCO packet prepared in HCI packet buffer
 */
uint8_t hci_send_sco_packet_buffer(int size);

/**
 * @brief Request emission of HCI_EVENT_BIS_CAN_SEND_NOW for all BIS as soon as possible
 * @param big_handle
 * @note HCI_EVENT_ISO_CAN_SEND_NOW might be emitted during call to this function
 *       so packet handler should be ready to handle it
 */
uint8_t hci_request_bis_can_send_now_events(uint8_t big_handle);

/**
 * @brief Request emission of HCI_EVENT_CIS_CAN_SEND_NOW for CIS as soon as possible
 * @param cis_con_handle
 * @note HCI_EVENT_CIS_CAN_SEND_NOW might be emitted during call to this function
 *       so packet handler should be ready to handle it
 */
uint8_t hci_request_cis_can_send_now_events(hci_con_handle_t cis_con_handle);

/**
 * @brief Send ISO packet prepared in HCI packet buffer
 */
uint8_t hci_send_iso_packet_buffer(uint16_t size);

/**
 * Reserves outgoing packet buffer.
 * @note Must only be called after a 'can send now' check or event
 * @note Asserts if packet buffer is already reserved
 */
void hci_reserve_packet_buffer(void);

/**
 * Get pointer for outgoing packet buffer
 */
uint8_t* hci_get_outgoing_packet_buffer(void);

/**
 * Release outgoing packet buffer\
 * @note only called instead of hci_send_prepared
 */
void hci_release_packet_buffer(void);

/**
* @brief Sets the master/slave policy
* @param policy (0: attempt to become master, 1: let connecting device decide)
*/
void hci_set_master_slave_policy(uint8_t policy);

/**
 * @brief Check if Controller supports BR/EDR (Bluetooth Classic)
 * @return true if supported
 * @note only valid in working state
 */
bool hci_classic_supported(void);

/**
 * @brief Check if Controller supports LE (Bluetooth Low Energy)
 * @return true if supported
 * @note only valid in working state
 */
bool hci_le_supported(void);

/**
 * @brief Check if LE Extended Advertising is supported
 * @return true if supported
 */
bool hci_le_extended_advertising_supported(void);

/** @brief Check if address type corresponds to LE connection
 *  @bparam address_type
 *  @erturn true if LE connection
 */
bool hci_is_le_connection_type(bd_addr_type_t address_type);

/** @brief Check if address type corresponds to Identity Address
 *  @bparam address_type
 *  @erturn true if LE connection
 */
bool hci_is_le_identity_address_type(bd_addr_type_t address_type);

HCI Logging API {#sec:hci_dump_api}

hci_dump.h : Dump HCI trace as BlueZ's hcidump format, Apple's PacketLogger, or stdout.

typedef enum {
    HCI_DUMP_INVALID = 0,
    HCI_DUMP_BLUEZ,
    HCI_DUMP_PACKETLOGGER,
    HCI_DUMP_BTSNOOP,
} hci_dump_format_t;

typedef struct {
    // reset output, called if max packets is reached, to limit file size
    void (*reset)(void);
    // log packet
    void (*log_packet)(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len);
    // log message
    void (*log_message)(int log_level, const char * format, va_list argptr);
#ifdef __AVR__ \
    // log message - AVR
    void (*log_message_P)(int log_level, PGM_P * format, va_list argptr);
#endif
} hci_dump_t;

/**
 * @brief Init HCI Dump
 * @param hci_dump_impl - platform-specific implementation
 */
void hci_dump_init(const hci_dump_t * hci_dump_impl);

/**
 * @brief Enable packet logging
 * @param enabled default: true
 */
void hci_dump_enable_packet_log(bool enabled);

/**
 * @brief
 */
void hci_dump_enable_log_level(int log_level, int enable);

/*
 * @brief Set max number of packets - output file might be truncated
 */
void hci_dump_set_max_packets(int packets); // -1 for unlimited

/**
 * @brief Dump Packet
 * @param packet_type
 * @param in is 1 for incoming, 0 for outoing
 * @param packet
 * @param len
 */
void hci_dump_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len);

/**
 * @brief Dump Message
 * @param log_level
 * @param format
 */
void hci_dump_log(int log_level, const char * format, ...)
#ifdef __GNUC__
__attribute__ ((format (__printf__, 2, 3)))
#endif
;

#ifdef __AVR__
/*
 * @brief Dump Message using format string stored in PGM memory (allows to save RAM)
 * @param log_level
 * @param format
 */
void hci_dump_log_P(int log_level, PGM_P format, ...)
#ifdef __GNUC__
__attribute__ ((format (__printf__, 2, 3)))
#endif
;
#endif

/**
 * @brief Dump internal BTstack event
 * @note only logged if ENABLE_LOG_BTSTACK_EVENTS is defined
 * @param packet
 * @param len
 */
void hci_dump_btstack_event(const uint8_t *packet, uint16_t len);

/**
 * @brief Setup header for PacketLogger format
 * @param buffer
 * @param tv_sec
 * @param tv_us
 * @param packet_type
 * @param in
 * @param len
 */
void hci_dump_setup_header_packetlogger(uint8_t * buffer, uint32_t tv_sec, uint32_t tv_us, uint8_t packet_type, uint8_t in, uint16_t len);

/**
 * @brief Setup header for BLUEZ (hcidump) format
 * @param buffer
 * @param tv_sec
 * @param tv_us
 * @param packet_type
 * @param in
 * @param len
 */
void hci_dump_setup_header_bluez(uint8_t * buffer, uint32_t tv_sec, uint32_t tv_us, uint8_t packet_type, uint8_t in, uint16_t len);

/**
 * @brief Setup header for BT Snoop format
 * @param buffer
 * @param ts_usec_high upper 32-bit of 64-bit microsecond timestamp
 * @param ts_usec_low  lower 2-bit of 64-bit microsecond timestamp
 * @param cumulative_drops since last packet was recorded
 * @param packet_type
 * @param in
 * @param len
 */
void hci_dump_setup_header_btsnoop(uint8_t * buffer, uint32_t ts_usec_high, uint32_t ts_usec_low, uint32_t cumulative_drops, uint8_t packet_type, uint8_t in, uint16_t len);

HCI Transport API {#sec:hci_transport_api}

hci_transport.h : The API allows BTstack to use different transport interfaces.

/* HCI packet types */
typedef struct {
    /**
     * transport name 
     */
    const char * name;

    /**
     * init transport
     * @param transport_config
     */
    void   (*init) (const void *transport_config);

    /**
     * open transport connection
     */
    int    (*open)(void);

    /**
     * close transport connection
     */
    int    (*close)(void);

    /**
     * register packet handler for HCI packets: ACL, SCO, and Events
     */
    void   (*register_packet_handler)(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size));

    /**
     * support async transport layers, e.g. IRQ driven without buffers
     */
    int    (*can_send_packet_now)(uint8_t packet_type);

    /**
     * send packet
     */
    int    (*send_packet)(uint8_t packet_type, uint8_t *packet, int size);

    /**
     * extension for UART transport implementations
     */
    int    (*set_baudrate)(uint32_t baudrate);

    /**
     * extension for UART H5 on CSR: reset BCSP/H5 Link
     */
    void   (*reset_link)(void);

    /**
     * extension for USB transport implementations: config SCO connections
     */
    void   (*set_sco_config)(uint16_t voice_setting, int num_connections);

} hci_transport_t;

typedef enum {
    HCI_TRANSPORT_CONFIG_UART,
    HCI_TRANSPORT_CONFIG_USB
} hci_transport_config_type_t;

typedef struct {
    hci_transport_config_type_t type;
} hci_transport_config_t;

typedef struct {
    hci_transport_config_type_t type; // == HCI_TRANSPORT_CONFIG_UART
    uint32_t   baudrate_init; // initial baud rate
    uint32_t   baudrate_main; // = 0: same as initial baudrate
    int        flowcontrol;   // 
    const char *device_name;
    int        parity;        // see btstack_uart.h BTSTACK_UART_PARITY
} hci_transport_config_uart_t;

HCI Transport EM9304 API API {#sec:hci_transport_em9304_spi_api}

hci_transport_em9304_spi.h : The EM9304 uses an extended SPI interface and this HCI Transport is based on the the btstack_em9304.h interface.

/*
 * @brief Setup H4 over SPI instance for EM9304 with em9304_spi_driver
 * @param em9304_spi_driver to use
 */
const hci_transport_t * hci_transport_em9304_spi_instance(const btstack_em9304_spi_t * em9304_spi_driver);

HCI Transport H4 API {#sec:hci_transport_h4_api}

hci_transport_h4.h

/*
 * @brief Setup H4 instance with btstack_uart implementation
 * @param btstack_uart_block_driver to use
 */
const hci_transport_t * hci_transport_h4_instance_for_uart(const btstack_uart_t * uart_driver);

/*
 * @brief Setup H4 instance with btstack_uart_block implementation
 * @param btstack_uart_block_driver to use
 * @deprecated use hci_transport_h4_instance_for_uart instead
 */
const hci_transport_t * hci_transport_h4_instance(const btstack_uart_block_t * uart_driver);

HCI Transport H5 API {#sec:hci_transport_h5_api}

hci_transport_h5.h

/*
 * @brief Setup H5 instance with btstack_uart implementation that supports SLIP frames
 * @param uart_driver to use
 */
const hci_transport_t * hci_transport_h5_instance(const btstack_uart_t * uart_driver);

/*
 * @brief Enable H5 Low Power Mode: enter sleep mode after x ms of inactivity
 * @param inactivity_timeout_ms or 0 for off
 */
void hci_transport_h5_set_auto_sleep(uint16_t inactivity_timeout_ms);

/*
 * @brief Enable BSCP mode H5, by enabling event parity
 * @deprecated Parity can be enabled in UART driver configuration
 */
void hci_transport_h5_enable_bcsp_mode(void);

HCI Transport USB API {#sec:hci_transport_usb_api}

hci_transport_usb.h

/*
 * @brief
 */
const hci_transport_t * hci_transport_usb_instance(void);

/**
 * @brief Specify USB Bluetooth device via port numbers from root to device
 */
void hci_transport_usb_set_path(int len, uint8_t * port_numbers);

/**
 * @brief Add device to list of known Bluetooth USB Controller
 * @param vendor_id
 * @param product_id
 */
void hci_transport_usb_add_device(uint16_t vendor_id, uint16_t product_id);

L2CAP API {#sec:l2cap_api}

l2cap.h : Logical Link Control and Adaption Protocol

//
// PSM numbers from https://www.bluetooth.com/specifications/assigned-numbers/logical-link-control 
//
#define PSM_SDP           BLUETOOTH_PROTOCOL_SDP
#define PSM_RFCOMM        BLUETOOTH_PROTOCOL_RFCOMM
#define PSM_BNEP          BLUETOOTH_PROTOCOL_BNEP
// @TODO: scrape PSMs Bluetooth SIG site and put in bluetooth_psm.h or bluetooth_l2cap.h
#define PSM_HID_CONTROL   0x11
#define PSM_HID_INTERRUPT 0x13
#define PSM_ATT           0x1f
#define PSM_IPSP          0x23

/** 
 * @brief Set up L2CAP and register L2CAP with HCI layer.
 */
void l2cap_init(void);

/**
 * @brief Add event packet handler for LE Connection Parameter Update events
 */
void l2cap_add_event_handler(btstack_packet_callback_registration_t * callback_handler);

/**
 * @brief Remove event packet handler.
 */
void l2cap_remove_event_handler(btstack_packet_callback_registration_t * callback_handler);

/** 
 * @brief Get max MTU for Classic connections based on btstack configuration
 */
uint16_t l2cap_max_mtu(void);

/** 
 * @brief Get max MTU for LE connections based on btstack configuration
 */
uint16_t l2cap_max_le_mtu(void);

/**
* @brief Set the max MTU for LE connections, if not set l2cap_max_mtu() will be used.
*/
void l2cap_set_max_le_mtu(uint16_t max_mtu);

/** 
 * @brief Creates L2CAP channel to the PSM of a remote device with baseband address. A new baseband connection will be initiated if necessary.
 * @param packet_handler
 * @param address
 * @param psm
 * @param mtu
 * @param local_cid
 * @return status
 */
uint8_t l2cap_create_channel(btstack_packet_handler_t packet_handler, bd_addr_t address, uint16_t psm, uint16_t mtu, uint16_t * out_local_cid);

/** 
 * @brief Disconnects L2CAP channel with given identifier. 
 * @param local_cid
 * @return status ERROR_CODE_SUCCESS if successful or L2CAP_LOCAL_CID_DOES_NOT_EXIST
 */
uint8_t l2cap_disconnect(uint16_t local_cid);

/** 
 * @brief Queries the maximal transfer unit (MTU) for L2CAP channel with given identifier. 
 */
uint16_t l2cap_get_remote_mtu_for_local_cid(uint16_t local_cid);

/** 
 * @brief Sends L2CAP data packet to the channel with given identifier.
 * @note For channel in credit-based flow control mode, data needs to stay valid until .. event
 * @param local_cid
 * @param data to send
 * @param len of data
 * @return status
 */
uint8_t l2cap_send(uint16_t local_cid, const uint8_t *data, uint16_t len);

/** 
 * @brief Registers L2CAP service with given PSM and MTU, and assigns a packet handler. 
 * @param packet_handler
 * @param psm
 * @param mtu
 * @param security_level
 * @return status ERROR_CODE_SUCCESS if successful, otherwise L2CAP_SERVICE_ALREADY_REGISTERED or BTSTACK_MEMORY_ALLOC_FAILED
 */
uint8_t l2cap_register_service(btstack_packet_handler_t packet_handler, uint16_t psm, uint16_t mtu, gap_security_level_t security_level);

/** 
 * @brief Unregisters L2CAP service with given PSM.
 */
uint8_t l2cap_unregister_service(uint16_t psm);

/** 
 * @brief Accepts incoming L2CAP connection.
 */
void l2cap_accept_connection(uint16_t local_cid);

/** 
 * @brief Deny incoming L2CAP connection.
 */
void l2cap_decline_connection(uint16_t local_cid);

/** 
 * @brief Check if outgoing buffer is available and that there's space on the Bluetooth module
 * @return true if packet can be sent
 */
bool l2cap_can_send_packet_now(uint16_t local_cid);

/** 
 * @brief Request emission of L2CAP_EVENT_CAN_SEND_NOW as soon as possible
 * @note L2CAP_EVENT_CAN_SEND_NOW might be emitted during call to this function
 *       so packet handler should be ready to handle it
 * @param local_cid
 * @return status
 */
uint8_t l2cap_request_can_send_now_event(uint16_t local_cid);

/** 
 * @brief Reserve outgoing buffer
 * @note Only for L2CAP Basic Mode Channels
 * @note Must only be called after a 'can send now' check or event
 * @note Asserts if packet buffer is already reserved
 */
void l2cap_reserve_packet_buffer(void);

/** 
 * @brief Get outgoing buffer and prepare data.
 * @note Only for L2CAP Basic Mode Channels
 */
uint8_t *l2cap_get_outgoing_buffer(void);

/** 
 * @brief Send L2CAP packet prepared in outgoing buffer to channel
 * @note Only for L2CAP Basic Mode Channels
 */
uint8_t l2cap_send_prepared(uint16_t local_cid, uint16_t len);

/** 
 * @brief Release outgoing buffer (only needed if l2cap_send_prepared is not called)
 * @note Only for L2CAP Basic Mode Channels
 */
void l2cap_release_packet_buffer(void);

//
// Connection-Oriented Channels in Enhanced Retransmission Mode - ERTM
//

/**
 * @brief Creates L2CAP channel to the PSM of a remote device with baseband address using Enhanced Retransmission Mode.
 *        A new baseband connection will be initiated if necessary.
 * @param packet_handler
 * @param address
 * @param psm
 * @param ertm_config
 * @param buffer to store reassembled rx packet, out-of-order packets and unacknowledged outgoing packets with their tretransmission timers
 * @param size of buffer
 * @param local_cid
 * @return status
 */
uint8_t l2cap_ertm_create_channel(btstack_packet_handler_t packet_handler, bd_addr_t address, uint16_t psm,
                                  l2cap_ertm_config_t * ertm_contig, uint8_t * buffer, uint32_t size, uint16_t * out_local_cid);

/**
 * @brief Accepts incoming L2CAP connection for Enhanced Retransmission Mode
 * @param local_cid
 * @param ertm_config
 * @param buffer to store reassembled rx packet, out-of-order packets and unacknowledged outgoing packets with their tretransmission timers
 * @param size of buffer
 * @return status
 */
uint8_t l2cap_ertm_accept_connection(uint16_t local_cid, l2cap_ertm_config_t * ertm_contig, uint8_t * buffer, uint32_t size);

/**
 * @brief Deny incoming incoming L2CAP connection for Enhanced Retransmission Mode
 * @param local_cid
 * @return status
 */
uint8_t l2cap_ertm_decline_connection(uint16_t local_cid);

/**
 * @brief ERTM Set channel as busy.
 * @note Can be cleared by l2cap_ertm_set_ready
 * @param local_cid
 * @return status
 */
uint8_t l2cap_ertm_set_busy(uint16_t local_cid);

/**
 * @brief ERTM Set channel as ready
 * @note Used after l2cap_ertm_set_busy
 * @param local_cid
 * @return status
 */
uint8_t l2cap_ertm_set_ready(uint16_t local_cid);


//
// L2CAP Connection-Oriented Channels in LE Credit-Based Flow-Control Mode - CBM
//

/**
 * @brief Register L2CAP service in LE Credit-Based Flow-Control Mode
 * @note MTU and initial credits are specified in l2cap_cbm_accept_connection(..) call
 * @param packet_handler
 * @param psm
 * @param security_level
 */
uint8_t l2cap_cbm_register_service(btstack_packet_handler_t packet_handler, uint16_t psm, gap_security_level_t security_level);

/**
 * @brief Unregister L2CAP service in LE Credit-Based Flow-Control Mode
 * @param psm
 */

uint8_t l2cap_cbm_unregister_service(uint16_t psm);

/*
 * @brief Accept incoming connection LE Credit-Based Flow-Control Mode
 * @param local_cid             L2CAP Channel Identifier
 * @param receive_buffer        buffer used for reassembly of L2CAP LE Information Frames into service data unit (SDU) with given MTU
 * @param receive_buffer_size   buffer size equals MTU
 * @param initial_credits       Number of initial credits provided to peer or L2CAP_LE_AUTOMATIC_CREDITS to enable automatic credits
 */

uint8_t l2cap_cbm_accept_connection(uint16_t local_cid, uint8_t * receive_sdu_buffer, uint16_t mtu, uint16_t initial_credits);

/** 
 * @brief Deecline connection in LE Credit-Based Flow-Control Mode
 * @param local_cid             L2CAP Channel Identifier
 * @param result                result, see L2CAP_CBM_CONNECTION_RESULT_SUCCESS in bluetooth.h
 */

uint8_t l2cap_cbm_decline_connection(uint16_t local_cid, uint16_t result);

/**
 * @brief Create outgoing channel in LE Credit-Based Flow-Control Mode
 * @param packet_handler        Packet handler for this connection
 * @param con_handle            HCI Connection Handle, LE transport
 * @param psm                   Service PSM to connect to
 * @param receive_buffer        buffer used for reassembly of L2CAP LE Information Frames into service data unit (SDU) with given MTU
 * @param receive_buffer_size   buffer size equals MTU
 * @param initial_credits       Number of initial credits provided to peer or L2CAP_LE_AUTOMATIC_CREDITS to enable automatic credits
 * @param security_level        Minimum required security level
 * @param out_local_cid         L2CAP LE Channel Identifier is stored here
 */
uint8_t l2cap_cbm_create_channel(btstack_packet_handler_t packet_handler, hci_con_handle_t con_handle,
    uint16_t psm, uint8_t * receive_sdu_buffer, uint16_t mtu, uint16_t initial_credits, gap_security_level_t security_level,
    uint16_t * out_local_cid);

/**
 * @brief Provide credits for channel in LE Credit-Based Flow-Control Mode
 * @param local_cid             L2CAP Channel Identifier
 * @param credits               Number additional credits for peer
 */
uint8_t l2cap_cbm_provide_credits(uint16_t local_cid, uint16_t credits);

//
// L2CAP Connection-Oriented Channels in Enhanced Credit-Based Flow-Control Mode - ECBM
//

/**
 * @brief Register L2CAP service in Enhanced Credit-Based Flow-Control Mode
 * @note MTU and initial credits are specified in l2cap_enhanced_accept_connection(..) call
 * @param packet_handler
 * @param psm
 * @param min_remote_mtu
 * @param security_level
 * @oaram authorization_required
 * @return status
 */
uint8_t l2cap_ecbm_register_service(btstack_packet_handler_t packet_handler, uint16_t psm, uint16_t min_remote_mtu,
                                    gap_security_level_t security_level, bool authorization_required);

/**
 * @brief Unregister L2CAP service in Enhanced Credit-Based Flow-Control Mode
 * @param psm
 * @return status
 */

uint8_t l2cap_ecbm_unregister_service(uint16_t psm);

/**
 * @brief Set Minimal MPS for channel in Enhanced Credit-Based Flow-Control Mode
 * @param mps_min
 */
void l2cap_ecbm_mps_set_min(uint16_t mps_min);

/**
 * @brief Set Minimal MPS for channel in Enhanced Credit-Based Flow-Control Mode
 * @param mps_max
 */
void l2cap_ecbm_mps_set_max(uint16_t mps_max);

/**
 * @brief Create outgoing channel in Enhanced Credit-Based Flow-Control Mode
 * @note receive_buffer points to an array of receive buffers with num_channels elements
 * @note out_local_cid points to an array where CID is stored with num_channel elements
 * @param packet_handler        Packet handler for this connection
 * @param con_handle            HCI Connection Handle
 * @param security_level        Minimum required security level
 * @param psm                   Service PSM to connect to
 * @param num_channels          number of channels to create
 * @param initial_credits       Number of initial credits provided to peer per channel or L2CAP_LE_AUTOMATIC_CREDITS to enable automatic credits
 * @param receive_buffer_size   buffer size equals MTU
 * @param receive_buffers       Array of buffers used for reassembly of L2CAP Information Frames into service data unit (SDU) with given MTU
 * @param out_local_cids        Array of L2CAP Channel Identifiers is stored here on success
 * @return status
 */
uint8_t l2cap_ecbm_create_channels(btstack_packet_handler_t packet_handler, hci_con_handle_t con_handle,
                                       gap_security_level_t security_level,
                                       uint16_t psm, uint8_t num_channels, uint16_t initial_credits, uint16_t receive_buffer_size,
                                       uint8_t ** receive_buffers, uint16_t * out_local_cids);

/**
 * @brief  Accept incoming connection Enhanced Credit-Based Flow-Control Mode
 * @param local_cid            from L2CAP_EVENT_INCOMING_DATA_CONNECTION
 * @param num_channels
 * @param initial_credits      Number of initial credits provided to peer per channel or L2CAP_LE_AUTOMATIC_CREDITS to enable automatic credits
 * @param receive_buffer_size
 * @param receive_buffers      Array of buffers used for reassembly of L2CAP Information Frames into service data unit (SDU) with given MTU
 * @param out_local_cids       Array of L2CAP Channel Identifiers is stored here on success
 * @return status
 */
uint8_t l2cap_ecbm_accept_channels(uint16_t local_cid, uint8_t num_channels, uint16_t initial_credits,
                                            uint16_t receive_buffer_size, uint8_t ** receive_buffers, uint16_t * out_local_cids);
/**
 * @brief Decline connection in Enhanced Credit-Based Flow-Control Mode
 * @param local_cid           from L2CAP_EVENT_INCOMING_DATA_CONNECTION
 * @param result              See L2CAP_ECBM_CONNECTION_RESULT_ALL_SUCCESS in bluetooth.h
 * @return status
 */
uint8_t l2cap_ecbm_decline_channels(uint16_t local_cid, uint16_t result);

/**
 * @brief Provide credits for channel in Enhanced Credit-Based Flow-Control Mode
 * @param local_cid             L2CAP Channel Identifier
 * @param credits               Number additional credits for peer
 * @return status
 */
uint8_t l2cap_ecbm_provide_credits(uint16_t local_cid, uint16_t credits);

/**
 * @brief Request emission of L2CAP_EVENT_ECBM_CAN_SEND_NOW as soon as possible
 * @note L2CAP_EVENT_ECBM_CAN_SEND_NOW might be emitted during call to this function
 *       so packet handler should be ready to handle it
 * @param local_cid             L2CAP Channel Identifier
 * @return status
 */
uint8_t l2cap_ecbm_request_can_send_now_event(uint16_t local_cid);

/**
 * @brief Reconfigure MPS/MTU of local channels
 * @param num_cids
 * @param local_cids            array of local_cids to reconfigure
 * @param receive_buffer_size   buffer size equals MTU
 * @param receive_buffers       Array of buffers used for reassembly of L2CAP Information Frames into service data unit (SDU) with given MTU
 * @return status
 */
uint8_t l2cap_ecbm_reconfigure_channels(uint8_t num_cids, uint16_t * local_cids, int16_t receive_buffer_size, uint8_t ** receive_buffers);

/**
 * @brief Trigger pending connection responses after pairing completed
 * @note Must be called after receiving an SM_PAIRING_COMPLETE event, will be removed eventually
 * @param con_handle
 */
void l2cap_ecbm_trigger_pending_connection_responses(hci_con_handle_t con_handle);

/**
 * @brief De-Init L2CAP
 */
void l2cap_deinit(void);

Audio Stream Control Service Client API {#sec:broadcast_audio_scan_service_client_api}

broadcast_audio_scan_service_client.h

typedef enum {
    BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_IDLE,
    BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE,
    BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT,
    BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTICS,
    BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_RESULT,

    BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTIC_DESCRIPTORS,
    BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_DESCRIPTORS_RESULT,

    BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_REGISTER_NOTIFICATION,
    BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_NOTIFICATION_REGISTERED,
    BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED,

    BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_READ_CHARACTERISTIC_CONFIGURATION,
    BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_CHARACTERISTIC_CONFIGURATION_RESULT,

    BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_START_SCAN,
    BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_START_SCAN,

    BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_STOP_SCAN,
    BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_STOP_SCAN,

    BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_ADD_SOURCE,
    BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_ADD_SOURCE,

    BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_MODIFY_SOURCE,
    BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_MODIFY_SOURCE,

    BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_SET_BROADCAST_CODE,
    BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_SET_BROADCAST_CODE,

    BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_REMOVE_SOURCE,
    BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_REMOVE_SOURCE,

    BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_READE_RECEIVE_STATE,
    BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_READE_RECEIVE_STATE,

} broadcast_audio_scan_service_client_state_t;

typedef struct {
    // used for add source command
    bass_source_data_t data;

    // received via notification
    bool    in_use;
    uint8_t source_id;
    le_audio_big_encryption_t big_encryption;
    uint8_t  bad_code[16];

    // characteristic
    uint16_t receive_state_value_handle;
    uint16_t receive_state_ccc_handle;
    uint16_t receive_state_properties;
    uint16_t receive_state_end_handle;
} bass_client_source_t;

typedef struct {
    btstack_linked_item_t item;

    hci_con_handle_t  con_handle;
    uint16_t          cid;
    uint16_t          mtu;
    broadcast_audio_scan_service_client_state_t  state;

    // service
    uint16_t start_handle;
    uint16_t end_handle;
    uint16_t control_point_value_handle;

    // used for memory capacity checking
    uint8_t  service_instances_num;
    uint8_t  receive_states_instances_num;
    // used for notification registration
    uint8_t  receive_states_index;

    uint8_t max_receive_states_num;
    bass_client_source_t * receive_states;

    // used for write segmentation
    uint8_t  buffer[BASS_CLIENT_MAX_ATT_BUFFER_SIZE];
    uint16_t buffer_offset;
    uint16_t data_size;

    gatt_client_notification_t notification_listener;

    // used for adding and modifying source
    const bass_source_data_t * control_point_operation_data;
    uint8_t control_point_operation_source_id;
    // used for setting the broadcast code
    const uint8_t * broadcast_code;
} bass_client_connection_t;

/**
 * @brief Init Broadcast Audio Scan Service Client. Register packet handler to receive events:
 * - LEAUDIO_SUBEVENT_BASS_CLIENT_CONNECTED
 * - LEAUDIO_SUBEVENT_BASS_CLIENT_DISCONNECTED
 * - LEAUDIO_SUBEVENT_BASS_CLIENT_SCAN_OPERATION_COMPLETE
 * - LEAUDIO_SUBEVENT_BASS_CLIENT_SOURCE_OPERATION_COMPLETE
 * - LEAUDIO_SUBEVENT_BASS_CLIENT_NOTIFICATION_COMPLETE
 * @param packet_handler for events
 */
void broadcast_audio_scan_service_client_init(btstack_packet_handler_t packet_handler);

/**
 * @brief Connect to BASS Service on remote device
 * @note LEAUDIO_SUBEVENT_BASS_CLIENT_CONNECTED will be emitted
 * @param connection struct provided by user, needs to stay valid until disconnect event is received
 * @param sources buffer to store information on Broadcast Sources on the service
 * @param num_sources
 * @param con_handle to connect to
 * @param bass_cid connection id for this connection for other functions
 * @return status
 */
uint8_t broadcast_audio_scan_service_client_connect(bass_client_connection_t * connection, bass_client_source_t * sources, uint8_t num_sources, hci_con_handle_t con_handle, uint16_t * bass_cid);

/**
 * @brief Notify BASS Service that scanning has started
 * @param bass_cid
 * @return status
 */
uint8_t broadcast_audio_scan_service_client_scanning_started(uint16_t bass_cid);

/**
 * @brief Notify BASS Service that scanning has stopped
 * @note emits LEAUDIO_SUBEVENT_BASS_CLIENT_SOURCE_OPERATION_COMPLETE
 * @param bass_cid
 * @return status
 */
uint8_t broadcast_audio_scan_service_client_scanning_stopped(uint16_t bass_cid);

/**
 * @brief Add Broadcast Source on service
 * @note GATTSERVICE_SUBEVENT_BASS_NOTIFICATION_COMPLETE will contain source_id for other functions
 * @param bass_cid
 * @param add_source_data data to add, needs to stay valid until LEAUDIO_SUBEVENT_BASS_CLIENT_SOURCE_OPERATION_COMPLETE
 * @return status
 */
uint8_t broadcast_audio_scan_service_client_add_source(uint16_t bass_cid, const bass_source_data_t * add_source_data);

/**
 * @brief Modify information about Broadcast Source on service
 * @param bass_cid
 * @param source_id
 * @param modify_source_data data to modify, needs to stay valid until LEAUDIO_SUBEVENT_BASS_CLIENT_SOURCE_OPERATION_COMPLETE
 * @return status
 */
uint8_t broadcast_audio_scan_service_client_modify_source(uint16_t bass_cid, uint8_t source_id, const bass_source_data_t * modify_source_data);

/**
 * @brief Set Broadcast Code for a Broadcast Source to allow remote do decrypt audio stream
 * @param bass_cid
 * @param source_id
 * @param broadcast_code
 * @return status
 */
uint8_t broadcast_audio_scan_service_client_set_broadcast_code(uint16_t bass_cid, uint8_t source_id, const uint8_t * broadcast_code);

/**
 * @brief Remove information about Broadcast Source
 * @param bass_cid
 * @param source_id
 * @return status
 */
uint8_t broadcast_audio_scan_service_client_remove_source(uint16_t bass_cid, uint8_t source_id);

/**
 * @param Provide read-only access to Broadcast Receive State of given Broadcast Source on service
 * @param bass_cid
 * @param source_id
 * @return pointer to source data or NULL, if source_id not found
 */
const bass_source_data_t * broadcast_audio_scan_service_client_get_source_data(uint16_t bass_cid, uint8_t source_id);

/**
 * @param Get BIG Encryption and Bad Code from Broadcast Receive State of given Broadcast Source on service
 * @param bass_cid
 * @param source_id
 * @param out_big_encryption
 * @param out_bad_code 16-byte buffer
 * @return status
 */
uint8_t broadcast_audio_scan_service_client_get_encryption_state(uint16_t bass_cid, uint8_t source_id,
                                                                 le_audio_big_encryption_t * out_big_encryption, uint8_t * out_bad_code);

/**
 * @brief Deinit Broadcast Audio Scan Service Client
 */
void broadcast_audio_scan_service_client_deinit(uint16_t bass_cid);

Broadcast Audio Scan Service Server (BASS) API {#sec:broadcast_audio_scan_service_server_api}

broadcast_audio_scan_service_server.h : @text The Broadcast Audio Scan Service is used by servers to expose their status with respect to synchronization to broadcast Audio Streams and associated data, including Broadcast_Codes used to decrypt encrypted broadcast Audio Streams. Clients can use the attributes exposed by servers to observe and/or request changes in server behavior.

To use with your application, add #import <broadcast_audio_scan_service.gatt> to your .gatt file.

// memory for list of these structs is allocated by the application
typedef struct {
    // assigned by client via control point
    bass_source_data_t data;

    uint8_t  update_counter;
    uint8_t  source_id; 
    bool     in_use;

    le_audio_big_encryption_t big_encryption;
    uint8_t  bad_code[16];

    uint16_t bass_receive_state_handle;
    uint16_t bass_receive_state_client_configuration_handle;
    uint16_t bass_receive_state_client_configuration;
} bass_server_source_t;

typedef struct {
    hci_con_handle_t con_handle;
    uint16_t sources_to_notify;

    // used for caching long write
    uint8_t  long_write_buffer[512];
    uint16_t long_write_value_size;
    uint16_t long_write_attribute_handle;
} bass_server_connection_t;

/**
 * @brief Init Broadcast Audio Scan Service Server with ATT DB
 * @param sources_num
 * @param sources
 * @param clients_num
 * @param clients
 */
void broadcast_audio_scan_service_server_init(uint8_t const sources_num, bass_server_source_t * sources, uint8_t const clients_num, bass_server_connection_t * clients);

/**
 * @brief Register packet handler to receive events:
 * - LEAUDIO_SUBEVENT_BASS_SERVER_SCAN_STOPPED
 * - LEAUDIO_SUBEVENT_BASS_SERVER_SCAN_STARTED
 * - LEAUDIO_SUBEVENT_BASS_SERVER_BROADCAST_CODE
 * - LEAUDIO_SUBEVENT_BASS_SERVER_SOURCE_ADDED
 * - LEAUDIO_SUBEVENT_BASS_SERVER_SOURCE_MODIFIED
 * - LEAUDIO_SUBEVENT_BASS_SERVER_SOURCE_DELETED
 * @param packet_handler
 */
void broadcast_audio_scan_service_server_register_packet_handler(btstack_packet_handler_t packet_handler);

/**
 * @brief Set PA state of source.
 * @param source_index
 * @param sync_state
 */
void broadcast_audio_scan_service_server_set_pa_sync_state(uint8_t source_index, le_audio_pa_sync_state_t sync_state);

/**
 * @brief Add source.
 * @param source_data
 * @param source_index
 */
void broadcast_audio_scan_service_server_add_source(const bass_source_data_t *source_data, uint8_t * source_index);

/**
 * @brief Deinit Broadcast Audio Scan Service Server
 */
void broadcast_audio_scan_service_server_deinit(void);

Volume Offset Control Service Server API {#sec:le_audio_api}

le_audio.h

Broadcast Audio Source Endpoint AD Builder API {#sec:le_audio_base_builder_api}

le_audio_base_builder.h

Broadcast Audio Source Endpoint AD Parser API {#sec:le_audio_base_parser_api}

le_audio_base_parser.h

LE Audio Util API {#sec:le_audio_util_api}

le_audio_util.h

Mesh Provisioning Service Server API {#sec:mesh_provisioning_service_server_api}

mesh_provisioning_service_server.h

/**
 * @brief Init Mesh Provisioning Service Server with ATT DB
 */
void mesh_provisioning_service_server_init(void);

/**
 * @brief Send a Proxy PDU message containing Provisioning PDU from a Provisioning Server to a Provisioning Client.
 * @param con_handle 
 * @param proxy_pdu 
 * @param proxy_pdu_size max lenght MESH_PROV_MAX_PROXY_PDU
 */
void mesh_provisioning_service_server_send_proxy_pdu(uint16_t con_handle, const uint8_t * proxy_pdu, uint16_t proxy_pdu_size);

/**
 * @brief Register callback for the PB-GATT.
 * @param callback
 */
void mesh_provisioning_service_server_register_packet_handler(btstack_packet_handler_t callback);

/**
 * @brief Request can send now event to send PDU
 * Generates an MESH_SUBEVENT_CAN_SEND_NOW subevent
 * @param con_handle
 */
void mesh_provisioning_service_server_request_can_send_now(hci_con_handle_t con_handle);

Mesh Proxy Service Server API {#sec:mesh_proxy_service_server_api}

mesh_proxy_service_server.h

/**
 * @brief Init Mesh Proxy Service Server with ATT DB
 */
void mesh_proxy_service_server_init(void);

/**
 * @brief Send a Proxy PDU message containing proxy PDU from a proxy Server to a proxy Client.
 * @param con_handle 
 * @param proxy_pdu 
 * @param proxy_pdu_size max lenght MESH_PROV_MAX_PROXY_PDU
 */
void mesh_proxy_service_server_send_proxy_pdu(uint16_t con_handle, const uint8_t * proxy_pdu, uint16_t proxy_pdu_size);

/**
 * @brief Register callback for the PB-GATT.
 * @param callback
 */
void mesh_proxy_service_server_register_packet_handler(btstack_packet_handler_t callback);

/**
 * @brief Request can send now event to send PDU
 * Generates an MESH_SUBEVENT_CAN_SEND_NOW subevent
 * @param con_handle
 */
void mesh_proxy_service_server_request_can_send_now(hci_con_handle_t con_handle);