Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1067276
  • 博文数量: 264
  • 博客积分: 6005
  • 博客等级: 大校
  • 技术积分: 2798
  • 用 户 组: 普通用户
  • 注册时间: 2007-08-08 20:15
文章分类

全部博文(264)

文章存档

2011年(42)

2010年(213)

2009年(4)

2008年(2)

2007年(3)

分类:

2010-06-11 16:38:34

/*! @file
********************************************************************************

模 块名      : 通讯
文件名       : Factory.h
相关文件     : Factory.cpp
              SerialPort.h SerialPort.cpp
文件实现功能 : 设计模式中的工厂模式,用来创建通讯.
作者         : 毛勇
版本         : 1.0
--------------------------------------------------------------------------------
多线程安全性 : 否,会存在重复创建的问题,只能在一个线程中使用
异常时安全性 : 是,异常时时,会返回创建失败,并处理异常.
--------------------------------------------------------------------------------
备 注         : 使用智能指针保存通讯对象指针,使用了boost的asio(库在boost_1_43_0文件夹中)
--------------------------------------------------------------------------------
修 改记录 :
日 期        版本     修改人              修改内容
2010/06/10   1.0.0    毛勇                创建

*******************************************************************************/
#pragma once
#include "stdafx.h"
#include "Channel.h"
#include
#include
#include
#include
#include


using namespace std;
using boost::asio::serial_port;

class CTemperatureDlg;


/*! @class
********************************************************************************

类名称   : CSerialPort
功能     : 串口通讯类
异常类   : 无
--------------------------------------------------------------------------------
备注     :
典型用法 :
--------------------------------------------------------------------------------
作者     : 毛勇

*******************************************************************************/
class CSerialPort : public CChannel
{
public:
///////////////////////////////////////////////////////////// 构造和虚析构
    CSerialPort(boost::asio::io_service& ioService,
                const CCommAttr &commAttr,
                CTemperatureDlg *pDlg
                );
    ~CSerialPort();
    
public:
/////////////////////////////////////////////////////////////  公用方法
    // [[ 功能组1
    //! 处理接收到的数据
    void HandleReceiveFrom(const boost::system::error_code& error,
                           size_t nBytesReceived
                          );

    //! 处理发生数据
    void HandleSendTo(const boost::system::error_code& /*error*/,
                      size_t /*bytes_sent*/
                     );

    //! 直接发送数据
    void Send(const string &strSend, const string &strSendType);

    //! 申请资源
    //int  OpenPort();

    //! 关闭端口
    void Close();//退出();
    // [[ 功能组1

private:
/////////////////////////////////////////////////////////////  私有方法
    // [[ 功能组1
    // [[ 功能组1
private:
/////////////////////////////////////////////////////////////  私有成员
    boost::asio::io_service  &m_ioService;
    serial_port              m_serialPort;



    enum { MAX_LENGTH = 100 };

    //! 接收缓冲区
    char m_chRecvBuf[MAX_LENGTH];

    //! 发生缓冲区
    char m_chSendBuf[MAX_LENGTH];
};

==================================================================
==================================================================
串口cpp文件
==================================================================
==================================================================
#include "StdAfx.h"
#include "SerialPort.h"
#include "Resource.h"
#include "TemperatureDlg.h"
#include "Channel.h"
#include "TemperatureDlg.h"



