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