BowlerKernel
UsbCDCSerialConnection.java
Go to the documentation of this file.
1 package com.neuronrobotics.sdk.javaxusb;
2 
3 import java.io.IOException;
4 import java.io.UnsupportedEncodingException;
5 import java.util.ArrayList;
6 import java.util.Arrays;
7 import java.util.List;
8 
9 import javax.usb.UsbClaimException;
10 import javax.usb.UsbConfiguration;
11 import javax.usb.UsbConst;
12 import javax.usb.UsbControlIrp;
13 import javax.usb.UsbDevice;
14 import javax.usb.UsbDisconnectedException;
15 import javax.usb.UsbEndpoint;
16 import javax.usb.UsbException;
17 import javax.usb.UsbHostManager;
18 import javax.usb.UsbHub;
19 import javax.usb.UsbInterface;
20 import javax.usb.UsbInterfaceDescriptor;
21 import javax.usb.UsbIrp;
22 import javax.usb.UsbNotActiveException;
23 import javax.usb.UsbNotOpenException;
24 import javax.usb.UsbPipe;
25 import javax.usb.UsbServices;
26 import javax.usb.event.UsbDeviceDataEvent;
27 import javax.usb.event.UsbDeviceErrorEvent;
28 import javax.usb.event.UsbDeviceEvent;
29 import javax.usb.event.UsbDeviceListener;
30 import javax.usb.util.DefaultUsbIrp;
31 
32 import org.usb4java.Context;
33 import org.usb4java.Device;
34 import org.usb4java.DeviceDescriptor;
35 import org.usb4java.DeviceHandle;
36 import org.usb4java.DeviceList;
37 import org.usb4java.HotplugCallback;
38 import org.usb4java.HotplugCallbackHandle;
39 import org.usb4java.LibUsb;
40 import org.usb4java.LibUsbException;
41 
42 import com.neuronrobotics.sdk.common.BowlerAbstractConnection;
43 import com.neuronrobotics.sdk.common.BowlerDatagram;
44 import com.neuronrobotics.sdk.common.BowlerDatagramFactory;
45 import com.neuronrobotics.sdk.common.BowlerRuntimeException;
46 import com.neuronrobotics.sdk.common.ByteList;
47 import com.neuronrobotics.sdk.common.Log;
48 import com.neuronrobotics.sdk.util.OsInfoUtil;
49 //import com.neuronrobotics.sdk.util.OsInfoUtil;
50 import com.neuronrobotics.sdk.util.ThreadUtil;
51 
52 // TODO: Auto-generated Javadoc
56 public class UsbCDCSerialConnection extends BowlerAbstractConnection implements
57  IUsbDeviceEventListener, UsbDeviceListener {
58 
60  static UsbServices services = null;
61 
63  private UsbDevice mDevice;
64 
66  private String MyDeviceString="";
67 
69  // private UsbInterface controlInterface;
70  private UsbInterface dataInterface;
71 
73  private UsbEndpoint dataInEndpoint;
74 
76  private UsbEndpoint dataOutEndpoint;
77 
79  // private byte [] data = new byte[64];
80  private DeviceHandle deviceHandle;
81 
83  private int interfaceNumber;
84 
86  private UsbPipe camInpipe;
87 
89  private UsbIrp read = new DefaultUsbIrp();
90 
92  private UsbPipe camOutpipe;
93 
95  private UsbIrp write = new DefaultUsbIrp();
96 
98  private static HotplugCallbackHandle callbackHandle;
99 
101  private static ArrayList<IUsbDeviceEventListener> usbDeviceEventListeners = new ArrayList<IUsbDeviceEventListener>();
102 
104  private static EventHandlingThread thread;
105 
107  byte[] data = new byte[64];
108 
114  public UsbCDCSerialConnection(String deviceString) {
115  MyDeviceString=deviceString;
116  setup();
117 
118  }
119 
125  public UsbCDCSerialConnection(UsbDevice device) {
126  if (device == null)
127  throw new NullPointerException(
128  "A valid USB device is needed to regester this connection.");
129 
130  try {
131  MyDeviceString=getUniqueID(device);
132 
133  } catch (UnsupportedEncodingException e) {
134  // TODO Auto-generated catch block
135  e.printStackTrace();
136  } catch (UsbDisconnectedException e) {
137  // TODO Auto-generated catch block
138  e.printStackTrace();
139  } catch (UsbException e) {
140  // TODO Auto-generated catch block
141  e.printStackTrace();
142  }
143  setup();
144 
145  }
146 
152  static class EventHandlingThread extends Thread {
154  private volatile boolean abort;
155 
159  public void abort() {
160  this.abort = true;
161  }
162 
163  /* (non-Javadoc)
164  * @see java.lang.Thread#run()
165  */
166  @Override
167  public void run() {
168  //if(!OsInfoUtil.isWindows()){
169  setName("Bowler Platform USB Events thread");
170  while (!this.abort) {
171  // Let libusb handle pending events. This blocks until events
172  // have been handled, a hotplug callback has been deregistered
173  // or the specified time of .1 second (Specified in
174  // Microseconds) has passed.
175  try {
176  int result = LibUsb.handleEventsTimeoutCompleted(null, 0,
177  null);
178  } catch (Exception e) {
179  e.printStackTrace();
180  }
181  ThreadUtil.wait(100);
182  }
183  //}
184  }
185  }
186 
187  static {
188  resetUsbSystem();
189  }
190 
194  private static void resetUsbSystem(){
195  try {
196 
197  services = UsbHostManager.getUsbServices();
198  if(!OsInfoUtil.isWindows()){
199  callbackHandle = new HotplugCallbackHandle();
200  int result = LibUsb.hotplugRegisterCallback(null,
201  LibUsb.HOTPLUG_EVENT_DEVICE_ARRIVED
202  | LibUsb.HOTPLUG_EVENT_DEVICE_LEFT,
203  LibUsb.HOTPLUG_ENUMERATE, LibUsb.HOTPLUG_MATCH_ANY,
204  LibUsb.HOTPLUG_MATCH_ANY, LibUsb.HOTPLUG_MATCH_ANY,
205  new HotplugCallback() {
206 
207  @Override
208  public int processEvent(Context arg0, Device arg1,
209  int arg2, Object arg3) {
210  DeviceDescriptor descriptor = new DeviceDescriptor();
211  int result = LibUsb.getDeviceDescriptor(arg1,
212  descriptor);
213  if (result != LibUsb.SUCCESS)
214  throw new LibUsbException(
215  "Unable to read device descriptor",
216  result);
217  if (0x04d8 == descriptor.idVendor()) {
219  d.onDeviceEvent(mapLibUsbDevicetoJavaxDevice(arg1));
220  }
221  }
222  return 0;
223  }
224  }, null, callbackHandle);
225  if (result != LibUsb.SUCCESS) {
226  throw new LibUsbException("Unable to register hotplug callback", result);
227  }
228  }
229  } catch (SecurityException e) {
230  // TODO Auto-generated catch block
231  e.printStackTrace();
232  } catch (UsbException e) {
233  // TODO Auto-generated catch block
234  e.printStackTrace();
235  }
236  if(thread!=null)
237  thread.abort();
238 
239  // Start the event handling thread
240  thread = new EventHandlingThread();
241  thread.start();
242  }
243 
250  if (!usbDeviceEventListeners.contains(l))
252  }
253 
260  if (usbDeviceEventListeners.contains(l))
261  usbDeviceEventListeners.remove(l);
262  }
263 
270  public static UsbDevice mapLibUsbDevicetoJavaxDevice(Device device) {
271  try {
272  DeviceDescriptor descriptor = new DeviceDescriptor();
273  LibUsb.getDeviceDescriptor(device, descriptor);
274  ArrayList<UsbDevice> javaxDev = getAllUsbBowlerDevices();
275  for (UsbDevice d : javaxDev) {
276  if (descriptor.iSerialNumber() == d.getUsbDeviceDescriptor()
277  .iSerialNumber()
278  && descriptor.idProduct() == d.getUsbDeviceDescriptor()
279  .iProduct()
280  && descriptor.idVendor() == d.getUsbDeviceDescriptor()
281  .idVendor()) {
282  return d;
283  }
284  }
285  } catch (UnsupportedEncodingException e) {
286  // TODO Auto-generated catch block
287  e.printStackTrace();
288  } catch (UsbDisconnectedException e) {
289  // TODO Auto-generated catch block
290  e.printStackTrace();
291  } catch (SecurityException e) {
292  // TODO Auto-generated catch block
293  e.printStackTrace();
294  } catch (UsbException e) {
295  // TODO Auto-generated catch block
296  e.printStackTrace();
297  }
298  return null;
299 
300  }
301 
311  @SuppressWarnings("unchecked")
312  private static void dumpDevice(final UsbDevice device,
313  ArrayList<UsbDevice> addrs) throws UnsupportedEncodingException,
314  UsbDisconnectedException, UsbException {
315  try {
316  if (device.getUsbDeviceDescriptor().idVendor() == 0x04d8 &&
317  ( device.getUsbDeviceDescriptor().idProduct() == 0x0001||
318  device.getUsbDeviceDescriptor().idProduct() == 0x3742
319  )
320  ) {// Neuron
321  // robotics
322  // devices
323  // Dump information about the device itself
324  // System.out.println("Device: "+device.getProductString());
325  addrs.add(device);
326 
327  // Dump device descriptor
328  // System.out.println(device.getUsbDeviceDescriptor());
329  }
330 
331  // System.out.println();
332 
333  // Dump child devices if device is a hub
334  if (device.isUsbHub()) {
335  final UsbHub hub = (UsbHub) device;
336  for (UsbDevice child : (List<UsbDevice>) hub
337  .getAttachedUsbDevices()) {
338  dumpDevice(child, addrs);
339  }
340  }
341  } catch (Exception e) {
342  e.printStackTrace();
343  }
344  }
345 
355  public static ArrayList<UsbDevice> getAllUsbBowlerDevices()
356  throws UnsupportedEncodingException, UsbDisconnectedException,
357  SecurityException, UsbException {
358  ArrayList<UsbDevice> addrs = null;
359  if (addrs == null) {
360  addrs = new ArrayList<UsbDevice>();
361  dumpDevice(services.getRootUsbHub(), addrs);
362 
363  }
364  return addrs;
365  }
366 
376  public static String getUniqueID(UsbDevice d)
377  throws UnsupportedEncodingException, UsbDisconnectedException,
378  UsbException {
379  return d.getProductString().trim() + " "
380  + d.getSerialNumberString().trim();
381  }
382 
383 
384 
388  private void setup(){
389 
390  ArrayList<UsbDevice> devices;
391  try {
392  devices = getAllUsbBowlerDevices();
393  this.mDevice = null;
394 
395  for (UsbDevice d : devices) {
396  if (getUniqueID(d).contains(MyDeviceString)) {
397  this.mDevice = d;
398  }
399  }
400  } catch (UnsupportedEncodingException e) {
401  // TODO Auto-generated catch block
402  e.printStackTrace();
403  } catch (UsbDisconnectedException e) {
404  // TODO Auto-generated catch block
405  e.printStackTrace();
406  } catch (SecurityException e) {
407  // TODO Auto-generated catch block
408  e.printStackTrace();
409  } catch (UsbException e) {
410  // TODO Auto-generated catch block
411  e.printStackTrace();
412  }
413 
414  if (MyDeviceString == null)
415  throw new NullPointerException(
416  "A valid USB device is needed to regester this connection.");
417  }
418 
419 
420 
421  /*
422  * (non-Javadoc)
423  *
424  * @see com.neuronrobotics.sdk.common.BowlerAbstractConnection#connect()
425  */
426  @SuppressWarnings("unchecked")
427  @Override
428  public boolean connect() {
429  try{
430  localDisconnect();
431  resetUsbSystem();
432  setup();
433  }catch(Exception e){
434  e.printStackTrace();
435  }
436 
437  // System.out.println(mDevice);
438  // Dump device descriptor
439  // System.out.println(mDevice.getUsbDeviceDescriptor());
440 
441  // Process all configurations
442  for (UsbConfiguration configuration : (List<UsbConfiguration>) mDevice
443  .getUsbConfigurations()) {
444  // Process all interfaces
445  for (UsbInterface iface : (List<UsbInterface>) configuration
446  .getUsbInterfaces()) {
447  // Dump the interface descriptor
448  // System.out.println(iface.getUsbInterfaceDescriptor());
449 
450  if (iface.getUsbInterfaceDescriptor().bInterfaceClass() == 2) {
451  // controlInterface = iface;
452  // controlEndpoint = (UsbEndpoint)
453  // controlInterface.getUsbEndpoints().get(0);
454  }
455  if (iface.getUsbInterfaceDescriptor().bInterfaceClass() == 10) {
456  dataInterface = iface;
457  try {
459 
460  } catch (Exception e1) {
461  // TODO Auto-generated catch block
462  e1.printStackTrace();
463  return false;
464  }
465  if (!dataInterface.isClaimed()) {
466  try {
467  dataInterface.claim();
468  // Process all endpoints
469  for (UsbEndpoint endpoint : (List<UsbEndpoint>) dataInterface
470  .getUsbEndpoints()) {
471  if (endpoint.getUsbEndpointDescriptor()
472  .bEndpointAddress() == 0x03) {
473  // System.out.println("Data out Endpipe");
474  dataOutEndpoint = endpoint;
475 
476  } else {
477  // System.out.println("Data in Endpipe");
478  dataInEndpoint = endpoint;
479  }
480  }
481  } catch (UsbClaimException e) {
482  // TODO Auto-generated catch block
483  e.printStackTrace();
484  } catch (UsbNotActiveException e) {
485  // TODO Auto-generated catch block
486  e.printStackTrace();
487  } catch (UsbDisconnectedException e) {
488  // TODO Auto-generated catch block
489  e.printStackTrace();
490  } catch (UsbException e) {
491  // TODO Auto-generated catch block
492  e.printStackTrace();
493  }
494  } else {
495  Log.error("Interface is already climed");
496  }
497 
498  }
499 
500  }
501  }
502 
503  if (dataInEndpoint != null && dataOutEndpoint != null) {
504 
505  setConnected(true);
506  mDevice.addUsbDeviceListener(this);
507  }
508 
509 
510 
511  return isConnected();
512  }
513 
520  public Device findDevice(String seriualNumber) {
521  //if(!OsInfoUtil.isWindows()){
522  // Read the USB device list
523  DeviceList list = new DeviceList();
524  int result = LibUsb.getDeviceList(null, list);
525  if (result < 0)
526  throw new LibUsbException("Unable to get device list", result);
527 
528  try {
529  // Iterate over all devices and scan for the right one
530  for (Device device : list) {
531 
532  DeviceDescriptor descriptor = new DeviceDescriptor();
533  result = LibUsb.getDeviceDescriptor(device, descriptor);
534  if (result != LibUsb.SUCCESS)
535  throw new LibUsbException(
536  "Unable to read device descriptor", result);
537  DeviceHandle handle = new DeviceHandle();
538  result = LibUsb.open(device, handle);
539  if (result == LibUsb.SUCCESS) {
540  String sn = LibUsb.getStringDescriptor(handle,
541  descriptor.iSerialNumber()).trim();
542  LibUsb.close(handle);
543  if (sn.contains(seriualNumber.trim())) {
544 
545  return device;
546  }
547  }
548  }
549  } finally {
550  // Ensure the allocated device list is freed
551  LibUsb.freeDeviceList(list, true);
552  }
553  //}
554  // Device not found
555  return null;
556  }
557 
563  private void kernelDetatch(UsbDevice mDevice){
564  //if(!OsInfoUtil.isWindows()){
565  Device kDev=null;
566  try {
567  kDev = findDevice(mDevice.getSerialNumberString());
568  } catch (UnsupportedEncodingException e) {
569  // TODO Auto-generated catch block
570  e.printStackTrace();
571  } catch (UsbDisconnectedException e) {
572  // TODO Auto-generated catch block
573  e.printStackTrace();
574  } catch (UsbException e) {
575  // TODO Auto-generated catch block
576  e.printStackTrace();
577  }
578  if (kDev == null)
579  return;
580 
581  deviceHandle = new DeviceHandle();
582  interfaceNumber = dataInterface.getUsbInterfaceDescriptor()
583  .bInterfaceNumber();
584 
585  int result = LibUsb.open(kDev, deviceHandle);
586  if (result != LibUsb.SUCCESS)
587  throw new LibUsbException("Unable to open USB device", result);
588 
589  int r = LibUsb.detachKernelDriver(deviceHandle, interfaceNumber);
590  if (r != LibUsb.SUCCESS && r != LibUsb.ERROR_NOT_SUPPORTED
591  && r != LibUsb.ERROR_NOT_FOUND)
592  throw new LibUsbException("Unable to detach kernel driver", r);
593  // System.out.println("Kernel detatched for device "+mDevice);
594  //}
595  }
596 
600  private void localDisconnect(){
601  mDevice.removeUsbDeviceListener(this);
602  try {
603  if(camInpipe!=null)
604  camInpipe.close();
605  camInpipe=null;
606  if(camOutpipe!=null)
607  camOutpipe.close();
608  camOutpipe=null;
609  } catch (UsbDisconnectedException e) {
610  // TODO Auto-generated catch block
611  e.printStackTrace();
612  } catch (UsbException e) {
613  // TODO Auto-generated catch block
614  e.printStackTrace();
615  }
616  if(dataInterface!=null){
617  if (dataInterface.isClaimed()){
618  try {
619  dataInterface.release();
620  dataInterface=null;
621  } catch (UsbDisconnectedException e) {
622  // TODO Auto-generated catch block
623  e.printStackTrace();
624  } catch (UsbException e) {
625  // TODO Auto-generated catch block
626  e.printStackTrace();
627  }
628  }
629  }
630  //if(!OsInfoUtil.isWindows()){
631  if (deviceHandle != null) {
632  //LibUsb.attachKernelDriver(deviceHandle, interfaceNumber);
633  try{
634  LibUsb.close(deviceHandle);
635  deviceHandle=null;
636  }catch(IllegalStateException e){
637  e.printStackTrace();
638  }
639  }
640  //}
641 
642 
643  }
644 
645  /*
646  * (non-Javadoc)
647  *
648  * @see com.neuronrobotics.sdk.common.BowlerAbstractConnection#disconnect()
649  */
650  @Override
651  public void disconnect() {
652  super.disconnect();
653  localDisconnect();
654 
655  }
656 
663  private void prepIrp(UsbIrp irp, byte[] data) {
664  irp.complete();
665  irp.setData(data);
666  irp.setLength(data.length);
667  irp.setOffset(0);
668  irp.setAcceptShortPacket(true);
669  irp.setComplete(false);
670  irp.setUsbException(null);
671  }
672 
679  // private ByteList outgoing = new ByteList();
680  public void write(byte[] src) throws IOException {
681  if (!isConnected())
682  return;
684  setLastWrite(System.currentTimeMillis());
685  try {
686  if (camOutpipe == null) {
687  camOutpipe = dataOutEndpoint.getUsbPipe();
688 
689  }
690  if (!camOutpipe.isOpen())
691  camOutpipe.open();
692 
693  prepIrp(write, src);
694 
695  camOutpipe.asyncSubmit(write);
696  write.waitUntilComplete();
697 
698  while (!write.isComplete()) {
699  ThreadUtil.wait(1);
700  }
701 
702  } catch (Exception e) {// TODO Auto-generated catch block
703  //e.printStackTrace();
704  disconnect();
705  throw new BowlerRuntimeException(
706  "Connection is no longer availible "
707  + e.getLocalizedMessage());
708  }
709 
710  return;
711  }
712 
716  enum usbControlState{
717 
719  init,
720 
722  submitted,
723 
725  done
726  } ;
727 
729  usbControlState usbReadState = usbControlState.init;
730 
731  /* (non-Javadoc)
732  * @see com.neuronrobotics.sdk.common.BowlerAbstractConnection#loadPacketFromPhy(com.neuronrobotics.sdk.common.ByteList)
733  */
734  @Override
735  public BowlerDatagram loadPacketFromPhy(ByteList bytesToPacketBuffer)
736  throws NullPointerException, IOException {
737 
738  if (dataInEndpoint == null)
739  return null;
740  int got = 0;
741 
742 
743  switch (usbReadState){
744 
745  case init:
746  try {
747  if (camInpipe == null) {
748  camInpipe = dataInEndpoint.getUsbPipe();
749 
750  }
751  if (!camInpipe.isOpen())
752  camInpipe.open();
753 
754  prepIrp(read, data);
755 
756  camInpipe.asyncSubmit(read);
757 
758 
759  read.waitUntilComplete();
760 
761  usbReadState = usbControlState.submitted;
762 
763  } catch ( IllegalArgumentException
764  e) {
765  //e.printStackTrace();
766  disconnect();
767  return null;
768  } catch (UsbNotActiveException e) {
769  // TODO Auto-generated catch block
770  e.printStackTrace();
771  } catch (UsbNotOpenException e) {
772  // TODO Auto-generated catch block
773  e.printStackTrace();
774  } catch (UsbDisconnectedException e) {
775  // TODO Auto-generated catch block
776  e.printStackTrace();
777  } catch (UsbException e) {
778  // TODO Auto-generated catch block
779  e.printStackTrace();
780  }
781  break;
782  case submitted:
783  if(read.isComplete()){
784  got = read.getActualLength();
785  if (got > 0) {
786  bytesToPacketBuffer.add(Arrays.copyOfRange(data, 0, got));
787  }
788  usbReadState = usbControlState.init;
789  }
790  default:
791  break;
792  }
793 
794 
795  return BowlerDatagramFactory
796  .build(bytesToPacketBuffer);
797  }
798 
799  // /* (non-Javadoc)
800  // * @see com.neuronrobotics.sdk.common.BowlerAbstractConnection#reconnect()
801  // */
802  // @Override
803  // public boolean reconnect() {
804  // if(!isConnected())
805  // return false;
806  // else
807  // return true;
808  // }
809 
810  /*
811  * (non-Javadoc)
812  *
813  * @see
814  * com.neuronrobotics.sdk.common.BowlerAbstractConnection#waitingForConnection
815  * ()
816  */
817  @Override
818  public boolean waitingForConnection() {
819  // TODO Auto-generated method stub
820  return false;
821  }
822 
823  /* (non-Javadoc)
824  * @see javax.usb.event.UsbDeviceListener#dataEventOccurred(javax.usb.event.UsbDeviceDataEvent)
825  */
826  @Override
827  public void dataEventOccurred(UsbDeviceDataEvent arg0) {
828  // TODO Auto-generated method stub
829 
830  }
831 
832  /* (non-Javadoc)
833  * @see javax.usb.event.UsbDeviceListener#errorEventOccurred(javax.usb.event.UsbDeviceErrorEvent)
834  */
835  @Override
836  public void errorEventOccurred(UsbDeviceErrorEvent arg0) {
837  if(arg0.getUsbDevice() == mDevice){
838  new RuntimeException("Disconnect in USB called").printStackTrace();
839  disconnect();
840  //connect() ;
841  }
842  }
843 
844  /* (non-Javadoc)
845  * @see javax.usb.event.UsbDeviceListener#usbDeviceDetached(javax.usb.event.UsbDeviceEvent)
846  */
847  @Override
848  public void usbDeviceDetached(UsbDeviceEvent arg0) {
849 
850  if(arg0.getUsbDevice() == mDevice){
851  //new RuntimeException("Disconnect in USB called").printStackTrace();
852  disconnect();
853  //connect() ;
854  }
855  }
856 
857  /* (non-Javadoc)
858  * @see com.neuronrobotics.sdk.javaxusb.IUsbDeviceEventListener#onDeviceEvent(javax.usb.UsbDevice)
859  */
860  @Override
861  public void onDeviceEvent(UsbDevice device) {
862  // TODO Auto-generated method stub
863 
864  }
865 
866 }
static void error(String message)
Definition: Log.java:92
static void dumpDevice(final UsbDevice device, ArrayList< UsbDevice > addrs)
BowlerDatagram loadPacketFromPhy(ByteList bytesToPacketBuffer)
static ArrayList< IUsbDeviceEventListener > usbDeviceEventListeners
static void removeUsbDeviceEventListener(IUsbDeviceEventListener l)
static void addUsbDeviceEventListener(IUsbDeviceEventListener l)