www.pudn.com > AtModem.rar > YsATModem.cpp
// ATModem.cpp: implementation of the CYsATModem class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "YsATModem.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
UINT CYsATModem::WaitThread(LPVOID lpvoid)
{
CYsATModem* pThis=(CYsATModem*)lpvoid;
pThis->DetectConnect();
return 1;
}
//检测modem是否就续
UINT CYsATModem::DetectModemThread(LPVOID pParam)
{
TRACE(_T("in Detect Thread"));
CYsATModem* pThis=(CYsATModem*)pParam;
DWORD dwEvent;
DWORD dwTime;
int iRing=0;
pThis->m_bCD=0;
while(1==pThis->WaitEvent(&dwEvent,INFINITE))
{
if(dwEvent&EV_DSR)
{
pThis->SetEvent(0);
//糟啦,modem坏啦!!!
TRACE(_T("My God!!! the modem broken!!!\n"));
pThis->Purge(PURGE_ALL);
pThis->ChangeMode(MODE_UNMODEM);
TRACE(_T("Quit Detect Thread"));
return 1;
}
else if(dwEvent&EV_RING)//win95不支持这种通知
{
//这里有个问题,如果对方拨号一声后,挂断,计数器没清零,第二次就会出问题
if(iRing>0)
{
if(GetTickCount()-dwTime>10000)
iRing=0;//如果两次响铃大于10秒钟,重设为0
}
dwTime=GetTickCount();
iRing++;
CString s;
s.Format("ring count=%d %d Mode=%d\n",iRing,pThis->m_nRingCount,pThis->m_nMode);
TRACE(s);
if(pThis->m_nMode==MODE_COMMAND)
{
if(iRing>=pThis->m_nRingCount)
{
iRing=0;
#ifdef USER_ANSWER
Sleep(500);
pThis->SendAT(CMD_ATA);
#endif
AfxBeginThread(WaitThread,pThis);
}
}
}
else if(dwEvent&EV_RLSD)
{
CString s;
s.Format("\nCD灯改变 @@@ %d -%d\n",pThis->m_nMode,pThis->m_bCD);
TRACE(s);
if(pThis->m_nMode==MODE_DATA)
{
pThis->m_bCD=FALSE;
TRACE("Modem Disconnect!!!!\n");
ResetEvent(pThis->m_hConnected);
pThis->ChangeMode(MODE_COMMAND);
pThis->HangUp();
if(pThis->m_Thread)
{
if(WAIT_OBJECT_0!=WaitForSingleObject(pThis->m_Thread->m_hThread,10000))
{
TerminateThread(pThis->m_Thread->m_hThread,-11);
}
delete pThis->m_Thread;
pThis->m_Thread=NULL;
}
}
else if(pThis->m_nMode==MODE_CONNECTING)
{
pThis->m_bCD=TRUE;
pThis->StopRead();
pThis->Purge(PURGE_ALL);
pThis->m_Thread = AfxBeginThread(CYsATModem::ReadCommThread,(LPVOID)pThis);
if(!pThis->m_Thread)
{
pThis->ChangeMode(MODE_COMMAND);
pThis->SetLastError(_TEXT("Start read comm thread error"));
return FALSE;
}
pThis->m_Thread->m_bAutoDelete=FALSE;
::SetEvent(pThis->m_hConnected);
pThis->ChangeMode(MODE_DATA);
TRACE("Modem connect!!!!\n");
//无处理
}
else pThis->m_bCD=FALSE;//如果正在拨号的时候断线,可能会出现CD变化?
}
}
TRACE(_T("Quit Detect Thread"));
return 1;
}
/*************************2001.10.30 ycat *********************************************
FUNCTION: UINT CYsATModem::ReadCommThread(LPVOID pParam)
PURPOSE: 线程函数,把串口读入缓冲区的字符,写到自己维护的缓冲区中,并判断断线
PARAMETERS:
pParam:指向CYsATModem类
RETURN VALUE:
COMMENTS: 断线的处理,也许还要改进
**********************************************************************/
UINT CYsATModem::ReadCommThread(LPVOID pParam)
{
//judge if no carrier
char strJudge[]=ECHO_NOCARRIER;
//current judge string position
int iJudge=0;
int iJudgeSize=strlen(strJudge);
TRACE("Start Thread\n");
CYsATModem* pThis=(CYsATModem*)pParam;
DWORD dwInterTimeOut=INFINITE;//读每个字符之间的等待时间
int i;
BYTE chRead;
DWORD dwHaveRead;
while(1)
{
do
{
//read one char
i=pThis->ReadComm(&chRead,1,&dwHaveRead,dwInterTimeOut);
if (1==i)
{
TRACE(_TEXT("##:%02x\n"),chRead,chRead);
pThis->m_pQueue->Put(&chRead);
}
else if(i==-3)
{
TRACE(_TEXT("stop event set!~\n"));
//user hangup
i=TRUE;
goto Exit;
}
else if(i==-1) //非超时
{
TRACE(_TEXT("in Function Read Error code%d\n"),i);
i=FALSE;
goto Exit;
}
}
while(dwHaveRead);
}//while
Exit:
TRACE(_TEXT("End Read comm Thread\n"));
if(!i) TRACE(_TEXT("there are some error occur in thread\n"));
return i;
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CYsATModem::CYsATModem()
{
m_nRingCount=2;
m_bInit=FALSE;
m_bTestMode=FALSE;
ChangeMode(MODE_UNINITIALIZE);
m_pQueue=new CYsQueue(QUEUE_SIZE);
m_Thread=NULL;
//顺序不能变
pstrCmdString[0]=ECHO_OK;
pstrCmdString[1]=ECHO_CONNECT;
pstrCmdString[2]=ECHO_RING;
pstrCmdString[3]=ECHO_NOCARRIER;
pstrCmdString[4]=ECHO_ERROR;
pstrCmdString[5]=ECHO_CONNECT1200;
pstrCmdString[6]=ECHO_NODIALTONE;
pstrCmdString[7]=ECHO_BUSY;
pstrCmdString[8]=ECHO_NOANSWER;
m_hConnected=CreateEvent(NULL,TRUE,FALSE,NULL);
ResetError();
}
CYsATModem::~CYsATModem()
{
#ifndef USER_ANSWER
if(m_nMode==MODE_COMMAND)
SendAT(CMD_ATS0);
#endif
//because m_Thread->m_bAutoDelete set FALSE
if(m_pQueue)delete m_pQueue;
}
/*************************2001.10.30 ycat *********************************************
/*************************2002.04.15 ycat *********************************************
FUNCTION: BOOL CYsATModem::DialUp(LPTSTR strDial,int iTime)
PURPOSE: 用AT命令建立连接
PARAMETERS:
strDial:要拨号的号码
iTime:如果不为0,如果当前状态为连接状态,或线路忙(转成等待方式),等待的时间
RETURN VALUE:
如果操作成功,返回TRUE,如果失败返回FALSE
COMMENTS:
1)发送ATDXXX后,会段时间等待,连接字符串的返回,
如果另一边一拨号成功就发送数据,很可能会导致数据丢失
2)对电话号码的支持有待测试,特别字符
**********************************************************************/
BOOL CYsATModem::DialUp(LPCTSTR strDial)
{
if(m_bTestMode)return TRUE;
if(m_nMode==MODE_UNINITIALIZE||m_nMode==MODE_UNMODEM)
if(m_bInit)
{
if(!InitModem(m_nPort,m_iBaud,2,m_hWnd))
return FALSE;
}
if(m_nMode==MODE_DATA)
{
return TRUE;//have connected
}
if(m_nMode==MODE_CONNECTING)//connecting
{
//wait connect success
if(WAIT_OBJECT_0==WaitForSingleObject(m_hConnected,DIALTIME_START))
return TRUE;//have connected
return FALSE;
}
if(m_nMode!=MODE_COMMAND)//MODE_DIALING MODE_WAITRING
return FALSE;
CHAR strTemp[200];
lstrcpy(strTemp,CMD_ATD);
lstrcat(strTemp,(LPCTSTR)strDial);
SendAT(strTemp);
return DetectConnect();
}
/*************************2001.10.30 ycat *********************************************
FUNCTION: int CYsATModem::DetectConnect()
PURPOSE: 检测连接
PARAMETERS:
RETURN VALUE:
如果操作成功,返回TRUE,如果失败返回FALSE
COMMENTS:
**********************************************************************/
int CYsATModem::DetectConnect()
{
if(m_nMode!=MODE_COMMAND) return FALSE;
ChangeMode(MODE_CONNECTING);
CHAR strTemp[200];
Sleep(3000);
//读字符
DWORD dwRead;
int nErr;
int nRet=FALSE;
Purge(PURGE_ALL);
TRACE("\n Clear \n");
memset(strTemp,0,200);
nErr=this->ReadComm((PBYTE)strTemp,200,&dwRead,DIALTIME_START,DIALTIME_INTER);
TRACE(strTemp);
/* if(nErr!=-2)
{
goto Exit;
}
strTemp[dwRead]='\0';
i=CheckString(strTemp);
//find AT command string
if(i==CODE_CONNECT) nRet=TRUE;
else if(i==CODE_CANNTFIND)//can't fine AT command string
{
TRACE(_TEXT("Unknow string %s\n"),strTemp);
goto Exit;
}
else// if(i==CODE_BUSY||i==CODE_NODIALTONE)
{
goto Exit;
}
if(m_nMode!=MODE_CONNECTING) return m_bCD;//可能中间运行了hangup()*/
//Exit:
if(!m_bCD)
{
SendAT(CMD_AT);//打断连接
Sleep(500);
Purge(PURGE_ALL);
ChangeMode(MODE_COMMAND);
}
else ChangeMode(MODE_DATA);
return m_bCD;
}
/*************************2001.10.30 ycat *********************************************
FUNCTION: BOOL InitModem(UINT nPort,HWND hWnd)
PURPOSE: 生成串口文件句柄,
发送AT命令查看Modem是否正常,
生成一个挂起的收数线程
PARAMETERS:
nPort:串口号,com1为1,com2为2
hWnd:用来接收消息的窗口
RETURN VALUE:
如果操作成功,返回TRUE,如果失败返回FALSE
COMMENTS:
**********************************************************************/
BOOL CYsATModem::InitModem(UINT nPort,UINT uBaud,int iRingCount,HWND hWnd)
{
m_bCD=FALSE;
m_nRingCount=iRingCount;
if(!m_bTestMode)
{
if(m_nMode!=MODE_UNINITIALIZE&&m_nMode!=MODE_UNMODEM) return TRUE;
}
//create comm
if(!Create(nPort))
{
SetLastError(_TEXT("Create Comm error"));
return FALSE;
}
if(!SetComm(uBaud))
{
SetLastError(_TEXT("Set comm error"));
return FALSE;
}
m_hWnd=hWnd;
//clear comm buffer
if(!Purge(PURGE_ALL))
{
return FALSE;
}
m_pQueue->Clear();
if(m_bTestMode) return TRUE;
ChangeMode(MODE_UNMODEM);
int i;
TCHAR buffer[50];
DWORD length=0;
//send ATZ0,复位命令
if(!SendAT(CMD_ATZ0))
{
return FALSE;
}
//if echo don't open then must timeout
i=ReadComm((PBYTE)buffer,11,&length,WAITTIME);
if(i!=1&&i!=-2)
{
SetLastError(_TEXT("Read comm error"));
return FALSE;
}
buffer[length]='\0';
i=CheckString(buffer);
if(i!=CODE_OK)
{
SetLastError(_TEXT("Cann't find OK string"));
return FALSE;
}
//取消回显
if(!SendAT(CMD_ATE))
{
return FALSE;
}
i=ReadComm((PBYTE)buffer,10,&length,WAITTIME);
if(1!=i)
{
SetLastError(_TEXT("Read comm error"));
return FALSE;
}
buffer[length]='\0';
i=CheckString(buffer);
if(i!=CODE_OK)
{
SetLastError(_TEXT("Cann't find OK string"));
return FALSE;
}
#ifndef USER_ANSWER
TCHAR temp[10];
lstrcpy(buffer,"ATS0=");
sprintf(temp,"%d",iRingCount);
lstrcat(buffer,temp);
//send 设置自动应答
SendAT(buffer);
ReadComm((PBYTE)buffer,6,&length,WAITTIME);
buffer[length]='\0';
i=CheckString(buffer);
if(i!=CODE_OK)
{
SetLastError(_TEXT("Set autoreply mode fail"));
return FALSE;
}
#endif
//clear comm buffer
if(!Purge(PURGE_ALL))
{
return FALSE;
}
TRACE("Com%d InitModem Success \n",m_nPort);
ChangeMode(MODE_COMMAND);
if(!SetEvent(EV_DSR|EV_RING|EV_RLSD))//设备就续状态改变性号,现在已经就续,如果收到这个信号表示modem出问题了
{
SetLastError(_TEXT("Set comm event error"));
return FALSE;
}
AfxBeginThread(DetectModemThread,this);
ResetError();
m_bInit=TRUE;
return TRUE;
}
/*************************2001.10.30 ycat *********************************************
BOOL CYsATModem::SendAT(LPCSTR strCmd,BOOL AddReturn)
PURPOSE: 发送AT命令
PARAMETERS:
strCmd:要发送的AT命令
AddReturn:指明是否要在AT命令后面加上回车
RETURN VALUE:
如果操作成功,返回TRUE,如果失败返回FALSE
COMMENTS:
1)大多数AT命令要加上回车符,才能运行,但+++却不同,不要加回车
所以不支持+++命令
**********************************************************************/
BOOL CYsATModem::SendAT(LPCSTR strCmd,BOOL AddReturn)
{
//在传送data模式
if(m_nMode==MODE_DATA)
{
SetLastError(_TEXT("Send AT Command error"));
return FALSE;
}
TCHAR buffer[50];
lstrcpy(buffer,strCmd);
lstrcat(buffer,"\r\n");//只有+++,可以省\n
TRACE("send AT command %s\n",buffer);
// DWORD dw;
// WaitEvent(&dw,0);
//如果strCmd中间含有值为0的字符,将会产生不良后果
if(WriteComm((PBYTE)buffer,strlen(buffer))==1)
return TRUE;
SetLastError(_TEXT("Send AT Command error"));
return FALSE;
}
/*
挂断连接,进入MODE_COMMAND状态
后面被取消的程序挂断连接,有时不能很好运行
*/
BOOL CYsATModem::HangUp()
{
if(m_bTestMode)return TRUE;
if(m_nMode==MODE_UNINITIALIZE) return TRUE;
//如果正在连接,发送任意字符,则会中断
if(m_nMode==MODE_CONNECTING)
{
SendAT(CMD_AT);
Sleep(500);
}
if(!Purge(PURGE_ALL)) return FALSE;
if(!Clear(PURGE_ALL)) return FALSE;
if(m_nMode==MODE_COMMAND) return TRUE;
if(m_nMode==MODE_UNMODEM) return TRUE;
TCHAR buffer[50];
DWORD length=0;
if(m_Thread)
{
if(WAIT_OBJECT_0!=WaitForSingleObject(m_Thread->m_hThread,10000))
{
TerminateThread(m_Thread->m_hThread,-11);
}
delete m_Thread;
m_Thread=NULL;
}
if(m_nMode!=MODE_DATA) return TRUE;
ResetEvent(m_hConnected);
ChangeMode(MODE_COMMAND);
if(!Purge(PURGE_ALL))
return FALSE;//comm error
Sleep(1000);
//change mode to MODE_COMMAND
//+++ 不用换行
TCHAR strSend[]=_TEXT("+++");
if(1!=WriteComm((PBYTE)strSend,3)) return FALSE;//comm error
TRACE(_TEXT("Send +++ \n"));
int i;
DWORD dwReaded;
if(-1==ReadComm((PBYTE)buffer,6,&dwReaded,WAITADDADDADDTIME))
return FALSE;//comm error
buffer[dwReaded]='\0';
i=CheckString(buffer);
if(i!=CODE_OK)
{
SetLastError(_TEXT("send +++ but cann't recept OK"));
TRACE("1 %s\n",buffer);
return HangUp2();
}
//hangup command
SendAT(CMD_ATH0);
if(-1==ReadComm((PBYTE)buffer,6,&dwReaded,WAITATHTIME)) return FALSE;
buffer[dwReaded]='\0';
i=CheckString(buffer);
//wait for OK
if(i!=CODE_OK)
{
SetLastError(_TEXT("send ATH0 but cann't recept OK"));
TRACE("2 %s\n",buffer);
return HangUp2();
}
TRACE("hang up OK!!!\n");
ChangeMode(MODE_COMMAND);
return TRUE;
}
/*************************2001.10.30 ycat *********************************************
FUNCTION: BOOL CYsATModem::Clear(DWORD dwType)
PURPOSE: 清除串口
PARAMETERS:
nType的值及说明,可组合起来用
nType=PURGE_TXABORT Terminates all outstanding
overlapped write operations and returns
immediately, even if the write operations
have not been completed.
nType=PURGE_RXABORT Terminates all outstanding
overlapped read operations and returns
immediately, even if the read operations
have not been completed.
nType=PURGE_TXCLEAR Clears the output buffer
(if the device driver has one).
nType=PURGE_RXCLEAR Clears the input buffer
(if the device driver has one).
RETURN VALUE:
如果操作成功,返回TRUE,如果失败返回FALSE
COMMENTS:
1)读缓冲区实际上是m_pQueue里的缓冲区
2)PURGE_RXABORT不起作用
**********************************************************************/
BOOL CYsATModem::Clear(DWORD dwType)
{
if(m_bTestMode)return Purge(dwType);
if(dwType&PURGE_RXCLEAR)
{
if(!m_pQueue->Clear())
{
SetLastError(_T("In clear() clear queue error"));
return FALSE;
}
}
if(dwType&PURGE_TXCLEAR)
if(!Purge(PURGE_TXCLEAR))
{
SetLastError(_T("In clear() clear tx buffer error"));
return FALSE;
}
if(dwType&PURGE_TXABORT)
if(!Purge(PURGE_TXABORT))
{
SetLastError(_T("In clear() clear tx abort error"));
return FALSE;
}
return TRUE;
}
/*************************2001.10.30 ycat *********************************************
FUNCTION: int CYsATModem::Write(LPCSTR lpstrWrite,DWORD dwCount)
PURPOSE: 写数据
PARAMETERS:
lpstrWrite:要写的字符串
dwCount: 字符串的长度
RETURN VALUE:
返回1为正常
返回-1为失败
返回-4为断线
COMMENTS:
**********************************************************************/
int CYsATModem::Write(LPCSTR lpstrWrite,DWORD dwCount)
{
if(!m_bTestMode)
{
if(m_nMode==MODE_COMMAND) return -4;
if(m_nMode!=MODE_DATA) return -1;
}
int nRet=CYsComm::WriteComm((PBYTE)lpstrWrite,dwCount);
if(nRet==1) return 1;
return -1;
}
/*************************2001.10.30 ycat *********************************************
FUNCTION: int CYsATModem::Read(LPTSTR lpstrRead,DWORD dwCount,
DWORD* dwHaveReaded,DWORD nTimeOut)
PURPOSE: 读数据
PARAMETERS:
lpstrRead: 放读出字符串的缓冲区
dwCount: 缓冲区的长度
dwHaveReaded: 实际读到的字符数
nTimeOut: 超时
RETURN VALUE:
返回1为正常
返回-1为失败
返回-2为超时
返回-4为断线
COMMENTS:
**********************************************************************/
int CYsATModem::Read(LPTSTR lpstrRead,DWORD dwCount,
DWORD* dwHaveReaded,DWORD nTimeOut)
{
if(m_bTestMode)
{
return CYsComm::ReadComm((PBYTE)lpstrRead,dwCount,dwHaveReaded,nTimeOut);
}
if(m_nMode==MODE_COMMAND) return -4;
if(m_nMode!=MODE_DATA) return -1;
int nRet;
DWORD dwTimeAfter;
DWORD dwTimeUsed;
DWORD dwTimeBefore;
for(DWORD i=0;iGet((PBYTE)(lpstrRead+i),nTimeOut))
{
//TRACE("Read2 Timeout %ld \n",nTimeOut);
nRet=-2;//超时
goto Exit;
}
dwTimeAfter=GetTickCount();
dwTimeUsed=dwTimeAfter-dwTimeBefore;
//断线
if(m_nMode==MODE_COMMAND)
{
nRet=-3;
goto Exit;
}
if(dwTimeUsed>nTimeOut)
{
if(iGetCount();
}
//return state describe string
CString CYsATModem::GetStateDesc()
{
if(m_bTestMode) return "测试状态";
switch(m_nMode)
{
case MODE_UNINITIALIZE:
return _TEXT("串口有问题");
case MODE_UNMODEM:
return _TEXT("Modem有问题");
case MODE_COMMAND:
return _TEXT("可以拨号");
case MODE_CONNECTING:
return _TEXT("正在建立连接");
case MODE_DATA:
return _TEXT("远程Modem连接");//(如不成功,返回2状态)
default:
return _TEXT("Unknow state!");
}
}
//如果HangUp()不成功,只好调用HangUp2()了
BOOL CYsATModem::HangUp2()
{
if(m_bTestMode)return TRUE;
TRACE("\n\n In Hangup 2\n\n");
ChangeMode(MODE_UNINITIALIZE);
Sleep(1000);
return InitModem(m_nPort,m_iBaud,m_nRingCount,m_hWnd);
}
void CYsATModem::ChangeMode(int newMode)
{
if(m_nMode!=newMode)
{
if(m_hWnd)
PostMessage(m_hWnd,WM_MODEM_CHANGE,newMode,m_nPort);
m_nMode=newMode;
TRACE("Mode Change =%d \n",m_nMode);
}
}