www.pudn.com > GsmToUart.rar > GsmToUartDlg.cpp


// GsmToUartDlg.cpp : implementation file 
// 
 
#include "stdafx.h" 
#include "GsmToUart.h" 
#include "GsmToUartDlg.h" 
#include "UartSettingDlg.h" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
 
///////////////////////////////////////////////////////////////////////////// 
// CAboutDlg dialog used for App About 
 
class CAboutDlg : public CDialog 
{ 
public: 
	CAboutDlg(); 
 
// Dialog Data 
	//{{AFX_DATA(CAboutDlg) 
	enum { IDD = IDD_ABOUTBOX }; 
	//}}AFX_DATA 
 
	// ClassWizard generated virtual function overrides 
	//{{AFX_VIRTUAL(CAboutDlg) 
	protected: 
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support 
	//}}AFX_VIRTUAL 
 
// Implementation 
protected: 
	//{{AFX_MSG(CAboutDlg) 
	//}}AFX_MSG 
	DECLARE_MESSAGE_MAP() 
}; 
 
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) 
{ 
	//{{AFX_DATA_INIT(CAboutDlg) 
	//}}AFX_DATA_INIT 
} 
 
void CAboutDlg::DoDataExchange(CDataExchange* pDX) 
{ 
	CDialog::DoDataExchange(pDX); 
	//{{AFX_DATA_MAP(CAboutDlg) 
	//}}AFX_DATA_MAP 
} 
 
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) 
	//{{AFX_MSG_MAP(CAboutDlg) 
		// No message handlers 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// CGsmToUartDlg dialog 
 
CGsmToUartDlg::CGsmToUartDlg(CWnd* pParent /*=NULL*/) 
	: CDialog(CGsmToUartDlg::IDD, pParent) 
{ 
	//{{AFX_DATA_INIT(CGsmToUartDlg) 
	m_nViewSmsRead = _T(""); 
	m_nViewSmsSend = _T(""); 
	m_nPhoneNumber = _T(""); 
	m_nResultAt = _T(""); 
	m_nCommandAt = _T(""); 
	m_nSignalintensity = _T(""); 
	m_nSmsSerNumber = _T(""); 
	m_nSmsSendNumber = _T(""); 
	//}}AFX_DATA_INIT 
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32 
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); 
	ComOpenFlag=0; 
	ComUseEnable=1; 
} 
 
void CGsmToUartDlg::DoDataExchange(CDataExchange* pDX) 
{ 
	CDialog::DoDataExchange(pDX); 
	//{{AFX_DATA_MAP(CGsmToUartDlg) 
	DDX_Text(pDX, IDC_VIEWSMS_READ, m_nViewSmsRead); 
	DDX_Text(pDX, IDC_VIEWSMS_SEND, m_nViewSmsSend); 
	DDX_Text(pDX, IDC_PHONE_NUMBER, m_nPhoneNumber); 
	DDX_Text(pDX, IDC_RESULT_AT, m_nResultAt); 
	DDX_Text(pDX, IDC_COMMAND_AT, m_nCommandAt); 
	DDX_Text(pDX, IDC_SIGNALINTENSITY, m_nSignalintensity); 
	DDX_Text(pDX, IDC_SMSSERNUMBER, m_nSmsSerNumber); 
	DDX_Text(pDX, IDC_SMSSENDNUMBER, m_nSmsSendNumber); 
	//}}AFX_DATA_MAP 
} 
 
BEGIN_MESSAGE_MAP(CGsmToUartDlg, CDialog) 
	//{{AFX_MSG_MAP(CGsmToUartDlg) 
	ON_WM_SYSCOMMAND() 
	ON_WM_PAINT() 
	ON_WM_QUERYDRAGICON() 
	ON_BN_CLICKED(IDC_RUN_AT, OnRunAt) 
	ON_BN_CLICKED(IDC_SEND_SMS, OnSendSms) 
	ON_BN_CLICKED(IDC_READ_SMS, OnReadSms) 
	ON_BN_CLICKED(IDC_CLOSE_PHONE, OnClosePhone) 
	ON_BN_CLICKED(IDC_ONLINE_PHONE, OnOnlinePhone) 
	ON_BN_CLICKED(IDC_UART_SETTING, OnUartSetting) 
	ON_BN_CLICKED(IDC_OPEN_UART, OnOpenUart) 
	ON_BN_CLICKED(IDC_CLOSE_UART, OnCloseUart) 
	ON_WM_TIMER() 
	ON_BN_CLICKED(IDC_HELP_AT, OnHelpAt) 
	ON_BN_CLICKED(IDC_LOADSMS, OnLoadsms) 
	ON_BN_CLICKED(IDC_SAVESMS, OnSavesms) 
	ON_BN_CLICKED(IDC_VIEWNOTREADSMS, OnViewnotreadsms) 
	ON_BN_CLICKED(IDC_DELETESMS, OnDeletesms) 
	ON_BN_CLICKED(IDC_SETSMSSERNUMBER, OnSetsmssernumber) 
	ON_BN_CLICKED(IDC_GETSMSSERNUMBER, OnGetsmssernumber) 
	ON_BN_CLICKED(IDC_CLEARATRESULT, OnClearatresult) 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// CGsmToUartDlg message handlers 
 
