#include "stdafx.h"
|
#include "PLC.h"
|
#include "Log.h"
|
|
|
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;
|
}
|
|
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_nUnHeartBeat = 0;
|
m_hTimeEvent = nullptr;
|
m_hMcMonitorStop = nullptr;
|
m_hMcMonitorThreadHandle = nullptr;
|
m_mcMonitorThrdaddr = 0;
|
m_nTimerId = 0;
|
m_hTimeEvent = nullptr;
|
}
|
|
CPLC::~CPLC()
|
{
|
}
|
|
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("PLC(1)");
|
}
|
|
void CPLC::init()
|
{
|
// mc channel
|
McChannelListener m_mcChannellistener;
|
m_mcChannellistener.funOnConnected = [&](IMcChannel* pChannel, int nErrorCode) -> void {
|
LOGI("<PLC-%s>Á¬½Ó½á¹û<code= %d>", 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("<PLC-%s>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-%s>ÕýÔÚÁ¬½Ó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);
|
}
|
|
|
// ¾¯¸æ¼à¿Ø
|
CString strAlarmFile;
|
strAlarmFile.Format(_T("%s\\%s\\AlarmList.txt"), m_strWorkDir.c_str(), m_strName.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("<CPLC-%s>Received plc data.%s.monitor=%d", m_strName.c_str(), monitor.id, (LPTSTR)(LPCTSTR)s, monitor.id);
|
}
|
}
|
else {
|
LOGE("<CPLC-%s>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) {
|
ASSERT(m_listener.onMonitorData);
|
m_listener.onMonitorData(this, monitor.id);
|
}
|
}
|
|
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);
|
}
|
}
|
}
|