LAPTOP-SNT8I5JK\Boounion
2025-02-10 02c39baf5375f1588e9c20dc06d89a0605077672
Merge branch 'liuyang' into clh

# Conflicts:
# SourceCode/Bond/Servo/Servo.vcxproj.filters
# SourceCode/Bond/Servo/ServoDlg.cpp
# SourceCode/Bond/Servo/ServoDlg.h
已添加6个文件
已修改17个文件
已删除2个文件
1417 ■■■■ 文件已修改
SourceCode/Bond/BoounionPLC/AddPLCInfo.cpp 124 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/AddPLCInfo.h 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/AxisDetailSettingsDlg.cpp 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/AxisSettingsDlg.cpp 205 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/AxisSettingsDlg.h 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/BoounionPLC.rc 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/BoounionPLC.vcxproj 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/BoounionPLC.vcxproj.filters 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/BoounionPLCDlg.cpp 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/RegexEdit.cpp 146 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/RegexEdit.h 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/Resource.h 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/AlarmManager.cpp 289 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/AlarmManager.h 163 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.cpp 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.h 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.vcxproj 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.vcxproj.filters 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/ServoDlg.cpp 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/ServoDlg.h 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/ServoGraph.cpp 92 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/ServoGraph.h 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/stdafx.h 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/x64/Debug/Res/Robot001.bmp 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/x64/Debug/Res/Servo002.bmp 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/BoounionPLC/AddPLCInfo.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,124 @@
// AddPLCInfo.cpp: å®žçŽ°æ–‡ä»¶
//
#include "stdafx.h"
#include "BoounionPLC.h"
#include "afxdialogex.h"
#include "AddPLCInfo.h"
// CAddPLCInfo å¯¹è¯æ¡†
IMPLEMENT_DYNAMIC(CAddPLCInfo, CDialogEx)
CAddPLCInfo::CAddPLCInfo(CWnd* pParent /*=nullptr*/)
    : CDialogEx(IDD_DIALOG_ADD_PLC_INFO, pParent)
{
}
CAddPLCInfo::~CAddPLCInfo()
{
}
CString CAddPLCInfo::GetPLCName() { return m_strPLCName; }
CString CAddPLCInfo::GetIP() { return m_strIP; }
CString CAddPLCInfo::GetPort() { return m_strPort; }
bool CAddPLCInfo::IsValidPort(const CString& strPort)
{
    // åˆ¤æ–­æ˜¯å¦ä¸ºæ•°å­—
    for (int i = 0; i < strPort.GetLength(); ++i) {
        if (!_istdigit(strPort[i])) {
            return false; // éžæ•°å­—
        }
    }
    // è½¬æ¢ä¸ºæ•´æ•°å¹¶åˆ¤æ–­èŒƒå›´
    int nPort = _ttoi(strPort);
    return nPort >= 1 && nPort <= 65535;
}
bool CAddPLCInfo::IsValidIPAddress(const CString& strIP1, const CString& strIP2, const CString& strIP3, const CString& strIP4)
{
    // æ ¡éªŒæ¯ä¸€æ®µæ˜¯å¦æ˜¯æ•°å­—并在范围内
    return IsValidIPSegment(strIP1) &&
        IsValidIPSegment(strIP2) &&
        IsValidIPSegment(strIP3) &&
        IsValidIPSegment(strIP4);
}
bool CAddPLCInfo::IsValidIPSegment(const CString& strSegment)
{
    // åˆ¤æ–­æ˜¯å¦ä¸ºæ•°å­—
    for (int i = 0; i < strSegment.GetLength(); ++i) {
        if (!_istdigit(strSegment[i])) {
            return false; // éžæ•°å­—
        }
    }
    // è½¬æ¢ä¸ºæ•´æ•°å¹¶åˆ¤æ–­èŒƒå›´
    int nSegment = _ttoi(strSegment);
    return nSegment >= 0 && nSegment <= 255;
}
void CAddPLCInfo::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_EDIT_PLC_NAME, m_editPLCName);
    DDX_Control(pDX, IDC_EDIT_PORT, m_editPort);
}
BEGIN_MESSAGE_MAP(CAddPLCInfo, CDialogEx)
    ON_BN_CLICKED(IDOK, &CAddPLCInfo::OnBnClickedOk)
END_MESSAGE_MAP()
// CAddPLCInfo æ¶ˆæ¯å¤„理程序
void CAddPLCInfo::OnBnClickedOk()
{
    // TODO: åœ¨æ­¤æ·»åŠ æŽ§ä»¶é€šçŸ¥å¤„ç†ç¨‹åºä»£ç 
    CString strIPAddr1;
    CString strIPAddr2;
    CString strIPAddr3;
    CString strIPAddr4;
    m_editPLCName.GetWindowText(m_strPLCName);
    if (m_strPLCName.IsEmpty()) {
        AfxMessageBox(_T("PLC åç§°ä¸èƒ½ä¸ºç©ºï¼"));
        return;
    }
    // æ ¡éªŒç«¯å£å·
    m_editPort.GetWindowText(m_strPort);
    if (!IsValidPort(m_strPort)) {
        AfxMessageBox(_T("端口号不合法!请输入 1 åˆ° 65535 ä¹‹é—´çš„æ•°å­—。"));
        return;
    }
    // æ ¡éªŒIP地址
    GetDlgItem(IDC_EDIT_IP_ADDR1)->GetWindowText(strIPAddr1);
    GetDlgItem(IDC_EDIT_IP_ADDR2)->GetWindowText(strIPAddr2);
    GetDlgItem(IDC_EDIT_IP_ADDR3)->GetWindowText(strIPAddr3);
    GetDlgItem(IDC_EDIT_IP_ADDR4)->GetWindowText(strIPAddr4);
    if (strIPAddr1.IsEmpty() || strIPAddr2.IsEmpty() || strIPAddr3.IsEmpty() || strIPAddr4.IsEmpty()) {
        AfxMessageBox(_T("IP åœ°å€ä¸åˆæ³•!每段不能为空。"));
        return;
    }
    if (!IsValidIPAddress(strIPAddr1, strIPAddr2, strIPAddr3, strIPAddr4)) {
        AfxMessageBox(_T("IP åœ°å€ä¸åˆæ³•!每段必须是 0 åˆ° 255 çš„æ•°å­—。"));
        return;
    }
    // æ‹¼æŽ¥IP地址
    m_strIP.Format(_T("%s.%s.%s.%s"), strIPAddr1, strIPAddr2, strIPAddr3, strIPAddr4);
    CDialogEx::OnOK();
}
SourceCode/Bond/BoounionPLC/AddPLCInfo.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,43 @@
#pragma once
#include "afxdialogex.h"
// CAddPLCInfo å¯¹è¯æ¡†
class CAddPLCInfo : public CDialogEx
{
    DECLARE_DYNAMIC(CAddPLCInfo)
public:
    CAddPLCInfo(CWnd* pParent = nullptr);   // æ ‡å‡†æž„造函数
    virtual ~CAddPLCInfo();
    // èŽ·å–plc名称\ip\端口
    CString GetPLCName();
    CString GetIP();
    CString GetPort();
// å¯¹è¯æ¡†æ•°æ®
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_DIALOG_ADD_PLC_INFO };
#endif
protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV æ”¯æŒ
    afx_msg void OnBnClickedOk();
    DECLARE_MESSAGE_MAP()
private:
    bool IsValidPort(const CString& strPort);
    bool IsValidIPAddress(const CString& strIP1, const CString& strIP2, const CString& strIP3, const CString& strIP4);
    bool IsValidIPSegment(const CString& strSegment);
    // æ•°æ®
    CString m_strPLCName;
    CString m_strIP;
    CString m_strPort;
    // æŽ§ä»¶
    CEdit m_editPLCName;
    CEdit m_editPort;
};
SourceCode/Bond/BoounionPLC/AxisDetailSettingsDlg.cpp
@@ -460,6 +460,16 @@
    strTitle.Format(_T("轴细部设定(PLC: %s)"), m_pPLC->getName().c_str());
    SetWindowText(strTitle);
    // ä¸å¯ç¼–辑
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_POS_MIN)->EnableWindow(FALSE);
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_AUTO_SPEED_MIN)->EnableWindow(FALSE);
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_ACCE_TIME_MIN)->EnableWindow(FALSE);
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_ACCE_TIME_MAX)->EnableWindow(FALSE);
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_DECE_TIME_MIN)->EnableWindow(FALSE);
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_DECE_TIME_MAX)->EnableWindow(FALSE);
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_MICROMENTUM_MIN)->EnableWindow(FALSE);
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_MICROMENTUM_MAX)->EnableWindow(FALSE);
    // èŽ·å–è½´æ•°æ®
    auto axisDetails = m_pAxisManager->GetAxis(m_nAxisNO);
    if (axisDetails.id == -1) {
SourceCode/Bond/BoounionPLC/AxisSettingsDlg.cpp
@@ -8,6 +8,7 @@
#include "AxisDetailSettingsDlg.h"
#include "ToolUnits.h"
#include <cctype>
#include <regex>
#define COLOR_GREEN_ON    RGB(0, 255, 0)  // æ­£å¸¸çŠ¶æ€ç»¿è‰²
@@ -53,10 +54,6 @@
        m_pBlBtns[i] = new CBlButton();
    }
    for (int i = 0; i < EDIT_MAX; i++) {
        m_pRegexEdit[i] = new CRegexEdit();
    }
    for (int i = 0; i < LABEL_MAX; i++) {
        m_pBlLabels[i] = new CBLLabel();
    }
@@ -73,10 +70,6 @@
{
    for (int i = 0; i < BTN_MAX; i++) {
        delete m_pBlBtns[i];
    }
    for (int i = 0; i < EDIT_MAX; i++) {
        delete m_pRegexEdit[i];
    }
    for (int i = 0; i < LABEL_MAX; i++) {
@@ -179,24 +172,6 @@
    SetLabelColorBasedOnState(*m_pBlLabels[LABEL_ERR], m_bErr, COLOR_RED, COLOR_GREEN_OFF);
}
void CAxisSettingsDlg::UpdateRegexEdit(CRegexEdit* pRegexEdit, const ValueRange& range, const CString& title)
{
    auto formatDouble = [](double value) -> CString {
        CString str;
        str.Format(_T("%.3f"), value);
        return str;
    };
    pRegexEdit->SetWindowText(formatDouble(range.currentValue));
    pRegexEdit->SetRegexType(RegexType::Decimal);
    pRegexEdit->SetValueRange(range.minValue, range.maxValue);
    pRegexEdit->SetInvalidInputCallback([title, range]() {
        CString strError;
        strError.Format(_T("%s的值必须在 %.3f å’Œ %.3f ä¹‹é—´ï¼"), title, range.minValue, range.maxValue);
        AfxMessageBox(strError);
    });
}
void CAxisSettingsDlg::UpdatePageButtonStates()
{
    for (int i = 0; i < AXIS_PAGE_SIZE; ++i) {
@@ -271,11 +246,11 @@
    m_staticAxisDescription.SetWindowText(CString(axisDetails.description.c_str()));    // è½´æè¿°
    m_staticStartAddress.SetWindowText(CString(axisDetails.startAddress.c_str()));        // èµ·å§‹åœ°å€
    UpdateRegexEdit(m_pRegexEdit[EDIT_MICROMENTUM], axisDetails.jogDistance, _T("微动量"));
    UpdateRegexEdit(m_pRegexEdit[EDIT_MANUAL_SPEED], axisDetails.manualSpeed, _T("手动速度"));
    UpdateRegexEdit(m_pRegexEdit[EDIT_AUTO_SPEED], axisDetails.autoSpeed, _T("自动速度"));
    UpdateRegexEdit(m_pRegexEdit[EDIT_ACCE_TIME], axisDetails.accelerationTime, _T("加速时间"));
    UpdateRegexEdit(m_pRegexEdit[EDIT_DECE_TIME], axisDetails.decelerationTime, _T("减速时间"));
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_MANUAL_SPEED)->SetWindowText(formatDouble(axisDetails.manualSpeed.currentValue));
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_AUTO_SPEED)->SetWindowText(formatDouble(axisDetails.autoSpeed.currentValue));
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_ACCE_TIME)->SetWindowText(formatDouble(axisDetails.accelerationTime.currentValue));
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_DECE_TIME)->SetWindowText(formatDouble(axisDetails.decelerationTime.currentValue));
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_MICROMENTUM)->SetWindowText(formatDouble(axisDetails.jogDistance.currentValue));
}
void CAxisSettingsDlg::RefreshPositionDetails(int nAxisId, int pageNumber)
@@ -309,13 +284,16 @@
            CString value;
            value.Format(_T("%.3f"), position.range.currentValue);
            if (pPositionCtrl) {
                pPositionCtrl->SetWindowText(value);
                pPositionCtrl->EnableWindow(position.isEnable);
                if (position.isEnable) {
                    CString strError;
                    strError.Format(_T("定位点%d"), i + 1);
                    UpdateRegexEdit((CRegexEdit*)pPositionCtrl, position.range, strError);
                    if (!IsFloatInRange((LPTSTR)(LPCTSTR)value, position.range.minValue, position.range.maxValue)) {
                        CString strError;
                        strError.Format(_T("定位点%d值必须在 %.3f å’Œ %.3f ä¹‹é—´ï¼"), i + 1, position.range.minValue, position.range.maxValue);
                        ShowTipText(strError, 5);
                    }
                    else {
                        pPositionCtrl->SetWindowText(value);
                    }
                }
            }
        }
@@ -364,8 +342,8 @@
    // åˆ¤æ–­è¾“入的值是否在合法范围内
    if (enteredValue < minValue || enteredValue > maxValue) {
        CString strError;
        strError.Format(_T("定位点的值必须在 %f å’Œ %f ä¹‹é—´ï¼"), minValue, maxValue);
        pDescriptionCtrl->SetWindowText(strError);
        strError.Format(_T("定位点%d的值必须在 %f å’Œ %f ä¹‹é—´ï¼"), currentIndex + 1, minValue, maxValue);
        ShowTipText(strError, 5);
    }
    else {
        position.range.currentValue = enteredValue;
@@ -403,19 +381,19 @@
    // èŽ·å–ç•Œé¢ä¸Šçš„ä¿®æ”¹å‚æ•°
    CString text;
    m_pRegexEdit[EDIT_MANUAL_SPEED]->GetWindowText(text);
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_MANUAL_SPEED)->GetWindowText(text);
    axisData.manualSpeed.currentValue = _ttof(text);
    m_pRegexEdit[EDIT_AUTO_SPEED]->GetWindowText(text);
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_AUTO_SPEED)->GetWindowText(text);
    axisData.autoSpeed.currentValue = _ttof(text);
    m_pRegexEdit[EDIT_ACCE_TIME]->GetWindowText(text);
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_ACCE_TIME)->GetWindowText(text);
    axisData.accelerationTime.currentValue = _ttof(text);
    m_pRegexEdit[EDIT_DECE_TIME]->GetWindowText(text);
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_DECE_TIME)->GetWindowText(text);
    axisData.decelerationTime.currentValue = _ttof(text);
    m_pRegexEdit[EDIT_MICROMENTUM]->GetWindowText(text);
    GetDlgItem(IDC_EDIT_AXIS_MODITFY_MICROMENTUM)->GetWindowText(text);
    axisData.jogDistance.currentValue = _ttof(text);
    // æ›´æ–°å®šä½ç‚¹æ•°æ®
