BLE Advertisements Parser API

typedef struct ad_context {
     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, uint8_t * ad_data);
int  ad_iterator_has_more(ad_context_t * context);
void ad_iterator_next(ad_context_t * context);

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

// convenience function on complete advertisements
int ad_data_contains_uuid16(uint8_t ad_len, uint8_t * ad_data, uint16_t uuid);
int ad_data_contains_uuid128(uint8_t ad_len, uint8_t * ad_data, uint8_t * uuid128);

BLE ANCS Client API

typedef struct ancs_event{
    uint8_t  type;
    uint16_t handle;
    uint16_t attribute_id;
    const char * text;
} ancs_event_t;

void ancs_client_init(void);
void ancs_client_hci_event_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
void ancs_client_register_callback(void (*handler)(ancs_event_t * event));
const char * ancs_client_attribute_name_for_id(int id);

BLE ATT Database API

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

/**
 * @brief Add primary service for 16-bit UUID
 */
void att_db_util_add_service_uuid16(uint16_t udid16);

/**
 * @brief Add primary service for 128-bit UUID
 */
void att_db_util_add_service_uuid128(uint8_t * udid128);

/**
 * @brief Add Characteristic with 16-bit UUID, properties, and data
 * @returns attribute value handle
 * @see ATT_PROPERTY_* in ble/att.h
 */
uint16_t att_db_util_add_characteristic_uuid16(uint16_t   udid16,  uint16_t properties, uint8_t * data, uint16_t data_len);

/**
 * @brief Add Characteristic with 128-bit UUID, properties, and data
 * @returns attribute value handle
 * @see ATT_PROPERTY_* in ble/att.h
 */
uint16_t att_db_util_add_characteristic_uuid128(uint8_t * udid128, uint16_t properties, 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);

BLE ATT Server API

/*
 * @brief setup ATT server
 * @param db attribute database created by compile-gatt.ph
 * @param read_callback, see att.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 register packet handler for general HCI Events like connect, diconnect, etc.
 * @param handler
 */
void att_server_register_packet_handler(btstack_packet_handler_t handler);

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

/*
 * @brief notify client about attribute value change
 * @return 0 if ok, error otherwise
 */
int att_server_notify(uint16_t handle, uint8_t *value, uint16_t value_len);

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

BLE GAP API

typedef enum {
    GAP_RANDOM_ADDRESS_TYPE_OFF = 0,
    GAP_RANDOM_ADDRESS_NON_RESOLVABLE,
    GAP_RANDOM_ADDRESS_RESOLVABLE,
} gap_random_address_type_t;

/**
 * @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 off
 */
void gap_random_address_set(bd_addr_t addr);

/**
 * @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)
 * @returns 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 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)
 * @returns 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 Set Advertisement Data
 * @param advertising_data_length
 * @param advertising_data (max 31 octets)
 * @note data is not copied, pointer has to stay valid
 */
void gap_advertisements_set_data(uint8_t advertising_data_length, uint8_t * advertising_data);

/**
 * @brief Set Advertisement Paramters
 * @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
 * @param enabled
 */
void gap_advertisements_enable(int enabled);

/**
 * @brief Auto Connection Establishment - Start Connecting to device
 * @param address_typ
 * @param address
 * @returns 0 if ok
 */
int gap_auto_connection_start(bd_addr_type_t address_typ, bd_addr_t address);

/**
 * @brief Auto Connection Establishment - Stop Connecting to device
 * @param address_typ
 * @param address
 * @returns 0 if ok
 */
int gap_auto_connection_stop(bd_addr_type_t address_typ, bd_addr_t address);

/**
 * @brief Auto Connection Establishment - Stop everything
 * @note  Convenience function to stop all active auto connection attempts
 */
void gap_auto_connection_stop_all(void);

BLE GATT Client API

typedef struct gatt_complete_event{
    uint8_t   type;
    uint16_t handle;
    uint16_t attribute_handle;
    uint8_t status;
} gatt_complete_event_t;

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

typedef struct le_service_event{
    uint8_t  type;
    uint16_t handle;
    le_service_t service;
} le_service_event_t;

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

typedef struct le_characteristic_event{
    uint8_t  type;
    uint16_t handle;
    le_characteristic_t characteristic;
} le_characteristic_event_t;

typedef struct le_characteristic_value_event{
    uint8_t   type;
    uint16_t  handle;
    uint16_t  value_handle;
    uint16_t  value_offset;
    uint16_t  blob_length;
    uint8_t * blob;
} le_characteristic_value_event_t;

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

typedef struct le_characteristic_descriptor_event{
    uint8_t  type;
    uint16_t handle;
    le_characteristic_descriptor_t characteristic_descriptor;
    uint16_t value_length;
    uint16_t value_offset;
    uint8_t * value;
} le_characteristic_descriptor_event_t;

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

/** 
 * @brief Register callback (packet handler) for GATT client. Returns GATT client ID.
 */
uint16_t gatt_client_register_packet_handler (gatt_client_callback_t callback);

/** 
 * @brief Unregister callback (packet handler) for GATT client.
 */
void gatt_client_unregister_packet_handler(uint16_t gatt_client_id);

/** 
 * @brief MTU is available after the first query has completed. If status is equal to BLE_PERIPHERAL_OK, it returns the real value, otherwise the default value of 23. 
 */
le_command_status_t gatt_client_get_mtu(uint16_t handle, uint16_t * mtu);

/** 
 * @brief Returns if the GATT client is ready to receive a query. It is used with daemon. 
 */
int gatt_client_is_ready(uint16_t handle);

/** 
 * @brief Discovers all primary services. For each found service, an le_service_event_t with type set to GATT_SERVICE_QUERY_RESULT will be generated and passed to the registered callback. The gatt_complete_event_t, with type set to GATT_QUERY_COMPLETE, marks the end of discovery. 
 */
le_command_status_t gatt_client_discover_primary_services(uint16_t gatt_client_id, uint16_t con_handle);

/** 
 * @brief Discovers a specific primary service given its UUID. This service may exist multiple times. For each found service, an le_service_event_t with type set to GATT_SERVICE_QUERY_RESULT will be generated and passed to the registered callback. The gatt_complete_event_t, with type set to GATT_QUERY_COMPLETE, marks the end of discovery. 
 */
le_command_status_t gatt_client_discover_primary_services_by_uuid16(uint16_t gatt_client_id, uint16_t con_handle, uint16_t uuid16);
le_command_status_t gatt_client_discover_primary_services_by_uuid128(uint16_t gatt_client_id, uint16_t con_handle, const uint8_t  * uuid);

/** 
 * @brief Finds included services within the specified service. For each found included service, an le_service_event_t with type set to GATT_INCLUDED_SERVICE_QUERY_RESULT will be generated and passed to the registered callback. The gatt_complete_event_t with type set to GATT_QUERY_COMPLETE, 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. 
 */
le_command_status_t gatt_client_find_included_services_for_service(uint16_t gatt_client_id, uint16_t con_handle, le_service_t  *service);

/** 
 * @brief Discovers all characteristics within the specified service. For each found characteristic, an le_characteristics_event_t with type set to GATT_CHARACTERISTIC_QUERY_RESULT will be generated and passed to the registered callback. The gatt_complete_event_t with type set to GATT_QUERY_COMPLETE, marks the end of discovery.
 */
