首页 > 编程语言 >在 Java 应用程序中访问 USB 设备

在 Java 应用程序中访问 USB 设备

时间:2023-09-12 10:37:02浏览次数:43  
标签:Java USB 应用程序 API 接口 JSR 设备


介绍 USB、jUSB 和 JSR-80


Java 平台一直都以其平台无关性自豪。虽然这种无关性有许多好处,但是它也使得编写与硬件交互的 Java 应用程序的过程变得相当复杂。在本文中,研究科学家蒋清野讨论了两个项目,它们通过提供使Java 应用程序可以使用 USB 设备的 API 而使这个过程变得更容易。虽然这两个项目仍然处于萌芽状态,但是它们都显示了良好的前景,并已经成为一些实用应用程序的基础。

蒋清野研究科学家, HappyFox Engineering Solutions

2003 年 10 月 25 日

在 Java 应用程序中访问 USB 设备_Java

内容


通用串行总线(Universal Serial Bus USB)规范的第一个版本发表于 1996年 1月。因为它的低成本、高数据传输率、使用容易和灵活性,USB 在计算机行业里获得了广泛接受。今天,许多周边设备和装置都是通过 USB 接口连接到计算机上的。目前,大多数一般用途的操作系统都提供了对 USB 设备的支持,并且用 C 或者 C++ 可以相对容易地开发访问这些外设的应用程序。不过,Java 编程语言在设计上对硬件访问提供的支持很少,所以编写与 USB 设备交互的应用程序是相当困难的。

IBM 的 Dan Streetman 最早开始了在 Java 语言中提供对 USB 设备的访问的努力。2001年,他的项目通过 Java 规范请求(Java Specification Request,JSR)过程被接受为 Java 语言的候选扩展标准。这个项目现在称为 JSR-80 并且指定了官方包 javax.usb 。同时,在 2000年 6月,Mojo Jojo 和 David Brownell 在 SourceForge 开始了 jUSB 项目。这两个项目都开发出了 Linux 开发人员可以使用的包,尽管它们都还很不完善。这两个项目也都开始试图向其他操作系统上的 Java 应用程序提供对 USB 设备的访问,尽管它们都还没有开发出可以使用的包(参阅 参考资料 中有关本文中讨论的这两个项目及其他项目的资料)。

在本文中,将对 jUSB 和 JSR-80 项目作一个简要介绍,不过,我们首先要看一下 USB 协议的具体细节,这样您就可以理解这两个项目是如何与 USB 设备交互的。我们还将提供代码片段以展示如何用这两个项目的 API 访问 USB 设备。

USB 介绍

1994年,一个由四个行业伙伴(Compaq、Intel、Microsoft 和 NEC)组成的联盟开始制定 USB 协议。该协议最初的目的是将 PC 与电话相连并提供容易扩展和重新配置的 I/O 接口。1996年 1月,发表了 USB 规范的第一个版本,1998年 9月发表了后续版本(版本 1.1)。这个规范允许 127台设备同时连接到一起,总的通信带宽限制为 12 Mbps。后来,又有三个成员(Hewlett-Packard、Lucent 和 Philips)加入了这个联盟。2000年 4月,发表了 USB 规范的 2.0版本,它支持高达 480 Mbps 的传输率。今天,USB 在高速(视频、图像、储存)和全速(音频、宽带、麦克风)数据传输应用中起了关键作用。它还使各种低速设备(键盘、鼠标、游戏外设、虚拟现实外设)连接到 PC 上。

USB 协议有严格的层次结构。在所有 USB 系统中,只有一个主设备,到主计算机的的 USB 接口称为 主控器(host controller)。主控器有两个标准――开放主控器接口(Compaq 的 Open Host Controller Interface,OHCI)和通用主控器接口(Intel 的 Universal Host Controller Interface,UHCI)。这两个标准提供了同样的能力,并可用于所有的 USB 设备,UHCI 的硬件实现更简单一些,但是需要更复杂的设备驱动程序(因而 CPU 的负荷更大一些)。

USB 物理互连是分层的星形拓朴,最多有七层。一个 hub 是每个星形的中心,USB 主机被认为是 root hub。每一段连线都是 hub 与 USB 设备的点对点连接,后者可以是为系统提供更多附加点的另一个 hub,也可以是一个提供功能的某种设备。主机使用主/从协议与 USB 设备通信。这种方式解决了包冲突的问题,但是同时也阻止了附加的设备彼此建立直接通信。

