static void sdpc_trysend() { uint8_t buf[128]; if (state != SENDING) return; if (!l2cap_cid) return; if (!l2cap_can_send_packet_now(l2cap_cid)) return; buf[0] = SDP_ServiceSearchAttributeRequest; net_store_16(buf, 1, transitionid++); uint8_t *param = &buf[5]; de_create_sequence(param); de_add_number(param, DE_UUID, DE_SIZE_16, serviceids[current_server]); uint16_t size = de_get_len(param); net_store_16(param, size, 30); // max length is 30 bytes size+=2; de_create_sequence(param + size); //de_add_number(param + size, DE_UINT, DE_SIZE_16, SDP_ServiceClassIDList); de_add_number(param + size, DE_UINT, DE_SIZE_16, SDP_ProtocolDescriptorList); size += de_get_len(param + size); param[size++] = 0; net_store_16(buf, 3, size); hexdump(buf, size + 5); int err = l2cap_send_internal(l2cap_cid, buf, size + 5); if (!err) { state = RECV; log_info("sdp request sent.\n"); } else { log_info("sdpc_trysend l2cap_send_internal error: %d\n", err); } }
int btstack_main(int argc, const char * argv[]){ printf("Starting up..\n"); hci_set_class_of_device(0x200404); hci_disable_l2cap_timeout_check(); hci_ssp_set_io_capability(IO_CAPABILITY_NO_INPUT_NO_OUTPUT); gap_io_capabilities = "IO_CAPABILITY_NO_INPUT_NO_OUTPUT"; hci_ssp_set_authentication_requirement(0); hci_ssp_set_auto_accept(0); // gap_set_bondable_mode(0); l2cap_init(); l2cap_register_packet_handler(&packet_handler2); l2cap_register_fixed_channel(&packet_handler, L2CAP_CID_CONNECTIONLESS_CHANNEL); rfcomm_init(); rfcomm_register_packet_handler(packet_handler2); rfcomm_register_service_internal(NULL, RFCOMM_SERVER_CHANNEL, 150); // reserved channel, mtu=100 // init SDP, create record for SPP and register with SDP sdp_init(); memset(spp_service_buffer, 0, sizeof(spp_service_buffer)); sdp_create_spp_service((uint8_t*) spp_service_buffer, RFCOMM_SERVER_CHANNEL, "SPP Counter"); de_dump_data_element((uint8_t*) spp_service_buffer); printf("SDP service record size: %u\n\r", de_get_len((uint8_t*)spp_service_buffer)); sdp_register_service_internal(NULL, (uint8_t*)spp_service_buffer); memset(dummy_service_buffer, 0, sizeof(dummy_service_buffer)); sdp_create_dummy_service((uint8_t*)dummy_service_buffer, "UUID128 Test"); 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_internal(NULL, (uint8_t*)dummy_service_buffer); sdp_query_rfcomm_register_callback(handle_query_rfcomm_event, NULL); hci_discoverable_control(0); hci_connectable_control(0); // turn on! hci_power_control(HCI_POWER_ON); btstack_stdin_setup(stdin_process); // set one-shot timer // timer_source_t heartbeat; // heartbeat.process = &heartbeat_handler; // run_loop_set_timer(&heartbeat, HEARTBEAT_PERIOD_MS); // run_loop_add_timer(&heartbeat); return 0; }
static uint16_t setup_service_search_request(uint8_t * data){ uint16_t offset = 0; transactionID++; // uint8_t SDP_PDU_ID_t.SDP_ServiceSearchRequest; data[offset++] = SDP_ServiceSearchRequest; // 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; // 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; }
/* LISTING_START(SPPSetup): SPP service setup */ void spp_service_setup(){ l2cap_init(); l2cap_register_packet_handler(packet_handler); rfcomm_init(); rfcomm_register_packet_handler(packet_handler); rfcomm_register_service_internal(NULL, RFCOMM_SERVER_CHANNEL, 0xffff); // reserved channel, mtu limited by l2cap // init SDP, create record for SPP and register with SDP sdp_init(); memset(spp_service_buffer, 0, sizeof(spp_service_buffer)); /* LISTING_PAUSE */ #ifdef EMBEDDED /* LISTING_RESUME */ service_record_item_t * service_record_item = (service_record_item_t *) spp_service_buffer; sdp_create_spp_service( (uint8_t*) &service_record_item->service_record, RFCOMM_SERVER_CHANNEL, "SPP Counter"); printf("SDP service buffer size: %u\n", (uint16_t) (sizeof(service_record_item_t) + de_get_len((uint8_t*) &service_record_item->service_record))); sdp_register_service_internal(NULL, service_record_item); /* LISTING_PAUSE */ #else sdp_create_spp_service( spp_service_buffer, RFCOMM_SERVER_CHANNEL, "SPP Counter"); printf("SDP service record size: %u\n", de_get_len(spp_service_buffer)); sdp_register_service_internal(NULL, spp_service_buffer); #endif /* LISTING_RESUME */ }
int btstack_main(int argc, const char * argv[]){ (void)argc; (void)argv; // register for HCI events hci_event_callback_registration.callback = &packet_handler; hci_add_event_handler(&hci_event_callback_registration); hci_register_sco_packet_handler(&packet_handler); gap_discoverable_control(1); gap_set_class_of_device(0x2540); gap_set_local_name("HID Mouse Demo 00:00:00:00:00:00"); // L2CAP l2cap_init(); // SDP Server sdp_init(); memset(hid_service_buffer, 0, sizeof(hid_service_buffer)); // hid sevice subclass 2540 Keyboard, hid counntry code 33 US, hid virtual cable off, hid reconnect initiate off, hid boot device off hid_create_sdp_record(hid_service_buffer, 0x10001, 0x2540, 33, 0, 0, 0, hid_descriptor_mouse_boot_mode, sizeof(hid_descriptor_mouse_boot_mode), hid_device_name); printf("SDP service record size: %u\n", de_get_len( hid_service_buffer)); sdp_register_service(hid_service_buffer); // HID Device hid_device_init(); hid_device_register_packet_handler(&packet_handler); #ifdef HAVE_BTSTACK_STDIN btstack_stdin_setup(stdin_process); #endif // turn on! hci_power_control(HCI_POWER_ON); return 0; }
int btstack_main(int argc, const char * argv[]){ /* Register for HCI events */ hci_event_callback_registration.callback = &packet_handler; hci_add_event_handler(&hci_event_callback_registration); /* Initialize L2CAP */ l2cap_init(); /* Initialise BNEP */ bnep_init(); bnep_register_service(&packet_handler, bnep_local_service_uuid, 1691); /* Minimum L2CAP MTU for bnep is 1691 bytes */ /* Initialize SDP and add PANU record */ sdp_init(); uint16_t network_packet_types[] = { NETWORK_TYPE_IPv4, NETWORK_TYPE_ARP, 0}; // 0 as end of list pan_create_panu_sdp_record(panu_sdp_record, 0x10002, network_packet_types, NULL, NULL, BNEP_SECURITY_NONE); printf("SDP service record size: %u\n", de_get_len((uint8_t*) panu_sdp_record)); sdp_register_service((uint8_t*)panu_sdp_record); /* Turn on the device */ hci_power_control(HCI_POWER_ON); gap_discoverable_control(1); btstack_stdin_setup(stdin_process); return 0; }
void setup(void){ /// GET STARTED with BTstack /// btstack_memory_init(); run_loop_init(RUN_LOOP_POSIX); // use logger: format HCI_DUMP_PACKETLOGGER, HCI_DUMP_BLUEZ or HCI_DUMP_STDOUT hci_dump_open("/tmp/hci_dump.pklg", HCI_DUMP_PACKETLOGGER); // init HCI hci_transport_t * transport = hci_transport_usb_instance(); hci_uart_config_t * config = NULL; bt_control_t * control = NULL; remote_device_db_t * remote_db = (remote_device_db_t *) &remote_device_db_memory; hci_init(transport, config, control, remote_db); hci_discoverable_control(1); l2cap_init(); l2cap_register_packet_handler(packet_handler); rfcomm_init(); rfcomm_register_packet_handler(packet_handler); rfcomm_register_service_internal(NULL, RFCOMM_SERVER_CHANNEL, 100); // reserved channel, mtu=100 // init SDP, create record for SPP and register with SDP sdp_init(); memset(spp_service_buffer, 0, sizeof(spp_service_buffer)); // service_record_item_t * service_record_item = (service_record_item_t *) spp_service_buffer; // sdp_create_spp_service( (uint8_t*) &service_record_item->service_record, RFCOMM_SERVER_CHANNEL, "SPP Counter"); // printf("SDP service buffer size: %u\n\r", (uint16_t) (sizeof(service_record_item_t) + de_get_len((uint8_t*) &service_record_item->service_record))); // sdp_register_service_internal(NULL, service_record_item); sdp_create_spp_service( spp_service_buffer, RFCOMM_SERVER_CHANNEL, "SPP Counter"); printf("SDP service record size: %u\n\r", de_get_len(spp_service_buffer)); sdp_register_service_internal(NULL, spp_service_buffer); }
int btstack_main(int argc, const char * argv[]){ /* Initialize L2CAP */ l2cap_init(); l2cap_register_packet_handler(packet_handler); /* Initialise BNEP */ bnep_init(); bnep_register_packet_handler(packet_handler); bnep_register_service(NULL, bnep_local_service_uuid, 1691); /* Minimum L2CAP MTU for bnep is 1691 bytes */ /* Initialize SDP and add PANU record */ sdp_init(); uint16_t network_packet_types[] = { NETWORK_TYPE_IPv4, NETWORK_TYPE_ARP, 0}; // 0 as end of list #ifdef EMBEDDED service_record_item_t * service_record_item = (service_record_item_t *) panu_sdp_record; pan_create_panu_service((uint8_t*) &service_record_item->service_record, network_packet_types, NULL, NULL, BNEP_SECURITY_NONE); printf("SDP service buffer size: %u\n", (uint16_t) (sizeof(service_record_item_t) + de_get_len((uint8_t*) &service_record_item->service_record))); sdp_register_service_internal(NULL, service_record_item); #else pan_create_panu_service(panu_sdp_record, network_packet_types, NULL, NULL, BNEP_SECURITY_NONE); printf("SDP service record size: %u\n", de_get_len((uint8_t*) panu_sdp_record)); sdp_register_service_internal(NULL, (uint8_t*)panu_sdp_record); #endif /* Turn on the device */ hci_power_control(HCI_POWER_ON); hci_discoverable_control(1); btstack_stdin_setup(stdin_process); return 0; }
int btstack_main(void) { // register for HCI events hci_event_callback_registration.callback = &packet_handler; hci_add_event_handler(&hci_event_callback_registration); l2cap_init(); rfcomm_init(); rfcomm_register_service(packet_handler, RFCOMM_SERVER_CHANNEL, 0xffff); // init SDP, create record for SPP and register with SDP sdp_init(); memset(spp_service_buffer, 0, sizeof(spp_service_buffer)); spp_create_sdp_record(spp_service_buffer, 0x10001, RFCOMM_SERVER_CHANNEL, "SPP Counter"); sdp_register_service(spp_service_buffer); printf("SDP service record size: %u\n", de_get_len(spp_service_buffer)); gap_set_local_name("SPP and LE Counter 00:00:00:00:00:00"); gap_ssp_set_io_capability(SSP_IO_CAPABILITY_DISPLAY_YES_NO); gap_discoverable_control(1); // setup le device db le_device_db_init(); // setup SM: Display only sm_init(); // setup ATT server att_server_init(profile_data, att_read_callback, att_write_callback); att_server_register_packet_handler(packet_handler); // set one-shot timer heartbeat.process = &heartbeat_handler; btstack_run_loop_set_timer(&heartbeat, HEARTBEAT_PERIOD_MS); btstack_run_loop_add_timer(&heartbeat); // setup advertisements uint16_t adv_int_min = 0x0030; uint16_t adv_int_max = 0x0030; uint8_t adv_type = 0; bd_addr_t null_addr; memset(null_addr, 0, 6); gap_advertisements_set_params(adv_int_min, adv_int_max, adv_type, 0, null_addr, 0x07, 0x00); gap_advertisements_set_data(adv_data_len, (uint8_t*) adv_data); gap_advertisements_enable(1); // beat once beat(); // turn on! hci_power_control(HCI_POWER_ON); return 0; }
void deviceid_init() { memset(&did_service_record, 0, sizeof(did_service_record)); did_service_record.service_record = (uint8_t*)&did_service_buffer[0]; #if 1 sdp_create_did_service((uint8_t*)did_service_record.service_record); log_info("SDP service buffer size: %u\n", de_get_len(did_service_record.service_record)); //hexdump((void*)did_service_buffer, de_get_len(did_service_record.service_record)); //de_dump_data_element(did_service_record.service_record); #endif sdp_register_service_internal(NULL, &did_service_record); }
int btstack_main(void) { hci_discoverable_control(1); l2cap_init(); l2cap_register_packet_handler(packet_handler); rfcomm_init(); rfcomm_register_packet_handler(packet_handler); rfcomm_register_service_internal(NULL, RFCOMM_SERVER_CHANNEL, 0xffff); // init SDP, create record for SPP and register with SDP sdp_init(); memset(spp_service_buffer, 0, sizeof(spp_service_buffer)); /* LISTING_PAUSE */ #ifdef EMBEDDED /* LISTING_RESUME */ service_record_item_t * service_record_item = (service_record_item_t *) spp_service_buffer; sdp_create_spp_service( (uint8_t*) &service_record_item->service_record, RFCOMM_SERVER_CHANNEL, "SPP Counter"); printf("SDP service buffer size: %u\n", (uint16_t) (sizeof(service_record_item_t) + de_get_len((uint8_t*) &service_record_item->service_record))); sdp_register_service_internal(NULL, service_record_item); /* LISTING_PAUSE */ #else sdp_create_spp_service( spp_service_buffer, RFCOMM_SERVER_CHANNEL, "SPP Counter"); printf("SDP service record size: %u\n", de_get_len(spp_service_buffer)); sdp_register_service_internal(NULL, spp_service_buffer); #endif /* LISTING_RESUME */ hci_ssp_set_io_capability(SSP_IO_CAPABILITY_DISPLAY_YES_NO); // setup le device db le_device_db_init(); // setup SM: Display only sm_init(); // setup ATT server att_server_init(profile_data, att_read_callback, att_write_callback); att_dump_attributes(); // set one-shot timer heartbeat.process = &heartbeat_handler; run_loop_set_timer(&heartbeat, HEARTBEAT_PERIOD_MS); run_loop_add_timer(&heartbeat); // turn on! hci_power_control(HCI_POWER_ON); return 0; }
int btstack_main(int argc, const char * argv[]){ hci_discoverable_control(1); l2cap_init(); l2cap_register_packet_handler(packet_handler); rfcomm_init(); rfcomm_register_packet_handler(packet_handler); rfcomm_register_service_internal(NULL, RFCOMM_SERVER_CHANNEL, 0xffff); // reserved channel, mtu limited by l2cap // init SDP, create record for SPP and register with SDP sdp_init(); memset(spp_service_buffer, 0, sizeof(spp_service_buffer)); #ifdef EMBEDDED service_record_item_t * service_record_item = (service_record_item_t *) spp_service_buffer; sdp_create_spp_service( (uint8_t*) &service_record_item->service_record, RFCOMM_SERVER_CHANNEL, "SPP Counter"); printf("SDP service buffer size: %u\n", (uint16_t) (sizeof(service_record_item_t) + de_get_len((uint8_t*) &service_record_item->service_record))); sdp_register_service_internal(NULL, service_record_item); #else sdp_create_spp_service( spp_service_buffer, RFCOMM_SERVER_CHANNEL, "SPP Counter"); printf("SDP service record size: %u\n", de_get_len(spp_service_buffer)); sdp_register_service_internal(NULL, spp_service_buffer); #endif hci_ssp_set_io_capability(SSP_IO_CAPABILITY_DISPLAY_YES_NO); // set one-shot timer timer_source_t heartbeat; heartbeat.process = &heartbeat_handler; run_loop_set_timer(&heartbeat, HEARTBEAT_PERIOD_MS); run_loop_add_timer(&heartbeat); // turn on! hci_power_control(HCI_POWER_ON); // go! run_loop_execute(); // happy compiler! return 0; }
/* LISTING_START(explicitFlowControl): Providing one initial credit during RFCOMM service initialization */ static void spp_service_setup(void){ // register for HCI events hci_event_callback_registration.callback = &packet_handler; hci_add_event_handler(&hci_event_callback_registration); // init L2CAP l2cap_init(); // init RFCOMM rfcomm_init(); // reserved channel, mtu limited by l2cap, 1 credit rfcomm_register_service_with_initial_credits(&packet_handler, rfcomm_channel_nr, 0xffff, 1); // init SDP, create record for SPP and register with SDP sdp_init(); memset(spp_service_buffer, 0, sizeof(spp_service_buffer)); spp_create_sdp_record(spp_service_buffer, 0x10001, 1, "SPP Counter"); sdp_register_service(spp_service_buffer); printf("SDP service buffer size: %u\n\r", (uint16_t) de_get_len(spp_service_buffer)); }
static uint16_t setup_service_attribute_request(uint8_t * data){ uint16_t offset = 0; transactionID++; // uint8_t SDP_PDU_ID_t.SDP_ServiceSearchRequest; data[offset++] = SDP_ServiceAttributeRequest; // uint16_t transactionID net_store_16(data, offset, transactionID); offset += 2; // param legnth offset += 2; // parameters: // ServiceRecordHandle net_store_32(data, offset, serviceRecordHandle); offset += 4; // 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; }
int btstack_main(int argc, const char * argv[]){ // register for HCI events hci_event_callback_registration.callback = &packet_handler; hci_add_event_handler(&hci_event_callback_registration); // init L2CAP l2cap_init(); // init RFCOMM rfcomm_init(); rfcomm_register_service(packet_handler, rfcomm_channel_nr, 100); // reserved channel, mtu=100 // init SDP, create record for SPP and register with SDP sdp_init(); memset(spp_service_buffer, 0, sizeof(spp_service_buffer)); spp_create_sdp_record( (uint8_t*) spp_service_buffer, 1, "SPP Counter"); printf("SDP service buffer size: %u\n\r", (uint16_t) (de_get_len((uint8_t*) spp_service_buffer))); sdp_register_service(service_record_item); // set one-shot timer btstack_timer_source_t heartbeat; heartbeat.process = &heartbeat_handler; btstack_run_loop_set_timer(&heartbeat, HEARTBEAT_PERIOD_MS); btstack_run_loop_add_timer(&heartbeat); // set local name gap_set_local_name("BlueMSP-Demo"); // make discoverable gap_discoverable_control(1); printf("Run...\n\r"); // turn on! hci_power_control(HCI_POWER_ON); return 0; }
int sdp_handle_service_search_attribute_request(uint8_t * packet, uint16_t remote_mtu) { // SDP header before attribute sevice list: 7 // Continuation, worst case: 5 // get request details uint16_t transaction_id = READ_NET_16(packet, 1); // not used yet - uint16_t param_len = READ_NET_16(packet, 3); uint8_t * serviceSearchPattern = &packet[5]; uint16_t serviceSearchPatternLen = de_get_len(serviceSearchPattern); uint16_t maximumAttributeByteCount = READ_NET_16(packet, 5 + serviceSearchPatternLen); uint8_t * attributeIDList = &packet[5+serviceSearchPatternLen+2]; uint16_t attributeIDListLen = de_get_len(attributeIDList); uint8_t * continuationState = &packet[5+serviceSearchPatternLen+2+attributeIDListLen]; // calc maximumAttributeByteCount based on remote MTU, SDP header and reserved Continuation block uint16_t maximumAttributeByteCount2 = remote_mtu - 12; if (maximumAttributeByteCount2 < maximumAttributeByteCount) { maximumAttributeByteCount = maximumAttributeByteCount2; } // continuation state contains: index of next service record to examine // continuation state contains: byte offset into this service record uint16_t continuation_service_index = 0; uint16_t continuation_offset = 0; if (continuationState[0] == 4) { continuation_service_index = READ_NET_16(continuationState, 1); continuation_offset = READ_NET_16(continuationState, 3); } // log_info("--> sdp_handle_service_search_attribute_request, cont %u/%u, max %u", continuation_service_index, continuation_offset, maximumAttributeByteCount); // AttributeLists - starts at offset 7 uint16_t pos = 7; // add DES with total size for first request if (continuation_service_index == 0 && continuation_offset == 0) { uint16_t total_response_size = sdp_get_size_for_service_search_attribute_response(serviceSearchPattern, attributeIDList); de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, total_response_size); // log_info("total response size %u", total_response_size); pos += 3; maximumAttributeByteCount -= 3; } // create attribute list int first_answer = 1; int continuation = 0; uint16_t current_service_index = 0; linked_item_t *it = (linked_item_t *) sdp_service_records; for ( ; it ; it = it->next, ++current_service_index) { service_record_item_t * item = (service_record_item_t *) it; if (current_service_index < continuation_service_index ) continue; if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue; if (continuation_offset == 0) { // get size of this record uint16_t filtered_attributes_size = spd_get_filtered_size(item->service_record, attributeIDList); // stop if complete record doesn't fits into response but we already have a partial response if ((filtered_attributes_size + 3 > maximumAttributeByteCount) && !first_answer) { continuation = 1; break; } // store DES de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, filtered_attributes_size); pos += 3; maximumAttributeByteCount -= 3; } first_answer = 0; // copy maximumAttributeByteCount from record uint16_t bytes_used; int complete = sdp_filter_attributes_in_attributeIDList(item->service_record, attributeIDList, continuation_offset, maximumAttributeByteCount, &bytes_used, &sdp_response_buffer[pos]); pos += bytes_used; maximumAttributeByteCount -= bytes_used; if (complete) { continuation_offset = 0; continue; } continuation = 1; continuation_offset += bytes_used; break; } uint16_t attributeListsByteCount = pos - 7; // Continuation State if (continuation) { sdp_response_buffer[pos++] = 4; net_store_16(sdp_response_buffer, pos, (uint16_t) current_service_index); pos += 2; net_store_16(sdp_response_buffer, pos, continuation_offset); pos += 2; } else { // complete sdp_response_buffer[pos++] = 0; } // create SDP header sdp_response_buffer[0] = SDP_ServiceSearchAttributeResponse; net_store_16(sdp_response_buffer, 1, transaction_id); net_store_16(sdp_response_buffer, 3, pos - 5); // size of variable payload net_store_16(sdp_response_buffer, 5, attributeListsByteCount); return pos; }
int sdp_handle_service_attribute_request(uint8_t * packet, uint16_t remote_mtu) { // get request details uint16_t transaction_id = READ_NET_16(packet, 1); // not used yet - uint16_t param_len = READ_NET_16(packet, 3); uint32_t serviceRecordHandle = READ_NET_32(packet, 5); uint16_t maximumAttributeByteCount = READ_NET_16(packet, 9); uint8_t * attributeIDList = &packet[11]; uint16_t attributeIDListLen = de_get_len(attributeIDList); uint8_t * continuationState = &packet[11+attributeIDListLen]; // calc maximumAttributeByteCount based on remote MTU uint16_t maximumAttributeByteCount2 = remote_mtu - (7+3); if (maximumAttributeByteCount2 < maximumAttributeByteCount) { maximumAttributeByteCount = maximumAttributeByteCount2; } // continuation state contains the offset into the complete response uint16_t continuation_offset = 0; if (continuationState[0] == 2) { continuation_offset = READ_NET_16(continuationState, 1); } // get service record service_record_item_t * item = sdp_get_record_for_handle(serviceRecordHandle); if (!item) { // service record handle doesn't exist return sdp_create_error_response(transaction_id, 0x0002); /// invalid Service Record Handle } // AttributeList - starts at offset 7 uint16_t pos = 7; if (continuation_offset == 0) { // get size of this record uint16_t filtered_attributes_size = spd_get_filtered_size(item->service_record, attributeIDList); // store DES de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, filtered_attributes_size); maximumAttributeByteCount -= 3; pos += 3; } // copy maximumAttributeByteCount from record uint16_t bytes_used; int complete = sdp_filter_attributes_in_attributeIDList(item->service_record, attributeIDList, continuation_offset, maximumAttributeByteCount, &bytes_used, &sdp_response_buffer[pos]); pos += bytes_used; uint16_t attributeListByteCount = pos - 7; if (complete) { sdp_response_buffer[pos++] = 0; } else { continuation_offset += bytes_used; sdp_response_buffer[pos++] = 2; net_store_16(sdp_response_buffer, pos, continuation_offset); pos += 2; } // header sdp_response_buffer[0] = SDP_ServiceAttributeResponse; net_store_16(sdp_response_buffer, 1, transaction_id); net_store_16(sdp_response_buffer, 3, pos - 5); // size of variable payload net_store_16(sdp_response_buffer, 5, attributeListByteCount); return pos; }
int sdp_handle_service_search_request(uint8_t * packet, uint16_t remote_mtu) { // get request details uint16_t transaction_id = READ_NET_16(packet, 1); // not used yet - uint16_t param_len = READ_NET_16(packet, 3); uint8_t * serviceSearchPattern = &packet[5]; uint16_t serviceSearchPatternLen = de_get_len(serviceSearchPattern); uint16_t maximumServiceRecordCount = READ_NET_16(packet, 5 + serviceSearchPatternLen); uint8_t * continuationState = &packet[5+serviceSearchPatternLen+2]; // calc maxumumServiceRecordCount based on remote MTU uint16_t maxNrServiceRecordsPerResponse = (remote_mtu - (9+3))/4; // continuation state contains index of next service record to examine int continuation = 0; uint16_t continuation_index = 0; if (continuationState[0] == 2) { continuation_index = READ_NET_16(continuationState, 1); } // get and limit total count linked_item_t *it; uint16_t total_service_count = 0; for (it = (linked_item_t *) sdp_service_records; it ; it = it->next) { service_record_item_t * item = (service_record_item_t *) it; if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue; total_service_count++; } if (total_service_count > maximumServiceRecordCount) { total_service_count = maximumServiceRecordCount; } // ServiceRecordHandleList at 9 uint16_t pos = 9; uint16_t current_service_count = 0; uint16_t current_service_index = 0; uint16_t matching_service_count = 0; for (it = (linked_item_t *) sdp_service_records; it ; it = it->next, ++current_service_index) { service_record_item_t * item = (service_record_item_t *) it; if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue; matching_service_count++; if (current_service_index < continuation_index) continue; net_store_32(sdp_response_buffer, pos, item->service_record_handle); pos += 4; current_service_count++; if (matching_service_count >= total_service_count) break; if (current_service_count >= maxNrServiceRecordsPerResponse) { continuation = 1; continuation_index = current_service_index + 1; break; } } // Store continuation state if (continuation) { sdp_response_buffer[pos++] = 2; net_store_16(sdp_response_buffer, pos, continuation_index); pos += 2; } else { sdp_response_buffer[pos++] = 0; } // header sdp_response_buffer[0] = SDP_ServiceSearchResponse; net_store_16(sdp_response_buffer, 1, transaction_id); net_store_16(sdp_response_buffer, 3, pos - 5); // size of variable payload net_store_16(sdp_response_buffer, 5, total_service_count); net_store_16(sdp_response_buffer, 7, current_service_count); return pos; }
void sdp_test(){ const uint16_t remote_mtu = 48; uint8_t allAttributeIDs[20]; // // create an attribute list de_create_sequence(allAttributeIDs); de_add_number(allAttributeIDs, DE_UINT, DE_SIZE_32, 0x0000ffff); // create two records with 2 attributes each de_create_sequence(record); de_add_number(record, DE_UINT, DE_SIZE_16, SDP_ServiceRecordHandle); de_add_number(record, DE_UINT, DE_SIZE_32, 0x10001); de_add_number(record, DE_UINT, DE_SIZE_16, SDP_ServiceClassIDList); de_add_number(record, DE_UUID, DE_SIZE_16, 0x0001); de_add_number(record, DE_UINT, DE_SIZE_16, SDP_BrowseGroupList); de_add_number(record, DE_UUID, DE_SIZE_16, 0x0001); uint32_t handle_1 = sdp_register_service_internal(NULL, record); de_dump_data_element(record); de_create_sequence(record); de_add_number(record, DE_UINT, DE_SIZE_16, SDP_ServiceRecordHandle); de_add_number(record, DE_UINT, DE_SIZE_32, 0x10002); de_add_number(record, DE_UINT, DE_SIZE_16, SDP_ServiceClassIDList); de_add_number(record, DE_UUID, DE_SIZE_16, 0x0002); de_add_number(record, DE_UINT, DE_SIZE_16, SDP_BrowseGroupList); de_add_number(record, DE_UUID, DE_SIZE_16, 0x0001); sdp_register_service_internal(NULL, record); de_dump_data_element(record); uint16_t size = spd_get_filtered_size(record, allAttributeIDs); printf("Attribute size %u\n", size); uint16_t transactionID = 1; uint8_t * attributeIDList; uint16_t attributeIDListLen; uint16_t response_pos; uint8_t * serviceSearchPattern; uint16_t serviceSearchPatternLen; #if 1 // sdp_handle_service_search_request uint16_t nr_services = 1; request[0] = SDP_ServiceSearchRequest; net_store_16(request, 1, transactionID++); // transaction ID serviceSearchPattern = &request[5]; de_create_sequence(serviceSearchPattern); { de_add_number(serviceSearchPattern, DE_UUID, DE_SIZE_16, 0x0001); } serviceSearchPatternLen = de_get_len(serviceSearchPattern); net_store_16(request, 5 + serviceSearchPatternLen, 2); // max request[5 + serviceSearchPatternLen + 2] = 0; // cont sdp_handle_service_search_request(request, 16); dump_service_search_response(); memcpy(request + 5 + serviceSearchPatternLen + 2, sdp_response_buffer + 9 + nr_services*4, 3); sdp_handle_service_search_request(request, remote_mtu); dump_service_search_response(); #endif #if 1 // sdp_handle_service_attribute_request request[0] = SDP_ServiceAttributeRequest; net_store_16(request, 1, transactionID++); // transaction ID net_store_32(request, 5, handle_1); // record handle net_store_16(request, 9, 11); // max bytes attributeIDList = request + 11; de_create_sequence(attributeIDList); de_add_number(attributeIDList, DE_UINT, DE_SIZE_32, 0x0000ffff); attributeIDListLen = de_get_len(attributeIDList); request[11+attributeIDListLen] = 0; response_pos = 0; while(1) { sdp_handle_service_attribute_request(request, remote_mtu); uint16_t attributeListByteCount = READ_NET_16(sdp_response_buffer, 5); memcpy( &response[response_pos], &sdp_response_buffer[7], attributeListByteCount); response_pos += attributeListByteCount; printf("attributeListByteCount %u\n", attributeListByteCount); printf("Continuation %u\n", sdp_response_buffer[7+attributeListByteCount]); if (sdp_response_buffer[7+attributeListByteCount] == 0) break; printf("Continuation {%u}\n", READ_NET_16(sdp_response_buffer, 7+attributeListByteCount+1)); memcpy(request+11+attributeIDListLen, sdp_response_buffer+7+attributeListByteCount, 3); } de_dump_data_element(response); #endif #if 1 // sdp_handle_service_search_attribute_request request[0] = SDP_ServiceSearchAttributeRequest; net_store_16(request, 1, transactionID++); // transaction ID serviceSearchPattern = &request[5]; de_create_sequence(serviceSearchPattern); { de_add_number(serviceSearchPattern, DE_UUID, DE_SIZE_16, 0x0001); } serviceSearchPatternLen = de_get_len(serviceSearchPattern); net_store_16(request, 5 + serviceSearchPatternLen, 11); // MaximumAttributeByteCount: attributeIDList = request + 5 + serviceSearchPatternLen + 2; de_create_sequence(attributeIDList); de_add_number(attributeIDList, DE_UINT, DE_SIZE_32, 0x0000ffff); attributeIDListLen = de_get_len(attributeIDList); request[5 + serviceSearchPatternLen + 2 + attributeIDListLen] = 0; response_pos = 0; while (1) { sdp_handle_service_search_attribute_request(request, remote_mtu); uint16_t attributeListByteCount = READ_NET_16(sdp_response_buffer, 5); memcpy( &response[response_pos], &sdp_response_buffer[7], attributeListByteCount); response_pos += attributeListByteCount; printf("attributeListByteCount %u\n", attributeListByteCount); printf("Continuation %u\n", sdp_response_buffer[7+attributeListByteCount]); if (sdp_response_buffer[7+attributeListByteCount] == 0) break; printf("Continuation {%u,%u}\n", READ_NET_16(sdp_response_buffer, 7+attributeListByteCount+1), READ_NET_16(sdp_response_buffer, 7+attributeListByteCount+3)); memcpy(request+5 + serviceSearchPatternLen + 2 + attributeIDListLen, sdp_response_buffer+7+attributeListByteCount, 5); } de_dump_data_element(response); #endif exit(0); }
// main int main(void) { // stop watchdog timer WDTCTL = WDTPW + WDTHOLD; //Initialize clock and peripherals halBoardInit(); halBoardStartXT1(); halBoardSetSystemClock(SYSCLK_16MHZ); // init debug UART halUsbInit(); // init LEDs LED_PORT_OUT |= LED_1 | LED_2; LED_PORT_DIR |= LED_1 | LED_2; /// GET STARTED with BTstack /// btstack_memory_init(); run_loop_init(RUN_LOOP_EMBEDDED); // init HCI hci_transport_t * transport = hci_transport_h4_dma_instance(); bt_control_t * control = bt_control_cc256x_instance(); hci_uart_config_t * config = hci_uart_config_cc256x_instance(); remote_device_db_t * remote_db = (remote_device_db_t *) &remote_device_db_memory; hci_init(transport, config, control, remote_db); // use eHCILL bt_control_cc256x_enable_ehcill(1); // init L2CAP l2cap_init(); l2cap_register_packet_handler(packet_handler); // init RFCOMM rfcomm_init(); rfcomm_register_packet_handler(packet_handler); rfcomm_register_service_with_initial_credits_internal(NULL, rfcomm_channel_nr, 100, 1); // reserved channel, mtu=100, 1 credit // init SDP, create record for SPP and register with SDP sdp_init(); memset(spp_service_buffer, 0, sizeof(spp_service_buffer)); service_record_item_t * service_record_item = (service_record_item_t *) spp_service_buffer; sdp_create_spp_service( (uint8_t*) &service_record_item->service_record, 1, "SPP Counter"); printf("SDP service buffer size: %u\n\r", (uint16_t) (sizeof(service_record_item_t) + de_get_len((uint8_t*) &service_record_item->service_record))); sdp_register_service_internal(NULL, service_record_item); // set one-shot timer timer_source_t heartbeat; heartbeat.process = &heartbeat_handler; run_loop_set_timer(&heartbeat, HEARTBEAT_PERIOD_MS); run_loop_add_timer(&heartbeat); puts("SPP FlowControl Demo: simulates processing on received data...\n\r"); // ready - enable irq used in h4 task __enable_interrupt(); // turn on! hci_power_control(HCI_POWER_ON); // go! run_loop_execute(); // happy compiler! return 0; }
int btstack_main(int argc, const char * argv[]){ // init L2CAP l2cap_init(); l2cap_register_packet_handler(packet_handler); // init RFCOMM rfcomm_init(); rfcomm_register_packet_handler(packet_handler); rfcomm_register_service_with_initial_credits_internal(NULL, rfcomm_channel_nr, 0xffff, 1); // reserved channel, mtu limited by l2cap, 1 credit // init SDP, create record for SPP and register with SDP sdp_init(); memset(spp_service_buffer, 0, sizeof(spp_service_buffer)); service_record_item_t * service_record_item = (service_record_item_t *) spp_service_buffer; sdp_create_spp_service( (uint8_t*) &service_record_item->service_record, 1, "SPP Counter"); printf("SDP service buffer size: %u\n\r", (uint16_t) (sizeof(service_record_item_t) + de_get_len((uint8_t*) &service_record_item->service_record))); sdp_register_service_internal(NULL, service_record_item); // set one-shot timer heartbeat.process = &heartbeat_handler; run_loop_set_timer(&heartbeat, HEARTBEAT_PERIOD_MS); run_loop_add_timer(&heartbeat); puts("SPP FlowControl Demo: simulates processing on received data...\n\r"); gap_set_local_name("BTstack SPP Flow Control"); hci_discoverable_control(1); // turn on! hci_power_control(HCI_POWER_ON); return 0; }
static void BTAttached() { btstack_memory_init(); // init HCI hci_transport_t * transport = hci_transport_mchpusb_instance(bt_buf, bt_buf_size); bt_control_t * control = NULL; hci_uart_config_t * config = NULL; const remote_device_db_t * remote_db = &remote_device_db_memory; hci_init(transport, config, control, remote_db); // init L2CAP l2cap_init(); l2cap_register_packet_handler(PacketHandler); // init RFCOMM rfcomm_init(); rfcomm_register_packet_handler(PacketHandler); rfcomm_register_service_internal(NULL, rfcomm_channel_nr, 100); // reserved channel, mtu=100 // init SDP, create record for SPP and register with SDP sdp_init(); memset(spp_service_buffer, 0, sizeof (spp_service_buffer)); service_record_item_t * service_record_item = (service_record_item_t *) spp_service_buffer; sdp_create_spp_service((uint8_t*) & service_record_item->service_record, 1, "IOIO-App"); log_printf("SDP service buffer size: %u\n\r", (uint16_t) (sizeof (service_record_item_t) + de_get_len((uint8_t*) & service_record_item->service_record))); sdp_register_service_internal(NULL, service_record_item); hci_power_control(HCI_POWER_ON); client_callback = DummyCallback; }
static int btstack_command_handler(connection_t *connection, uint8_t *packet, uint16_t size){ bd_addr_t addr; uint16_t cid; uint16_t psm; uint16_t service_channel; uint16_t mtu; uint8_t reason; uint8_t rfcomm_channel; uint8_t rfcomm_credits; uint32_t service_record_handle; client_state_t *client; uint16_t serviceSearchPatternLen; uint16_t attributeIDListLen; // BTstack internal commands - 16 Bit OpCode, 8 Bit ParamLen, Params... switch (READ_CMD_OCF(packet)){ case BTSTACK_GET_STATE: log_info("BTSTACK_GET_STATE"); hci_emit_state(); break; case BTSTACK_SET_POWER_MODE: log_info("BTSTACK_SET_POWER_MODE %u", packet[3]); // track client power requests client = client_for_connection(connection); if (!client) break; client->power_mode = packet[3]; // handle merged state if (!clients_require_power_on()){ start_power_off_timer(); } else if (!power_management_sleep) { stop_power_off_timer(); hci_power_control(HCI_POWER_ON); } break; case BTSTACK_GET_VERSION: log_info("BTSTACK_GET_VERSION"); hci_emit_btstack_version(); break; #ifdef USE_BLUETOOL case BTSTACK_SET_SYSTEM_BLUETOOTH_ENABLED: log_info("BTSTACK_SET_SYSTEM_BLUETOOTH_ENABLED %u", packet[3]); iphone_system_bt_set_enabled(packet[3]); hci_emit_system_bluetooth_enabled(iphone_system_bt_enabled()); break; case BTSTACK_GET_SYSTEM_BLUETOOTH_ENABLED: log_info("BTSTACK_GET_SYSTEM_BLUETOOTH_ENABLED"); hci_emit_system_bluetooth_enabled(iphone_system_bt_enabled()); break; #else case BTSTACK_SET_SYSTEM_BLUETOOTH_ENABLED: case BTSTACK_GET_SYSTEM_BLUETOOTH_ENABLED: hci_emit_system_bluetooth_enabled(0); break; #endif case BTSTACK_SET_DISCOVERABLE: log_info("BTSTACK_SET_DISCOVERABLE discoverable %u)", packet[3]); // track client discoverable requests client = client_for_connection(connection); if (!client) break; client->discoverable = packet[3]; // merge state hci_discoverable_control(clients_require_discoverable()); break; case BTSTACK_SET_BLUETOOTH_ENABLED: log_info("BTSTACK_SET_BLUETOOTH_ENABLED: %u\n", packet[3]); if (packet[3]) { // global enable global_enable = 1; hci_power_control(HCI_POWER_ON); } else { global_enable = 0; clients_clear_power_request(); hci_power_control(HCI_POWER_OFF); } break; case L2CAP_CREATE_CHANNEL_MTU: bt_flip_addr(addr, &packet[3]); psm = READ_BT_16(packet, 9); mtu = READ_BT_16(packet, 11); l2cap_create_channel_internal( connection, NULL, addr, psm, mtu); break; case L2CAP_CREATE_CHANNEL: bt_flip_addr(addr, &packet[3]); psm = READ_BT_16(packet, 9); l2cap_create_channel_internal( connection, NULL, addr, psm, 150); // until r865 break; case L2CAP_DISCONNECT: cid = READ_BT_16(packet, 3); reason = packet[5]; l2cap_disconnect_internal(cid, reason); break; case L2CAP_REGISTER_SERVICE: psm = READ_BT_16(packet, 3); mtu = READ_BT_16(packet, 5); l2cap_register_service_internal(connection, NULL, psm, mtu); break; case L2CAP_UNREGISTER_SERVICE: psm = READ_BT_16(packet, 3); l2cap_unregister_service_internal(connection, psm); break; case L2CAP_ACCEPT_CONNECTION: cid = READ_BT_16(packet, 3); l2cap_accept_connection_internal(cid); break; case L2CAP_DECLINE_CONNECTION: cid = READ_BT_16(packet, 3); reason = packet[7]; l2cap_decline_connection_internal(cid, reason); break; case RFCOMM_CREATE_CHANNEL: bt_flip_addr(addr, &packet[3]); rfcomm_channel = packet[9]; rfcomm_create_channel_internal( connection, &addr, rfcomm_channel ); break; case RFCOMM_CREATE_CHANNEL_WITH_CREDITS: bt_flip_addr(addr, &packet[3]); rfcomm_channel = packet[9]; rfcomm_credits = packet[10]; rfcomm_create_channel_with_initial_credits_internal( connection, &addr, rfcomm_channel, rfcomm_credits ); break; case RFCOMM_DISCONNECT: cid = READ_BT_16(packet, 3); reason = packet[5]; rfcomm_disconnect_internal(cid); break; case RFCOMM_REGISTER_SERVICE: rfcomm_channel = packet[3]; mtu = READ_BT_16(packet, 4); rfcomm_register_service_internal(connection, rfcomm_channel, mtu); break; case RFCOMM_REGISTER_SERVICE_WITH_CREDITS: rfcomm_channel = packet[3]; mtu = READ_BT_16(packet, 4); rfcomm_credits = packet[6]; rfcomm_register_service_with_initial_credits_internal(connection, rfcomm_channel, mtu, rfcomm_credits); break; case RFCOMM_UNREGISTER_SERVICE: service_channel = READ_BT_16(packet, 3); rfcomm_unregister_service_internal(service_channel); break; case RFCOMM_ACCEPT_CONNECTION: cid = READ_BT_16(packet, 3); rfcomm_accept_connection_internal(cid); break; case RFCOMM_DECLINE_CONNECTION: cid = READ_BT_16(packet, 3); reason = packet[7]; rfcomm_decline_connection_internal(cid); break; case RFCOMM_GRANT_CREDITS: cid = READ_BT_16(packet, 3); rfcomm_credits = packet[5]; rfcomm_grant_credits(cid, rfcomm_credits); break; case RFCOMM_PERSISTENT_CHANNEL: { if (remote_device_db) { // enforce \0 packet[3+248] = 0; rfcomm_channel = remote_device_db->persistent_rfcomm_channel((char*)&packet[3]); } else { // NOTE: hack for non-iOS platforms rfcomm_channel = rfcomm_channel_generator++; } log_info("RFCOMM_EVENT_PERSISTENT_CHANNEL %u", rfcomm_channel); uint8_t event[4]; event[0] = RFCOMM_EVENT_PERSISTENT_CHANNEL; event[1] = sizeof(event) - 2; event[2] = 0; event[3] = rfcomm_channel; hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event)); socket_connection_send_packet(connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event)); break; } case SDP_REGISTER_SERVICE_RECORD: log_info("SDP_REGISTER_SERVICE_RECORD size %u\n", size); sdp_register_service_internal(connection, &packet[3]); break; case SDP_UNREGISTER_SERVICE_RECORD: service_record_handle = READ_BT_32(packet, 3); log_info("SDP_UNREGISTER_SERVICE_RECORD handle 0x%x ", service_record_handle); sdp_unregister_service_internal(connection, service_record_handle); break; case SDP_CLIENT_QUERY_RFCOMM_SERVICES: bt_flip_addr(addr, &packet[3]); serviceSearchPatternLen = de_get_len(&packet[9]); memcpy(serviceSearchPattern, &packet[9], serviceSearchPatternLen); sdp_query_rfcomm_register_callback(handle_sdp_rfcomm_service_result, connection); 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_parser_register_callback(handle_sdp_client_query_result); serviceSearchPatternLen = de_get_len(&packet[9]); memcpy(serviceSearchPattern, &packet[9], serviceSearchPatternLen); attributeIDListLen = de_get_len(&packet[9+serviceSearchPatternLen]); memcpy(attributeIDList, &packet[9+serviceSearchPatternLen], attributeIDListLen); sdp_client_query(addr, (uint8_t*)&serviceSearchPattern[0], (uint8_t*)&attributeIDList[0]); // sdp_general_query_for_uuid(addr, 0x1002); break; default: log_error("Error: command %u not implemented\n:", READ_CMD_OCF(packet)); break; } // verbose log info on command before dumped command unknown to PacketLogger or Wireshark hci_dump_packet( HCI_COMMAND_DATA_PACKET, 1, packet, size); return 0; }
int btstack_main(int argc, const char * argv[]){ // init L2CAP l2cap_init(); l2cap_register_packet_handler(packet_handler); // init RFCOMM rfcomm_init(); rfcomm_register_packet_handler(packet_handler); rfcomm_register_service_internal(NULL, rfcomm_channel_nr, 100); // reserved channel, mtu=100 // init SDP, create record for SPP and register with SDP sdp_init(); memset(spp_service_buffer, 0, sizeof(spp_service_buffer)); service_record_item_t * service_record_item = (service_record_item_t *) spp_service_buffer; sdp_create_spp_service( (uint8_t*) &service_record_item->service_record, 1, "SPP Counter"); printf("SDP service buffer size: %u\n\r", (uint16_t) (sizeof(service_record_item_t) + de_get_len((uint8_t*) &service_record_item->service_record))); sdp_register_service_internal(NULL, service_record_item); // set one-shot timer timer_source_t heartbeat; heartbeat.process = &heartbeat_handler; run_loop_set_timer(&heartbeat, HEARTBEAT_PERIOD_MS); run_loop_add_timer(&heartbeat); printf("Run...\n\r"); // turn on! hci_power_control(HCI_POWER_ON); // default to discoverable hci_discoverable_control(1); // go! run_loop_execute(); // happy compiler! return 0; }