xref: /btstack/src/btstack_hid_parser.c (revision 960622b07234680cab982d9522c2f2b2781dacab)
1 /*
2  * Copyright (C) 2017 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 BLUEKITCHEN
24  * GMBH 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__ "btstack_hid_parser.c"
39 
40 #include <inttypes.h>
41 #include <string.h>
42 
43 #include "btstack_hid_parser.h"
44 #include "btstack_util.h"
45 #include "btstack_debug.h"
46 
47 // Not implemented:
48 // - Support for Push/Pop
49 // - Optional Pretty Print of HID Descripor
50 // - Support to query descriptort for contained usages, e.g. to detect keyboard or mouse
51 
52 // #define HID_PARSER_PRETTY_PRINT
53 
54 /*
55  *  btstack_hid_parser.c
56  */
57 
58 #ifdef HID_PARSER_PRETTY_PRINT
59 
60 static const char * type_names[] = {
61     "Main",
62     "Global",
63     "Local",
64     "Reserved"
65 };
66 static const char * main_tags[] = {
67     "",
68     "",
69     "",
70     "",
71     "",
72     "",
73     "",
74     "",
75     "Input ",
76     "Output",
77     "Collection",
78     "Feature",
79     "End Collection",
80     "Reserved",
81     "Reserved",
82     "Reserved"
83 };
84 static const char * global_tags[] = {
85     "Usage Page",
86     "Logical Minimum",
87     "Logical Maximum",
88     "Physical Minimum",
89     "Physical Maximum",
90     "Unit Exponent",
91     "Unit",
92     "Report Size",
93     "Report ID",
94     "Report Count",
95     "Push",
96     "Pop",
97     "Reserved",
98     "Reserved",
99     "Reserved",
100     "Reserved"
101 };
102 static const char * local_tags[] = {
103     "Usage",
104     "Usage Minimum",
105     "Usage Maximum",
106     "Designator Index",
107     "Designator Minimum",
108     "Designator Maximum",
109     "String Index",
110     "String Minimum",
111     "String Maximum",
112     "Delimiter",
113     "Reserved",
114     "Reserved",
115     "Reserved",
116     "Reserved",
117     "Reserved",
118     "Reserved"
119 };
120 #endif
121 
122 static void hid_pretty_print_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){
123 #ifdef HID_PARSER_PRETTY_PRINT
124     const char ** item_tag_table;
125     switch ((TagType)item->item_type){
126         case Main:
127             item_tag_table = main_tags;
128             break;
129         case Global:
130             item_tag_table = global_tags;
131             break;
132         case Local:
133             item_tag_table = local_tags;
134             break;
135         default:
136             item_tag_table = NULL;
137             break;
138     }
139     const char * item_tag_name = "Invalid";
140     if (item_tag_table){
141         item_tag_name = item_tag_table[item->item_tag];
142     }
143     log_info("%-15s (%-6s) // %02x 0x%0008x", item_tag_name, type_names[item->item_type], parser->descriptor[parser->descriptor_pos], item->item_value);
144 #else
145     UNUSED(parser);
146     UNUSED(item);
147 #endif
148 }
149 
150 // parse descriptor item and read up to 32-bit bit value
151 bool btstack_hid_parse_descriptor_item(hid_descriptor_item_t * item, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len){
152 
153     const int hid_item_sizes[] = { 0, 1, 2, 4 };
154 
155     // parse item header
156     if (hid_descriptor_len < 1u) return false;
157     uint16_t pos = 0;
158     uint8_t item_header = hid_descriptor[pos++];
159     item->data_size = hid_item_sizes[item_header & 0x03u];
160     item->item_type = (item_header & 0x0cu) >> 2u;
161     item->item_tag  = (item_header & 0xf0u) >> 4u;
162     // long item
163     if ((item->data_size == 2u) && (item->item_tag == 0x0fu) && (item->item_type == 3u)){
164         if (hid_descriptor_len < 3u) return false;
165         item->data_size = hid_descriptor[pos++];
166         item->item_tag  = hid_descriptor[pos++];
167     }
168     item->item_size =  pos + item->data_size;
169     item->item_value = 0;
170 
171     // read item value
172     if (hid_descriptor_len < item->item_size) return false;
173     if (item->data_size > 4u) return false;
174     int i;
175     int sgnd = (item->item_type == Global) && (item->item_tag > 0u) && (item->item_tag < 5u);
176     int32_t value = 0;
177     uint8_t latest_byte = 0;
178     for (i=0;i<item->data_size;i++){
179         latest_byte = hid_descriptor[pos++];
180         value = (latest_byte << (8*i)) | value;
181     }
182     if (sgnd && (item->data_size > 0u)){
183         if (latest_byte & 0x80u) {
184             value -= 1u << (item->data_size*8u);
185         }
186     }
187     item->item_value = value;
188     return true;
189 }
190 
191 static void btstack_hid_handle_global_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){
192     switch((GlobalItemTag)item->item_tag){
193         case UsagePage:
194             parser->global_usage_page = item->item_value;
195             break;
196         case LogicalMinimum:
197             parser->global_logical_minimum = item->item_value;
198             break;
199         case LogicalMaximum:
200             parser->global_logical_maximum = item->item_value;
201             break;
202         case ReportSize:
203             parser->global_report_size = item->item_value;
204             break;
205         case ReportID:
206             parser->global_report_id = item->item_value;
207             break;
208         case ReportCount:
209             parser->global_report_count = item->item_value;
210             break;
211 
212         // TODO handle tags
213         case PhysicalMinimum:
214         case PhysicalMaximum:
215         case UnitExponent:
216         case Unit:
217         case Push:
218         case Pop:
219             break;
220 
221         default:
222             btstack_assert(false);
223             break;
224     }
225 }
226 
227 static void hid_find_next_usage(btstack_hid_parser_t * parser){
228     bool have_usage_min = false;
229     bool have_usage_max = false;
230     parser->usage_range = false;
231     while ((parser->available_usages == 0u) && (parser->usage_pos < parser->descriptor_pos)){
232         hid_descriptor_item_t usage_item;
233         // parser->usage_pos < parser->descriptor_pos < parser->descriptor_len
234         bool ok = btstack_hid_parse_descriptor_item(&usage_item, &parser->descriptor[parser->usage_pos], parser->descriptor_len - parser->usage_pos);
235         if (ok == false){
236             break;
237         }
238         if ((usage_item.item_type == Global) && (usage_item.item_tag == UsagePage)){
239             parser->usage_page = usage_item.item_value;
240         }
241         if (usage_item.item_type == Local){
242             uint32_t usage_value = (usage_item.data_size > 2u) ? usage_item.item_value : ((parser->usage_page << 16u) | usage_item.item_value);
243             switch (usage_item.item_tag){
244                 case Usage:
245                     parser->available_usages = 1;
246                     parser->usage_minimum = usage_value;
247                     break;
248                 case UsageMinimum:
249                     parser->usage_minimum = usage_value;
250                     have_usage_min = true;
251                     break;
252                 case UsageMaximum:
253                     parser->usage_maximum = usage_value;
254                     have_usage_max = true;
255                     break;
256                 default:
257                     break;
258             }
259             if (have_usage_min && have_usage_max){
260                 parser->available_usages = parser->usage_maximum - parser->usage_minimum + 1u;
261                 parser->usage_range = true;
262                 if (parser->available_usages < parser->required_usages){
263                     log_debug("Usage Min - Usage Max [%04"PRIx32"..%04"PRIx32"] < Report Count %u", parser->usage_minimum & 0xffff, parser->usage_maximum & 0xffff, parser->required_usages);
264                 }
265             }
266         }
267         parser->usage_pos += usage_item.item_size;
268     }
269 }
270 
271 static void hid_process_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){
272     hid_pretty_print_item(parser, item);
273     int valid_field = 0;
274     uint16_t report_id_before;
275     switch ((TagType)item->item_type){
276         case Main:
277             switch ((MainItemTag)item->item_tag){
278                 case Input:
279                     valid_field = parser->report_type == HID_REPORT_TYPE_INPUT;
280                     break;
281                 case Output:
282                     valid_field = parser->report_type == HID_REPORT_TYPE_OUTPUT;
283                     break;
284                 case Feature:
285                     valid_field = parser->report_type == HID_REPORT_TYPE_FEATURE;
286                     break;
287                 default:
288                     break;
289             }
290             break;
291         case Global:
292             report_id_before = parser->global_report_id;
293             btstack_hid_handle_global_item(parser, item);
294             // track record id for report handling
295             if ((GlobalItemTag)item->item_tag == ReportID){
296                 if (parser->active_record && (report_id_before != item->item_value)){
297                     parser->active_record = 0;
298                 }
299             }
300             break;
301         case Local:
302         case Reserved:
303             break;
304         default:
305             btstack_assert(false);
306             break;
307     }
308     if (!valid_field) return;
309 
310     // verify record id
311     if (parser->global_report_id && !parser->active_record){
312         if (parser->report[0] != parser->global_report_id){
313             return;
314         }
315         parser->report_pos_in_bit += 8u;
316     }
317     parser->active_record = 1;
318     // handle constant fields used for padding
319     if (item->item_value & 1){
320         int item_bits = parser->global_report_size * parser->global_report_count;
321 #ifdef HID_PARSER_PRETTY_PRINT
322         log_info("- Skip %u constant bits", item_bits);
323 #endif
324         parser->report_pos_in_bit += item_bits;
325         return;
326     }
327     // Empty Item
328     if (parser->global_report_count == 0u) return;
329     // let's start
330     parser->required_usages = parser->global_report_count;
331 }
332 
333 static void hid_post_process_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){
334     if ((TagType)item->item_type == Main){
335         // reset usage
336         parser->usage_pos  = parser->descriptor_pos;
337         parser->usage_page = parser->global_usage_page;
338     }
339     parser->descriptor_pos += item->item_size;
340 }
341 
342 static void btstack_hid_parser_find_next_usage(btstack_hid_parser_t * parser){
343     while (parser->state == BTSTACK_HID_PARSER_SCAN_FOR_REPORT_ITEM){
344         if (parser->descriptor_pos >= parser->descriptor_len){
345             // end of descriptor
346             parser->state = BTSTACK_HID_PARSER_COMPLETE;
347             break;
348         }
349         bool ok = btstack_hid_parse_descriptor_item(&parser->descriptor_item, &parser->descriptor[parser->descriptor_pos], parser->descriptor_len - parser->descriptor_pos);
350         if (ok == false){
351             // abort parsing
352             parser->state = BTSTACK_HID_PARSER_COMPLETE;
353             break;
354         }
355         hid_process_item(parser, &parser->descriptor_item);
356         if (parser->required_usages){
357             hid_find_next_usage(parser);
358             if (parser->available_usages) {
359                 parser->state = BTSTACK_HID_PARSER_USAGES_AVAILABLE;
360             } else {
361                 log_debug("no usages found");
362                 parser->state = BTSTACK_HID_PARSER_COMPLETE;
363             }
364         } else {
365             hid_post_process_item(parser, &parser->descriptor_item);
366         }
367     }
368 }
369 
370 // PUBLIC API
371 
372 void btstack_hid_parser_init(btstack_hid_parser_t * parser, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len, hid_report_type_t hid_report_type, const uint8_t * hid_report, uint16_t hid_report_len){
373 
374     memset(parser, 0, sizeof(btstack_hid_parser_t));
375 
376     parser->descriptor     = hid_descriptor;
377     parser->descriptor_len = hid_descriptor_len;
378     parser->report_type    = hid_report_type;
379     parser->report         = hid_report;
380     parser->report_len     = hid_report_len;
381     parser->state          = BTSTACK_HID_PARSER_SCAN_FOR_REPORT_ITEM;
382 
383     btstack_hid_parser_find_next_usage(parser);
384 }
385 
386 bool btstack_hid_parser_has_more(btstack_hid_parser_t * parser){
387     return parser->state == BTSTACK_HID_PARSER_USAGES_AVAILABLE;
388 }
389 
390 void btstack_hid_parser_get_field(btstack_hid_parser_t * parser, uint16_t * usage_page, uint16_t * usage, int32_t * value){
391 
392     *usage_page = parser->usage_minimum >> 16;
393 
394     // read field (up to 32 bit unsigned, up to 31 bit signed - 32 bit signed behaviour is undefined) - check report len
395     bool is_variable   = (parser->descriptor_item.item_value & 2) != 0;
396     bool is_signed     = parser->global_logical_minimum < 0;
397     int pos_start     = btstack_min(  parser->report_pos_in_bit >> 3, parser->report_len);
398     int pos_end       = btstack_min( (parser->report_pos_in_bit + parser->global_report_size - 1u) >> 3u, parser->report_len);
399     int bytes_to_read = pos_end - pos_start + 1;
400     int i;
401     uint32_t multi_byte_value = 0;
402     for (i=0;i < bytes_to_read;i++){
403         multi_byte_value |= parser->report[pos_start+i] << (i*8);
404     }
405     uint32_t unsigned_value = (multi_byte_value >> (parser->report_pos_in_bit & 0x07u)) & ((1u<<parser->global_report_size)-1u);
406     // log_debug("bit pos %2u, report size %u, start %u, end %u, len %u;; unsigned value %08x", parser->report_pos_in_bit, parser->global_report_size, pos_start, pos_end, parser->report_len, unsigned_value);
407     if (is_variable){
408         *usage      = parser->usage_minimum & 0xffffu;
409         if (is_signed && (unsigned_value & (1u<<(parser->global_report_size-1u)))){
410             *value = unsigned_value - (1u<<parser->global_report_size);
411         } else {
412             *value = unsigned_value;
413         }
414     } else {
415         *usage  = unsigned_value;
416         *value  = 1;
417     }
418     parser->required_usages--;
419     parser->report_pos_in_bit += parser->global_report_size;
420 
421     // next usage
422     if (is_variable){
423         parser->usage_minimum++;
424         parser->available_usages--;
425         if (parser->usage_range && (parser->usage_minimum > parser->usage_maximum)){
426             // usage min - max range smaller than report count, ignore remaining bit in report
427             log_debug("Ignoring %u items without Usage", parser->required_usages);
428             parser->report_pos_in_bit += parser->global_report_size * parser->required_usages;
429             parser->required_usages = 0;
430         }
431     } else {
432         if (parser->required_usages == 0u){
433             parser->available_usages = 0;
434         }
435     }
436     if (parser->available_usages) {
437         return;
438     }
439     if (parser->required_usages == 0u){
440         hid_post_process_item(parser, &parser->descriptor_item);
441         parser->state = BTSTACK_HID_PARSER_SCAN_FOR_REPORT_ITEM;
442         btstack_hid_parser_find_next_usage(parser);
443     } else {
444         hid_find_next_usage(parser);
445         if (parser->available_usages == 0u) {
446             parser->state = BTSTACK_HID_PARSER_COMPLETE;
447         }
448     }
449 }
450 
451 void btstack_hid_descriptor_iterator_init(btstack_hid_descriptor_iterator_t * iterator, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len){
452     iterator->descriptor = hid_descriptor;
453     iterator->descriptor_pos = 0;
454     iterator->descriptor_len = hid_descriptor_len;
455     iterator->item_ready = false;
456     iterator->valid = true;
457 }
458 
459 bool btstack_hid_descriptor_iterator_has_more(btstack_hid_descriptor_iterator_t * iterator){
460     if ((iterator->item_ready == false) && (iterator->descriptor_len > 0)){
461         uint16_t  item_len = iterator->descriptor_len - iterator->descriptor_pos;
462         const uint8_t *item_data = &iterator->descriptor[iterator->descriptor_pos];
463         bool ok = btstack_hid_parse_descriptor_item(&iterator->descriptor_item, item_data, item_len);
464         if (ok){
465             iterator->item_ready = true;
466         } else {
467             iterator->valid = false;
468         }
469     }
470     return iterator->item_ready;
471 }
472 
473 const hid_descriptor_item_t * const btstack_hid_descriptor_iterator_get_item(btstack_hid_descriptor_iterator_t * iterator){
474 
475     btstack_assert(iterator->descriptor_len >= iterator->descriptor_item.item_size);
476 
477     iterator->descriptor_len -= iterator->descriptor_item.item_size;
478     iterator->descriptor     += iterator->descriptor_item.item_size;
479     iterator->item_ready = false;
480     return &iterator->descriptor_item;
481 }
482 
483 bool btstack_hid_descriptor_iterator_valid(btstack_hid_descriptor_iterator_t * iterator){
484     return iterator->valid;
485 }
486 
487 int btstack_hid_get_report_size_for_id(int report_id, hid_report_type_t report_type, uint16_t hid_descriptor_len, const uint8_t * hid_descriptor) {
488     int total_report_size = 0;
489     int report_size = 0;
490     int report_count = 0;
491     int current_report_id = 0;
492 
493     btstack_hid_descriptor_iterator_t iterator;
494     btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len);
495     while (btstack_hid_descriptor_iterator_has_more(&iterator)) {
496         const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator);
497         int valid_report_type = 0;
498         switch (item->item_type) {
499             case Global:
500                 switch ((GlobalItemTag) item->item_tag) {
501                     case ReportID:
502                         current_report_id = item->item_value;
503                         break;
504                     case ReportCount:
505                         report_count = item->item_value;
506                         break;
507                     case ReportSize:
508                         report_size = item->item_value;
509                         break;
510                     default:
511                         break;
512                 }
513                 break;
514             case Main:
515                 if (current_report_id != report_id) break;
516                 switch ((MainItemTag) item->item_tag) {
517                     case Input:
518                         if (report_type != HID_REPORT_TYPE_INPUT) break;
519                         valid_report_type = 1;
520                         break;
521                     case Output:
522                         if (report_type != HID_REPORT_TYPE_OUTPUT) break;
523                         valid_report_type = 1;
524                         break;
525                     case Feature:
526                         if (report_type != HID_REPORT_TYPE_FEATURE) break;
527                         valid_report_type = 1;
528                         break;
529                     default:
530                         break;
531                 }
532                 if (!valid_report_type) break;
533                 total_report_size += report_count * report_size;
534                 break;
535             default:
536                 break;
537         }
538         if (total_report_size > 0 && current_report_id != report_id) break;
539     }
540 
541     if (btstack_hid_descriptor_iterator_valid(&iterator)){
542         return (total_report_size + 7) / 8;
543     } else {
544         return 0;
545     }
546 }
547 
548 hid_report_id_status_t btstack_hid_id_valid(int report_id, uint16_t hid_descriptor_len, const uint8_t * hid_descriptor){
549     int current_report_id = -1;
550     btstack_hid_descriptor_iterator_t iterator;
551     btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len);
552     while (btstack_hid_descriptor_iterator_has_more(&iterator)) {
553         const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator);
554         switch (item->item_type){
555             case Global:
556                 switch ((GlobalItemTag)item->item_tag){
557                     case ReportID:
558                         current_report_id = item->item_value;
559                         if (current_report_id != report_id) break;
560                         return HID_REPORT_ID_VALID;
561                     default:
562                         break;
563                 }
564                 break;
565             default:
566                 break;
567         }
568     }
569 
570     if (btstack_hid_descriptor_iterator_valid(&iterator)) {
571         if (current_report_id != -1) {
572             return HID_REPORT_ID_INVALID;
573         } else {
574             return HID_REPORT_ID_UNDECLARED;
575         }
576     } else {
577         return HID_REPORT_ID_INVALID;
578     }
579 }
580 
581 bool btstack_hid_report_id_declared(uint16_t hid_descriptor_len, const uint8_t * hid_descriptor){
582     btstack_hid_descriptor_iterator_t iterator;
583     btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len);
584     while (btstack_hid_descriptor_iterator_has_more(&iterator)) {
585         const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator);
586         switch (item->item_type){
587             case Global:
588                 switch ((GlobalItemTag)item->item_tag){
589                     case ReportID:
590                         return true;
591                     default:
592                         break;
593                 }
594                 break;
595             default:
596                 break;
597         }
598     }
599     return false;
600 }
601