diff --git a/arch/sim/src/sim/up_rptun.c b/arch/sim/src/sim/up_rptun.c index 57c3ff52249..d3f78826fd0 100644 --- a/arch/sim/src/sim/up_rptun.c +++ b/arch/sim/src/sim/up_rptun.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include "up_internal.h" @@ -237,6 +239,10 @@ int up_rptun_init(void) syslog_rpmsg_server_init(); #endif +#if CONFIG_SIM_RPTUN_MASTER == 0 + up_rtc_set_lowerhalf(rpmsg_rtc_initialize("server", 0)); +#endif + #ifdef CONFIG_FS_HOSTFS_RPMSG hostfs_rpmsg_init("server"); #endif diff --git a/arch/sim/src/sim/up_rtc.c b/arch/sim/src/sim/up_rtc.c index a3b630db95b..efcb07cb544 100644 --- a/arch/sim/src/sim/up_rtc.c +++ b/arch/sim/src/sim/up_rtc.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "up_internal.h" @@ -122,6 +123,10 @@ static bool sim_rtc_havesettime(FAR struct rtc_lowerhalf_s *lower) int up_rtc_initialize(void) { +#ifdef CONFIG_SIM_RPTUN_MASTER + up_rtc_set_lowerhalf(rpmsg_rtc_server_initialize(&g_sim_rtc)); +#else up_rtc_set_lowerhalf(&g_sim_rtc); +#endif return rtc_initialize(0, &g_sim_rtc); } diff --git a/drivers/timers/rpmsg_rtc.c b/drivers/timers/rpmsg_rtc.c index f294c576cfa..2eef9b52077 100644 --- a/drivers/timers/rpmsg_rtc.c +++ b/drivers/timers/rpmsg_rtc.c @@ -24,7 +24,9 @@ #include +#include #include +#include #include #include #include @@ -44,6 +46,7 @@ #define RPMSG_RTC_ALARM_SET 2 #define RPMSG_RTC_ALARM_CANCEL 3 #define RPMSG_RTC_ALARM_FIRE 4 +#define RPMSG_RTC_SYNC 5 /**************************************************************************** * Private Types @@ -105,12 +108,27 @@ struct rpmsg_rtc_lowerhalf_s struct rpmsg_endpoint ept; FAR const char *cpuname; + struct work_s syncwork; #ifdef CONFIG_RTC_ALARM struct lower_setalarm_s alarminfo[CONFIG_RTC_NALARMS]; #endif }; +struct rpmsg_rtc_server_s +{ + FAR struct rtc_ops_s *ops; + FAR struct rtc_lowerhalf_s *lower; + struct list_node list; + sem_t exclsem; +}; + +struct rpmsg_rtc_session_s +{ + struct list_node node; + struct rpmsg_endpoint ept; +}; + /**************************************************************************** * Private Function Prototypes ****************************************************************************/ @@ -131,6 +149,7 @@ static int rpmsg_rtc_rdtime(FAR struct rtc_lowerhalf_s *lower, static int rpmsg_rtc_settime(FAR struct rtc_lowerhalf_s *lower, FAR const struct rtc_time *rtctime); static bool rpmsg_rtc_havesettime(FAR struct rtc_lowerhalf_s *lower); + #ifdef CONFIG_RTC_ALARM static int rpmsg_rtc_setalarm(FAR struct rtc_lowerhalf_s *lower_, FAR const struct lower_setalarm_s *alarminfo); @@ -142,6 +161,31 @@ static int rpmsg_rtc_rdalarm(FAR struct rtc_lowerhalf_s *lower_, FAR struct lower_rdalarm_s *alarminfo); #endif +static int rpmsg_rtc_server_rdtime(FAR struct rtc_lowerhalf_s *lower, + FAR struct rtc_time *rtctime); +static int rpmsg_rtc_server_settime(FAR struct rtc_lowerhalf_s *lower, + FAR const struct rtc_time *rtctime); +static bool rpmsg_rtc_server_havesettime(FAR struct rtc_lowerhalf_s *lower); + +#ifdef CONFIG_RTC_ALARM +static int rpmsg_rtc_server_setalarm(FAR struct rtc_lowerhalf_s *lower, + FAR const struct lower_setalarm_s *alarminfo); +static int rpmsg_rtc_server_setrelative(FAR struct rtc_lowerhalf_s *lower, + FAR const struct lower_setrelative_s *relinfo); +static int rpmsg_rtc_server_cancelalarm(FAR struct rtc_lowerhalf_s *lower, + int alarmid); +static int rpmsg_rtc_server_rdalarm(FAR struct rtc_lowerhalf_s *lower, + FAR struct lower_rdalarm_s *alarminfo); +#endif + +#ifdef CONFIG_RTC_PERIODIC +static int rpmsg_rtc_server_setperiodic(FAR struct rtc_lowerhalf_s *lower, + FAR const struct lower_setperiodic_s *alarminfo); + +static int rpmsg_rtc_server_cancelperiodic + (FAR struct rtc_lowerhalf_s *lower, int alarmid); +#endif + /**************************************************************************** * Private Data ****************************************************************************/ @@ -159,6 +203,23 @@ static const struct rtc_ops_s g_rpmsg_rtc_ops = #endif }; +static struct rtc_ops_s g_rpmsg_rtc_server_ops = +{ + .rdtime = rpmsg_rtc_server_rdtime, + .settime = rpmsg_rtc_server_settime, + .havesettime = rpmsg_rtc_server_havesettime, +#ifdef CONFIG_RTC_ALARM + .setalarm = rpmsg_rtc_server_setalarm, + .setrelative = rpmsg_rtc_server_setrelative, + .cancelalarm = rpmsg_rtc_server_cancelalarm, + .rdalarm = rpmsg_rtc_server_rdalarm, +#endif +#ifdef CONFIG_RTC_PERIODIC + .setperiodic = rpmsg_rtc_server_setperiodic, + .cancelperiodic = rpmsg_rtc_server_cancelperiodic, +#endif +}; + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -202,12 +263,24 @@ static void rpmsg_rtc_alarm_fire_handler(FAR struct rpmsg_endpoint *ept, #endif } +static void rpmsg_rtc_syncworker(FAR void *arg) +{ + clock_synchronize(); +} + +static void rpmsg_rtc_sync_handler(FAR void *priv) +{ + FAR struct rpmsg_rtc_lowerhalf_s *lower = priv; + + work_queue(HPWORK, &lower->syncwork, rpmsg_rtc_syncworker, NULL, 0); +} + static int rpmsg_rtc_ept_cb(FAR struct rpmsg_endpoint *ept, FAR void *data, size_t len, uint32_t src, FAR void *priv) { FAR struct rpmsg_rtc_header_s *header = data; FAR struct rpmsg_rtc_cookie_s *cookie = - (struct rpmsg_rtc_cookie_s *)(uintptr_t)header->cookie; + (FAR struct rpmsg_rtc_cookie_s *)(uintptr_t)header->cookie; switch (header->command) { @@ -215,6 +288,10 @@ static int rpmsg_rtc_ept_cb(FAR struct rpmsg_endpoint *ept, FAR void *data, rpmsg_rtc_alarm_fire_handler(ept, data, len, src, priv); break; + case RPMSG_RTC_SYNC: + rpmsg_rtc_sync_handler(priv); + break; + default: if (cookie) { @@ -231,7 +308,7 @@ static int rpmsg_rtc_send_recv(FAR struct rpmsg_rtc_lowerhalf_s *lower, uint32_t command, FAR struct rpmsg_rtc_header_s *msg, int len) { - FAR struct rpmsg_rtc_cookie_s cookie; + struct rpmsg_rtc_cookie_s cookie; int ret; nxsem_init(&cookie.sem, 0, 0); @@ -321,8 +398,8 @@ static int rpmsg_rtc_setalarm(FAR struct rtc_lowerhalf_s *lower_, } static int - rpmsg_rtc_setrelative(FAR struct rtc_lowerhalf_s *lower, - FAR const struct lower_setrelative_s *relinfo) +rpmsg_rtc_setrelative(FAR struct rtc_lowerhalf_s *lower, + FAR const struct lower_setrelative_s *relinfo) { struct lower_setalarm_s alarminfo = { @@ -365,6 +442,237 @@ static int rpmsg_rtc_rdalarm(FAR struct rtc_lowerhalf_s *lower_, } #endif +static int rpmsg_rtc_server_rdtime(FAR struct rtc_lowerhalf_s *lower, + FAR struct rtc_time *rtctime) +{ + FAR struct rpmsg_rtc_server_s *server = + (FAR struct rpmsg_rtc_server_s *)lower; + + return server->lower->ops->rdtime(server->lower, rtctime); +} + +static int rpmsg_rtc_server_settime(FAR struct rtc_lowerhalf_s *lower, + FAR const struct rtc_time *rtctime) +{ + FAR struct rpmsg_rtc_server_s *server = + (FAR struct rpmsg_rtc_server_s *)lower; + FAR struct rpmsg_rtc_session_s *session; + FAR struct list_node *node; + struct rpmsg_rtc_header_s header; + int ret; + + ret = server->lower->ops->settime(server->lower, rtctime); + if (ret >= 0) + { + nxsem_wait_uninterruptible(&server->exclsem); + header.command = RPMSG_RTC_SYNC; + list_for_every(&server->list, node) + { + session = (FAR struct rpmsg_rtc_session_s *)node; + rpmsg_send(&session->ept, &header, sizeof(header)); + } + + nxsem_post(&server->exclsem); + } + + return ret; +} + +static bool rpmsg_rtc_server_havesettime(FAR struct rtc_lowerhalf_s *lower) +{ + FAR struct rpmsg_rtc_server_s *server = + (FAR struct rpmsg_rtc_server_s *)lower; + + return server->lower->ops->havesettime(server->lower); +} + +#ifdef CONFIG_RTC_ALARM +static int rpmsg_rtc_server_setalarm(FAR struct rtc_lowerhalf_s *lower, + FAR const struct lower_setalarm_s *alarminfo) +{ + FAR struct rpmsg_rtc_server_s *server = + (FAR struct rpmsg_rtc_server_s *)lower; + + return server->lower->ops->setalarm(server->lower, alarminfo); +} + +static int rpmsg_rtc_server_setrelative(FAR struct rtc_lowerhalf_s *lower, + FAR const struct lower_setrelative_s *relinfo) +{ + FAR struct rpmsg_rtc_server_s *server = + (FAR struct rpmsg_rtc_server_s *)lower; + + return server->lower->ops->setrelative(server->lower, relinfo); +} + +static int rpmsg_rtc_server_cancelalarm(FAR struct rtc_lowerhalf_s *lower, + int alarmid) +{ + FAR struct rpmsg_rtc_server_s *server = + (FAR struct rpmsg_rtc_server_s *)lower; + + return server->lower->ops->cancelalarm(server->lower, alarmid); +} + +static int rpmsg_rtc_server_rdalarm(FAR struct rtc_lowerhalf_s *lower, + FAR struct lower_rdalarm_s *alarminfo) +{ + FAR struct rpmsg_rtc_server_s *server = + (FAR struct rpmsg_rtc_server_s *)lower; + + return server->lower->ops->rdalarm(server->lower, alarminfo); +} +#endif + +#ifdef CONFIG_RTC_PERIODIC +static int rpmsg_rtc_server_setperiodic(FAR struct rtc_lowerhalf_s *lower, + FAR const struct lower_setperiodic_s *alarminfo) +{ + FAR struct rpmsg_rtc_server_s *server = + (FAR struct rpmsg_rtc_server_s *)lower; + + return server->lower->ops->setperiodic(server->lower, alarminfo); +} + +static int rpmsg_rtc_server_cancelperiodic + (FAR struct rtc_lowerhalf_s *lower, int alarmid) +{ + FAR struct rpmsg_rtc_server_s *server = + (FAR struct rpmsg_rtc_server_s *)lower; + + return server->lower->ops->cancelperiodic(server->lower, alarmid); +} +#endif + +static void rpmsg_rtc_server_ns_unbind(FAR struct rpmsg_endpoint *ept) +{ + FAR struct rpmsg_rtc_session_s *session = container_of(ept, + struct rpmsg_rtc_session_s, ept); + FAR struct rpmsg_rtc_server_s *server = ept->priv; + + nxsem_wait_uninterruptible(&server->exclsem); + list_delete(&session->node); + nxsem_post(&server->exclsem); + rpmsg_destroy_ept(&session->ept); + kmm_free(session); +} + +#ifdef CONFIG_RTC_ALARM +static void rpmsg_rtc_server_alarm_cb(FAR void *priv, int alarmid) +{ + FAR struct rpmsg_rtc_session_s *session = priv; + struct rpmsg_rtc_alarm_fire_s msg = + { + .header.command = RPMSG_RTC_ALARM_FIRE, + .id = alarmid, + }; + + rpmsg_send(&session->ept, &msg, sizeof(msg)); +} +#endif + +static int rpmsg_rtc_server_ept_cb(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, uint32_t src, + FAR void *priv) +{ + FAR struct rpmsg_rtc_header_s *header = data; + + switch (header->command) + { + case RPMSG_RTC_GET: + { + FAR struct rpmsg_rtc_get_s *msg = data; + struct timespec ts; + + header->result = clock_gettime(CLOCK_REALTIME, &ts); + msg->sec = ts.tv_sec; + msg->nsec = ts.tv_nsec; + return rpmsg_send(ept, msg, sizeof(*msg)); + } + + case RPMSG_RTC_SET: + { + FAR struct rpmsg_rtc_set_s *msg = data; + struct timespec ts; + + ts.tv_sec = msg->sec; + ts.tv_nsec = msg->nsec; + header->result = clock_settime(CLOCK_REALTIME, &ts); + return rpmsg_send(ept, msg, sizeof(*msg)); + } + +#ifdef CONFIG_RTC_ALARM + case RPMSG_RTC_ALARM_SET: + { + FAR struct rpmsg_rtc_session_s *session = container_of(ept, + struct rpmsg_rtc_session_s, ept); + FAR struct rpmsg_rtc_alarm_set_s *msg = data; + FAR struct rpmsg_rtc_server_s *server = priv; + time_t time = msg->sec; + struct lower_setalarm_s alarminfo = + { + .id = msg->id, + .cb = rpmsg_rtc_server_alarm_cb, + .priv = session + }; + + gmtime_r(&time, (FAR struct tm *)&alarminfo.time); + alarminfo.time.tm_nsec = msg->nsec; + header->result = server->lower->ops->setalarm(server->lower, + &alarminfo); + return rpmsg_send(ept, msg, sizeof(*msg)); + } + + case RPMSG_RTC_ALARM_CANCEL: + { + FAR struct rpmsg_rtc_alarm_cancel_s *msg = data; + FAR struct rpmsg_rtc_server_s *server = priv; + header->result = server->lower->ops->cancelalarm(server->lower, + msg->id); + return rpmsg_send(ept, msg, sizeof(*msg)); + } +#endif + + default: + header->result = -ENOSYS; + return rpmsg_send(ept, header, sizeof(*header)); + } +} + +static void rpmsg_rtc_server_ns_bind(FAR struct rpmsg_device *rdev, + FAR void *priv, + FAR const char *name, + uint32_t dest) +{ + FAR struct rpmsg_rtc_server_s *server = priv; + FAR struct rpmsg_rtc_session_s *session; + + if (strcmp(name, RPMSG_RTC_EPT_NAME)) + { + return; + } + + session = kmm_zalloc(sizeof(*session)); + if (!session) + { + return; + } + + session->ept.priv = server; + if (rpmsg_create_ept(&session->ept, rdev, RPMSG_RTC_EPT_NAME, + RPMSG_ADDR_ANY, dest, + rpmsg_rtc_server_ept_cb, + rpmsg_rtc_server_ns_unbind) < 0) + { + kmm_free(session); + return; + } + + nxsem_wait_uninterruptible(&server->exclsem); + list_add_tail(&server->list, &session->node); + nxsem_post(&server->exclsem); +} + /**************************************************************************** * Name: rpmsg_rtc_initialize * @@ -377,7 +685,8 @@ static int rpmsg_rtc_rdalarm(FAR struct rtc_lowerhalf_s *lower_, * minor - device minor number * * Returned Value: - * Zero (OK) on success; a negated errno on failure + * Return the lower half RTC driver instance on success; + * A NULL pointer on failure. * ****************************************************************************/ @@ -402,3 +711,40 @@ FAR struct rtc_lowerhalf_s *rpmsg_rtc_initialize(FAR const char *cpuname, return (FAR struct rtc_lowerhalf_s *)lower; } + +/**************************************************************************** + * Name: rpmsg_rtc_server_initialize + * + * Description: + * Sync RTC info to remote core without external RTC hardware through + * rpmsg. + * + * Returned Value: + * Return the lower half RTC driver instance on success; + * A NULL pointer on failure. + * + ****************************************************************************/ + +FAR struct rtc_lowerhalf_s *rpmsg_rtc_server_initialize( + FAR struct rtc_lowerhalf_s *lower) +{ + FAR struct rpmsg_rtc_server_s *server; + + server = kmm_zalloc(sizeof(*server)); + if (server) + { + server->ops = &g_rpmsg_rtc_server_ops; + server->lower = lower; + list_initialize(&server->list); + nxsem_init(&server->exclsem, 0, 1); + if (rpmsg_register_callback(server, NULL, NULL, + rpmsg_rtc_server_ns_bind) < 0) + { + nxsem_destroy(&server->exclsem); + kmm_free(server); + return NULL; + } + } + + return (FAR struct rtc_lowerhalf_s *)server; +} diff --git a/include/nuttx/timers/rpmsg_rtc.h b/include/nuttx/timers/rpmsg_rtc.h index 6699b99de1a..b0b2928c820 100644 --- a/include/nuttx/timers/rpmsg_rtc.h +++ b/include/nuttx/timers/rpmsg_rtc.h @@ -45,6 +45,9 @@ extern "C" FAR struct rtc_lowerhalf_s *rpmsg_rtc_initialize(FAR const char *cpu_name, int minor); +FAR struct rtc_lowerhalf_s *rpmsg_rtc_server_initialize( + FAR struct rtc_lowerhalf_s *lower); + #endif /* CONFIG_RTC_RPMSG */ #undef EXTERN