mirror of
https://bitbucket.org/librepilot/librepilot.git
synced 2025-03-01 18:29:16 +01:00
Merge branch 'android' into sim_android
This commit is contained in:
commit
a8fa1c6b0d
@ -29,11 +29,14 @@
|
|||||||
*/
|
*/
|
||||||
package org.openpilot.androidgcs;
|
package org.openpilot.androidgcs;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ListIterator;
|
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
import java.util.Observer;
|
import java.util.Observer;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
import org.openpilot.androidgcs.fragments.ObjectManagerFragment;
|
import org.openpilot.androidgcs.fragments.ObjectManagerFragment;
|
||||||
import org.openpilot.androidgcs.telemetry.OPTelemetryService;
|
import org.openpilot.androidgcs.telemetry.OPTelemetryService;
|
||||||
import org.openpilot.androidgcs.telemetry.OPTelemetryService.LocalBinder;
|
import org.openpilot.androidgcs.telemetry.OPTelemetryService.LocalBinder;
|
||||||
@ -76,105 +79,22 @@ public abstract class ObjectManagerActivity extends Activity {
|
|||||||
BroadcastReceiver connectedReceiver;
|
BroadcastReceiver connectedReceiver;
|
||||||
//! Indicate if this activity has already connected it's telemetry callbacks
|
//! Indicate if this activity has already connected it's telemetry callbacks
|
||||||
private boolean telemetryStatsConnected = false;
|
private boolean telemetryStatsConnected = false;
|
||||||
|
//! Maintain a list of all the UAVObject listeners for this activity
|
||||||
|
private HashMap<Observer, UAVObject> listeners;
|
||||||
/** Called when the activity is first created. */
|
/** Called when the activity is first created. */
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
connectedReceiver = new BroadcastReceiver() {
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
if (DEBUG)
|
|
||||||
Log.d(TAG, "Received intent");
|
|
||||||
TelemTask task;
|
|
||||||
if(intent.getAction().compareTo(OPTelemetryService.INTENT_ACTION_CONNECTED) == 0) {
|
|
||||||
if(binder == null)
|
|
||||||
return;
|
|
||||||
if((task = binder.getTelemTask(0)) == null)
|
|
||||||
return;
|
|
||||||
objMngr = task.getObjectManager();
|
|
||||||
mConnected = true;
|
|
||||||
onOPConnected();
|
|
||||||
Log.d(TAG, "Connected()");
|
|
||||||
} else if (intent.getAction().compareTo(OPTelemetryService.INTENT_ACTION_DISCONNECTED) == 0) {
|
|
||||||
objMngr = null;
|
|
||||||
mConnected = false;
|
|
||||||
onOPDisconnected();
|
|
||||||
Log.d(TAG, "Disonnected()");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
IntentFilter filter = new IntentFilter();
|
|
||||||
filter.addCategory(OPTelemetryService.INTENT_CATEGORY_GCS);
|
|
||||||
filter.addAction(OPTelemetryService.INTENT_ACTION_CONNECTED);
|
|
||||||
filter.addAction(OPTelemetryService.INTENT_ACTION_DISCONNECTED);
|
|
||||||
registerReceiver(connectedReceiver, filter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called whenever any objects subscribed to via registerObjects
|
* Called whenever any objects subscribed to via registerObjects
|
||||||
|
* whenever this Activity is not paused
|
||||||
*/
|
*/
|
||||||
protected void objectUpdated(UAVObject obj) {
|
protected void objectUpdated(UAVObject obj) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A message handler and a custom Observer to use it which calls
|
|
||||||
* objectUpdated with the right object type
|
|
||||||
*/
|
|
||||||
final Handler uavobjHandler = new Handler();
|
|
||||||
private class ActivityUpdatedObserver implements Observer {
|
|
||||||
UAVObject obj;
|
|
||||||
ActivityUpdatedObserver(UAVObject obj) { this.obj = obj; };
|
|
||||||
@Override
|
|
||||||
public void update(Observable observable, Object data) {
|
|
||||||
uavobjHandler.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() { objectUpdated(obj); }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
private class FragmentUpdatedObserver implements Observer {
|
|
||||||
UAVObject obj;
|
|
||||||
ObjectManagerFragment frag;
|
|
||||||
FragmentUpdatedObserver(UAVObject obj, ObjectManagerFragment frag) {
|
|
||||||
this.obj = obj;
|
|
||||||
this.frag = frag;
|
|
||||||
};
|
|
||||||
@Override
|
|
||||||
public void update(Observable observable, Object data) {
|
|
||||||
uavobjHandler.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() { frag.objectUpdated(obj); }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register an activity to receive updates from this object
|
|
||||||
*
|
|
||||||
* the objectUpdated() method will be called in the original UI thread
|
|
||||||
*/
|
|
||||||
protected void registerObjectUpdates(UAVObject object) {
|
|
||||||
object.addUpdatedObserver(new ActivityUpdatedObserver(object));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void registerObjectUpdates(UAVObject object,
|
|
||||||
ObjectManagerFragment frag) {
|
|
||||||
object.addUpdatedObserver(new FragmentUpdatedObserver(object, frag));
|
|
||||||
}
|
|
||||||
protected void registerObjectUpdates(List<List<UAVObject>> objects) {
|
|
||||||
ListIterator<List<UAVObject>> li = objects.listIterator();
|
|
||||||
while(li.hasNext()) {
|
|
||||||
ListIterator<UAVObject> li2 = li.next().listIterator();
|
|
||||||
while(li2.hasNext())
|
|
||||||
registerObjectUpdates(li2.next());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateStats() {
|
private void updateStats() {
|
||||||
UAVObject stats = objMngr.getObject("GCSTelemetryStats");
|
UAVObject stats = objMngr.getObject("GCSTelemetryStats");
|
||||||
TextView rxRate = (TextView) findViewById(R.id.telemetry_stats_rx_rate);
|
TextView rxRate = (TextView) findViewById(R.id.telemetry_stats_rx_rate);
|
||||||
@ -208,14 +128,21 @@ public abstract class ObjectManagerActivity extends Activity {
|
|||||||
if ( telemetryStatsConnected )
|
if ( telemetryStatsConnected )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Create a map for all the object updates register for this activity. If anyone
|
||||||
|
// tries to register an object update before this a null exception will occur
|
||||||
|
listeners = new HashMap<Observer,UAVObject>();
|
||||||
|
|
||||||
// We are not using the objectUpdated mechanism in place so that all the children
|
// We are not using the objectUpdated mechanism in place so that all the children
|
||||||
// don't have to sort through the messages.
|
// don't have to sort through the messages.
|
||||||
UAVObject stats = objMngr.getObject("GCSTelemetryStats");
|
|
||||||
if (stats == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
stats.addUpdatedObserver(telemetryObserver);
|
if (!telemetryStatsConnected) {
|
||||||
telemetryStatsConnected = true;
|
UAVObject stats = objMngr.getObject("GCSTelemetryStats");
|
||||||
|
if (stats == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
stats.addUpdatedObserver(telemetryObserver);
|
||||||
|
telemetryStatsConnected = true;
|
||||||
|
}
|
||||||
updateStats();
|
updateStats();
|
||||||
|
|
||||||
if (DEBUG) Log.d(TAG, "Notifying listeners about connection. There are " + connectionListeners.countObservers());
|
if (DEBUG) Log.d(TAG, "Notifying listeners about connection. There are " + connectionListeners.countObservers());
|
||||||
@ -236,46 +163,103 @@ public abstract class ObjectManagerActivity extends Activity {
|
|||||||
|
|
||||||
// Providing a null update triggers a disconnect on fragments
|
// Providing a null update triggers a disconnect on fragments
|
||||||
connectionListeners.disconnected();
|
connectionListeners.disconnected();
|
||||||
|
|
||||||
|
if (objMngr == null) {
|
||||||
|
Log.d(TAG, "onOPDisconnected(): Object manager already went away");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (telemetryStatsConnected) {
|
||||||
|
UAVObject stats = objMngr.getObject("GCSTelemetryStats");
|
||||||
|
if (stats != null) {
|
||||||
|
stats.removeUpdatedObserver(telemetryObserver);
|
||||||
|
}
|
||||||
|
telemetryStatsConnected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disconnect from any UAVO updates
|
||||||
|
if (DEBUG) Log.d(TAG, "onOpDisconnected(): Pausing the listeners and deleting the list");
|
||||||
|
pauseObjectUpdates();
|
||||||
|
listeners = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
|
||||||
|
if (mConnected && !telemetryStatsConnected) {
|
||||||
|
UAVObject stats = objMngr.getObject("GCSTelemetryStats");
|
||||||
|
if (stats == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
stats.addUpdatedObserver(telemetryObserver);
|
||||||
|
telemetryStatsConnected = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
resumeObjectUpdates();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
protected void onPause() {
|
||||||
if (!mBound || binder == null) {
|
super.onPause();
|
||||||
Log.e(TAG, "Unable to connect to service");
|
|
||||||
return super.onOptionsItemSelected(item);
|
if (telemetryStatsConnected) {
|
||||||
}
|
UAVObject stats = objMngr.getObject("GCSTelemetryStats");
|
||||||
switch(item.getItemId()) {
|
Assert.assertNotNull(stats); // Should not be null if we connected
|
||||||
case R.id.menu_connect:
|
|
||||||
binder.openConnection();
|
stats.removeUpdatedObserver(telemetryObserver);
|
||||||
return true;
|
telemetryStatsConnected = false;
|
||||||
case R.id.menu_disconnect:
|
|
||||||
binder.stopConnection();
|
|
||||||
return true;
|
|
||||||
case R.id.menu_settings:
|
|
||||||
startActivity(new Intent(this, Preferences.class));
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return super.onOptionsItemSelected(item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
pauseObjectUpdates();
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
|
||||||
MenuInflater inflater = getMenuInflater();
|
|
||||||
inflater.inflate(R.menu.status_menu, menu);
|
|
||||||
inflater.inflate(R.menu.options_menu, menu);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
|
if (DEBUG) Log.d(TAG, "onStart()");
|
||||||
|
|
||||||
|
// Register a receiver to get connected/disconnected signals from the telemetry
|
||||||
|
// service
|
||||||
|
connectedReceiver = new BroadcastReceiver() {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
if (DEBUG)
|
||||||
|
Log.d(TAG, "Received intent");
|
||||||
|
TelemTask task;
|
||||||
|
if(intent.getAction().compareTo(OPTelemetryService.INTENT_ACTION_CONNECTED) == 0) {
|
||||||
|
if(binder == null)
|
||||||
|
return;
|
||||||
|
if((task = binder.getTelemTask(0)) == null)
|
||||||
|
return;
|
||||||
|
objMngr = task.getObjectManager();
|
||||||
|
mConnected = true;
|
||||||
|
onOPConnected();
|
||||||
|
Log.d(TAG, "Connected()");
|
||||||
|
} else if (intent.getAction().compareTo(OPTelemetryService.INTENT_ACTION_DISCONNECTED) == 0) {
|
||||||
|
onOPDisconnected();
|
||||||
|
objMngr = null;
|
||||||
|
mConnected = false;
|
||||||
|
Log.d(TAG, "Disonnected()");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set up the filters
|
||||||
|
IntentFilter filter = new IntentFilter();
|
||||||
|
filter.addCategory(OPTelemetryService.INTENT_CATEGORY_GCS);
|
||||||
|
filter.addAction(OPTelemetryService.INTENT_ACTION_CONNECTED);
|
||||||
|
filter.addAction(OPTelemetryService.INTENT_ACTION_DISCONNECTED);
|
||||||
|
registerReceiver(connectedReceiver, filter);
|
||||||
|
|
||||||
|
// Bind to the telemetry service (which will start it)
|
||||||
Intent intent = new Intent(getApplicationContext(),
|
Intent intent = new Intent(getApplicationContext(),
|
||||||
org.openpilot.androidgcs.telemetry.OPTelemetryService.class);
|
org.openpilot.androidgcs.telemetry.OPTelemetryService.class);
|
||||||
if (DEBUG)
|
if (DEBUG)
|
||||||
Log.d(TAG, "Attempting to bind: " + intent);
|
Log.d(TAG, "Attempting to bind: " + intent);
|
||||||
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
|
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -284,14 +268,137 @@ public abstract class ObjectManagerActivity extends Activity {
|
|||||||
@Override
|
@Override
|
||||||
public void onStop() {
|
public void onStop() {
|
||||||
super.onStop();
|
super.onStop();
|
||||||
|
if (DEBUG) Log.d(TAG, "onStop()");
|
||||||
unbindService(mConnection);
|
unbindService(mConnection);
|
||||||
//unregisterReceiver(connectedReceiver);
|
unregisterReceiver(connectedReceiver);
|
||||||
|
connectedReceiver = null;
|
||||||
|
|
||||||
|
// Disconnect from any UAVO updates
|
||||||
|
if (DEBUG) Log.d(TAG, "onStop(): Pausing the listeners and deleting the list");
|
||||||
|
pauseObjectUpdates();
|
||||||
|
listeners = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onBind() {
|
/*********** This provides the object update messaging service ************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A message handler and a custom Observer to use it which calls
|
||||||
|
* objectUpdated with the right object type
|
||||||
|
*/
|
||||||
|
final Handler uavobjHandler = new Handler();
|
||||||
|
private class ActivityUpdatedObserver implements Observer {
|
||||||
|
UAVObject obj;
|
||||||
|
ActivityUpdatedObserver(UAVObject obj) { this.obj = obj; };
|
||||||
|
@Override
|
||||||
|
public void update(Observable observable, Object data) {
|
||||||
|
uavobjHandler.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() { objectUpdated(obj); }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private class FragmentUpdatedObserver implements Observer {
|
||||||
|
UAVObject obj;
|
||||||
|
ObjectManagerFragment frag;
|
||||||
|
FragmentUpdatedObserver(UAVObject obj, ObjectManagerFragment frag) {
|
||||||
|
this.obj = obj;
|
||||||
|
this.frag = frag;
|
||||||
|
};
|
||||||
|
@Override
|
||||||
|
public void update(Observable observable, Object data) {
|
||||||
|
uavobjHandler.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() { frag.objectUpdated(obj); }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregister all the objects connected to this activity
|
||||||
|
*/
|
||||||
|
private boolean paused = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When an activity is paused, disconnect from all
|
||||||
|
* updates to ensure we don't draw to an invalid view
|
||||||
|
*/
|
||||||
|
protected void pauseObjectUpdates()
|
||||||
|
{
|
||||||
|
// When listeners is null then a pause occurred after
|
||||||
|
// disconnecting from the service
|
||||||
|
if (listeners == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Set<Observer> s = listeners.keySet();
|
||||||
|
Iterator<Observer> i = s.iterator();
|
||||||
|
while (i.hasNext()) {
|
||||||
|
Observer o = i.next();
|
||||||
|
UAVObject obj = listeners.get(o);
|
||||||
|
obj.removeUpdatedObserver(o);
|
||||||
|
}
|
||||||
|
paused = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When an activity is resumed, reconnect all now the view
|
||||||
|
* is valid again
|
||||||
|
*/
|
||||||
|
protected void resumeObjectUpdates()
|
||||||
|
{
|
||||||
|
// When listeners is null this is the resume at the beginning
|
||||||
|
// before connecting to the telemetry service
|
||||||
|
if(listeners == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Set<Observer> s = listeners.keySet();
|
||||||
|
Iterator<Observer> i = s.iterator();
|
||||||
|
while (i.hasNext()) {
|
||||||
|
Observer o = i.next();
|
||||||
|
UAVObject obj = listeners.get(o);
|
||||||
|
obj.addUpdatedObserver(o);
|
||||||
|
}
|
||||||
|
paused = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register to listen to a single object from a fragment
|
||||||
|
* @param object The object to listen to updates from
|
||||||
|
* @param frag The fragment who should be notified
|
||||||
|
* the objectUpdated() method will be called in the original UI thread
|
||||||
|
*/
|
||||||
|
public void registerObjectUpdates(UAVObject object,
|
||||||
|
ObjectManagerFragment frag) {
|
||||||
|
Observer o = new FragmentUpdatedObserver(object, frag);
|
||||||
|
listeners.put(o, object);
|
||||||
|
if (!paused)
|
||||||
|
object.addUpdatedObserver(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register an activity to receive updates from this object
|
||||||
|
* @param object The object the activity should listen to updates from
|
||||||
|
* the objectUpdated() method will be called in the original UI thread
|
||||||
|
*/
|
||||||
|
protected void registerObjectUpdates(UAVObject object) {
|
||||||
|
Observer o = new ActivityUpdatedObserver(object);
|
||||||
|
listeners.put(o, object);
|
||||||
|
if (!paused)
|
||||||
|
object.addUpdatedObserver(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to register array of objects
|
||||||
|
*/
|
||||||
|
protected void registerObjectUpdates(List<List<UAVObject>> objects) {
|
||||||
|
for (int i = 0; i < objects.size(); i++) {
|
||||||
|
List<UAVObject> inner = objects.get(i);
|
||||||
|
for (int j = 0; j < inner.size(); j++)
|
||||||
|
registerObjectUpdates(inner.get(j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********** Deals with fragments listening for connections ***************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callbacks so ObjectManagerFragments get the onOPConnected and onOPDisconnected signals
|
* Callbacks so ObjectManagerFragments get the onOPConnected and onOPDisconnected signals
|
||||||
@ -328,7 +435,6 @@ public abstract class ObjectManagerActivity extends Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
public void addOnConnectionListenerFragment(ObjectManagerFragment frag) {
|
public void addOnConnectionListenerFragment(ObjectManagerFragment frag) {
|
||||||
connectionListeners.addObserver(new OnConnectionListener(frag));
|
connectionListeners.addObserver(new OnConnectionListener(frag));
|
||||||
if (DEBUG) Log.d(TAG, "Connecting " + frag + " there are now " + connectionListeners.countObservers());
|
if (DEBUG) Log.d(TAG, "Connecting " + frag + " there are now " + connectionListeners.countObservers());
|
||||||
@ -337,6 +443,8 @@ public abstract class ObjectManagerActivity extends Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*********** Deals with (dis)connection to telemetry service ***************/
|
||||||
|
|
||||||
/** Defines callbacks for service binding, passed to bindService() */
|
/** Defines callbacks for service binding, passed to bindService() */
|
||||||
private final ServiceConnection mConnection = new ServiceConnection() {
|
private final ServiceConnection mConnection = new ServiceConnection() {
|
||||||
@Override
|
@Override
|
||||||
@ -359,13 +467,45 @@ public abstract class ObjectManagerActivity extends Activity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onServiceDisconnected(ComponentName name) {
|
public void onServiceDisconnected(ComponentName name) {
|
||||||
|
onOPDisconnected();
|
||||||
mBound = false;
|
mBound = false;
|
||||||
binder = null;
|
binder = null;
|
||||||
mConnected = false;
|
mConnected = false;
|
||||||
objMngr = null;
|
objMngr = null;
|
||||||
objMngr = null;
|
objMngr = null;
|
||||||
mConnected = false;
|
mConnected = false;
|
||||||
onOPDisconnected();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/************* Deals with menus *****************/
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
if (!mBound || binder == null) {
|
||||||
|
Log.e(TAG, "Unable to connect to service");
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
switch(item.getItemId()) {
|
||||||
|
case R.id.menu_connect:
|
||||||
|
binder.openConnection();
|
||||||
|
return true;
|
||||||
|
case R.id.menu_disconnect:
|
||||||
|
binder.stopConnection();
|
||||||
|
return true;
|
||||||
|
case R.id.menu_settings:
|
||||||
|
startActivity(new Intent(this, Preferences.class));
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
|
MenuInflater inflater = getMenuInflater();
|
||||||
|
inflater.inflate(R.menu.status_menu, menu);
|
||||||
|
inflater.inflate(R.menu.options_menu, menu);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -23,14 +23,18 @@
|
|||||||
|
|
||||||
package org.openpilot.androidgcs;
|
package org.openpilot.androidgcs;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.ListIterator;
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
import java.util.Observer;
|
import java.util.Observer;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.openpilot.androidgcs.fragments.ObjectManagerFragment;
|
||||||
import org.openpilot.androidgcs.telemetry.OPTelemetryService;
|
import org.openpilot.androidgcs.telemetry.OPTelemetryService;
|
||||||
import org.openpilot.androidgcs.telemetry.OPTelemetryService.LocalBinder;
|
import org.openpilot.androidgcs.telemetry.OPTelemetryService.LocalBinder;
|
||||||
import org.openpilot.androidgcs.telemetry.OPTelemetryService.TelemTask;
|
import org.openpilot.androidgcs.telemetry.OPTelemetryService.TelemTask;
|
||||||
import org.openpilot.uavtalk.UAVDataObject;
|
|
||||||
import org.openpilot.uavtalk.UAVObject;
|
import org.openpilot.uavtalk.UAVObject;
|
||||||
import org.openpilot.uavtalk.UAVObjectManager;
|
import org.openpilot.uavtalk.UAVObjectManager;
|
||||||
|
|
||||||
@ -46,6 +50,7 @@ import android.graphics.Canvas;
|
|||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.Point;
|
import android.graphics.Point;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
@ -73,6 +78,7 @@ public class UAVLocation extends MapActivity
|
|||||||
UAVObjectManager objMngr;
|
UAVObjectManager objMngr;
|
||||||
boolean mBound = false;
|
boolean mBound = false;
|
||||||
boolean mConnected = false;
|
boolean mConnected = false;
|
||||||
|
BroadcastReceiver connectedReceiver;
|
||||||
org.openpilot.androidgcs.telemetry.OPTelemetryService.LocalBinder binder;
|
org.openpilot.androidgcs.telemetry.OPTelemetryService.LocalBinder binder;
|
||||||
|
|
||||||
GeoPoint homeLocation;
|
GeoPoint homeLocation;
|
||||||
@ -103,36 +109,6 @@ public class UAVLocation extends MapActivity
|
|||||||
|
|
||||||
mapView.postInvalidate();
|
mapView.postInvalidate();
|
||||||
|
|
||||||
// ObjectManager related stuff (can't inherit standard class)
|
|
||||||
BroadcastReceiver connectedReceiver = new BroadcastReceiver() {
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
Log.d(TAG, "Received intent");
|
|
||||||
TelemTask task;
|
|
||||||
if(intent.getAction().compareTo(OPTelemetryService.INTENT_ACTION_CONNECTED) == 0) {
|
|
||||||
|
|
||||||
if(binder == null)
|
|
||||||
return;
|
|
||||||
if((task = binder.getTelemTask(0)) == null)
|
|
||||||
return;
|
|
||||||
objMngr = task.getObjectManager();
|
|
||||||
mConnected = true;
|
|
||||||
onOPConnected();
|
|
||||||
Log.d(TAG, "Connected()");
|
|
||||||
} else if (intent.getAction().compareTo(OPTelemetryService.INTENT_ACTION_DISCONNECTED) == 0) {
|
|
||||||
objMngr = null;
|
|
||||||
mConnected = false;
|
|
||||||
onOPDisconnected();
|
|
||||||
Log.d(TAG, "Disonnected()");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
IntentFilter filter = new IntentFilter();
|
|
||||||
filter.addCategory(OPTelemetryService.INTENT_CATEGORY_GCS);
|
|
||||||
filter.addAction(OPTelemetryService.INTENT_ACTION_CONNECTED);
|
|
||||||
filter.addAction(OPTelemetryService.INTENT_ACTION_DISCONNECTED);
|
|
||||||
registerReceiver(connectedReceiver, filter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//@Override
|
//@Override
|
||||||
@ -192,40 +168,10 @@ public class UAVLocation extends MapActivity
|
|||||||
|
|
||||||
void onOPConnected() {
|
void onOPConnected() {
|
||||||
UAVObject obj = objMngr.getObject("HomeLocation");
|
UAVObject obj = objMngr.getObject("HomeLocation");
|
||||||
if(obj != null)
|
registerObjectUpdates(obj);
|
||||||
obj.addUpdatedObserver(new Observer() {
|
|
||||||
@Override
|
|
||||||
public void update(Observable observable, Object data) {
|
|
||||||
UAVDataObject obj = (UAVDataObject) data;
|
|
||||||
Double lat = obj.getField("Latitude").getDouble() / 10;
|
|
||||||
Double lon = obj.getField("Longitude").getDouble() / 10;
|
|
||||||
homeLocation = new GeoPoint(lat.intValue(), lon.intValue());
|
|
||||||
runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
mapController.setCenter(homeLocation);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
System.out.println("HomeLocation: " + homeLocation.toString());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
obj.updateRequested();
|
|
||||||
|
|
||||||
obj = objMngr.getObject("PositionActual");
|
obj = objMngr.getObject("PositionActual");
|
||||||
if(obj != null)
|
registerObjectUpdates(obj);
|
||||||
obj.addUpdatedObserver(new Observer() {
|
|
||||||
@Override
|
|
||||||
public void update(Observable observable, Object data) {
|
|
||||||
uavLocation = getUavLocation();
|
|
||||||
runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
mapView.invalidate();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private GeoPoint getUavLocation() {
|
private GeoPoint getUavLocation() {
|
||||||
@ -260,7 +206,7 @@ public class UAVLocation extends MapActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
void onOPDisconnected() {
|
void onOPDisconnected() {
|
||||||
|
unregisterObjectUpdates();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -291,10 +237,56 @@ public class UAVLocation extends MapActivity
|
|||||||
@Override
|
@Override
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
|
// ObjectManager related stuff (can't inherit standard class)
|
||||||
|
connectedReceiver = new BroadcastReceiver() {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
Log.d(TAG, "Received intent");
|
||||||
|
TelemTask task;
|
||||||
|
if(intent.getAction().compareTo(OPTelemetryService.INTENT_ACTION_CONNECTED) == 0) {
|
||||||
|
|
||||||
|
if(binder == null)
|
||||||
|
return;
|
||||||
|
if((task = binder.getTelemTask(0)) == null)
|
||||||
|
return;
|
||||||
|
objMngr = task.getObjectManager();
|
||||||
|
mConnected = true;
|
||||||
|
onOPConnected();
|
||||||
|
Log.d(TAG, "Connected()");
|
||||||
|
} else if (intent.getAction().compareTo(OPTelemetryService.INTENT_ACTION_DISCONNECTED) == 0) {
|
||||||
|
objMngr = null;
|
||||||
|
mConnected = false;
|
||||||
|
onOPDisconnected();
|
||||||
|
Log.d(TAG, "Disonnected()");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
IntentFilter filter = new IntentFilter();
|
||||||
|
filter.addCategory(OPTelemetryService.INTENT_CATEGORY_GCS);
|
||||||
|
filter.addAction(OPTelemetryService.INTENT_ACTION_CONNECTED);
|
||||||
|
filter.addAction(OPTelemetryService.INTENT_ACTION_DISCONNECTED);
|
||||||
|
registerReceiver(connectedReceiver, filter);
|
||||||
|
|
||||||
Intent intent = new Intent(this, OPTelemetryService.class);
|
Intent intent = new Intent(this, OPTelemetryService.class);
|
||||||
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
|
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When stopping disconnect form the service and the broadcast receiver
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onStop() {
|
||||||
|
super.onStop();
|
||||||
|
if (DEBUG) Log.d(TAG, "onStop()");
|
||||||
|
unbindService(mConnection);
|
||||||
|
unregisterReceiver(connectedReceiver);
|
||||||
|
connectedReceiver = null;
|
||||||
|
|
||||||
|
// TODO: The register and unregister probably should move to onPause / onResume
|
||||||
|
unregisterObjectUpdates();
|
||||||
|
}
|
||||||
|
|
||||||
public void onBind() {
|
public void onBind() {
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -330,4 +322,96 @@ public class UAVLocation extends MapActivity
|
|||||||
onOPDisconnected();
|
onOPDisconnected();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/******* STRAIGHT COPY PASTE FROM ObjectManagerActivity *************/
|
||||||
|
/**
|
||||||
|
* Called whenever any objects subscribed to via registerObjects
|
||||||
|
*/
|
||||||
|
protected void objectUpdated(UAVObject obj) {
|
||||||
|
if (obj == null)
|
||||||
|
return;
|
||||||
|
if (obj.getName().compareTo("HomeLocation") == 0) {
|
||||||
|
Double lat = obj.getField("Latitude").getDouble() / 10;
|
||||||
|
Double lon = obj.getField("Longitude").getDouble() / 10;
|
||||||
|
homeLocation = new GeoPoint(lat.intValue(), lon.intValue());
|
||||||
|
mapController.setCenter(homeLocation);
|
||||||
|
} else if (obj.getName().compareTo("PositionActual") == 0) {
|
||||||
|
uavLocation = getUavLocation();
|
||||||
|
mapView.invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A message handler and a custom Observer to use it which calls
|
||||||
|
* objectUpdated with the right object type
|
||||||
|
*/
|
||||||
|
final Handler uavobjHandler = new Handler();
|
||||||
|
private class ActivityUpdatedObserver implements Observer {
|
||||||
|
UAVObject obj;
|
||||||
|
ActivityUpdatedObserver(UAVObject obj) { this.obj = obj; };
|
||||||
|
@Override
|
||||||
|
public void update(Observable observable, Object data) {
|
||||||
|
uavobjHandler.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() { objectUpdated(obj); }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private class FragmentUpdatedObserver implements Observer {
|
||||||
|
UAVObject obj;
|
||||||
|
ObjectManagerFragment frag;
|
||||||
|
FragmentUpdatedObserver(UAVObject obj, ObjectManagerFragment frag) {
|
||||||
|
this.obj = obj;
|
||||||
|
this.frag = frag;
|
||||||
|
};
|
||||||
|
@Override
|
||||||
|
public void update(Observable observable, Object data) {
|
||||||
|
uavobjHandler.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() { frag.objectUpdated(obj); }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register an activity to receive updates from this object
|
||||||
|
*
|
||||||
|
* the objectUpdated() method will be called in the original UI thread
|
||||||
|
*/
|
||||||
|
HashMap<Observer, UAVObject> listeners = new HashMap<Observer,UAVObject>();
|
||||||
|
protected void registerObjectUpdates(UAVObject object) {
|
||||||
|
Observer o = new ActivityUpdatedObserver(object);
|
||||||
|
object.addUpdatedObserver(o);
|
||||||
|
listeners.put(o, object);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Unregister all the objects connected to this activity
|
||||||
|
*/
|
||||||
|
protected void unregisterObjectUpdates()
|
||||||
|
{
|
||||||
|
Set<Observer> s = listeners.keySet();
|
||||||
|
Iterator<Observer> i = s.iterator();
|
||||||
|
while (i.hasNext()) {
|
||||||
|
Observer o = i.next();
|
||||||
|
UAVObject obj = listeners.get(o);
|
||||||
|
obj.removeUpdatedObserver(o);
|
||||||
|
}
|
||||||
|
listeners.clear();
|
||||||
|
}
|
||||||
|
public void registerObjectUpdates(UAVObject object,
|
||||||
|
ObjectManagerFragment frag) {
|
||||||
|
Observer o = new FragmentUpdatedObserver(object, frag);
|
||||||
|
object.addUpdatedObserver(o);
|
||||||
|
listeners.put(o, object);
|
||||||
|
}
|
||||||
|
protected void registerObjectUpdates(List<List<UAVObject>> objects) {
|
||||||
|
ListIterator<List<UAVObject>> li = objects.listIterator();
|
||||||
|
while(li.hasNext()) {
|
||||||
|
ListIterator<UAVObject> li2 = li.next().listIterator();
|
||||||
|
while(li2.hasNext())
|
||||||
|
registerObjectUpdates(li2.next());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ import org.openpilot.uavtalk.UAVObject;
|
|||||||
import org.openpilot.uavtalk.UAVObjectField;
|
import org.openpilot.uavtalk.UAVObjectField;
|
||||||
import org.openpilot.uavtalk.UAVObjectManager;
|
import org.openpilot.uavtalk.UAVObjectManager;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
@ -72,7 +73,16 @@ public class SystemAlarmsFragment extends ObjectManagerFragment {
|
|||||||
if (DEBUG)
|
if (DEBUG)
|
||||||
Log.d(TAG, "Updated");
|
Log.d(TAG, "Updated");
|
||||||
if (obj.getName().compareTo("SystemAlarms") == 0) {
|
if (obj.getName().compareTo("SystemAlarms") == 0) {
|
||||||
|
Activity activity = getActivity();
|
||||||
|
if (activity == null) {
|
||||||
|
// TODO: Need to unregister all the callbacks
|
||||||
|
return;
|
||||||
|
}
|
||||||
TextView alarms = (TextView) getActivity().findViewById(R.id.system_alarms_fragment_field);
|
TextView alarms = (TextView) getActivity().findViewById(R.id.system_alarms_fragment_field);
|
||||||
|
if (alarms == null) {
|
||||||
|
// TODO: Need to figure out how to unregister all the callbacks
|
||||||
|
return;
|
||||||
|
}
|
||||||
UAVObjectField a = obj.getField("Alarm");
|
UAVObjectField a = obj.getField("Alarm");
|
||||||
List<String> names = a.getElementNames();
|
List<String> names = a.getElementNames();
|
||||||
String contents = new String();
|
String contents = new String();
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
package org.openpilot.androidgcs.telemetry;
|
package org.openpilot.androidgcs.telemetry;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
import java.util.Observer;
|
import java.util.Observer;
|
||||||
|
|
||||||
@ -83,75 +84,85 @@ public class OPTelemetryService extends Service {
|
|||||||
|
|
||||||
private final IBinder mBinder = new LocalBinder();
|
private final IBinder mBinder = new LocalBinder();
|
||||||
|
|
||||||
private final class ServiceHandler extends Handler {
|
static class ServiceHandler extends Handler {
|
||||||
public ServiceHandler(Looper looper) {
|
private final WeakReference<OPTelemetryService> mService;
|
||||||
super(looper);
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void handleMessage(Message msg) {
|
|
||||||
if (DEBUG)
|
|
||||||
Log.d(TAG, "handleMessage: " + msg);
|
|
||||||
switch(msg.arg1) {
|
|
||||||
case MSG_START:
|
|
||||||
stopSelf(msg.arg2);
|
|
||||||
break;
|
|
||||||
case MSG_CONNECT:
|
|
||||||
terminate = false;
|
|
||||||
int connection_type;
|
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(OPTelemetryService.this);
|
|
||||||
try {
|
|
||||||
connection_type = Integer.decode(prefs.getString("connection_type", ""));
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
connection_type = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(connection_type) {
|
ServiceHandler(OPTelemetryService service, Looper looper) {
|
||||||
case 0: // No connection
|
super(looper);
|
||||||
return;
|
mService = new WeakReference<OPTelemetryService>(service);
|
||||||
case 1:
|
}
|
||||||
Toast.makeText(getApplicationContext(), "Attempting fake connection", Toast.LENGTH_SHORT).show();
|
|
||||||
activeTelem = new FakeTelemetryThread();
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
Toast.makeText(getApplicationContext(), "Attempting BT connection", Toast.LENGTH_SHORT).show();
|
|
||||||
activeTelem = new BTTelemetryThread();
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
Toast.makeText(getApplicationContext(), "Attempting TCP connection", Toast.LENGTH_SHORT).show();
|
|
||||||
activeTelem = new TcpTelemetryThread();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Error("Unsupported");
|
|
||||||
}
|
|
||||||
activeTelem.start();
|
|
||||||
break;
|
|
||||||
case MSG_DISCONNECT:
|
|
||||||
Toast.makeText(getApplicationContext(), "Disconnect requested", Toast.LENGTH_SHORT).show();
|
|
||||||
terminate = true;
|
|
||||||
activeTelem.interrupt();
|
|
||||||
try {
|
|
||||||
activeTelem.join();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
activeTelem = null;
|
|
||||||
|
|
||||||
Intent intent = new Intent();
|
@Override
|
||||||
intent.setAction(INTENT_ACTION_DISCONNECTED);
|
public void handleMessage(Message msg)
|
||||||
sendBroadcast(intent,null);
|
{
|
||||||
|
OPTelemetryService service = mService.get();
|
||||||
|
if (service != null) {
|
||||||
|
service.handleMessage(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
stopSelf();
|
void handleMessage(Message msg) {
|
||||||
|
switch(msg.arg1) {
|
||||||
break;
|
case MSG_START:
|
||||||
case MSG_TOAST:
|
stopSelf(msg.arg2);
|
||||||
Toast.makeText(OPTelemetryService.this, (String) msg.obj, Toast.LENGTH_SHORT).show();
|
break;
|
||||||
break;
|
case MSG_CONNECT:
|
||||||
default:
|
terminate = false;
|
||||||
System.out.println(msg.toString());
|
int connection_type;
|
||||||
throw new Error("Invalid message");
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(OPTelemetryService.this);
|
||||||
|
try {
|
||||||
|
connection_type = Integer.decode(prefs.getString("connection_type", ""));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
connection_type = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch(connection_type) {
|
||||||
|
case 0: // No connection
|
||||||
|
return;
|
||||||
|
case 1:
|
||||||
|
Toast.makeText(getApplicationContext(), "Attempting fake connection", Toast.LENGTH_SHORT).show();
|
||||||
|
activeTelem = new FakeTelemetryThread();
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
Toast.makeText(getApplicationContext(), "Attempting BT connection", Toast.LENGTH_SHORT).show();
|
||||||
|
activeTelem = new BTTelemetryThread();
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
Toast.makeText(getApplicationContext(), "Attempting TCP connection", Toast.LENGTH_SHORT).show();
|
||||||
|
activeTelem = new TcpTelemetryThread();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error("Unsupported");
|
||||||
|
}
|
||||||
|
activeTelem.start();
|
||||||
|
break;
|
||||||
|
case MSG_DISCONNECT:
|
||||||
|
Toast.makeText(getApplicationContext(), "Disconnect requested", Toast.LENGTH_SHORT).show();
|
||||||
|
terminate = true;
|
||||||
|
activeTelem.interrupt();
|
||||||
|
try {
|
||||||
|
activeTelem.join();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
activeTelem = null;
|
||||||
|
|
||||||
|
Intent intent = new Intent();
|
||||||
|
intent.setAction(INTENT_ACTION_DISCONNECTED);
|
||||||
|
sendBroadcast(intent,null);
|
||||||
|
|
||||||
|
stopSelf();
|
||||||
|
|
||||||
|
break;
|
||||||
|
case MSG_TOAST:
|
||||||
|
Toast.makeText(this, (String) msg.obj, Toast.LENGTH_SHORT).show();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
System.out.println(msg.toString());
|
||||||
|
throw new Error("Invalid message");
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the service starts. It creates a thread to handle messages (e.g. connect and disconnect)
|
* Called when the service starts. It creates a thread to handle messages (e.g. connect and disconnect)
|
||||||
@ -160,15 +171,12 @@ public class OPTelemetryService extends Service {
|
|||||||
public void startup() {
|
public void startup() {
|
||||||
Toast.makeText(getApplicationContext(), "Telemetry service starting", Toast.LENGTH_SHORT).show();
|
Toast.makeText(getApplicationContext(), "Telemetry service starting", Toast.LENGTH_SHORT).show();
|
||||||
|
|
||||||
if (DEBUG)
|
|
||||||
Log.d(TAG, "startup()");
|
|
||||||
|
|
||||||
thread = new HandlerThread("TelemetryServiceHandler", Process.THREAD_PRIORITY_BACKGROUND);
|
thread = new HandlerThread("TelemetryServiceHandler", Process.THREAD_PRIORITY_BACKGROUND);
|
||||||
thread.start();
|
thread.start();
|
||||||
|
|
||||||
// Get the HandlerThread's Looper and use it for our Handler
|
// Get the HandlerThread's Looper and use it for our Handler
|
||||||
mServiceLooper = thread.getLooper();
|
mServiceLooper = thread.getLooper();
|
||||||
mServiceHandler = new ServiceHandler(mServiceLooper);
|
mServiceHandler = new ServiceHandler(this, mServiceLooper);
|
||||||
|
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(OPTelemetryService.this);
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(OPTelemetryService.this);
|
||||||
if(prefs.getBoolean("autoconnect", false)) {
|
if(prefs.getBoolean("autoconnect", false)) {
|
||||||
@ -190,16 +198,13 @@ public class OPTelemetryService extends Service {
|
|||||||
@Override
|
@Override
|
||||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
// Currently only using as bound service
|
// Currently only using as bound service
|
||||||
if (DEBUG)
|
|
||||||
Log.d(TAG, "onStartCommand()");
|
|
||||||
// If we get killed, after returning from here, restart
|
// If we get killed, after returning from here, restart
|
||||||
return START_STICKY;
|
return START_STICKY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBinder onBind(Intent intent) {
|
public IBinder onBind(Intent intent) {
|
||||||
if (DEBUG)
|
|
||||||
Log.d(TAG, "onBind()");
|
|
||||||
return mBinder;
|
return mBinder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -360,7 +365,7 @@ public class OPTelemetryService extends Service {
|
|||||||
mon.addObserver(new Observer() {
|
mon.addObserver(new Observer() {
|
||||||
@Override
|
@Override
|
||||||
public void update(Observable arg0, Object arg1) {
|
public void update(Observable arg0, Object arg1) {
|
||||||
System.out.println("Mon updated. Connected: " + mon.getConnected() + " objects updated: " + mon.getObjectsUpdated());
|
if (DEBUG) Log.d(TAG, "Mon updated. Connected: " + mon.getConnected() + " objects updated: " + mon.getObjectsUpdated());
|
||||||
if(mon.getConnected() /*&& mon.getObjectsUpdated()*/) {
|
if(mon.getConnected() /*&& mon.getObjectsUpdated()*/) {
|
||||||
Intent intent = new Intent();
|
Intent intent = new Intent();
|
||||||
intent.setAction(INTENT_ACTION_CONNECTED);
|
intent.setAction(INTENT_ACTION_CONNECTED);
|
||||||
@ -439,8 +444,8 @@ public class OPTelemetryService extends Service {
|
|||||||
mon.addObserver(new Observer() {
|
mon.addObserver(new Observer() {
|
||||||
@Override
|
@Override
|
||||||
public void update(Observable arg0, Object arg1) {
|
public void update(Observable arg0, Object arg1) {
|
||||||
System.out.println("Mon updated. Connected: " + mon.getConnected() + " objects updated: " + mon.getObjectsUpdated());
|
if (DEBUG) Log.d(TAG, "Mon updated. Connected: " + mon.getConnected() + " objects updated: " + mon.getObjectsUpdated());
|
||||||
if(mon.getConnected() /*&& mon.getObjectsUpdated()*/) {
|
if(mon.getConnected()) {
|
||||||
Intent intent = new Intent();
|
Intent intent = new Intent();
|
||||||
intent.setAction(INTENT_ACTION_CONNECTED);
|
intent.setAction(INTENT_ACTION_CONNECTED);
|
||||||
sendBroadcast(intent,null);
|
sendBroadcast(intent,null);
|
||||||
|
@ -87,9 +87,9 @@ public class Telemetry {
|
|||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
public Telemetry(UAVTalk utalk, UAVObjectManager objMngr)
|
public Telemetry(UAVTalk utalkIn, UAVObjectManager objMngr)
|
||||||
{
|
{
|
||||||
this.utalk = utalk;
|
this.utalk = utalkIn;
|
||||||
this.objMngr = objMngr;
|
this.objMngr = objMngr;
|
||||||
|
|
||||||
// Process all objects in the list
|
// Process all objects in the list
|
||||||
@ -113,16 +113,28 @@ public class Telemetry {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Listen to transaction completions
|
// Listen to transaction completions
|
||||||
utalk.addObserver(new Observer() {
|
this.utalk.setOnTransactionCompletedListener(
|
||||||
|
this.utalk.new OnTransactionCompletedListener() {
|
||||||
@Override
|
@Override
|
||||||
public void update(Observable observable, Object data) {
|
void TransactionSucceeded(UAVObject data) {
|
||||||
try {
|
try {
|
||||||
transactionCompleted((UAVObject) data);
|
transactionCompleted(data);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// Disconnect when stream fails
|
// Disconnect when stream fails
|
||||||
observable.deleteObserver(this);
|
utalk.setOnTransactionCompletedListener(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
|
void TransactionFailed(UAVObject data) {
|
||||||
|
try {
|
||||||
|
Log.d(TAG, "TransactionFailed(" + data.getName() + ")");
|
||||||
|
transactionCompleted(data);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// Disconnect when stream fails
|
||||||
|
utalk.setOnTransactionCompletedListener(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get GCS stats object
|
// Get GCS stats object
|
||||||
@ -475,7 +487,6 @@ public class Telemetry {
|
|||||||
++txErrors;
|
++txErrors;
|
||||||
obj.transactionCompleted(false);
|
obj.transactionCompleted(false);
|
||||||
Log.w(TAG,"Telemetry: priority event queue is full, event lost " + obj.getName());
|
Log.w(TAG,"Telemetry: priority event queue is full, event lost " + obj.getName());
|
||||||
new Exception().printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -36,20 +36,20 @@ import java.util.TimerTask;
|
|||||||
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
public class TelemetryMonitor extends Observable{
|
public class TelemetryMonitor extends Observable {
|
||||||
|
|
||||||
private static final String TAG = "TelemetryMonitor";
|
private static final String TAG = "TelemetryMonitor";
|
||||||
public static int LOGLEVEL = 0;
|
public static int LOGLEVEL = 0;
|
||||||
public static boolean WARN = LOGLEVEL > 1;
|
public static boolean WARN = LOGLEVEL > 1;
|
||||||
public static boolean DEBUG = LOGLEVEL > 0;
|
public static boolean DEBUG = LOGLEVEL > 0;
|
||||||
|
|
||||||
static final int STATS_UPDATE_PERIOD_MS = 4000;
|
static final int STATS_UPDATE_PERIOD_MS = 4000;
|
||||||
static final int STATS_CONNECT_PERIOD_MS = 1000;
|
static final int STATS_CONNECT_PERIOD_MS = 1000;
|
||||||
static final int CONNECTION_TIMEOUT_MS = 8000;
|
static final int CONNECTION_TIMEOUT_MS = 8000;
|
||||||
|
|
||||||
private final UAVObjectManager objMngr;
|
private final UAVObjectManager objMngr;
|
||||||
private final Telemetry tel;
|
private final Telemetry tel;
|
||||||
// private UAVObject objPending;
|
// private UAVObject objPending;
|
||||||
private UAVObject gcsStatsObj;
|
private UAVObject gcsStatsObj;
|
||||||
private UAVObject flightStatsObj;
|
private UAVObject flightStatsObj;
|
||||||
private Timer periodicTask;
|
private Timer periodicTask;
|
||||||
@ -60,324 +60,333 @@ public class TelemetryMonitor extends Observable{
|
|||||||
private boolean connected = false;
|
private boolean connected = false;
|
||||||
private boolean objects_updated = false;
|
private boolean objects_updated = false;
|
||||||
|
|
||||||
public boolean getConnected() { return connected; };
|
public boolean getConnected() {
|
||||||
public boolean getObjectsUpdated() { return objects_updated; };
|
return connected;
|
||||||
|
};
|
||||||
|
|
||||||
public TelemetryMonitor(UAVObjectManager objMngr, Telemetry tel)
|
public boolean getObjectsUpdated() {
|
||||||
{
|
return objects_updated;
|
||||||
this.objMngr = objMngr;
|
};
|
||||||
this.tel = tel;
|
|
||||||
// this.objPending = null;
|
|
||||||
queue = new ArrayList<UAVObject>();
|
|
||||||
|
|
||||||
// Get stats objects
|
public TelemetryMonitor(UAVObjectManager objMngr, Telemetry tel) {
|
||||||
gcsStatsObj = objMngr.getObject("GCSTelemetryStats");
|
this.objMngr = objMngr;
|
||||||
flightStatsObj = objMngr.getObject("FlightTelemetryStats");
|
this.tel = tel;
|
||||||
|
// this.objPending = null;
|
||||||
|
queue = new ArrayList<UAVObject>();
|
||||||
|
|
||||||
flightStatsObj.addUpdatedObserver(new Observer() {
|
// Get stats objects
|
||||||
|
gcsStatsObj = objMngr.getObject("GCSTelemetryStats");
|
||||||
|
flightStatsObj = objMngr.getObject("FlightTelemetryStats");
|
||||||
|
|
||||||
|
flightStatsObj.addUpdatedObserver(new Observer() {
|
||||||
@Override
|
@Override
|
||||||
public void update(Observable observable, Object data) {
|
public void update(Observable observable, Object data) {
|
||||||
try {
|
try {
|
||||||
flightStatsUpdated((UAVObject) data);
|
flightStatsUpdated((UAVObject) data);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// The UAVTalk stream was broken, disconnect this signal
|
// The UAVTalk stream was broken, disconnect this signal
|
||||||
// TODO: Should this actually be disconnected. Do we create a new TelemetryMonitor for this
|
// TODO: Should this actually be disconnected. Do we create
|
||||||
|
// a new TelemetryMonitor for this
|
||||||
// or fix the stream?
|
// or fix the stream?
|
||||||
flightStatsObj.removeUpdatedObserver(this);
|
flightStatsObj.removeUpdatedObserver(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Start update timer
|
// Start update timer
|
||||||
setPeriod(STATS_CONNECT_PERIOD_MS);
|
setPeriod(STATS_CONNECT_PERIOD_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initiate object retrieval, initialize queue with objects to be retrieved.
|
* Initiate object retrieval, initialize queue with objects to be retrieved.
|
||||||
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public synchronized void startRetrievingObjects() throws IOException
|
public synchronized void startRetrievingObjects() throws IOException {
|
||||||
{
|
if (DEBUG)
|
||||||
if (DEBUG) Log.d(TAG, "Start retrieving objects");
|
Log.d(TAG, "Start retrieving objects");
|
||||||
|
|
||||||
// Clear object queue
|
// Clear object queue
|
||||||
queue.clear();
|
queue.clear();
|
||||||
// Get all objects, add metaobjects, settings and data objects with OnChange update mode to the queue
|
// Get all objects, add metaobjects, settings and data objects with
|
||||||
List< List<UAVObject> > objs = objMngr.getObjects();
|
// OnChange update mode to the queue
|
||||||
|
List<List<UAVObject>> objs = objMngr.getObjects();
|
||||||
|
|
||||||
ListIterator<List<UAVObject>> objListIterator = objs.listIterator();
|
ListIterator<List<UAVObject>> objListIterator = objs.listIterator();
|
||||||
while( objListIterator.hasNext() )
|
while (objListIterator.hasNext()) {
|
||||||
{
|
List<UAVObject> instList = objListIterator.next();
|
||||||
List <UAVObject> instList = objListIterator.next();
|
UAVObject obj = instList.get(0);
|
||||||
UAVObject obj = instList.get(0);
|
UAVObject.Metadata mdata = obj.getMetadata();
|
||||||
UAVObject.Metadata mdata = obj.getMetadata();
|
if (obj.isMetadata()) {
|
||||||
if ( obj.isMetadata() )
|
queue.add(obj);
|
||||||
{
|
} else /* Data object */
|
||||||
queue.add(obj);
|
{
|
||||||
}
|
UAVDataObject dobj = (UAVDataObject) obj;
|
||||||
else /* Data object */
|
if (dobj.isSettings()) {
|
||||||
{
|
queue.add(obj);
|
||||||
UAVDataObject dobj = (UAVDataObject) obj;
|
} else {
|
||||||
if ( dobj.isSettings() )
|
if (mdata.GetFlightTelemetryUpdateMode() == UAVObject.UpdateMode.UPDATEMODE_ONCHANGE) {
|
||||||
{
|
queue.add(obj);
|
||||||
queue.add(obj);
|
}
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
{
|
}
|
||||||
if ( mdata.GetFlightTelemetryUpdateMode() == UAVObject.UpdateMode.UPDATEMODE_ONCHANGE )
|
// Start retrieving
|
||||||
{
|
Log.d(TAG,
|
||||||
queue.add(obj);
|
"Starting to retrieve meta and settings objects from the autopilot ("
|
||||||
}
|
+ queue.size() + " objects)");
|
||||||
}
|
retrieveNextObject();
|
||||||
}
|
|
||||||
}
|
|
||||||
// Start retrieving
|
|
||||||
System.out.println(TAG + "Starting to retrieve meta and settings objects from the autopilot (" + queue.size() + " objects)");
|
|
||||||
retrieveNextObject();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancel the object retrieval
|
* Cancel the object retrieval
|
||||||
*/
|
*/
|
||||||
public void stopRetrievingObjects()
|
public void stopRetrievingObjects() {
|
||||||
{
|
|
||||||
Log.d(TAG, "Stop retrieving objects");
|
Log.d(TAG, "Stop retrieving objects");
|
||||||
queue.clear();
|
queue.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the next object in the queue
|
* Retrieve the next object in the queue
|
||||||
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public synchronized void retrieveNextObject() throws IOException
|
public synchronized void retrieveNextObject() throws IOException {
|
||||||
{
|
// If queue is empty return
|
||||||
// If queue is empty return
|
if (queue.isEmpty()) {
|
||||||
if ( queue.isEmpty() )
|
if (DEBUG)
|
||||||
{
|
Log.d(TAG, "All objects retrieved: Connected Successfully");
|
||||||
if (DEBUG) Log.d(TAG, "All objects retrieved: Connected Successfully");
|
objects_updated = true;
|
||||||
objects_updated = true;
|
setChanged();
|
||||||
setChanged();
|
notifyObservers();
|
||||||
notifyObservers();
|
return;
|
||||||
return;
|
}
|
||||||
}
|
// Get next object from the queue
|
||||||
// Get next object from the queue
|
UAVObject obj = queue.remove(0);
|
||||||
UAVObject obj = queue.remove(0);
|
|
||||||
|
|
||||||
if(obj == null) {
|
if (obj == null) {
|
||||||
throw new Error("Got null object forom transaction queue");
|
throw new Error("Got null object forom transaction queue");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DEBUG) Log.d(TAG, "Retrieving object: " + obj.getName()) ;
|
if (DEBUG)
|
||||||
// Connect to object
|
Log.d(TAG, "Retrieving object: " + obj.getName());
|
||||||
|
|
||||||
// TODO: Does this need to stay here permanently? This appears to be used for setup mainly
|
// TODO: Does this need to stay here permanently? This appears to be
|
||||||
obj.addTransactionCompleted(new Observer() {
|
// used for setup mainly
|
||||||
|
obj.addTransactionCompleted(new Observer() {
|
||||||
@Override
|
@Override
|
||||||
public void update(Observable observable, Object data) {
|
public void update(Observable observable, Object data) {
|
||||||
UAVObject.TransactionResult result = (UAVObject.TransactionResult) data;
|
UAVObject.TransactionResult result = (UAVObject.TransactionResult) data;
|
||||||
if (DEBUG) Log.d(TAG,"Got transaction completed event from " + result.obj.getName() + " status: " + result.success);
|
if (DEBUG)
|
||||||
|
Log.d(TAG, "Got transaction completed event from "
|
||||||
|
+ result.obj.getName() + " status: "
|
||||||
|
+ result.success);
|
||||||
try {
|
try {
|
||||||
transactionCompleted(result.obj, result.success);
|
transactionCompleted(result.obj, result.success);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// When the telemetry stream is broken disconnect these updates
|
// When the telemetry stream is broken disconnect these
|
||||||
|
// updates
|
||||||
observable.deleteObserver(this);
|
observable.deleteObserver(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Request update
|
// Request update
|
||||||
tel.updateRequested(obj);
|
tel.updateRequested(obj);
|
||||||
// objPending = obj;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by the retrieved object when a transaction is completed.
|
* Called by the retrieved object when a transaction is completed.
|
||||||
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public synchronized void transactionCompleted(UAVObject obj, boolean success) throws IOException
|
public synchronized void transactionCompleted(UAVObject obj, boolean success)
|
||||||
{
|
throws IOException {
|
||||||
//QMutexLocker locker(mutex);
|
if (DEBUG)
|
||||||
// Disconnect from sending object
|
Log.d(TAG, "transactionCompleted. Status: " + success);
|
||||||
if (DEBUG) Log.d(TAG,"transactionCompleted. Status: " + success);
|
|
||||||
// TODO: Need to be able to disconnect signals
|
|
||||||
//obj->disconnect(this);
|
|
||||||
// objPending = null;
|
|
||||||
|
|
||||||
if(!success) {
|
if (!success) {
|
||||||
//Log.e(TAG, "Transaction failed: " + obj.getName() + " sending again.");
|
// Right now success = false means received a NAK so don't
|
||||||
return;
|
// re-attempt
|
||||||
}
|
Log.e(TAG, "Transaction failed.");
|
||||||
|
}
|
||||||
|
|
||||||
// Process next object if telemetry is still available
|
// Process next object if telemetry is still available
|
||||||
if ( ((String) gcsStatsObj.getField("Status").getValue()).compareTo("Connected") == 0 )
|
if (((String) gcsStatsObj.getField("Status").getValue())
|
||||||
{
|
.compareTo("Connected") == 0) {
|
||||||
retrieveNextObject();
|
retrieveNextObject();
|
||||||
}
|
} else {
|
||||||
else
|
stopRetrievingObjects();
|
||||||
{
|
}
|
||||||
stopRetrievingObjects();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called each time the flight stats object is updated by the autopilot
|
* Called each time the flight stats object is updated by the autopilot
|
||||||
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public synchronized void flightStatsUpdated(UAVObject obj) throws IOException
|
public synchronized void flightStatsUpdated(UAVObject obj)
|
||||||
{
|
throws IOException {
|
||||||
// Force update if not yet connected
|
// Force update if not yet connected
|
||||||
gcsStatsObj = objMngr.getObject("GCSTelemetryStats");
|
gcsStatsObj = objMngr.getObject("GCSTelemetryStats");
|
||||||
flightStatsObj = objMngr.getObject("FlightTelemetryStats");
|
flightStatsObj = objMngr.getObject("FlightTelemetryStats");
|
||||||
if (DEBUG) Log.d(TAG,"GCS Status: " + gcsStatsObj.getField("Status").getValue());
|
if (DEBUG)
|
||||||
if (DEBUG) Log.d(TAG,"Flight Status: " + flightStatsObj.getField("Status").getValue());
|
Log.d(TAG, "GCS Status: "
|
||||||
if ( ((String) gcsStatsObj.getField("Status").getValue()).compareTo("Connected") != 0 ||
|
+ gcsStatsObj.getField("Status").getValue());
|
||||||
((String) flightStatsObj.getField("Status").getValue()).compareTo("Connected") == 0 )
|
if (DEBUG)
|
||||||
{
|
Log.d(TAG, "Flight Status: "
|
||||||
processStatsUpdates();
|
+ flightStatsObj.getField("Status").getValue());
|
||||||
}
|
if (((String) gcsStatsObj.getField("Status").getValue())
|
||||||
|
.compareTo("Connected") != 0
|
||||||
|
|| ((String) flightStatsObj.getField("Status").getValue())
|
||||||
|
.compareTo("Connected") == 0) {
|
||||||
|
processStatsUpdates();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private long lastStatsTime;
|
private long lastStatsTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called periodically to update the statistics and connection status.
|
* Called periodically to update the statistics and connection status.
|
||||||
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public synchronized void processStatsUpdates() throws IOException
|
public synchronized void processStatsUpdates() throws IOException {
|
||||||
{
|
// Get telemetry stats
|
||||||
// Get telemetry stats
|
if (DEBUG)
|
||||||
if (DEBUG) Log.d(TAG, "processStatsUpdates()");
|
Log.d(TAG, "processStatsUpdates()");
|
||||||
Telemetry.TelemetryStats telStats = tel.getStats();
|
Telemetry.TelemetryStats telStats = tel.getStats();
|
||||||
|
|
||||||
if (DEBUG) Log.d(TAG, "processStatsUpdates() - stats reset");
|
if (DEBUG)
|
||||||
|
Log.d(TAG, "processStatsUpdates() - stats reset");
|
||||||
|
|
||||||
// Need to compute time because this update is not regular enough
|
// Need to compute time because this update is not regular enough
|
||||||
float dT = (System.currentTimeMillis() - lastStatsTime) / 1000.0f;
|
float dT = (System.currentTimeMillis() - lastStatsTime) / 1000.0f;
|
||||||
lastStatsTime = System.currentTimeMillis();
|
lastStatsTime = System.currentTimeMillis();
|
||||||
|
|
||||||
// Update stats object
|
// Update stats object
|
||||||
gcsStatsObj.getField("RxDataRate").setDouble( telStats.rxBytes / dT );
|
gcsStatsObj.getField("RxDataRate").setDouble(telStats.rxBytes / dT);
|
||||||
gcsStatsObj.getField("TxDataRate").setDouble( telStats.txBytes / dT );
|
gcsStatsObj.getField("TxDataRate").setDouble(telStats.txBytes / dT);
|
||||||
UAVObjectField field = gcsStatsObj.getField("RxFailures");
|
UAVObjectField field = gcsStatsObj.getField("RxFailures");
|
||||||
field.setDouble(field.getDouble() + telStats.rxErrors);
|
field.setDouble(field.getDouble() + telStats.rxErrors);
|
||||||
field = gcsStatsObj.getField("TxFailures");
|
field = gcsStatsObj.getField("TxFailures");
|
||||||
field.setDouble(field.getDouble() + telStats.txErrors);
|
field.setDouble(field.getDouble() + telStats.txErrors);
|
||||||
field = gcsStatsObj.getField("TxRetries");
|
field = gcsStatsObj.getField("TxRetries");
|
||||||
field.setDouble(field.getDouble() + telStats.txRetries);
|
field.setDouble(field.getDouble() + telStats.txRetries);
|
||||||
|
|
||||||
tel.resetStats();
|
tel.resetStats();
|
||||||
|
|
||||||
if (DEBUG) Log.d(TAG, "processStatsUpdates() - stats updated");
|
if (DEBUG)
|
||||||
|
Log.d(TAG, "processStatsUpdates() - stats updated");
|
||||||
|
|
||||||
// Check for a connection timeout
|
// Check for a connection timeout
|
||||||
boolean connectionTimeout;
|
boolean connectionTimeout;
|
||||||
if ( telStats.rxObjects > 0 )
|
if (telStats.rxObjects > 0) {
|
||||||
{
|
lastUpdateTime = System.currentTimeMillis();
|
||||||
lastUpdateTime = System.currentTimeMillis();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
if ( (System.currentTimeMillis() - lastUpdateTime) > CONNECTION_TIMEOUT_MS )
|
if ((System.currentTimeMillis() - lastUpdateTime) > CONNECTION_TIMEOUT_MS) {
|
||||||
{
|
connectionTimeout = true;
|
||||||
connectionTimeout = true;
|
} else {
|
||||||
}
|
connectionTimeout = false;
|
||||||
else
|
}
|
||||||
{
|
|
||||||
connectionTimeout = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update connection state
|
// Update connection state
|
||||||
gcsStatsObj = objMngr.getObject("GCSTelemetryStats");
|
gcsStatsObj = objMngr.getObject("GCSTelemetryStats");
|
||||||
flightStatsObj = objMngr.getObject("FlightTelemetryStats");
|
flightStatsObj = objMngr.getObject("FlightTelemetryStats");
|
||||||
if(gcsStatsObj == null) {
|
if (gcsStatsObj == null) {
|
||||||
System.out.println("No GCS stats yet");
|
Log.d(TAG, "No GCS stats yet");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
UAVObjectField statusField = gcsStatsObj.getField("Status");
|
UAVObjectField statusField = gcsStatsObj.getField("Status");
|
||||||
String oldStatus = new String((String) statusField.getValue());
|
String oldStatus = new String((String) statusField.getValue());
|
||||||
|
|
||||||
if (DEBUG) Log.d(TAG,"GCS: " + statusField.getValue() + " Flight: " + flightStatsObj.getField("Status").getValue());
|
if (DEBUG)
|
||||||
|
Log.d(TAG, "GCS: " + statusField.getValue() + " Flight: "
|
||||||
|
+ flightStatsObj.getField("Status").getValue());
|
||||||
|
|
||||||
if ( oldStatus.compareTo("Disconnected") == 0 )
|
if (oldStatus.compareTo("Disconnected") == 0) {
|
||||||
{
|
// Request connection
|
||||||
// Request connection
|
statusField.setValue("HandshakeReq");
|
||||||
statusField.setValue("HandshakeReq");
|
} else if (oldStatus.compareTo("HandshakeReq") == 0) {
|
||||||
}
|
// Check for connection acknowledge
|
||||||
else if ( oldStatus.compareTo("HandshakeReq") == 0 )
|
if (((String) flightStatsObj.getField("Status").getValue())
|
||||||
{
|
.compareTo("HandshakeAck") == 0) {
|
||||||
// Check for connection acknowledge
|
statusField.setValue("Connected");
|
||||||
if ( ((String) flightStatsObj.getField("Status").getValue()).compareTo("HandshakeAck") == 0 )
|
if (DEBUG)
|
||||||
{
|
Log.d(TAG, "Connected" + statusField.toString());
|
||||||
statusField.setValue("Connected");
|
}
|
||||||
if (DEBUG) Log.d(TAG,"Connected" + statusField.toString());
|
} else if (oldStatus.compareTo("Connected") == 0) {
|
||||||
}
|
// Check if the connection is still active and the the autopilot is
|
||||||
}
|
// still connected
|
||||||
else if ( oldStatus.compareTo("Connected") == 0 )
|
if (((String) flightStatsObj.getField("Status").getValue())
|
||||||
{
|
.compareTo("Disconnected") == 0 || connectionTimeout) {
|
||||||
// Check if the connection is still active and the the autopilot is still connected
|
statusField.setValue("Disconnected");
|
||||||
if ( ((String) flightStatsObj.getField("Status").getValue()).compareTo("Disconnected") == 0 || connectionTimeout)
|
}
|
||||||
{
|
}
|
||||||
statusField.setValue("Disconnected");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Force telemetry update if not yet connected
|
// Force telemetry update if not yet connected
|
||||||
boolean gcsStatusChanged = !oldStatus.equals(statusField.getValue());
|
boolean gcsStatusChanged = !oldStatus.equals(statusField.getValue());
|
||||||
|
|
||||||
boolean gcsConnected = statusField.getValue().equals("Connected");
|
boolean gcsConnected = statusField.getValue().equals("Connected");
|
||||||
boolean gcsDisconnected = statusField.getValue().equals("Disconnected");
|
boolean gcsDisconnected = statusField.getValue().equals("Disconnected");
|
||||||
boolean flightConnected = flightStatsObj.getField("Status").equals("Connected");
|
boolean flightConnected = flightStatsObj.getField("Status").equals(
|
||||||
|
"Connected");
|
||||||
|
|
||||||
if ( !gcsConnected || !flightConnected )
|
if (!gcsConnected || !flightConnected) {
|
||||||
{
|
if (DEBUG)
|
||||||
if (DEBUG) Log.d(TAG,"Sending gcs status");
|
Log.d(TAG, "Sending gcs status");
|
||||||
gcsStatsObj.updated();
|
gcsStatsObj.updated();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Act on new connections or disconnections
|
// Act on new connections or disconnections
|
||||||
if (gcsConnected && gcsStatusChanged)
|
if (gcsConnected && gcsStatusChanged) {
|
||||||
{
|
if (DEBUG)
|
||||||
if (DEBUG) Log.d(TAG,"Connection with the autopilot established");
|
Log.d(TAG, "Connection with the autopilot established");
|
||||||
setPeriod(STATS_UPDATE_PERIOD_MS);
|
setPeriod(STATS_UPDATE_PERIOD_MS);
|
||||||
connected = true;
|
connected = true;
|
||||||
objects_updated = false;
|
objects_updated = false;
|
||||||
startRetrievingObjects();
|
startRetrievingObjects();
|
||||||
setChanged();
|
setChanged();
|
||||||
}
|
}
|
||||||
if (gcsDisconnected && gcsStatusChanged)
|
if (gcsDisconnected && gcsStatusChanged) {
|
||||||
{
|
if (DEBUG)
|
||||||
if (DEBUG) Log.d(TAG,"Trying to connect to the autopilot");
|
Log.d(TAG, "Trying to connect to the autopilot");
|
||||||
setPeriod(STATS_CONNECT_PERIOD_MS);
|
setPeriod(STATS_CONNECT_PERIOD_MS);
|
||||||
connected = false;
|
connected = false;
|
||||||
objects_updated = false;
|
objects_updated = false;
|
||||||
setChanged();
|
setChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DEBUG) Log.d(TAG, "processStatsUpdates() - before notify");
|
if (DEBUG)
|
||||||
notifyObservers();
|
Log.d(TAG, "processStatsUpdates() - before notify");
|
||||||
if (DEBUG) Log.d(TAG, "processStatsUpdates() - after notify");
|
notifyObservers();
|
||||||
|
if (DEBUG)
|
||||||
|
Log.d(TAG, "processStatsUpdates() - after notify");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setPeriod(int ms) {
|
private void setPeriod(int ms) {
|
||||||
if(periodicTask == null)
|
if (periodicTask == null)
|
||||||
periodicTask = new Timer();
|
periodicTask = new Timer();
|
||||||
|
|
||||||
periodicTask.cancel();
|
periodicTask.cancel();
|
||||||
currentPeriod = ms;
|
currentPeriod = ms;
|
||||||
periodicTask = new Timer();
|
periodicTask = new Timer();
|
||||||
periodicTask.scheduleAtFixedRate(new TimerTask() {
|
periodicTask.scheduleAtFixedRate(new TimerTask() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
processStatsUpdates();
|
processStatsUpdates();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// Once the stream has died stop trying to process these updates
|
// Once the stream has died stop trying to process these
|
||||||
|
// updates
|
||||||
periodicTask.cancel();
|
periodicTask.cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, currentPeriod, currentPeriod);
|
}, currentPeriod, currentPeriod);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stopMonitor()
|
public void stopMonitor() {
|
||||||
{
|
|
||||||
periodicTask.cancel();
|
periodicTask.cancel();
|
||||||
periodicTask = null;
|
periodicTask = null;
|
||||||
}
|
}
|
||||||
|
@ -174,9 +174,10 @@ public class UAVObjectField {
|
|||||||
Integer val = (Integer) getValue(index);
|
Integer val = (Integer) getValue(index);
|
||||||
dataOut.put(val.byteValue());
|
dataOut.put(val.byteValue());
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case STRING:
|
case STRING:
|
||||||
// TODO: Implement strings
|
// TODO: Implement strings
|
||||||
throw new Error("Strings not yet implemented");
|
throw new Error("Strings not yet implemented. Field name: " + getName());
|
||||||
}
|
}
|
||||||
// Done
|
// Done
|
||||||
return getNumBytes();
|
return getNumBytes();
|
||||||
|
@ -31,16 +31,18 @@ import java.io.InputStream;
|
|||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
import java.util.Observable;
|
|
||||||
|
|
||||||
|
import junit.framework.Assert;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
public class UAVTalk extends Observable {
|
public class UAVTalk {
|
||||||
|
|
||||||
static final String TAG = "UAVTalk";
|
static final String TAG = "UAVTalk";
|
||||||
public static int LOGLEVEL = 0;
|
public static int LOGLEVEL = 0;
|
||||||
public static boolean WARN = LOGLEVEL > 1;
|
public static boolean VERBOSE = LOGLEVEL > 3;
|
||||||
public static boolean DEBUG = LOGLEVEL > 0;
|
public static boolean WARN = LOGLEVEL > 2;
|
||||||
|
public static boolean DEBUG = LOGLEVEL > 1;
|
||||||
|
public static boolean ERROR = LOGLEVEL > 0;
|
||||||
|
|
||||||
private Thread inputProcessingThread = null;
|
private Thread inputProcessingThread = null;
|
||||||
|
|
||||||
@ -102,12 +104,13 @@ public class UAVTalk extends Observable {
|
|||||||
STATE_SYNC, STATE_TYPE, STATE_SIZE, STATE_OBJID, STATE_INSTID, STATE_DATA, STATE_CS
|
STATE_SYNC, STATE_TYPE, STATE_SIZE, STATE_OBJID, STATE_INSTID, STATE_DATA, STATE_CS
|
||||||
};
|
};
|
||||||
|
|
||||||
static final int TYPE_MASK = 0xFC;
|
static final int TYPE_MASK = 0xF8;
|
||||||
static final int TYPE_VER = 0x20;
|
static final int TYPE_VER = 0x20;
|
||||||
static final int TYPE_OBJ = (TYPE_VER | 0x00);
|
static final int TYPE_OBJ = (TYPE_VER | 0x00);
|
||||||
static final int TYPE_OBJ_REQ = (TYPE_VER | 0x01);
|
static final int TYPE_OBJ_REQ = (TYPE_VER | 0x01);
|
||||||
static final int TYPE_OBJ_ACK = (TYPE_VER | 0x02);
|
static final int TYPE_OBJ_ACK = (TYPE_VER | 0x02);
|
||||||
static final int TYPE_ACK = (TYPE_VER | 0x03);
|
static final int TYPE_ACK = (TYPE_VER | 0x03);
|
||||||
|
static final int TYPE_NACK = (TYPE_VER | 0x04);
|
||||||
|
|
||||||
static final int MIN_HEADER_LENGTH = 8; // sync(1), type (1), size(2),
|
static final int MIN_HEADER_LENGTH = 8; // sync(1), type (1), size(2),
|
||||||
// object ID(4)
|
// object ID(4)
|
||||||
@ -271,6 +274,8 @@ public class UAVTalk extends Observable {
|
|||||||
// Send object depending on if a response is needed
|
// Send object depending on if a response is needed
|
||||||
if (type == TYPE_OBJ_ACK || type == TYPE_OBJ_REQ) {
|
if (type == TYPE_OBJ_ACK || type == TYPE_OBJ_REQ) {
|
||||||
if (transmitObject(obj, type, allInstances)) {
|
if (transmitObject(obj, type, allInstances)) {
|
||||||
|
if(type == TYPE_OBJ_REQ)
|
||||||
|
if (ERROR) Log.e(TAG, "Sending obj req");
|
||||||
respObj = obj;
|
respObj = obj;
|
||||||
respAllInstances = allInstances;
|
respAllInstances = allInstances;
|
||||||
return true;
|
return true;
|
||||||
@ -290,7 +295,7 @@ public class UAVTalk extends Observable {
|
|||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public synchronized boolean processInputByte(int rxbyte) throws IOException {
|
public synchronized boolean processInputByte(int rxbyte) throws IOException {
|
||||||
assert (objMngr != null);
|
Assert.assertNotNull(objMngr);
|
||||||
|
|
||||||
// Update stats
|
// Update stats
|
||||||
stats.rxBytes++;
|
stats.rxBytes++;
|
||||||
@ -318,12 +323,13 @@ public class UAVTalk extends Observable {
|
|||||||
rxCS = updateCRC(rxCS, rxbyte);
|
rxCS = updateCRC(rxCS, rxbyte);
|
||||||
|
|
||||||
if ((rxbyte & TYPE_MASK) != TYPE_VER) {
|
if ((rxbyte & TYPE_MASK) != TYPE_VER) {
|
||||||
|
Log.e(TAG, "Unknown UAVTalk type:" + rxbyte);
|
||||||
rxState = RxStateType.STATE_SYNC;
|
rxState = RxStateType.STATE_SYNC;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
rxType = rxbyte;
|
rxType = rxbyte;
|
||||||
|
if (VERBOSE) Log.v(TAG, "Received packet type: " + rxType);
|
||||||
packetSize = 0;
|
packetSize = 0;
|
||||||
|
|
||||||
rxState = RxStateType.STATE_SIZE;
|
rxState = RxStateType.STATE_SIZE;
|
||||||
@ -380,7 +386,7 @@ public class UAVTalk extends Observable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Determine data length
|
// Determine data length
|
||||||
if (rxType == TYPE_OBJ_REQ || rxType == TYPE_ACK)
|
if (rxType == TYPE_OBJ_REQ || rxType == TYPE_ACK || rxType == TYPE_NACK)
|
||||||
rxLength = 0;
|
rxLength = 0;
|
||||||
else
|
else
|
||||||
rxLength = rxObj.getNumBytes();
|
rxLength = rxObj.getNumBytes();
|
||||||
@ -565,6 +571,24 @@ public class UAVTalk extends Observable {
|
|||||||
error = true;
|
error = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case TYPE_NACK:
|
||||||
|
if (DEBUG) Log.d(TAG, "Received NAK: " + objId + " " + objMngr.getObject(objId).getName());
|
||||||
|
// All instances, not allowed for NACK messages
|
||||||
|
if (!allInstances)
|
||||||
|
{
|
||||||
|
// Get object
|
||||||
|
obj = objMngr.getObject(objId, instId);
|
||||||
|
// Check if object exists:
|
||||||
|
if (obj != null)
|
||||||
|
{
|
||||||
|
updateNack(obj);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
case TYPE_ACK:
|
case TYPE_ACK:
|
||||||
// All instances, not allowed for ACK messages
|
// All instances, not allowed for ACK messages
|
||||||
if (!allInstances) {
|
if (!allInstances) {
|
||||||
@ -636,15 +660,33 @@ public class UAVTalk extends Observable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a transaction is pending and if yes complete it.
|
||||||
|
*/
|
||||||
|
void updateNack(UAVObject obj)
|
||||||
|
{
|
||||||
|
if (DEBUG) Log.d(TAG, "NACK received: " + obj.getName());
|
||||||
|
Assert.assertNotNull(obj);
|
||||||
|
//obj.transactionCompleted(false);
|
||||||
|
if (respObj != null && respObj.getObjID() == obj.getObjID() &&
|
||||||
|
(respObj.getInstID() == obj.getInstID() || respAllInstances)) {
|
||||||
|
if (transactionListener != null)
|
||||||
|
transactionListener.TransactionFailed(obj);
|
||||||
|
respObj = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a transaction is pending and if yes complete it.
|
* Check if a transaction is pending and if yes complete it.
|
||||||
*/
|
*/
|
||||||
synchronized void updateAck(UAVObject obj) {
|
synchronized void updateAck(UAVObject obj) {
|
||||||
|
if (DEBUG) Log.d(TAG, "ACK received: " + obj.getName());
|
||||||
|
Assert.assertNotNull(obj);
|
||||||
if (respObj != null && respObj.getObjID() == obj.getObjID()
|
if (respObj != null && respObj.getObjID() == obj.getObjID()
|
||||||
&& (respObj.getInstID() == obj.getInstID() || respAllInstances)) {
|
&& (respObj.getInstID() == obj.getInstID() || respAllInstances)) {
|
||||||
|
if (transactionListener != null)
|
||||||
|
transactionListener.TransactionSucceeded(obj);
|
||||||
respObj = null;
|
respObj = null;
|
||||||
setChanged();
|
|
||||||
notifyObservers(obj);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -784,4 +826,14 @@ public class UAVTalk extends Observable {
|
|||||||
return crc;
|
return crc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private OnTransactionCompletedListener transactionListener = null;
|
||||||
|
abstract class OnTransactionCompletedListener {
|
||||||
|
abstract void TransactionSucceeded(UAVObject data);
|
||||||
|
abstract void TransactionFailed(UAVObject data);
|
||||||
|
};
|
||||||
|
void setOnTransactionCompletedListener(OnTransactionCompletedListener onTransactionListener) {
|
||||||
|
this.transactionListener = onTransactionListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user