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