MFC使用mscomm串口通信


转载: http://blog.csdn.net/u011311985/article/details/51279740

使用VS2013


需要注册MSCOMM插件


1、添加串口变量

对话框上右键 插入Active X控件,选择 Micsrosft Commuunication Control,version 6.0 ,之后界面上有一个类似于电话的控件图标,把ID号改为 IDC_MSCOMM,右键这个控件 添加变量,命名为m_mscomm,(此时会新建mscomm的头文件和源文件),把DoDataExchange中的DDX_Control(pDX, IDC_MSCOMM, m_mscomm)这行删除掉。

2、初始化串口

  1. //创建模块串口  
  2. if (!m_mscomm.Create(nullptr, WS_VISIBLE | WS_CHILD, CRect(0, 0, 0, 0), this, IDC_MSCOMM))  
  3. {  
  4.     MessageBox(_T(”创建mscomm串口失败”));  
  5. }  
 //创建模块串口
    if (!m_mscomm.Create(nullptr, WS_VISIBLE | WS_CHILD, CRect(0, 0, 0, 0), this, IDC_MSCOMM))
    {
        MessageBox(_T("创建mscomm串口失败"));
    }

3、打开串口


  1. if (m_mscomm.get_PortOpen())//如果是打开的,则关闭  
  2. {  
  3.     m_mscomm.put_PortOpen(FALSE);  
  4.     GetDlgItem(IDC_Btn_OpenComm)->SetWindowText(g_CommState[g_eCSI::CSOFF]);  
  5.     return;  
  6. }  
  7. m_mscomm.put__CommPort(m_ci.comm);//选择串口  
  8. m_mscomm.put_InBufferSize(1024);//接收缓冲区  
  9. m_mscomm.put_OutBufferSize(1024);//发送缓冲区  
  10. m_mscomm.put_InputLen(0);//设置当前接受去数据长度为0,表示全部读取  
  11. m_mscomm.put_InputMode(1);//以二进制方式读写数据  
  12. m_mscomm.put_RThreshold(1);//接收缓冲区有1个及以上字符时,将响应接收数据事件  
  13. CString setting;  
  14. setting.Format(_T(”%s,%c,%s,%s”),  
  15.     m_ci.baudrate, m_ci.parity[0], m_ci.data, m_ci.stop);  
  16. m_mscomm.put_Settings(setting);//波特率、校验位、数据位、停止位  
  17. try  
  18. {  
  19.     m_mscomm.put_PortOpen(TRUE);  
  20.     GetDlgItem(IDC_Btn_OpenComm)->SetWindowText(g_CommState[g_eCSI::CSON]);  
  21. }  
  22. catch (CException*)  
  23. {  
  24.     m_mscomm.put_OutBufferCount(0);  
  25.     CString errmsg;  
  26.     errmsg.Format(_T(”打开串口失败[串口信息:串口号%d,波特率%s,校验位%s,数据位%s,停止位%s]”),  
  27.         m_ci.comm, m_ci.baudrate, m_ci.parity, m_ci.data, m_ci.stop);  
  28.     //AddShowInfo(errmsg);  
  29. }  
  if (m_mscomm.get_PortOpen())//如果是打开的,则关闭
    {
        m_mscomm.put_PortOpen(FALSE);
        GetDlgItem(IDC_Btn_OpenComm)->SetWindowText(g_CommState[g_eCSI::CSOFF]);
        return;
    }
    m_mscomm.put__CommPort(m_ci.comm);//选择串口
    m_mscomm.put_InBufferSize(1024);//接收缓冲区
    m_mscomm.put_OutBufferSize(1024);//发送缓冲区
    m_mscomm.put_InputLen(0);//设置当前接受去数据长度为0,表示全部读取
    m_mscomm.put_InputMode(1);//以二进制方式读写数据
    m_mscomm.put_RThreshold(1);//接收缓冲区有1个及以上字符时,将响应接收数据事件
    CString setting;
    setting.Format(_T("%s,%c,%s,%s"),
        m_ci.baudrate, m_ci.parity[0], m_ci.data, m_ci.stop);
    m_mscomm.put_Settings(setting);//波特率、校验位、数据位、停止位
    try
    {
        m_mscomm.put_PortOpen(TRUE);
        GetDlgItem(IDC_Btn_OpenComm)->SetWindowText(g_CommState[g_eCSI::CSON]);
    }
    catch (CException*)
    {
        m_mscomm.put_OutBufferCount(0);
        CString errmsg;
        errmsg.Format(_T("打开串口失败[串口信息:串口号%d,波特率%s,校验位%s,数据位%s,停止位%s]"),
            m_ci.comm, m_ci.baudrate, m_ci.parity, m_ci.data, m_ci.stop);
        //AddShowInfo(errmsg);
    }

4、发送数据

//CByteArray    m_senddata;//发送的数据

  1. //发送数据  
  2. m_mscomm.put_Output(COleVariant(m_senddata));  
  //发送数据
    m_mscomm.put_Output(COleVariant(m_senddata));
5、接收数据  

头文件:

  1. DECLARE_EVENTSINK_MAP()  
  2. void OnCommMscomm();//串口接收处理  
  DECLARE_EVENTSINK_MAP()
    void OnCommMscomm();//串口接收处理
源文件消息映射

  1. BEGIN_EVENTSINK_MAP(CKELONCommDlg, CDialogEx)  
  2.     ON_EVENT(CKELONCommDlg, IDC_MSCOMM, 1, CKELONCommDlg::OnCommMscomm, VTS_NONE)  
  3. END_EVENTSINK_MAP()  
BEGIN_EVENTSINK_MAP(CKELONCommDlg, CDialogEx)
    ON_EVENT(CKELONCommDlg, IDC_MSCOMM, 1, CKELONCommDlg::OnCommMscomm, VTS_NONE)
END_EVENTSINK_MAP()

OnCommMscomm里面的处理
  1. if (m_mscomm.get_CommEvent() != 2)  
  2. {  
  3.     return;  
  4. }  
  5.   
  6. //读缓冲区信息  
  7. unsigned char rcvdata[1024] = { 0 };//接收的数据  
  8. COleSafeArray safearray_inp = m_mscomm.get_Input();//读缓冲区消息  
  9. DWORD len = safearray_inp.GetOneDimSize();//获取有效数据长度  
  10. for (long j = 0; j < len; j++)//转化为unsigned char数组  
  11. {  
  12.     safearray_inp.GetElement(&j, rcvdata + j);  
  13. }  
 if (m_mscomm.get_CommEvent() != 2)
    {
        return;
    }

    //读缓冲区信息
    unsigned char rcvdata[1024] = { 0 };//接收的数据
    COleSafeArray safearray_inp = m_mscomm.get_Input();//读缓冲区消息
    DWORD len = safearray_inp.GetOneDimSize();//获取有效数据长度
    for (long j = 0; j < len; j++)//转化为unsigned char数组
    {
        safearray_inp.GetElement(&j, rcvdata + j);
    }
6、完整程序

(不含组帧和解析帧)

头文件:

  1. #ifndef KELONCommDlg_h__  
  2. #define KELONCommDlg_h__  
  3.   
  4.   
  5. // KELONCommDlg.h : 头文件  
  6. //  
  7.   
  8. #include “mscomm.h”  
  9. #include “DLGCommConfig.h”  
  10. #include “FrameHandle.h”  
  11. #include “GridCtrl\GridCtrl.h”  
  12.   
  13.   
  14. // CKELONCommDlg 对话框  
  15. class CKELONCommDlg : public CDialogEx  
  16. {  
  17. // 构造  
  18. public:  
  19.     CKELONCommDlg(CWnd* pParent = NULL);    // 标准构造函数  
  20.     ~CKELONCommDlg();  
  21.   
  22. // 对话框数据  
  23.     enum { IDD = IDD_KELONCOMM_DIALOG };  
  24.   
  25.     using comminfo = CDLGCommConfig::comminfo;  
  26.   
  27.     struct ShowInfo//显示信息的格式  
  28.     {  
  29.         const CString &info;//显示的信息  
  30.         CString state;//显示状态,三种状态:发送、接收、无,有显示状态时一定会显示时间,一定要换行  
  31.         bool breturnline;//是否换行  
  32.         ShowInfo(const CString &info)  
  33.             :info(info)  
  34.         {  
  35.             breturnline = false;  
  36.         }  
  37.     };  
  38.   
  39. protected:  
  40.     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持  
  41.   
  42.   
  43. // 实现  
  44. protected:  
  45.     HICON m_hIcon;  
  46.   
  47.     // 生成的消息映射函数  
  48.     virtual BOOL OnInitDialog();  
  49.     afx_msg void OnSysCommand(UINT nID, LPARAM lParam);  
  50.     afx_msg void OnPaint();  
  51.     afx_msg HCURSOR OnQueryDragIcon();  
  52.     DECLARE_MESSAGE_MAP()  
  53.   
  54. private:  
  55.     CMscomm m_mscomm;//串口控件  
  56.     comminfo    m_ci;//串口信息  
  57.     FrameHandle m_rcvdata;//接收的数据  
  58.     CByteArray  m_senddata;//发送的数据  
  59.   
  60.     int         m_sendtimes;//发送次数  
  61.     UINT        m_timesE, m_timesRetE;//多次发送事件句柄  
  62.       
  63.     CGridCtrl   m_datagrid;//显示接收数据的表格  
  64.   
  65. public:  
  66.     DECLARE_EVENTSINK_MAP()  
  67.     void OnCommMscomm();//串口接收处理  
  68.     afx_msg void OnTimer(UINT_PTR nIDEvent);  
  69.     void SendData();//发送数据  
  70.   
  71.     afx_msg void OnBnClickedBtnOpencomm();  
  72.     void GetConfigInfo(const CString &ifile);//读配置信息  
  73.     void SetConfigInfo(const CString &ifile);//写配置信息  
  74.     afx_msg void OnBnClickedBtnSenddata();  
  75.     afx_msg void OnBnClickedBtnSetcomm();  
  76.     void OnInitUI();//初始化界面  
  77.     UIDataInfo GetUIDataInfo();//获取界面信息  
  78.     //检测消息,消息合法返回真,并组织成unsigned char数组,消息不合法,存储错误消息  
  79.     bool JudgeMsg(CString imsg,std::vector<unsigned char> &omsg,CString &errmsg);  
  80.     afx_msg void OnBnClickedOk();  
  81.     void AddShowInfo(const ShowInfo &si);//添加显示信息  
  82.     afx_msg void OnBnClickedBtnClearshowinfo();  
  83.     afx_msg void OnBnClickedBtnAbout();  
  84.     void AddGridData(const std::vector<UIDataInfo> &uidi);//添加接收数据到表格上  
  85.     CString parseMsg(const UIDataInfo & uidi);//解析消息内容  
  86.     unsigned long BCDToDec(const unsigned char *bcd, int length);//BCD码  
  87.     void copy_V2A(std::vector<unsigned char>::const_iterator begin, unsigned char *arr, int length);//拷贝:vector -> 数组  
  88.     afx_msg void OnBnClickedBtnCleargrid();  
  89. };  
  90.   
  91. #endif // KELONCommDlg_h__  
