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 { 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 40 std::string HidReport::getStringType() const { 41 return reportTypeToString(mReportType); 42 } 43 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 58 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 70 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 79 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 90 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. 110 bool HidReport::isArray() const { 111 using namespace HidDef::ReportFlag; 112 return (mFlag & ARRAY_VARIABLE) == 0 && mIsCollapsed; 113 } 114 115 bool HidReport::isVariable() const { 116 return !isArray(); 117 } 118 119 bool HidReport::isData() const { 120 using namespace HidDef::ReportFlag; 121 return (mFlag & DATA_CONST) == 0; 122 } 123 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 160 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 176 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 195 unsigned int HidReport::getFullUsage() const { 196 return mUsage | (mUsagePage << 16); 197 } 198 199 size_t HidReport::getSize() const { 200 return mReportSize; 201 } 202 203 size_t HidReport::getCount() const { 204 return mReportCount; 205 } 206 207 unsigned int HidReport::getUnit() const { 208 return mUnit.get(0); // default unit is 0 means default unit 209 } 210 211 unsigned HidReport::getReportId() const { 212 // if report id is not specified, it defaults to zero 213 return mReportId.get(0); 214 } 215 216 unsigned HidReport::getType() const { 217 return mReportType; 218 } 219 220 void HidReport::setCollapsed(uint32_t fullUsage) { 221 mUsage = fullUsage & 0xFFFF; 222 mUsagePage = fullUsage >> 16; 223 mIsCollapsed = true; 224 } 225 226 const std::vector<unsigned int>& HidReport::getUsageVector() const { 227 return mUsageVector; 228 } 229 } // namespace HidUtil 230