<?xml version="1.0" encoding="utf-8"?>
<TcPlcObject Version="1.1.0.1" ProductVersion="3.1.4024.12">
  <POU Name="FB_EcSlavesDiag" Id="{a30f3bc4-81e1-4acf-a256-4f4bc3891abb}" SpecialFunc="None">
    <Declaration><![CDATA[// 该功能块可以对EtherCAT从站进行检测，检测内容详见 EC_SLAVE_DIAG_INFO_DATA
{attribute 'no_check'}
{attribute 'enable_dynamic_creation'}
FUNCTION_BLOCK FB_EcSlavesDiag 
VAR_INPUT
	Execute													:	BOOL := FALSE; 		// 如果为TRUE，则执行功能块
	MasterAmsNetId											:	T_AmsNetId;
END_VAR
VAR_OUTPUT
	ExecutionTime											: 	TIME;
	NoOfSlaves												:	UINT;			
    InfoData												:	ARRAY [MIN_SLAVES..MAX_SLAVES] OF EC_SLAVE_DIAG_INFO_DATA; 
	
	Busy													: BOOL; 			// 如果为TRUE，则功能块忙碌
	Done													: BOOL; 			// 如果为TRUE，则功能块完成
	Error													: BOOL;				// 如果为TRUE，则功能块存在错误
{attribute 'displaymode':='hex'}  
	ErrorId													: UDINT; 			// 错误ID
END_VAR
VAR
    {attribute 'hide'} 
	State													: INT := 0;
    {attribute 'hide'} 
	rtExecute												: R_TRIG;		

	StartTime												:	TIME;	

	pMemory													:	POINTER TO BYTE;
	SizeOfMemory											:	UDINT;

	pScannedSlaves											:	POINTER TO ARRAY [MIN_SLAVES..MAX_SLAVES] OF Tc2_EtherCAT.ST_EcSlaveScannedData;
	pConfigSlaves											:	POINTER TO ARRAY [MIN_SLAVES..MAX_SLAVES] OF Tc2_EtherCAT.ST_EcSlaveConfigData; 
	pSlavesState											:	POINTER TO ARRAY [MIN_SLAVES..MAX_SLAVES] OF Tc2_EtherCAT.ST_EcSlaveState;
	pSlavesStatusCode										:	POINTER TO ARRAY [MIN_SLAVES..MAX_SLAVES] OF DWORD;
	
(* dummy **********************************************************)
	i,k,idx													:	UINT := 0;
	
(* function-blocks *************************************************)
	EcGetSlaveCount											:	FB_EcGetSlaveCount ;
	EcGetConfSlaves											:	FB_EcGetConfSlaves ;
	EcGetScannedSlaves										:	FB_EcGetScannedSlaves ;
	EcGetAllSlaveStateS										:	FB_EcGetAllSlaveStateS ;
	EcGetAllSlaveCrcErrors									:	FB_EcGetAllSlaveCrcErrors ;
	EcGetAllSlaveAbnormalStateChanges						:	FB_EcGetAllSlaveAbnormalStateChanges ;	
	EcGetSlaveTopologyInfo									: 	FB_EcGetSlaveTopologyInfo ;	
END_VAR

]]></Declaration>
    <Implementation>
      <ST><![CDATA[(* Sequence *********************************)
	rtExecute(CLK := Execute);
	

	CASE State OF
	0:
		Busy 												:= FALSE;
		IF rtExecute.Q
		THEN //Clear data if FB is disabled or started
			Busy 											:= TRUE;
			Done											:= FALSE;
			Error											:= FALSE;
			Errorid											:= 0;


		//	NoOfSlavesNIO									:= 0;	


			StartTime										:= TIME();
			ExecutionTime									:= T#0MS;
			
			EcGetSlaveCount(bExecute := FALSE,sNetId := MasterAmsNetId);
			EcGetConfSlaves(bExecute := FALSE,sNetId := MasterAmsNetId);
			EcGetSlaveTopologyInfo(bExecute := FALSE,sNetId := MasterAmsNetId);
			EcGetAllSlaveStates(bExecute := FALSE, sNetId := MasterAmsNetId);
			EcGetAllSlaveCrcErrors(bExecute := FALSE,sNetId := MasterAmsNetId);
			EcGetAllSlaveAbnormalStateChanges(bExecute := FALSE,sNetId := MasterAmsNetId);
			EcGetScannedSlaves(bExecute := FALSE,sNetId := MasterAmsNetId);
			
			State										:= 1;
			
		ELSIF NOT Execute THEN
			Done											:= FALSE;
			Error											:= FALSE;
			Errorid											:= 0;

		END_IF
		IF StartTime > T#0MS AND ExecutionTime = T#0MS
		THEN
			ExecutionTime									:= TIME() - StartTime;
		END_IF
		
	(* Read no of configured slaves *********************************************************************)
	1:
		EcGetSlaveCount(bExecute := NoOfSlaves = 0);
		IF NOT EcGetSlaveCount.bBusy
		THEN
			IF EcGetSlaveCount.bError 
			THEN
				Busy										:= FALSE;
				Error										:= TRUE;
				ErrorId										:= EcGetSlaveCount.nErrId;
				State 										:= 0;
			ELSIF EcGetSlaveCount.bExecute AND NoOfSlaves <> EcGetSlaveCount.nSlaves
			THEN
				NoOfSlaves									:= EcGetSlaveCount.nSlaves;					

				//Init Info Data 	
				MEMSET(ADR(InfoData),0,SIZEOF(InfoData));

				//k 											:= NoOfSlaves + 1;
				//Set buffer lenght according to needed memory space
				EcGetConfSlaves.cbBufLen					:= SIZEOF(Tc2_EtherCAT.ST_EcSlaveConfigData) * NoOfSlaves;
				EcGetScannedSlaves.cbBufLen					:= SIZEOF(Tc2_EtherCAT.ST_EcSlaveScannedData) * NoOfSlaves;
				EcGetAllSlaveStates.cbBufLen				:= SIZEOF(Tc2_EtherCAT.ST_EcSlaveState) * NoOfSlaves;
				EcGetAllSlaveCrcErrors.cbBufLen				:= SIZEOF(DWORD) * NoOfSlaves;						
					
				//Allocate dynamic buffer memory 
				IF Allocate(MAX(MAX(EcGetConfSlaves.cbBufLen,EcGetAllSlaveCrcErrors.cbBufLen), MAX(EcGetScannedSlaves.cbBufLen,EcGetAllSlaveStateS.cbBufLen) ))
				THEN
					//Write buffer lenght per FB	
					pConfigSlaves							:= pMemory;
					pScannedSlaves							:= pMemory;
					pSlavesState							:= pMemory;
					pSlavesStatusCode						:= pMemory;	
					
					State 									:= State + 1;			
				ELSE
					Busy									:= FALSE;
					Error									:= TRUE;
					ErrorId									:= E_AdsErr.DEVICE_NOMEMORY; //No memory
					State 									:= 0;	
				END_IF

			ELSE
				State 										:= State + 1;
			END_IF
		ELSE
			;
		END_IF		
		
			(* Read slaves "configuration" ************************************************************************************************************)
	2:
		EcGetConfSlaves(bExecute := TRUE, pArrEcConfSlaveInfo := pConfigSlaves, cbBufLen := (* See State 1 *) );
			
		IF NOT EcGetConfSlaves.bBusy
		THEN
			IF EcGetConfSlaves.bError 
			THEN
				Busy										:= FALSE;
				Error										:= TRUE;
				ErrorId										:= EcGetConfSlaves.nErrorId;
				State										:= 0;     
					
			ELSIF EcGetConfSlaves.nSlaves > MAX_SLAVES
			THEN
				Busy										:= FALSE;
				Error										:= TRUE;
				ErrorId										:= E_AdsErr.DEVICE_INVALIDSIZE  ;
				State										:= 0;  					
			ELSE
				State 										:= State + 1;
			END_IF
		END_IF	
		
	3: //Fill structure	
		k													:= MIN(EcGetConfSlaves.nSlaves, NoOfSlaves);
		FOR i := MIN_SLAVES TO k DO
			InfoData[i].Addr								:= pConfigSlaves^[i].nAddr;
			InfoData[i].ConfigType							:= pConfigSlaves^[i].sType; 
			InfoData[i].ConfigName							:= DELETE(pConfigSlaves^[i].sName, LEN(InfoData[i].ConfigType) + 3 , FIND(pConfigSlaves^[i].sName,InfoData[i].ConfigType) - 1);  	
			InfoData[i].ConfigTypeIdentity					:= F_ConvProductCodeToString(pConfigSlaves^[i].stSlaveIdentity);
			InfoData[i].ConfigIdentity						:= pConfigSlaves^[i].stSlaveIdentity;		
		END_FOR
		
		State:=20;
		
		(* Read slaves "EtherCAT State and link state" ***************************************************************************************)
	20	:
		EcGetAllSlaveStateS(bExecute := NoOfSlaves > 0, pStateBuf:=  pSlavesState, cbBufLen	:= (* See State 1 *));
					
		IF NOT EcGetAllSlaveStateS.bBusy
		THEN
			IF EcGetAllSlaveStateS.bError 
			THEN
				Busy										:= FALSE;
				Error										:= TRUE;
				ErrorId										:= EcGetAllSlaveStateS.nErrId;
				State 										:= 0;
			ELSE
				k											:= MIN(EcGetAllSlaveStateS.nSlaves, NoOfSlaves);
				FOR i := MIN_SLAVES TO k DO
					InfoData[i].LinkState					:= pSlavesState^[i].linkState;
					InfoData[i].DevState					:= pSlavesState^[i].deviceState;
					InfoData[i].DevStateText				:= F_ConvSlaveStateToString(pSlavesState^[i]);
				END_FOR	

				State 										:= State + 1;
			END_IF
		ELSE
			;
		END_IF	
		
	(* Get all slaves "CRC counter" ********************************************************************)
	21:	
		EcGetAllSlaveCrcErrors(bExecute := NoOfSlaves > 0, sNetId	:= MasterAmsNetId,  pCrcErrorBuf:= pSlavesStatusCode,  cbBufLen	:= (* See State 1 *));
		IF NOT EcGetAllSlaveCrcErrors.bBusy
		THEN
			IF EcGetAllSlaveCrcErrors.bError 
			THEN
				Busy										:= FALSE;
				Error										:= TRUE;
				ErrorId										:= EcGetAllSlaveStateS.nErrId;
				
				State 										:= 0;
			ELSE
				k											:= MIN(EcGetAllSlaveCrcErrors.nSlaves, NoOfSlaves);
				FOR i := MIN_SLAVES TO k DO
					InfoData[i].CntOfCRCErrors				:= pSlavesStatusCode^[i];				
				END_FOR				
				
				State 										:= 40;
			END_IF
		ELSE
			;
		END_IF
		
	40:
	    Busy											:= FALSE;
		Done											:= TRUE;
		State											:= 0; 



	
END_CASE]]></ST>
    </Implementation>
    <Method Name="allocate" Id="{84c9eb29-241f-45cf-9e2d-f9926d3a919d}">
      <Declaration><![CDATA[METHOD PROTECTED  allocate : BOOL
VAR_INPUT 
	MemSize													:	UDINT;
END_VAR
VAR
END_VAR	
]]></Declaration>
      <Implementation>
        <ST><![CDATA[IF MemSize = 0 THEN
	Allocate												:= FALSE;	
	
ELSIF pMemory = 0 THEN
	pMemory													:= __NEW(BYTE,MemSize );
	SizeOfMemory											:= MemSize;
	Allocate												:= TRUE;	
	
ELSIF MemSize > SizeOfMemory THEN
	__DELETE(pMemory);  	
	pMemory													:= __NEW(BYTE,MemSize );
	SizeOfMemory											:= MemSize;
	Allocate												:= TRUE;
	
ELSE
	Allocate												:= FALSE;
END_IF

]]></ST>
      </Implementation>
    </Method>
    <Method Name="FB_exit" Id="{ef2288a3-2b10-45cb-8f96-c8c520cb638f}">
      <Declaration><![CDATA[METHOD FB_exit : BOOL
VAR_INPUT
	bInCopyCode : BOOL; // if TRUE, the exit method is called for exiting an instance that is copied afterwards (online change).
END_VAR
]]></Declaration>
      <Implementation>
        <ST><![CDATA[IF NOT bInCopyCode AND pMemory <> 0
THEN //Release memory in case the PLC stopps
	__DELETE(pMemory);
	SizeOfMemory								:= 0;
END_IF]]></ST>
      </Implementation>
    </Method>
    <Method Name="FB_init" Id="{65b6810e-47d4-4a19-b755-3593dc5d8f56}">
      <Declaration><![CDATA[METHOD FB_init : BOOL
VAR_INPUT
	bInitRetains : BOOL; // if TRUE, the retain variables are initialized (warm start / cold start)
	bInCopyCode : BOOL;  // if TRUE, the instance afterwards gets moved into the copy code (online change)
END_VAR
]]></Declaration>
      <Implementation>
        <ST><![CDATA[MasterAmsNetId:='5.18.64.212.2.1';]]></ST>
      </Implementation>
    </Method>
    <LineIds Name="FB_EcSlavesDiag">
      <LineId Id="28" Count="1" />
      <LineId Id="254" Count="0" />
      <LineId Id="30" Count="12" />
      <LineId Id="44" Count="10" />
      <LineId Id="9" Count="0" />
      <LineId Id="66" Count="0" />
      <LineId Id="71" Count="0" />
      <LineId Id="83" Count="0" />
      <LineId Id="73" Count="0" />
      <LineId Id="75" Count="7" />
      <LineId Id="72" Count="0" />
      <LineId Id="87" Count="0" />
      <LineId Id="89" Count="9" />
      <LineId Id="100" Count="13" />
      <LineId Id="116" Count="7" />
      <LineId Id="125" Count="6" />
      <LineId Id="133" Count="7" />
      <LineId Id="88" Count="0" />
      <LineId Id="84" Count="0" />
      <LineId Id="144" Count="10" />
      <LineId Id="156" Count="6" />
      <LineId Id="164" Count="3" />
      <LineId Id="85" Count="0" />
      <LineId Id="168" Count="0" />
      <LineId Id="173" Count="4" />
      <LineId Id="179" Count="2" />
      <LineId Id="169" Count="0" />
      <LineId Id="183" Count="0" />
      <LineId Id="170" Count="0" />
      <LineId Id="184" Count="0" />
      <LineId Id="186" Count="10" />
      <LineId Id="198" Count="4" />
      <LineId Id="240" Count="0" />
      <LineId Id="244" Count="1" />
      <LineId Id="203" Count="0" />
      <LineId Id="211" Count="20" />
      <LineId Id="233" Count="6" />
      <LineId Id="185" Count="0" />
      <LineId Id="171" Count="1" />
      <LineId Id="252" Count="1" />
      <LineId Id="251" Count="0" />
      <LineId Id="248" Count="2" />
      <LineId Id="247" Count="0" />
      <LineId Id="67" Count="0" />
    </LineIds>
    <LineIds Name="FB_EcSlavesDiag.allocate">
      <LineId Id="387" Count="0" />
      <LineId Id="389" Count="0" />
      <LineId Id="403" Count="0" />
      <LineId Id="252" Count="0" />
      <LineId Id="261" Count="0" />
      <LineId Id="378" Count="0" />
      <LineId Id="305" Count="0" />
      <LineId Id="404" Count="0" />
      <LineId Id="330" Count="0" />
      <LineId Id="358" Count="0" />
      <LineId Id="363" Count="1" />
      <LineId Id="332" Count="0" />
      <LineId Id="396" Count="0" />
      <LineId Id="379" Count="1" />
      <LineId Id="306" Count="1" />
      <LineId Id="2" Count="0" />
    </LineIds>
    <LineIds Name="FB_EcSlavesDiag.FB_exit">
      <LineId Id="3" Count="3" />
      <LineId Id="2" Count="0" />
    </LineIds>
    <LineIds Name="FB_EcSlavesDiag.FB_init">
      <LineId Id="7" Count="0" />
    </LineIds>
  </POU>
</TcPlcObject>