///////////////////////////////////////////////////////////////////////////////
// ModuleDevice.cpp
#include "TcPch.h"
#pragma hdrstop


#include"public.h"
#include"Fields.h"
#include"Dictionary.h"

#include"map"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
#include "IoDoor.h"
#include"BoatModule.h"
#include"IoSensor.h"
#include"TlvSession.h"
#include "ModuleDevice.h"
#include"Simulator.h"
  
#ifdef USE_UDP_PROTOCOL
#define TCP_UDP_PTR m_spIpUdp
#else
#define TCP_UDP_PTR m_spIpTcp

#endif
#define TEST_LEN  15
DEFINE_THIS_FILE()
void * ioModule;
///////////////////////////////////////////////////////////////////////////////
// CModuleDevice
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
// Collection of interfaces implemented by module CModuleDevice
BEGIN_INTERFACE_MAP(CModuleDevice)
	INTERFACE_ENTRY_ITCOMOBJECT()
	INTERFACE_ENTRY(IID_ITcADI, ITcADI)
	INTERFACE_ENTRY(IID_ITcWatchSource, ITcWatchSource)
///<AutoGeneratedContent id="InterfaceMap">
	INTERFACE_ENTRY(IID_ITcCyclic, ITcCyclic)
///</AutoGeneratedContent>
END_INTERFACE_MAP()


IMPLEMENT_ITCOMOBJECT(CModuleDevice)
IMPLEMENT_ITCOMOBJECT_SETSTATE_LOCKOP2(CModuleDevice)
IMPLEMENT_ITCADI(CModuleDevice)
IMPLEMENT_ITCWATCHSOURCE(CModuleDevice)


///////////////////////////////////////////////////////////////////////////////
// Set parameters of CModuleDevice 
BEGIN_SETOBJPARA_MAP(CModuleDevice)
	SETOBJPARA_DATAAREA_MAP()
///<AutoGeneratedContent id="SetObjectParameterMap">
	SETOBJPARA_VALUE(PID_TcTraceLevel, m_TraceLevelMax)
	SETOBJPARA_VALUE(PID_ModuleDeviceParameter, m_Parameter)
	SETOBJPARA_VALUE(PID_ModuleDeviceLoggerPort, m_LoggerPort)
	SETOBJPARA_ITFPTR(PID_Ctx_TaskOid, m_spCyclicCaller)
	SETOBJPARA_ITFPTR(PID_ModuleDeviceAsyncFileAccessor, m_spAsyncFileAccessor)
///</AutoGeneratedContent>
END_SETOBJPARA_MAP()

///////////////////////////////////////////////////////////////////////////////
// Get parameters of CModuleDevice 
BEGIN_GETOBJPARA_MAP(CModuleDevice)
	GETOBJPARA_DATAAREA_MAP()
///<AutoGeneratedContent id="GetObjectParameterMap">
	GETOBJPARA_VALUE(PID_TcTraceLevel, m_TraceLevelMax)
	GETOBJPARA_VALUE(PID_ModuleDeviceParameter, m_Parameter)
	GETOBJPARA_VALUE(PID_ModuleDeviceLoggerPort, m_LoggerPort)
	GETOBJPARA_ITFPTR(PID_Ctx_TaskOid, m_spCyclicCaller)
	GETOBJPARA_ITFPTR(PID_ModuleDeviceAsyncFileAccessor, m_spAsyncFileAccessor)
///</AutoGeneratedContent>
END_GETOBJPARA_MAP()

///////////////////////////////////////////////////////////////////////////////
// Get watch entries of CModuleDevice
BEGIN_OBJPARAWATCH_MAP(CModuleDevice)
	OBJPARAWATCH_DATAAREA_MAP()
///<AutoGeneratedContent id="ObjectParameterWatchMap">
///</AutoGeneratedContent>
END_OBJPARAWATCH_MAP()

///////////////////////////////////////////////////////////////////////////////
// Get data area members of CModuleDevice
BEGIN_OBJDATAAREA_MAP(CModuleDevice)
///<AutoGeneratedContent id="ObjectDataAreaMap">
	OBJDATAAREA_VALUE(ADI_ModuleDeviceNDI, m_NDI)
	OBJDATAAREA_VALUE(ADI_ModuleDeviceSDI, m_SDI)
	OBJDATAAREA_VALUE(ADI_ModuleDeviceAI, m_AI)
	OBJDATAAREA_VALUE(ADI_ModuleDeviceNDO, m_NDO)
	OBJDATAAREA_VALUE(ADI_ModuleDeviceSDO, m_SDO)
	OBJDATAAREA_VALUE(ADI_ModuleDeviceAO, m_AO)
///</AutoGeneratedContent>
END_OBJDATAAREA_MAP()

