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

📄 serialcommlayer.cpp

📁 利用VC++实现PC通过串口收发手机短消息
💻 CPP
📖 第 1 页 / 共 2 页
字号:
		if(!PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
		{
			// If there are no messages pending, wait for a message or
			// the CloseEvent.
			if(CompleteOneWriteRequire)
			{
				if(!PostMessage( hComm32Window, PWM_SENDDATAEMPTY, 0, 0 ))
				{
					goto EndWriteThread;
				}
			}
			//CompleteOneWriteRequire的用处在于:即使RCCComm向WriteThread发送了一个
			//非PWM_COMMWRITE的消息,也不会导致WriteThread又向RCCComm发送一个
			//PWM_SENDDATAEMPTY消息.
			CompleteOneWriteRequire = FALSE;
			
			dwHandleSignaled = MsgWaitForMultipleObjects(1, &hCloseEvent, FALSE,
				INFINITE, QS_ALLINPUT);
			
			switch(dwHandleSignaled)
			{
			case WAIT_OBJECT_0:     // CloseEvent signaled!
				// Time to exit.
				goto EndWriteThread;
				
			case WAIT_OBJECT_0 + 1: // New message was received.
				// Get the message that woke us up by looping again.
				continue;
				
			case WAIT_FAILED:       // Wait failed.  Shouldn't happen.
				goto EndWriteThread;
			default:                // This case should never occur.
				goto EndWriteThread;
			}
		}
		
		// Make sure the CloseEvent isn't signaled while retrieving messages.
		if (WaitForSingleObject(hCloseEvent,0) !=  WAIT_TIMEOUT)
			goto EndWriteThread;
		
		// Handle the message.
		switch(msg.message)
		{
		case PWM_COMMWRITE:  // New string to write to Comm port.
			// Write the string to the comm port.  HandleWriteData
			// does not return until the whole string has been written,
			// an error occurs or until the CloseEvent is signaled.
			if(!HandleWriteData( &overlappedWrite,
				(LPSTR)msg.lParam, (DWORD)msg.wParam ))
			{
				// If it failed, either we got a signal to end or there
				// really was a failure.
				
				LocalFree( HLOCAL(msg.lParam) );
				goto EndWriteThread;
			}
			
			CompleteOneWriteRequire = TRUE;
			// Data was sent in a LocalAlloc()d buffer.  Must free it.
			LocalFree( HLOCAL(msg.lParam) );
			break;
		}
	}//{main loop}

EndWriteThread:
	PostHangupCall();
	PurgeComm(hCommFile, PURGE_TXABORT | PURGE_TXCLEAR);
	CloseHandle(overlappedWrite.hEvent);
	
	return 0; //CWinThread::Run();
}

void CCommWriteThread::PostHangupCall()
{
	PostMessage( hComm32Window, PWM_REQUESTHANGUP, 0, 0 );
}

//(******************************************************************************)
//  CRCCComm
//(******************************************************************************)

CRCCComm::CRCCComm()
{
	hCommFile = INVALID_HANDLE;
	hCloseEvent = INVALID_HANDLE;
	ReadThread = NULL;
	WriteThread = NULL;
	Init();
}

CRCCComm::~CRCCComm()
{
	if (hCommFile != INVALID_HANDLE)
		Close();
}

void CRCCComm::Init()
{
	LastError = RCC_ERROR_SUCCESS;
}

