/* * Copyright (C) 2008 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. */ #include <fcntl.h> #include <errno.h> #include <math.h> #include <poll.h> #include <string.h> #include <unistd.h> #include <dirent.h> #include <sys/select.h> #include <cutils/log.h> #include "AdxlSensor.h" #define ADXL_DATA_NAME "ADXL34x accelerometer" #define ADXL_MAX_SAMPLE_RATE_VAL 11 /* 200 Hz */ #define ADXL_UNIT_CONVERSION(value) ((value) * GRAVITY_EARTH / (256.0f)) /*****************************************************************************/ AdxlSensor::AdxlSensor() : SensorBase(NULL, ADXL_DATA_NAME), mEnabled(0), mDelay(-1), mInputReader(4), mHasPendingEvent(false) { mPendingEvent.version = sizeof(sensors_event_t); mPendingEvent.sensor = ID_A; mPendingEvent.type = SENSOR_TYPE_ACCELEROMETER; memset(mPendingEvent.data, 0, sizeof(mPendingEvent.data)); if (data_fd >= 0) { strcpy(input_sysfs_path, "/sys/class/input/"); strcat(input_sysfs_path, input_name); strcat(input_sysfs_path, "/device/device/"); input_sysfs_path_len = strlen(input_sysfs_path); ALOGD("AdxlSensor: sysfs_path=%s", input_sysfs_path); } else { input_sysfs_path[0] = '\0'; input_sysfs_path_len = 0; } } AdxlSensor::~AdxlSensor() { if (mEnabled) { setEnable(0, 0); } } int AdxlSensor::setInitialState() { struct input_absinfo absinfo; if (mEnabled) { if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_ACCEL_X), &absinfo)) { mPendingEvent.acceleration.x = ADXL_UNIT_CONVERSION(absinfo.value); } if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_ACCEL_Y), &absinfo)) { mPendingEvent.acceleration.y = ADXL_UNIT_CONVERSION(absinfo.value); } if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_ACCEL_Z), &absinfo)) { mPendingEvent.acceleration.z = ADXL_UNIT_CONVERSION(absinfo.value); } } return 0; } bool AdxlSensor::hasPendingEvents() const { return mHasPendingEvent; } int AdxlSensor::setEnable(int32_t handle, int enabled) { int err = 0; char buffer[2]; /* handle check */ if (handle != ID_A) { ALOGE("AdxlSensor: Invalid handle (%d)", handle); return -EINVAL; } buffer[0] = '\0'; buffer[1] = '\0'; if (mEnabled <= 0) { if(enabled) buffer[0] = '0'; } else if (mEnabled == 1) { if(!enabled) buffer[0] = '1'; } if (buffer[0] != '\0') { strcpy(&input_sysfs_path[input_sysfs_path_len], "disable"); err = write_sys_attribute(input_sysfs_path, buffer, 1); if (err != 0) { return err; } ALOGD("AdxlSensor: Control set %s", buffer); setInitialState(); } if (enabled) { mEnabled++; if (mEnabled > 32767) mEnabled = 32767; } else { mEnabled--; if (mEnabled < 0) mEnabled = 0; } ALOGD("AdxlSensor: mEnabled = %d", mEnabled); return err; } int AdxlSensor::setDelay(int32_t handle, int64_t delay_ns) { int err = 0; int rate_val; int32_t us; char buffer[16]; int bytes; /* handle check */ if (handle != ID_A) { ALOGE("AdxlSensor: Invalid handle (%d)", handle); return -EINVAL; } if (mDelay != delay_ns) { /* * The ADXL34x Supports 16 sample rates ranging from 3200Hz-0.098Hz * Calculate best fit and limit to max 200Hz (rate_val 11) */ us = (int32_t)(delay_ns / 1000); for (rate_val = 0; rate_val < 16; rate_val++) if (us >= ((10000000) >> rate_val)) break; if (rate_val > ADXL_MAX_SAMPLE_RATE_VAL) { rate_val = ADXL_MAX_SAMPLE_RATE_VAL; } strcpy(&input_sysfs_path[input_sysfs_path_len], "rate"); bytes = sprintf(buffer, "%d", rate_val); err = write_sys_attribute(input_sysfs_path, buffer, bytes); if (err == 0) { mDelay = delay_ns; ALOGD("AdxlSensor: Control set delay %f ms requetsed, using %f ms", delay_ns/1000000.0f, 1e6 / (3200000 >> (15 - rate_val))); } } return err; } int64_t AdxlSensor::getDelay(int32_t handle) { return (handle == ID_A) ? mDelay : 0; } int AdxlSensor::getEnable(int32_t handle) { return (handle == ID_A) ? mEnabled : 0; } int AdxlSensor::readEvents(sensors_event_t* data, int count) { if (count < 1) return -EINVAL; if (mHasPendingEvent) { mHasPendingEvent = false; mPendingEvent.timestamp = getTimestamp(); *data = mPendingEvent; return mEnabled ? 1 : 0; } ssize_t n = mInputReader.fill(data_fd); if (n < 0) return n; int numEventReceived = 0; input_event const* event; while (count && mInputReader.readEvent(&event)) { int type = event->type; if (type == EV_ABS) { float value = event->value; if (event->code == EVENT_TYPE_ACCEL_X) { mPendingEvent.acceleration.x = ADXL_UNIT_CONVERSION(value); } else if (event->code == EVENT_TYPE_ACCEL_Y) { mPendingEvent.acceleration.y = ADXL_UNIT_CONVERSION(value); } else if (event->code == EVENT_TYPE_ACCEL_Z) { mPendingEvent.acceleration.z = ADXL_UNIT_CONVERSION(value); } } else if (type == EV_SYN) { mPendingEvent.timestamp = timevalToNano(event->time); if (mEnabled) { *data++ = mPendingEvent; count--; numEventReceived++; } } else { ALOGE("AdxlSensor: unknown event (type=%d, code=%d)", type, event->code); } mInputReader.next(); } return numEventReceived; }