mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-02-20 18:40:31 +00:00
hfp: sdp query
This commit is contained in:
parent
92fdd6fa5f
commit
ea5029c9a4
@ -50,10 +50,6 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "btstack-config.h"
|
||||
#include "hci.h"
|
||||
#include "l2cap.h"
|
||||
#include "rfcomm.h"
|
||||
|
||||
|
||||
// MARK: hci_connection_t
|
||||
@ -412,6 +408,39 @@ void btstack_memory_bnep_channel_free(bnep_channel_t *bnep_channel){
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// MARK: hfp_connection_t
|
||||
#ifdef MAX_NO_HFP_CONNECTIONS
|
||||
#if MAX_NO_HFP_CONNECTIONS > 0
|
||||
static hfp_connection_t hfp_connection_storage[MAX_NO_HFP_CONNECTIONS];
|
||||
static memory_pool_t hfp_connection_pool;
|
||||
hfp_connection_t * btstack_memory_hfp_connection_get(void){
|
||||
return (hfp_connection_t *) memory_pool_get(&hfp_connection_pool);
|
||||
}
|
||||
void btstack_memory_hfp_connection_free(hfp_connection_t *hfp_connection){
|
||||
memory_pool_free(&hfp_connection_pool, hfp_connection);
|
||||
}
|
||||
#else
|
||||
hfp_connection_t * btstack_memory_hfp_connection_get(void){
|
||||
return NULL;
|
||||
}
|
||||
void btstack_memory_hfp_connection_free(hfp_connection_t *hfp_connection){
|
||||
// silence compiler warning about unused parameter in a portable way
|
||||
(void) hfp_connection;
|
||||
};
|
||||
#endif
|
||||
#elif defined(HAVE_MALLOC)
|
||||
hfp_connection_t * btstack_memory_hfp_connection_get(void){
|
||||
return (hfp_connection_t*) malloc(sizeof(hfp_connection_t));
|
||||
}
|
||||
void btstack_memory_hfp_connection_free(hfp_connection_t *hfp_connection){
|
||||
free(hfp_connection);
|
||||
}
|
||||
#else
|
||||
#error "Neither HAVE_MALLOC nor MAX_NO_HFP_CONNECTIONS for struct hfp_connection is defined. Please, edit the config file."
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_BLE
|
||||
|
||||
// MARK: gatt_client_t
|
||||
@ -514,6 +543,9 @@ void btstack_memory_init(void){
|
||||
#if MAX_NO_BNEP_CHANNELS > 0
|
||||
memory_pool_create(&bnep_channel_pool, bnep_channel_storage, MAX_NO_BNEP_CHANNELS, sizeof(bnep_channel_t));
|
||||
#endif
|
||||
#if MAX_NO_HFP_CONNECTIONS > 0
|
||||
memory_pool_create(&hfp_connection_pool, hfp_connection_storage, MAX_NO_HFP_CONNECTIONS, sizeof(hfp_connection_t));
|
||||
#endif
|
||||
#ifdef HAVE_BLE
|
||||
#if MAX_NO_GATT_CLIENTS > 0
|
||||
memory_pool_create(&gatt_client_pool, gatt_client_storage, MAX_NO_GATT_CLIENTS, sizeof(gatt_client_t));
|
||||
|
@ -57,6 +57,7 @@ extern "C" {
|
||||
#include "l2cap.h"
|
||||
#include "rfcomm.h"
|
||||
#include "bnep.h"
|
||||
#include "hfp.h"
|
||||
#include "remote_device_db.h"
|
||||
|
||||
#ifdef HAVE_BLE
|
||||
@ -104,6 +105,10 @@ void btstack_memory_bnep_service_free(bnep_service_t *bnep_service);
|
||||
bnep_channel_t * btstack_memory_bnep_channel_get(void);
|
||||
void btstack_memory_bnep_channel_free(bnep_channel_t *bnep_channel);
|
||||
|
||||
// hfp_connection
|
||||
hfp_connection_t * btstack_memory_hfp_connection_get(void);
|
||||
void btstack_memory_hfp_connection_free(hfp_connection_t *hfp_connection);
|
||||
|
||||
#ifdef HAVE_BLE
|
||||
// gatt_client, gatt_subclient
|
||||
gatt_client_t * btstack_memory_gatt_client_get(void);
|
||||
|
257
src/hfp.c
Normal file
257
src/hfp.c
Normal file
@ -0,0 +1,257 @@
|
||||
/*
|
||||
* Copyright (C) 2014 BlueKitchen GmbH
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
* 4. Any redistribution, use, or modification is done solely for
|
||||
* personal benefit and not for any commercial purpose or for
|
||||
* monetary gain.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
|
||||
* RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* Please inquire about commercial licensing options at
|
||||
* contact@bluekitchen-gmbh.com
|
||||
*
|
||||
*/
|
||||
|
||||
// *****************************************************************************
|
||||
//
|
||||
// Minimal setup for HFP Audio Gateway (AG) unit (!! UNDER DEVELOPMENT !!)
|
||||
//
|
||||
// *****************************************************************************
|
||||
|
||||
#include "btstack-config.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <btstack/hci_cmds.h>
|
||||
#include <btstack/run_loop.h>
|
||||
|
||||
#include "hci.h"
|
||||
#include "btstack_memory.h"
|
||||
#include "hci_dump.h"
|
||||
#include "l2cap.h"
|
||||
#include "sdp_query_rfcomm.h"
|
||||
#include "sdp.h"
|
||||
#include "debug.h"
|
||||
#include "hfp_ag.h"
|
||||
|
||||
static hfp_callback_t hfp_callback;
|
||||
static linked_list_t hfp_connections = NULL;
|
||||
|
||||
static hfp_connection_t * get_hfp_connection_context_for_handle(uint16_t handle){
|
||||
linked_item_t *it;
|
||||
for (it = (linked_item_t *) &hfp_connections; it ; it = it->next){
|
||||
hfp_connection_t * connection = (hfp_connection_t *) it;
|
||||
if (connection->con_handle == handle){
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static hfp_connection_t * get_hfp_connection_context_for_bd_addr(bd_addr_t bd_addr){
|
||||
linked_item_t *it;
|
||||
for (it = (linked_item_t *) &hfp_connections; it ; it = it->next){
|
||||
hfp_connection_t * connection = (hfp_connection_t *) it;
|
||||
if (memcmp(connection->remote_addr, bd_addr, 6) == 0) {
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static hfp_connection_t * create_hfp_connection_context(){
|
||||
hfp_connection_t * context = btstack_memory_hfp_connection_get();
|
||||
if (!context) return NULL;
|
||||
// init state
|
||||
context->state = HFP_IDLE;
|
||||
linked_list_add(&hfp_connections, (linked_item_t*)context);
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
static hfp_connection_t * provide_hfp_connection_context_for_bd_addr(bd_addr_t bd_addr){
|
||||
hfp_connection_t * context = get_hfp_connection_context_for_bd_addr(bd_addr);
|
||||
if (context) return context;
|
||||
context = create_hfp_connection_context();
|
||||
memcpy(context->remote_addr, bd_addr, 6);
|
||||
return context;
|
||||
}
|
||||
|
||||
hfp_connection_t * provide_hfp_connection_context_for_conn_handle(uint16_t con_handle){
|
||||
hfp_connection_t * context = get_hfp_connection_context_for_handle(con_handle);
|
||||
if (context) return context;
|
||||
context = create_hfp_connection_context();
|
||||
context->con_handle = con_handle;
|
||||
return context;
|
||||
}
|
||||
|
||||
void hfp_register_packet_handler(hfp_callback_t callback){
|
||||
if (callback == NULL){
|
||||
log_error("hfp_register_packet_handler called with NULL callback");
|
||||
return;
|
||||
}
|
||||
hfp_callback = callback;
|
||||
}
|
||||
|
||||
void hfp_create_service(uint8_t * service, uint16_t service_uuid, int rfcomm_channel_nr, const char * name, uint16_t supported_features){
|
||||
uint8_t* attribute;
|
||||
de_create_sequence(service);
|
||||
|
||||
// 0x0000 "Service Record Handle"
|
||||
de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ServiceRecordHandle);
|
||||
de_add_number(service, DE_UINT, DE_SIZE_32, 0x10001);
|
||||
|
||||
// 0x0001 "Service Class ID List"
|
||||
de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ServiceClassIDList);
|
||||
attribute = de_push_sequence(service);
|
||||
{
|
||||
// "UUID for Service"
|
||||
de_add_number(attribute, DE_UUID, DE_SIZE_16, service_uuid);
|
||||
de_add_number(attribute, DE_UUID, DE_SIZE_16, SDP_GenericAudio);
|
||||
}
|
||||
de_pop_sequence(service, attribute);
|
||||
|
||||
// 0x0004 "Protocol Descriptor List"
|
||||
de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ProtocolDescriptorList);
|
||||
attribute = de_push_sequence(service);
|
||||
{
|
||||
uint8_t* l2cpProtocol = de_push_sequence(attribute);
|
||||
{
|
||||
de_add_number(l2cpProtocol, DE_UUID, DE_SIZE_16, SDP_L2CAPProtocol);
|
||||
}
|
||||
de_pop_sequence(attribute, l2cpProtocol);
|
||||
|
||||
uint8_t* rfcomm = de_push_sequence(attribute);
|
||||
{
|
||||
de_add_number(rfcomm, DE_UUID, DE_SIZE_16, SDP_RFCOMMProtocol); // rfcomm_service
|
||||
de_add_number(rfcomm, DE_UINT, DE_SIZE_8, rfcomm_channel_nr); // rfcomm channel
|
||||
}
|
||||
de_pop_sequence(attribute, rfcomm);
|
||||
}
|
||||
de_pop_sequence(service, attribute);
|
||||
|
||||
|
||||
// 0x0005 "Public Browse Group"
|
||||
de_add_number(service, DE_UINT, DE_SIZE_16, SDP_BrowseGroupList); // public browse group
|
||||
attribute = de_push_sequence(service);
|
||||
{
|
||||
de_add_number(attribute, DE_UUID, DE_SIZE_16, SDP_PublicBrowseGroup);
|
||||
}
|
||||
de_pop_sequence(service, attribute);
|
||||
|
||||
// 0x0009 "Bluetooth Profile Descriptor List"
|
||||
de_add_number(service, DE_UINT, DE_SIZE_16, SDP_BluetoothProfileDescriptorList);
|
||||
attribute = de_push_sequence(service);
|
||||
{
|
||||
uint8_t *sppProfile = de_push_sequence(attribute);
|
||||
{
|
||||
de_add_number(sppProfile, DE_UUID, DE_SIZE_16, SDP_Handsfree);
|
||||
de_add_number(sppProfile, DE_UINT, DE_SIZE_16, 0x0107); // Verision 1.7
|
||||
}
|
||||
de_pop_sequence(attribute, sppProfile);
|
||||
}
|
||||
de_pop_sequence(service, attribute);
|
||||
|
||||
// 0x0100 "Service Name"
|
||||
de_add_number(service, DE_UINT, DE_SIZE_16, 0x0100);
|
||||
de_add_data(service, DE_STRING, strlen(name), (uint8_t *) name);
|
||||
|
||||
de_add_number(service, DE_UINT, DE_SIZE_16, supported_features);
|
||||
/* Bit position:
|
||||
* 0: EC and/or NR function (yes/no, 1 = yes, 0 = no)
|
||||
* 1: Call waiting or three-way calling(yes/no, 1 = yes, 0 = no)
|
||||
* 2: CLI presentation capability (yes/no, 1 = yes, 0 = no)
|
||||
* 3: Voice recognition activation (yes/no, 1= yes, 0 = no)
|
||||
* 4: Remote volume control (yes/no, 1 = yes, 0 = no)
|
||||
* 5: Wide band speech (yes/no, 1 = yes, 0 = no)
|
||||
*/
|
||||
}
|
||||
|
||||
static hfp_connection_t * connection_doing_sdp_query = NULL;
|
||||
static void handle_query_rfcomm_event(sdp_query_event_t * event, void * context){
|
||||
sdp_query_rfcomm_service_event_t * ve;
|
||||
sdp_query_complete_event_t * ce;
|
||||
hfp_connection_t * connection = connection_doing_sdp_query;
|
||||
|
||||
switch (event->type){
|
||||
case SDP_QUERY_RFCOMM_SERVICE:
|
||||
ve = (sdp_query_rfcomm_service_event_t*) event;
|
||||
if (!connection) {
|
||||
log_error("handle_query_rfcomm_event alloc connection for RFCOMM port %u failed", ve->channel_nr);
|
||||
return;
|
||||
}
|
||||
connection->rfcomm_channel_nr = ve->channel_nr;
|
||||
break;
|
||||
case SDP_QUERY_COMPLETE:
|
||||
connection_doing_sdp_query = NULL;
|
||||
ce = (sdp_query_complete_event_t*) event;
|
||||
|
||||
if (connection->rfcomm_channel_nr > 0){
|
||||
connection->state = HFP_W4_RFCOMM_CONNECTED;
|
||||
rfcomm_create_channel_internal(NULL, connection->remote_addr, connection->rfcomm_channel_nr);
|
||||
break;
|
||||
}
|
||||
log_info("rfcomm service not found, status %u.", ce->status);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void packet_handler (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
|
||||
// printf("packet_handler type %u, packet[0] %x\n", packet_type, packet[0]);
|
||||
if (packet_type == RFCOMM_DATA_PACKET){
|
||||
}
|
||||
|
||||
if (packet_type != HCI_EVENT_PACKET) return;
|
||||
}
|
||||
|
||||
|
||||
void hfp_init(uint16_t rfcomm_channel_nr){
|
||||
rfcomm_register_service_internal(NULL, rfcomm_channel_nr, 0xffff);
|
||||
|
||||
l2cap_register_packet_handler(packet_handler);
|
||||
rfcomm_register_packet_handler(packet_handler);
|
||||
|
||||
sdp_query_rfcomm_register_callback(handle_query_rfcomm_event, NULL);
|
||||
}
|
||||
|
||||
void hfp_connect(bd_addr_t bd_addr){
|
||||
hfp_connection_t * connection = provide_hfp_connection_context_for_bd_addr(bd_addr);
|
||||
if (!connection) {
|
||||
log_error("hfp_hf_connect for addr %s failed", bd_addr_to_str(bd_addr));
|
||||
return;
|
||||
}
|
||||
|
||||
if (connection->state != HFP_IDLE) return;
|
||||
connection->state = HFP_SDP_QUERY_RFCOMM_CHANNEL;
|
||||
memcpy(connection->remote_addr, bd_addr, 6);
|
||||
connection_doing_sdp_query = connection;
|
||||
// @TODO trigger SDP query
|
||||
}
|
93
src/hfp.h
Normal file
93
src/hfp.h
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (C) 2014 BlueKitchen GmbH
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
* 4. Any redistribution, use, or modification is done solely for
|
||||
* personal benefit and not for any commercial purpose or for
|
||||
* monetary gain.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
|
||||
* RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* Please inquire about commercial licensing options at
|
||||
* contact@bluekitchen-gmbh.com
|
||||
*
|
||||
*/
|
||||
|
||||
// *****************************************************************************
|
||||
//
|
||||
// HFP Hands-Free (HF) unit and Audio-Gateway Commons
|
||||
//
|
||||
// *****************************************************************************
|
||||
|
||||
|
||||
#ifndef btstack_hfp_h
|
||||
#define btstack_hfp_h
|
||||
|
||||
#include "hci.h"
|
||||
#include "sdp_query_rfcomm.h"
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
HFP_IDLE,
|
||||
HFP_SDP_QUERY_RFCOMM_CHANNEL,
|
||||
HFP_W4_SDP_QUERY_COMPLETE,
|
||||
HFP_W4_RFCOMM_CONNECTED,
|
||||
HFP_ACTIVE,
|
||||
HFP_W2_DISCONNECT_RFCOMM,
|
||||
HFP_W4_RFCOMM_DISCONNECTED,
|
||||
HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN
|
||||
} hfp_state_t;
|
||||
|
||||
typedef void (*hfp_callback_t)(uint8_t * event, uint16_t event_size);
|
||||
|
||||
typedef struct hfp_connection {
|
||||
linked_item_t item;
|
||||
hfp_state_t state;
|
||||
|
||||
bd_addr_t remote_addr;
|
||||
uint16_t con_handle;
|
||||
uint16_t rfcomm_channel_nr;
|
||||
uint16_t rfcomm_cid;
|
||||
|
||||
hfp_callback_t callback;
|
||||
} hfp_connection_t;
|
||||
|
||||
|
||||
void hfp_create_service(uint8_t * service, uint16_t service_uuid, int rfcomm_channel_nr, const char * name, uint16_t supported_features);
|
||||
|
||||
void hfp_init(uint16_t rfcomm_channel_nr);
|
||||
void hfp_register_packet_handler(hfp_callback_t callback);
|
||||
|
||||
hfp_connection_t * provide_hfp_connection_context_for_conn_handle(uint16_t con_handle);
|
||||
void hfp_connect(bd_addr_t bd_addr);
|
||||
|
||||
#if defined __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
148
src/hfp_ag.c
148
src/hfp_ag.c
@ -58,106 +58,18 @@
|
||||
#include "sdp_query_rfcomm.h"
|
||||
#include "sdp.h"
|
||||
#include "debug.h"
|
||||
#include "hfp.h"
|
||||
#include "hfp_ag.h"
|
||||
|
||||
typedef enum {
|
||||
HFP_IDLE,
|
||||
HFP_SDP_QUERY_RFCOMM_CHANNEL,
|
||||
HFP_W4_SDP_QUERY_COMPLETE,
|
||||
HFP_W4_RFCOMM_CONNECTED,
|
||||
HFP_ACTIVE,
|
||||
HFP_W2_DISCONNECT_RFCOMM,
|
||||
HFP_W4_RFCOMM_DISCONNECTED,
|
||||
HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN
|
||||
} hfp_state_t;
|
||||
|
||||
static hfp_state_t hfp_state = HFP_IDLE;
|
||||
|
||||
static const char default_hfp_ag_service_name[] = "Voice gateway";
|
||||
static bd_addr_t remote;
|
||||
static uint8_t channel_nr = 0;
|
||||
|
||||
static hfp_ag_callback_t hfp_ag_callback;
|
||||
|
||||
static void hfp_run();
|
||||
static void packet_handler (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
|
||||
static void handle_query_rfcomm_event(sdp_query_event_t * event, void * context);
|
||||
|
||||
static void dummy_notify(uint8_t * event, uint16_t size){}
|
||||
|
||||
void hfp_ag_register_packet_handler(hfp_ag_callback_t callback){
|
||||
if (callback == NULL){
|
||||
callback = &dummy_notify;
|
||||
}
|
||||
hfp_ag_callback = callback;
|
||||
}
|
||||
|
||||
void hfp_ag_create_service(uint8_t * service, int rfcomm_channel_nr, const char * name, uint8_t ability_to_reject_call, uint16_t supported_features){
|
||||
uint8_t* attribute;
|
||||
de_create_sequence(service);
|
||||
|
||||
// 0x0000 "Service Record Handle"
|
||||
de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ServiceRecordHandle);
|
||||
de_add_number(service, DE_UINT, DE_SIZE_32, 0x10001);
|
||||
|
||||
// 0x0001 "Service Class ID List"
|
||||
de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ServiceClassIDList);
|
||||
attribute = de_push_sequence(service);
|
||||
{
|
||||
// "UUID for PAN Service"
|
||||
de_add_number(attribute, DE_UUID, DE_SIZE_16, SDP_HandsfreeAudioGateway);
|
||||
de_add_number(attribute, DE_UUID, DE_SIZE_16, SDP_GenericAudio);
|
||||
}
|
||||
de_pop_sequence(service, attribute);
|
||||
|
||||
// 0x0004 "Protocol Descriptor List"
|
||||
de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ProtocolDescriptorList);
|
||||
attribute = de_push_sequence(service);
|
||||
{
|
||||
uint8_t* l2cpProtocol = de_push_sequence(attribute);
|
||||
{
|
||||
de_add_number(l2cpProtocol, DE_UUID, DE_SIZE_16, SDP_L2CAPProtocol);
|
||||
}
|
||||
de_pop_sequence(attribute, l2cpProtocol);
|
||||
|
||||
uint8_t* rfcomm = de_push_sequence(attribute);
|
||||
{
|
||||
de_add_number(rfcomm, DE_UUID, DE_SIZE_16, SDP_RFCOMMProtocol); // rfcomm_service
|
||||
de_add_number(rfcomm, DE_UINT, DE_SIZE_8, rfcomm_channel_nr); // rfcomm channel
|
||||
}
|
||||
de_pop_sequence(attribute, rfcomm);
|
||||
}
|
||||
de_pop_sequence(service, attribute);
|
||||
|
||||
|
||||
// 0x0005 "Public Browse Group"
|
||||
de_add_number(service, DE_UINT, DE_SIZE_16, SDP_BrowseGroupList); // public browse group
|
||||
attribute = de_push_sequence(service);
|
||||
{
|
||||
de_add_number(attribute, DE_UUID, DE_SIZE_16, SDP_PublicBrowseGroup);
|
||||
}
|
||||
de_pop_sequence(service, attribute);
|
||||
|
||||
// 0x0009 "Bluetooth Profile Descriptor List"
|
||||
de_add_number(service, DE_UINT, DE_SIZE_16, SDP_BluetoothProfileDescriptorList);
|
||||
attribute = de_push_sequence(service);
|
||||
{
|
||||
uint8_t *sppProfile = de_push_sequence(attribute);
|
||||
{
|
||||
de_add_number(sppProfile, DE_UUID, DE_SIZE_16, SDP_Handsfree);
|
||||
de_add_number(sppProfile, DE_UINT, DE_SIZE_16, 0x0107); // Verision 1.7
|
||||
}
|
||||
de_pop_sequence(attribute, sppProfile);
|
||||
}
|
||||
de_pop_sequence(service, attribute);
|
||||
|
||||
// 0x0100 "Service Name"
|
||||
de_add_number(service, DE_UINT, DE_SIZE_16, 0x0100);
|
||||
if (name){
|
||||
de_add_data(service, DE_STRING, strlen(name), (uint8_t *) name);
|
||||
} else {
|
||||
de_add_data(service, DE_STRING, strlen(default_hfp_ag_service_name), (uint8_t *) default_hfp_ag_service_name);
|
||||
if (!name){
|
||||
name = default_hfp_ag_service_name;
|
||||
}
|
||||
hfp_create_service(service, SDP_HandsfreeAudioGateway, rfcomm_channel_nr, name, supported_features);
|
||||
|
||||
// Network
|
||||
de_add_number(service, DE_UINT, DE_SIZE_8, ability_to_reject_call);
|
||||
@ -165,26 +77,13 @@ void hfp_ag_create_service(uint8_t * service, int rfcomm_channel_nr, const char
|
||||
* 0x01 – Ability to reject a call
|
||||
* 0x00 – No ability to reject a call
|
||||
*/
|
||||
|
||||
// SupportedFeatures
|
||||
de_add_number(service, DE_UINT, DE_SIZE_16, supported_features);
|
||||
/* Bit position:
|
||||
* 0: EC and/or NR function (yes/no, 1 = yes, 0 = no)
|
||||
* 1: Call waiting or three-way calling(yes/no, 1 = yes, 0 = no)
|
||||
* 2: CLI presentation capability (yes/no, 1 = yes, 0 = no)
|
||||
* 3: Voice recognition activation (yes/no, 1= yes, 0 = no)
|
||||
* 4: Remote volume control (yes/no, 1 = yes, 0 = no)
|
||||
* 5: Wide band speech (yes/no, 1 = yes, 0 = no)
|
||||
*/
|
||||
}
|
||||
|
||||
void hfp_ag_init(uint8_t rfcomm_channel_nr){
|
||||
hfp_run();
|
||||
}
|
||||
|
||||
void hfp_ag_connect(bd_addr_t bd_addr){
|
||||
hfp_connect(bd_addr);
|
||||
hfp_run();
|
||||
}
|
||||
|
||||
void hfp_ag_disconnect(){
|
||||
hfp_run();
|
||||
}
|
||||
@ -192,38 +91,3 @@ void hfp_ag_disconnect(){
|
||||
static void hfp_run(void){
|
||||
}
|
||||
|
||||
static void packet_handler (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
|
||||
// printf("packet_handler type %u, packet[0] %x\n", packet_type, packet[0]);
|
||||
if (packet_type == RFCOMM_DATA_PACKET){
|
||||
}
|
||||
|
||||
if (packet_type != HCI_EVENT_PACKET) return;
|
||||
}
|
||||
|
||||
static void handle_query_rfcomm_event(sdp_query_event_t * event, void * context){
|
||||
sdp_query_rfcomm_service_event_t * ve;
|
||||
sdp_query_complete_event_t * ce;
|
||||
|
||||
switch (event->type){
|
||||
case SDP_QUERY_RFCOMM_SERVICE:
|
||||
ve = (sdp_query_rfcomm_service_event_t*) event;
|
||||
channel_nr = ve->channel_nr;
|
||||
printf("** Service name: '%s', RFCOMM port %u\n", ve->service_name, channel_nr);
|
||||
break;
|
||||
case SDP_QUERY_COMPLETE:
|
||||
ce = (sdp_query_complete_event_t*) event;
|
||||
|
||||
if (channel_nr > 0){
|
||||
hfp_state = HFP_W4_RFCOMM_CONNECTED;
|
||||
printf("RFCOMM create channel. state %d\n", HFP_W4_RFCOMM_CONNECTED);
|
||||
rfcomm_create_channel_internal(NULL, remote, channel_nr);
|
||||
break;
|
||||
}
|
||||
// hfp_ag_reset_state();
|
||||
printf("Service not found, status %u.\n", ce->status);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,17 +47,13 @@
|
||||
|
||||
#include "hci.h"
|
||||
#include "sdp_query_rfcomm.h"
|
||||
#include "hfp.h"
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*hfp_ag_callback_t)(uint8_t * event, uint16_t event_size);
|
||||
// Register callback (packet handler) for hsp headset
|
||||
void hfp_ag_register_packet_handler(hfp_ag_callback_t callback);
|
||||
void hfp_ag_create_service(uint8_t * service, int rfcomm_channel_nr, const char * name, uint8_t ability_to_reject_call, uint16_t supported_features);
|
||||
|
||||
void hfp_ag_init(uint8_t rfcomm_channel_nr);
|
||||
void hfp_ag_connect(bd_addr_t bd_addr);
|
||||
void hfp_ag_disconnect();
|
||||
|
||||
|
145
src/hfp_hf.c
145
src/hfp_hf.c
@ -58,126 +58,37 @@
|
||||
#include "sdp_query_rfcomm.h"
|
||||
#include "sdp.h"
|
||||
#include "debug.h"
|
||||
#include "hfp.h"
|
||||
#include "hfp_hf.h"
|
||||
|
||||
typedef enum {
|
||||
HFP_IDLE,
|
||||
HFP_SDP_QUERY_RFCOMM_CHANNEL,
|
||||
HFP_W4_SDP_QUERY_COMPLETE,
|
||||
HFP_W4_RFCOMM_CONNECTED,
|
||||
HFP_ACTIVE,
|
||||
HFP_W2_DISCONNECT_RFCOMM,
|
||||
HFP_W4_RFCOMM_DISCONNECTED,
|
||||
HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN
|
||||
} hfp_state_t;
|
||||
|
||||
static hfp_state_t hfp_state = HFP_IDLE;
|
||||
|
||||
|
||||
static const char default_hfp_hf_service_name[] = "Hands-Free unit";
|
||||
static bd_addr_t remote;
|
||||
static uint8_t channel_nr = 0;
|
||||
|
||||
static hfp_hf_callback_t hfp_hf_callback;
|
||||
|
||||
static void hfp_run();
|
||||
static void packet_handler (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
|
||||
static void handle_query_rfcomm_event(sdp_query_event_t * event, void * context);
|
||||
|
||||
static void dummy_notify(uint8_t * event, uint16_t size){}
|
||||
|
||||
void hfp_hf_register_packet_handler(hfp_hf_callback_t callback){
|
||||
if (callback == NULL){
|
||||
callback = &dummy_notify;
|
||||
}
|
||||
hfp_hf_callback = callback;
|
||||
}
|
||||
|
||||
void hfp_hf_create_service(uint8_t * service, int rfcomm_channel_nr, const char * name, uint16_t supported_features){
|
||||
uint8_t* attribute;
|
||||
de_create_sequence(service);
|
||||
|
||||
// 0x0000 "Service Record Handle"
|
||||
de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ServiceRecordHandle);
|
||||
de_add_number(service, DE_UINT, DE_SIZE_32, 0x10001);
|
||||
|
||||
// 0x0001 "Service Class ID List"
|
||||
de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ServiceClassIDList);
|
||||
attribute = de_push_sequence(service);
|
||||
{
|
||||
// "UUID for PAN Service"
|
||||
de_add_number(attribute, DE_UUID, DE_SIZE_16, SDP_Handsfree);
|
||||
de_add_number(attribute, DE_UUID, DE_SIZE_16, SDP_GenericAudio);
|
||||
if (!name){
|
||||
name = default_hfp_hf_service_name;
|
||||
}
|
||||
de_pop_sequence(service, attribute);
|
||||
|
||||
// 0x0004 "Protocol Descriptor List"
|
||||
de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ProtocolDescriptorList);
|
||||
attribute = de_push_sequence(service);
|
||||
{
|
||||
uint8_t* l2cpProtocol = de_push_sequence(attribute);
|
||||
{
|
||||
de_add_number(l2cpProtocol, DE_UUID, DE_SIZE_16, SDP_L2CAPProtocol);
|
||||
}
|
||||
de_pop_sequence(attribute, l2cpProtocol);
|
||||
|
||||
uint8_t* rfcomm = de_push_sequence(attribute);
|
||||
{
|
||||
de_add_number(rfcomm, DE_UUID, DE_SIZE_16, SDP_RFCOMMProtocol); // rfcomm_service
|
||||
de_add_number(rfcomm, DE_UINT, DE_SIZE_8, rfcomm_channel_nr); // rfcomm channel
|
||||
}
|
||||
de_pop_sequence(attribute, rfcomm);
|
||||
}
|
||||
de_pop_sequence(service, attribute);
|
||||
|
||||
|
||||
// 0x0005 "Public Browse Group"
|
||||
de_add_number(service, DE_UINT, DE_SIZE_16, SDP_BrowseGroupList); // public browse group
|
||||
attribute = de_push_sequence(service);
|
||||
{
|
||||
de_add_number(attribute, DE_UUID, DE_SIZE_16, SDP_PublicBrowseGroup);
|
||||
}
|
||||
de_pop_sequence(service, attribute);
|
||||
|
||||
// 0x0009 "Bluetooth Profile Descriptor List"
|
||||
de_add_number(service, DE_UINT, DE_SIZE_16, SDP_BluetoothProfileDescriptorList);
|
||||
attribute = de_push_sequence(service);
|
||||
{
|
||||
uint8_t *sppProfile = de_push_sequence(attribute);
|
||||
{
|
||||
de_add_number(sppProfile, DE_UUID, DE_SIZE_16, SDP_Handsfree);
|
||||
de_add_number(sppProfile, DE_UINT, DE_SIZE_16, 0x0107); // Verision 1.7
|
||||
}
|
||||
de_pop_sequence(attribute, sppProfile);
|
||||
}
|
||||
de_pop_sequence(service, attribute);
|
||||
|
||||
// 0x0100 "Service Name"
|
||||
de_add_number(service, DE_UINT, DE_SIZE_16, 0x0100);
|
||||
if (name){
|
||||
de_add_data(service, DE_STRING, strlen(name), (uint8_t *) name);
|
||||
} else {
|
||||
de_add_data(service, DE_STRING, strlen(default_hfp_hf_service_name), (uint8_t *) default_hfp_hf_service_name);
|
||||
}
|
||||
|
||||
de_add_number(service, DE_UINT, DE_SIZE_16, supported_features);
|
||||
/* Bit position:
|
||||
* 0: EC and/or NR function (yes/no, 1 = yes, 0 = no)
|
||||
* 1: Call waiting or three-way calling(yes/no, 1 = yes, 0 = no)
|
||||
* 2: CLI presentation capability (yes/no, 1 = yes, 0 = no)
|
||||
* 3: Voice recognition activation (yes/no, 1= yes, 0 = no)
|
||||
* 4: Remote volume control (yes/no, 1 = yes, 0 = no)
|
||||
* 5: Wide band speech (yes/no, 1 = yes, 0 = no)
|
||||
*/
|
||||
hfp_create_service(service, SDP_Handsfree, rfcomm_channel_nr, name, supported_features);
|
||||
}
|
||||
|
||||
void hfp_hf_init(uint8_t rfcomm_channel_nr){
|
||||
hfp_run();
|
||||
}
|
||||
|
||||
// static void hfp_hf_reset_state(uint16_t con_handle){
|
||||
// hfp_connection_t * connection = provide_hfp_connection_context_for_conn_handle(con_handle);
|
||||
// if (!connection) {
|
||||
// log_error("hfp_hf_reset_state for handle 0x%02x failed", con_handle);
|
||||
// return;
|
||||
// }
|
||||
// connection->state = HFP_IDLE;
|
||||
// }
|
||||
|
||||
void hfp_hf_connect(bd_addr_t bd_addr){
|
||||
hfp_connect(bd_addr);
|
||||
hfp_run();
|
||||
}
|
||||
|
||||
void hfp_hf_disconnect(){
|
||||
hfp_run();
|
||||
}
|
||||
@ -193,29 +104,3 @@ static void packet_handler (void * connection, uint8_t packet_type, uint16_t cha
|
||||
if (packet_type != HCI_EVENT_PACKET) return;
|
||||
}
|
||||
|
||||
static void handle_query_rfcomm_event(sdp_query_event_t * event, void * context){
|
||||
sdp_query_rfcomm_service_event_t * ve;
|
||||
sdp_query_complete_event_t * ce;
|
||||
|
||||
switch (event->type){
|
||||
case SDP_QUERY_RFCOMM_SERVICE:
|
||||
ve = (sdp_query_rfcomm_service_event_t*) event;
|
||||
channel_nr = ve->channel_nr;
|
||||
printf("** Service name: '%s', RFCOMM port %u\n", ve->service_name, channel_nr);
|
||||
break;
|
||||
case SDP_QUERY_COMPLETE:
|
||||
ce = (sdp_query_complete_event_t*) event;
|
||||
|
||||
if (channel_nr > 0){
|
||||
hfp_state = HFP_W4_RFCOMM_CONNECTED;
|
||||
printf("RFCOMM create channel. state %d\n", HFP_W4_RFCOMM_CONNECTED);
|
||||
rfcomm_create_channel_internal(NULL, remote, channel_nr);
|
||||
break;
|
||||
}
|
||||
// hfp_ag_reset_state();
|
||||
printf("Service not found, status %u.\n", ce->status);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -47,17 +47,14 @@
|
||||
|
||||
#include "hci.h"
|
||||
#include "sdp_query_rfcomm.h"
|
||||
#include "hfp.h"
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*hfp_hf_callback_t)(uint8_t * event, uint16_t event_size);
|
||||
// Register callback (packet handler) for hsp headset
|
||||
void hfp_hf_register_packet_handler(hfp_hf_callback_t callback);
|
||||
void hfp_hf_create_service(uint8_t * service, int rfcomm_channel_nr, const char * name, uint16_t supported_features);
|
||||
|
||||
void hfp_hf_init(uint8_t rfcomm_channel_nr);
|
||||
void hfp_hf_create_service(uint8_t * service, int rfcomm_channel_nr, const char * name, uint16_t supported_features);
|
||||
void hfp_hf_connect(bd_addr_t bd_addr);
|
||||
void hfp_hf_disconnect();
|
||||
|
||||
|
@ -37,10 +37,10 @@ hsp_ag_test: ${CORE_OBJ} ${COMMON_OBJ} ${SDP_CLIENT} hsp_ag.o hsp_ag_test.c
|
||||
hsp_hs_test: ${CORE_OBJ} ${COMMON_OBJ} ${SDP_CLIENT} hsp_hs.o hsp_hs_test.c
|
||||
${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@
|
||||
|
||||
hfp_hf_test: ${CORE_OBJ} ${COMMON_OBJ} ${SDP_CLIENT} hfp_hf.o hfp_hf_test.c
|
||||
hfp_hf_test: ${CORE_OBJ} ${COMMON_OBJ} ${SDP_CLIENT} hfp.o hfp_hf.o hfp_hf_test.c
|
||||
${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@
|
||||
|
||||
hfp_ag_test: ${CORE_OBJ} ${COMMON_OBJ} ${SDP_CLIENT} hfp_ag.o hfp_ag_test.c
|
||||
hfp_ag_test: ${CORE_OBJ} ${COMMON_OBJ} ${SDP_CLIENT} hfp.o hfp_ag.o hfp_ag_test.c
|
||||
${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@
|
||||
|
||||
l2cap_test: ${CORE_OBJ} ${COMMON_OBJ} l2cap_test.c
|
||||
|
@ -62,6 +62,7 @@
|
||||
|
||||
#include "hci.h"
|
||||
#include "l2cap.h"
|
||||
#include "rfcomm.h"
|
||||
#include "sdp.h"
|
||||
#include "debug.h"
|
||||
#include "hfp_ag.h"
|
||||
@ -74,7 +75,6 @@ const char hfp_ag_service_name[] = "Headset Test";
|
||||
static bd_addr_t pts_addr = {0x00,0x1b,0xDC,0x07,0x32,0xEF};
|
||||
static bd_addr_t local_mac = {0x04, 0x0C, 0xCE, 0xE4, 0x85, 0xD3};
|
||||
|
||||
static char hs_cmd_buffer[100];
|
||||
|
||||
// prototypes
|
||||
static void show_usage();
|
||||
@ -126,16 +126,21 @@ void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
}
|
||||
|
||||
int btstack_main(int argc, const char * argv[]){
|
||||
// init L2CAP
|
||||
l2cap_init();
|
||||
rfcomm_init();
|
||||
|
||||
hfp_init(rfcomm_channel_nr);
|
||||
hfp_register_packet_handler(packet_handler);
|
||||
|
||||
sdp_init();
|
||||
|
||||
// init SDP, create record for SPP and register with SDP
|
||||
memset((uint8_t *)hfp_service_buffer, 0, sizeof(hfp_service_buffer));
|
||||
hfp_ag_create_service((uint8_t *)hfp_service_buffer, rfcomm_channel_nr, hfp_ag_service_name, 0, 0);
|
||||
|
||||
hfp_ag_init(rfcomm_channel_nr);
|
||||
hfp_ag_register_packet_handler(packet_handler);
|
||||
|
||||
sdp_init();
|
||||
sdp_register_service_internal(NULL, (uint8_t *)hfp_service_buffer);
|
||||
|
||||
|
||||
// turn on!
|
||||
hci_power_control(HCI_POWER_ON);
|
||||
|
||||
|
@ -62,6 +62,7 @@
|
||||
|
||||
#include "hci.h"
|
||||
#include "l2cap.h"
|
||||
#include "rfcomm.h"
|
||||
#include "sdp.h"
|
||||
#include "debug.h"
|
||||
#include "hfp_hf.h"
|
||||
@ -73,9 +74,7 @@ const char hfp_hf_service_name[] = "Headset Test";
|
||||
|
||||
static bd_addr_t pts_addr = {0x00,0x1b,0xDC,0x07,0x32,0xEF};
|
||||
static bd_addr_t local_mac = {0x04, 0x0C, 0xCE, 0xE4, 0x85, 0xD3};
|
||||
|
||||
static char hs_cmd_buffer[100];
|
||||
|
||||
|
||||
// prototypes
|
||||
static void show_usage();
|
||||
|
||||
@ -126,14 +125,17 @@ void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
}
|
||||
|
||||
int btstack_main(int argc, const char * argv[]){
|
||||
// init L2CAP
|
||||
l2cap_init();
|
||||
rfcomm_init();
|
||||
|
||||
hfp_init(rfcomm_channel_nr);
|
||||
hfp_register_packet_handler(packet_handler);
|
||||
|
||||
sdp_init();
|
||||
// init SDP, create record for SPP and register with SDP
|
||||
memset((uint8_t *)hfp_service_buffer, 0, sizeof(hfp_service_buffer));
|
||||
hfp_hf_create_service((uint8_t *)hfp_service_buffer, rfcomm_channel_nr, hfp_hf_service_name, 0);
|
||||
|
||||
hfp_hf_init(rfcomm_channel_nr);
|
||||
hfp_hf_register_packet_handler(packet_handler);
|
||||
|
||||
sdp_init();
|
||||
sdp_register_service_internal(NULL, (uint8_t *)hfp_service_buffer);
|
||||
|
||||
// turn on!
|
||||
|
@ -60,6 +60,7 @@ extern "C" {
|
||||
#include "l2cap.h"
|
||||
#include "rfcomm.h"
|
||||
#include "bnep.h"
|
||||
#include "hfp.h"
|
||||
#include "remote_device_db.h"
|
||||
|
||||
#ifdef HAVE_BLE
|
||||
@ -99,10 +100,6 @@ cfile_header_begin = """
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "btstack-config.h"
|
||||
#include "hci.h"
|
||||
#include "l2cap.h"
|
||||
#include "rfcomm.h"
|
||||
"""
|
||||
|
||||
header_template = """STRUCT_NAME_t * btstack_memory_STRUCT_NAME_get(void);
|
||||
@ -155,7 +152,7 @@ def replacePlaceholder(template, struct_name):
|
||||
snippet = template.replace("STRUCT_TYPE", struct_type).replace("STRUCT_NAME", struct_name).replace("POOL_COUNT", pool_count)
|
||||
return snippet
|
||||
|
||||
list_of_structs = [ ["hci_connection"], ["l2cap_service", "l2cap_channel"], ["rfcomm_multiplexer", "rfcomm_service", "rfcomm_channel"], ["db_mem_device_name", "db_mem_device_link_key", "db_mem_service"], ["bnep_service", "bnep_channel"]]
|
||||
list_of_structs = [ ["hci_connection"], ["l2cap_service", "l2cap_channel"], ["rfcomm_multiplexer", "rfcomm_service", "rfcomm_channel"], ["db_mem_device_name", "db_mem_device_link_key", "db_mem_service"], ["bnep_service", "bnep_channel"], ["hfp_connection"]]
|
||||
list_of_le_structs = [["gatt_client", "gatt_subclient"]]
|
||||
|
||||
file_name = "../src/btstack_memory"
|
||||
|
Loading…
x
Reference in New Issue
Block a user