zoukankan      html  css  js  c++  java
  • 基于usb4java实现的java下的usb通信

    项目地址:点击打开

    使用java开发的好处就是跨平台,基本上java的开发的程序在linux、mac、MS上都可以运行,对应这java的那句经典名言:一次编写,到处运行。这个项目里面有两种包选择,一个是low-level(libus)一个是high-level(javax-usb),相关的优缺点在官方网站上已经说明了,我这里就不翻译了,不过前者好像基于libusb已经好久不更新了,所以还是选择后者。

    配置:你需要在你包的根目录下新建一个名为:javax.usb.properties的文件,里面的内容是这样的:

    javax.usb.services = org.usb4java.javax.Services

    查找usb设备,其实通过usb通信流程大体上都是一致,之前我做过android与arduino通过usb通信,然后java通信走了一遍之后发现是一样的。USB 设备棵树上进行管理所有物理集线器连接一个虚拟的 USB集线器更多集线器可以连接这些集线器任何集线器可以大量连接的 USB设备

    通常需要使用之前搜索特定设备,下面的一个例子如何扫描一个特定供应商产品 id 第一个设备设备:

    public UsbDevice findDevice(UsbHub hub, short vendorId, short productId)
    {
        for (UsbDevice device : (List<UsbDevice>) hub.getAttachedUsbDevices())
        {
            UsbDeviceDescriptor desc = device.getUsbDeviceDescriptor();
            if (desc.idVendor() == vendorId && desc.idProduct() == productId) return device;
            if (device.isUsbHub())
            {
                device = findDevice((UsbHub) device, vendorId, productId);
                if (device != null) return device;
            }
        }
        return null;
    }

    接口

    当你想要与一个接口或者这个接口的端点进行通信时,那么你在使用它之前必须要claim它,并且当你结束时你必须释放它。比如:下面的代码:

    UsbConfiguration configuration = device.getActiveUsbConfiguration();
    UsbInterface iface = configuration.getUsbInterface((byte) 1);
    iface.claim();
    try
    {
        ... Communicate with the interface or endpoints ...
    }
    finally        
    {
        iface.release();
    }

    可能出现的一种情况是你想要通信的接口已经被内核驱动使用,在这种情况下你可能需要通过传递一个接口策略到claim方法以此尝试强制claim:

    iface.claim(new UsbInterfacePolicy()
    {            
        @Override
        public boolean forceClaim(UsbInterface usbInterface)
        {
            return true;
        }
    });

    需要注意的是,接口策略只是为了实现基础USB的一个提示.接口策略在MS-Windows上将被忽略,因为libusb在windows上不支持分派驱动。

    同步 I/O

    这个example发送8个字节到端点0x03:

    UsbEndpoint endpoint = iface.getUsbEndpoint(0x03);
    UsbPipe pipe = endpoint.getUsbPipe();
    pipe.open();
    try
    {
        int sent = pipe.syncSubmit(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 });
        System.out.println(sent + " bytes sent");
    }
    finally
    {
        pipe.close();
    }

    这个example是从端点0x83读取8个字节:

    UsbEndpoint endpoint = iface.getUsbEndpoint((byte) 0x83);
    UsbPipe pipe = endpoint.getUsbPipe();
    pipe.open();
    try
    {
        byte[] data = new byte[8];
        int received = pipe.syncSubmit(data);
        System.out.println(received + " bytes received");
    }
    finally
    {
        pipe.close();
    }

    异步 I/O

    同步I/O操作与异步I/O操作类似,仅仅是使用asyncSubmint方法取代syncSubmit方法。syncSubmit方法将会阻塞直到请求完成,而asyncSubmit不会阻塞并且立即返回,为了接受请求的返回,你必须为Pipe添加一个监听器,像下面这样:

    pipe.addUsbPipeListener(new UsbPipeListener()
    {            
        @Override
        public void errorEventOccurred(UsbPipeErrorEvent event)
        {
            UsbException error = event.getUsbException();
            ... Handle error ...
        }
        
        @Override
        public void dataEventOccurred(UsbPipeDataEvent event)
        {
            byte[] data = event.getData();
            ... Process received data ...
        }
    });

    遇到的问题:在Linux上不能打开设备Device,其实是权限的问题导致的,你应该知道在Linux下权限分配是一门很重要的学问,其实该问题在官方网站的FAQ一栏已经提供了解决的办法,地址:点击打开

    在Linux环境下,你需要给你想要通信的usb设备写一个许可文件。在此之前,你可以以root用户运行你的程序检查设备是否可以获取,如果有上述操作有作用,那么我推荐配置下udev以便当设备连接上后你的用户拥有对设备写的权限

      SUBSYSTEM=="usb",ATTR{idVendor}=="89ab",ATTR{idProduct}=="4567",MODE="0660",GROUP="wheel"

    需要该更改的就是PID、VID、GROUP,关于PID和VID信息以及查看相关的接口、端口信息的查看,linux下可以使用一个叫usbview的软件,软件安装很简单,仅仅一条命令:

    sudo apt-get insall usbview

    注意启动的时候需要权限,而且还需要以图形界面显示(sudo usbview在我的Linux Mint没有反应的):

    sudo gksu usbview

     参考官方写的一段简单的代码:

    package nir.desktop.demo;
    
    import java.util.List;
    
    import javax.usb.UsbConfiguration;
    import javax.usb.UsbConst;
    import javax.usb.UsbControlIrp;
    import javax.usb.UsbDevice;
    import javax.usb.UsbDeviceDescriptor;
    import javax.usb.UsbEndpoint;
    import javax.usb.UsbException;
    import javax.usb.UsbHostManager;
    import javax.usb.UsbHub;
    import javax.usb.UsbInterface;
    import javax.usb.UsbInterfacePolicy;
    import javax.usb.UsbPipe;
    import javax.usb.event.UsbPipeDataEvent;
    import javax.usb.event.UsbPipeErrorEvent;
    import javax.usb.event.UsbPipeListener;
    
    public class UsbConn {
         private static final short VENDOR_ID = 0x2341;
         /** The product ID of the missile launcher. */
         private static final short PRODUCT_ID = 0x43;
    //    private static final short VENDOR_ID = 0x10c4;
    //    // /** The product ID of the missile launcher. */
    //    private static final short PRODUCT_ID = -5536;
        private static UsbPipe pipe81, pipe01;
    
        /**
         * 依据VID和PID找到设备device
         * 
         * @param hub
         * @return
         */
        @SuppressWarnings("unchecked")
        public static UsbDevice findMissileLauncher(UsbHub hub) {
            UsbDevice launcher = null;
    
            for (UsbDevice device : (List<UsbDevice>) hub.getAttachedUsbDevices()) {
                if (device.isUsbHub()) {
                    launcher = findMissileLauncher((UsbHub) device);
                    if (launcher != null)
                        return launcher;
                } else {
                    UsbDeviceDescriptor desc = device.getUsbDeviceDescriptor();
                    if (desc.idVendor() == VENDOR_ID
                            && desc.idProduct() == PRODUCT_ID) {
                        System.out.println("找到设备:" + device);
                        return device;
                    }
                }
            }
            return null;
        }
    
        public static void sendMessage(UsbDevice device, byte[] message)
                throws UsbException {
            UsbControlIrp irp = device
                    .createUsbControlIrp(
                            (byte) (UsbConst.REQUESTTYPE_TYPE_CLASS | UsbConst.REQUESTTYPE_RECIPIENT_INTERFACE),
                            (byte) 0x09, (short) 2, (short) 1);
            irp.setData(message);
            device.syncSubmit(irp);
        }
    
        /**
         * 注意权限的配置问题,在linux下可能无法打开device,解决办法参考官方的FAQ
         * 
         * @param args
         */
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            UsbDevice device;
            try {
                device = findMissileLauncher(UsbHostManager.getUsbServices()
                        .getRootUsbHub());
                if (device == null) {
                    System.out.println("Missile launcher not found.");
                    System.exit(1);
                    return;
                }
                UsbConfiguration configuration = device.getActiveUsbConfiguration();//获取配置信息
                UsbInterface iface = configuration.getUsbInterface((byte) 1);//接口
                iface.claim(new UsbInterfacePolicy() {
    
                    @Override
                    public boolean forceClaim(UsbInterface arg0) {
                        // TODO Auto-generated method stub
                        return true;
                    }
                });
                // for (UsbEndpoint endpoints : (List<UsbEndpoint>) iface
                // .getUsbEndpoints()) {
                // System.out.println("--->"+endpoints.getUsbEndpointDescriptor());
                // }
                UsbEndpoint endpoint81 = iface.getUsbEndpoint((byte) 0x83);//接受数据地址
                UsbEndpoint endpoint01 = iface.getUsbEndpoint((byte)0x04);//发送数据地址
                pipe81 = endpoint81.getUsbPipe();
                pipe81.open();
                pipe01 = endpoint01.getUsbPipe();
                pipe01.open();
                byte[] dataSend = { (byte) 0x00 };//需要发送的数据
                pipe01.asyncSubmit(dataSend);
                pipe81.addUsbPipeListener(new UsbPipeListener() {
                    
                    @Override
                    public void errorEventOccurred(UsbPipeErrorEvent arg0) {
                        // TODO Auto-generated method stub
                        System.out.println(arg0);
                    }
                    
                    @Override
                    public void dataEventOccurred(UsbPipeDataEvent arg0) {
                        // TODO Auto-generated method stub
                        System.out.println(new String(arg0.getData()));
                    }
                });
    //             pipe81.close();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } finally {
                //
            }
        }
    }

    其中的一些接口、端口都是依据usbview写的,数据是发成功了(RX灯亮了),但是因为我使用的是arduino,里面的代码不知道怎么写,如果有这方便的高手还请帮我一下,谢谢。翻墙看了下有的人用的是同步传输出现的问题,相关的解决办法,这里我就完全粘贴、复制了:Here is an abbreviated example. Note that I have removed from this, allchecks, error handling, and such.It is just the logic of creating two pipes for two endpoints. One IN andone OUT. Then using them to do a write and a read.It assumes that endpoint 2 is an OUT and endpoint 4 is an IN.Note also that the name of an IN endpoint is OR'd with 0x80:

    import javax.usb.*;
    
    public class Example {
    
    public static void main(String[] args) throws Exception {
    UsbDevice usbDevice = ...getUsbDevice by matching vID, pID, knowing
    the path... or whatever works for you...
    usbDevice.getUsbConfigurations();
    UsbConfiguration config = usbDevice.getActiveUsbConfiguration();
    UsbInterface xface = config.getUsbInterface((byte)0);
    xface.claim();
    
    UsbEndpoint endPt2 = xface.getUsbEndpoint((byte)2); //OUT
    endpoint
    UsbEndpoint endPt4 = xface.getUsbEndpoint((byte)(4 | 0x80) ); //IN
    endpoint
    
    UsbPipe pipe2 = endPt2.getUsbPipe();
    pipe2.open();
    UsbPipe pipe4 = endPt4.getUsbPipe();
    pipe4.open();
    
    //Use the pipes:
    byte[] bytesToSend = new byte[] {1,2,3}; //Going to send out these 3
    bytes
    UsbIrp irpSend = pipe2.createUsbIrp();
    irpSend.setData(bytesToSend);
    pipe2.asyncSubmit(irpSend); //Send out some bytes
    irpSend.waitUntilComplete(1000); //Wait up to 1 second
    
    byte[] bytesToRead = new byte[3]; //Going to read 3 bytes into here
    UsbIrp irpRead = pipe2.createUsbIrp();
    irpRead.setData(bytesToRead);
    pipe4.asyncSubmit(irpRead); //Read some bytes
    irpRead.waitUntilComplete(1000); //Wait up to 1 second
    }
    }
    View Code

    下面是我监听数据返回点完整代码:

     UsbConn.java:

    package DemoMath;
    
    import java.util.List;
    
    import javax.usb.UsbConfiguration;
    import javax.usb.UsbConst;
    import javax.usb.UsbControlIrp;
    import javax.usb.UsbDevice;
    import javax.usb.UsbDeviceDescriptor;
    import javax.usb.UsbEndpoint;
    import javax.usb.UsbException;
    import javax.usb.UsbHostManager;
    import javax.usb.UsbHub;
    import javax.usb.UsbInterface;
    import javax.usb.UsbInterfacePolicy;
    import javax.usb.UsbPipe;
    import javax.usb.util.UsbUtil;
    
    public class UsbConn {
        private static final short VENDOR_ID = 0x04b4;
        private static final short PRODUCT_ID = 0x1004;
        private static final byte INTERFACE_AD= 0x00;
        private static final byte ENDPOINT_OUT= 0x02;
        private static final byte ENDPOINT_IN= (byte) 0x86;
        private static final byte[] COMMAND = {0x01,0x00};
    
        @SuppressWarnings("unchecked")
        public static UsbDevice findMissileLauncher(UsbHub hub) {
            UsbDevice launcher = null;
    
            for (UsbDevice device : (List<UsbDevice>) hub.getAttachedUsbDevices()) {
                if (device.isUsbHub()) {
                    launcher = findMissileLauncher((UsbHub) device);
                    if (launcher != null)
                        return launcher;
                } else {
                    UsbDeviceDescriptor desc = device.getUsbDeviceDescriptor();
                    if (desc.idVendor() == VENDOR_ID
                            && desc.idProduct() == PRODUCT_ID) {
                        System.out.println("发现设备" + device);
                        return device;
                    }
                }
            }
            return null;
        }
        //command for controlTransfer
        public static void sendMessage(UsbDevice device, byte[] message)
                throws UsbException {
            UsbControlIrp irp = device
                    .createUsbControlIrp(
                            (byte) (UsbConst.REQUESTTYPE_TYPE_CLASS | UsbConst.REQUESTTYPE_RECIPIENT_INTERFACE),
                            (byte) 0x09, (short) 2, (short) 1);
            irp.setData(message);
            device.syncSubmit(irp);
        }
        /**
         * Class to listen in a dedicated Thread for data coming events.
         * This really could be used for any HID device.
         */
        public static class HidMouseRunnable implements Runnable
        {
            /* This pipe must be the HID interface's interrupt-type in-direction endpoint's pipe. */
            public HidMouseRunnable(UsbPipe pipe) { usbPipe = pipe; }
            public void run()
            {
                byte[] buffer = new byte[UsbUtil.unsignedInt(usbPipe.getUsbEndpoint().getUsbEndpointDescriptor().wMaxPacketSize())];
                @SuppressWarnings("unused")
                int length = 0;
    
                while (running) {
                    try {
                        length = usbPipe.syncSubmit(buffer);
                    } catch ( UsbException uE ) {
                        if (running) {
                            System.out.println("Unable to submit data buffer to HID mouse : " + uE.getMessage());
                            break;
                        }
                    }
                    if (running) {
    //                    System.out.print("Got " + length + " bytes of data from HID mouse :");
    //                    for (int i=0; i<length; i++)
    //                        System.out.print(" 0x" + UsbUtil.toHexString(buffer[i]));
                        try {
                            String result = DataFix.getHexString(buffer); 
                            System.out.println(result);
                        } catch (Exception e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                }
            }
            /**
             * Stop/abort listening for data events.
             */
            public void stop()
            {
                running = false;
                usbPipe.abortAllSubmissions();
            }
            public boolean running = true;
            public UsbPipe usbPipe = null;
        }
        /**
         * get the  correct Interface for USB
         * @param device
         * @return
         * @throws UsbException
         */
        public static UsbInterface readInit() throws UsbException{
            UsbDevice device = findMissileLauncher(UsbHostManager.getUsbServices()
                    .getRootUsbHub());
            if (device == null) {
                System.out.println("Missile launcher not found.");
                System.exit(1);
            }
            UsbConfiguration configuration = device.getActiveUsbConfiguration();
            UsbInterface iface = configuration.getUsbInterface(INTERFACE_AD);//Interface Alternate Number
            //if you using the MS os,may be you need judge,because MS do not need follow code,by tong
            iface.claim(new UsbInterfacePolicy() {
                @Override
                public boolean forceClaim(UsbInterface arg0) {
                    // TODO Auto-generated method stub
                    return true;
                }
            });
            return iface;
        }
        /**
         * 异步bulk传输,by tong
         * @param usbInterface
         * @param data
         */
        public static void syncSend(UsbInterface usbInterface,byte[] data) {
            UsbEndpoint endpoint = usbInterface.getUsbEndpoint(ENDPOINT_OUT);
            UsbPipe outPipe = endpoint.getUsbPipe();
            try {
                outPipe.open();
                outPipe.syncSubmit(data);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }finally{
                try {
                    outPipe.close();
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
        public static HidMouseRunnable listenData(UsbInterface usbInterface) {
            UsbEndpoint endpoint = usbInterface.getUsbEndpoint(ENDPOINT_IN);
            UsbPipe inPipe = endpoint.getUsbPipe();
            HidMouseRunnable hmR = null;
            try {
                inPipe.open();
                hmR = new HidMouseRunnable(inPipe);
                Thread t = new Thread(hmR);
                t.start();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return hmR;
        }
        /**
         * 主程序入口
         * 
         * @param args
         */
        public static void main(String[] args) {
            // TODO Auto-generated method stub
                UsbInterface iface;
                try {
                    iface = readInit();
                    listenData(iface);
                    syncSend(iface, COMMAND);
                } catch (UsbException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
        }
    }
    View Code
  • 相关阅读:
    跨域
    关于DEDECMS自定义模型当中添加自定义字段后在后台添加内容后不显示解决方案
    js复制文本
    dedecms 织梦显示时间格式
    基本特效:饿了么丝滑无缝过度搜索栏的实现
    2016-wing的年度总结
    这交互炸了(四) :一分钟让你拥有微信拖拽透明返回PhotoView
    这交互炸了(三):闪屏页是像云一样消失的
    这交互炸了(二):爱范儿是如何让详情页缩小为横向列表的
    这交互炸了:饿了么是怎么让Image变成详情页的
  • 原文地址:https://www.cnblogs.com/sowhat4999/p/4572720.html
Copyright © 2011-2022 走看看