www.pudn.com > SMS.rar > hwmobile.cpp


// HwMobile.cpp: implementation of the CHwMobile class. 
// 
////////////////////////////////////////////////////////////////////// 
 
#include "stdafx.h" 
#include "DllHwMobile.h" 
#include "HwMobile.h" 
 
#ifdef _DEBUG 
#undef THIS_FILE 
static char THIS_FILE[]=__FILE__; 
#define new DEBUG_NEW 
#endif 
 
#ifndef _SMS_DISABLE 
 
// 
// 计算字符个数 
// 
int CountCharNumber ( char *szStr, char cCalc ) 
{ 
	ASSERT ( szStr ); 
	int nCount = 0; 
	for ( int i=0; szStr[i]!='\0'; i++ ) 
	{ 
		if ( szStr[i] == cCalc ) 
			nCount ++; 
	} 
 
	return nCount; 
} 
 
// 
// 得到字符串的编码方式,纯英文用 GSM_7BIT 编码、带特殊字符的英文用 GSM_8BIT 编码、中文等用 GSM_UCS2 编码 
// 
int GetStringEncodeType ( char *pStr, int nSize) 
{ 
	if ( !pStr ) return FALSE; 
	int nLen = (int)strlen(pStr); 
 
	int nEncode = GSM_7BIT; 
	int nEspecialCharCount = 0; 
	for ( int i=0; i 0 ) 
		nEncode = GSM_8BIT; 
 
	return nEncode; 
} 
 
// 
// 分析短信属性,编码方式、做一条短信时可以发送多少字节数据、超过了多少数据等等 
// return : ---------------------------------------------------------------------------------------- 
//		szSMSContent 中可以用一条短信来发送的字节数 
// Remark : ---------------------------------------------------------------------------------------- 
//		编码方式决定短信长度:GSM_7BIT 编码可以发送160个字符, GSM_8BIT 编码可以发送140个字符, 
//		GSM_UCS2 编码只能发送70个字符 
// Notice : ---------------------------------------------------------------------------------------- 
//		这里,将一个英文字母、一个汉字和一个数据字节都视为一个字符 
// 
int ParseSMSContentAttr ( 
		IN char* szSMSContent, 
		OUT int *pnTotalCharNum/*=NULL*/,		// szSMSContent 总字符数 
		OUT int *pnFreeCharNum/*=NULL*/,		// 将 szSMSContent 作成一条短信后,一条满负荷的短信还剩下多少个字符空间可以填入 
		OUT int *pTP_DCS 
	) 
{ 
	ASSERT ( szSMSContent ); 
	int nSMSContentLen = (int)strlen ( szSMSContent ); 
	// 根据短信字符串来计算应该使用的编码方式 
	int TP_DCS = GetStringEncodeType ( szSMSContent, nSMSContentLen ); 
	if ( pTP_DCS ) *pTP_DCS = TP_DCS; 
	// 根据编码方式来获取一条短信的最大字符数 
	int nUDMaxCharNum = GET_UD_MAX_CHAR_NUM ( TP_DCS ); 
	 
	int nTotalCharCount = 0;		// 用来统计总字符数 
	int nOneSMSByteCount = 0;		// 用来统计 szSMSContent 中可以用一条短信来发送的字节数 
	for ( int i=0; i 0 ) 
			{ 
				int TP_DCS = 0, nTotalCharNum = 0; 
				int nOneSMSByteCount = ParseSMSContentAttr ( szText, &nTotalCharNum, pnFreeCharNum, &TP_DCS ); 
				nOneSMSByteCount = FindSentenceSyncopatePostion ( szText, nOneSMSByteCount-1 ); 
				memset ( szOneSMSText, 0, sizeof(szOneSMSText) ); 
				strncpy ( szOneSMSText, szText, nOneSMSByteCount ); 
				pStrAry->Add ( GetCompatibleString(szOneSMSText,FALSE) ); 
				if ( pUIntAry_DCS ) pUIntAry_DCS->Add ( TP_DCS ); 
				int nRemainLen = (int)strlen(szText)-nOneSMSByteCount; 
				memmove ( szText, szText+nOneSMSByteCount, nRemainLen ); 
				szText[nRemainLen] = '\0'; 
			} 
			ASSERT ( !pUIntAry_DCS || pStrAry->GetSize() == pUIntAry_DCS->GetSize() ); 
		} 
	} 
 
#ifdef UNICODE 
	delete[] szText; 
#endif 
	return pStrAry; 
} 
 
////////////////////////////////////////////////////////////////////// 
// Construction/Destruction 
////////////////////////////////////////////////////////////////////// 
 
CHwMobile::CHwMobile () 
	: m_nInitOK ( TRUE ) 
	, m_bSoundPrompt ( TRUE ) 
	, m_nBaudRate ( 0 ) 
	, m_nComNO ( 0 ) 
	, m_Proc_SaveSMSCFromGSM ( NULL ) 
	, m_Proc_IncomingFromGSM ( NULL ) 
	, m_bInitMobileLastRes ( -1 ) 
{ 
	HwDbgLog ( L_DEBUG, _T("CHwMobile 构造完成") ); 
	m_hEvt_IsBusy = ::CreateEvent ( NULL, TRUE, FALSE, NULL ); 
} 
 
CHwMobile::~CHwMobile() 
{ 
	if ( HANDLE_IS_VALID(m_hEvt_IsBusy) ) 
		::CloseHandle (m_hEvt_IsBusy); 
	m_hEvt_IsBusy = NULL; 
 
	m_UIntAry_NeedDelSMS.RemoveAll (); 
} 
 
// 
// PDU编码,用于编制、发送短消息 
// 输入: pSrc - 源PDU参数指针 
// 输出: szDst - 目标PDU串指针 
// 返回: 目标PDU串长度 
// 
int CHwMobile::gsmEncodePdu(const SM_PARAM *pSrc, char *szDst, int nDstSize ) 
{ 
	int nLength=0;							// 内部用的串长度 
	int nDstLength=0;						// 目标PDU串长度 
	BYTE buf[4096]={0};			// 内部用的缓冲区 
 
//	strcpy ( (char*)pSrc->TPA, "13823310105" ); 
//	strcpy ( (char*)pSrc->SCA, "8613800755500" ); 
 
	// SMSC 地址信息段 
	nLength = (int)strlen(pSrc->SCA);	// SMSC地址字符串的长度	 
	buf[0] = (char)((nLength & 1) == 0 ? nLength : nLength + 1) / 2 + 1;	// SMSC地址信息长度 
	buf[1] = 0x91;					// 0x0 : 本地格式; 0x91 : 用国际格式号码,就是:国家代码+手机号码 
	nDstLength = gsmBytes2String(buf, szDst, 2, nDstSize);	// 转换2个字节到目标PDU串 
	// 转换SMSC号码到目标PDU串 
	nDstLength += gsmInvertNumbers(pSrc->SCA, &szDst[nDstLength], nLength,nDstSize-nDstLength); 
	// TPDU段基本参数、目标地址等 
	nLength = (int)strlen(pSrc->TPA);	// TP-DA地址字符串的长度 
	buf[0] = 0x11;					// 是发送短信(TP-MTI=01),TP-VP用相对格式(TP-VPF=10) 
	buf[1] = 0;						// TP-MR=0 
	buf[2] = (char)nLength;			// 目标地址数字个数(TP-DA地址字符串真实长度) 
	buf[3] = pSrc->bInternationalMobileNO ? 0x91 : 0x0;		// 0x0 : 本地格式; 0x91 : 用国际格式号码,就是:国家代码+手机号码 
	nDstLength += gsmBytes2String(buf, &szDst[nDstLength], 4, nDstSize-nDstLength );		// 转换4个字节到目标PDU串 
	nDstLength += gsmInvertNumbers(pSrc->TPA, &szDst[nDstLength], nLength,nDstSize-nDstLength);	// 转换TP-DA到目标PDU串 
 
	// TPDU段协议标识、编码方式、用户信息等 
	nLength = (int)strlen(pSrc->TP_UD_Byte);	// 用户信息字符串的长度 
	buf[0] = pSrc->TP_PID;			// 协议标识(TP-PID) 
	buf[1] = pSrc->TP_DCS;			// 用户信息编码方式(TP-DCS) 
	buf[2] = 0xFF;					// 有效期(TP-VP)为 : 0x00~0xff (5分钟~最长) 
	if ( GET_DCS(pSrc->TP_DCS) == GSM_8BIT )	 
	{ 
		// 8-bit编码方式 
		buf[3] = gsmEncode8bit(pSrc->TP_UD_Byte, &buf[4], nLength, sizeof(buf)-4);	// 转换TP-DA到目标PDU串 
		nLength = buf[3] + 4;		// nLength等于该段数据长度 
	} 
	else if ( GET_DCS(pSrc->TP_DCS) == GSM_UCS2 ) 
	{ 
		// UCS2编码方式 
		buf[3] = gsmEncodeUcs2(pSrc->TP_UD_Byte, &buf[4], nLength, sizeof(buf)-4);	// 转换TP-DA到目标PDU串 
		nLength = buf[3] + 4;		// nLength等于该段数据长度 
	} 
	else 
	{ 
		// 7-bit编码方式 
		buf[3] = nLength;			// 编码前长度 
		nLength = gsmEncode7bit(pSrc->TP_UD_Byte, &buf[4], nLength+1, sizeof(buf)-4) + 4;	// 转换TP-DA到目标PDU串 
	} 
	nDstLength += gsmBytes2String(buf, &szDst[nDstLength], nLength,nDstSize-nDstLength);		// 转换该段数据到目标PDU串 
 
	// 返回目标字符串长度 
	return nDstLength; 
} 
 
