PDA

View Full Version : Tương tác thiết bị USB từ ứng dụng Java



Kevin Hoang
15-03-2012, 09:56 PM
Tập 1: Hiểu về USB Protocol và những khó khăn trong việc tương tác thiết bị USB từ ứng dụng Java

Phiên bản đầu tiên của Universal Serial Bus (USB) được đưa ra và phát hành vào năm 1996. Thiết bị USB có giá thành thấp, tốc độ truyền tải dữ liệu cao, dễ dàng sử dụng và mềm dẻo đã nhanh chóng được chấp nhận rộng rãi trong ngành công nghiệp máy tính. Cho đến hiện nay, rất nhiều thiết bị ngoại vi và các thiết bị khác kết nối với máy tính thông qua USB. Phần lớn các hệ điều hành phổ biến đều hỗ trợ tốt đối với các thiết bị USB, tương đối dễ dàng để phát triển ứng dụng tương tác USB trong C/C++ . Tuy nhiên, Java được thiết kế hỗ trợ rất ít để truy cập vào phần cứng (hardware), vì thế viết một ứng dụng Java để tương tác với các thiết bị USB khá vất vả.

Sự lỗ lực cố gắng để truy cập vào các thiết bị USB trong Java được bắt đầu năm 1999 bởi Dan Streetman tại IBM. Năm 2001, project của anh đã được chấp nhận như một chuẩn mở rộng (candidate extended standard) của Java thông qua Java Specification Request (JSR). Project này bây giờ gọi là JSR-80 đã được chính thức công khai dưới package javax.usb. Trong thời gian đó, khoảng tháng 01/2000 Mojo Jojo và David Brownell đã bắt đầu project Java USB trên SourceForge. Cả 2 project này đều đưa ra packages cho các Linux Developers, mặc dù cả 2 gần như đã hoàn hảo. Cả 2 project đều bắt đầu lỗ lực cung cấp khả năng truy cập thiết bị USB cho ứng dụng Java trên các hệ điều hành khác, tuy nhiên các packages không có sự nổi trội rõ nét.

Trong bài viết này, bạn sẽ được giới thiệu ngắn gọn về 2 project này. Nhưng trước hết hãy tìm hiểu một chút về USB

Giới thiệu về USB
Năm 1994, sự liên minh cộng tác của 4 công ty công nghiệp máy tính lớn (Compaq, Intel, Microsoft, và NEC) đã bắt đầu đưa ra USB Protocol. Mục tiêu ban đầu của Protocol này là kết nối máy tính PC với Telephone và cung cấp giao diện nhập xuất I/O có khả năng dễ dàng mở rộng và cấu hình. Tháng 1/1996, phiên bản đầu tiên của USB specification đã được phát hành, tiếp ngay sau đó là revision (version 1.1) được phát hành vào tháng 9/1998. Trong bản đặc tính kỹ thuật này đã cho phép 127 thiết bị connnect với nhau ở cùng thời điểm, với tổng cộng băng thông giao tiếp giới hạn đến 12MBs. Sau đó, có nhiều thành viên hơn (Hewlett-Packard, Lucent, và Philips) tham gia vào liên minh. Tháng 4/2000, phiên bản 2.0 của USB specification hỗ trợ transfer rate lên đến 480Mbs đã được phát hành. Hiện nay, USB đóng vai trò quan trọng trong các ứng dụng truyền dữ liệu tốc độ cao (video, image, storage) và băng thông rộng (audio, broadband, microphone). Cũng đa dạng hóa trong việc kết nối các thiết bị tốc độ thấp (keyboards, mice, game peripherals, virtual reality peripherals) với máy tính PC.

USB protocol là giao thức có thứ bậc. Trong bất kỳ hệ thống USB nào chỉ có duy nhất 1 host, và USB interface với host computer được xem là host controller. Có 2 chuẩn cho host controller đó là: Open Host Controller Interface (OHCI, by Compaq) và Universal Host Controller Interface (UHCI, by Intel). Cả 2 chuẩn cung cấp khả năng như nhau và làm việc với toàn bộ thiết bị USB. Xây dựng hardware cho UHCI đơn giản hơn, nhưng đòi hỏi device driver phức tạp hơn (hao tốn tài nguyên CPU hơn)

