Package: ntp-shm
OverviewA pure Python interface to the NTP shared memory segment with no external
dependencies.The only platform-dependent part of this library is theSHM_CREATconstant,
which seems to always be the octal value of 01000 (Linux and BSDs). Technically
the size oftime_tis also platform-dependent, but it's 2021 and this should
be 64 bit everywhere.PrerequisitesPython: 3.7+OSs: Posix-compliant with the System V shared memory interface.This usesctypesfor direct access to memory and shared memory routines. This
will dynamically load the system's C library to accessshmget()andshmat()functions.UsageNTP Shared MemoryTheNtpShmclass wraps up access to the NTP shared memory segments. See theNTP documentationfor
information on the contents of this memory and how to safely access it.Example use:fromntp_shmimportNtpShmseg=NtpShm(segment=0)# Access copies of the memory segment (ShmTime) through read()/write()shm_time=seg.read()shm_time.count+=1shm_time.clock_time_sec=42# ...seg.write(shm_time)# Dynamic, direct access (by ref) through .refshm_time=seg.ref# Or just use seg.ref directlyshm_time.count+=1shm_time.clock_time_sec=42# ...TheShmTimeobject is actypesstructure with a few extra properties for
convenience, and with fields renamed slightly to be more pythonic. The
convenience properties can be used to set or get the clock or receive times
usingdatetimeobjects or integer time in nanoseconds.>>>shm_time=seg.ref>>>seg.ref.receive_dtdatetime.datetime(2021,9,6,13,45,3,495830,tzinfo=datetime.timezone.utc)>>>seg.ref.receive_dtdatetime.datetime(2021,9,6,13,45,4,440210,tzinfo=datetime.timezone.utc)>>>shm_time.clock_ns1630935919000000000Keep in mind that thedatetimerepresentation is only accurate to the
microsecond.Important: Direct access to the shared memory segment suffers from race
conditions. Since the time values are split up across multiple fields, these
may be modified in between field reads leading to consumers reading corrupted
values.The NTP documentation (above) specifies two different methods of updating and
reading from the shared memory segment to avoid this issue. Writing via mode 1
is implemented in theShmTime.update()method. This can be used to update
the clock and receive times:fromntp_shmimportutil,NtpShmseg=NtpShm()clock_time_ns=some_function_that_gives_integer_nanoseconds()receive_time_ns=util.datetime_to_ns(datetime.datetime.now())seg.update(clock_time_ns,receive_time_ns)Since Python lacks memory barriers or cache synchronization controls, its still
not 100% guaranteed that theupdate()method will be issue free.NTP BridgeIncluded is a utility command:ntp-shm bridge. This acts as a very basic
NMEA0183 bridge to NTP shared memory. It reads lines from a file input, looking
for and parsing valid GPRMC NMEA sentences. Valid times, after a small holdoff
to allow for stabilization, are passed to the NTP shared memory segment.The NMEA sentences must come from a file-like device, such as a character
device or pipe (stdin). For GPSs connected to a serial tty device, usesttyto configure the device for direct access. Alternatively, use one of many
applications to handle the serial interface and pipe the output tontp-shm bridge.Example tty setup for raw access (on FreeBSD).stty-f/dev/ttyu1.initraw9600Test the tty configuration usingcat /dev/ttyu1. The output should be
smooth, without extra blank lines or non-printable characters.To bridge the NMEA data onttyu1to segment 0:ntp-shmbridge-p/dev/ttyu1-s0To create a persistent process, consider usingdaemon(FreeBSD) ordaemonize(Linux) and your system's service manager.InstallationFrom pypi:pipinstallntp-shmFrom your local checkout:pipinstall[--user].orpythonsetup.pyinstall[--user]