altosdroid: Add USB support for TeleDongle/TeleBT
[fw/altos] / altosdroid / src / org / altusmetrum / AltosDroid / AltosUsb.java
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosUsb.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosUsb.java
new file mode 100644 (file)
index 0000000..81d50ab
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * Copyright © 2015 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.UUID;
+import java.util.HashMap;
+
+import android.content.Context;
+import android.hardware.usb.*;
+import android.app.*;
+import android.os.Handler;
+import android.util.Log;
+
+import org.altusmetrum.altoslib_6.*;
+
+public class AltosUsb extends AltosDroidLink {
+
+       // Debugging
+       private static final String TAG = "AltosUsb";
+       private static final boolean D = true;
+
+       private Thread           input_thread   = null;
+
+       private Handler          handler;
+
+       private UsbManager              manager;
+       private UsbDevice               device;
+       private UsbDeviceConnection     connection;
+       private UsbInterface            iface;
+       private UsbEndpoint             in, out;
+
+       private InputStream      input;
+       private OutputStream     output;
+
+       // Constructor
+       public AltosUsb(Context context, UsbDevice device, Handler handler) {
+               super(handler);
+//             set_debug(D);
+               this.handler = handler;
+
+               iface = null;
+               in = null;
+               out = null;
+
+               int     niface = device.getInterfaceCount();
+
+               for (int i = 0; i < niface; i++) {
+
+                       iface = device.getInterface(i);
+
+                       in = null;
+                       out = null;
+
+                       int nendpoints = iface.getEndpointCount();
+
+                       for (int e = 0; e < nendpoints; e++) {
+                               UsbEndpoint     endpoint = iface.getEndpoint(e);
+
+                               if (endpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
+                                       switch (endpoint.getDirection()) {
+                                       case UsbConstants.USB_DIR_OUT:
+                                               out = endpoint;
+                                               break;
+                                       case UsbConstants.USB_DIR_IN:
+                                               in = endpoint;
+                                               break;
+                                       }
+                               }
+                       }
+
+                       if (in != null && out != null)
+                               break;
+               }
+
+               if (in != null && out != null) {
+                       Log.d(TAG, String.format("\tin %s out %s\n", in.toString(), out.toString()));
+
+                       manager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
+
+                       if (manager == null) {
+                               Log.d(TAG, "USB_SERVICE failed");
+                               return;
+                       }
+
+                       connection = manager.openDevice(device);
+
+                       if (connection == null) {
+                               Log.d(TAG, "openDevice failed");
+                               return;
+                       }
+
+                       connection.claimInterface(iface, true);
+
+                       input_thread = new Thread(this);
+                       input_thread.start();
+
+                       // Configure the newly connected device for telemetry
+                       print("~\nE 0\n");
+                       set_monitor(false);
+               }
+       }
+
+       static private boolean isAltusMetrum(UsbDevice device) {
+               if (device.getVendorId() != AltosLib.vendor_altusmetrum)
+                       return false;
+               if (device.getProductId() < AltosLib.product_altusmetrum_min)
+                       return false;
+               if (device.getProductId() > AltosLib.product_altusmetrum_max)
+                       return false;
+               return true;
+       }
+
+       static boolean matchProduct(int want_product, UsbDevice device) {
+
+               if (!isAltusMetrum(device))
+                       return false;
+
+               if (want_product == AltosLib.product_any)
+                       return true;
+
+               int have_product = device.getProductId();
+
+               if (want_product == AltosLib.product_basestation)
+                       return have_product == AltosLib.product_teledongle ||
+                               have_product == AltosLib.product_teleterra ||
+                               have_product == AltosLib.product_telebt ||
+                               have_product == AltosLib.product_megadongle;
+
+               if (want_product == AltosLib.product_altimeter)
+                       return have_product == AltosLib.product_telemetrum ||
+                               have_product == AltosLib.product_telemega ||
+                               have_product == AltosLib.product_easymega ||
+                               have_product == AltosLib.product_telegps ||
+                               have_product == AltosLib.product_easymini ||
+                               have_product == AltosLib.product_telemini;
+
+               if (have_product == AltosLib.product_altusmetrum)       /* old devices match any request */
+                       return true;
+
+               if (want_product == have_product)
+                       return true;
+
+               return false;
+       }
+
+       static public boolean request_permission(Context context, UsbDevice device, PendingIntent pi) {
+               UsbManager      manager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
+
+//             if (manager.hasPermission(device))
+//                     return true;
+
+               Log.d(TAG, "request permission for USB device " + device.toString());
+
+               manager.requestPermission(device, pi);
+               return false;
+       }
+
+       static public UsbDevice find_device(Context context, int match_product) {
+               UsbManager      manager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
+
+               HashMap<String,UsbDevice>       devices = manager.getDeviceList();
+
+               for (UsbDevice  device : devices.values()) {
+                       int     vendor = device.getVendorId();
+                       int     product = device.getProductId();
+
+                       if (matchProduct(match_product, device)) {
+                               Log.d(TAG, "found USB device " + device.toString());
+                               return device;
+                       }
+               }
+
+               return null;
+       }
+
+       private void disconnected() {
+               if (closed()) {
+                       if (D) Log.d(TAG, "disconnected after closed");
+                       return;
+               }
+
+               if (D) Log.d(TAG, "Sending disconnected message");
+               handler.obtainMessage(TelemetryService.MSG_DISCONNECTED, this).sendToTarget();
+       }
+
+       void close_device() {
+               UsbDeviceConnection     tmp_connection;
+
+               synchronized(this) {
+                       tmp_connection = connection;
+                       connection = null;
+               }
+
+               if (tmp_connection != null) {
+                       if (D) Log.d(TAG, "Closing USB device");
+                       tmp_connection.close();
+               }
+       }
+
+       int read(byte[] buffer, int len) {
+               int ret = connection.bulkTransfer(in, buffer, len, -1);
+               if (D) Log.d(TAG, String.format("read(%d) = %d\n", len, ret));
+               return ret;
+       }
+
+       int write(byte[] buffer, int len) {
+               int ret = connection.bulkTransfer(out, buffer, len, -1);
+               if (D) Log.d(TAG, String.format("write(%d) = %d\n", len, ret));
+               return ret;
+       }
+
+       // Stubs of required methods when extending AltosLink
+       public boolean can_cancel_reply()   { return false; }
+       public boolean show_reply_timeout() { return true; }
+       public void hide_reply_timeout()    { }
+
+}