16,471
社区成员
发帖
与我相关
我的任务
分享
// 设置窗口参数
void RsCommunication::SetWnd(void)
{
//////////////////////////////////
m_pMainWnd = &m_win; // 窗口指针
//////////////////////////////////
m_pDataExplain=m_pCommParam->pdata; // 数据解释窗口指针
m_pFWnd=m_pCommParam->pwnd;
m_hmWnd=m_pCommParam->pwnd->GetSafeHwnd(); // 管理窗口句柄
delete m_pCommParam; // 删除参数结构
CreateReadTimer(); // 建立定时器
}
// 设置通信参数
void RsCommunication::SetComm(void)
{
m_sPortParam.port=m_pCommParam->str[0]; // 通信口号
m_sPortParam.baud=_tstol(m_pCommParam->str[1]); // 波特率
m_sPortParam.bytesize=_tstoi(m_pCommParam->str[3]); // 数据位数
// 停止位
if(_tstof(m_pCommParam->str[4])==1.5)
m_sPortParam.stopbits=1; // 停止位1.5
else if(_tstof(m_pCommParam->str[4])==2)
m_sPortParam.stopbits=2; // 停止位2
else
m_sPortParam.stopbits=0; // 停止位1
// 校验位
if(m_pCommParam->str[2].MakeUpper()=="O")
m_sPortParam.parity=1; // 奇校验
else if(m_pCommParam->str[2].MakeUpper()=="E")
m_sPortParam.parity=2; // 偶校验
else if(m_pCommParam->str[2].MakeUpper()=="M")
m_sPortParam.parity=3; // 标记校验
else if(m_pCommParam->str[2].MakeUpper()=="S")
m_sPortParam.parity=4; // 空格校验
else
m_sPortParam.parity=0; // 无校验
delete m_pCommParam; // 删除参数结构
}
// 发送数据
void RsCommunication::SendData(byte events, byte * pdata)
{
static enum{S0,S1} state=S0;
int Len=0;
byte datas[OUT_BUFF_SIZE]; // 发送数据缓冲
byte crc;
CHANG_DATA *pd=(CHANG_DATA *)pdata;
if(!m_fInitState)
{
state=S0;
m_fInitState=true;
}
if(pd!=NULL)
{
Len=pd->len;
}
switch(state)
{
case S0:
if(events==EVE_SEND_DATA) // 发送数据事件
{
// 1.增加校验位
datas[0]=pd->pDatas[0];
crc=datas[0];
for(int i=1;i<Len;i++)
{
datas[i]=pd->pDatas[i];
crc=crc^datas[i];
}
datas[Len++]=crc; // 写校验位,发送长度加1
delete pd->pDatas;
delete pd; // 删除原数据结构
// 2.发送数据
Wol.hEvent=CreateEvent(NULL, // 创建事件句柄
TRUE,
FALSE,
NULL);
WriteFile(hCom, // 发送数据
&datas,
Len,
NULL,
&Wol);
// 钩子
if(m_pHook!=NULL) // 钩子线程已经打开
{
SDIP_COMMDATA *pStuThd=new SDIP_COMMDATA;
byte *pBuf=new byte[Len+1];
for(int i=0;i<Len;i++)
pBuf[i]=datas[i];
pStuThd->sTitle=_T("发送数据");
pStuThd->pBuf=pBuf;
pStuThd->len=Len;
::PostThreadMessage(m_pHook->m_nThreadID,WM_DATADSP_MESSAGE,(WPARAM)pStuThd,0); // 钩子线程显示发送数据
}
}
if(events==EVE_SEND_EMPTY) // 发送缓冲区空事件
{
state=S1; // 改变状态机
// 包间隔定时器
m_Timer.SetMyTimer(m_distanceID,TO_WRITE_TIMER); // 延迟15ms再写
}
break;
case S1:
if(events==EVE_SEND_TIMEOUT)
{
// 4.发送完毕后的处理
m_Timer.StopTimer(m_distanceID); // 关间隔定时器
state=S0; // 改变状态机
PostMessage(m_hmWnd,WM_COMBACK_MESSAGE,0,SEND_OK);
}
break;
}
}
// 接收数据(单状态)
void RsCommunication::ReceiveData(byte ev)
{
static int Len=0;
byte myByte[256];
DWORD dwErrors; // 错误信息
COMSTAT Rcs; // COMSTAT结构通信设备的当前信息
byte crc;
if(ev==EVE_READ_EVENT || ev==EVE_READ_TIMEOUT) // 接收缓冲区有数据或超时
{
m_Timer.StopTimer(m_timerID); // 关闭定时器
fStopMsg=true; // 阻塞消息
ClearCommError(hCom,
&dwErrors,
&Rcs); // 获取读缓冲区数据长度
if(Len!=Rcs.cbInQue) // 数据未收完
{
Len=Rcs.cbInQue;
m_Timer.SetMyTimer(m_timerID,TO_READ_TIMER); // 打开定时器,延时读查缓冲区
return; // 再接收
}
else
{
if(Len<1) // 无数据时
return;
// 读缓冲区并处理收到的数据
if(ReadFile(hCom,
&myByte,
Len,
NULL,
&Rol))
{
////////////////////////////////////////////////////////////////////////////////////
// 钩子
if(m_pHook!=NULL) // 钩子线程已经打开
{
SDIP_COMMDATA *pStuThd=new SDIP_COMMDATA;
byte *pBuf=new byte[Len+1];
for(int i=0;i<Len;i++)
pBuf[i]=myByte[i];
pStuThd->sTitle=_T("收到数据");
pStuThd->pBuf=pBuf;
pStuThd->len=Len;
::PostThreadMessage(m_pHook->m_nThreadID,WM_DATADSP_MESSAGE,(WPARAM)pStuThd,0); // 钩子线程显示发送数据
}
////////////////////////////////////////////////////////////////////////////////////
// CRC数据校验
crc=myByte[0];
for(int k=1;k<Len;k++)
crc=crc ^ myByte[k]; // CRC运算
if(crc)
{
// crc检查错丢弃
}
else
{
// crc检查正确,发送数据给命令解释类
PostData(myByte,Len-1);
}
}
Len=0; // 读入计数清0
fStopMsg=false; // 允许事件函数发送消息
}
}
}
// 读定时器静态函数
void RsCommunication::ReadTimer(RsCommunication * pt)
{
pt->ReceiveData(EVE_READ_TIMEOUT); // 定时时间到
}
// 发送数据间隔定时器静态处理函数
void RsCommunication::SendTimer(RsCommunication * pt)
{
pt->SendData(EVE_SEND_TIMEOUT,NULL); // 写间隔时间到
}
// 创建一个读定时器
void RsCommunication::CreateReadTimer(void)
{
m_Timer.RegisterWnd(m_pMainWnd);
m_timerID=m_Timer.GetTimerID();
m_Timer.CreateProcFun((void *)this,(void *)ReadTimer,m_timerID); // 注册读数据处理函数
m_distanceID=m_Timer.GetTimerID();
m_Timer.CreateProcFun((void *)this,(void *)SendTimer,m_distanceID); // 注册发送数据间隔函数
}
// 发送接收的数据
void RsCommunication::PostData(byte * pb, int len)
{
byte *pdata=new byte[len];
for(int i=0;i<len;i++)
pdata[i]=pb[i]; // 写数据
CHANG_DATA *pc=new CHANG_DATA;
pc->len=len;
pc->pDatas=pdata;
::PostMessage(m_pDataExplain->GetSafeHwnd(),WM_RECEV_DATA,(WPARAM)pc,0); // 向解释窗口发送数据
}
// RsCommunication.cpp : 实现文件
//
#include "stdafx.h"
#include "ComHelp.h"
#include "RsCommunication.h"
#include "StaticData.h"
#include ".\HookWnd\HookDisplayData.h"
//***************************************************************
// 全局变量
//***************************************************************
HANDLE hCom; // 串口的句柄
HANDLE hThreadEvent; // 事件线程句柄
DWORD ThreadProcEvent(LPVOID pParam); // 事件响应函数
bool fEventRun; // 事件函数执行标志
DWORD dwWinThreadID; // 窗口线程ID
DWORD dwThreadID; // 事件线程ID
OVERLAPPED Eol={0}; // 事件线程使用的结构
OVERLAPPED Wol={0}; // 写操作使用的结构
OVERLAPPED Rol={0}; // 读操作使用的结构
bool fStopMsg; // 停止事件线程向主线程发送消息标志
//***************************************************************
// hCom:用于存放创建串口时返回的句柄,在程序中通过该句柄来访问所创建的串口
// hThreadEvent:存放创建事件线程产生的句柄,关闭事件线程时使用该句柄
// ThreadProcEvent():当串口产生了事件或错误时,将执行该事件响应函数
// hEventRun:是事件函数内循环体执行的条件
// hWnd:窗口句柄,在创建线程时需要该参数
// dwThreadID:事件线程的ID,在创建线程时需要该参数
// Eol,Wol,Rol:是3个OVERLAPPED结构变量,在重叠操作中需要使用这些变量
// fStopMsg:是事件线程停止向主线程发送消息的标志,为TRUE时阻塞消息发送,处理完缓冲区数据后,置为FALSE,开放事件消息
// ************ 串口事件响应程序 **************
DWORD ThreadProcEvent(LPVOID pParam)
{
DWORD dwEvtMask,dwRes;
Eol.hEvent=CreateEvent(NULL, // 设置为无信号状态
TRUE, // 需要手工复原
FALSE,
NULL);
while(fEventRun)
{
WaitCommEvent(hCom,
&dwEvtMask,
&Eol);
dwRes=WaitForSingleObject(Eol.hEvent,
TO_EVENT_TIMEOUT);
switch(dwRes)
{
case WAIT_OBJECT_0: // 得到监视结果
switch(dwEvtMask)
{
case EV_RXCHAR: // 接收到数据
if(!fStopMsg)
{
fStopMsg=true;
::PostThreadMessage(dwWinThreadID, // 向窗口线程发收到数据的消息
WM_COMMDATA_MESSAGE,
(WPARAM)EV_RXCHAR,1); // 发送接收缓冲区有数据事件消息
}
break;
case EV_TXEMPTY: // 发送缓冲区已空
// 发送缓冲区空
::PostThreadMessage(dwWinThreadID, // 向窗口线程发收到数据的消息
WM_COMMDATA_MESSAGE,
(WPARAM)EV_TXEMPTY,1); // 发送缓冲区已空事件消息
break;
}
break;
}
}
return true;
}
////////////////////////////////////// 全局END /////////////////////////////////////////
// RsCommunication
bool RsCommunication::fEvent=false; // 初始化线程启动标志
IMPLEMENT_DYNCREATE(RsCommunication, CWinThread)
RsCommunication::RsCommunication()
: m_pCommParam(NULL)
, m_pHook(NULL)
, m_pFWnd(NULL)
, m_timerID(0)
, m_pDataExplain(NULL)
, m_distanceID(0)
, m_fInitState(false)
{
}
RsCommunication::~RsCommunication()
{
}
BOOL RsCommunication::InitInstance()
{
return TRUE;
}
int RsCommunication::ExitInstance()
{
// TODO: 在此执行任意逐线程清理
ClosePort(); // 关闭通信口
return CWinThread::ExitInstance();
}
BEGIN_MESSAGE_MAP(RsCommunication, CWinThread)
ON_THREAD_MESSAGE(WM_COMMDATA_MESSAGE,OnCommMessag) // 收到要交换数据的消息
ON_THREAD_MESSAGE(WM_CONTROL_MESSAGE,OnCtrlMessag) // 收到控制消息
END_MESSAGE_MAP()
// RsCommunication 消息处理程序
// 数据收发事件消息
void RsCommunication::OnCommMessag(WPARAM wParam, LPARAM lParam)
{
switch(wParam)
{
case EV_RXCHAR:
// 接收缓冲区有数据
ReceiveData(EVE_READ_EVENT);
break;
case EV_TXEMPTY:
// 发送缓冲区空
SendData(EVE_SEND_EMPTY,NULL);
break;
}
}
// 控制消息
void RsCommunication::OnCtrlMessag(WPARAM wParam, LPARAM lParam)
{
if(lParam==CTRL_COMMEXIT)
{
// 线程结束处理
return;
}
COMMSTRUCT *pCtrl=(COMMSTRUCT *)wParam;
byte cmd=pCtrl->cmd;
switch(cmd)
{
case CTRL_REGWND:
m_pCommParam=(SETCOMM *)pCtrl->pDataPoint; // 保存收到的参数指针
SetWnd(); // 设置窗口
break;
case CTRL_SETCOMM: // 设置通信参数 1.首先执行
// 以参数设置通信参数
m_pCommParam=(SETCOMM *)pCtrl->pDataPoint; // 保存收到的参数指针
SetComm(); // 只保存转换了参数,并没有做其它动作
break;
case CTRL_GETCOMM: // 获取通信参数
// 获取通信参数,并以消息将参数返回给申请者
break;
case CTRL_OPENPORT: // 打开通信口 2.第二个执行
OpenPort();
break;
case CTRL_CLOSEPORT: // 关闭通信口
ClosePort();
break;
case CTRL_SENDDATA: // 发送数据
SendData(EVE_SEND_DATA, pCtrl->pDataPoint);
break;
case CTRL_REGHOOK: // 注册钩子
m_pHook=(CWinThread *)pCtrl->pDataPoint; // 钩子
break;
case CTRL_HOOKEXIT: // 注册钩子
m_pHook=NULL; // 钩子结束
break;
}
delete pCtrl; // 删除通信控制结构
}
// 关闭通信口
void RsCommunication::ClosePort(void)
{
fEventRun=false; // 停止事件线程循环体的操作
WaitForSingleObject(hThreadEvent, // 等待事件线程函数退出
INFINITE); // 无限时的等待,直到事件线程函数退出
CloseHandle(hThreadEvent); // 关闭事件线程句柄
CloseHandle(hCom); // 关闭串口句柄
fEvent=false; // 事件线程关闭
m_fInitState=false; // 恢复发送状态
PostMessage(m_hmWnd,WM_COMBACK_MESSAGE,0,CLOSE_OK);
}
// 打开通信口
void RsCommunication::OpenPort(void)
{
// 1.打开串行通信口,保存串口句柄
hCom=CreateFile(m_sPortParam.port,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, // 使用重叠方式
NULL);
if(hCom==(HANDLE)INVALID_FILE_SIZE)
{
PostMessage(m_hmWnd,WM_COMBACK_MESSAGE,0,SETCOMM_ERROR); // 报告端口打开失败
return;
}
if(hCom != INVALID_HANDLE_VALUE)
{
SetupComm(hCom,OUT_BUFF_SIZE,IN_BUFF_SIZE);
DCB myDCB;
GetCommState(hCom, &myDCB);
myDCB.BaudRate=m_sPortParam.baud;
myDCB.fBinary=TRUE;
myDCB.fParity=TRUE;
myDCB.Parity=m_sPortParam.parity;
myDCB.ByteSize=m_sPortParam.bytesize;
myDCB.StopBits=m_sPortParam.stopbits;
SetCommState(hCom, &myDCB);
}
else
{
// 设置失败
PostMessage(m_hmWnd,WM_COMBACK_MESSAGE,0,SETCOMM_ERROR); // 报告端口打开失败
return;
}
dwWinThreadID=this->m_nThreadID;
if(!fEvent)
{
// 2.启动事件线程
DWORD dwParam;
if(!SetCommMask(hCom,EV_RXCHAR | EV_TXEMPTY)) // 设置允许的事件类型
{
// 建立事件掩码失败
PostMessage(m_hmWnd,WM_COMBACK_MESSAGE,0,BUILD_EVENT_ERROR); // 报告端口打开失败
return;
}
hThreadEvent=::CreateThread(NULL, // 创建事件线程
0,
(LPTHREAD_START_ROUTINE)ThreadProcEvent,
&dwParam,
0,
&dwThreadID);
if(hThreadEvent==INVALID_HANDLE_VALUE)
{
// 线程创建失败
PostMessage(m_hmWnd,WM_COMBACK_MESSAGE,0,BUILD_THREAD_ERROR); // 报告端口打开失败
}
else
fEvent=true; // 创建事件线程成功
}
fEventRun=true; // 允许事件函数执行循环体
PostMessage(m_hmWnd,WM_COMBACK_MESSAGE,0,OPENPORT_OK); // 报告端口打开成功
}
#pragma once
#include "HelpGeneral.h"
#include "TimerGovernor.h"
#include "afxwin.h"
typedef struct
{
CString port; // 通信口
DWORD baud; // 波特率
BYTE parity; // 校验方式
BYTE bytesize; // 数据位数
BYTE stopbits; // 停止位
}PORT_PARAM; // 串行接口参数
// RsCommunication
// RS-232通信线程类
class RsCommunication : public CWinThread
{
DECLARE_DYNCREATE(RsCommunication)
protected:
RsCommunication(); // 动态创建所使用的受保护的构造函数
virtual ~RsCommunication();
public:
virtual BOOL InitInstance(); // 线程初始化
virtual int ExitInstance(); // 线程结束的清理
protected:
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnCommMessag(WPARAM wParam,LPARAM lParam); // 收到数据的消息
afx_msg void OnCtrlMessag(WPARAM wParam,LPARAM lParam); // 收到控制消息
private:
// 事件线程已经启动
static bool fEvent;
// 通信参数表指针
SETCOMM *m_pCommParam;
// 设置窗口参数
void SetWnd(void);
// 设置通信参数
void SetComm(void);
// 串行口参数结构
PORT_PARAM m_sPortParam;
// 打开通信口
void OpenPort(void);
// 发送数据
void SendData(byte events, byte * pdata=NULL);
// 管理窗口句柄
HWND m_hmWnd;
// 关闭通信口
void ClosePort(void);
// 接收数据
void ReceiveData(byte ev);
// 钩子线程
CWinThread *m_pHook;
// 调用者窗口指针
CWnd *m_pFWnd;
// 定时器实例
CTimerGovernor m_Timer;
// 创建一个读定时器
void CreateReadTimer(void);
// 定时器ID
UINT m_timerID;
// 读定时器静态函数
static void ReadTimer(RsCommunication * pt);
// 发送间隔定时器ID
UINT m_distanceID;
// 发送数据间隔定时器
static void SendTimer(RsCommunication * pt);
// 窗口实例
CWnd m_win;
// 数据解释者指针
CWnd *m_pDataExplain;
// 发送接收的数据
void PostData(byte * pb, int len);
// 初始化状态
bool m_fInitState;
};
while (readbyted<filesize+1)
{
getdata=fnDevRead(serial,rbufer,1023,t);//读串口
if (getdata>7)
{
for (int i=0;i<getdata;i++)
{
if (rbufer[i]==0xFA&&rbufer[i+1]==0xAA)
{
cnt=i;
}
if (rbufer[i]==0xAA&&rbufer[i+1]==0xFA)
{
num=i;
}
}
if (num-cnt>4)
{
datacrc=crc16.GetCrc16(&rbufer[cnt+2],num-cnt-4);
mycrc=(rbufer[num-2]<<8)|(rbufer[num-1]);
if (datacrc== mycrc)
{
if (rbufer[cnt+2]==0x01)//文件名
{
if (rbufer[cnt+3]==0x00)
{
break;
}
}
if (rbufer[cnt+2]==0x02)//数据
{
if (rbufer[cnt+3]==0x00)
{
break;
}
}
if (rbufer[cnt+2]==0x03)//
{
if (rbufer[cnt+3]==0x01)
{
CString md5str=_T("");
int dwlength=0;
memset(namebf,0,100);
namebf[0]=0xFA; //帧头
namebf[1]=0xAA;
namebf[2]=0x03;
CloseHandle(handle1);
md5->TargetFile(mypath);
md5str.Format(_T("%s"),md5->Digest);
WideCharToMultiByte(CP_OEMCP,0, md5str, -1,(LPSTR)(&namebf[3]),
md5str.GetLength(), NULL, NULL);
dwlength=md5str.GetLength();
datacrc1=crc16.GetCrc16(&namebf[2],1+dwlength);
namebf[3+dwlength]=(BYTE)(datacrc1>>8);
namebf[4+dwlength]=(BYTE)datacrc1;
namebf[5+dwlength]=0xAA;
namebf[6+dwlength]=0xFA;
int ss=fnDevWrite(serial,namebf,7+dwlength);
break;
}
else
break;
}
bool sucess=true;
sucess=ReadFile(handle1,data,762,&readbyte,0);
if (sucess==false)
{
AfxMessageBox(_T("读文件"));
}
sbufer[0]=0xFA;
sbufer[1]=0xAA;
sbufer[2]=0x02;
asciiToBase64((char*)(&sbufer[3]),data,readbyte);
ilength=getBase64LenFromAsciiLen(readbyte);
datacrc=crc16.GetCrc16(&sbufer[2],(unsigned int )ilength+1);
sbufer[3+ilength]=(BYTE)(datacrc>>8);
sbufer[4+ilength]=(BYTE)datacrc;
sbufer[5+ilength]=0xAA;
sbufer[6+ilength]=0xFA;
fnDevWrite(serial,sbufer,(UINT)ilength+7);
readbyted+=readbyte;
}
}
else
Sleep(50);
}
else
Sleep(50);
}
接收
while (1)
{
readbyte=fnDevRead(serial,data,1023,t);
if (readbyte>7)
{
for (int i=0;i<(int)readbyte;i++)
{
if (data[i]==0xFA&&data[i+1]==0xAA)
{
cnt=i;
}
if (data[i]==0xAA&&data[i+1]==0xFA)
{
num=i;
}
}
if(num-cnt>4)
{
datacrc=crc16.GetCrc16(&data[cnt+2],num-cnt-4);
mycrc=(data[num-2]<<8)|(data[num-1]);
if (datacrc==mycrc)
{
for (int j=cnt+3, k=0;j<num-2;j++,k++)
{
recov[k]=data[j];
}
if (data[cnt+2]==0x01)//收到文件名
{
data1[3]=0x01;
data1[4]=0xc1;
data1[5]=0xe0;
fnDevWrite(serial,data1,8);
}
if (data[cnt+2]==0x02)//收到文件数据
{
ilength=base64ToAscii((char*)rbufer,(const char *) recov);
bool ss=true;
ss=WriteFile(handle1, rbufer, (DWORD)ilength, &writed, NULL);
if (ss==false)
{
AfxMessageBox(_T("读文件出错"));
}
if (readbyte==1023)
{
data2[2]=0x02;
data2[3]=0x01;
data2[4]=0xc1;
data2[5]=0x10;
fnDevWrite(serial,data2,8);
}
else//文件发送结束
{
data3[2]=0x03;
data3[3]=0x01;
testcrc=crc16.GetCrc16(&data3[2],2);
data3[4]=0xc0;
data3[5]=0x80;
fnDevWrite(serial,data3,8);
}
}
if (data[cnt+2]==0x03)//文件发送完毕
{
CString str;
for (int i=0;i<num-cnt-3;i++)
{
str+=recov[i];
}
CloseHandle(handle1);
CString md5str=_T("");
Md5.TargetFile(mypath);
md5str.Format(_T("%s"),Md5.Digest);
DWORD ss=GetLastError();
if (str==md5str)
{
AfxMessageBox(_T("sucessful"));
}
break;
}
}
else//数据错误
{
data4[3]=data[cnt+2];
data4[3]=0x00;
testcrc=crc16.GetCrc16(&data4[2],2);
data4[4]=(BYTE)(testcrc>>8);
data4[5]=(BYTE)testcrc;
fnDevWrite(serial,data4,8);//写串口
break;
}
}
else
Sleep(30);
}
else
Sleep(30);
}