#include "stdafx.h"
|
#include "RemoteEquipment.h"
|
#include <Ws2tcpip.h>
|
#include <map>
|
#include <vector>
|
#include <string>
|
#include <unordered_map>
|
#include "BEQCommon.h"
|
|
|
/* ³¬Ê±Ê±¼ä */
|
extern int g_nActionTimeout;
|
|
namespace BEQ {
|
|
/* socket »º³åÇø´óС */
|
#define BUFFER_SIZE 1024
|
|
|
CRemoteEquipment::CRemoteEquipment()
|
{
|
m_nPort = 0;
|
m_nLocalPort = 0;
|
m_listener.onConnected = nullptr;
|
m_listener.onConnectFailed = nullptr;
|
m_listener.onDisconnecting = nullptr;
|
m_listener.onDisconnected = nullptr;
|
m_listener.onRead = nullptr;
|
m_listener.onEventUpdate = nullptr;
|
m_hSocket = NULL;
|
m_remoteEqNetState = REMOTE_EQ_NET_STATE::DISCONNECTED;
|
m_bWorking = FALSE;
|
m_hWSAEvent = nullptr;
|
m_hEventClose = nullptr;
|
m_hEventWrite = nullptr;
|
m_hEventActions = nullptr;
|
m_hEventActionsThreadExit = nullptr;
|
m_hEventTimeoutCheckThreadExit = nullptr;
|
m_pCurrentAction = nullptr;
|
m_data.init(1024);
|
::InitializeCriticalSection(&m_cs);
|
}
|
|
CRemoteEquipment::CRemoteEquipment(const char* pszAddr, int port)
|
{
|
m_nPort = 0;
|
m_nLocalPort = 0;
|
m_listener.onConnecting = nullptr;
|
m_listener.onConnected = nullptr;
|
m_listener.onConnectFailed = nullptr;
|
m_listener.onDisconnecting = nullptr;
|
m_listener.onDisconnected = nullptr;
|
m_listener.onRead = nullptr;
|
m_listener.onEventUpdate = nullptr;
|
m_strAddr = pszAddr;
|
m_nPort = port;
|
m_hSocket = NULL;
|
m_remoteEqNetState = REMOTE_EQ_NET_STATE::DISCONNECTED;
|
m_bWorking = FALSE;
|
m_hWSAEvent = nullptr;
|
m_hEventClose = nullptr;
|
m_hEventWrite = nullptr;
|
m_hEventActions = nullptr;
|
m_hEventActionsThreadExit = nullptr;
|
m_hEventTimeoutCheckThreadExit = nullptr;
|
m_pCurrentAction = nullptr;
|
m_data.init(1024);
|
::InitializeCriticalSection(&m_cs);
|
m_ullConnectTick = 0;
|
}
|
|
CRemoteEquipment::~CRemoteEquipment()
|
{
|
close();
|
|
for (auto iter = m_units.begin(); iter != m_units.end(); iter++) {
|
delete iter->second;
|
}
|
m_units.clear();
|
|
::DeleteCriticalSection(&m_cs);
|
}
|
|
void CRemoteEquipment::setRemoteEquipmentListener(RemoteEquipmentListener listener)
|
{
|
m_listener.onConnecting = listener.onConnecting;
|
m_listener.onConnected = listener.onConnected;
|
m_listener.onConnectFailed = listener.onConnectFailed;
|
m_listener.onDisconnecting = listener.onDisconnecting;
|
m_listener.onDisconnected = listener.onDisconnected;
|
m_listener.onRead = listener.onRead;
|
m_listener.onEventUpdate = listener.onEventUpdate;
|
}
|
|
int CRemoteEquipment::getAddr(char* pszBuffer, int nMaxCount)
|
{
|
return strcpy_s(pszBuffer, nMaxCount, m_strAddr.c_str());
|
}
|
|
int CRemoteEquipment::getPort()
|
{
|
return m_nPort;
|
}
|
|
int CRemoteEquipment::getName(char* pszBuffer, int nMaxCount)
|
{
|
if (!m_strName.empty()) {
|
return strcpy_s(pszBuffer, nMaxCount, m_strName.c_str());
|
}
|
else {
|
return sprintf_s(pszBuffer, nMaxCount, "%s:%d", m_strAddr.c_str(), m_nPort);
|
}
|
|
}
|
|
int CRemoteEquipment::getVersion(char* pszBuffer, int nMaxCount)
|
{
|
return strcpy_s(pszBuffer, nMaxCount, m_strVersion.c_str());
|
}
|
|
bool CRemoteEquipment::isConnected()
|
{
|
return m_hSocket != NULL && m_remoteEqNetState == REMOTE_EQ_NET_STATE::CONNECTED;
|
}
|
|
int CRemoteEquipment::connect()
|
{
|
TRACE("%p, m_remoteEqNetState:%d\n", this, m_remoteEqNetState);
|
if (m_remoteEqNetState == REMOTE_EQ_NET_STATE::CONNECTING
|
|| m_remoteEqNetState == REMOTE_EQ_NET_STATE::CONNECTED
|
|| m_remoteEqNetState == REMOTE_EQ_NET_STATE::DISCONNECTING) {
|
return -1;
|
}
|
m_remoteEqNetState = REMOTE_EQ_NET_STATE::CONNECTING;
|
if (m_listener.onConnecting != nullptr) {
|
m_listener.onConnecting(this);
|
}
|
|
|
// ´ýÔÏß³ÌÍËÁËÏÈ
|
m_bWorking = FALSE;
|
WSASetEvent(m_hWSAEvent);
|
if (m_hEventActions != NULL) {
|
SetEvent(m_hEventActions);
|
}
|
if (m_hEventActionsThreadExit != NULL) {
|
::WaitForSingleObject(m_hEventActionsThreadExit, INFINITE);
|
}
|
|
if (m_hEventTimeoutCheckThreadExit != NULL) {
|
::WaitForSingleObject(m_hEventTimeoutCheckThreadExit, INFINITE);
|
}
|
|
|
//×¼±¸·þÎñÆ÷µÄÐÅÏ¢£¬ÕâÀïÐèÒªÖ¸¶¨·þÎñÆ÷µÄµØÖ·
|
sockaddr_in addr;
|
struct in_addr dst;
|
if (InetPton(AF_INET, m_strAddr.c_str(), &dst) != 1) {
|
return -1;
|
}
|
|
addr.sin_family = AF_INET;
|
addr.sin_addr = dst;
|
addr.sin_port = htons(m_nPort); //¸Ä±ä¶Ë¿ÚºÅµÄÊý¾Ý¸ñʽ
|
|
|
// Èç¹ûÔÀ´´ò¿ªÕâÌ×½Ó×ÖÏȹرÕ
|
if (m_hSocket != NULL) {
|
closesocket(m_hSocket);
|
m_hSocket = NULL;
|
}
|
|
|
// ´´½¨ÐµÄÌ×½Ó×Ö
|
if (m_hSocket == NULL) {
|
m_hSocket = socket(AF_INET, SOCK_STREAM, 0);
|
ASSERT(m_hSocket != NULL);
|
initClient();
|
}
|
|
if (m_hEventClose == NULL) {
|
m_hEventClose = ::CreateEvent(NULL, TRUE, FALSE, NULL);
|
}
|
ResetEvent(m_hEventClose);
|
|
if (m_hEventActions == NULL) {
|
m_hEventActions = ::CreateEvent(NULL, TRUE, FALSE, NULL);
|
}
|
ResetEvent(m_hEventActions);
|
|
if (m_hEventActionsThreadExit == NULL) {
|
m_hEventActionsThreadExit = ::CreateEvent(NULL, TRUE, FALSE, NULL);
|
}
|
ResetEvent(m_hEventActionsThreadExit);
|
|
if (m_hEventTimeoutCheckThreadExit == NULL) {
|
m_hEventTimeoutCheckThreadExit = ::CreateEvent(NULL, TRUE, FALSE, NULL);
|
}
|
ResetEvent(m_hEventTimeoutCheckThreadExit);
|
|
|
// Ö÷¶¯Á¬½Ó·þÎñÆ÷£¬¸Ã¹ý³Ì½«µÈ´ýÒ»¶¨Ê±¼ä
|
if (SOCKET_ERROR == ::connect(m_hSocket, (LPSOCKADDR)&addr, sizeof(addr))) {
|
if (WSAGetLastError() != WSAEWOULDBLOCK)
|
return -2;
|
}
|
|
|
return 0;
|
}
|
|
int CRemoteEquipment::close()
|
{
|
m_bWorking = FALSE;
|
WSASetEvent(m_hWSAEvent);
|
if (m_hEventActions != NULL) {
|
SetEvent(m_hEventActions);
|
}
|
|
lock();
|
if (m_hSocket != NULL) {
|
m_remoteEqNetState = REMOTE_EQ_NET_STATE::DISCONNECTING;
|
if (m_listener.onDisconnecting != nullptr) {
|
m_listener.onDisconnecting(this);
|
}
|
|
shutdown(m_hSocket, SD_BOTH);
|
closesocket(m_hSocket);
|
m_hSocket = NULL;
|
unlock();
|
|
if (m_hEventClose != NULL) {
|
::WaitForSingleObject(m_hEventClose, INFINITE);
|
}
|
|
if (m_hEventActionsThreadExit != NULL) {
|
::WaitForSingleObject(m_hEventActionsThreadExit, INFINITE);
|
}
|
|
if (m_hEventTimeoutCheckThreadExit != NULL) {
|
::WaitForSingleObject(m_hEventTimeoutCheckThreadExit, INFINITE);
|
}
|
|
m_remoteEqNetState = REMOTE_EQ_NET_STATE::DISCONNECTED;
|
if (m_listener.onDisconnected != nullptr) {
|
m_listener.onDisconnected(this);
|
}
|
}
|
else {
|
unlock();
|
}
|
|
|
return 0;
|
}
|
|
int CRemoteEquipment::reqGetAction(int type, const char* pszCommand, const char* pszUnitName, const char* pszParams)
|
{
|
std::string strRawText = std::string(pszCommand) + "@EQID=" + m_strName;
|
|
if (pszUnitName) {
|
strRawText += ("/UNIT=" + std::string(pszUnitName));
|
}
|
if (pszParams) {
|
strRawText += pszParams;
|
}
|
strRawText += "#";
|
|
CAction* pAction = new CAction(type);
|
ASSERT(pAction);
|
pAction->setRawString(strRawText.c_str());
|
|
lock();
|
m_actions.push_back(pAction);
|
unlock();
|
|
SetEvent(m_hEventActions);
|
|
return pAction->getId();
|
}
|
|
int CRemoteEquipment::reqGetName()
|
{
|
return reqGetAction(ACTION_GETNAME, CMD_GET_EQID_REQ);
|
}
|
|
int CRemoteEquipment::reqGetVersion()
|
{
|
return reqGetAction(ACTION_GETVERSION, CMD_GET_VERSION_REQ);
|
}
|
|
int CRemoteEquipment::reqGetState(const char* pszUnitName)
|
{
|
return reqGetAction(ACTION_GETDEVICESTATE, CMD_GET_STATE_REQ, pszUnitName);
|
}
|
|
int CRemoteEquipment::reqGetDoorState(const char* pszUnitName)
|
{
|
return reqGetAction(ACTION_GETDOORSTATE, CMD_GET_DOOR_REQ, pszUnitName);
|
}
|
|
int CRemoteEquipment::reqGetAlarmInfo(const char* pszUnitName)
|
{
|
return reqGetAction(ACTION_GETALARMINFO, CMD_GET_ERROR_REQ, pszUnitName);
|
}
|
|
int CRemoteEquipment::reqGetStep(const char* pszUnitName)
|
{
|
return reqGetAction(ACTION_GETSTEP, CMD_GET_STEP_REQ, pszUnitName);
|
}
|
|
int CRemoteEquipment::reqGetData(const char* pszUnitName)
|
{
|
return reqGetAction(ACTION_GETDATA, CMD_GET_DATA_REQ, pszUnitName);
|
}
|
|
int CRemoteEquipment::reqRecipeList(const char* pszUnitName)
|
{
|
return reqGetAction(ACTION_GETRECIPELIST, CMD_GET_RECIPE_LIST_REQ, pszUnitName);
|
}
|
|
int CRemoteEquipment::reqRunRecipe(const char* pszUnitName, int nRecipeId, const char* pszRecipeName)
|
{
|
std::string strParams = "/RECIPEID=" + std::to_string(nRecipeId) + "/RECIPENAME=" + pszRecipeName;
|
return reqGetAction(ACTION_RUNRECIPE, CMD_RUN_RECIPE_REQ, pszUnitName, strParams.c_str());
|
}
|
|
IUnit* CRemoteEquipment::addUnit(const char* pszName, int nDoorCount)
|
{
|
auto iter = m_units.find(pszName);
|
if (iter != m_units.end()) {
|
return (IUnit*)iter->second;
|
}
|
|
CUnit* pUnit = new CUnit(pszName);
|
m_units[pszName] = pUnit;
|
pUnit->setDoorCount(nDoorCount);
|
|
UnitListener listener;
|
listener.onStateChanged = [&](void* pUnit, EQ_STATE nStete) -> void {
|
TRACE("<UnitListener>onStateChanged...\n");
|
};
|
listener.onDoorStateChanged = [&](void* pUnit, int stete) -> void {
|
TRACE("<UnitListener>onDoorStateChanged...\n");
|
};
|
listener.onAlarm = [&](void* pUnit, int code, int level, const char* pszText) -> void {
|
TRACE("<UnitListener>onAlarm...\n");
|
};
|
listener.onRemoveAlarm = [&](void* pUnit, int code, int level, const char* pszText) -> void {
|
TRACE("<UnitListener>onRemoveAlarm...\n");
|
};
|
listener.onStepChanged = [&](void* pUnit, STEP_STATE) -> void {
|
TRACE("<UnitListener>onStepChanged...\n");
|
};
|
listener.onDataChanged = [&](void* pUnit, unsigned long long time) -> void {
|
TRACE("<UnitListener>onDataChanged...\n");
|
};
|
listener.onReqLoad = [&](void* pUnit, int layer) -> void {
|
TRACE("<UnitListener>onReqLoad...\n");
|
};
|
listener.onReqUnload = [&](void* pUnit, int layer) -> void {
|
TRACE("<UnitListener>onReqUnload...\n");
|
};
|
pUnit->setListener(listener);
|
|
return (IUnit*)pUnit;
|
}
|
|
IUnit* CRemoteEquipment::getUnit(const char* pszName)
|
{
|
auto iter = m_units.find(pszName);
|
if (iter != m_units.end()) {
|
return (IUnit*)iter->second;
|
}
|
|
return nullptr;
|
}
|
|
const char** CRemoteEquipment::getAllUnitNames()
|
{
|
const int maxUnits = 128;
|
static const char* unitNames[maxUnits];
|
int index = 0;
|
|
for (const auto& pair : m_units) {
|
if (index >= maxUnits) break;
|
unitNames[index++] = pair.first.c_str();
|
}
|
|
return unitNames;
|
}
|
|
int CRemoteEquipment::getUnitCount() const
|
{
|
return m_units.size();
|
}
|
|
ULONGLONG CRemoteEquipment::getConnectTick()
|
{
|
return m_ullConnectTick;
|
}
|
|
BOOL CRemoteEquipment::initClient()
|
{
|
// Èç¹ûÖ¸¶¨Á˱¾µØ¶Ë¿Ú(port != 0), ÔòÒª°ó¶¨Ö¸¶¨¶Ë¿Ú
|
// °ó¶¨Ò»¸öÌ×½Ó×Öµ½±¾»úµÄµØÖ·
|
ASSERT(m_hSocket);
|
|
// ref https://docs.microsoft.com/en-us/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse
|
int reuse = 1;
|
setsockopt(m_hSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse));
|
|
if (m_nLocalPort != 0) {
|
sockaddr_in addr;
|
addr.sin_family = AF_INET;
|
addr.sin_addr.S_un.S_addr = INADDR_ANY;
|
addr.sin_port = htons(m_nLocalPort);
|
bind(m_hSocket, (LPSOCKADDR)&addr, sizeof(addr));
|
}
|
|
|
// ²ÉÓÃʼþÑ¡ÔñÄ£ÐÍWSAEventSelect
|
m_hWSAEvent = WSACreateEvent();
|
WSAEventSelect(m_hSocket, m_hWSAEvent, FD_CONNECT | FD_READ | FD_CLOSE | FD_WRITE);
|
m_bWorking = TRUE;
|
CWinThread* pThread = AfxBeginThread(&CRemoteEquipment::WorkerThreadFunction, (LPVOID)this,
|
THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
|
if (pThread) {
|
pThread->ResumeThread();
|
}
|
|
pThread = AfxBeginThread(&CRemoteEquipment::TimeoutCheckThreadFunction, (LPVOID)this,
|
THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
|
if (pThread) {
|
pThread->ResumeThread();
|
}
|
|
pThread = AfxBeginThread(&CRemoteEquipment::ActionsThreadFunction, (LPVOID)this,
|
THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
|
if (pThread) {
|
pThread->ResumeThread();
|
}
|
|
return TRUE;
|
}
|
|
UINT CRemoteEquipment::WorkerThreadFunction(LPVOID lpvData)
|
{
|
CRemoteEquipment *pRemoteEquipment = (CRemoteEquipment *)lpvData;
|
return pRemoteEquipment->WorkerThreadFunctionInner();
|
}
|
|
UINT CRemoteEquipment::WorkerThreadFunctionInner()
|
{
|
int nThreadID, ret, index;
|
WSANETWORKEVENTS networkEvents;
|
|
|
Sleep(100); // ±ØÐëµÈ´ý,ʹCreateChann...·µ»Ø
|
nThreadID = 0;
|
char szRecvBuffer[BUFFER_SIZE];
|
|
|
while (m_bWorking) {
|
// ¼ì²âsocketÊÇ·ñÓÐЧ
|
lock();
|
if (m_hSocket == NULL) {
|
unlock();
|
break;
|
}
|
unlock();
|
|
|
// µÈ´ýÍøÂçʼþ
|
ret = WSAWaitForMultipleEvents(1, &m_hWSAEvent, FALSE, 1000, FALSE);
|
if (ret == WSA_WAIT_FAILED || ret == WSA_WAIT_TIMEOUT) {
|
continue;
|
}
|
|
index = ret - WSA_WAIT_EVENT_0;
|
WSAEnumNetworkEvents(m_hSocket, m_hWSAEvent, &networkEvents);
|
|
|
// ÓÐÊý¾Ýµ½´ï
|
if (networkEvents.lNetworkEvents & FD_READ) {
|
int nRet = recv(m_hSocket, (char*)&szRecvBuffer, BUFFER_SIZE, 0);
|
if (nRet != SOCKET_ERROR) {
|
// ½âÊÍÊý¾Ý
|
int nDecodeRet = decode((char*)&szRecvBuffer, nRet);
|
if (m_listener.onRead != nullptr) {
|
m_listener.onRead(this, szRecvBuffer, nRet);
|
}
|
}
|
}
|
|
|
// Á´½Ó¹Ø±Õ
|
if (networkEvents.lNetworkEvents & FD_CLOSE) {
|
TRACE("Á´½Ó¹Ø±Õ<FD_CLOSE>\n");
|
m_remoteEqNetState = REMOTE_EQ_NET_STATE::DISCONNECTED;
|
if (m_listener.onDisconnected != nullptr) {
|
m_listener.onDisconnected(this);
|
}
|
break;
|
}
|
|
|
// Á´½Ó½á¹û
|
if (networkEvents.lNetworkEvents & FD_CONNECT) {
|
TRACE("Á´½Ó½á¹û<FD_CONNECT>\n");
|
m_ullConnectTick = GetTickCount64();
|
ResetEvent(m_hEventClose);
|
|
if (networkEvents.iErrorCode[FD_CONNECT_BIT] == 0) {
|
reqGetName();
|
}
|
else {
|
m_remoteEqNetState = REMOTE_EQ_NET_STATE::DISCONNECTED;
|
if (m_listener.onConnectFailed != nullptr) {
|
m_listener.onConnectFailed(this, networkEvents.iErrorCode[FD_CONNECT_BIT]);
|
}
|
m_bWorking = false;
|
break;
|
}
|
}
|
|
if (networkEvents.lNetworkEvents & FD_WRITE) {
|
if (m_hEventWrite != NULL) {
|
SetEvent(m_hEventWrite);
|
}
|
}
|
}
|
|
|
// ʹm_hEventClose ÊÜÐÅ, Closeº¯Êý·µ»Ø
|
if (m_hEventClose != NULL) {
|
TRACE("m_hEventClose ÊÜÐÅ\n");
|
::SetEvent(m_hEventClose);
|
}
|
|
|
return 0;
|
}
|
|
UINT CRemoteEquipment::ActionsThreadFunction(LPVOID lpvData)
|
{
|
CRemoteEquipment *pRemoteEquipment = (CRemoteEquipment *)lpvData;
|
return pRemoteEquipment->ActionsThreadFunctionInner();
|
}
|
|
UINT CRemoteEquipment::ActionsThreadFunctionInner()
|
{
|
ULONGLONG lastTick = 0;
|
DWORD dwWait = INFINITE;
|
while (m_bWorking) {
|
|
DWORD dwRet = WaitForSingleObject(m_hEventActions, dwWait);
|
ResetEvent(m_hEventActions);
|
if (!m_bWorking) {
|
break;
|
}
|
|
lock();
|
if (m_pCurrentAction == NULL && m_actions.size() > 0) {
|
CAction* pAction = m_actions.front();
|
|
m_pCurrentAction = pAction;
|
m_actions.pop_front();
|
|
// ·¢ËÍÊý¾Ý
|
char* pRawData = NULL;
|
int size, validLen;
|
m_pCurrentAction->getRawData(pRawData, size, validLen);
|
send(m_hSocket, pRawData, validLen, 0);
|
}
|
unlock();
|
}
|
|
|
TRACE("ActionsThreadFunctionInner exit\n");
|
SetEvent(m_hEventActionsThreadExit);
|
|
return 0;
|
}
|
|
UINT CRemoteEquipment::TimeoutCheckThreadFunction(LPVOID lpvData)
|
{
|
CRemoteEquipment *pRemoteEquipment = (CRemoteEquipment *)lpvData;
|
return pRemoteEquipment->TimeoutCheckThreadFunctionInner();
|
}
|
|
UINT CRemoteEquipment::TimeoutCheckThreadFunctionInner()
|
{
|
BOOL bMatchRemoteEq = TRUE;
|
while (m_bWorking) {
|
Sleep(1000);
|
if (!m_bWorking) {
|
break;
|
}
|
|
lock();
|
if (m_pCurrentAction != NULL) {
|
int nTime = m_pCurrentAction->timeIncrease(1000);
|
if (nTime > g_nActionTimeout) {
|
CurrentActionTimeout();
|
if (m_pCurrentAction->getType() == ACTION_GETNAME) {
|
bMatchRemoteEq = FALSE;
|
}
|
|
delete m_pCurrentAction;
|
m_pCurrentAction = NULL;
|
SetEvent(m_hEventActions);
|
|
if (!bMatchRemoteEq) {
|
unlock();
|
break;
|
}
|
}
|
}
|
unlock();
|
}
|
|
|
SetEvent(m_hEventTimeoutCheckThreadExit);
|
if (!bMatchRemoteEq) {
|
this->close();
|
if (m_listener.onConnectFailed != nullptr) {
|
m_listener.onConnectFailed(this, -1);
|
}
|
}
|
TRACE("TimeoutCheckThreadFunctionInner exit\n");
|
return 0;
|
}
|
|
void CRemoteEquipment::CurrentActionTimeout()
|
{
|
TRACE("Packer CurrentActionTimeout %d", g_nActionTimeout);
|
}
|
|
void CRemoteEquipment::splitCString(const CString& strText, TCHAR delimiter, std::function<void(const CString&, int)> callback)
|
{
|
// ͨÓÃ×Ö·û´®ÇиÊý£¬Ö§³Ö»Øµ÷º¯Êý´¦Àíÿ´Î½âÎöºóµÄ½á¹û
|
CString strGet;
|
int index = 0;
|
|
while (AfxExtractSubString(strGet, strText.GetString(), index, delimiter)) {
|
// Èç¹ûÌṩÁ˻ص÷º¯Êý£¬ÔòÖ´Ðлص÷£¬´«µÝµ±Ç°µÄ×Ö·û´®ºÍË÷Òý
|
if (callback) {
|
callback(strGet, index);
|
}
|
++index;
|
}
|
}
|
|
void CRemoteEquipment::notifyEventUpdate(REMOTE_EQ_EVENT eventCode, CUnit* pUnit)
|
{
|
if (m_listener.onEventUpdate != nullptr) {
|
m_listener.onEventUpdate(this, pUnit, eventCode);
|
}
|
}
|
|
void CRemoteEquipment::processDoorState(const CString& strPart, int index, int& doorState)
|
{
|
if (strPart.CompareNoCase(_T("OPEN")) == 0) {
|
doorState |= (0x01 << index);
|
}
|
}
|
|
void CRemoteEquipment::updateDoorState(const CString& strText, int& doorState, CUnit* pUnit)
|
{
|
// ²¶»ñthisÖ¸Õ룬ʹµÃLambda¿ÉÒÔ·ÃÎÊÀàµÄ³ÉÔ±º¯Êý»ò±äÁ¿
|
splitCString(strText, ',', [this, &doorState](const CString& part, int index) {
|
processDoorState(part, index, doorState);
|
});
|
|
pUnit->setDoorState(doorState);
|
}
|
|
void CRemoteEquipment::parseAlarm(const CString& strText, CUnit* pUnit)
|
{
|
int alarmCode = -1;
|
int alarmLevel = -1;
|
CString alarmMessage;
|
|
if (0 == _ttoi(strText))
|
{
|
pUnit->setAlarm(0, 0, "");
|
return;
|
}
|
|
splitCString(strText, ',', [&alarmCode, &alarmLevel, &alarmMessage](const CString& part, int index) {
|
// ¸ù¾Ýµ±Ç°Ë÷Òý´¦Àí²»Í¬µÄ±¨¾¯ÐÅÏ¢
|
switch (index) {
|
case 0: // ±¨¾¯´úÂë
|
alarmCode = _ttoi(part);
|
break;
|
case 1: // ±¨¾¯¼¶±ð
|
alarmLevel = _ttoi(part);
|
break;
|
case 2: // ±¨¾¯ÏûÏ¢
|
alarmMessage = part;
|
break;
|
default:
|
break;
|
}
|
});
|
|
// È·±£½âÎöµ½3¸ö×Ó×Ö·û´®£¬²¢ÉèÖñ¨¾¯ÐÅÏ¢
|
if (alarmCode != -1 && alarmLevel != -1 && !alarmMessage.IsEmpty()) {
|
pUnit->setAlarm(alarmCode, alarmLevel, alarmMessage.GetString());
|
}
|
}
|
|
void CRemoteEquipment::handleState(const std::map<std::string, std::string>& params, CUnit* pUnit)
|
{
|
auto iter = params.find(PARAM_STATE);
|
if (iter != params.end()) {
|
std::string strState(iter->second);
|
pUnit->setStateFromString(strState);
|
notifyEventUpdate(REMOTE_EQ_EVENT::DEVICE_STATUS_CHANGED, pUnit);
|
}
|
}
|
|
void CRemoteEquipment::handleDoorState(const std::map<std::string, std::string>& params, CUnit* pUnit)
|
{
|
auto iter = params.find(PARAM_DOOR);
|
if (iter != params.end()) {
|
CString strText = iter->second.c_str();
|
int doorState = 0;
|
updateDoorState(strText, doorState, pUnit);
|
notifyEventUpdate(REMOTE_EQ_EVENT::DOOR_STATUS_CHANGED, pUnit);
|
}
|
}
|
|
void CRemoteEquipment::handleAlarmInfo(const std::map<std::string, std::string>& params, CUnit* pUnit)
|
{
|
auto iter = params.find(PARAM_CODE);
|
if (iter != params.end()) {
|
CString strText = iter->second.c_str();
|
parseAlarm(strText, pUnit);
|
notifyEventUpdate(REMOTE_EQ_EVENT::ALARM_INFO_CHANGED, pUnit);
|
}
|
}
|
|
void CRemoteEquipment::handleStep(const std::map<std::string, std::string>& params, CUnit* pUnit)
|
{
|
auto materialIter = params.find(PARAM_MATERIAL_ID);
|
auto stepIter = params.find(PARAM_STEP);
|
if (stepIter != params.end()) {
|
auto pvIter = params.find(PARAM_PVTIME);
|
auto svIter = params.find(PARAM_SVTIME);
|
const std::string& strStep = stepIter->second;
|
const std::string& strMaterialId = materialIter != params.end() ? materialIter->second : "";
|
int iSVTime = svIter != params.end() ? _ttoi(svIter->second.c_str()) : 0;
|
int iPVTime = pvIter != params.end() ? _ttoi(pvIter->second.c_str()) : 0;
|
|
handleMachineProcess(strMaterialId, strStep, pUnit, iSVTime, iPVTime);
|
notifyEventUpdate(REMOTE_EQ_EVENT::PRODUCTION_PROCESS_CHANGED, pUnit);
|
}
|
}
|
|
void CRemoteEquipment::handleData(const std::map<std::string, std::string>& params, CUnit* pUnit)
|
{
|
auto retIter = params.find(PARAM_RESULT);
|
auto texIter = params.find(PARAM_TEX);
|
if ((retIter != params.end() && retIter->second.compare("FAIL")) || (texIter != params.end() && texIter->second.compare("NO DATA")))
|
{
|
// »ñÈ¡Êý¾Ýʧ°Ü»òûÓÐÊý¾Ý£¬²»×ö´¦Àí
|
}
|
else {
|
auto preIter = params.find(PARAM_PRE);
|
auto airIter = params.find(PARAM_AIR);
|
auto tmpIter = params.find(PARAM_TMP);
|
auto timeIter = params.find(PARAM_TIME);
|
if (timeIter != params.end() && preIter != params.end() && airIter != params.end() && tmpIter != params.end()) {
|
uint64_t timestamp = pUnit->stringToTimeStamp(timeIter->second);
|
pUnit->setDataTimeAndResetData(timestamp);
|
pUnit->addData("PRE", preIter->second.c_str(), true);
|
pUnit->addData("AIR", airIter->second.c_str(), true);
|
pUnit->addData("TMP", tmpIter->second.c_str(), true);
|
|
notifyEventUpdate(REMOTE_EQ_EVENT::SERSOR_DATA_CHANGED, pUnit);
|
}
|
}
|
}
|
|
void CRemoteEquipment::handleRecipeList(const std::map<std::string, std::string>& params, CUnit* pUnit)
|
{
|
auto retIter = params.find(PARAM_RESULT);
|
auto texIter = params.find(PARAM_TEX);
|
if ((retIter != params.end() && retIter->second.compare("FAIL")) || (texIter != params.end() && texIter->second.compare("NO RECIPE"))) {
|
// »ñÈ¡Å䷽ʧ°Ü»òûÓÐÅä·½£¬²»×ö´¦Àí
|
}
|
else {
|
auto recipeIter = params.find(PARAM_RECIPE_LIST);
|
if (recipeIter != params.end()) {
|
// ½âÎöÅä·½Áбí
|
CString strRecipeList = recipeIter->second.c_str();
|
splitCString(strRecipeList, ',', [pUnit](const CString& part, int index) {
|
static int iRecipeid = -1;
|
if ((index + 1) % 2 == 0) {
|
pUnit->addRecipe(iRecipeid, part, true);
|
}
|
else {
|
iRecipeid = _ttoi(part);
|
}
|
});
|
|
notifyEventUpdate(REMOTE_EQ_EVENT::RECIPE_LIST_CHANGED, pUnit);
|
}
|
}
|
}
|
|
void CRemoteEquipment::handleIdle(CUnit* pUnit)
|
{
|
pUnit->stepIdle();
|
}
|
|
void CRemoteEquipment::handleMaterialReceived(const std::string& strMaterialId, CUnit* pUnit)
|
{
|
pUnit->stepMaterialReceived(strMaterialId.c_str());
|
}
|
|
void CRemoteEquipment::handleMaterialRemoved(const std::string& strMaterialId, CUnit* pUnit)
|
{
|
pUnit->stepMaterialRemoved(strMaterialId.c_str());
|
}
|
|
void CRemoteEquipment::handleProcessingStarted(const std::string& strMaterialId, CUnit* pUnit)
|
{
|
pUnit->stepProcessingStarted(strMaterialId.c_str());
|
}
|
|
void CRemoteEquipment::handleProcessing(const std::string& strMaterialId, CUnit* pUnit, int svTime, int pvTime)
|
{
|
pUnit->stepProcessing(strMaterialId.c_str(), svTime, pvTime);
|
}
|
|
void CRemoteEquipment::handleProcessingCompleted(const std::string& strMaterialId, CUnit* pUnit)
|
{
|
pUnit->stepProcessingCompleted(strMaterialId.c_str());
|
}
|
|
void CRemoteEquipment::handleMachineProcess(const std::string& strMaterialId, const std::string& strStep, CUnit* pUnit, int svTime, int pvTime)
|
{
|
// Ó³Éä²½Öèµ½´¦Àíº¯Êý
|
static const std::unordered_map<std::string, std::function<void(const std::string&, CUnit*, int, int)>> stepHandlers = {
|
{"IDLE", [this](const std::string&, CUnit* pUnit, int, int) { handleIdle(pUnit); }},
|
{"MATERIAL_RECEIVED", [this](const std::string& strMaterialId, CUnit* pUnit, int, int) { handleMaterialReceived(strMaterialId, pUnit); }},
|
{"MATERIAL_REMOVED", [this](const std::string& strMaterialId, CUnit* pUnit, int, int) { handleMaterialRemoved(strMaterialId, pUnit); }},
|
{"PROCESSING_STARTED", [this](const std::string& strMaterialId, CUnit* pUnit, int, int) { handleProcessingStarted(strMaterialId, pUnit); }},
|
{"PROCESSING_COMPLETED", [this](const std::string& strMaterialId, CUnit* pUnit, int, int) { handleProcessingCompleted(strMaterialId, pUnit); }},
|
{"PROCESSING", [this](const std::string& strMaterialId, CUnit* pUnit, int svTime, int pvTime) {
|
handleProcessing(strMaterialId, pUnit, svTime, pvTime);
|
}}
|
};
|
|
// ²éÕÒ´¦Àíº¯Êý²¢Ö´ÐÐ
|
auto handler = stepHandlers.find(strStep);
|
if (handler != stepHandlers.end()) {
|
handler->second(strMaterialId, pUnit, svTime, pvTime); // ´«µÝ svTime ºÍ pvTime
|
}
|
}
|
|
int CRemoteEquipment::decode(char* pszBuffer, int nBufferSize)
|
{
|
std::string txt = std::string(pszBuffer, nBufferSize);
|
TRACE("decode:%s\n", txt.c_str());
|
int nRet = REPLY_NOERROR;
|
int iParam = 0;
|
CString strParam, strCmd, strBody;
|
std::map<std::string, std::string> params;
|
|
|
lock();
|
if (-1 == m_data.append(pszBuffer, nBufferSize)) {
|
nRet = REPLY_MEMROY_ERROR;
|
goto CURACTION;
|
}
|
|
// ÔÚδÕÒµ½@·û֮ǰ£¬ËùÓеÄ×Öĸ±ØÐëÊÇ 'A' ~ 'Z' »ò '_'
|
int nCmdEnd = -1;
|
BOOL bInvalid = false;
|
for (int i = 0; i < m_data.m_nDataLen; i++) {
|
if ((char)'@' == m_data.m_pBuffer[i]) {
|
nCmdEnd = i;
|
break;
|
}
|
|
if (!(((char)'A' <= m_data.m_pBuffer[i] && m_data.m_pBuffer[i] <= (char)'Z')
|
|| (char)'_' == m_data.m_pBuffer[i])) {
|
bInvalid = true;
|
break;
|
}
|
}
|
|
if (bInvalid) {
|
m_data.clear();
|
nRet = REPLY_PACKET_ERROR;
|
goto CURACTION;
|
}
|
|
if (nCmdEnd <= 0) {
|
nRet = REPLY_PACKET_ERROR;
|
goto CURACTION;
|
}
|
|
|
// ²éÕÒÖÕÖ¹·û
|
int nPacketEnd = -1;
|
bInvalid = false;
|
for (int i = nCmdEnd; i < m_data.m_nDataLen; i++) {
|
if ((char)'#' == m_data.m_pBuffer[i]) {
|
nPacketEnd = i;
|
break;
|
}
|
|
/*
|
if (!((char)32 <= m_data.m_pBuffer[i] && m_data.m_pBuffer[i] <= (char)127)) {
|
bInvalid = true;
|
break;
|
}
|
*/
|
}
|
|
if (bInvalid) {
|
m_data.clear();
|
nRet = REPLY_PACKET_ERROR;
|
goto CURACTION;
|
}
|
|
if (nPacketEnd <= nCmdEnd) {
|
nRet = REPLY_PACKET_NOT_END;
|
goto CURACTION;
|
}
|
|
|
// µÃµ½ÃüÁÏûÏ¢Ìå
|
// ÏûÏ¢Ìå·Ö½âΪ²ÎÊýÁбí
|
strCmd = CString(m_data.m_pBuffer, nCmdEnd);
|
strBody = CString(&m_data.m_pBuffer[nCmdEnd + 1], nPacketEnd - nCmdEnd - 1);
|
do {
|
if (!AfxExtractSubString(strParam, (LPCTSTR)strBody, iParam, '/')) break;
|
int n = strParam.Find("=");
|
if (n > 0) {
|
std::string strName = (LPTSTR)(LPCTSTR)strParam.Left(n);
|
std::string strValue = (LPTSTR)(LPCTSTR)strParam.Right(strParam.GetLength() - n - 1);
|
params[strName] = strValue;
|
}
|
iParam++;
|
} while (true);
|
|
|
CURACTION:
|
m_data.clear();
|
|
// »ñÈ¡É豸µ¥ÔªÖ¸Õë
|
CUnit* pUnit = nullptr;
|
auto unitParamIter = params.find(PARAM_UNIT);
|
if (unitParamIter != params.end()) {
|
auto unitMapIter = m_units.find(unitParamIter->second);
|
if (unitMapIter != m_units.end() && unitMapIter->second != nullptr) {
|
pUnit = unitMapIter->second;
|
}
|
}
|
|
if (m_pCurrentAction != NULL) {
|
m_pCurrentAction->setReplyCode(nRet);
|
if (m_pCurrentAction->getType() == ACTION_GETNAME
|
&& strCmd.Compare(CMD_GET_EQID_REP) == 0) {
|
auto iter = params.find(PARAM_EQID);
|
if (iter != params.end()) {
|
m_strName = iter->second;
|
m_remoteEqNetState = REMOTE_EQ_NET_STATE::CONNECTED;
|
if (m_listener.onConnected != nullptr) {
|
m_listener.onConnected(this);
|
}
|
|
// test
|
reqGetVersion();
|
reqGetState("UNITA");
|
reqGetDoorState("UNITA");
|
}
|
}
|
else if (m_pCurrentAction->getType() == ACTION_GETVERSION && strCmd.Compare(CMD_GET_VERSION_REP) == 0) {
|
auto iter = params.find(PARAM_VERSION);
|
if (iter != params.end()) {
|
m_strVersion = iter->second;
|
}
|
}
|
else if (m_pCurrentAction->getType() == ACTION_GETDEVICESTATE && strCmd.Compare(CMD_GET_STATE_REP) == 0 && pUnit != nullptr) {
|
handleState(params, pUnit);
|
}
|
else if (m_pCurrentAction->getType() == ACTION_GETDOORSTATE && strCmd.Compare(CMD_GET_DOOR_REP) == 0 && pUnit != nullptr) {
|
handleDoorState(params, pUnit);
|
}
|
else if (m_pCurrentAction->getType() == ACTION_GETALARMINFO && strCmd.Compare(CMD_GET_ERROR_REP) == 0 && pUnit != nullptr) {
|
handleAlarmInfo(params, pUnit);
|
}
|
else if (m_pCurrentAction->getType() == ACTION_GETSTEP && strCmd.Compare(CMD_GET_STEP_REP) == 0 && pUnit != nullptr) {
|
handleStep(params, pUnit);
|
}
|
else if (m_pCurrentAction->getType() == ACTION_GETDATA && strCmd.Compare(CMD_GET_DATA_REP) == 0 && pUnit != nullptr) {
|
handleData(params, pUnit);
|
}
|
else if (m_pCurrentAction->getType() == ACTION_GETRECIPELIST && strCmd.Compare(CMD_GET_RECIPE_LIST_REP) == 0 && pUnit != nullptr) {
|
handleRecipeList(params, pUnit);
|
}
|
else if (m_pCurrentAction->getType() == ACTION_RUNRECIPE && strCmd.Compare(CMD_RUN_RECIPE_REP) == 0 && pUnit != nullptr) {
|
AfxMessageBox("Åä·½Ö´ÐÐÖÐ... ...");
|
}
|
else {
|
// ÆäËûÃüÁî
|
}
|
|
// °ü³ö´í£¬ÇÒ²»ÐèҪƴÏÂÒ»°ü
|
if (nRet != REPLY_PACKET_NOT_END) {
|
delete m_pCurrentAction;
|
m_pCurrentAction = NULL;
|
SetEvent(m_hEventActions);
|
}
|
}
|
else {
|
if (pUnit != nullptr) {
|
if (strCmd.Compare(AS_MC_STATE_REP) == 0) {
|
// »ñÈ¡»úÆ÷״̬
|
handleState(params, pUnit);
|
}
|
else if (strCmd.Compare(AS_GET_DOOR_REP) == 0) {
|
// »ñÈ¡ÃÅ״̬
|
handleDoorState(params, pUnit);
|
}
|
else if (strCmd.Compare(AS_SEND_ERROR_REP) == 0) {
|
// »ñÈ¡´íÎóÂë
|
handleAlarmInfo(params, pUnit);
|
}
|
else if (strCmd.Compare(AS_REMOVE_ERROR_REP) == 0) {
|
// ½â³ý¸æ¾¯
|
pUnit->setAlarm(0, 0, "");
|
notifyEventUpdate(REMOTE_EQ_EVENT::REMOVE_ALARM_INFO, pUnit);
|
}
|
else if (strCmd.Compare(AS_SEND_STEP_REP) == 0) {
|
// ´¦Àí»úÆ÷ÖÆ³Ì
|
handleStep(params, pUnit);
|
}
|
else if (strCmd.Compare(AS_MC_INFO_REP) == 0) {
|
// »ñÈ¡×îÐÂÊý¾Ý£¬´«¸ÐÆ÷£¨Î¶ȡ¢Ñ¹Á¦µÈ£©
|
handleData(params, pUnit);
|
}
|
else if (strCmd.Compare(AS_SEND_EVENT_REP) == 0) {
|
// ´¦ÀíÉϱ¨Ê¼þ
|
notifyEventUpdate(REMOTE_EQ_EVENT::LOAD_EVENT_CHANGED, pUnit);
|
}
|
}
|
}
|
unlock();
|
|
|
return 0;
|
}
|
}
|