xref: /btstack/src/btstack_hid_parser.c (revision 3465b19cc1b17616f822e28e6094321aeaa42d6a)
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 /*
5212ccb71bSMatthias Ringwald  *  btstack_hid_parser.c
5312ccb71bSMatthias Ringwald  */
5412ccb71bSMatthias Ringwald 
5512ccb71bSMatthias Ringwald #ifdef HID_PARSER_PRETTY_PRINT
5612ccb71bSMatthias Ringwald 
5712ccb71bSMatthias Ringwald static const char * type_names[] = {
5812ccb71bSMatthias Ringwald     "Main",
5912ccb71bSMatthias Ringwald     "Global",
6012ccb71bSMatthias Ringwald     "Local",
6112ccb71bSMatthias Ringwald     "Reserved"
6212ccb71bSMatthias Ringwald };
6312ccb71bSMatthias Ringwald static const char * main_tags[] = {
6412ccb71bSMatthias Ringwald     "",
6512ccb71bSMatthias Ringwald     "",
6612ccb71bSMatthias Ringwald     "",
6712ccb71bSMatthias Ringwald     "",
6812ccb71bSMatthias Ringwald     "",
6912ccb71bSMatthias Ringwald     "",
7012ccb71bSMatthias Ringwald     "",
7112ccb71bSMatthias Ringwald     "",
7212ccb71bSMatthias Ringwald     "Input ",
7312ccb71bSMatthias Ringwald     "Output",
7412ccb71bSMatthias Ringwald     "Collection",
7512ccb71bSMatthias Ringwald     "Feature",
7612ccb71bSMatthias Ringwald     "End Collection",
7712ccb71bSMatthias Ringwald     "Reserved",
7812ccb71bSMatthias Ringwald     "Reserved",
7912ccb71bSMatthias Ringwald     "Reserved"
8012ccb71bSMatthias Ringwald };
8112ccb71bSMatthias Ringwald static const char * global_tags[] = {
8212ccb71bSMatthias Ringwald     "Usage Page",
8312ccb71bSMatthias Ringwald     "Logical Minimum",
8412ccb71bSMatthias Ringwald     "Logical Maximum",
8512ccb71bSMatthias Ringwald     "Physical Minimum",
8612ccb71bSMatthias Ringwald     "Physical Maximum",
8712ccb71bSMatthias Ringwald     "Unit Exponent",
8812ccb71bSMatthias Ringwald     "Unit",
8912ccb71bSMatthias Ringwald     "Report Size",
9012ccb71bSMatthias Ringwald     "Report ID",
9112ccb71bSMatthias Ringwald     "Report Count",
9212ccb71bSMatthias Ringwald     "Push",
9312ccb71bSMatthias Ringwald     "Pop",
9412ccb71bSMatthias Ringwald     "Reserved",
9512ccb71bSMatthias Ringwald     "Reserved",
9612ccb71bSMatthias Ringwald     "Reserved",
9712ccb71bSMatthias Ringwald     "Reserved"
9812ccb71bSMatthias Ringwald };
9912ccb71bSMatthias Ringwald static const char * local_tags[] = {
10012ccb71bSMatthias Ringwald     "Usage",
10112ccb71bSMatthias Ringwald     "Usage Minimum",
10212ccb71bSMatthias Ringwald     "Usage Maximum",
10312ccb71bSMatthias Ringwald     "Designator Index",
10412ccb71bSMatthias Ringwald     "Designator Minimum",
10512ccb71bSMatthias Ringwald     "Designator Maximum",
10612ccb71bSMatthias Ringwald     "String Index",
10712ccb71bSMatthias Ringwald     "String Minimum",
10812ccb71bSMatthias Ringwald     "String Maximum",
10912ccb71bSMatthias Ringwald     "Delimiter",
11012ccb71bSMatthias Ringwald     "Reserved",
11112ccb71bSMatthias Ringwald     "Reserved",
11212ccb71bSMatthias Ringwald     "Reserved",
11312ccb71bSMatthias Ringwald     "Reserved",
11412ccb71bSMatthias Ringwald     "Reserved",
11512ccb71bSMatthias Ringwald     "Reserved"
11612ccb71bSMatthias Ringwald };
11712ccb71bSMatthias Ringwald #endif
11812ccb71bSMatthias Ringwald 
1195dd091fdSMatthias Ringwald // HID Descriptor Iterator
12012ccb71bSMatthias Ringwald 
12112ccb71bSMatthias Ringwald // parse descriptor item and read up to 32-bit bit value
1225dd091fdSMatthias Ringwald static bool btstack_hid_descriptor_parse_item(hid_descriptor_item_t * item, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len){
1238334d3d8SMatthias Ringwald 
1248334d3d8SMatthias Ringwald     const int hid_item_sizes[] = { 0, 1, 2, 4 };
1258334d3d8SMatthias Ringwald 
12612ccb71bSMatthias Ringwald     // parse item header
12776fa2448SMatthias Ringwald     if (hid_descriptor_len < 1u) return false;
12812ccb71bSMatthias Ringwald     uint16_t pos = 0;
12912ccb71bSMatthias Ringwald     uint8_t item_header = hid_descriptor[pos++];
1304ea43905SMatthias Ringwald     item->data_size = hid_item_sizes[item_header & 0x03u];
1314ea43905SMatthias Ringwald     item->item_type = (item_header & 0x0cu) >> 2u;
1324ea43905SMatthias Ringwald     item->item_tag  = (item_header & 0xf0u) >> 4u;
13312ccb71bSMatthias Ringwald     // long item
1344ea43905SMatthias Ringwald     if ((item->data_size == 2u) && (item->item_tag == 0x0fu) && (item->item_type == 3u)){
13576fa2448SMatthias Ringwald         if (hid_descriptor_len < 3u) return false;
13612ccb71bSMatthias Ringwald         item->data_size = hid_descriptor[pos++];
13712ccb71bSMatthias Ringwald         item->item_tag  = hid_descriptor[pos++];
13812ccb71bSMatthias Ringwald     }
13912ccb71bSMatthias Ringwald     item->item_size =  pos + item->data_size;
14012ccb71bSMatthias Ringwald     item->item_value = 0;
14112ccb71bSMatthias Ringwald 
14212ccb71bSMatthias Ringwald     // read item value
14376fa2448SMatthias Ringwald     if (hid_descriptor_len < item->item_size) return false;
14476fa2448SMatthias Ringwald     if (item->data_size > 4u) return false;
14512ccb71bSMatthias Ringwald     int i;
1464ea43905SMatthias Ringwald     int sgnd = (item->item_type == Global) && (item->item_tag > 0u) && (item->item_tag < 5u);
14712ccb71bSMatthias Ringwald     int32_t value = 0;
14812ccb71bSMatthias Ringwald     uint8_t latest_byte = 0;
14912ccb71bSMatthias Ringwald     for (i=0;i<item->data_size;i++){
15012ccb71bSMatthias Ringwald         latest_byte = hid_descriptor[pos++];
15112ccb71bSMatthias Ringwald         value = (latest_byte << (8*i)) | value;
15212ccb71bSMatthias Ringwald     }
1534ea43905SMatthias Ringwald     if (sgnd && (item->data_size > 0u)){
1544ea43905SMatthias Ringwald         if (latest_byte & 0x80u) {
1554ea43905SMatthias Ringwald             value -= 1u << (item->data_size*8u);
15612ccb71bSMatthias Ringwald         }
15712ccb71bSMatthias Ringwald     }
15812ccb71bSMatthias Ringwald     item->item_value = value;
15976fa2448SMatthias Ringwald     return true;
16012ccb71bSMatthias Ringwald }
16112ccb71bSMatthias Ringwald 
1625dd091fdSMatthias Ringwald static void btstack_hid_descriptor_iterator_pretty_print_item(btstack_hid_descriptor_iterator_t * iterator, hid_descriptor_item_t * item){
1635dd091fdSMatthias Ringwald #ifdef HID_PARSER_PRETTY_PRINT
1645dd091fdSMatthias Ringwald     const char ** item_tag_table;
1655dd091fdSMatthias Ringwald     switch ((TagType)item->item_type){
1665dd091fdSMatthias Ringwald         case Main:
1675dd091fdSMatthias Ringwald             item_tag_table = main_tags;
1685dd091fdSMatthias Ringwald             break;
1695dd091fdSMatthias Ringwald         case Global:
1705dd091fdSMatthias Ringwald             item_tag_table = global_tags;
1715dd091fdSMatthias Ringwald             break;
1725dd091fdSMatthias Ringwald         case Local:
1735dd091fdSMatthias Ringwald             item_tag_table = local_tags;
1745dd091fdSMatthias Ringwald             break;
1755dd091fdSMatthias Ringwald         default:
1765dd091fdSMatthias Ringwald             item_tag_table = NULL;
1775dd091fdSMatthias Ringwald             break;
1785dd091fdSMatthias Ringwald     }
1795dd091fdSMatthias Ringwald     const char * item_tag_name = "Invalid";
1805dd091fdSMatthias Ringwald     if (item_tag_table){
1815dd091fdSMatthias Ringwald         item_tag_name = item_tag_table[item->item_tag];
1825dd091fdSMatthias Ringwald     }
1835dd091fdSMatthias Ringwald     log_info("%-15s (%-6s) // %02x 0x%0008x", item_tag_name, type_names[item->item_type], iterator->descriptor[iterator->descriptor_pos], item->item_value);
1845dd091fdSMatthias Ringwald     printf("%-15s (%-6s) // %02x 0x%0008x\n", item_tag_name, type_names[item->item_type], iterator->descriptor[iterator->descriptor_pos], item->item_value);
1855dd091fdSMatthias Ringwald #else
1865dd091fdSMatthias Ringwald     UNUSED(iterator);
1875dd091fdSMatthias Ringwald     UNUSED(item);
1885dd091fdSMatthias Ringwald #endif
1895dd091fdSMatthias Ringwald }
1905dd091fdSMatthias Ringwald 
1915dd091fdSMatthias Ringwald void btstack_hid_descriptor_iterator_init(btstack_hid_descriptor_iterator_t * iterator, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len){
1925dd091fdSMatthias Ringwald     iterator->descriptor = hid_descriptor;
1935dd091fdSMatthias Ringwald     iterator->descriptor_pos = 0;
1945dd091fdSMatthias Ringwald     iterator->descriptor_len = hid_descriptor_len;
1955dd091fdSMatthias Ringwald     iterator->item_ready = false;
1965dd091fdSMatthias Ringwald     iterator->valid = true;
1975dd091fdSMatthias Ringwald }
1985dd091fdSMatthias Ringwald 
1995dd091fdSMatthias Ringwald bool btstack_hid_descriptor_iterator_has_more(btstack_hid_descriptor_iterator_t * iterator){
2005dd091fdSMatthias Ringwald     if ((iterator->item_ready == false) && (iterator->descriptor_len > iterator->descriptor_pos)){
2015dd091fdSMatthias Ringwald         uint16_t  item_len = iterator->descriptor_len - iterator->descriptor_pos;
2025dd091fdSMatthias Ringwald         const uint8_t *item_data = &iterator->descriptor[iterator->descriptor_pos];
2035dd091fdSMatthias Ringwald         bool ok = btstack_hid_descriptor_parse_item(&iterator->descriptor_item, item_data, item_len);
2045dd091fdSMatthias Ringwald         btstack_hid_descriptor_iterator_pretty_print_item(iterator, &iterator->descriptor_item);
2055dd091fdSMatthias Ringwald         if (ok){
2065dd091fdSMatthias Ringwald             iterator->item_ready = true;
2075dd091fdSMatthias Ringwald         } else {
2085dd091fdSMatthias Ringwald             iterator->valid = false;
2095dd091fdSMatthias Ringwald         }
2105dd091fdSMatthias Ringwald     }
2115dd091fdSMatthias Ringwald     return iterator->item_ready;
2125dd091fdSMatthias Ringwald }
2135dd091fdSMatthias Ringwald 
214*3465b19cSDirk Helbig const hid_descriptor_item_t * btstack_hid_descriptor_iterator_get_item(btstack_hid_descriptor_iterator_t * iterator){
2155dd091fdSMatthias Ringwald     iterator->descriptor_pos += iterator->descriptor_item.item_size;
2165dd091fdSMatthias Ringwald     iterator->item_ready = false;
2175dd091fdSMatthias Ringwald     return &iterator->descriptor_item;
2185dd091fdSMatthias Ringwald }
2195dd091fdSMatthias Ringwald 
2205dd091fdSMatthias Ringwald bool btstack_hid_descriptor_iterator_valid(btstack_hid_descriptor_iterator_t * iterator){
2215dd091fdSMatthias Ringwald     return iterator->valid;
2225dd091fdSMatthias Ringwald }
2235dd091fdSMatthias Ringwald 
2245dd091fdSMatthias Ringwald // HID Descriptor Usage Iterator
2255dd091fdSMatthias Ringwald 
2265dd091fdSMatthias Ringwald static bool btstack_hid_usage_iterator_main_item_tag_matches_report_type(MainItemTag tag, hid_report_type_t report_type){
2270a4fc5fbSMatthias Ringwald     switch (tag){
2280a4fc5fbSMatthias Ringwald         case Input:
2290a4fc5fbSMatthias Ringwald             return report_type == HID_REPORT_TYPE_INPUT;
2300a4fc5fbSMatthias Ringwald         case Output:
2310a4fc5fbSMatthias Ringwald             return report_type == HID_REPORT_TYPE_OUTPUT;
2320a4fc5fbSMatthias Ringwald         case Feature:
2330a4fc5fbSMatthias Ringwald             return report_type == HID_REPORT_TYPE_FEATURE;
2340a4fc5fbSMatthias Ringwald         default:
2350a4fc5fbSMatthias Ringwald             return false;
2360a4fc5fbSMatthias Ringwald     }
2370a4fc5fbSMatthias Ringwald }
2380a4fc5fbSMatthias Ringwald 
2395dd091fdSMatthias Ringwald static void btstack_hid_usage_iterator_handle_global_item(btstack_hid_usage_iterator_t * iterator, hid_descriptor_item_t * item){
2407bbeb3adSMilanka Ringwald     switch((GlobalItemTag)item->item_tag){
24112ccb71bSMatthias Ringwald         case UsagePage:
242c4241e61SMatthias Ringwald             iterator->global_usage_page = item->item_value;
24312ccb71bSMatthias Ringwald             break;
24412ccb71bSMatthias Ringwald         case LogicalMinimum:
245c4241e61SMatthias Ringwald             iterator->global_logical_minimum = item->item_value;
24612ccb71bSMatthias Ringwald             break;
24712ccb71bSMatthias Ringwald         case LogicalMaximum:
248c4241e61SMatthias Ringwald             iterator->global_logical_maximum = item->item_value;
24912ccb71bSMatthias Ringwald             break;
25012ccb71bSMatthias Ringwald         case ReportSize:
251c4241e61SMatthias Ringwald             iterator->global_report_size = item->item_value;
25212ccb71bSMatthias Ringwald             break;
25312ccb71bSMatthias Ringwald         case ReportID:
254c4241e61SMatthias Ringwald             iterator->global_report_id = item->item_value;
25512ccb71bSMatthias Ringwald             break;
25612ccb71bSMatthias Ringwald         case ReportCount:
257c4241e61SMatthias Ringwald             iterator->global_report_count = item->item_value;
25812ccb71bSMatthias Ringwald             break;
2597bbeb3adSMilanka Ringwald 
2607bbeb3adSMilanka Ringwald         // TODO handle tags
2617bbeb3adSMilanka Ringwald         case PhysicalMinimum:
2627bbeb3adSMilanka Ringwald         case PhysicalMaximum:
2637bbeb3adSMilanka Ringwald         case UnitExponent:
2647bbeb3adSMilanka Ringwald         case Unit:
2657bbeb3adSMilanka Ringwald         case Push:
2667bbeb3adSMilanka Ringwald         case Pop:
2677bbeb3adSMilanka Ringwald             break;
2687bbeb3adSMilanka Ringwald 
26912ccb71bSMatthias Ringwald         default:
2707bbeb3adSMilanka Ringwald             btstack_assert(false);
27112ccb71bSMatthias Ringwald             break;
27212ccb71bSMatthias Ringwald     }
27312ccb71bSMatthias Ringwald }
27412ccb71bSMatthias Ringwald 
2755dd091fdSMatthias Ringwald static void btstack_usage_iterator_hid_find_next_usage(btstack_hid_usage_iterator_t * main_iterator){
2761a05cde1SMatthias Ringwald     bool have_usage_min = false;
2771a05cde1SMatthias Ringwald     bool have_usage_max = false;
278c4241e61SMatthias Ringwald     main_iterator->usage_range = false;
27941afcabaSMatthias Ringwald     btstack_hid_descriptor_iterator_t iterator;
280c4241e61SMatthias Ringwald     btstack_hid_descriptor_iterator_init(&iterator, &main_iterator->descriptor[main_iterator->usage_pos], main_iterator->descriptor_len - main_iterator->usage_pos);
281c4241e61SMatthias Ringwald     while ((main_iterator->available_usages == 0u) && btstack_hid_descriptor_iterator_has_more(&iterator) ){
28241afcabaSMatthias Ringwald         hid_descriptor_item_t usage_item = *btstack_hid_descriptor_iterator_get_item(&iterator);
2830e588213SMatthias Ringwald         if ((usage_item.item_type == Global) && (usage_item.item_tag == UsagePage)){
284c4241e61SMatthias Ringwald             main_iterator->usage_page = usage_item.item_value;
28512ccb71bSMatthias Ringwald         }
28612ccb71bSMatthias Ringwald         if (usage_item.item_type == Local){
287c4241e61SMatthias Ringwald             uint32_t usage_value = (usage_item.data_size > 2u) ? usage_item.item_value : ((main_iterator->usage_page << 16u) | usage_item.item_value);
28812ccb71bSMatthias Ringwald             switch (usage_item.item_tag){
28912ccb71bSMatthias Ringwald                 case Usage:
290c4241e61SMatthias Ringwald                     main_iterator->available_usages = 1;
291c4241e61SMatthias Ringwald                     main_iterator->usage_minimum = usage_value;
29212ccb71bSMatthias Ringwald                     break;
29312ccb71bSMatthias Ringwald                 case UsageMinimum:
294c4241e61SMatthias Ringwald                     main_iterator->usage_minimum = usage_value;
2951a05cde1SMatthias Ringwald                     have_usage_min = true;
29612ccb71bSMatthias Ringwald                     break;
29712ccb71bSMatthias Ringwald                 case UsageMaximum:
298c4241e61SMatthias Ringwald                     main_iterator->usage_maximum = usage_value;
2991a05cde1SMatthias Ringwald                     have_usage_max = true;
30012ccb71bSMatthias Ringwald                     break;
30112ccb71bSMatthias Ringwald                 default:
30212ccb71bSMatthias Ringwald                     break;
30312ccb71bSMatthias Ringwald             }
3041a05cde1SMatthias Ringwald             if (have_usage_min && have_usage_max){
305c4241e61SMatthias Ringwald                 main_iterator->available_usages = main_iterator->usage_maximum - main_iterator->usage_minimum + 1u;
306c4241e61SMatthias Ringwald                 main_iterator->usage_range = true;
307c4241e61SMatthias Ringwald                 if (main_iterator->available_usages < main_iterator->required_usages){
308c4241e61SMatthias 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);
309dfb01e77SMatthias Ringwald                 }
31012ccb71bSMatthias Ringwald             }
31112ccb71bSMatthias Ringwald         }
31212ccb71bSMatthias Ringwald     }
313c4241e61SMatthias Ringwald     main_iterator->usage_pos += iterator.descriptor_pos;
31412ccb71bSMatthias Ringwald }
31512ccb71bSMatthias Ringwald 
3165dd091fdSMatthias Ringwald static void btstack_parser_usage_iterator_process_item(btstack_hid_usage_iterator_t * iterator, hid_descriptor_item_t * item){
3175dd091fdSMatthias Ringwald     int valid_field = 0;
3185dd091fdSMatthias Ringwald     uint16_t report_id_before;
3195dd091fdSMatthias Ringwald     switch ((TagType)item->item_type){
3205dd091fdSMatthias Ringwald         case Main:
3215dd091fdSMatthias Ringwald             valid_field = btstack_hid_usage_iterator_main_item_tag_matches_report_type((MainItemTag) item->item_tag,
3225dd091fdSMatthias Ringwald                                                                                        iterator->report_type);
3235dd091fdSMatthias Ringwald             break;
3245dd091fdSMatthias Ringwald         case Global:
3255dd091fdSMatthias Ringwald             report_id_before = iterator->global_report_id;
3265dd091fdSMatthias Ringwald             btstack_hid_usage_iterator_handle_global_item(iterator, item);
3275dd091fdSMatthias Ringwald             // track record id for report handling, reset report position
3285dd091fdSMatthias Ringwald             if (report_id_before != iterator->global_report_id){
329619253e6SMatthias Ringwald                 iterator->report_pos_in_bit = 0u;
3305dd091fdSMatthias Ringwald             }
3315dd091fdSMatthias Ringwald             break;
3325dd091fdSMatthias Ringwald         case Local:
3335dd091fdSMatthias Ringwald         case Reserved:
3345dd091fdSMatthias Ringwald             break;
3355dd091fdSMatthias Ringwald         default:
3365dd091fdSMatthias Ringwald             btstack_assert(false);
3375dd091fdSMatthias Ringwald             break;
3385dd091fdSMatthias Ringwald     }
3395dd091fdSMatthias Ringwald     if (!valid_field) return;
34012ccb71bSMatthias Ringwald 
3415dd091fdSMatthias Ringwald     // handle constant fields used for padding
3425dd091fdSMatthias Ringwald     if (item->item_value & 1){
3435dd091fdSMatthias Ringwald         int item_bits = iterator->global_report_size * iterator->global_report_count;
3445dd091fdSMatthias Ringwald #ifdef HID_PARSER_PRETTY_PRINT
3455dd091fdSMatthias Ringwald         log_info("- Skip %u constant bits", item_bits);
3465dd091fdSMatthias Ringwald #endif
3475dd091fdSMatthias Ringwald         iterator->report_pos_in_bit += item_bits;
3485dd091fdSMatthias Ringwald         return;
3495dd091fdSMatthias Ringwald     }
3505dd091fdSMatthias Ringwald     // Empty Item
3515dd091fdSMatthias Ringwald     if (iterator->global_report_count == 0u) return;
3525dd091fdSMatthias Ringwald     // let's start
3535dd091fdSMatthias Ringwald     iterator->required_usages = iterator->global_report_count;
3540c7e4a25SMatthias Ringwald }
3550c7e4a25SMatthias Ringwald 
3565dd091fdSMatthias Ringwald static void btstack_hid_usage_iterator_find_next_usage(btstack_hid_usage_iterator_t * iterator) {
3575dd091fdSMatthias Ringwald     while (btstack_hid_descriptor_iterator_has_more(&iterator->descriptor_iterator)){
3585dd091fdSMatthias Ringwald         iterator->descriptor_item = * btstack_hid_descriptor_iterator_get_item(&iterator->descriptor_iterator);
3595dd091fdSMatthias Ringwald 
3605dd091fdSMatthias Ringwald         btstack_parser_usage_iterator_process_item(iterator, &iterator->descriptor_item);
3615dd091fdSMatthias Ringwald 
3625dd091fdSMatthias Ringwald         if (iterator->required_usages){
3635dd091fdSMatthias Ringwald             btstack_usage_iterator_hid_find_next_usage(iterator);
3645dd091fdSMatthias Ringwald             if (iterator->available_usages) {
3655dd091fdSMatthias Ringwald                 iterator->state = BTSTACK_HID_USAGE_ITERATOR_USAGES_AVAILABLE;
3665dd091fdSMatthias Ringwald                 return;
3670c7e4a25SMatthias Ringwald             } else {
3685dd091fdSMatthias Ringwald                 log_debug("no usages found");
3695dd091fdSMatthias Ringwald                 iterator->state = BTSTACK_HID_USAGE_ITERATOR_PARSER_COMPLETE;
3705dd091fdSMatthias Ringwald                 return;
3715dd091fdSMatthias Ringwald             }
3725dd091fdSMatthias Ringwald         } else {
3735dd091fdSMatthias Ringwald             if ((TagType) (&iterator->descriptor_item)->item_type == Main) {
3745dd091fdSMatthias Ringwald                 // reset usage
3755dd091fdSMatthias Ringwald                 iterator->usage_pos = iterator->descriptor_iterator.descriptor_pos;
3765dd091fdSMatthias Ringwald                 iterator->usage_page = iterator->global_usage_page;
3770c7e4a25SMatthias Ringwald             }
3780c7e4a25SMatthias Ringwald         }
3795dd091fdSMatthias Ringwald     }
3805dd091fdSMatthias Ringwald     // end of descriptor
3815dd091fdSMatthias Ringwald     iterator->state = BTSTACK_HID_USAGE_ITERATOR_PARSER_COMPLETE;
3820c7e4a25SMatthias Ringwald }
3830c7e4a25SMatthias Ringwald 
3845dd091fdSMatthias 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){
3855dd091fdSMatthias Ringwald     memset(iterator, 0, sizeof(btstack_hid_usage_iterator_t));
3865dd091fdSMatthias Ringwald 
3875dd091fdSMatthias Ringwald     iterator->descriptor     = hid_descriptor;
3885dd091fdSMatthias Ringwald     iterator->descriptor_len = hid_descriptor_len;
3895dd091fdSMatthias Ringwald     iterator->report_type    = hid_report_type;
3905dd091fdSMatthias Ringwald     iterator->state          = BTSTACK_HID_USAGE_ITERATOR_STATE_SCAN_FOR_REPORT_ITEM;
3915dd091fdSMatthias Ringwald     iterator->global_report_id = HID_REPORT_ID_UNDEFINED;
3925dd091fdSMatthias Ringwald     btstack_hid_descriptor_iterator_init(&iterator->descriptor_iterator, hid_descriptor, hid_descriptor_len);
3930c7e4a25SMatthias Ringwald }
3940c7e4a25SMatthias Ringwald 
3955dd091fdSMatthias Ringwald bool btstack_hid_usage_iterator_has_more(btstack_hid_usage_iterator_t * iterator){
3965dd091fdSMatthias Ringwald     while (iterator->state == BTSTACK_HID_USAGE_ITERATOR_STATE_SCAN_FOR_REPORT_ITEM){
3975dd091fdSMatthias Ringwald         btstack_hid_usage_iterator_find_next_usage(iterator);
3985dd091fdSMatthias Ringwald     }
3995dd091fdSMatthias Ringwald     return iterator->state == BTSTACK_HID_USAGE_ITERATOR_USAGES_AVAILABLE;
4000c7e4a25SMatthias Ringwald }
4010c7e4a25SMatthias Ringwald 
4025dd091fdSMatthias Ringwald void btstack_hid_usage_iterator_get_item(btstack_hid_usage_iterator_t * iterator, btstack_hid_usage_item_t * item){
4035dd091fdSMatthias Ringwald     // cache current values
4045dd091fdSMatthias Ringwald     memset(item, 0, sizeof(btstack_hid_usage_item_t));
4055dd091fdSMatthias Ringwald     item->size = iterator->global_report_size;
4065dd091fdSMatthias Ringwald     item->report_id = iterator->global_report_id;
4075dd091fdSMatthias Ringwald     item->usage_page = iterator->usage_minimum >> 16;
4085dd091fdSMatthias Ringwald     item->bit_pos = iterator->report_pos_in_bit;
4095dd091fdSMatthias Ringwald 
4105dd091fdSMatthias Ringwald     bool is_variable  = (iterator->descriptor_item.item_value & 2) != 0;
4115dd091fdSMatthias Ringwald     if (is_variable){
4125dd091fdSMatthias Ringwald         item->usage = iterator->usage_minimum & 0xffffu;
4135dd091fdSMatthias Ringwald     }
4145dd091fdSMatthias Ringwald     iterator->required_usages--;
4155dd091fdSMatthias Ringwald     iterator->report_pos_in_bit += iterator->global_report_size;
4165dd091fdSMatthias Ringwald 
4175dd091fdSMatthias Ringwald     // cache descriptor item and
4185dd091fdSMatthias Ringwald     item->descriptor_item = iterator->descriptor_item;
4195dd091fdSMatthias Ringwald     item->global_logical_minimum = iterator->global_logical_minimum;
4205dd091fdSMatthias Ringwald 
4215dd091fdSMatthias Ringwald     // next usage
4225dd091fdSMatthias Ringwald     if (is_variable){
4235dd091fdSMatthias Ringwald         iterator->usage_minimum++;
4245dd091fdSMatthias Ringwald         iterator->available_usages--;
4255dd091fdSMatthias Ringwald         if (iterator->usage_range && (iterator->usage_minimum > iterator->usage_maximum)){
4265dd091fdSMatthias Ringwald             // usage min - max range smaller than report count, ignore remaining bit in report
4275dd091fdSMatthias Ringwald             log_debug("Ignoring %u items without Usage", parser->required_usages);
4285dd091fdSMatthias Ringwald             iterator->report_pos_in_bit += iterator->global_report_size * iterator->required_usages;
4295dd091fdSMatthias Ringwald             iterator->required_usages = 0;
4305dd091fdSMatthias Ringwald         }
4315dd091fdSMatthias Ringwald     } else {
4325dd091fdSMatthias Ringwald         if (iterator->required_usages == 0u){
4335dd091fdSMatthias Ringwald             iterator->available_usages = 0;
4345dd091fdSMatthias Ringwald         }
4355dd091fdSMatthias Ringwald     }
4365dd091fdSMatthias Ringwald 
4375dd091fdSMatthias Ringwald     if (iterator->available_usages) {
4385dd091fdSMatthias Ringwald         return;
4395dd091fdSMatthias Ringwald     }
4405dd091fdSMatthias Ringwald     if (iterator->required_usages == 0u){
4415dd091fdSMatthias Ringwald         iterator->state = BTSTACK_HID_USAGE_ITERATOR_STATE_SCAN_FOR_REPORT_ITEM;
4425dd091fdSMatthias Ringwald     } else {
4435dd091fdSMatthias Ringwald         btstack_usage_iterator_hid_find_next_usage(iterator);
4445dd091fdSMatthias Ringwald         if (iterator->available_usages == 0u) {
4455dd091fdSMatthias Ringwald             iterator->state = BTSTACK_HID_USAGE_ITERATOR_PARSER_COMPLETE;
4465dd091fdSMatthias Ringwald         }
4475dd091fdSMatthias Ringwald     }
4485dd091fdSMatthias Ringwald }
4495dd091fdSMatthias Ringwald 
4505dd091fdSMatthias Ringwald 
4515dd091fdSMatthias Ringwald // HID Report Parser
4525dd091fdSMatthias Ringwald 
4535dd091fdSMatthias 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){
4545dd091fdSMatthias Ringwald     btstack_hid_usage_iterator_init(&parser->usage_iterator, hid_descriptor, hid_descriptor_len, hid_report_type);
4555dd091fdSMatthias Ringwald     parser->report = hid_report;
4565dd091fdSMatthias Ringwald     parser->report_len = hid_report_len;
4575dd091fdSMatthias Ringwald     parser->have_report_usage_ready = false;
4585dd091fdSMatthias Ringwald }
4595dd091fdSMatthias Ringwald 
4605dd091fdSMatthias Ringwald /**
4615dd091fdSMatthias Ringwald  * @brief Checks if more fields are available
4625dd091fdSMatthias Ringwald  * @param parser
4635dd091fdSMatthias Ringwald  */
4645dd091fdSMatthias Ringwald bool btstack_hid_parser_has_more(btstack_hid_parser_t * parser){
4655dd091fdSMatthias Ringwald     while ((parser->have_report_usage_ready == false) && btstack_hid_usage_iterator_has_more(&parser->usage_iterator)){
466a05e6df3SMatthias Ringwald         btstack_hid_usage_iterator_get_item(&parser->usage_iterator, &parser->descriptor_usage_item);
4675dd091fdSMatthias Ringwald         // ignore usages for other report ids
468a05e6df3SMatthias Ringwald         if (parser->descriptor_usage_item.report_id != HID_REPORT_ID_UNDEFINED){
469a05e6df3SMatthias Ringwald             if (parser->descriptor_usage_item.report_id != parser->report[0]){
4705dd091fdSMatthias Ringwald                 continue;
4715dd091fdSMatthias Ringwald             }
4725dd091fdSMatthias Ringwald         }
4735dd091fdSMatthias Ringwald         parser->have_report_usage_ready = true;
4745dd091fdSMatthias Ringwald     }
4755dd091fdSMatthias Ringwald     return parser->have_report_usage_ready;
4765dd091fdSMatthias Ringwald }
4775dd091fdSMatthias Ringwald 
4785dd091fdSMatthias Ringwald /**
4795dd091fdSMatthias Ringwald  * @brief Get next field
4805dd091fdSMatthias Ringwald  * @param parser
4815dd091fdSMatthias Ringwald  * @param usage_page
4825dd091fdSMatthias Ringwald  * @param usage
4835dd091fdSMatthias Ringwald  * @param value provided in HID report
4845dd091fdSMatthias Ringwald  */
4855dd091fdSMatthias Ringwald 
4865dd091fdSMatthias Ringwald void btstack_hid_parser_get_field(btstack_hid_parser_t * parser, uint16_t * usage_page, uint16_t * usage, int32_t * value){
4875dd091fdSMatthias Ringwald 
4885dd091fdSMatthias Ringwald     // fetch data from descriptor usage item
489a05e6df3SMatthias Ringwald     uint16_t bit_pos = parser->descriptor_usage_item.bit_pos;
490a05e6df3SMatthias Ringwald     uint16_t size    = parser->descriptor_usage_item.size;
491a05e6df3SMatthias Ringwald     *usage_page      = parser->descriptor_usage_item.usage_page;
492a05e6df3SMatthias Ringwald     *usage           = parser->descriptor_usage_item.usage;
4935dd091fdSMatthias Ringwald 
494619253e6SMatthias Ringwald     // skip optional Report ID
495619253e6SMatthias Ringwald     if (parser->descriptor_usage_item.report_id != HID_REPORT_ID_UNDEFINED){
496619253e6SMatthias Ringwald         bit_pos += 8;
497619253e6SMatthias Ringwald     }
4985dd091fdSMatthias Ringwald 
4995dd091fdSMatthias Ringwald     // read field (up to 32 bit unsigned, up to 31 bit signed - 32 bit signed behaviour is undefined) - check report len
500a05e6df3SMatthias Ringwald     bool is_variable   = (parser->descriptor_usage_item.descriptor_item.item_value & 2) != 0;
501a05e6df3SMatthias Ringwald     bool is_signed     = parser->descriptor_usage_item.global_logical_minimum < 0;
5025dd091fdSMatthias Ringwald     int pos_start     = btstack_min(  bit_pos >> 3, parser->report_len);
5035dd091fdSMatthias Ringwald     int pos_end       = btstack_min( (bit_pos + size - 1u) >> 3u, parser->report_len);
5045dd091fdSMatthias Ringwald     int bytes_to_read = pos_end - pos_start + 1;
5055dd091fdSMatthias Ringwald 
5065dd091fdSMatthias Ringwald     int i;
5075dd091fdSMatthias Ringwald     uint32_t multi_byte_value = 0;
5085dd091fdSMatthias Ringwald     for (i=0;i < bytes_to_read;i++){
5095dd091fdSMatthias Ringwald         multi_byte_value |= parser->report[pos_start+i] << (i*8);
5105dd091fdSMatthias Ringwald     }
5115dd091fdSMatthias Ringwald     uint32_t unsigned_value = (multi_byte_value >> (bit_pos & 0x07u)) & ((1u<<size)-1u);
5125dd091fdSMatthias 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);
5135dd091fdSMatthias Ringwald     if (is_variable){
5145dd091fdSMatthias Ringwald         if (is_signed && (unsigned_value & (1u<<(size-1u)))){
5155dd091fdSMatthias Ringwald             *value = unsigned_value - (1u<<size);
5165dd091fdSMatthias Ringwald         } else {
5175dd091fdSMatthias Ringwald             *value = unsigned_value;
5185dd091fdSMatthias Ringwald         }
5195dd091fdSMatthias Ringwald     } else {
5205dd091fdSMatthias Ringwald         *usage  = unsigned_value;
5215dd091fdSMatthias Ringwald         *value  = 1;
5225dd091fdSMatthias Ringwald     }
5235dd091fdSMatthias Ringwald 
5245dd091fdSMatthias Ringwald     parser->have_report_usage_ready = false;
5255dd091fdSMatthias Ringwald }
5265dd091fdSMatthias Ringwald 
5275dd091fdSMatthias Ringwald 
5285dd091fdSMatthias Ringwald // Utility functions
5290ba748f2SMatthias Ringwald 
5302cca3b08SMatthias Ringwald int btstack_hid_get_report_size_for_id(uint16_t report_id, hid_report_type_t report_type, const uint8_t *hid_descriptor,
5312cca3b08SMatthias Ringwald                                        uint16_t hid_descriptor_len) {
532fada7179SMilanka Ringwald     int total_report_size = 0;
533fada7179SMilanka Ringwald     int report_size = 0;
534fada7179SMilanka Ringwald     int report_count = 0;
535279225e6SMatthias Ringwald     int current_report_id = HID_REPORT_ID_UNDEFINED;
536fada7179SMilanka Ringwald 
537960622b0SMatthias Ringwald     btstack_hid_descriptor_iterator_t iterator;
538960622b0SMatthias Ringwald     btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len);
539960622b0SMatthias Ringwald     while (btstack_hid_descriptor_iterator_has_more(&iterator)) {
540960622b0SMatthias Ringwald         const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator);
541fada7179SMilanka Ringwald         int valid_report_type = 0;
542960622b0SMatthias Ringwald         switch (item->item_type) {
543fada7179SMilanka Ringwald             case Global:
544960622b0SMatthias Ringwald                 switch ((GlobalItemTag) item->item_tag) {
545fada7179SMilanka Ringwald                     case ReportID:
546960622b0SMatthias Ringwald                         current_report_id = item->item_value;
547fada7179SMilanka Ringwald                         break;
548fada7179SMilanka Ringwald                     case ReportCount:
549960622b0SMatthias Ringwald                         report_count = item->item_value;
550fada7179SMilanka Ringwald                         break;
551fada7179SMilanka Ringwald                     case ReportSize:
552960622b0SMatthias Ringwald                         report_size = item->item_value;
553fada7179SMilanka Ringwald                         break;
554fada7179SMilanka Ringwald                     default:
555fada7179SMilanka Ringwald                         break;
556fada7179SMilanka Ringwald                 }
557fada7179SMilanka Ringwald                 break;
558fada7179SMilanka Ringwald             case Main:
559fada7179SMilanka Ringwald                 if (current_report_id != report_id) break;
560960622b0SMatthias Ringwald                 switch ((MainItemTag) item->item_tag) {
561fada7179SMilanka Ringwald                     case Input:
562662cddc2SMilanka Ringwald                         if (report_type != HID_REPORT_TYPE_INPUT) break;
563fada7179SMilanka Ringwald                         valid_report_type = 1;
564fada7179SMilanka Ringwald                         break;
565fada7179SMilanka Ringwald                     case Output:
566662cddc2SMilanka Ringwald                         if (report_type != HID_REPORT_TYPE_OUTPUT) break;
567fada7179SMilanka Ringwald                         valid_report_type = 1;
568fada7179SMilanka Ringwald                         break;
569fada7179SMilanka Ringwald                     case Feature:
570662cddc2SMilanka Ringwald                         if (report_type != HID_REPORT_TYPE_FEATURE) break;
571fada7179SMilanka Ringwald                         valid_report_type = 1;
572fada7179SMilanka Ringwald                         break;
573fada7179SMilanka Ringwald                     default:
574fada7179SMilanka Ringwald                         break;
575fada7179SMilanka Ringwald                 }
576fada7179SMilanka Ringwald                 if (!valid_report_type) break;
577fada7179SMilanka Ringwald                 total_report_size += report_count * report_size;
578fada7179SMilanka Ringwald                 break;
579fada7179SMilanka Ringwald             default:
580fada7179SMilanka Ringwald                 break;
581fada7179SMilanka Ringwald         }
58215cf8612Sx0rloser         if (total_report_size > 0 && current_report_id != report_id) break;
583fada7179SMilanka Ringwald     }
584960622b0SMatthias Ringwald 
585960622b0SMatthias Ringwald     if (btstack_hid_descriptor_iterator_valid(&iterator)){
586fada7179SMilanka Ringwald         return (total_report_size + 7) / 8;
587960622b0SMatthias Ringwald     } else {
588960622b0SMatthias Ringwald         return 0;
589960622b0SMatthias Ringwald     }
590fada7179SMilanka Ringwald }
591dbcaefc7SMilanka Ringwald 
592279225e6SMatthias 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){
593279225e6SMatthias Ringwald     uint16_t current_report_id = HID_REPORT_ID_UNDEFINED;
594960622b0SMatthias Ringwald     btstack_hid_descriptor_iterator_t iterator;
595960622b0SMatthias Ringwald     btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len);
596279225e6SMatthias Ringwald     bool report_id_found = false;
597960622b0SMatthias Ringwald     while (btstack_hid_descriptor_iterator_has_more(&iterator)) {
598960622b0SMatthias Ringwald         const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator);
599960622b0SMatthias Ringwald         switch (item->item_type){
600dbcaefc7SMilanka Ringwald             case Global:
601960622b0SMatthias Ringwald                 switch ((GlobalItemTag)item->item_tag){
602dbcaefc7SMilanka Ringwald                     case ReportID:
603960622b0SMatthias Ringwald                         current_report_id = item->item_value;
604279225e6SMatthias Ringwald                         if (current_report_id == report_id) {
605279225e6SMatthias Ringwald                             report_id_found = true;
606279225e6SMatthias Ringwald                         }
607dbcaefc7SMilanka Ringwald                     default:
608dbcaefc7SMilanka Ringwald                         break;
609dbcaefc7SMilanka Ringwald                 }
610dbcaefc7SMilanka Ringwald                 break;
611dbcaefc7SMilanka Ringwald             default:
612dbcaefc7SMilanka Ringwald                 break;
613dbcaefc7SMilanka Ringwald         }
614dbcaefc7SMilanka Ringwald     }
615960622b0SMatthias Ringwald 
616960622b0SMatthias Ringwald     if (btstack_hid_descriptor_iterator_valid(&iterator)) {
617279225e6SMatthias Ringwald         if (report_id_found){
618279225e6SMatthias Ringwald             return HID_REPORT_ID_VALID;
619dbcaefc7SMilanka Ringwald         }
620279225e6SMatthias Ringwald         if ((report_id  == HID_REPORT_ID_UNDEFINED) && (current_report_id == HID_REPORT_ID_UNDEFINED)) {
621279225e6SMatthias Ringwald             return HID_REPORT_ID_VALID;
622279225e6SMatthias Ringwald         }
623279225e6SMatthias Ringwald         return HID_REPORT_ID_UNDECLARED;
624960622b0SMatthias Ringwald     } else {
625960622b0SMatthias Ringwald         return HID_REPORT_ID_INVALID;
626960622b0SMatthias Ringwald     }
627960622b0SMatthias Ringwald }
628dbcaefc7SMilanka Ringwald 
6292cca3b08SMatthias Ringwald bool btstack_hid_report_id_declared(const uint8_t *hid_descriptor, uint16_t hid_descriptor_len) {
630960622b0SMatthias Ringwald     btstack_hid_descriptor_iterator_t iterator;
631960622b0SMatthias Ringwald     btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len);
632960622b0SMatthias Ringwald     while (btstack_hid_descriptor_iterator_has_more(&iterator)) {
633960622b0SMatthias Ringwald         const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator);
634960622b0SMatthias Ringwald         switch (item->item_type){
635dbcaefc7SMilanka Ringwald             case Global:
636960622b0SMatthias Ringwald                 switch ((GlobalItemTag)item->item_tag){
637dbcaefc7SMilanka Ringwald                     case ReportID:
638c17118d0SMatthias Ringwald                         return true;
639dbcaefc7SMilanka Ringwald                     default:
640dbcaefc7SMilanka Ringwald                         break;
641dbcaefc7SMilanka Ringwald                 }
642dbcaefc7SMilanka Ringwald                 break;
643dbcaefc7SMilanka Ringwald             default:
644dbcaefc7SMilanka Ringwald                 break;
645dbcaefc7SMilanka Ringwald         }
646dbcaefc7SMilanka Ringwald     }
647c17118d0SMatthias Ringwald     return false;
648dbcaefc7SMilanka Ringwald }
649