+= connection status reporting (based on Jeff's suggestions plus timestamps for connection loss events)
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user