summaryrefslogtreecommitdiff
path: root/6515/libsensors_iio/CompassSensor.IIO.primary.cpp
diff options
context:
space:
mode:
Diffstat (limited to '6515/libsensors_iio/CompassSensor.IIO.primary.cpp')
-rw-r--r--6515/libsensors_iio/CompassSensor.IIO.primary.cpp563
1 files changed, 563 insertions, 0 deletions
diff --git a/6515/libsensors_iio/CompassSensor.IIO.primary.cpp b/6515/libsensors_iio/CompassSensor.IIO.primary.cpp
new file mode 100644
index 0000000..5d8d120
--- /dev/null
+++ b/6515/libsensors_iio/CompassSensor.IIO.primary.cpp
@@ -0,0 +1,563 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_NDEBUG 0
+
+#include <fcntl.h>
+#include <errno.h>
+#include <math.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/select.h>
+#include <cutils/log.h>
+#include <linux/input.h>
+#include <string.h>
+
+#include "CompassSensor.IIO.primary.h"
+#include "sensors.h"
+#include "MPLSupport.h"
+#include "sensor_params.h"
+#include "ml_sysfs_helper.h"
+
+#define COMPASS_MAX_SYSFS_ATTRB sizeof(compassSysFs) / sizeof(char*)
+#define COMPASS_NAME "USE_SYSFS"
+
+#if defined COMPASS_AK8975
+#pragma message("HAL:build Invensense compass cal with AK8975 on primary bus")
+#define USE_MPL_COMPASS_HAL (1)
+#define COMPASS_NAME "INV_AK8975"
+#endif
+
+/******************************************************************************/
+
+CompassSensor::CompassSensor()
+ : SensorBase(COMPASS_NAME, NULL),
+ mCompassTimestamp(0),
+ mCompassInputReader(8),
+ mCoilsResetFd(0)
+{
+ FILE *fptr;
+
+ VFUNC_LOG;
+
+ mYasCompass = false;
+ if(!strcmp(dev_name, "USE_SYSFS")) {
+ char sensor_name[20];
+ find_name_by_sensor_type("in_magn_x_raw", "iio:device", sensor_name);
+ strncpy(dev_full_name, sensor_name,
+ sizeof(dev_full_name) / sizeof(dev_full_name[0]));
+ if(!strncmp(dev_full_name, "yas", 3)) {
+ mYasCompass = true;
+ }
+ } else {
+
+#ifdef COMPASS_YAS53x
+ /* for YAS53x compasses, dev_name is just a prefix,
+ we need to find the actual name */
+ if (fill_dev_full_name_by_prefix(dev_name,
+ dev_full_name, sizeof(dev_full_name) / sizeof(dev_full_name[0]))) {
+ LOGE("Cannot find Yamaha device with prefix name '%s' - "
+ "magnetometer will likely not work.", dev_name);
+ } else {
+ mYasCompass = true;
+ }
+#else
+ strncpy(dev_full_name, dev_name,
+ sizeof(dev_full_name) / sizeof(dev_full_name[0]));
+#endif
+
+}
+
+ if (inv_init_sysfs_attributes()) {
+ LOGE("Error Instantiating Compass\n");
+ return;
+ }
+
+ if (!strcmp(dev_full_name, "INV_COMPASS")) {
+ mI2CBus = COMPASS_BUS_SECONDARY;
+ } else {
+ mI2CBus = COMPASS_BUS_PRIMARY;
+ }
+
+ memset(mCachedCompassData, 0, sizeof(mCachedCompassData));
+
+ if (!isIntegrated()) {
+ enable(ID_M, 0);
+ }
+
+ LOGV_IF(SYSFS_VERBOSE, "HAL:compass name: %s", dev_full_name);
+ enable_iio_sysfs();
+
+ LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:cat %s (%lld)",
+ compassSysFs.compass_orient, getTimestamp());
+ fptr = fopen(compassSysFs.compass_orient, "r");
+ if (fptr != NULL) {
+ int om[9];
+ if (fscanf(fptr, "%d,%d,%d,%d,%d,%d,%d,%d,%d",
+ &om[0], &om[1], &om[2], &om[3], &om[4], &om[5],
+ &om[6], &om[7], &om[8]) < 0 || fclose(fptr)) {
+ LOGE("HAL:could not read compass mounting matrix");
+ } else {
+
+ LOGV_IF(EXTRA_VERBOSE,
+ "HAL:compass mounting matrix: "
+ "%+d %+d %+d %+d %+d %+d %+d %+d %+d",
+ om[0], om[1], om[2], om[3], om[4], om[5], om[6], om[7], om[8]);
+
+ mCompassOrientation[0] = om[0];
+ mCompassOrientation[1] = om[1];
+ mCompassOrientation[2] = om[2];
+ mCompassOrientation[3] = om[3];
+ mCompassOrientation[4] = om[4];
+ mCompassOrientation[5] = om[5];
+ mCompassOrientation[6] = om[6];
+ mCompassOrientation[7] = om[7];
+ mCompassOrientation[8] = om[8];
+ }
+ }
+
+ if(mYasCompass) {
+ mCoilsResetFd = fopen(compassSysFs.compass_attr_1, "r+");
+ if (fptr == NULL) {
+ LOGE("HAL:Could not open compass overunderflow");
+ }
+ }
+}
+
+void CompassSensor::enable_iio_sysfs()
+{
+ VFUNC_LOG;
+
+ int tempFd = 0;
+ char iio_device_node[MAX_CHIP_ID_LEN];
+ FILE *tempFp = NULL;
+ const char* compass = dev_full_name;
+
+ LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)",
+ 1, compassSysFs.in_timestamp_en, getTimestamp());
+ write_sysfs_int(compassSysFs.in_timestamp_en, 1);
+
+ LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)",
+ IIO_BUFFER_LENGTH, compassSysFs.buffer_length, getTimestamp());
+ tempFp = fopen(compassSysFs.buffer_length, "w");
+ if (tempFp == NULL) {
+ LOGE("HAL:could not open buffer length");
+ } else {
+ if (fprintf(tempFp, "%d", IIO_BUFFER_LENGTH) < 0 || fclose(tempFp) < 0) {
+ LOGE("HAL:could not write buffer length");
+ }
+ }
+
+ sprintf(iio_device_node, "%s%d", "/dev/iio:device",
+ find_type_by_name(compass, "iio:device"));
+ compass_fd = open(iio_device_node, O_RDONLY);
+ int res = errno;
+ if (compass_fd < 0) {
+ LOGE("HAL:could not open '%s' iio device node in path '%s' - "
+ "error '%s' (%d)",
+ compass, iio_device_node, strerror(res), res);
+ } else {
+ LOGV_IF(EXTRA_VERBOSE,
+ "HAL:iio %s, compass_fd opened : %d", compass, compass_fd);
+ }
+
+ /* TODO: need further tests for optimization to reduce context-switch
+ LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo 1 > %s (%lld)",
+ compassSysFs.compass_x_fifo_enable, getTimestamp());
+ tempFd = open(compassSysFs.compass_x_fifo_enable, O_RDWR);
+ res = errno;
+ if (tempFd > 0) {
+ res = enable_sysfs_sensor(tempFd, 1);
+ } else {
+ LOGE("HAL:open of %s failed with '%s' (%d)",
+ compassSysFs.compass_x_fifo_enable, strerror(res), res);
+ }
+
+ LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo 1 > %s (%lld)",
+ compassSysFs.compass_y_fifo_enable, getTimestamp());
+ tempFd = open(compassSysFs.compass_y_fifo_enable, O_RDWR);
+ res = errno;
+ if (tempFd > 0) {
+ res = enable_sysfs_sensor(tempFd, 1);
+ } else {
+ LOGE("HAL:open of %s failed with '%s' (%d)",
+ compassSysFs.compass_y_fifo_enable, strerror(res), res);
+ }
+
+ LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo 1 > %s (%lld)",
+ compassSysFs.compass_z_fifo_enable, getTimestamp());
+ tempFd = open(compassSysFs.compass_z_fifo_enable, O_RDWR);
+ res = errno;
+ if (tempFd > 0) {
+ res = enable_sysfs_sensor(tempFd, 1);
+ } else {
+ LOGE("HAL:open of %s failed with '%s' (%d)",
+ compassSysFs.compass_z_fifo_enable, strerror(res), res);
+ }
+ */
+}
+
+CompassSensor::~CompassSensor()
+{
+ VFUNC_LOG;
+
+ free(pathP);
+ if( compass_fd > 0)
+ close(compass_fd);
+ if(mYasCompass) {
+ if( mCoilsResetFd != NULL )
+ fclose(mCoilsResetFd);
+ }
+}
+
+int CompassSensor::getFd(void) const
+{
+ VHANDLER_LOG;
+ LOGI_IF(0, "HAL:compass_fd=%d", compass_fd);
+ return compass_fd;
+}
+
+/**
+ * @brief This function will enable/disable sensor.
+ * @param[in] handle
+ * which sensor to enable/disable.
+ * @param[in] en
+ * en=1, enable;
+ * en=0, disable
+ * @return if the operation is successful.
+ */
+int CompassSensor::enable(int32_t handle, int en)
+{
+ VFUNC_LOG;
+
+ mEnable = en;
+ int tempFd;
+ int res = 0;
+
+ /* reset master enable */
+ res = masterEnable(0);
+ if (res < 0) {
+ return res;
+ }
+
+ if (en) {
+ LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)",
+ en, compassSysFs.compass_x_fifo_enable, getTimestamp());
+ res = write_sysfs_int(compassSysFs.compass_x_fifo_enable, en);
+ LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)",
+ en, compassSysFs.compass_y_fifo_enable, getTimestamp());
+ res += write_sysfs_int(compassSysFs.compass_y_fifo_enable, en);
+ LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)",
+ en, compassSysFs.compass_z_fifo_enable, getTimestamp());
+ res += write_sysfs_int(compassSysFs.compass_z_fifo_enable, en);
+
+ res = masterEnable(en);
+ if (res < en) {
+ return res;
+ }
+ }
+
+ return res;
+}
+
+int CompassSensor::masterEnable(int en)
+{
+ VFUNC_LOG;
+ LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)",
+ en, compassSysFs.chip_enable, getTimestamp());
+ return write_sysfs_int(compassSysFs.chip_enable, en);
+}
+
+int CompassSensor::setDelay(int32_t handle, int64_t ns)
+{
+ VFUNC_LOG;
+ int tempFd;
+ int res;
+
+ mDelay = ns;
+ if (ns == 0)
+ return -1;
+ tempFd = open(compassSysFs.compass_rate, O_RDWR);
+ LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %.0f > %s (%lld)",
+ 1000000000.f / ns, compassSysFs.compass_rate, getTimestamp());
+ res = write_attribute_sensor(tempFd, 1000000000.f / ns);
+ if(res < 0) {
+ LOGE("HAL:Compass update delay error");
+ }
+ return res;
+}
+
+/**
+ @brief This function will return the state of the sensor.
+ @return 1=enabled; 0=disabled
+**/
+int CompassSensor::getEnable(int32_t handle)
+{
+ VFUNC_LOG;
+ return mEnable;
+}
+
+/* use for Invensense compass calibration */
+#define COMPASS_EVENT_DEBUG (0)
+void CompassSensor::processCompassEvent(const input_event *event)
+{
+ VHANDLER_LOG;
+
+ switch (event->code) {
+ case EVENT_TYPE_ICOMPASS_X:
+ LOGV_IF(COMPASS_EVENT_DEBUG, "EVENT_TYPE_ICOMPASS_X\n");
+ mCachedCompassData[0] = event->value;
+ break;
+ case EVENT_TYPE_ICOMPASS_Y:
+ LOGV_IF(COMPASS_EVENT_DEBUG, "EVENT_TYPE_ICOMPASS_Y\n");
+ mCachedCompassData[1] = event->value;
+ break;
+ case EVENT_TYPE_ICOMPASS_Z:
+ LOGV_IF(COMPASS_EVENT_DEBUG, "EVENT_TYPE_ICOMPASS_Z\n");
+ mCachedCompassData[2] = event->value;
+ break;
+ }
+
+ mCompassTimestamp =
+ (int64_t)event->time.tv_sec * 1000000000L + event->time.tv_usec * 1000L;
+}
+
+void CompassSensor::getOrientationMatrix(signed char *orient)
+{
+ VFUNC_LOG;
+ memcpy(orient, mCompassOrientation, sizeof(mCompassOrientation));
+}
+
+long CompassSensor::getSensitivity()
+{
+ VFUNC_LOG;
+
+ long sensitivity;
+ LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:cat %s (%lld)",
+ compassSysFs.compass_scale, getTimestamp());
+ inv_read_data(compassSysFs.compass_scale, &sensitivity);
+ return sensitivity;
+}
+
+/**
+ @brief This function is called by sensors_mpl.cpp
+ to read sensor data from the driver.
+ @param[out] data sensor data is stored in this variable. Scaled such that
+ 1 uT = 2^16
+ @para[in] timestamp data's timestamp
+ @return 1, if 1 sample read, 0, if not, negative if error
+ */
+int CompassSensor::readSample(long *data, int64_t *timestamp) {
+ VFUNC_LOG;
+
+ int i;
+ char *rdata = mIIOBuffer;
+
+ size_t rsize = read(compass_fd, rdata, (8 * mEnable + 8) * 1);
+
+ if (!mEnable) {
+ rsize = read(compass_fd, rdata, (8 + 8) * IIO_BUFFER_LENGTH);
+ // LOGI("clear buffer with size: %d", rsize);
+ }
+/*
+ LOGI("get one sample of AMI IIO data with size: %d", rsize);
+ LOGI_IF(mEnable, "compass x/y/z: %d/%d/%d", *((short *) (rdata + 0)),
+ *((short *) (rdata + 2)), *((short *) (rdata + 4)));
+*/
+ if (mEnable) {
+ for (i = 0; i < 3; i++) {
+ data[i] = *((short *) (rdata + i * 2));
+ }
+ *timestamp = *((long long *) (rdata + 8 * mEnable));
+ }
+
+ return mEnable;
+}
+
+/**
+ * @brief This function will return the current delay for this sensor.
+ * @return delay in nanoseconds.
+ */
+int64_t CompassSensor::getDelay(int32_t handle)
+{
+ VFUNC_LOG;
+ return mDelay;
+}
+
+void CompassSensor::fillList(struct sensor_t *list)
+{
+ VFUNC_LOG;
+
+ const char *compass = dev_full_name;
+
+ if (compass) {
+ if(!strcmp(compass, "INV_COMPASS")) {
+ list->maxRange = COMPASS_MPU9150_RANGE;
+ list->resolution = COMPASS_MPU9150_RESOLUTION;
+ list->power = COMPASS_MPU9150_POWER;
+ list->minDelay = COMPASS_MPU9150_MINDELAY;
+ mMinDelay = list->minDelay;
+ return;
+ }
+ if(!strcmp(compass, "compass")
+ || !strcmp(compass, "INV_AK8975")
+ || !strcmp(compass, "AK8975")
+ || !strcmp(compass, "ak8975")) {
+ list->maxRange = COMPASS_AKM8975_RANGE;
+ list->resolution = COMPASS_AKM8975_RESOLUTION;
+ list->power = COMPASS_AKM8975_POWER;
+ list->minDelay = COMPASS_AKM8975_MINDELAY;
+ mMinDelay = list->minDelay;
+ return;
+ }
+ if(!strcmp(compass, "compass")
+ || !strcmp(compass, "INV_AK8963")
+ || !strcmp(compass, "AK8963")
+ || !strcmp(compass, "ak8963")) {
+ list->maxRange = COMPASS_AKM8963_RANGE;
+ list->resolution = COMPASS_AKM8963_RESOLUTION;
+ list->power = COMPASS_AKM8963_POWER;
+ list->minDelay = COMPASS_AKM8963_MINDELAY;
+ mMinDelay = list->minDelay;
+ return;
+ }
+ if(!strcmp(compass, "ami306")) {
+ list->maxRange = COMPASS_AMI306_RANGE;
+ list->resolution = COMPASS_AMI306_RESOLUTION;
+ list->power = COMPASS_AMI306_POWER;
+ list->minDelay = COMPASS_AMI306_MINDELAY;
+ mMinDelay = list->minDelay;
+ return;
+ }
+ if(!strcmp(compass, "yas530")
+ || !strcmp(compass, "yas532")
+ || !strcmp(compass, "yas533")) {
+ list->maxRange = COMPASS_YAS53x_RANGE;
+ list->resolution = COMPASS_YAS53x_RESOLUTION;
+ list->power = COMPASS_YAS53x_POWER;
+ list->minDelay = COMPASS_YAS53x_MINDELAY;
+ mMinDelay = list->minDelay;
+ return;
+ }
+ }
+
+ LOGE("HAL:unknown compass id %s -- "
+ "params default to ak8975 and might be wrong.",
+ compass);
+ list->maxRange = COMPASS_AKM8975_RANGE;
+ list->resolution = COMPASS_AKM8975_RESOLUTION;
+ list->power = COMPASS_AKM8975_POWER;
+ list->minDelay = COMPASS_AKM8975_MINDELAY;
+ mMinDelay = list->minDelay;
+}
+
+/* Read sysfs entry to determine whether overflow had happend
+ then write to sysfs to reset to zero */
+int CompassSensor::checkCoilsReset()
+{
+ int result=-1;
+ VFUNC_LOG;
+
+ if(mCoilsResetFd != NULL) {
+ int attr;
+ rewind(mCoilsResetFd);
+ fscanf(mCoilsResetFd, "%d", &attr);
+ if(attr == 0)
+ return 0;
+ else {
+ LOGV_IF(SYSFS_VERBOSE, "HAL:overflow detected");
+ rewind(mCoilsResetFd);
+ if(fprintf(mCoilsResetFd, "%d", 0) < 0)
+ LOGE("HAL:could not write overunderflow");
+ else
+ return 1;
+ }
+ } else {
+ LOGE("HAL:could not read overunderflow");
+ }
+ return result;
+}
+
+int CompassSensor::inv_init_sysfs_attributes(void)
+{
+ VFUNC_LOG;
+
+ unsigned char i = 0;
+ char sysfs_path[MAX_SYSFS_NAME_LEN], tbuf[2];
+ char *sptr;
+ char **dptr;
+ int num;
+ const char* compass = dev_full_name;
+
+ pathP = (char*)malloc(
+ sizeof(char[COMPASS_MAX_SYSFS_ATTRB][MAX_SYSFS_NAME_LEN]));
+ sptr = pathP;
+ dptr = (char**)&compassSysFs;
+ if (sptr == NULL)
+ return -1;
+
+ do {
+ *dptr++ = sptr;
+ sptr += sizeof(char[MAX_SYSFS_NAME_LEN]);
+ } while (++i < COMPASS_MAX_SYSFS_ATTRB);
+
+ // get proper (in absolute/relative) IIO path & build sysfs paths
+ sprintf(sysfs_path, "%s%d", "/sys/bus/iio/devices/iio:device",
+ find_type_by_name(compass, "iio:device"));
+
+#if defined COMPASS_AK8975
+ inv_get_input_number(compass, &num);
+ tbuf[0] = num + 0x30;
+ tbuf[1] = 0;
+ sprintf(sysfs_path, "%s%s", "sys/class/input/input", tbuf);
+ strcat(sysfs_path, "/ak8975");
+
+ sprintf(compassSysFs.compass_enable, "%s%s", sysfs_path, "/enable");
+ sprintf(compassSysFs.compass_rate, "%s%s", sysfs_path, "/rate");
+ sprintf(compassSysFs.compass_scale, "%s%s", sysfs_path, "/scale");
+ sprintf(compassSysFs.compass_orient, "%s%s", sysfs_path, "/compass_matrix");
+#else /* IIO */
+ sprintf(compassSysFs.chip_enable, "%s%s", sysfs_path, "/buffer/enable");
+ sprintf(compassSysFs.in_timestamp_en, "%s%s", sysfs_path, "/scan_elements/in_timestamp_en");
+ sprintf(compassSysFs.buffer_length, "%s%s", sysfs_path, "/buffer/length");
+
+ sprintf(compassSysFs.compass_x_fifo_enable, "%s%s", sysfs_path, "/scan_elements/in_magn_x_en");
+ sprintf(compassSysFs.compass_y_fifo_enable, "%s%s", sysfs_path, "/scan_elements/in_magn_y_en");
+ sprintf(compassSysFs.compass_z_fifo_enable, "%s%s", sysfs_path, "/scan_elements/in_magn_z_en");
+ sprintf(compassSysFs.compass_rate, "%s%s", sysfs_path, "/sampling_frequency");
+ sprintf(compassSysFs.compass_scale, "%s%s", sysfs_path, "/in_magn_scale");
+ sprintf(compassSysFs.compass_orient, "%s%s", sysfs_path, "/compass_matrix");
+
+ if(mYasCompass) {
+ sprintf(compassSysFs.compass_attr_1, "%s%s", sysfs_path, "/overunderflow");
+ }
+#endif
+
+#if 0
+ // test print sysfs paths
+ dptr = (char**)&compassSysFs;
+ LOGI("sysfs path base: %s", sysfs_path);
+ for (i = 0; i < COMPASS_MAX_SYSFS_ATTRB; i++) {
+ LOGE("HAL:sysfs path: %s", *dptr++);
+ }
+#endif
+ return 0;
+}
+
+int CompassSensor::isYasCompass(void)
+{
+ return mYasCompass;
+}