Subject: Re: new TIODCDTIMESTAMP patch
To: Chris Torek <torek@BSDI.COM>
From: Jonathan Stone <jonathan@DSG.Stanford.EDU>
List: tech-kern
Date: 04/21/1998 16:23:57
>But we still need the `bad' bits used by the existing code.
 [and]
>I think more general timestamping (and management) is a separate isssue.

>I am not quite sure what you meant by "separate issue".  There is
>a pretty clear migration path, I think, that shows they are entwined:

> 1) ask the NTP folks to add:
>
>        #ifdef TIOCSTSTAMP
>        {
>                int how = DCD_LEADING_EDGE;
>		if (ioctl(fd, TIOCSTSTAMP, &how)) ... error ...
>        }
>        #endif

Hi Chris,

I see what you're getting at.  The latest patch I posted has get and
set ioctls, and I buy into

 * your names (like I said, I'm lousy at ioctl names)
 * the symbolic namespace for 
       NONE, 
       DCD_LEADINGEDGE,
       DCD_TRAILING_EDGE,   (even if we don't implement, its a hardware bug),

But this API really truly is for GPS or atomic clock pulse-per-second
sampling.  I'd like to use this ioctl interface for other PPS sources.
But I think it's a bad design decision to fold other, unrelated
timestamping into either the API or the datastream of PPS timestamps.

There are other NTP apps which want timestamping, but the actual radio
clock signals, and the processing required for them, are very
different to the PPS signal which DCD_LEADINGEDGE handles.

I'm gonna go back to the basics again, just to be sure we're on the
same, uh, wavelength, and I dunno how much you know about this stuff.


\begin{NTP_TUTORIAL}
  The case, the only I'm aiming at here is a GPS radio clock (or
  reference atomic clock) which emits an once-per-second, on-the-second
  pusle (PPS), accurate to within microseconds.  NTP wants to use that
  PPS pulse to discipline the local clock.  The clock also provides
  ASCII-encoded timestamps, but GPS embeded realtime system does those
  at low priority and they're +- 200 ms.  For this app, the important
  thing is the phase difference between the reflock PPs and the local
  clock time.  As long as you know the period beteen samples, It doesn't
  matter when you collect the timestamp. IIRC, xtnpd can sample up to 15
  minutes apart, and it keeps track of the period between samples so it
  can calculate drift and do its thing.  (xntp might sample every
  second; i dont remember.)
  
  The ``other'' case where NTP might want timestamping is for obsolete
  radio-clock signals, or bad GPS clocks, which don't have a PPS signal.
  Some radio signals, like CHU, emit about ten time "pips" per second
  with abotu ten bytes for each "pip".  To reconstruct the time, you
  need to get the timestamps for each char of each "pip", and do a
  convolution on those timestamps. That lets you figure out when the
  atomic-second epoch happened relative to the low-data-rate "pips"
  (e.g., 300 baud for CHU).  You can get to +- 30 ms this way -- four
  orders of magnitude worse than PPS, but good enough for home use.
  
  For this application, the kernel API is a linediscipline which stuffs
  four bytes of tv_usec into tty the data stream after each input char.
  Or for slightly more friendly clock signals, stuffs in four bytes
  of tv_usec only for `distinguished'   chars (e.g., CR or DEL).

  The ioctl interface for setting and getting timestaps doesn't really
  cut it here, since there's no good way to associate any one timestamp
  fetched via ioctl() with a specific char, and the application *needs*
  that information.  The linedisciplines also have code to do some basic
  error-checking and filtering (shortwave is noisy).
  
  If there are applications where timestamping each char is useful, then
  I'd buy extending this API to support that.  I don't know of any, and
  I dont' see how to get round the problem of tying a timestamp to a
  specific char. 

\end{NTP_TUTORIAL}

I really, really regret being ``long-winded'' again, but I'm told
again and again that these distinctuions are really confusing to
non-NTP people.  There doesn't seem to be any way to win.


Are there any apps that care about an in-kernel timestamp of the "most
recent" input char, irrespective of which char it is?  My take is that
you'd probably want two distinct _separate_ timestamps here: one for
the data steram and one for the DCD edge(s).  And it's certainly not
useful to NTP.

FreeBSD has an ioctl to timestamp data, but it's a separate ioctl with
a separate timestamp field. I don't know what it's used for and as I
said earlier, I dont' want to add that without seeing some use for it.


> GTSTAMP
>    might well be in common code (while STSTAMP gets examined by
>    the driver -- maybe DCD is not available on particular serial
>    ports).

But putting these in common code loses, unless we also move the
timestamp value to the struct tty. And that loses, for serial devices
that aren't tty devices (e.g., keyboards?).  With wscons, I can see
someone wanting to hook up a second keyboard to a zs serial port, and
using the modem lead of that port for a PPS signal from a cheap
handheld GPS device.

Plus, we'd want to duplicate all this for parallel ports, since that
avoids the $200 or so for a spiffy level-converter...


> 2) Write the appropriate kernel code, with a compat hack so that
>    "get last stamp" has the side effect of going from "off" to
>    DCD_LEADINGEDGE mode.  The compat hack can be removed when
>    step 1 above has been in effect long enough.

That's what i did alrady , but with the old 0=off, 1=compile-time
selected edge.  


And I don't buy folding non-PPS timestamps into the stream of PPS
timestamps. But Suppose we do support multiple kinds of timestamps
(dcd PPS and per-char). What would you recommend: a distinct ioctl()
to fetch each kind of timestamp, or one ioctl() which takes a
timeval/timespec and an encoding of which timestamp stream (and
resolution) to fetch? something like


	struct tstamparg { int kind; union { timeval tv;  timespec ts}};

	struct tstmparg tstamp;
	/* Fetch a timestamp. Timestamps  could be  
	    TSTAMP_TS_DCD
	    TSTAMP_TV_DCD
	    TSTAMP_TS_PERCHAR,
	    TSTAMP_TV_PERCHAR, 	     ... */

	tstmap.kind = TSTAMP_TV_PPS;
	ioctl(fd, TIOCFETCHTSTMP, &tstamp);