在Java中操作串口实现短信收发

采用串口操作进行短信收发,是比较常见的一种方式.比如,很多群发软件,用的就是这种方法.

1.配置comm.jar.

Comm.jar是Sub实现底层串口操作的API,调用了本地的DLL文件,因为Java本身不具备直接访问硬件设置的能力,都是通过调用本地方法来实现的.可以Java的官方网站下载.下载之后把其中Comm.jar包导入到工程的Classpath中,把另外两个非常重要的文件javax.comm.properties和win32com.dll考贝到你的工程目录下,即java.user下.

2.打开串口.

在打开串口前首先要加载Win32com.dll,因为我们没有把它放到JRE路径下,所以必须要自己显式的加载.

 

  String driverName  =   " com.sun.comm.Win32Driver " ;
  CommDriver driver 
=   null ;

  
try   {
   System.loadLibrary(
"win32com");
    driver 
= (CommDriver) Class.forName(driverName).newInstance();
   driver.initialize();
  }
  catch  (InstantiationException e1)  {
   logger.error(
"1:" + e1.getMessage());
 
  }
  catch  (IllegalAccessException e1)  {
   logger.error(
"2:" + e1.getMessage());
 
  }
  catch  (ClassNotFoundException e1)  {
   logger.error(e1.getMessage()); 
  }

 

然后获取你指定的端口:

 

成功打开端口之后,设置端口的相关参数,如波特率、数据位、奇偶校验位等.这个跟具体的设备有关,不过一般情况下波特率为9600,数据位为8,停止位为1,奇偶为0,流量控制为Off:

 

