Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:22

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSImplClassicClock
0007  *
0008  * @brief This source file contains the implementation of
0009  *   rtems_clock_get_tod().
0010  */
0011 
0012 /*
0013  *  COPYRIGHT (c) 1989-2007.
0014  *  On-Line Applications Research Corporation (OAR).
0015  *
0016  * Redistribution and use in source and binary forms, with or without
0017  * modification, are permitted provided that the following conditions
0018  * are met:
0019  * 1. Redistributions of source code must retain the above copyright
0020  *    notice, this list of conditions and the following disclaimer.
0021  * 2. Redistributions in binary form must reproduce the above copyright
0022  *    notice, this list of conditions and the following disclaimer in the
0023  *    documentation and/or other materials provided with the distribution.
0024  *
0025  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0026  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0027  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0028  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0029  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0030  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0031  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0032  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0033  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0034  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0035  * POSSIBILITY OF SUCH DAMAGE.
0036  */
0037 
0038 #ifdef HAVE_CONFIG_H
0039 #include "config.h"
0040 #endif
0041 
0042 #include <rtems/rtems/clock.h>
0043 #include <rtems/score/todimpl.h>
0044 #include <rtems/config.h>
0045 
0046 #define RTEMS_SECS_PER_MINUTE (60UL)
0047 #define RTEMS_MINUTE_PER_HOUR (60UL)
0048 #define RTEMS_SECS_PER_HOUR   (RTEMS_SECS_PER_MINUTE * RTEMS_MINUTE_PER_HOUR)
0049 #define RTEMS_HOURS_PER_DAY   (24UL)
0050 #define RTEMS_SECS_PER_DAY    (RTEMS_SECS_PER_HOUR * RTEMS_HOURS_PER_DAY)
0051 #define RTEMS_DAYS_PER_YEAR   (365UL)
0052 #define RTEMS_YEAR_BASE       (1970UL)
0053 
0054 static bool _Leap_year(
0055   uint32_t year
0056 )
0057 {
0058   return (((year % 4) == 0) && ((year % 100) != 0)) || ((year % 400) == 0);
0059 }
0060 
0061 static uint32_t _Leap_years_before(
0062   uint32_t year
0063 )
0064 {
0065   year -= 1;
0066   return (year / 4) - (year / 100) + (year / 400);
0067 }
0068 
0069 static uint32_t _Leap_years_between(
0070   uint32_t from, uint32_t to
0071 )
0072 {
0073   return _Leap_years_before( to ) - _Leap_years_before( from + 1 );
0074 }
0075 
0076 static uint32_t _Year_day_as_month(
0077   uint32_t year, uint32_t *day
0078 )
0079 {
0080   const uint16_t* days_to_date;
0081   uint32_t        month = 0;
0082 
0083   if ( _Leap_year( year ) )
0084     days_to_date = _TOD_Days_to_date[0];
0085   else
0086     days_to_date = _TOD_Days_to_date[1];
0087 
0088   days_to_date += 2;
0089 
0090   while (month < 11) {
0091     if (*day < *days_to_date)
0092       break;
0093     ++month;
0094     ++days_to_date;
0095   }
0096 
0097   *day -= *(days_to_date - 1);
0098 
0099   return month;
0100 }
0101 
0102 rtems_status_code rtems_clock_get_tod(
0103   rtems_time_of_day  *time_of_day
0104 )
0105 {
0106   struct timeval now;
0107   uint32_t       days;
0108   uint32_t       day_secs;
0109   uint32_t       year;
0110   uint32_t       year_days;
0111   uint32_t       leap_years;
0112 
0113   if ( !time_of_day )
0114     return RTEMS_INVALID_ADDRESS;
0115 
0116   if ( !_TOD_Is_set() )
0117     return RTEMS_NOT_DEFINED;
0118 
0119   /* Obtain the current time */
0120   _TOD_Get_timeval( &now );
0121 
0122   /*
0123    * How many days and how many seconds in the day?
0124    *
0125    * A 32-bit integer can represent enough days for several 1000 years.  When
0126    * the current time is valid, the integer conversions below are well defined.
0127    */
0128   days = (uint32_t) ( now.tv_sec / RTEMS_SECS_PER_DAY );
0129   day_secs = (uint32_t) ( now.tv_sec % RTEMS_SECS_PER_DAY );
0130 
0131   /* How many non-leap year years ? */
0132   year = ( days / RTEMS_DAYS_PER_YEAR ) + RTEMS_YEAR_BASE;
0133 
0134   /* Determine the number of leap years. */
0135   leap_years = _Leap_years_between( RTEMS_YEAR_BASE, year );
0136 
0137   /* Adjust the remaining number of days based on the leap years. */
0138   year_days = ( days - leap_years ) % RTEMS_DAYS_PER_YEAR;
0139 
0140   /* Adjust the year and days in the year if in the leap year overflow. */
0141   if ( leap_years > ( days % RTEMS_DAYS_PER_YEAR ) ) {
0142     year -= 1;
0143     if ( _Leap_year( year ) ) {
0144       year_days += 1;
0145     }
0146   }
0147 
0148   time_of_day->year   = year;
0149   time_of_day->month  = _Year_day_as_month( year, &year_days ) + 1;
0150   time_of_day->day    = year_days + 1;
0151   time_of_day->hour   = day_secs / RTEMS_SECS_PER_HOUR;
0152   time_of_day->minute = day_secs % RTEMS_SECS_PER_HOUR;
0153   time_of_day->second = time_of_day->minute % RTEMS_SECS_PER_MINUTE;
0154   time_of_day->minute = time_of_day->minute / RTEMS_SECS_PER_MINUTE;
0155   time_of_day->ticks  = now.tv_usec /
0156     rtems_configuration_get_microseconds_per_tick( );
0157 
0158   return RTEMS_SUCCESSFUL;
0159 }