// 
// PDU解码,用于接收、阅读短消息 
// 输入: pSrc - 源PDU串指针 
// 输出: pDst - 目标PDU参数指针 
// 返回: >= 0 用户信息串长度; -1 数据长度不够;-2 非法的数据 
// 
int CHwMobile::gsmDecodePdu ( char* pSrc, IN OUT int &nHandleBytes, SM_PARAM *pDst ) 
{ 
	ASSERT ( pSrc && nHandleBytes>0 && pDst ); 
	HwDbgLog ( L_DEBUG, _T("Pdu code is :\r\n%s"), GetCompatibleString(pSrc,FALSE) ); 
	const int nSrcLength = nHandleBytes; 
	nHandleBytes = 0; 
	int nDstLength=0;				// 目标PDU串长度 
	unsigned int tmp=0;				// 内部用的临时字节变量 
	BYTE buf[4096] = {0};	// 内部用的缓冲区 
 
	// SMSC地址信息段 
	gsmString2Bytes(pSrc+nHandleBytes, (BYTE *)&tmp, 2, sizeof(tmp) );	// 取长度 
	tmp = (tmp - 1) * 2;			// SMSC号码串长度 
	nHandleBytes += 4;						// 指针后移,忽略了SMSC地址格式 
	if ( nHandleBytes > nSrcLength ) 
		return -1; 
	if ( tmp >= sizeof ( pDst->SCA ) ) 
		return -2; 
	gsmSerializeNumbers ( pSrc+nHandleBytes, pDst->SCA, tmp, sizeof(pDst->SCA) );	// 转换SMSC号码到目标PDU串 
	nHandleBytes += tmp;		// 指针后移 
	if ( nHandleBytes > nSrcLength ) 
		return -1; 
 
	// TPDU段基本参数 
	gsmString2Bytes(pSrc+nHandleBytes, (BYTE *)&tmp, 2, sizeof(tmp) );	// 取基本参数 
	nHandleBytes += 2;			// 指针后移 
	if ( nHandleBytes > nSrcLength ) 
		return -1; 
 
	// 取回复号码 
	gsmString2Bytes(pSrc+nHandleBytes, (BYTE *)&tmp, 2, sizeof(tmp) );	// 取长度 
	if(tmp & 1) tmp += 1;	// 调整奇偶性 
	nHandleBytes += 4;			// 指针后移,忽略了回复地址(TP-RA)格式 
	if ( nHandleBytes > nSrcLength ) 
		return -1; 
	// 取TP-RA号码 
	if ( tmp >= sizeof ( pDst->TPA ) ) 
		return -2; 
	gsmSerializeNumbers(pSrc+nHandleBytes, pDst->TPA, tmp, sizeof(pDst->TPA) ); 
	nHandleBytes += tmp;		// 指针后移 
	if ( nHandleBytes > nSrcLength ) 
		return -1; 
 
	// TPDU段协议标识、编码方式、用户信息等 
	gsmString2Bytes(pSrc+nHandleBytes, (BYTE*)&pDst->TP_PID, 2, sizeof(pDst->TP_PID));	// 取协议标识(TP-PID) 
	nHandleBytes += 2;		// 指针后移 
	if ( nHandleBytes > nSrcLength ) 
		return -1; 
	gsmString2Bytes(pSrc+nHandleBytes, (BYTE*)&pDst->TP_DCS, 2, sizeof(pDst->TP_DCS));	// 取编码方式(TP-DCS) 
	nHandleBytes += 2;		// 指针后移 
	if ( nHandleBytes > nSrcLength ) 
		return -1; 
	gsmSerializeNumbers(pSrc+nHandleBytes, pDst->TP_SCTS, 14, sizeof(pDst->TP_SCTS));			// 服务时间戳字符串(TP_SCTS)  
	nHandleBytes += 14;		// 指针后移 
	if ( nHandleBytes > nSrcLength ) 
		return -1; 
	gsmString2Bytes ( pSrc+nHandleBytes, (BYTE *)&tmp, 2, sizeof(tmp) );			// 用户信息长度(TP-UDL) 
	nHandleBytes += 2;		// 指针后移 
	if ( nHandleBytes > nSrcLength ) 
		return -1; 
 
	int nLength = 0; 
	if ( GET_DCS(pDst->TP_DCS) == GSM_8BIT ) 
	{ 
		nLength = tmp * 2; 
		if ( nHandleBytes + nLength > nSrcLength ) 
			return -1; 
		// 8-bit解码 
		nDstLength = gsmString2Bytes(pSrc+nHandleBytes, buf, nLength, sizeof(buf) );				// 格式转换 
		nDstLength = gsmDecode8bit(buf, pDst->TP_UD_Byte, nDstLength, sizeof(pDst->TP_UD_Byte) );	// 转换到TP-DU 
	} 
	else if ( GET_DCS(pDst->TP_DCS) == GSM_UCS2 ) 
	{ 
		nLength = tmp * 2; 
		if ( nHandleBytes + nLength > nSrcLength ) 
			return -1; 
		// UCS2解码 
		nDstLength = gsmString2Bytes(pSrc+nHandleBytes, buf, nLength, sizeof(buf) );				// 格式转换 
		nDstLength = gsmDecodeUcs2(buf, pDst->TP_UD_Byte, nDstLength, sizeof(pDst->TP_UD_Byte) );	// 转换到TP-DU 
	} 
	else 
	{ 
		// 7-bit解码 
		nLength = (tmp & 7) ? ((int)tmp * 7 / 4 + 2) : ((int)tmp * 7 / 4); 
		if ( nHandleBytes + nLength > nSrcLength ) 
			return -1; 
		nDstLength = gsmString2Bytes(pSrc+nHandleBytes, buf, nLength, sizeof(buf) );				// 格式转换 
		gsmDecode7bit(buf, pDst->TP_UD_Byte, nDstLength, sizeof(pDst->TP_UD_Byte) );				// 转换到TP-DU 
		nDstLength = tmp; 
	} 
 
	nHandleBytes += nLength;		// 指针后移 
 
	// 返回目标字符串长度 
	return nDstLength; 
} 
 
// 
// 字节数据转换为可打印字符串 
// 如:{0xC8, 0x32, 0x9B, 0xFD, 0x0E, 0x01} --> "C8329BFD0E01"  
// 输入: pSrc - 源数据指针 
//       nSrcLength - 源数据长度 
// 输出: szDst - 目标字符串指针 
// 返回: 目标字符串长度 
// 
int CHwMobile::gsmBytes2String(const BYTE *pSrc, char *szDst, int nSrcLength, int nDstSize) 
{ 
	const char tab[]="0123456789ABCDEF";	// 0x0-0xf的字符查找表 
	char *pDstTail = (char *)(szDst + nDstSize); 
 
	for (int i = 0; i < nSrcLength; i++) 
	{ 
		*szDst++ = tab[*pSrc >> 4];		// 输出高4位 
		if ( (char*)szDst >= pDstTail ) break; 
		*szDst++ = tab[*pSrc & 0x0f];	// 输出低4位 
		if ( (char*)szDst >= pDstTail ) break; 
		pSrc++; 
	} 
 
	// 输出字符串加个结束符 
	*szDst = '\0'; 
 
	// 返回目标字符串长度 
	return (nSrcLength * 2); 
} 
 
// 
// 正常顺序的字符串转换为两两颠倒的字符串,若长度为奇数,补'F'凑成偶数 
// 如:"8613851872468" --> "683158812764F8" 
// 输入: pSrc - 源字符串指针 
//       nSrcLength - 源字符串长度 
// 输出: szDst - 目标字符串指针 
// 返回: 目标字符串长度 
// 
int CHwMobile::gsmInvertNumbers(const char *pSrc, char *szDst, int nSrcLength, int nDstSize) 
{ 
	int nDstLength=0;	// 目标字符串长度 
	char ch;			// 用于保存一个字符 
	char *pDstTail = (char *)(szDst + nDstSize); 
 
	// 复制串长度 
	nDstLength = nSrcLength; 
 
	// 两两颠倒 
	for(int i=0; i= pDstTail ) break; 
		*szDst++ = ch;		// 复制先出现的字符 
		if ( (char*)szDst >= pDstTail ) break; 
	} 
 
	// 源串长度是奇数吗? 
	if(nSrcLength & 1) 
	{ 
		*(szDst-2) = 'F';	// 补'F' 
		nDstLength++;		// 目标串长度加1 
	} 
 
	// 输出字符串加个结束符 
	*szDst = '\0'; 
 
	// 返回目标字符串长度 
	return nDstLength; 
} 
 
// 
// 两两颠倒的字符串转换为正常顺序的字符串 
// 如:"683158812764F8" --> "8613851872468" 
// 输入: pSrc - 源字符串指针 
//       nSrcLength - 源字符串长度 
// 输出: szDst - 目标字符串指针 
// 返回: 目标字符串长度 
// 
int CHwMobile::gsmSerializeNumbers(const char *pSrc, char *szDst, int nSrcLength, int nDstSize) 
{ 
	int nDstLength=0;	// 目标字符串长度 
	char ch;			// 用于保存一个字符 
	char *pDstTail = (char *)(szDst + nDstSize); 
 
	// 复制串长度 
	nDstLength = nSrcLength; 
 
	// 两两颠倒 
	for(int i=0; i= pDstTail ) break; 
		*szDst++ = ch;		// 复制先出现的字符 
		if ( (char*)szDst >= pDstTail ) break; 
	} 
 
	// 最后的字符是'F'吗? 
	if(*(szDst-1) == 'F') 
	{ 
		szDst--; 
		nDstLength--;		// 目标字符串长度减1 
	} 
 
	// 输出字符串加个结束符 
	*szDst = '\0'; 
 
	// 返回目标字符串长度 
	return nDstLength; 
} 
 
