EPICS Controls 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  <20102011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024  Index 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  <20102011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
<== Date ==> <== Thread ==>

Subject: Re: Patch to subArray record
From: Andrew Johnson <[email protected]>
To: [email protected]
Date: Fri, 12 Nov 2010 15:22:21 -0500
Hi Michael,

There are 3 record support routines that deal with information about array 
fields for the dbAccess routines:

* cvt_dbaddr(*paddr) is called during channel lookup, and is responsible for 
describing the array; the paddr->no_elements field must be set to the maximum 
number of elements that can ever be stored in the array's buffer.  CA uses 
that as the native size of the channel; I have no idea what might happen if 
you later tell it that the array is bigger than this number.
* get_array_info(*paddr, *no_elements, *offset) is called at the start of a 
get operation to find out the current size of the array, and if it's a 
circular buffer what the current offset is to the origin.
* put_array_info(*paddr, nNew) is called *after* dbAccess has written new data 
to the array, to update the array size.

During a put operation dbAccess relies on the information it got from the 
connection-time call to cvt_dbaddr() to tell it how many elements it may copy 
into the array.  The dbAccess routine dbPut() does not communicate with the 
record before directly overwriting the array buffer, using the information in 
its dbAddr structure.  It only calls put_array_info() to set the data size 
after writing the data.  If the dbAddr says the array size is zero, dbPut() 
will only write one element.

On Friday 12 November 2010 04:25:32 Michael Abbott wrote:
>
> Unfortunately patch [email protected]
> changes the length reported by subArray to return MALM.  Looking at this
> patch I suspect this was an oversight, but one that hasn't been noticed
> for three years!

When you say "the length reported by subArray" you are talking about the value 
returned by cvt_dbaddr().  As described above, this routine *must* return MALM 
as that's size of the array buffer and someone could later set INDX=0 and 
NELM=MALM.

> The patch below, I believe, fixes this.  cvt_dbaddr() now reports NORD as
> the true size of the available data, which makes this record type a bit
> more useful.

No, the size of the available data is returned by get_array_info(), and the 
current code for that routine correctly returns NORD, or zero if the record is 
marked as undefined.

> I discovered this change when a 4000 point record I was using to index
> into a 30000 point waveform exploded in size (and refused to update,
> because EPICS_CA_MAX_ARRAY_BYTES was not set) after upgrading from EPICS
> 3.14.8.2 to 3.14.11.

I don't quite follow what you're saying happened there, please elaborate if 
you feel I've missed something in my discussions below.

> diff --git a/src/dev/softDev/devSASoft.c b/src/dev/softDev/devSASoft.c
> index 5600ac1..32b5ad7 100644
> --- a/src/dev/softDev/devSASoft.c
> +++ b/src/dev/softDev/devSASoft.c
> @@ -81,6 +81,8 @@ static long read_sa(subArrayRecord *prec)
>          memmove(prec->bptr, (char *)prec->bptr + prec->indx * esize,
>                  ecount * esize);
>      }
> +    else
> +        prec->nord = 0;

