sdp_query: pass in packet handler on query instead of global registration. integrate sdp_parser into sdp_client

This commit is contained in:
Matthias Ringwald 2016-02-17 20:21:21 +01:00
parent 69a7c8111f
commit 6c927b22a9
37 changed files with 506 additions and 631 deletions

View File

@ -21,7 +21,6 @@ apis = [
["src/classic/pan.h", "PAN", "pan"],
["src/classic/rfcomm.h", "RFCOMM", "rfcomm"],
["src/classic/sdp_client.h", "SDP Client", "sdpClient"],
["src/classic/sdp_parser.h","SDP Parser","sdpParser"],
["src/classic/sdp_query_rfcomm.h", "SDP RFCOMM Query", "sdpQueries"],
["src/classic/sdp_query_util.h","SDP Query Utils","sdpQueryUtil"],
["src/classic/sdp_server.h", "SDP Server", "sdpSrv"],

View File

@ -85,7 +85,6 @@
#include "btstack_event.h"
#include "btstack_run_loop.h"
#include "classic/sdp_client.h"
#include "classic/sdp_parser.h"
#include "classic/sdp_query_util.h"
#include "classic/sdp_util.h"
#include "hci.h"
@ -151,10 +150,6 @@ static void panu_setup(void){
bnep_register_packet_handler(packet_handler);
// Minimum L2CAP MTU for bnep is 1691 bytes
bnep_register_service(SDP_PANU, 1691);
// Initialise SDP
sdp_parser_init();
sdp_parser_register_callback(handle_sdp_client_query_result);
}
/* LISTING_END */

View File

@ -55,7 +55,6 @@
#include "btstack_memory.h"
#include "btstack_run_loop.h"
#include "classic/sdp_client.h"
#include "classic/sdp_parser.h"
#include "classic/sdp_query_util.h"
#include "classic/sdp_util.h"
#include "hci.h"
@ -90,7 +89,7 @@ static void assertBuffer(int size){
/* LISTING_START(SDPClientInit): SDP client setup */
static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
static void handle_sdp_client_query_result(uint8_t packet_type, uint8_t *packet, uint16_t size);
static void handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
static void sdp_client_init(void){
@ -100,9 +99,6 @@ static void sdp_client_init(void){
// init L2CAP
l2cap_init();
sdp_parser_init();
sdp_parser_register_callback(handle_sdp_client_query_result);
}
/* LISTING_END */
@ -125,7 +121,7 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
// BTstack activated, get started
if (packet[2] == HCI_STATE_WORKING){
printf("Start SDP BNEP query.\n");
sdp_general_query_for_uuid(remote, SDP_BNEPProtocol);
sdp_general_query_for_uuid(&handle_sdp_client_query_result, remote, SDP_BNEPProtocol);
}
break;
default:
@ -165,7 +161,7 @@ static char * get_string_from_data_element(uint8_t * element){
*/
/* LISTING_START(HandleSDPQUeryResult): Extracting BNEP Protcol UUID and L2CAP PSM */
static void handle_sdp_client_query_result(uint8_t packet_type, uint8_t *packet, uint16_t size){
static void handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
/* LISTING_PAUSE */
des_iterator_t des_list_it;
des_iterator_t prot_it;

View File

@ -54,8 +54,6 @@
#include "btstack_memory.h"
#include "btstack_run_loop.h"
#include "classic/sdp_client.h"
#include "classic/sdp_parser.h"
#include "classic/sdp_parser.h"
#include "classic/sdp_query_util.h"
#include "hci.h"
#include "hci_cmd.h"
@ -80,7 +78,7 @@ static btstack_packet_callback_registration_t hci_event_callback_registration;
/* LISTING_START(SDPClientInit): SDP client setup */
static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
static void handle_sdp_client_query_result(uint8_t packet_type, uint8_t *packet, uint16_t size);
static void handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
static void sdp_client_init(void){
@ -90,9 +88,6 @@ static void sdp_client_init(void){
// init L2CAP
l2cap_init();
sdp_parser_init();
sdp_parser_register_callback(handle_sdp_client_query_result);
}
/* LISTING_END */
@ -120,7 +115,7 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
switch (event) {
case BTSTACK_EVENT_STATE:
if (packet[2] == HCI_STATE_WORKING){
sdp_general_query_for_uuid(remote, SDP_PublicBrowseGroup);
sdp_general_query_for_uuid(&handle_sdp_client_query_result, remote, SDP_PublicBrowseGroup);
}
break;
default:
@ -149,7 +144,7 @@ static void assertBuffer(int size){
*/
/* LISTING_START(HandleSDPQUeryResult): Handling query result chunks. */
static void handle_sdp_client_query_result(uint8_t packet_type, uint8_t *packet, uint16_t size){
static void handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
switch (packet[0]){
case SDP_EVENT_QUERY_ATTRIBUTE_VALUE:
// handle new record

View File

@ -59,6 +59,8 @@
#include "classic/sdp_query_rfcomm.h"
#include "btstack_event.h"
static void handle_query_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
// static bd_addr_t remote = {0x04,0x0C,0xCE,0xE4,0x85,0xD3};
static bd_addr_t remote = {0x84, 0x38, 0x35, 0x65, 0xD1, 0x15};
@ -78,7 +80,7 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
case BTSTACK_EVENT_STATE:
// bt stack activated, get started
if (packet[2] == HCI_STATE_WORKING){
sdp_query_rfcomm_channel_and_name_for_uuid(remote, SDP_PublicBrowseGroup);
sdp_query_rfcomm_channel_and_name_for_uuid(&handle_query_rfcomm_event, remote, SDP_PublicBrowseGroup);
}
break;
default:
@ -109,7 +111,7 @@ static void report_found_services(void){
printf(" ***\n\n");
}
static void handle_query_rfcomm_event(uint8_t packet_type, uint8_t *packet, uint16_t size){
static void handle_query_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
switch (packet[0]){
case SDP_EVENT_QUERY_RFCOMM_SERVICE:
store_found_service(sdp_event_query_rfcomm_service_get_name(packet),
@ -133,8 +135,6 @@ int btstack_main(int argc, const char * argv[]){
// init L2CAP
l2cap_init();
sdp_query_rfcomm_register_callback(handle_query_rfcomm_event);
// turn on!
hci_power_control(HCI_POWER_ON);

View File

@ -70,6 +70,8 @@ typedef enum {
DONE
} state_t;
static void handle_query_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
#define DATA_VOLUME (1000 * 1000)
// configuration area {
@ -124,7 +126,7 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
case BTSTACK_EVENT_STATE:
// bt stack activated, get started
if (packet[2] == HCI_STATE_WORKING){
sdp_query_rfcomm_channel_and_name_for_uuid(remote, SDP_PublicBrowseGroup);
sdp_query_rfcomm_channel_and_name_for_uuid(&handle_query_rfcomm_event, remote, SDP_PublicBrowseGroup);
}
break;
case RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE:
@ -161,7 +163,7 @@ static void handle_found_service(const char * name, uint8_t port){
state = W4_SDP_COMPLETE;
}
static void handle_query_rfcomm_event(uint8_t packet_type, uint8_t *packet, uint16_t size){
static void handle_query_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
switch (packet[0]){
case SDP_EVENT_QUERY_RFCOMM_SERVICE:
handle_found_service(sdp_event_query_rfcomm_service_get_name(packet),
@ -196,8 +198,6 @@ int btstack_main(int argc, const char * argv[]){
// init L2CAP
l2cap_init();
sdp_query_rfcomm_register_callback(handle_query_rfcomm_event);
// turn on!
hci_power_control(HCI_POWER_ON);

View File

@ -68,7 +68,6 @@
#include "classic/rfcomm.h"
#include "classic/sdp_server.h"
#include "classic/sdp_client.h"
#include "classic/sdp_parser.h"
#include "classic/sdp_query_rfcomm.h"
#include "classic/sdp_query_util.h"
#include "hci.h"
@ -1134,13 +1133,11 @@ static int btstack_command_handler(connection_t *connection, uint8_t *packet, ui
memcpy(serviceSearchPattern, &packet[9], serviceSearchPatternLen);
sdp_client_query_connection = connection;
sdp_query_rfcomm_register_callback(handle_sdp_rfcomm_service_result);
sdp_query_rfcomm_channel_and_name_for_search_pattern(addr, serviceSearchPattern);
break;
case SDP_CLIENT_QUERY_SERVICES:
bt_flip_addr(addr, &packet[3]);
sdp_parser_init();
sdp_client_query_connection = connection;
sdp_parser_register_callback(handle_sdp_client_query_result);

View File

@ -57,7 +57,6 @@
<itemPath>../../../src/rfcomm.h</itemPath>
<itemPath>../../../src/sdp_server.h</itemPath>
<itemPath>../../../src/sdp_client.h</itemPath>
<itemPath>../../../src/sdp_parser.h</itemPath>
<itemPath>../../../src/sdp_query_rfcomm.h</itemPath>
<itemPath>../../../src/sdp_query_util.h</itemPath>
</logicalFolder>

View File

@ -88,7 +88,6 @@
#include "classic/rfcomm.h"
#include "classic/sdp_server.h"
#include "classic/sdp_client.h"
#include "classic/sdp_parser.h"
#include "classic/sdp_query_rfcomm.h"
#include "classic/sdp_query_util.h"
#include "classic/sdp_util.h"

View File

@ -424,7 +424,7 @@ static void handle_hci_event(uint8_t packet_type, uint16_t channel, uint8_t *pac
hfp_handle_hci_event(packet_type, packet, size);
}
static void handle_query_rfcomm_event(uint8_t packet_type, uint8_t *packet, uint16_t size){
static void handle_query_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
hfp_connection_t * connection = connection_doing_sdp_query;
if ( connection->state != HFP_W4_SDP_EVENT_QUERY_COMPLETE) return;
@ -1268,10 +1268,6 @@ static void parse_sequence(hfp_connection_t * context){
}
}
void hfp_init(void){
sdp_query_rfcomm_register_callback(handle_query_rfcomm_event);
}
void hfp_establish_service_level_connection(bd_addr_t bd_addr, uint16_t service_uuid){
hfp_connection_t * context = provide_hfp_connection_context_for_bd_addr(bd_addr);
log_info("hfp_connect %s, context %p", bd_addr_to_str(bd_addr), context);
@ -1293,7 +1289,7 @@ void hfp_establish_service_level_connection(bd_addr_t bd_addr, uint16_t service_
context->state = HFP_W4_SDP_EVENT_QUERY_COMPLETE;
connection_doing_sdp_query = context;
context->service_uuid = service_uuid;
sdp_query_rfcomm_channel_and_name_for_uuid(context->remote_addr, service_uuid);
sdp_query_rfcomm_channel_and_name_for_uuid(&handle_query_rfcomm_event, context->remote_addr, service_uuid);
break;
default:
break;

View File

@ -634,7 +634,6 @@ void set_hfp_generic_status_indicators(hfp_generic_status_indicator_t * indicato
btstack_linked_list_t * hfp_get_connections(void);
void hfp_parse(hfp_connection_t * context, uint8_t byte, int isHandsFree);
void hfp_init(void);
void hfp_establish_service_level_connection(bd_addr_t bd_addr, uint16_t service_uuid);
void hfp_release_service_level_connection(hfp_connection_t * connection);
void hfp_reset_context_flags(hfp_connection_t * context);

View File

@ -1998,7 +1998,6 @@ void hfp_ag_init(uint16_t rfcomm_channel_nr, uint32_t supported_features,
l2cap_init();
rfcomm_register_service(packet_handler, rfcomm_channel_nr, 0xffff);
hfp_init();
hfp_supported_features = supported_features;
hfp_codecs_nr = codecs_nr;

View File

@ -1058,8 +1058,7 @@ void hfp_hf_init(uint16_t rfcomm_channel_nr, uint32_t supported_features, uint16
l2cap_init();
rfcomm_register_service(packet_handler, rfcomm_channel_nr, 0xffff);
hfp_init();
hfp_supported_features = supported_features;
hfp_indicators_nr = indicators_nr;

View File

@ -116,7 +116,7 @@ static hsp_ag_callback_t hsp_ag_callback;
static void hsp_run();
static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
static void handle_query_rfcomm_event(uint8_t packet_type, uint8_t *packet, uint16_t size);
static void handle_query_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
static void dummy_notify(uint8_t * event, uint16_t size){}
@ -263,8 +263,6 @@ void hsp_ag_init(uint8_t rfcomm_channel_nr){
rfcomm_init();
rfcomm_register_service(packet_handler, rfcomm_channel_nr, 0xffff); // reserved channel, mtu limited by l2cap
sdp_query_rfcomm_register_callback(handle_query_rfcomm_event);
hsp_ag_reset_state();
}
@ -367,7 +365,7 @@ static void hsp_run(void){
case HSP_SDP_QUERY_RFCOMM_CHANNEL:
hsp_state = HSP_W4_SDP_EVENT_QUERY_COMPLETE;
log_info("Start SDP query %s, 0x%02x", bd_addr_to_str(remote), SDP_HSP);
sdp_query_rfcomm_channel_and_name_for_uuid(remote, SDP_HSP);
sdp_query_rfcomm_channel_and_name_for_uuid(&handle_query_rfcomm_event, remote, SDP_HSP);
break;
case HSP_W4_RING_ANSWER:
@ -441,7 +439,7 @@ static void hsp_run(void){
}
static void packet_handler (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
// log_info("packet_handler type %u, packet[0] %x", packet_type, packet[0]);
if (packet_type == RFCOMM_DATA_PACKET){
while (size > 0 && (packet[0] == '\n' || packet[0] == '\r')){
@ -601,7 +599,7 @@ static void packet_handler (void * connection, uint8_t packet_type, uint16_t cha
hsp_run();
}
static void handle_query_rfcomm_event(uint8_t packet_type, uint8_t *packet, uint16_t size){
static void handle_query_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
switch (packet[0]){
case SDP_EVENT_QUERY_RFCOMM_SERVICE:
channel_nr = sdp_event_query_rfcomm_service_get_rfcomm_channel(packet);

View File

@ -55,7 +55,7 @@ extern "C" {
typedef void (*hsp_ag_callback_t)(uint8_t * event, uint16_t event_size);
void hsp_ag_create_sdp_record(uint8_t * service, int rfcomm_channel_nr, const char * name);
void hsp_ag_create_sdp_record(uint8_t * service, uint32_t service_record_handle, int rfcomm_channel_nr, const char * name);
void hsp_ag_init(uint8_t rfcomm_channel_nr);

View File

@ -111,7 +111,7 @@ static hsp_state_t hsp_state = HSP_IDLE;
static void hsp_run(void);
static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
static void handle_query_rfcomm_event(uint8_t packet_type, uint8_t *packet, uint16_t size);
static void handle_query_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
static hsp_hs_callback_t hsp_hs_callback;
static void dummy_notify(uint8_t * event, uint16_t size){}
@ -263,8 +263,6 @@ void hsp_hs_init(uint8_t rfcomm_channel_nr){
rfcomm_init();
rfcomm_register_service(packet_handler, rfcomm_channel_nr, 0xffff); // reserved channel, mtu limited by l2cap
sdp_query_rfcomm_register_callback(handle_query_rfcomm_event);
hsp_hs_reset_state();
}
@ -330,7 +328,7 @@ static void hsp_run(void){
switch (hsp_state){
case HSP_SDP_QUERY_RFCOMM_CHANNEL:
hsp_state = HSP_W4_SDP_EVENT_QUERY_COMPLETE;
sdp_query_rfcomm_channel_and_name_for_uuid(remote, SDP_Headset_AG);
sdp_query_rfcomm_channel_and_name_for_uuid(&handle_query_rfcomm_event, remote, SDP_Headset_AG);
break;
case HSP_W2_CONNECT_SCO:
@ -565,7 +563,7 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
hsp_run();
}
static void handle_query_rfcomm_event(uint8_t packet_type, uint8_t *packet, uint16_t size){
static void handle_query_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
switch (packet[0]){
case SDP_EVENT_QUERY_RFCOMM_SERVICE:
channel_nr = sdp_event_query_rfcomm_service_get_rfcomm_channel(packet);

View File

@ -45,64 +45,284 @@
#include "hci_cmd.h"
#include "l2cap.h"
#include "classic/sdp_parser.h"
#include "classic/sdp_server.h"
#include "btstack_debug.h"
// Types SDP Parser - Data Element stream helper
typedef enum {
GET_LIST_LENGTH = 1,
GET_RECORD_LENGTH,
GET_ATTRIBUTE_ID_HEADER_LENGTH,
GET_ATTRIBUTE_ID,
GET_ATTRIBUTE_VALUE_LENGTH,
GET_ATTRIBUTE_VALUE
} sdp_parser_state_t;
// Types SDP Client
typedef enum {
INIT, W4_CONNECT, W2_SEND, W4_RESPONSE, QUERY_COMPLETE
} sdp_client_state_t;
void sdp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
static uint16_t setup_service_search_attribute_request(uint8_t * data);
// Prototypes SDP Parser
void sdp_parser_init(btstack_packet_handler_t callback);
void sdp_parser_handle_chunk(uint8_t * data, uint16_t size);
void sdp_parser_handle_done(uint8_t status);
void sdp_parser_init_service_attribute_search(void);
void sdp_parser_init_service_search(void);
void sdp_parser_handle_service_search(uint8_t * data, uint16_t total_count, uint16_t record_handle_count);
// Prototypes SDP Client
void sdp_client_reset(void);
void sdp_client_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
static uint16_t sdp_client_setup_service_search_attribute_request(uint8_t * data);
#ifdef ENABLE_SDP_EXTRA_QUERIES
static uint16_t setup_service_search_request(uint8_t * data);
static uint16_t setup_service_attribute_request(uint8_t * data);
static void parse_service_search_response(uint8_t* packet);
static void parse_service_attribute_response(uint8_t* packet);
static uint16_t sdp_client_setup_service_search_request(uint8_t * data);
static uint16_t sdp_client_setup_service_attribute_request(uint8_t * data);
static void sdp_client_parse_service_search_response(uint8_t* packet);
static void sdp_client_parse_service_attribute_response(uint8_t* packet);
static uint32_t serviceRecordHandle;
static uint32_t record_handle;
#endif
// SDP Client Query
// State DES Parser
static de_state_t de_header_state;
// State SDP Parser
static sdp_parser_state_t state = GET_LIST_LENGTH;
static uint16_t attribute_id = 0;
static uint16_t attribute_bytes_received = 0;
static uint16_t attribute_bytes_delivered = 0;
static uint16_t list_offset = 0;
static uint16_t list_size;
static uint16_t record_offset = 0;
static uint16_t record_size;
static uint16_t attribute_value_size;
static int record_counter = 0;
static btstack_packet_handler_t sdp_parser_callback;
// State SDP Client
static uint16_t mtu;
static uint16_t sdp_cid = 0x40;
static uint8_t * serviceSearchPattern;
static uint8_t * attributeIDList;
static const uint8_t * service_search_pattern;
static const uint8_t * attribute_id_list;
static uint16_t transactionID = 0;
static uint8_t continuationState[16];
static uint8_t continuationStateLen;
static sdp_client_state_t sdp_client_state = INIT;
static SDP_PDU_ID_t PDU_ID = SDP_Invalid;
// DES Parser
void de_state_init(de_state_t * de_state){
de_state->in_state_GET_DE_HEADER_LENGTH = 1;
de_state->addon_header_bytes = 0;
de_state->de_size = 0;
de_state->de_offset = 0;
}
int de_state_size(uint8_t eventByte, de_state_t *de_state){
if (de_state->in_state_GET_DE_HEADER_LENGTH){
de_state->addon_header_bytes = de_get_header_size(&eventByte) - 1;
de_state->de_size = 0;
de_state->de_offset = 0;
if (de_state->addon_header_bytes == 0){
de_state->de_size = de_get_data_size(&eventByte);
if (de_state->de_size == 0) {
log_error(" ERROR: ID size is zero");
}
// log_info("Data element payload is %d bytes.", de_state->de_size);
return 1;
}
de_state->in_state_GET_DE_HEADER_LENGTH = 0;
return 0;
}
if (de_state->addon_header_bytes > 0){
de_state->de_size = (de_state->de_size << 8) | eventByte;
de_state->addon_header_bytes--;
}
if (de_state->addon_header_bytes > 0) return 0;
// log_info("Data element payload is %d bytes.", de_state->de_size);
de_state->in_state_GET_DE_HEADER_LENGTH = 1;
return 1;
}
// SDP Parser
static void sdp_parser_emit_value_byte(uint8_t event_byte){
uint8_t event[11];
event[0] = SDP_EVENT_QUERY_ATTRIBUTE_VALUE;
event[1] = 9;
little_endian_store_16(event, 2, record_counter);
little_endian_store_16(event, 4, attribute_id);
little_endian_store_16(event, 6, attribute_value_size);
little_endian_store_16(event, 8, attribute_bytes_delivered);
event[10] = event_byte;
(*sdp_parser_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
}
static void sdp_parser_process_byte(uint8_t eventByte){
// count all bytes
list_offset++;
record_offset++;
// log_info(" parse BYTE_RECEIVED %02x", eventByte);
switch(state){
case GET_LIST_LENGTH:
if (!de_state_size(eventByte, &de_header_state)) break;
list_offset = de_header_state.de_offset;
list_size = de_header_state.de_size;
// log_info("parser: List offset %u, list size %u", list_offset, list_size);
record_counter = 0;
state = GET_RECORD_LENGTH;
break;
case GET_RECORD_LENGTH:
// check size
if (!de_state_size(eventByte, &de_header_state)) break;
// log_info("parser: Record payload is %d bytes.", de_header_state.de_size);
record_offset = de_header_state.de_offset;
record_size = de_header_state.de_size;
state = GET_ATTRIBUTE_ID_HEADER_LENGTH;
break;
case GET_ATTRIBUTE_ID_HEADER_LENGTH:
if (!de_state_size(eventByte, &de_header_state)) break;
attribute_id = 0;
log_info("ID data is stored in %d bytes.", (int) de_header_state.de_size);
state = GET_ATTRIBUTE_ID;
break;
case GET_ATTRIBUTE_ID:
attribute_id = (attribute_id << 8) | eventByte;
de_header_state.de_size--;
if (de_header_state.de_size > 0) break;
log_info("parser: Attribute ID: %04x.", attribute_id);
state = GET_ATTRIBUTE_VALUE_LENGTH;
attribute_bytes_received = 0;
attribute_bytes_delivered = 0;
attribute_value_size = 0;
de_state_init(&de_header_state);
break;
case GET_ATTRIBUTE_VALUE_LENGTH:
attribute_bytes_received++;
sdp_parser_emit_value_byte(eventByte);
attribute_bytes_delivered++;
if (!de_state_size(eventByte, &de_header_state)) break;
attribute_value_size = de_header_state.de_size + attribute_bytes_received;
state = GET_ATTRIBUTE_VALUE;
break;
case GET_ATTRIBUTE_VALUE:
attribute_bytes_received++;
sdp_parser_emit_value_byte(eventByte);
attribute_bytes_delivered++;
// log_info("paser: attribute_bytes_received %u, attribute_value_size %u", attribute_bytes_received, attribute_value_size);
if (attribute_bytes_received < attribute_value_size) break;
// log_info("parser: Record offset %u, record size %u", record_offset, record_size);
if (record_offset != record_size){
state = GET_ATTRIBUTE_ID_HEADER_LENGTH;
// log_info("Get next attribute");
break;
}
record_offset = 0;
// log_info("parser: List offset %u, list size %u", list_offset, list_size);
if (list_size > 0 && list_offset != list_size){
record_counter++;
state = GET_RECORD_LENGTH;
log_info("parser: END_OF_RECORD");
break;
}
list_offset = 0;
de_state_init(&de_header_state);
state = GET_LIST_LENGTH;
record_counter = 0;
log_info("parser: END_OF_RECORD & DONE");
break;
default:
break;
}
}
void sdp_parser_init(btstack_packet_handler_t callback){
// init
sdp_parser_callback = callback;
de_state_init(&de_header_state);
state = GET_LIST_LENGTH;
list_offset = 0;
record_offset = 0;
record_counter = 0;
}
void sdp_parser_handle_chunk(uint8_t * data, uint16_t size){
int i;
for (i=0;i<size;i++){
sdp_parser_process_byte(data[i]);
}
}
#ifdef ENABLE_SDP_EXTRA_QUERIES
void sdp_parser_init_service_attribute_search(void){
// init
de_state_init(&de_header_state);
state = GET_RECORD_LENGTH;
list_offset = 0;
record_offset = 0;
record_counter = 0;
}
void sdp_parser_init_service_search(void){
record_offset = 0;
}
void sdp_parser_handle_service_search(uint8_t * data, uint16_t total_count, uint16_t record_handle_count){
int i;
for (i=0;i<record_handle_count;i++){
record_handle = big_endian_read_32(data, i*4);
record_counter++;
uint8_t event[10];
event[0] = SDP_EVENT_QUERY_SERVICE_RECORD_HANDLE;
event[1] = 8;
little_endian_store_16(event, 2, total_count);
little_endian_store_16(event, 4, record_counter);
little_endian_store_32(event, 6, record_handle);
(*sdp_parser_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
}
}
#endif
void sdp_parser_handle_done(uint8_t status){
uint8_t event[3];
event[0] = SDP_EVENT_QUERY_COMPLETE;
event[1] = 1;
event[2] = status;
(*sdp_parser_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
}
// SDP Client
// TODO: inline if not needed (des(des))
static void parse_attribute_lists(uint8_t* packet, uint16_t length){
sdp_parser_handle_chunk(packet, length);
}
/* 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){
serviceSearchPattern = des_serviceSearchPattern;
attributeIDList = des_attributeIDList;
continuationStateLen = 0;
PDU_ID = SDP_ServiceSearchAttributeResponse;
sdp_client_state = W4_CONNECT;
l2cap_create_channel(sdp_packet_handler, remote, PSM_SDP, l2cap_max_mtu(), NULL);
}
static int can_send_now(uint16_t channel){
static int sdp_client_can_send_now(uint16_t channel){
if (sdp_client_state != W2_SEND) return 0;
if (!l2cap_can_send_packet_now(channel)) return 0;
return 1;
}
static void send_request(uint16_t channel){
static void sdp_client_parse_attribute_lists(uint8_t* packet, uint16_t length){
sdp_parser_handle_chunk(packet, length);
}
static void sdp_client_send_request(uint16_t channel){
l2cap_reserve_packet_buffer();
uint8_t * data = l2cap_get_outgoing_buffer();
uint16_t request_len = 0;
@ -110,17 +330,17 @@ static void send_request(uint16_t channel){
switch (PDU_ID){
#ifdef ENABLE_SDP_EXTRA_QUERIES
case SDP_ServiceSearchResponse:
request_len = setup_service_search_request(data);
request_len = sdp_client_setup_service_search_request(data);
break;
case SDP_ServiceAttributeResponse:
request_len = setup_service_attribute_request(data);
request_len = sdp_client_setup_service_attribute_request(data);
break;
#endif
case SDP_ServiceSearchAttributeResponse:
request_len = setup_service_search_attribute_request(data);
request_len = sdp_client_setup_service_search_attribute_request(data);
break;
default:
log_error("SDP Client send_request :: PDU ID invalid. %u", PDU_ID);
log_error("SDP Client sdp_client_send_request :: PDU ID invalid. %u", PDU_ID);
return;
}
@ -145,7 +365,7 @@ static void send_request(uint16_t channel){
}
static void parse_service_search_attribute_response(uint8_t* packet){
static void sdp_client_parse_service_search_attribute_response(uint8_t* packet){
uint16_t offset = 3;
uint16_t parameterLength = big_endian_read_16(packet,offset);
offset+=2;
@ -159,7 +379,7 @@ static void parse_service_search_attribute_response(uint8_t* packet){
}
// AttributeLists
parse_attribute_lists(packet+offset, attributeListByteCount);
sdp_client_parse_attribute_lists(packet+offset, attributeListByteCount);
offset+=attributeListByteCount;
continuationStateLen = packet[offset];
@ -177,7 +397,7 @@ static void parse_service_search_attribute_response(uint8_t* packet){
}
}
void sdp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
void sdp_client_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
// uint16_t handle;
if (packet_type == L2CAP_DATA_PACKET){
uint16_t responseTransactionID = big_endian_read_16(packet,1);
@ -199,14 +419,14 @@ void sdp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet,
switch (PDU_ID){
#ifdef ENABLE_SDP_EXTRA_QUERIES
case SDP_ServiceSearchResponse:
parse_service_search_response(packet);
sdp_client_parse_service_search_response(packet);
break;
case SDP_ServiceAttributeResponse:
parse_service_attribute_response(packet);
sdp_client_parse_service_attribute_response(packet);
break;
#endif
case SDP_ServiceSearchAttributeResponse:
parse_service_search_attribute_response(packet);
sdp_client_parse_service_search_attribute_response(packet);
break;
default:
log_error("SDP Client :: PDU ID invalid. %u ,%u", PDU_ID, packet[0]);
@ -223,7 +443,7 @@ void sdp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet,
}
// prepare next request and send
sdp_client_state = W2_SEND;
if (can_send_now(sdp_cid)) send_request(sdp_cid);
if (sdp_client_can_send_now(sdp_cid)) sdp_client_send_request(sdp_cid);
return;
}
@ -247,11 +467,11 @@ void sdp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet,
log_info("SDP Client Connected, cid %x, mtu %u.", sdp_cid, mtu);
sdp_client_state = W2_SEND;
if (can_send_now(sdp_cid)) send_request(sdp_cid);
if (sdp_client_can_send_now(sdp_cid)) sdp_client_send_request(sdp_cid);
break;
case L2CAP_EVENT_CAN_SEND_NOW:
if (can_send_now(sdp_cid)) send_request(sdp_cid);
if (sdp_client_can_send_now(sdp_cid)) sdp_client_send_request(sdp_cid);
break;
case L2CAP_EVENT_CHANNEL_CLOSED: {
if (sdp_cid != little_endian_read_16(packet, 2)) {
@ -270,7 +490,7 @@ void sdp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet,
}
static uint16_t setup_service_search_attribute_request(uint8_t * data){
static uint16_t sdp_client_setup_service_search_attribute_request(uint8_t * data){
uint16_t offset = 0;
transactionID++;
@ -284,19 +504,19 @@ static uint16_t setup_service_search_attribute_request(uint8_t * data){
offset += 2;
// parameters:
// ServiceSearchPattern - DES (min 1 UUID, max 12)
uint16_t serviceSearchPatternLen = de_get_len(serviceSearchPattern);
memcpy(data + offset, serviceSearchPattern, serviceSearchPatternLen);
offset += serviceSearchPatternLen;
// Service_search_pattern - DES (min 1 UUID, max 12)
uint16_t service_search_pattern_len = de_get_len(service_search_pattern);
memcpy(data + offset, service_search_pattern, service_search_pattern_len);
offset += service_search_pattern_len;
// MaximumAttributeByteCount - uint16_t 0x0007 - 0xffff -> mtu
big_endian_store_16(data, offset, mtu);
offset += 2;
// AttibuteIDList
uint16_t attributeIDListLen = de_get_len(attributeIDList);
memcpy(data + offset, attributeIDList, attributeIDListLen);
offset += attributeIDListLen;
uint16_t attribute_id_list_len = de_get_len(attribute_id_list);
memcpy(data + offset, attribute_id_list, attribute_id_list_len);
offset += attribute_id_list_len;
// ContinuationState - uint8_t number of cont. bytes N<=16
data[offset++] = continuationStateLen;
@ -311,11 +531,11 @@ static uint16_t setup_service_search_attribute_request(uint8_t * data){
}
#ifdef ENABLE_SDP_EXTRA_QUERIES
void parse_service_record_handle_list(uint8_t* packet, uint16_t total_count, uint16_t current_count){
void sdp_client_parse_service_record_handle_list(uint8_t* packet, uint16_t total_count, uint16_t current_count){
sdp_parser_handle_service_search(packet, total_count, current_count);
}
static uint16_t setup_service_search_request(uint8_t * data){
static uint16_t sdp_client_setup_service_search_request(uint8_t * data){
uint16_t offset = 0;
transactionID++;
// uint8_t SDP_PDU_ID_t.SDP_ServiceSearchRequest;
@ -328,10 +548,10 @@ static uint16_t setup_service_search_request(uint8_t * data){
offset += 2;
// parameters:
// ServiceSearchPattern - DES (min 1 UUID, max 12)
uint16_t serviceSearchPatternLen = de_get_len(serviceSearchPattern);
memcpy(data + offset, serviceSearchPattern, serviceSearchPatternLen);
offset += serviceSearchPatternLen;
// Service_search_pattern - DES (min 1 UUID, max 12)
uint16_t service_search_pattern_len = de_get_len(service_search_pattern);
memcpy(data + offset, service_search_pattern, service_search_pattern_len);
offset += service_search_pattern_len;
// MaximumAttributeByteCount - uint16_t 0x0007 - 0xffff -> mtu
big_endian_store_16(data, offset, mtu);
@ -350,7 +570,7 @@ static uint16_t setup_service_search_request(uint8_t * data){
}
static uint16_t setup_service_attribute_request(uint8_t * data){
static uint16_t sdp_client_setup_service_attribute_request(uint8_t * data){
uint16_t offset = 0;
transactionID++;
@ -373,9 +593,9 @@ static uint16_t setup_service_attribute_request(uint8_t * data){
offset += 2;
// AttibuteIDList
uint16_t attributeIDListLen = de_get_len(attributeIDList);
memcpy(data + offset, attributeIDList, attributeIDListLen);
offset += attributeIDListLen;
uint16_t attribute_id_list_len = de_get_len(attribute_id_list);
memcpy(data + offset, attribute_id_list, attribute_id_list_len);
offset += attribute_id_list_len;
// ContinuationState - uint8_t number of cont. bytes N<=16
data[offset++] = continuationStateLen;
@ -389,7 +609,7 @@ static uint16_t setup_service_attribute_request(uint8_t * data){
return offset;
}
static void parse_service_search_response(uint8_t* packet){
static void sdp_client_parse_service_search_response(uint8_t* packet){
uint16_t offset = 3;
uint16_t parameterLength = big_endian_read_16(packet,offset);
offset+=2;
@ -404,7 +624,7 @@ static void parse_service_search_response(uint8_t* packet){
return;
}
parse_service_record_handle_list(packet+offset, totalServiceRecordCount, currentServiceRecordCount);
sdp_client_parse_service_record_handle_list(packet+offset, totalServiceRecordCount, currentServiceRecordCount);
offset+=(currentServiceRecordCount * 4);
continuationStateLen = packet[offset];
@ -421,7 +641,7 @@ static void parse_service_search_response(uint8_t* packet){
}
}
static void parse_service_attribute_response(uint8_t* packet){
static void sdp_client_parse_service_attribute_response(uint8_t* packet){
uint16_t offset = 3;
uint16_t parameterLength = big_endian_read_16(packet,offset);
offset+=2;
@ -436,7 +656,7 @@ static void parse_service_attribute_response(uint8_t* packet){
}
// AttributeLists
parse_attribute_lists(packet+offset, attributeListByteCount);
sdp_client_parse_attribute_lists(packet+offset, attributeListByteCount);
offset+=attributeListByteCount;
continuationStateLen = packet[offset];
@ -453,24 +673,62 @@ static void parse_service_attribute_response(uint8_t* packet){
log_error("Error parsing ServiceAttributeResponse: wrong size of parameters, number of expected bytes%u, actual number %u.", parameterLength, offset);
}
}
#endif
void sdp_client_service_attribute_search(bd_addr_t remote, uint32_t search_serviceRecordHandle, uint8_t * des_attributeIDList){
serviceRecordHandle = search_serviceRecordHandle;
attributeIDList = des_attributeIDList;
// for testing only
void sdp_client_reset(void){
sdp_client_state = INIT;
}
// Public API
int sdp_client_ready(void){
return sdp_client_state == INIT;
}
void sdp_client_query(btstack_packet_handler_t callback, bd_addr_t remote, const uint8_t * des_service_search_pattern, const uint8_t * des_attribute_id_list){
if (!sdp_client_ready()) {
log_error("sdp_client_query called when not ready");
return;
}
sdp_parser_init(callback);
service_search_pattern = des_service_search_pattern;
attribute_id_list = des_attribute_id_list;
continuationStateLen = 0;
PDU_ID = SDP_ServiceSearchAttributeResponse;
sdp_client_state = W4_CONNECT;
l2cap_create_channel(sdp_client_packet_handler, remote, PSM_SDP, l2cap_max_mtu(), NULL);
}
#ifdef ENABLE_SDP_EXTRA_QUERIES
void sdp_client_service_attribute_search(btstack_packet_handler_t callback, bd_addr_t remote, uint32_t search_service_record_handle, uint8_t * des_attribute_id_list){
if (!sdp_client_ready()) {
log_error("sdp_client_query called when not ready");
return;
}
sdp_parser_init(callback);
serviceRecordHandle = search_service_record_handle;
attribute_id_list = des_attribute_id_list;
continuationStateLen = 0;
PDU_ID = SDP_ServiceAttributeResponse;
sdp_client_state = W4_CONNECT;
l2cap_create_channel(sdp_packet_handler, remote, PSM_SDP, l2cap_max_mtu(), NULL);
l2cap_create_channel(sdp_client_packet_handler, remote, PSM_SDP, l2cap_max_mtu(), NULL);
}
void sdp_client_service_search(bd_addr_t remote, uint8_t * des_serviceSearchPattern){
serviceSearchPattern = des_serviceSearchPattern;
void sdp_client_service_search(btstack_packet_handler_t callback, bd_addr_t remote, uint8_t * des_service_search_pattern){
if (!sdp_client_ready()) {
log_error("sdp_client_query called when not ready");
return;
}
sdp_parser_init(callback);
service_search_pattern = des_service_search_pattern;
continuationStateLen = 0;
PDU_ID = SDP_ServiceSearchResponse;
sdp_client_state = W4_CONNECT;
l2cap_create_channel(sdp_packet_handler, remote, PSM_SDP, l2cap_max_mtu(), NULL);
l2cap_create_channel(sdp_client_packet_handler, remote, PSM_SDP, l2cap_max_mtu(), NULL);
}
#endif

View File

@ -51,17 +51,55 @@ extern "C" {
#endif
/* API_START */
typedef struct de_state {
uint8_t in_state_GET_DE_HEADER_LENGTH ;
uint32_t addon_header_bytes;
uint32_t de_size;
uint32_t de_offset;
} de_state_t;
void de_state_init(de_state_t * state);
int de_state_size(uint8_t eventByte, de_state_t *de_state);
/**
* @brief Checks if the SDP Client is ready
* @return 1 when no query is active
*/
int sdp_client_ready(void);
/**
* @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.
* The remote data is handled by the SDP parser. The SDP parser delivers attribute values and done event via the callback.
* @param callback for attributes values and done event
* @param remote address
* @param des_service_search_pattern
* @param des_attribute_id_list
*/
void sdp_client_query(bd_addr_t remote, uint8_t * des_serviceSearchPattern, uint8_t * des_attributeIDList);
void sdp_client_query(btstack_packet_handler_t callback, bd_addr_t remote, const uint8_t * des_service_search_pattern, const uint8_t * des_attribute_id_list);
/**
* @brief Retrieves all attribute IDs of a SDP record specified by its service record handle and a list of attribute IDs.
* The remote data is handled by the SDP parser. The SDP parser delivers attribute values and done event via the callback.
* @note only provided if ENABLE_SDP_EXTRA_QUERIES is defined
* @param callback for attributes values and done event
* @param remote address
* @param search_service_record_handle
* @param des_attributeIDList
*/
void sdp_client_service_attribute_search(btstack_packet_handler_t callback, bd_addr_t remote, uint32_t search_service_record_handle, const uint8_t * des_attributeIDList);
/**
* @brief Query the list of SDP records that match a given service search pattern.
* The remote data is handled by the SDP parser. The SDP parser delivers attribute values and done event via the callback.
* @note only provided if ENABLE_SDP_EXTRA_QUERIES is defined
* @param callback for attributes values and done event
* @param remote address
* @param des_service_search_pattern
*/
void sdp_client_service_search(btstack_packet_handler_t callback, bd_addr_t remote, const uint8_t * des_service_search_pattern);
#ifdef ENABLE_SDP_EXTRA_QUERIES
void sdp_client_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
/* API_END */
#if defined __cplusplus

View File

@ -1,273 +0,0 @@
/*
* 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
*
*/
/*
* sdp_parser.c
*/
#include "hci_cmd.h"
#include "classic/sdp_parser.h"
#include "btstack_debug.h"
typedef enum {
GET_LIST_LENGTH = 1,
GET_RECORD_LENGTH,
GET_ATTRIBUTE_ID_HEADER_LENGTH,
GET_ATTRIBUTE_ID,
GET_ATTRIBUTE_VALUE_LENGTH,
GET_ATTRIBUTE_VALUE
} state_t;
static state_t state = GET_LIST_LENGTH;
static uint16_t attribute_id = 0;
static uint16_t attribute_bytes_received = 0;
static uint16_t attribute_bytes_delivered = 0;
static uint16_t list_offset = 0;
static uint16_t list_size;
static uint16_t record_offset = 0;
static uint16_t record_size;
static uint16_t attribute_value_size;
static int record_counter = 0;
#ifdef ENABLE_SDP_EXTRA_QUERIES
static uint32_t record_handle;
#endif
static void (*sdp_query_callback)(uint8_t packet_type, uint8_t *packet, uint16_t size);
// Low level parser
static de_state_t de_header_state;
void de_state_init(de_state_t * de_state){
de_state->in_state_GET_DE_HEADER_LENGTH = 1;
de_state->addon_header_bytes = 0;
de_state->de_size = 0;
de_state->de_offset = 0;
}
int de_state_size(uint8_t eventByte, de_state_t *de_state){
if (de_state->in_state_GET_DE_HEADER_LENGTH){
de_state->addon_header_bytes = de_get_header_size(&eventByte) - 1;
de_state->de_size = 0;
de_state->de_offset = 0;
if (de_state->addon_header_bytes == 0){
de_state->de_size = de_get_data_size(&eventByte);
if (de_state->de_size == 0) {
log_error(" ERROR: ID size is zero");
}
// log_info("Data element payload is %d bytes.", de_state->de_size);
return 1;
}
de_state->in_state_GET_DE_HEADER_LENGTH = 0;
return 0;
}
if (de_state->addon_header_bytes > 0){
de_state->de_size = (de_state->de_size << 8) | eventByte;
de_state->addon_header_bytes--;
}
if (de_state->addon_header_bytes > 0) return 0;
// log_info("Data element payload is %d bytes.", de_state->de_size);
de_state->in_state_GET_DE_HEADER_LENGTH = 1;
return 1;
}
static void dummy_notify(uint8_t packet_type, uint8_t *packet, uint16_t size){}
void sdp_parser_register_callback(void (*sdp_callback)(uint8_t packet_type, uint8_t *packet, uint16_t size)){
sdp_query_callback = dummy_notify;
if (sdp_callback != NULL){
sdp_query_callback = sdp_callback;
}
}
static void emit_value_byte(uint8_t event_byte){
uint8_t event[11];
event[0] = SDP_EVENT_QUERY_ATTRIBUTE_VALUE;
event[1] = 9;
little_endian_store_16(event, 2, record_counter);
little_endian_store_16(event, 4, attribute_id);
little_endian_store_16(event, 6, attribute_value_size);
little_endian_store_16(event, 8, attribute_bytes_delivered);
event[10] = event_byte;
(*sdp_query_callback)(HCI_EVENT_PACKET, event, sizeof(event));
}
static void parse(uint8_t eventByte){
// count all bytes
list_offset++;
record_offset++;
// log_info(" parse BYTE_RECEIVED %02x", eventByte);
switch(state){
case GET_LIST_LENGTH:
if (!de_state_size(eventByte, &de_header_state)) break;
list_offset = de_header_state.de_offset;
list_size = de_header_state.de_size;
// log_info("parser: List offset %u, list size %u", list_offset, list_size);
record_counter = 0;
state = GET_RECORD_LENGTH;
break;
case GET_RECORD_LENGTH:
// check size
if (!de_state_size(eventByte, &de_header_state)) break;
// log_info("parser: Record payload is %d bytes.", de_header_state.de_size);
record_offset = de_header_state.de_offset;
record_size = de_header_state.de_size;
state = GET_ATTRIBUTE_ID_HEADER_LENGTH;
break;
case GET_ATTRIBUTE_ID_HEADER_LENGTH:
if (!de_state_size(eventByte, &de_header_state)) break;
attribute_id = 0;
log_info("ID data is stored in %d bytes.", (int) de_header_state.de_size);
state = GET_ATTRIBUTE_ID;
break;
case GET_ATTRIBUTE_ID:
attribute_id = (attribute_id << 8) | eventByte;
de_header_state.de_size--;
if (de_header_state.de_size > 0) break;
log_info("parser: Attribute ID: %04x.", attribute_id);
state = GET_ATTRIBUTE_VALUE_LENGTH;
attribute_bytes_received = 0;
attribute_bytes_delivered = 0;
attribute_value_size = 0;
de_state_init(&de_header_state);
break;
case GET_ATTRIBUTE_VALUE_LENGTH:
attribute_bytes_received++;
emit_value_byte(eventByte);
attribute_bytes_delivered++;
if (!de_state_size(eventByte, &de_header_state)) break;
attribute_value_size = de_header_state.de_size + attribute_bytes_received;
state = GET_ATTRIBUTE_VALUE;
break;
case GET_ATTRIBUTE_VALUE:
attribute_bytes_received++;
emit_value_byte(eventByte);
attribute_bytes_delivered++;
// log_info("paser: attribute_bytes_received %u, attribute_value_size %u", attribute_bytes_received, attribute_value_size);
if (attribute_bytes_received < attribute_value_size) break;
// log_info("parser: Record offset %u, record size %u", record_offset, record_size);
if (record_offset != record_size){
state = GET_ATTRIBUTE_ID_HEADER_LENGTH;
// log_info("Get next attribute");
break;
}
record_offset = 0;
// log_info("parser: List offset %u, list size %u", list_offset, list_size);
if (list_size > 0 && list_offset != list_size){
record_counter++;
state = GET_RECORD_LENGTH;
log_info("parser: END_OF_RECORD");
break;
}
list_offset = 0;
de_state_init(&de_header_state);
state = GET_LIST_LENGTH;
record_counter = 0;
log_info("parser: END_OF_RECORD & DONE");
break;
default:
break;
}
}
void sdp_parser_init(void){
// init
de_state_init(&de_header_state);
state = GET_LIST_LENGTH;
list_offset = 0;
record_offset = 0;
record_counter = 0;
}
void sdp_parser_handle_chunk(uint8_t * data, uint16_t size){
int i;
for (i=0;i<size;i++){
parse(data[i]);
}
}
#ifdef ENABLE_SDP_EXTRA_QUERIES
void sdp_parser_init_service_attribute_search(void){
// init
de_state_init(&de_header_state);
state = GET_RECORD_LENGTH;
list_offset = 0;
record_offset = 0;
record_counter = 0;
}
void sdp_parser_init_service_search(void){
record_offset = 0;
}
void sdp_parser_handle_service_search(uint8_t * data, uint16_t total_count, uint16_t record_handle_count){
int i;
for (i=0;i<record_handle_count;i++){
record_handle = big_endian_read_32(data, i*4);
record_counter++;
uint8_t event[10];
event[0] = SDP_EVENT_QUERY_SERVICE_RECORD_HANDLE;
event[1] = 8;
little_endian_store_16(event, 2, total_count);
little_endian_store_16(event, 4, record_counter);
little_endian_store_32(event, 6, record_handle);
(*sdp_query_callback)(HCI_EVENT_PACKET, event, sizeof(event));
}
}
#endif
void sdp_parser_handle_done(uint8_t status){
uint8_t event[3];
event[0] = SDP_EVENT_QUERY_COMPLETE;
event[1] = 1;
event[2] = status;
(*sdp_query_callback)(HCI_EVENT_PACKET, event, sizeof(event));
}

View File

@ -1,118 +0,0 @@
/*
* 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
*
*/
/*
* sdp_parser.h
*/
#ifndef __SDP_PARSER_H
#define __SDP_PARSER_H
#include "btstack_config.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "classic/sdp_util.h"
#include "btstack_util.h"
#if defined __cplusplus
extern "C" {
#endif
/* SDP Parser */
// Data Element stream parser helper
typedef struct de_state {
uint8_t in_state_GET_DE_HEADER_LENGTH ;
uint32_t addon_header_bytes;
uint32_t de_size;
uint32_t de_offset;
} de_state_t;
void de_state_init(de_state_t * state);
int de_state_size(uint8_t eventByte, de_state_t *de_state);
/* API_START */
/*
* @brief
*/
void sdp_parser_init(void);
/*
* @brief Registers a callback to receive attribute value data and parse complete event.
*/
void sdp_parser_register_callback(void (*sdp_callback)(uint8_t packet_type, uint8_t *packet, uint16_t size));
/*
* @brief
*/
void sdp_parser_handle_chunk(uint8_t * data, uint16_t size);
/*
* @brief
*/
void sdp_parser_handle_done(uint8_t status);
#ifdef ENABLE_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
/* API_END */
#if defined __cplusplus
}
#endif
#endif // __SDP_PARSER_H

View File

@ -44,6 +44,7 @@
#include <stdlib.h>
#include <string.h>
#include "btstack_debug.h"
#include "btstack_event.h"
#include "classic/sdp_client.h"
#include "classic/sdp_query_rfcomm.h"
@ -53,11 +54,6 @@
// called by test/sdp_client
void sdp_query_rfcomm_init(void);
// called by test/sdp_client
void sdp_query_rfcomm_init(void);
static void dummy_notify_app(uint8_t packet_type, uint8_t *packet, uint16_t size);
typedef enum {
GET_PROTOCOL_LIST_LENGTH = 1,
GET_PROTOCOL_LENGTH,
@ -88,12 +84,9 @@ static int protocol_id_bytes_to_read;
static int protocol_value_size;
static de_state_t de_header_state;
static de_state_t sn_de_header_state;
static void (*sdp_app_callback)(uint8_t packet_type, uint8_t *packet, uint16_t size) = dummy_notify_app;
static btstack_packet_handler_t sdp_app_callback;
//
static void dummy_notify_app(uint8_t packet_type, uint8_t *packet, uint16_t size){}
static void emit_service(void){
uint8_t event[3+SDP_SERVICE_NAME_LEN+1];
event[0] = SDP_EVENT_QUERY_RFCOMM_SERVICE;
@ -101,17 +94,10 @@ static void emit_service(void){
event[2] = sdp_rfcomm_channel_nr;
memcpy(&event[3], sdp_service_name, sdp_service_name_len);
event[3+sdp_service_name_len] = 0;
(*sdp_app_callback)(HCI_EVENT_PACKET, event, sizeof(event));
(*sdp_app_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
sdp_rfcomm_channel_nr = 0;
}
void sdp_query_rfcomm_register_callback(void (*sdp_callback)(uint8_t packet_type, uint8_t *packet, uint16_t size)){
sdp_app_callback = dummy_notify_app;
if (sdp_callback != NULL){
sdp_app_callback = sdp_callback;
}
}
static void handleProtocolDescriptorListData(uint32_t attribute_value_length, uint32_t data_offset, uint8_t data){
// init state on first byte
if (data_offset == 0){
@ -253,7 +239,7 @@ static void handleServiceNameData(uint32_t attribute_value_length, uint32_t data
}
}
static void handle_sdp_parser_event(uint8_t packet_type, uint8_t *packet, uint16_t size){
static void handle_sdp_parser_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
switch (packet[0]){
case SDP_EVENT_QUERY_SERVICE_RECORD_HANDLE:
// handle service without a name
@ -292,7 +278,7 @@ static void handle_sdp_parser_event(uint8_t packet_type, uint8_t *packet, uint16
if (sdp_rfcomm_channel_nr){
emit_service();
}
(*sdp_app_callback)(HCI_EVENT_PACKET, packet, size);
(*sdp_app_callback)(HCI_EVENT_PACKET, 0, packet, size);
break;
}
// insert higher level code HERE
@ -304,19 +290,31 @@ void sdp_query_rfcomm_init(void){
de_state_init(&sn_de_header_state);
pdl_state = GET_PROTOCOL_LIST_LENGTH;
protocol_offset = 0;
sdp_parser_register_callback(handle_sdp_parser_event);
sdp_rfcomm_channel_nr = 0;
sdp_service_name[0] = 0;
}
// Public API
void sdp_query_rfcomm_channel_and_name_for_search_pattern(bd_addr_t remote, uint8_t * serviceSearchPattern){
sdp_parser_init();
int sdp_query_rfcomm_ready(void){
return sdp_client_ready();
}
void sdp_query_rfcomm_channel_and_name_for_search_pattern(btstack_packet_handler_t callback, bd_addr_t remote, uint8_t * serviceSearchPattern){
if (!sdp_query_rfcomm_ready()){
log_error("sdp_query_rfcomm_channel_and_name_for_search_pattern called when not readdy");
return;
}
sdp_app_callback = callback;
sdp_query_rfcomm_init();
sdp_client_query(remote, serviceSearchPattern, (uint8_t*)&des_attributeIDList[0]);
sdp_client_query(&handle_sdp_parser_event, remote, serviceSearchPattern, (uint8_t*)&des_attributeIDList[0]);
}
void sdp_query_rfcomm_channel_and_name_for_uuid(bd_addr_t remote, uint16_t uuid){
void sdp_query_rfcomm_channel_and_name_for_uuid(btstack_packet_handler_t callback, bd_addr_t remote, uint16_t uuid){
if (!sdp_query_rfcomm_ready()){
log_error("sdp_query_rfcomm_channel_and_name_for_uuid called when not readdy");
return;
}
big_endian_store_16(des_serviceSearchPattern, 3, uuid);
sdp_query_rfcomm_channel_and_name_for_search_pattern(remote, (uint8_t*)des_serviceSearchPattern);
sdp_query_rfcomm_channel_and_name_for_search_pattern(callback, remote, (uint8_t*)des_serviceSearchPattern);
}

View File

@ -43,7 +43,6 @@
#define __SDP_QUERY_RFCOMM_H
#include "btstack_util.h"
#include "classic/sdp_parser.h"
#include "classic/sdp_query_util.h"
#define SDP_SERVICE_NAME_LEN 20
@ -55,19 +54,20 @@ extern "C" {
/* API_START */
/**
* @brief Registers a callback to receive RFCOMM service and query complete event.
* @brief Checks if the SDP Client is ready
* @return 1 when no query is active
*/
void sdp_query_rfcomm_register_callback(void(*sdp_app_callback)(uint8_t packet_type, uint8_t *packet, uint16_t size));
int sdp_query_rfcomm_ready(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);
void sdp_query_rfcomm_channel_and_name_for_uuid(btstack_packet_handler_t callback, 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);
void sdp_query_rfcomm_channel_and_name_for_search_pattern(btstack_packet_handler_t callback, bd_addr_t remote, uint8_t * des_serviceSearchPattern);
/* API_END */
#if defined __cplusplus

View File

@ -38,7 +38,7 @@
/*
* sdp_query_util.c
*/
#include "classic/sdp_parser.h"
#include "btstack_debug.h"
#include "classic/sdp_client.h"
#include "classic/sdp_query_util.h"
@ -54,21 +54,35 @@ static uint8_t* create_service_search_pattern_for_uuid128(uint8_t* uuid){
return (uint8_t*)des_serviceSearchPatternUUID128;
}
/**
* @brief Checks if the SDP Client is ready
* @return 1 when no query is active
*/
int sdp_general_query_ready(void){
return sdp_client_ready();
}
uint8_t* create_service_search_pattern_for_uuid(uint16_t uuid){
big_endian_store_16(des_serviceSearchPattern, 3, uuid);
return (uint8_t*)des_serviceSearchPattern;
}
void sdp_general_query_for_uuid(bd_addr_t remote, uint16_t uuid){
void sdp_general_query_for_uuid(btstack_packet_handler_t callback, bd_addr_t remote, uint16_t uuid){
if (!sdp_client_ready()){
log_error("sdp_general_query_for_uuid called when not readdy");
return;
}
create_service_search_pattern_for_uuid(uuid);
sdp_parser_init();
sdp_client_query(remote, (uint8_t*)&des_serviceSearchPattern[0], (uint8_t*)&des_attributeIDList[0]);
sdp_client_query(callback, remote, (uint8_t*)&des_serviceSearchPattern[0], (uint8_t*)&des_attributeIDList[0]);
}
void sdp_general_query_for_uuid128(bd_addr_t remote, uint8_t* uuid){
void sdp_general_query_for_uuid128(btstack_packet_handler_t callback, bd_addr_t remote, uint8_t* uuid){
if (!sdp_client_ready()){
log_error("sdp_general_query_for_uuid called when not readdy");
return;
}
create_service_search_pattern_for_uuid128(uuid);
sdp_parser_init();
sdp_client_query(remote, (uint8_t*)&des_serviceSearchPatternUUID128[0], (uint8_t*)&des_attributeIDList[0]);
sdp_client_query(callback, remote, (uint8_t*)&des_serviceSearchPatternUUID128[0], (uint8_t*)&des_attributeIDList[0]);
}

View File

@ -54,15 +54,21 @@ extern "C" {
*/
uint8_t* create_service_search_pattern_for_uuid(uint16_t uuid);
/**
* @brief Checks if the SDP Client is ready
* @return 1 when no query is active
*/
int sdp_general_query_ready(void);
/*
* @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);
void sdp_general_query_for_uuid(btstack_packet_handler_t callback, bd_addr_t remote, uint16_t uuid16);
/*
* @brief
*/
void sdp_general_query_for_uuid128(bd_addr_t remote, uint8_t* uuid128);
void sdp_general_query_for_uuid128(btstack_packet_handler_t callback, bd_addr_t remote, uint8_t* uuid128);
/* API_END */

View File

@ -61,15 +61,15 @@ const char * const type_names[] = { "NIL", "UINT", "INT", "UUID", "STRING", "BOO
#endif
// MARK: DataElement getter
de_size_t de_get_size_type(uint8_t *header){
de_size_t de_get_size_type(const uint8_t *header){
return (de_size_t) (header[0] & 7);
}
de_type_t de_get_element_type(uint8_t *header){
de_type_t de_get_element_type(const uint8_t *header){
return (de_type_t) (header[0] >> 3);
}
int de_get_header_size(uint8_t * header){
int de_get_header_size(const uint8_t * header){
de_size_t de_size = de_get_size_type(header);
if (de_size <= DE_SIZE_128) {
return 1;
@ -77,7 +77,7 @@ int de_get_header_size(uint8_t * header){
return 1 + (1 << (de_size-DE_SIZE_VAR_8));
}
int de_get_data_size(uint8_t * header){
int de_get_data_size(const uint8_t * header){
uint32_t result = 0;
de_type_t de_type = de_get_element_type(header);
de_size_t de_size = de_get_size_type(header);
@ -103,19 +103,19 @@ int de_get_data_size(uint8_t * header){
return result;
}
int de_get_len(uint8_t *header){
int de_get_len(const uint8_t *header){
return de_get_header_size(header) + de_get_data_size(header);
}
// @returns OK, if UINT16 value was read
int de_element_get_uint16(uint8_t * element, uint16_t * value){
int de_element_get_uint16(const uint8_t * element, uint16_t * value){
if (de_get_size_type(element) != DE_SIZE_16) return 0;
*value = big_endian_read_16(element, de_get_header_size(element));
return 1;
}
// @returns: element is valid UUID
int de_get_normalized_uuid(uint8_t *uuid128, uint8_t *element){
int de_get_normalized_uuid(uint8_t *uuid128, const uint8_t *element){
de_type_t uuidType = de_get_element_type(element);
de_size_t uuidSize = de_get_size_type(element);
if (uuidType != DE_UUID) return 0;
@ -138,7 +138,7 @@ int de_get_normalized_uuid(uint8_t *uuid128, uint8_t *element){
}
// @returns 0 if no UUID16 or UUID32 is present, and UUID32 otherwise
uint32_t de_get_uuid32(uint8_t * element){
uint32_t de_get_uuid32(const uint8_t * element){
uint8_t uuid128[16];
int validUuid128 = de_get_normalized_uuid(uuid128, element);
if (!validUuid128) return 0;
@ -665,13 +665,13 @@ static int de_traversal_dump_data(uint8_t * element, de_type_t de_type, de_size_
}
#endif
void de_dump_data_element(uint8_t * record){
void de_dump_data_element(const uint8_t * record){
#ifdef ENABLE_SDP_DES_DUMP
int indent = 0;
// hack to get root DES, too.
de_type_t type = de_get_element_type(record);
de_size_t size = de_get_size_type(record);
de_traversal_dump_data(record, type, size, (void*) &indent);
de_traversal_dump_data((uint8_t *) record, type, size, (void*) &indent);
#endif
}

View File

@ -74,23 +74,24 @@ typedef enum {
} 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_dump_data_element(const uint8_t * record);
int de_get_len(const uint8_t * header);
de_size_t de_get_size_type(const uint8_t * header);
de_type_t de_get_element_type(const uint8_t * header);
int de_get_header_size(const uint8_t * header);
int de_element_get_uint16(const uint8_t * element, uint16_t * value);
int de_get_data_size(const uint8_t * header);
uint32_t de_get_uuid32(const uint8_t * element);
int de_get_normalized_uuid(uint8_t *uuid128, const uint8_t *element);
void de_create_sequence(uint8_t * header);
void de_store_descriptor_with_len(uint8_t * header, de_type_t type, de_size_t size, uint32_t len);
uint8_t * de_push_sequence(uint8_t *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 {

View File

@ -59,7 +59,6 @@
#include "l2cap.h"
#include "classic/rfcomm.h"
#include "classic/sdp_server.h"
#include "classic/sdp_parser.h"
#include "btstack_debug.h"
#include "classic/hfp_ag.h"

View File

@ -59,7 +59,6 @@
#include "l2cap.h"
#include "classic/rfcomm.h"
#include "classic/sdp_server.h"
#include "classic/sdp_parser.h"
#include "btstack_debug.h"
#include "classic/hfp_hf.h"

View File

@ -70,7 +70,7 @@ static uint8_t rfcomm_reserved_buffer[1000];
hfp_connection_t * hfp_context;
void (*registered_rfcomm_packet_handler)(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
void (*registered_sdp_app_callback)(uint8_t packet_type, uint8_t *packet, uint16_t size);
void (*registered_sdp_app_callback)(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
uint8_t * get_rfcomm_payload(){
return &rfcomm_payload[0];
@ -198,17 +198,12 @@ int hci_send_cmd(const hci_cmd_t *cmd, ...){
return 0;
}
void sdp_query_rfcomm_register_callback(void(*sdp_app_callback)(uint8_t packet_type, uint8_t *packet, uint16_t size)){
registered_sdp_app_callback = sdp_app_callback;
}
static void sdp_query_complete_response(uint8_t status){
uint8_t event[3];
event[0] = SDP_EVENT_QUERY_COMPLETE;
event[1] = 1;
event[2] = status;
(*registered_sdp_app_callback)(HCI_EVENT_PACKET, event, sizeof(event));
(*registered_sdp_app_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
}
static void sdp_query_rfcomm_service_response(uint8_t status){
@ -219,11 +214,12 @@ static void sdp_query_rfcomm_service_response(uint8_t status){
event[2] = sdp_rfcomm_channel_nr;
memcpy(&event[3], sdp_rfcomm_service_name, sdp_service_name_len);
event[3+sdp_service_name_len] = 0;
(*registered_sdp_app_callback)(HCI_EVENT_PACKET, event, sizeof(event));
(*registered_sdp_app_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
}
void sdp_query_rfcomm_channel_and_name_for_uuid(bd_addr_t remote, uint16_t uuid){
void sdp_query_rfcomm_channel_and_name_for_uuid(btstack_packet_handler_t callback, bd_addr_t remote, uint16_t uuid){
// printf("sdp_query_rfcomm_channel_and_name_for_uuid %p\n", registered_sdp_app_callback);
registered_sdp_app_callback = callback;
sdp_query_rfcomm_service_response(0);
sdp_query_complete_response(0);
}

View File

@ -398,7 +398,7 @@ static void handle_found_service(const char * name, uint8_t port){
rfcomm_channel_nr = port;
}
static void handle_query_rfcomm_event(uint8_t packet_type, uint8_t *packet, uint16_t size){
static void handle_query_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
switch (packet[0]){
case SDP_EVENT_QUERY_RFCOMM_SERVICE:
handle_found_service(sdp_event_query_rfcomm_service_get_name(packet),
@ -596,7 +596,7 @@ static int stdin_process(struct btstack_data_source *ds){
case 'k':
printf("Start SDP query for SPP service\n");
sdp_query_rfcomm_channel_and_name_for_uuid(remote_rfcomm, 0x1101);
sdp_query_rfcomm_channel_and_name_for_uuid(&handle_query_rfcomm_event, remote_rfcomm, 0x1101);
break;
case 't':
@ -790,8 +790,6 @@ int btstack_main(int argc, const char * argv[]){
de_dump_data_element((uint8_t*)dummy_service_buffer);
printf("Dummy service record size: %u\n\r", de_get_len((uint8_t*)dummy_service_buffer));
sdp_register_service((uint8_t*)dummy_service_buffer);
sdp_query_rfcomm_register_callback(handle_query_rfcomm_event);
hci_discoverable_control(0);
hci_connectable_control(0);

View File

@ -107,7 +107,7 @@ static void packet_handler(void * connection, uint8_t packet_type, uint16_t chan
// bt stack activated, get started
if (packet[2] == HCI_STATE_WORKING){
printf("Start SDP RFCOMM Query for UUID 0x%02x\n", SDP_Handsfree);
// sdp_query_rfcomm_channel_and_name_for_uuid(remote, SDP_Handsfree);
sdp_query_rfcomm_channel_and_name_for_uuid(&handle_query_rfcomm_event, remote, SDP_Handsfree);
}
break;
@ -146,7 +146,7 @@ static void hci_event_handler(uint8_t packet_type, uint8_t * packet, uint16_t si
}
void handle_query_rfcomm_event(uint8_t packet_type, uint8_t *packet, uint16_t size){
static void handle_query_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
switch (event->type){
case SDP_EVENT_QUERY_RFCOMM_SERVICE:
channel_nr = sdp_event_query_rfcomm_service_get_name(packet);
@ -177,8 +177,6 @@ int btstack_main(int argc, const char * argv[]){
l2cap_init();
rfcomm_init();
sdp_query_rfcomm_register_callback(handle_query_rfcomm_event);
// turn on!
hci_power_control(HCI_POWER_ON);

View File

@ -103,10 +103,10 @@ int btstack_main(int argc, const char * argv[]){
pan_create_panu_service(pan_service_buffer, 0x10002, network_packet_types, NULL, NULL, BNEP_SECURITY_NONE);
sdp_register_service((uint8_t*)pan_service_buffer);
hsp_ag_create_service((uint8_t *)hsp_ag_service_buffer, 0x10003, 2, "HSP AG");
hsp_ag_create_sdp_record((uint8_t *)hsp_ag_service_buffer, 0x10003, 2, "HSP AG");
sdp_register_service((uint8_t *)hsp_ag_service_buffer);
hsp_hs_create_service((uint8_t *)hsp_hs_service_buffer, 0x10004, 3, "HSP HS", 0);
hsp_hs_create_sdp_record((uint8_t *)hsp_hs_service_buffer, 0x10004, 3, "HSP HS", 0);
sdp_register_service((uint8_t *)hsp_hs_service_buffer);
hfp_ag_create_sdp_record((uint8_t *)hfp_ag_service_buffer, 0x10005, 4, "HFP AG", 0, 0);

View File

@ -15,7 +15,8 @@ VPATH += ${BTSTACK_ROOT}/platform/posix
COMMON = \
sdp_util.c \
sdp_parser.c \
sdp_client.c \
mock.c \
hci_dump.c \
btstack_util.c \

View File

@ -15,11 +15,11 @@
#include "btstack_event.h"
#include "btstack_memory.h"
#include "btstack_run_loop.h"
#include "classic/sdp_parser.h"
#include "hci.h"
#include "hci_cmd.h"
#include "hci_dump.h"
#include "l2cap.h"
#include "mock.h"
#include "CppUTest/TestHarness.h"
#include "CppUTest/CommandLineTestRunner.h"
@ -95,7 +95,6 @@ static uint8_t sdp_test_record_list[] = {
0x09, 0x03, 0x0A, 0x09, 0x00, 0x01, 0x09, 0x03, 0x0B, 0x09, 0x00, 0x05
};
uint16_t attribute_id = -1;
uint16_t record_id = -1;
@ -142,7 +141,7 @@ static void test_attribute_value_event(const uint8_t * event){
}
static void handle_sdp_parser_event(uint8_t packet_type, uint8_t *packet, uint16_t size){
static void handle_sdp_parser_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
switch (packet[0]){
case SDP_EVENT_QUERY_ATTRIBUTE_VALUE:
test_attribute_value_event(packet);
@ -168,8 +167,7 @@ TEST_GROUP(SDPClient){
attribute_value_buffer_size = 1000;
attribute_value = (uint8_t*) malloc(attribute_value_buffer_size);
record_id = -1;
sdp_parser_init();
sdp_parser_register_callback(handle_sdp_parser_event);
sdp_parser_init(&handle_sdp_parser_event);
}
};

View File

@ -21,6 +21,7 @@
#include "hci_dump.h"
#include "l2cap.h"
#include "btstack_event.h"
#include "mock.h"
#include "CppUTest/TestHarness.h"
#include "CppUTest/CommandLineTestRunner.h"
@ -82,15 +83,8 @@ static uint8_t sdp_test_record_list[] = { 0x36, 0x02, 0xE7, 0x35, 0x48,
0x6B, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65
};
// dummy function to allow compile without the stack
extern "C" void sdp_client_query(bd_addr_t remote, uint8_t * des_serviceSearchPattern, uint8_t * des_attributeIDList){
}
// for test purposes
void sdp_query_rfcomm_init();
void handle_query_rfcomm_event(uint8_t packet_type, uint8_t *packet, uint16_t size){
void handle_query_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
switch (packet[0]){
case SDP_EVENT_QUERY_RFCOMM_SERVICE:
channel_nr[service_index] = sdp_event_query_rfcomm_service_get_rfcomm_channel(packet);
@ -109,12 +103,13 @@ void handle_query_rfcomm_event(uint8_t packet_type, uint8_t *packet, uint16_t si
TEST_GROUP(SDPClient){
uint8_t spp_buffer[sizeof(sdp_test_record_list)];
bd_addr_t address;
void setup(void){
service_index = 0;
sdp_query_rfcomm_register_callback(handle_query_rfcomm_event);
sdp_parser_init();
sdp_query_rfcomm_init();
sdp_client_reset(); // avoid "not ready" warning
// start query using public API although data will be injected
sdp_query_rfcomm_channel_and_name_for_uuid(&handle_query_rfcomm_event, address, 0x1234);
}
};
@ -148,7 +143,6 @@ TEST(SDPClient, QueryRFCOMMWithMacOSXData){
"Bluetooth-PDA-Sync", "Headset Audio Gatewa"};
uint8_t expected_channel[] = {10, 2, 15, 3, 4};
// de_dump_data_element(sdp_test_record_list);
sdp_parser_handle_chunk(sdp_test_record_list, de_get_len(sdp_test_record_list));
CHECK_EQUAL(service_index, 5);

View File

@ -15,11 +15,11 @@
#include "btstack_event.h"
#include "btstack_memory.h"
#include "btstack_run_loop.h"
#include "classic/sdp_parser.h"
#include "hci.h"
#include "hci_cmd.h"
#include "hci_dump.h"
#include "l2cap.h"
#include "mock.h"
#include "CppUTest/TestHarness.h"
#include "CppUTest/CommandLineTestRunner.h"
@ -87,7 +87,7 @@ static void test_attribute_value_event(const uint8_t * event){
}
static void handle_sdp_parser_event(uint8_t packet_type, uint8_t *packet, uint16_t size){
static void handle_sdp_parser_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
switch (packet[0]){
case SDP_EVENT_QUERY_ATTRIBUTE_VALUE:
test_attribute_value_event(packet);
@ -113,8 +113,8 @@ TEST_GROUP(SDPClient){
attribute_value_buffer_size = 1000;
attribute_value = (uint8_t*) malloc(attribute_value_buffer_size);
record_id = -1;
sdp_parser_init(&handle_sdp_parser_event);
sdp_parser_init_service_attribute_search();
sdp_parser_register_callback(handle_sdp_parser_event);
}
};

View File

@ -15,11 +15,11 @@
#include "btstack_event.h"
#include "btstack_memory.h"
#include "btstack_run_loop.h"
#include "classic/sdp_parser.h"
#include "hci.h"
#include "hci_cmd.h"
#include "hci_dump.h"
#include "l2cap.h"
#include "mock.h"
#include "CppUTest/TestHarness.h"
#include "CppUTest/CommandLineTestRunner.h"
@ -39,8 +39,7 @@ static uint8_t sdp_test_record_list[] = {
0x00, 0x00, 0x00, 0x0A
};
static void handle_sdp_parser_event(uint8_t packet_type, uint8_t *packet, uint16_t size){
static void handle_sdp_parser_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
static uint32_t record_handle = sdp_test_record_list[0];
switch (packet[0]){
case SDP_EVENT_QUERY_SERVICE_RECORD_HANDLE:
@ -56,8 +55,8 @@ static void handle_sdp_parser_event(uint8_t packet_type, uint8_t *packet, uint16
TEST_GROUP(SDPClient){
void setup(void){
sdp_parser_init(&handle_sdp_parser_event);
sdp_parser_init_service_search();
sdp_parser_register_callback(handle_sdp_parser_event);
}
};