BOOL CGsmToUartDlg::OnInitDialog() 
{ 
	CDialog::OnInitDialog(); 
 
	// Add "About..." menu item to system menu. 
 
	// IDM_ABOUTBOX must be in the system command range. 
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); 
	ASSERT(IDM_ABOUTBOX < 0xF000); 
 
	char* pFileName = "TmpSetting.dat"; 
	CStdioFile ComSetting; 
	if (!ComSetting.Open ("TmpSetting.dat", CFile::modeRead | CFile::typeText)) 
	{ 
		AfxMessageBox("打开文件TmpSetting.dat出错!"); 
		return FALSE; 
	} 
 
	ComSetting.ReadString(nComBaud); 
	ComSetting.ReadString(nComSel); 
	ComSetting.ReadString(nComData); 
	CString	tmptring; 
	ComSetting.ReadString(tmptring); 
	sscanf(tmptring,"%d", &nComStop); 
	ComSetting.ReadString(tmptring); 
	sscanf(tmptring,"%d", &nComParity); 
	ComSetting.ReadString(tmptring); 
	sscanf(tmptring,"%d", &nComShake); 
	ComSetting.Close(); 
	ComOpenFlag=0; 
	ComUseEnable=1; 
	SetTimer(100,1000,NULL); 
 
 
	CMenu* pSysMenu = GetSystemMenu(FALSE); 
	if (pSysMenu != NULL) 
	{ 
		CString strAboutMenu; 
		strAboutMenu.LoadString(IDS_ABOUTBOX); 
		if (!strAboutMenu.IsEmpty()) 
		{ 
			pSysMenu->AppendMenu(MF_SEPARATOR); 
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); 
		} 
	} 
 
	// Set the icon for this dialog.  The framework does this automatically 
	//  when the application's main window is not a dialog 
	SetIcon(m_hIcon, TRUE);			// Set big icon 
	SetIcon(m_hIcon, FALSE);		// Set small icon 
	 
	// TODO: Add extra initialization here 
	 
	return TRUE;  // return TRUE  unless you set the focus to a control 
} 
 
void CGsmToUartDlg::OnSysCommand(UINT nID, LPARAM lParam) 
{ 
	if ((nID & 0xFFF0) == IDM_ABOUTBOX) 
	{ 
		CAboutDlg dlgAbout; 
		dlgAbout.DoModal(); 
	} 
	else 
	{ 
		CDialog::OnSysCommand(nID, lParam); 
	} 
} 
 
// If you add a minimize button to your dialog, you will need the code below 
//  to draw the icon.  For MFC applications using the document/view model, 
//  this is automatically done for you by the framework. 
 
void CGsmToUartDlg::OnPaint()  
{ 
	if (IsIconic()) 
	{ 
		CPaintDC dc(this); // device context for painting 
 
		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); 
 
		// Center icon in client rectangle 
		int cxIcon = GetSystemMetrics(SM_CXICON); 
		int cyIcon = GetSystemMetrics(SM_CYICON); 
		CRect rect; 
		GetClientRect(&rect); 
		int x = (rect.Width() - cxIcon + 1) / 2; 
		int y = (rect.Height() - cyIcon + 1) / 2; 
 
		// Draw the icon 
		dc.DrawIcon(x, y, m_hIcon); 
	} 
	else 
	{ 
		CDialog::OnPaint(); 
	} 
} 
 
// The system calls this to obtain the cursor to display while the user drags 
//  the minimized window. 
HCURSOR CGsmToUartDlg::OnQueryDragIcon() 
{ 
	return (HCURSOR) m_hIcon; 
} 
 
void CGsmToUartDlg::OnRunAt()  
{ 
	// TODO: Add your control notification handler code here 
	CString tmpSend;  
	int nLength; 
	char ReceiveData[128];  
 
	if(!ComOpenFlag) 
	{ 
	AfxMessageBox(_T("串口未打开!")); 
	return ; 
	} 
	if(!ComUseEnable) 
	{ 
	AfxMessageBox(_T("串口在使用中!")); 
	return ; 
	} 
	ComUseEnable=0; 
	UpdateData(FALSE); 
	tmpSend=m_nCommandAt; 
	nLength=tmpSend.GetLength(); 
	WriteComm(tmpSend,nLength); 
 
	nLength = ReadComm(ReceiveData,128);    
	ReceiveData[nLength+1]='\0'; 
	m_nResultAt=ReceiveData; 
	m_nResultAt+="\r\n"; 
	UpdateData(FALSE); 
	ComUseEnable=1;	 
 
} 
 
