xref: /btstack/src/btstack_hid_parser.c (revision c4241e61df634d103b90a40fb5ece7fd4bb9b48f)
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_usage_iterator_t * iterator, 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], iterator->descriptor[iterator->descriptor_pos], item->item_value);
143 #else
144     UNUSED(iterator);
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_usage_iterator_t * iterator, hid_descriptor_item_t * item){
204     switch((GlobalItemTag)item->item_tag){
205         case UsagePage:
206             iterator->global_usage_page = item->item_value;
207             break;
208         case LogicalMinimum:
209             iterator->global_logical_minimum = item->item_value;
210             break;
211         case LogicalMaximum:
212             iterator->global_logical_maximum = item->item_value;
213             break;
214         case ReportSize:
215             iterator->global_report_size = item->item_value;
216             break;
217         case ReportID:
218             iterator->global_report_id = item->item_value;
219             break;
220         case ReportCount:
221             iterator->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_usage_iterator_t * main_iterator){
240     bool have_usage_min = false;
241     bool have_usage_max = false;
242     main_iterator->usage_range = false;
243     btstack_hid_descriptor_iterator_t iterator;
244     btstack_hid_descriptor_iterator_init(&iterator, &main_iterator->descriptor[main_iterator->usage_pos], main_iterator->descriptor_len - main_iterator->usage_pos);
245     while ((main_iterator->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             main_iterator->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 : ((main_iterator->usage_page << 16u) | usage_item.item_value);
252             switch (usage_item.item_tag){
253                 case Usage:
254                     main_iterator->available_usages = 1;
255                     main_iterator->usage_minimum = usage_value;
256                     break;
257                 case UsageMinimum:
258                     main_iterator->usage_minimum = usage_value;
259                     have_usage_min = true;
260                     break;
261                 case UsageMaximum:
262                     main_iterator->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                 main_iterator->available_usages = main_iterator->usage_maximum - main_iterator->usage_minimum + 1u;
270                 main_iterator->usage_range = true;
271                 if (main_iterator->available_usages < main_iterator->required_usages){
272                     log_debug("Usage Min - Usage Max [%04"PRIx32"..%04"PRIx32"] < Report Count %u", main_iterator->usage_minimum & 0xffff, main_iterator->usage_maximum & 0xffff, main_iterator->required_usages);
273                 }
274             }
275         }
276     }
277     main_iterator->usage_pos += iterator.descriptor_pos;
278 }
279 
280 
281 // PUBLIC API
282 
283 // HID Descriptor Iterator
284 
285 void btstack_hid_descriptor_iterator_init(btstack_hid_descriptor_iterator_t * iterator, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len){
286     iterator->descriptor = hid_descriptor;
287     iterator->descriptor_pos = 0;
288     iterator->descriptor_len = hid_descriptor_len;
289     iterator->item_ready = false;
290     iterator->valid = true;
291 }
292 
293 bool btstack_hid_descriptor_iterator_has_more(btstack_hid_descriptor_iterator_t * iterator){
294     if ((iterator->item_ready == false) && (iterator->descriptor_len > iterator->descriptor_pos)){
295         uint16_t  item_len = iterator->descriptor_len - iterator->descriptor_pos;
296         const uint8_t *item_data = &iterator->descriptor[iterator->descriptor_pos];
297         bool ok = btstack_hid_parse_descriptor_item(&iterator->descriptor_item, item_data, item_len);
298         if (ok){
299             iterator->item_ready = true;
300         } else {
301             iterator->valid = false;
302         }
303     }
304     return iterator->item_ready;
305 }
306 
307 const hid_descriptor_item_t * const btstack_hid_descriptor_iterator_get_item(btstack_hid_descriptor_iterator_t * iterator){
308     iterator->descriptor_pos += iterator->descriptor_item.item_size;
309     iterator->item_ready = false;
310     return &iterator->descriptor_item;
311 }
312 
313 bool btstack_hid_descriptor_iterator_valid(btstack_hid_descriptor_iterator_t * iterator){
314     return iterator->valid;
315 }
316 
317 
318 int btstack_hid_get_report_size_for_id(uint16_t report_id, hid_report_type_t report_type, const uint8_t *hid_descriptor,
319                                        uint16_t hid_descriptor_len) {
320     int total_report_size = 0;
321     int report_size = 0;
322     int report_count = 0;
323     int current_report_id = HID_REPORT_ID_UNDEFINED;
324 
325     btstack_hid_descriptor_iterator_t iterator;
326     btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len);
327     while (btstack_hid_descriptor_iterator_has_more(&iterator)) {
328         const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator);
329         int valid_report_type = 0;
330         switch (item->item_type) {
331             case Global:
332                 switch ((GlobalItemTag) item->item_tag) {
333                     case ReportID:
334                         current_report_id = item->item_value;
335                         break;
336                     case ReportCount:
337                         report_count = item->item_value;
338                         break;
339                     case ReportSize:
340                         report_size = item->item_value;
341                         break;
342                     default:
343                         break;
344                 }
345                 break;
346             case Main:
347                 if (current_report_id != report_id) break;
348                 switch ((MainItemTag) item->item_tag) {
349                     case Input:
350                         if (report_type != HID_REPORT_TYPE_INPUT) break;
351                         valid_report_type = 1;
352                         break;
353                     case Output:
354                         if (report_type != HID_REPORT_TYPE_OUTPUT) break;
355                         valid_report_type = 1;
356                         break;
357                     case Feature:
358                         if (report_type != HID_REPORT_TYPE_FEATURE) break;
359                         valid_report_type = 1;
360                         break;
361                     default:
362                         break;
363                 }
364                 if (!valid_report_type) break;
365                 total_report_size += report_count * report_size;
366                 break;
367             default:
368                 break;
369         }
370         if (total_report_size > 0 && current_report_id != report_id) break;
371     }
372 
373     if (btstack_hid_descriptor_iterator_valid(&iterator)){
374         return (total_report_size + 7) / 8;
375     } else {
376         return 0;
377     }
378 }
379 
380 hid_report_id_status_t btstack_hid_report_id_valid(uint16_t report_id, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len){
381     uint16_t current_report_id = HID_REPORT_ID_UNDEFINED;
382     btstack_hid_descriptor_iterator_t iterator;
383     btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len);
384     bool report_id_found = false;
385     while (btstack_hid_descriptor_iterator_has_more(&iterator)) {
386         const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator);
387         switch (item->item_type){
388             case Global:
389                 switch ((GlobalItemTag)item->item_tag){
390                     case ReportID:
391                         current_report_id = item->item_value;
392                         if (current_report_id == report_id) {
393                             report_id_found = true;
394                         }
395                     default:
396                         break;
397                 }
398                 break;
399             default:
400                 break;
401         }
402     }
403 
404     if (btstack_hid_descriptor_iterator_valid(&iterator)) {
405         if (report_id_found){
406             return HID_REPORT_ID_VALID;
407         }
408         if ((report_id  == HID_REPORT_ID_UNDEFINED) && (current_report_id == HID_REPORT_ID_UNDEFINED)) {
409             return HID_REPORT_ID_VALID;
410         }
411         return HID_REPORT_ID_UNDECLARED;
412     } else {
413         return HID_REPORT_ID_INVALID;
414     }
415 }
416 
417 bool btstack_hid_report_id_declared(const uint8_t *hid_descriptor, uint16_t hid_descriptor_len) {
418     btstack_hid_descriptor_iterator_t iterator;
419     btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len);
420     while (btstack_hid_descriptor_iterator_has_more(&iterator)) {
421         const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator);
422         switch (item->item_type){
423             case Global:
424                 switch ((GlobalItemTag)item->item_tag){
425                     case ReportID:
426                         return true;
427                     default:
428                         break;
429                 }
430                 break;
431             default:
432                 break;
433         }
434     }
435     return false;
436 }
437 
438 // HID Descriptor Usage Iterator
439 
440 static void btstack_parser_usage_iterator_process_item(btstack_hid_usage_iterator_t * iterator, hid_descriptor_item_t * item){
441     hid_pretty_print_item(iterator, item);
442     int valid_field = 0;
443     uint16_t report_id_before;
444     switch ((TagType)item->item_type){
445         case Main:
446             valid_field = btstack_hid_main_item_tag_matches_report_type((MainItemTag) item->item_tag,
447                                                                         iterator->report_type);
448             break;
449         case Global:
450             report_id_before = iterator->global_report_id;
451             btstack_hid_handle_global_item(iterator, item);
452             // track record id for report handling, reset report position
453             if (report_id_before != iterator->global_report_id){
454                 iterator->report_pos_in_bit = 8u;
455             }
456             break;
457         case Local:
458         case Reserved:
459             break;
460         default:
461             btstack_assert(false);
462             break;
463     }
464     if (!valid_field) return;
465 
466     // handle constant fields used for padding
467     if (item->item_value & 1){
468         int item_bits = iterator->global_report_size * iterator->global_report_count;
469 #ifdef HID_PARSER_PRETTY_PRINT
470         log_info("- Skip %u constant bits", item_bits);
471 #endif
472         iterator->report_pos_in_bit += item_bits;
473         return;
474     }
475     // Empty Item
476     if (iterator->global_report_count == 0u) return;
477     // let's start
478     iterator->required_usages = iterator->global_report_count;
479 }
480 
481 static void btstack_hid_usage_iterator_find_next_usage(btstack_hid_usage_iterator_t * iterator) {
482     while (btstack_hid_descriptor_iterator_has_more(&iterator->descriptor_iterator)){
483         iterator->descriptor_item = * btstack_hid_descriptor_iterator_get_item(&iterator->descriptor_iterator);
484 
485         btstack_parser_usage_iterator_process_item(iterator, &iterator->descriptor_item);
486 
487         if (iterator->required_usages){
488             hid_find_next_usage(iterator);
489             if (iterator->available_usages) {
490                 iterator->state = BTSTACK_HID_USAGE_ITERATOR_USAGES_AVAILABLE;
491                 return;
492             } else {
493                 log_debug("no usages found");
494                 iterator->state = BTSTACK_HID_USAGE_ITERATOR_PARSER_COMPLETE;
495                 return;
496             }
497         } else {
498             if ((TagType) (&iterator->descriptor_item)->item_type == Main) {
499                 // reset usage
500                 iterator->usage_pos = iterator->descriptor_iterator.descriptor_pos;
501                 iterator->usage_page = iterator->global_usage_page;
502             }
503         }
504     }
505     // end of descriptor
506     iterator->state = BTSTACK_HID_USAGE_ITERATOR_PARSER_COMPLETE;
507 }
508 
509 void btstack_hid_usage_iterator_init(btstack_hid_usage_iterator_t * iterator, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len, hid_report_type_t hid_report_type){
510     memset(iterator, 0, sizeof(btstack_hid_usage_iterator_t));
511 
512     iterator->descriptor     = hid_descriptor;
513     iterator->descriptor_len = hid_descriptor_len;
514     iterator->report_type    = hid_report_type;
515     iterator->state          = BTSTACK_HID_USAGE_ITERATOR_STATE_SCAN_FOR_REPORT_ITEM;
516     iterator->global_report_id = HID_REPORT_ID_UNDEFINED;
517     btstack_hid_descriptor_iterator_init(&iterator->descriptor_iterator, hid_descriptor, hid_descriptor_len);
518 }
519 
520 bool btstack_hid_usage_iterator_has_more(btstack_hid_usage_iterator_t * iterator){
521     while (iterator->state == BTSTACK_HID_USAGE_ITERATOR_STATE_SCAN_FOR_REPORT_ITEM){
522         btstack_hid_usage_iterator_find_next_usage(iterator);
523     }
524     return iterator->state == BTSTACK_HID_USAGE_ITERATOR_USAGES_AVAILABLE;
525 }
526 
527 void btstack_hid_usage_iterator_get_item(btstack_hid_usage_iterator_t * iterator, btstack_hid_usage_item_t * item){
528     // cache current values
529     memset(item, 0, sizeof(btstack_hid_usage_item_t));
530     item->size = iterator->global_report_size;
531     item->report_id = iterator->global_report_id;
532     item->usage_page = iterator->usage_minimum >> 16;
533     item->bit_pos = iterator->report_pos_in_bit;
534 
535     bool is_variable  = (iterator->descriptor_item.item_value & 2) != 0;
536     if (is_variable){
537         item->usage = iterator->usage_minimum & 0xffffu;
538     }
539     iterator->required_usages--;
540     iterator->report_pos_in_bit += iterator->global_report_size;
541 
542     // cache descriptor item and
543     item->descriptor_item = iterator->descriptor_item;
544     item->global_logical_minimum = iterator->global_logical_minimum;
545 
546     // next usage
547     if (is_variable){
548         iterator->usage_minimum++;
549         iterator->available_usages--;
550         if (iterator->usage_range && (iterator->usage_minimum > iterator->usage_maximum)){
551             // usage min - max range smaller than report count, ignore remaining bit in report
552             log_debug("Ignoring %u items without Usage", parser->required_usages);
553             iterator->report_pos_in_bit += iterator->global_report_size * iterator->required_usages;
554             iterator->required_usages = 0;
555         }
556     } else {
557         if (iterator->required_usages == 0u){
558             iterator->available_usages = 0;
559         }
560     }
561 
562     if (iterator->available_usages) {
563         return;
564     }
565     if (iterator->required_usages == 0u){
566         iterator->state = BTSTACK_HID_USAGE_ITERATOR_STATE_SCAN_FOR_REPORT_ITEM;
567     } else {
568         hid_find_next_usage(iterator);
569         if (iterator->available_usages == 0u) {
570             iterator->state = BTSTACK_HID_USAGE_ITERATOR_PARSER_COMPLETE;
571         }
572     }
573 }
574 
575 
576 // HID Report Parser
577 
578 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){
579     btstack_hid_usage_iterator_init(&parser->usage_iterator, hid_descriptor, hid_descriptor_len, hid_report_type);
580     parser->report = hid_report;
581     parser->report_len = hid_report_len;
582     parser->have_report_usage_ready = false;
583 }
584 
585 /**
586  * @brief Checks if more fields are available
587  * @param parser
588  */
589 bool btstack_hid_parser_has_more(btstack_hid_parser_t * parser){
590     while ((parser->have_report_usage_ready == false) && btstack_hid_usage_iterator_has_more(&parser->usage_iterator)){
591         btstack_hid_usage_iterator_get_item(&parser->usage_iterator, &parser->descriptor__usage_item);
592         // ignore usages for other report ids
593         if (parser->descriptor__usage_item.report_id != HID_REPORT_ID_UNDEFINED){
594             if (parser->descriptor__usage_item.report_id != parser->report[0]){
595                 continue;
596             }
597         }
598         parser->have_report_usage_ready = true;
599     }
600     return parser->have_report_usage_ready;
601 }
602 
603 /**
604  * @brief Get next field
605  * @param parser
606  * @param usage_page
607  * @param usage
608  * @param value provided in HID report
609  */
610 
611 void btstack_hid_parser_get_field(btstack_hid_parser_t * parser, uint16_t * usage_page, uint16_t * usage, int32_t * value){
612 
613     // fetch data from descriptor usage item
614     uint16_t bit_pos = parser->descriptor__usage_item.bit_pos;
615     uint16_t size    = parser->descriptor__usage_item.size;
616     *usage_page      = parser->descriptor__usage_item.usage_page;
617     *usage           = parser->descriptor__usage_item.usage;
618 
619 
620     // read field (up to 32 bit unsigned, up to 31 bit signed - 32 bit signed behaviour is undefined) - check report len
621     bool is_variable   = (parser->descriptor__usage_item.descriptor_item.item_value & 2) != 0;
622     bool is_signed     = parser->descriptor__usage_item.global_logical_minimum < 0;
623     int pos_start     = btstack_min(  bit_pos >> 3, parser->report_len);
624     int pos_end       = btstack_min( (bit_pos + size - 1u) >> 3u, parser->report_len);
625     int bytes_to_read = pos_end - pos_start + 1;
626 
627     int i;
628     uint32_t multi_byte_value = 0;
629     for (i=0;i < bytes_to_read;i++){
630         multi_byte_value |= parser->report[pos_start+i] << (i*8);
631     }
632     uint32_t unsigned_value = (multi_byte_value >> (bit_pos & 0x07u)) & ((1u<<size)-1u);
633     // 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);
634     if (is_variable){
635         if (is_signed && (unsigned_value & (1u<<(size-1u)))){
636             *value = unsigned_value - (1u<<size);
637         } else {
638             *value = unsigned_value;
639         }
640     } else {
641         *usage  = unsigned_value;
642         *value  = 1;
643     }
644 
645     parser->have_report_usage_ready = false;
646 }
647