基於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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM