#include "stdafx.h" #include "PLC.h" #include "Log.h" #include "ToolUnits.h" #define ADDR_NIGHT_SHIFT_CAPACTITY 1627 void CALLBACK TimerFileProc(UINT uID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) { CPLC* pPlc = (CPLC*)dwUser; SetEvent(pPlc->m_hTimeEvent); } unsigned __stdcall McMonitorThreadFunction(LPVOID lpParam) { CPLC* pPlc = (CPLC*)lpParam; return pPlc->onMonitor(); } CPLC::CPLC() { m_pChannel = nullptr; m_state = PLCSTATE::READY; m_listener.onStateChanged = nullptr; m_listener.onMonitorData = nullptr; m_listener.onAlarm = nullptr; m_nUnHeartBeat = 0; m_nActionInterval = 500; m_hTimeEvent = nullptr; m_hMcMonitorStop = nullptr; m_hMcMonitorThreadHandle = nullptr; m_mcMonitorThrdaddr = 0; m_nTimerId = 0; m_hTimeEvent = nullptr; m_bMute = false; m_pPlcData = new char[4096]; m_nVelocityRatio = 0; InitializeCriticalSection(&m_criticalSection); } CPLC::CPLC(const char* pszName, const char* pszIp, const unsigned int port) { m_strName = pszName; m_strIp = pszIp; m_nPort = port; m_pChannel = nullptr; m_state = PLCSTATE::READY; m_listener.onStateChanged = nullptr; m_listener.onMonitorData = nullptr; m_listener.onAlarm = nullptr; m_nUnHeartBeat = 0; m_hTimeEvent = nullptr; m_hMcMonitorStop = nullptr; m_hMcMonitorThreadHandle = nullptr; m_mcMonitorThrdaddr = 0; m_nTimerId = 0; m_hTimeEvent = nullptr; m_pPlcData = new char[4096]; m_nVelocityRatio = 0; m_dTactTime = 0.0; m_nDayShiftCapacity = 0; m_nNightShiftCapacity = 0; for (int i = 0; i < 7; i++) { m_bBlBtnsStates[i] = false; } InitializeCriticalSection(&m_criticalSection); } CPLC::~CPLC() { if (m_pPlcData != nullptr) { delete[] m_pPlcData; m_pPlcData = nullptr; } DeleteCriticalSection(&m_criticalSection); } void CPLC::setListener(PLCListener& listener) { m_listener.onStateChanged = listener.onStateChanged; m_listener.onMonitorData = listener.onMonitorData; m_listener.onAlarm = listener.onAlarm; } void CPLC::setWorkDir(const char* pszDir) { m_strWorkDir = pszDir; } std::string& CPLC::getName() { return m_strName; } std::string& CPLC::getIp() { return m_strIp; } unsigned int CPLC::getPort() { return m_nPort; } bool CPLC::isMute() { return m_bMute; } CAlarmMonitor* CPLC::getAlarmMonitor() { return (CAlarmMonitor*)getComponent("¾¯¸æÐÅÏ¢"); } int CPLC::addMonitor(int id, int beginAddr, int endAddr, MC::SOFT_COMPONENT softComponent, char* pszRecvBuffer) { // ¼ì²éÊÇ·ñÓÐÖØ¸´µÄ Lock(); for (auto& m : m_monitors) { if (m.id == id) { Unlock(); return -1; } } MONITOR m; memset(&m, 0, sizeof(MONITOR)); m.id = id; m.beginAddr = beginAddr; m.readLen = (endAddr - beginAddr + 1) * 2; m.softComponent = softComponent; m.szRecvBuffer = pszRecvBuffer; m.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL); m_monitors.push_back(m); Unlock(); return 0; } void CPLC::init() { // mc channel McChannelListener m_mcChannellistener; m_mcChannellistener.funOnConnected = [&](IMcChannel* pChannel, int nErrorCode) -> void { LOGI("Á¬½Ó½á¹û", m_strName.c_str(), nErrorCode); if (nErrorCode == 0) { setState(PLCSTATE::CONNECTED); } else { setState(PLCSTATE::DISCONNECTED); } }; m_mcChannellistener.funOnClose = [&](IMcChannel* pChannel) -> void { setState(PLCSTATE::DISCONNECTED); }; m_mcChannellistener.funOnClosing = [&](IMcChannel* pChannel) -> void { }; m_mcChannellistener.funOnRead = [&](IMcChannel* pChannel, char* pData, unsigned int nDataSize, int nDecodeRet) -> void { CString strText; dataToHexString(pData, nDataSize, strText); if (nDecodeRet != 0) { LOGE("funOnRead[%s], nDecodeRet=%d", m_strName.c_str(), (LPTSTR)(LPCTSTR)strText, nDecodeRet); } m_nUnHeartBeat = 0; }; m_mcChannellistener.funOnWrite = [&](IMcChannel* pChannel) -> void { }; if (0 == MCL_CreateChannel(m_pChannel, m_strName.c_str(), m_strIp.c_str(), m_nPort, 0) && m_pChannel != NULL) { m_pChannel->setChannelListener(&m_mcChannellistener); m_pChannel->setActionInterval(m_nActionInterval); LOGI("ÕýÔÚÁ¬½ÓPLC.", m_strName.c_str()); setState(PLCSTATE::CONNECTING); m_pChannel->connect(); } else if (m_pChannel != NULL) { m_pChannel->setChannelListener(&m_mcChannellistener); m_pChannel->setActionInterval(m_nActionInterval); } addMonitor(MONITOR_ID_ALARM, 10001, 10064, MC::SOFT_COMPONENT::M, &m_pPlcData[600]); // ¾¯¸æ¼à¿Ø CString strAlarmFile; strAlarmFile.Format(_T("%s\\AlarmList.txt"), m_strWorkDir.c_str()); CAlarmMonitor* pAlarmMonitor = new CAlarmMonitor(); pAlarmMonitor->setName("¾¯¸æÐÅÏ¢"); pAlarmMonitor->setDescription("¾¯¸æÐÅÏ¢¼à¿Ø"); pAlarmMonitor->setIndex(0); pAlarmMonitor->readAlarmListFromFile((LPTSTR)(LPCTSTR)strAlarmFile); addComponent(pAlarmMonitor); pAlarmMonitor->init(); // ¶¨Ê±Æ÷ m_hTimeEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL); timeBeginPeriod(1); m_nTimerId = timeSetEvent(200, 1, TimerFileProc, (DWORD_PTR)this, TIME_PERIODIC); // Êý¾Ý¼à¿ØÏß³Ì if (m_hMcMonitorStop != NULL) return; m_hMcMonitorStop = ::CreateEvent(NULL, TRUE, FALSE, NULL); m_hMcMonitorThreadHandle = (HANDLE)_beginthreadex(NULL, 0, ::McMonitorThreadFunction, this, 0, &m_mcMonitorThrdaddr); } void CPLC::term() { timeKillEvent(m_nTimerId); timeEndPeriod(1); // Çå³ýÇ°Ãæ¶Ô¶¨Ê±Æ÷µÄÉèÖà for (auto item : m_components) { delete item; } m_components.clear(); ASSERT(m_hMcMonitorStop); SetEvent(m_hMcMonitorStop); if (m_hMcMonitorThreadHandle != NULL) { WaitForSingleObject(m_hMcMonitorThreadHandle, INFINITE); CloseHandle(m_hMcMonitorThreadHandle); m_hMcMonitorThreadHandle = NULL; } CloseHandle(m_hMcMonitorStop); m_hMcMonitorStop = NULL; for (auto& m : m_monitors) { CloseHandle(m.hEvent); } } bool CPLC::isConnected() { return m_pChannel != nullptr && m_pChannel->isConnected(); } void CPLC::connect() { if (m_pChannel != nullptr && !m_pChannel->isConnected()) { m_pChannel->connect(); } } void CPLC::setState(PLCSTATE state) { m_state = state; if (m_listener.onStateChanged != nullptr) { m_listener.onStateChanged(this, (int)m_state); } } void CPLC::setActionInterval(unsigned int nInterval) { m_nActionInterval = nInterval; } CString& CPLC::dataToHexString(const char* pData, const int size, CString& strOut) { strOut.Empty(); for (int i = 0; i < size; i++) { if (i < size - 1) { strOut.AppendFormat(_T("%02X "), (BYTE)pData[i]); } else { strOut.AppendFormat(_T("%02X"), (BYTE)pData[i]); } } return strOut; } unsigned CPLC::onMonitor() { HANDLE hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL); int nReadLen = 60 * 2; HANDLE hEvents[2] = { m_hMcMonitorStop, m_hTimeEvent }; while (1) { int nRet = WaitForMultipleObjects(2, hEvents, FALSE, INFINITE); ResetEvent(m_hTimeEvent); if (nRet == WAIT_OBJECT_0) { break; } if (/*!m_bRunning || */!isConnected()) { continue; } for (auto& m : m_monitors) { monitorReadData(m); } } TRACE("CPLC::onMonitor Ïß³ÌÍ˳ö\n"); return 0; } void CPLC::monitorReadData(MONITOR& monitor) { BOOL bOutputLog = FALSE; BOOL bReadOk; // ÅúÁ¿¶ÁÊý¾ÝÔÙ½âÊÍ auto funOnReadData = [&](IMcChannel* pChannel, int addr, char* pData, unsigned int nDataSize, int flag) -> void { if (flag == 0) { if (bOutputLog) { CString s; s.Format(_T("CPLC::monitorReadData::funOnReadData %d ["), nDataSize); for (unsigned int i = 0; i < nDataSize; i++) { s.AppendFormat(" %x", (BYTE)pData[i]); } s.Append("]"); LOGD("Received plc data.%s.monitor=%d", m_strName.c_str(), monitor.id, (LPTSTR)(LPCTSTR)s, monitor.id); } } else { LOGE("PLCÅú¶ÁÈ¡Êý¾Ýλ³¬Ê±.monitor=%d, flag=%d", m_strName.c_str(), monitor.id, flag); } if (nDataSize == monitor.readLen && flag == 0) { memcpy(monitor.szRecvBuffer, pData, nDataSize); monitor.readCount++; bReadOk = TRUE; } SetEvent(monitor.hEvent); }; bReadOk = FALSE; m_pChannel->readData(monitor.softComponent, monitor.beginAddr, monitor.readLen, funOnReadData); WaitForSingleObject(monitor.hEvent, INFINITE); ResetEvent(monitor.hEvent); if (bReadOk) { onMonitorData(monitor); } } int CPLC::onMonitorData(MONITOR& monitor) { // ת·¢µ½¾¯¸æÄ£¿é´¦Àí½âÊÍÊý¾Ý if (monitor.id == MONITOR_ID_ALARM) { for (auto c : m_components) { c->onData(monitor.id, monitor.szRecvBuffer, monitor.readLen); } } if (m_listener.onMonitorData) { m_listener.onMonitorData(this, monitor.id); } return 0; } int CPLC::readWord(MC::SOFT_COMPONENT softComponent, unsigned int addr, ONREAD funOnRead) { return m_pChannel->readWord(softComponent, addr, funOnRead); } int CPLC::readData(MC::SOFT_COMPONENT softComponent, unsigned int addr, unsigned int nReadLen, ONREADDATA funOnReadData) { return m_pChannel->readData(softComponent, addr, nReadLen, funOnReadData); } int CPLC::writeBit(MC::SOFT_COMPONENT softComponent, unsigned int addr, BOOL bValue, ONWRITE funOnWrite) { return m_pChannel->writeBit(softComponent, addr, bValue, funOnWrite); } int CPLC::writeWord(MC::SOFT_COMPONENT softComponent, unsigned int addr, int value, ONWRITE funOnWrite) { return m_pChannel->writeWord(softComponent, addr, value, funOnWrite); } int CPLC::writeDWord(MC::SOFT_COMPONENT softComponent, unsigned int addr, int value, ONWRITE funOnWrite) { return m_pChannel->writeDWord(softComponent, addr, value, funOnWrite); } int CPLC::writeData(MC::SOFT_COMPONENT softComponent, unsigned int addr, const char* pszData, unsigned int length, ONWRITE funOnWrite) { return m_pChannel->writeData(softComponent, addr, pszData, length, funOnWrite); } void CPLC::addComponent(CComponent* pComponent) { ASSERT(pComponent); pComponent->setPlc(this); m_components.push_back(pComponent); } CComponent* CPLC::getComponent(const char* pszName) { for (auto c : m_components) { if (c->getName().compare(pszName) == 0) { return c; } } return nullptr; } void CPLC::sendBroadcast(CComponent* pSender, CIntent* pIntent) { for (auto item : m_components) { if (item != pSender) { item->onRecvBroadcast(pSender, pIntent); } } this->onRecvBroadcast(pSender, pIntent); } void CPLC::onRecvBroadcast(CComponent* pSender, CIntent* pIntent) { int code = pIntent->getCode(); if (BC_CODE_ALARM_ON == code) { if (m_listener.onAlarm != nullptr) { m_listener.onAlarm(this, (CAlarm*)pIntent->getContext(), 1); } } else if (BC_CODE_ALARM_OFF == code) { if (m_listener.onAlarm != nullptr) { m_listener.onAlarm(this, (CAlarm*)pIntent->getContext(), 0); } } } void CPLC::readPLCDataRegularly() { if (!isConnected()) return; { auto funOnReadData = [this](IMcChannel* pChannel, int addr, char* pData, unsigned int nDataSize, int flag) -> void { if (nDataSize == 2 && flag == 0) { int nVelocityRatio = CToolUnits::toInt16(&pData[0]); if (nVelocityRatio != m_nVelocityRatio) { m_nVelocityRatio = nVelocityRatio; //notifyInt(RX_CODE_VELOCITY_RATIO, m_nVelocityRatio); } } }; readData(MC::D, 530, 2, funOnReadData); } { auto funOnReadData = [this](IMcChannel* pChannel, int addr, char* pData, unsigned int nDataSize, int flag) -> void { if (nDataSize == 2 && flag == 0) { double dTactTime = (double)CToolUnits::toInt16(&pData[0]); if (dTactTime != m_dTactTime) { m_dTactTime = dTactTime; // notifyDouble(RX_CODE_TACT_TIME, m_dTactTime); } } }; readData(MC::ZR, 1500, 2, funOnReadData); } { auto funOnReadData = [this](IMcChannel* pChannel, int addr, char* pData, unsigned int nDataSize, int flag) -> void { if (nDataSize == (ADDR_NIGHT_SHIFT_CAPACTITY - 1612 + 1) * 2 && flag == 0) { int nDayShiftCapacity = CToolUnits::toInt16(&pData[0]); int nNightShiftCapacity = CToolUnits::toInt16(&pData[(ADDR_NIGHT_SHIFT_CAPACTITY - 1612) * 2]); if (nDayShiftCapacity != m_nDayShiftCapacity) { m_nDayShiftCapacity = nDayShiftCapacity; // notifyInt(RX_CODE_DAY_SHIFT_CAPACTITY, nDayShiftCapacity); } if (nNightShiftCapacity != m_nNightShiftCapacity) { m_nNightShiftCapacity = nNightShiftCapacity; // notifyInt(RX_CODE_NIGHT_SHIFT_CAPACTITY, nNightShiftCapacity); } } }; readData(MC::ZR, 1612, (ADDR_NIGHT_SHIFT_CAPACTITY - 1612 + 1) * 2, funOnReadData); } { int nStartAddress = 1000; int nEndAddress = 1200; int nReadSize = (nEndAddress - nStartAddress + 1) * 2; auto funOnReadData = [this, nStartAddress, nReadSize](IMcChannel* pChannel, int addr, char* pData, unsigned int nDataSize, int flag) -> void { if (nDataSize == nReadSize && flag == 0) { bool bRun = CToolUnits::toInt16(&pData[(1103 - nStartAddress) * 2]) != 0; // Æô¶¯ bool bAuto = CToolUnits::toInt16(&pData[(1100 - nStartAddress) * 2]) != 0; // ×Ô¶¯ bool bPuase = CToolUnits::toInt16(&pData[(1104 - nStartAddress) * 2]) != 0; // ÔÝÍ£ bool bManual = CToolUnits::toInt16(&pData[(1100 - nStartAddress) * 2]) != 0; // ÊÖ¶¯ bool bBeep = CToolUnits::toInt16(&pData[(1003 - nStartAddress) * 2]) != 0; // ¾²Òô bool bResetting = CToolUnits::toInt16(&pData[(1150 - nStartAddress) * 2]) != 0; // ¸´Î» bool bStop = CToolUnits::toInt16(&pData[(1114 - nStartAddress) * 2]) != 0; // Í£Ö¹ if (m_bBlBtnsStates[0] != bRun) { m_bBlBtnsStates[0] = bRun; // notifyInt(RX_CODE_ACTIVATE, bRun); } if (m_bBlBtnsStates[1] != bAuto) { m_bBlBtnsStates[1] = bAuto; // notifyInt(RX_CODE_AUTO, bAuto); } if (m_bBlBtnsStates[2] != bPuase) { m_bBlBtnsStates[2] = bPuase; // notifyInt(RX_CODE_PUASE, bPuase); } if (m_bBlBtnsStates[3] != bManual) { m_bBlBtnsStates[3] = bManual; // notifyInt(RX_CODE_MANUAL, bManual); } if (m_bBlBtnsStates[4] != bBeep) { m_bBlBtnsStates[4] = bBeep; // notifyInt(RX_CODE_BEEP, bBeep); } if (m_bBlBtnsStates[5] != bResetting) { m_bBlBtnsStates[5] = bResetting; // notifyInt(RX_CODE_RESETTING, bResetting); } if (m_bBlBtnsStates[6] != bStop) { m_bBlBtnsStates[6] = bStop; // notifyInt(RX_CODE_STOP, bStop); } } }; readData(MC::M, nStartAddress, nReadSize, funOnReadData); } } int CPLC::getVelocityRatio() { return m_nVelocityRatio; } double CPLC::getTackTime() { return m_dTactTime; } int CPLC::getDayShiftCapacity() { return m_nDayShiftCapacity; } int CPLC::getNightShiftCapacity() { return m_nNightShiftCapacity; }