diff --git a/src/catools/Makefile b/src/catools/Makefile new file mode 100644 index 000000000..b24e91eb6 --- /dev/null +++ b/src/catools/Makefile @@ -0,0 +1,34 @@ +#************************************************************************* +# 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 Versions 3.13.7 +# and higher are distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. +#************************************************************************* +TOP=../.. + +include $(TOP)/configure/CONFIG + +SHARED_LIBRARIES = NO +#STATIC_BUILD=YES + +LIBRARY_HOST += catools + +catools_SRCS += tool_lib.c +catools_LIBS += ca Com + +#Remove LIBNAME from the library names to be installed (make it a local library) +INSTALL_LIBS= $(addprefix $(INSTALL_LIB)/,$(filterout $(TESTLIBNAME),$(LIBNAME))) + +PROD_HOST += caget + +caget_SRCS += caget.c +caget_LIBS += catools ca Com + +catools_DIR=. + +include $(TOP)/configure/RULES diff --git a/src/catools/caget.c b/src/catools/caget.c new file mode 100644 index 000000000..6086d582f --- /dev/null +++ b/src/catools/caget.c @@ -0,0 +1,471 @@ +/*************************************************************************\ +* 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 Versions 3.13.7 +* and higher are distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ +/* + * $Id$ + * + * Author: Ralph Lange (BESSY) + * + */ + +#include +#include +#include +#include + +#if defined(_WIN32) +#include +#endif + +#include +#include +#include + +#include "tool_lib.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 */ + + +void usage (void) +{ + fprintf (stderr, "\nUsage: caget [options] ...\n\n" + " -h: Help: Print this message\n" + "Channel Access options:\n" + " -w : Wait time, specifies longer CA timeout, default is %f second\n" + " -c: Asynchronous get (use ca_get_callback instead of ca_get)\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" + " -n: Print DBF_ENUM values as number (default are enum string values)\n" + " -d : 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" + "Arrays: Value format: print number of requested values, then list of values\n" + " Default: Print all values\n" + " -# : Print first elements of an array\n" + "Floating point type format:\n" + " Default: Use g format\n" + " -f : Use f format, with digits after the decimal point\n" + " -e : Use e format, with digits after the decimal point\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" + "\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); +} + + + +/*+************************************************************************** + * + * 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) + * + **************************************************************************-*/ + +void event_handler (evargs args) +{ + pv* pv = args.usr; + + pv->status = args.status; + if (args.status == ECA_NORMAL) + { + pv->dbrType = args.type; + pv->value = calloc(1, dbr_size_n(args.type, args.count)); + memcpy(pv->value, args.dbr, dbr_size_n(args.type, 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 + * + **************************************************************************-*/ + +/* caget - Get PV values */ +int caget (pv *pvs, int nPvs, RequestT request, OutputT format, + chtype dbrType, unsigned long reqElems) +{ + int i, n, result; + + for (n = 0; n < nPvs; n++) { + + /* Set up pvs structure */ + /* -------------------- */ + + /* Get natural type and array count */ + pvs[n].nElems = ca_element_count(pvs[n].chid); + pvs[n].dbfType = ca_field_type(pvs[n].chid); + + /* Set up value structures */ + if (format != specifiedDbr) + { + dbrType = dbf_type_to_DBR_TIME(pvs[n].dbfType); /* Use native type */ + if (dbr_type_is_ENUM(dbrType)) /* Enums honour -n option */ + { + if (charAsNr) dbrType = DBR_TIME_INT; + else dbrType = DBR_TIME_STRING; + } + } + /* Adjust array count */ + if (reqElems == 0 || pvs[n].nElems < reqElems) + reqElems = pvs[n].nElems; + /* Remember dbrType and reqElems */ + pvs[n].dbrType = dbrType; + pvs[n].reqElems = reqElems; + + /* Issue CA request */ + /* ---------------- */ + + if (ca_state(pvs[n].chid) == cs_conn) + { + nConn++; + if (request == callback) + { /* Event handler will allocate value */ + result = ca_array_get_callback(dbrType, + reqElems, + pvs[n].chid, + event_handler, + (void*)&pvs[n]); + } else { + /* Allocate value structure */ + pvs[n].value = calloc(1, dbr_size_n(dbrType, reqElems)); + result = ca_array_get(dbrType, + reqElems, + 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(timeout); + if (result == ECA_TIMEOUT) + fprintf(stderr, "Read operation timed out: some PV data was not read.\n"); + + if (request == callback) /* Also wait for callbacks */ + { + double slice = timeout / 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"); + } + + /* Print the data */ + /* -------------- */ + + for (n = 0; n < nPvs; n++) { + reqElems = pvs[n].reqElems; + + switch (format) { + case plain: /* Emulate old caget behaviour */ + if (reqElems <= 1) printf("%-30s ", pvs[n].name); + else printf("%s", pvs[n].name); + 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 (reqElems > 1) printf(" %lu ", reqElems); + for (i=0; i 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] ... + * + * Arg(s) Out: none + * + * Return(s): Standard return code (0=success, 1=error) + * + **************************************************************************-*/ + +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 = 0; + int result; /* CA result */ + OutputT format = plain; /* User specified format */ + RequestT request = get; /* User specified request 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 = 0; /* Array of PV structures */ + + setvbuf(stdout,NULL,_IOLBF,0); /* Set stdout to line buffering */ + + while ((opt = getopt(argc, argv, ":taicnhe:f:#:d:0:w:")) != -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 */ + charAsNr=1; + break; + case 'w': /* Set CA timeout value */ + if(sscanf(optarg,"%lf", &timeout) != 1) + { + fprintf(stderr, "'%s' is not a valid timeout value " + "- ignored. ('caget -h' for help.)\n", optarg); + timeout = 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 'e': /* Select %e format, using digits */ + if (sscanf(optarg, "%d", &digits) != 1) + fprintf(stderr, + "Invalid precision argument '%s' " + "for option '-e' - ignored.\n", optarg); + else + { + if (digits>=0 && digits<=VALID_DOUBLE_DIGITS) + sprintf(dblFormatStr, "%%-.%de", digits); + else + fprintf(stderr, "Precision %d for option '-e' " + "out of range - ignored.\n", digits); + } + break; + case 'f': /* Select %f format, using digits */ + if (sscanf(optarg, "%d", &digits) != 1) + fprintf(stderr, "Invalid precision argument '%s' " + "for option '-f' - ignored.\n", optarg); + else + { + if (digits>=0 && digits<=VALID_DOUBLE_DIGITS) + sprintf(dblFormatStr, "%%-.%df", digits); + else + fprintf(stderr, "Precision %d for option '-f' " + "out of range - ignored.\n", digits); + } + break; + case '0': /* Select integer format */ + type = DBR_LONG; + switch ((char) *optarg) { + case 'x': outType = hex; break; /* 0x print Hex */ + case 'b': outType = bin; break; /* 0b print Binary */ + case 'o': outType = oct; break; /* 0o print Octal */ + default : + fprintf(stderr, "Invalid argument '%s' " + "for option '-0' - ignored.\n", 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 '%s'.\n", ca_message(result), pvs[n].name); + 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); + + /* Read and print data */ + + result = caget(pvs, nPvs, request, format, type, count); + + /* Shut down Channel Access */ + ca_context_destroy(); + + return result; +} diff --git a/src/catools/tool_lib.c b/src/catools/tool_lib.c new file mode 100644 index 000000000..d80b05d05 --- /dev/null +++ b/src/catools/tool_lib.c @@ -0,0 +1,517 @@ +/*************************************************************************\ +* 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 Versions 3.13.7 +* and higher are distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ +/* + * $Id$ + * + * Author: Ralph Lange (BESSY) + * + */ + +#include +#include +#include +#include + +#if defined(_WIN32) +#include +#endif + +#define epicsAlarmGLOBAL +#include +#undef epicsAlarmGLOBAL +#include +#include + +#include "tool_lib.h" + +/* Time stamps for program start, previous value (used for differential + * times with monitors) */ +static TS_STAMP tsStart, tsPrev; + +static int tsInit = 0; /* Flag: Timestamps init'd */ +static int firstStampPrinted = 0; /* Flag: First timestamp already printed */ + +TimeT tsType = absTime; /* Timestamp type flag (-q or -Q option) */ +IntFormatT outType = dec; /* For -0.. output format option */ + +char dblFormatStr[30] = "%g"; /* Format string to print doubles (see -e -f option) */ + +int charAsNr = 0; /* used for -n option - get DBF_CHAR as number */ +double timeout = 1.0; /* wait time default (see -w option) */ + + + +void sprint_long (char *ret, long val) +{ + long i, bit, skip=-1L; /* used only for printing bits */ + switch (outType) { + case hex: sprintf(ret, "0x%lX", val); break; + case oct: sprintf(ret, "0o%lo", val); break; + case bin: + for (i=31; i>=0 ; i--) + { + bit = (val>>i) & 0x1L; + if (skip<0 && bit) + { + skip = 31 - i; /* skip leading 0's */ + ret[i+1] = '\0'; + } + if (skip >= 0) + { + ret[31-i-skip] = (bit) ? '1' : '0'; + } + } + break; + default: sprintf(ret, "%ld", val); /* decimal */ + } +} + + + +/*+************************************************************************** + * + * Function: val2str + * + * Description: Print (convert) value to a string + * + * Arg(s) In: v - Pointer to dbr_... structure + * type - Numeric dbr type + * index - Index of element to print (for arrays) + * + * Return(s): Pointer to static output string + * + **************************************************************************-*/ + +char *val2str (const void *v, unsigned type, int index) +{ + static char str[500]; + char ch; + void *val_ptr; + unsigned base_type; + + if (!dbr_type_is_valid(type)) { + strcpy (str, "*** invalid type"); + return str; + } + + base_type = type % (LAST_TYPE+1); + + if (type == DBR_STSACK_STRING || type == DBR_CLASS_NAME) + base_type = DBR_STRING; + + val_ptr = dbr_value_ptr(v, type); + + switch (base_type) { + case DBR_STRING: + sprintf(str, "%s", ((dbr_string_t*)val_ptr)[index]); + break; + case DBR_FLOAT: + sprintf(str, dblFormatStr, ((dbr_float_t*) val_ptr)[index]); + break; + case DBR_DOUBLE: + sprintf(str, dblFormatStr, ((dbr_double_t*)val_ptr)[index]); + break; + case DBR_CHAR: + ch = ((dbr_char_t*) val_ptr)[index]; + if(ch > 31 ) + sprintf(str, "%d \'%c\'",ch,ch); + else + sprintf(str, "%d",ch); + break; + case DBR_INT: + sprint_long(str, ((dbr_int_t*) val_ptr)[index]); + break; + case DBR_LONG: + sprint_long(str, ((dbr_long_t*) val_ptr)[index]); + break; + case DBR_ENUM: + { + dbr_enum_t *val = (dbr_enum_t *)val_ptr; + if (dbr_type_is_GR(type)) + sprintf(str,"%s (%d)", + ((struct dbr_gr_enum *)v)->strs[val[index]],val[index]); + else if (dbr_type_is_CTRL(type)) + sprintf(str,"%s (%d)", + ((struct dbr_ctrl_enum *)v)->strs[val[index]],val[index]); + else + sprintf(str, "%d", val[index]); + } + } + return str; +} + + + +/*+************************************************************************** + * + * Function: dbr2str + * + * Description: Print (convert) additional information contained in dbr_... + * + * Arg(s) In: value - Pointer to dbr_... structure + * type - Numeric dbr type + * + * Return(s): Pointer to static output string + * + **************************************************************************-*/ + +/* Definitions for sprintf format strings and matching argument lists */ + +#define FMT_TIME \ + " Timestamp: %s" + +#define ARGS_TIME(T) \ + tsStampToText( &(((struct T *)value)->stamp), \ + TS_TEXT_MMDDYY, \ + timeText) + +#define FMT_STS \ + " Status: %s\n" \ + " Severity: %s" + +#define ARGS_STS(T) \ + stat_to_str(((struct T *)value)->status), \ + sevr_to_str(((struct T *)value)->severity) + +#define FMT_ACK \ + " Ack transient?: %s\n" \ + " Ack severity: %s" + +#define ARGS_ACK(T) \ + ((struct T *)value)->ackt ? "YES" : "NO", \ + sevr_to_str(((struct T *)value)->acks) + +#define FMT_UNITS \ + " Units: %s" + +#define ARGS_UNITS(T) \ + ((struct T *)value)->units + +#define FMT_PREC \ + " Precision: %d" + +#define ARGS_PREC(T) \ + ((struct T *)value)->precision + +#define FMT_GR(FMT) \ + " Lo disp limit: " #FMT "\n" \ + " Hi disp limit: " #FMT "\n" \ + " Lo alarm limit: " #FMT "\n" \ + " Lo warn limit: " #FMT "\n" \ + " Hi warn limit: " #FMT "\n" \ + " Hi alarm limit: " #FMT + +#define ARGS_GR(T,F) \ + (F)((struct T *)value)->lower_disp_limit, \ + (F)((struct T *)value)->upper_disp_limit, \ + (F)((struct T *)value)->lower_alarm_limit, \ + (F)((struct T *)value)->lower_warning_limit, \ + (F)((struct T *)value)->upper_warning_limit, \ + (F)((struct T *)value)->upper_alarm_limit + +#define FMT_CTRL(FMT) \ + " Lo ctrl limit: " #FMT "\n" \ + " Hi ctrl limit: " #FMT + +#define ARGS_CTRL(T,F) \ + (F)((struct T *)value)->lower_ctrl_limit, \ + (F)((struct T *)value)->upper_ctrl_limit + + +/* Definitions for the actual sprintf calls */ + +#define PRN_DBR_STS(T) \ + sprintf(str, \ + FMT_STS, \ + ARGS_STS(T)) + +#define PRN_DBR_TIME(T) \ + sprintf(str, \ + FMT_TIME "\n" FMT_STS, \ + ARGS_TIME(T), ARGS_STS(T)) + +#define PRN_DBR_GR(T,F,FMT) \ + sprintf(str, \ + FMT_STS "\n" FMT_UNITS "\n" FMT_GR(FMT), \ + ARGS_STS(T), ARGS_UNITS(T), ARGS_GR(T,F)) + +#define PRN_DBR_GR_PREC(T,F,FMT) \ + sprintf(str, \ + FMT_STS "\n" FMT_UNITS "\n" FMT_PREC "\n" FMT_GR(FMT), \ + ARGS_STS(T), ARGS_UNITS(T), ARGS_PREC(T), ARGS_GR(T,F)) + +#define PRN_DBR_CTRL(T,F,FMT) \ + sprintf(str, \ + FMT_STS "\n" FMT_UNITS "\n" FMT_GR(FMT) "\n" FMT_CTRL(FMT), \ + ARGS_STS(T), ARGS_UNITS(T), ARGS_GR(T,F), ARGS_CTRL(T,F)) + +#define PRN_DBR_CTRL_PREC(T,F,FMT) \ + sprintf(str, \ + FMT_STS "\n" FMT_UNITS "\n" FMT_PREC "\n" FMT_GR(FMT) "\n" FMT_CTRL(FMT), \ + ARGS_STS(T), ARGS_UNITS(T), ARGS_PREC(T), ARGS_GR(T,F), ARGS_CTRL(T,F)) + +#define PRN_DBR_STSACK(T) \ + sprintf(str, \ + FMT_STS "\n" FMT_ACK, \ + ARGS_STS(T), ARGS_ACK(T)) + +#define PRN_DBR_X_ENUM(T) \ + n = ((struct T *)value)->no_str; \ + PRN_DBR_STS(T); \ + sprintf(str+strlen(str), \ + "\n Enums: (%2d)", n); \ + for (i=0; istrs[i]); + + +/* Make a good guess how long the dbr_... stuff might get as worst case */ +#define DBR_PRINT_BUFFER_SIZE \ + 50 /* timestamp */ \ + + 2 * 30 /* status / Severity */ \ + + 2 * 30 /* acks / ackt */ \ + + 20 + MAX_UNITS_SIZE /* units */ \ + + 30 /* precision */ \ + + 6 * 45 /* graphic limits */ \ + + 2 * 45 /* control limits */ \ + + 30 + (MAX_ENUM_STATES * (20 + MAX_ENUM_STRING_SIZE)) /* enums */ \ + + 50 /* just to be sure */ + +char *dbr2str (const void *value, unsigned type) +{ + static char str[DBR_PRINT_BUFFER_SIZE]; + char timeText[28]; + int n, i; + + switch (type) { + case DBR_STRING: /* no additional information for basic data types */ + case DBR_INT: + case DBR_FLOAT: + case DBR_ENUM: + case DBR_CHAR: + case DBR_LONG: + case DBR_DOUBLE: break; + + case DBR_CTRL_STRING: /* see db_access.h: not implemented */ + case DBR_GR_STRING: /* see db_access.h: not implemented */ + case DBR_STS_STRING: PRN_DBR_STS(dbr_sts_string); break; + case DBR_STS_SHORT: PRN_DBR_STS(dbr_sts_short); break; + case DBR_STS_FLOAT: PRN_DBR_STS(dbr_sts_float); break; + case DBR_STS_ENUM: PRN_DBR_STS(dbr_sts_enum); break; + case DBR_STS_CHAR: PRN_DBR_STS(dbr_sts_char); break; + case DBR_STS_LONG: PRN_DBR_STS(dbr_sts_long); break; + case DBR_STS_DOUBLE: PRN_DBR_STS(dbr_sts_double); break; + + case DBR_TIME_STRING: PRN_DBR_TIME(dbr_time_string); break; + case DBR_TIME_SHORT: PRN_DBR_TIME(dbr_time_short); break; + case DBR_TIME_FLOAT: PRN_DBR_TIME(dbr_time_float); break; + case DBR_TIME_ENUM: PRN_DBR_TIME(dbr_time_enum); break; + case DBR_TIME_CHAR: PRN_DBR_TIME(dbr_time_char); break; + case DBR_TIME_LONG: PRN_DBR_TIME(dbr_time_long); break; + case DBR_TIME_DOUBLE: PRN_DBR_TIME(dbr_time_double); break; + + case DBR_GR_CHAR: + PRN_DBR_GR(dbr_gr_char, char, %8d); break; + case DBR_GR_INT: + PRN_DBR_GR(dbr_gr_int, int, %8d); break; + case DBR_GR_LONG: + PRN_DBR_GR(dbr_gr_long, long int, %8ld); break; + case DBR_GR_FLOAT: + PRN_DBR_GR_PREC(dbr_gr_float, float, %g); break; + case DBR_GR_DOUBLE: + PRN_DBR_GR_PREC(dbr_gr_double, double, %g); break; + case DBR_GR_ENUM: + PRN_DBR_X_ENUM(dbr_gr_enum); break; + case DBR_CTRL_CHAR: + PRN_DBR_CTRL(dbr_ctrl_char, char, %8d); break; + case DBR_CTRL_INT: + PRN_DBR_CTRL(dbr_ctrl_int, int, %8d); break; + case DBR_CTRL_LONG: + PRN_DBR_CTRL(dbr_ctrl_long, long int, %8ld); break; + case DBR_CTRL_FLOAT: + PRN_DBR_CTRL_PREC(dbr_ctrl_float, float, %g); break; + case DBR_CTRL_DOUBLE: + PRN_DBR_CTRL_PREC(dbr_ctrl_double, double, %g); break; + case DBR_CTRL_ENUM: + PRN_DBR_X_ENUM(dbr_ctrl_enum); break; + case DBR_STSACK_STRING: + PRN_DBR_STSACK(dbr_stsack_string); break; + default : strcpy (str, "can't print data type"); + } + return str; +} + +/* tsDef.h: TsDiffAsDouble macro defined in 3.13 is no longer available in 3.14 */ +double tsDiffDbl(TS_STAMP *ts1, TS_STAMP * ts2) +{ + double tdiff; + tdiff = ( ((double) ts1->nsec) - ((double)ts2->nsec)) / 1000000000.; + tdiff += ((double) ts1->secPastEpoch) - ((double)ts2->secPastEpoch); + return tdiff; +} + + +/*+************************************************************************** + * + * Function: print_time_val_sts + * + * Description: Print (to stdout) one wide output line + * (name, timestamp, value, status, severity) + * + * Arg(s) In: pv - Pointer to pv structure + * nElems - Number of elements (array) + * + **************************************************************************-*/ + +#define PRN_TIME_VAL_STS(TYPE,TYPE_ENUM) \ + if (!tsInit) \ + { /* Initialise reference timestamp */ \ + tsStart = tsPrev = ((struct TYPE *)value)->stamp; \ + tsInit = 1; \ + } \ + /* Print Timestamp */ \ + if (!firstStampPrinted) \ + { /* First stamp is always absolute */ \ + printf("%s ", tsStampToText(&(((struct TYPE *)value)->stamp), \ + TS_TEXT_MMDDYY, timeText)); \ + firstStampPrinted = 1; \ + } else { \ + switch (tsType) { \ + case incTime: /* The following can be incremental, */ \ + printf("%10.4fs ", \ + tsDiffDbl( &(((struct TYPE *)value)->stamp), \ + &tsPrev) ); \ + break; \ + case relTime: /* relative, */ \ + printf("%10.4fs ", \ + tsDiffDbl( &(((struct TYPE *)value)->stamp), \ + &tsStart)); \ + break; \ + default : /* or also absolute */ \ + printf("%s ", \ + tsStampToText( &(((struct TYPE *)value)->stamp), \ + TS_TEXT_MMDDYY, timeText)); \ + break; \ + } \ + } \ + tsPrev = ((struct TYPE *)value)->stamp; \ + /* Print Values */ \ + for (i=0; istatus || ((struct TYPE *)value)->severity ) \ + { \ + printf("%s %s\n", \ + stat_to_str(((struct TYPE *)value)->status), \ + sevr_to_str(((struct TYPE *)value)->severity)); \ + } else { \ + printf("\n"); \ + } + + +void print_time_val_sts (const pv* pv, int nElems) +{ + char timeText[28]; + int i; + void* value = pv->value; + + printf("%-30s ", pv->name); + if (pv->status == ECA_DISCONN) + printf("*** not connected\n"); + else if (pv->status == ECA_NORDACCESS) + printf("*** no read access\n"); + else if (pv->status != ECA_NORMAL) + printf("*** CA error %s\n", ca_message(pv->status)); + else if (pv->value == 0) + printf("*** no data available (timeout)\n"); + else + switch (pv->dbrType) { + case DBR_TIME_STRING: + PRN_TIME_VAL_STS(dbr_time_string, DBR_TIME_STRING); + break; + case DBR_TIME_SHORT: + PRN_TIME_VAL_STS(dbr_time_short, DBR_TIME_SHORT); + break; + case DBR_TIME_FLOAT: + PRN_TIME_VAL_STS(dbr_time_float, DBR_TIME_FLOAT); + break; + case DBR_TIME_ENUM: + PRN_TIME_VAL_STS(dbr_time_enum, DBR_TIME_ENUM); + break; + case DBR_TIME_CHAR: + PRN_TIME_VAL_STS(dbr_time_char, DBR_TIME_CHAR); + break; + case DBR_TIME_LONG: + PRN_TIME_VAL_STS(dbr_time_long, DBR_TIME_LONG); + break; + case DBR_TIME_DOUBLE: + PRN_TIME_VAL_STS(dbr_time_double, DBR_TIME_DOUBLE); + break; + default: printf("can't print data type\n"); + } +} + + +/*+************************************************************************** + * + * Function: connect_pvs + * + * Description: Connects an arbitrary number of PVs + * + * Arg(s) In: pvs - Pointer to an array of pv structures + * nPvs - Number of elements in the pvs array + * + * Arg(s) Out: none + * + * Return(s): Error code: + * 0 - All PVs connected + * 1 - Some PV(s) not connected + * + **************************************************************************-*/ + +int connect_pvs (pv* pvs, int nPvs) +{ + int n; + int result; + int returncode = 0; + /* Issue channel connections */ + for (n = 0; n < nPvs; n++) { + result = ca_create_channel (pvs[n].name, + 0, + 0, + CA_PRIORITY, + &pvs[n].chid); + if (result != ECA_NORMAL) { + fprintf(stderr, "CA error %s occurred while trying " + "to create channel '%s'.\n", ca_message(result), pvs[n].name); + pvs[n].status = result; + returncode = 1; + } + } + /* Wait for channels to connect */ + result = ca_pend_io (timeout); + if (result == ECA_TIMEOUT) + { + if (nPvs > 1) + { + fprintf(stderr, "Channel connect timed out: some PV(s) not found.\n"); + } else { + fprintf(stderr, "Channel connect timed out: '%s' not found.\n", + pvs[0].name); + } + returncode = 1; + } + + return returncode; +} diff --git a/src/catools/tool_lib.h b/src/catools/tool_lib.h new file mode 100644 index 000000000..137ed2488 --- /dev/null +++ b/src/catools/tool_lib.h @@ -0,0 +1,71 @@ +/*************************************************************************\ +* 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 Versions 3.13.7 +* and higher are distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ +/* + * $Id$ + * + * Author: Ralph Lange (BESSY) + * + */ + +#ifndef INCLtool_libh +#define INCLtool_libh + +/* Convert status and severity to strings */ +#define stat_to_str(stat) \ + ((stat) >= 0 && (stat) <= (signed)lastEpicsAlarmCond) ? \ + epicsAlarmConditionStrings[stat] : "??" + +#define sevr_to_str(stat) \ + ((stat) >= 0 && (stat) <= (signed)lastEpicsAlarmSev) ? \ + epicsAlarmSeverityStrings[stat] : "??" + + +#define CA_PRIORITY 50 /* CA priority */ +#define DEFAULT_TIMEOUT 1.0 /* Default CA timeout */ + + +/* Type of timestamp (absolute, relative, incremental) */ +typedef enum { absTime, relTime, incTime } TimeT; + +/* Output formats for integer data types */ +typedef enum { dec, bin, oct, hex } IntFormatT; + +/* Structure representing one PV (= channel) */ +typedef struct +{ + char* name; + chid chid; + long dbfType; + long dbrType; + unsigned long nElems; + unsigned long reqElems; + int status; + void* value; +} pv; + + +extern TimeT tsType; /* Timestamp type flag (-q or -Q option) */ +extern IntFormatT outType; /* Flag used for -0.. output format option */ +extern int charAsNr; /* Used for -n option (get DBF_CHAR as number) */ +extern double timeout; /* Wait time default (see -w option) */ +extern char dblFormatStr[]; /* Format string to print doubles (see -e -f option) */ + + +extern char *val2str (const void *v, unsigned type, int index); +extern char *dbr2str (const void *value, unsigned type); +extern void print_time_val_sts (const pv *pv, int nElems); +extern int connect_pvs (pv *pvs, int nPvs); + +/* + * no additions below this endif + */ +#endif /* ifndef INCLtool_libh */