manual: added SDP query examples

This commit is contained in:
Milanka Ringwald 2015-04-24 16:05:54 +02:00
parent cf18d7621d
commit 82d6daf181
3 changed files with 126 additions and 44 deletions

View File

@ -8,17 +8,17 @@ list_of_groups = ["Hello World", "GAP", "SDP Queries", "SPP Server", "BNEP/PAN",
# Defines which examples belong to a group. Example is defined as [example file, example title].
list_of_examples = {
"Hello World" : [["led_counter"]],
"GAP" : [["gap_inquiry"]],
"SDP Queries" :[["sdp_general_query"],
# "Hello World" : [["led_counter"]],
# "GAP" : [["gap_inquiry"]],
"SDP Queries" :[#["sdp_general_query"],
["sdp_bnep_query"]
],
"SPP Server" : [["spp_counter"],
["spp_flowcontrol"]],
"BNEP/PAN" : [["panu_demo"]],
"Low Energy" : [["gatt_browser"],
["le_counter"]],
"Dual Mode" : [["spp_and_le_counter"]],
# "SPP Server" : [["spp_counter"],
# ["spp_flowcontrol"]],
# "BNEP/PAN" : [["panu_demo"]],
# "Low Energy" : [["gatt_browser"],
# ["le_counter"]],
# "Dual Mode" : [["spp_and_le_counter"]],
}
lst_header = """
@ -51,7 +51,7 @@ examples_header = """
"""
example_item = """
\item \emph{EXAMPLE_TITLE}: EXAMPLE_DESC, see Section \\ref{example:EXAMPLE_LABLE}.
\item \emph{EXAMPLE_TITLE}: EXAMPLE_DESC, in Section \\ref{example:EXAMPLE_LABLE}.
"""
example_section = """
\subsection{EXAMPLE_TITLE: EXAMPLE_DESC}
@ -59,7 +59,7 @@ example_section = """
"""
example_subsection = """
\subsubsection{LISTING_CAPTION}
\subsubsection{SECTION_TITLE}
"""
listing_start = """
@ -162,15 +162,15 @@ def writeListings(aout, infile_name, ref_prefix):
continue
# detect @section
section_parts = re.match('.*(@section)\s*(.*)\s*(\*?/?)\n',line)
section_parts = re.match('.*(@section)\s*(.*)(:?\s*.?)\*?/?\n',line)
if section_parts:
aout.write("\n" + example_subsection.replace("LISTING_CAPTION", section_parts.group(2)))
aout.write("\n" + example_subsection.replace("SECTION_TITLE", section_parts.group(2)))
continue
# detect @subsection
subsection_parts = re.match('.*(@subsection)\s*(.*)\s*(\*?/?)\n',line)
subsection_parts = re.match('.*(@section)\s*(.*)(:?\s*.?)\*?/?\n',line)
if section_parts:
subsubsection = example_subsection.replace("LISTING_CAPTION", section_parts.group(2)).replace('section', 'subsection')
subsubsection = example_subsection.replace("SECTION_TITLE", section_parts.group(2)).replace('section', 'subsection')
aout.write("\n" + subsubsection)
continue
@ -186,7 +186,7 @@ def writeListings(aout, infile_name, ref_prefix):
itemize_block = None
else:
if isEmptyCommentLine(line):
text_block = text_block + "\n"
text_block = text_block + "\n\n"
else:
# finish text
aout.write(text_block)

View File

@ -36,8 +36,11 @@
*/
// *****************************************************************************
/* EXAMPLE_START(sdp_bnep_query): Minimal setup for SDP client over USB or UART
/* EXAMPLE_START(sdp_bnep_query): Dump remote BNEP PAN protocol UUID and L2CAP PSM.
*
* @text The example shows how the SDP Client is used to get the BNEP
* service records on a remote device. It extracts the remote BNEP PAN protocol
* UUID and the L2CAP PSM, which are needed to connect to a remote BNEP service.
*/
// *****************************************************************************
@ -77,6 +80,39 @@ static void assertBuffer(int size){
}
}
/* @section SDP Client Setup
*
* @text To receive SDP query events you must register a
* callback, i.e. query handler, with the SPD parser, as shown in
* Listing SDPClientInit. Via this handler, the SDP client will receive events:
* - SDP_QUERY_ATTRIBUTE_VALUE containing the results of the query in chunks,
* - SDP_QUERY_COMPLETE reporting the status and the end of the query.
*/
/* LISTING_START(SDPClientInit): SDP client setup */
static void packet_handler (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
static void handle_sdp_client_query_result(sdp_query_event_t * event);
static void sdp_client_init(){
// init L2CAP
l2cap_init();
l2cap_register_packet_handler(packet_handler);
sdp_parser_init();
sdp_parser_register_callback(handle_sdp_client_query_result);
}
/* LISTING_END */
/* @section SDP Client Query
*
* @text To get the the BNEP service records on a remote device, you need to
* call sdp_general_query_for_uuid() with the remote address and the
* BNEP protocol UUID, as shown in Listing SDPQueryUUID.
* In this example we used fixed address of the remote device.
*/
/* LISTING_START(SDPQueryUUID): Quering the a list of service records on a remote device. */
static void packet_handler (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
if (packet_type != HCI_EVENT_PACKET) return;
uint8_t event = packet[0];
@ -93,6 +129,7 @@ static void packet_handler (void * connection, uint8_t packet_type, uint16_t cha
break;
}
}
/* LISTING_END */
char * get_string_from_data_element(uint8_t * element){
de_size_t de_size = de_get_size_type(element);
@ -115,8 +152,26 @@ char * get_string_from_data_element(uint8_t * element){
}
/* @section Handling SDP Client Query Result
*
* @text The SDP Client returns the result of the query in chunks. Each result
* packet contains the record ID, the Attribute ID, and a chunk of the Attribute
* value, see Listing HandleSDPQUeryResult. Here, we show how to parse the
* Service Class ID List and Protocol Descriptor List, as they contain
* the BNEP Protocol UUID and L2CAP PSM respectively.
*
* Service Class ID List is a data element sequence (DES) of 32bit UUIDs.
* One of these UUIDs is the BNEP PAN protocol UUID. The BNEP PAN protocol UUID
* is within this list.
*
* Protocol Descriptor List is a data element sequence (DES)
* which contains a DES with the L2CAP PSM, and another DES with BNEP
* version of 32bit UUIDs.
*/
/* LISTING_START(HandleSDPQUeryResult): Extracting BNEP Prototocol UUID and L2CAP PSM. */
static void handle_sdp_client_query_result(sdp_query_event_t * event){
/* LISTING_PAUSE */
sdp_query_attribute_value_event_t * ve;
sdp_query_complete_event_t * ce;
des_iterator_t des_list_it;
@ -137,7 +192,10 @@ static void handle_sdp_client_query_result(sdp_query_event_t * event){
attribute_value[ve->data_offset] = ve->data;
if ((uint16_t)(ve->data_offset+1) == ve->attribute_length){
/* LISTING_RESUME */
switch(ve->attribute_id){
// 0x0001 "Service Class ID List"
case SDP_ServiceClassIDList:
if (de_get_element_type(attribute_value) != DE_DES) break;
for (des_iterator_init(&des_list_it, attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)){
@ -155,13 +213,17 @@ static void handle_sdp_client_query_result(sdp_query_event_t * event){
}
}
break;
/* LISTING_PAUSE */
// 0x0100 "Service Name"
case 0x0100:
// 0x0101 "Service Description"
case 0x0101:
str = get_string_from_data_element(attribute_value);
printf(" ** Attribute 0x%04x: %s\n", ve->attribute_id, str);
free(str);
break;
case 0x004:{
/* LISTING_RESUME */
case SDP_ProtocolDescriptorList:{
printf(" ** Attribute 0x%04x: ", ve->attribute_id);
uint16_t l2cap_psm = 0;
@ -190,38 +252,28 @@ static void handle_sdp_client_query_result(sdp_query_event_t * event){
}
}
printf("l2cap_psm 0x%04x, bnep_version 0x%04x\n", l2cap_psm, bnep_version);
// printf(" -> row data (length %d): ", ve->attribute_length);
// hexdumpf(attribute_value, ve->attribute_length);
// printf("\n");
}
break;
/* LISTING_PAUSE */
default:
break;
}
}
break;
case SDP_QUERY_COMPLETE:
ce = (sdp_query_complete_event_t*) event;
printf("General query done with status %d.\n\n", ce->status);
break;
}
/* LISTING_RESUME */
}
/* LISTING_END */
int btstack_main(int argc, const char * argv[]);
int btstack_main(int argc, const char * argv[]){
printf("Client HCI init done\r\n");
// init L2CAP
l2cap_init();
l2cap_register_packet_handler(packet_handler);
sdp_parser_init();
sdp_parser_register_callback(handle_sdp_client_query_result);
sdp_client_init();
// turn on!
hci_power_control(HCI_POWER_ON);

View File

@ -39,11 +39,7 @@
/* EXAMPLE_START(sdp_general_query): Dump remote SDP Records
*
* @text The example shows how the SDP Client is used to get a list of
* service records on a remote device. The address of the remote device is
* fixed in the variable remote below.
* The SDP Client returns the results of the query in chunks. Each result
* packet contains the record ID, the Attribute ID, and a chunk of the Attribute
* value.
* service records on a remote device.
*/
// *****************************************************************************
@ -75,8 +71,38 @@ static const int attribute_value_buffer_size = sizeof(attribute_value);
static bd_addr_t remote = {0x04,0x0C,0xCE,0xE4,0x85,0xD3};
/* @section SDP Client Setup
*
* @text SDP is based on L2CAP. To receive SDP query events you must register a
* callback, i.e. query handler, with the SPD parser, as shown in
* Listing SDPClientInit. Via this handler, the SDP client will receive events:
* - SDP_QUERY_ATTRIBUTE_VALUE containing the results of the query in chunks,
* - SDP_QUERY_COMPLETE reporting the status and the end of the query.
*/
/* LISTING_START(SDPClientInit): SDP client setup */
static void packet_handler (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
static void handle_sdp_client_query_result(sdp_query_event_t * event);
static void sdp_client_init(){
// init L2CAP
l2cap_init();
l2cap_register_packet_handler(packet_handler);
sdp_parser_init();
sdp_parser_register_callback(handle_sdp_client_query_result);
}
/* LISTING_END */
/* @section SDP Client Query
*
* @text To get the a list of service records on a remote device, you need to
* call sdp_general_query_for_uuid() with the remote address and the
* UUID of the public browse group, as shown in Listing SDPQueryUUID.
* In this example we used fixed address of the remote device.
*/
/* LISTING_START(SDPQueryUUID): Quering a list of service records on a remote device. */
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]);
@ -85,7 +111,6 @@ static void packet_handler (void * connection, uint8_t packet_type, uint16_t cha
switch (event) {
case BTSTACK_EVENT_STATE:
// bt stack activated, get started
if (packet[2] == HCI_STATE_WORKING){
sdp_general_query_for_uuid(remote, SDP_PublicBrowseGroup);
}
@ -94,6 +119,7 @@ static void packet_handler (void * connection, uint8_t packet_type, uint16_t cha
break;
}
}
/* LISTING_END */
static void assertBuffer(int size){
if (size > attribute_value_buffer_size){
@ -101,6 +127,14 @@ static void assertBuffer(int size){
}
}
/* @section Handling SDP Client Query Result
*
* @text The SDP Client returns the results of the query in chunks. Each result
* packet contains the record ID, the Attribute ID, and a chunk of the Attribute
* value, see Listing HandleSDPQUeryResult.
*/
/* LISTING_START(HandleSDPQUeryResult): Handling query result chunks. */
static void handle_sdp_client_query_result(sdp_query_event_t * event){
sdp_query_attribute_value_event_t * ve;
sdp_query_complete_event_t * ce;
@ -130,18 +164,14 @@ static void handle_sdp_client_query_result(sdp_query_event_t * event){
break;
}
}
/* LISTING_END */
int btstack_main(int argc, const char * argv[]);
int btstack_main(int argc, const char * argv[]){
printf("Client HCI init done\r\n");
// init L2CAP
l2cap_init();
l2cap_register_packet_handler(packet_handler);
sdp_parser_init();
sdp_parser_register_callback(handle_sdp_client_query_result);
sdp_client_init();
// turn on!
hci_power_control(HCI_POWER_ON);