// SeriesCommDlg.cpp : implementation file
//
#include "stdafx.h"
#include "SeriesComm.h"
#include "SeriesCommDlg.h"
#include "Shlwapi.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define FILE_BLOCK_SIZE 1024 //16 //
/////////////////////////////////////////////////////////////////////////////
// CSeriesCommDlg dialog
CSeriesCommDlg::CSeriesCommDlg(CWnd* pParent /*=NULL*/)
: CDialog(CSeriesCommDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CSeriesCommDlg)
m_strRecv = _T("");
m_strSend = _T("");
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CSeriesCommDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CSeriesCommDlg)
DDX_Control(pDX, IDC_EDIT_RECV, m_EditMsg);
DDX_Control(pDX, IDC_EDIT_COM_STATE, m_ComState);
DDX_Control(pDX, IDC_COMBO_BAUD, m_CBoxBaud);
DDX_Control(pDX, IDC_COMBO_COM, m_CBoxSetCom);
DDX_Control(pDX, IDC_MSCOMM1, m_ctrlComm);
DDX_Text(pDX, IDC_EDIT_RECV, m_strRecv);
//}}AFX_DATA_MAP
DDX_Control(pDX, IDC_BTN_SEND, m_btnSend);
}
BEGIN_MESSAGE_MAP(CSeriesCommDlg, CDialog)
//{{AFX_MSG_MAP(CSeriesCommDlg)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BTN_EXIT, OnBtnExit)
ON_BN_CLICKED(IDC_BTN_SEND, OnBtnSend)
ON_CBN_SELCHANGE(IDC_COMBO_BAUD, OnSelchangeComboBaud)
ON_CBN_SELCHANGE(IDC_COMBO_COM, OnSelchangeComboCom)
//}}AFX_MSG_MAP
ON_WM_CLOSE()
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CSeriesCommDlg message handlers
BOOL CSeriesCommDlg::OnInitDialog()
{
BOOL ret;
CDialog::OnInitDialog();
// 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
CString strCmdLine;
//取命令行参数 "D: est.bin 1" //命令行参数为1则是下载图片数据 为2则表示下载用户程序
//参数1:源文件路径; 参数2:选择下载用户程序或图片
strCmdLine = AfxGetApp()->m_lpCmdLine;
m_strPath = strCmdLine.Left(strCmdLine.GetLength()-2);
if (m_strPath.GetLength()-4 != m_strPath.Find(".bin"))
{
MessageBox("参数传递不正确,请与厂家联系.", "程序异常", MB_OK);
}
else
{
m_flag = strCmdLine[strCmdLine.GetLength()-1];
}
m_strBaud ="115200";
m_CBoxSetCom.SetCurSel(0);
m_CBoxBaud.SetCurSel(5);
ret = SetComPort(1); //初始化串口
if (ret)
{
m_nMsgFlag = 0;
m_nRxLen = 0;
m_nFileSize = 0;
m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
m_ComState.SetWindowText("COM1 已打开. 115200,N,8,1");
}
else
{
m_bComStatus = FALSE;
m_ComState.SetWindowText("COM1 没有发现此串口或被占用,请重新选择串口");
}
return TRUE; // return TRUE unless you set the focus to a control
}
// 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 CSeriesCommDlg::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 CSeriesCommDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
void CSeriesCommDlg::OnBtnExit()
{
// TODO: Add your control notification handler code here
if (m_bComStatus)
{
m_ctrlComm.SetPortOpen(0);
CloseHandle(m_hThread);
CloseHandle(m_hEvent);
}
CDialog::OnCancel();
}
void CSeriesCommDlg::SendString(BYTE *Buf, int len)
{
CByteArray array;
int i=0;
if(Buf)
{
array.RemoveAll(); //清空数组
array.SetSize(len); //设置数组大小为帧长度
for(i=0; i<len; i++) //把待发送数据存入数组
array.SetAt(i,Buf[i]);
m_ctrlComm.SetOutput(COleVariant(array));
}
}
BYTE ucCurrBlock=0; //当前段号
DWORD WINAPI ThreadFunc(LPVOID lpParameter)
{
int i=0;
CSeriesCommDlg * pThis =(CSeriesCommDlg*)lpParameter;
BYTE cHandDate[5]={0xA1,0xB2,0xC3,0xD4,0x00};
BYTE cNum[6]={0xAA,0xBB,0x01,0x00,0x00,0x00};
BYTE cFileInfo[6]={0xAA,0xCC,0x00,0x00,0x20,0x00};
BYTE cEnd[3]={0xAA,0xDD,0x00};
BYTE ucFileBlcok=0; //文件段数
WORD wSendSize=0; //当前段长
int nFileSize = 0; //文件大小
if(pThis->m_flag == '1') //1 表示下载图片数据
{
cNum[3] = 0x01;
}
else if(pThis->m_flag == '2') //2 表示下载用户程序
{
cNum[3] = 0x02;
}
nFileSize = pThis->m_nFileSize;
if(nFileSize < FILE_BLOCK_SIZE)
{
ucFileBlcok = 1;
}
else
{
if( (nFileSize % FILE_BLOCK_SIZE) == 0 )
ucFileBlcok = nFileSize / FILE_BLOCK_SIZE;
else
ucFileBlcok = nFileSize / FILE_BLOCK_SIZE + 1;
}
cNum[4] = ucFileBlcok;
pThis->SendString(cHandDate, 4); //发握手包 send 1
pThis->m_EditMsg.SetWindowText("发握手包");
pThis->m_btnSend.EnableWindow(false);
for(;;)
{
WaitForSingleObject(pThis->m_hEvent, INFINITE); //1500 //INFINITE
switch(pThis->m_nMsgFlag)
{
case 0:
pThis->m_EditMsg.SetWindowText("接收超时,系统重发。");
pThis->MessageBox("控制器没有返回,请确认连接是否正常,点确认后系统重发。", "提示", MB_OK);
pThis->SendString(cHandDate, 4); //发握手包 send 1
pThis->m_EditMsg.SetWindowText("发握手包");
break;
case 1:
ucCurrBlock=0;
pThis->m_nRxLen = 2;
pThis->SendString(cNum, 5); // send 2
pThis->m_EditMsg.SetWindowText("发文件接收扇区");
break;
case 2:
if (ucFileBlcok == ucCurrBlock)
{
pThis->SendString(cEnd, 2);
pThis->m_EditMsg.SetWindowText("发完成命令");
break;
}
if (ucFileBlcok > (ucCurrBlock+1)) // send 3
{
wSendSize = FILE_BLOCK_SIZE;
}
else
{
wSendSize = nFileSize - ucCurrBlock*FILE_BLOCK_SIZE;
}
cFileInfo[2] = ucCurrBlock;
cFileInfo[3] = (BYTE)(wSendSize>>8);
cFileInfo[4] = (BYTE)(wSendSize&0x00FF);
pThis->SendString(cFileInfo, 5);
if(pThis->pFileBuf)
{
pThis->SendString(pThis->pFileBuf+(ucCurrBlock*FILE_BLOCK_SIZE), wSendSize);
}
else
{
::MessageBox(pThis->GetSafeHwnd(),_T("pThis->Buf为空"),NULL,0);
}
pThis->m_EditMsg.SetWindowText("发送数据");
ucCurrBlock++;
break;
case 5:
pThis->m_EditMsg.SetWindowText("下载完成");
pThis->m_btnSend.EnableWindow(true);
pThis->m_nRxLen = 2;
if(pThis->pFileBuf)
{
int flag = ::ResetEvent(pThis->m_hEvent);
delete pThis->pFileBuf;
pThis->pFileBuf = NULL;
CloseHandle(pThis->m_hThread);
}
if(IDOK == MessageBox(pThis->GetSafeHwnd(),_T("下载完成!"),NULL,0))
{
pThis->Destroy() ;
}
break;
default:
pThis->m_nRxLen = 0;
break;
}
i++;
}
return 0x00;
}
BEGIN_EVENTSINK_MAP(CSeriesCommDlg, CDialog)
//{{AFX_EVENTSINK_MAP(CSeriesCommDlg)
ON_EVENT(CSeriesCommDlg, IDC_MSCOMM1, 1 /* OnComm */, OnOnCommMscomm1, VTS_NONE)
//}}AFX_EVENTSINK_MAP
END_EVENTSINK_MAP()
void CSeriesCommDlg::Destroy()
{
CSeriesCommApp * pApp = (CSeriesCommApp*)::AfxGetApp();
CSeriesCommDlg * pDlg = (CSeriesCommDlg*)pApp->m_pMainWnd;
pDlg->SendMessage(WM_CLOSE);
}
void CSeriesCommDlg::OnOnCommMscomm1()
{
// TODO: Add your control notification handler code here
VARIANT variant_inp;
COleSafeArray safearray_inp;
LONG len,k;
CString strtemp;
BYTE cFileFlag[4]={0xAA,0xBB,0x01,0x00};
BYTE rxData[2048]={0}; //设置BYTE数组
//static LONG lSize=0;
m_nRxLen = 2;
if(m_ctrlComm.GetCommEvent()==2) //事件值为2表示接收缓冲区内有字符
{
variant_inp=m_ctrlComm.GetInput(); //读缓冲区
safearray_inp=variant_inp; //VARIANT型变量转换为ColeSafeArray型变量
len=safearray_inp.GetOneDimSize(); //得到有效数据长度
for(k=0;k<len;k++)
safearray_inp.GetElement(&k,rxData+k); //转换为BYTE型数组
//lSize += len;
if (len >= m_nRxLen)
{
if (rxData[0]==0x55 && rxData[1]==0x55) //握手包
{
m_nMsgFlag = 1;
memset(rxData, 0, sizeof(rxData));
::SetEvent(m_hEvent);
}
else if (rxData[0]==0xBB && rxData[1]==0xAA) //写flash扇区号 0 or 1
{
m_nMsgFlag = 2;
memset(rxData, 0, sizeof(rxData));
::SetEvent(m_hEvent);
}
else if (rxData[0]==0xCC && rxData[1]==0xAA) //继续发下一块数据
{
m_nMsgFlag = 2;
memset(rxData, 0, sizeof(rxData));
::SetEvent(m_hEvent);
}
else if (rxData[0]==0xDD && rxData[1]==0xAA) //数据完成
{
m_nMsgFlag = 5;
memset(rxData, 0, sizeof(rxData));
::SetEvent(m_hEvent);
}
else
{
m_nMsgFlag = -1;
memset(rxData, 0, sizeof(rxData));
}
}
/*
for(k=0;k<len;k++) //将数组转换为Cstring型变量
{
BYTE bt=*(char*)(rxData+k); //字符型
strtemp.Format("%c",bt); //将字符送入临时变量strtemp存放
m_strRecv+=strtemp; //加入接收编辑框对应字符串
}*/
}
UpdateData(FALSE);
}
void CSeriesCommDlg::OnBtnSend()
{
CFile fp;
UpdateData(TRUE);
int err = 0;
//fp.Open(m_strPath, CFile::modeRead);
fp.Open("D:\ceshi.bin", CFile::modeRead); //不读命令行参数时,用绝对路径
m_nFileSize = fp.GetLength();
if (m_nFileSize > 0)
{
pFileBuf = new BYTE[m_nFileSize+1];
memset(pFileBuf,0,m_nFileSize);
if( (err = fp.Read(pFileBuf, m_nFileSize)) == 0 || !pFileBuf)
{
MessageBox(_T("文件读取失败"));
}
pFileBuf[m_nFileSize] = ' ';
fp.Close();
m_hThread = ::CreateThread(NULL,
0,
ThreadFunc,
this,
0,//CREATE_SUSPENDED 挂起
&m_dwThreadId);
::SetThreadPriority(m_hThread,THREAD_PRIORITY_HIGHEST);
}
else
{
MessageBox("文件为空或不存在!", "错误", MB_OK);
}
//BYTE cHandDate[5]={0xA1,0x00,0xC3,0xD4,0x00};
//m_ctrlComm.SetOutput(COleVariant(m_strSend)); //发送数据
//CSeriesCommDlg::SendString(cHandDate, 4);
//UpdateData(TRUE);
}
void CSeriesCommDlg::OnSelchangeComboBaud()
{
// TODO: Add your control notification handler code here
CString temp,str;
int i=m_CBoxBaud.GetCurSel();
switch(i)
{
case 0:
m_strBaud="9600";
break;
case 1:
m_strBaud="19200";
break;
case 2:
m_strBaud="38400";
break;
case 3:
m_strBaud="56000";
break;
case 4:
m_strBaud="57600";
break;
case 5:
m_strBaud="115200";
break;
default:
break;
}
if (!m_bComStatus)
{
m_ComState.SetWindowText("串口没有打开不能进行此操作!");
return;
}
temp = m_strBaud + ",n,8,1";
m_ctrlComm.SetSettings(temp);
i=m_CBoxSetCom.GetCurSel();
m_CBoxSetCom.GetLBText(i,str);
str += "已打开. "+ temp;
m_ComState.SetWindowText(str);
}
void CSeriesCommDlg::OnSelchangeComboCom()
{
// TODO: Add your control notification handler code here
int index=m_CBoxSetCom.GetCurSel();
CString str;
CString strTemp="COM";
CString strBaud;
BOOL ret;
m_CBoxSetCom.GetLBText(index,str);
strTemp = str;
str += " 没有发现此串口或被占用,请重新选择串口";
if (!m_bComStatus)
{
m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
}
ret = SetComPort(index+1); //初始化串口
if (!ret)
{
m_bComStatus = FALSE;
m_ComState.SetWindowText(str);
return;
}
strBaud = m_strBaud+",n,8,1";
m_ctrlComm.SetSettings(strBaud);
strTemp += "已打开. "+ strBaud;
m_ComState.SetWindowText(strTemp);
//MessageBox(str, "错误", MB_OK);
}
BOOL CSeriesCommDlg::SetComPort(int index)
{
HANDLE m_hCom;
CString strComPort="COM";
CString strError;
CString strTemp;
strComPort.Format("COM%d",index);
// 这里的CreateFile函数起了很大的作用,可以用来创建系统设备文件,如果该设备不存在或者被占用,
// 则会返回一个错误,即下面的 INVALID_HANDLE_VALUE ,据此可以判断可使用性。详细参见MSDN中的介绍。
m_hCom = CreateFile(strComPort, GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL| FILE_FLAG_OVERLAPPED, NULL);
if(m_hCom == INVALID_HANDLE_VALUE) // 如果没有该设备,或者被其他应用程序在用
{
CloseHandle(m_hCom); // 关闭文件句柄,后面我们采用控件,不用API
m_bComStatus = FALSE;
strError = strComPort +" 没有发现此串口或被占用,请重新选择串口";
m_ComState.SetWindowText(strError);
AfxMessageBox(strError,MB_OK);
return FALSE;
}
else
{
m_bComStatus = TRUE;
CloseHandle(m_hCom);
}
try
{
if(m_ctrlComm.GetPortOpen()) //如果串口是打开的,则行关闭串口
{
m_ctrlComm.SetPortOpen(FALSE);
}
m_ctrlComm.SetCommPort(index); //选择COM1
m_ctrlComm.SetInputMode(1); //输入方式为二进制方式
m_ctrlComm.SetInBufferSize(1024); //设置输入缓冲区大小
//设置输出缓冲区大小,波特率9600,无校验,8个数据位,1个停止位
m_ctrlComm.SetOutBufferSize(1024);
strTemp = m_strBaud + ",N,8,1";
m_ctrlComm.SetSettings(strTemp);
if(!m_ctrlComm.GetPortOpen())
{
m_ctrlComm.SetPortOpen(TRUE); //打开串口
}
//参数1表示每当串口接收缓冲区中有多于或等于1个字符时将引发一个接收数据的OnComm事件
m_ctrlComm.SetRThreshold(1);
m_ctrlComm.SetInputLen(0); //设置当前接收区数据长度为0
m_ctrlComm.GetInput(); //先预读缓冲区以清除残留数据
return TRUE;
}
catch(CException * /*e*/)
{
m_bComStatus = FALSE;
MessageBox("没有发现此串口或被占用,请重新选择串口", "错误", MB_OK);
return FALSE;
}
}
void CSeriesCommDlg::OnClose()
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if(pFileBuf)
{
delete pFileBuf;
pFileBuf = NULL;
}
if(m_hThread)
{
CloseHandle(m_hThread);
m_hThread = NULL;
}
/**/
if(m_ctrlComm.GetPortOpen()) //如果串口是打开的,则行关闭串口
{
m_ctrlComm.SetPortOpen(FALSE);
}
CDialog::OnClose();
}