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); 
		} 
	} 
}