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