Argonne National Laboratory

Experimental Physics and
Industrial Control System

1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  <20132014  2015  2016  2017  2018  2019  Index 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  <20132014  2015  2016  2017  2018  2019 
<== Date ==> <== Thread ==>

Subject: RE: Mclennan PM600 motor controller
From: Mark Rivers <rivers@cars.uchicago.edu>
To: Peter Linardakis <peter.linardakis@anu.edu.au>, Ron Sluiter <sluiter@aps.anl.gov>
Cc: "tech-talk@aps.anl.gov" <tech-talk@aps.anl.gov>
Date: Tue, 17 Dec 2013 14:03:51 +0000
Hi Peter,

I looked at your original post that contained the commands in your startup script.  I don't see any commands that set the input and output terminators.

You should set the input eos to "\r\n" and the output eos to "\r".  I know these are the correct values for the PM304, and I'm pretty sure they are also the correct values for the PM600.

drvAsynIPPortConfigure("test-se1-1", "172.16.0.108:5300")
asynOctetSetInputEos("test-se1-1", 0, "\r\n")
asynOctetSetOutputEos("test-se1-1", 0, "\r")

Mark

________________________________________
From: Peter Linardakis [peter.linardakis@anu.edu.au]
Sent: Tuesday, December 17, 2013 12:07 AM
To: Mark Rivers; Ron Sluiter
Cc: Torsten Bögershausen; nick.rees@diamond.ac.uk; tech-talk@aps.anl.gov
Subject: RE: Mclennan PM600 motor controller

Hello all

First, thank you for the assistance.  Second, today I had some success....of a sort.  With either the Ron and Torsten patch combo or Mark's patch, I can now run the IOC without it seg faulting immediately after boot.

However, it's not all good.  The motor record values don't seem to initialise correctly, and when I explicitly caput to motor.RVAL (or anything really), it seg faults.  The output from caput is:

        caput test:motor.RVAL -1000
        Old : test:motor.RVAL                0
        CA.Client.Exception...............................................
            Warning: "Virtual circuit disconnect"
            Context: "epicstestpi.control.local:5064"
            Source File: ../cac.cpp line 1214
            Current Time: Tue Dec 17 2013 15:37:13.158012820
        ..................................................................
        CA.Client.Exception...............................................
            Warning: "Virtual circuit disconnect"
            Context: "op=0, channel=test:motor.RVAL, type=DBR_TIME_LONG, count=1, ctx="epicstestpi.control.local:5064""
            Source File: ../getCopy.cpp line 92
            Current Time: Tue Dec 17 2013 15:37:13.158084304
        ..................................................................
        Read operation timed out: PV data was not read.
        New : test:motor.RVAL                0

And the IOC doesn't seem to dump a core file.  Now, the drvPM304 debug output upon IOC boot is:

        motor_init, return from pasynOctetSyncIO->connect for port test-se1-1 = 1, pasynUser=0x10fbd48
        recv_mess: card 0 flush returned no characters
        send_recv_mess: sending message to card 0, message=1OA
        send_recv_mess: card 0, response = "1OA"
        send_mess: sending message to card 0, message=1ST
        send_mess: card 0, response=1ST
        send_recv_mess: sending message to card 0, message=1ID
        send_recv_mess: card 0, response = "1ID"
        send_recv_mess: sending message to card 0, message=1ID
        send_recv_mess: card 0, response = "1ID"
        PM304 motor_init(), cntrl->model=1, cntrl->use_encoder[0]=1.
        send_recv_mess: sending message to card 0, message=1OS
        send_recv_mess: card 0, response = "1OS"
        set_status, status query, card 0, response=1OS
        send_recv_mess: sending message to card 0, message=1OA
        send_recv_mess: card 0, response = "1OA"
        set_status, position query, card 0, response=1OA
        set_status, return value=1
        motor_init: spawning motor task
        iocRun: All initialization complete

They are not the responses you'd expect from the commands 1oa and 1os.  I know the PM600 repeats the command as the first line of output and that send_recv_mess() in drvPM304.cc tries to parse this out via (I think?!):

        if (cntrl->model == MODEL_PM600) {
               pos = strchr(response, '\r');
               if (pos != NULL) {
                   strcpy(temp, pos+1);
                   strcpy(response, temp);
               }
            }

