📄 hwmobile.cpp
字号:
int nWideSize/*=0*/
)
{
WCHAR wchar[256] = {0}; // UNICODE串缓冲区
ASSERT ( szDst );
memset ( szDst, 0, nDstSize );
// 高低字节对调,拼成UNICODE
for(int i=0; i<nSrcLength/2; i++)
{
wchar[i] = *pSrc++ << 8; // 先高位字节
wchar[i] |= *pSrc++; // 后低位字节
}
if ( wzSMSContent_Wide && nWideSize > 0 )
{
wcsncpy ( wzSMSContent_Wide, wchar, nWideSize );
}
// UNICODE串-->字符串,因为不知道源字符串到底是GB还是Big5,所以用两种方式分别给于解码,解码后的结果再来取舍
// 取汉字多的那个,如果计算出的汉字数目相等,就取里面包含问号少的那个
CString csDestTemp1('\0',1024), csDestTemp2('\0',1024);
int nDstLength1, nDstLength2;
nDstLength1 = WideCharToMultiByte ( CHARCODEPAGE_GB, 0, wchar, nSrcLength/2, csDestTemp1.GetBuffer(0), 1024, NULL, NULL);
csDestTemp1.ReleaseBuffer ();
int nQuestionCount1 = CountCharNumber ( csDestTemp1.GetBuffer(0), '?' );
int nChineseNum1 = 0;
CalcStringCodeType ( csDestTemp1, &nChineseNum1 );
nDstLength2 = WideCharToMultiByte ( CHARCODEPAGE_BIG5, 0, wchar, nSrcLength/2, csDestTemp2.GetBuffer(0), 1024, NULL, NULL);
csDestTemp2.ReleaseBuffer();
int nQuestionCount2 = CountCharNumber ( csDestTemp2.GetBuffer(0), '?' );
int nChineseNum2 = 0;
CalcStringCodeType ( csDestTemp2, &nChineseNum2 );
CString csDest;
if ( nChineseNum1 == nChineseNum2 )
{
if ( nQuestionCount1 == nQuestionCount2 )
{
if ( GetCurLanguageType() == ENUM_LanguageType_SimpChinese )
csDest = csDestTemp1;
else
csDest = csDestTemp2;
}
else
{
csDest = ( (nQuestionCount1 < nQuestionCount2) ? csDestTemp1 : csDestTemp2 );
}
}
else
{
csDest = ( (nChineseNum1 > nChineseNum2) ? csDestTemp1 : csDestTemp2 );
}
csDest = GBAndBig5Convert ( csDest );
return hwSnprintf ( szDst, nDstSize, "%s", csDest );
}
//
// 8bit编码
// 输入: pSrc - 源字符串指针
// nSrcLength - 源字符串长度
// 输出: szDst - 目标编码串指针
// 返回: 目标编码串长度
//
int CHwMobile::gsmEncode8bit(const char *pSrc, unsigned char *szDst, int nSrcLength, int nDstSize)
{
char *pDstTail = (char *)(szDst + nDstSize);
// 简单复制
memcpy(szDst, pSrc, nSrcLength);
return nSrcLength;
}
//
// 8bit解码
// 输入: pSrc - 源编码串指针
// nSrcLength - 源编码串长度
// 输出: szDst - 目标字符串指针
// 返回: 目标字符串长度
//
int CHwMobile::gsmDecode8bit(const unsigned char* 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, unsigned char *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;
DbgLog ( L_DEBUG, "从 [COM%d] 来打开手机", m_nComNO );
// 打开串口
if ( !OpenCOM ( m_nComNO, m_nBaudRate, TRUE ) )
{
if ( m_nInitOK )
{
LogML ( L_WARNING, "Open(#2) mobile module interface [COM%d] failed", m_nComNO );
}
m_nInitOK = FALSE;
return FALSE;
}
// 初始化手机模块
if ( !gsmInit() )
{
if ( m_nInitOK )
{
LogML ( L_WARNING, "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;
if ( !ReadResponse ( "OK" ) )
return FALSE;
// 获取手机信息
char szMobileInfo[256] = {0};
if ( DemandMobileInfo ( "AT+CGMI\r", szMobileInfo, sizeof(szMobileInfo) ) )
LogML ( L_NORMAL | L_OUT_DLG, "Mobile Brand : $[ %s ]$", szMobileInfo );
if ( DemandMobileInfo ( "AT+CGMM\r", szMobileInfo, sizeof(szMobileInfo) ) )
LogML ( L_NORMAL | L_OUT_DLG, "Mobile Model : $[ %s ]$", szMobileInfo );
// 设置短信为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" ) )
{
LogML ( L_WARNING | L_OUT_DLG, "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;
if ( !ReadResponse ( "OK", TRUE, csAns.GetBuffer(MAX_COM_BUFSIZE), MAX_COM_BUFSIZE ) )
return FALSE;
csAns.ReleaseBuffer ();
LPCTSTR lpszFindStr = "+CSCA: \"";
int nFindPos = csAns.Find ( lpszFindStr, 0 );
if ( nFindPos < 0 ) return FALSE;
nFindPos += strlen ( lpszFindStr );
csAns = csAns.Mid ( nFindPos );
nFindPos = csAns.Find ( "\"", 0 );
if ( nFindPos < 0 ) return FALSE;
csAns = csAns.Left ( nFindPos );
// UCS2解码
char szTempBuf[1024] = {0};
int nRet = gsmString2Bytes ( csAns, (BYTE*)szTempBuf, csAns.GetLength(), sizeof(szTempBuf) ); // 格式转换
gsmDecodeUcs2 ( (BYTE*)szTempBuf, m_csSMSC.GetBuffer(PHONENO_LENGTH), nRet, PHONENO_LENGTH ); // 转换到TP-DU
m_csSMSC.ReleaseBuffer();
LogML ( L_VERBOSE | L_OUT_DLG, "Get SMSC : %s", m_csSMSC );
if ( m_Proc_SaveSMSCFromGSM )
{
m_Proc_SaveSMSCFromGSM ( m_csSMSC );
}
return TRUE;
}
//
// 用命令来从手机中获取一些信息
// return : ----------------------------------------------------------------
// NULL - 失败
// 结果字符串
//
char *CHwMobile::DemandMobileInfo ( LPCTSTR lpszCmd, char *szOutBuf, int nOutSize )
{
ASSERT_ADDRESS ( szOutBuf, nOutSize );
ASSERT ( nOutSize > 0 );
if ( Write ( lpszCmd ) < 1 )
return NULL;
CString csAns;
if ( !ReadResponse ( "OK", TRUE, csAns.GetBuffer(MAX_COM_BUFSIZE), MAX_COM_BUFSIZE ) )
return NULL;
csAns.ReleaseBuffer ();
csAns.Replace ( "OK", "" );
csAns.Remove ( '\r' );
csAns.Remove ( '\n' );
hwSnprintf ( szOutBuf, nOutSize, "%s", csAns );
return szOutBuf;
}
//
// 从串口中读回应代码, 如果读到的回应代码里能找到字符串 lpszResponse 就返回“TRUE”
// 否则返回“FALSE”
//
BOOL CHwMobile::ReadResponse ( LPCTSTR lpszResponse, BOOL bQuick/*=TRUE*/, char *szAns/*=NULL*/, int nSize/*=0*/ )
{
ASSERT ( lpszResponse );
int nLen = strlen(lpszResponse);
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, lpszResponse ) )
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(LPCTSTR lpszData)
{
if ( !lpszData || strlen(lpszData) < 1 )
return 0;
int nLen = strlen ( lpszData );
#ifdef _DEBUG
if ( strcmp ( lpszData, "AT\r" ) != 0 )
{
// TRACE ( "手机模块发送命令 [ %d bytes ]: %s\n", nLen, lpszData );
}
#endif
int nRet = 0;
char szOneSendPkt[32] = {0};
int nSentBytes = 0, nRemainBytes = nLen;
while ( nRemainBytes > 0 )
{
int nMinLength = MIN ( sizeof(szOneSendPkt), nRemainBytes );
memcpy ( szOneSendPkt, lpszData+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;
}
// 正在读的时候收到了短信
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 = p-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 = 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;
}
return nRet;
}
int CHwMobile::HandleCOMRW(int nRet)
{
if ( nRet < 0 )
{
CloseCOM ();
if ( nRet == -1 )
{
LogML ( L_WARNING | L_OUT_DLG, "Device [COM%d] {got way}", m_nComNO );
}
else if ( nRet == -2 )
{
LogML ( L_WARNING | L_OUT_DLG, "SMS Module be(#2) removed" );
}
}
return nRet;
}
//
// 发送短消息,仅发送命令
// 输入: pSrc - 源PDU参数指针
// return : 发送结果
//
int CHwMobile::gsmSendMessage ( SM_PARAM *pSrc )
{
int nPduLength=0; // PDU串长度
int nSmscLength=0; // SMSC串长度
int nLength=0; // 串口收到的数据长度
char cmd[256]={0}; // 命令串
char pdu[1024]={0}; // PDU串
char ans[256]={0}; // 应答串
nPduLength = gsmEncodePdu ( pSrc, pdu, sizeof(pdu) ); // 根据PDU参数,编码PDU串
strcat(pdu, "\x01a"); // 以Ctrl-Z结束
gsmString2Bytes ( pdu, (unsigned char *)&nSmscLength, 2, sizeof(nSmscLength) ); // 取PDU串中的SMSC信息长度
nSmscLength++; // 加上长度字节本身
// 命令中的长度,不包括SMSC信息长度,以数据字节计
sprintf(cmd, "AT+CMGS=%d\r", nPduLength / 2 - nSmscLength); // 生成命令
// 先输出命令串
// LogML ( L_VERBOSE, "SMS Module Send Command : %s\n", cmd );
if ( Write ( cmd ) < 1 )
return GSM_ERR;
// 根据能否找到"\r\n> "决定成功与否
// 得到肯定回答
if ( !ReadResponse ( "\r\n> ", FALSE ) )
return GSM_ERR;
// 就继续输出PDU串
// LogML ( L_VERBOSE, "SMS Module Send Command : %s\n", pdu );
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 );
int nRes = GSM_UNKNOWN;
DbgLog ( L_DEBUG, "要发送 %d 字节的短信", strlen(pSMSend->TP_UD_Byte) );
// 最多重试 3 次
for ( int i=0; i<3; i++ )
{
nRes = gsmSendMessage ( pSMSend );
if ( nRes == GSM_UNKNOWN )
{
Sleep ( 100 ); // 休息一下再试
}
else
{
break;
}
}
TRACE ( "发送短信给 [ %s ] - %d 字节 [ %s ] 完成\n", pSMSend->TPA, strlen(pSMSend->TP_UD_Byte), pSMSend->TP_UD_Byte );
BOOL bRet = FALSE;
if ( nRes==GSM_OK )
{
DbgLog ( L_DEBUG, "Retry %d times", i );
SMSBeep ( FALSE );
bRet = TRUE;
}
LogML ( bRet?L_VERBOSE:L_WARNING, "Send SMS to(#4) [%s] %s, SMSC : %s", pSMSend->TPA,
(bRet?"successfully":"failed"), pSMSend->SCA );
return bRet;
}
//
// 读取短信内容,读到的短信将在函数 HandleRecvSMS() 中处理,命令已经发送
// 过了,或者不需要发送读取短信的命令,只是在等待接收
//
int 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 = strlen ( szSupplement );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -