FB_ClientDataExcha

Bei einer steigenden Flanke am bExecute-Eingang wird ein Nullterminierter-String zum Remote-Server gesendet und ein vom Remote-Server zurückgelieferter String zurückgelesen. Der Funktionsbaustein versucht die Daten so lange zu lesen, bis eine Nullterminierung in dem empfangenen String erkannt wurde. Wenn die Timeout-Zeit PLCPRJ_RECEIVE_TIMEOUT überschritten wurde oder wenn ein Fehler auftritt, wird der Empfang abgebrochen. Der nächste Lesevorgang wird nach einer Verzögerungszeit ausgeführt, wenn beim letzten Lesevorgang keine neuen Daten gelesen werden konnten. Die Systemauslastung verringert sich dadurch.
Schnittstelle
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
Realisierung
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