int testVar = 0;
///////////////////////////////////////////////////////////////////////////////
CModuleDevice::CModuleDevice()
	: m_Trace(m_TraceLevelMax, m_spSrv)
	, m_counter(0)

{
///<AutoGeneratedContent id="MemberInitialization">
	m_TraceLevelMax = tlAlways;
	memset(&m_Parameter, 0, sizeof(m_Parameter));
	m_LoggerPort = 0;
	memset(&m_NDI, 0, sizeof(m_NDI));
	memset(&m_SDI, 0, sizeof(m_SDI));
	memset(&m_AI, 0, sizeof(m_AI));
	memset(&m_NDO, 0, sizeof(m_NDO));
	memset(&m_SDO, 0, sizeof(m_SDO));
	memset(&m_AO, 0, sizeof(m_AO));
///</AutoGeneratedContent>
	INIT_MODULE_DEVICE
}

///////////////////////////////////////////////////////////////////////////////
CModuleDevice::~CModuleDevice() 
{
}


///////////////////////////////////////////////////////////////////////////////
// State Transitions 
///////////////////////////////////////////////////////////////////////////////
IMPLEMENT_ITCOMOBJECT_SETOBJSTATE_IP_PI(CModuleDevice)

///////////////////////////////////////////////////////////////////////////////
// State transition from PREOP to SAFEOP
//
// Initialize input parameters 
// Allocate memory
HRESULT CModuleDevice::SetObjStatePS(PTComInitDataHdr pInitData)
{
	m_Trace.Log(tlVerbose, FENTERA);
	HRESULT hr = S_OK;
	IMPLEMENT_ITCOMOBJECT_EVALUATE_INITDATA(pInitData);

	// TODO: Add initialization code
	
	
	logger->info("Initialize...");
	initEnvironment();
	logger->info("Device count=%d", DEVICE->getDeviceCount());
	/*
	logger->info("[%s]", DEVICE->getDeviceByIndex(500)->name);
	OP->subscribe("SimpleFunction", []()->OperatorStatusEnum {
		EV->postInfoLog("Simple function");
		return OperatorStatusEnum::SUCCESS;
		});
	
	OperatorNode* node;
	for (int id = TEST_LEN-1; id >=0; id--) {
		char cmd[128];
		sprintf(cmd, "CheckFunction%d", id);
		node = OP->subscribe(cmd);
		
		node->addPreCheck([]()->OperatorStatusEnum {
			EV->postInfoLog("Prepare checking [%s]...",OP->current->params.get(1));
			return OperatorStatusEnum::SUCCESS;
			});
		
		node->addExec([]()->OperatorStatusEnum {
			EV->postInfoLog("Execute %s",OP->current->name);
			return OperatorStatusEnum::RUNNING;
			});
		node->addCheck([]()->OperatorStatusEnum {
			static PMCBOOL first = TRUE;
			if (first) {
				EV->postInfoLog("%s check Running", OP->current->name);
				first = FALSE;
				return OperatorStatusEnum::RUNNING;
			}
			else {
				//EV->postInfoLog("Second check ->Success");
				static int count = 1;
				count++;
				if (strcmp(OP->current->name, "CheckFunction9") == 0) {
					if (count < 300) {
						EV->postInfoLog("%s check Running", OP->current->name);
						return OperatorStatusEnum::RUNNING;
					}
					else {
						EV->postInfoLog("%s check Success", OP->current->name);
						return OperatorStatusEnum::SUCCESS;
					}
				}
				if (OP->current->status == OperatorStatusEnum::SUCCESS && OP->current->status.trigger()) {
					EV->postInfoLog("%s check Success",OP->current->name);
				}
				return OperatorStatusEnum::SUCCESS;
			}

			});
		node->addAlarmCheck([]()->OperatorStatusEnum {
			return OperatorStatusEnum::SUCCESS;

			});
			
	}
	
	
	node = OP->subscribe("GroupFunction");
	auto father = node;
	node = node->addChild();
	node->addExec([]()->OperatorStatusEnum {
		EV->postInfoLog("Group1 Execute ...");
		return RUNNING;
		});
	node->addCheck([]()->OperatorStatusEnum {
		static int counter = 0;
		if (counter<2) {
			//EV->postInfoLog("Group1 check ->Running");
			counter++;
			return RUNNING;
		}
		else {
			EV->postInfoLog("Group1 check ->Success");
			
			
			return SUCCESS;
		}

		});
	node = father;
	node = node->addChild();
	node->addExec([]()->OperatorStatusEnum {
		EV->postInfoLog("Group2 Execute ...");
		return RUNNING;
		});
	node->addCheck([]()->OperatorStatusEnum {
		static int counter = 0;
		if (counter<2) {
			//EV->postInfoLog("Group2 check ->Running");
			counter++;
			return RUNNING;
		}
		else {
			EV->postInfoLog("Group2 check ->Success");
			
			return SUCCESS;
		}

		});
	node->addAlarmCheck([]()->OperatorStatusEnum {
		strcpy(OP->alarmText , "Test alarm");
		EV->postInfoLog("Test alarm");
		return ALARM;

		

		});
	node = OP->subscribe("LastFunction", []()->OperatorStatusEnum {
		EV->postInfoLog("Last function");
		return SUCCESS;
		});
	*/
	m_Trace.Log(tlVerbose, FLEAVEA "hr=0x%08x", hr);
	return hr;
}

