[LinuxPPS] Advise on kernel documentation

Rodolfo Giometti giometti at enneenne.com
Mon Jan 29 00:17:36 CET 2007


Hello,

I'm just writing some notes as kernel documentation (the file which
goes under directory Documentation in the Linux source tree) and I
like some suggestions about it before submitting it to the LKML.

Thanks,

Rodolfo

-- 

GNU/Linux Solutions                  e-mail:    giometti at enneenne.com
Linux Device Driver                             giometti at gnudd.com
Embedded Systems                     		giometti at linux.it
UNIX programming                     phone:     +39 349 2432127
-------------- next part --------------

			PPS - Pulse Per Second
			----------------------

Overview
--------

LinuxPPS provides a programming interface (API) to define into the
system several PPS sources. A PPS source is just a device who provide
an high and precise signal each second so that an application can use
it to adjust time clock.

A PPS source can be connected to a serial port (usually to the Data
Carrier Detect pin) or to a parallel port or to a special CPU's GPIOs
(this is the common case in embedded systems) but in each case when a
new pulse comes the system must apply to it a timestamp and record it
for the userland.

Combining this timestamp and the precise time from a GPS antenna (for
example) an userland program as NTPD, for example, can setup the
system time with a very low error.


RFC considerations
------------------

To define a common PPS API a RFC exists that is RFC 2783.

This document says:

     pps_handle_t type is an opaque scalar type used to represent a
     PPS source within the API

In LinuxPPS I intentionally want to separate the concept of "file
descriptor" to the concept of the "PPS source" since, as said above,
some devices do not have such association.

If your GPS antenna (or other PPS source) is connected to a serial
line or a parallel port then everything works well but, if this is not
true, you have no "filedes" to pass to the function
time_pps_create(). That's why I added new functions like
time_pps_findsource() and time_pps_findpath() in order to find a
generic PPS source into the system.

So, my opinion is that RFC 2783 should say that

    pps_handle_t type is an opaque variable used to represent a PPS
    source within the API

and programs should not access it directly to it due to its opacity.

Also note that the RFC 2783 does not say that programs should check
the pps_handle_t variable before calling the time_pps_*() functions,
since each function should do this job internally.

That's why current NTPD drivers' code should be modified as follow:

+#ifdef PPS_HAVE_FINDPATH
+      /* Get the PPS source's real name */
+      fd = readlink(link, path, STRING_LEN-1);
+      if (fd <= 0)
+              strncpy(path, link, STRING_LEN);
+      else
+              path[fd] = '\0';
+
+      /* Try to find the source */
+      fd = time_pps_findpath(path, STRING_LEN, id, STRING_LEN);
+      if (fd < 0) {
+              msyslog(LOG_ERR, "refclock: cannot find PPS source \"%s\" in the system", path);
+              return 1;
+      }
+      msyslog(LOG_INFO, "refclock: found PPS source #%d \"%s\" on \"%s\"", fd, path, id);
+#endif   /* PPS_HAVE_FINDPATH */
+
+
       if (time_pps_create(fd, &pps_handle) < 0) {
-              pps_handle = 0;
               msyslog(LOG_ERR, "refclock: time_pps_create failed: %m");
       }


Coding example
--------------

To register a PPS source into the kernel you should define a struct
linuxpps_source_info_s as follow:

    static struct linuxpps_source_info_s linuxpps_ktimer_info = {
            name         : "ktimer",
            path         : "",
            mode         : PPS_CAPTUREASSERT|PPS_OFFSETASSERT|PPS_ECHOASSERT| \
                           PPS_CANWAIT|PPS_TSFMT_TSPEC,
            echo         : linuxpps_ktimer_echo,
    };

and then calling the function linuxpps_register_source() in your
intialization routine as follow:

    source = linuxpps_register_source(&linuxpps_ktimer_info,
			PPS_CAPTUREASSERT|PPS_OFFSETASSERT,
			-1 /* is up to the system */);

The linuxpps_register_source() prototipe is:

  int linuxpps_register_source(struct linuxpps_source_info_s *info, int default_params, int try_id)

where "info" is a pointer to a structure that describes a particular
PPS source, "default_params" tells the system what the initial default
parameters for the device should be (is obvious that these parameters
must be a subset of ones defined into the struct
linuxpps_source_info_s which describe the capabilities of the driver)
and "try_id" can be used to force a particular ID for your device into
the system (just use -1 if you wish the system chooses one for you).

Once you have registered a new PPS source into the system you can
signal an assert event (for example in the interrupt handler routine)
just using:

    linuxpps_event(source, PPS_CAPTUREASSERT, ptr);

The same function may also run the defined echo function
(linuxpps_ktimer_echo(), passing to it the "ptr" pointer) if the user
asked for that... etc..

Please see the file drivers/pps/clients/ktimer.c for an example code.


Resources
---------

Wiki: http://wiki.enneenne.com/index.php/LinuxPPS_support and the LinuxPPS
ML:   http://ml.enneenne.com/cgi-bin/mailman/listinfo/linuxpps.


More information about the LinuxPPS mailing list