SECS/GEM 原生态支持C#、C++
- 软件特点:
- 符合SEMI E5、E30、E37 的 SECS 通讯规范
- 提供高速 Transaction 的通讯能力,高性能多线程并发处理Transaction
- 提供 DLL 元件供程式设计者使用
- 快速 Encode 与 Decode Big Message
- 提供VC++、C#等程式语言,提供程式的.Sample Code让程式设计师参考
软件下载地址 www.secsgem.cn
- 开发使用
2.1 添加模块
SECS/GEM 将项目中secs文件拷贝至自己的项目中,同时引入项目
\EquipViewApp\EquipViewApp\secs
|- Group.h
|- SecsBase.cpp
|- SecsBase.h
|- SecsEquip.cpp
|- SecsEquip.h
|- SecsPortExport.h
|- SecsPort.lib (x86/x64) 该lib放置在demo对应的版本中
2.2 运行环境
SECS/GEM Demo对应版本的所有文件都需要拷贝到运行目录下
- JngServer文件夹
- SecsSystemConfig文件夹
- ClientConnect.dll
- ErrInfo.dll
- SecsPort.dll
- Common.dll
SECS/GEM软件完美的支持Microsoft Visual C++6.0 build C++ 6以及后面的版本软件
SECS/GEM 测试软件界面
功能清单
协议支持
// EquipViewAppDlg.cpp : 实现文件
//
#include “stdafx.h”
#include “EquipViewApp.h”
#include “EquipViewAppDlg.h”
#include “afxdialogex.h”
#include “ChildView/ConnectControlView.h”
#include “ChildView/SecsParamentView.h”
#include “ChildView/AlarmView.h”
#include “ChildView/EventView.h”
#include “ChildView/VariableView.h”
#include “ChildView/RemoteView.h”
#include “ChildView/PPTransferView.h”
#include “ChildView/TerminalView.h”
#include “ChildView/LogView.h”
#include “ChildView/ConstantView.h”
#include “ChildView/ThreadTestView.h”
#include “ChildView/PPFormatView.h”
#include “ChildView/AutoSimpleView.h”
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
#define TEST_BY_THREAD
// SECS/GEM CEquipViewAppDlg 对话框
-
CEquipViewAppDlg::CEquipViewAppDlg(CWnd* pParent /
=NULL/)
-
CMyDialogEx(CEquipViewAppDlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
m_activeView = nullptr;
}
void CEquipViewAppDlg::DoDataExchange(CDataExchange* pDX)
{
CMyDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_TREE_FUNCTION, m_treeCtrl);
DDX_Control(pDX, IDC_TAB_CHILD, m_tabChild);
DDX_Control(pDX, IDC_STATIC_TITLE, m_staticTitle);
DDX_Control(pDX, IDC_STATIC_COMM_STATE, m_staticCommState);
DDX_Control(pDX, IDC_STATIC_CONTROL_STATE, m_staticControlState);
DDX_Control(pDX, IDC_EDIT_COMM_STATE, m_editCommState);
DDX_Control(pDX, IDC_EDIT_CONTROL_STATE, m_editControlState);
}
BEGIN_MESSAGE_MAP(CEquipViewAppDlg, CMyDialogEx)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_NOTIFY(TVN_SELCHANGED, IDC_TREE_FUNCTION, OnTvnSelchangedTreeFunction)
ON_WM_DESTROY()
ON_MESSAGE(ON_COMM_CHANGE, OnStateChange)
ON_MESSAGE(ON_CONTROL_CHANGE, OnStateChange)
END_MESSAGE_MAP()
// CEquipViewAppDlg 消息处理程序
// 数据类型
// L
// A data1
// A data2
// …
// A dataN
bool listData(string pListData/* 发送该的Code对应数据 */, list& listDataDes)
{
vector vecTmpData;
RcResult rc = listSplit(pListData, vecTmpData);
if(rc.rc != 0)
{
// 处理失败,解析数据失败
return false;
}
// 解析数据
string pTmp;
for (unsigned int i = 1; i < vecTmpData.size(); i++)
{
pTmp = listElement(vecTmpData[i], 1);
listDataDes.push_back(pTmp);
}
return true;
}
BOOL CEquipViewAppDlg::OnInitDialog()
{
CMyDialogEx::OnInitDialog();
// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
SetName();
ShowWindow(SW_SHOWNOACTIVATE);
SetNewCreateType(false);
// 测试
string pListData;
list<string> listDataDes;
pListData = "L {A 123} {A KKIX} {A A2}";
listData(pListData, listDataDes);
// 初始化连接 SECS
InitConnect();
InitChildArea();
AddView();
InitTree();
// 初始化子窗口
InitCtrl();
InitChildView();
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。
void CEquipViewAppDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
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;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CEquipViewAppDlg::OnQueryDragIcon()
{
return static_cast(m_hIcon);
}
void CEquipViewAppDlg::InitCtrl()
{
m_editControlState.SetWindowText(“OFF-LINE”);
if (g_appdata.m_bCommEnable)
{
string text = GetCommunicationText(eCOMM_ENABLED_NOT_COMMUNICATING);
m_editCommState.SetWindowText(text.c_str());
}
}
// 初始化子窗口
void CEquipViewAppDlg::AddView()
{
AddChildView(“Event”, new CEventView);
AddChildView(“Connect”, new CConnectControlView);
AddChildView(“Remote”, new CRemoteView);
AddChildView(“Terminal”, new CTerminalView);
AddChildView(“Variable”, new CVariableView);
AddChildView(“Alarm”, new CAlarmView);
AddChildView(“PP Transfer”, new CPPTransferView);
AddChildView(“SECS Parament”, new CSecsParamentView);
AddChildView(“Constant”, new CConstantView);
AddChildView(“PP Format”, new CPPFormatView);
AddChildView(“Auto Simple”, new CAutoSimpleView);
// test
#ifdef TEST_BY_THREAD
AddChildView(“temp test”, new CThreadTestView);
#endif
// 设置第一个窗口
SetActiveView("Connect");
}
// 初始化树
void CEquipViewAppDlg::InitTree()
{
HTREEITEM hItem;
// 一级对象
hItem = AddItem(“Equip”, nullptr);
// 二级子对象
AddItem(“Event”, hItem);
AddItem(“Variable”, hItem);
AddItem(“Constant”, hItem);
AddItem(“Alarm”, hItem);
AddItem(“Remote”, hItem);
AddItem(“Terminal”, hItem);
AddItem(“PP Transfer”, hItem);
AddItem(“PP Format”, hItem);
// 一级对象
hItem = AddItem("Connect", nullptr);
AddItem("SECS Parament", hItem);
AddItem("Auto Simple", hItem);
// test
#ifdef TEST_BY_THREAD
AddItem(“temp test”, hItem);
#endif
ExpandAllTree();
}
void CEquipViewAppDlg::ExpandAllTree()
{
HTREEITEM hItem = m_treeCtrl.GetFirstVisibleItem();
while (hItem != nullptr)
{
m_treeCtrl.Expand(hItem, TVE_EXPAND);
hItem = m_treeCtrl.GetNextItem(hItem, TVGN_NEXT);
}
}
// 初始化窗口位置与大小
void CEquipViewAppDlg::InitChildArea()
{
m_tabChild.GetWindowRect(m_rChildRect);
CRect rect;
GetWindowRect(rect);
// 计算长宽
m_rChildRect.bottom -= m_rChildRect.top;
m_rChildRect.right -= m_rChildRect.left;
// 位置偏移
m_rChildRect.top -= 26;
m_rChildRect.left -= 2;
// 计算位置
m_rChildRect.left -= rect.left;
m_rChildRect.top -= rect.top;
m_rChildRect.bottom += m_rChildRect.top;
m_rChildRect.right += m_rChildRect.left;
}
// 发送消息给窗口
LRESULT CEquipViewAppDlg::SendMsgToView(string pViewName, UINT message,
WPARAM wParam /* = 0 /, LPARAM lParam / = 0 /)
{
CMyDialogEx pView = GetView(pViewName);
if(pView != nullptr)
{
if(IsWindow(pView->m_hWnd))
{
return pView->SendMessage(message, wParam, lParam);
}
}
return 0;
}
// 发送消息给窗口
bool CEquipViewAppDlg::PostMsgToView(string pViewName, UINT message,
WPARAM wParam /* = 0 /, LPARAM lParam / = 0 /)
{
CMyDialogEx pView = GetView(pViewName);
if(pView != nullptr)
{
if(IsWindow(pView->m_hWnd))
{
return ((pView->PostMessage(message, wParam, lParam)) == 0);
}
}
return false;
}
// 初始化通讯
bool CEquipViewAppDlg::InitConnect()
{
try
{
m_pSecs = new CSecsEquip();
}
catch (…)
{
m_pSecs = nullptr;
}
if (m_pSecs == nullptr)
{
MessageBox(“错误”, “创建secs通讯对象失败”);
// 暴力退出不推荐
exit(0);
}
// 连接服务器
RcResult rc = m_pSecs->Start();
if (rc.rc != 0)
{
MessageBox(rc.ToString().c_str(), "JNG_Server.exe没有初始化");
// 暴力退出不推荐
exit(0);
}
// 初始化其他
// 设置参数
rc = m_pSecs->SetIP(g_appdata.m_pAddress); SHOW_MSG_RC(rc);
rc = m_pSecs->SetPort(g_appdata.m_nPort); SHOW_MSG_RC(rc);
rc = m_pSecs->SetPassive(g_appdata.m_bPassive); SHOW_MSG_RC(rc);
rc = m_pSecs->SetDeviceID(g_appdata.m_nDeviceID); SHOW_MSG_RC(rc);
rc = m_pSecs->SetMDLN(g_appdata.m_pInterfaceName); SHOW_MSG_RC(rc);
rc = m_pSecs->SetEnableLog(g_appdata.m_bEnableLog); SHOW_MSG_RC(rc);
rc = m_pSecs->SetT1(g_appdata.m_nTimeout[0]); SHOW_MSG_RC(rc);
rc = m_pSecs->SetT2(g_appdata.m_nTimeout[1]); SHOW_MSG_RC(rc);
rc = m_pSecs->SetT3(g_appdata.m_nTimeout[2]); SHOW_MSG_RC(rc);
rc = m_pSecs->SetT4(g_appdata.m_nTimeout[3]); SHOW_MSG_RC(rc);
rc = m_pSecs->SetT5(g_appdata.m_nTimeout[4]); SHOW_MSG_RC(rc);
rc = m_pSecs->SetT6(g_appdata.m_nTimeout[5]); SHOW_MSG_RC(rc);
rc = m_pSecs->SetT7(g_appdata.m_nTimeout[6]); SHOW_MSG_RC(rc);
// 设置winrar.exe的路径
// 如果recipe是单个文档,无需设置
m_pSecs->SetWinrarPath("C:/Program Files/WinRAR/WinRAR.exe");
// 设置回调
m_pSecs->SetClientData(this);
m_pSecs->m_pTerminalCallback = ::OnTerminalProc;
m_pSecs->m_pStateChangeCallback = ::OnStateChangeProc;
m_pSecs->m_pRemoteCallback = ::OnRemoteProc;
// 示例的回调
m_pSecs->m_pConstantsChangeCallback = ::OnConstantChangeProc;
m_pSecs->m_pVarValueProc = ::OnVarValueProc;
m_pSecs->m_pConstantValueProc = ::OnVarValueProc;
m_pSecs->m_pPPNameListProc = ::OnPPNameListProc;
m_pSecs->m_pPPEventProc = ::OnSecsPPEventProc;
// 示例的回调内容结束
// 特殊
m_pSecs->m_pPPFormatValueProc = OnPPFormatValueProc;
// 通过Csv文件加载配置
rc = m_pSecs->LoadDataByCsvFile();
SHOW_MSG_RC(rc);
// test代码,请忽略
TestCode();
// 建立通讯
rc = m_pSecs->SetControlMode((CONTROL_MODE)g_appdata.m_nControlMode);
SHOW_MSG_RC(rc);
if(g_appdata.m_bCommEnable)
{
rc = m_pSecs->CommEnable();
SHOW_MSG_RC(rc);
}
return true;
}
// 测试代码
// 请忽略
void CEquipViewAppDlg::TestCode()
{
RcResult rc;
// 测试加载参数,测试代码
TestData();
TestReportLinke();
m_pSecs->LoadSecsConfig();
// m_pSecs->LoadSecsConfig(“D:\SECS Soft\SECS debug\SecsSystemConfig/TSMC/”);
// m_pSecs->SetLogDir("C:\\A\\");
// 设置自定义处理PP事务
m_pSecs->PPHandleMode(::eCostomizeHandle);
}
// 测试数据
void CEquipViewAppDlg::TestData()
{
RcResult rc;
// method handle
rc = m_pSecs->VariableAdd(1260, "method_test", "method test", "A", "1", "um"); SHOW_MSG_RC(rc);
rc = m_pSecs->VariableAdd(1261, "addr", "method test", "U4", "1", "um"); SHOW_MSG_RC(rc);
rc = m_pSecs->VariableAdd(1270, "addr", "method test", "L", "", "um"); SHOW_MSG_RC(rc);
rc = m_pSecs->VariableAdd(2200, "addr", "method test", "A", "1", ""); SHOW_MSG_RC(rc);
rc = m_pSecs->VariableSetMethod(1260, ::OnVarValueProc); SHOW_MSG_RC(rc);
rc = m_pSecs->VariableSetMethod(1261, ::OnVarValueProc); SHOW_MSG_RC(rc);
rc = m_pSecs->VariableSetMethod(1270, ::OnVarValueProc); SHOW_MSG_RC(rc);
rc = m_pSecs->ConstantsAdd(4004, "Constant 4004", "Constants", "A", "", "", "", ""); SHOW_MSG_RC(rc);
rc = m_pSecs->ConstantsSetMethod(4004, ::OnVarValueProc); SHOW_MSG_RC(rc);
}
// 报表关联例子
void CEquipViewAppDlg::TestReportLinke()
{
RcResult rc;
// 定义报表
std::vector<int> varID;
varID.push_back(1260);
varID.push_back(1261);
rc = m_pSecs->ReportDefine(5000, varID); SHOW_MSG_RC(rc);
varID.clear();
varID.push_back(1261);
rc = m_pSecs->ReportDefine(5001, varID); SHOW_MSG_RC(rc);
varID.clear();
varID.push_back(672);
rc = m_pSecs->ReportDefine(5002, varID); SHOW_MSG_RC(rc);
// 事件-报表关联
rc = m_pSecs->EventReportLink(8004, 5001); SHOW_MSG_RC(rc);
rc = m_pSecs->EventReportLink(1150, 5002); SHOW_MSG_RC(rc);
}
void CEquipViewAppDlg::OnTvnSelchangedTreeFunction(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast(pNMHDR);
HTREEITEM hItem = pNMTreeView->itemNew.hItem;
string pSel = m_treeCtrl.GetItemText (hItem);
// 显示选中页面
SetActiveView(pSel);
*pResult = 0;
}
// 增加显示对象
HTREEITEM CEquipViewAppDlg::AddItem(string name, HTREEITEM hItem)
{
HTREEITEM hChild = nullptr;
if(hItem == nullptr)
{
hChild = m_treeCtrl.InsertItem(name.c_str(), NULL, NULL);
}
else
{
hChild = m_treeCtrl.InsertItem(name.c_str(), NULL, NULL, hItem);
}
return hChild;
}
// 增加窗口
void CEquipViewAppDlg::AddChildView(string name, CMyDialogEx* pView)
{
if(pView == nullptr)
{
return ;
}
pView->SetMainView(this); // 自己就是主界面
pView->SetSecs(m_pSecs);
pView->SetConnectName(m_pConnectName);
pView->Create(pView->GetIDD());
AddMap(name, pView);
}
// 显示指定窗口
void CEquipViewAppDlg::SetActiveView(string name)
{
CMyDialogEx* pView = GetViewMap(name);
if (pView == nullptr)
{
return;
}
// 隐藏之前的窗口
if(m_activeView != nullptr)
{
m_activeView->ShowWindow(SW_HIDE);
}
// 新窗口
pView->SetParent(this);
pView->ShowWindow(SW_SHOW);
m_activeView = pView;
// 设置标题
string pTitle = pView->GetTitle();
m_staticTitle.SetWindowText(pTitle.c_str());
// 设置位置
pView->MoveWindow(m_rChildRect.left, m_rChildRect.top,
m_rChildRect.right - m_rChildRect.left, m_rChildRect.bottom - m_rChildRect.top, TRUE);
}
// 映射操作
void CEquipViewAppDlg::AddMap(string name, CMyDialogEx* pView)
{
map<string, CMyDialogEx*>::iterator ite;
vLocker lock(&m_syncMapOpt);
ite = m_mapChildView.find(name);
if(ite != m_mapChildView.end())
{
m_mapChildView.erase(ite);
}
m_mapChildView.insert(make_pair(name, pView));
}
// SECS/GEM获取窗口
CMyDialogEx* CEquipViewAppDlg::GetViewMap(string name)
{
map<string, CMyDialogEx*>::iterator ite;
vLocker lock(&m_syncMapOpt);
ite = m_mapChildView.find(name);
if(ite != m_mapChildView.end())
{
return ite->second;
}
return nullptr;
}
// SECS/GEM关闭窗口
// SECS/GEM释放资源
BOOL CEquipViewAppDlg::DestroyWindow()
{
// 关闭窗口
CMyDialogEx* pView;
map<string, CMyDialogEx*>::iterator ite;
for (ite = m_mapChildView.begin(); ite != m_mapChildView.end(); ite++)
{
pView = ite->second;
if(pView != nullptr)
{
pView->DestroyWindow();
}
}
// 释放SECS
if(m_pSecs != nullptr)
{
m_pSecs->Abort();
delete m_pSecs;
}
g_appdata.Save();
// 调用父类释放自己
return CMyDialogEx::DestroyWindow();
}
// 初始化子窗口
void CEquipViewAppDlg::InitChildView()
{
CMyDialogEx* pView;
map<string, CMyDialogEx*>::iterator ite;
for (ite = m_mapChildView.begin(); ite != m_mapChildView.end(); ite++)
{
pView = ite->second;
if(pView != nullptr)
{
pView->OnInitView();
}
}
}
// 获取窗口
CMyDialogEx* CEquipViewAppDlg::GetView(string name)
{
CMyDialogEx* pView = nullptr;
map<string, CMyDialogEx*>::iterator ite;
ite = m_mapChildView.find(name);
if(ite != m_mapChildView.end())
{
pView = ite->second;
}
return pView;
}
const char* CEquipViewAppDlg::SecsVarValue(int varID)
{
SYSTEMTIME time;
GetLocalTime(&time);
static CString result;
switch (varID)
{
case 1260: result = ::g_appdata.GetExePath().c_str(); break;
case 1261: result = IntToString(time.wSecond).c_str(); break;
case 4004: result.Format("dynamic constant value %d", time.wMilliseconds); break;
case 1270:
{
// L 类型变量示例
// 极其少情况下使用到
string nMinute = listJoin("A", IntToString(time.wMinute).c_str());
string nSec = listJoin("U4", IntToString(time.wSecond).c_str());
string nMilliseconds = listJoin("I4", IntToString(time.wMilliseconds).c_str());
string pLTypeTmp = listJoin(nMinute.c_str(),
nSec.c_str(),
nMilliseconds.c_str());
result = pLTypeTmp.c_str();
}
break;
default:
{
result = "";
CString pTmp;
pTmp.Format("error variable %d, please contact the engineer", varID);
OutputDebugString(pTmp);
}
break;
}
return (LPCSTR)result;
}
LRESULT CEquipViewAppDlg::OnStateChange(WPARAM wp, LPARAM lp)
{
if(wp == ::eCommStateChange)
{
string text = GetCommunicationText((COMM_STATE)lp);
m_editCommState.SetWindowText(text.c_str());
}
else if(wp == ::eControlStateChange)
{
string text = GetControlText((CONTROL_STATE)lp);
m_editControlState.SetWindowText(text.c_str());
}
return 0;
}
// 设置标题
void CEquipViewAppDlg::SetName()
{
CString title;
title = “EquipViewApp( www.semisecs.com )”;
SetWindowText(title);
}
// 参数的类型
// listParament参数的列表
string RecipeJoin(list listParament, string pDataFormat)
{
string pTmp;
list listSML;
list::iterator ite;
listSML.push_back(“L”);
for (ite = listParament.begin(); ite != listParament.end(); ite++)
{
pTmp = listJoin(pDataFormat.c_str(), ite->c_str());
listSML.push_back(pTmp);
}
pTmp = listJoin(listSML);
return pTmp;
}
// 服务器请求设备上存在的recipe参数
// 调用顺序如下
// 回调函数保证数据是每次询问完一次recipe才会到下一次
const char* CEquipViewAppDlg::SecsPPFormatValue(PP_FORMAT_CMD pp_cmd, const char* pCmd)
{
if(pp_cmd == eLOAD_TMP_PPID)
{
// 第一步:加载硬盘的recipe到一个recipe临时变量里面
int nRS = SendMsgToView(“PP Format”, ON_PP_FORMAT, 0, (LPARAM)pCmd);
if(nRS == 0)
{
return “0”;
}
}
else if(pp_cmd == eGET_PPID_VALUE)
{
// 第二步:回调会咨询每一个FormatPP.csv里面ID的值
// 将ID映射到临时recipe变量的参数值,作为返回值返回
int nCmdCode = ::atoi(pCmd);
switch(nCmdCode)
{
case 1: return ::g_statu.param1.c_str();
case 2: return ::g_statu.param2.c_str();
case 3:
{
list listParament;
string pDataFormat = “A”;
listParament.push_back(“1.2”);
listParament.push_back(“31.223”);
listParament.push_back(“11.21”);
listParament.push_back(“14.32”);
::g_statu.param3 = RecipeJoin(listParament, pDataFormat);
return ::g_statu.param3.c_str();
}
break;
}
}
return “”;
}