le_command_status_t gatt_client_discover_characteristics_for_service(uint16_t gatt_client_id, uint16_t con_handle, le_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, an le_characteristic_event_t with type set to GATT_CHARACTERISTIC_QUERY_RESULT will be generated and passed to the registered callback. The gatt_complete_event_t with type set to GATT_QUERY_COMPLETE, marks the end of discovery.
 */
le_command_status_t gatt_client_discover_characteristics_for_handle_range_by_uuid16(uint16_t gatt_client_id, uint16_t con_handle, uint16_t start_handle, uint16_t end_handle, uint16_t uuid16);
le_command_status_t gatt_client_discover_characteristics_for_handle_range_by_uuid128(uint16_t gatt_client_id, uint16_t con_handle, uint16_t start_handle, uint16_t end_handle, uint8_t  * uuid);
le_command_status_t gatt_client_discover_characteristics_for_service_by_uuid16 (uint16_t gatt_client_id, uint16_t con_handle, le_service_t  *service, uint16_t  uuid16);
le_command_status_t gatt_client_discover_characteristics_for_service_by_uuid128(uint16_t gatt_client_id, uint16_t con_handle, le_service_t  *service, uint8_t  * uuid128);

/** 
 * @brief Discovers attribute handle and UUID of a characteristic descriptor within the specified characteristic. For each found descriptor, an le_characteristic_descriptor_event_t with type set to GATT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT will be generated and passed to the registered callback. The gatt_complete_event_t with type set to GATT_QUERY_COMPLETE, marks the end of discovery.
 */
le_command_status_t gatt_client_discover_characteristic_descriptors(uint16_t gatt_client_id, uint16_t con_handle, le_characteristic_t  *characteristic);

/** 
 * @brief Reads the characteristic value using the characteristic's value handle. If the characteristic value is found, an le_characteristic_value_event_t with type set to GATT_CHARACTERISTIC_VALUE_QUERY_RESULT will be generated and passed to the registered callback. The gatt_complete_event_t with type set to GATT_QUERY_COMPLETE, marks the end of read.
 */
le_command_status_t gatt_client_read_value_of_characteristic(uint16_t gatt_client_id, uint16_t con_handle, le_characteristic_t  *characteristic);
le_command_status_t gatt_client_read_value_of_characteristic_using_value_handle(uint16_t gatt_client_id, uint16_t con_handle, uint16_t characteristic_value_handle);

/**
 * @brief Reads the characteric value of all characteristics with the uuid. For each found, an le_characteristic_value_event_t with type set to GATT_CHARACTERISTIC_VALUE_QUERY_RESULT will be generated and passed to the registered callback. The gatt_complete_event_t with type set to GATT_QUERY_COMPLETE, marks the end of read.
 */
le_command_status_t gatt_client_read_value_of_characteristics_by_uuid16(uint16_t gatt_client_id, uint16_t con_handle, uint16_t start_handle, uint16_t end_handle, uint16_t uuid16);
le_command_status_t gatt_client_read_value_of_characteristics_by_uuid128(uint16_t gatt_client_id, uint16_t con_handle, uint16_t start_handle, uint16_t end_handle, 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, an le_characteristic_value_event_t with type set to GATT_CHARACTERISTIC_VALUE_QUERY_RESULT and updated value offset will be generated and passed to the registered callback. The gatt_complete_event_t with type set to GATT_QUERY_COMPLETE, mark the end of read.
 */
le_command_status_t gatt_client_read_long_value_of_characteristic(uint16_t gatt_client_id, uint16_t con_handle, le_characteristic_t  *characteristic);
le_command_status_t gatt_client_read_long_value_of_characteristic_using_value_handle(uint16_t gatt_client_id, uint16_t con_handle, uint16_t characteristic_value_handle);
le_command_status_t gatt_client_read_long_value_of_characteristic_using_value_handle_with_offset(uint16_t gatt_client_id, uint16_t con_handle, uint16_t characteristic_value_handle, uint16_t offset);

/*
 * @brief Read multiple characteristic values
 * @param number handles
 * @param list_of_handles list of handles 
 */
le_command_status_t gatt_client_read_multiple_characteristic_values(uint16_t gatt_client_id, uint16_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.
 */
le_command_status_t gatt_client_write_value_of_characteristic_without_response(uint16_t gatt_client_id, uint16_t con_handle, uint16_t characteristic_value_handle, uint16_t length, uint8_t  * data);

/** 
 * @brief Writes the authenticated characteristic value using the characteristic's value handle without an acknowledgment that the write was successfully performed.
 */
le_command_status_t gatt_client_signed_write_without_response(uint16_t gatt_client_id, uint16_t con_handle, uint16_t handle, uint16_t message_len, uint8_t  * message);

/** 
 * @brief Writes the characteristic value using the characteristic's value handle. The gatt_complete_event_t with type set to GATT_QUERY_COMPLETE, marks the end of write. The write is successfully performed, if the event's status field is set to 0.
 */
le_command_status_t gatt_client_write_value_of_characteristic(uint16_t gatt_client_id, uint16_t con_handle, uint16_t characteristic_value_handle, uint16_t length, uint8_t  * data);
le_command_status_t gatt_client_write_long_value_of_characteristic(uint16_t gatt_client_id, uint16_t con_handle, uint16_t characteristic_value_handle, uint16_t length, uint8_t  * data);
le_command_status_t gatt_client_write_long_value_of_characteristic_with_offset(uint16_t gatt_client_id, uint16_t con_handle, uint16_t characteristic_value_handle, uint16_t offset, uint16_t length, uint8_t  * data);

/** 
 * @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_complete_event_t with type set to GATT_QUERY_COMPLETE marks the end of write. The write is successfully performed, if the event's status field is set to 0.
 */
le_command_status_t gatt_client_reliable_write_long_value_of_characteristic(uint16_t gatt_client_id, uint16_t con_handle, uint16_t characteristic_value_handle, uint16_t length, uint8_t  * data);

/** 
 * @brief Reads the characteristic descriptor using its handle. If the characteristic descriptor is found, an le_characteristic_descriptor_event_t with type set to GATT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT will be generated and passed to the registered callback. The gatt_complete_event_t with type set to GATT_QUERY_COMPLETE, marks the end of read.
 */
le_command_status_t gatt_client_read_characteristic_descriptor(uint16_t gatt_client_id, uint16_t con_handle, le_characteristic_descriptor_t  * descriptor);
le_command_status_t gatt_client_read_characteristic_descriptor_using_descriptor_handle(uint16_t gatt_client_id, uint16_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, an le_characteristic_descriptor_event_t with type set to GATT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT will be generated and passed to the registered callback. The gatt_complete_event_t with type set to GATT_QUERY_COMPLETE, marks the end of read.
 */
le_command_status_t gatt_client_read_long_characteristic_descriptor(uint16_t gatt_client_id, uint16_t con_handle, le_characteristic_descriptor_t  * descriptor);
le_command_status_t gatt_client_read_long_characteristic_descriptor_using_descriptor_handle(uint16_t gatt_client_id, uint16_t con_handle, uint16_t descriptor_handle);
le_command_status_t gatt_client_read_long_characteristic_descriptor_using_descriptor_handle_with_offset(uint16_t gatt_client_id, uint16_t con_handle, uint16_t descriptor_handle, uint16_t offset);

/** 
 * @brief Writes the characteristic descriptor using its handle. The gatt_complete_event_t with type set to GATT_QUERY_COMPLETE, marks the end of write. The write is successfully performed, if the event's status field is set to 0.
 */
le_command_status_t gatt_client_write_characteristic_descriptor(uint16_t gatt_client_id, uint16_t con_handle, le_characteristic_descriptor_t  * descriptor, uint16_t length, uint8_t  * data);
le_command_status_t gatt_client_write_characteristic_descriptor_using_descriptor_handle(uint16_t gatt_client_id, uint16_t con_handle, uint16_t descriptor_handle, uint16_t length, uint8_t  * data);
le_command_status_t gatt_client_write_long_characteristic_descriptor(uint16_t gatt_client_id, uint16_t con_handle, le_characteristic_descriptor_t  * descriptor, uint16_t length, uint8_t  * data);
le_command_status_t gatt_client_write_long_characteristic_descriptor_using_descriptor_handle(uint16_t gatt_client_id, uint16_t con_handle, uint16_t descriptor_handle, uint16_t length, uint8_t  * data);
le_command_status_t gatt_client_write_long_characteristic_descriptor_using_descriptor_handle_with_offset(uint16_t gatt_client_id, uint16_t con_handle, uint16_t descriptor_handle, uint16_t offset, uint16_t length, uint8_t  * data);

/** 
 * @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.
 */
le_command_status_t gatt_client_write_client_characteristic_configuration(uint16_t gatt_client_id, uint16_t con_handle, le_characteristic_t * characteristic, uint16_t configuration);

BLE Device Database API

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

/**
 * @brief add device to db
 * @param addr_type, address of the device
 * @param irk of the device
 * @returns 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 for enumeration
 * @returns number of device in db
 */
int le_device_db_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
 */
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);

/**
 * @brief get remote encryption info
 * @brief index
 * @brief ediv 
 * @brief rand
 * @brief ltk
 * @brief key size
 * @brief authenticated
 * @brief authorized
 */
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);

/**
 * @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
 * @returns 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
 * @returns 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);

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

void le_device_db_dump(void);

BLE Security Manager API

/**
 * @brief Security Manager event
 */
typedef struct sm_event {
    uint8_t   type;                 ///< See <btstack/hci_cmds.h> SM_...
    uint8_t   addr_type;
    bd_addr_t address;
    uint32_t  passkey;              ///< only used for SM_PASSKEY_DISPLAY_NUMBER 
    uint16_t  le_device_db_index;   ///< only used for SM_IDENTITY_RESOLVING_..
    uint8_t   authorization_result; ///< only use for SM_AUTHORIZATION_RESULT
} sm_event_t;

/**
 * @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 
 * @param er
 */
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 
 */
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 addres_type, bd_addr_t addr, uint8_t * oob_data));