Kết nối vật lý của USB là cấu trúc sao tầng, lên tới 7 tầng. Một hub tại trung tâm, và USB host được hiểu là root hub. Mỗi phân đoạn là kết nối từng điểm giữa 1 hub và USB device; sau đó có thể một hub khác cung cấp bổ sung các điểm đính kèm vào hệ thống, hoặc 1 thiết bị hoặc một vài loại có khả năng. Host sử dụng một giao thức master/subordinate để giao tiếp với các USB device. Cách tiếp cận này đã giải quyết được vấn đề các gói dữ liệu đụng độ với nhau và ngăn ngừa các thiết bị được đính kèm liên lạc trực tiếp với nhau.

Toàn bộ việc truyền dữ liệu được khởi tạo bởi host controller. Dữ liệu được truyền thẳng từ host tới thiết bị được gọi là downstream hay out transfer, dữ liệu được truyền thẳng từ thiết bị tới host được gọi là upstream hay in transfer. Việc truyền dữ liệu được xảy ra gữa host và một endpoint riêng biệt trong thiết bị USB, việc liên kết dữ liệu giữa host và endpoint được gọi là pipe. Một thiết bị USB có thể có nhiều endpoint, số lượng của data pipes giữa host và thiết bị bằng số endpoints của thiết bị. Một pipe có thể là đơn hướng hoặc đa hướng, dòng dữ liệu trong 1 pipe là độc lập với dòng dữ liệu trong các pipe khác.

Việc giao tiếp trong mạng USB có thể sử dụng bất kỳ 1 trong 4 loại kiểu truyền dữ liệu:
Control transfers: Là các gói dữ liệu ngắn đối với việc điều khiển và cấu hình thiết bị, đặc biệt là lúc đính kèm thời gian
Bulk transfers: Là các gói dữ liệu tương đối lớn. Thiết bị như máy scan hoặc SCSI adapter sử dụng kiểu truyền dữ liệu này.
Interrupt transfers: Các gói dữ liệu được điều tra định kỳ. Host controller sẽ tự động gửi một interrupt trong một khoảng thời gian nhất định.
Isochronous transfers: Luồng dữ liệu theo thời gian thực với yêu cầu cao hơn về băng thông và độ tin cậy. Các thiết bị âm thanh, video thường sử dụng kiểu truyền dữ liệu này.

Giống như serial port, một USB Port trong máy tính được gán một số định danh duy nhất gọi là Port ID bởi USB controller. Khi một thiết bị USB đính kèm vào một USB Port. Post ID sẽ được gán cho thiết bị và bộ nhận diện thiết bị(device descriptor) được đọc bởi USB controller, device descriptor kèm theo các thông tin được áp dụng trên toàn cầu vào thiết bị cũng như thông tin cấu hình của thiết bị đó. Một cấu hình định nghĩa các chức năng và các ứng xử trong việc nhập xuất của thiết bị. Một thiết bị USB có thể có nhiều cấu hình được miêu tả bởi cấu hình tương ứng của chúng. Mỗi cấu hình có một hoặc nhiều interfaces được hiểu là kênh giao tiếp vật lý. Mỗi interface có không hoặc nhiều endpoints có thể là dữ liệu của nhà cung cấp, hoặc dữ liệu người dùng, hoặ cả 2. Interfaces được miêu tả bởi bộ nhận diện interface (interface descriptors) và endpoints được miêu tả bởi bộ nhận diện endpoints (end-point descriptors). Hơn nữa, một thiết bị có thể có một chuỗi descriptors để cung cấp bổ sung thông tin chẳng hạn như vendor name, device name, hoặc serial numbers

Như bạn đã thấy, một protocol như USB đã đưa ra một nhiệm vụ khó khăn cho developer sử dụng Java, ngôn ngữ cố gắng cho việc sử dụng trên nhiều platform không phụ thuộc vào phần cứng.

Tài liệu được dịch từ IBM Developer Works Library bởi Kevin Hoang dành cho thành viên cộng đồng C Việt!

Hết tập 1

Kevin Hoang
15-03-2012, 09:59 PM
Tập 2: Tìm hiểu về jUSB API