void CGsmToUartDlg::OnSendSms()  
{ 
	// TODO: Add your control notification handler code here 
 
} 
 
void CGsmToUartDlg::OnReadSms()  
{ 
	// TODO: Add your control notification handler code here 
	 
} 
 
void CGsmToUartDlg::OnClosePhone()  
{ 
	// TODO: Add your control notification handler code here 
 
} 
 
void CGsmToUartDlg::OnOnlinePhone()  
{ 
	// TODO: Add your control notification handler code here 
	UpdateData(TRUE); 
 
} 
 
void CGsmToUartDlg::OnUartSetting()  
{ 
	// TODO: Add your control notification handler code here 
	CUartSettingDlg dlg; 
 
	dlg.m_nComSel=nComSel; 
	dlg.m_nComData=nComData; 
	dlg.m_nComBaud=nComBaud; 
	dlg.m_nComParity=nComParity; 
	dlg.m_nComShake=nComShake; 
	dlg.m_nComStop=nComStop; 
 
	if(dlg.DoModal()==IDOK) 
	{ 
		OnCloseUart(); 
		nComSel=dlg.m_nComSel; 
		nComData=dlg.m_nComData; 
		nComBaud=dlg.m_nComBaud; 
		nComParity=dlg.m_nComParity; 
		nComShake=dlg.m_nComShake; 
		nComStop=dlg.m_nComStop; 
		OnOpenUart(); 
	}	 
} 
 
void CGsmToUartDlg::OnOpenUart()  
{ 
	// TODO: Add your control notification handler code here 
	sscanf(nComBaud,"%d", &dwBaud); 
	sscanf(nComData,"%d", &dwData); 
	CString strCom; 
	CString TestData; 
	if(ComOpenFlag) 
	{ 
		AfxMessageBox(_T("串口已经打开!")); 
	} 
	else 
	{ 
		strCom.Format(nComSel); 
 
		// 打开指定的串口 
		hCom1 = ::CreateFile(strCom,GENERIC_READ | GENERIC_WRITE,0,NULL, 
			OPEN_EXISTING,0,NULL); 
 
		// 获得串口的配置信息 
		COMMCONFIG ComCfg; 
		DWORD dwSize2 = sizeof(ComCfg); 
		if (!::GetCommConfig(hCom1,&ComCfg,&dwSize2)) 
		{ 
			AfxMessageBox("读取串口配置失败!"); 
			::CloseHandle(hCom1); 
			return; 
		} 
 
		// 获得当前的串口配置状态 
		DCB dcb; 
		if (!GetCommState(hCom1,&dcb)) 
		{ 
			AfxMessageBox(_T("读取串口状态失败!")); 
			::CloseHandle(hCom1); 
			return; 
		} 
	 
		// 设置奇偶校验方式 
		switch (nComParity) 
		{ 
		case 0: 
			// 不校验 
			dcb.Parity = NOPARITY;     
			break;	 
		case 1: 
			// 奇校验 
			dcb.Parity = ODDPARITY;    
			break; 
		case 2: 
			// 偶校验 
			dcb.Parity = EVENPARITY;   
			break; 
		case 3: 
			// MARK方式 
			dcb.Parity = MARKPARITY;   
			break; 
		case 4: 
			// SPACE方式 
			dcb.Parity = SPACEPARITY;  
			break; 
		} 
	 
		// 设置数据位格式 
		dcb.ByteSize = dwData; 
 
		// 设置波特率 
		dcb.BaudRate = dwBaud; 
 
		// 设置停止位方式 
		switch (nComStop) 
		{ 
		case 0: 
			// 停止位为1位 
			dcb.StopBits = ONESTOPBIT; 
			break; 
		case 1: 
			// 停止位为1.5位 
			dcb.StopBits = ONE5STOPBITS;  
			break; 
		case 2: 
			// 停止位为2位 
			dcb.StopBits = TWOSTOPBITS;   
			break; 
		} 
 
		// 设置灵敏度 
		dcb.fDsrSensitivity = FALSE; 
 
		// 设置流控制方式 
		switch (nComShake) 
		{ 
		case 0: 
			// 无流量控制 
			dcb.fOutxCtsFlow = FALSE; 
			dcb.fOutxDsrFlow = FALSE; 
			dcb.fOutX = FALSE; 
			dcb.fInX = FALSE; 
			break; 
		case 1: 
			// RTS控制,监视CTS信号 
			dcb.fOutxCtsFlow = TRUE; 
			dcb.fOutxDsrFlow = FALSE; 
			dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; 
			dcb.fOutX = FALSE; 
			dcb.fInX = FALSE; 
			break; 
		case 2: 
			// DTR控制,监视CTS信号 
			dcb.fOutxCtsFlow = TRUE; 
			dcb.fOutxDsrFlow = FALSE; 
			dcb.fDtrControl = DTR_CONTROL_HANDSHAKE; 
			dcb.fOutX = FALSE; 
			dcb.fInX = FALSE; 
			break; 
		case 3: 
			// RTS控制,监视DSR信号 
			dcb.fOutxCtsFlow = FALSE; 
			dcb.fOutxDsrFlow = TRUE; 
			dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; 
			dcb.fOutX = FALSE; 
			dcb.fInX = FALSE; 
			break; 
		case 4: 
			// DTR控制,监视DSR信号 
			dcb.fOutxCtsFlow = FALSE; 
			dcb.fOutxDsrFlow = TRUE; 
			dcb.fDtrControl = DTR_CONTROL_HANDSHAKE; 
			dcb.fOutX = FALSE; 
			dcb.fInX = FALSE; 
			break; 
		case 5: 
			// XON/XOFF控制方式 
			dcb.fOutxCtsFlow = FALSE; 
			dcb.fOutxDsrFlow = FALSE; 
			dcb.fOutX = TRUE; 
			dcb.fInX = TRUE; 
			dcb.XonChar = 0x11; 
			dcb.XoffChar = 0x13; 
			dcb.XoffLim = 100; 
			dcb.XonLim = 100; 
			break; 
		} 
		COMMTIMEOUTS timeouts = {   // 串口超时控制参数 
			100,					// 读字符间隔超时时间: 100 ms 
	        1,						// 读操作时每字符的时间: 1 ms (n个字符总共为n ms) 
		    500,					// 基本的(额外的)读超时时间: 500 ms 
			1,						// 写操作时每字符的时间: 1 ms (n个字符总共为n ms) 
			100};					// 基本的(额外的)写超时时间: 100 ms 
 
		SetCommTimeouts(hCom1,&timeouts); 
 
		SetupComm(hCom1, 4096, 1024);     // 设置输入输出缓冲区大小 
 
 
		// 将设定的参数值用于该串口 
		if (!SetCommState(hCom1, &dcb)) 
		{ 
			AfxMessageBox(_T("设置COM端口状态失败!")); 
			::CloseHandle(hCom1); 
			return; 
		} 
		AfxMessageBox("串口打开成功!"); 
		ComOpenFlag=1; 
	} 
	 
} 
 
