
(* TODO: Add your comment here *)
FUNCTION_BLOCK PMC_CommandManager
	//perform setup	
	IF IsSetup THEN
		//save fieldbus buffer memory location
		FromPMCBufferAddress := ADR(FBin_pointer);
		ToPMCBufferAddress := ADR(FBout_pointer);		
		//possibly also initialize the ticketing system
		AvailableTicketNumber := 1;
		ExecutingTicket := 1;	
		NewStoredPMCReplyIndex := 0;		
		PMCResponseFrameNumber := -1;
		PMCRespondedCurrentTicket := FALSE;		
		SentNewCommand := FALSE;
	END_IF
	
	//ticketing system to provide new callers with a ticket number
	IF GetTicket THEN
		//add sempaphore control here unnecessary for single threaded B&R Controllers
		NewTicket := AvailableTicketNumber;
		//calculate the next ticket number
		IF AvailableTicketNumber = 65535 THEN
			AvailableTicketNumber := 1;	//not sure if it wraps around automatically
		ELSE
			AvailableTicketNumber := AvailableTicketNumber + 1;	
		END_IF
		
	END_IF	
	
	//completed ticket handling
	IF PMCRespondedCurrentTicket = FALSE AND IsSetup = FALSE THEN
		IF CompletedTicketNumber = ExecutingTicket THEN
			PMCRespondedCurrentTicket := TRUE;
			TicketResultAddress := FromPMCBufferAddress;
		ELSIF FromPMCBufferAddress > 0 AND ToPMCBufferAddress >0 AND PMCResponseFrameNumber < 0 AND SentNewCommand THEN			
			//automatic ticket completion monitoring
			//check the command counter and reply counter to see if we already received the response for the command
			memcpy(pDest := ADR(CmdCounterToPMC),pSrc := ToPMCBufferAddress  + H2P_START + H2P_CMDC_OFFSET,length := 1);
			memcpy(pDest := ADR(CmdCounterFromPMC),pSrc := FromPMCBufferAddress + P2H_START + P2H_CMDC_OFFSET,length := 1);	
			IF CmdCounterToPMC = CmdCounterFromPMC THEN
				PMCResponseFrameNumber := 0;
				memcpy(pDest := ADR(PMCResponseFrameNumber),pSrc := FromPMCBufferAddress + P2H_START + P2H_FRMC_OFFSET,length := 1);					
			END_IF				
		ELSIF PMCResponseFrameNumber >= 0 AND SentNewCommand THEN
			//check to see if we already received a response the previous cycle
			CurrentFrameNumber := 0;
			memcpy(pDest := ADR(CurrentFrameNumber),pSrc := FromPMCBufferAddress + P2H_START + P2H_FRMC_OFFSET,length := 1);	
			IF CurrentFrameNumber <> PMCResponseFrameNumber THEN
				//we have waited 1 cycle without the caller getting the data, copy the data to a backup buffer
				StoredPMCReplies[NewStoredPMCReplyIndex].TicketNumber := ExecutingTicket;
				memcpy(pDest := ADR(StoredPMCReplies[NewStoredPMCReplyIndex].FromPMCBuffer),pSrc := FromPMCBufferAddress,length := 54);
				NewStoredPMCReplyIndex := NewStoredPMCReplyIndex + 1;	//later can look for an empty buffer instead
				IF NewStoredPMCReplyIndex >= 20 THEN
					NewStoredPMCReplyIndex := 0;
				END_IF
				//start processing the next ticket
				PMCRespondedCurrentTicket := TRUE;				
			END_IF			
		END_IF
	END_IF
				
	IF PMCRespondedCurrentTicket THEN
		IF ExecutingTicket = 65535 THEN
			ExecutingTicket := 1;	//not sure if it wraps around automatically
		ELSE
			ExecutingTicket := ExecutingTicket + 1;	
		END_IF	
		PMCRespondedCurrentTicket := FALSE;
		PMCResponseFrameNumber := -1;
		SentNewCommand := FALSE;
	END_IF
	
	//find the result for a ticket
	IF FindTicketNumberResult > 0 THEN
		TicketResultAddress := 0;
		FOR Var1 := 0 TO 19 BY 1 DO
			IF StoredPMCReplies[Var1].TicketNumber = FindTicketNumberResult THEN
				TicketResultAddress := ADR(StoredPMCReplies[Var1].FromPMCBuffer);
				Var1 := 100;//break out of the for loop
			END_IF
		END_FOR;
	END_IF
	
END_FUNCTION_BLOCK
