www.pudn.com > ATCLib.rar > ATCLib.cs
using System;
using System.Text;
using System.Threading;
using System.Data.SqlTypes;
using System.Globalization;
namespace ATCLib
{
///
/// ATC 的摘要说明。
///
public class ATC
{
// 成员
public IntPtr _hComm =IntPtr.Zero; //串口句柄
// cnt属性
public string CommPort="";
private int ComBaudRate =0;
UnicodeEncoding Ue = new UnicodeEncoding(true,false);
public ATC()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
#region 端口操作
public bool Open(string Port,int BaudRate)
{
CommPort = Port;
ComBaudRate = BaudRate;
/* 端口编号为10以上的 需要使用\\.\COM10,这里统一修改为此种格式 */
string szSpecPort = @"\\.\"+ Port;
_hComm =Win32Com.CreateFile(szSpecPort,Win32Com.GENERIC_READ|Win32Com.GENERIC_WRITE,0,IntPtr.Zero,
Win32Com.OPEN_EXISTING,0,IntPtr.Zero);
if( _hComm == (IntPtr)Win32Com.INVALID_HANDLE_VALUE)
{
_hComm =IntPtr.Zero;
return false;
}
// 设置端口属性
Win32Com.DCB dcb = new Win32Com.DCB();
if( !Win32Com.GetCommState(_hComm,out dcb))
{
CloseComm();
return false;
}
dcb.BaudRate = BaudRate;
dcb.ByteSize =8;
dcb.Parity =0;
dcb.StopBits =0;
if(!Win32Com.SetCommState(_hComm,ref dcb))
{
CloseComm();
return false;
}
// 设置端口超时
Win32Com.COMMTIMEOUTS CommTimeouts = new Win32Com.COMMTIMEOUTS();
if( !Win32Com.GetCommTimeouts(_hComm, out CommTimeouts))
{
CloseComm();
return false;
}
// 有超时控制
CommTimeouts.ReadIntervalTimeout = 100;
CommTimeouts.ReadTotalTimeoutConstant = 500;
CommTimeouts.ReadTotalTimeoutMultiplier = 10;
CommTimeouts.WriteTotalTimeoutConstant = 100;
CommTimeouts.WriteTotalTimeoutMultiplier =10;
if( !Win32Com.SetCommTimeouts(_hComm,ref CommTimeouts))
{
CloseComm();
return false;
}
// 简单AT 指令测试
string sRecv = AtCmd("AT\r\n");
if( sRecv.Length ==0 || sRecv.IndexOf("OK") == -1)
{
CloseComm();
return false;
}
return true;
}
public void CloseComm()
{
Win32Com.CloseHandle(_hComm);
}
public bool ReOpen()
{
CloseComm();
return Open(CommPort,ComBaudRate);
}
// 发送字节数组
private int WriteData(byte[] tosend,int len)
{
uint sent = 0;
if (!Win32Com.WriteFile(_hComm,tosend,(uint)len,out sent, IntPtr.Zero))
{
return 0;
}
Win32Com.FlushFileBuffers(_hComm);
return (int)sent;
}
// 接收
private string RecvComm()
{
byte[] bRx = new byte[128];
Int32 nRead =0;
string szReturn ="";
if(Win32Com.ReadFile(_hComm,bRx,128,out nRead,IntPtr.Zero))
{
if(nRead >0)
szReturn= Encoding.ASCII.GetString(bRx,0,nRead);
}
return szReturn;
}
// 写入ASCII字符串,发送AT指令
private int SendAtCmd(string Cmd)
{
byte[] b = new byte[Cmd.Length];
b = Encoding.ASCII.GetBytes(Cmd);
int sentLen = WriteData(b,b.Length);
return sentLen;
}
// 发送At指令并返回响应内容
public string AtCmd(string Cmd)
{
string szReturn=string.Empty;
if( SendAtCmd(Cmd) >0)
szReturn = RecvComm();
return szReturn;
}
#endregion
#region Tools
// 增加字节
private byte[] AppendOct(byte[] bys,byte[] byDest)
{
byte[] bysNew =new byte[byDest.Length +bys.Length];
try
{
Array.Copy(byDest,bysNew,byDest.Length);
Array.Copy(bys,0,bysNew,byDest.Length,bys.Length);
}
catch(Exception e)
{
Console.WriteLine(e);
}
return bysNew;
}
// 号码按照GSM规范编码
private string GsmInvertNumbers(string Mobile)
{
StringBuilder sb =new StringBuilder();
for(int i=0;i0)
{
int nTrytimes =0;
string szResp="";
while( nTrytimes< 1) // list all sms,反馈比较多,因此等待时间稍长
{
string sRecv = RecvComm();
if( sRecv.Length >0)
szResp += sRecv;
else
nTrytimes++;
}
string szResult=ParseSmsResp(szResp);
if( szResult.StartsWith("2 "))
Count = Int32.Parse(szResult.Substring(2));
}
return Count;
}
// 清除制定位置短信
void RemoveSms(int at)
{
if(SendAtCmd("AT+CMGD=" + at.ToString() +"\r\n") >0)
{
int nTrytimes =0;
while(nTrytimes<2)
{
string sRecv = RecvComm();
if( sRecv.Length >0)
{
ParseSmsResp(sRecv);
break;
}
nTrytimes++;
}
}
}
// 解析短信回应
private string ParseSmsResp(string szResp)
{
string szReturn ="";
int nNewSms =0;
string[] sl= szResp.Split(new char[]{'\r','\n'});
for(int i=0;i-1 ) // 继续
{
szReturn ="0 " + s;
break;
}
else if(s.IndexOf("ERROR") > -1)
{
szReturn="1 "+ s;
break;
}
else if( s.IndexOf("+CMGL:") >-1) // list sms
{
int at = s.IndexOf(",");
if( at>0)
{
string szPos = s.Substring(6,at-6).Trim();
i+=2;
// 解析新短信内容
ParseSmsMsg(sl[i]);
// 删除指定位置的短信
RemoveSms(Int32.Parse(szPos));
nNewSms ++;
}
}
else
{
// 未能识别的内容
//AddRunInfo(s);
Console.WriteLine(s);
}
}
if( nNewSms >0 ) // 如果接受到新的短信,则返回新的短信数量
szReturn ="2 "+ nNewSms.ToString();
return szReturn;
}
// 解析短信内容
void ParseSmsMsg(string Msg)
{
string sOrg =string.Empty; // 发送者
string sTxt =string.Empty; // 消息内容
byte[] bys = Txt2Bytes(Msg);
int at =0;
// 短信中心
int nLen = bys[at++];
at += nLen;
// First-Octet
byte b = bys[at++];
// TP-OA
nLen = bys[at++]; // 号码个数
if( bys[at++]==0x91) // 0x91表示国际号码,前有+,如果是0xA1,则表示号码为国内号码
sOrg +="+";
int OALen =0;
if( SqlInt32.Mod(nLen,2) ==0)
OALen = nLen/2;
else
OALen = nLen/2 +1;
byte[] bysOA = new byte[OALen];
Array.Copy(bys,at,bysOA,0,OALen);
sOrg += GsmSerializeNumbers(Bytes2Txt(bysOA));
at += OALen;
// TP-PID
b = bys[at++];
// TP-DCS
int nDCS = bys[at++];
// TP-SCTS
at += 7; // 固定长度7位,Year,Month,Day,Hour,Minute,Second,TimeZone
// TP-UDL
nLen = bys[at++]; // 信息内容的字节长度
// TP-UD
if( nDCS ==8)
{
// UCS2编码,文字短信
UnicodeEncoding ue=new UnicodeEncoding(true,false);
sTxt =ue.GetString(bys,at,nLen);
AddRunInfo(string.Format("Sms {0} {1}",sOrg,sTxt));
}
else if( nDCS ==4)
{
// 二进制信息,当做mms notification解析
byte[] byUD= new byte[nLen];
Array.Copy(bys,at,byUD,0,nLen);
try
{
sTxt =ParseMmsNotification(byUD,ref sOrg);
AddRunInfo(string.Format("Mms {0} {1}",sOrg,sTxt));
// 使用网络连接获取mms
}
catch(Exception e)
{
AddRunInfo(e.Message);
}
}
}
// 接收到Mms Notification,返回mms message获取地址
//0605040B8423F02006246170706C69636174696F6E2F766E642E7761702E6D6D732D6D65737361676500B487AF848C82984F4C576468484A5A734F7142008D9083687474703A2F2F3231312E3133392E3134342E3138312F4F4C576468484A5A734F7142008805810302A30089178031333537303234313331392F545950453D504C4D4E008A808E020150
private string ParseMmsNotification(byte[] bys,ref string Org)
{
string Url =string.Empty;
int at =0;
// WSP协议
int nLen = bys[at++];
at += nLen;
// 消息类型
at +=2;
// ContenType Length
nLen = bys[at];
at ++;
// ContenType
byte[] bysContentType= new byte[nLen];
Array.Copy(bys,at,bysContentType,0,nLen);
string sContentType = Encoding.ASCII.GetString(bysContentType);
at += nLen;
if(sContentType.StartsWith("application/vnd.wap.mms-message"))
{
byte b;
// Actual MMS notification message starts
while(at< bys.Length)
{
switch(bys[at])
{
case 0x8C: // X-MMS-Message-Type
at++;
b = bys[at++];
break;
case 0x98: //X-Mms-Transaction-ID
at++;
string TransID = GetTextString(bys,ref at);
break;
case 0x8D: // X-Mms-MMS-Version
at+=2;
break;
case 0x89: // From
at++;
nLen = bys[at++];
if( bys[at++] == 0x80)
{
//Address-present-token Encoded-string-value
Org = GetTextString(bys,ref at);
Org = Org.Replace("/TYPE=PLMN","");
}
else
at += (nLen-1);
break;
case 0x96: // Subject
at++;
string Subject = GetTextString(bys,ref at);
break;
case 0x8A: // X-Mms-Message-Class
at+=2;
break;
case 0x8E: // X-Mms-Message-Size
at++;
nLen = bys[at++];
at += nLen;
break;
case 0x88: // X-Mms-Expiry
at++;
nLen = bys[at++];
at += nLen;
break;
case 0x83: // X-Mms-Content-Location
at++;
Url= GetTextString(bys,ref at);
break;
}
}
}
return Url;
}
// 发送GSM信息,使用PDU方式,发送给手机号码
/*
08 SMSC地址信息的长度 共8个八位字节(包括91)
91 SMSC地址格式(TON/NPI) 用国际格式号码(在前面加‘+’)
68 31 08 20 05 05 F0 SMSC地址 8613800250500,补‘F’凑成偶数个
11 基本参数(TP-MTI/VFP) 发送,TP-VP用相对格式
00 消息基准值(TP-MR) 0
0D 目标地址数字个数 共13个十进制数(不包括91和‘F’)
91 目标地址格式(TON/NPI) 用国际格式号码(在前面加‘+’)
68 31 58 81 27 64 F8 目标地址(TP-DA) 8613851872468,补‘F’凑成偶数个
00 协议标识(TP-PID) 是普通GSM类型,点到点方式
00 用户信息编码方式(TP-DCS) 7-bit编码
00 有效期(TP-VP) 5分钟
06 用户信息长度(TP-UDL) 实际长度6个字节
C8 32 9B FD 0E 01 用户信息(TP-UD) “Hello!”
联通测试用
AT+CMGS=19 0891683110808805F011000D91683128251715F1000800044F60597D
移动测试,上海卡发送到5388
AT+CMGS=
0891683108200105F01100069168358800080004004C0053
*/
public int SendSMS_GSM(string Mobile,string Txt)
{
int nResult =-1;
// Address of the SMSC
byte[] bysPdu = new byte[]{0x00};
//byte[] bysPdu = new byte[]{0x08,0x91};
//bysPdu = AppendOct(Txt2Bytes(GsmInvertNumbers(AddrSMSC)),bysPdu);
//int lenSMSC = bysPdu.Length;
// TPDU
bysPdu = AppendOct(new byte[]{0x11,0x00},bysPdu);
// 增加Dest
if( (!Mobile.StartsWith("86")) && Mobile.Length ==11) // 手机号码使用 +86
Mobile= Mobile.Insert(0,"86");
byte[] byLenDest = new byte[]{0x00,0x91};
byLenDest[0] = (byte)Mobile.Length;
if( !Mobile.StartsWith("86"))
byLenDest[1] = 0xA1; // 使用国内号码,深圳卡需要
bysPdu = AppendOct(byLenDest,bysPdu);
bysPdu = AppendOct(Txt2Bytes(GsmInvertNumbers(Mobile)),bysPdu);
//
bysPdu = AppendOct(new byte[]{0x00,0x08,0x00},bysPdu);
byte[] UD = Ue.GetBytes(Txt);
byte[] byLenData = new byte[1];
byLenData[0] = (byte) UD.Length;
bysPdu = AppendOct(byLenData,bysPdu);
bysPdu = AppendOct(UD,bysPdu);
string sAt = string.Format("AT+CMGS={0}\r",bysPdu.Length-1); // 结尾的0x1A不包含在长度内
if( SendAtCmd(sAt)>0)
{
string sRecv = RecvComm();
if(sRecv.IndexOf("\r\n> ") >-1)
{
if( SendAtCmd(Bytes2Txt(bysPdu) + Encoding.ASCII.GetString(new byte[]{0x1A}))>0)
{
int TryTimes =0;
while(TryTimes <5)
{
string sRecv2 = RecvComm();
if( sRecv2.Length ==0)
{
TryTimes ++;
continue;
}
string szResult =ParseSmsResp(sRecv2);
if( szResult.StartsWith("0 "))
{
AddRunInfo(szResult);
nResult=0; // 成功
break;
}
else if(szResult.StartsWith("1 "))
{
AddRunInfo(szResult);
Thread.Sleep(4000); // 暂停4s
// 清除sms
//ClearSms();
break; // 失败
}
}
if( TryTimes ==5)
{
AddRunInfo("发送后等待响应超时");
Thread.Sleep(1000);
}
}
else
{
AddRunInfo("Com Data Write Error");
Thread.Sleep(1000);
}
}
else
{
AddRunInfo("Get Error Response,"+ sRecv);
Thread.Sleep(1000);
}
}
else
{
AddRunInfo("Com Data Write Error");
Thread.Sleep(1000);
}
return nResult;
}
#endregion
#region 语音呼叫部分
// 语音呼叫
public bool Dial(string Number)
{
if(SendAtCmd("ATD"+ Number +";\r\n") >0)
{
int TryTimes =0;
while(TryTimes <5)
{
string sRecv = RecvComm();
if( sRecv.Length ==0)
{
TryTimes++;
continue;
}
string szResult = ParseDialResp(sRecv);
if(szResult.StartsWith("0 "))
return true;
else if( szResult.StartsWith("1 "))
return false;
}
}
return false;
}
public void HangUp()
{
if(SendAtCmd("ATH\r\n") >0)
{
int TryTimes =0;
while(TryTimes <5)
{
string sRecv = RecvComm();
if( sRecv.Length ==0)
{
TryTimes++;
continue;
}
string szResult = ParseDialResp(sRecv);
if(szResult.StartsWith("0 "))
break;
else if( szResult.StartsWith("1 "))
break;
}
}
}
private string ParseDialResp(string Msg)
{
string szReturn =string.Empty;
string[] sl= Msg.Split(new char[]{'\r','\n'});
for(int i=0;i-1 ) // 继续
{
szReturn ="0 " + s;
break;
}
else if(s.IndexOf("ERROR") > -1)
{
szReturn="1 "+ s;
break;
}
else
AddRunInfo(s);
}
return szReturn;
}
#endregion
public void AddRunInfo(string Msg)
{
MobileSim.MainWnd.frm.AddRunInfo(Msg);
}
}
}