Project jUSB được tạo ra bởi Mojo Jojo và David Brownell vào tháng 6 năm 2000. Mục đích của project này là cung cấp một bộ Java APIs miễn phí để tương tác với thiết bị USB trên Linux platforms. API được bảo vệ dưới giấy phép Lesser GPL (LGPL), điều này có nghĩa là bạn có thể sử dụng nó trong các project bản quyền hoặc miễn phí đều được. API này cung cấp nhiều luồng để tương tác với nhiều USB vật lý, hỗ trợ cả 2 loại thiết bị native và remote USB. Các thiết bị có nhiều interfaces có thể được tương tác bởi nhiều ứng dụng hoặc nhiều device drivers đồng thời, với điều kiện mỗi ứng dụng hoặc mỗi device driver khai thác 1 interface. API này hỗ trợ các kiểu truyền dữ liệu control transfers, bulk transfers, và interrupt transfers, riêng isochronous transfers không hỗ trợ vì kiểu truyền dữ liệu này được sử dụng trong các media data (audio, video), kiểu truyền dữ liệu này đã được hỗ trợ rất tốt bởi JMF API trên các thiết bị tiêu chuẩn khác. jUSB API hoạt động tốt trên các phiên bản GNU/Linux với Linux Kernel từ 2.2 trở lên.

jUSB API bao gồm cả packages sau:
usb.core: Package này là phần core của jUSB API cho phép Java applications tương tác với thiết bị USB từ USB hosts.
usb.linux: Package này chứa Linux implementation của usb.core.Host object, hỗ trợ bootstrapping, và các lớp khác tận dụng sự hỗ trợ của Linux USB. Việc Implementation này giúp tương tác với thiết bị USB devices thông qua thiết bị USB ảo là file system (usbdevfs).
usb.windows: Package này chứa Windows implementation của usb.core.Host object, hỗ trợ bootstrapping, và các lớp khác tận dụng sự hỗ trợ của Windows USB. Việc Implementation vẫn còn ở giai đoạn đầu tiên.
usb.remote: Package này là remote version của usb.core API. Nó bao gồm một RMI proxy và một daemon application cho phép Java applications tương tác với thiết bị USB devices trên một remote computer.
usb.util: Package này cung cấp một vài tiện ích để download firmware cho thiết bị USB, dump nội dung của USB system vào XML, và chuyển đổi một thiết bị USB chỉ với một bulk I/O vào trong một socket.
usb.devices: Đây là optional package tổng hợp Java code để tương tác một vài loại thiết bị USB với jUSB API, bao gồm có máy ảnh Kodak digital và Rio 500 MP3 Players. Các APIs này là viết thêm để đơn giản hóa quá trình tương tác với các thiết bị USB được thiết kế không thể sử dụng để tương tác từ các thiết bị khác. Các APIs được xây dựng trên usb.core APIs, và nó sẽ hoạt động trên bất kỳ hệ điều hành nào mà jUSB API hỗ trợ.
usb.view: Đây là optional package cung cấp một trình duyệt USB đơn giản dạng cây dựa trên Swing. Nó là một chương trình ví dụ tốt để miêu tả việc sử dụng jUSB API.

Mặc dù implementation của usb.core.Host object biến đổi theo hệ điều hành, một Java programmer chỉ cần hiểu usb.core package để bắt đầu phát triển ứng dụng với jUSB APIs. Bảng sau sẽ là hình dáng bên ngoài interfaces và classes của usb.core cái mà một Java programmer có lẽ đã quen thuộc.



Interface Miêu tả
Bus Kết nối một bộ các thiết bị USB từ 1 Host
Host Đại diện cho một USB controller với một hoặc nhiều Bus

Class Description
Configuration Cung cấp khả năng tương tác một cấu hình USB được hỗ trợ bởi một thiết bị kết hợp với interfaces
Descriptor Base class cho các thực thể kiểu USB descriptors
Device Cung cấp khả năng tương tác thiết bị USB
DeviceDescriptor Cung cấp khả năng tương tác thiết bị USB descriptor
EndPoint Cung cấp khả năng tương tác USB end-point descriptor, cấu trúc dữ liệu thiết bị đầu ra hoặc đầu vào trong một cấu hình thiết bị đã cho
HostFactory Chứa bootstrapping methods
Hub Cung cấp khả năng tương tác thiết bị USB hub descriptor và một vài hoạt động của hub
Interface Miêu tả một bộ endpoints, và kết hợp với một cấu hình thiết bị cụ thể
PortIdentifier Cung cấp chuỗi nhận dạng ổn định đối với các thiết bị USB, thích hợp đối với việc sử dụng trong các hoạt động hoặc sự cố

