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 #include "HidReport.h"
17 #include "HidDefs.h"
18 #include <cmath>
19 #include <sstream>
20 #include <iomanip>
21
22 namespace HidUtil {
HidReport(uint32_t type,uint32_t data,const HidGlobal & global,const HidLocal & local)23 HidReport::HidReport(uint32_t type, uint32_t data,
24 const HidGlobal &global, const HidLocal &local)
25 : mIsCollapsed(false),
26 mReportType(type),
27 mFlag(data),
28 mUsagePage(global.usagePage.get(0)), // default value 0
29 mUsage(local.getUsage(0)),
30 mUsageVector(local.usage),
31 mLogicalMin(global.logicalMin.get(0)), // default value 0
32 mLogicalMax(global.logicalMax.get(0)),
33 mReportSize(global.reportSize),
34 mReportCount(global.reportCount),
35 mPhysicalMin(global.physicalMin),
36 mPhysicalMax(global.physicalMax),
37 mExponent(global.exponent),
38 mUnit(global.unit),
39 mReportId(global.reportId) { }
40
getStringType() const41 std::string HidReport::getStringType() const {
42 return reportTypeToString(mReportType);
43 }
44
reportTypeToString(int type)45 std::string HidReport::reportTypeToString(int type) {
46 using namespace HidDef::MainTag;
47 switch(type) {
48 case INPUT:
49 return "INPUT";
50 case OUTPUT:
51 return "OUTPUT";
52 case FEATURE:
53 return "FEATURE";
54 default:
55 return "<<UNKNOWN>>";
56 }
57 }
58
getExponentValue() const59 double HidReport::getExponentValue() const {
60 if (!mExponent.isSet()) {
61 return 1;
62 }
63 // default exponent is 0
64 int exponentInt = mExponent.get(0);
65 if (exponentInt > 15 || exponentInt < 0) {
66 return NAN;
67 }
68 return pow(10.0, static_cast<double>((exponentInt <= 7) ? exponentInt : exponentInt - 16));
69 }
70
getExponentString() const71 std::string HidReport::getExponentString() const {
72 int exponentInt = mExponent.get(0);
73 if (exponentInt > 15 || exponentInt < 0) {
74 return "[error]";
75 }
76 return std::string("x10^")
77 + std::to_string((exponentInt <= 7) ? exponentInt : exponentInt - 16);
78 }
79
getUnitString() const80 std::string HidReport::getUnitString() const {
81 if (!mUnit.isSet()) {
82 return "default";
83 }
84 return "[not implemented]";
85
86 std::ostringstream ret;
87 ret << std::hex << std::setfill('0') << std::setw(2) << mUnit.get(0);
88 return ret.str();
89 }
90
getFlagString() const91 std::string HidReport::getFlagString() const {
92 using namespace HidDef::ReportFlag;
93 std::string ret;
94 ret += (mFlag & DATA_CONST) ? "Const " : "Data ";
95 ret += (mFlag & ARRAY_VARIABLE) ? "Variable " : "Array ";
96 ret += (mFlag & WRAP) ? "Wrap " : "";
97 ret += (mFlag & NONLINEAR) ? "Nonlinear " : "";
98 ret += (mFlag & NO_PREFERRED) ? "NoPreferred " : "";
99 ret += (mFlag & NULL_STATE) ? "NullState " : "";
100 ret += (mFlag & VOLATILE) ? "Volatile " : "";
101 ret += (mFlag & BUFFERED_BYTES) ? "BufferedBytes " : "";
102 return ret;
103 }
104
105 // isArray() will return true for reports that may contains multiple values, e.g. keyboard scan
106 // code, which can have multiple value, each denoting a key pressed down at the same time. It will
107 // return false if repor represent a vector or matrix.
108 //
109 // This slightly deviates from HID's definition, it is more convenient this way as matrix/vector
110 // input is treated similarly as variables.
isArray() const111 bool HidReport::isArray() const {
112 using namespace HidDef::ReportFlag;
113 return (mFlag & ARRAY_VARIABLE) == 0 && mIsCollapsed;
114 }
115
isVariable() const116 bool HidReport::isVariable() const {
117 return !isArray();
118 }
119
isData() const120 bool HidReport::isData() const {
121 using namespace HidDef::ReportFlag;
122 return (mFlag & DATA_CONST) == 0;
123 }
124
operator <<(std::ostream & os,const HidReport & h)125 std::ostream& operator<<(std::ostream& os, const HidReport& h) {
126 os << h.getStringType() << ", "
127 << "usage: " << std::hex << h.getFullUsage() << std::dec << ", ";
128
129 if (h.isData()) {
130 auto range = h.getLogicalRange();
131 os << "logMin: " << range.first << ", "
132 << "logMax: " << range.second << ", ";
133
134 if (range == h.getPhysicalRange()) {
135 os << "phy===log, ";
136 } else {
137 range = h.getPhysicalRange();
138 os << "phyMin: " << range.first << ", "
139 << "phyMax: " << range.second << ", ";
140 }
141
142 if (h.isArray()) {
143 os << "map: (" << std::hex;
144 for (auto i : h.getUsageVector()) {
145 os << i << ",";
146 }
147 os << "), " << std::dec;
148 }
149
150 os << "exponent: " << h.getExponentString() << ", "
151 << "unit: " << h.getUnitString() << ", ";
152 } else {
153 os << "constant: ";
154 }
155 os << "size: " << h.getSize() << "bit x " << h.getCount() << ", "
156 << "id: " << h.mReportId;
157
158 return os;
159 }
160
getLogicalRange() const161 std::pair<int64_t, int64_t> HidReport::getLogicalRange() const {
162 int64_t a = mLogicalMin;
163 int64_t b = mLogicalMax;
164
165 if (a > b) {
166 // might be unsigned
167 a = a & ((static_cast<int64_t>(1) << getSize()) - 1);
168 b = b & ((static_cast<int64_t>(1) << getSize()) - 1);
169 if (a > b) {
170 // bad hid descriptor
171 return {0, 0};
172 }
173 }
174 return {a, b};
175 }
176
getPhysicalRange() const177 std::pair<int64_t, int64_t> HidReport::getPhysicalRange() const {
178 if (!(mPhysicalMin.isSet() && mPhysicalMax.isSet())) {
179 // physical range undefined, use logical range
180 return getLogicalRange();
181 }
182
183 int64_t a = mPhysicalMin.get(0);
184 int64_t b = mPhysicalMax.get(0);
185
186 if (a > b) {
187 a = a & ((static_cast<int64_t>(1) << getSize()) - 1);
188 b = b & ((static_cast<int64_t>(1) << getSize()) - 1);
189 if (a > b) {
190 return {0, 0};
191 }
192 }
193 return {a, b};
194 }
195
getFullUsage() const196 unsigned int HidReport::getFullUsage() const {
197 return mUsage | (mUsagePage << 16);
198 }
199
getSize() const200 size_t HidReport::getSize() const {
201 return mReportSize;
202 }
203
getCount() const204 size_t HidReport::getCount() const {
205 return mReportCount;
206 }
207
getUnit() const208 unsigned int HidReport::getUnit() const {
209 return mUnit.get(0); // default unit is 0 means default unit
210 }
211
getReportId() const212 unsigned HidReport::getReportId() const {
213 // if report id is not specified, it defaults to zero
214 return mReportId.get(0);
215 }
216
getType() const217 unsigned HidReport::getType() const {
218 return mReportType;
219 }
220
setCollapsed(uint32_t fullUsage)221 void HidReport::setCollapsed(uint32_t fullUsage) {
222 mUsage = fullUsage & 0xFFFF;
223 mUsagePage = fullUsage >> 16;
224 mIsCollapsed = true;
225 }
226
getUsageVector() const227 const std::vector<unsigned int>& HidReport::getUsageVector() const {
228 return mUsageVector;
229 }
230 } // namespace HidUtil
231