金笛工业手机论坛  

返回   金笛工业手机论坛 > 开发者乐园 > 短信开发资料

短信开发资料 短信开发技巧,代码分析

回复
 
LinkBack 主题工具 显示模式
旧 2012-08-24   #1 (permalink)
论坛管理员
 
admin 的头像
 
注册日期: 2009-06-30
帖子: 861
admin 的声望功能已被禁用
默认 中英文手机短信 PDU 串 编码(UCS2) 解码(UCS2,7-Bit) 程序 ( in C# )

中英文手机短信 PDU 串 编码(UCS2) 解码(UCS2,7-Bit) 程序 ( in C# )
//=====================================================================================
/* 关于手机短信(SMS)的编码模式及其规则,读者可以查阅相关规范, 如 GSM03.08, GSM03.40,
GSM07.05等. 科脑工作室的 bhw98 先生在文献<<通过串口收发短消息(上/下篇)>>中通过实例给出了
详细说明, <<Visual C++/Turbo C 串口通信编程实践>>(电子工业出版社)一书中对其原文进行了全
面重载, 有兴趣的读者可参考以上文献.
本文给出通过串口收发手机中英文短信的全部 C# 实现过程.中英文短信内容编码均采用UCS2模
式, 考虑到有些手机在纯英文模式下编码为 7-Bit模式, 为了能对这些内容解读, 文中也提供了
7-Bit 模式短信内容解码程序; 文中编码解码过程未使用任何第三方控件.
文中提供了两个主要函数 SendSms()和 ReceiveSms(), 直接调用就可实现短信发送和接收, 例
如: SendSms("13800755500","13423714101","神州六号将于近期发射!"); 即完成发送;
ReceiveSms(); 即完成接收, 内容存于字符数组 ReceTele[],ReceTime[],ReceText[]中;
开发平台: Windows 2003 Server; Visual Studio.NET 2003 ;添加 VS 98 MSComm控件;
硬件: 西门子TC35i终端或其它无线MODEM;
西门子TC35i终端AT指令集可从以下网站下载:
http://www.wlt.net.cn/index0/tc35i/tc35i.htm, 文件名为:tc35i_atc_v0103_1073581.pdf
主要程序代码如下:
[作者约定: 若某一行以注释开头, 则该注释用于说明该行后面内容;否则, 若以代码开头,则其后
注释用于说明本行内容]
*/
//=====================================================================================
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Text; //Encoding 等函数名字空间
using System.Threading; // Thread.Sleep 函数名字空间

namespace TC35iSMS
{
public class Form1 : System.Windows.Forms.Form
{
//下列字符串数组用于存放已收短信相关内容
private string[] ReceTele=new string[40]; //电话号码
private string[] ReceTime=new string[40]; //日期时间
private string[] ReceText=new string[40]; //短信正文
private System.Windows.Forms.TextBox txtSmscNumber;
private System.Windows.Forms.ListBox RecMessListBox;
private System.Windows.Forms.TextBox txtDestNumber;
private System.Windows.Forms.TextBox txtSmsText;
private System.Windows.Forms.Button btnReceive;
private System.Windows.Forms.Label lbMessage;
private System.Windows.Forms.Button btnSend;
private System.Windows.Forms.Label label3;
//MsComm串口控件,可从 VS 98 选择安装;即将发行的 VS.NET 2005 中
//自带有串口控件,用户可直接使用
private AxMSCommLib.AxMSComm COM1;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;

private System.ComponentModel.Container components = null;

public Form1()
{
InitializeComponent();
}

protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows 窗体设计器生成的代码
/// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void InitializeComponent()
{
System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(Form1));
this.txtSmscNumber = new System.Windows.Forms.TextBox();
this.RecMessListBox = new System.Windows.Forms.ListBox();
this.txtDestNumber = new System.Windows.Forms.TextBox();
this.txtSmsText = new System.Windows.Forms.TextBox();
this.btnReceive = new System.Windows.Forms.Button();
this.lbMessage = new System.Windows.Forms.Label();
this.btnSend = new System.Windows.Forms.Button();
this.label3 = new System.Windows.Forms.Label();
this.COM1 = new AxMSCommLib.AxMSComm();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
((System.ComponentModel.ISupportInitialize)(this.COM1)).BeginInit();
this.SuspendLayout();
//
// txtSmscNumber
//
this.txtSmscNumber.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));
this.txtSmscNumber.ForeColor = System.Drawing.Color.Blue;
this.txtSmscNumber.Location = new System.Drawing.Point(24, 32);
this.txtSmscNumber.MaxLength = 11;
this.txtSmscNumber.Name = "txtSmscNumber";
this.txtSmscNumber.Size = new System.Drawing.Size(80, 21);
this.txtSmscNumber.TabIndex = 42;
this.txtSmscNumber.Text = "13800755500";
//
// RecMessListBox
//
this.RecMessListBox.ItemHeight = 12;
this.RecMessListBox.Location = new System.Drawing.Point(8, 96);
this.RecMessListBox.Name = "RecMessListBox";
this.RecMessListBox.ScrollAlwaysVisible = true;
this.RecMessListBox.Size = new System.Drawing.Size(536, 280);
this.RecMessListBox.TabIndex = 41;
//
// txtDestNumber
//
this.txtDestNumber.ForeColor = System.Drawing.Color.Blue;
this.txtDestNumber.Location = new System.Drawing.Point(552, 120);
this.txtDestNumber.MaxLength = 13;
this.txtDestNumber.Name = "txtDestNumber";
this.txtDestNumber.Size = new System.Drawing.Size(88, 21);
this.txtDestNumber.TabIndex = 37;
this.txtDestNumber.Text = "13423714101";
//
// txtSmsText
//
this.txtSmsText.ForeColor = System.Drawing.Color.Blue;
this.txtSmsText.Location = new System.Drawing.Point(208, 8);
this.txtSmsText.MaxLength = 70;
this.txtSmsText.Multiline = true;
this.txtSmsText.Name = "txtSmsText";
this.txtSmsText.Size = new System.Drawing.Size(432, 80);
this.txtSmsText.TabIndex = 35;
this.txtSmsText.Text = "";
//
// btnReceive
//
this.btnReceive.Font = new System.Drawing.Font("宋体", 10F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));
this.btnReceive.ForeColor = System.Drawing.Color.Blue;
this.btnReceive.Location = new System.Drawing.Point(560, 248);
this.btnReceive.Name = "btnReceive";
this.btnReceive.Size = new System.Drawing.Size(80, 24);
this.btnReceive.TabIndex = 40;
this.btnReceive.Text = "接 收";
this.btnReceive.Click += new System.EventHandler(this.btnReceive_Click);
//
// lbMessage
//
this.lbMessage.Font = new System.Drawing.Font("宋体", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));
this.lbMessage.ForeColor = System.Drawing.Color.Red;
this.lbMessage.Location = new System.Drawing.Point(16, 64);
this.lbMessage.Name = "lbMessage";
this.lbMessage.Size = new System.Drawing.Size(184, 23);
this.lbMessage.TabIndex = 38;
//
// btnSend
//
this.btnSend.Font = new System.Drawing.Font("宋体", 10F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));
this.btnSend.Location = new System.Drawing.Point(560, 184);
this.btnSend.Name = "btnSend";
this.btnSend.Size = new System.Drawing.Size(80, 23);
this.btnSend.TabIndex = 1;
this.btnSend.Text = "发 送";
this.btnSend.Click += new System.EventHandler(this.btnSend_Click);
//
// label3
//
this.label3.ForeColor = System.Drawing.Color.Blue;
this.label3.Location = new System.Drawing.Point(144, 8);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(56, 16);
this.label3.TabIndex = 34;
this.label3.Text = "发送内容";
//
// COM1
//
this.COM1.Enabled = true;
this.COM1.Location = new System.Drawing.Point(96, 32);
this.COM1.Name = "COM1";
this.COM1.OcxState = ((System.Windows.Forms.AxHost.State)(resources.GetObject("COM1.OcxState")));
this.COM1.Size = new System.Drawing.Size(38, 38);
this.COM1.TabIndex = 43;
//
// label1
//
this.label1.ForeColor = System.Drawing.Color.Black;
this.label1.Location = new System.Drawing.Point(8, 8);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(112, 16);
this.label1.TabIndex = 44;
this.label1.Text = "中心号码(不需+86)";
//
// label2
//
this.label2.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));
this.label2.ForeColor = System.Drawing.Color.Blue;
this.label2.Location = new System.Drawing.Point(568, 96);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(56, 16);
this.label2.TabIndex = 45;
this.label2.Text = "对方号码";
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(648, 381);
this.Controls.Add(this.label2);
this.Controls.Add(this.label1);
this.Controls.Add(this.COM1);
this.Controls.Add(this.txtSmscNumber);
this.Controls.Add(this.RecMessListBox);
this.Controls.Add(this.txtDestNumber);
this.Controls.Add(this.txtSmsText);
this.Controls.Add(this.btnReceive);
this.Controls.Add(this.lbMessage);
this.Controls.Add(this.btnSend);
this.Controls.Add(this.label3);
this.Name = "Form1";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "中英文手机短信 PDU 串 编码(UCS2) 解码(UCS2,7-Bit) 程序 ( in C# by 李仓海 )";
this.Load += new System.EventHandler(this.Form1_Load);
((System.ComponentModel.ISupportInitialize)(this.COM1)).EndInit();
this.ResumeLayout(false);

}
#endregion

