Merged Michael Abbott's dynamic-array branch, rebased.

I added Perl support, and wrote some release notes.
This commit is contained in:
Andrew Johnson
2010-09-20 16:21:50 -05:00
22 changed files with 299 additions and 393 deletions

View File

@@ -12,6 +12,33 @@
<h2 align="center">Changes between 3.14.11 and 3.14.12</h2>
<!-- Insert new items immediately below here ... -->
<h4>Dynamic arrays over CA</h4>
<p>Dymanic array sizing was developed by Michael Abbott at the 2010 EPICS
Codeathon. It permits a CA client to fetch only the currently valid elements of
an array by specifying a COUNT of zero to either of the ca_array_get_callback()
or ca_create_subscription() routines. It has never before been legal to pass a
COUNT of zero to the ca_array_get_callback() routine, but this development does
introduce a subtle change to the published API of the ca_create_subscription()
routine.</p>
<p>In previous releases a COUNT of zero for a subscription meant use the
ca_element_count() for the channel, but from this release it can return fewer
elements (never more), at the behest of the server. The number of elements can
vary with subsequent array update events, so a client that uses this technique
must use the count field of the event_handler_args in its callback function each
time it is called to obtain the correct element count from the server. Note that
the ca_element_count() value for a channel is only updated at connection time,
and supplies the maximum number of elements that the server array variable can
hold.</p>
<p>Dynamic arrays are currently only supported by the CA client library and IOC
server RSRV, the Perl CA library and the catools programs. The portable CAS does
not understand them, and database links that connect over CA do not attempt to
use them either. CA clients that try to use this functionality with a server
that does not support it will receive the same full-sized zero-filled arrays
that previous releases supported.</p>
<h4>CA over TCP connections</h4>
<p>Merged the CA-over-TCP changes developed by Ralph and Jeff at the 2008 EPICS

View File

