Example #1
0
// Queue an interrupt and set the Lua hook
// Returns PLATFORM_OK or PLATFORM_ERR
int elua_int_add( elua_int_id inttype, elua_int_resnum resnum )
{
  if( inttype < ELUA_INT_FIRST_ID || inttype > INT_ELUA_LAST )
    return PLATFORM_ERR;

  // If Lua is not running (no Lua state), or no Lua interrupt handler is set, 
  // or the interrupt is not enabled, don't do anything
  if( lua_getstate() == NULL || !elua_int_is_enabled( inttype ) )
    return PLATFORM_ERR;

  // If there's no more room in the queue, set the overflow flag and return
  if( elua_int_queue[ elua_int_write_idx ].id != ELUA_INT_EMPTY_SLOT )
  {
    printf( "ERROR in elua_int_add: buffer overflow, interrupt not queued\n" );
    return PLATFORM_ERR;
  }

  // Queue the interrupt
  elua_int_queue[ elua_int_write_idx ].id = inttype;
  elua_int_queue[ elua_int_write_idx ].resnum = resnum;
  elua_int_write_idx = ( elua_int_write_idx + 1 ) & INT_IDX_MASK;

  // Set the Lua hook (it's OK to set it even if it's already set)
  lua_sethook( lua_getstate(), elua_int_hook, LUA_MASKCOUNT, 2 ); 

  // All OK
  return PLATFORM_OK;
}
Example #2
0
static void net_dns_cb(const char *name, ip_addr_t *ipaddr, void *arg) {
  ip_addr_t addr;
  if (ipaddr != NULL) addr = *ipaddr;
  else addr.addr = 0xFFFFFFFF;
  lnet_userdata *ud = (lnet_userdata*)arg;
  if (!ud) return;
  lua_State *L = lua_getstate();
  if (ud->self_ref != LUA_NOREF && ud->client.cb_dns_ref != LUA_NOREF) {
    lua_rawgeti(L, LUA_REGISTRYINDEX, ud->client.cb_dns_ref);
    lua_rawgeti(L, LUA_REGISTRYINDEX, ud->self_ref);
    if (addr.addr != 0xFFFFFFFF) {
      char iptmp[16];
      bzero(iptmp, 16);
      ets_sprintf(iptmp, IPSTR, IP2STR(&addr.addr));
      lua_pushstring(L, iptmp);
    } else {
      lua_pushnil(L);
    }
    lua_call(L, 2, 0);
  }
  ud->client.wait_dns --;
  if (ud->pcb && ud->type == TYPE_TCP_CLIENT && ud->tcp_pcb->state == CLOSED) {
    tcp_connect(ud->tcp_pcb, &addr, ud->tcp_pcb->remote_port, net_connected_cb);
  } else if (!ud->pcb && ud->client.wait_dns == 0) {
    lua_gc(L, LUA_GCSTOP, 0);
    luaL_unref(L, LUA_REGISTRYINDEX, ud->self_ref);
    ud->self_ref = LUA_NOREF;
    lua_gc(L, LUA_GCRESTART, 0);
  }
}
Example #3
0
static void alarm_timer_common(void* arg){
	timer_t tmr = (timer_t)arg;
	lua_State* L = lua_getstate();
	if(tmr->lua_ref == LUA_NOREF)
		return;
	lua_rawgeti(L, LUA_REGISTRYINDEX, tmr->lua_ref);
	if (tmr->self_ref == LUA_REFNIL) {
		uint32_t id = tmr - alarm_timers;
		lua_pushinteger(L, id);
	} else {
		lua_rawgeti(L, LUA_REGISTRYINDEX, tmr->self_ref);
	}
	//if the timer was set to single run we clean up after it
	if(tmr->mode == TIMER_MODE_SINGLE){
		luaL_unref(L, LUA_REGISTRYINDEX, tmr->lua_ref);
		tmr->lua_ref = LUA_NOREF;
		tmr->mode = TIMER_MODE_OFF;
	}else if(tmr->mode == TIMER_MODE_SEMI){
		tmr->mode |= TIMER_IDLE_FLAG;
	}
	if (tmr->mode != TIMER_MODE_AUTO && tmr->self_ref != LUA_REFNIL) {
		luaL_unref(L, LUA_REGISTRYINDEX, tmr->self_ref);
		tmr->self_ref = LUA_NOREF;
	}
	lua_call(L, 1, 0);
}
Example #4
0
static void net_recv_cb(lnet_userdata *ud, struct pbuf *p, ip_addr_t *addr, u16_t port) {
  if (ud->client.cb_receive_ref == LUA_NOREF) {
    pbuf_free(p);
    return;
  }

  int num_args = 2;
  char iptmp[16] = { 0, };
  if (ud->type == TYPE_UDP_SOCKET)
  {
    num_args += 2;
    ets_sprintf(iptmp, IPSTR, IP2STR(&addr->addr));
  }

  lua_State *L = lua_getstate();
  struct pbuf *pp = p;
  while (pp)
  {
    lua_rawgeti(L, LUA_REGISTRYINDEX, ud->client.cb_receive_ref);
    lua_rawgeti(L, LUA_REGISTRYINDEX, ud->self_ref);
    lua_pushlstring(L, pp->payload, pp->len);
    if (ud->type == TYPE_UDP_SOCKET) {
      lua_pushinteger(L, port);
      lua_pushstring(L, iptmp);
    }
    lua_call(L, num_args, 0);
    pp = pp->next;
  }
  pbuf_free(p);
}
Example #5
0
static err_t net_accept_cb(void *arg, struct tcp_pcb *newpcb, err_t err) {
  lnet_userdata *ud = (lnet_userdata*)arg;
  if (!ud || ud->type != TYPE_TCP_SERVER || !ud->pcb) return ERR_ABRT;
  if (ud->self_ref == LUA_NOREF || ud->server.cb_accept_ref == LUA_NOREF) return ERR_ABRT;

  lua_State *L = lua_getstate();
  lua_rawgeti(L, LUA_REGISTRYINDEX, ud->server.cb_accept_ref);

  lnet_userdata *nud = net_create(L, TYPE_TCP_CLIENT);
  lua_pushvalue(L, 2);
  nud->self_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  nud->tcp_pcb = newpcb;
  tcp_arg(nud->tcp_pcb, nud);
  tcp_err(nud->tcp_pcb, net_err_cb);
  tcp_recv(nud->tcp_pcb, net_tcp_recv_cb);
  tcp_sent(nud->tcp_pcb, net_sent_cb);
  nud->tcp_pcb->so_options |= SOF_KEEPALIVE;
  nud->tcp_pcb->keep_idle = ud->server.timeout * 1000;
  nud->tcp_pcb->keep_cnt = 1;
  tcp_accepted(ud->tcp_pcb);

  lua_call(L, 1, 0);

  return net_connected_cb(nud, nud->tcp_pcb, ERR_OK);
}
Example #6
0
static void tls_socket_onreconnect( struct espconn *pesp_conn, s8 err ) {
  tls_socket_ud *ud = (tls_socket_ud *)pesp_conn->reverse;
  if (!ud || ud->self_ref == LUA_NOREF) return;
  if (ud->cb_reconnect_ref != LUA_NOREF) {
    const char* reason = NULL;
    switch (err) {
      case(ESPCONN_MEM): reason = "Out of memory"; break;
      case(ESPCONN_TIMEOUT): reason = "Timeout"; break;
      case(ESPCONN_RTE): reason = "Routing problem"; break;
      case(ESPCONN_ABRT): reason = "Connection aborted"; break;
      case(ESPCONN_RST): reason = "Connection reset"; break;
      case(ESPCONN_CLSD): reason = "Connection closed"; break;
      case(ESPCONN_HANDSHAKE): reason = "SSL handshake failed"; break;
      case(ESPCONN_SSL_INVALID_DATA): reason = "SSL application invalid"; break;
    }
    lua_State *L = lua_getstate();
    lua_rawgeti(L, LUA_REGISTRYINDEX, ud->cb_reconnect_ref);
    lua_rawgeti(L, LUA_REGISTRYINDEX, ud->self_ref);
    if (reason != NULL) {
      lua_pushstring(L, reason);
    } else {
      lua_pushnil(L);
    }
    tls_socket_cleanup(ud);
    lua_call(L, 2, 0);
  } else tls_socket_cleanup(ud);
}
Example #7
0
static void tls_socket_dns_cb( const char* domain, const ip_addr_t *ip_addr, tls_socket_ud *ud ) {
  if (ud->self_ref == LUA_NOREF) return;
  ip_addr_t addr;
  if (ip_addr) addr = *ip_addr;
  else addr.addr = 0xFFFFFFFF;
  lua_State *L = lua_getstate();
  if (ud->cb_dns_ref != LUA_NOREF) {
    lua_rawgeti(L, LUA_REGISTRYINDEX, ud->cb_dns_ref);
    lua_rawgeti(L, LUA_REGISTRYINDEX, ud->self_ref);
    if (addr.addr == 0xFFFFFFFF) {
      lua_pushnil(L);
    } else {
      char tmp[20];
      c_sprintf(tmp, IPSTR, IP2STR(&addr.addr));
      lua_pushstring(L, tmp);
    }
    lua_call(L, 2, 0);
  }
  if (addr.addr == 0xFFFFFFFF) {
    lua_gc(L, LUA_GCSTOP, 0);
    luaL_unref(L, LUA_REGISTRYINDEX, ud->self_ref);
    ud->self_ref = LUA_NOREF;
    lua_gc(L, LUA_GCRESTART, 0);
  } else {
    os_memcpy(ud->pesp_conn->proto.tcp->remote_ip, &addr.addr, 4);
    espconn_secure_connect(ud->pesp_conn);
  }
}
Example #8
0
static void do_node_task (task_param_t task_fn_ref, uint8_t prio)
{
  lua_State* L = lua_getstate();
  lua_rawgeti(L, LUA_REGISTRYINDEX, (int)task_fn_ref);
  luaL_unref(L, LUA_REGISTRYINDEX, (int)task_fn_ref);
  lua_pushinteger(L, prio);
  lua_call(L, 1, 0);
}
Example #9
0
static err_t net_sent_cb(void *arg, struct tcp_pcb *tpcb, u16_t len) {
  lnet_userdata *ud = (lnet_userdata*)arg;
  if (!ud || !ud->pcb || ud->type != TYPE_TCP_CLIENT || ud->self_ref == LUA_NOREF) return ERR_ABRT;
  if (ud->client.cb_sent_ref == LUA_NOREF) return ERR_OK;
  lua_State *L = lua_getstate();
  lua_rawgeti(L, LUA_REGISTRYINDEX, ud->client.cb_sent_ref);
  lua_rawgeti(L, LUA_REGISTRYINDEX, ud->self_ref);
  lua_call(L, 1, 0);
  return ERR_OK;
}
Example #10
0
static void key_short_press(void *arg) {
  lua_State *L = lua_getstate();
  NODE_DBG("key_short_press is called.\n");
  if (short_key_ref == LUA_NOREF) {
    default_short_press(arg);
    return;
  }
  lua_rawgeti(L, LUA_REGISTRYINDEX, short_key_ref);
  lua_call(L, 0, 0);
}
Example #11
0
static void tls_socket_onconnect( struct espconn *pesp_conn ) {
  tls_socket_ud *ud = (tls_socket_ud *)pesp_conn->reverse;
  if (!ud || ud->self_ref == LUA_NOREF) return;
  if (ud->cb_connect_ref != LUA_NOREF) {
    lua_State *L = lua_getstate();
    lua_rawgeti(L, LUA_REGISTRYINDEX, ud->cb_connect_ref);
    lua_rawgeti(L, LUA_REGISTRYINDEX, ud->self_ref);
    lua_call(L, 1, 0);
  }
}
Example #12
0
static void on_timeout (void *arg)
{
  (void)arg;
  sntp_dbg("sntp: timer\n");
  lua_State *L = lua_getstate ();
  if (state->attempts >= MAX_ATTEMPTS)
    handle_error (L, NTP_TIMEOUT_ERR);
  else
    sntp_dosend (L);
}
Example #13
0
static void tls_socket_onrecv( struct espconn *pesp_conn, char *buf, u16 length ) {
  tls_socket_ud *ud = (tls_socket_ud *)pesp_conn->reverse;
  if (!ud || ud->self_ref == LUA_NOREF) return;
  if (ud->cb_receive_ref != LUA_NOREF) {
    lua_State *L = lua_getstate();
    lua_rawgeti(L, LUA_REGISTRYINDEX, ud->cb_receive_ref);
    lua_rawgeti(L, LUA_REGISTRYINDEX, ud->self_ref);
    lua_pushlstring(L, buf, length);
    lua_call(L, 2, 0);
  }
}
Example #14
0
static err_t net_connected_cb(void *arg, struct tcp_pcb *tpcb, err_t err) {
  lnet_userdata *ud = (lnet_userdata*)arg;
  if (!ud || ud->pcb != tpcb) return ERR_ABRT;
  if (err != ERR_OK) {
    net_err_cb(arg, err);
    return ERR_ABRT;
  }
  lua_State *L = lua_getstate();
  if (ud->self_ref != LUA_NOREF && ud->client.cb_connect_ref != LUA_NOREF) {
    lua_rawgeti(L, LUA_REGISTRYINDEX, ud->client.cb_connect_ref);
    lua_rawgeti(L, LUA_REGISTRYINDEX, ud->self_ref);
    lua_call(L, 1, 0);
  }
  return ERR_OK;
}
Example #15
0
static void sntp_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
{
  (void)arg;

  lua_State *L = lua_getstate ();
  if (ipaddr == NULL)
  {
    sntp_dbg("DNS Fail!\n");
    handle_error(L, NTP_DNS_ERR);
  }
  else
  {
    server = *ipaddr;
    sntp_dosend(L);
  }
}
Example #16
0
static void pcm_start_play_task( task_param_t param, uint8 prio )
{
  lua_State *L = lua_getstate();
  pud_t *pud = (pud_t *)param;
  cfg_t *cfg = &(pud->cfg);

  // stop driver before starting it in case it hasn't been stopped from Lua
  pud->drv->stop( cfg );

  if (!pud->drv->play( cfg )) {
      luaL_error( L, "pcm driver start" );
  }

  // unthrottle ISR and reader
  pud->cfg.isr_throttled = 0;
}
Example #17
0
static void tls_socket_cleanup(tls_socket_ud *ud) {
  if (ud->pesp_conn) {
    espconn_secure_disconnect(ud->pesp_conn);
    if (ud->pesp_conn->proto.tcp) {
      c_free(ud->pesp_conn->proto.tcp);
      ud->pesp_conn->proto.tcp = NULL;
    }
    c_free(ud->pesp_conn);
    ud->pesp_conn = NULL;
  }
  lua_State *L = lua_getstate();
  lua_gc(L, LUA_GCSTOP, 0);
  luaL_unref(L, LUA_REGISTRYINDEX, ud->self_ref);
  ud->self_ref = LUA_NOREF;
  lua_gc(L, LUA_GCRESTART, 0);
}
Example #18
0
static void websocketclient_onConnectionCallback(ws_info *ws) {
  NODE_DBG("websocketclient_onConnectionCallback\n");

  lua_State *L = lua_getstate();

  if (ws == NULL || ws->reservedData == NULL) {
    luaL_error(L, "Client websocket is nil.\n");
    return;
  }
  ws_data *data = (ws_data *) ws->reservedData;

  if (data->onConnection != LUA_NOREF) {
    lua_rawgeti(L, LUA_REGISTRYINDEX, data->onConnection); // load the callback function
    lua_rawgeti(L, LUA_REGISTRYINDEX, data->self_ref);  // pass itself, #1 callback argument
    lua_call(L, 1, 0);
  }
}
Example #19
0
static void websocketclient_onReceiveCallback(ws_info *ws, char *message, int opCode) {
  NODE_DBG("websocketclient_onReceiveCallback\n");

  lua_State *L = lua_getstate();

  if (ws == NULL || ws->reservedData == NULL) {
    luaL_error(L, "Client websocket is nil.\n");
    return;
  }
  ws_data *data = (ws_data *) ws->reservedData;

  if (data->onReceive != LUA_NOREF) {
    lua_rawgeti(L, LUA_REGISTRYINDEX, data->onReceive); // load the callback function
    lua_rawgeti(L, LUA_REGISTRYINDEX, data->self_ref);  // pass itself, #1 callback argument
    lua_pushstring(L, message); // #2 callback argument
    lua_pushnumber(L, opCode); // #3 callback argument
    lua_call(L, 3, 0);
  }
}
Example #20
0
static void wifi_status_cb(int arg)
{
  lua_State* L = lua_getstate();
  if (wifi_get_opmode() == SOFTAP_MODE)
  {
    os_timer_disarm(&wifi_sta_status_timer);
    return;
  }
  int wifi_status = wifi_station_get_connect_status();
  if (wifi_status != prev_wifi_status)
  {
    if(wifi_station_status_cb_ref[wifi_status] != LUA_NOREF)
    {
      lua_rawgeti(L, LUA_REGISTRYINDEX, wifi_station_status_cb_ref[wifi_status]);
      lua_pushnumber(L, prev_wifi_status);
      lua_call(L, 1, 0);
    }
  }
  prev_wifi_status = wifi_status;
}
Example #21
0
void output_redirect(const char *str) {
  lua_State *L = lua_getstate();
  // if(c_strlen(str)>=TX_BUFF_SIZE){
  //   NODE_ERR("output too long.\n");
  //   return;
  // }

  if (output_redir_ref == LUA_NOREF || !L) {
    uart0_sendStr(str);
    return;
  }

  if (serial_debug != 0) {
    uart0_sendStr(str);
  }

  lua_rawgeti(L, LUA_REGISTRYINDEX, output_redir_ref);
  lua_pushstring(L, str);
  lua_call(L, 1, 0);   // this call back function should never user output.
}
Example #22
0
static void net_dns_static_cb(const char *name, ip_addr_t *ipaddr, void *callback_arg) {
  ip_addr_t addr;
  if (ipaddr != NULL)
    addr = *ipaddr;
  else addr.addr = 0xFFFFFFFF;
  int cb_ref = ((int*)callback_arg)[0];
  c_free(callback_arg);
  lua_State *L = lua_getstate();

  lua_rawgeti(L, LUA_REGISTRYINDEX, cb_ref);
  lua_pushnil(L);
  if (addr.addr != 0xFFFFFFFF) {
    char iptmp[20];
    size_t ipl = c_sprintf(iptmp, IPSTR, IP2STR(&addr.addr));
    lua_pushlstring(L, iptmp, ipl);
  } else {
    lua_pushnil(L);
  }
  lua_call(L, 2, 0);

  luaL_unref(L, LUA_REGISTRYINDEX, cb_ref);
}
Example #23
0
static void net_err_cb(void *arg, err_t err) {
  lnet_userdata *ud = (lnet_userdata*)arg;
  if (!ud || ud->type != TYPE_TCP_CLIENT || ud->self_ref == LUA_NOREF) return;
  ud->pcb = NULL; // Will be freed at LWIP level
  lua_State *L = lua_getstate();
  int ref;
  if (err != ERR_OK && ud->client.cb_reconnect_ref != LUA_NOREF)
    ref = ud->client.cb_reconnect_ref;
  else ref = ud->client.cb_disconnect_ref;
  if (ref != LUA_NOREF) {
    lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
    lua_rawgeti(L, LUA_REGISTRYINDEX, ud->self_ref);
    lua_pushinteger(L, err);
    lua_call(L, 2, 0);
  }
  if (ud->client.wait_dns == 0) {
    lua_gc(L, LUA_GCSTOP, 0);
    luaL_unref(L, LUA_REGISTRYINDEX, ud->self_ref);
    ud->self_ref = LUA_NOREF;
    lua_gc(L, LUA_GCRESTART, 0);
  }
}
Example #24
0
static void websocketclient_onCloseCallback(ws_info *ws, int errorCode) {
  NODE_DBG("websocketclient_onCloseCallback\n");

  lua_State *L = lua_getstate();

  if (ws == NULL || ws->reservedData == NULL) {
    luaL_error(L, "Client websocket is nil.\n");
    return;
  }
  ws_data *data = (ws_data *) ws->reservedData;  

  if (data->onClose != LUA_NOREF) {
    lua_rawgeti(L, LUA_REGISTRYINDEX, data->onClose); // load the callback function
    lua_rawgeti(L, LUA_REGISTRYINDEX, data->self_ref);  // pass itself, #1 callback argument
    lua_pushnumber(L, errorCode); // pass the error code, #2 callback argument
    lua_call(L, 2, 0);
  }

  // free self-reference to allow gc (no futher callback will be called until next ws:connect())
  lua_gc(L, LUA_GCSTOP, 0); // required to avoid freeing ws_data
  luaL_unref(L, LUA_REGISTRYINDEX, data->self_ref);
  data->self_ref = LUA_NOREF;
  lua_gc(L, LUA_GCRESTART, 0);
}
Example #25
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);
  }
}