The above change is fixing a bug, although I'm going to write it slightly 
differently so as to set NORD only once in the code I commit.  Without this 
change if the sub-array's INDX points beyond the end of the current target 
array, NORD will be set to the unsigned representation of a negative number, 
which is obviously a (big) mistake.  [Sorry, couldn't resist that one!]

> diff --git a/src/rec/subArrayRecord.c b/src/rec/subArrayRecord.c
> index 081304e..bc00d69 100644
> --- a/src/rec/subArrayRecord.c
> +++ b/src/rec/subArrayRecord.c
> @@ -168,7 +168,7 @@ static long cvt_dbaddr(DBADDR *paddr)
>      subArrayRecord *prec = (subArrayRecord *) paddr->precord;
>
>      paddr->pfield = prec->bptr;
> -    paddr->no_elements = prec->malm;
> +    paddr->no_elements = prec->nord;
>      paddr->field_type = prec->ftvl;
>      paddr->field_size = dbValueSize(prec->ftvl);
>      paddr->dbr_field_type = prec->ftvl;

This change is wrong, it's telling lies about the field, and it enables the "I 
don't know what would happen if" scenario that I described above.  It also 
prevents a DB link or a transient CA client from ever being able to write more 
than a single element to the VAL field of an empty subArray record, because 
when the link is created NORD will be zero, which the dbPut() routine takes to 
mean that it can write one element.

If a subArray's INP field is not set (prec->inp.type == CONSTANT), the record 
could be used to extract a sub-array from any data that gets put into its VAL 
field â processing the record triggers the extraction code in the device 
support's read_sa() routine.  I believe it would be useful to be able to write 
arrays into the VAL field, although unfortunately that only currently works if 
you point its INP field at a non-existent record.  That is easily fixed 
though, so in R3.14.12-pre2-DEV I can now do this:

epics> dbpr anjHost:saExample 1
ASG:                BKPT: 00            BUSY: 0             DESC:
DISA: 0             DISP: 0             DISS: NO_ALARM      DISV: 1
DTYP: Soft Channel  EGU:                EVNT: 0             FLNK:CONSTANT 0
FTVL: STRING        HOPR: 0             INDX: 2             INP:CONSTANT
LOPR: 0             MALM: 10            NAME: anjHost:saExample
NELM: 8             NORD: 0             PACT: 0             PHAS: 0
PINI: NO            PREC: 0             PRIO: LOW           PUTF: 0
RPRO: 0             SCAN: Passive       SDIS:CONSTANT       SEVR: INVALID
STAT: UDF           TPRO: 0             TSE: 0              TSEL:CONSTANT
UDF: 1              VAL: (nil)

tux% caput -a anjHost:saExample 10 1 2 3 4 5 6 7 8 9 10
Old : anjHost:saExample 10
New : anjHost:saExample 10 3 4 5 6 7 8 9 10
tux% caput -t anjHost:saExample.PROC 1
1
tux% caget anjHost:saExample
anjHost:saExample 10 5 6 7 8 9 10
tux% caput -t anjHost:saExample.PROC 1
1
tux% caget anjHost:saExample
anjHost:saExample 10 7 8 9 10
tux% caput -t anjHost:saExample.PROC 1
1
tux% caget anjHost:saExample
anjHost:saExample 10 9 10
tux% caput -t anjHost:saExample.PROC 1
1
tux% caget anjHost:saExample
anjHost:saExample 10

epics> dbpr anjHost:saExample
ASG:                BUSY: 0             DESC:               DISA: 0
DISP: 0             DISV: 1             INDX: 2
NAME: anjHost:saExample                 NELM: 8             NORD: 0
SEVR: INVALID       STAT: UDF           TPRO: 0             VAL: (nil)

Interestingly you could use this to feed a series of values into some other 
record in order; just set INDX=1 and NELM=MALM and have your other record read 
the first element of the VAL field each time.  This has lots of related 
possibilities.


> @@ -180,10 +180,7 @@ static long get_array_info(DBADDR *paddr, long
> *no_elements, long *offset) {
>      subArrayRecord *prec = (subArrayRecord *) paddr->precord;
>
> -    if (prec->udf)
> -       *no_elements = 0;
> -    else
> -       *no_elements = prec->nord;
> +    *no_elements = prec->nord;
>      *offset = 0;
>
>      return 0;

Why would you want an undefined array to be able to report that it contains 
data?  That's what this change would do.


> @@ -194,9 +191,8 @@ static long put_array_info(DBADDR *paddr, long nNew)
>      subArrayRecord *prec = (subArrayRecord *) paddr->precord;
>
>      if (nNew > prec->malm)
> -       prec->nord = prec->malm;
> -    else
> -       prec->nord = nNew;
> +        nNew = prec->malm;
> +    prec->nord = nNew;
>
>      return 0;
>  }

This change doesn't alter the functionality, but I will commit it anyway.

Thanks for the report and patch,

- Andrew
-- 
If a man is offered a fact which goes against his instincts, he will
scrutinize it closely, and unless the evidence is overwhelming, he will
refuse to believe it.  If, on the other hand, he is offered something
which affords a reason for acting in accordance to his instincts, he
will accept it even on the slightest evidence.  -- Bertrand Russell



References:
Patch to subArray record Michael Abbott

Navigate by Date:
Prev: Re: MDrive - a novice in trouble Ron Sluiter
Next: RE: MDrive - a novice in trouble Mark Rivers
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  <20102011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
Navigate by Thread:
Prev: Patch to subArray record Michael Abbott
Next: hex format convert to a specified length Damek Yahto
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  <20102011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
ANJ, 15 Nov 2010 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·