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 std::vector<unsigned int> usageVector; 93 94 int64_t minRaw; 95 int64_t maxRaw; 96 97 // conversion for float point values 98 // real value = (signExtendIfNeeded(raw) + b) * a 99 // raw value = mask(real/a - b); 100 // 101 // conversion for integer values 102 // real value = signExtendedIfNeeded(raw) + b; 103 // raw value = mask(real - b); 104 double a; // scaling 105 int64_t b; // offset 106 unsigned int unit; 107 108 size_t bitOffset; 109 size_t bitSize; // bit length per unit 110 size_t count; 111 112 // helper function isSignedReportItem113 bool isSigned() const { 114 return minRaw < 0; 115 } 116 isByteAlignedReportItem117 bool isByteAligned() const { 118 return (bitOffset & 7) == 0 && (bitSize & 7) == 0; 119 } 120 121 // convert raw values to unsigned format maskReportItem122 uint32_t mask(int64_t input) const { 123 return static_cast<uint32_t>(input & rawMask()); 124 } 125 decodeReportItem126 bool decode(uint32_t input, double *output) const { 127 if (output == nullptr) { 128 return false; 129 } 130 int64_t s = signExtendIfNeeded(input); 131 if (s < minRaw || s > maxRaw) { 132 return false; 133 } 134 *output = (s + b) * a; 135 return true; 136 } 137 encodeReportItem138 bool encode(double input, uint32_t *output) const { 139 if (output == nullptr) { 140 return false; 141 } 142 input = input / a - b; 143 if (input < minRaw || input > maxRaw) { 144 return false; 145 } 146 *output = static_cast<uint32_t>(static_cast<int64_t>(input) & rawMask()); 147 return true; 148 } 149 rawMaskReportItem150 int64_t rawMask() const { 151 constexpr int64_t one = 1; 152 return (one << bitSize) - 1; 153 } 154 signExtendIfNeededReportItem155 int64_t signExtendIfNeeded(int64_t value) const { 156 return value | ((isSigned() && isNegative(value)) ? ~rawMask() : 0); 157 } 158 isNegativeReportItem159 bool isNegative(int64_t value) const { 160 constexpr int64_t one = 1; 161 return ((one << (bitSize - 1)) & value) != 0; 162 } 163 }; 164 165 // a collection of report item that forms a packet 166 // this is the input output unit with HID hardware 167 struct HidParser::ReportPacket { 168 std::vector<ReportItem> reports; 169 size_t bitSize; 170 int type; // REPORT_TYPE_FEATURE/INPUT/OUTPUT 171 unsigned int id; 172 getByteSizeReportPacket173 size_t getByteSize() const { return (bitSize + 7) / 8; }; 174 }; 175 176 std::ostream& operator<<(std::ostream &os, const HidParser::DigestVector &digest2); 177 178 } // namespace HidUtil 179 180 #endif // HIDUTIL_HIDPARSER_H_ 181