xref: /btstack/src/classic/hid_device.c (revision a1118d112978a037509e88ec1570a25a218393d9)
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"
49662cddc2SMilanka Ringwald #include "btstack_hid_parser.h"
508eb8d463SMatthias Ringwald 
51c12110e4SMilanka Ringwald typedef enum {
52c12110e4SMilanka Ringwald     HID_DEVICE_IDLE,
53c12110e4SMilanka Ringwald     HID_DEVICE_CONNECTED,
54ba9a58feSMilanka Ringwald     HID_DEVICE_W2_GET_REPORT,
55ba9a58feSMilanka Ringwald     HID_DEVICE_W2_SET_REPORT,
56ba9a58feSMilanka Ringwald     HID_DEVICE_W2_GET_PROTOCOL,
57ba9a58feSMilanka Ringwald     HID_DEVICE_W2_SET_PROTOCOL,
58ba9a58feSMilanka Ringwald     HID_DEVICE_W2_ANSWER_SET_PROTOCOL,
59ba9a58feSMilanka Ringwald     HID_DEVICE_W2_SEND_UNSUPPORTED_REQUEST,
60c12110e4SMilanka Ringwald } hid_device_state_t;
61c12110e4SMilanka Ringwald 
628eb8d463SMatthias Ringwald // hid device state
638eb8d463SMatthias Ringwald typedef struct hid_device {
648eb8d463SMatthias Ringwald     uint16_t  cid;
658eb8d463SMatthias Ringwald     bd_addr_t bd_addr;
668eb8d463SMatthias Ringwald     hci_con_handle_t con_handle;
678eb8d463SMatthias Ringwald     uint16_t  control_cid;
688eb8d463SMatthias Ringwald     uint16_t  interrupt_cid;
698eb8d463SMatthias Ringwald     uint8_t   incoming;
7057c643eeSMatthias Ringwald     uint8_t   connected;
71c12110e4SMilanka Ringwald     hid_device_state_t state;
72c12110e4SMilanka Ringwald     hid_report_type_t report_type;
73c12110e4SMilanka Ringwald     uint16_t  report_id;
74*a1118d11SMilanka Ringwald     uint16_t  expected_report_size;
75*a1118d11SMilanka Ringwald     uint16_t  report_size;
76ba9a58feSMilanka Ringwald 
77bc967e00SMilanka Ringwald     hid_handshake_param_type_t report_status;
78ba9a58feSMilanka Ringwald     hid_protocol_mode_t protocol_mode;
798eb8d463SMatthias Ringwald } hid_device_t;
808eb8d463SMatthias Ringwald 
818eb8d463SMatthias Ringwald static hid_device_t _hid_device;
82ba9a58feSMilanka Ringwald static uint8_t hid_boot_protocol_mode_supported;
83662cddc2SMilanka Ringwald static const uint8_t * hid_descriptor;
84662cddc2SMilanka Ringwald static uint16_t hid_descriptor_len;
85c12110e4SMilanka Ringwald 
86*a1118d11SMilanka Ringwald static int dummy_write_report(uint16_t hid_cid, hid_report_type_t report_type, uint16_t report_id, int * out_report_size, uint8_t * out_report){
87c12110e4SMilanka Ringwald     UNUSED(hid_cid);
88c12110e4SMilanka Ringwald     UNUSED(report_type);
89c12110e4SMilanka Ringwald     UNUSED(report_id);
90c12110e4SMilanka Ringwald     UNUSED(out_report_size);
91c12110e4SMilanka Ringwald     UNUSED(out_report);
92*a1118d11SMilanka Ringwald     return -1;
93c12110e4SMilanka Ringwald }
944dfe6a8bSMilanka Ringwald 
954dfe6a8bSMilanka Ringwald static void dummy_set_report(uint16_t hid_cid, hid_report_type_t report_type, int report_size, uint8_t * report){
96ba9a58feSMilanka Ringwald     UNUSED(hid_cid);
97ba9a58feSMilanka Ringwald     UNUSED(report_type);
98ba9a58feSMilanka Ringwald     UNUSED(report_size);
99ba9a58feSMilanka Ringwald     UNUSED(report);
100ba9a58feSMilanka Ringwald }
1014dfe6a8bSMilanka Ringwald 
1027d26fe66SMilanka Ringwald static void dummy_report_data(uint16_t hid_cid, hid_report_type_t report_type, uint16_t report_id, int report_size, uint8_t * report){
1037d26fe66SMilanka Ringwald     UNUSED(hid_cid);
1047d26fe66SMilanka Ringwald     UNUSED(report_type);
1057d26fe66SMilanka Ringwald     UNUSED(report_id);
1067d26fe66SMilanka Ringwald     UNUSED(report_size);
1077d26fe66SMilanka Ringwald     UNUSED(report);
1087d26fe66SMilanka Ringwald }
1097d26fe66SMilanka Ringwald 
110*a1118d11SMilanka Ringwald static int  (*hci_device_get_report) (uint16_t hid_cid, hid_report_type_t report_type, uint16_t report_id, int * out_report_size, uint8_t * out_report) = dummy_write_report;
1114dfe6a8bSMilanka Ringwald static void (*hci_device_set_report)   (uint16_t hid_cid, hid_report_type_t report_type, int report_size, uint8_t * report) = dummy_set_report;
1127d26fe66SMilanka Ringwald static void (*hci_device_report_data)  (uint16_t hid_cid, hid_report_type_t report_type, uint16_t report_id, int report_size, uint8_t * report) = dummy_report_data;
1138eb8d463SMatthias Ringwald 
1148eb8d463SMatthias Ringwald static btstack_packet_handler_t hid_callback;
115d40c9ac6SMatthias Ringwald 
116c12110e4SMilanka Ringwald static uint16_t hid_device_cid = 0;
117c12110e4SMilanka Ringwald 
118c12110e4SMilanka Ringwald static uint16_t hid_device_get_next_cid(void){
119c12110e4SMilanka Ringwald     hid_device_cid++;
120c12110e4SMilanka Ringwald     if (!hid_device_cid){
121c12110e4SMilanka Ringwald         hid_device_cid = 1;
122c12110e4SMilanka Ringwald     }
123c12110e4SMilanka Ringwald     return hid_device_cid;
124c12110e4SMilanka Ringwald }
125c12110e4SMilanka Ringwald 
126c12110e4SMilanka Ringwald // TODO: store hid device connection into list
127c12110e4SMilanka Ringwald static hid_device_t * hid_device_get_instance_for_cid(uint16_t cid){
128a78157ddSMilanka Ringwald     // printf("control_cid 0x%02x, interrupt_cid 0x%02x, query_cid 0x%02x \n", _hid_device.control_cid,  _hid_device.interrupt_cid, cid);
129c12110e4SMilanka Ringwald     if (_hid_device.cid == cid || _hid_device.control_cid == cid || _hid_device.interrupt_cid == cid){
130c12110e4SMilanka Ringwald         return &_hid_device;
131c12110e4SMilanka Ringwald     }
132c12110e4SMilanka Ringwald     return NULL;
133c12110e4SMilanka Ringwald }
134c12110e4SMilanka Ringwald 
135ba9a58feSMilanka Ringwald static hid_device_t * hid_device_provide_instance_for_bt_addr(bd_addr_t bd_addr){
1366510739bSMilanka Ringwald     if (!_hid_device.cid){
137ba9a58feSMilanka Ringwald         memcpy(_hid_device.bd_addr, bd_addr, 6);
1386510739bSMilanka Ringwald         _hid_device.cid = hid_device_get_next_cid();
139ba9a58feSMilanka Ringwald         _hid_device.protocol_mode = HID_PROTOCOL_MODE_REPORT;
1406510739bSMilanka Ringwald     }
141c12110e4SMilanka Ringwald     return &_hid_device;
142c12110e4SMilanka Ringwald }
143c12110e4SMilanka Ringwald 
144c12110e4SMilanka Ringwald static hid_device_t * hid_device_get_instance_for_con_handle(uint16_t con_handle){
145c12110e4SMilanka Ringwald     UNUSED(con_handle);
146c12110e4SMilanka Ringwald     return &_hid_device;
147c12110e4SMilanka Ringwald }
148c12110e4SMilanka Ringwald 
149c12110e4SMilanka Ringwald static hid_device_t * hid_device_create_instance(void){
150ba9a58feSMilanka Ringwald 
151c12110e4SMilanka Ringwald     return &_hid_device;
152c12110e4SMilanka Ringwald }
153c12110e4SMilanka Ringwald 
154d40c9ac6SMatthias Ringwald void hid_create_sdp_record(
155d40c9ac6SMatthias Ringwald     uint8_t *service,
156d40c9ac6SMatthias Ringwald     uint32_t service_record_handle,
157d40c9ac6SMatthias Ringwald     uint16_t hid_device_subclass,
158d40c9ac6SMatthias Ringwald     uint8_t  hid_country_code,
159d40c9ac6SMatthias Ringwald     uint8_t  hid_virtual_cable,
160d40c9ac6SMatthias Ringwald     uint8_t  hid_reconnect_initiate,
161d40c9ac6SMatthias Ringwald     uint8_t  hid_boot_device,
162662cddc2SMilanka Ringwald     const uint8_t * descriptor, uint16_t descriptor_size,
163d40c9ac6SMatthias Ringwald     const char *device_name){
164d40c9ac6SMatthias Ringwald 
165d40c9ac6SMatthias Ringwald     uint8_t * attribute;
166d40c9ac6SMatthias Ringwald     de_create_sequence(service);
167d40c9ac6SMatthias Ringwald 
168d40c9ac6SMatthias Ringwald     de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_RECORD_HANDLE);
169d40c9ac6SMatthias Ringwald     de_add_number(service, DE_UINT, DE_SIZE_32, service_record_handle);
170d40c9ac6SMatthias Ringwald 
171d40c9ac6SMatthias Ringwald     de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST);
172d40c9ac6SMatthias Ringwald     attribute = de_push_sequence(service);
173d40c9ac6SMatthias Ringwald     {
174d40c9ac6SMatthias Ringwald         de_add_number(attribute,  DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE_SERVICE);
175d40c9ac6SMatthias Ringwald     }
176d40c9ac6SMatthias Ringwald     de_pop_sequence(service, attribute);
177d40c9ac6SMatthias Ringwald 
178d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST);
179d40c9ac6SMatthias Ringwald     attribute = de_push_sequence(service);
180d40c9ac6SMatthias Ringwald     {
181d40c9ac6SMatthias Ringwald         uint8_t * l2cpProtocol = de_push_sequence(attribute);
182d40c9ac6SMatthias Ringwald         {
183d40c9ac6SMatthias Ringwald             de_add_number(l2cpProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_L2CAP);
184d40c9ac6SMatthias Ringwald             de_add_number(l2cpProtocol,  DE_UINT, DE_SIZE_16, PSM_HID_CONTROL);
185d40c9ac6SMatthias Ringwald         }
186d40c9ac6SMatthias Ringwald         de_pop_sequence(attribute, l2cpProtocol);
187d40c9ac6SMatthias Ringwald 
188d40c9ac6SMatthias Ringwald         uint8_t * hidProtocol = de_push_sequence(attribute);
189d40c9ac6SMatthias Ringwald         {
190d40c9ac6SMatthias Ringwald             de_add_number(hidProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_HIDP);
191d40c9ac6SMatthias Ringwald         }
192d40c9ac6SMatthias Ringwald         de_pop_sequence(attribute, hidProtocol);
193d40c9ac6SMatthias Ringwald     }
194d40c9ac6SMatthias Ringwald     de_pop_sequence(service, attribute);
195d40c9ac6SMatthias Ringwald 
196d40c9ac6SMatthias Ringwald     // TODO?
197d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
198d40c9ac6SMatthias Ringwald     attribute = de_push_sequence(service);
199d40c9ac6SMatthias Ringwald     {
200d40c9ac6SMatthias Ringwald         de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x656e);
201d40c9ac6SMatthias Ringwald         de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x006a);
202d40c9ac6SMatthias Ringwald         de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x0100);
203d40c9ac6SMatthias Ringwald     }
204d40c9ac6SMatthias Ringwald     de_pop_sequence(service, attribute);
205d40c9ac6SMatthias Ringwald 
206d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS);
207d40c9ac6SMatthias Ringwald     attribute = de_push_sequence(service);
208d40c9ac6SMatthias Ringwald     {
209d40c9ac6SMatthias Ringwald         uint8_t * additionalDescriptorAttribute = de_push_sequence(attribute);
210d40c9ac6SMatthias Ringwald         {
211d40c9ac6SMatthias Ringwald             uint8_t * l2cpProtocol = de_push_sequence(additionalDescriptorAttribute);
212d40c9ac6SMatthias Ringwald             {
213d40c9ac6SMatthias Ringwald                 de_add_number(l2cpProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_L2CAP);
214d40c9ac6SMatthias Ringwald                 de_add_number(l2cpProtocol,  DE_UINT, DE_SIZE_16, PSM_HID_INTERRUPT);
215d40c9ac6SMatthias Ringwald             }
216d40c9ac6SMatthias Ringwald             de_pop_sequence(additionalDescriptorAttribute, l2cpProtocol);
217d40c9ac6SMatthias Ringwald 
2189fa0921fSMatthias Ringwald             uint8_t * hidProtocol = de_push_sequence(additionalDescriptorAttribute);
219d40c9ac6SMatthias Ringwald             {
220d40c9ac6SMatthias Ringwald                 de_add_number(hidProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_HIDP);
221d40c9ac6SMatthias Ringwald             }
2229fa0921fSMatthias Ringwald             de_pop_sequence(additionalDescriptorAttribute, hidProtocol);
223d40c9ac6SMatthias Ringwald         }
224d40c9ac6SMatthias Ringwald         de_pop_sequence(attribute, additionalDescriptorAttribute);
225d40c9ac6SMatthias Ringwald     }
226d40c9ac6SMatthias Ringwald     de_pop_sequence(service, attribute);
227d40c9ac6SMatthias Ringwald 
228d40c9ac6SMatthias Ringwald     // 0x0100 "ServiceName"
229d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, 0x0100);
230d40c9ac6SMatthias Ringwald     de_add_data(service,  DE_STRING, strlen(device_name), (uint8_t *) device_name);
231d40c9ac6SMatthias Ringwald 
232d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
233d40c9ac6SMatthias Ringwald     attribute = de_push_sequence(service);
234d40c9ac6SMatthias Ringwald     {
235d40c9ac6SMatthias Ringwald         uint8_t * hidProfile = de_push_sequence(attribute);
236d40c9ac6SMatthias Ringwald         {
237d40c9ac6SMatthias Ringwald             de_add_number(hidProfile,  DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE_SERVICE);
238d40c9ac6SMatthias Ringwald             de_add_number(hidProfile,  DE_UINT, DE_SIZE_16, 0x0101);    // Version 1.1
239d40c9ac6SMatthias Ringwald         }
240d40c9ac6SMatthias Ringwald         de_pop_sequence(attribute, hidProfile);
241d40c9ac6SMatthias Ringwald     }
242d40c9ac6SMatthias Ringwald     de_pop_sequence(service, attribute);
243d40c9ac6SMatthias Ringwald 
244d40c9ac6SMatthias Ringwald     // Deprecated in v1.1.1
245d40c9ac6SMatthias Ringwald     // de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_DEVICE_RELEASE_NUMBER);
246d40c9ac6SMatthias Ringwald     // de_add_number(service,  DE_UINT, DE_SIZE_16, 0x0101);
247d40c9ac6SMatthias Ringwald 
248d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_PARSER_VERSION);
249d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, 0x0111);  // v1.1.1
250d40c9ac6SMatthias Ringwald 
251d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_DEVICE_SUBCLASS);
2529679ea81SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_8,  hid_device_subclass);
253d40c9ac6SMatthias Ringwald 
254d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_COUNTRY_CODE);
2559679ea81SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_8,  hid_country_code);
256d40c9ac6SMatthias Ringwald 
257d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_VIRTUAL_CABLE);
258d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_BOOL, DE_SIZE_8,  hid_virtual_cable);
259d40c9ac6SMatthias Ringwald 
260d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_RECONNECT_INITIATE);
261d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_BOOL, DE_SIZE_8,  hid_reconnect_initiate);
262d40c9ac6SMatthias Ringwald 
263d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_DESCRIPTOR_LIST);
264d40c9ac6SMatthias Ringwald     attribute = de_push_sequence(service);
265d40c9ac6SMatthias Ringwald     {
266d40c9ac6SMatthias Ringwald         uint8_t* hidDescriptor = de_push_sequence(attribute);
267d40c9ac6SMatthias Ringwald         {
268d40c9ac6SMatthias Ringwald             de_add_number(hidDescriptor,  DE_UINT, DE_SIZE_8, 0x22);    // Report Descriptor
269662cddc2SMilanka Ringwald             de_add_data(hidDescriptor,  DE_STRING, descriptor_size, (uint8_t *) descriptor);
270d40c9ac6SMatthias Ringwald         }
271d40c9ac6SMatthias Ringwald         de_pop_sequence(attribute, hidDescriptor);
272d40c9ac6SMatthias Ringwald     }
273d40c9ac6SMatthias Ringwald     de_pop_sequence(service, attribute);
274d40c9ac6SMatthias Ringwald 
2759679ea81SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HIDLANGID_BASE_LIST);
2769679ea81SMatthias Ringwald     attribute = de_push_sequence(service);
2779679ea81SMatthias Ringwald     {
2789679ea81SMatthias Ringwald         uint8_t* hig_lang_base = de_push_sequence(attribute);
2799679ea81SMatthias Ringwald         {
2809679ea81SMatthias Ringwald             // see: http://www.usb.org/developers/docs/USB_LANGIDs.pdf
2819679ea81SMatthias Ringwald             de_add_number(hig_lang_base,  DE_UINT, DE_SIZE_16, 0x0409);    // HIDLANGID = English (US)
2829679ea81SMatthias Ringwald             de_add_number(hig_lang_base,  DE_UINT, DE_SIZE_16, 0x0100);    // HIDLanguageBase = 0x0100 default
2839679ea81SMatthias Ringwald         }
2849679ea81SMatthias Ringwald         de_pop_sequence(attribute, hig_lang_base);
2859679ea81SMatthias Ringwald     }
2869679ea81SMatthias Ringwald     de_pop_sequence(service, attribute);
2879679ea81SMatthias Ringwald 
2886510739bSMilanka Ringwald     uint8_t hid_remote_wake = 1;
2896510739bSMilanka Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_REMOTE_WAKE);
2906510739bSMilanka Ringwald     de_add_number(service,  DE_BOOL, DE_SIZE_8,  hid_remote_wake);
2916510739bSMilanka Ringwald 
292d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_BOOT_DEVICE);
293d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_BOOL, DE_SIZE_8,  hid_boot_device);
294d40c9ac6SMatthias Ringwald }
2958eb8d463SMatthias Ringwald 
2968eb8d463SMatthias Ringwald static inline void hid_device_emit_connected_event(hid_device_t * context, uint8_t status){
2978eb8d463SMatthias Ringwald     uint8_t event[15];
2988eb8d463SMatthias Ringwald     int pos = 0;
2998eb8d463SMatthias Ringwald     event[pos++] = HCI_EVENT_HID_META;
3008eb8d463SMatthias Ringwald     pos++;  // skip len
3018eb8d463SMatthias Ringwald     event[pos++] = HID_SUBEVENT_CONNECTION_OPENED;
3028eb8d463SMatthias Ringwald     little_endian_store_16(event,pos,context->cid);
3038eb8d463SMatthias Ringwald     pos+=2;
3048eb8d463SMatthias Ringwald     event[pos++] = status;
3056510739bSMilanka Ringwald     reverse_bd_addr(context->bd_addr, &event[pos]);
3068eb8d463SMatthias Ringwald     pos += 6;
3078eb8d463SMatthias Ringwald     little_endian_store_16(event,pos,context->con_handle);
3088eb8d463SMatthias Ringwald     pos += 2;
3098eb8d463SMatthias Ringwald     event[pos++] = context->incoming;
3108eb8d463SMatthias Ringwald     event[1] = pos - 2;
3118eb8d463SMatthias Ringwald     if (pos != sizeof(event)) log_error("hid_device_emit_connected_event size %u", pos);
3128eb8d463SMatthias Ringwald     hid_callback(HCI_EVENT_PACKET, context->cid, &event[0], pos);
3138eb8d463SMatthias Ringwald }
3148eb8d463SMatthias Ringwald 
3158eb8d463SMatthias Ringwald static inline void hid_device_emit_connection_closed_event(hid_device_t * context){
3168eb8d463SMatthias Ringwald     uint8_t event[5];
3178eb8d463SMatthias Ringwald     int pos = 0;
3188eb8d463SMatthias Ringwald     event[pos++] = HCI_EVENT_HID_META;
3198eb8d463SMatthias Ringwald     pos++;  // skip len
3208eb8d463SMatthias Ringwald     event[pos++] = HID_SUBEVENT_CONNECTION_CLOSED;
3218eb8d463SMatthias Ringwald     little_endian_store_16(event,pos,context->cid);
3228eb8d463SMatthias Ringwald     pos+=2;
3238eb8d463SMatthias Ringwald     event[1] = pos - 2;
3248eb8d463SMatthias Ringwald     if (pos != sizeof(event)) log_error("hid_device_emit_connection_closed_event size %u", pos);
3258eb8d463SMatthias Ringwald     hid_callback(HCI_EVENT_PACKET, context->cid, &event[0], pos);
3268eb8d463SMatthias Ringwald }
3278eb8d463SMatthias Ringwald 
3288eb8d463SMatthias Ringwald static inline void hid_device_emit_can_send_now_event(hid_device_t * context){
3298eb8d463SMatthias Ringwald     uint8_t event[5];
3308eb8d463SMatthias Ringwald     int pos = 0;
3318eb8d463SMatthias Ringwald     event[pos++] = HCI_EVENT_HID_META;
3328eb8d463SMatthias Ringwald     pos++;  // skip len
3338eb8d463SMatthias Ringwald     event[pos++] = HID_SUBEVENT_CAN_SEND_NOW;
3348eb8d463SMatthias Ringwald     little_endian_store_16(event,pos,context->cid);
3358eb8d463SMatthias Ringwald     pos+=2;
3368eb8d463SMatthias Ringwald     event[1] = pos - 2;
3378eb8d463SMatthias Ringwald     if (pos != sizeof(event)) log_error("hid_device_emit_can_send_now_event size %u", pos);
3388eb8d463SMatthias Ringwald     hid_callback(HCI_EVENT_PACKET, context->cid, &event[0], pos);
3398eb8d463SMatthias Ringwald }
3408eb8d463SMatthias Ringwald 
3416510739bSMilanka Ringwald static inline void hid_device_emit_event(hid_device_t * context, uint8_t subevent_type){
3426510739bSMilanka Ringwald     uint8_t event[4];
3436510739bSMilanka Ringwald     int pos = 0;
3446510739bSMilanka Ringwald     event[pos++] = HCI_EVENT_HID_META;
3456510739bSMilanka Ringwald     pos++;  // skip len
3466510739bSMilanka Ringwald     event[pos++] = subevent_type;
3476510739bSMilanka Ringwald     little_endian_store_16(event,pos,context->cid);
3486510739bSMilanka Ringwald     pos+=2;
3496510739bSMilanka Ringwald     event[1] = pos - 2;
3506510739bSMilanka Ringwald     if (pos != sizeof(event)) log_error("hid_device_emit_event size %u", pos);
3516510739bSMilanka Ringwald     hid_callback(HCI_EVENT_PACKET, context->cid, &event[0], pos);
3526510739bSMilanka Ringwald }
3536510739bSMilanka Ringwald 
3544dfe6a8bSMilanka Ringwald static hid_handshake_param_type_t hid_device_set_report_cmd_is_valid(uint16_t cid, hid_report_type_t report_type, int report_size, uint8_t * report){
3554dfe6a8bSMilanka Ringwald     int pos = 0;
3564dfe6a8bSMilanka Ringwald     int report_id = report[0];
3574dfe6a8bSMilanka Ringwald     hid_report_id_status_t report_id_status = hid_report_id_status(cid, report_id);
3584dfe6a8bSMilanka Ringwald     switch (report_id_status){
3594dfe6a8bSMilanka Ringwald         case HID_REPORT_ID_VALID:
3604dfe6a8bSMilanka Ringwald             pos++;
3614dfe6a8bSMilanka Ringwald             break;
3624dfe6a8bSMilanka Ringwald         case HID_REPORT_ID_INVALID:
3634dfe6a8bSMilanka Ringwald             printf("invalid id\n");
3644dfe6a8bSMilanka Ringwald             return HID_HANDSHAKE_PARAM_TYPE_ERR_INVALID_REPORT_ID;
3654dfe6a8bSMilanka Ringwald         default:
3664dfe6a8bSMilanka Ringwald             report_id = 0;
3674dfe6a8bSMilanka Ringwald             break;
3684dfe6a8bSMilanka Ringwald     }
3694dfe6a8bSMilanka Ringwald 
3704dfe6a8bSMilanka Ringwald     if (!hid_report_size_valid(cid, report_id, report_type, report_size-pos)){
3714dfe6a8bSMilanka Ringwald         printf("invalid report size\n");
3724dfe6a8bSMilanka Ringwald         return HID_HANDSHAKE_PARAM_TYPE_ERR_INVALID_PARAMETER;
3734dfe6a8bSMilanka Ringwald     }
3744dfe6a8bSMilanka Ringwald     return HID_HANDSHAKE_PARAM_TYPE_SUCCESSFUL;
3754dfe6a8bSMilanka Ringwald }
3764dfe6a8bSMilanka Ringwald 
3778eb8d463SMatthias Ringwald static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * packet, uint16_t packet_size){
3788eb8d463SMatthias Ringwald     UNUSED(channel);
3798eb8d463SMatthias Ringwald     UNUSED(packet_size);
3808eb8d463SMatthias Ringwald     int connected_before;
38157c643eeSMatthias Ringwald     uint16_t psm;
38257c643eeSMatthias Ringwald     uint8_t status;
383c12110e4SMilanka Ringwald     hid_device_t * device = NULL;
3846510739bSMilanka Ringwald     uint8_t param;
3856510739bSMilanka Ringwald     bd_addr_t address;
3867d26fe66SMilanka Ringwald     uint16_t local_cid;
387*a1118d11SMilanka Ringwald     int pos = 0;
388ba9a58feSMilanka Ringwald     int report_size;
389*a1118d11SMilanka Ringwald     uint8_t report[48];
390c12110e4SMilanka Ringwald 
3918eb8d463SMatthias Ringwald     switch (packet_type){
392c12110e4SMilanka Ringwald         case L2CAP_DATA_PACKET:
393c12110e4SMilanka Ringwald             device = hid_device_get_instance_for_cid(channel);
394c12110e4SMilanka Ringwald             if (!device) {
395c12110e4SMilanka Ringwald                 log_error("no device with cid 0x%02x", channel);
396c12110e4SMilanka Ringwald                 return;
397c12110e4SMilanka Ringwald             }
398c12110e4SMilanka Ringwald             hid_message_type_t message_type = packet[0] >> 4;
399df3cc7a0SMilanka Ringwald             // printf("L2CAP_DATA_PACKET message_type %d, packet_size %d  \n", message_type, packet_size);
400c12110e4SMilanka Ringwald             switch (message_type){
401c12110e4SMilanka Ringwald                 case HID_MESSAGE_TYPE_GET_REPORT:
402*a1118d11SMilanka Ringwald                     pos = 0;
403*a1118d11SMilanka Ringwald                     device->report_type = packet[pos++] & 0x03;
404c12110e4SMilanka Ringwald                     device->report_id = 0;
4057d26fe66SMilanka Ringwald                     device->report_status = HID_HANDSHAKE_PARAM_TYPE_SUCCESSFUL;
406*a1118d11SMilanka Ringwald                     device->state = HID_DEVICE_W2_GET_REPORT;
4077d26fe66SMilanka Ringwald 
4087d26fe66SMilanka Ringwald                     switch (device->protocol_mode){
4097d26fe66SMilanka Ringwald                         case HID_PROTOCOL_MODE_BOOT:
410dbcaefc7SMilanka Ringwald                             if (!btstack_hid_report_id_declared(hid_descriptor_len, hid_descriptor) || packet_size < 2){
411ba9a58feSMilanka Ringwald                                 device->report_status = HID_HANDSHAKE_PARAM_TYPE_ERR_INVALID_PARAMETER;
412ba9a58feSMilanka Ringwald                                 break;
413ba9a58feSMilanka Ringwald                             }
414*a1118d11SMilanka Ringwald                             device->report_id = packet[pos++];
4157d26fe66SMilanka Ringwald                             break;
4167d26fe66SMilanka Ringwald                         case HID_PROTOCOL_MODE_REPORT:
417*a1118d11SMilanka Ringwald                             if (!btstack_hid_report_id_declared(hid_descriptor_len, hid_descriptor)) {
418*a1118d11SMilanka Ringwald                                 printf("id are not in report\n");
419*a1118d11SMilanka Ringwald                                 break;
420*a1118d11SMilanka Ringwald                             }
4217d26fe66SMilanka Ringwald                             if (packet_size < 2){
4227d26fe66SMilanka Ringwald                                 device->report_status = HID_HANDSHAKE_PARAM_TYPE_ERR_INVALID_PARAMETER;
4237d26fe66SMilanka Ringwald                                 break;
4247d26fe66SMilanka Ringwald                             }
425*a1118d11SMilanka Ringwald                             device->report_id = packet[pos++];
426*a1118d11SMilanka Ringwald 
427*a1118d11SMilanka Ringwald                             hid_report_id_status_t report_id_status = hid_report_id_status(device->cid, device->report_id);
428*a1118d11SMilanka Ringwald                             switch (report_id_status){
429*a1118d11SMilanka Ringwald                                 case HID_REPORT_ID_INVALID:
430*a1118d11SMilanka Ringwald                                     printf("id %d invalid\n", device->report_id);
431*a1118d11SMilanka Ringwald                                     device->report_status = HID_HANDSHAKE_PARAM_TYPE_ERR_INVALID_REPORT_ID;
432*a1118d11SMilanka Ringwald                                     break;
433*a1118d11SMilanka Ringwald                                 default:
434*a1118d11SMilanka Ringwald                                     printf("id %d, status %d\n", device->report_id,report_id_status);
4357d26fe66SMilanka Ringwald                                     break;
4367d26fe66SMilanka Ringwald                             }
437*a1118d11SMilanka Ringwald                             break;
4387d26fe66SMilanka Ringwald                     }
439*a1118d11SMilanka Ringwald                     device->expected_report_size = btstack_hid_get_report_size_for_id(device->report_id, device->report_type, hid_descriptor_len, hid_descriptor);
440*a1118d11SMilanka Ringwald                     report_size =  device->expected_report_size + pos; // add 1 for header size and report id
441*a1118d11SMilanka Ringwald 
442*a1118d11SMilanka Ringwald                     printf("report size with header and id %d\n", report_size);
443*a1118d11SMilanka Ringwald                     if ((packet[0] & 0x08) && packet_size >= pos + 1){
444*a1118d11SMilanka Ringwald                         device->report_size = btstack_min(btstack_min(little_endian_read_16(packet, pos), report_size), sizeof(report));
445*a1118d11SMilanka Ringwald                     } else {
446*a1118d11SMilanka Ringwald                         device->report_size = btstack_min(btstack_min(l2cap_max_mtu(), report_size), sizeof(report));
447*a1118d11SMilanka Ringwald                     }
448*a1118d11SMilanka Ringwald                     printf("report size with header and id, after %d\n", device->report_size);
449*a1118d11SMilanka Ringwald 
4507d26fe66SMilanka Ringwald                     hid_device_request_can_send_now_event(channel);
4517d26fe66SMilanka Ringwald                     break;
4527d26fe66SMilanka Ringwald 
4537d26fe66SMilanka Ringwald                 case HID_MESSAGE_TYPE_SET_REPORT:
4547d26fe66SMilanka Ringwald                     device->state = HID_DEVICE_W2_SET_REPORT;
455*a1118d11SMilanka Ringwald                     device->report_size = l2cap_max_mtu();
456a78157ddSMilanka Ringwald                     device->report_type = packet[0] & 0x03;
4577d26fe66SMilanka Ringwald                     if (packet_size < 1){
4587d26fe66SMilanka Ringwald                         device->report_status = HID_HANDSHAKE_PARAM_TYPE_ERR_INVALID_PARAMETER;
4597d26fe66SMilanka Ringwald                         break;
4607d26fe66SMilanka Ringwald                     }
4617d26fe66SMilanka Ringwald 
4627d26fe66SMilanka Ringwald                     switch (device->protocol_mode){
4637d26fe66SMilanka Ringwald                         case HID_PROTOCOL_MODE_BOOT:
464df3cc7a0SMilanka Ringwald                             // printf("HID_PROTOCOL_MODE_BOOT \n");
4657d26fe66SMilanka Ringwald                             if (packet_size < 3){
4667d26fe66SMilanka Ringwald                                 device->report_status = HID_HANDSHAKE_PARAM_TYPE_ERR_INVALID_PARAMETER;
4677d26fe66SMilanka Ringwald                                 break;
4687d26fe66SMilanka Ringwald                             }
4697d26fe66SMilanka Ringwald                             device->report_id = packet[1];
4704dfe6a8bSMilanka Ringwald                             device->report_status = hid_device_set_report_cmd_is_valid(device->cid, device->report_type, packet_size - 1, &packet[1]);
4714dfe6a8bSMilanka Ringwald                             if (device->report_status != HID_HANDSHAKE_PARAM_TYPE_SUCCESSFUL) break;
4724dfe6a8bSMilanka Ringwald                             (*hci_device_set_report)(device->cid, device->report_type, packet_size-1, &packet[1]);
4737d26fe66SMilanka Ringwald                             break;
4747d26fe66SMilanka Ringwald                         case HID_PROTOCOL_MODE_REPORT:
475df3cc7a0SMilanka Ringwald                             // printf("HID_PROTOCOL_MODE_REPORT \n");
4764dfe6a8bSMilanka Ringwald                             device->report_status = hid_device_set_report_cmd_is_valid(device->cid, device->report_type, packet_size - 1, &packet[1]);
4774dfe6a8bSMilanka Ringwald                             if (device->report_status != HID_HANDSHAKE_PARAM_TYPE_SUCCESSFUL) break;
4784dfe6a8bSMilanka Ringwald 
4797d26fe66SMilanka Ringwald                             if (packet_size >= 2){
4804dfe6a8bSMilanka Ringwald                                 (*hci_device_set_report)(device->cid, device->report_type, packet_size-1, &packet[1]);
4817d26fe66SMilanka Ringwald                             } else {
4827d26fe66SMilanka Ringwald                                 uint8_t payload[] = {0};
4834dfe6a8bSMilanka Ringwald                                 (*hci_device_set_report)(device->cid, device->report_type, 1, payload);
4847d26fe66SMilanka Ringwald                             }
4857d26fe66SMilanka Ringwald                             break;
4867d26fe66SMilanka Ringwald                     }
487ba9a58feSMilanka Ringwald                     device->report_type = packet[0] & 0x03;
4887d26fe66SMilanka Ringwald                     hid_device_request_can_send_now_event(channel);
4897d26fe66SMilanka Ringwald                     // l2cap_request_can_send_now_event(device->control_cid);
490ba9a58feSMilanka Ringwald                     break;
491ba9a58feSMilanka Ringwald                 case HID_MESSAGE_TYPE_GET_PROTOCOL:
492df3cc7a0SMilanka Ringwald                     // printf(" HID_MESSAGE_TYPE_GET_PROTOCOL\n");
493ba9a58feSMilanka Ringwald                     device->state = HID_DEVICE_W2_GET_PROTOCOL;
494ba9a58feSMilanka Ringwald                     if (packet_size != 1) {
495ba9a58feSMilanka Ringwald                         device->report_status = HID_HANDSHAKE_PARAM_TYPE_ERR_INVALID_PARAMETER;
496ba9a58feSMilanka Ringwald                         break;
497ba9a58feSMilanka Ringwald                     }
498ba9a58feSMilanka Ringwald                     device->report_status = HID_HANDSHAKE_PARAM_TYPE_SUCCESSFUL;
499df3cc7a0SMilanka Ringwald                     // hid_device_request_can_send_now_event(channel);
500df3cc7a0SMilanka Ringwald                     // printf("HID_MESSAGE_TYPE_GET_PROTOCOL l2cap_request_can_send_now_event\n");
501df3cc7a0SMilanka Ringwald                     l2cap_request_can_send_now_event(device->control_cid);
5027d26fe66SMilanka Ringwald                     break;
503ba9a58feSMilanka Ringwald 
504ba9a58feSMilanka Ringwald                 case HID_MESSAGE_TYPE_SET_PROTOCOL:
505ba9a58feSMilanka Ringwald                     device->state = HID_DEVICE_W2_SET_PROTOCOL;
506ba9a58feSMilanka Ringwald                     if (packet_size != 1) {
507ba9a58feSMilanka Ringwald                         device->report_status = HID_HANDSHAKE_PARAM_TYPE_ERR_INVALID_PARAMETER;
508ba9a58feSMilanka Ringwald                         break;
509ba9a58feSMilanka Ringwald                     }
510ba9a58feSMilanka Ringwald                     param = packet[0] & 0x01;
511ba9a58feSMilanka Ringwald                     if (param == HID_PROTOCOL_MODE_BOOT && !hid_boot_protocol_mode_supported){
512ba9a58feSMilanka Ringwald                         device->report_status = HID_HANDSHAKE_PARAM_TYPE_ERR_INVALID_PARAMETER;
513ba9a58feSMilanka Ringwald                         break;
514ba9a58feSMilanka Ringwald                     }
515ba9a58feSMilanka Ringwald                     device->protocol_mode = param;
5167d26fe66SMilanka Ringwald                     switch (device->protocol_mode){
5177d26fe66SMilanka Ringwald                         case HID_PROTOCOL_MODE_BOOT:
518df3cc7a0SMilanka Ringwald                             // printf("Set protocol mode to BOOT\n");
519ba9a58feSMilanka Ringwald                             break;
5207d26fe66SMilanka Ringwald                         case HID_PROTOCOL_MODE_REPORT:
521df3cc7a0SMilanka Ringwald                             // printf("Set protocol mode to REPORT\n");
5227d26fe66SMilanka Ringwald                             break;
5237d26fe66SMilanka Ringwald                     }
5247d26fe66SMilanka Ringwald                     device->report_status = HID_HANDSHAKE_PARAM_TYPE_SUCCESSFUL;
5257d26fe66SMilanka Ringwald                     hid_device_request_can_send_now_event(channel);
5267d26fe66SMilanka Ringwald                     break;
5277d26fe66SMilanka Ringwald 
5286510739bSMilanka Ringwald                 case HID_MESSAGE_TYPE_HID_CONTROL:
5296510739bSMilanka Ringwald                     param = packet[0] & 0x0F;
5306510739bSMilanka Ringwald                     switch (param){
5316510739bSMilanka Ringwald                         case HID_CONTROL_PARAM_SUSPEND:
5326510739bSMilanka Ringwald                             hid_device_emit_event(device, HID_SUBEVENT_SUSPEND);
5336510739bSMilanka Ringwald                             break;
5346510739bSMilanka Ringwald                         case HID_CONTROL_PARAM_EXIT_SUSPEND:
5356510739bSMilanka Ringwald                             hid_device_emit_event(device, HID_SUBEVENT_EXIT_SUSPEND);
5366510739bSMilanka Ringwald                             break;
5376510739bSMilanka Ringwald                         default:
5386510739bSMilanka Ringwald                             device->state = HID_DEVICE_W2_SEND_UNSUPPORTED_REQUEST;
5397d26fe66SMilanka Ringwald                             hid_device_request_can_send_now_event(channel);
5407d26fe66SMilanka Ringwald                             // l2cap_request_can_send_now_event(device->control_cid);
5416510739bSMilanka Ringwald                             break;
5426510739bSMilanka Ringwald                     }
5436510739bSMilanka Ringwald                     break;
5447d26fe66SMilanka Ringwald 
5457d26fe66SMilanka Ringwald                 case HID_MESSAGE_TYPE_DATA:
5467d26fe66SMilanka Ringwald                     if (packet_size < 2) {
5477d26fe66SMilanka Ringwald                         break;
5487d26fe66SMilanka Ringwald                     }
5497d26fe66SMilanka Ringwald                     device->report_type = packet[0] & 0x03;
5507d26fe66SMilanka Ringwald                     device->report_id = packet[1];
551738c9391SMilanka Ringwald 
552738c9391SMilanka Ringwald                     if (hid_report_id_status(device->cid, device->report_id) == HID_REPORT_ID_INVALID ||
553738c9391SMilanka Ringwald                         !hid_report_size_valid(device->cid, device->report_id, device->report_type, packet_size - 2)){
554738c9391SMilanka Ringwald                         log_info("Ignore report data packet\n");
555738c9391SMilanka Ringwald                         return;
556738c9391SMilanka Ringwald                     }
5577d26fe66SMilanka Ringwald                     (*hci_device_report_data)(device->cid, device->report_type, device->report_id, packet_size - 2, &packet[2]);
5587d26fe66SMilanka Ringwald                     break;
559c12110e4SMilanka Ringwald                 default:
5605139b81eSMilanka Ringwald                     // printf("HID_DEVICE_W2_SEND_UNSUPPORTED_REQUEST %d  \n", message_type);
561c12110e4SMilanka Ringwald                     device->state = HID_DEVICE_W2_SEND_UNSUPPORTED_REQUEST;
5627d26fe66SMilanka Ringwald                     // l2cap_request_can_send_now_event(device->control_cid);
5637d26fe66SMilanka Ringwald                     hid_device_request_can_send_now_event(channel);
564c12110e4SMilanka Ringwald                     break;
565c12110e4SMilanka Ringwald             }
566c12110e4SMilanka Ringwald             break;
5678eb8d463SMatthias Ringwald         case HCI_EVENT_PACKET:
5688eb8d463SMatthias Ringwald             switch (packet[0]){
5698eb8d463SMatthias Ringwald                 case L2CAP_EVENT_INCOMING_CONNECTION:
5708eb8d463SMatthias Ringwald                     switch (l2cap_event_incoming_connection_get_psm(packet)){
5718eb8d463SMatthias Ringwald                         case PSM_HID_CONTROL:
5728eb8d463SMatthias Ringwald                         case PSM_HID_INTERRUPT:
5736510739bSMilanka Ringwald                             l2cap_event_incoming_connection_get_address(packet, address);
574ba9a58feSMilanka Ringwald                             device = hid_device_provide_instance_for_bt_addr(address);
575c12110e4SMilanka Ringwald                             if (!device) {
576c12110e4SMilanka Ringwald                                 log_error("L2CAP_EVENT_INCOMING_CONNECTION, no hid device for con handle 0x%02x", l2cap_event_incoming_connection_get_handle(packet));
577c12110e4SMilanka Ringwald                                 l2cap_decline_connection(channel);
578c12110e4SMilanka Ringwald                                 break;
579c12110e4SMilanka Ringwald                             }
580c12110e4SMilanka Ringwald                             if (device->con_handle == 0 || l2cap_event_incoming_connection_get_handle(packet) == device->con_handle){
581c12110e4SMilanka Ringwald                                 device->con_handle = l2cap_event_incoming_connection_get_handle(packet);
582c12110e4SMilanka Ringwald                                 device->incoming = 1;
5836510739bSMilanka Ringwald                                 l2cap_event_incoming_connection_get_address(packet, device->bd_addr);
5848eb8d463SMatthias Ringwald                                 l2cap_accept_connection(channel);
5858eb8d463SMatthias Ringwald                             } else {
5868eb8d463SMatthias Ringwald                                 l2cap_decline_connection(channel);
587c12110e4SMilanka Ringwald                                 log_error("L2CAP_EVENT_INCOMING_CONNECTION, decline connection for con handle 0x%02x", l2cap_event_incoming_connection_get_handle(packet));
5888eb8d463SMatthias Ringwald                             }
5898eb8d463SMatthias Ringwald                             break;
5908eb8d463SMatthias Ringwald                         default:
5918eb8d463SMatthias Ringwald                             l2cap_decline_connection(channel);
5928eb8d463SMatthias Ringwald                             break;
5938eb8d463SMatthias Ringwald                     }
5948eb8d463SMatthias Ringwald                     break;
5958eb8d463SMatthias Ringwald                 case L2CAP_EVENT_CHANNEL_OPENED:
596c12110e4SMilanka Ringwald                     device = hid_device_get_instance_for_con_handle(l2cap_event_channel_opened_get_handle(packet));
597c12110e4SMilanka Ringwald                     if (!device) {
598c12110e4SMilanka Ringwald                         log_error("L2CAP_EVENT_CHANNEL_OPENED, no hid device for local cid 0x%02x", l2cap_event_channel_opened_get_local_cid(packet));
599c12110e4SMilanka Ringwald                         return;
600c12110e4SMilanka Ringwald                     }
60157c643eeSMatthias Ringwald                     status = l2cap_event_channel_opened_get_status(packet);
60257c643eeSMatthias Ringwald                     if (status) {
603c12110e4SMilanka Ringwald                         if (device->incoming == 0){
60457c643eeSMatthias Ringwald                             // report error for outgoing connection
605c12110e4SMilanka Ringwald                             hid_device_emit_connected_event(device, status);
60657c643eeSMatthias Ringwald                         }
60757c643eeSMatthias Ringwald                         return;
60857c643eeSMatthias Ringwald                     }
60957c643eeSMatthias Ringwald                     psm = l2cap_event_channel_opened_get_psm(packet);
610c12110e4SMilanka Ringwald                     connected_before = device->connected;
61157c643eeSMatthias Ringwald                     switch (psm){
6128eb8d463SMatthias Ringwald                         case PSM_HID_CONTROL:
613c12110e4SMilanka Ringwald                             device->control_cid = l2cap_event_channel_opened_get_local_cid(packet);
614df3cc7a0SMilanka Ringwald                             // printf("HID Control opened, cid 0x%02x\n", device->control_cid);
6158eb8d463SMatthias Ringwald                             break;
6168eb8d463SMatthias Ringwald                         case PSM_HID_INTERRUPT:
617c12110e4SMilanka Ringwald                             device->interrupt_cid = l2cap_event_channel_opened_get_local_cid(packet);
618df3cc7a0SMilanka Ringwald                             // printf("HID Interrupt opened, cid 0x%02x\n", device->interrupt_cid);
6198eb8d463SMatthias Ringwald                             break;
6208eb8d463SMatthias Ringwald                         default:
6218eb8d463SMatthias Ringwald                             break;
6228eb8d463SMatthias Ringwald                     }
6236510739bSMilanka Ringwald 
62457c643eeSMatthias Ringwald                     // connect HID Interrupt for outgoing
625c12110e4SMilanka Ringwald                     if (device->incoming == 0 && psm == PSM_HID_CONTROL){
626df3cc7a0SMilanka Ringwald                         // printf("Create outgoing HID Interrupt\n");
627c12110e4SMilanka Ringwald                         status = l2cap_create_channel(packet_handler, device->bd_addr, PSM_HID_INTERRUPT, 48, &device->interrupt_cid);
62857c643eeSMatthias Ringwald                         break;
62957c643eeSMatthias Ringwald                     }
630c12110e4SMilanka Ringwald                     if (!connected_before && device->control_cid && device->interrupt_cid){
631c12110e4SMilanka Ringwald                         device->connected = 1;
632df3cc7a0SMilanka Ringwald                         // printf("HID Connected\n");
633c12110e4SMilanka Ringwald                         hid_device_emit_connected_event(device, 0);
6348eb8d463SMatthias Ringwald                     }
6358eb8d463SMatthias Ringwald                     break;
6368eb8d463SMatthias Ringwald                 case L2CAP_EVENT_CHANNEL_CLOSED:
637c12110e4SMilanka Ringwald                     device = hid_device_get_instance_for_cid(l2cap_event_channel_closed_get_local_cid(packet));
638c12110e4SMilanka Ringwald                     if (!device) return;
639c12110e4SMilanka Ringwald 
6406510739bSMilanka Ringwald                     // connected_before = device->connected;
641c12110e4SMilanka Ringwald                     device->incoming  = 0;
642c12110e4SMilanka Ringwald                     if (l2cap_event_channel_closed_get_local_cid(packet) == device->interrupt_cid){
643df3cc7a0SMilanka Ringwald                         // printf("HID Interrupt closed\n");
644c12110e4SMilanka Ringwald                         device->interrupt_cid = 0;
64557c18996SMilanka Ringwald                     }
64657c18996SMilanka Ringwald                     if (l2cap_event_channel_closed_get_local_cid(packet) == device->control_cid){
647df3cc7a0SMilanka Ringwald                         // printf("HID Control closed\n");
64857c18996SMilanka Ringwald                         device->control_cid = 0;
6498eb8d463SMatthias Ringwald                     }
6506510739bSMilanka Ringwald                     if (!device->interrupt_cid && !device->control_cid){
6516510739bSMilanka Ringwald                         device->connected = 0;
652c12110e4SMilanka Ringwald                         device->con_handle = 0;
6536510739bSMilanka Ringwald                         device->cid = 0;
654df3cc7a0SMilanka Ringwald                         // printf("HID Disconnected\n");
655c12110e4SMilanka Ringwald                         hid_device_emit_connection_closed_event(device);
6568eb8d463SMatthias Ringwald                     }
6578eb8d463SMatthias Ringwald                     break;
658c12110e4SMilanka Ringwald 
65957c18996SMilanka Ringwald                 case L2CAP_EVENT_CAN_SEND_NOW:
6607d26fe66SMilanka Ringwald                     local_cid = l2cap_event_can_send_now_get_local_cid(packet);
661c12110e4SMilanka Ringwald                     device = hid_device_get_instance_for_cid(l2cap_event_can_send_now_get_local_cid(packet));
6627d26fe66SMilanka Ringwald 
663c12110e4SMilanka Ringwald                     if (!device) return;
664c12110e4SMilanka Ringwald                     switch (device->state){
665*a1118d11SMilanka Ringwald                         case HID_DEVICE_W2_GET_REPORT:{
666*a1118d11SMilanka Ringwald                             printf("HID_DEVICE_W2_GET_REPORT. on entry device->report_status %d \n", device->report_status);
6677d26fe66SMilanka Ringwald                             if (device->report_status != HID_HANDSHAKE_PARAM_TYPE_SUCCESSFUL) {
6687d26fe66SMilanka Ringwald                                 report[0] = (HID_MESSAGE_TYPE_HANDSHAKE << 4) | device->report_status;
6697d26fe66SMilanka Ringwald                                 hid_device_send_control_message(device->cid, &report[0], 1);
6707d26fe66SMilanka Ringwald                                 break;
6717d26fe66SMilanka Ringwald                             }
672*a1118d11SMilanka Ringwald 
673*a1118d11SMilanka Ringwald                             pos = 0;
674*a1118d11SMilanka Ringwald                             report[pos++] = (HID_MESSAGE_TYPE_DATA << 4) | device->report_type;
675*a1118d11SMilanka Ringwald                             if (device->report_id){
676*a1118d11SMilanka Ringwald                                 report[pos++] = device->report_id;
677*a1118d11SMilanka Ringwald                             }
678*a1118d11SMilanka Ringwald                             printf(" report size with header and id %d\n", pos);
679*a1118d11SMilanka Ringwald 
6807d26fe66SMilanka Ringwald                             report_size = 0;
681*a1118d11SMilanka Ringwald                             status = (*hci_device_get_report)(device->cid, device->report_type, device->report_id, &report_size, &report[pos]);
682*a1118d11SMilanka Ringwald                             printf(" report size %d, status after callback %d, expected report_size %d\n", report_size + pos, status, device->report_size);
683481c7cdcSMilanka Ringwald 
684*a1118d11SMilanka Ringwald                             switch (status){
685*a1118d11SMilanka Ringwald                                 case 0:
686*a1118d11SMilanka Ringwald                                     device->report_status = HID_HANDSHAKE_PARAM_TYPE_NOT_READY;
687*a1118d11SMilanka Ringwald                                     break;
688*a1118d11SMilanka Ringwald                                 case 1:
689*a1118d11SMilanka Ringwald                                     if (report_size == 0){
690*a1118d11SMilanka Ringwald                                         device->report_status = HID_HANDSHAKE_PARAM_TYPE_ERR_UNSUPPORTED_REQUEST;
691*a1118d11SMilanka Ringwald                                         break;
692*a1118d11SMilanka Ringwald                                     }
693*a1118d11SMilanka Ringwald                                     if (device->expected_report_size != report_size){
694*a1118d11SMilanka Ringwald                                         log_error("Expected report size of %d bytes, received %d", device->expected_report_size, report_size);
695*a1118d11SMilanka Ringwald                                         device->report_status = HID_HANDSHAKE_PARAM_TYPE_ERR_UNSUPPORTED_REQUEST;
696*a1118d11SMilanka Ringwald                                         break;
697*a1118d11SMilanka Ringwald                                     }
698*a1118d11SMilanka Ringwald                                     break;
699*a1118d11SMilanka Ringwald                                 default:
700*a1118d11SMilanka Ringwald                                     device->report_status = HID_HANDSHAKE_PARAM_TYPE_ERR_UNSUPPORTED_REQUEST;
701*a1118d11SMilanka Ringwald                                     break;
702*a1118d11SMilanka Ringwald                             }
703ba9a58feSMilanka Ringwald                             if (device->report_status != HID_HANDSHAKE_PARAM_TYPE_SUCCESSFUL){
704ba9a58feSMilanka Ringwald                                 report[0] = (HID_MESSAGE_TYPE_HANDSHAKE << 4) | device->report_status;
705481c7cdcSMilanka Ringwald                                 hid_device_send_control_message(device->cid, &report[0], 1);
706481c7cdcSMilanka Ringwald                                 break;
707481c7cdcSMilanka Ringwald                             }
708481c7cdcSMilanka Ringwald 
709*a1118d11SMilanka Ringwald                             // if (report_size > l2cap_max_mtu()){
710*a1118d11SMilanka Ringwald                             //     report[0] = (HID_MESSAGE_TYPE_HANDSHAKE << 4) | HID_HANDSHAKE_PARAM_TYPE_ERR_INVALID_PARAMETER;
711*a1118d11SMilanka Ringwald                             //     hid_device_send_control_message(device->cid, &report[0], 1);
712*a1118d11SMilanka Ringwald                             //     break;
713*a1118d11SMilanka Ringwald                             // }
714481c7cdcSMilanka Ringwald 
715*a1118d11SMilanka Ringwald                             // printf("report type %d, report_size %d, report_size %d \n", device->report_type, report_size, device->report_size);
716*a1118d11SMilanka Ringwald                             hid_device_send_control_message(device->cid, &report[0], device->report_size);
717481c7cdcSMilanka Ringwald                             //     device->state = HID_DEVICE_IDLE;
718c12110e4SMilanka Ringwald                             break;
719*a1118d11SMilanka Ringwald                         }
720ba9a58feSMilanka Ringwald                         case HID_DEVICE_W2_SET_REPORT:
721ba9a58feSMilanka Ringwald                         case HID_DEVICE_W2_SET_PROTOCOL:
722ba9a58feSMilanka Ringwald                             report[0] = (HID_MESSAGE_TYPE_HANDSHAKE << 4) | device->report_status;
7236510739bSMilanka Ringwald                             hid_device_send_control_message(device->cid, &report[0], 1);
724ba9a58feSMilanka Ringwald                             break;
725ba9a58feSMilanka Ringwald                         case HID_DEVICE_W2_GET_PROTOCOL:
726ba9a58feSMilanka Ringwald                             if (device->report_status != HID_HANDSHAKE_PARAM_TYPE_SUCCESSFUL){
727df3cc7a0SMilanka Ringwald                                 // printf("send HID_MESSAGE_TYPE_HANDSHAKE, report_status %d \n", device->report_status);
728ba9a58feSMilanka Ringwald                                 report[0] = (HID_MESSAGE_TYPE_HANDSHAKE << 4) | device->report_status;
729ba9a58feSMilanka Ringwald                                 hid_device_send_control_message(device->cid, &report[0], 1);
730ba9a58feSMilanka Ringwald                                 break;
731ba9a58feSMilanka Ringwald                             }
7325139b81eSMilanka Ringwald 
733df3cc7a0SMilanka Ringwald                             // printf("send HID_MESSAGE_TYPE_DATA, protocol_mode %d \n", device->protocol_mode);
7345139b81eSMilanka Ringwald                             report[0] = (HID_MESSAGE_TYPE_DATA << 4);
7355139b81eSMilanka Ringwald                             report[1] =  device->protocol_mode;
7365139b81eSMilanka Ringwald                             hid_device_send_control_message(device->cid, &report[0], 2);
737ba9a58feSMilanka Ringwald                             break;
738ba9a58feSMilanka Ringwald 
739ba9a58feSMilanka Ringwald 
740ba9a58feSMilanka Ringwald                         case HID_DEVICE_W2_SEND_UNSUPPORTED_REQUEST:
741ba9a58feSMilanka Ringwald                             report[0] = (HID_MESSAGE_TYPE_HANDSHAKE << 4) | HID_HANDSHAKE_PARAM_TYPE_ERR_UNSUPPORTED_REQUEST;
742ba9a58feSMilanka Ringwald                             hid_device_send_control_message(device->cid, &report[0], 1);
743c12110e4SMilanka Ringwald                             break;
744c12110e4SMilanka Ringwald                         default:
7458eb8d463SMatthias Ringwald                             log_info("HID Can send now, emit event");
746c12110e4SMilanka Ringwald                             hid_device_emit_can_send_now_event(device);
747ba9a58feSMilanka Ringwald                             // device->state = HID_DEVICE_IDLE;
748c12110e4SMilanka Ringwald                             break;
749c12110e4SMilanka Ringwald                     }
750ba9a58feSMilanka Ringwald                     device->state = HID_DEVICE_IDLE;
7518eb8d463SMatthias Ringwald                     break;
7528eb8d463SMatthias Ringwald                 default:
7538eb8d463SMatthias Ringwald                     break;
7548eb8d463SMatthias Ringwald             }
7558eb8d463SMatthias Ringwald             break;
7568eb8d463SMatthias Ringwald         default:
7578eb8d463SMatthias Ringwald             break;
7588eb8d463SMatthias Ringwald     }
7598eb8d463SMatthias Ringwald }
7608eb8d463SMatthias Ringwald 
7618eb8d463SMatthias Ringwald /**
7628eb8d463SMatthias Ringwald  * @brief Set up HID Device
7638eb8d463SMatthias Ringwald  */
764662cddc2SMilanka Ringwald void hid_device_init(uint8_t boot_protocol_mode_supported, uint16_t descriptor_len, const uint8_t * descriptor){
765ba9a58feSMilanka Ringwald     hid_boot_protocol_mode_supported = boot_protocol_mode_supported;
766662cddc2SMilanka Ringwald     hid_descriptor =  descriptor;
767662cddc2SMilanka Ringwald     hid_descriptor_len = descriptor_len;
768*a1118d11SMilanka Ringwald     hci_device_get_report = dummy_write_report;
769*a1118d11SMilanka Ringwald     hci_device_set_report = dummy_set_report;
770*a1118d11SMilanka Ringwald     hci_device_report_data = dummy_report_data;
771*a1118d11SMilanka Ringwald 
77245a58b30SMatthias Ringwald     l2cap_register_service(packet_handler, PSM_HID_INTERRUPT, 100, LEVEL_2);
77345a58b30SMatthias Ringwald     l2cap_register_service(packet_handler, PSM_HID_CONTROL,   100, LEVEL_2);
7748eb8d463SMatthias Ringwald }
7758eb8d463SMatthias Ringwald 
7768eb8d463SMatthias Ringwald /**
7778eb8d463SMatthias Ringwald  * @brief Register callback for the HID Device client.
7788eb8d463SMatthias Ringwald  * @param callback
7798eb8d463SMatthias Ringwald  */
7808eb8d463SMatthias Ringwald void hid_device_register_packet_handler(btstack_packet_handler_t callback){
7818eb8d463SMatthias Ringwald     hid_callback = callback;
7828eb8d463SMatthias Ringwald }
7838eb8d463SMatthias Ringwald 
784c12110e4SMilanka Ringwald 
785c12110e4SMilanka Ringwald 
786*a1118d11SMilanka Ringwald void hid_device_register_report_request_callback(int (*callback)(uint16_t hid_cid, hid_report_type_t report_type, uint16_t report_id, int * out_report_size, uint8_t * out_report)){
787c12110e4SMilanka Ringwald     if (callback == NULL){
788c12110e4SMilanka Ringwald         callback = dummy_write_report;
789c12110e4SMilanka Ringwald     }
790*a1118d11SMilanka Ringwald     hci_device_get_report = callback;
791c12110e4SMilanka Ringwald }
792c12110e4SMilanka Ringwald 
7934dfe6a8bSMilanka Ringwald void hid_device_register_set_report_callback(void (*callback)(uint16_t hid_cid, hid_report_type_t report_type, int report_size, uint8_t * report)){
794ba9a58feSMilanka Ringwald     if (callback == NULL){
795ba9a58feSMilanka Ringwald         callback = dummy_set_report;
796ba9a58feSMilanka Ringwald     }
797ba9a58feSMilanka Ringwald     hci_device_set_report = callback;
798ba9a58feSMilanka Ringwald }
799c12110e4SMilanka Ringwald 
8007d26fe66SMilanka Ringwald void hid_device_register_report_data_callback(void (*callback)(uint16_t cid, hid_report_type_t report_type, uint16_t report_id, int report_size, uint8_t * report)){
8017d26fe66SMilanka Ringwald     if (callback == NULL){
8027d26fe66SMilanka Ringwald         callback = dummy_report_data;
8037d26fe66SMilanka Ringwald     }
8047d26fe66SMilanka Ringwald     hci_device_report_data = callback;
8057d26fe66SMilanka Ringwald }
8067d26fe66SMilanka Ringwald 
8077d26fe66SMilanka Ringwald 
8088eb8d463SMatthias Ringwald /**
8098eb8d463SMatthias Ringwald  * @brief Request can send now event to send HID Report
8108eb8d463SMatthias Ringwald  * @param hid_cid
8118eb8d463SMatthias Ringwald  */
8128eb8d463SMatthias Ringwald void hid_device_request_can_send_now_event(uint16_t hid_cid){
813c12110e4SMilanka Ringwald     hid_device_t * hid_device = hid_device_get_instance_for_cid(hid_cid);
8147d26fe66SMilanka Ringwald     if (!hid_device || !hid_device->control_cid){
8157d26fe66SMilanka Ringwald          hid_device->state = HID_DEVICE_IDLE;
8167d26fe66SMilanka Ringwald          return;
8177d26fe66SMilanka Ringwald     }
8188eb8d463SMatthias Ringwald     l2cap_request_can_send_now_event(hid_device->control_cid);
8198eb8d463SMatthias Ringwald }
8208eb8d463SMatthias Ringwald 
8218eb8d463SMatthias Ringwald /**
8228eb8d463SMatthias Ringwald  * @brief Send HID messageon interrupt channel
8238eb8d463SMatthias Ringwald  * @param hid_cid
8248eb8d463SMatthias Ringwald  */
8258eb8d463SMatthias Ringwald void hid_device_send_interrupt_message(uint16_t hid_cid, const uint8_t * message, uint16_t message_len){
826c12110e4SMilanka Ringwald     hid_device_t * hid_device = hid_device_get_instance_for_cid(hid_cid);
827c12110e4SMilanka Ringwald     if (!hid_device || !hid_device->interrupt_cid) return;
8288eb8d463SMatthias Ringwald     l2cap_send(hid_device->interrupt_cid, (uint8_t*) message, message_len);
8298eb8d463SMatthias Ringwald }
8308eb8d463SMatthias Ringwald 
8318eb8d463SMatthias Ringwald /**
8328eb8d463SMatthias Ringwald  * @brief Send HID messageon control channel
8338eb8d463SMatthias Ringwald  * @param hid_cid
8348eb8d463SMatthias Ringwald  */
835c12110e4SMilanka Ringwald void hid_device_send_control_message(uint16_t hid_cid, const uint8_t * message, uint16_t message_len){
836c12110e4SMilanka Ringwald     hid_device_t * hid_device = hid_device_get_instance_for_cid(hid_cid);
837c12110e4SMilanka Ringwald     if (!hid_device || !hid_device->control_cid) return;
8388eb8d463SMatthias Ringwald     l2cap_send(hid_device->control_cid, (uint8_t*) message, message_len);
8398eb8d463SMatthias Ringwald }
8408eb8d463SMatthias Ringwald 
84157c643eeSMatthias Ringwald /*
84257c643eeSMatthias Ringwald  * @brief Create HID connection to HID Host
84357c643eeSMatthias Ringwald  * @param addr
84457c643eeSMatthias Ringwald  * @param hid_cid to use for other commands
84557c643eeSMatthias Ringwald  * @result status
84657c643eeSMatthias Ringwald  */
84757c643eeSMatthias Ringwald uint8_t hid_device_connect(bd_addr_t addr, uint16_t * hid_cid){
848c12110e4SMilanka Ringwald     hid_device_t * hid_device = hid_device_create_instance();
849c12110e4SMilanka Ringwald     if (!hid_device){
850c12110e4SMilanka Ringwald         log_error("hid_device_connect: could not create a hid device instace");
851c12110e4SMilanka Ringwald         return BTSTACK_MEMORY_ALLOC_FAILED;
852c12110e4SMilanka Ringwald     }
85357c643eeSMatthias Ringwald     // assign hic_cid
854c12110e4SMilanka Ringwald     *hid_cid = hid_device_get_next_cid();
85557c643eeSMatthias Ringwald     // store address
85657c643eeSMatthias Ringwald     memcpy(hid_device->bd_addr, addr, 6);
85757c643eeSMatthias Ringwald 
85857c643eeSMatthias Ringwald     // reset state
8596510739bSMilanka Ringwald     hid_device->cid           = *hid_cid;
86057c643eeSMatthias Ringwald     hid_device->incoming      = 0;
86157c643eeSMatthias Ringwald     hid_device->connected     = 0;
86257c643eeSMatthias Ringwald     hid_device->control_cid   = 0;
86357c643eeSMatthias Ringwald     hid_device->interrupt_cid = 0;
86457c643eeSMatthias Ringwald     // create l2cap control using fixed HID L2CAP PSM
86557c643eeSMatthias Ringwald     log_info("Create outgoing HID Control");
86657c643eeSMatthias Ringwald     uint8_t status = l2cap_create_channel(packet_handler, hid_device->bd_addr, PSM_HID_CONTROL, 48, &hid_device->control_cid);
86757c643eeSMatthias Ringwald     return status;
86857c643eeSMatthias Ringwald }
8696510739bSMilanka Ringwald 
8706510739bSMilanka Ringwald /*
8716510739bSMilanka Ringwald  * @brief Disconnect from HID Host
8726510739bSMilanka Ringwald  * @param hid_cid
8736510739bSMilanka Ringwald  * @result status
8746510739bSMilanka Ringwald  */
87557c18996SMilanka Ringwald void hid_device_disconnect_interrupt_channel(uint16_t hid_cid){
87657c18996SMilanka Ringwald     hid_device_t * hid_device = hid_device_get_instance_for_cid(hid_cid);
87757c18996SMilanka Ringwald     if (!hid_device){
87857c18996SMilanka Ringwald         log_error("hid_device_disconnect_interrupt_channel: could not find hid device instace");
87957c18996SMilanka Ringwald         return;
88057c18996SMilanka Ringwald     }
88157c18996SMilanka Ringwald     log_info("Disconnect from interrupt channel HID Host");
88257c18996SMilanka Ringwald     if (hid_device->interrupt_cid){
88357c18996SMilanka Ringwald         l2cap_disconnect(hid_device->interrupt_cid, 0);  // reason isn't used
88457c18996SMilanka Ringwald     }
88557c18996SMilanka Ringwald }
88657c18996SMilanka Ringwald 
88757c18996SMilanka Ringwald void hid_device_disconnect_control_channel(uint16_t hid_cid){
88857c18996SMilanka Ringwald     hid_device_t * hid_device = hid_device_get_instance_for_cid(hid_cid);
88957c18996SMilanka Ringwald     if (!hid_device){
89057c18996SMilanka Ringwald         log_error("hid_device_disconnect_control_channel: could not find hid device instace");
89157c18996SMilanka Ringwald         return;
89257c18996SMilanka Ringwald     }
89357c18996SMilanka Ringwald     log_info("Disconnect from control channel HID Host");
89457c18996SMilanka Ringwald     if (hid_device->control_cid){
89557c18996SMilanka Ringwald         l2cap_disconnect(hid_device->control_cid, 0);  // reason isn't used
89657c18996SMilanka Ringwald     }
89757c18996SMilanka Ringwald }
89857c18996SMilanka Ringwald 
8996510739bSMilanka Ringwald void hid_device_disconnect(uint16_t hid_cid){
9006510739bSMilanka Ringwald     hid_device_t * hid_device = hid_device_get_instance_for_cid(hid_cid);
9016510739bSMilanka Ringwald     if (!hid_device){
9026510739bSMilanka Ringwald         log_error("hid_device_disconnect: could not find hid device instace");
9036510739bSMilanka Ringwald         return;
9046510739bSMilanka Ringwald     }
9056510739bSMilanka Ringwald     log_info("Disconnect from HID Host");
9066510739bSMilanka Ringwald     if (hid_device->interrupt_cid){
9076510739bSMilanka Ringwald         l2cap_disconnect(hid_device->interrupt_cid, 0);  // reason isn't used
9086510739bSMilanka Ringwald     }
90957c18996SMilanka Ringwald     if (hid_device->control_cid){
91057c18996SMilanka Ringwald         l2cap_disconnect(hid_device->control_cid, 0); // reason isn't used
91157c18996SMilanka Ringwald     }
9126510739bSMilanka Ringwald }
9137d26fe66SMilanka Ringwald 
9147d26fe66SMilanka Ringwald int hid_device_in_boot_protocol_mode(uint16_t hid_cid){
9157d26fe66SMilanka Ringwald     hid_device_t * hid_device = hid_device_get_instance_for_cid(hid_cid);
9167d26fe66SMilanka Ringwald     if (!hid_device){
9177d26fe66SMilanka Ringwald         log_error("hid_device_in_boot_protocol_mode: could not find hid device instace");
9187d26fe66SMilanka Ringwald         return 0;
9197d26fe66SMilanka Ringwald     }
9207d26fe66SMilanka Ringwald     return hid_device->protocol_mode == HID_PROTOCOL_MODE_BOOT;
9217d26fe66SMilanka Ringwald }
922662cddc2SMilanka Ringwald 
923662cddc2SMilanka Ringwald 
924662cddc2SMilanka Ringwald int hid_report_size_valid(uint16_t cid, int report_id, hid_report_type_t report_type, int report_size){
925662cddc2SMilanka Ringwald     // printf("report size %d, report type %d, report id %d\n", report_size, report_type, report_id);
926662cddc2SMilanka Ringwald     if (!report_size) return 0;
927662cddc2SMilanka Ringwald     if (hid_device_in_boot_protocol_mode(cid)){
928662cddc2SMilanka Ringwald         switch (report_id){
929662cddc2SMilanka Ringwald             case HID_BOOT_MODE_KEYBOARD_ID:
930662cddc2SMilanka Ringwald                 if (report_size < 8) return 0;
931662cddc2SMilanka Ringwald                 break;
932662cddc2SMilanka Ringwald             case HID_BOOT_MODE_MOUSE_ID:
933662cddc2SMilanka Ringwald                 if (report_size < 1) return 0;
934662cddc2SMilanka Ringwald                 break;
935662cddc2SMilanka Ringwald             default:
936662cddc2SMilanka Ringwald                 return 0;
937662cddc2SMilanka Ringwald         }
938662cddc2SMilanka Ringwald     } else {
939662cddc2SMilanka Ringwald         int size =  btstack_hid_get_report_size_for_id(report_id, report_type, hid_descriptor_len, hid_descriptor);
940662cddc2SMilanka Ringwald         if (size == 0 || size != report_size) return 0;
941662cddc2SMilanka Ringwald     }
942662cddc2SMilanka Ringwald     return 1;
943662cddc2SMilanka Ringwald }
944dbcaefc7SMilanka Ringwald 
945dbcaefc7SMilanka Ringwald 
946dbcaefc7SMilanka Ringwald hid_report_id_status_t hid_report_id_status(uint16_t cid, uint16_t report_id){
947dbcaefc7SMilanka Ringwald     if (hid_device_in_boot_protocol_mode(cid)){
948dbcaefc7SMilanka Ringwald         switch (report_id){
949dbcaefc7SMilanka Ringwald             case HID_BOOT_MODE_KEYBOARD_ID:
950dbcaefc7SMilanka Ringwald             case HID_BOOT_MODE_MOUSE_ID:
951dbcaefc7SMilanka Ringwald                 return HID_REPORT_ID_VALID;
952dbcaefc7SMilanka Ringwald             default:
953dbcaefc7SMilanka Ringwald                 return HID_REPORT_ID_INVALID;
954dbcaefc7SMilanka Ringwald         }
955dbcaefc7SMilanka Ringwald     } else {
956dbcaefc7SMilanka Ringwald         return btstack_hid_id_valid(report_id, hid_descriptor_len, hid_descriptor);
957dbcaefc7SMilanka Ringwald     }
958dbcaefc7SMilanka Ringwald }