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