分享一个GSM短信猫接口程序

本系列文章由ex_net(张建波)编写,转载请注明出处。

http://blog.csdn.net/ex_net/article/details/8586348

作者:张建波 邮箱: 281451020@qq.com 电话:13577062679 欢迎来电交流!

市面上的短信猫,大多是TC35i、Tc35的模块。下面的程序主要是针对西门子的TC35系列的GSM模块。GSM模块的通讯采用AT指令。上位机(PC、单片机、ARM等)通过串口与GSM模块连接。

上图是TC35i模块,淘宝上大多短信猫的里面都是这个模块+232电平转换电路+SIM卡座+天线部分等。

基于GSM短信的应用很多,例如远程控制、数据采集等等。GSM短信猫编程的难点在与“程序与GSM”通讯是异步的。

例如:

AT+CSQ 查询信号指令,PC通过RS232串口发送后,GSM短信猫要等一小会才回答,而且还可能不回答。

这样一来就导致编程复杂了。

下面的程序采用了串口中断接收、定时器、线程的方式配合。实现了接收短信,并把接收到的短信存在数据库中。然后定期发送短信。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace SMS
{
public class GSMModem
{
private string protName;
private int BaudRate;
private System.Collections.ArrayList alRecevingSM;// 短信接收 缓冲区
private System.Collections.ArrayList alSendSM;    // 短信【待】发送 缓冲区
private System.Collections.ArrayList alAuthorizationNumber; //授权号码,系统只会回复授权号码
int WORK_STATE;//短信猫工作状态
//错误的短信数,主要是未经授权的号码发来的短信
private int ErrorSMCount = 0;
public int _ErrorSMCount
{
get
{
return ErrorSMCount;
}
}
/// <summary>
/// 0=自检
/// 1=接收
/// 2=发送
/// </summary>
public int _WORK_STATE
{
get
{
return WORK_STATE;
}
}
//接收和发送定时器不能同时工作,切记
//短信接收 轮询 定时器,定时发送 AT+CGMR={0}
System.Windows.Forms.Timer revTimer = new System.Windows.Forms.Timer();
//短信发送 队列 定时器,定时发送 AT+CMGS={0}
System.Windows.Forms.Timer sendTimer = new System.Windows.Forms.Timer();
//短信猫自检
System.Windows.Forms.Timer selfCheckingTimer = new System.Windows.Forms.Timer();
//短信猫连接设备端口
System.IO.Ports.SerialPort Port = new System.IO.Ports.SerialPort();
//短信猫串口接收缓冲
/*备注:该缓冲变量由串口DataReceived事件负责接收,具体的处理过程由
*     Timer 定时器内的代码具体执行
*/
string temp_gsm_str_buf = "";
//
int CMGD_MAX_ID = 0;//短信卡最大SM容量,通常情况下设置为25
int CMGD_ID = 1;    //当前串口发送读取的短信ID号
int GSM_RST_ACT = 0;
int GSM_MAX_RST_ACT = 8;
int CGMS_Count = 0; //短信发送数量
public int _CGMS_Count
{
get
{
return CGMS_Count;
}
}
public int _CMGD_MAX_ID
{
get
{
return CMGD_MAX_ID;
}
}
public int _CMGD_ID
{
get
{
return CMGD_ID;
}
}
public int _GSM_RST_ACT
{
get
{
return GSM_RST_ACT;
}
}
public int _GSM_MAX_RST_ACT
{
get
{
return GSM_MAX_RST_ACT;
}
}
#region 短信猫工作状态
string INF_GSM_CSQ;
string INF_GSM_CSCS;
string INF_GSM_CSCA;
string INF_GSM_CNMI;
bool INF_GSM_State;
public string _INF_GSM_CSQ
{
get
{
return INF_GSM_CSQ;
}
}
public string _INF_GSM_CSCS
{
get
{
return INF_GSM_CSCS;
}
}
public string _INF_GSM_CSCA
{
get
{
return INF_GSM_CSCA;
}
}
public string _INF_GSM_CNMI
{
get
{
return INF_GSM_CNMI;
}
}
public bool _INF_GSM_State
{
get
{
return INF_GSM_State;
}
}
#endregion
private int _CmgsSleepTime;
public GSMModem(string protName,
string BaudRate,
int CMGD_MAX_ID,
System.Collections.ArrayList RecevingSM,
System.Collections.ArrayList SendSM,
int revTimerInterval,
int sendTimerInterval,
int selfCheckingTimerInterval,
int CmgsSleepTime,
System.Collections.ArrayList alAuthorizationNumber
)
{
_CmgsSleepTime = CmgsSleepTime;//AT+CMGS 指令发送后,稍微延迟一定时间,让短信猫做出反应
this.alAuthorizationNumber = alAuthorizationNumber;//保存授权号码
this.CMGD_MAX_ID = CMGD_MAX_ID;
this.protName = protName;
this.BaudRate = int.Parse(BaudRate);
this.alRecevingSM = RecevingSM;
this.alSendSM = SendSM;
selfCheckingTimer.Enabled = false;
revTimer.Interval = revTimerInterval;
revTimer.Enabled = false;
sendTimer.Interval = sendTimerInterval;
sendTimer.Enabled = false;
revTimer.Tick += revTimer_Tick; //挂接短信轮询 定时器
sendTimer.Tick += sendTimer_Tick;
selfCheckingTimer.Interval = selfCheckingTimerInterval;
selfCheckingTimer.Tick += selfCheckingTimer_Tick;
Port.DataReceived += Port_DataReceived;
}
public bool Start()
{
try
{
Port.PortName = protName;
Port.BaudRate = BaudRate;
Port.Open();//打开串口
//短信猫 先自检,自检成功了,才能进行 接收 或 发送
selfCheckingTimer.Enabled = true;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return false;
}
return false;
}
public bool Stop()
{
sendTimer.Enabled = false;
revTimer.Enabled = false;
selfCheckingTimer.Enabled = false;
Port.Close();
CMGD_ID = 1;
alRecevingSM.Clear();
alSendSM.Clear();
ErrorSMCount = 0;
return true;
}
void Port_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
System.IO.Ports.SerialPort serialPort = Port;
int len = serialPort.BytesToRead;
byte[] bs = new byte[len];
serialPort.Read(bs, 0, len);
if (len == 0)
{
return;
}
else
{
//接收处理
string r = Encoding.ASCII.GetString(bs, 0, len);
temp_gsm_str_buf += r;
//接收数据处理
//txtGsmRevLog.Invoke(new EventHandler(DoUpdate), r);  //线程处理
Console.Write(r);
}
}
private bool AuthorizationPhoneNumber(string phoneID)
{
for (int i = 0; i < alAuthorizationNumber.Count; i++)
{
string s = alAuthorizationNumber[i].ToString();
if (phoneID.Equals(s))
return true;
}
return false;
}
bool DoGsmDataReceived()
{
//短信猫发回数据处理
string str = temp_gsm_str_buf;
if (str.Trim().StartsWith("+CMGR"))
{
int P1 = str.IndexOf("0891");
if (P1 != -1)
{
str = str.Substring(P1);
int P2 = str.IndexOf("\r\n");
if (P2 != -1)
{
string uPDU = str.Substring(0, P2);
string decMsg = PDUDecoding.DecodingMsg(uPDU);
string[] content = decMsg.Split(',');
string stime = content[1].ToString();
string sphoneId = content[0].ToString().Replace("+86", "");
string sgsmtxt = content[2].ToString();
//object[] row = { stime, sphoneId, sgsmtxt };
if (AuthorizationPhoneNumber(sphoneId))
{
SMDATA sm = new SMDATA();
sm.sTime = stime;
sm.sPoneID = sphoneId;
sm.sContent = sgsmtxt;
sm.pdu = uPDU;
sm.sType = "Admin";
alRecevingSM.Add(sm);
}
else
{
//未经授权的用户,10086短信,广告信息,垃圾短信,用户手机号码
string[] gsmCmd = sgsmtxt.Trim().Split('+');
string cmd = gsmCmd[0].ToString();
if (cmd == "CX")
{
if (gsmCmd.Length == 1)
{
//仅限 用户手机号码
SMDATA sm = new SMDATA();
sm.sTime = stime;
sm.sPoneID = sphoneId;
sm.sContent = "CX";  //让BI查询车辆信息
sm.pdu = uPDU;
sm.sType = "User";
alRecevingSM.Add(sm);
}
}
else
{
Console.WriteLine("Error:" + stime + " " + sphoneId + " " + sgsmtxt);
ErrorSMCount++;
}
}
return true;
}
}
}
else
{
}
return false;
}
bool DoGsmDataSend()
{
//短信猫发回数据处理
string str = temp_gsm_str_buf;
if (str.Trim().IndexOf("+CMGS") > -1)
{
temp_gsm_str_buf = "";
CGMS_Count++;
return true;
}
else
{
//接收到错误信息,可能是短信发送失败
}
temp_gsm_str_buf = "";
return false;
}
//短信发送 指令发送定时器
int SendID;
int AT_CMGS_LEN;
void sendTimer_Tick(object sender, EventArgs e)
{
WORK_STATE = 2;//设置短信猫工作模式为 发送
if (DoGsmDataSend())
{
alSendSM.RemoveAt(SendID);
}
//没有发送的短信了
if (alSendSM.Count == 0)
{
CMGD_ID = 1;
sendTimer.Enabled = false; //关闭发送
revTimer.Enabled = true;   //打开接收
}
else
{
SendID = 0;
SMDATA sendSM = (SMDATA)alSendSM[SendID];
string sPoneID = sendSM.sPoneID;
string sContent = sendSM.sContent;
string msg = sContent;
string pdu = PDUDecoding.GetPDUMsg(sPoneID, msg);
AT_CMGS_LEN = PDUDecoding.getLenght(msg);
GsmWrite(string.Format("AT+CMGS={0}\r", AT_CMGS_LEN.ToString()));
Thread.Sleep(_CmgsSleepTime);  //500延时,如果短信猫反应慢,设置为1000
GsmWrite(pdu + "\r");
}
}
//短信轮询 指令发送定时器
void revTimer_Tick(object sender, EventArgs e)
{
//定时器每中断1次,接收1条指令
WORK_STATE = 1;//设置短信猫工作模式为 接收
if (DoGsmDataReceived())
{
int old_CMGD_ID = CMGD_ID - 1;
GsmWrite("AT+CMGD=" + old_CMGD_ID.ToString() + "\r");
Thread.Sleep(1000);
}
if (CMGD_ID > CMGD_MAX_ID)
{
revTimer.Enabled = false;//停止接收
sendTimer.Enabled = true;//启动短信发送
}
else
{
//再读取下一条
temp_gsm_str_buf = "";
GsmWrite("AT+CMGR=" + CMGD_ID.ToString() + "\r");
CMGD_ID++;
}
}
#region 短信猫初始信息
private void selfCheckingTimer_Tick(object sender, EventArgs e)
{
//先处理串口接收的数据
//Console.WriteLine(temp_gsm_str_buf);
WORK_STATE = 0;  //设置工作状态为自检
string str = "";
if (temp_gsm_str_buf.Length > 0)
{
int CSQ = temp_gsm_str_buf.IndexOf("+CSQ");
if (CSQ > -1)
{
str = temp_gsm_str_buf.Substring(CSQ);
string[] content = str.Trim().Split(':');
if (content.Length > 1)
{
INF_GSM_CSQ = content[1].ToString().Replace("OK", "").Replace("\r\n", "").Replace("\"", "");
GSM_RST_ACT++;
}
temp_gsm_str_buf = "";
}
int CSCS = temp_gsm_str_buf.IndexOf("+CSCS");
if (CSCS > -1)
{
str = temp_gsm_str_buf.Substring(CSCS);
string[] content = str.Trim().Split(':');
if (content.Length > 1)
{
INF_GSM_CSCS = content[1].ToString().Replace("OK", "").Replace("\r\n", "").Replace("\"", "");
GSM_RST_ACT++;
}
temp_gsm_str_buf = "";
}
int CSCA = temp_gsm_str_buf.IndexOf("+CSCA");
if (CSCA > -1)
{
str = temp_gsm_str_buf.Substring(CSCA);
string[] content = str.Trim().Split(':');
if (content.Length > 1)
{
INF_GSM_CSCA = content[1].ToString().Replace("OK", "").Replace("\r\n", "").Replace("\"", "");
GSM_RST_ACT++;
}
temp_gsm_str_buf = "";
}
int CNMI = temp_gsm_str_buf.IndexOf("+CNMI");
if (CNMI > -1)
{
str = temp_gsm_str_buf.Substring(CNMI);
string[] content = str.Trim().Split(':');
if (content.Length > 1)
{
INF_GSM_CNMI = content[1].ToString().Replace("OK", "").Replace("\r\n", "");
GSM_RST_ACT++;
}
temp_gsm_str_buf = "";
}
}
//
switch (GSM_RST_ACT)
{
case 0: { GsmWrite("ATE0\r"); GSM_RST_ACT++; break; }
case 1: { GsmWrite("AT+CSQ\r"); break; }
case 2: { GsmWrite("AT+CMGF=1\r"); GSM_RST_ACT++; break; }
case 3: { GsmWrite("AT+CSCS?\r"); break; }
case 4: { GsmWrite("AT+CSCA?\r"); break; }
case 5: { GsmWrite("AT+CMGF=0\r"); GSM_RST_ACT++; break; }
//AT+CNMI=0,0,0,0
//case 6: { GsmWrite("AT+CNMI=3,1,0,0\r"); GSM_ACT++; break; }
case 6: { GsmWrite("AT+CNMI=0,0,0,0\r"); GSM_RST_ACT++; break; }
case 7: { GsmWrite("AT+CNMI?\r"); break; }
case 8:
{
INF_GSM_State = true;
selfCheckingTimer.Enabled = false;
revTimer.Enabled = true;//启动 接收
//btnSendTestSM.Enabled = true;
//checkBox1.Enabled = true;
//btnSendTestSM.Enabled = true;
//timer_gsm_REST.Enabled = false;
break;
}
default:
{
selfCheckingTimer.Enabled = false;
//timer_gsm_REST.Enabled = false;
INF_GSM_State = false;
MessageBox.Show("短信猫自检失败!");
break;
}
}
}
#endregion
private void GsmWrite(string str)
{
Port.Write(str);
Console.Write(str);
}
public int GetSMCount()
{
return alRecevingSM.Count;
}
}
}

