xref: /btstack/example/hid_keyboard_demo.c (revision ca44a803f13415bf37ec56c98a364f2a2a9e62d2)
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 //
122 
123 #define CHAR_ILLEGAL     0xff
124 #define CHAR_RETURN     '\n'
125 #define CHAR_ESCAPE      27
126 #define CHAR_TAB         '\t'
127 #define CHAR_BACKSPACE   0x7f
128 
129 // Simplified US Keyboard with Shift modifier
130 
131 /**
132  * English (US)
133  */
134 static const uint8_t keytable_us_none [] = {
135     CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL,             /*   0-3 */
136     'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',                   /*  4-13 */
137     'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',                   /* 14-23 */
138     'u', 'v', 'w', 'x', 'y', 'z',                                       /* 24-29 */
139     '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',                   /* 30-39 */
140     CHAR_RETURN, CHAR_ESCAPE, CHAR_BACKSPACE, CHAR_TAB, ' ',            /* 40-44 */
141     '-', '=', '[', ']', '\\', CHAR_ILLEGAL, ';', '\'', 0x60, ',',       /* 45-54 */
142     '.', '/', CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL,   /* 55-60 */
143     CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL,             /* 61-64 */
144     CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL,             /* 65-68 */
145     CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL,             /* 69-72 */
146     CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL,             /* 73-76 */
147     CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL,             /* 77-80 */
148     CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL,             /* 81-84 */
149     '*', '-', '+', '\n', '1', '2', '3', '4', '5',                       /* 85-97 */
150     '6', '7', '8', '9', '0', '.', 0xa7,                                 /* 97-100 */
151 };
152 
153 static const uint8_t keytable_us_shift[] = {
154     CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL,             /*  0-3  */
155     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',                   /*  4-13 */
156     'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',                   /* 14-23 */
157     'U', 'V', 'W', 'X', 'Y', 'Z',                                       /* 24-29 */
158     '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',                   /* 30-39 */
159     CHAR_RETURN, CHAR_ESCAPE, CHAR_BACKSPACE, CHAR_TAB, ' ',            /* 40-44 */
160     '_', '+', '{', '}', '|', CHAR_ILLEGAL, ':', '"', 0x7E, '<',         /* 45-54 */
161     '>', '?', CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL,   /* 55-60 */
162     CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL,             /* 61-64 */
163     CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL,             /* 65-68 */
164     CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL,             /* 69-72 */
165     CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL,             /* 73-76 */
166     CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL,             /* 77-80 */
167     CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL,             /* 81-84 */
168     '*', '-', '+', '\n', '1', '2', '3', '4', '5',                       /* 85-97 */
169     '6', '7', '8', '9', '0', '.', 0xb1,                                 /* 97-100 */
170 };
171 
172 
173 void hid_create_sdp_record(
174     uint8_t *service,
175     uint32_t service_record_handle,
176     uint16_t hid_device_subclass,
177     uint8_t  hid_country_code,
178     uint8_t  hid_virtual_cable,
179     uint8_t  hid_reconnect_initiate,
180     uint8_t  hid_boot_device,
181     const uint8_t * hid_descriptor, uint16_t hid_descriptor_size,
182     const char *device_name);
183 
184 void hid_create_sdp_record(
185     uint8_t *service,
186     uint32_t service_record_handle,
187     uint16_t hid_device_subclass,
188     uint8_t  hid_country_code,
189     uint8_t  hid_virtual_cable,
190     uint8_t  hid_reconnect_initiate,
191     uint8_t  hid_boot_device,
192     const uint8_t * hid_descriptor, uint16_t hid_descriptor_size,
193     const char *device_name){
194 
195     uint8_t * attribute;
196     de_create_sequence(service);
197 
198     de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_RECORD_HANDLE);
199     de_add_number(service, DE_UINT, DE_SIZE_32, service_record_handle);
200 
201     de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST);
202     attribute = de_push_sequence(service);
203     {
204         de_add_number(attribute,  DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE_SERVICE);
205     }
206     de_pop_sequence(service, attribute);
207 
208     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST);
209     attribute = de_push_sequence(service);
210     {
211         uint8_t * l2cpProtocol = de_push_sequence(attribute);
212         {
213             de_add_number(l2cpProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_L2CAP);
214             de_add_number(l2cpProtocol,  DE_UINT, DE_SIZE_16, PSM_HID_CONTROL);
215         }
216         de_pop_sequence(attribute, l2cpProtocol);
217 
218         uint8_t * hidProtocol = de_push_sequence(attribute);
219         {
220             de_add_number(hidProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_HIDP);
221         }
222         de_pop_sequence(attribute, hidProtocol);
223     }
224     de_pop_sequence(service, attribute);
225 
226     // TODO?
227     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
228     attribute = de_push_sequence(service);
229     {
230         de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x656e);
231         de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x006a);
232         de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x0100);
233     }
234     de_pop_sequence(service, attribute);
235 
236     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS);
237     attribute = de_push_sequence(service);
238     {
239         uint8_t * additionalDescriptorAttribute = de_push_sequence(attribute);
240         {
241             uint8_t * l2cpProtocol = de_push_sequence(additionalDescriptorAttribute);
242             {
243                 de_add_number(l2cpProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_L2CAP);
244                 de_add_number(l2cpProtocol,  DE_UINT, DE_SIZE_16, PSM_HID_INTERRUPT);
245             }
246             de_pop_sequence(additionalDescriptorAttribute, l2cpProtocol);
247 
248             uint8_t * hidProtocol = de_push_sequence(attribute);
249             {
250                 de_add_number(hidProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_HIDP);
251             }
252             de_pop_sequence(attribute, hidProtocol);
253         }
254         de_pop_sequence(attribute, additionalDescriptorAttribute);
255     }
256     de_pop_sequence(service, attribute);
257 
258     // 0x0100 "ServiceName"
259     de_add_number(service,  DE_UINT, DE_SIZE_16, 0x0100);
260     de_add_data(service,  DE_STRING, strlen(device_name), (uint8_t *) device_name);
261 
262     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
263     attribute = de_push_sequence(service);
264     {
265         uint8_t * hidProfile = de_push_sequence(attribute);
266         {
267             de_add_number(hidProfile,  DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE_SERVICE);
268             de_add_number(hidProfile,  DE_UINT, DE_SIZE_16, 0x0101);    // Version 1.1
269         }
270         de_pop_sequence(attribute, hidProfile);
271     }
272     de_pop_sequence(service, attribute);
273 
274     // Deprecated in v1.1.1
275     // de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_DEVICE_RELEASE_NUMBER);
276     // de_add_number(service,  DE_UINT, DE_SIZE_16, 0x0101);
277 
278     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_PARSER_VERSION);
279     de_add_number(service,  DE_UINT, DE_SIZE_16, 0x0111);  // v1.1.1
280 
281     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_DEVICE_SUBCLASS);
282     de_add_number(service,  DE_UINT, DE_SIZE_16, hid_device_subclass);
283 
284     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_COUNTRY_CODE);
285     de_add_number(service,  DE_UINT, DE_SIZE_16, hid_country_code);
286 
287     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_VIRTUAL_CABLE);
288     de_add_number(service,  DE_BOOL, DE_SIZE_8,  hid_virtual_cable);
289 
290     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_RECONNECT_INITIATE);
291     de_add_number(service,  DE_BOOL, DE_SIZE_8,  hid_reconnect_initiate);
292 
293     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_DESCRIPTOR_LIST);
294     attribute = de_push_sequence(service);
295     {
296         uint8_t* hidDescriptor = de_push_sequence(attribute);
297         {
298             de_add_number(hidDescriptor,  DE_UINT, DE_SIZE_8, 0x22);    // Report Descriptor
299             de_add_data(hidDescriptor,  DE_STRING, hid_descriptor_size, (uint8_t *) hid_descriptor);
300         }
301         de_pop_sequence(attribute, hidDescriptor);
302     }
303     de_pop_sequence(service, attribute);
304 
305     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_BOOT_DEVICE);
306     de_add_number(service,  DE_BOOL, DE_SIZE_8,  hid_boot_device);
307 }
308 
309 // HID Keyboard lookup
310 static int lookup_keycode(uint8_t character, const uint8_t * table, int size, uint8_t * keycode){
311     int i;
312     for (i=0;i<size;i++){
313         if (table[i] != character) continue;
314         *keycode = i;
315         return 1;
316     }
317     return 0;
318 }
319 
320 static int keycode_and_modifer_us_for_character(uint8_t character, uint8_t * keycode, uint8_t * modifier){
321     int found;
322     found = lookup_keycode(character, keytable_us_none, sizeof(keytable_us_none), keycode);
323     if (found) {
324         *modifier = 0;  // none
325         return 1;
326     }
327     found = lookup_keycode(character, keytable_us_shift, sizeof(keytable_us_shift), keycode);
328     if (found) {
329         *modifier = 2;  // shift
330         return 1;
331     }
332     return 0;
333 }
334 
335 // HID Report sending
336 static int send_keycode;
337 static int send_modifier;
338 
339 static void send_key(int modifier, int keycode){
340     send_keycode = keycode;
341     send_modifier = modifier;
342     l2cap_request_can_send_now_event(hid_interrupt_cid);
343 }
344 
345 static void send_report(int modifier, int keycode){
346     uint8_t report[] = { 0xa1, modifier, 0, 0, keycode, 0, 0, 0, 0, 0};
347     l2cap_send(hid_interrupt_cid, &report[0], sizeof(report));
348 }
349 
350 
351 
352 #ifdef HAVE_POSIX_STDIN
353 
354 // prototypes
355 static void show_usage(void);
356 
357 // Testig User Interface
358 static void show_usage(void){
359     bd_addr_t iut_address;
360     gap_local_bd_addr(iut_address);
361 
362     printf("\n--- Bluetooth HID Device Test Console %s ---\n", bd_addr_to_str(iut_address));
363     printf("\n");
364     printf("---\n");
365     printf("Ctrl-c - exit\n");
366     printf("---\n");
367 }
368 
369 static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type){
370     UNUSED(ds);
371     UNUSED(callback_type);
372 
373     char character = btstack_stdin_read();
374 
375     uint8_t modifier;
376     uint8_t keycode;
377     int found = keycode_and_modifer_us_for_character(character, &keycode, &modifier);
378     if (found){
379         send_key(modifier, keycode);
380         return;
381     }
382     show_usage();
383 }
384 #endif
385 
386 static int hid_connected(void){
387     return hid_control_cid && hid_interrupt_cid;
388 }
389 
390 static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * packet, uint16_t packet_size){
391     UNUSED(channel);
392     UNUSED(packet_size);
393     int connected_before;
394     switch (packet_type){
395         case HCI_EVENT_PACKET:
396             switch (packet[0]){
397                 case HCI_EVENT_USER_CONFIRMATION_REQUEST:
398                     // ssp: inform about user confirmation request
399                     log_info("SSP User Confirmation Request with numeric value '%06"PRIu32"'\n", hci_event_user_confirmation_request_get_numeric_value(packet));
400                     log_info("SSP User Confirmation Auto accept\n");
401                     break;
402 
403                 // into HID Device/Server
404                 case L2CAP_EVENT_INCOMING_CONNECTION:
405                     switch (l2cap_event_incoming_connection_get_psm(packet)){
406                         case PSM_HID_CONTROL:
407                         case PSM_HID_INTERRUPT:
408                             l2cap_accept_connection(channel);
409                             break;
410                         default:
411                             l2cap_decline_connection(channel);
412                             break;
413                     }
414                     break;
415                 case L2CAP_EVENT_CHANNEL_OPENED:
416                     if (packet[2]) return;
417                     connected_before = hid_connected();
418                     switch (l2cap_event_channel_opened_get_psm(packet)){
419                         case PSM_HID_CONTROL:
420                             hid_control_cid = l2cap_event_channel_opened_get_local_cid(packet);
421                             log_info("HID Control opened, cid 0x%02x", hid_control_cid);
422                             break;
423                         case PSM_HID_INTERRUPT:
424                             hid_interrupt_cid = l2cap_event_channel_opened_get_local_cid(packet);
425                             log_info("HID Interrupt opened, cid 0x%02x", hid_interrupt_cid);
426                             break;
427                         default:
428                             break;
429                     }
430                     if (!connected_before && hid_connected()){
431                         printf("HID Connected\n");
432                     }
433                     break;
434                 case L2CAP_EVENT_CHANNEL_CLOSED:
435                     connected_before = hid_connected();
436                     if (l2cap_event_channel_closed_get_local_cid(packet) == hid_control_cid){
437                         log_info("HID Control closed");
438                         hid_control_cid = 0;
439                     }
440                     if (l2cap_event_channel_closed_get_local_cid(packet) == hid_interrupt_cid){
441                         log_info("HID Interrupt closed");
442                         hid_interrupt_cid = 0;
443                     }
444                     if (connected_before && !hid_connected()){
445                         printf("HID Disconnected\n");
446                     }
447                     break;
448                 case L2CAP_EVENT_CAN_SEND_NOW:
449                     if (send_keycode){
450                         send_report(send_modifier, send_keycode);
451                         send_keycode = 0;
452                         send_modifier = 0;
453                         l2cap_request_can_send_now_event(hid_interrupt_cid);
454                     } else {
455                         send_report(0, 0);
456                     }
457                 default:
458                     break;
459             }
460             break;
461         default:
462             break;
463     }
464 }
465 
466 /* @section Main Application Setup
467  *
468  * @text Listing MainConfiguration shows main application code.
469  * To run a HID Device service you need to initialize the SDP, and to create and register HID Device record with it.
470  * At the end the Bluetooth stack is started.
471  */
472 
473 /* LISTING_START(MainConfiguration): Setup HID Device */
474 
475 int btstack_main(int argc, const char * argv[]);
476 int btstack_main(int argc, const char * argv[]){
477     (void)argc;
478     (void)argv;
479 
480     // register for HCI events
481     hci_event_callback_registration.callback = &packet_handler;
482     hci_add_event_handler(&hci_event_callback_registration);
483     hci_register_sco_packet_handler(&packet_handler);
484 
485     gap_discoverable_control(1);
486     gap_set_class_of_device(0x2540);
487     gap_set_local_name(hid_device_name);
488 
489     // L2CAP
490     l2cap_init();
491     l2cap_register_service(packet_handler, PSM_HID_INTERRUPT, 100, LEVEL_0);
492     l2cap_register_service(packet_handler, PSM_HID_CONTROL,   100, LEVEL_0);
493 
494     // SDP Server
495     sdp_init();
496     memset(hid_service_buffer, 0, sizeof(hid_service_buffer));
497     // hid sevice subclass 2540 Keyboard, hid counntry code 33 US, hid virtual cable off, hid reconnect initiate off, hid boot device off
498     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);
499     printf("SDP service record size: %u\n", de_get_len( hid_service_buffer));
500     sdp_register_service(hid_service_buffer);
501 
502 #ifdef HAVE_POSIX_STDIN
503     btstack_stdin_setup(stdin_process);
504 #endif
505     // turn on!
506     hci_power_control(HCI_POWER_ON);
507     return 0;
508 }
509 /* LISTING_END */
510 /* EXAMPLE_END */
511