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 "HidRawSensor.h" 17#include "HidSensorDef.h" 18 19#include <utils/Errors.h> 20#include "HidLog.h" 21 22#include <algorithm> 23#include <cfloat> 24#include <codecvt> 25#include <iomanip> 26#include <sstream> 27 28namespace android { 29namespace SensorHalExt { 30 31namespace { 32const std::string CUSTOM_TYPE_PREFIX("com.google.hardware.sensor.hid_dynamic."); 33} 34 35HidRawSensor::HidRawSensor( 36 SP(HidDevice) device, uint32_t usage, const std::vector<HidParser::ReportPacket> &packets) 37 : mReportingStateId(-1), mPowerStateId(-1), mReportIntervalId(-1), mInputReportId(-1), 38 mEnabled(false), mSamplingPeriod(1000ll*1000*1000), mBatchingPeriod(0), 39 mDevice(device), mValid(false) { 40 if (device == nullptr) { 41 return; 42 } 43 memset(&mSensor, 0, sizeof(mSensor)); 44 45 const HidDevice::HidDeviceInfo &info = device->getDeviceInfo(); 46 initFeatureValueFromHidDeviceInfo(&mFeatureInfo, info); 47 48 if (!populateFeatureValueFromFeatureReport(&mFeatureInfo, packets)) { 49 LOG_E << "populate feature from feature report failed" << LOG_ENDL; 50 return; 51 } 52 53 if (!findSensorControlUsage(packets)) { 54 LOG_E << "finding sensor control usage failed" << LOG_ENDL; 55 return; 56 } 57 58 // build translation table 59 bool translationTableValid = false; 60 switch (usage) { 61 using namespace Hid::Sensor::SensorTypeUsage; 62 using namespace Hid::Sensor::ReportUsage; 63 case ACCELEROMETER_3D: 64 // Hid unit default g 65 // Android unit m/s^2 66 // 1g = 9.81 m/s^2 67 mFeatureInfo.typeString = SENSOR_STRING_TYPE_ACCELEROMETER; 68 mFeatureInfo.type = SENSOR_TYPE_ACCELEROMETER; 69 mFeatureInfo.isWakeUp = false; 70 71 translationTableValid = processTriAxisUsage(packets, 72 ACCELERATION_X_AXIS, 73 ACCELERATION_Y_AXIS, 74 ACCELERATION_Z_AXIS, 9.81); 75 break; 76 case GYROMETER_3D: 77 // Hid unit default degree/s 78 // Android unit rad/s 79 // 1 degree/s = pi/180 rad/s 80 mFeatureInfo.typeString = SENSOR_STRING_TYPE_GYROSCOPE; 81 mFeatureInfo.type = SENSOR_TYPE_GYROSCOPE; 82 mFeatureInfo.isWakeUp = false; 83 84 translationTableValid = processTriAxisUsage(packets, 85 ANGULAR_VELOCITY_X_AXIS, 86 ANGULAR_VELOCITY_Y_AXIS, 87 ANGULAR_VELOCITY_Z_AXIS, M_PI/180); 88 break; 89 case COMPASS_3D: { 90 // Hid unit default mGauss 91 // Android unit uT 92 // 1uT = 0.1 nGauss 93 mFeatureInfo.typeString = SENSOR_STRING_TYPE_MAGNETIC_FIELD; 94 mFeatureInfo.type = SENSOR_TYPE_MAGNETIC_FIELD; 95 96 if (!processTriAxisUsage(packets, 97 MAGNETIC_FLUX_X_AXIS, 98 MAGNETIC_FLUX_Y_AXIS, 99 MAGNETIC_FLUX_Z_AXIS, 0.1)) { 100 break; 101 } 102 const HidParser::ReportItem *pReportAccuracy = find(packets, 103 MAGNETOMETER_ACCURACY, 104 HidParser::REPORT_TYPE_INPUT, 105 mInputReportId); 106 107 if (pReportAccuracy == nullptr) { 108 LOG_E << "Cannot find accuracy field in usage " 109 << std::hex << usage << std::dec << LOG_ENDL; 110 break; 111 } 112 if (!pReportAccuracy->isByteAligned()) { 113 LOG_E << "Accuracy field must align to byte" << LOG_ENDL; 114 break; 115 } 116 if (pReportAccuracy->minRaw != 0 || pReportAccuracy->maxRaw != 2) { 117 LOG_E << "Accuracy field value range must be [0, 2]" << LOG_ENDL; 118 break; 119 } 120 ReportTranslateRecord accuracyRecord = { 121 .type = TYPE_ACCURACY, 122 .maxValue = 2, 123 .minValue = 0, 124 .byteOffset = pReportAccuracy->bitOffset / 8, 125 .byteSize = pReportAccuracy->bitSize / 8, 126 .a = 1, 127 .b = 1}; 128 mTranslateTable.push_back(accuracyRecord); 129 translationTableValid = true; 130 break; 131 } 132 case DEVICE_ORIENTATION: 133 translationTableValid = processQuaternionUsage(packets); 134 break; 135 case CUSTOM: { 136 if (!mFeatureInfo.isAndroidCustom) { 137 LOG_E << "Invalid android custom sensor" << LOG_ENDL; 138 break; 139 } 140 const HidParser::ReportPacket *pPacket = nullptr; 141 const uint32_t usages[] = { 142 CUSTOM_VALUE_1, CUSTOM_VALUE_2, CUSTOM_VALUE_3, 143 CUSTOM_VALUE_4, CUSTOM_VALUE_5, CUSTOM_VALUE_6 144 }; 145 for (const auto &packet : packets) { 146 if (packet.type == HidParser::REPORT_TYPE_INPUT && std::any_of( 147 packet.reports.begin(), packet.reports.end(), 148 [&usages] (const HidParser::ReportItem &d) { 149 return std::find(std::begin(usages), std::end(usages), d.usage) 150 != std::end(usages); 151 })) { 152 pPacket = &packet; 153 break; 154 } 155 } 156 157 if (pPacket == nullptr) { 158 LOG_E << "Cannot find CUSTOM_VALUE_X in custom sensor" << LOG_ENDL; 159 break; 160 } 161 162 double range = 0; 163 double resolution = 1; 164 165 for (const auto &digest : pPacket->reports) { 166 if (digest.minRaw >= digest.maxRaw) { 167 LOG_E << "Custome usage " << digest.usage << ", min must < max" << LOG_ENDL; 168 return; 169 } 170 171 if (!digest.isByteAligned() 172 || (digest.bitSize != 8 && digest.bitSize != 16 && digest.bitSize != 32)) { 173 LOG_E << "Custome usage " << std::hex << digest.usage << std::hex 174 << ", each input must be 8/16/32 bits and must align to byte boundary" 175 << LOG_ENDL; 176 return; 177 } 178 179 ReportTranslateRecord record = { 180 .minValue = digest.minRaw, 181 .maxValue = digest.maxRaw, 182 .byteOffset = digest.bitOffset / 8, 183 .byteSize = digest.bitSize / 8, 184 .a = digest.a, 185 .b = digest.b, 186 .type = TYPE_FLOAT 187 }; 188 // keep track of range and resolution 189 range = std::max(std::max(std::abs((digest.maxRaw + digest.b) * digest.a), 190 std::abs((digest.minRaw + digest.b) * digest.a)), 191 range); 192 resolution = std::min(digest.a, resolution); 193 194 for (size_t i = 0; i < digest.count; ++i) { 195 if (mTranslateTable.size() == 16) { 196 LOG_I << "Custom usage has more than 16 inputs, ignore the rest" << LOG_ENDL; 197 break; 198 } 199 record.index = mTranslateTable.size(); 200 mTranslateTable.push_back(record); 201 record.byteOffset += digest.bitSize / 8; 202 } 203 if (mTranslateTable.size() == 16) { 204 break; 205 } 206 } 207 mFeatureInfo.maxRange = range; 208 mFeatureInfo.resolution = resolution; 209 mInputReportId = pPacket->id; 210 translationTableValid = !mTranslateTable.empty(); 211 break; 212 } 213 default: 214 LOG_I << "unsupported sensor usage " << usage << LOG_ENDL; 215 } 216 217 bool sensorValid = validateFeatureValueAndBuildSensor(); 218 mValid = translationTableValid && sensorValid; 219 LOG_V << "HidRawSensor init, translationTableValid: " << translationTableValid 220 << ", sensorValid: " << sensorValid << LOG_ENDL; 221} 222 223bool HidRawSensor::processQuaternionUsage(const std::vector<HidParser::ReportPacket> &packets) { 224 const HidParser::ReportItem *pReportQuaternion 225 = find(packets, 226 Hid::Sensor::ReportUsage::ORIENTATION_QUATERNION, 227 HidParser::REPORT_TYPE_INPUT); 228 229 if (pReportQuaternion == nullptr) { 230 return false; 231 } 232 233 const HidParser::ReportItem &quat = *pReportQuaternion; 234 if ((quat.bitSize != 16 && quat.bitSize != 32) || !quat.isByteAligned()) { 235 LOG_E << "Quaternion usage input must be 16 or 32 bits and aligned at byte boundary" << LOG_ENDL; 236 return false; 237 } 238 239 double min, max; 240 quat.decode(quat.mask(quat.minRaw), &min); 241 quat.decode(quat.mask(quat.maxRaw), &max); 242 if (quat.count != 4 || min > -1 || max < 1) { 243 LOG_E << "Quaternion usage need 4 inputs with range [-1, 1]" << LOG_ENDL; 244 return false; 245 } 246 247 if (quat.minRaw > quat.maxRaw) { 248 LOG_E << "Quaternion usage min must <= max" << LOG_ENDL; 249 return false; 250 } 251 252 ReportTranslateRecord record = { 253 .minValue = quat.minRaw, 254 .maxValue = quat.maxRaw, 255 .byteOffset = quat.bitOffset / 8, 256 .byteSize = quat.bitSize / 8, 257 .b = quat.b, 258 .type = TYPE_FLOAT, 259 }; 260 261 // Android X Y Z maps to HID X -Z Y 262 // Android order xyzw, HID order wxyz 263 // X 264 record.index = 0; 265 record.a = quat.a; 266 record.byteOffset = (quat.bitOffset + quat.bitSize) / 8; 267 mTranslateTable.push_back(record); 268 // Y 269 record.index = 1; 270 record.a = -quat.a; 271 record.byteOffset = (quat.bitOffset + 3 * quat.bitSize) / 8; 272 mTranslateTable.push_back(record); 273 // Z 274 record.index = 2; 275 record.a = quat.a; 276 record.byteOffset = (quat.bitOffset + 2 * quat.bitSize) / 8; 277 mTranslateTable.push_back(record); 278 // W 279 record.index = 3; 280 record.a = quat.a; 281 record.byteOffset = quat.bitOffset / 8; 282 mTranslateTable.push_back(record); 283 284 mFeatureInfo.typeString = SENSOR_STRING_TYPE_ROTATION_VECTOR; 285 mFeatureInfo.type = SENSOR_TYPE_ROTATION_VECTOR; 286 mFeatureInfo.maxRange = 1; 287 mFeatureInfo.resolution = quat.a; 288 mFeatureInfo.reportModeFlag = SENSOR_FLAG_CONTINUOUS_MODE; 289 290 mInputReportId = quat.id; 291 292 return true; 293} 294 295bool HidRawSensor::processTriAxisUsage(const std::vector<HidParser::ReportPacket> &packets, 296 uint32_t usageX, uint32_t usageY, uint32_t usageZ, double defaultScaling) { 297 const HidParser::ReportItem *pReportX = find(packets, usageX, HidParser::REPORT_TYPE_INPUT); 298 const HidParser::ReportItem *pReportY = find(packets, usageY, HidParser::REPORT_TYPE_INPUT); 299 const HidParser::ReportItem *pReportZ = find(packets, usageZ, HidParser::REPORT_TYPE_INPUT); 300 301 if (pReportX == nullptr || pReportY == nullptr|| pReportZ == nullptr) { 302 LOG_E << "Three axis sensor does not find all 3 axis" << LOG_ENDL; 303 return false; 304 } 305 306 const HidParser::ReportItem &reportX = *pReportX; 307 const HidParser::ReportItem &reportY = *pReportY; 308 const HidParser::ReportItem &reportZ = *pReportZ; 309 if (reportX.id != reportY.id || reportY.id != reportZ.id) { 310 LOG_E << "All 3 axis should be in the same report" << LOG_ENDL; 311 return false; 312 } 313 if (reportX.minRaw >= reportX.maxRaw 314 || reportX.minRaw != reportY.minRaw 315 || reportX.maxRaw != reportY.maxRaw 316 || reportY.minRaw != reportZ.minRaw 317 || reportY.maxRaw != reportZ.maxRaw) { 318 LOG_E << "All 3 axis should have same min and max value and min must < max" << LOG_ENDL; 319 return false; 320 } 321 if (reportX.a != reportY.a || reportY.a != reportY.a) { 322 LOG_E << "All 3 axis should have same resolution" << LOG_ENDL; 323 return false; 324 } 325 if (reportX.count != 1 || reportY.count != 1 || reportZ.count != 1 326 || (reportX.bitSize != 16 && reportX.bitSize != 32) 327 || reportX.bitSize != reportY.bitSize || reportY.bitSize != reportZ.bitSize 328 || !reportX.isByteAligned() 329 || !reportY.isByteAligned() 330 || !reportZ.isByteAligned() ) { 331 LOG_E << "All 3 axis should have count == 1, same size == 16 or 32 " 332 "and align at byte boundary" << LOG_ENDL; 333 return false; 334 } 335 336 if (reportX.unit != 0 || reportY.unit != 0 || reportZ.unit != 0) { 337 LOG_E << "Specified unit for usage is not supported" << LOG_ENDL; 338 return false; 339 } 340 341 if (reportX.a != reportY.a || reportY.a != reportZ.a 342 || reportX.b != reportY.b || reportY.b != reportZ.b) { 343 LOG_W << "Scaling for 3 axis are different. It is recommended to keep them the same" << LOG_ENDL; 344 } 345 346 // set features 347 mFeatureInfo.maxRange = std::max( 348 std::abs((reportX.maxRaw + reportX.b) * reportX.a), 349 std::abs((reportX.minRaw + reportX.b) * reportX.a)); 350 mFeatureInfo.resolution = reportX.a * defaultScaling; 351 mFeatureInfo.reportModeFlag = SENSOR_FLAG_CONTINUOUS_MODE; 352 353 ReportTranslateRecord record = { 354 .minValue = reportX.minRaw, 355 .maxValue = reportX.maxRaw, 356 .byteSize = reportX.bitSize / 8, 357 .type = TYPE_FLOAT 358 }; 359 360 // Reorder and swap axis 361 // 362 // HID class devices are encouraged, where possible, to use a right-handed 363 // coordinate system. If a user is facing a device, report values should increase as 364 // controls are moved from left to right (X), from far to near (Y) and from high to 365 // low (Z). 366 // 367 368 // Android X axis = Hid X axis 369 record.index = 0; 370 record.a = reportX.a * defaultScaling; 371 record.b = reportX.b; 372 record.byteOffset = reportX.bitOffset / 8; 373 mTranslateTable.push_back(record); 374 375 // Android Y axis = - Hid Z axis 376 record.index = 1; 377 record.a = -reportZ.a * defaultScaling; 378 record.b = reportZ.b; 379 record.byteOffset = reportZ.bitOffset / 8; 380 mTranslateTable.push_back(record); 381 382 // Android Z axis = Hid Y axis 383 record.index = 2; 384 record.a = reportY.a * defaultScaling; 385 record.b = reportY.b; 386 record.byteOffset = reportY.bitOffset / 8; 387 mTranslateTable.push_back(record); 388 389 mInputReportId = reportX.id; 390 return true; 391} 392 393const HidParser::ReportItem *HidRawSensor::find( 394 const std::vector<HidParser::ReportPacket> &packets, 395 unsigned int usage, int type, int id) { 396 for (const auto &packet : packets) { 397 if (packet.type != type) { 398 continue; 399 } 400 auto i = std::find_if( 401 packet.reports.begin(), packet.reports.end(), 402 [usage, id](const HidParser::ReportItem &p) { 403 return p.usage == usage 404 && (id == -1 || p.id == static_cast<unsigned int>(id)); 405 }); 406 if (i != packet.reports.end()) { 407 return &(*i); 408 } 409 } 410 return nullptr; 411}; 412 413void HidRawSensor::initFeatureValueFromHidDeviceInfo( 414 FeatureValue *featureValue, const HidDevice::HidDeviceInfo &info) { 415 featureValue->name = info.name; 416 417 std::ostringstream ss; 418 ss << info.busType << " " 419 << std::hex << std::setfill('0') << std::setw(4) << info.vendorId 420 << ":" << std::setw(4) << info.productId; 421 featureValue->vendor = ss.str(); 422 423 featureValue->permission = ""; 424 featureValue->typeString = ""; 425 featureValue->type = -1; // invalid type 426 featureValue->version = 1; 427 428 featureValue->maxRange = -1.f; 429 featureValue->resolution = FLT_MAX; 430 featureValue->power = 1.f; // default value, does not have a valid source yet 431 432 featureValue->minDelay = 0; 433 featureValue->maxDelay = 0; 434 435 featureValue->fifoSize = 0; 436 featureValue->fifoMaxSize = 0; 437 438 featureValue->reportModeFlag = SENSOR_FLAG_SPECIAL_REPORTING_MODE; 439 featureValue->isWakeUp = false; 440 memset(featureValue->uuid, 0, sizeof(featureValue->uuid)); 441 featureValue->isAndroidCustom = false; 442} 443 444bool HidRawSensor::populateFeatureValueFromFeatureReport( 445 FeatureValue *featureValue, const std::vector<HidParser::ReportPacket> &packets) { 446 SP(HidDevice) device = PROMOTE(mDevice); 447 if (device == nullptr) { 448 return false; 449 } 450 451 std::vector<uint8_t> buffer; 452 for (const auto &packet : packets) { 453 if (packet.type != HidParser::REPORT_TYPE_FEATURE) { 454 continue; 455 } 456 457 if (!device->getFeature(packet.id, &buffer)) { 458 continue; 459 } 460 461 std::string str; 462 using namespace Hid::Sensor::PropertyUsage; 463 for (const auto & r : packet.reports) { 464 switch (r.usage) { 465 case FRIENDLY_NAME: 466 if (!r.isByteAligned() || r.bitSize != 16 || r.count < 1) { 467 // invalid friendly name 468 break; 469 } 470 if (decodeString(r, buffer, &str) && !str.empty()) { 471 featureValue->name = str; 472 } 473 break; 474 case SENSOR_MANUFACTURER: 475 if (!r.isByteAligned() || r.bitSize != 16 || r.count < 1) { 476 // invalid manufacturer 477 break; 478 } 479 if (decodeString(r, buffer, &str) && !str.empty()) { 480 featureValue->vendor = str; 481 } 482 break; 483 case PERSISTENT_UNIQUE_ID: 484 if (!r.isByteAligned() || r.bitSize != 16 || r.count < 1) { 485 // invalid unique id string 486 break; 487 } 488 if (decodeString(r, buffer, &str) && !str.empty()) { 489 featureValue->uniqueId = str; 490 } 491 break; 492 case SENSOR_DESCRIPTION: 493 if (!r.isByteAligned() || r.bitSize != 16 || r.count < 1 494 || (r.bitOffset / 8 + r.count * 2) > buffer.size() ) { 495 // invalid description 496 break; 497 } 498 if (decodeString(r, buffer, &str)) { 499 mFeatureInfo.isAndroidCustom = detectAndroidCustomSensor(str); 500 } 501 break; 502 default: 503 // do not care about others 504 break; 505 } 506 } 507 } 508 return true; 509} 510 511bool HidRawSensor::validateFeatureValueAndBuildSensor() { 512 if (mFeatureInfo.name.empty() || mFeatureInfo.vendor.empty() || mFeatureInfo.typeString.empty() 513 || mFeatureInfo.type <= 0 || mFeatureInfo.maxRange <= 0 514 || mFeatureInfo.resolution <= 0) { 515 return false; 516 } 517 518 switch (mFeatureInfo.reportModeFlag) { 519 case SENSOR_FLAG_CONTINUOUS_MODE: 520 case SENSOR_FLAG_ON_CHANGE_MODE: 521 if (mFeatureInfo.minDelay < 0) { 522 return false; 523 } 524 if (mFeatureInfo.maxDelay != 0 && mFeatureInfo.maxDelay < mFeatureInfo.minDelay) { 525 return false; 526 } 527 break; 528 case SENSOR_FLAG_ONE_SHOT_MODE: 529 if (mFeatureInfo.minDelay != -1 && mFeatureInfo.maxDelay != 0) { 530 return false; 531 } 532 break; 533 case SENSOR_FLAG_SPECIAL_REPORTING_MODE: 534 if (mFeatureInfo.minDelay != -1 && mFeatureInfo.maxDelay != 0) { 535 return false; 536 } 537 break; 538 default: 539 break; 540 } 541 542 if (mFeatureInfo.fifoMaxSize < mFeatureInfo.fifoSize) { 543 return false; 544 } 545 546 // initialize uuid field, use name, vendor and uniqueId 547 if (mFeatureInfo.name.size() >= 4 548 && mFeatureInfo.vendor.size() >= 4 549 && mFeatureInfo.typeString.size() >= 4 550 && mFeatureInfo.uniqueId.size() >= 4) { 551 uint32_t tmp[4], h; 552 std::hash<std::string> stringHash; 553 h = stringHash(mFeatureInfo.uniqueId); 554 tmp[0] = stringHash(mFeatureInfo.name) ^ h; 555 tmp[1] = stringHash(mFeatureInfo.vendor) ^ h; 556 tmp[2] = stringHash(mFeatureInfo.typeString) ^ h; 557 tmp[3] = tmp[0] ^ tmp[1] ^ tmp[2]; 558 memcpy(mFeatureInfo.uuid, tmp, sizeof(mFeatureInfo.uuid)); 559 } 560 561 mSensor = (sensor_t) { 562 mFeatureInfo.name.c_str(), // name 563 mFeatureInfo.vendor.c_str(), // vendor 564 mFeatureInfo.version, // version 565 -1, // handle, dummy number here 566 mFeatureInfo.type, 567 mFeatureInfo.maxRange, // maxRange 568 mFeatureInfo.resolution, // resolution 569 mFeatureInfo.power, // power 570 mFeatureInfo.minDelay, // minDelay 571 (uint32_t)mFeatureInfo.fifoSize, // fifoReservedEventCount 572 (uint32_t)mFeatureInfo.fifoMaxSize, // fifoMaxEventCount 573 mFeatureInfo.typeString.c_str(), // type string 574 mFeatureInfo.permission.c_str(), // requiredPermission 575 (long)mFeatureInfo.maxDelay, // maxDelay 576 mFeatureInfo.reportModeFlag | (mFeatureInfo.isWakeUp ? 1 : 0), 577 { NULL, NULL } 578 }; 579 return true; 580} 581 582bool HidRawSensor::decodeString( 583 const HidParser::ReportItem &report, const std::vector<uint8_t> &buffer, std::string *d) { 584 if (!report.isByteAligned() || report.bitSize != 16 || report.count < 1) { 585 return false; 586 } 587 588 size_t offset = report.bitOffset / 8; 589 if (offset + report.count * 2 > buffer.size()) { 590 return false; 591 } 592 593 std::vector<uint16_t> data(report.count); 594 auto i = data.begin(); 595 auto j = buffer.begin() + offset; 596 for ( ; i != data.end(); ++i, j += sizeof(uint16_t)) { 597 // hid specified little endian 598 *i = *j + (*(j + 1) << 8); 599 } 600 std::wstring wstr(data.begin(), data.end()); 601 602 std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter; 603 *d = converter.to_bytes(wstr); 604 return true; 605} 606 607std::vector<std::string> split(const std::string &text, char sep) { 608 std::vector<std::string> tokens; 609 size_t start = 0, end = 0; 610 while ((end = text.find(sep, start)) != std::string::npos) { 611 if (end != start) { 612 tokens.push_back(text.substr(start, end - start)); 613 } 614 start = end + 1; 615 } 616 if (end != start) { 617 tokens.push_back(text.substr(start)); 618 } 619 return tokens; 620} 621 622bool HidRawSensor::detectAndroidCustomSensor(const std::string &description) { 623 size_t nullPosition = description.find('\0'); 624 if (nullPosition == std::string::npos) { 625 return false; 626 } 627 const std::string prefix("#ANDROID#"); 628 if (description.find(prefix, nullPosition + 1) != nullPosition + 1) { 629 return false; 630 } 631 632 std::string str(description.c_str() + nullPosition + 1 + prefix.size()); 633 634 // Format for predefined sensor types: 635 // #ANDROID#nn,[C|X|T|S],[B|0],[W|N] 636 // Format for vendor type sensor 637 // #ANDROID#xxx.yyy.zzz,[C|X|T|S],[B|0],[W|N] 638 // 639 // C: continuous 640 // X: on-change 641 // T: one-shot 642 // S: special trigger 643 // 644 // B: body permission 645 // 0: no permission required 646 std::vector<std::string> segments; 647 size_t start = 0, end = 0; 648 while ((end = str.find(',', start)) != std::string::npos) { 649 if (end != start) { 650 segments.push_back(str.substr(start, end - start)); 651 } 652 start = end + 1; 653 } 654 if (end != start) { 655 segments.push_back(str.substr(start)); 656 } 657 658 if (segments.size() < 4) { 659 LOG_E << "Not enough segments in android custom description" << LOG_ENDL; 660 return false; 661 } 662 663 // type 664 bool typeParsed = false; 665 if (!segments[0].empty()) { 666 if (::isdigit(segments[0][0])) { 667 int type = ::atoi(segments[0].c_str()); 668 // all supported types here 669 switch (type) { 670 case SENSOR_TYPE_HEART_RATE: 671 mFeatureInfo.type = SENSOR_TYPE_HEART_RATE; 672 mFeatureInfo.typeString = SENSOR_STRING_TYPE_HEART_RATE; 673 typeParsed = true; 674 break; 675 case SENSOR_TYPE_AMBIENT_TEMPERATURE: 676 mFeatureInfo.type = SENSOR_TYPE_AMBIENT_TEMPERATURE; 677 mFeatureInfo.typeString = SENSOR_STRING_TYPE_AMBIENT_TEMPERATURE; 678 typeParsed = true; 679 case SENSOR_TYPE_LIGHT: 680 mFeatureInfo.type = SENSOR_TYPE_LIGHT; 681 mFeatureInfo.typeString = SENSOR_STRING_TYPE_LIGHT; 682 typeParsed = true; 683 break; 684 case SENSOR_TYPE_PRESSURE: 685 mFeatureInfo.type = SENSOR_TYPE_PRESSURE; 686 mFeatureInfo.typeString = SENSOR_STRING_TYPE_PRESSURE; 687 typeParsed = true; 688 break; 689 default: 690 LOG_W << "Android type " << type << " has not been supported yet" << LOG_ENDL; 691 break; 692 } 693 } else { 694 // assume a xxx.yyy.zzz format 695 std::ostringstream s; 696 bool lastIsDot = true; 697 for (auto c : segments[0]) { 698 if (::isalpha(c)) { 699 s << static_cast<char>(c); 700 lastIsDot = false; 701 } else if (!lastIsDot && c == '.') { 702 s << static_cast<char>(c); 703 lastIsDot = true; 704 } else { 705 break; 706 } 707 } 708 if (s.str() == segments[0]) { 709 mFeatureInfo.type = SENSOR_TYPE_DEVICE_PRIVATE_BASE; 710 mFeatureInfo.typeString = CUSTOM_TYPE_PREFIX + s.str(); 711 typeParsed = true; 712 } 713 } 714 } 715 716 // reporting type 717 bool reportingModeParsed = false; 718 if (segments[1].size() == 1) { 719 switch (segments[1][0]) { 720 case 'C': 721 mFeatureInfo.reportModeFlag = SENSOR_FLAG_CONTINUOUS_MODE; 722 reportingModeParsed = true; 723 break; 724 case 'X': 725 mFeatureInfo.reportModeFlag = SENSOR_FLAG_ON_CHANGE_MODE; 726 reportingModeParsed = true; 727 break; 728 case 'T': 729 mFeatureInfo.reportModeFlag = SENSOR_FLAG_ONE_SHOT_MODE; 730 reportingModeParsed = true; 731 break; 732 case 'S': 733 mFeatureInfo.reportModeFlag = SENSOR_FLAG_SPECIAL_REPORTING_MODE; 734 reportingModeParsed = true; 735 break; 736 default: 737 LOG_E << "Undefined reporting mode designation " << segments[1] << LOG_ENDL; 738 } 739 } 740 741 // permission parsed 742 bool permissionParsed = false; 743 if (segments[2].size() == 1) { 744 switch (segments[2][0]) { 745 case 'B': 746 mFeatureInfo.permission = SENSOR_PERMISSION_BODY_SENSORS; 747 permissionParsed = true; 748 break; 749 case '0': 750 mFeatureInfo.permission = ""; 751 permissionParsed = true; 752 break; 753 default: 754 LOG_E << "Undefined permission designation " << segments[2] << LOG_ENDL; 755 } 756 } 757 758 // wake up 759 bool wakeUpParsed = false; 760 if (segments[3].size() == 1) { 761 switch (segments[3][0]) { 762 case 'W': 763 mFeatureInfo.isWakeUp = true; 764 wakeUpParsed = true; 765 break; 766 case 'N': 767 mFeatureInfo.isWakeUp = false; 768 wakeUpParsed = true; 769 break; 770 default: 771 LOG_E << "Undefined wake up designation " << segments[3] << LOG_ENDL; 772 } 773 } 774 775 int ret = typeParsed && reportingModeParsed && permissionParsed && wakeUpParsed; 776 if (!ret) { 777 LOG_D << "detectAndroidCustomSensor typeParsed: " << typeParsed 778 << " reportingModeParsed: " << reportingModeParsed 779 << " permissionParsed: " << permissionParsed 780 << " wakeUpParsed: " << wakeUpParsed << LOG_ENDL; 781 } 782 return ret; 783} 784 785bool HidRawSensor::findSensorControlUsage(const std::vector<HidParser::ReportPacket> &packets) { 786 using namespace Hid::Sensor::PropertyUsage; 787 using namespace Hid::Sensor::RawMinMax; 788 789 //REPORTING_STATE 790 const HidParser::ReportItem *reportingState 791 = find(packets, REPORTING_STATE, HidParser::REPORT_TYPE_FEATURE); 792 793 if (reportingState == nullptr 794 || !reportingState->isByteAligned() 795 || reportingState->bitSize != 8 796 || reportingState->minRaw != REPORTING_STATE_MIN 797 || reportingState->maxRaw != REPORTING_STATE_MAX) { 798 LOG_W << "Cannot find valid reporting state feature" << LOG_ENDL; 799 } else { 800 mReportingStateId = reportingState->id; 801 mReportingStateOffset = reportingState->bitOffset / 8; 802 } 803 804 //POWER_STATE 805 const HidParser::ReportItem *powerState 806 = find(packets, POWER_STATE, HidParser::REPORT_TYPE_FEATURE); 807 if (powerState == nullptr 808 || !powerState->isByteAligned() 809 || powerState->bitSize != 8 810 || powerState->minRaw != POWER_STATE_MIN 811 || powerState->maxRaw != POWER_STATE_MAX) { 812 LOG_W << "Cannot find valid power state feature" << LOG_ENDL; 813 } else { 814 mPowerStateId = powerState->id; 815 mPowerStateOffset = powerState->bitOffset / 8; 816 } 817 818 //REPORT_INTERVAL 819 const HidParser::ReportItem *reportInterval 820 = find(packets, REPORT_INTERVAL, HidParser::REPORT_TYPE_FEATURE); 821 if (reportInterval == nullptr 822 || !reportInterval->isByteAligned() 823 || reportInterval->minRaw < 0 824 || (reportInterval->bitSize != 16 && reportInterval->bitSize != 32)) { 825 LOG_W << "Cannot find valid report interval feature" << LOG_ENDL; 826 } else { 827 mReportIntervalId = reportInterval->id; 828 mReportIntervalOffset = reportInterval->bitOffset / 8; 829 mReportIntervalSize = reportInterval->bitSize / 8; 830 831 mFeatureInfo.minDelay = std::max(static_cast<int64_t>(1), reportInterval->minRaw) * 1000; 832 mFeatureInfo.maxDelay = std::min(static_cast<int64_t>(1000000), 833 reportInterval->maxRaw) * 1000; // maximum 1000 second 834 } 835 return true; 836 return (mPowerStateId >= 0 || mReportingStateId >= 0) && mReportIntervalId >= 0; 837} 838 839const sensor_t* HidRawSensor::getSensor() const { 840 return &mSensor; 841} 842 843void HidRawSensor::getUuid(uint8_t* uuid) const { 844 memcpy(uuid, mFeatureInfo.uuid, sizeof(mFeatureInfo.uuid)); 845} 846 847int HidRawSensor::enable(bool enable) { 848 using namespace Hid::Sensor::StateValue; 849 SP(HidDevice) device = PROMOTE(mDevice); 850 851 if (device == nullptr) { 852 return NO_INIT; 853 } 854 855 if (enable == mEnabled) { 856 return NO_ERROR; 857 } 858 859 std::vector<uint8_t> buffer; 860 bool setPowerOk = true; 861 if (mPowerStateId >= 0) { 862 setPowerOk = false; 863 uint8_t id = static_cast<uint8_t>(mPowerStateId); 864 if (device->getFeature(id, &buffer) 865 && buffer.size() > mPowerStateOffset) { 866 buffer[mPowerStateOffset] = enable ? POWER_STATE_FULL_POWER : POWER_STATE_POWER_OFF; 867 setPowerOk = device->setFeature(id, buffer); 868 } else { 869 LOG_E << "enable: changing POWER STATE failed" << LOG_ENDL; 870 } 871 } 872 873 bool setReportingOk = true; 874 if (mReportingStateId >= 0) { 875 setReportingOk = false; 876 uint8_t id = static_cast<uint8_t>(mReportingStateId); 877 if (device->getFeature(id, &buffer) 878 && buffer.size() > mReportingStateOffset) { 879 buffer[mReportingStateOffset] 880 = enable ? REPORTING_STATE_ALL_EVENT : REPORTING_STATE_NO_EVENT; 881 setReportingOk = device->setFeature(id, buffer); 882 } else { 883 LOG_E << "enable: changing REPORTING STATE failed" << LOG_ENDL; 884 } 885 } 886 887 if (setPowerOk && setReportingOk) { 888 mEnabled = enable; 889 return NO_ERROR; 890 } else { 891 return INVALID_OPERATION; 892 } 893} 894 895int HidRawSensor::batch(int64_t samplingPeriod, int64_t batchingPeriod) { 896 SP(HidDevice) device = PROMOTE(mDevice); 897 if (device == nullptr) { 898 return NO_INIT; 899 } 900 901 if (samplingPeriod < 0 || batchingPeriod < 0) { 902 return BAD_VALUE; 903 } 904 905 bool needRefresh = mSamplingPeriod != samplingPeriod || mBatchingPeriod != batchingPeriod; 906 std::vector<uint8_t> buffer; 907 908 bool ok = true; 909 if (needRefresh && mReportIntervalId >= 0) { 910 ok = false; 911 uint8_t id = static_cast<uint8_t>(mReportIntervalId); 912 if (device->getFeature(id, &buffer) 913 && buffer.size() >= mReportIntervalOffset + mReportIntervalSize) { 914 int64_t periodMs = samplingPeriod / 1000000; //ns -> ms 915 switch (mReportIntervalSize) { 916 case sizeof(uint16_t): 917 periodMs = std::min(periodMs, static_cast<int64_t>(UINT16_MAX)); 918 buffer[mReportIntervalOffset] = periodMs & 0xFF; 919 buffer[mReportIntervalOffset + 1] = (periodMs >> 8) & 0xFF; 920 case sizeof(uint32_t): 921 periodMs = std::min(periodMs, static_cast<int64_t>(UINT32_MAX)); 922 buffer[mReportIntervalOffset] = periodMs & 0xFF; 923 buffer[mReportIntervalOffset + 1] = (periodMs >> 8) & 0xFF; 924 buffer[mReportIntervalOffset + 2] = (periodMs >> 16) & 0xFF; 925 buffer[mReportIntervalOffset + 3] = (periodMs >> 24) & 0xFF; 926 } 927 ok = device->setFeature(id, buffer); 928 } 929 } 930 931 if (ok) { 932 mSamplingPeriod = samplingPeriod; 933 mBatchingPeriod = batchingPeriod; 934 return NO_ERROR; 935 } else { 936 return INVALID_OPERATION; 937 } 938} 939 940void HidRawSensor::handleInput(uint8_t id, const std::vector<uint8_t> &message) { 941 if (id != mInputReportId || mEnabled == false) { 942 return; 943 } 944 sensors_event_t event = { 945 .version = sizeof(event), 946 .sensor = -1, 947 .type = mSensor.type 948 }; 949 bool valid = true; 950 for (const auto &rec : mTranslateTable) { 951 int64_t v = (message[rec.byteOffset + rec.byteSize - 1] & 0x80) ? -1 : 0; 952 for (int i = static_cast<int>(rec.byteSize) - 1; i >= 0; --i) { 953 v = (v << 8) | message[rec.byteOffset + i]; // HID is little endian 954 } 955 956 switch (rec.type) { 957 case TYPE_FLOAT: 958 if (v > rec.maxValue || v < rec.minValue) { 959 valid = false; 960 } 961 event.data[rec.index] = rec.a * (v + rec.b); 962 break; 963 case TYPE_INT64: 964 if (v > rec.maxValue || v < rec.minValue) { 965 valid = false; 966 } 967 event.u64.data[rec.index] = v + rec.b; 968 break; 969 case TYPE_ACCURACY: 970 event.magnetic.status = (v & 0xFF) + rec.b; 971 break; 972 } 973 } 974 if (!valid) { 975 LOG_V << "Range error observed in decoding, discard" << LOG_ENDL; 976 } 977 event.timestamp = -1; 978 generateEvent(event); 979} 980 981std::string HidRawSensor::dump() const { 982 std::ostringstream ss; 983 ss << "Feature Values " << LOG_ENDL 984 << " name: " << mFeatureInfo.name << LOG_ENDL 985 << " vendor: " << mFeatureInfo.vendor << LOG_ENDL 986 << " permission: " << mFeatureInfo.permission << LOG_ENDL 987 << " typeString: " << mFeatureInfo.typeString << LOG_ENDL 988 << " type: " << mFeatureInfo.type << LOG_ENDL 989 << " maxRange: " << mFeatureInfo.maxRange << LOG_ENDL 990 << " resolution: " << mFeatureInfo.resolution << LOG_ENDL 991 << " power: " << mFeatureInfo.power << LOG_ENDL 992 << " minDelay: " << mFeatureInfo.minDelay << LOG_ENDL 993 << " maxDelay: " << mFeatureInfo.maxDelay << LOG_ENDL 994 << " fifoSize: " << mFeatureInfo.fifoSize << LOG_ENDL 995 << " fifoMaxSize: " << mFeatureInfo.fifoMaxSize << LOG_ENDL 996 << " reportModeFlag: " << mFeatureInfo.reportModeFlag << LOG_ENDL 997 << " isWakeUp: " << (mFeatureInfo.isWakeUp ? "true" : "false") << LOG_ENDL 998 << " uniqueId: " << mFeatureInfo.uniqueId << LOG_ENDL 999 << " uuid: "; 1000 1001 ss << std::hex << std::setfill('0'); 1002 for (auto d : mFeatureInfo.uuid) { 1003 ss << std::setw(2) << static_cast<int>(d) << " "; 1004 } 1005 ss << std::dec << std::setfill(' ') << LOG_ENDL; 1006 1007 ss << "Input report id: " << mInputReportId << LOG_ENDL; 1008 for (const auto &t : mTranslateTable) { 1009 ss << " type, index: " << t.type << ", " << t.index 1010 << "; min,max: " << t.minValue << ", " << t.maxValue 1011 << "; byte-offset,size: " << t.byteOffset << ", " << t.byteSize 1012 << "; scaling,bias: " << t.a << ", " << t.b << LOG_ENDL; 1013 } 1014 1015 ss << "Control features: " << LOG_ENDL; 1016 ss << " Power state "; 1017 if (mPowerStateId >= 0) { 1018 ss << "found, id: " << mPowerStateId 1019 << " offset: " << mPowerStateOffset << LOG_ENDL; 1020 } else { 1021 ss << "not found" << LOG_ENDL; 1022 } 1023 1024 ss << " Reporting state "; 1025 if (mReportingStateId >= 0) { 1026 ss << "found, id: " << mReportingStateId 1027 << " offset: " << mReportingStateOffset << LOG_ENDL; 1028 } else { 1029 ss << "not found" << LOG_ENDL; 1030 } 1031 1032 ss << " Report interval "; 1033 if (mReportIntervalId >= 0) { 1034 ss << "found, id: " << mReportIntervalId 1035 << " offset: " << mReportIntervalOffset 1036 << " size: " << mReportIntervalSize << LOG_ENDL; 1037 } else { 1038 ss << "not found" << LOG_ENDL; 1039 } 1040 return ss.str(); 1041} 1042 1043} // namespace SensorHalExt 1044} // namespace android 1045