[STAThread]
static void Main()
{
Application.Run(new Form1());
}
//=====================================================================================
private void Form1_Load(object sender, System.EventArgs e)
{
COM1.CommPort=1; //硬件连于 COM1
//串口设定: 波特率19200,无校验,8位数据位,1位停止位
COM1.Settings="19200,n,8,1";
COM1.InBufferSize=1024*8; //8K 读缓冲
COM1.PortOpen=true;//打开串口
for(int i=0;i<40;i++) //字符串数组清空
{
ReceTele[i]=""; //电话号码
ReceTime[i]=""; //日期时间
ReceText[i]=""; //短信正文
}
}
//=====================================================================================
private void btnSend_Click(object sender, System.EventArgs e) //点击发送按扭
{
this.btnSend.Enabled=false; //发送过程其它功能按扭禁用
this.btnReceive.Enabled=false;
this.SendSms(this.txtSmscNumber.Text,this.txtDestNumber.Text,
this.txtSmsText.Text);
this.btnSend.Enabled=true; //开启功能按扭
this.btnReceive.Enabled=true;
}
//=====================================================================================
private void btnReceive_Click(object sender, System.EventArgs e)//点击接收按扭
{
this.btnSend.Enabled=false;//接收过程其它功能按扭禁用
this.btnReceive.Enabled=false;
this.ReceiveSms(); //调用接收函数, 接收内容存于相应数组
this.RecMessListBox.Items.Clear();//短信显示栏清空
int Sms_Number=0; //短信数目变量
for (int i=0;i<40;i++) //显示已收短信内容
{
if ( ReceText[i].ToString().Length>0)
{
Sms_Number+=1;
this.RecMessListBox.Items.Add("来自:"+ReceTele[i]+
" 时间:"+ReceTime[i]);
this.RecMessListBox.Items.Add("内容:"+ReceText[i]);
this.RecMessListBox.Items.Add(" "); //短信间隔用空行
ReceTele[i]=""; //显示后字符串数组清空
ReceTime[i]="";
ReceText[i]="";
}
}
if(Sms_Number==0)
this.lbMessage.Text="暂无短信!";
else
this.lbMessage.Text="收到 "+Sms_Number.ToString()+" 条新短信!";
this.btnSend.Enabled=true;//开启功能按扭
this.btnReceive.Enabled=true;
}
//=====================================================================================
private void SendSms(string Smsc_Number,string Dest_Number,string Sms_Text)//发送函数
{
string pdu=""; //开始合成 PDU 串
pdu+="089168";
//SMSC中心号码补F凑成偶数
char[] tmpSmscNumber=(Smsc_Number+"F").ToCharArray();
for(int i=0;i<tmpSmscNumber.Length;i+=2) //字符两两对调
{
pdu+=tmpSmscNumber[i+1].ToString();
pdu+=tmpSmscNumber[i].ToString();
}
pdu+="11000D9168";
char[] tmpDestNumber=(Dest_Number+"F").ToCharArray();//对方号码
for(int i=0;i<tmpDestNumber.Length;i+=2) //字符两两对调
{
pdu+=tmpDestNumber[i+1].ToString();
pdu+=tmpDestNumber[i].ToString();
}
pdu+="000800"; //08 表示采用 UCS2 编码
//短信正文转为Unicode
byte[] tmpSmsText=Encoding.Unicode.GetBytes(Sms_Text);
pdu+=tmpSmsText.Length.ToString("X2"); //正文内容长度
for(int i=0;i<tmpSmsText.Length;i+=2) //高低字节对调
{
pdu+=tmpSmsText[i+1].ToString("X2");//("X2")转为16进制
pdu+=tmpSmsText[i].ToString("X2");
} //PDU串 完成
int tmpLength=(pdu.Length-18)/2;//除去SMSC段长度
//向串口发Send an SMS 命令
this.COM1.Output="AT+CMGC="+tmpLength+(char)13;
Thread.Sleep(500);//延时 0.5 秒
this.COM1.Output=pdu;//输出 PDU 串
this.COM1.Output=((char)26).ToString();//结束
Thread.Sleep(1500);//延时 1.5 秒
}
//=====================================================================================
private void ReceiveSms() //接收函数
{
//向串口发 List SMS Messages from preferred store 指令
this.COM1.Output="AT+CMGL=0"+(char)13;
Thread.Sleep(1000); //延时 1 秒
if(this.COM1.InBufferCount<=0)
return;
string ans="";//清空应答串
//该循环用于当卡中有多条(>=5)未读短信时可一次全部读出
while(this.COM1.InBufferCount>0)
{
ans+=this.COM1.Input.ToString(); //将串口 Buff 内容存入应答串 ans
Thread.Sleep(3000); //延迟3秒
}
//下列循环将已读短信逐一从SIM卡内存中删除,否则若SIM卡内存不足将再无发收发!
for (int i=1;i<=40;i++)
{
string m_id="+CMGL: "+i.ToString();
if(ans.IndexOf(m_id,0)>=0) //取得 SIM 卡内存中短信 ID 号
{
Thread.Sleep(500);//延时 0.5 秒
this.COM1.Output="AT+CMGD="+i+(char)13; //删除SIM卡内存中短信
}
}
//开始查找是否有合格 PDU 串
if(ans.IndexOf("+CMGL:",0)<0 ||ans.IndexOf("OK",0)<0
|| ans.IndexOf("ERROR",0)>=0)
{ ans=""; return;}
ans=ans.Substring(ans.IndexOf("+CMGL:",0));
int MessNo=0; //存储短信相关内容的数组下标
string tmpPdu="";
while(ans.IndexOf("0891")!=-1)
{
ans=ans.Substring(ans.IndexOf("0891",0));
int NextOne=ans.IndexOf("+CMGL:");
if(NextOne!=-1) //同时收到多条 SMSes
{
tmpPdu=ans.Substring(0,NextOne-2);//读取第一条PDU串
ans=ans.Substring(NextOne);//定位到下一条
}
else
{
int LastOk=ans.IndexOf("OK",0); //仅收到一条 SMS
tmpPdu=ans.Substring(0,LastOk-4);//读取PDU串
ans="";//应答串清空
}
string EncodeType=tmpPdu.Substring(40,2);//编码方式
if(EncodeType=="08" || EncodeType=="00")
{
ReceTele[MessNo]=this.GetTeleFromPdu(tmpPdu);//电话号码
ReceTime[MessNo]=this.GetTimeFromPdu(tmpPdu);//日期时间
//以下为短信正文解析
if(EncodeType=="08") //UCS2 解码
ReceText[MessNo]=this.GetTextFromPdu_UCS2(tmpPdu);
else //7-Bit 解码
ReceText[MessNo]=this.GetTextFromPdu_7Bit(tmpPdu);
MessNo+=1;
}
} // end of while
}
//=====================================================================================
private string GetTeleFromPdu(string pdu) //解析 TeleNumber 函数
{
//截取PDU串中短信发送方电话号码源码
string TeleInPdu=pdu.Substring(26,12);
string Tele="";
char[] d=TeleInPdu.ToCharArray();//存入字符数组
for (int i=0;i<d.Length;i+=2)//字符两两对调
{
Tele+=d[i+1].ToString();
Tele+=d[i].ToString();
}
Tele=Tele.Substring(0,11);//去掉末位"F"
return Tele;//返回发送方电话号码
}
//=====================================================================================
private string GetTimeFromPdu(string pdu) //解析 DateTime 函数
{
//截取PDU串中短信日期时间源码
string TimeInPdu=pdu.Substring(42,12);
string Time="";
char[] d=TimeInPdu.ToCharArray();//存入字符数组
for (int i=0;i<d.Length;i+=2)//字符两两对调
{
Time+=d[i+1].ToString();
Time+=d[i].ToString();
}
Time="20"+Time; //将年份前加 20 形成 4 位格式,以下为日期时间输出格式控制
Time=Time.Substring(0,4)+"-"+Time.Substring(4,2)+"-"
+Time.Substring(6,2)+" "+Time.Substring(8,2)+":"
+Time.Substring(10,2)+":"+Time.Substring(12,2);
return Time; //返回短信日期时间[年-月-日 时:分:秒]
}
//=====================================================================================
private string GetTextFromPdu_UCS2(string pdu) //解析短信正文函数_UCS2编码
{
//截取PDU串中短信正文部分源码,读者也可用BitConverter函数实现部分转换
string TextInPdu=pdu.Substring(58);
string Text="";
char[] d=TextInPdu.ToCharArray();//存入字符数组
for (int i=0;i<d.Length;i+=4)
{
int unicode_nu=0;
for (int m=0;m<4;m++) //计算 Unicode 十进制值
unicode_nu+=HexToDec(d[i+m])*(1<<((3-m)*4));
Text+=(char)unicode_nu; //输出 Unicode 对应字符
}
return Text;//返回短信正文内容
}
//=====================================================================================
private int HexToDec(char Hex) //16 进制转 10 进制
{
int Dec;
if(Hex>='0' && Hex<='9')
Dec=Convert.ToInt16(Hex-'0'); //0-9
else
Dec=Convert.ToInt16(Hex-'A')+10;// A-F
return Dec;//返回 10 进制值
}
//=====================================================================================
//该段内容为作者根据 7-Bit 编码原理图,应用数学矩阵关系式方法导出的解码流程,相信一定有
//更简便的方法, 恳请读者批评指教!! Email: sztcm@public.szptt.net.cn
private string GetTextFromPdu_7Bit(string pdu) //解析短信正文函数_7-Bit编码
{
string TextInPdu=pdu.Substring(58);//截取PDU串中短信正文部分源码
string Text="";
while (TextInPdu.Length%14!=0) //最后一组不满7个成员时补"0"
TextInPdu+="0";
char[] a=TextInPdu.ToCharArray(); //将源码存入字符数组 a[]
string b="";
for(int i=0;i<a.Length;i++) //将源码转为二进制并存入字符串 b
b+=GetBinary(a[i]);
char[] total=b.ToCharArray(); //将二进制码存入字符数组 total[]
for ( int j=0;j<total.Length;j+=56) //56位二进制码为一组,循环所有组
{
char[] s=new char[56];
for(int i=0;i<56;i++) //将一组二进制码拷贝到字符数组 s[]
s[i]=total[i+j];
char[] d=new char[56];
//-------------------------------------------------------------------------------------
for(int i=0;i<7;i++) //组内解码得到目标二进制码数组 d[]
d[i]=s[i+1];
for(int k=1;k<=6;k++)
{
for( int i=k*7;i<(k+1)*7-k; i++)
d[i]=s[i+(k*2+1)];
for ( int i=(k+1)*7-k;i<(k+1)*7;i++)
d[i]=s[i-((7-k)*2+1)];
}
for ( int i=49;i<56;i++)
d[i]=s[i-1];
//-------------------------------------------------------------------------------------
for(int k=0;k<56;k+=7) //组内循环得到目标 ASCII 字符
{
int ascii_nu=0;
for (int m=0;m<7;m++)
ascii_nu+=Convert.ToInt16(d[k+m].ToString())*(1<<(6-m));
Text+=(char)ascii_nu; //输出 ASCII 码相应字符
}
} // END OF loop j
return Text;
}
//=====================================================================================
private string GetBinary(char Hex) //16 进制转 2 进制
{
int Dec;
if(Hex>='0' && Hex<='9')
Dec=Convert.ToInt16(Hex-'0');
else
Dec=Convert.ToInt16(Hex-'A')+10;
int displayMask=1<<3;
StringBuilder Bin=new StringBuilder();
for(int i=0;i<4;i++)
{
//append 0 or 1 depending on result of masking
Bin.Append( (Dec & displayMask)==0 ? "0":"1" );
//shift left so that mask will find bit of next digit
//during next iteration of loop
Dec<<=1;
}
return Bin.ToString();
}
//=====================================================================================
} // END OF class Form1
} // END OF namespace TC35iSMS
__________________

让世界倾听我们的笛声
admin 当前离线   回复时引用此帖
回复

书签


当前查看此主题的会员: 1 (0 位会员和 1 位游客)
 

发帖规则
不可以发表新主题
不可以发表回复
不可以上传附件
不可以编辑自己的帖子

启用 BB 代码
论坛启用 表情符号
论坛启用 [IMG] 代码
论坛禁用 HTML 代码
Trackbacks are 启用
Pingbacks are 启用
Refbacks are 启用


相似的主题
主题 主题作者 版面 回复 最后发表
AT指令-通过串口收发短消息(上,下) admin 短信开发资料 0 2012-08-24 18:44
用串口连接GSM手机发送和接收短消息,在应用程序中如何编程实现 admin 短信开发资料 0 2012-08-24 15:58
编译指令与说明(Delphi) susu8988 短信开发资料 0 2009-10-26 09:59
Delphi中的DLL的编写 susu8988 短信开发资料 0 2009-10-22 10:38
通过串口收发短消息 lihb 短信开发资料 0 2009-10-15 14:53


所有时间均为北京时间。现在的时间是 19:47


Powered by vBulletin® 版本 3.8.3
版权所有 ©2000 - 2024,Jelsoft Enterprises Ltd.