nuttx/sched/clock/clock_settime.c
Michal Lenc 360e938fa6 sched: add support for adjtime() interface
This commit adds Linux like adjtime() interface that is used to correct
the system time clock if it varies from real value. The adjustment is
done by slight adjustment of clock period and therefore the adjustment
is without time jumps (both forward and backwards)

The implementation is enabled by CONFIG_CLOCK_ADJTIME and separated from
CONFIG_CLOCK_TIMEKEEPING functions. Options CONFIG_CLOCK_ADJTIME_SLEWLIMIT
and CONFIG_CLOCK_ADJTIME_PERIOD can be used to control the adjustment
speed.

Interfaces up_get_timer_period() and up_adj_timer_period() has to be
defined by architecture level support.

This is not a POSIX interface but derives from 4.3BSD, System V.
It is also supported for Linux compatibility.

Signed-off-by: Michal Lenc <michallenc@seznam.cz>
2023-04-25 14:37:50 -03:00

137 lines
3.8 KiB
C

/****************************************************************************
* sched/clock/clock_settime.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 <time.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include "clock/clock.h"
#ifdef CONFIG_CLOCK_TIMEKEEPING
# include "clock/clock_timekeeping.h"
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: clock_settime
*
* Description:
* Clock Functions based on POSIX APIs
*
****************************************************************************/
int clock_settime(clockid_t clock_id, FAR const struct timespec *tp)
{
#ifndef CONFIG_CLOCK_TIMEKEEPING
struct timespec bias;
irqstate_t flags;
#endif
int ret = OK;
sinfo("clock_id=%d\n", clock_id);
DEBUGASSERT(tp != NULL);
/* CLOCK_REALTIME - POSIX demands this to be present. This is the wall
* time clock.
*/
if (clock_id == CLOCK_REALTIME &&
tp->tv_nsec >= 0 && tp->tv_nsec < 1000000000)
{
#ifndef CONFIG_CLOCK_TIMEKEEPING
/* Interrupts are disabled here so that the in-memory time
* representation and the RTC setting will be as close as
* possible.
*/
flags = enter_critical_section();
/* Get the elapsed time since power up (in milliseconds). This is a
* bias value that we need to use to correct the base time.
*/
clock_systime_timespec(&bias);
/* Save the new base time. */
g_basetime.tv_sec = tp->tv_sec;
g_basetime.tv_nsec = tp->tv_nsec;
/* Subtract that bias from the basetime so that when the system
* timer is again added to the base time, the result is the current
* time relative to basetime.
*/
if (g_basetime.tv_nsec < bias.tv_nsec)
{
g_basetime.tv_nsec += NSEC_PER_SEC;
g_basetime.tv_sec--;
}
/* Result could be negative seconds */
g_basetime.tv_nsec -= bias.tv_nsec;
g_basetime.tv_sec -= bias.tv_sec;
/* Setup the RTC (lo- or high-res) */
#ifdef CONFIG_RTC
if (g_rtc_enabled)
{
up_rtc_settime(tp);
}
#endif
#ifdef CONFIG_CLOCK_ADJTIME
g_clk_adj_count = 0;
g_clk_adj_usec = 0;
#endif
leave_critical_section(flags);
sinfo("basetime=(%ld,%lu) bias=(%ld,%lu)\n",
(long)g_basetime.tv_sec, (unsigned long)g_basetime.tv_nsec,
(long)bias.tv_sec, (unsigned long)bias.tv_nsec);
#else
ret = clock_timekeeping_set_wall_time(tp);
#endif
}
else
{
serr("Returning ERROR\n");
set_errno(EINVAL);
ret = ERROR;
}
return ret;
}