| /**************************************************************************** |
| * drivers/timers/rpmsg_rtc.c |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. The |
| * ASF licenses this file to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the |
| * License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations |
| * under the License. |
| * |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <nuttx/config.h> |
| |
| #include <nuttx/nuttx.h> |
| #include <nuttx/list.h> |
| #include <nuttx/clock.h> |
| #include <nuttx/kmalloc.h> |
| #include <nuttx/rptun/openamp.h> |
| #include <nuttx/mutex.h> |
| #include <nuttx/timers/rpmsg_rtc.h> |
| #include <nuttx/timers/arch_rtc.h> |
| |
| #include <errno.h> |
| #include <string.h> |
| |
| /**************************************************************************** |
| * Pre-processor definitions |
| ****************************************************************************/ |
| |
| #define RPMSG_RTC_EPT_NAME "rpmsg-rtc" |
| |
| #define RPMSG_RTC_SET 0 |
| #define RPMSG_RTC_GET 1 |
| #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 |
| ****************************************************************************/ |
| |
| begin_packed_struct struct rpmsg_rtc_header_s |
| { |
| uint32_t command; |
| int32_t result; |
| uint64_t cookie; |
| } end_packed_struct; |
| |
| begin_packed_struct struct rpmsg_rtc_set_s |
| { |
| struct rpmsg_rtc_header_s header; |
| int64_t sec; |
| int32_t nsec; |
| } end_packed_struct; |
| |
| #define rpmsg_rtc_get_s rpmsg_rtc_set_s |
| |
| begin_packed_struct struct rpmsg_rtc_alarm_set_s |
| { |
| struct rpmsg_rtc_header_s header; |
| int64_t sec; |
| int32_t nsec; |
| int32_t id; |
| } end_packed_struct; |
| |
| begin_packed_struct struct rpmsg_rtc_alarm_cancel_s |
| { |
| struct rpmsg_rtc_header_s header; |
| int32_t id; |
| } end_packed_struct; |
| |
| #define rpmsg_rtc_alarm_fire_s rpmsg_rtc_alarm_cancel_s |
| |
| #ifndef CONFIG_RTC_RPMSG_SERVER |
| struct rpmsg_rtc_cookie_s |
| { |
| FAR struct rpmsg_rtc_header_s *msg; |
| sem_t sem; |
| }; |
| |
| /* This is the private type for the RTC state. It must be cast compatible |
| * with struct rtc_lowerhalf_s. |
| */ |
| |
| struct rpmsg_rtc_lowerhalf_s |
| { |
| /* This is the contained reference to the read-only, lower-half |
| * operations vtable (which may lie in FLASH or ROM) |
| */ |
| |
| FAR const struct rtc_ops_s *ops; |
| |
| /* Data following is private to this driver and not visible outside of |
| * this file. |
| */ |
| |
| struct rpmsg_endpoint ept; |
| |
| #ifdef CONFIG_RTC_ALARM |
| struct lower_setalarm_s alarminfo[CONFIG_RTC_NALARMS]; |
| #endif |
| }; |
| #else |
| struct rpmsg_rtc_server_s |
| { |
| FAR struct rtc_ops_s *ops; |
| FAR struct rtc_lowerhalf_s *lower; |
| struct list_node list; |
| mutex_t lock; |
| }; |
| |
| struct rpmsg_rtc_client_s |
| { |
| struct list_node node; |
| struct rpmsg_endpoint ept; |
| }; |
| #endif |
| |
| /**************************************************************************** |
| * Private Function Prototypes |
| ****************************************************************************/ |
| |
| #ifndef CONFIG_RTC_RPMSG_SERVER |
| static void rpmsg_rtc_device_created(FAR struct rpmsg_device *rdev, |
| FAR void *priv); |
| static void rpmsg_rtc_device_destroy(FAR struct rpmsg_device *rdev, |
| FAR void *priv); |
| static void rpmsg_rtc_alarm_fire_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, uint32_t src, FAR void *priv); |
| static int rpmsg_rtc_ept_cb(FAR struct rpmsg_endpoint *ept, FAR void *data, |
| size_t len, uint32_t src, FAR void *priv); |
| |
| 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); |
| static int rpmsg_rtc_rdtime(FAR struct rtc_lowerhalf_s *lower, |
| FAR struct rtc_time *rtctime); |
| 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); |
| static int rpmsg_rtc_setrelative(FAR struct rtc_lowerhalf_s *lower, |
| FAR const struct lower_setrelative_s *relinfo); |
| static int rpmsg_rtc_cancelalarm(FAR struct rtc_lowerhalf_s *lower, |
| int alarmid); |
| static int rpmsg_rtc_rdalarm(FAR struct rtc_lowerhalf_s *lower_, |
| FAR struct lower_rdalarm_s *alarminfo); |
| #endif |
| #else |
| 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 |
| #ifdef CONFIG_RTC_IOCTL |
| static int rpmsg_rtc_server_ioctl(FAR struct rtc_lowerhalf_s *lower, |
| int cmd, unsigned long arg); |
| #endif |
| #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS |
| static int rpmsg_rtc_server_destroy(FAR struct rtc_lowerhalf_s *lower); |
| #endif |
| #endif |
| |
| /**************************************************************************** |
| * Private Data |
| ****************************************************************************/ |
| |
| #ifndef CONFIG_RTC_RPMSG_SERVER |
| static const struct rtc_ops_s g_rpmsg_rtc_ops = |
| { |
| rpmsg_rtc_rdtime, |
| rpmsg_rtc_settime, |
| rpmsg_rtc_havesettime, |
| #ifdef CONFIG_RTC_ALARM |
| rpmsg_rtc_setalarm, |
| rpmsg_rtc_setrelative, |
| rpmsg_rtc_cancelalarm, |
| rpmsg_rtc_rdalarm, |
| #endif |
| }; |
| #else |
| static struct rtc_ops_s g_rpmsg_rtc_server_ops = |
| { |
| rpmsg_rtc_server_rdtime, |
| rpmsg_rtc_server_settime, |
| rpmsg_rtc_server_havesettime, |
| #ifdef CONFIG_RTC_ALARM |
| rpmsg_rtc_server_setalarm, |
| rpmsg_rtc_server_setrelative, |
| rpmsg_rtc_server_cancelalarm, |
| rpmsg_rtc_server_rdalarm, |
| #endif |
| #ifdef CONFIG_RTC_PERIODIC |
| rpmsg_rtc_server_setperiodic, |
| rpmsg_rtc_server_cancelperiodic, |
| #endif |
| #ifdef CONFIG_RTC_IOCTL |
| rpmsg_rtc_server_ioctl, |
| #endif |
| #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS |
| rpmsg_rtc_server_destroy, |
| #endif |
| }; |
| #endif |
| |
| /**************************************************************************** |
| * Private Functions |
| ****************************************************************************/ |
| |
| #ifndef CONFIG_RTC_RPMSG_SERVER |
| static void rpmsg_rtc_device_created(FAR struct rpmsg_device *rdev, |
| FAR void *priv) |
| { |
| FAR struct rpmsg_rtc_lowerhalf_s *lower = priv; |
| |
| if (strcmp(CONFIG_RTC_RPMSG_SERVER_NAME, |
| rpmsg_get_cpuname(rdev)) == 0) |
| { |
| lower->ept.priv = lower; |
| |
| rpmsg_create_ept(&lower->ept, rdev, RPMSG_RTC_EPT_NAME, |
| RPMSG_ADDR_ANY, RPMSG_ADDR_ANY, |
| rpmsg_rtc_ept_cb, NULL); |
| } |
| } |
| |
| static void rpmsg_rtc_device_destroy(FAR struct rpmsg_device *rdev, |
| FAR void *priv) |
| { |
| FAR struct rpmsg_rtc_lowerhalf_s *lower = priv; |
| |
| if (strcmp(CONFIG_RTC_RPMSG_SERVER_NAME, |
| rpmsg_get_cpuname(rdev)) == 0) |
| { |
| rpmsg_destroy_ept(&lower->ept); |
| } |
| } |
| |
| static void rpmsg_rtc_alarm_fire_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv) |
| { |
| #ifdef CONFIG_RTC_ALARM |
| FAR struct rpmsg_rtc_lowerhalf_s *lower = priv; |
| FAR struct rpmsg_rtc_alarm_fire_s *msg = data; |
| FAR struct lower_setalarm_s *alarminfo = &lower->alarminfo[msg->id]; |
| |
| alarminfo->cb(alarminfo->priv, alarminfo->id); |
| #endif |
| } |
| |
| 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 = |
| (FAR struct rpmsg_rtc_cookie_s *)(uintptr_t)header->cookie; |
| |
| switch (header->command) |
| { |
| case RPMSG_RTC_ALARM_FIRE: |
| rpmsg_rtc_alarm_fire_handler(ept, data, len, src, priv); |
| break; |
| |
| case RPMSG_RTC_SYNC: |
| { |
| struct rpmsg_rtc_set_s *msg = data; |
| struct timespec tp; |
| |
| tp.tv_sec = msg->sec; |
| tp.tv_nsec = msg->nsec; |
| |
| clock_synchronize(&tp); |
| } |
| break; |
| |
| default: |
| if (cookie) |
| { |
| memcpy(cookie->msg, data, len); |
| nxsem_post(&cookie->sem); |
| } |
| break; |
| } |
| |
| return 0; |
| } |
| |
| 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) |
| { |
| struct rpmsg_rtc_cookie_s cookie; |
| int ret; |
| |
| nxsem_init(&cookie.sem, 0, 0); |
| cookie.msg = msg; |
| |
| msg->command = command; |
| msg->result = -ENXIO; |
| msg->cookie = (uintptr_t)&cookie; |
| |
| ret = rpmsg_send(&lower->ept, msg, len); |
| if (ret < 0) |
| { |
| goto fail; |
| } |
| |
| ret = nxsem_wait_uninterruptible(&cookie.sem); |
| if (ret == 0) |
| { |
| ret = msg->result; |
| } |
| |
| fail: |
| nxsem_destroy(&cookie.sem); |
| return ret; |
| } |
| |
| static int rpmsg_rtc_rdtime(FAR struct rtc_lowerhalf_s *lower, |
| FAR struct rtc_time *rtctime) |
| { |
| struct rpmsg_rtc_get_s msg; |
| int ret; |
| |
| ret = rpmsg_rtc_send_recv((FAR struct rpmsg_rtc_lowerhalf_s *)lower, |
| RPMSG_RTC_GET, (struct rpmsg_rtc_header_s *)&msg, sizeof(msg)); |
| if (ret >= 0) |
| { |
| time_t time = msg.sec; |
| gmtime_r(&time, (FAR struct tm *)rtctime); |
| rtctime->tm_nsec = msg.nsec; |
| } |
| |
| return ret; |
| } |
| |
| static int rpmsg_rtc_settime(FAR struct rtc_lowerhalf_s *lower, |
| FAR const struct rtc_time *rtctime) |
| { |
| struct rpmsg_rtc_set_s msg; |
| |
| msg.sec = timegm((FAR struct tm *)rtctime); |
| msg.nsec = rtctime->tm_nsec; |
| |
| return rpmsg_rtc_send_recv((FAR struct rpmsg_rtc_lowerhalf_s *)lower, |
| RPMSG_RTC_SET, (struct rpmsg_rtc_header_s *)&msg, sizeof(msg)); |
| } |
| |
| static bool rpmsg_rtc_havesettime(FAR struct rtc_lowerhalf_s *lower) |
| { |
| return true; |
| } |
| |
| #ifdef CONFIG_RTC_ALARM |
| static int rpmsg_rtc_setalarm(FAR struct rtc_lowerhalf_s *lower_, |
| FAR const struct lower_setalarm_s *alarminfo) |
| { |
| FAR struct rpmsg_rtc_lowerhalf_s *lower = |
| (FAR struct rpmsg_rtc_lowerhalf_s *)lower_; |
| struct rpmsg_rtc_alarm_set_s msg; |
| int ret; |
| |
| msg.id = alarminfo->id; |
| msg.sec = timegm((FAR struct tm *)&alarminfo->time); |
| msg.nsec = alarminfo->time.tm_nsec; |
| |
| ret = rpmsg_rtc_send_recv(lower, RPMSG_RTC_ALARM_SET, |
| (struct rpmsg_rtc_header_s *)&msg, sizeof(msg)); |
| if (ret >= 0) |
| { |
| lower->alarminfo[alarminfo->id] = *alarminfo; |
| } |
| |
| return ret; |
| } |
| |
| static int |
| rpmsg_rtc_setrelative(FAR struct rtc_lowerhalf_s *lower, |
| FAR const struct lower_setrelative_s *relinfo) |
| { |
| struct lower_setalarm_s alarminfo; |
| time_t time; |
| |
| alarminfo.id = relinfo->id; |
| alarminfo.cb = relinfo->cb; |
| alarminfo.priv = relinfo->priv; |
| |
| rpmsg_rtc_rdtime(lower, &alarminfo.time); |
| time = timegm((FAR struct tm *)&alarminfo.time); |
| time = time + relinfo->reltime; |
| gmtime_r(&time, (FAR struct tm *)&alarminfo.time); |
| |
| return rpmsg_rtc_setalarm(lower, &alarminfo); |
| } |
| |
| static int rpmsg_rtc_cancelalarm(FAR struct rtc_lowerhalf_s *lower, |
| int alarmid) |
| { |
| struct rpmsg_rtc_alarm_cancel_s msg; |
| |
| msg.id = alarmid; |
| return rpmsg_rtc_send_recv((FAR struct rpmsg_rtc_lowerhalf_s *)lower, |
| RPMSG_RTC_ALARM_CANCEL, (struct rpmsg_rtc_header_s *)&msg, |
| sizeof(msg)); |
| } |
| |
| static int rpmsg_rtc_rdalarm(FAR struct rtc_lowerhalf_s *lower_, |
| FAR struct lower_rdalarm_s *alarminfo) |
| { |
| FAR struct rpmsg_rtc_lowerhalf_s *lower = |
| (FAR struct rpmsg_rtc_lowerhalf_s *)lower_; |
| |
| *alarminfo->time = lower->alarminfo[alarminfo->id].time; |
| return 0; |
| } |
| #endif |
| #else |
| 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_client_s *client; |
| FAR struct list_node *node; |
| struct rpmsg_rtc_set_s msg; |
| int ret; |
| |
| ret = server->lower->ops->settime(server->lower, rtctime); |
| if (ret >= 0) |
| { |
| msg.sec = timegm((FAR struct tm *)rtctime); |
| msg.nsec = rtctime->tm_nsec; |
| msg.header.command = RPMSG_RTC_SYNC; |
| |
| if (ret == 0) |
| { |
| struct timespec tp; |
| |
| tp.tv_sec = msg.sec; |
| tp.tv_nsec = msg.nsec; |
| clock_synchronize(&tp); |
| |
| ret = 1; /* Request the upper half skip clock synchronize */ |
| } |
| |
| nxmutex_lock(&server->lock); |
| list_for_every(&server->list, node) |
| { |
| client = (FAR struct rpmsg_rtc_client_s *)node; |
| rpmsg_send(&client->ept, &msg, sizeof(msg)); |
| } |
| |
| nxmutex_unlock(&server->lock); |
| } |
| |
| 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 |
| |
| #ifdef CONFIG_RTC_IOCTL |
| static int rpmsg_rtc_server_ioctl(FAR struct rtc_lowerhalf_s *lower, |
| int cmd, unsigned long arg) |
| { |
| FAR struct rpmsg_rtc_server_s *server = |
| (FAR struct rpmsg_rtc_server_s *)lower; |
| |
| return server->lower->ops->ioctl(server->lower, cmd, arg); |
| } |
| #endif |
| |
| #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS |
| static int rpmsg_rtc_server_destroy(FAR struct rtc_lowerhalf_s *lower) |
| { |
| FAR struct rpmsg_rtc_server_s *server = |
| (FAR struct rpmsg_rtc_server_s *)lower; |
| FAR struct rpmsg_rtc_client_s *client; |
| FAR struct list_node *node; |
| FAR struct list_node *temp; |
| int ret; |
| |
| ret = server->lower->ops->destroy(server->lower); |
| if (ret >= 0) |
| { |
| list_for_every_safe(&server->list, node, temp) |
| { |
| client = (FAR struct rpmsg_rtc_client_s *)node; |
| list_delete(&client->node); |
| rpmsg_destroy_ept(&client->ept); |
| kmm_free(client); |
| } |
| |
| kmm_free(server); |
| } |
| |
| return ret; |
| } |
| #endif |
| |
| static void rpmsg_rtc_server_ns_unbind(FAR struct rpmsg_endpoint *ept) |
| { |
| FAR struct rpmsg_rtc_client_s *client = container_of(ept, |
| struct rpmsg_rtc_client_s, ept); |
| FAR struct rpmsg_rtc_server_s *server = ept->priv; |
| |
| nxmutex_lock(&server->lock); |
| list_delete(&client->node); |
| nxmutex_unlock(&server->lock); |
| rpmsg_destroy_ept(&client->ept); |
| kmm_free(client); |
| } |
| |
| #ifdef CONFIG_RTC_ALARM |
| static void rpmsg_rtc_server_alarm_cb(FAR void *priv, int alarmid) |
| { |
| FAR struct rpmsg_rtc_client_s *client = priv; |
| struct rpmsg_rtc_alarm_fire_s msg; |
| |
| msg.header.command = RPMSG_RTC_ALARM_FIRE; |
| msg.id = alarmid; |
| |
| rpmsg_send(&client->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 rtc_time rtctime; |
| |
| header->result = rpmsg_rtc_server_rdtime(priv, &rtctime); |
| |
| msg->sec = timegm((FAR struct tm *)&rtctime); |
| msg->nsec = rtctime.tm_nsec; |
| return rpmsg_send(ept, msg, sizeof(*msg)); |
| } |
| |
| case RPMSG_RTC_SET: |
| { |
| FAR struct rpmsg_rtc_set_s *msg = data; |
| struct rtc_time rtctime; |
| time_t time = msg->sec; |
| |
| gmtime_r(&time, (FAR struct tm *)&rtctime); |
| rtctime.tm_nsec = msg->nsec; |
| |
| header->result = rpmsg_rtc_server_settime(priv, &rtctime); |
| return rpmsg_send(ept, msg, sizeof(*msg)); |
| } |
| |
| #ifdef CONFIG_RTC_ALARM |
| case RPMSG_RTC_ALARM_SET: |
| { |
| FAR struct rpmsg_rtc_client_s *client = container_of(ept, |
| struct rpmsg_rtc_client_s, ept); |
| FAR struct rpmsg_rtc_alarm_set_s *msg = data; |
| time_t time = msg->sec; |
| struct lower_setalarm_s alarminfo; |
| |
| alarminfo.id = msg->id; |
| alarminfo.cb = rpmsg_rtc_server_alarm_cb; |
| alarminfo.priv = client; |
| |
| gmtime_r(&time, (FAR struct tm *)&alarminfo.time); |
| alarminfo.time.tm_nsec = msg->nsec; |
| header->result = rpmsg_rtc_server_setalarm(priv, &alarminfo); |
| return rpmsg_send(ept, msg, sizeof(*msg)); |
| } |
| |
| case RPMSG_RTC_ALARM_CANCEL: |
| { |
| FAR struct rpmsg_rtc_alarm_cancel_s *msg = data; |
| header->result = rpmsg_rtc_server_cancelalarm(priv, msg->id); |
| return rpmsg_send(ept, msg, sizeof(*msg)); |
| } |
| #endif |
| |
| default: |
| header->result = -ENOSYS; |
| return rpmsg_send(ept, header, sizeof(*header)); |
| } |
| } |
| |
| static bool rpmsg_rtc_server_ns_match(FAR struct rpmsg_device *rdev, |
| FAR void *priv, |
| FAR const char *name, |
| uint32_t dest) |
| { |
| return !strcmp(name, RPMSG_RTC_EPT_NAME); |
| } |
| |
| 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_client_s *client; |
| struct rpmsg_rtc_set_s msg; |
| struct rtc_time rtctime; |
| |
| client = kmm_zalloc(sizeof(*client)); |
| if (client == NULL) |
| { |
| return; |
| } |
| |
| client->ept.priv = server; |
| if (rpmsg_create_ept(&client->ept, rdev, RPMSG_RTC_EPT_NAME, |
| RPMSG_ADDR_ANY, dest, |
| rpmsg_rtc_server_ept_cb, |
| rpmsg_rtc_server_ns_unbind) < 0) |
| { |
| kmm_free(client); |
| return; |
| } |
| |
| if (server->lower->ops->rdtime(server->lower, &rtctime) >= 0) |
| { |
| msg.sec = timegm((FAR struct tm *)&rtctime); |
| msg.nsec = rtctime.tm_nsec; |
| msg.header.command = RPMSG_RTC_SYNC; |
| rpmsg_send(&client->ept, &msg, sizeof(msg)); |
| } |
| |
| nxmutex_lock(&server->lock); |
| list_add_tail(&server->list, &client->node); |
| nxmutex_unlock(&server->lock); |
| } |
| #endif |
| |
| /**************************************************************************** |
| * Name: rpmsg_rtc_initialize |
| * |
| * Description: |
| * |
| * Take remote core RTC as external RTC hardware through rpmsg. |
| * |
| * Returned Value: |
| * Return the lower half RTC driver instance on success; |
| * A NULL pointer on failure. |
| * |
| ****************************************************************************/ |
| |
| #ifndef CONFIG_RTC_RPMSG_SERVER |
| FAR struct rtc_lowerhalf_s *rpmsg_rtc_initialize(void) |
| { |
| FAR struct rpmsg_rtc_lowerhalf_s *lower; |
| |
| lower = kmm_zalloc(sizeof(*lower)); |
| if (lower != NULL) |
| { |
| lower->ops = &g_rpmsg_rtc_ops; |
| |
| rpmsg_register_callback(lower, |
| rpmsg_rtc_device_created, |
| rpmsg_rtc_device_destroy, |
| NULL, |
| NULL); |
| } |
| |
| return (FAR struct rtc_lowerhalf_s *)lower; |
| } |
| |
| #else |
| /**************************************************************************** |
| * 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); |
| nxmutex_init(&server->lock); |
| if (rpmsg_register_callback(server, NULL, NULL, |
| rpmsg_rtc_server_ns_match, |
| rpmsg_rtc_server_ns_bind) < 0) |
| { |
| nxmutex_destroy(&server->lock); |
| kmm_free(server); |
| return NULL; |
| } |
| } |
| |
| return (FAR struct rtc_lowerhalf_s *)server; |
| } |
| #endif |