v0.1 board believed to be reading Vbat, Pressure, and X/Y/Z correctly now,
[fw/openalt] / rtc / rtc.c
1 #include "FreeRTOS.h"
2 #include "task.h"
3 #include "queue.h"
4
5 #include <stdlib.h>
6 #include <string.h>
7 #include <time.h>
8 #include <sys/times.h>
9
10 #include "rtcISR.h"
11 #include "rtc.h"
12
13 //
14 //  Place RTC on 32kHz xtal and disconnect power.
15 //
16 static inline void rtcSleep (void)
17 {
18   RTC_CCR = (RTC_CCR_CLKEN | RTC_CCR_CLKSRC);
19   SCB_PCONP &= ~SCB_PCONP_PCRTC;
20 }
21
22 //
23 //  Prepare clock for interactive use.
24 //
25 static inline void rtcWake (void)
26 {
27   RTC_CCR = (RTC_CCR_CLKEN | RTC_CCR_CLKSRC);
28   SCB_PCONP |= SCB_PCONP_PCRTC;
29 }
30
31 //
32 //  Read clock registers and return tm structure.
33 //
34 static void rtcRead (struct tm *theTime, unsigned int *milliseconds)
35 {
36   unsigned int ticks32Khz;
37   rtcCTIME0_t ctime0;
38   rtcCTIME1_t ctime1;
39   rtcCTIME2_t ctime2;
40
41   rtcWake ();
42   portENTER_CRITICAL ();
43
44   do
45   {
46     ctime0.i = RTC_CTIME0;
47     ctime1.i = RTC_CTIME1;
48     ctime2.i = RTC_CTIME2;
49
50     do
51       ticks32Khz = (RTC_CTC & 0xfffe);
52     while (ticks32Khz != (RTC_CTC & 0xfffe));
53   }
54   while (ctime0.i != RTC_CTIME0);
55
56   portEXIT_CRITICAL ();
57   rtcSleep ();
58
59   if (milliseconds)
60     *milliseconds = (((ticks32Khz / 2) * 1000u) / 32768u);
61
62   theTime->tm_sec   = ctime0.seconds;
63   theTime->tm_min   = ctime0.minutes;
64   theTime->tm_hour  = ctime0.hours;
65   theTime->tm_mday  = ctime1.dom;
66   theTime->tm_mon   = ctime1.month - 1;
67   theTime->tm_year  = ctime1.year - 1900;
68   theTime->tm_wday  = ctime0.dow;
69   theTime->tm_yday  = ctime2.doy - 1;
70   theTime->tm_isdst = 0;
71 }
72
73 //
74 //  Set clock to new values.
75 //
76 static void rtcWrite (struct tm *newTime)
77 {
78   rtcWake ();
79   portENTER_CRITICAL ();
80
81   RTC_CCR &= ~RTC_CCR_CLKEN;
82   RTC_CCR |=  RTC_CCR_CTCRST;
83
84   RTC_SEC   = newTime->tm_sec;
85   RTC_MIN   = newTime->tm_min;
86   RTC_HOUR  = newTime->tm_hour;
87   RTC_DOM   = newTime->tm_mday;
88   RTC_MONTH = newTime->tm_mon + 1;
89   RTC_YEAR  = newTime->tm_year + 1900;
90   RTC_DOW   = newTime->tm_wday;
91   RTC_DOY   = newTime->tm_yday + 1;
92
93   RTC_CCR &= ~RTC_CCR_CTCRST;
94   RTC_CCR |=  RTC_CCR_CLKEN;
95
96   portEXIT_CRITICAL ();
97   rtcSleep ();
98 }
99
100 //
101 //
102 //
103 time_t rtcGetEpochSeconds (unsigned int *milliseconds)
104 {
105   struct tm tm;
106
107   rtcRead (&tm, milliseconds);
108   return mktime (&tm);
109 }
110
111 void rtcSetEpochSeconds (time_t now)
112 {
113   struct tm tm;
114
115   localtime_r (&now, &tm);
116   rtcWrite (&tm);
117 }
118
119 //
120 //  Start clock so that the sytsem may use it.
121 //
122 static void rtcInitClockCalendar (void)
123 {
124   int nonsense = 0;
125   rtcCTIME0_t ctime0;
126   rtcCTIME1_t ctime1;
127   rtcCTIME2_t ctime2;
128
129   rtcWake ();
130   
131   ctime0.i = RTC_CTIME0; 
132   ctime1.i = RTC_CTIME1; 
133   ctime2.i = RTC_CTIME2;
134
135   //
136   //  Leisurely tear the packed time apart into individual time.
137   //
138   if ((ctime0.seconds < 0) || (ctime0.seconds > 59))  nonsense = 1;
139   if ((ctime0.minutes < 0) || (ctime0.minutes > 59))  nonsense = 1;
140   if ((ctime0.hours < 0)   || (ctime0.hours > 23))    nonsense = 1;
141   if ((ctime1.dom < 1)     || (ctime1.dom > 31))      nonsense = 1;
142   if ((ctime1.month < 1)   || (ctime1.month > 12))    nonsense = 1;
143   if ((ctime1.year < 1980) || (ctime1.year > 2050))   nonsense = 1;
144   if ((ctime0.dow < 0)     || (ctime0.dow > 6))       nonsense = 1;
145   if ((ctime2.doy < 0)     || (ctime2.doy > 366))     nonsense = 1;
146
147   rtcSleep ();
148
149   //
150   //  Set the clock to Jan 1, 2006 00:00:00
151   //
152   if (nonsense) 
153     rtcSetEpochSeconds ((time_t) 1136073600);
154 }
155
156 //
157 //
158 //
159 void rtcInit (void)
160 {
161   rtcISRInit ();
162
163   SCB_PCONP |= SCB_PCONP_PCRTC;
164
165   RTC_CCR = 0;
166
167   RTC_CCR |= RTC_CCR_CLKSRC;
168
169   RTC_AMR = RTC_AMR_AMRMASK;
170   RTC_CIIR = 0;
171
172   RTC_ILR = RTC_ILR_MASK;
173
174   RTC_CCR |= RTC_CCR_CLKEN;
175
176   VIC_IntSelect &= ~VIC_IntSelect_RTC;
177 #ifdef RTC_NONVECTOREDIRQ
178   VIC_DefVectAddr = (portLONG) rtcISR;
179 #else
180   VIC_VectAddr6 = (portLONG) rtcISR;
181   VIC_VectCntl6 = VIC_VectCntl_ENABLE | VIC_Channel_RTC;
182 #endif
183   VIC_IntEnable = VIC_IntEnable_RTC;
184
185   rtcInitClockCalendar ();
186 }
187
188 int rtcSetAlarm (struct tm *tm)
189 {
190   if (tm && (mktime (tm) < time (NULL)))
191     return -1;
192
193   rtcWake ();
194
195   RTC_AMR = RTC_AMR_AMRMASK;
196
197   if (tm)
198   {
199     RTC_ALYEAR = tm->tm_year + 1900;
200     RTC_ALMON = tm->tm_mon + 1;
201     RTC_ALDOM = tm->tm_mday;
202     RTC_ALHOUR = tm->tm_hour;
203     RTC_ALMIN = tm->tm_min;
204     RTC_ALSEC = tm->tm_sec;
205     RTC_ALDOW = 0;
206     RTC_ALDOY = 0;
207
208     RTC_AMR = RTC_AMR_AMRDOW | RTC_AMR_AMRDOY;
209   }
210
211   rtcSleep ();
212
213   return 0;
214 }
215
216 struct tm *rtcGetAlarmTm (struct tm *tm)
217 {
218   if (tm)
219   {
220     memset (tm, 0, sizeof (* tm));
221
222     rtcWake ();
223
224     if (RTC_AMR != RTC_AMR_AMRMASK)
225     {
226       tm->tm_year = RTC_ALYEAR - 1900;
227       tm->tm_mon = RTC_ALMON - 1;
228       tm->tm_mday = RTC_ALDOM;
229       tm->tm_hour = RTC_ALHOUR;
230       tm->tm_min = RTC_ALMIN;
231       tm->tm_sec = RTC_ALSEC;
232     }
233     else
234     {
235       time_t now = 0;
236       memcpy (tm, localtime (&now), sizeof (* tm));
237     }
238
239     rtcSleep ();
240   }
241
242   return tm;
243 }
244
245 time_t rtcGetAlarmEpochSeconds (void)
246 {
247   struct tm tm;
248
249   return mktime (rtcGetAlarmTm (&tm));
250 }
251
252 int rtcPeriodicAlarm (int mode)
253 {
254   int state;
255     
256   rtcWake ();
257
258   state = RTC_CIIR & RTC_CIIR_IMMIN;
259
260   if (!mode)
261     RTC_CIIR &= ~RTC_CIIR_IMMIN;
262   else if (mode > 0)
263     RTC_CIIR |= RTC_CIIR_IMMIN;
264
265   rtcSleep ();
266
267   return state ? 1 : 0;
268 }