@@ -774,11 +752,15 @@
    ON_BN_CLICKED(IDC_BUTTON_AXIS_UPDATE_UI, &CAxisSettingsDlg::OnBnClickedButtonAxisUpdateUi)
    ON_BN_CLICKED(IDC_BUTTON_AXIS_DETAIL_SETTINGS, &CAxisSettingsDlg::OnBnClickedButtonAxisDetailSettings)
    ON_MESSAGE(ID_MSG_UPDATA_DATA_TO_UI, &CAxisSettingsDlg::OnUpdateDataToUI)
    ON_EN_KILLFOCUS(IDC_EDIT_AXIS_MODITFY_MANUAL_SPEED, &CAxisSettingsDlg::OnKillfocusEditAxisModitfyManualSpeed)
    ON_EN_KILLFOCUS(IDC_EDIT_AXIS_MODITFY_AUTO_SPEED, &CAxisSettingsDlg::OnKillfocusEditAxisModitfyAutoSpeed)
    ON_EN_KILLFOCUS(IDC_EDIT_AXIS_MODITFY_DECE_TIME, &CAxisSettingsDlg::OnKillfocusEditAxisModitfyDeceTime)
    ON_EN_KILLFOCUS(IDC_EDIT_AXIS_MODITFY_ACCE_TIME, &CAxisSettingsDlg::OnKillfocusEditAxisModitfyAcceTime)
    ON_EN_KILLFOCUS(IDC_EDIT_AXIS_MODITFY_MICROMENTUM, &CAxisSettingsDlg::OnEnKillfocusEditAxisModitfyMicromentum)
    ON_WM_SIZE()
    ON_WM_TIMER()
    ON_WM_CLOSE()
    ON_WM_CTLCOLOR()
    ON_EN_KILLFOCUS(IDC_EDIT_AXIS_MODITFY_MICROMENTUM, &CAxisSettingsDlg::OnEnKillfocusEditAxisModitfyMicromentum)
END_MESSAGE_MAP()
@@ -826,18 +808,6 @@
        AdjustLabelFont(*pLabel);
    }
    // åˆå§‹åŒ–编辑框
    m_pRegexEdit[EDIT_MANUAL_SPEED]->SubclassDlgItem(IDC_EDIT_AXIS_MODITFY_MANUAL_SPEED, this);
    m_pRegexEdit[EDIT_AUTO_SPEED]->SubclassDlgItem(IDC_EDIT_AXIS_MODITFY_AUTO_SPEED, this);
    m_pRegexEdit[EDIT_ACCE_TIME]->SubclassDlgItem(IDC_EDIT_AXIS_MODITFY_ACCE_TIME, this);
    m_pRegexEdit[EDIT_DECE_TIME]->SubclassDlgItem(IDC_EDIT_AXIS_MODITFY_DECE_TIME, this);
    m_pRegexEdit[EDIT_MICROMENTUM]->SubclassDlgItem(IDC_EDIT_AXIS_MODITFY_MICROMENTUM, this);
    m_pRegexEdit[EDIT_ANCHOR_POINT1]->SubclassDlgItem(IDC_EDIT_AXIS_ANCHOR_POINT1, this);
    m_pRegexEdit[EDIT_ANCHOR_POINT2]->SubclassDlgItem(IDC_EDIT_AXIS_ANCHOR_POINT2, this);
    m_pRegexEdit[EDIT_ANCHOR_POINT3]->SubclassDlgItem(IDC_EDIT_AXIS_ANCHOR_POINT3, this);
    m_pRegexEdit[EDIT_ANCHOR_POINT4]->SubclassDlgItem(IDC_EDIT_AXIS_ANCHOR_POINT4, this);
    m_pRegexEdit[EDIT_ANCHOR_POINT5]->SubclassDlgItem(IDC_EDIT_AXIS_ANCHOR_POINT5, this);
    // æŒ‰é’®åˆå§‹åŒ–
    m_pBlBtns[BTN_PAGE1]->SubclassDlgItem(IDC_BUTTON_AXIS_ANCHOR_POINT_GROUP1, this);