所有传输的数据都是由主控器发起的。数据从主机流向设备称为 下行(downstream)或者 输出(out)传输,数据从设备流向主机称为 上 行(upstream)或者 输入(in)传输。数据传输发生在主机和 USB 设备上特定的 端点(endpoint) 之间,主机与端点之间的数据链接称为 管道(pipe)。 一个给定的 USB 设备可以有许多个端点,主机与设备之间数据管道的数量与该设备上端点的数量相同。一个管道可以是单向或者是双向的,一个管道中的数据流与所有其他管道中的数据流无关。

USB 网络中的通信可以使用下面四种数据传输类型中的任意一种:

  • 控制传输:这些是一些短的数据包,用于设备控制和配置,特别是在设备附加到主机上时。
  • 批量传输:这些是数量相对大的数据包。像扫描仪或者 SCSI 适配器这样的设备使用这种传输类型。
  • 中断传输:这些是定期轮询的数据包。主控器会以特定的间隔自动发出一个中断。
  • 等时传输:这些是实时的数据流,它们对带宽的要求高于可靠性要求。音频和视频设备一般使用这种传输类型。

像串行端口一样,计算机上每一个 USB 端口都由 USB 控制器指定了一个惟一的标识数字(端口 ID)。当 USB 设备附加到 USB 端口上时,就将这个 惟一端口 ID 分配给这台设备,并且 USB 控制器会读取 设备描述符。设备描述符包括适用于该设备的全局信息、以及设备的 配置信息。配置定义了一台 USB 设备的功能和 I/O 行为。一台 USB 设备可以有一个或者多个配置,这由它们相应的配置描述符所描述。每一个配置都有一个或者多个 接口,它可以视为一个物理通信渠道 ;每一个接口有零个或者多个端点,它可以是数据提供者或者数据消费者,或者同时具有这两种身份。接口由接口描述符描述,端点由端点描述符描述。并且一台 USB 设备可能还有字符串描述符以提供像厂商名、设备名或者序列号这样的附加信息。

正如您所看到的,像 USB 这样的协议为使用 Java 这种强调平台和硬件无关性的语言的开发人员提出了挑战。现在让我们看两个试图解决这个问题的项目。



回页首

jUSB API

jUSB 项目是由 Mojo Jojo 和 David Brownell 于 2000年 6月创立的。其目标是提供一组免费的、在 Linux 平台上访问 USB 设备的 Java API。这个 API 是按照 Lesser GPL (LGPL)条款发表的,这意味着您可以在专有和免费软件项目中使用它。这个 API 提供了对多个物理 USB 设备的多线程访问,并支持本机和远程设备。具有多个接口的设备可以同时被多个应用程序(或者设备驱动程序)所访问,其中每一个应用程序(或者设备驱动程序)都占据一个不同的接口。该 API 支持控制传输、批量传输和中断传输,不支持等时传输,因为等时传输用于媒体数据(如音频和视频),JMF API 已经在其他标准设备驱动程序上对此提供了很好的支持(参阅 参考资料)。当前,该 API 可以在具有 Linux 2.4 核心或者以前的 2.2.18 核心的 GNU/Linux 版本上工作。因此可支持大多数最新的版本,例如,该 API 可以在没有任何补丁或者升级的 Red Hat 7.2 和 9.0 上工作。

jUSB API 包括以下包:

在 Java 应用程序中访问 USB 设备_java_02

尽管 usb.core.Host 对象的实现对于不同的操作系统是不同的,但是 Java 程序员只需要理解 usb.core 包就可以用 jUSB API 开始应用程序的开发。表 1 列出了 usb.core 的接口和类,Java 程序员应该熟悉它们:

表 1. jUSB 中的接口和类

接口

说明

Bus

将一组 USB 设备连接到 Host 

Host

表示具有一个或者多个 Bus 的 USB 控制器

说明

Configuration

提供对设备所支持的 USB 配置的访问,以及对与该配置关联的接口的访问

Descriptor

具有 USB 类型的描述符的实体的基类

Device

提供对 USB 设备的访问

DeviceDescriptor

提供对 USB 设备描述符的访问

EndPoint

提供对 USB 端点描述符的访问、在给定设备配置中构造设备数据输入或者输出

HostFactory

包含 bootstrapping 方法

Hub

提供对 USB hub 描述符以及一些 hub 操作的访问

Interface

描述一组端点,并与一个特定设备配置相关联

PortIdentifier

为 USB 设备提供稳定的字符串标识符,以便在操作和故障诊断时使用

在 Java 应用程序中访问 USB 设备_Java_03

