diff --git a/src/catools/camonitor.c b/src/catools/camonitor.c index a0fae501e..b068915e6 100644 --- a/src/catools/camonitor.c +++ b/src/catools/camonitor.c @@ -27,6 +27,7 @@ #define VALID_DOUBLE_DIGITS 18 /* Max usable precision for a double */ +static unsigned long reqElems = 0; static int nConn = 0; /* Number of connected PVs */ static unsigned long eventMask = DBE_VALUE | DBE_ALARM; /* Event mask used */ @@ -91,82 +92,70 @@ void event_handler (evargs args) } } - /*+************************************************************************** * - * Function: camonitor + * Function: connection_handler * - * Description: Issue read requests, wait for incoming data - * and print the data according to the selected format + * Description: CA connection_handler * - * Arg(s) In: pvs - Pointer to an array of pv structures - * nPvs - Number of elements in the pvs array - * reqElems - Requested number of (array) elements - * - * Return(s): Error code: 0 = OK, 1 = Error + * Arg(s) In: args - connection_handler_args (see CA manual) * **************************************************************************-*/ - -int camonitor (pv *pvs, int nPvs, unsigned long reqElems) + +void connection_handler ( struct connection_handler_args args ) { - int n, result; - chtype dbrType; - - for (n = 0; n < nPvs; n++) { - - /* Set up pvs structure */ - /* -------------------- */ + pv *ppv = ( pv * ) ca_puser ( args.chid ); + if ( args.op == CA_OP_CONN_UP ) { + int dbrType; + /* Set up pv 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); + ppv->nElems = ca_element_count(ppv->chid); + ppv->dbfType = ca_field_type(ppv->chid); /* Set up value structures */ - dbrType = dbf_type_to_DBR_TIME(pvs[n].dbfType); /* Use native type */ + dbrType = dbf_type_to_DBR_TIME(ppv->dbfType); /* Use native type */ if (dbr_type_is_ENUM(dbrType)) /* Enums honour -n option */ { if (enumAsNr) dbrType = DBR_TIME_INT; else dbrType = DBR_TIME_STRING; } /* Adjust array count */ - if (reqElems == 0 || pvs[n].nElems < reqElems) - reqElems = pvs[n].nElems; + if (reqElems == 0 || ppv->nElems < reqElems) + reqElems = ppv->nElems; /* Remember dbrType and reqElems */ - pvs[n].dbrType = dbrType; - pvs[n].reqElems = reqElems; - + ppv->dbrType = dbrType; + ppv->reqElems = reqElems; + nConn++; /* Issue CA request */ /* ---------------- */ - - if (ca_state(pvs[n].chid) == cs_conn) - { - nConn++; - /* Allocate value structure */ - pvs[n].value = calloc(1, dbr_size_n(dbrType, reqElems)); - - result = ca_create_subscription(dbrType, - reqElems, - pvs[n].chid, - eventMask, - event_handler, - (void*)&pvs[n], - NULL); - pvs[n].status = result; - } else { - pvs[n].status = ECA_DISCONN; + /* install monitor once with first connect */ + if ( ! ppv->value ) { + /* Allocate value structure */ + ppv->value = calloc(1, dbr_size_n(dbrType, reqElems)); + if ( ppv->value ) { + ppv->status = ca_create_subscription(dbrType, + reqElems, + ppv->chid, + eventMask, + event_handler, + (void*)ppv, + NULL); + if ( ppv->status != ECA_NORMAL ) { + free ( ppv->value ); + } + } } } - - if (nConn) - /* Wait for callbacks */ - /* ------------------ */ - while (1) ca_pend_event(caTimeout); - else - return 1; /* No connection? We're done. */ + else if ( args.op == CA_OP_CONN_DOWN ) { + nConn--; + ppv->status = ECA_DISCONN; + print_time_val_sts(ppv, ppv->reqElems); + } } - /*+************************************************************************** * @@ -186,10 +175,10 @@ int camonitor (pv *pvs, int nPvs, unsigned long reqElems) int main (int argc, char *argv[]) { + int returncode = 0; int n = 0; int result; /* CA result */ - int count = 0; /* 0 = not specified by -# option */ int opt; /* getopt() current option */ int digits = 0; /* getopt() no. of float digits */ @@ -224,11 +213,11 @@ int main (int argc, char *argv[]) } break; case '#': /* Array count */ - if (sscanf(optarg,"%d", &count) != 1) + if (sscanf(optarg,"%ld", &reqElems) != 1) { fprintf(stderr, "'%s' is not a valid array element count " "- ignored. ('caget -h' for help.)\n", optarg); - count = 0; + reqElems = 0; } break; case 'm': /* Select CA event mask */ @@ -316,14 +305,27 @@ int main (int argc, char *argv[]) } /* Connect channels */ + /* Copy PV names from command line */ for (n = 0; optind < argc; n++, optind++) - pvs[n].name = argv[optind] ; /* Copy PV names from command line */ + { + pvs[n].name = argv[optind]; + pvs[n].status = ECA_NEWCONN; + } + /* Create CA connections */ + returncode = create_pvs(pvs, nPvs, connection_handler); + if ( returncode ) { + return returncode; + } + /* Check for channels that didn't connect */ + ca_pend_event(caTimeout); + for (n = 0; n < nPvs; n++) + { + if (pvs[n].status == ECA_NEWCONN) + print_time_val_sts(&pvs[n], pvs[n].reqElems); + } - connect_pvs(pvs, nPvs); - - /* Read and print data */ - - result = camonitor(pvs, nPvs, count); + /* Read and print data forever */ + ca_pend_event(0); /* Shut down Channel Access */ ca_context_destroy(); diff --git a/src/catools/tool_lib.c b/src/catools/tool_lib.c index bd0db687d..d75daa135 100644 --- a/src/catools/tool_lib.c +++ b/src/catools/tool_lib.c @@ -426,6 +426,7 @@ void print_time_val_sts (pv* pv, int nElems) int i, printAbs; void* value = pv->value; epicsTimeStamp *ptsRef = &tsStart; + epicsTimeStamp tsNow; if (!tsInit) /* Initialize start timestamp */ { @@ -434,15 +435,20 @@ void print_time_val_sts (pv* pv, int nElems) tsInit = 1; } + epicsTimeGetCurrent(&tsNow); + epicsTimeToStrftime(timeText, TIMETEXTLEN, timeFormatStr, &tsNow); + printf("%-30s ", pv->name); - if (pv->status == ECA_DISCONN) - printf("*** not connected\n"); + if (pv->status == ECA_NEWCONN) + printf("*** Not connected (PV not found)\n"); + else if (pv->status == ECA_DISCONN) + printf("%s *** disconnected\n", timeText); else if (pv->status == ECA_NORDACCESS) - printf("*** no read access\n"); + printf("%s *** no read access\n", timeText); else if (pv->status != ECA_NORMAL) - printf("*** CA error %s\n", ca_message(pv->status)); + printf("%s *** CA error %s\n", timeText, ca_message(pv->status)); else if (pv->value == 0) - printf("*** no data available (timeout)\n"); + printf("%s *** no data available (timeout)\n", timeText); else switch (pv->dbrType) { case DBR_TIME_STRING: @@ -470,6 +476,48 @@ void print_time_val_sts (pv* pv, int nElems) } } + +/*+************************************************************************** + * + * Function: create_pvs + * + * Description: Creates an arbitrary number of PVs + * + * Arg(s) In: pvs - Pointer to an array of pv structures + * nPvs - Number of elements in the pvs array + * pCB - Connection state change callback + * + * Arg(s) Out: none + * + * Return(s): Error code: + * 0 - All PVs created + * 1 - Some PV(s) not created + * + **************************************************************************-*/ + +int create_pvs (pv* pvs, int nPvs, caCh *pCB) +{ + int n; + int result; + int returncode = 0; + /* Issue channel connections */ + for (n = 0; n < nPvs; n++) { + result = ca_create_channel (pvs[n].name, + pCB, + &pvs[n], + 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; + } + } + + return returncode; +} + /*+************************************************************************** * @@ -490,36 +538,21 @@ void print_time_val_sts (pv* pv, int nElems) 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; + int returncode = create_pvs ( pvs, nPvs, 0); + if ( returncode == 0 ) { + /* Wait for channels to connect */ + int result = ca_pend_io (caTimeout); + 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; } } - /* Wait for channels to connect */ - result = ca_pend_io (caTimeout); - 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 index 0804f0186..0487293b2 100644 --- a/src/catools/tool_lib.h +++ b/src/catools/tool_lib.h @@ -80,7 +80,8 @@ 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 (pv *pv, int nElems); -extern int connect_pvs (pv *pvs, int nPvs); +extern int create_pvs (pv *pvs, int nPvs, caCh *pCB ); +extern int connect_pvs (pv *pvs, int nPvs ); /* * no additions below this endif