Esempio n. 1
0
 async def _poller(self):
     self._status = 0
     while True:
         # print("\nperforming NTP query")
         try:
             self.status = (self._status << 1) & 0xFFFF
             (delay_us, step_us) = await self._poll()
             if step_us > self._max_step or -step_us > self._max_step:
                 # large adjustment: step the clock, don't slew
                 # print(time.localtime())
                 (tgt_s, tgt_us) = divmod(time.time_us() + step_us, 1000000)
                 log.warning("stepping to %s", time.localtime(tgt_s))
                 settime(tgt_s, tgt_us)
                 # print(time.localtime())
             # if the adjustment is too small WRT round-trip delay, it's likely not to be
             # very good and result in lots of noise, so skip
             elif step_us > 2 * delay_us or -step_us > 2 * delay_us:
                 lvl = logging.DEBUG if abs(
                     step_us) < 10000 else logging.INFO
                 log.log(lvl, "adjusting by %dus (delay=%dus)", step_us,
                         delay_us)
                 adjtime(step_us)
             self.status |= 1
             await asyncio.sleep(61)
         except asyncio.TimeoutError:
             log.warning("%s timed out", self._host)
             if (self._status & 0x7) == 0:
                 # Three failures in a row, force fresh DNS look-up
                 self.sock = None
                 await asyncio.sleep(11)
         except OSError as e:
             # Most likely DNS lookup failure
             log.warning("%s: %s", self._host, e)
             self.sock = None
             await asyncio.sleep(11)
         except Exception as e:
             log.error("%s", e)
             print_exception(e)
             await asyncio.sleep(121)
Esempio n. 2
0
 async def _poller(self):
     self._status = 0
     while True:
         # print("\nperforming NTP query")
         try:
             self.status = (self._status << 1) & 0xFFFF
             (delay_us, step_us) = await self._poll()
             if step_us > self._max_step or -step_us > self._max_step:
                 # print(time.localtime())
                 (tgt_s, tgt_us) = divmod(time.time_us() + step_us, 1000000)
                 log.warning("stepping to %s", time.localtime(tgt_s))
                 settime(tgt_s, tgt_us)
                 # print(time.localtime())
             else:
                 lvl = logging.DEBUG if abs(
                     step_us) < 10000 else logging.INFO
                 log.log(lvl, "adjusting by %dus (delay=%dus)", step_us,
                         delay_us)
                 adjtime(step_us)
             self.status |= 1
             await asyncio.sleep(61)
         except asyncio.TimeoutError:
             log.warning("%s timed out", self._host)
             if (self._status & 0x7) == 0:
                 # Three failures in a row, force fresh DNS look-up
                 self.sock = None
                 await asyncio.sleep(11)
         except OSError as e:
             # Most likely DNS lookup failure
             log.warning("%s: %s", self._host, e)
             self.sock = None
             await asyncio.sleep(11)
         except Exception as e:
             log.error("%s", e)
             print_exception(e)
             await asyncio.sleep(121)
Esempio n. 3
0
    async def _poll(self):
        # We try to stay with the same server as long as possible. Only
        # lookup the address on startup or after errors.
        if self._sock is None:
            self._addr = socket.getaddrinfo(self._host, 123)[0][-1]
            log.debug("server %s->%s", self._host, self._addr)
            if sys.implementation.name == "micropython":
                self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
                self._sock.connect(self._addr)
                stream = asyncio.StreamReader(self._sock)

                async def write_drain(pkt):
                    stream.write(pkt)
                    await stream.drain()

                self._send = write_drain
                self._recv = lambda length: stream.read(length)
                self._close = lambda: self._sock.close()
            else:
                stream = await dgram_connect(self._addr)

                async def stream_send(pkt):
                    return await stream.send(pkt)

                self._send = stream_send

                async def stream_recv(length):
                    return (await stream.recv())[0]

                self._recv = stream_recv
                self._close = lambda: stream.close()

        # Send the NTP v3 request to the server
        wbuf = bytearray(48)
        wbuf[0] = 0b00011011
        send_us = time_us()
        send_ntp = mp2ntp(send_us)
        struct.pack_into("!II", wbuf, OFF_TX, send_ntp[0],
                         send_ntp[1])  # set tx timestamp
        await self._send(wbuf)

        # Get server reply
        while True:
            # Raises asyncio.TimeoutError on time-out
            rbuf = await asyncio.wait_for(self._recv(48), timeout=1)
            recv_us = time_us()
            # Verify it's truly a response to our request
            orig_ntp = struct.unpack_from("!II", rbuf,
                                          OFF_ORIG)  # get originate timestamp
            if orig_ntp == send_ntp:
                break

        # Calculate clock step to apply per RFC4330
        rx_us = ntp2mp(*struct.unpack_from(
            "!II", rbuf, OFF_RX))  # get server recv timestamp
        tx_us = ntp2mp(*struct.unpack_from(
            "!II", rbuf, OFF_TX))  # get server transmit timestamp
        delay = (recv_us - send_us) - (tx_us - rx_us)
        step = ((rx_us - send_us) + (tx_us - recv_us)) // 2

        tup = struct.unpack_from("!IIIIII", rbuf, OFF_ORIG)
        r = mp2ntp(recv_us)
        # log.debug( "orig=[%d,%x] rx=[%d,%x] tx=[%d,%x] recv=[%d,%x] -> delay=%fms step=%dus",
        #    tup[0], tup[1], tup[2], tup[3], tup[4], tup[5], r[0], r[1], delay / 1000, step)

        return (delay, step)
Esempio n. 4
0
 def adjtime(usecs):
     print("adjtime(%d) - an adjustment of %d" % (usecs, time_us() -
                                                  (usecs + UNIX_DELTA)))
Esempio n. 5
0
 def settime(usecs):
     print("settime(%d) - a step of %d" % (usecs, time_us() -
                                           (usecs + UNIX_DELTA)))