#include "stdafx.h" #include "SmsProcess.h" #include "CommAsyn.h" #include "CommRS232.h" #include "Sms.h" HANDLE g_hRunObject = NULL; HANDLE g_hReceiveSmsThread = NULL; DWORD WINAPI ReceiveSmsThread(LPVOID lpParameter); typedef int (WINAPI *PFCALLBACK)( BOOL bEnableAlarm );//true 恢复正常 false 报警不打电话不发短信 PFCALLBACK gEnalbeAlarmCallBack=NULL; CCommRS232 *g_pComm = NULL; CHAR g_strDirectory[MAX_PATH + 1] = {0}; // 软件所在路径 int g_nNeedLanguageTrans = -1; // 是否需要繁简转换 int g_nMaxChar = 70; // 短信猫一条短信最大支持的字符个数 int g_nMakeCall = 0; // 发送后是否先拔打电话提醒 extern CSmsApp theApp; int MyCharCount(const char* szMsg); char* PickSegTxt(const char* pMsgAll, char* szSeg, int nSize); void Make_PDU_Message( const char *szNumber, const char *szMsg, BOOL bNeedReport, char *szPDU ); void Make_PDU_Number(const char *szNumber, char *szPDUNumber); void SwapChars(char *szNumber); int Str2PDU_Unicode(const char *szMsg, char *szPDU); int GSMResponse(const char *szBuff,int nCount, int &nErrorType, int &nErrorCode); BOOL GetValidResponse(const char *szBuff, int nCount, char *szResponse); char ACharToBChar(char c); int SendSMS( const char *szNo, const char *szMsg, char* szEvent ); int SMS_DLLInit( char *pDirectory, int nAddr, // 保留,因为短信猫是串口232没有地址 int nCommPort, // 串口号 int nRate, // 波特率 int nDataBit, // 数据位 int nStopBit, // 停止位 int nParity, // 校验位 int nInterval, // 间隔时间 int nNeedLanguageTrans, // 是否需要语言转换 int nMaxChar, // 短信猫一条短信最大支持的字符个数 int nMakeCall ) // 发送后是否先拔打电话提醒 { strcpy(g_strDirectory, pDirectory); g_nNeedLanguageTrans = nNeedLanguageTrans; g_nMaxChar = nMaxChar; g_nMakeCall = nMakeCall; if( g_pComm == NULL ) { g_pComm = new CCommRS232; PORTPARAM portParam; portParam.StartAddr = nAddr; //起止地址 portParam.PortNo = nCommPort; //Com端口 portParam.BaudRate = nRate; //波特率 portParam.ByteSize = nDataBit; // Number of bits/byte, 4-8 portParam.StopBits = nStopBit; /* 结束位 0,1,2 = 1, 1.5, 2 */ portParam.Parity = nParity; /* 校验位 0-4=None,Odd,Even,Mark,Space */ portParam.Interval = nInterval; //间隔时间 if(!g_pComm->InitParam(&portParam)) { delete g_pComm; g_pComm = NULL; return ERR_CODE_SMS_OPEN_COMM; } #if 1 // 设置成PDU模式 char szBuf[MAX_SIZE] = {0}; //取号码 strcpy(szBuf, "AT+CMGF=1\r"); int nLen = g_pComm->Write((BYTE *)szBuf, (int)strlen(szBuf)); nLen = g_pComm->Read((BYTE *)szBuf, MAX_SIZE - 1); #endif } return 0; } void SMS_DLLUnInit() { if( g_hRunObject ) MTVERIFY( SetEvent( g_hRunObject ) ); if( g_hReceiveSmsThread ) { MTVERIFY( WaitForSingleObject( g_hReceiveSmsThread, INFINITE ) != WAIT_FAILED ); MTVERIFY( CloseHandle( g_hReceiveSmsThread ) ); g_hReceiveSmsThread = NULL; } // 关闭串口 if( g_pComm ) { delete g_pComm; g_pComm = NULL; } return; } int SMS_DLLSendSms(char *pTel, // 手机号码 char *pContent, // 发送内容 char *pErrorMsg // 错误消息 ) { int nRet = 0; BOOL bOK = FALSE; AFX_MANAGE_STATE(AfxGetStaticModuleState()); CString strMsg = CString(pContent); if(g_nNeedLanguageTrans) strMsg = theApp.FtToJt(strMsg); if(MyCharCount(strMsg) < 70) nRet = SendSMS(pTel, strMsg, pErrorMsg); else { char* szMsg2 = new char[strlen(strMsg)+1]; strcpy(szMsg2, strMsg); char* pMsgSegLeft = (char*)szMsg2; bOK = TRUE; while (1) { char szMsgSegSend[255] = {0}; int nMaxCharCanSend = g_nMaxChar; // 最大能够发送的字符,暂固定为70 pMsgSegLeft = PickSegTxt(pMsgSegLeft, szMsgSegSend, nMaxCharCanSend); nRet = SendSMS(pTel, szMsgSegSend, pErrorMsg); if(!nRet) { bOK = FALSE; break; } if(pMsgSegLeft == NULL) break; } delete []szMsg2; } if(bOK && 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); g_pComm->Write( (BYTE *)WriteBuff, iOffset ); int nLen = g_pComm->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); g_pComm->Write((BYTE *)WriteBuff, iOffset); nLen = g_pComm->Read((BYTE *)ReadBuff, MAX_READ_STR_LEN); } return nRet; } bool SMS_DLLGetCSQ( int iMin,int iMax,int &iNowData ) // 得到短信貓的信号 { bool bRet=false; char szBuf[MAX_SIZE] = {0}; //取号码 strcpy(szBuf, "AT+CSQ\r"); int nLen = g_pComm->Write((BYTE *)szBuf, (int)strlen(szBuf)); memset( szBuf,0,sizeof(szBuf) ); nLen = g_pComm->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; return bRet; } int SMS_DLLSetCallBack(PFCALLBACK Func) { if( Func==NULL || gEnalbeAlarmCallBack!=NULL ) return 0; gEnalbeAlarmCallBack = Func; MTVERIFY (g_hRunObject = ::CreateEvent( NULL, /* Security */ TRUE, /* Manual event */ 0, /* Clear on creation */ 0)); DWORD dwReceiveSmsThreadId; MTVERIFY( g_hReceiveSmsThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ReceiveSmsThread,NULL, 0, &dwReceiveSmsThreadId) ); return 0; } int MyCharCount(const char* szMsg) { int i = 0; int nCharCount = 0; while(szMsg[i] != 0) { if(szMsg[i] & 0x80) { ASSERT(szMsg[i+1] & 0x80); if(szMsg[i+1] & 0x80) i++; } i++; nCharCount++; } return nCharCount; } char ACharToBChar(char c) { if(c >= '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; } 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; } //============================================================================================ // 函数名称:Make_PDU_Number // 函数功能:将电话号码转换为gsm pdu格式 // 函数参数: // [IN] char *szNumber // 需要转换的电话号码 // [OUT] char *szPDUNumber // 转换后的电话号码 // 返回值: // //============================================================================================ void Make_PDU_Number(const char *szNumber, char *szPDUNumber) { char szTmp[PDU_MAXNUMLEN]; int nType, nLen; nLen = (int)strlen(szNumber); if ( szNumber[0] == '+') { strncpy(szTmp, szNumber + 1, PDU_MAXNUMLEN); nType = NUM_INT; nLen--; } else { strncpy(szTmp,szNumber,PDU_MAXNUMLEN); nType = NUM_NAT; }//end if (szNumber[0]...) if (strlen(szTmp) % 2) { strcat(szTmp,"F"); } SwapChars(szTmp); sprintf(szPDUNumber,"%02X%02X%s",nLen,nType,szTmp); } //============================================================================================ // 函数名称:Make_PDU_Message // 函数功能:将短消息(包括电话号码、文本)转换为GSM PDU格式 // 函数参数: // [IN] char *szNumber // 需要转换的电话号码 // [IN] char *szMsg // 需要转换的短消息文本 // [IN] BOOL bNeedReport // 是否需要提供信息报告 // [OUT] char *szPDU // 转换后的gsm pdu文本 // 返回值: // //============================================================================================ void Make_PDU_Message( const char *szNumber, const char *szMsg, BOOL bNeedReport, char *szPDU ) { int nType, nCodingScheme; char szPDU_Number[PDU_MAXNUMLEN]; Make_PDU_Number(szNumber,szPDU_Number); nType = 0x10 + 0x01; // 0x11 -- 0001 0001 if (bNeedReport) { nType = nType + 0x20; // 0x20 -- 0010 0000 } nCodingScheme = 0x08; // 0x08 -- 0000 1000 -- 16bit UCS2 char szPDU_Msg[500]; Str2PDU_Unicode(szMsg,szPDU_Msg); //sprintf(pdu,"00%02X00%s00%02XFF%02X%s", sprintf(szPDU,"00%02X00%s00%02X00%02X%s", //00 - 默认短消息中心 nType,// FO //00 - TP-MO szPDU_Number, //00 - TP-PID nCodingScheme, //00 - TP-VP strlen(szPDU_Msg)/2, szPDU_Msg); } //============================================================================================ // 函数名称:SwapChars // 函数功能:交换编码 13823652665F --> 3128632566F5, 用于电话号码编码 // 函数参数: // [IN/OUT] char *szNumber // 需要转换的电话号码 // 返回值: // //============================================================================================ void SwapChars(char *szNumber) { int nLength; int nPosition; char ch; nLength = (int)strlen(szNumber); for (nPosition=0;nPosition0;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) ); szResponse[nCount-2-(i+1)] = '\0'; return TRUE; } //============================================================================================ int SendSMS( const char *szNo, const char *szMsg, char* szEvent ) { 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]; Make_PDU_Message(szNo,szMsg,FALSE,szPDU); 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)); g_pComm->Write((BYTE*)WriteBuff, iOffset); g_pComm->Read((BYTE*)szTmp, MAX_READ_STR_LEN); iOffset = 0; sprintf(WriteBuff+iOffset,szPDU); iOffset += (int)strlen(szPDU); WriteBuff[iOffset++] = 0x1a; //LOG4C_HEX_DUMP((LOG_NOTICE, WriteBuff, iOffset)); g_pComm->Write((BYTE*)WriteBuff, iOffset); int nErrorType,nErrorCode; //发送错误类型、编码 int nResponse = GSM_RESPONSE_NORESPONSE; //发送结果 Sleep(3000);//发送完短信时等待3秒发送 do { nTmp = g_pComm->Read((BYTE*)szTmp,MAX_READ_STR_LEN); 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!"); return 0; break; case GSM_RESPONSE_NORESPONSE: sprintf(szEvent,"GSM Modem No Response! Please Check The Connection!"); return ERR_CODE_SMS_GSM_NO_RESPONSE; break; case GSM_RESPONSE_ERROR: sprintf(szEvent,"Send fail! The card maybe has little money, Please recharge!"); return ERR_CODE_SMS_GSM_ERROR_RESPONSE; break; case GSM_RESPONSE_UNKNOWN: sprintf(szEvent,"Send Timeout. The Message may Send OK!"); return ERR_CODE_SMS_GSM_UNKOWN_RESPONSE; default: sprintf(szEvent,"Send Timeout. The Message may Send OK!"); return ERR_CODE_SMS_GSM_UNKOWN_RESPONSE; }//end switch return ERR_CODE_SMS_GSM_UNKOWN_RESPONSE; } int ReceiveSms(int iIndex, char* strTelFrom, char* strTime, char* strReceiveMsg, int nCharSize) { int nRet=-1;//0:关闭报警 1:恢复正常 char szBuf[MAX_SIZE] = {0}; //取号码 strcpy(szBuf, "AT+CMGF=1\r"); int nLen = g_pComm->Write((BYTE *)szBuf, (int)strlen(szBuf)); nLen = g_pComm->Read((BYTE *)szBuf, MAX_SIZE - 1); //int nLen=0; sprintf(szBuf, "AT+CMGR=%d\r", 2); nLen = g_pComm->Write((BYTE *)szBuf, (int)strlen(szBuf)); nLen = g_pComm->Read((BYTE *)szBuf, 511); 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"); ASSERT(pTemp); if(pTemp && strlen(pTemp) > 2+5+5+14)//至少有4个元素:"\r\n"(=2), 服务中心码(>5),接受中心码(>5),时间(=14), { pTemp = pTemp + 2;//strlen("\r\n") = 2; //取发送短信的服务器号码: int nLenTelNo = 0; nLenTelNo = nLenTelNo*16 + ACharToBChar(pTemp[0]); nLenTelNo = nLenTelNo*16 + ACharToBChar(pTemp[1]); nLenTelNo = 13;//这个长度分析有问题,先定死为13. nTelServiceType = 0; nTelServiceType = nTelServiceType*16 + ACharToBChar(pTemp[2]); nTelServiceType = nTelServiceType*16 + ACharToBChar(pTemp[3]); int nOffset = 0; if(nTelServiceType == 0x91) { szTelService[nOffset++] = '+'; } pTemp = pTemp + 4; int nLenTelNoFix = nLenTelNo + (nLenTelNo%2); for(int i = 0; i < nLenTelNo; i+=2) { szTelService[nOffset++] = pTemp[i+1]; szTelService[nOffset++] = pTemp[i+0]; } if(szTelService[nOffset-1] == 'F') szTelService[nOffset-1] = 0; pTemp += nLenTelNoFix; pTemp += 2;//暂不知道服务器号码后的两个字节是干么用的 //取发送短信的手机的号码 nLenTelNo = 0; nLenTelNo = nLenTelNo*16 + ACharToBChar(pTemp[0]); nLenTelNo = nLenTelNo*16 + ACharToBChar(pTemp[1]); nTelType = 0; nTelType = nTelType*16 + ACharToBChar(pTemp[2]); nTelType = nTelType*16 + ACharToBChar(pTemp[3]); nOffset = 0; if(nTelType == 0x91) { szTel[nOffset++] = '+'; } pTemp = pTemp + 4; nLenTelNoFix = nLenTelNo + (nLenTelNo%2); for(i = 0; i < nLenTelNo; i+=2) { szTel[nOffset++] = pTemp[i+1]; szTel[nOffset++] = pTemp[i+0]; } if(szTel[nOffset-1] == 'F') szTel[nOffset-1] = 0; pTemp += nLenTelNoFix; pTemp += 4;//暂不知道手机号码后的四个字节是干么用的 // 取日期 nOffset = 0; ASSERT(strlen(pTemp) >=14); for(i = 0; i < 14; i+=2) { szTime[nOffset++] = pTemp[i+1]; szTime[nOffset++] = pTemp[i+0]; } pTemp += 14; pTemp += 2;//日期后的两个字节不知道是什么. //取短信内容 strcpy(szWideBuf, pTemp);//留下原文备用 unsigned short szShort[MAX_SIZE] = {0}; nLen = (int)strlen(pTemp)-2;//最后两个字节是校验,不计 str.Format("%s",pTemp ); if( (str.Left(1)=='o' || str.Left(1)=='O') && nLen==8 ) nRet = 1; else if( (str.Left(1)=='c' || str.Left(1)=='C') && nLen==10 ) nRet = 0; //for(i = 0; i < nLen; i+=4) //{ // szShort[i/4] = 0; // szShort[i/4] = szShort[i/4]*16 + ACharToBChar(pTemp[i+0]); // szShort[i/4] = szShort[i/4]*16 + ACharToBChar(pTemp[i+1]); // szShort[i/4] = szShort[i/4]*16 + ACharToBChar(pTemp[i+2]); // szShort[i/4] = szShort[i/4]*16 + ACharToBChar(pTemp[i+3]); //} //for(i = 0; i < nLen; i+=2) //{ // szShort[i/2] = 0; // szShort[i/2] = szShort[i/2]*16 + ACharToBChar(pTemp[i+0]); // szShort[i/2] = szShort[i/2]*16 + ACharToBChar(pTemp[i+1]); // //szShort[i/4] = szShort[i/4]*16 + ACharToBChar(pTemp[i+2]); // //szShort[i/4] = szShort[i/4]*16 + ACharToBChar(pTemp[i+3]); //} nLen = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)_T(szShort), nLen, szReceiAscii, MAX_SIZE-1, NULL, NULL); } } ////////////////////////////////////////////////////////////////////////// //显示 if(strlen(szTel) < UINT(nCharSize)) strcpy(strTelFrom, szTel); if(strlen(szTime) < UINT(nCharSize)) strcpy(strTime, szTime); if(strlen(szReceiAscii) < UINT(nCharSize)) strcpy(strReceiveMsg, szReceiAscii); ////清除 //if(strlen(strTelFrom) > 0) //{ // sprintf(szBuf, "AT+CMGD=%d\r", iIndex); // nLen = g_pComm->Write((BYTE *)szBuf, (int)strlen(szBuf)); // nLen = g_pComm->Read((BYTE *)szBuf, MAX_SIZE - 1); //} // return nRet;//return strlen(strTelFrom) > 0; } DWORD WINAPI ReceiveSmsThread(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( g_hRunObject, 500L ) == WAIT_TIMEOUT ); return 0; }