diff --git a/src/ca/CAref.html b/src/ca/CAref.html
index 5145585b6..89d35e14e 100644
--- a/src/ca/CAref.html
+++ b/src/ca/CAref.html
@@ -6,10 +6,11 @@
EPICS R3.14 Channel Access Reference Manual
@@ -411,7 +412,8 @@ other facility is already using the default port numbers. The default Channel
Access port numbers have been registered with IANA.
-
+
+
| Purpose |
Default |
@@ -1330,19 +1332,18 @@ the output.
| Default: |
- Print absolute timestamps (as reported by CA) |
+ Print absolute timestamps (as reported by CA server) |
- | -r |
- Relative timestamps (time elapsed since start of program) |
-
-
- | -i |
- Incremental timestamps (time elapsed since last update) |
-
-
- | -I |
- Incremental timestamps (time elapsed since last update for this
+ | -t <key> |
+ Specify timestamp source(s) and type, with <key>
+ containing
+ 's' = CA server (remote) timestamps
+ 'c' = CA client (local) timestamps (shown in '()'s)
+ 'n' = no timestamps
+ 'r' = relative timestamps (time elapsed since start of program)
+ 'i' = incremental timestamps (time elapsed since last update)
+ 'I' = incremental timestamps (time elapsed since last update, by
channel) |
diff --git a/src/catools/camonitor.c b/src/catools/camonitor.c
index 2be6eb5bd..06ab8a83e 100644
--- a/src/catools/camonitor.c
+++ b/src/catools/camonitor.c
@@ -45,10 +45,14 @@ void usage (void)
" -m : Specify CA event mask to use, with being any combination of\n"
" 'v' (value), 'a' (alarm), 'l' (log). Default: va\n"
"Timestamps:\n"
- " Default: Print absolute timestamps (as reported by CA)\n"
- " -r: Relative timestamps (time elapsed since start of program)\n"
- " -i: Incremental timestamps (time elapsed since last update)\n"
- " -I: Incremental timestamps (time elapsed since last update for this channel)\n"
+ " Default: Print absolute timestamps (as reported by CA server)\n"
+ " -t : Specify timestamp source(s) and type, with containing\n"
+ " 's' = CA server (remote) timestamps\n"
+ " 'c' = CA client (local) timestamps (shown in '()'s)\n"
+ " 'n' = No timestamps\n"
+ " 'r' = relative timestamps (time elapsed since start of program)\n"
+ " 'i' = incremental timestamps (time elapsed since last update)\n"
+ " 'I' = incremental timestamps (time elapsed since last update, by channel)\n"
"Enum format:\n"
" -n: Print DBF_ENUM values as number (default are enum string values)\n"
"Arrays: Value format: print number of requested values, then list of values\n"
@@ -204,7 +208,7 @@ int main (int argc, char *argv[])
setvbuf(stdout,NULL,_IOLBF,BUFSIZ); /* Set stdout to line buffering */
- while ((opt = getopt(argc, argv, ":nhriIm:se:f:g:#:d:0:w:")) != -1) {
+ while ((opt = getopt(argc, argv, ":nhm:se:f:g:#:d:0:w:t:")) != -1) {
switch (opt) {
case 'h': /* Print usage */
usage();
@@ -212,14 +216,25 @@ int main (int argc, char *argv[])
case 'n': /* Print ENUM as index numbers */
enumAsNr=1;
break;
- case 'r': /* Select relative timestamps */
- tsType = relative;
- break;
- case 'i': /* Select incremental timestamps */
- tsType = incremental;
- break;
- case 'I': /* Select incremental timestamps (by channel) */
- tsType = incrementalByChan;
+ case 't': /* Select timestamp source(s) and type */
+ tsSrcServer = 0;
+ tsSrcClient = 0;
+ {
+ int i = 0;
+ char c;
+ while ((c = optarg[i++]))
+ switch (c) {
+ case 's': tsSrcServer = 1; break;
+ case 'c': tsSrcClient = 1; break;
+ case 'n': break;
+ case 'r': tsType = relative; break;
+ case 'i': tsType = incremental; break;
+ case 'I': tsType = incrementalByChan; break;
+ default :
+ fprintf(stderr, "Invalid argument '%c' "
+ "for option '-t' - ignored.\n", c);
+ }
+ }
break;
case 'w': /* Set CA timeout value */
if(epicsScanDouble(optarg, &caTimeout) != 1)
diff --git a/src/catools/tool_lib.c b/src/catools/tool_lib.c
index 4bbe08a52..1db0a5503 100644
--- a/src/catools/tool_lib.c
+++ b/src/catools/tool_lib.c
@@ -28,13 +28,17 @@
#include "tool_lib.h"
-/* Time stamps for program start, previous value (used for relative resp.
- * incremental times with monitors) */
-static epicsTimeStamp tsStart, tsPrevious;
+/* Time stamps for program start, first incoming monitor,
+ previous value (client and server stamp):
+ used for relative resp. incremental timestamps with monitors */
+static epicsTimeStamp tsStart, tsFirst, tsPreviousC, tsPreviousS;
-static int tsInit = 0; /* Flag: Timestamps init'd */
+static int tsInitS = 0; /* Flag: Server timestamps init'd */
+static int tsInitC = 0; /* Flag: Client timestamps init'd */
-TimeT tsType = absolute; /* Timestamp type flag (-riI options) */
+TimeT tsType = absolute; /* Timestamp type flag (-t option) */
+int tsSrcServer = 1; /* Timestamp source flag (-t option) */
+int tsSrcClient = 0; /* Timestamp source flag (-t option) */
IntFormatT outType = dec; /* For -0.. output format option */
char dblFormatStr[30] = "%g"; /* Format string to print doubles (-efg options) */
@@ -366,80 +370,91 @@ char *dbr2str (const void *value, unsigned type)
*
**************************************************************************-*/
-#define PRN_TIME_VAL_STS(TYPE,TYPE_ENUM) \
- printAbs = 0; \
- \
- switch (tsType) { \
- case relative: \
- ptsRef = &tsStart; \
- break; \
- case incremental: \
- ptsRef = &tsPrevious; \
- break; \
- case incrementalByChan: \
- ptsRef = &pv->tsPrevious; \
- break; \
- default : \
- printAbs = 1; \
- } \
- \
- if (!printAbs) { \
- if (pv->firstStampPrinted) \
- { \
- printf("%10.4fs ", epicsTimeDiffInSeconds( \
- &(((struct TYPE *)value)->stamp), ptsRef) ); \
- } else { /* First stamp is always absolute */ \
- printAbs = 1; \
- pv->firstStampPrinted = 1; \
- } \
- } \
- \
- if (tsType == incrementalByChan) \
- pv->tsPrevious = ((struct TYPE *)value)->stamp; \
- \
- if (printAbs) { \
- epicsTimeToStrftime(timeText, TIMETEXTLEN, timeFormatStr, \
- &(((struct TYPE *)value)->stamp)); \
- printf("%s ", timeText); \
- } \
- \
- tsPrevious = ((struct TYPE *)value)->stamp; \
- \
- /* Print count if array */ \
- if ( nElems > 1 ) printf("%lu ", nElems); \
- /* 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"); \
+#define PRN_TIME_VAL_STS(TYPE,TYPE_ENUM) \
+ printAbs = !pv->firstStampPrinted; \
+ \
+ ptsNewS = &((struct TYPE *)value)->stamp; \
+ ptsNewC = &tsNow; \
+ \
+ switch (tsType) { \
+ case relative: \
+ ptsRefC = &tsStart; \
+ ptsRefS = &tsFirst; \
+ break; \
+ case incremental: \
+ ptsRefC = &tsPreviousC; \
+ ptsRefS = &tsPreviousS; \
+ break; \
+ case incrementalByChan: \
+ ptsRefC = &pv->tsPreviousC; \
+ ptsRefS = &pv->tsPreviousS; \
+ break; \
+ default : \
+ printAbs = 1; \
+ } \
+ \
+ if (printAbs) { \
+ if (tsSrcServer) { \
+ epicsTimeToStrftime(timeText, TIMETEXTLEN, timeFormatStr, ptsNewS); \
+ printf("%s ", timeText); \
+ } \
+ if (tsSrcClient) { \
+ epicsTimeToStrftime(timeText, TIMETEXTLEN, timeFormatStr, ptsNewC); \
+ printf("(%s) ", timeText); \
+ } \
+ pv->firstStampPrinted = 1; \
+ } else { \
+ if (tsSrcServer) { \
+ printf(" %+12.6f ", epicsTimeDiffInSeconds(ptsNewS, ptsRefS) ); \
+ } \
+ if (tsSrcClient) { \
+ printf(" (%+12.6f) ", epicsTimeDiffInSeconds(ptsNewC, ptsRefC) ); \
+ } \
+ } \
+ \
+ if (tsType == incrementalByChan) { \
+ pv->tsPreviousC = *ptsNewC; \
+ pv->tsPreviousS = *ptsNewS; \
+ } \
+ \
+ tsPreviousC = *ptsNewC; \
+ tsPreviousS = *ptsNewS; \
+ \
+ /* Print count if array */ \
+ if ( nElems > 1 ) printf("%lu ", nElems); \
+ /* 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 (pv* pv, unsigned long nElems)
{
- char timeText[TIMETEXTLEN];
+ char timeText[2*TIMETEXTLEN+2];
int i, printAbs;
void* value = pv->value;
- epicsTimeStamp *ptsRef = &tsStart;
+ epicsTimeStamp *ptsRefC, *ptsRefS; /* Reference timestamps (client, server) */
+ epicsTimeStamp *ptsNewC, *ptsNewS; /* Update timestamps (client, server) */
epicsTimeStamp tsNow;
- if (!tsInit) /* Initialize start timestamp */
- {
- epicsTimeGetCurrent(&tsStart);
- tsPrevious = tsStart;
- tsInit = 1;
- }
-
epicsTimeGetCurrent(&tsNow);
epicsTimeToStrftime(timeText, TIMETEXTLEN, timeFormatStr, &tsNow);
+ if (!tsInitS)
+ {
+ tsFirst = tsNow;
+ tsInitS = 1;
+ }
+
printf("%-30s ", pv->name);
if (!pv->onceConnected)
printf("*** Not connected (PV not found)\n");
@@ -502,6 +517,12 @@ int create_pvs (pv* pvs, int nPvs, caCh *pCB)
int n;
int result;
int returncode = 0;
+
+ if (!tsInitC) /* Initialize start timestamp */
+ {
+ epicsTimeGetCurrent(&tsStart);
+ tsInitC = 1;
+ }
/* Issue channel connections */
for (n = 0; n < nPvs; n++) {
result = ca_create_channel (pvs[n].name,
diff --git a/src/catools/tool_lib.h b/src/catools/tool_lib.h
index d0f5d5e79..f811dfb2d 100644
--- a/src/catools/tool_lib.h
+++ b/src/catools/tool_lib.h
@@ -65,13 +65,16 @@ typedef struct
unsigned long reqElems;
int status;
void* value;
- epicsTimeStamp tsPrevious;
+ epicsTimeStamp tsPreviousC;
+ epicsTimeStamp tsPreviousS;
char firstStampPrinted;
char onceConnected;
} pv;
-extern TimeT tsType; /* Timestamp type flag (-r -i -I options) */
+extern TimeT tsType; /* Timestamp type flag (-t option) */
+extern int tsSrcServer; /* Timestamp source flag (-t option) */
+extern int tsSrcClient; /* Timestamp source flag (-t option) */
extern IntFormatT outType; /* Flag used for -0.. output format option */
extern int enumAsNr; /* Used for -n option (get DBF_ENUM as number) */
extern double caTimeout; /* Wait time default (see -w option) */