#ifndef KELONCommDlg_h__

define KELONCommDlg_h__

// KELONCommDlg.h : 头文件
//

include "mscomm.h"

include "DLGCommConfig.h"

include "FrameHandle.h"

include "GridCtrl\GridCtrl.h"

// CKELONCommDlg 对话框
class CKELONCommDlg : public CDialogEx
{
// 构造
public:
CKELONCommDlg(CWnd* pParent = NULL); // 标准构造函数
~CKELONCommDlg();

// 对话框数据
enum { IDD = IDD_KELONCOMM_DIALOG };

using comminfo = CDLGCommConfig::comminfo;

struct ShowInfo//显示信息的格式
{
    const CString &amp;info;//显示的信息
    CString state;//显示状态,三种状态:发送、接收、无,有显示状态时一定会显示时间,一定要换行
    bool breturnline;//是否换行
    ShowInfo(const CString &amp;info)
        :info(info)
    {
        breturnline = false;
    }
};

protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持

// 实现
protected:
HICON m_hIcon;

// 生成的消息映射函数
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()

private:
CMscomm m_mscomm;//串口控件
comminfo m_ci;//串口信息
FrameHandle m_rcvdata;//接收的数据
CByteArray m_senddata;//发送的数据

int         m_sendtimes;//发送次数
UINT        m_timesE, m_timesRetE;//多次发送事件句柄

CGridCtrl   m_datagrid;//显示接收数据的表格

public:
DECLARE_EVENTSINK_MAP()
void OnCommMscomm();//串口接收处理
afx_msg void OnTimer(UINT_PTR nIDEvent);
void SendData();//发送数据

afx_msg void OnBnClickedBtnOpencomm();
void GetConfigInfo(const CString &amp;ifile);//读配置信息
void SetConfigInfo(const CString &amp;ifile);//写配置信息
afx_msg void OnBnClickedBtnSenddata();
afx_msg void OnBnClickedBtnSetcomm();
void OnInitUI();//初始化界面
UIDataInfo GetUIDataInfo();//获取界面信息
//检测消息,消息合法返回真,并组织成unsigned char数组,消息不合法,存储错误消息
bool JudgeMsg(CString imsg,std::vector&lt;unsigned char&gt; &amp;omsg,CString &amp;errmsg);
afx_msg void OnBnClickedOk();
void AddShowInfo(const ShowInfo &amp;si);//添加显示信息
afx_msg void OnBnClickedBtnClearshowinfo();
afx_msg void OnBnClickedBtnAbout();
void AddGridData(const std::vector&lt;UIDataInfo&gt; &amp;uidi);//添加接收数据到表格上
CString parseMsg(const UIDataInfo &amp; uidi);//解析消息内容
unsigned long BCDToDec(const unsigned char *bcd, int length);//BCD码
void copy_V2A(std::vector&lt;unsigned char&gt;::const_iterator begin, unsigned char *arr, int length);//拷贝:vector -&gt; 数组
afx_msg void OnBnClickedBtnCleargrid();

};

endif // KELONCommDlg_h__

