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