// 
// 7bit编码 
// 输入: pSrc - 源字符串指针 
//       nSrcLength - 源字符串长度 
// 输出: szDst - 目标编码串指针 
// 返回: 目标编码串长度 
// 
int CHwMobile::gsmEncode7bit(const char *pSrc, BYTE *szDst, int nSrcLength, int nDstSize) 
{ 
	int nSrc=0;		// 源字符串的计数值 
	int nDst=0;		// 目标编码串的计数值 
	int nChar=0;	// 当前正在处理的组内字符字节的序号,范围是0-7 
	BYTE nLeft=0;	// 上一字节残余的数据 
	char *pDstTail = (char *)(szDst + nDstSize); 
 
	// 计数值初始化 
	nSrc = 0; 
	nDst = 0; 
 
	// 将源串每8个字节分为一组,压缩成7个字节 
	// 循环该处理过程,直至源串被处理完 
	// 如果分组不到8字节,也能正确处理 
	while (nSrc < nSrcLength) 
	{ 
		// 取源字符串的计数值的最低3位 
		nChar = nSrc & 7; 
 
		// 处理源串的每个字节 
		if(nChar == 0) 
		{ 
			// 组内第一个字节,只是保存起来,待处理下一个字节时使用 
			nLeft = *pSrc; 
		} 
		else 
		{ 
			// 组内其它字节,将其右边部分与残余数据相加,得到一个目标编码字节 
			*szDst = (*pSrc << (8-nChar)) | nLeft; 
 
			// 将该字节剩下的左边部分,作为残余数据保存起来 
			nLeft = *pSrc >> nChar; 
 
			// 修改目标串的指针和计数值 
			szDst++; 
			if ( (char*)szDst >= pDstTail ) break; 
			nDst++; 
		} 
 
		// 修改源串的指针和计数值 
		pSrc++; 
		nSrc++; 
	} 
 
	// 返回目标串长度 
	return nDst; 
} 
 
// 7bit解码 
// 输入: pSrc - 源编码串指针 
//       nSrcLength - 源编码串长度 
// 输出: szDst - 目标字符串指针 
// 返回: 目标字符串长度 
int CHwMobile::gsmDecode7bit(const BYTE* pSrc, char* szDst, int nSrcLength, int nDstSize) 
{ 
	int nSrc=0;		// 源字符串的计数值 
	int nDst=0;		// 目标解码串的计数值 
	int nByte=0;	// 当前正在处理的组内字节的序号,范围是0-6 
	BYTE nLeft=0;	// 上一字节残余的数据 
	char *pDstTail = (char *)(szDst + nDstSize); 
 
	// 计数值初始化 
	nSrc = 0; 
	nDst = 0; 
	 
	// 组内字节序号和残余数据初始化 
	nByte = 0; 
	nLeft = 0; 
 
	// 将源数据每7个字节分为一组,解压缩成8个字节 
	// 循环该处理过程,直至源数据被处理完 
	// 如果分组不到7字节,也能正确处理 
	while(nSrc> (7-nByte); 
 
		// 修改目标串的指针和计数值 
		szDst++; 
		if ( (char*)szDst >= pDstTail ) break; 
		nDst++; 
 
		// 修改字节计数值 
		nByte++; 
 
		// 到了一组的最后一个字节 
		if(nByte == 7) 
		{ 
			// 额外得到一个目标解码字节 
			*szDst = nLeft; 
 
			// 修改目标串的指针和计数值 
			szDst++; 
			if ( (char*)szDst >= pDstTail ) break; 
			nDst++; 
 
			// 组内字节序号和残余数据初始化 
			nByte = 0; 
			nLeft = 0; 
		} 
 
		// 修改源串的指针和计数值 
		pSrc++; 
		nSrc++; 
	} 
 
	// 输出字符串加个结束符 
	*szDst = '\0'; 
 
	// 返回目标串长度 
	return nDst; 
} 
 
// 
// UCS2编码 
// 输入: pSrc - 源字符串指针 
//       nSrcLength - 源字符串长度 
// 输出: szDst - 目标编码串指针 
// 返回: 目标编码串长度 
// 
int CHwMobile::gsmEncodeUcs2(const char *pSrcByte, BYTE *szDst, int nSrcLength, int nDstSize, WCHAR *wzSrc/*=NULL*/ ) 
{ 
	int nDstLength=0;		// UNICODE宽字符数目 
	WCHAR wchar[1024] = {0};	// UNICODE串缓冲区 
	char *pDstTail = (char *)(szDst + nDstSize); 
 
	// 字符串-->UNICODE串 
	if ( wzSrc ) 
		nDstLength = (int)wcslen ( wzSrc ); 
	if ( nDstLength <= 0 ) 
	{ 
		nDstLength = MultiByteToWideChar(CP_ACP, 0, pSrcByte, nSrcLength, wchar, 1024); 
		wzSrc = wchar; 
	} 
 
	// 高低字节对调,输出 
	for(int i=0; i> 8;		// 先输出高位字节 
		if ( (char*)szDst >= pDstTail ) break; 
		*szDst++ = wzSrc[i] & 0xff;		// 后输出低位字节 
		if ( (char*)szDst >= pDstTail ) break; 
	} 
 
	// 返回目标编码串长度 
	return nDstLength * 2; 
} 
 
// UCS2解码 
// 输入: pSrc - 源编码串指针 
//       nSrcLength -  源编码串长度 
// 输出: szDst -  目标字符串指针 
// 返回: 目标字符串长度 
int CHwMobile::gsmDecodeUcs2( 
		const BYTE* pSrc, 
		char* szDst, 
		int nSrcLength, 
		int nDstSize, 
		WCHAR* wzSMSContent_Wide/*=NULL*/, 
		int nWideSize/*=0*/ 
	) 
{ 
	WCHAR wchar[1024] = {0};	// UNICODE串缓冲区 
	ASSERT ( szDst ); 
	memset ( szDst, 0, nDstSize ); 
	// 源数据长度必须是2的倍数 
	int nModLength = (nSrcLength%2); 
	int nValidSrcLength = nSrcLength + nModLength; 
	nValidSrcLength = MIN(nValidSrcLength,1024*2); 
	BYTE *pSrcValid = new BYTE[nValidSrcLength]; 
	if ( !pSrcValid ) return -1; 
	memset ( pSrcValid, 0, nValidSrcLength ); 
	memcpy ( pSrcValid + nModLength, pSrc, nSrcLength ); 
 
	// 高低字节对调,拼成UNICODE 
	for ( int i=0; i 0 ) 
	{ 
		wcsncpy ( wzSMSContent_Wide, wchar, nWideSize ); 
	} 
 
	// UNICODE串-->字符串,因为不知道源字符串到底是GB还是Big5,所以用两种方式分别给于解码,解码后的结果再来取舍 
	// 取面包含问号少的那个 
	char szDestTemp1[4096] = {0}, szDestTemp2[4096] = {0}; 
	int nDstLength1 = WideCharToMultiByte ( CHARCODEPAGE_GB, 0, wchar, nValidSrcLength/2, szDestTemp1, 4096, NULL, NULL); 
	int nQuestionCount1 = CountCharNumber ( szDestTemp1, '?' ); 
 
	int nDstLength2 = WideCharToMultiByte ( CHARCODEPAGE_BIG5, 0, wchar, nValidSrcLength/2, szDestTemp2, 4096, NULL, NULL); 
	int nQuestionCount2 = CountCharNumber ( szDestTemp2, '?' ); 
 
	char *szDestTemp = NULL; 
	if ( nQuestionCount1 == nQuestionCount2 ) 
	{ 
		// 随机取一个算了 
		if ( GetTickCount()%2 ) 
			szDestTemp = szDestTemp1; 
		else 
			szDestTemp = szDestTemp2; 
	} 
	else 
	{ 
		szDestTemp = ( (nQuestionCount1 < nQuestionCount2) ? szDestTemp1 : szDestTemp2 ); 
	} 
 
	return hwSnprintfA ( szDst, nDstSize/sizeof(char), "%s", szDestTemp ); 
} 
 
// 
// 8bit编码 
// 输入: pSrc - 源字符串指针 
//       nSrcLength - 源字符串长度 
// 输出: szDst - 目标编码串指针 
// 返回: 目标编码串长度 
// 
int CHwMobile::gsmEncode8bit(const char *pSrc, BYTE *szDst, int nSrcLength, int nDstSize) 
{ 
	char *pDstTail = (char *)(szDst + nDstSize); 
	// 简单复制 
	memcpy(szDst, pSrc, nSrcLength); 
 
	return nSrcLength; 
} 
 
// 
// 8bit解码 
// 输入: pSrc - 源编码串指针 
//       nSrcLength -  源编码串长度 
// 输出: szDst -  目标字符串指针 
// 返回: 目标字符串长度 
// 
int CHwMobile::gsmDecode8bit(const BYTE* pSrc, char* szDst, int nSrcLength, int nDstSize) 
{ 
	char *pDstTail = (char *)(szDst + nDstSize); 
	// 简单复制 
	memcpy(szDst, pSrc, nSrcLength); 
 
	// 输出字符串加个结束符 
	*szDst = '\0'; 
 
	return nSrcLength; 
} 
 