源文件:

  1. // KELONCommDlg.cpp : 实现文件  
  2. //  
  3.   
  4. #include “stdafx.h”  
  5. #include “KELONComm.h”  
  6. #include “KELONCommDlg.h”  
  7. #include “afxdialogex.h”  
  8.   
  9. #include <map>  
  10. #include <set>  
  11. #include <vector>  
  12. #include <chrono>  
  13. #include <algorithm>  
  14.   
  15. //表格处理  
  16. #include “GridCtrl\CellRange.h”  
  17. #include “GridCtrl\GridCell.h”  
  18. #include “GridCtrl\GridCellBase.h”  
  19. #include “GridCtrl\GridDropTarget.h”  
  20. #include “GridCtrl\InPlaceEdit.h”  
  21. #include “GridCtrl\MemDC.h”  
  22. #include “GridCtrl\TitleTip.h”  
  23.   
  24. #ifdef _DEBUG  
  25. #define new DEBUG_NEW  
  26. #endif  
  27.   
  28. namespace  
  29. {  
  30.     int g_timespan = 300;//多次发送的时间间隔,300ms  
  31.     int g_sendtimes = 3;//最多重发这么多次  
  32.   
  33.     CString g_configfilepath;//配置路径  
  34.   
  35.     struct MsgCmd//消息命令  
  36.     {  
  37.         int cmdtype;//命令类型  
  38.         int cmdsubtype;//命令子类型  
  39.         int result;//操作结果  
  40.         friend bool operator==(const MsgCmd &item1, const MsgCmd &item2)  
  41.         {  
  42.             return item1.cmdtype == item2.cmdtype  
  43.                 && item1.cmdsubtype == item2.cmdsubtype  
  44.                 && item1.result == item2.result;  
  45.         }  
  46.     };  
  47.   
  48.     std::map<CString,MsgCmd> g_msghead;//消息头:<描述,命令>  
  49.   
  50.     const CString g_CommState[2] = { _T(“打开串口”), _T(“关闭串口”) };  
  51.     //enum CommState Index :关闭状态时显示”打开串口”,打开状态时显示”关闭串口”  
  52.     enum g_eCSI{ CSOFF = 0, CSON };  
  53.   
  54.     const CString g_RSState[2] = { _T(“receive:”), _T(“send:”) };  
  55.     enum g_erssi{ RECV = 0, SEND };//enum reveive send state index  
  56. }  
  57.   
  58. // 用于应用程序“关于”菜单项的 CAboutDlg 对话框  
  59.   
  60. class CAboutDlg : public CDialogEx  
  61. {  
  62. public:  
  63.     CAboutDlg();  
  64.   
  65. // 对话框数据  
  66.     enum { IDD = IDD_ABOUTBOX };  
  67.   
  68.     protected:  
  69.     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持  
  70.   
  71. // 实现  
  72. protected:  
  73.     DECLARE_MESSAGE_MAP()  
  74. };  
  75.   
  76. CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)  
  77. {  
  78. }  
  79.   
  80. void CAboutDlg::DoDataExchange(CDataExchange* pDX)  
  81. {  
  82.     CDialogEx::DoDataExchange(pDX);  
  83. }  
  84.   
  85. BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)  
  86. END_MESSAGE_MAP()  
  87.   
  88.   
  89. // CKELONCommDlg 对话框  
  90.   
  91.   
  92.   
  93. CKELONCommDlg::CKELONCommDlg(CWnd* pParent /=NULL/)  
  94.     : CDialogEx(CKELONCommDlg::IDD, pParent)  
  95.     , m_timesE(1001)  
  96. {  
  97.     m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);  
  98. }  
  99.   
  100. CKELONCommDlg::~CKELONCommDlg()  
  101. {  
  102.     SetConfigInfo(g_configfilepath);  
  103. }  
  104.   
  105. void CKELONCommDlg::DoDataExchange(CDataExchange* pDX)  
  106. {  
  107.     CDialogEx::DoDataExchange(pDX);  
  108. }  
  109.   
  110. BEGIN_MESSAGE_MAP(CKELONCommDlg, CDialogEx)  
  111.     ON_WM_SYSCOMMAND()  
  112.     ON_WM_PAINT()  
  113.     ON_WM_QUERYDRAGICON()  
  114.     ON_BN_CLICKED(IDC_Btn_OpenComm, &CKELONCommDlg::OnBnClickedBtnOpencomm)  
  115.     ON_BN_CLICKED(IDC_Btn_SendData, &CKELONCommDlg::OnBnClickedBtnSenddata)  
  116.     ON_WM_TIMER()  
  117.     ON_BN_CLICKED(IDC_Btn_SetComm, &CKELONCommDlg::OnBnClickedBtnSetcomm)  
  118.     ON_BN_CLICKED(IDOK, &CKELONCommDlg::OnBnClickedOk)  
  119.     ON_BN_CLICKED(IDC_Btn_ClearShowInfo, &CKELONCommDlg::OnBnClickedBtnClearshowinfo)  
  120.     ON_BN_CLICKED(IDC_Btn_About, &CKELONCommDlg::OnBnClickedBtnAbout)  
  121.     ON_BN_CLICKED(IDC_Btn_ClearGrid, &CKELONCommDlg::OnBnClickedBtnCleargrid)  
  122. END_MESSAGE_MAP()  
  123.   
  124. BEGIN_EVENTSINK_MAP(CKELONCommDlg, CDialogEx)  
  125.     ON_EVENT(CKELONCommDlg, IDC_MSCOMM, 1, CKELONCommDlg::OnCommMscomm, VTS_NONE)  
  126. END_EVENTSINK_MAP()  
  127.   
  128. // CKELONCommDlg 消息处理程序  
  129.   
  130. BOOL CKELONCommDlg::OnInitDialog()  
  131. {  
  132.     CDialogEx::OnInitDialog();  
  133.   
  134.     // 将“关于…”菜单项添加到系统菜单中。  
  135.   
  136.     // IDM_ABOUTBOX 必须在系统命令范围内。  
  137.     ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);  
  138.     ASSERT(IDM_ABOUTBOX < 0xF000);  
  139.   
  140.     CMenu* pSysMenu = GetSystemMenu(FALSE);  
  141.     if (pSysMenu != NULL)  
  142.     {  
  143.         BOOL bNameValid;  
  144.         CString strAboutMenu;  
  145.         bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);  
  146.         ASSERT(bNameValid);  
  147.         if (!strAboutMenu.IsEmpty())  
  148.         {  
  149.             pSysMenu->AppendMenu(MF_SEPARATOR);  
  150.             pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);  
  151.         }  
  152.     }  
  153.   
  154.     // 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动  
  155.     //  执行此操作  
  156.     SetIcon(m_hIcon, TRUE);         // 设置大图标  
  157.     SetIcon(m_hIcon, FALSE);        // 设置小图标  
  158.   
  159.     // TODO:  在此添加额外的初始化代码  
  160.     //创建模块串口  
  161.     if (!m_mscomm.Create(nullptr, WS_VISIBLE | WS_CHILD, CRect(0, 0, 0, 0), this, IDC_MSCOMM))  
  162.     {  
  163.         MessageBox(_T(”创建mscomm串口失败”));  
  164.     }  
  165.   
  166.     //设置串口状态  
  167.     GetDlgItem(IDC_Btn_OpenComm)->SetWindowText(g_CommState[g_eCSI::CSOFF]);  
  168.   
  169.     //添加显示信息的滚动条  
  170.     CEdit pedit = (CEdit)GetDlgItem(IDC_Edt_ShowInfo);  
  171.     pedit->ShowScrollBar(SB_VERT, TRUE);//显示滚动条  
  172.   
  173.     //获取程序目录  
  174.     CString dirpath;  
  175.     GetModuleFileName(NULL, dirpath.GetBuffer(MAX_PATH), MAX_PATH);//获取程序的路径,注意GetBuffer里面的MAX_PATH  
  176.     dirpath.ReleaseBuffer();//需要释放,不然的话szPath的长度为0,也就是GetBuffer要和ReleaseBuffer配对使用  
  177.     dirpath = dirpath.Left(dirpath.ReverseFind(’\’));  
  178.   
  179.     //配置路径   
  180.     g_configfilepath = dirpath + _T(”\configinfo.ini”);  
  181.     //获取串口信息  
  182.     GetConfigInfo(g_configfilepath);  
  183.   
  184.     //初始化界面  
  185.     OnInitUI();  
  186.   
  187.     return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE  
  188. }  
  189.   
  190. void CKELONCommDlg::OnInitUI()  
  191. {  
  192.     //初始化表格  
  193.     CRect rc;  
  194.     CWnd pwnd = (this->GetDlgItem(IDC_STATIC_ShowGrid));  
  195.     pwnd->GetWindowRect(&rc);  
  196.     ScreenToClient(&rc);  
  197.     m_datagrid.Create(rc, this, 100);  
  198.   
  199.     m_datagrid.DeleteAllItems();  
  200.     m_datagrid.SetBkColor(RGB(192, 192, 192));  
  201.     m_datagrid.SetColumnCount(5);  
  202.     m_datagrid.SetRowCount(1);  
  203.     m_datagrid.SetFixedColumnCount(5);  
  204.     m_datagrid.SetFixedRowCount(1);  
  205.   
  206.     m_datagrid.SetItemText(0, 0, _T(”正确/错误”));  
  207.     m_datagrid.SetItemText(0, 1, _T(”链路层信息”));  
  208.     m_datagrid.SetItemText(0, 2, _T(”网络层信息”));  
  209.     m_datagrid.SetItemText(0, 3, _T(”传输层信息”));  
  210.     m_datagrid.SetItemText(0, 4, _T(”应用层消息头”));  
  211.   
  212.     m_datagrid.AutoSizeColumns();  
  213.     m_datagrid.ExpandColumnsToFit();  
  214.   
  215.     //  
  216.     //初始化控件  
  217.     CComboBox *pcombo;  
  218.     CString text;  
  219.   
  220.     //链路层应答标识  
  221.     pcombo = (CComboBox)GetDlgItem(IDC_COMBO_LinkRF);  
  222.     for (int i = 0; i != 9; i++)  
  223.     {  
  224.         text.Format(_T(”%d”), i);  
  225.         pcombo->AddString(text);  
  226.     }  
  227.     pcombo->SetCurSel(0);  
  228.   
  229.     //网络层应答标识  
  230.     pcombo = (CComboBox*)GetDlgItem(IDC_COMBO_NWRF);  
  231.     for (int i = 0; i != 9; i++)  
  232.     {  
  233.         text.Format(_T(”%d”), i);  
  234.         pcombo->AddString(text);  
  235.     }  
  236.     pcombo->SetCurSel(0);  
  237.   
  238.     //传输层应答标识  
  239.     pcombo = (CComboBox*)GetDlgItem(IDC_COMBO_TransPortRF);  
  240.     for (int i = 0; i != 9; i++)  
  241.     {  
  242.         text.Format(_T(”%d”), i);  
  243.         pcombo->AddString(text);  
  244.     }  
  245.     pcombo->SetCurSel(0);  
  246.   
  247.     //应用层命令类型消息头  
  248.     pcombo = (CComboBox*)GetDlgItem(IDC_COMBO_AppMsgHead);  
  249.     for (auto it = g_msghead.begin(); it != g_msghead.end(); ++it)  
  250.     {  
  251.         pcombo->AddString(it->first);  
  252.     }  
  253.     if (!g_msghead.empty())  
  254.     {  
  255.         pcombo->SetCurSel(0);  
  256.     }  
  257. }  
  258.   
  259. void CKELONCommDlg::OnSysCommand(UINT nID, LPARAM lParam)  
  260. {  
  261.     if ((nID & 0xFFF0) == IDM_ABOUTBOX)  
  262.     {  
  263.         CAboutDlg dlgAbout;  
  264.         dlgAbout.DoModal();  
  265.     }  
  266.     else  
  267.     {  
  268.         CDialogEx::OnSysCommand(nID, lParam);  
  269.     }  
  270. }  
  271.   
  272. // 如果向对话框添加最小化按钮,则需要下面的代码  
  273. //  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,  
  274. //  这将由框架自动完成。  
  275.   
  276. void CKELONCommDlg::OnPaint()  
  277. {  
  278.     if (IsIconic())  
  279.     {  
  280.         CPaintDC dc(this); // 用于绘制的设备上下文  
  281.   
  282.         SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);  
  283.   
  284.         // 使图标在工作区矩形中居中  
  285.         int cxIcon = GetSystemMetrics(SM_CXICON);  
  286.         int cyIcon = GetSystemMetrics(SM_CYICON);  
  287.         CRect rect;  
  288.         GetClientRect(&rect);  
  289.         int x = (rect.Width() - cxIcon + 1) / 2;  
  290.         int y = (rect.Height() - cyIcon + 1) / 2;  
  291.   
  292.         // 绘制图标  
  293.         dc.DrawIcon(x, y, m_hIcon);  
  294.     }  
  295.     else  
  296.     {  
  297.         CDialogEx::OnPaint();  
  298.     }  
  299. }  
  300.   
  301. //当用户拖动最小化窗口时系统调用此函数取得光标  
  302. //显示。  
  303. HCURSOR CKELONCommDlg::OnQueryDragIcon()  
  304. {  
  305.     return static_cast<HCURSOR>(m_hIcon);  
  306. }  
  307.   
  308.   
  309.   
  310. void CKELONCommDlg::GetConfigInfo(const CString &ifile)  
  311. {  
  312.     //串口信息  
  313.     m_ci.comm = GetPrivateProfileInt(_T(”comminfo”), _T(“comm”), 1, ifile);  
  314.     GetPrivateProfileString(_T(”comminfo”), _T(“baudrate”), _T(“9600”),  
  315.         m_ci.baudrate, 256, ifile);  
  316.     GetPrivateProfileString(_T(”comminfo”), _T(“parity”), _T(“even”),  
  317.         m_ci.parity, 256, ifile);  
  318.     GetPrivateProfileString(_T(”comminfo”), _T(“data”), _T(“8”),  
  319.         m_ci.data, 256, ifile);  
  320.     GetPrivateProfileString(_T(”comminfo”), _T(“stop”), _T(“1”),  
  321.         m_ci.stop, 256, ifile);  
  322.   
  323.     //时间处理  
  324.     //多次发送的时间间隔  
  325.     g_timespan = GetPrivateProfileInt(_T(”timeinfo”),  
  326.         _T(”timespan”), 300, ifile);  
  327.     //最多重发几次 g_sendtimes  
  328.     g_sendtimes = GetPrivateProfileInt(_T(”timeinfo”),  
  329.         _T(”sendtimes”), 3, ifile);  
  330.   
  331.     using std::map;  
  332.     using std::set;  
  333.     //消息头处理  
  334.     //std::map<CString,MsgCmd> g_msghead;//消息头:<描述,命令>  
  335.     int msgcount = GetPrivateProfileInt(_T(“msghead”), _T(“msgcount”), 0, ifile);  
  336.     for (int i = 0; i != msgcount; i++)  
  337.     {  
  338.         MsgCmd mc;  
  339.         CString indexstr;  
  340.         indexstr.Format(_T(”msg%d”), i);  
  341.         mc.cmdtype = GetPrivateProfileInt(indexstr, _T(”cmdtype”), 0, ifile);  
  342.         mc.cmdsubtype = GetPrivateProfileInt(indexstr, _T(”cmdsubtype”), 0, ifile);  
  343.         mc.result = GetPrivateProfileInt(indexstr, _T(”result”), 0, ifile);  
  344.   
  345.         TCHAR szdescrip[1024];  
  346.         GetPrivateProfileString(indexstr, _T(”description”), _T(“”),  
  347.             szdescrip, sizeof(szdescrip), ifile);  
  348.         CString descrip(szdescrip);  
  349.   
  350.         //插入到消息头map中:std::map<CString,MsgCmd> g_msghead;//消息头:<描述,命令>  
  351.         //查找有没有这个消息头命令或消息描述  
  352.         auto findit = std::find_if(g_msghead.begin(), g_msghead.end(),  
  353.             [&mc, &descrip](const std::pair<CString, MsgCmd> &item)  
  354.         {return item.second == mc || item.first == descrip; });  
  355.         if (findit != g_msghead.end())//已存在这个描述或命令  
  356.         {  
  357.             CString errmsg;  
  358.             errmsg.Format(_T(“发现有重复的消息命令头或描述:\r\n\  
  359.                              [cmdtype : %d, cmdsubtype : %d, result : %d, description : %s]\r\n\  
  360.                              [cmdtype : %d, cmdsubtype : %d, result : %d, description : %s]”),  
  361.                 findit->second.cmdtype, findit->second.cmdsubtype,  
  362.                 findit->second.result, findit->first,  
  363.                 mc.cmdtype, mc.cmdsubtype, mc.result, descrip  
  364.                 );  
  365.             MessageBox(errmsg);  
  366.         }  
  367.         else  
  368.         {  
  369.             g_msghead[descrip] = mc;  
  370.         }  
  371.     }  
  372. }  
  373.   
  374. void CKELONCommDlg::SetConfigInfo(const CString &ifile)  
  375. {  
  376.     //串口信息  
  377.     CString commstr;  
  378.     commstr.Format(_T(”%d”), m_ci.comm);  
  379.     WritePrivateProfileString(_T(”comminfo”), _T(“comm”), commstr, ifile);  
  380.     WritePrivateProfileString(_T(”comminfo”), _T(“baudrate”), m_ci.baudrate, ifile);  
  381.     WritePrivateProfileString(_T(”comminfo”), _T(“parity”), m_ci.parity, ifile);  
  382.     WritePrivateProfileString(_T(”comminfo”), _T(“data”), m_ci.data, ifile);  
  383.     WritePrivateProfileString(_T(”comminfo”), _T(“stop”), m_ci.stop, ifile);  
  384. }  
  385.   
  386. void CKELONCommDlg::OnCommMscomm()  
  387. {  
  388.     if (m_mscomm.get_CommEvent() != 2)  
  389.     {  
  390.         return;  
  391.     }  
  392.   
  393.     //读缓冲区信息  
  394.     unsigned char rcvdata[1024] = { 0 };//接收的数据  
  395.     COleSafeArray safearray_inp = m_mscomm.get_Input();//读缓冲区消息  
  396.     DWORD len = safearray_inp.GetOneDimSize();//获取有效数据长度  
  397.     for (long j = 0; j < len; j++)//转化为unsigned char数组  
  398.     {  
  399.         safearray_inp.GetElement(&j, rcvdata + j);  
  400.     }  
  401.     CString Temp;  
  402.     for (long i = 0; i < len; i++)  
  403.     {  
  404.         Temp.AppendFormat(_T(”%.2X ”), rcvdata[i]);  
  405.     }  
  406.     bool havenodata = m_rcvdata.GetDataLength() == 0;  
  407.     ShowInfo si(Temp);  
  408.     if (havenodata)//没有接收数据  
  409.     {  
  410.         si.state = g_RSState[g_erssi::RECV];  
  411.     }   
  412.     AddShowInfo(si);  
  413.   
  414.     //数据处理  
  415.     auto appret = m_rcvdata.appdata(rcvdata, len);  
  416.   
  417.     //判断数据。。。  
  418.     if (appret.first)  
  419.     {  
  420.         KillTimer(m_timesRetE);  
  421.         //显示接收到的数据  
  422.         AddGridData(appret.second);  
  423.     }  
  424. }  
  425.   
  426.   
  427. void CKELONCommDlg::SendData()  
  428. {  
  429.     //判断是否启动模块串口  
  430.     CString ButtonText;  
  431.     GetDlgItem(IDC_Btn_OpenComm)->GetWindowText(ButtonText);  
  432.     if (ButtonText == g_CommState[g_eCSI::CSOFF])  
  433.     {  
  434.         CString errmsg = _T(”没有打开串口”);  
  435.         MessageBox(errmsg);  
  436.         return;  
  437.     }  
  438.       
  439.     CString showinfo;  
  440.     for (int i = 0; i != m_senddata.GetSize(); i++)  
  441.     {  
  442.         showinfo.AppendFormat(_T(”%.2X ”), m_senddata.GetAt(i));  
  443.     }  
  444.     ShowInfo si(showinfo);  
  445.     si.state = g_RSState[g_erssi::SEND];  
  446.     AddShowInfo(si);  
  447.   
  448.     //发送数据  
  449.     m_mscomm.put_Output(COleVariant(m_senddata));  
  450.   
  451.     m_rcvdata.init();//初始化接收帧  
  452.     m_sendtimes = 1;//第一次发送  
  453.   
  454.     //多次发送事件  
  455.     m_timesRetE = SetTimer(m_timesE, g_timespan, NULL);  
  456. }  
  457.   
  458. void CKELONCommDlg::OnTimer(UINT_PTR nIDEvent)  
  459. {  
  460.     // TODO:  在此添加消息处理程序代码和/或调用默认值  
  461.     KillTimer(nIDEvent);  
  462.     if (nIDEvent == m_timesRetE)//多次发送事件  
  463.     {  
  464.         m_sendtimes++;  
  465.         if (m_sendtimes <= g_sendtimes)//发送不满3次  
  466.         {  
  467.             size_t sendtimes = m_sendtimes;  
  468.             SendData();  
  469.             m_sendtimes = sendtimes;  
  470.         }  
  471.         else//发送了3次  
  472.         {  
  473.             //AddShowInfo(_T(“刷新失败”));  
  474.         }  
  475.     }  
  476.     CDialogEx::OnTimer(nIDEvent);  
  477. }  
  478.   
  479. void CKELONCommDlg::OnBnClickedBtnOpencomm()  
  480. {  
  481.     // TODO:  在此添加控件通知处理程序代码  
  482.     if (m_mscomm.get_PortOpen())//如果是打开的,则关闭  
  483.     {  
  484.         m_mscomm.put_PortOpen(FALSE);  
  485.         GetDlgItem(IDC_Btn_OpenComm)->SetWindowText(g_CommState[g_eCSI::CSOFF]);  
  486.         return;  
  487.     }  
  488.     m_mscomm.put__CommPort(m_ci.comm);//选择串口  
  489.     m_mscomm.put_InBufferSize(1024);//接收缓冲区  
  490.     m_mscomm.put_OutBufferSize(1024);//发送缓冲区  
  491.     m_mscomm.put_InputLen(0);//设置当前接受去数据长度为0,表示全部读取  
  492.     m_mscomm.put_InputMode(1);//以二进制方式读写数据  
  493.     m_mscomm.put_RThreshold(1);//接收缓冲区有1个及以上字符时,将响应接收数据事件  
  494.     CString setting;  
  495.     setting.Format(_T(”%s,%c,%s,%s”),  
  496.         m_ci.baudrate, m_ci.parity[0], m_ci.data, m_ci.stop);  
  497.     m_mscomm.put_Settings(setting);//波特率、校验位、数据位、停止位  
  498.     try  
  499.     {  
  500.         m_mscomm.put_PortOpen(TRUE);  
  501.         GetDlgItem(IDC_Btn_OpenComm)->SetWindowText(g_CommState[g_eCSI::CSON]);  
  502.     }  
  503.     catch (CException*)  
  504.     {  
  505.         m_mscomm.put_OutBufferCount(0);  
  506.         CString errmsg;  
  507.         errmsg.Format(_T(”打开串口失败[串口信息:串口号%d,波特率%s,校验位%s,数据位%s,停止位%s]”),  
  508.             m_ci.comm, m_ci.baudrate, m_ci.parity, m_ci.data, m_ci.stop);  
  509.         //AddShowInfo(errmsg);  
  510.     }  
  511. }  
  512.   
  513. void CKELONCommDlg::OnBnClickedBtnSenddata()  
  514. {  
  515.     // TODO:  在此添加控件通知处理程序代码  
  516.     UpdateData(TRUE);  
  517.   
  518.     //获取界面数据信息  
  519.     UIDataInfo di = GetUIDataInfo();  
  520.     if (!di.bOK)//获取界面信息失败  
  521.     {  
  522.         MessageBox(di.errmsg);  
  523.         return;  
  524.     }  
  525.   
  526.     //发送数据  
  527.     //对需要发送的数据组帧  
  528.     auto framedata = FrameHandle::createFrame(di);  
  529.     if (!framedata.bok)//组帧失败  
  530.     {  
  531.         MessageBox(framedata.errmsg);  
  532.         return;  
  533.     }  
  534.     else  
  535.     {  
  536.         m_senddata.RemoveAll();  
  537.         m_senddata.SetSize(framedata.length);  
  538.         for (int i = 0; i < framedata.length; i++)  
  539.         {  
  540.             m_senddata.SetAt(i, framedata.data[i]);  
  541.         }  
  542.   
  543.         SendData();//发送数据  
  544.     }  
  545. }  
  546.   
  547.   
  548. void CKELONCommDlg::OnBnClickedBtnSetcomm()  
  549. {  
  550.     // TODO:  在此添加控件通知处理程序代码  
  551.     CDLGCommConfig commconfigdlg(m_ci, NULL);  
  552.     if (commconfigdlg.DoModal() == IDOK)  
  553.     {  
  554.         CString ButtonText;  
  555.         GetDlgItem(IDC_Btn_OpenComm)->GetWindowText(ButtonText);  
  556.         if (ButtonText == g_CommState[g_eCSI::CSON])  
  557.         {  
  558.             if (m_mscomm.get_PortOpen())  
  559.             {  
  560.                 m_mscomm.put_PortOpen(FALSE);  
  561.             }  
  562.             GetDlgItem(IDC_Btn_OpenComm)->SetWindowText(g_CommState[g_eCSI::CSOFF]);  
  563.         }  
  564.     }  
  565. }  
  566.   
  567.   
  568. UIDataInfo CKELONCommDlg::GetUIDataInfo()  
  569. {  
  570.     UIDataInfo di;  
  571.   
  572.     //略  
  573.       
  574.     return di;  
  575. }  
  576.   
  577.   
  578. void CKELONCommDlg::OnBnClickedOk()  
  579. {  
  580.     // TODO:  在此添加控件通知处理程序代码  
  581.     OnBnClickedBtnSenddata();  
  582.     //CDialogEx::OnOK();  
  583. }  
  584.   
  585. void CKELONCommDlg::AddShowInfo(const ShowInfo &si)  
  586. {  
  587.     CString info;  
  588.     GetDlgItemText(IDC_Edt_ShowInfo, info);  
  589.     int nLen = info.GetLength();  
  590.     if (nLen > 0xffffffff)//以前显示的信息很多,清空  
  591.     {  
  592.         info.Empty();  
  593.     }  
  594.   
  595.     if (!si.state.IsEmpty())//有显示状态  
  596.     {  
  597.         //获取时间  
  598.         auto timepoint = std::chrono::system_clock::now();  
  599.         time_t tm_t = std::chrono::system_clock::to_time_t(timepoint);  
  600.         tm t;  
  601.         localtime_s(&t, &tm_t);  
  602.         char sztime[100];  
  603.         strftime(sztime, sizeof(sztime), “%Y/%m/%d %H:%M:%S”, &t);  
  604.   
  605.         if (!info.IsEmpty())//非空,添加两次换行  
  606.         {  
  607.             info.Append(_T(”\r\n\r\n”));  
  608.         }  
  609.         info.AppendFormat(_T(”%-10s %s\r\n%s”), si.state, CString(sztime), si.info);  
  610.     }  
  611.     else if (si.breturnline)//没有显示状态,需要换行  
  612.     {  
  613.         if (!info.IsEmpty())//非空,添加一次换行  
  614.         {  
  615.             info.Append(_T(”\r\n”));  
  616.         }  
  617.         info.AppendFormat(_T(”%s”), si.info);  
  618.     }  
  619.     else//不需要换行  
  620.     {  
  621.         info.AppendFormat(_T(”%s”), si.info);  
  622.     }  
  623.     SetDlgItemText(IDC_Edt_ShowInfo, info);//收发框会闪烁  
  624.   
  625.     nLen = info.GetLength();  
  626.     CEdit pedit = (CEdit)GetDlgItem(IDC_Edt_ShowInfo);  
  627.     pedit->SetSel(nLen - 1, nLen - 1);//滚动到底部  
  628. }  
  629.   
  630.   
  631. void CKELONCommDlg::OnBnClickedBtnClearshowinfo()  
  632. {  
  633.     // TODO:  在此添加控件通知处理程序代码  
  634.     SetDlgItemText(IDC_Edt_ShowInfo, _T(”“));  
  635. }  
  636.   
  637. bool CKELONCommDlg::JudgeMsg(CString imsg,   
  638.     std::vector<unsigned char> &omsg, CString &oerrmsg)  
  639. {  
  640.     oerrmsg.Empty();  
  641.     omsg.clear();  
  642.   
  643.     USES_CONVERSION;  
  644.   
  645.     //去除中间的空格  
  646.     imsg.Remove(’ ’);  
  647.   
  648.     //判断输入的长度是否为偶数  
  649.     if (imsg.GetLength() % 2)  
  650.     {  
  651.         imsg = _T(”0”) + imsg;  
  652.     }  
  653.     int CurrPos = 0;  
  654.     for (; CurrPos < imsg.GetLength(); CurrPos++)  
  655.     {  
  656.         TCHAR currch = imsg.GetAt(CurrPos);  
  657.         if ((currch >= ‘0’ && currch <= ‘9’)  
  658.             || (currch >= ’a’ && currch <= ‘f’)  
  659.             || (currch >= ’A’ && currch <= ‘F’))  
  660.         {  
  661.         }  
  662.         else  
  663.         {  
  664.             oerrmsg=_T(”消息内容格式不对[应该为0-F]”);  
  665.             return false;  
  666.         }  
  667.     }  
  668.   
  669.     //转换为字节数组  
  670.     CurrPos = 0;  
  671.     int i = 0;  
  672.     for (; CurrPos < imsg.GetLength(); CurrPos += 2)  
  673.     {  
  674.         CString tmpbytestr = imsg.Mid(CurrPos, 2);  
  675.         int tmpbyte;  
  676.         sscanf_s(W2A(tmpbytestr), ”%x”, &tmpbyte);  
  677.         omsg.push_back(tmpbyte);  
  678.     }  
  679.   
  680.     return true;  
  681. }  
  682.   
  683.   
  684. void CKELONCommDlg::OnBnClickedBtnAbout()  
  685. {  
  686.     // TODO:  在此添加控件通知处理程序代码  
  687.     CAboutDlg dlg;  
  688.     dlg.DoModal();  
  689. }  
  690.   
  691. void CKELONCommDlg::AddGridData(const std::vector<UIDataInfo> &uidi)  
  692. {  
  693.     int rowcount = m_datagrid.GetRowCount();  
  694.     m_datagrid.SetRowCount(rowcount + uidi.size());  
  695.   
  696.     for (int i = 0; i != uidi.size(); i++)  
  697.     {  
  698.         CString tmpstr(_T(”√”));  
  699.         if (!uidi[i].bOK)  
  700.         {  
  701.             tmpstr.Format(_T(”× : %s”), uidi[i].errmsg);  
  702.         }  
  703.         m_datagrid.SetItemText(rowcount + i, 0, tmpstr);  
  704.         tmpstr.Format(_T(”%.2X / %.2X”), uidi[i].link.RF, uidi[i].link.flag); // 链路层信息  
  705.         m_datagrid.SetItemText(rowcount + i, 1, tmpstr);  
  706.         tmpstr.Format(_T(”%.2X / %.2X / %.2X%.2X / %.2X%.2X”),  // 网络层信息  
  707.             uidi[i].NW.RF, uidi[i].NW.flag,  
  708.             uidi[i].NW.addr1[0], uidi[i].NW.addr1[1],  
  709.             uidi[i].NW.addr2[0], uidi[i].NW.addr2[1]  
  710.             );  
  711.         m_datagrid.SetItemText(rowcount + i, 2, tmpstr);  
  712.         tmpstr.Format(_T(”%.2X / %.2X”), uidi[i].Transport.RF, uidi[i].Transport.flag); // 传输层信息  
  713.         m_datagrid.SetItemText(rowcount + i, 3, tmpstr);  
  714.         tmpstr.Format(_T(”%.2X / %.2X / %.2X”),  // 应用层消息头  
  715.             uidi[i].App.msghead[0], uidi[i].App.msghead[1], uidi[i].App.msghead[2]);  
  716.         m_datagrid.SetItemText(rowcount + i, 4, tmpstr);  
  717.   
  718.         if (uidi[i].bOK)  
  719.         {  
  720.             const CString parsemsg = parseMsg(uidi[i]);  
  721.             ShowInfo si(parsemsg);  
  722.             si.breturnline = true;  
  723.             AddShowInfo(si);  
  724.         }  
  725.     }  
  726.   
  727.     /m_datagrid.AutoSizeColumns(); 
  728.     m_datagrid.ExpandColumnsToFit();/  
  729.     m_datagrid.EnsureVisible(rowcount, 0);//滚动到最后一行  
  730. }  
  731.   
  732. CString CKELONCommDlg::parseMsg(const UIDataInfo & uidi)  
  733. {  
  734.     using namespace std;  
  735.     CString msg;  
  736.   
  737.     //略  
  738.   
  739.     return msg;  
  740. }  
  741.   
  742. unsigned long CKELONCommDlg::BCDToDec(const unsigned char bcd, int length)  
  743. {  
  744.     int i, tmp;  
  745.     unsigned long dec = 0;  
  746.     for (i = 0; i != length; i++)  
  747.     {  
  748.         tmp = bcd[i];  
  749.         tmp = ((bcd[i] >> 4) & 0x0F)  10 + (bcd[i] & 0x0F);  
  750.         dec = dec  100 + tmp;  
  751.     }  
  752.     return dec;  
  753. }  
  754.   
  755. void CKELONCommDlg::copy_V2A(std::vector<unsigned char>::const_iterator begin,  
  756.     unsigned char *arr, int length)  
  757. {  
  758.     int i = 0;  
  759.     for (auto it = begin; it != begin + length; ++it,++i)  
  760.     {  
  761.         arr[i] = *it;  
  762.     }  
  763. }  
  764.   
  765.   
  766. void CKELONCommDlg::OnBnClickedBtnCleargrid()  
  767. {  
  768.     // TODO:  在此添加控件通知处理程序代码  
  769.     m_datagrid.SetRowCount(1);  
  770.   
  771.     /*m_datagrid.AutoSizeColumns(); 
  772.     m_datagrid.ExpandColumnsToFit();/  
  773. }  
// KELONCommDlg.cpp : 实现文件 
//

include "stdafx.h"

include "KELONComm.h"

include "KELONCommDlg.h"

include "afxdialogex.h"

include <map>

include <set>

include <vector>

include <chrono>

include <algorithm>

//表格处理

include "GridCtrl\CellRange.h"

include "GridCtrl\GridCell.h"

include "GridCtrl\GridCellBase.h"

include "GridCtrl\GridDropTarget.h"

include "GridCtrl\InPlaceEdit.h"

include "GridCtrl\MemDC.h"

include "GridCtrl\TitleTip.h"

ifdef _DEBUG

define new DEBUG_NEW

endif

namespace
{
int g_timespan = 300;//多次发送的时间间隔,300ms
int g_sendtimes = 3;//最多重发这么多次

CString g_configfilepath;//配置路径

struct MsgCmd//消息命令
{
    int cmdtype;//命令类型
    int cmdsubtype;//命令子类型
    int result;//操作结果
    friend bool operator==(const MsgCmd &amp;item1, const MsgCmd &amp;item2)
    {
        return item1.cmdtype == item2.cmdtype
            &amp;&amp; item1.cmdsubtype == item2.cmdsubtype
            &amp;&amp; item1.result == item2.result;
    }
};

std::map&lt;CString,MsgCmd&gt; g_msghead;//消息头:&lt;描述,命令&gt;

const CString g_CommState[2] = { _T("打开串口"), _T("关闭串口") };
//enum CommState Index :关闭状态时显示"打开串口",打开状态时显示"关闭串口"
enum g_eCSI{ CSOFF = 0, CSON };

const CString g_RSState[2] = { _T("receive:"), _T("send:") };
enum g_erssi{ RECV = 0, SEND };//enum reveive send state index

}

// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();

// 对话框数据
enum { IDD = IDD_ABOUTBOX };

protected:
virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()

// CKELONCommDlg 对话框

CKELONCommDlg::CKELONCommDlg(CWnd* pParent /=NULL/)
: CDialogEx(CKELONCommDlg::IDD, pParent)
, m_timesE(1001)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

CKELONCommDlg::~CKELONCommDlg()
{
SetConfigInfo(g_configfilepath);
}

void CKELONCommDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CKELONCommDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_Btn_OpenComm, &CKELONCommDlg::OnBnClickedBtnOpencomm)
ON_BN_CLICKED(IDC_Btn_SendData, &CKELONCommDlg::OnBnClickedBtnSenddata)
ON_WM_TIMER()
ON_BN_CLICKED(IDC_Btn_SetComm, &CKELONCommDlg::OnBnClickedBtnSetcomm)
ON_BN_CLICKED(IDOK, &CKELONCommDlg::OnBnClickedOk)
ON_BN_CLICKED(IDC_Btn_ClearShowInfo, &CKELONCommDlg::OnBnClickedBtnClearshowinfo)
ON_BN_CLICKED(IDC_Btn_About, &CKELONCommDlg::OnBnClickedBtnAbout)
ON_BN_CLICKED(IDC_Btn_ClearGrid, &CKELONCommDlg::OnBnClickedBtnCleargrid)
END_MESSAGE_MAP()

BEGIN_EVENTSINK_MAP(CKELONCommDlg, CDialogEx)
ON_EVENT(CKELONCommDlg, IDC_MSCOMM, 1, CKELONCommDlg::OnCommMscomm, VTS_NONE)
END_EVENTSINK_MAP()

// CKELONCommDlg 消息处理程序

BOOL CKELONCommDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();

// 将“关于...”菜单项添加到系统菜单中。

// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX &amp; 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX &lt; 0xF000);

CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
    BOOL bNameValid;
    CString strAboutMenu;
    bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
    ASSERT(bNameValid);
    if (!strAboutMenu.IsEmpty())
    {
        pSysMenu-&gt;AppendMenu(MF_SEPARATOR);
        pSysMenu-&gt;AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
    }
}

// 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
//  执行此操作
SetIcon(m_hIcon, TRUE);         // 设置大图标
SetIcon(m_hIcon, FALSE);        // 设置小图标

// TODO:  在此添加额外的初始化代码
//创建模块串口
if (!m_mscomm.Create(nullptr, WS_VISIBLE | WS_CHILD, CRect(0, 0, 0, 0), this, IDC_MSCOMM))
{
    MessageBox(_T("创建mscomm串口失败"));
}

//设置串口状态
GetDlgItem(IDC_Btn_OpenComm)-&gt;SetWindowText(g_CommState[g_eCSI::CSOFF]);

//添加显示信息的滚动条
CEdit *pedit = (CEdit*)GetDlgItem(IDC_Edt_ShowInfo);
pedit-&gt;ShowScrollBar(SB_VERT, TRUE);//显示滚动条

//获取程序目录
CString dirpath;
GetModuleFileName(NULL, dirpath.GetBuffer(MAX_PATH), MAX_PATH);//获取程序的路径,注意GetBuffer里面的MAX_PATH
dirpath.ReleaseBuffer();//需要释放,不然的话szPath的长度为0,也就是GetBuffer要和ReleaseBuffer配对使用
dirpath = dirpath.Left(dirpath.ReverseFind('\\'));

//配置路径 
g_configfilepath = dirpath + _T("\\configinfo.ini");
//获取串口信息
GetConfigInfo(g_configfilepath);

//初始化界面
OnInitUI();

return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE

}

void CKELONCommDlg::OnInitUI()
{
//初始化表格
CRect rc;
CWnd *pwnd = (this->GetDlgItem(IDC_STATIC_ShowGrid));
pwnd->GetWindowRect(&rc);
ScreenToClient(&rc);
m_datagrid.Create(rc, this, 100);

m_datagrid.DeleteAllItems();
m_datagrid.SetBkColor(RGB(192, 192, 192));
m_datagrid.SetColumnCount(5);
m_datagrid.SetRowCount(1);
m_datagrid.SetFixedColumnCount(5);
m_datagrid.SetFixedRowCount(1);

m_datagrid.SetItemText(0, 0, _T("正确/错误"));
m_datagrid.SetItemText(0, 1, _T("链路层信息"));
m_datagrid.SetItemText(0, 2, _T("网络层信息"));
m_datagrid.SetItemText(0, 3, _T("传输层信息"));
m_datagrid.SetItemText(0, 4, _T("应用层消息头"));

m_datagrid.AutoSizeColumns();
m_datagrid.ExpandColumnsToFit();

//
//初始化控件
CComboBox *pcombo;
CString text;

//链路层应答标识
pcombo = (CComboBox*)GetDlgItem(IDC_COMBO_LinkRF);
for (int i = 0; i != 9; i++)
{
    text.Format(_T("%d"), i);
    pcombo-&gt;AddString(text);
}
pcombo-&gt;SetCurSel(0);

//网络层应答标识
pcombo = (CComboBox*)GetDlgItem(IDC_COMBO_NWRF);
for (int i = 0; i != 9; i++)
{
    text.Format(_T("%d"), i);
    pcombo-&gt;AddString(text);
}
pcombo-&gt;SetCurSel(0);

//传输层应答标识
pcombo = (CComboBox*)GetDlgItem(IDC_COMBO_TransPortRF);
for (int i = 0; i != 9; i++)
{
    text.Format(_T("%d"), i);
    pcombo-&gt;AddString(text);
}
pcombo-&gt;SetCurSel(0);

//应用层命令类型消息头
pcombo = (CComboBox*)GetDlgItem(IDC_COMBO_AppMsgHead);
for (auto it = g_msghead.begin(); it != g_msghead.end(); ++it)
{
    pcombo-&gt;AddString(it-&gt;first);
}
if (!g_msghead.empty())
{
    pcombo-&gt;SetCurSel(0);
}

}

void CKELONCommDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}

// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。

void CKELONCommDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文

    SendMessage(WM_ICONERASEBKGND, reinterpret_cast&lt;WPARAM&gt;(dc.GetSafeHdc()), 0);

    // 使图标在工作区矩形中居中
    int cxIcon = GetSystemMetrics(SM_CXICON);
    int cyIcon = GetSystemMetrics(SM_CYICON);
    CRect rect;
    GetClientRect(&amp;rect);
    int x = (rect.Width() - cxIcon + 1) / 2;
    int y = (rect.Height() - cyIcon + 1) / 2;

    // 绘制图标
    dc.DrawIcon(x, y, m_hIcon);
}
else
{
    CDialogEx::OnPaint();
}

}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CKELONCommDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}

void CKELONCommDlg::GetConfigInfo(const CString &ifile)
{
//串口信息
m_ci.comm = GetPrivateProfileInt(_T(“comminfo”), _T(“comm”), 1, ifile);
GetPrivateProfileString(_T(“comminfo”), _T(“baudrate”), _T(“9600”),
m_ci.baudrate, 256, ifile);
GetPrivateProfileString(_T(“comminfo”), _T(“parity”), _T(“even”),
m_ci.parity, 256, ifile);
GetPrivateProfileString(_T(“comminfo”), _T(“data”), _T(“8”),
m_ci.data, 256, ifile);
GetPrivateProfileString(_T(“comminfo”), _T(“stop”), _T(“1”),
m_ci.stop, 256, ifile);

//时间处理
//多次发送的时间间隔
g_timespan = GetPrivateProfileInt(_T("timeinfo"),
    _T("timespan"), 300, ifile);
//最多重发几次 g_sendtimes
g_sendtimes = GetPrivateProfileInt(_T("timeinfo"),
    _T("sendtimes"), 3, ifile);

using std::map;
using std::set;
//消息头处理
//std::map&lt;CString,MsgCmd&gt; g_msghead;//消息头:&lt;描述,命令&gt;
int msgcount = GetPrivateProfileInt(_T("msghead"), _T("msgcount"), 0, ifile);
for (int i = 0; i != msgcount; i++)
{
    MsgCmd mc;
    CString indexstr;
    indexstr.Format(_T("msg%d"), i);
    mc.cmdtype = GetPrivateProfileInt(indexstr, _T("cmdtype"), 0, ifile);
    mc.cmdsubtype = GetPrivateProfileInt(indexstr, _T("cmdsubtype"), 0, ifile);
    mc.result = GetPrivateProfileInt(indexstr, _T("result"), 0, ifile);

    TCHAR szdescrip[1024];
    GetPrivateProfileString(indexstr, _T("description"), _T(""),
        szdescrip, sizeof(szdescrip), ifile);
    CString descrip(szdescrip);

    //插入到消息头map中:std::map&lt;CString,MsgCmd&gt; g_msghead;//消息头:&lt;描述,命令&gt;
    //查找有没有这个消息头命令或消息描述
    auto findit = std::find_if(g_msghead.begin(), g_msghead.end(),
        [&amp;mc, &amp;descrip](const std::pair&lt;CString, MsgCmd&gt; &amp;item)
    {return item.second == mc || item.first == descrip; });
    if (findit != g_msghead.end())//已存在这个描述或命令
    {
        CString errmsg;
        errmsg.Format(_T("发现有重复的消息命令头或描述:\r\n\
                         [cmdtype : %d, cmdsubtype : %d, result : %d, description : %s]\r\n\
                         [cmdtype : %d, cmdsubtype : %d, result : %d, description : %s]"),
            findit-&gt;second.cmdtype, findit-&gt;second.cmdsubtype,
            findit-&gt;second.result, findit-&gt;first,
            mc.cmdtype, mc.cmdsubtype, mc.result, descrip
            );
        MessageBox(errmsg);
    }
    else
    {
        g_msghead[descrip] = mc;
    }
}

}

void CKELONCommDlg::SetConfigInfo(const CString &ifile)
{
//串口信息
CString commstr;
commstr.Format(_T(“%d”), m_ci.comm);
WritePrivateProfileString(_T(“comminfo”), _T(“comm”), commstr, ifile);
WritePrivateProfileString(_T(“comminfo”), _T(“baudrate”), m_ci.baudrate, ifile);
WritePrivateProfileString(_T(“comminfo”), _T(“parity”), m_ci.parity, ifile);
WritePrivateProfileString(_T(“comminfo”), _T(“data”), m_ci.data, ifile);
WritePrivateProfileString(_T(“comminfo”), _T(“stop”), m_ci.stop, ifile);
}

void CKELONCommDlg::OnCommMscomm()
{
if (m_mscomm.get_CommEvent() != 2)
{
return;
}

//读缓冲区信息
unsigned char rcvdata[1024] = { 0 };//接收的数据
COleSafeArray safearray_inp = m_mscomm.get_Input();//读缓冲区消息
DWORD len = safearray_inp.GetOneDimSize();//获取有效数据长度
for (long j = 0; j &lt; len; j++)//转化为unsigned char数组
{
    safearray_inp.GetElement(&amp;j, rcvdata + j);
}
CString Temp;
for (long i = 0; i &lt; len; i++)
{
    Temp.AppendFormat(_T("%.2X "), rcvdata[i]);
}
bool havenodata = m_rcvdata.GetDataLength() == 0;
ShowInfo si(Temp);
if (havenodata)//没有接收数据
{
    si.state = g_RSState[g_erssi::RECV];
} 
AddShowInfo(si);

//数据处理
auto appret = m_rcvdata.appdata(rcvdata, len);

//判断数据。。。
if (appret.first)
{
    KillTimer(m_timesRetE);
    //显示接收到的数据
    AddGridData(appret.second);
}

}

void CKELONCommDlg::SendData()
{
//判断是否启动模块串口
CString ButtonText;
GetDlgItem(IDC_Btn_OpenComm)->GetWindowText(ButtonText);
if (ButtonText == g_CommState[g_eCSI::CSOFF])
{
CString errmsg = _T(“没有打开串口”);
MessageBox(errmsg);
return;
}

CString showinfo;
for (int i = 0; i != m_senddata.GetSize(); i++)
{
    showinfo.AppendFormat(_T("%.2X "), m_senddata.GetAt(i));
}
ShowInfo si(showinfo);
si.state = g_RSState[g_erssi::SEND];
AddShowInfo(si);

//发送数据
m_mscomm.put_Output(COleVariant(m_senddata));

m_rcvdata.init();//初始化接收帧
m_sendtimes = 1;//第一次发送

//多次发送事件
m_timesRetE = SetTimer(m_timesE, g_timespan, NULL);

}

void CKELONCommDlg::OnTimer(UINT_PTR nIDEvent)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
KillTimer(nIDEvent);
if (nIDEvent == m_timesRetE)//多次发送事件
{
m_sendtimes++;
if (m_sendtimes <= g_sendtimes)//发送不满3次
{
size_t sendtimes = m_sendtimes;
SendData();
m_sendtimes = sendtimes;
}
else//发送了3次
{
//AddShowInfo(_T(“刷新失败”));
}
}
CDialogEx::OnTimer(nIDEvent);
}

void CKELONCommDlg::OnBnClickedBtnOpencomm()
{
// TODO: 在此添加控件通知处理程序代码
if (m_mscomm.get_PortOpen())//如果是打开的,则关闭
{
m_mscomm.put_PortOpen(FALSE);
GetDlgItem(IDC_Btn_OpenComm)->SetWindowText(g_CommState[g_eCSI::CSOFF]);
return;
}
m_mscomm.put__CommPort(m_ci.comm);//选择串口
m_mscomm.put_InBufferSize(1024);//接收缓冲区
m_mscomm.put_OutBufferSize(1024);//发送缓冲区
m_mscomm.put_InputLen(0);//设置当前接受去数据长度为0,表示全部读取
m_mscomm.put_InputMode(1);//以二进制方式读写数据
m_mscomm.put_RThreshold(1);//接收缓冲区有1个及以上字符时,将响应接收数据事件
CString setting;
setting.Format(_T(“%s,%c,%s,%s”),
m_ci.baudrate, m_ci.parity[0], m_ci.data, m_ci.stop);
m_mscomm.put_Settings(setting);//波特率、校验位、数据位、停止位
try
{
m_mscomm.put_PortOpen(TRUE);
GetDlgItem(IDC_Btn_OpenComm)->SetWindowText(g_CommState[g_eCSI::CSON]);
}
catch (CException*)
{
m_mscomm.put_OutBufferCount(0);
CString errmsg;
errmsg.Format(_T(“打开串口失败[串口信息:串口号%d,波特率%s,校验位%s,数据位%s,停止位%s]”),
m_ci.comm, m_ci.baudrate, m_ci.parity, m_ci.data, m_ci.stop);
//AddShowInfo(errmsg);
}
}

void CKELONCommDlg::OnBnClickedBtnSenddata()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);

//获取界面数据信息
UIDataInfo di = GetUIDataInfo();
if (!di.bOK)//获取界面信息失败
{
    MessageBox(di.errmsg);
    return;
}

//发送数据
//对需要发送的数据组帧
auto framedata = FrameHandle::createFrame(di);
if (!framedata.bok)//组帧失败
{
    MessageBox(framedata.errmsg);
    return;
}
else
{
    m_senddata.RemoveAll();
    m_senddata.SetSize(framedata.length);
    for (int i = 0; i &lt; framedata.length; i++)
    {
        m_senddata.SetAt(i, framedata.data[i]);
    }

    SendData();//发送数据
}

}

void CKELONCommDlg::OnBnClickedBtnSetcomm()
{
// TODO: 在此添加控件通知处理程序代码
CDLGCommConfig commconfigdlg(m_ci, NULL);
if (commconfigdlg.DoModal() == IDOK)
{
CString ButtonText;
GetDlgItem(IDC_Btn_OpenComm)->GetWindowText(ButtonText);
if (ButtonText == g_CommState[g_eCSI::CSON])
{
if (m_mscomm.get_PortOpen())
{
m_mscomm.put_PortOpen(FALSE);
}
GetDlgItem(IDC_Btn_OpenComm)->SetWindowText(g_CommState[g_eCSI::CSOFF]);
}
}
}

UIDataInfo CKELONCommDlg::GetUIDataInfo()
{
    UIDataInfo di;

    //略
    
    return di;
}

void CKELONCommDlg::OnBnClickedOk()
{
// TODO: 在此添加控件通知处理程序代码
OnBnClickedBtnSenddata();
//CDialogEx::OnOK();
}

void CKELONCommDlg::AddShowInfo(const ShowInfo &si)
{
CString info;
GetDlgItemText(IDC_Edt_ShowInfo, info);
int nLen = info.GetLength();
if (nLen > 0xffffffff)//以前显示的信息很多,清空
{
info.Empty();
}

if (!si.state.IsEmpty())//有显示状态
{
    //获取时间
    auto timepoint = std::chrono::system_clock::now();
    time_t tm_t = std::chrono::system_clock::to_time_t(timepoint);
    tm t;
    localtime_s(&amp;t, &amp;tm_t);
    char sztime[100];
    strftime(sztime, sizeof(sztime), "%Y/%m/%d %H:%M:%S", &amp;t);

    if (!info.IsEmpty())//非空,添加两次换行
    {
        info.Append(_T("\r\n\r\n"));
    }
    info.AppendFormat(_T("%-10s %s\r\n%s"), si.state, CString(sztime), si.info);
}
else if (si.breturnline)//没有显示状态,需要换行
{
    if (!info.IsEmpty())//非空,添加一次换行
    {
        info.Append(_T("\r\n"));
    }
    info.AppendFormat(_T("%s"), si.info);
}
else//不需要换行
{
    info.AppendFormat(_T("%s"), si.info);
}
SetDlgItemText(IDC_Edt_ShowInfo, info);//收发框会闪烁

nLen = info.GetLength();
CEdit *pedit = (CEdit*)GetDlgItem(IDC_Edt_ShowInfo);
pedit-&gt;SetSel(nLen - 1, nLen - 1);//滚动到底部

}

void CKELONCommDlg::OnBnClickedBtnClearshowinfo()
{
// TODO: 在此添加控件通知处理程序代码
SetDlgItemText(IDC_Edt_ShowInfo, _T(“”));
}

bool CKELONCommDlg::JudgeMsg(CString imsg,
std::vector<unsigned char> &omsg, CString &oerrmsg)
{
oerrmsg.Empty();
omsg.clear();

USES_CONVERSION;

//去除中间的空格
imsg.Remove(' ');

//判断输入的长度是否为偶数
if (imsg.GetLength() % 2)
{
    imsg = _T("0") + imsg;
}
int CurrPos = 0;
for (; CurrPos &lt; imsg.GetLength(); CurrPos++)
{
    TCHAR currch = imsg.GetAt(CurrPos);
    if ((currch &gt;= '0' &amp;&amp; currch &lt;= '9')
        || (currch &gt;= 'a' &amp;&amp; currch &lt;= 'f')
        || (currch &gt;= 'A' &amp;&amp; currch &lt;= 'F'))
    {
    }
    else
    {
        oerrmsg=_T("消息内容格式不对[应该为0-F]");
        return false;
    }
}

//转换为字节数组
CurrPos = 0;
int i = 0;
for (; CurrPos &lt; imsg.GetLength(); CurrPos += 2)
{
    CString tmpbytestr = imsg.Mid(CurrPos, 2);
    int tmpbyte;
    sscanf_s(W2A(tmpbytestr), "%x", &amp;tmpbyte);
    omsg.push_back(tmpbyte);
}

return true;

}

void CKELONCommDlg::OnBnClickedBtnAbout()
{
// TODO: 在此添加控件通知处理程序代码
CAboutDlg dlg;
dlg.DoModal();
}

void CKELONCommDlg::AddGridData(const std::vector<UIDataInfo> &uidi)
{
int rowcount = m_datagrid.GetRowCount();
m_datagrid.SetRowCount(rowcount + uidi.size());

for (int i = 0; i != uidi.size(); i++)
{
    CString tmpstr(_T("√"));
    if (!uidi[i].bOK)
    {
        tmpstr.Format(_T("× : %s"), uidi[i].errmsg);
    }
    m_datagrid.SetItemText(rowcount + i, 0, tmpstr);
    tmpstr.Format(_T("%.2X / %.2X"), uidi[i].link.RF, uidi[i].link.flag); // 链路层信息
    m_datagrid.SetItemText(rowcount + i, 1, tmpstr);
    tmpstr.Format(_T("%.2X / %.2X / %.2X%.2X / %.2X%.2X"),  // 网络层信息
        uidi[i].NW.RF, uidi[i].NW.flag,
        uidi[i].NW.addr1[0], uidi[i].NW.addr1[1],
        uidi[i].NW.addr2[0], uidi[i].NW.addr2[1]
        );
    m_datagrid.SetItemText(rowcount + i, 2, tmpstr);
    tmpstr.Format(_T("%.2X / %.2X"), uidi[i].Transport.RF, uidi[i].Transport.flag); // 传输层信息
    m_datagrid.SetItemText(rowcount + i, 3, tmpstr);
    tmpstr.Format(_T("%.2X / %.2X / %.2X"),  // 应用层消息头
        uidi[i].App.msghead[0], uidi[i].App.msghead[1], uidi[i].App.msghead[2]);
    m_datagrid.SetItemText(rowcount + i, 4, tmpstr);

    if (uidi[i].bOK)
    {
        const CString parsemsg = parseMsg(uidi[i]);
        ShowInfo si(parsemsg);
        si.breturnline = true;
        AddShowInfo(si);
    }
}

/*m_datagrid.AutoSizeColumns();
m_datagrid.ExpandColumnsToFit();*/
m_datagrid.EnsureVisible(rowcount, 0);//滚动到最后一行

}

