⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hwmobile.cpp

📁 短信收发的程序源代码。能自动检测手机是否连接好
💻 CPP
📖 第 1 页 / 共 3 页
字号:
		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 + -