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.HashMap; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.io.IOException; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.hardware.usb.*; import android.widget.Toast; import android.util.Log; import android.os.PowerManager; import android.view.WindowManager; //-- Text To Speech import android.os.Bundle; import android.speech.tts.TextToSpeech; 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 implements TextToSpeech.OnInitListener { public static int BAD_PORT = 0; private static QGCActivity m_instance; private static UsbManager m_manager; // ANDROID USB HOST CLASS private static List m_devices; // LIST OF CURRENT DEVICES private static HashMap m_openedDevices; // LIST OF OPENED DEVICES private static HashMap m_ioManager; // THREADS FOR LISTENING FOR INCOMING DATA private static HashMap m_userData; // CORRESPONDING USER DATA FOR OPENED DEVICES. USED IN DISCONNECT CALLBACK // USED TO DETECT WHEN A DEVICE HAS BEEN UNPLUGGED private BroadcastReceiver m_UsbReceiver = null; private final static ExecutorService m_Executor = Executors.newSingleThreadExecutor(); private static final String TAG = "QGC_QGCActivity"; private static TextToSpeech m_tts; private static PowerManager.WakeLock m_wl; public static Context m_context; private final static UsbIoManager.Listener m_Listener = new UsbIoManager.Listener() { @Override public void onRunError(Exception eA, int userDataA) { Log.e(TAG, "onRunError Exception"); nativeDeviceException(userDataA, eA.getMessage()); } @Override public void onNewData(final byte[] dataA, int userDataA) { // IK: Log.d(TAG, "UsbIoManager.Listener.onNewData: read " + dataA.length + " bytes"); nativeDeviceNewData(userDataA, dataA); } }; // 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); private static native void nativeDeviceNewData(int userDataA, byte[] dataA); // Native C++ functions called to log output public static native void qgcLogDebug(String message); public static native void qgcLogWarning(String message); //////////////////////////////////////////////////////////////////////////////////////////////// // // Constructor. Only used once to create the initial instance for the static functions. // //////////////////////////////////////////////////////////////////////////////////////////////// public QGCActivity() { m_instance = this; m_openedDevices = new HashMap(); m_userData = new HashMap(); m_ioManager = new HashMap(); Log.i(TAG, "Instance created"); } ///////////////////////////////////////////////////////////////////////////////////////////////////////// // // Text To Speech // Pigback a ride for providing TTS to QGC // ///////////////////////////////////////////////////////////////////////////////////////////////////////// @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); m_tts = new TextToSpeech(this,this); PowerManager pm = (PowerManager)m_instance.getSystemService(Context.POWER_SERVICE); m_wl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "QGroundControl"); if(m_wl != null) { m_wl.acquire(); Log.i(TAG, "SCREEN_BRIGHT_WAKE_LOCK acquired."); } else { Log.i(TAG, "SCREEN_BRIGHT_WAKE_LOCK not acquired!!!"); } m_instance.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } @Override protected void onDestroy() { try { if(m_wl != null) { m_wl.release(); Log.i(TAG, "SCREEN_BRIGHT_WAKE_LOCK released."); } m_tts.shutdown(); } catch(Exception e) { Log.e(TAG, "Exception onDestroy()"); } super.onDestroy(); } public void onInit(int status) { } public static void say(String msg) { Log.i(TAG, "Say: " + msg); m_tts.speak(msg, TextToSpeech.QUEUE_FLUSH, null); } ///////////////////////////////////////////////////////////////////////////////////////////////////////// // // Find all current devices that match the device filter described in the androidmanifest.xml and the // device_filter.xml // ///////////////////////////////////////////////////////////////////////////////////////////////////////// private static boolean getCurrentDevices() { 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(); m_devices = UsbSerialProber.findAllDevices(m_manager); return true; } ///////////////////////////////////////////////////////////////////////////////////////////////////////// // // List all available devices that are not already open. It returns the serial port info // in a : separated string array. Each string entry consists of the following: // // DeviceName:Company:ProductId:VendorId // ///////////////////////////////////////////////////////////////////////////////////////////////////////// public static String[] availableDevicesInfo() { // GET THE LIST OF CURRENT DEVICES if (!getCurrentDevices()) { Log.e(TAG, "QGCActivity instance not present"); return null; } // MAKE SURE WE HAVE ENTRIES if (m_devices.size() <= 0) { // Log.e(TAG, "No USB devices found"); return null; } if (m_openedDevices == null) { Log.e(TAG, "m_openedDevices is null"); return null; } int countL = 0; int iL; // CHECK FOR ALREADY OPENED DEVICES AND DON"T INCLUDE THEM IN THE COUNT for (iL=0; iL