EPICS Controls Argonne National Laboratory

Experimental Physics and
Industrial Control System

2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  <20142015  2016  2017  2018  2019  2020  2021  2022  2023  2024  Index 2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  <20142015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
<== Date ==> <== Thread ==>

Subject: auto-configure EPICS_CA_MAX_ARRAY_BYTES in catools/caget
From: "Hu, Yong" <[email protected]>
To: "[email protected]" <[email protected]>
Date: Thu, 5 Jun 2014 18:40:06 +0000
Hello All,

I guess many EPICS users, especially beginners, had problems when using the command "caget" to read large waveform data because they forgot to reconfigure EPICS_CA_MAX_ARRAY_BYTES to a bigger number or they didn't know how to configure this parameter. Now, this problem seems to be fixed. See attached patch or .c file. I tested it on Debian 6 / gcc 4.4.5 / base-3.14.12.2.

I hope no users would use the command "camonitor" for big waveform data. Auto-configuring of EPICS_CA_MAX_ARRAY_BYTES in camonitor seems more complicated.  

Two years ago, there were discussions about automatically resizing max_array_bytes: http://www.aps.anl.gov/epics/tech-talk/2012/msg02136.php . I have an idea about how to implement this on the ioc side (RSRV), but no progress has been made yet. We just successfully completed NSLS-II Storage Ring phase-I commissioning and our machine is in maintenance. So, I have some free time to work on this again.   

All are welcomed to test the attached caget on Windows, Mac, and other Linux distros. Any idea & suggestion is welcomed!

Yong
--- src/catools/caget.c.orig	2014-06-04 11:00:41.760259462 -0400
+++ src/catools/caget.c	2014-06-05 14:29:54.897362881 -0400
@@ -37,6 +37,10 @@
 
 #include "tool_lib.h"
 
+#include "envDefs.h"
+#include "caProto.h"
+#include <stdlib.h>
+
 #define VALID_DOUBLE_DIGITS 18  /* Max usable precision for a double */
 #define PEND_EVENT_SLICES 5     /* No. of pend_event slices for callback requests */
 
@@ -389,6 +393,13 @@
 
     LINE_BUFFER(stdout);        /* Configure stdout buffering */
 
