Home | History | Annotate | Download | only in HidUtils
      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