Một thủ tục bình thường để tương tác thiết bị USB bằng jUSB API sẽ như sau:
1. Bootstrap bằng lấy USB Host từ HostFactory
2. Tương tác USB Bus từ Host, sau đó tương tác USB root hub từ Bus
3. Xác định số lượng USB port sẵn sàng trên Hub, duyệt qua tất cả các Port để tìm thiết bị thích hợp
4. Tương tác USB Device đã được gắn vào một Port cụ thể. Một thiết bị có thể được tương tác trực tiếp từ Host dựa vào cổng định danh, hoặc có thể thấy bằng duyệt qua các USB Bus bắt đầu từ root hub
5. Tương tác với thiết bị trực tiếp với ControlMessage hoặc yêu cầu một Interface từ cấu hình của thiết bị và thực hiện nhập xuất với Endpoint sẵn sàng trên Interface đó.

Ví dụ 1: Lấy nội dung của một thiết bị USB với jUSB API.



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());
}
}
}


Ví dụ 2: Thực hiện bulk I/O với Interface và EndPoint


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();
}
}
}
}


Project jUSB hoạt động sôi nổi từ tháng 6 năm 2000 đến tháng 2 năm 2001. Phiên bản gần đây nhất là 0.4.4 được phát hành vào ngày 14 tháng 2 năm 2001. Chỉ một vài quá trình nhỏ được tuyên bố (reported) vào thời gian này, gần như chắc chắn là do sự thành công của IBM group trong việc trở thành một chuẩn mở rộng (candidate extended standard) của Java language. Tuy nhiên, một số ứng dụng đã được dựa trên jUSB, bao gồm có project JPhoto (một ứng dụng sử dụng jUSB để kết nối tới máy ảnh kỹ thuật số) và dựa án jSyncManager (một ứng dụng sử dụng jUSB để đồng bộ với một Palm OS-based PDA).

Tài liệu được dịch từ IBM Developer Works Library bởi Kevin Hoang dành cho thành viên cộng đồng C Việt!

Hết tập 2

Kevin Hoang
16-03-2012, 05:12 PM
Tập 3: Tìm hiểu về JSR-80 API (javax.usb)

Giống như tập 1 đã đưa ra, JSR-80 project được tạo bởi Dan Streetman tại IBM năm 1999. Năm 2011, project này đã được chấp nhận như là một chuẩn mở rộng (candidate extended standard) của Java thông qua Java Specification Request (JSR). Project này đến nay được gọi là JSR-80 đã được chính thức công khai dưới package javax.usb. Project này được bảo vệ dưới giấy phép Common Public License (CPL) và được phát triển sử dụng Java Community Process. Mục tiêu của project này là phát triển một USB interface cho Java platform mà cho phép full access vào USB system đối với bất kỳ Java Application hoặc middleware component nào. JSR-80 API hỗ trợ đầy đủ 4 kiểu truyền dữ liệu đã được định nghĩa bởi USB specification. Hiện tại, phần Linux implementation của API này hoạt động trên hầu hết các phiên bản GNU/Linux gần đây với Kernel 2.4 trở lên.

JSR-80 project bao gồm 3 packages: javax-usb (javax.usb API), javax-usb-ri (phần thông dụng của việc implementation tham chiếu với các hệ điều hành độc lập nhau), và javax-usb-ri-linux (phần implementation cho Linux platform, kết nối việc implementation tham chiếu thông dụng với Linux USB stack). Tất cả 3 phần này là yêu cầu để tạo nên một tính năng đầy đủ của java.usb API trên Linux platform. Các lỗ lực để không phụ thuộc vào hệ điều hành (OS-independent) đối với việc porting API tới các hệ điều hành khác đã được reported trong email-list của project, nhưng chưa có bất kỳ một tính năng hoặc packages nào được phát hành.

Mặc dù việc implementation của JSR-80 APIs là biến đổi theo từng hệ điều hành (OS-dependent), một Java programmer chỉ cần hiểu javax.usb package để có thể bắt đầu phát triển ứng dụng. Bảng sau sẽ là hình dáng bên ngoài interfaces và classes của javax.usb cái mà một Java programmer có lẽ đã quen thuộc.