+    unsigned long nElems = 0;
+    long maxBytesAsALong = 0;
+    unsigned long bytes = 0;
+    unsigned long minBytes = 0;
+    unsigned headerSize;
+    char strMinBytes[17];
+
     while ((opt = getopt(argc, argv, ":taicnhsSe:f:g:l:#:d:0:w:p:F:")) != -1) {
         switch (opt) {
         case 'h':               /* Print usage */
@@ -520,14 +531,15 @@
         fprintf(stderr, "No pv name specified. ('caget -h' for help.)\n");
         return 1;
     }
-                                /* Start up Channel Access */
 
+                                /* Start up Channel Access */
     result = ca_context_create(ca_disable_preemptive_callback);
     if (result != ECA_NORMAL) {
         fprintf(stderr, "CA error %s occurred while trying "
                 "to start channel access.\n", ca_message(result));
         return 1;
     }
+
                                 /* Allocate PV structure array */
 
     pvs = calloc (nPvs, sizeof(pv));
@@ -543,6 +555,53 @@
 
     connect_pvs(pvs, nPvs);
 
+    /*get the value of EPICS_CA_MAX_ARRAY_BYTES*/
+    if (0 != envGetLongConfigParam ( &EPICS_CA_MAX_ARRAY_BYTES, &maxBytesAsALong )){
+        printf("Odd: can't get the value of EPICS_CA_MAX_ARRAY_BYTES\n");
+        maxBytesAsALong = 1024*16u;
+    }
+
+    /*minimum bytes required for the ca_get: element * sizeof(native-field-type) + ca-header*/
+    for (n = 0; n < nPvs; n++) {
+        nElems = ca_element_count(pvs[n].chid);
+        if (nElems < 1) {/*disconnected PV*/
+            continue;
+        }
+        pvs[n].dbfType = ca_field_type(pvs[n].chid);
+        bytes = nElems * dbr_size[pvs[n].dbfType];
+        if (bytes > minBytes) {
+            minBytes = bytes;
+        }
+    }
+    /*codes stolen from rsrv_init()*/
+    headerSize = sizeof ( caHdr ) + 2 * sizeof ( ca_uint32_t );
+    if ( minBytes < 0xffffffff - headerSize) {
+        minBytes += headerSize;
+    }
+    else {
+        minBytes = 0xffffffff;
+    }
+
+    /*big operation: reconfigure EPICS_CA_MAX_ARRAY_BYTES, clear channels, destroy context ...*/
+    if (maxBytesAsALong < minBytes) {
+        sprintf(strMinBytes, "%ld", minBytes);
+        /*epicsEnvSet("EPICS_CA_MAX_ARRAY_BYTES", strMinBytes);*/
+        if (0 != setenv("EPICS_CA_MAX_ARRAY_BYTES", strMinBytes, 1)){
+            printf("Odd: can't reconfigure EPICS_CA_MAX_ARRAY_BYTES to %d\n", minBytes);
+        }
+        /*clearing channel seems not enough, have to start over:
+          clear channels, destroy context and recreate it, then connect pvs again
+        */
+         for (n = 0; n < nPvs; n++) {
+             if (ECA_NORMAL != ca_clear_channel(pvs[n].chid)){
+                 printf("Odd: can't clear channel\n");
+             }
+         }
+         ca_context_destroy();
+         ca_context_create(ca_disable_preemptive_callback);
+         connect_pvs(pvs, nPvs);
+    }
+
                                 /* Read and print data */
 
     result = caget(pvs, nPvs, request, format, type, count);
/*************************************************************************\
* Copyright (c) 2009 Helmholtz-Zentrum Berlin fuer Materialien und Energie.
* Copyright (c) 2006 Diamond Light Source Ltd.
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
*     National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
*     Operator of Los Alamos National Laboratory.
* Copyright (c) 2002 Berliner Elektronenspeicherringgesellschaft fuer
*     Synchrotronstrahlung.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution. 
\*************************************************************************/

/*
 *  Author: Ralph Lange (BESSY)
 *
 *  Modification History
 *  2006/01/17 Malcolm Walters (Tessella/Diamond Light Source)
 *     Fixed problem with "-c -w 0" hanging forever
 *  2008/04/16 Ralph Lange (BESSY)
 *     Updated usage info
 *  2009/03/31 Larry Hoff (BNL)
 *     Added field separators
 *  2009/04/01 Ralph Lange (HZB/BESSY)
 *     Added support for long strings (array of char) and quoting of nonprintable characters
 *
 */

#include <stdio.h>
#include <string.h>
#include <epicsStdlib.h>
#include <epicsString.h>

#include <alarm.h>
#include <cadef.h>
#include <epicsGetopt.h>

#include "tool_lib.h"

#include "envDefs.h"
#include "caProto.h"
#include <stdlib.h>

#define VALID_DOUBLE_DIGITS 18  /* Max usable precision for a double */
#define PEND_EVENT_SLICES 5     /* No. of pend_event slices for callback requests */

/* Different output formats */
typedef enum { plain, terse, all, specifiedDbr } OutputT;

/* Different request types */
typedef enum { get, callback } RequestT;

static int nConn = 0;           /* Number of connected PVs */
static int nRead = 0;           /* Number of channels that were read */
static int floatAsString = 0;   /* Flag: fetch floats as string */


static void usage (void)
{
    fprintf (stderr, "\nUsage: caget [options] <PV name> ...\n\n"
    "  -h: Help: Print this message\n"
    "Channel Access options:\n"
    "  -w <sec>: Wait time, specifies CA timeout, default is %f second(s)\n"
    "  -c: Asynchronous get (use ca_get_callback and wait for completion)\n"
    "  -p <prio>: CA priority (0-%u, default 0=lowest)\n"
    "Format options:\n"
    "      Default output format is \"name value\"\n"
    "  -t: Terse mode - print only value, without name\n"
    "  -a: Wide mode \"name timestamp value stat sevr\" (read PVs as DBR_TIME_xxx)\n"
    "  -d <type>: Request specific dbr type; use string (DBR_ prefix may be omitted)\n"
    "      or number of one of the following types:\n"
    " DBR_STRING     0  DBR_STS_FLOAT    9  DBR_TIME_LONG   19  DBR_CTRL_SHORT    29\n"
    " DBR_INT        1  DBR_STS_ENUM    10  DBR_TIME_DOUBLE 20  DBR_CTRL_INT      29\n"
    " DBR_SHORT      1  DBR_STS_CHAR    11  DBR_GR_STRING   21  DBR_CTRL_FLOAT    30\n"
    " DBR_FLOAT      2  DBR_STS_LONG    12  DBR_GR_SHORT    22  DBR_CTRL_ENUM     31\n"
    " DBR_ENUM       3  DBR_STS_DOUBLE  13  DBR_GR_INT      22  DBR_CTRL_CHAR     32\n"
    " DBR_CHAR       4  DBR_TIME_STRING 14  DBR_GR_FLOAT    23  DBR_CTRL_LONG     33\n"
    " DBR_LONG       5  DBR_TIME_INT    15  DBR_GR_ENUM     24  DBR_CTRL_DOUBLE   34\n"
    " DBR_DOUBLE     6  DBR_TIME_SHORT  15  DBR_GR_CHAR     25  DBR_STSACK_STRING 37\n"
    " DBR_STS_STRING 7  DBR_TIME_FLOAT  16  DBR_GR_LONG     26  DBR_CLASS_NAME    38\n"
    " DBR_STS_SHORT  8  DBR_TIME_ENUM   17  DBR_GR_DOUBLE   27\n"
    " DBR_STS_INT    8  DBR_TIME_CHAR   18  DBR_CTRL_STRING 28\n"
    "Enum format:\n"
    "  -n: Print DBF_ENUM value as number (default is enum string)\n"
    "Arrays: Value format: print number of requested values, then list of values\n"
    "  Default:    Print all values\n"
    "  -# <count>: Print first <count> elements of an array\n"
    "  -S:         Print array of char as a string (long string)\n"
    "Floating point type format:\n"
    "  Default: Use %%g format\n"
    "  -e <nr>: Use %%e format, with a precision of <nr> digits\n"
    "  -f <nr>: Use %%f format, with a precision of <nr> digits\n"
    "  -g <nr>: Use %%g format, with a precision of <nr> digits\n"
    "  -s:      Get value as string (honors server-side precision)\n"
    "  -lx:     Round to long integer and print as hex number\n"
    "  -lo:     Round to long integer and print as octal number\n"
    "  -lb:     Round to long integer and print as binary number\n"
    "Integer number format:\n"
    "  Default: Print as decimal number\n"
    "  -0x: Print as hex number\n"
    "  -0o: Print as octal number\n"
    "  -0b: Print as binary number\n"
    "Alternate output field separator:\n"
    "  -F <ofs>: Use <ofs> as an alternate output field separator\n"
    "\nExample: caget -a -f8 my_channel another_channel\n"
    "  (uses wide output format, doubles are printed as %%f with precision of 8)\n\n"
             , DEFAULT_TIMEOUT, CA_PRIORITY_MAX);
}



/*+**************************************************************************
 *
 * Function:	event_handler
 *
 * Description:	CA event_handler for request type callback
 * 		Allocates the dbr structure and copies the data
 *
 * Arg(s) In:	args  -  event handler args (see CA manual)
 *
 **************************************************************************-*/

static void event_handler (evargs args)
{
    pv* ppv = args.usr;

    ppv->status = args.status;
    if (args.status == ECA_NORMAL)
    {
        ppv->dbrType = args.type;
        ppv->value   = calloc(1, dbr_size_n(args.type, args.count));
        memcpy(ppv->value, args.dbr, dbr_size_n(args.type, args.count));
        ppv->nElems = args.count;
        nRead++;
    }
}



/*+**************************************************************************
 *
 * Function:	caget
 *
 * Description:	Issue read requests, wait for incoming data
 * 		and print the data according to the selected format
 *
 * Arg(s) In:	pvs       -  Pointer to an array of pv structures
 *              nPvs      -  Number of elements in the pvs array
 *              request   -  Request type
 *              format    -  Output format
 *              dbrType   -  Requested dbr type
 *              reqElems  -  Requested number of (array) elements
 *
 * Return(s):	Error code: 0 = OK, 1 = Error
 *
 **************************************************************************-*/
 
static int caget (pv *pvs, int nPvs, RequestT request, OutputT format,
           chtype dbrType, unsigned long reqElems)
{
    unsigned int i;
    int n, result;

    for (n = 0; n < nPvs; n++) {
        unsigned long nElems;

                                /* Set up pvs structure */
                                /* -------------------- */

                                /* Get natural type and array count */
        nElems         = ca_element_count(pvs[n].chid);
        pvs[n].dbfType = ca_field_type(pvs[n].chid);
        pvs[n].dbrType = dbrType;

                                /* Set up value structures */
        if (format != specifiedDbr)
        {
            pvs[n].dbrType = dbf_type_to_DBR_TIME(pvs[n].dbfType); /* Use native type */
            if (dbr_type_is_ENUM(pvs[n].dbrType))                  /* Enums honour -n option */
            {
                if (enumAsNr) pvs[n].dbrType = DBR_TIME_INT;
                else          pvs[n].dbrType = DBR_TIME_STRING;
            }
            else if (floatAsString &&
                     (dbr_type_is_FLOAT(pvs[n].dbrType) || dbr_type_is_DOUBLE(pvs[n].dbrType)))
            {
                pvs[n].dbrType = DBR_TIME_STRING;
            }
        }

                                /* Issue CA request */
                                /* ---------------- */

        if (ca_state(pvs[n].chid) == cs_conn)
        {
            nConn++;
            pvs[n].onceConnected = 1;
            if (request == callback)
            {
                /* Event handler will allocate value and set nElems */
                pvs[n].reqElems = reqElems > nElems ? nElems : reqElems;
                result = ca_array_get_callback(pvs[n].dbrType,
                                               pvs[n].reqElems,
                                               pvs[n].chid,
                                               event_handler,
                                               (void*)&pvs[n]);
            } else {
                /* We allocate value structure and set nElems */
                pvs[n].nElems = reqElems && reqElems < nElems ? reqElems : nElems;
                pvs[n].value = calloc(1, dbr_size_n(pvs[n].dbrType, pvs[n].nElems));
                if (!pvs[n].value) {
                    fprintf(stderr,"Memory allocation failed\n");
                    return 1;
                }
                result = ca_array_get(pvs[n].dbrType,
                                      pvs[n].nElems,
                                      pvs[n].chid,
                                      pvs[n].value);
            }
            pvs[n].status = result;
        } else {
            pvs[n].status = ECA_DISCONN;
        }
    }
    if (!nConn) return 1;              /* No connection? We're done. */

                                /* Wait for completion */
                                /* ------------------- */

    result = ca_pend_io(caTimeout);
    if (result == ECA_TIMEOUT)
        fprintf(stderr, "Read operation timed out: some PV data was not read.\n");

    if (request == callback)    /* Also wait for callbacks */
    {
        if (caTimeout != 0)
        {
            double slice = caTimeout / PEND_EVENT_SLICES;
            for (n = 0; n < PEND_EVENT_SLICES; n++)
            {
                ca_pend_event(slice);
                if (nRead >= nConn) break;
            }
            if (nRead < nConn)
                fprintf(stderr, "Read operation timed out: some PV data was not read.\n");
        } else {
            /* For 0 timeout keep waiting until all are done */
            while (nRead < nConn) {
                  ca_pend_event(1.0);
            }
        }
    }

                                /* Print the data */
                                /* -------------- */

    for (n = 0; n < nPvs; n++) {

        switch (format) {
        case plain:             /* Emulate old caget behaviour */
            if (pvs[n].nElems <= 1 && fieldSeparator == ' ') printf("%-30s", pvs[n].name);
            else                                               printf("%s", pvs[n].name);
            printf("%c", fieldSeparator);
        case terse:
            if (pvs[n].status == ECA_DISCONN)
                printf("*** not connected\n");
            else if (pvs[n].status == ECA_NORDACCESS)
                printf("*** no read access\n");
            else if (pvs[n].status != ECA_NORMAL)
                printf("*** CA error %s\n", ca_message(pvs[n].status));
            else if (pvs[n].value == 0)
                printf("*** no data available (timeout)\n");
            else
            {
                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));
                    if(d) {
                        epicsStrnEscapedFromRaw(d, dlen+1, (char*)s, strlen((char*)s));
                        printf("%s", d);
                        free(d);
                    } else {
                        fprintf(stderr,"Failed to allocate space for escaped string\n");
                    }
                } else {
                    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));
                    }
                }
                printf("\n");
            }
            break;
        case all:
            print_time_val_sts(&pvs[n], reqElems);
            break;
        case specifiedDbr:
            printf("%s\n", pvs[n].name);
            if (pvs[n].status == ECA_DISCONN)
                printf("    *** not connected\n");
            else if (pvs[n].status == ECA_NORDACCESS)
                printf("    *** no read access\n");
            else if (pvs[n].status != ECA_NORMAL)
                printf("    *** CA error %s\n", ca_message(pvs[n].status));
            else
            {
                printf("    Native data type: %s\n",
                       dbf_type_to_text(pvs[n].dbfType));
                printf("    Request type:     %s\n",
                       dbr_type_to_text(pvs[n].dbrType));
                if (pvs[n].dbrType == DBR_CLASS_NAME)
                    printf("    Class Name:       %s\n",
                           *((dbr_string_t*)dbr_value_ptr(pvs[n].value,
                                                          pvs[n].dbrType)));
                else {
                    printf("    Element count:    %lu\n"
                           "    Value:            ",
                           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));
                        if(d) {
                            epicsStrnEscapedFromRaw(d, dlen+1, (char*)s, strlen((char*)s));
                            printf("%s", d);
                            free(d);
                        } else {
                            fprintf(stderr,"Failed to allocate space for escaped string\n");
                        }
                    } else {
                        for (i=0; i<pvs[n].nElems; ++i) {
                            if (i) printf ("%c", fieldSeparator);
                            printf("%s", val2str(pvs[n].value, pvs[n].dbrType, i));
                        }
                    }
                    printf("\n");
                    if (pvs[n].dbrType > DBR_DOUBLE) /* Extended type extra info */
                        printf("%s\n", dbr2str(pvs[n].value, pvs[n].dbrType));
                }
            }
            break;
        default :
            break;
        }
    }
    return 0;
}



