| /* |
| * 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_ |