Updated SNTP module for RTOS compatibility.

This commit is contained in:
Johny Mattsson 2016-06-01 16:43:14 +10:00
parent 740c06b48f
commit c378298000
1 changed files with 102 additions and 22 deletions

View File

@ -35,6 +35,7 @@
#include "module.h" #include "module.h"
#include "lauxlib.h" #include "lauxlib.h"
#include "task/task.h"
#include "os_type.h" #include "os_type.h"
#include "osapi.h" #include "osapi.h"
#include "lwip/udp.h" #include "lwip/udp.h"
@ -42,6 +43,8 @@
#include "user_modules.h" #include "user_modules.h"
#include "lwip/dns.h" #include "lwip/dns.h"
#include "user_interface.h" #include "user_interface.h"
#include <freertos/FreeRTOS.h>
#include <freertos/semphr.h>
#ifdef LUA_USE_MODULES_RTCTIME #ifdef LUA_USE_MODULES_RTCTIME
#include "rtc/rtctime.h" #include "rtc/rtctime.h"
@ -97,15 +100,31 @@ typedef struct
int sync_cb_ref; int sync_cb_ref;
int err_cb_ref; int err_cb_ref;
uint8_t attempts; uint8_t attempts;
/* callback cache, locked by mutex */
xSemaphoreHandle mtx;
struct
{
ntp_err_t result;
uint32_t s, us;
ip_addr_t used_server;
} callback_args;
} sntp_state_t; } sntp_state_t;
enum { TASKCMD_DOSEND, TASKCMD_TIMER, TASKCMD_CALLBACK };
#define LockCbArgs() xSemaphoreTake(state->mtx, portMAX_DELAY)
#define UnlockCbArgs() xSemaphoreGive(state->mtx)
static sntp_state_t *state; static sntp_state_t *state;
static task_handle_t sntp_task;
static ip_addr_t server; static ip_addr_t server;
static void on_timeout (void *arg); static void on_timeout (void *arg);
static void cleanup (lua_State *L) static void cleanup (lua_State *L)
{ {
vSemaphoreDelete (state->mtx);
os_timer_disarm (&state->timer); os_timer_disarm (&state->timer);
udp_remove (state->pcb); udp_remove (state->pcb);
luaL_unref (L, LUA_REGISTRYINDEX, state->sync_cb_ref); luaL_unref (L, LUA_REGISTRYINDEX, state->sync_cb_ref);
@ -130,6 +149,15 @@ static void handle_error (lua_State *L, ntp_err_t err)
} }
static inline void report_error (ntp_err_t err)
{
LockCbArgs();
state->callback_args.result = err;
UnlockCbArgs();
task_post_medium (sntp_task, TASKCMD_CALLBACK);
}
static void sntp_dosend (lua_State *L) static void sntp_dosend (lua_State *L)
{ {
if (state->attempts == 0) if (state->attempts == 0)
@ -144,7 +172,10 @@ static void sntp_dosend (lua_State *L)
struct pbuf *p = pbuf_alloc (PBUF_TRANSPORT, sizeof (ntp_frame_t), PBUF_RAM); struct pbuf *p = pbuf_alloc (PBUF_TRANSPORT, sizeof (ntp_frame_t), PBUF_RAM);
if (!p) if (!p)
{
handle_error (L, NTP_MEM_ERR); handle_error (L, NTP_MEM_ERR);
return;
}
ntp_frame_t req; ntp_frame_t req;
os_memset (&req, 0, sizeof (req)); os_memset (&req, 0, sizeof (req));
@ -172,17 +203,15 @@ static void sntp_dosend (lua_State *L)
static void sntp_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) static void sntp_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
{ {
(void)arg; (void)arg;
lua_State *L = lua_getstate ();
if (ipaddr == NULL) if (ipaddr == NULL)
{ {
sntp_dbg("DNS Fail!\n"); sntp_dbg("DNS Fail!\n");
handle_error(L, NTP_DNS_ERR); report_error(NTP_DNS_ERR);
} }
else else
{ {
server = *ipaddr; server = *ipaddr;
sntp_dosend(L); task_post_medium (sntp_task, TASKCMD_DOSEND);
} }
} }
@ -191,11 +220,7 @@ static void on_timeout (void *arg)
{ {
(void)arg; (void)arg;
sntp_dbg("sntp: timer\n"); sntp_dbg("sntp: timer\n");
lua_State *L = lua_getstate (); task_post_medium (sntp_task, TASKCMD_TIMER);
if (state->attempts >= MAX_ATTEMPTS)
handle_error (L, NTP_TIMEOUT_ERR);
else
sntp_dosend (L);
} }
@ -292,39 +317,90 @@ static void on_recv (void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_a
if (have_cb) if (have_cb)
{ {
lua_rawgeti (L, LUA_REGISTRYINDEX, state->sync_cb_ref); LockCbArgs();
lua_pushnumber (L, tv.tv_sec); state->callback_args.s = tv.tv_sec;
lua_pushnumber (L, tv.tv_usec); state->callback_args.us = tv.tv_usec;
UnlockCbArgs();
} }
#else #else
if (have_cb) if (have_cb)
{ {
lua_rawgeti (L, LUA_REGISTRYINDEX, state->sync_cb_ref); LockCbArgs();
lua_pushnumber (L, ntp.xmit.sec - NTP_TO_UNIX_EPOCH); state->callback_args.s = ntp.xmit.sec - NTP_TO_UNIX_EPOCH;
lua_pushnumber (L, (MICROSECONDS * ntp.xmit.frac) / UINT32_MAXI); state->callback_args.us = (MICROSECONDS * ntp.xmit.frac) / UINT32_MAXI;
UnlockCbArgs();
} }
#endif #endif
cleanup (L);
if (have_cb) if (have_cb)
{ {
lua_pushstring (L, ipaddr_ntoa (&server)); LockCbArgs();
lua_call (L, 3, 0); state->callback_args.used_server = server;
UnlockCbArgs();
task_post_medium (sntp_task, TASKCMD_CALLBACK);
} }
} }
static void run_task (task_param_t cmd, task_prio_t prio)
{
(void)prio;
lua_State *L = lua_getstate ();
switch (cmd)
{
case TASKCMD_DOSEND:
sntp_dosend (L);
break;
case TASKCMD_TIMER:
if (state->attempts >= MAX_ATTEMPTS)
handle_error (L, NTP_TIMEOUT_ERR);
else
sntp_dosend (L);
break;
case TASKCMD_CALLBACK:
{
LockCbArgs();
ntp_err_t err = state->callback_args.result;
UnlockCbArgs();
if (err == NTP_NO_ERR)
{
bool have_cb = (state->sync_cb_ref != LUA_NOREF);
if (have_cb)
{
lua_rawgeti (L, LUA_REGISTRYINDEX, state->sync_cb_ref);
LockCbArgs();
lua_pushnumber (L, state->callback_args.s);
lua_pushnumber (L, state->callback_args.us);
lua_pushstring (L, ipaddr_ntoa (&state->callback_args.used_server));
UnlockCbArgs();
}
cleanup (L);
if (have_cb)
lua_call (L, 3, 0);
}
else
handle_error (L, err);
}
}
}
// sntp.sync (server or nil, syncfn or nil, errfn or nil) // sntp.sync (server or nil, syncfn or nil, errfn or nil)
static int sntp_sync (lua_State *L) static int sntp_sync (lua_State *L)
{ {
const char *errmsg = 0;
#define sync_err(x) do { errmsg = x; goto error; } while (0)
if (!sntp_task)
sntp_task = task_get_id (run_task);
if (!sntp_task)
sync_err ("can't register task");
// default to anycast address, then allow last server to stick // default to anycast address, then allow last server to stick
if (server.addr == IPADDR_ANY) if (server.addr == IPADDR_ANY)
NTP_ANYCAST_ADDR(&server); NTP_ANYCAST_ADDR(&server);
const char *errmsg = 0;
#define sync_err(x) do { errmsg = x; goto error; } while (0)
if (state) if (state)
return luaL_error (L, "sync in progress"); return luaL_error (L, "sync in progress");
@ -334,6 +410,10 @@ static int sntp_sync (lua_State *L)
memset (state, 0, sizeof (sntp_state_t)); memset (state, 0, sizeof (sntp_state_t));
state->mtx = xSemaphoreCreateMutex ();
if (!state->mtx)
sync_err ("no memory for mutex");
state->sync_cb_ref = LUA_NOREF; state->sync_cb_ref = LUA_NOREF;
state->err_cb_ref = LUA_NOREF; state->err_cb_ref = LUA_NOREF;