1 #include "ameba_soc.h"
2 #include "k_api.h"
3 #include "board.h"
4 #include "device.h"
5 #include "aos/hal/rtc.h"
6 #include <time.h>
7 #include "rtc_api.h"
8 
9 static struct tm rtc_timeinfo;
10 static int rtc_en = 0;
11 
12 const static u8 dim[12] = {
13 	31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
14 
15 /**
16   * @brief  This function is used to tell a year is a leap year or not.
17   * @param  year: The year need to be told.
18   * @retval value:
19   *             - 1: This year is leap year.
20   *             - 0: This year is not leap year.
21   */
is_leap_year(unsigned int year)22 static inline bool is_leap_year(unsigned int year)
23 {
24 	u32 full_year = year + 1900;
25 	return (!(full_year % 4) && (full_year % 100)) || !(full_year % 400);
26 }
27 
28 
29 /**
30   * @brief  This function tells how many days in a month of a year.
31   * @param  year: Specified year
32   * @param  month: Specified month
33   * @retval value: Number of days in the month.
34   */
days_in_month(u8 month,u8 year)35 static u8 days_in_month (u8 month, u8 year)
36 {
37 	u8 ret = dim[month];
38 	if (ret == 0)
39 		ret = is_leap_year (year) ? 29 : 28;
40 	return ret;
41 }
42 
43 /**
44   * @brief  This function is used to calculate month and day of month according to year and day of the year.
45   * @param  year: years since 1900.
46   * @param  yday: day of the year.
47   * @param  mon: pointer to the variable which stores month,  the value can be 0-11
48   * @param  mday: pointer to the variable which stores day of month, the value can be 1-31
49   * @retval value: none
50   */
rtc_calculate_mday(int year,int yday,int * mon,int * mday)51 static void rtc_calculate_mday(int year, int yday, int* mon, int* mday)
52 {
53 	int t_mon = -1, t_yday = yday + 1;
54 
55 	while(t_yday > 0){
56 		t_mon ++;
57 		t_yday -= days_in_month(t_mon, year);
58 	}
59 
60 	*mon = t_mon;
61 	*mday = t_yday + days_in_month(t_mon, year);
62 }
63 
64 /**
65   * @brief  This function is used to calculate day of week according to date.
66   * @param  year: years since 1900.
67   * @param  mon: which month of the year
68   * @param  mday: pointer to the variable which store day of month
69   * @param  wday: pointer to the variable which store day of week, the value can be 0-6, and 0 means Sunday
70   * @retval value: none
71   */
rtc_calculate_wday(int year,int mon,int mday,int * wday)72 static void rtc_calculate_wday(int year, int mon, int mday, int* wday)
73 {
74 	int t_year = year + 1900, t_mon = mon + 1;
75 
76 	if(t_mon == 1 || t_mon == 2){
77 		t_year --;
78 		t_mon += 12;
79 	}
80 
81 	int c = t_year / 100;
82 	int y = t_year % 100;
83 	int week = (c / 4) - 2 * c + (y + y / 4) + (26 * (t_mon + 1) / 10) + mday -1;
84 
85 	while(week < 0){
86 		week += 7;
87 	}
88 	week %= 7;
89 
90 	*wday = week;
91 }
92 
get_yday(rtc_time_t * time)93 static u32  get_yday(rtc_time_t *time)
94 {
95 	int days = time->date;
96 
97 	for(int i = 0; i < time->month-1; i++){
98 		days += dim[i];
99 	}
100 }
101 
102 /**
103   * @brief  This function is used to restore rtc_timeinfo global variable whose value is lost after system reset.
104   * @param  none
105   * @retval value: none
106   */
rtc_restore_timeinfo(rtc_dev_t * rtc)107 static void rtc_restore_timeinfo(rtc_dev_t *rtc)
108 {
109 	u32 value, days_in_year, format;
110 
111 	if(rtc->config.format == HAL_RTC_FORMAT_DEC)
112 		format = RTC_Format_BIN;
113 	else if(rtc->config.format == HAL_RTC_FORMAT_BCD)
114 		format = RTC_Format_BCD;
115 
116 
117 	RTC_TimeTypeDef RTC_TimeStruct;
118         RTC_GetTime(format, &RTC_TimeStruct);
119 	rtc_timeinfo.tm_sec = RTC_TimeStruct.RTC_Seconds;
120 	rtc_timeinfo.tm_min = RTC_TimeStruct.RTC_Minutes;
121 	rtc_timeinfo.tm_hour = RTC_TimeStruct.RTC_Hours;
122 	rtc_timeinfo.tm_yday = RTC_TimeStruct.RTC_Days;
123 
124 	value = BKUP_Read(0);
125 
126 	rtc_timeinfo.tm_year = (value & BIT_RTC_BACKUP) >> 8;
127 
128 	days_in_year =  (is_leap_year(rtc_timeinfo.tm_year) ? 366 : 365);
129 	if(rtc_timeinfo.tm_yday > days_in_year - 1){
130 		rtc_timeinfo.tm_year ++;
131 		rtc_timeinfo.tm_yday -= days_in_year;
132 
133 		/* over one year, update days in RTC_TR */
134 		RTC_TimeStruct.RTC_Days = rtc_timeinfo.tm_yday;
135 		RTC_SetTime(format, &RTC_TimeStruct);
136 	}
137 
138 	rtc_calculate_mday(rtc_timeinfo.tm_year, rtc_timeinfo.tm_yday, &rtc_timeinfo.tm_mon, &rtc_timeinfo.tm_mday);
139 	rtc_calculate_wday(rtc_timeinfo.tm_year, rtc_timeinfo.tm_mon, rtc_timeinfo.tm_mday, &rtc_timeinfo.tm_wday);
140 }
141 
142 
143 /**
144   * @brief  Initializes the RTC device, include clock, RTC registers and function.
145   * @param  none
146   * @retval  none
147   */
148 
149 /**
150  * This function will initialize the on board CPU real time clock
151  *
152  *
153  * @param[in]  rtc  rtc device
154  *
155  * @return  0 : on success, EIO : if an error occurred with any step
156  */
hal_rtc_init(rtc_dev_t * rtc)157 int32_t hal_rtc_init(rtc_dev_t *rtc)
158 {
159 	RTC_InitTypeDef RTC_InitStruct;
160 
161 	RCC_PeriphClockSource_RTC(0);
162 
163 	RTC_StructInit(&RTC_InitStruct);
164 	RTC_InitStruct.RTC_HourFormat = RTC_HourFormat_24;
165 
166 	RTC_Init(&RTC_InitStruct);
167 
168 	/* 32760 need add need add 15 cycles (256Hz) every 4 min*/
169 	//RTC_SmoothCalibConfig(RTC_CalibSign_Positive, 15,
170 	//	RTC_CalibPeriod_4MIN, RTC_Calib_Enable);
171 
172 	rtc_en = 1;
173 
174 	return 0;
175 }
176 
177 /**
178  * This function will return the value of time read from the on board CPU real time clock.
179  *
180  * @param[in]   rtc   rtc device
181  * @param[out]  time  pointer to a time structure
182  *
183  * @return  0 : on success, EIO : if an error occurred with any step
184  */
hal_rtc_get_time(rtc_dev_t * rtc,rtc_time_t * time)185 int32_t hal_rtc_get_time(rtc_dev_t *rtc, rtc_time_t *time)
186 {
187 	int format;
188 	struct tm tm_temp;
189 	RTC_TimeTypeDef RTC_TimeStruct;
190 	u32 delta_days = 0;
191 
192 	if(BKUP_Read(0) & BIT_RTC_RESTORE){
193 		rtc_restore_timeinfo(rtc);
194 		BKUP_Clear(0, BIT_RTC_RESTORE);
195 	}
196 
197 	_memcpy((void*)&tm_temp, (void*)&rtc_timeinfo, sizeof(struct tm));
198 
199 	if(rtc->config.format == HAL_RTC_FORMAT_DEC)
200 		format = RTC_Format_BIN;
201 	else if(rtc->config.format == HAL_RTC_FORMAT_BCD)
202 		format = RTC_Format_BCD;
203 	/*hour, min, sec get from RTC*/
204 	RTC_GetTime(format, &RTC_TimeStruct);
205 	tm_temp.tm_sec = RTC_TimeStruct.RTC_Seconds;
206 	tm_temp.tm_min = RTC_TimeStruct.RTC_Minutes;
207 	tm_temp.tm_hour = RTC_TimeStruct.RTC_Hours;
208 
209 	/* calculate how many days later from last time update rtc_timeinfo */
210 	delta_days = RTC_TimeStruct.RTC_Days - tm_temp.tm_yday;
211 
212 	/* calculate  wday, mday, yday, mon, year*/
213 	tm_temp.tm_wday += delta_days;
214 	if(tm_temp.tm_wday >= 7){
215 		tm_temp.tm_wday = tm_temp.tm_wday % 7;
216 	}
217 
218 	tm_temp.tm_yday += delta_days;
219 	tm_temp.tm_mday += delta_days;
220 
221 	while(tm_temp.tm_mday > days_in_month(tm_temp.tm_mon, tm_temp.tm_year)){
222 		tm_temp.tm_mday -= days_in_month(tm_temp.tm_mon, tm_temp.tm_year);
223 		tm_temp.tm_mon++;
224 
225 		if(tm_temp.tm_mon >= 12){
226 			tm_temp.tm_mon -= 12;
227 			tm_temp.tm_yday -= is_leap_year(tm_temp.tm_year) ? 366 : 365;
228 			tm_temp.tm_year ++;
229 
230 			/* over one year, update days in RTC_TR */
231 			RTC_TimeStruct.RTC_Days = tm_temp.tm_yday;
232 			RTC_SetTime(RTC_Format_BIN, &RTC_TimeStruct);
233 
234 			/* update rtc_timeinfo */
235 			_memcpy((void*)&rtc_timeinfo, (void*)&tm_temp, sizeof(struct tm));
236 		}
237 	}
238 
239 	time->sec = tm_temp.tm_sec;
240 	time->min = tm_temp.tm_min;
241 	time->hr = tm_temp.tm_hour;
242 	time->weekday = tm_temp.tm_wday;
243 	time->date = tm_temp.tm_mday;
244 	time->month = tm_temp.tm_mon;
245 	time->year = tm_temp.tm_year;
246 
247 	return 0;
248 }
249 
250 /**
251  * This function will set MCU RTC time to a new value.
252  *
253  * @param[in]   rtc   rtc device
254  * @param[out]  time  pointer to a time structure
255  *
256  * @return  0 : on success, EIO : if an error occurred with any step
257  */
hal_rtc_set_time(rtc_dev_t * rtc,const rtc_time_t * time)258 int32_t hal_rtc_set_time(rtc_dev_t *rtc, const rtc_time_t *time)
259 {
260 	struct tm timeinfo;
261 	int format;
262 
263 	timeinfo.tm_sec = time->sec;
264 	timeinfo.tm_min = time->min ;
265 	timeinfo.tm_hour= time->hr;
266 	timeinfo.tm_wday= time->weekday;
267 	timeinfo.tm_mday= time->date;
268 	timeinfo.tm_mon =time->month;
269 	timeinfo.tm_year= time->year;
270 
271 	timeinfo.tm_yday = get_yday((rtc_time_t *)time);
272 
273 	RTC_TimeTypeDef RTC_TimeStruct;
274 
275 	/*set time in RTC */
276 	RTC_TimeStruct.RTC_H12_PMAM = RTC_H12_AM;
277 	RTC_TimeStruct.RTC_Days = timeinfo.tm_yday;
278 	RTC_TimeStruct.RTC_Hours = timeinfo.tm_hour;
279 	RTC_TimeStruct.RTC_Minutes = timeinfo.tm_min;
280 	RTC_TimeStruct.RTC_Seconds = timeinfo.tm_sec;
281 
282 
283 	if(rtc->config.format == HAL_RTC_FORMAT_DEC)
284 		format = RTC_Format_BIN;
285 	else if(rtc->config.format == HAL_RTC_FORMAT_BCD)
286 		format = RTC_Format_BCD;
287 
288 	RTC_SetTime(format, &RTC_TimeStruct);
289 
290 	/* Set rtc_timeinfo*/
291 	_memcpy((void*)&rtc_timeinfo, (void*)&timeinfo, sizeof(struct tm));
292 
293 	return 0;
294 }
295 /**
296  * De-initialises an RTC interface, Turns off an RTC hardware interface
297  *
298  * @param[in]  RTC  the interface which should be de-initialised
299  *
300  * @return  0 : on success, EIO : if an error occurred with any step
301  */
hal_rtc_finalize(rtc_dev_t * rtc)302 int32_t hal_rtc_finalize(rtc_dev_t *rtc)
303 {
304 	rtc_en = 0;
305 
306 	return 0;
307 }
308 
309