I inserted additional debug messages within this code and it does get into the first "if" statement (it knows it's a PM600), but it doesn't get into the second "if" statement.  It's been a very long time since I have written anything in C, so I'm hesitant to mess around too much.

Using the asynRecord  and sending "1os", results in

        asynmotor.TINP                 1os\\r\\n01:0           \\r\\n

I don't know if this matches what is expected by drvPM304.cc

Regards
Peter

-----Original Message-----
From: Mark Rivers [mailto:rivers@cars.uchicago.edu]
Sent: Tuesday, 17 December 2013 3:56 PM
To: Ron Sluiter
Cc: Torsten Bögershausen; Peter Linardakis; nick.rees@diamond.ac.uk; tech-talk@aps.anl.gov
Subject: RE: Mclennan PM600 motor controller

Peter,

Here's a patch that does not involve epicsStrDup or free:

corvette:motor/motorApp/MclennanSrc>svn diff
Index: drvPM304.cc
===================================================================
--- drvPM304.cc (revision 16975)
+++ drvPM304.cc (working copy)
@@ -356,6 +356,7 @@
 {
     char *p, *tok_save;
     char response[BUFF_SIZE];
+    char temp[BUFF_SIZE];
     struct PM304controller *cntrl;
     size_t nwrite, nread;
     int eomReason;
@@ -372,7 +373,8 @@
     /* Device support can send us multiple commands separated with ';'
      * characters.  The PM304 cannot handle more than 1 command on a line
      * so send them separately */
-    for (p = epicsStrtok_r((char *) com, ";", &tok_save);
+    strcpy(temp, com);
+    for (p = epicsStrtok_r(temp, ";", &tok_save);
                 ((p != NULL) && (strlen(p) != 0));
                 p = epicsStrtok_r(NULL, ";", &tok_save)) {
         Debug(2, "send_mess: sending message to card %d, message=%s\n", card, p); @@ -487,7 +489,8 @@
     /* Device support can send us multiple commands separated with ';'
      * characters.  The PM304 cannot handle more than 1 command on a line
      * so send them separately */
-    for (p = epicsStrtok_r((char *) out, ";", &tok_save);
+    strcpy(temp, out);
+    for (p = epicsStrtok_r(temp, ";", &tok_save);
                 ((p != NULL) && (strlen(p) != 0));
                 p = epicsStrtok_r(NULL, ";", &tok_save)) {
         Debug(2, "send_recv_mess: sending message to card %d, message=%s\n", card, p);


Please let me know if it fixes the problem, and if so I will commit it to Subversion.

Mark

________________________________________
From: Ron Sluiter [sluiter@aps.anl.gov]
Sent: Monday, December 16, 2013 3:51 PM
To: Mark Rivers
Cc: Torsten Bögershausen; Peter Linardakis; nick.rees@diamond.ac.uk; tech-talk@aps.anl.gov
Subject: Re: Mclennan PM600 motor controller

Hello Mark,

I was able to recreate a problem (I presume it is "the" problem) that is along the same line that Torsten points to. More specifically, motor_init() in drvPM304.cc makes this call when it tests for the presence of the device,

> send_recv_mess(card_index, "1OA;", buff);

send_recv_mess() then calls epicsStrtok_r() with a pointer to the above "1OA;" string.  This call to
epicsStrtok_r() is, I believe, what is causing the crash Peter is experiencing.

I suggest that both Torsten's patch to send_mess() and the following patch to send_recv_mess() are needed;

> Index: drvPM304.cc
> ===================================================================
> --- drvPM304.cc (revision 16681)
> +++ drvPM304.cc (working copy)
> @@ -484,10 +484,12 @@
>
>      cntrl = (struct PM304controller *)
> motor_state[card]->DevicePrivate;
>
> +    strcpy(temp, out);
> +
>      /* Device support can send us multiple commands separated with ';'
>       * characters.  The PM304 cannot handle more than 1 command on a line
>       * so send them separately */
> -    for (p = epicsStrtok_r((char *) out, ";", &tok_save);
> +    for (p = epicsStrtok_r((char *) temp, ";", &tok_save);
>                  ((p != NULL) && (strlen(p) != 0));
>                  p = epicsStrtok_r(NULL, ";", &tok_save)) {
>          Debug(2, "send_recv_mess: sending message to card %d,
> message=%s\n", card, p);

Hope this helps,
Ron

On 12/16/2013 8:04 AM, Mark Rivers wrote:
> Peter,
>
> I suspect Torsten has found the problem.  "com" was declared "const char *", but it is being cast to "char *" when passed to epicsStrtok_r, which modifies the string.  Some compilers put const data into memory blocks that are read-only, and this could cause your crash.  I have definitely seen this with the Visual Studio compilers, (incorrect) code that ran OK on Linux would crash on Windows.
>
> Mark
>
> ________________________________________
> From: Torsten Bögershausen [torsten.bogershausen@esss.se]
> Sent: Monday, December 16, 2013 2:51 AM
> To: Peter Linardakis; Mark Rivers; nick.rees@diamond.ac.uk;
> tech-talk@aps.anl.gov
> Subject: Re: Mclennan PM600 motor controller
>
> Peter, does the following help:
>
>
> diff --git a/motorApp/MclennanSrc/drvPM304.cc
> b/motorApp/MclennanSrc/drvPM304.cc
> index e703082..3b15757 100644
> --- a/motorApp/MclennanSrc/drvPM304.cc
> +++ b/motorApp/MclennanSrc/drvPM304.cc
> @@ -352,8 +352,9 @@ STATIC int set_status(int card, int signal)
>    /* ring buffer                                       */
>    /* send_mess()                                       */
>    /*****************************************************/
> -STATIC RTN_STATUS send_mess(int card, const char *com, char *name)
> +STATIC RTN_STATUS send_mess(int card, const char *com0, char *name)
>    {
> +    char *com = NULL;
>        char *p, *tok_save;
>        char response[BUFF_SIZE];
>        struct PM304controller *cntrl;
> @@ -367,12 +368,13 @@ STATIC RTN_STATUS send_mess(int card, const char *com, char *name)
>        return(ERROR);
>        }
>
> +    com = strdup(com0);
>        cntrl = (struct PM304controller *)
> motor_state[card]->DevicePrivate;
>
>        /* Device support can send us multiple commands separated with ';'
>         * characters.  The PM304 cannot handle more than 1 command on a line
>         * so send them separately */
> -    for (p = epicsStrtok_r((char *) com, ";", &tok_save);
> +    for (p = epicsStrtok_r(com, ";", &tok_save);
>                    ((p != NULL) && (strlen(p) != 0));
>                    p = epicsStrtok_r(NULL, ";", &tok_save)) {
>            Debug(2, "send_mess: sending message to card %d,
> message=%s\n", card, p); @@ -381,6 +383,7 @@ STATIC RTN_STATUS send_mess(int card, const char *com, char *name)
>            Debug(2, "send_mess: card %d, response=%s\n", card, response);
>        }
>
> +    free(com);
>        return(OK);
>    }
>
>
>
> On 12/13/13 3:54 AM, Peter Linardakis wrote:
>> Hi Mark
>>
>> By including asynSetTraceMask("test-se1-1",0,255) in st.cmd, between boot and seg fault we get:
>>
>>        ...
>>        2013/12/13 01:56:21.420 test-se1-1 asynManager::queueLockPort locking port
>>        2013/12/13 01:56:21.423 test-se1-1 asynManager::queueLockPort created queueLockPortPvt=0x289718
>>        2013/12/13 01:56:21.426 test-se1-1 asynManager::queueLockPort created queueLockPortPvt=0x289718, event=0x28ee98, mutex=0x28ef10
>>        2013/12/13 01:56:21.428 test-se1-1 asynManager::queueLockPort taking mutex 0x28ef10
>>        2013/12/13 01:56:21.430 test-se1-1 asynManager::queueLockPort queueing request
>>        2013/12/13 01:56:21.431 test-se1-1 addr -1 queueRequest priority 0 not lockHolder
>>        2013/12/13 01:56:21.432 asynManager::portThread port=test-se1-1 callback
>>        2013/12/13 01:56:21.434 test-se1-1 asynManager::queueLockPortCallback signaling begin event
>>        2013/12/13 01:56:21.435 test-se1-1 asynManager::queueLockPortCallback waiting for mutex from queueUnlockPort
>>        2013/12/13 01:56:21.436 test-se1-1 asynManager::queueLockPort waiting for event
>>        2013/12/13 01:56:21.437 test-se1-1 asynManager::queueLockPort got event from callback
>>        2013/12/13 01:56:21.438 test-se1-1 flush
>>        2013/12/13 01:56:21.439 172.16.0.108:5300 flush
>>        2013/12/13 01:56:21.440 asynOctetSyncIO flush
>>        2013/12/13 01:56:21.441 test-se1-1 queueUnlockPort
>>        2013/12/13 01:56:21.442 test-se1-1 asynManager::queueUnlockPort waiting for event
>>        2013/12/13 01:56:21.443 test-se1-1 queueUnlockPort unlock mutex 0x28ef10 complete.
>>        2013/12/13 01:56:21.445 test-se1-1 asynManager::queueLockPort locking port
>>        2013/12/13 01:56:21.445 test-se1-1 asynManager::queueLockPort taking mutex 0x28ef10
>>        2013/12/13 01:56:21.446 test-se1-1 asynManager::queueLockPort queueing request
>>        2013/12/13 01:56:21.447 test-se1-1 addr -1 queueRequest priority 0 not lockHolder
>>        2013/12/13 01:56:21.448 asynManager::portThread port=test-se1-1 callback
>>        2013/12/13 01:56:21.449 test-se1-1 asynManager::queueLockPortCallback signaling begin event
>>        2013/12/13 01:56:21.450 test-se1-1 asynManager::queueLockPortCallback waiting for mutex from queueUnlockPort
>>        2013/12/13 01:56:21.451 test-se1-1 asynManager::queueLockPort waiting for event
>>        2013/12/13 01:56:21.452 test-se1-1 asynManager::queueLockPort got event from callback
>>        2013/12/13 01:56:21.453 172.16.0.108:5300 read.
>>        2013/12/13 01:56:21.455 test-se1-1 queueUnlockPort
>>        2013/12/13 01:56:21.456 test-se1-1 asynManager::queueUnlockPort waiting for event
>>        2013/12/13 01:56:21.458 test-se1-1 queueUnlockPort unlock mutex 0x28ef10 complete.
>>
>> and the gdb backtrace is:
>>
>>        ...
>>        Core was generated by `../../bin/linux-arm/pitest st.cmd'.
>>        Program terminated with signal 11, Segmentation fault.
>>        #0  0xb6d649d4 in epicsStrtok_r () from /opt/epics/base/lib/linux-arm/libCom.so
>>        (gdb) backtrace
>>        #0  0xb6d649d4 in epicsStrtok_r () from /opt/epics/base/lib/linux-arm/libCom.so
>>        #1  0xb6eb4bb0 in send_recv_mess(int, char const*, char*) () from /opt/epics/modules/motorR6-8/lib/linux-arm/libMclennan.so
>>        #2  0xb6eb5218 in motor_init() () from /opt/epics/modules/motorR6-8/lib/linux-arm/libMclennan.so
>>        #3  0xb6eb49dc in PM304_init(void*) () from /opt/epics/modules/motorR6-8/lib/linux-arm/libMclennan.so
>>        #4  0xb6de26d0 in dbInitDevSup () from /opt/epics/base/lib/linux-arm/libdbStaticIoc.so
>>        #5  0xb6e7af8c in iocBuild () from /opt/epics/base/lib/linux-arm/libmiscIoc.so
>>        #6  0xb6e7b52c in iocInit () from /opt/epics/base/lib/linux-arm/libmiscIoc.so
>>        #7  0xb6d5ef78 in iocshBody () from /opt/epics/base/lib/linux-arm/libCom.so
>>        #8  0x0000bcc4 in main ()
>>
>> As far as the dbior command goes, I assume you meant commenting out the database that contains the motor record?  If that's the case, the it seg faults before I get to a prompt, as it normally does and the backtrace is the same as above.
>>
>> Regards
>> Peter
>>
>> -----Original Message-----
>> From: Mark Rivers [mailto:rivers@cars.uchicago.edu]
>> Sent: Friday, 13 December 2013 11:14 AM
>> To: Peter Linardakis; nick.rees@diamond.ac.uk; tech-talk@aps.anl.gov
>> Subject: RE: Mclennan PM600 motor controller
>>
>> Hi Peter,
>>
>>> I had this nagging suspicion that I should indeed be basing my
>>> record on motor.db, but was confused from the motorR6-8 README file saying that serial devices needed asyn4-2.  Live and learn I guess.
>> Your confusion is understandable.  There are actually 2 layers in the motor software that use asyn.
>>
>> 1) The interface between the motor driver and message based interfaces like RS-232, GPIB, and TCP/IP.  The motor drivers always use asyn for this layer, even the old Model 1 drivers.
>>
>> 2) The interface between motor record device support and the motor driver.  Only Model 2 and Model 3 drivers use asyn in this layer.
>>
>>> I changed the PM304Config(0, "test-se1-1", 1) line from
>>> PM304Config(1, "test-se1-1", 1), since I assumed from the "#C0 S0" syntax that if I only have one card, then it must be card 0.
>>> In this case, the IOC seg faults immediately after boot.
>> The correct command is card 0, as you did.
>>
>> These are the command in my startup script:
>> ##############################
>> # PM304 driver setup parameters:
>> #     (1) maximum # of controllers,
>> #     (2) motor task polling rate (min=1Hz, max=60Hz)
>> PM304Setup(1, 10)
>> # PM304 driver configuration parameters:
>> #     (1) controller
>> #     (2) asyn port
>> #     (3) MAX axes
>> # Example:
>> #   PM304Config(0, "serial1", 1)
>> PM304Config(0, "serial9", 1)
>> ##############################
>>
>> So now we need to figure out why it is segfaulting for you.
>>
>> Your startup script has these lines:
>>
>> drvAsynIPPortConfigure("test-se1-1", "172.16.0.108:5300") # Add these
>> lines for asynTrace debugging
>> asynSetTraceIOMask("test-se1-1",0,2)
>> asynSetTraceMask("test-se1-1",0,9)
>>
>> The last line is turning on ASYN_TRACEIO_DRIVER for the TCP driver.  So you should see messages for every write and read operation to the device.  Do you see any such I/O before it crashes?  You could change the last line to:
>>
>> asynSetTraceMask("test-se1-1",0,255)
>>
>> to turn on all possible messages.
>>
>> See if you get any messages before it seg faults.
>>
>> You should also run gdb to figure out where it is crashing.  Here's how to do that:
>>
>> - Enable core dumps.  With the csh this is done with
>>
>> limit core 1000000
>>
>> With bash it is
>>
>> ulimit -c 1000000
>>
>> Now run your application so it seqfaults.  You will get a core file, core.XXXXX, where XXXXX is a number.
>>
>> Now run gdb on your application with that core file:
>>
>> gdb PATH_TO_YOUR_APPLICATION core.XXXXX
>>
>> When you get the gdb prompt type the command
>>
>> backtrace
>>
>> That should show what function was executing when it crashed.
>>
>> Here is something else to do.  Load your application, but comment out
>> the line to load the motor database.  At the IOC prompt type this
>> command
>>
>> dbior "drvPM304",10
>>
>> That should give you a report like the following:
>>
>> Driver: drvPM304
>>       PM304 controller 0, id: Mclennan Servo Supplies Ltd  PM304
>> V6.17
>>
>>
>> Mark
>>
>>
>>
>>
>>





Replies:
RE: Mclennan PM600 motor controller Mark Rivers
References:
Mclennan PM600 motor controller Peter Linardakis
RE: Mclennan PM600 motor controller Mark Rivers
RE: Mclennan PM600 motor controller Peter Linardakis
RE: Mclennan PM600 motor controller nick.rees
RE: Mclennan PM600 motor controller Mark Rivers
RE: Mclennan PM600 motor controller Peter Linardakis
RE: Mclennan PM600 motor controller Mark Rivers
RE: Mclennan PM600 motor controller Peter Linardakis
Re: Mclennan PM600 motor controller Torsten Bögershausen
RE: Mclennan PM600 motor controller Mark Rivers
Re: Mclennan PM600 motor controller Ron Sluiter
RE: Mclennan PM600 motor controller Mark Rivers
RE: Mclennan PM600 motor controller Peter Linardakis

Navigate by Date:
Prev: PIXIS pvCam and 64 bit peter.leicester
Next: RE: PIXIS pvCam and 64 bit Gebhardt, Jeffrey R.
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  <20132014  2015  2016  2017  2018  2019 
Navigate by Thread:
Prev: RE: Mclennan PM600 motor controller Peter Linardakis
Next: RE: Mclennan PM600 motor controller Mark Rivers
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  <20132014  2015  2016  2017  2018  2019 
ANJ, 20 Apr 2015 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·