/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "HidReport.h" #include "HidDefs.h" #include #include #include namespace HidUtil { HidReport::HidReport(uint32_t type, uint32_t data, const HidGlobal &global, const HidLocal &local) : mReportType(type), mFlag(data), mUsagePage(global.usagePage.get(0)), // default value 0 mUsage(local.getUsage(0)), mUsageVector(local.usage), mLogicalMin(global.logicalMin.get(0)), // default value 0 mLogicalMax(global.logicalMax.get(0)), mReportSize(global.reportSize), mReportCount(global.reportCount), mPhysicalMin(global.physicalMin), mPhysicalMax(global.physicalMax), mExponent(global.exponent), mUnit(global.unit), mReportId(global.reportId) { } std::string HidReport::getStringType() const { return reportTypeToString(mReportType); } std::string HidReport::reportTypeToString(int type) { using namespace HidDef::MainTag; switch(type) { case INPUT: return "INPUT"; case OUTPUT: return "OUTPUT"; case FEATURE: return "FEATURE"; default: return "<>"; } } double HidReport::getExponentValue() const { if (!mExponent.isSet()) { return 1; } // default exponent is 0 int exponentInt = mExponent.get(0); if (exponentInt > 15 || exponentInt < 0) { return NAN; } return pow(10.0, static_cast((exponentInt <= 7) ? exponentInt : exponentInt - 16)); } std::string HidReport::getExponentString() const { int exponentInt = mExponent.get(0); if (exponentInt > 15 || exponentInt < 0) { return "[error]"; } return std::string("x10^") + std::to_string((exponentInt <= 7) ? exponentInt : exponentInt - 16); } std::string HidReport::getUnitString() const { if (!mUnit.isSet()) { return "default"; } return "[not implemented]"; std::ostringstream ret; ret << std::hex << std::setfill('0') << std::setw(2) << mUnit.get(0); return ret.str(); } std::string HidReport::getFlagString() const { using namespace HidDef::ReportFlag; std::string ret; ret += (mFlag & DATA_CONST) ? "Const " : "Data "; ret += (mFlag & ARRAY_VARIABLE) ? "Variable " : "Array "; ret += (mFlag & WRAP) ? "Wrap " : ""; ret += (mFlag & NONLINEAR) ? "Nonlinear " : ""; ret += (mFlag & NO_PREFERRED) ? "NoPreferred " : ""; ret += (mFlag & NULL_STATE) ? "NullState " : ""; ret += (mFlag & VOLATILE) ? "Volatile " : ""; ret += (mFlag & BUFFERED_BYTES) ? "BufferedBytes " : ""; return ret; } // isArray() will return true for reports that may contains multiple values, e.g. keyboard scan // code, which can have multiple value, each denoting a key pressed down at the same time. It will // return false if repor represent a vector or matrix. // // This slightly deviates from HID's definition, it is more convenient this way as matrix/vector // input is treated similarly as variables. bool HidReport::isArray() const { using namespace HidDef::ReportFlag; return (mFlag & ARRAY_VARIABLE) == 0 && mIsCollapsed; } bool HidReport::isVariable() const { return !isArray(); } bool HidReport::isData() const { using namespace HidDef::ReportFlag; return (mFlag & DATA_CONST) == 0; } std::ostream& operator<<(std::ostream& os, const HidReport& h) { os << h.getStringType() << ", " << "usage: " << std::hex << h.getFullUsage() << std::dec << ", "; if (h.isData()) { auto range = h.getLogicalRange(); os << "logMin: " << range.first << ", " << "logMax: " << range.second << ", "; if (range == h.getPhysicalRange()) { os << "phy===log, "; } else { range = h.getPhysicalRange(); os << "phyMin: " << range.first << ", " << "phyMax: " << range.second << ", "; } if (h.isArray()) { os << "map: (" << std::hex; for (auto i : h.getUsageVector()) { os << i << ","; } os << "), " << std::dec; } os << "exponent: " << h.getExponentString() << ", " << "unit: " << h.getUnitString() << ", "; } else { os << "constant: "; } os << "size: " << h.getSize() << "bit x " << h.getCount() << ", " << "id: " << h.mReportId; return os; } std::pair HidReport::getLogicalRange() const { int64_t a = mLogicalMin; int64_t b = mLogicalMax; if (a > b) { // might be unsigned a = a & ((static_cast(1) << getSize()) - 1); b = b & ((static_cast(1) << getSize()) - 1); if (a > b) { // bad hid descriptor return {0, 0}; } } return {a, b}; } std::pair HidReport::getPhysicalRange() const { if (!(mPhysicalMin.isSet() && mPhysicalMax.isSet())) { // physical range undefined, use logical range return getLogicalRange(); } int64_t a = mPhysicalMin.get(0); int64_t b = mPhysicalMax.get(0); if (a > b) { a = a & ((static_cast(1) << getSize()) - 1); b = b & ((static_cast(1) << getSize()) - 1); if (a > b) { return {0, 0}; } } return {a, b}; } unsigned int HidReport::getFullUsage() const { return mUsage | (mUsagePage << 16); } size_t HidReport::getSize() const { return mReportSize; } size_t HidReport::getCount() const { return mReportCount; } unsigned int HidReport::getUnit() const { return mUnit.get(0); // default unit is 0 means default unit } unsigned HidReport::getReportId() const { // if report id is not specified, it defaults to zero return mReportId.get(0); } unsigned HidReport::getType() const { return mReportType; } void HidReport::setCollapsed(uint32_t fullUsage) { mUsage = fullUsage & 0xFFFF; mUsagePage = fullUsage >> 16; mIsCollapsed = true; } const std::vector& HidReport::getUsageVector() const { return mUsageVector; } } // namespace HidUtil