/**
 *
 * @brief Registers packet handler. Called by att_server.c
 */
void sm_register_packet_handler(btstack_packet_handler_t 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
 * @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 Let Peripheral request an encrypted connection right after connecting
 * @note Not used normally. Bonding is triggered by access to protected attributes in ATT Server
 */
void sm_set_request_security(int enable);

/** 
 * @brief Trigger Security Request
 * @note Not used normally. Bonding is triggered by access to protected attributes in ATT Server
 */
void sm_send_security_request(uint16_t handle);

/**
 * @brief Decline bonding triggered by event before
 * @param addr_type and address
 */
void sm_bonding_decline(uint8_t addr_type, bd_addr_t address);

/**
 * @brief Confirm Just Works bonding 
 * @param addr_type and address
 */
void sm_just_works_confirm(uint8_t addr_type, bd_addr_t address);

/**
 * @brief Reports passkey input by user
 * @param addr_type and address
 * @param passkey in [0..999999]
 */
void sm_passkey_input(uint8_t addr_type, bd_addr_t address, uint32_t passkey);

/**
 *
 * @brief Get encryption key size.
 * @param addr_type and address
 * @return 0 if not encrypted, 7-16 otherwise
 */
int sm_encryption_key_size(uint8_t addr_type, bd_addr_t address);

/**
 * @brief Get authentication property.
 * @param addr_type and address
 * @return 1 if bonded with OOB/Passkey (AND MITM protection)
 */
int sm_authenticated(uint8_t addr_type, bd_addr_t address);

/**
 * @brief Queries authorization state.
 * @param addr_type and address
 * @return authorization_state for the current session
 */
authorization_state_t sm_authorization_state(uint8_t addr_type, bd_addr_t address);

/**
 * @brief Used by att_server.c to request user authorization.
 * @param addr_type and address
 */
void sm_request_pairing(uint8_t addr_type, bd_addr_t address);

/**
 * @brief Report user authorization decline.
 * @param addr_type and address
 */
void sm_authorization_decline(uint8_t addr_type, bd_addr_t address);

/**
 * @brief Report user authorization grant.
 * @param addr_type and address
 */
void sm_authorization_grant(uint8_t addr_type, bd_addr_t address);

/**
 * @brief Support for signed writes, used by att_server.
 * @note Message and result are in little endian to allows passing in ATT PDU without flipping. 
 * @note calculated hash in done_callback is big endian
 */
int  sm_cmac_ready(void);
void sm_cmac_start(sm_key_t k, uint8_t opcode, uint16_t attribute_handle, uint16_t message_len, uint8_t * message, uint32_t sign_counter, void (*done_handler)(uint8_t hash[8]));

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

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

BNEP API

/**
 * @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 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.
 */
void bnep_set_required_security_level(gap_security_level_t security_level);

/**
 * @brief Register packet handler. 
 */
void bnep_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size));

/**
 * @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(void * connection, 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. 
 */
void bnep_register_service(void * connection, uint16_t service_uuid, uint16_t max_frame_size);

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

BTstack Memory Management API

/**
 * @brief Initializes BTstack memory pools.
 */
void btstack_memory_init(void);

GAP API

/**
 * @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 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);
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);
int  gap_mitm_protection_required_for_security_level(gap_security_level_t level);

/** 
 * @brief Sets local name.
 * @note has to be done before stack starts up
 * @param name is not copied, make sure memory is accessible during stack startup
 */
void gap_set_local_name(const char * local_name);

HCI API

void gap_le_get_connection_parameter_range(le_connection_parameter_range_t * range);
void gap_le_set_connection_parameter_range(le_connection_parameter_range_t * range);

/* LE Client Start */

le_command_status_t le_central_start_scan(void);
le_command_status_t le_central_stop_scan(void);
le_command_status_t le_central_connect(bd_addr_t addr, bd_addr_type_t addr_type);
le_command_status_t le_central_connect_cancel(void);
le_command_status_t gap_disconnect(hci_con_handle_t handle);
void le_central_set_scan_parameters(uint8_t scan_type, uint16_t scan_interval, uint16_t scan_window);

/* LE Client End */

void hci_connectable_control(uint8_t enable);
void hci_close(void);

/** 
 * @note New functions replacing: hci_can_send_packet_now[_using_packet_buffer]
 */
int hci_can_send_command_packet_now(void);

/**
 * @brief Gets local address.
 */
void hci_local_bd_addr(bd_addr_t address_buffer);

/**
 * @brief Set up HCI. Needs to be called before any other function.
 */
void hci_init(hci_transport_t *transport, void *config, bt_control_t *control, remote_device_db_t const* remote_device_db);

/**
 * @brief Set class of device that will be set during Bluetooth init.
 */
void hci_set_class_of_device(uint32_t class_of_device);

/**
 * @brief Set Public BD ADDR - passed on to Bluetooth chipset if supported in bt_control_h
 */
void hci_set_bd_addr(bd_addr_t addr);

/**
 * @brief Registers a packet handler. Used if L2CAP is not used (rarely). 
 */
void hci_register_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size));

