- 浏览: 181558 次
- 性别:
- 来自: 北京
文章分类
最新评论
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 modem;
// 发送是否已成功完成
private boolean sendOKFlag;
private int errCount;
// 发送模式是否是PDU方式
private boolean isPduMode;
private String smContent;
private ArrayList<SubmitPack> sendBuffer;
// 要打开使用的串口
private SerialPort sPort;
static Logger logger = Logger.getLogger(ModemAdapter.class);
private ModemAdapter() {
DOMConfigurator.configure(MyFinal.LOG4J_CONF_FILE);
isPduMode = false;
errCount = 0;
logger.debug("Add a test data");
sendBuffer = new ArrayList<SubmitPack>();
SubmitPack msg = new SubmitPack();
ArrayList<String> destList = new ArrayList<String>();
destList.add("136××××××××");
msg.setSm("你好,张新波");
msg.setDestAddr(destList);
add(msg);
start();
}
public static ModemAdapter getInstance() {
if (modem == null)
modem = new ModemAdapter();
return modem;
}
// 得到计算机的串口
private SerialPort getSerialPort(String com) {
SerialPort sPort = null;
CommPortIdentifier portID;
String owner = new String("modemn");
int keeptime = 5000;
Enumeration portList;
portList = CommPortIdentifier.getPortIdentifiers();
String driverName = "com.sun.comm.Win32Driver";
CommDriver driver = null;
try {
System.loadLibrary("win32com");
logger.debug("Win32Com Library Loaded");
driver = (CommDriver) Class.forName(driverName).newInstance();
driver.initialize();
logger.debug("Win32Driver Initialized");
} catch (InstantiationException e1) {
logger.error("1:" + e1.getMessage());
e1.printStackTrace();
} catch (IllegalAccessException e1) {
logger.error("2:" + e1.getMessage());
e1.printStackTrace();
} catch (ClassNotFoundException e1) {
logger.error(e1.getMessage());
e1.printStackTrace();
}
// 如果有多个端口
while (portList.hasMoreElements()) {
portID = (CommPortIdentifier) portList.nextElement();
if (portID.getName().equals(com))
try {
sPort = (SerialPort) portID.open(owner, keeptime);
break;
}// 打开一个串口
catch (PortInUseException e) {
logger.fatal(e.getMessage());
System.exit(1);
}
}// while
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());
}
}
return sPort;
}
private boolean init() {
boolean result = false;
Config conf = new Config();
String comName = conf.comName();
sPort = getSerialPort(comName);
String msg = null;
if (sPort != null) {
listenSerialPort(sPort);
// 用配置参数初始化MODEM
msg = conf.initParam();
if (msg != null) {
if (conf.modemMode() != null && conf.modemMode().equals("0"))
isPduMode = true;
if (isPduMode)
msg = "at+cmgf=0;" + msg;
else
msg = "at+cmgf=1;" + msg;
sendMsg(msg, sPort);
sendOKFlag = true;
}
}
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(1000);
if (sendOKFlag) {
logger.debug("初始化MODEM成功!");
return true;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return result;
}
// 把短消息通过数据猫发送出去
private void sendMsg(String msg, SerialPort sPort) {
PrintWriter pw;
if (msg != null && sPort != null)
try {
pw = new PrintWriter(sPort.getOutputStream());
pw.println(msg);
pw.flush();
pw.close();
logger.debug("msg has been send from Modemn:");
logger.debug(msg);
} catch (IOException e) {
logger.error(e.getMessage());
e.printStackTrace();
}
}
// 把短消息通过数据猫发送出去
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();
}
}
private void listenSerialPort(SerialPort sPort) {
if (sPort != null)
try {
sPort.addEventListener(this);
sPort.notifyOnDataAvailable(true);
} catch (TooManyListenersException e) {
logger.error(e.getMessage());
e.printStackTrace();
}
}
public void run() {
int waitCount = 0;
String cmd1 = null;
SubmitPack msg;
String dest;
String content;
if (init()) {
while (true) {
try {
sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
msg = getOneMsg();
if (msg != null) {
ArrayList<String> destList = msg.getDestAddr();
for (int i = 0; destList != null && i < destList.size(); i++) {
dest = (String) destList.get(i);
content = msg.getSm();
if (content != null) {
while (true) {
if (sendOKFlag == true) {
if (isPduMode) {
Config conf = new Config();
PduPack pack = new PduPack();
pack.setAddr(dest);
pack.setMsgContent(content);
pack.setSmsc(conf.smsc());
String coded = pack.getCodedResult();
if (coded != null
&& coded.length() > 18)
cmd1 = "AT+CMGS="
+ (coded.length() - 18) / 2
+ "\r";
smContent = coded
+ (char) Integer.parseInt("1A",
16);
// cmd1+=smContent;
sendMsg(cmd1.getBytes(), sPort);
cmd1 = null;
} else
cmd1 = "AT+CMGS=\"+86"
+ dest
+ "\"\r"
+ content
+ (char) Integer.parseInt("1a",
16) + "z";
if (cmd1 != null) {
logger.debug("Cmd:" + cmd1);
sendMsg(cmd1, sPort);
sendOKFlag = false;
logger.debug("isSendOK=false");
}
break;
} else
try {
sleep(100);
if (waitCount > 300) {
sendOKFlag = true;
waitCount = 0;
} else
waitCount++;
} catch (InterruptedException e) {
}
}
}
}
}
}// while
} else {
logger.fatal("无法成功初始化MODEM,请检查设备");
System.exit(0);
}
}
// 处理侦听到的串口事件
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();
}
}
}
/**
* 判断接收到的数据是否最后是以"OK"结束的
*
* @param data
* @return
*/
private boolean isRecOK(String data) {
final String OK_FLAG = "OK";
int index1 = 0;
if (data != null) {
index1 = data.indexOf(OK_FLAG);
if (index1 >= 0 && index1 + 4 <= data.length()) {
String t = data.substring(index1 + 2);
byte[] b = t.getBytes();
if (b.length >= 2) {
if (b[0] == 0x0D && b[1] == 0x0A)
return true;
}
}
}
return false;
}
/**
* 发送短消息是否成功.
* <p>
* 判断依据: 收到回应的消息中有+CMGS:<space><number>,紧接着是两个换行回车(0x0D,0x0A,0x0D,0x0A),
* 然后是OK,最后是一个回车换行(0x0D,0x0A)
*
* @param data
* @return
*/
private boolean isSendOK(String data) {
final String FLAG = "+CMGS:";
int index = -1;
int index2 = -1;
if (data != null) {
index = data.indexOf(FLAG);
if (index > 0) {
index += 6;
if (index < data.length()) {
String temp = data.substring(index);
index = 0;
byte[] b = temp.getBytes();
for (int i = 0; i < b.length; i++) {
if (b[i] == 0x0D) {
index2 = i;
break;
}
}
if (index2 < temp.length() && index2 > index + 1) {
String t1 = temp.substring(index + 1, index2);
try {
int seqid = Integer.parseInt(t1);
logger.debug("seqID:" + seqid);
if (index2 + 8 == temp.length()) {
// 两个回车换行符
if (b[index2] == 0x0D && b[++index2] == 0x0A
&& b[++index2] == 0x0D
&& b[++index2] == 0x0A) {
if (b[++index2] == 0x4F
&& b[++index2] == 0x4B) {// OK
if (b[++index2] == 0x0D
&& b[++index2] == 0x0A) {// 一个回车换行
return true;
}
}
}
}
} catch (NumberFormatException e) {
e.printStackTrace();
return false;
}
}
}
}
}
return false;
}
/**
* 判断接收到的字符串最后是否是以"ERROR"结束的
*
* @param data
* @return
*/
private boolean isRecError(String data) {
final String FLAG = "ERROR";
int index1 = 0;
if (data != null) {
index1 = data.indexOf(FLAG);
if (index1 >= 0 && index1 + 7 <= data.length()) {
String t = data.substring(index1 + 5);
byte[] b = t.getBytes();
if (b.length >= 2) {
if (b[0] == 0x0D && b[1] == 0x0A)
return true;
}
}
}
return false;
}
/**
* 是否接收到手机发来的完整数据,上传的数据是以"+CMT:"开头
*
* @param data
* @return
*/
private boolean isRecData(String data) {
final String BEGIN_FLAG = "+CMT:";
int index0 = -1;
int index1 = -1;
int index2 = -1;
if (data != null) {
index0 = data.indexOf(BEGIN_FLAG);
if (index0 >= 0 && index0 < data.length()) {
// data=data.substring(index0);
// index1 = data.indexOf("\r\n");
// if (index1 > index0 && index1 + 2 < data.length()) {
// String str=data.substring(index1+2);
// index2=str.indexOf("\r\n");
// if(index2>0 && index2<str.length()){
//
// return true;
// }
// }
return true;
}
}
return false;
}
private boolean handleRecData(StringBuffer sb) {
String data = null;
if (sb != null) {
data = sb.toString();
if (isRecOK(data)) {
sendOKFlag = true;
return true;
} else if (isRecError(data)) {
errCount++;
if (errCount > 3) {
sendOKFlag = true;
errCount = 0;
}
return true;
} else if (sb.indexOf(">") != -1 && smContent != null) {
sendMsg(smContent.getBytes(), sPort);
smContent = null;
}
else {
int index0 = data.lastIndexOf("+CMT:");
if (index0 >= 0 && index0 < data.length()) {
data = data.substring(index0);
int index1 = data.indexOf("\r\n");
if (index1 != -1 && index1 + 2 < data.length()) {
data = data.substring(index1 + 2);
int index2 = data.indexOf("\r\n");
if (index2 > 1 && index2 < data.length()) {
data = data.substring(0, index2);
if (data != null && data.length() > 0) {
PduPack pack = new PduPack(data);
String srcAddr = pack.getAddr();
String content = pack.getMsgContent();
String destAddr = "012345";
if (srcAddr != null && content != null) {
logger.debug("srcAddr:"+srcAddr);
logger.debug("content:"+content);
Config conf = new Config();
destAddr = conf.cmppSSN();
DeliverPack deliver = new DeliverPack(
srcAddr, destAddr, content);
ServerAdapter server = ServerAdapter
.getInstance();
server.addDeliverPack(deliver);
return true;
}
}
}
}
}
}
}
return false;
}
private SubmitPack getOneMsg() {
SubmitPack result = null;
if (sendBuffer != null && sendBuffer.size() > 0)
result = (SubmitPack) sendBuffer.remove(0);
return result;
}
public void add(SubmitPack msg) {
sendBuffer.add(msg);
}
}
9.结束语
在如下环境调试通过:
Eclipse3.1,Jdk1.5,西门子 Tc35i Modem
发表评论
-
人民币转换数字
2012-11-07 15:14 1115该贴原因: ... -
个人收集的java精品网站
2012-05-30 08:19 0java进阶网 http://www.javady.com ... -
JVM(java 虚拟机)内存设置
2011-06-02 16:37 15177JVM(java 虚拟机)内存 ... -
汉字全半角转化程序
2011-02-25 08:52 1473转载一个牛人的。方便以后查看使用: 也许. 这个代码对很多人 ... -
md5JAVA实现
2010-06-07 22:43 1200MD5算法研究 MD5的 ... -
在Java中操作串口实现短信收发1
2010-06-07 22:06 1602在Java中操作串口实现短信收发 采用串口操作进行短信收发 ... -
JVM内存参数调优
2010-06-07 22:03 1951JVM内存参数调优 我们前面所提到的堆内存(heap)是由 ... -
多线程程序设计的要点
2010-06-07 22:00 854多线程中有主内存和工 ... -
Java 处理事务精要
2010-06-07 21:58 989简单事务的概念 我 ... -
如何开公司及手续过程
2010-06-07 21:55 1213注册一个公司,首先想好经营什么,怎样经营好,再来注册。要不,注 ... -
运用加密技术保护Java源代码
2010-06-07 21:52 942Java程序的源代码很容易被别人偷看,只要有一个反编译器,任何 ... -
连接池的基本工作原理
2010-06-07 21:39 841连接池的基本工作原理 1、基本概念及原理 由上面的分析可以 ... -
高效的Java音乐播放类
2010-06-07 21:34 1529/** *//** * 自动播放,循环停止后结束。 ... -
高效的Java音乐播放类 2
2010-06-07 21:32 1191/** *//** * 直接播放url文件 * ... -
高效的Java音乐播放类
2010-06-07 21:26 1372Java音频播放,因为必须依赖到本地环境,所以JAVA在音频处 ... -
用开源的 InnoSetup 为 Java 应用制作 Windows 安装程序
2010-04-24 11:30 1679在这个例子里, 我将给大家展示如何使用 InnoSetup 自 ... -
Swing: 用 GlassPane 显示一个透明的正在操作框
2010-04-24 10:25 2029这个组件可以让用户看到界面里的显示但是无法操作. 需要的图: ... -
文本放大器
2010-04-24 10:06 1270/** * @(#)Text2Image.java 1.0 D ... -
在自定义 JToolTip 里面显示组件
2010-04-24 10:03 2316在自定义 JToolTip 里面显示组件 我们经常可以看 ... -
JIDE的开源Swing组件
2010-04-24 09:57 9591虽然它们早就开源了(去年吧),我也是今天才看到,虽然目前也用不 ...
相关推荐
在本案例中,Java程序通过串口与GSM modem或其他支持短信功能的硬件设备连接,实现短信的收发。 4. **GSM Modem**:GSM modem是一种能够接入GSM网络的设备,它可以连接到计算机的串口,通过AT命令集控制,实现短信...
Java 实现通过串口与 GSM 猫相连发送短信是一个常见的通信应用场景,主要涉及 Java 的串口编程技术以及 SMS(Short Message Service)协议的理解。在本文中,我们将深入探讨这个主题,了解如何利用 Java 来操作串行...
在"短信猫收发例子"中,这个OCX控件可能封装了与短信猫进行通信的函数和方法,包括初始化串口、发送短信、接收短信、查询状态等功能。开发者可以通过调用这些控件的方法,实现对短信猫的操作。 文件名为"smsdemo_pb...
总结起来,通过Java实现基于短信猫的短信收发,需要深入理解PDU编码机制,掌握串口通信技术,以及对短信猫硬件特性的了解。通过上述的各个Java类,我们可以构建一个完整的短信收发系统,实现高效、可靠的短信服务。
在实现短信发送功能后,需要编写测试用例来验证其正确性。这可能包括发送短信到一个已知的手机号码,检查是否能成功发送,以及是否能接收到正确的返回信息。同时,考虑到可能存在的网络延迟和短信中心的处理时间,...
Java短信猫收发短信的例子是基于Java编程语言实现的一个实用工具,主要用于与短信猫设备进行交互,实现短信的发送和接收功能。短信猫是一种硬件设备,通常通过USB或串口连接到计算机,使得电脑能够通过GSM网络发送和...
在“SMS.rar”这个压缩包中,可能包含了示例代码或详细教程,帮助开发者理解如何使用Java和AT命令进行串口短信收发的具体步骤。学习这些内容有助于开发相关应用,例如远程监控系统、自动报警系统或物联网设备的通信...
6. **错误处理和调试**:在实现过程中,可能遇到如超时、数据错乱、短信发送失败等问题,需要编写适当的错误处理代码,并利用串口终端软件进行调试,查看通信过程中的原始数据。 7. **安全性与隐私**:由于短信可能...
综上所述,Java短信猫多串口收短信涉及到Java串口通信、smslib库的使用、多线程编程以及错误处理等多个知识点。通过理解和实践这些技术,可以构建出稳定可靠的短信服务系统。在开发过程中,不断学习和优化,可以有效...
在IT行业中,尤其是在通信与自动化领域,通过编程语言如Java来控制硬件设备是常见的需求。本教程将聚焦于如何利用Java...在实际开发中,确保对硬件设备的理解和Java串口编程的熟练掌握,将有助于提升你的解决方案质量。
java读取串口通过AT指令发送短信 操作短信猫进行收发短信
在实现短信息收发时,需要了解CDMA MODEM的短信息数据协议格式,包括短信息的发送、接收、删除、存储等操作。同时,需要使用AT指令来控制CDMA MODEM的各种通信功能,例如呼叫、接听、短信息接收和发送等。 在搭建...
总结起来,使用SMSLib在Java项目中实现短信收发功能,需要理解Java串口通信的基本原理,正确配置相关库,然后通过SMSLib提供的API调用来实现短信的发送和接收。这为开发者提供了一种高效且无需深入了解底层细节的...
使用java SMslib实现了短信猫收发短信。串口开发,串口配置工具,配合了完整的测试用例,可以使用到项目中。
KEIL中如何用虚拟串口调试串口程序.doc Message PDU编码规则.doc QHDQ-29DDDAD3A0.LOG SMSLib串口通信.doc 串口常用参数.doc 关于java使用javacomm20.doc 常见的进制转换方法.doc 浅谈Java串行端口技术协议.doc 短信...
由于前段时间做的系统需要使用短信猫收发短信,所以研究了一下在Java下使用短信猫,网上很多资料都是使用的smslib的jar包来发送短信,但是这种方式只支持32的jdk,而我的系统使用的是linux的64位环境,所以最后采用...
综上所述,Java短信收发涉及到API集成、硬件设备交互、协议理解、安全性、性能优化等多个方面,是一个综合性的技术实践。通过学习和实践这些知识点,开发者可以构建出稳定且高效的短信服务系统。
本示例将详细介绍如何使用RXTX库在Java中实现通过AT指令控制短信猫进行收发短信的功能。 首先,你需要安装RXTX库。提供的压缩包文件`rxtx-2.1-7-bins-r2.zip`和`rxtx-2.2pre2-bins.zip`包含了RXTX的不同版本。解压...
综上所述,Java短信收发文档提供了一个基于smslib库的解决方案,用于通过短信猫在Java应用程序中实现短信服务。这涉及到硬件驱动的安装、配置文件的管理、Java代码的编写以及库的使用等多个方面,是Java与硬件设备...