diff --git a/src/Makefile.in b/src/Makefile.in index bc0166f77..2860fc494 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -28,6 +28,9 @@ BTdaemon_SOURCES = $(libBTstack_SOURCES) \ $(remote_device_db_sources) \ rfcomm.c \ sdp.c \ + sdp_client.c \ + sdp_parser.c \ + sdp_query_rfcomm.c \ $(springboard_access_sources) # use $(CC) for Objective-C files diff --git a/src/Makefile.iphone b/src/Makefile.iphone index ae5a35d25..e2bf50a3b 100644 --- a/src/Makefile.iphone +++ b/src/Makefile.iphone @@ -22,6 +22,9 @@ BTdaemon_FILES = $(libBTstack_FILES) \ remote_device_db_iphone.m \ rfcomm.c \ sdp.c \ + sdp_client.c \ + sdp_parser.c \ + sdp_query_rfcomm.c \ ../SpringBoardAccess/SpringBoardAccess.c BTdaemon_CFLAGS = -I../include -I.. BTdaemon_FRAMEWORKS = IOKit diff --git a/src/sdp_client.c b/src/sdp_client.c new file mode 100644 index 000000000..3e29ecdf0 --- /dev/null +++ b/src/sdp_client.c @@ -0,0 +1,238 @@ + +//***************************************************************************** +// +// minimal setup for SDP client over USB or UART +// +//***************************************************************************** + + +#include "config.h" +#include "sdp_client.h" + +#include + +#include "l2cap.h" +#include "sdp_parser.h" +#include "sdp.h" +#include "debug.h" + +typedef enum { + INIT, W4_CONNECT, W2_SEND, W4_RESPONSE +} 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_sdp_request(uint8_t * data); + +// SDP Client Query +static uint16_t mtu; +static uint16_t sdp_cid = 0x40; +static uint8_t * serviceSearchPattern; +static uint8_t * attributeIDList; +static uint16_t transactionID = 0; +static uint8_t continuationState[16]; +static uint8_t continuationStateLen; + +static sdp_client_state_t sdp_client_state; + +void sdp_client_handle_done(uint8_t status){ + if (status == 0){ + l2cap_disconnect_internal(sdp_cid, 0); + } + sdp_parser_handle_done(status); +} + +// TODO: inline if not needed +void parse_AttributeLists(uint8_t* packet, uint16_t length){ + sdp_parser_handle_chunk(packet, length); +} + + +void hexdump2(void *data, int size){ + int i; + for (i=0; i OK\n\r"); + sdp_client_state = W4_RESPONSE; + break; + case BTSTACK_ACL_BUFFERS_FULL: + printf("l2cap_send_internal() ->BTSTACK_ACL_BUFFERS_FULL\n\r"); + break; + default: + printf("l2cap_send_internal() -> err %d\n\r", err); + break; + } +} + +void parse_ServiceSearchAttributeResponse(uint8_t* packet){ + uint16_t offset = 3; + uint16_t parameterLength = READ_NET_16(packet,offset); + offset+=2; + // AttributeListByteCount <= mtu + uint16_t attributeListByteCount = READ_NET_16(packet,offset); + offset+=2; + + if (attributeListByteCount > mtu){ + log_error("Error parsing ServiceSearchAttributeResponse: Number of bytes in found attribute list is larger then MTU.\n"); + return; + } + + // AttributeLists + parse_AttributeLists(packet+offset, attributeListByteCount); + offset+=attributeListByteCount; + + continuationStateLen = packet[offset]; + offset++; + + if (continuationStateLen > 16){ + log_error("Error parsing ServiceSearchAttributeResponse: Number of bytes in continuation state exceedes 16.\n"); + return; + } + memcpy(continuationState, packet+offset, continuationStateLen); + offset+=continuationStateLen; + + if (parameterLength != offset - 5){ + log_error("Error parsing ServiceSearchAttributeResponse: wrong size of parameters, number of expected bytes%u, actual number %u.\n", parameterLength, offset); + } +} + +void sdp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ + + uint16_t handle; + + printf("l2cap_packet_handler type %u, packet[0] %x\n", packet_type, packet[0]); + + if (packet_type == L2CAP_DATA_PACKET){ + uint16_t responseTransactionID = READ_NET_16(packet,1); + if ( responseTransactionID != transactionID){ + printf("Missmatching transaction ID, expected %u, found %u.\n", transactionID, responseTransactionID); + return; + } + + if (packet[0] == SDP_ServiceSearchAttributeResponse){ + parse_ServiceSearchAttributeResponse(packet); + + // continuation set or DONE? + if (continuationStateLen == 0){ + printf("DONE! All clients already notified.\n"); + sdp_client_handle_done(0); + sdp_client_state = INIT; + return; + } + + // prepare next request and send + sdp_client_state = W2_SEND; + tryToSend(sdp_cid); + } + return; + } + + if (packet_type != HCI_EVENT_PACKET) return; + + switch(packet[0]){ + + case L2CAP_EVENT_CHANNEL_OPENED: + if (sdp_client_state != W4_CONNECT) break; + + // data: event (8), len(8), status (8), address(48), handle (16), psm (16), local_cid(16), remote_cid (16), local_mtu(16), remote_mtu(16) + if (packet[2]) { + printf("Connection failed.\n\r"); + sdp_client_handle_done(packet[2]); + break; + } + sdp_cid = channel; + mtu = READ_BT_16(packet, 17); + handle = READ_BT_16(packet, 9); + printf("Connected, cid %x, mtu %u.\n\r", sdp_cid, mtu); + + sdp_client_state = W2_SEND; + tryToSend(sdp_cid); + break; + case L2CAP_EVENT_CREDITS: + case DAEMON_EVENT_HCI_PACKET_SENT: + tryToSend(sdp_cid); + break; + case L2CAP_EVENT_CHANNEL_CLOSED: + printf("Channel closed.\n\r"); + if (sdp_client_state == INIT) break; + sdp_client_handle_done(SDP_QUERY_INCOMPLETE); + break; + default: + break; + } +} + +static uint16_t setup_sdp_request(uint8_t * data){ + + uint16_t offset = 0; + transactionID++; + // uint8_t SDP_PDU_ID_t.SDP_ServiceSearchRequest; + data[offset++] = SDP_ServiceSearchAttributeRequest; + // uint16_t transactionID + net_store_16(data, offset, transactionID); + offset += 2; + + // param legnth + offset += 2; + + // parameters: + // ServiceSearchPattern - DES (min 1 UUID, max 12) + uint16_t serviceSearchPatternLen = de_get_len(serviceSearchPattern); + memcpy(data + offset, serviceSearchPattern, serviceSearchPatternLen); + offset += serviceSearchPatternLen; + + // MaximumAttributeByteCount - uint16_t 0x0007 - 0xffff -> mtu + net_store_16(data, offset, mtu); + offset += 2; + + // AttibuteIDList + uint16_t attributeIDListLen = de_get_len(attributeIDList); + memcpy(data + offset, attributeIDList, attributeIDListLen); + offset += attributeIDListLen; + + // ContinuationState - uint8_t number of cont. bytes N<=16 + data[offset++] = continuationStateLen; + // - N-bytes previous response from server + memcpy(data + offset, continuationState, continuationStateLen); + offset += continuationStateLen; + + // uint16_t paramLength + net_store_16(data, 3, offset - 5); + + return offset; +} + + + diff --git a/src/sdp_client.h b/src/sdp_client.h new file mode 100644 index 000000000..dad5a444f --- /dev/null +++ b/src/sdp_client.h @@ -0,0 +1,10 @@ + +//***************************************************************************** +// +// minimal setup for SDP client over USB or UART +// +//***************************************************************************** + +#include + +void sdp_client_query(bd_addr_t remote, uint8_t * des_serviceSearchPattern, uint8_t * des_attributeIDList); diff --git a/src/sdp_parser.c b/src/sdp_parser.c new file mode 100644 index 000000000..367cdaeb3 --- /dev/null +++ b/src/sdp_parser.c @@ -0,0 +1,202 @@ +#include "sdp_parser.h" +#include "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 uint32_t attribute_bytes_received = 0; +static uint32_t attribute_bytes_delivered = 0; +static int list_offset = 0; +static int list_size; +static int record_offset = 0; +static int record_size; +static int attribute_value_size; + +static int record_counter = 0; + +static void (*sdp_query_rfcomm_callback)(sdp_parser_event_t * event); + +// Low level parser +static de_state_t de_header_state; + + +void de_state_init(de_state_t * state){ + state->in_state_GET_DE_HEADER_LENGTH = 1; + state->addon_header_bytes = 0; + state->de_size = 0; + 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\n\r"); + } + // printf("Data element payload is %d bytes.\n", 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; + // printf("Data element payload is %d bytes.\n", de_state->de_size); + de_state->in_state_GET_DE_HEADER_LENGTH = 1; + return 1; +} + +void dummy_notify(sdp_parser_event_t* event){} + +void sdp_parser_register_callback(void (*sdp_callback)(sdp_parser_event_t* event)){ + sdp_query_rfcomm_callback = dummy_notify; + if (sdp_callback != NULL){ + sdp_query_rfcomm_callback = sdp_callback; + } +} + +void parse(uint8_t eventByte){ + // count all bytes + list_offset++; + record_offset++; + + // printf("BYTE_RECEIVED %02x\n", 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; + // printf("parser: List offset %u, list size %u\n", 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; + // printf("parser: Record payload is %d bytes.\n", 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; + // printf("ID data is stored in %d bytes.\n", 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; + // printf("parser: Attribute ID: %04x.\n", 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_attribute_value_event_t attribute_value_event = { + .type = SDP_PARSER_ATTRIBUTE_VALUE, + .record_id = record_counter, + .attribute_id = attribute_id, + .attribute_length = attribute_value_size, + .data_offset = attribute_bytes_delivered++, + .data = eventByte + }; + (*sdp_query_rfcomm_callback)((sdp_parser_event_t*)&attribute_value_event); + + 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_attribute_value_event_t attribute_value_event1 = { + .type = SDP_PARSER_ATTRIBUTE_VALUE, + .record_id = record_counter, + .attribute_id = attribute_id, + .attribute_length = attribute_value_size, + .data_offset = attribute_bytes_delivered++, + .data = eventByte + }; + (*sdp_query_rfcomm_callback)((sdp_parser_event_t*)&attribute_value_event1); + // printf("paser: attribute_bytes_received %u, attribute_value_size %u\n", attribute_bytes_received, attribute_value_size); + + if (attribute_bytes_received < attribute_value_size) break; + // printf("parser: Record offset %u, record size %u\n", record_offset, record_size); + if (record_offset != record_size){ + state = GET_ATTRIBUTE_ID_HEADER_LENGTH; + // printf("Get next attribute\n"); + break; + } + record_offset = 0; + // printf("parser: List offset %u, list size %u\n", list_offset, list_size); + if (list_offset != list_size){ + record_counter++; + state = GET_RECORD_LENGTH; + // printf("parser: END_OF_RECORD\n\n"); + break; + } + list_offset = 0; + de_state_init(&de_header_state); + state = GET_LIST_LENGTH; + record_counter = 0; + // printf("parser: END_OF_RECORD & DONE\n\n\n"); + 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 +#include +#include +#include + +#include + +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; + +typedef enum sdp_parser_event_type { + SDP_PARSER_ATTRIBUTE_VALUE = 1, + SDP_PARSER_COMPLETE, +} sdp_parser_event_type_t; + +typedef struct sdp_parser_event { + uint8_t type; +} sdp_parser_event_t; + +typedef struct sdp_parser_attribute_value_event { + uint8_t type; + int record_id; + uint16_t attribute_id; + uint32_t attribute_length; + int data_offset; + uint8_t data; +} sdp_parser_attribute_value_event_t; + +typedef struct sdp_parser_complete_event { + uint8_t type; + uint8_t status; // 0 == OK +} sdp_parser_complete_event_t; + +void de_state_init(de_state_t * state); +int de_state_size(uint8_t eventByte, de_state_t *de_state); + +void sdp_parser_init(); +void sdp_parser_handle_chunk(uint8_t * data, uint16_t size); +void sdp_parser_handle_done(uint8_t status); +void sdp_parser_register_callback(void (*sdp_callback)(sdp_parser_event_t* event)); diff --git a/src/sdp_query_rfcomm.c b/src/sdp_query_rfcomm.c new file mode 100644 index 000000000..791b06618 --- /dev/null +++ b/src/sdp_query_rfcomm.c @@ -0,0 +1,267 @@ + +//***************************************************************************** +// +// minimal setup for SDP client over USB or UART +// +//***************************************************************************** + +#include "sdp_query_rfcomm.h" + +#include +#include +#include +#include + +#include +#include + +#include "sdp_client.h" + +static void dummy_notify_app(sdp_query_rfcomm_event_t* event, void * context); + +typedef enum { + GET_PROTOCOL_LIST_LENGTH = 1, + GET_PROTOCOL_LENGTH, + GET_PROTOCOL_ID_HEADER_LENGTH, + GET_PROTOCOL_ID, + GET_PROTOCOL_VALUE_LENGTH, + GET_PROTOCOL_VALUE +} pdl_state_t; + + +// higher layer query - get rfcomm channel and name + +#define SDP_SERVICE_NAME_LEN 20 + +const uint8_t des_attributeIDList[] = { 0x35, 0x05, 0x0A, 0x00, 0x01, 0x01, 0x00}; // Arribute: 0x0001 - 0x0100 + +static uint8_t des_serviceSearchPattern[5] = {0x35, 0x03, 0x19, 0x00, 0x00}; + +static uint8_t sdp_service_name[SDP_SERVICE_NAME_LEN+1]; +static uint8_t sdp_rfcom_channel_nr = 0; +static uint8_t sdp_service_name_header_size; + +static pdl_state_t pdl_state = GET_PROTOCOL_LIST_LENGTH; +static uint32_t protocol_value_bytes_received = 0; +static uint16_t protocol_id = 0; +static int protocol_offset; +static int protocol_size; +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_context; +static void (*sdp_app_callback)(sdp_query_rfcomm_event_t * event, void * context) = dummy_notify_app; + +// + +static void dummy_notify_app(sdp_query_rfcomm_event_t* event, void * context){} + +void sdp_query_rfcomm_register_callback(void (*sdp_callback)(sdp_query_rfcomm_event_t* event, void * context), void * context){ + sdp_app_callback = dummy_notify_app; + if (sdp_callback != NULL){ + sdp_app_callback = sdp_callback; + } + sdp_app_context = context; +} + +void handleProtocolDescriptorListData(uint32_t attribute_value_length, uint32_t data_offset, uint8_t data){ + // init state on first byte + if (data_offset == 0){ + pdl_state = GET_PROTOCOL_LIST_LENGTH; + } + + // printf("handleProtocolDescriptorListData (%u,%u) %02x\n", attribute_value_length, data_offset, data); + + switch(pdl_state){ + + case GET_PROTOCOL_LIST_LENGTH: + if (!de_state_size(data, &de_header_state)) break; + // printf(" query: PD List payload is %d bytes.\n", de_header_state.de_size); + // printf(" query: PD List offset %u, list size %u\n", de_header_state.de_offset, de_header_state.de_size); + + pdl_state = GET_PROTOCOL_LENGTH; + break; + + case GET_PROTOCOL_LENGTH: + // check size + if (!de_state_size(data, &de_header_state)) break; + // printf(" query: PD Record payload is %d bytes.\n", de_header_state.de_size); + + // cache protocol info + protocol_offset = de_header_state.de_offset; + protocol_size = de_header_state.de_size; + + pdl_state = GET_PROTOCOL_ID_HEADER_LENGTH; + break; + + case GET_PROTOCOL_ID_HEADER_LENGTH: + protocol_offset++; + if (!de_state_size(data, &de_header_state)) break; + + protocol_id = 0; + protocol_id_bytes_to_read = de_header_state.de_size; + // printf(" query: ID data is stored in %d bytes.\n", protocol_id_bytes_to_read); + pdl_state = GET_PROTOCOL_ID; + + break; + + case GET_PROTOCOL_ID: + protocol_offset++; + + protocol_id = (protocol_id << 8) | data; + protocol_id_bytes_to_read--; + if (protocol_id_bytes_to_read > 0) break; + + // printf(" query: Protocol ID: %04x.\n", protocol_id); + + if (protocol_offset >= protocol_size){ + pdl_state = GET_PROTOCOL_LENGTH; + // printf(" query: Get next protocol\n"); + break; + } + + pdl_state = GET_PROTOCOL_VALUE_LENGTH; + protocol_value_bytes_received = 0; + break; + + case GET_PROTOCOL_VALUE_LENGTH: + protocol_offset++; + + if (!de_state_size(data, &de_header_state)) break; + + protocol_value_size = de_header_state.de_size; + pdl_state = GET_PROTOCOL_VALUE; + sdp_rfcom_channel_nr = 0; + break; + + case GET_PROTOCOL_VALUE: + protocol_offset++; + protocol_value_bytes_received++; + + // printf(" query: protocol_value_bytes_received %u, protocol_value_size %u\n", protocol_value_bytes_received, protocol_value_size); + + if (protocol_value_bytes_received < protocol_value_size) break; + + if (protocol_id == 0x0003){ + // printf("\n\n ******* Data ***** %02x\n\n", data); + sdp_rfcom_channel_nr = data; + } + + // printf(" query: protocol done\n"); + // printf(" query: Protocol offset %u, protocol size %u\n", protocol_offset, protocol_size); + + if (protocol_offset >= protocol_size) { + pdl_state = GET_PROTOCOL_LENGTH; + break; + + } + pdl_state = GET_PROTOCOL_ID_HEADER_LENGTH; + // printf(" query: Get next protocol\n"); + break; + default: + break; + } +} + +void handleServiceNameData(uint32_t attribute_value_length, uint32_t data_offset, uint8_t data){ + + // Get Header Len + if (data_offset == 0){ + de_state_size(data, &sn_de_header_state); + sdp_service_name_header_size = sn_de_header_state.addon_header_bytes + 1; + return; + } + + // Get Header + if (data_offset < sdp_service_name_header_size){ + de_state_size(data, &sn_de_header_state); + return; + } + + // Process payload + int name_len = attribute_value_length - sdp_service_name_header_size; + int name_pos = data_offset - sdp_service_name_header_size; + + if (name_pos < SDP_SERVICE_NAME_LEN){ + sdp_service_name[name_pos] = data; + name_pos++; + } + + // sdp_rfcom_channel_nr is stored in Attribute 0x0004 which is received before this 0x0100 + if (name_pos >= SDP_SERVICE_NAME_LEN || name_pos >= name_len){ + sdp_service_name[name_pos] = 0; + } + // notify on last char + if (data_offset == attribute_value_length - 1 && sdp_rfcom_channel_nr!=0){ + sdp_query_rfcomm_service_event_t value_event = { + .type = SDP_QUERY_RFCOMM_SERVICE, + .service_name = (uint8_t *) sdp_service_name, + .rfcomm_channel_nr = sdp_rfcom_channel_nr + }; + printf("Service found %s\n", sdp_service_name); + (*sdp_app_callback)((sdp_query_rfcomm_event_t*)&value_event, sdp_app_context); + sdp_rfcom_channel_nr = 0; + } +} + + +static void handle_sdp_parser_event(sdp_parser_event_t * event){ + // printf(" CN - [ RID, AID, ALen, VOffset] : [%d, %04x, %u, %u, %u] BYTE %02x\n", + // record_id, attribute_id, attribute_length, data_offset, *src); + // return ; + sdp_parser_attribute_value_event_t * ve; + sdp_parser_complete_event_t * ce; + switch (event->type){ + case SDP_PARSER_ATTRIBUTE_VALUE: + ve = (sdp_parser_attribute_value_event_t*) event; + + switch (ve->attribute_id){ + case SDP_ProtocolDescriptorList: + // find rfcomm channel + handleProtocolDescriptorListData(ve->attribute_length, ve->data_offset, ve->data); + break; + case 0x0100: + // get service name + handleServiceNameData(ve->attribute_length, ve->data_offset, ve->data); + break; + default: + // give up + return; + } + break; + case SDP_PARSER_COMPLETE: + ce = (sdp_parser_complete_event_t*) event; + sdp_query_rfcomm_complete_event_t c_event = { + .type = SDP_QUERY_COMPLETE, + .status = ce->status + }; + (*sdp_app_callback)((sdp_query_rfcomm_event_t*)&c_event, sdp_app_context); + break; + } + // insert higher level code HERE +} + +void sdp_query_rfcomm_init(){ + // init + de_state_init(&de_header_state); + de_state_init(&sn_de_header_state); + pdl_state = GET_PROTOCOL_LIST_LENGTH; + protocol_offset = 0; + sdp_parser_register_callback(handle_sdp_parser_event); +} + + +void sdp_query_rfcomm_channel_and_name_for_service_with_service_search_pattern(bd_addr_t remote, uint8_t * serviceSearchPattern){ + sdp_parser_init(); + sdp_query_rfcomm_init(); + sdp_client_query(remote, serviceSearchPattern, (uint8_t*)&des_attributeIDList[0]); +} + +void sdp_query_rfcomm_channel_and_name_for_service_with_uuid(bd_addr_t remote, uint16_t uuid){ + net_store_16(des_serviceSearchPattern, 3, uuid); + sdp_query_rfcomm_channel_and_name_for_service_with_service_search_pattern(remote, (uint8_t*)des_serviceSearchPattern); +} + + diff --git a/src/sdp_query_rfcomm.h b/src/sdp_query_rfcomm.h new file mode 100644 index 000000000..134e2b34d --- /dev/null +++ b/src/sdp_query_rfcomm.h @@ -0,0 +1,31 @@ + +//***************************************************************************** +// +// minimal setup for SDP client over USB or UART +// +//***************************************************************************** + +#include +#include "sdp_parser.h" + + +typedef struct sdp_query_rfcomm_event { + uint8_t type; +} sdp_query_rfcomm_event_t; + +typedef struct sdp_query_rfcomm_service_event { + uint8_t type; + uint8_t rfcomm_channel_nr; + uint8_t * service_name; +} sdp_query_rfcomm_service_event_t; + +typedef struct sdp_query_rfcomm_complete_event { + uint8_t type; + uint8_t status; // 0 == OK +} sdp_query_rfcomm_complete_event_t; + + +void sdp_query_rfcomm_init(void); +void sdp_query_rfcomm_channel_and_name_for_service_with_uuid(bd_addr_t remote, uint16_t uuid); +void sdp_query_rfcomm_channel_and_name_for_service_with_service_search_pattern(bd_addr_t remote, uint8_t * des_serviceSearchPattern); +void sdp_query_rfcomm_register_callback(void(*sdp_app_callback)(sdp_query_rfcomm_event_t * event, void * context), void * context);