void CGsmToUartDlg::OnCloseUart()  
{ 
	// TODO: Add your control notification handler code here 
	if(ComOpenFlag) 
	{ 
		ComOpenFlag=0; 
		WaitForSingleObject(hCom1,1500); 
		CloseHandle(hCom1); 
		//AfxMessageBox(_T("串口1关闭成功!")); 
	} 
} 
 
void CGsmToUartDlg::OnTimer(UINT nIDEvent)  
{ 
	// TODO: Add your message handler code here and/or call default 
	UpdateData(TRUE);	 
	CDialog::OnTimer(100); 
 
} 
 
// 7-bit编码 
// pSrc: 源字符串指针 
// pDst: 目标编码串指针 
// nSrcLength: 源字符串长度 
// 返回: 目标编码串长度 
int CGsmToUartDlg::GsmEncode7bit(const char *pSrc, unsigned char *pDst, int nSrcLength) 
{ 
	int nSrc;        // 源字符串的计数值 
    int nDst;        // 目标编码串的计数值 
    int nChar;       // 当前正在处理的组内字符字节的序号,范围是0-7 
    unsigned char nLeft;    // 上一字节残余的数据 
     
    // 计数值初始化 
    nSrc = 0; 
    nDst = 0; 
     
    // 将源串每8个字节分为一组,压缩成7个字节 
    // 循环该处理过程,直至源串被处理完 
    // 如果分组不到8字节,也能正确处理 
    while(nSrc> nChar; 
            // 修改目标串的指针和计数值 pDst++; 
            nDst++;  
        }  
         
        // 修改源串的指针和计数值 
        pSrc++; nSrc++; 
    } 
     
    // 返回目标串长度 
    return nDst;  
} 
 
