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