清单 1 展示了如何用 jUSB API 获得 USB 系统中的内容。这个程序编写为只是查看 root hub 上可用的 USB 设备,但是很容易将它改为遍历整个 USB 树。这里的逻辑对应于上述步骤 1 到步骤 4。

清单 1. 用 jUSB API 获得 USB 系统的内容



import usb.core.*;
 
public class ListUSB
{
    public static void main(String[] args)
    {
        try
        {
            // Bootstrap by getting the USB Host from the HostFactory.
            Host   host = HostFactory.getHost();
 
            // Obtain a list of the USB buses available on the Host.
            Bus[]  bus  = host.getBusses();
            int    total_bus = bus.length;
 
            // Traverse through all the USB buses.
            for (int i=0; i<total_bus; i++)
            {
                // Access the root hub on the USB bus and obtain the
                // number of USB ports available on the root hub.
                Device root = bus[i].getRootHub();
                int total_port = root.getNumPorts();
 
                // Traverse through all the USB ports available on the 
                // root hub. It should be mentioned that the numbering 
                // starts from 1, not 0.
                for (int j=1; j<=total_port; j++)
                {
                    // Obtain the Device connected to the port.
                    Device device = root.getChild(j);
                    if (device != null)
                    {
                        // USB device available, do something here.
                    }
                }
            }
        } catch (Exception e)
        {
            System.out.println(e.getMessage());
        }
    }


清单 2 展示了在应用程序成功地找到了 Device 的条件下,如何与 Interface 和 EndPoint 进行批量 I/O。 这个代码段也可以修改为执行控制或者中断 I/O。它对应于上述步骤 5。

清单 2. 用 jUSB API 执行批量 I/O



if (device != null)
   {
       // Obtain the current Configuration of the device and the number of 
       // Interfaces available under the current Configuration.
       Configuration config = device.getConfiguration();
       int total_interface = config.getNumInterfaces();
 
       // Traverse through the Interfaces
       for (int k=0; k<total_interface; k++)
       {
           // Access the currently Interface and obtain the number of 
           // endpoints available on the Interface. 
           Interface itf = config.getInterface(k, 0);
           int total_ep  = itf.getNumEndpoints();
 
           // Traverse through all the endpoints.
           for (int l=0; l<total_ep; l++)
           {
               // Access the endpoint, and obtain its I/O type.
               Endpoint ep = itf.getEndpoint(l);
               String io_type = ep.getType();
               boolean input  = ep.isInput();
 
               // If the endpoint is an input endpoint, obtain its
               // InputStream and read in data.
               if (input)
               {
                   InputStream in;
                   in = ep.getInputStream();
                   // Read in data here
                   in.close();
               }
               // If the Endpoint is and output Endpoint, obtain its 
               // OutputStream and write out data.
               else
               {
                   OutputStream out;
                   out = ep.getOutputStream();
                   // Write out data here.
                   out.close();
               }
           }
       }
    }



jUSB 项目在 2000年 6月到 2001年 2月期间非常活跃。该 API 的最新的版本 0.4.4发表于 2001年 2月 14日。从那以后只提出了很少的改进,原因可能是 IBM 小组成功地成为了 Java 语言的候选扩展标准。不过,基于 jUSB 已经开发出一些第三方应用程序,包括 JPhoto 项目(这是一个用 jUSB 连接到数码照相机的应用程序)和 jSyncManager 项目(这是一个用 jUSB 与使用 Palm 操作系统的 PDA 同步的应用程序)。



 



回页首

JSR-80 API (javax.usb)

正如前面提到的,JSR-80 项目是由 IBM 的 Dan Streetman 于 1999年创立的。2001年,这个项目通过 Java 规范请求(JSR)过程被接受为 Java 语言的候选扩展标准。这个项目现在称为 JSR-80 并且被正式分派了 Java 包 javax.usb 。这个项目使用 Common Public License 的许可证形式,并通过 Java Community Process 进行开发。这个项目的目标是为 Java 平台开发一个 USB 接口,可以从任何 Java 应用程序中完全访问 USB 系统。JSR-80 API 支持 USB 规范所定义的全部四种传输类型。目前,该 API 的 Linux 实现可以在支持 2.4 核心的大多数最新 GNU/Linux 版本上工作,如 Red Hat 7.2 和 9.0。JSR-80 项目包括三个包: javax-usb ( javax.usb API)、 javax-usb-ri (操作系统无关的基准实现的公共部分)以及 javax-usb-ri-linux(Linux 平台的基准实现,它将公共基准实现链接到 Linux USB 堆栈)。所有这三个部分都是构成 Linux 平台上 java.usb API 完整功能所必需的。在该项目的电子邮件列表中可以看到有人正在致力于将这个 API 移植到其他操作系统上(主要是 Microsoft Windows),但是还没有可以工作的版本发表。尽管 JSR-80 API 的操作系统无关的实现在不同的操作系统上是不同的,但是 Java 程序员只需要理解 javax.usb 包就可以开始开发应用程序了。表 2 列出了 javax.usb 中的接口和类, Java 程序员应该熟悉它们:

表 2. JSR-80 API 中的接口和类

接口

说明

UsbConfiguration

表示 USB 设备的配置

UsbConfigurationDescriptor

USB 配置描述符的接口

UsbDevice

USB 设备的接口

UsbDeviceDescriptor

USB 设备描述符的接口

UsbEndpoint

USB 端点的接口

UsbEndpointDescriptor

USB 端点描述符的接口

UsbHub

USB hub 的接口

UsbInterface

USB 接口的接口

UsbInterfaceDescriptor

USB 接口描述符的接口

UsbPipe

USB 管道的接口

UsbPort

USB 端口的接口

UsbServices

javax.usb 实现的接口

说明

UsbHostManager

javax.usb 的入口点

用 JSR-80 API 访问 USB 设备的正常过程如下:

在 Java 应用程序中访问 USB 设备_API_04

在清单 3 中,我们用 JSR-80 API 获得 USB 系统的内容。这个程序递归地遍历 USB 系统上的所有 USB hub 并找出连接到主机计算机上的所有 USB 设备。这段代码对应于上述步骤 1 到步骤 3。

清单 3. 用 JSR-80 API 获得 USB 系统的内容



import javax.usb.*;
import java.util.List;
 
public class TraverseUSB
{
        public static void main(String argv[])
        {
          try
          {
              // Access the system USB services, and access to the root 
              // hub. Then traverse through the root hub.
              UsbServices services = UsbHostManager.getUsbServices();
              UsbHub rootHub = services.getRootUsbHub();
              traverse(rootHub);
          } catch (Exception e) {}
        }
 