/**
 * @brief Registers a packet handler for SCO data. Used for HSP and HFP profiles.
 */
void hci_register_sco_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size));

/**
 * @brief Requests the change of BTstack power mode.
 */
int  hci_power_control(HCI_POWER_MODE mode);

/**
 * @brief Allows to control if device is discoverable. OFF by default.
 */
void hci_discoverable_control(uint8_t enable);

/**
 * @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. 
 */
int hci_send_cmd(const hci_cmd_t *cmd, ...);

/**
 * @brief Deletes link key for remote device with baseband address.
 */
void hci_drop_link_key_for_bd_addr(bd_addr_t addr);

/* Configure Secure Simple Pairing */

/**
 * @brief Enable will enable SSP during init.
 */
void hci_ssp_set_enable(int enable);

/**
 * @brief If set, BTstack will respond to io capability request using authentication requirement.
 */
void hci_ssp_set_io_capability(int ssp_io_capability);
void hci_ssp_set_authentication_requirement(int authentication_requirement);

/**
 * @brief If set, BTstack will confirm a numeric comparison and enter '000000' if requested.
 */
void hci_ssp_set_auto_accept(int auto_accept);

/**
 * @brief Get addr type and address used in advertisement packets.
 */
void hci_le_advertisement_address(uint8_t * addr_type, bd_addr_t addr);

/**
 * @brief Set callback for Bluetooth Hardware Error
 */
void hci_set_hardware_error_callback(void (*fn)(void));

/** 
 * @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 Get SCO packet length for current SCO Voice setting
 *  @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
 */
int hci_get_sco_packet_length(void);

HCI Logging API

typedef enum {
    HCI_DUMP_BLUEZ = 0,
    HCI_DUMP_PACKETLOGGER,
    HCI_DUMP_STDOUT
} hci_dump_format_t;

/*
 * @brief 
 */
void hci_dump_open(const char *filename, hci_dump_format_t format);

/*
 * @brief 
 */
void hci_dump_set_max_packets(int packets); // -1 for unlimited

/*
 * @brief 
 */
void hci_dump_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len);

/*
 * @brief 
 */
void hci_dump_log(int log_level, const char * format, ...)
#ifdef __GNUC__
__attribute__ ((format (__printf__, 2, 3)));
#endif
;

/*
 * @brief 
 */
void hci_dump_enable_log_level(int log_level, int enable);

/*
 * @brief 
 */
void hci_dump_close(void);

HCI Transport API

/* HCI packet types */
typedef struct {
    int    (*open)(void *transport_config);
    int    (*close)(void *transport_config);
    int    (*send_packet)(uint8_t packet_type, uint8_t *packet, int size);
    void   (*register_packet_handler)(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size));
    const char * (*get_transport_name)(void);
    // custom extension for UART transport implementations
    int    (*set_baudrate)(uint32_t baudrate);
    // support async transport layers, e.g. IRQ driven without buffers
    int    (*can_send_packet_now)(uint8_t packet_type);
} hci_transport_t;

typedef struct {
    const char *device_name;
    uint32_t   baudrate_init; // initial baud rate
    uint32_t   baudrate_main; // = 0: same as initial baudrate
    int   flowcontrol; // 
} hci_uart_config_t;


// inline various hci_transport_X.h files

/*
 * @brief
 */
extern hci_transport_t * hci_transport_h4_instance(void);

/*
 * @brief
 */
extern hci_transport_t * hci_transport_h4_dma_instance(void);

/*
 * @brief
 */
extern hci_transport_t * hci_transport_h4_iphone_instance(void);

/*
 * @brief
 */
extern hci_transport_t * hci_transport_h5_instance(void);

/*
 * @brief
 */
extern hci_transport_t * hci_transport_usb_instance(void);

L2CAP API

/** 
 * @brief Set up L2CAP and register L2CAP with HCI layer.
 */
void l2cap_init(void);

/** 
 * @brief Registers a packet handler that handles HCI and general BTstack events.
 */
void l2cap_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size));

/** 
 * @brief Creates L2CAP channel to the PSM of a remote device with baseband address. A new baseband connection will be initiated if necessary.
 */
void l2cap_create_channel_internal(void * connection, btstack_packet_handler_t packet_handler, bd_addr_t address, uint16_t psm, uint16_t mtu);

/** 
 * @brief Disconnects L2CAP channel with given identifier. 
 */
void l2cap_disconnect_internal(uint16_t local_cid, uint8_t reason);

/** 
 * @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.
 */
int l2cap_send_internal(uint16_t local_cid, uint8_t *data, uint16_t len);

/** 
 * @brief Registers L2CAP service with given PSM and MTU, and assigns a packet handler. On embedded systems, use NULL for connection parameter.
 */
void l2cap_register_service_internal(void *connection, 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.  On embedded systems, use NULL for connection parameter.
 */
void l2cap_unregister_service_internal(void *connection, uint16_t psm);

/** 
 * @brief Accepts/Deny incoming L2CAP connection.
 */
void l2cap_accept_connection_internal(uint16_t local_cid);
void l2cap_decline_connection_internal(uint16_t local_cid, uint8_t reason);

/** 
 * @brief Non-blocking UART write
 */
int  l2cap_can_send_packet_now(uint16_t local_cid); 
int  l2cap_can_send_prepared_packet_now(uint16_t local_cid);

int  l2cap_reserve_packet_buffer(void);
void l2cap_release_packet_buffer(void);

/** 
 * @brief Get outgoing buffer and prepare data.
 */
uint8_t *l2cap_get_outgoing_buffer(void);

int l2cap_send_prepared(uint16_t local_cid, uint16_t len);

int l2cap_send_prepared_connectionless(uint16_t handle, uint16_t cid, uint16_t len);

/** 
 * @brief Bluetooth 4.0 - allows to register handler for Attribute Protocol and Security Manager Protocol.
 */
void l2cap_register_fixed_channel(btstack_packet_handler_t packet_handler, uint16_t channel_id);

uint16_t l2cap_max_mtu(void);
uint16_t l2cap_max_le_mtu(void);

int  l2cap_send_connectionless(uint16_t handle, uint16_t cid, uint8_t *data, uint16_t len);

PAN API

/** 
 * @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 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_service(uint8_t *service, 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 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_service(uint8_t *service, 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 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_service(uint8_t *service, 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);

Remote Device DB API

typedef struct {

    // management
    void (*open)(void);
    void (*close)(void);

    // link key
    int  (*get_link_key)(bd_addr_t bd_addr, link_key_t link_key, link_key_type_t * type);
    void (*put_link_key)(bd_addr_t bd_addr, link_key_t link_key, link_key_type_t   type);
    void (*delete_link_key)(bd_addr_t bd_addr);

    // remote name
    int  (*get_name)(bd_addr_t bd_addr, device_name_t *device_name);
    void (*put_name)(bd_addr_t bd_addr, device_name_t *device_name);
    void (*delete_name)(bd_addr_t bd_addr);

    // persistent rfcomm channel
    uint8_t (*persistent_rfcomm_channel)(char *servicename);

} remote_device_db_t;

/*
 * @brief
 */
extern       remote_device_db_t remote_device_db_iphone;

/*
 * @brief
 */
extern const remote_device_db_t remote_device_db_memory;

/*
 * @brief
 */
extern const remote_device_db_t remote_device_db_fs;

const remote_device_db_t * remote_device_db_fs_instance(void);

RFCOMM API

/** 
 * @brief Set up RFCOMM.
 */
void rfcomm_init(void);

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

/** 
 * @brief Register packet handler.
 */
void rfcomm_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size));

