FB_ClientDataExcha

In the event of an rising edge at the bExecute input, a null-terminated string is sent to the remote server, and a string returned by the remote server is read. The function block will try reading the data until null termination was detected in the string received. If the PLCPRJ_RECEIVE_TIMEOUT time-out period is exceeded or if an error occurs, reception is aborted. Data are attempted to be read again after a certain delay time, if no new data could be read during the last read attempt. This reduces the system load.
Interface
FUNCTION_BLOCK FB_ClientDataExcha
VAR_INPUT
hSocket : T_HSOCKET;
sToServer : T_MaxString;
bExecute : BOOL;
END_VAR
VAR_OUTPUT
bBusy : BOOL;
bError : BOOL;
nErrId : UDINT;
sFromServer : T_MaxString;
END_VAR
VAR
fbSocketSend : FB_SocketSend := ( sSrvNetID := '', tTimeout := DEFAULT_ADS_TIMEOUT );
fbSocketReceive : FB_SocketReceive := ( sSrvNetID := '', tTimeout := DEFAULT_ADS_TIMEOUT );
fbReceiveTON : TON;
fbDisconnectTON : TON;
RisingEdge : R_TRIG;
eStep : E_DataExchaSteps;
cbReceived, startPos, endPos, idx : UDINT;
cbFrame : UDINT;
rxBuffer : ARRAY[0..MAX_PLCPRJ_RXBUFFER_SIZE] OF BYTE;
END_VAR
Implementation
RisingEdge( CLK := bExecute );
CASE eStep OF
DATAEXCHA_STATE_IDLE:
IF RisingEdge.Q THEN
bBusy := TRUE;
bError := FALSE;
nErrid := 0;
cbReceived := 0;
fbReceiveTON( IN := FALSE, PT := T#0s ); (* don't wait, read the first answer data immediately *)
fbDisconnectTON( IN := FALSE, PT := T#0s );(* disable timeout check first *)
eStep := DATAEXCHA_STATE_SEND_START;
END_IF
DATAEXCHA_STATE_SEND_START:
fbSocketSend( bExecute := FALSE );
fbSocketSend( hSocket := hSocket,
pSrc := ADR( sToServer ),
cbLen := LEN( sToServer ) + 1,(* string length inclusive zero delimiter *)
bExecute:= TRUE );
eStep := DATAEXCHA_STATE_SEND_WAIT;
DATAEXCHA_STATE_SEND_WAIT:
fbSocketSend( bExecute := FALSE );
IF NOT fbSocketSend.bBusy THEN
IF NOT fbSocketSend.bError THEN
eStep := DATAEXCHA_STATE_RECEIVE_START;
ELSE
LogError( 'FB_SocketSend (local client)', fbSocketSend.nErrId );
nErrId := fbSocketSend.nErrId;
eStep := DATAEXCHA_STATE_ERROR;
END_IF
END_IF
DATAEXCHA_STATE_RECEIVE_START:
fbDisconnectTON( );
fbReceiveTON( IN := TRUE );
IF fbReceiveTON.Q THEN
fbReceiveTON( IN := FALSE );
fbSocketReceive( bExecute := FALSE );
fbSocketReceive( hSocket:= hSocket,
pDest:= ADR( rxBuffer ) + cbReceived,
cbLen:= SIZEOF( rxBuffer ) - cbReceived,
bExecute:= TRUE );
eStep := DATAEXCHA_STATE_RECEIVE_WAIT;
END_IF
DATAEXCHA_STATE_RECEIVE_WAIT:
fbSocketReceive( bExecute := FALSE );
IF NOT fbSocketReceive.bBusy THEN
IF NOT fbSocketReceive.bError THEN
IF (fbSocketReceive.nRecBytes > 0) THEN(* bytes received *)
startPos := cbReceived;(* rxBuffer array index of first data byte *)
endPos := cbReceived + fbSocketReceive.nRecBytes - 1;(* rxBuffer array index of last data byte *)
cbReceived := cbReceived + fbSocketReceive.nRecBytes;(* calculate the number of received data bytes *)
cbFrame := 0;(* reset frame length *)
IF cbReceived < SIZEOF( sFromServer ) THEN(* no overflow *)
fbReceiveTON( PT := T#0s ); (* bytes received => increase the read (polling) speed *)
fbDisconnectTON( IN := FALSE );(* bytes received => disable timeout check *)
(* search for string end delimiter *)
FOR idx := startPos TO endPos BY 1 DO
IF rxBuffer[idx] = 0 THEN(* string end delimiter found *)
cbFrame := idx + 1;(* calculate the length of the received string (inclusive the end delimiter) *)
MEMCPY( ADR( sFromServer ), ADR( rxBuffer ), cbFrame );(* copy the received string to the output variable (inclusive the end delimiter) *)
MEMMOVE( ADR( rxBuffer ), ADR( rxBuffer[cbFrame] ), cbReceived - cbFrame );(* move the reamaining data bytes *)
cbReceived := cbReceived - cbFrame;(* recalculate the remaining data byte length *)
bBusy := FALSE;
eStep := DATAEXCHA_STATE_IDLE;
EXIT;
END_IF
END_FOR
ELSE(* there is no more free read buffer space => the answer string should be terminated *)
LogError( 'FB_SocketReceive (local client)', PLCPRJ_ERROR_RECEIVE_BUFFER_OVERFLOW );
nErrId := PLCPRJ_ERROR_RECEIVE_BUFFER_OVERFLOW;(* buffer overflow !*)
eStep := DATAEXCHA_STATE_ERROR;
END_IF
ELSE(* no bytes received *)
fbReceiveTON( PT := PLCPRJ_RECEIVE_POLLING_TIME );(* no bytes received => decrease the read (polling) speed *)
fbDisconnectTON( IN := TRUE, PT := PLCPRJ_RECEIVE_TIMEOUT );(* no bytes received => enable timeout check*)
IF fbDisconnectTON.Q THEN (* timeout error*)
fbDisconnectTON( IN := FALSE );
LogError( 'FB_SocketReceive (local client)', PLCPRJ_ERROR_RECEIVE_TIMEOUT );
nErrID := PLCPRJ_ERROR_RECEIVE_TIMEOUT;
eStep := DATAEXCHA_STATE_ERROR;
ELSE(* repeat reading *)
eStep := DATAEXCHA_STATE_RECEIVE_START; (* repeat reading *)
END_IF
END_IF
ELSE(* receive error *)
LogError( 'FB_SocketReceive (local client)', fbSocketReceive.nErrId );
nErrId := fbSocketReceive.nErrId;
eStep := DATAEXCHA_STATE_ERROR;
END_IF
END_IF
DATAEXCHA_STATE_ERROR:(* error step *)
bBusy := FALSE;
bError := TRUE;
cbReceived := 0;
eStep := DATAEXCHA_STATE_IDLE;
END_CASE