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

Subject: Re: C++ multi threaded application.
From: "Giacomo S." <giacomo.strangolino@elettra.eu>
To: Andrew Johnson <anj@aps.anl.gov>, tech-talk@aps.anl.gov
Date: Wed, 6 Sep 2017 10:02:32 +0200
Good morning Andrew! Wow, your support is great! Thanks a lot!

On 09/05/2017 06:58 PM, Andrew Johnson wrote:
> Hi Giacomo,
>
> On 09/05/2017 10:01 AM, Giacomo S. wrote:
>> So, summing up, suppose to recreate this scenario:
>>
>> - application starts
>> --> client requests monitoring of  pv1 = foo:ai1
>>
>> - (first request, so)   ca_context_create(ca_enable_preemptive_callback)
>>
>> - ca_create_channel (...)
>>
>> - (in  connection_handler invoked from EPICS foo thread: ) 
>> ca_create_subscription(...)
> A note: You are allowed to subscribe to channels using a different
> request data type than their native type, and the IOC will do its best
> to convert the data for you. I don't completely understand how your
> connection_handler() method transforms the native type, but I just
> wanted to make that point for later on...

Hmm actually just as a starting point, I took the code from camonitor,

ppv->dbfType = ca_field_type(ppv->ch_id);
ppv->dbrType = dbf_type_to_DBR_TIME(ppv->dbfType); /* Use native type */


where dbf_type_to_DBR_TIME is a macro so defined:

#define dbf_type_to_DBR_TIME(type)  \
    (((type) >= 0 && (type) <= dbf_text_dim-3) ? \
        (type) + 2*(dbf_text_dim-2)   :  -1  )

Of course at this early stage I don't understand it.

I've had a look in the source code but I got lost between what is called
new/old db/channel and so on...

// example where I got lost:

// #define dbChannelExportCAType(pChan)
(dbDBRnewToDBRold[dbChannelExportType(pChan)])


So, probably it's safe to remove dbf_type_to_DBR_TIME, but in that case
what's the difference between
dbR type and dbF type?

one more question follows below...

>> [ monitors for a while, receive event callbacks from EPICS foo thread]
>>
>> --> client requests pv2  = foo:ai2
>>
>>  - ca_create_channel (...)
>>
>> - (in  connection_handler invoked from EPICS foo thread: ) 
>> ca_create_subscription(...)
>>
>>
>> ---> network goes down
>>
>> - (in pv1 connection callback invoked from EPICS foo thread:)  1. 
>> ca_clear_subscription()   BUT NOT ca_clear_channel()
> Here's where Michael and I have slightly differing opinions: I wouldn't
> necessarily clear the subscription when the connection goes down,
> especially if I'm not relying on the native data type of the channel to
> select what type I subscribe with. CA will remember the original
> subscription and will reconnect it to the IOC when it comes back. In
> connection_handler() you were already storing the fact that you have
> already subscribed, so that code wouldn't create multiple subscriptions.
>
> One issue that you do have to be careful of though is if an IOC gets
> rebooted with a modified database so the data type of a channel you were
> subscribed to changes between the connection going down and coming back
> up. In this case CA subscriptions will reconnect using the type in their
> original subscription request, which might now be different to the
> native type of the channel. The client code has to be aware of that and
> use the type information from the data update callback.

If the data type on the IOC (server) has changed, shouldn't this change
reflect into the client?
I mean, if on the server (IOC) side a double type becomes an integer,
the client should change, right?

>
> Michael's approach of clearing subscriptions at disconnect is probably
> safer, but requires the application code to do a bit more work, as
> evidenced by the additional calls to ca_create_subscription() below. The
> difference is really a matter of opinion.
>
>> - (in pv2 connection callback invoked from EPICS foo thread:)  1. 
>> ca_clear_subscription()      BUT NOT   ca_clear_channel()
>>
>> ---> network UP again
>>
>>
>> - (in pv1 connection callback invoked from EPICS foo thread:)  1. 
>> ca_create_subscription() 
>>
>> - (in pv2 connection callback invoked from EPICS foo thread:)  1. 
>> ca_create_subscription()  
>>
>> ---> client requests pv3  = bar:ai3
>>
>>  - ca_create_channel (...)
>>
>> - (in  connection_handler invoked from EPICS >>> bar <<<  thread: ) 
>> ca_create_subscription(...)   <--- bar THREAD <----
>>
>> [ receive event callbacks from 2 threads: foo for pv1 and pv2,  bar for
>> pv3 ]
>>
>> ---> client wants to disconnect everything (or application shutdown)
>>
>> - foreach pv:                                                 // is this
>> safe to be called from the thread that initially called the ca_create* 
>> counterparts???
> You can call any ca routine from any thread that has been attached to
> the context, so yes.
>
>>   * ca_clear_subscription();
>>   * ca_clear_channel();
>>
>> - ca_context_destroy();                                // from same
>> thread where ca_context_create() was called
>>
>>
>> Is the above correct? Am I somewhere wrong?
> It looks like you understand it pretty well.
>
>
>> Some more simpler questions:
>>
>> 1. every time I receive an event, evargs contain not only the value /
>> timestamp but also configuration parameters, right (HI, LO thresholds
>> and so on...)
> Not sure what the question is there. Your event_handler_cb() routine is
> given a struct event_handler_args whose void *dbr pointer points to the
> dbr_* type that you subscribed to. There are many different dbr_* data
> types defined in db_access.h containing different subsets of the
> available data, but none of them provides everything, so you may need to
> subscribe to the same channel multiple times with different types and
> different event masks. Channel metadata (enum strings, alarm levels etc)
> usually change much less frequently than the data itself, and the event
> mask DBE_PROPERTY is designed to tell you when metadata has changed.