///////////////////////////////////////////////////////////////////////////////
// State transition from SAFEOP to OP
//
// Register with other TwinCAT objects
HRESULT CModuleDevice::SetObjStateSO()
{
	m_Trace.Log(tlVerbose, FENTERA);
	HRESULT hr = S_OK;

	// TODO: Add any additional initialization
	//调用设备的initialyze函数
	int count = DEVICE->getDeviceCount();
	for (int index = 0; index < count; index++) {
		BaseDevice* device = DEVICE->getDeviceByIndex(index);
		device->initialize();
}
	boatModule->initialize();
	
#if defined( _DEBUG ) && defined(_WITH_SIMULATOR)
	simulatorSet();
#endif


	m_Trace.Log(tlVerbose, FLEAVEA "In SAFEOP to OP");
#ifdef USE_UDP_PROTOCOL
	if (SUCCEEDED(hr) && TCP_UDP_PTR.HasOID())
	{
		if (SUCCEEDED_DBG(hr = m_spSrv->TcQuerySmartObjectInterface(TCP_UDP_PTR))) {
			if (SUCCEEDED_DBG(hr = TCP_UDP_PTR->RegisterReceiver(logger->port, THIS_CAST(ITcIoUdpProtocolRecv)))) {
				testVar = 200;
				m_Trace.Log(tlVerbose, FLEAVEA "Server: RegisterReceiver success on Port: %d", logger->port);

			}else {
				m_Trace.Log(tlError, FLEAVEA "Server: RegisterReceiver failed on Port: %d", logger->port);
				TCP_UDP_PTR = NULL;
				testVar = 404;
			}			
		}

	}
#else
#ifdef USE_TCP_PROTOCOL
	if (SUCCEEDED(hr) && TCP_UDP_PTR.HasOID())
	{
		if (SUCCEEDED_DBG(hr = m_spSrv->TcQuerySmartObjectInterface(TCP_UDP_PTR))) {
			hr = TCP_UDP_PTR->AllocSocket(THIS_CAST(ITcIoTcpProtocolRecv), logger->listenSocketId);
			if (FAILED(hr)) {
				m_Trace.Log(tlError, FLEAVEA "Listen error on Port: %d,[%s]", logger->port, AdsGetHResultText(hr));
			}
			if (SUCCEEDED_DBG(hr = TCP_UDP_PTR->Listen(logger->listenSocketId, logger->port))) {

				testVar = 200;
				m_Trace.Log(tlVerbose, FLEAVEA "Server: RegisterReceiver success on Port: %d", logger->port);

			}
			else {
				m_Trace.Log(tlError, FLEAVEA "Server: RegisterReceiver failed on Port: %d", logger->port);
				TCP_UDP_PTR = NULL;
				testVar = 404;
			}

		}
	}
#endif
#endif
	// If following call is successful the CycleUpdate method will be called, 
	// possibly even before method has been left.
	hr = FAILED(hr) ? hr : AddModuleToCaller(); 

	// Cleanup if transition failed at some stage
	if ( FAILED(hr) )
	{

#ifdef USE_UDP_PROTOCOL
		if (TCP_UDP_PTR != NULL) {
			TCP_UDP_PTR->UnregisterReceiver(logger->port);
			TCP_UDP_PTR = NULL;
			testVar = 405;
		}
#else
#ifdef USE_TCP_PROTOCOL
		if (TCP_UDP_PTR != NULL) {
			if (logger->acceptSocketId != 0) {
				TCP_UDP_PTR->Close(logger->acceptSocketId);
				logger->acceptSocketId = 0;
			}
			if (logger->listenSocketId != 0) {
				TCP_UDP_PTR->Close(logger->listenSocketId);
				logger->listenSocketId = 0;
			}
			
			testVar = 405;
		}
#endif
#endif
		RemoveModuleFromCaller(); 
		m_Trace.Log(tlVerbose, FLEAVEA "SAFEOP to OP failed:%d", hr);
	}
	
	m_Trace.Log(tlVerbose, FLEAVEA "hr=0x%08x", hr);
	return hr;
}

