[LinuxPPS] Advise on kernel documentation

Rodolfo Giometti giometti at enneenne.com
Mon Jan 29 00:37:54 CET 2007


On Mon, Jan 29, 2007 at 12:17:36AM +0100, Rodolfo Giometti wrote:

> 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.

Please, consider this last version! :)

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.


PROCFS support
--------------

If the PROCFS support is enabled a new directory is created:

    $ ls /proc/pps/
    00       01       sources

The file "sources" holds a brief description of all PPS sources
defined into the system:

    $ cat /proc/pps/sources 
    id    mode		echo	name			path
    ----  ------	----	----------------	----------------
    00    1133		no	serial0			/dev/ttyS0
    01    1133		no	serial1			/dev/ttyS1

while other files are directories that hold one or two files according
to the ability of the associated source to provide "assert" and
"clear" timestamps:

    $ ls /proc/pps/00 
    assert		  clear

Inside each "assert" and "clear" file you can find the timestamp and a
sequence number as reported below:

    $ cat /proc/pps/00/assert 
    1170026870.983207967 #8


SYSFS support
-------------

The SYSFS support is enabled by default if the SYSFS filesystem is
enabled into the kernel and it provides a new class:

   $ ls /sys/class/pps/
   00/  01/  02/

Each directory is the ID of each PPS sources defined into the system
and inside each one you can find several files:

    $ ls /sys/class/pps/00/
    assert	clear  echo  mode  name  path  subsystem@  uevent

Files "assert" and "clear" have the same functionality as the PROCFS
alter ego while other files are:

* echo: reports if the PPS source has an echo function or not;

* mode: reports available PPS functioning modes (in the same form of
  PROCFS);

* name: reports the PPS source's name;

* path: reports the PPS source's device path, that is the device the
  PPS source is connected to (if it exists).


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