EPICS Controls Argonne National Laboratory

Experimental Physics and
Industrial Control System

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

Subject: Re: writing your own stream cronverter
From: Dirk Zimoch <[email protected]>
To: Emmanuel Mayssat <[email protected]>
Cc: [email protected]
Date: Tue, 04 Dec 2007 11:57:55 +0100
Hello Emmanuel,

The return type of parse() defines the data type as seen by the record. This is not necessarily the type of the record, it is the type of the conversion.
For example, %i is long_format and %f is a double_format in stream. Both can be used with an ai record. The long value from %i goes to the RVAL field and the double value from %f goes to the VAL field. Thus, it depends on the data type of the conversion, to which field the input is passed.


Depending on the return value of parse, different versions of print and scan are used when actually processing in and out commands. By the way, parse can return different values for input and output. For example %c is a long output but a string input format. Note that stream uses long and double but but not short and float.

In your case, you want to read/write a floating point value. Thus parse returns double_format and you have to implement
bool printDouble(const StreamFormat& fmt, StreamBuffer& output, double value);
int scanDouble(const StreamFormat& fmt, const char* input, double& value);


Because the number is always coded in 4 bytes, scanDouble() always returns 4. You can handle endianess with flags. I usually assume big endian by default and use the # flag for little endian.

To read several values, you can use a waveform or aai record. The converter reads/writes only one element at a time. It is called multiple times to handle arrays. There are no array converters.

On output, your converter will be called NELM times any should write one value (4 bytes). On input, your converter will be called as long as there is input left, a maximum of NELM times, and until you return -1, whatever happens first. NORD will be set to the number of read elements. Reading at least one element is a success. You will write just set NELM of the record to 25 and use { in "%R"; } to read the complete array.

The other possibility is to use redirected input %(otherrecord.VAL)R. Then, you have to specify 25 format conversions in the protocol as in your example below. Note the capital .VAL. Using .val will not work because the record has no .val field. You can use parametres like \$1 \$2 ... \$9 to keep the record names, or at least parts of the record names, out of the protocol file. But there are only 9 parameters. Thus you would use something like:

in "%(\$1:status1.VAL)R%(\$1:status2.VAL)R...%(\$1:status24.VAL)R%R";

record(ai, "$(DEVICE):status1")
{
}

...

record(ai, "$(DEVICE):status24")
{
}

record(ai, "$(DEVICE):status25")
{
  field (DTYP, "stream")
  field (INP, "@file getStatus($(DEVICE)) $(BUS)")
}

Unfortunately, you will find errors only in status25, because that's the record that processes the protocol.

In either case, the converter does not know about arrays. It always handles one value at a time.

Dirk

Emmanuel Mayssat wrote:
Dirk, others,

I am trying to write a new converter.
That converter is almost like the RawConvert except:
* the bit order and meaning are the same a C float ( sign + mantissa +
exponent )
* the content is coded on 4 bytes
* Width is not meaningful, big/small endian may be
* Several values should be extracted from the same reply ( 25 ai ). So
devaiStream does not work.


I looked at the existing converter.
A converter has 3 methods parse, print, read/scan.
Parse returns a type (long, double, string, etc.), what is this type
referring to? The input (4*8 bits), the value (float), other ?
I understand that it is used to find the correct print/read methods but
what should it be in my case?


If Read/scan method returns the # of bytes read, I should be forced to 4
in my case? Is the return value always the number of bytes?

I want to assign the values of several records based on the returned
message. Should I create a custom record with 25 additional fields when
compared to ai and then soft link them to other AI. Is there a way to
use devaiStream and directly populate the 25 records?


getStatus {
out "GET STATUS"
in  "%(record1.val)R%(record2.val)R%(record3.val)R"
}

Thanks,

--
Emmanuel



-- Dr. Dirk Zimoch Paul Scherrer Institut, WBGB/006 5232 Villigen PSI, Switzerland Phone +41 56 310 5182

References:
writing your own stream cronverter Emmanuel Mayssat

Navigate by Date:
Prev: I want to unsubscribe from tech-talk Aravamuthan Govindan
Next: Multiple IOC Robert Emery
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  <20072008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
Navigate by Thread:
Prev: Re: Stream protocol configuration Dirk Zimoch
Next: device support for output connected to volatile device John Dobbins
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  <20072008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
ANJ, 10 Nov 2011 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·