| | |
| | | #include "Common.h" |
| | | #include "Log.h" |
| | | #include "SecsTestDlg.h" |
| | | #include <chrono> |
| | | #include <thread> |
| | | #include <cmath> |
| | | |
| | | |
| | | #ifdef _DEBUG |
| | | #define new DEBUG_NEW |
| | | #endif |
| | | |
| | | // Image |
| | | #define IMAGE_ROBOT 2 |
| | | |
| | | #define INDICATE_BONDER1 1 |
| | | #define INDICATE_BONDER2 2 |
| | |
| | | #define INDICATE_VACUUM_BAKE 11 |
| | | #define INDICATE_BAKE_COOLING 12 |
| | | #define INDICATE_MEASUREMENT 13 |
| | | |
| | | |
| | | /* 创建终端的定时器 */ |
| | | #define TIMER_ID_CREATE_TERMINAL 1 |
| | | |
| | | |
| | | // 用于应用程序“关于”菜单项的 CAboutDlg 对话框 |
| | |
| | | m_crBkgnd = APPDLG_BACKGROUND_COLOR; |
| | | m_hbrBkgnd = nullptr; |
| | | m_bShowLogWnd = FALSE; |
| | | m_bIsRobotMoving = FALSE; |
| | | m_pLogDlg = nullptr; |
| | | m_pTerminalDisplayDlg = nullptr; |
| | | m_pObserver = nullptr; |
| | | } |
| | | |
| | | void CServoDlg::DoDataExchange(CDataExchange* pDX) |
| | |
| | | ON_UPDATE_COMMAND_UI(ID_MENU_WND_LOG, &CServoDlg::OnUpdateMenuWndLog) |
| | | ON_COMMAND(ID_MENU_HELP_ABOUT, &CServoDlg::OnMenuHelpAbout) |
| | | ON_WM_INITMENUPOPUP() |
| | | ON_WM_TIMER() |
| | | ON_WM_ERASEBKGND() |
| | | END_MESSAGE_MAP() |
| | | |
| | | |
| | | // CServoDlg 消息处理程序 |
| | | |
| | | void CServoDlg::InitRxWindows() |
| | | { |
| | | /* code */ |
| | | // 订阅数据 |
| | | IRxWindows* pRxWindows = RX_GetRxWindows(); |
| | | pRxWindows->enableLog(5); |
| | | if (m_pObserver == NULL) { |
| | | m_pObserver = pRxWindows->allocObserver([&](IAny* pAny) -> void { |
| | | // onNext |
| | | pAny->addRef(); |
| | | int code = pAny->getCode(); |
| | | if (RX_HSMS_TERMINAL_TEXT == code) { |
| | | const char* pszText; |
| | | if (pAny->getStringValue("text", pszText)) { |
| | | ShowTerminalText(pszText); |
| | | } |
| | | } |
| | | else if (RX_CODE_EQ_ALIVE == code) { |
| | | // 通知设备状态 |
| | | SERVO::CEquipment* pEquipment = nullptr; |
| | | if (pAny->getPtrValue("ptr", (void*&)pEquipment)) { |
| | | if (pEquipment != nullptr) { |
| | | int nID = pEquipment->getID(); |
| | | BOOL bAlive = pEquipment->isAlive(); |
| | | if (1 == nID) { |
| | | DeviceStatus status = bAlive ? DeviceStatus::ONLINE : DeviceStatus::OFFLINE; |
| | | UpdateDeviceStatus(INDICATE_ROBOT_ARM1, status); |
| | | UpdateDeviceStatus(INDICATE_ROBOT_ARM2, status); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | pAny->release(); |
| | | }, [&]() -> void { |
| | | // onComplete |
| | | }, [&](IThrowable* pThrowable) -> void { |
| | | // onErrorm |
| | | pThrowable->printf(); |
| | | }); |
| | | |
| | | theApp.m_model.getObservable()->observeOn(pRxWindows->mainThread()) |
| | | ->subscribe(m_pObserver); |
| | | } |
| | | } |
| | | |
| | | BOOL CServoDlg::OnInitDialog() |
| | | { |
| | |
| | | strPath.Format(_T("%s\\res\\Servo001.bmp"), (LPTSTR)(LPCTSTR)theApp.m_strAppDir); |
| | | m_pGraph->AddImage(1, (LPTSTR)(LPCTSTR)strPath, 0, 0); |
| | | |
| | | strPath.Format(_T("%s\\res\\Robot001.bmp"), (LPTSTR)(LPCTSTR)theApp.m_strAppDir); |
| | | m_pGraph->AddImage(IMAGE_ROBOT, (LPTSTR)(LPCTSTR)strPath, 170, 270); |
| | | |
| | | // 添加指示器 |
| | | // Bonder |
| | |
| | | |
| | | |
| | | // Robot |
| | | m_pGraph->AddIndicateBox(INDICATE_ROBOT_ARM1, 620, 294, 48, RGB(22, 22, 22), |
| | | m_pGraph->AddIndicateBox(INDICATE_ROBOT_ARM1, 190, 294, 48, RGB(22, 22, 22), |
| | | RGB(255, 127, 39), RGB(0, 176, 80)); |
| | | m_pGraph->SetBoxText(INDICATE_ROBOT_ARM1, "5", "Robot"); |
| | | m_pGraph->AddIndicateBox(INDICATE_ROBOT_ARM2, 673, 294, 48, RGB(22, 22, 22), |
| | | m_pGraph->AddIndicateBox(INDICATE_ROBOT_ARM2, 243, 294, 48, RGB(22, 22, 22), |
| | | RGB(255, 127, 39), RGB(0, 176, 80)); |
| | | m_pGraph->SetBoxText(INDICATE_ROBOT_ARM2, "6", "Robot"); |
| | | |
| | |
| | | theApp.m_model.init(); |
| | | |
| | | |
| | | SetTimer(TIMER_ID_CREATE_TERMINAL, 3000, nullptr); |
| | | InitRxWindows(); |
| | | OnBnClickedButtonLog(); |
| | | UpdateLogBtn(); |
| | | Resize(); |
| | | |
| | | |
| | | // 相当于延时调用master的初始化 |
| | | theApp.m_model.m_master.init(); |
| | | |
| | | |
| | | return TRUE; // 除非将焦点设置到控件,否则返回 TRUE |
| | | } |
| | | |
| | |
| | | delete m_pLogDlg; |
| | | m_pLogDlg = nullptr; |
| | | } |
| | | if (m_pTerminalDisplayDlg != nullptr) { |
| | | m_pTerminalDisplayDlg->DestroyWindow(); |
| | | delete m_pTerminalDisplayDlg; |
| | | m_pTerminalDisplayDlg = nullptr; |
| | | } |
| | | |
| | | if (m_hbrBkgnd != nullptr) { |
| | | ::DeleteObject(m_hbrBkgnd); |
| | | } |
| | | |
| | | if (m_pObserver != nullptr) { |
| | | m_pObserver->unsubscribe(); |
| | | m_pObserver = NULL; |
| | | } |
| | | |
| | | } |
| | | |
| | | void CServoDlg::OnBnClickedButtonLog() |
| | |
| | | m_btnLog.SetBkgndColor(BS_HOVER, BTN_LOG_BKGND_HOVER); |
| | | m_btnLog.SetBkgndColor(BS_PRESS, BTN_LOG_BKGND_PRESS); |
| | | m_btnLog.Invalidate(); |
| | | } |
| | | |
| | | void CServoDlg::UpdateRobotPosition(float percentage) |
| | | { |
| | | // 限制百分比范围在 [0, 1] 之间 |
| | | if (percentage < 0.0f) percentage = 0.0f; |
| | | if (percentage > 1.0f) percentage = 1.0f; |
| | | |
| | | // 根据百分比计算目标 X 坐标 |
| | | int startX = m_pGraph->GetImage(IMAGE_ROBOT)->x; |
| | | int endX = static_cast<int>(170 + percentage * (700 - 170)); |
| | | |
| | | int arm1Offset = 20; // 从图片到ARM1的偏移 |
| | | int arm2Offset = 73; // 从图片到ARM2的偏移 |
| | | |
| | | // 计算移动所需的时间 |
| | | int distance = abs(endX - startX); |
| | | int duration = static_cast<int>((distance / 100.0) * 1000); |
| | | |
| | | auto startTime = std::chrono::steady_clock::now(); |
| | | auto endTime = startTime + std::chrono::milliseconds(duration); |
| | | |
| | | // 开始移动,设置标记 |
| | | m_bIsRobotMoving = TRUE; |
| | | |
| | | // 开始平滑移动 |
| | | while (std::chrono::steady_clock::now() < endTime) { |
| | | auto currentTime = std::chrono::steady_clock::now(); |
| | | float progress = std::chrono::duration<float, std::milli>(currentTime - startTime).count() / duration; |
| | | progress = min(progress, 1.0f); |
| | | |
| | | // 根据进度计算当前位置 |
| | | int currentX = static_cast<int>(startX + progress * (endX - startX)); |
| | | m_pGraph->UpdateImageCoordinates(IMAGE_ROBOT, currentX, 270); |
| | | m_pGraph->UpdateIndicateBoxCoordinates(INDICATE_ROBOT_ARM1, currentX + arm1Offset, 294); |
| | | m_pGraph->UpdateIndicateBoxCoordinates(INDICATE_ROBOT_ARM2, currentX + arm2Offset, 294); |
| | | |
| | | // 刷新界面 |
| | | Invalidate(); |
| | | UpdateWindow(); |
| | | |
| | | // 控制帧率约为 60 FPS |
| | | std::this_thread::sleep_for(std::chrono::milliseconds(16)); |
| | | } |
| | | |
| | | // 确保最后位置精确到目标位置 |
| | | m_pGraph->UpdateImageCoordinates(IMAGE_ROBOT, endX, 270); |
| | | m_pGraph->UpdateIndicateBoxCoordinates(INDICATE_ROBOT_ARM1, endX + arm1Offset, 294); |
| | | m_pGraph->UpdateIndicateBoxCoordinates(INDICATE_ROBOT_ARM2, endX + arm2Offset, 294); |
| | | |
| | | // 界面重绘 |
| | | Invalidate(); |
| | | |
| | | // 动画结束,设置标记 |
| | | m_bIsRobotMoving = FALSE; |
| | | } |
| | | |
| | | void CServoDlg::RotateRobot(float angleInDegrees) |
| | | { |
| | | // 将角度转换为弧度 |
| | | float angleInRadians = static_cast<float>(std::acos(-1)) / 180.0f * angleInDegrees; |
| | | |
| | | // 获取机器人图片的当前坐标和中心 |
| | | auto* pImage = m_pGraph->GetImage(IMAGE_ROBOT); |
| | | if (!pImage) return; |
| | | |
| | | // 更新 Rotate 图片的角度,确保角度保持在 [0, 360) 范围内 |
| | | m_pGraph->UpdateImageAngle(IMAGE_ROBOT, static_cast<float>(fmod(pImage->angle + angleInDegrees + 360, 360))); |
| | | |
| | | int cx = pImage->x + pImage->bmWidth / 2; // 图片中心 X |
| | | int cy = pImage->y + pImage->bmHeight / 2; // 图片中心 Y |
| | | |
| | | // 旋转指示框的坐标 |
| | | auto* pRobot1 = m_pGraph->GetIndicateBox(INDICATE_ROBOT_ARM1); |
| | | auto* pRobot2 = m_pGraph->GetIndicateBox(INDICATE_ROBOT_ARM2); |
| | | |
| | | if (pRobot1 && pRobot2) { |
| | | int newArmX1 = pImage->x + 20; |
| | | int newArmY1 = 294; |
| | | |
| | | int newArmX2 = pImage->x + 73; |
| | | int newArmY2 = 294; |
| | | |
| | | if (angleInDegrees != 0.0f) { |
| | | // 计算指示框1的新坐标 |
| | | newArmX1 = static_cast<int>(cx + (pRobot1->x - cx) * cos(angleInRadians) - (pRobot1->y - cy) * sin(angleInRadians)); |
| | | newArmY1 = static_cast<int>(cy + (pRobot1->x - cx) * sin(angleInRadians) + (pRobot1->y - cy) * cos(angleInRadians)); |
| | | |
| | | // 计算指示框2的新坐标 |
| | | newArmX2 = static_cast<int>(cx + (pRobot2->x - cx) * cos(angleInRadians) - (pRobot2->y - cy) * sin(angleInRadians)); |
| | | newArmY2 = static_cast<int>(cy + (pRobot2->x - cx) * sin(angleInRadians) + (pRobot2->y - cy) * cos(angleInRadians)); |
| | | } |
| | | |
| | | // 更新指示框的位置 |
| | | m_pGraph->UpdateIndicateBoxCoordinates(INDICATE_ROBOT_ARM1, newArmX1, newArmY1); |
| | | m_pGraph->UpdateIndicateBoxCoordinates(INDICATE_ROBOT_ARM2, newArmX2, newArmY2); |
| | | } |
| | | |
| | | // 强制重绘界面 |
| | | Invalidate(); |
| | | } |
| | | |
| | | void CServoDlg::UpdateDeviceStatus(int id, DeviceStatus status) |
| | | { |
| | | // 根据状态设置颜色 |
| | | COLORREF newBackgroundColor; |
| | | COLORREF newFrameColor1; |
| | | COLORREF newFrameColor2; |
| | | |
| | | switch (status) { |
| | | case ONLINE: |
| | | newBackgroundColor = RGB(255, 0, 0); |
| | | newFrameColor1 = RGB(22, 22, 22); |
| | | newFrameColor2 = RGB(255, 127, 39); |
| | | break; |
| | | case OFFLINE: |
| | | newBackgroundColor = RGB(0, 255, 0); |
| | | newFrameColor1 = RGB(22, 22, 22); |
| | | newFrameColor2 = RGB(255, 127, 39); |
| | | break; |
| | | default: |
| | | newBackgroundColor = RGB(255, 255, 255); // 默认白色背景 |
| | | newFrameColor1 = RGB(0, 0, 0); // 默认黑色框架1 |
| | | newFrameColor2 = RGB(0, 0, 0); // 默认黑色框架2 |
| | | break; |
| | | } |
| | | |
| | | m_pGraph->UpdateIndicateBox1Colors(id, newBackgroundColor, newFrameColor1, newFrameColor2); |
| | | |
| | | // 刷新界面 |
| | | Invalidate(); |
| | | UpdateWindow(); |
| | | } |
| | | |
| | | void CServoDlg::OnSize(UINT nType, int cx, int cy) |
| | |
| | | UpdateLogBtn(); |
| | | LOGE("OnLogDlgHide"); |
| | | |
| | | unsigned int DATAID, RPTID; |
| | | DATAID = 111; |
| | | RPTID = 1001; |
| | | std::vector<std::string> v; |
| | | v.push_back("abc"); |
| | | v.push_back("def"); |
| | | theApp.m_model.m_hsmsPassive.requestEventReportSend(DATAID, RPTID, v); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | |
| | | |
| | | CDialogEx::OnMove(x, y); |
| | | } |
| | | |
| | | void CServoDlg::ShowTerminalText(const char* pszText, unsigned int duration/* = -1*/) |
| | | { |
| | | ASSERT(m_pTerminalDisplayDlg); |
| | | m_pTerminalDisplayDlg->ShowText(pszText, duration); |
| | | } |
| | | |
| | | void CServoDlg::OnTimer(UINT_PTR nIDEvent) |
| | | { |
| | | if (TIMER_ID_CREATE_TERMINAL == nIDEvent) { |
| | | // 预先创建终端窗口 |
| | | KillTimer(TIMER_ID_CREATE_TERMINAL); |
| | | char szBuffer[MAX_PATH]; |
| | | sprintf_s(szBuffer, MAX_PATH, "%s\\RES\\TeminalMsg.html", (LPTSTR)(LPCTSTR)theApp.m_strAppDir); |
| | | m_pTerminalDisplayDlg = new CTerminalDisplayDlg(); |
| | | m_pTerminalDisplayDlg->SetTemplateHtml(szBuffer); |
| | | m_pTerminalDisplayDlg->Create(IDD_DIALOG_TERMINAL_DISPLAY, this); |
| | | } |
| | | |
| | | CDialogEx::OnTimer(nIDEvent); |
| | | } |
| | | |
| | | |
| | | BOOL CServoDlg::OnEraseBkgnd(CDC* pDC) |
| | | { |
| | | // TODO: 在此添加消息处理程序代码和/或调用默认值 |
| | | if (m_bIsRobotMoving) { |
| | | // 禁止刷新背景,避免闪烁 |
| | | return TRUE; |
| | | } |
| | | |
| | | return CDialogEx::OnEraseBkgnd(pDC); |
| | | } |