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