1 /* 2 * Copyright (C) 2017 BlueKitchen GmbH 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the copyright holders nor the names of 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 4. Any redistribution, use, or modification is done solely for 17 * personal benefit and not for any commercial purpose or for 18 * monetary gain. 19 * 20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24 * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * Please inquire about commercial licensing options at 34 * [email protected] 35 * 36 */ 37 38 #define __BTSTACK_FILE__ "hid_host_demo.c" 39 40 /* 41 * hid_host_demo.c 42 */ 43 44 /* EXAMPLE_START(hid_host_demo): HID Host Demo 45 * 46 * @text This example implements an HID Host. 47 */ 48 49 #include <stdio.h> 50 51 #include "btstack_config.h" 52 #include "btstack.h" 53 54 #define MAX_ATTRIBUTE_VALUE_SIZE 200 55 56 static uint8_t hid_descriptor[MAX_ATTRIBUTE_VALUE_SIZE]; 57 static uint16_t hid_descriptor_len; 58 59 static uint16_t hid_control_psm; 60 static uint16_t hid_interrupt_psm; 61 62 63 static uint8_t attribute_value[MAX_ATTRIBUTE_VALUE_SIZE]; 64 static const unsigned int attribute_value_buffer_size = MAX_ATTRIBUTE_VALUE_SIZE; 65 66 // MBP 2016 67 static const char * remote_addr_string = "F4-0F-24-3B-1B-E1"; 68 // iMpulse static const char * remote_addr_string = "64:6E:6C:C1:AA:B5"; 69 70 static bd_addr_t remote_addr; 71 72 static btstack_packet_callback_registration_t hci_event_callback_registration; 73 74 75 /* @section Main application configuration 76 * 77 * @text In the application configuration, L2CAP is initialized 78 */ 79 80 /* LISTING_START(PanuSetup): Panu setup */ 81 static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 82 static void handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 83 84 static void hid_host_setup(void){ 85 86 // register for HCI events 87 hci_event_callback_registration.callback = &packet_handler; 88 hci_add_event_handler(&hci_event_callback_registration); 89 90 // Initialize L2CAP 91 l2cap_init(); 92 } 93 /* LISTING_END */ 94 95 /* @section SDP parser callback 96 * 97 * @text The SDP parsers retrieves the BNEP PAN UUID as explained in 98 * Section [on SDP BNEP Query example](#sec:sdpbnepqueryExample}. 99 */ 100 101 static void handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) { 102 103 UNUSED(packet_type); 104 UNUSED(channel); 105 UNUSED(size); 106 107 des_iterator_t attribute_list_it; 108 des_iterator_t additional_des_it; 109 des_iterator_t prot_it; 110 uint8_t *des_element; 111 uint8_t *element; 112 uint32_t uuid; 113 114 switch (hci_event_packet_get_type(packet)){ 115 case SDP_EVENT_QUERY_ATTRIBUTE_VALUE: 116 if (sdp_event_query_attribute_byte_get_attribute_length(packet) <= attribute_value_buffer_size) { 117 attribute_value[sdp_event_query_attribute_byte_get_data_offset(packet)] = sdp_event_query_attribute_byte_get_data(packet); 118 if ((uint16_t)(sdp_event_query_attribute_byte_get_data_offset(packet)+1) == sdp_event_query_attribute_byte_get_attribute_length(packet)) { 119 switch(sdp_event_query_attribute_byte_get_attribute_id(packet)) { 120 case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST: 121 for (des_iterator_init(&attribute_list_it, attribute_value); des_iterator_has_more(&attribute_list_it); des_iterator_next(&attribute_list_it)) { 122 if (des_iterator_get_type(&attribute_list_it) != DE_DES) continue; 123 des_element = des_iterator_get_element(&attribute_list_it); 124 des_iterator_init(&prot_it, des_element); 125 element = des_iterator_get_element(&prot_it); 126 if (de_get_element_type(element) != DE_UUID) continue; 127 uuid = de_get_uuid32(element); 128 switch (uuid){ 129 case BLUETOOTH_PROTOCOL_L2CAP: 130 if (!des_iterator_has_more(&prot_it)) continue; 131 des_iterator_next(&prot_it); 132 de_element_get_uint16(des_iterator_get_element(&prot_it), &hid_control_psm); 133 printf("HID Control PSM: 0x%004x\n", (int) hid_control_psm); 134 break; 135 default: 136 break; 137 } 138 } 139 break; 140 case BLUETOOTH_ATTRIBUTE_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS: 141 for (des_iterator_init(&attribute_list_it, attribute_value); des_iterator_has_more(&attribute_list_it); des_iterator_next(&attribute_list_it)) { 142 if (des_iterator_get_type(&attribute_list_it) != DE_DES) continue; 143 des_element = des_iterator_get_element(&attribute_list_it); 144 for (des_iterator_init(&additional_des_it, des_element); des_iterator_has_more(&additional_des_it); des_iterator_next(&additional_des_it)) { 145 if (des_iterator_get_type(&additional_des_it) != DE_DES) continue; 146 des_element = des_iterator_get_element(&additional_des_it); 147 des_iterator_init(&prot_it, des_element); 148 element = des_iterator_get_element(&prot_it); 149 if (de_get_element_type(element) != DE_UUID) continue; 150 uuid = de_get_uuid32(element); 151 switch (uuid){ 152 case BLUETOOTH_PROTOCOL_L2CAP: 153 if (!des_iterator_has_more(&prot_it)) continue; 154 des_iterator_next(&prot_it); 155 de_element_get_uint16(des_iterator_get_element(&prot_it), &hid_interrupt_psm); 156 printf("HID Interrupt PSM: 0x%004x\n", (int) hid_interrupt_psm); 157 break; 158 default: 159 break; 160 } 161 } 162 } 163 break; 164 case BLUETOOTH_ATTRIBUTE_HID_DESCRIPTOR_LIST: 165 hid_descriptor_len = sdp_event_query_attribute_byte_get_attribute_length(packet); 166 memcpy(hid_descriptor, attribute_value, hid_descriptor_len); 167 printf("HID Descriptor:\n"); 168 printf_hexdump(hid_descriptor, hid_descriptor_len); 169 break; 170 default: 171 break; 172 } 173 } 174 } else { 175 fprintf(stderr, "SDP attribute value buffer size exceeded: available %d, required %d\n", attribute_value_buffer_size, sdp_event_query_attribute_byte_get_attribute_length(packet)); 176 } 177 break; 178 179 case SDP_EVENT_QUERY_COMPLETE: 180 if (!hid_control_psm) { 181 printf("HID Control PSM missing\n"); 182 break; 183 } 184 if (!hid_interrupt_psm) { 185 printf("HID Interrupt PSM missing\n"); 186 break; 187 } 188 printf("Setup HID\n"); 189 break; 190 } 191 } 192 193 /* 194 * @section Packet Handler 195 * 196 * @text The packet handler responds to various HCI Events. 197 */ 198 199 /* LISTING_START(packetHandler): Packet Handler */ 200 static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) 201 { 202 /* LISTING_PAUSE */ 203 UNUSED(channel); 204 UNUSED(size); 205 206 uint8_t event; 207 bd_addr_t event_addr; 208 209 /* LISTING_RESUME */ 210 switch (packet_type) { 211 case HCI_EVENT_PACKET: 212 event = hci_event_packet_get_type(packet); 213 switch (event) { 214 /* @text When BTSTACK_EVENT_STATE with state HCI_STATE_WORKING 215 * is received and the example is started in client mode, the remote SDP HID query is started. 216 */ 217 case BTSTACK_EVENT_STATE: 218 if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING){ 219 printf("Start SDP HID query for remote HID Device.\n"); 220 sdp_client_query_uuid16(&handle_sdp_client_query_result, remote_addr, BLUETOOTH_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE_SERVICE); 221 } 222 break; 223 224 /* LISTING_PAUSE */ 225 case HCI_EVENT_PIN_CODE_REQUEST: 226 // inform about pin code request 227 printf("Pin code request - using '0000'\n"); 228 hci_event_pin_code_request_get_bd_addr(packet, event_addr); 229 gap_pin_code_response(event_addr, "0000"); 230 break; 231 232 case HCI_EVENT_USER_CONFIRMATION_REQUEST: 233 // inform about user confirmation request 234 printf("SSP User Confirmation Request with numeric value '%06u'\n", little_endian_read_32(packet, 8)); 235 printf("SSP User Confirmation Auto accept\n"); 236 break; 237 238 /* LISTING_RESUME */ 239 default: 240 break; 241 242 } 243 default: 244 break; 245 } 246 } 247 /* LISTING_END */ 248 249 int btstack_main(int argc, const char * argv[]); 250 int btstack_main(int argc, const char * argv[]){ 251 252 (void)argc; 253 (void)argv; 254 255 hid_host_setup(); 256 257 // parse human readable Bluetooth address 258 sscanf_bd_addr(remote_addr_string, remote_addr); 259 260 // Turn on the device 261 hci_power_control(HCI_POWER_ON); 262 return 0; 263 } 264 265 /* EXAMPLE_END */ 266 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*- */ 267 268