/** 
 * @brief Creates RFCOMM connection (channel) to a given server channel on a remote device with baseband address. A new baseband connection will be initiated if necessary. This channel will automatically provide enough credits to the remote side
 */
void rfcomm_create_channel_internal(void * connection, bd_addr_t addr, uint8_t channel);

/** 
 * @brief Creates RFCOMM connection (channel) to a given server channel on a remote device with baseband address. new baseband connection will be initiated if necessary. This channel will use explicit credit management. During channel establishment, an initial  amount of credits is provided.
 */
void rfcomm_create_channel_with_initial_credits_internal(void * connection, bd_addr_t addr, uint8_t server_channel, uint8_t initial_credits);

/** 
 * @brief Disconnects RFCOMM channel with given identifier. 
 */
void rfcomm_disconnect_internal(uint16_t rfcomm_cid);

/** 
 * @brief Registers RFCOMM service for a server channel and a maximum frame size, and assigns a packet handler. On embedded systems, use NULL for connection parameter. This channel provides automatically enough credits to the remote side.
 */
void rfcomm_register_service_internal(void * connection, 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. On embedded systems, use NULL for connection parameter. This channel will use explicit credit management. During channel establishment, an initial amount of credits is provided.
 */
void rfcomm_register_service_with_initial_credits_internal(void * connection, uint8_t channel, uint16_t max_frame_size, uint8_t initial_credits);

/** 
 * @brief Unregister RFCOMM service.
 */
void rfcomm_unregister_service_internal(uint8_t service_channel);

/** 
 * @brief Accepts/Deny incoming RFCOMM connection.
 */
void rfcomm_accept_connection_internal(uint16_t rfcomm_cid);
void rfcomm_decline_connection_internal(uint16_t rfcomm_cid);

/** 
 * @brief Grant more incoming credits to the remote side for the given RFCOMM channel identifier.
 */
void rfcomm_grant_credits(uint16_t rfcomm_cid, uint8_t credits);

/** 
 * @brief Checks if RFCOMM can send packet. Returns yes if packet can be sent.
 */
int rfcomm_can_send_packet_now(uint16_t rfcomm_cid);

/** 
 * @brief Sends RFCOMM data packet to the RFCOMM channel with given identifier.
 */
int  rfcomm_send_internal(uint16_t rfcomm_cid, uint8_t *data, uint16_t len);

/** 
 * @brief Sends Local Line Status, see LINE_STATUS_..
 */
int rfcomm_send_local_line_status(uint16_t rfcomm_cid, uint8_t line_status);

/** 
 * @brief Send local modem status. see MODEM_STAUS_..
 */
int rfcomm_send_modem_status(uint16_t rfcomm_cid, uint8_t modem_status);

/** 
 * @brief Configure remote port 
 */
int 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, rpn_flow_control_t flow_control);

/** 
 * @brief Query remote port 
 */
int rfcomm_query_port_configuration(uint16_t rfcomm_cid);

/** 
 * @brief Allow to create RFCOMM packet in outgoing buffer.
 */
int       rfcomm_reserve_packet_buffer(void);
void      rfcomm_release_packet_buffer(void);
uint8_t * rfcomm_get_outgoing_buffer(void);
uint16_t  rfcomm_get_max_frame_size(uint16_t rfcomm_cid);
int       rfcomm_send_prepared(uint16_t rfcomm_cid, uint16_t len);

Run Loop API

/**
 * @brief Set timer based on current time in milliseconds.
 */
void run_loop_set_timer(timer_source_t *a, uint32_t timeout_in_ms);

/**
 * @brief Set callback that will be executed when timer expires.
 */
void run_loop_set_timer_handler(timer_source_t *ts, void (*process)(timer_source_t *_ts));

/**
 * @brief Add/Remove timer source.
 */
void run_loop_add_timer(timer_source_t *timer); 
int  run_loop_remove_timer(timer_source_t *timer);

/**
 * @brief Get current time in ms
 * @note 32-bit ms counter will overflow after approx. 52 days
 */
uint32_t run_loop_get_time_ms(void);

/**
 * @brief Init must be called before any other run_loop call. Use RUN_LOOP_EMBEDDED for embedded devices.
 */
void run_loop_init(RUN_LOOP_TYPE type);

/**
 * @brief Set data source callback.
 */
void run_loop_set_data_source_handler(data_source_t *ds, int (*process)(data_source_t *_ds));

/**
 * @brief Add/Remove data source.
 */
void run_loop_add_data_source(data_source_t *dataSource);
int  run_loop_remove_data_source(data_source_t *dataSource);

/**
 * @brief Execute configured run loop. This function does not return.
 */
void run_loop_execute(void);


// hack to fix HCI timer handling
#ifdef HAVE_TICK
/**
 * @brief Sets how many milliseconds has one tick.
 */
uint32_t embedded_ticks_for_ms(uint32_t time_in_ms);
/**
 * @brief Queries the current time in ticks.
 */
uint32_t embedded_get_ticks(void);
/**
 * @brief Allows to update BTstack system ticks based on another already existing clock.
 */
void embedded_set_ticks(uint32_t ticks);
#endif
#ifdef EMBEDDED
/**
 * @brief Sets an internal flag that is checked in the critical section just before entering sleep mode. Has to be called by the interrupt handler of a data source to signal the run loop that a new data is available.
 */
void embedded_trigger(void);    
/**
 * @brief Execute run_loop once. It can be used to integrate BTstack's timer and data source processing into a foreign run loop (it is not recommended).
 */
void embedded_execute_once(void);
#endif

SDP API

/** 
 * @brief Set up SDP.
 */
void sdp_init(void);

void sdp_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size));

#ifdef EMBEDDED
/** 
 * @brief Register service record internally - this version doesn't copy the record therefore it must be forever accessible. Preconditions:
    - AttributeIDs are in ascending order;
    - ServiceRecordHandle is first attribute and valid.
 * @return ServiceRecordHandle or 0 if registration failed.
 */
uint32_t sdp_register_service_internal(void *connection, service_record_item_t * record_item);
#endif

#ifndef EMBEDDED
/** 
 * @brief Register service record internally - this version creates a copy of the record precondition: AttributeIDs are in ascending order => ServiceRecordHandle is first attribute if present. 
 * @return ServiceRecordHandle or 0 if registration failed
 */
uint32_t sdp_register_service_internal(void *connection, uint8_t * service_record);
#endif

/** 
 * @brief Unregister service record internally.
 */
void sdp_unregister_service_internal(void *connection, uint32_t service_record_handle);

SDP Client API

/** 
 * @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 a registered callback.
 */
void sdp_client_query(bd_addr_t remote, uint8_t * des_serviceSearchPattern, uint8_t * des_attributeIDList);

#ifdef HAVE_SDP_EXTRA_QUERIES
void sdp_client_service_attribute_search(bd_addr_t remote, uint32_t search_serviceRecordHandle, uint8_t * des_attributeIDList);
void sdp_client_service_search(bd_addr_t remote, uint8_t * des_serviceSearchPattern);
#endif

SDP Parser API

// SDP Parser
// Basic SDP Query event type
typedef struct sdp_query_event {
    uint8_t type;
    void * dummy;   // force sdp_query_event struct to be word aligned -> avoid -Wcast-align warning
} sdp_query_event_t;