CString CKELONCommDlg::parseMsg(const UIDataInfo & uidi)
{
    using namespace std;
    CString msg;

    //略

    return msg;
}

unsigned long CKELONCommDlg::BCDToDec(const unsigned char *bcd, int length)
{
int i, tmp;
unsigned long dec = 0;
for (i = 0; i != length; i++)
{
tmp = bcd[i];
tmp = ((bcd[i] >> 4) & 0x0F) * 10 + (bcd[i] & 0x0F);
dec = dec * 100 + tmp;
}
return dec;
}

void CKELONCommDlg::copy_V2A(std::vector<unsigned char>::const_iterator begin,
unsigned char *arr, int length)
{
int i = 0;
for (auto it = begin; it != begin + length; ++it,++i)
{
arr[i] = *it;
}
}

void CKELONCommDlg::OnBnClickedBtnCleargrid()
{
// TODO: 在此添加控件通知处理程序代码
m_datagrid.SetRowCount(1);

/*m_datagrid.AutoSizeColumns();
m_datagrid.ExpandColumnsToFit();*/

}
配置文件:

  1. //串口配置信息  
  2. //串口comm  
  3. //波特率baudrate  
  4. //校验位parity  
  5. //数据位data  
  6. //停止位stop  
  7.   
  8. [comminfo]  
  9. comm=4  
  10. baudrate=9600  
  11. parity=even  
  12. data=8  
  13. stop=1  
  14.   
  15. //时间信息  
  16. //timespan ms 重发数据  
  17. // 重复发送sendtimes次  
  18. [timeinfo]  
  19. timespan=500  
  20. sendtimes=1  
  21.   
  22. //消息头配置  
  23. //每一个消息头有:命令类型、命令子类型、操作结果、描述信息  
  24. [msghead]  
  25. msgcount=18  
  26. [msg0]  
  27. cmdtype=7  
  28. cmdsubtype=1  
  29. result=0  
  30. description=查询设备版本号  
  31. //。。。。。。  
  32. [msg17]  
  33. cmdtype=103  
  34. cmdsubtype=1  
  35. result=0  
  36. description=读电量模块型号和厂家信息  
//串口配置信息 
//串口comm
//波特率baudrate
//校验位parity
//数据位data
//停止位stop

[comminfo]
comm=4
baudrate=9600
parity=even
data=8
stop=1

//时间信息
//timespan ms 重发数据
// 重复发送sendtimes次
[timeinfo]
timespan=500
sendtimes=1

//消息头配置
//每一个消息头有:命令类型、命令子类型、操作结果、描述信息
[msghead]
msgcount=18
[msg0]
cmdtype=7
cmdsubtype=1
result=0
description=查询设备版本号
//。。。。。。
[msg17]
cmdtype=103
cmdsubtype=1
result=0
description=读电量模块型号和厂家信息



  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值