/* * Copyright (C) 2014 BlueKitchen GmbH * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * 4. Any redistribution, use, or modification is done solely for * personal benefit and not for any commercial purpose or for * monetary gain. * * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Please inquire about commercial licensing options at * contact@bluekitchen-gmbh.com * */ // ***************************************************************************** // // minimal setup for SDP client over USB or UART // // ***************************************************************************** #include "btstack-config.h" #include #include #include #include #include #include "hci_cmds.h" #include "run_loop.h" #include "hci.h" #include "gap.h" #include "btstack_memory.h" #include "hci_dump.h" #include "l2cap.h" #include "rfcomm.h" #include "sdp.h" #include "sdp_query_rfcomm.h" #include "sm.h" #include "stdin_support.h" static void show_usage(); // static bd_addr_t remote = {0x04,0x0C,0xCE,0xE4,0x85,0xD3}; // static bd_addr_t remote = {0x84, 0x38, 0x35, 0x65, 0xD1, 0x15}; static bd_addr_t remote = {0x00, 0x1b, 0xdc, 0x07, 0x32, 0xef}; static bd_addr_t remote_rfcomm = {0x00, 0x00, 0x91, 0xE0, 0xD4, 0xC7}; static uint8_t rfcomm_channel_nr = 1; static int gap_discoverable = 0; static int gap_connectable = 0; // static int gap_pagable = 0; static int gap_bondable = 0; static int gap_dedicated_bonding_mode = 0; static int gap_mitm_protection = 0; static uint8_t gap_auth_req = 0; static char * gap_io_capabilities; static int ui_passkey = 0; static int ui_digits_for_passkey = 0; static int ui_chars_for_pin = 0; static uint8_t ui_pin[17]; static int ui_pin_offset = 0; static uint16_t handle; static uint16_t local_cid; // SPP / RFCOMM #define RFCOMM_SERVER_CHANNEL 1 #define HEARTBEAT_PERIOD_MS 1000 static uint16_t rfcomm_channel_id; static uint32_t spp_service_buffer[150/4]; // implicit alignment to 4-byte memory address static uint32_t dummy_service_buffer[150/4]; // implicit alignment to 4-byte memory address static uint8_t dummy_uuid128[] = { 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1}; static uint16_t mtu; // GAP INQUIRY #define MAX_DEVICES 10 enum DEVICE_STATE { REMOTE_NAME_REQUEST, REMOTE_NAME_INQUIRED, REMOTE_NAME_FETCHED }; struct device { bd_addr_t address; uint16_t clockOffset; uint32_t classOfDevice; uint8_t pageScanRepetitionMode; uint8_t rssi; enum DEVICE_STATE state; }; #define INQUIRY_INTERVAL 5 struct device devices[MAX_DEVICES]; int deviceCount = 0; enum STATE {INIT, W4_INQUIRY_MODE_COMPLETE, ACTIVE} ; enum STATE state = INIT; static int getDeviceIndexForAddress( bd_addr_t addr){ int j; for (j=0; j< deviceCount; j++){ if (BD_ADDR_CMP(addr, devices[j].address) == 0){ return j; } } return -1; } static void start_scan(void){ printf("Starting inquiry scan..\n"); hci_send_cmd(&hci_inquiry, HCI_INQUIRY_LAP, INQUIRY_INTERVAL, 0); } static int has_more_remote_name_requests(void){ int i; for (i=0;i= 0) continue; // already in our list memcpy(devices[deviceCount].address, addr, 6); devices[deviceCount].pageScanRepetitionMode = packet[offset]; offset += 1; if (event == HCI_EVENT_INQUIRY_RESULT){ offset += 2; // Reserved + Reserved devices[deviceCount].classOfDevice = READ_BT_24(packet, offset); offset += 3; devices[deviceCount].clockOffset = READ_BT_16(packet, offset) & 0x7fff; offset += 2; devices[deviceCount].rssi = 0; } else { offset += 1; // Reserved devices[deviceCount].classOfDevice = READ_BT_24(packet, offset); offset += 3; devices[deviceCount].clockOffset = READ_BT_16(packet, offset) & 0x7fff; offset += 2; devices[deviceCount].rssi = packet[offset]; offset += 1; } devices[deviceCount].state = REMOTE_NAME_REQUEST; printf("Device found: %s with COD: 0x%06x, pageScan %d, clock offset 0x%04x, rssi 0x%02x\n", bd_addr_to_str(addr), devices[deviceCount].classOfDevice, devices[deviceCount].pageScanRepetitionMode, devices[deviceCount].clockOffset, devices[deviceCount].rssi); deviceCount++; } break; } case HCI_EVENT_INQUIRY_COMPLETE: for (i=0;i= 0) { if (packet[2] == 0) { printf("Name: '%s'\n", &packet[9]); devices[index].state = REMOTE_NAME_FETCHED; } else { printf("Failed to get name: page timeout\n"); } } continue_remote_names(); break; default: break; } } // GAP INQUIRY END static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ uint16_t psm; uint32_t passkey; if (packet_type == UCD_DATA_PACKET){ printf("UCD Data for PSM %04x received, size %u\n", READ_BT_16(packet, 0), size - 2); } if (packet_type != HCI_EVENT_PACKET) return; switch (packet[0]) { case HCI_EVENT_INQUIRY_RESULT: case HCI_EVENT_INQUIRY_RESULT_WITH_RSSI: case HCI_EVENT_INQUIRY_COMPLETE: case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE: inquiry_packet_handler(packet_type, packet, size); break; case BTSTACK_EVENT_STATE: // bt stack activated, get started if (packet[2] == HCI_STATE_WORKING){ printf("BTstack Bluetooth Classic Test Ready\n"); hci_send_cmd(&hci_write_inquiry_mode, 0x01); // with RSSI show_usage(); } break; case GAP_DEDICATED_BONDING_COMPLETED: printf("GAP Dedicated Bonding Complete, status %u\n", packet[2]); break; case HCI_EVENT_CONNECTION_COMPLETE: if (!packet[2]){ handle = READ_BT_16(packet, 3); bt_flip_addr(remote, &packet[5]); printf("HCI_EVENT_CONNECTION_COMPLETE: handle 0x%04x\n", handle); } break; case HCI_EVENT_USER_PASSKEY_REQUEST: bt_flip_addr(remote, &packet[2]); printf("GAP User Passkey Request for %s\nPasskey:", bd_addr_to_str(remote)); fflush(stdout); ui_digits_for_passkey = 6; break; case HCI_EVENT_USER_CONFIRMATION_REQUEST: bt_flip_addr(remote, &packet[2]); passkey = READ_BT_32(packet, 8); printf("GAP User Confirmation Request for %s, number '%06u'\n", bd_addr_to_str(remote),passkey); break; case HCI_EVENT_PIN_CODE_REQUEST: bt_flip_addr(remote, &packet[2]); printf("GAP Legacy PIN Request for %s (press ENTER to send)\nPasskey:", bd_addr_to_str(remote)); fflush(stdout); ui_chars_for_pin = 1; break; case L2CAP_EVENT_CHANNEL_OPENED: // inform about new l2cap connection bt_flip_addr(remote, &packet[3]); psm = READ_BT_16(packet, 11); local_cid = READ_BT_16(packet, 13); handle = READ_BT_16(packet, 9); if (packet[2] == 0) { printf("L2CAP Channel successfully opened: %s, handle 0x%02x, psm 0x%02x, local cid 0x%02x, remote cid 0x%02x\n", bd_addr_to_str(remote), handle, psm, local_cid, READ_BT_16(packet, 15)); } else { printf("L2CAP connection to device %s failed. status code %u\n", bd_addr_to_str(remote), packet[2]); } break; case L2CAP_EVENT_INCOMING_CONNECTION: { // data: event (8), len(8), address(48), handle (16), psm (16), local_cid(16), remote_cid (16) psm = READ_BT_16(packet, 10); // uint16_t l2cap_cid = READ_BT_16(packet, 12); printf("L2CAP incoming connection request on PSM %u\n", psm); // l2cap_accept_connection_internal(l2cap_cid); break; } case RFCOMM_EVENT_INCOMING_CONNECTION: // data: event (8), len(8), address(48), channel (8), rfcomm_cid (16) bt_flip_addr(remote, &packet[2]); rfcomm_channel_nr = packet[8]; rfcomm_channel_id = READ_BT_16(packet, 9); printf("RFCOMM channel %u requested for %s\n\r", rfcomm_channel_nr, bd_addr_to_str(remote)); rfcomm_accept_connection_internal(rfcomm_channel_id); break; case RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE: // data: event(8), len(8), status (8), address (48), server channel(8), rfcomm_cid(16), max frame size(16) if (packet[2]) { printf("RFCOMM channel open failed, status %u\n\r", packet[2]); } else { rfcomm_channel_id = READ_BT_16(packet, 12); mtu = READ_BT_16(packet, 14); if (mtu > 60){ printf("BTstack libusb hack: using reduced MTU for sending instead of %u\n", mtu); mtu = 60; } printf("\n\rRFCOMM channel open succeeded. New RFCOMM Channel ID %u, max frame size %u\n\r", rfcomm_channel_id, mtu); } break; case RFCOMM_EVENT_CHANNEL_CLOSED: rfcomm_channel_id = 0; break; default: break; } } static void packet_handler2 (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ packet_handler(packet_type, 0, packet, size); } static void update_auth_req(void){ gap_set_bondable_mode(gap_bondable); gap_auth_req = 0; if (gap_mitm_protection){ gap_auth_req |= 1; // MITM Flag } if (gap_dedicated_bonding_mode){ gap_auth_req |= 2; // Dedicated bonding } else if (gap_bondable){ gap_auth_req |= 4; // General bonding } printf("Authentication Requirements: %u\n", gap_auth_req); hci_ssp_set_authentication_requirement(gap_auth_req); } static void handle_found_service(char * name, uint8_t port){ printf("SDP: Service name: '%s', RFCOMM port %u\n", name, port); rfcomm_channel_nr = port; } static void handle_query_rfcomm_event(sdp_query_event_t * event, void * context){ sdp_query_rfcomm_service_event_t * ve; switch (event->type){ case SDP_QUERY_RFCOMM_SERVICE: ve = (sdp_query_rfcomm_service_event_t*) event; handle_found_service((char*) ve->service_name, ve->channel_nr); break; case SDP_QUERY_COMPLETE: printf("SDP SPP Query complete\n"); break; default: break; } } static void send_ucd_packet(void){ l2cap_reserve_packet_buffer(); int ucd_size = 50; uint8_t * ucd_buffer = l2cap_get_outgoing_buffer(); bt_store_16(ucd_buffer, 0, 0x2211); int i; for (i=2; i< ucd_size ; i++){ ucd_buffer[i] = i; } l2cap_send_prepared_connectionless(handle, L2CAP_CID_CONNECTIONLESS_CHANNEL, ucd_size); } static void show_usage(void){ printf("\n--- Bluetooth Classic Test Console ---\n"); printf("GAP: discoverable %u, connectable %u, bondable %u, MITM %u, dedicated bonding %u, auth_req 0x0%u, %s\n", gap_discoverable, gap_connectable, gap_bondable, gap_mitm_protection, gap_dedicated_bonding_mode, gap_auth_req, gap_io_capabilities); printf("---\n"); printf("b/B - bondable off/on\n"); printf("c/C - connectable off/on\n"); printf("d/D - discoverable off/on\n"); printf(" - dedicated bonding off/on\n"); printf("m/M - MITM protection off/on\n"); // printf("a/A - pageable off/on\n"); printf("---\n"); printf("e - IO_CAPABILITY_DISPLAY_ONLY\n"); printf("f - IO_CAPABILITY_DISPLAY_YES_NO\n"); printf("g - IO_CAPABILITY_NO_INPUT_NO_OUTPUT\n"); printf("h - IO_CAPABILITY_KEYBOARD_ONLY\n"); printf("---\n"); printf("i - perform inquiry and remote name request\n"); printf("j - perform dedicated bonding to %s, MITM = %u\n", bd_addr_to_str(remote), gap_mitm_protection); printf("z - perform dedicated bonding to %s using legacy pairing\n", bd_addr_to_str(remote)); printf("t - terminate HCI connection with handle 0x%04x\n", handle); printf("y - disable SSP\n"); printf("---\n"); printf("k - query %s for RFCOMM channel\n", bd_addr_to_str(remote_rfcomm)); printf("l - create RFCOMM connection to %s using channel #%u\n", bd_addr_to_str(remote_rfcomm), rfcomm_channel_nr); printf("n - send RFCOMM data\n"); printf("u - send RFCOMM Remote Line Status Indication indicating Framing Error\n"); printf("v - send RFCOMM Remote Port Negotiation to select 115200 baud\n"); printf("w - query RFCOMM Remote Port Negotiation\n"); printf("o - close RFCOMM connection\n"); printf("---\n"); // printf("p - create L2CAP channel to SDP at addr %s\n", bd_addr_to_str(remote)); printf("p - create HCI connection to addr %s\n", bd_addr_to_str(remote)); printf("Q - close HCI connection\n"); printf("q - send L2CAP data\n"); printf("r - send L2CAP ECHO request\n"); printf("U - send UCD data\n"); printf("s - close L2CAP channel\n"); printf("x - require SSP for outgoing SDP L2CAP channel\n"); printf("+ - initate SSP on current connection\n"); printf("* - send SSP User Confirm YES\n"); printf("= - delete link key\n"); printf("---\n"); printf("Ctrl-c - exit\n"); printf("---\n"); } static int stdin_process(struct data_source *ds){ char buffer; read(ds->fd, &buffer, 1); // passkey input if (ui_digits_for_passkey){ if (buffer < '0' || buffer > '9') return 0; printf("%c", buffer); fflush(stdout); ui_passkey = ui_passkey * 10 + buffer - '0'; ui_digits_for_passkey--; if (ui_digits_for_passkey == 0){ printf("\nSending Passkey '%06u'\n", ui_passkey); hci_send_cmd(&hci_user_passkey_request_reply, remote, ui_passkey); } return 0; } if (ui_chars_for_pin){ printf("%c", buffer); fflush(stdout); if (buffer == '\n'){ printf("\nSending Pin '%s'\n", ui_pin); hci_send_cmd(&hci_pin_code_request_reply, remote, ui_pin_offset, ui_pin); } else { ui_pin[ui_pin_offset++] = buffer; } return 0; } switch (buffer){ case 'c': gap_connectable = 0; hci_connectable_control(0); show_usage(); break; case 'C': gap_connectable = 1; hci_connectable_control(1); show_usage(); break; case 'd': gap_discoverable = 0; hci_discoverable_control(0); show_usage(); break; case 'D': gap_discoverable = 1; hci_discoverable_control(1); show_usage(); break; case 'b': gap_bondable = 0; update_auth_req(); show_usage(); break; case 'B': gap_bondable = 1; update_auth_req(); show_usage(); break; case 'm': gap_mitm_protection = 0; update_auth_req(); show_usage(); break; case 'M': gap_mitm_protection = 1; update_auth_req(); show_usage(); break; case '<': gap_dedicated_bonding_mode = 0; update_auth_req(); show_usage(); break; case '>': gap_dedicated_bonding_mode = 1; update_auth_req(); show_usage(); break; case 'e': gap_io_capabilities = "IO_CAPABILITY_DISPLAY_ONLY"; hci_ssp_set_io_capability(IO_CAPABILITY_DISPLAY_ONLY); show_usage(); break; case 'f': gap_io_capabilities = "IO_CAPABILITY_DISPLAY_YES_NO"; hci_ssp_set_io_capability(IO_CAPABILITY_DISPLAY_YES_NO); show_usage(); break; case 'g': gap_io_capabilities = "IO_CAPABILITY_NO_INPUT_NO_OUTPUT"; hci_ssp_set_io_capability(IO_CAPABILITY_NO_INPUT_NO_OUTPUT); show_usage(); break; case 'h': gap_io_capabilities = "IO_CAPABILITY_KEYBOARD_ONLY"; hci_ssp_set_io_capability(IO_CAPABILITY_KEYBOARD_ONLY); show_usage(); break; case 'i': start_scan(); break; case 'j': printf("Start dedicated bonding to %s using MITM %u\n", bd_addr_to_str(remote), gap_mitm_protection); gap_dedicated_bonding(remote, gap_mitm_protection); break; case 'z': printf("Start dedicated bonding to %s using legacy pairing\n", bd_addr_to_str(remote)); gap_dedicated_bonding(remote, gap_mitm_protection); break; case 'y': printf("Disabling SSP for this session\n"); hci_send_cmd(&hci_write_simple_pairing_mode, 0); break; case 'k': printf("Start SDP query for SPP service\n"); sdp_query_rfcomm_channel_and_name_for_uuid(remote_rfcomm, 0x1101); break; case 't': printf("Terminate connection with handle 0x%04x\n", handle); hci_send_cmd(&hci_disconnect, handle, 0x13); // remote closed connection break; case 'p': printf("Creating HCI Connection to %s\n", bd_addr_to_str(remote)); hci_send_cmd(&hci_create_connection, remote, hci_usable_acl_packet_types(), 0, 0, 0, 1); break; // printf("Creating L2CAP Connection to %s, PSM SDP\n", bd_addr_to_str(remote)); // l2cap_create_channel_internal(NULL, packet_handler, remote, PSM_SDP, 100); // break; // case 'u': // printf("Creating L2CAP Connection to %s, PSM 3\n", bd_addr_to_str(remote)); // l2cap_create_channel_internal(NULL, packet_handler, remote, 3, 100); // break; case 'q': printf("Send L2CAP Data\n"); l2cap_send_internal(local_cid, (uint8_t *) "0123456789", 10); break; case 'r': printf("Send L2CAP ECHO Request\n"); l2cap_send_echo_request(handle, (uint8_t *) "Hello World!", 13); break; case 's': printf("L2CAP Channel Closed\n"); l2cap_disconnect_internal(local_cid, 0); break; case 'x': printf("Outgoing L2CAP Channels to SDP will also require SSP\n"); l2cap_require_security_level_2_for_outgoing_sdp(); break; case 'l': printf("Creating RFCOMM Channel to %s #%u\n", bd_addr_to_str(remote_rfcomm), rfcomm_channel_nr); rfcomm_create_channel_internal(NULL, remote_rfcomm, rfcomm_channel_nr); break; case 'n': printf("Send RFCOMM Data\n"); // mtu < 60 rfcomm_send_internal(rfcomm_channel_id, (uint8_t *) "012345678901234567890123456789012345678901234567890123456789", mtu); break; case 'u': printf("Sending RLS indicating framing error\n"); // mtu < 60 rfcomm_send_local_line_status(rfcomm_channel_id, 9); break; case 'v': printf("Sending RPN CMD to select 115200 baud\n"); // mtu < 60 rfcomm_send_port_configuration(rfcomm_channel_id, RPN_BAUD_115200, RPN_DATA_BITS_8, RPN_STOP_BITS_1_0, RPN_PARITY_NONE, 0); break; case 'w': printf("Sending RPN REQ to query remote port settings\n"); // mtu < 60 rfcomm_query_port_configuration(rfcomm_channel_id); break; case 'o': printf("RFCOMM Channel Closed\n"); rfcomm_disconnect_internal(rfcomm_channel_id); rfcomm_channel_id = 0; break; case '+': printf("Initiate SSP on current connection\n"); gap_request_security_level(handle, LEVEL_2); break; case '*': printf("Sending SSP User Confirmation for %s\n", bd_addr_to_str(remote)); hci_send_cmd(&hci_user_confirmation_request_reply, remote); break; case '=': printf("Deleting Link Key for %s\n", bd_addr_to_str(remote)); hci_drop_link_key_for_bd_addr(remote); break; case 'U': printf("Sending UCD data on handle 0x%04x\n", handle); send_ucd_packet(); break; case 'Q': printf("Closing HCI Connection to handle 0x%04x\n", handle); gap_disconnect(handle); break; default: show_usage(); break; } return 0; } static void sdp_create_dummy_service(uint8_t *service, const char *name){ uint8_t* attribute; de_create_sequence(service); // 0x0000 "Service Record Handle" de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ServiceRecordHandle); de_add_number(service, DE_UINT, DE_SIZE_32, 0x10002); // 0x0001 "Service Class ID List" de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ServiceClassIDList); attribute = de_push_sequence(service); { de_add_uuid128(attribute, &dummy_uuid128[0] ); } de_pop_sequence(service, attribute); // 0x0004 "Protocol Descriptor List" de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ProtocolDescriptorList); attribute = de_push_sequence(service); { uint8_t* l2cpProtocol = de_push_sequence(attribute); { de_add_number(l2cpProtocol, DE_UUID, DE_SIZE_16, 0x0100); } de_pop_sequence(attribute, l2cpProtocol); } de_pop_sequence(service, attribute); // 0x0005 "Public Browse Group" de_add_number(service, DE_UINT, DE_SIZE_16, SDP_BrowseGroupList); // public browse group attribute = de_push_sequence(service); { de_add_number(attribute, DE_UUID, DE_SIZE_16, SDP_PublicBrowseGroup); } de_pop_sequence(service, attribute); // 0x0006 de_add_number(service, DE_UINT, DE_SIZE_16, SDP_LanguageBaseAttributeIDList); attribute = de_push_sequence(service); { de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x656e); de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x006a); de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x0100); } de_pop_sequence(service, attribute); // 0x0009 "Bluetooth Profile Descriptor List" de_add_number(service, DE_UINT, DE_SIZE_16, SDP_BluetoothProfileDescriptorList); attribute = de_push_sequence(service); { uint8_t *sppProfile = de_push_sequence(attribute); { de_add_number(sppProfile, DE_UINT, DE_SIZE_16, 0x0100); } de_pop_sequence(attribute, sppProfile); } de_pop_sequence(service, attribute); // 0x0100 "ServiceName" de_add_number(service, DE_UINT, DE_SIZE_16, 0x0100); de_add_data(service, DE_STRING, strlen(name), (uint8_t *) name); } int btstack_main(int argc, const char * argv[]); int btstack_main(int argc, const char * argv[]){ printf("Starting up..\n"); hci_set_class_of_device(0x220404); 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); update_auth_req(); 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); return 0; } // Notes: // UCD Test 1: C // UCD Test 2: p, U, Q // UCD Test 3: =, p, +, *, U, Q