Java Web_Java通信
Java通信
Java通信3.0 API是一个Java的扩展,有利于发展独立于平台的通信应用,如智能卡,嵌入式系统,销售点设备,金融服务设备,传真机,调制解调器,显示终端,以及机器人设备的技术。
Java通信API(也被称为javax.comm)提供的应用程序访问到RS- 232硬件(串口)和有限的访问IEEE- 1284并行端口,SPP模式。
Java提供了 CommunicationAPI(包含于javax.comm包中)用于通过与机器无关的方式,控制各种外部设备。Communications API,是标准的Java的扩展部分,它在JavaAPI中是没有附带的。
目前3.0可用于Sparc结构下的Solaris系统和x86以及x86下的Linux系统的API的实现。
Windows版本只能用较老的版本了,完整的2.0版本地址:http://mdubuc.freeshell.org/Jolt/javacomm20-win32.zip
成功下载解压后,目录下有3个文件:
comm.jar:拷贝到%JAVA_HOME%\jre\lib\ext
javax.comm.properties:拷贝到%JAVA_HOME%\jre\lib\
win32com.dll:拷贝到%JAVA_HOME%\jre\lib\ext
注:%JAVA_HOME%:jdk的路径
Java的这个扩展类就不做详细介绍了,网上可以搜索到很多相关资料。下面我所做的是一个基于JAVA读取蓝牙GPS接收器中的数据。在我们下载的完整的2.0版本的API中的samples中提供了一些简单的实例,这里我采用了其中的SerialDemo,这个实例做了一个UI窗口,可以显示获取到的信息,设置各个参数,打开/关闭端口等功能。可以说这个实例将我所要做的大部分主要功能都已做好,我只需在这个实例的基础上来获得坐标位置并保存即可。
以下只截取部分主要代码:
1. 列举出本机所有可用串口
void listPortChoices() {
CommPortIdentifier portId;
Enumeration en = CommPortIdentifier.getPortIdentifiers();
// iterate through the ports.
while (en.hasMoreElements()) {
portId = (CommPortIdentifier) en.nextElement();
//如果端口的类型是串行口的话,将端口的名称添加到下拉框中。
if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
portChoice.addItem(portId.getName());
}
}
//设置下拉框的选择项
portChoice.select(parameters.getPortName());
}
2. 打开连接
public void openConnection() throws SerialConnectionException {
//获取一个要打开的端口CommPortIdentifier对象。
try {
portId = CommPortIdentifier.getPortIdentifier(parameters.getPortName());
} catch (NoSuchPortException e) {
throw new SerialConnectionException(e.getMessage());
}
// 打开CommPortIdentifier对象代表端口。
//公开征集一个比较长的30秒超时,让不同的应用程序reliquish的端口,如果用户想要的。
try {
sPort = (SerialPort)portId.open("SerialDemo", 30000);
} catch (PortInUseException e) {
throw new SerialConnectionException(e.getMessage());
}
// Set the parameters of the connection. If they won't set, close the
// port before throwing an exception.
//设置连接参数。如果他们将不会设置,在抛出异常之前关闭该端口。
try {
setConnectionParameters();
} catch (SerialConnectionException e) {
sPort.close();
throw e;
}
//打开连接的输入和输出流。如果他们不打开,关闭端口抛出异常前。
try {
os = sPort.getOutputStream();
is = sPort.getInputStream();
} catch (IOException e) {
sPort.close();
throw new SerialConnectionException("Error opening i/o streams");
}
//创建一个新的KeyHandler响应messageAreaOut。添加KeyHandler keyListener messageAreaOut。
keyHandler = new KeyHandler(os);
messageAreaOut.addKeyListener(keyHandler);
//为串行端口添加一个事件侦听器。
try {
sPort.addEventListener(this);
} catch (TooManyListenersException e) {
sPort.close();
throw new SerialConnectionException("too many listeners added");
}
//notifyOnDataAvailable设置为true,允许事件驱动的输入。
sPort.notifyOnDataAvailable(true);
//设置notifyOnBreakInterrup允许事件驱动的中断处理。
sPort.notifyOnBreakInterrupt(true);
//设置接收超时,允许打破轮询循环在输入处理。
try {
sPort.enableReceiveTimeout(30);
} catch (UnsupportedCommOperationException e) {
}
//添加所有权监听器,让所有权的事件处理。
portId.addPortOwnershipListener(this);
open = true;
}
3. 事件侦听器监听到数据
public void serialEvent(SerialPortEvent e) {
//创建一个StringBuffer和int接收输入数据。
StringBuffer inputBuffer = new StringBuffer();
int newData = 0;
//确定事件的类型。
switch (e.getEventType()) {
//DATA_AVAILABLE端口缓冲区读取数据,直到返回-1。如果\r是代替\n收到正确的换行处理。
case SerialPortEvent.DATA_AVAILABLE:
while (newData != -1) {
try {
newData = is.read();
if (newData == -1) {
break;
}
if ('\r' == (char)newData) {
inputBuffer.append('\n');
} else {
inputBuffer.append((char)newData);
}
} catch (IOException ex) {
System.err.println(ex);
return;
}
}
//附加收到的数据来messageAreaIn。
messageAreaIn.append(new String(inputBuffer));
//在这里我截取读入的数据,传送到ParseData()这个类中。
String inString=new String(inputBuffer);
new ParseData().parse(inString);
break;
// If break event append BREAK RECEIVED message.
//如果中断事件追加BREAK收到的消息。
case SerialPortEvent.BI:
messageAreaIn.append("\n--- BREAK RECEIVED ---\n");
}
4. ParseData()
import java.io.IOException;
public class ParseData {
String xString="";
String yString="";
String timeStr="";
String state="";
//分析接口
public boolean parse(String sentence)
{
String rawData = sentence;
try
{
if (!(rawData.length()>0))
{
return false;
}
sentence = sentence.substring(1, sentence.indexOf('*') - 1);
String[] words =getWords(sentence);
if (words[0].equals("GPGGA")) {
return parseGPGGA(words);
}else if (words[0].equals("GPRMC")) {
return false;
}else if (words[0].equals("GPGSA")) {
return false;
}else if (words[0].equals("GPGSV")) {
return false;
}else {
return false;
}
}
catch (Exception e)
{
e.printStackTrace();
return false;
}
}
public boolean parseGPGGA(String[] words)
{
//取经纬度
if (words[6].length() > 0)
{
timeStr=getTimeFormat(words[1]);
yString=getYformat(words[2]);
xString=getXformat(words[4]);
state=words[6];
String gpsString="时间:"+timeStr+"\n状态:"+state+"\n北纬:"+yString+"\n东经:"+xString+"\n";
try {
new FileOutput().file(gpsString);
} catch (IOException e) {
e.printStackTrace();
}
return true;
}else {
return false;
}
}
//拆分字符串为字符串数组
public String[] getWords(String str){
String[] words=str.split(",");
return words;
}
//时间
public String getTimeFormat(String str){
int t1=Integer.parseInt(str.substring(0, 2))+8;
String t2=str.substring(2, 4);
String t3=str.substring(4, str.length());
return String.valueOf(t1)+"点"+t2+"分"+t3+"秒";
}
//东经
public String getXformat(String str){
double a1=Double.valueOf(str.substring(0, 3));
double a2=Double.valueOf(str.substring(3, str.length()));
double aa1=a2/60;
return String.valueOf(a1+aa1);
}
//北纬
public String getYformat(String str){
double b1=Double.valueOf(str.substring(0, 2));
double b2=Double.valueOf(str.substring(2, str.length()));
double bb1=b2/60;
return String.valueOf(b1+bb1);
}
}
5. FileOutput()
import java.io.*;
class FileOutput {
public void file(String str) throws IOException {
byte b[];
//获取当前类文件所在路径
String classPath=Class.class.getResource("/").getPath().substring(1);
classPath=classPath.substring(0, classPath.lastIndexOf("/"));
String parentPath=classPath.substring(0, classPath.lastIndexOf("/"));
//处理文件路径乱码问题
parentPath = java.net.URLDecoder.decode(parentPath, "utf-8");
File f = new File(parentPath + "/gpsdata.txt");
f.createNewFile();
b = str.getBytes();
//追加内容
// FileOutputStream fos = new FileOutputStream(f, true);
//覆盖内容
FileOutputStream fos = new FileOutputStream(f);
fos.write(b);
fos.close(); }
}
注:
1. UI窗口中根据设备选择设置端口及波特率,点击“Open Port”打开端口,读取数据。
2. 4种常用的 NMEA0183标准格式说明
$GPGGA,012440.00,3202.1798,N,11849.0763,E,1,05,2.7,40.2,M,0.5,M,,*6F..
1 时间: 01+8=9点24分40.00秒
2 纬度: 北纬32度02.1798分
3 经度: 东经118度49.0763分
4 定位: 1=(定位sps模式) 0=(未定位)
5 应用卫星数: 05个
6 HDOP: 2.7米
7 海拔: 40.2
8 海拔单位: M=(米)
9 WGS84水准面划分: 0.5
10 WGS84水准面划分单位 M(米)
11
12 校验位: 6F
$GPRMC,013946.00,A,3202.1855,N,11849.0769,E,0.05,218.30,111105,4.5,W,A*20..
01 时间01时39分46.00秒
02 定位状态 A=可用 V=警告(不可用)
03 纬度: 北纬(N) 32度02.1855分
04 经度: 东经(E) 118度49.0769分
05 相对位移速度: 0.05 knots
06 相对位移方向: 218.30度
07 日期: 11日11月05年(日日月月年年)
08
09
10 检查位
$GPGSA,A,3,01,03,14,20,,,,,,,,,2.6,2.5,1.0*35..
01 模式2: A=自动 M=手动
02 模式1: 1=未定位 2=二维定位 3=三维定位
03 卫星编号: 01到32
04 PDOP-位置精度稀释: (2.6) 0.5--99.9
05 HDOP-水平经度稀释: (2.6) 0.5--99.9
06 VDOP-垂直经度稀释: (1.0) 0.5--99.9
07 检验位 35
$GPGSV,2,1,08,01,62,160,42,03,23,189,42,06,23,049,32,14,24,150,35*78..
01 天空中收到讯号的卫星总数
02 定位的卫星总数
03 天空中卫星总数
04 (01,62,160,42)分别是卫星编号01-32,卫星仰角00-90度,卫星方位角000-359度,讯号噪声比00-99dB
以下类似(03,23,189,42) (06,23,049,32) (14,24,150,35)
05 Checksum检查位*78
附加:
/**
*获得本机串行和并行端口号
*/
import javax.comm.*;
import java.util.Enumeration;
public class GpsText
{
public static void main(String args[]){
Enumeration ports;
System.out.println("Verifying Build Environment");
try{
ports=CommPortIdentifier.getPortIdentifiers();
if(ports==null){
System.out.println("No comm ports found!");
return;
}
while(ports.hasMoreElements()){
System.out.println("Here is a prot ["+((CommPortIdentifier)ports.nextElement()).getName()+"]");
}
}catch(Exception e){
System.out.println("Failed to enumerate ports ["+e.getMessage()+"]");
e.printStackTrace();
}
System.out.println("Complete");
}
}