diff --git a/android.pri b/android.pri
index 8179a76f155b1cb3b9b46c595f8e2001a4309fb6..f655709bc50e8b137bf808938fba18a5bc075f6c 100644
--- a/android.pri
+++ b/android.pri
@@ -15,7 +15,8 @@ OTHER_FILES += \
$$PWD/android/src/com/hoho/android/usbserial/driver/UsbSerialProber.java \
$$PWD/android/src/com/hoho/android/usbserial/driver/UsbSerialRuntimeException.java \
$$PWD/android/src/org/mavlink/qgroundcontrol/QGCActivity.java \
- $$PWD/android/src/org/mavlink/qgroundcontrol/UsbIoManager.java
+ $$PWD/android/src/org/mavlink/qgroundcontrol/UsbIoManager.java \
+ $$PWD/android/src/org/mavlink/qgroundcontrol/TaiSync.java
DISTFILES += \
$$PWD/android/gradle/wrapper/gradle-wrapper.jar \
diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml
index 7143aa2a4970df8292496c271219ff246bef8988..beddd03b6cc1420a604282d0812968789c0eb244 100644
--- a/android/AndroidManifest.xml
+++ b/android/AndroidManifest.xml
@@ -7,10 +7,12 @@
+
+
@@ -60,13 +62,14 @@
-
-
+
+
-
+
-
-
+
+
+
diff --git a/android/res/xml/device_filter.xml b/android/res/xml/device_filter.xml
index 782fae8dd7e17709718b824ace9fa92e9479b52b..31474575daf185cb8eafd71bbd15022deb3c27d0 100644
--- a/android/res/xml/device_filter.xml
+++ b/android/res/xml/device_filter.xml
@@ -2,5 +2,6 @@
+
diff --git a/android/src/org/mavlink/qgroundcontrol/QGCActivity.java b/android/src/org/mavlink/qgroundcontrol/QGCActivity.java
index 2f99cd20607072c7d5c4202b93ea7656a0b67e22..756597b29dc0b521e7047f5021e3bd72489bf894 100644
--- a/android/src/org/mavlink/qgroundcontrol/QGCActivity.java
+++ b/android/src/org/mavlink/qgroundcontrol/QGCActivity.java
@@ -29,10 +29,13 @@ package org.mavlink.qgroundcontrol;
//
////////////////////////////////////////////////////////////////////////////////////////////
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.Timer;
+import java.util.TimerTask;
import java.io.IOException;
import android.app.Activity;
@@ -40,12 +43,16 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.hardware.usb.*;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbDeviceConnection;
+import android.hardware.usb.UsbManager;
import android.widget.Toast;
import android.util.Log;
import android.os.PowerManager;
-import android.view.WindowManager;
import android.os.Bundle;
+import android.app.PendingIntent;
+import android.view.WindowManager;
import com.hoho.android.usbserial.driver.*;
import org.qtproject.qt5.android.bindings.QtActivity;
@@ -65,6 +72,8 @@ public class QGCActivity extends QtActivity
private final static ExecutorService m_Executor = Executors.newSingleThreadExecutor();
private static final String TAG = "QGC_QGCActivity";
private static PowerManager.WakeLock m_wl;
+ private static String USB_ACTION = "org.mavlink.qgroundcontrol.action.USB_PERMISSION";
+ private TaiSync taiSync = null;
public static Context m_context;
@@ -85,6 +94,26 @@ public class QGCActivity extends QtActivity
}
};
+ private final BroadcastReceiver mOpenAccessoryReceiver =
+ new BroadcastReceiver()
+ {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (USB_ACTION.equals(action)) {
+ UsbAccessory accessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+ if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
+ openAccessory(accessory);
+ }
+ } else if( UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
+ UsbAccessory accessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+ if (accessory != null) {
+ closeAccessory(accessory);
+ }
+ }
+ }
+ };
+
// NATIVE C++ FUNCTION THAT WILL BE CALLED IF THE DEVICE IS UNPLUGGED
private static native void nativeDeviceHasDisconnected(int userDataA);
private static native void nativeDeviceException(int userDataA, String messageA);
@@ -120,10 +149,27 @@ public class QGCActivity extends QtActivity
Log.i(TAG, "SCREEN_BRIGHT_WAKE_LOCK not acquired!!!");
}
m_instance.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
+ if (m_manager == null) {
+ try {
+ m_manager = (UsbManager)m_instance.getSystemService(Context.USB_SERVICE);
+ taiSync = new TaiSync();
+
+ IntentFilter filter = new IntentFilter(USB_ACTION);
+ filter.addAction( UsbManager.ACTION_USB_ACCESSORY_DETACHED);
+ registerReceiver(mOpenAccessoryReceiver, filter);
+
+ probeAccessories();
+ } catch(Exception e) {
+ Log.e(TAG, "Exception getCurrentDevices(): " + e);
+ }
+ }
}
@Override
- protected void onDestroy() {
+ protected void onDestroy()
+ {
+ unregisterReceiver(mOpenAccessoryReceiver);
try {
if(m_wl != null) {
m_wl.release();
@@ -149,9 +195,6 @@ public class QGCActivity extends QtActivity
if (m_instance == null)
return false;
- if (m_manager == null)
- m_manager = (UsbManager)m_instance.getSystemService(Context.USB_SERVICE);
-
if (m_devices != null)
m_devices.clear();
@@ -193,7 +236,7 @@ public class QGCActivity extends QtActivity
int countL = 0;
int iL;
- // CHECK FOR ALREADY OPENED DEVICES AND DON"T INCLUDE THEM IN THE COUNT
+ // CHECK FOR ALREADY OPENED DEVICES AND DON'T INCLUDE THEM IN THE COUNT
for (iL=0; iL= 0) {
+ synchronized (this)
+ {
+ if (!running) {
+ break;
+ }
+ }
+
+ bytesRead = mFileInputStream.read(mBytes);
+
+ if (bytesRead > 0)
+ {
+ if (mBytes[3] == PROTOCOL_VERSION)
+ {
+ vMaj = mBytes[19];
+ Log.i("QGC_TaiSync", "Got protocol version message vMaj = " + mBytes[19]);
+ byte[] data = { 0x00, 0x00, 0x00, 0x01, // uint32 - protocol
+ 0x00, 0x00, 0x00, 0x00, // uint32 - dport
+ 0x00, 0x00, 0x00, 0x1C, // uint32 - length
+ 0x00, 0x00, 0x00, 0x00, // uint32 - magic
+ 0x00, 0x00, 0x00, vMaj, // uint32 - version major
+ 0x00, 0x00, 0x00, 0x00, // uint32 - version minor
+ 0x00, 0x00, 0x00, 0x00 }; // uint32 - padding
+ mFileOutputStream.write(data);
+ }
+ else if (mBytes[3] == PROTOCOL_CHANNEL) {
+ int dPort = ((mBytes[4] & 0xff)<< 24) | ((mBytes[5]&0xff) << 16) | ((mBytes[6]&0xff) << 8) | (mBytes[7] &0xff);
+ int dLength = ((mBytes[8] & 0xff)<< 24) | ((mBytes[9]&0xff) << 16) | ((mBytes[10]&0xff) << 8) | (mBytes[11] &0xff);
+ Log.i("QGC_TaiSync", "Read 2 port = " + dPort + " length = " + dLength);
+ byte[] data = { 0x00, 0x00, 0x00, 0x02, // uint32 - protocol
+ 0x00, 0x00, mBytes[6], mBytes[7], // uint32 - dport
+ 0x00, 0x00, 0x00, 0x1C, // uint32 - length
+ 0x00, 0x00, 0x00, 0x00, // uint32 - magic
+ 0x00, 0x00, 0x00, vMaj, // uint32 - version major
+ 0x00, 0x00, 0x00, 0x00, // uint32 - version minor
+ 0x00, 0x00, 0x00, 0x00 }; // uint32 - padding
+ mFileOutputStream.write(data);
+ }
+ else if (mBytes[3] == PROTOCOL_DATA) {
+ int dPort = ((mBytes[4] & 0xff)<< 24) | ((mBytes[5]&0xff) << 16) | ((mBytes[6]&0xff) << 8) | (mBytes[7] &0xff);
+ int dLength = ((mBytes[8] & 0xff)<< 24) | ((mBytes[9]&0xff) << 16) | ((mBytes[10]&0xff) << 8) | (mBytes[11] &0xff);
+
+ int payloadOffset = 28;
+ int payloadLength = bytesRead - payloadOffset;
+
+ if (dPort == 8000) { // Video
+ byte[] sBytes = new byte[payloadLength];
+ System.arraycopy(mBytes, payloadOffset, sBytes, 0, payloadLength);
+ DatagramPacket packet = new DatagramPacket(sBytes, sBytes.length, address, VIDEO_PORT);
+ socket.send(packet);
+
+ } else if (dPort == 8200) { // Command
+/*
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < dLength; i++) {
+ sb.append(String.format("%02X ", mBytes[i]));
+ }
+ Log.i("QGC_TaiSync", "Read 3 port = " + dPort + " length = " + dLength + " - " + sb.toString());
+*/
+ } else if (dPort == 8400) { // Telemetry
+ byte[] sBytes = new byte[payloadLength];
+ System.arraycopy(mBytes, payloadOffset, sBytes, 0, payloadLength);
+ DatagramPacket packet = new DatagramPacket(sBytes, sBytes.length, address, TELEM_PORT);
+ socket.send(packet);
+ }
+ }
+ }
+ }
+ } catch (IOException e) {
+ Log.e("QGC_TaiSync", "Exception: " + e);
+ e.printStackTrace();
+ } finally {
+ close();
+ }
+ }
+ });
+
+ mThreadPool.execute(new Runnable() {
+ @Override
+ public void run()
+ {
+ byte[] inbuf = new byte[256];
+
+ try {
+ while (true) {
+ synchronized (this)
+ {
+ if (!running) {
+ break;
+ }
+ }
+
+ DatagramPacket packet = new DatagramPacket(inbuf, inbuf.length);
+ socket.receive(packet);
+
+ int dataPort = 8400;
+ byte portMSB = (byte)((dataPort >> 8) & 0xFF);
+ byte portLSB = (byte)(dataPort & 0xFF);
+
+ byte[] lA = new byte[4];
+ int len = 28 + packet.getLength();
+ byte[] buffer = new byte[len];
+
+ for (int i = 3; i >= 0; i--) {
+ lA[i] = (byte)(len & 0xFF);
+ len >>= 8;
+ }
+
+ byte[] header = { 0x00, 0x00, 0x00, PROTOCOL_DATA, // uint32 - protocol
+ 0x00, 0x00, portMSB, portLSB, // uint32 - dport
+ lA[0], lA[1], lA[2], lA[3], // uint32 - length
+ 0x00, 0x00, 0x00, 0x00, // uint32 - magic
+ 0x00, 0x00, 0x00, vMaj, // uint32 - version major
+ 0x00, 0x00, 0x00, 0x00, // uint32 - version minor
+ 0x00, 0x00, 0x00, 0x00 }; // uint32 - padding
+
+ System.arraycopy(header, 0, buffer, 0, header.length);
+ System.arraycopy(packet.getData(), 0, buffer, header.length, packet.getLength());
+ mFileOutputStream.write(buffer);
+ }
+ } catch (IOException e) {
+ Log.e("QGC_TaiSync", "Exception: " + e);
+ e.printStackTrace();
+ } finally {
+ close();
+ }
+ }
+ });
+ }
+
+ public void close()
+ {
+// Log.i("QGC_TaiSync", "Close");
+ synchronized (this)
+ {
+ running = false;
+ }
+ try {
+ if (socket != null) {
+ socket.close();
+ socket = null;
+ }
+ if (mParcelFileDescriptor != null) {
+ mParcelFileDescriptor.close();
+ mParcelFileDescriptor = null;
+ }
+ } catch (Exception e) {
+ }
+ socket = null;
+ }
+}