///////////////////////////////////////////////////////////////////////////////
// State transition from OP to SAFEOP
HRESULT CModuleDevice::SetObjStateOS()
{
	m_Trace.Log(tlVerbose, FENTERA);

	HRESULT hr = S_OK;
	//调用设备的temrinate函数
	int count = DEVICE->getDeviceCount();
	//boatModule->terminate();
	for (int index = 0; index < count; index++) {
		BaseDevice* device = DEVICE->getDeviceByIndex(index);
		device->terminate();
}
	
#ifdef USE_UDP_PROTOCOL
	if (TCP_UDP_PTR != NULL) {
		TCP_UDP_PTR->UnregisterReceiver(logger->port);
		TCP_UDP_PTR = NULL;
		testVar = 0;
	}
#else
#ifdef USE_TCP_PROTOCOL
	if (TCP_UDP_PTR != NULL) {
		if (logger->acceptSocketId != 0) {
			TCP_UDP_PTR->Close(logger->acceptSocketId);
			logger->acceptSocketId = 0;
		}
		if (logger->listenSocketId != 0) {
			TCP_UDP_PTR->Close(logger->listenSocketId);
			logger->listenSocketId = 0;
		}

		testVar = 0;
	}
#endif
#endif
	RemoveModuleFromCaller(); 

	

	/// ////////////////////////////////////////

	m_Trace.Log(tlVerbose, FLEAVEA "hr=0x%08x", hr);
	return hr;
}

///////////////////////////////////////////////////////////////////////////////
// State transition from SAFEOP to PREOP
HRESULT CModuleDevice::SetObjStateSP()
{
	HRESULT hr = S_OK;
	m_Trace.Log(tlVerbose, FENTERA);

	// TODO: Add deinitialization code
	// TODO: Add any additional deinitialization
	
	void closeDEVICE();
	closeDEVICE();
	m_Trace.Log(tlVerbose, FLEAVEA "hr=0x%08x", hr);
	m_counter = 0;
	return hr;
}

///<AutoGeneratedContent id="ImplementationOf_ITcCyclic">
HRESULT CModuleDevice::CycleUpdate(ITcTask* ipTask, ITcUnknown* ipCaller, ULONG_PTR context)
{
	HRESULT hr = S_OK;
	// TODO: Replace the sample with your cyclic code
	m_counter++;

	if (m_counter < 100) {
		return hr;
	}
#if defined( _DEBUG ) && defined(_WITH_SIMULATOR)
	simulatorMonitor();
#endif
	if(m_counter==100){
		OperatorNode *op=OP->select("PM1.SetBoatMotion.boatload");
		op->setParams("boatload;300;0;12");
		op->Do();
	}
	else {
		OperatorStatus status = OP->monitor();
		if (status == OperatorStatusEnum::SUCCESS) {
			if (status.trigger()) {
				status.clearTrigger();
				logger->info("Now success");
				OP->reset();
			}
		}
		else if (status == OperatorStatusEnum::ALARM) {
			logger->info("Now error finish");
			OP->reset();
		}else if (m_counter % 20 == 0) {
			logger->info("[Tick]");
		}
	}

	return S_OK;
	

}
///</AutoGeneratedContent>

///////////////////////////////////////////////////////////////////////////////
HRESULT CModuleDevice::AddModuleToCaller()
{
	m_Trace.Log(tlVerbose, FENTERA);

	HRESULT hr = S_OK;
	if ( m_spCyclicCaller.HasOID() )
	{
		if ( SUCCEEDED_DBG(hr = m_spSrv->TcQuerySmartObjectInterface(m_spCyclicCaller)) )
		{
			if ( FAILED(hr = m_spCyclicCaller->AddModule(m_spCyclicCaller, THIS_CAST(ITcCyclic))) )
			{
				m_spCyclicCaller = NULL;
			}
		}
		
	}
	else
	{
		hr = ADS_E_INVALIDOBJID; 
		SUCCEEDED_DBGT(hr, "Invalid OID specified for caller task");
	}

	m_Trace.Log(tlVerbose, FLEAVEA "hr=0x%08x", hr);
	return hr;
}

///////////////////////////////////////////////////////////////////////////////
VOID CModuleDevice::RemoveModuleFromCaller()
{
	m_Trace.Log(tlVerbose, FENTERA);

	if ( m_spCyclicCaller )
	{
		m_spCyclicCaller->RemoveModule(m_spCyclicCaller);
	}
	m_spCyclicCaller	= NULL;

	m_Trace.Log(tlVerbose, FLEAVEA);
}

HRESULT CModuleDevice::SendClientData(unsigned long socketId, unsigned long nData, void* pData, unsigned long& nSendData)
{
	nSendData = nData;
	return S_OK;
}



