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

Subject: Re: Asyn or Stream device interface for struct data
From: Zimoch Dirk via Tech-talk <tech-talk at aps.anl.gov>
To: "Abdalla.Ahmad at sesame.org.jo" <Abdalla.Ahmad at sesame.org.jo>
Cc: "Tech-talk at aps.anl.gov" <Tech-talk at aps.anl.gov>
Date: Thu, 5 Sep 2024 10:13:17 +0000
Hi Abdalla

First the question of format: Are your structure fields in big endian or little
endian byte order? Are there any gaps in the structure for alignment?

In case of big endian unaligned fields you can for example use:

MaxInput = 10;
command1 {
    out 0x00 0x00 0x00 0x01 0x00 0x0a 0x00 0x00 0x00 0x00;
    in "%(\$1:STATUS)02r" 0x00 0x01 0x00 0x0a "%04r";
}

field(INP, "@$(PROTOCOLFILE) command1($(DEVICE)) $(PORT)")

This will send a fixed request, wait for the reply, put status into the *:STATUS
record and keep data for itself.

Assuming you use addresses up to 0xff only, you can pass the address low byte as
argument 2 and use a fixed 0x00 high byte:

command1 {
    out 0x00 0x00 0x00 0x01 0x00 $2 0x00 0x00 0x00 0x00;
    in "%(\$1:STATUS)02r" 0x00 0x01 0x00 $2 "%04r";
}

field(INP, "@$(PROTOCOLFILE) command1($(DEVICE),0xa) $(PORT)")

Unfortunately you cannot format protocol arguments at the moment. So if for
example you wanted to pass a 16 bit address like 0x1234 and format it with %.2r
like this: "%(\$2).2r", that will not work. It would try to find a record with
the name "0x1234" to take the value from. I may change that in the future,
assuming that record names and field names never start with digits.


BTW: If you want to invalidate your record if status is not 0000, you can use
this:
command1 {
    out 0x00 0x00 0x00 0x01 0x00 $2 0x00 0x00 0x00 0x00;
    in 0x00 0x00 0x00 0x01 0x00 $2 "%04r";
  @mismatch {    
    in "%(\$1:STATUS)02r" 0x00 0x01 0x00 $2 "%04r";
  }
}

The normal 'in' will fail if status is not 0x0000, which will set SEVR to
INVALID and STAT to CALC. But then it will execute @mismatch, re-parse the input
and store the status in the other record and read the (invalid) data for itself.

Thus you will end up with either the record containing a valid value and
unfortunately the STATUS record unchanged or with the record in INVALID/CALC
alarm state (but still containing the received value) and the STATUS record
updated.

Dirk


On Thu, 2024-09-05 at 09:27 +0000, Abdalla Ahmad wrote:
> Hello Dirk
>  
> Thank you very much that was helpful. As an example let’s assume we want to read the value of address 10, we send a packet with the following:
> Status = 0x0
> Command = 0x1
> Address = 0xa
> Data = 0x0
>  
> And we receive the same packet but with status filled by the device and the actual data is in the data field. So all the packets’ fields are constants and need not to be passed as a protocol argument. How to do it in this way? Also, if I want to use protocol arguments, is it possible to format the argument?
>  
> Best Regards,
> Abdalla.
>  
> From: Zimoch Dirk <dirk.zimoch at psi.ch> 
> Sent: Thursday, September 5, 2024 11:59 AM
> To: Abdalla Ahmad <Abdalla.Ahmad at sesame.org.jo>
> Cc: tech-talk at aps.anl.gov
> Subject: Re: Asyn or Stream device interface for struct data
>  
> Hello Abdalla
>  
> Yes, you can do this using the %r format together with redirection in order to split the values into 4 records or combing the data from them. As your communication does not use terminators but has a fixed data size, use MaxInput.
> You need to know how the exact struct layout will look like on the network, in particular what the byte order is and if there will be "gaps" due to alignment. The compiler will probably add 2 bytes gap before u32 data when mapping this structure to memory in order to align the u32.
>  
> Without any gaps:
>  
> MaxInput = 10; # total struct size
> read {
>    in "%(\$1:STATUS)02r%(\$1:COMAND)02r%(\$1:ADDRESS)%04r";
> }
> The 0 prefix in %()02r handles the value as unsigned, so that e.g. 0xf000 is not expanded to a negative record value. 
> I assume here that the data is in big endian byte order. If you have little endian byte order, use the # modifier: %()#02r.
> The "\$1" is the first argument to the protocol. Pass the "basename" of your records like this:
>  
> record (longin, "$(DEVICE):DATA") {
>     field(DTYP, "stream")
>     field(INP, "@$(PROTOCOLFILE) read($(DEVICE)) $(PORT)")
> }
>  
> record(longin "$(DEVICE):STATUS) {
> # the 'status' field will be put here by the read protocol
> }
>  
> Maybe you want to use a constant address instead of having it in a record. Pass it as a second parameter:
>    field(INP, "@$(PROTOCOLFILE) read($(DEVICE),$(ADDRESS)) $(PORT)")
> and then reference it as $2 You need to pass the 16 byte address  as 2 bytes like "00 01" (or maybe only use 1 byte and have a for example fixed 00 upper byte):
>     in "%(\$1:STATUS)02r%(\$1:COMAND)02r" $2 "%04r";
>  
> Also the command may be fixed. Either pass it as a third argument or have different protocols for different commands:
>  
> commandABCD {
>     in "%(\$1:STATUS)02r" AB CD $2 "%04r";
> }
>  
> This way multiple input records may wait for input with "I/O Intr" scanning and select the matching command (if the device sends on it own without being asked). Or if you have the send a request first and use the command (and address) in both, the out and the in command, the in command will check that it actually gets the correct address.
>  
> I am speculating a lot how your protocol actually works. Give me more details if you need a detailed advice.
>  
> Dirk
>  
> 
> 
> > On 5 Sep 2024, at 09:33, Abdalla Ahmad via Tech-talk <Tech-talk at aps.anl.gov> wrote:
> >  
> > Hi
> >  
> > We have a device that I am working on a device support for using asynPortDriver, but its interface is very simple, it is basically a simple C struct used for both TX and RX. Something like this:
> >  
> > typedef struct {
> >      u16 status,
> >      u16 command,
> >      u16 address,
> >      u32 data
> > } packet_t;
> >  
> > I send this packet and I receive the same packet in the response with the corresponding data. Can such a communication interface be achieved using stream device or asyn support?
> >  
> > Best Regards,
> > Abdalla.
> 
>  

References:
Asyn or Stream device interface for struct data Abdalla Ahmad via Tech-talk
Re: Asyn or Stream device interface for struct data Zimoch Dirk via Tech-talk
RE: Asyn or Stream device interface for struct data Abdalla Ahmad via Tech-talk

Navigate by Date:
Prev: Re: iSeghal queue overflow Florian Feldbauer via Tech-talk
Next: Re: areaDetector Overlay problem Mark Rivers via Tech-talk
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  <20242025 
Navigate by Thread:
Prev: RE: Asyn or Stream device interface for struct data Abdalla Ahmad via Tech-talk
Next: iSeghal queue overflow Marco Filho via Tech-talk
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  <20242025 
ANJ, 11 Sep 2024 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions ·
· Download · Search · IRMIS · Talk · Documents · Links · Licensing ·