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' &&
pStr[i] != '<' && pStr[i] != '/' && pStr[i] != '.' && pStr[i] != ',' && pStr[i] != '\t' && pStr[i] != '\r' &&
pStr[i] != '\n' && pStr[i] != ' '
)
{
nEspecialCharCount ++;
}
}
if ( nEncode == GSM_7BIT && nEspecialCharCount > 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