泽泽的歌

By , 2004年8月31日 5:54 上午

山歌
http://scms.whedu.net/feeling/8.mp3
词:王泽 曲:王泽  演唱:王泽


花儿花儿,开了 鸟儿鸟儿,唱歌了
春天到了,回声响了
慢慢地走啊走啊 到哪里去啊
随着溪流走啊走啊 沿着山路走啊走啊
口琴在悠悠,流年在水中
他们说年少的往事 山谷回响潮湿
春雨低吟未完的诗 年华已逝

一棵叫Feeling的植物
http://scms.whedu.net/feeling/3.mp3

曲:王泽 演唱:王泽 制作人:侯钧 编曲:孟可
MIDI工程:戴劲松 录音、混音:顾评


朋友,走的时候 留给我一个礼物
那是一棵叫做Feeling的植物
我知道他的一路
都曾有它的相处
他的成长带它一起生长
它的生长支撑他的脚步

它喜欢我心里面的土壤和阳光
偶尔的降雨能使它茁壮
所以它在冬天静静等待一双美丽的翅膀
它在雨天静静接受失败的漫长

它说你看你有一些总有一天要实现的梦想
你有一年四季可以喜怒哀乐心里有种下Feeling的地方
希望它能长成一棵漂亮的树
一棵漂亮的绿色植物
一棵飞舞的树 可以让我的一路
都有它的帮助 再不怕变的麻木
变得庸庸碌碌

航行
http://scms.whedu.net/zhijue/3.mp3

词:王泽  曲:王泽  演唱:王泽


我的心啊 有一片云 飘啊飘啊
漂泊不定 我的心啊 很少下雨
我总用快乐把它挂在天际 我的船啊
不停的划啊 一直到天边 找不到家

我的船啊 轻轻的摇啊 你知道我
什么也不怕 我把春天全都挂在桅杆
让它飘扬 让大海看见
我把阳光全都写在脸上 让它灿烂
让蓝天看见


心愿
http://scms.whedu.net/zhijue/8.mp3

词:王泽  曲:王泽  演唱:王泽&杨颖


湖水是你的眼神 梦想满天星辰
心情是一个传说 亘古不变地等候
成长是一扇树叶的门
童年有一群亲爱的人
春天是一段路程 沧海桑田的拥有

那些我爱的人 那些离逝的风
那些永远的誓言一遍一遍 

那些爱我的人  那些沉淀的泪
那些永远的誓言一遍一遍

我们都曾有过一张天真而忧伤的脸
手握阳光我们望着遥远
轻轻的一天天一年又一年
长大间我们是否还会再唱起 心愿
长大间我们是否还会再唱起 心愿

 

基于Java的GPS接收机解析器

By , 2004年8月31日 5:17 上午

[摘要]本文介绍了一个基于Java的GPS 接收机解析器。这个Java类通过解析标准GPS接收机的输出信号,能够为导航与控制系统提供GPS 时钟、经度、纬度、高程等一系列信息。本类库使用标准Java语言编写,不需要任何第三方通讯类库(包括Sun 公司的Java通讯API )的支持,稍加修改即可被广泛应用在各种便携式设备和嵌入式系统中。

[介绍]

全球定位系统 (Global Position System,简称GPS )是由美国研制的导航、授时和定位系统。该系统包括空中卫星、地面跟踪监测站、地面卫星数据注入站、地面数据处理中心和数据通讯网络等部分。这个系统通过 24颗地球同步卫星全天候向地面发送授时和定位信号,其中高精度的信号仅供美国军方和北约盟军使用,普通用户只能够接收和解析低经度的民用信号。如果对接 收到的民用信号进行差分处理,也可以得到精度很高的定位数据。目前一般的差分GPS 接收机都可以得到1 米精度的定位数据,在欧美市场上已经出现了厘米级的差分GPS 接收机。普通用户只需购买GPS 接收机,就可享受免费的导航、授时和定位服务。目前全球定位系统技术在农业、林业、水利、交通、航空、测绘、安全防范、军事、电力、通讯、城市管理等领域 都有广泛应用。

在上述所述应用领域中,GPS 接收机通常是某些便携式设备或者是嵌入式系统的外接输入设备。一般的GPS 接收机均通过串行通讯口主动向主机发送数据,其通讯参数为4800(波特率),8(数据位),1(停止位),0(奇偶校验位)。 由于 Java语言的平台无关性,很多基于便携式设备和嵌入式系统的应用程序都采用Java 语言进行开发。因此,一个基于标准Java语言的GPS 接收机解析器,无疑具有广泛的应用前景。

本文所介绍的基于Java的GPS 接收机解析器从标准GPS 接收机的GGA 输出信息中解析标准时钟(Universal Time Coordinate, UTC)、纬度(Latitude)、经度(Longitude )和高程(Altitude)等基本授时和定位信息。根据美国海军电子设备标准接口规定,该信息包含标准时间、经纬度、高程等数据,每个数据之间用逗号分 隔,以一个回车符号结束,一般格式如下:

$–GGA,标准时间,纬度,南北,经度,东西,信号质量,卫星总数,水平精度,高程,米,地理间隔,米,差分数据龄期,差分基准站ID*hh

$–GGA — GGA 信息标示符,根据接收机的不同,该标示符中的第二和 第三个字节会有所不同。
标准时间 — 一个浮点数,数据格式hhmmss.ss。
纬度 — 数据格式ddmm.mm,其中dd为度(整数,0 到90);mm.mm为 分(浮点数,0 到60)。
南北 — 南北半球标示符号,一个字节,S 为南半球,N 为北半球。
经度 — 数据格式dddmm.mm,其中ddd为度(整数,0到180);mm.mm 为分(浮点数,0 到60)。
东西 — 东西半球标示符号,一个字节,E 为东半球,W 为西半球。
信号质量 — 一个整数,从0 到8。
卫星总数 — 一个整数,从0 到24。
水平精度 — 一个浮点数。
高程 — 该地点在平均海平面以上的高程,一个浮点数。
米 — 长度单位标示符,一个字节,M。
地理间隔 — WGS-84地球椭球表面与平均海平面表面之间的距离,一个浮 点数。
米 — 长度单位标示符,一个字节,M。
差分数据龄期 — 上一次SC-104标定到当前的总秒数,一个浮点数。
查分基准站ID — 一个整数,从0000到1023。
除 了GGA 信息以外,一般的GPS 接收机还会输出其他类型的信息,例如AAM 信息,ACK 信息,GNS 信息等等。本文所介绍的Java类库持续的监听GPS 接收机所在的串行通讯口,从其输出信息中截获GGA 信息并进行解析,从而获得当前的时间和定位信息。本类库包括三个Java模块以及一组测试数据:

GPS 数据模块 — 实时保存当前数据(GpsInfo.java)。
GPS 接收机模块 — 供外部程序调用(GpsReceiver.java)。
数据接收与解析模块 — 接收与解析GPS 信息(GpsParser.java)。
测试模块 — 功能测试与范例(TestGps.java)。
测试数据 — 一组实际GPS 测量数据(gps.dat)。
[GPS 数据模块]

GPS 数据模块用来保存经过解析的授时与定位数据,同时提供访问与更新这些数据的方法。数据接收与解析模块通过数据更新方法SetXyz()实时更新授时与定位 数据,用户应用程序通过数据访问方法GetXyz()使用授时与定位数据。考虑到可能存在多个应用程序(线程)同时对GPS 数据进行修改的情况,所有的数据更新方法都利用synchronized关键字和notifyAll() 方法实现了数据同步。在这个类中包含的数据访问与更新方法比较多,部分列举如下:

数据访问方法:

public float GetTime()
此方法返回当前标准时间,其返回值是一个浮点数,数据格式hhmmss.ss。

public float GetLatitude()
此方法返回当前纬度信息,数据格式ddmm.mm,其中dd为度(整数,0 到90); mm.mm为分(浮点数,0 到60)。

public String GetNS()
此方法返回南北半球标示符号,一个字节,S 为南半球,N 为北半球。

public float GetLongitude()
此方法返回当前经度信息,数据格式dddmm.mm,其中ddd为度(整数,0到180) ;mm.mm为分(浮点数,0 到60)。

public String GetEW()
此方法返回东西半球标示符号,一个字节,E 为东半球,W 为西半球。

public float GetAltitude()
此方法返回当前平均海平面以上高程,一个浮点数。

数据更新方法:

public void SetTime(float time)
此方法更新当前标准时间,输入参数是一个浮点数,数据格式hhmmss.ss。

public void SetLatitude(float latitude)
此方法更新当前纬度信息,参数格式ddmm.mm,其中dd为度(整数,0 到90); mm.mm为分(浮点数,0 到60)。

public void SetNS(String ns)
此方法更新南北半球标示符号,一个字节,S 为南半球,N 为北半球。

public void SetLongitude(float longitude)
此方法更新当前经度信息,参数格式dddmm.mm,其中ddd为度(整数,0到180) ;mm.mm为分(浮点数,0 到60)。

public void SetEW(String ew)
此方法更新东西半球标示符号,一个字节,E 为东半球,W 为西半球。

public void SetAltitude(float altitude)
此方法更新当前平均海平面以上高程,输入参数是一个浮点数。

[GPS 接收机模块]

GPS 接收接模块是本类库于其他应用程序的接口,本模块为其他应用程序提供了连接、启动、切断GPS 接收机以及实时查询GPS 数据的方法。具体介绍如下:

构造方法:

public GpsReceiver(String GpsDevice, int Factor)
public GpsReceiver(String GpsDevice, int Factor, boolean Record)

其中:

GpsDevice — 即将使用的GPS 设备名称。如果GPS 接收机与计算机的串口COM1 或者是COM2相连接,则使用”COM1″或者是”COM2″作为设备名称, 以此类推;如果使用GPS 数据文件代替GPS 接收机的输入,则使 用该文件名作为设备名称,例如”gps.dat”。

Factor — 如果使用GPS 数据文件代替GPS 接收机的输入,则可以利用此变 量制定一个加速系数,用于快速回放等功能。普通GPS 接收机每 秒钟更新一次数据,如果指定加速系数为5 ,则每秒钟回放5 秒 钟的实际测量数据。如果从GPS 接收机接收数据,则需要将该参 数设定为0 。

Record — 如果使用了GPS 接收机,则可以通过将该参数设定为true来记录 GPS 接收机的输出数据。这些数据可以在程序测试中模拟GPS 接 收机的输入。

操作方法:

public void StartReceiver()
此方法启动与GPS 接收机的连接,并且开始更新授时与定位数据。

public void StopReceiver()
此方法停止更新授时与定位数据,并且切断与GPS 接收机的连接。

public GpsInfo GetGpsData()
此方法返回当前的授时与定位数据。

用 户在使用本类库的时候,通常是先声明一个GpsReceiver 对象,然后利用上述StartReceiver() 方法启动与GPS 接收机的连接并且开始接收与解析授时与定位信息。当用户不再需要使用来自GPS 接收机的信息时,可以利用StopReceiver()方法切断与GPS 接收机的连接并且释放所占用的系统资源。

[数据接收与解析模块]

数 据接收与解析模块是本类库的核心部分,这个模块负责监听GPS 设备输出的信号,从中截获并解析GGA 信息,从而得到最新的授时与定位数据。该模块可以使用实时和模拟两种方式工作,在实时模式下使用GPS 接收机作为输入设备,在模拟模式下使用GPS 数据文件模拟GPS 接收机的输入。此外,数据接收与解析模块还能够将GPS 接收机的输出数据保存到数据文件中供程序测试等使用。因此,数据接收与解析模块的构造方法与GPS 接收机模块的构造方法是类似的。

构造方法:

public GpsParser(String GpsDevice, int Factor, boolean Record, GpsInfo Info)

其中:

GpsDevice — 即将使用的GPS 设备名称。如果GPS 接收机与计算机的串口COM1 或者是COM2相连接,则使用”COM1″或者是”COM2″作为设备名称, 以此类推;如果使用GPS 数据文件代替GPS 接收机的输入,则使 用该文件名作为设备名称,例如”gps.dat”。

Factor — 如果使用GPS 数据文件代替GPS 接收机的输入,则可以利用此变 量制定一个加速系数,用于快速回放等功能。普通GPS 接收机每 秒钟更新一次数据,如果指定加速系数为5 ,则每秒钟回放5 秒 钟的实际测量数据。如果从GPS 接收机接收数据,则需要将该参 数设定为0 。

Record — 如果使用了GPS 接收机,则可以通过将该参数设定为true来记录 GPS 接收机的输出数据。这些数据可以在程序测试中模拟GPS 接 收机的输入。

Info — 用来保存授时与定位信息的GPS 数据对象。

数 据接收与解析模块的核心部分是一个线程,该线程被设计成一个内置类,这样的设计是的外部程序能够通过该类自定义的start() 和stop()方法来启动和终止该线程。在start() 方法中将一个名为DevOn 的逻辑变量设置为真并且启动数据接收与解析线程,在stop()方法中则将DevOn 设置为假。数据接收与解析线程在运行过程中不断监测DevOn 的值,如果DevOn 为假,则终止自身的执行。这个设计避免了已经不鼓励使用的(deprecated)的stop()方法来强制终止线程的执行,从而保证了该线程的安全终 止。

在数据接收与解析模块中把GPS 输入设备统一当作文件进行处理,因为大多数的操作系统均将串行端口设置为系统保留文件,应用程序只需要对该文件进行读写即可以通过串行端口与外界设备进行 通讯。一个GPS 接收机解析器只需要从串行端口实时读取数据而并不需要向GPS 接收机发送控制指令,使用标准文件输入函数来读取GPS 接收机的输入信号,完全能够满足功能上的要求。这样的设计使得数据接收与解析模块在实时模式和模拟模式下都能够使用同样的数据接收与解析程序,大大的简化 了整个程序的结构。此外,利用标准文件输入函数来对GPS 接收机进行操作,避免了在类库中使用例如javax.comm等第三方通讯API ,大大的提高了本类库的可移植性。

由于GPS 接收机的每一条信息均以回车换行符号结束,在数据接收与解析模块中使用了BufferedReader来读取GPS 接收机的输入信息。GPS 接收机的所有输入信号,首先被系统存放在一个缓冲区里面。数据接收与解析模块利用readLine()方法每次从该缓冲区里面读取一行数据,如果该行数据 包含GGA 数据标示符,则利用该数据解析授时与定位信息,反之则将该行数据舍弃继续读取下一行数据进行判断和处理。

