xref: /btstack/src/btstack_hid_parser.c (revision a05e6df3cc4a3f040a8383ac398c2ac1e51c3b9e)
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 
2145dd091fdSMatthias Ringwald const hid_descriptor_item_t * const 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){
3295dd091fdSMatthias Ringwald                 iterator->report_pos_in_bit = 8u;
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)){
466*a05e6df3SMatthias Ringwald         btstack_hid_usage_iterator_get_item(&parser->usage_iterator, &parser->descriptor_usage_item);
4675dd091fdSMatthias Ringwald         // ignore usages for other report ids
468*a05e6df3SMatthias Ringwald         if (parser->descriptor_usage_item.report_id != HID_REPORT_ID_UNDEFINED){
469*a05e6df3SMatthias 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
489*a05e6df3SMatthias Ringwald     uint16_t bit_pos = parser->descriptor_usage_item.bit_pos;
490*a05e6df3SMatthias Ringwald     uint16_t size    = parser->descriptor_usage_item.size;
491*a05e6df3SMatthias Ringwald     *usage_page      = parser->descriptor_usage_item.usage_page;
492*a05e6df3SMatthias Ringwald     *usage           = parser->descriptor_usage_item.usage;
4935dd091fdSMatthias Ringwald 
4945dd091fdSMatthias Ringwald 
4955dd091fdSMatthias Ringwald     // read field (up to 32 bit unsigned, up to 31 bit signed - 32 bit signed behaviour is undefined) - check report len
496*a05e6df3SMatthias Ringwald     bool is_variable   = (parser->descriptor_usage_item.descriptor_item.item_value & 2) != 0;
497*a05e6df3SMatthias Ringwald     bool is_signed     = parser->descriptor_usage_item.global_logical_minimum < 0;
4985dd091fdSMatthias Ringwald     int pos_start     = btstack_min(  bit_pos >> 3, parser->report_len);
4995dd091fdSMatthias Ringwald     int pos_end       = btstack_min( (bit_pos + size - 1u) >> 3u, parser->report_len);
5005dd091fdSMatthias Ringwald     int bytes_to_read = pos_end - pos_start + 1;
5015dd091fdSMatthias Ringwald 
5025dd091fdSMatthias Ringwald     int i;
5035dd091fdSMatthias Ringwald     uint32_t multi_byte_value = 0;
5045dd091fdSMatthias Ringwald     for (i=0;i < bytes_to_read;i++){
5055dd091fdSMatthias Ringwald         multi_byte_value |= parser->report[pos_start+i] << (i*8);
5065dd091fdSMatthias Ringwald     }
5075dd091fdSMatthias Ringwald     uint32_t unsigned_value = (multi_byte_value >> (bit_pos & 0x07u)) & ((1u<<size)-1u);
5085dd091fdSMatthias 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);
5095dd091fdSMatthias Ringwald     if (is_variable){
5105dd091fdSMatthias Ringwald         if (is_signed && (unsigned_value & (1u<<(size-1u)))){
5115dd091fdSMatthias Ringwald             *value = unsigned_value - (1u<<size);
5125dd091fdSMatthias Ringwald         } else {
5135dd091fdSMatthias Ringwald             *value = unsigned_value;
5145dd091fdSMatthias Ringwald         }
5155dd091fdSMatthias Ringwald     } else {
5165dd091fdSMatthias Ringwald         *usage  = unsigned_value;
5175dd091fdSMatthias Ringwald         *value  = 1;
5185dd091fdSMatthias Ringwald     }
5195dd091fdSMatthias Ringwald 
5205dd091fdSMatthias Ringwald     parser->have_report_usage_ready = false;
5215dd091fdSMatthias Ringwald }
5225dd091fdSMatthias Ringwald 
5235dd091fdSMatthias Ringwald 
5245dd091fdSMatthias Ringwald // Utility functions
5250ba748f2SMatthias Ringwald 
5262cca3b08SMatthias Ringwald int btstack_hid_get_report_size_for_id(uint16_t report_id, hid_report_type_t report_type, const uint8_t *hid_descriptor,
5272cca3b08SMatthias Ringwald                                        uint16_t hid_descriptor_len) {
528fada7179SMilanka Ringwald     int total_report_size = 0;
529fada7179SMilanka Ringwald     int report_size = 0;
530fada7179SMilanka Ringwald     int report_count = 0;
531279225e6SMatthias Ringwald     int current_report_id = HID_REPORT_ID_UNDEFINED;
532fada7179SMilanka Ringwald 
533960622b0SMatthias Ringwald     btstack_hid_descriptor_iterator_t iterator;
534960622b0SMatthias Ringwald     btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len);
535960622b0SMatthias Ringwald     while (btstack_hid_descriptor_iterator_has_more(&iterator)) {
536960622b0SMatthias Ringwald         const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator);
537fada7179SMilanka Ringwald         int valid_report_type = 0;
538960622b0SMatthias Ringwald         switch (item->item_type) {
539fada7179SMilanka Ringwald             case Global:
540960622b0SMatthias Ringwald                 switch ((GlobalItemTag) item->item_tag) {
541fada7179SMilanka Ringwald                     case ReportID:
542960622b0SMatthias Ringwald                         current_report_id = item->item_value;
543fada7179SMilanka Ringwald                         break;
544fada7179SMilanka Ringwald                     case ReportCount:
545960622b0SMatthias Ringwald                         report_count = item->item_value;
546fada7179SMilanka Ringwald                         break;
547fada7179SMilanka Ringwald                     case ReportSize:
548960622b0SMatthias Ringwald                         report_size = item->item_value;
549fada7179SMilanka Ringwald                         break;
550fada7179SMilanka Ringwald                     default:
551fada7179SMilanka Ringwald                         break;
552fada7179SMilanka Ringwald                 }
553fada7179SMilanka Ringwald                 break;
554fada7179SMilanka Ringwald             case Main:
555fada7179SMilanka Ringwald                 if (current_report_id != report_id) break;
556960622b0SMatthias Ringwald                 switch ((MainItemTag) item->item_tag) {
557fada7179SMilanka Ringwald                     case Input:
558662cddc2SMilanka Ringwald                         if (report_type != HID_REPORT_TYPE_INPUT) break;
559fada7179SMilanka Ringwald                         valid_report_type = 1;
560fada7179SMilanka Ringwald                         break;
561fada7179SMilanka Ringwald                     case Output:
562662cddc2SMilanka Ringwald                         if (report_type != HID_REPORT_TYPE_OUTPUT) break;
563fada7179SMilanka Ringwald                         valid_report_type = 1;
564fada7179SMilanka Ringwald                         break;
565fada7179SMilanka Ringwald                     case Feature:
566662cddc2SMilanka Ringwald                         if (report_type != HID_REPORT_TYPE_FEATURE) break;
567fada7179SMilanka Ringwald                         valid_report_type = 1;
568fada7179SMilanka Ringwald                         break;
569fada7179SMilanka Ringwald                     default:
570fada7179SMilanka Ringwald                         break;
571fada7179SMilanka Ringwald                 }
572fada7179SMilanka Ringwald                 if (!valid_report_type) break;
573fada7179SMilanka Ringwald                 total_report_size += report_count * report_size;
574fada7179SMilanka Ringwald                 break;
575fada7179SMilanka Ringwald             default:
576fada7179SMilanka Ringwald                 break;
577fada7179SMilanka Ringwald         }
57815cf8612Sx0rloser         if (total_report_size > 0 && current_report_id != report_id) break;
579fada7179SMilanka Ringwald     }
580960622b0SMatthias Ringwald 
581960622b0SMatthias Ringwald     if (btstack_hid_descriptor_iterator_valid(&iterator)){
582fada7179SMilanka Ringwald         return (total_report_size + 7) / 8;
583960622b0SMatthias Ringwald     } else {
584960622b0SMatthias Ringwald         return 0;
585960622b0SMatthias Ringwald     }
586fada7179SMilanka Ringwald }
587dbcaefc7SMilanka Ringwald 
588279225e6SMatthias 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){
589279225e6SMatthias Ringwald     uint16_t current_report_id = HID_REPORT_ID_UNDEFINED;
590960622b0SMatthias Ringwald     btstack_hid_descriptor_iterator_t iterator;
591960622b0SMatthias Ringwald     btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len);
592279225e6SMatthias Ringwald     bool report_id_found = false;
593960622b0SMatthias Ringwald     while (btstack_hid_descriptor_iterator_has_more(&iterator)) {
594960622b0SMatthias Ringwald         const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator);
595960622b0SMatthias Ringwald         switch (item->item_type){
596dbcaefc7SMilanka Ringwald             case Global:
597960622b0SMatthias Ringwald                 switch ((GlobalItemTag)item->item_tag){
598dbcaefc7SMilanka Ringwald                     case ReportID:
599960622b0SMatthias Ringwald                         current_report_id = item->item_value;
600279225e6SMatthias Ringwald                         if (current_report_id == report_id) {
601279225e6SMatthias Ringwald                             report_id_found = true;
602279225e6SMatthias Ringwald                         }
603dbcaefc7SMilanka Ringwald                     default:
604dbcaefc7SMilanka Ringwald                         break;
605dbcaefc7SMilanka Ringwald                 }
606dbcaefc7SMilanka Ringwald                 break;
607dbcaefc7SMilanka Ringwald             default:
608dbcaefc7SMilanka Ringwald                 break;
609dbcaefc7SMilanka Ringwald         }
610dbcaefc7SMilanka Ringwald     }
611960622b0SMatthias Ringwald 
612960622b0SMatthias Ringwald     if (btstack_hid_descriptor_iterator_valid(&iterator)) {
613279225e6SMatthias Ringwald         if (report_id_found){
614279225e6SMatthias Ringwald             return HID_REPORT_ID_VALID;
615dbcaefc7SMilanka Ringwald         }
616279225e6SMatthias Ringwald         if ((report_id  == HID_REPORT_ID_UNDEFINED) && (current_report_id == HID_REPORT_ID_UNDEFINED)) {
617279225e6SMatthias Ringwald             return HID_REPORT_ID_VALID;
618279225e6SMatthias Ringwald         }
619279225e6SMatthias Ringwald         return HID_REPORT_ID_UNDECLARED;
620960622b0SMatthias Ringwald     } else {
621960622b0SMatthias Ringwald         return HID_REPORT_ID_INVALID;
622960622b0SMatthias Ringwald     }
623960622b0SMatthias Ringwald }
624dbcaefc7SMilanka Ringwald 
6252cca3b08SMatthias Ringwald bool btstack_hid_report_id_declared(const uint8_t *hid_descriptor, uint16_t hid_descriptor_len) {
626960622b0SMatthias Ringwald     btstack_hid_descriptor_iterator_t iterator;
627960622b0SMatthias Ringwald     btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len);
628960622b0SMatthias Ringwald     while (btstack_hid_descriptor_iterator_has_more(&iterator)) {
629960622b0SMatthias Ringwald         const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator);
630960622b0SMatthias Ringwald         switch (item->item_type){
631dbcaefc7SMilanka Ringwald             case Global:
632960622b0SMatthias Ringwald                 switch ((GlobalItemTag)item->item_tag){
633dbcaefc7SMilanka Ringwald                     case ReportID:
634c17118d0SMatthias Ringwald                         return true;
635dbcaefc7SMilanka Ringwald                     default:
636dbcaefc7SMilanka Ringwald                         break;
637dbcaefc7SMilanka Ringwald                 }
638dbcaefc7SMilanka Ringwald                 break;
639dbcaefc7SMilanka Ringwald             default:
640dbcaefc7SMilanka Ringwald                 break;
641dbcaefc7SMilanka Ringwald         }
642dbcaefc7SMilanka Ringwald     }
643c17118d0SMatthias Ringwald     return false;
644dbcaefc7SMilanka Ringwald }
645