xref: /btstack/src/ble/gatt-service/hids_device.c (revision 0235c9e5bd8f74d334b3a98669f13136376f9c8d)
1a4bfc4feSMatthias Ringwald /*
2a4bfc4feSMatthias Ringwald  * Copyright (C) 2014 BlueKitchen GmbH
3a4bfc4feSMatthias Ringwald  *
4a4bfc4feSMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5a4bfc4feSMatthias Ringwald  * modification, are permitted provided that the following conditions
6a4bfc4feSMatthias Ringwald  * are met:
7a4bfc4feSMatthias Ringwald  *
8a4bfc4feSMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9a4bfc4feSMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10a4bfc4feSMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11a4bfc4feSMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12a4bfc4feSMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13a4bfc4feSMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14a4bfc4feSMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15a4bfc4feSMatthias Ringwald  *    from this software without specific prior written permission.
16a4bfc4feSMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17a4bfc4feSMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18a4bfc4feSMatthias Ringwald  *    monetary gain.
19a4bfc4feSMatthias Ringwald  *
20a4bfc4feSMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21a4bfc4feSMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22a4bfc4feSMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23a4bfc4feSMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24a4bfc4feSMatthias Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25a4bfc4feSMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26a4bfc4feSMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27a4bfc4feSMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28a4bfc4feSMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29a4bfc4feSMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30a4bfc4feSMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31a4bfc4feSMatthias Ringwald  * SUCH DAMAGE.
32a4bfc4feSMatthias Ringwald  *
33a4bfc4feSMatthias Ringwald  * Please inquire about commercial licensing options at
34a4bfc4feSMatthias Ringwald  * [email protected]
35a4bfc4feSMatthias Ringwald  *
36a4bfc4feSMatthias Ringwald  */
37a4bfc4feSMatthias Ringwald 
38523edd21SMatthias Ringwald #define __BTSTACK_FILE__ "hids_device.c"
39523edd21SMatthias Ringwald 
40a4bfc4feSMatthias Ringwald /**
41a4bfc4feSMatthias Ringwald  * Implementation of the GATT HIDS Device
42a4bfc4feSMatthias Ringwald  * To use with your application, add '#import <hids.gatt>' to your .gatt file
43a4bfc4feSMatthias Ringwald  */
44a4bfc4feSMatthias Ringwald 
45a4bfc4feSMatthias Ringwald #include "hids_device.h"
46a4bfc4feSMatthias Ringwald 
4735b80bb0SMatthias Ringwald #include "ble/att_db.h"
4835b80bb0SMatthias Ringwald #include "ble/att_server.h"
49a4bfc4feSMatthias Ringwald #include "bluetooth_gatt.h"
50a4bfc4feSMatthias Ringwald #include "btstack_util.h"
51523edd21SMatthias Ringwald #include "btstack_debug.h"
52a4bfc4feSMatthias Ringwald 
53*0235c9e5SMilanka Ringwald #define HIDS_DEVICE_ERROR_CODE_INAPPROPRIATE_CONNECTION_PARAMETERS    0x80
54*0235c9e5SMilanka Ringwald 
55*0235c9e5SMilanka Ringwald typedef struct{
56*0235c9e5SMilanka Ringwald     uint16_t        con_handle;
57*0235c9e5SMilanka Ringwald 
58*0235c9e5SMilanka Ringwald     uint8_t         hid_country_code;
59*0235c9e5SMilanka Ringwald     const uint8_t * hid_descriptor;
60*0235c9e5SMilanka Ringwald     uint16_t        hid_descriptor_size;
61*0235c9e5SMilanka Ringwald 
62*0235c9e5SMilanka Ringwald     uint16_t        hid_report_map_handle;
63*0235c9e5SMilanka Ringwald     uint16_t        hid_protocol_mode;
64*0235c9e5SMilanka Ringwald     uint16_t        hid_protocol_mode_value_handle;
65*0235c9e5SMilanka Ringwald 
66*0235c9e5SMilanka Ringwald     uint16_t        hid_boot_mouse_input_value_handle;
67*0235c9e5SMilanka Ringwald     uint16_t        hid_boot_mouse_input_client_configuration_handle;
68*0235c9e5SMilanka Ringwald     uint16_t        hid_boot_mouse_input_client_configuration_value;
69*0235c9e5SMilanka Ringwald 
70*0235c9e5SMilanka Ringwald     uint16_t        hid_boot_keyboard_input_value_handle;
71*0235c9e5SMilanka Ringwald     uint16_t        hid_boot_keyboard_input_client_configuration_handle;
72*0235c9e5SMilanka Ringwald     uint16_t        hid_boot_keyboard_input_client_configuration_value;
73*0235c9e5SMilanka Ringwald 
74*0235c9e5SMilanka Ringwald     uint16_t        hid_report_input_value_handle;
75*0235c9e5SMilanka Ringwald     uint16_t        hid_report_input_client_configuration_handle;
76*0235c9e5SMilanka Ringwald     uint16_t        hid_report_input_client_configuration_value;
77*0235c9e5SMilanka Ringwald 
78*0235c9e5SMilanka Ringwald     uint16_t        hid_report_output_value_handle;
79*0235c9e5SMilanka Ringwald     uint16_t        hid_report_output_client_configuration_handle;
80*0235c9e5SMilanka Ringwald     uint16_t        hid_report_output_client_configuration_value;
81*0235c9e5SMilanka Ringwald 
82*0235c9e5SMilanka Ringwald     uint16_t        hid_report_feature_value_handle;
83*0235c9e5SMilanka Ringwald     uint16_t        hid_report_feature_client_configuration_handle;
84*0235c9e5SMilanka Ringwald     uint16_t        hid_report_feature_client_configuration_value;
85*0235c9e5SMilanka Ringwald 
86*0235c9e5SMilanka Ringwald     uint16_t        hid_control_point_value_handle;
87*0235c9e5SMilanka Ringwald     // uint16_t        hid_control_point_client_configuration_descriptor_handle;
88*0235c9e5SMilanka Ringwald     uint8_t         hid_control_point_suspend;
89*0235c9e5SMilanka Ringwald     // btstack_context_callback_registration_t control_point_callback;
90*0235c9e5SMilanka Ringwald 
91*0235c9e5SMilanka Ringwald     btstack_context_callback_registration_t  battery_callback;
92*0235c9e5SMilanka Ringwald } hids_device_t;
93*0235c9e5SMilanka Ringwald 
94*0235c9e5SMilanka Ringwald static hids_device_t hids_device;
95*0235c9e5SMilanka Ringwald 
96a4bfc4feSMatthias Ringwald static btstack_packet_handler_t packet_handler;
97a4bfc4feSMatthias Ringwald static att_service_handler_t hid_service;
98a4bfc4feSMatthias Ringwald 
99*0235c9e5SMilanka Ringwald // TODO: store hids device connection into list
100*0235c9e5SMilanka Ringwald static hids_device_t * hids_device_get_instance_for_con_handle(uint16_t con_handle){
101*0235c9e5SMilanka Ringwald     UNUSED(con_handle);
102*0235c9e5SMilanka Ringwald     return &hids_device;
103*0235c9e5SMilanka Ringwald }
104*0235c9e5SMilanka Ringwald 
105*0235c9e5SMilanka Ringwald static hids_device_t * hids_device_create_instance(void){
106*0235c9e5SMilanka Ringwald     return &hids_device;
107*0235c9e5SMilanka Ringwald }
108*0235c9e5SMilanka Ringwald 
109*0235c9e5SMilanka Ringwald // static int hids_device_delete_instance(void){
110*0235c9e5SMilanka Ringwald //     return 0;
111*0235c9e5SMilanka Ringwald // }
112*0235c9e5SMilanka Ringwald 
113a4bfc4feSMatthias Ringwald static void hids_device_emit_event_with_uint8(uint8_t event, hci_con_handle_t con_handle, uint8_t value){
114*0235c9e5SMilanka Ringwald     hids_device_t * instance = hids_device_get_instance_for_con_handle(con_handle);
115*0235c9e5SMilanka Ringwald     if (!instance){
116*0235c9e5SMilanka Ringwald         log_error("no instance for handle 0x%02x", con_handle);
117*0235c9e5SMilanka Ringwald         return;
118*0235c9e5SMilanka Ringwald     }
119*0235c9e5SMilanka Ringwald 
120a4bfc4feSMatthias Ringwald     if (!packet_handler) return;
121a4bfc4feSMatthias Ringwald     uint8_t buffer[6];
122a4bfc4feSMatthias Ringwald     buffer[0] = HCI_EVENT_HIDS_META;
123a4bfc4feSMatthias Ringwald     buffer[1] = 4;
124a4bfc4feSMatthias Ringwald     buffer[2] = event;
125a4bfc4feSMatthias Ringwald     little_endian_store_16(buffer, 3, (uint16_t) con_handle);
126a4bfc4feSMatthias Ringwald     buffer[5] = value;
127a4bfc4feSMatthias Ringwald     (*packet_handler)(HCI_EVENT_PACKET, 0, buffer, sizeof(buffer));
128a4bfc4feSMatthias Ringwald }
129a4bfc4feSMatthias Ringwald 
130*0235c9e5SMilanka Ringwald static void hids_device_emit_event(uint8_t event, hci_con_handle_t con_handle){
131*0235c9e5SMilanka Ringwald     hids_device_t * instance = hids_device_get_instance_for_con_handle(con_handle);
132*0235c9e5SMilanka Ringwald     if (!instance){
133*0235c9e5SMilanka Ringwald         log_error("no instance for handle 0x%02x", con_handle);
134*0235c9e5SMilanka Ringwald         return;
135*0235c9e5SMilanka Ringwald     }
136*0235c9e5SMilanka Ringwald 
137*0235c9e5SMilanka Ringwald     if (!packet_handler) return;
138*0235c9e5SMilanka Ringwald     uint8_t buffer[5];
139*0235c9e5SMilanka Ringwald     buffer[0] = HCI_EVENT_HIDS_META;
140*0235c9e5SMilanka Ringwald     buffer[1] = 4;
141*0235c9e5SMilanka Ringwald     buffer[2] = event;
142*0235c9e5SMilanka Ringwald     little_endian_store_16(buffer, 3, (uint16_t) con_handle);
143*0235c9e5SMilanka Ringwald     (*packet_handler)(HCI_EVENT_PACKET, 0, buffer, sizeof(buffer));
144*0235c9e5SMilanka Ringwald }
145*0235c9e5SMilanka Ringwald 
146a4bfc4feSMatthias Ringwald static void hids_device_can_send_now(void * context){
147a4bfc4feSMatthias Ringwald     hci_con_handle_t con_handle = (hci_con_handle_t) (uintptr_t) context;
148a4bfc4feSMatthias Ringwald     // notify client
149*0235c9e5SMilanka Ringwald     hids_device_t * instance = hids_device_get_instance_for_con_handle(con_handle);
150*0235c9e5SMilanka Ringwald     if (!instance){
151*0235c9e5SMilanka Ringwald         log_error("no instance for handle 0x%02x", con_handle);
152*0235c9e5SMilanka Ringwald         return;
153*0235c9e5SMilanka Ringwald     }
154*0235c9e5SMilanka Ringwald 
155a4bfc4feSMatthias Ringwald     if (!packet_handler) return;
156a4bfc4feSMatthias Ringwald     uint8_t buffer[5];
157a4bfc4feSMatthias Ringwald     buffer[0] = HCI_EVENT_HIDS_META;
158a4bfc4feSMatthias Ringwald     buffer[1] = 3;
159a4bfc4feSMatthias Ringwald     buffer[2] = HIDS_SUBEVENT_CAN_SEND_NOW;
160a4bfc4feSMatthias Ringwald     little_endian_store_16(buffer, 3, (uint16_t) con_handle);
161a4bfc4feSMatthias Ringwald     (*packet_handler)(HCI_EVENT_PACKET, 0, buffer, sizeof(buffer));
162a4bfc4feSMatthias Ringwald }
163a4bfc4feSMatthias Ringwald 
164a4bfc4feSMatthias Ringwald // ATT Client Read Callback for Dynamic Data
165a4bfc4feSMatthias Ringwald // - if buffer == NULL, don't copy data, just return size of value
166a4bfc4feSMatthias Ringwald // - if buffer != NULL, copy data and return number bytes copied
167*0235c9e5SMilanka Ringwald static uint16_t att_read_callback(hci_con_handle_t con_handle, uint16_t att_handle, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){
168*0235c9e5SMilanka Ringwald     hids_device_t * instance = hids_device_get_instance_for_con_handle(con_handle);
169*0235c9e5SMilanka Ringwald     if (!instance){
170*0235c9e5SMilanka Ringwald         log_error("no instance for handle 0x%02x", con_handle);
171*0235c9e5SMilanka Ringwald         return HIDS_DEVICE_ERROR_CODE_INAPPROPRIATE_CONNECTION_PARAMETERS;
172a4bfc4feSMatthias Ringwald     }
173*0235c9e5SMilanka Ringwald 
174*0235c9e5SMilanka Ringwald     printf("att_read_callback att handle 0x%02x\n", att_handle);
175*0235c9e5SMilanka Ringwald 
176*0235c9e5SMilanka Ringwald     if (att_handle == instance->hid_protocol_mode_value_handle){
177*0235c9e5SMilanka Ringwald         log_info("Read protocol mode");
178*0235c9e5SMilanka Ringwald         return att_read_callback_handle_byte(instance->hid_protocol_mode, offset, buffer, buffer_size);
179*0235c9e5SMilanka Ringwald     }
180*0235c9e5SMilanka Ringwald     if (att_handle == instance->hid_report_map_handle){
181523edd21SMatthias Ringwald         log_info("Read report map");
182*0235c9e5SMilanka Ringwald         return att_read_callback_handle_blob(instance->hid_descriptor, instance->hid_descriptor_size, offset, buffer, buffer_size);
183a4bfc4feSMatthias Ringwald     }
184a4bfc4feSMatthias Ringwald     // if (att_handle == hid_boot_mouse_input_value_handle){
185a4bfc4feSMatthias Ringwald     // }
186*0235c9e5SMilanka Ringwald     if (att_handle == instance->hid_boot_mouse_input_client_configuration_handle){
187*0235c9e5SMilanka Ringwald         return att_read_callback_handle_little_endian_16(instance->hid_boot_mouse_input_client_configuration_value, offset, buffer, buffer_size);
188a4bfc4feSMatthias Ringwald     }
189a4bfc4feSMatthias Ringwald     // if (att_handle == hid_boot_keyboard_input_value_handle){
190a4bfc4feSMatthias Ringwald     // }
191*0235c9e5SMilanka Ringwald     if (att_handle == instance->hid_boot_keyboard_input_client_configuration_handle){
192*0235c9e5SMilanka Ringwald         return att_read_callback_handle_little_endian_16(instance->hid_boot_keyboard_input_client_configuration_value, offset, buffer, buffer_size);
193a4bfc4feSMatthias Ringwald     }
194a4bfc4feSMatthias Ringwald     // if (att_handle == hid_report_input_value_handle){
195a4bfc4feSMatthias Ringwald     // }
196*0235c9e5SMilanka Ringwald     if (att_handle == instance->hid_report_input_client_configuration_handle){
197*0235c9e5SMilanka Ringwald         return att_read_callback_handle_little_endian_16(instance->hid_report_input_client_configuration_value, offset, buffer, buffer_size);
198*0235c9e5SMilanka Ringwald     }
199*0235c9e5SMilanka Ringwald     if (att_handle == instance->hid_report_input_client_configuration_handle){
200*0235c9e5SMilanka Ringwald         return att_read_callback_handle_little_endian_16(instance->hid_report_output_client_configuration_value, offset, buffer, buffer_size);
201*0235c9e5SMilanka Ringwald     }
202*0235c9e5SMilanka Ringwald     if (att_handle == instance->hid_report_input_client_configuration_handle){
203*0235c9e5SMilanka Ringwald         return att_read_callback_handle_little_endian_16(instance->hid_report_feature_client_configuration_value, offset, buffer, buffer_size);
204*0235c9e5SMilanka Ringwald     }
205*0235c9e5SMilanka Ringwald     if (att_handle == instance->hid_control_point_value_handle){
206*0235c9e5SMilanka Ringwald         if (buffer && buffer_size >= 1){
207*0235c9e5SMilanka Ringwald             buffer[0] = instance->hid_control_point_suspend;
208*0235c9e5SMilanka Ringwald         }
209*0235c9e5SMilanka Ringwald         return 1;
210a4bfc4feSMatthias Ringwald     }
211a4bfc4feSMatthias Ringwald     return 0;
212a4bfc4feSMatthias Ringwald }
213a4bfc4feSMatthias Ringwald 
214a4bfc4feSMatthias Ringwald static int att_write_callback(hci_con_handle_t con_handle, uint16_t att_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size){
215a4bfc4feSMatthias Ringwald     UNUSED(transaction_mode);
216a4bfc4feSMatthias Ringwald     UNUSED(buffer_size);
217a4bfc4feSMatthias Ringwald     UNUSED(offset);
218a4bfc4feSMatthias Ringwald 
219*0235c9e5SMilanka Ringwald     hids_device_t * instance = hids_device_get_instance_for_con_handle(con_handle);
220*0235c9e5SMilanka Ringwald     if (!instance){
221*0235c9e5SMilanka Ringwald         log_error("no instance for handle 0x%02x", con_handle);
222*0235c9e5SMilanka Ringwald         return HIDS_DEVICE_ERROR_CODE_INAPPROPRIATE_CONNECTION_PARAMETERS;
223*0235c9e5SMilanka Ringwald     }
224*0235c9e5SMilanka Ringwald     printf("att_write_callback att handle 0x%02x\n", att_handle);
225*0235c9e5SMilanka Ringwald 
226*0235c9e5SMilanka Ringwald     if (att_handle == instance->hid_boot_mouse_input_client_configuration_handle){
22785828295SMatthias Ringwald         uint16_t new_value = little_endian_read_16(buffer, 0);
2289ff89460SMatthias Ringwald         // if (new_value == hid_boot_mouse_input_client_configuration_value) return 0;
229*0235c9e5SMilanka Ringwald         instance->hid_boot_mouse_input_client_configuration_value = new_value;
230*0235c9e5SMilanka Ringwald         hids_device_emit_event_with_uint8(HIDS_SUBEVENT_BOOT_MOUSE_INPUT_REPORT_ENABLE, con_handle, new_value);
231a4bfc4feSMatthias Ringwald     }
232*0235c9e5SMilanka Ringwald     if (att_handle == instance->hid_boot_keyboard_input_client_configuration_handle){
23385828295SMatthias Ringwald         uint16_t new_value = little_endian_read_16(buffer, 0);
2349ff89460SMatthias Ringwald         // if (new_value == hid_boot_keyboard_input_client_configuration_value) return 0;
235*0235c9e5SMilanka Ringwald         instance->hid_boot_keyboard_input_client_configuration_value = new_value;
236*0235c9e5SMilanka Ringwald         hids_device_emit_event_with_uint8(HIDS_SUBEVENT_BOOT_KEYBOARD_INPUT_REPORT_ENABLE, con_handle, new_value);
237a4bfc4feSMatthias Ringwald     }
238*0235c9e5SMilanka Ringwald     if (att_handle == instance->hid_report_input_client_configuration_handle){
23985828295SMatthias Ringwald         uint16_t new_value = little_endian_read_16(buffer, 0);
2409ff89460SMatthias Ringwald         // if (new_value == hid_report_input_client_configuration_value) return 0;
241*0235c9e5SMilanka Ringwald         instance->hid_report_input_client_configuration_value = new_value;
24285828295SMatthias Ringwald         log_info("Enable Report Input notifications: %x", new_value);
243*0235c9e5SMilanka Ringwald         hids_device_emit_event_with_uint8(HIDS_SUBEVENT_INPUT_REPORT_ENABLE, con_handle, new_value);
244a4bfc4feSMatthias Ringwald     }
245*0235c9e5SMilanka Ringwald     if (att_handle == instance->hid_report_output_client_configuration_handle){
246*0235c9e5SMilanka Ringwald         uint16_t new_value = little_endian_read_16(buffer, 0);
247*0235c9e5SMilanka Ringwald         // if (new_value == hid_report_output_client_configuration_value) return 0;
248*0235c9e5SMilanka Ringwald         instance->hid_report_output_client_configuration_value = new_value;
249*0235c9e5SMilanka Ringwald         log_info("Enable Report Output notifications: %x", new_value);
250*0235c9e5SMilanka Ringwald         hids_device_emit_event_with_uint8(HIDS_SUBEVENT_OUTPUT_REPORT_ENABLE, con_handle, new_value);
251a4bfc4feSMatthias Ringwald     }
252*0235c9e5SMilanka Ringwald     if (att_handle == instance->hid_report_feature_client_configuration_handle){
253*0235c9e5SMilanka Ringwald         uint16_t new_value = little_endian_read_16(buffer, 0);
254*0235c9e5SMilanka Ringwald         // if (new_value == hid_report_feature_client_configuration_value) return 0;
255*0235c9e5SMilanka Ringwald         instance->hid_report_feature_client_configuration_value = new_value;
256*0235c9e5SMilanka Ringwald         log_info("Enable Report Feature notifications: %x", new_value);
257*0235c9e5SMilanka Ringwald         hids_device_emit_event_with_uint8(HIDS_SUBEVENT_FEATURE_REPORT_ENABLE, con_handle, new_value);
258*0235c9e5SMilanka Ringwald     }
259*0235c9e5SMilanka Ringwald 
260*0235c9e5SMilanka Ringwald     if (att_handle == instance->hid_protocol_mode_value_handle){
261*0235c9e5SMilanka Ringwald         instance->hid_protocol_mode = buffer[0];
262*0235c9e5SMilanka Ringwald         log_info("Set protocol mode: %u", instance->hid_protocol_mode);
263*0235c9e5SMilanka Ringwald         hids_device_emit_event_with_uint8(HIDS_SUBEVENT_PROTOCOL_MODE, con_handle, instance->hid_protocol_mode);
264*0235c9e5SMilanka Ringwald     }
265*0235c9e5SMilanka Ringwald 
266*0235c9e5SMilanka Ringwald     if (att_handle == instance->hid_control_point_value_handle){
267*0235c9e5SMilanka Ringwald         if (buffer_size < 1){
268*0235c9e5SMilanka Ringwald             return ATT_ERROR_INVALID_OFFSET;
269*0235c9e5SMilanka Ringwald         }
270*0235c9e5SMilanka Ringwald         instance->hid_control_point_suspend = buffer[0];
271*0235c9e5SMilanka Ringwald         instance->con_handle = con_handle;
272*0235c9e5SMilanka Ringwald         log_info("Set suspend tp: %u", instance->hid_control_point_suspend );
273*0235c9e5SMilanka Ringwald         if (instance->hid_control_point_suspend == 0){
274*0235c9e5SMilanka Ringwald             hids_device_emit_event(HIDS_SUBEVENT_SUSPEND, con_handle);
275*0235c9e5SMilanka Ringwald         } else if (instance->hid_control_point_suspend == 1){
276*0235c9e5SMilanka Ringwald             hids_device_emit_event(HIDS_SUBEVENT_EXIT_SUSPEND, con_handle);
277*0235c9e5SMilanka Ringwald         }
278*0235c9e5SMilanka Ringwald         // } else {
279*0235c9e5SMilanka Ringwald         //     return ATT_ERROR_INAPPROPRIATE_CONNECTION_PARAMETERS;
280*0235c9e5SMilanka Ringwald         // }
281*0235c9e5SMilanka Ringwald     }
282*0235c9e5SMilanka Ringwald 
283a4bfc4feSMatthias Ringwald     return 0;
284a4bfc4feSMatthias Ringwald }
285a4bfc4feSMatthias Ringwald 
286a4bfc4feSMatthias Ringwald /**
287a4bfc4feSMatthias Ringwald  * @brief Set up HIDS Device
288a4bfc4feSMatthias Ringwald  */
289a4bfc4feSMatthias Ringwald void hids_device_init(uint8_t country_code, const uint8_t * descriptor, uint16_t descriptor_size){
290*0235c9e5SMilanka Ringwald     hids_device_t * instance = hids_device_create_instance();
291*0235c9e5SMilanka Ringwald     if (!instance){
292*0235c9e5SMilanka Ringwald         log_error("hids_device_init: instance could not be created, not enough memory");
293*0235c9e5SMilanka Ringwald         return;
294*0235c9e5SMilanka Ringwald     }
295a4bfc4feSMatthias Ringwald 
296*0235c9e5SMilanka Ringwald     instance->hid_country_code    = country_code;
297*0235c9e5SMilanka Ringwald     instance->hid_descriptor      = descriptor;
298*0235c9e5SMilanka Ringwald     instance->hid_descriptor_size = descriptor_size;
299a4bfc4feSMatthias Ringwald 
300a4bfc4feSMatthias Ringwald     // default
301*0235c9e5SMilanka Ringwald     instance->hid_protocol_mode   = 1;
302a4bfc4feSMatthias Ringwald 
303a4bfc4feSMatthias Ringwald     // get service handle range
304a4bfc4feSMatthias Ringwald     uint16_t start_handle = 0;
305a4bfc4feSMatthias Ringwald     uint16_t end_handle   = 0xfff;
306a4bfc4feSMatthias Ringwald     int service_found = gatt_server_get_get_handle_range_for_service_with_uuid16(ORG_BLUETOOTH_SERVICE_HUMAN_INTERFACE_DEVICE, &start_handle, &end_handle);
307a4bfc4feSMatthias Ringwald     if (!service_found) return;
308a4bfc4feSMatthias Ringwald 
309a4bfc4feSMatthias Ringwald     // get report map handle
310*0235c9e5SMilanka Ringwald     instance->hid_report_map_handle                               = gatt_server_get_value_handle_for_characteristic_with_uuid16(start_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_REPORT_MAP);
311a4bfc4feSMatthias Ringwald 
312a4bfc4feSMatthias Ringwald     // get report map handle
313*0235c9e5SMilanka Ringwald     instance->hid_protocol_mode_value_handle                      = gatt_server_get_value_handle_for_characteristic_with_uuid16(start_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_PROTOCOL_MODE);
314a4bfc4feSMatthias Ringwald 
315a4bfc4feSMatthias Ringwald     // get value and client configuration handles for boot mouse input, boot keyboard input and report input
316*0235c9e5SMilanka Ringwald     instance->hid_boot_mouse_input_value_handle                   = gatt_server_get_value_handle_for_characteristic_with_uuid16(start_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_BOOT_MOUSE_INPUT_REPORT);
317*0235c9e5SMilanka Ringwald     instance->hid_boot_mouse_input_client_configuration_handle    = gatt_server_get_client_configuration_handle_for_characteristic_with_uuid16(start_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_BOOT_MOUSE_INPUT_REPORT);
318a4bfc4feSMatthias Ringwald 
319*0235c9e5SMilanka Ringwald     instance->hid_boot_keyboard_input_value_handle                = gatt_server_get_value_handle_for_characteristic_with_uuid16(start_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_BOOT_KEYBOARD_INPUT_REPORT);
320*0235c9e5SMilanka Ringwald     instance->hid_boot_keyboard_input_client_configuration_handle = gatt_server_get_client_configuration_handle_for_characteristic_with_uuid16(start_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_BOOT_KEYBOARD_INPUT_REPORT);
321a4bfc4feSMatthias Ringwald 
322*0235c9e5SMilanka Ringwald     instance->hid_report_input_value_handle                       = gatt_server_get_value_handle_for_characteristic_with_uuid16(start_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_REPORT);
323*0235c9e5SMilanka Ringwald     instance->hid_report_input_client_configuration_handle        = gatt_server_get_client_configuration_handle_for_characteristic_with_uuid16(start_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_REPORT);
324*0235c9e5SMilanka Ringwald 
325*0235c9e5SMilanka Ringwald     instance->hid_report_output_value_handle                      = gatt_server_get_value_handle_for_characteristic_with_uuid16(instance->hid_report_input_client_configuration_handle+1, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_REPORT);
326*0235c9e5SMilanka Ringwald     instance->hid_report_output_client_configuration_handle       = gatt_server_get_client_configuration_handle_for_characteristic_with_uuid16(instance->hid_report_input_client_configuration_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_REPORT);
327*0235c9e5SMilanka Ringwald 
328*0235c9e5SMilanka Ringwald     instance->hid_report_feature_value_handle                     = gatt_server_get_value_handle_for_characteristic_with_uuid16(instance->hid_report_output_client_configuration_handle+1, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_REPORT);
329*0235c9e5SMilanka Ringwald     instance->hid_report_feature_client_configuration_handle      = gatt_server_get_client_configuration_handle_for_characteristic_with_uuid16(instance->hid_report_output_client_configuration_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_REPORT);
330*0235c9e5SMilanka Ringwald 
331*0235c9e5SMilanka Ringwald     instance->hid_control_point_value_handle = gatt_server_get_value_handle_for_characteristic_with_uuid16(start_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_HID_CONTROL_POINT);
332*0235c9e5SMilanka Ringwald 
333*0235c9e5SMilanka Ringwald     printf("hid_report_map_handle                               0x%02x\n", instance->hid_report_map_handle);
334*0235c9e5SMilanka Ringwald     printf("hid_protocol_mode_value_handle                      0x%02x\n", instance->hid_protocol_mode_value_handle);
335*0235c9e5SMilanka Ringwald     printf("hid_boot_mouse_input_value_handle                   0x%02x\n", instance->hid_boot_mouse_input_value_handle);
336*0235c9e5SMilanka Ringwald     printf("hid_boot_mouse_input_client_configuration_handle    0x%02x\n", instance->hid_boot_mouse_input_client_configuration_handle);
337*0235c9e5SMilanka Ringwald     printf("\n");
338*0235c9e5SMilanka Ringwald     printf("hid_boot_keyboard_input_value_handle                0x%02x\n", instance->hid_boot_keyboard_input_value_handle);
339*0235c9e5SMilanka Ringwald     printf("hid_boot_keyboard_input_client_configuration_handle 0x%02x\n", instance->hid_boot_keyboard_input_client_configuration_handle);
340*0235c9e5SMilanka Ringwald     printf("\n");
341*0235c9e5SMilanka Ringwald     printf("hid_report_input_value_handle                       0x%02x\n", instance->hid_report_input_value_handle);
342*0235c9e5SMilanka Ringwald     printf("hid_report_input_client_configuration_handle        0x%02x\n", instance->hid_report_input_client_configuration_handle);
343*0235c9e5SMilanka Ringwald     printf("\n");
344*0235c9e5SMilanka Ringwald     printf("hid_report_output_value_handle                      0x%02x\n", instance->hid_report_output_value_handle);
345*0235c9e5SMilanka Ringwald     printf("hid_report_output_client_configuration_handle       0x%02x\n", instance->hid_report_output_client_configuration_handle);
346*0235c9e5SMilanka Ringwald     printf("\n");
347*0235c9e5SMilanka Ringwald     printf("hid_report_feature_value_handle                     0x%02x\n", instance->hid_report_feature_value_handle);
348*0235c9e5SMilanka Ringwald     printf("hid_report_feature_client_configuration_handle      0x%02x\n", instance->hid_report_feature_client_configuration_handle);
349*0235c9e5SMilanka Ringwald 
350*0235c9e5SMilanka Ringwald     printf("hid_control_point_value_handle                      0x%02x\n", instance->hid_control_point_value_handle);
351a4bfc4feSMatthias Ringwald 
3523d71c7a4SMatthias Ringwald     // register service with ATT Server
353a4bfc4feSMatthias Ringwald     hid_service.start_handle   = start_handle;
354a4bfc4feSMatthias Ringwald     hid_service.end_handle     = end_handle;
355a4bfc4feSMatthias Ringwald     hid_service.read_callback  = &att_read_callback;
356a4bfc4feSMatthias Ringwald     hid_service.write_callback = &att_write_callback;
3573d71c7a4SMatthias Ringwald     att_server_register_service_handler(&hid_service);
358a4bfc4feSMatthias Ringwald }
359a4bfc4feSMatthias Ringwald 
360a4bfc4feSMatthias Ringwald /**
361a4bfc4feSMatthias Ringwald  * @brief Register callback for the HIDS Device client.
362a4bfc4feSMatthias Ringwald  * @param callback
363a4bfc4feSMatthias Ringwald  */
364a4bfc4feSMatthias Ringwald void hids_device_register_packet_handler(btstack_packet_handler_t callback){
365a4bfc4feSMatthias Ringwald     packet_handler = callback;
366a4bfc4feSMatthias Ringwald }
367a4bfc4feSMatthias Ringwald 
368a4bfc4feSMatthias Ringwald /**
369a4bfc4feSMatthias Ringwald  * @brief Request can send now event to send HID Report
370a4bfc4feSMatthias Ringwald  * Generates an HIDS_SUBEVENT_CAN_SEND_NOW subevent
371a4bfc4feSMatthias Ringwald  * @param hid_cid
372a4bfc4feSMatthias Ringwald  */
373a4bfc4feSMatthias Ringwald void hids_device_request_can_send_now_event(hci_con_handle_t con_handle){
374*0235c9e5SMilanka Ringwald     hids_device_t * instance = hids_device_get_instance_for_con_handle(con_handle);
375*0235c9e5SMilanka Ringwald     if (!instance){
376*0235c9e5SMilanka Ringwald         log_error("no instance for handle 0x%02x", con_handle);
377*0235c9e5SMilanka Ringwald         return;
378*0235c9e5SMilanka Ringwald     }
379*0235c9e5SMilanka Ringwald 
380*0235c9e5SMilanka Ringwald     instance->battery_callback.callback = &hids_device_can_send_now;
381*0235c9e5SMilanka Ringwald     instance->battery_callback.context  = (void*) (uintptr_t) con_handle;
382*0235c9e5SMilanka Ringwald     att_server_register_can_send_now_callback(&instance->battery_callback, con_handle);
383a4bfc4feSMatthias Ringwald }
384a4bfc4feSMatthias Ringwald 
385a4bfc4feSMatthias Ringwald /**
386a4bfc4feSMatthias Ringwald  * @brief Send HID Report: Input
387a4bfc4feSMatthias Ringwald  */
388a4bfc4feSMatthias Ringwald void hids_device_send_input_report(hci_con_handle_t con_handle, const uint8_t * report, uint16_t report_len){
389*0235c9e5SMilanka Ringwald     hids_device_t * instance = hids_device_get_instance_for_con_handle(con_handle);
390*0235c9e5SMilanka Ringwald     if (!instance){
391*0235c9e5SMilanka Ringwald         log_error("no instance for handle 0x%02x", con_handle);
392*0235c9e5SMilanka Ringwald         return;
393*0235c9e5SMilanka Ringwald     }
394*0235c9e5SMilanka Ringwald     att_server_notify(con_handle, instance->hid_report_input_value_handle, (uint8_t*) report, report_len);
395*0235c9e5SMilanka Ringwald }
396*0235c9e5SMilanka Ringwald 
397*0235c9e5SMilanka Ringwald /**
398*0235c9e5SMilanka Ringwald  * @brief Send HID Report: Output
399*0235c9e5SMilanka Ringwald  */
400*0235c9e5SMilanka Ringwald void hids_device_send_output_report(hci_con_handle_t con_handle, const uint8_t * report, uint16_t report_len){
401*0235c9e5SMilanka Ringwald     hids_device_t * instance = hids_device_get_instance_for_con_handle(con_handle);
402*0235c9e5SMilanka Ringwald     if (!instance){
403*0235c9e5SMilanka Ringwald         log_error("no instance for handle 0x%02x", con_handle);
404*0235c9e5SMilanka Ringwald         return;
405*0235c9e5SMilanka Ringwald     }
406*0235c9e5SMilanka Ringwald     att_server_notify(con_handle, instance->hid_report_output_value_handle, (uint8_t*) report, report_len);
407*0235c9e5SMilanka Ringwald }
408*0235c9e5SMilanka Ringwald 
409*0235c9e5SMilanka Ringwald /**
410*0235c9e5SMilanka Ringwald  * @brief Send HID Report: Feature
411*0235c9e5SMilanka Ringwald  */
412*0235c9e5SMilanka Ringwald void hids_device_send_feature_report(hci_con_handle_t con_handle, const uint8_t * report, uint16_t report_len){
413*0235c9e5SMilanka Ringwald     hids_device_t * instance = hids_device_get_instance_for_con_handle(con_handle);
414*0235c9e5SMilanka Ringwald     if (!instance){
415*0235c9e5SMilanka Ringwald         log_error("no instance for handle 0x%02x", con_handle);
416*0235c9e5SMilanka Ringwald         return;
417*0235c9e5SMilanka Ringwald     }
418*0235c9e5SMilanka Ringwald     att_server_notify(con_handle, instance->hid_report_feature_value_handle, (uint8_t*) report, report_len);
419a4bfc4feSMatthias Ringwald }
420a4bfc4feSMatthias Ringwald 
421a4bfc4feSMatthias Ringwald /**
422a4bfc4feSMatthias Ringwald  * @brief Send HID Boot Mouse Input Report
423a4bfc4feSMatthias Ringwald  */
424a4bfc4feSMatthias Ringwald void hids_device_send_boot_mouse_input_report(hci_con_handle_t con_handle, const uint8_t * report, uint16_t report_len){
425*0235c9e5SMilanka Ringwald     hids_device_t * instance = hids_device_get_instance_for_con_handle(con_handle);
426*0235c9e5SMilanka Ringwald     if (!instance){
427*0235c9e5SMilanka Ringwald         log_error("no instance for handle 0x%02x", con_handle);
428*0235c9e5SMilanka Ringwald         return;
429*0235c9e5SMilanka Ringwald     }
430*0235c9e5SMilanka Ringwald     att_server_notify(con_handle, instance->hid_boot_mouse_input_value_handle, (uint8_t*) report, report_len);
431a4bfc4feSMatthias Ringwald }
432a4bfc4feSMatthias Ringwald 
433a4bfc4feSMatthias Ringwald /**
434a4bfc4feSMatthias Ringwald  * @brief Send HID Boot Mouse Input Report
435a4bfc4feSMatthias Ringwald  */
436a4bfc4feSMatthias Ringwald void hids_device_send_boot_keyboard_input_report(hci_con_handle_t con_handle, const uint8_t * report, uint16_t report_len){
437*0235c9e5SMilanka Ringwald     hids_device_t * instance = hids_device_get_instance_for_con_handle(con_handle);
438*0235c9e5SMilanka Ringwald     if (!instance){
439*0235c9e5SMilanka Ringwald         log_error("no instance for handle 0x%02x", con_handle);
440*0235c9e5SMilanka Ringwald         return;
441*0235c9e5SMilanka Ringwald     }
442*0235c9e5SMilanka Ringwald     att_server_notify(con_handle, instance->hid_boot_keyboard_input_value_handle, (uint8_t*) report, report_len);
443a4bfc4feSMatthias Ringwald }
444