树莓派.GPRS.短信接收器
起因
曾经用过西门子出的短信猫, 好处是直接有sdk开发包, 不会硬件开发也能直接使用
缺点也是明显的, 就是只支持windows系统, 另外就是在windows下工作很不稳定, 隔开几天就会出现收不到短信的毛病, 要断电重启设备才有机会恢复(还不是必然恢复)
后来在地府(dfrobot)发现了新品"gravity: uart a6 gsm & gprs 无线通信模块",买来试了一下发现可用(不过不清楚地府的a6和外面常见的sim800系列、sim900系列有什么不同), 而且可以自己写驱动支持linux下运行,完美
期间也碰到一些小坑, 记录一下。
需求清单
- 自动初始化gprs模块
- 接收短信并能解析出重要元素(包括:来电号码/时间/短信内容)
- 把解析到的短信内容上传到服务器保存
- 清除已阅短信
- 支持linux系统
- 开发语言:java
硬件清单
- 树莓派2代b型(3代串口使用上有区别,需要另外的方法处理)
- gravity: uart a6 gsm & gprs 无线通信模块
- usb无线网卡(可选)
- usb电源适配器2个(重要,为什么要2个后面会说明)
- 16gb tf卡一张
- 可以接收短信的手机卡1张(必须是移动或联通的卡, 电信的不支持)
接线方法
(树莓派40pin引脚图)
(a6引脚说明)
树莓派 a6
--------------------------------------
gpio15 rx
gpio16 tx
gnd gnd
重要: a6模块的电源需要单独供电!!!
a6模块不能直接从树莓派上的gpio 5v针脚接电,因为电流不足!
最开始的时候, 我是从树莓派上取电供给a6, 结果串口怎么都无法通信,刚开始还以为是波特率的问题,结果折腾了半天后, 留意到a6上有个蓝灯(上面写着sleep)有明暗变化, 不稳定,感觉像是电压不稳定一样, 果断试了一下把a6外接电源,然后a6才正常工作! 可以从蓝灯看得出来,亮度较高,且稳定(不闪烁)
资料准备
- 树莓派系统(用noobs或raspbian都可以)
- pi4j (java支持包)
- at指令知识
树莓派系统安装方法可以自行搜索,或看我之前发过的文章
系统装好后还涉及到如何把gpio15(tx)和gpio16(rx)启用的问题, 见这篇文章:《两个树莓派通过串口通信》
pi4j是个能让java访问树莓派40个gpio的支持包, 可以上官网下载安装,传送门>>>
最重要和容易掉坑的是关于接收短信的at指令部分,下面要详细讲解
这里需要做的功能是利用a6接收短信,涉及到以下指令
* 第一步:初始化gprs.模块
* at 握手 / sim卡检测等
* at+cpin? 查询是否检测到sim卡
* at+csq 信号质量测试,值为0-31,31表示最好
* at+ccid 读取sim的ccid(sim卡背面20位数字),可以检测是否有sim卡或者是否接触良好
* at+creg? 检测是否注册网络
------以上指令用于初始化模块,一般接线没问题,波特率设置没问题的话都是比较容易调通
* 第二步:初始化gprs.设置短信模式及短信接收参数
* at+cmgf=1 0-pdu, 1-文本格式
* at+csdh=1
* at+cpms="sm","sm","sm" 将信息保存在sim卡中, sm-表示存在sim卡上
* at+cnmi=2,1,0,1,1 收接通知,并存在指定位置(与at+cpms设置有关)
极易掉坑系列,逐个讲解:
设置短信格式指令:at+cmgf=1
分2种短信格式: 0-pdu, 1-文本格式
如果设置的是pdu模式, 那么你收到的短信就是这样 的:
+ciev: "message",1
+cmt: ,32
0891683110200005f0040ba18126601728f00000710102610272230e74747a0e4acf416110bd3ca703
如何读懂pdu要另外翻阅专业文章, 这里如果你不使用发短信功能的话,建议不要采用pdu格式
pdu格式的好处是可以发中文短信!
好, 如果设置是文本格式,收到的短信就类似下面这样的:
+ciev: "message",1
+cmt: "test again ,中文也试试
直接就能看到短信内容,中文也一样可以显示出来(注意它可以gb2312或gbk编码)
然后就有问题产生了, 新短信来时是上面这样的格式, 短信内容是可以获取了, 但特么为什么看不出是谁(手机号)发来的呢?下面就是入坑的时候:
看不到手机号怎么办, 你可以试试这个指令:
at+cmgl="all"
它能读出存在sim卡上的短信(包括已读和未读,以及外发时存着的短信),执行后收到的内容大概是这个样子:
+cmgl: 2,"rec read","106907931100",,"2017/06/02,10:15:21+08",160,134
【小米】[小米移动]您2017年5月共消费0.75元,当前余额99.05元。其中:数据流量费0.05元;语音通信费0.7元;短/彩信费+cmgl: 3,"rec read","106907931100",,"2017/07/02,10:15:19+08",160,54
。查询账单 。+cmgl: 4,"rec read","106907931100",,"2017/07/02,10:15:19+08",160,134
【小米】[小米移动]您2017年6月共消费1.32元,当前余额97.88元。其中:数据流量费1.32元;语音通信费0元;短/彩信费0元+cmgl: 5,"rec read","106908761100",,"2017/08/02,10:15:30+08",160,54
。查询账单 。+cmgl: 6,"rec read","106908761100",,"2017/08/02,10:15:30+08",160,134
【小米】[小米移动]您2017年7月共消费0.81元,当前余额97.01元。其中:数据流量费0.81元;语音通信费0元;短/彩信费0元at+cmgd=2
好! 很明显你要的信息都有了, 来电号码/时间/短信内容, 似乎可以用了喔!
但是这时你会发现刚收到的信息不一定在这个清单里! 这是怎么回事呢? 我反正查阅了很多资料,费了大量的时间也不知怎么回事
后来才发现这个指令(查看sim卡内存情况):
at+cpms?
执行后你可能会看到这个结果:
+cpms: "mt",0,50,"sm",1,50,"me",0,50
ok
重点关注"sm"后面第1个数字"1"代表当前存了多少条短信, 第2个数字"50"代表存储上限
"sm"表示sim卡, 其它2个一个代表手机设备, 另一个是手机内存
然后你给a6发个新短信, 有可能发现这个"1"不会增加! 为什么收到的新短信不存到sim卡上呢?
然后就找到这个指令
at+cnmi=<mode>,<mt>,<bm>,<ds>,<bfr>
这个指令比较复杂, 它负责设置收到新短信后的处理机制, 下面是参数含义
<mode>控制通知te的方式.
0 - 先将通知缓存起来,再按照<mt>的值进行发送.
1 - 在数据线空闲的情况下,通知te,否则,不通知te.
2 - 数据线空闲时,直接通知te;否则先将通知缓存起来,待数据线空闲时再行发送.
3 - 直接通知te.在数据线被占用的情况下,通知te的消息将混合在数据中一起传输.
<mt>设置短消息存储和通知te的内容.
0 - 接受的短消息存储到默认的内存位置(包括class 3),不通知te.
1 - 接收的短消息储存到默认的内存位置,并且向te发出通知(包括class 3).通知的形式为:+cmti:"sm",<index>
2 - 对于class 2短消息,储存到sim卡,并且向te发出通知;对于其他class,直接将短消息转发到te:+cmt:[<alpha>],<length><cr><lf><pdu>(pdu模式)
或者+cmt:<oa>,[<alpha>,]<scts>[,<tooa>,<fo>,<pid>,<dcs>,<sca>,<tosca>,<length>]<cr><lf><data>(text模式)
3 - 对于class 3短消息,直接转发到te,同<mt>=2;对于其他class,同<mt>=1.
<bm>设置小区广播
0 - 小区广播不通知
2 - 新的小区广播通知,返回+cbm:;length;;cr;;lf;;pdu;
3 - class3格式的小区广播通知,使用bm=2格式
<ds>状态报告
0 - 状态报告不通知
1 - 新的状态报告通知,返回:+cds:;length;;cr;;lf;;pdu;
2 - 如果新的状态报告存储到me,则返回:+cdsi:;mem;,;index;
相信看完你已经蒙圈, 我就是, 如果你看得懂, 那恭喜了!
我在这里采用的参数是
at+cnmi=2,1,0,1,1 收接通知,并存在指定位置
这时再测试一下发条新短信给a6
+ciev: "message",1
+cmti: "sm",0
现在不显示短信内容了(反正显示也没用, 因为没来电号码), 但"sm"后面仍然是0!
这时再用at+cmgl="all" 你会发现短信依然没存到卡上, 结果当然也没法看到短信内容及来电号码等信息啦
这是怎么回事裂
后来发现这个at+cnmi跟刚才说的指令(at+cpms)息息相关,再来查一下:
at+cpms?
+cpms: "mt",0,50,"sm",1,50,"me",0,50
ok
注意看, 如果你看到的和上面差不多, 会发现有"mt"和"me"存在, 这时收到短信虽然在cnmi告诉a6收到短信要存下来啊! 但是a6找不到"mt"和"me",结果存储失败!
我们现在是希望它收到短信后能存在sim卡上, 所以要设置一下:
at+cpms="sm","sm","sm"
再发条短信试试效果:
+ciev: "message",1
+cmti: "sm",1
现在看到"sm"后面是1了! 后面这个1表示的是短信存储的sim卡内存的位置
然后可以用指令查看短信内容了, 这里有2种方法
方法1,单条读取(at+cmgr=index)
at+cmgr=1
+cmgr: "rec unread","18620671820",,"2017/10/26,11:37:03+08",161,17,0,0,"+8613010200500",145,25
test again ,中文也试试
方法2,全部读取(at+cmgl="all")
+cmgl: 2,"rec read","106907931100",,"2017/06/02,10:15:21+08",160,134
【小米】[小米移动]您2017年5月共消费0.75元,当前余额99.05元。其中:数据流量费0.05元;语音通信费0.7元;短/彩信费+cmgl: 3,"rec read","106907931100",,"2017/07/02,10:15:19+08",160,54
。查询账单 。+cmgl: 4,"rec read","106907931100",,"2017/07/02,10:15:19+08",160,134
【小米】[小米移动]您2017年6月共消费1.32元,当前余额97.88元。其中:数据流量费1.32元;语音通信费0元;短/彩信费0元+cmgl: 5,"rec read","106908761100",,"2017/08/02,10:15:30+08",160,54
。查询账单 。+cmgl: 6,"rec read","106908761100",,"2017/08/02,10:15:30+08",160,134
【小米】[小米移动]您2017年7月共消费0.81元,当前余额97.01元。其中:数据流量费0.81元;语音通信费0元;短/彩信费0元at+cmgd=2
小结一下正确获取短信的姿势(流程):
at+cmgf=1
at+csdh=1
at+cpms="sm","sm","sm"
at+cnmi=2,1,0,1,1
ps: 其中有一条指令没解释:at+csdh=1
这个留给大家查资料
好, 接下来只需要写出java代码分析短信内容即可.
程序部分
import java.io.ioexception; import java.util.date; import com.common.datetimeutil; import com.common.stringutil; import com.pi4j.io.serial.baud; import com.pi4j.io.serial.databits; import com.pi4j.io.serial.flowcontrol; import com.pi4j.io.serial.parity; import com.pi4j.io.serial.serial; import com.pi4j.io.serial.serialconfig; import com.pi4j.io.serial.serialfactory; import com.pi4j.io.serial.serialport; import com.pi4j.io.serial.stopbits; import com.pi4j.util.commandargumentparser; import com.pi4j.util.console; /** * this example code demonstrates how to perform serial communications using the raspberry pi. * * @author robert savage */ public class seriallistensms { /** * this example program supports the following optional command arguments/options: * "--device (device-path)" [default: /dev/ttyama0] * "--baud (baud-rate)" [default: 38400] * "--data-bits (5|6|7|8)" [default: 8] * "--parity (none|odd|even)" [default: none] * "--stop-bits (1|2)" [default: 1] * "--flow-control (none|hardware|software)" [default: none] * * @param args * @throws interruptedexception * @throws ioexception */ public static void main(string args[]) throws interruptedexception, ioexception { // !! attention !! // by default, the serial port is configured as a console port // for interacting with the linux os shell. if you want to use // the serial port in a software program, you must disable the // os from using this port. // // please see this blog article for instructions on how to disable // the os console for this port: // https://www.cube-controls.com/2015/11/02/disable-serial-port-terminal-output-on-raspbian/ // create pi4j console wrapper/helper // (this is a utility class to abstract some of the boilerplate code) final console console = new console(); // print program title/header console.title("<-- the pi4j project -->", "监听串口(gpio15-tx / gpio16-rx)数据并写入memcached中"); // allow for user to exit program using ctrl-c console.promptforexit(); // create an instance of the serial communications class final serial serial = serialfactory.createinstance(); byte [] data = new byte[1024]; //数据缓冲区 try { // create serial config object serialconfig config = new serialconfig(); system.out.println(">>>"+serialport.getdefaultport()); config.device(serialport.getdefaultport()) // "/dev/ttyacm0" .baud(baud._115200) .databits(databits._8) .parity(parity.none) .stopbits(stopbits._1) .flowcontrol(flowcontrol.none); // parse optional command argument options to override the default serial settings. if(args.length > 0){ config = commandargumentparser.getserialconfig(config, args); } // display connection details console.box(" connecting to: " + config.tostring(), " data received on serial port will be displayed below."); // open the default serial device/port with the configuration settings serial.open(config); serial.flush(); system.out.println("serial.isopen():"+serial.isopen()); /**初始化gprs模块**/ boolean isinit = initgprs(serial); long trydelay = 2000; while(!isinit){ system.out.println("初始化gprs模块不成功, 请检查模块工作状态灯, 以及sim卡是否接触良好..."+trydelay); thread.sleep(trydelay+=1000); isinit = initgprs(serial); if(trydelay>(10*1000)){return;} //检测10次都不成功时, 退出程序 } /**初始化短信参数**/ isinit = initgprs_sms(serial); trydelay = 2000; while(!isinit){ system.out.println("初始化短信参数不成功, 请检查模块工作状态灯, 以及sim卡是否接触良好."); thread.sleep(trydelay+=1000); isinit = initgprs_sms(serial); if(trydelay>(10*1000)){return;} //检测10次都不成功时, 退出程序 } //每次开机时尝试读取一次存储卡中的短信 string res = new string(sendcmd(serial, "at+cmgl=\"all\""), "gbk"); system.out.println("at+cmgl=\"rec read\".res:"+res); if(res.indexof("ok")==-1){ system.out.println("设置失败!"); } //下面进入主程序 system.out.println("进入短信监听程序:"); long old_msg_delay = 60000; //设置旧短信搜索间隔时间(毫秒),在sim卡内存中搜索数据 long old_msg_count = 0; //旧短信计时器 int index = 1; data = null; while(true){ system.out.print("."); if(!serial.isopen()){ system.out.println("串口未打开, 退出程序"); break; } if(old_msg_count>=old_msg_delay){ // system.out.println("发送获取sim卡内存中的所有信息的指令"); sendcmd(serial, "at+cmgl=\"all\""); old_msg_count = 0; }else{ old_msg_count+=1000; //system.out.println("old_msg_count..."+old_msg_count); } if(serial.available()>0){ while(serial.available()>0){ data=serial.read(); //此处接收到的数据上限是1024 //system.out.print(new string(serial.read(), "utf-8")); } serial.flush(); } if(data!=null){ //接收到数据 string cc = new string(data, "gbk"); //处理中文 system.out.println("cc:"+cc); if(cc!=null && !cc.trim().equals("")){ //处理数据 /** * 有新短信时: * +ciev: "message",1 * * +cmti: "sm",1 */ if(cc.indexof("+cmti")!=-1){ index = getindexfromnewsms(cc); system.out.println("发现新短信.index:"+index); sendcmd(serial, "at+cmgr="+index); } if(cc.indexof("+cmgr")!=-1){ string[] contents = getcontentfromindex(index, cc); system.out.println("[at+cmgr=index]读取存在卡上的短信内容.分析后:"); if(contents!=null){ system.out.println("新短信内容:"); for(string tt : contents){ system.out.println(tt); } //保存读到的短信 -> 服务器 if(senddatatoserver(contents)){ //删除已读出的短信 system.out.println("删除已读出的新短信.index:"+contents[0]); delsmsbyindex(serial, integer.parseint(contents[0])); } }else{ system.out.println("新短信内容:null"); } } /** * 查询旧短信时: * at+cmgl="all" * * +cmgl: 1,"rec read","18620671820",,"2017/10/26,11:37:03+08",161,25 * just because the people11 * +cmgl: 2,"rec read","18620671820",,"2017/10/26,11:37:03+08",161,25 * just because the people11 */ if(cc.indexof("cmgl:")!=-1){ //获取第1条短信 string[] contents = getcontentfromstoragesms(cc); system.out.println("[at+cmgl=\"all\"]存在卡上的短信内容.分析后:"); for(string tt : contents){ system.out.println(tt); } //保存读到的短信 if(senddatatoserver(contents)){ //删除已读出的短信 system.out.println("删除已读出的旧短信.index:"+contents[0]); delsmsbyindex(serial, integer.parseint(contents[0])); } } }else{ system.out.println("data:"+new string(data)); system.out.println("data(byte[]) 转换成 string时出错"); } } //if(cc!=null && !cc.trim().equals(""))system.out.println(cc); data = null; thread.sleep(1000); } } catch(ioexception ex) { console.println(" ==>> serial setup failed : " + ex.getmessage()); return; } } /** * 把短信上传到服务器中 * @param contents 数组 [0] - 短信位置索引 [1] - 电话号码 [2] - 日期+时间 2017/10/26 11:37:03+08 [3] - 短信内容 * @return */ public static boolean senddatatoserver(string[] contents){ system.out.println("尝试上传短信数据"); try{ //移除时间中的时区 +08 2017/10/26 12:38:14+08...2017-10-26 12:38:14 string d = contents[2].substring(0,contents[2].lastindexof("+")); d = d.replace("/", "-").replace(" ", "%20"); stringbuffer url = new stringbuffer("http://192.168.6.2:9080/webservice.do?method=savesmsbank"); string vno = datetimeutil.datetostring(new date(), "yyyymmdd"); vno = stringutil.encodepassword(vno, "md5"); url.append("&vno=").append(vno); url.append("&smstype=0"); url.append("&port=2"); url.append("&rectime=").append(d); //need: 2013-12-05%2014:35:20 url.append("&phone=").append(contents[1]); url.append("&serialno=0"); url.append("&nums=0"); url.append("&submitport=0"); url.append("&sendid=").append(contents[1]); url.append("&sendtype=0"); url.append("&sendno=0"); string xx = new string(contents[3].getbytes(), "utf-8"); url.append("&txt=").append(java.net.urlencoder.encode(xx, "utf-8")); system.out.println("senddatatoserver().url:"+url.tostring()); string resurl = stringutil.getcontentbyurl2(url.tostring()); system.out.println("senddatatoserver().resurl:"+resurl); if(resurl.trim().equals("200")){ system.out.println("数据上传成功!"); return true; }else if(resurl.trim().equals("401")){ system.out.println("这个电话号码和短信内容已上传过, 数据重复!"); system.out.println("清除sim卡上的短信!"); return true; } }catch(exception e){ e.printstacktrace(); return false; } return false; } /** * 解析返回的短信内容 * @return */ public static string[] getcontentfromindex(int index, string res){ try{ system.out.println("尝试读取短信...getcontentfromindex.res:"+res); if(res.indexof("ok")!=-1){ system.out.println("获取短信成功,解析内容..."); /** * +cmgr: "rec read","18620671820",,"2017/10/26,11:37:03+08",161,17,0,0,"+8613010200500",145,25 * just because the people11 * * +cmgr: "rec read","18620671820",,"2017/10/26,11:37:03+08",161,17,0,0,"+8613010200500",145,25 * ---------------- ------------- - ---------- ----------- --- -- - - ---------------- --- -- * [0] [1] [2] [3] [4] [5] [6][7][8] [9] [10][11] */ string[] ccs = res.split("\r\n"); string phone = new string(); string senddate = new string(); string content = new string(); boolean isvalid = false; //数据获取成功 for(int i=0;i<ccs.length;i++){ if(ccs[i].indexof("cmgr:")!=-1){ string[] temp1 = ccs[i].split(","); phone = temp1[1]; senddate = temp1[3]+" "+temp1[4]; content = ccs[i+1]; isvalid = true; break; //只处理1条 } } if(!isvalid)return null; //处理双引号 phone = phone.substring(1,phone.length()-1); senddate = senddate.substring(1,senddate.length()-1); string[] resu = new string[4]; resu[0] = string.valueof(index); resu[1] = phone.trim(); resu[2] = senddate; resu[3] = content; return resu; }else if(res.indexof("cms error")!=-1){ //cms error:321 表示所读取的内存位置出错,一般是指定位置无短信内容所致 system.out.println("获取短信失败,错误内容..."); return null; } }catch(exception e){ e.printstacktrace(); } return null; } /** * 有新短信时,获取短信内容: * +ciev: "message",1 * * +cmti: "sm",1 * * @return index 短信所在的内存位置 index */ public static int getindexfromnewsms(string cc){ try{ string[] ccs = cc.split("\r\n"); for(string v : ccs){ if(v.indexof("cmti: \"sm\",")!=-1){ string c = v.substring(v.indexof(",")+1); return integer.parseint(c); } } }catch(exception e){ e.printstacktrace(); } return 0; } /** * 查询旧短信, 每次只抓1条: * +cmgl: 4,"rec read","106907931100",,"2017/07/02,10:15:19+08" * -------- ---------- -------------- ----------- ------------ * [0] [1] [2] [3] [4] [5] 【小米】[小米移动]您2017年6月共消费1.32元,当前余额97.88元。其中:数据流量费1.32元;语音通信费0元;短/彩信费0元 +cmgl: 5,"rec read","106908761100",,"2017/08/02,10:15:30+08" 。查询账单 http://10046.mi.com 。 +cmgl: 6,"rec read","106908761100",,"2017/08/02,10:15:30+08" 【小米】[小米移动]您2017年7月共消费0.81元,当前余额97.01元。其中:数据流量费0.81元;语音通信费0元;短/彩信费0元 ok @return 数组 [0] - 短信位置索引 [1] - 电话号码 [2] - 日期+时间 [3] - 短信内容 */ public static string[] getcontentfromstoragesms(string cc){ string[] ccs = cc.split("\r\n"); string smsindex = new string(); string phone = new string(); string senddate = new string(); string content = new string(); for(int i=0;i<ccs.length;i++){ if(ccs[i].indexof("cmgl:")!=-1){ //smsindex = integer.parseint(ccs[i].substring(ccs[i].indexof("cmgl:")+5, ccs[i].indexof(","))); smsindex = ccs[i].substring(ccs[i].indexof("cmgl:")+5, ccs[i].indexof(",")); string[] temp1 = ccs[i].split(","); phone = temp1[2]; senddate = temp1[4]+" "+temp1[5]; content = ccs[i+1]; break; //只处理1条 } } //处理双引号 phone = phone.substring(1,phone.length()-1); senddate = senddate.substring(1,senddate.length()-1); string[] res = new string[4]; res[0] = smsindex.trim(); res[1] = phone.trim(); res[2] = senddate; res[3] = content; return res; } /** * 删除指定位置上的短信 * at+cmgd=4 * @param index 短信索引位置 * @return */ public static boolean delsmsbyindex(serial serial, int index){ string res = new string(sendcmd(serial, "at+cmgd="+index)); system.out.println("at+cmgd="+index+":"+res); //if(res.indexof("ok")==-1){ // system.out.println("删除["+index+"]位置的短信失败!"); // return false; //} return true; } /** * * 初始化gprs.模块 * at 100ms 握手 / sim卡检测等 * at+cpin? 100ms 查询是否检测到sim卡 * at+csq 100ms 信号质量测试,值为0-31,31表示最好 * at+ccid 100ms 读取sim的ccid(sim卡背面20位数字),可以检测是否有sim卡或者是否接触良好 * at+creg? 500ms 检测是否注册网络 * @return */ public static boolean initgprs(serial serial){ if(!serial.isopen()){return false;} //串口未准备好 byte[] buffs = new byte[128]; try{ system.out.println("try send at to module..."); //char cmd[] = {'a', 't'}; //byte cmd[] = "at".getbytes(); //buffs = sendcmd(serial, "at".getbytes()); system.out.print("\r\ngprs模块检测中..."); buffs = sendcmd(serial, "at"); string res = new string(buffs); if(res.indexof("ok")==-1){ system.out.println("gprs模块未准备好, 请检查电源和串口波特率是否正确!"); return false; } system.out.println(" ...[正常]\r\n"); //system.out.println("at.res:"+res); system.out.print("\r\n检测sim卡..."); res = new string(sendcmd(serial, "at+cpin?")); if(res.indexof("ready")==-1){ system.out.println("sim卡未准备好!"); return false; } system.out.println(" ...[正常]\r\n"); //system.out.println("at+cpin?.res:"+res); system.out.print("\r\n信号质量测试,值为0-31,31表示最好..."); res = new string(sendcmd(serial, "at+csq")); if(res.indexof("error")!=-1){ system.out.println("信号质量测试检测失败"); return false; } /** * +csq: 24,99 */ string[] vs = res.split("\r\n"); for(string v : vs){ if(v.indexof(":")!=-1){ string x = v.substring(v.indexof(":")+1); //system.out.println("x:"+x); system.out.println(" ...信号强度:["+x.trim()+"]\r\n"); } } //system.out.println("at+csq.res:"+res); res = new string(sendcmd(serial, "at+ccid")); system.out.println("at+ccid.res:"+res); res = new string(sendcmd(serial, "at+creg?")); system.out.println("at+creg.res:"+res); }catch(exception e){ e.printstacktrace(); return false; } return true; } /** * * 初始化gprs.设置短信模式及短信接收参数 * at+cmgf=1 0-pdu, 1-文本格式 * at+csdh=1 * at+cpms="sm","sm","sm" 将信息保存在sim卡中, sm-表示存在sim卡上 * at+cnmi=2,1,0,1,1 收接通知,并存在指定位置(与at+cpms设置有关) * * 设置好后, 收到短信: * +ciev: "message",1 * +cmti: "sm",1 表示存储位置index=1 * @return */ public static boolean initgprs_sms(serial serial){ if(!serial.isopen()){return false;} //串口未准备好 string res = new string(); try{ system.out.print("\r\n设置短信格式..."); res = new string(sendcmd(serial, "at+cmgf=1")); if(res.indexof("ok")==-1){ system.out.println("设置失败!"); return false; } system.out.println(" ...[文本格式]\r\n"); thread.sleep(100); system.out.print("\r\nat+csdh=1..."); res = new string(sendcmd(serial, "at+csdh=1")); if(res.indexof("ok")==-1){ system.out.println("设置失败!"); return false; } system.out.println(" ...[done]\r\n"); thread.sleep(100); system.out.print("\r\n设置信息保存位置..."); res = new string(sendcmd(serial, "at+cpms=\"sm\",\"sm\",\"sm\"")); if(res.indexof("ok")==-1){ system.out.println("设置失败!"); return false; } system.out.println(" ...[sim卡]\r\n"); thread.sleep(100); system.out.print("\r\n收接通知,并存在指定位置..."); res = new string(sendcmd(serial, "at+cnmi=2,1,0,1,1")); if(res.indexof("ok")==-1){ system.out.println("设置失败!"); return false; } system.out.println(" ...[done]\r\n"); thread.sleep(100); }catch(exception e){ e.printstacktrace(); return false; } return true; } //public static byte[] sendcmd(serial serial, byte[] cmd){ public static byte[] sendcmd(serial serial, string cmd){ long overtime = 10000; //每条指令超时上限 5秒 long timecount = 0; //计时器 byte[] buffs = new byte[128]; try { serial.writeln(cmd+"\r"); //serial.writeln("at\r"); timecount = 0; while(timecount<overtime){ //system.out.print(serial.available()); if(serial.available()>0){ while(serial.available()>0){ buffs = serial.read(); //system.out.print(new string(serial.read())); //system.out.print(new string(buffs)); } serial.flush(); timecount = overtime; //exit while } timecount += 100; thread.sleep(100); } //system.out.println("sendcmd:"+new string(buffs)); } catch (illegalstateexception e) { // todo auto-generated catch block e.printstacktrace(); } catch (exception e) { // todo auto-generated catch block e.printstacktrace(); } return buffs; } } // end snippet: serial-snippet
程序中的方法: senddatatoserver()
主要是用于上传保存短信, 大家替换成自己的方式即可
总结
以上所述是小编给大家介绍的树莓派.gprs.短信接收器,希望对大家有所帮助!
上一篇: JAVA超级简单的爬虫实例讲解
下一篇: yii2实现根据时间搜索的方法
推荐阅读