1 /*
2  * Copyright (c) 2019-2020 Peter Bigot Consulting, LLC
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdio.h>
8 
9 #include <zephyr/kernel.h>
10 #include <zephyr/device.h>
11 #include <zephyr/drivers/counter.h>
12 #include <zephyr/sys/printk.h>
13 #include <zephyr/drivers/rtc/maxim_ds3231.h>
14 
15 /* Format times as: YYYY-MM-DD HH:MM:SS DOW DOY */
format_time(time_t time,long nsec)16 static const char *format_time(time_t time,
17 			       long nsec)
18 {
19 	static char buf[64];
20 	char *bp = buf;
21 	char *const bpe = bp + sizeof(buf);
22 	struct tm tv;
23 	struct tm *tp = gmtime_r(&time, &tv);
24 
25 	bp += strftime(bp, bpe - bp, "%Y-%m-%d %H:%M:%S", tp);
26 	if (nsec >= 0) {
27 		bp += snprintf(bp, bpe - bp, ".%09lu", nsec);
28 	}
29 	bp += strftime(bp, bpe - bp, " %a %j", tp);
30 	return buf;
31 }
32 
sec_counter_callback(const struct device * dev,uint8_t id,uint32_t ticks,void * ud)33 static void sec_counter_callback(const struct device *dev,
34 				 uint8_t id,
35 				 uint32_t ticks,
36 				 void *ud)
37 {
38 	printk("Counter callback at %u ms, id %d, ticks %u, ud %p\n",
39 	       k_uptime_get_32(), id, ticks, ud);
40 }
41 
sec_alarm_handler(const struct device * dev,uint8_t id,uint32_t syncclock,void * ud)42 static void sec_alarm_handler(const struct device *dev,
43 			      uint8_t id,
44 			      uint32_t syncclock,
45 			      void *ud)
46 {
47 	uint32_t now = maxim_ds3231_read_syncclock(dev);
48 	struct counter_alarm_cfg alarm = {
49 		.callback = sec_counter_callback,
50 		.ticks = 10,
51 		.user_data = ud,
52 	};
53 
54 	printk("setting channel alarm\n");
55 	int rc = counter_set_channel_alarm(dev, id, &alarm);
56 
57 	printk("Sec signaled at %u ms, param %p, delay %u; set %d\n",
58 	       k_uptime_get_32(), ud, now - syncclock, rc);
59 }
60 
61 
62 /** Calculate the normalized result of a - b.
63  *
64  * For both inputs and outputs tv_nsec must be in the range [0,
65  * NSEC_PER_SEC).  tv_sec may be negative, zero, or positive.
66  */
timespec_subtract(struct timespec * amb,const struct timespec * a,const struct timespec * b)67 void timespec_subtract(struct timespec *amb,
68 		       const struct timespec *a,
69 		       const struct timespec *b)
70 {
71 	if (a->tv_nsec >= b->tv_nsec) {
72 		amb->tv_nsec = a->tv_nsec - b->tv_nsec;
73 		amb->tv_sec = a->tv_sec - b->tv_sec;
74 	} else {
75 		amb->tv_nsec = NSEC_PER_SEC + a->tv_nsec - b->tv_nsec;
76 		amb->tv_sec = a->tv_sec - b->tv_sec - 1;
77 	}
78 }
79 
80 /** Calculate the normalized result of a + b.
81  *
82  * For both inputs and outputs tv_nsec must be in the range [0,
83  * NSEC_PER_SEC).  tv_sec may be negative, zero, or positive.
84  */
timespec_add(struct timespec * apb,const struct timespec * a,const struct timespec * b)85 void timespec_add(struct timespec *apb,
86 		  const struct timespec *a,
87 		  const struct timespec *b)
88 {
89 	apb->tv_nsec = a->tv_nsec + b->tv_nsec;
90 	apb->tv_sec = a->tv_sec + b->tv_sec;
91 	if (apb->tv_nsec >= NSEC_PER_SEC) {
92 		apb->tv_sec += 1;
93 		apb->tv_nsec -= NSEC_PER_SEC;
94 	}
95 }
96 
min_alarm_handler(const struct device * dev,uint8_t id,uint32_t syncclock,void * ud)97 static void min_alarm_handler(const struct device *dev,
98 			      uint8_t id,
99 			      uint32_t syncclock,
100 			      void *ud)
101 {
102 	uint32_t time = 0;
103 	struct maxim_ds3231_syncpoint sp = { 0 };
104 
105 	(void)counter_get_value(dev, &time);
106 
107 	uint32_t uptime = k_uptime_get_32();
108 	uint16_t ms = uptime % 1000U;
109 
110 	uptime /= 1000U;
111 	uint8_t se = uptime % 60U;
112 
113 	uptime /= 60U;
114 	uint8_t mn = uptime % 60U;
115 
116 	uptime /= 60U;
117 	uint8_t hr = uptime;
118 
119 	(void)maxim_ds3231_get_syncpoint(dev, &sp);
120 
121 	uint32_t offset_syncclock = syncclock - sp.syncclock;
122 	uint32_t offset_s = time - (uint32_t)sp.rtc.tv_sec;
123 	uint32_t syncclock_Hz = maxim_ds3231_syncclock_frequency(dev);
124 	struct timespec adj;
125 
126 	adj.tv_sec = offset_syncclock / syncclock_Hz;
127 	adj.tv_nsec = (offset_syncclock % syncclock_Hz)
128 		* (uint64_t)NSEC_PER_SEC / syncclock_Hz;
129 
130 	int32_t err_ppm = (int32_t)(offset_syncclock
131 				- offset_s * syncclock_Hz)
132 			* (int64_t)1000000
133 			/ (int32_t)syncclock_Hz / (int32_t)offset_s;
134 	struct timespec *ts = &sp.rtc;
135 
136 	ts->tv_sec += adj.tv_sec;
137 	ts->tv_nsec += adj.tv_nsec;
138 	if (ts->tv_nsec >= NSEC_PER_SEC) {
139 		ts->tv_sec += 1;
140 		ts->tv_nsec -= NSEC_PER_SEC;
141 	}
142 
143 	printk("%s: adj %d.%09lu, uptime %u:%02u:%02u.%03u, clk err %d ppm\n",
144 	       format_time(time, -1),
145 	       (uint32_t)(ts->tv_sec - time), ts->tv_nsec,
146 	       hr, mn, se, ms, err_ppm);
147 }
148 
149 struct maxim_ds3231_alarm sec_alarm;
150 struct maxim_ds3231_alarm min_alarm;
151 
show_counter(const struct device * ds3231)152 static void show_counter(const struct device *ds3231)
153 {
154 	uint32_t now = 0;
155 
156 	printk("\nCounter at %p\n", ds3231);
157 	printk("\tMax top value: %u (%08x)\n",
158 	       counter_get_max_top_value(ds3231),
159 	       counter_get_max_top_value(ds3231));
160 	printk("\t%u channels\n", counter_get_num_of_channels(ds3231));
161 	printk("\t%u Hz\n", counter_get_frequency(ds3231));
162 
163 	printk("Top counter value: %u (%08x)\n",
164 	       counter_get_top_value(ds3231),
165 	       counter_get_top_value(ds3231));
166 
167 	(void)counter_get_value(ds3231, &now);
168 
169 	printk("Now %u: %s\n", now, format_time(now, -1));
170 }
171 
172 /* Take the currently stored RTC time and round it up to the next
173  * hour.  Program the RTC as though this time had occurred at the
174  * moment the application booted.
175  *
176  * Subsequent reads of the RTC time adjusted based on a syncpoint
177  * should match the uptime relative to the programmed hour.
178  */
set_aligned_clock(const struct device * ds3231)179 static void set_aligned_clock(const struct device *ds3231)
180 {
181 	if (!IS_ENABLED(CONFIG_APP_SET_ALIGNED_CLOCK)) {
182 		return;
183 	}
184 
185 	uint32_t syncclock_Hz = maxim_ds3231_syncclock_frequency(ds3231);
186 	uint32_t syncclock = maxim_ds3231_read_syncclock(ds3231);
187 	uint32_t now = 0;
188 	int rc = counter_get_value(ds3231, &now);
189 	uint32_t align_hour = now + 3600 - (now % 3600);
190 
191 	struct maxim_ds3231_syncpoint sp = {
192 		.rtc = {
193 			.tv_sec = align_hour,
194 			.tv_nsec = (uint64_t)NSEC_PER_SEC * syncclock / syncclock_Hz,
195 		},
196 		.syncclock = syncclock,
197 	};
198 
199 	struct k_poll_signal ss;
200 	struct sys_notify notify;
201 	struct k_poll_event sevt = K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL,
202 							    K_POLL_MODE_NOTIFY_ONLY,
203 							    &ss);
204 
205 	k_poll_signal_init(&ss);
206 	sys_notify_init_signal(&notify, &ss);
207 
208 	uint32_t t0 = k_uptime_get_32();
209 
210 	rc = maxim_ds3231_set(ds3231, &sp, &notify);
211 
212 	printk("\nSet %s at %u ms past: %d\n", format_time(sp.rtc.tv_sec, sp.rtc.tv_nsec),
213 	       syncclock, rc);
214 
215 	/* Wait for the set to complete */
216 	rc = k_poll(&sevt, 1, K_FOREVER);
217 
218 	uint32_t t1 = k_uptime_get_32();
219 
220 	/* Delay so log messages from sync can complete */
221 	k_sleep(K_MSEC(100));
222 	printk("Synchronize final: %d %d in %u ms\n", rc, ss.result, t1 - t0);
223 
224 	rc = maxim_ds3231_get_syncpoint(ds3231, &sp);
225 	printk("wrote sync %d: %u %u at %u\n", rc,
226 	       (uint32_t)sp.rtc.tv_sec, (uint32_t)sp.rtc.tv_nsec,
227 	       sp.syncclock);
228 }
229 
main(void)230 int main(void)
231 {
232 	const struct device *const ds3231 = DEVICE_DT_GET_ONE(maxim_ds3231);
233 
234 	if (!device_is_ready(ds3231)) {
235 		printk("%s: device not ready.\n", ds3231->name);
236 		return 0;
237 	}
238 
239 	uint32_t syncclock_Hz = maxim_ds3231_syncclock_frequency(ds3231);
240 
241 	printk("DS3231 on %s syncclock %u Hz\n\n", CONFIG_BOARD, syncclock_Hz);
242 
243 	int rc = maxim_ds3231_stat_update(ds3231, 0, MAXIM_DS3231_REG_STAT_OSF);
244 
245 	if (rc >= 0) {
246 		printk("DS3231 has%s experienced an oscillator fault\n",
247 		       (rc & MAXIM_DS3231_REG_STAT_OSF) ? "" : " not");
248 	} else {
249 		printk("DS3231 stat fetch failed: %d\n", rc);
250 		return 0;
251 	}
252 
253 	/* Show the DS3231 counter properties */
254 	show_counter(ds3231);
255 
256 	/* Show the DS3231 ctrl and ctrl_stat register values */
257 	printk("\nDS3231 ctrl %02x ; ctrl_stat %02x\n",
258 	       maxim_ds3231_ctrl_update(ds3231, 0, 0),
259 	       maxim_ds3231_stat_update(ds3231, 0, 0));
260 
261 	/* Test maxim_ds3231_set, if enabled */
262 	set_aligned_clock(ds3231);
263 
264 	struct k_poll_signal ss;
265 	struct sys_notify notify;
266 	struct maxim_ds3231_syncpoint sp = { 0 };
267 	struct k_poll_event sevt = K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL,
268 							    K_POLL_MODE_NOTIFY_ONLY,
269 							    &ss);
270 
271 	k_poll_signal_init(&ss);
272 	sys_notify_init_signal(&notify, &ss);
273 
274 	uint32_t t0 = k_uptime_get_32();
275 
276 	rc = maxim_ds3231_synchronize(ds3231, &notify);
277 	printk("\nSynchronize init: %d\n", rc);
278 
279 	rc = k_poll(&sevt, 1, K_FOREVER);
280 
281 	uint32_t t1 = k_uptime_get_32();
282 
283 	k_sleep(K_MSEC(100));   /* wait for log messages */
284 
285 	printk("Synchronize complete in %u ms: %d %d\n", t1 - t0, rc, ss.result);
286 
287 	rc = maxim_ds3231_get_syncpoint(ds3231, &sp);
288 	printk("\nread sync %d: %u %u at %u\n", rc,
289 	       (uint32_t)sp.rtc.tv_sec, (uint32_t)sp.rtc.tv_nsec,
290 	       sp.syncclock);
291 
292 	rc = maxim_ds3231_get_alarm(ds3231, 0, &sec_alarm);
293 	printk("\nAlarm 1 flags %x at %u: %d\n", sec_alarm.flags,
294 	       (uint32_t)sec_alarm.time, rc);
295 	rc = maxim_ds3231_get_alarm(ds3231, 1, &min_alarm);
296 	printk("Alarm 2 flags %x at %u: %d\n", min_alarm.flags,
297 	       (uint32_t)min_alarm.time, rc);
298 
299 	/* One-shot auto-disable callback in 5 s.  The handler will
300 	 * then use the base device counter API to schedule a second
301 	 * alarm 10 s later.
302 	 */
303 	sec_alarm.time = sp.rtc.tv_sec + 5;
304 	sec_alarm.flags = MAXIM_DS3231_ALARM_FLAGS_AUTODISABLE
305 			  | MAXIM_DS3231_ALARM_FLAGS_DOW;
306 	sec_alarm.handler = sec_alarm_handler;
307 	sec_alarm.user_data = &sec_alarm;
308 
309 	printk("Min Sec base time: %s\n", format_time(sec_alarm.time, -1));
310 
311 	/* Repeating callback at rollover to a new minute. */
312 	min_alarm.time = sec_alarm.time;
313 	min_alarm.flags = 0
314 			  | MAXIM_DS3231_ALARM_FLAGS_IGNDA
315 			  | MAXIM_DS3231_ALARM_FLAGS_IGNHR
316 			  | MAXIM_DS3231_ALARM_FLAGS_IGNMN
317 			  | MAXIM_DS3231_ALARM_FLAGS_IGNSE;
318 	min_alarm.handler = min_alarm_handler;
319 
320 	rc = maxim_ds3231_set_alarm(ds3231, 0, &sec_alarm);
321 	printk("Set sec alarm %x at %u ~ %s: %d\n", sec_alarm.flags,
322 	       (uint32_t)sec_alarm.time, format_time(sec_alarm.time, -1), rc);
323 
324 	rc = maxim_ds3231_set_alarm(ds3231, 1, &min_alarm);
325 	printk("Set min alarm flags %x at %u ~ %s: %d\n", min_alarm.flags,
326 	       (uint32_t)min_alarm.time, format_time(min_alarm.time, -1), rc);
327 
328 	printk("%u ms in: get alarms: %d %d\n", k_uptime_get_32(),
329 	       maxim_ds3231_get_alarm(ds3231, 0, &sec_alarm),
330 	       maxim_ds3231_get_alarm(ds3231, 1, &min_alarm));
331 	if (rc >= 0) {
332 		printk("Sec alarm flags %x at %u ~ %s\n", sec_alarm.flags,
333 		       (uint32_t)sec_alarm.time, format_time(sec_alarm.time, -1));
334 
335 		printk("Min alarm flags %x at %u ~ %s\n", min_alarm.flags,
336 		       (uint32_t)min_alarm.time, format_time(min_alarm.time, -1));
337 	}
338 
339 	k_sleep(K_FOREVER);
340 	return 0;
341 }
342