// 
// 可打印字符串转换为字节数据 
// 如:"C8329BFD0E01" --> {0xC8, 0x32, 0x9B, 0xFD, 0x0E, 0x01} 
// 输入: pSrc - 源字符串指针 
//       nSrcLength - 源字符串长度 
// 输出: szDst - 目标数据指针 
// 返回: 目标数据长度 
// 
int CHwMobile::gsmString2Bytes(const char *pSrc, BYTE *szDst, int nSrcLength, int nDstSize) 
{ 
	char *pDstTail = (char *)(szDst + nDstSize); 
	for (int i = 0; i < nSrcLength; i += 2) 
	{ 
		// 输出高4位 
		if ((*pSrc >= '0') && (*pSrc <= '9')) 
		{ 
			*szDst = (*pSrc - '0') << 4; 
		} 
		else 
		{ 
			*szDst = (*pSrc - 'A' + 10) << 4; 
		} 
 
		pSrc++; 
 
		// 输出低4位 
		if ((*pSrc>='0') && (*pSrc<='9')) 
		{ 
			*szDst |= *pSrc - '0'; 
		} 
		else 
		{ 
			*szDst |= *pSrc - 'A' + 10; 
		} 
 
		pSrc++; 
		szDst++; 
		if ( (char*)szDst >= pDstTail ) break; 
	} 
 
	// 返回目标数据长度 
	return (nSrcLength / 2); 
} 
 
BOOL CHwMobile::Init () 
{ 
	if ( m_nComNO < 1 || m_nBaudRate < 1 ) 
		return FALSE; 
 
//	HwDbgLog ( L_DEBUG, "从 [COM%d] 来打开手机", m_nComNO ); 
	// 打开串口 
	if ( !OpenCOM ( m_nComNO, m_nBaudRate, TRUE ) ) 
	{ 
		if ( m_nInitOK ) 
		{ 
			Log ( L_WARNING, _T("Open mobile module interface [COM%d] failed"), m_nComNO ); 
		} 
		m_nInitOK = FALSE; 
		return FALSE; 
	} 
	// 初始化手机模块 
	if ( !gsmInit() ) 
	{ 
		if ( m_nInitOK ) 
		{ 
			Log ( L_WARNING, _T("Initialize mobile module [COM%d] failed"), m_nComNO ); 
		} 
		m_nInitOK = FALSE; 
		return FALSE; 
	} 
 
	m_nInitOK = TRUE; 
	return TRUE; 
} 
 
// 
// 初始化GSM状态 
// 
BOOL CHwMobile::gsmInit() 
{ 
	// 测试 GSM-MODEM 的存在性 
	if ( !QueryExistByRWCmd () ) 
		return FALSE; 
 
	// 关闭回显功能 
	if ( Write ( "ATE0\r" ) < 1 ) return FALSE; 
	ReadResponse ( "OK" ); 
 
	// 开启来电显示 
	if ( Write ( "AT+CLIP=1\r" ) < 1 ) return FALSE; 
	ReadResponse ( "OK" ); 
 
	// 设置短信为PDU模式 
	if ( Write("AT+CMGF=0\r" ) < 1 ) return FALSE; 
	if ( !ReadResponse ( "OK" ) ) 
		return FALSE; 
 
	// 设置短信通知方式为“直接通知TE” 
	// mode : 2 - 通知TE。在数据线被占用的情况下,先缓冲起来,待数据线空闲,再行通知。 
	// mt : 2 - 对于class 2,储存到SIM卡,并且向TE发出通知;对于其它class,直接将消息转发到 TE  
	if ( Write("AT+CNMI=2,2\r" ) < 1 ) return FALSE; 
	if ( !ReadResponse ( "OK" ) ) 
	{ 
		Log ( L_WARNING | L_OUT_UI, _T("Maybe none SIM card") ); 
		return FALSE; 
	} 
 
	// 设置手机使用的字符集为“UCS2” 
	if ( Write ( "AT+CSCS=\"UCS2\"\r" ) < 1 ) 
		return FALSE; 
	if ( !ReadResponse ( "OK\r\n" ) ) 
		return FALSE; 
 
	ClearComm ( TRUE ); 
	return TRUE; 
} 
 
// 
// 读取短信中心号码 
// 
BOOL CHwMobile::GetSMSCNO () 
{ 
	if ( m_csSMSC.GetLength() > MIN_MOBILENO_LENGTH ) 
		return TRUE; 
 
	if ( !m_nInitOK || !m_handleCOM || m_handleCOM == INVALID_HANDLE_VALUE ) 
		return FALSE; 
	if ( Write ( "AT+CSCA?\r" ) < 1 ) 
		return FALSE; 
	CString csAns; 
	char szAns[MAX_COM_BUFSIZE] = {0}; 
	if ( !ReadResponse ( "OK", TRUE, szAns, MAX_COM_BUFSIZE ) ) 
		return FALSE; 
	csAns = GetCompatibleString ( szAns, FALSE ); 
	LPCTSTR lpszFindStr = _T("+CSCA: \""); 
	int nFindPos = csAns.Find ( lpszFindStr, 0 ); 
	if ( nFindPos < 0 ) return FALSE; 
	nFindPos += lstrlen ( lpszFindStr ); 
	csAns = csAns.Mid ( nFindPos ); 
	nFindPos = csAns.Find ( _T("\""), 0 ); 
	if ( nFindPos < 0 ) return FALSE; 
	csAns = csAns.Left ( nFindPos ); 
 
	// UCS2解码 
	char szTempBuf[MAX_COM_BUFSIZE] = {0}; 
	CMultiByteString MultiByteString_Ans(csAns); 
	int nRet = gsmString2Bytes ( MultiByteString_Ans.GetBuffer(), (BYTE*)szTempBuf, MultiByteString_Ans.GetLength(), sizeof(szTempBuf) );	// 格式转换 
	char szSMSC[PHONENO_LENGTH] = {0}; 
	gsmDecodeUcs2 ( (BYTE*)szTempBuf, szSMSC, nRet, PHONENO_LENGTH );		// 转换到TP-DU 
	m_csSMSC = GetCompatibleString ( szSMSC, FALSE ); 
	Log ( L_VERBOSE | L_OUT_UI, _T("Get SMSC : %s"), m_csSMSC ); 
 
	if ( m_Proc_SaveSMSCFromGSM ) 
	{ 
		m_Proc_SaveSMSCFromGSM ( m_csSMSC ); 
	} 
	return TRUE; 
} 
 
// 
// 用命令来从手机中获取一些信息 
// 
BOOL CHwMobile::DemandMobileInfo ( char *szCmd, OUT CString &csAns ) 
{ 
	csAns.Empty (); 
	ClearComm ( TRUE ); ClearComm ( FALSE ); 
	if ( Write ( szCmd ) < 1 ) 
		return FALSE; 
	char szAns[MAX_COM_BUFSIZE] = {0}; 
	if ( !ReadResponse ( "OK", TRUE, szAns, MAX_COM_BUFSIZE ) ) 
		return FALSE; 
	csAns = GetCompatibleString(szAns,FALSE); 
	csAns.ReleaseBuffer (); 
	csAns.Replace ( _T("OK"), _T("") ); 
	csAns.Remove ( _T('\r') ); 
	csAns.Remove ( _T('\n') ); 
	return TRUE; 
} 
 
// 
// 从串口中读回应代码, 如果读到的回应代码里能找到字符串 szResponse 就返回“TRUE” 
// 否则返回“FALSE” 
// 
BOOL CHwMobile::ReadResponse ( char* szResponse, BOOL bQuick/*=TRUE*/, char *szAns/*=NULL*/, int nSize/*=0*/ ) 
{ 
	ASSERT ( szResponse ); 
	int nLen = (int)strlen(szResponse); 
	ASSERT ( nLen >= 2 ); 
	if ( !WaitForDataToRead ( nLen, bQuick ? WAIT_GSM_DATA_TIME_QUICK : WAIT_GSM_DATA_TIME_SLOW ) ) 
		return FALSE; 
 
	char ans[MAX_COM_BUFSIZE+1] = {0};		// 应答串 
	int nReadLen = Read ( ans, MAX_COM_BUFSIZE ); 
	BOOL bRet = FALSE; 
 
	if ( strstr ( ans, szResponse ) ) 
		bRet = TRUE; 
 
	if ( nReadLen > 0 && szAns && nSize > 0 ) 
	{ 
		int nLen = MIN ( nReadLen,nSize-1 ); 
		memcpy ( szAns, ans, nLen ); 
		szAns[nLen] = '\0'; 
	} 
 
	return bRet; 
} 
 
/******************************************************************************** 
* Function Type	:	protected 
* Parameter		:	lpszData	-	要写的字符串 
* Return Value	:	>=0			-	写出去的字节数 
*					-1			-	COM got way 
* Description	:	往串口写数据 
*********************************************************************************/ 
int CHwMobile::Write(char *szData) 
{ 
	if ( !szData || strlen(szData) < 1 ) 
		return 0; 
	int nLen = (int)strlen ( szData ); 
#ifdef _DEBUG 
	if ( strcmp ( szData, "AT\r" ) != 0 ) 
	{ 
//		TRACE ( _T("手机模块发送命令 [ %d bytes ]: %s\n"), nLen, GetCompatibleString(szData,FALSE) ); 
	} 
#endif 
	int nRet = 0; 
 
	char szOneSendPkt[32] = {0}; 
	int nSentBytes = 0, nRemainBytes = nLen; 
	while ( nRemainBytes > 0 ) 
	{ 
		int nMinLength = MIN ( sizeof(szOneSendPkt), nRemainBytes ); 
		memcpy ( szOneSendPkt, szData+nSentBytes, nMinLength ); 
		int nRetTemp = CHwCOM::Write ( szOneSendPkt, nMinLength ); 
		if ( nRetTemp != nMinLength ) 
		{ 
			nRet = nRetTemp; 
			break; 
		} 
		nSentBytes += nMinLength; 
		nRemainBytes -= nMinLength; 
		nRet = nSentBytes; 
		if ( nRemainBytes > 0 ) Sleep ( 10 ); 
	} 
 
	return HandleCOMRW ( nRet ); 
} 
 