Ok, this is a good answer.
A typical graphical interface wants to put in evidence warning or alarm
values (for example, in a gauge you want yellow or red bands or you may
want coloured stripes on the background of a plot in the alarm or
warning sections), so, in this case I may be interested in two kind of
subscriptions:

- the DBE_PROPERTY to get alarms. LO/HI thresholds, display and so on...
- the DBE_VALUE to get value changes.

It would be very useful to me a kind of documentation where this is
described.
I'll have a look at your link now.

Thanks again

Giacomo


>
>> 2. are there utility functions to extract the value and timestamp from
>> the evargs and easily convert them into  the correct type (short,
>> double, int...)
> There are some macros in db_access.h that can help, e.g. dbr_value_ptr
>
> if you limit the number of types you subscribe to you can avoid having
> to write code that understands all the dbr_* types.
>
>> 3. If I monitor a PV, is it possible to know from the args if it's a
>> vector (and its dimension) or a scalar?
> Yes, the struct event_handler_args contains the data type, chid and
> element count for the data contained in this update (look in cadef.h for
> its definition). count==1 means it's a scalar.
>
>> 4. where can I find the explanation of this: Lo disp limit, hi disp
>> limit, Lo alarm limit.... ?
> Those metadata fields are supplied from fields of the record, disp =
> display, so a graph of the channel data over time should expect to use
> the low display limit for the bottom of the y axis and the high display
> limit for the top. Alarm limits tell you if the PV generates alarms what
> data values would trigger those alarms, so you could put a marker on the
> axis if you chose to do so.
>
>> 5. How to extract the timestamp of the event (as far as I've seen from
>> the code, there must be a timestamp from the server and one from the
>> client. In this case, what does the client side timestamp mean. Is it
>> the timestamp when the event is received on the client itself?)
> You appear to be looking at code from catools, which added the idea of
> providing a client-side timestamp as well as or instead of the timestamp
> from the IOC itself. I think it just provides the client's idea of the
> time when the CA library called its callback; this isn't part of the CA
> client library itself.
>
>> Is there a good tutorial for a quick start and the answers to my
>> questions 1 to 5?
>> I mean a quick start to understand how to program a client in C (C++).
> Maybe not at the level of detail you're asking, I think you've probably
> gone beyond what most CA client tutorials covered, but you could browse
> the EPICS Training links to see if there are any that help:
>     http://www.aps.anl.gov/epics/docs/training.php
>
>> One final thing: I've seen a set of C++ libraries (pvaClientCPP,
>> pvCommonCPP)  and in general the
>>
>> "EPICS V4 C++ module"
>>
>> but it looks like it's not up to date with the latest EPICS release.
>>
>> Is this the "official" C++ Epics module?
>>
>> Is it normal that it trails the last EPICS version?
> Those modules are part of the newer EPICS V4 network protocol
> implementation, which are designed to supplement and eventually replace
> the CA protocol. That's a completely different topic and the APIs are
> completely different, I suggest you ignore them for now.
>
> HTH,
>
> - Andrew
>


Replies:
Re: C++ multi threaded application. Ralph Lange
Re: C++ multi threaded application. Andrew Johnson
References:
C++ multi threaded application. Giacomo S.
Re: C++ multi threaded application. Andrew Johnson
Re: C++ multi threaded application. Giacomo S.
Re: C++ multi threaded application. Giacomo S.
Re: C++ multi threaded application. Andrew Johnson

Navigate by Date:
Prev: Re: data refresh and add pv Shankar, Murali
Next: Re: C++ multi threaded application. Ralph Lange
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
Navigate by Thread:
Prev: Re: C++ multi threaded application. Andrew Johnson
Next: Re: C++ multi threaded application. Ralph Lange
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
ANJ, 06 Sep 2017 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·