mbgtools-lx  4.2.8
mbggpscap.c
Go to the documentation of this file.
1 
2 /**************************************************************************
3  *
4  * $Id: mbggpscap.c 1.14 2018/11/15 12:12:36 martin TRASH $
5  *
6  * Description:
7  * Main file for mbggpscap program which demonstrates how to access
8  * a Meinberg device via IOCTL calls and read entries from the time
9  * capture FIFO buffer.
10  *
11  * Please note that this may only work with devices which provide
12  * time capture input(s).
13  *
14  * -----------------------------------------------------------------------
15  * $Log: mbggpscap.c $
16  * Revision 1.14 2018/11/15 12:12:36 martin
17  * Individual MBG_MICRO_VERSION codes are now obsolete.
18  * Revision 1.13 2018/01/10 13:36:35 martin
19  * Use current API mbg_get_serial_settings() to check
20  * serial settings. Don't change configuration but just warn
21  * if capture events might be spit out via a serial port.
22  * Added some doxygen comments.
23  * Revision 1.12 2017/11/29 12:49:31 martin
24  * Added feature to log capture events to a file.
25  * Revision 1.11 2017/07/05 18:59:14 martin
26  * New way to maintain version information.
27  * Support build under Windows.
28  * Improved code execution paths.
29  * Improved reading capture events arriving at a high rate.
30  * Support validation of capture signals arriving at a constant rate.
31  * Fixed a bug when displaying the capture event status. TTM and
32  * PCPS_HR_TIME are using different sets of status flags.
33  * New option -r which displays raw timestamps and raw status.
34  * New option -o which forces usage of old API.
35  * New command line option to clear buffer.
36  * Account for PCPS_HRT_BIN_FRAC_SCALE renamed to MBG_FRAC32_UNITS_PER_SEC.
37  * Use more functions from common library modules.
38  * Use codes and inline functions from mbgerror.h.
39  * Proper return codes and exit codes.
40  * Revision 1.10 2009/09/29 15:02:15 martin
41  * Updated version number to 3.4.0.
42  * Revision 1.9 2009/07/24 09:50:08 martin
43  * Updated version number to 3.3.0.
44  * Revision 1.8 2009/06/19 12:38:51 martin
45  * Updated version number to 3.2.0.
46  * Revision 1.7 2009/03/19 17:04:26 martin
47  * Updated version number to 3.1.0.
48  * Updated copyright year to include 2009.
49  * Revision 1.6 2008/12/22 12:00:55 martin
50  * Updated description, copyright, revision number and string.
51  * Use unified functions from toolutil module.
52  * Accept device name(s) on the command line.
53  * Don't use printf() without format, which migth produce warnings
54  * with newer gcc versions.
55  * Revision 1.5 2007/07/24 09:32:26 martin
56  * Updated copyright to include 2007.
57  * Revision 1.4 2006/02/22 15:29:17 martin
58  * Support new ucap API.
59  * Print an error message if device can't be opened.
60  * Revision 1.3 2004/11/08 15:47:10 martin
61  * Using type cast to avoid compiler warning.
62  * Revision 1.2 2003/04/25 10:28:05 martin
63  * Use new functions from mbgdevio library.
64  * New program version v2.1.
65  * Revision 1.1 2001/09/17 15:08:22 martin
66  *
67  **************************************************************************/
68 
69 // include Meinberg headers
70 #include <mbgdevio.h>
71 #include <deviohlp.h>
72 #include <toolutil.h> // common utility functions
73 #include <str_util.h>
74 
75 // include system headers
76 #include <stdio.h>
77 #include <stdlib.h>
78 #include <time.h>
79 
80 
81 #define USLEEP_INTV 10000 // [microseconds]
82 
83 
84 #define MBG_FIRST_COPYRIGHT_YEAR 2001
85 #define MBG_LAST_COPYRIGHT_YEAR 0 // use default
86 
87 static const char *pname = "mbggpscap";
88 
89 
90 static int continuous;
91 static double nom_cap_intv; // nominal capture interval to check [s]
92 static double max_cap_jitter; // max allowed jitter [s]
93 static int raw;
94 static int force_old_api;
95 static int clear_buffer;
96 static const char *log_fn;
97 
98 static int has_been_called;
99 static int must_check_intv;
100 static int query_only;
101 static ulong err_cnt;
103 
104 
105 
106 static /*HDR*/
121 void show_ucap_event( const PCPS_HR_TIME *ucap )
122 {
123  char ws[80];
124  char s[400];
125  int n;
126 
127  // Print converted date and time to a string:
128  mbg_snprint_hr_time( ws, sizeof( ws ), ucap, raw );
129 
130  // Print the time stamp, ucap->signal contains the channel number:
131  n = snprintf_safe( s, sizeof( s ), "New capture: CH%i: %s", ucap->signal, ws );
132 
134  {
135  int jitter_exceeded;
136  double abs_delta;
137  double d = ucap->tstamp.sec - prv_ucap.tstamp.sec;
138  d += ( (double) ucap->tstamp.frac - prv_ucap.tstamp.frac ) / MBG_FRAC32_UNITS_PER_SEC;
139 
140  n += snprintf_safe( &s[n], sizeof( s ) - n, " %+.6f", d );
141 
142  abs_delta = d - nom_cap_intv;
143 
144  if ( abs_delta < 0.0 )
145  abs_delta = -abs_delta;
146 
147  jitter_exceeded = 0;
148 
149  if ( abs_delta > max_cap_jitter )
150  {
151  jitter_exceeded = 1;
152  err_cnt++;
153  }
154 
155  if ( err_cnt )
156  n += snprintf_safe( &s[n], sizeof( s ) - n, " %lu%s", err_cnt, jitter_exceeded ? " <<" : "" );
157  }
158 
159  // status bit definitions can be found in pcpsdefs.h.
160 
161  if ( raw )
162  n += snprintf_safe( &s[n], sizeof( s ) - n, ", st: 0x%04X", ucap->status );
163 
164  if ( ucap->status & PCPS_UCAP_OVERRUN ) // capture events have occurred too fast
165  n += snprintf_safe( &s[n], sizeof( s ) - n, " << CAP OVR" );
166 
167  if ( ucap->status & PCPS_UCAP_BUFFER_FULL ) // capture buffer has been full, events lost
168  n += snprintf_safe( &s[n], sizeof( s ) - n, " << BUF OVR" );
169 
170  prv_ucap = *ucap;
171  has_been_called = 1;
172 
173  printf( "%s\n", s );
174 
175  if ( log_fn )
176  {
177  FILE *fp = fopen( log_fn, "at" );
178 
179  if ( fp )
180  {
181  fprintf( fp, "%s\n", s );
182  fclose( fp );
183  }
184  else
185  {
186  fprintf( stderr, "** Failed to open file %s for writing: %s\n",
187  log_fn, strerror( errno ) );
188  log_fn = NULL;
189  }
190  }
191 
192 } // show_ucap_event
193 
194 
195 
196 static /*HDR*/
214 void show_gps_ucap( const TTM *ucap )
215 {
216  printf( "New capture: CH%i: %04i-%02i-%02i %2i:%02i:%02i.%07li",
217  ucap->channel,
218  ucap->tm.year,
219  ucap->tm.month,
220  ucap->tm.mday,
221  ucap->tm.hour,
222  ucap->tm.min,
223  ucap->tm.sec,
224  (ulong) ucap->tm.frac
225  );
226 
227  if ( raw )
228  printf( ", st: 0x%04lX", (ulong) ucap->tm.status );
229 
230  printf( "\n" );
231 
232 } // show_gps_ucap
233 
234 
235 
236 static /*HDR*/
259 void check_serial_mode( MBG_DEV_HANDLE dh, const PCPS_DEV *p_dev )
260 {
261  RECEIVER_INFO ri;
262  RECEIVER_PORT_CFG rpcfg;
263  int i;
264  int must_warn = 0;
265 
266  int rc = mbg_setup_receiver_info( dh, p_dev, &ri );
267 
268  if ( mbg_cond_err_msg( rc, "mbg_setup_receiver_info" ) )
269  return;
270 
271  if ( ri.n_com_ports == 0 ) // The device provides no serial port
272  return; // so there's nothing to check.
273 
274  // read the clock's current serial port settings
275  rc = mbg_get_serial_settings( dh, p_dev, &rpcfg, &ri );
276 
277  if ( mbg_cond_err_msg( rc, "mbg_get_serial_settings" ) )
278  return;
279 
280 
281  // Check if one of the serial ports uses STR_AUTO mode.
282  for ( i = 0; i < ri.n_com_ports; i++ )
283  {
284  PORT_SETTINGS *p = &rpcfg.pii[i].port_info.port_settings;
285 
286  if ( p->mode == STR_AUTO )
287  {
288  must_warn = 1;
289  break;
290  }
291  }
292 
293  if ( must_warn )
294  fprintf( stderr,
295  "ATTENTION: At least one of the device's serial ports has been\n"
296  "configured to send time strings automatically, which can remove\n"
297  "capture events from the on-board FIFO, so they are unavailable\n"
298  "to this application\n"
299  "\n"
300  "Please change the configuration of the serial port(s) in a way that\n"
301  "none of the serial ports sends a capture event string automatically.\n"
302  "\n"
303  "For example, use the \"mbgctrl\" program to let the serial ports\n"
304  "transmit the Meinberg standard time string once per second.\n"
305  "\n"
306  "See \"mbgctrl -?\" for details.\n"
307  "\n" );
308 
309 } // check_serial_mode
310 
311 
312 
313 static /*HDR*/
314 int do_mbggpscap( MBG_DEV_HANDLE dh, const PCPS_DEV *p_dev )
315 {
316  int rc;
317  int this_clear_buffer = clear_buffer;
318 
320  has_been_called = 0;
321  err_cnt = 0;
322 
323 
324  if ( !_pcps_has_ucap( p_dev ) && !_pcps_is_gps( p_dev ) )
325  {
326  printf( "This device type does not provide time capture inputs.\n" );
327  return 0;
328  }
329 
330  check_serial_mode( dh, p_dev );
331 
332  printf( "Be sure the card has been properly configured to enable capture inputs.\n" );
333 
334  // There's an older API which has been introduced with the first GPS boards
335  // and uses the TTM structure to return the capture events. However, that
336  // API call is slow and not very flexible, so a new set of API calls has been
337  // introduced to handle capture events.
338  // The new API calls are supported by all supported by all newer boards which
339  // provide user capture inputs, and also for older boards with a firmware update.
340 
341  if ( !force_old_api && _pcps_has_ucap( p_dev ) ) // check if the new API is supported
342  {
343  // The new API provides the following functions:
344  // mbg_clr_ucap_buff() clear the on-board FIFO buffer
345  // mbg_get_ucap_entries() get the max number of FIFO entries, and the current number of entries
346  // mbg_get_ucap_event() read one entry from the FIFO
347 
348  PCPS_UCAP_ENTRIES ucap_entries;
349 
350  // retrieve and print information of the maximum number of events that can
351  // be stored in the on-board FIFO, and the number of events that are currently
352  // stored
353  rc = mbg_get_ucap_entries( dh, &ucap_entries );
354 
355  if ( rc == MBG_SUCCESS )
356  {
357  // Cards report they could save one more capture event
358  // than they actually do save, so adjust the reported value
359  // for a proper display.
360  if ( ucap_entries.max )
361  ucap_entries.max--;
362 
363  printf( "\nOn-board FIFO: %u of %u entries used\n\n",
364  ucap_entries.used, ucap_entries.max );
365  }
366 
367  if ( this_clear_buffer )
368  {
369  printf( "Clearing on-board FIFO buffer\n" );
370  mbg_clr_ucap_buff( dh );
371  this_clear_buffer = 0;
372  }
373 
374  // If the program is not to run continuously and no
375  // capture events are available then we're through.
376  if ( query_only || ( !continuous && ucap_entries.used == 0 ) )
377  return 0;
378 
379 
380  printf( ( ucap_entries.used == 0 ) ?
381  "Waiting for capture events:\n" :
382  "Reading capture events:\n"
383  );
384 
385  if ( must_check_intv )
386  if ( max_cap_jitter == 0.0 )
387  max_cap_jitter = 0.1e-6;
388 
389  // Now read out all events from the FIFO and wait
390  // for new events if the FIFO is empty.
391  for (;;)
392  {
393  PCPS_HR_TIME ucap_event;
394 
395  rc = mbg_get_ucap_event( dh, &ucap_event );
396 
397  if ( mbg_cond_err_msg( rc, "mbg_get_ucap_event" ) )
398  break; // an error has occurred
399 
400  // If a user capture event has been read then it
401  // has been removed from the card's FIFO buffer.
402 
403  // If the time stamp is not 0 then a new capture event has been retrieved.
404  if ( ucap_event.tstamp.sec || ucap_event.tstamp.frac )
405  {
406  show_ucap_event( &ucap_event );
407  continue;
408  }
409 
410  usleep( USLEEP_INTV ); // sleep, then try again
411  }
412  }
413  else // use the old API
414  {
415  printf( "Checking for capture events using the old API:\n" );
416 
417  for (;;)
418  {
419  TTM ucap_ttm;
420 
421  rc = mbg_get_gps_ucap( dh, &ucap_ttm );
422 
423  if ( mbg_cond_err_msg( rc, "mbg_get_gps_ucap" ) )
424  break; // an error has occurred
425 
426 
427  // If a user capture event has been read then it
428  // has been removed from the card's FIFO buffer.
429 
430  // If a new capture event has been available then
431  // the ucap.tm contains a time stamp.
432  if ( _pcps_time_is_read( &ucap_ttm.tm ) )
433  show_gps_ucap( &ucap_ttm );
434 
435  if ( !continuous )
436  {
437  printf( "No capture event available!\n" );
438  break;
439  }
440 
441  usleep( USLEEP_INTV ); // sleep, then try again
442  }
443  }
444 
445  return 0;
446 
447 } // do_mbggpscap
448 
450 
451 
452 
453 static /*HDR*/
454 void usage( void )
455 {
457  "This example program reads time capture events from a card.\n"
458  "This works only with cards which provide time capture inputs."
459  );
461  mbg_print_opt_info( "-c", "run continuously" );
462  mbg_print_opt_info( "-C", "clear capture buffer" );
463  mbg_print_opt_info( "-i val", "check interval between captures events [s]" );
464  mbg_print_opt_info( "-j val", "max allowed jitter of capture interval [s]" );
465  mbg_print_opt_info( "-q", "query FIFO buffer status only" );
466  mbg_print_opt_info( "-r", "show raw (hex) timestamp and status)" );
467  mbg_print_opt_info( "-o", "force usage of old API (for testing only)" );
469  puts( "" );
470 
471 } // usage
472 
473 
474 
475 int main( int argc, char *argv[] )
476 {
477  int rc;
478  int c;
479 
481 
482  // check command line parameters
483  while ( ( c = getopt( argc, argv, "cCi:j:l:oqrh?" ) ) != -1 )
484  {
485  switch ( c )
486  {
487  case 'c':
488  continuous = 1;
489  break;
490 
491  case 'C':
492  clear_buffer = 1;
493  break;
494 
495  case 'i':
496  nom_cap_intv = atof( optarg );
497  break;
498 
499  case 'j':
500  max_cap_jitter = atof( optarg );
501  break;
502 
503  case 'l':
504  log_fn = optarg;
505  break;
506 
507  case 'o':
508  force_old_api = 1;
509  break;
510 
511  case 'q':
512  query_only = 1;
513  break;
514 
515  case 'r':
516  raw = 1;
517  break;
518 
519  case 'h':
520  case '?':
521  default:
522  must_print_usage = 1;
523  }
524  }
525 
526  if ( must_print_usage )
527  {
528  usage();
529  return MBG_EXIT_CODE_USAGE;
530  }
531 
532  if ( nom_cap_intv != 0.0 )
533  {
534  printf( "Nominal capture interval: %f s\n", nom_cap_intv );
535  printf( "Maximum allowed capture jitter: %f s\n", max_cap_jitter );
536  }
537 
538  // Handle each of the specified devices.
539  rc = mbg_handle_devices( argc, argv, optind, do_mbggpscap, 0 );
540 
542 }
events read too slow (capture events only)
Definition: pcpsdefs.h:1279
_MBG_API_ATTR int _MBG_API mbg_get_ucap_event(MBG_DEV_HANDLE dh, PCPS_HR_TIME *p)
Retrieve a single time capture event from the on-board FIFO buffer.
Definition: mbgdevio.c:5401
#define USLEEP_INTV
Definition: mbggpscap.c:81
TM_GPS tm
time converted to UTC and/or local time according to TZDL settings
Definition: gpsdefs.h:2717
int mbg_handle_devices(int argc, char *argv[], int optind, MBG_DEV_HANDLER_FNC *fnc, int chk_dev_flags)
Main action handler that can be called by utility programs.
Definition: toolutil.c:655
int must_print_usage
uint32_t used
the number of saved capture events
Definition: pcpsdefs.h:1531
#define _pcps_time_is_read(_t)
Definition: pcpsdev.h:1344
_MBG_API_ATTR int _MBG_API mbg_get_gps_ucap(MBG_DEV_HANDLE dh, TTM *p)
Read a time capture event from the on-board FIFO buffer using a TTM structure.
Definition: mbgdevio.c:5741
int32_t frac
fractions of a second, 1/RECEIVER_INFO::ticks_per_sec units
Definition: gpsdefs.h:2603
static double nom_cap_intv
Definition: mbggpscap.c:91
Requested action completed successfully.
Definition: mbgerror.h:631
#define _pcps_has_ucap(_d)
Definition: pcpsdev.h:1162
int mbg_snprint_hr_time(char *s, size_t max_len, const PCPS_HR_TIME *p, int show_raw)
Print date and time from a PCPS_HR_TIME structure to a string.
Definition: toolutil.c:851
int16_t channel
-1: the current on-board time; >= 0 the capture channel number
Definition: gpsdefs.h:2715
Configuration settings of a serial port.
Definition: gpsdefs.h:3507
bool mbg_cond_err_msg(int rc, const char *what)
Check if a value is an error code and print an associated error message.
Definition: mbgerror.c:714
PCPS_SECONDS sec
seconds since 1970, usually UTC scale
Definition: pcpsdefs.h:974
int8_t sec
seconds, 0..59, or 60 in case of inserted leap second
Definition: gpsdefs.h:2602
static int query_only
Definition: mbggpscap.c:100
_MBG_API_ATTR int _MBG_API mbg_clr_ucap_buff(MBG_DEV_HANDLE dh)
Clear a device&#39;s on-board time capture FIFO buffer.
Definition: mbgdevio.c:5331
#define _pcps_is_gps(_d)
Definition: pcpsdev.h:1074
static const char * log_fn
Definition: mbggpscap.c:96
Unable to handle requested action, usage printed.
Definition: mbgerror.h:632
#define mbg_rc_is_success(_rc)
Definition: mbgerror.h:618
int mbg_get_serial_settings(MBG_DEV_HANDLE dh, const PCPS_DEV *p_dev, RECEIVER_PORT_CFG *p_rpcfg, const RECEIVER_INFO *p_ri)
Read all serial port settings and supported configuration parameters.
Definition: deviohlp.c:244
int8_t mday
day of month, 1..31
Definition: gpsdefs.h:2597
uint8_t n_com_ports
number of on-board serial ports
Definition: gpsdefs.h:887
int16_t year
year number, 0..9999
Definition: gpsdefs.h:2595
static PCPS_HR_TIME prv_ucap
Definition: mbggpscap.c:102
Status of the time capture FIFO buffer.
Definition: pcpsdefs.h:1529
int8_t hour
hours, 0..23
Definition: gpsdefs.h:2600
int8_t min
minutes, 0..59
Definition: gpsdefs.h:2601
static int raw
Definition: mbggpscap.c:93
void mbg_print_device_options(void)
Print common info on how to specify devices on the command line.
Definition: toolutil.c:270
void mbg_print_usage_intro(const char *pname, const char *info)
Print usage intro to console.
Definition: toolutil.c:217
PCPS_TIME_STATUS_X status
status bits, see PCPS_TIME_STATUS_FLAGS
Definition: pcpsdefs.h:1089
static MBG_DEV_HANDLER_FNC do_mbggpscap
Definition: mbggpscap.c:449
int main(int argc, char *argv[])
Definition: mbggpscap.c:475
uint32_t max
capture buffer size
Definition: pcpsdefs.h:1532
uint16_t status
status flags, see TM_GPS_STATUS_BIT_MASKS
Definition: gpsdefs.h:2605
A structure used to transmit information on date and time.
Definition: gpsdefs.h:2713
transmission automatically if required, e.g. on capture event
Definition: gpsdefs.h:3762
PCPS_FRAC_32 frac
binary fractions of second, see PCPS_FRAC_32
Definition: pcpsdefs.h:975
#define MBG_LAST_COPYRIGHT_YEAR
Definition: mbggpscap.c:85
static int continuous
Definition: mbggpscap.c:90
static const char * pname
Definition: mbggpscap.c:87
PCPS_TIME_STAMP tstamp
High resolution time stamp (UTC)
Definition: pcpsdefs.h:1087
static int clear_buffer
Definition: mbggpscap.c:95
static int must_check_intv
Definition: mbggpscap.c:99
int MBG_DEV_HANDLER_FNC(MBG_DEV_HANDLE, const PCPS_DEV *)
The type of functions to called to handle a device in a specific way.
Definition: toolutil.h:144
#define MBG_FRAC32_UNITS_PER_SEC
Constant used to convert e.g. PCPS_TIME_STAMP::frac values.
Definition: mbgtime.h:400
#define MBG_SUCCESS
Error codes used with Meinberg devices and drivers.
Definition: mbgerror.h:259
_MBG_API_ATTR int _MBG_API mbg_setup_receiver_info(MBG_DEV_HANDLE dh, const PCPS_DEV *p_dev, RECEIVER_INFO *p)
Set up a RECEIVER_INFO structure for a device.
Definition: mbgdevio.c:6329
static void show_gps_ucap(const TTM *ucap)
Show a user capture event in TTM format read from device.
Definition: mbggpscap.c:214
Action failed for specified device.
Definition: mbgerror.h:634
uint8_t mode
string mode, see STR_MODES
Definition: gpsdefs.h:3510
High resolution time including status and local time offset.
Definition: pcpsdefs.h:1085
static void check_serial_mode(MBG_DEV_HANDLE dh, const PCPS_DEV *p_dev)
Check the modes of a device&#39;s serial ports.
Definition: mbggpscap.c:259
void mbg_print_help_options(void)
Print info on common program help arguments.
Definition: toolutil.c:257
_MBG_API_ATTR int _MBG_API mbg_get_ucap_entries(MBG_DEV_HANDLE dh, PCPS_UCAP_ENTRIES *p)
Read information on a device&#39;s event capture buffer.
Definition: mbgdevio.c:5362
static int has_been_called
Definition: mbggpscap.c:98
PCPS_SIG_VAL signal
signal strength, see PCPS_SIG_VAL_DEFS, or capture input channel number
Definition: pcpsdefs.h:1090
#define MBG_FIRST_COPYRIGHT_YEAR
Definition: mbggpscap.c:84
ALL_PORT_INFO_IDX pii
all serial port configuration settings
Definition: cfg_hlp.h:192
int snprintf_safe(char *s, size_t max_len, const char *fmt,...)
A portable, safe implementation of snprintf()
Definition: str_util.c:156
void mbg_print_opt_info(const char *opt_name, const char *opt_info)
Print info on a single program option / argument.
Definition: toolutil.c:236
static void usage(void)
Definition: mbggpscap.c:454
void mbg_print_program_info(const char *pname, int first_year, int last_year)
Print program info to console.
Definition: toolutil.c:193
static int force_old_api
Definition: mbggpscap.c:94
int8_t month
month, 1..12
Definition: gpsdefs.h:2596
unsigned long ulong
Definition: words.h:292
A structure used to identify a device type and supported features.
Definition: gpsdefs.h:873
static void show_ucap_event(const PCPS_HR_TIME *ucap)
Show a user capture event in PCPS_HR_TIME format.
Definition: mbggpscap.c:121
static double max_cap_jitter
Definition: mbggpscap.c:92
events interval too short (capture events only)
Definition: pcpsdefs.h:1278
Device info structure.
Definition: pcpsdev.h:1043
static ulong err_cnt
Definition: mbggpscap.c:101
All configuration parameters for all serial ports.
Definition: cfg_hlp.h:190