// SDP Query event to indicate that query/parser is complete.
typedef struct sdp_query_complete_event {
    uint8_t type;
    uint8_t status; // 0 == OK
    void * dummy;   // force sdp_query_complete_event struct to be word aligned -> avoid -Wcast-align warning
} sdp_query_complete_event_t;

// SDP Parser event to deliver an attribute value byte by byte
typedef struct sdp_query_attribute_value_event {
    uint8_t type;
    int record_id;
    uint16_t attribute_id;
    uint32_t attribute_length;
    int data_offset;
    uint8_t data;
    void * dummy;   // force sdp_query_attribute_value_event struct to be word aligned -> avoid -Wcast-align warning
} sdp_query_attribute_value_event_t;


#ifdef HAVE_SDP_EXTRA_QUERIES
typedef struct sdp_query_service_record_handle_event {
    uint8_t type;
    uint16_t total_count;
    uint16_t current_count;
    uint32_t record_handle;
    void * dummy;   // force sdp_query_service_record_handle_event struct to be word aligned -> avoid -Wcast-align warning
} sdp_query_service_record_handle_event_t;
#endif

/*
 * @brief
 */
void sdp_parser_init(void);

/*
 * @brief
 */
void sdp_parser_handle_chunk(uint8_t * data, uint16_t size);

#ifdef HAVE_SDP_EXTRA_QUERIES

/*
 * @brief
 */
void sdp_parser_init_service_attribute_search(void);

/*
 * @brief
 */
void sdp_parser_init_service_search(void);

/*
 * @brief
 */
void sdp_parser_handle_service_search(uint8_t * data, uint16_t total_count, uint16_t record_handle_count);
#endif

void sdp_parser_handle_done(uint8_t status);

/*
 * @brief Registers a callback to receive attribute value data and parse complete event.
 */
void sdp_parser_register_callback(void (*sdp_callback)(sdp_query_event_t * event));

SDP RFCOMM Query API

/** 
 * @brief SDP Query RFCOMM event to deliver channel number and service name byte by byte.
 */
typedef struct sdp_query_rfcomm_service_event {
    uint8_t type;
    uint8_t channel_nr;
    uint8_t * service_name;
} sdp_query_rfcomm_service_event_t;

/** 
 * @brief Registers a callback to receive RFCOMM service and query complete event. 
 */
void sdp_query_rfcomm_register_callback(void(*sdp_app_callback)(sdp_query_event_t * event, void * context), void * context);

void sdp_query_rfcomm_deregister_callback(void);

/** 
 * @brief Searches SDP records on a remote device for RFCOMM services with a given UUID.
 */
void sdp_query_rfcomm_channel_and_name_for_uuid(bd_addr_t remote, uint16_t uuid);

/** 
 * @brief Searches SDP records on a remote device for RFCOMM services with a given service search pattern.
 */
void sdp_query_rfcomm_channel_and_name_for_search_pattern(bd_addr_t remote, uint8_t * des_serviceSearchPattern);

SDP Query Utils API

/*
 * @brief Returns service search pattern for given UUID
 */
uint8_t* create_service_search_pattern_for_uuid(uint16_t uuid);

/*
 * @brief Searches SDP records on a remote device for all services with a given UUID.
 */
void sdp_general_query_for_uuid(bd_addr_t remote, uint16_t uuid16);

/*
 * @brief
 */
void sdp_general_query_for_uuid128(bd_addr_t remote, uint8_t* uuid128);

SDP Utils API

// UNIVERSAL ATTRIBUTE DEFINITIONS
#define SDP_ServiceRecordHandle     0x0000
#define SDP_ServiceClassIDList      0x0001
#define SDP_ServiceRecordState      0x0002
#define SDP_ServiceID               0x0003
#define SDP_ProtocolDescriptorList  0x0004
#define SDP_BrowseGroupList         0x0005
#define SDP_LanguageBaseAttributeIDList 0x0006
#define SDP_ServiceInfoTimeToLive   0x0007
#define SDP_ServiceAvailability     0x0008
#define SDP_BluetoothProfileDescriptorList 0x0009
#define SDP_DocumentationURL        0x000a
#define SDP_ClientExecutableURL     0x000b
#define SDP_IconURL                 0x000c
#define SDP_AdditionalProtocolDescriptorList 0x000d
#define SDP_SupportedFormatsList    0x0303

// SERVICE CLASSES
#define SDP_OBEXObjectPush          0x1105
#define SDP_OBEXFileTransfer        0x1106
#define SDP_PublicBrowseGroup       0x1002
#define SDP_HSP                     0x1108
#define SDP_Headset_AG              0x1112
#define SDP_PANU                    0x1115
#define SDP_NAP                     0x1116
#define SDP_GN                      0x1117
#define SDP_Handsfree               0x111E
#define SDP_HandsfreeAudioGateway   0x111F
#define SDP_Headset_HS              0x1131
#define SDP_GenericAudio            0x1203


// PROTOCOLS
#define SDP_SDPProtocol       0x0001
#define SDP_UDPProtocol       0x0002
#define SDP_RFCOMMProtocol    0x0003
#define SDP_OBEXProtocol      0x0008
#define SDP_L2CAPProtocol     0x0100
#define SDP_BNEPProtocol      0x000F
#define SDP_AVDTPProtocol     0x0019

// OFFSETS FOR LOCALIZED ATTRIBUTES - SDP_LanguageBaseAttributeIDList
#define SDP_Offest_ServiceName      0x0000
#define SDP_Offest_ServiceDescription 0x0001
#define SDP_Offest_ProviderName     0x0002

// OBEX
#define SDP_vCard_2_1       0x01
#define SDP_vCard_3_0       0x02
#define SDP_vCal_1_0        0x03
#define SDP_iCal_2_0        0x04
#define SDP_vNote           0x05
#define SDP_vMessage        0x06
#define SDP_OBEXFileTypeAny 0xFF


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(uint8_t * record);
int       de_get_len(uint8_t *header);
de_size_t de_get_size_type(uint8_t *header);
de_type_t de_get_element_type(uint8_t *header);
int       de_get_header_size(uint8_t * header);
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 *header);
void      de_pop_sequence(uint8_t * parent, uint8_t * child);
void      de_add_number(uint8_t *seq, de_type_t type, de_size_t size, uint32_t value);
void      de_add_data( uint8_t *seq, de_type_t type, uint16_t size, uint8_t *data);
int       de_element_get_uint16(uint8_t * element, uint16_t * value);

int       de_get_data_size(uint8_t * header);
void      de_add_uuid128(uint8_t * seq, uint8_t * uuid);
uint32_t  de_get_uuid32(uint8_t * element);
int       de_get_normalized_uuid(uint8_t *uuid128, uint8_t *element);

// MARK: DES iterator
typedef struct {
    uint8_t * element;
    uint16_t pos;
    uint16_t length;
} des_iterator_t;

int des_iterator_init(des_iterator_t * it, uint8_t * element);
int  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);
uint8_t   sdp_set_attribute_value_for_attribute_id(uint8_t * record, uint16_t attributeID, uint32_t value);
int       sdp_record_matches_service_search_pattern(uint8_t *record, uint8_t *serviceSearchPattern);
int       spd_get_filtered_size(uint8_t *record, uint8_t *attributeIDList);
int       sdp_filter_attributes_in_attributeIDList(uint8_t *record, uint8_t *attributeIDList, uint16_t startOffset, uint16_t maxBytes, uint16_t *usedBytes, uint8_t *buffer);  
int       sdp_attribute_list_constains_id(uint8_t *attributeIDList, uint16_t attributeID);
int       sdp_traversal_match_pattern(uint8_t * element, de_type_t attributeType, de_size_t size, void *my_context);