由于普通GPS 接收机的数据更新频率为1 秒,在模拟模式下,数据接收与解析模块每读取到一条GGA 数据就暂停1 秒钟,从而模拟GPS 接收机的输入。如果用户指定了一个大于1 的加速系数,则根据加速系数计算暂停的时间,例如在加速系数为5 的情况下暂停时间为200 毫秒,因此回放模拟的速度相当于实际速度的5 倍。这个功能在耗时较长的程序测试中非常有用。考虑到一般应用程序所能够获得的时钟信号的精度不是很高的缘故,我们不推荐使用大于50的加速系数。

此外,数据接收与解析模块还提供了数据记录功能。利用数据记录功能能够将实测到GPS 信号保存到一个数据文件里面供回放和测试使用。该功能自动产生一个扩展名为.gps的数据文件,主文件名根据当时的系统时间自动生成,在通常的情况下不会发生数据覆盖的问题。

[程序测试]

在 本类库中提供了一个测试程序和一组测试数据。利用这个程序和数据用户可以使用实时和模拟两种方式对本类库进行测试,也可以在这个测试程序的基础上开发自己 的应用程序。测试环境包括多种版本的Windows 95/98/2000操作系统,四个不同型号的差分GPS 接收机,两个常规Java虚拟机以及两个嵌入式Java虚拟机。测试结果表明,本类库在以上不同条件的各种组合下均能够利用实时和模拟两种模式正常工作。

[结论]

本文设计和实现了一个基于Java的GPS 接收机解析器,全面测试结果表明,这个GPS 接收机解析器能够实现如下功能:

(1) 在实时模式下,从GPS 接收机接收与解析授时与定位数据。

(2) 在模拟模式下,利用GPS 数据文件回放授时与定位数据。用户可以通过设 定一个加速系数来改变数据回访的速度。

(3) 能够将实测到GPS 信号保存到一个数据文件里面供回放和测试使用。

(4) 本类库不需要任何第三方通讯类库(包括Sun 公司的Java通讯API )的支 持,稍加修改即可被广泛应用在各种便携式设备和嵌入式系统中。

[其他]

很早的一篇文章了,大概是2001年写的,很多东西已经跟不上形式了,放在这里做个记录吧。

Access USB devices from Java applications

By , 2004年8月30日 5:15 上午

Introduction 

The Java platform has traditionally prided itself on its platform independence. While that independence has many benefits, it makes the process of writing Java applications that interact with hardware quite tricky. In this article, research scientist Qingye Jiang examines two projects that are making the process easier by providing APIs through which Java applications can make use of USB devices. While both projects are still in embryo form, both show promise and are already serving as the foundations of some real-world applications.

The first version of the Universal Serial Bus (USB) specification was released in January 1996. Because of its low cost, high data-transfer rate, ease of use, and flexibility, USB has gained wide acceptance in the computer industry. Today, many peripherals and devices connect to computers through USB interfaces. Currently, most general-purpose operating systems provide support for USB devices, and it is relatively easy to develop applications in C or C++ that access such peripherals. However, the Java programming language by design provides very little support for hardware access, so writing Java applications that interact with USB devices has proved quite difficult.

Efforts to provide access to USB devices in the Java language were initiated in 1999 by Dan Streetman at IBM. In 2001, his project was accepted as a candidate extended standard of the Java language through the Java Specification Request (JSR) process. The project is now called JSR-80 and has been officially assigned the Java package javax.usb. Meanwhile, in June 2000, Mojo Jojo and David Brownell started the jUSB project at SourceForge. Both of these projects have since produced usable packages for Linux developers, although neither is close to perfect. Both projects also have begun attempts to provide access to USB devices for Java applications on other operating systems, though usable packages have not yet emerged from either. (See Resources for references to these and other projects discussed in this article.)

In this article, you’ll get a brief introduction to the jUSB and JSR-80 projects; first, however, we’ll take a look at the nuts and bolts of the USB protocol, so that you can understand how both of those projects interact with USB devices. We’ll also offer code snippets to show how you’d use both projects’ APIs to access USB devices.

An introduction to USB


In 1994, an alliance of four industrial partners (Compaq, Intel, Microsoft, and NEC) started specifying the USB protocol. The original goal of the protocol was to connect the PC to the telephone and to provide I/O interfaces that were easy to expand and reconfigure. In January 1996, the first version of the USB specification was released, and a subsequent revision (version 1.1) was released in September 1998. The specification allowed 127 devices to be connected together at the same time, with the total communication bandwidth limited to 12 Mbps. Later on, three more members (Hewlett-Packard, Lucent, and Philips) joined the alliance. In April 2000, version 2.0 of the USB specification, which supports transfer rates up to 480 Mbps, was released. Today, USB plays a key role in high-speed (video, imaging, storage) and full-speed (audio, broadband, microphone) data-transfer applications. It also connects a variety of low-speed devices (keyboards, mice, game peripherals, virtual reality peripherals) to the PC.

The USB protocol is strictly hierarchical. In any USB system there is only a single host, and the USB interface to the host computer is referred to as the host controller. There are two standards for host controllers — the Open Host Controller Interface (OHCI, by Compaq) and the Universal Host Controller Interface (UHCI, by Intel). Both standards provide the same capabilities and work with all USB devices; the hardware implementation of a UHCI is simpler, but requires a more complex device driver (and thus puts more load onto the CPU).

The USB physical interconnect is a tiered star topology, with up to seven tiers. A hub is at the center of each star, and the USB host is considered the root hub. Each wired segment is a point-to-point connection between a hub and USB device; the latter can be either another hub that provides additional attachment points to the system, or a device of some sort that provides functional capabilities. The host uses a master/subordinate protocol to communicate with the USB devices. This approach solves the problem of packet collision but also prevents the attached devices from establishing direct communication with each other.

All the data transfers are initiated by the host controller. Data directed from the host to a device is called downstream or out transfer; data directed from a device to the host is called upstream or in transfer. Data transfer occurs between the host and a particular endpoint on the USB device, and the data link between the host and the endpoint is called a pipe. A given USB device may have many endpoints, and the number of data pipes between the host and the device is the same as the number of endpoints on the device. A pipe may be uni-directional or bi-directional, and the data flow in one pipe is independent of the data flow in any other pipes.

Communication on the USB network can use any one of four different data transfer types:

  • Control transfers: These are short data packets for device control and configuration, particularly at attach time.
  • Bulk transfers: These are data packets in relatively large quantities. Devices like scanners or SCSI adapters use this transfer type.
  • Interrupt transfers: These are data packets that are polled periodically. The host controller will automatically post an interrupt at a specified interval.
  • Isochronous transfers: These are data streams in real time with higher requirements for bandwidth than for reliability. Audio and video devices generally use this transfer type.

Like a serial port, each USB port on a computer is assigned a unique identification number (port ID) by the USB controller. When a USB device is attached to a USB port, this unique port ID is assigned to the device and the device descriptor is read by the USB controller The device descriptor includes information that applies globally to the device, as well as information on the configuration of the device. A configuration defines the functionality and I/O behavior of a USB device. A USB device may have one or more configurations, which are described by their corresponding configuration descriptors. Each configuration has one or more interfaces, which can be considered as a physical communication channel; each interface has zero or more endpoints, which can be either data providers or data consumers, or both. Interfaces are described by interface descriptors, and endpoints are described by end-point descriptors. Furthermore, a USB device might also have string descriptors to provide additional information such as vendor name, device name, or serial numbers.

As you can see, a protocol like USB offers challenges to developers who use the Java language, which strives for platform- and hardware-independence. Let’s now take a look at two projects that have tried to bridge the gap.

The jUSB API


The jUSB project was created by Mojo Jojo and David Brownell in June 2000. Its objective was to provide a set of free software Java APIs to access USB devices on Linux platforms. The API is distributed under the Lesser GPL (LGPL), which means that you can use it in proprietary as well as free software projects. The API provides multithreaded access to multiple physical USB devices, and supports both native and remote devices. Devices with multiple interfaces can be accessed by multiple applications (or device drivers) simultaneously, with each application (or device driver) claiming a different interface. The API supports control transfers, bulk transfers, and interrupt transfers; isochronous transfers are not supported because these are used for media data (such as audio and video) that are already well supported by the JMF API (see
Resources) over other standardized device drivers. Currently, the API works on GNU/Linux distributions with either the Linux 2.4 kernel or a back port into 2.2.18 kernel. Thus, most recent distributions are supported; for example, the API works on Red Hat 7.2 and 9.0 without any patches or other upgrades.

The jUSB API includes the following packages:

  • usb.core: This package is the core part of the jUSB API. It allows Java applications to access USB devices from USB hosts.
  • usb.linux: This package contains a Linux implementation of a usb.core.Host object, bootstrapping support, and other classes leveraging Linux USB support. This implementation accesses the USB devices through the virtual USB device file system (usbdevfs).
  • usb.windows: This package has a Windows implementation of a usb.core.Host object, bootstrapping support, and other classes leveraging Windows USB support. This implementation is still in its very early stage.
  • usb.remote: This package is a remote version of the usb.core API. It includes an RMI proxy and a daemon application, which allow Java applications to access USB devices on a remote computer.
  • usb.util: This package provides some useful utilities to download firmware to USB devices, dump the content of the USB system into XML, and convert a USB device with only bulk I/O into a socket.
  • usb.devices: This optional package collects Java code to access a variety of USB devices with the jUSB API, including Kodak digital cameras and Rio 500 MP3 Players. These APIs were specially written to simplify the process of accessing the designated USB devices and cannot be used to access other devices. The APIs were built upon the usb.core APIs, and they will work on any operating system where jUSB is supported.
  • usb.view: This optional package provides a simple USB tree browser based on Swing. It is a very good example program illustrating the use of the jUSB API.

Although the implementation of the usb.core.Host object varies from operating system to operating system, a Java programmer needs to understand only the usb.core package to start developing applications with the jUSB APIs. Table 1 outlines the interfaces and classes from usb.core with which a Java programmer should be familiar:

Table 1. Interfaces and classes in jUSB

Interface Description
Bus Connects a set of USB devices to a Host
Host Represents a USB controller with one or more Buses
Class Description
Configuration Provides access to a USB configuration supported by a device and to the interfaces associated with that configuration
Descriptor Base class for entities with USB typed descriptors
Device Provides access to a USB device
DeviceDescriptor Provides access to a USB device descriptor
EndPoint Provides access to a USB end-point descriptor, structuring device data input or output in a given device configuration
HostFactory Contains bootstrapping methods
Hub Provides access to a USB hub descriptor and some hub operations
Interface Describes sets of endpoints, and is associated with a particular device configuration
PortIdentifier Provides stable string identifiers for USB devices, appropriate for use in operations and troubleshooting

The normal procedure to access a USB device with the jUSB API is as follows:

  1. Bootstrap by getting the USB Host from the HostFactory.
  2. Access the USB Bus from the Host, then access the USB root hub (which is a USB Device) from the Bus.
  3. Obtain the number of USB ports available on the hub, and traverse through all the ports to find the appropriate Device.
  4. Access the USB Device that is attached to a particular port. A Device can be accessed directly from the Host with its PortIdentifier, or can be found by traversing the USB Bus starting from the root hub.
  5. Interact with the Device directly with ControlMessage, or claim an Interface from the current Configuration of the Device and perform I/O with the Endpoint available on the Interface.

Listing 1 illustrates how to obtain the content of a USB system with the jUSB API. The program as written simply looks at the root hub for available USB devices, but it would be easy to improve it to traverse the whole USB tree. The logic here corresponds to steps 1 through 4 above.

Listing 1. Obtaining the content of a USB system with the 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

Listing 2 illustrates how to perform bulk I/O with Interface and EndPoint, assuming that the application has successfully located the Device. This code snippet can also be modified to perform control or interrupt I/O. It corresponds to step 5 above.

Listing 2. Performing bulk I/O with the jUSB API


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

The jUSB project was very active from June 2000 to February 2001. The most recent release of the API, version 0.4.4, was made available on February 14, 2001. Only some minor progress has been reported since that time, probably due to the success of the IBM group in becoming a candidate extended standard of the Java language. However, several third-party applications have been developed based on jUSB, including the JPhoto project (an application using jUSB to connect to digital cameras) and the jSyncManager project (an application using jUSB to synchronize with a Palm OS-based PDA).

The JSR-80 API (javax.usb)

As noted earlier, the JSR-80 project was created by Dan Streetman at IBM in 1999. In 2001, the project was accepted as a candidate extended standard of the Java language through the Java Specification Request (JSR) process. The project is now called JSR-80 and has been officially assigned the Java package javax.usb. The project is licensed under the Common Public License and is developed using the Java Community Process. The objective of this project is to develop a USB interface for the Java platform that will allow full access to the USB system for any Java application or middleware component. The JSR-80 API provides full support for all four transfer types defined by the USB specification. Currently, the Linux implementation of the API works on most recent GNU/Linux distributions with 2.4 kernel support, such as Red Hat 7.2 and 9.0.

The JSR-80 project includes three packages: javax-usb (the javax.usb API), javax-usb-ri (the common part of the OS-independent reference implementation), and javax-usb-ri-linux (the reference implementation for the Linux platform, which connects the common reference implementation to the Linux USB stack). All three parts are required to form a complete functioning java.usb API on the Linux platform. Independent efforts aimed at porting the API to other operating systems (primarily Microsoft Windows) have been reported on the project e-mail list, but no functioning packages have been released yet.

Although the OS-dependent implementation of the JSR-80 APIs varies from operating system to operating system, a Java programmer needs to understand only the javax.usb package to start developing applications. Table 2 lists the interfaces and classes in javax.usb with which a Java programmer should be familiar:

Table 2. Interfaces and classes in the JSR-80 APIs

Interface Description
UsbConfiguration Represents a configuration of 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

The normal procedure for accessing a USB device with the JSR-80 API is as follows:

  1. Bootstrap by getting the appropriate UsbServices from the UsbHostManager.
  2. Access the root hub through the UsbServices. The root hub is considered as a UsbHub in the application.
  3. Obtain a list of the UsbDevices that are connected to the root hub. Traverse through all the lower-level hubs to find the appropriate UsbDevice.
  4. Interact with the UsbDevice directly with a control message (UsbControlIrp), or claim a UsbInterface from the appropriate UsbConfiguration of the UsbDevice and perform I/O with the UsbEndpoint available on the UsbInterface.
  5. If a UsbEndpoint is used to perform I/O, open the UsbPipe associated with it. Both upstream data (from the USB device to the host computer) and downstream data (from the host computer to the USB device) can be submitted either synchronously or asynchronously through the UsbPipe.
  6. Close the UsbPipe and release the appropriate UsbInterface when the application no longer needs access to the UsbDevice.