在短信接收上,上面的代码实现了对垃圾号码、或着非授权号码进行了简单过滤。

另外附上一个机遇W77E58单片机+GPS+GSM做的一个远程定位系统的资料,虽然已经很“老土”了。

http://blog.csdn.net/ex_net/article/details/2765895

可以供大家参考PC机、单片机和GSM的通信处理方式。

分享一个GSM短信猫接口程序相关推荐

  1. 基于JCFXBL与GSM短信猫的短信中心建设方案

    基于JCFXBL与GSM短信猫的短信中心建设方案 本系列文章由ex_net(张建波)编写,转载请注明出处. http://blog.csdn.net/ex_net/article/details/87 ...

  2. gsm短信猫长短信pdu数据包分析[转]

    原文地址:gsm短信猫长短信pdu数据包分析作者:sunnyboy 查看原文:http://blog.appdoc.cn/2011/04/29/gsm-pdu-packet-analyze [capt ...

  3. 关于设计一个群发短信的小程序

    关于设计一个群发短信的小程序 写这个小程序是因为我身边的一些朋友在做一些工作时经常需要群发一些短信,这些短信往往是"你好!XXX,感谢你--"在除了名字XXX不一样其他内容相同的情 ...

  4. 老许,免费分享一个python短信接口,包含200条短信,你要不要?

    今天给大家分享一个免费的python短信接口.可以用于短信注册.登录.密码找回.短信通知等场景. 使用方法如下: 1.下载资源包,按照文档申请签名和模板,就可以看到200条短信额度了 2.在代码中填写 ...

  5. 分享一个诺基亚短信生成器

    https://zzkia.noddl.me:8020/

  6. 短信猫二次开发(java版)

    短信猫二次开发(java版) 短信猫 短信猫用于批量收/发短信或其它SIM卡服务. 短信猫与PC通过GSM无线网络交互. 交互过程可以分为三个层次: 1.物理层,即无线网络通信. 2.指令层,短信猫支 ...

  7. 终结所有短信猫(GPRS,GSM,CDMA,PHS)的发短信问题,以及想语音告警的问题!

     smsMan短信猫开发中间件介绍 smsMan 短信猫开发中间件 联系方式: qq:101143933,加我时注明"smsMan",否则我不会加的.             Em ...

  8. C#通用类库--短信猫操作类1(原始AT命令)

    一个C#资源分享平台,专业分享学习高质量代码,每周期布置学习任务,激发学习C#兴趣!(QQ群:128874886)  关于C#操作短信猫的文章在博客园也有很多,其中个人认为比较专业的就是 给我一杯酒 ...

  9. 把安卓手机当作短信猫的三款ANDROID应用

    把安卓手机当作短信猫,性能稳定,管理方便,最近研究了一下相关的ANDROID短信猫应用,推荐一下三款:虫虫云猫,SMSSync,中文版SMS Gateway,下面做分别做介绍. 1.虫虫云猫: 收到短 ...

