Home | History | Annotate | Download | only in libsensors_iio
      1 /*
      2  * Copyright (C) 2012 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", sensor_name);
     72         if(result) {
     73             LOGE("HAL:Cannot read secondary device name - (%d)", result);
     74         }
     75         dev_name = sensor_name;
     76     }
     77     LOGI("HAL:Secondary Chip Id: %s", dev_name);
     78 
     79     if(inv_init_sysfs_attributes()) {
     80         LOGE("Error Instantiating Compass\n");
     81         return;
     82     }
     83 
     84     /*if (!strcmp(COMPASS_NAME, "INV_COMPASS")) {
     85         mI2CBus = COMPASS_BUS_SECONDARY;
     86     } else {
     87         mI2CBus = COMPASS_BUS_PRIMARY;
     88     }*/
     89 
     90     memset(mCachedCompassData, 0, sizeof(mCachedCompassData));
     91 
     92     LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:cat %s (%lld)",
     93             compassSysFs.compass_orient, getTimestamp());
     94     FILE *fptr;
     95     fptr = fopen(compassSysFs.compass_orient, "r");
     96     if (fptr != NULL) {
     97         int om[9];
     98         fscanf(fptr, "%d,%d,%d,%d,%d,%d,%d,%d,%d",
     99                &om[0], &om[1], &om[2], &om[3], &om[4], &om[5],
    100                &om[6], &om[7], &om[8]);
    101         fclose(fptr);
    102 
    103         LOGV_IF(EXTRA_VERBOSE,
    104                 "HAL:compass mounting matrix: "
    105                 "%+d %+d %+d %+d %+d %+d %+d %+d %+d",
    106                 om[0], om[1], om[2], om[3], om[4], om[5], om[6], om[7], om[8]);
    107 
    108         mCompassOrientation[0] = om[0];
    109         mCompassOrientation[1] = om[1];
    110         mCompassOrientation[2] = om[2];
    111         mCompassOrientation[3] = om[3];
    112         mCompassOrientation[4] = om[4];
    113         mCompassOrientation[5] = om[5];
    114         mCompassOrientation[6] = om[6];
    115         mCompassOrientation[7] = om[7];
    116         mCompassOrientation[8] = om[8];
    117     } else {
    118         LOGE("HAL:Couldn't read compass mounting matrix");
    119     }
    120 
    121     if (!isIntegrated()) {
    122         enable(ID_M, 0);
    123     }
    124 }
    125 
    126 CompassSensor::~CompassSensor()
    127 {
    128     VFUNC_LOG;
    129 
    130     free(pathP);
    131     if( compass_fd > 0)
    132         close(compass_fd);
    133 }
    134 
    135 int CompassSensor::getFd() const
    136 {
    137     VHANDLER_LOG;
    138     return compass_fd;
    139 }
    140 
    141 /**
    142  *  @brief        This function will enable/disable sensor.
    143  *  @param[in]    handle
    144  *                  which sensor to enable/disable.
    145  *  @param[in]    en
    146  *                  en=1, enable;
    147  *                  en=0, disable
    148  *  @return       if the operation is successful.
    149  */
    150 int CompassSensor::enable(int32_t handle, int en)
    151 {
    152     VFUNC_LOG;
    153 
    154     int res = 0;
    155 
    156     res = write_sysfs_int(compassSysFs.compass_enable, en);
    157 
    158     return res;
    159 }
    160 
    161 int CompassSensor::setDelay(int32_t handle, int64_t ns)
    162 {
    163     VFUNC_LOG;
    164     int tempFd;
    165     int res;
    166 
    167     LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %.0f > %s (%lld)",
    168             1000000000.f / ns, compassSysFs.compass_rate, getTimestamp());
    169     mDelay = ns;
    170     if (ns == 0)
    171         return -1;
    172     tempFd = open(compassSysFs.compass_rate, O_RDWR);
    173     res = write_attribute_sensor(tempFd, 1000000000.f / ns);
    174     if(res < 0) {
    175         LOGE("HAL:Compass update delay error");
    176     }
    177     return res;
    178 }
    179 
    180 
    181 /**
    182     @brief      This function will return the state of the sensor.
    183     @return     1=enabled; 0=disabled
    184 **/
    185 int CompassSensor::getEnable(int32_t handle)
    186 {
    187     VFUNC_LOG;
    188     return mEnable;
    189 }
    190 
    191 /* use for Invensense compass calibration */
    192 #define COMPASS_EVENT_DEBUG (0)
    193 void CompassSensor::processCompassEvent(const input_event *event)
    194 {
    195     VHANDLER_LOG;
    196 
    197     switch (event->code) {
    198     case EVENT_TYPE_ICOMPASS_X:
    199         LOGV_IF(COMPASS_EVENT_DEBUG, "EVENT_TYPE_ICOMPASS_X\n");
    200         mCachedCompassData[0] = event->value;
    201         break;
    202     case EVENT_TYPE_ICOMPASS_Y:
    203         LOGV_IF(COMPASS_EVENT_DEBUG, "EVENT_TYPE_ICOMPASS_Y\n");
    204         mCachedCompassData[1] = event->value;
    205         break;
    206     case EVENT_TYPE_ICOMPASS_Z:
    207         LOGV_IF(COMPASS_EVENT_DEBUG, "EVENT_TYPE_ICOMPASS_Z\n");
    208         mCachedCompassData[2] = event->value;
    209         break;
    210     }
    211 
    212     mCompassTimestamp =
    213         (int64_t)event->time.tv_sec * 1000000000L + event->time.tv_usec * 1000L;
    214 }
    215 
    216 void CompassSensor::getOrientationMatrix(signed char *orient)
    217 {
    218     VFUNC_LOG;
    219     memcpy(orient, mCompassOrientation, sizeof(mCompassOrientation));
    220 }
    221 
    222 long CompassSensor::getSensitivity()
    223 {
    224     VFUNC_LOG;
    225 
    226     long sensitivity;
    227     LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:cat %s (%lld)",
    228             compassSysFs.compass_scale, getTimestamp());
    229     inv_read_data(compassSysFs.compass_scale, &sensitivity);
    230     return sensitivity;
    231 }
    232 
    233 /**
    234     @brief         This function is called by sensors_mpl.cpp
    235                    to read sensor data from the driver.
    236     @param[out]    data      sensor data is stored in this variable. Scaled such that
    237                              1 uT = 2^16
    238     @para[in]      timestamp data's timestamp
    239     @return        1, if 1   sample read, 0, if not, negative if error
    240  */
    241 int CompassSensor::readSample(long *data, int64_t *timestamp)
    242 {
    243     VHANDLER_LOG;
    244 
    245     int numEventReceived = 0, done = 0;
    246 
    247     ssize_t n = mCompassInputReader.fill(compass_fd);
    248     if (n < 0) {
    249         LOGE("HAL:no compass events read");
    250         return n;
    251     }
    252 
    253     input_event const* event;
    254 
    255     while (done == 0 && mCompassInputReader.readEvent(&event)) {
    256         int type = event->type;
    257         if (type == EV_REL) {
    258             processCompassEvent(event);
    259         } else if (type == EV_SYN) {
    260             *timestamp = mCompassTimestamp;
    261             memcpy(data, mCachedCompassData, sizeof(mCachedCompassData));
    262             done = 1;
    263         } else {
    264             LOGE("HAL:Compass Sensor: unknown event (type=%d, code=%d)",
    265                  type, event->code);
    266         }
    267         mCompassInputReader.next();
    268     }
    269 
    270     return done;
    271 }
    272 
    273 /**
    274  *  @brief  This function will return the current delay for this sensor.
    275  *  @return delay in nanoseconds.
    276  */
    277 int64_t CompassSensor::getDelay(int32_t handle)
    278 {
    279     VFUNC_LOG;
    280     return mDelay;
    281 }
    282 
    283 void CompassSensor::fillList(struct sensor_t *list)
    284 {
    285     VFUNC_LOG;
    286 
    287     const char *compass = sensor_name;
    288 
    289     if (compass) {
    290         if(!strcmp(compass, "INV_COMPASS")) {
    291             list->maxRange = COMPASS_MPU9150_RANGE;
    292             list->resolution = COMPASS_MPU9150_RESOLUTION;
    293             list->power = COMPASS_MPU9150_POWER;
    294             list->minDelay = COMPASS_MPU9150_MINDELAY;
    295             return;
    296         }
    297         if(!strcmp(compass, "compass")
    298                 || !strcmp(compass, "INV_AK8975")
    299                 || !strncmp(compass, "AK89xx",2)
    300                 || !strncmp(compass, "ak89xx",2)) {
    301             list->maxRange = COMPASS_AKM8975_RANGE;
    302             list->resolution = COMPASS_AKM8975_RESOLUTION;
    303             list->power = COMPASS_AKM8975_POWER;
    304             list->minDelay = COMPASS_AKM8975_MINDELAY;
    305             return;
    306         }
    307         if(!strcmp(compass, "INV_YAS530")) {
    308             list->maxRange = COMPASS_YAS53x_RANGE;
    309             list->resolution = COMPASS_YAS53x_RESOLUTION;
    310             list->power = COMPASS_YAS53x_POWER;
    311             list->minDelay = COMPASS_YAS53x_MINDELAY;
    312             return;
    313         }
    314         if(!strcmp(compass, "INV_AMI306")) {
    315             list->maxRange = COMPASS_AMI306_RANGE;
    316             list->resolution = COMPASS_AMI306_RESOLUTION;
    317             list->power = COMPASS_AMI306_POWER;
    318             list->minDelay = COMPASS_AMI306_MINDELAY;
    319             return;
    320         }
    321     }
    322     LOGE("HAL:unknown compass id %s -- "
    323          "params default to ak8975 and might be wrong.",
    324          compass);
    325     list->maxRange = COMPASS_AKM8975_RANGE;
    326     list->resolution = COMPASS_AKM8975_RESOLUTION;
    327     list->power = COMPASS_AKM8975_POWER;
    328     list->minDelay = COMPASS_AKM8975_MINDELAY;
    329 }
    330 
    331 int CompassSensor::inv_init_sysfs_attributes(void)
    332 {
    333     VFUNC_LOG;
    334 
    335     unsigned char i = 0;
    336     char sysfs_path[MAX_SYSFS_NAME_LEN];
    337     char iio_trigger_path[MAX_SYSFS_NAME_LEN], tbuf[2];
    338     char *sptr;
    339     char **dptr;
    340     int num;
    341 
    342     pathP = (char*)malloc(
    343                     sizeof(char[COMPASS_MAX_SYSFS_ATTRB][MAX_SYSFS_NAME_LEN]));
    344     sptr = pathP;
    345     dptr = (char**)&compassSysFs;
    346     if (sptr == NULL)
    347         return -1;
    348 
    349     memset(sysfs_path, 0, sizeof(sysfs_path));
    350     memset(iio_trigger_path, 0, sizeof(iio_trigger_path));
    351 
    352     do {
    353         *dptr++ = sptr;
    354         memset(sptr, 0, sizeof(sptr));
    355         sptr += sizeof(char[MAX_SYSFS_NAME_LEN]);
    356     } while (++i < COMPASS_MAX_SYSFS_ATTRB);
    357 
    358     // get proper (in absolute/relative) IIO path & build MPU's sysfs paths
    359     // inv_get_sysfs_abs_path(sysfs_path);
    360     inv_get_sysfs_path(sysfs_path);
    361     inv_get_iio_trigger_path(iio_trigger_path);
    362 
    363     if (strcmp(sysfs_path, "") == 0  || strcmp(iio_trigger_path, "") == 0)
    364         return 0;
    365 
    366 #if defined COMPASS_AK8975
    367     inv_get_input_number(dev_name, &num);
    368     tbuf[0] = num + 0x30;
    369     tbuf[1] = 0;
    370     sprintf(sysfs_path, "%s%s", "sys/class/input/input", tbuf);
    371     strcat(sysfs_path, "/ak8975");
    372 
    373     sprintf(compassSysFs.compass_enable, "%s%s", sysfs_path, "/enable");
    374     sprintf(compassSysFs.compass_rate, "%s%s", sysfs_path, "/rate");
    375     sprintf(compassSysFs.compass_scale, "%s%s", sysfs_path, "/scale");
    376     sprintf(compassSysFs.compass_orient, "%s%s", sysfs_path, "/compass_matrix");
    377 #else
    378     sprintf(compassSysFs.compass_enable, "%s%s", sysfs_path, "/compass_enable");
    379     sprintf(compassSysFs.compass_rate, "%s%s", sysfs_path, "/compass_rate");
    380     sprintf(compassSysFs.compass_scale, "%s%s", sysfs_path, "/in_magn_scale");
    381     sprintf(compassSysFs.compass_orient, "%s%s", sysfs_path, "/compass_matrix");
    382 #endif
    383 
    384 #if 0
    385     // test print sysfs paths
    386     dptr = (char**)&compassSysFs;
    387     for (i = 0; i < COMPASS_MAX_SYSFS_ATTRB; i++) {
    388         LOGE("HAL:sysfs path: %s", *dptr++);
    389     }
    390 #endif
    391     return 0;
    392 }
    393