// 7-bit解码 
// pSrc: 源编码串指针 
// pDst: 目标字符串指针 
// nSrcLength: 源编码串长度 
// 返回: 目标字符串长度 
int CGsmToUartDlg::GsmDecode7bit(const unsigned char *pSrc, char *pDst, int nSrcLength) 
{ 
    int nSrc;        // 源字符串的计数值 
    int nDst;        // 目标解码串的计数值 
    int nByte;       // 当前正在处理的组内字节的序号,范围是0-6 
    unsigned char nLeft;    // 上一字节残余的数据 
     
    // 计数值初始化 
    nSrc = 0; 
    nDst = 0; 
     
    // 组内字节序号和残余数据初始化 
    nByte = 0; 
    nLeft = 0; 
     
    // 将源数据每7个字节分为一组,解压缩成8个字节 
    // 循环该处理过程,直至源数据被处理完 
    // 如果分组不到7字节,也能正确处理 
    while(nSrc> (7-nByte); 
     
        // 修改目标串的指针和计数值 
        pDst++; 
        nDst++; 
     
        // 修改字节计数值 
        nByte++; 
     
        // 到了一组的最后一个字节 
        if(nByte == 7) 
        { 
            // 额外得到一个目标解码字节 
            *pDst = nLeft; 
     
            // 修改目标串的指针和计数值 
            pDst++; 
            nDst++; 
     
            // 组内字节序号和残余数据初始化 
            nByte = 0; 
            nLeft = 0; 
        } 
     
        // 修改源串的指针和计数值 
        pSrc++; 
        nSrc++; 
    } 
     
    *pDst = 0; 
     
    // 返回目标串长度 
    return nDst; 
} 
 
// UCS2编码 
// pSrc: 源字符串指针 
// pDst: 目标编码串指针 
// nSrcLength: 源字符串长度 
// 返回: 目标编码串长度 
int CGsmToUartDlg::GsmEncodeUcs2(const char *pSrc, unsigned char *pDst, int nSrcLength) 
{ 
    int nDstLength;        // UNICODE宽字符数目 
    WCHAR wchar[128];      // UNICODE串缓冲区 
     
    // 字符串-->UNICODE串 
    nDstLength = ::MultiByteToWideChar(CP_ACP, 0, pSrc, nSrcLength, wchar, 128); 
     
    // 高低字节对调,输出 
    for(int i=0; i> 8; 
        // 后输出低位字节 
        *pDst++ = wchar[i] & 0xff; 
    } 
     
    // 返回目标编码串长度 
    return nDstLength * 2; 
} 
 
// UCS2解码 
// pSrc: 源编码串指针 
// pDst: 目标字符串指针 
// nSrcLength: 源编码串长度 
// 返回: 目标字符串长度 
int CGsmToUartDlg::GsmDecodeUcs2(const unsigned char *pSrc, char *pDst, int nSrcLength) 
{ 
    int nDstLength;        // UNICODE宽字符数目 
    WCHAR wchar[128];      // UNICODE串缓冲区 
     
    // 高低字节对调,拼成UNICODE 
    for(int i=0; i字符串 
    nDstLength = ::WideCharToMultiByte(CP_ACP, 0, wchar, nSrcLength/2, pDst, 160, NULL, NULL); 
     
    // 输出字符串加个结束符     
    pDst[nDstLength] = '\0';     
     
    // 返回目标字符串长度 
    return nDstLength; 
} 
 
// 可打印字符串转换为字节数据 
// 如:"C8329BFD0E01" --> {0xC8, 0x32, 0x9B, 0xFD, 0x0E, 0x01} 
// pSrc: 源字符串指针 
// pDst: 目标数据指针 
// nSrcLength: 源字符串长度 
// 返回: 目标数据长度 
int CGsmToUartDlg::GsmString2Bytes(const char *pSrc, unsigned char *pDst, int nSrcLength) 
{ 
    for(int i=0; i='0' && *pSrc<='9') 
        { 
            *pDst = (*pSrc - '0') << 4; 
        } 
        else 
        { 
            *pDst = (*pSrc - 'A' + 10) << 4; 
        } 
     
        pSrc++; 
     
        // 输出低4位 
        if(*pSrc>='0' && *pSrc<='9') 
        { 
            *pDst |= *pSrc - '0'; 
        } 
        else 
        { 
            *pDst |= *pSrc - 'A' + 10; 
        } 
        pSrc++; 
        pDst++; 
	} 
     
    // 返回目标数据长度 
    return nSrcLength / 2; 
} 
 
// 字节数据转换为可打印字符串 
// 如:{0xC8, 0x32, 0x9B, 0xFD, 0x0E, 0x01} --> "C8329BFD0E01"  
// pSrc: 源数据指针 
// pDst: 目标字符串指针 
// nSrcLength: 源数据长度 
// 返回: 目标字符串长度 
int CGsmToUartDlg::GsmBytes2String(const unsigned char *pSrc, char *pDst, int nSrcLength) 
{ 
    const char tab[]="0123456789ABCDEF";    // 0x0-0xf的字符查找表 
     
    for(int i=0; i> 4]; 
     
        // 输出高4位 
        *pDst++ = tab[*pSrc & 0x0f]; 
     
        pSrc++; 
    } 
     
    // 输出字符串加个结束符 
    *pDst = '\0'; 
     
    // 返回目标字符串长度 
    return nSrcLength * 2; 
} 
 