void      sdp_create_spp_service(uint8_t *service, int service_id, const char *name);
void      sdp_normalize_uuid(uint8_t *uuid, uint32_t shortUUID);
int       sdp_has_blueooth_base_uuid(uint8_t * uuid128);

HSP Headset API

/**
 * @brief Packet handler for HSP Headset (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 event See include/btstack/hci_cmds.h
 * @param event_size
 */
typedef void (*hsp_hs_callback_t)(uint8_t * event, uint16_t event_size);

/**
 * @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, int rfcomm_channel_nr, const char * name, uint8_t have_remote_audio_control);

/**
 * @brief Register packet handler to receive HSP HS events.
 * @param callback 
 */
void hsp_hs_register_packet_handler(hsp_hs_callback_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);

HSP Audio Gateway API

/**
 * @brief Packet handler for HSP Audio Gateway (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 event See include/btstack/hci_cmds.h
 * @param event_size
 */
typedef void (*hsp_ag_callback_t)(uint8_t * event, uint16_t event_size);

/**
 * @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 rfcomm_channel_nr
 * @param name
 */
void hsp_ag_create_sdp_record(uint8_t * service, int rfcomm_channel_nr, const char * name);

/**
 * @brief Register packet handler to receive HSP AG events.
 * @param callback 
 */
void hsp_ag_register_packet_handler(hsp_ag_callback_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);

HFP Hands-Free API

/**
 * @brief Create HFP Hands-Free (HF) SDP service record. 
 * @param service
 * @param rfcomm_channel_nr
 * @param name
 * @param suported_features 32-bit bitmap, see HFP_HFSF_* values in hfp.h
 */
void hfp_hf_create_sdp_record(uint8_t * service, int rfcomm_channel_nr, const char * name, uint32_t supported_features);

/**
 * @brief Set up HFP Hands-Free (HF) device without additional supported features. 
 * @param rfcomm_channel_nr
 */
void hfp_hf_init(uint16_t rfcomm_channel_nr);

/**
 * @brief Set codecs. 
 * @param codecs_nr
 * @param codecs
 */
void hfp_hf_init_codecs(int codecs_nr, 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, uint16_t * indicators);


/**
 * @brief Register callback for the HFP Hands-Free (HF) client. 
 * @param callback
 */
void hfp_hf_register_packet_handler(hfp_callback_t callback);

/**
 * @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
 */
void 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 bd_addr Bluetooth address of the AG
 */
void hfp_hf_release_service_level_connection(bd_addr_t bd_addr);

/**
 * @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 bd_addr Bluetooth address of the AG
 */
void hfp_hf_enable_status_update_for_all_ag_indicators(bd_addr_t bd_addr);

/**
 * @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 bd_addr Bluetooth address of the AG
 */
void hfp_hf_disable_status_update_for_all_ag_indicators(bd_addr_t bd_addr);

/**
 * @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 bd_addr Bluetooth address of the AG
 * @param indicators_status_bitmap 32-bit bitmap, 0 - indicator is disabled, 1 - indicator is enabled
 */