/******************************************************************************** 
* Function Type	:	protected 
* Parameter		:	data		-	读数据缓冲 
*					size		-	要读的字节数 
* Return Value	:	>=0			-	读到的字节数 
*					-1			-	COM got way 
* Description	:	从串口中读数据 
*********************************************************************************/ 
int CHwMobile::Read(char *data, int size) 
{ 
	int nRet = HandleCOMRW ( CHwCOM::Read ( data, size ) ); 
	if ( nRet <= 0 ) 
	{ 
		return nRet; 
	} 
//	TRACE ( "Read data from GSM module : %s\n", data ); 
 
	// 正在读的时候收到了短信 
	char *p = strstr ( data, "+CMT:" ); 
	if ( p ) 
	{ 
		int nTempBufSize = nRet + 1; 
		char *pHeadData = new char[nTempBufSize+1]; 
		char *pTailData = new char[nTempBufSize+1]; 
		if ( pHeadData && pTailData ) 
		{ 
			memset ( pHeadData, 0, nTempBufSize+1 ); 
			memset ( pTailData, 0, nTempBufSize+1 ); 
			int nHeadLen = (int)((ULONGLONG)p-(ULONGLONG)data); 
			memcpy ( pHeadData, data, nHeadLen );	// 将 "+CMT:" 之前的数据先复制下来 
			memcpy ( pTailData, p, MIN(nTempBufSize,nRet-nHeadLen) ); 
			// 将从 "+CMT:" 开始后面的数据做为新短信来处理,处理剩下的数据会保存到 pTailData 中 
			gsmReadMessageContent ( "+CMT:", pTailData, nTempBufSize ); 
			 
			// 将 "+CMT:" 之前的数据和处理新短信后剩下的数据合起来就是本次读到的数据 
			memset ( data, 0, size ); 
			nRet = 0; 
			int nLen = MIN(nHeadLen,size); 
			memcpy ( data, pHeadData, nLen ); 
			data += nLen; 
			nRet += nLen; 
			int nTailLen = (int)strlen ( pTailData ); 
			nLen = MIN(nTailLen,size-nLen); 
			memcpy ( data, pTailData, nLen ); 
			nRet += nLen; 
		} 
		else 
		{ 
			memset ( data, 0, size ); 
			nRet = 0; 
		} 
 
		if ( pHeadData ) delete[] pHeadData; 
		if ( pTailData ) delete[] pTailData; 
	} 
 
	// 正在读的时候有新来电 
	nRet = HandleNewIncoming ( data, nRet ); 
 
	return nRet; 
} 
 
int CHwMobile::HandleCOMRW(int nRet) 
{ 
	if ( nRet < 0 ) 
	{ 
		CloseCOM (); 
		if ( nRet == -1 ) 
		{ 
			Log ( L_WARNING | L_OUT_UI, _T("Device [COM%d] {got way}"), m_nComNO ); 
			m_csCurPhoneBookName.Empty (); 
			m_bInitMobileLastRes = -1; 
		} 
		else if ( nRet == -2 ) 
		{ 
			Log ( L_WARNING | L_OUT_UI, _T("SMS Module be removed") ); 
			m_csCurPhoneBookName.Empty (); 
			m_bInitMobileLastRes = -1; 
		} 
		// 将短信中心号码清除掉,等手机再次接上来的时候可以重新获取中心号码 
		// 以防止用户更换不同提供商的sim卡而发不了短信。 
		m_csSMSC = _T(""); 
	} 
	return nRet; 
} 
 
// 
// 发送短消息,仅发送命令 
// 输入: pSrc - 源PDU参数指针 
// return : 发送结果 
// 
int CHwMobile::gsmSendMessage ( SM_PARAM *pSrc ) 
{ 
	int nPduLength=0;		// PDU串长度 
	int nSmscLength=0;		// SMSC串长度 
	int nLength=0;			// 串口收到的数据长度 
	char cmd[1024]={0};		// 命令串 
	char pdu[4096]={0};		// PDU串 
	char ans[1024]={0};		// 应答串 
 
	nPduLength = gsmEncodePdu ( pSrc, pdu, sizeof(pdu) );	// 根据PDU参数,编码PDU串 
	strcat(pdu, "\x01a");		// 以Ctrl-Z结束 
 
	gsmString2Bytes ( pdu, (BYTE *)&nSmscLength, 2, sizeof(nSmscLength) );	// 取PDU串中的SMSC信息长度 
	nSmscLength++;		// 加上长度字节本身 
 
	// 命令中的长度,不包括SMSC信息长度,以数据字节计 
	sprintf(cmd, "AT+CMGS=%d\r", nPduLength / 2 - nSmscLength);	// 生成命令 
 
	// 先输出命令串 
//	Log ( L_VERBOSE, "SMS Module Send Command : %s\n", GetCompatibleString(cmd,FALSE) ); 
	if ( Write ( cmd ) < 1 ) 
		return GSM_ERR; 
 
	// 根据能否找到"\r\n> "决定成功与否 
	// 得到肯定回答 
	if ( !ReadResponse ( "\r\n> ", FALSE ) ) 
		return GSM_ERR; 
 
	// 就继续输出PDU串 
//	Log ( L_VERBOSE, "SMS Module Send Command : %s\n", GetCompatibleString(pdu,FALSE) ); 
	if ( Write ( pdu ) < 1 ) 
		return GSM_ERR; 
 
	char szAns[MAX_COM_BUFSIZE+1] = {0}; 
	if ( ReadResponse ( "OK\r\n", FALSE, szAns, MAX_COM_BUFSIZE ) ) 
		return GSM_OK; 
	if ( strstr ( szAns, "+CMS ERROR" ) ) 
		return GSM_ERR; 
 
	return GSM_UNKNOWN;	// 应该再次发送 
} 
 
// 
// 发送一条短信 
// 
BOOL CHwMobile::SendOneSMSPkt ( SM_PARAM *pSMSend ) 
{ 
	ASSERT ( pSMSend ); 
	if ( strlen(pSMSend->TP_UD_Byte) < 1 ) 
		return FALSE; 
 
	int nRes = GSM_UNKNOWN; 
	HwDbgLog ( L_DEBUG, _T("要发送 %d 字节的短信"), strlen(pSMSend->TP_UD_Byte) ); 
	// 最多重试 3 次 
	int i=0; 
	for ( ; i<3; i++ ) 
	{ 
		nRes = gsmSendMessage ( pSMSend ); 
		if ( nRes == GSM_UNKNOWN ) 
		{ 
			Sleep ( 100 );	// 休息一下再试 
		} 
		else 
		{ 
			break; 
		} 
	} 
 
	TRACE ( _T("发送短信给 [ %s ] - %d 字节 [ %s ] 完成\n"), pSMSend->TPA, strlen(pSMSend->TP_UD_Byte), pSMSend->TP_UD_Byte ); 
 
	BOOL bRet = FALSE; 
	if ( nRes==GSM_OK ) 
	{ 
		HwDbgLog ( L_DEBUG, _T("Retry %d times"), i ); 
		SMSBeep ( FALSE ); 
		bRet = TRUE; 
	}  
 
	Log ( bRet?L_VERBOSE:L_WARNING, _T("Send SMS to [%s] %s, SMSC : %s"), GetCompatibleString(pSMSend->TPA,FALSE), 
		(bRet?_T("successfully"):_T("failed")), GetCompatibleString(pSMSend->SCA,FALSE) ); 
	return bRet; 
} 
 
// 
// 处理新来电信息, 处理完以后剩下的数据由 data 返回,返回值为剩下的字节数 
// 
int CHwMobile::HandleNewIncoming(char *data, int size) 
{ 
	if ( size < 20 ) return size; 
	if ( !data ) return 0; 
	CString csData = GetCompatibleString(data,FALSE); 
	CString csRingFlag = _T("RING\r\n\r\n+CLIP: "); 
	while ( TRUE ) 
	{ 
		int nEndPos_Left = csData.Find ( csRingFlag, 0 ); 
		int nDeletePos = nEndPos_Left; 
		if ( nEndPos_Left < 0 ) break; 
		nEndPos_Left += csRingFlag.GetLength(); 
		int nEndPos_Right = csData.Find ( _T("\r\n"), nEndPos_Left ); 
		if ( nEndPos_Right < 0 ) nEndPos_Right = csData.GetLength()-1; 
		if ( nEndPos_Right <= nEndPos_Left ) break; 
		else nEndPos_Right += 2; 
		CString csOneRingInfo = csData.Mid ( nEndPos_Left, nEndPos_Right-nEndPos_Left ); 
		csData.Delete ( nDeletePos, nEndPos_Right-nDeletePos ); 
 
		// 取到来电显示号码,交给外部模块处理 
		int nCallerIDEndPos = csOneRingInfo.Find ( _T("\""), 1 ); 
		if ( nCallerIDEndPos < 0 ) nCallerIDEndPos = csOneRingInfo.GetLength() - 1; 
		static CString csCallerID_Last; 
		static time_t tLastTime = 0; 
		CString csCallerID = csOneRingInfo.Mid ( 1, nCallerIDEndPos-1 ); 
		if ( csCallerID_Last != csCallerID || difftime(time(NULL),tLastTime) > 60 ) 
		{ 
			if ( m_Proc_IncomingFromGSM ) m_Proc_IncomingFromGSM ( csCallerID ); 
			csCallerID_Last = csCallerID; 
			tLastTime = time(NULL); 
		} 
	} 
	memset ( data, 0, size ); 
	CMultiByteString ( csData, STRING_IS_SOFTCODE, data, size-1 ); 
	return (int)strlen(data); 
} 
 
