xref: /btstack/src/classic/hid_device.c (revision 57c643ee41a2c2258ebe43ed0f6f9da434da9f2a)
1d40c9ac6SMatthias Ringwald /*
2d40c9ac6SMatthias Ringwald  * Copyright (C) 2014 BlueKitchen GmbH
3d40c9ac6SMatthias Ringwald  *
4d40c9ac6SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5d40c9ac6SMatthias Ringwald  * modification, are permitted provided that the following conditions
6d40c9ac6SMatthias Ringwald  * are met:
7d40c9ac6SMatthias Ringwald  *
8d40c9ac6SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9d40c9ac6SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10d40c9ac6SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11d40c9ac6SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12d40c9ac6SMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13d40c9ac6SMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14d40c9ac6SMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15d40c9ac6SMatthias Ringwald  *    from this software without specific prior written permission.
16d40c9ac6SMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17d40c9ac6SMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18d40c9ac6SMatthias Ringwald  *    monetary gain.
19d40c9ac6SMatthias Ringwald  *
20d40c9ac6SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21d40c9ac6SMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22d40c9ac6SMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23d40c9ac6SMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24d40c9ac6SMatthias Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25d40c9ac6SMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26d40c9ac6SMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27d40c9ac6SMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28d40c9ac6SMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29d40c9ac6SMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30d40c9ac6SMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31d40c9ac6SMatthias Ringwald  * SUCH DAMAGE.
32d40c9ac6SMatthias Ringwald  *
33d40c9ac6SMatthias Ringwald  * Please inquire about commercial licensing options at
34d40c9ac6SMatthias Ringwald  * [email protected]
35d40c9ac6SMatthias Ringwald  *
36d40c9ac6SMatthias Ringwald  */
37d40c9ac6SMatthias Ringwald 
38d40c9ac6SMatthias Ringwald #define __BTSTACK_FILE__ "hid_device.c"
39d40c9ac6SMatthias Ringwald 
40d40c9ac6SMatthias Ringwald #include <string.h>
41d40c9ac6SMatthias Ringwald 
42d40c9ac6SMatthias Ringwald #include "classic/hid_device.h"
43d40c9ac6SMatthias Ringwald #include "classic/sdp_util.h"
44d40c9ac6SMatthias Ringwald #include "bluetooth.h"
45d40c9ac6SMatthias Ringwald #include "bluetooth_sdp.h"
468eb8d463SMatthias Ringwald #include "l2cap.h"
478eb8d463SMatthias Ringwald #include "btstack_event.h"
488eb8d463SMatthias Ringwald #include "btstack_debug.h"
498eb8d463SMatthias Ringwald 
508eb8d463SMatthias Ringwald // hid device state
518eb8d463SMatthias Ringwald typedef struct hid_device {
528eb8d463SMatthias Ringwald     uint16_t  cid;
538eb8d463SMatthias Ringwald     bd_addr_t bd_addr;
548eb8d463SMatthias Ringwald     hci_con_handle_t con_handle;
558eb8d463SMatthias Ringwald     uint16_t  control_cid;
568eb8d463SMatthias Ringwald     uint16_t  interrupt_cid;
578eb8d463SMatthias Ringwald     uint8_t   incoming;
58*57c643eeSMatthias Ringwald     uint8_t   connected;
598eb8d463SMatthias Ringwald } hid_device_t;
608eb8d463SMatthias Ringwald 
618eb8d463SMatthias Ringwald static hid_device_t _hid_device;
628eb8d463SMatthias Ringwald static hid_device_t * hid_device = &_hid_device;
638eb8d463SMatthias Ringwald 
648eb8d463SMatthias Ringwald static btstack_packet_handler_t hid_callback;
65d40c9ac6SMatthias Ringwald 
66d40c9ac6SMatthias Ringwald void hid_create_sdp_record(
67d40c9ac6SMatthias Ringwald     uint8_t *service,
68d40c9ac6SMatthias Ringwald     uint32_t service_record_handle,
69d40c9ac6SMatthias Ringwald     uint16_t hid_device_subclass,
70d40c9ac6SMatthias Ringwald     uint8_t  hid_country_code,
71d40c9ac6SMatthias Ringwald     uint8_t  hid_virtual_cable,
72d40c9ac6SMatthias Ringwald     uint8_t  hid_reconnect_initiate,
73d40c9ac6SMatthias Ringwald     uint8_t  hid_boot_device,
74d40c9ac6SMatthias Ringwald     const uint8_t * hid_descriptor, uint16_t hid_descriptor_size,
75d40c9ac6SMatthias Ringwald     const char *device_name){
76d40c9ac6SMatthias Ringwald 
77d40c9ac6SMatthias Ringwald     uint8_t * attribute;
78d40c9ac6SMatthias Ringwald     de_create_sequence(service);
79d40c9ac6SMatthias Ringwald 
80d40c9ac6SMatthias Ringwald     de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_RECORD_HANDLE);
81d40c9ac6SMatthias Ringwald     de_add_number(service, DE_UINT, DE_SIZE_32, service_record_handle);
82d40c9ac6SMatthias Ringwald 
83d40c9ac6SMatthias Ringwald     de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST);
84d40c9ac6SMatthias Ringwald     attribute = de_push_sequence(service);
85d40c9ac6SMatthias Ringwald     {
86d40c9ac6SMatthias Ringwald         de_add_number(attribute,  DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE_SERVICE);
87d40c9ac6SMatthias Ringwald     }
88d40c9ac6SMatthias Ringwald     de_pop_sequence(service, attribute);
89d40c9ac6SMatthias Ringwald 
90d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST);
91d40c9ac6SMatthias Ringwald     attribute = de_push_sequence(service);
92d40c9ac6SMatthias Ringwald     {
93d40c9ac6SMatthias Ringwald         uint8_t * l2cpProtocol = de_push_sequence(attribute);
94d40c9ac6SMatthias Ringwald         {
95d40c9ac6SMatthias Ringwald             de_add_number(l2cpProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_L2CAP);
96d40c9ac6SMatthias Ringwald             de_add_number(l2cpProtocol,  DE_UINT, DE_SIZE_16, PSM_HID_CONTROL);
97d40c9ac6SMatthias Ringwald         }
98d40c9ac6SMatthias Ringwald         de_pop_sequence(attribute, l2cpProtocol);
99d40c9ac6SMatthias Ringwald 
100d40c9ac6SMatthias Ringwald         uint8_t * hidProtocol = de_push_sequence(attribute);
101d40c9ac6SMatthias Ringwald         {
102d40c9ac6SMatthias Ringwald             de_add_number(hidProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_HIDP);
103d40c9ac6SMatthias Ringwald         }
104d40c9ac6SMatthias Ringwald         de_pop_sequence(attribute, hidProtocol);
105d40c9ac6SMatthias Ringwald     }
106d40c9ac6SMatthias Ringwald     de_pop_sequence(service, attribute);
107d40c9ac6SMatthias Ringwald 
108d40c9ac6SMatthias Ringwald     // TODO?
109d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
110d40c9ac6SMatthias Ringwald     attribute = de_push_sequence(service);
111d40c9ac6SMatthias Ringwald     {
112d40c9ac6SMatthias Ringwald         de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x656e);
113d40c9ac6SMatthias Ringwald         de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x006a);
114d40c9ac6SMatthias Ringwald         de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x0100);
115d40c9ac6SMatthias Ringwald     }
116d40c9ac6SMatthias Ringwald     de_pop_sequence(service, attribute);
117d40c9ac6SMatthias Ringwald 
118d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS);
119d40c9ac6SMatthias Ringwald     attribute = de_push_sequence(service);
120d40c9ac6SMatthias Ringwald     {
121d40c9ac6SMatthias Ringwald         uint8_t * additionalDescriptorAttribute = de_push_sequence(attribute);
122d40c9ac6SMatthias Ringwald         {
123d40c9ac6SMatthias Ringwald             uint8_t * l2cpProtocol = de_push_sequence(additionalDescriptorAttribute);
124d40c9ac6SMatthias Ringwald             {
125d40c9ac6SMatthias Ringwald                 de_add_number(l2cpProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_L2CAP);
126d40c9ac6SMatthias Ringwald                 de_add_number(l2cpProtocol,  DE_UINT, DE_SIZE_16, PSM_HID_INTERRUPT);
127d40c9ac6SMatthias Ringwald             }
128d40c9ac6SMatthias Ringwald             de_pop_sequence(additionalDescriptorAttribute, l2cpProtocol);
129d40c9ac6SMatthias Ringwald 
130d40c9ac6SMatthias Ringwald             uint8_t * hidProtocol = de_push_sequence(attribute);
131d40c9ac6SMatthias Ringwald             {
132d40c9ac6SMatthias Ringwald                 de_add_number(hidProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_HIDP);
133d40c9ac6SMatthias Ringwald             }
134d40c9ac6SMatthias Ringwald             de_pop_sequence(attribute, hidProtocol);
135d40c9ac6SMatthias Ringwald         }
136d40c9ac6SMatthias Ringwald         de_pop_sequence(attribute, additionalDescriptorAttribute);
137d40c9ac6SMatthias Ringwald     }
138d40c9ac6SMatthias Ringwald     de_pop_sequence(service, attribute);
139d40c9ac6SMatthias Ringwald 
140d40c9ac6SMatthias Ringwald     // 0x0100 "ServiceName"
141d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, 0x0100);
142d40c9ac6SMatthias Ringwald     de_add_data(service,  DE_STRING, strlen(device_name), (uint8_t *) device_name);
143d40c9ac6SMatthias Ringwald 
144d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
145d40c9ac6SMatthias Ringwald     attribute = de_push_sequence(service);
146d40c9ac6SMatthias Ringwald     {
147d40c9ac6SMatthias Ringwald         uint8_t * hidProfile = de_push_sequence(attribute);
148d40c9ac6SMatthias Ringwald         {
149d40c9ac6SMatthias Ringwald             de_add_number(hidProfile,  DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE_SERVICE);
150d40c9ac6SMatthias Ringwald             de_add_number(hidProfile,  DE_UINT, DE_SIZE_16, 0x0101);    // Version 1.1
151d40c9ac6SMatthias Ringwald         }
152d40c9ac6SMatthias Ringwald         de_pop_sequence(attribute, hidProfile);
153d40c9ac6SMatthias Ringwald     }
154d40c9ac6SMatthias Ringwald     de_pop_sequence(service, attribute);
155d40c9ac6SMatthias Ringwald 
156d40c9ac6SMatthias Ringwald     // Deprecated in v1.1.1
157d40c9ac6SMatthias Ringwald     // de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_DEVICE_RELEASE_NUMBER);
158d40c9ac6SMatthias Ringwald     // de_add_number(service,  DE_UINT, DE_SIZE_16, 0x0101);
159d40c9ac6SMatthias Ringwald 
160d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_PARSER_VERSION);
161d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, 0x0111);  // v1.1.1
162d40c9ac6SMatthias Ringwald 
163d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_DEVICE_SUBCLASS);
1649679ea81SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_8,  hid_device_subclass);
165d40c9ac6SMatthias Ringwald 
166d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_COUNTRY_CODE);
1679679ea81SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_8,  hid_country_code);
168d40c9ac6SMatthias Ringwald 
169d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_VIRTUAL_CABLE);
170d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_BOOL, DE_SIZE_8,  hid_virtual_cable);
171d40c9ac6SMatthias Ringwald 
172d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_RECONNECT_INITIATE);
173d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_BOOL, DE_SIZE_8,  hid_reconnect_initiate);
174d40c9ac6SMatthias Ringwald 
175d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_DESCRIPTOR_LIST);
176d40c9ac6SMatthias Ringwald     attribute = de_push_sequence(service);
177d40c9ac6SMatthias Ringwald     {
178d40c9ac6SMatthias Ringwald         uint8_t* hidDescriptor = de_push_sequence(attribute);
179d40c9ac6SMatthias Ringwald         {
180d40c9ac6SMatthias Ringwald             de_add_number(hidDescriptor,  DE_UINT, DE_SIZE_8, 0x22);    // Report Descriptor
181d40c9ac6SMatthias Ringwald             de_add_data(hidDescriptor,  DE_STRING, hid_descriptor_size, (uint8_t *) hid_descriptor);
182d40c9ac6SMatthias Ringwald         }
183d40c9ac6SMatthias Ringwald         de_pop_sequence(attribute, hidDescriptor);
184d40c9ac6SMatthias Ringwald     }
185d40c9ac6SMatthias Ringwald     de_pop_sequence(service, attribute);
186d40c9ac6SMatthias Ringwald 
1879679ea81SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HIDLANGID_BASE_LIST);
1889679ea81SMatthias Ringwald     attribute = de_push_sequence(service);
1899679ea81SMatthias Ringwald     {
1909679ea81SMatthias Ringwald         uint8_t* hig_lang_base = de_push_sequence(attribute);
1919679ea81SMatthias Ringwald         {
1929679ea81SMatthias Ringwald             // see: http://www.usb.org/developers/docs/USB_LANGIDs.pdf
1939679ea81SMatthias Ringwald             de_add_number(hig_lang_base,  DE_UINT, DE_SIZE_16, 0x0409);    // HIDLANGID = English (US)
1949679ea81SMatthias Ringwald             de_add_number(hig_lang_base,  DE_UINT, DE_SIZE_16, 0x0100);    // HIDLanguageBase = 0x0100 default
1959679ea81SMatthias Ringwald         }
1969679ea81SMatthias Ringwald         de_pop_sequence(attribute, hig_lang_base);
1979679ea81SMatthias Ringwald     }
1989679ea81SMatthias Ringwald     de_pop_sequence(service, attribute);
1999679ea81SMatthias Ringwald 
200d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_BOOT_DEVICE);
201d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_BOOL, DE_SIZE_8,  hid_boot_device);
202d40c9ac6SMatthias Ringwald }
2038eb8d463SMatthias Ringwald 
2048eb8d463SMatthias Ringwald static inline void hid_device_emit_connected_event(hid_device_t * context, uint8_t status){
2058eb8d463SMatthias Ringwald     uint8_t event[15];
2068eb8d463SMatthias Ringwald     int pos = 0;
2078eb8d463SMatthias Ringwald     event[pos++] = HCI_EVENT_HID_META;
2088eb8d463SMatthias Ringwald     pos++;  // skip len
2098eb8d463SMatthias Ringwald     event[pos++] = HID_SUBEVENT_CONNECTION_OPENED;
2108eb8d463SMatthias Ringwald     little_endian_store_16(event,pos,context->cid);
2118eb8d463SMatthias Ringwald     pos+=2;
2128eb8d463SMatthias Ringwald     event[pos++] = status;
2138eb8d463SMatthias Ringwald     memcpy(&event[pos], context->bd_addr, 6);
2148eb8d463SMatthias Ringwald     pos += 6;
2158eb8d463SMatthias Ringwald     little_endian_store_16(event,pos,context->con_handle);
2168eb8d463SMatthias Ringwald     pos += 2;
2178eb8d463SMatthias Ringwald     event[pos++] = context->incoming;
2188eb8d463SMatthias Ringwald     event[1] = pos - 2;
2198eb8d463SMatthias Ringwald     if (pos != sizeof(event)) log_error("hid_device_emit_connected_event size %u", pos);
2208eb8d463SMatthias Ringwald     hid_callback(HCI_EVENT_PACKET, context->cid, &event[0], pos);
2218eb8d463SMatthias Ringwald }
2228eb8d463SMatthias Ringwald 
2238eb8d463SMatthias Ringwald static inline void hid_device_emit_connection_closed_event(hid_device_t * context){
2248eb8d463SMatthias Ringwald     uint8_t event[5];
2258eb8d463SMatthias Ringwald     int pos = 0;
2268eb8d463SMatthias Ringwald     event[pos++] = HCI_EVENT_HID_META;
2278eb8d463SMatthias Ringwald     pos++;  // skip len
2288eb8d463SMatthias Ringwald     event[pos++] = HID_SUBEVENT_CONNECTION_CLOSED;
2298eb8d463SMatthias Ringwald     little_endian_store_16(event,pos,context->cid);
2308eb8d463SMatthias Ringwald     pos+=2;
2318eb8d463SMatthias Ringwald     event[1] = pos - 2;
2328eb8d463SMatthias Ringwald     if (pos != sizeof(event)) log_error("hid_device_emit_connection_closed_event size %u", pos);
2338eb8d463SMatthias Ringwald     hid_callback(HCI_EVENT_PACKET, context->cid, &event[0], pos);
2348eb8d463SMatthias Ringwald }
2358eb8d463SMatthias Ringwald 
2368eb8d463SMatthias Ringwald static inline void hid_device_emit_can_send_now_event(hid_device_t * context){
2378eb8d463SMatthias Ringwald     uint8_t event[5];
2388eb8d463SMatthias Ringwald     int pos = 0;
2398eb8d463SMatthias Ringwald     event[pos++] = HCI_EVENT_HID_META;
2408eb8d463SMatthias Ringwald     pos++;  // skip len
2418eb8d463SMatthias Ringwald     event[pos++] = HID_SUBEVENT_CAN_SEND_NOW;
2428eb8d463SMatthias Ringwald     little_endian_store_16(event,pos,context->cid);
2438eb8d463SMatthias Ringwald     pos+=2;
2448eb8d463SMatthias Ringwald     event[1] = pos - 2;
2458eb8d463SMatthias Ringwald     if (pos != sizeof(event)) log_error("hid_device_emit_can_send_now_event size %u", pos);
2468eb8d463SMatthias Ringwald     hid_callback(HCI_EVENT_PACKET, context->cid, &event[0], pos);
2478eb8d463SMatthias Ringwald }
2488eb8d463SMatthias Ringwald 
2498eb8d463SMatthias Ringwald 
2508eb8d463SMatthias Ringwald static int hid_connected(void){
251*57c643eeSMatthias Ringwald     return hid_device->connected;
2528eb8d463SMatthias Ringwald }
2538eb8d463SMatthias Ringwald 
2548eb8d463SMatthias Ringwald static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * packet, uint16_t packet_size){
2558eb8d463SMatthias Ringwald     UNUSED(channel);
2568eb8d463SMatthias Ringwald     UNUSED(packet_size);
2578eb8d463SMatthias Ringwald     int connected_before;
258*57c643eeSMatthias Ringwald     uint16_t psm;
259*57c643eeSMatthias Ringwald     uint8_t status;
2608eb8d463SMatthias Ringwald     switch (packet_type){
2618eb8d463SMatthias Ringwald         case HCI_EVENT_PACKET:
2628eb8d463SMatthias Ringwald             switch (packet[0]){
2638eb8d463SMatthias Ringwald                 case L2CAP_EVENT_INCOMING_CONNECTION:
2648eb8d463SMatthias Ringwald                     switch (l2cap_event_incoming_connection_get_psm(packet)){
2658eb8d463SMatthias Ringwald                         case PSM_HID_CONTROL:
2668eb8d463SMatthias Ringwald                         case PSM_HID_INTERRUPT:
2678eb8d463SMatthias Ringwald                             if (hid_device->con_handle == 0 || l2cap_event_incoming_connection_get_handle(packet) == hid_device->con_handle){
2688eb8d463SMatthias Ringwald                                 hid_device->con_handle = l2cap_event_incoming_connection_get_handle(packet);
269*57c643eeSMatthias Ringwald                                 hid_device->incoming = 1;
2708eb8d463SMatthias Ringwald                                 l2cap_accept_connection(channel);
2718eb8d463SMatthias Ringwald                             } else {
2728eb8d463SMatthias Ringwald                                 l2cap_decline_connection(channel);
2738eb8d463SMatthias Ringwald                             }
2748eb8d463SMatthias Ringwald                             break;
2758eb8d463SMatthias Ringwald                         default:
2768eb8d463SMatthias Ringwald                             l2cap_decline_connection(channel);
2778eb8d463SMatthias Ringwald                             break;
2788eb8d463SMatthias Ringwald                     }
2798eb8d463SMatthias Ringwald                     break;
2808eb8d463SMatthias Ringwald                 case L2CAP_EVENT_CHANNEL_OPENED:
281*57c643eeSMatthias Ringwald                     status = l2cap_event_channel_opened_get_status(packet);
282*57c643eeSMatthias Ringwald                     if (status) {
283*57c643eeSMatthias Ringwald                         if (hid_device->incoming == 0){
284*57c643eeSMatthias Ringwald                             // report error for outgoing connection
285*57c643eeSMatthias Ringwald                             hid_device_emit_connected_event(hid_device, status);
286*57c643eeSMatthias Ringwald                         }
287*57c643eeSMatthias Ringwald                         return;
288*57c643eeSMatthias Ringwald                     }
289*57c643eeSMatthias Ringwald                     psm = l2cap_event_channel_opened_get_psm(packet);
2908eb8d463SMatthias Ringwald                     connected_before = hid_connected();
291*57c643eeSMatthias Ringwald                     switch (psm){
2928eb8d463SMatthias Ringwald                         case PSM_HID_CONTROL:
2938eb8d463SMatthias Ringwald                             hid_device->control_cid = l2cap_event_channel_opened_get_local_cid(packet);
2948eb8d463SMatthias Ringwald                             log_info("HID Control opened, cid 0x%02x", hid_device->control_cid);
2958eb8d463SMatthias Ringwald                             break;
2968eb8d463SMatthias Ringwald                         case PSM_HID_INTERRUPT:
2978eb8d463SMatthias Ringwald                             hid_device->interrupt_cid = l2cap_event_channel_opened_get_local_cid(packet);
2988eb8d463SMatthias Ringwald                             log_info("HID Interrupt opened, cid 0x%02x", hid_device->interrupt_cid);
2998eb8d463SMatthias Ringwald                             break;
3008eb8d463SMatthias Ringwald                         default:
3018eb8d463SMatthias Ringwald                             break;
3028eb8d463SMatthias Ringwald                     }
303*57c643eeSMatthias Ringwald                     // connect HID Interrupt for outgoing
304*57c643eeSMatthias Ringwald                     if (hid_device->incoming == 0 && psm == PSM_HID_CONTROL){
305*57c643eeSMatthias Ringwald                         log_info("Create outgoing HID Interrupt");
306*57c643eeSMatthias Ringwald                         status = l2cap_create_channel(packet_handler, hid_device->bd_addr, PSM_HID_INTERRUPT, 48, &hid_device->interrupt_cid);
307*57c643eeSMatthias Ringwald                         break;
308*57c643eeSMatthias Ringwald                     }
309*57c643eeSMatthias Ringwald                     if (!connected_before && hid_device->control_cid && hid_device->interrupt_cid){
310*57c643eeSMatthias Ringwald                         hid_device->connected = 1;
3118eb8d463SMatthias Ringwald                         log_info("HID Connected");
3128eb8d463SMatthias Ringwald                         hid_device_emit_connected_event(hid_device, 0);
3138eb8d463SMatthias Ringwald                     }
3148eb8d463SMatthias Ringwald                     break;
3158eb8d463SMatthias Ringwald                 case L2CAP_EVENT_CHANNEL_CLOSED:
316*57c643eeSMatthias Ringwald                     hid_device->incoming  = 0;
317*57c643eeSMatthias Ringwald                     hid_device->connected = 0;
3188eb8d463SMatthias Ringwald                     connected_before = hid_connected();
3198eb8d463SMatthias Ringwald                     if (l2cap_event_channel_closed_get_local_cid(packet) == hid_device->control_cid){
3208eb8d463SMatthias Ringwald                         log_info("HID Control closed");
3218eb8d463SMatthias Ringwald                         hid_device->control_cid = 0;
3228eb8d463SMatthias Ringwald                     }
3238eb8d463SMatthias Ringwald                     if (l2cap_event_channel_closed_get_local_cid(packet) == hid_device->interrupt_cid){
3248eb8d463SMatthias Ringwald                         log_info("HID Interrupt closed");
3258eb8d463SMatthias Ringwald                         hid_device->interrupt_cid = 0;
3268eb8d463SMatthias Ringwald                     }
3278eb8d463SMatthias Ringwald                     if (connected_before && !hid_connected()){
3288eb8d463SMatthias Ringwald                         hid_device->con_handle = 0;
3298eb8d463SMatthias Ringwald                         log_info("HID Disconnected");
3308eb8d463SMatthias Ringwald                         hid_device_emit_connection_closed_event(hid_device);
3318eb8d463SMatthias Ringwald                     }
3328eb8d463SMatthias Ringwald                     break;
3338eb8d463SMatthias Ringwald                 case L2CAP_EVENT_CAN_SEND_NOW:
3348eb8d463SMatthias Ringwald                     log_info("HID Can send now, emit event");
3358eb8d463SMatthias Ringwald                     hid_device_emit_can_send_now_event(hid_device);
3368eb8d463SMatthias Ringwald                     break;
3378eb8d463SMatthias Ringwald                 default:
3388eb8d463SMatthias Ringwald                     break;
3398eb8d463SMatthias Ringwald             }
3408eb8d463SMatthias Ringwald             break;
3418eb8d463SMatthias Ringwald         default:
3428eb8d463SMatthias Ringwald             break;
3438eb8d463SMatthias Ringwald     }
3448eb8d463SMatthias Ringwald }
3458eb8d463SMatthias Ringwald 
3468eb8d463SMatthias Ringwald /**
3478eb8d463SMatthias Ringwald  * @brief Set up HID Device
3488eb8d463SMatthias Ringwald  */
3498eb8d463SMatthias Ringwald void hid_device_init(void){
3508eb8d463SMatthias Ringwald     memset(hid_device, 0, sizeof(hid_device_t));
3518eb8d463SMatthias Ringwald     hid_device->cid = 1;
35245a58b30SMatthias Ringwald     l2cap_register_service(packet_handler, PSM_HID_INTERRUPT, 100, LEVEL_2);
35345a58b30SMatthias Ringwald     l2cap_register_service(packet_handler, PSM_HID_CONTROL,   100, LEVEL_2);
3548eb8d463SMatthias Ringwald }
3558eb8d463SMatthias Ringwald 
3568eb8d463SMatthias Ringwald /**
3578eb8d463SMatthias Ringwald  * @brief Register callback for the HID Device client.
3588eb8d463SMatthias Ringwald  * @param callback
3598eb8d463SMatthias Ringwald  */
3608eb8d463SMatthias Ringwald void hid_device_register_packet_handler(btstack_packet_handler_t callback){
3618eb8d463SMatthias Ringwald     hid_callback = callback;
3628eb8d463SMatthias Ringwald }
3638eb8d463SMatthias Ringwald 
3648eb8d463SMatthias Ringwald /**
3658eb8d463SMatthias Ringwald  * @brief Request can send now event to send HID Report
3668eb8d463SMatthias Ringwald  * @param hid_cid
3678eb8d463SMatthias Ringwald  */
3688eb8d463SMatthias Ringwald void hid_device_request_can_send_now_event(uint16_t hid_cid){
3698eb8d463SMatthias Ringwald     UNUSED(hid_cid);
3708eb8d463SMatthias Ringwald     if (!hid_device->control_cid) return;
3718eb8d463SMatthias Ringwald     l2cap_request_can_send_now_event(hid_device->control_cid);
3728eb8d463SMatthias Ringwald }
3738eb8d463SMatthias Ringwald 
3748eb8d463SMatthias Ringwald /**
3758eb8d463SMatthias Ringwald  * @brief Send HID messageon interrupt channel
3768eb8d463SMatthias Ringwald  * @param hid_cid
3778eb8d463SMatthias Ringwald  */
3788eb8d463SMatthias Ringwald void hid_device_send_interrupt_message(uint16_t hid_cid, const uint8_t * message, uint16_t message_len){
3798eb8d463SMatthias Ringwald     UNUSED(hid_cid);
3808eb8d463SMatthias Ringwald     if (!hid_device->interrupt_cid) return;
3818eb8d463SMatthias Ringwald     l2cap_send(hid_device->interrupt_cid, (uint8_t*) message, message_len);
3828eb8d463SMatthias Ringwald }
3838eb8d463SMatthias Ringwald 
3848eb8d463SMatthias Ringwald /**
3858eb8d463SMatthias Ringwald  * @brief Send HID messageon control channel
3868eb8d463SMatthias Ringwald  * @param hid_cid
3878eb8d463SMatthias Ringwald  */
3888eb8d463SMatthias Ringwald void hid_device_send_contro_message(uint16_t hid_cid, const uint8_t * message, uint16_t message_len){
3898eb8d463SMatthias Ringwald     UNUSED(hid_cid);
3908eb8d463SMatthias Ringwald     if (!hid_device->control_cid) return;
3918eb8d463SMatthias Ringwald     l2cap_send(hid_device->control_cid, (uint8_t*) message, message_len);
3928eb8d463SMatthias Ringwald }
3938eb8d463SMatthias Ringwald 
394*57c643eeSMatthias Ringwald /*
395*57c643eeSMatthias Ringwald  * @brief Create HID connection to HID Host
396*57c643eeSMatthias Ringwald  * @param addr
397*57c643eeSMatthias Ringwald  * @param hid_cid to use for other commands
398*57c643eeSMatthias Ringwald  * @result status
399*57c643eeSMatthias Ringwald  */
400*57c643eeSMatthias Ringwald uint8_t hid_device_connect(bd_addr_t addr, uint16_t * hid_cid){
401*57c643eeSMatthias Ringwald 
402*57c643eeSMatthias Ringwald     // assign hic_cid
403*57c643eeSMatthias Ringwald     *hid_cid = hid_device->cid;
404*57c643eeSMatthias Ringwald 
405*57c643eeSMatthias Ringwald     // store address
406*57c643eeSMatthias Ringwald     memcpy(hid_device->bd_addr, addr, 6);
407*57c643eeSMatthias Ringwald 
408*57c643eeSMatthias Ringwald     // reset state
409*57c643eeSMatthias Ringwald     hid_device->incoming      = 0;
410*57c643eeSMatthias Ringwald     hid_device->connected     = 0;
411*57c643eeSMatthias Ringwald     hid_device->control_cid   = 0;
412*57c643eeSMatthias Ringwald     hid_device->interrupt_cid = 0;
413*57c643eeSMatthias Ringwald 
414*57c643eeSMatthias Ringwald     // create l2cap control using fixed HID L2CAP PSM
415*57c643eeSMatthias Ringwald     log_info("Create outgoing HID Control");
416*57c643eeSMatthias Ringwald     uint8_t status = l2cap_create_channel(packet_handler, hid_device->bd_addr, PSM_HID_CONTROL, 48, &hid_device->control_cid);
417*57c643eeSMatthias Ringwald 
418*57c643eeSMatthias Ringwald     return status;
419*57c643eeSMatthias Ringwald }
420