move sensorservice from frameworks/base to frameworks/native
this commit also imports all of sensorservice history.
Change-Id: Iadffcc92be600c48175b8afadcb15b6648532b3f
diff --git a/cmds/sensorservice/Android.mk b/cmds/sensorservice/Android.mk
new file mode 100644
index 0000000..0811be5
--- /dev/null
+++ b/cmds/sensorservice/Android.mk
@@ -0,0 +1,19 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ main_sensorservice.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libsensorservice \
+ libbinder \
+ libutils
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/../../services/sensorservice
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE:= sensorservice
+
+include $(BUILD_EXECUTABLE)
diff --git a/cmds/sensorservice/main_sensorservice.cpp b/cmds/sensorservice/main_sensorservice.cpp
new file mode 100644
index 0000000..8610627
--- /dev/null
+++ b/cmds/sensorservice/main_sensorservice.cpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2011 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 <binder/BinderService.h>
+#include <SensorService.h>
+
+using namespace android;
+
+int main(int argc, char** argv) {
+ SensorService::publishAndJoinThreadPool();
+ return 0;
+}
diff --git a/services/sensorservice/Android.mk b/services/sensorservice/Android.mk
new file mode 100644
index 0000000..6a302c0
--- /dev/null
+++ b/services/sensorservice/Android.mk
@@ -0,0 +1,31 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ CorrectedGyroSensor.cpp \
+ Fusion.cpp \
+ GravitySensor.cpp \
+ LinearAccelerationSensor.cpp \
+ OrientationSensor.cpp \
+ RotationVectorSensor.cpp \
+ SensorDevice.cpp \
+ SensorFusion.cpp \
+ SensorInterface.cpp \
+ SensorService.cpp \
+
+
+LOCAL_CFLAGS:= -DLOG_TAG=\"SensorService\"
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libhardware \
+ libutils \
+ libbinder \
+ libui \
+ libgui
+
+
+
+LOCAL_MODULE:= libsensorservice
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/services/sensorservice/CorrectedGyroSensor.cpp b/services/sensorservice/CorrectedGyroSensor.cpp
new file mode 100644
index 0000000..1857443
--- /dev/null
+++ b/services/sensorservice/CorrectedGyroSensor.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2011 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 <stdint.h>
+#include <math.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+
+#include <hardware/sensors.h>
+
+#include "CorrectedGyroSensor.h"
+#include "SensorDevice.h"
+#include "SensorFusion.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+CorrectedGyroSensor::CorrectedGyroSensor(sensor_t const* list, size_t count)
+ : mSensorDevice(SensorDevice::getInstance()),
+ mSensorFusion(SensorFusion::getInstance())
+{
+ for (size_t i=0 ; i<count ; i++) {
+ if (list[i].type == SENSOR_TYPE_GYROSCOPE) {
+ mGyro = Sensor(list + i);
+ break;
+ }
+ }
+}
+
+bool CorrectedGyroSensor::process(sensors_event_t* outEvent,
+ const sensors_event_t& event)
+{
+ if (event.type == SENSOR_TYPE_GYROSCOPE) {
+ const vec3_t bias(mSensorFusion.getGyroBias());
+ *outEvent = event;
+ outEvent->data[0] -= bias.x;
+ outEvent->data[1] -= bias.y;
+ outEvent->data[2] -= bias.z;
+ outEvent->sensor = '_cgy';
+ return true;
+ }
+ return false;
+}
+
+status_t CorrectedGyroSensor::activate(void* ident, bool enabled) {
+ mSensorDevice.activate(this, mGyro.getHandle(), enabled);
+ return mSensorFusion.activate(this, enabled);
+}
+
+status_t CorrectedGyroSensor::setDelay(void* ident, int handle, int64_t ns) {
+ mSensorDevice.setDelay(this, mGyro.getHandle(), ns);
+ return mSensorFusion.setDelay(this, ns);
+}
+
+Sensor CorrectedGyroSensor::getSensor() const {
+ sensor_t hwSensor;
+ hwSensor.name = "Corrected Gyroscope Sensor";
+ hwSensor.vendor = "Google Inc.";
+ hwSensor.version = 1;
+ hwSensor.handle = '_cgy';
+ hwSensor.type = SENSOR_TYPE_GYROSCOPE;
+ hwSensor.maxRange = mGyro.getMaxValue();
+ hwSensor.resolution = mGyro.getResolution();
+ hwSensor.power = mSensorFusion.getPowerUsage();
+ hwSensor.minDelay = mGyro.getMinDelay();
+ Sensor sensor(&hwSensor);
+ return sensor;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/services/sensorservice/CorrectedGyroSensor.h b/services/sensorservice/CorrectedGyroSensor.h
new file mode 100644
index 0000000..3c49c08
--- /dev/null
+++ b/services/sensorservice/CorrectedGyroSensor.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#ifndef ANDROID_CORRECTED_GYRO_SENSOR_H
+#define ANDROID_CORRECTED_GYRO_SENSOR_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <gui/Sensor.h>
+
+#include "SensorInterface.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+class SensorDevice;
+class SensorFusion;
+
+class CorrectedGyroSensor : public SensorInterface {
+ SensorDevice& mSensorDevice;
+ SensorFusion& mSensorFusion;
+ Sensor mGyro;
+
+public:
+ CorrectedGyroSensor(sensor_t const* list, size_t count);
+ virtual bool process(sensors_event_t* outEvent,
+ const sensors_event_t& event);
+ virtual status_t activate(void* ident, bool enabled);
+ virtual status_t setDelay(void* ident, int handle, int64_t ns);
+ virtual Sensor getSensor() const;
+ virtual bool isVirtual() const { return true; }
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_CORRECTED_GYRO_SENSOR_H
diff --git a/services/sensorservice/Fusion.cpp b/services/sensorservice/Fusion.cpp
new file mode 100644
index 0000000..2b6b793
--- /dev/null
+++ b/services/sensorservice/Fusion.cpp
@@ -0,0 +1,464 @@
+/*
+ * Copyright (C) 2011 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 <stdio.h>
+
+#include <utils/Log.h>
+
+#include "Fusion.h"
+
+namespace android {
+
+// -----------------------------------------------------------------------
+
+/*
+ * gyroVAR gives the measured variance of the gyro's output per
+ * Hz (or variance at 1 Hz). This is an "intrinsic" parameter of the gyro,
+ * which is independent of the sampling frequency.
+ *
+ * The variance of gyro's output at a given sampling period can be
+ * calculated as:
+ * variance(T) = gyroVAR / T
+ *
+ * The variance of the INTEGRATED OUTPUT at a given sampling period can be
+ * calculated as:
+ * variance_integrate_output(T) = gyroVAR * T
+ *
+ */
+static const float gyroVAR = 1e-7; // (rad/s)^2 / Hz
+static const float biasVAR = 1e-8; // (rad/s)^2 / s (guessed)
+
+/*
+ * Standard deviations of accelerometer and magnetometer
+ */
+static const float accSTDEV = 0.05f; // m/s^2 (measured 0.08 / CDD 0.05)
+static const float magSTDEV = 0.5f; // uT (measured 0.7 / CDD 0.5)
+
+static const float SYMMETRY_TOLERANCE = 1e-10f;
+
+/*
+ * Accelerometer updates will not be performed near free fall to avoid
+ * ill-conditioning and div by zeros.
+ * Threshhold: 10% of g, in m/s^2
+ */
+static const float FREE_FALL_THRESHOLD = 0.981f;
+static const float FREE_FALL_THRESHOLD_SQ =
+ FREE_FALL_THRESHOLD*FREE_FALL_THRESHOLD;
+
+/*
+ * The geomagnetic-field should be between 30uT and 60uT.
+ * Fields strengths greater than this likely indicate a local magnetic
+ * disturbance which we do not want to update into the fused frame.
+ */
+static const float MAX_VALID_MAGNETIC_FIELD = 100; // uT
+static const float MAX_VALID_MAGNETIC_FIELD_SQ =
+ MAX_VALID_MAGNETIC_FIELD*MAX_VALID_MAGNETIC_FIELD;
+
+/*
+ * Values of the field smaller than this should be ignored in fusion to avoid
+ * ill-conditioning. This state can happen with anomalous local magnetic
+ * disturbances canceling the Earth field.
+ */
+static const float MIN_VALID_MAGNETIC_FIELD = 10; // uT
+static const float MIN_VALID_MAGNETIC_FIELD_SQ =
+ MIN_VALID_MAGNETIC_FIELD*MIN_VALID_MAGNETIC_FIELD;
+
+/*
+ * If the cross product of two vectors has magnitude squared less than this,
+ * we reject it as invalid due to alignment of the vectors.
+ * This threshold is used to check for the case where the magnetic field sample
+ * is parallel to the gravity field, which can happen in certain places due
+ * to magnetic field disturbances.
+ */
+static const float MIN_VALID_CROSS_PRODUCT_MAG = 1.0e-3;
+static const float MIN_VALID_CROSS_PRODUCT_MAG_SQ =
+ MIN_VALID_CROSS_PRODUCT_MAG*MIN_VALID_CROSS_PRODUCT_MAG;
+
+// -----------------------------------------------------------------------
+
+template <typename TYPE, size_t C, size_t R>
+static mat<TYPE, R, R> scaleCovariance(
+ const mat<TYPE, C, R>& A,
+ const mat<TYPE, C, C>& P) {
+ // A*P*transpose(A);
+ mat<TYPE, R, R> APAt;
+ for (size_t r=0 ; r<R ; r++) {
+ for (size_t j=r ; j<R ; j++) {
+ double apat(0);
+ for (size_t c=0 ; c<C ; c++) {
+ double v(A[c][r]*P[c][c]*0.5);
+ for (size_t k=c+1 ; k<C ; k++)
+ v += A[k][r] * P[c][k];
+ apat += 2 * v * A[c][j];
+ }
+ APAt[j][r] = apat;
+ APAt[r][j] = apat;
+ }
+ }
+ return APAt;
+}
+
+template <typename TYPE, typename OTHER_TYPE>
+static mat<TYPE, 3, 3> crossMatrix(const vec<TYPE, 3>& p, OTHER_TYPE diag) {
+ mat<TYPE, 3, 3> r;
+ r[0][0] = diag;
+ r[1][1] = diag;
+ r[2][2] = diag;
+ r[0][1] = p.z;
+ r[1][0] =-p.z;
+ r[0][2] =-p.y;
+ r[2][0] = p.y;
+ r[1][2] = p.x;
+ r[2][1] =-p.x;
+ return r;
+}
+
+
+template<typename TYPE, size_t SIZE>
+class Covariance {
+ mat<TYPE, SIZE, SIZE> mSumXX;
+ vec<TYPE, SIZE> mSumX;
+ size_t mN;
+public:
+ Covariance() : mSumXX(0.0f), mSumX(0.0f), mN(0) { }
+ void update(const vec<TYPE, SIZE>& x) {
+ mSumXX += x*transpose(x);
+ mSumX += x;
+ mN++;
+ }
+ mat<TYPE, SIZE, SIZE> operator()() const {
+ const float N = 1.0f / mN;
+ return mSumXX*N - (mSumX*transpose(mSumX))*(N*N);
+ }
+ void reset() {
+ mN = 0;
+ mSumXX = 0;
+ mSumX = 0;
+ }
+ size_t getCount() const {
+ return mN;
+ }
+};
+
+// -----------------------------------------------------------------------
+
+Fusion::Fusion() {
+ Phi[0][1] = 0;
+ Phi[1][1] = 1;
+
+ Ba.x = 0;
+ Ba.y = 0;
+ Ba.z = 1;
+
+ Bm.x = 0;
+ Bm.y = 1;
+ Bm.z = 0;
+
+ x0 = 0;
+ x1 = 0;
+
+ init();
+}
+
+void Fusion::init() {
+ mInitState = 0;
+
+ mGyroRate = 0;
+
+ mCount[0] = 0;
+ mCount[1] = 0;
+ mCount[2] = 0;
+
+ mData = 0;
+}
+
+void Fusion::initFusion(const vec4_t& q, float dT)
+{
+ // initial estimate: E{ x(t0) }
+ x0 = q;
+ x1 = 0;
+
+ // process noise covariance matrix: G.Q.Gt, with
+ //
+ // G = | -1 0 | Q = | q00 q10 |
+ // | 0 1 | | q01 q11 |
+ //
+ // q00 = sv^2.dt + 1/3.su^2.dt^3
+ // q10 = q01 = 1/2.su^2.dt^2
+ // q11 = su^2.dt
+ //
+
+ const float dT2 = dT*dT;
+ const float dT3 = dT2*dT;
+
+ // variance of integrated output at 1/dT Hz (random drift)
+ const float q00 = gyroVAR * dT + 0.33333f * biasVAR * dT3;
+
+ // variance of drift rate ramp
+ const float q11 = biasVAR * dT;
+ const float q10 = 0.5f * biasVAR * dT2;
+ const float q01 = q10;
+
+ GQGt[0][0] = q00; // rad^2
+ GQGt[1][0] = -q10;
+ GQGt[0][1] = -q01;
+ GQGt[1][1] = q11; // (rad/s)^2
+
+ // initial covariance: Var{ x(t0) }
+ // TODO: initialize P correctly
+ P = 0;
+
+ // it is unclear how to set the initial covariance. It does affect
+ // how quickly the fusion converges. Experimentally it would take
+ // about 10 seconds at 200 Hz to estimate the gyro-drift with an
+ // initial covariance of 0, and about a second with an initial covariance
+ // of about 1 deg/s.
+ const float covv = 0;
+ const float covu = 0.5f * (float(M_PI) / 180);
+ mat33_t& Pv = P[0][0];
+ Pv[0][0] = covv;
+ Pv[1][1] = covv;
+ Pv[2][2] = covv;
+ mat33_t& Pu = P[1][1];
+ Pu[0][0] = covu;
+ Pu[1][1] = covu;
+ Pu[2][2] = covu;
+}
+
+bool Fusion::hasEstimate() const {
+ return (mInitState == (MAG|ACC|GYRO));
+}
+
+bool Fusion::checkInitComplete(int what, const vec3_t& d, float dT) {
+ if (hasEstimate())
+ return true;
+
+ if (what == ACC) {
+ mData[0] += d * (1/length(d));
+ mCount[0]++;
+ mInitState |= ACC;
+ } else if (what == MAG) {
+ mData[1] += d * (1/length(d));
+ mCount[1]++;
+ mInitState |= MAG;
+ } else if (what == GYRO) {
+ mGyroRate = dT;
+ mData[2] += d*dT;
+ mCount[2]++;
+ if (mCount[2] == 64) {
+ // 64 samples is good enough to estimate the gyro drift and
+ // doesn't take too much time.
+ mInitState |= GYRO;
+ }
+ }
+
+ if (mInitState == (MAG|ACC|GYRO)) {
+ // Average all the values we collected so far
+ mData[0] *= 1.0f/mCount[0];
+ mData[1] *= 1.0f/mCount[1];
+ mData[2] *= 1.0f/mCount[2];
+
+ // calculate the MRPs from the data collection, this gives us
+ // a rough estimate of our initial state
+ mat33_t R;
+ vec3_t up(mData[0]);
+ vec3_t east(cross_product(mData[1], up));
+ east *= 1/length(east);
+ vec3_t north(cross_product(up, east));
+ R << east << north << up;
+ const vec4_t q = matrixToQuat(R);
+
+ initFusion(q, mGyroRate);
+ }
+
+ return false;
+}
+
+void Fusion::handleGyro(const vec3_t& w, float dT) {
+ if (!checkInitComplete(GYRO, w, dT))
+ return;
+
+ predict(w, dT);
+}
+
+status_t Fusion::handleAcc(const vec3_t& a) {
+ // ignore acceleration data if we're close to free-fall
+ if (length_squared(a) < FREE_FALL_THRESHOLD_SQ) {
+ return BAD_VALUE;
+ }
+
+ if (!checkInitComplete(ACC, a))
+ return BAD_VALUE;
+
+ const float l = 1/length(a);
+ update(a*l, Ba, accSTDEV*l);
+ return NO_ERROR;
+}
+
+status_t Fusion::handleMag(const vec3_t& m) {
+ // the geomagnetic-field should be between 30uT and 60uT
+ // reject if too large to avoid spurious magnetic sources
+ const float magFieldSq = length_squared(m);
+ if (magFieldSq > MAX_VALID_MAGNETIC_FIELD_SQ) {
+ return BAD_VALUE;
+ } else if (magFieldSq < MIN_VALID_MAGNETIC_FIELD_SQ) {
+ // Also reject if too small since we will get ill-defined (zero mag)
+ // cross-products below
+ return BAD_VALUE;
+ }
+
+ if (!checkInitComplete(MAG, m))
+ return BAD_VALUE;
+
+ // Orthogonalize the magnetic field to the gravity field, mapping it into
+ // tangent to Earth.
+ const vec3_t up( getRotationMatrix() * Ba );
+ const vec3_t east( cross_product(m, up) );
+
+ // If the m and up vectors align, the cross product magnitude will
+ // approach 0.
+ // Reject this case as well to avoid div by zero problems and
+ // ill-conditioning below.
+ if (length_squared(east) < MIN_VALID_CROSS_PRODUCT_MAG_SQ) {
+ return BAD_VALUE;
+ }
+
+ // If we have created an orthogonal magnetic field successfully,
+ // then pass it in as the update.
+ vec3_t north( cross_product(up, east) );
+
+ const float l = 1 / length(north);
+ north *= l;
+
+ update(north, Bm, magSTDEV*l);
+ return NO_ERROR;
+}
+
+void Fusion::checkState() {
+ // P needs to stay positive semidefinite or the fusion diverges. When we
+ // detect divergence, we reset the fusion.
+ // TODO(braun): Instead, find the reason for the divergence and fix it.
+
+ if (!isPositiveSemidefinite(P[0][0], SYMMETRY_TOLERANCE) ||
+ !isPositiveSemidefinite(P[1][1], SYMMETRY_TOLERANCE)) {
+ ALOGW("Sensor fusion diverged; resetting state.");
+ P = 0;
+ }
+}
+
+vec4_t Fusion::getAttitude() const {
+ return x0;
+}
+
+vec3_t Fusion::getBias() const {
+ return x1;
+}
+
+mat33_t Fusion::getRotationMatrix() const {
+ return quatToMatrix(x0);
+}
+
+mat34_t Fusion::getF(const vec4_t& q) {
+ mat34_t F;
+
+ // This is used to compute the derivative of q
+ // F = | [q.xyz]x |
+ // | -q.xyz |
+
+ F[0].x = q.w; F[1].x =-q.z; F[2].x = q.y;
+ F[0].y = q.z; F[1].y = q.w; F[2].y =-q.x;
+ F[0].z =-q.y; F[1].z = q.x; F[2].z = q.w;
+ F[0].w =-q.x; F[1].w =-q.y; F[2].w =-q.z;
+ return F;
+}
+
+void Fusion::predict(const vec3_t& w, float dT) {
+ const vec4_t q = x0;
+ const vec3_t b = x1;
+ const vec3_t we = w - b;
+ const vec4_t dq = getF(q)*((0.5f*dT)*we);
+ x0 = normalize_quat(q + dq);
+
+ // P(k+1) = F*P(k)*Ft + G*Q*Gt
+
+ // Phi = | Phi00 Phi10 |
+ // | 0 1 |
+ const mat33_t I33(1);
+ const mat33_t I33dT(dT);
+ const mat33_t wx(crossMatrix(we, 0));
+ const mat33_t wx2(wx*wx);
+ const float lwedT = length(we)*dT;
+ const float ilwe = 1/length(we);
+ const float k0 = (1-cosf(lwedT))*(ilwe*ilwe);
+ const float k1 = sinf(lwedT);
+
+ Phi[0][0] = I33 - wx*(k1*ilwe) + wx2*k0;
+ Phi[1][0] = wx*k0 - I33dT - wx2*(ilwe*ilwe*ilwe)*(lwedT-k1);
+
+ P = Phi*P*transpose(Phi) + GQGt;
+
+ checkState();
+}
+
+void Fusion::update(const vec3_t& z, const vec3_t& Bi, float sigma) {
+ vec4_t q(x0);
+ // measured vector in body space: h(p) = A(p)*Bi
+ const mat33_t A(quatToMatrix(q));
+ const vec3_t Bb(A*Bi);
+
+ // Sensitivity matrix H = dh(p)/dp
+ // H = [ L 0 ]
+ const mat33_t L(crossMatrix(Bb, 0));
+
+ // gain...
+ // K = P*Ht / [H*P*Ht + R]
+ vec<mat33_t, 2> K;
+ const mat33_t R(sigma*sigma);
+ const mat33_t S(scaleCovariance(L, P[0][0]) + R);
+ const mat33_t Si(invert(S));
+ const mat33_t LtSi(transpose(L)*Si);
+ K[0] = P[0][0] * LtSi;
+ K[1] = transpose(P[1][0])*LtSi;
+
+ // update...
+ // P = (I-K*H) * P
+ // P -= K*H*P
+ // | K0 | * | L 0 | * P = | K0*L 0 | * | P00 P10 | = | K0*L*P00 K0*L*P10 |
+ // | K1 | | K1*L 0 | | P01 P11 | | K1*L*P00 K1*L*P10 |
+ // Note: the Joseph form is numerically more stable and given by:
+ // P = (I-KH) * P * (I-KH)' + K*R*R'
+ const mat33_t K0L(K[0] * L);
+ const mat33_t K1L(K[1] * L);
+ P[0][0] -= K0L*P[0][0];
+ P[1][1] -= K1L*P[1][0];
+ P[1][0] -= K0L*P[1][0];
+ P[0][1] = transpose(P[1][0]);
+
+ const vec3_t e(z - Bb);
+ const vec3_t dq(K[0]*e);
+ const vec3_t db(K[1]*e);
+
+ q += getF(q)*(0.5f*dq);
+ x0 = normalize_quat(q);
+ x1 += db;
+
+ checkState();
+}
+
+// -----------------------------------------------------------------------
+
+}; // namespace android
+
diff --git a/services/sensorservice/Fusion.h b/services/sensorservice/Fusion.h
new file mode 100644
index 0000000..7062999
--- /dev/null
+++ b/services/sensorservice/Fusion.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#ifndef ANDROID_FUSION_H
+#define ANDROID_FUSION_H
+
+#include <utils/Errors.h>
+
+#include "quat.h"
+#include "mat.h"
+#include "vec.h"
+
+namespace android {
+
+typedef mat<float, 3, 4> mat34_t;
+
+class Fusion {
+ /*
+ * the state vector is made of two sub-vector containing respectively:
+ * - modified Rodrigues parameters
+ * - the estimated gyro bias
+ */
+ quat_t x0;
+ vec3_t x1;
+
+ /*
+ * the predicated covariance matrix is made of 4 3x3 sub-matrices and it is
+ * semi-definite positive.
+ *
+ * P = | P00 P10 | = | P00 P10 |
+ * | P01 P11 | | P10t P11 |
+ *
+ * Since P01 = transpose(P10), the code below never calculates or
+ * stores P01.
+ */
+ mat<mat33_t, 2, 2> P;
+
+ /*
+ * the process noise covariance matrix
+ */
+ mat<mat33_t, 2, 2> GQGt;
+
+public:
+ Fusion();
+ void init();
+ void handleGyro(const vec3_t& w, float dT);
+ status_t handleAcc(const vec3_t& a);
+ status_t handleMag(const vec3_t& m);
+ vec4_t getAttitude() const;
+ vec3_t getBias() const;
+ mat33_t getRotationMatrix() const;
+ bool hasEstimate() const;
+
+private:
+ mat<mat33_t, 2, 2> Phi;
+ vec3_t Ba, Bm;
+ uint32_t mInitState;
+ float mGyroRate;
+ vec<vec3_t, 3> mData;
+ size_t mCount[3];
+ enum { ACC=0x1, MAG=0x2, GYRO=0x4 };
+ bool checkInitComplete(int, const vec3_t& w, float d = 0);
+ void initFusion(const vec4_t& q0, float dT);
+ void checkState();
+ void predict(const vec3_t& w, float dT);
+ void update(const vec3_t& z, const vec3_t& Bi, float sigma);
+ static mat34_t getF(const vec4_t& p);
+};
+
+}; // namespace android
+
+#endif // ANDROID_FUSION_H
diff --git a/services/sensorservice/GravitySensor.cpp b/services/sensorservice/GravitySensor.cpp
new file mode 100644
index 0000000..c57715f
--- /dev/null
+++ b/services/sensorservice/GravitySensor.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2010 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 <stdint.h>
+#include <math.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+
+#include <hardware/sensors.h>
+
+#include "GravitySensor.h"
+#include "SensorDevice.h"
+#include "SensorFusion.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+GravitySensor::GravitySensor(sensor_t const* list, size_t count)
+ : mSensorDevice(SensorDevice::getInstance()),
+ mSensorFusion(SensorFusion::getInstance())
+{
+ for (size_t i=0 ; i<count ; i++) {
+ if (list[i].type == SENSOR_TYPE_ACCELEROMETER) {
+ mAccelerometer = Sensor(list + i);
+ break;
+ }
+ }
+}
+
+bool GravitySensor::process(sensors_event_t* outEvent,
+ const sensors_event_t& event)
+{
+ const static double NS2S = 1.0 / 1000000000.0;
+ if (event.type == SENSOR_TYPE_ACCELEROMETER) {
+ vec3_t g;
+ if (!mSensorFusion.hasEstimate())
+ return false;
+ const mat33_t R(mSensorFusion.getRotationMatrix());
+ // FIXME: we need to estimate the length of gravity because
+ // the accelerometer may have a small scaling error. This
+ // translates to an offset in the linear-acceleration sensor.
+ g = R[2] * GRAVITY_EARTH;
+
+ *outEvent = event;
+ outEvent->data[0] = g.x;
+ outEvent->data[1] = g.y;
+ outEvent->data[2] = g.z;
+ outEvent->sensor = '_grv';
+ outEvent->type = SENSOR_TYPE_GRAVITY;
+ return true;
+ }
+ return false;
+}
+
+status_t GravitySensor::activate(void* ident, bool enabled) {
+ return mSensorFusion.activate(this, enabled);
+}
+
+status_t GravitySensor::setDelay(void* ident, int handle, int64_t ns) {
+ return mSensorFusion.setDelay(this, ns);
+}
+
+Sensor GravitySensor::getSensor() const {
+ sensor_t hwSensor;
+ hwSensor.name = "Gravity Sensor";
+ hwSensor.vendor = "Google Inc.";
+ hwSensor.version = 3;
+ hwSensor.handle = '_grv';
+ hwSensor.type = SENSOR_TYPE_GRAVITY;
+ hwSensor.maxRange = GRAVITY_EARTH * 2;
+ hwSensor.resolution = mAccelerometer.getResolution();
+ hwSensor.power = mSensorFusion.getPowerUsage();
+ hwSensor.minDelay = mSensorFusion.getMinDelay();
+ Sensor sensor(&hwSensor);
+ return sensor;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/services/sensorservice/GravitySensor.h b/services/sensorservice/GravitySensor.h
new file mode 100644
index 0000000..ac177c4
--- /dev/null
+++ b/services/sensorservice/GravitySensor.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef ANDROID_GRAVITY_SENSOR_H
+#define ANDROID_GRAVITY_SENSOR_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <gui/Sensor.h>
+
+#include "SensorInterface.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+class SensorDevice;
+class SensorFusion;
+
+class GravitySensor : public SensorInterface {
+ SensorDevice& mSensorDevice;
+ SensorFusion& mSensorFusion;
+ Sensor mAccelerometer;
+
+public:
+ GravitySensor(sensor_t const* list, size_t count);
+ virtual bool process(sensors_event_t* outEvent,
+ const sensors_event_t& event);
+ virtual status_t activate(void* ident, bool enabled);
+ virtual status_t setDelay(void* ident, int handle, int64_t ns);
+ virtual Sensor getSensor() const;
+ virtual bool isVirtual() const { return true; }
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_GRAVITY_SENSOR_H
diff --git a/services/sensorservice/LinearAccelerationSensor.cpp b/services/sensorservice/LinearAccelerationSensor.cpp
new file mode 100644
index 0000000..f0054f2
--- /dev/null
+++ b/services/sensorservice/LinearAccelerationSensor.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2010 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 <stdint.h>
+#include <math.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+
+#include <hardware/sensors.h>
+
+#include "LinearAccelerationSensor.h"
+#include "SensorDevice.h"
+#include "SensorFusion.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+LinearAccelerationSensor::LinearAccelerationSensor(sensor_t const* list, size_t count)
+ : mSensorDevice(SensorDevice::getInstance()),
+ mGravitySensor(list, count)
+{
+}
+
+bool LinearAccelerationSensor::process(sensors_event_t* outEvent,
+ const sensors_event_t& event)
+{
+ bool result = mGravitySensor.process(outEvent, event);
+ if (result && event.type == SENSOR_TYPE_ACCELEROMETER) {
+ outEvent->data[0] = event.acceleration.x - outEvent->data[0];
+ outEvent->data[1] = event.acceleration.y - outEvent->data[1];
+ outEvent->data[2] = event.acceleration.z - outEvent->data[2];
+ outEvent->sensor = '_lin';
+ outEvent->type = SENSOR_TYPE_LINEAR_ACCELERATION;
+ return true;
+ }
+ return false;
+}
+
+status_t LinearAccelerationSensor::activate(void* ident, bool enabled) {
+ return mGravitySensor.activate(this, enabled);
+}
+
+status_t LinearAccelerationSensor::setDelay(void* ident, int handle, int64_t ns) {
+ return mGravitySensor.setDelay(this, handle, ns);
+}
+
+Sensor LinearAccelerationSensor::getSensor() const {
+ Sensor gsensor(mGravitySensor.getSensor());
+ sensor_t hwSensor;
+ hwSensor.name = "Linear Acceleration Sensor";
+ hwSensor.vendor = "Google Inc.";
+ hwSensor.version = gsensor.getVersion();
+ hwSensor.handle = '_lin';
+ hwSensor.type = SENSOR_TYPE_LINEAR_ACCELERATION;
+ hwSensor.maxRange = gsensor.getMaxValue();
+ hwSensor.resolution = gsensor.getResolution();
+ hwSensor.power = gsensor.getPowerUsage();
+ hwSensor.minDelay = gsensor.getMinDelay();
+ Sensor sensor(&hwSensor);
+ return sensor;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/services/sensorservice/LinearAccelerationSensor.h b/services/sensorservice/LinearAccelerationSensor.h
new file mode 100644
index 0000000..5deb24f
--- /dev/null
+++ b/services/sensorservice/LinearAccelerationSensor.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef ANDROID_LINEAR_ACCELERATION_SENSOR_H
+#define ANDROID_LINEAR_ACCELERATION_SENSOR_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <gui/Sensor.h>
+
+#include "SensorInterface.h"
+#include "GravitySensor.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+class SensorDevice;
+class SensorFusion;
+
+class LinearAccelerationSensor : public SensorInterface {
+ SensorDevice& mSensorDevice;
+ GravitySensor mGravitySensor;
+
+ virtual bool process(sensors_event_t* outEvent,
+ const sensors_event_t& event);
+public:
+ LinearAccelerationSensor(sensor_t const* list, size_t count);
+ virtual status_t activate(void* ident, bool enabled);
+ virtual status_t setDelay(void* ident, int handle, int64_t ns);
+ virtual Sensor getSensor() const;
+ virtual bool isVirtual() const { return true; }
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_LINEAR_ACCELERATION_SENSOR_H
diff --git a/services/sensorservice/OrientationSensor.cpp b/services/sensorservice/OrientationSensor.cpp
new file mode 100644
index 0000000..037adaa
--- /dev/null
+++ b/services/sensorservice/OrientationSensor.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2011 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 <stdint.h>
+#include <math.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+
+#include <hardware/sensors.h>
+
+#include "OrientationSensor.h"
+#include "SensorDevice.h"
+#include "SensorFusion.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+OrientationSensor::OrientationSensor()
+ : mSensorDevice(SensorDevice::getInstance()),
+ mSensorFusion(SensorFusion::getInstance())
+{
+}
+
+bool OrientationSensor::process(sensors_event_t* outEvent,
+ const sensors_event_t& event)
+{
+ if (event.type == SENSOR_TYPE_ACCELEROMETER) {
+ if (mSensorFusion.hasEstimate()) {
+ vec3_t g;
+ const float rad2deg = 180 / M_PI;
+ const mat33_t R(mSensorFusion.getRotationMatrix());
+ g[0] = atan2f(-R[1][0], R[0][0]) * rad2deg;
+ g[1] = atan2f(-R[2][1], R[2][2]) * rad2deg;
+ g[2] = asinf ( R[2][0]) * rad2deg;
+ if (g[0] < 0)
+ g[0] += 360;
+
+ *outEvent = event;
+ outEvent->orientation.azimuth = g.x;
+ outEvent->orientation.pitch = g.y;
+ outEvent->orientation.roll = g.z;
+ outEvent->orientation.status = SENSOR_STATUS_ACCURACY_HIGH;
+ outEvent->sensor = '_ypr';
+ outEvent->type = SENSOR_TYPE_ORIENTATION;
+ return true;
+ }
+ }
+ return false;
+}
+
+status_t OrientationSensor::activate(void* ident, bool enabled) {
+ return mSensorFusion.activate(this, enabled);
+}
+
+status_t OrientationSensor::setDelay(void* ident, int handle, int64_t ns) {
+ return mSensorFusion.setDelay(this, ns);
+}
+
+Sensor OrientationSensor::getSensor() const {
+ sensor_t hwSensor;
+ hwSensor.name = "Orientation Sensor";
+ hwSensor.vendor = "Google Inc.";
+ hwSensor.version = 1;
+ hwSensor.handle = '_ypr';
+ hwSensor.type = SENSOR_TYPE_ORIENTATION;
+ hwSensor.maxRange = 360.0f;
+ hwSensor.resolution = 1.0f/256.0f; // FIXME: real value here
+ hwSensor.power = mSensorFusion.getPowerUsage();
+ hwSensor.minDelay = mSensorFusion.getMinDelay();
+ Sensor sensor(&hwSensor);
+ return sensor;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/services/sensorservice/OrientationSensor.h b/services/sensorservice/OrientationSensor.h
new file mode 100644
index 0000000..855949d
--- /dev/null
+++ b/services/sensorservice/OrientationSensor.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#ifndef ANDROID_ORIENTATION_SENSOR_H
+#define ANDROID_ORIENTATION_SENSOR_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <gui/Sensor.h>
+
+#include "SensorInterface.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+class SensorDevice;
+class SensorFusion;
+
+class OrientationSensor : public SensorInterface {
+ SensorDevice& mSensorDevice;
+ SensorFusion& mSensorFusion;
+
+public:
+ OrientationSensor();
+ virtual bool process(sensors_event_t* outEvent,
+ const sensors_event_t& event);
+ virtual status_t activate(void* ident, bool enabled);
+ virtual status_t setDelay(void* ident, int handle, int64_t ns);
+ virtual Sensor getSensor() const;
+ virtual bool isVirtual() const { return true; }
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_ORIENTATION_SENSOR_H
diff --git a/services/sensorservice/RotationVectorSensor.cpp b/services/sensorservice/RotationVectorSensor.cpp
new file mode 100644
index 0000000..5ea9568
--- /dev/null
+++ b/services/sensorservice/RotationVectorSensor.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2010 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 <stdint.h>
+#include <math.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+
+#include <hardware/sensors.h>
+
+#include "RotationVectorSensor.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+RotationVectorSensor::RotationVectorSensor()
+ : mSensorDevice(SensorDevice::getInstance()),
+ mSensorFusion(SensorFusion::getInstance())
+{
+}
+
+bool RotationVectorSensor::process(sensors_event_t* outEvent,
+ const sensors_event_t& event)
+{
+ if (event.type == SENSOR_TYPE_ACCELEROMETER) {
+ if (mSensorFusion.hasEstimate()) {
+ const vec4_t q(mSensorFusion.getAttitude());
+ *outEvent = event;
+ outEvent->data[0] = q.x;
+ outEvent->data[1] = q.y;
+ outEvent->data[2] = q.z;
+ outEvent->data[3] = q.w;
+ outEvent->sensor = '_rov';
+ outEvent->type = SENSOR_TYPE_ROTATION_VECTOR;
+ return true;
+ }
+ }
+ return false;
+}
+
+status_t RotationVectorSensor::activate(void* ident, bool enabled) {
+ return mSensorFusion.activate(this, enabled);
+}
+
+status_t RotationVectorSensor::setDelay(void* ident, int handle, int64_t ns) {
+ return mSensorFusion.setDelay(this, ns);
+}
+
+Sensor RotationVectorSensor::getSensor() const {
+ sensor_t hwSensor;
+ hwSensor.name = "Rotation Vector Sensor";
+ hwSensor.vendor = "Google Inc.";
+ hwSensor.version = 3;
+ hwSensor.handle = '_rov';
+ hwSensor.type = SENSOR_TYPE_ROTATION_VECTOR;
+ hwSensor.maxRange = 1;
+ hwSensor.resolution = 1.0f / (1<<24);
+ hwSensor.power = mSensorFusion.getPowerUsage();
+ hwSensor.minDelay = mSensorFusion.getMinDelay();
+ Sensor sensor(&hwSensor);
+ return sensor;
+}
+
+// ---------------------------------------------------------------------------
+
+GyroDriftSensor::GyroDriftSensor()
+ : mSensorDevice(SensorDevice::getInstance()),
+ mSensorFusion(SensorFusion::getInstance())
+{
+}
+
+bool GyroDriftSensor::process(sensors_event_t* outEvent,
+ const sensors_event_t& event)
+{
+ if (event.type == SENSOR_TYPE_ACCELEROMETER) {
+ if (mSensorFusion.hasEstimate()) {
+ const vec3_t b(mSensorFusion.getGyroBias());
+ *outEvent = event;
+ outEvent->data[0] = b.x;
+ outEvent->data[1] = b.y;
+ outEvent->data[2] = b.z;
+ outEvent->sensor = '_gbs';
+ outEvent->type = SENSOR_TYPE_ACCELEROMETER;
+ return true;
+ }
+ }
+ return false;
+}
+
+status_t GyroDriftSensor::activate(void* ident, bool enabled) {
+ return mSensorFusion.activate(this, enabled);
+}
+
+status_t GyroDriftSensor::setDelay(void* ident, int handle, int64_t ns) {
+ return mSensorFusion.setDelay(this, ns);
+}
+
+Sensor GyroDriftSensor::getSensor() const {
+ sensor_t hwSensor;
+ hwSensor.name = "Gyroscope Bias (debug)";
+ hwSensor.vendor = "Google Inc.";
+ hwSensor.version = 1;
+ hwSensor.handle = '_gbs';
+ hwSensor.type = SENSOR_TYPE_ACCELEROMETER;
+ hwSensor.maxRange = 1;
+ hwSensor.resolution = 1.0f / (1<<24);
+ hwSensor.power = mSensorFusion.getPowerUsage();
+ hwSensor.minDelay = mSensorFusion.getMinDelay();
+ Sensor sensor(&hwSensor);
+ return sensor;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/services/sensorservice/RotationVectorSensor.h b/services/sensorservice/RotationVectorSensor.h
new file mode 100644
index 0000000..bb97fe1
--- /dev/null
+++ b/services/sensorservice/RotationVectorSensor.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef ANDROID_ROTATION_VECTOR_SENSOR_H
+#define ANDROID_ROTATION_VECTOR_SENSOR_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <gui/Sensor.h>
+
+#include "SensorDevice.h"
+#include "SensorInterface.h"
+
+#include "Fusion.h"
+#include "SensorFusion.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+class RotationVectorSensor : public SensorInterface {
+ SensorDevice& mSensorDevice;
+ SensorFusion& mSensorFusion;
+
+public:
+ RotationVectorSensor();
+ virtual bool process(sensors_event_t* outEvent,
+ const sensors_event_t& event);
+ virtual status_t activate(void* ident, bool enabled);
+ virtual status_t setDelay(void* ident, int handle, int64_t ns);
+ virtual Sensor getSensor() const;
+ virtual bool isVirtual() const { return true; }
+};
+
+class GyroDriftSensor : public SensorInterface {
+ SensorDevice& mSensorDevice;
+ SensorFusion& mSensorFusion;
+
+public:
+ GyroDriftSensor();
+ virtual bool process(sensors_event_t* outEvent,
+ const sensors_event_t& event);
+ virtual status_t activate(void* ident, bool enabled);
+ virtual status_t setDelay(void* ident, int handle, int64_t ns);
+ virtual Sensor getSensor() const;
+ virtual bool isVirtual() const { return true; }
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_ROTATION_VECTOR_SENSOR_H
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
new file mode 100644
index 0000000..2244a86
--- /dev/null
+++ b/services/sensorservice/SensorDevice.cpp
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2010 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 <stdint.h>
+#include <math.h>
+#include <sys/types.h>
+
+#include <utils/Atomic.h>
+#include <utils/Errors.h>
+#include <utils/Singleton.h>
+
+#include <binder/BinderService.h>
+#include <binder/Parcel.h>
+#include <binder/IServiceManager.h>
+
+#include <hardware/sensors.h>
+
+#include "SensorDevice.h"
+#include "SensorService.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+class BatteryService : public Singleton<BatteryService> {
+ static const int TRANSACTION_noteStartSensor = IBinder::FIRST_CALL_TRANSACTION + 3;
+ static const int TRANSACTION_noteStopSensor = IBinder::FIRST_CALL_TRANSACTION + 4;
+ static const String16 DESCRIPTOR;
+
+ friend class Singleton<BatteryService>;
+ sp<IBinder> mBatteryStatService;
+
+ BatteryService() {
+ const sp<IServiceManager> sm(defaultServiceManager());
+ if (sm != NULL) {
+ const String16 name("batteryinfo");
+ mBatteryStatService = sm->getService(name);
+ }
+ }
+
+ status_t noteStartSensor(int uid, int handle) {
+ Parcel data, reply;
+ data.writeInterfaceToken(DESCRIPTOR);
+ data.writeInt32(uid);
+ data.writeInt32(handle);
+ status_t err = mBatteryStatService->transact(
+ TRANSACTION_noteStartSensor, data, &reply, 0);
+ err = reply.readExceptionCode();
+ return err;
+ }
+
+ status_t noteStopSensor(int uid, int handle) {
+ Parcel data, reply;
+ data.writeInterfaceToken(DESCRIPTOR);
+ data.writeInt32(uid);
+ data.writeInt32(handle);
+ status_t err = mBatteryStatService->transact(
+ TRANSACTION_noteStopSensor, data, &reply, 0);
+ err = reply.readExceptionCode();
+ return err;
+ }
+
+public:
+ void enableSensor(int handle) {
+ if (mBatteryStatService != 0) {
+ int uid = IPCThreadState::self()->getCallingUid();
+ int64_t identity = IPCThreadState::self()->clearCallingIdentity();
+ noteStartSensor(uid, handle);
+ IPCThreadState::self()->restoreCallingIdentity(identity);
+ }
+ }
+ void disableSensor(int handle) {
+ if (mBatteryStatService != 0) {
+ int uid = IPCThreadState::self()->getCallingUid();
+ int64_t identity = IPCThreadState::self()->clearCallingIdentity();
+ noteStopSensor(uid, handle);
+ IPCThreadState::self()->restoreCallingIdentity(identity);
+ }
+ }
+};
+
+const String16 BatteryService::DESCRIPTOR("com.android.internal.app.IBatteryStats");
+
+ANDROID_SINGLETON_STATIC_INSTANCE(BatteryService)
+
+// ---------------------------------------------------------------------------
+
+ANDROID_SINGLETON_STATIC_INSTANCE(SensorDevice)
+
+SensorDevice::SensorDevice()
+ : mSensorDevice(0),
+ mSensorModule(0)
+{
+ status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID,
+ (hw_module_t const**)&mSensorModule);
+
+ ALOGE_IF(err, "couldn't load %s module (%s)",
+ SENSORS_HARDWARE_MODULE_ID, strerror(-err));
+
+ if (mSensorModule) {
+ err = sensors_open(&mSensorModule->common, &mSensorDevice);
+
+ ALOGE_IF(err, "couldn't open device for module %s (%s)",
+ SENSORS_HARDWARE_MODULE_ID, strerror(-err));
+
+ if (mSensorDevice) {
+ sensor_t const* list;
+ ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list);
+ mActivationCount.setCapacity(count);
+ Info model;
+ for (size_t i=0 ; i<size_t(count) ; i++) {
+ mActivationCount.add(list[i].handle, model);
+ mSensorDevice->activate(mSensorDevice, list[i].handle, 0);
+ }
+ }
+ }
+}
+
+void SensorDevice::dump(String8& result, char* buffer, size_t SIZE)
+{
+ if (!mSensorModule) return;
+ sensor_t const* list;
+ ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list);
+
+ snprintf(buffer, SIZE, "%d h/w sensors:\n", int(count));
+ result.append(buffer);
+
+ Mutex::Autolock _l(mLock);
+ for (size_t i=0 ; i<size_t(count) ; i++) {
+ const Info& info = mActivationCount.valueFor(list[i].handle);
+ snprintf(buffer, SIZE, "handle=0x%08x, active-count=%d, rates(ms)={ ",
+ list[i].handle,
+ info.rates.size());
+ result.append(buffer);
+ for (size_t j=0 ; j<info.rates.size() ; j++) {
+ snprintf(buffer, SIZE, "%4.1f%s",
+ info.rates.valueAt(j) / 1e6f,
+ j<info.rates.size()-1 ? ", " : "");
+ result.append(buffer);
+ }
+ snprintf(buffer, SIZE, " }, selected=%4.1f ms\n", info.delay / 1e6f);
+ result.append(buffer);
+ }
+}
+
+ssize_t SensorDevice::getSensorList(sensor_t const** list) {
+ if (!mSensorModule) return NO_INIT;
+ ssize_t count = mSensorModule->get_sensors_list(mSensorModule, list);
+ return count;
+}
+
+status_t SensorDevice::initCheck() const {
+ return mSensorDevice && mSensorModule ? NO_ERROR : NO_INIT;
+}
+
+ssize_t SensorDevice::poll(sensors_event_t* buffer, size_t count) {
+ if (!mSensorDevice) return NO_INIT;
+ ssize_t c;
+ do {
+ c = mSensorDevice->poll(mSensorDevice, buffer, count);
+ } while (c == -EINTR);
+ return c;
+}
+
+status_t SensorDevice::activate(void* ident, int handle, int enabled)
+{
+ if (!mSensorDevice) return NO_INIT;
+ status_t err(NO_ERROR);
+ bool actuateHardware = false;
+
+ Info& info( mActivationCount.editValueFor(handle) );
+
+
+ ALOGD_IF(DEBUG_CONNECTIONS,
+ "SensorDevice::activate: ident=%p, handle=0x%08x, enabled=%d, count=%d",
+ ident, handle, enabled, info.rates.size());
+
+ if (enabled) {
+ Mutex::Autolock _l(mLock);
+ ALOGD_IF(DEBUG_CONNECTIONS, "... index=%ld",
+ info.rates.indexOfKey(ident));
+
+ if (info.rates.indexOfKey(ident) < 0) {
+ info.rates.add(ident, DEFAULT_EVENTS_PERIOD);
+ if (info.rates.size() == 1) {
+ actuateHardware = true;
+ }
+ } else {
+ // sensor was already activated for this ident
+ }
+ } else {
+ Mutex::Autolock _l(mLock);
+ ALOGD_IF(DEBUG_CONNECTIONS, "... index=%ld",
+ info.rates.indexOfKey(ident));
+
+ ssize_t idx = info.rates.removeItem(ident);
+ if (idx >= 0) {
+ if (info.rates.size() == 0) {
+ actuateHardware = true;
+ }
+ } else {
+ // sensor wasn't enabled for this ident
+ }
+ }
+
+ if (actuateHardware) {
+ ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w");
+
+ err = mSensorDevice->activate(mSensorDevice, handle, enabled);
+ if (enabled) {
+ ALOGE_IF(err, "Error activating sensor %d (%s)", handle, strerror(-err));
+ if (err == 0) {
+ BatteryService::getInstance().enableSensor(handle);
+ }
+ } else {
+ if (err == 0) {
+ BatteryService::getInstance().disableSensor(handle);
+ }
+ }
+ }
+
+ { // scope for the lock
+ Mutex::Autolock _l(mLock);
+ nsecs_t ns = info.selectDelay();
+ mSensorDevice->setDelay(mSensorDevice, handle, ns);
+ }
+
+ return err;
+}
+
+status_t SensorDevice::setDelay(void* ident, int handle, int64_t ns)
+{
+ if (!mSensorDevice) return NO_INIT;
+ Mutex::Autolock _l(mLock);
+ Info& info( mActivationCount.editValueFor(handle) );
+ status_t err = info.setDelayForIdent(ident, ns);
+ if (err < 0) return err;
+ ns = info.selectDelay();
+ return mSensorDevice->setDelay(mSensorDevice, handle, ns);
+}
+
+// ---------------------------------------------------------------------------
+
+status_t SensorDevice::Info::setDelayForIdent(void* ident, int64_t ns)
+{
+ ssize_t index = rates.indexOfKey(ident);
+ if (index < 0) {
+ ALOGE("Info::setDelayForIdent(ident=%p, ns=%lld) failed (%s)",
+ ident, ns, strerror(-index));
+ return BAD_INDEX;
+ }
+ rates.editValueAt(index) = ns;
+ return NO_ERROR;
+}
+
+nsecs_t SensorDevice::Info::selectDelay()
+{
+ nsecs_t ns = rates.valueAt(0);
+ for (size_t i=1 ; i<rates.size() ; i++) {
+ nsecs_t cur = rates.valueAt(i);
+ if (cur < ns) {
+ ns = cur;
+ }
+ }
+ delay = ns;
+ return ns;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
new file mode 100644
index 0000000..728b6cb
--- /dev/null
+++ b/services/sensorservice/SensorDevice.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef ANDROID_SENSOR_DEVICE_H
+#define ANDROID_SENSOR_DEVICE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/KeyedVector.h>
+#include <utils/Singleton.h>
+#include <utils/String8.h>
+
+#include <gui/Sensor.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+static const nsecs_t DEFAULT_EVENTS_PERIOD = 200000000; // 5 Hz
+
+class SensorDevice : public Singleton<SensorDevice> {
+ friend class Singleton<SensorDevice>;
+ struct sensors_poll_device_t* mSensorDevice;
+ struct sensors_module_t* mSensorModule;
+ mutable Mutex mLock; // protect mActivationCount[].rates
+ // fixed-size array after construction
+ struct Info {
+ Info() : delay(0) { }
+ KeyedVector<void*, nsecs_t> rates;
+ nsecs_t delay;
+ status_t setDelayForIdent(void* ident, int64_t ns);
+ nsecs_t selectDelay();
+ };
+ DefaultKeyedVector<int, Info> mActivationCount;
+
+ SensorDevice();
+public:
+ ssize_t getSensorList(sensor_t const** list);
+ status_t initCheck() const;
+ ssize_t poll(sensors_event_t* buffer, size_t count);
+ status_t activate(void* ident, int handle, int enabled);
+ status_t setDelay(void* ident, int handle, int64_t ns);
+ void dump(String8& result, char* buffer, size_t SIZE);
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_SENSOR_DEVICE_H
diff --git a/services/sensorservice/SensorFusion.cpp b/services/sensorservice/SensorFusion.cpp
new file mode 100644
index 0000000..d23906d
--- /dev/null
+++ b/services/sensorservice/SensorFusion.cpp
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2011 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 "SensorDevice.h"
+#include "SensorFusion.h"
+#include "SensorService.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+ANDROID_SINGLETON_STATIC_INSTANCE(SensorFusion)
+
+SensorFusion::SensorFusion()
+ : mSensorDevice(SensorDevice::getInstance()),
+ mEnabled(false), mGyroTime(0)
+{
+ sensor_t const* list;
+ ssize_t count = mSensorDevice.getSensorList(&list);
+ if (count > 0) {
+ for (size_t i=0 ; i<size_t(count) ; i++) {
+ if (list[i].type == SENSOR_TYPE_ACCELEROMETER) {
+ mAcc = Sensor(list + i);
+ }
+ if (list[i].type == SENSOR_TYPE_MAGNETIC_FIELD) {
+ mMag = Sensor(list + i);
+ }
+ if (list[i].type == SENSOR_TYPE_GYROSCOPE) {
+ mGyro = Sensor(list + i);
+ // 200 Hz for gyro events is a good compromise between precision
+ // and power/cpu usage.
+ mGyroRate = 200;
+ mTargetDelayNs = 1000000000LL/mGyroRate;
+ }
+ }
+ mFusion.init();
+ }
+}
+
+void SensorFusion::process(const sensors_event_t& event) {
+ if (event.type == SENSOR_TYPE_GYROSCOPE) {
+ if (mGyroTime != 0) {
+ const float dT = (event.timestamp - mGyroTime) / 1000000000.0f;
+ const float freq = 1 / dT;
+ if (freq >= 100 && freq<1000) { // filter values obviously wrong
+ const float alpha = 1 / (1 + dT); // 1s time-constant
+ mGyroRate = freq + (mGyroRate - freq)*alpha;
+ }
+ }
+ mGyroTime = event.timestamp;
+ mFusion.handleGyro(vec3_t(event.data), 1.0f/mGyroRate);
+ } else if (event.type == SENSOR_TYPE_MAGNETIC_FIELD) {
+ const vec3_t mag(event.data);
+ mFusion.handleMag(mag);
+ } else if (event.type == SENSOR_TYPE_ACCELEROMETER) {
+ const vec3_t acc(event.data);
+ mFusion.handleAcc(acc);
+ mAttitude = mFusion.getAttitude();
+ }
+}
+
+template <typename T> inline T min(T a, T b) { return a<b ? a : b; }
+template <typename T> inline T max(T a, T b) { return a>b ? a : b; }
+
+status_t SensorFusion::activate(void* ident, bool enabled) {
+
+ ALOGD_IF(DEBUG_CONNECTIONS,
+ "SensorFusion::activate(ident=%p, enabled=%d)",
+ ident, enabled);
+
+ const ssize_t idx = mClients.indexOf(ident);
+ if (enabled) {
+ if (idx < 0) {
+ mClients.add(ident);
+ }
+ } else {
+ if (idx >= 0) {
+ mClients.removeItemsAt(idx);
+ }
+ }
+
+ mSensorDevice.activate(ident, mAcc.getHandle(), enabled);
+ mSensorDevice.activate(ident, mMag.getHandle(), enabled);
+ mSensorDevice.activate(ident, mGyro.getHandle(), enabled);
+
+ const bool newState = mClients.size() != 0;
+ if (newState != mEnabled) {
+ mEnabled = newState;
+ if (newState) {
+ mFusion.init();
+ mGyroTime = 0;
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t SensorFusion::setDelay(void* ident, int64_t ns) {
+ mSensorDevice.setDelay(ident, mAcc.getHandle(), ns);
+ mSensorDevice.setDelay(ident, mMag.getHandle(), ms2ns(20));
+ mSensorDevice.setDelay(ident, mGyro.getHandle(), mTargetDelayNs);
+ return NO_ERROR;
+}
+
+
+float SensorFusion::getPowerUsage() const {
+ float power = mAcc.getPowerUsage() +
+ mMag.getPowerUsage() +
+ mGyro.getPowerUsage();
+ return power;
+}
+
+int32_t SensorFusion::getMinDelay() const {
+ return mAcc.getMinDelay();
+}
+
+void SensorFusion::dump(String8& result, char* buffer, size_t SIZE) {
+ const Fusion& fusion(mFusion);
+ snprintf(buffer, SIZE, "9-axis fusion %s (%d clients), gyro-rate=%7.2fHz, "
+ "q=< %g, %g, %g, %g > (%g), "
+ "b=< %g, %g, %g >\n",
+ mEnabled ? "enabled" : "disabled",
+ mClients.size(),
+ mGyroRate,
+ fusion.getAttitude().x,
+ fusion.getAttitude().y,
+ fusion.getAttitude().z,
+ fusion.getAttitude().w,
+ length(fusion.getAttitude()),
+ fusion.getBias().x,
+ fusion.getBias().y,
+ fusion.getBias().z);
+ result.append(buffer);
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/services/sensorservice/SensorFusion.h b/services/sensorservice/SensorFusion.h
new file mode 100644
index 0000000..4c99bcb
--- /dev/null
+++ b/services/sensorservice/SensorFusion.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#ifndef ANDROID_SENSOR_FUSION_H
+#define ANDROID_SENSOR_FUSION_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/SortedVector.h>
+#include <utils/Singleton.h>
+#include <utils/String8.h>
+
+#include <gui/Sensor.h>
+
+#include "Fusion.h"
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+class SensorDevice;
+
+class SensorFusion : public Singleton<SensorFusion> {
+ friend class Singleton<SensorFusion>;
+
+ SensorDevice& mSensorDevice;
+ Sensor mAcc;
+ Sensor mMag;
+ Sensor mGyro;
+ Fusion mFusion;
+ bool mEnabled;
+ float mGyroRate;
+ nsecs_t mTargetDelayNs;
+ nsecs_t mGyroTime;
+ vec4_t mAttitude;
+ SortedVector<void*> mClients;
+
+ SensorFusion();
+
+public:
+ void process(const sensors_event_t& event);
+
+ bool isEnabled() const { return mEnabled; }
+ bool hasEstimate() const { return mFusion.hasEstimate(); }
+ mat33_t getRotationMatrix() const { return mFusion.getRotationMatrix(); }
+ vec4_t getAttitude() const { return mAttitude; }
+ vec3_t getGyroBias() const { return mFusion.getBias(); }
+ float getEstimatedRate() const { return mGyroRate; }
+
+ status_t activate(void* ident, bool enabled);
+ status_t setDelay(void* ident, int64_t ns);
+
+ float getPowerUsage() const;
+ int32_t getMinDelay() const;
+
+ void dump(String8& result, char* buffer, size_t SIZE);
+};
+
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_SENSOR_FUSION_H
diff --git a/services/sensorservice/SensorInterface.cpp b/services/sensorservice/SensorInterface.cpp
new file mode 100644
index 0000000..468aa61
--- /dev/null
+++ b/services/sensorservice/SensorInterface.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2010 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 <stdint.h>
+#include <sys/types.h>
+
+#include <cutils/log.h>
+
+#include "SensorInterface.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+SensorInterface::~SensorInterface()
+{
+}
+
+// ---------------------------------------------------------------------------
+
+HardwareSensor::HardwareSensor(const sensor_t& sensor)
+ : mSensorDevice(SensorDevice::getInstance()),
+ mSensor(&sensor)
+{
+ ALOGI("%s", sensor.name);
+}
+
+HardwareSensor::~HardwareSensor() {
+}
+
+bool HardwareSensor::process(sensors_event_t* outEvent,
+ const sensors_event_t& event) {
+ *outEvent = event;
+ return true;
+}
+
+status_t HardwareSensor::activate(void* ident, bool enabled) {
+ return mSensorDevice.activate(ident, mSensor.getHandle(), enabled);
+}
+
+status_t HardwareSensor::setDelay(void* ident, int handle, int64_t ns) {
+ return mSensorDevice.setDelay(ident, handle, ns);
+}
+
+Sensor HardwareSensor::getSensor() const {
+ return mSensor;
+}
+
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/services/sensorservice/SensorInterface.h b/services/sensorservice/SensorInterface.h
new file mode 100644
index 0000000..fb357d7
--- /dev/null
+++ b/services/sensorservice/SensorInterface.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef ANDROID_SENSOR_INTERFACE_H
+#define ANDROID_SENSOR_INTERFACE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <gui/Sensor.h>
+
+#include "SensorDevice.h"
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+class SensorInterface {
+public:
+ virtual ~SensorInterface();
+
+ virtual bool process(sensors_event_t* outEvent,
+ const sensors_event_t& event) = 0;
+
+ virtual status_t activate(void* ident, bool enabled) = 0;
+ virtual status_t setDelay(void* ident, int handle, int64_t ns) = 0;
+ virtual Sensor getSensor() const = 0;
+ virtual bool isVirtual() const = 0;
+};
+
+// ---------------------------------------------------------------------------
+
+class HardwareSensor : public SensorInterface
+{
+ SensorDevice& mSensorDevice;
+ Sensor mSensor;
+
+public:
+ HardwareSensor(const sensor_t& sensor);
+
+ virtual ~HardwareSensor();
+
+ virtual bool process(sensors_event_t* outEvent,
+ const sensors_event_t& event);
+
+ virtual status_t activate(void* ident, bool enabled);
+ virtual status_t setDelay(void* ident, int handle, int64_t ns);
+ virtual Sensor getSensor() const;
+ virtual bool isVirtual() const { return false; }
+};
+
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_SENSOR_INTERFACE_H
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
new file mode 100644
index 0000000..9e5e84b
--- /dev/null
+++ b/services/sensorservice/SensorService.cpp
@@ -0,0 +1,637 @@
+/*
+ * Copyright (C) 2010 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 <stdint.h>
+#include <math.h>
+#include <sys/types.h>
+
+#include <cutils/properties.h>
+
+#include <utils/SortedVector.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+#include <utils/Atomic.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/Singleton.h>
+#include <utils/String16.h>
+
+#include <binder/BinderService.h>
+#include <binder/IServiceManager.h>
+#include <binder/PermissionCache.h>
+
+#include <gui/ISensorServer.h>
+#include <gui/ISensorEventConnection.h>
+#include <gui/SensorEventQueue.h>
+
+#include <hardware/sensors.h>
+
+#include "CorrectedGyroSensor.h"
+#include "GravitySensor.h"
+#include "LinearAccelerationSensor.h"
+#include "OrientationSensor.h"
+#include "RotationVectorSensor.h"
+#include "SensorFusion.h"
+#include "SensorService.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+/*
+ * Notes:
+ *
+ * - what about a gyro-corrected magnetic-field sensor?
+ * - run mag sensor from time to time to force calibration
+ * - gravity sensor length is wrong (=> drift in linear-acc sensor)
+ *
+ */
+
+SensorService::SensorService()
+ : mInitCheck(NO_INIT)
+{
+}
+
+void SensorService::onFirstRef()
+{
+ ALOGD("nuSensorService starting...");
+
+ SensorDevice& dev(SensorDevice::getInstance());
+
+ if (dev.initCheck() == NO_ERROR) {
+ sensor_t const* list;
+ ssize_t count = dev.getSensorList(&list);
+ if (count > 0) {
+ ssize_t orientationIndex = -1;
+ bool hasGyro = false;
+ uint32_t virtualSensorsNeeds =
+ (1<<SENSOR_TYPE_GRAVITY) |
+ (1<<SENSOR_TYPE_LINEAR_ACCELERATION) |
+ (1<<SENSOR_TYPE_ROTATION_VECTOR);
+
+ mLastEventSeen.setCapacity(count);
+ for (ssize_t i=0 ; i<count ; i++) {
+ registerSensor( new HardwareSensor(list[i]) );
+ switch (list[i].type) {
+ case SENSOR_TYPE_ORIENTATION:
+ orientationIndex = i;
+ break;
+ case SENSOR_TYPE_GYROSCOPE:
+ hasGyro = true;
+ break;
+ case SENSOR_TYPE_GRAVITY:
+ case SENSOR_TYPE_LINEAR_ACCELERATION:
+ case SENSOR_TYPE_ROTATION_VECTOR:
+ virtualSensorsNeeds &= ~(1<<list[i].type);
+ break;
+ }
+ }
+
+ // it's safe to instantiate the SensorFusion object here
+ // (it wants to be instantiated after h/w sensors have been
+ // registered)
+ const SensorFusion& fusion(SensorFusion::getInstance());
+
+ if (hasGyro) {
+ // Always instantiate Android's virtual sensors. Since they are
+ // instantiated behind sensors from the HAL, they won't
+ // interfere with applications, unless they looks specifically
+ // for them (by name).
+
+ registerVirtualSensor( new RotationVectorSensor() );
+ registerVirtualSensor( new GravitySensor(list, count) );
+ registerVirtualSensor( new LinearAccelerationSensor(list, count) );
+
+ // these are optional
+ registerVirtualSensor( new OrientationSensor() );
+ registerVirtualSensor( new CorrectedGyroSensor(list, count) );
+
+ // virtual debugging sensors...
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.sensors", value, "0");
+ if (atoi(value)) {
+ registerVirtualSensor( new GyroDriftSensor() );
+ }
+ }
+
+ // build the sensor list returned to users
+ mUserSensorList = mSensorList;
+ if (hasGyro &&
+ (virtualSensorsNeeds & (1<<SENSOR_TYPE_ROTATION_VECTOR))) {
+ // if we have the fancy sensor fusion, and it's not provided by the
+ // HAL, use our own (fused) orientation sensor by removing the
+ // HAL supplied one form the user list.
+ if (orientationIndex >= 0) {
+ mUserSensorList.removeItemsAt(orientationIndex);
+ }
+ }
+
+ run("SensorService", PRIORITY_URGENT_DISPLAY);
+ mInitCheck = NO_ERROR;
+ }
+ }
+}
+
+void SensorService::registerSensor(SensorInterface* s)
+{
+ sensors_event_t event;
+ memset(&event, 0, sizeof(event));
+
+ const Sensor sensor(s->getSensor());
+ // add to the sensor list (returned to clients)
+ mSensorList.add(sensor);
+ // add to our handle->SensorInterface mapping
+ mSensorMap.add(sensor.getHandle(), s);
+ // create an entry in the mLastEventSeen array
+ mLastEventSeen.add(sensor.getHandle(), event);
+}
+
+void SensorService::registerVirtualSensor(SensorInterface* s)
+{
+ registerSensor(s);
+ mVirtualSensorList.add( s );
+}
+
+SensorService::~SensorService()
+{
+ for (size_t i=0 ; i<mSensorMap.size() ; i++)
+ delete mSensorMap.valueAt(i);
+}
+
+static const String16 sDump("android.permission.DUMP");
+
+status_t SensorService::dump(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 1024;
+ char buffer[SIZE];
+ String8 result;
+ if (!PermissionCache::checkCallingPermission(sDump)) {
+ snprintf(buffer, SIZE, "Permission Denial: "
+ "can't dump SurfaceFlinger from pid=%d, uid=%d\n",
+ IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid());
+ result.append(buffer);
+ } else {
+ Mutex::Autolock _l(mLock);
+ snprintf(buffer, SIZE, "Sensor List:\n");
+ result.append(buffer);
+ for (size_t i=0 ; i<mSensorList.size() ; i++) {
+ const Sensor& s(mSensorList[i]);
+ const sensors_event_t& e(mLastEventSeen.valueFor(s.getHandle()));
+ snprintf(buffer, SIZE,
+ "%-48s| %-32s | 0x%08x | maxRate=%7.2fHz | "
+ "last=<%5.1f,%5.1f,%5.1f>\n",
+ s.getName().string(),
+ s.getVendor().string(),
+ s.getHandle(),
+ s.getMinDelay() ? (1000000.0f / s.getMinDelay()) : 0.0f,
+ e.data[0], e.data[1], e.data[2]);
+ result.append(buffer);
+ }
+ SensorFusion::getInstance().dump(result, buffer, SIZE);
+ SensorDevice::getInstance().dump(result, buffer, SIZE);
+
+ snprintf(buffer, SIZE, "%d active connections\n",
+ mActiveConnections.size());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "Active sensors:\n");
+ result.append(buffer);
+ for (size_t i=0 ; i<mActiveSensors.size() ; i++) {
+ int handle = mActiveSensors.keyAt(i);
+ snprintf(buffer, SIZE, "%s (handle=0x%08x, connections=%d)\n",
+ getSensorName(handle).string(),
+ handle,
+ mActiveSensors.valueAt(i)->getNumConnections());
+ result.append(buffer);
+ }
+ }
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+bool SensorService::threadLoop()
+{
+ ALOGD("nuSensorService thread starting...");
+
+ const size_t numEventMax = 16;
+ const size_t minBufferSize = numEventMax + numEventMax * mVirtualSensorList.size();
+ sensors_event_t buffer[minBufferSize];
+ sensors_event_t scratch[minBufferSize];
+ SensorDevice& device(SensorDevice::getInstance());
+ const size_t vcount = mVirtualSensorList.size();
+
+ ssize_t count;
+ do {
+ count = device.poll(buffer, numEventMax);
+ if (count<0) {
+ ALOGE("sensor poll failed (%s)", strerror(-count));
+ break;
+ }
+
+ recordLastValue(buffer, count);
+
+ // handle virtual sensors
+ if (count && vcount) {
+ sensors_event_t const * const event = buffer;
+ const DefaultKeyedVector<int, SensorInterface*> virtualSensors(
+ getActiveVirtualSensors());
+ const size_t activeVirtualSensorCount = virtualSensors.size();
+ if (activeVirtualSensorCount) {
+ size_t k = 0;
+ SensorFusion& fusion(SensorFusion::getInstance());
+ if (fusion.isEnabled()) {
+ for (size_t i=0 ; i<size_t(count) ; i++) {
+ fusion.process(event[i]);
+ }
+ }
+ for (size_t i=0 ; i<size_t(count) && k<minBufferSize ; i++) {
+ for (size_t j=0 ; j<activeVirtualSensorCount ; j++) {
+ if (count + k >= minBufferSize) {
+ ALOGE("buffer too small to hold all events: "
+ "count=%u, k=%u, size=%u",
+ count, k, minBufferSize);
+ break;
+ }
+ sensors_event_t out;
+ SensorInterface* si = virtualSensors.valueAt(j);
+ if (si->process(&out, event[i])) {
+ buffer[count + k] = out;
+ k++;
+ }
+ }
+ }
+ if (k) {
+ // record the last synthesized values
+ recordLastValue(&buffer[count], k);
+ count += k;
+ // sort the buffer by time-stamps
+ sortEventBuffer(buffer, count);
+ }
+ }
+ }
+
+ // send our events to clients...
+ const SortedVector< wp<SensorEventConnection> > activeConnections(
+ getActiveConnections());
+ size_t numConnections = activeConnections.size();
+ for (size_t i=0 ; i<numConnections ; i++) {
+ sp<SensorEventConnection> connection(
+ activeConnections[i].promote());
+ if (connection != 0) {
+ connection->sendEvents(buffer, count, scratch);
+ }
+ }
+ } while (count >= 0 || Thread::exitPending());
+
+ ALOGW("Exiting SensorService::threadLoop => aborting...");
+ abort();
+ return false;
+}
+
+void SensorService::recordLastValue(
+ sensors_event_t const * buffer, size_t count)
+{
+ Mutex::Autolock _l(mLock);
+
+ // record the last event for each sensor
+ int32_t prev = buffer[0].sensor;
+ for (size_t i=1 ; i<count ; i++) {
+ // record the last event of each sensor type in this buffer
+ int32_t curr = buffer[i].sensor;
+ if (curr != prev) {
+ mLastEventSeen.editValueFor(prev) = buffer[i-1];
+ prev = curr;
+ }
+ }
+ mLastEventSeen.editValueFor(prev) = buffer[count-1];
+}
+
+void SensorService::sortEventBuffer(sensors_event_t* buffer, size_t count)
+{
+ struct compar {
+ static int cmp(void const* lhs, void const* rhs) {
+ sensors_event_t const* l = static_cast<sensors_event_t const*>(lhs);
+ sensors_event_t const* r = static_cast<sensors_event_t const*>(rhs);
+ return l->timestamp - r->timestamp;
+ }
+ };
+ qsort(buffer, count, sizeof(sensors_event_t), compar::cmp);
+}
+
+SortedVector< wp<SensorService::SensorEventConnection> >
+SensorService::getActiveConnections() const
+{
+ Mutex::Autolock _l(mLock);
+ return mActiveConnections;
+}
+
+DefaultKeyedVector<int, SensorInterface*>
+SensorService::getActiveVirtualSensors() const
+{
+ Mutex::Autolock _l(mLock);
+ return mActiveVirtualSensors;
+}
+
+String8 SensorService::getSensorName(int handle) const {
+ size_t count = mUserSensorList.size();
+ for (size_t i=0 ; i<count ; i++) {
+ const Sensor& sensor(mUserSensorList[i]);
+ if (sensor.getHandle() == handle) {
+ return sensor.getName();
+ }
+ }
+ String8 result("unknown");
+ return result;
+}
+
+Vector<Sensor> SensorService::getSensorList()
+{
+ return mUserSensorList;
+}
+
+sp<ISensorEventConnection> SensorService::createSensorEventConnection()
+{
+ sp<SensorEventConnection> result(new SensorEventConnection(this));
+ return result;
+}
+
+void SensorService::cleanupConnection(SensorEventConnection* c)
+{
+ Mutex::Autolock _l(mLock);
+ const wp<SensorEventConnection> connection(c);
+ size_t size = mActiveSensors.size();
+ ALOGD_IF(DEBUG_CONNECTIONS, "%d active sensors", size);
+ for (size_t i=0 ; i<size ; ) {
+ int handle = mActiveSensors.keyAt(i);
+ if (c->hasSensor(handle)) {
+ ALOGD_IF(DEBUG_CONNECTIONS, "%i: disabling handle=0x%08x", i, handle);
+ SensorInterface* sensor = mSensorMap.valueFor( handle );
+ ALOGE_IF(!sensor, "mSensorMap[handle=0x%08x] is null!", handle);
+ if (sensor) {
+ sensor->activate(c, false);
+ }
+ }
+ SensorRecord* rec = mActiveSensors.valueAt(i);
+ ALOGE_IF(!rec, "mActiveSensors[%d] is null (handle=0x%08x)!", i, handle);
+ ALOGD_IF(DEBUG_CONNECTIONS,
+ "removing connection %p for sensor[%d].handle=0x%08x",
+ c, i, handle);
+
+ if (rec && rec->removeConnection(connection)) {
+ ALOGD_IF(DEBUG_CONNECTIONS, "... and it was the last connection");
+ mActiveSensors.removeItemsAt(i, 1);
+ mActiveVirtualSensors.removeItem(handle);
+ delete rec;
+ size--;
+ } else {
+ i++;
+ }
+ }
+ mActiveConnections.remove(connection);
+}
+
+status_t SensorService::enable(const sp<SensorEventConnection>& connection,
+ int handle)
+{
+ if (mInitCheck != NO_ERROR)
+ return mInitCheck;
+
+ Mutex::Autolock _l(mLock);
+ SensorInterface* sensor = mSensorMap.valueFor(handle);
+ status_t err = sensor ? sensor->activate(connection.get(), true) : status_t(BAD_VALUE);
+ if (err == NO_ERROR) {
+ SensorRecord* rec = mActiveSensors.valueFor(handle);
+ if (rec == 0) {
+ rec = new SensorRecord(connection);
+ mActiveSensors.add(handle, rec);
+ if (sensor->isVirtual()) {
+ mActiveVirtualSensors.add(handle, sensor);
+ }
+ } else {
+ if (rec->addConnection(connection)) {
+ // this sensor is already activated, but we are adding a
+ // connection that uses it. Immediately send down the last
+ // known value of the requested sensor if it's not a
+ // "continuous" sensor.
+ if (sensor->getSensor().getMinDelay() == 0) {
+ sensors_event_t scratch;
+ sensors_event_t& event(mLastEventSeen.editValueFor(handle));
+ if (event.version == sizeof(sensors_event_t)) {
+ connection->sendEvents(&event, 1);
+ }
+ }
+ }
+ }
+ if (err == NO_ERROR) {
+ // connection now active
+ if (connection->addSensor(handle)) {
+ // the sensor was added (which means it wasn't already there)
+ // so, see if this connection becomes active
+ if (mActiveConnections.indexOf(connection) < 0) {
+ mActiveConnections.add(connection);
+ }
+ }
+ }
+ }
+ return err;
+}
+
+status_t SensorService::disable(const sp<SensorEventConnection>& connection,
+ int handle)
+{
+ if (mInitCheck != NO_ERROR)
+ return mInitCheck;
+
+ status_t err = NO_ERROR;
+ Mutex::Autolock _l(mLock);
+ SensorRecord* rec = mActiveSensors.valueFor(handle);
+ if (rec) {
+ // see if this connection becomes inactive
+ connection->removeSensor(handle);
+ if (connection->hasAnySensor() == false) {
+ mActiveConnections.remove(connection);
+ }
+ // see if this sensor becomes inactive
+ if (rec->removeConnection(connection)) {
+ mActiveSensors.removeItem(handle);
+ mActiveVirtualSensors.removeItem(handle);
+ delete rec;
+ }
+ SensorInterface* sensor = mSensorMap.valueFor(handle);
+ err = sensor ? sensor->activate(connection.get(), false) : status_t(BAD_VALUE);
+ }
+ return err;
+}
+
+status_t SensorService::setEventRate(const sp<SensorEventConnection>& connection,
+ int handle, nsecs_t ns)
+{
+ if (mInitCheck != NO_ERROR)
+ return mInitCheck;
+
+ SensorInterface* sensor = mSensorMap.valueFor(handle);
+ if (!sensor)
+ return BAD_VALUE;
+
+ if (ns < 0)
+ return BAD_VALUE;
+
+ nsecs_t minDelayNs = sensor->getSensor().getMinDelayNs();
+ if (ns < minDelayNs) {
+ ns = minDelayNs;
+ }
+
+ if (ns < MINIMUM_EVENTS_PERIOD)
+ ns = MINIMUM_EVENTS_PERIOD;
+
+ return sensor->setDelay(connection.get(), handle, ns);
+}
+
+// ---------------------------------------------------------------------------
+
+SensorService::SensorRecord::SensorRecord(
+ const sp<SensorEventConnection>& connection)
+{
+ mConnections.add(connection);
+}
+
+bool SensorService::SensorRecord::addConnection(
+ const sp<SensorEventConnection>& connection)
+{
+ if (mConnections.indexOf(connection) < 0) {
+ mConnections.add(connection);
+ return true;
+ }
+ return false;
+}
+
+bool SensorService::SensorRecord::removeConnection(
+ const wp<SensorEventConnection>& connection)
+{
+ ssize_t index = mConnections.indexOf(connection);
+ if (index >= 0) {
+ mConnections.removeItemsAt(index, 1);
+ }
+ return mConnections.size() ? false : true;
+}
+
+// ---------------------------------------------------------------------------
+
+SensorService::SensorEventConnection::SensorEventConnection(
+ const sp<SensorService>& service)
+ : mService(service), mChannel(new BitTube())
+{
+}
+
+SensorService::SensorEventConnection::~SensorEventConnection()
+{
+ ALOGD_IF(DEBUG_CONNECTIONS, "~SensorEventConnection(%p)", this);
+ mService->cleanupConnection(this);
+}
+
+void SensorService::SensorEventConnection::onFirstRef()
+{
+}
+
+bool SensorService::SensorEventConnection::addSensor(int32_t handle) {
+ Mutex::Autolock _l(mConnectionLock);
+ if (mSensorInfo.indexOf(handle) <= 0) {
+ mSensorInfo.add(handle);
+ return true;
+ }
+ return false;
+}
+
+bool SensorService::SensorEventConnection::removeSensor(int32_t handle) {
+ Mutex::Autolock _l(mConnectionLock);
+ if (mSensorInfo.remove(handle) >= 0) {
+ return true;
+ }
+ return false;
+}
+
+bool SensorService::SensorEventConnection::hasSensor(int32_t handle) const {
+ Mutex::Autolock _l(mConnectionLock);
+ return mSensorInfo.indexOf(handle) >= 0;
+}
+
+bool SensorService::SensorEventConnection::hasAnySensor() const {
+ Mutex::Autolock _l(mConnectionLock);
+ return mSensorInfo.size() ? true : false;
+}
+
+status_t SensorService::SensorEventConnection::sendEvents(
+ sensors_event_t const* buffer, size_t numEvents,
+ sensors_event_t* scratch)
+{
+ // filter out events not for this connection
+ size_t count = 0;
+ if (scratch) {
+ Mutex::Autolock _l(mConnectionLock);
+ size_t i=0;
+ while (i<numEvents) {
+ const int32_t curr = buffer[i].sensor;
+ if (mSensorInfo.indexOf(curr) >= 0) {
+ do {
+ scratch[count++] = buffer[i++];
+ } while ((i<numEvents) && (buffer[i].sensor == curr));
+ } else {
+ i++;
+ }
+ }
+ } else {
+ scratch = const_cast<sensors_event_t *>(buffer);
+ count = numEvents;
+ }
+
+ // NOTE: ASensorEvent and sensors_event_t are the same type
+ ssize_t size = SensorEventQueue::write(mChannel,
+ reinterpret_cast<ASensorEvent const*>(scratch), count);
+ if (size == -EAGAIN) {
+ // the destination doesn't accept events anymore, it's probably
+ // full. For now, we just drop the events on the floor.
+ //ALOGW("dropping %d events on the floor", count);
+ return size;
+ }
+
+ return size < 0 ? status_t(size) : status_t(NO_ERROR);
+}
+
+sp<BitTube> SensorService::SensorEventConnection::getSensorChannel() const
+{
+ return mChannel;
+}
+
+status_t SensorService::SensorEventConnection::enableDisable(
+ int handle, bool enabled)
+{
+ status_t err;
+ if (enabled) {
+ err = mService->enable(this, handle);
+ } else {
+ err = mService->disable(this, handle);
+ }
+ return err;
+}
+
+status_t SensorService::SensorEventConnection::setEventRate(
+ int handle, nsecs_t ns)
+{
+ return mService->setEventRate(this, handle, ns);
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
new file mode 100644
index 0000000..e357f96
--- /dev/null
+++ b/services/sensorservice/SensorService.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef ANDROID_SENSOR_SERVICE_H
+#define ANDROID_SENSOR_SERVICE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Vector.h>
+#include <utils/SortedVector.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+#include <utils/RefBase.h>
+
+#include <binder/BinderService.h>
+
+#include <gui/Sensor.h>
+#include <gui/BitTube.h>
+#include <gui/ISensorServer.h>
+#include <gui/ISensorEventConnection.h>
+
+#include "SensorInterface.h"
+
+// ---------------------------------------------------------------------------
+
+#define DEBUG_CONNECTIONS false
+
+struct sensors_poll_device_t;
+struct sensors_module_t;
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+class SensorService :
+ public BinderService<SensorService>,
+ public BnSensorServer,
+ protected Thread
+{
+ friend class BinderService<SensorService>;
+
+ static const nsecs_t MINIMUM_EVENTS_PERIOD = 1000000; // 1000 Hz
+
+ SensorService();
+ virtual ~SensorService();
+
+ virtual void onFirstRef();
+
+ // Thread interface
+ virtual bool threadLoop();
+
+ // ISensorServer interface
+ virtual Vector<Sensor> getSensorList();
+ virtual sp<ISensorEventConnection> createSensorEventConnection();
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+
+ class SensorEventConnection : public BnSensorEventConnection {
+ virtual ~SensorEventConnection();
+ virtual void onFirstRef();
+ virtual sp<BitTube> getSensorChannel() const;
+ virtual status_t enableDisable(int handle, bool enabled);
+ virtual status_t setEventRate(int handle, nsecs_t ns);
+
+ sp<SensorService> const mService;
+ sp<BitTube> const mChannel;
+ mutable Mutex mConnectionLock;
+
+ // protected by SensorService::mLock
+ SortedVector<int> mSensorInfo;
+
+ public:
+ SensorEventConnection(const sp<SensorService>& service);
+
+ status_t sendEvents(sensors_event_t const* buffer, size_t count,
+ sensors_event_t* scratch = NULL);
+ bool hasSensor(int32_t handle) const;
+ bool hasAnySensor() const;
+ bool addSensor(int32_t handle);
+ bool removeSensor(int32_t handle);
+ };
+
+ class SensorRecord {
+ SortedVector< wp<SensorEventConnection> > mConnections;
+ public:
+ SensorRecord(const sp<SensorEventConnection>& connection);
+ bool addConnection(const sp<SensorEventConnection>& connection);
+ bool removeConnection(const wp<SensorEventConnection>& connection);
+ size_t getNumConnections() const { return mConnections.size(); }
+ };
+
+ SortedVector< wp<SensorEventConnection> > getActiveConnections() const;
+ DefaultKeyedVector<int, SensorInterface*> getActiveVirtualSensors() const;
+
+ String8 getSensorName(int handle) const;
+ void recordLastValue(sensors_event_t const * buffer, size_t count);
+ static void sortEventBuffer(sensors_event_t* buffer, size_t count);
+ void registerSensor(SensorInterface* sensor);
+ void registerVirtualSensor(SensorInterface* sensor);
+
+ // constants
+ Vector<Sensor> mSensorList;
+ Vector<Sensor> mUserSensorList;
+ DefaultKeyedVector<int, SensorInterface*> mSensorMap;
+ Vector<SensorInterface *> mVirtualSensorList;
+ status_t mInitCheck;
+
+ // protected by mLock
+ mutable Mutex mLock;
+ DefaultKeyedVector<int, SensorRecord*> mActiveSensors;
+ DefaultKeyedVector<int, SensorInterface*> mActiveVirtualSensors;
+ SortedVector< wp<SensorEventConnection> > mActiveConnections;
+
+ // The size of this vector is constant, only the items are mutable
+ KeyedVector<int32_t, sensors_event_t> mLastEventSeen;
+
+public:
+ static char const* getServiceName() { return "sensorservice"; }
+
+ void cleanupConnection(SensorEventConnection* connection);
+ status_t enable(const sp<SensorEventConnection>& connection, int handle);
+ status_t disable(const sp<SensorEventConnection>& connection, int handle);
+ status_t setEventRate(const sp<SensorEventConnection>& connection, int handle, nsecs_t ns);
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_SENSOR_SERVICE_H
diff --git a/services/sensorservice/mat.h b/services/sensorservice/mat.h
new file mode 100644
index 0000000..a76fc91
--- /dev/null
+++ b/services/sensorservice/mat.h
@@ -0,0 +1,393 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#ifndef ANDROID_MAT_H
+#define ANDROID_MAT_H
+
+#include "vec.h"
+#include "traits.h"
+
+// -----------------------------------------------------------------------
+
+namespace android {
+
+template <typename TYPE, size_t C, size_t R>
+class mat;
+
+namespace helpers {
+
+template <typename TYPE, size_t C, size_t R>
+mat<TYPE, C, R>& doAssign(
+ mat<TYPE, C, R>& lhs,
+ typename TypeTraits<TYPE>::ParameterType rhs) {
+ for (size_t i=0 ; i<C ; i++)
+ for (size_t j=0 ; j<R ; j++)
+ lhs[i][j] = (i==j) ? rhs : 0;
+ return lhs;
+}
+
+template <typename TYPE, size_t C, size_t R, size_t D>
+mat<TYPE, C, R> PURE doMul(
+ const mat<TYPE, D, R>& lhs,
+ const mat<TYPE, C, D>& rhs)
+{
+ mat<TYPE, C, R> res;
+ for (size_t c=0 ; c<C ; c++) {
+ for (size_t r=0 ; r<R ; r++) {
+ TYPE v(0);
+ for (size_t k=0 ; k<D ; k++) {
+ v += lhs[k][r] * rhs[c][k];
+ }
+ res[c][r] = v;
+ }
+ }
+ return res;
+}
+
+template <typename TYPE, size_t R, size_t D>
+vec<TYPE, R> PURE doMul(
+ const mat<TYPE, D, R>& lhs,
+ const vec<TYPE, D>& rhs)
+{
+ vec<TYPE, R> res;
+ for (size_t r=0 ; r<R ; r++) {
+ TYPE v(0);
+ for (size_t k=0 ; k<D ; k++) {
+ v += lhs[k][r] * rhs[k];
+ }
+ res[r] = v;
+ }
+ return res;
+}
+
+template <typename TYPE, size_t C, size_t R>
+mat<TYPE, C, R> PURE doMul(
+ const vec<TYPE, R>& lhs,
+ const mat<TYPE, C, 1>& rhs)
+{
+ mat<TYPE, C, R> res;
+ for (size_t c=0 ; c<C ; c++) {
+ for (size_t r=0 ; r<R ; r++) {
+ res[c][r] = lhs[r] * rhs[c][0];
+ }
+ }
+ return res;
+}
+
+template <typename TYPE, size_t C, size_t R>
+mat<TYPE, C, R> PURE doMul(
+ const mat<TYPE, C, R>& rhs,
+ typename TypeTraits<TYPE>::ParameterType v)
+{
+ mat<TYPE, C, R> res;
+ for (size_t c=0 ; c<C ; c++) {
+ for (size_t r=0 ; r<R ; r++) {
+ res[c][r] = rhs[c][r] * v;
+ }
+ }
+ return res;
+}
+
+template <typename TYPE, size_t C, size_t R>
+mat<TYPE, C, R> PURE doMul(
+ typename TypeTraits<TYPE>::ParameterType v,
+ const mat<TYPE, C, R>& rhs)
+{
+ mat<TYPE, C, R> res;
+ for (size_t c=0 ; c<C ; c++) {
+ for (size_t r=0 ; r<R ; r++) {
+ res[c][r] = v * rhs[c][r];
+ }
+ }
+ return res;
+}
+
+
+}; // namespace helpers
+
+// -----------------------------------------------------------------------
+
+template <typename TYPE, size_t C, size_t R>
+class mat : public vec< vec<TYPE, R>, C > {
+ typedef typename TypeTraits<TYPE>::ParameterType pTYPE;
+ typedef vec< vec<TYPE, R>, C > base;
+public:
+ // STL-like interface.
+ typedef TYPE value_type;
+ typedef TYPE& reference;
+ typedef TYPE const& const_reference;
+ typedef size_t size_type;
+ size_type size() const { return R*C; }
+ enum { ROWS = R, COLS = C };
+
+
+ // -----------------------------------------------------------------------
+ // default constructors
+
+ mat() { }
+ mat(const mat& rhs) : base(rhs) { }
+ mat(const base& rhs) : base(rhs) { }
+
+ // -----------------------------------------------------------------------
+ // conversion constructors
+
+ // sets the diagonal to the value, off-diagonal to zero
+ mat(pTYPE rhs) {
+ helpers::doAssign(*this, rhs);
+ }
+
+ // -----------------------------------------------------------------------
+ // Assignment
+
+ mat& operator=(const mat& rhs) {
+ base::operator=(rhs);
+ return *this;
+ }
+
+ mat& operator=(const base& rhs) {
+ base::operator=(rhs);
+ return *this;
+ }
+
+ mat& operator=(pTYPE rhs) {
+ return helpers::doAssign(*this, rhs);
+ }
+
+ // -----------------------------------------------------------------------
+ // non-member function declaration and definition
+
+ friend inline mat PURE operator + (const mat& lhs, const mat& rhs) {
+ return helpers::doAdd(
+ static_cast<const base&>(lhs),
+ static_cast<const base&>(rhs));
+ }
+ friend inline mat PURE operator - (const mat& lhs, const mat& rhs) {
+ return helpers::doSub(
+ static_cast<const base&>(lhs),
+ static_cast<const base&>(rhs));
+ }
+
+ // matrix*matrix
+ template <size_t D>
+ friend mat PURE operator * (
+ const mat<TYPE, D, R>& lhs,
+ const mat<TYPE, C, D>& rhs) {
+ return helpers::doMul(lhs, rhs);
+ }
+
+ // matrix*vector
+ friend vec<TYPE, R> PURE operator * (
+ const mat& lhs, const vec<TYPE, C>& rhs) {
+ return helpers::doMul(lhs, rhs);
+ }
+
+ // vector*matrix
+ friend mat PURE operator * (
+ const vec<TYPE, R>& lhs, const mat<TYPE, C, 1>& rhs) {
+ return helpers::doMul(lhs, rhs);
+ }
+
+ // matrix*scalar
+ friend inline mat PURE operator * (const mat& lhs, pTYPE v) {
+ return helpers::doMul(lhs, v);
+ }
+
+ // scalar*matrix
+ friend inline mat PURE operator * (pTYPE v, const mat& rhs) {
+ return helpers::doMul(v, rhs);
+ }
+
+ // -----------------------------------------------------------------------
+ // streaming operator to set the columns of the matrix:
+ // example:
+ // mat33_t m;
+ // m << v0 << v1 << v2;
+
+ // column_builder<> stores the matrix and knows which column to set
+ template<size_t PREV_COLUMN>
+ struct column_builder {
+ mat& matrix;
+ column_builder(mat& matrix) : matrix(matrix) { }
+ };
+
+ // operator << is not a method of column_builder<> so we can
+ // overload it for unauthorized values (partial specialization
+ // not allowed in class-scope).
+ // we just set the column and return the next column_builder<>
+ template<size_t PREV_COLUMN>
+ friend column_builder<PREV_COLUMN+1> operator << (
+ const column_builder<PREV_COLUMN>& lhs,
+ const vec<TYPE, R>& rhs) {
+ lhs.matrix[PREV_COLUMN+1] = rhs;
+ return column_builder<PREV_COLUMN+1>(lhs.matrix);
+ }
+
+ // we return void here so we get a compile-time error if the
+ // user tries to set too many columns
+ friend void operator << (
+ const column_builder<C-2>& lhs,
+ const vec<TYPE, R>& rhs) {
+ lhs.matrix[C-1] = rhs;
+ }
+
+ // this is where the process starts. we set the first columns and
+ // return the next column_builder<>
+ column_builder<0> operator << (const vec<TYPE, R>& rhs) {
+ (*this)[0] = rhs;
+ return column_builder<0>(*this);
+ }
+};
+
+// Specialize column matrix so they're exactly equivalent to a vector
+template <typename TYPE, size_t R>
+class mat<TYPE, 1, R> : public vec<TYPE, R> {
+ typedef vec<TYPE, R> base;
+public:
+ // STL-like interface.
+ typedef TYPE value_type;
+ typedef TYPE& reference;
+ typedef TYPE const& const_reference;
+ typedef size_t size_type;
+ size_type size() const { return R; }
+ enum { ROWS = R, COLS = 1 };
+
+ mat() { }
+ mat(const base& rhs) : base(rhs) { }
+ mat(const mat& rhs) : base(rhs) { }
+ mat(const TYPE& rhs) { helpers::doAssign(*this, rhs); }
+ mat& operator=(const mat& rhs) { base::operator=(rhs); return *this; }
+ mat& operator=(const base& rhs) { base::operator=(rhs); return *this; }
+ mat& operator=(const TYPE& rhs) { return helpers::doAssign(*this, rhs); }
+ // we only have one column, so ignore the index
+ const base& operator[](size_t) const { return *this; }
+ base& operator[](size_t) { return *this; }
+ void operator << (const vec<TYPE, R>& rhs) { base::operator[](0) = rhs; }
+};
+
+// -----------------------------------------------------------------------
+// matrix functions
+
+// transpose. this handles matrices of matrices
+inline int PURE transpose(int v) { return v; }
+inline float PURE transpose(float v) { return v; }
+inline double PURE transpose(double v) { return v; }
+
+// Transpose a matrix
+template <typename TYPE, size_t C, size_t R>
+mat<TYPE, R, C> PURE transpose(const mat<TYPE, C, R>& m) {
+ mat<TYPE, R, C> r;
+ for (size_t i=0 ; i<R ; i++)
+ for (size_t j=0 ; j<C ; j++)
+ r[i][j] = transpose(m[j][i]);
+ return r;
+}
+
+// Calculate the trace of a matrix
+template <typename TYPE, size_t C> static TYPE trace(const mat<TYPE, C, C>& m) {
+ TYPE t;
+ for (size_t i=0 ; i<C ; i++)
+ t += m[i][i];
+ return t;
+}
+
+// Test positive-semidefiniteness of a matrix
+template <typename TYPE, size_t C>
+static bool isPositiveSemidefinite(const mat<TYPE, C, C>& m, TYPE tolerance) {
+ for (size_t i=0 ; i<C ; i++)
+ if (m[i][i] < 0)
+ return false;
+
+ for (size_t i=0 ; i<C ; i++)
+ for (size_t j=i+1 ; j<C ; j++)
+ if (fabs(m[i][j] - m[j][i]) > tolerance)
+ return false;
+
+ return true;
+}
+
+// Transpose a vector
+template <
+ template<typename T, size_t S> class VEC,
+ typename TYPE,
+ size_t SIZE
+>
+mat<TYPE, SIZE, 1> PURE transpose(const VEC<TYPE, SIZE>& v) {
+ mat<TYPE, SIZE, 1> r;
+ for (size_t i=0 ; i<SIZE ; i++)
+ r[i][0] = transpose(v[i]);
+ return r;
+}
+
+// -----------------------------------------------------------------------
+// "dumb" matrix inversion
+template<typename T, size_t N>
+mat<T, N, N> PURE invert(const mat<T, N, N>& src) {
+ T t;
+ size_t swap;
+ mat<T, N, N> tmp(src);
+ mat<T, N, N> inverse(1);
+
+ for (size_t i=0 ; i<N ; i++) {
+ // look for largest element in column
+ swap = i;
+ for (size_t j=i+1 ; j<N ; j++) {
+ if (fabs(tmp[j][i]) > fabs(tmp[i][i])) {
+ swap = j;
+ }
+ }
+
+ if (swap != i) {
+ /* swap rows. */
+ for (size_t k=0 ; k<N ; k++) {
+ t = tmp[i][k];
+ tmp[i][k] = tmp[swap][k];
+ tmp[swap][k] = t;
+
+ t = inverse[i][k];
+ inverse[i][k] = inverse[swap][k];
+ inverse[swap][k] = t;
+ }
+ }
+
+ t = 1 / tmp[i][i];
+ for (size_t k=0 ; k<N ; k++) {
+ tmp[i][k] *= t;
+ inverse[i][k] *= t;
+ }
+ for (size_t j=0 ; j<N ; j++) {
+ if (j != i) {
+ t = tmp[j][i];
+ for (size_t k=0 ; k<N ; k++) {
+ tmp[j][k] -= tmp[i][k] * t;
+ inverse[j][k] -= inverse[i][k] * t;
+ }
+ }
+ }
+ }
+ return inverse;
+}
+
+// -----------------------------------------------------------------------
+
+typedef mat<float, 2, 2> mat22_t;
+typedef mat<float, 3, 3> mat33_t;
+typedef mat<float, 4, 4> mat44_t;
+
+// -----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif /* ANDROID_MAT_H */
diff --git a/services/sensorservice/quat.h b/services/sensorservice/quat.h
new file mode 100644
index 0000000..fea1afe
--- /dev/null
+++ b/services/sensorservice/quat.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#ifndef ANDROID_QUAT_H
+#define ANDROID_QUAT_H
+
+#include <math.h>
+
+#include "vec.h"
+#include "mat.h"
+
+// -----------------------------------------------------------------------
+namespace android {
+// -----------------------------------------------------------------------
+
+template <typename TYPE>
+mat<TYPE, 3, 3> quatToMatrix(const vec<TYPE, 4>& q) {
+ mat<TYPE, 3, 3> R;
+ TYPE q0(q.w);
+ TYPE q1(q.x);
+ TYPE q2(q.y);
+ TYPE q3(q.z);
+ TYPE sq_q1 = 2 * q1 * q1;
+ TYPE sq_q2 = 2 * q2 * q2;
+ TYPE sq_q3 = 2 * q3 * q3;
+ TYPE q1_q2 = 2 * q1 * q2;
+ TYPE q3_q0 = 2 * q3 * q0;
+ TYPE q1_q3 = 2 * q1 * q3;
+ TYPE q2_q0 = 2 * q2 * q0;
+ TYPE q2_q3 = 2 * q2 * q3;
+ TYPE q1_q0 = 2 * q1 * q0;
+ R[0][0] = 1 - sq_q2 - sq_q3;
+ R[0][1] = q1_q2 - q3_q0;
+ R[0][2] = q1_q3 + q2_q0;
+ R[1][0] = q1_q2 + q3_q0;
+ R[1][1] = 1 - sq_q1 - sq_q3;
+ R[1][2] = q2_q3 - q1_q0;
+ R[2][0] = q1_q3 - q2_q0;
+ R[2][1] = q2_q3 + q1_q0;
+ R[2][2] = 1 - sq_q1 - sq_q2;
+ return R;
+}
+
+template <typename TYPE>
+vec<TYPE, 4> matrixToQuat(const mat<TYPE, 3, 3>& R) {
+ // matrix to quaternion
+
+ struct {
+ inline TYPE operator()(TYPE v) {
+ return v < 0 ? 0 : v;
+ }
+ } clamp;
+
+ vec<TYPE, 4> q;
+ const float Hx = R[0].x;
+ const float My = R[1].y;
+ const float Az = R[2].z;
+ q.x = sqrtf( clamp( Hx - My - Az + 1) * 0.25f );
+ q.y = sqrtf( clamp(-Hx + My - Az + 1) * 0.25f );
+ q.z = sqrtf( clamp(-Hx - My + Az + 1) * 0.25f );
+ q.w = sqrtf( clamp( Hx + My + Az + 1) * 0.25f );
+ q.x = copysignf(q.x, R[2].y - R[1].z);
+ q.y = copysignf(q.y, R[0].z - R[2].x);
+ q.z = copysignf(q.z, R[1].x - R[0].y);
+ // guaranteed to be unit-quaternion
+ return q;
+}
+
+template <typename TYPE>
+vec<TYPE, 4> normalize_quat(const vec<TYPE, 4>& q) {
+ vec<TYPE, 4> r(q);
+ if (r.w < 0) {
+ r = -r;
+ }
+ return normalize(r);
+}
+
+// -----------------------------------------------------------------------
+
+typedef vec4_t quat_t;
+
+// -----------------------------------------------------------------------
+}; // namespace android
+
+#endif /* ANDROID_QUAT_H */
diff --git a/services/sensorservice/tests/Android.mk b/services/sensorservice/tests/Android.mk
new file mode 100644
index 0000000..45296dd
--- /dev/null
+++ b/services/sensorservice/tests/Android.mk
@@ -0,0 +1,14 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ sensorservicetest.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils libutils libui libgui
+
+LOCAL_MODULE:= test-sensorservice
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_EXECUTABLE)
diff --git a/services/sensorservice/tests/sensorservicetest.cpp b/services/sensorservice/tests/sensorservicetest.cpp
new file mode 100644
index 0000000..1025fa8
--- /dev/null
+++ b/services/sensorservice/tests/sensorservicetest.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2010 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 <android/sensor.h>
+#include <gui/Sensor.h>
+#include <gui/SensorManager.h>
+#include <gui/SensorEventQueue.h>
+#include <utils/Looper.h>
+
+using namespace android;
+
+static nsecs_t sStartTime = 0;
+
+
+int receiver(int fd, int events, void* data)
+{
+ sp<SensorEventQueue> q((SensorEventQueue*)data);
+ ssize_t n;
+ ASensorEvent buffer[8];
+
+ static nsecs_t oldTimeStamp = 0;
+
+ while ((n = q->read(buffer, 8)) > 0) {
+ for (int i=0 ; i<n ; i++) {
+ float t;
+ if (oldTimeStamp) {
+ t = float(buffer[i].timestamp - oldTimeStamp) / s2ns(1);
+ } else {
+ t = float(buffer[i].timestamp - sStartTime) / s2ns(1);
+ }
+ oldTimeStamp = buffer[i].timestamp;
+
+ if (buffer[i].type == Sensor::TYPE_ACCELEROMETER) {
+ printf("%lld\t%8f\t%8f\t%8f\t%f\n",
+ buffer[i].timestamp,
+ buffer[i].data[0], buffer[i].data[1], buffer[i].data[2],
+ 1.0/t);
+ }
+
+ }
+ }
+ if (n<0 && n != -EAGAIN) {
+ printf("error reading events (%s)\n", strerror(-n));
+ }
+ return 1;
+}
+
+
+int main(int argc, char** argv)
+{
+ SensorManager& mgr(SensorManager::getInstance());
+
+ Sensor const* const* list;
+ ssize_t count = mgr.getSensorList(&list);
+ printf("numSensors=%d\n", int(count));
+
+ sp<SensorEventQueue> q = mgr.createEventQueue();
+ printf("queue=%p\n", q.get());
+
+ Sensor const* accelerometer = mgr.getDefaultSensor(Sensor::TYPE_ACCELEROMETER);
+ printf("accelerometer=%p (%s)\n",
+ accelerometer, accelerometer->getName().string());
+
+ sStartTime = systemTime();
+
+ q->enableSensor(accelerometer);
+
+ q->setEventRate(accelerometer, ms2ns(10));
+
+ sp<Looper> loop = new Looper(false);
+ loop->addFd(q->getFd(), 0, ALOOPER_EVENT_INPUT, receiver, q.get());
+
+ do {
+ //printf("about to poll...\n");
+ int32_t ret = loop->pollOnce(-1);
+ switch (ret) {
+ case ALOOPER_POLL_WAKE:
+ //("ALOOPER_POLL_WAKE\n");
+ break;
+ case ALOOPER_POLL_CALLBACK:
+ //("ALOOPER_POLL_CALLBACK\n");
+ break;
+ case ALOOPER_POLL_TIMEOUT:
+ printf("ALOOPER_POLL_TIMEOUT\n");
+ break;
+ case ALOOPER_POLL_ERROR:
+ printf("ALOOPER_POLL_TIMEOUT\n");
+ break;
+ default:
+ printf("ugh? poll returned %d\n", ret);
+ break;
+ }
+ } while (1);
+
+
+ return 0;
+}
diff --git a/services/sensorservice/traits.h b/services/sensorservice/traits.h
new file mode 100644
index 0000000..da4c599
--- /dev/null
+++ b/services/sensorservice/traits.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#ifndef ANDROID_TRAITS_H
+#define ANDROID_TRAITS_H
+
+// -----------------------------------------------------------------------
+// Typelists
+
+namespace android {
+
+// end-of-list marker
+class NullType {};
+
+// type-list node
+template <typename T, typename U>
+struct TypeList {
+ typedef T Head;
+ typedef U Tail;
+};
+
+// helpers to build typelists
+#define TYPELIST_1(T1) TypeList<T1, NullType>
+#define TYPELIST_2(T1, T2) TypeList<T1, TYPELIST_1(T2)>
+#define TYPELIST_3(T1, T2, T3) TypeList<T1, TYPELIST_2(T2, T3)>
+#define TYPELIST_4(T1, T2, T3, T4) TypeList<T1, TYPELIST_3(T2, T3, T4)>
+
+// typelists algorithms
+namespace TL {
+template <typename TList, typename T> struct IndexOf;
+
+template <typename T>
+struct IndexOf<NullType, T> {
+ enum { value = -1 };
+};
+
+template <typename T, typename Tail>
+struct IndexOf<TypeList<T, Tail>, T> {
+ enum { value = 0 };
+};
+
+template <typename Head, typename Tail, typename T>
+struct IndexOf<TypeList<Head, Tail>, T> {
+private:
+ enum { temp = IndexOf<Tail, T>::value };
+public:
+ enum { value = temp == -1 ? -1 : 1 + temp };
+};
+
+}; // namespace TL
+
+// type selection based on a boolean
+template <bool flag, typename T, typename U>
+struct Select {
+ typedef T Result;
+};
+template <typename T, typename U>
+struct Select<false, T, U> {
+ typedef U Result;
+};
+
+// -----------------------------------------------------------------------
+// Type traits
+
+template <typename T>
+class TypeTraits {
+ typedef TYPELIST_4(
+ unsigned char, unsigned short,
+ unsigned int, unsigned long int) UnsignedInts;
+
+ typedef TYPELIST_4(
+ signed char, signed short,
+ signed int, signed long int) SignedInts;
+
+ typedef TYPELIST_1(
+ bool) OtherInts;
+
+ typedef TYPELIST_3(
+ float, double, long double) Floats;
+
+ template<typename U> struct PointerTraits {
+ enum { result = false };
+ typedef NullType PointeeType;
+ };
+ template<typename U> struct PointerTraits<U*> {
+ enum { result = true };
+ typedef U PointeeType;
+ };
+
+public:
+ enum { isStdUnsignedInt = TL::IndexOf<UnsignedInts, T>::value >= 0 };
+ enum { isStdSignedInt = TL::IndexOf<SignedInts, T>::value >= 0 };
+ enum { isStdIntegral = TL::IndexOf<OtherInts, T>::value >= 0 || isStdUnsignedInt || isStdSignedInt };
+ enum { isStdFloat = TL::IndexOf<Floats, T>::value >= 0 };
+ enum { isPointer = PointerTraits<T>::result };
+ enum { isStdArith = isStdIntegral || isStdFloat };
+
+ // best parameter type for given type
+ typedef typename Select<isStdArith || isPointer, T, const T&>::Result ParameterType;
+};
+
+// -----------------------------------------------------------------------
+}; // namespace android
+
+#endif /* ANDROID_TRAITS_H */
diff --git a/services/sensorservice/vec.h b/services/sensorservice/vec.h
new file mode 100644
index 0000000..24f30ff
--- /dev/null
+++ b/services/sensorservice/vec.h
@@ -0,0 +1,438 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#ifndef ANDROID_VEC_H
+#define ANDROID_VEC_H
+
+#include <math.h>
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include "traits.h"
+
+// -----------------------------------------------------------------------
+
+#define PURE __attribute__((pure))
+
+namespace android {
+
+// -----------------------------------------------------------------------
+// non-inline helpers
+
+template <typename TYPE, size_t SIZE>
+class vec;
+
+template <typename TYPE, size_t SIZE>
+class vbase;
+
+namespace helpers {
+
+template <typename T> inline T min(T a, T b) { return a<b ? a : b; }
+template <typename T> inline T max(T a, T b) { return a>b ? a : b; }
+
+template < template<typename T, size_t S> class VEC,
+ typename TYPE, size_t SIZE, size_t S>
+vec<TYPE, SIZE>& doAssign(
+ vec<TYPE, SIZE>& lhs, const VEC<TYPE, S>& rhs) {
+ const size_t minSize = min(SIZE, S);
+ const size_t maxSize = max(SIZE, S);
+ for (size_t i=0 ; i<minSize ; i++)
+ lhs[i] = rhs[i];
+ for (size_t i=minSize ; i<maxSize ; i++)
+ lhs[i] = 0;
+ return lhs;
+}
+
+
+template <
+ template<typename T, size_t S> class VLHS,
+ template<typename T, size_t S> class VRHS,
+ typename TYPE,
+ size_t SIZE
+>
+VLHS<TYPE, SIZE> PURE doAdd(
+ const VLHS<TYPE, SIZE>& lhs,
+ const VRHS<TYPE, SIZE>& rhs) {
+ VLHS<TYPE, SIZE> r;
+ for (size_t i=0 ; i<SIZE ; i++)
+ r[i] = lhs[i] + rhs[i];
+ return r;
+}
+
+template <
+ template<typename T, size_t S> class VLHS,
+ template<typename T, size_t S> class VRHS,
+ typename TYPE,
+ size_t SIZE
+>
+VLHS<TYPE, SIZE> PURE doSub(
+ const VLHS<TYPE, SIZE>& lhs,
+ const VRHS<TYPE, SIZE>& rhs) {
+ VLHS<TYPE, SIZE> r;
+ for (size_t i=0 ; i<SIZE ; i++)
+ r[i] = lhs[i] - rhs[i];
+ return r;
+}
+
+template <
+ template<typename T, size_t S> class VEC,
+ typename TYPE,
+ size_t SIZE
+>
+VEC<TYPE, SIZE> PURE doMulScalar(
+ const VEC<TYPE, SIZE>& lhs,
+ typename TypeTraits<TYPE>::ParameterType rhs) {
+ VEC<TYPE, SIZE> r;
+ for (size_t i=0 ; i<SIZE ; i++)
+ r[i] = lhs[i] * rhs;
+ return r;
+}
+
+template <
+ template<typename T, size_t S> class VEC,
+ typename TYPE,
+ size_t SIZE
+>
+VEC<TYPE, SIZE> PURE doScalarMul(
+ typename TypeTraits<TYPE>::ParameterType lhs,
+ const VEC<TYPE, SIZE>& rhs) {
+ VEC<TYPE, SIZE> r;
+ for (size_t i=0 ; i<SIZE ; i++)
+ r[i] = lhs * rhs[i];
+ return r;
+}
+
+}; // namespace helpers
+
+// -----------------------------------------------------------------------
+// Below we define the mathematical operators for vectors.
+// We use template template arguments so we can generically
+// handle the case where the right-hand-size and left-hand-side are
+// different vector types (but with same value_type and size).
+// This is needed for performance when using ".xy{z}" element access
+// on vec<>. Without this, an extra conversion to vec<> would be needed.
+//
+// example:
+// vec4_t a;
+// vec3_t b;
+// vec3_t c = a.xyz + b;
+//
+// "a.xyz + b" is a mixed-operation between a vbase<> and a vec<>, requiring
+// a conversion of vbase<> to vec<>. The template gunk below avoids this,
+// by allowing the addition on these different vector types directly
+//
+
+template <
+ template<typename T, size_t S> class VLHS,
+ template<typename T, size_t S> class VRHS,
+ typename TYPE,
+ size_t SIZE
+>
+inline VLHS<TYPE, SIZE> PURE operator + (
+ const VLHS<TYPE, SIZE>& lhs,
+ const VRHS<TYPE, SIZE>& rhs) {
+ return helpers::doAdd(lhs, rhs);
+}
+
+template <
+ template<typename T, size_t S> class VLHS,
+ template<typename T, size_t S> class VRHS,
+ typename TYPE,
+ size_t SIZE
+>
+inline VLHS<TYPE, SIZE> PURE operator - (
+ const VLHS<TYPE, SIZE>& lhs,
+ const VRHS<TYPE, SIZE>& rhs) {
+ return helpers::doSub(lhs, rhs);
+}
+
+template <
+ template<typename T, size_t S> class VEC,
+ typename TYPE,
+ size_t SIZE
+>
+inline VEC<TYPE, SIZE> PURE operator * (
+ const VEC<TYPE, SIZE>& lhs,
+ typename TypeTraits<TYPE>::ParameterType rhs) {
+ return helpers::doMulScalar(lhs, rhs);
+}
+
+template <
+ template<typename T, size_t S> class VEC,
+ typename TYPE,
+ size_t SIZE
+>
+inline VEC<TYPE, SIZE> PURE operator * (
+ typename TypeTraits<TYPE>::ParameterType lhs,
+ const VEC<TYPE, SIZE>& rhs) {
+ return helpers::doScalarMul(lhs, rhs);
+}
+
+
+template <
+ template<typename T, size_t S> class VLHS,
+ template<typename T, size_t S> class VRHS,
+ typename TYPE,
+ size_t SIZE
+>
+TYPE PURE dot_product(
+ const VLHS<TYPE, SIZE>& lhs,
+ const VRHS<TYPE, SIZE>& rhs) {
+ TYPE r(0);
+ for (size_t i=0 ; i<SIZE ; i++)
+ r += lhs[i] * rhs[i];
+ return r;
+}
+
+template <
+ template<typename T, size_t S> class V,
+ typename TYPE,
+ size_t SIZE
+>
+TYPE PURE length(const V<TYPE, SIZE>& v) {
+ return sqrt(dot_product(v, v));
+}
+
+template <
+ template<typename T, size_t S> class V,
+ typename TYPE,
+ size_t SIZE
+>
+TYPE PURE length_squared(const V<TYPE, SIZE>& v) {
+ return dot_product(v, v);
+}
+
+template <
+ template<typename T, size_t S> class V,
+ typename TYPE,
+ size_t SIZE
+>
+V<TYPE, SIZE> PURE normalize(const V<TYPE, SIZE>& v) {
+ return v * (1/length(v));
+}
+
+template <
+ template<typename T, size_t S> class VLHS,
+ template<typename T, size_t S> class VRHS,
+ typename TYPE
+>
+VLHS<TYPE, 3> PURE cross_product(
+ const VLHS<TYPE, 3>& u,
+ const VRHS<TYPE, 3>& v) {
+ VLHS<TYPE, 3> r;
+ r.x = u.y*v.z - u.z*v.y;
+ r.y = u.z*v.x - u.x*v.z;
+ r.z = u.x*v.y - u.y*v.x;
+ return r;
+}
+
+
+template <typename TYPE, size_t SIZE>
+vec<TYPE, SIZE> PURE operator - (const vec<TYPE, SIZE>& lhs) {
+ vec<TYPE, SIZE> r;
+ for (size_t i=0 ; i<SIZE ; i++)
+ r[i] = -lhs[i];
+ return r;
+}
+
+// -----------------------------------------------------------------------
+
+// This our basic vector type, it just implements the data storage
+// and accessors.
+
+template <typename TYPE, size_t SIZE>
+struct vbase {
+ TYPE v[SIZE];
+ inline const TYPE& operator[](size_t i) const { return v[i]; }
+ inline TYPE& operator[](size_t i) { return v[i]; }
+};
+template<> struct vbase<float, 2> {
+ union {
+ float v[2];
+ struct { float x, y; };
+ struct { float s, t; };
+ };
+ inline const float& operator[](size_t i) const { return v[i]; }
+ inline float& operator[](size_t i) { return v[i]; }
+};
+template<> struct vbase<float, 3> {
+ union {
+ float v[3];
+ struct { float x, y, z; };
+ struct { float s, t, r; };
+ vbase<float, 2> xy;
+ vbase<float, 2> st;
+ };
+ inline const float& operator[](size_t i) const { return v[i]; }
+ inline float& operator[](size_t i) { return v[i]; }
+};
+template<> struct vbase<float, 4> {
+ union {
+ float v[4];
+ struct { float x, y, z, w; };
+ struct { float s, t, r, q; };
+ vbase<float, 3> xyz;
+ vbase<float, 3> str;
+ vbase<float, 2> xy;
+ vbase<float, 2> st;
+ };
+ inline const float& operator[](size_t i) const { return v[i]; }
+ inline float& operator[](size_t i) { return v[i]; }
+};
+
+// -----------------------------------------------------------------------
+
+template <typename TYPE, size_t SIZE>
+class vec : public vbase<TYPE, SIZE>
+{
+ typedef typename TypeTraits<TYPE>::ParameterType pTYPE;
+ typedef vbase<TYPE, SIZE> base;
+
+public:
+ // STL-like interface.
+ typedef TYPE value_type;
+ typedef TYPE& reference;
+ typedef TYPE const& const_reference;
+ typedef size_t size_type;
+
+ typedef TYPE* iterator;
+ typedef TYPE const* const_iterator;
+ iterator begin() { return base::v; }
+ iterator end() { return base::v + SIZE; }
+ const_iterator begin() const { return base::v; }
+ const_iterator end() const { return base::v + SIZE; }
+ size_type size() const { return SIZE; }
+
+ // -----------------------------------------------------------------------
+ // default constructors
+
+ vec() { }
+ vec(const vec& rhs) : base(rhs) { }
+ vec(const base& rhs) : base(rhs) { }
+
+ // -----------------------------------------------------------------------
+ // conversion constructors
+
+ vec(pTYPE rhs) {
+ for (size_t i=0 ; i<SIZE ; i++)
+ base::operator[](i) = rhs;
+ }
+
+ template < template<typename T, size_t S> class VEC, size_t S>
+ explicit vec(const VEC<TYPE, S>& rhs) {
+ helpers::doAssign(*this, rhs);
+ }
+
+ explicit vec(TYPE const* array) {
+ for (size_t i=0 ; i<SIZE ; i++)
+ base::operator[](i) = array[i];
+ }
+
+ // -----------------------------------------------------------------------
+ // Assignment
+
+ vec& operator = (const vec& rhs) {
+ base::operator=(rhs);
+ return *this;
+ }
+
+ vec& operator = (const base& rhs) {
+ base::operator=(rhs);
+ return *this;
+ }
+
+ vec& operator = (pTYPE rhs) {
+ for (size_t i=0 ; i<SIZE ; i++)
+ base::operator[](i) = rhs;
+ return *this;
+ }
+
+ template < template<typename T, size_t S> class VEC, size_t S>
+ vec& operator = (const VEC<TYPE, S>& rhs) {
+ return helpers::doAssign(*this, rhs);
+ }
+
+ // -----------------------------------------------------------------------
+ // operation-assignment
+
+ vec& operator += (const vec& rhs);
+ vec& operator -= (const vec& rhs);
+ vec& operator *= (pTYPE rhs);
+
+ // -----------------------------------------------------------------------
+ // non-member function declaration and definition
+ // NOTE: we declare the non-member function as friend inside the class
+ // so that they are known to the compiler when the class is instantiated.
+ // This helps the compiler doing template argument deduction when the
+ // passed types are not identical. Essentially this helps with
+ // type conversion so that you can multiply a vec<float> by an scalar int
+ // (for instance).
+
+ friend inline vec PURE operator + (const vec& lhs, const vec& rhs) {
+ return helpers::doAdd(lhs, rhs);
+ }
+ friend inline vec PURE operator - (const vec& lhs, const vec& rhs) {
+ return helpers::doSub(lhs, rhs);
+ }
+ friend inline vec PURE operator * (const vec& lhs, pTYPE v) {
+ return helpers::doMulScalar(lhs, v);
+ }
+ friend inline vec PURE operator * (pTYPE v, const vec& rhs) {
+ return helpers::doScalarMul(v, rhs);
+ }
+ friend inline TYPE PURE dot_product(const vec& lhs, const vec& rhs) {
+ return android::dot_product(lhs, rhs);
+ }
+};
+
+// -----------------------------------------------------------------------
+
+template <typename TYPE, size_t SIZE>
+vec<TYPE, SIZE>& vec<TYPE, SIZE>::operator += (const vec<TYPE, SIZE>& rhs) {
+ vec<TYPE, SIZE>& lhs(*this);
+ for (size_t i=0 ; i<SIZE ; i++)
+ lhs[i] += rhs[i];
+ return lhs;
+}
+
+template <typename TYPE, size_t SIZE>
+vec<TYPE, SIZE>& vec<TYPE, SIZE>::operator -= (const vec<TYPE, SIZE>& rhs) {
+ vec<TYPE, SIZE>& lhs(*this);
+ for (size_t i=0 ; i<SIZE ; i++)
+ lhs[i] -= rhs[i];
+ return lhs;
+}
+
+template <typename TYPE, size_t SIZE>
+vec<TYPE, SIZE>& vec<TYPE, SIZE>::operator *= (vec<TYPE, SIZE>::pTYPE rhs) {
+ vec<TYPE, SIZE>& lhs(*this);
+ for (size_t i=0 ; i<SIZE ; i++)
+ lhs[i] *= rhs;
+ return lhs;
+}
+
+// -----------------------------------------------------------------------
+
+typedef vec<float, 2> vec2_t;
+typedef vec<float, 3> vec3_t;
+typedef vec<float, 4> vec4_t;
+
+// -----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif /* ANDROID_VEC_H */