123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549 |
- /*
- * Copyright (c) 2006-2018, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2012-12-08 Bernard fix the issue of _timevalue.tv_usec initialization,
- * which found by Rob <rdent@iinet.net.au>
- */
- #include <rtdevice.h>
- #include <time.h>
- #include "clock_time.h"
- #include "lwp.h"
- static struct timeval _timevalue;
- int clock_time_system_init()
- {
- time_t time;
- rt_tick_t tick;
- rt_device_t device;
- time = 0;
- device = rt_device_find("rtc");
- if (device != RT_NULL)
- {
- /* get realtime seconds */
- rt_device_control(device, RT_DEVICE_CTRL_RTC_GET_TIME, &time);
- }
- /* get tick */
- tick = rt_tick_get();
- _timevalue.tv_usec = (tick%RT_TICK_PER_SECOND) * MICROSECOND_PER_TICK;
- _timevalue.tv_sec = time - tick/RT_TICK_PER_SECOND - 1;
- return 0;
- }
- INIT_COMPONENT_EXPORT(clock_time_system_init);
- int clock_time_to_tick(const struct timespec *time)
- {
- int tick;
- long nsecond, second;
- struct timespec tp;
- RT_ASSERT(time != RT_NULL);
- tick = RT_WAITING_FOREVER;
- if (time != RT_NULL)
- {
- /* get current tp */
- clock_gettime(CLOCK_REALTIME, &tp);
- if ((time->tv_nsec - tp.tv_nsec) < 0)
- {
- nsecond = (long)NANOSECOND_PER_SECOND - (tp.tv_nsec - time->tv_nsec);
- second = time->tv_sec - tp.tv_sec - 1;
- }
- else
- {
- nsecond = time->tv_nsec - tp.tv_nsec;
- second = time->tv_sec - tp.tv_sec;
- }
- /*
- * Warning: NANOSECOND_PER_SECOND is unsigned long, division method instruction will be `divu`.
- * so then result is overflow undefined behavior.
- */
- tick = (int)(second * RT_TICK_PER_SECOND + (long)(nsecond * RT_TICK_PER_SECOND) / (long)NANOSECOND_PER_SECOND);
- if (tick < 0) tick = 0;
- }
- return tick;
- }
- RTM_EXPORT(clock_time_to_tick);
- int clock_getres(clockid_t clockid, struct timespec *res)
- {
- int ret = 0;
- if (res == RT_NULL)
- {
- rt_set_errno(EINVAL);
- return -RT_ERROR;
- }
- switch (clockid)
- {
- case CLOCK_REALTIME:
- res->tv_sec = 0;
- res->tv_nsec = NANOSECOND_PER_SECOND/RT_TICK_PER_SECOND;
- break;
- #ifdef RT_USING_CPUTIME
- case CLOCK_MONOTONIC:
- case CLOCK_CPUTIME_ID:
- res->tv_sec = 0;
- res->tv_nsec = clock_cpu_getres();
- break;
- #endif
- default:
- ret = -RT_ERROR;
- rt_set_errno(EINVAL);
- break;
- }
- return ret;
- }
- RTM_EXPORT(clock_getres);
- int clock_gettime(clockid_t clockid, struct timespec *tp)
- {
- int ret = 0;
- if (tp == RT_NULL)
- {
- rt_set_errno(EINVAL);
- return -RT_ERROR;
- }
- switch (clockid)
- {
- case CLOCK_REALTIME:
- {
- /* get tick */
- rt_tick_t tick = rt_tick_get();
- tp->tv_sec = _timevalue.tv_sec + tick / RT_TICK_PER_SECOND;
- tp->tv_nsec = (_timevalue.tv_usec + (tick % RT_TICK_PER_SECOND) * MICROSECOND_PER_TICK) * 1000;
- }
- break;
- #ifdef RT_USING_CPUTIME
- case CLOCK_MONOTONIC:
- case CLOCK_CPUTIME_ID:
- {
- float unit = 0;
- uint64_t cpu_tick;
- unit = clock_cpu_getres();
- cpu_tick = clock_cpu_gettime();
- tp->tv_sec = ((uint64_t)(cpu_tick * unit)) / NANOSECOND_PER_SECOND;
- tp->tv_nsec = ((uint64_t)(cpu_tick * unit)) % NANOSECOND_PER_SECOND;
- }
- break;
- #endif
- default:
- rt_set_errno(EINVAL);
- ret = -RT_ERROR;
- }
- return ret;
- }
- RTM_EXPORT(clock_gettime);
- int clock_settime(clockid_t clockid, const struct timespec *tp)
- {
- int second;
- rt_tick_t tick;
- rt_device_t device;
- if ((clockid != CLOCK_REALTIME) || (tp == RT_NULL))
- {
- rt_set_errno(EINVAL);
- return -RT_ERROR;
- }
- /* get second */
- second = tp->tv_sec;
- /* get tick */
- tick = rt_tick_get();
- /* update timevalue */
- _timevalue.tv_usec = MICROSECOND_PER_SECOND - (tick % RT_TICK_PER_SECOND) * MICROSECOND_PER_TICK;
- _timevalue.tv_sec = second - tick/RT_TICK_PER_SECOND - 1;
- /* update for RTC device */
- device = rt_device_find("rtc");
- if (device != RT_NULL)
- {
- /* set realtime seconds */
- rt_device_control(device, RT_DEVICE_CTRL_RTC_SET_TIME, &second);
- }
- else
- return -RT_ERROR;
- return 0;
- }
- RTM_EXPORT(clock_settime);
- int clock_nanosleep(clockid_t clockid, int flags, const struct timespec *rqtp, struct timespec *rmtp)
- {
- if (rqtp->tv_sec < 0 || rqtp->tv_nsec < 0 || rqtp->tv_nsec >= NANOSECOND_PER_SECOND)
- {
- rt_set_errno(EINVAL);
- return -RT_ERROR;
- }
- switch (clockid)
- {
- case CLOCK_REALTIME:
- {
- rt_tick_t tick;
- if (flags & TIMER_ABSTIME == TIMER_ABSTIME)
- {
- tick = (rqtp->tv_sec - _timevalue.tv_sec) * RT_TICK_PER_SECOND + (rqtp->tv_nsec - _timevalue.tv_usec) * (RT_TICK_PER_SECOND / NANOSECOND_PER_SECOND);
- rt_tick_t rt_tick = rt_tick_get();
- tick = tick < rt_tick ? 0 : tick - rt_tick;
- }
- else
- {
- tick = rqtp->tv_sec * RT_TICK_PER_SECOND + ((uint64_t)(rqtp->tv_nsec) * RT_TICK_PER_SECOND) / NANOSECOND_PER_SECOND;
- }
- rt_thread_delay(tick);
- if (rt_get_errno() == -RT_EINTR)
- {
- if (rmtp)
- {
- tick = rt_tick_get() - tick;
- /* get the passed time */
- rmtp->tv_sec = tick / RT_TICK_PER_SECOND;
- rmtp->tv_nsec = (tick % RT_TICK_PER_SECOND) * (NANOSECOND_PER_SECOND / RT_TICK_PER_SECOND);
- }
- rt_set_errno(EINTR);
- return -RT_ERROR;
- }
- }
- break;
- #ifdef RT_USING_CPUTIME
- case CLOCK_MONOTONIC:
- case CLOCK_CPUTIME_ID:
- {
- uint64_t cpu_tick, cpu_tick_old;
- cpu_tick_old = clock_cpu_gettime();
- rt_tick_t tick;
- float unit = clock_cpu_getres();
- cpu_tick = (rqtp->tv_sec * NANOSECOND_PER_SECOND + rqtp->tv_nsec * (NANOSECOND_PER_SECOND / NANOSECOND_PER_SECOND)) / unit;
- if (flags & TIMER_ABSTIME == TIMER_ABSTIME)
- cpu_tick = cpu_tick < cpu_tick_old ? 0 : cpu_tick - cpu_tick_old;
- tick = (unit * cpu_tick) / (NANOSECOND_PER_SECOND / RT_TICK_PER_SECOND);
- rt_thread_delay(tick);
- if (rt_get_errno() == -RT_EINTR)
- {
- if (rmtp)
- {
- uint64_t rmtp_cpu_tick = clock_cpu_gettime() - tick * (NANOSECOND_PER_SECOND / RT_TICK_PER_SECOND);
- rmtp->tv_sec = ((int)(rmtp_cpu_tick * unit)) / NANOSECOND_PER_SECOND;
- rmtp->tv_nsec = ((int)(rmtp_cpu_tick * unit)) % NANOSECOND_PER_SECOND;
- }
- rt_set_errno(EINTR);
- return -RT_ERROR;
- }
- else
- while (clock_cpu_gettime() - cpu_tick_old < cpu_tick);
- }
- break;
- #endif
- default:
- rt_set_errno(EINVAL);
- return -RT_ERROR;
- }
- return 0;
- }
- RTM_EXPORT(clock_nanosleep);
- int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
- {
- if (rqtp->tv_sec < 0 || rqtp->tv_nsec < 0 || rqtp->tv_nsec >= NANOSECOND_PER_SECOND)
- {
- rt_set_errno(EINVAL);
- return -RT_ERROR;
- }
- #ifdef RT_USING_CPUTIME
- uint64_t cpu_tick, cpu_tick_old;
- cpu_tick_old = clock_cpu_gettime();
- rt_tick_t tick;
- float unit = clock_cpu_getres();
- cpu_tick = (rqtp->tv_sec * NANOSECOND_PER_SECOND + ((uint64_t)rqtp->tv_nsec * NANOSECOND_PER_SECOND) / NANOSECOND_PER_SECOND)/unit;
- tick = (unit * cpu_tick) / (NANOSECOND_PER_SECOND / RT_TICK_PER_SECOND);
- rt_thread_delay(tick);
- if (rt_get_errno() == -RT_EINTR)
- {
- if (rmtp)
- {
- uint64_t rmtp_cpu_tick = clock_cpu_gettime() - tick * (NANOSECOND_PER_SECOND / RT_TICK_PER_SECOND);
- rmtp->tv_sec = ((int)(rmtp_cpu_tick * unit)) / NANOSECOND_PER_SECOND;
- rmtp->tv_nsec = ((int)(rmtp_cpu_tick * unit)) % NANOSECOND_PER_SECOND;
- }
- rt_set_errno(EINTR);
- return -RT_ERROR;
- }
- else
- while (clock_cpu_gettime() - cpu_tick_old < cpu_tick);
- #else
- rt_tick_t tick;
- tick = rqtp->tv_sec * RT_TICK_PER_SECOND + ((uint64_t)rqtp->tv_nsec * RT_TICK_PER_SECOND) / NANOSECOND_PER_SECOND;
- rt_thread_delay(tick);
- if (rt_get_errno() == -RT_EINTR)
- {
- if (rmtp)
- {
- tick = rt_tick_get() - tick;
- /* get the passed time */
- rmtp->tv_sec = tick / RT_TICK_PER_SECOND;
- rmtp->tv_nsec = (tick % RT_TICK_PER_SECOND) * (NANOSECOND_PER_SECOND / RT_TICK_PER_SECOND);
- }
- rt_set_errno(EINTR);
- return -RT_ERROR;
- }
- #endif
- return 0;
- }
- RTM_EXPORT(nanosleep);
- static void rtthread_timer_wrapper(void *timerobj)
- {
- struct timer_obj *timer;
- timer = (struct timer_obj *)timerobj;
- sys_kill(timer->pid, timer->sigev_signo);
- if (timer->reload == 0U)
- {
- timer->status = NOT_ACTIVE;
- }
- // if (timer->sigev_notify_function != RT_NULL)
- // {
- // (timer->sigev_notify_function)(timer->val);
- // }
- timer->reload = (timer->interval.tv_sec * RT_TICK_PER_SECOND) + (timer->interval.tv_nsec * RT_TICK_PER_SECOND) / NANOSECOND_PER_SECOND;
- rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_TIME, &(timer->reload));
- }
- int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid)
- {
- static int num = 0;
- struct timer_obj *timer;
- char timername[RT_NAME_MAX] = {0};
- if (clockid > CLOCK_TAI || evp->sigev_notify != SIGEV_NONE && evp->sigev_notify != SIGEV_SIGNAL)
- {
- rt_set_errno(EINVAL);
- return -RT_ERROR;
- }
- timer = rt_malloc(sizeof(struct timer_obj));
- if (timer == RT_NULL)
- {
- rt_set_errno(ENOMEM);
- return -RT_ENOMEM;
- }
- rt_snprintf(timername, RT_NAME_MAX, "psx_tm%02d", num++);
- num %= 100;
- timer->sigev_signo = evp->sigev_signo;
- timer->pid = lwp_self()->pid;
- timer->sigev_notify_function = evp->sigev_notify_function;
- timer->val = evp->sigev_value;
- timer->interval.tv_sec = 0;
- timer->interval.tv_nsec = 0;
- timer->reload = 0U;
- timer->status = NOT_ACTIVE;
- if (evp->sigev_notify == SIGEV_NONE)
- {
- rt_timer_init(&timer->timer, timername, RT_NULL, RT_NULL, 0, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER);
- }
- else
- {
- rt_timer_init(&timer->timer, timername, rtthread_timer_wrapper, timer, 0, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER);
- }
- *timerid = (timer_t)((uintptr_t)timer >> 1);
- return RT_EOK;
- }
- RTM_EXPORT(timer_create);
- int timer_delete(timer_t timerid)
- {
- struct timer_obj *timer = (struct timer_obj *)((uintptr_t)timerid << 1);
- if (timer == RT_NULL || rt_object_get_type(&timer->timer.parent) != RT_Object_Class_Timer)
- {
- rt_set_errno(EINVAL);
- return -RT_ERROR;
- }
- if (timer->status == ACTIVE)
- {
- timer->status = NOT_ACTIVE;
- rt_timer_stop(&timer->timer);
- }
- rt_timer_detach(&timer->timer);
- rt_free(timer);
- return RT_EOK;
- }
- RTM_EXPORT(timer_delete);
- int timer_getoverrun(timer_t timerid)
- {
- struct timer_obj *timer = (struct timer_obj *)((uintptr_t)timerid << 1);
- rt_set_errno(ENOSYS);
- return -RT_ERROR;
- }
- int timer_gettime(timer_t timerid, struct itimerspec *its)
- {
- struct timer_obj *timer = (struct timer_obj *)((uintptr_t)timerid << 1);
- rt_tick_t remaining;
- rt_uint32_t seconds, nanoseconds;
- if (timer == NULL || rt_object_get_type(&timer->timer.parent) != RT_Object_Class_Timer)
- {
- rt_set_errno(EINVAL);
- return -RT_ERROR;
- }
- if (its == NULL)
- {
- rt_set_errno(EFAULT);
- return -RT_ERROR;
- }
- if (timer->status == ACTIVE)
- {
- rt_tick_t remain_tick;
- rt_timer_control(&timer->timer, RT_TIMER_CTRL_GET_REMAIN_TIME, &remain_tick);
- /* 'remain_tick' is minimum-unit in the RT-Thread' timer,
- * so the seconds, nanoseconds will be calculated by 'remain_tick'.
- */
- remaining = remain_tick - rt_tick_get();
- /* calculate 'second' */
- seconds = remaining / RT_TICK_PER_SECOND;
- /* calculate 'nanosecond'; To avoid lost of accuracy, because "RT_TICK_PER_SECOND" maybe 100, 1000, 1024 and so on.
- *
- * remain_tick millisecond remain_tick * MILLISECOND_PER_SECOND
- * ------------------------- = -------------------------- ---> millisecond = -------------------------------------------
- * RT_TICK_PER_SECOND MILLISECOND_PER_SECOND RT_TICK_PER_SECOND
- *
- * remain_tick * MILLISECOND_PER_SECOND remain_tick * MILLISECOND_PER_SECOND * MICROSECOND_PER_SECOND
- * millisecond = ---------------------------------------- ---> nanosecond = -------------------------------------------------------------------
- * RT_TICK_PER_SECOND RT_TICK_PER_SECOND
- *
- */
- nanoseconds = (((remaining % RT_TICK_PER_SECOND) * MILLISECOND_PER_SECOND) * MICROSECOND_PER_SECOND) / RT_TICK_PER_SECOND;
- its->it_value.tv_sec = (rt_int32_t)seconds;
- its->it_value.tv_nsec = (rt_int32_t)nanoseconds;
- }
- else
- {
- /* Timer is disarmed */
- its->it_value.tv_sec = 0;
- its->it_value.tv_nsec = 0;
- }
- /* The interval last set by timer_settime() */
- its->it_interval = timer->interval;
- return RT_EOK;
- }
- RTM_EXPORT(timer_gettime);
- int timer_settime(timer_t timerid, int flags, const struct itimerspec *value,
- struct itimerspec *ovalue)
- {
- struct timer_obj *timer = (struct timer_obj *)((uintptr_t)timerid << 1);
- if (timer == NULL ||
- rt_object_get_type(&timer->timer.parent) != RT_Object_Class_Timer ||
- value->it_interval.tv_nsec < 0 ||
- value->it_interval.tv_nsec >= NANOSECOND_PER_SECOND ||
- value->it_interval.tv_sec < 0 ||
- value->it_value.tv_nsec < 0 ||
- value->it_value.tv_nsec >= NANOSECOND_PER_SECOND ||
- value->it_value.tv_sec < 0)
- {
- rt_set_errno(EINVAL);
- return -RT_ERROR;
- }
- /* Save time to expire and old reload value. */
- if (ovalue != NULL)
- {
- timer_gettime(timerid, ovalue);
- }
- /* Stop the timer if the value is 0 */
- if ((value->it_value.tv_sec == 0) && (value->it_value.tv_nsec == 0))
- {
- if (timer->status == ACTIVE)
- {
- rt_timer_stop(&timer->timer);
- }
- timer->status = NOT_ACTIVE;
- return RT_EOK;
- }
-
- if (flags & TIMER_ABSTIME == TIMER_ABSTIME)
- {
- rt_int64_t ts = ((value->it_value.tv_sec - _timevalue.tv_sec) * RT_TICK_PER_SECOND);
- rt_int64_t tns = (value->it_value.tv_nsec - _timevalue.tv_usec) * (RT_TICK_PER_SECOND / NANOSECOND_PER_SECOND);
- rt_int64_t reload = ts + tns;
- rt_tick_t rt_tick = rt_tick_get();
- timer->reload = reload < rt_tick ? 0 : reload - rt_tick;
- }
- else
- timer->reload = (value->it_value.tv_sec * RT_TICK_PER_SECOND) + value->it_value.tv_nsec * (RT_TICK_PER_SECOND / NANOSECOND_PER_SECOND);
- timer->interval.tv_sec = value->it_interval.tv_sec;
- timer->interval.tv_nsec = value->it_interval.tv_nsec;
- timer->value.tv_sec = value->it_value.tv_sec;
- timer->value.tv_nsec = value->it_value.tv_nsec;
- if (timer->status == ACTIVE)
- {
- rt_timer_stop(&timer->timer);
- }
- timer->status = ACTIVE;
- if ((value->it_interval.tv_sec == 0) && (value->it_interval.tv_nsec == 0))
- rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_ONESHOT, RT_NULL);
- else
- rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_PERIODIC, RT_NULL);
- rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_TIME, &(timer->reload));
- rt_timer_start(&timer->timer);
- return RT_EOK;
- }
- RTM_EXPORT(timer_settime);
|