void hfp_hf_set_status_update_for_individual_ag_indicators(bd_addr_t bd_addr, 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 bd_addr Bluetooth address of the AG
 */
void hfp_hf_query_operator_selection(bd_addr_t bd_addr);

/**
 * @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 bd_addr Bluetooth address of the AG
 */
void hfp_hf_enable_report_extended_audio_gateway_error_result_code(bd_addr_t bd_addr);

/**
 * @brief Disable Extended Audio Gateway Error result codes in the AG.
 *
 * @param bd_addr Bluetooth address of the AG
 */
 void hfp_hf_disable_report_extended_audio_gateway_error_result_code(bd_addr_t bd_addr);

/**
 * @brief Establish audio connection. 
 * The status of audio connection establishment is reported via
 * HFP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED.
 * @param bd_addr Bluetooth address of the AG
 */
void hfp_hf_establish_audio_connection(bd_addr_t bd_addr);

/**
 * @brief Release audio connection.
 * The status of releasing of the audio connection is reported via
 * HFP_SUBEVENT_AUDIO_CONNECTION_RELEASED.
 *
 * @param bd_addr Bluetooth address of the AG
 */
void hfp_hf_release_audio_connection(bd_addr_t bd_addr);

/**
 * @brief Answer incoming call.
 * @param bd_addr Bluetooth address of the AG
 */
void hfp_hf_answer_incoming_call(bd_addr_t bd_addr);

/**
 * @brief Reject incoming call.
 * @param bd_addr Bluetooth address of the AG
 */
void hfp_hf_reject_incoming_call(bd_addr_t bd_addr);

/**
 * @brief Release all held calls or sets User Determined User Busy (UDUB) for a waiting call.
 * @param bd_addr Bluetooth address of the AG
 */
void hfp_hf_user_busy(bd_addr_t addr);

/**
 * @brief Release all active calls (if any exist) and accepts the other (held or waiting) call.
 * @param bd_addr Bluetooth address of the AG
 */
void hfp_hf_end_active_and_accept_other(bd_addr_t addr);

/**
 * @brief Place all active calls (if any exist) on hold and accepts the other (held or waiting) call.
 * @param bd_addr Bluetooth address of the AG
 */
void hfp_hf_swap_calls(bd_addr_t addr);

/**
 * @brief Add a held call to the conversation.
 * @param bd_addr Bluetooth address of the AG
 */
void hfp_hf_join_held_call(bd_addr_t addr);

/**
 * @brief Connect the two calls and disconnects the subscriber from both calls (Explicit Call
Transfer).
 * @param bd_addr Bluetooth address of the AG
 */
void hfp_hf_connect_calls(bd_addr_t addr);

/**
 * @brief Terminate an incoming or an outgoing call. 
 * HFP_SUBEVENT_CALL_TERMINATED is sent upon call termination.
 * @param bd_addr Bluetooth address of the AG
 */
void hfp_hf_terminate_call(bd_addr_t bd_addr);

/**
 * @brief Initiate outgoing voice call by providing the destination phone number to the AG. 
 * @param bd_addr Bluetooth address of the AG
 * @param number
 */
void hfp_hf_dial_number(bd_addr_t bd_addr, char * number);

/**
 * @brief Initiate outgoing voice call using the memory dialing feature of the AG.
 * @param bd_addr Bluetooth address of the AG
 * @param memory_id
 */
void hfp_hf_dial_memory(bd_addr_t bd_addr, int memory_id);

/**
 * @brief Initiate outgoing voice call by recalling the last number dialed by the AG.
 * @param bd_addr Bluetooth address of the AG
 */
void hfp_hf_redial_last_number(bd_addr_t bd_addr);

/*
 * @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 bd_addr Bluetooth address of the AG
 */
void hfp_hf_activate_call_waiting_notification(bd_addr_t bd_addr);

/*
 * @brief Disable the “Call Waiting notification” function in the AG.
 * @param bd_addr Bluetooth address of the AG
 */
void hfp_hf_deactivate_call_waiting_notification(bd_addr_t bd_addr);

/*
 * @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 bd_addr Bluetooth address of the AG
 */
void hfp_hf_activate_calling_line_notification(bd_addr_t bd_addr);

/*
 * @brief Disable the “Calling Line Identification notification” function in the AG.
 * @param bd_addr Bluetooth address of the AG
 */
void hfp_hf_deactivate_calling_line_notification(bd_addr_t bd_addr);


/*
 * @brief Activate echo canceling and noise reduction in the AG. By default, 
 * if the AG supports its own embedded echo canceling and/or noise reduction 
 * functions, it shall have them activated until this function is called.
 * If the AG does not support any echo canceling and noise reduction functions, 
 * it shall respond with the ERROR indicator (TODO)
 * @param bd_addr Bluetooth address of the AG
 */
void hfp_hf_activate_echo_canceling_and_noise_reduction(bd_addr_t bd_addr);

/*
 * @brief Deactivate echo canceling and noise reduction in the AG.
 */
void hfp_hf_deactivate_echo_canceling_and_noise_reduction(bd_addr_t bd_addr);

/*
 * @brief Activate voice recognition function.
 * @param bd_addr Bluetooth address of the AG
 */
void hfp_hf_activate_voice_recognition_notification(bd_addr_t bd_addr);

/*
 * @brief Dectivate voice recognition function.
 * @param bd_addr Bluetooth address of the AG
 */
void hfp_hf_deactivate_voice_recognition_notification(bd_addr_t bd_addr);

/*
 * @brief Set microphone gain. 
 * @param bd_addr Bluetooth address of the AG
 * @param gain Valid range: [0,15]
 */
void hfp_hf_set_microphone_gain(bd_addr_t bd_addr, int gain);

/*
 * @brief Set speaker gain.
 * @param bd_addr Bluetooth address of the AG
 * @param gain Valid range: [0,15]
 */
void hfp_hf_set_speaker_gain(bd_addr_t bd_addr, int gain);

/*
 * @brief Instruct the AG to transmit a DTMF code.
 * @param bd_addr Bluetooth address of the AG
 * @param dtmf_code
 */
void hfp_hf_send_dtmf_code(bd_addr_t bd_addr, 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 bd_addr Bluetooth address of the AG
 */
void hfp_hf_request_phone_number_for_voice_tag(bd_addr_t addr);

/*
 * @brief Query the list of current calls in AG. 
 * The result is received via HFP_SUBEVENT_ENHANCED_CALL_STATUS.
 * @param bd_addr Bluetooth address of the AG
 */
void hfp_hf_query_current_call_status(bd_addr_t addr);

/*
 * @brief Release a call with index in the AG.
 * @param bd_addr Bluetooth address of the AG
 * @param index
 */
void hfp_hf_release_call_with_index(bd_addr_t addr, int index);

/*
 * @brief Place all parties of a multiparty call on hold with the 
 * exception of the specified call.
 * @param bd_addr Bluetooth address of the AG
 * @param index
 */
void hfp_hf_private_consultation_with_call(bd_addr_t addr, 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 bd_addr Bluetooth address of the AG
 */
void hfp_hf_rrh_query_status(bd_addr_t addr);

/*
 * @brief Put an incoming call on hold in the AG.
 * @param bd_addr Bluetooth address of the AG
 */
void hfp_hf_rrh_hold_call(bd_addr_t addr);

/*
 * @brief Accept held incoming call in the AG.
 * @param bd_addr Bluetooth address of the AG
 */
void hfp_hf_rrh_accept_held_call(bd_addr_t addr);

/*
 * @brief Reject held incoming call in the AG.
 * @param bd_addr Bluetooth address of the AG
 */
void hfp_hf_rrh_reject_held_call(bd_addr_t addr);

/*
 * @brief Query the AG subscriber number.
 * The result is reported via HFP_SUBEVENT_SUBSCRIBER_NUMBER_INFORMATION.
 * @param bd_addr Bluetooth address of the AG
 */
void hfp_hf_query_subscriber_number(bd_addr_t addr);

/*
 * @brief Set HF indicator.
 * @param bd_addr Bluetooth address of the AG
 * @param assigned_number
 * @param value
 */
void hfp_hf_set_hf_indicator(bd_addr_t addr, int assigned_number, int value);

HFP Audio Gateway API

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
 * @param ability_to_reject_call
 * @param suported_features 32-bit bitmap, see HFP_AGSF_* values in hfp.h
 */
void hfp_ag_create_sdp_record(uint8_t * service, int rfcomm_channel_nr, const char * name, uint8_t ability_to_reject_call, uint16_t supported_features);;

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

/**
 * @brief Set codecs. 
 * @param codecs_nr
 * @param codecs
 */
void hfp_ag_init_codecs(int codecs_nr, 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, 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, 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(hfp_callback_t callback);

/**
 * @brief Enable 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 Bluetooth address of the HF
 */
void 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 bd_addr Bluetooth address of the HF
 */
void hfp_ag_release_service_level_connection(bd_addr_t bd_addr);

/**
 * @brief Establish audio connection.
 * The status of Audio connection establishment is reported via is reported via
 * HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE.
 * @param bd_addr Bluetooth address of the HF
 */
void hfp_ag_establish_audio_connection(bd_addr_t bd_addr);

/**
 * @brief Release audio connection.
 * The status of releasing the Audio connection is reported via is reported via
 * HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE.
 * @param bd_addr Bluetooth address of the HF
 */
void hfp_ag_release_audio_connection(bd_addr_t bd_addr);

/**
 * @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 bd_addr Bluetooth address of the HF
 * @param gain Valid range: [0,15]
 */
void hfp_ag_set_microphone_gain(bd_addr_t bd_addr, int gain);

/*
 * @brief Set speaker gain.
 * @param bd_addr Bluetooth address of the HF
 * @param gain Valid range: [0,15]
 */
void hfp_ag_set_speaker_gain(bd_addr_t bd_addr, int gain);

/*
 * @brief Set battery level.
 * @param level Valid range: [0,5]
 */
void hfp_ag_set_battery_level(int level);

/*
 * @brief Clear last dialed number.
 */
void hfp_ag_clear_last_dialed_number(void);

/*
 * @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 bd_addr Bluetooth address of the HF
 */
void hfp_ag_notify_incoming_call_waiting(bd_addr_t bd_addr);

// Voice Recognition

/*
 * @brief Activate voice recognition.
 * @param bd_addr Bluetooth address of the HF
 * @param activate
 */
void hfp_ag_activate_voice_recognition(bd_addr_t bd_addr, int activate);

/*
 * @brief Send a phone number back to the HF.
 * @param bd_addr Bluetooth address of the HF
 * @param phone_number
 */
void hfp_ag_send_phone_number_for_voice_tag(bd_addr_t bd_addr, const char * phone_number);

/*
 * @brief Reject sending a phone number to the HF.
 * @param bd_addr Bluetooth address of the HF
 */
void hfp_ag_reject_phone_number_for_voice_tag(bd_addr_t bd_addr);

/**
 * @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 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 droped event to the AG.
 */
void hfp_ag_call_dropped(void);

/*
 * @brief Set network registration status.  
 * @param status 0 - not registered, 1 - registered 
 */
void hfp_ag_set_registration_status(int status);

/*
 * @brief Set network signal strength.
 * @param strength [0-5]
 */
void hfp_ag_set_signal_strength(int strength);

/*
 * @brief Set roaming status.
 * @param status 0 - no roaming, 1 - roaming active
 */
void hfp_ag_set_roaming_status(int 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 bd_addr Bluetooth address of the HF 
 */
void hfp_ag_send_dtmf_code_done(bd_addr_t bd_addr);

/**
 * @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 bd_addr Bluetooth address of the HF
 * @param error
 */
void hfp_ag_report_extended_audio_gateway_error_result_code(bd_addr_t bd_addr, hfp_cme_error_t error);