/*+**************************************************************************
 *
 * Function:	main
 *
 * Description:	caget main()
 * 		Evaluate command line options, set up CA, connect the
 * 		channels, collect and print the data as requested
 *
 * Arg(s) In:	[options] <pv-name> ...
 *
 * Arg(s) Out:	none
 *
 * Return(s):	Standard return code (0=success, 1=error)
 *
 **************************************************************************-*/

static void complainIfNotPlainAndSet (OutputT *current, const OutputT requested)
{
    if (*current != plain) 
        fprintf(stderr,
                "Options t,d,a are mutually exclusive. "
                "('caget -h' for help.)\n");
    *current = requested;
}

int main (int argc, char *argv[])
{
    int n;
    int result;                 /* CA result */
    OutputT format = plain;     /* User specified format */
    RequestT request = get;     /* User specified request type */
    IntFormatT outType;         /* Output type */

    int count = 0;              /* 0 = not specified by -# option */
    int opt;                    /* getopt() current option */
    int type = -1;              /* getopt() data type argument */
    int digits = 0;             /* getopt() no. of float digits */

    int nPvs;                   /* Number of PVs */
    pv* pvs;                    /* Array of PV structures */

    LINE_BUFFER(stdout);        /* Configure stdout buffering */

    unsigned long nElems = 0;
    long maxBytesAsALong = 0;
    unsigned long bytes = 0;
    unsigned long minBytes = 0;
    unsigned headerSize;
    char strMinBytes[17];

    while ((opt = getopt(argc, argv, ":taicnhsSe:f:g:l:#:d:0:w:p:F:")) != -1) {
        switch (opt) {
        case 'h':               /* Print usage */
            usage();
            return 0;
        case 't':               /* Terse output mode */
            complainIfNotPlainAndSet(&format, terse);
            break;
        case 'a':               /* Wide output mode */
            complainIfNotPlainAndSet(&format, all);
            break;
        case 'c':               /* Callback mode */
            request = callback;
            break;
        case 'd':               /* Data type specification */
            complainIfNotPlainAndSet(&format, specifiedDbr);
                                /* Argument (type) may be text or number */
            if (sscanf(optarg, "%d", &type) != 1)
            {
                dbr_text_to_type(optarg, type);
                if (type == -1)                   /* Invalid? Try prefix DBR_ */
                {
                    char str[30] = "DBR_";
                    strncat(str, optarg, 25);
                    dbr_text_to_type(str, type);
                }
            }
            if (type < DBR_STRING       || type > DBR_CLASS_NAME
                || type == DBR_PUT_ACKT || type == DBR_PUT_ACKS)
            {
                fprintf(stderr, "Requested dbr type out of range "
                        "or invalid - ignored. ('caget -h' for help.)\n");
                format = plain;
            }
            break;
        case 'n':               /* Print ENUM as index numbers */
            enumAsNr = 1;
            break;
        case 'w':               /* Set CA timeout value */
            if(epicsScanDouble(optarg, &caTimeout) != 1)
            {
                fprintf(stderr, "'%s' is not a valid timeout value "
                        "- ignored. ('caget -h' for help.)\n", optarg);
                caTimeout = DEFAULT_TIMEOUT;
            }
            break;
        case '#':               /* Array count */
            if (sscanf(optarg,"%d", &count) != 1)
            {
                fprintf(stderr, "'%s' is not a valid array element count "
                        "- ignored. ('caget -h' for help.)\n", optarg);
                count = 0;
            }
            break;
        case 'p':               /* CA priority */
            if (sscanf(optarg,"%u", &caPriority) != 1)
            {
                fprintf(stderr, "'%s' is not a valid CA priority "
                        "- ignored. ('caget -h' for help.)\n", optarg);
                caPriority = DEFAULT_CA_PRIORITY;
            }
            if (caPriority > CA_PRIORITY_MAX) caPriority = CA_PRIORITY_MAX;
            break;
        case 's':               /* Select string dbr for floating type data */
            floatAsString = 1;
            break;
        case 'S':               /* Treat char array as (long) string */
            charArrAsStr = 1;
            break;
        case 'e':               /* Select %e/%f/%g format, using <arg> digits */
        case 'f':
        case 'g':
            if (sscanf(optarg, "%d", &digits) != 1)
                fprintf(stderr, 
                        "Invalid precision argument '%s' "
                        "for option '-%c' - ignored.\n", optarg, opt);
            else
            {
                if (digits>=0 && digits<=VALID_DOUBLE_DIGITS)
                    sprintf(dblFormatStr, "%%-.%d%c", digits, opt);
                else
                    fprintf(stderr, "Precision %d for option '-%c' "
                            "out of range - ignored.\n", digits, opt);
            }
            break;
        case 'l':               /* Convert to long and use integer format */
        case '0':               /* Select integer format */
            switch ((char) *optarg) {
            case 'x': outType = hex; break;    /* x print Hex */
            case 'b': outType = bin; break;    /* b print Binary */
            case 'o': outType = oct; break;    /* o print Octal */
            default :
                outType = dec;
                fprintf(stderr, "Invalid argument '%s' "
                        "for option '-%c' - ignored.\n", optarg, opt);
            }
            if (outType != dec) {
              if (opt == '0') {
                type = DBR_LONG;
                outTypeI = outType;
              } else {
                outTypeF = outType;
              }
            }
            break;
        case 'F':               /* Store this for output and tool_lib formatting */
            fieldSeparator = (char) *optarg;
            break;
        case '?':
            fprintf(stderr,
                    "Unrecognized option: '-%c'. ('caget -h' for help.)\n",
                    optopt);
            return 1;
        case ':':
            fprintf(stderr,
                    "Option '-%c' requires an argument. ('caget -h' for help.)\n",
                    optopt);
            return 1;
        default :
            usage();
            return 1;
        }
    }

    nPvs = argc - optind;       /* Remaining arg list are PV names */

    if (nPvs < 1)
    {
        fprintf(stderr, "No pv name specified. ('caget -h' for help.)\n");
        return 1;
    }

                                /* Start up Channel Access */
    result = ca_context_create(ca_disable_preemptive_callback);
    if (result != ECA_NORMAL) {
        fprintf(stderr, "CA error %s occurred while trying "
                "to start channel access.\n", ca_message(result));
        return 1;
    }

                                /* Allocate PV structure array */

    pvs = calloc (nPvs, sizeof(pv));
    if (!pvs)
    {
        fprintf(stderr, "Memory allocation for channel structures failed.\n");
        return 1;
    }
                                /* Connect channels */

    for (n = 0; optind < argc; n++, optind++)
        pvs[n].name = argv[optind] ;       /* Copy PV names from command line */

    connect_pvs(pvs, nPvs);

    /*get the value of EPICS_CA_MAX_ARRAY_BYTES*/
    if (0 != envGetLongConfigParam ( &EPICS_CA_MAX_ARRAY_BYTES, &maxBytesAsALong )){
        printf("Odd: can't get the value of EPICS_CA_MAX_ARRAY_BYTES\n");
        maxBytesAsALong = 1024*16u;
    }

    /*minimum bytes required for the ca_get: element * sizeof(native-field-type) + ca-header*/
    for (n = 0; n < nPvs; n++) {
        nElems = ca_element_count(pvs[n].chid);
        if (nElems < 1) {/*disconnected PV*/
            continue;
        }
        pvs[n].dbfType = ca_field_type(pvs[n].chid);
        bytes = nElems * dbr_size[pvs[n].dbfType];
        if (bytes > minBytes) {
            minBytes = bytes;
        }
    }
    /*codes stolen from rsrv_init()*/
    headerSize = sizeof ( caHdr ) + 2 * sizeof ( ca_uint32_t );
    if ( minBytes < 0xffffffff - headerSize) {
        minBytes += headerSize;
    }
    else {
        minBytes = 0xffffffff;
    }

    /*big operation: reconfigure EPICS_CA_MAX_ARRAY_BYTES, clear channels, destroy context ...*/
    if (maxBytesAsALong < minBytes) {
        sprintf(strMinBytes, "%ld", minBytes);
        /*epicsEnvSet("EPICS_CA_MAX_ARRAY_BYTES", strMinBytes);*/
        if (0 != setenv("EPICS_CA_MAX_ARRAY_BYTES", strMinBytes, 1)){
            printf("Odd: can't reconfigure EPICS_CA_MAX_ARRAY_BYTES to %d\n", minBytes);
        }
        /*clearing channel seems not enough, have to start over:
          clear channels, destroy context and recreate it, then connect pvs again
        */
         for (n = 0; n < nPvs; n++) {
             if (ECA_NORMAL != ca_clear_channel(pvs[n].chid)){
                 printf("Odd: can't clear channel\n");
             }
         }
         ca_context_destroy();
         ca_context_create(ca_disable_preemptive_callback);
         connect_pvs(pvs, nPvs);
    }

                                /* Read and print data */

    result = caget(pvs, nPvs, request, format, type, count);

                                /* Shut down Channel Access */
    ca_context_destroy();

    return result;
}

Replies:
Re: auto-configure EPICS_CA_MAX_ARRAY_BYTES in catools/caget Eric Norum

Navigate by Date:
Prev: Jenkins build is back to stable : epics-base-3.15 #54 APS Jenkins
Next: Re: auto-configure EPICS_CA_MAX_ARRAY_BYTES in catools/caget Eric Norum
Index: 2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  <20142015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
Navigate by Thread:
Prev: Jenkins build is back to stable : epics-base-3.15 #54 APS Jenkins
Next: Re: auto-configure EPICS_CA_MAX_ARRAY_BYTES in catools/caget Eric Norum
Index: 2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  <20142015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
ANJ, 05 Jun 2014 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·