if  (sPort  !=   null {
   logger.debug(
"serial name is :" + sPort.getName());
   
try {
    
// 设置串口的参数
    sPort.setSerialPortParams(9600,// 波特率
      SerialPort.DATABITS_8,// 数据位数
      SerialPort.STOPBITS_1, // 停止位
      SerialPort.PARITY_NONE);// 奇偶位
   }
 catch (UnsupportedCommOperationException e) {
    e.printStackTrace();
    logger.error(e.getMessage());
   }

  }

 

3.对端口进行初始化

 对进行数据接收或发送之前,还要先进行一些参数的设置。重要的有:

AT+cmgf=0(设置Modem收发采用Pdu方式,1为Text方式。有些Modem可能正好相反,具体参考Modem的At指令说明)

At+cnmi=2,2,0,0,0(设置Modem自动接收,AT指令说明书给的定义是新的短消息指示说明,就是说说有了新的短消息,怎么给你提示。这个设置是有消息将自动显示,无需进行读卡操作。看到有很网上的例子都是1,1,这样还要通过读卡操作才能得到短消息,十分不方便,还降低了SIM卡的使用寿命)

At+csmp=17,167,0,240(设置短消息文本模式参数。其中17是指SMS-SUBMIT的十进制整数表达形式,即提交;167指是有效期的整数表达形式;0指的是协议标识的十进制整数表示形式。前三个参数都该命令的默认值。最后一240指是编码方案,在Text方式下发送英文和Pdu模式下一般设置成240.如果要在Text模式下发送中文,有多Modem要设成8)

对端口所作的上述初始化工作,可以在超终终端里直接设置。但最好是把它写在程序里,在程序启动之后就进行此工作,避免手工操作的麻烦。

对Modem进行初始化,就必须把上述命令输出到Modem的端口上,还要看它的反回值是不是OK。要想得到返回值,就要对COM端口进行侦听了。所以初始化的工作有三步:

第一,侦听端口
   

 sPort.addEventListener( this );
    sPort.notifyOnDataAvailable(
true );

第二,建立输入输出流,把初始化命令输出到Modem的COM端口

 

//  用配置参数初始化MODEM
   msg  =  conf.initParam();
   
if  (msg  !=   null {
    
if (conf.modemMode() != null && conf.modemMode().equals("0"))
      
if (isPduMode)
        msg 
= "at+cmgf=0;" + msg;
    
else
       msg 
= "at+cmgf=1;" + msg;
       sendMsg(msg.getBytes(), sPort);
       sendOKFlag 
= true;
   }



//  把短消息通过数据猫发送出去
  private   void  sendMsg( byte [] msg, SerialPort sPort)  {

  DataOutputStream pw;
  
if (msg != null && sPort != null)
   
try {

    pw 
= new DataOutputStream(sPort.getOutputStream());
    pw.write(msg);

    pw.flush();
    pw.close();
    logger.debug(
"msg has been send from Modemn:");

   }
 catch (IOException e) {
    logger.error(e.getMessage());
    e.printStackTrace();
   }

 }


//  处理侦听到的串口事件
  public   synchronized   void  serialEvent(SerialPortEvent ev)  {

  DataInputStream in;
  
int c = 0;
  StringBuffer sb 
= null;
  
// 如果有串口事件发生
  if (ev.getEventType() == SerialPortEvent.DATA_AVAILABLE) {

   
try {
    in 
= new DataInputStream(sPort.getInputStream());
    sb 
= new StringBuffer();
    
while ((c = in.read()) != -1{
     sb.append((
char) c);

     System.out.println(sb);
     
if (handleRecData(sb)) {
      logger.debug(
"从Modem接收到的数据" + sb);
      sb 
= new StringBuffer();

     }


    }


   }
// try
   catch (IOException e) {
    logger.error(e.getMessage());
    e.printStackTrace();
   }

  }

 }

 

serialEvent事件就是刚才添加侦听之后要工作的部分。如果写过界面程序的人,对这个会比较熟悉。一但Modem回复数据,此事件就会触发。我们在发送完初始化命令之后,就从此事件中接收数据,看能不能收到OK。如果收到,就初始化成功。

4.发送数据

成功进行初始化之后,就可以进行正常的数据收发了。我们在此使用PDU的方式做说明,Text方式一是很多Modem或手机都不支持,二是也比较简单,在最后再提。

首先我们可以把要发送的数据放到发送缓冲列表中,对数据一条一条的发送。因为Modem不支持异步(我自己的经验),我们只能发完一条之后,再发第二条。发送的原理同发送初始化命令一样,但是要注意的一点是发送内容首先要进行PDU编码,发送的格式为:

AT+CMGS=<Length><CR>PDU DATA<CTRL-z>

其中Length为经过编码之后的PDU data的长度减去18再除以2得到,至于为什么这样算,可以参考AT命令手册。有些Modem支持直接把上面的做为一个完整的数据包发送过去(比如:FALCOM系列的),有的就非常的笨(比如:西门子 Tc35i),它要求必须先发前面的At命令,等接收到回应“>”符号之后,再发送PDU DATA,十分麻烦,一点去不为咱们开发人员着想:(,我就是在这吃的亏。按以前的习惯做,结果怎么都发不出去。

步骤是这样的:

首先取出经过PDU编码过的数据,计算它的长度,生成At+cmgs=<length><cr>

然后发送出去

接着侦听COM端口,等待接收">"字符

接收“>”之后,接着发送剩余的部分

然后再侦听,接收回应,看是否发送成功。如果发送成功的话,一般会接到这样的数据:

数据本身:PDU DATA<CTRL-z>

发送序号:+CMGS:22

成功标志:OK

有时候也能接收OK,但是收不到+CMGS:22这样的东西,还是没有发送成功,这两个都必须有,才真正发送成功。

5.接收数据

接收数据其实也是在serialEvent里面处理。如果象上面的设置那样,设成自动接收,那么一但有短消息来了之后,自动触发事件,完整的数据格式大概是这样的:

+CMT:<data><time><index>

PDU Data

"/n/r"

最后是以回车换行结束

我们收到完整的数据之后,把PDU data取出来,再按PDU编码进行解码就行。

6.调试

首先最好能用超级终端,因为它使用起来很方便,直接输命令,直接看结果。

还有一些非常好的串口监测调试软件,能直接显示出来你向串口都发了什么数据,从串口接收到了什么数据,发送接收的对错,一看就清楚了。我在调TC35i的时候就折腾了好几天,就是不知道是什么原因,最后有网友建议我用串口监测软件,结果我没有半个小时就把问题搞定了,不是它,我都要哭了。强烈推荐一款是AcessPort,中文,免费,非常好用。

7.关于Text方式

格式如下:

AT+CMGS="+8613912345678"<CR>Text content<ctrl-z>

如果是英文数字的话,直接发送就行了,接收到的也是Ascii码,无需编码

如果是中文的话,要先进行Unicode编码,接收也一样,收到之后要进行Unicode转gb的转换

另外先把配置设置好

8.参考源代码:

package  com.gftech.dcs.commu;

import  java.io.BufferedReader;
import  java.io.DataInputStream;
import  java.io.DataOutputStream;
import  java.io.IOException;
import  java.io.InputStreamReader;
import  java.io.PrintWriter;
import  java.util.ArrayList;
import  java.util.Enumeration;
import  java.util.TooManyListenersException;

import  javax.comm.CommDriver;
import  javax.comm.CommPortIdentifier;
import  javax.comm.PortInUseException;
import  javax.comm.SerialPort;
import  javax.comm.SerialPortEvent;
import  javax.comm.SerialPortEventListener;
import  javax.comm.UnsupportedCommOperationException;

import  org.apache.log4j.Logger;
import  org.apache.log4j.xml.DOMConfigurator;

import  com.gftech.common.PduPack;
import  com.gftech.smp.DeliverPack;
import  com.gftech.smp.SubmitPack;

/**
 * 
@author sinboy
 * 
 * 无线MODEM适配器。 用来从MODEM发送短消息,以及从MODEM接收短消息
 
*/

public   class  ModemAdapter  extends  Thread  implements  SerialPortEventListener  {
 
private static ModemAdapter
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 18
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值