mirror of
https://bitbucket.org/librepilot/librepilot.git
synced 2025-01-18 03:52:11 +01:00
AndroidGCS: Refactor TCP and HID onto a common TelemTask class which handles
most of the logic of setting up the UAVTalk, ObjectMangager, Telemetry and TelemetryMonitor classes. Provides a cleaner shutdown too.
This commit is contained in:
parent
5addc15f60
commit
d0bb6c3813
@ -11,12 +11,7 @@ import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.openpilot.uavtalk.UAVObjectManager;
|
||||
import org.openpilot.uavtalk.UAVTalk;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@ -30,21 +25,13 @@ import android.hardware.usb.UsbManager;
|
||||
import android.hardware.usb.UsbRequest;
|
||||
import android.util.Log;
|
||||
|
||||
public class HidUAVTalk {
|
||||
public class HidUAVTalk extends TelemetryTask {
|
||||
|
||||
private static final String TAG = HidUAVTalk.class.getSimpleName();
|
||||
public static int LOGLEVEL = 0;
|
||||
public static boolean WARN = LOGLEVEL > 1;
|
||||
public static boolean DEBUG = LOGLEVEL > 0;
|
||||
|
||||
Service hostDisplayActivity;
|
||||
|
||||
private boolean connected;
|
||||
|
||||
private UAVTalk uavTalk;
|
||||
|
||||
private UAVObjectManager objMngr;
|
||||
|
||||
//! USB constants
|
||||
static final int OPENPILOT_VENDOR_ID = 0x20A0;
|
||||
|
||||
@ -56,51 +43,57 @@ public class HidUAVTalk {
|
||||
static final int USB_PRODUCT_ID_OSD = 0x4194;
|
||||
static final int USB_PRODUCT_ID_SPARE = 0x4195;
|
||||
|
||||
public HidUAVTalk(Service service) {
|
||||
hostDisplayActivity = service;
|
||||
}
|
||||
|
||||
public boolean getConnected() {
|
||||
return connected;
|
||||
}
|
||||
|
||||
public UAVTalk getUavtalk() {
|
||||
return uavTalk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a TCP socket to the address determined on construction. If successful
|
||||
* creates a UAVTalk stream connection this socket to the passed in object manager
|
||||
*/
|
||||
public boolean openTelemetryHid(UAVObjectManager objMngr) {
|
||||
uavTalk = new UAVTalk(inStream, outStream, objMngr);
|
||||
this.objMngr = objMngr;
|
||||
return true;
|
||||
private static final String ACTION_USB_PERMISSION = "com.access.device.USB_PERMISSION";
|
||||
|
||||
UsbDevice currentDevice;
|
||||
|
||||
public HidUAVTalk(OPTelemetryService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect() {
|
||||
|
||||
CleanUpAndClose();
|
||||
//hostDisplayActivity.unregisterReceiver(usbReceiver);
|
||||
//hostDisplayActivity.unregisterReceiver(usbPermissionReceiver);
|
||||
inStream.stop();
|
||||
outStream.stop();
|
||||
telemService.unregisterReceiver(usbPermissionReceiver);
|
||||
((TalkInputStream)inStream).stop();
|
||||
((TalkOutputStream)outStream).stop();
|
||||
|
||||
super.disconnect();
|
||||
|
||||
try {
|
||||
readThread.join();
|
||||
writeThread.join();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
public boolean connect(UAVObjectManager objMngr) {
|
||||
if (readRequest != null) {
|
||||
readRequest.cancel();
|
||||
readRequest.close();
|
||||
readRequest = null;
|
||||
}
|
||||
|
||||
if (writeRequest != null) {
|
||||
writeRequest.cancel();
|
||||
writeRequest.close();
|
||||
writeRequest = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean attemptConnection() {
|
||||
if (DEBUG) Log.d(TAG, "connect()");
|
||||
|
||||
// Register to get permission requested dialog
|
||||
usbManager = (UsbManager) hostDisplayActivity.getSystemService(Context.USB_SERVICE);
|
||||
permissionIntent = PendingIntent.getBroadcast(hostDisplayActivity, 0, new Intent(ACTION_USB_PERMISSION), 0);
|
||||
usbManager = (UsbManager) telemService.getSystemService(Context.USB_SERVICE);
|
||||
permissionIntent = PendingIntent.getBroadcast(telemService, 0, new Intent(ACTION_USB_PERMISSION), 0);
|
||||
permissionFilter = new IntentFilter(ACTION_USB_PERMISSION);
|
||||
hostDisplayActivity.registerReceiver(usbPermissionReceiver, permissionFilter);
|
||||
|
||||
// Register to get notified on device attached
|
||||
/*deviceAttachedFilter = new IntentFilter();
|
||||
deviceAttachedFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
|
||||
deviceAttachedFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
|
||||
hostDisplayActivity.registerReceiver(usbReceiver, deviceAttachedFilter);*/
|
||||
telemService.registerReceiver(usbPermissionReceiver, permissionFilter);
|
||||
|
||||
// Go through all the devices plugged in
|
||||
HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
|
||||
if (DEBUG) Log.d(TAG, "Found " + deviceList.size() + " devices");
|
||||
Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
|
||||
@ -108,33 +101,13 @@ public class HidUAVTalk {
|
||||
UsbDevice dev = deviceIterator.next();
|
||||
if (DEBUG) Log.d(TAG, "Testing device: " + dev);
|
||||
usbManager.requestPermission(dev, permissionIntent);
|
||||
//ConnectToDeviceInterface(dev);
|
||||
}
|
||||
|
||||
if (DEBUG) Log.d(TAG, "Registered the deviceAttachedFilter");
|
||||
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
return deviceList.size() > 0;
|
||||
}
|
||||
|
||||
if( !openTelemetryHid(objMngr) )
|
||||
return false;
|
||||
|
||||
return connected;
|
||||
|
||||
}
|
||||
|
||||
public HidUAVTalk(OPTelemetryService opTelemetryService) {
|
||||
this.hostDisplayActivity = opTelemetryService;
|
||||
}
|
||||
|
||||
private static final String ACTION_USB_PERMISSION = "com.access.device.USB_PERMISSION";
|
||||
|
||||
UsbDevice currentDevice;
|
||||
|
||||
/*
|
||||
* Receives a requested broadcast from the operating system.
|
||||
* In this case the following actions are handled:
|
||||
@ -172,9 +145,6 @@ public class HidUAVTalk {
|
||||
{
|
||||
if (DEBUG) Log.d(TAG, "Unable to connect to device");
|
||||
}
|
||||
sendEnabledMessage();
|
||||
// TODO: Create a listener to receive messages from the host
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -224,12 +194,8 @@ public class HidUAVTalk {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sendEnabledMessage() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
private UsbEndpoint usbEndpointRead;
|
||||
|
||||
private UsbEndpoint usbEndpointWrite;
|
||||
@ -246,11 +212,6 @@ public class HidUAVTalk {
|
||||
|
||||
private IntentFilter permissionFilter;
|
||||
|
||||
protected void sendEnabledMessage() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
protected void CleanUpAndClose() {
|
||||
if (UsingSingleInterface) {
|
||||
if(connectionRead != null && usbInterfaceRead != null)
|
||||
@ -372,12 +333,53 @@ public class HidUAVTalk {
|
||||
}
|
||||
|
||||
connectedDevice = connectDevice;
|
||||
connected = true;
|
||||
if (DEBUG) Log.d(TAG, "Opened endpoints");
|
||||
|
||||
// Create the USB requests
|
||||
readRequest = new UsbRequest();
|
||||
readRequest.initialize(connectionRead, usbEndpointRead);
|
||||
|
||||
writeRequest = new UsbRequest();
|
||||
writeRequest.initialize(connectionWrite, usbEndpointWrite);
|
||||
|
||||
|
||||
handler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
inStream = new TalkInputStream();
|
||||
outStream = new TalkOutputStream();
|
||||
attemptSucceeded();
|
||||
}
|
||||
});
|
||||
|
||||
readThread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
while (!shutdown) {
|
||||
readData();
|
||||
sendData();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
readThread.start();
|
||||
|
||||
writeThread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
while (!shutdown) {
|
||||
sendData();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
//writeThread.start();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Thread readThread;
|
||||
Thread writeThread;
|
||||
private int byteToInt(byte b) { return b & 0x000000ff; }
|
||||
|
||||
private class TalkInputStream extends InputStream {
|
||||
@ -409,7 +411,6 @@ public class HidUAVTalk {
|
||||
data.put(b);
|
||||
}
|
||||
};
|
||||
private final TalkInputStream inStream = new TalkInputStream();
|
||||
|
||||
private class ByteFifo {
|
||||
|
||||
@ -479,11 +480,6 @@ public class HidUAVTalk {
|
||||
int bufferDataLength = usbEndpointRead.getMaxPacketSize();
|
||||
ByteBuffer buffer = ByteBuffer.allocate(bufferDataLength + 1);
|
||||
|
||||
if(readRequest == null) {
|
||||
readRequest = new UsbRequest();
|
||||
readRequest.initialize(connectionRead, usbEndpointRead);
|
||||
}
|
||||
|
||||
// queue a request on the interrupt endpoint
|
||||
if(!readRequest.queue(buffer, bufferDataLength)) {
|
||||
if (DEBUG) Log.d(TAG, "Failed to queue request");
|
||||
@ -511,17 +507,12 @@ public class HidUAVTalk {
|
||||
buffer.position(2);
|
||||
buffer.get(dst, 0, dataSize);
|
||||
if (DEBUG) Log.d(TAG, "Entered read");
|
||||
inStream.write(dst);
|
||||
((TalkInputStream)inStream).write(dst);
|
||||
if (DEBUG) Log.d(TAG, "Got read: " + dataSize + " bytes");
|
||||
}
|
||||
} else
|
||||
return 0;
|
||||
|
||||
if(false) {
|
||||
readRequest.cancel();
|
||||
readRequest.close();
|
||||
}
|
||||
|
||||
return dataSize;
|
||||
}
|
||||
|
||||
@ -600,30 +591,32 @@ public class HidUAVTalk {
|
||||
// Remove that data from the write buffer
|
||||
data.compact();
|
||||
writePosition -= size;
|
||||
if (DEBUG) Log.d(TAG, "packetizeData(): size="+size);
|
||||
}
|
||||
WriteToDevice(packet);
|
||||
}
|
||||
|
||||
};
|
||||
private final TalkOutputStream outStream = new TalkOutputStream();
|
||||
private static final int MAX_HID_PACKET_SIZE = 64;
|
||||
|
||||
/**
|
||||
* Send a packet or wait for data to be available
|
||||
*/
|
||||
public void send() {
|
||||
synchronized(outStream.data){
|
||||
if (outStream.writePosition > 0)
|
||||
outStream.packetizeData();
|
||||
public void sendData() {
|
||||
TalkOutputStream o = (TalkOutputStream) outStream;
|
||||
synchronized(o.data){
|
||||
if (o.writePosition > 0)
|
||||
o.packetizeData();
|
||||
else {
|
||||
outStream.data.notify();
|
||||
outStream.packetizeData();
|
||||
o.data.notify();
|
||||
o.packetizeData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UsbRequest writeRequest = null;
|
||||
boolean WriteToDevice(ByteBuffer DataToSend) {
|
||||
if (DEBUG) Log.d(TAG, "Writing to device()");
|
||||
|
||||
//The report must be formatted correctly for the device being connected to. On some devices, this requires that a specific value must be the first byte in the report. This can be followed by the length of the data in the report. This format is determined by the device, and isn't specified here.
|
||||
|
||||
@ -708,4 +701,5 @@ public class HidUAVTalk {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -81,6 +81,7 @@ public class OPTelemetryService extends Service {
|
||||
private boolean terminate = false;
|
||||
|
||||
private Thread activeTelem;
|
||||
private TelemetryTask telemTask;
|
||||
|
||||
private final IBinder mBinder = new LocalBinder();
|
||||
|
||||
@ -130,11 +131,13 @@ public class OPTelemetryService extends Service {
|
||||
break;
|
||||
case 3:
|
||||
Toast.makeText(getApplicationContext(), "Attempting TCP connection", Toast.LENGTH_SHORT).show();
|
||||
activeTelem = new TcpTelemetryThread();
|
||||
telemTask = new TcpUAVTalk(this);
|
||||
activeTelem = new Thread(telemTask);
|
||||
break;
|
||||
case 4:
|
||||
Toast.makeText(getApplicationContext(), "Attempting USB HID connection", Toast.LENGTH_SHORT).show();
|
||||
activeTelem = new HidTelemetryThread();
|
||||
telemTask = new HidUAVTalk(this);
|
||||
activeTelem = new Thread(telemTask);
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unsupported");
|
||||
@ -143,8 +146,19 @@ public class OPTelemetryService extends Service {
|
||||
break;
|
||||
case MSG_DISCONNECT:
|
||||
Toast.makeText(getApplicationContext(), "Disconnect requested", Toast.LENGTH_SHORT).show();
|
||||
if (DEBUG) Log.d(TAG, "Calling disconnect");
|
||||
terminate = true;
|
||||
if (activeTelem != null) {
|
||||
if (telemTask != null) {
|
||||
telemTask.disconnect();
|
||||
telemTask = null;
|
||||
|
||||
try {
|
||||
activeTelem.join();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
else if (activeTelem != null) {
|
||||
activeTelem.interrupt();
|
||||
try {
|
||||
activeTelem.join();
|
||||
@ -153,6 +167,7 @@ public class OPTelemetryService extends Service {
|
||||
}
|
||||
activeTelem = null;
|
||||
}
|
||||
if (DEBUG) Log.d(TAG, "Telemetry thread terminated");
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(INTENT_ACTION_DISCONNECTED);
|
||||
sendBroadcast(intent,null);
|
||||
@ -215,12 +230,25 @@ public class OPTelemetryService extends Service {
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
|
||||
if (telemTask != null) {
|
||||
Log.d(TAG, "onDestory() shutting down telemetry task");
|
||||
telemTask.disconnect();
|
||||
telemTask = null;
|
||||
|
||||
try {
|
||||
activeTelem.join();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
Log.d(TAG, "onDestory() shut down telemetry task");
|
||||
Toast.makeText(this, "Telemetry service done", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
public class LocalBinder extends Binder {
|
||||
public TelemTask getTelemTask(int id) {
|
||||
return (TelemTask) activeTelem;
|
||||
return telemTask.getTelemTaskIface();
|
||||
}
|
||||
public void openConnection() {
|
||||
Toast.makeText(getApplicationContext(), "Requested open connection", Toast.LENGTH_SHORT).show();
|
||||
@ -395,225 +423,4 @@ public class OPTelemetryService extends Service {
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private class TcpTelemetryThread extends Thread implements TelemTask {
|
||||
|
||||
private final UAVObjectManager objMngr;
|
||||
private UAVTalk uavTalk;
|
||||
private Telemetry tel;
|
||||
private TelemetryMonitor mon;
|
||||
|
||||
@Override
|
||||
public UAVObjectManager getObjectManager() { return objMngr; };
|
||||
|
||||
TcpTelemetryThread() {
|
||||
objMngr = new UAVObjectManager();
|
||||
UAVObjectsInitialize.register(objMngr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (DEBUG) Log.d(TAG, "Telemetry Thread started");
|
||||
|
||||
Looper.prepare();
|
||||
|
||||
TcpUAVTalk tcp = new TcpUAVTalk(OPTelemetryService.this);
|
||||
for( int i = 0; i < 10; i++ ) {
|
||||
if (DEBUG) Log.d(TAG, "Attempting network Connection");
|
||||
|
||||
tcp.connect(objMngr);
|
||||
|
||||
if( tcp.getConnected() )
|
||||
|
||||
break;
|
||||
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
Log.e(TAG, "Thread interrupted while trying to connect");
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if( ! tcp.getConnected() || terminate ) {
|
||||
toastMessage("TCP connection failed");
|
||||
return;
|
||||
}
|
||||
toastMessage("TCP Connected");
|
||||
|
||||
if (DEBUG) Log.d(TAG, "Connected via network");
|
||||
|
||||
uavTalk = tcp.getUavtalk();
|
||||
tel = new Telemetry(uavTalk, objMngr);
|
||||
mon = new TelemetryMonitor(objMngr,tel);
|
||||
mon.addObserver(new Observer() {
|
||||
@Override
|
||||
public void update(Observable arg0, Object arg1) {
|
||||
if (DEBUG) Log.d(TAG, "Mon updated. Connected: " + mon.getConnected() + " objects updated: " + mon.getObjectsUpdated());
|
||||
if(mon.getConnected()) {
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(INTENT_ACTION_CONNECTED);
|
||||
sendBroadcast(intent,null);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if (DEBUG) Log.d(TAG, "Entering UAVTalk processing loop");
|
||||
while( !terminate ) {
|
||||
try {
|
||||
if( !uavTalk.processInputStream() )
|
||||
break;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
toastMessage("TCP Stream interrupted");
|
||||
break;
|
||||
}
|
||||
}
|
||||
Looper.myLooper().quit();
|
||||
|
||||
// Shut down all the attached
|
||||
mon.stopMonitor();
|
||||
mon = null;
|
||||
tel.stopTelemetry();
|
||||
tel = null;
|
||||
|
||||
// Finally close the stream if it is still open
|
||||
tcp.disconnect();
|
||||
|
||||
if (DEBUG) Log.d(TAG, "UAVTalk stream disconnected");
|
||||
toastMessage("TCP Thread finished");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private class HidTelemetryThread extends Thread implements TelemTask {
|
||||
|
||||
private final UAVObjectManager objMngr;
|
||||
private UAVTalk uavTalk;
|
||||
private Telemetry tel;
|
||||
private TelemetryMonitor mon;
|
||||
|
||||
@Override
|
||||
public UAVObjectManager getObjectManager() { return objMngr; };
|
||||
|
||||
HidTelemetryThread() {
|
||||
objMngr = new UAVObjectManager();
|
||||
UAVObjectsInitialize.register(objMngr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (DEBUG) Log.d(TAG, "HID Telemetry Thread started");
|
||||
|
||||
Looper.prepare();
|
||||
|
||||
final HidUAVTalk hid = new HidUAVTalk(OPTelemetryService.this);
|
||||
hid.connect(objMngr);
|
||||
|
||||
try {
|
||||
Thread.sleep(200);
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if( !hid.getConnected() ) {
|
||||
toastMessage("HID connection failed");
|
||||
return;
|
||||
}
|
||||
|
||||
uavTalk = hid.getUavtalk();
|
||||
tel = new Telemetry(uavTalk, objMngr);
|
||||
mon = new TelemetryMonitor(objMngr,tel);
|
||||
mon.addObserver(new Observer() {
|
||||
@Override
|
||||
public void update(Observable arg0, Object arg1) {
|
||||
if (DEBUG) Log.d(TAG, "Mon updated. Connected: " + mon.getConnected() + " objects updated: " + mon.getObjectsUpdated());
|
||||
if(mon.getConnected()) {
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(INTENT_ACTION_CONNECTED);
|
||||
sendBroadcast(intent,null);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Read data from HID and push it ont the UAVTalk input stream
|
||||
Thread t = new Thread(this) {
|
||||
@Override
|
||||
public void run() {
|
||||
while(!terminate) {
|
||||
hid.readData();
|
||||
hid.send();
|
||||
}
|
||||
Log.e(TAG, "TERMINATED");
|
||||
}
|
||||
};
|
||||
t.start();
|
||||
|
||||
// Read data from HID and push it ont the UAVTalk input stream
|
||||
Thread t2 = new Thread(this) {
|
||||
@Override
|
||||
public void run() {
|
||||
while(!terminate) {
|
||||
hid.send();
|
||||
try {
|
||||
sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
//t2.start();
|
||||
|
||||
// Process any bytes that have been pushed onto the UAVTalk stream
|
||||
if (DEBUG) Log.d(TAG, "Entering UAVTalk processing loop");
|
||||
while( !terminate ) {
|
||||
try {
|
||||
if( !uavTalk.processInputStream() )
|
||||
break;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
toastMessage("TCP Stream interrupted");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (InterruptedException e1) {
|
||||
// TODO Auto-generated catch block
|
||||
e1.printStackTrace();
|
||||
}
|
||||
|
||||
Looper.myLooper().quit();
|
||||
|
||||
// Stop the HID reading loop
|
||||
t.interrupt();
|
||||
try {
|
||||
t.join();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
|
||||
hid.disconnect();
|
||||
|
||||
// Shut down all the attached
|
||||
mon.stopMonitor();
|
||||
mon = null;
|
||||
tel.stopTelemetry();
|
||||
tel = null;
|
||||
|
||||
// Finally close the stream if it is still open
|
||||
hid.disconnect();
|
||||
|
||||
if (DEBUG) Log.d(TAG, "UAVTalk stream disconnected");
|
||||
toastMessage("TCP Thread finished");
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
@ -28,15 +28,11 @@ import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import org.openpilot.uavtalk.UAVObjectManager;
|
||||
import org.openpilot.uavtalk.UAVTalk;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
|
||||
public class TcpUAVTalk {
|
||||
public class TcpUAVTalk extends TelemetryTask {
|
||||
private final String TAG = "TcpUAVTalk";
|
||||
public static int LOGLEVEL = 2;
|
||||
public static boolean WARN = LOGLEVEL > 1;
|
||||
@ -46,16 +42,23 @@ public class TcpUAVTalk {
|
||||
private String ip_address = "1";
|
||||
private int port = 9001;
|
||||
|
||||
private UAVTalk uavTalk;
|
||||
private boolean connected;
|
||||
private Socket socket;
|
||||
|
||||
/**
|
||||
* Construct a TcpUAVTalk object attached to the OPTelemetryService. Gets the
|
||||
* connection settings from the preferences.
|
||||
*/
|
||||
public TcpUAVTalk(Context caller) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(caller);
|
||||
public TcpUAVTalk(OPTelemetryService caller) {
|
||||
super(caller);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean attemptConnection() {
|
||||
|
||||
if( getConnected() )
|
||||
return true;
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(telemService);
|
||||
ip_address = prefs.getString("ip_address","127.0.0.1");
|
||||
try {
|
||||
port = Integer.decode(prefs.getString("port", ""));
|
||||
@ -65,44 +68,6 @@ public class TcpUAVTalk {
|
||||
|
||||
if (DEBUG) Log.d(TAG, "Trying to open UAVTalk with " + ip_address);
|
||||
|
||||
connected = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect a TCP object to an object manager. Returns true if already
|
||||
* connected, otherwise returns true if managed a successful socket.
|
||||
*/
|
||||
public boolean connect(UAVObjectManager objMngr) {
|
||||
if( getConnected() )
|
||||
return true;
|
||||
if( !openTelemetryTcp(objMngr) )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void disconnect() {
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
socket = null;
|
||||
}
|
||||
|
||||
public boolean getConnected() {
|
||||
return connected;
|
||||
}
|
||||
|
||||
public UAVTalk getUavtalk() {
|
||||
return uavTalk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a TCP socket to the address determined on construction. If successful
|
||||
* creates a UAVTalk stream connection this socket to the passed in object manager
|
||||
*/
|
||||
private boolean openTelemetryTcp(UAVObjectManager objMngr) {
|
||||
Log.d(TAG, "Opening connection to " + ip_address + " at address " + port);
|
||||
|
||||
InetAddress serverAddr = null;
|
||||
@ -121,18 +86,43 @@ public class TcpUAVTalk {
|
||||
return false;
|
||||
}
|
||||
|
||||
connected = true;
|
||||
|
||||
try {
|
||||
uavTalk = new UAVTalk(socket.getInputStream(), socket.getOutputStream(), objMngr);
|
||||
inStream = socket.getInputStream();
|
||||
outStream = socket.getOutputStream();
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG,"Error starting UAVTalk");
|
||||
// TODO Auto-generated catch block
|
||||
//e.printStackTrace();
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException e2) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Post message to call attempt succeeded on the parent class
|
||||
handler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
TcpUAVTalk.this.attemptSucceeded();
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void disconnect() {
|
||||
super.disconnect();
|
||||
if (socket != null) {
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
socket = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,235 @@
|
||||
package org.openpilot.androidgcs.telemetry;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
|
||||
import org.openpilot.uavtalk.Telemetry;
|
||||
import org.openpilot.uavtalk.TelemetryMonitor;
|
||||
import org.openpilot.uavtalk.UAVObjectManager;
|
||||
import org.openpilot.uavtalk.UAVTalk;
|
||||
import org.openpilot.uavtalk.uavobjects.UAVObjectsInitialize;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
|
||||
public abstract class TelemetryTask implements Runnable {
|
||||
|
||||
// Logging settings
|
||||
private final String TAG = TelemetryTask.class.getSimpleName();
|
||||
public static final int LOGLEVEL = 2;
|
||||
public static final boolean WARN = LOGLEVEL > 1;
|
||||
public static final boolean DEBUG = LOGLEVEL > 0;
|
||||
|
||||
/*
|
||||
* This is a self contained runnable that will establish (if possible)
|
||||
* a telemetry connection and provides a listener interface to be
|
||||
* notified of a set of events
|
||||
*
|
||||
* 1. attempt to establish connection
|
||||
* 2. callback when it succeeds (or fails) which notifies listener
|
||||
* 3. once physical connection is established instantiate uavtalk / objectmanager
|
||||
* 4. notify listener they are connected
|
||||
* 5. detect physical link failure and notify listener about that
|
||||
* 6. provide "close link" method
|
||||
*
|
||||
* There are essentially four tasks that need to occur here
|
||||
* 1. Transfer data from the outputStream to the physical link (some protocols do this automatically)
|
||||
* 2. Transfer data from the physical link to the inputStream (again some protocols do this automatically)
|
||||
* 3. Transfer data from the inputStream to UAVTalk (uavTalk.processInputByte)
|
||||
* 4. Transfer data from objects via UAVTalk to output stream (occurs from Telemetry object)
|
||||
*/
|
||||
|
||||
//! Private variables
|
||||
protected Handler handler;
|
||||
|
||||
//! Handle to the parent service
|
||||
protected final OPTelemetryService telemService;
|
||||
|
||||
//! The object manager that will be used for this telemetry task
|
||||
protected UAVObjectManager objMngr;
|
||||
|
||||
//! The UAVTalk connected to the below streams
|
||||
private UAVTalk uavTalk;
|
||||
|
||||
//! The input stream for the telemetry channel
|
||||
protected InputStream inStream;
|
||||
|
||||
//! The output stream for the telemetry channel
|
||||
protected OutputStream outStream;
|
||||
|
||||
//! The telemetry object which takes care of higher level transactions
|
||||
private Telemetry tel;
|
||||
|
||||
//! The telemetry monitor which takes care of high level connects / disconnects
|
||||
private TelemetryMonitor mon;
|
||||
|
||||
//! Flag to indicate a shut down was requested. Derived classes should take care to respect this.
|
||||
boolean shutdown;
|
||||
|
||||
//! Indicate a physical connection is established
|
||||
private boolean connected;
|
||||
|
||||
TelemetryTask(OPTelemetryService s) {
|
||||
telemService = s;
|
||||
shutdown = false;
|
||||
connected = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt a connection. This method may return before the results are
|
||||
* known.
|
||||
* @return False if the attempt failed and no connection will be established
|
||||
* @return True if the attempt succeeded but does not guarantee success
|
||||
*/
|
||||
abstract boolean attemptConnection();
|
||||
|
||||
/**
|
||||
* Called when a physical channel is opened
|
||||
*
|
||||
* When this method is called the derived class must have
|
||||
* created a valid inStream and outStream
|
||||
*/
|
||||
boolean attemptSucceeded() {
|
||||
// Create a new object manager and register all objects
|
||||
// in the future the particular register method should
|
||||
// be dependent on what is connected (e.g. board and
|
||||
// version number).
|
||||
objMngr = new UAVObjectManager();
|
||||
UAVObjectsInitialize.register(objMngr);
|
||||
|
||||
// Create the required telemetry objects attached to this
|
||||
// data stream
|
||||
uavTalk = new UAVTalk(inStream, outStream, objMngr);
|
||||
tel = new Telemetry(uavTalk, objMngr);
|
||||
mon = new TelemetryMonitor(objMngr,tel);
|
||||
|
||||
// Create an observer to notify system of connection
|
||||
mon.addObserver(connectionObserver);
|
||||
|
||||
// Create a new thread that processes the input bytes
|
||||
startInputProcessing();
|
||||
|
||||
connected = true;
|
||||
return connected;
|
||||
}
|
||||
|
||||
boolean attemptedFailed() {
|
||||
connected = false;
|
||||
return connected;
|
||||
}
|
||||
|
||||
void disconnect() {
|
||||
// Make the default input procesing loop stop
|
||||
shutdown = true;
|
||||
|
||||
// Shut down all the attached
|
||||
if (mon != null) {
|
||||
mon.stopMonitor();
|
||||
mon.deleteObserver(connectionObserver);
|
||||
mon = null;
|
||||
}
|
||||
if (tel != null) {
|
||||
tel.stopTelemetry();
|
||||
tel = null;
|
||||
}
|
||||
|
||||
// Stop the master telemetry thread
|
||||
handler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Looper.myLooper().quit();
|
||||
}
|
||||
});
|
||||
|
||||
// TODO: Make sure the input and output stream is closed
|
||||
|
||||
// TODO: Make sure any threads for input and output are closed
|
||||
}
|
||||
|
||||
/**
|
||||
* Default implementation for processing input stream
|
||||
* which creates a new thread that keeps attempting
|
||||
* to read from the input stream.
|
||||
*/
|
||||
private void startInputProcessing() {
|
||||
new Thread(new processUavTalk()).start();
|
||||
}
|
||||
|
||||
//! Runnable to process input stream
|
||||
class processUavTalk implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
if (DEBUG) Log.d(TAG, "Entering UAVTalk processing loop");
|
||||
while (!shutdown) {
|
||||
try {
|
||||
if( !uavTalk.processInputStream() )
|
||||
break;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
telemService.toastMessage("Telemetry input stream interrupted");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (DEBUG) Log.d(TAG, "UAVTalk processing loop finished");
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
|
||||
Looper.prepare();
|
||||
handler = new Handler();
|
||||
|
||||
if (DEBUG) Log.d(TAG, "Attempting connection");
|
||||
if( attemptConnection() == false )
|
||||
return; // Attempt failed
|
||||
|
||||
Looper.loop();
|
||||
|
||||
if (DEBUG) Log.d(TAG, "TelemetryTask runnable finished");
|
||||
|
||||
} catch (Throwable t) {
|
||||
Log.e(TAG, "halted due to an error", t);
|
||||
}
|
||||
|
||||
telemService.toastMessage("Telemetry Thread finished");
|
||||
}
|
||||
|
||||
private final Observer connectionObserver = new Observer() {
|
||||
@Override
|
||||
public void update(Observable arg0, Object arg1) {
|
||||
if (DEBUG) Log.d(TAG, "Mon updated. Connected: " + mon.getConnected() + " objects updated: " + mon.getObjectsUpdated());
|
||||
if(mon.getConnected()) {
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(OPTelemetryService.INTENT_ACTION_CONNECTED);
|
||||
telemService.sendBroadcast(intent,null);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**** General accessors ****/
|
||||
|
||||
public boolean getConnected() {
|
||||
return connected;
|
||||
}
|
||||
|
||||
public UAVTalk getUavtalk() {
|
||||
return uavTalk;
|
||||
}
|
||||
|
||||
public OPTelemetryService.TelemTask getTelemTaskIface() {
|
||||
return new OPTelemetryService.TelemTask() {
|
||||
@Override
|
||||
public UAVObjectManager getObjectManager() {
|
||||
return objMngr;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user