[LinuxPPS] Advise on kernel documentation

Rodolfo Giometti giometti at enneenne.com
Wed Feb 7 11:02:43 CET 2007


On Wed, Feb 07, 2007 at 10:21:52AM +0100, Bernhard Schiffner wrote:
> 
> BTW: I didn't try the SYSFS. It's possible to do some write there to change 
> pps behavior?
> echo 1 > /sys/class/pps/00/echo ?

Currently not.

> --- pps.txt     2007-02-07 10:08:10.000000000 +0100
> +++ pps_4.txt   2007-02-07 10:18:44.000000000 +0100
> @@ -113,7 +113,7 @@
>                         PPS_CAPTUREASSERT|PPS_OFFSETASSERT,
>                         -1 /* is up to the system */);
> 
> -The linuxpps_register_source() prototipe is:
> +The linuxpps_register_source() prototype is:
> 
>    int linuxpps_register_source(struct linuxpps_source_info_s *info, int 
> default_params, int try_id)

Applied.

> @@ -141,13 +141,13 @@
>  PROCFS support
>  --------------
> 
> -If the PROCFS support is enabled a new directory is created:
> +If PROCFS support is enabled a new directory /proc/pps is created:
> 
>      $ ls /proc/pps/
>      00       01       sources

Applied.

>  The file "sources" holds a brief description of all PPS sources
> -defined into the system:
> +defined in the system:
> 
>      $ cat /proc/pps/sources
>      id    mode         echo    name                    path

Applied.

> @@ -155,7 +155,7 @@
>      00    1133         no      serial0                 /dev/ttyS0
>      01    1133         no      serial1                 /dev/ttyS1
> 
> -while other files are directories that hold one or two files according
> +The other entries are directories that hold one or two files according
>  to the ability of the associated source to provide "assert" and
>  "clear" timestamps:

Applied.

> @@ -163,7 +163,7 @@
>      assert               clear
> 
>  Inside each "assert" and "clear" file you can find the timestamp and a
> -sequence number as reported below:
> +sequence number:
> 
>      $ cat /proc/pps/00/assert
>      1170026870.983207967 #8

Applied.

> @@ -173,25 +173,26 @@
>  -------------
> 
>  The SYSFS support is enabled by default if the SYSFS filesystem is
> -enabled into the kernel and it provides a new class:
> +enabled in 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:
> +Every directory is the ID of a PPS source defined in the system
> +and inside you 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 (even if with different syntax due the one-value-per-file
> -sysfs pragma) while other files are:
> +Files "assert" and "clear" have the same functionality as their PROCFS
> +counterparts but with different syntax due to the one-value-per-file
> + sysfs pragma.
> +Other files are:

Applied.

>  * echo: reports if the PPS source has an echo function or not;
> 
> -* mode: reports available PPS functioning modes (in the same form of
> -  PROCFS);
> +* mode: reports available PPS functioning modes (in the same form as
> +  PROCFS does);
> 
>  * name: reports the PPS source's name;

Applied.

All applied! :)

Thanks,

Rodolfo

P.S. I attach the new doc version.

-- 

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

(C) Copyright 2007 Rodolfo Giometti <giometti at enneenne.com>


Overview
--------

LinuxPPS provides a programming interface (API) to define into the
system several PPS sources.

PPS means "pulse per second" and a PPS source is just a device who
provides 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 (ACK-pin) 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.

Common use is the combination of the NTPD as userland program with a
GPS receiver as PPS source to obtain a wallclock-time with
sub-millisecond synchronisation to UTC.


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

While implementing a PPS API as RFC 2783 defines and using an embedded
CPU GPIO-Pin as physical link to the signal, I encountered a deeper
problem:

   At startup it needs a file descriptor as argument for the function
   time_pps_create().

This implies that the source has a /dev/... entry. This assumption is
ok for the serial and parallel port, where you can do something
usefull beside(!) the gathering of timestamps as it is the central
task for a PPS-API. But this assumption does not work for a single
purpose GPIO line. In this case even basic file-related functionality
(like read() and write()) makes no sense at all and should not be a
precondition for the use of a PPS-API.

The problem can be simply solved if you change the original RFC 2783:

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

into a modified:

   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.

This change seems to be neglibile because even the original RFC 2783
does not encourage programs to check (read: use) the pps_handle_t
variable before calling the time_pps_*() functions, since each
function should do this job internally.

If I intentionally separate the concept of "file descriptor" from the
concept of the "PPS source" I'm obliged to provide a solution to find
and register a PPS-source without using a file descriptor: it's done
by the functions time_pps_findsource() and time_pps_findpath() now.

According to this current NTPD drivers' code should be modified as
follows:

+#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() prototype 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 PROCFS support is enabled a new directory "/proc/pps" is created:

    $ ls /proc/pps/
    00       01       sources

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

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

The other entries 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:

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


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

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

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

Every directory is the ID of each PPS sources defined into the system
and inside you 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 their PROCFS
counterparts but with different syntax due the one-value-per-file
sysfs pragma. 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 as
  PROCFS does);

* 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