@@ -1385,6 +1355,110 @@
    return 0;
}
void CAxisSettingsDlg::OnKillfocusEditAxisModitfyManualSpeed()
{
    // TODO: åœ¨æ­¤æ·»åŠ æŽ§ä»¶é€šçŸ¥å¤„ç†ç¨‹åºä»£ç 
    int nAxisId = GetCurrentSelectedAxisID();
    if (nAxisId == -1) {
        AfxMessageBox(_T("请选择一个有效的轴编号!"));
        return;
    }
    auto axisDetails = m_pAxisManager->GetAxis(nAxisId);
    auto dMinValue = axisDetails.manualSpeed.minValue;
    auto dMaxValue = axisDetails.manualSpeed.maxValue;
    CString strText;
    GetDlgItemText(IDC_EDIT_AXIS_MODITFY_MANUAL_SPEED, strText);
    if (!IsFloatInRange((LPTSTR)(LPCTSTR)strText, dMinValue, dMaxValue)) {
        CString strError;
        strError.Format(_T("手动速度值必须在 %.3f å’Œ %.3f ä¹‹é—´ï¼"), dMinValue, dMaxValue);
        ShowTipText(strError, 5);
    }
}
void CAxisSettingsDlg::OnKillfocusEditAxisModitfyAutoSpeed()
{
    // TODO: åœ¨æ­¤æ·»åŠ æŽ§ä»¶é€šçŸ¥å¤„ç†ç¨‹åºä»£ç 
    int nAxisId = GetCurrentSelectedAxisID();
    if (nAxisId == -1) {
        AfxMessageBox(_T("请选择一个有效的轴编号!"));
        return;
    }
    auto axisDetails = m_pAxisManager->GetAxis(nAxisId);
    auto dMinValue = axisDetails.autoSpeed.minValue;
    auto dMaxValue = axisDetails.autoSpeed.maxValue;
    CString strText;
    GetDlgItemText(IDC_EDIT_AXIS_MODITFY_AUTO_SPEED, strText);
    if (!IsFloatInRange((LPTSTR)(LPCTSTR)strText, dMinValue, dMaxValue)) {
        CString strError;
        strError.Format(_T("自动速度值必须在 %.3f å’Œ %.3f ä¹‹é—´ï¼"), dMinValue, dMaxValue);
        ShowTipText(strError, 5);
    }
}
void CAxisSettingsDlg::OnKillfocusEditAxisModitfyAcceTime()
{
    // TODO: åœ¨æ­¤æ·»åŠ æŽ§ä»¶é€šçŸ¥å¤„ç†ç¨‹åºä»£ç 
    int nAxisId = GetCurrentSelectedAxisID();
    if (nAxisId == -1) {
        AfxMessageBox(_T("请选择一个有效的轴编号!"));
        return;
    }
    auto axisDetails = m_pAxisManager->GetAxis(nAxisId);
    auto dMinValue = axisDetails.accelerationTime.minValue;
    auto dMaxValue = axisDetails.accelerationTime.maxValue;
    CString strText;
    GetDlgItemText(IDC_EDIT_AXIS_MODITFY_ACCE_TIME, strText);
    if (!IsFloatInRange((LPTSTR)(LPCTSTR)strText, dMinValue, dMaxValue)) {
        CString strError;
        strError.Format(_T("加速时间值必须在 %.3f å’Œ %.3f ä¹‹é—´ï¼"), dMinValue, dMaxValue);
        ShowTipText(strError, 5);
    }
}
void CAxisSettingsDlg::OnKillfocusEditAxisModitfyDeceTime()
{
    // TODO: åœ¨æ­¤æ·»åŠ æŽ§ä»¶é€šçŸ¥å¤„ç†ç¨‹åºä»£ç 
    int nAxisId = GetCurrentSelectedAxisID();
    if (nAxisId == -1) {
        AfxMessageBox(_T("请选择一个有效的轴编号!"));
        return;
    }
    auto axisDetails = m_pAxisManager->GetAxis(nAxisId);
    auto dMinValue = axisDetails.decelerationTime.minValue;
    auto dMaxValue = axisDetails.decelerationTime.maxValue;
    CString strText;
    GetDlgItemText(IDC_EDIT_AXIS_MODITFY_DECE_TIME, strText);
    if (!IsFloatInRange((LPTSTR)(LPCTSTR)strText, dMinValue, dMaxValue)) {
        CString strError;
        strError.Format(_T("减速时间值必须在 %.3f å’Œ %.3f ä¹‹é—´ï¼"), dMinValue, dMaxValue);
        ShowTipText(strError, 5);
    }
}
void CAxisSettingsDlg::OnEnKillfocusEditAxisModitfyMicromentum()
{
    int nAxisId = GetCurrentSelectedAxisID();
    if (nAxisId == -1) {
        AfxMessageBox(_T("请选择一个有效的轴编号!"));
        return;
    }
    auto axisDetails = m_pAxisManager->GetAxis(nAxisId);
    auto dMinValue = axisDetails.jogDistance.minValue;
    auto dMaxValue = axisDetails.jogDistance.maxValue;
    CString strText;
    GetDlgItemText(IDC_EDIT_AXIS_MODITFY_MICROMENTUM, strText);
    if (!IsFloatInRange((LPTSTR)(LPCTSTR)strText, dMinValue, dMaxValue)) {
        CString strError;
        strError.Format(_T("微动量值必须在 %.3f å’Œ %.3f ä¹‹é—´ï¼"), dMinValue, dMaxValue);
        ShowTipText(strError, 5);
    }
}
void CAxisSettingsDlg::OnTimer(UINT_PTR nIDEvent)
{
    if (TIMER_READ_PLC_DATA == nIDEvent) {
@@ -1455,12 +1529,19 @@
    GetDlgItem(IDC_LABEL_TIP)->ShowWindow(SW_HIDE);
}
void CAxisSettingsDlg::OnEnKillfocusEditAxisModitfyMicromentum()
bool CAxisSettingsDlg::IsFloatInRange(const std::string& strInput, double fLowerBound, double fUpperBound)
{
    CString strText;
    GetDlgItemText(IDC_EDIT_AXIS_MODITFY_MICROMENTUM, strText);
    double value = atof(strText);
    if (value < 0.0 || value > 0.1) {
        ShowTipText("微动量值必须在0.0 ~ 0.1之间", 5);
    // æ˜¯å¦ä¸ºåˆæ³•浮点数
    std::regex floatRegex(R"([-+]?\d*\.?\d+([eE][-+]?\d+)?)");
    if (!std::regex_match(strInput, floatRegex)) {
        return false;
    }
    try {
        double value = std::stod(strInput);
        return value >= fLowerBound && value <= fUpperBound;
    }
    catch (const std::exception&) {
        return false;
    }
}
SourceCode/Bond/BoounionPLC/AxisSettingsDlg.h
@@ -1,7 +1,6 @@
#pragma once
#include "BlButton.h"
#include "BLLabel.h"
#include "RegexEdit.h"
#include "CBaseDlg.h"
#include "PLC.h"
#include "AxisManager.h"
@@ -17,19 +16,6 @@
#define LABEL_READY        3
#define LABEL_BUSY        4
#define LABEL_ERR        5
// RegexEdit控件
#define EDIT_MAX            10
#define EDIT_MANUAL_SPEED    0
#define EDIT_AUTO_SPEED        1
#define EDIT_ACCE_TIME        2
#define EDIT_DECE_TIME        3
#define EDIT_MICROMENTUM    4
#define EDIT_ANCHOR_POINT1    5
#define EDIT_ANCHOR_POINT2    6
#define EDIT_ANCHOR_POINT3    7
#define EDIT_ANCHOR_POINT4    8
#define EDIT_ANCHOR_POINT5    9
// BUTTON控件
#define BTN_MAX            15
@@ -88,7 +74,6 @@
    void SetLabelColor(CBLLabel& label, COLORREF color);
    void SetLabelColorBasedOnState(CBLLabel& label, BOOL bState, COLORREF colorTrue, COLORREF colorFalse);
    void UpdateLabels();
    void UpdateRegexEdit(CRegexEdit* pRegexEdit, const ValueRange& range, const CString& title);
    void UpdatePageButtonStates();
    void HideEditCursor(int nCtrlID);
    int GetCurrentSelectedAxisID();
@@ -105,6 +90,7 @@
    void ReadPLCDataToUI(int nAxisId);
    void ShowTipText(const char* pszText, float sec);
    void HideTip();
    bool IsFloatInRange(const std::string& strInput, double fLowerBound, double fUpperBound);
private:
    CPLC* m_pPLC;
@@ -122,7 +108,6 @@
    // æŽ§ä»¶
    CBlButton* m_pBlBtns[BTN_MAX];
    CBLLabel* m_pBlLabels[LABEL_MAX];
    CRegexEdit* m_pRegexEdit[EDIT_MAX];
    CComboBox m_comboAxisNO;
    CStatic m_staticAxisNO, m_staticAxisDescription, m_staticStartAddress;
@@ -169,10 +154,13 @@
    afx_msg void OnBnClickedButtonAxisUpdateUi();
    afx_msg void OnBnClickedButtonAxisDetailSettings();
    afx_msg LRESULT OnUpdateDataToUI(WPARAM wParam, LPARAM lParam);
    afx_msg void OnKillfocusEditAxisModitfyManualSpeed();
    afx_msg void OnKillfocusEditAxisModitfyAutoSpeed();
    afx_msg void OnKillfocusEditAxisModitfyDeceTime();
    afx_msg void OnKillfocusEditAxisModitfyAcceTime();
    afx_msg void OnEnKillfocusEditAxisModitfyMicromentum();
    afx_msg void OnTimer(UINT_PTR nIDEvent);
    afx_msg void OnClose();
    DECLARE_MESSAGE_MAP()
public:
    afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
    afx_msg void OnEnKillfocusEditAxisModitfyMicromentum();
    DECLARE_MESSAGE_MAP()
};
SourceCode/Bond/BoounionPLC/BoounionPLC.rc
Binary files differ
SourceCode/Bond/BoounionPLC/BoounionPLC.vcxproj
@@ -193,6 +193,7 @@
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="..\BondEq\HorizontalLine.h" />
    <ClInclude Include="AddPLCInfo.h" />
    <ClInclude Include="Alarm.h" />
    <ClInclude Include="AlarmMonitor.h" />
    <ClInclude Include="AlarmPopupDlg.h" />
@@ -230,7 +231,6 @@
    <ClInclude Include="PagePlcList.h" />
    <ClInclude Include="PLC.h" />
    <ClInclude Include="PlcView.h" />
    <ClInclude Include="RegexEdit.h" />
    <ClInclude Include="Resource.h" />
    <ClInclude Include="stdafx.h" />
    <ClInclude Include="targetver.h" />
@@ -240,6 +240,7 @@
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="..\BondEq\HorizontalLine.cpp" />
    <ClCompile Include="AddPLCInfo.cpp" />
    <ClCompile Include="Alarm.cpp" />
    <ClCompile Include="AlarmMonitor.cpp" />
    <ClCompile Include="AlarmPopupDlg.cpp" />
@@ -280,7 +281,6 @@
    <ClCompile Include="PagePlcList.cpp" />
    <ClCompile Include="PLC.cpp" />
    <ClCompile Include="PlcView.cpp" />
    <ClCompile Include="RegexEdit.cpp" />
    <ClCompile Include="stdafx.cpp">
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
SourceCode/Bond/BoounionPLC/BoounionPLC.vcxproj.filters
@@ -156,7 +156,7 @@
    <ClInclude Include="CBaseDlg.h">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="RegexEdit.h">
    <ClInclude Include="AddPLCInfo.h">
      <Filter>头文件</Filter>
    </ClInclude>
  </ItemGroup>
@@ -281,7 +281,7 @@
    <ClCompile Include="CBaseDlg.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
    <ClCompile Include="RegexEdit.cpp">
    <ClCompile Include="AddPLCInfo.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
  </ItemGroup>
SourceCode/Bond/BoounionPLC/BoounionPLCDlg.cpp
@@ -10,6 +10,7 @@
#include "PlcView.h"
#include "Log.h"
#include "InputDialog.h"
#include "AddPLCInfo.h"
#include "AxisManager.h"
#include "IOManager.h"
@@ -505,24 +506,25 @@
{
    int id = (int)lParam;
    if (id == IDC_BUTTON_ADD) {
        CInputDialog inputDialog(_T("新建设备"), _T("请输入设备名称:"));
        if (inputDialog.DoModal() != IDOK) {
            AfxMessageBox(_T("取消验证!"));
        CAddPLCInfo dlgAddPLCInfo;
        if (dlgAddPLCInfo.DoModal() != IDOK) {
            return 0;
        }
        CString strName;
        strName = inputDialog.GetInputText();
        if (!strName.IsEmpty()) {
            theApp.m_model.addPlc((LPTSTR)(LPCTSTR)strName, "192.168.1.188", 1001);
        CString strPLCName = dlgAddPLCInfo.GetPLCName();
        CString strIP = dlgAddPLCInfo.GetIP();
        CString strPort = dlgAddPLCInfo.GetPort();
        if (!strPLCName.IsEmpty() && !strIP.IsEmpty() && !strPort.IsEmpty()) {
            theApp.m_model.addPlc((LPTSTR)(LPCTSTR)strPLCName, (LPTSTR)(LPCTSTR)strIP, std::stoi((LPTSTR)(LPCTSTR)strPort));
            // æ–°å»ºè½´æ–‡ä»¶
            AxisManager axisManager;
            axisManager.SaveAxis((LPTSTR)(LPCTSTR)strName);
            axisManager.SaveAxis((LPTSTR)(LPCTSTR)strPLCName);
            // æ–°å»ºIO文件
            IOManager ioManager;
            ioManager.SaveToFile((LPTSTR)(LPCTSTR)strName);
            ioManager.SaveToFile((LPTSTR)(LPCTSTR)strPLCName);
        }
    }
    else if (id == IDC_BUTTON_DELETE) {
SourceCode/Bond/BoounionPLC/RegexEdit.cpp
ÎļþÒÑɾ³ý
SourceCode/Bond/BoounionPLC/RegexEdit.h
ÎļþÒÑɾ³ý
SourceCode/Bond/BoounionPLC/Resource.h
Binary files differ
SourceCode/Bond/Servo/AlarmManager.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,289 @@
#include "stdafx.h"
#include "AlarmManager.h"
#include <sstream>
#include <iostream>
#include <stdexcept>
#include <ctime>
// å¸¸é‡
const std::string DATABASE_FILE = R"(AlarmManager.db)";
// é™æ€æˆå‘˜åˆå§‹åŒ–
std::mutex AlarmManager::m_mutex;
// èŽ·å–å•ä¾‹å®žä¾‹
AlarmManager& AlarmManager::getInstance() {
    static AlarmManager instance;
    return instance;
}
// æž„造函数
AlarmManager::AlarmManager() {
    m_pDB = new BL::SQLiteDatabase();
}
// æžæž„函数
AlarmManager::~AlarmManager() {
    if (m_pDB != nullptr) {
        delete m_pDB;
        m_pDB = nullptr;
    }
}
// è®¾ç½®æ•°æ®åº“连接
void AlarmManager::setDatabase(BL::Database* db) {
    std::lock_guard<std::mutex> lock(m_mutex);
    m_pDB = db;
}
// åˆå§‹åŒ–报警表
bool AlarmManager::initAlarmTable() {
    char path[MAX_PATH];
    GetModuleFileName(NULL, path, MAX_PATH);
    std::string exePath(path);
    std::string dbFileDir = exePath.substr(0, exePath.find_last_of("\\/")) + "\\DB";
    if (!CreateDirectory(dbFileDir.c_str(), NULL) && ERROR_ALREADY_EXISTS != GetLastError()) {
        throw std::runtime_error("Failed to create database directory.");
    }
    std::string dbFilePath = dbFileDir + "\\" + DATABASE_FILE;
    if (!m_pDB->connect(dbFilePath, true)) {
        throw std::runtime_error("Failed to connect to database.");
    }
    const std::string createTableQuery = R"(
        CREATE TABLE IF NOT EXISTS alarms (
            id TEXT NOT NULL,
            device_name TEXT NOT NULL,
            description TEXT NOT NULL,
            start_time DATETIME NOT NULL,
            end_time DATETIME NOT NULL
        )
    )";
    return m_pDB->executeQuery(createTableQuery);
}
// é”€æ¯æŠ¥è­¦è¡¨
void AlarmManager::termAlarmTable() {
    if (m_pDB != nullptr) {
        m_pDB->disconnect();
    }
}
// é”€æ¯æŠ¥è­¦è¡¨
bool AlarmManager::destroyAlarmTable() {
    if (!m_pDB) {
        throw std::runtime_error("Database connection is not set.");
    }
    const std::string dropTableQuery = "DROP TABLE IF EXISTS alarms";
    return m_pDB->executeQuery(dropTableQuery);
}
// æ·»åŠ æŠ¥è­¦
bool AlarmManager::addAlarm(const std::string& id, const std::string& deviceName, const std::string& description, const std::string& startTime, const std::string& endTime) {
    if (!m_pDB) {
        throw std::runtime_error("Database connection is not set.");
    }
    std::ostringstream query;
    query << "INSERT INTO alarms (id, device_name, description, start_time, end_time) VALUES ("
        << "'" << id << "', "
        << "'" << deviceName << "', "
        << "'" << description << "', "
        << "'" << startTime << "', "
        << "'" << endTime << "')";
    std::lock_guard<std::mutex> lock(m_mutex);
    return m_pDB->executeQuery(query.str());
}
// æŸ¥è¯¢æ‰€æœ‰æŠ¥è­¦æ•°æ®
std::vector<std::vector<std::string>> AlarmManager::getAllAlarms() {
    if (!m_pDB) {
        throw std::runtime_error("Database connection is not set.");
    }
    const std::string query = "SELECT id, device_name, description, start_time, end_time FROM alarms";
    return m_pDB->fetchResults(query);
}
// æ ¹æ®æŠ¥è­¦ID查询报警
std::vector<std::vector<std::string>> AlarmManager::getAlarmsById(const std::string& id) {
    if (!m_pDB) {
        throw std::runtime_error("Database connection is not set.");
    }
    std::ostringstream query;
    query << "SELECT id, device_name, description, start_time, end_time FROM alarms WHERE id = '" << id << "'";
    return m_pDB->fetchResults(query.str());
}
// æ ¹æ®æè¿°æŸ¥è¯¢æŠ¥è­¦
std::vector<std::vector<std::string>> AlarmManager::getAlarmsByDescription(const std::string& description) {
    if (!m_pDB) {
        throw std::runtime_error("Database connection is not set.");
    }
    std::ostringstream query;
    query << "SELECT id, device_name, description, start_time, end_time FROM alarms WHERE description LIKE '%" << description << "%'";
    return m_pDB->fetchResults(query.str());
}
// æ ¹æ®æ—¶é—´èŒƒå›´æŸ¥è¯¢æŠ¥è­¦
std::vector<std::vector<std::string>> AlarmManager::getAlarmsByTimeRange(
    const std::string& startTime, const std::string& endTime) {
    if (!m_pDB) {
        throw std::runtime_error("Database connection is not set.");
    }
    std::ostringstream query;
    query << "SELECT id, device_name, description, start_time, end_time FROM alarms WHERE 1=1";
    if (!startTime.empty()) {
        query << " AND start_time >= '" << startTime << "'";
    }
    if (!endTime.empty()) {
        query << " AND end_time <= '" << endTime << "'";
    }
    return m_pDB->fetchResults(query.str());
}
// æ ¹æ®ID、开始时间和结束时间查询报警
std::vector<std::vector<std::string>> AlarmManager::getAlarmsByIdAndTimeRange(
    const std::string& id, const std::string& startTime, const std::string& endTime) {
    if (!m_pDB) {
        throw std::runtime_error("Database connection is not set.");
    }
    std::ostringstream query;
    query << "SELECT id, device_name, description, start_time, end_time FROM alarms WHERE id = '" << id << "'";
    if (!startTime.empty()) {
        query << " AND start_time >= '" << startTime << "'";
    }
    if (!endTime.empty()) {
        query << " AND end_time <= '" << endTime << "'";
    }
    return m_pDB->fetchResults(query.str());
}
// åˆ†é¡µæŸ¥è¯¢æŠ¥è­¦æ•°æ®
std::vector<std::vector<std::string>> AlarmManager::getAlarms(int startPosition, int count) {
    if (!m_pDB) {
        throw std::runtime_error("Database connection is not set.");
    }
    std::ostringstream query;
    query << "SELECT id, device_name, description, start_time, end_time FROM alarms LIMIT " << count << " OFFSET " << startPosition;
    return m_pDB->fetchResults(query.str());
}
// ç­›é€‰æŠ¥è­¦æ•°æ®
std::vector<std::vector<std::string>> AlarmManager::getFilteredAlarms(
    const std::string& id,
    const std::string& deviceName,
    const std::string& description,
    const std::string& startTime,
    const std::string& endTime,
    int pageNumber,
    int pageSize) {
    if (!m_pDB) {
        throw std::runtime_error("Database connection is not set.");
    }
    std::ostringstream query;
    query << "SELECT id, device_name, description, start_time, end_time FROM alarms WHERE 1=1";
    if (!id.empty()) {
        query << " AND id = '" << id << "'";
    }
    if (!deviceName.empty()) {
        query << " AND device_name LIKE '%" << deviceName << "%'";
    }
    if (!description.empty()) {
        query << " AND description LIKE '%" << description << "%'";
    }
    if (!startTime.empty()) {
        query << " AND start_time >= '" << startTime << "'";
    }
    if (!endTime.empty()) {
        query << " AND end_time <= '" << endTime << "'";
    }
    int offset = (pageNumber - 1) * pageSize;
    query << " ORDER BY start_time DESC LIMIT " << pageSize << " OFFSET " << offset;
    return m_pDB->fetchResults(query.str());
}
// èŽ·å–ç¬¦åˆæ¡ä»¶çš„æŠ¥è­¦æ€»æ•°
int AlarmManager::getTotalAlarmCount(
    const std::string& id,
    const std::string& deviceName,
    const std::string& description,
    const std::string& startTime,
    const std::string& endTime) {
    if (!m_pDB) {
        throw std::runtime_error("Database connection is not set.");
    }
    std::ostringstream query;
    query << "SELECT COUNT(*) FROM alarms WHERE 1=1";
    if (!id.empty()) {
        query << " AND id = '" << id << "'";
    }
    if (!deviceName.empty()) {
        query << " AND device_name LIKE '%" << deviceName << "%'";
    }
    if (!description.empty()) {
        query << " AND description LIKE '%" << description << "%'";
    }
    if (!startTime.empty()) {
        query << " AND start_time >= '" << startTime << "'";
    }
    if (!endTime.empty()) {
        query << " AND end_time <= '" << endTime << "'";
    }
    auto results = m_pDB->fetchResults(query.str());
    return (!results.empty() && !results[0].empty()) ? std::stoi(results[0][0]) : 0;
}
// æ›´æ–°æŠ¥è­¦çš„结束时间
bool AlarmManager::updateAlarmEndTime(const std::string& id, const std::string& deviceName, const std::string& description, const std::string& startTime, const std::string& newEndTime) {
    if (!m_pDB) {
        throw std::runtime_error("Database connection is not set.");
    }
    std::ostringstream query;
    query << "UPDATE alarms SET end_time = '" << newEndTime << "'"
        << " WHERE id = '" << id << "'"
        << " AND device_name = '" << deviceName << "'"
        << " AND description = '" << description << "'"
        << " AND start_time = '" << startTime << "'";
    return m_pDB->executeQuery(query.str());
}
// æ¸…理旧报警数据
void AlarmManager::cleanOldAlarms(int daysToKeep, const std::string& deviceName) {
    if (!m_pDB) {
        throw std::runtime_error("Database connection is not set.");
    }
    std::ostringstream query;
    query << "DELETE FROM alarms WHERE end_time < datetime('now', '-" << daysToKeep << " days')";
    if (!deviceName.empty()) {
        query << " AND device_name = '" << deviceName << "'";
    }
    m_pDB->executeQuery(query.str());
}
SourceCode/Bond/Servo/AlarmManager.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,163 @@
#ifndef ALARM_MANAGER_H
#define ALARM_MANAGER_H
#include <string>
#include <vector>
#include <mutex>
#include "Database.h"
class AlarmManager {
public:
    /**
     * èŽ·å–å•ä¾‹å®žä¾‹
     * @return AlarmManager实例的引用
     */
    static AlarmManager& getInstance();
    /**
     * è®¾ç½®æ•°æ®åº“连接
     * @param db æ•°æ®åº“连接的指针
     */
    void setDatabase(BL::Database* db);
    /**
     * åˆå§‹åŒ–报警表
     * @return æˆåŠŸè¿”å›žtrue,失败返回false
     */
    bool initAlarmTable();
    /**
     * é”€æ¯æŠ¥è­¦è¡¨
     */
    void termAlarmTable();
    /**
     * é”€æ¯æŠ¥è­¦è¡¨
     * @return æˆåŠŸè¿”å›žtrue,失败返回false
     */
    bool destroyAlarmTable();
    /**
     * æ·»åŠ æŠ¥è­¦
     * @param id æŠ¥è­¦ID
     * @param deviceName è®¾å¤‡åç§°
     * @param description æŠ¥è­¦æè¿°
     * @param startTime æŠ¥è­¦å¼€å§‹æ—¶é—´
     * @param endTime æŠ¥è­¦ç»“束时间
     * @return æˆåŠŸè¿”å›žtrue,失败返回false
     */
    bool addAlarm(const std::string& id, const std::string& deviceName, const std::string& description, const std::string& startTime, const std::string& endTime);
    /**
     * æŸ¥è¯¢æ‰€æœ‰æŠ¥è­¦æ•°æ®
     * @return åŒ…含所有报警数据的二维字符串向量
     */
    std::vector<std::vector<std::string>> getAllAlarms();
    /**
     * æ ¹æ®æŠ¥è­¦ID查询报警
     * @param id æŠ¥è­¦ID
     * @return åŒ…含筛选后报警数据的二维字符串向量
     */
    std::vector<std::vector<std::string>> getAlarmsById(const std::string& id);
    /**
     * æ ¹æ®æè¿°æŸ¥è¯¢æŠ¥è­¦
     * @param description æŠ¥è­¦æè¿°çš„筛选条件
     * @return åŒ…含筛选后报警数据的二维字符串向量
     */
    std::vector<std::vector<std::string>> getAlarmsByDescription(const std::string& description);
    /**
     * æ ¹æ®æ—¶é—´èŒƒå›´æŸ¥è¯¢æŠ¥è­¦
     * @param startTime èµ·å§‹æ—¶é—´
     * @param endTime ç»“束时间
     * @return åŒ…含查询结果的二维字符串向量
     */
    std::vector<std::vector<std::string>> getAlarmsByTimeRange(
        const std::string& startTime, const std::string& endTime);
    /**
    * æ ¹æ®ID和时间范围查询报警
     * @param id æŠ¥è­¦ID
     * @param startTime èµ·å§‹æ—¶é—´
     * @param endTime ç»“束时间
     * @return åŒ…含查询结果的二维字符串向量
     */
    std::vector<std::vector<std::string>> getAlarmsByIdAndTimeRange(
        const std::string& id, const std::string& startTime, const std::string& endTime);
    /**
     * èŽ·å–æŠ¥è­¦æ•°æ®
     * @param startPosition èµ·å§‹ä½ç½®
     * @param count èŽ·å–çš„è®°å½•æ•°é‡
     * @return åŒ…含报警数据的二维字符串向量
     */
    std::vector<std::vector<std::string>> getAlarms(int startPosition, int count);
    /**
     * èŽ·å–ç­›é€‰åŽçš„æŠ¥è­¦æ•°æ®
     * @param id æŠ¥è­¦ID的筛选条件
     * @param deviceName è®¾å¤‡åç§°çš„筛选条件
     * @param description æŠ¥è­¦æè¿°çš„筛选条件
     * @param startTime èµ·å§‹æ—¶é—´ç­›é€‰æ¡ä»¶
     * @param endTime ç»“束时间筛选条件
     * @param pageNumber é¡µç 
     * @param pageSize æ¯é¡µçš„记录数
     * @return åŒ…含筛选后报警数据的二维字符串向量
     */
    std::vector<std::vector<std::string>> getFilteredAlarms(
        const std::string& id,
        const std::string& deviceName,
        const std::string& description,
        const std::string& startTime,
        const std::string& endTime,
        int pageNumber,
        int pageSize);
    /**
     * èŽ·å–ç¬¦åˆæ¡ä»¶çš„æŠ¥è­¦æ€»æ•°
     * @param id æŠ¥è­¦ID的筛选条件
     * @param deviceName è®¾å¤‡åç§°çš„筛选条件
     * @param description æŠ¥è­¦æè¿°çš„筛选条件
     * @param startTime èµ·å§‹æ—¶é—´ç­›é€‰æ¡ä»¶
     * @param endTime ç»“束时间筛选条件
     * @return ç¬¦åˆæ¡ä»¶çš„æŠ¥è­¦æ€»æ•°
     */
    int getTotalAlarmCount(
        const std::string& id,
        const std::string& deviceName,
        const std::string& description,
        const std::string& startTime,
        const std::string& endTime);
    /**
     * æ›´æ–°æŠ¥è­¦ç»“束时间
     * @param id æŠ¥è­¦ID
     * @param description æŠ¥è­¦æè¿°
     * @param startTime æŠ¥è­¦å¼€å§‹æ—¶é—´
     * @param newEndTime æ–°çš„æŠ¥è­¦ç»“束时间
     * @return æˆåŠŸè¿”å›žtrue,失败返回false
     */
    bool updateAlarmEndTime(const std::string& id, const std::string& deviceName, const std::string& description, const std::string& startTime, const std::string& newEndTime);
    /**
     * æ¸…理旧报警
     * @param daysToKeep ä¿ç•™çš„天数
     * @param deviceName è®¾å¤‡åç§°
     */
    void cleanOldAlarms(int daysToKeep = 30, const std::string& deviceName = "");
private:
    AlarmManager();
    ~AlarmManager();
    // ç¦æ­¢æ‹·è´å’Œèµ‹å€¼
    AlarmManager(const AlarmManager&) = delete;
    AlarmManager& operator=(const AlarmManager&) = delete;
    BL::Database* m_pDB;
    static std::mutex m_mutex;
};
#endif // ALARM_MANAGER_H
SourceCode/Bond/Servo/Servo.cpp
@@ -6,6 +6,11 @@
#include "Servo.h"
#include "ServoDlg.h"
#include "ServoGraph.h"
#include "AlarmManager.h"
// å£°æ˜Žå…¨å±€å˜é‡ï¼Œç”¨äºŽç®¡ç† GDI+ åˆå§‹åŒ–
ULONG_PTR g_diplusToken;
GdiplusStartupInput g_diplusStartupInput;
#ifdef _DEBUG
#define new DEBUG_NEW
@@ -93,6 +98,25 @@
    HSMS_Initialize();
    // åˆå§‹åŒ– GDI+
    InitGDIPlus();
    // åˆå§‹åŒ–报警管理器
    try {
        if (!AlarmManager::getInstance().initAlarmTable()) {
            AfxMessageBox("初始化报警管理器失败!");
            return FALSE;
        }
    }
    catch (const std::exception& ex) {
        CString errorMsg;
        errorMsg.Format(_T("初始化报警管理器失败:%s"), CString(ex.what()));
        AfxMessageBox(errorMsg, MB_ICONERROR);
        return FALSE;
    }
    CServoDlg dlg;
    m_pMainWnd = &dlg;
    INT_PTR nResponse = dlg.DoModal();
@@ -129,5 +153,25 @@
    HSMS_Term();
    RX_Term();
    // æ¸…理 GDI+
    TermGDIPlus();
    // é”€æ¯æŠ¥è­¦è¡¨
    AlarmManager::getInstance().termAlarmTable();
    return CWinApp::ExitInstance();
}
// åˆå§‹åŒ– GDI+
void CServoApp::InitGDIPlus()
{
    // åˆå§‹åŒ– GDI+ å›¾å½¢åº“
    GdiplusStartup(&g_diplusToken, &g_diplusStartupInput, NULL);
}
// æ¸…理 GDI+
void CServoApp::TermGDIPlus()
{
    // æ¸…理 GDI+ å›¾å½¢åº“
    GdiplusShutdown(g_diplusToken);
}
SourceCode/Bond/Servo/Servo.h
@@ -20,6 +20,8 @@
{
public:
    CServoApp();
    void InitGDIPlus();
    void TermGDIPlus();
public:
SourceCode/Bond/Servo/Servo.vcxproj
@@ -115,6 +115,7 @@
      <Optimization>Disabled</Optimization>
      <PreprocessorDefinitions>_WINDOWS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <SDLCheck>true</SDLCheck>
      <AdditionalIncludeDirectories>.;..;..\DatabaseSDK\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
@@ -168,6 +169,7 @@
      <IntrinsicFunctions>true</IntrinsicFunctions>
      <PreprocessorDefinitions>_WINDOWS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <SDLCheck>true</SDLCheck>
      <AdditionalIncludeDirectories>.;..;..\DatabaseSDK\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
@@ -190,6 +192,7 @@
    <Text Include="ReadMe.txt" />
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="AlarmManager.h" />
    <ClInclude Include="BlButton.h" />
    <ClInclude Include="Common.h" />
    <ClInclude Include="Configuration.h" />
@@ -210,6 +213,7 @@
    <ClInclude Include="TerminalDisplayDlg.h" />
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="AlarmManager.cpp" />
    <ClCompile Include="BlButton.cpp" />
    <ClCompile Include="Configuration.cpp" />
    <ClCompile Include="Context.cpp" />
SourceCode/Bond/Servo/Servo.vcxproj.filters
@@ -70,6 +70,7 @@
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="TerminalDisplayDlg.h">
    <ClInclude Include="AlarmManager.h">
      <Filter>头文件</Filter>
    </ClInclude>
  </ItemGroup>
@@ -117,6 +118,7 @@
      <Filter>源文件</Filter>
    </ClCompile>
    <ClCompile Include="TerminalDisplayDlg.cpp">
    <ClCompile Include="AlarmManager.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
  </ItemGroup>
SourceCode/Bond/Servo/ServoDlg.cpp
@@ -9,12 +9,18 @@
#include "Common.h"
#include "Log.h"
#include "SecsTestDlg.h"
#include "AlarmManager.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
@@ -79,6 +85,7 @@
    m_crBkgnd = APPDLG_BACKGROUND_COLOR;
    m_hbrBkgnd = nullptr;
    m_bShowLogWnd = FALSE;
    m_bIsRobotMoving = FALSE;
    m_pLogDlg = nullptr;
    m_pTerminalDisplayDlg = nullptr;
    m_pObserver = nullptr;
@@ -115,6 +122,7 @@
    ON_COMMAND(ID_MENU_HELP_ABOUT, &CServoDlg::OnMenuHelpAbout)
    ON_WM_INITMENUPOPUP()
    ON_WM_TIMER()
    ON_WM_ERASEBKGND()
END_MESSAGE_MAP()
@@ -193,6 +201,8 @@
    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
@@ -241,10 +251,10 @@
    // 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");
@@ -536,6 +546,106 @@
    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::OnSize(UINT nType, int cx, int cy)
{
    CDialogEx::OnSize(nType, cx, cy);
@@ -615,3 +725,15 @@
    CDialogEx::OnTimer(nIDEvent);
}
BOOL CServoDlg::OnEraseBkgnd(CDC* pDC)
{
    // TODO: åœ¨æ­¤æ·»åŠ æ¶ˆæ¯å¤„ç†ç¨‹åºä»£ç å’Œ/或调用默认值
    if (m_bIsRobotMoving) {
        // ç¦æ­¢åˆ·æ–°èƒŒæ™¯ï¼Œé¿å…é—ªçƒ
        return TRUE;
    }
    return CDialogEx::OnEraseBkgnd(pDC);
}
SourceCode/Bond/Servo/ServoDlg.h
@@ -24,6 +24,8 @@
    void InitRxWindows();
    void Resize();
    void UpdateLogBtn();
    void UpdateRobotPosition(float percentage);
    void RotateRobot(float angleInDegrees);
private:
@@ -41,6 +43,11 @@
    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV æ”¯æŒ
private:
    BOOL m_bIsRobotMoving;
    BOOL m_bShowLogWnd;
    CLogDlg* m_pLogDlg;
// å®žçް
protected:
@@ -79,4 +86,5 @@
    afx_msg void OnUpdateMenuFileExit(CCmdUI* pCmdUI);
    afx_msg void OnMenuHelpAbout();
    afx_msg void OnTimer(UINT_PTR nIDEvent);
    afx_msg BOOL OnEraseBkgnd(CDC* pDC);
};
SourceCode/Bond/Servo/ServoGraph.cpp
@@ -306,29 +306,9 @@
    // ç”»IMAGE
    HDC hDCTemp = ::CreateCompatibleDC(hMemDC);
    for (auto& item : m_images) {
        // è½½å…¥BMP
        if (item.hBitmap == nullptr) {
            item.hBitmap = (HBITMAP)LoadImage(AfxGetInstanceHandle(),
                item.szPath, IMAGE_BITMAP, 0, 0,
                LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE);
            if (item.hBitmap != nullptr) {
                BITMAP bitmap;
                ::GetObject(item.hBitmap, sizeof(BITMAP), &bitmap);
                item.bmWidth = bitmap.bmWidth;
                item.bmHeight = bitmap.bmHeight;
            }
        }
        if (item.hBitmap != nullptr) {
            ::SelectObject(hDCTemp, item.hBitmap);
            ::BitBlt(hMemDC, item.x, item.y, item.bmWidth, item.bmHeight,
                hDCTemp, 0, 0, SRCCOPY);
        }
        DrawImage(hMemDC, item);
    }
    ::DeleteDC(hDCTemp);
    // ç”»èƒŒæ™¯æŒ‡ç¤º
@@ -368,7 +348,7 @@
        }
        // text
        ::DrawText(hMemDC, item.szText, strlen(item.szText),
        ::DrawText(hMemDC, item.szText, static_cast<int>(strlen(item.szText)),
            &rcItem, DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
    }
@@ -627,3 +607,71 @@
        SendMessage(m_hWndTooltip, TTM_ADDTOOL, 0, (LPARAM)(LPTOOLINFO)&tti);
    }
}
void CServoGraph::UpdateImageCoordinates(int id, int newX, int newY)
{
    IMAGE* pImage = GetImage(id);
    if (pImage != nullptr) {
        pImage->x = newX;
        pImage->y = newY;
    }
}
void CServoGraph::UpdateIndicateBoxCoordinates(int id, int newX, int newY)
{
    INDICATEBOX* pIndicateBox = GetIndicateBox(id);
    if (pIndicateBox != nullptr) {
        pIndicateBox->x = newX;
        pIndicateBox->y = newY;
    }
}
void CServoGraph::UpdateImageAngle(int id, float angle)
{
    IMAGE* pImage = GetImage(id);
    if (pImage != nullptr) {
        pImage->angle = angle;
    }
}
void CServoGraph::DrawImage(HDC hMemDC, IMAGE& item)
{
    // è½½å…¥BMP
    if (item.hBitmap == nullptr) {
        item.hBitmap = (HBITMAP)LoadImage(AfxGetInstanceHandle(),
            item.szPath, IMAGE_BITMAP, 0, 0,
            LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE);
        if (item.hBitmap != nullptr) {
            BITMAP bitmap;
            ::GetObject(item.hBitmap, sizeof(BITMAP), &bitmap);
            item.bmWidth = bitmap.bmWidth;
            item.bmHeight = bitmap.bmHeight;
        }
    }
    if (item.hBitmap != nullptr) {
        // ä½¿ç”¨ GDI+ åŠ è½½ä½å›¾ï¼Œå¹¶åˆ›å»ºGDI+ Graphics å¯¹è±¡
        Bitmap bitmap(item.hBitmap, nullptr);
        Graphics graphics(hMemDC);
        // å¦‚果图像需要旋转
        if (item.angle != 0.0f) {
            // è§’度转换为弧度
            float angleInRadians = item.angle;
            // èŽ·å–å›¾åƒä¸­å¿ƒ
            REAL cx = static_cast<REAL>(item.x + item.bmWidth / 2);  // å°†ä¸­å¿ƒX转换为REAL类型
            REAL cy = static_cast<REAL>(item.y + item.bmHeight / 2); // å°†ä¸­å¿ƒY转换为REAL类型
            // åˆ›å»ºæ—‹è½¬çŸ©é˜µ
            Matrix rotateMatrix;
            rotateMatrix.RotateAt(angleInRadians, PointF(cx, cy));
            // åº”用旋转矩阵到图形
            graphics.SetTransform(&rotateMatrix);
        }
        graphics.DrawImage(&bitmap, item.x, item.y);
        graphics.ResetTransform();
    }
}
SourceCode/Bond/Servo/ServoGraph.h
@@ -75,6 +75,7 @@
        HBITMAP hBitmap;
        int bmWidth;
        int bmHeight;
        float angle;
    } IMAGE;
