How can I add code to a libnodave test program (testISO_TCP simplified) that protects the read routine from crashing?

StackOverflow https://stackoverflow.com/questions/7046127

  •  20-12-2020
  •  | 
  •  

Question

I will start by saying that I am a college student with little c++ experience. How many times have you heard that right? I am working with the test program testISO_TCP (simplified version) from the libnodave library. This program does a simple read of flag values and data blocks while it is connected to a seimens 300 PLC. The program doesn't bring up any errors per se. What I am trying to do is hopefully add some code to this program that will protect the reads from ever crashing. Let me explain a little better. Say for example I have a lot of reads implemented in the code. As of now there are only two reads. Eventually I will run this code with many more reads. Now, say that I am running the test program and for some reason I lose the connection to the PLC. I would like to have the program do one of two things: 1) Once the connection is lost, do a retry connect a certain amount of times and when it runs out of tries, exit. or 2) Somehow continue to read from the PLC until they are all done.

I hope this is enough information to get some help. I will post the code that I have been looking at for so long without any idea how to do this effectively. Thanks to all in advance.

#define PLAY_WITH_KEEPALIVE
#include <stdlib.h>
#include <stdio.h>
#include "nodavesimple.h"
#include "openSocket.h"


#ifdef PLAY_WITH_KEEPALIVE
#include <winsock.h>
#endif


int main(int argc, char **argv) {
    int a,b,c,res, doRun, doStop, doRead, doreadFlag, useProtocol, useSlot;
#ifdef PLAY_WITH_KEEPALIVE      
    int opt;
#endif    
    float d;
    daveInterface * di;
    daveConnection * dc;
    _daveOSserialType fds;
    doRun=0;
    doStop=0;
    doRead=0;
    doreadFlag=0;
    useProtocol=daveProtoISOTCP;
    useSlot=2;


 fds.rfd=openSocket(102, argv[1]);
    #ifdef PLAY_WITH_KEEPALIVE
    errno=0;    
    opt=1;
   //res=setsockopt(fds.rfd, SOL_SOCKET, SO_KEEPALIVE, &opt, 4);
   //LOG3("setsockopt %s %d\n", strerror(errno),res);
    #endif
 fds.wfd=fds.rfd;

    if (fds.rfd>0) 
        { 
        di =daveNewInterface(fds,"IF1",0, daveProtoISOTCP, daveSpeed187k);
        daveSetTimeout(di,5000000);
        dc =daveNewConnection(di,2,0, 2);  // insert your rack and slot here



            if (0==daveConnectPLC(dc)) 
                {
                    printf("Connected.\n");

                res=daveReadBytes(dc,daveFlags,0,0,16,NULL);
                if (0==res)  
                { 
                        a=daveGetU32(dc);
                        b=daveGetU32(dc);
                        c=daveGetU32(dc);
                        d=daveGetFloat(dc);
                    printf("FD0: %d\n",a);
                    printf("FD4: %d\n",b);
                    printf("FD8: %d\n",c);
                    printf("FD12: %f\n",d);
                }//end 0==res

                }//end daveConnectPLC


            else 

            {
        printf("Couldn't connect to PLC.\n Please make sure you use the -2 option with a CP243 but not with CPs 343 or 443.\n");    
        //closeSocket(fds.rfd);
        //return -2;
            }

    }//end fds.rfd



    fds.rfd=openSocket(102, argv[1]);
    fds.wfd=fds.rfd;

    if (fds.rfd>0) 
        { 
        di =daveNewInterface(fds,"IF1",0, daveProtoISOTCP, daveSpeed187k);
        daveSetTimeout(di,5000000);
        dc =daveNewConnection(di,2,0, 2);  // insert your rack and slot here


            if (0==daveConnectPLC(dc)) 
                {
                    printf("Connected.\n");

                res=daveReadBytes(dc,daveDB,1,0,64,NULL);
                if (0==res) 
                { 

                    a=daveGetU16(dc);
                    printf("DB1:DW0: %d\n",a);
                    a=daveGetU16(dc);
                    printf("DB1:DW1: %d\n...\n",a);
                    a=daveGetU16At(dc,62);
                    printf("DB1:DW32: %d\n",a);


                }//end 0==res

                    return 0;

                }//end daveConnectPLC
            else 

            {
        printf("Couldn't connect to PLC.\n Please make sure you use the -2 option with a CP243 but not with CPs 343 or 443.\n");    
        closeSocket(fds.rfd);
        return -2;
            }

    }//end fds.rfd






    else 
    {
    printf("Couldn't open TCP port. \nPlease make sure a CP is connected and the IP address is ok. \n");    
        return -1;
    }    



}// end main
Was it helpful?

Solution

You have to check the return value of the daveReadBytes function. If it is not zero, something went wrong and you can use the daveStrerror function to get a proper error message:

printf ("error: %s\n", daveStrerror(res));

After that it's up to you to decide to either simply retry the read or disconnect (with closeSocket(...)) and then create a new connection from the beginning. Check the documentation on what errorcodes there are. Some errors can't be resolved by retrying (e.g. because you try reading a data block that doesn't exist).

OTHER TIPS

I have a loop that attempts to connect 3 times and exits gracefully if it fails You may be able to write some other code to first check to see if the connection is up and also if the PLC is up. Typically if you try to connect to an IP address that doesn't esond; it will hang there and tie up resources...

I am also new programmer.But want to say that. First we have to differentiate between the TCP/IP connection with the ethernet card ISO_TCP. The openSocket() function does the connection to remote IP adress in the given port/Service (102 ISO_TCP). When called next, the function daveNewInterface(), it will initialise the specific interface for doing a connection to the PLC. After this, the function daveNewConnection() tries to open a connection on a given MPI adress, and very important, the given rack and slot. If this function returns the value 0, it will call the daveConnectPLC() function to connect to the PLC. At this point it´s established a ethernet connection,and also the PLC Connection. Now you can use all the function from the libnodave library for read or write data, stop or run the PLC and much more.

In the actually simplified TCP_ISO code there are no function to disconnect the adapter or close the connection with the PLC, in your code there is the closeSocket() function and also the function that returns -2. Find at what line the code breaks, introducing for example a log after every function to see the returns values.

All info for detecting loss of communication is in the documentation.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top