#include "StdAfx.h" #include "SMSProcess.h" namespace SMSProcess { ////////////////////////////////////////////////////////////////////////// CCommRS232 *_pSMSComm = NULL; CRITICAL_SECTION _csRS232; INT _nMaxSMSChar = 70; // 短信猫一条短信最大支持的字符个数; const INT MAX_SIZE = 512; int g_nCMGFStatus = 0;//保存现在的传输格式 发送短信用0 接收短信用1; HANDLE _hSMSReceiveThread = NULL; HANDLE _hCtrlEvent = NULL; int g_nMakeCall = 0; // 发送后是否先拔打电话提醒 PFCALLBACK gEnalbeAlarmCallBack = NULL; #define PDU_MAXNUMLEN 70 // 最大号码长度; #define PDU_MAXUNICODELEN 70 // pdu Unicode的最大长度; #define NUM_NAT 0x81 // 非国际号码前缀 phone number type for non- '+'(national) numbers #define NUM_INT 0x91 // 国际号码前缀 phone number type for numbers prefixed by '+'(international) //-------------------------------------------------------------------------------- // FOR gsm sms #define GSM_MAX_WAIT_TIME 12000 //发送短消息时的最长等待时间 #define GSM_RESPONSE_NORESPONSE 0 //无响应 #define GSM_RESPONSE_OK 1 //正确返回 #define GSM_RESPONSE_ERROR 2 //返回错误信息,含错误代码 #define GSM_RESPONSE_UNKNOWN 3 //返回无法确定的信息 #define GSM_CMS_ERROR 0 //CMS Error -- Message service error #define GSM_CME_ERROR 1 //CME Error #define NOP 183 //非可见字符 #define MAX_WRITE_STR_LEN 3840 #define MAX_READ_STR_LEN 512//256 #define MIN_READ_STR_LEN 6 #define MAX_TMPSTR_LEN 512//256 void SwapChars(IN OUT TCHAR *szNumber); char ACharToBChar(char c); CString DeleteEnterForStr( CString sData ); int MyCharCount(const char* szMsg); INT Str2PDU_Unicode(const TCHAR *szMsg, TCHAR *szPDU); BOOL GetValidResponse(const TCHAR *szBuff, int nCount, TCHAR *szResponse); int GSMResponse(const TCHAR *szBuff,int nCount, int &nErrorType, int &nErrorCode); int SendSMS(const char *szNo,const char *szMsg,char* szEvent); int ReceiveSms(int iIndex, char* strTelFrom, char* strTime, char* strReceiveMsg, int nCharSize); char* PickSegTxt(const char* pMsgAll, char* szSeg, int nSize); void TransformPDUPhone( IN CONST TCHAR *szPhone, OUT TCHAR* szPDUPhone, IN CONST INT& nPDUPhoneLen); void TransformPDUMsg(IN CONST TCHAR *szPhone, IN CONST TCHAR* szMsg, IN BOOL bNeedReport, OUT TCHAR* szPduContent, IN CONST INT& nContLen); DWORD WINAPI SMSReceiveThread( LPVOID lpParameter); ////////////////////////////////////////////////////////////////////////// /************************************************************************/ /* 函数:SwapChars[2/22/2016 IT]; /* 描述:交换编码 13823652665F --> 3128632566F5, 用于电话号码编码; /* 参数:; /* [IN]szNumber:需要转换的电话号码; /* 返回:void; /* 注意:; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ void SwapChars(IN OUT TCHAR *szNumber) { int nLength; int nPosition; TCHAR ch; nLength = (int)_tcslen(szNumber); for ( nPosition = 0; nPosition < nLength-1; nPosition += 2 ) { ch = szNumber[nPosition]; szNumber[nPosition] = szNumber[nPosition+1]; szNumber[nPosition+1] = ch; } } /************************************************************************/ /* 函数:TransformPDUPhone[2/22/2016 IT]; /* 描述:将电话号码转换为GSM PDU格式; /* 参数:; /* [IN]szPhone:需要转换的电话号码; /* [OUT]szPDUPhone:转换后的PDU电话号码; /* 返回:void; /* 注意:; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ void TransformPDUPhone( IN CONST TCHAR *szPhone, OUT TCHAR* szPDUPhone, IN CONST INT& nPDUPhoneLen) { TCHAR szTemp[PDU_MAXNUMLEN] = {0}; INT nType = 0; INT nLen = 0; nLen = (INT)_tcslen(szPhone); if ( szPhone[0] == _T('+')) { _tcsncpy_s(szTemp, szPhone + 1, PDU_MAXNUMLEN); nType = NUM_INT; nLen--; } else { _tcsncpy_s(szTemp, szPhone, PDU_MAXNUMLEN); nType = NUM_NAT; } if ( _tcslen(szTemp) %2 ) { _tcscat_s(szTemp, _T("F")); } SwapChars(szTemp); _stprintf_s(szPDUPhone, nPDUPhoneLen, _T("%02X%02X%s"), nLen, nType, szTemp); } /************************************************************************/ /* 函数:TransformPDUMsg[2/22/2016 IT]; /* 描述:将短消息(包括电话号码、文本)转换为GSM PDU格式; /* 参数:; /* [IN]szPhone :需要转换的电话号码; /* [IN]szMsg :需要转换的短信消息文本; /* [IN] bNeedReport:是否需要提供信息报告; /* [OUT] szPduContent:转换后的GSM PDU文本; /* [IN] nContLen:szPduContent缓冲区大小; /* 返回:void; /* 注意:; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ void TransformPDUMsg(IN CONST TCHAR *szPhone, IN CONST TCHAR* szMsg, IN BOOL bNeedReport, OUT TCHAR* szPduContent, IN CONST INT& nContLen) { INT nType = 0; INT nCodingScheme = 0; TCHAR szPDUPhone[PDU_MAXNUMLEN] = {0}; TransformPDUPhone(szPhone,szPDUPhone, PDU_MAXNUMLEN); nType = 0X10 + 0X01; // 0x11 -- 0001 0001; if ( bNeedReport ) { nType += 0X20; // 0x20 -- 0010 0000; } nCodingScheme = 0X08; // 0x08 -- 0000 1000 -- 16bit UCS2; TCHAR szPduMsg[1024] = {0}; Str2PDU_Unicode(szMsg, szPduMsg); _stprintf_s(szPduContent, nContLen, _T("00%02X00%s00%02X00%02X%s"), //00 - 默认短消息中心; nType,// FO; //00 - TP-MO; szPDUPhone, //00 - TP-PID; nCodingScheme, //00 - TP-VP; _tcslen(szPduMsg)/2, szPduMsg); } /************************************************************************/ /* 函数:Str2PDU_Unicode[2/22/2016 IT]; /* 描述:将普通文本转换为gsm需要的unicode编码格式(可用于中、英文模式); /* 参数:; /* [IN] szMsg:需要转换的字符串文本; /* [OUT] szPDU:转换后的pdu unicode文本; /* [IN/OUT] :; /* 返回:int <=0 表示转换失败,否则为unicode字符长度; /* 注意:; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ INT Str2PDU_Unicode(IN CONST TCHAR *szMsg, TCHAR *szPDU) { WCHAR wszPDU[PDU_MAXUNICODELEN]; int nCount = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szMsg, (int)_tcslen(szMsg), wszPDU,PDU_MAXUNICODELEN ); if (nCount<1) { return 0; } for (int i=0;i0;i--) { if ( szBuff[i]==0x0A && szBuff[i-1]==0x0D ) { break; }//end if }//end for if (i<1) { return FALSE; } strncpy(szResponse,szBuff+i+1,nCount-2-(i+1) ); // _tcsncpy_s szResponse[nCount-2-(i+1)] = '\0'; return TRUE; } //============================================================================================ /************************************************************************/ /* 函数:[2/22/2016 IT]; /* 描述:; /* 参数:; /* [IN] :; /* [OUT] :; /* [IN/OUT] :; /* 返回:void; /* 注意:; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ int SendSMS(const char *szNo,const char *szMsg,char* szEvent) { EnterCriticalSection( &_csRS232 ); if( g_nCMGFStatus == 1 ) { char szBuf[MAX_SIZE] = {0}; g_nCMGFStatus = 0; strcpy(szBuf, "AT+CMGF=0\r"); int nLen = _pSMSComm->Write((BYTE *)szBuf, (int)strlen(szBuf)); nLen = _pSMSComm->Read((BYTE *)szBuf, MAX_SIZE - 1); } char WriteBuff[MAX_WRITE_STR_LEN+1] = {0}; char ReadBuff[MAX_READ_STR_LEN+1] = {0}; int iOffset = 0; int iDataLength = 0; char szTmp[MAX_TMPSTR_LEN+1] = {0}; int nTmp; char szPDU[512]; TransformPDUMsg(szNo,szMsg,FALSE,szPDU,512); sprintf(WriteBuff,"AT+CMGS="); iOffset += 8; sprintf(WriteBuff+iOffset,"%03d",strlen(szPDU)/2-1); iOffset = (int)strlen(WriteBuff); WriteBuff[iOffset] = 0x0d; iOffset++; //LOG4C_HEX_DUMP((LOG_NOTICE, WriteBuff, iOffset)); INT nReturnSize = _pSMSComm->Write((BYTE*)WriteBuff, iOffset); nReturnSize = _pSMSComm->Read((BYTE*)szTmp, MAX_READ_STR_LEN); //LOG4C_HEX_DUMP((LOG_NOTICE, szTmp, nReturnSize)); iOffset = 0; sprintf(WriteBuff+iOffset,szPDU); iOffset += (int)strlen(szPDU); WriteBuff[iOffset++] = 0x1a; //LOG4C_HEX_DUMP((LOG_NOTICE, WriteBuff, iOffset)); nReturnSize = _pSMSComm->Write((BYTE*)WriteBuff, iOffset); int nErrorType,nErrorCode; //发送错误类型、编码 int nResponse = GSM_RESPONSE_NORESPONSE; //发送结果 Sleep(3000);//发送完短信时等待3秒发送 do { nTmp = _pSMSComm->Read((BYTE*)szTmp,MAX_READ_STR_LEN); //LOG4C_HEX_DUMP((LOG_NOTICE, szTmp, nTmp)); if (nTmp>0 && iDataLength < MAX_READ_STR_LEN) { strncpy(ReadBuff+iDataLength,szTmp,nTmp); iDataLength += nTmp; } else break; } while(1); nResponse = GSMResponse(ReadBuff,iDataLength,nErrorType,nErrorCode); switch(nResponse) { case GSM_RESPONSE_OK: sprintf(szEvent,"Send OK!"); LOG4C_NO_FILENUM((LOG_NOTICE,"发送结果:%s", szEvent)) return 0; break; case GSM_RESPONSE_NORESPONSE: sprintf(szEvent,"GSM Modem No Response! Please Check The Connection!"); LOG4C_NO_FILENUM((LOG_NOTICE,"发送结果:%s", szEvent)) return ERR_CODE_SMS_GSM_NO_RESPONSE; break; case GSM_RESPONSE_ERROR: sprintf(szEvent,"Send fail! The card maybe has little money, Please recharge!"); LOG4C_NO_FILENUM((LOG_NOTICE,"发送结果:%s", szEvent)) return ERR_CODE_SMS_GSM_ERROR_RESPONSE; break; case GSM_RESPONSE_UNKNOWN: sprintf(szEvent,"Send Timeout. The Message may Send OK!"); LOG4C_NO_FILENUM((LOG_NOTICE,"发送结果:%s", szEvent)) return ERR_CODE_SMS_GSM_UNKOWN_RESPONSE; default: sprintf(szEvent,"Send Timeout. The Message may Send OK!"); LOG4C_NO_FILENUM((LOG_NOTICE,"发送结果:%s", szEvent)) return ERR_CODE_SMS_GSM_UNKOWN_RESPONSE; }//end switch LeaveCriticalSection( &_csRS232 ); return ERR_CODE_SMS_GSM_UNKOWN_RESPONSE; } /************************************************************************/ /* 函数:[2/22/2016 IT]; /* 描述:; /* 参数:; /* [IN] :; /* [OUT] :; /* [IN/OUT] :; /* 返回:void; /* 注意:; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ int ReceiveSms(int iIndex, char* strTelFrom, char* strTime, char* strReceiveMsg, int nCharSize) { EnterCriticalSection( &_csRS232 ); int nRet=-1;//0:关闭报警 1:恢复正常 int nLen=0; char szBuf[MAX_SIZE] = {0}; // if( g_nCMGFStatus==0 ) { g_nCMGFStatus = 1; strcpy(szBuf, "AT+CMGF=1\r"); nLen = _pSMSComm->Write((BYTE *)szBuf, (int)strlen(szBuf)); nLen = _pSMSComm->Read((BYTE *)szBuf, MAX_SIZE - 1); } sprintf(szBuf, "AT+CMGR=%d\r", iIndex); nLen = _pSMSComm->Write((BYTE *)szBuf, (int)strlen(szBuf)); nLen = _pSMSComm->Read((BYTE *)szBuf, 511); if( nLen<50 )//没有短信 { LeaveCriticalSection( &_csRS232 ); return nRet; } CString str; int nReaded = 0; int nTelServiceType = 0x91; int nTelType = 0x91; char szTelService[512] = {0}; char szTel[512] = {0}; char szTime[512] = {0}; char szWideBuf[512] = {0}; char szReceiAscii[512] = {0}; char *pData = strstr(szBuf, "+CMGR:"); char *pOK = strstr(szBuf, "\r\nOK\r\n"); if(pData!= NULL && pOK!=NULL && pOK>pData) { //pOK[0] = 0; memset(pOK, 0, strlen("\r\nOK\r\n")); char* pTemp = pData+6;//strlen("+CMGR:") = 6; nReaded = atoi(pTemp);//短信已读取标志和类型 pTemp = strstr(pTemp, "\r\n"); str.Format("%s",pTemp ); str = DeleteEnterForStr( str ); str = str.MakeLower(); if( str=="open" ) nRet = 1; if( str=="close" ) nRet = 0; } //清除 //if(strlen(strTelFrom) > 0) { sprintf(szBuf, "AT+CMGD=%d\r", iIndex); nLen = _pSMSComm->Write((BYTE *)szBuf, (int)strlen(szBuf)); nLen = _pSMSComm->Read((BYTE *)szBuf, MAX_SIZE - 1); } LeaveCriticalSection( &_csRS232 ); return nRet;//return strlen(strTelFrom) > 0; } /************************************************************************/ /* 函数:[2/22/2016 IT]; /* 描述:; /* 参数:; /* [IN] :; /* [OUT] :; /* [IN/OUT] :; /* 返回:void; /* 注意:; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ DWORD WINAPI SMSReceiveThread(LPVOID lpParameter) { do { char sTelFrom[MAX_SIZE],sTime[MAX_SIZE],sReceiveMsg[MAX_SIZE]; int nRet = ReceiveSms( 1, sTelFrom, sTime, sReceiveMsg, MAX_SIZE ); if( nRet==1 ) { gEnalbeAlarmCallBack( nRet ); } else if( nRet==0 ) { gEnalbeAlarmCallBack( nRet ); } }while( WaitForSingleObject( _hCtrlEvent, 2000L ) == WAIT_TIMEOUT ); return 0; } //删除字符串中的换行 /************************************************************************/ /* 函数:[2/22/2016 IT]; /* 描述:; /* 参数:; /* [IN] :; /* [OUT] :; /* [IN/OUT] :; /* 返回:void; /* 注意:; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ CString DeleteEnterForStr( CString sData ) { CString sRet; int iLen=sData.GetLength(); char* pc=new char[iLen]; memset(pc,0,iLen); int j=0; for(int i=0;i = '0' && c <= '9') c = c - '0'; else if(c >= 'A' && c <= 'F') c = c - 'A' + 10; else if(c >= 'a' && c <='f') c = c - 'a' + 10; return c; } /************************************************************************/ /* 函数:[2/22/2016 IT]; /* 描述:; /* 参数:; /* [IN] :; /* [OUT] :; /* [IN/OUT] :; /* 返回:void; /* 注意:; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ char* PickSegTxt(const char* pMsgAll, char* szSeg, int nSize) { char* pRtn = NULL; int i = 0; int nCharCount = 0; while(pMsgAll[i] != 0) { if(pMsgAll[i] & 0x80) { ASSERT(pMsgAll[i+1] & 0x80); if(pMsgAll[i+1] & 0x80) i++; } i++; nCharCount++; if(pMsgAll[i] == 0 || //已经到了结束符 nCharCount == nSize || //大小已经达到 nCharCount == nSize-1 && (pMsgAll[i]&0x80)) //或者只差最后一个字节并且后续的一个字节为汉字 { memcpy(szSeg, pMsgAll, i); szSeg[i] = 0; if(pMsgAll[i] != 0) pRtn = (char*)(pMsgAll+i); break; } } return pRtn; } ////////////////////////////////////////////////////////////////////////// INT SMS_INIT( IN CONST BYTE& byCommPort, IN CONST DWORD& dwBaudRate, IN CONST BYTE& bySize, IN CONST BYTE& byParity, IN CONST BYTE& byStopBits, IN CONST BYTE& byStartAddr, IN CONST INT& nInterval, IN CONST INT& nMaxSMSChar ) { _nMaxSMSChar = nMaxSMSChar; if ( _pSMSComm == NULL ) { _pSMSComm = new CCommRS232; if ( !_pSMSComm->InitComm(byCommPort, dwBaudRate, bySize, byParity, byStopBits, byStartAddr, nInterval) ) { delete _pSMSComm; _pSMSComm = NULL; return ERR_CODE_SMS_OPEN_COMM; } } // 设置成PDU模式; TCHAR szBuf[MAX_SIZE] = _T("AT+CMGF=0\r"); INT nReturnSize = _pSMSComm->Write((BYTE*)szBuf, (INT)_tcslen(szBuf)); memset(szBuf, 0, MAX_SIZE); nReturnSize = _pSMSComm->Read((BYTE*)szBuf, MAX_SIZE -1); if (nReturnSize) { if ( _tcsstr(szBuf, _T("OK")) == NULL ) { delete _pSMSComm; _pSMSComm = NULL; return -1; } } else { delete _pSMSComm; _pSMSComm = NULL; return -1; } // 把卡里的第一条短信删掉; _tcscpy_s(szBuf, _T("AT+CMGD=1\r")); nReturnSize = _pSMSComm->Write((BYTE*)szBuf,(INT)_tcslen(szBuf)); memset(szBuf, 0, MAX_SIZE); nReturnSize = _pSMSComm->Read((BYTE*)szBuf, MAX_SIZE -1); InitializeCriticalSection(&_csRS232); return 0; } VOID SMS_UNINIT() { // 结束线程; if (_hCtrlEvent) SetEvent(_hCtrlEvent); if ( _hSMSReceiveThread ) { WaitForSingleObject(_hSMSReceiveThread, INFINITE); CloseHandle(_hSMSReceiveThread); _hSMSReceiveThread = NULL; } if (_hCtrlEvent) CloseHandle(_hCtrlEvent); _hCtrlEvent = NULL; DeleteCriticalSection(&_csRS232); // 清理串口句柄; if ( _pSMSComm ) { delete _pSMSComm; _pSMSComm = NULL; } } INT SMS_SENDMSG( IN CONST TCHAR *pTel, IN CONST TCHAR *pContent, IN TCHAR *pErrorMsg ) { if ( pContent == NULL || pTel == NULL ) return -1; INT nRet = 0; BOOL bRet = FALSE; AFX_MANAGE_STATE(AfxGetStaticModuleState()); CString strMsg = pContent; if ( MyCharCount(strMsg) < 70 ) { nRet = SendSMS(pTel, strMsg, pErrorMsg); } else { char* szMsg2 = new char[strlen(strMsg)+1]; strcpy(szMsg2, strMsg); char* pMsgSegLeft = (char*)szMsg2; bRet = TRUE; while (1) { char szMsgSegSend[255] = {0}; int nMaxCharCanSend = _nMaxSMSChar; // 最大能够发送的字符,暂固定为70 pMsgSegLeft = PickSegTxt(pMsgSegLeft, szMsgSegSend, nMaxCharCanSend); nRet = SendSMS(pTel, szMsgSegSend, pErrorMsg); if(!nRet) { bRet = FALSE; break; } if(pMsgSegLeft == NULL) break; } delete []szMsg2; } if(bRet && g_nMakeCall == 1) { //拨号通知用户留心短信(拨号20秒) char WriteBuff[MAX_WRITE_STR_LEN+1] = {0}; char ReadBuff[MAX_READ_STR_LEN+1] = {0}; sprintf(WriteBuff,"ATD%s;\r", pTel); int iOffset = (int)strlen(WriteBuff); _pSMSComm->Write( (BYTE *)WriteBuff, iOffset ); int nLen = _pSMSComm->Read( (BYTE *)ReadBuff, MAX_READ_STR_LEN ); COleDateTime timeStart = COleDateTime::GetCurrentTime(); while (1) { #ifndef _DEBUG //CString strToStop; //if(GetTempVar("ToStop", strToStop) && strToStop == "1") // break; #endif COleDateTimeSpan span = COleDateTime::GetCurrentTime() - timeStart; if(span.GetTotalSeconds() > 20) break; } sprintf(WriteBuff,"ATH\r"); iOffset = (int)strlen(WriteBuff); _pSMSComm->Write((BYTE *)WriteBuff, iOffset); nLen = _pSMSComm->Read((BYTE *)ReadBuff, MAX_READ_STR_LEN); } return nRet; } BOOL SMS_GETCSQ( int iMin,int iMax,int &iNowData ) // 得到短信貓的信号 { bool bRet=false; EnterCriticalSection( &_csRS232 ); char szBuf[MAX_SIZE] = {0}; //取号码 strcpy(szBuf, "AT+CSQ\r"); int nLen = _pSMSComm->Write((BYTE *)szBuf, (int)strlen(szBuf)); memset( szBuf,0,sizeof(szBuf) ); nLen = _pSMSComm->Read((BYTE *)szBuf, MAX_SIZE - 1); CString str; str.Format("%s",szBuf ); int nPos=str.Find("CSQ: " ); str = str.Mid( nPos+5,2 ); iNowData = atoi(str); if( iNowData>=iMin && iNowData<=iMax ) bRet = true; LeaveCriticalSection( &_csRS232 ); return bRet; } INT SMS_SetCallBack(PFCALLBACK Func) { if( Func == NULL || gEnalbeAlarmCallBack != NULL ) return 0; gEnalbeAlarmCallBack = Func; _hCtrlEvent = ::CreateEvent(NULL,TRUE,0,0); DWORD dwReceiveSmsThreadId; _hSMSReceiveThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)SMSReceiveThread, NULL, 0, &dwReceiveSmsThreadId); return 0; } };