// 
// 读取短信内容,读到的短信将在函数 HandleRecvSMS() 中处理,命令已经发送 
// 过了,或者不需要发送读取短信的命令,只是在等待接收。 
// 如果在读取短信的时候收到“RING”命令说明有来电,进入来电处理模块 
// 
BOOL CHwMobile::gsmReadMessageContent ( const char *szSMSFlag, char *szSupplement/*=NULL*/, const int nSupplementSize/*=0*/ ) 
{ 
	ASSERT ( szSMSFlag ); 
	// 计算 SMS 缓冲尺寸 
	int nSMSSize = MAX_COM_BUFSIZE; 
	int nSupplementLen = 0; 
	if ( szSupplement ) 
	{ 
		nSupplementLen = (int)strlen ( szSupplement ); 
	} 
	if ( nSMSSize <= nSupplementLen ) 
		nSMSSize = nSupplementLen+MAX_COM_BUFSIZE; 
 
	// 根据计算的尺寸,从 CString 中取内存 
	CString csSMS; 
	char *pSMS = new char[nSMSSize+1]; 
	if ( !pSMS ) return FALSE; 
	memset ( pSMS, 0, nSMSSize+1 ); 
 
	int nSMSDataLen = 0; 
	if ( szSupplement ) 
	{ 
		strncpy ( pSMS, szSupplement, nSMSSize ); 
		ASSERT ( nSupplementLen < nSMSSize ); 
		nSMSDataLen += nSupplementLen; 
	} 
 
	while ( nSupplementLen > 0 || GetCommInputBuffLen () > (int)strlen ( szSMSFlag ) ) 
	{ 
		int nRet = CHwCOM::Read ( pSMS+nSMSDataLen, MAX_COM_BUFSIZE-nSMSDataLen );		 
		if ( nSupplementLen > 0 || nRet > 0 ) 
		{ 
			nSMSDataLen += nRet; 
			nSMSDataLen = HandleNewIncoming ( pSMS, nSMSDataLen ); 
//			Log ( L_DEBUG, "Received SMS %d bytes data :\r\n%s", nSMSDataLen, GetCompatibleString(pSMS,FALSE) ); 
			int nHandleCount = gsmParseMessage ( szSMSFlag, pSMS, nSMSDataLen ); 
			if ( nHandleCount > 0 ) 
			{ 
				ASSERT ( nHandleCount < nSMSSize ); 
				int nMoveLen = nSMSDataLen - nHandleCount; 
				ASSERT ( nMoveLen <= (int)(nSMSSize-nHandleCount) ); 
				memmove ( pSMS, pSMS+nHandleCount, nMoveLen ); 
				pSMS[nMoveLen] = '\0'; 
				nSMSDataLen = nMoveLen; 
			} 
		} 
		else 
		{ 
			break; 
		} 
		nSupplementLen = 0; 
	} 
 
	// 把处理后剩下的数据拷贝给调用者 
	if ( szSupplement && nSupplementSize > 0 ) 
	{ 
		strncpy ( szSupplement, pSMS, nSupplementSize ); 
	} 
 
	for ( int i=0; i (int)strlen(szSMSFlag) ) 
	{ 
		SM_PARAM SMRecv = {0}; 
		int nRet = gsmParseOneMessage ( szSMSFlag, szRecvedData+nHandleBytes, nRecvedDataLen-nHandleBytes, &SMRecv ); 
		if ( strlen ( SMRecv.TP_UD_Byte ) > 0 ) 
		{ 
			HandleRecvSMS ( &SMRecv ); 
		} 
 
		if ( nRet > 0 ) 
		{ 
			nHandleBytes += nRet; 
		} 
		else 
		{ 
			break; 
		} 
	} 
 
	return nHandleBytes; 
} 
 
// 
// 分析一条短信,返回处理了多少个字节 
// 
int CHwMobile::gsmParseOneMessage ( IN const char *szSMSFlag, IN char *szRecvedData, int nRecvedDataLen, OUT SM_PARAM *pSMRecv ) 
{ 
	ASSERT ( szSMSFlag && szRecvedData ); 
	memset ( pSMRecv, 0, sizeof(SM_PARAM) ); 
	if ( nRecvedDataLen < 4 ) return 0; 
	char *ptr = szRecvedData; 
	int nHandleCount = 0; 
 
	if ( (ptr = strstr ( ptr, szSMSFlag )) == NULL ) 
		return 0; 
	ptr += strlen ( szSMSFlag );				// 跳过命令标志, 定位到序号 
	if ( ptr - szRecvedData > nRecvedDataLen ) 
		return 0; 
 
	int nIndex = 0; 
	sscanf ( ptr, "%d", &nIndex );	// 读取序号 
	pSMRecv->index = nIndex; 
	// 找下一行 
	if ( (ptr = strstr ( ptr, "\r\n")) == NULL ) 
		return 0; 
 
	// 跳过"\r\n", 定位到PDU 
	ptr += 2; 
	if ( ptr - szRecvedData > nRecvedDataLen ) 
		return 0; 
	nHandleCount += (int)( (ULONGLONG)ptr-(ULONGLONG)szRecvedData ); 
 
	// PDU串解码 
	int nPduBytes = nRecvedDataLen-nHandleCount; 
	int nRet = gsmDecodePdu ( ptr, nPduBytes, pSMRecv ); 
	if ( nRet == -1 )		// 数据不够 
		return 0; 
	else if ( nRet == -2 || strlen(pSMRecv->TP_UD_Byte) < 1 )	// 非法的数据 
	{ 
		CString csIllegal = GetCompatibleString(ptr,FALSE); 
		csIllegal = csIllegal.Left ( nPduBytes ); 
		Log ( L_WARNING, _T("SMS module received illegal data : %s"), csIllegal ); 
	} 
	ASSERT ( nPduBytes < nRecvedDataLen-nHandleCount ); 
	nHandleCount += nPduBytes; 
 
	return nHandleCount; 
} 
 
BOOL CHwMobile::HandleRecvSMS(SM_PARAM *pSMRecv) 
{ 
	ASSERT ( pSMRecv ); 
	// 收到的短信应该要删除,所以将它的序号添加到数组中 
	m_UIntAry_NeedDelSMS.Add ( pSMRecv->index ); 
	SMSBeep ( TRUE ); 
	return TRUE; 
} 
 
// 
// 将时间戳字符串转为标准的时间格式 
// 
char* CHwMobile::Convert_SCTS2Standard(char *szSCTS, char *szStandardTime, int nSize) 
{ 
	ASSERT ( szSCTS && strlen(szSCTS) >= 14 ); 
	ASSERT ( szStandardTime && nSize > 19 ); 
	char *pSrc = szSCTS; 
	char *pDst = szStandardTime; 
 
	for ( int i=0; i<6; i++ ) 
	{ 
		char *pConn = ( (i==0)?"20": ((i==3)?" ": ((i>3)?":":"-") ) ); 
		strcpy ( pDst, pConn ); 
		pDst += strlen(pConn); 
		memcpy ( pDst, pSrc, 2 ); 
		pSrc += 2; 
		pDst += 2; 
	} 
 
	return szStandardTime; 
} 
 
// 
// 将标准的时间格式转为时间戳字符串 
// 
char* CHwMobile::Convert_Standard2SCTS(char *szStandardTime, char *szSCTS, int nSize) 
{ 
	ASSERT ( szStandardTime && strlen(szStandardTime) == 19 ); 
	ASSERT ( szSCTS && nSize >= 16 ); 
	CString csSCTS = GetCompatibleString(szStandardTime,FALSE); 
	if ( csSCTS.GetLength() >= 2 ) 
		csSCTS.Delete ( 0, 2 ); 
	if ( csSCTS.GetLength() >= 1 ) 
		csSCTS.Delete ( 2, 1 ); 
	if ( csSCTS.GetLength() >= 1 ) 
		csSCTS.Delete ( 4, 1 ); 
	if ( csSCTS.GetLength() >= 1 ) 
		csSCTS.Delete ( 6, 1 ); 
	if ( csSCTS.GetLength() >= 1 ) 
		csSCTS.Delete ( 8, 1 ); 
	if ( csSCTS.GetLength() >= 1 ) 
		csSCTS.Delete ( 10, 1 ); 
	csSCTS += _T("00"); 
	strncpy ( szSCTS, CMultiByteString(csSCTS).GetBuffer(), nSize ); 
	return szSCTS; 
} 
 
BOOL CHwMobile::gsmDeleteSMS ( int nIndex ) 
{ 
	char szCmd[1024] = {0}; 
	hwSnprintfA ( szCmd, sizeof(szCmd)/sizeof(char), "AT+CMGD=%d\r", nIndex ); 
	if ( Write ( szCmd ) < 1 ) return FALSE; 
 
	if ( ReadResponse ( "OK\r\n" ) ) 
		return TRUE; 
	return FALSE; 
} 
 
