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