From e2a90b2265d721e1fc28f76b6630dfa979dc5fd8 Mon Sep 17 00:00:00 2001 From: James Cotton Date: Sun, 20 Mar 2011 06:09:06 -0500 Subject: [PATCH] Added some missing files. Improved object browser to use ListView. ExpandableListView next. --- androidgcs/Doc/.AndroidArchitecture.txt.swp | Bin 0 -> 12288 bytes androidgcs/Doc/AndroidArchitecture.txt | 31 +++++++ androidgcs/res/layout/main.xml | 17 ++-- androidgcs/res/layout/object_view.xml | 7 ++ androidgcs/res/menu/options_menu.xml | 6 ++ androidgcs/res/values/strings.xml | 4 + androidgcs/res/xml/telemetry_widget_info.xml | 9 ++ .../androidgcs/OPTelemetryService.java | 69 +++++++++++--- .../openpilot/androidgcs/ObjectBrowser.java | 84 +++++++++++++----- .../androidgcs/ObjectManagerActivity.java | 1 - .../openpilot/uavtalk/TelemetryMonitor.java | 30 +++++-- .../src/org/openpilot/uavtalk/UAVTalk.java | 3 +- 12 files changed, 202 insertions(+), 59 deletions(-) create mode 100644 androidgcs/Doc/.AndroidArchitecture.txt.swp create mode 100644 androidgcs/Doc/AndroidArchitecture.txt create mode 100644 androidgcs/res/layout/object_view.xml create mode 100644 androidgcs/res/menu/options_menu.xml create mode 100644 androidgcs/res/xml/telemetry_widget_info.xml diff --git a/androidgcs/Doc/.AndroidArchitecture.txt.swp b/androidgcs/Doc/.AndroidArchitecture.txt.swp new file mode 100644 index 0000000000000000000000000000000000000000..167a072526a8207b396d71d6dd7d3e7a417cba19 GIT binary patch literal 12288 zcmeHNzmFS56rMwnA3z`iK>^J`id>>QJ0S%T4RS8dVU#03?7Kh}jd#cP-0jXRGqdLy zB_JeP;2%IhK?4;OL^LQ=G-;^`1>rxSqu_h9yY}UZv?yp!`Qr2bn0fDe-}~N1+2N_J z-UffYb%x>RC}UrI^6`eazqIt*H;ip3#(SgBo~CmT`FUIA`E0F~nM7m{xr}`{U$A}N zBxNqOckRp8jIGFXrN`|{h18c-W_(-d)EbqJ6GxY}JJr{YO(x3A#FtjK{0;xG&EmPp zKxAOSK2dF}KmI(Y2WSNQYKZ7$Bo-y#E%fyh8)ATkgchzvvqA_I|u|2+e~ zSYjU`%g5?WFVvq)`#$Th@gp)28Hfx-1|kEIfyh8)ATkgchzvvqA_I|uN00%LGPe3S zW8w(}kN^K~{{8>wvy6QWdgNH7@GiVz&YUWBaGb!egqV740sWE0XPKw z{4`@0=mO_~lfb>F82cRP0!M*ofjdt!whJr+$AP~NGj<=i3)}=&fZq=>_6u+am;%ed z%fL&(-Ghw%0DKSJ0&W6r;2>}SxP5@J?|^TC1b7#?2Al(q0{?)6KY)9{ufSKpm%uIH zCJ;D!1Zx~ajtoQw{v!rDLzO8%3N*zup~i9E8`N zJjt(=($1ROmC@XJ;Y%0Jt%)q-ixtDMb+s$`1g~IalEU^A$uAAJvEPQ!Vk~WlMhc{| z+1bJ!d>}KKOOH)@=af#RWz3aDVXT*Fi}iSFw8t_^?}Wu_0x0t`OR*ESqfJcV5uM{= zXiCqg6IJbi16DEy2JlW;QP7eDT)l4K9sH7M5==$7f5Rz69N4eGEt)$7oa0aK>dR<<+V;*EZhkKkq=f0;#uJWRh7h|Lk)@Mia*XtyY#&& zZ&P+!eJnl81(K?`_p@bp0t|FA4-tfozxuZv%GMYV5G@j`J6 zy5|AVh8{o$Lu5PWw$TtDS(68fK+`@G=y$Jf_13zT3-nFZvp2l7T4daWb|zs;NP;A2 z<(RC7`h?s^4AJ|}YlBe!Esc)S*+4( zVXz0Jx=DhbcZh^O(6Wiip%Xq8!7NiU9#D!uWPYRr+*Jk6mt6^O5H9GbdN-7=fY?G2 zKqZt<w>-1wnI&T9)>r`IggCxCM`qiRMFH(r;p=PLhmUW2tq;~>J3K{ zE@~y3gMwQW(#?=$4srAA~;j1tIlNGZG^8G*3NuIRz$>-_K0|9#2o7)E zy0$aPj`Sd1^D6_g-Fh==!;D$w8{K}tv)<*GJN z%~W%*a@k^KkwQ03=yfqrhy(^WMiQ{XP&Dw5tf{9ObFD)iG$zf~s?3mXt&3{yFhFYt zLUMI{W)!}SFonYu2;1PDnASejO27?lH&?XqC1*CKB2< zJRd2H4ssgICx|G+fTt48MX*tgmL`RI(p33h$kce^=a=@Oe8i7VUSI1!c$Bh$@MKO} z)yAt)QxAH8;9x{Ma{lmmg0?`p(M<5NMIcQCRwfb;P%hM!HY3^6{aAa>5fmB5hHtb? zVZnXGHoT4&hb!U1?v2pE^H6zZEvPGvF2pr&X_;cKVK49(?j|=txdk7|DGdht+4F>0 I9l+o0U$ht(TmS$7 literal 0 HcmV?d00001 diff --git a/androidgcs/Doc/AndroidArchitecture.txt b/androidgcs/Doc/AndroidArchitecture.txt new file mode 100644 index 000000000..d9cdf2ada --- /dev/null +++ b/androidgcs/Doc/AndroidArchitecture.txt @@ -0,0 +1,31 @@ +------- TELEMETRY --------- +The Telemetry system has been implemented, and is composed of a few +major components: + +Telemetry.java - receives command to transmit objects through telemetry and +also emits notification when transactions are completed + +TelemetryMonitor.java - monitors the FlightTelemetryStats and GCSTelemetryStats +to establish when a working connection is in place. Also initiates downloading +all the objects on a new connection. + +UAVObjectManager.java - the central data store. The data is actually stored +within objects, but this maintains the handles to all of them. + +UAVTalk.java - the actual communication layer. Can packetize an object and +insert into stream and process the incoming stream and update objects +accordingly. + +---- MESSAGE PASSING ---- +The current implementation/analog to the slots/sockets in QT are Observers +which are registered as added to an Observable. This is used extensibly within +the telemetry system. I will continue to use this _within_ the Telemetry +module so it doesn't depend on any android features. + +In android there is a constraint that UI operations should all be done from the +UI thread. The most common way to do this is for the UI object (such as +Activity) to instantiate a Handler to which messages or runnables are posted. + +So for external objects they will register a runnable somehow... + + diff --git a/androidgcs/res/layout/main.xml b/androidgcs/res/layout/main.xml index 9e5f90add..880e276ff 100644 --- a/androidgcs/res/layout/main.xml +++ b/androidgcs/res/layout/main.xml @@ -1,13 +1,6 @@ - - - - - + + + diff --git a/androidgcs/res/layout/object_view.xml b/androidgcs/res/layout/object_view.xml new file mode 100644 index 000000000..fdf5a0bae --- /dev/null +++ b/androidgcs/res/layout/object_view.xml @@ -0,0 +1,7 @@ + + + diff --git a/androidgcs/res/menu/options_menu.xml b/androidgcs/res/menu/options_menu.xml new file mode 100644 index 000000000..db86aa670 --- /dev/null +++ b/androidgcs/res/menu/options_menu.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/androidgcs/res/values/strings.xml b/androidgcs/res/values/strings.xml index 52fa56534..8daa0ec36 100644 --- a/androidgcs/res/values/strings.xml +++ b/androidgcs/res/values/strings.xml @@ -1,4 +1,8 @@ OpenPilot GCS + Settings + Connect + Disconnect + OpenPilot Object Browser diff --git a/androidgcs/res/xml/telemetry_widget_info.xml b/androidgcs/res/xml/telemetry_widget_info.xml new file mode 100644 index 000000000..f2ced6645 --- /dev/null +++ b/androidgcs/res/xml/telemetry_widget_info.xml @@ -0,0 +1,9 @@ + + + android:minWidth="294dp" + android:minHeight="72dp" + android:updatePeriodMillis="86400000" + android:initialLayout="@layout/telemetry_widget"> + + diff --git a/androidgcs/src/org/openpilot/androidgcs/OPTelemetryService.java b/androidgcs/src/org/openpilot/androidgcs/OPTelemetryService.java index 557c3b256..7b3030d4f 100644 --- a/androidgcs/src/org/openpilot/androidgcs/OPTelemetryService.java +++ b/androidgcs/src/org/openpilot/androidgcs/OPTelemetryService.java @@ -1,5 +1,8 @@ package org.openpilot.androidgcs; +import java.util.Observable; +import java.util.Observer; + import org.openpilot.uavtalk.Telemetry; import org.openpilot.uavtalk.TelemetryMonitor; import org.openpilot.uavtalk.UAVDataObject; @@ -27,7 +30,7 @@ import android.widget.Toast; public class OPTelemetryService extends Service { // Logging settings - private final String TAG = "OPTElemetryService"; + private final String TAG = "OPTelemetryService"; public static int LOGLEVEL = 2; public static boolean WARN = LOGLEVEL > 1; public static boolean DEBUG = LOGLEVEL > 0; @@ -44,10 +47,13 @@ public class OPTelemetryService extends Service { private ServiceHandler mServiceHandler; // Message ids - final int MSG_START = 0; - final int MSG_CONNECT_BT = 1; - final int MSG_CONNECT_FAKE = 2; - final int MSG_TOAST = 100; + static final int MSG_START = 0; + static final int MSG_CONNECT_BT = 1; + static final int MSG_CONNECT_FAKE = 2; + static final int MSG_DISCONNECT = 3; + static final int MSG_TOAST = 100; + + private boolean terminate = false; private Thread activeTelem; @@ -65,12 +71,28 @@ public class OPTelemetryService extends Service { System.out.println("HERE"); stopSelf(msg.arg2); case MSG_CONNECT_BT: + terminate = false; activeTelem = new BTTelemetryThread(); activeTelem.start(); break; case MSG_CONNECT_FAKE: + terminate = false; activeTelem = new FakeTelemetryThread(); activeTelem.start(); + break; + case MSG_DISCONNECT: + terminate = true; + try { + activeTelem.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + activeTelem = null; + + Intent intent = new Intent(); + intent.setAction(INTENT_ACTION_DISCONNECTED); + sendBroadcast(intent,null); + break; case MSG_TOAST: Toast.makeText(OPTelemetryService.this, (String) msg.obj, Toast.LENGTH_SHORT); @@ -129,8 +151,18 @@ public class OPTelemetryService extends Service { msg.arg1 = MSG_CONNECT_FAKE; mServiceHandler.sendMessage(msg); } + public void openBTConnection() { + Message msg = mServiceHandler.obtainMessage(); + msg.arg1 = MSG_CONNECT_BT; + mServiceHandler.sendMessage(msg); + } + public void stopConnection() { + Message msg = mServiceHandler.obtainMessage(); + msg.arg1 = MSG_DISCONNECT; + mServiceHandler.sendMessage(msg); + } }; - + public void toastMessage(String msgText) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = MSG_TOAST; @@ -151,17 +183,17 @@ public class OPTelemetryService extends Service { objMngr = new UAVObjectManager(); UAVObjectsInitialize.register(objMngr); } - + public void run() { - System.out.println("Runnin fake thread"); + System.out.println("Running fake thread"); Intent intent = new Intent(); intent.setAction(INTENT_ACTION_CONNECTED); sendBroadcast(intent,null); - + //toastMessage("Started fake telemetry thread"); UAVDataObject systemStats = (UAVDataObject) objMngr.getObject("SystemStats"); - while(true) { + while( !terminate ) { systemStats.updated(); try { Thread.sleep(1000); @@ -176,7 +208,7 @@ public class OPTelemetryService extends Service { private UAVObjectManager objMngr; private UAVTalk uavTalk; private Telemetry tel; - //private TelemetryMonitor mon; + private TelemetryMonitor mon; public UAVObjectManager getObjectManager() { return objMngr; }; @@ -217,10 +249,21 @@ public class OPTelemetryService extends Service { uavTalk = bt.getUavtalk(); tel = new Telemetry(uavTalk, objMngr); - new TelemetryMonitor(objMngr,tel); + mon = new TelemetryMonitor(objMngr,tel); + mon.addObserver(new Observer() { + public void update(Observable arg0, Object arg1) { + System.out.println("Mon updated. Connected: " + mon.getConnected() + " objects updated: " + mon.getObjectsUpdated()); + if(mon.getConnected() /*&& mon.getObjectsUpdated()*/) { + Intent intent = new Intent(); + intent.setAction(INTENT_ACTION_CONNECTED); + sendBroadcast(intent,null); + } + } + }); + if (DEBUG) Log.d(TAG, "Entering UAVTalk processing loop"); - while(true) { + while( !terminate ) { if( !uavTalk.processInputStream() ) break; } diff --git a/androidgcs/src/org/openpilot/androidgcs/ObjectBrowser.java b/androidgcs/src/org/openpilot/androidgcs/ObjectBrowser.java index 48aa1cd10..f68e839c1 100644 --- a/androidgcs/src/org/openpilot/androidgcs/ObjectBrowser.java +++ b/androidgcs/src/org/openpilot/androidgcs/ObjectBrowser.java @@ -1,42 +1,67 @@ package org.openpilot.androidgcs; +import java.util.ArrayList; +import java.util.List; +import java.util.ListIterator; import java.util.Observable; import java.util.Observer; +import android.database.DataSetObserver; import android.os.Bundle; import android.os.Handler; import android.util.Log; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ExpandableListAdapter; +import android.widget.ExpandableListView; +import android.widget.ListView; +import android.widget.SimpleAdapter; +import android.widget.SimpleExpandableListAdapter; import android.widget.TextView; -import android.widget.ToggleButton; +import android.widget.Toast; +import org.openpilot.uavtalk.UAVDataObject; import org.openpilot.uavtalk.UAVObject; public class ObjectBrowser extends ObjectManagerActivity { + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch(item.getItemId()) { + case R.id.menu_connect: + binder.openBTConnection(); + return true; + case R.id.menu_disconnect: + binder.stopConnection(); + updateText.run(); + return true; + case R.id.menu_settings: + return true; + default: + return super.onOptionsItemSelected(item); + } + + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.options_menu, menu); + return true; + } + private final String TAG = "ObjectBrower"; boolean connected; final Handler uavobjHandler = new Handler(); final Runnable updateText = new Runnable() { public void run() { - ToggleButton button = (ToggleButton) findViewById(R.id.toggleButton1); - button.setChecked(!connected); - - Log.d(TAG,"HERE" + connected); - - TextView text = (TextView) findViewById(R.id.textView1); - - UAVObject obj1 = objMngr.getObject("SystemStats"); - UAVObject obj2 = objMngr.getObject("AttitudeRaw"); - UAVObject obj3 = objMngr.getObject("AttitudeActual"); - UAVObject obj4 = objMngr.getObject("SystemAlarms"); - - if(obj1 == null || obj2 == null || obj3 == null || obj4 == null) - return; - - Log.d(TAG,"And here"); - text.setText(obj1.toString() + "\n" + obj2.toString() + "\n" + obj3.toString() + "\n" + obj4.toString() ); - + Log.d(TAG,"Update"); + update(); } }; @@ -44,16 +69,15 @@ public class ObjectBrowser extends ObjectManagerActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.main); + setContentView(R.layout.main); } @Override void onOPConnected() { - // Toast.makeText(this,"Telemetry estabilished",Toast.LENGTH_SHORT); + Toast.makeText(this,"Telemetry estabilished",Toast.LENGTH_SHORT); Log.d(TAG, "onOPConnected()"); - + UAVObject obj = objMngr.getObject("SystemStats"); - Log.d(TAG, ((Boolean) (obj == null)).toString()); if(obj != null) obj.addUpdatedObserver(new Observer() { public void update(Observable observable, Object data) { @@ -62,4 +86,18 @@ public class ObjectBrowser extends ObjectManagerActivity { }); } + + public void update() { + List> allobjects = objMngr.getDataObjects(); + List linearized = new ArrayList(); + ListIterator> li = allobjects.listIterator(); + while(li.hasNext()) { + linearized.addAll(li.next()); + } + + ArrayAdapter adapter = new ArrayAdapter(this,R.layout.object_view, linearized); + ListView objects = (ListView) findViewById(R.id.object_list); + objects.setAdapter(adapter); + + } } diff --git a/androidgcs/src/org/openpilot/androidgcs/ObjectManagerActivity.java b/androidgcs/src/org/openpilot/androidgcs/ObjectManagerActivity.java index 9f57796dc..12a072de7 100644 --- a/androidgcs/src/org/openpilot/androidgcs/ObjectManagerActivity.java +++ b/androidgcs/src/org/openpilot/androidgcs/ObjectManagerActivity.java @@ -85,7 +85,6 @@ public abstract class ObjectManagerActivity extends Activity { // We've bound to LocalService, cast the IBinder and attempt to open a connection if (DEBUG) Log.d(TAG,"Service bound"); binder = (LocalBinder) service; - binder.openFakeConnection(); } public void onServiceDisconnected(ComponentName name) { diff --git a/androidgcs/src/org/openpilot/uavtalk/TelemetryMonitor.java b/androidgcs/src/org/openpilot/uavtalk/TelemetryMonitor.java index 7208181ad..daedcc85b 100644 --- a/androidgcs/src/org/openpilot/uavtalk/TelemetryMonitor.java +++ b/androidgcs/src/org/openpilot/uavtalk/TelemetryMonitor.java @@ -10,10 +10,10 @@ import java.util.TimerTask; import android.util.Log; -public class TelemetryMonitor { +public class TelemetryMonitor extends Observable{ private static final String TAG = "TelemetryMonitor"; - public static int LOGLEVEL = 0; + public static int LOGLEVEL = 2; public static boolean WARN = LOGLEVEL > 1; public static boolean DEBUG = LOGLEVEL > 0; @@ -31,6 +31,12 @@ public class TelemetryMonitor { private long lastUpdateTime; private List queue; + private boolean connected = false; + private boolean objects_updated = false; + + public boolean getConnected() { return connected; }; + public boolean getObjectsUpdated() { return objects_updated; }; + public TelemetryMonitor(UAVObjectManager objMngr, Telemetry tel) { this.objMngr = objMngr; @@ -116,8 +122,9 @@ public class TelemetryMonitor { if ( queue.isEmpty() ) { if (DEBUG) Log.d(TAG, "All objects retrieved: Connected Successfully"); - //qxtLog->debug("Object retrieval completed"); - //emit connected(); + objects_updated = true; + setChanged(); + notifyObservers(); return; } // Get next object from the queue @@ -260,9 +267,9 @@ public class TelemetryMonitor { // Force telemetry update if not yet connected boolean gcsStatusChanged = !oldStatus.equals(statusField.getValue()); - boolean gcsConnected = ((String) statusField.getValue()).compareTo("Connected") == 0; - boolean gcsDisconnected = ((String) statusField.getValue()).compareTo("Disconnected") == 0; - boolean flightConnected = ((String) flightStatsObj.getField("Status").getValue()).compareTo("Connected") == 0; + boolean gcsConnected = statusField.getValue().equals("Connected"); + boolean gcsDisconnected = statusField.getValue().equals("Disconnected"); + boolean flightConnected = flightStatsObj.getField("Status").equals("Connected"); if ( !gcsConnected || !flightConnected ) { @@ -275,14 +282,21 @@ public class TelemetryMonitor { { if (DEBUG) Log.d(TAG,"Connection with the autopilot established"); setPeriod(STATS_UPDATE_PERIOD_MS); + connected = true; + objects_updated = false; startRetrievingObjects(); + setChanged(); } if (gcsDisconnected && gcsStatusChanged) { if (DEBUG) Log.d(TAG,"Trying to connect to the autopilot"); setPeriod(STATS_CONNECT_PERIOD_MS); - //emit disconnected(); + connected = false; + objects_updated = false; + setChanged(); } + notifyObservers(); + } private void setPeriod(int ms) { diff --git a/androidgcs/src/org/openpilot/uavtalk/UAVTalk.java b/androidgcs/src/org/openpilot/uavtalk/UAVTalk.java index 8671cdef9..39c1f6ee7 100644 --- a/androidgcs/src/org/openpilot/uavtalk/UAVTalk.java +++ b/androidgcs/src/org/openpilot/uavtalk/UAVTalk.java @@ -197,8 +197,7 @@ public class UAVTalk extends Observable { return false; } - // System.out.println("Received byte " + val + " in state + " + - // rxState); + //System.out.println("Received byte " + val + " in state + " + rxState); processInputByte(val); return true; }