// rtctime.set (sec, usec) static int rtctime_set (lua_State *L) { if (!rtc_time_check_magic ()) rtc_time_prepare (); uint32_t sec = luaL_checknumber (L, 1); uint32_t usec = 0; if (lua_isnumber (L, 2)) usec = lua_tonumber (L, 2); struct rtc_timeval tv = { sec, usec }; rtctime_settimeofday (&tv); return 0; }
static void on_recv (void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, uint16_t port) { (void)port; sntp_dbg("sntp: on_recv\n"); lua_State *L = lua_getstate(); if (!state || state->pcb != pcb) { // "impossible", but don't leak if it did happen somehow... udp_remove (pcb); pbuf_free (p); return; } if (!p) return; if (p->len < sizeof (ntp_frame_t)) { pbuf_free (p); return; // not an ntp frame, ignore } // make sure we have an aligned copy to work from ntp_frame_t ntp; os_memcpy (&ntp, p->payload, sizeof (ntp)); pbuf_free (p); sntp_dbg("sntp: transmit timestamp: %u, %u\n", ntp.xmit.sec, ntp.xmit.frac); // sanity checks before we touch our clocks ip_addr_t anycast; NTP_ANYCAST_ADDR(&anycast); if (server.addr != anycast.addr && server.addr != addr->addr) return; // unknown sender, ignore if (ntp.origin.sec != state->cookie.sec || ntp.origin.frac != state->cookie.frac) return; // unsolicited message, ignore if (ntp.LI == 3) return; // server clock not synchronized (why did it even respond?!) server.addr = addr->addr; ntp.origin.sec = ntohl (ntp.origin.sec); ntp.origin.frac = ntohl (ntp.origin.frac); ntp.recv.sec = ntohl (ntp.recv.sec); ntp.recv.frac = ntohl (ntp.recv.frac); ntp.xmit.sec = ntohl (ntp.xmit.sec); ntp.xmit.frac = ntohl (ntp.xmit.frac); const uint32_t UINT32_MAXI = (uint32_t)-1; const uint64_t MICROSECONDS = 1000000ull; const uint32_t NTP_TO_UNIX_EPOCH = 2208988800ul; bool have_cb = (state->sync_cb_ref != LUA_NOREF); // if we have rtctime, do higher resolution delta calc, else just use // the transmit timestamp #ifdef LUA_USE_MODULES_RTCTIME struct rtc_timeval tv; rtctime_gettimeofday (&tv); ntp_timestamp_t dest; dest.sec = tv.tv_sec; dest.frac = (MICROSECONDS * tv.tv_usec) / UINT32_MAXI; // Compensation as per RFC2030 int64_t delta_s = (((int64_t)ntp.recv.sec - ntp.origin.sec) + ((int64_t)ntp.xmit.sec - dest.sec)) / 2; int64_t delta_f = (((int64_t)ntp.recv.frac - ntp.origin.frac) + ((int64_t)ntp.xmit.frac - dest.frac)) / 2; dest.sec += delta_s; if (delta_f + dest.frac < 0) { delta_f += UINT32_MAXI; --dest.sec; } else if (delta_f + dest.frac > UINT32_MAXI) { delta_f -= UINT32_MAXI; ++dest.sec; } dest.frac += delta_f; tv.tv_sec = dest.sec - NTP_TO_UNIX_EPOCH; tv.tv_usec = (MICROSECONDS * dest.frac) / UINT32_MAXI; rtctime_settimeofday (&tv); if (have_cb) { lua_rawgeti (L, LUA_REGISTRYINDEX, state->sync_cb_ref); lua_pushnumber (L, tv.tv_sec); lua_pushnumber (L, tv.tv_usec); } #else if (have_cb) { lua_rawgeti (L, LUA_REGISTRYINDEX, state->sync_cb_ref); lua_pushnumber (L, ntp.xmit.sec - NTP_TO_UNIX_EPOCH); lua_pushnumber (L, (MICROSECONDS * ntp.xmit.frac) / UINT32_MAXI); } #endif cleanup (L); if (have_cb) { lua_pushstring (L, ipaddr_ntoa (&server)); lua_call (L, 3, 0); } }