// 
// 选择电话本 
// 
BOOL CHwMobile::gsmSelectPhoneBook ( LPCTSTR lpszPhoneBookName ) 
{ 
	ASSERT ( lpszPhoneBookName && lstrlen(lpszPhoneBookName) > 0 ); 
	if ( m_csCurPhoneBookName == lpszPhoneBookName ) 
		return TRUE; 
	HwDbgLog ( L_DEBUG, _T("选择电话本 [%s]"), lpszPhoneBookName ); 
	// 两次选择电话本的时间间隔必须大于 SELECT_PHONEBOOK_INTVERVAL 秒 
	static DWORD dwStartTime = GetTickCount(); 
	while ( !TimeIntervalArrived ( dwStartTime, SELECT_PHONEBOOK_INTVERVAL ) ) 
		Sleep ( 100 ); 
 
	// 选择电话本 
	char szCmd[1024] = {0}; 
	sprintf ( szCmd, "AT+CPBS=\"%s\"\r", CMultiByteString(lpszPhoneBookName).GetBuffer() ); 
	if ( Write ( szCmd ) < 1 ) 
		return FALSE; 
	if ( !ReadResponse ( "OK\r\n" ) ) 
		return FALSE; 
 
	m_csCurPhoneBookName = lpszPhoneBookName; 
	return TRUE; 
} 
 
// 
// 读一个电话本 
// “FD” 固定拨号电话本 
// “SM” SIM 卡电话本 
// “ON” 本机电话号码列表 
// “ME” 手机电话本 
// “LD” 最近已拨电话(SIM) 
// “MC” 最近来电未接电话本 
// “RC” 最近来电已接电话本 
// “DC” 最近拨号电话本 
// 
BOOL CHwMobile::gsmReadPhoneBook ( LPCTSTR lpszPhoneBookName, t_Ary_PhoneBook *pAry_PhoneBook) 
{ 
	if ( HANDLE_IS_VALID(m_hEvt_IsBusy) ) 
		::SetEvent ( m_hEvt_IsBusy ); 
	BOOL bRet = FALSE; 
	int nMaxRecNum = 0; 
	char szCmd[1024] = {0}; 
	int nStoreStartPos = 0; 
	int nStoreEndPos = 0; 
	int nMaxPhoneNOSize = 0;  
	int nMaxInfoSize = 0; 
	int nMaxRecSize = 0; 
	ASSERT ( pAry_PhoneBook ); 
	if ( !gsmSelectPhoneBook ( lpszPhoneBookName ) ) 
		goto finished; 
 
	if ( !gmsGetPhoneBookInfo ( 
		nStoreStartPos, 
		nStoreEndPos, 
		nMaxPhoneNOSize,  
		nMaxInfoSize, 
		nMaxRecSize ) ) 
		goto finished; 
 
	HwDbgLog ( L_DEBUG, _T(" [%s].nStoreEndPos = %d"), lpszPhoneBookName, nStoreEndPos ); 
	// 发送“读”当前选择电话本所有电话纪录的 AT 指令 
	hwSnprintfA ( szCmd, sizeof(szCmd)/sizeof(char), "AT+CPBR=%d,%d\r", nStoreStartPos, nStoreEndPos ); 
	if ( Write ( szCmd ) < 1 ) goto finished; 
 
	// 取回所有读到的电话纪录 
	nMaxRecNum = nStoreEndPos - nStoreStartPos + 1; 
	gsmGetAllPhoneBookRec ( nMaxRecSize, nMaxRecNum, lpszPhoneBookName, pAry_PhoneBook ); 
 
	bRet = TRUE; 
finished: 
	if ( HANDLE_IS_VALID(m_hEvt_IsBusy) ) 
		::ResetEvent ( m_hEvt_IsBusy ); 
	return bRet; 
} 
 
// 
// 从电话本中删除一条纪录 
// 
BOOL CHwMobile::gsmDeleteOneRecordFromPhoneBook ( int nIndex ) 
{ 
	if ( HANDLE_IS_VALID(m_hEvt_IsBusy) ) 
		::SetEvent ( m_hEvt_IsBusy ); 
	BOOL bRet = FALSE; 
	char szCmd[1024] = {0}; 
	sprintf ( szCmd, "AT+CPBW=%d\r", nIndex ); 
	if ( Write ( szCmd ) < 1 ) 
		goto finished; 
	if ( !ReadResponse ( "OK\r\n" ) ) 
		goto finished; 
 
	bRet = TRUE; 
finished: 
	if ( HANDLE_IS_VALID(m_hEvt_IsBusy) ) 
		::ResetEvent ( m_hEvt_IsBusy ); 
	return bRet; 
} 
 
// 
// 获取电话本的基本信息 
// 
BOOL CHwMobile::gmsGetPhoneBookInfo ( 
		int &nStoreStartPos, 
		int &nStoreEndPos, 
		int &nMaxPhoneNOSize,  
		int &nMaxInfoSize, 
		int &nMaxRecSize 
	) 
{ 
	if ( Write ( "AT+CPBR=?\r" ) < 1 ) 
		return FALSE; 
	if ( !WaitForDataToRead ( 10, WAIT_GSM_DATA_TIME_SLOW ) ) 
		return FALSE; 
 
	char szRead[MAX_COM_BUFSIZE] = {0}; 
	int nReadLen = Read ( szRead, sizeof(szRead) ); 
	char *pStr = strstr ( szRead, "+CPBR: (" ); 
	if ( !pStr ) return FALSE; 
	pStr += 8; 
	if ( pStr - szRead >= nReadLen ) 
		return FALSE; 
 
	sscanf ( pStr, "%d", &nStoreStartPos );		// 电话本起始位置 
 
	pStr = strstr ( pStr, "-" ); 
	if ( !pStr ) return FALSE; 
	pStr += 1; 
	if ( pStr - szRead >= nReadLen ) 
		return FALSE; 
	sscanf ( pStr, "%d", &nStoreEndPos );		// 电话本结束位置 
 
	pStr = strstr ( pStr, ")," ); 
	if ( !pStr ) return FALSE; 
	pStr += 2; 
	if ( pStr - szRead >= nReadLen ) 
		return FALSE; 
	sscanf ( pStr, "%d", &nMaxPhoneNOSize );	// 电话号码最大长度 
 
	pStr = strstr ( pStr, "," ); 
	if ( !pStr ) return FALSE; 
	pStr += 1; 
	if ( pStr - szRead >= nReadLen ) 
		return FALSE; 
	sscanf ( pStr, "%d", &nMaxInfoSize );		// 相关信息最大长度 
 
	nMaxRecSize = nMaxPhoneNOSize +				// 一条纪录的最大长度 
		nMaxInfoSize + 30; 
	return TRUE; 
} 
 
// 
// 获取所有电话本纪录 
// 
BOOL CHwMobile::gsmGetAllPhoneBookRec ( int nMaxRecSize, int nMaxRecNum, LPCTSTR lpszPhoneBookName, OUT t_Ary_PhoneBook *pAry_PhoneBook ) 
{ 
	ASSERT ( pAry_PhoneBook ); 
	// 读所有电话本纪录,结果存入 pAry_PhoneBook 数组中 
	if ( !WaitForDataToRead ( 10, WAIT_GSM_DATA_TIME_SLOW ) ) 
		return FALSE; 
	// 要一次全部读入到内存来,否则可能会漏掉一些纪录,为什么会这样我也不知道。 
	const int nDataBufferSize = nMaxRecSize * ( nMaxRecNum + 5 ); 
	char *pPhoneBookData = new char[nDataBufferSize+1]; 
	if ( !pPhoneBookData ) 
	{ 
		::AfxThrowMemoryException(); 
		return FALSE; 
	} 
	memset ( pPhoneBookData, 0, nDataBufferSize+1 ); 
	int nRet = Read ( pPhoneBookData, nDataBufferSize ); 
	if ( nRet > 0 ) 
	{ 
		char szRemainData[MAX_COM_BUFSIZE+1] = {0}; 
		int nRemainBytes = gsmDecodePhoneBook ( lpszPhoneBookName, pPhoneBookData, 
			pAry_PhoneBook, szRemainData, MAX_COM_BUFSIZE ); 
		if ( nRemainBytes > 0 ) 
		{ 
			memcpy ( pPhoneBookData, szRemainData, nRemainBytes ); 
			pPhoneBookData[nRemainBytes] = '\0'; 
		} 
	} 
	delete[] pPhoneBookData; 
 
	return TRUE; 
} 
 
// 
// 解码所有电话纪录, 返回处理完后剩余的字节数 
// 
int CHwMobile::gsmDecodePhoneBook ( 
		LPCTSTR lpszPhoneBookName, 
		char *szPhoneBookRec, 
		OUT t_Ary_PhoneBook *pAry_PhoneBook, 
		OUT char *szRemainData,					// 处理后剩下的数据放到这里 
		const int nRemainSize 
	) 
{ 
	ASSERT ( szPhoneBookRec ); 
	CStringArray StrAry; 
	PartStringAndAddToStrAry ( GetCompatibleString(szPhoneBookRec,FALSE), StrAry, _T('\r') ); 
	int nRemainCount = 0; 
	for ( int i=0; iAdd ( PhoneBook ); 
//			HwDbgLog ( L_DEBUG, _T("得到电话本纪录如下:\r\nNO.%d - [%s] - %s - %s"), 
//				PhoneBook.nIndex, PhoneBook.szPhoneBookName, PhoneBook.szName, PhoneBook.szPhoneNO ); 
		} 
		else 
		{ 
			int nLen = MIN ( MultiByteString_Temp.GetLength(), nRemainSize-nRemainCount ); 
			if ( nLen < 0 ) nLen = 0; 
			memcpy ( szRemainData, MultiByteString_Temp.GetBuffer(), nLen ); 
			nRemainCount += nLen; 
		} 
	} 
 
	return nRemainCount; 
} 
 