BOOL CRCCComm::StartComm(char * lpCommNo, DWORD dwBaudRate, BYTE byByteSize, BYTE byParity, BYTE byStopBits)
{
	HANDLE hNewCommFile;
     
	// 如果已经启动COMM口,则返回
    if (hCommFile != INVALID_HANDLE)
	{
		LastError = RCC_ERROR_ALREADY_OPEN;
		return FALSE;
	}

	hNewCommFile = CreateFile(lpCommNo, GENERIC_READ|GENERIC_WRITE,
                             0, NULL, OPEN_EXISTING,
                             FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, 0 );
	if (hNewCommFile == INVALID_HANDLE_VALUE)
	{
		LastError = RCC_ERROR_OPEN;
		return FALSE;
	}

	// 检查新句柄是否是一个适当的设备
    if (GetFileType( hNewCommFile ) != FILE_TYPE_CHAR)
	{
		CloseHandle(hNewCommFile);
		LastError = RCC_ERROR_INVALID_COMM;
		return FALSE;
	}

	if( !SetupComm(hNewCommFile, 8192, 8192) )
	{
		CloseHandle( hNewCommFile );
		LastError = RCC_ERROR_SET_BUFFER;
		return FALSE;
	}

    hCommFile = hNewCommFile;
	// 删除系统缓冲区内的任何东西
    PurgeComm( hCommFile, PURGE_TXABORT | PURGE_RXABORT |
                           PURGE_TXCLEAR | PURGE_RXCLEAR ) ;

	DCB  dcb;
	if ( !::GetCommState(hCommFile, &dcb) ) 
	{
		CloseHandle( hCommFile );
        hCommFile = INVALID_HANDLE;
		LastError = RCC_ERROR_GETCOMMSTATE;
		return FALSE;
	}
	dcb.BaudRate = dwBaudRate;
	dcb.ByteSize = byByteSize;
	dcb.Parity   = byParity;
	dcb.StopBits = byStopBits;

	if ( !::SetCommState(hCommFile, &dcb) ) 
	{
		CloseHandle( hCommFile );
        hCommFile = INVALID_HANDLE;
		LastError = RCC_ERROR_SETCOMMSTATE;
		return FALSE;
	}

	//设置底层超时参数
	COMMTIMEOUTS commtimeouts;
	GetCommTimeouts(hCommFile, &commtimeouts);
	commtimeouts.ReadIntervalTimeout         = 20;
	commtimeouts.ReadTotalTimeoutMultiplier  = 0;
	commtimeouts.ReadTotalTimeoutConstant    = 0;
	commtimeouts.WriteTotalTimeoutMultiplier = 30;
	commtimeouts.WriteTotalTimeoutConstant   = 400;
	SetCommTimeouts(hCommFile, &commtimeouts);

	//Sends the DTR (data-terminal-ready) signal.
	::EscapeCommFunction(hCommFile,SETDTR);  

	hCloseEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
	if (hCloseEvent == INVALID_HANDLE)
	{
		CloseHandle( hCommFile );
        hCommFile = INVALID_HANDLE;
		LastError = RCC_ERROR_CREATE_CLOSE_EVENT;
		return FALSE;
	}

	// 创建串口读写线程.
	ReadThread = new CCommReadThread();
	WriteThread = new CCommWriteThread();
	 
	if(ReadThread == NULL || WriteThread == NULL)
	{
		LastError = RCC_ERROR_CREATE_THREAD;
		if(ReadThread)
		{
			delete ReadThread;
			ReadThread = NULL;
		}
		if(WriteThread)
		{
			delete WriteThread;
			WriteThread = NULL;
		}
        CloseHandle( hCloseEvent );
		hCloseEvent=INVALID_HANDLE;
        CloseHandle( hCommFile );
		hCommFile=INVALID_HANDLE;
		return FALSE;
	}

	if( !ReadThread->CreateThread(CREATE_SUSPENDED) ||
		!WriteThread->CreateThread(CREATE_SUSPENDED) )
	{
		LastError = RCC_ERROR_CREATE_THREAD;
		if(ReadThread)
		{
			delete ReadThread;
			ReadThread = NULL;
		}
		if(WriteThread)
		{
			delete WriteThread;
			WriteThread = NULL;
		}
		CloseHandle( hCloseEvent );
		hCloseEvent=INVALID_HANDLE;
		CloseHandle( hCommFile );
		hCommFile=INVALID_HANDLE;
	    return FALSE;
	}
    ReadThread -> SetThreadPriority(THREAD_PRIORITY_HIGHEST);
	WriteThread->SetThreadPriority(THREAD_PRIORITY_HIGHEST);

	ReadThread->hCommFile = hCommFile;
    ReadThread->hCloseEvent = hCloseEvent;
    ReadThread->hComm32Window = m_hWnd;
	ReadThread->m_bAutoDelete = FALSE;
	 
    WriteThread->hCommFile = hCommFile;
    WriteThread->hCloseEvent = hCloseEvent;
    WriteThread->hComm32Window = m_hWnd;
	WriteThread->m_bAutoDelete = FALSE;

	//启动线程
	ReadThread->ResumeThread();
	WriteThread->ResumeThread();

	return TRUE;
}

