Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
[fw/altos] / altosdroid / src / org / altusmetrum / AltosDroid / AltosUsb.java
1 /*
2  * Copyright © 2015 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 package org.altusmetrum.AltosDroid;
19
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.OutputStream;
23 import java.util.UUID;
24 import java.util.HashMap;
25
26 import android.content.Context;
27 import android.hardware.usb.*;
28 import android.app.*;
29 import android.os.Handler;
30
31 import org.altusmetrum.altoslib_8.*;
32
33 public class AltosUsb extends AltosDroidLink {
34
35         private Thread           input_thread   = null;
36
37         private Handler          handler;
38
39         private UsbManager              manager;
40         private UsbDevice               device;
41         private UsbDeviceConnection     connection;
42         private UsbInterface            iface;
43         private UsbEndpoint             in, out;
44
45         private InputStream      input;
46         private OutputStream     output;
47
48         // Constructor
49         public AltosUsb(Context context, UsbDevice device, Handler handler) {
50                 super(handler);
51 //              set_debug(D);
52                 this.handler = handler;
53
54                 iface = null;
55                 in = null;
56                 out = null;
57
58                 int     niface = device.getInterfaceCount();
59
60                 for (int i = 0; i < niface; i++) {
61
62                         iface = device.getInterface(i);
63
64                         in = null;
65                         out = null;
66
67                         int nendpoints = iface.getEndpointCount();
68
69                         for (int e = 0; e < nendpoints; e++) {
70                                 UsbEndpoint     endpoint = iface.getEndpoint(e);
71
72                                 if (endpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
73                                         switch (endpoint.getDirection()) {
74                                         case UsbConstants.USB_DIR_OUT:
75                                                 out = endpoint;
76                                                 break;
77                                         case UsbConstants.USB_DIR_IN:
78                                                 in = endpoint;
79                                                 break;
80                                         }
81                                 }
82                         }
83
84                         if (in != null && out != null)
85                                 break;
86                 }
87
88                 if (in != null && out != null) {
89                         AltosDebug.debug("\tin %s out %s\n", in.toString(), out.toString());
90
91                         manager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
92
93                         if (manager == null) {
94                                 AltosDebug.debug("USB_SERVICE failed");
95                                 return;
96                         }
97
98                         connection = manager.openDevice(device);
99
100                         if (connection == null) {
101                                 AltosDebug.debug("openDevice failed");
102                                 return;
103                         }
104
105                         connection.claimInterface(iface, true);
106
107                         input_thread = new Thread(this);
108                         input_thread.start();
109
110                         // Configure the newly connected device for telemetry
111                         print("~\nE 0\n");
112                         set_monitor(false);
113                 }
114         }
115
116         static private boolean isAltusMetrum(UsbDevice device) {
117                 if (device.getVendorId() != AltosLib.vendor_altusmetrum)
118                         return false;
119                 if (device.getProductId() < AltosLib.product_altusmetrum_min)
120                         return false;
121                 if (device.getProductId() > AltosLib.product_altusmetrum_max)
122                         return false;
123                 return true;
124         }
125
126         static boolean matchProduct(int want_product, UsbDevice device) {
127
128                 if (!isAltusMetrum(device))
129                         return false;
130
131                 if (want_product == AltosLib.product_any)
132                         return true;
133
134                 int have_product = device.getProductId();
135
136                 if (want_product == AltosLib.product_basestation)
137                         return have_product == AltosLib.product_teledongle ||
138                                 have_product == AltosLib.product_teleterra ||
139                                 have_product == AltosLib.product_telebt ||
140                                 have_product == AltosLib.product_megadongle;
141
142                 if (want_product == AltosLib.product_altimeter)
143                         return have_product == AltosLib.product_telemetrum ||
144                                 have_product == AltosLib.product_telemega ||
145                                 have_product == AltosLib.product_easymega ||
146                                 have_product == AltosLib.product_telegps ||
147                                 have_product == AltosLib.product_easymini ||
148                                 have_product == AltosLib.product_telemini;
149
150                 if (have_product == AltosLib.product_altusmetrum)       /* old devices match any request */
151                         return true;
152
153                 if (want_product == have_product)
154                         return true;
155
156                 return false;
157         }
158
159         static public boolean request_permission(Context context, UsbDevice device, PendingIntent pi) {
160                 UsbManager      manager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
161
162 //              if (manager.hasPermission(device))
163 //                      return true;
164
165                 AltosDebug.debug("request permission for USB device " + device.toString());
166
167                 manager.requestPermission(device, pi);
168                 return false;
169         }
170
171         static public UsbDevice find_device(Context context, int match_product) {
172                 UsbManager      manager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
173
174                 HashMap<String,UsbDevice>       devices = manager.getDeviceList();
175
176                 for (UsbDevice  device : devices.values()) {
177                         int     vendor = device.getVendorId();
178                         int     product = device.getProductId();
179
180                         if (matchProduct(match_product, device)) {
181                                 AltosDebug.debug("found USB device " + device.toString());
182                                 return device;
183                         }
184                 }
185
186                 return null;
187         }
188
189         private void disconnected() {
190                 if (closed()) {
191                         AltosDebug.debug("disconnected after closed");
192                         return;
193                 }
194
195                 AltosDebug.debug("Sending disconnected message");
196                 handler.obtainMessage(TelemetryService.MSG_DISCONNECTED, this).sendToTarget();
197         }
198
199         void close_device() {
200                 UsbDeviceConnection     tmp_connection;
201
202                 synchronized(this) {
203                         tmp_connection = connection;
204                         connection = null;
205                 }
206
207                 if (tmp_connection != null) {
208                         AltosDebug.debug("Closing USB device");
209                         tmp_connection.close();
210                 }
211         }
212
213         int read(byte[] buffer, int len) {
214                 int ret = connection.bulkTransfer(in, buffer, len, -1);
215                 AltosDebug.debug("read(%d) = %d\n", len, ret);
216                 return ret;
217         }
218
219         int write(byte[] buffer, int len) {
220                 int ret = connection.bulkTransfer(out, buffer, len, -1);
221                 AltosDebug.debug("write(%d) = %d\n", len, ret);
222                 return ret;
223         }
224
225         // Stubs of required methods when extending AltosLink
226         public boolean can_cancel_reply()   { return false; }
227         public boolean show_reply_timeout() { return true; }
228         public void hide_reply_timeout()    { }
229
230 }