@@ -2297,11 +2297,11 @@ ca_put_callback, ca_get_callback, and ca_add_event all request notification of
asynchronous completion via this mechanism. The <code>event_handler_args
</code>structure is passed <em>by value</em> to the application supplied
callback. In this structure the <code>dbr</code> field is a void pointer to any
data that might be returned. The <code>s</code><code>tatus </code>field will be
data that might be returned. The <code>status</code> field will be
set to one of the CA error codes in caerr.h and will indicate the status of the
operation performed in the IOC. If the status field isn't set to ECA_NORMAL or
data isn't normally returned from the operation (i.e. put call back) then you
should expect that the <code>dbr </code>field will be set to a nill pointer
should expect that the <code>dbr</code> field will be set to a nill pointer
(zero). The fields <code>usr</code>, <code>chid</code>, and <code>type</code>
are set to the values specified when the request was made by the application.
The "dbr" pointer, and any data that it points to, are valid only when
@@ -2352,8 +2352,8 @@ library functions that request them.</p>
<p>For routines that require an argument specifying the number of array
elements, no more than the process variable's maximum native element count may
be requested. The process variable's maximum native element count is available
from ca_element_count() when the channel is connected. If less elements than
the process variable's native element count are requested the requested values
from ca_element_count() when the channel is connected. If fewer elements than
the process variable's native element count are requested, the requested values
will be fetched beginning at element zero. By default CA limits the number of
elements in an array to be no more than approximately 16k divided by the size
of one element in the array. Starting with EPICS R3.14 the maximum array size
@@ -2381,12 +2381,12 @@ href="#ca_create_channel">ca_create_channel</a></code>. The <code><a
href="#ca_pend_io">ca_pend_io</a></code> approach is best suited to simple
command line programs with short runtime duration, and the connection callback
method is best suited to toolkit components with long runtime duration. Use of
<code><a href="#ca_state">ca_state</a> </code>is appropriate only in programs
<code><a href="#ca_state">ca_state</a></code> is appropriate only in programs
that prefer to poll for connection state changes instead of opting for
asynchronous notification. The <code>ca_pend_io</code> function blocks only for
channels created specifying a nill connection handler callback function. The
user's connection state change function will be run immediately from within
<code><a href="#ca_create_channel">ca_create_channel</a> </code>if the CA
<code><a href="#ca_create_channel">ca_create_channel</a></code> if the CA
client and CA server are both hosted within the same address space (within the
same process).</p>
@@ -2709,9 +2709,9 @@ time.</p>
<p>The following structure is passed <em>by value </em>to the user's
connection connection callback function. The <code>op</code> field will
be set by the CA client library to <code>CA_OP_CONN_UP</code> when the
channel connects, and to <code>CA_OP_CONN_DOWN </code>when the channel
channel connects, and to <code>CA_OP_CONN_DOWN</code> when the channel
disconnects. See <code><a href="#ca_puser">ca_puser</a></code> if the
<code>PUSER </code>argument is required in your callback
<code>PUSER</code> argument is required in your callback
handler<code>.</code></p>
<pre>struct ca_connection_handler_args {
chanId chid; /* channel id */
@@ -2973,7 +2973,8 @@ when a CA get request is initiated.</p>
<dl>
<dt><code>COUNT</code></dt>
<dd>Element count to be read from the specified channel. Must match the
array pointed to by PVALUE.</dd>
array pointed to by PVALUE. For ca_array_get_callback a count of zero
means use the current element count from the server.</dd>
</dl>
<dl>
<dt><code>CHID</code></dt>
@@ -3081,7 +3082,7 @@ indicating the current state of the channel.</p>
<dl>
<dt><code>COUNT</code></dt>
<dd>The element count to be read from the specified channel. A count of
zero specifies the native elemnt count.</dd>
zero means use the current element count from the server.</dd>
</dl>
<dl>
<dt><code>CHID</code></dt>
@@ -3391,7 +3392,7 @@ field should not be used.</p>
<dd>Address of user callback function to be executed when an exceptions
occur. Passing a nil value causes the default exception handler to be
reinstalled. The following structure is passed by value to the user's
callback function. Currently, the <code>op </code>field can be one of
callback function. Currently, the <code>op</code> field can be one of
<code>CA_OP_GET, CA_OP_PUT, CA_OP_CREATE_CHANNEL, CA_OP_ADD_EVENT,
CA_OP_CLEAR_EVENT, or CA_OP_OTHER.</code>
<pre>struct exception_handler_args {

View File

@@ -41,6 +41,7 @@
# define CA_V410(MINOR) ((MINOR)>=10u) /* beacon counter */
# define CA_V411(MINOR) ((MINOR)>=11u) /* sequence numbers in UDP version command */
# define CA_V412(MINOR) ((MINOR)>=12u) /* TCP-based search requests */
# define CA_V413(MINOR) ((MINOR)>=13u) /* Allow zero length in requests. */
#elif CA_MAJOR_PROTOCOL_REVISION > 4u
# define CA_V41(MINOR) ( 1u )
# define CA_V42(MINOR) ( 1u )
@@ -54,6 +55,7 @@
# define CA_V410(MINOR) ( 1u )
# define CA_V411(MINOR) ( 1u )
# define CA_V412(MINOR) ( 1u )
# define CA_V413(MINOR) ( 1u )
#else
# define CA_V41(MINOR) ( 0u )
# define CA_V42(MINOR) ( 0u )
@@ -67,6 +69,7 @@
# define CA_V410(MINOR) ( 0u )
# define CA_V411(MINOR) ( 0u )
# define CA_V412(MINOR) ( 0u )
# define CA_V413(MINOR) ( 0u )
#endif
/*

View File

@@ -524,16 +524,16 @@ struct dbr_ctrl_double{
dbr_double_t value; /* current value */
};
#ifndef db_accessHFORdb_accessC
#define dbr_size_n(TYPE,COUNT)\
((unsigned)((COUNT)<=0?dbr_size[TYPE]:dbr_size[TYPE]+((COUNT)-1)*dbr_value_size[TYPE]))
/* size for each type - array indexed by the DBR_ type code */
epicsShareExtern const unsigned short dbr_size[LAST_BUFFER_TYPE+1];
epicsShareExtern const unsigned short dbr_size[];
/* size for each type's value - array indexed by the DBR_ type code */
epicsShareExtern const unsigned short dbr_value_size[LAST_BUFFER_TYPE+1];
epicsShareExtern const unsigned short dbr_value_size[];
#ifndef db_accessHFORdb_accessC
/* class for each type's value */
enum dbr_value_class {
dbr_class_int,

View File

@@ -291,9 +291,6 @@ cacChannel::ioStatus nciu::read (
if ( countIn > this->count ) {
throw cacChannel::outOfBounds ();
}
if ( countIn == 0 ) {
countIn = this->count;
}
//
// fail out if their arguments are invalid

View File

@@ -41,7 +41,7 @@
# include "shareLib.h"
#endif
#define CA_MINOR_PROTOCOL_REVISION 12
#define CA_MINOR_PROTOCOL_REVISION 13
#include "caProto.h"
#include "cacIO.h"
@@ -205,6 +205,7 @@ public:
void disconnectAllIO (
epicsGuard < epicsMutex > &, epicsGuard < epicsMutex > & );
bool connected ( epicsGuard < epicsMutex > & ) const;
unsigned getcount() const { return count; }
private:
tsDLList < class baseNMIU > eventq;

View File

@@ -83,7 +83,7 @@ public:
void show (
epicsGuard < epicsMutex > &, unsigned level ) const;
arrayElementCount getCount (
epicsGuard < epicsMutex > & ) const;
epicsGuard < epicsMutex > &, bool allow_zero ) const;
unsigned getType (
epicsGuard < epicsMutex > & ) const;
unsigned getMask (
@@ -242,11 +242,11 @@ inline netSubscription * netSubscription::factory (
}
inline arrayElementCount netSubscription::getCount (
epicsGuard < epicsMutex > & guard ) const // X aCC 361
epicsGuard < epicsMutex > & guard, bool allow_zero ) const // X aCC 361
{
//guard.assertIdenticalMutex ( this->mutex );
arrayElementCount nativeCount = this->privateChanForIO.nativeElementCount ( guard );
if ( this->count == 0u || this->count > nativeCount ) {
if ( (this->count == 0u && !allow_zero) || this->count > nativeCount ) {
return nativeCount;
}
else {

View File

@@ -280,6 +280,9 @@ int epicsShareAPI ca_array_get ( chtype type,
if ( type < 0 ) {
return ECA_BADTYPE;
}
if ( count == 0 )
return ECA_BADCOUNT;
unsigned tmpType = static_cast < unsigned > ( type );
epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () );
pChan->eliminateExcessiveSendBacklog ( guard );

View File

@@ -1464,6 +1464,8 @@ void tcpiiu::readNotifyRequest ( epicsGuard < epicsMutex > & guard, // X aCC 431
if ( nElem > maxElem ) {
throw cacChannel::msgBodyCacheTooSmall ();
}
if (nElem == 0 && !CA_V413(this->minorProtocolVersion))
nElem = chan.getcount();
comQueSendMsgMinder minder ( this->sendQue, guard );
this->sendQue.insertRequestHeader (
CA_PROTO_READ_NOTIFY, 0u,
@@ -1559,7 +1561,8 @@ void tcpiiu::subscriptionRequest (
if ( mask > 0xffff ) {
throw cacChannel::badEventSelection ();
}
arrayElementCount nElem = subscr.getCount ( guard );
arrayElementCount nElem = subscr.getCount (
guard, CA_V413(this->minorProtocolVersion) );
arrayElementCount maxBytes;
if ( CA_V49 ( this->minorProtocolVersion ) ) {
maxBytes = this->cacRef.largeBufferSizeTCP ();
@@ -1605,7 +1608,8 @@ void tcpiiu::subscriptionUpdateRequest (
if ( this->state != iiucs_connected ) {
return;
}
arrayElementCount nElem = subscr.getCount ( guard );
arrayElementCount nElem = subscr.getCount (
guard, CA_V413(this->minorProtocolVersion) );
arrayElementCount maxBytes;
if ( CA_V49 ( this->minorProtocolVersion ) ) {
maxBytes = this->cacRef.largeBufferSizeTCP ();
@@ -1643,7 +1647,8 @@ void tcpiiu::subscriptionCancelRequest ( epicsGuard < epicsMutex > & guard, // X
this->sendQue.insertRequestHeader (
CA_PROTO_EVENT_CANCEL, 0u,
static_cast < ca_uint16_t > ( subscr.getType ( guard ) ),
static_cast < ca_uint16_t > ( subscr.getCount ( guard ) ),
static_cast < ca_uint16_t > ( subscr.getCount (
guard, CA_V413(this->minorProtocolVersion) ) ),
chan.getSID(guard), subscr.getId(),
CA_V49 ( this->minorProtocolVersion ) );
minder.commit ();

View File

@@ -210,8 +210,9 @@ data type requested will be the widened form of the channel's native type
fetch all available elements.
The element count can be overridden by providing an integer argument in the
range 1 .. C<element_count>. Note that the count argument must be an integer;
add 0 to it if it is necessary to convert it from a string.
range 0 .. C<element_count>, where zero means use the current length from the
server. Note that the count argument must be an integer; add 0 to it if it is
necessary to convert it from a string.
The optional data type I<TYPE> should be a string naming
the desired C<DBR_xxx_yyy> type; the actual type used will have the C<yyy> part
widened to one of C<STRING>, C<CHAR>, C<LONG> or C<DOUBLE>. The valid type

View File

@@ -782,7 +782,7 @@ void CA_get(SV *ca_ref) {
New(0, pch->sdata, count + 1, char);
pch->ssize = count;
}
status = ca_array_get(DBF_CHAR, count, pch->chan, pch->sdata);
status = ca_array_get(DBF_CHAR, 0, pch->chan, pch->sdata);
} else {
status = ca_get(best_type(pch), pch->chan, &pch->data);
}
@@ -818,16 +818,16 @@ void CA_get_callback(SV *ca_ref, SV *sub, ...) {
SV *get_sub = newSVsv(sub);
int status;
chtype type = best_type(pch);
int count = ca_element_count(pch->chan);
int count = 0;
int i = 2;
const char *croak_msg;
while (items > i
&& SvOK(ST(i))) {
if (SvIOK(ST(i))) {
/* Interger => Count arg */
/* Interger => Count arg, zero means current size */
count = SvIV(ST(i));
if (count < 1 || count > ca_element_count(pch->chan)) {
if (count < 0 || count > ca_element_count(pch->chan)) {
croak_msg = "Requested array size is out of range";
goto exit_croak;
}
@@ -901,7 +901,7 @@ SV * CA_create_subscription(SV *ca_ref, const char *mask_str, SV *sub, ...) {
while (items > i
&& SvOK(ST(i))) {
if (SvIOK(ST(i))) {
/* Interger => Count arg, zero means native size */
/* Interger => Count arg, zero means current size */
count = SvIV(ST(i));
if (count < 0 || count > ca_element_count(pch->chan)) {
croak_msg = "Requested array size is out of range";

View File

@@ -6,10 +6,12 @@ use FindBin qw($Bin);
use lib "$Bin/../../lib/perl";
use Getopt::Std;
use Scalar::Util qw(looks_like_number);
use CA;
our ($opt_0, $opt_a, $opt_c, $opt_d, $opt_e, $opt_f, $opt_g, $opt_h, $opt_n);
our ($opt_0, $opt_a, $opt_d, $opt_e, $opt_f, $opt_g, $opt_h, $opt_n);
our ($opt_s, $opt_S, $opt_t);
our $opt_c = 0;
our $opt_F = ' ';
our $opt_w = 1;
@@ -18,6 +20,9 @@ $Getopt::Std::OUTPUT_HELP_VERSION = 1;
HELP_MESSAGE() unless getopts('0:ac:d:e:f:F:g:hnsStw:');
HELP_MESSAGE() if $opt_h;
die "caget: -c option takes a positive number\n"
unless looks_like_number($opt_c) && $opt_c >= 0;
die "No pv name specified. ('caget -h' gives help.)\n"
unless @ARGV;
@@ -51,9 +56,7 @@ map {
if $opt_a;
}
$rtype{$_} = $type;
my $count = $_->element_count;
$count = +$opt_c if $opt_c && $opt_c <= $count;
$_->get_callback(\&get_callback, $type, $count);
$_->get_callback(\&get_callback, $type, 0+$opt_c);
} @chans;
my $incomplete = @chans;

View File

@@ -6,9 +6,11 @@ use FindBin qw($Bin);
use lib "$Bin/../../lib/perl";
use Getopt::Std;
use Scalar::Util qw(looks_like_number);
use CA;
our ($opt_0, $opt_c, $opt_e, $opt_f, $opt_g, $opt_h, $opt_n, $opt_s, $opt_S);
our ($opt_0, $opt_e, $opt_f, $opt_g, $opt_h, $opt_n, $opt_s, $opt_S);
our $opt_c = 0;
our $opt_F = ' ';
our $opt_w = 1;
our $opt_m = 'va';
@@ -18,6 +20,9 @@ $Getopt::Std::OUTPUT_HELP_VERSION = 1;
HELP_MESSAGE() unless getopts('0:c:e:f:F:g:hm:nsSw:');
HELP_MESSAGE() if $opt_h;
die "caget: -c option takes a positive number\n"
unless looks_like_number($opt_c) && $opt_c >= 0;
die "No pv name specified. ('camonitor -h' gives help.)\n"
unless @ARGV;
@@ -45,11 +50,8 @@ sub conn_callback {
|| (!$opt_S && $type eq 'DBR_CHAR');
$type =~ s/^DBR_/DBR_TIME_/;
my $count = $chan->element_count;
$count = +$opt_c if $opt_c && $opt_c <= $count;
$monitors{$chan} =
$chan->create_subscription($opt_m, \&mon_callback, $type, $count);
$chan->create_subscription($opt_m, \&mon_callback, $type, 0+$opt_c);
}
}

View File

@@ -127,6 +127,7 @@ static void event_handler (evargs args)
ppv->value = calloc(1, dbr_size_n(args.type, args.count));
memcpy(ppv->value, args.dbr, dbr_size_n(args.type, args.count));
ppv->onceConnected = 1;
ppv->nElems = args.count;
nRead++;
}
}
@@ -183,11 +184,9 @@ static int caget (pv *pvs, int nPvs, RequestT request, OutputT format,
}
}
/* Adjust array count */
if (reqElems == 0 || pvs[n].nElems < reqElems){
pvs[n].reqElems = pvs[n].nElems; /* Use full number of points */
} else {
pvs[n].reqElems = reqElems; /* Limit to specified number */
}
if (reqElems > pvs[n].nElems)
reqElems = pvs[n].nElems;
pvs[n].reqElems = reqElems;
/* Issue CA request */
/* ---------------- */
@@ -205,13 +204,13 @@ static int caget (pv *pvs, int nPvs, RequestT request, OutputT format,
(void*)&pvs[n]);
} else {
/* Allocate value structure */
pvs[n].value = calloc(1, dbr_size_n(pvs[n].dbrType, pvs[n].reqElems));
pvs[n].value = calloc(1, dbr_size_n(pvs[n].dbrType, pvs[n].nElems));
if(!pvs[n].value) {
fprintf(stderr,"Allocation failed\n");
return 1;
}
result = ca_array_get(pvs[n].dbrType,
pvs[n].reqElems,
pvs[n].nElems,
pvs[n].chid,
pvs[n].value);
}
@@ -253,10 +252,13 @@ static int caget (pv *pvs, int nPvs, RequestT request, OutputT format,
/* -------------- */
for (n = 0; n < nPvs; n++) {
/* Truncate the data printed to what was requested. */
if (pvs[n].reqElems != 0 && pvs[n].nElems > pvs[n].reqElems)
pvs[n].nElems = pvs[n].reqElems;
switch (format) {
case plain: /* Emulate old caget behaviour */
if (pvs[n].reqElems <= 1 && fieldSeparator == ' ') printf("%-30s", pvs[n].name);
if (pvs[n].nElems <= 1 && fieldSeparator == ' ') printf("%-30s", pvs[n].name);
else printf("%s", pvs[n].name);
printf("%c", fieldSeparator);
case terse:
@@ -270,7 +272,7 @@ static int caget (pv *pvs, int nPvs, RequestT request, OutputT format,
printf("*** no data available (timeout)\n");
else
{
if (charArrAsStr && dbr_type_is_CHAR(pvs[n].dbrType) && (reqElems || pvs[n].reqElems > 1)) {
if (charArrAsStr && dbr_type_is_CHAR(pvs[n].dbrType) && (reqElems || pvs[n].nElems > 1)) {
dbr_char_t *s = (dbr_char_t*) dbr_value_ptr(pvs[n].value, pvs[n].dbrType);
int dlen = epicsStrnEscapedFromRawSize((char*)s, strlen((char*)s));
char *d = calloc(dlen+1, sizeof(char));
@@ -282,8 +284,8 @@ static int caget (pv *pvs, int nPvs, RequestT request, OutputT format,
fprintf(stderr,"Failed to allocate space for escaped string\n");
}
} else {
if (reqElems || pvs[n].nElems > 1) printf("%lu%c", pvs[n].reqElems, fieldSeparator);
for (i=0; i<pvs[n].reqElems; ++i) {
if (reqElems || pvs[n].nElems > 1) printf("%lu%c", pvs[n].nElems, fieldSeparator);
for (i=0; i<pvs[n].nElems; ++i) {
if (i) printf ("%c", fieldSeparator);
printf("%s", val2str(pvs[n].value, pvs[n].dbrType, i));
}
@@ -315,8 +317,8 @@ static int caget (pv *pvs, int nPvs, RequestT request, OutputT format,
else {
printf(" Element count: %lu\n"
" Value: ",
pvs[n].reqElems);
if (charArrAsStr && dbr_type_is_CHAR(pvs[n].dbrType) && (reqElems || pvs[n].reqElems > 1)) {
pvs[n].nElems);
if (charArrAsStr && dbr_type_is_CHAR(pvs[n].dbrType) && (reqElems || pvs[n].nElems > 1)) {
dbr_char_t *s = (dbr_char_t*) dbr_value_ptr(pvs[n].value, pvs[n].dbrType);
int dlen = epicsStrnEscapedFromRawSize((char*)s, strlen((char*)s));
char *d = calloc(dlen+1, sizeof(char));
@@ -328,7 +330,7 @@ static int caget (pv *pvs, int nPvs, RequestT request, OutputT format,
fprintf(stderr,"Failed to allocate space for escaped string\n");
}
} else {
for (i=0; i<pvs[n].reqElems; ++i) {
for (i=0; i<pvs[n].nElems; ++i) {
if (i) printf ("%c", fieldSeparator);
printf("%s", val2str(pvs[n].value, pvs[n].dbrType, i));
}

View File

@@ -107,6 +107,7 @@ static void event_handler (evargs args)
if (args.status == ECA_NORMAL)
{
pv->dbrType = args.type;
pv->nElems = args.count;
memcpy(pv->value, args.dbr, dbr_size_n(args.type, args.count));
print_time_val_sts(pv, reqElems);
@@ -150,11 +151,9 @@ static void connection_handler ( struct connection_handler_args args )
ppv->dbrType = DBR_TIME_STRING;
}
/* Adjust array count */
if (reqElems == 0 || ppv->nElems < reqElems){
ppv->reqElems = ppv->nElems; /* Use full number of points */
} else {
ppv->reqElems = reqElems; /* Limit to specified number */
}
if (reqElems > ppv->nElems)
reqElems = ppv->nElems;
ppv->reqElems = reqElems;
ppv->onceConnected = 1;
nConn++;
@@ -163,7 +162,7 @@ static void connection_handler ( struct connection_handler_args args )
/* install monitor once with first connect */
if ( ! ppv->value ) {
/* Allocate value structure */
ppv->value = calloc(1, dbr_size_n(ppv->dbrType, ppv->reqElems));
ppv->value = calloc(1, dbr_size_n(ppv->dbrType, ppv->nElems));
if ( ppv->value ) {
ppv->status = ca_create_subscription(ppv->dbrType,
ppv->reqElems,

View File

@@ -455,8 +455,8 @@ char *dbr2str (const void *value, unsigned type)
printf("Failed to allocate for print_time_val_sts\n"); \
} \
} else { \
if (reqElems || pv->nElems > 1) printf("%c%lu", fieldSeparator, pv->reqElems); \
for (i=0; i<pv->reqElems; ++i) { \
if (reqElems || pv->nElems > 1) printf("%c%lu", fieldSeparator, pv->nElems); \
for (i=0; i<pv->nElems; ++i) { \
printf("%c%s", fieldSeparator, val2str(value, TYPE_ENUM, i)); \
} \
} \
@@ -492,7 +492,7 @@ void print_time_val_sts (pv* pv, unsigned long reqElems)
tsInitS = 1;
}
if (pv->reqElems <= 1 && fieldSeparator == ' ') printf("%-30s", pv->name);
if (pv->nElems <= 1 && fieldSeparator == ' ') printf("%-30s", pv->name);
else printf("%s", pv->name);
printf("%c", fieldSeparator);
if (!pv->onceConnected)

View File

@@ -64,8 +64,8 @@ typedef struct
chid chid;
long dbfType;
long dbrType;
unsigned long nElems;
unsigned long reqElems;
unsigned long nElems; // True length of data in value
unsigned long reqElems; // Requested length of data
int status;
void* value;
epicsTimeStamp tsPreviousC;

View File

@@ -148,95 +148,58 @@ int epicsShareAPI db_name_to_addr(const char *pname, struct dbAddr *paddr)
int epicsShareAPI db_get_field(struct dbAddr *paddr,
int buffer_type, void *pbuffer, int no_elements, void *pfl)
{
long nRequest = no_elements;
int result = db_get_field_and_count(
paddr, buffer_type, pbuffer, &nRequest, pfl);
if (nRequest < no_elements)
/* If the database request returned fewer elements than requested then
* fill out the remainder of the array with zeros. */
memset(
(char *)pbuffer + dbr_size_n(buffer_type, nRequest), 0,
(no_elements - nRequest) * dbr_value_size[buffer_type]);
return result;
}
/* Performs the work of the public db_get_field API, but also returns the number
* of elements actually copied to the buffer. The caller is responsible for
* zeroing the remaining part of the buffer. */
int epicsShareAPI db_get_field_and_count(
struct dbAddr *paddr, int buffer_type,
void *pbuffer, long *nRequest, void *pfl)
{
long status;
long options;
long nRequest;
long i;
long zero = 0;
/* The order of the DBR* elements in the "new" structures below is
/* The order of the DBR* elements in the "newSt" structures below is
* very important and must correspond to the order of processing
* in the dbAccess.c dbGet() and getOptions() routines.
*/
switch(buffer_type) {
case(oldDBR_STRING):
{
DBSTRING *pvalue = (DBSTRING *)pbuffer;
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_STRING, pbuffer, &options, &nRequest,
pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i][0] = 0;
}
status = dbGetField(paddr, DBR_STRING, pbuffer, &zero, nRequest, pfl);
break;
/* case(oldDBR_INT): */
case(oldDBR_SHORT):
{
dbr_short_t *pvalue = (dbr_short_t *)pbuffer;
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_SHORT, pbuffer, &options, &nRequest,
pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
}
status = dbGetField(paddr, DBR_SHORT, pbuffer, &zero, nRequest, pfl);
break;
case(oldDBR_FLOAT):
{
dbr_float_t *pvalue = (dbr_float_t *)pbuffer;
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_FLOAT, pbuffer, &options, &nRequest,
pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
}
status = dbGetField(paddr, DBR_FLOAT, pbuffer, &zero, nRequest, pfl);
break;
case(oldDBR_ENUM):
{
dbr_enum_t *pvalue = (dbr_enum_t *)pbuffer;
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_ENUM, pbuffer, &options, &nRequest,
pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
}
status = dbGetField(paddr, DBR_ENUM, pbuffer, &zero, nRequest, pfl);
break;
case(oldDBR_CHAR):
{
dbr_char_t *pvalue = (dbr_char_t *)pbuffer;
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_CHAR, pbuffer, &options, &nRequest,
pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
}
status = dbGetField(paddr, DBR_CHAR, pbuffer, &zero, nRequest, pfl);
break;
case(oldDBR_LONG):
{
dbr_long_t *pvalue = (dbr_long_t *)pbuffer;
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_LONG, pbuffer, &options, &nRequest,
pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
}
status = dbGetField(paddr, DBR_LONG, pbuffer, &zero, nRequest, pfl);
break;
case(oldDBR_DOUBLE):
{
dbr_double_t *pvalue = (dbr_double_t *)pbuffer;
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_DOUBLE, pbuffer, &options, &nRequest,
pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
}
status = dbGetField(paddr, DBR_DOUBLE, pbuffer, &zero, nRequest, pfl);
break;
case(oldDBR_STS_STRING):
@@ -247,19 +210,13 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
struct {
DBRstatus
} newSt;
DBSTRING *pvalue = (DBSTRING *)pold->value;
options = DBR_STATUS;
nRequest = 0;
status = dbGetField(paddr, DBR_STRING, &newSt, &options, &nRequest,
pfl);
status = dbGetField(paddr, DBR_STRING, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_STRING, pold->value, &options,
&nRequest, pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i][0] = 0;
status = dbGetField(paddr, DBR_STRING, pold->value, &zero,
nRequest, pfl);
}
break;
/* case(oldDBR_STS_INT): */
@@ -269,19 +226,13 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
struct {
DBRstatus
} newSt;
dbr_short_t *pvalue = &pold->value;
options = DBR_STATUS;
nRequest = 0;
status = dbGetField(paddr, DBR_SHORT, &newSt, &options, &nRequest,
pfl);
status = dbGetField(paddr, DBR_SHORT, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_SHORT, &pold->value, &options,
&nRequest, pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
status = dbGetField(paddr, DBR_SHORT, &pold->value, &zero,
nRequest, pfl);
}
break;
case(oldDBR_STS_FLOAT):
@@ -290,19 +241,13 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
struct {
DBRstatus
} newSt;
dbr_float_t *pvalue = &pold->value;
options = DBR_STATUS;
nRequest = 0;
status = dbGetField(paddr, DBR_FLOAT, &newSt, &options, &nRequest,
pfl);
status = dbGetField(paddr, DBR_FLOAT, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_FLOAT, &pold->value, &options,
&nRequest, pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
status = dbGetField(paddr, DBR_FLOAT, &pold->value, &zero,
nRequest, pfl);
}
break;
case(oldDBR_STS_ENUM):
@@ -311,19 +256,13 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
struct {
DBRstatus
} newSt;
dbr_enum_t *pvalue = &pold->value;
options = DBR_STATUS;
nRequest = 0;
status = dbGetField(paddr, DBR_ENUM, &newSt, &options, &nRequest,
pfl);
status = dbGetField(paddr, DBR_ENUM, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_ENUM, &pold->value, &options,
&nRequest, pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
status = dbGetField(paddr, DBR_ENUM, &pold->value, &zero,
nRequest, pfl);
}
break;
case(oldDBR_STS_CHAR):
@@ -332,19 +271,13 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
struct {
DBRstatus
} newSt;
dbr_char_t *pvalue = &pold->value;
options = DBR_STATUS;
nRequest = 0;
status = dbGetField(paddr, DBR_UCHAR, &newSt, &options, &nRequest,
pfl);
status = dbGetField(paddr, DBR_UCHAR, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_UCHAR, &pold->value, &options,
&nRequest, pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
status = dbGetField(paddr, DBR_UCHAR, &pold->value, &zero,
nRequest, pfl);
}
break;
case(oldDBR_STS_LONG):
@@ -353,19 +286,13 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
struct {
DBRstatus
} newSt;
dbr_long_t *pvalue = &pold->value;
options = DBR_STATUS;
nRequest = 0;
status = dbGetField(paddr, DBR_LONG, &newSt, &options, &nRequest,
pfl);
status = dbGetField(paddr, DBR_LONG, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_LONG, &pold->value, &options,
&nRequest, pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
status = dbGetField(paddr, DBR_LONG, &pold->value, &zero,
nRequest, pfl);
}
break;
case(oldDBR_STS_DOUBLE):
@@ -374,19 +301,14 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
struct {
DBRstatus
} newSt;
dbr_double_t *pvalue = &pold->value;
options = DBR_STATUS;
nRequest = 0;
status = dbGetField(paddr, DBR_DOUBLE, &newSt, &options, &nRequest,
pfl);
status = dbGetField(paddr, DBR_DOUBLE, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_DOUBLE, &pold->value, &options,
&nRequest, pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
nRequest, pfl);
}
break;
@@ -397,20 +319,15 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRstatus
DBRtime
} newSt;
DBSTRING *pvalue = (DBSTRING *)(pold->value);
options = DBR_STATUS | DBR_TIME;
nRequest = 0;
status = dbGetField(paddr, DBR_STRING, &newSt, &options, &nRequest,
pfl);
status = dbGetField(paddr, DBR_STRING, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->stamp = newSt.time; /* structure copy */
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_STRING, pold->value, &options,
&nRequest, pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i][0] = 0;
status = dbGetField(paddr, DBR_STRING, pold->value, &options,
nRequest, pfl);
}
break;
/* case(oldDBR_TIME_INT): */
@@ -421,20 +338,15 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRstatus
DBRtime
} newSt;
dbr_short_t *pvalue = &pold->value;
options = DBR_STATUS | DBR_TIME;
nRequest = 0;
status = dbGetField(paddr, DBR_SHORT, &newSt, &options, &nRequest,
pfl);
status = dbGetField(paddr, DBR_SHORT, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->stamp = newSt.time; /* structure copy */
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_SHORT, &pold->value, &options,
&nRequest, pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
nRequest, pfl);
}
break;
case(oldDBR_TIME_FLOAT):
@@ -444,20 +356,15 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRstatus
DBRtime
} newSt;
dbr_float_t *pvalue = &pold->value;
options = DBR_STATUS | DBR_TIME;
nRequest = 0;
status = dbGetField(paddr, DBR_FLOAT, &newSt, &options, &nRequest,
pfl);
status = dbGetField(paddr, DBR_FLOAT, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->stamp = newSt.time; /* structure copy */
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_FLOAT, &pold->value, &options,
&nRequest, pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
nRequest, pfl);
}
break;
case(oldDBR_TIME_ENUM):
@@ -467,20 +374,15 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRstatus
DBRtime
} newSt;
dbr_enum_t *pvalue = &pold->value;
options = DBR_STATUS | DBR_TIME;
nRequest = 0;
status = dbGetField(paddr, DBR_ENUM, &newSt, &options, &nRequest,
pfl);
status = dbGetField(paddr, DBR_ENUM, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->stamp = newSt.time; /* structure copy */
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_ENUM, &pold->value, &options,
&nRequest, pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
nRequest, pfl);
}
break;
case(oldDBR_TIME_CHAR):
@@ -490,20 +392,15 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRstatus
DBRtime
} newSt;
dbr_char_t *pvalue = &pold->value;
options = DBR_STATUS | DBR_TIME;
nRequest = 0;
status = dbGetField(paddr, DBR_CHAR, &newSt, &options, &nRequest,
pfl);
status = dbGetField(paddr, DBR_CHAR, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->stamp = newSt.time; /* structure copy */
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_CHAR, &pold->value, &options,
&nRequest, pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
nRequest, pfl);
}
break;
case(oldDBR_TIME_LONG):
@@ -513,20 +410,15 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRstatus
DBRtime
} newSt;
dbr_long_t *pvalue = &pold->value;
options = DBR_STATUS | DBR_TIME;
nRequest = 0;
status = dbGetField(paddr, DBR_LONG, &newSt, &options, &nRequest,
pfl);
status = dbGetField(paddr, DBR_LONG, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->stamp = newSt.time; /* structure copy */
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_LONG, &pold->value, &options,
&nRequest, pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
nRequest, pfl);
}
break;
case(oldDBR_TIME_DOUBLE):
@@ -536,20 +428,15 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRstatus
DBRtime
} newSt;
dbr_double_t *pvalue = &pold->value;
options = DBR_STATUS | DBR_TIME;
nRequest = 0;
status = dbGetField(paddr, DBR_DOUBLE, &newSt, &options, &nRequest,
pfl);
status = dbGetField(paddr, DBR_DOUBLE, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->stamp = newSt.time; /* structure copy */
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_DOUBLE, &pold->value, &options,
&nRequest, pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
nRequest, pfl);
}
break;
@@ -564,12 +451,9 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRgrLong
DBRalLong
} newSt;
dbr_short_t *pvalue = &pold->value;
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_AL_LONG;
nRequest = 0;
status = dbGetField(paddr, DBR_SHORT, &newSt, &options, &nRequest,
pfl);
status = dbGetField(paddr, DBR_SHORT, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
@@ -581,10 +465,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
pold->lower_warning_limit = newSt.lower_warning_limit;
pold->lower_alarm_limit = newSt.lower_alarm_limit;
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_SHORT, &pold->value, &options,
&nRequest, pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
nRequest, pfl);
}
break;
case(oldDBR_GR_FLOAT):
@@ -597,13 +479,10 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRgrDouble
DBRalDouble
} newSt;
dbr_float_t *pvalue = &pold->value;
options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE |
DBR_AL_DOUBLE;
nRequest = 0;
status = dbGetField(paddr, DBR_FLOAT, &newSt, &options, &nRequest,
pfl);
status = dbGetField(paddr, DBR_FLOAT, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->precision = newSt.precision.dp;
@@ -616,10 +495,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
pold->upper_warning_limit = epicsConvertDoubleToFloat(newSt.upper_warning_limit);
pold->lower_warning_limit = epicsConvertDoubleToFloat(newSt.lower_warning_limit);
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_FLOAT, &pold->value, &options,
&nRequest, pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
nRequest, pfl);
}
break;
/* case(oldDBR_GR_ENUM): see oldDBR_CTRL_ENUM */
@@ -632,12 +509,9 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRgrLong
DBRalLong
} newSt;
dbr_char_t *pvalue = &pold->value;
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_AL_LONG;
nRequest = 0;
status = dbGetField(paddr, DBR_UCHAR, &newSt, &options, &nRequest,
pfl);
status = dbGetField(paddr, DBR_UCHAR, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
@@ -649,10 +523,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
pold->lower_warning_limit = newSt.lower_warning_limit;
pold->lower_alarm_limit = newSt.lower_alarm_limit;
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_UCHAR, &pold->value, &options,
&nRequest, pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
nRequest, pfl);
}
break;
case(oldDBR_GR_LONG):
@@ -664,12 +536,9 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRgrLong
DBRalLong
} newSt;
dbr_long_t *pvalue = &pold->value;
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_AL_LONG;
nRequest = 0;
status = dbGetField(paddr, DBR_LONG, &newSt, &options, &nRequest,
pfl);
status = dbGetField(paddr, DBR_LONG, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
@@ -681,10 +550,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
pold->lower_warning_limit = newSt.lower_warning_limit;
pold->lower_alarm_limit = newSt.lower_alarm_limit;
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_LONG, &pold->value, &options,
&nRequest, pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
nRequest, pfl);
}
break;
case(oldDBR_GR_DOUBLE):
@@ -697,13 +564,10 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRgrDouble
DBRalDouble
} newSt;
dbr_double_t *pvalue = &pold->value;
options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE |
DBR_AL_DOUBLE;
nRequest = 0;
status = dbGetField(paddr, DBR_DOUBLE, &newSt, &options, &nRequest,
pfl);
status = dbGetField(paddr, DBR_DOUBLE, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->precision = newSt.precision.dp;
@@ -716,10 +580,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
pold->lower_warning_limit = newSt.lower_warning_limit;
pold->lower_alarm_limit = newSt.lower_alarm_limit;
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_DOUBLE, &pold->value, &options,
&nRequest, pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
nRequest, pfl);
}
break;
@@ -734,13 +596,10 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRctrlLong
DBRalLong
} newSt;
dbr_short_t *pvalue = &pold->value;
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_CTRL_LONG |
DBR_AL_LONG;
nRequest = 0;
status = dbGetField(paddr, DBR_SHORT, &newSt, &options, &nRequest,
pfl);
status = dbGetField(paddr, DBR_SHORT, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
@@ -754,10 +613,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
pold->upper_ctrl_limit = newSt.upper_ctrl_limit;
pold->lower_ctrl_limit = newSt.lower_ctrl_limit;
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_SHORT, &pold->value, &options,
&nRequest, pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
nRequest, pfl);
}
break;
case(oldDBR_CTRL_FLOAT):
@@ -771,13 +628,10 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRctrlDouble
DBRalDouble
} newSt;
dbr_float_t *pvalue = &pold->value;
options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE |
DBR_CTRL_DOUBLE | DBR_AL_DOUBLE;
nRequest = 0;
status = dbGetField(paddr, DBR_FLOAT, &newSt, &options, &nRequest,
pfl);
status = dbGetField(paddr, DBR_FLOAT, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->precision = newSt.precision.dp;
@@ -792,10 +646,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
pold->upper_ctrl_limit = epicsConvertDoubleToFloat(newSt.upper_ctrl_limit);
pold->lower_ctrl_limit = epicsConvertDoubleToFloat(newSt.lower_ctrl_limit);
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_FLOAT, &pold->value, &options,
&nRequest, pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
nRequest, pfl);
}
break;
case(oldDBR_GR_ENUM):
@@ -807,14 +659,11 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRenumStrs
} newSt;
short no_str;
dbr_enum_t *pvalue = &pold->value;
memset(pold, '\0', sizeof(struct dbr_ctrl_enum));
/* first get status and severity */
options = DBR_STATUS | DBR_ENUM_STRS;
nRequest = 0;
status = dbGetField(paddr, DBR_ENUM, &newSt, &options, &nRequest,
pfl);
status = dbGetField(paddr, DBR_ENUM, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
no_str = newSt.no_str;
@@ -824,10 +673,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
strncpy(pold->strs[i], newSt.strs[i], sizeof(pold->strs[i]));
/*now get values*/
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_ENUM, &pold->value, &options,
&nRequest, pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
nRequest, pfl);
}
break;
case(oldDBR_CTRL_CHAR):
@@ -840,13 +687,10 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRctrlLong
DBRalLong
} newSt;
dbr_char_t *pvalue = &pold->value;
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_CTRL_LONG |
DBR_AL_LONG;
nRequest = 0;
status = dbGetField(paddr, DBR_UCHAR, &newSt, &options, &nRequest,
pfl);
status = dbGetField(paddr, DBR_UCHAR, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
@@ -860,10 +704,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
pold->upper_ctrl_limit = newSt.upper_ctrl_limit;
pold->lower_ctrl_limit = newSt.lower_ctrl_limit;
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_UCHAR, &pold->value, &options,
&nRequest, pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
nRequest, pfl);
}
break;
case(oldDBR_CTRL_LONG):
@@ -876,13 +718,10 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRctrlLong
DBRalLong
} newSt;
dbr_long_t *pvalue = &pold->value;
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_CTRL_LONG |
DBR_AL_LONG;
nRequest = 0;
status = dbGetField(paddr, DBR_LONG, &newSt, &options, &nRequest,
pfl);
status = dbGetField(paddr, DBR_LONG, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
@@ -896,10 +735,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
pold->upper_ctrl_limit = newSt.upper_ctrl_limit;
pold->lower_ctrl_limit = newSt.lower_ctrl_limit;
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_LONG, &pold->value, &options,
&nRequest, pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
nRequest, pfl);
}
break;
case(oldDBR_CTRL_DOUBLE):
@@ -913,13 +750,10 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRctrlDouble
DBRalDouble
} newSt;
dbr_double_t *pvalue = &pold->value;
options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE |
DBR_CTRL_DOUBLE | DBR_AL_DOUBLE;
nRequest = 0;
status = dbGetField(paddr, DBR_DOUBLE, &newSt, &options, &nRequest,
pfl);
status = dbGetField(paddr, DBR_DOUBLE, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->precision = newSt.precision.dp;
@@ -934,10 +768,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
pold->upper_ctrl_limit = newSt.upper_ctrl_limit;
pold->lower_ctrl_limit = newSt.lower_ctrl_limit;
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_DOUBLE, &pold->value, &options,
&nRequest, pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
nRequest, pfl);
}
break;
@@ -947,21 +779,16 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
struct {
DBRstatus
} newSt;
DBSTRING *pvalue = (DBSTRING *)(pold->value);
options = DBR_STATUS;
nRequest = 0;
status = dbGetField(paddr, DBR_STRING, &newSt, &options, &nRequest,
pfl);
status = dbGetField(paddr, DBR_STRING, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->ackt = newSt.ackt;
pold->acks = newSt.acks;
options = 0;
nRequest = no_elements;
status = dbGetField(paddr, DBR_STRING, pold->value,
&options, &nRequest, pfl);
for (i = nRequest; i < no_elements; i++) pvalue[i][0] = 0;
&options, nRequest, pfl);
}
break;

