// CRobotCmdTestDlg.cpp: 实现文件
|
//
|
|
#include "stdafx.h"
|
#include "Servo.h"
|
#include "afxdialogex.h"
|
#include "CRobotCmdTestDlg.h"
|
|
// 日志颜色宏定义
|
#define LOG_COLOR_NORMAL RGB(0, 0, 0) // 普通:黑色
|
#define LOG_COLOR_SUCCESS RGB(0, 128, 0) // 成功:绿色
|
#define LOG_COLOR_ERROR RGB(255, 0, 0) // 错误:红色
|
#define LOG_COLOR_WARNING RGB(255, 165, 0) // 警告:橙色
|
#define LOG_COLOR_TIME RGB(0, 0, 255) // 时间戳:蓝色
|
|
// 快捷命令映射表
|
std::map<CString, QuickCmdFieldMask> g_mapQuickCmd = {
|
{_T("SendHome"), {false, false, false, false, false}},
|
{_T("SendTransfer"), {true, true, true, true, true }},
|
{_T("SendMoveToGet"), {true, true, true, false, false}},
|
{_T("SendMoveToPut"), {true, false, false, true, true }},
|
{_T("SendGet"), {true, true, true, false, false}},
|
{_T("SendPut"), {true, false, false, true, true }},
|
{_T("SendExchange"), {true, true, true, true, true }},
|
{_T("SendCommandClear"), {false, false, false, false, false}},
|
{_T("SendBatchGet"), {true, true, true, false, false}},
|
{_T("SendBatchPut"), {true, false, false, true, true }},
|
{_T("SendMoveToGetAndHome"), {true, true, true, false, false}},
|
{_T("SendMoveToPutAndHome"), {true, false, false, true, true }},
|
{_T("SendTransferAndHome"), {true, true, true, true, true }},
|
{_T("SendGetAndPut"), {true, true, true, true, true }},
|
{_T("SendPutAndHome"), {true, false, false, true, true }}
|
};
|
|
std::map<CString, int> g_mapDeviceSlotCount = {
|
{_T("Port1"), 8},
|
{_T("Port2"), 8},
|
{_T("Port3"), 8},
|
{_T("Port4"), 8},
|
{_T("RB1"), 1},
|
{_T("RB2"), 1},
|
{_T("AL"), 1},
|
{_T("FLIP"), 1},
|
{_T("Bonder1-上产品"), 1},
|
{_T("Bonder1-下产品"), 1},
|
{_T("Bonder2-上产品"), 1},
|
{_T("Bonder2-下产品"), 1},
|
{_T("VacBakeA腔"), 1},
|
{_T("VacBakeB腔"), 1},
|
{_T("BakecCoolingA烘烤"), 1},
|
{_T("BakecCoolingA冷却"), 1},
|
{_T("BakecCoolingB烘烤"), 1},
|
{_T("BakecCoolingB冷却"), 1},
|
{_T("Measurement"), 1}
|
};
|
|
// CRobotCmdTestDlg 对话框
|
|
IMPLEMENT_DYNAMIC(CRobotCmdTestDlg, CDialogEx)
|
|
CRobotCmdTestDlg::CRobotCmdTestDlg(CWnd* pParent /*=nullptr*/)
|
: CDialogEx(IDD_DIALOG_ROBOT_CMD_TEST, pParent)
|
{
|
m_pEFEM = nullptr;
|
}
|
|
CRobotCmdTestDlg::~CRobotCmdTestDlg()
|
{
|
}
|
|
void CRobotCmdTestDlg::SetEFEM(SERVO::CEFEM* pEFEM)
|
{
|
m_pEFEM = pEFEM;
|
}
|
|
void CRobotCmdTestDlg::DoDataExchange(CDataExchange* pDX)
|
{
|
CDialogEx::DoDataExchange(pDX);
|
DDX_Control(pDX, IDC_COMBO_CMD_TYPE, m_comboCmdType);
|
DDX_Control(pDX, IDC_COMBO_ARM_NO, m_comboArmNo);
|
DDX_Control(pDX, IDC_COMBO_GET_POS, m_comboGetPos);
|
DDX_Control(pDX, IDC_COMBO_GET_SLOT, m_comboGetSlot);
|
DDX_Control(pDX, IDC_COMBO_PUT_POS, m_comboPutPos);
|
DDX_Control(pDX, IDC_COMBO_PUT_SLOT, m_comboPutSlot);
|
DDX_Control(pDX, IDC_RICHEDIT_LOG, m_editLog);
|
}
|
|
BEGIN_MESSAGE_MAP(CRobotCmdTestDlg, CDialogEx)
|
ON_BN_CLICKED(IDC_BUTTON_EXECUTE, &CRobotCmdTestDlg::OnBnClickedButtonExecute)
|
ON_CBN_SELCHANGE(IDC_COMBO_CMD_TYPE, &CRobotCmdTestDlg::OnSelchangeComboCmdType)
|
ON_CBN_SELCHANGE(IDC_COMBO_GET_POS, &CRobotCmdTestDlg::OnSelchangeComboGetPos)
|
ON_CBN_SELCHANGE(IDC_COMBO_PUT_POS, &CRobotCmdTestDlg::OnSelchangeComboPutPos)
|
END_MESSAGE_MAP()
|
|
// CRobotCmdTestDlg 消息处理程序
|
|
BOOL CRobotCmdTestDlg::OnInitDialog()
|
{
|
CDialogEx::OnInitDialog();
|
|
// TODO: 在此添加额外的初始化
|
// 初始化命令组合列表
|
for (const auto& pair : g_mapQuickCmd) {
|
m_comboCmdType.AddString(pair.first);
|
}
|
m_comboCmdType.SetCurSel(0);
|
|
// 初始化 Arm No(1:Arm#1,2:Arm#2)
|
m_comboArmNo.AddString(_T("1"));
|
m_comboArmNo.AddString(_T("2"));
|
m_comboArmNo.SetCurSel(0);
|
|
// 示例设备名称列表
|
CStringList eqNameList;
|
eqNameList.AddTail(_T("Port1")); // 1
|
eqNameList.AddTail(_T("Port2")); // 2
|
eqNameList.AddTail(_T("Port3")); // 3
|
eqNameList.AddTail(_T("Port4")); // 4
|
eqNameList.AddTail(_T("RB1")); // 5
|
eqNameList.AddTail(_T("RB2")); // 6
|
eqNameList.AddTail(_T("AL")); // 7
|
eqNameList.AddTail(_T("FLIP")); // 8
|
eqNameList.AddTail(_T("Bonder1-上产品")); // 9
|
eqNameList.AddTail(_T("Bonder1-下产品")); // 10
|
eqNameList.AddTail(_T("Bonder2-上产品")); // 11
|
eqNameList.AddTail(_T("Bonder2-下产品")); // 12
|
eqNameList.AddTail(_T("VacBakeA腔")); // 13
|
eqNameList.AddTail(_T("VacBakeB腔")); // 14
|
eqNameList.AddTail(_T("BakecCoolingA烘烤")); // 15
|
eqNameList.AddTail(_T("BakecCoolingA冷却")); // 16
|
eqNameList.AddTail(_T("BakecCoolingB烘烤")); // 17
|
eqNameList.AddTail(_T("BakecCoolingB冷却")); // 18
|
eqNameList.AddTail(_T("Measurement")); // 19
|
|
for (POSITION pos = eqNameList.GetHeadPosition(); pos != NULL;) {
|
CString item = eqNameList.GetNext(pos);
|
m_comboGetPos.AddString(item);
|
m_comboPutPos.AddString(item);
|
}
|
m_comboGetPos.SetCurSel(0);
|
m_comboPutPos.SetCurSel(0);
|
|
// 初始化 Slot
|
m_comboGetPos.SetCurSel(0);
|
m_comboPutPos.SetCurSel(0);
|
UpdateSlotList(&m_comboGetPos, &m_comboGetSlot);
|
UpdateSlotList(&m_comboPutPos, &m_comboPutSlot);
|
|
// 初始化命令输入控件
|
if (!g_mapQuickCmd.empty()) {
|
UpdateCommandInputUI(g_mapQuickCmd.begin()->first);
|
}
|
|
// 快捷命令执行映射表
|
m_mapCmdExec = {
|
{_T("SendHome"), [this](int seq, int, int, int, int, int, SERVO::ONWRITED onWritedBlock) {
|
return m_pEFEM->robotSendHome(seq, onWritedBlock);
|
}},
|
|
{_T("SendTransfer"), [this](int seq, int armNo, int getPos, int putPos, int getSlot, int putSlot, SERVO::ONWRITED onWritedBlock) {
|
return m_pEFEM->robotSendTransfer(seq, armNo, getPos, putPos, getSlot, putSlot, onWritedBlock);
|
}},
|
|
{_T("SendMoveToGet"), [this](int seq, int armNo, int pos, int, int slot, int, SERVO::ONWRITED onWritedBlock) {
|
return m_pEFEM->robotSendMoveToGet(seq, armNo, pos, slot, onWritedBlock);
|
}},
|
|
{_T("SendMoveToPut"), [this](int seq, int armNo, int, int pos, int, int slot, SERVO::ONWRITED onWritedBlock) {
|
return m_pEFEM->robotSendMoveToPut(seq, armNo, pos, slot, onWritedBlock);
|
}},
|
|
{_T("SendGet"), [this](int seq, int armNo, int pos, int, int slot, int, SERVO::ONWRITED onWritedBlock) {
|
return m_pEFEM->robotSendGet(seq, armNo, pos, slot, onWritedBlock);
|
}},
|
|
{_T("SendPut"), [this](int seq, int armNo, int, int pos, int, int slot, SERVO::ONWRITED onWritedBlock) {
|
return m_pEFEM->robotSendPut(seq, armNo, pos, slot, onWritedBlock);
|
}},
|
|
{_T("SendExchange"), [this](int seq, int armNo, int pos, int, int getSlot, int putSlot, SERVO::ONWRITED onWritedBlock) {
|
return m_pEFEM->robotSendExchange(seq, armNo, pos, getSlot, putSlot, onWritedBlock);
|
}},
|
|
{_T("SendCommandClear"), [this](int seq, int, int, int, int, int, SERVO::ONWRITED onWritedBlock) {
|
return m_pEFEM->robotSendCommandClear(seq, onWritedBlock);
|
}},
|
|
{_T("SendBatchGet"), [this](int seq, int armNo, int pos, int, int slot, int, SERVO::ONWRITED onWritedBlock) {
|
return m_pEFEM->robotSendBatchGet(seq, pos, slot, onWritedBlock);
|
}},
|
|
{_T("SendBatchPut"), [this](int seq, int armNo, int, int pos, int, int slot, SERVO::ONWRITED onWritedBlock) {
|
return m_pEFEM->robotSendBatchPut(seq, pos, slot, onWritedBlock);
|
}},
|
|
{_T("SendMoveToGetAndHome"), [this](int seq, int armNo, int pos, int, int slot, int, SERVO::ONWRITED onWritedBlock) {
|
return m_pEFEM->robotSendMoveToGetAndHome(seq, armNo, pos, slot, onWritedBlock);
|
}},
|
|
{_T("SendMoveToPutAndHome"), [this](int seq, int armNo, int, int pos, int, int slot, SERVO::ONWRITED onWritedBlock) {
|
return m_pEFEM->robotSendMoveToPutAndHome(seq, armNo, pos, slot, onWritedBlock);
|
}},
|
|
{_T("SendTransferAndHome"), [this](int seq, int armNo, int getPos, int putPos, int getSlot, int putSlot, SERVO::ONWRITED onWritedBlock) {
|
return m_pEFEM->robotSendTransferAndHome(seq, armNo, getPos, putPos, getSlot, putSlot, onWritedBlock);
|
}},
|
|
{_T("SendGetAndPut"), [this](int seq, int armNo, int getPos, int putPos, int getSlot, int putSlot, SERVO::ONWRITED onWritedBlock) {
|
return m_pEFEM->robotSendGetAndPut(seq, armNo, getPos, putPos, getSlot, putSlot, onWritedBlock);
|
}},
|
|
{_T("SendPutAndHome"), [this](int seq, int armNo, int, int pos, int, int slot, SERVO::ONWRITED onWritedBlock) {
|
return m_pEFEM->robotSendPutAndHome(seq, armNo, pos, slot, onWritedBlock);
|
}}
|
};
|
|
// 初始化日志框
|
AppendLogLineRichStyled(_T("准备就绪..."), LOG_COLOR_SUCCESS);
|
|
return TRUE; // return TRUE unless you set the focus to a control
|
// 异常: OCX 属性页应返回 FALSE
|
}
|
|
void CRobotCmdTestDlg::UpdateCommandInputUI(const CString& cmdName)
|
{
|
auto it = g_mapQuickCmd.find(cmdName);
|
if (it == g_mapQuickCmd.end()) {
|
AppendLogLineRichStyled(_T("未知的命令类型"), LOG_COLOR_ERROR);
|
return;
|
}
|
|
const QuickCmdFieldMask& mask = it->second;
|
m_comboArmNo.SetCurSel(0);
|
m_comboArmNo.EnableWindow(mask.useArm);
|
m_comboGetPos.SetCurSel(0);
|
m_comboGetPos.EnableWindow(mask.useGetPos);
|
m_comboGetSlot.SetCurSel(0);
|
m_comboGetSlot.EnableWindow(mask.useGetSlot);
|
m_comboPutPos.SetCurSel(0);
|
m_comboPutPos.EnableWindow(mask.usePutPos);
|
m_comboPutSlot.SetCurSel(0);
|
m_comboPutSlot.EnableWindow(mask.usePutSlot);
|
}
|
|
void CRobotCmdTestDlg::AppendLogLineBatchBegin()
|
{
|
m_editLog.SetRedraw(FALSE);
|
m_editLog.SetEventMask(0); // 防止触发不必要的通知
|
}
|
|
void CRobotCmdTestDlg::AppendLogLineBatchEnd()
|
{
|
m_editLog.SetRedraw(TRUE);
|
m_editLog.Invalidate(); // 强制重绘
|
m_editLog.SetEventMask(ENM_CHANGE | ENM_SELCHANGE);
|
}
|
|
void CRobotCmdTestDlg::TrimRichEditLineLimit(int maxLines)
|
{
|
int lineCount = m_editLog.GetLineCount();
|
if (lineCount <= maxLines) {
|
return;
|
}
|
|
// 获取多余行的字符数范围
|
int charIndex = m_editLog.LineIndex(maxLines);
|
m_editLog.SetSel(0, charIndex); // 选中多余内容
|
m_editLog.ReplaceSel(_T("")); // 删除
|
}
|
|
void CRobotCmdTestDlg::AppendLogLineRichStyled(const CString& content, COLORREF color /*= RGB(0, 0, 0)*/)
|
{
|
if (!::IsWindow(GetSafeHwnd())) return;
|
|
// 时间戳
|
CString timestamp;
|
CTime now = CTime::GetCurrentTime();
|
timestamp.Format(_T("[%02d:%02d:%02d] "), now.GetHour(), now.GetMinute(), now.GetSecond());
|
|
// 插入点移到最后(也可以设为 0 表示顶部)
|
m_editLog.SetSel(-1, -1);
|
|
// 插入时间(蓝色)
|
CHARFORMAT2 cfTime = {};
|
cfTime.cbSize = sizeof(cfTime);
|
cfTime.dwMask = CFM_COLOR;
|
cfTime.crTextColor = LOG_COLOR_TIME;
|
m_editLog.SetSelectionCharFormat(cfTime);
|
m_editLog.ReplaceSel(timestamp);
|
|
// 插入日志正文(传入颜色)
|
CHARFORMAT2 cfMsg = {};
|
cfMsg.cbSize = sizeof(cfMsg);
|
cfMsg.dwMask = CFM_COLOR;
|
cfMsg.crTextColor = color;
|
m_editLog.SetSelectionCharFormat(cfMsg);
|
m_editLog.ReplaceSel(content + _T("\r\n"));
|
|
// 限制最大行数
|
TrimRichEditLineLimit(100);
|
}
|
|
void CRobotCmdTestDlg::HighlightAllMatches(const CString& strSearch, COLORREF clrHighlight)
|
{
|
if (strSearch.IsEmpty()) {
|
return;
|
}
|
|
long nStart = 0;
|
long nEnd = m_editLog.GetTextLength();
|
FINDTEXTEX ft = { 0 };
|
ft.chrg.cpMin = 0;
|
ft.chrg.cpMax = nEnd;
|
ft.lpstrText = strSearch.GetString();
|
|
// 高亮前不清除全文颜色,避免历史多色混淆
|
while (m_editLog.FindText(FR_DOWN, &ft) != -1) {
|
m_editLog.SetSel(ft.chrgText.cpMin, ft.chrgText.cpMax);
|
|
CHARFORMAT2 cf = {};
|
cf.cbSize = sizeof(cf);
|
cf.dwMask = CFM_COLOR;
|
cf.crTextColor = clrHighlight;
|
m_editLog.SetSelectionCharFormat(cf);
|
|
// 下次搜索从后面开始
|
ft.chrg.cpMin = ft.chrgText.cpMax;
|
}
|
m_editLog.SetSel(-1, 0);
|
}
|
|
void CRobotCmdTestDlg::UpdateSlotList(CComboBox* pComboDevice, CComboBox* pComboSlot)
|
{
|
if (pComboDevice == nullptr || pComboSlot == nullptr) {
|
return;
|
}
|
|
int nSelIndex = pComboDevice->GetCurSel();
|
if (nSelIndex < 0) {
|
return;
|
}
|
|
CString strDeviceName;
|
pComboDevice->GetLBText(nSelIndex, strDeviceName);
|
|
int nMaxSlot = 1; // 默认槽位数
|
auto it = g_mapDeviceSlotCount.find(strDeviceName);
|
if (it != g_mapDeviceSlotCount.end()) {
|
nMaxSlot = it->second;
|
}
|
else {
|
CString strLog;
|
strLog.Format(_T("设备 %s 未定义槽位数,使用默认值 1"), strDeviceName.GetString());
|
AppendLogLineRichStyled(strLog, LOG_COLOR_WARNING);
|
}
|
|
// 清空并添加槽号
|
pComboSlot->ResetContent();
|
for (int i = 1; i <= nMaxSlot; ++i) {
|
CString str;
|
str.Format(_T("%d"), i);
|
pComboSlot->AddString(str);
|
}
|
|
pComboSlot->SetCurSel(0);
|
pComboSlot->EnableWindow(1 != nMaxSlot);
|
}
|
|
void CRobotCmdTestDlg::UpdateArmList(CComboBox* pComboDevice, CComboBox* pComboArm)
|
{
|
if (pComboDevice == nullptr || pComboArm == nullptr) {
|
return;
|
}
|
|
int nSelIndex = pComboDevice->GetCurSel();
|
if (nSelIndex < 0) {
|
return;
|
}
|
|
CString strDeviceName;
|
pComboDevice->GetLBText(nSelIndex, strDeviceName);
|
if (IsDualArmSupported(strDeviceName)) {
|
pComboArm->EnableWindow(TRUE);
|
}
|
else {
|
pComboArm->EnableWindow(FALSE);
|
}
|
|
pComboArm->SetCurSel(0);
|
}
|
|
bool CRobotCmdTestDlg::IsDualArmSupported(const CString& strDeviceName)
|
{
|
// 注意匹配规则是否区分“-上产品”、“-下产品”等后缀
|
if (strDeviceName.Find(_T("FLIP")) >= 0) return true;
|
if (strDeviceName.Find(_T("Bonder1")) >= 0) return true;
|
if (strDeviceName.Find(_T("Bonder2")) >= 0) return true;
|
return false;
|
}
|
|
void CRobotCmdTestDlg::OnBnClickedButtonExecute()
|
{
|
// TODO: 在此添加控件通知处理程序代码
|
int sel = m_comboCmdType.GetCurSel();
|
if (sel == CB_ERR) {
|
AppendLogLineRichStyled(_T("未选择命令类型"), LOG_COLOR_ERROR);
|
return;
|
}
|
|
CString cmdName;
|
m_comboCmdType.GetLBText(sel, cmdName);
|
|
// 参数收集
|
int armNo = m_comboArmNo.GetCurSel() + 1;
|
int getPos = m_comboGetPos.GetCurSel() + 1;
|
int getSlot = m_comboGetSlot.GetCurSel() + 1;
|
int putPos = m_comboPutPos.GetCurSel() + 1;
|
int putSlot = m_comboPutSlot.GetCurSel() + 1;
|
|
// 查找函数并执行
|
auto it = m_mapCmdExec.find(cmdName);
|
if (it != m_mapCmdExec.end() && nullptr != m_pEFEM) {
|
int ret = it->second(1, armNo, getPos, putPos, getSlot, putSlot, [&](int code) -> int {
|
if (code == WOK) {
|
AppendLogLineRichStyled(_T("已收到Robot回应!"), LOG_COLOR_SUCCESS);
|
}
|
else {
|
AppendLogLineRichStyled(_T("未收到Robot回应!"), LOG_COLOR_ERROR);
|
}
|
|
return 0;
|
});
|
|
CString log;
|
if (ret == 0) {
|
log.Format(_T("执行命令 %s 成功"), cmdName.GetString());
|
AppendLogLineRichStyled(log, LOG_COLOR_SUCCESS);
|
}
|
else {
|
log.Format(_T("执行命令 %s 参数错误"), cmdName.GetString());
|
AppendLogLineRichStyled(log, LOG_COLOR_ERROR);
|
}
|
}
|
else {
|
CString log;
|
log.Format(_T("命令 %s 不存在或 EFEM 未初始化"), cmdName.GetString());
|
AppendLogLineRichStyled(log, LOG_COLOR_ERROR);
|
}
|
}
|
|
void CRobotCmdTestDlg::OnSelchangeComboCmdType()
|
{
|
int nSel = m_comboCmdType.GetCurSel();
|
if (nSel < 0) {
|
return;
|
}
|
|
CString str;
|
m_comboCmdType.GetLBText(nSel, str);
|
UpdateCommandInputUI(str);
|
|
str.Format(_T("切换当前命令类型:%s"), str);
|
AppendLogLineRichStyled(str, LOG_COLOR_NORMAL);
|
}
|
|
void CRobotCmdTestDlg::OnSelchangeComboGetPos()
|
{
|
// TODO: 在此添加控件通知处理程序代码
|
UpdateSlotList(&m_comboGetPos, &m_comboGetSlot);
|
UpdateArmList(&m_comboGetPos, &m_comboArmNo);
|
}
|
|
void CRobotCmdTestDlg::OnSelchangeComboPutPos()
|
{
|
// TODO: 在此添加控件通知处理程序代码
|
UpdateSlotList(&m_comboPutPos, &m_comboPutSlot);
|
UpdateArmList(&m_comboPutPos, &m_comboArmNo);
|
}
|