1 /*
2  * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
3  *
4  * HDF is dual licensed: you can use it either under the terms of
5  * the GPL, or the BSD license, at your option.
6  * See the LICENSE file in the root of this repository for complete details.
7  */
8 
9 #include "rtc_base.h"
10 #include "platform_log.h"
11 #define HDF_UINT32_MAX 0xffffffffu
12 
13 #define HDF_LOG_TAG rtc_base
14 
RtcGetMonthDays(const uint8_t isLeapYear,const uint8_t month)15 uint8_t RtcGetMonthDays(const uint8_t isLeapYear, const uint8_t month)
16 {
17     uint8_t days;
18     uint8_t oddMonth;
19 
20     if (IS_INVALID_MONTH(month) || (isLeapYear > RTC_TRUE)) {
21         return 0;
22     }
23 
24     if (month == RTC_FEBRUARY) {
25         days = RTC_TWO_MONTH_DAY + isLeapYear;
26     } else {
27         oddMonth = (month >= RTC_AUGUST) ? (month - RTC_UNIT_DIFF) : month;
28         days = (oddMonth & RTC_ODD_MONTH_MASK) ? RTC_GREAT_MONTH_DAY : RTC_SMALL_MONTH_DAY;
29     }
30     return days;
31 }
32 
RtcIsInvalidDay(const uint8_t day,const uint8_t month,const uint16_t year)33 uint8_t RtcIsInvalidDay(const uint8_t day, const uint8_t month, const uint16_t year)
34 {
35     uint8_t maxDay;
36     maxDay = RtcGetMonthDays(IS_LEAP_YEAR(year), month);
37 
38     return ((day == 0) || (day > maxDay)) ? RTC_TRUE : RTC_FALSE;
39 }
40 
RtcIsInvalid(const struct RtcTime * time)41 uint8_t RtcIsInvalid(const struct RtcTime *time)
42 {
43     if (time == NULL) {
44         HDF_LOGE("RtcIsInvalid: time is null!");
45         return RTC_FALSE;
46     }
47 
48     return (IS_INVALID_YEAR(time->year) || IS_INVALID_MONTH(time->month) ||
49         (RtcIsInvalidDay(time->day, time->month, time->year) == RTC_TRUE) ||
50         IS_INVALID_HOUR(time->hour) || IS_INVALID_MIN(time->minute) ||
51         IS_INVALID_SECOND(time->second) || IS_INVALID_MS(time->millisecond));
52 }
53 
RtcGetWeekDay(const struct RtcTime * time)54 uint8_t RtcGetWeekDay(const struct RtcTime *time)
55 {
56     uint32_t days;
57     int8_t month;
58     uint16_t year;
59 
60     if ((time == NULL) || IS_INVALID_MONTH(time->month) || IS_INVALID_YEAR(time->year) ||
61         (RtcIsInvalidDay(time->day, time->month, time->year) == RTC_TRUE)) {
62         HDF_LOGE("RtcGetWeekDay: time is invalid!");
63         return RTC_FALSE;
64     }
65 
66     days = time->day - RTC_UNIT_DIFF;
67     month = time->month;
68     while (--month >= RTC_JANUARY) {
69         days += RtcGetMonthDays(IS_LEAP_YEAR(time->year), month);
70     }
71 
72     year = time->year;
73     while (--year >= RTC_BEGIN_YEAR) {
74         days += RTC_YEAR_DAYS(year);
75     }
76 
77     if (days > (HDF_UINT32_MAX - RTC_BEGIN_WEEKDAY)) {
78         HDF_LOGE("RtcGetWeekDay: days is invalid!");
79         return RTC_FALSE;
80     }
81     return ((RTC_BEGIN_WEEKDAY + days - RTC_UNIT_DIFF) % RTC_MAX_WEEKDAY + RTC_UNIT_DIFF);
82 }
83 
84 #ifndef __KERNEL__
RtcTimeToTimestamp(const struct RtcTime * time)85 uint64_t RtcTimeToTimestamp(const struct RtcTime *time)
86 {
87     uint64_t seconds;
88     uint32_t days;
89     uint16_t year;
90     int8_t month;
91 
92     if (time == NULL) {
93         HDF_LOGE("RtcTimeToTimestamp: time is null!");
94         return RTC_FALSE;
95     }
96     PLAT_LOGV("RtcToTimestamp: year-month-day hour:min:second ms %04u-%02u-%02u %02u:%02u:%02u .%03u",
97         time->year, time->month, time->day, time->hour, time->minute, time->second, time->millisecond);
98     if (RtcIsInvalid(time) == RTC_TRUE) {
99         HDF_LOGE("RtcTimeToTimestamp: time invalid");
100         return 0;
101     }
102 
103     seconds = ((uint64_t)time->hour * RTC_MAX_MINUTE + time->minute) * RTC_MAX_SECOND + time->second;
104     days = time->day - RTC_UNIT_DIFF;
105     month = time->month;
106     year = time->year;
107 
108     for (month--; month >=  RTC_JANUARY; month--) {
109         days += RtcGetMonthDays(IS_LEAP_YEAR(time->year), month);
110     }
111 
112     for (year--; year >= RTC_BEGIN_YEAR; year--) {
113         days += RTC_YEAR_DAYS(year);
114     }
115 
116     seconds += days * RTC_DAY_SECONDS;
117     return seconds;
118 }
119 
TimestampToRtcTime(struct RtcTime * time,const uint64_t seconds)120 void TimestampToRtcTime(struct RtcTime *time, const uint64_t seconds)
121 {
122     uint32_t daySeconds = (uint32_t)(seconds % RTC_DAY_SECONDS);
123     uint32_t days = (uint32_t)(seconds / RTC_DAY_SECONDS);
124 
125     if (time == NULL) {
126         HDF_LOGE("TimestampToRtcTime: time is null!");
127         return;
128     }
129 
130     time->year = RTC_BEGIN_YEAR;
131     while (days >= RTC_YEAR_DAYS(time->year)) {
132         days -= RTC_YEAR_DAYS(time->year);
133         time->year++;
134     }
135 
136     time->month = RTC_JANUARY;
137     while (days >= RtcGetMonthDays(IS_LEAP_YEAR(time->year), time->month)) {
138         days -= RtcGetMonthDays(IS_LEAP_YEAR(time->year), time->month);
139         time->month++;
140     }
141 
142     time->day = days;
143     time->second = daySeconds % RTC_MAX_SECOND;
144     time->minute = (daySeconds % RTC_HOUR_SECONDS) / RTC_MAX_MINUTE;
145     time->hour = daySeconds / RTC_HOUR_SECONDS;
146 
147     time->day += RTC_UNIT_DIFF;
148     time->weekday = RtcGetWeekDay(time);
149     PLAT_LOGV("TimestampToRtc: year-month-day weekday hour:min:second ms %04u-%02u-%02u %u %02u:%02u:%02u .%03u",
150         time->year, time->month, time->day, time->weekday, time->hour, time->minute, time->second, time->millisecond);
151 }
152 #endif
153