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
28 namespace android {
29 namespace SensorHalExt {
30
31 namespace {
32 const std::string CUSTOM_TYPE_PREFIX("com.google.hardware.sensor.hid_dynamic.");
33 }
34
HidRawSensor(SP (HidDevice)device,uint32_t usage,const std::vector<HidParser::ReportPacket> & packets)35 HidRawSensor::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
processQuaternionUsage(const std::vector<HidParser::ReportPacket> & packets)223 bool 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
processTriAxisUsage(const std::vector<HidParser::ReportPacket> & packets,uint32_t usageX,uint32_t usageY,uint32_t usageZ,double defaultScaling)295 bool 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
find(const std::vector<HidParser::ReportPacket> & packets,unsigned int usage,int type,int id)393 const 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
initFeatureValueFromHidDeviceInfo(FeatureValue * featureValue,const HidDevice::HidDeviceInfo & info)413 void 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
populateFeatureValueFromFeatureReport(FeatureValue * featureValue,const std::vector<HidParser::ReportPacket> & packets)444 bool 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
validateFeatureValueAndBuildSensor()511 bool 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
decodeString(const HidParser::ReportItem & report,const std::vector<uint8_t> & buffer,std::string * d)582 bool 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
split(const std::string & text,char sep)607 std::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
detectAndroidCustomSensor(const std::string & description)622 bool 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 break;
680 case SENSOR_TYPE_LIGHT:
681 mFeatureInfo.type = SENSOR_TYPE_LIGHT;
682 mFeatureInfo.typeString = SENSOR_STRING_TYPE_LIGHT;
683 typeParsed = true;
684 break;
685 case SENSOR_TYPE_PRESSURE:
686 mFeatureInfo.type = SENSOR_TYPE_PRESSURE;
687 mFeatureInfo.typeString = SENSOR_STRING_TYPE_PRESSURE;
688 typeParsed = true;
689 break;
690 default:
691 LOG_W << "Android type " << type << " has not been supported yet" << LOG_ENDL;
692 break;
693 }
694 } else {
695 // assume a xxx.yyy.zzz format
696 std::ostringstream s;
697 bool lastIsDot = true;
698 for (auto c : segments[0]) {
699 if (::isalpha(c)) {
700 s << static_cast<char>(c);
701 lastIsDot = false;
702 } else if (!lastIsDot && c == '.') {
703 s << static_cast<char>(c);
704 lastIsDot = true;
705 } else {
706 break;
707 }
708 }
709 if (s.str() == segments[0]) {
710 mFeatureInfo.type = SENSOR_TYPE_DEVICE_PRIVATE_BASE;
711 mFeatureInfo.typeString = CUSTOM_TYPE_PREFIX + s.str();
712 typeParsed = true;
713 }
714 }
715 }
716
717 // reporting type
718 bool reportingModeParsed = false;
719 if (segments[1].size() == 1) {
720 switch (segments[1][0]) {
721 case 'C':
722 mFeatureInfo.reportModeFlag = SENSOR_FLAG_CONTINUOUS_MODE;
723 reportingModeParsed = true;
724 break;
725 case 'X':
726 mFeatureInfo.reportModeFlag = SENSOR_FLAG_ON_CHANGE_MODE;
727 reportingModeParsed = true;
728 break;
729 case 'T':
730 mFeatureInfo.reportModeFlag = SENSOR_FLAG_ONE_SHOT_MODE;
731 reportingModeParsed = true;
732 break;
733 case 'S':
734 mFeatureInfo.reportModeFlag = SENSOR_FLAG_SPECIAL_REPORTING_MODE;
735 reportingModeParsed = true;
736 break;
737 default:
738 LOG_E << "Undefined reporting mode designation " << segments[1] << LOG_ENDL;
739 }
740 }
741
742 // permission parsed
743 bool permissionParsed = false;
744 if (segments[2].size() == 1) {
745 switch (segments[2][0]) {
746 case 'B':
747 mFeatureInfo.permission = SENSOR_PERMISSION_BODY_SENSORS;
748 permissionParsed = true;
749 break;
750 case '0':
751 mFeatureInfo.permission = "";
752 permissionParsed = true;
753 break;
754 default:
755 LOG_E << "Undefined permission designation " << segments[2] << LOG_ENDL;
756 }
757 }
758
759 // wake up
760 bool wakeUpParsed = false;
761 if (segments[3].size() == 1) {
762 switch (segments[3][0]) {
763 case 'W':
764 mFeatureInfo.isWakeUp = true;
765 wakeUpParsed = true;
766 break;
767 case 'N':
768 mFeatureInfo.isWakeUp = false;
769 wakeUpParsed = true;
770 break;
771 default:
772 LOG_E << "Undefined wake up designation " << segments[3] << LOG_ENDL;
773 }
774 }
775
776 int ret = typeParsed && reportingModeParsed && permissionParsed && wakeUpParsed;
777 if (!ret) {
778 LOG_D << "detectAndroidCustomSensor typeParsed: " << typeParsed
779 << " reportingModeParsed: " << reportingModeParsed
780 << " permissionParsed: " << permissionParsed
781 << " wakeUpParsed: " << wakeUpParsed << LOG_ENDL;
782 }
783 return ret;
784 }
785
findSensorControlUsage(const std::vector<HidParser::ReportPacket> & packets)786 bool HidRawSensor::findSensorControlUsage(const std::vector<HidParser::ReportPacket> &packets) {
787 using namespace Hid::Sensor::PropertyUsage;
788 using namespace Hid::Sensor::RawMinMax;
789
790 //REPORTING_STATE
791 const HidParser::ReportItem *reportingState
792 = find(packets, REPORTING_STATE, HidParser::REPORT_TYPE_FEATURE);
793
794 if (reportingState == nullptr
795 || !reportingState->isByteAligned()
796 || reportingState->bitSize != 8
797 || reportingState->minRaw != REPORTING_STATE_MIN
798 || reportingState->maxRaw != REPORTING_STATE_MAX) {
799 LOG_W << "Cannot find valid reporting state feature" << LOG_ENDL;
800 } else {
801 mReportingStateId = reportingState->id;
802 mReportingStateOffset = reportingState->bitOffset / 8;
803 }
804
805 //POWER_STATE
806 const HidParser::ReportItem *powerState
807 = find(packets, POWER_STATE, HidParser::REPORT_TYPE_FEATURE);
808 if (powerState == nullptr
809 || !powerState->isByteAligned()
810 || powerState->bitSize != 8
811 || powerState->minRaw != POWER_STATE_MIN
812 || powerState->maxRaw != POWER_STATE_MAX) {
813 LOG_W << "Cannot find valid power state feature" << LOG_ENDL;
814 } else {
815 mPowerStateId = powerState->id;
816 mPowerStateOffset = powerState->bitOffset / 8;
817 }
818
819 //REPORT_INTERVAL
820 const HidParser::ReportItem *reportInterval
821 = find(packets, REPORT_INTERVAL, HidParser::REPORT_TYPE_FEATURE);
822 if (reportInterval == nullptr
823 || !reportInterval->isByteAligned()
824 || reportInterval->minRaw < 0
825 || (reportInterval->bitSize != 16 && reportInterval->bitSize != 32)) {
826 LOG_W << "Cannot find valid report interval feature" << LOG_ENDL;
827 } else {
828 mReportIntervalId = reportInterval->id;
829 mReportIntervalOffset = reportInterval->bitOffset / 8;
830 mReportIntervalSize = reportInterval->bitSize / 8;
831
832 mFeatureInfo.minDelay = std::max(static_cast<int64_t>(1), reportInterval->minRaw) * 1000;
833 mFeatureInfo.maxDelay = std::min(static_cast<int64_t>(1000000),
834 reportInterval->maxRaw) * 1000; // maximum 1000 second
835 }
836 return true;
837 return (mPowerStateId >= 0 || mReportingStateId >= 0) && mReportIntervalId >= 0;
838 }
839
getSensor() const840 const sensor_t* HidRawSensor::getSensor() const {
841 return &mSensor;
842 }
843
getUuid(uint8_t * uuid) const844 void HidRawSensor::getUuid(uint8_t* uuid) const {
845 memcpy(uuid, mFeatureInfo.uuid, sizeof(mFeatureInfo.uuid));
846 }
847
enable(bool enable)848 int HidRawSensor::enable(bool enable) {
849 using namespace Hid::Sensor::StateValue;
850 SP(HidDevice) device = PROMOTE(mDevice);
851
852 if (device == nullptr) {
853 return NO_INIT;
854 }
855
856 if (enable == mEnabled) {
857 return NO_ERROR;
858 }
859
860 std::vector<uint8_t> buffer;
861 bool setPowerOk = true;
862 if (mPowerStateId >= 0) {
863 setPowerOk = false;
864 uint8_t id = static_cast<uint8_t>(mPowerStateId);
865 if (device->getFeature(id, &buffer)
866 && buffer.size() > mPowerStateOffset) {
867 buffer[mPowerStateOffset] = enable ? POWER_STATE_FULL_POWER : POWER_STATE_POWER_OFF;
868 setPowerOk = device->setFeature(id, buffer);
869 } else {
870 LOG_E << "enable: changing POWER STATE failed" << LOG_ENDL;
871 }
872 }
873
874 bool setReportingOk = true;
875 if (mReportingStateId >= 0) {
876 setReportingOk = false;
877 uint8_t id = static_cast<uint8_t>(mReportingStateId);
878 if (device->getFeature(id, &buffer)
879 && buffer.size() > mReportingStateOffset) {
880 buffer[mReportingStateOffset]
881 = enable ? REPORTING_STATE_ALL_EVENT : REPORTING_STATE_NO_EVENT;
882 setReportingOk = device->setFeature(id, buffer);
883 } else {
884 LOG_E << "enable: changing REPORTING STATE failed" << LOG_ENDL;
885 }
886 }
887
888 if (setPowerOk && setReportingOk) {
889 mEnabled = enable;
890 return NO_ERROR;
891 } else {
892 return INVALID_OPERATION;
893 }
894 }
895
batch(int64_t samplingPeriod,int64_t batchingPeriod)896 int HidRawSensor::batch(int64_t samplingPeriod, int64_t batchingPeriod) {
897 SP(HidDevice) device = PROMOTE(mDevice);
898 if (device == nullptr) {
899 return NO_INIT;
900 }
901
902 if (samplingPeriod < 0 || batchingPeriod < 0) {
903 return BAD_VALUE;
904 }
905
906 bool needRefresh = mSamplingPeriod != samplingPeriod || mBatchingPeriod != batchingPeriod;
907 std::vector<uint8_t> buffer;
908
909 bool ok = true;
910 if (needRefresh && mReportIntervalId >= 0) {
911 ok = false;
912 uint8_t id = static_cast<uint8_t>(mReportIntervalId);
913 if (device->getFeature(id, &buffer)
914 && buffer.size() >= mReportIntervalOffset + mReportIntervalSize) {
915 int64_t periodMs = samplingPeriod / 1000000; //ns -> ms
916 switch (mReportIntervalSize) {
917 case sizeof(uint16_t):
918 periodMs = std::min(periodMs, static_cast<int64_t>(UINT16_MAX));
919 buffer[mReportIntervalOffset] = periodMs & 0xFF;
920 buffer[mReportIntervalOffset + 1] = (periodMs >> 8) & 0xFF;
921 break;
922 case sizeof(uint32_t):
923 periodMs = std::min(periodMs, static_cast<int64_t>(UINT32_MAX));
924 buffer[mReportIntervalOffset] = periodMs & 0xFF;
925 buffer[mReportIntervalOffset + 1] = (periodMs >> 8) & 0xFF;
926 buffer[mReportIntervalOffset + 2] = (periodMs >> 16) & 0xFF;
927 buffer[mReportIntervalOffset + 3] = (periodMs >> 24) & 0xFF;
928 break;
929 }
930 ok = device->setFeature(id, buffer);
931 }
932 }
933
934 if (ok) {
935 mSamplingPeriod = samplingPeriod;
936 mBatchingPeriod = batchingPeriod;
937 return NO_ERROR;
938 } else {
939 return INVALID_OPERATION;
940 }
941 }
942
handleInput(uint8_t id,const std::vector<uint8_t> & message)943 void HidRawSensor::handleInput(uint8_t id, const std::vector<uint8_t> &message) {
944 if (id != mInputReportId || mEnabled == false) {
945 return;
946 }
947 sensors_event_t event = {
948 .version = sizeof(event),
949 .sensor = -1,
950 .type = mSensor.type
951 };
952 bool valid = true;
953 for (const auto &rec : mTranslateTable) {
954 int64_t v = (message[rec.byteOffset + rec.byteSize - 1] & 0x80) ? -1 : 0;
955 for (int i = static_cast<int>(rec.byteSize) - 1; i >= 0; --i) {
956 v = (v << 8) | message[rec.byteOffset + i]; // HID is little endian
957 }
958
959 switch (rec.type) {
960 case TYPE_FLOAT:
961 if (v > rec.maxValue || v < rec.minValue) {
962 valid = false;
963 }
964 event.data[rec.index] = rec.a * (v + rec.b);
965 break;
966 case TYPE_INT64:
967 if (v > rec.maxValue || v < rec.minValue) {
968 valid = false;
969 }
970 event.u64.data[rec.index] = v + rec.b;
971 break;
972 case TYPE_ACCURACY:
973 event.magnetic.status = (v & 0xFF) + rec.b;
974 break;
975 }
976 }
977 if (!valid) {
978 LOG_V << "Range error observed in decoding, discard" << LOG_ENDL;
979 }
980 event.timestamp = -1;
981 generateEvent(event);
982 }
983
dump() const984 std::string HidRawSensor::dump() const {
985 std::ostringstream ss;
986 ss << "Feature Values " << LOG_ENDL
987 << " name: " << mFeatureInfo.name << LOG_ENDL
988 << " vendor: " << mFeatureInfo.vendor << LOG_ENDL
989 << " permission: " << mFeatureInfo.permission << LOG_ENDL
990 << " typeString: " << mFeatureInfo.typeString << LOG_ENDL
991 << " type: " << mFeatureInfo.type << LOG_ENDL
992 << " maxRange: " << mFeatureInfo.maxRange << LOG_ENDL
993 << " resolution: " << mFeatureInfo.resolution << LOG_ENDL
994 << " power: " << mFeatureInfo.power << LOG_ENDL
995 << " minDelay: " << mFeatureInfo.minDelay << LOG_ENDL
996 << " maxDelay: " << mFeatureInfo.maxDelay << LOG_ENDL
997 << " fifoSize: " << mFeatureInfo.fifoSize << LOG_ENDL
998 << " fifoMaxSize: " << mFeatureInfo.fifoMaxSize << LOG_ENDL
999 << " reportModeFlag: " << mFeatureInfo.reportModeFlag << LOG_ENDL
1000 << " isWakeUp: " << (mFeatureInfo.isWakeUp ? "true" : "false") << LOG_ENDL
1001 << " uniqueId: " << mFeatureInfo.uniqueId << LOG_ENDL
1002 << " uuid: ";
1003
1004 ss << std::hex << std::setfill('0');
1005 for (auto d : mFeatureInfo.uuid) {
1006 ss << std::setw(2) << static_cast<int>(d) << " ";
1007 }
1008 ss << std::dec << std::setfill(' ') << LOG_ENDL;
1009
1010 ss << "Input report id: " << mInputReportId << LOG_ENDL;
1011 for (const auto &t : mTranslateTable) {
1012 ss << " type, index: " << t.type << ", " << t.index
1013 << "; min,max: " << t.minValue << ", " << t.maxValue
1014 << "; byte-offset,size: " << t.byteOffset << ", " << t.byteSize
1015 << "; scaling,bias: " << t.a << ", " << t.b << LOG_ENDL;
1016 }
1017
1018 ss << "Control features: " << LOG_ENDL;
1019 ss << " Power state ";
1020 if (mPowerStateId >= 0) {
1021 ss << "found, id: " << mPowerStateId
1022 << " offset: " << mPowerStateOffset << LOG_ENDL;
1023 } else {
1024 ss << "not found" << LOG_ENDL;
1025 }
1026
1027 ss << " Reporting state ";
1028 if (mReportingStateId >= 0) {
1029 ss << "found, id: " << mReportingStateId
1030 << " offset: " << mReportingStateOffset << LOG_ENDL;
1031 } else {
1032 ss << "not found" << LOG_ENDL;
1033 }
1034
1035 ss << " Report interval ";
1036 if (mReportIntervalId >= 0) {
1037 ss << "found, id: " << mReportIntervalId
1038 << " offset: " << mReportIntervalOffset
1039 << " size: " << mReportIntervalSize << LOG_ENDL;
1040 } else {
1041 ss << "not found" << LOG_ENDL;
1042 }
1043 return ss.str();
1044 }
1045
1046 } // namespace SensorHalExt
1047 } // namespace android
1048