Home | History | Annotate | Download | only in HidUtils
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 #include "HidDefs.h"
     17 #include "HidParser.h"
     18 #include "HidLog.h"
     19 #include <iostream>
     20 #include <iomanip>
     21 
     22 namespace HidUtil {
     23 
     24 void HidParser::reset() {
     25     mGlobalStack = HidGlobalStack();
     26     mLocal = HidLocal();
     27     mTree = std::make_shared<HidTreeNode>();
     28     mCurrent = mTree;
     29 }
     30 
     31 bool HidParser::parse(const std::vector<HidItem> &token) {
     32     // Clean up internal states of the parser for a new stream of descriptor token
     33     reset();
     34 
     35     bool ret = true;
     36     using namespace HidDef::TagType;
     37 
     38     for (auto &i : token) {
     39         switch (i.type) {
     40             case MAIN:
     41                 ret = processMainTag(i);
     42                 break;
     43             case GLOBAL:
     44                 ret = mGlobalStack.append(i);
     45                 break;
     46             case LOCAL:
     47                 ret = mLocal.append(i);
     48                 break;
     49             default:
     50                 LOG_E << "HidParser found illegal HidItem: " << i << LOG_ENDL;
     51                 ret = false;
     52         }
     53 
     54         // in case a parse failure, quit prematurely
     55         if (!ret) {
     56             break;
     57         }
     58     }
     59     return ret;
     60 }
     61 
     62 bool HidParser::processMainTag(const HidItem &i) {
     63     using namespace HidDef::MainTag;
     64     using namespace HidDef::ReportFlag;
     65 
     66     bool ret = true;
     67     switch (i.tag) {
     68         case COLLECTION: {
     69             unsigned int collectionType;
     70             if (!i.dataAsUnsigned(&collectionType)) {
     71                 LOG_E << "Cannot get collection type at offset " << i.offset << LOG_ENDL;
     72                 ret = false;
     73                 break;
     74             }
     75             unsigned int fullUsage =
     76                     mGlobalStack.top().usagePage.get(0) << 16 | mLocal.getUsage(0);
     77             mCurrent = mCurrent->addChild(
     78                     std::make_shared<HidTreeNode>(mCurrent, collectionType, fullUsage));
     79             break;
     80         }
     81         case END_COLLECTION:
     82             mCurrent = mCurrent->getParent();
     83             if (!mCurrent) {
     84                 // trigger parse failure so that mCurrent will not be accessed
     85                 LOG_E << "unmatched END_COLLECTION at " << i.offset << LOG_ENDL;
     86                 ret = false;
     87             }
     88             break;
     89         case INPUT:
     90         case OUTPUT:
     91         case FEATURE: {
     92             unsigned int reportType = i.tag;
     93             unsigned int flag;
     94             if (!i.dataAsUnsigned(&flag)) {
     95                 LOG_E << "Cannot get report flag at offset " << i.offset << LOG_ENDL;
     96                 ret = false;
     97                 break;
     98             }
     99             const HidGlobal &top = mGlobalStack.top();
    100 
    101             // usage page, local min/max, report size and count have to be defined at report
    102             // definition.
    103             if (!(top.usagePage.isSet() && top.logicalMin.isSet() && top.logicalMax.isSet()
    104                   && top.reportSize.isSet() && top.reportCount.isSet())) {
    105                 LOG_E << "Report defined at " << i.offset
    106                       << " does not have all mandatory fields set" << LOG_ENDL;
    107                 ret = false;
    108                 break;
    109             }
    110             if (top.reportSize.get(0) > 32) {
    111                 LOG_E << "Report defined at " << i.offset
    112                       << " has unsupported report size(> 32 bit)" << LOG_ENDL;
    113                 ret = false;
    114                 break;
    115             }
    116 
    117             HidReport report(reportType, flag, top, mLocal);
    118             mReport.push_back(report);
    119             std::shared_ptr<HidTreeNode> node(new HidReportNode(mCurrent, report));
    120             mCurrent->addChild(node);
    121             break;
    122         }
    123         default:
    124             LOG_E << "unknown main tag, " << i << LOG_ENDL;
    125             ret = false;
    126     }
    127     // locals is cleared after any main tag according to HID spec
    128     mLocal.clear();
    129     return ret;
    130 }
    131 
    132 bool HidParser::parse(const unsigned char *begin, size_t size) {
    133     std::vector<HidItem> hidItemVector = HidItem::tokenize(begin, size);
    134     return parse(hidItemVector);
    135 }
    136 
    137 void HidParser::filterTree() {
    138     if (mTree != nullptr) {
    139         filterTree(mTree);
    140     }
    141 }
    142 
    143 void HidParser::filterTree(std::shared_ptr<HidTreeNode> &node) {
    144     if (node->isReportCollection()) {
    145         std::shared_ptr<HidReportNode> reportNode =
    146                 std::static_pointer_cast<HidReportNode>(node->getChildren().front());
    147         if (reportNode != nullptr) {
    148             reportNode->collapse(node->getFullUsage());
    149             node = reportNode;
    150         }
    151     } else {
    152         for (auto &i : node->getChildren()) {
    153             filterTree(i);
    154         }
    155     }
    156 }
    157 
    158 HidParser::DigestVector HidParser::generateDigest(
    159         const std::unordered_set<unsigned int> &interestedUsage) {
    160     DigestVector digestVector;
    161     digest(&digestVector, mTree, interestedUsage);
    162     return digestVector;
    163 }
    164 
    165 void HidParser::digest(HidParser::DigestVector *digestVector,
    166                        const std::shared_ptr<HidTreeNode> &node,
    167                        const std::unordered_set<unsigned int> &interestedUsage) {
    168     if (digestVector == nullptr) {
    169         return;
    170     }
    171 
    172     if (node->isUsageCollection()
    173             && interestedUsage.find(node->getFullUsage()) != interestedUsage.end()) {
    174         // this collection contains the usage interested
    175         ReportSetGroup reportSetGroup;
    176 
    177         // one layer deep search
    178         for (auto &i : node->getChildren()) {
    179             // skip all nodes that is not a report node
    180             if (i->getNodeType() != HidTreeNode::TYPE_REPORT) {
    181                 continue;
    182             }
    183             const HidReport &report =
    184                     std::static_pointer_cast<HidReportNode>(i)->getReport();
    185 
    186             unsigned int id = report.getReportId();;
    187             if (reportSetGroup.find(id) == reportSetGroup.end()) {
    188                 // create an id group if it is not created
    189                 reportSetGroup.emplace(id, ReportSet());
    190             }
    191 
    192             ReportSet &reportGroup = reportSetGroup[id];
    193             switch(report.getType()) {
    194                 using namespace HidDef::MainTag;
    195                 case FEATURE:
    196                     reportGroup[REPORT_TYPE_FEATURE].push_back(report);
    197                     break;
    198                 case INPUT:
    199                     reportGroup[REPORT_TYPE_INPUT].push_back(report);
    200                     break;
    201                 case OUTPUT:
    202                     reportGroup[REPORT_TYPE_OUTPUT].push_back(report);
    203                     break;
    204             }
    205         }
    206         ReportDigest digest = {
    207             .fullUsage = node->getFullUsage(),
    208             .packets = convertGroupToPacket(reportSetGroup)
    209         };
    210         digestVector->emplace_back(digest);
    211     } else {
    212         for (const auto &child : node->getChildren()) {
    213             if (child->getNodeType() == HidTreeNode::TYPE_NORMAL) {
    214                 // only follow into collection nodes
    215                 digest(digestVector, child, interestedUsage);
    216             }
    217         }
    218     }
    219 }
    220 
    221 std::vector<HidParser::ReportPacket> HidParser::convertGroupToPacket(
    222         const HidParser::ReportSetGroup &group) {
    223     std::vector<ReportPacket> packets;
    224 
    225     const std::vector<int> types = {REPORT_TYPE_FEATURE, REPORT_TYPE_INPUT, REPORT_TYPE_OUTPUT};
    226 
    227     for (const auto &setPair : group) {
    228         unsigned int id = setPair.first;
    229         for (auto type : types) {
    230             const auto &reports = setPair.second[type]; // feature
    231 
    232             // template
    233             ReportPacket packet = {
    234                 .type = type,
    235                 .id = id,
    236                 .bitSize = 0
    237             };
    238 
    239             for (const auto &r : reports) {
    240                 auto logical = r.getLogicalRange();
    241                 auto physical = r.getPhysicalRange();
    242 
    243                 int64_t offset = physical.first - logical.first;
    244                 double scale = static_cast<double>((physical.second - physical.first))
    245                         / (logical.second - logical.first);
    246                 scale *= r.getExponentValue();
    247 
    248                 ReportItem digest = {
    249                     .usage = r.getFullUsage(),
    250                     .id = id,
    251                     .minRaw = logical.first,
    252                     .maxRaw = logical.second,
    253                     .a = scale,
    254                     .b = offset,
    255                     .bitOffset = packet.bitSize,
    256                     .bitSize = r.getSize(),
    257                     .count = r.getCount(),
    258                     .unit = r.getUnit(),
    259                 };
    260                 packet.reports.push_back(digest);
    261                 packet.bitSize += digest.bitSize * digest.count;
    262             }
    263             if (!packet.reports.empty()) {
    264                 packets.push_back(std::move(packet));
    265             }
    266         }
    267     }
    268     return packets;
    269 }
    270 
    271 static std::string reportTypeToString(int reportType) {
    272     switch (reportType) {
    273         case HidParser::REPORT_TYPE_INPUT:
    274             return "INPUT";
    275         case HidParser::REPORT_TYPE_OUTPUT:
    276             return "OUTPUT";
    277         case HidParser::REPORT_TYPE_FEATURE:
    278             return "FEATURE";
    279         default:
    280             return "INVALID REPORT";
    281     }
    282 }
    283 
    284 std::ostream& operator<<(std::ostream &os, const HidParser::DigestVector &digests) {
    285     for (const auto &i : digests) {
    286         os << "Usage: 0x" << std::hex  << i.fullUsage << std::dec
    287            << ", " << i.packets.size() << " report packet:" << LOG_ENDL;
    288         for (const auto &packet : i.packets) {
    289             os << reportTypeToString(packet.type) << " id: " << packet.id
    290                << " size: " << packet.bitSize
    291                << "b(" << packet.getByteSize() << "B), "
    292                << packet.reports.size() << " entries" << LOG_ENDL;
    293 
    294             for (const auto &report : packet.reports) {
    295                 double min, max;
    296                 report.decode(report.mask(report.minRaw), &min);
    297                 report.decode(report.mask(report.maxRaw), &max);
    298 
    299                 os << "  " << report.bitOffset << " size: " << report.bitSize
    300                    << ", count: " << report.count
    301                    << ", usage: " << std::hex << std::setfill('0') << std::setw(8)
    302                    << report.usage << std::dec
    303                    << ", min: " << report.minRaw << ", max: " << report.maxRaw
    304                    << ", minDecoded: " << min
    305                    << ", maxDecoded: " << max
    306                    << ", a: " << report.a << ", b: " << report.b
    307                    << std::hex
    308                    << ", minRawHex: 0x" << report.mask(report.minRaw)
    309                    << ", maxRawHex: 0x" << report.mask(report.maxRaw)
    310                    << ", rawMasked: 0x" << report.rawMask()
    311                    << std::dec << LOG_ENDL;
    312             }
    313         }
    314         os << LOG_ENDL;
    315     }
    316     os << LOG_ENDL;
    317     return os;
    318 }
    319 } // namespace HidUtil
    320