In Listing 3, we obtain the content of the USB system with the JSR-80 API. The program recursively traverses through all the USB hubs on the USB system and locates all the USB devices connected to the host computer. The code corresponds to steps 1 through 3 above.

Listing 3. Obtaining the content of the USB system with the 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

Listing 4 illustrates how to perform I/O with Interface and EndPoint, assuming that the application has successfully located a Device. This code snippet can also be modified to perform I/O of all four data transfer types. It corresponds to steps 4 through 6 above.

Listing 4. Performing I/O with the JSR-80 API


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

The JSR-80 project has been very active from its very beginning. Version 0.10.0 of the javax.usb API, RI, and RI for Linux were released in February 2003. It is likely that this version will be submitted to the JSR-80 committee for final approval. It is expected that implementations for other operating systems will soon be available after JSR-80 formally becomes an extended standard of the Java language. The Linux developer community seems to show more interest in the JSR-80 project than the jUSB project, and there have been an increasing number of projects launched using the javax.usb API on the Linux platform.

Conclusion


Both the jUSB API and the JSR-80 API provide Java applications with the capability to access USB devices from a machine running the Linux operating system. The JSR-80 API provides more functionality than the jUSB API, and has the potential of becoming an extended standard of the Java language. Currently, only Linux developers can take advantage of the jUSB and JSR-80 APIs. However, active efforts to port both APIs to other operating systems have been reported. Java developers should be able to access USB devices on other operating systems in the near future. By familiarizing yourself with these APIs now, you can be ready to add USB functionality to your applications when these projects are ready for prime time on multiple platforms.

Resources

其他

本文于2003年9月发表于IBM DeveloperWorks美国网站:

http://www-106.ibm.com/developerworks/java/library/j-usb.html

 

多功能串口设备服务器

By , 2004年8月28日 5:12 上午

[摘要]

本 文介绍了一个基于Java的多功能串口设备服务器。本服务器能够实现如下功能:(1) 接受从指定串口发送来的信号并将其转发到另外的串口、广播到局域网、或者是通过TCP/IP链接转发给局域网内的其它设备,从而实现局域网内部的信息共 享;(2) 通过TCP/IP链接或者是串口接受其他设备发送给该串口设备的控制信息,从而实现设备的远程控制。

[介绍]

随 着网络技术的高速发展,基于IP技术的局域网已经成为最简单有效的数据交换与共享手段。但是,对于很多遗留设备(譬如说单片机和数据采集设备)来说,唯一 可用的通讯通道就是串口(通常是RS-232)。这些设备一般都配备有专门的数据采集和控制软件,这些软件安装在被称为主控系统的终端或者是PC机上,通 过串口与该设备进行通讯。从串口设备发送来的数据被存储在主控系统的文件系统上,其它设备通过网络访问该主控系统,从而实现数据的共享。对串口设备的配置 和控制,只能够通过主控系统来进行。

这些遗留设备的特征, 就是其“设备–控制终端–网络”体系。在涉及到数据交换与共享的时候,主控系统实质上相当于一个缓冲区。这个缓冲过程使用了效率低下的磁盘操作,从而 使主控系统成为整个数据交换过程中的瓶颈。主控系统的唯一功能是配置和控制该串口设备,用户也只能够通过主控系统来配置和控制该串口设备,这不仅在使用上 给用户带来极大的不便,也带来了硬件资源的浪费。

串口设 备服务器的功能,就是接受串口设备发送来的信息,实时的将其通过串口、网络广播、或者是TCP/IP链接转发给需要这些信息的设备。同时,串口设备服务器 还接受从其它串口或者是网络发送来的信息并将其转发给串口设备。与传统的 “设备–控制终端–网络”体系相比较,串口设备服务器具有如下优势:

(1) 串口设备服务器并不将所交换的数据保留到本地文件系统上,从而消除了 “设备–控制终端–网络”体系中的瓶颈(磁盘操作),从而提高了数据 交换与共享的效率,保证了数据的实时性。

(2) 网络广播技术使得多个设备能够同时利用一个串口设备所提供的数据,从 而提高了设备利用率。

(3) 一台串口设备服务器能够同时为多个设备提供服务。

(4) 远程设备能够通过网络获取串口设备所提供的数据,使得远程数据采集与 处理成为可能。

(5) 远程设备能够通过网络向串口设备发送数据,因此能够从远程对该设备进 行控制和配置。

(6) 用户能够从远程对串口设备服务器进行控制和配置。

由 于以上技术上的优势,串口设备服务器在任何涉及到数据采集与处理的系统中都能够得到广泛的应用。在实验室中采用串口设备服务器,使得科研人员在家里也能够 实时监测实验仪器的运行情况,采集和处理实验数据甚至调整实验条件。在医院里采用串口设备服务器,使得医护人员在办公室里就可以得到各个病人的心电图和脉 搏等数据,这不但提高了医护人员及时发现突发情况的能力,还减轻了医护人员的劳动强度。在航天器上采用串口设备服务器,地面控制人员能够通过无线网络直接 获取传感器数据,修正系统的错误,甚至上载新的任务模块。

本文利用Java实现了一个简单的多功能串口设备服务器。这个服务器能够实现如下功能:

(1) 接受从指定串口发送来的信号并将其转发到另外的串口、广播到局域网、 或者是通过TCP/IP链接转发给局域网内的其它设备。

(2) 通过TCP/IP链接或者是串口接受其他设备发送的控制信息并将其转发给该 串口设备。

(3) 通过TCP/IP链接接受用户的控制指令,从而改变自身的运行参数。

[系统设计]

根据一上所述系统需求,这个简单的串口设备服务器包括如下功能模块:主控模块,远程控制模块,以及数据交换模块。

主控模块的功能是初始化各项运行参数,同时启动远程控制模块。

远程控制模块通过TCP/IP链接接受用户指令并根据指令实现如下功能:改变串口参数,与指定串口设备进行通讯,启动或者终止指定数据交换模块。

数据交换模块接受串口设备的输出数据并转发给其他设备,同时从其它设备接受控制信号并转发给串口设备。根据系统需求我们设计了三个数据交换模块:

(1) 数据广播模块,接受串口设备的输出数据并将其广播到局域网;

(2) TCP/IP数据服务模块,接受串口设备的输出数据并通过TCP/IP链接将其转 发到指定客户机,同时接受该客户机发送的控制指令并将其转发给串口设 备;

(3) 串口数据服务模块,接受串口设备的输出数据并通过另一串口转发给其他 设备,同时接受其他设备发送的控制指令并将其转发给串口设备。

根据以上设计,将各个功能模块命名如下:

主控模块 — DeviceServer
远程控制模块 — RemoteControl
数据广播模块 — Broadcast
TCP/IP数据服务模块 — ServeTcp
串口数据服务模块 — ServeCom

以上所述功能模块,在程序设计中分别作为一个Java类进行实现。功能模块与 Java源代码文件之间的一一对应关系如下:

主控模块 — DeviceServer.java
远程控制模块 — RemoteControl.java
数据广播模块 — Broadcast.java
TCP/IP数据服务模块 — ServeTcp.java
串口数据服务模块 — ServeCom.java

[程序设计]

(1) 主控模块

主 控模块的功能是初始化各项运行参数,同时启动远程控制模块。在这个简单的串口设备服务器中并没有定义任何运行参数,因此主控模块的唯一功能是启动远程控制 模块。本模块从命令行接受一个参数,该参数指定远程控制模块所使用的端口号,远程客户可以通过该端口对本系统进行控制和配置。本功能模块包括如下步骤:

a. 检查用户是否从命令行提供了一个参数。如果是,继续运行下一步;如果 否,输出一条出错信息并退出系统。

b. 检查用户所提供的命令行参数是否可以解释成一个端口号(一个整数)。如 果是,继续运行下一步;如果否,输出一条出错信息并退出系统。

c. 检查用户所提供的端口号是否系统端口(即小于1024)或者是无效端口( 即 大于65535)。如果否,继续运行下一步;如果是,输出一条出错信息并退 出系统。

d. 声明一个远程控制模块,然后启动该模块。

主控模块被保存为DeviceServer.java

(2) 远程控制模块

远程控制模块通过TCP/IP链接接受用户指令并根据指令实现如下功能:改变串口参数,与指定串口设备进行通讯,启动或者终止指定数据交换模块。根据系统需求,本模块又包括如下方法:

系统配置方法:

a. 指定串口设备所在的串口;
b. 指定与该串口设备通讯所使用的参数,包括波特率,数据位,停止位和奇 偶性校验位。
c. 指定其他设备所在的串口;
d. 指定与其他设备通讯所使用的参数,包括波特率,数据位,停止位和奇偶 性校验位。
e. 指定数据广播端口,即客户机用来监听实时数据的端口。
f. 指定数据服务端口,即客户机用来请求实时数据的端口。
g. 指定数据交换模块。为简单起见,本系统一次只能够启动一个数据交换模 块提供数据交换服务。
系统控制方法:

a. 解释控制指令,这个方法解释客户机所发送的控制和配置指令,然后调用 相应的系统控制或配置方法。

b. 启动与串口设备的连接。
c. 切断与串口设备的连接。在切断与串口设备的连接之前必须关闭所使用的 端口或者是切断与客户机的联接。
d. 启动数据交换模块。
e. 终止数据交换模块。在终止数据交换模块之前必须关闭所使用的端口或者 是切断与客户机的联接。
f. 退出系统。在退出系统之前必须关闭所有端口,终止数据交换模块。

由于这个功能模块所需要实现的功能比较多,为节省篇幅起见,以下示例程序中没有设计异常处理功能。在程序的注释行中,对有可能导致异常的地方添加了部分说明。

远程控制模块被保存为RemoteControl.java

(3) 数据广播模块

数 据广播模块的功能是接受串口设备的输出信号,然后将其通过广播将其转发到局域网。在局域网中的所有设备都可以通过监听广播端口来获得串口设备所提供的数 据,从而使得多个设备同时共享一个特殊设备成为可能。这个功能模块首先建立一个广播服务器,然后不断的监听串口设备的输出流。当输出流里面有数据存在的时 候,广播服务器将其取出并广播到局域网。

数据广播模块被保存为Broadcast.java

(4) TCP/IP数据服务模块

TCP/IP 数据服务模块的功能是接受串口设备的输出信号,然后通过TCP/IP连接将其转发给客户机。这个模块还能够接受客户机通过TCP/IP连接发送来的控制信 号并将其转发给串口设备,从而实现了串口设备的远程控制与配置功能。在这个模块中包括三个线程:服务器线程接受客户机的连接请求,数据服务线程监测串口设 备的输出流并将数据转发给客户机,控制信号服务线程监测客户机的输出流并将信号转发给串口设备。为简单起见,这个示例程序一次只能够接受一个客户机的连接 请求,但是用户能够很容易的将其改写成能够同时为多个客户机提供服务。

TCP/IP数据服务模块被保存为ServeTcp.java

(5) 串口数据服务模块

串 口数据服务模块的功能是接受串口设备的输出信号,然后通过串口将数据转发给其它通过串口连接的设备。与TCP/IP数据服务模块类似,这个模块还能够接受 客户设备通过串口发送来的控制信号并将其转发给串口设备,从而实现了串口设备的远程控制与配置功能。通常来说,两个设备通过串口进行通讯要求这两个设备使 用相同的通讯参数,例如波特率,数据位,停止位和奇偶性校验位。但是对于很多遗留设备来说,他们往往只能够使用固定的通讯参数进行工作,从而导致了由于两 个设备由于通讯参数不同而无法共享数据的问题。在这个示例程序中,不同的设备可以使用不同的通讯参数,从而解决了具有不同固定通讯参数的设备之间的数据交 换问题。

在这个功能模块中包括两个线程:数据服务线程监 测串口设备的输出流并将数据转发给客户设备,控制信号服务线程监测客户设备的输出流并将信号转发给串口设备。为简单起见,这个示例程序一次只能够为一个客 户设备提供数据服务,但是用户也能够很容易的将其改写成能够同时为多个客户设备提供服务。

串口数据服务模块被保存为ServeCom.java

[系统测试]

本多功能串口设备服务器的测试应该在局域网中进行。优选的测试方案应该具备如下硬件条件:

计 算机A — 运行本多功能串口设备服务器。本机必须配备Java运行环境和由 Sun公司提供的通讯扩展类库javax.comm,这些软件都可以从Java 软件的主页www.javasoft.com免费下载。再进行测试之前必须根据 该软件包所提供的说明文件正确进行安装,否则在测试的时候系统 将无法找到本机串口。

计算机B — 运行超级终端模拟一个串口设备,通过RS-232电缆与计算机A的串 口COM1相连接。

计算机C — 运行超级终端模拟其它串口设备,通过RS-232电缆与计算机A的串 口COM2相连接。

计算机D — 通过局域网与计算机A相连接,模拟局域网中向多功能串口设备服 务器请求数据的其它网络设备。

在计算机A 上运行本多功能串口设备服务器,然后通过TELNET进入远程控制状态。用户通过命令行方式对服务器进行控制和配置。本服务器所提供的控制和配置指令如下:

SET DEVICE PORT — 设定串口设备所在的串口。本命令接受一个整数 参数,该参数指定串口设备所在的串口。

SET DEVICE PARAM — 设定串口设备所使用的通讯参数。本命令接受一 个参数串,如38400,8,1,0 表示波特率38400 , 数据位8,停止位1,无奇偶检验。

SET PEER PORT — 设定其它设备所在的串口。本命令接受一个整数 参数,该参数指定串口设备所在的串口。

SET PEER PARAM — 设定其它设备所使用的通讯参数。本命令接受一 个参数串,如38400,8,1,0 表示波特率38400 , 数据位8,停止位1,无奇偶检验。

SET BROADCAST PORT — 设定数据广播端口。本命令接受一个整数参数, 该参数指定客户机用来监听数据广播的端口。

SET SERVICE PORT — 设定数据服务端口。本命令接受一个整数参数, 该参数指定服务器用来提供数据服务的端口。

SET SERVICE TYPE — 指定数据服务类型。本命令接受一个整数参数, 1 表示数据广播服务,2 表示TCP/IP数据服务, 3 表示串口数据服务。其它数值都是无效参数。

CONNECT TO DEVICE — 接通串口设备。本命令不接受任何参数。

DISCONNECT FROM DEVICE — 切断串口设备。本命令不接受任何参数。

START SERVICE — 启动数据服务。本命令不接受任何参数。

STOP SERVICE — 终止数据服务。本命令不接受任何参数。

SHUT DOWN — 终止多功能串口设备服务器。本命令不接受任何 参数。

