xref: /btstack/example/hid_keyboard_demo.c (revision 4cf728558f3c3efbda3b2f1ec36124a563b3da03)
1 /*
2  * Copyright (C) 2014 BlueKitchen GmbH
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holders nor the names of
14  *    contributors may be used to endorse or promote products derived
15  *    from this software without specific prior written permission.
16  * 4. Any redistribution, use, or modification is done solely for
17  *    personal benefit and not for any commercial purpose or for
18  *    monetary gain.
19  *
20  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * Please inquire about commercial licensing options at
34  * [email protected]
35  *
36  */
37 
38 #define __BTSTACK_FILE__ "hid_device_demo.c"
39 
40 // *****************************************************************************
41 /* EXAMPLE_START(hid_device_demo): HID Device (Server) Demo
42  *
43  * @text This HID Device example demonstrates how to implement
44  * an HID keyboard. Without a HAVE_POSIX_STDIN, a fixed message is sent
45  * If HAVE_POSIX_STDIN is defined, you can control and type from the terminal
46  */
47 // *****************************************************************************
48 
49 
50 #include <stdint.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <unistd.h>
55 #include <inttypes.h>
56 
57 #include "btstack.h"
58 #ifdef HAVE_POSIX_STDIN
59 #include "stdin_support.h"
60 #endif
61 
62 uint8_t hid_service_buffer[250];
63 const char hid_device_name[] = "BTstack HID Keyboard";
64 static btstack_packet_callback_registration_t hci_event_callback_registration;
65 
66 // hid device state
67 static uint16_t hid_control_cid;
68 static uint16_t hid_interrupt_cid;
69 
70 // from USB HID Specification 1.1, Appendix B.1
71 const uint8_t hid_descriptor_keyboard_boot_mode[] = {
72 
73     0x05, 0x01,                    // Usage Page (Generic Desktop)
74     0x09, 0x06,                    // Usage (Keyboard)
75     0xa1, 0x01,                    // Collection (Application)
76 
77     // Modifier byte
78 
79     0x75, 0x01,                    //   Report Size (1)
80     0x95, 0x08,                    //   Report Count (8)
81     0x05, 0x07,                    //   Usage Page (Key codes)
82     0x19, 0xe0,                    //   Usage Minimum (Keyboard LeftControl)
83     0x29, 0xe7,                    //   Usage Maxium (Keyboard Right GUI)
84     0x15, 0x00,                    //   Logical Minimum (0)
85     0x25, 0x01,                    //   Logical Maximum (1)
86     0x81, 0x02,                    //   Input (Data, Variable, Absolute)
87 
88     // Reserved byte
89 
90     0x75, 0x01,                    //   Report Size (1)
91     0x95, 0x08,                    //   Report Count (8)
92     0x81, 0x03,                    //   Input (Constant, Variable, Absolute)
93 
94     // LED report + padding
95 
96     0x95, 0x05,                    //   Report Count (5)
97     0x75, 0x01,                    //   Report Size (1)
98     0x05, 0x08,                    //   Usage Page (LEDs)
99     0x19, 0x01,                    //   Usage Minimum (Num Lock)
100     0x29, 0x05,                    //   Usage Maxium (Kana)
101     0x91, 0x02,                    //   Output (Data, Variable, Absolute)
102 
103     0x95, 0x01,                    //   Report Count (1)
104     0x75, 0x03,                    //   Report Size (3)
105     0x91, 0x03,                    //   Output (Constant, Variable, Absolute)
106 
107     // Keycodes
108 
109     0x95, 0x06,                    //   Report Count (6)
110     0x75, 0x08,                    //   Report Size (8)
111     0x15, 0x00,                    //   Logical Minimum (0)
112     0x25, 0xff,                    //   Logical Maximum (1)
113     0x05, 0x07,                    //   Usage Page (Key codes)
114     0x19, 0x00,                    //   Usage Minimum (Reserved (no event indicated))
115     0x29, 0xff,                    //   Usage Maxium (Reserved)
116     0x81, 0x00,                    //   Input (Data, Array)
117 
118     0xc0,                          // End collection
119 };
120 
121 void hid_create_sdp_record(
122     uint8_t *service,
123     uint32_t service_record_handle,
124     uint16_t hid_device_subclass,
125     uint8_t  hid_country_code,
126     uint8_t  hid_virtual_cable,
127     uint8_t  hid_reconnect_initiate,
128     uint8_t  hid_boot_device,
129     const uint8_t * hid_descriptor, uint16_t hid_descriptor_size,
130     const char *device_name);
131 
132 void hid_create_sdp_record(
133     uint8_t *service,
134     uint32_t service_record_handle,
135     uint16_t hid_device_subclass,
136     uint8_t  hid_country_code,
137     uint8_t  hid_virtual_cable,
138     uint8_t  hid_reconnect_initiate,
139     uint8_t  hid_boot_device,
140     const uint8_t * hid_descriptor, uint16_t hid_descriptor_size,
141     const char *device_name){
142 
143     uint8_t * attribute;
144     de_create_sequence(service);
145 
146     de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_RECORD_HANDLE);
147     de_add_number(service, DE_UINT, DE_SIZE_32, service_record_handle);
148 
149     de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST);
150     attribute = de_push_sequence(service);
151     {
152         de_add_number(attribute,  DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE_SERVICE);
153     }
154     de_pop_sequence(service, attribute);
155 
156     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST);
157     attribute = de_push_sequence(service);
158     {
159         uint8_t * l2cpProtocol = de_push_sequence(attribute);
160         {
161             de_add_number(l2cpProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_L2CAP);
162             de_add_number(l2cpProtocol,  DE_UINT, DE_SIZE_16, PSM_HID_CONTROL);
163         }
164         de_pop_sequence(attribute, l2cpProtocol);
165 
166         uint8_t * hidProtocol = de_push_sequence(attribute);
167         {
168             de_add_number(hidProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_HIDP);
169         }
170         de_pop_sequence(attribute, hidProtocol);
171     }
172     de_pop_sequence(service, attribute);
173 
174     // TODO?
175     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
176     attribute = de_push_sequence(service);
177     {
178         de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x656e);
179         de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x006a);
180         de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x0100);
181     }
182     de_pop_sequence(service, attribute);
183 
184     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS);
185     attribute = de_push_sequence(service);
186     {
187         uint8_t * additionalDescriptorAttribute = de_push_sequence(attribute);
188         {
189             uint8_t * l2cpProtocol = de_push_sequence(additionalDescriptorAttribute);
190             {
191                 de_add_number(l2cpProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_L2CAP);
192                 de_add_number(l2cpProtocol,  DE_UINT, DE_SIZE_16, PSM_HID_INTERRUPT);
193             }
194             de_pop_sequence(additionalDescriptorAttribute, l2cpProtocol);
195 
196             uint8_t * hidProtocol = de_push_sequence(attribute);
197             {
198                 de_add_number(hidProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_HIDP);
199             }
200             de_pop_sequence(attribute, hidProtocol);
201         }
202         de_pop_sequence(attribute, additionalDescriptorAttribute);
203     }
204     de_pop_sequence(service, attribute);
205 
206     // 0x0100 "ServiceName"
207     de_add_number(service,  DE_UINT, DE_SIZE_16, 0x0100);
208     de_add_data(service,  DE_STRING, strlen(device_name), (uint8_t *) device_name);
209 
210     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
211     attribute = de_push_sequence(service);
212     {
213         uint8_t * hidProfile = de_push_sequence(attribute);
214         {
215             de_add_number(hidProfile,  DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE_SERVICE);
216             de_add_number(hidProfile,  DE_UINT, DE_SIZE_16, 0x0101);    // Version 1.1
217         }
218         de_pop_sequence(attribute, hidProfile);
219     }
220     de_pop_sequence(service, attribute);
221 
222     // Deprecated in v1.1.1
223     // de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_DEVICE_RELEASE_NUMBER);
224     // de_add_number(service,  DE_UINT, DE_SIZE_16, 0x0101);
225 
226     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_PARSER_VERSION);
227     de_add_number(service,  DE_UINT, DE_SIZE_16, 0x0111);  // v1.1.1
228 
229     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_DEVICE_SUBCLASS);
230     de_add_number(service,  DE_UINT, DE_SIZE_16, hid_device_subclass);
231 
232     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_COUNTRY_CODE);
233     de_add_number(service,  DE_UINT, DE_SIZE_16, hid_country_code);
234 
235     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_VIRTUAL_CABLE);
236     de_add_number(service,  DE_BOOL, DE_SIZE_8,  hid_virtual_cable);
237 
238     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_RECONNECT_INITIATE);
239     de_add_number(service,  DE_BOOL, DE_SIZE_8,  hid_reconnect_initiate);
240 
241     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_DESCRIPTOR_LIST);
242     attribute = de_push_sequence(service);
243     {
244         uint8_t* hidDescriptor = de_push_sequence(attribute);
245         {
246             de_add_number(hidDescriptor,  DE_UINT, DE_SIZE_8, 0x22);    // Report Descriptor
247             de_add_data(hidDescriptor,  DE_STRING, hid_descriptor_size, (uint8_t *) hid_descriptor);
248         }
249         de_pop_sequence(attribute, hidDescriptor);
250     }
251     de_pop_sequence(service, attribute);
252 
253     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_BOOT_DEVICE);
254     de_add_number(service,  DE_BOOL, DE_SIZE_8,  hid_boot_device);
255 }
256 
257 static int send_keycode;
258 static int send_modifier;
259 
260 static void send_key(int modifier, int keycode){
261     send_keycode = keycode;
262     send_modifier = modifier;
263     l2cap_request_can_send_now_event(hid_interrupt_cid);
264 }
265 
266 static void send_report(int modifier, int keycode){
267     uint8_t report[] = { 0xa1, modifier, 0, 0, keycode, 0, 0, 0, 0, 0};
268     l2cap_send(hid_interrupt_cid, &report[0], sizeof(report));
269 }
270 
271 #ifdef HAVE_POSIX_STDIN
272 
273 // prototypes
274 static void show_usage(void);
275 
276 // Testig User Interface
277 static void show_usage(void){
278     bd_addr_t iut_address;
279     gap_local_bd_addr(iut_address);
280 
281     printf("\n--- Bluetooth HID Device Test Console %s ---\n", bd_addr_to_str(iut_address));
282     printf("\n");
283     printf("---\n");
284     printf("Ctrl-c - exit\n");
285     printf("---\n");
286 }
287 
288 static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type){
289     UNUSED(ds);
290     UNUSED(callback_type);
291 
292     char cmd = btstack_stdin_read();
293     // switch (cmd){
294     //     default:
295     //         show_usage();
296     //         break;
297     // }
298 
299     // naive translation
300     if (cmd >= 'a' && cmd <= 'z'){
301         send_key(0, cmd - 'a' + 0x04);
302         return;
303     }
304     if (cmd >= 'A' && cmd <= 'Z'){
305         send_key(2, cmd - 'A' + 0x04);
306         return;
307     }
308     if (cmd == '0'){
309         send_key(0, 0x27);
310         return;
311     }
312     if (cmd == 127){
313         send_key(0, 0x2a);
314         return;
315     }
316     if (cmd == ' '){
317         send_key(0, 0x2c);
318         return;
319     }
320     if (cmd >= '1' && cmd <= '9'){
321        send_key(0, cmd - '1' + 0x1e);
322         return;
323     }
324 
325     show_usage();
326 }
327 #endif
328 
329 static int hid_connected(void){
330     return hid_control_cid && hid_interrupt_cid;
331 }
332 
333 static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * packet, uint16_t packet_size){
334     UNUSED(channel);
335     UNUSED(packet_size);
336     int connected_before;
337     switch (packet_type){
338         case HCI_EVENT_PACKET:
339             switch (packet[0]){
340                 case HCI_EVENT_USER_CONFIRMATION_REQUEST:
341                     // ssp: inform about user confirmation request
342                     log_info("SSP User Confirmation Request with numeric value '%06"PRIu32"'\n", hci_event_user_confirmation_request_get_numeric_value(packet));
343                     log_info("SSP User Confirmation Auto accept\n");
344                     break;
345 
346                 // into HID Device/Server
347                 case L2CAP_EVENT_INCOMING_CONNECTION:
348                     switch (l2cap_event_incoming_connection_get_psm(packet)){
349                         case PSM_HID_CONTROL:
350                         case PSM_HID_INTERRUPT:
351                             l2cap_accept_connection(channel);
352                             break;
353                         default:
354                             l2cap_decline_connection(channel);
355                             break;
356                     }
357                     break;
358                 case L2CAP_EVENT_CHANNEL_OPENED:
359                     if (packet[2]) return;
360                     connected_before = hid_connected();
361                     switch (l2cap_event_channel_opened_get_psm(packet)){
362                         case PSM_HID_CONTROL:
363                             hid_control_cid = l2cap_event_channel_opened_get_local_cid(packet);
364                             log_info("HID Control opened, cid 0x%02x", hid_control_cid);
365                             break;
366                         case PSM_HID_INTERRUPT:
367                             hid_interrupt_cid = l2cap_event_channel_opened_get_local_cid(packet);
368                             log_info("HID Interrupt opened, cid 0x%02x", hid_interrupt_cid);
369                             break;
370                         default:
371                             break;
372                     }
373                     if (!connected_before && hid_connected()){
374                         printf("HID Connected\n");
375                     }
376                     break;
377                 case L2CAP_EVENT_CHANNEL_CLOSED:
378                     connected_before = hid_connected();
379                     if (l2cap_event_channel_closed_get_local_cid(packet) == hid_control_cid){
380                         log_info("HID Control closed");
381                         hid_control_cid = 0;
382                     }
383                     if (l2cap_event_channel_closed_get_local_cid(packet) == hid_interrupt_cid){
384                         log_info("HID Interrupt closed");
385                         hid_interrupt_cid = 0;
386                     }
387                     if (connected_before && !hid_connected()){
388                         printf("HID Disconnected\n");
389                     }
390                     break;
391                 case L2CAP_EVENT_CAN_SEND_NOW:
392                     if (send_keycode){
393                         send_report(send_modifier, send_keycode);
394                         send_keycode = 0;
395                         send_modifier = 0;
396                         l2cap_request_can_send_now_event(hid_interrupt_cid);
397                     } else {
398                         send_report(0, 0);
399                     }
400                 default:
401                     break;
402             }
403             break;
404         default:
405             break;
406     }
407 }
408 
409 /* @section Main Application Setup
410  *
411  * @text Listing MainConfiguration shows main application code.
412  * To run a HID Device service you need to initialize the SDP, and to create and register HID Device record with it.
413  * At the end the Bluetooth stack is started.
414  */
415 
416 /* LISTING_START(MainConfiguration): Setup HID Device */
417 
418 int btstack_main(int argc, const char * argv[]);
419 int btstack_main(int argc, const char * argv[]){
420     (void)argc;
421     (void)argv;
422 
423     // register for HCI events
424     hci_event_callback_registration.callback = &packet_handler;
425     hci_add_event_handler(&hci_event_callback_registration);
426     hci_register_sco_packet_handler(&packet_handler);
427 
428     gap_discoverable_control(1);
429     gap_set_class_of_device(0x2540);
430     gap_set_local_name(hid_device_name);
431 
432     // L2CAP
433     l2cap_init();
434     l2cap_register_service(packet_handler, PSM_HID_INTERRUPT, 100, LEVEL_0);
435     l2cap_register_service(packet_handler, PSM_HID_CONTROL,   100, LEVEL_0);
436 
437     // SDP Server
438     sdp_init();
439     memset(hid_service_buffer, 0, sizeof(hid_service_buffer));
440     // hid sevice subclass 2540 Keyboard, hid counntry code 33 US, hid virtual cable off, hid reconnect initiate off, hid boot device off
441     hid_create_sdp_record(hid_service_buffer, 0x10001, 0x2540, 33, 0, 0, 0, hid_descriptor_keyboard_boot_mode, sizeof(hid_descriptor_keyboard_boot_mode), hid_device_name);
442     printf("SDP service record size: %u\n", de_get_len( hid_service_buffer));
443     sdp_register_service(hid_service_buffer);
444 
445 #ifdef HAVE_POSIX_STDIN
446     btstack_stdin_setup(stdin_process);
447 #endif
448     // turn on!
449     hci_power_control(HCI_POWER_ON);
450     return 0;
451 }
452 /* LISTING_END */
453 /* EXAMPLE_END */
454