CSerialPort::CSerialPort(boost::asio::io_service& ioService,
                         const CCommAttr &commAttr,
                         CTemperatureDlg *pDlg)
    : m_ioService(ioService)
    , CChannel (commAttr, pDlg)     //初始化对话框指针
    , m_serialPort(ioService, commAttr.strSerialPort.c_str())
{
    // =========================================================================
    // = 初始化波特率  fixme:波特率需要检查下是否是支持的波特率。通过表驱动检查比较简单
    m_serialPort.set_option(serial_port::baud_rate(commAttr.nBaudRate));


    // =========================================================================
    // = 初始化流控制
    if (0 == commAttr.strFlowControl.compare("none"))
    {
        m_serialPort.set_option(serial_port::flow_control(serial_port::flow_control::none));//无
    }
    else if (0 == commAttr.strFlowControl.compare("software"))
    {
        m_serialPort.set_option(serial_port::flow_control(serial_port::flow_control::software));//软件
    }
    else if (0 == commAttr.strFlowControl.compare("hardware"))
    {
        m_serialPort.set_option(serial_port::flow_control(serial_port::flow_control::hardware));//硬件
    }
    else
    {
        //出错,抛出异常?
    }
   

    // =========================================================================
    // = 初始化奇偶校验
    if (0 == commAttr.strParity.compare("none"))
    {
        m_serialPort.set_option(serial_port::parity(serial_port::parity::none));
    }
    else if (0 == commAttr.strParity.compare("odd"))
    {
        m_serialPort.set_option(serial_port::parity(serial_port::parity::odd));
    }
    else if (0 == commAttr.strParity.compare("even"))
    {
        m_serialPort.set_option(serial_port::parity(serial_port::parity::even));
    }
    else
    {
    }
   

    // =========================================================================
    // = 初始化停止位
    if (0 == commAttr.strStopBits.compare("one"))
    {
        m_serialPort.set_option(serial_port::stop_bits(serial_port::stop_bits::one));
    }
    else if (0 == commAttr.strStopBits.compare("onepointfive"))
    {
        m_serialPort.set_option(serial_port::stop_bits(serial_port::stop_bits::onepointfive));
    }
    else if (0 == commAttr.strStopBits.compare("two"))
    {
        m_serialPort.set_option(serial_port::stop_bits(serial_port::stop_bits::two));
    }
   

    // =========================================================================
    // = 初始化数据位
    m_serialPort.set_option(serial_port::character_size(commAttr.nCharacterSize));
   
   

    // =========================================================================
    // = 开始读数据
    m_serialPort.async_read_some(boost::asio::buffer(m_chRecvBuf, MAX_LENGTH),
                                 boost::bind(&CSerialPort::HandleReceiveFrom,
                                             this,
                                             boost::asio::placeholders::error,
                                             boost::asio::placeholders::bytes_transferred
                                             )
                                );
}


CSerialPort::~CSerialPort()
{

}

void
CSerialPort::HandleSendTo( const boost::system::error_code& /*error*/, size_t /*bytes_sent*/ )
{
    m_serialPort.async_read_some(//async_receive_from
                                 boost::asio::buffer(m_chRecvBuf, MAX_LENGTH),
                                 boost::bind( &CSerialPort::HandleReceiveFrom,
                                              this,
                                              boost::asio::placeholders::error,
                                              boost::asio::placeholders::bytes_transferred
                                             )
                                );
    return;
}


void
CSerialPort::HandleReceiveFrom( const boost::system::error_code& error, size_t nBytesReceived )
{
    if (!error && nBytesReceived > 0)
    {
       
        string strRecv(m_chRecvBuf, nBytesReceived);

        m_pDlg->UpdateRecvMessage(strRecv); //更新主界面的接收发送
    }
   
    m_serialPort.async_read_some(boost::asio::buffer(m_chRecvBuf, MAX_LENGTH),
                                 boost::bind( &CSerialPort::HandleReceiveFrom,
                                              this,
                                              boost::asio::placeholders::error,
                                              boost::asio::placeholders::bytes_transferred
                                              )
                                );
}


void
CSerialPort::Send(const string &strSend, const string &strSendType )
{
    memcpy (m_chSendBuf, strSend.c_str(), strSend.length());
    m_serialPort.async_write_some(boost::asio::buffer(m_chSendBuf, strSend.length()),
                                  boost::bind(&CSerialPort::HandleSendTo,
                                              this,
                                              boost::asio::placeholders::error,
                                              boost::asio::placeholders::bytes_transferred
                                              )
                                  );
}


void
CSerialPort::Close()
{
    if (m_serialPort.is_open()) {
        m_serialPort.close();
    }
}


=====================================================================
=================== channel =========================================
/*! @file
********************************************************************************

模 块名      : 通讯模块 comm
文件名       : Channel.h
相关文件     : Channel.cpp 
               Product.h Product.cpp  //通道
               TcpServer.h TcpServer.cpp
               UdpClient.h  UdpClient.cpp 
               UdpServer.h  UdpServer.cpp
               SerialPort.h SerialPort.cpp
文件实现功能 : 存储软件版本号
作者         : 毛勇
版本         : 1.0
--------------------------------------------------------------------------------
多线程安全性 : 是
异常时安全性 : 是
--------------------------------------------------------------------------------
备 注         : <其它说明>
--------------------------------------------------------------------------------
修 改记录 :
日 期        版本     修改人              修改内容
2010/05/28   1.0.0    毛勇                创建

*******************************************************************************/
#pragma once
#include


