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>
Cc: "tech-talk@aps.anl.gov" <tech-talk@aps.anl.gov>
Date: Mon, 23 Dec 2013 01:08:31 +0000
This is a follow-up post to tech-talk.  The problems with the PM600 motor have been resolved.  There were bugs in both drvPM304.cc and devPM304.cc that caused it to crash on Linux, while it previously had run fine on vxWorks.

I have committed the fixes to the APS Subversion repository.

Mark

________________________________________
From: Mark Rivers
Sent: Tuesday, December 17, 2013 8:03 AM
To: Peter Linardakis; Ron Sluiter
Cc: Torsten Bögershausen; nick.rees@diamond.ac.uk; tech-talk@aps.anl.gov
Subject: RE: Mclennan PM600 motor controller

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
>>
>>
>>
>>
>>





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
RE: Mclennan PM600 motor controller Mark Rivers

Navigate by Date:
Prev: EPICS Website and mailing lists Andrew Johnson
Next: Re: Increasing scan rate to 10 kHz Evgeniy
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 Mark Rivers
Next: Re: Mclennan PM600 motor controller Torsten Bögershausen
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 ·