package org.mavlink.qgroundcontrol; /* Copyright 2013 Google Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. * * Project home page: http://code.google.com/p/usb-serial-for-android/ */ /////////////////////////////////////////////////////////////////////////////////////////// // Written by: Mike Goza April 2014 // // These routines interface with the Android USB Host devices for serial port communication. // The code uses the usb-serial-for-android software library. The QGCActivity class is the // interface to the C++ routines through jni calls. Do not change the functions without also // changing the corresponding calls in the C++ routines or you will break the interface. // //////////////////////////////////////////////////////////////////////////////////////////// import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.ArrayList; 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; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; 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.os.Bundle; import android.app.PendingIntent; import android.view.WindowManager; import com.hoho.android.usbserial.driver.*; import org.qtproject.qt5.android.bindings.QtActivity; import org.qtproject.qt5.android.bindings.QtApplication; public class QGCActivity extends QtActivity { public static int BAD_DEVICE_ID = 0; private static QGCActivity _instance = null; private static UsbManager _usbManager = null; private static List _drivers; private static HashMap m_ioManager; private static HashMap _userDataHashByDeviceId; private static final String TAG = "QGC_QGCActivity"; private static PowerManager.WakeLock _wakeLock; // private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION"; private static final String ACTION_USB_PERMISSION = "org.mavlink.qgroundcontrol.action.USB_PERMISSION"; private static PendingIntent _usbPermissionIntent = null; private TaiSync taiSync = null; public static Context m_context; private final static ExecutorService m_Executor = Executors.newSingleThreadExecutor(); private final static UsbIoManager.Listener m_Listener = new UsbIoManager.Listener() { @Override public void onRunError(Exception eA, int userData) { Log.e(TAG, "onRunError Exception"); nativeDeviceException(userData, eA.getMessage()); } @Override public void onNewData(final byte[] dataA, int userData) { nativeDeviceNewData(userData, dataA); } }; private final BroadcastReceiver mOpenAccessoryReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (ACTION_USB_PERMISSION.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); } } } }; private static UsbSerialDriver _findDriverByDeviceId(int deviceId) { for (UsbSerialDriver driver: _drivers) { if (driver.getDevice().getDeviceId() == deviceId) { return driver; } } return null; } private static UsbSerialDriver _findDriverByDeviceName(String deviceName) { for (UsbSerialDriver driver: _drivers) { if (driver.getDevice().getDeviceName().equals(deviceName)) { return driver; } } return null; } private final static BroadcastReceiver _usbReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); Log.i(TAG, "BroadcastReceiver USB action " + action); if (ACTION_USB_PERMISSION.equals(action)) { synchronized (_instance) { UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); if (device != null) { UsbSerialDriver driver = _findDriverByDeviceId(device.getDeviceId()); if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { qgcLogDebug("Permission granted to " + device.getDeviceName()); driver.setPermissionStatus(UsbSerialDriver.permissionStatusSuccess); } else { qgcLogDebug("Permission denied for " + device.getDeviceName()); driver.setPermissionStatus(UsbSerialDriver.permissionStatusDenied); } } } } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) { UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); if (device != null) { if (_userDataHashByDeviceId.containsKey(device.getDeviceId())) { nativeDeviceHasDisconnected(_userDataHashByDeviceId.get(device.getDeviceId())); } } } } }; // Native C++ functions which connect back to QSerialPort code private static native void nativeDeviceHasDisconnected(int userData); private static native void nativeDeviceException(int userData, String messageA); private static native void nativeDeviceNewData(int userData, byte[] dataA); // Native C++ functions called to log output public static native void qgcLogDebug(String message); public static native void qgcLogWarning(String message); // QGCActivity singleton public QGCActivity() { _instance = this; _drivers = new ArrayList(); _userDataHashByDeviceId = new HashMap(); m_ioManager = new HashMap(); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); PowerManager pm = (PowerManager)_instance.getSystemService(Context.POWER_SERVICE); _wakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "QGroundControl"); if(_wakeLock != null) { _wakeLock.acquire(); } else { Log.i(TAG, "SCREEN_BRIGHT_WAKE_LOCK not acquired!!!"); } _instance.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); _usbManager = (UsbManager)_instance.getSystemService(Context.USB_SERVICE); // Register for USB Detach and USB Permission intent IntentFilter filter = new IntentFilter(); filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); filter.addAction(ACTION_USB_PERMISSION); _instance.registerReceiver(_instance._usbReceiver, filter); // Create intent for usb permission request _usbPermissionIntent = PendingIntent.getBroadcast(_instance, 0, new Intent(ACTION_USB_PERMISSION), 0); try { taiSync = new TaiSync(); IntentFilter accessoryFilter = new IntentFilter(ACTION_USB_PERMISSION); filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED); registerReceiver(mOpenAccessoryReceiver, accessoryFilter); probeAccessories(); } catch(Exception e) { Log.e(TAG, "Exception: " + e); } } @Override protected void onDestroy() { unregisterReceiver(mOpenAccessoryReceiver); try { if(_wakeLock != null) { _wakeLock.release(); } } catch(Exception e) { Log.e(TAG, "Exception onDestroy()"); } super.onDestroy(); } public void onInit(int status) { } /// Incrementally updates the list of drivers connected to the device private static void updateCurrentDrivers() { List currentDrivers = UsbSerialProber.findAllDevices(_usbManager); // Remove stale drivers for (int i=_drivers.size()-1; i>=0; i--) { boolean found = false; for (UsbSerialDriver currentDriver: currentDrivers) { if (_drivers.get(i).getDevice().getDeviceId() == currentDriver.getDevice().getDeviceId()) { found = true; break; } } if (!found) { qgcLogDebug("Remove stale driver " + _drivers.get(i).getDevice().getDeviceName()); _drivers.remove(i); } } // Add new drivers for (int i=0; i deviceInfoList = new ArrayList(); for (int i=0; i<_drivers.size(); i++) { String deviceInfo; UsbSerialDriver driver = _drivers.get(i); if (driver.permissionStatus() != UsbSerialDriver.permissionStatusSuccess) { continue; } UsbDevice device = driver.getDevice(); deviceInfo = device.getDeviceName() + ":"; if (driver instanceof FtdiSerialDriver) { deviceInfo = deviceInfo + "FTDI:"; } else if (driver instanceof CdcAcmSerialDriver) { deviceInfo = deviceInfo + "Cdc Acm:"; } else if (driver instanceof Cp2102SerialDriver) { deviceInfo = deviceInfo + "Cp2102:"; } else if (driver instanceof ProlificSerialDriver) { deviceInfo = deviceInfo + "Prolific:"; } else { deviceInfo = deviceInfo + "Unknown:"; } deviceInfo = deviceInfo + Integer.toString(device.getProductId()) + ":"; deviceInfo = deviceInfo + Integer.toString(device.getVendorId()) + ":"; deviceInfoList.add(deviceInfo); } String[] rgDeviceInfo = new String[deviceInfoList.size()]; for (int i=0; i