xref: /btstack/src/btstack_hid_parser.c (revision c4241e61df634d103b90a40fb5ece7fd4bb9b48f)
112ccb71bSMatthias Ringwald /*
212ccb71bSMatthias Ringwald  * Copyright (C) 2017 BlueKitchen GmbH
312ccb71bSMatthias Ringwald  *
412ccb71bSMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
512ccb71bSMatthias Ringwald  * modification, are permitted provided that the following conditions
612ccb71bSMatthias Ringwald  * are met:
712ccb71bSMatthias Ringwald  *
812ccb71bSMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
912ccb71bSMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
1012ccb71bSMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
1112ccb71bSMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
1212ccb71bSMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
1312ccb71bSMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
1412ccb71bSMatthias Ringwald  *    contributors may be used to endorse or promote products derived
1512ccb71bSMatthias Ringwald  *    from this software without specific prior written permission.
1612ccb71bSMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
1712ccb71bSMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
1812ccb71bSMatthias Ringwald  *    monetary gain.
1912ccb71bSMatthias Ringwald  *
2012ccb71bSMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
2112ccb71bSMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2212ccb71bSMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
232fca4dadSMilanka Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
242fca4dadSMilanka Ringwald  * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2512ccb71bSMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2612ccb71bSMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
2712ccb71bSMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2812ccb71bSMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2912ccb71bSMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
3012ccb71bSMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3112ccb71bSMatthias Ringwald  * SUCH DAMAGE.
3212ccb71bSMatthias Ringwald  *
3312ccb71bSMatthias Ringwald  * Please inquire about commercial licensing options at
3412ccb71bSMatthias Ringwald  * [email protected]
3512ccb71bSMatthias Ringwald  *
3612ccb71bSMatthias Ringwald  */
3712ccb71bSMatthias Ringwald 
38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "btstack_hid_parser.c"
3912ccb71bSMatthias Ringwald 
40cb406331SDirk Helbig #include <inttypes.h>
4112ccb71bSMatthias Ringwald #include <string.h>
4212ccb71bSMatthias Ringwald 
4312ccb71bSMatthias Ringwald #include "btstack_hid_parser.h"
4412ccb71bSMatthias Ringwald #include "btstack_util.h"
4512ccb71bSMatthias Ringwald #include "btstack_debug.h"
4612ccb71bSMatthias Ringwald 
4712ccb71bSMatthias Ringwald // Not implemented:
4812ccb71bSMatthias Ringwald // - Support for Push/Pop
490ba748f2SMatthias Ringwald // - Optional Pretty Print of HID Descriptor
5012ccb71bSMatthias Ringwald 
5112ccb71bSMatthias Ringwald // #define HID_PARSER_PRETTY_PRINT
5212ccb71bSMatthias Ringwald 
5312ccb71bSMatthias Ringwald /*
5412ccb71bSMatthias Ringwald  *  btstack_hid_parser.c
5512ccb71bSMatthias Ringwald  */
5612ccb71bSMatthias Ringwald 
5712ccb71bSMatthias Ringwald #ifdef HID_PARSER_PRETTY_PRINT
5812ccb71bSMatthias Ringwald 
5912ccb71bSMatthias Ringwald static const char * type_names[] = {
6012ccb71bSMatthias Ringwald     "Main",
6112ccb71bSMatthias Ringwald     "Global",
6212ccb71bSMatthias Ringwald     "Local",
6312ccb71bSMatthias Ringwald     "Reserved"
6412ccb71bSMatthias Ringwald };
6512ccb71bSMatthias Ringwald static const char * main_tags[] = {
6612ccb71bSMatthias Ringwald     "",
6712ccb71bSMatthias Ringwald     "",
6812ccb71bSMatthias Ringwald     "",
6912ccb71bSMatthias Ringwald     "",
7012ccb71bSMatthias Ringwald     "",
7112ccb71bSMatthias Ringwald     "",
7212ccb71bSMatthias Ringwald     "",
7312ccb71bSMatthias Ringwald     "",
7412ccb71bSMatthias Ringwald     "Input ",
7512ccb71bSMatthias Ringwald     "Output",
7612ccb71bSMatthias Ringwald     "Collection",
7712ccb71bSMatthias Ringwald     "Feature",
7812ccb71bSMatthias Ringwald     "End Collection",
7912ccb71bSMatthias Ringwald     "Reserved",
8012ccb71bSMatthias Ringwald     "Reserved",
8112ccb71bSMatthias Ringwald     "Reserved"
8212ccb71bSMatthias Ringwald };
8312ccb71bSMatthias Ringwald static const char * global_tags[] = {
8412ccb71bSMatthias Ringwald     "Usage Page",
8512ccb71bSMatthias Ringwald     "Logical Minimum",
8612ccb71bSMatthias Ringwald     "Logical Maximum",
8712ccb71bSMatthias Ringwald     "Physical Minimum",
8812ccb71bSMatthias Ringwald     "Physical Maximum",
8912ccb71bSMatthias Ringwald     "Unit Exponent",
9012ccb71bSMatthias Ringwald     "Unit",
9112ccb71bSMatthias Ringwald     "Report Size",
9212ccb71bSMatthias Ringwald     "Report ID",
9312ccb71bSMatthias Ringwald     "Report Count",
9412ccb71bSMatthias Ringwald     "Push",
9512ccb71bSMatthias Ringwald     "Pop",
9612ccb71bSMatthias Ringwald     "Reserved",
9712ccb71bSMatthias Ringwald     "Reserved",
9812ccb71bSMatthias Ringwald     "Reserved",
9912ccb71bSMatthias Ringwald     "Reserved"
10012ccb71bSMatthias Ringwald };
10112ccb71bSMatthias Ringwald static const char * local_tags[] = {
10212ccb71bSMatthias Ringwald     "Usage",
10312ccb71bSMatthias Ringwald     "Usage Minimum",
10412ccb71bSMatthias Ringwald     "Usage Maximum",
10512ccb71bSMatthias Ringwald     "Designator Index",
10612ccb71bSMatthias Ringwald     "Designator Minimum",
10712ccb71bSMatthias Ringwald     "Designator Maximum",
10812ccb71bSMatthias Ringwald     "String Index",
10912ccb71bSMatthias Ringwald     "String Minimum",
11012ccb71bSMatthias Ringwald     "String Maximum",
11112ccb71bSMatthias Ringwald     "Delimiter",
11212ccb71bSMatthias Ringwald     "Reserved",
11312ccb71bSMatthias Ringwald     "Reserved",
11412ccb71bSMatthias Ringwald     "Reserved",
11512ccb71bSMatthias Ringwald     "Reserved",
11612ccb71bSMatthias Ringwald     "Reserved",
11712ccb71bSMatthias Ringwald     "Reserved"
11812ccb71bSMatthias Ringwald };
11912ccb71bSMatthias Ringwald #endif
12012ccb71bSMatthias Ringwald 
121*c4241e61SMatthias Ringwald static void hid_pretty_print_item(btstack_hid_usage_iterator_t * iterator, hid_descriptor_item_t * item){
12212ccb71bSMatthias Ringwald #ifdef HID_PARSER_PRETTY_PRINT
12312ccb71bSMatthias Ringwald     const char ** item_tag_table;
1247bbeb3adSMilanka Ringwald     switch ((TagType)item->item_type){
12512ccb71bSMatthias Ringwald         case Main:
12612ccb71bSMatthias Ringwald             item_tag_table = main_tags;
12712ccb71bSMatthias Ringwald             break;
12812ccb71bSMatthias Ringwald         case Global:
12912ccb71bSMatthias Ringwald             item_tag_table = global_tags;
13012ccb71bSMatthias Ringwald             break;
13112ccb71bSMatthias Ringwald         case Local:
13212ccb71bSMatthias Ringwald             item_tag_table = local_tags;
13312ccb71bSMatthias Ringwald             break;
13412ccb71bSMatthias Ringwald         default:
13512ccb71bSMatthias Ringwald             item_tag_table = NULL;
13612ccb71bSMatthias Ringwald             break;
13712ccb71bSMatthias Ringwald     }
13812ccb71bSMatthias Ringwald     const char * item_tag_name = "Invalid";
13912ccb71bSMatthias Ringwald     if (item_tag_table){
14012ccb71bSMatthias Ringwald         item_tag_name = item_tag_table[item->item_tag];
14112ccb71bSMatthias Ringwald     }
142*c4241e61SMatthias Ringwald     log_info("%-15s (%-6s) // %02x 0x%0008x", item_tag_name, type_names[item->item_type], iterator->descriptor[iterator->descriptor_pos], item->item_value);
14312ccb71bSMatthias Ringwald #else
144*c4241e61SMatthias Ringwald     UNUSED(iterator);
14512ccb71bSMatthias Ringwald     UNUSED(item);
14612ccb71bSMatthias Ringwald #endif
14712ccb71bSMatthias Ringwald }
14812ccb71bSMatthias Ringwald 
14912ccb71bSMatthias Ringwald // parse descriptor item and read up to 32-bit bit value
15076fa2448SMatthias Ringwald bool btstack_hid_parse_descriptor_item(hid_descriptor_item_t * item, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len){
1518334d3d8SMatthias Ringwald 
1528334d3d8SMatthias Ringwald     const int hid_item_sizes[] = { 0, 1, 2, 4 };
1538334d3d8SMatthias Ringwald 
15412ccb71bSMatthias Ringwald     // parse item header
15576fa2448SMatthias Ringwald     if (hid_descriptor_len < 1u) return false;
15612ccb71bSMatthias Ringwald     uint16_t pos = 0;
15712ccb71bSMatthias Ringwald     uint8_t item_header = hid_descriptor[pos++];
1584ea43905SMatthias Ringwald     item->data_size = hid_item_sizes[item_header & 0x03u];
1594ea43905SMatthias Ringwald     item->item_type = (item_header & 0x0cu) >> 2u;
1604ea43905SMatthias Ringwald     item->item_tag  = (item_header & 0xf0u) >> 4u;
16112ccb71bSMatthias Ringwald     // long item
1624ea43905SMatthias Ringwald     if ((item->data_size == 2u) && (item->item_tag == 0x0fu) && (item->item_type == 3u)){
16376fa2448SMatthias Ringwald         if (hid_descriptor_len < 3u) return false;
16412ccb71bSMatthias Ringwald         item->data_size = hid_descriptor[pos++];
16512ccb71bSMatthias Ringwald         item->item_tag  = hid_descriptor[pos++];
16612ccb71bSMatthias Ringwald     }
16712ccb71bSMatthias Ringwald     item->item_size =  pos + item->data_size;
16812ccb71bSMatthias Ringwald     item->item_value = 0;
16912ccb71bSMatthias Ringwald 
17012ccb71bSMatthias Ringwald     // read item value
17176fa2448SMatthias Ringwald     if (hid_descriptor_len < item->item_size) return false;
17276fa2448SMatthias Ringwald     if (item->data_size > 4u) return false;
17312ccb71bSMatthias Ringwald     int i;
1744ea43905SMatthias Ringwald     int sgnd = (item->item_type == Global) && (item->item_tag > 0u) && (item->item_tag < 5u);
17512ccb71bSMatthias Ringwald     int32_t value = 0;
17612ccb71bSMatthias Ringwald     uint8_t latest_byte = 0;
17712ccb71bSMatthias Ringwald     for (i=0;i<item->data_size;i++){
17812ccb71bSMatthias Ringwald         latest_byte = hid_descriptor[pos++];
17912ccb71bSMatthias Ringwald         value = (latest_byte << (8*i)) | value;
18012ccb71bSMatthias Ringwald     }
1814ea43905SMatthias Ringwald     if (sgnd && (item->data_size > 0u)){
1824ea43905SMatthias Ringwald         if (latest_byte & 0x80u) {
1834ea43905SMatthias Ringwald             value -= 1u << (item->data_size*8u);
18412ccb71bSMatthias Ringwald         }
18512ccb71bSMatthias Ringwald     }
18612ccb71bSMatthias Ringwald     item->item_value = value;
18776fa2448SMatthias Ringwald     return true;
18812ccb71bSMatthias Ringwald }
18912ccb71bSMatthias Ringwald 
1900a4fc5fbSMatthias Ringwald static bool btstack_hid_main_item_tag_matches_report_type(MainItemTag tag, hid_report_type_t report_type){
1910a4fc5fbSMatthias Ringwald     switch (tag){
1920a4fc5fbSMatthias Ringwald         case Input:
1930a4fc5fbSMatthias Ringwald             return report_type == HID_REPORT_TYPE_INPUT;
1940a4fc5fbSMatthias Ringwald         case Output:
1950a4fc5fbSMatthias Ringwald             return report_type == HID_REPORT_TYPE_OUTPUT;
1960a4fc5fbSMatthias Ringwald         case Feature:
1970a4fc5fbSMatthias Ringwald             return report_type == HID_REPORT_TYPE_FEATURE;
1980a4fc5fbSMatthias Ringwald         default:
1990a4fc5fbSMatthias Ringwald             return false;
2000a4fc5fbSMatthias Ringwald     }
2010a4fc5fbSMatthias Ringwald }
2020a4fc5fbSMatthias Ringwald 
203*c4241e61SMatthias Ringwald static void btstack_hid_handle_global_item(btstack_hid_usage_iterator_t * iterator, hid_descriptor_item_t * item){
2047bbeb3adSMilanka Ringwald     switch((GlobalItemTag)item->item_tag){
20512ccb71bSMatthias Ringwald         case UsagePage:
206*c4241e61SMatthias Ringwald             iterator->global_usage_page = item->item_value;
20712ccb71bSMatthias Ringwald             break;
20812ccb71bSMatthias Ringwald         case LogicalMinimum:
209*c4241e61SMatthias Ringwald             iterator->global_logical_minimum = item->item_value;
21012ccb71bSMatthias Ringwald             break;
21112ccb71bSMatthias Ringwald         case LogicalMaximum:
212*c4241e61SMatthias Ringwald             iterator->global_logical_maximum = item->item_value;
21312ccb71bSMatthias Ringwald             break;
21412ccb71bSMatthias Ringwald         case ReportSize:
215*c4241e61SMatthias Ringwald             iterator->global_report_size = item->item_value;
21612ccb71bSMatthias Ringwald             break;
21712ccb71bSMatthias Ringwald         case ReportID:
218*c4241e61SMatthias Ringwald             iterator->global_report_id = item->item_value;
21912ccb71bSMatthias Ringwald             break;
22012ccb71bSMatthias Ringwald         case ReportCount:
221*c4241e61SMatthias Ringwald             iterator->global_report_count = item->item_value;
22212ccb71bSMatthias Ringwald             break;
2237bbeb3adSMilanka Ringwald 
2247bbeb3adSMilanka Ringwald         // TODO handle tags
2257bbeb3adSMilanka Ringwald         case PhysicalMinimum:
2267bbeb3adSMilanka Ringwald         case PhysicalMaximum:
2277bbeb3adSMilanka Ringwald         case UnitExponent:
2287bbeb3adSMilanka Ringwald         case Unit:
2297bbeb3adSMilanka Ringwald         case Push:
2307bbeb3adSMilanka Ringwald         case Pop:
2317bbeb3adSMilanka Ringwald             break;
2327bbeb3adSMilanka Ringwald 
23312ccb71bSMatthias Ringwald         default:
2347bbeb3adSMilanka Ringwald             btstack_assert(false);
23512ccb71bSMatthias Ringwald             break;
23612ccb71bSMatthias Ringwald     }
23712ccb71bSMatthias Ringwald }
23812ccb71bSMatthias Ringwald 
239*c4241e61SMatthias Ringwald static void hid_find_next_usage(btstack_hid_usage_iterator_t * main_iterator){
2401a05cde1SMatthias Ringwald     bool have_usage_min = false;
2411a05cde1SMatthias Ringwald     bool have_usage_max = false;
242*c4241e61SMatthias Ringwald     main_iterator->usage_range = false;
24341afcabaSMatthias Ringwald     btstack_hid_descriptor_iterator_t iterator;
244*c4241e61SMatthias Ringwald     btstack_hid_descriptor_iterator_init(&iterator, &main_iterator->descriptor[main_iterator->usage_pos], main_iterator->descriptor_len - main_iterator->usage_pos);
245*c4241e61SMatthias Ringwald     while ((main_iterator->available_usages == 0u) && btstack_hid_descriptor_iterator_has_more(&iterator) ){
24641afcabaSMatthias Ringwald         hid_descriptor_item_t usage_item = *btstack_hid_descriptor_iterator_get_item(&iterator);
2470e588213SMatthias Ringwald         if ((usage_item.item_type == Global) && (usage_item.item_tag == UsagePage)){
248*c4241e61SMatthias Ringwald             main_iterator->usage_page = usage_item.item_value;
24912ccb71bSMatthias Ringwald         }
25012ccb71bSMatthias Ringwald         if (usage_item.item_type == Local){
251*c4241e61SMatthias Ringwald             uint32_t usage_value = (usage_item.data_size > 2u) ? usage_item.item_value : ((main_iterator->usage_page << 16u) | usage_item.item_value);
25212ccb71bSMatthias Ringwald             switch (usage_item.item_tag){
25312ccb71bSMatthias Ringwald                 case Usage:
254*c4241e61SMatthias Ringwald                     main_iterator->available_usages = 1;
255*c4241e61SMatthias Ringwald                     main_iterator->usage_minimum = usage_value;
25612ccb71bSMatthias Ringwald                     break;
25712ccb71bSMatthias Ringwald                 case UsageMinimum:
258*c4241e61SMatthias Ringwald                     main_iterator->usage_minimum = usage_value;
2591a05cde1SMatthias Ringwald                     have_usage_min = true;
26012ccb71bSMatthias Ringwald                     break;
26112ccb71bSMatthias Ringwald                 case UsageMaximum:
262*c4241e61SMatthias Ringwald                     main_iterator->usage_maximum = usage_value;
2631a05cde1SMatthias Ringwald                     have_usage_max = true;
26412ccb71bSMatthias Ringwald                     break;
26512ccb71bSMatthias Ringwald                 default:
26612ccb71bSMatthias Ringwald                     break;
26712ccb71bSMatthias Ringwald             }
2681a05cde1SMatthias Ringwald             if (have_usage_min && have_usage_max){
269*c4241e61SMatthias Ringwald                 main_iterator->available_usages = main_iterator->usage_maximum - main_iterator->usage_minimum + 1u;
270*c4241e61SMatthias Ringwald                 main_iterator->usage_range = true;
271*c4241e61SMatthias Ringwald                 if (main_iterator->available_usages < main_iterator->required_usages){
272*c4241e61SMatthias Ringwald                     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);
273dfb01e77SMatthias Ringwald                 }
27412ccb71bSMatthias Ringwald             }
27512ccb71bSMatthias Ringwald         }
27612ccb71bSMatthias Ringwald     }
277*c4241e61SMatthias Ringwald     main_iterator->usage_pos += iterator.descriptor_pos;
27812ccb71bSMatthias Ringwald }
27912ccb71bSMatthias Ringwald 
28012ccb71bSMatthias Ringwald 
28112ccb71bSMatthias Ringwald // PUBLIC API
28212ccb71bSMatthias Ringwald 
2830ba748f2SMatthias Ringwald // HID Descriptor Iterator
284fada7179SMilanka Ringwald 
2850c7e4a25SMatthias Ringwald void btstack_hid_descriptor_iterator_init(btstack_hid_descriptor_iterator_t * iterator, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len){
2860c7e4a25SMatthias Ringwald     iterator->descriptor = hid_descriptor;
2870c7e4a25SMatthias Ringwald     iterator->descriptor_pos = 0;
2880c7e4a25SMatthias Ringwald     iterator->descriptor_len = hid_descriptor_len;
2890c7e4a25SMatthias Ringwald     iterator->item_ready = false;
2900c7e4a25SMatthias Ringwald     iterator->valid = true;
2910c7e4a25SMatthias Ringwald }
2920c7e4a25SMatthias Ringwald 
2930c7e4a25SMatthias Ringwald bool btstack_hid_descriptor_iterator_has_more(btstack_hid_descriptor_iterator_t * iterator){
2943cc55c4aSMatthias Ringwald     if ((iterator->item_ready == false) && (iterator->descriptor_len > iterator->descriptor_pos)){
2950c7e4a25SMatthias Ringwald         uint16_t  item_len = iterator->descriptor_len - iterator->descriptor_pos;
2960c7e4a25SMatthias Ringwald         const uint8_t *item_data = &iterator->descriptor[iterator->descriptor_pos];
2970c7e4a25SMatthias Ringwald         bool ok = btstack_hid_parse_descriptor_item(&iterator->descriptor_item, item_data, item_len);
2980c7e4a25SMatthias Ringwald         if (ok){
2990c7e4a25SMatthias Ringwald             iterator->item_ready = true;
3000c7e4a25SMatthias Ringwald         } else {
3010c7e4a25SMatthias Ringwald             iterator->valid = false;
3020c7e4a25SMatthias Ringwald         }
3030c7e4a25SMatthias Ringwald     }
3040c7e4a25SMatthias Ringwald     return iterator->item_ready;
3050c7e4a25SMatthias Ringwald }
3060c7e4a25SMatthias Ringwald 
3070c7e4a25SMatthias Ringwald const hid_descriptor_item_t * const btstack_hid_descriptor_iterator_get_item(btstack_hid_descriptor_iterator_t * iterator){
3083cc55c4aSMatthias Ringwald     iterator->descriptor_pos += iterator->descriptor_item.item_size;
3090c7e4a25SMatthias Ringwald     iterator->item_ready = false;
3100c7e4a25SMatthias Ringwald     return &iterator->descriptor_item;
3110c7e4a25SMatthias Ringwald }
3120c7e4a25SMatthias Ringwald 
3130c7e4a25SMatthias Ringwald bool btstack_hid_descriptor_iterator_valid(btstack_hid_descriptor_iterator_t * iterator){
3140c7e4a25SMatthias Ringwald     return iterator->valid;
3150c7e4a25SMatthias Ringwald }
3160c7e4a25SMatthias Ringwald 
3170ba748f2SMatthias Ringwald 
3182cca3b08SMatthias Ringwald int btstack_hid_get_report_size_for_id(uint16_t report_id, hid_report_type_t report_type, const uint8_t *hid_descriptor,
3192cca3b08SMatthias Ringwald                                        uint16_t hid_descriptor_len) {
320fada7179SMilanka Ringwald     int total_report_size = 0;
321fada7179SMilanka Ringwald     int report_size = 0;
322fada7179SMilanka Ringwald     int report_count = 0;
323279225e6SMatthias Ringwald     int current_report_id = HID_REPORT_ID_UNDEFINED;
324fada7179SMilanka Ringwald 
325960622b0SMatthias Ringwald     btstack_hid_descriptor_iterator_t iterator;
326960622b0SMatthias Ringwald     btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len);
327960622b0SMatthias Ringwald     while (btstack_hid_descriptor_iterator_has_more(&iterator)) {
328960622b0SMatthias Ringwald         const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator);
329fada7179SMilanka Ringwald         int valid_report_type = 0;
330960622b0SMatthias Ringwald         switch (item->item_type) {
331fada7179SMilanka Ringwald             case Global:
332960622b0SMatthias Ringwald                 switch ((GlobalItemTag) item->item_tag) {
333fada7179SMilanka Ringwald                     case ReportID:
334960622b0SMatthias Ringwald                         current_report_id = item->item_value;
335fada7179SMilanka Ringwald                         break;
336fada7179SMilanka Ringwald                     case ReportCount:
337960622b0SMatthias Ringwald                         report_count = item->item_value;
338fada7179SMilanka Ringwald                         break;
339fada7179SMilanka Ringwald                     case ReportSize:
340960622b0SMatthias Ringwald                         report_size = item->item_value;
341fada7179SMilanka Ringwald                         break;
342fada7179SMilanka Ringwald                     default:
343fada7179SMilanka Ringwald                         break;
344fada7179SMilanka Ringwald                 }
345fada7179SMilanka Ringwald                 break;
346fada7179SMilanka Ringwald             case Main:
347fada7179SMilanka Ringwald                 if (current_report_id != report_id) break;
348960622b0SMatthias Ringwald                 switch ((MainItemTag) item->item_tag) {
349fada7179SMilanka Ringwald                     case Input:
350662cddc2SMilanka Ringwald                         if (report_type != HID_REPORT_TYPE_INPUT) break;
351fada7179SMilanka Ringwald                         valid_report_type = 1;
352fada7179SMilanka Ringwald                         break;
353fada7179SMilanka Ringwald                     case Output:
354662cddc2SMilanka Ringwald                         if (report_type != HID_REPORT_TYPE_OUTPUT) break;
355fada7179SMilanka Ringwald                         valid_report_type = 1;
356fada7179SMilanka Ringwald                         break;
357fada7179SMilanka Ringwald                     case Feature:
358662cddc2SMilanka Ringwald                         if (report_type != HID_REPORT_TYPE_FEATURE) break;
359fada7179SMilanka Ringwald                         valid_report_type = 1;
360fada7179SMilanka Ringwald                         break;
361fada7179SMilanka Ringwald                     default:
362fada7179SMilanka Ringwald                         break;
363fada7179SMilanka Ringwald                 }
364fada7179SMilanka Ringwald                 if (!valid_report_type) break;
365fada7179SMilanka Ringwald                 total_report_size += report_count * report_size;
366fada7179SMilanka Ringwald                 break;
367fada7179SMilanka Ringwald             default:
368fada7179SMilanka Ringwald                 break;
369fada7179SMilanka Ringwald         }
37015cf8612Sx0rloser         if (total_report_size > 0 && current_report_id != report_id) break;
371fada7179SMilanka Ringwald     }
372960622b0SMatthias Ringwald 
373960622b0SMatthias Ringwald     if (btstack_hid_descriptor_iterator_valid(&iterator)){
374fada7179SMilanka Ringwald         return (total_report_size + 7) / 8;
375960622b0SMatthias Ringwald     } else {
376960622b0SMatthias Ringwald         return 0;
377960622b0SMatthias Ringwald     }
378fada7179SMilanka Ringwald }
379dbcaefc7SMilanka Ringwald 
380279225e6SMatthias Ringwald hid_report_id_status_t btstack_hid_report_id_valid(uint16_t report_id, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len){
381279225e6SMatthias Ringwald     uint16_t current_report_id = HID_REPORT_ID_UNDEFINED;
382960622b0SMatthias Ringwald     btstack_hid_descriptor_iterator_t iterator;
383960622b0SMatthias Ringwald     btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len);
384279225e6SMatthias Ringwald     bool report_id_found = false;
385960622b0SMatthias Ringwald     while (btstack_hid_descriptor_iterator_has_more(&iterator)) {
386960622b0SMatthias Ringwald         const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator);
387960622b0SMatthias Ringwald         switch (item->item_type){
388dbcaefc7SMilanka Ringwald             case Global:
389960622b0SMatthias Ringwald                 switch ((GlobalItemTag)item->item_tag){
390dbcaefc7SMilanka Ringwald                     case ReportID:
391960622b0SMatthias Ringwald                         current_report_id = item->item_value;
392279225e6SMatthias Ringwald                         if (current_report_id == report_id) {
393279225e6SMatthias Ringwald                             report_id_found = true;
394279225e6SMatthias Ringwald                         }
395dbcaefc7SMilanka Ringwald                     default:
396dbcaefc7SMilanka Ringwald                         break;
397dbcaefc7SMilanka Ringwald                 }
398dbcaefc7SMilanka Ringwald                 break;
399dbcaefc7SMilanka Ringwald             default:
400dbcaefc7SMilanka Ringwald                 break;
401dbcaefc7SMilanka Ringwald         }
402dbcaefc7SMilanka Ringwald     }
403960622b0SMatthias Ringwald 
404960622b0SMatthias Ringwald     if (btstack_hid_descriptor_iterator_valid(&iterator)) {
405279225e6SMatthias Ringwald         if (report_id_found){
406279225e6SMatthias Ringwald             return HID_REPORT_ID_VALID;
407dbcaefc7SMilanka Ringwald         }
408279225e6SMatthias Ringwald         if ((report_id  == HID_REPORT_ID_UNDEFINED) && (current_report_id == HID_REPORT_ID_UNDEFINED)) {
409279225e6SMatthias Ringwald             return HID_REPORT_ID_VALID;
410279225e6SMatthias Ringwald         }
411279225e6SMatthias Ringwald         return HID_REPORT_ID_UNDECLARED;
412960622b0SMatthias Ringwald     } else {
413960622b0SMatthias Ringwald         return HID_REPORT_ID_INVALID;
414960622b0SMatthias Ringwald     }
415960622b0SMatthias Ringwald }
416dbcaefc7SMilanka Ringwald 
4172cca3b08SMatthias Ringwald bool btstack_hid_report_id_declared(const uint8_t *hid_descriptor, uint16_t hid_descriptor_len) {
418960622b0SMatthias Ringwald     btstack_hid_descriptor_iterator_t iterator;
419960622b0SMatthias Ringwald     btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len);
420960622b0SMatthias Ringwald     while (btstack_hid_descriptor_iterator_has_more(&iterator)) {
421960622b0SMatthias Ringwald         const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator);
422960622b0SMatthias Ringwald         switch (item->item_type){
423dbcaefc7SMilanka Ringwald             case Global:
424960622b0SMatthias Ringwald                 switch ((GlobalItemTag)item->item_tag){
425dbcaefc7SMilanka Ringwald                     case ReportID:
426c17118d0SMatthias Ringwald                         return true;
427dbcaefc7SMilanka Ringwald                     default:
428dbcaefc7SMilanka Ringwald                         break;
429dbcaefc7SMilanka Ringwald                 }
430dbcaefc7SMilanka Ringwald                 break;
431dbcaefc7SMilanka Ringwald             default:
432dbcaefc7SMilanka Ringwald                 break;
433dbcaefc7SMilanka Ringwald         }
434dbcaefc7SMilanka Ringwald     }
435c17118d0SMatthias Ringwald     return false;
436dbcaefc7SMilanka Ringwald }
437cdb96ae5SMatthias Ringwald 
4380ba748f2SMatthias Ringwald // HID Descriptor Usage Iterator
4390ba748f2SMatthias Ringwald 
440*c4241e61SMatthias Ringwald static void btstack_parser_usage_iterator_process_item(btstack_hid_usage_iterator_t * iterator, hid_descriptor_item_t * item){
441*c4241e61SMatthias Ringwald     hid_pretty_print_item(iterator, item);
442cdb96ae5SMatthias Ringwald     int valid_field = 0;
443cdb96ae5SMatthias Ringwald     uint16_t report_id_before;
444cdb96ae5SMatthias Ringwald     switch ((TagType)item->item_type){
445cdb96ae5SMatthias Ringwald         case Main:
446cdb96ae5SMatthias Ringwald             valid_field = btstack_hid_main_item_tag_matches_report_type((MainItemTag) item->item_tag,
447*c4241e61SMatthias Ringwald                                                                         iterator->report_type);
448cdb96ae5SMatthias Ringwald             break;
449cdb96ae5SMatthias Ringwald         case Global:
450*c4241e61SMatthias Ringwald             report_id_before = iterator->global_report_id;
451*c4241e61SMatthias Ringwald             btstack_hid_handle_global_item(iterator, item);
452cdb96ae5SMatthias Ringwald             // track record id for report handling, reset report position
453*c4241e61SMatthias Ringwald             if (report_id_before != iterator->global_report_id){
454*c4241e61SMatthias Ringwald                 iterator->report_pos_in_bit = 8u;
455cdb96ae5SMatthias Ringwald             }
456cdb96ae5SMatthias Ringwald             break;
457cdb96ae5SMatthias Ringwald         case Local:
458cdb96ae5SMatthias Ringwald         case Reserved:
459cdb96ae5SMatthias Ringwald             break;
460cdb96ae5SMatthias Ringwald         default:
461cdb96ae5SMatthias Ringwald             btstack_assert(false);
462cdb96ae5SMatthias Ringwald             break;
463cdb96ae5SMatthias Ringwald     }
464cdb96ae5SMatthias Ringwald     if (!valid_field) return;
465cdb96ae5SMatthias Ringwald 
466cdb96ae5SMatthias Ringwald     // handle constant fields used for padding
467cdb96ae5SMatthias Ringwald     if (item->item_value & 1){
468*c4241e61SMatthias Ringwald         int item_bits = iterator->global_report_size * iterator->global_report_count;
469cdb96ae5SMatthias Ringwald #ifdef HID_PARSER_PRETTY_PRINT
470cdb96ae5SMatthias Ringwald         log_info("- Skip %u constant bits", item_bits);
471cdb96ae5SMatthias Ringwald #endif
472*c4241e61SMatthias Ringwald         iterator->report_pos_in_bit += item_bits;
473cdb96ae5SMatthias Ringwald         return;
474cdb96ae5SMatthias Ringwald     }
475cdb96ae5SMatthias Ringwald     // Empty Item
476*c4241e61SMatthias Ringwald     if (iterator->global_report_count == 0u) return;
477cdb96ae5SMatthias Ringwald     // let's start
478*c4241e61SMatthias Ringwald     iterator->required_usages = iterator->global_report_count;
479cdb96ae5SMatthias Ringwald }
480cdb96ae5SMatthias Ringwald 
481*c4241e61SMatthias Ringwald static void btstack_hid_usage_iterator_find_next_usage(btstack_hid_usage_iterator_t * iterator) {
482*c4241e61SMatthias Ringwald     while (btstack_hid_descriptor_iterator_has_more(&iterator->descriptor_iterator)){
483*c4241e61SMatthias Ringwald         iterator->descriptor_item = * btstack_hid_descriptor_iterator_get_item(&iterator->descriptor_iterator);
484cdb96ae5SMatthias Ringwald 
485*c4241e61SMatthias Ringwald         btstack_parser_usage_iterator_process_item(iterator, &iterator->descriptor_item);
486cdb96ae5SMatthias Ringwald 
487*c4241e61SMatthias Ringwald         if (iterator->required_usages){
488*c4241e61SMatthias Ringwald             hid_find_next_usage(iterator);
489*c4241e61SMatthias Ringwald             if (iterator->available_usages) {
490*c4241e61SMatthias Ringwald                 iterator->state = BTSTACK_HID_USAGE_ITERATOR_USAGES_AVAILABLE;
491cdb96ae5SMatthias Ringwald                 return;
492cdb96ae5SMatthias Ringwald             } else {
493cdb96ae5SMatthias Ringwald                 log_debug("no usages found");
494*c4241e61SMatthias Ringwald                 iterator->state = BTSTACK_HID_USAGE_ITERATOR_PARSER_COMPLETE;
495cdb96ae5SMatthias Ringwald                 return;
496cdb96ae5SMatthias Ringwald             }
497cdb96ae5SMatthias Ringwald         } else {
498*c4241e61SMatthias Ringwald             if ((TagType) (&iterator->descriptor_item)->item_type == Main) {
499cdb96ae5SMatthias Ringwald                 // reset usage
500*c4241e61SMatthias Ringwald                 iterator->usage_pos = iterator->descriptor_iterator.descriptor_pos;
501*c4241e61SMatthias Ringwald                 iterator->usage_page = iterator->global_usage_page;
502cdb96ae5SMatthias Ringwald             }
503cdb96ae5SMatthias Ringwald         }
504cdb96ae5SMatthias Ringwald     }
505cdb96ae5SMatthias Ringwald     // end of descriptor
506*c4241e61SMatthias Ringwald     iterator->state = BTSTACK_HID_USAGE_ITERATOR_PARSER_COMPLETE;
507cdb96ae5SMatthias Ringwald }
508cdb96ae5SMatthias Ringwald 
509*c4241e61SMatthias Ringwald 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*c4241e61SMatthias Ringwald     memset(iterator, 0, sizeof(btstack_hid_usage_iterator_t));
511cdb96ae5SMatthias Ringwald 
512*c4241e61SMatthias Ringwald     iterator->descriptor     = hid_descriptor;
513*c4241e61SMatthias Ringwald     iterator->descriptor_len = hid_descriptor_len;
514*c4241e61SMatthias Ringwald     iterator->report_type    = hid_report_type;
515*c4241e61SMatthias Ringwald     iterator->state          = BTSTACK_HID_USAGE_ITERATOR_STATE_SCAN_FOR_REPORT_ITEM;
516*c4241e61SMatthias Ringwald     iterator->global_report_id = HID_REPORT_ID_UNDEFINED;
517*c4241e61SMatthias Ringwald     btstack_hid_descriptor_iterator_init(&iterator->descriptor_iterator, hid_descriptor, hid_descriptor_len);
518cdb96ae5SMatthias Ringwald }
519cdb96ae5SMatthias Ringwald 
520*c4241e61SMatthias Ringwald bool btstack_hid_usage_iterator_has_more(btstack_hid_usage_iterator_t * iterator){
521*c4241e61SMatthias Ringwald     while (iterator->state == BTSTACK_HID_USAGE_ITERATOR_STATE_SCAN_FOR_REPORT_ITEM){
522*c4241e61SMatthias Ringwald         btstack_hid_usage_iterator_find_next_usage(iterator);
52387256a6aSMatthias Ringwald     }
524*c4241e61SMatthias Ringwald     return iterator->state == BTSTACK_HID_USAGE_ITERATOR_USAGES_AVAILABLE;
525cdb96ae5SMatthias Ringwald }
526cdb96ae5SMatthias Ringwald 
527*c4241e61SMatthias Ringwald void btstack_hid_usage_iterator_get_item(btstack_hid_usage_iterator_t * iterator, btstack_hid_usage_item_t * item){
528cdb96ae5SMatthias Ringwald     // cache current values
529cdb96ae5SMatthias Ringwald     memset(item, 0, sizeof(btstack_hid_usage_item_t));
530*c4241e61SMatthias Ringwald     item->size = iterator->global_report_size;
531*c4241e61SMatthias Ringwald     item->report_id = iterator->global_report_id;
532*c4241e61SMatthias Ringwald     item->usage_page = iterator->usage_minimum >> 16;
533*c4241e61SMatthias Ringwald     item->bit_pos = iterator->report_pos_in_bit;
534cdb96ae5SMatthias Ringwald 
535*c4241e61SMatthias Ringwald     bool is_variable  = (iterator->descriptor_item.item_value & 2) != 0;
536cdb96ae5SMatthias Ringwald     if (is_variable){
537*c4241e61SMatthias Ringwald         item->usage = iterator->usage_minimum & 0xffffu;
538cdb96ae5SMatthias Ringwald     }
539*c4241e61SMatthias Ringwald     iterator->required_usages--;
540*c4241e61SMatthias Ringwald     iterator->report_pos_in_bit += iterator->global_report_size;
541cdb96ae5SMatthias Ringwald 
5420ba748f2SMatthias Ringwald     // cache descriptor item and
543*c4241e61SMatthias Ringwald     item->descriptor_item = iterator->descriptor_item;
544*c4241e61SMatthias Ringwald     item->global_logical_minimum = iterator->global_logical_minimum;
5450ba748f2SMatthias Ringwald 
546cdb96ae5SMatthias Ringwald     // next usage
547cdb96ae5SMatthias Ringwald     if (is_variable){
548*c4241e61SMatthias Ringwald         iterator->usage_minimum++;
549*c4241e61SMatthias Ringwald         iterator->available_usages--;
550*c4241e61SMatthias Ringwald         if (iterator->usage_range && (iterator->usage_minimum > iterator->usage_maximum)){
551cdb96ae5SMatthias Ringwald             // usage min - max range smaller than report count, ignore remaining bit in report
552cdb96ae5SMatthias Ringwald             log_debug("Ignoring %u items without Usage", parser->required_usages);
553*c4241e61SMatthias Ringwald             iterator->report_pos_in_bit += iterator->global_report_size * iterator->required_usages;
554*c4241e61SMatthias Ringwald             iterator->required_usages = 0;
555cdb96ae5SMatthias Ringwald         }
556cdb96ae5SMatthias Ringwald     } else {
557*c4241e61SMatthias Ringwald         if (iterator->required_usages == 0u){
558*c4241e61SMatthias Ringwald             iterator->available_usages = 0;
559cdb96ae5SMatthias Ringwald         }
560cdb96ae5SMatthias Ringwald     }
56187256a6aSMatthias Ringwald 
562*c4241e61SMatthias Ringwald     if (iterator->available_usages) {
563cdb96ae5SMatthias Ringwald         return;
564cdb96ae5SMatthias Ringwald     }
565*c4241e61SMatthias Ringwald     if (iterator->required_usages == 0u){
566*c4241e61SMatthias Ringwald         iterator->state = BTSTACK_HID_USAGE_ITERATOR_STATE_SCAN_FOR_REPORT_ITEM;
567cdb96ae5SMatthias Ringwald     } else {
568*c4241e61SMatthias Ringwald         hid_find_next_usage(iterator);
569*c4241e61SMatthias Ringwald         if (iterator->available_usages == 0u) {
570*c4241e61SMatthias Ringwald             iterator->state = BTSTACK_HID_USAGE_ITERATOR_PARSER_COMPLETE;
571cdb96ae5SMatthias Ringwald         }
572cdb96ae5SMatthias Ringwald     }
573cdb96ae5SMatthias Ringwald }
574cdb96ae5SMatthias Ringwald 
5750ba748f2SMatthias Ringwald 
5760ba748f2SMatthias Ringwald // HID Report Parser
5770ba748f2SMatthias Ringwald 
5780ba748f2SMatthias Ringwald 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*c4241e61SMatthias Ringwald     btstack_hid_usage_iterator_init(&parser->usage_iterator, hid_descriptor, hid_descriptor_len, hid_report_type);
5800ba748f2SMatthias Ringwald     parser->report = hid_report;
5810ba748f2SMatthias Ringwald     parser->report_len = hid_report_len;
5820ba748f2SMatthias Ringwald     parser->have_report_usage_ready = false;
5830ba748f2SMatthias Ringwald }
5840ba748f2SMatthias Ringwald 
5850ba748f2SMatthias Ringwald /**
5860ba748f2SMatthias Ringwald  * @brief Checks if more fields are available
5870ba748f2SMatthias Ringwald  * @param parser
5880ba748f2SMatthias Ringwald  */
5890ba748f2SMatthias Ringwald bool btstack_hid_parser_has_more(btstack_hid_parser_t * parser){
590*c4241e61SMatthias Ringwald     while ((parser->have_report_usage_ready == false) && btstack_hid_usage_iterator_has_more(&parser->usage_iterator)){
591*c4241e61SMatthias Ringwald         btstack_hid_usage_iterator_get_item(&parser->usage_iterator, &parser->descriptor__usage_item);
5920ba748f2SMatthias Ringwald         // ignore usages for other report ids
593279225e6SMatthias Ringwald         if (parser->descriptor__usage_item.report_id != HID_REPORT_ID_UNDEFINED){
5940ba748f2SMatthias Ringwald             if (parser->descriptor__usage_item.report_id != parser->report[0]){
5950ba748f2SMatthias Ringwald                 continue;
5960ba748f2SMatthias Ringwald             }
5970ba748f2SMatthias Ringwald         }
5980ba748f2SMatthias Ringwald         parser->have_report_usage_ready = true;
5990ba748f2SMatthias Ringwald     }
6000ba748f2SMatthias Ringwald     return parser->have_report_usage_ready;
6010ba748f2SMatthias Ringwald }
6020ba748f2SMatthias Ringwald 
6030ba748f2SMatthias Ringwald /**
6040ba748f2SMatthias Ringwald  * @brief Get next field
6050ba748f2SMatthias Ringwald  * @param parser
6060ba748f2SMatthias Ringwald  * @param usage_page
6070ba748f2SMatthias Ringwald  * @param usage
6080ba748f2SMatthias Ringwald  * @param value provided in HID report
6090ba748f2SMatthias Ringwald  */
6100ba748f2SMatthias Ringwald 
6110ba748f2SMatthias Ringwald void btstack_hid_parser_get_field(btstack_hid_parser_t * parser, uint16_t * usage_page, uint16_t * usage, int32_t * value){
6120ba748f2SMatthias Ringwald 
6130ba748f2SMatthias Ringwald     // fetch data from descriptor usage item
6140ba748f2SMatthias Ringwald     uint16_t bit_pos = parser->descriptor__usage_item.bit_pos;
6150ba748f2SMatthias Ringwald     uint16_t size    = parser->descriptor__usage_item.size;
6160ba748f2SMatthias Ringwald     *usage_page      = parser->descriptor__usage_item.usage_page;
6170ba748f2SMatthias Ringwald     *usage           = parser->descriptor__usage_item.usage;
6180ba748f2SMatthias Ringwald 
6190ba748f2SMatthias Ringwald 
6200ba748f2SMatthias Ringwald     // read field (up to 32 bit unsigned, up to 31 bit signed - 32 bit signed behaviour is undefined) - check report len
6210ba748f2SMatthias Ringwald     bool is_variable   = (parser->descriptor__usage_item.descriptor_item.item_value & 2) != 0;
6220ba748f2SMatthias Ringwald     bool is_signed     = parser->descriptor__usage_item.global_logical_minimum < 0;
6230ba748f2SMatthias Ringwald     int pos_start     = btstack_min(  bit_pos >> 3, parser->report_len);
6240ba748f2SMatthias Ringwald     int pos_end       = btstack_min( (bit_pos + size - 1u) >> 3u, parser->report_len);
6250ba748f2SMatthias Ringwald     int bytes_to_read = pos_end - pos_start + 1;
6260ba748f2SMatthias Ringwald 
6270ba748f2SMatthias Ringwald     int i;
6280ba748f2SMatthias Ringwald     uint32_t multi_byte_value = 0;
6290ba748f2SMatthias Ringwald     for (i=0;i < bytes_to_read;i++){
6300ba748f2SMatthias Ringwald         multi_byte_value |= parser->report[pos_start+i] << (i*8);
6310ba748f2SMatthias Ringwald     }
6320ba748f2SMatthias Ringwald     uint32_t unsigned_value = (multi_byte_value >> (bit_pos & 0x07u)) & ((1u<<size)-1u);
6330ba748f2SMatthias Ringwald     // 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);
6340ba748f2SMatthias Ringwald     if (is_variable){
6350ba748f2SMatthias Ringwald         if (is_signed && (unsigned_value & (1u<<(size-1u)))){
6360ba748f2SMatthias Ringwald             *value = unsigned_value - (1u<<size);
6370ba748f2SMatthias Ringwald         } else {
6380ba748f2SMatthias Ringwald             *value = unsigned_value;
6390ba748f2SMatthias Ringwald         }
6400ba748f2SMatthias Ringwald     } else {
6410ba748f2SMatthias Ringwald         *usage  = unsigned_value;
6420ba748f2SMatthias Ringwald         *value  = 1;
6430ba748f2SMatthias Ringwald     }
6440ba748f2SMatthias Ringwald 
6450ba748f2SMatthias Ringwald     parser->have_report_usage_ready = false;
6460ba748f2SMatthias Ringwald }
647