QUIT — 退出远程控制系统。本命令不接受任何参数。

由于远程控制服务器在处理命令之前将命令行转换成大写,因此用户可以用大写或者是小写输入控制与配置指令。

(1) 数据广播功能测试

计 算机A 启动多功能串口设备服务器,计算机B 启动超级终端模拟串口设备。启动多功能串口设备服务器时必须指定一个端口号(如8888)以提供远程控制服务。利用Telnet进入远程控制程序(如 telnet localhost 8888),就可以通过控制指令控制和配置多功能串口设备服务器了。

需 要说明的是,由于Windows 自带的Telnet程序不回显输入数据,因此用户看不到自己所输入的命令。建议用户从一台类似于UNIX的系统远程Telnet到串口设备服务器进行控制 和配置。如果计算机A 的IP为90.0.0.1,多功能串口设备服务器的远程控制服务程序运行在端口8888,那么用户就可以通过telnet 90.0.0.1 8888连接到远程控制服务器。

用户连接到远程控制服务器后,运行如下命令:

SET DEVICE PORT 1
SET DEVICE PARAM 115200,8,1,0
CONNECT TO DEVICE
SET SERVICE TYPE 1
SET BROADCAST PORT 8080
START SERVICE

以 上指令设定串口设备连接在COM1 ,通讯参数为115200,8,1,0。运行在计算机B 上的超级终端应该使用同样的通讯参数。成功的与串口设备建立起连接后指定8080为数据广播端口,再指定系统提供数据广播服务,最后启动数据广播服务。这 时候,在同一局域网内的其它计算机(如计算机D )就应该能够在8080端口监听到由串口设备(计算机B )所发送的数据。

本文提供了一个示例程序可以用来监听广播到指定端口的数据。该程序从命令行接受一个参数,这个参数指定监听的端口。这个程序被保存为 BClient.java

在 机器D 上运行以上程序并指定8080为监听端口。在机器B 的超级终端窗口内随意输入作为串口设备的输出数据,这些数据被多功能串口设备服务器所接收并实时的广播到局域网,因此机器D 的屏幕上应该同时打印出这些数据来。如果局域网网中同时还有其它计算机运行以上接收程序并指定8080为监听端口,那么这些计算机也能够同时接收到串口设 备的输出数据。

(2) TCP/IP数据服务功能测试

在远程控制终端输入如下控制指令测试TCP/IP数据服务功能:

STOP SERVICE
SET SERVICE TYPE 2
SET SERVICE PORT 8023
START SERVICE

以 上控制指令指定多功能串口设备服务器在端口8023启动TCP/IP数据服务。从机器D 通过Telnet连接到该端口(如telnet 90.0.0.1 8023)就可以接收到串口设备所输出的数据。在机器D 上所输入的数据,也被实时的传送到串口设备,因此在机器B 的超级终端窗口内能够看到从机器D 所输入的数据。因此,局域网内的设备不但能够通过串口设备服务器利用该串口设备进行远程数据采集与处理,还能够实现串口设备的远程控制和配置。

(3) 串口数据服务功能测试

在远程控制终端输入如下控制指令测试串口数据服务功能:

STOP SERVICE
SET PEER PORT 2
SET PEER PARAM 38400,8,1,0
SET SERVICE TYPE 3
START SERVICE

以上控制指令指定其它串口设备被连接在COM2上,所使用的通讯参数为38400, 8,1,0。 最后面两个控制指令指定系统运行串口数据服务。

计 算机C 上运行超级终端程序,其通讯参数为38400,8,1,0。这时候串口设备(计算机B )可以接收到其它设备(计算机C )所发送的数据,其它设备(计算机C ) 也可以接收串口设备(计算机B )所发送的数据。我们注意到,两个串口设备( 计算机B 和C ) 所使用的通讯参数是不同的,但是他们可以通过这个多功能串口设备服务器进行数据交换。

(4) 其它功能测试

在远程控制终端输入如下控制指令:

DISCONNECT FROM DEVICE

以上控制指令切断与串口设备的连接。如果当前正在提供远程数据服务( 如数据广播服务,TCP/IP数据服务,串口数据服务),这项服务将被关闭。

QUIT

以上控制指令终止客户机与远程控制终端的会话,多功能串口设备服务器的所有配置保持终止会话前的状态,正在提供的远程数据服务继续提供。

SHUT DOWN

以上控制指令强制停止多功能串口设备服务器的执行。当前正在提供的远程数据服务将被关闭,与串口设备的连接将被切断。

(5) 测试结果

作者对本系统的功能进行了全面的测试,实际测试环境如下:

计算机A — Windows 2000英文版 + Java SDK 1.3 + Java Comm API
计算机B — Windows 98英文版 + 超级终端
计算机C — Windows 98英文版 + 超级终端
计算机D — Windows 98英文版 + Java SDK 1.3
计算机E — Red Hat 6.1

所 有机器通过100M高速Ehternet连接。计算机B 通过RS-232电缆连接到计算机 A 的COM1,计算机C 通过RS-232电缆连接到计算机A 的COM2。在实际测试中,通过计算机E 远程连接到计算机A 进行远程控制与配置。测试结果表明,该系统能够实现远程控制与配置与远程数据服务等全部功能。

[结论]

本文设计和实现了一个基于Java的多功能串口设备服务器。本多功能串口设备服务器能够实现如下功能:

(1) 远程控制与配置。

(2) 为串口设备提供远程数据服务。数据广播服务使得局域网内的多个设备能 够同时利用一个串口设备所提供的数据;TCP/IP数据服务使得局域网内的 设备能够通过TCP/IP连接获得串口设备所提供的数据,并且能够远程对该 串口设备进行控制和配置;串口数据服务使得两个使用不同通讯参数的串 口设备能够进行数据交换。

(3) 本系统不但实现了在局域网内的串口设备信息共享,并且大幅度提高了数 据交换的速度和效率。

(4) 本系统在Windows 平台上测试成功。由于Java语言的垮平台特性,本系统 只需要进行很小的改动就可以移植到其它平台上。

(5) 本系统在涉及到数据采集与处理的行业中具有广泛的应用前景。

[其他]

本文于2001年8月首次发表于IBM DeveloperWorks中国网站。
http://www.ibm.com/developerWorks/cn

基于PPP协议的Linux与Windows CE网络

By , 2004年8月23日 11:21 下午

本文介绍了通过网络实现 Linux 主机与 Windows CE 设备协同工作的方法。本文首先利用 PPP 协议在 Linux 主机与 Windows CE 设备之间建立起连接,然后在 Windows CE 设备上运行一个 FTP 服务器使得 Linux 主机能够访问 Windows CE 设备上的资源。本文所介绍的解决方案,对 Windows 9x/2000/NT 主机同样适用。

背景介绍

Linux 是一个类似于UNIX 的操作系统,它起源于芬兰一个名为Linus Torvalds 的业余爱好,但是现在已经是最为流行的一款免费操作系统。普通用户在Linux 上办公、浏览网站、发送邮件以及玩游戏,许多大学和科研机构也Linux 来完成日常 的计算任务。在商业领域,由于Linux 系统价格低、安全性能高并且非常稳定,许 多公司均将自己的服务器构建在Linux的基础上。根据国际商用数据公司(IDC)的统计,世界上大约有三分之一的网站服务器使用Linux作为操作系 统。

Windows CE,根据微软公司在Windows CE and Pocket PC: FAQ 中的定义,是操作系统开发商用以构建专有操作系统的一系列组件。原始设备制造商(OEM) 可以 向微软公司购买一个称为”Windows CE平台开发系统”的集成开发环境并利用该系 统组装和编译基于Windows CE的操作系统,该操作系统包括一系列基于Windows CE 的组件以及开发商自行开发的应用软件或者是设备驱动程序。由于基于Windows CE 的操作系统具有与微软Windows 系列操作系统相类似的用户界面,因此受到众多最 终用户以及开发商的青睐。目前Windows CE已经被广泛应用在手机,掌上型电脑,个人数字助理,快译通以及电子字典等便携式设备上。

长 期以来,Windows CE设备的用户还需要配备一台基于Windows 9x/2000/NT的 主机用于与Windows CE设备交换数据。在该主机上运行微软公司提供的Windows CE 服务软件,该软件通过一条RS-232数据线与Windows CE设备建立起点对点连接,用 户可以通过这个服务软件访问Windows CE设备,但是局域网里面的其它计算机不能 够访问该Windows CE设备。如果需要使得局域网里面的其它计算机也能够访问该设备,则需要为该设备安装昂贵的专用网卡以及相关接入设备,是一种非常不经济的 解决方案。

本 文利用Red Hat Linux 7.2操作系统自带的PPP服务器与Windows CE设备之间 建立起TCP/IP连接,然后在Windows CE设备上运行一个FTP服务器使得Linux主机能 够访问Windows CE设备上的资源。由于本方法基于Windows CE设备自带的RS-232数据线,不需要购买额外的任何设备,因此是一种经济实用的解决方案。此外,本文 所介绍的解决方案,对Windows 9x/2000/NT主机同样适用。

连接Linux与Windows CE

点 对点数据传输协议(Point to Point Protocol, PPP)是一个通过串口线传送 IP数据包的协议。使用PPP 协议,一台计算机能够通过串口线、电话线等通讯设备登陆到远程主机并且利用该主机或者是主机所在网络的资源。在点对点通讯中包括服务器和客户机两个部分, 其中客户机向服务器请求网络连接,服务器接收客户机的请求建立网络连接并分配给客户机相应的网络资源。当网络连接建立起来以后,服务器和客户机之间是严格 对等的。由于Linux操作系统通常都带有PPP服务器和客 户端程序,而Windows CE操作系统通常仅带有PPP客户端程序,因此我们使用Linux 主机作为PPP服务器,Windows CE设备作为PPP客户端。

为了使用Linux主机作为PPP服务器,我们首先必须确认该主机上是否已经安装有PPP服务器程序pppd。通常该程序被安装在/usr/sbin目录下,我们可以利用下面 的命令查找该目录下是否存在这个文件:

ls /usr/sbin/pppd

最 近正式发行的Linux操作系统(例如Red Hat Linux 6.x/7.x)通常都已经预先 安装有PPP服务器程序。如果Linux 主机尚未安装PPP服务器,那么我们应该首先下 载并安装一个PPP服务器程序,例如pppd2.3.4。安装该程序包可能还需要其它包的支持,由于应用程序的安装已经超出了本文的讨论范围,请感兴趣的 读者自行参考 其它相关资料。

确认PPP服务器已经安装在Linux主机上之后,我们需要对Linux 主机进行一些必要的配置,为了进行这些配置我们需要拥有root权限。

建立文件/etc/ppp/peers/wince,内容如下:

       /dev/ttyS0 115200 crtscts
connect '/usr/sbin/chat -v -f /etc/ppp/wince.chat'
noauth
local
90.0.0.1:90.0.0.2

建立文件/etc/ppp/wince.chat,内容如下:

       TIMEOUT 3600
"CLIENT" "CLIENT\c"
"" "SERVER\c"

在上面的两个配置文件中,使用wince 作为文件名仅仅是用来表示这个配置文 件是给一个Windows CE设备使用的。读者也可以自行选用其它的文件名,例如palm 或者是handheld等等,但是必须保证两个文件名是一致的。

配 置文件/etc/ppp/peers/wince指定使用串口ttyS0以115,200 bps的速率与客户设备建立连接,noauth参数说明在客户机请求连接的时候不需要身份认证。在这 个对等连接中,服务器(Linux 主机)的IP是90.0.0.1,客户机(Windows Ce设备)的 IP是90.0.0.2。配置文件/etc/ppp/wince.chat中的TIMEOUT参数指定服务器的等待时间,如果超过这个时间仍然没有接收到 客户机的连接请求则终止当前的服务器程序。如果有读者需要更进一步的了解相关的配置,请自行参考chat以及pppd的相关 文档。

在Windows CE设备端需要做的配置相对来说比较简单。由于Windows CE默认的自动连接功能占用了该设备的串口,我们首先需要停止使用该功能。在开始菜单中选择”设置->通讯->PC连线”并将其设置为不启用 与PC的连接即可停止该功能。然后我们重新建立一个连接,在开始菜单种选择”程序->通讯->连接管理器”,然后点击 “新建连接”图标,将新的连接命名为Linux 并指定连接类型为”直线连接”,在下一 步中指定使用COM1进行连接并设置其通讯速率为115,200,在TCP/IP 设置中指定该设备的IP为90.0.0.2。点击OK存盘以后该连接会出现在”程序->通讯”菜单里面。

利用如下命令在Linux主机上启动PPP服务器:

pppd call wince

在Windows CE 设备上启动新建的连接(程序->通讯->Linux)之后,网络连线图 标会出现在Windows CE设备的任务栏上,Linux 主机则显示如下信息表明已经成功 与Windows CE设备建立起连接:

       Serial connection established.
Using interface ppp0
Connect: ppp0 <--> ttyS0
found interface eth0 for proxy arp
local  IP address 90.0.0.1
remote IP address 90.0.0.2

我们还可以使用Linux 主机提供的ping命令来验证是否已经成功与Windows CE 设备建立连接:

ping 90.0.0.2

如果Linux 主机已经成功的与Windows CE设备建立连接,那么我们应该能够看 到类似于下面的信息:

       PING 90.0.0.2 (90.0.0.2) from 90.0.0.1 : 56(84) bytes of data.
64 bytes from 90.0.0.2: icmp_seq=0 ttl=32 time=26.587 msec
64 bytes from 90.0.0.2: icmp_seq=1 ttl=32 time=19.928 msec
64 bytes from 90.0.0.2: icmp_seq=2 ttl=32 time=19.939 msec
64 bytes from 90.0.0.2: icmp_seq=3 ttl=32 time=19.947 msec

基于Windows CE的FTP软件

当 我们成功的在Linux主机与Windows CE设备之间建立起PPP连接之后,下一步应该做些什么呢?当然,我们需要一些合适的程序用来在Linux 主机与Windows CE 设备之间进行文件交换。我们现在已经能够利用TCP/IP协议在Linux主机和Windows CE设备之间传输数据,很显然FTP程序是一个合适的选择。

FTP(File Transport Protocol,文件传输协议)是一种被广泛使用的在网络上进行文件交换的协议。由于数据传输可靠性的要求,FTP 是一种基于TCP/IP的传输 协议。在一个FTP 会话中包括一个服务器端和一个客户端,客户端主动连接到服务器端并向服务器发送文件传输请求,服务器端等待客户端的接入并处理客户端的文 件传输请求。