最新文章

  1. Android内核开发必备知识
  2. 集成Lucene和HBase(转)
  3. 信号与系统 chapter2 冲激偶函数与阶跃函数
  4. mysql set语句_从强网杯随便注浅析mysql存储过程
  5. 设计模式——工厂方法
  6. 新年第一份“欧气”,“中国开发者大调查”第五批中奖名单出炉啦
  7. df命令--Linux命令应用大词典729个命令解读
  8. JS中某事件需要同时调用几个function另类解决办法。
  9. 共享没有计算机网络连接不上去,苹果usb共享给电脑连接不上怎么办
  10. 费马,solovay-staassen,米勒拉宾素性检验方法python实现与比较
  11. 十一则:程序员冷“笑话”据说只有真正的程序员才看得懂
  12. SAS逻辑回归之二分类
  13. 【Python量化】风险平价策略
  14. 计算机云维护是做什么的,IT运维是什么?云时代下的运维人员是怎样的?
  15. 大数据可视化(八)数据可视化中的交互
  16. 运维文档管理规范标准
  17. python中的结束用语,python语句结束符号_Python从文本中提取hashtags;以标点符号结尾...
  18. 培训机构靠谱吗?|猿代码科技
  19. 楼市、二手、分期……2个月后iPhone X在中国将会一机难求?
  20. 气象学需要计算机知识吗,应用气象学专业学什么

热门文章

  1. MySQL中IF函数的使用方法
  2. python做万花筒代码_Python实现PS滤镜的万花筒效果示例
  3. 【C语言功法手册】第三话 · 循环结构一点就通
  4. 怎样使用“查找我的iPhone”查找丢失的AirPods
  5. 用Python批量给照片换底色,基于opencv模块
  6. 【二分查找】一文带你掌握二分法 (附万能模板)
  7. CapsLocker for Mac(Capslock键开关)
  8. 软件测试面试刷题app包含了各种难题
  9. SETUP EXE 安装文件加密器V4.0
  10. Android ART Oat文件格式简析(上)