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