当前位置: 移动技术网 > IT编程>开发语言>Java > 树莓派.GPRS.短信接收器

树莓派.GPRS.短信接收器

2019年07月19日  | 移动技术网IT编程  | 我要评论

起因

曾经用过西门子出的短信猫, 好处是直接有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.短信接收器,希望对大家有所帮助!

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网