/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef HIDUTIL_HIDPARSER_H_ #define HIDUTIL_HIDPARSER_H_ #include "HidItem.h" #include "HidTree.h" #include "HidGlobal.h" #include "HidLocal.h" #include <unordered_map> #include <unordered_set> #include <vector> #include <array> #include <ostream> namespace HidUtil { class HidParser { public: enum { REPORT_TYPE_FEATURE = 0, REPORT_TYPE_INPUT = 1, REPORT_TYPE_OUTPUT = 2 }; struct ReportItem; struct ReportPacket; // report (including input output and feature) grouped by full usage struct ReportDigest { unsigned int fullUsage; std::vector<ReportPacket> packets; }; typedef std::vector<ReportDigest> DigestVector; // parse HID descriptor bool parse(const std::vector<HidItem> &token); bool parse(const unsigned char *begin, size_t size); // filter the tree to eliminate single child report leaf node causes by usage array type // reports void filterTree(); // generate a list of report digest for all interested usage. It will automatically // call filterTree(). DigestVector generateDigest(const std::unordered_set<unsigned int> &interestedUsage); // get parsed tree (filtered or not filtered) const std::shared_ptr<HidTreeNode> getTree() const { return mTree; } // get all parsed report in a parsed form. const std::vector<HidReport>& getReport() const { return mReport; } private: typedef std::array<std::vector<HidReport>, 3> ReportSet; typedef std::unordered_map<unsigned int /* reportId */, ReportSet> ReportSetGroup; // helper subroutines void reset(); bool processMainTag(const HidItem &i); static void filterTree(std::shared_ptr<HidTreeNode> &node); static void digest( DigestVector *digestVector, const std::shared_ptr<HidTreeNode> &node, const std::unordered_set<unsigned int> &interestedUsage); static std::vector<ReportPacket> convertGroupToPacket(const ReportSetGroup &group); HidGlobalStack mGlobalStack; HidLocal mLocal; std::shared_ptr<HidTreeNode> mTree; std::shared_ptr<HidTreeNode> mCurrent; std::vector<HidReport> mReport; }; struct HidParser::ReportItem { unsigned int usage; unsigned int id; int type; // feature, input or output int64_t minRaw; int64_t maxRaw; // conversion for float point values // real value = (signExtendIfNeeded(raw) + b) * a // raw value = mask(real/a - b); // // conversion for integer values // real value = signExtendedIfNeeded(raw) + b; // raw value = mask(real - b); double a; // scaling int64_t b; // offset unsigned int unit; size_t bitOffset; size_t bitSize; // bit length per unit size_t count; // helper function bool isSigned() const { return minRaw < 0; } bool isByteAligned() const { return (bitOffset & 7) == 0 && (bitSize & 7) == 0; } // convert raw values to unsigned format uint32_t mask(int64_t input) const { return static_cast<uint32_t>(input & rawMask()); } bool decode(uint32_t input, double *output) const { if (output == nullptr) { return false; } int64_t s = signExtendIfNeeded(input); if (s < minRaw || s > maxRaw) { return false; } *output = (s + b) * a; return true; } bool encode(double input, uint32_t *output) const { if (output == nullptr) { return false; } input = input / a - b; if (input < minRaw || input > maxRaw) { return false; } *output = static_cast<uint32_t>(static_cast<int64_t>(input) & rawMask()); return true; } int64_t rawMask() const { constexpr int64_t one = 1; return (one << bitSize) - 1; } int64_t signExtendIfNeeded(int64_t value) const { return value | ((isSigned() && isNegative(value)) ? ~rawMask() : 0); } bool isNegative(int64_t value) const { constexpr int64_t one = 1; return ((one << (bitSize - 1)) & value) != 0; } }; // a collection of report item that forms a packet // this is the input output unit with HID hardware struct HidParser::ReportPacket { std::vector<ReportItem> reports; size_t bitSize; int type; // REPORT_TYPE_FEATURE/INPUT/OUTPUT unsigned int id; size_t getByteSize() const { return (bitSize + 7) / 8; }; }; std::ostream& operator<<(std::ostream &os, const HidParser::DigestVector &digest2); } // namespace HidUtil #endif // HIDUTIL_HIDPARSER_H_