// 正常顺序的字符串转换为两两颠倒的字符串,若长度为奇数,补'F'凑成偶数 
// 如:"8613851872468" --> "683158812764F8" 
// pSrc: 源字符串指针 
// pDst: 目标字符串指针 
// nSrcLength: 源字符串长度 
// 返回: 目标字符串长度 
int CGsmToUartDlg::GsmInvertNumbers(const char *pSrc, char *pDst, int nSrcLength) 
{ 
    int nDstLength;   // 目标字符串长度 
    char ch;          // 用于保存一个字符 
     
    // 复制串长度 
    nDstLength = nSrcLength; 
     
    // 两两颠倒 
    for(int i=0; i "8613851872468" 
// pSrc: 源字符串指针 
// pDst: 目标字符串指针 
// nSrcLength: 源字符串长度 
// 返回: 目标字符串长度 
int CGsmToUartDlg::GsmSerializeNumbers(const char *pSrc, char *pDst, int nSrcLength) 
{ 
    int nDstLength;   // 目标字符串长度 
    char ch;          // 用于保存一个字符 
     
    // 复制串长度 
    nDstLength = nSrcLength; 
     
    // 两两颠倒 
    for(int i=0; iSCA);    // SMSC地址字符串的长度     
    buf[0] = (char)((nLength & 1) == 0 ? nLength : nLength + 1) / 2 + 1;    // SMSC地址信息长度 
    buf[1] = 0x91;        // 固定: 用国际格式号码 
    nDstLength = GsmBytes2String(buf, pDst, 2);        // 转换2个字节到目标PDU串 
    nDstLength += GsmInvertNumbers(pSrc->SCA, &pDst[nDstLength], nLength);    // 转换SMSC到目标PDU串 
     
    // TPDU段基本参数、目标地址等 
    nLength = strlen(pSrc->TPA);    // TP-DA地址字符串的长度 
    buf[0] = 0x11;            // 是发送短信(TP-MTI=01),TP-VP用相对格式(TP-VPF=10) 
    buf[1] = 0;               // TP-MR=0 
    buf[2] = (char)nLength;   // 目标地址数字个数(TP-DA地址字符串真实长度) 
    buf[3] = 0x91;            // 固定: 用国际格式号码 
    nDstLength += GsmBytes2String(buf, &pDst[nDstLength], 4);  // 转换4个字节到目标PDU串 
    nDstLength += GsmInvertNumbers(pSrc->TPA, &pDst[nDstLength], nLength); // 转换TP-DA到目标PDU串 
     
    // TPDU段协议标识、编码方式、用户信息等 
    nLength = strlen(pSrc->TP_UD);    // 用户信息字符串的长度 
    buf[0] = pSrc->TP_PID;        // 协议标识(TP-PID) 
    buf[1] = pSrc->TP_DCS;        // 用户信息编码方式(TP-DCS) 
    buf[2] = 0;            // 有效期(TP-VP)为5分钟 
    if(pSrc->TP_DCS == GSM_7BIT)     
    { 
        // 7-bit编码方式 
        buf[3] = nLength;            // 编码前长度 
        nLength = GsmEncode7bit(pSrc->TP_UD, &buf[4], nLength+1) + 4;    // 转换TP-DA到目标PDU串 
    } 
    else if(pSrc->TP_DCS == GSM_UCS2) 
    { 
        // UCS2编码方式 
        buf[3] = GsmEncodeUcs2(pSrc->TP_UD, &buf[4], nLength);    // 转换TP-DA到目标PDU串 
        nLength = buf[3] + 4;        // nLength等于该段数据长度 
    } 
    else 
    { 
        // 8-bit编码方式 
        buf[3] = GsmEncode8bit(pSrc->TP_UD, &buf[4], nLength);    // 转换TP-DA到目标PDU串 
        nLength = buf[3] + 4;        // nLength等于该段数据长度 
    } 
    nDstLength += GsmBytes2String(buf, &pDst[nDstLength], nLength);        // 转换该段数据到目标PDU串 
     
    // 返回目标字符串长度 
    return nDstLength; 
} 
 
// PDU解码,用于接收、阅读短消息 
// pSrc: 源PDU串指针 
// pDst: 目标PDU参数指针 
// 返回: 用户信息串长度 
int CGsmToUartDlg::GsmDecodePdu(const char *pSrc, SM_PARAM *pDst) 
{ 
    int nDstLength;          // 目标PDU串长度 
    unsigned char tmp;       // 内部用的临时字节变量 
    unsigned char buf[256];  // 内部用的缓冲区 
     
    // SMSC地址信息段 
    GsmString2Bytes(pSrc, &tmp, 2);    // 取长度 
    tmp = (tmp - 1) * 2;    // SMSC号码串长度 
    pSrc += 4;              // 指针后移 
    GsmSerializeNumbers(pSrc, pDst->SCA, tmp);    // 转换SMSC号码到目标PDU串 
    pSrc += tmp;        // 指针后移 
     
    // TPDU段基本参数、回复地址等 
    GsmString2Bytes(pSrc, &tmp, 2);    // 取基本参数 
    pSrc += 2;        // 指针后移 
    if(tmp & 0x80) 
    { 
        // 包含回复地址,取回复地址信息 
        GsmString2Bytes(pSrc, &tmp, 2);    // 取长度 
        if(tmp & 1) tmp += 1;    // 调整奇偶性 
        pSrc += 4;          // 指针后移 
        GsmSerializeNumbers(pSrc, pDst->TPA, tmp);    // 取TP-RA号码 
        pSrc += tmp;        // 指针后移 
    } 
     
    // TPDU段协议标识、编码方式、用户信息等 
    GsmString2Bytes(pSrc, (unsigned char*)&pDst->TP_PID, 2);    // 取协议标识(TP-PID) 
    pSrc += 2;        // 指针后移 
    GsmString2Bytes(pSrc, (unsigned char*)&pDst->TP_DCS, 2);    // 取编码方式(TP-DCS) 
    pSrc += 2;        // 指针后移 
    GsmSerializeNumbers(pSrc, pDst->TP_SCTS, 14);        // 服务时间戳字符串(TP_SCTS)  
    pSrc += 14;       // 指针后移 
    GsmString2Bytes(pSrc, &tmp, 2);    // 用户信息长度(TP-UDL) 
    pSrc += 2;        // 指针后移 
    if(pDst->TP_DCS == GSM_7BIT)     
    { 
        // 7-bit解码 
        nDstLength = GsmString2Bytes(pSrc, buf, tmp & 7 ? (int)tmp * 7 / 4 + 2 : (int)tmp * 7 / 4);  // 格式转换 
        GsmDecode7bit(buf, pDst->TP_UD, nDstLength);    // 转换到TP-DU 
        nDstLength = tmp; 
    } 
    else if(pDst->TP_DCS == GSM_UCS2) 
    { 
        // UCS2解码 
        nDstLength = GsmString2Bytes(pSrc, buf, tmp * 2);        // 格式转换 
        nDstLength = GsmDecodeUcs2(buf, pDst->TP_UD, nDstLength);    // 转换到TP-DU 
    } 
    else 
    { 
        // 8-bit解码 
        nDstLength = GsmString2Bytes(pSrc, buf, tmp * 2);        // 格式转换 
        nDstLength = GsmDecode8bit(buf, pDst->TP_UD, nDstLength);    // 转换到TP-DU 
    } 
     
    // 返回目标字符串长度 
    return nDstLength; 
} 
 
// 发送短消息 
// pSrc: 源PDU参数指针 
BOOL CGsmToUartDlg::GsmSendMessage(const SM_PARAM *pSrc) 
{ 
    int nPduLength;        // PDU串长度 
    unsigned char nSmscLength;    // SMSC串长度 
    int nLength;           // 串口收到的数据长度 
    char cmd[16];          // 命令串 
    char pdu[512];         // PDU串 
    char ans[128];         // 应答串 
     
    nPduLength = GsmEncodePdu(pSrc, pdu);    // 根据PDU参数,编码PDU串 
    strcat(pdu, "\x01a");        // 以Ctrl-Z结束 
     
    GsmString2Bytes(pdu, &nSmscLength, 2);    // 取PDU串中的SMSC信息长度 
    nSmscLength++;        // 加上长度字节本身 
     
    // 命令中的长度,不包括SMSC信息长度,以数据字节计 
    sprintf(cmd, "AT+CMGS=%d\r", nPduLength / 2 - nSmscLength);    // 生成命令 
     
    WriteComm(cmd, strlen(cmd));    // 先输出命令串 
     
    nLength = ReadComm(ans,128);   // 读应答数据 
     
    // 根据能否找到"\r\n> "决定成功与否 
    if(nLength == 4 && strncmp(ans, "\r\n> ", 4) == 0) 
    { 
        WriteComm(pdu, strlen(pdu));        // 得到肯定回答,继续输出PDU串 
     
        nLength = ReadComm(ans,128);       // 读应答数据 
 
        // 根据能否找到"+CMS ERROR"决定成功与否 
        if(nLength > 0 && strncmp(ans, "+CMS ERROR", 10) != 0) 
        { 
            return TRUE; 
        } 
    } 
     
    return FALSE; 
} 
 
// 读取短消息 
// 用+CMGL代替+CMGR,可一次性读出全部短消息 
// pMsg: 短消息缓冲区,必须足够大 
// 返回: 短消息条数 
int CGsmToUartDlg::GsmReadMessage(SM_PARAM *pMsg) 
{ 
    int nLength;        // 串口收到的数据长度 
    int nMsg;           // 短消息计数值 
    char* ptr;          // 内部用的数据指针 
    char cmd[16];       // 命令串 
    char ans[1024];     // 应答串 
     
    nMsg = 0; 
    ptr = ans; 
     
    sprintf(cmd, "AT+CMGL\r");    // 生成命令 
     
    WriteComm(cmd, strlen(cmd));    // 输出命令串 
    nLength = ReadComm(ans,1024);    // 读应答数据 
 
    // 根据能否找到"+CMS ERROR"决定成功与否 
    if(nLength > 0 && strncmp(ans, "+CMS ERROR", 10) != 0) 
    { 
        // 循环读取每一条短消息, 以"+CMGL:"开头 
        while((ptr = strstr(ptr, "+CMGL:")) != NULL) 
        { 
            ptr += 6;        // 跳过"+CMGL:" 
            sscanf(ptr, "%d", &pMsg->index);    // 读取序号 
            TRACE("  index=%d\n",pMsg->index); 
     
            ptr = strstr(ptr, "\r\n");    // 找下一行 
            ptr += 2;        // 跳过"\r\n" 
                 
            GsmDecodePdu(ptr, pMsg);    // PDU串解码 
            pMsg++;        // 准备读下一条短消息 
            nMsg++;        // 短消息计数加1 
        } 
    } 
     
    return nMsg; 
} 
 
// 删除短消息 
// index: 短消息序号,从1开始 
BOOL CGsmToUartDlg::GsmDeleteMessage(const int index) 
{ 
    int nLength;          // 串口收到的数据长度 
    char cmd[16];         // 命令串 
    char ans[128];        // 应答串 
     
    sprintf(cmd, "AT+CMGD=%d\r", index);    // 生成命令 
     
    // 输出命令串 
    WriteComm(cmd, strlen(cmd)); 
     
    // 读应答数据 
    nLength = ReadComm(ans,128); 
 
    // 根据能否找到"+CMS ERROR"决定成功与否 
    if(nLength > 0 && strncmp(ans, "+CMS ERROR", 10) != 0) 
    { 
        return TRUE; 
    } 
     
    return FALSE; 
} 
 
// 写串口 
// pData: 待写的数据缓冲区指针 
// nLength: 待写的数据长度 
void CGsmToUartDlg::WriteComm(CString tmpSend, int nLength) 
{ 
	DWORD dwNumWrite;    // 串口发出的数据长度 
	if (!WriteFile(hCom1,(LPCTSTR)tmpSend,(DWORD)nLength,&dwNumWrite,NULL)) 
	{ 
		AfxMessageBox("向端口写数据失败!"); 
		::CloseHandle(hCom1); 
		return ; 
	} 
	// 选定“感兴趣”的事件、信号 
	if (!SetCommMask(hCom1,EV_TXEMPTY)) 
	{ 
		AfxMessageBox(_T("选择监听信号失败!")); 
		::CloseHandle(hCom1); 
		return ; 
	} 
	// 停止对串口的写操作 
	if (!PurgeComm(hCom1,PURGE_TXABORT)) 
	{ 
		AfxMessageBox(_T("停止写端口操作时发生错误!")); 
		::CloseHandle(hCom1); 
		return ; 
	} 
	// 将缓冲区中的数据发送到串口 
	if (!FlushFileBuffers(hCom1)) 
	{ 
		AfxMessageBox(_T("处理缓冲数据时发生错误!")); 
		::CloseHandle(hCom1); 
		return ; 
	} 
} 
 
// 读串口 
// pData: 待读的数据缓冲区指针 
// nLength: 待读的最大数据长度 
// 返回: 实际读入的数据长度 
int CGsmToUartDlg::ReadComm(void * pData , int nLength) 
{ 
    DWORD dwNumRead;    // 串口收到的数据长度 
    ReadFile(hCom1, pData, (DWORD)nLength, &dwNumRead, NULL); 
    return (int)dwNumRead; 
} 
 
// 8-bit编码 
// pSrc: 源字符串指针 
// pDst: 目标编码串指针 
// nSrcLength: 源字符串长度 
// 返回: 目标编码串长度 
int CGsmToUartDlg::GsmEncode8bit(const char *pSrc, unsigned char *pDst, int nSrcLength) 
{ 
    for(int i=0; i