package org.witness.informacam.informa.suckers;
import java.text.DecimalFormat;
import java.util.List;
import java.util.TimerTask;
import org.witness.informacam.informa.SensorLogger;
import org.witness.informacam.json.*;
import org.witness.informacam.models.j3m.ILogPack;
import org.witness.informacam.utils.Constants.Suckers;
import org.witness.informacam.utils.Constants.Suckers.Accelerometer;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.Log;
@SuppressWarnings("rawtypes")
public class AccelerometerSucker extends SensorLogger implements SensorEventListener {
SensorManager sm;
List<Sensor> availableSensors;
boolean hasAccelerometer, hasOrientation, hasMagneticField;
org.witness.informacam.models.j3m.ILogPack currentAccelerometer, currentMagField;
private DecimalFormat df = new DecimalFormat();
private final static String LOG = Suckers.LOG;
// onSensorChanged cached values for performance, not all needed to be declared here.
private float[] mGravity = new float[3];
private float[] mGeomagnetic = new float[3];
private float alpha = 0.09f;// low pass filter factor
private boolean useLowPassFilter = false; // set to true if you have a GUI implementation of compass!
private int i = 0;
private final static int SENSOR_COMPUTE_LIMIT = 6;
@SuppressWarnings("unchecked")
public AccelerometerSucker(Context context) {
super(context);
setSucker(this);
df.setMaximumFractionDigits(1);
df.setPositivePrefix("+");
sm = (SensorManager)context.getApplicationContext().getSystemService(Context.SENSOR_SERVICE);
availableSensors = sm.getSensorList(Sensor.TYPE_ALL);
for(Sensor s : availableSensors) {
switch(s.getType()) {
case Sensor.TYPE_ACCELEROMETER:
hasAccelerometer = true;
sm.registerListener(this, s, SensorManager.SENSOR_DELAY_GAME);
break;
case Sensor.TYPE_MAGNETIC_FIELD:
sm.registerListener(this, s, SensorManager.SENSOR_DELAY_GAME);
hasOrientation = true;
break;
}
}
setTask(new TimerTask() {
@Override
public void run() {
try {
if(hasAccelerometer)
readAccelerometer();
if(hasOrientation)
readOrientation();
} catch(JSONException e){}
}
});
getTimer().schedule(getTask(), 0, Accelerometer.LOG_RATE);
}
private void readAccelerometer() throws JSONException, NullPointerException {
if(currentAccelerometer != null)
sendToBuffer(currentAccelerometer);
}
private void readOrientation() throws JSONException, NullPointerException {
if(currentMagField != null)
{
if(currentAccelerometer != null)
{
// float orientation = computeRealOrientation();
// currentMagField.put(Accelerometer.Keys.ORIENTATION, orientation+"");
}
sendToBuffer(currentMagField);
}
}
public ILogPack forceReturn() throws JSONException {
ILogPack fr = new ILogPack(Accelerometer.Keys.ACC, currentAccelerometer);
fr.put(Accelerometer.Keys.ORIENTATION, currentMagField);
return fr;
}
@SuppressWarnings("unused")
private String frm(float sensorValue) {
return df.format(sensorValue);
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// Log.v(TAG, "onAccuracyChanged() accuracy:" + accuracy);
}
/**
* taken from this xclnt project:
* https://github.com/matheszabi/PortaitLandscapeCompass/blob/master/src/com/example/compassfix/AccelerometerAndMagnetometerListener.java
*/
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
// apply a low pass filter: output = alpha*input + (1-alpha)*previous output;
if (useLowPassFilter) {
mGravity[0] = alpha * event.values[0] + (1f - alpha) * mGravity[0];
mGravity[1] = alpha * event.values[1] + (1f - alpha) * mGravity[1];
mGravity[2] = alpha * event.values[2] + (1f - alpha) * mGravity[2];
} else {
mGravity = event.values.clone();
}
try
{
ILogPack sVals = new ILogPack();
sVals.put(Accelerometer.Keys.X, mGravity[0]);
sVals.put(Accelerometer.Keys.Y, mGravity[1]);
sVals.put(Accelerometer.Keys.Z, mGravity[2]);
currentAccelerometer = sVals;
}
catch (JSONException jse)
{
Log.d(LOG,"json exc",jse);
}
}
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
// apply a low pass filter: output = alpha*input + (1-alpha)*previous output;
if (useLowPassFilter) {
mGeomagnetic[0] = alpha * event.values[0] + (1f - alpha) * mGeomagnetic[0];
mGeomagnetic[1] = alpha * event.values[1] + (1f - alpha) * mGeomagnetic[1];
mGeomagnetic[2] = alpha * event.values[2] + (1f - alpha) * mGeomagnetic[2];
} else {
mGeomagnetic = event.values.clone();
}
try
{
ILogPack sVals = new ILogPack();
sVals.put(Accelerometer.Keys.AZIMUTH, mGeomagnetic[0]);
sVals.put(Accelerometer.Keys.PITCH, mGeomagnetic[1]);
sVals.put(Accelerometer.Keys.ROLL, mGeomagnetic[2]);
currentMagField = sVals;
}
catch (JSONException jse)
{
Log.d(LOG,"json exc",jse);
}
}
i++; //increment idx - we don't want to calculate actual bearing every time
if (i == SENSOR_COMPUTE_LIMIT) {
i = 0;
if (mGravity != null && mGeomagnetic != null) {
float R[] = new float[9];
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(R, I, mGravity,
mGeomagnetic);
if (success) {
float newOrientation[] = new float[3];
SensorManager.getOrientation(R, newOrientation);
try
{
float azimuthInDegress = (float)(Math.toDegrees(newOrientation[0])+360)%360;
currentMagField.put(Accelerometer.Keys.BEARING_DEGREES, azimuthInDegress);
currentMagField.put(Accelerometer.Keys.AZIMUTH_CORRECTED, newOrientation[0]);
currentMagField.put(Accelerometer.Keys.PITCH_CORRECTED, newOrientation[1]);
currentMagField.put(Accelerometer.Keys.ROLL_CORRECTED, newOrientation[2]);
}
catch (JSONException jse)
{
Log.d(LOG,"json exc",jse);
}
}
}
// separate sensor reference and maybe on new thread too is time consuming:
}
}
public void stopUpdates() {
setIsRunning(false);
sm.unregisterListener(this);
Log.d(LOG, "shutting down AccelerometerSucker...");
}
}