summaryrefslogtreecommitdiff
path: root/AK8975_FS/libsensors/AkmSensor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'AK8975_FS/libsensors/AkmSensor.cpp')
-rw-r--r--AK8975_FS/libsensors/AkmSensor.cpp323
1 files changed, 323 insertions, 0 deletions
diff --git a/AK8975_FS/libsensors/AkmSensor.cpp b/AK8975_FS/libsensors/AkmSensor.cpp
new file mode 100644
index 0000000..6c8da8b
--- /dev/null
+++ b/AK8975_FS/libsensors/AkmSensor.cpp
@@ -0,0 +1,323 @@
+/*
+ * 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 <unistd.h>
+#include <dirent.h>
+#include <sys/select.h>
+#include <dlfcn.h>
+
+#include <cutils/log.h>
+
+#include "AkmSensor.h"
+
+#define AKMD_DEFAULT_INTERVAL 200000000
+
+/*****************************************************************************/
+
+AkmSensor::AkmSensor()
+: SensorBase(NULL, "compass"),
+ mPendingMask(0),
+ mInputReader(32)
+{
+ for (int i=0; i<numSensors; i++) {
+ mEnabled[i] = 0;
+ mDelay[i] = -1;
+ }
+ memset(mPendingEvents, 0, sizeof(mPendingEvents));
+
+ mPendingEvents[Accelerometer].version = sizeof(sensors_event_t);
+ mPendingEvents[Accelerometer].sensor = ID_A;
+ mPendingEvents[Accelerometer].type = SENSOR_TYPE_ACCELEROMETER;
+ mPendingEvents[Accelerometer].acceleration.status = SENSOR_STATUS_ACCURACY_HIGH;
+
+ mPendingEvents[MagneticField].version = sizeof(sensors_event_t);
+ mPendingEvents[MagneticField].sensor = ID_M;
+ mPendingEvents[MagneticField].type = SENSOR_TYPE_MAGNETIC_FIELD;
+ mPendingEvents[MagneticField].magnetic.status = SENSOR_STATUS_ACCURACY_HIGH;
+
+ mPendingEvents[Orientation ].version = sizeof(sensors_event_t);
+ mPendingEvents[Orientation ].sensor = ID_O;
+ mPendingEvents[Orientation ].type = SENSOR_TYPE_ORIENTATION;
+ mPendingEvents[Orientation ].orientation.status = SENSOR_STATUS_ACCURACY_HIGH;
+
+ if (data_fd) {
+ strcpy(input_sysfs_path, "/sys/class/compass/akm8975/");
+ input_sysfs_path_len = strlen(input_sysfs_path);
+ } else {
+ input_sysfs_path[0] = '\0';
+ input_sysfs_path_len = 0;
+ }
+}
+
+AkmSensor::~AkmSensor()
+{
+ for (int i=0; i<numSensors; i++) {
+ setEnable(i, 0);
+ }
+}
+
+int AkmSensor::setEnable(int32_t handle, int enabled)
+{
+ int id = handle2id(handle);
+ int err = 0;
+ char buffer[2];
+
+ switch (id) {
+ case Accelerometer:
+ strcpy(&input_sysfs_path[input_sysfs_path_len], "enable_acc");
+ break;
+ case MagneticField:
+ strcpy(&input_sysfs_path[input_sysfs_path_len], "enable_mag");
+ break;
+ case Orientation:
+ strcpy(&input_sysfs_path[input_sysfs_path_len], "enable_ori");
+ break;
+ default:
+ ALOGE("AkmSensor: unknown handle (%d)", handle);
+ return -EINVAL;
+ }
+
+ buffer[0] = '\0';
+ buffer[1] = '\0';
+
+ if (mEnabled[id] <= 0) {
+ if(enabled) buffer[0] = '1';
+ } else if (mEnabled[id] == 1) {
+ if(!enabled) buffer[0] = '0';
+ }
+
+ if (buffer[0] != '\0') {
+ err = write_sys_attribute(input_sysfs_path, buffer, 1);
+ if (err != 0) {
+ return err;
+ }
+ ALOGD("AkmSensor: set %s to %s",
+ &input_sysfs_path[input_sysfs_path_len], buffer);
+
+ /* for AKMD specification */
+ if (buffer[0] == '1') {
+ setDelay(handle, AKMD_DEFAULT_INTERVAL);
+ } else {
+ setDelay(handle, -1);
+ }
+ }
+
+ if (enabled) {
+ (mEnabled[id])++;
+ if (mEnabled[id] > 32767) mEnabled[id] = 32767;
+ } else {
+ (mEnabled[id])--;
+ if (mEnabled[id] < 0) mEnabled[id] = 0;
+ }
+ ALOGD("AkmSensor: mEnabled[%d] = %d", id, mEnabled[id]);
+
+ return err;
+}
+
+int AkmSensor::setDelay(int32_t handle, int64_t ns)
+{
+ int id = handle2id(handle);
+ int err = 0;
+ char buffer[32];
+ int bytes;
+
+ if (ns < -1 || 2147483647 < ns) {
+ ALOGE("AkmSensor: invalid delay (%lld)", ns);
+ return -EINVAL;
+ }
+
+ switch (id) {
+ case Accelerometer:
+ strcpy(&input_sysfs_path[input_sysfs_path_len], "delay_acc");
+ break;
+ case MagneticField:
+ strcpy(&input_sysfs_path[input_sysfs_path_len], "delay_mag");
+ break;
+ case Orientation:
+ strcpy(&input_sysfs_path[input_sysfs_path_len], "delay_ori");
+ break;
+ default:
+ ALOGE("AkmSensor: unknown handle (%d)", handle);
+ return -EINVAL;
+ }
+
+ if (ns != mDelay[id]) {
+ bytes = sprintf(buffer, "%lld", ns);
+ err = write_sys_attribute(input_sysfs_path, buffer, bytes);
+ if (err == 0) {
+ mDelay[id] = ns;
+ ALOGD("AkmSensor: set %s to %f ms.",
+ &input_sysfs_path[input_sysfs_path_len], ns/1000000.0f);
+ }
+ }
+
+ return err;
+}
+
+int64_t AkmSensor::getDelay(int32_t handle)
+{
+ int id = handle2id(handle);
+ if (id > 0) {
+ return mDelay[id];
+ } else {
+ return 0;
+ }
+}
+
+int AkmSensor::getEnable(int32_t handle)
+{
+ int id = handle2id(handle);
+ if (id >= 0) {
+ return mEnabled[id];
+ } else {
+ return 0;
+ }
+}
+
+int AkmSensor::readEvents(sensors_event_t* data, int count)
+{
+ if (count < 1)
+ return -EINVAL;
+
+ 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) {
+ processEvent(event->code, event->value);
+ mInputReader.next();
+ } else if (type == EV_SYN) {
+ int64_t time = timevalToNano(event->time);
+ for (int j=0 ; count && mPendingMask && j<numSensors ; j++) {
+ if (mPendingMask & (1<<j)) {
+ mPendingMask &= ~(1<<j);
+ mPendingEvents[j].timestamp = time;
+ //ALOGD("data=%8.5f,%8.5f,%8.5f",
+ //mPendingEvents[j].data[0],
+ //mPendingEvents[j].data[1],
+ //mPendingEvents[j].data[2]);
+ if (mEnabled[j]) {
+ *data++ = mPendingEvents[j];
+ count--;
+ numEventReceived++;
+ }
+ }
+ }
+ if (!mPendingMask) {
+ mInputReader.next();
+ }
+ } else {
+ ALOGE("AkmSensor: unknown event (type=%d, code=%d)",
+ type, event->code);
+ mInputReader.next();
+ }
+ }
+ return numEventReceived;
+}
+
+int AkmSensor::setAccel(sensors_event_t* data)
+{
+ int err;
+ int16_t acc[3];
+
+ acc[0] = (int16_t)(data->acceleration.x / GRAVITY_EARTH * AKSC_LSG);
+ acc[1] = (int16_t)(data->acceleration.y / GRAVITY_EARTH * AKSC_LSG);
+ acc[2] = (int16_t)(data->acceleration.z / GRAVITY_EARTH * AKSC_LSG);
+
+ strcpy(&input_sysfs_path[input_sysfs_path_len], "accel");
+ err = write_sys_attribute(input_sysfs_path, (char*)acc, 6);
+ if (err < 0) {
+ ALOGD("AkmSensor: %s write failed.",
+ &input_sysfs_path[input_sysfs_path_len]);
+ }
+ return err;
+}
+
+int AkmSensor::handle2id(int32_t handle)
+{
+ switch (handle) {
+ case ID_A:
+ return Accelerometer;
+ case ID_M:
+ return MagneticField;
+ case ID_O:
+ return Orientation;
+ default:
+ ALOGE("AkmSensor: unknown handle (%d)", handle);
+ return -EINVAL;
+ }
+}
+
+void AkmSensor::processEvent(int code, int value)
+{
+ switch (code) {
+ case EVENT_TYPE_ACCEL_X:
+ mPendingMask |= 1<<Accelerometer;
+ mPendingEvents[Accelerometer].acceleration.x = value * CONVERT_A;
+ break;
+ case EVENT_TYPE_ACCEL_Y:
+ mPendingMask |= 1<<Accelerometer;
+ mPendingEvents[Accelerometer].acceleration.y = value * CONVERT_A;
+ break;
+ case EVENT_TYPE_ACCEL_Z:
+ mPendingMask |= 1<<Accelerometer;
+ mPendingEvents[Accelerometer].acceleration.z = value * CONVERT_A;
+ break;
+
+ case EVENT_TYPE_MAGV_X:
+ mPendingMask |= 1<<MagneticField;
+ mPendingEvents[MagneticField].magnetic.x = value * CONVERT_M;
+ break;
+ case EVENT_TYPE_MAGV_Y:
+ mPendingMask |= 1<<MagneticField;
+ mPendingEvents[MagneticField].magnetic.y = value * CONVERT_M;
+ break;
+ case EVENT_TYPE_MAGV_Z:
+ mPendingMask |= 1<<MagneticField;
+ mPendingEvents[MagneticField].magnetic.z = value * CONVERT_M;
+ break;
+ case EVENT_TYPE_MAGV_STATUS:
+ mPendingMask |= 1<<MagneticField;
+ mPendingEvents[MagneticField].magnetic.status = value;
+ break;
+
+ case EVENT_TYPE_YAW:
+ mPendingMask |= 1<<Orientation;
+ mPendingEvents[Orientation].orientation.azimuth = value * CONVERT_O;
+ break;
+ case EVENT_TYPE_PITCH:
+ mPendingMask |= 1<<Orientation;
+ mPendingEvents[Orientation].orientation.pitch = value * CONVERT_O;
+ break;
+ case EVENT_TYPE_ROLL:
+ mPendingMask |= 1<<Orientation;
+ mPendingEvents[Orientation].orientation.roll = value * CONVERT_O;
+ break;
+ case EVENT_TYPE_ORIENT_STATUS:
+ mPendingMask |= 1<<Orientation;
+ mPendingEvents[Orientation].orientation.status = value;
+ break;
+ }
+}