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]. # Defines which examples belong to a group. Example is defined as [example file, example title].
list_of_examples = { list_of_examples = {
"Hello World" : [["led_counter"]], # "Hello World" : [["led_counter"]],
"GAP" : [["gap_inquiry"]], # "GAP" : [["gap_inquiry"]],
"SDP Queries" :[["sdp_general_query"], "SDP Queries" :[#["sdp_general_query"],
["sdp_bnep_query"] ["sdp_bnep_query"]
], ],
"SPP Server" : [["spp_counter"], # "SPP Server" : [["spp_counter"],
["spp_flowcontrol"]], # ["spp_flowcontrol"]],
"BNEP/PAN" : [["panu_demo"]], # "BNEP/PAN" : [["panu_demo"]],
"Low Energy" : [["gatt_browser"], # "Low Energy" : [["gatt_browser"],
["le_counter"]], # ["le_counter"]],
"Dual Mode" : [["spp_and_le_counter"]], # "Dual Mode" : [["spp_and_le_counter"]],
} }
lst_header = """ lst_header = """
@ -51,7 +51,7 @@ examples_header = """
""" """
example_item = """ 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 = """ example_section = """
\subsection{EXAMPLE_TITLE: EXAMPLE_DESC} \subsection{EXAMPLE_TITLE: EXAMPLE_DESC}
@ -59,7 +59,7 @@ example_section = """
""" """
example_subsection = """ example_subsection = """
\subsubsection{LISTING_CAPTION} \subsubsection{SECTION_TITLE}
""" """
listing_start = """ listing_start = """
@ -162,15 +162,15 @@ def writeListings(aout, infile_name, ref_prefix):
continue continue
# detect @section # detect @section
section_parts = re.match('.*(@section)\s*(.*)\s*(\*?/?)\n',line) section_parts = re.match('.*(@section)\s*(.*)(:?\s*.?)\*?/?\n',line)
if section_parts: 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 continue
# detect @subsection # detect @subsection
subsection_parts = re.match('.*(@subsection)\s*(.*)\s*(\*?/?)\n',line) subsection_parts = re.match('.*(@section)\s*(.*)(:?\s*.?)\*?/?\n',line)
if section_parts: 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) aout.write("\n" + subsubsection)
continue continue
@ -186,7 +186,7 @@ def writeListings(aout, infile_name, ref_prefix):
itemize_block = None itemize_block = None
else: else:
if isEmptyCommentLine(line): if isEmptyCommentLine(line):
text_block = text_block + "\n" text_block = text_block + "\n\n"
else: else:
# finish text # finish text
aout.write(text_block) 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){ 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; if (packet_type != HCI_EVENT_PACKET) return;
uint8_t event = packet[0]; uint8_t event = packet[0];
@ -93,6 +129,7 @@ static void packet_handler (void * connection, uint8_t packet_type, uint16_t cha
break; break;
} }
} }
/* LISTING_END */
char * get_string_from_data_element(uint8_t * element){ char * get_string_from_data_element(uint8_t * element){
de_size_t de_size = de_get_size_type(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){ static void handle_sdp_client_query_result(sdp_query_event_t * event){
/* LISTING_PAUSE */
sdp_query_attribute_value_event_t * ve; sdp_query_attribute_value_event_t * ve;
sdp_query_complete_event_t * ce; sdp_query_complete_event_t * ce;
des_iterator_t des_list_it; 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; attribute_value[ve->data_offset] = ve->data;
if ((uint16_t)(ve->data_offset+1) == ve->attribute_length){ if ((uint16_t)(ve->data_offset+1) == ve->attribute_length){
/* LISTING_RESUME */
switch(ve->attribute_id){ switch(ve->attribute_id){
// 0x0001 "Service Class ID List"
case SDP_ServiceClassIDList: case SDP_ServiceClassIDList:
if (de_get_element_type(attribute_value) != DE_DES) break; 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)){ 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; break;
/* LISTING_PAUSE */
// 0x0100 "Service Name"
case 0x0100: case 0x0100:
// 0x0101 "Service Description"
case 0x0101: case 0x0101:
str = get_string_from_data_element(attribute_value); str = get_string_from_data_element(attribute_value);
printf(" ** Attribute 0x%04x: %s\n", ve->attribute_id, str); printf(" ** Attribute 0x%04x: %s\n", ve->attribute_id, str);
free(str); free(str);
break; break;
case 0x004:{ /* LISTING_RESUME */
case SDP_ProtocolDescriptorList:{
printf(" ** Attribute 0x%04x: ", ve->attribute_id); printf(" ** Attribute 0x%04x: ", ve->attribute_id);
uint16_t l2cap_psm = 0; 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("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; break;
/* LISTING_PAUSE */
default: default:
break; break;
} }
} }
break; break;
case SDP_QUERY_COMPLETE: case SDP_QUERY_COMPLETE:
ce = (sdp_query_complete_event_t*) event; ce = (sdp_query_complete_event_t*) event;
printf("General query done with status %d.\n\n", ce->status); printf("General query done with status %d.\n\n", ce->status);
break; break;
} }
/* LISTING_RESUME */
} }
/* LISTING_END */
int btstack_main(int argc, const char * argv[]); int btstack_main(int argc, const char * argv[]);
int btstack_main(int argc, const char * argv[]){ int btstack_main(int argc, const char * argv[]){
printf("Client HCI init done\r\n"); printf("Client HCI init done\r\n");
// init L2CAP sdp_client_init();
l2cap_init();
l2cap_register_packet_handler(packet_handler);
sdp_parser_init();
sdp_parser_register_callback(handle_sdp_client_query_result);
// turn on! // turn on!
hci_power_control(HCI_POWER_ON); hci_power_control(HCI_POWER_ON);

View File

@ -39,11 +39,7 @@
/* EXAMPLE_START(sdp_general_query): Dump remote SDP Records /* EXAMPLE_START(sdp_general_query): Dump remote SDP Records
* *
* @text The example shows how the SDP Client is used to get a list of * @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 * service records on a remote device.
* 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.
*/ */
// ***************************************************************************** // *****************************************************************************
@ -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}; 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 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){ 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]); // 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) { switch (event) {
case BTSTACK_EVENT_STATE: case BTSTACK_EVENT_STATE:
// bt stack activated, get started
if (packet[2] == HCI_STATE_WORKING){ if (packet[2] == HCI_STATE_WORKING){
sdp_general_query_for_uuid(remote, SDP_PublicBrowseGroup); 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; break;
} }
} }
/* LISTING_END */
static void assertBuffer(int size){ static void assertBuffer(int size){
if (size > attribute_value_buffer_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){ static void handle_sdp_client_query_result(sdp_query_event_t * event){
sdp_query_attribute_value_event_t * ve; sdp_query_attribute_value_event_t * ve;
sdp_query_complete_event_t * ce; sdp_query_complete_event_t * ce;
@ -130,18 +164,14 @@ static void handle_sdp_client_query_result(sdp_query_event_t * event){
break; break;
} }
} }
/* LISTING_END */
int btstack_main(int argc, const char * argv[]); int btstack_main(int argc, const char * argv[]);
int btstack_main(int argc, const char * argv[]){ int btstack_main(int argc, const char * argv[]){
printf("Client HCI init done\r\n"); printf("Client HCI init done\r\n");
// init L2CAP sdp_client_init();
l2cap_init();
l2cap_register_packet_handler(packet_handler);
sdp_parser_init();
sdp_parser_register_callback(handle_sdp_client_query_result);
// turn on! // turn on!
hci_power_control(HCI_POWER_ON); hci_power_control(HCI_POWER_ON);