        public static void traverse(UsbDevice device)
        {
          if (device.isUsbHub())
          {   
             // This is a USB Hub, traverse through the hub.
             List attachedDevices = 
                 ((UsbHub) device).getAttachedUsbDevices();
             for (int i=0; i<attachedDevices.size(); i++)
             {
               traverse((UsbDevice) attachedDevices.get(i));
             }
          }
          else
          {
             // This is a USB function, not a hub.
             // Do something.
          }
        }
}


清单 4 展示了在应用程序成功地找到 Device 后,如何与 Interface 和 EndPoint 进行 I/O。这段代码还可以修改为进行所有四种数据传输类型的 I/O。它对应于上述步骤 4 到步骤 6。

清单 4. 用 JSR-80 API 进行 I/O



public static void testIO(UsbDevice device)
{
    try
    {
       // Access to the active configuration of the USB device, obtain 
       // all the interfaces available in that configuration.
       UsbConfiguration config = device.getActiveUsbConfiguration();
       List totalInterfaces = config.getUsbInterfaces();
        
       // Traverse through all the interfaces, and access the endpoints 
       // available to that interface for I/O.
       for (int i=0; i<totalInterfaces.size(); i++)
       {
          UsbInterface interf = (UsbInterface) totalInterfaces.get(i);
          interf.claim();
          List totalEndpoints = interf.getUsbEndpoints();
          for (int j=0; j<totalEndpoints.size(); j++)
          {
             // Access the particular endpoint, determine the direction
             // of its data flow, and type of data transfer, and open the 
             // data pipe for I/O.
             UsbEndpoint ep = (UsbEndpoint) totalEndpoints.get(i);
             int direction = ep.getDirection();
             int type = ep.getType();
             UsbPipe pipe = ep.getUsbPipe();
             pipe.open();
             // Perform I/O through the USB pipe here.
             pipe.close();
          }
          interf.release();
       }
    } catch (Exception e) {} 
}


JSR-80 项目从一开始就非常活跃。2003年 2月发表了 javax.usb API、RI 和 RI 的 0.10.0 版本。看起来这一版本会提交给 JSR-80 委员会做最终批准。预计正式成为 Java 语言的扩展标准后,其他操作系统上的实现会很快出现。Linux 开发者团体看来对 JSR-80 项目的兴趣比 jUSB 项目更大,使用 Linux 平台的 javax.usb API 的项目数量在不断地增加。


 



回页首

结束语

jUSB API 和 JSR-80 API 都为应用程序提供了从运行 Linux 操作系统的计算机中访问 USB 设备的能力。JSR-80 API 提供了比 jUSB API 更多的功能,很有可能成为 Java 语言的扩展标准。目前,只有 Linux 开发人员可以利用 jUSB 和 JSR-80 API 的功能。不过,有人正在积极地将这两种 API 移植到其他操作系统上。Java 开发人员应该在不久就可以在其他操作系统上访问 USB 设备。从现在起就熟悉这些 API,当这些项目可以在多个平台上发挥作用时,您就可以在自己的应用程序中加入 USB 功能了。



参考资料



================================================================

http://www.ibm.com/developerworks/cn/java/j-usb/

标签:Java,USB,应用程序,API,接口,JSR,设备
From: https://blog.51cto.com/u_16255870/7443167

相关文章

