[ntp:questions] win32_io.c

Dave Hart hart at ntp.org
Mon Aug 1 15:53:25 UTC 2011

On Tue, Jun 21, 2011 at 02:08 UTC, Charles Elliott
<elliott.ch at verizon.net> wrote:
> Hello:

I'm sorry it took me over 5 weeks to notice this message, I was on
vacation at the time.  Also, the hackers at lists.ntp.org mailing list is
more appropriate for this discussion.  I'm subscribed to both, so feel
free to replace questions@ with hackers@ once you're subscribed.

>                In win32_io.c why is the event char set to CR instead of LF
> as the NMEA protocol indicates lines are terminated with CRLF?  This might
> make a difference as if one read the message string without the LF, leaving
> it in the buffer, the next line might be begun with the LF.  The relevant
> line is #228 dcb.EvtChar = 13; /* CR */ // Should be 10;

That's the line in your source, perhaps, but here the "// Should be
10;" seems to be missing ;)

Note this code is not specific to the NMEA driver, but is used for all
serial-connected refclocks operating on the Windows port of ntpd,
including, for example, the ACTS modem refclock.  The issue being
addressed is that POSIX and Windows serial APIs are fundamentally
different, and this code is trying to emulate the POSIX semantics
using the Windows API.  In particular, many reference clocks open the
serial port in a line-oriented mode, where read() calls are not
completed until either a CR or LF is seen.  That's when the
dcb.EvtChar comes into play:  ntpd's Windows serial reading code will
not try to read until the EvtChar (CR) is reported seen by
WaitCommEvent(), at which point it will race to read everything so far
buffered.  The line so read is passed to add_full_recv_buffer() which
queues it to be dispatched to the refclock's receive entrypoint, which
for line-oriented refclocks will call a routine which strips any LFs
and CRs from the raw buffer before further processing.  To further
mimic POSIX ntpd behavior, an empty buffer is then passed to
add_full_recv_buffer().  This is because on POSIX systems each
CRLF-terminated line results in one read terminated by CR, then
another immediately terminated by the following LF.  After the
processing strips CRs and LFs, the result the refclock sees is a line
with data, then an empty line.

While in theory much the same could be achieved by using LF as the
dcb.EvtChar, to mimic POSIX the first read should be completed as soon
as CR is received.

>                Also on win32_io.c, why is the is the Comm Mask set to watch
> out for the CD line, in addition to the event flag?  If one just waits for
> the event char, then he is sure of receiving a whole line.  If he waits for
> the CD line, then a partial line or, worse, a line plus a partial line might
> be read.

You need to read ports\winnt\ntpd\ntp_iocompletionport.c as well as
win32_io.c to get a complete picture.  When the WaitCommEvent
indicates the CD line (referred to as RLSD by the Win32 API IIRC) has
changed state, the buffered data is not read from the port.  That
occurs only when WaitCommEvent() indicates the event character CR has
been seen.

The code is watching for CD state changes to provide a hack, referred
to as user-mode PPS support.  Note there is real PPSAPI support in the
Windows ntpd port, but it requires a separately-distributed modified
Windows serial.sys kernel-mode device driver (serialpps.sys) and an
associated serialpps-ppsapi-provider.dll which is optionally loaded by
ntpd.  The hack user-mode PPS support works only for the first
complete line of input after each PPS event and replaces the timestamp
for that line with the timestamp of the preceding PPS event.  This
imposes several annoying limitations compared to the real PPSAPI
approach:  the replacement happens only for one line, meaning for NMEA
you need to ensure the first line emitted by the GPS each second is
the one ntpd is processing, and the fudge factor that's supposed to be
fudging the end-of-line is in fact then fudging the PPS event
timestamp instead.

Dave Hart

More information about the questions mailing list