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 "androidcontexthub.h"
     18 
     19 #include <errno.h>
     20 #include <fcntl.h>
     21 #include <poll.h>
     22 #include <time.h>
     23 #include <unistd.h>
     24 #include <sys/stat.h>
     25 
     26 #include <chrono>
     27 #include <cstdint>
     28 #include <cstdio>
     29 #include <cstring>
     30 #include <thread>
     31 #include <vector>
     32 
     33 #include "calibrationfile.h"
     34 #include "log.h"
     35 
     36 namespace android {
     37 
     38 constexpr char kSensorDeviceFile[] = "/dev/nanohub";
     39 constexpr char kCommsDeviceFile[] = "/dev/nanohub_comms";
     40 constexpr char kLockDirectory[] = "/data/vendor/sensor/nanohub_lock";
     41 constexpr char kLockFile[] = "/data/vendor/sensor/nanohub_lock/lock";
     42 
     43 constexpr mode_t kLockDirPermissions = (S_IRUSR | S_IWUSR | S_IXUSR);
     44 
     45 constexpr auto kLockDelay = std::chrono::milliseconds(100);
     46 
     47 constexpr int kDeviceFileCount = 2;
     48 constexpr int kPollNoTimeout = -1;
     49 
     50 static const std::vector<std::tuple<const char *, SensorType>> kCalibrationKeys = {
     51     std::make_tuple("accel",     SensorType::Accel),
     52     std::make_tuple("gyro",      SensorType::Gyro),
     53     std::make_tuple("mag",       SensorType::Magnetometer),
     54     std::make_tuple("proximity", SensorType::Proximity),
     55     std::make_tuple("barometer", SensorType::Barometer),
     56     std::make_tuple("light",     SensorType::AmbientLightSensor),
     57 };
     58 
     59 static void AppendBytes(const void *data, size_t length, std::vector<uint8_t>& buffer) {
     60     const uint8_t *bytes = (const uint8_t *) data;
     61     for (size_t i = 0; i < length; i++) {
     62         buffer.push_back(bytes[i]);
     63     }
     64 }
     65 
     66 static bool CopyInt32Array(const char *key,
     67         sp<JSONObject> json, std::vector<uint8_t>& bytes) {
     68     sp<JSONArray> array;
     69     if (json->getArray(key, &array)) {
     70         for (size_t i = 0; i < array->size(); i++) {
     71             int32_t val = 0;
     72             array->getInt32(i, &val);
     73             AppendBytes(&val, sizeof(uint32_t), bytes);
     74         }
     75 
     76         return true;
     77     }
     78     return false;
     79 }
     80 
     81 static bool CopyFloatArray(const char *key,
     82         sp<JSONObject> json, std::vector<uint8_t>& bytes) {
     83     sp<JSONArray> array;
     84     if (json->getArray(key, &array)) {
     85         for (size_t i = 0; i < array->size(); i++) {
     86             float val = 0;
     87             array->getFloat(i, &val);
     88             AppendBytes(&val, sizeof(float), bytes);
     89         }
     90 
     91         return true;
     92     }
     93     return false;
     94 }
     95 
     96 static bool GetCalibrationBytes(const char *key, SensorType sensor_type,
     97         std::vector<uint8_t>& bytes) {
     98     bool success = true;
     99     std::shared_ptr<CalibrationFile> cal_file = CalibrationFile::Instance();
    100     if (!cal_file) {
    101         return false;
    102     }
    103     auto json = cal_file->GetJSONObject();
    104 
    105     switch (sensor_type) {
    106       case SensorType::Accel:
    107       case SensorType::Gyro:
    108         success = CopyInt32Array(key, json, bytes);
    109         break;
    110 
    111       case SensorType::Magnetometer:
    112         success = CopyFloatArray(key, json, bytes);
    113         break;
    114 
    115       case SensorType::AmbientLightSensor:
    116       case SensorType::Barometer: {
    117         float value = 0;
    118         success = json->getFloat(key, &value);
    119         if (success) {
    120             AppendBytes(&value, sizeof(float), bytes);
    121         }
    122         break;
    123       }
    124 
    125       case SensorType::Proximity: {
    126         // Proximity might be an int32 array with 4 values (CRGB) or a single
    127         // int32 value - try both
    128         success = CopyInt32Array(key, json, bytes);
    129         if (!success) {
    130             int32_t value = 0;
    131             success = json->getInt32(key, &value);
    132             if (success) {
    133                 AppendBytes(&value, sizeof(int32_t), bytes);
    134             }
    135         }
    136         break;
    137       }
    138 
    139       default:
    140         // If this log message gets printed, code needs to be added in this
    141         // switch statement
    142         LOGE("Missing sensor type to calibration data mapping sensor %d",
    143              static_cast<int>(sensor_type));
    144         success = false;
    145     }
    146 
    147     return success;
    148 }
    149 
    150 AndroidContextHub::~AndroidContextHub() {
    151     if (unlink(kLockFile) < 0) {
    152         LOGE("Couldn't remove lock file: %s", strerror(errno));
    153     }
    154     if (sensor_fd_ >= 0) {
    155         DisableActiveSensors();
    156         (void) close(sensor_fd_);
    157     }
    158     if (comms_fd_ >= 0) {
    159         (void) close(comms_fd_);
    160     }
    161 }
    162 
    163 void AndroidContextHub::TerminateHandler() {
    164     (void) unlink(kLockFile);
    165 }
    166 
    167 bool AndroidContextHub::Initialize() {
    168     // Acquire a lock on nanohub, so the HAL read threads won't take our events.
    169     // We need to delay after creating the file to have good confidence that
    170     // the HALs noticed the lock file creation.
    171     if (access(kLockDirectory, F_OK) < 0) {
    172         if (mkdir(kLockDirectory, kLockDirPermissions) < 0 && errno != EEXIST) {
    173             LOGE("Couldn't create lock directory: %s", strerror(errno));
    174         }
    175     }
    176     int lock_fd = open(kLockFile, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
    177     if (lock_fd < 0) {
    178         LOGE("Couldn't create lock file: %s", strerror(errno));
    179         if (errno != EEXIST) {
    180             return false;
    181         }
    182     } else {
    183         close(lock_fd);
    184         std::this_thread::sleep_for(kLockDelay);
    185         LOGD("Lock sleep complete");
    186     }
    187 
    188     // Sensor device file is used for sensor requests, e.g. configure, etc., and
    189     // returns sensor events
    190     sensor_fd_ = open(kSensorDeviceFile, O_RDWR);
    191     if (sensor_fd_ < 0) {
    192         LOGE("Couldn't open device file: %s", strerror(errno));
    193         return false;
    194     }
    195 
    196     // The comms device file is used for more generic communication with
    197     // nanoapps. Calibration results are returned through this channel.
    198     comms_fd_ = open(kCommsDeviceFile, O_RDONLY);
    199     if (comms_fd_ < 0) {
    200         // TODO(bduddie): Currently informational only, as the kernel change
    201         // that adds this device file is not available/propagated yet.
    202         // Eventually this should be an error.
    203         LOGI("Couldn't open comms device file: %s", strerror(errno));
    204     }
    205 
    206     return true;
    207 }
    208 
    209 void AndroidContextHub::SetLoggingEnabled(bool logging_enabled) {
    210     if (logging_enabled) {
    211         LOGE("Logging is not supported on this platform");
    212     }
    213 }
    214 
    215 ContextHub::TransportResult AndroidContextHub::WriteEvent(
    216         const std::vector<uint8_t>& message) {
    217     ContextHub::TransportResult result;
    218 
    219     LOGD("Writing %zu bytes", message.size());
    220     LOGD_BUF(message.data(), message.size());
    221     int ret = write(sensor_fd_, message.data(), message.size());
    222     if (ret == -1) {
    223         LOGE("Couldn't write %zu bytes to device file: %s", message.size(),
    224              strerror(errno));
    225         result = TransportResult::GeneralFailure;
    226     } else if (ret != (int) message.size()) {
    227         LOGW("Write returned %d, expected %zu", ret, message.size());
    228         result = TransportResult::GeneralFailure;
    229     } else {
    230         LOGD("Successfully sent event");
    231         result = TransportResult::Success;
    232     }
    233 
    234     return result;
    235 }
    236 
    237 ContextHub::TransportResult AndroidContextHub::ReadEvent(
    238         std::vector<uint8_t>& message, int timeout_ms) {
    239     ContextHub::TransportResult result = TransportResult::GeneralFailure;
    240 
    241     struct pollfd pollfds[kDeviceFileCount];
    242     int fd_count = ResetPollFds(pollfds, kDeviceFileCount);
    243 
    244     int timeout = timeout_ms > 0 ? timeout_ms : kPollNoTimeout;
    245     int ret = poll(pollfds, fd_count, timeout);
    246     if (ret < 0) {
    247         LOGE("Polling failed: %s", strerror(errno));
    248         if (errno == EINTR) {
    249             result = TransportResult::Canceled;
    250         }
    251     } else if (ret == 0) {
    252         LOGD("Poll timed out");
    253         result = TransportResult::Timeout;
    254     } else {
    255         int read_fd = -1;
    256         for (int i = 0; i < kDeviceFileCount; i++) {
    257             if (pollfds[i].revents & POLLIN) {
    258                 read_fd = pollfds[i].fd;
    259                 break;
    260             }
    261         }
    262 
    263         if (read_fd == sensor_fd_) {
    264             LOGD("Data ready on sensors device file");
    265         } else if (read_fd == comms_fd_) {
    266             LOGD("Data ready on comms device file");
    267         }
    268 
    269         if (read_fd >= 0) {
    270             result = ReadEventFromFd(read_fd, message);
    271         } else {
    272             LOGE("Poll returned but none of expected files are ready");
    273         }
    274     }
    275 
    276     return result;
    277 }
    278 
    279 bool AndroidContextHub::FlashSensorHub(const std::vector<uint8_t>& bytes) {
    280     (void)bytes;
    281     LOGE("Flashing is not supported on this platform");
    282     return false;
    283 }
    284 
    285 bool AndroidContextHub::LoadCalibration() {
    286     std::vector<uint8_t> cal_data;
    287     bool success = true;
    288 
    289     for (size_t i = 0; success && i < kCalibrationKeys.size(); i++) {
    290         std::string key;
    291         SensorType sensor_type;
    292 
    293         std::tie(key, sensor_type) = kCalibrationKeys[i];
    294         if (GetCalibrationBytes(key.c_str(), sensor_type, cal_data)) {
    295             success = SendCalibrationData(sensor_type, cal_data);
    296         }
    297 
    298         cal_data.clear();
    299     }
    300 
    301     return success;
    302 }
    303 
    304 bool AndroidContextHub::SetCalibration(SensorType sensor_type, int32_t data) {
    305     LOGI("Setting calibration for sensor %d (%s) to %d",
    306          static_cast<int>(sensor_type),
    307          ContextHub::SensorTypeToAbbrevName(sensor_type).c_str(), data);
    308     auto cal_file = CalibrationFile::Instance();
    309     const char *key = AndroidContextHub::SensorTypeToCalibrationKey(sensor_type);
    310     if (cal_file && key) {
    311         return cal_file->SetSingleAxis(key, data);
    312     }
    313     return false;
    314 }
    315 
    316 bool AndroidContextHub::SetCalibration(SensorType sensor_type, float data) {
    317     LOGI("Setting calibration for sensor %d (%s) to %f",
    318          static_cast<int>(sensor_type),
    319          ContextHub::SensorTypeToAbbrevName(sensor_type).c_str(), data);
    320     auto cal_file = CalibrationFile::Instance();
    321     const char *key = AndroidContextHub::SensorTypeToCalibrationKey(sensor_type);
    322     if (cal_file && key) {
    323         return cal_file->SetSingleAxis(key, data);
    324     }
    325     return false;
    326 }
    327 
    328 bool AndroidContextHub::SetCalibration(SensorType sensor_type, int32_t x,
    329         int32_t y, int32_t z) {
    330     LOGI("Setting calibration for %d to %d %d %d", static_cast<int>(sensor_type),
    331          x, y, z);
    332     auto cal_file = CalibrationFile::Instance();
    333     const char *key = AndroidContextHub::SensorTypeToCalibrationKey(sensor_type);
    334     if (cal_file && key) {
    335         return cal_file->SetTripleAxis(key, x, y, z);
    336     }
    337     return false;
    338 }
    339 
    340 bool AndroidContextHub::SetCalibration(SensorType sensor_type, int32_t x,
    341         int32_t y, int32_t z, int32_t w) {
    342     LOGI("Setting calibration for %d to %d %d %d %d", static_cast<int>(sensor_type),
    343          x, y, z, w);
    344     auto cal_file = CalibrationFile::Instance();
    345     const char *key = AndroidContextHub::SensorTypeToCalibrationKey(sensor_type);
    346     if (cal_file && key) {
    347         return cal_file->SetFourAxis(key, x, y, z, w);
    348     }
    349     return false;
    350 }
    351 
    352 bool AndroidContextHub::SaveCalibration() {
    353     LOGI("Saving calibration data");
    354     auto cal_file = CalibrationFile::Instance();
    355     if (cal_file) {
    356         return cal_file->Save();
    357     }
    358     return false;
    359 }
    360 
    361 ContextHub::TransportResult AndroidContextHub::ReadEventFromFd(
    362         int fd, std::vector<uint8_t>& message) {
    363     ContextHub::TransportResult result = TransportResult::GeneralFailure;
    364 
    365     // Set the size to the maximum, so when we resize later, it's always a
    366     // shrink (otherwise it will end up clearing the bytes)
    367     message.resize(message.capacity());
    368 
    369     LOGD("Calling into read()");
    370     int ret = read(fd, message.data(), message.capacity());
    371     if (ret < 0) {
    372         LOGE("Couldn't read from device file: %s", strerror(errno));
    373         if (errno == EINTR) {
    374             result = TransportResult::Canceled;
    375         }
    376     } else if (ret == 0) {
    377         // We might need to handle this specially, if the driver implements this
    378         // to mean something specific
    379         LOGE("Read unexpectedly returned 0 bytes");
    380     } else {
    381         message.resize(ret);
    382         LOGD_VEC(message);
    383         result = TransportResult::Success;
    384     }
    385 
    386     return result;
    387 }
    388 
    389 int AndroidContextHub::ResetPollFds(struct pollfd *pfds, size_t count) {
    390     memset(pfds, 0, sizeof(struct pollfd) * count);
    391     pfds[0].fd = sensor_fd_;
    392     pfds[0].events = POLLIN;
    393 
    394     int nfds = 1;
    395     if (count > 1 && comms_fd_ >= 0) {
    396         pfds[1].fd = comms_fd_;
    397         pfds[1].events = POLLIN;
    398         nfds++;
    399     }
    400     return nfds;
    401 }
    402 
    403 const char *AndroidContextHub::SensorTypeToCalibrationKey(SensorType sensor_type) {
    404     for (size_t i = 0; i < kCalibrationKeys.size(); i++) {
    405         const char *key;
    406         SensorType sensor_type_for_key;
    407 
    408         std::tie(key, sensor_type_for_key) = kCalibrationKeys[i];
    409         if (sensor_type == sensor_type_for_key) {
    410             return key;
    411         }
    412     }
    413 
    414     LOGE("No calibration key mapping for sensor type %d",
    415          static_cast<int>(sensor_type));
    416     return nullptr;
    417 }
    418 
    419 }  // namespace android
    420