xref: /btstack/src/btstack_hid_parser.c (revision cdb96ae56a3e1cf8f717b5b9363b5402275fc879)
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 bool btstack_hid_main_item_tag_matches_report_type(MainItemTag tag, hid_report_type_t report_type){
192     switch (tag){
193         case Input:
194             return report_type == HID_REPORT_TYPE_INPUT;
195         case Output:
196             return report_type == HID_REPORT_TYPE_OUTPUT;
197         case Feature:
198             return report_type == HID_REPORT_TYPE_FEATURE;
199         default:
200             return false;
201     }
202 }
203 
204 static void btstack_hid_handle_global_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){
205     switch((GlobalItemTag)item->item_tag){
206         case UsagePage:
207             parser->global_usage_page = item->item_value;
208             break;
209         case LogicalMinimum:
210             parser->global_logical_minimum = item->item_value;
211             break;
212         case LogicalMaximum:
213             parser->global_logical_maximum = item->item_value;
214             break;
215         case ReportSize:
216             parser->global_report_size = item->item_value;
217             break;
218         case ReportID:
219             parser->global_report_id = item->item_value;
220             break;
221         case ReportCount:
222             parser->global_report_count = item->item_value;
223             break;
224 
225         // TODO handle tags
226         case PhysicalMinimum:
227         case PhysicalMaximum:
228         case UnitExponent:
229         case Unit:
230         case Push:
231         case Pop:
232             break;
233 
234         default:
235             btstack_assert(false);
236             break;
237     }
238 }
239 
240 static void hid_find_next_usage(btstack_hid_parser_t * parser){
241     bool have_usage_min = false;
242     bool have_usage_max = false;
243     parser->usage_range = false;
244     btstack_hid_descriptor_iterator_t iterator;
245     btstack_hid_descriptor_iterator_init(&iterator, &parser->descriptor[parser->usage_pos], parser->descriptor_len - parser->usage_pos);
246     while ((parser->available_usages == 0u) && btstack_hid_descriptor_iterator_has_more(&iterator) ){
247         hid_descriptor_item_t usage_item = *btstack_hid_descriptor_iterator_get_item(&iterator);
248         if ((usage_item.item_type == Global) && (usage_item.item_tag == UsagePage)){
249             parser->usage_page = usage_item.item_value;
250         }
251         if (usage_item.item_type == Local){
252             uint32_t usage_value = (usage_item.data_size > 2u) ? usage_item.item_value : ((parser->usage_page << 16u) | usage_item.item_value);
253             switch (usage_item.item_tag){
254                 case Usage:
255                     parser->available_usages = 1;
256                     parser->usage_minimum = usage_value;
257                     break;
258                 case UsageMinimum:
259                     parser->usage_minimum = usage_value;
260                     have_usage_min = true;
261                     break;
262                 case UsageMaximum:
263                     parser->usage_maximum = usage_value;
264                     have_usage_max = true;
265                     break;
266                 default:
267                     break;
268             }
269             if (have_usage_min && have_usage_max){
270                 parser->available_usages = parser->usage_maximum - parser->usage_minimum + 1u;
271                 parser->usage_range = true;
272                 if (parser->available_usages < parser->required_usages){
273                     log_debug("Usage Min - Usage Max [%04"PRIx32"..%04"PRIx32"] < Report Count %u", parser->usage_minimum & 0xffff, parser->usage_maximum & 0xffff, parser->required_usages);
274                 }
275             }
276         }
277     }
278     parser->usage_pos += iterator.descriptor_pos;
279 }
280 
281 static void hid_process_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){
282     hid_pretty_print_item(parser, item);
283     int valid_field = 0;
284     uint16_t report_id_before;
285     switch ((TagType)item->item_type){
286         case Main:
287             valid_field = btstack_hid_main_item_tag_matches_report_type((MainItemTag) item->item_tag,
288                                                                         parser->report_type);
289             break;
290         case Global:
291             report_id_before = parser->global_report_id;
292             btstack_hid_handle_global_item(parser, item);
293             // track record id for report handling
294             if ((GlobalItemTag)item->item_tag == ReportID){
295                 if (parser->active_record && (report_id_before != item->item_value)){
296                     parser->active_record = 0;
297                 }
298             }
299             break;
300         case Local:
301         case Reserved:
302             break;
303         default:
304             btstack_assert(false);
305             break;
306     }
307     if (!valid_field) return;
308 
309     // verify record id
310     if (parser->global_report_id && !parser->active_record){
311         if (parser->report[0] != parser->global_report_id){
312             return;
313         }
314         parser->report_pos_in_bit += 8u;
315     }
316     parser->active_record = 1;
317     // handle constant fields used for padding
318     if (item->item_value & 1){
319         int item_bits = parser->global_report_size * parser->global_report_count;
320 #ifdef HID_PARSER_PRETTY_PRINT
321         log_info("- Skip %u constant bits", item_bits);
322 #endif
323         parser->report_pos_in_bit += item_bits;
324         return;
325     }
326     // Empty Item
327     if (parser->global_report_count == 0u) return;
328     // let's start
329     parser->required_usages = parser->global_report_count;
330 }
331 
332 static void btstack_hid_parser_find_next_usage(btstack_hid_parser_t * parser){
333     while (btstack_hid_descriptor_iterator_has_more(&parser->descriptor_iterator)){
334         parser->descriptor_item = * btstack_hid_descriptor_iterator_get_item(&parser->descriptor_iterator);
335         hid_process_item(parser, &parser->descriptor_item);
336         if (parser->required_usages){
337             hid_find_next_usage(parser);
338             if (parser->available_usages) {
339                 parser->state = BTSTACK_HID_PARSER_USAGES_AVAILABLE;
340                 return;
341             } else {
342                 log_debug("no usages found");
343                 parser->state = BTSTACK_HID_PARSER_COMPLETE;
344                 return;
345             }
346         } else {
347             if ((TagType) (&parser->descriptor_item)->item_type == Main) {
348                 // reset usage
349                 parser->usage_pos = parser->descriptor_iterator.descriptor_pos;
350                 parser->usage_page = parser->global_usage_page;
351             }
352         }
353     }
354     // end of descriptor
355     parser->state = BTSTACK_HID_PARSER_COMPLETE;
356 }
357 
358 // PUBLIC API
359 
360 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){
361 
362     memset(parser, 0, sizeof(btstack_hid_parser_t));
363 
364     parser->descriptor     = hid_descriptor;
365     parser->descriptor_len = hid_descriptor_len;
366     parser->report_type    = hid_report_type;
367     parser->report         = hid_report;
368     parser->report_len     = hid_report_len;
369     parser->state          = BTSTACK_HID_PARSER_SCAN_FOR_REPORT_ITEM;
370 
371     btstack_hid_descriptor_iterator_init(&parser->descriptor_iterator, hid_descriptor, hid_descriptor_len);
372 
373     btstack_hid_parser_find_next_usage(parser);
374 }
375 
376 bool btstack_hid_parser_has_more(btstack_hid_parser_t * parser){
377     return parser->state == BTSTACK_HID_PARSER_USAGES_AVAILABLE;
378 }
379 
380 void btstack_hid_parser_get_field(btstack_hid_parser_t * parser, uint16_t * usage_page, uint16_t * usage, int32_t * value){
381 
382     *usage_page = parser->usage_minimum >> 16;
383 
384     // read field (up to 32 bit unsigned, up to 31 bit signed - 32 bit signed behaviour is undefined) - check report len
385     bool is_variable   = (parser->descriptor_item.item_value & 2) != 0;
386     bool is_signed     = parser->global_logical_minimum < 0;
387     int pos_start     = btstack_min(  parser->report_pos_in_bit >> 3, parser->report_len);
388     int pos_end       = btstack_min( (parser->report_pos_in_bit + parser->global_report_size - 1u) >> 3u, parser->report_len);
389     int bytes_to_read = pos_end - pos_start + 1;
390     int i;
391     uint32_t multi_byte_value = 0;
392     for (i=0;i < bytes_to_read;i++){
393         multi_byte_value |= parser->report[pos_start+i] << (i*8);
394     }
395     uint32_t unsigned_value = (multi_byte_value >> (parser->report_pos_in_bit & 0x07u)) & ((1u<<parser->global_report_size)-1u);
396     // 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);
397     if (is_variable){
398         *usage      = parser->usage_minimum & 0xffffu;
399         if (is_signed && (unsigned_value & (1u<<(parser->global_report_size-1u)))){
400             *value = unsigned_value - (1u<<parser->global_report_size);
401         } else {
402             *value = unsigned_value;
403         }
404     } else {
405         *usage  = unsigned_value;
406         *value  = 1;
407     }
408     parser->required_usages--;
409     parser->report_pos_in_bit += parser->global_report_size;
410 
411     // next usage
412     if (is_variable){
413         parser->usage_minimum++;
414         parser->available_usages--;
415         if (parser->usage_range && (parser->usage_minimum > parser->usage_maximum)){
416             // usage min - max range smaller than report count, ignore remaining bit in report
417             log_debug("Ignoring %u items without Usage", parser->required_usages);
418             parser->report_pos_in_bit += parser->global_report_size * parser->required_usages;
419             parser->required_usages = 0;
420         }
421     } else {
422         if (parser->required_usages == 0u){
423             parser->available_usages = 0;
424         }
425     }
426     if (parser->available_usages) {
427         return;
428     }
429     if (parser->required_usages == 0u){
430         parser->state = BTSTACK_HID_PARSER_SCAN_FOR_REPORT_ITEM;
431         btstack_hid_parser_find_next_usage(parser);
432     } else {
433         hid_find_next_usage(parser);
434         if (parser->available_usages == 0u) {
435             parser->state = BTSTACK_HID_PARSER_COMPLETE;
436         }
437     }
438 }
439 
440 void btstack_hid_descriptor_iterator_init(btstack_hid_descriptor_iterator_t * iterator, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len){
441     iterator->descriptor = hid_descriptor;
442     iterator->descriptor_pos = 0;
443     iterator->descriptor_len = hid_descriptor_len;
444     iterator->item_ready = false;
445     iterator->valid = true;
446 }
447 
448 bool btstack_hid_descriptor_iterator_has_more(btstack_hid_descriptor_iterator_t * iterator){
449     if ((iterator->item_ready == false) && (iterator->descriptor_len > iterator->descriptor_pos)){
450         uint16_t  item_len = iterator->descriptor_len - iterator->descriptor_pos;
451         const uint8_t *item_data = &iterator->descriptor[iterator->descriptor_pos];
452         bool ok = btstack_hid_parse_descriptor_item(&iterator->descriptor_item, item_data, item_len);
453         if (ok){
454             iterator->item_ready = true;
455         } else {
456             iterator->valid = false;
457         }
458     }
459     return iterator->item_ready;
460 }
461 
462 const hid_descriptor_item_t * const btstack_hid_descriptor_iterator_get_item(btstack_hid_descriptor_iterator_t * iterator){
463     iterator->descriptor_pos += iterator->descriptor_item.item_size;
464     iterator->item_ready = false;
465     return &iterator->descriptor_item;
466 }
467 
468 bool btstack_hid_descriptor_iterator_valid(btstack_hid_descriptor_iterator_t * iterator){
469     return iterator->valid;
470 }
471 
472 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) {
473     int total_report_size = 0;
474     int report_size = 0;
475     int report_count = 0;
476     int current_report_id = 0;
477 
478     btstack_hid_descriptor_iterator_t iterator;
479     btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len);
480     while (btstack_hid_descriptor_iterator_has_more(&iterator)) {
481         const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator);
482         int valid_report_type = 0;
483         switch (item->item_type) {
484             case Global:
485                 switch ((GlobalItemTag) item->item_tag) {
486                     case ReportID:
487                         current_report_id = item->item_value;
488                         break;
489                     case ReportCount:
490                         report_count = item->item_value;
491                         break;
492                     case ReportSize:
493                         report_size = item->item_value;
494                         break;
495                     default:
496                         break;
497                 }
498                 break;
499             case Main:
500                 if (current_report_id != report_id) break;
501                 switch ((MainItemTag) item->item_tag) {
502                     case Input:
503                         if (report_type != HID_REPORT_TYPE_INPUT) break;
504                         valid_report_type = 1;
505                         break;
506                     case Output:
507                         if (report_type != HID_REPORT_TYPE_OUTPUT) break;
508                         valid_report_type = 1;
509                         break;
510                     case Feature:
511                         if (report_type != HID_REPORT_TYPE_FEATURE) break;
512                         valid_report_type = 1;
513                         break;
514                     default:
515                         break;
516                 }
517                 if (!valid_report_type) break;
518                 total_report_size += report_count * report_size;
519                 break;
520             default:
521                 break;
522         }
523         if (total_report_size > 0 && current_report_id != report_id) break;
524     }
525 
526     if (btstack_hid_descriptor_iterator_valid(&iterator)){
527         return (total_report_size + 7) / 8;
528     } else {
529         return 0;
530     }
531 }
532 
533 hid_report_id_status_t btstack_hid_id_valid(int report_id, uint16_t hid_descriptor_len, const uint8_t * hid_descriptor){
534     int current_report_id = -1;
535     btstack_hid_descriptor_iterator_t iterator;
536     btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len);
537     while (btstack_hid_descriptor_iterator_has_more(&iterator)) {
538         const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator);
539         switch (item->item_type){
540             case Global:
541                 switch ((GlobalItemTag)item->item_tag){
542                     case ReportID:
543                         current_report_id = item->item_value;
544                         if (current_report_id != report_id) break;
545                         return HID_REPORT_ID_VALID;
546                     default:
547                         break;
548                 }
549                 break;
550             default:
551                 break;
552         }
553     }
554 
555     if (btstack_hid_descriptor_iterator_valid(&iterator)) {
556         if (current_report_id != -1) {
557             return HID_REPORT_ID_INVALID;
558         } else {
559             return HID_REPORT_ID_UNDECLARED;
560         }
561     } else {
562         return HID_REPORT_ID_INVALID;
563     }
564 }
565 
566 bool btstack_hid_report_id_declared(uint16_t hid_descriptor_len, const uint8_t * hid_descriptor){
567     btstack_hid_descriptor_iterator_t iterator;
568     btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len);
569     while (btstack_hid_descriptor_iterator_has_more(&iterator)) {
570         const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator);
571         switch (item->item_type){
572             case Global:
573                 switch ((GlobalItemTag)item->item_tag){
574                     case ReportID:
575                         return true;
576                     default:
577                         break;
578                 }
579                 break;
580             default:
581                 break;
582         }
583     }
584     return false;
585 }
586 
587 static void btstack_parser_usage_iterator_process_item2(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){
588     hid_pretty_print_item(parser, item);
589     int valid_field = 0;
590     uint16_t report_id_before;
591     switch ((TagType)item->item_type){
592         case Main:
593             valid_field = btstack_hid_main_item_tag_matches_report_type((MainItemTag) item->item_tag,
594                                                                         parser->report_type);
595             break;
596         case Global:
597             report_id_before = parser->global_report_id;
598             btstack_hid_handle_global_item(parser, item);
599             // track record id for report handling, reset report position
600             if (report_id_before != parser->global_report_id){
601                 parser->report_pos_in_bit = 8u;
602             }
603             break;
604         case Local:
605         case Reserved:
606             break;
607         default:
608             btstack_assert(false);
609             break;
610     }
611     if (!valid_field) return;
612 
613     // handle constant fields used for padding
614     if (item->item_value & 1){
615         int item_bits = parser->global_report_size * parser->global_report_count;
616 #ifdef HID_PARSER_PRETTY_PRINT
617         log_info("- Skip %u constant bits", item_bits);
618 #endif
619         parser->report_pos_in_bit += item_bits;
620         return;
621     }
622     // Empty Item
623     if (parser->global_report_count == 0u) return;
624     // let's start
625     parser->required_usages = parser->global_report_count;
626 }
627 
628 static void btstack_hid_usage_iterator_find_next_usage(btstack_hid_parser_t * parser) {
629     while (btstack_hid_descriptor_iterator_has_more(&parser->descriptor_iterator)){
630         parser->descriptor_item = * btstack_hid_descriptor_iterator_get_item(&parser->descriptor_iterator);
631 
632         btstack_parser_usage_iterator_process_item2(parser, &parser->descriptor_item);
633 
634         if (parser->required_usages){
635             hid_find_next_usage(parser);
636             if (parser->available_usages) {
637                 parser->state = BTSTACK_HID_PARSER_USAGES_AVAILABLE;
638                 return;
639             } else {
640                 log_debug("no usages found");
641                 parser->state = BTSTACK_HID_PARSER_COMPLETE;
642                 return;
643             }
644         } else {
645             if ((TagType) (&parser->descriptor_item)->item_type == Main) {
646                 // reset usage
647                 parser->usage_pos = parser->descriptor_iterator.descriptor_pos;
648                 parser->usage_page = parser->global_usage_page;
649             }
650         }
651     }
652     // end of descriptor
653     parser->state = BTSTACK_HID_PARSER_COMPLETE;
654 }
655 
656 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){
657     memset(parser, 0, sizeof(btstack_hid_parser_t));
658 
659     parser->descriptor     = hid_descriptor;
660     parser->descriptor_len = hid_descriptor_len;
661     parser->report_type    = hid_report_type;
662     parser->state          = BTSTACK_HID_PARSER_SCAN_FOR_REPORT_ITEM;
663     btstack_hid_descriptor_iterator_init(&parser->descriptor_iterator, hid_descriptor, hid_descriptor_len);
664 
665     btstack_hid_usage_iterator_find_next_usage(parser);
666 }
667 
668 bool btstack_hid_usage_iterator_has_more(btstack_hid_parser_t * parser){
669     return parser->state == BTSTACK_HID_PARSER_USAGES_AVAILABLE;
670 }
671 
672 void btstack_hid_usage_iterator_get_item(btstack_hid_parser_t * parser, btstack_hid_usage_item_t * item){
673     // cache current values
674     memset(item, 0, sizeof(btstack_hid_usage_item_t));
675     item->size = parser->global_report_size;
676     item->report_id = parser->global_report_id;
677     item->usage_page = parser->usage_minimum >> 16;
678     item->bit_pos = parser->report_pos_in_bit;
679 
680     bool is_variable  = (parser->descriptor_item.item_value & 2) != 0;
681     if (is_variable){
682         item->usage = parser->usage_minimum & 0xffffu;
683     }
684     parser->required_usages--;
685     parser->report_pos_in_bit += parser->global_report_size;
686 
687     // next usage
688     if (is_variable){
689         parser->usage_minimum++;
690         parser->available_usages--;
691         if (parser->usage_range && (parser->usage_minimum > parser->usage_maximum)){
692             // usage min - max range smaller than report count, ignore remaining bit in report
693             log_debug("Ignoring %u items without Usage", parser->required_usages);
694             parser->report_pos_in_bit += parser->global_report_size * parser->required_usages;
695             parser->required_usages = 0;
696         }
697     } else {
698         if (parser->required_usages == 0u){
699             parser->available_usages = 0;
700         }
701     }
702     if (parser->available_usages) {
703         return;
704     }
705     if (parser->required_usages == 0u){
706         parser->state = BTSTACK_HID_PARSER_SCAN_FOR_REPORT_ITEM;
707         btstack_hid_usage_iterator_find_next_usage(parser);
708     } else {
709         hid_find_next_usage(parser);
710         if (parser->available_usages == 0u) {
711             parser->state = BTSTACK_HID_PARSER_COMPLETE;
712         }
713     }
714 }
715 
716 //