BOOL CRCCComm::StopComm()
{
	if (hCommFile == INVALID_HANDLE)
		return TRUE;

	// 关闭读写线程.
	CloseReadThread();
	CloseWriteThread();
	
	// 关闭事件句柄.
	CloseHandle( hCloseEvent );
	hCloseEvent = INVALID_HANDLE;

	// 关闭通讯端口.
	CloseHandle( hCommFile );
	hCommFile = INVALID_HANDLE;
	return TRUE;
}

//
//  函数: CloseWriteThread CloseReadThread
//  用途: 关闭读写线程.
//  参数: 无
//  返回值:无
//  备注:
//  关闭串口读写线程,并且清除在串口上的任何写操作
//  如果强制关闭一个线程可能导致内存汇漏,但是本程序是通过
//  关闭事件触发的方式去关闭线程,线程在检测到关闭事件触发
//  时会自动退出,因此不会出现强制关闭一个线程的情况
//
void CRCCComm::CloseReadThread(void) //关闭读线程
{
	if (ReadThread != NULL)
	{
		// 触发事件去关闭工作线程.
        SetEvent(hCloseEvent);

        // 清除在串口上的任何读操作.
        PurgeComm(hCommFile, PURGE_RXABORT|PURGE_RXCLEAR);

        // 等待10秒线程关闭.
		if (WaitForSingleObject( ReadThread->m_hThread, 10000 ) == WAIT_TIMEOUT)
			TerminateThread(ReadThread->m_hThread,-1);
		delete ReadThread;
        ReadThread = NULL;
	}
}

void CRCCComm::CloseWriteThread()
{
	if (WriteThread != NULL)
	{
		// 触发事件去关闭工作线程.
        SetEvent(hCloseEvent);

		// 清除在串口上的任何写操作.
        PurgeComm(hCommFile, PURGE_TXABORT|PURGE_TXCLEAR);

        // 等待10秒线程关闭,因为不会发生,所以注释掉.
        if (WaitForSingleObject( WriteThread->m_hThread, 10000 ) == WAIT_TIMEOUT)
			TerminateThread(WriteThread->m_hThread,-1);
		delete WriteThread;
        WriteThread = NULL;
	}
}

int CRCCComm::Send(char *Buffer,int BufLen)
{
	if(Buffer == NULL || BufLen <= 0)
	{
		return 1;
	}
	LPBYTE lpszStringToWrite = (LPBYTE)LocalAlloc(LPTR, BufLen);
	memcpy(lpszStringToWrite, Buffer, BufLen);

	if (WriteThread->PostThreadMessage(PWM_COMMWRITE, 
		(WPARAM)BufLen, (LPARAM)lpszStringToWrite))
	{
		return 0;
	}
	LocalFree(lpszStringToWrite);
	return 1;
}

//
//  函数: int CRCCComm::Close(void) 
//  用途: 关闭串口链接,重新初始化缓冲区,同时关闭串口.
//  参数: 无 
//  返回值:
//      0 表示成功,即串口关闭成功进行
//      其它表示失败
//  备注:
//  对该函数的理解,可参照CAsyncSocket::Close函数
//  在MODEM连线方式下,需要将该MODEM转入命令状态之下,再进行
//  挂断操作;在RS232方式下,只做内部缓冲区初始化操作。
// 
int CRCCComm::Close(void) 
{
	if(hCommFile == INVALID_HANDLE)
		return 0;
	EscapeCommFunction(hCommFile,CLRDTR);  //Clears the DTR (data-terminal-ready) signal.
	Init();
	StopComm();

	return 0;
}

//
//  函数: LRESULT CRCCComm::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
//  用途: 底层通讯消息截获函数
//  参数: 
//  返回值:
//  备注:
//  本底层主要的通讯方式基于消息,所有的消息分发都通过本函数 

LRESULT CRCCComm::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
{
	switch(message)
	{
	case PWM_GOTCOMMDATA:
		OnRawReceive((LPSTR)lParam,(DWORD)wParam); 
		return 1;
	case PWM_REQUESTHANGUP: //关闭链接
		Close();
		return 1;
	}

	return CWnd::WindowProc(message, wParam, lParam);
}

