rtc/rpmsg: support server and client to set time each other

Change-Id: I5d13f424cb636a79a9fd98c275786771c213ddb8
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
This commit is contained in:
Jiuzhu Dong 2021-03-19 14:34:43 +08:00 committed by Xiang Xiao
parent e4c27dfdd6
commit 1c74d8042a
4 changed files with 365 additions and 5 deletions

View File

@ -27,6 +27,8 @@
#include <nuttx/rptun/rptun.h>
#include <nuttx/serial/uart_rpmsg.h>
#include <nuttx/syslog/syslog_rpmsg.h>
#include <nuttx/timers/arch_rtc.h>
#include <nuttx/timers/rpmsg_rtc.h>
#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

View File

@ -27,6 +27,7 @@
#include <nuttx/arch.h>
#include <nuttx/timers/rtc.h>
#include <nuttx/timers/arch_rtc.h>
#include <nuttx/timers/rpmsg_rtc.h>
#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);
}

View File

@ -24,7 +24,9 @@
#include <nuttx/config.h>
#include <nuttx/list.h>
#include <nuttx/clock.h>
#include <nuttx/wqueue.h>
#include <nuttx/kmalloc.h>
#include <nuttx/rptun/openamp.h>
#include <nuttx/semaphore.h>
@ -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;
}

View File

@ -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