move sensorservice from frameworks/base to frameworks/native
this commit also imports all of sensorservice history. Change-Id: Iadffcc92be600c48175b8afadcb15b6648532b3f
This commit is contained in:
commit
852db07d69
19
cmds/sensorservice/Android.mk
Normal file
19
cmds/sensorservice/Android.mk
Normal file
@ -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)
|
25
cmds/sensorservice/main_sensorservice.cpp
Normal file
25
cmds/sensorservice/main_sensorservice.cpp
Normal file
@ -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;
|
||||
}
|
31
services/sensorservice/Android.mk
Normal file
31
services/sensorservice/Android.mk
Normal file
@ -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)
|
86
services/sensorservice/CorrectedGyroSensor.cpp
Normal file
86
services/sensorservice/CorrectedGyroSensor.cpp
Normal file
@ -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
|
||||
|
52
services/sensorservice/CorrectedGyroSensor.h
Normal file
52
services/sensorservice/CorrectedGyroSensor.h
Normal file
@ -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
|
464
services/sensorservice/Fusion.cpp
Normal file
464
services/sensorservice/Fusion.cpp
Normal file
@ -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
|
||||
|
85
services/sensorservice/Fusion.h
Normal file
85
services/sensorservice/Fusion.h
Normal file
@ -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
|
94
services/sensorservice/GravitySensor.cpp
Normal file
94
services/sensorservice/GravitySensor.cpp
Normal file
@ -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
|
||||
|
52
services/sensorservice/GravitySensor.h
Normal file
52
services/sensorservice/GravitySensor.h
Normal file
@ -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
|
79
services/sensorservice/LinearAccelerationSensor.cpp
Normal file
79
services/sensorservice/LinearAccelerationSensor.cpp
Normal file
@ -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
|
||||
|
52
services/sensorservice/LinearAccelerationSensor.h
Normal file
52
services/sensorservice/LinearAccelerationSensor.h
Normal file
@ -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
|
90
services/sensorservice/OrientationSensor.cpp
Normal file
90
services/sensorservice/OrientationSensor.cpp
Normal file
@ -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
|
||||
|
51
services/sensorservice/OrientationSensor.h
Normal file
51
services/sensorservice/OrientationSensor.h
Normal file
@ -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
|
129
services/sensorservice/RotationVectorSensor.cpp
Normal file
129
services/sensorservice/RotationVectorSensor.cpp
Normal file
@ -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
|
||||
|
66
services/sensorservice/RotationVectorSensor.h
Normal file
66
services/sensorservice/RotationVectorSensor.h
Normal file
@ -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
|
282
services/sensorservice/SensorDevice.cpp
Normal file
282
services/sensorservice/SensorDevice.cpp
Normal file
@ -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
|
||||
|
64
services/sensorservice/SensorDevice.h
Normal file
64
services/sensorservice/SensorDevice.h
Normal file
@ -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
|
148
services/sensorservice/SensorFusion.cpp
Normal file
148
services/sensorservice/SensorFusion.cpp
Normal file
@ -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
|
78
services/sensorservice/SensorFusion.h
Normal file
78
services/sensorservice/SensorFusion.h
Normal file
@ -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
|
63
services/sensorservice/SensorInterface.cpp
Normal file
63
services/sensorservice/SensorInterface.cpp
Normal file
@ -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
|
70
services/sensorservice/SensorInterface.h
Normal file
70
services/sensorservice/SensorInterface.h
Normal file
@ -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
|
637
services/sensorservice/SensorService.cpp
Normal file
637
services/sensorservice/SensorService.cpp
Normal file
@ -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
|
||||
|
142
services/sensorservice/SensorService.h
Normal file
142
services/sensorservice/SensorService.h
Normal file
@ -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
|
393
services/sensorservice/mat.h
Normal file
393
services/sensorservice/mat.h
Normal file
@ -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 */
|
98
services/sensorservice/quat.h
Normal file
98
services/sensorservice/quat.h
Normal file
@ -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 */
|
14
services/sensorservice/tests/Android.mk
Normal file
14
services/sensorservice/tests/Android.mk
Normal file
@ -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)
|
110
services/sensorservice/tests/sensorservicetest.cpp
Normal file
110
services/sensorservice/tests/sensorservicetest.cpp
Normal file
@ -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;
|
||||
}
|
118
services/sensorservice/traits.h
Normal file
118
services/sensorservice/traits.h
Normal file
@ -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 */
|
438
services/sensorservice/vec.h
Normal file
438
services/sensorservice/vec.h
Normal file
@ -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 */
|
Loading…
Reference in New Issue
Block a user