//
//  函数: int CRCCComm::OnRawReceive(LPSTR lpNewString,DWORD dwSizeOfNewString)
//  用途: 原始数据的接收,本函数是进行RCC协议解析的函数。
//  参数: 
//      lpNewString 接收到的新数据
//      dwSizeOfNewString 新数据的长度
//  返回值: 目前无具体涵义
//  备注:
//      如果应用程序想直接获取原始数据,可稍做修改,派生本函数

int CRCCComm::OnRawReceive(LPSTR lpNewString, DWORD dwSizeOfNewString)
{
	SM_PARAM SmParam;
    char DbgMsg[500];

	int nMsg;			// 短消息计数值
	char * ptr;			// 内部用的数据指针
	char * ptr_tmp;
	
	strcpy(smsResponseBuf, lpNewString);
	smsResponseBuf_length = dwSizeOfNewString;

	DisplayMessage(smsResponseBuf); 

	delete lpNewString;

	if (smsResponseBuf[0] = '+')
	{
	    if (strstr(smsResponseBuf, "+CMT") != NULL)
		{
			DisplayMessage("*** you have new message. ***");
		}
		else if (strstr(smsResponseBuf, "+CMGL:") != NULL)
		{
			nMsg = 0;
	        ptr = smsResponseBuf;
		    
			// 循环读取每一条短消息, 以"+CMGL:"开头
	        while ((ptr = strstr(ptr, "+CMGL:")) != NULL)
			{
                memset(&SmParam, 0, sizeof(SM_PARAM));

		        ptr += 6;		// 跳过"+CMGL:", 定位到序号
				ptr++;          // skip space.
		        sscanf(ptr, "%d", &(SmParam.index));	// 读取序号

		        ptr = strstr(ptr, "\r\n");	// 找下一行
		        if (ptr != NULL)
				{
			        ptr += 2;		// 跳过"\r\n", 定位到PDU
			
			        gsmDecodePdu(ptr, &SmParam);	// PDU串解码
				    sprintf(DbgMsg, "index=%d,SCA=%s,TPA=%s,SCTS=%s,TP_UD=%s", 
		            SmParam.index, SmParam.SCA, SmParam.TPA, SmParam.TP_SCTS, SmParam.TP_UD);

					DisplayMessage(DbgMsg);

			        nMsg++;		// 短消息计数加1
				}
			}  
		}
		else if (strstr(smsResponseBuf, "+CMGR:") != NULL)
		{
			memset(&SmParam, 0, sizeof(SM_PARAM));
			ptr = smsResponseBuf;

			ptr = strstr(ptr, "+CMGR:");
			//ptr++;      //skip a space.
            //sscanf(ptr, "%d", ((SM_PARAM *)&SmParam)->index);	// 读取序号

			//skip first <CR><LF>
			for ( ; (ptr != 0) && (*ptr != 0x0D); ptr++);
			if ((*ptr) == 0)
				return 0;
			ptr++;
			if ((*ptr) != 0x0A)            
				return 0;
			ptr++;

			ptr_tmp = &smsResponseBuf[smsResponseBuf_length - 1];
			if ((*ptr_tmp) != 0x0A)
				return 0;
			ptr_tmp--;
			if ((*ptr_tmp) != 0x0D)
				return 0;
			ptr_tmp--;
			if ((*ptr_tmp) != 0x4B)
				return 0;
			ptr_tmp--;
			if ((*ptr_tmp) != 0x4F)
				return 0;
			
			if ((ptr_tmp - ptr) == 2)
			{
				sprintf(DbgMsg, "OK");
			    DisplayMessage(DbgMsg);
                return 0;

			}

            gsmDecodePdu(ptr, &SmParam);	// PDU串解码
			sprintf(DbgMsg, "SCA=%s,TPA=%s,SCTS=%s,TP_UD=%s", 
		            SmParam.SCA, SmParam.TPA, SmParam.TP_SCTS, SmParam.TP_UD);

			DisplayMessage(DbgMsg);
		}
	}

	return 0;
}

/////////////////////////////////////////////////////////////////////////////



⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -