1*12ccb71bSMatthias Ringwald /* 2*12ccb71bSMatthias Ringwald * Copyright (C) 2017 BlueKitchen GmbH 3*12ccb71bSMatthias Ringwald * 4*12ccb71bSMatthias Ringwald * Redistribution and use in source and binary forms, with or without 5*12ccb71bSMatthias Ringwald * modification, are permitted provided that the following conditions 6*12ccb71bSMatthias Ringwald * are met: 7*12ccb71bSMatthias Ringwald * 8*12ccb71bSMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 9*12ccb71bSMatthias Ringwald * notice, this list of conditions and the following disclaimer. 10*12ccb71bSMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11*12ccb71bSMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 12*12ccb71bSMatthias Ringwald * documentation and/or other materials provided with the distribution. 13*12ccb71bSMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 14*12ccb71bSMatthias Ringwald * contributors may be used to endorse or promote products derived 15*12ccb71bSMatthias Ringwald * from this software without specific prior written permission. 16*12ccb71bSMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 17*12ccb71bSMatthias Ringwald * personal benefit and not for any commercial purpose or for 18*12ccb71bSMatthias Ringwald * monetary gain. 19*12ccb71bSMatthias Ringwald * 20*12ccb71bSMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21*12ccb71bSMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22*12ccb71bSMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23*12ccb71bSMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24*12ccb71bSMatthias Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25*12ccb71bSMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26*12ccb71bSMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27*12ccb71bSMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28*12ccb71bSMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29*12ccb71bSMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30*12ccb71bSMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31*12ccb71bSMatthias Ringwald * SUCH DAMAGE. 32*12ccb71bSMatthias Ringwald * 33*12ccb71bSMatthias Ringwald * Please inquire about commercial licensing options at 34*12ccb71bSMatthias Ringwald * [email protected] 35*12ccb71bSMatthias Ringwald * 36*12ccb71bSMatthias Ringwald */ 37*12ccb71bSMatthias Ringwald 38*12ccb71bSMatthias Ringwald #define __BTSTACK_FILE__ "btstack_hid_parser.c" 39*12ccb71bSMatthias Ringwald 40*12ccb71bSMatthias Ringwald #include <string.h> 41*12ccb71bSMatthias Ringwald 42*12ccb71bSMatthias Ringwald #include "btstack_hid_parser.h" 43*12ccb71bSMatthias Ringwald #include "btstack_util.h" 44*12ccb71bSMatthias Ringwald #include "btstack_debug.h" 45*12ccb71bSMatthias Ringwald 46*12ccb71bSMatthias Ringwald // Not implemented: 47*12ccb71bSMatthias Ringwald // - Support for Push/Pop 48*12ccb71bSMatthias Ringwald // - Optional Pretty Print of HID Descripor 49*12ccb71bSMatthias Ringwald // - Support to query descriptort for contained usages, e.g. to detect keyboard or mouse 50*12ccb71bSMatthias Ringwald 51*12ccb71bSMatthias Ringwald // #define HID_PARSER_PRETTY_PRINT 52*12ccb71bSMatthias Ringwald 53*12ccb71bSMatthias Ringwald /* 54*12ccb71bSMatthias Ringwald * btstack_hid_parser.c 55*12ccb71bSMatthias Ringwald */ 56*12ccb71bSMatthias Ringwald 57*12ccb71bSMatthias Ringwald 58*12ccb71bSMatthias Ringwald typedef enum { 59*12ccb71bSMatthias Ringwald Main=0, 60*12ccb71bSMatthias Ringwald Global, 61*12ccb71bSMatthias Ringwald Local, 62*12ccb71bSMatthias Ringwald Reserved 63*12ccb71bSMatthias Ringwald } TagType; 64*12ccb71bSMatthias Ringwald 65*12ccb71bSMatthias Ringwald typedef enum { 66*12ccb71bSMatthias Ringwald Input=8, 67*12ccb71bSMatthias Ringwald Output, 68*12ccb71bSMatthias Ringwald Coll, 69*12ccb71bSMatthias Ringwald Feature, 70*12ccb71bSMatthias Ringwald EndColl 71*12ccb71bSMatthias Ringwald } MainItemTag; 72*12ccb71bSMatthias Ringwald 73*12ccb71bSMatthias Ringwald typedef enum { 74*12ccb71bSMatthias Ringwald UsagePage, 75*12ccb71bSMatthias Ringwald LogicalMinimum, 76*12ccb71bSMatthias Ringwald LogicalMaximum, 77*12ccb71bSMatthias Ringwald PhysicalMinimum, 78*12ccb71bSMatthias Ringwald PhysicalMaximum, 79*12ccb71bSMatthias Ringwald UnitExponent, 80*12ccb71bSMatthias Ringwald Unit, 81*12ccb71bSMatthias Ringwald ReportSize, 82*12ccb71bSMatthias Ringwald ReportID, 83*12ccb71bSMatthias Ringwald ReportCount, 84*12ccb71bSMatthias Ringwald Push, 85*12ccb71bSMatthias Ringwald Pop 86*12ccb71bSMatthias Ringwald } GlobalItemTag; 87*12ccb71bSMatthias Ringwald 88*12ccb71bSMatthias Ringwald typedef enum { 89*12ccb71bSMatthias Ringwald Usage, 90*12ccb71bSMatthias Ringwald UsageMinimum, 91*12ccb71bSMatthias Ringwald UsageMaximum, 92*12ccb71bSMatthias Ringwald DesignatorIndex, 93*12ccb71bSMatthias Ringwald DesignatorMinimum, 94*12ccb71bSMatthias Ringwald DesignatorMaximum, 95*12ccb71bSMatthias Ringwald StringIndex, 96*12ccb71bSMatthias Ringwald StringMinimum, 97*12ccb71bSMatthias Ringwald StringMaximum, 98*12ccb71bSMatthias Ringwald Delimiter 99*12ccb71bSMatthias Ringwald } LocalItemTag; 100*12ccb71bSMatthias Ringwald 101*12ccb71bSMatthias Ringwald const int hid_item_sizes[] = { 0, 1, 2, 4 }; 102*12ccb71bSMatthias Ringwald 103*12ccb71bSMatthias Ringwald #ifdef HID_PARSER_PRETTY_PRINT 104*12ccb71bSMatthias Ringwald 105*12ccb71bSMatthias Ringwald static const char * type_names[] = { 106*12ccb71bSMatthias Ringwald "Main", 107*12ccb71bSMatthias Ringwald "Global", 108*12ccb71bSMatthias Ringwald "Local", 109*12ccb71bSMatthias Ringwald "Reserved" 110*12ccb71bSMatthias Ringwald }; 111*12ccb71bSMatthias Ringwald static const char * main_tags[] = { 112*12ccb71bSMatthias Ringwald "", 113*12ccb71bSMatthias Ringwald "", 114*12ccb71bSMatthias Ringwald "", 115*12ccb71bSMatthias Ringwald "", 116*12ccb71bSMatthias Ringwald "", 117*12ccb71bSMatthias Ringwald "", 118*12ccb71bSMatthias Ringwald "", 119*12ccb71bSMatthias Ringwald "", 120*12ccb71bSMatthias Ringwald "Input ", 121*12ccb71bSMatthias Ringwald "Output", 122*12ccb71bSMatthias Ringwald "Collection", 123*12ccb71bSMatthias Ringwald "Feature", 124*12ccb71bSMatthias Ringwald "End Collection", 125*12ccb71bSMatthias Ringwald "Reserved", 126*12ccb71bSMatthias Ringwald "Reserved", 127*12ccb71bSMatthias Ringwald "Reserved" 128*12ccb71bSMatthias Ringwald }; 129*12ccb71bSMatthias Ringwald static const char * global_tags[] = { 130*12ccb71bSMatthias Ringwald "Usage Page", 131*12ccb71bSMatthias Ringwald "Logical Minimum", 132*12ccb71bSMatthias Ringwald "Logical Maximum", 133*12ccb71bSMatthias Ringwald "Physical Minimum", 134*12ccb71bSMatthias Ringwald "Physical Maximum", 135*12ccb71bSMatthias Ringwald "Unit Exponent", 136*12ccb71bSMatthias Ringwald "Unit", 137*12ccb71bSMatthias Ringwald "Report Size", 138*12ccb71bSMatthias Ringwald "Report ID", 139*12ccb71bSMatthias Ringwald "Report Count", 140*12ccb71bSMatthias Ringwald "Push", 141*12ccb71bSMatthias Ringwald "Pop", 142*12ccb71bSMatthias Ringwald "Reserved", 143*12ccb71bSMatthias Ringwald "Reserved", 144*12ccb71bSMatthias Ringwald "Reserved", 145*12ccb71bSMatthias Ringwald "Reserved" 146*12ccb71bSMatthias Ringwald }; 147*12ccb71bSMatthias Ringwald static const char * local_tags[] = { 148*12ccb71bSMatthias Ringwald "Usage", 149*12ccb71bSMatthias Ringwald "Usage Minimum", 150*12ccb71bSMatthias Ringwald "Usage Maximum", 151*12ccb71bSMatthias Ringwald "Designator Index", 152*12ccb71bSMatthias Ringwald "Designator Minimum", 153*12ccb71bSMatthias Ringwald "Designator Maximum", 154*12ccb71bSMatthias Ringwald "String Index", 155*12ccb71bSMatthias Ringwald "String Minimum", 156*12ccb71bSMatthias Ringwald "String Maximum", 157*12ccb71bSMatthias Ringwald "Delimiter", 158*12ccb71bSMatthias Ringwald "Reserved", 159*12ccb71bSMatthias Ringwald "Reserved", 160*12ccb71bSMatthias Ringwald "Reserved", 161*12ccb71bSMatthias Ringwald "Reserved", 162*12ccb71bSMatthias Ringwald "Reserved", 163*12ccb71bSMatthias Ringwald "Reserved" 164*12ccb71bSMatthias Ringwald }; 165*12ccb71bSMatthias Ringwald #endif 166*12ccb71bSMatthias Ringwald 167*12ccb71bSMatthias Ringwald static void hid_pretty_print_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){ 168*12ccb71bSMatthias Ringwald #ifdef HID_PARSER_PRETTY_PRINT 169*12ccb71bSMatthias Ringwald const char ** item_tag_table; 170*12ccb71bSMatthias Ringwald switch (item->item_type){ 171*12ccb71bSMatthias Ringwald case Main: 172*12ccb71bSMatthias Ringwald item_tag_table = main_tags; 173*12ccb71bSMatthias Ringwald break; 174*12ccb71bSMatthias Ringwald case Global: 175*12ccb71bSMatthias Ringwald item_tag_table = global_tags; 176*12ccb71bSMatthias Ringwald break; 177*12ccb71bSMatthias Ringwald case Local: 178*12ccb71bSMatthias Ringwald item_tag_table = local_tags; 179*12ccb71bSMatthias Ringwald break; 180*12ccb71bSMatthias Ringwald default: 181*12ccb71bSMatthias Ringwald item_tag_table = NULL; 182*12ccb71bSMatthias Ringwald break; 183*12ccb71bSMatthias Ringwald } 184*12ccb71bSMatthias Ringwald const char * item_tag_name = "Invalid"; 185*12ccb71bSMatthias Ringwald if (item_tag_table){ 186*12ccb71bSMatthias Ringwald item_tag_name = item_tag_table[item->item_tag]; 187*12ccb71bSMatthias Ringwald } 188*12ccb71bSMatthias Ringwald log_info("%-15s (%-6s) // %02x 0x%0008x", item_tag_table[item->item_tag], type_names[item->item_type], parser->descriptor[parser->descriptor_pos], item->item_value); 189*12ccb71bSMatthias Ringwald #else 190*12ccb71bSMatthias Ringwald UNUSED(parser); 191*12ccb71bSMatthias Ringwald UNUSED(item); 192*12ccb71bSMatthias Ringwald #endif 193*12ccb71bSMatthias Ringwald } 194*12ccb71bSMatthias Ringwald 195*12ccb71bSMatthias Ringwald // parse descriptor item and read up to 32-bit bit value 196*12ccb71bSMatthias Ringwald static void btstack_hid_parse_descriptor_item(hid_descriptor_item_t * item, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len){ 197*12ccb71bSMatthias Ringwald // parse item header 198*12ccb71bSMatthias Ringwald if (hid_descriptor_len < 1) return; 199*12ccb71bSMatthias Ringwald uint16_t pos = 0; 200*12ccb71bSMatthias Ringwald uint8_t item_header = hid_descriptor[pos++]; 201*12ccb71bSMatthias Ringwald item->data_size = hid_item_sizes[item_header & 0x03]; 202*12ccb71bSMatthias Ringwald item->item_type = (item_header & 0x0c) >> 2; 203*12ccb71bSMatthias Ringwald item->item_tag = (item_header & 0xf0) >> 4; 204*12ccb71bSMatthias Ringwald // long item 205*12ccb71bSMatthias Ringwald if (item->data_size == 2 && item->item_tag == 0x0f && item->item_type == 3){ 206*12ccb71bSMatthias Ringwald if (hid_descriptor_len < 3) return; 207*12ccb71bSMatthias Ringwald item->data_size = hid_descriptor[pos++]; 208*12ccb71bSMatthias Ringwald item->item_tag = hid_descriptor[pos++]; 209*12ccb71bSMatthias Ringwald } 210*12ccb71bSMatthias Ringwald item->item_size = pos + item->data_size; 211*12ccb71bSMatthias Ringwald item->item_value = 0; 212*12ccb71bSMatthias Ringwald 213*12ccb71bSMatthias Ringwald // read item value 214*12ccb71bSMatthias Ringwald if (hid_descriptor_len < item->item_size) return; 215*12ccb71bSMatthias Ringwald if (item->data_size > 4) return; 216*12ccb71bSMatthias Ringwald int i; 217*12ccb71bSMatthias Ringwald int sgnd = item->item_type == Global && item->item_tag > 0 && item->item_tag < 5; 218*12ccb71bSMatthias Ringwald int32_t value = 0; 219*12ccb71bSMatthias Ringwald uint8_t latest_byte = 0; 220*12ccb71bSMatthias Ringwald for (i=0;i<item->data_size;i++){ 221*12ccb71bSMatthias Ringwald latest_byte = hid_descriptor[pos++]; 222*12ccb71bSMatthias Ringwald value = (latest_byte << (8*i)) | value; 223*12ccb71bSMatthias Ringwald } 224*12ccb71bSMatthias Ringwald if (sgnd && item->data_size > 0){ 225*12ccb71bSMatthias Ringwald if (latest_byte & 0x80) { 226*12ccb71bSMatthias Ringwald value -= 1 << (item->data_size*8); 227*12ccb71bSMatthias Ringwald } 228*12ccb71bSMatthias Ringwald } 229*12ccb71bSMatthias Ringwald item->item_value = value; 230*12ccb71bSMatthias Ringwald } 231*12ccb71bSMatthias Ringwald 232*12ccb71bSMatthias Ringwald static void btstack_hid_handle_global_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){ 233*12ccb71bSMatthias Ringwald switch(item->item_tag){ 234*12ccb71bSMatthias Ringwald case UsagePage: 235*12ccb71bSMatthias Ringwald parser->global_usage_page = item->item_value; 236*12ccb71bSMatthias Ringwald break; 237*12ccb71bSMatthias Ringwald case LogicalMinimum: 238*12ccb71bSMatthias Ringwald parser->global_logical_minimum = item->item_value; 239*12ccb71bSMatthias Ringwald break; 240*12ccb71bSMatthias Ringwald case LogicalMaximum: 241*12ccb71bSMatthias Ringwald parser->global_logical_maximum = item->item_value; 242*12ccb71bSMatthias Ringwald break; 243*12ccb71bSMatthias Ringwald case ReportSize: 244*12ccb71bSMatthias Ringwald parser->global_report_size = item->item_value; 245*12ccb71bSMatthias Ringwald break; 246*12ccb71bSMatthias Ringwald case ReportID: 247*12ccb71bSMatthias Ringwald if (parser->active_record && parser->global_report_id != item->item_value){ 248*12ccb71bSMatthias Ringwald // log_debug("New report, don't match anymore"); 249*12ccb71bSMatthias Ringwald parser->active_record = 0; 250*12ccb71bSMatthias Ringwald } 251*12ccb71bSMatthias Ringwald parser->global_report_id = item->item_value; 252*12ccb71bSMatthias Ringwald // log_info("- Report ID: %02x", parser->global_report_id); 253*12ccb71bSMatthias Ringwald break; 254*12ccb71bSMatthias Ringwald case ReportCount: 255*12ccb71bSMatthias Ringwald parser->global_report_count = item->item_value; 256*12ccb71bSMatthias Ringwald break; 257*12ccb71bSMatthias Ringwald default: 258*12ccb71bSMatthias Ringwald break; 259*12ccb71bSMatthias Ringwald } 260*12ccb71bSMatthias Ringwald } 261*12ccb71bSMatthias Ringwald 262*12ccb71bSMatthias Ringwald static void hid_find_next_usage(btstack_hid_parser_t * parser){ 263*12ccb71bSMatthias Ringwald while (parser->available_usages == 0 && parser->usage_pos < parser->descriptor_pos){ 264*12ccb71bSMatthias Ringwald hid_descriptor_item_t usage_item; 265*12ccb71bSMatthias Ringwald // parser->usage_pos < parser->descriptor_pos < parser->descriptor_len 266*12ccb71bSMatthias Ringwald btstack_hid_parse_descriptor_item(&usage_item, &parser->descriptor[parser->usage_pos], parser->descriptor_len - parser->usage_pos); 267*12ccb71bSMatthias Ringwald if (usage_item.item_type == Global && usage_item.item_tag == UsagePage){ 268*12ccb71bSMatthias Ringwald parser->usage_page = usage_item.item_value; 269*12ccb71bSMatthias Ringwald } 270*12ccb71bSMatthias Ringwald if (usage_item.item_type == Local){ 271*12ccb71bSMatthias Ringwald uint32_t usage_value = (usage_item.data_size > 2) ? usage_item.item_value : (parser->usage_page << 16) | usage_item.item_value; 272*12ccb71bSMatthias Ringwald switch (usage_item.item_tag){ 273*12ccb71bSMatthias Ringwald case Usage: 274*12ccb71bSMatthias Ringwald parser->available_usages = 1; 275*12ccb71bSMatthias Ringwald parser->usage_minimum = usage_value; 276*12ccb71bSMatthias Ringwald break; 277*12ccb71bSMatthias Ringwald case UsageMinimum: 278*12ccb71bSMatthias Ringwald parser->usage_minimum = usage_value; 279*12ccb71bSMatthias Ringwald parser->have_usage_min = 1; 280*12ccb71bSMatthias Ringwald break; 281*12ccb71bSMatthias Ringwald case UsageMaximum: 282*12ccb71bSMatthias Ringwald parser->usage_maximum = usage_value; 283*12ccb71bSMatthias Ringwald parser->have_usage_max = 1; 284*12ccb71bSMatthias Ringwald break; 285*12ccb71bSMatthias Ringwald default: 286*12ccb71bSMatthias Ringwald break; 287*12ccb71bSMatthias Ringwald } 288*12ccb71bSMatthias Ringwald if (parser->have_usage_min && parser->have_usage_max){ 289*12ccb71bSMatthias Ringwald parser->available_usages = parser->usage_maximum - parser->usage_minimum + 1; 290*12ccb71bSMatthias Ringwald parser->have_usage_min = 0; 291*12ccb71bSMatthias Ringwald parser->have_usage_max = 0; 292*12ccb71bSMatthias Ringwald } 293*12ccb71bSMatthias Ringwald } 294*12ccb71bSMatthias Ringwald parser->usage_pos += usage_item.item_size; 295*12ccb71bSMatthias Ringwald } 296*12ccb71bSMatthias Ringwald } 297*12ccb71bSMatthias Ringwald 298*12ccb71bSMatthias Ringwald static void hid_process_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){ 299*12ccb71bSMatthias Ringwald hid_pretty_print_item(parser, item); 300*12ccb71bSMatthias Ringwald int valid_field = 0; 301*12ccb71bSMatthias Ringwald switch (item->item_type){ 302*12ccb71bSMatthias Ringwald case Main: 303*12ccb71bSMatthias Ringwald switch (item->item_tag){ 304*12ccb71bSMatthias Ringwald case Input: 305*12ccb71bSMatthias Ringwald valid_field = parser->report_type == BTSTACK_HID_REPORT_TYPE_INPUT; 306*12ccb71bSMatthias Ringwald break; 307*12ccb71bSMatthias Ringwald case Output: 308*12ccb71bSMatthias Ringwald valid_field = parser->report_type == BTSTACK_HID_REPORT_TYPE_OUTPUT; 309*12ccb71bSMatthias Ringwald break; 310*12ccb71bSMatthias Ringwald case Feature: 311*12ccb71bSMatthias Ringwald valid_field = parser->report_type == BTSTACK_HID_REPORT_TYPE_FEATURE; 312*12ccb71bSMatthias Ringwald break; 313*12ccb71bSMatthias Ringwald default: 314*12ccb71bSMatthias Ringwald break; 315*12ccb71bSMatthias Ringwald } 316*12ccb71bSMatthias Ringwald break; 317*12ccb71bSMatthias Ringwald case Global: 318*12ccb71bSMatthias Ringwald btstack_hid_handle_global_item(parser, item); 319*12ccb71bSMatthias Ringwald break; 320*12ccb71bSMatthias Ringwald case Local: 321*12ccb71bSMatthias Ringwald break; 322*12ccb71bSMatthias Ringwald } 323*12ccb71bSMatthias Ringwald if (!valid_field) return; 324*12ccb71bSMatthias Ringwald 325*12ccb71bSMatthias Ringwald // verify record id 326*12ccb71bSMatthias Ringwald if (parser->global_report_id && !parser->active_record){ 327*12ccb71bSMatthias Ringwald if (parser->report[0] != parser->global_report_id){ 328*12ccb71bSMatthias Ringwald return; 329*12ccb71bSMatthias Ringwald } 330*12ccb71bSMatthias Ringwald parser->report_pos_in_bit += 8; 331*12ccb71bSMatthias Ringwald } 332*12ccb71bSMatthias Ringwald parser->active_record = 1; 333*12ccb71bSMatthias Ringwald // handle constant fields used for padding 334*12ccb71bSMatthias Ringwald if (item->item_value & 1){ 335*12ccb71bSMatthias Ringwald int item_bits = parser->global_report_size * parser->global_report_count; 336*12ccb71bSMatthias Ringwald #ifdef HID_PARSER_PRETTY_PRINT 337*12ccb71bSMatthias Ringwald log_info("- Skip %u constant bits", item_bits); 338*12ccb71bSMatthias Ringwald #endif 339*12ccb71bSMatthias Ringwald parser->report_pos_in_bit += item_bits; 340*12ccb71bSMatthias Ringwald return; 341*12ccb71bSMatthias Ringwald } 342*12ccb71bSMatthias Ringwald // Empty Item 343*12ccb71bSMatthias Ringwald if (parser->global_report_count == 0) return; 344*12ccb71bSMatthias Ringwald // let's start 345*12ccb71bSMatthias Ringwald parser->required_usages = parser->global_report_count; 346*12ccb71bSMatthias Ringwald } 347*12ccb71bSMatthias Ringwald 348*12ccb71bSMatthias Ringwald static void hid_post_process_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){ 349*12ccb71bSMatthias Ringwald if (item->item_type == Main){ 350*12ccb71bSMatthias Ringwald // reset usage 351*12ccb71bSMatthias Ringwald parser->usage_pos = parser->descriptor_pos; 352*12ccb71bSMatthias Ringwald parser->usage_page = parser->global_usage_page; 353*12ccb71bSMatthias Ringwald } 354*12ccb71bSMatthias Ringwald parser->descriptor_pos += item->item_size; 355*12ccb71bSMatthias Ringwald } 356*12ccb71bSMatthias Ringwald 357*12ccb71bSMatthias Ringwald static void btstack_hid_parser_find_next_usage(btstack_hid_parser_t * parser){ 358*12ccb71bSMatthias Ringwald while (parser->state == BTSTACK_HID_PARSER_SCAN_FOR_REPORT_ITEM){ 359*12ccb71bSMatthias Ringwald if (parser->descriptor_pos >= parser->descriptor_len){ 360*12ccb71bSMatthias Ringwald // end of descriptor 361*12ccb71bSMatthias Ringwald parser->state = BTSTACK_HID_PARSER_COMPLETE; 362*12ccb71bSMatthias Ringwald break; 363*12ccb71bSMatthias Ringwald } 364*12ccb71bSMatthias Ringwald btstack_hid_parse_descriptor_item(&parser->descriptor_item, &parser->descriptor[parser->descriptor_pos], parser->descriptor_len - parser->descriptor_pos); 365*12ccb71bSMatthias Ringwald hid_process_item(parser, &parser->descriptor_item); 366*12ccb71bSMatthias Ringwald if (parser->required_usages){ 367*12ccb71bSMatthias Ringwald hid_find_next_usage(parser); 368*12ccb71bSMatthias Ringwald if (parser->available_usages) { 369*12ccb71bSMatthias Ringwald parser->state = BTSTACK_HID_PARSER_USAGES_AVAILABLE; 370*12ccb71bSMatthias Ringwald } else { 371*12ccb71bSMatthias Ringwald log_error("no usages found"); 372*12ccb71bSMatthias Ringwald parser->state = BTSTACK_HID_PARSER_COMPLETE; 373*12ccb71bSMatthias Ringwald } 374*12ccb71bSMatthias Ringwald } else { 375*12ccb71bSMatthias Ringwald hid_post_process_item(parser, &parser->descriptor_item); 376*12ccb71bSMatthias Ringwald } 377*12ccb71bSMatthias Ringwald } 378*12ccb71bSMatthias Ringwald } 379*12ccb71bSMatthias Ringwald 380*12ccb71bSMatthias Ringwald // PUBLIC API 381*12ccb71bSMatthias Ringwald 382*12ccb71bSMatthias Ringwald void btstack_hid_parser_init(btstack_hid_parser_t * parser, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len, btstack_hid_report_type_t hid_report_type, const uint8_t * hid_report, uint16_t hid_report_len){ 383*12ccb71bSMatthias Ringwald 384*12ccb71bSMatthias Ringwald memset(parser, 0, sizeof(btstack_hid_parser_t)); 385*12ccb71bSMatthias Ringwald 386*12ccb71bSMatthias Ringwald parser->descriptor = hid_descriptor; 387*12ccb71bSMatthias Ringwald parser->descriptor_len = hid_descriptor_len; 388*12ccb71bSMatthias Ringwald parser->report_type = hid_report_type; 389*12ccb71bSMatthias Ringwald parser->report = hid_report; 390*12ccb71bSMatthias Ringwald parser->report_len = hid_report_len; 391*12ccb71bSMatthias Ringwald parser->state = BTSTACK_HID_PARSER_SCAN_FOR_REPORT_ITEM; 392*12ccb71bSMatthias Ringwald 393*12ccb71bSMatthias Ringwald btstack_hid_parser_find_next_usage(parser); 394*12ccb71bSMatthias Ringwald } 395*12ccb71bSMatthias Ringwald 396*12ccb71bSMatthias Ringwald int btstack_hid_parser_has_more(btstack_hid_parser_t * parser){ 397*12ccb71bSMatthias Ringwald return parser->state == BTSTACK_HID_PARSER_USAGES_AVAILABLE; 398*12ccb71bSMatthias Ringwald } 399*12ccb71bSMatthias Ringwald 400*12ccb71bSMatthias Ringwald void btstack_hid_parser_get_field(btstack_hid_parser_t * parser, uint16_t * usage_page, uint16_t * usage, int32_t * value){ 401*12ccb71bSMatthias Ringwald 402*12ccb71bSMatthias Ringwald *usage_page = parser->usage_minimum >> 16; 403*12ccb71bSMatthias Ringwald 404*12ccb71bSMatthias Ringwald // read field (up to 32 bit unsigned, up to 31 bit signed - 32 bit signed behaviour is undefined) - check report len 405*12ccb71bSMatthias Ringwald int is_variable = parser->descriptor_item.item_value & 2; 406*12ccb71bSMatthias Ringwald int is_signed = parser->global_logical_minimum < 0; 407*12ccb71bSMatthias Ringwald int pos_start = btstack_min( parser->report_pos_in_bit >> 3, parser->report_len); 408*12ccb71bSMatthias Ringwald int pos_end = btstack_min( (parser->report_pos_in_bit + parser->global_report_size - 1) >> 3, parser->report_len); 409*12ccb71bSMatthias Ringwald int bytes_to_read = pos_end - pos_start + 1; 410*12ccb71bSMatthias Ringwald int i; 411*12ccb71bSMatthias Ringwald uint32_t multi_byte_value = 0; 412*12ccb71bSMatthias Ringwald for (i=0;i < bytes_to_read;i++){ 413*12ccb71bSMatthias Ringwald multi_byte_value |= parser->report[pos_start+i] << (i*8); 414*12ccb71bSMatthias Ringwald } 415*12ccb71bSMatthias Ringwald uint32_t unsigned_value = (multi_byte_value >> (parser->report_pos_in_bit & 0x07)) & ((1<<parser->global_report_size)-1); 416*12ccb71bSMatthias 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); 417*12ccb71bSMatthias Ringwald if (is_variable){ 418*12ccb71bSMatthias Ringwald *usage = parser->usage_minimum & 0xffff; 419*12ccb71bSMatthias Ringwald if (is_signed && (unsigned_value & (1<<(parser->global_report_size-1)))){ 420*12ccb71bSMatthias Ringwald *value = unsigned_value - (1<<parser->global_report_size); 421*12ccb71bSMatthias Ringwald } else { 422*12ccb71bSMatthias Ringwald *value = unsigned_value; 423*12ccb71bSMatthias Ringwald } 424*12ccb71bSMatthias Ringwald } else { 425*12ccb71bSMatthias Ringwald *usage = unsigned_value; 426*12ccb71bSMatthias Ringwald *value = 1; 427*12ccb71bSMatthias Ringwald } 428*12ccb71bSMatthias Ringwald parser->required_usages--; 429*12ccb71bSMatthias Ringwald parser->report_pos_in_bit += parser->global_report_size; 430*12ccb71bSMatthias Ringwald 431*12ccb71bSMatthias Ringwald // next usage 432*12ccb71bSMatthias Ringwald if (is_variable){ 433*12ccb71bSMatthias Ringwald parser->usage_minimum++; 434*12ccb71bSMatthias Ringwald parser->available_usages--; 435*12ccb71bSMatthias Ringwald } else { 436*12ccb71bSMatthias Ringwald if (parser->required_usages == 0){ 437*12ccb71bSMatthias Ringwald parser->available_usages = 0; 438*12ccb71bSMatthias Ringwald } 439*12ccb71bSMatthias Ringwald } 440*12ccb71bSMatthias Ringwald if (parser->available_usages) { 441*12ccb71bSMatthias Ringwald return; 442*12ccb71bSMatthias Ringwald } 443*12ccb71bSMatthias Ringwald if (parser->required_usages == 0){ 444*12ccb71bSMatthias Ringwald hid_post_process_item(parser, &parser->descriptor_item); 445*12ccb71bSMatthias Ringwald parser->state = BTSTACK_HID_PARSER_SCAN_FOR_REPORT_ITEM; 446*12ccb71bSMatthias Ringwald btstack_hid_parser_find_next_usage(parser); 447*12ccb71bSMatthias Ringwald } else { 448*12ccb71bSMatthias Ringwald hid_find_next_usage(parser); 449*12ccb71bSMatthias Ringwald if (parser->available_usages == 0) { 450*12ccb71bSMatthias Ringwald parser->state = BTSTACK_HID_PARSER_COMPLETE; 451*12ccb71bSMatthias Ringwald } 452*12ccb71bSMatthias Ringwald } 453*12ccb71bSMatthias Ringwald } 454