"Fossies" - the Fresh Open Source Software Archive

Member "PPSkit-2.1.7/ppsctl.c" (7 Jul 2001, 9755 Bytes) of package /linux/misc/old/PPSkit-2.1.7.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /* Control program for PPS API v1 (RFC 2783), a bit like `stty'
    2  *
    3  * Copyright (c) 1996 - 2001 by Ulrich Windl
    4  *
    5  * This program is free software; you can redistribute it and/or
    6  * modify it under the terms of the GNU General Public License as
    7  * published by the Free Software Foundation; either version 2 of the
    8  * License, or (at your option) any later version.
    9  *
   10  * This program is distributed in the hope that it will be useful, but
   11  * WITHOUT ANY WARRANTY; without even the implied warranty of
   12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   13  * General Public License for more details.
   14  *
   15  * You should have received a copy of the GNU General Public License
   16  * along with this program; if not, write to the Free Software
   17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   18  *
   19  * $Id: ppsctl.c,v 1.4 2001/07/07 17:02:44 windl Exp $
   20  */
   21 #include    <unistd.h>
   22 #include    <stdlib.h>
   23 #include    <stdio.h>
   24 #include    <ctype.h>
   25 #include    <string.h>
   26 #include    <errno.h>
   27 #include    <sys/time.h>
   28 #include    <sys/stat.h>
   29 #include    <fcntl.h>
   30 #include    <sys/utsname.h>
   31 
   32 #include    <linux/version.h>
   33 
   34 #include    <sys/timepps.h>
   35 
   36 #define ALL_BITS_ON(v, b)       (((v) & (b)) == (b))
   37 #define ALL_BITS_OFF(v, b)      (((v) & (b)) == 0)
   38 #define BITS_OFF(v, b)          ((v) & ~(b))
   39 #define BITS_ON(v, b)           ((v) | (b))
   40 
   41 static  const char  id[] = "$Id: ppsctl.c,v 1.4 2001/07/07 17:02:44 windl Exp $";
   42 
   43 #define BIT(n)  (1UL << (n))
   44 #define OPT_MONITOR_LOOP    BIT(0)  /* monitor loop */
   45 
   46 static  unsigned long   options = 0;
   47 static  const char  *format = "Etdj";   /* output format */
   48 
   49 static  char        trigger = '0';  /* off | assert | clear | both */
   50 
   51 static  int     fd  = -1;   /* file descriptor of port */
   52 static  pps_handle_t    ppshandle;  /* PPS handle */
   53 
   54 struct clock_info {         /* information about clock and conditions */
   55     pps_info_t  info;       /* pulse information */
   56     int     have_assert;    /* assert event detected */
   57     int     have_clear; /* clear event detected */
   58     long        sec, nsec;  /* last time stamp */
   59     long        dsec, dnsec;    /* difference since last time stamp */
   60     long        seq, dseq;  /* sequence number and difference */
   61     long        nano_offset;    /* offset around zero (ns) */
   62     long        jitter;     /* jitter between pulses (ns) */
   63 };
   64 
   65 /* update *cip */
   66 static  int update_clock_info(struct clock_info *cip)
   67 {
   68     static struct clock_info    last;
   69     static struct timespec  sleeper = {0, 0};
   70     pps_seq_t   ds;
   71     int result = -1;
   72 
   73     if ( time_pps_fetch(ppshandle, PPS_TSFMT_TSPEC,
   74                 &cip->info, &sleeper) == -1 )
   75     {
   76         perror("time_pps_fetch()");
   77         memset(&cip->info, 0, sizeof(cip->info));
   78     }
   79 
   80     cip->dseq = cip->have_assert = cip->have_clear = 0;
   81     if ( (ds = cip->info.assert_sequence - last.info.assert_sequence)
   82          != 0 ) {
   83         cip->have_assert = 1;
   84         cip->dseq += ds;
   85         cip->sec = cip->info.assert_timestamp.tv_sec;
   86         cip->nsec = cip->info.assert_timestamp.tv_nsec;
   87         cip->seq = cip->info.assert_sequence;
   88     }
   89     if ( (ds = cip->info.clear_sequence - last.info.clear_sequence)
   90          != 0 ) {
   91         cip->have_clear = 1;
   92         cip->dseq += ds;
   93         cip->sec = cip->info.clear_timestamp.tv_sec;
   94         cip->nsec = cip->info.clear_timestamp.tv_nsec;
   95         cip->seq = cip->info.clear_sequence;
   96     }
   97     cip->dsec = cip->sec - last.sec;
   98     cip->dnsec = cip->nsec - last.nsec;
   99     if ( cip->dseq )
  100     {
  101         cip->nano_offset = cip->nsec;
  102         if ( cip->nano_offset > 500000000 )
  103             cip->nano_offset -= 1000000000;
  104         if ( cip->dnsec < 0 )
  105         {
  106             --cip->dsec;
  107             cip->dnsec += 1000000000;
  108         }
  109         else if ( cip->dnsec > 1000000000 )
  110         {
  111             ++cip->dsec;
  112             cip->dnsec -= 1000000000;
  113         }
  114         cip->jitter = cip->dsec - last.dsec;
  115         cip->jitter *= 1000000000;
  116         cip->jitter += cip->dnsec - last.dnsec;
  117         last = *cip;
  118         result = 0;
  119     }
  120     return(result);
  121 }
  122 
  123 /* monitor PPS API values */
  124 static  void    monitor_loop(struct clock_info *cip)
  125 {
  126     struct clock_info   last;
  127     pps_info_t      buf;
  128     const char      *fmt;
  129     char            fmtchr;
  130     const char      *sep;
  131 
  132     while ( 1 )
  133     {
  134         if ( time_pps_fetch(ppshandle, PPS_TSFMT_TSPEC,
  135                     &buf, NULL) != 0 )
  136         {
  137             perror("time_pps_fetch()");
  138             continue;
  139         }
  140         update_clock_info(cip);
  141         if ( cip->dseq == 0 )
  142             continue;
  143         sep = "";
  144         for ( fmt = format; (fmtchr = *fmt) != '\0'; ++fmt )
  145         {
  146             if ( fmtchr == 'E' )    /* automagic event */
  147                 fmtchr = cip->have_assert ? 'a' : 'c';
  148             switch ( fmtchr )
  149             {
  150             case 'a':
  151                 printf("%sassert %lu",
  152                        sep, cip->info.assert_sequence);
  153                 sep = " ";
  154                 break;
  155             case 'c':
  156                 printf("%sclear %lu",
  157                        sep, cip->info.clear_sequence);
  158                 sep = " ";
  159                 break;
  160             case 'd':
  161                 printf("%sdelta %lu.%09lu",
  162                        sep, cip->dsec, cip->dnsec);
  163                 sep = " ";
  164                 break;
  165             case 'j':
  166                 printf("%sjitter %ld", sep, cip->jitter);
  167                 sep = " ";
  168                 break;
  169             case 'l':
  170                 printf("%slevel %c",
  171                        sep, cip->have_assert ? '1' : '0');
  172                 sep = " ";
  173                 break;
  174             case 'o':
  175                 printf("%soffset %ld", sep, cip->nano_offset);
  176                 sep = " ";
  177                 break;
  178             case 't':
  179                 printf("%stime %lu.%09lu",
  180                        sep, cip->sec, cip->nsec);
  181                 sep = " ";
  182                 break;
  183             default:
  184                 printf("%s?", sep);
  185                 sep = " ";
  186                 break;
  187             
  188             }
  189         }
  190         printf("\n");
  191 
  192         last = *cip;
  193         fflush(stdout);
  194     }
  195 }
  196 
  197 /* provide a usage message */
  198 static  void    usage(void)
  199 {
  200     fprintf(stderr,
  201         "Known options are:\n"
  202         "\t-eX\tEcho - set PPS API echo for `X' events (a|c)\n"
  203         "\t-Ffmt\tFormat - set output format to `fmt' (see below)\n"
  204         "\t-m\tmonitor values\n"
  205         "\t-oXY\tSet PPS API offset for `X' events (a|c) to `Y'ns\n"
  206         "\t-pZ\tUse port `Z'\n"
  207         "\t-t{0|a|c|b}[h]\ttrigger for event: off|assert|clear|both\n"
  208         "\t\t'h' = route to `hardpps()' kernel consumer\n"
  209         );
  210     fprintf(stderr,
  211         "\n"
  212         "Format is composed of the following components:\n"
  213         "\tE\tcurrent event's counter\n"
  214         "\ta\tassert event's counter\n"
  215         "\tc\tclear event's counter\n"
  216         "\td\tdelta between event timestamps\n"
  217         "\tj\tjitter between event time stamps (delta of delta)\n"
  218         "\tl\tlogical level of event ('0' = clear, '1' = assert)\n"
  219         "\to\toffset around current second\n"
  220         "\tt\ttimestamp of current event\n"
  221         );
  222 }
  223 
  224 int main(int argc, char *argv[])
  225 {
  226     struct utsname  un;
  227     struct clock_info ci;
  228     pps_params_t    parm;
  229     int     kc_edge;
  230     int     caps;
  231     int     ch;
  232 
  233     printf("(This version has been compiled"
  234 #ifdef __linux__
  235            " on Linux %s\n", UTS_RELEASE
  236 #endif
  237            );
  238     printf(" using "
  239 #if !defined(__GNU_LIBRARY__) || __GNU_LIBRARY__ < 6
  240            "an old C library (not glibc-2.x)"
  241 #else
  242            "glibc-%d.%d",
  243            __GLIBC__, __GLIBC_MINOR__
  244 #endif
  245            );
  246     uname(&un);
  247     printf(". Now running %s %s)\n", un.sysname, un.release);
  248     parm.mode = PPS_TSFMT_TSPEC;    /* set default flags */
  249     while ( (ch = getopt(argc, argv, "e:F:mo:p:t:")) != -1 )
  250     {
  251         switch ( ch )
  252         {
  253         case 'e':
  254             switch (optarg[0])
  255             {
  256             case 'a':
  257                 parm.mode |= PPS_ECHOASSERT;
  258                 break;
  259             case 'c':
  260                 parm.mode |= PPS_ECHOCLEAR;
  261                 break;
  262             default:
  263                 fprintf(stderr, "'-%c%s' is illegal\n",
  264                     ch, optarg);
  265                 usage();
  266                 exit(1);
  267             }
  268             break;
  269         case 'F':
  270             format = optarg;
  271             break;
  272         case 'm':   /* monitor jitter only */
  273             options = BITS_ON(options, OPT_MONITOR_LOOP);
  274             break;
  275         case 'o':
  276             switch (optarg[0])
  277             {
  278             case 'a':
  279                 parm.mode |= PPS_OFFSETASSERT;
  280                 parm.assert_offset.tv_sec = 0;
  281                 parm.assert_offset.tv_nsec = strtol(optarg + 1,
  282                                     NULL, 10);
  283                 break;
  284             case 'c':
  285                 parm.mode |= PPS_OFFSETCLEAR;
  286                 parm.clear_offset.tv_sec = 0;
  287                 parm.clear_offset.tv_nsec = strtol(optarg + 1,
  288                                    NULL, 10);
  289                 break;
  290             default:
  291                 fprintf(stderr, "'-%c%s' is illegal\n",
  292                     ch, optarg);
  293                 usage();
  294                 exit(1);
  295             }
  296             break;
  297         case 'p':
  298             if ( (fd = open(optarg, O_RDWR)) == -1 )
  299             {
  300                 perror(optarg);
  301                 return(1);
  302             }
  303             break;
  304         case 't':   /* select desired edge of the pulse */
  305             trigger = optarg[0];
  306             switch ( trigger )
  307             {
  308             case '0':
  309             case 'a':
  310             case 'c':
  311             case 'b':
  312                 break;
  313             default:
  314                 fprintf(stderr, "'-%c%s' is illegal\n",
  315                     ch, optarg);
  316                 usage();
  317                 exit(1);
  318             }
  319             if ( optarg[1] == 'h' )
  320                 trigger = toupper(trigger);
  321             break;
  322         case '?':
  323             fprintf (stderr, "Unknown option `-%c'.\n", optopt);
  324             usage();
  325             exit(1);
  326         }
  327     }
  328     if ( optind > argc )
  329     {
  330         fprintf(stderr, "Extra arguments ignored!\n");
  331         usage();
  332         exit(1);
  333     }
  334 
  335     if ( fd == -1 )
  336     {
  337         fprintf(stderr, "Missing port to set up!\n");
  338         usage();
  339         exit(1);
  340     }
  341 
  342     kc_edge = 0;
  343     switch ( trigger )
  344     {
  345     case 'A':
  346         kc_edge |= PPS_CAPTUREASSERT;   /* fall through */
  347     case 'a':
  348         parm.mode |= PPS_CAPTUREASSERT;
  349         break;
  350     case 'C':
  351         kc_edge |= PPS_CAPTURECLEAR;    /* fall through */
  352     case 'c':
  353         parm.mode |= PPS_CAPTURECLEAR;
  354         break;
  355     case 'B':
  356         /* parm.mode |= PPS_HARDPPSONBOTH; */   /* fall through */
  357     case 'b':
  358         parm.mode |= PPS_CAPTUREBOTH;
  359         break;
  360     }
  361 
  362     if ( time_pps_create(fd, &ppshandle) )
  363     {
  364         perror("time_pps_create()");
  365         return(1);
  366     }
  367     if ( time_pps_getcap(ppshandle, &caps) )
  368     {
  369         perror("time_pps_getcap()");
  370         return(1);
  371     }
  372     printf("PPS API capabilities are 0x%x\n", caps);
  373 
  374     parm.api_version = PPS_API_VERS_1;
  375     if ( time_pps_setparams(ppshandle, &parm) != 0 )
  376     {
  377         perror("time_pps_setparams()");
  378         fprintf(stderr, "handle=%d, mode=%#04x\n",
  379             ppshandle, parm.mode);
  380         /* continue, maybe just monitoring */
  381     }
  382     else
  383     {
  384         fprintf(stderr,
  385             "PPS API v%d set up (handle %d, mode %#04x)\n",
  386             parm.api_version, ppshandle, parm.mode);
  387         if ( kc_edge != 0 )
  388         {
  389             if ( time_pps_kcbind(ppshandle, PPS_KC_HARDPPS,
  390                          kc_edge, PPS_TSFMT_TSPEC) != 0 )
  391             {
  392                 perror("time_pps_kcbind()");
  393                 fprintf(stderr, "handle=%d, edge=%#04x\n",
  394                     ppshandle, kc_edge);
  395                 /* continue, maybe just monitoring */
  396             }
  397             else
  398             {
  399                 fprintf(stderr,
  400                     "PPS API kernel consumer HARDPPS bound"
  401                     " to edge %#04x\n",
  402                     kc_edge);
  403             }
  404         }
  405     }
  406     memset(&ci, 0, sizeof(ci));
  407     update_clock_info(&ci);
  408     if ( options & OPT_MONITOR_LOOP )
  409         monitor_loop(&ci);
  410     return(0);
  411 }