Problem with SysSockRecv function

mpi
2019-12-09
2021-02-24
  • mpi - 2019-12-09

    Hello,

    I am running a wago PFC200 PLC and try to drive a equipment using ethernet TCP protocol under Codesys V2.3. I am able to create and connect a socket, send data and close the socket. Yet each time I want to receive data, that I know to be send by the equipment the connexion got stuck and I just have to switch on and of the equipment and restart my PLC.

    When I check if the equipement is ready to send back data using SysSockSelect, it returns 0, meaning that it is not ready to talk although it does send data. If I don't use the SysSockSelect and go straight to SysSockRecv then the program got stuck.

    Does anyone have an idea ?

    Thank for your help.

    Michel

    PROGRAM PLC_PRG
    VAR

    sendBt:BOOL;
    recvBT:BOOL;
    
    
    strLec:STRING(100);
    strEcr:STRING(100):=':FREQ:21.2345MHz';
    
    openSocket:BOOL;
    closeSocket:BOOL;
    
    
    diSocket : DINT := -1;
    iPort : INT:=9760;
    stDestIPAddress : STRING := '192.168.9.47';
    
    bySend : STRING(12) := ':IDN?';
    byRecv : STRING(128);
    xx:INT;
    yy:DINT;
    nbS:INT:=64;
    nbR:INT:=128;
    

    END_VAR

    IF openSocket THEN
    openSocket:=FALSE;
    IF(diSocket=-1) THEN
    diSocket := TcpClientOpenSocket(iPort, stDestIPAddress, 1000);
    END_IF
    END_IF

    IF recvBt THEN
    IF diSocket <> -1 THEN
    TcpReceiveData(diSocket, ADR(byRecv), SIZEOF(byRecv), 2);
    END_IF
    recvBt:=FALSE;
    END_IF

    IF sendBt THEN
    IF diSocket <> -1 THEN
    TcpSendData(diSocket, ADR(bySend), SIZEOF(bySend), 2);
    END_IF
    sendBt:=FALSE;
    END_IF

    IF closeSocket THEN
    closeSocket := FALSE;
    SysSockClose(diSocket:=diSocket);
    diSocket := -1;
    END_IF

    (*******)
    FUNCTION TcpClientOpenSocket : DINT
    ( Open TCP client socket to connect to server.
    Return: Socket-Id for connection session
    )
    VAR_INPUT
    iPort:INT; ( Port number of TCP socket to open )
    stIPAddress:STRING; ( IP-Address of server to connect to )
    diMaxDataSize:DINT; ( Max size of data to transmitt; if size = 0 default values are used )
    END_VAR
    VAR
    diSocket:DINT;
    bOptNoDelay:BOOL;
    lOptLinger:SOCKET_LINGER;
    bResult:BOOL;
    sa:SOCKADDRESS;
    END_VAR

    diSocket:=SysSockCreate(SOCKET_AF_INET, SOCKET_STREAM, 0);

    IF diSocket <> SOCKET_INVALID THEN

    SysSockSetOption(diSocket, SOCKET_SOL, SOCKET_SO_SNDBUF, ADR(diMaxDataSize), SIZEOF(diMaxDataSize));
    SysSockSetOption(diSocket, SOCKET_SOL, SOCKET_SO_RCVBUF, ADR(diMaxDataSize), SIZEOF(diMaxDataSize));
    lOptLinger.l_onoff:=0;
    lOptLinger.l_linger:=0;
    SysSockSetOption(diSocket,  SOCKET_SOL, SOCKET_SO_LINGER, ADR(lOptLinger), SIZEOF(lOptLinger));
    bOptNoDelay:=TRUE;
    SysSockSetOption(diSocket,  SOCKET_IPPROTO_TCP, SOCKET_TCP_NODELAY, ADR(bOptNoDelay), SIZEOF(bOptNoDelay));
    
    sa.sin_family:=SOCKET_AF_INET;
    sa.sin_addr:=GetIPAddress(stIPAddress);
    IF sa.sin_addr <> SOCKET_INADDR_NONE THEN
        sa.sin_port:=SysSockHtons(iPort);
        IF SysSockConnect(diSocket, ADR(sa), SIZEOF(sa)) = FALSE THEN
            SysSockClose(diSocket);
            diSocket:=SOCKET_INVALID;
        END_IF
    ELSE
        SysSockClose(diSocket);
        diSocket:=SOCKET_INVALID;
    END_IF
    

    END_IF
    TcpClientOpenSocket:=diSocket;
    (*******)
    FUNCTION TcpReceiveData : DINT
    ( Receive data from a tcp socket.
    Return: Number of bytes received
    )
    VAR_INPUT
    diSocket:DINT; ( Socket Id )
    pbyData:DWORD; ( Address of data buffer )
    diDataSize:DINT; ( Size of data to send )
    diTImeout : DINT; ( Timeout in seconds )
    END_VAR
    VAR
    fdRead:SOCKET_FD_SET;
    tvTimeout:SOCKET_TIMEVAL;
    rr:DINT;

    END_VAR

    tvTimeout.tv_usec := 0;
    fdRead.fd_count := 1;
    fdRead.fd_array[0] := diSocket;

    IF (SysSockSelect(SOCKET_FD_SETSIZE, ADR(fdRead), 0, 0, ADR(tvTimeout)) > 0) THEN
    TcpReceiveData:=SysSockRecv(diSocket, pbyData, diDataSize, 0);
    END_IF

    (*******)
    FUNCTION TcpSendData : DINT
    ( Send data via TCP socket.
    Return: Number of bytes sent
    )
    VAR_INPUT
    diSocket:DINT; ( Socket Id )
    pbyData:DWORD; ( Address of data buffer )
    diDataSize:DINT; ( Size of data to send )
    diTImeout : DINT; ( Timeout in seconds )
    END_VAR
    VAR
    fdWrite:SOCKET_FD_SET;
    tvTimeout:SOCKET_TIMEVAL;
    END_VAR
    tvTimeout.tv_sec := diTimeout ;
    tvTimeout.tv_usec := 0;
    fdWrite.fd_count := 1;
    fdWrite.fd_array[0] := diSocket;
    IF (SysSockSelect(SOCKET_FD_SETSIZE, 0, ADR(fdWrite), 0, ADR(tvTimeout)) > 0) THEN
    TcpSendData:=SysSockSend(diSocket, pbyData, diDataSize, 0);
    END_IF

    (*******)

     
  • mpi - 2019-12-12

    Hello
    Me again
    Actually I have found where the problem came from. The code was ok but the format of the command I used was missing a new line character at the end (what was not said in the notice).
    I have managed to see that using Wireshark a freeware that allows tcp frame inspection on the net. There I saw that the '0a' character was missing compared to the utility software provided by the manufacturer.
    Though nobody answered I have thought It might be usefull to some of you to have a clue on how to debug this kind of problem.
    Michel

     
  • ray2020 - 2021-02-24

    did you able to send and receive data later ?

     

Log in to post a comment.