// 
// 解码一条电话纪录 
// 
BOOL CHwMobile::gsmDecodeOnePhoneBook ( char *szPhoneBookRec, OUT t_PhoneBook &PhoneBook ) 
{ 
	ASSERT ( szPhoneBookRec ); 
	char *pStr = strstr ( szPhoneBookRec, "+CPBR: " ); 
	if ( !pStr ) return FALSE; 
	pStr += 7; 
	CString csTemp; 
	CStringArray StrAry; 
	PartStringAndAddToStrAry ( GetCompatibleString(pStr,FALSE), StrAry, _T(',') ); 
	if ( StrAry.GetSize() < 4 ) return FALSE; 
	 
	csTemp = StrAry.GetAt(0);			// 序号 
	PhoneBook.nIndex = atoi ( CMultiByteString(csTemp).GetBuffer() ); 
 
	csTemp = StrAry.GetAt(1);			// 电话号码 
	csTemp.TrimLeft ( _T("\"") ); csTemp.TrimRight ( _T("\"") ); 
	lstrcpyn ( PhoneBook.szPhoneNO, csTemp, COUNT(PhoneBook.szPhoneNO) ); 
 
	csTemp = StrAry.GetAt(2);			// 类型 
 
	csTemp = StrAry.GetAt(3);			// 姓名 
	csTemp.TrimLeft ( _T("\"") ); csTemp.TrimRight ( _T("\"") ); 
	int nPos = csTemp.Find ( _T('\"'), 0 ); 
	if ( nPos >= 0 ) csTemp = csTemp.Left ( nPos ); 
	char szName[1024] = {0}; 
	CMultiByteString ( csTemp, STRING_IS_SOFTCODE, szName, sizeof(szName) ); 
 
	// UCS2解码 
	char szTempBuf[4096] = {0}; 
	int nRet = gsmString2Bytes ( szName, (BYTE*)szTempBuf, (int)strlen(szName), COUNT(szTempBuf) );	// 格式转换 
	gsmDecodeUcs2 ( (BYTE*)szTempBuf, (char*)PhoneBook.szName, nRet, sizeof(PhoneBook.szName) );		// 转换到TP-DU 
	CString csName = GetCompatibleString ( PhoneBook.szName, FALSE ); 
	lstrcpyn ( PhoneBook.szName, csName, COUNT(PhoneBook.szName) ); 
	return TRUE; 
} 
 
// 
// 编码一条电话纪录 
// return : 编码后的字节长度 
// 
int CHwMobile::gsmPhoneBookEncode ( 
		OUT char *szPhoneBookRec, 
		int nPhoneBookRecSize, 
		IN LPCTSTR lpszType, 
		IN t_PhoneBook &PhoneBook 
	) 
{ 
	ASSERT_ADDRESS ( szPhoneBookRec, nPhoneBookRecSize ); 
	ASSERT ( lpszType ); 
	memset ( szPhoneBookRec, 0, nPhoneBookRecSize ); 
 
	// UCS2编码 
	char szUCS2Name[1024] = {0}, szStrName[1024] = {0}; 
	CMultiByteString MultiByteString_Name(PhoneBook.szName); 
	int nRet = gsmEncodeUcs2 ( MultiByteString_Name.GetBuffer(), (BYTE*)szUCS2Name, MultiByteString_Name.GetLength(), sizeof(szUCS2Name) ); 
	gsmBytes2String ( (BYTE*)szUCS2Name, szStrName, nRet, sizeof(szStrName) ); 
 
	int nCount = 0; 
	// 写电话本,向当前的电话本存储区某一位置处写入记录 
	nCount += hwSnprintfA ( szPhoneBookRec+nCount, (nPhoneBookRecSize-nCount)/sizeof(char), "AT+CPBW=,\"%s\",%s,\"%s\"\r", 
		CMultiByteString(PhoneBook.szPhoneNO).GetBuffer(), CMultiByteString(lpszType).GetBuffer(), szStrName ); 
 
	return nCount; 
} 
 
// 
// 插入一条电话本纪录 
// 
BOOL CHwMobile::InsertPhoneBook(LPCTSTR lpszName, LPCTSTR lpszPhoneNO, LPCTSTR lpszPhoneBookName) 
{ 
	if ( !lpszName || lstrlen(lpszName) < 1 ) return FALSE; 
	if ( !lpszPhoneNO || lstrlen(lpszPhoneNO) < 1 ) return FALSE; 
 
	BOOL bRet = FALSE; 
	char szCmd[1024] = {0}; 
	t_PhoneBook PhoneBook = {0}; 
	char *pStr = NULL; 
	int nRet = 0; 
	char szReadBuf[MAX_COM_BUFSIZE+1] = {0}; 
	memset ( &PhoneBook, 0, sizeof(t_PhoneBook) ); 
	CString csTypeDesc; 
	if ( HANDLE_IS_VALID(m_hEvt_IsBusy) ) 
		::SetEvent ( m_hEvt_IsBusy ); 
	if ( lpszPhoneBookName && lstrlen(lpszPhoneBookName) > 0 ) 
	{ 
		if ( !gsmSelectPhoneBook ( lpszPhoneBookName ) ) 
			goto finished; 
	} 
 
	// 获取电话纪录类型 
	if ( Write ( "AT+CPBW=?\r" ) < 1 ) goto finished; 
	if ( !WaitForDataToRead ( 10, WAIT_GSM_DATA_TIME_SLOW ) ) 
		goto finished; 
 
	nRet = Read ( szReadBuf, MAX_COM_BUFSIZE ); 
	if ( nRet < 10 ) goto finished; 
 
	pStr = strstr ( szReadBuf, "+CPBW: (" ); 
	if ( !pStr ) goto finished; 
	pStr += 8; 
	if ( (pStr = strstr ( pStr, "(" )) == NULL ) 
		goto finished; 
	pStr += 1; 
	 
	for ( ; *pStr != '\0' && isdigit(*pStr); pStr++ ) 
	{ 
		if ( pStr-szReadBuf >= MAX_COM_BUFSIZE ) 
			break; 
		csTypeDesc += *pStr; 
	} 
 
	lstrcpyn ( PhoneBook.szName, lpszName, COUNT(PhoneBook.szName) ); 
	lstrcpyn ( PhoneBook.szPhoneNO, lpszPhoneNO, COUNT(PhoneBook.szPhoneNO) ); 
	lstrcpyn ( PhoneBook.szPhoneBookName, lpszPhoneBookName, COUNT(PhoneBook.szPhoneBookName) ); 
 
	// 产生插入命令,并将电话纪录插入 
	nRet = gsmPhoneBookEncode ( szCmd, sizeof(szCmd), csTypeDesc, PhoneBook ); 
	if ( Write ( szCmd ) < 1 ) goto finished; 
	if ( !ReadResponse ( "OK", FALSE ) ) goto finished; 
	bRet = TRUE; 
 
finished: 
	if ( HANDLE_IS_VALID(m_hEvt_IsBusy) ) 
		::ResetEvent ( m_hEvt_IsBusy ); 
	HwDbgLog ( L_DEBUG, _T("Insert PhoneNO [%s] %s"), lpszPhoneNO, bRet?_T("successfully"):_T("failed") ); 
	return bRet; 
} 
 
void CHwMobile::SMSBeep(BOOL bRecv) 
{ 
	if ( !m_bSoundPrompt ) return; 
	DWORD dwFreq_Start = 1000, dwFreq_Interval=800; 
	DWORD dwDuration = 100; 
	for ( int i=0; i<5; i++ ) 
	{ 
		Beep ( dwFreq_Start+dwFreq_Interval*( bRecv?(5-i):i ), dwDuration ); 
	} 
} 
 
// 
// 检测设备是否存在,通过发送命令和读取回应的办法来实现 
// 
BOOL CHwMobile::QueryDeviceExist() 
{ 
	for ( int i=0; ; i++ ) 
	{ 
		if ( HANDLE_IS_VALID(m_hEvt_IsBusy) && 
			::WaitForSingleObject(m_hEvt_IsBusy,0)==WAIT_OBJECT_0 ) 
			return TRUE; 
		if ( QueryExistByRWCmd () ) 
			return TRUE; 
		if ( i 0 && 
		ReadResponse ( "OK" ) ) 
	{ 
		return TRUE; 
	} 
 
	return FALSE; 
} 
 
// 
// 恢复短信通知方式:  
// 
void CHwMobile::RestoreRecvSMSNotifyMode() 
{ 
	if ( m_nInitOK && m_handleCOM && m_handleCOM != INVALID_HANDLE_VALUE ) 
	{ 
		Write("AT+CNMI=0,0\r" ); 
	} 
} 
 
void CHwMobile::ShowGSMModuleInfo() 
{ 
	// 获取手机信息 
	CString csMobileInfo; 
	for ( int i=0; i<3; i++ ) 
	{ 
		if ( DemandMobileInfo ( "AT+CGMI\r", csMobileInfo ) ) 
			break; 
		Sleep ( 1000 ); 
	} 
	Log ( L_NORMAL | L_OUT_UI, _T("SMS Module Brand : [ %s ]"), 
		#ifdef _DEBUG 
			csMobileInfo 
		#else 
			COMPANY_PRINCIPAL_NAME 
		#endif 
		); 
 
	for ( i=0; i<3; i++ ) 
	{ 
		if ( DemandMobileInfo ( "AT+CGMM\r", csMobileInfo ) ) 
			break; 
		Sleep ( 1000 ); 
	} 
	 
	Log ( L_NORMAL | L_OUT_UI, _T("SMS Module Model : [ %s ]"),  
		#ifdef _DEBUG 
			csMobileInfo 
		#else 
			_T("HW-MB32A") 
		#endif 
		); 
} 
 
#endif