最近有不少网友来这里问电信串口书写实际开发中的应用是怎么写的,现在我把一段写出来,供大家参考。如果还有想了解更细的加我QQ吧,444084929 回钦波
package huiqinbo.telecom;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.comm.CommDriver;
import javax.comm.CommPortIdentifier;
import javax.comm.SerialPort;
import javax.comm.SerialPortEvent;
import javax.comm.SerialPortEventListener;
import java.util.logging.Logger;
//import org.apache.log4j.Logger;
/**
* Title: 串口管理程序 Description: 创建串口,初始化,监听,并处理HUM的上行 Copyright: Copyright (c)
* 2007 Company: EVERSINO gift 1.初始化和打开端口 --->定义串口流对象 --->向串中对象的数据流写数据
*
* gift 2.串口对象注册监听器--->监听吕征听事件发生--->如果事件发生,从串口对象的数据流读取数据 --->计算机处理接收的数据
*
* @author Xuze
* @version 1.0
*/
public class PortServer_New extends Thread implements SerialPortEventListener,
PortServerItf {
private static Logger oLogger = Logger
.getLogger(PortServer.class.getName());
// gift_new
public static final boolean UETCP_SMS = false;
// define error info
public static final int SUCCESS = 0;
public static final int ErrorDataFormat = 1;
public static final int InvalidPhoneNumber = 2;
public static final int InvalidRecvTime = 3;
public static final int InvalidContent = 4;
public static final int InvalidRetryTime = 5;
public static final int InvalidIsReplay = 6;
public static final int InvalidMOId = 7;
public static final int InvalidStatus = 8;
public static final int SwapFileNotExist = 30;
public static final int SwapFileCantOpen = 31;
public static final int MCCCantCon = 40;
public static final int SERIALPORT_NOTREADY = -1; // not ready
public static final int SERIALPORT_IDEL = 0; //idel 空闲
public static final int SERIALPORT_RECVMSG = 1; // recvmsg
public static final int SERIALPORT_SENDMSG = 2;
public static int SerStatus = SERIALPORT_NOTREADY;
// after add
public static boolean canSend = false;
public static boolean canSendNext = false;
public static boolean portSendOK = true;
private String sPortName = GSMModule.CONF.getElementValue("serialportname");
// SerialPort类可以产生串口对象
public static SerialPort serialPort = null;
public static InputStream serialPortIn = null;
public static OutputStream serialPortOut = null;
private final int nPortSpeed = 9600;
public static int nInitCompleted = 0;
private byte[] readBuffer = null;
private int readLen = 0;
private boolean bReadBufInit = false;
public void run() {
initDriver();
try {
// CommPortIdentifier 主要负责端口的初始化和开启端口的注册、查找、初始化以及为端口绑定应用程序并为此程序打开端口、监听端口占用状态等端口管理工作由CommPortIdentifier负责,
//而CommPort则是管理实际的数据传输等工作,比如使用CommPort获取输入输出流
CommPortIdentifier portId = CommPortIdentifier
.getPortIdentifier(sPortName);
try {
//gift上面这句代码作用是为一个应用程序实例绑定此端口,appName为java实例名称,outTime为端口打开时阻塞等待时间,单位是ms,在调用CommPort的close()方法之前此端口被名为appName的实例程序独占
// 打开端口
serialPort = (SerialPort) portId.open("GSMPort", 2000);
//通知 有数据到达
serialPort.notifyOnDataAvailable(true); //// 当有数据时通知
//gift 使用SerialPort类的addEventListener( SerialPortEventListener arg0)方法为串口添加事件监听.
serialPort.addEventListener(this); // gift this ?
serialPortIn = serialPort.getInputStream();
serialPortOut = serialPort.getOutputStream();
//gift 设置串口读写参数
serialPort.setSerialPortParams(nPortSpeed, // 端口波特率是9 600 bps
SerialPort.DATABITS_8, SerialPort.STOPBITS_1, // 数据位是8 位
SerialPort.PARITY_NONE);
System.out.println("Create SerialPort...");
System.out.println("ATE0");
serialPortOut.write("ATE0\r\n".getBytes());
serialPortOut.flush();
sleep(1000);
if (!PduUtil.CDMA) {
System.out.println("AT+CMGF=0"); // 0,PDU的方式;1,文本方式
serialPortOut.write("AT+CMGF=0\r".getBytes());
serialPortOut.flush();
sleep(1000);
System.out.println("AT+CNMI=2,2");
serialPortOut.write("AT+CNMI=2,2\r".getBytes());
serialPortOut.flush();
sleep(1000);
} else {
// WLZ: For CDMA
System.out.println("AT+CMGF=1"); // CDMA下仅仅支持文本方式发送
serialPortOut.write("AT+CMGF=1\r\n".getBytes());
serialPortOut.flush();
sleep(1000);
// +CNMI=[<mode>=1 [,<mt>=2 [,<bm>=0 [,<ds>=1[, <bfr>=0]]]]]
/*
* 来设置新短信上报给TE 的程序。其中:
* <mode>和<bfr>用来设置新短信通知(包括+CMTI、^HCMT、+CDSI、^HCDS 4 种)上报给TE
* 的方式。 <mt>用来设置接收新短信时,采用直接上报给TE 还是存储在MT 中并上报存储位置。 <bm>暂不使用。
* <ds>用来设置是否上报短信状态报告(+CDSI,^HCDS)。
* <mode>:设置短信通知方式(目前支持之mode=1)。 0:将短信通知缓存在ME 中,如果ME
* 的缓存已满,则用新通知覆盖最老的通知。 1:将短信通知直接发送给TE。当无法发送时(例如,处在online
* data 模式),则丢弃通知。 <ds>:用于设置短信回执。 0:不向TE 发送短信回执。
* <ds>1:不将短信回执存储在MT 中,将短信回执直接发送给TE。 ^HCDS:
* <callerID>,<year>,<month>, <day>, <hour>,
* <minute>,<second>, <lang>, <format>, <length>, <prt>,
* <prv>,<type>,<tag><CR><LF><msg> <CTRL+Z> 2:短信回执存储在MT
* 中,则通过+CDSI 向TE 发送一条存储位置通知。 +CDSI:<mem>,<index>
*/
/*
* System.out.println("AT+CNMI=1,2,0,1,0"); //CDMA设置方式
* serialPortOut.write("AT+CNMI=1,2,0,1,0\r\n".getBytes());
*/
System.out.println("AT+CNMI=1,2,0,0,0"); // CDMA设置方式
serialPortOut.write("AT+CNMI=1,2,0,0,0\r\n".getBytes());
serialPortOut.flush();
sleep(1000);
System.out.println("AT^HSMSSS=0,0,6,0"); // 6,文本以Unicode编码发送;
// 1,ASCII编码发送
serialPortOut.write("AT^HSMSSS=0,0,6,0\r\n".getBytes());
// serialPortOut.write("AT^HSMSSS=0,0,6,0\r\n".getBytes());
serialPortOut.flush();
sleep(1000);
}
// wlz +CMGD:删除短信命令
/*
* <index<index> :短信的存储位置 如果给出了第二个参数<delflag>且不为0,则MT
* 会忽略参数<index>,而按照<delflag>参数执行,<delflag>: 0:(或缺省)
* 删除有<index>指定的短信。 1:删除首选存储器上所有的已读短信,保留未读短信、已发送短信和未发送短信
* 2:删除首选存储器上所有的已读短信和已发送短信,保留未读短信和未发送短信。
* 3:删除首选存储器上所有的已读短信、已发送短信和未发送短信,保留未读短信。 4:删除首选存储器上所有短信,包括未读短信。
*/
System.out.println("AT+CMGD=0,4");
serialPortOut.write("AT+CMGD=0,4\r\n".getBytes());
serialPortOut.flush();
sleep(7000);
System.out.println("SerialPort init completed!");
nInitCompleted = 1;
readBuffer = new byte[2000];
bReadBufInit = true;
readLen = 0;
SerStatus = isbusy;
} catch (Exception e) {
System.err.println(e.toString());
oLogger.warning(e.toString());
}
} catch (Exception e) {
System.err.println(e.toString());
oLogger.warning(e.toString());
}
}
/**
* 1.MT只需要知道串口isbusy?,yes 不发送返回 no将数据发送到串口中
* 2.串口发送完成后需要把结果发送回MT中,包括:ok or fail
* @param oMT
* @return
*/
public boolean sendMessage(MTDataStruct oMT) {
String msisdn = "", sendContent = "";
msisdn = oMT.getMSISDN();
sendContent = oMT.getContent();
System.out.println("-->[info]mtgateway, is sending.");
String str[] = PduUtil.pduPack(msisdn, sendContent);
SerStatus = SERIALPORT_SENDMSG;
// ------------------------------start send -----------------------
// boolean nSendMsgResult = sendMessage(str[0],str[1]);
boolean nSendMsgResult = true;
try {
if (PduUtil.CDMA) {
PortServer.serialPortOut.write(str[0]
.getBytes(GSMModule.ENCODE)); // str[0] 为号码
PortServer.serialPortOut.flush();
System.out.println(" ----> 短信发送:AT命令已发出 "
+ str[0].replace("\r\n", ""));
canSend = false;
Long startTime = System.currentTimeMillis();
while (true) {
if (canSend) {
PortServer.serialPortOut.write(str[1]
.getBytes(GSMModule.ENCODE)); // str[1] 为内容
PortServer.serialPortOut
.write(new byte[] { 0x00, 0x1A });
PortServer.serialPortOut.flush();
System.out.println(" ----> 短信发送:内容已发出 " + str[1]);
try {
Thread.sleep(500); // 尝试让线程休眠200毫秒,这样做可以降低CPU的使用率
} catch (Exception e) {
System.out.println("-->[error]mtgateway,"
+ e.toString());
oLogger.warning(e.toString());
}
break;
} else if ((System.currentTimeMillis() - startTime) > 1000) {
System.out.println(" ----> 发送超时,取消此次发送\r\n ");
PortServer.serialPortOut
.write(new byte[] { 0x00, 0x1B });
PortServer.serialPortOut.flush();
System.out.println(" ----> 短信发送:取消此次发送" + str[1]);
nSendMsgResult = false;
break;
}
}
} else {
// 保留PDU发送方式
PortServer.serialPortOut.write(str[0].getBytes());
PortServer.serialPortOut.write(str[1].getBytes());
PortServer.serialPortOut.write("\u001A\n".getBytes());
PortServer.serialPortOut.flush();
}
} catch (Exception e) {
nSendMsgResult = false;
System.out.println(" ----> 短信发送:短信发送异常 " + str[1]);
}
return nSendMsgResult; // 其实这个可合掉
// ------------------------------send end -----------------------
}
public void againSendMessage(){
}
/**
* 读短消息
* @param readCommand
*/
public void ReadSMS(String readCommand) {
try {
SerStatus = SERIALPORT_RECVMSG; //from MOGateWay
PortServer.serialPortOut.write(readCommand.getBytes());
PortServer.serialPortOut.flush();
} catch (Exception e) {
System.err.println("-->[error]mogateway, PortServer.serialPortOut Error:" + e.toString());
oLogger.warning(e.toString());
}
}
/**
* 删除短消息
* @param deleteCommand
*/
public void DeleteSMS(String deleteCommand) {
try {
PortServer.serialPortOut.write(deleteCommand.getBytes());
PortServer.serialPortOut.flush();
} catch (Exception e) {
System.err.println("-->[error]mogateway, PortServer.serialPortOut Error:" + e.toString());
oLogger.warning(e.toString());
}
}
/**
* 串口向SMSC发送AT命令
* //PortServer.serialPortOut.write("AT+CNMI=1,2,0,0,0\r\n".getBytes());
*/
public static void sendAtCommandOfString(String at) {
try {
PortServer.serialPortOut.write(at.getBytes());
PortServer.serialPortOut.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 串口向SMSC发送AT命令
* //PortServer.serialPortOut.write("AT+CNMI=1,2,0,0,0\r\n".getBytes());
*/
public static void sendAtCommandOfByte(byte[] at) {
try {
PortServer.serialPortOut.write(at);
PortServer.serialPortOut.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
private void initReadBuff() {
readBuffer = new byte[2000];
bReadBufInit = true;
readLen = 0;
}
/**
* gift:
* 使用上述方法注册了通知之后,还要实现串口的监听接口SerialPortEventListener,实现此接口的方法
public void serialEvent( SerialPortEvent arg0 ){}
通过SerialPortEvent的getEventType()方法可以得到当前事件的变量值,然后与上表中的事件值对比,即可知道当前串口上产生了哪种类型的事件.
使用SerialPort类的addEventListener( SerialPortEventListener arg0)方法为串口添加事件监听.
*/
// 当有可用数据时读取数据,并且给串口返回数据
public void serialEvent(SerialPortEvent serialPortEvent) {
switch (serialPortEvent.getEventType()) {
case SerialPortEvent.DATA_AVAILABLE: //gift有数据到达 able 能够..的, avail 效用,利益,有利
SerStatus = SERIALPORT_RECVMSG;
try {
if (!PduUtil.CDMA) {
// WLZ: For GSM
String s = "";
while (!s.endsWith("\r\n")) {
if (!bReadBufInit)
initReadBuff();
if (s.trim().indexOf("+CMT") == 0) {
System.out.println(s);
initReadBuff();
}
int nLen = serialPortIn.available();
serialPortIn.read(readBuffer, readLen, nLen);
readLen += nLen;
s = new String(readBuffer);
s = s.replace("\u0000", "");
// 对于"AT+CNMI=2,2"命令PDU数据位于最后,并用"\r\n"分开。
if (s.endsWith("\r\n")) {
String sTemp[] = s.split("\r\n");
s = sTemp[sTemp.length - 1]; // 最后一段数据
initReadBuff();
System.out
.println("-->[info]Serialport, received sms.");
break;
} else {
// 如果数据不完整,等待下次数据到达事件继续读取。
return;
}
}
if (nInitCompleted == 1) {
if (s.indexOf("OK") == 0 || s.indexOf("ERROR") == 0) {
System.out
.println("-->[info]Serialport, discard OK/ERROR AT commands.["
+ s + "]");
// 抛弃响应命令,不处理..
} else if (s.indexOf("+") == 0
|| s.indexOf("RING") == 0) {
System.out
.println("-->[info]Serialport, discard +/Ring AT commands.["
+ s + "]");
// 抛弃+XX(+CMT...)响应命令,不处理..
} else {
// 处理接收的短信数据
System.out
.println("-->[info]Serialport, forward sms to mogateway.");
MOGateWay mogateway = new MOGateWay(s);
mogateway.start();
}
} else {
// 抛弃数据不处理..
System.err
.println("-->[warnning]Serialport, initialization not completed and discard sms data:["
+ s + "]");
}
} else {
// WLZ: For CDMA
String s = "";
while (true) {
if (!bReadBufInit)
initReadBuff();
if (!isEmptyOrSegment())
initReadBuff();
int nLen = serialPortIn.available();
serialPortIn.read(readBuffer, readLen, nLen);
readLen += nLen;
s = new String(readBuffer);
s = s.replace("\u0000", "");
// System.out.println("-->[info]Serialport, BufferData:["
// +s+"]");
/*
* 打印输出流十六进制 System.out.println(s); byte[] sb =
* s.getBytes(); for (int i = 0; i < sb.length; i++) {
* System.out.print( PduUtil.byteToHexString(sb[i])+
* " "); } System.out.println();
*/
if (s.endsWith("\r\n")) {
/*
* 参照规范,以<CTRL+Z><CR><LF>结束只有三种情况: 1、新短信直接上报
* ^HCMT的末尾 2、新短信状态直接上报^HCDS的末尾 3、接受到读短信命令
* ^HCMGR发回数据的的末尾
*
* 后两种情况在本程序中不会出现。
*
* 先处理完整数据
*/
String endSignal = new String(new byte[] { 0x1A,
0x0D, 0x0A });
int indexofHCMT = s.indexOf("^HCMT:");
int indexofEndSignal = s.indexOf(endSignal);
while (indexofHCMT >= 0
&& indexofEndSignal > indexofHCMT) {
// WLZ: AT+CNMA需要发给模块,确认我们接收到了新短信,但是现在处于接收状态。
// WLZ add:
System.out
.println("AT+CNMA:确认收到一条直接发送给TE 的新短信!\r\n");
serialPortOut.write("AT+CNMA\r\n".getBytes());
serialPortOut.flush();
try {
Thread.sleep(500); // 尝试让线程休眠500毫秒,这样做可以降低CPU的使用率
} catch (Exception e) {
System.out.println("-->[error]mtgateway,"
+ e.toString());
oLogger.warning(e.toString());
}
// WLZ add-end
String getRealData = s.substring(indexofHCMT,
indexofEndSignal);
dealWithRealData(getRealData);
s = s.replace(getRealData + endSignal, "");
indexofHCMT = s.indexOf("^HCMT:");
indexofEndSignal = s.indexOf(endSignal);
}
initReadBuff();
// 再处理剩下的不完整数据及其他信息
String sTemp[] = s.split("\r\n");
for (int i = 0; i < sTemp.length; i++) {
if (sTemp[i].trim().equals("")
|| sTemp[i].trim().equals("OK")) {
continue;
}
System.out.println(" ----> 收到内容: "
+ sTemp[i]);
// 发送数据标识设置
if (sTemp[i].equals("> ")) {
MTGateWay.canSend = true;
SerStatus = SERIALPORT_SENDMSG;
}
// 发送失败,清除
if (sTemp[i].indexOf("ERROR:") >= 0) {
// wlz begin
// PortServer.serialPortOut.write( new
// byte[]{0x00,0x1B});
// /PortServer.serialPortOut.write(
// "\r\n".getBytes());
// PortServer.serialPortOut.flush();
// /System.out.println("发送失败!!! " + sTemp[i]
// );
// System.out.println("从新设置AT+CNMI=1,2,0,0,0");
// //CDMA设置方式
// serialPortOut.write("AT+CNMI=1,2,0,0,0\r\n".getBytes());
// serialPortOut.flush();
oLogger
.warning("-->[info]send cmd-sms got CMS ERROR "
+ sTemp[i]);
try {
Thread.sleep(500); // 尝试让线程休眠500毫秒,这样做可以降低CPU的使用率
} catch (Exception e) {
System.out
.println("-->[error]mtgateway,"
+ e.toString());
oLogger.warning(e.toString());
}
// wlz end
MTGateWay.portSendOK = false;
MTGateWay.canSendNext = true;
}
// 报告SIM卡失效(可能),假定非卡失效因素,允许发送下一条
if (sTemp[i].indexOf("^HCMGSF") >= 0) {
System.out.println("发送失败,错误号是--> "
+ sTemp[i]);
// wlz begin
// System.out.println("从新设置AT+CNMI=1,2,0,0,0");
// //CDMA设置方式
// serialPortOut.write("AT+CNMI=1,2,0,0,0\r\n".getBytes());
// serialPortOut.flush();
oLogger
.warning("-->[info]send cmd-sms got HCMGSF ERROR "
+ sTemp[i]);
try {
Thread.sleep(500); // 尝试让线程休眠500毫秒,这样做可以降低CPU的使用率
} catch (Exception e) {
System.out
.println("-->[error]mtgateway,"
+ e.toString());
oLogger.warning(e.toString());
}
// wlz end
MTGateWay.portSendOK = false;
MTGateWay.canSendNext = true;
}
// 发送成功后,可以发送下一条
/*
* wlz if (sTemp[i].indexOf("^HCMGS")>=0){ int
* pos = sTemp[i].indexOf("^HCMGS")+6; if
* (pos<sTemp[i].length()){ if
* (sTemp[i].charAt(pos)!='S'){
* //System.out.println("发送成功");
* MTGateWay.canSendNext = true;
* System.out.println("发送成功,MR=" + sTemp[i] );
* }else{ ; } } else{
* //System.out.println("发送成功");
* MTGateWay.canSendNext = true;
* System.out.println("发送成功,MR=" + sTemp[i] ); }
* }
*/
// ////
if (sTemp[i].indexOf("^HCMGSS") >= 0) {
{
// System.out.println("发送成功");
MTGateWay.canSendNext = true;
System.out.println("发送成功,MR="
+ sTemp[i]);
}
}
// wlz begin
if (sTemp[i].indexOf("CMTI") >= 0) {
{
// System.out.println("发送成功");
MTGateWay.canSendNext = true;
System.out.println("收到Class 2 SMS="
+ sTemp[i]);
}
}
if (sTemp[i].indexOf("^HCDS") >= 0) {
{
// System.out.println("发送成功");
MTGateWay.canSendNext = true;
System.out.println("短信回执=" + sTemp[i]);
}
}
// wlz end
// 完整数据已经取出,如果存在^HCMT则为不完整数据,写回Buffer
if (sTemp[i].indexOf("^HCMT:") == 0) {
byte[] bTmp = (sTemp[i] + "\r\n")
.getBytes(GSMModule.ENCODE);
for (int j = 0; j < bTmp.length; j++) {
readBuffer[j] = bTmp[j];
}
readLen = (sTemp[i] + "\r\n").length();
}
}
break;
} else {
return;
}
}
}
} catch (IOException e) {
oLogger.warning(e.toString());
}
SerStatus = isbusy;
break;
default:
SerStatus = isbusy;
break;
}
}
/**gift
* 在java程序中,为了实现同本地系统的硬件端口(RS-232标准串口/IEEE1284标准并口)通讯,目前有两个方法,第一个就是以前说过的,
* 使用JNI技术自己写一个与java程序相关的dll/so文件,是一个花费巨大且不实际的想法.第二个方法就是使用sun公司提供的comm包,
* 这套API是用于开发平台独立的通讯应用程序的扩展API
* 初始化comm驱动(可能不是必须的)
使用如下方式初始化comm的驱动(windows系统):
javax.comm.CommDriver commDriver = (javax.comm.CommDriver) Class.forName( "com.sun.comm.Win32Driver" ).newInstance();
commDriver.initialize();
*/
private final void initDriver() {
GSMModule.SerStatus = GSMModule.SERIALPORT_NOTREADY;
try {
String driverName = "com.sun.comm.Win32Driver";
// CommDriver driver = null;
System.loadLibrary("win32com");
CommDriver driver = (CommDriver) Class.forName(driverName)
.newInstance();
driver.initialize(); // 执行initialize()会把当前设备上的所有端口注册给CommPortIdentifier
} catch (Exception e) {
oLogger.warning(e.toString());
}
}
private boolean isEmptyOrSegment() {
if (readLen == 0)
return true;
String s = new String(readBuffer);
if (s.indexOf("^HCMT:") >= 0)
return true;
return false;
}
private void dealWithRealData(String realData) {
String[] sTmp = realData.split("\r\n");
String[] sTe = sTmp[0].replace("^HCMT: ", "").split(",");
String s = sTe[0];
s += "::" + sTmp[1]; // 完整数据:电话+内容,以两个冒号分割
if (nInitCompleted == 1) {
// 处理接收的短信数据
System.out
.println("-->[info]Serialport, forward sms to mogateway.["
+ s + "]");
MOGateWay mogateway = new MOGateWay(s);
mogateway.start();
} else {
// 抛弃数据不处理..
System.err
.println("-->[warnning]Serialport, initialization not completed and discard sms data:["
+ s + "]");
}
System.out.println("-->[info]Serialport, received sms. --> " + s);
}
}