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 #ifndef HIDUTIL_HIDPARSER_H_ 17 #define HIDUTIL_HIDPARSER_H_ 18 19 #include "HidItem.h" 20 #include "HidTree.h" 21 #include "HidGlobal.h" 22 #include "HidLocal.h" 23 #include <unordered_map> 24 #include <unordered_set> 25 #include <vector> 26 #include <array> 27 #include <ostream> 28 29 namespace HidUtil { 30 class HidParser { 31 public: 32 enum { 33 REPORT_TYPE_FEATURE = 0, 34 REPORT_TYPE_INPUT = 1, 35 REPORT_TYPE_OUTPUT = 2 36 }; 37 38 struct ReportItem; 39 struct ReportPacket; 40 41 // report (including input output and feature) grouped by full usage 42 struct ReportDigest { 43 unsigned int fullUsage; 44 std::vector<ReportPacket> packets; 45 }; 46 47 typedef std::vector<ReportDigest> DigestVector; 48 49 // parse HID descriptor 50 bool parse(const std::vector<HidItem> &token); 51 bool parse(const unsigned char *begin, size_t size); 52 53 // filter the tree to eliminate single child report leaf node causes by usage array type 54 // reports 55 void filterTree(); 56 57 // generate a list of report digest for all interested usage. It will automatically 58 // call filterTree(). 59 DigestVector generateDigest(const std::unordered_set<unsigned int> &interestedUsage); 60 61 // get parsed tree (filtered or not filtered) getTree()62 const std::shared_ptr<HidTreeNode> getTree() const { return mTree; } 63 64 // get all parsed report in a parsed form. getReport()65 const std::vector<HidReport>& getReport() const { return mReport; } 66 67 private: 68 typedef std::array<std::vector<HidReport>, 3> ReportSet; 69 typedef std::unordered_map<unsigned int /* reportId */, ReportSet> ReportSetGroup; 70 71 // helper subroutines 72 void reset(); 73 bool processMainTag(const HidItem &i); 74 static void filterTree(std::shared_ptr<HidTreeNode> &node); 75 static void digest( 76 DigestVector *digestVector, 77 const std::shared_ptr<HidTreeNode> &node, 78 const std::unordered_set<unsigned int> &interestedUsage); 79 static std::vector<ReportPacket> convertGroupToPacket(const ReportSetGroup &group); 80 81 HidGlobalStack mGlobalStack; 82 HidLocal mLocal; 83 std::shared_ptr<HidTreeNode> mTree; 84 std::shared_ptr<HidTreeNode> mCurrent; 85 std::vector<HidReport> mReport; 86 }; 87 88 struct HidParser::ReportItem { 89 unsigned int usage; 90 unsigned int id; 91 int type; // feature, input or output 92 93 int64_t minRaw; 94 int64_t maxRaw; 95 96 // conversion for float point values 97 // real value = (signExtendIfNeeded(raw) + b) * a 98 // raw value = mask(real/a - b); 99 // 100 // conversion for integer values 101 // real value = signExtendedIfNeeded(raw) + b; 102 // raw value = mask(real - b); 103 double a; // scaling 104 int64_t b; // offset 105 unsigned int unit; 106 107 size_t bitOffset; 108 size_t bitSize; // bit length per unit 109 size_t count; 110 111 // helper function isSignedReportItem112 bool isSigned() const { 113 return minRaw < 0; 114 } 115 isByteAlignedReportItem116 bool isByteAligned() const { 117 return (bitOffset & 7) == 0 && (bitSize & 7) == 0; 118 } 119 120 // convert raw values to unsigned format maskReportItem121 uint32_t mask(int64_t input) const { 122 return static_cast<uint32_t>(input & rawMask()); 123 } 124 decodeReportItem125 bool decode(uint32_t input, double *output) const { 126 if (output == nullptr) { 127 return false; 128 } 129 int64_t s = signExtendIfNeeded(input); 130 if (s < minRaw || s > maxRaw) { 131 return false; 132 } 133 *output = (s + b) * a; 134 return true; 135 } 136 encodeReportItem137 bool encode(double input, uint32_t *output) const { 138 if (output == nullptr) { 139 return false; 140 } 141 input = input / a - b; 142 if (input < minRaw || input > maxRaw) { 143 return false; 144 } 145 *output = static_cast<uint32_t>(static_cast<int64_t>(input) & rawMask()); 146 return true; 147 } 148 rawMaskReportItem149 int64_t rawMask() const { 150 constexpr int64_t one = 1; 151 return (one << bitSize) - 1; 152 } 153 signExtendIfNeededReportItem154 int64_t signExtendIfNeeded(int64_t value) const { 155 return value | ((isSigned() && isNegative(value)) ? ~rawMask() : 0); 156 } 157 isNegativeReportItem158 bool isNegative(int64_t value) const { 159 constexpr int64_t one = 1; 160 return ((one << (bitSize - 1)) & value) != 0; 161 } 162 }; 163 164 // a collection of report item that forms a packet 165 // this is the input output unit with HID hardware 166 struct HidParser::ReportPacket { 167 std::vector<ReportItem> reports; 168 size_t bitSize; 169 int type; // REPORT_TYPE_FEATURE/INPUT/OUTPUT 170 unsigned int id; 171 getByteSizeReportPacket172 size_t getByteSize() const { return (bitSize + 7) / 8; }; 173 }; 174 175 std::ostream& operator<<(std::ostream &os, const HidParser::DigestVector &digest2); 176 } // namespace HidUtil 177 178 #endif // HIDUTIL_HIDPARSER_H_ 179