  • javascript事件循环机制及面试题详解
    javascript事件循环机制及面试题详解 javascript是单线程执行的程序,也就是它只有一条主线,所有的程序都是逐行“排队”执行,在这种情况下可能存在一些问题,比如说setTimeout、ajax等待执行的时间较长,就会阻塞后续代码的执行,使得整个程序执行的耗时非常久,那么为了应对这样一个问......
  • Vue.js的index.html文件中引入JavaScript文件
    将js文件放在public文件夹下面在index.html文件下引入js文件在前面加<%=BASE_URL%>后面加路径,如果想将本地js文件打包之后也放在static/js文件夹下,需要在public文件夹下创建一个和打包之后文件放的位置一样的文件夹<scriptsrc="<%=BASE_URL%>./static/js/js文件名"></sc......
  • javascript:window.print() 打印
    1.JavaScript打印<inputid="btnPrint"type="button"value="button"οnclick="javascript:window.print();"style="color:#00f;font-weight:bold;text-decoration:none;cursor:pointer!important;cursor:hand"/>......
  • tomcat 分配java内存
    //首先检查程序有没有限入死循环这个问题主要还是由这个问题java.lang.OutOfMemoryError:Javaheapspace引起的。第一次出现这样的的问题以后,引发了其他的问题。在网上一查可能是JAVA的堆栈设置太小的原因。跟据网上的答案大致有这两种解决方法:1、设置环境变量setJAVA_OPTS=-......
  • 解决IDEA不编译java目录下的xml文件
    对于IDEA系列编辑器,XML文件是不能放在java文件夹中的,IDEA默认不会编译源码文件夹中的XML文件,可以参照以下方式解决:<build><resources><resource><!--xml放在java目录下--><directory>src/main/java</directory><includes>......
  • Java获取时间戳的三种方式
    Java获取时间戳的三种方式System类中的currentTimeMillis()方法是三种方式中效率最好的,运行时间最短newDate()其实就是调用了System.currentTimeMillis(),再传入自己的有参构造函数Canlendar是区分时区的System.out.println(System.currentTimeMillis());//推荐使用Syste......
  • Java程序启动时执行某个方法
    很多时候我们都会碰到需要在程序启动时去执行的方法,比如说去读取某个配置,预加载缓存,定时任务的初始化等。1、使用@PostConstruct注解这个注解可以在Spring加载这个类的时候执行一次。@PostConstructprivatevoidinit(){//todo}注意:1、只有一个非静态方法能使用此注......
  • java.lang.ClassCastException: java.sql.Timestamp cannot be cast to java.lang.Str
    这个问题来自于想把从数据库查询的数据转化为字符串,方便后面做时间比较,显示格式转化错误 sql改造部分 as的左边为我的sql语句语法使用如下DATE_FORMAT((sql语句),'%Y-%m-%d%H:%i:%s')如果是涉及时间的计算,可以考虑如下方式BigDecimala=(BigDecimal)sprint......
  • SPI在Java中的实现与应用 | 京东物流技术团队
    1SPI的概念APIAPI在我们日常开发工作中是比较直观可以看到的,比如在Spring项目中,我们通常习惯在写service层代码前,添加一个接口层,对于service的调用一般也都是基于接口操作,通过依赖注入,可以使用接口实现类的实例。简单形容就是这样的:图1:API如上图所示,服务调用方无需关......
  • javafx列表不显示内容
    今天在做测试项目的时候,出现了个问题,就是列表内容不显示。找了N多原因1 是不是数据的问题-》数据没问题2没有对应取值=》对应了奇葩了。。。不知道为什么,陷入了停滞。 打开断点,逐行排查,找到原因了。。。。原来如此我在程序里,做了一个预加载。将所有的页面全部放到了has......