Interface Description
UsbConfiguration Đại diện cho một cấu hình của USB device
UsbConfigurationDescriptor Interface for a USB configuration descriptor
UsbDevice Interface for a USB device
UsbDeviceDescriptor Interface for a USB device descriptor
UsbEndpoint Interface for a USB endpoint
UsbEndpointDescriptor Interface for a USB endpoint descriptor
UsbHub Interface for a USB hub
UsbInterface Interface for a USB interface
UsbInterfaceDescriptor Interface for a USB interface descriptor
UsbPipe Interface for a USB pipe
UsbPort Interface for a USB port
UsbServices Interface for a javax.usb implementation

Class Description
UsbHostManager Entry point for javax.usb

Một thủ tục bình thường để tương tác thiết bị USB bằng JSR-80 API sẽ như sau:
1. Bootstrap bằng việc lấy UsbServices tương ứng từ UsbHostManager
2. Tương tác root hub thông qua UsbServices. Root hub được coi là UsbHub trong ứng dụng
3. Lấy danh sách UsbDevices đã connect với Root hub. Duyệt qua toàn bộ từ cấp thấp nhất của hub để tìm UsbDevice tương ứng
4. Tương tác với UsbDevice trực tiếp bằng một control message (UsbControlIrp) hoặc yêu cầu UsbInterface từ UsbConfiguration tương ứng của UsbDevice và thực hiện nhập xuất I/O với UsbEndpoint trên UsbInterface.
5. Nếu UsbEndpoint được sử dụng để thực hiện nhập xuất I/O, mở UsbPipe kết hợp với nó. Cả upstream data (từ USB device tới host computer) và downstream data (từ host computer tới USB device) có thể được gửi đồng bộ hoặc bất đồng bộ thông qua UsbPipe.
6. Đóng UsbPipe và giải phóng UsbInterface tương ứng khi ứng dụng không còn tương tác với UsbDevice

Ví dụ 1: Lấy nội dung của một thiết bị USB với JSR-80 API.


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.
}
}
}

Ví dụ 2: Thực hiện bulk I/O với Interface và EndPoint


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 project rất sôi nổi trong giai đoạn đầu. Version 0.10.0 của javax.usb API, RI, và RI for Linux đã được phát hành vào tháng 2 năm 2003. Có khả năng phiên bản này sẽ được trình lên ủy ban phê duyệt JSR-80 đối với việc chấp thuận cuối cùng. Dự kiến sẽ implementation cho các hệ điều hành khác sau khi JSR-80 chính thức trở thành chuẩn mở rộng của Java. Cộng đồng phát triển Linux quan tâm đến JSR-80 project nhiều hơn jUSB project bằng chứng là số lượng ngày càng tăng các project sử dụng javax.usb API trên Linux Platform.

Kết luận
Cả 2 project jUSB API và JSR-80 API đều cung cấp khả năng để Java application tương tác thiết bị USB từ một máy chạy Linux. JSR-80 API cung cấp nhiều tính năng hơn jUSB API và có tiền năng lớn trở thành chuẩn mở rộng của Java. Hiện tại, chỉ có Linux Developer có khả năng hưởng các lợi ích của jUSB API và JSR-80 API, tuy nhiên lỗ lực để port sang hệ điều hành khác đã được tuyên bố (reported). Các Java developer có thể tương tác với USB Device trên các hệ điều hành khác trong tương lai gần. Bằng việc làm quen và hiểu các API này, bạn có thể sẵn sàng để thêm chức năng tương tác USB vào ứng dụng của bạn khi các project này sẵn sàng thêm thời gian xây dựng cho multiple platforms.

Tài liệu được dịch từ IBM Developer Works Library bởi Kevin Hoang dành cho thành viên cộng đồng C Việt!

The end

manhdt
16-03-2012, 06:04 PM
Nếu xài máy đọc mã vạch thì cũng sử dụng cách này phải k anh ?

Kevin Hoang
16-03-2012, 07:14 PM
Phần lớn máy đọc mã vạch đâu cần phải làm gì, nó sẽ tự động làm cho bạn như là bạn gõ phím ấy, nghĩa là bạn chỉ cần đặt focus vào một textbox nào đó là bạn sẽ nhận được chuỗi đã được giải mã. Một số ít mới cần đến các công đoạn kỹ thuật.

manhdt
17-03-2012, 05:49 PM
Vâng em cảm ơn gợi ý của anh, em đang có kế hoạch cho dự án kỳ tới và muốn làm 1 app tương tác với máy đọc mã vạch. Vấn đề này cũng hơi ... mông lung ^^. Hỏi nhiều ng thì họ nói phải lập trình driver này nọ, API tương tác với máy đó