PE FTP Explorer是非常流行的基于Windows CE的FTP客户端软件,同时也是一 个功能齐全的文件浏览器。与在PC机上常用的Cute FTP和WS FTP等FTP 客户端相类 似,用户能够利用鼠标(指针)放缩本地端和服务器端的目录树,上载或者是下载文件和目录,也可以对文件或者是目录进行改名和删除。这个软件可以从CE Archive 网站(http://www.cearchives.com/ftp.html)获得。在该网站读者还可以找到另外 一个很流行的FTP客户端vxFTP。

FTP 客户端软件的功能虽然已经非常的完备而且操作简单,但是仍然不可避免的要收到便携式设备窄小的显示器的限制。如果能够在便携式设备上建立一个FTP 服务器,那么文件传输操作就可以在Linux主机上利用常用FTP客户端的进行。

ftpsrv.exe 就是这样一个基于Windows CE的FTP服务器软件。这个仅有28.5 KB 的小程序,除了不提供身份认证功能和Passive 传输模式以外,能够处理大多数常 见的FTP 请求。利用微软提供的Windows CE服务软件将ftpsrv.exe上载到便携式设备的任意目录下,启动该程序以后在任务条上会出现一个类似于一台计算机连接两个便携式设备的小图标。利 用指针点击该图标以后会出现一个小小的控制窗口,在这里我们可以改变FTP服务器的端口号或者是终止该程序。

ftpsrv.exe可以从http://pda.tucows.com/或者是http://www.oohito.com/获 得。在这两个网站读者还可以找到更多有用的小程序。

其它

如果有读者使用的是Windows 9x/2000/NT主机,那么也可以利用Windows 提供 的直线电缆连接功能与Windows CE设备建立起PPP连接。

例 如:在Windows 2000主机上,从开始菜单中选择设置->网络和拨号连接->新建连接。在随后出现的网络连接向导中选择直接连接到另一台计算机并将该机器配 置为主机。选择合适的通讯端口并配置通讯速率以后,该主机作为PPP 服务器等待 客户机接入。同样,在Windows CE设备上新建一个连接,指定合适的通讯端口并配 置起通讯参数以后,即可与Windows主机建立起点对点连接。由于Windows主机已经配备了动态网络地址分配(DHCP)服务器,因此 Windows CE设备既可以使用实现指定的静态IP地址,也可以使用服务器实时分配的动态IP地址。但是,由于直线电缆连 接所允许的最高传输速率为19,200 bps,使用Windows 9x/2000/NT主机作为PPP 服 务器似乎比不上Linux主机实用。

如 果将PPP 服务器设置为网关,则局域网里面所有的机器都可以通过改网关访 问已经连接到网络上的Windows CE设备。在Linux 主机上,可以通过ipchains将该 主机设置成透明网关;在Windows 9x/2000/NT 主机上,可以通过Win Proxy等代理服务器软件将其设置为透明网关。如果有读者需要更进一步了解如何将Linux 或者是Windows主机设置为透明网关的方法,请自行阅读其它参考资料。

本文于2002年2月首先发表于IBM Developworks中国网站。

http://www-900.ibm.com/developerWorks/cn/linux/l-tip-prompt/tip16/index.shtml

在运行时刻更新功能模块

By , 2004年8月20日 11:18 下午

[摘要] 本文介绍了一个利用类库加载器ClassLoader 实现在运行时刻更新部分功能模块的Java程序,并将其与C/C++中实现同样功能的动态链接库方案进行了简单比较。

[介绍]

在 嵌入式系统的设计中,经常涉及到在运行时刻更新部分功能模块的设计。例如一个用于数据采集与处理的设备,包括数据采集,数据发送,命令接收等功能模块,有 可能被要求在继续进行数据采集的同时采用新的数据格式向一个新的数据处理系统发送数据。在这种情况下,就必须在运行时刻动态的更新数据发送的功能模块。

在C/C++中,这样的功能可以很容易的利用动态链接库来实 现。Win32 API函数 LoadLibrary和FreeLibrary提供了在运行时刻加载新的功能模块和释放内存空间的功能。需要被更新的功能模块被封装在动态连接库里,主 程序利用LoadLibrary 函数装载该动态链接库,然后调用其中的功能模块。需要更新某功能模块的时候,首先终止运行该功能模块,利用FreeLibrary 函数卸载现有的动态链接库,通过网络或者是其他通讯端口将新的动态链接库文件发送到指定目录下,然后利用再次利用 LoadLibrary 函数装载新的动态链接库并调用其中的新功能模块。(如果需要进一步了解动态链接库程序设计的内容,请参阅参考文献1中的相关部分。)

在Java中,有一个被称为类库加载器的抽象类ClassLoader 能够用来实现类似于LoadLibrary的功能。本文下面的部分着重介绍ClassLoader的一般结构以及利用 ClassLoader实现在运行时刻更新部分功能模块的方法。

[类库加载器]

类 库加载器ClassLoader 是一个负责加载类库的抽象类。它接受一个类库的名称并试图定位和生成包含有改类库定义的数据。通常的实现方法是将该类库的名称转化成一个文件名,然后从文 件系统中找到该文件并读取其中的内容。(关于类库加载器的定义,请参阅参考文献2。)

所 有的Java虚拟机都包括一个内置的类库加载器。这个内置的类库加载器被称为主类库加载器。主类库加载器的特殊之处是它只能够加载在设计时刻已知的类,因 此虚拟机假定由主类库加载器所加载的类都是可信任的,可以不经过安全认证而直接运行。当应用程序需要加载在设计时刻未知的类库时,就必须使用用户自定义的 类库加载器。

一个用户自定义的类库加载器是抽象类java.lang.ClassLoader 的派生类,其中唯一必须实现的抽象方法是loadClass()。通常来说,loadClass()方法需要实现如下操作:

确认类库名称
检查请求加载的类库是否已经被加载
检查请求加载的类库是否是系统类库
尝试从类库加载器的存储区获取所清求的类库
在虚拟机中定义所请求的类库
解析所请求的类库
返回所请求的类库

一 个用户自定义类库加载器几乎可以从任何存储设备上加载类库。装载本地硬盘上的类库当然不在话下,通过超级连接装载网络上的类库也很容易。由于类库加载器的 存在,Java虚拟机并不需要事先知道关于将要运行的类库的任何细节。由于类库加载器的功能是如此的强大,出于安全考虑某些Java类库如applets 等不允许启用自定义的类库加载器。

参考文献3 给出了关于用户自定义类库的更详细描述,同时提供了一个示例程序SimpleClassLoader。在本文下面的例子中,使用该文献中的SimpleClassLoader 作为用户自定义类库加载器。

[在运行时刻更新功能模块]

在 动态链接库技术中,LoadLibrary函数负责加载功能模块,FreeLibrary函数负责卸载功能模块。新的功能模块与旧的功能模块同名,新的动 态链接库文件也与旧的动态链接库文件同名。当需要更新某个功能模块的时候,使用新的动态链接库文件替换旧的动态链接库文件,被旧的功能模块所占用的内存空 间也同时被释放。

但是Java并不提供一个类似于类库卸 载器(ClassUnloader) 的功能,能够把已经装载的功能模块从内存里面清除掉。目前的虚拟机,大都使用了及时编译(JIT) 技术,也就是说一个功能模块只有在它第一次被使用的时候才被编译。经过编译的可执行代码被放到内存里面,用一个HashTable 做索引,其关键字为与之相对应的类库名。虚拟机需要用到某个功能模块的时候,它先到这个HashTable 里面查找相应的关键字。如果该功能模块已经存在,虚拟机直接从内存里调用经过编译的可执行代码,反之则调用类库加载器装载新的功能模块并进行编译。由于没 有模块卸载功能,在运行时刻已经被装载的功能模块是一直存在的。当某功能模块实际上已经被更新(即.class文件被替换为同名的新文件)并需要被重新加 载的时候,虚拟机并不会试图装载新的功能模块而直接调用旧的功能模块。如果试图利用用户自定义的类库加载器强行装载新的功能模块,则会因为新的功能模块与 旧的功能模块同名而导致虚拟机抛出链接错误: Linkage Error: duplicate class definition。

脑子快的朋友也许已经想出了以下的方法:


SimpleClassLoader scl = new SimpleClassLoader();
Object o;
Class  c;

c = scl.loadClass("SomeNewClass");
o = c.newInstance();
((SomeNewClass) o).SomeClassMethod(SomeParam);

但 是,这样的方法实际上是不能够实现的。首先,SomeNewClass在程序设计的时候尚未存在,这样的程序是无法通过编译的。其次,在运行时刻只有用户 自定义的类库加载器SimpleClassLoader能够获取有关SomeNewClass 的定义,虚拟机的主类库加载器是无法创建一个SomeNewClass对象的,因此以上程序的最后一行也会出错。

参 考文献3 指出有两个方法可以解决这个问题。一是被装载的模块是虚拟机的主类库加载器已经加载的某个类库的派生类库(subclass),一是被加载的模块实现某个 已经被系统虚拟机的主类库加载器加载的接口(interface)。 在浏览器中通常都使用了第一种方法,譬如说所有的applet都是java.applet.Applet的派生类库,因此在所有的applet源代码中都 有类似于public class MyClass extends Applet 的声明。在这里我们采用参考文献3 中介绍的第二种方法,也就是被加载的新模块实现某个预先设计好的接口。

声明接口UpdatableModule如下:


public interface UpdatableModule
{
void start(String RunTimeParam)
}

由于这个接口在设计时刻已经存在,它可以被虚拟机的主类库加载器和将要被加载的新功能模块所调用。新功能模块所需要做的,只是实现这个接口中的方法,例如:


public class NewModule_1 implements UpdatableModule
{
void start(String RunTimeParam)
{
System.out.println("This is new module 1.");
}
}

public class NewModule_2 implements UpdatableModule
{
void start(String RunTimeParam)
{
System.out.println("This is new module 2.");
}
}

在运行时刻,主程序需要从外部获得新的功能模块名,利用用户自定义的类库加载器加载新的功能模块,生成一个新的功能模块对象,然后通过事先定义好的接口调用新的功能模块中的方法。例如:


public class Test
{
public static void main(String[] args)
{
SimpleClassLoader scl = new SimpleClassLoader();
String RunTimeModule;
Object o;
Class  c;

RunTimeModule = args[0];
c = scl.loadClass(RunTimeModule);
o = c.newInstance();
((UpdatableModule) o).start("No parameter needed.");
}
}

[示范程序]

下面我们介绍一个简单的数据采集与处理程序。该程序采集当前的系统时间并按照一定的格式输出到标准输出设备,其中的数据处理模块(即数据输出模块)可以在运行时刻被更新。该程序包括如下功能模块:

DataBuffer — 数据缓冲区
DataCollector — 数据采集模块
DataProcessor — 数据处理模块接口
PrintData_1 — 数据输出模块,实现数据处理模块DataProcessor的接口
PrintData_2 — 数据输出模块,实现数据处理模块DataProcessor的接口
TestGUI — 测试图形界面

数据缓冲区DataBuffer存放数据采集模块DataCollector 所采集的数据,它提供了更新数据和查询数据的方法。

数据采集模块DataCollector是一个线程,它每隔5秒钟采集一次系统时间并更新数据缓冲区DataBuffer。

数据处理模块接口DataProcessor定义了数据处理模块所需要实现的方法。

数据输出模块PrintData_1实现数据处理模块DataProcessor的接口。该模块每 3秒钟查询一次数据缓冲区DataBuffer 中的数据并将其加上标志”Data 1: “输出到标准输出设备。

数据输出模块PrintData_2实现数据处理模块DataProcessor的接口。该模块每 2秒钟查询一次数据缓冲区DataBuffer 中的数据并将其加上标志”Data 2: “输出到标准输出设备。

测试图形界面TestGUI 创建一个简单的用户图形界面。该程序声明一个数据缓冲区对象并启动数据采集线程。用户可以通过该图形界面输入运行时刻的数据处理模块名称,启动或者是终止数据处理模块,以及退出应用程序。

将 以上源代码编译以后运行TestGUI ,在测试图形界面的文本框里面输入需要运行的数据处理模块的名称,然后点击“启动数据处理模块”按钮,即可运行指定的数据处理模块,点击“终止数据处理模 块”即可终止当前的数据处理模块。在运行时刻,用户可以根据数据处理接口DataProcessor 编制新的数据处理模块并提交该示例程序运行。因此,本示例程序能够实现在运行时刻更新功能模块的功能。

本示例程序没有实现复杂的出错处理。在运行时刻,用户需要首先终止当前的数据处理模块,才能够启动新的数据处理模块。

[讨论与比较]

到此为止我们已经利用类库加载器实现了在运行时刻更新程序模块的功能。下面我们将这种方法与C/C++中的动态链接库做一个简单的比较。

首 先,C/C++ 所使用的动态链接库是经过编译的可执行代码,可以直接被主程序所调用执行。Java的类库是字节码,在第一次被调用之前必须经过虚拟机的及时编译才能够被 调用执行。因此,Java程序的启动时间要比C/C++ 程序的启动事件更长。另外,Java程序的执行效率普遍来说要比C/C++ 程序低20% ~ 30%。

其次,C/C++能够利用 FreeLibrary函数释放旧的功能模块所占用的内存空间,从而保持了功能模块名和动态链接库文件名的一致性,同时节省了内存空间和磁盘空间。而 Java并不提供类似的类库卸载功能,被旧的功能模块所占用的内存空间已经不再被使用却无法被释放,因此会有相当数量的内存被浪费。

由 于动态链接库文件在其中的功能模块被使用的过程中是一直打开的,更新动态链接库文件的操作只能够在其中的功能模块已经被终止以后才能够进行。而Java 的新功能模块和旧功能模块使用不同的文件名,可以在运行旧的功能模块的同时下载和传输新的功能模块到指定的位置。通常来说,下载和传输文件要涉及到效率低 下的磁盘操作,因此,在实际应用中动态链接库实现方案下载和传输文件所需要的时间可能比虚拟机编译新的功能模块所需要的时间更长。但是如果在下载和传输过 程中新的动态链接库文件采用一个不同的文件名,在需要加载新的功能模块之前删除旧的动态链接库文件并且将新的动态链接库文件改名,动态链接库实现方案所需 要的时间就要大大的缩短。

综上所述,利用C/C++ 和Java都能够实现在运行时刻更新功能模块的功能。相对来说,基于动态链接库技术的C/C++ 方案在执行效率,内存利用以及操作效率等方面都比基于类库加载器的Java方案更有优势,应该作为首选的实现方案。

[参考文献]

1. Ori Gurewich and Nathan Gurewich, Teach Yourself Visual C++ 4 in 21 days, Sams Publishing, Indianapolis, 1996

2. Java 2 Platform API Specification, Java 2 SDK, Standard Edition Documentation,

3. Chuck McManis, The basics of Java class loaders, Java World, October 1996

[其他]

本文的前一个版本曾以《在运行时刻更新程序模块》为题目发表于《编程技巧与维护》2001年第9期上。
http://www.comprg.com.cn/

本文全文于2001年11月首次发表于IBM DeveloperWorks中国网站。
http://www.ibm.com/developerWorks/cn

Waba — 嵌入式Java程序开发的另类选择

By , 2004年8月19日 10:19 下午

[摘要] 本 文介绍了一个目前在国内尚未广为人知的嵌入式Java程序开发工具–Waba。 Waba是一个专门为嵌入式系统设计的Java语言的子集,利用Waba能够为手机、个人数字助理、掌上型电脑、多功能计算器等多种便携式设备开发应用程 序。目前版本的Waba虚拟机支持的平台包括AmigaOS, BeOS, Linux, MacOS, MS-DOS, Newton, OS/2, PalmOS, Windows 和Windows CE。在本文中作者将全面介绍Waba平台、开发工具以及Waba相关资源。

[Waba平台介绍]

Waba 是一种专门为微小型设备设计的程序开发平台,在该平台上定义了一种程序设计语言,一个虚拟机,一种类库文件格式以及一组基本类库。由于Waba语言的语法 是Java语言的语法的严格子集,Waba平台的类库文件格式也是Java平台类库文件格式的严格子集,因此熟悉Java的开发人员能够利用自己已经熟悉 的Java开发平台进行Waba程序开发。

Waba平台 所针对的是例如手机、个人数字助理、掌上型电脑、多功能计算器等硬件资源非常紧张的微小型设备。因此,Waba的编程语言、虚拟机和基本类库都针对微小型 设备进行了优化处理。在Java语言中需要耗费大量内存或者是被认为与微小型设备无关的特性均被排除在Waba平台之外。同样,Waba平台也对Java 平台的基本类库进行了大幅度裁减,从而使得Waba平台只需要占用很少的硬件资源而仍然能够满足微小性设备应用程序设计的需要。

和Java 应用程序相类似,Waba应用程序能够在任何安装了Waba平台的操作系统上运行。最早的Waba平台是针对Windows CE操作系统进行开发的,但是目前Waba虚拟机已经被移植到多种平台上,其中包括AmigaOS, BeOS, Linux, MacOS, MS-DOS, Newton, OS/2, PalmOS和Windows。就我所了解的情况,目前支持DOS的Java虚拟机只有KaffePC 和Waba,两者均要求Intel 386以上的中央处理器,但是KaffePC需要 8 MB的内存(推荐配置是16 MB),而Waba仅仅需要4 MB或者是更少的内存。Psion也与前段时间宣布开发支持MS-DOS的Java虚拟机,但是其测试版本至今尚未发布。前段时间Waba又推出了专门为 T1计算器设计的虚拟机,这是目前仅有的一个专门为计算器设计的Java虚拟机。

为 了保持与Java平台的兼容,Waba提供了一系列过渡类库使得Waba应用程序也能够在仅仅任何安装了Java运行环境的平台上运行。它既可以是 Windows或者UNIX 下面的普通应用程序(Application),也可以是内嵌在浏览器中的一个小应用程序 (Applet)。

与其他嵌入式应用程序开发环境相比较,Waba平台具有如下优点:

(1) 由于Waba本身是为硬件资源非常紧张的微小型便携式设备设计的,Waba虚拟机所要求的存储空间通常都小于64 K,其中包括基本类库,基于Waba的应用程序在运行时刻仅仅要求少于10 K的内存。

(2) Waba所提供的基本类库事先封装了大量在嵌入式系统中常见的功能,因此开发人员能够在这些事先经过严格测试的基本类库的基础上迅速开发自己的应用程序。 同时,Waba所支持的平台非常广泛,为一个平台所开发的应用程序不需要经过任何修改即可以在另一平台上运行。

(3) 微小型便携式设备通常没有任何外界存储设备,如果应用程序对内存进行了非法操作,用户必须重新启动该设备,从而导致不可挽回的数据丢失。作为Java 的一个严格子集,Waba同样限制用户应用程序直接对内存进行操作,从而避免了由于对内存进行非法操作而导致的系统崩溃和数据丢失。此外,Java语言特 有的垃圾回收功能(Garbage Collection)减少了在应用程序中发生内存泄露(Memory Leak) 的可能性。

[Waba开发工具]

在一个Waba应用程序的开发过程中,开发人员需要一个针对目标平台的Waba虚拟机,一套Waba开发环境,以及一个测试环境。

Waba 虚拟机:Waba虚拟机已经被移植到多种平台上,其中包括AmigaOS, BeOS, Linux, MacOS, MS-DOS, Newton, OS/2, PalmOS, Windows和Windows CE。Waba虚拟机的源代码是开放的,开发人员可以根据自己的需要对Waba虚拟机进行裁剪或者是修改。

Waba 开发环境:WabaSoft提供了一个软件开发工具包(Software Development Kit),称为WabaSDK 。这个工具包提供了所有的Waba基本类库,开发人员可以将这些基本类库添加到自己熟悉Java开发环境中去,然后在自己熟悉的Java开发环境中进行 Waba应用程序开发。一个最基本的Waba开发环境是JavaSDK + WabaSDK, 开发人员需要利用JavaSDK中提供的javac来编译Waba应用程序。此外,WabaSDK 还提供了针对PalmPilot和Windows CE 的代码转换工具ExeGen和Warp,利用这两个工具开发人员能够将编译以后的Waba类库文件转换成PalmPilot或者是Windows CE 可以识别的可执行文件。WabaSDK 的源代码同样是开放的,开发人员可以根据需要对其进行裁剪和修改,或者是将其移植到自己的开发平台上。

随 着Waba平台在嵌入式系统中的广泛应用,专门为Waba设计的集成开发环境也不断的涌现出来,VisualWaba和UIGen 可以说是这些第三方集成开发环境中的佼佼者。VisualWaba和UIGen 本身都是利用Java开发的应用程序,用来进行应用程序开发似乎有点反应迟钝,但是如果综合考虑一下Borland JBuilder和IBM Visual Age for Java的性能,VisualWaba和UIGen 的速度还是可以容忍的。相对来说UIGen 的功能还比较弱,只能够根据用户设计的界面生成相对应源代码。VisualWaba更类似于微软的Visual Basic,开发人员不但能够在其中进行界面设计和程序设计并生成源代码,还能够对程序进行编译和调试,最后生成PalmPilot 或者是Windows CE平台上的可执行代码。

除了 VisualWaba和UIGen 以外,还有另外一些由第三方开发的工具。这些工具或者为Waba提供一些专门的类库,或者是增强Waba的图形用户界面。例如MathFP为 Waba提供了高性能的符点运算类库,使得Waba在没有数学协同处理器的情况下也能够进行高性能的符点运算。mWaba AWT Toolkit 为Waba提供了类似于Java AWT的图形用户界面功能。Waba GUI Library为Waba提供了更加强大的串口通讯、图形用户界面以及HTML解析功能。

测 试环境:在嵌入式便携式设备应用程序设计中,经常需要将生成的可执行代码上载到目标平台上进行调试和测试。例如开发一个针对Windows CE的应用程序,开发人员通常需要预先在桌面计算机上进行程序开发和编译,然后通过微软的便携式设备服务程序将可执行代码上载到目标平台,最后在目标平台 上进行调试,整个过程非常的繁琐。在Waba中提供了一款针对Windows CE的模拟器,使得开发人员能够在桌面计算机上直接调试应用程序,从而大大的减轻了开发人员的负担。

[相关资源]

(1) WabaSoft (http://www.wabasoft.com)

WabaSoft是Waba的大本营,从该网站可以获得关于Waba平台的最新消息,并且可以下载各种版本的Waba开发工具以及相关文档。

(2) Waba Workbench (http://www.wabaworkbench.com)

Waba Workbench是由Ed Crandell 创办的一个专门用于Waba技术交流的网站,该网站提供了一系列关于Waba开发的技术文章、扩展类库以及虚拟机。在这里也可以找到指向其他Waba技术网站的连接。

(3) Visual Waba (http://www.dmic.fr/palm/prg2.htm)

VisualWaba的主页,从该网站可以获得关于VisualWaba的最新消息,并且可以免费下载VisualWaba的试用版以及相关文档。

(4) UIGen (http://home.c2i.net/badeand/UIGen/)

UIGen 的主页,从该网站可以获得关于UIGen的最新消息,并且可以在浏览器上直接利用UIGen 进行图形用户界面并且生成相对应的源代码。如果你需要经常性的使用UIGen的话,你需要将UIGen下载并安装在你的开发平台上。虽然UIGen 的用户界面非常简单,你还是可以在该网站上找到一个比较具体的用户指南。

(5) 其他网络资源

http://www.superwaba.org/
http://www.wabajump.org/
http://www.cygnus.uwa.edu.au/~rnielsen/wextras/
news://news.massena.com/pilot.programmer.waba
news://news.falch.net/pilot.programmer.waba

[结论]

本 文全面介绍了专门为嵌入式系统设计的Waba平台、开发工具以及Waba相关资源。该平台支持包括AmigaOS, BeOS, Linux, MacOS, MS-DOS, Newton, PalmOS 和 Windows CE等一系列嵌入式操作系统,能够在手机、个人数字助理、掌上型电脑、多功能计算器等多种便携式设备上运行。现有的Waba开发工具使得开发人员能够在一 般开发平台上设计、编译和调试针对便携式设备等目标平台的应用程序,能够大大缩短嵌入式应用程序的开发周期。目前Waba平台已经在嵌入式应用程序设计领 域得到了广泛的应用,是一个优秀的嵌入式应用程序平台。

[其他]

本文于2001年11月首次发表于IBM DeveloperWorks中国网站。
http://www.ibm.com/developerWorks/cn

基于Windows CE的嵌入式Java解决方案

By , 2004年8月19日 10:17 下午

这篇文章是好几年前写的了,这次收录到BLOG里面,顺便做一点小小的修改,简单的说明一下比较新的技术方案。新增加的部分用蓝色注明了出来。

[摘要]

本文介绍了一系列基于Windows CE的Java虚拟机以及集成开发环境,其中包括 IBM公司的Visual Age Micro Edition (就是现在的WebSphere Studio Device Developer), Sun公司的Personal Java, WabaSoft 发起的Waba,Insignia公司的Jeode (就是现在Esmertec的Jeode),Nsicom 公司的CrEme以及New Monics公司的PERC。在Java虚拟机的支持下,一个嵌入式应用程序不但可以运行在不同硬件平台不同版本的Windows CE操作系统上,还可以轻易的移植到其他嵌入式操作系统上。因此,在嵌入式应用程序开发方面,嵌入式Java比嵌入式VC或者是嵌入式VB具有不可替代的 优势。

[介绍]

Windows CE,根据微软公司在Windows CE and Pocket PC: FAQ 中的定义,是操作系统开发商用以构建专有操作系统的一系列组件。原始设备制造商(OEM) 可以向微软公司购买一个称为“Windows CE平台开发系统”的集成开发环境并利用该系统组装和编译基于Windows CE的操作系统,该操作系统包括一系列基于Windows CE 的组件以及开发商自行开发的应用软件或者是设备驱动程序。由于基于Windows CE 的操作系统具有与微软Windows 系列操作系统相类似的用户界面,因此受到众多最终用户以及开发商的青睐。目前Windows CE已经被广泛应用在手机,掌上型电脑,个人数字助理,快译通以及电子字典等便携式设备上。

虽 然Windows CE的原义是指一系列操作系统组件,通常意义上的Windows CE,则是指一切基于Windows CE的操作系统,例如采用了Windows CE 2.x技术的掌上型电脑Palm-Size PC操作系统(譬如CASIO的Cassiopeia) 和采用了Windows CE 3.0技术的Pocket PC操作系统(譬如Compaq的iPad H3650)。 通常意义上的Windows CE应用程序开发,基本上也是针对这两个操作系统的应用程序开发。

(Windows CE的最新版本是Windows CE.NET 4.2,来自Microsoft的嵌入式操作系统还包括Windows XP EMbedded。)

就 象微软的Visual Studio系列产品是Windows平台上最有效率的集成开发环境一样,目前最为流行的针对Windows CE的两个集成开发环境也是由微软开发的,分别称为嵌入式VC (Embedded VC 3.0)和嵌入式VB (Embedded VB 3.0)。可以想象,这两个集成开发环境与Windows 平台上的VC和VB具有异曲同工之妙。但是,即使是使用微软自己的集成开发环境为微软自己的操作系统开发应用程序,开发人员仍然需要时时忍受不兼容的痛 苦,例如为Pocket PC 编写的应用程序不能够在Palm-Size PC上运行,即使是完全一模一样的应用程序也要为不同版本的Windows CE不同的硬件平台分别建立一个项目分别编译发布,等等。

(Embedded VB 3.0自2002年之后便没有大的改进,Embedded VC于2003年推出了4.0版本,2004年发布了SP4。在新的Embedded VB/VC下,同样的应用程序不需要分别为不同的硬件平台分别建立项目,只需要在一个项目里面设置不同的configuration,分别编译发布即 可。)

自从Java语言问世以后,其“一次编 译,到处运行”的强大特性立即吸引了众多的嵌入式系统开发商。在短短的几年时间内,大量基于Linux, QNX, VxWorks 等嵌入式操作系统的Java虚拟机在业界不断的涌现出来,同时也产生了大量针对不同设备的嵌入式Java应用程序。虽然微软公司由于控制Java的努力失 败而对Java采取了抵制措施,但是嵌入式Java仍然顽强的在微软一统天下的Windows CE市场中占据了一席之地。在Java虚拟机的支持下,一个应用程序不但可以运行在不同硬件平台不同版本的Windows CE操作系统上,还可以轻易的移植到其他嵌入式操作系统上。因此,在嵌入式应用程序开发方面,嵌入式Java比嵌入式VC或者是嵌入式VB具有不可替代的 优势。

本文介绍了一系列基于Windows CE的Java虚拟机以及集成开发环境,其中包括 IBM公司的Visual Age Micro Edition, Sun公司的Personal Java, WabaSoft 发起的Waba,Insignia公司的Jeode,Nsicom公司的CrEme以及Newmonics公司的PERC。

[Visual Age Micro Edition]

Visual Age for Java,这个由IBM公司开发的集成开发环境,想来任何一个经常使用Java的开发人员都不应该感到陌生。在2001年9月,Visual Age for Java被 Java开发人员杂志(Java Developer’s Journal)评选为本年度最佳Java集成开发环境,最佳团队开发工具,以及最有新意的Java产品。

Visual Age Micro Edition则是IBM 公司开发的嵌入式Java解决方案,包括一个完备的集成开发环境和一系列针对不同平台的虚拟机。 在2001年7 月, Visual Age Micro Edition被Java专家杂志(Java Pro)以及Sun公司共同评选为本年度最佳嵌入式Java开发工具。

使 用Embedded VC或者是Embedded VB的开发人员有福了。为Pocket PC 编写的应用程序不能够在Palm-Size PC上运行?即使是完全一模一样的应用程序也要为不同版本的Windows CE不同的硬件平台分别建立一个项目分别编译发布?这些微软专有缺陷(Microsoft Proprietary Bug) 在Java语言“一次编译,到处运行”的强大特性面前已经不复存在。利用Visual Age Embedded Edition 编写的应用程序不仅仅可以不加修改的顺利运行在各种硬件平台各种版本的Windows CE上,还可以不加修改的顺利运行在AIX, Linux, ITRON, OSE, PalmOS, QNX, Solaris, Windows 等其他平台上。

Visual Age Micro Edition包括如下强大特性:

(1) 一个可靠的可裁剪的J9虚拟机。该虚拟机提供了对Java本地方法(JNI) 的支持和可靠的递增式垃圾回收机制。该虚拟机支持扩展的Java实时标准和TCP/IP协议,并且支持动态类库加载。更为重要的是,该虚拟机能够从文件加 载事先编译好的软件与程序,从而减少了应用程序的启动时间,提高了整个应用程序的速度。该虚拟机包括四个不同版本的标准配置,开发人员可以根据应用程序的 需要选择合适的配置,例如jclXtr比较适合资源十分紧张运行环境,而jclMax需要占用更多的系统资源但是能够提供更多的功能和特性。此外,开发人 员还可以根据应用程序的需要对这些配置进行裁剪,从而为自己的应用程序设计一个最佳的配置。

(2) 支持多个硬件平台多种操作系统。目前Visual Age Micro Edition支持的硬件平台(微处理器)包括:386, 68K, MIPS, PowerPC, SH3, SH4, Sparc, Strong Arm和x86。目前Visual Age Micro Edition支持的操作系统包括:AIX, Hard Hat Linux, ITRON, OSE, PalmOS, Pocket PC, QNX, Solaris, Windows和Windows CE。

(3) 功能完备的集成开发环境。除了其他集成开发环境都会提供的界面设计、代码编译和程序编译功能之外,Visual Age Micro Edition能够制作ROM 镜象文件并且将应用程序上栽到目标平台进行调试,能够对应用程序的资源使用状况进行分析和评估。此外,Visual Age Micro Edition还提供了一系了的工具,使得开发人员能够很容易的实现代码重用、团队合作、以及版本控制。

Visual Age Micro Edition的网站地址为:http://www.embedded.oti.com/。感兴趣的读者可以访问该网站以获得更多的信息。

(OTI 被IBM收购之后,并入IBM公司的WebSphere项目,最终发布了WebSphere Studio Device Developer,可以从http://www.ibm.com/embedded/ 下载到。WebSphere中的许多技术,也被应用到开源项目Eclipse之中。)

[Personal Java]

Personal Java是Sun公司专门为Windows CE 2.11设计的Java 运行环境,该运行环境的目标硬件平台是MIPS和SH3,并且要求目标平台至少具备16 MB的存储空间和16色或者是灰度显示设备。经测试Personal Java运行环境还可以在Windows CE 2.12, IBM Workpad Z50, Compaq Aero 2100以及HP Jornada 430 SE等便携式设备上运行。由于Windows CE 2.11中使用了一些与Windows CE 2.0不同的I/O函数,因此Personal Java不能够很好的在Windows CE 2.0上运行,并且Sun公司也没有计划继续完善对Windows CE 2.0的支持。根据Sun 公司网站所提供的消息,目前有一个团队正在开发基于Windows CE 3.0 (Pocket PC 3.0) 的Personal Java,并且计划于2000年10月发布一个测试版本。但是知道作者撰稿之日为止,我们还是没有能够从Sun 公司的网站下载到支持Pocket PC 3.0的Personal Java。

Personal Java支持标准Java语言1.1.6版本的一个子集,此外又增加了一些专门为Windows CE设计的API 。熟悉Java的开发人员能够在自己熟悉的Java开发平台上进行应用程序开发,唯一需要注意的就是不能够使用Personal Java 所不支持的类库与特性。

在Personal Java中完全支持的标准Java类库包如下:


java.applet           java.awt.datatransfer      java.awt.event
java.awt.image        java.beans                 java.lang
java.lang.reflect     java.net                   java.net
java.text             java.util

此 外,在Personal Java中还包括了一些不完全支持的标准Java类库包(例如 java.awt和java.io)和一些可支持可不支持的标准Java类库包(例如java.math, 和java.rmi)。开发人员使用这些类库时必须注意这些类库是否被Personal Java 支持或者是其特性是否与标准Java类库有所不同。

Personal Java虽然没有能够提供一个集成开发环境,但是它为开发人员提供了一个模拟运行环境(Personal Java Emulation Environment, PJEE),使得开发人员能够在开发平台(桌面计算机)上模拟运行专门为Windows CE设计的应用程序。 PJEE有点类似于标准的Java运行环境(Java Runtime Environment, JRE),用户需要将其安装在自己的开发平台上并且设置PATH, JAVA_HOME, CLASSPATH 等环境变量才能够使用。与标准JRE相类似,在PJEE中开发人员通过命令行来启动Personal Java应用程序,例如命令pjava MyApp可以启动一个名为MyApp 的应用程序。目前版本的PJEE仅仅支持Windows和UNIX两个平台。

Personal Java的网站地址为:http://java.sun.com/products/personaljava/。感兴趣的读者可以访问该网站以获得更多的信息。

(Personal Java现在被称为J2ME Personal Profile。)

[Waba]

Waba 是一种专门为微小型设备设计的程序开发平台,在该平台上定义了一种程序设计语言,一个虚拟机,一种类库文件格式以及一组基本类库。由于Waba语言的语法 是Java语言的语法的严格子集,Waba平台的类库文件格式也是Java平台类库文件格式的严格子集,因此熟悉Java的开发人员能够利用自己已经熟悉 的Java开发平台进行Waba程序开发。

Waba平台 所针对的是例如手机、个人数字助理、掌上型电脑、多功能计算器等硬件资源非常紧张的微小型设备。因此,Waba的编程语言、虚拟机和基本类库都针对微小型 设备进行了优化处理。在Java语言中需要耗费大量内存或者是被认为与微小型设备无关的特性均被排除在Waba平台之外。同样,Waba平台也对Java 平台的基本类库进行了大幅度裁减,从而使得Waba平台只需要占用很少的硬件资源而仍然能够满足微小型设备应用程序设计的需要。

和Java 应用程序相类似,Waba应用程序能够在任何安装了Waba平台的操作系统上运行。最早的Waba平台是针对Windows CE操作系统进行开发的,但是目前Waba虚拟机已经被移植到多种平台上,其中包括AmigaOS, BeOS, Linux, MacOS, MS-DOS, Newton, OS/2, PalmOS和Windows。 为了保持与Java平台的兼容,Waba还提供了一系列过渡类库使得Waba应用程序也能够在仅仅任何安装了Java运行环境的平台上运行。它既可以是 Windows或者UNIX下面的普通应用程序(Application),也可以是内嵌在浏览器中的一个小应用程序(Applet)。

WabaSoft 提供了一个软件开发工具包(Software Development Kit),称为Waba SDK 。这个工具包提供了所有的Waba基本类库,开发人员可以将这些基本类库添加到自己熟悉Java开发环境中去,然后在自己熟悉的Java开发环境中进行 Waba应用程序开发。一个最基本的Waba开发环境是Java SDK + Waba SDK,开发人员需要利用 Java SDK中提供的javac来编译Waba应用程序。此外,Waba SDK 还提供了针对一个针对Windows CE的代码转换工具ExeGen和Warp,利用这两个工具开发人员能够将编译以后的Waba类库文件转换成Windows CE平台上的可执行文件。

随着Waba平台在嵌入式系统中的广泛应用,专门为Waba 设计的集成开发环境也不断的涌现出来,VisualWaba和UIGen 可以说是这些第三方集成开发环境中的佼佼者。VisualWaba和UIGen 本身都是利用Java开发的应用程序,用来进行应用程序开发似乎有点反应迟钝,但是如果综合考虑一下Borland JBuilder和IBM Visual Age for Java的性能,VisualWaba和UIGen 的速度还是可以容忍的。相对来说UIGen 的功能还比较弱,只能够根据用户设计的界面生成相对应源代码。VisualWaba更类似于微软的Visual Basic,开发人员不但能够在其中进行界面设计和程序设计并生成源代码,还能够对程序进行编译,最后生成Windows CE平台上的可执行文件。

关于Waba平台的更多情况,感兴趣的读者可以访问如下网站:

(1) WabaSoft: http://www.wabasoft.com
(2) Waba Workbench: http://www.wabaworkbench.com
(3) Visual Waba: http://www.dmic.fr/palm/prg2.htm

[Jeode]

Jeode是Insignia 公司开发的针对多个平台的嵌入式Java运行环境。目前版本的Jeode虚拟机支持如下硬件平台和操作系统:

基于SH或者是MIPS芯片的Windows CE 2.12/3.0;
基于ARM芯片的Linux;
基于Intel x86芯片的Windows NT; 以及
基于PowerPC芯片的VxWorks。

Jeode 虚拟机支持Personal Java标准中的所有内容,因此基于Personal Java的应用程序基本上可以不加修改的在Jeode虚拟机上运行,基于Jeode 的应用程序也可以不加修改的在Personal Java上运行。这些共同的标准Java类库包括如下内容:


java.awt              java.applet                java.beans
java.io               java.lang                  java.lang.reflect
java.math             java.net                   java.rmi
java.security         java.sql                   java.text
java.util             java.util.zip

由 于Jeode 虚拟机使用了Insignia公司的动态适应性编译技术,并且实现了精确的同步垃圾回收,因此能够大大的提高Java应用程序的效率和反应速度。根据一些 用户以及第三方测试人员所提供的数据,动态适应性编译技术使得应用程序的执行效率比标准的解释执行方式提高6 倍,而对内存的要求基本上与标准的解释执行方式相同;动态适应性编译技术使得应用程序的执行效率与及时编译技术(JIT) 相类似,但是对内存的要求仅仅是即使编译技术的1/4。

Jeode 的网站地址为:http://www.insignia.com/products/default.asp。感兴趣的读者可以访问该网站以获得更多的信息。

mbed(Jeode在2003年被Insignia出卖给Esmertec公司,现在是Esmertec公司的嵌入式Java产品,支持所有流行的嵌入式操作系统,包括Windows CE.NET和Linux + Qtopia。该公司的网址为:http://www.esmertec.com/。)

[其他]

(1) CrEme

CrEme 是由Nsicom公司专门为Windows CE设计的Java虚拟机,该虚拟机符合Sun 公司所制定的Personal Java标准,因此能够运行基于Personal Java的应用程序。在Personal Java标准的基础上,CrEme虚拟机提供了对Swing的支持。但是,需要注意的是,在应用程序中使用Swing往往意味着更大的内存开销,因此 Swing 可以说是 CrEme的一个特色,但却不一定是CrEme的一个优点。

目前版本的CrEme虚拟机支持MIPS, Power PC, SH3, Strong Arm以及Intel x86 芯片上的Windows CE 2.x的所有版本。

参考站点:http://www.nsicom.com/products/creme.asp

(2) PERC

PERC是目前唯一的一个与Java 1.3相兼容的嵌入式Java虚拟机。该虚拟机目前支持68K, Intel x86, MIPS以及Power PC芯片上的Linux, Windows CE以及VxWorks等一系列操作系统。

参考站点:http://www.newmonics.com/

[结论]

本 文介绍了一系列基于Windows CE的Java虚拟机以及集成开发环境,其中包括 IBM公司的Visual Age Micro Edition, Sun公司的Personal Java, WabaSoft 发起的Waba,Insignia公司的Jeode,Nsicom公司的CrEme以及New Monics公司的PERC。众多厂家纷纷开发Windows CE的Java虚拟机以及集成开发环境表明:虽然微软公司由于控制Java的努力失败而对Java采取了抵制措施,但是嵌入式Java仍然顽强的在微软一 统天下的Windows CE市场中占据了一席之地。

在Java虚拟机的支持下,一个嵌入式应用程序不但可以运行在不同硬件平台不同版本的Windows CE操作系统上,还可以轻易的移植到其他嵌入式操作系统上。因此,在嵌入式应用程序开发方面,嵌入式Java比嵌入式VC或者是嵌入式VB具有不可替代的优势。

(文章比较老,就是收录进来做个纪录,各位就凑合看吧。)

在QNX平台上开发Java应用程序 (4)

By , 2004年8月19日 10:11 下午

4.1 SWT类库的安装和配置 Eclipse 项目的发布在IT界可以说是一次震撼,这不仅仅是因为IBM 公司无偿公开了花费4000万美元开发出来的一整套代码,也不仅仅是因为支持这个项目的包括目前在市场上相当吃香的Rational, Borland, Red Hat以及QNX等公司。最让人吃惊的是:Eclipse 项目的矛头直接针对的是IBM公司最亲密无间的Java合作夥伴 — Sun公司。就象Eclipse这个名字所意味的那样,IBM 的目的是要建立一套各种程序设计语言都能够使用的模块化的开发平台,并且希望它能够成为一个业界公认的标准平台。

Eclipse 项目中最令人震撼的一点是它用称为SWT的的图形库和工具包取代了Java标准中的AWT和Swing。根据Eclipse项目的解释,SWT直接调用了 操作系统的图形库,从而使得Java应用程序的Look & Feel 与操作系统的习惯完全一致;更为重要的是,对本地方法的直接调用大幅度的提高了基于SWT 的Java应用程序的运行速度。关于SWT与AWT/Swing的优点和缺点我们将在这一章的第三节中进行比较和讨论。

为了在我们的Java应用程序中使用SWT,我们需要做一点必要的配置,如下:

(1) /usr/eclipse/plugins/org.eclipse.core.runtime/runtime.jar 是Eclipse平台的运行库,需要将它放到类路径里面。
(2) /usr/eclipse/plugins/org.eclipse.ui/workbench.jar是Eclipse 平台的图形界面库,需要把它放到类路径里面。
(3) /usr/eclipse/plugins/org.eclipse.swt/ws/photon/swt.jar里面是SWT 的基本类库,需要将它放在类路径里面。
(4) /usr/eclipse/plugins/org.eclipse.swt/os/qnx/x86 这个目录下面存放的是SWT 与本地方法的接口,需要放在LD_LIBRARY_PATH里面。

修改.profile文件,如下:

export CLASSPATH=$CLASSPATH:/usr/eclipse/plugins/org.eclipse.core.runtime/runtime.jar
export CLASSPATH=$CLASSPATH:/usr/eclipse/plugins/org.eclipse.ui/workbench.jar
export CLASSPATH=$CLASSPATH:/usr/eclipse/plugins/org.eclipse.swt/ws/photon/swt.jar
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/eclipse/plugins/org.eclipse.swt/os/qnx/x86

改动过这些设置以后,最简单的办法是重新启动Photon来让这些新的设置生效。

4.2 一个简单的SWT图形用户界面

通常来说,构建一个基于SWT 的图形用户界面需要经过如下步骤:

(1) 创建一个Display对象,该对象代表一个SWT 进程(session)。
(2) 创建一个或者是多个Shell对象,一个Shell对象相当于我们在AWT/Sing里面所说的顶极容器,也就是应用程序的主窗口。
(3) 在Shell对象上面创建用户所需要的控件。
(4) 初始化所有的控件,包括大小和初始值等,为控件的事件注册必要的监听器Listener。
(5) 打开主窗口。
(6) 启动事件处理循环,一直到用户结束程序的运行。
(7) 垃圾回收。

下面是一个简单的基于SWT 的Java应用程序HelloSwt:


import org.eclipse.swt.widgets.*;
import org.eclipse.swt.SWT;

public class HelloSwt
{
public static void main(String[] args)
{
Display display = new Display();
Shell   shell   = new Shell(display);
Label   label   = new Label(shell, SWT.CENTER);
label.setText("Hello SWT!");
label.setBounds(shell.getClientArea());
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch()) display.sleep();
}
display.dispose();
}
}

使用下面的命令编译以上例程:

#j9c -classpath $CLASSPATH HelloSwt.java

使用下面的命令运行以上例程:

#j9 HelloSwt

我 们可以看到,基于SWT的图形用户界面在外观上和基于AWT的图形用户界面有明显的不同。更为重要的是,能够明显的感受到HelloSwt的启动速度比 HelloAwt要快很多。 QNX 高效的微内核图形界面系统当然是提高用户应用程序运行速度的一个方面,但是更重要的是SWT 直接调用了QNX 的微内核图形界面系统的功能,而AWT 则没有利用到操作系统所提供的这些优势。

SWT 是一套与AWT/Swing 完全不同的图形界面系统,新接触SWT 的程序员还是需要花费一段时间来熟悉SWT的结构和API。下面推荐的几个参考资料能够让你轻松的开始利用SWT 进行图形用户界面设计:

The Programmer’s Guide for Eclipse, 这是Eclipse项目发布的官方程序员手册,其PDF 版可以从这个地址下载:

http://www.eclipse.org/documentation/pdf/org.eclipse.platform.doc.isv.pdf

这份文档也可以从这个网站联机查看:

http://download.eclipse.org/downloads/documentation/2.0/html/plugins/org.eclipse.platform.doc.isv/

另外,www.eclipse.org最近在其网站上发布了关于SWT的结构及其应用的一系列文章,也非常的有参考价值。如果有感兴趣的网友,请自行到 Eclipse 的网站查看。

4.3 关于SWT和AWT/Swing的一点讨论

通 过3.3 的讨论我们知道在AWT 中的图形用户界面是通过本地方法来实现的,每个AWT 方法都有一个与其对应的本地方法,称为peer。由于平台无关性的需要,AWT 所能够实现的功能是各种不同操作系统的图形库所提供的功能的交集。通过这种机制,在所有的平台上相同的AWT 控件的Java代码是一样的,其性能也是类似的。SWT 所采取的则是一种完全相反的方法,它是通过一些本地方法将操作系统的图形库完全的暴露给虚拟机。在这些本地方法的基础上,SWT 通过纯粹的Java代码实现了需要的图形界面功能。由于各个操作系统所提供的图形库是不一样的,同样一个控件在不同平台上的Java实现通常来说是不一样 的。基于同样的道理,同样的SWT 程序在不同平台上的性能和表现也许是不一样的。

SWT 所采取的这种方法决定了它在技术上要比AWT 要具有更多的优点,如下:

(1) 如果操作系统A 支持某种图形控件而操作系统B 不支持,AWT 就会出于平台无关性的要求拒绝提供这个控件。SWT 则会在操作系统A 上原封不动的调用操作系统所提供的控件,在操作系统B 上则使用该操作系统所提供的其它功能对该控件进行模拟。例如Windows平台本身就提供了树和表格等控件而其它一些操作系统不提供这些控件,SWT 在Widnows平台上就会直接调用Windows的方法来实现这些控件,AWT 为了实现平台无关性拒绝提供这些控件,Swing 则为了实现纯Java的目的在AWT 的基础上自己来画这些控件 — 尽管它画出来的东西很少有画得好的。

(2) 由于SWT 大量的采用了本地平台所提供的图形库,SWT 中的控件风格跟本地平台的UI风格是完全一致的,因为在SWT 中的控件基本上就是操作系统本身的控件。这一点对于AWT 来说是比较相似的,但是Swing 的表现就不太一样了,譬如说在Windows XP上面用Swing 画一颗树它看起来就跟Widnows 2000上面的树一模一样,尽管Windows XP跟Widnows 2000本身的树形控件是不一样的。

(3) 在SWT中,大部份的事物逻辑都是用Java写的,在SWT 中C/C++代码的比重远比AWT中C/C++代码比重要小。这样使得程序设计人员能够更加方便的对SWT 应用程序进行调试,也能够更清楚的知道在后台运行的本地方法究竟在做什么事情。更为重要的是,SWT利用比AWT 更少的C/C++ 代码实现了比AWT 更快的图形用户界面,这个优势在嵌入式应用中往往是决定性的。

SWT 的缺点主要在于两点:(1) 不是Java语言标准;和(2) 支持的平台太少。目前版本的Eclipse仅仅支持Windows 98/ME/2000/XP, RH 7.1, SuSE 7.l, Solaris 8, QNX, AIX和HP-UX几个有限的平台。而作为Java 语言标准的AWT/Swing 则在目前大部份的主流和非主流操作系统上都有支持。

在QNX平台上开发Java应用程序 (4)

By , 2004年8月19日 10:10 下午

4.1 SWT类库的安装和配置 Eclipse 项目的发布在IT界可以说是一次震撼,这不仅仅是因为IBM 公司无偿公开了花费4000万美元开发出来的一整套代码,也不仅仅是因为支持这个项目的包括目前在市场上相当吃香的Rational, Borland, Red Hat以及QNX等公司。最让人吃惊的是:Eclipse 项目的矛头直接针对的是IBM公司最亲密无间的Java合作夥伴 — Sun公司。就象Eclipse这个名字所意味的那样,IBM 的目的是要建立一套各种程序设计语言都能够使用的模块化的开发平台,并且希望它能够成为一个业界公认的标准平台。

Eclipse 项目中最令人震撼的一点是它用称为SWT的的图形库和工具包取代了Java标准中的AWT和Swing。根据Eclipse项目的解释,SWT直接调用了 操作系统的图形库,从而使得Java应用程序的Look & Feel 与操作系统的习惯完全一致;更为重要的是,对本地方法的直接调用大幅度的提高了基于SWT 的Java应用程序的运行速度。关于SWT与AWT/Swing的优点和缺点我们将在这一章的第三节中进行比较和讨论。

为了在我们的Java应用程序中使用SWT,我们需要做一点必要的配置,如下:

(1) /usr/eclipse/plugins/org.eclipse.core.runtime/runtime.jar 是Eclipse平台的运行库,需要将它放到类路径里面。
(2) /usr/eclipse/plugins/org.eclipse.ui/workbench.jar是Eclipse 平台的图形界面库,需要把它放到类路径里面。
(3) /usr/eclipse/plugins/org.eclipse.swt/ws/photon/swt.jar里面是SWT 的基本类库,需要将它放在类路径里面。
(4) /usr/eclipse/plugins/org.eclipse.swt/os/qnx/x86 这个目录下面存放的是SWT 与本地方法的接口,需要放在LD_LIBRARY_PATH里面。

修改.profile文件,如下:

export CLASSPATH=$CLASSPATH:/usr/eclipse/plugins/org.eclipse.core.runtime/runtime.jar
export CLASSPATH=$CLASSPATH:/usr/eclipse/plugins/org.eclipse.ui/workbench.jar
export CLASSPATH=$CLASSPATH:/usr/eclipse/plugins/org.eclipse.swt/ws/photon/swt.jar
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/eclipse/plugins/org.eclipse.swt/os/qnx/x86

改动过这些设置以后,最简单的办法是重新启动Photon来让这些新的设置生效。

4.2 一个简单的SWT图形用户界面

通常来说,构建一个基于SWT 的图形用户界面需要经过如下步骤:

(1) 创建一个Display对象,该对象代表一个SWT 进程(session)。
(2) 创建一个或者是多个Shell对象,一个Shell对象相当于我们在AWT/Sing里面所说的顶极容器,也就是应用程序的主窗口。
(3) 在Shell对象上面创建用户所需要的控件。
(4) 初始化所有的控件,包括大小和初始值等,为控件的事件注册必要的监听器Listener。
(5) 打开主窗口。
(6) 启动事件处理循环,一直到用户结束程序的运行。
(7) 垃圾回收。

下面是一个简单的基于SWT 的Java应用程序HelloSwt:


import org.eclipse.swt.widgets.*;
import org.eclipse.swt.SWT;

public class HelloSwt
{
public static void main(String[] args)
{
Display display = new Display();
Shell   shell   = new Shell(display);
Label   label   = new Label(shell, SWT.CENTER);
label.setText("Hello SWT!");
label.setBounds(shell.getClientArea());
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch()) display.sleep();
}
display.dispose();
}
}

使用下面的命令编译以上例程:

#j9c -classpath $CLASSPATH HelloSwt.java

使用下面的命令运行以上例程:

#j9 HelloSwt

我 们可以看到,基于SWT的图形用户界面在外观上和基于AWT的图形用户界面有明显的不同。更为重要的是,能够明显的感受到HelloSwt的启动速度比 HelloAwt要快很多。 QNX 高效的微内核图形界面系统当然是提高用户应用程序运行速度的一个方面,但是更重要的是SWT 直接调用了QNX 的微内核图形界面系统的功能,而AWT 则没有利用到操作系统所提供的这些优势。

SWT 是一套与AWT/Swing 完全不同的图形界面系统,新接触SWT 的程序员还是需要花费一段时间来熟悉SWT的结构和API。下面推荐的几个参考资料能够让你轻松的开始利用SWT 进行图形用户界面设计:

The Programmer’s Guide for Eclipse, 这是Eclipse项目发布的官方程序员手册,其PDF 版可以从这个地址下载:

http://www.eclipse.org/documentation/pdf/org.eclipse.platform.doc.isv.pdf

这份文档也可以从这个网站联机查看:

http://download.eclipse.org/downloads/documentation/2.0/html/plugins/org.eclipse.platform.doc.isv/

另外,www.eclipse.org最近在其网站上发布了关于SWT的结构及其应用的一系列文章,也非常的有参考价值。如果有感兴趣的网友,请自行到 Eclipse 的网站查看。

4.3 关于SWT和AWT/Swing的一点讨论

通 过3.3 的讨论我们知道在AWT 中的图形用户界面是通过本地方法来实现的,每个AWT 方法都有一个与其对应的本地方法,称为peer。由于平台无关性的需要,AWT 所能够实现的功能是各种不同操作系统的图形库所提供的功能的交集。通过这种机制,在所有的平台上相同的AWT 控件的Java代码是一样的,其性能也是类似的。SWT 所采取的则是一种完全相反的方法,它是通过一些本地方法将操作系统的图形库完全的暴露给虚拟机。在这些本地方法的基础上,SWT 通过纯粹的Java代码实现了需要的图形界面功能。由于各个操作系统所提供的图形库是不一样的,同样一个控件在不同平台上的Java实现通常来说是不一样 的。基于同样的道理,同样的SWT 程序在不同平台上的性能和表现也许是不一样的。

SWT 所采取的这种方法决定了它在技术上要比AWT 要具有更多的优点,如下:

(1) 如果操作系统A 支持某种图形控件而操作系统B 不支持,AWT 就会出于平台无关性的要求拒绝提供这个控件。SWT 则会在操作系统A 上原封不动的调用操作系统所提供的控件,在操作系统B 上则使用该操作系统所提供的其它功能对该控件进行模拟。例如Windows平台本身就提供了树和表格等控件而其它一些操作系统不提供这些控件,SWT 在Widnows平台上就会直接调用Windows的方法来实现这些控件,AWT 为了实现平台无关性拒绝提供这些控件,Swing 则为了实现纯Java的目的在AWT 的基础上自己来画这些控件 — 尽管它画出来的东西很少有画得好的。

(2) 由于SWT 大量的采用了本地平台所提供的图形库,SWT 中的控件风格跟本地平台的UI风格是完全一致的,因为在SWT 中的控件基本上就是操作系统本身的控件。这一点对于AWT 来说是比较相似的,但是Swing 的表现就不太一样了,譬如说在Windows XP上面用Swing 画一颗树它看起来就跟Widnows 2000上面的树一模一样,尽管Windows XP跟Widnows 2000本身的树形控件是不一样的。

(3) 在SWT中,大部份的事物逻辑都是用Java写的,在SWT 中C/C++代码的比重远比AWT中C/C++代码比重要小。这样使得程序设计人员能够更加方便的对SWT 应用程序进行调试,也能够更清楚的知道在后台运行的本地方法究竟在做什么事情。更为重要的是,SWT利用比AWT 更少的C/C++ 代码实现了比AWT 更快的图形用户界面,这个优势在嵌入式应用中往往是决定性的。

SWT 的缺点主要在于两点:(1) 不是Java语言标准;和(2) 支持的平台太少。目前版本的Eclipse仅仅支持Windows 98/ME/2000/XP, RH 7.1, SuSE 7.l, Solaris 8, QNX, AIX和HP-UX几个有限的平台。而作为Java 语言标准的AWT/Swing 则在目前大部份的主流和非主流操作系统上都有支持。

 

Panorama Theme by Themocracy