Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • danc/MicroCART
  • snawerdt/MicroCART_17-18
  • bbartels/MicroCART_17-18
  • jonahu/MicroCART
4 results
Show changes
Showing
with 0 additions and 1235 deletions
src/vrpn/android_widgets/vrpn_library/res/drawable-hdpi/icon.png

4.05 KiB

src/vrpn/android_widgets/vrpn_library/res/drawable-ldpi/icon.png

1.68 KiB

src/vrpn/android_widgets/vrpn_library/res/drawable-mdpi/icon.png

2.51 KiB

<?xml version="1.0" encoding="utf-8"?>
<eu.ensam.ii.vrpn.views.DebugSensors
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:orientation="vertical"
android:id="@+id/DebugSensors"
>
<ToggleButton android:text="Save" android:id="@+id/BtnSave"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</ToggleButton>
<TableLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:stretchColumns ="*">
<TableRow android:id="@+id/TableRow01"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:text="Sensor" android:id="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="Rel." android:id="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="X" android:id="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="Y" android:id="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="Z" android:id="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="L" android:id="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
</TableRow>
<TableRow android:id="@+id/TableRow01"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:text="Accelerator" android:id="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="" android:id="@+id/AccAccuracy" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="X" android:id="@+id/AccX" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="Y" android:id="@+id/AccY" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="Z" android:id="@+id/AccZ" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="L" android:id="@+id/AccL" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
</TableRow>
<TableRow android:id="@+id/TableRow01"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:text="AcceleratorN" android:id="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="" android:id="@+id/xx" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="X" android:id="@+id/AccXn" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="Y" android:id="@+id/AccYn" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="Z" android:id="@+id/AccZn" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="L" android:id="@+id/AccLn" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
</TableRow>
<TableRow android:id="@+id/TableRow01"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:text="Magnetic" android:id="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="" android:id="@+id/MagAccuracy" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="X" android:id="@+id/MagX" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="Y" android:id="@+id/MagY" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="Z" android:id="@+id/MagZ" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="L" android:id="@+id/MagL" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
</TableRow>
<TableRow android:id="@+id/TableRow01"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:text="Magnetic" android:id="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="" android:id="@+id/xx" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="X" android:id="@+id/MagXn" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="Y" android:id="@+id/MagYn" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="Z" android:id="@+id/MagZn" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="L" android:id="@+id/MagLn" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
</TableRow>
<TableRow android:id="@+id/TableRow01"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:text="Gyroscope" android:id="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="" android:id="@+id/GyrAccuracy" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="X" android:id="@+id/GyrX" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="Y" android:id="@+id/GyrY" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="Z" android:id="@+id/GyrZ" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
</TableRow>
<TableRow android:id="@+id/TableRow01"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:text="Orientation" android:id="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="" android:id="@+id/xxx" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="X" android:id="@+id/OriX" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="Y" android:id="@+id/OriY" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="Z" android:id="@+id/OriZ" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
</TableRow>
<TableRow android:id="@+id/TableRow01"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:text="Or. remapped" android:id="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="" android:id="@+id/xxx" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="X" android:id="@+id/OriRX" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="Y" android:id="@+id/OriRY" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="Z" android:id="@+id/OriRZ" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
</TableRow>
<TableRow android:id="@+id/TableRow01"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:text="Rotation" android:id="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="" android:id="@+id/xxx" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="X" android:id="@+id/RotX" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="Y" android:id="@+id/RotY" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="Z" android:id="@+id/RotZ" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
</TableRow>
<TableRow android:id="@+id/TableRow01"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:text="inclination" android:id="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="X" android:id="@+id/Inclination" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
</TableRow>
</TableLayout>
</eu.ensam.ii.vrpn.views.DebugSensors>
<?xml version="1.0" encoding="utf-8"?>
<!--
Layout for the composite widget VrpnSeekBar , backed by the class VrpnSeekBar
The widget includes
- a title line
- a line with min, max and current values of the seekbar
- the seekbar itself
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/vrpn_seekbar"
android:orientation="vertical"
>
<TextView
android:id="@+id/txtSeekBarTitle"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Label">
</TextView>
<LinearLayout
android:id="@+id/lytSeekBarValues"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/txtSeekBarMinValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:gravity="bottom|left"
android:layout_weight="1"
android:text="min"
>
</TextView>
<TextView
android:id="@+id/txtSeekBarCurrentValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:textSize="20dip"
android:layout_weight="1"
android:text="Current">
</TextView>
<TextView
android:id="@+id/txtSeekBarMaxValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:gravity="bottom|right"
android:layout_weight="1"
android:text="max">
</TextView>
</LinearLayout>
<SeekBar
android:id="@+id/seekBarWidget"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
</SeekBar>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="VrpnSeekBar">
<attr name="hideTitle" format="boolean"/>
<attr name="hideValues" format="boolean"/>
<attr name="defaultValue" format="float"/>
<attr name="minValue" format="float"/>
<attr name="maxValue" format="float"/>
<attr name="title" format="string"/>
<attr name="vrpnAnalog" format="integer"/>
</declare-styleable>
<declare-styleable name="VrpnRadioButton">
<!--
This is the definition : declare the format.
The next ones will be declarations, without the forat
-->
<attr name="vrpnButton" format="integer"/>
</declare-styleable>
<declare-styleable name="VrpnPressButton">
<attr name="vrpnButton"/>
</declare-styleable>
<declare-styleable name="VrpnToggleButton">
<attr name="vrpnButton"/>
</declare-styleable>
<declare-styleable name="VrpnSurface">
<attr name="vrpnAnalogX" format="integer"/>
<attr name="vrpnAnalogY" format="integer"/>
<attr name="leftX" format="float"/>
<attr name="rightX" format="float"/>
<attr name="topY" format="float"/>
<attr name="bottomY" format="float"/>
</declare-styleable>
<declare-styleable name="VrpnSpinner">
<attr name="vrpnAnalog"/>
</declare-styleable>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World!</string>
<string name="app_name">vrpn_library</string>
<string name="DefaultIntentString">eu.ensam.ii.vrpn.STARTUI</string>
</resources>
package eu.ensam.ii.vrpn;
import org.json.JSONArray;
import org.json.JSONException;
import android.util.FloatMath;
/**
* A simple float quaternion
*
* @author Philippe
*
*/
class Quat {
Vec3f v = new Vec3f();
float w = 0.0f;
Quat() {
}
/**
* Computes a rotation quaternion that rotates <code>s</code> to <code>t</code>
*
* @param s
* @param t
*/
void setRotate(final Vec3f s, final Vec3f t) {
// from Real-Time Rendering, 3d ed p 79
final float e = s.dot(t);
final float k = FloatMath.sqrt(2.0f * (1.0f + e));
v = s.cross(t).mul(1.0f / k);
w = k / 2.0f;
}
/**
* Fill the first 4 elements of the JSON array with the values of this quaternion object
*
* Extraneous existing elements of the array are set to null
*
* @param jsonArray the JSON array to be filled
* @throws JSONException
*/
final void fill(JSONArray jsonArray) throws JSONException {
jsonArray.put(0, v.x);
jsonArray.put(1, v.y);
jsonArray.put(2, v.z);
jsonArray.put(3, w);
int i = 4;
while (i < jsonArray.length()) {
jsonArray.put(i++, null);
}
}
}
package eu.ensam.ii.vrpn;
import android.util.FloatMath;
import org.json.JSONArray;
import org.json.JSONException;
/**
* A basic 3-element float vector.
*
* Used for some computations with SensorEvent values
*
* @author Philippe
*
*/
class Vec3f {
public float x, y, z;
Vec3f() {
x = y = z = 0.0f;
}
Vec3f(float _x, float _y, float _z) {
set(_x, _y, _z);
}
void set(float _x, float _y, float _z) {
x = _x;
y = _y;
z = _z;
}
final float dot(final Vec3f v) {
return x*v.x + y*v.y + z*v.z;
}
final Vec3f cross(final Vec3f v) {
Vec3f w = new Vec3f(
y*v.z - z*v.y,
z*v.x - x*v.z,
x*v.y - y*v.x);
return w;
}
/**
* Computes a normalized vector
* @param u
* @return normalized vector value
*/
static Vec3f normalize(final Vec3f u) {
final float norm = u.norm();
Vec3f v = u;
v.x /= norm;
v.y /= norm;
v.z /= norm;
return v;
}
/**
* Normalizes this vector
*/
final void normalize() {
final float norm = norm();
x /= norm;
y /= norm;
z /= norm;
}
/**
* Computes the norm of this vector
*
* @return the float value of the norm of the object
*/
final float norm() {
return FloatMath.sqrt(x*x + y*y + z*z);
}
/**
* Fill the first 3 elements of the JSON array with the values of this Vec3f object
*
* Extraneous existing elements of the array are set to null
*
* @param jsonArray the JSON array to be filled
* @throws JSONException
*/
final void fill(JSONArray jsonArray) throws JSONException {
jsonArray.put(0, x);
jsonArray.put(1, y);
jsonArray.put(2, z);
int i = 3;
while (i < jsonArray.length()) {
jsonArray.put(i++, null);
}
}
Vec3f mul(float k) {
return new Vec3f(x*k, y*k, z*k);
}
}
package eu.ensam.ii.vrpn;
/**
* This class must be used as an {@link android.app.Application Application} for applications that use the Vrpn widgets.
* <p>
* An application that wants to use the Vrpn widgets must define an
* <em>application</em> tag with the name of this class in its manifest :
* </p>
* <ul>
* <li>edit your application <em>AndroidManifext.xml</em> and open the <em>Application</em> tab</li>
* <li>in the <em>Application toggle</em> section , check
* <em>Define an &lt;application&gt; tag ...</em></li>
* <li>in the <em>Application Attributes</em> section, type <em>eu.ensam.ii.vrpn.VrpnApplication</em> as the value of the
* <em>Name</em> attribute or use the <em>Browse...<em>button</li>
* </ul>
*
*/
public class VrpnApplication extends android.app.Application {
/*
* The VrpnApplication object holds and initializes an instance of VrpnClient.
*/
private VrpnClient _vrpnClient;
@Override
public void onCreate() {
_vrpnClient = VrpnClient.getInstance();
_vrpnClient.init(getApplicationContext());
}
}
package eu.ensam.ii.vrpn;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.net.Uri;
import android.util.Log;
/**
* Send updates button, analog and tracker updates to the JsonNet Vrpn server.
*
* <p>
* A application that uses the Vrpn widgets must initialize the unique instance
* of this class by calling {@link #setUri(Context, Uri) setUri} before the
* widgets are used.
* </p>
* <p>
* This class is not thread-safe. The methods <code>sendButton</code> and
* <code>sendAnalog</code> must be called from the main UI thread
* </p>
* <p>
* Currently the messages neither include a timestamp nor a sequence number
* </p>
*
* TODO Add timestamps and sequence numbers Add a method to allow sending TODO
* tracker updates from the widgets
*/
public class VrpnClient implements SensorEventListener {
private static VrpnClient _instance;
private static String LOG_TAG = "VrpnClient";
private SensorManager _sensorManager;
private boolean _isTiltTrackerEnabled = false;
private boolean _isRawGyroscopeEnabled = false;
private boolean _isRawAccelerometerEnabled = false;
private int _tiltTrackerSequenceNumber = 0;
private static final Vec3f Zpos = new Vec3f(0.0f, 0.0f, 1.0f);
float _values[] = new float[3];
/*
* Create the objects once to avoid repeated allocations in frequently
* called functions. As long as the VrpnClient methods that update the
* object are called from the same thread, no problem. This is currently the
* case, since the sensor updates are call on the main and the other updates
* are called from UI widgets callbacks, also on the main UI thread..
*/
private DatagramSocket _socket;
private DatagramPacket _packet;
JSONArray _jsonArray = new JSONArray();
private JSONObject _sensorJsonObject = new JSONObject();
private JSONObject _buttonJsonObject = new JSONObject();
private JSONObject _analogJsonObject = new JSONObject();
private Quat _quat = new Quat();
private Vec3f _v = new Vec3f();
/*
* These Ids must match those declared in vrpn_Tracker_Android.cpp
*/
private static final String MSG_KEY_TYPE = "type";
private static final String MSG_KEY_SEQUENCE_NUMBER = "sn";
private static final String MSG_KEY_TIMESTAMP = "ts";
private static final String MSG_KEY_TRACKER_ID = "id";
private static final String MSG_KEY_TRACKER_QUAT = "quat";
@SuppressWarnings("unused")
private static final String MSG_KEY_TRACKER_POS = "pos";
// Values for MSG_KEY_TRACKER_ID
private static final int MSG_SENSOR_ID_TILT = 0;
@SuppressWarnings("unused")
private static final int MSG_SENSOR_ID_RAW_ACCELEROMETER = 1;
@SuppressWarnings("unused")
private static final int MSG_SENSOR_ID_RAW_GYROSCOPE = 2;
private static final String MSG_KEY_BUTTON_ID = "button";
private static final String MSG_KEY_BUTTON_STATUS = "state";
private static final String MSG_KEY_ANALOG_CHANNEL = "num";
private static final String MSG_KEY_ANALOG_DATA = "data";
private final int MSG_TYPE_TRACKER = 1;
private final int MSG_TYPE_BUTTON = 2;
private final int MSG_TYPE_ANALOG = 3;
/**************************************************************************
*
* Create / Destroy
*
**************************************************************************/
/**
* Returns the unique VrpnClient instance
*/
public static VrpnClient getInstance() {
if (_instance == null) {
_instance = new VrpnClient();
}
return _instance;
}
/**
* Initializes the address and port of the VRPN server.
*
* <p>
* This method must be called before sending any update to the server.
* </p>
* Note that the widgets trigger updates when they they are displayed for
* the first time. So this method must be called before calling
* {@link android.app.Activity#setContentView(int) setContentView} in the
* main {@link android.app.Activity activity}
* {@link android.app.Activity#onCreate setContentView}
* <code>onCreate</code> method
*
* @param host
* a string that is a valid host name or IP address
* @param port
* the port number of the VRPN server
*/
public void setupVrpnServer(InetAddress hostAddress, int port) {
Log.d(LOG_TAG, "server:host = " + hostAddress + ":" + port);
/*
* Initialize the packet destination
*/
_packet.setAddress(hostAddress);
_packet.setPort(port);
}
/**
* Load the target server address and port from the shared preferences
*
* @param context
*/
void init(Context context) {
_sensorManager = (SensorManager) context
.getSystemService(Context.SENSOR_SERVICE);
enableOrDisableSensors();
}
/**
* Send an update to a Vrpn Button.
*
* This update will trigger a button callback on the application side
*
* @param buttonId
* the button number. Invalid button numbers are ignored on this
* side, but may trigger an error message on the Vrpn server
* @param buttonState
* the new status of the button
*/
public void sendButton(int buttonId, boolean buttonState) {
try {
_buttonJsonObject.put(MSG_KEY_TYPE, MSG_TYPE_BUTTON);
_buttonJsonObject.put(MSG_KEY_BUTTON_ID, buttonId);
_buttonJsonObject.put(MSG_KEY_BUTTON_STATUS, buttonState);
} catch (JSONException e1) {
e1.printStackTrace();
}
_sendObject(_buttonJsonObject);
}
/**
* Send an update to a Vrpn Analog channel.
*
* This update will trigger an analog callback on the application side
*
* @param channelId
* The channel number. Invalid channel numbers are ignored on
* this side but, they may trigger an error message on the Vrpn
* server
* @param channelValue
* the data that will be sent on the analog channel
*/
public void sendAnalog(int channelId, double channelValue) {
try {
_analogJsonObject.put(MSG_KEY_TYPE, MSG_TYPE_ANALOG);
_analogJsonObject.put(MSG_KEY_ANALOG_CHANNEL, channelId);
_analogJsonObject.put(MSG_KEY_ANALOG_DATA, channelValue);
} catch (JSONException e1) {
e1.printStackTrace();
}
_sendObject(_analogJsonObject);
}
/**
* Enables or disable the tilt tracker.
*
* The tilt tracker send a tracker update with a quaternion that rotates the
* "earth vertical up" vector to the +Z vector in device coordinates. See
* {@link android.hardware.SensorEvent SensorEvent} for a description of the
* device coordinate system. This quaternion can be used to retrieve the
* roll and pitch of the device.
*
* @param enable
* <code>true</code> enables the tilt tracker updates and
* <code>false</code> disable the tilt tracker updates
*/
public void enableTiltTracker(boolean enable) {
_isTiltTrackerEnabled = enable;
enableOrDisableSensors();
}
/**************************************************************************
*
* Sensorlistener implementation
*
**************************************************************************/
/**
* Called by the system when the sensor accuracy changes
*
* This method is empty and should not be called by widgets
*
*/
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
/**
* Called by the system when a sensor data changes.
*
* This method retrieves the Android sensor object. If an vrpn Tracker is
* active that involves this sensor object this method sends a Vrpn tracker
* update to the appropriate tracker. packages the sensor data into a JSON
* object then send the JSON object onto an UDP socket. The target socket
* endpoint configuration is configured by calling setupVrpnServer
*
*/
@Override
public void onSensorChanged(SensorEvent event) {
final int sensorType = event.sensor.getType();
// retrieve and update the adequate sequence number.
switch (sensorType) {
case Sensor.TYPE_ACCELEROMETER:
if (_isTiltTrackerEnabled) {
buildTiltTrackerObject(event.values, event.timestamp);
_sendObject(_sensorJsonObject);
}
if (_isRawAccelerometerEnabled) {
// To do
}
break;
case Sensor.TYPE_GYROSCOPE:
if (_isRawGyroscopeEnabled) {
// To do
}
break;
default:
return;
}
// Add other trackers here
// Send the data onto the network
}
/****************************************************************************
* Private methods
****************************************************************************/
private VrpnClient() {
try {
_socket = new DatagramSocket();
} catch (SocketException e) {
// Check this device IP network configuration
e.printStackTrace();
}
/*
* There is a single _packet instance to avoid numerous object creation
* in onSensorChanged()
*/
byte dummy[] = { 0 };
_packet = new DatagramPacket(dummy, dummy.length);
// Set the address with anything since _sendObject will be called before
// setUri has been called // why
try {
_packet.setAddress(InetAddress.getLocalHost());
} catch (UnknownHostException e) {
}
}
/**
* Send the string representation of a Json Object.
*
* @param[in] o the json object to send
*/
private void _sendObject(final JSONObject o) {
Log.d(LOG_TAG, o.toString());
// Send the data onto the network
_packet.setData(o.toString().getBytes());
try {
_socket.send(_packet);
} catch (SocketException e) {
// Local network not ready, no route to host, ...
;
} catch (IOException e) {
// TODO Auto-generated catch block : send a notification ?
e.printStackTrace();
}
}
/**
* Build a tilt tracker JSON object
*
* This method updates the _sensorJsonObject object
*
* @param x
* @param y
* @param z
* @param timestamp
*/
private void buildTiltTrackerObject(final float[] values, long timestamp) {
_v.set(values[0], values[1], values[2]);
_v.normalize();
/*
* When the device is at rest, the acceleration vector is -g (earth
* vertical up) in device coordinate system (Z out of the screen, that
* is Z up when the device lays on a table). Compute the rotation +Z -->
* -g
*/
_quat.setRotate(Zpos, _v);
// Build a Json message
try {
_sensorJsonObject.put(MSG_KEY_TYPE, MSG_TYPE_TRACKER);
_sensorJsonObject.put(MSG_KEY_SEQUENCE_NUMBER,
_tiltTrackerSequenceNumber++);
_sensorJsonObject.put(MSG_KEY_TIMESTAMP, timestamp);
_sensorJsonObject.put(MSG_KEY_TRACKER_ID, MSG_SENSOR_ID_TILT);
_quat.fill(_jsonArray);
_sensorJsonObject.put(MSG_KEY_TRACKER_QUAT, _jsonArray);
} catch (JSONException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
}
/**
* Update the device sensor activation status.
*/
private void enableOrDisableSensors() {
final int rate = SensorManager.SENSOR_DELAY_GAME;
final Sensor accelerometer = _sensorManager
.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
_sensorManager.unregisterListener(this);
if (_isTiltTrackerEnabled) {
_sensorManager.registerListener(this, accelerometer, rate);
} else {
/*
* We are closing down the tilt tracker, Send an update with
* horizontal position
*/
buildTiltTrackerObject(new float[] { 0.0f, 0.0f, 1.0f },
System.nanoTime());
_sendObject(_sensorJsonObject);
}
}
}
package eu.ensam.ii.vrpn;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
/**
* A {@link android.widget.Button Button} connected to a VRPN Button.
*
* <p>
* This button is linked to a Vrpn button. It sends sends a <code>true</code>
* update when its status changes to checked and a <code>false</code> update
* when its status changes to unchecked. The status of the VrpnPressButton
* changes when it is pushed, and also when it is released, unlike a
* {@link VrpnToggleButton}.
* </p>
*
* <p>
* In your <code>res/layout.xml</code>, include the widget in
* its parent layout :
* </p>
* <pre>
* &lt;eu.ensam.ii.VrpnPressButton
* android:layout_width="fill_parent"
* android:layout_height="wrap_content"
* app:vrpnButton="@id/MyButton"
* &#47&gt;
* </pre>
*
* <p>
* The root element of the layout must declare the following line just after the
* <code>xmlns:android ... </code>line :
*
* <pre>
* xmlns:app="http://schemas.android.com/apk/res/your.package.name.here"
* </pre>
*
* </p>
*
* <p>
* <strong>Custom XML attributes :</strong>
* </p>
* <ul>
* <li><code>app:vrpnButton</code> : the id of the Vrpn button that will receive
* updated from this widget. This value can be a literal or a resource Id that
* can be kept in a <a href="package-summary.html#vrpnids">separate Vrpn Id
* list</a></li>
* </ul>
*
*/
public class VrpnPressButton extends android.widget.Button implements
android.view.View.OnTouchListener {
private String TAG = "VrpnPressButton";
private int _vrpnButtonId = 0;
public VrpnPressButton(Context context) {
super(context);
init(null);
}
public VrpnPressButton(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public VrpnPressButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs);
}
/**
* Widget initialization
*
* @param attrs
* the AttributeSet that is required to access to the XML custom
* attributes
*/
private void init(AttributeSet attrs) {
// this.onTouch() will be called when this widget is touched
setOnTouchListener(this);
/*
* Get The Vrpn button id from the xml app:vrpnButton attribute The
* custom attribute is declared is in res/values/attrs.xml
*/
TypedArray a = getContext().obtainStyledAttributes(attrs,
R.styleable.VrpnRadioButton);
_vrpnButtonId = a.getInt(R.styleable.VrpnRadioButton_vrpnButton, 0);
a.recycle();
// Send a "false" since a PressButton is always initially released
Log.d(TAG, "ctor init : button " + _vrpnButtonId + " released ");
VrpnClient.getInstance().sendButton(_vrpnButtonId, false);
}
/**
* Called when a touch event is dispatched to this VrpnPressButton.
*
* This method sends a <code>true</code> update when the button is pressed
* and a <code>false</code> update when the button is released. when it is
* released. No event is send while the button is pressed.
*
* @see android.view.View.OnTouchListener#onTouch(android.view.View,
* android.view.MotionEvent)
*/
@Override
public boolean onTouch(View v, MotionEvent event) {
final int action = event.getAction();
/*
* Avoid unnecessary processing for irrelevant events Nothing is sent
* while the button is hold down (event=ACTION_MOVE)
*/
if (action != MotionEvent.ACTION_DOWN
&& action != MotionEvent.ACTION_UP
&& action != MotionEvent.ACTION_CANCEL) {
// Mark the event has handled, so it is not be handled by
// ToggleButton::onClick
return true;
}
/*
* Send true when the button is pressed and false when it is released.
*/
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.d(TAG, " button " + _vrpnButtonId + " pressed ");
VrpnClient.getInstance().sendButton(_vrpnButtonId, true);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
Log.d(TAG, " button " + _vrpnButtonId + " released ");
VrpnClient.getInstance().sendButton(_vrpnButtonId, false);
break;
default:
break;
}
// Mark the event has handled, so it is not be handled by
// ToggleButton::onClick
return false;
}
}
package eu.ensam.ii.vrpn;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.CompoundButton;
import android.widget.RadioGroup;
import android.widget.CompoundButton.OnCheckedChangeListener;
/**
* A {@link android.widget.RadioButton RadioButton} that updates a Vrpn Button channel.
*
* <p>
* The <code>VrpnRadioButton</code> is to be included inside a {@link RadioGroup}. The
* <code>VrpnRadioButton</code> will send a <code>true</code> when its state changes to
* checked and a <code> false</code> update when its state changes to unchecked.
* Checking another button of the <code>RadioGroup</code> will uncheck the <code>RadioButton</code>.</p>
* <p>in a <code>RadioGroup</code>, it is possible to include :
* <ul>
* <li>a <code>VrpnRadiobutton</code> and a <code>RadioButton</code>. Checking the <code>RadioButton</code> will uncheck the <code>VrpnRadioButton</code> that will send an update</li>
* <li>several <code>VrpnRadioButton</code> widgets. In this case the checked and the unchecked widgets will send updates</li>
* </ul>
* </p>
* <p>
* In your layout, declare the following :
* </p>
*
* <pre>
* &lt;RadioGroup
* android:id="@+id/RadioGroup01"
* &gt;
* &lt;eu.ensam.ii.vrpn.VrpnRadioButton
* android:text="This way"
* android:checked="true"
* app:vrpnButton="@id/VrpnButtonThisWay"
* /&gt;
* &lt;RadioButton
* android:text="other Way"
* android:checked="false"
* /&gt;
* &lt;/RadioGroup&gt;
* </pre>
*
* <p>
* The root element of the layout must declare the following line just after the
* <code>xmlns:android ... </code>line :
*
* <pre>
* xmlns:app="http://schemas.android.com/apk/res/your.package.name.here"
* </pre>
*
* </p>
*
* <p>
* <strong>Custom XML attributes :</strong>
* </p>
* <ul>
* <li><code>app:vrpnButton</code> : the id of the Vrpn button that will receive
* updated from this widget. This value can be a literal or a resource Id that
* can be kept in a <a href="package-summary.html#vrpnids">separate Vrpn Id
* list</a></li>
* </ul>
*/
public class VrpnRadioButton extends android.widget.RadioButton implements
OnCheckedChangeListener {
private static final String TAG = "VrpnRadioButton";
int _vrpnButtonId = 0;
public VrpnRadioButton(Context context) {
super(context);
init(null);
}
public VrpnRadioButton(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public VrpnRadioButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs);
}
private void init(AttributeSet attrs) {
setOnCheckedChangeListener(this);
// get The Vrpn button id from the xml app:vrpnButton attribute
TypedArray a = getContext().obtainStyledAttributes(attrs,
R.styleable.VrpnRadioButton);
_vrpnButtonId = a.getInt(R.styleable.VrpnRadioButton_vrpnButton, 0);
a.recycle();
// Trigger an initial Vrpn update
Log.d(TAG, "ctor init " + _vrpnButtonId + " : " + isChecked());
VrpnClient.getInstance().sendButton(_vrpnButtonId, isChecked());
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Log.d(TAG, "onCheckChanged " + _vrpnButtonId + " : " + isChecked);
// Send the update through the Vrpn service
VrpnClient.getInstance().sendButton(_vrpnButtonId, isChecked());
}
}
package eu.ensam.ii.vrpn;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
/**
* A {@link android.widget.SeekBar SeekBar} that updates a Vrpn Analog channel.
*
* <p>
* The seekbar include a line with the min, max and current
* values of the seekbar, and the seekbar itself.
*
* The seekbar progress is converted into a value in the
* <code>app:minValue</code> .. <code>app:maxValue</code>
* range. This value is then sent out to the Vrpn Analog channel whose
* id is specified in the <code>app:vrpnAnalog</code> attribute. The <code>VrpnSeekBar</code>
* moves in increments that are one hundredth of the value range.
* </p>
* <p>
* In your layout, declare the following (note the app:attributes)
* </p>
*
* <pre>
* &lt;eu.ensam.ii.vrpn.VrpnSeekBar
* android:layout_width="fill_parent"
* android:layout_height="wrap_content"
* app:minValue="-3"
* app:minValue="3"
* app:minValue="0"
* app:vrpnAnalog="@id/MyVrpnAnalogId"
* /&gt;
* </pre>
*
* <p>
* The root element of the layout must declare the following line just after the
* <code>xmlns:android ... </code>line :
*
* <pre>
* xmlns:app="http://schemas.android.com/apk/res/your.package.name.here"
* </pre>
*
* </p>
*
* <p>
* <strong>Custom XML attributes :</strong>
* </p>
* <ul>
* <li><code>app:vrpnAnalog</code> : the id of the Vrpn analog that will receive
* updates from this widget. This value can be a literal or a resource Id that
* can be kept in a <a href="package-summary.html#vrpnids">separate Vrpn Id
* list</a></li>
* <li><code>app:minValue</code> : the numeric value mapped onto the left
* position of the VrpnSeekbar</li>
* <li><code>app:maxValue</code> : the numeric value mapped onto the left
* position of the VrpnSeekbar</li>
* <li><code>app:defaultValue</code> : the initial numeric value of the VrpnSeekbar;</li>
* <li><code>app:hideValues</code> : <code>true</code> will cause the line with
* the minimum, maximum and current values to be hidden, <code>false</code> will cause
* the line to be displayed (default)</li>
* </ul>
*
* @author Philippe
*
*/
public class VrpnSeekBar extends android.widget.LinearLayout implements
OnSeekBarChangeListener {
// Partly adapted from
// http://www.codeproject.com/KB/android/seekbar_preference.aspx
private static final String TAG = "VrpnSeekBar";
private static final float DEFAULT_MIN_VALUE = 0.0f;
private static final float DEFAULT_MAX_VALUE = 100.0f;
private float _minValue;
private float _maxValue;
private float _currentValue;
private TextView _currentValueText;
private CharSequence _title;
private int _vrpnAnalogId;
private SeekBar _seekBar;
private boolean _hideValues;
public VrpnSeekBar(Context context) {
this(context, null);
}
public VrpnSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
// Get the custom attribute values
TypedArray a = getContext().obtainStyledAttributes(attrs,
R.styleable.VrpnSeekBar);
_minValue = a
.getFloat(R.styleable.VrpnSeekBar_minValue, DEFAULT_MIN_VALUE);
_maxValue = a
.getFloat(R.styleable.VrpnSeekBar_maxValue, DEFAULT_MAX_VALUE);
_currentValue = a.getFloat(R.styleable.VrpnSeekBar_defaultValue,
(_maxValue + _minValue) / 2.0f);
_title = a.getText(R.styleable.VrpnSeekBar_title);
_vrpnAnalogId = a.getInt(R.styleable.VrpnSeekBar_vrpnAnalog, 0);
boolean hideTitle = a.getBoolean(R.styleable.VrpnSeekBar_hideTitle, false);
_hideValues = a.getBoolean(R.styleable.VrpnSeekBar_hideValues, false);
a.recycle();
// Load the view layout
LayoutInflater li = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
li.inflate(R.layout.vrpn_seekbar, this, true);
// Load or hide the title
TextView titleView = (TextView) findViewById(R.id.txtSeekBarTitle);
if (hideTitle) {
titleView.setVisibility(GONE);
} else {
titleView.setText(_title);
}
// Load or hide the layout with the values
if (_hideValues) {
((LinearLayout) findViewById(R.id.lytSeekBarValues))
.setVisibility(GONE);
} else {
((TextView) findViewById(R.id.txtSeekBarMinValue)).setText(Float
.toString(_minValue));
((TextView) findViewById(R.id.txtSeekBarMaxValue)).setText(Float
.toString(_maxValue));
_currentValueText = (TextView) findViewById(R.id.txtSeekBarCurrentValue);
}
// Setup the SeekBar
_seekBar = (SeekBar) findViewById(R.id.seekBarWidget);
_seekBar.setOnSeekBarChangeListener(this);
// This triggers OnProgressChanged() and a VrpnUpdate
int currentValue = (int) (100.0 * (_currentValue - _minValue) / (_maxValue - _minValue));
_seekBar.setProgress(currentValue);
}
/**
* Called when the progress of the SeekBar changes
*
* Compute the value from the progress and send a VrpnUpdate to the analog
* channel that is associated to the widget with the custom attribute
* app:vrpnAnalog
*/
@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
// progress is in range 0..100 : map to min..max
_currentValue = (_maxValue - _minValue) / 100 * progress + _minValue;
if (!_hideValues) {
_currentValueText.setText(String.format("%.2f", _currentValue));
}
Log.d(TAG, "onProgressChanged " + _vrpnAnalogId + " progress/value: "
+ progress + " " + _currentValue);
// Send the vrpn update
// Note : The line below throws an exception in the Eclipse GUI preview
VrpnClient.getInstance().sendAnalog(_vrpnAnalogId, _currentValue);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
}