View File

@@ -39,6 +39,9 @@ epicsShareFunc int epicsShareAPI db_put_field(
DBADDR *paddr, int src_type,const void *psrc, int no_elements);
epicsShareFunc int epicsShareAPI db_get_field(
DBADDR *paddr, int dest_type,void *pdest, int no_elements, void *pfl);
epicsShareFunc int db_get_field_and_count(
struct dbAddr *paddr, int buffer_type,
void *pbuffer, long *nRequest, void *pfl);
#ifdef __cplusplus

View File

@@ -507,6 +507,9 @@ static void read_reply ( void *pArg, struct dbAddr *paddr,
const int readAccess = asCheckGet ( pciu->asClientPVT );
int status;
int v41;
int autosize;
long item_count;
ca_uint32_t payload_size;
SEND_LOCK ( pClient );
@@ -528,12 +531,21 @@ static void read_reply ( void *pArg, struct dbAddr *paddr,
cid = pciu->cid;
}
status = cas_copy_in_header ( pClient, pevext->msg.m_cmmd, pevext->size,
pevext->msg.m_dataType, pevext->msg.m_count, cid, pevext->msg.m_available,
/* If the client has requested a zero element count we interpret this as a
* request for all avaiable elements. In this case we initialise the
* header with the maximum element size specified by the database. */
autosize = pevext->msg.m_count == 0;
item_count =
autosize ? paddr->no_elements : pevext->msg.m_count;
payload_size = dbr_size_n(pevext->msg.m_dataType, item_count);
status = cas_copy_in_header(
pClient, pevext->msg.m_cmmd, payload_size,
pevext->msg.m_dataType, item_count, cid, pevext->msg.m_available,
&pPayload );
if ( status != ECA_NORMAL ) {
send_err ( &pevext->msg, status, pClient,
"server unable to load read (or subscription update) response into protocol buffer PV=\"%s\" max bytes=%u",
"server unable to load read (or subscription update) response "
"into protocol buffer PV=\"%s\" max bytes=%u",
RECORD_NAME ( paddr ), rsrvSizeofLargeBufTCP );
if ( ! eventsRemaining )
cas_send_bs_msg ( pClient, FALSE );
@@ -552,8 +564,8 @@ static void read_reply ( void *pArg, struct dbAddr *paddr,
return;
}
status = db_get_field ( paddr, pevext->msg.m_dataType,
pPayload, pevext->msg.m_count, pfl);
status = db_get_field_and_count(
paddr, pevext->msg.m_dataType, pPayload, &item_count, pfl);
if ( status < 0 ) {
/*
* I cant wait to redesign this protocol from scratch!
@@ -567,58 +579,52 @@ static void read_reply ( void *pArg, struct dbAddr *paddr,
send_err ( &pevext->msg, ECA_GETFAIL, pClient, RECORD_NAME ( paddr ) );
}
else {
/*
* New clients recv the status of the
* operation directly to the
/* New clients recv the status of the operation directly to the
* event/put/get callback.
*
* Fetched value is set to zero in case they
* use it even when the status indicates
* failure.
* Fetched value is set to zero in case they use it even when the
* status indicates failure -- unless the client selected autosizing
* data, in which case they'd better know what they're doing!
*
* The m_cid field in the protocol
* header is abused to carry the status
*/
memset ( pPayload, 0, pevext->size );
* The m_cid field in the protocol header is abused to carry the
* status */
if (autosize) {
payload_size = dbr_size_n(pevext->msg.m_dataType, 0);
cas_set_header_count(pClient, 0);
}
memset ( pPayload, 0, payload_size );
cas_set_header_cid ( pClient, ECA_GETFAIL );
cas_commit_msg ( pClient, pevext->size );
cas_commit_msg ( pClient, payload_size );
}
}
else {
ca_uint32_t payloadSize = pevext->size;
int cacStatus = caNetConvert (
pevext->msg.m_dataType, pPayload, pPayload,
TRUE /* host -> net format */, pevext->msg.m_count );
if ( cacStatus == ECA_NORMAL ) {
/*
* force string message size to be the true size rounded to even
* boundary
*/
if ( pevext->msg.m_dataType == DBR_STRING
&& pevext->msg.m_count == 1 ) {
char * pStr = (char *) pPayload;
size_t strcnt = strlen ( pStr );
if ( strcnt < payloadSize ) {
payloadSize = ( ca_uint32_t ) ( strcnt + 1u );
}
else {
pStr[payloadSize-1] = '\0';
errlogPrintf (
"caserver: read_reply: detected DBR_STRING w/o nill termination "
"in response from db_get_field, pPayload = \"%s\"\n",
pStr );
}
TRUE /* host -> net format */, item_count );
if ( cacStatus == ECA_NORMAL ) {
ca_uint32_t data_size =
dbr_size_n(pevext->msg.m_dataType, item_count);
if (autosize) {
payload_size = data_size;
cas_set_header_count(pClient, item_count);
}
else if (payload_size > data_size)
memset(
(char *) pPayload + data_size, 0, payload_size - data_size);
}
else {
memset ( pPayload, 0, payloadSize );
if (autosize) {
payload_size = dbr_size_n(pevext->msg.m_dataType, 0);
cas_set_header_count(pClient, 0);
}
memset ( pPayload, 0, payload_size );
cas_set_header_cid ( pClient, cacStatus );
}
cas_commit_msg ( pClient, payloadSize );
}
cas_commit_msg ( pClient, payload_size );
}
/*
* Ensures timely response for events, but does que
* Ensures timely response for events, but does queue
* them up like db requests when the OPI does not keep up.
*/
if ( ! eventsRemaining )

View File

@@ -33,6 +33,10 @@
#define epicsExportSharedSymbols
#include "server.h"
/* As an optimisation, any message allocated with a large header is resized to
* use a small header if the payload size is below this threshold. */
#define SMALL_MESSAGE_THRESHOLD 65
/*
* cas_send_bs_msg()
*
@@ -253,6 +257,7 @@ int cas_copy_in_header (
{
unsigned msgSize;
ca_uint32_t alignedPayloadSize;
caHdr *pMsg;
if ( payloadSize > UINT_MAX - sizeof ( caHdr ) - 8u ) {
return ECA_TOLARGE;
@@ -292,32 +297,25 @@ int cas_copy_in_header (
}
}
if ( alignedPayloadSize < 0xffff && nElem < 0xffff ) {
caHdr *pMsg = ( caHdr * ) &pclient->send.buf[pclient->send.stk];
pMsg->m_cmmd = htons ( response );
pMsg->m_postsize = htons ( ( ( ca_uint16_t ) alignedPayloadSize ) );
pMsg->m_dataType = htons ( dataType );
pMsg->m_count = htons ( ( ( ca_uint16_t ) nElem ) );
pMsg->m_cid = htonl ( cid );
pMsg->m_available = htonl ( responseSpecific );
if ( ppPayload ) {
*ppPayload = ( void * ) ( pMsg + 1 );
}
pMsg = (caHdr *) &pclient->send.buf[pclient->send.stk];
pMsg->m_cmmd = htons(response);
pMsg->m_dataType = htons(dataType);
pMsg->m_cid = htonl(cid);
pMsg->m_available = htonl(responseSpecific);
if (alignedPayloadSize < 0xffff && nElem < 0xffff) {
pMsg->m_postsize = htons(((ca_uint16_t) alignedPayloadSize));
pMsg->m_count = htons(((ca_uint16_t) nElem));
if (ppPayload)
*ppPayload = (void *) (pMsg + 1);
}
else {
caHdr *pMsg = ( caHdr * ) &pclient->send.buf[pclient->send.stk];
ca_uint32_t *pW32 = ( ca_uint32_t * ) ( pMsg + 1 );
pMsg->m_cmmd = htons ( response );
pMsg->m_postsize = htons ( 0xffff );
pMsg->m_dataType = htons ( dataType );
pMsg->m_count = htons ( 0u );
pMsg->m_cid = htonl ( cid );
pMsg->m_available = htonl ( responseSpecific );
pW32[0] = htonl ( alignedPayloadSize );
pW32[1] = htonl ( nElem );
if ( ppPayload ) {
*ppPayload = ( void * ) ( pW32 + 2 );
}
ca_uint32_t *pW32 = (ca_uint32_t *) (pMsg + 1);
pMsg->m_postsize = htons(0xffff);
pMsg->m_count = htons(0u);
pW32[0] = htonl(alignedPayloadSize);
pW32[1] = htonl(nElem);
if (ppPayload)
*ppPayload = (void *) (pW32 + 2);
}
/* zero out pad bytes */
@@ -336,6 +334,22 @@ void cas_set_header_cid ( struct client *pClient, ca_uint32_t cid )
pMsg->m_cid = htonl ( cid );
}
void cas_set_header_count (struct client *pClient, ca_uint32_t count)
{
caHdr *pMsg = (caHdr *) &pClient->send.buf[pClient->send.stk];
if (pMsg->m_postsize == htons(0xffff)) {
ca_uint32_t *pLW;
assert(pMsg->m_count == 0);
pLW = (ca_uint32_t *) (pMsg + 1);
pLW[1] = htonl(count);
}
else {
assert(count < 65536);
pMsg->m_count = htons((ca_uint16_t) count);
}
}
void cas_commit_msg ( struct client *pClient, ca_uint32_t size )
{
caHdr * pMsg = ( caHdr * ) &pClient->send.buf[pClient->send.stk];
@@ -343,8 +357,19 @@ void cas_commit_msg ( struct client *pClient, ca_uint32_t size )
if ( pMsg->m_postsize == htons ( 0xffff ) ) {
ca_uint32_t * pLW = ( ca_uint32_t * ) ( pMsg + 1 );
assert ( size <= ntohl ( *pLW ) );
pLW[0] = htonl ( size );
size += sizeof ( caHdr ) + 2 * sizeof ( *pLW );
if (size < SMALL_MESSAGE_THRESHOLD) {
/* If the message is sufficiently small it can be worth converting a
* large message header into a small header. This saves us all of 8
* bytes over the wire, so it's not such a big deal. */
pMsg->m_postsize = htons((ca_uint16_t) size);
pMsg->m_count = htons((ca_uint16_t) ntohl(pLW[1]));
memmove(pLW, pLW + 2, size);
size += sizeof(caHdr);
}
else {
pLW[0] = htonl ( size );
size += sizeof ( caHdr ) + 2 * sizeof ( *pLW );
}
}
else {
assert ( size <= ntohs ( pMsg->m_postsize ) );

View File

@@ -27,7 +27,7 @@
#include "asLib.h"
#include "dbAddr.h"
#include "dbNotify.h"
#define CA_MINOR_PROTOCOL_REVISION 12
#define CA_MINOR_PROTOCOL_REVISION 13
#include "caProto.h"
#include "ellLib.h"
#include "epicsTime.h"
@@ -226,6 +226,7 @@ int cas_copy_in_header (
ca_uint16_t dataType, ca_uint32_t nElem, ca_uint32_t cid,
ca_uint32_t responseSpecific, void **pPayload );
void cas_set_header_cid ( struct client *pClient, ca_uint32_t );
void cas_set_header_count (struct client *pClient, ca_uint32_t count);
void cas_commit_msg ( struct client *pClient, ca_uint32_t size );
#endif /*INCLserverh*/