15beee10b17e676380727da0b16b98ba7568669ecPeng Xu/* 25beee10b17e676380727da0b16b98ba7568669ecPeng Xu * Copyright (C) 2017 The Android Open Source Project 35beee10b17e676380727da0b16b98ba7568669ecPeng Xu * 45beee10b17e676380727da0b16b98ba7568669ecPeng Xu * Licensed under the Apache License, Version 2.0 (the "License"); 55beee10b17e676380727da0b16b98ba7568669ecPeng Xu * you may not use this file except in compliance with the License. 65beee10b17e676380727da0b16b98ba7568669ecPeng Xu * You may obtain a copy of the License at 75beee10b17e676380727da0b16b98ba7568669ecPeng Xu * 85beee10b17e676380727da0b16b98ba7568669ecPeng Xu * http://www.apache.org/licenses/LICENSE-2.0 95beee10b17e676380727da0b16b98ba7568669ecPeng Xu * 105beee10b17e676380727da0b16b98ba7568669ecPeng Xu * Unless required by applicable law or agreed to in writing, software 115beee10b17e676380727da0b16b98ba7568669ecPeng Xu * distributed under the License is distributed on an "AS IS" BASIS, 125beee10b17e676380727da0b16b98ba7568669ecPeng Xu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135beee10b17e676380727da0b16b98ba7568669ecPeng Xu * See the License for the specific language governing permissions and 145beee10b17e676380727da0b16b98ba7568669ecPeng Xu * limitations under the License. 155beee10b17e676380727da0b16b98ba7568669ecPeng Xu */ 165beee10b17e676380727da0b16b98ba7568669ecPeng Xu#include "HidDefs.h" 175beee10b17e676380727da0b16b98ba7568669ecPeng Xu#include "HidParser.h" 185beee10b17e676380727da0b16b98ba7568669ecPeng Xu#include "HidLog.h" 195beee10b17e676380727da0b16b98ba7568669ecPeng Xu#include <iostream> 205beee10b17e676380727da0b16b98ba7568669ecPeng Xu#include <iomanip> 215beee10b17e676380727da0b16b98ba7568669ecPeng Xu 225beee10b17e676380727da0b16b98ba7568669ecPeng Xunamespace HidUtil { 235beee10b17e676380727da0b16b98ba7568669ecPeng Xu 245beee10b17e676380727da0b16b98ba7568669ecPeng Xuvoid HidParser::reset() { 255beee10b17e676380727da0b16b98ba7568669ecPeng Xu mGlobalStack = HidGlobalStack(); 265beee10b17e676380727da0b16b98ba7568669ecPeng Xu mLocal = HidLocal(); 275beee10b17e676380727da0b16b98ba7568669ecPeng Xu mTree = std::make_shared<HidTreeNode>(); 285beee10b17e676380727da0b16b98ba7568669ecPeng Xu mCurrent = mTree; 295beee10b17e676380727da0b16b98ba7568669ecPeng Xu} 305beee10b17e676380727da0b16b98ba7568669ecPeng Xu 315beee10b17e676380727da0b16b98ba7568669ecPeng Xubool HidParser::parse(const std::vector<HidItem> &token) { 325beee10b17e676380727da0b16b98ba7568669ecPeng Xu // Clean up internal states of the parser for a new stream of descriptor token 335beee10b17e676380727da0b16b98ba7568669ecPeng Xu reset(); 345beee10b17e676380727da0b16b98ba7568669ecPeng Xu 355beee10b17e676380727da0b16b98ba7568669ecPeng Xu bool ret = true; 365beee10b17e676380727da0b16b98ba7568669ecPeng Xu using namespace HidDef::TagType; 375beee10b17e676380727da0b16b98ba7568669ecPeng Xu 385beee10b17e676380727da0b16b98ba7568669ecPeng Xu for (auto &i : token) { 395beee10b17e676380727da0b16b98ba7568669ecPeng Xu switch (i.type) { 405beee10b17e676380727da0b16b98ba7568669ecPeng Xu case MAIN: 415beee10b17e676380727da0b16b98ba7568669ecPeng Xu ret = processMainTag(i); 425beee10b17e676380727da0b16b98ba7568669ecPeng Xu break; 435beee10b17e676380727da0b16b98ba7568669ecPeng Xu case GLOBAL: 445beee10b17e676380727da0b16b98ba7568669ecPeng Xu ret = mGlobalStack.append(i); 455beee10b17e676380727da0b16b98ba7568669ecPeng Xu break; 465beee10b17e676380727da0b16b98ba7568669ecPeng Xu case LOCAL: 475beee10b17e676380727da0b16b98ba7568669ecPeng Xu ret = mLocal.append(i); 485beee10b17e676380727da0b16b98ba7568669ecPeng Xu break; 495beee10b17e676380727da0b16b98ba7568669ecPeng Xu default: 505beee10b17e676380727da0b16b98ba7568669ecPeng Xu LOG_E << "HidParser found illegal HidItem: " << i << LOG_ENDL; 515beee10b17e676380727da0b16b98ba7568669ecPeng Xu ret = false; 525beee10b17e676380727da0b16b98ba7568669ecPeng Xu } 535beee10b17e676380727da0b16b98ba7568669ecPeng Xu 545beee10b17e676380727da0b16b98ba7568669ecPeng Xu // in case a parse failure, quit prematurely 555beee10b17e676380727da0b16b98ba7568669ecPeng Xu if (!ret) { 565beee10b17e676380727da0b16b98ba7568669ecPeng Xu break; 575beee10b17e676380727da0b16b98ba7568669ecPeng Xu } 585beee10b17e676380727da0b16b98ba7568669ecPeng Xu } 595beee10b17e676380727da0b16b98ba7568669ecPeng Xu return ret; 605beee10b17e676380727da0b16b98ba7568669ecPeng Xu} 615beee10b17e676380727da0b16b98ba7568669ecPeng Xu 625beee10b17e676380727da0b16b98ba7568669ecPeng Xubool HidParser::processMainTag(const HidItem &i) { 635beee10b17e676380727da0b16b98ba7568669ecPeng Xu using namespace HidDef::MainTag; 645beee10b17e676380727da0b16b98ba7568669ecPeng Xu using namespace HidDef::ReportFlag; 655beee10b17e676380727da0b16b98ba7568669ecPeng Xu 665beee10b17e676380727da0b16b98ba7568669ecPeng Xu bool ret = true; 675beee10b17e676380727da0b16b98ba7568669ecPeng Xu switch (i.tag) { 685beee10b17e676380727da0b16b98ba7568669ecPeng Xu case COLLECTION: { 695beee10b17e676380727da0b16b98ba7568669ecPeng Xu unsigned int collectionType; 705beee10b17e676380727da0b16b98ba7568669ecPeng Xu if (!i.dataAsUnsigned(&collectionType)) { 715beee10b17e676380727da0b16b98ba7568669ecPeng Xu LOG_E << "Cannot get collection type at offset " << i.offset << LOG_ENDL; 725beee10b17e676380727da0b16b98ba7568669ecPeng Xu ret = false; 735beee10b17e676380727da0b16b98ba7568669ecPeng Xu break; 745beee10b17e676380727da0b16b98ba7568669ecPeng Xu } 755beee10b17e676380727da0b16b98ba7568669ecPeng Xu unsigned int fullUsage = 765beee10b17e676380727da0b16b98ba7568669ecPeng Xu mGlobalStack.top().usagePage.get(0) << 16 | mLocal.getUsage(0); 775beee10b17e676380727da0b16b98ba7568669ecPeng Xu mCurrent = mCurrent->addChild( 785beee10b17e676380727da0b16b98ba7568669ecPeng Xu std::make_shared<HidTreeNode>(mCurrent, collectionType, fullUsage)); 795beee10b17e676380727da0b16b98ba7568669ecPeng Xu break; 805beee10b17e676380727da0b16b98ba7568669ecPeng Xu } 815beee10b17e676380727da0b16b98ba7568669ecPeng Xu case END_COLLECTION: 825beee10b17e676380727da0b16b98ba7568669ecPeng Xu mCurrent = mCurrent->getParent(); 835beee10b17e676380727da0b16b98ba7568669ecPeng Xu if (!mCurrent) { 845beee10b17e676380727da0b16b98ba7568669ecPeng Xu // trigger parse failure so that mCurrent will not be accessed 855beee10b17e676380727da0b16b98ba7568669ecPeng Xu LOG_E << "unmatched END_COLLECTION at " << i.offset << LOG_ENDL; 865beee10b17e676380727da0b16b98ba7568669ecPeng Xu ret = false; 875beee10b17e676380727da0b16b98ba7568669ecPeng Xu } 885beee10b17e676380727da0b16b98ba7568669ecPeng Xu break; 895beee10b17e676380727da0b16b98ba7568669ecPeng Xu case INPUT: 905beee10b17e676380727da0b16b98ba7568669ecPeng Xu case OUTPUT: 915beee10b17e676380727da0b16b98ba7568669ecPeng Xu case FEATURE: { 925beee10b17e676380727da0b16b98ba7568669ecPeng Xu unsigned int reportType = i.tag; 935beee10b17e676380727da0b16b98ba7568669ecPeng Xu unsigned int flag; 945beee10b17e676380727da0b16b98ba7568669ecPeng Xu if (!i.dataAsUnsigned(&flag)) { 955beee10b17e676380727da0b16b98ba7568669ecPeng Xu LOG_E << "Cannot get report flag at offset " << i.offset << LOG_ENDL; 965beee10b17e676380727da0b16b98ba7568669ecPeng Xu ret = false; 975beee10b17e676380727da0b16b98ba7568669ecPeng Xu break; 985beee10b17e676380727da0b16b98ba7568669ecPeng Xu } 995beee10b17e676380727da0b16b98ba7568669ecPeng Xu const HidGlobal &top = mGlobalStack.top(); 1005beee10b17e676380727da0b16b98ba7568669ecPeng Xu 1015beee10b17e676380727da0b16b98ba7568669ecPeng Xu // usage page, local min/max, report size and count have to be defined at report 1025beee10b17e676380727da0b16b98ba7568669ecPeng Xu // definition. 1035beee10b17e676380727da0b16b98ba7568669ecPeng Xu if (!(top.usagePage.isSet() && top.logicalMin.isSet() && top.logicalMax.isSet() 1045beee10b17e676380727da0b16b98ba7568669ecPeng Xu && top.reportSize.isSet() && top.reportCount.isSet())) { 1055beee10b17e676380727da0b16b98ba7568669ecPeng Xu LOG_E << "Report defined at " << i.offset 1065beee10b17e676380727da0b16b98ba7568669ecPeng Xu << " does not have all mandatory fields set" << LOG_ENDL; 1075beee10b17e676380727da0b16b98ba7568669ecPeng Xu ret = false; 1085beee10b17e676380727da0b16b98ba7568669ecPeng Xu break; 1095beee10b17e676380727da0b16b98ba7568669ecPeng Xu } 1105beee10b17e676380727da0b16b98ba7568669ecPeng Xu if (top.reportSize.get(0) > 32) { 1115beee10b17e676380727da0b16b98ba7568669ecPeng Xu LOG_E << "Report defined at " << i.offset 1125beee10b17e676380727da0b16b98ba7568669ecPeng Xu << " has unsupported report size(> 32 bit)" << LOG_ENDL; 1135beee10b17e676380727da0b16b98ba7568669ecPeng Xu ret = false; 1145beee10b17e676380727da0b16b98ba7568669ecPeng Xu break; 1155beee10b17e676380727da0b16b98ba7568669ecPeng Xu } 1165beee10b17e676380727da0b16b98ba7568669ecPeng Xu 1175beee10b17e676380727da0b16b98ba7568669ecPeng Xu HidReport report(reportType, flag, top, mLocal); 1185beee10b17e676380727da0b16b98ba7568669ecPeng Xu mReport.push_back(report); 1195beee10b17e676380727da0b16b98ba7568669ecPeng Xu std::shared_ptr<HidTreeNode> node(new HidReportNode(mCurrent, report)); 1205beee10b17e676380727da0b16b98ba7568669ecPeng Xu mCurrent->addChild(node); 1215beee10b17e676380727da0b16b98ba7568669ecPeng Xu break; 1225beee10b17e676380727da0b16b98ba7568669ecPeng Xu } 1235beee10b17e676380727da0b16b98ba7568669ecPeng Xu default: 1245beee10b17e676380727da0b16b98ba7568669ecPeng Xu LOG_E << "unknown main tag, " << i << LOG_ENDL; 1255beee10b17e676380727da0b16b98ba7568669ecPeng Xu ret = false; 1265beee10b17e676380727da0b16b98ba7568669ecPeng Xu } 1275beee10b17e676380727da0b16b98ba7568669ecPeng Xu // locals is cleared after any main tag according to HID spec 1285beee10b17e676380727da0b16b98ba7568669ecPeng Xu mLocal.clear(); 1295beee10b17e676380727da0b16b98ba7568669ecPeng Xu return ret; 1305beee10b17e676380727da0b16b98ba7568669ecPeng Xu} 1315beee10b17e676380727da0b16b98ba7568669ecPeng Xu 1325beee10b17e676380727da0b16b98ba7568669ecPeng Xubool HidParser::parse(const unsigned char *begin, size_t size) { 1335beee10b17e676380727da0b16b98ba7568669ecPeng Xu std::vector<HidItem> hidItemVector = HidItem::tokenize(begin, size); 1345beee10b17e676380727da0b16b98ba7568669ecPeng Xu return parse(hidItemVector); 1355beee10b17e676380727da0b16b98ba7568669ecPeng Xu} 1365beee10b17e676380727da0b16b98ba7568669ecPeng Xu 1375beee10b17e676380727da0b16b98ba7568669ecPeng Xuvoid HidParser::filterTree() { 1385beee10b17e676380727da0b16b98ba7568669ecPeng Xu if (mTree != nullptr) { 1395beee10b17e676380727da0b16b98ba7568669ecPeng Xu filterTree(mTree); 1405beee10b17e676380727da0b16b98ba7568669ecPeng Xu } 1415beee10b17e676380727da0b16b98ba7568669ecPeng Xu} 1425beee10b17e676380727da0b16b98ba7568669ecPeng Xu 1435beee10b17e676380727da0b16b98ba7568669ecPeng Xuvoid HidParser::filterTree(std::shared_ptr<HidTreeNode> &node) { 1445beee10b17e676380727da0b16b98ba7568669ecPeng Xu if (node->isReportCollection()) { 1455beee10b17e676380727da0b16b98ba7568669ecPeng Xu std::shared_ptr<HidReportNode> reportNode = 1465beee10b17e676380727da0b16b98ba7568669ecPeng Xu std::static_pointer_cast<HidReportNode>(node->getChildren().front()); 1475beee10b17e676380727da0b16b98ba7568669ecPeng Xu if (reportNode != nullptr) { 1485beee10b17e676380727da0b16b98ba7568669ecPeng Xu reportNode->collapse(node->getFullUsage()); 1495beee10b17e676380727da0b16b98ba7568669ecPeng Xu node = reportNode; 1505beee10b17e676380727da0b16b98ba7568669ecPeng Xu } 1515beee10b17e676380727da0b16b98ba7568669ecPeng Xu } else { 1525beee10b17e676380727da0b16b98ba7568669ecPeng Xu for (auto &i : node->getChildren()) { 1535beee10b17e676380727da0b16b98ba7568669ecPeng Xu filterTree(i); 1545beee10b17e676380727da0b16b98ba7568669ecPeng Xu } 1555beee10b17e676380727da0b16b98ba7568669ecPeng Xu } 1565beee10b17e676380727da0b16b98ba7568669ecPeng Xu} 1575beee10b17e676380727da0b16b98ba7568669ecPeng Xu 1585beee10b17e676380727da0b16b98ba7568669ecPeng XuHidParser::DigestVector HidParser::generateDigest( 1595beee10b17e676380727da0b16b98ba7568669ecPeng Xu const std::unordered_set<unsigned int> &interestedUsage) { 1605beee10b17e676380727da0b16b98ba7568669ecPeng Xu DigestVector digestVector; 1615beee10b17e676380727da0b16b98ba7568669ecPeng Xu digest(&digestVector, mTree, interestedUsage); 1625beee10b17e676380727da0b16b98ba7568669ecPeng Xu return digestVector; 1635beee10b17e676380727da0b16b98ba7568669ecPeng Xu} 1645beee10b17e676380727da0b16b98ba7568669ecPeng Xu 1655beee10b17e676380727da0b16b98ba7568669ecPeng Xuvoid HidParser::digest(HidParser::DigestVector *digestVector, 1665beee10b17e676380727da0b16b98ba7568669ecPeng Xu const std::shared_ptr<HidTreeNode> &node, 1675beee10b17e676380727da0b16b98ba7568669ecPeng Xu const std::unordered_set<unsigned int> &interestedUsage) { 1685beee10b17e676380727da0b16b98ba7568669ecPeng Xu if (digestVector == nullptr) { 1695beee10b17e676380727da0b16b98ba7568669ecPeng Xu return; 1705beee10b17e676380727da0b16b98ba7568669ecPeng Xu } 1715beee10b17e676380727da0b16b98ba7568669ecPeng Xu 1725beee10b17e676380727da0b16b98ba7568669ecPeng Xu if (node->isUsageCollection() 1735beee10b17e676380727da0b16b98ba7568669ecPeng Xu && interestedUsage.find(node->getFullUsage()) != interestedUsage.end()) { 1745beee10b17e676380727da0b16b98ba7568669ecPeng Xu // this collection contains the usage interested 1755beee10b17e676380727da0b16b98ba7568669ecPeng Xu ReportSetGroup reportSetGroup; 1765beee10b17e676380727da0b16b98ba7568669ecPeng Xu 1775beee10b17e676380727da0b16b98ba7568669ecPeng Xu // one layer deep search 1785beee10b17e676380727da0b16b98ba7568669ecPeng Xu for (auto &i : node->getChildren()) { 1795beee10b17e676380727da0b16b98ba7568669ecPeng Xu // skip all nodes that is not a report node 1805beee10b17e676380727da0b16b98ba7568669ecPeng Xu if (i->getNodeType() != HidTreeNode::TYPE_REPORT) { 1815beee10b17e676380727da0b16b98ba7568669ecPeng Xu continue; 1825beee10b17e676380727da0b16b98ba7568669ecPeng Xu } 1835beee10b17e676380727da0b16b98ba7568669ecPeng Xu const HidReport &report = 1845beee10b17e676380727da0b16b98ba7568669ecPeng Xu std::static_pointer_cast<HidReportNode>(i)->getReport(); 1855beee10b17e676380727da0b16b98ba7568669ecPeng Xu 1865beee10b17e676380727da0b16b98ba7568669ecPeng Xu unsigned int id = report.getReportId();; 1875beee10b17e676380727da0b16b98ba7568669ecPeng Xu if (reportSetGroup.find(id) == reportSetGroup.end()) { 1885beee10b17e676380727da0b16b98ba7568669ecPeng Xu // create an id group if it is not created 1895beee10b17e676380727da0b16b98ba7568669ecPeng Xu reportSetGroup.emplace(id, ReportSet()); 1905beee10b17e676380727da0b16b98ba7568669ecPeng Xu } 1915beee10b17e676380727da0b16b98ba7568669ecPeng Xu 1925beee10b17e676380727da0b16b98ba7568669ecPeng Xu ReportSet &reportGroup = reportSetGroup[id]; 1935beee10b17e676380727da0b16b98ba7568669ecPeng Xu switch(report.getType()) { 1945beee10b17e676380727da0b16b98ba7568669ecPeng Xu using namespace HidDef::MainTag; 1955beee10b17e676380727da0b16b98ba7568669ecPeng Xu case FEATURE: 1965beee10b17e676380727da0b16b98ba7568669ecPeng Xu reportGroup[REPORT_TYPE_FEATURE].push_back(report); 1975beee10b17e676380727da0b16b98ba7568669ecPeng Xu break; 1985beee10b17e676380727da0b16b98ba7568669ecPeng Xu case INPUT: 1995beee10b17e676380727da0b16b98ba7568669ecPeng Xu reportGroup[REPORT_TYPE_INPUT].push_back(report); 2005beee10b17e676380727da0b16b98ba7568669ecPeng Xu break; 2015beee10b17e676380727da0b16b98ba7568669ecPeng Xu case OUTPUT: 2025beee10b17e676380727da0b16b98ba7568669ecPeng Xu reportGroup[REPORT_TYPE_OUTPUT].push_back(report); 2035beee10b17e676380727da0b16b98ba7568669ecPeng Xu break; 2045beee10b17e676380727da0b16b98ba7568669ecPeng Xu } 2055beee10b17e676380727da0b16b98ba7568669ecPeng Xu } 2065beee10b17e676380727da0b16b98ba7568669ecPeng Xu ReportDigest digest = { 2075beee10b17e676380727da0b16b98ba7568669ecPeng Xu .fullUsage = node->getFullUsage(), 2085beee10b17e676380727da0b16b98ba7568669ecPeng Xu .packets = convertGroupToPacket(reportSetGroup) 2095beee10b17e676380727da0b16b98ba7568669ecPeng Xu }; 2105beee10b17e676380727da0b16b98ba7568669ecPeng Xu digestVector->emplace_back(digest); 2115beee10b17e676380727da0b16b98ba7568669ecPeng Xu } else { 2125beee10b17e676380727da0b16b98ba7568669ecPeng Xu for (const auto &child : node->getChildren()) { 2135beee10b17e676380727da0b16b98ba7568669ecPeng Xu if (child->getNodeType() == HidTreeNode::TYPE_NORMAL) { 2145beee10b17e676380727da0b16b98ba7568669ecPeng Xu // only follow into collection nodes 2155beee10b17e676380727da0b16b98ba7568669ecPeng Xu digest(digestVector, child, interestedUsage); 2165beee10b17e676380727da0b16b98ba7568669ecPeng Xu } 2175beee10b17e676380727da0b16b98ba7568669ecPeng Xu } 2185beee10b17e676380727da0b16b98ba7568669ecPeng Xu } 2195beee10b17e676380727da0b16b98ba7568669ecPeng Xu} 2205beee10b17e676380727da0b16b98ba7568669ecPeng Xu 2215beee10b17e676380727da0b16b98ba7568669ecPeng Xustd::vector<HidParser::ReportPacket> HidParser::convertGroupToPacket( 2225beee10b17e676380727da0b16b98ba7568669ecPeng Xu const HidParser::ReportSetGroup &group) { 2235beee10b17e676380727da0b16b98ba7568669ecPeng Xu std::vector<ReportPacket> packets; 2245beee10b17e676380727da0b16b98ba7568669ecPeng Xu 2255beee10b17e676380727da0b16b98ba7568669ecPeng Xu const std::vector<int> types = {REPORT_TYPE_FEATURE, REPORT_TYPE_INPUT, REPORT_TYPE_OUTPUT}; 2265beee10b17e676380727da0b16b98ba7568669ecPeng Xu 2275beee10b17e676380727da0b16b98ba7568669ecPeng Xu for (const auto &setPair : group) { 2285beee10b17e676380727da0b16b98ba7568669ecPeng Xu unsigned int id = setPair.first; 2295beee10b17e676380727da0b16b98ba7568669ecPeng Xu for (auto type : types) { 2305beee10b17e676380727da0b16b98ba7568669ecPeng Xu const auto &reports = setPair.second[type]; // feature 2315beee10b17e676380727da0b16b98ba7568669ecPeng Xu 2325beee10b17e676380727da0b16b98ba7568669ecPeng Xu // template 2335beee10b17e676380727da0b16b98ba7568669ecPeng Xu ReportPacket packet = { 2345beee10b17e676380727da0b16b98ba7568669ecPeng Xu .type = type, 2355beee10b17e676380727da0b16b98ba7568669ecPeng Xu .id = id, 2365beee10b17e676380727da0b16b98ba7568669ecPeng Xu .bitSize = 0 2375beee10b17e676380727da0b16b98ba7568669ecPeng Xu }; 2385beee10b17e676380727da0b16b98ba7568669ecPeng Xu 2395beee10b17e676380727da0b16b98ba7568669ecPeng Xu for (const auto &r : reports) { 2405beee10b17e676380727da0b16b98ba7568669ecPeng Xu auto logical = r.getLogicalRange(); 2415beee10b17e676380727da0b16b98ba7568669ecPeng Xu auto physical = r.getPhysicalRange(); 2425beee10b17e676380727da0b16b98ba7568669ecPeng Xu 2435beee10b17e676380727da0b16b98ba7568669ecPeng Xu int64_t offset = physical.first - logical.first; 2445beee10b17e676380727da0b16b98ba7568669ecPeng Xu double scale = static_cast<double>((physical.second - physical.first)) 2455beee10b17e676380727da0b16b98ba7568669ecPeng Xu / (logical.second - logical.first); 2465beee10b17e676380727da0b16b98ba7568669ecPeng Xu scale *= r.getExponentValue(); 2475beee10b17e676380727da0b16b98ba7568669ecPeng Xu 2485beee10b17e676380727da0b16b98ba7568669ecPeng Xu ReportItem digest = { 2495beee10b17e676380727da0b16b98ba7568669ecPeng Xu .usage = r.getFullUsage(), 2505beee10b17e676380727da0b16b98ba7568669ecPeng Xu .id = id, 2515beee10b17e676380727da0b16b98ba7568669ecPeng Xu .minRaw = logical.first, 2525beee10b17e676380727da0b16b98ba7568669ecPeng Xu .maxRaw = logical.second, 2535beee10b17e676380727da0b16b98ba7568669ecPeng Xu .a = scale, 2545beee10b17e676380727da0b16b98ba7568669ecPeng Xu .b = offset, 2555beee10b17e676380727da0b16b98ba7568669ecPeng Xu .bitOffset = packet.bitSize, 2565beee10b17e676380727da0b16b98ba7568669ecPeng Xu .bitSize = r.getSize(), 2575beee10b17e676380727da0b16b98ba7568669ecPeng Xu .count = r.getCount(), 2585beee10b17e676380727da0b16b98ba7568669ecPeng Xu .unit = r.getUnit(), 2595beee10b17e676380727da0b16b98ba7568669ecPeng Xu }; 2605beee10b17e676380727da0b16b98ba7568669ecPeng Xu packet.reports.push_back(digest); 2615beee10b17e676380727da0b16b98ba7568669ecPeng Xu packet.bitSize += digest.bitSize * digest.count; 2625beee10b17e676380727da0b16b98ba7568669ecPeng Xu } 2635beee10b17e676380727da0b16b98ba7568669ecPeng Xu if (!packet.reports.empty()) { 2645beee10b17e676380727da0b16b98ba7568669ecPeng Xu packets.push_back(std::move(packet)); 2655beee10b17e676380727da0b16b98ba7568669ecPeng Xu } 2665beee10b17e676380727da0b16b98ba7568669ecPeng Xu } 2675beee10b17e676380727da0b16b98ba7568669ecPeng Xu } 2685beee10b17e676380727da0b16b98ba7568669ecPeng Xu return packets; 2695beee10b17e676380727da0b16b98ba7568669ecPeng Xu} 2705beee10b17e676380727da0b16b98ba7568669ecPeng Xu 2715beee10b17e676380727da0b16b98ba7568669ecPeng Xustatic std::string reportTypeToString(int reportType) { 2725beee10b17e676380727da0b16b98ba7568669ecPeng Xu switch (reportType) { 2735beee10b17e676380727da0b16b98ba7568669ecPeng Xu case HidParser::REPORT_TYPE_INPUT: 2745beee10b17e676380727da0b16b98ba7568669ecPeng Xu return "INPUT"; 2755beee10b17e676380727da0b16b98ba7568669ecPeng Xu case HidParser::REPORT_TYPE_OUTPUT: 2765beee10b17e676380727da0b16b98ba7568669ecPeng Xu return "OUTPUT"; 2775beee10b17e676380727da0b16b98ba7568669ecPeng Xu case HidParser::REPORT_TYPE_FEATURE: 2785beee10b17e676380727da0b16b98ba7568669ecPeng Xu return "FEATURE"; 2795beee10b17e676380727da0b16b98ba7568669ecPeng Xu default: 2805beee10b17e676380727da0b16b98ba7568669ecPeng Xu return "INVALID REPORT"; 2815beee10b17e676380727da0b16b98ba7568669ecPeng Xu } 2825beee10b17e676380727da0b16b98ba7568669ecPeng Xu} 2835beee10b17e676380727da0b16b98ba7568669ecPeng Xu 2845beee10b17e676380727da0b16b98ba7568669ecPeng Xustd::ostream& operator<<(std::ostream &os, const HidParser::DigestVector &digests) { 2855beee10b17e676380727da0b16b98ba7568669ecPeng Xu for (const auto &i : digests) { 2865beee10b17e676380727da0b16b98ba7568669ecPeng Xu os << "Usage: 0x" << std::hex << i.fullUsage << std::dec 2875beee10b17e676380727da0b16b98ba7568669ecPeng Xu << ", " << i.packets.size() << " report packet:" << LOG_ENDL; 2885beee10b17e676380727da0b16b98ba7568669ecPeng Xu for (const auto &packet : i.packets) { 2895beee10b17e676380727da0b16b98ba7568669ecPeng Xu os << reportTypeToString(packet.type) << " id: " << packet.id 2905beee10b17e676380727da0b16b98ba7568669ecPeng Xu << " size: " << packet.bitSize 2915beee10b17e676380727da0b16b98ba7568669ecPeng Xu << "b(" << packet.getByteSize() << "B), " 2925beee10b17e676380727da0b16b98ba7568669ecPeng Xu << packet.reports.size() << " entries" << LOG_ENDL; 2935beee10b17e676380727da0b16b98ba7568669ecPeng Xu 2945beee10b17e676380727da0b16b98ba7568669ecPeng Xu for (const auto &report : packet.reports) { 2955beee10b17e676380727da0b16b98ba7568669ecPeng Xu double min, max; 2965beee10b17e676380727da0b16b98ba7568669ecPeng Xu report.decode(report.mask(report.minRaw), &min); 2975beee10b17e676380727da0b16b98ba7568669ecPeng Xu report.decode(report.mask(report.maxRaw), &max); 2985beee10b17e676380727da0b16b98ba7568669ecPeng Xu 2995beee10b17e676380727da0b16b98ba7568669ecPeng Xu os << " " << report.bitOffset << " size: " << report.bitSize 3005beee10b17e676380727da0b16b98ba7568669ecPeng Xu << ", count: " << report.count 3015beee10b17e676380727da0b16b98ba7568669ecPeng Xu << ", usage: " << std::hex << std::setfill('0') << std::setw(8) 3025beee10b17e676380727da0b16b98ba7568669ecPeng Xu << report.usage << std::dec 3035beee10b17e676380727da0b16b98ba7568669ecPeng Xu << ", min: " << report.minRaw << ", max: " << report.maxRaw 3045beee10b17e676380727da0b16b98ba7568669ecPeng Xu << ", minDecoded: " << min 3055beee10b17e676380727da0b16b98ba7568669ecPeng Xu << ", maxDecoded: " << max 3065beee10b17e676380727da0b16b98ba7568669ecPeng Xu << ", a: " << report.a << ", b: " << report.b 3075beee10b17e676380727da0b16b98ba7568669ecPeng Xu << std::hex 3085beee10b17e676380727da0b16b98ba7568669ecPeng Xu << ", minRawHex: 0x" << report.mask(report.minRaw) 3095beee10b17e676380727da0b16b98ba7568669ecPeng Xu << ", maxRawHex: 0x" << report.mask(report.maxRaw) 3105beee10b17e676380727da0b16b98ba7568669ecPeng Xu << ", rawMasked: 0x" << report.rawMask() 3115beee10b17e676380727da0b16b98ba7568669ecPeng Xu << std::dec << LOG_ENDL; 3125beee10b17e676380727da0b16b98ba7568669ecPeng Xu } 3135beee10b17e676380727da0b16b98ba7568669ecPeng Xu } 3145beee10b17e676380727da0b16b98ba7568669ecPeng Xu os << LOG_ENDL; 3155beee10b17e676380727da0b16b98ba7568669ecPeng Xu } 3165beee10b17e676380727da0b16b98ba7568669ecPeng Xu os << LOG_ENDL; 3175beee10b17e676380727da0b16b98ba7568669ecPeng Xu return os; 3185beee10b17e676380727da0b16b98ba7568669ecPeng Xu} 3195beee10b17e676380727da0b16b98ba7568669ecPeng Xu} // namespace HidUtil 320