@@ -166,6 +167,12 @@
    BOOL GetIndicateBoxRect(int id, LPRECT lprcBox);
    void SetBoxText(int id, const char* pszText, const char* pszTooltip);
    HWND GetSafeWnd();
    void UpdateImageCoordinates(int id, int newX, int newY);
    void UpdateIndicateBoxCoordinates(int id, int newX, int newY);
    void UpdateImageAngle(int id, float angle);
private:
    void DrawImage(HDC hMemDC, IMAGE& item);
private:
    HWND        m_hWnd;
SourceCode/Bond/Servo/stdafx.h
@@ -34,6 +34,30 @@
#include <afxcontrolbars.h>     // åŠŸèƒ½åŒºå’ŒæŽ§ä»¶æ¡çš„ MFC æ”¯æŒ
// GDI+
#include <gdiplus.h>
using namespace Gdiplus;
// æ•°æ®åº“模块
#include "..\DatabaseSDK\include\Database.h"
#include "..\DatabaseSDK\include\MySQLDatabase.h"
#include "..\DatabaseSDK\include\SQLiteDatabase.h"
#if defined(_WIN64)
#if defined(_DEBUG)
#pragma comment(lib, "..\\DatabaseSDK\\lib\\x64\\Debug\\DatabaseEx.lib")
#else
#pragma comment(lib, "..\\DatabaseSDK\\lib\\x64\\Release\\DatabaseEx.lib")
#endif
#else
#if defined(_DEBUG)
#pragma comment(lib, "..\\DatabaseSDK\\lib\\Win32\\Debug\\DatabaseEx.lib")
#else
#pragma comment(lib, "..\\DatabaseSDK\\lib\\Win32\\Release\\DatabaseEx.lib")
#endif
#endif
#include "..\RxWindows1.0\include\RxWindowsLib.h"
#include "..\HSMSSDK\Include\HSMSSDK.h"
SourceCode/Bond/x64/Debug/Res/Robot001.bmp
SourceCode/Bond/x64/Debug/Res/Servo002.bmp