using  std::string;





/*! @class
********************************************************************************

类名称   : CCommAttr
功能     : 通讯参数,用来创建连接所需要的参数。
异常类   : 无
--------------------------------------------------------------------------------
备注     :
典型用法 :
--------------------------------------------------------------------------------
作者     : 毛勇

*******************************************************************************/
class CCommAttr
{
public:
    string   strSerialPort;
    int      nBaudRate; //9600
    string   strParity;//none, odd, even。   
    string   strStopBits;    //停止位,构造参数为serial_port::stop_bits::type,enum类型,可以是one onepointfive two
    string   strFlowControl;  //流控制  none software hardware
    int      nCharacterSize;  //character_size  5,6,7,8
};


/*
父类:  CChannel
子类:  CTcpServer, CTcpClient, CUdpServer, CUdpClient 都是从 CChannel 派生

class CTcpServer: public CChannel
{
};

class CTcpClient: public CChannel
{
};

class CUdpServer: public CChannel
{
};

class CUdpClient: public CChannel
{
};
*/

class CTemperatureDlg;





//=============================================================================
//=================  channel 类 相当于工厂模式中的 product 类==================
//=============================================================================
class CChannel
{
public:
/////////////////////////////////////////////////////////////  虚析构
    virtual ~CChannel();


/////////////////////////////////////////////////////////////  保护构造函数
protected:
    CChannel(const CCommAttr &commAttr,  CTemperatureDlg *pDlg); //const CCommAttr &commAttr
   
public:
/////////////////////////////////////////////////////////////  公用方法
    // [[ 功能组1
    //virtual void Suspend() = 0;//暂停
    //virtual void Startup() = 0;//启动
    virtual void Close() = 0;//退出
    virtual void Send(const string &strSend, const string &strSendType) = 0; //发送
    // ]] 功能组1


protected:
    //CCommAttr            m_commAttr;
    const CCommAttr             m_commAttr;
    CTemperatureDlg             *m_pDlg;
};


==================================================================
#include "StdAfx.h"
#include "Channel.h"

//=============================================================================
//=================  channel 类 相当于工厂模式中的 product 类==================
//=============================================================================


CChannel::CChannel( const CCommAttr &commAttr,
                    CTemperatureDlg *pDlg)
    : m_commAttr(commAttr)
    , m_pDlg(pDlg)
{

}

CChannel::~CChannel()
{
}



 
阅读(4603) | 评论(7) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-12-02 17:08:18

async_read_some是否一收到串口数据,就会触发绑定函数?那么没准没有完整的接收到整个串口数据消息,也许只是刚收到1个字节,就会向GUI发送收到的数据。 ================ reply:你说的哦是正确的,是会当一收倒是数据就发送给 gui,但是不会是一个字节发送一次。 所以,好点的方法是在 编写一个用来检测 报文完整性的函数。

chinaunix网友2010-10-29 22:48:26

在你的类中,serial_port对象关闭(close)掉后如何重新打开该串口?

chinaunix网友2010-10-27 22:52:12

sig(),恩,多谢。我现在有一个问题。目前用usb口(通过usb转串口驱动)实现与串口设备的通信。但每次打开串口之前,必须到设备管理器中启动虚拟串口,但是过了几秒后改虚拟串口又被画红叉了,请问是什么原因?

wumao22010-10-07 09:00:04

我看这里面直接用了回调函数: m_pDlg->UpdateRecvMessage(strRecv); //更新主界面的接收发送 现在让我写的话,会更多的考虑使用信号插槽来实现。也许这就是慢慢进步的过程吧。不过我知道,我技术实在是太烂了。

wumao22010-10-07 08:55:19

这是我以前写的代码,当时写的时候,觉得挺好的,现在回过头来看着,有点不舒服了,可能是经过一段时间沉淀,技术上会稍微有点进步吧。 看过去的代码总是会觉得哎,我怎么会写成这样。我应该写的更好。 不过写博客是要花费时间的。 有时会因为考虑时间,就乱写一通。 结果,自己都看不下去了。