Home | History | Annotate | Download | only in nanotool
      1 /*
      2  * Copyright (C) 2016 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 
     17 #include "contexthub.h"
     18 
     19 #include <cstring>
     20 #include <errno.h>
     21 #include <vector>
     22 
     23 #include "apptohostevent.h"
     24 #include "log.h"
     25 #include "resetreasonevent.h"
     26 #include "sensorevent.h"
     27 #include "util.h"
     28 
     29 namespace android {
     30 
     31 #define UNUSED_PARAM(param) (void) (param)
     32 
     33 constexpr int kCalibrationTimeoutMs(10000);
     34 constexpr int kTestTimeoutMs(10000);
     35 constexpr int kBridgeVersionTimeoutMs(500);
     36 
     37 struct SensorTypeNames {
     38     SensorType sensor_type;
     39     const char *name_abbrev;
     40 };
     41 
     42 static const SensorTypeNames sensor_names_[] = {
     43     { SensorType::Accel,                "accel" },
     44     { SensorType::AnyMotion,            "anymo" },
     45     { SensorType::NoMotion,             "nomo" },
     46     { SensorType::SignificantMotion,    "sigmo" },
     47     { SensorType::Flat,                 "flat" },
     48     { SensorType::Gyro,                 "gyro" },
     49     //{ SensorType::GyroUncal,            "gyro_uncal" },
     50     { SensorType::Magnetometer,         "mag" },
     51     //{ SensorType::MagnetometerUncal,    "mag_uncal" },
     52     { SensorType::Barometer,            "baro" },
     53     { SensorType::Temperature,          "temp" },
     54     { SensorType::AmbientLightSensor,   "als" },
     55     { SensorType::Proximity,            "prox" },
     56     { SensorType::Orientation,          "orien" },
     57     //{ SensorType::HeartRateECG,         "ecg" },
     58     //{ SensorType::HeartRatePPG,         "ppg" },
     59     { SensorType::Gravity,              "gravity" },
     60     { SensorType::LinearAccel,          "linear_acc" },
     61     { SensorType::RotationVector,       "rotation" },
     62     { SensorType::GeomagneticRotationVector, "geomag" },
     63     { SensorType::GameRotationVector,   "game" },
     64     { SensorType::StepCount,            "step_cnt" },
     65     { SensorType::StepDetect,           "step_det" },
     66     { SensorType::Gesture,              "gesture" },
     67     { SensorType::Tilt,                 "tilt" },
     68     { SensorType::DoubleTwist,          "twist" },
     69     { SensorType::DoubleTap,            "doubletap" },
     70     { SensorType::WindowOrientation,    "win_orien" },
     71     { SensorType::Hall,                 "hall" },
     72     { SensorType::Activity,             "activity" },
     73     { SensorType::Vsync,                "vsync" },
     74     { SensorType::WristTilt,            "wrist_tilt" },
     75     { SensorType::Humidity,             "humidity" },
     76 };
     77 
     78 struct SensorTypeAlias {
     79     SensorType sensor_type;
     80     SensorType sensor_alias;
     81     const char *name_abbrev;
     82 };
     83 
     84 static const SensorTypeAlias sensor_aliases_[] = {
     85     { SensorType::Accel, SensorType::CompressedAccel, "compressed_accel" },
     86     { SensorType::Magnetometer, SensorType::CompressedMag, "compressed_mag" },
     87 };
     88 
     89 bool SensorTypeIsAliasOf(SensorType sensor_type, SensorType alias) {
     90     for (size_t i = 0; i < ARRAY_LEN(sensor_aliases_); i++) {
     91         if (sensor_aliases_[i].sensor_type == sensor_type
     92                 && sensor_aliases_[i].sensor_alias == alias) {
     93             return true;
     94         }
     95     }
     96 
     97     return false;
     98 }
     99 
    100 SensorType ContextHub::SensorAbbrevNameToType(const char *sensor_name_abbrev) {
    101     for (unsigned int i = 0; i < ARRAY_LEN(sensor_names_); i++) {
    102         if (strcmp(sensor_names_[i].name_abbrev, sensor_name_abbrev) == 0) {
    103             return sensor_names_[i].sensor_type;
    104         }
    105     }
    106 
    107     return SensorType::Invalid_;
    108 }
    109 
    110 SensorType ContextHub::SensorAbbrevNameToType(const std::string& abbrev_name) {
    111     return ContextHub::SensorAbbrevNameToType(abbrev_name.c_str());
    112 }
    113 
    114 std::string ContextHub::SensorTypeToAbbrevName(SensorType sensor_type) {
    115     for (unsigned int i = 0; i < ARRAY_LEN(sensor_names_); i++) {
    116         if (sensor_names_[i].sensor_type == sensor_type) {
    117             return std::string(sensor_names_[i].name_abbrev);
    118         }
    119     }
    120 
    121     for (unsigned int i = 0; i < ARRAY_LEN(sensor_aliases_); i++) {
    122         if (sensor_aliases_[i].sensor_alias == sensor_type) {
    123             return std::string(sensor_aliases_[i].name_abbrev);
    124         }
    125     }
    126 
    127     char buffer[24];
    128     snprintf(buffer, sizeof(buffer), "unknown (%d)",
    129              static_cast<int>(sensor_type));
    130     return std::string(buffer);
    131 }
    132 
    133 std::string ContextHub::ListAllSensorAbbrevNames() {
    134     std::string sensor_list;
    135     for (unsigned int i = 0; i < ARRAY_LEN(sensor_names_); i++) {
    136         sensor_list += sensor_names_[i].name_abbrev;
    137         if (i < ARRAY_LEN(sensor_names_) - 1) {
    138             sensor_list += ", ";
    139         }
    140     }
    141 
    142     return sensor_list;
    143 }
    144 
    145 bool ContextHub::Flash(const std::string& filename) {
    146     FILE *firmware_file = fopen(filename.c_str(), "r");
    147     if (!firmware_file) {
    148         LOGE("Failed to open firmware image: %d (%s)", errno, strerror(errno));
    149         return false;
    150     }
    151 
    152     fseek(firmware_file, 0, SEEK_END);
    153     long file_size = ftell(firmware_file);
    154     fseek(firmware_file, 0, SEEK_SET);
    155 
    156     auto firmware_data = std::vector<uint8_t>(file_size);
    157     size_t bytes_read = fread(firmware_data.data(), sizeof(uint8_t),
    158         file_size, firmware_file);
    159     fclose(firmware_file);
    160 
    161     if (bytes_read != static_cast<size_t>(file_size)) {
    162         LOGE("Read of firmware file returned %zu, expected %ld",
    163             bytes_read, file_size);
    164         return false;
    165     }
    166     return FlashSensorHub(firmware_data);
    167 }
    168 
    169 bool ContextHub::CalibrateSensors(const std::vector<SensorSpec>& sensors) {
    170     bool success = ForEachSensor(sensors, [this](const SensorSpec &spec) -> bool {
    171         return CalibrateSingleSensor(spec);
    172     });
    173 
    174     if (success) {
    175         success = SaveCalibration();
    176     }
    177     return success;
    178 }
    179 
    180 bool ContextHub::TestSensors(const std::vector<SensorSpec>& sensors) {
    181     bool success = ForEachSensor(sensors, [this](const SensorSpec &spec) -> bool {
    182         return TestSingleSensor(spec);
    183     });
    184 
    185     return success;
    186 }
    187 
    188 bool ContextHub::EnableSensor(const SensorSpec& spec) {
    189     ConfigureSensorRequest req;
    190 
    191     req.config.event_type = static_cast<uint32_t>(EventType::ConfigureSensor);
    192     req.config.sensor_type = static_cast<uint8_t>(spec.sensor_type);
    193     req.config.command = static_cast<uint8_t>(
    194         ConfigureSensorRequest::CommandType::Enable);
    195     if (spec.special_rate != SensorSpecialRate::None) {
    196         req.config.rate = static_cast<uint32_t>(spec.special_rate);
    197     } else {
    198         req.config.rate = ConfigureSensorRequest::FloatRateToFixedPoint(
    199             spec.rate_hz);
    200     }
    201     req.config.latency = spec.latency_ns;
    202 
    203     LOGI("Enabling sensor %d at rate %.0f Hz (special 0x%x) and latency %.2f ms",
    204          spec.sensor_type, spec.rate_hz, spec.special_rate,
    205          spec.latency_ns / 1000000.0f);
    206     auto result = WriteEvent(req);
    207     if (result == TransportResult::Success) {
    208         sensor_is_active_[static_cast<int>(spec.sensor_type)] = true;
    209         return true;
    210     }
    211 
    212     LOGE("Could not enable sensor %d", spec.sensor_type);
    213     return false;
    214 }
    215 
    216 bool ContextHub::EnableSensors(const std::vector<SensorSpec>& sensors) {
    217     return ForEachSensor(sensors, [this](const SensorSpec &spec) -> bool {
    218         return EnableSensor(spec);
    219     });
    220 }
    221 
    222 bool ContextHub::DisableSensor(SensorType sensor_type) {
    223     ConfigureSensorRequest req;
    224 
    225     req.config.event_type = static_cast<uint32_t>(EventType::ConfigureSensor);
    226     req.config.sensor_type = static_cast<uint8_t>(sensor_type);
    227     req.config.command = static_cast<uint8_t>(
    228         ConfigureSensorRequest::CommandType::Disable);
    229 
    230     // Note that nanohub treats us as a single client, so if we call enable
    231     // twice then disable once, the sensor will be disabled
    232     LOGI("Disabling sensor %d", sensor_type);
    233     auto result = WriteEvent(req);
    234     if (result == TransportResult::Success) {
    235         sensor_is_active_[static_cast<int>(sensor_type)] = false;
    236         return true;
    237     }
    238 
    239     LOGE("Could not disable sensor %d", sensor_type);
    240     return false;
    241 }
    242 
    243 bool ContextHub::DisableSensors(const std::vector<SensorSpec>& sensors) {
    244     return ForEachSensor(sensors, [this](const SensorSpec &spec) -> bool {
    245         return DisableSensor(spec.sensor_type);
    246     });
    247 }
    248 
    249 bool ContextHub::DisableAllSensors() {
    250     bool success = true;
    251 
    252     for (size_t i = 0; i < ARRAY_LEN(sensor_names_); i++) {
    253         success &= DisableSensor(sensor_names_[i].sensor_type);
    254     }
    255 
    256     return success;
    257 }
    258 
    259 bool ContextHub::DisableActiveSensors() {
    260     bool success = true;
    261 
    262     LOGD("Disabling all active sensors");
    263     for (size_t i = 0; i < ARRAY_LEN(sensor_names_); i++) {
    264         if (sensor_is_active_[static_cast<int>(sensor_names_[i].sensor_type)]) {
    265             success &= DisableSensor(sensor_names_[i].sensor_type);
    266         }
    267     }
    268 
    269     return success;
    270 }
    271 
    272 void ContextHub::PrintAllEvents(unsigned int limit) {
    273     bool continuous = (limit == 0);
    274     auto event_printer = [&limit, continuous](const SensorEvent& event) -> bool {
    275         printf("%s", event.ToString().c_str());
    276         return (continuous || --limit > 0);
    277     };
    278     ReadSensorEvents(event_printer);
    279 }
    280 
    281 bool ContextHub::PrintBridgeVersion() {
    282     BridgeVersionInfoRequest request;
    283     TransportResult result = WriteEvent(request);
    284     if (result != TransportResult::Success) {
    285         LOGE("Failed to send bridge version info request: %d",
    286              static_cast<int>(result));
    287         return false;
    288     }
    289 
    290     bool success = false;
    291     auto event_handler = [&success](const AppToHostEvent &event) -> bool {
    292         bool keep_going = true;
    293         auto rsp = reinterpret_cast<const BrHostEventData *>(event.GetDataPtr());
    294         if (event.GetAppId() != kAppIdBridge) {
    295             LOGD("Ignored event from unexpected app");
    296         } else if (event.GetDataLen() < sizeof(BrHostEventData)) {
    297             LOGE("Got short app to host event from bridge: length %u, expected "
    298                  "at least %zu", event.GetDataLen(), sizeof(BrHostEventData));
    299         } else if (rsp->msgId != BRIDGE_HOST_EVENT_MSG_VERSION_INFO) {
    300             LOGD("Ignored bridge event with unexpected message ID %u", rsp->msgId);
    301         } else if (rsp->status) {
    302             LOGE("Bridge version info request failed with status %u", rsp->status);
    303             keep_going = false;
    304         } else if (event.GetDataLen() < (sizeof(BrHostEventData) +
    305                                          sizeof(BrVersionInfoRsp))) {
    306             LOGE("Got successful version info response with short payload: "
    307                  "length %u, expected at least %zu", event.GetDataLen(),
    308                  (sizeof(BrHostEventData) + sizeof(BrVersionInfoRsp)));
    309             keep_going = false;
    310         } else {
    311             auto ver = reinterpret_cast<const struct BrVersionInfoRsp *>(
    312                 rsp->payload);
    313             printf("Bridge version info:\n"
    314                    "  HW type:         0x%04x\n"
    315                    "  OS version:      0x%04x\n"
    316                    "  Variant version: 0x%08x\n"
    317                    "  Bridge version:  0x%08x\n",
    318                    ver->hwType, ver->osVer, ver->variantVer, ver->bridgeVer);
    319             keep_going = false;
    320             success = true;
    321         }
    322 
    323         return keep_going;
    324     };
    325 
    326     ReadAppEvents(event_handler, kBridgeVersionTimeoutMs);
    327     return success;
    328 }
    329 
    330 void ContextHub::PrintSensorEvents(SensorType type, int limit) {
    331     bool continuous = (limit == 0);
    332     auto event_printer = [type, &limit, continuous](const SensorEvent& event) -> bool {
    333         SensorType event_source = event.GetSensorType();
    334         if (event_source == type || SensorTypeIsAliasOf(type, event_source)) {
    335             printf("%s", event.ToString().c_str());
    336             limit -= event.GetNumSamples();
    337         }
    338         return (continuous || limit > 0);
    339     };
    340     ReadSensorEvents(event_printer);
    341 }
    342 
    343 void ContextHub::PrintSensorEvents(const std::vector<SensorSpec>& sensors, int limit) {
    344     bool continuous = (limit == 0);
    345     auto event_printer = [&sensors, &limit, continuous](const SensorEvent& event) -> bool {
    346         SensorType event_source = event.GetSensorType();
    347         for (unsigned int i = 0; i < sensors.size(); i++) {
    348             if (sensors[i].sensor_type == event_source
    349                     || SensorTypeIsAliasOf(sensors[i].sensor_type, event_source)) {
    350                 printf("%s", event.ToString().c_str());
    351                 limit -= event.GetNumSamples();
    352                 break;
    353             }
    354         }
    355         return (continuous || limit > 0);
    356     };
    357     ReadSensorEvents(event_printer);
    358 }
    359 
    360 // Protected methods -----------------------------------------------------------
    361 
    362 bool ContextHub::CalibrateSingleSensor(const SensorSpec& sensor) {
    363     ConfigureSensorRequest req;
    364 
    365     req.config.event_type = static_cast<uint32_t>(EventType::ConfigureSensor);
    366     req.config.sensor_type = static_cast<uint8_t>(sensor.sensor_type);
    367     req.config.command = static_cast<uint8_t>(
    368         ConfigureSensorRequest::CommandType::Calibrate);
    369 
    370     LOGI("Issuing calibration request to sensor %d (%s)", sensor.sensor_type,
    371          ContextHub::SensorTypeToAbbrevName(sensor.sensor_type).c_str());
    372     auto result = WriteEvent(req);
    373     if (result != TransportResult::Success) {
    374         LOGE("Failed to calibrate sensor %d", sensor.sensor_type);
    375         return false;
    376     }
    377 
    378     bool success = false;
    379     auto cal_event_handler = [this, &sensor, &success](const AppToHostEvent &event) -> bool {
    380         if (event.IsCalibrationEventForSensor(sensor.sensor_type)) {
    381             success = HandleCalibrationResult(sensor, event);
    382             return false;
    383         }
    384         return true;
    385     };
    386 
    387     result = ReadAppEvents(cal_event_handler, kCalibrationTimeoutMs);
    388     if (result != TransportResult::Success) {
    389       LOGE("Error reading calibration response %d", static_cast<int>(result));
    390       return false;
    391     }
    392 
    393     return success;
    394 }
    395 
    396 bool ContextHub::TestSingleSensor(const SensorSpec& sensor) {
    397     ConfigureSensorRequest req;
    398 
    399     req.config.event_type = static_cast<uint32_t>(EventType::ConfigureSensor);
    400     req.config.sensor_type = static_cast<uint8_t>(sensor.sensor_type);
    401     req.config.command = static_cast<uint8_t>(
    402         ConfigureSensorRequest::CommandType::SelfTest);
    403 
    404     LOGI("Issuing test request to sensor %d (%s)", sensor.sensor_type,
    405          ContextHub::SensorTypeToAbbrevName(sensor.sensor_type).c_str());
    406     auto result = WriteEvent(req);
    407     if (result != TransportResult::Success) {
    408         LOGE("Failed to test sensor %d", sensor.sensor_type);
    409         return false;
    410     }
    411 
    412     bool success = false;
    413     auto test_event_handler = [this, &sensor, &success](const AppToHostEvent &event) -> bool {
    414         if (event.IsTestEventForSensor(sensor.sensor_type)) {
    415             success = HandleTestResult(sensor, event);
    416             return false;
    417         }
    418         return true;
    419     };
    420 
    421     result = ReadAppEvents(test_event_handler, kTestTimeoutMs);
    422     if (result != TransportResult::Success) {
    423       LOGE("Error reading test response %d", static_cast<int>(result));
    424       return false;
    425     }
    426 
    427     return success;
    428 }
    429 
    430 bool ContextHub::ForEachSensor(const std::vector<SensorSpec>& sensors,
    431         std::function<bool(const SensorSpec&)> callback) {
    432     bool success = true;
    433 
    434     for (unsigned int i = 0; success && i < sensors.size(); i++) {
    435         success &= callback(sensors[i]);
    436     }
    437 
    438     return success;
    439 }
    440 
    441 bool ContextHub::HandleCalibrationResult(const SensorSpec& sensor,
    442         const AppToHostEvent &event) {
    443     auto hdr = reinterpret_cast<const SensorAppEventHeader *>(event.GetDataPtr());
    444     if (hdr->status) {
    445         LOGE("Calibration of sensor %d (%s) failed with status %u",
    446              sensor.sensor_type,
    447              ContextHub::SensorTypeToAbbrevName(sensor.sensor_type).c_str(),
    448              hdr->status);
    449         return false;
    450     }
    451 
    452     bool success = false;
    453     switch (sensor.sensor_type) {
    454       case SensorType::Accel:
    455       case SensorType::Gyro: {
    456         auto result = reinterpret_cast<const TripleAxisCalibrationResult *>(
    457             event.GetDataPtr());
    458         success = SetCalibration(sensor.sensor_type, result->xBias,
    459                                  result->yBias, result->zBias);
    460         break;
    461       }
    462 
    463       case SensorType::Barometer: {
    464         auto result = reinterpret_cast<const FloatCalibrationResult *>(
    465             event.GetDataPtr());
    466         if (sensor.have_cal_ref) {
    467             success = SetCalibration(sensor.sensor_type,
    468                                      (sensor.cal_ref - result->value));
    469         }
    470         break;
    471       }
    472 
    473       case SensorType::Proximity: {
    474         auto result = reinterpret_cast<const FourAxisCalibrationResult *>(
    475             event.GetDataPtr());
    476         success = SetCalibration(sensor.sensor_type, result->xBias,
    477                                  result->yBias, result->zBias, result->wBias);
    478         break;
    479       }
    480 
    481       case SensorType::AmbientLightSensor: {
    482         auto result = reinterpret_cast<const FloatCalibrationResult *>(
    483             event.GetDataPtr());
    484         if (sensor.have_cal_ref && (result->value != 0.0f)) {
    485             success = SetCalibration(sensor.sensor_type,
    486                                      (sensor.cal_ref / result->value));
    487         }
    488         break;
    489       }
    490 
    491       default:
    492         LOGE("Calibration not supported for sensor type %d",
    493              static_cast<int>(sensor.sensor_type));
    494     }
    495 
    496     return success;
    497 }
    498 
    499 bool ContextHub::HandleTestResult(const SensorSpec& sensor,
    500         const AppToHostEvent &event) {
    501     auto hdr = reinterpret_cast<const SensorAppEventHeader *>(event.GetDataPtr());
    502     if (!hdr->status) {
    503         LOGI("Self-test of sensor %d (%s) succeeded",
    504              sensor.sensor_type,
    505              ContextHub::SensorTypeToAbbrevName(sensor.sensor_type).c_str());
    506         return true;
    507     } else {
    508         LOGE("Self-test of sensor %d (%s) failed with status %u",
    509              sensor.sensor_type,
    510              ContextHub::SensorTypeToAbbrevName(sensor.sensor_type).c_str(),
    511              hdr->status);
    512         return false;
    513     }
    514 }
    515 
    516 ContextHub::TransportResult ContextHub::ReadAppEvents(
    517         std::function<bool(const AppToHostEvent&)> callback, int timeout_ms) {
    518     using Milliseconds = std::chrono::milliseconds;
    519 
    520     TransportResult result;
    521     bool timeout_required = timeout_ms > 0;
    522     bool keep_going = true;
    523 
    524     while (keep_going) {
    525         if (timeout_required && timeout_ms <= 0) {
    526             return TransportResult::Timeout;
    527         }
    528 
    529         std::unique_ptr<ReadEventResponse> event;
    530 
    531         SteadyClock start_time = std::chrono::steady_clock::now();
    532         result = ReadEvent(&event, timeout_ms);
    533         SteadyClock end_time = std::chrono::steady_clock::now();
    534 
    535         auto delta = end_time - start_time;
    536         timeout_ms -= std::chrono::duration_cast<Milliseconds>(delta).count();
    537 
    538         if (result == TransportResult::Success && event->IsAppToHostEvent()) {
    539             AppToHostEvent *app_event = reinterpret_cast<AppToHostEvent*>(
    540                 event.get());
    541             keep_going = callback(*app_event);
    542         } else {
    543             if (result != TransportResult::Success) {
    544                 LOGE("Error %d while reading", static_cast<int>(result));
    545                 if (result != TransportResult::ParseFailure) {
    546                     return result;
    547                 }
    548             } else {
    549                 LOGD("Ignoring non-app-to-host event");
    550             }
    551         }
    552     }
    553 
    554     return TransportResult::Success;
    555 }
    556 
    557 void ContextHub::ReadSensorEvents(std::function<bool(const SensorEvent&)> callback) {
    558     TransportResult result;
    559     bool keep_going = true;
    560 
    561     while (keep_going) {
    562         std::unique_ptr<ReadEventResponse> event;
    563         result = ReadEvent(&event);
    564         if (result == TransportResult::Success && event->IsSensorEvent()) {
    565             SensorEvent *sensor_event = reinterpret_cast<SensorEvent*>(
    566                 event.get());
    567             keep_going = callback(*sensor_event);
    568         } else {
    569             if (result != TransportResult::Success) {
    570                 LOGE("Error %d while reading", static_cast<int>(result));
    571                 if (result != TransportResult::ParseFailure) {
    572                     break;
    573                 }
    574             } else {
    575                 LOGD("Ignoring non-sensor event");
    576             }
    577         }
    578     }
    579 }
    580 
    581 bool ContextHub::SendCalibrationData(SensorType sensor_type,
    582         const std::vector<uint8_t>& cal_data) {
    583     ConfigureSensorRequest req;
    584 
    585     req.config.event_type = static_cast<uint32_t>(EventType::ConfigureSensor);
    586     req.config.sensor_type = static_cast<uint8_t>(sensor_type);
    587     req.config.command = static_cast<uint8_t>(
    588         ConfigureSensorRequest::CommandType::ConfigData);
    589     req.SetAdditionalData(cal_data);
    590 
    591     auto result = WriteEvent(req);
    592     return (result == TransportResult::Success);
    593 }
    594 
    595 ContextHub::TransportResult ContextHub::WriteEvent(
    596         const WriteEventRequest& request) {
    597     return WriteEvent(request.GetBytes());
    598 }
    599 
    600 ContextHub::TransportResult ContextHub::ReadEvent(
    601         std::unique_ptr<ReadEventResponse>* response, int timeout_ms) {
    602     std::vector<uint8_t> responseBuf(256);
    603     ContextHub::TransportResult result = ReadEvent(responseBuf, timeout_ms);
    604     if (result == TransportResult::Success) {
    605         *response = ReadEventResponse::FromBytes(responseBuf);
    606         if (*response == nullptr) {
    607             result = TransportResult::ParseFailure;
    608         }
    609     }
    610     return result;
    611 }
    612 
    613 // Stubs for subclasses that don't implement calibration support
    614 bool ContextHub::LoadCalibration() {
    615     LOGE("Loading calibration data not implemented");
    616     return false;
    617 }
    618 
    619 bool ContextHub::SetCalibration(SensorType sensor_type, int32_t data) {
    620     UNUSED_PARAM(sensor_type);
    621     UNUSED_PARAM(data);
    622     return false;
    623 }
    624 
    625 bool ContextHub::SetCalibration(SensorType sensor_type, float data) {
    626     UNUSED_PARAM(sensor_type);
    627     UNUSED_PARAM(data);
    628     return false;
    629 }
    630 
    631 bool ContextHub::SetCalibration(SensorType sensor_type, int32_t x,
    632         int32_t y, int32_t z) {
    633     UNUSED_PARAM(sensor_type);
    634     UNUSED_PARAM(x);
    635     UNUSED_PARAM(y);
    636     UNUSED_PARAM(z);
    637     return false;
    638 }
    639 
    640 bool ContextHub::SetCalibration(SensorType sensor_type, int32_t x,
    641         int32_t y, int32_t z, int32_t w) {
    642     UNUSED_PARAM(sensor_type);
    643     UNUSED_PARAM(x);
    644     UNUSED_PARAM(y);
    645     UNUSED_PARAM(z);
    646     UNUSED_PARAM(w);
    647     return false;
    648 }
    649 
    650 bool ContextHub::SaveCalibration() {
    651     LOGE("Saving calibration data not implemented");
    652     return false;
    653 }
    654 
    655 }  // namespace android
    656