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  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 
<== Date ==> <== Thread ==>

Subject: Conversion problem from double to 32 bit unsigned int (in ao)
From: Dirk Zimoch <dirk.zimoch@psi.ch>
To: EPICS <tech-talk@aps.anl.gov>
Date: Wed, 10 Apr 2013 10:20:34 +0200
Hi folks,

Today I found a strange problem. I have a device that has 32 bit unsigned int output registers. I want to scale an analog value (e.g. -10.0 .. +10.0) to the raw range 0x00000000 ... 0xffffffff. The special_linconv() function of the ao record sets ESLO and EOFF correctly (ESLO=20/4294967295=4.65661287416E-09, EOFF=-10.0). All negative values work but any positive value gives wrong results. Even worse, the results are different on different machines: 0x80000000 on linux-x86, 0x7fffffff on vxworks-ppc604 for all positive values.

What happens? In the convert() function the analog (double) value is converted to epicsInt32 (type of the RVAL field). However if the double value is too large for the integer, strange and obviously implementation dependent things happen. I cannot find anything about this case in K&R.

Strictly speaking one can argue that it is illegal to convert a double to an int if it is too large. But there is hardware that wants 32 bit unsigned integer raw values.

I suggest to modify the convert function as follows:

diff -u -r1.1.1.1 aoRecord.c
--- src/rec/aoRecord.c  29 Nov 2010 10:38:07 -0000      1.1.1.1
+++ src/rec/aoRecord.c  10 Apr 2013 07:30:08 -0000
@@ -469,7 +469,7 @@
     value -= prec->aoff;
     if (prec->aslo != 0) value /= prec->aslo;
     if (value >= 0.0)
-        prec->rval = (epicsInt32)(value + 0.5) - prec->roff;
+        prec->rval = (epicsUInt32)(value + 0.5) - prec->roff;
     else
         prec->rval = (epicsInt32)(value - 0.5) - prec->roff;
 }

I.e using unsigned integer conversion for positive values. This changes nothing for any values < 0x7fffffff and gives a useful result for positive values >= 0x80000000.

The same thing can happen at other locations, too.
Example:

record (mbbo, "DZ:mbbo") {
    field (FLNK, "DZ:calcout")
}
record (calcout, "DZ:calcout") {
    field (INPA, "DZ:mbbo")
    field (CALC, "A*65536")
    field (OUT,  "DZ:longout PP")
}
record (longout, "DZ:longout") {
}

Writing 0xffff to the mbbo results in 0x8000000 on my 32 bit Linux PC.

field (CALC, "A<<16") on the other hand gives the expected result 0xffff0000.

The ai record is more tricky because 0x80000000 may mean a positive unsigned or a negative signed value. I am not sure how to deal with this (and the initialization of the ao record).

Dirk






Replies:
Re: Conversion problem from double to 32 bit unsigned int (in ao) Benjamin Franksen
Re: Conversion problem from double to 32 bit unsigned int (in ao) Andrew Johnson

Navigate by Date:
Prev: RE: linux file search from Asyn nick.rees
Next: Re: macLib: macro PORT is undefined Alan Greer
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 
Navigate by Thread:
Prev: Re: macLib: macro PORT is undefined Alan Greer
Next: Re: Conversion problem from double to 32 bit unsigned int (in ao) Benjamin Franksen
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 
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 ·