Home | History | Annotate | Download | only in libsensors_iio
      1 /*
      2  * Copyright (C) 2014 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 #define LOG_NDEBUG 0
     18 
     19 #include <fcntl.h>
     20 #include <errno.h>
     21 #include <math.h>
     22 #include <unistd.h>
     23 #include <dirent.h>
     24 #include <sys/select.h>
     25 #include <cutils/log.h>
     26 #include <linux/input.h>
     27 #include <string.h>
     28 
     29 #include "CompassSensor.IIO.9150.h"
     30 #include "sensors.h"
     31 #include "MPLSupport.h"
     32 #include "sensor_params.h"
     33 #include "ml_sysfs_helper.h"
     34 
     35 #define COMPASS_MAX_SYSFS_ATTRB sizeof(compassSysFs) / sizeof(char*)
     36 #define COMPASS_NAME "USE_SYSFS"
     37 
     38 #if defined COMPASS_YAS53x
     39 #pragma message("HAL:build Invensense compass cal with YAS53x IIO on secondary bus")
     40 #define USE_MPL_COMPASS_HAL (1)
     41 #define COMPASS_NAME        "INV_YAS530"
     42 
     43 #elif defined COMPASS_AK8975
     44 #pragma message("HAL:build Invensense compass cal with AK8975 on primary bus")
     45 #define USE_MPL_COMPASS_HAL (1)
     46 #define COMPASS_NAME        "INV_AK8975"
     47 
     48 #elif defined INVENSENSE_COMPASS_CAL
     49 #   define COMPASS_NAME                 "USE_SYSFS"
     50 #pragma message("HAL:build Invensense compass cal with compass IIO on secondary bus")
     51 #define USE_MPL_COMPASS_HAL (1)
     52 #else
     53 #pragma message("HAL:build third party compass cal HAL")
     54 #define USE_MPL_COMPASS_HAL (0)
     55 // TODO: change to vendor's name
     56 #define COMPASS_NAME        "AKM8975"
     57 
     58 #endif
     59 
     60 /*****************************************************************************/
     61 
     62 CompassSensor::CompassSensor()
     63                   : SensorBase(NULL, NULL),
     64                     compass_fd(-1),
     65                     mCompassTimestamp(0),
     66                     mCompassInputReader(8)
     67 {
     68     VFUNC_LOG;
     69 
     70     if(!strcmp(COMPASS_NAME, "USE_SYSFS")) {
     71         int result = find_name_by_sensor_type("in_magn_scale", "iio:device",
     72                                               sensor_name);
     73         if(result) {
     74             LOGE("HAL:Cannot read secondary device name - (%d)", result);
     75         }
     76         dev_name = sensor_name;
     77     }
     78     LOGI_IF(PROCESS_VERBOSE, "HAL:Secondary Chip Id: %s", dev_name);
     79 
     80     if(inv_init_sysfs_attributes()) {
     81         LOGE("Error Instantiating Compass\n");
     82         return;
     83     }
     84 
     85     memset(mCachedCompassData, 0, sizeof(mCachedCompassData));
     86 
     87     LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:cat %s (%lld)",
     88             compassSysFs.compass_orient, getTimestamp());
     89     FILE *fptr;
     90     fptr = fopen(compassSysFs.compass_orient, "r");
     91     if (fptr != NULL) {
     92         int om[9];
     93         if (fscanf(fptr, "%d,%d,%d,%d,%d,%d,%d,%d,%d",
     94                &om[0], &om[1], &om[2], &om[3], &om[4], &om[5],
     95                &om[6], &om[7], &om[8]) < 0 || fclose(fptr) < 0) {
     96             LOGE("HAL:Could not read compass mounting matrix");
     97         } else {
     98             LOGV_IF(EXTRA_VERBOSE, "HAL:compass mounting matrix: "
     99                     "%+d %+d %+d %+d %+d %+d %+d %+d %+d", om[0], om[1], om[2],
    100                     om[3], om[4], om[5], om[6], om[7], om[8]);
    101             mCompassOrientation[0] = om[0];
    102             mCompassOrientation[1] = om[1];
    103             mCompassOrientation[2] = om[2];
    104             mCompassOrientation[3] = om[3];
    105             mCompassOrientation[4] = om[4];
    106             mCompassOrientation[5] = om[5];
    107             mCompassOrientation[6] = om[6];
    108             mCompassOrientation[7] = om[7];
    109             mCompassOrientation[8] = om[8];
    110         }
    111     }
    112 
    113     if (!isIntegrated()) {
    114         enable(ID_M, 0);
    115     }
    116 }
    117 
    118 CompassSensor::~CompassSensor()
    119 {
    120     VFUNC_LOG;
    121     free(pathP);
    122     if( compass_fd > 0)
    123         close(compass_fd);
    124 }
    125 
    126 int CompassSensor::getFd() const
    127 {
    128     VFUNC_LOG;
    129     return compass_fd;
    130 }
    131 
    132 /**
    133  *  @brief        This function will enable/disable sensor.
    134  *  @param[in]    handle
    135  *                  which sensor to enable/disable.
    136  *  @param[in]    en
    137  *                  en=1, enable;
    138  *                  en=0, disable
    139  *  @return       if the operation is successful.
    140  */
    141 int CompassSensor::enable(int32_t handle, int en)
    142 {
    143     VFUNC_LOG;
    144     int res = 0;
    145     LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)",
    146             en, compassSysFs.compass_enable, getTimestamp());
    147     res = write_sysfs_int(compassSysFs.compass_enable, en);
    148     return res;
    149 }
    150 
    151 int CompassSensor::setDelay(int32_t handle, int64_t ns)
    152 {
    153     VFUNC_LOG;
    154     int tempFd;
    155     int res;
    156 
    157     LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %.0f > %s (%lld)",
    158             1000000000.f / ns, compassSysFs.compass_rate, getTimestamp());
    159     mDelay = ns;
    160     if (ns == 0)
    161         return -1;
    162     tempFd = open(compassSysFs.compass_rate, O_RDWR);
    163     res = write_attribute_sensor(tempFd, 1000000000.f / ns);
    164     if(res < 0) {
    165         LOGE("HAL:Compass update delay error");
    166     }
    167     return res;
    168 }
    169 
    170 int CompassSensor::turnOffCompassFifo(void)
    171 {
    172     int i, res = 0, tempFd;
    173     LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)",
    174                         0, compassSysFs.compass_fifo_enable, getTimestamp());
    175     res += write_sysfs_int(compassSysFs.compass_fifo_enable, 0);
    176     return res;
    177 }
    178 
    179 int CompassSensor::turnOnCompassFifo(void)
    180 {
    181     int i, res = 0, tempFd;
    182     LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)",
    183                         1, compassSysFs.compass_fifo_enable, getTimestamp());
    184     res += write_sysfs_int(compassSysFs.compass_fifo_enable, 1);
    185     return res;
    186 }
    187 
    188 /**
    189     @brief      This function will return the state of the sensor.
    190     @return     1=enabled; 0=disabled
    191 **/
    192 int CompassSensor::getEnable(int32_t handle)
    193 {
    194     VFUNC_LOG;
    195     return mEnable;
    196 }
    197 
    198 /* use for Invensense compass calibration */
    199 #define COMPASS_EVENT_DEBUG (0)
    200 void CompassSensor::processCompassEvent(const input_event *event)
    201 {
    202     VHANDLER_LOG;
    203 
    204     switch (event->code) {
    205     case EVENT_TYPE_ICOMPASS_X:
    206         LOGV_IF(COMPASS_EVENT_DEBUG, "EVENT_TYPE_ICOMPASS_X\n");
    207         mCachedCompassData[0] = event->value;
    208         break;
    209     case EVENT_TYPE_ICOMPASS_Y:
    210         LOGV_IF(COMPASS_EVENT_DEBUG, "EVENT_TYPE_ICOMPASS_Y\n");
    211         mCachedCompassData[1] = event->value;
    212         break;
    213     case EVENT_TYPE_ICOMPASS_Z:
    214         LOGV_IF(COMPASS_EVENT_DEBUG, "EVENT_TYPE_ICOMPASS_Z\n");
    215         mCachedCompassData[2] = event->value;
    216         break;
    217     }
    218 
    219     mCompassTimestamp =
    220         (int64_t)event->time.tv_sec * 1000000000L + event->time.tv_usec * 1000L;
    221 }
    222 
    223 void CompassSensor::getOrientationMatrix(signed char *orient)
    224 {
    225     VFUNC_LOG;
    226     memcpy(orient, mCompassOrientation, sizeof(mCompassOrientation));
    227 }
    228 
    229 long CompassSensor::getSensitivity()
    230 {
    231     VFUNC_LOG;
    232 
    233     long sensitivity;
    234     LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:cat %s (%lld)",
    235             compassSysFs.compass_scale, getTimestamp());
    236     inv_read_data(compassSysFs.compass_scale, &sensitivity);
    237     return sensitivity;
    238 }
    239 
    240 /**
    241     @brief         This function is called by sensors_mpl.cpp
    242                    to read sensor data from the driver.
    243     @param[out]    data      sensor data is stored in this variable. Scaled such that
    244                              1 uT = 2^16
    245     @para[in]      timestamp data's timestamp
    246     @return        1, if 1   sample read, 0, if not, negative if error
    247  */
    248 int CompassSensor::readSample(long *data, int64_t *timestamp)
    249 {
    250     VHANDLER_LOG;
    251 
    252     int numEventReceived = 0, done = 0;
    253 
    254     ssize_t n = mCompassInputReader.fill(compass_fd);
    255     if (n < 0) {
    256         LOGE("HAL:no compass events read");
    257         return n;
    258     }
    259 
    260     input_event const* event;
    261 
    262     while (done == 0 && mCompassInputReader.readEvent(&event)) {
    263         int type = event->type;
    264         if (type == EV_REL) {
    265             processCompassEvent(event);
    266         } else if (type == EV_SYN) {
    267             *timestamp = mCompassTimestamp;
    268             memcpy(data, mCachedCompassData, sizeof(mCachedCompassData));
    269             done = 1;
    270         } else {
    271             LOGE("HAL:Compass Sensor: unknown event (type=%d, code=%d)",
    272                  type, event->code);
    273         }
    274         mCompassInputReader.next();
    275     }
    276 
    277     return done;
    278 }
    279 
    280 /**
    281  *  @brief  This function will return the current delay for this sensor.
    282  *  @return delay in nanoseconds.
    283  */
    284 int64_t CompassSensor::getDelay(int32_t handle)
    285 {
    286     VFUNC_LOG;
    287     return mDelay;
    288 }
    289 
    290 void CompassSensor::fillList(struct sensor_t *list)
    291 {
    292     VFUNC_LOG;
    293 
    294     const char *compass = sensor_name;
    295 
    296     if (compass) {
    297         if(!strcmp(compass, "INV_COMPASS")) {
    298             list->maxRange = COMPASS_MPU9150_RANGE;
    299             list->resolution = COMPASS_MPU9150_RESOLUTION;
    300             list->power = COMPASS_MPU9150_POWER;
    301             list->minDelay = COMPASS_MPU9150_MINDELAY;
    302             return;
    303         }
    304         if(!strcmp(compass, "compass")
    305                 || !strcmp(compass, "INV_AK8975")
    306                 || !strcmp(compass, "AK8975")
    307                 || !strcmp(compass, "ak8975")) {
    308             list->maxRange = COMPASS_AKM8975_RANGE;
    309             list->resolution = COMPASS_AKM8975_RESOLUTION;
    310             list->power = COMPASS_AKM8975_POWER;
    311             list->minDelay = COMPASS_AKM8975_MINDELAY;
    312             return;
    313         }
    314         if(!strcmp(compass, "compass")
    315                 || !strcmp(compass, "INV_AK8963")
    316                 || !strcmp(compass, "AK8963")
    317                 || !strcmp(compass, "ak8963")) {
    318             list->maxRange = COMPASS_AKM8963_RANGE;
    319             list->resolution = COMPASS_AKM8963_RESOLUTION;
    320             list->power = COMPASS_AKM8963_POWER;
    321             list->minDelay = COMPASS_AKM8963_MINDELAY;
    322             return;
    323         }
    324         if(!strcmp(compass, "compass")
    325                 || !strcmp(compass, "INV_AK09911")
    326                 || !strcmp(compass, "AK09911")
    327                 || !strcmp(compass, "ak09911")) {
    328             list->maxRange = COMPASS_AKM9911_RANGE;
    329             list->resolution = COMPASS_AKM9911_RESOLUTION;
    330             list->power = COMPASS_AKM9911_POWER;
    331             list->minDelay = COMPASS_AKM9911_MINDELAY;
    332             return;
    333         }
    334         if(!strcmp(compass, "compass")
    335                 || !strcmp(compass, "INV_AK09912")
    336                 || !strcmp(compass, "AK09912")
    337                 || !strcmp(compass, "ak09912")) {
    338             list->maxRange = COMPASS_AKM9912_RANGE;
    339             list->resolution = COMPASS_AKM9912_RESOLUTION;
    340             list->power = COMPASS_AKM9912_POWER;
    341             list->minDelay = COMPASS_AKM9912_MINDELAY;
    342             return;
    343         }
    344         if(!strcmp(compass, "compass")
    345                 || !strncmp(compass, "mlx90399",3)
    346                 || !strncmp(compass, "MLX90399",3)) {
    347             list->maxRange = COMPASS_MPU9350_RANGE;
    348             list->resolution = COMPASS_MPU9350_RESOLUTION;
    349             list->power = COMPASS_MPU9350_POWER;
    350             list->minDelay = COMPASS_MPU9350_MINDELAY;
    351             return;
    352         }
    353         if(!strcmp(compass, "INV_YAS530")) {
    354             list->maxRange = COMPASS_YAS53x_RANGE;
    355             list->resolution = COMPASS_YAS53x_RESOLUTION;
    356             list->power = COMPASS_YAS53x_POWER;
    357             list->minDelay = COMPASS_YAS53x_MINDELAY;
    358             return;
    359         }
    360         if(!strcmp(compass, "INV_AMI306")) {
    361             list->maxRange = COMPASS_AMI306_RANGE;
    362             list->resolution = COMPASS_AMI306_RESOLUTION;
    363             list->power = COMPASS_AMI306_POWER;
    364             list->minDelay = COMPASS_AMI306_MINDELAY;
    365             return;
    366         }
    367     }
    368     LOGE("HAL:unknown compass id %s -- "
    369          "params default to ak8975 and might be wrong.",
    370          compass);
    371     list->maxRange = COMPASS_AKM8975_RANGE;
    372     list->resolution = COMPASS_AKM8975_RESOLUTION;
    373     list->power = COMPASS_AKM8975_POWER;
    374     list->minDelay = COMPASS_AKM8975_MINDELAY;
    375 }
    376 
    377 int CompassSensor::inv_init_sysfs_attributes(void)
    378 {
    379     VFUNC_LOG;
    380 
    381     char sysfs_path[MAX_SYSFS_NAME_LEN];
    382     char iio_trigger_path[MAX_SYSFS_NAME_LEN];
    383 
    384     pathP = (char*)calloc(COMPASS_MAX_SYSFS_ATTRB,
    385                           sizeof(char[MAX_SYSFS_NAME_LEN]));
    386     if (pathP == NULL)
    387         return -1;
    388 
    389     memset(sysfs_path, 0, sizeof(sysfs_path));
    390     memset(iio_trigger_path, 0, sizeof(iio_trigger_path));
    391 
    392     char *sptr = pathP;
    393     char **dptr = reinterpret_cast<char **>(&compassSysFs);
    394     for (size_t i = 0; i < COMPASS_MAX_SYSFS_ATTRB; i++) {
    395       *dptr++ = sptr;
    396       sptr += sizeof(char[MAX_SYSFS_NAME_LEN]);
    397     }
    398 
    399     // get proper (in absolute/relative) IIO path & build MPU's sysfs paths
    400     // inv_get_sysfs_abs_path(sysfs_path);
    401     inv_get_sysfs_path(sysfs_path);
    402     inv_get_iio_trigger_path(iio_trigger_path);
    403 
    404 #if defined COMPASS_AK8975
    405     char tbuf[2];
    406     int num;
    407 
    408     inv_get_input_number(dev_name, &num);
    409     tbuf[0] = num + 0x30;
    410     tbuf[1] = 0;
    411     sprintf(sysfs_path, "%s%s", "sys/class/input/input", tbuf);
    412     strcat(sysfs_path, "/ak8975");
    413 
    414     sprintf(compassSysFs.compass_enable, "%s%s", sysfs_path, "/enable");
    415     sprintf(compassSysFs.compass_rate, "%s%s", sysfs_path, "/rate");
    416     sprintf(compassSysFs.compass_scale, "%s%s", sysfs_path, "/scale");
    417     sprintf(compassSysFs.compass_orient, "%s%s", sysfs_path, "/compass_matrix");
    418 #else
    419     sprintf(compassSysFs.compass_enable, "%s%s", sysfs_path, "/compass_enable");
    420     sprintf(compassSysFs.compass_fifo_enable, "%s%s", sysfs_path, "/compass_fifo_enable");
    421     sprintf(compassSysFs.compass_rate, "%s%s", sysfs_path, "/compass_rate");
    422     sprintf(compassSysFs.compass_scale, "%s%s", sysfs_path, "/in_magn_scale");
    423     sprintf(compassSysFs.compass_orient, "%s%s", sysfs_path, "/compass_matrix");
    424 #endif
    425 
    426     return 0;
    427 }
    428