📄 sensors_trout.c
字号:
/* * Copyright 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. */#define LOG_TAG "Sensors"#include <hardware/sensors.h>#include <fcntl.h>#include <errno.h>#include <dirent.h>#include <math.h>#include <poll.h>#include <linux/input.h>#include <linux/akm8976.h>#include <cutils/log.h>#include <cutils/atomic.h>/*****************************************************************************/#define AKM_DEVICE_NAME "/dev/akm8976_aot"#define SUPPORTED_SENSORS (SENSORS_ORIENTATION | \ SENSORS_ACCELERATION | \ SENSORS_MAGNETIC_FIELD | \ SENSORS_ORIENTATION_RAW)// sensor IDs must be a power of two and// must match values in SensorManager.java#define EVENT_TYPE_ACCEL_X ABS_X#define EVENT_TYPE_ACCEL_Y ABS_Z#define EVENT_TYPE_ACCEL_Z ABS_Y#define EVENT_TYPE_ACCEL_STATUS ABS_WHEEL#define EVENT_TYPE_YAW ABS_RX#define EVENT_TYPE_PITCH ABS_RY#define EVENT_TYPE_ROLL ABS_RZ#define EVENT_TYPE_ORIENT_STATUS ABS_RUDDER#define EVENT_TYPE_MAGV_X ABS_HAT0X#define EVENT_TYPE_MAGV_Y ABS_HAT0Y#define EVENT_TYPE_MAGV_Z ABS_BRAKE#define EVENT_TYPE_TEMPERATURE ABS_THROTTLE#define EVENT_TYPE_STEP_COUNT ABS_GAS// 720 LSG = 1G#define LSG (720.0f)// conversion of acceleration data to SI units (m/s^2)#define CONVERT_A (GRAVITY_EARTH / LSG)#define CONVERT_A_X (CONVERT_A)#define CONVERT_A_Y (-CONVERT_A)#define CONVERT_A_Z (CONVERT_A)// conversion of magnetic data to uT units#define CONVERT_M (1.0f/16.0f)#define CONVERT_M_X (CONVERT_M)#define CONVERT_M_Y (CONVERT_M)#define CONVERT_M_Z (CONVERT_M)#define SENSOR_STATE_MASK (0x7FFF)/*****************************************************************************/static int sAkmFD = -1;static uint32_t sActiveSensors = 0;/*****************************************************************************//* * We use a Least Mean Squares filter to smooth out the output of the yaw * sensor. * * The goal is to estimate the output of the sensor based on previous acquired * samples. * * We approximate the input by a line with the equation: * Z(t) = a * t + b * * We use the Least Mean Squares method to calculate a and b so that the * distance between the line and the measured COUNT inputs Z(t) is minimal. * * In practice we only need to compute b, which is the value we're looking for * (it's the estimated Z at t=0). However, to improve the latency a little bit, * we're going to discard a certain number of samples that are too far from * the estimated line and compute b again with the new (trimmed down) samples. * * notes: * 'a' is the slope of the line, and physicaly represent how fast the input * is changing. In our case, how fast the yaw is changing, that is, how fast the * user is spinning the device (in degre / nanosecond). This value should be * zero when the device is not moving. * * The minimum distance between the line and the samples (which we are not * explicitely computing here), is an indication of how bad the samples are * and gives an idea of the "quality" of the estimation (well, really of the * sensor values). * *//* sensor rate in me */#define SENSORS_RATE_MS 20/* timeout (constant value) in ms */#define SENSORS_TIMEOUT_MS 100/* # of samples to look at in the past for filtering */#define COUNT 24/* prediction ratio */#define PREDICTION_RATIO (1.0f/3.0f)/* prediction time in seconds (>=0) */#define PREDICTION_TIME ((SENSORS_RATE_MS*COUNT/1000.0f)*PREDICTION_RATIO)static float mV[COUNT*2];static float mT[COUNT*2];static int mIndex;static inlinefloat normalize(float x){ x *= (1.0f / 360.0f); if (fabsf(x) >= 0.5f) x = x - ceilf(x + 0.5f) + 1.0f; if (x < 0) x += 1.0f; x *= 360.0f; return x;}static void LMSInit(void){ memset(mV, 0, sizeof(mV)); memset(mT, 0, sizeof(mT)); mIndex = COUNT;}static float LMSFilter(int64_t time, int v){ const float ns = 1.0f / 1000000000.0f; const float t = time*ns; float v1 = mV[mIndex]; if ((v-v1) > 180) { v -= 360; } else if ((v1-v) > 180) { v += 360; } /* Manage the circular buffer, we write the data twice spaced by COUNT * values, so that we don't have to memcpy() the array when it's full */ mIndex++; if (mIndex >= COUNT*2) mIndex = COUNT; mV[mIndex] = v; mT[mIndex] = t; mV[mIndex-COUNT] = v; mT[mIndex-COUNT] = t; float A, B, C, D, E; float a, b; int i; A = B = C = D = E = 0; for (i=0 ; i<COUNT-1 ; i++) { const int j = mIndex - 1 - i; const float Z = mV[j]; const float T = 0.5f*(mT[j] + mT[j+1]) - t; float dT = mT[j] - mT[j+1]; dT *= dT; A += Z*dT; B += T*(T*dT); C += (T*dT); D += Z*(T*dT); E += dT; } b = (A*B + C*D) / (E*B + C*C); a = (E*b - A) / C; float f = b + PREDICTION_TIME*a; //LOGD("A=%f, B=%f, C=%f, D=%f, E=%f", A,B,C,D,E); //LOGD("%lld %d %f %f", time, v, f, a); f = normalize(f); return f;}/*****************************************************************************/static int open_input(){ /* scan all input drivers and look for "compass" */ int fd = -1; const char *dirname = "/dev/input"; char devname[PATH_MAX]; char *filename; DIR *dir; struct dirent *de; dir = opendir(dirname); if(dir == NULL) return -1; strcpy(devname, dirname); filename = devname + strlen(devname); *filename++ = '/'; while((de = readdir(dir))) { if(de->d_name[0] == '.' && (de->d_name[1] == '\0' || (de->d_name[1] == '.' && de->d_name[2] == '\0'))) continue; strcpy(filename, de->d_name); fd = open(devname, O_RDONLY); if (fd>=0) { char name[80]; if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) { name[0] = '\0'; } if (!strcmp(name, "compass")) { LOGD("using %s (name=%s)", devname, name); break; } close(fd); fd = -1; } } closedir(dir); if (fd < 0) { LOGE("Couldn't find or open 'compass' driver (%s)", strerror(errno)); } return fd;}static int open_akm(){ if (sAkmFD <= 0) { sAkmFD = open(AKM_DEVICE_NAME, O_RDONLY); LOGD("%s, fd=%d", __PRETTY_FUNCTION__, sAkmFD); LOGE_IF(sAkmFD<0, "Couldn't open %s (%s)", AKM_DEVICE_NAME, strerror(errno)); if (sAkmFD >= 0) { sActiveSensors = 0; } } return sAkmFD;}static void close_akm(){ if (sAkmFD > 0) { LOGD("%s, fd=%d", __PRETTY_FUNCTION__, sAkmFD); close(sAkmFD); sAkmFD = -1; }}static void enable_disable(int fd, uint32_t sensors, uint32_t mask){ if (fd<0) return; short flags; if (sensors & SENSORS_ORIENTATION_RAW) { sensors |= SENSORS_ORIENTATION; mask |= SENSORS_ORIENTATION; } else if (mask & SENSORS_ORIENTATION_RAW) { mask |= SENSORS_ORIENTATION; } if (mask & SENSORS_ORIENTATION) { flags = (sensors & SENSORS_ORIENTATION) ? 1 : 0; if (ioctl(fd, ECS_IOCTL_APP_SET_MFLAG, &flags) < 0) { LOGE("ECS_IOCTL_APP_SET_MFLAG error (%s)", strerror(errno)); } } if (mask & SENSORS_ACCELERATION) { flags = (sensors & SENSORS_ACCELERATION) ? 1 : 0; if (ioctl(fd, ECS_IOCTL_APP_SET_AFLAG, &flags) < 0) { LOGE("ECS_IOCTL_APP_SET_AFLAG error (%s)", strerror(errno)); } } if (mask & SENSORS_TEMPERATURE) { flags = (sensors & SENSORS_TEMPERATURE) ? 1 : 0; if (ioctl(fd, ECS_IOCTL_APP_SET_TFLAG, &flags) < 0) { LOGE("ECS_IOCTL_APP_SET_TFLAG error (%s)", strerror(errno)); } }#ifdef ECS_IOCTL_APP_SET_MVFLAG if (mask & SENSORS_MAGNETIC_FIELD) { flags = (sensors & SENSORS_MAGNETIC_FIELD) ? 1 : 0; if (ioctl(fd, ECS_IOCTL_APP_SET_MVFLAG, &flags) < 0) { LOGE("ECS_IOCTL_APP_SET_MVFLAG error (%s)", strerror(errno));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -