Contiki-NG
rtcc.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015, Zolertia <http://www.zolertia.com>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  *
31  */
32 /*---------------------------------------------------------------------------*/
33 /**
34  * \addtogroup remote-rtcc
35  * @{
36  *
37  * Driver for the RE-Mote RTCC (Real Time Clock Calendar)
38  * @{
39  *
40  * \file
41  * Driver for the RE-Mote RF Real Time Clock Calendar (RTCC)
42  *
43  * \author
44  *
45  * Antonio Lignan <alinan@zolertia.com>
46  * Aitor Mejias <amejias@zolertia.com>
47  * Toni Lozano <tlozano@zolertia.com>
48  */
49 /*---------------------------------------------------------------------------*/
50 #include "contiki.h"
51 #include "dev/gpio.h"
52 #include "dev/i2c.h"
53 #include "rtcc.h"
54 #include "rtcc-config.h"
55 #include "dev/leds.h"
56 #include <stdio.h>
57 /*---------------------------------------------------------------------------*/
58 #define DEBUG 0
59 #if DEBUG
60 #define PRINTF(...) printf(__VA_ARGS__)
61 #else
62 #define PRINTF(...)
63 #endif
64 /*---------------------------------------------------------------------------*/
65 #define RTC_INT1_PORT_BASE GPIO_PORT_TO_BASE(RTC_INT1_PORT)
66 #define RTC_INT1_PIN_MASK GPIO_PIN_MASK(RTC_INT1_PIN)
67 /*---------------------------------------------------------------------------*/
68 /* Callback pointers when interrupt occurs */
69 void (*rtcc_int1_callback)(uint8_t value);
70 /* -------------------------------------------------------------------------- */
71 static const char *ab080x_td_register_name[] =
72 {
73  "Mseconds",
74  "Seconds",
75  "Minutes",
76  "Hours",
77  "Days",
78  "Months",
79  "Years",
80  "Weekdays",
81 };
82 /* -------------------------------------------------------------------------- */
83 static const char *ab080x_config_register_name[] =
84 {
85  "STATUS",
86  "CTRL1",
87  "CTRL2",
88  "INTMASK",
89  "SQW",
90  "CAL_XT",
91  "CAL_RCU",
92  "CAL_RCL",
93  "INTPOL",
94  "TIMER_CTRL",
95  "TIMER_CDOWN",
96  "TIMER_INIT",
97  "WDT",
98  "OSC_CTRL",
99  "OSC_STAT",
100  "CONF_KEY",
101  "TRICKLE",
102  "BREF",
103 };
104 /*---------------------------------------------------------------------------*/
105 static uint8_t
106 bcd_to_dec(uint8_t val)
107 {
108  return (uint8_t)(((val >> 4) * 10) + (val % 16));
109 }
110 /*---------------------------------------------------------------------------*/
111 static uint8_t
112 dec_to_bcd(uint8_t val)
113 {
114  return (uint8_t)(((val / 10) << 4) + (val % 10));
115 }
116 /*---------------------------------------------------------------------------*/
117 static uint8_t
118 check_leap_year(uint8_t val)
119 {
120  return ((val % 4) && (val % 100)) || (val % 400);
121 }
122 /*---------------------------------------------------------------------------*/
123 static uint16_t
124 ab08_read_reg(uint8_t reg, uint8_t *buf, uint8_t regnum)
125 {
127  if(i2c_single_send(AB08XX_ADDR, reg) == I2C_MASTER_ERR_NONE) {
128  if(i2c_burst_receive(AB08XX_ADDR, buf, regnum) == I2C_MASTER_ERR_NONE) {
129  return AB08_SUCCESS;
130  }
131  }
132  return AB08_ERROR;
133 }
134 /*---------------------------------------------------------------------------*/
135 static int8_t
136 ab08_write_reg(uint8_t reg, uint8_t *buf, uint8_t regnum)
137 {
138  uint8_t i, buff[INT_BUFF_SIZE];
139 
140  if(regnum > (INT_BUFF_SIZE - 1)) {
141  return AB08_ERROR;
142  }
143 
144  /* FIXME: Replace by single_send/burst_send */
145 
146  buff[0] = reg;
147  for(i = 0; i < regnum; i++) {
148  buff[(i + 1)] = buf[i];
149  }
150 
152  if(i2c_burst_send(AB08XX_ADDR, buff, (regnum + 1)) == I2C_MASTER_ERR_NONE) {
153  return AB08_SUCCESS;
154  }
155 
156  return AB08_ERROR;
157 }
158 /*---------------------------------------------------------------------------*/
159 static void
160 write_default_config(void)
161 {
162  const ab080x_register_config_t *settings;
163  settings = ab080x_default_setting;
164  uint8_t i, len = (sizeof(ab080x_default_setting) / sizeof(ab080x_register_config_t));
165 
166  for(i = 0; i < len; i++) {
167  ab08_write_reg(settings[i].reg, (uint8_t *)&settings[i].val, 1);
168  }
169 }
170 /*---------------------------------------------------------------------------*/
171 static int8_t
172 ab08_key_reg(uint8_t unlock)
173 {
174  if((unlock != RTCC_CONFKEY_OSCONTROL) && (unlock != RTCC_CONFKEY_SWRESET) &&
175  (unlock != RTCC_CONFKEY_DEFREGS)) {
176  PRINTF("RTC: invalid confkey values\n");
177  return AB08_ERROR;
178  }
179 
180  if(ab08_write_reg((CONFIG_MAP_OFFSET + CONF_KEY_ADDR), &unlock, 1)) {
181  PRINTF("RTC: failed to write to confkey register\n");
182  return AB08_ERROR;
183  }
184 
185  return AB08_SUCCESS;
186 }
187 /*---------------------------------------------------------------------------*/
188 static int8_t
189 ab08_read_status(uint8_t *buf)
190 {
191  return ab08_read_reg((STATUS_ADDR + CONFIG_MAP_OFFSET), buf, 1);
192 }
193 /*---------------------------------------------------------------------------*/
194 static int8_t
195 ab08_ctrl1_config(uint8_t cmd)
196 {
197  uint8_t ctrl1 = 0;
198 
199  if(cmd >= RTCC_CMD_MAX) {
200  return AB08_ERROR;
201  }
202 
203  if(ab08_read_reg((CONFIG_MAP_OFFSET + CTRL_1_ADDR), &ctrl1, 1)) {
204  PRINTF("RTC: failed to retrieve CTRL1 register\n");
205  return AB08_ERROR;
206  }
207 
208  switch(cmd) {
209  case RTCC_CMD_LOCK:
210  ctrl1 &= ~CTRL1_WRTC;
211  break;
212  case RTCC_CMD_UNLOCK:
213  ctrl1 |= CTRL1_WRTC;
214  break;
215  case RTCC_CMD_ENABLE:
216  ctrl1 &= ~CTRL1_STOP;
217  break;
218  case RTCC_CMD_STOP:
219  ctrl1 |= CTRL1_STOP;
220  break;
221  default:
222  return AB08_ERROR;
223  }
224 
225  if(ab08_write_reg((CONFIG_MAP_OFFSET + CTRL_1_ADDR),
226  &ctrl1, 1) == AB08_ERROR) {
227  PRINTF("RTC: failed to write to the CTRL1 register\n");
228  return AB08_ERROR;
229  }
230 
231  return AB08_SUCCESS;
232 }
233 /*---------------------------------------------------------------------------*/
234 static int8_t
235 ab08_check_td_format(simple_td_map *data, uint8_t alarm_state)
236 {
237  /* Using fixed values as these are self-indicative of the variable */
238  if((data->seconds > 59) || (data->minutes > 59) || (data->hours > 23)) {
239  return AB08_ERROR;
240  }
241 
242  if((data->months > 12) || (data->weekdays > 7) || (data->day > 31)) {
243  return AB08_ERROR;
244  }
245 
246  /* Fixed condition for February (month 2) */
247  if(data->months == 2) {
248  if(check_leap_year(data->years)) {
249  if(data->day > 29) {
250  return AB08_ERROR;
251  }
252  } else {
253  if(data->day > 28) {
254  return AB08_ERROR;
255  }
256  }
257  }
258 
259  /* Alarm doesn't care about year */
260  if(!alarm_state) {
261  /* AB08X5 Real-Time Clock Family, page 55 (year up to 2199) */
262  if(data->years > 199) {
263  return AB08_ERROR;
264  }
265  }
266 
267  return AB08_SUCCESS;
268 }
269 /*---------------------------------------------------------------------------*/
270 int8_t
271 rtcc_set_time_date(simple_td_map *data)
272 {
273  uint8_t aux = 0;
274  uint8_t rtc_buffer[RTCC_TD_MAP_SIZE];
275 
276  if(ab08_check_td_format(data, 0) == AB08_ERROR) {
277  PRINTF("RTC: Invalid time/date values\n");
278  return AB08_ERROR;
279  }
280 
281  if(ab08_read_reg((CTRL_1_ADDR + CONFIG_MAP_OFFSET),
282  &aux, 1) == AB08_ERROR) {
283  PRINTF("RTC: failed to retrieve CONTROL1 register\n");
284  return AB08_ERROR;
285  }
286 
287  rtc_buffer[WEEKDAYLS_ADDR] = dec_to_bcd(data->weekdays);
288  rtc_buffer[YEAR_ADDR] = dec_to_bcd(data->years);
289  rtc_buffer[MONTHS_ADDR] = dec_to_bcd(data->months);
290  rtc_buffer[DAY_ADDR] = dec_to_bcd(data->day);
291  rtc_buffer[HOUR_ADDR] = dec_to_bcd(data->hours);
292  rtc_buffer[MIN_ADDR] = dec_to_bcd(data->minutes);
293  rtc_buffer[SEC_ADDR] = dec_to_bcd(data->seconds);
294  rtc_buffer[CENTHS_ADDR] = dec_to_bcd(data->miliseconds);
295 
296  /* Check if we are to set the time in 12h/24h format */
297  if(data->mode == RTCC_24H_MODE) {
298  aux &= ~CTRL1_1224;
299  } else {
300  if((data->hours == 0) || (data->hours > 12)) {
301  PRINTF("RTC: Invalid hour configuration (12h mode selected)\n");
302  return AB08_ERROR;
303  }
304  aux |= CTRL1_1224;
305  if(data->mode == RTCC_12H_MODE_PM) {
306  /* Toggle bit for PM */
307  rtc_buffer[HOUR_ADDR] |= RTCC_TOGGLE_PM_BIT;
308  } else {
309  PRINTF("RTC: Invalid time mode selected\n");
310  return AB08_ERROR;
311  }
312  }
313 
314  /* Write the 12h/24h config */
315  if(ab08_write_reg((CTRL_1_ADDR + CONFIG_MAP_OFFSET),
316  &aux, 1) == AB08_ERROR) {
317  PRINTF("RTC: failed to write 12h/24h configuration\n");
318  return AB08_ERROR;
319  }
320 
321  /* Reading the STATUS register with the CONTROL1.ARST set will clear the
322  * interrupt flags, we write directly to the register without caring its
323  * actual status and let the interrupt handler take care of any pending flag
324  */
325 
326  if(ab08_read_reg((STATUS_ADDR + CONFIG_MAP_OFFSET), &aux, 1) == AB08_ERROR) {
327  PRINTF("RTC: failed to retrieve STATUS register\n");
328  return AB08_ERROR;
329  }
330 
331  if(data->century == RTCC_CENTURY_20XX) {
332  aux |= STATUS_CB;
333  } else if(data->century == RTCC_CENTURY_19XX_21XX) {
334  aux |= ~STATUS_CB;
335  } else {
336  PRINTF("RTC: invalid century value\n");
337  return AB08_ERROR;
338  }
339 
340  PRINTF("RTC: current STATUS value 0x%02X\n", aux);
341 
342  if(ab08_write_reg((STATUS_ADDR + CONFIG_MAP_OFFSET), &aux, 1) == AB08_ERROR) {
343  PRINTF("RTC: failed to write century to STATUS register\n");
344  return AB08_ERROR;
345  }
346 
347  /* Set the WRTC bit to enable writting to the counters */
348  if(ab08_ctrl1_config(RTCC_CMD_UNLOCK) == AB08_ERROR) {
349  return AB08_ERROR;
350  }
351 
352  /* Write the buffers but the mode and century fields (used only for config) */
353  if(ab08_write_reg(CENTHS_ADDR, rtc_buffer,
354  RTCC_TD_MAP_SIZE) == AB08_ERROR) {
355  PRINTF("RTC: failed to write date configuration\n");
356  return AB08_ERROR;
357  }
358 
359  /* Lock the RTCC and return */
360  if(ab08_ctrl1_config(RTCC_CMD_LOCK) == AB08_ERROR) {
361  return AB08_ERROR;
362  }
363 
364  return AB08_SUCCESS;
365 }
366 /*---------------------------------------------------------------------------*/
367 int8_t
368 rtcc_get_time_date(simple_td_map *data)
369 {
370  uint8_t rtc_buffer[RTCC_TD_MAP_SIZE];
371 
372  if(ab08_read_reg(CENTHS_ADDR, rtc_buffer,
373  RTCC_TD_MAP_SIZE) == AB08_ERROR) {
374  PRINTF("RTC: failed to retrieve date and time values\n");
375  return AB08_ERROR;
376  }
377 
378  data->weekdays = bcd_to_dec(rtc_buffer[WEEKDAYLS_ADDR]);
379  data->years = bcd_to_dec(rtc_buffer[YEAR_ADDR]);
380  data->months = bcd_to_dec(rtc_buffer[MONTHS_ADDR]);
381  data->day = bcd_to_dec(rtc_buffer[DAY_ADDR]);
382  data->hours = bcd_to_dec(rtc_buffer[HOUR_ADDR]);
383  data->minutes = bcd_to_dec(rtc_buffer[MIN_ADDR]);
384  data->seconds = bcd_to_dec(rtc_buffer[SEC_ADDR]);
385  data->miliseconds = bcd_to_dec(rtc_buffer[CENTHS_ADDR]);
386 
387  return AB08_SUCCESS;
388 }
389 /*---------------------------------------------------------------------------*/
390 int8_t
391 rtcc_set_alarm_time_date(simple_td_map *data, uint8_t state, uint8_t repeat,
392  uint8_t trigger)
393 {
394  uint8_t aux[4], buf[RTCC_ALARM_MAP_SIZE];
395 
396  if((trigger != RTCC_TRIGGER_INT2) && (trigger != RTCC_TRIGGER_INT1) &&
397  (trigger != RTCC_TRIGGER_BOTH)) {
398  PRINTF("RTC: invalid trigger pin\n");
399  return AB08_ERROR;
400  }
401 
402  if(state == RTCC_ALARM_OFF) {
403  if(ab08_read_reg((INT_MASK_ADDR + CONFIG_MAP_OFFSET),
404  &aux[0], 1) == AB08_ERROR) {
405  PRINTF("RTC: failed to retrieve INTMASK register\n");
406  return AB08_ERROR;
407  }
408 
409  aux[0] &= ~INTMASK_AIE;
410 
411  if(ab08_write_reg((INT_MASK_ADDR + CONFIG_MAP_OFFSET),
412  &aux[0], 1) == AB08_ERROR) {
413  PRINTF("RTC: failed to clear the alarm config\n");
414  return AB08_ERROR;
415  }
416  return AB08_SUCCESS;
417  }
418 
419  if((data == NULL) || (ab08_check_td_format(data, 1) == AB08_ERROR)) {
420  PRINTF("RTC: invalid alarm values\n");
421  return AB08_ERROR;
422  }
423 
424  if((state >= RTCC_ALARM_MAX) || (repeat >= RTCC_REPEAT_100THS)) {
425  PRINTF("RTC: invalid alarm config type or state\n");
426  return AB08_ERROR;
427  }
428 
429  /* Stop the RTCC */
430  ab08_ctrl1_config(RTCC_CMD_STOP);
431 
432  buf[WEEKDAYS_ALARM_ADDR] = dec_to_bcd(data->weekdays);
433  buf[MONTHS_ALARM_ADDR] = dec_to_bcd(data->months);
434  buf[DAY_ALARMS_ADDR] = dec_to_bcd(data->day);
435  buf[HOURS_ALARM_ADDR] = dec_to_bcd(data->hours);
436  buf[MINUTES_ALARM_ADDR] = dec_to_bcd(data->minutes);
437  buf[SECONDS_ALARM_ADDR] = dec_to_bcd(data->seconds);
438  buf[HUNDREDTHS_ALARM_ADDR] = dec_to_bcd(data->miliseconds);
439 
440  /* Check if the 12h/24h match the current configuration */
441  if(ab08_read_reg((CTRL_1_ADDR + CONFIG_MAP_OFFSET),
442  &aux[0], 1) == AB08_ERROR) {
443  PRINTF("RTC: failed to retrieve CONTROL1 register\n");
444  return AB08_ERROR;
445  }
446 
447  if(((aux[0] & CTRL1_1224) && (data->mode == RTCC_24H_MODE)) ||
448  (!(aux[0] & CTRL1_1224) && ((data->mode == RTCC_12H_MODE_AM) ||
449  (data->mode == RTCC_12H_MODE_PM)))) {
450  PRINTF("RTC: 12/24h mode and present date config mismatch\n");
451  return AB08_ERROR;
452  }
453 
454  if(data->mode != RTCC_24H_MODE) {
455  if((data->hours == 0) || (data->hours > 12)) {
456  PRINTF("RTC: Invalid hour configuration (12h mode selected)\n");
457  return AB08_ERROR;
458  }
459 
460  /* Toggle the PM bit */
461  if(data->mode == RTCC_12H_MODE_PM) {
462  buf[HOURS_ALARM_ADDR] |= RTCC_TOGGLE_PM_BIT;
463  }
464  }
465 
466  /* Clear the RPT field */
467  if(ab08_read_reg((TIMER_CONTROL_ADDR + CONFIG_MAP_OFFSET),
468  &aux[0], 1) == AB08_ERROR) {
469  PRINTF("RTC: failed to retrieve TIMER CTRL register\n");
470  return AB08_ERROR;
471  }
472 
473  aux[0] &= ~COUNTDOWN_TIMER_RPT_SECOND;
474 
475  /* AB08XX application manual, table 76 */
476  if(repeat == RTCC_REPEAT_10THS) {
477  buf[HUNDREDTHS_ALARM_ADDR] |= RTCC_FIX_10THS_HUNDRETHS;
478  repeat = RTCC_REPEAT_SECOND;
479  } else if(repeat == RTCC_REPEAT_100THS) {
480  buf[HUNDREDTHS_ALARM_ADDR] |= RTCC_FIX_100THS_HUNDRETHS;
481  repeat = RTCC_REPEAT_SECOND;
482  }
483 
484  if(repeat != RTCC_REPEAT_NONE) {
485  aux[0] |= (repeat << COUNTDOWN_TIMER_RPT_SHIFT);
486  }
487 
488  /* We are using as default the level interrupt instead of pulses */
489  /* FIXME: make this selectable */
490  aux[0] |= COUNTDOWN_TIMER_TM;
491  aux[0] &= ~COUNTDOWN_TIMER_TRPT;
492 
493  if(ab08_write_reg((TIMER_CONTROL_ADDR + CONFIG_MAP_OFFSET),
494  &aux[0], 1) == AB08_ERROR) {
495  PRINTF("RTC: failed to clear the alarm config\n");
496  return AB08_ERROR;
497  }
498 
499  if(ab08_read_reg((STATUS_ADDR + CONFIG_MAP_OFFSET),
500  aux, 4) == AB08_ERROR) {
501  PRINTF("RTC: failed to read configuration registers\n");
502  return AB08_ERROR;
503  }
504 
505  /* Clear ALM field if any */
506  aux[STATUS_ADDR] &= ~STATUS_ALM;
507 
508 #if RTCC_CLEAR_INT_MANUALLY
509  aux[CTRL_1_ADDR] &= ~CTRL1_ARST;
510 #endif
511 
512  /* Clear the AIE alarm bit */
513  aux[INT_MASK_ADDR] &= ~INTMASK_AIE;
514 
515  /* Configure Interrupt parameters for Alarm Interrupt Mode in nIRQ
516  * or nAIRQ pins and fixed level until interrupt flag is cleared
517  * RTC_INT1 is connected to the CC2538
518  * RTC_INT2 is connected to the power management PIC in revision B
519  */
520  if (trigger == RTCC_TRIGGER_INT2) {
521  aux[CTRL_2_ADDR] |= CTRL2_OUT2S_NAIRQ_OUTB;
522  /* Only options left enable the INT1 interrupt pin */
523  } else {
524  GPIO_ENABLE_INTERRUPT(RTC_INT1_PORT_BASE, RTC_INT1_PIN_MASK);
525  ioc_set_over(RTC_INT1_PORT, RTC_INT1_PIN, IOC_OVERRIDE_PUE);
526  NVIC_EnableIRQ(RTC_INT1_VECTOR);
527  }
528 
529  if (trigger == RTCC_TRIGGER_INT1) {
530  aux[CTRL_2_ADDR] |= CTRL2_OUT1S_NIRQ_NAIRQ_OUT;
531  } else if (trigger == RTCC_TRIGGER_BOTH) {
532  aux[CTRL_2_ADDR] |= (CTRL2_OUT1S_NIRQ_NAIRQ_OUT + CTRL2_OUT2S_NAIRQ_OUTB);
533  }
534 
535  if(repeat != RTCC_REPEAT_NONE) {
536  aux[INT_MASK_ADDR] &= ~INTMASK_IM_LOW;
537  } else {
538  aux[INT_MASK_ADDR] |= INTMASK_IM_LOW;
539  }
540 
541  if(ab08_write_reg((STATUS_ADDR + CONFIG_MAP_OFFSET), aux, 4) == AB08_ERROR) {
542  PRINTF("RTC: failed to clear alarm config\n");
543  return AB08_ERROR;
544  }
545 
546  /* Write to the alarm counters */
547  if(ab08_write_reg((HUNDREDTHS_ALARM_ADDR + ALARM_MAP_OFFSET), buf,
548  RTCC_ALARM_MAP_SIZE) == AB08_ERROR) {
549  PRINTF("RTC: failed to set the alarm\n");
550  return AB08_ERROR;
551  }
552 
553  /* And finally enable the AIE bit */
554  aux[INT_MASK_ADDR] |= INTMASK_AIE;
555  if(ab08_write_reg((INT_MASK_ADDR + CONFIG_MAP_OFFSET),
556  &aux[INT_MASK_ADDR], 1) == AB08_ERROR) {
557  PRINTF("RTC: failed to enable the alarm\n");
558  return AB08_ERROR;
559  }
560 
561  /* Enable back the RTCC */
562  ab08_ctrl1_config(RTCC_CMD_ENABLE);
563 
564  return AB08_SUCCESS;
565 }
566 /*---------------------------------------------------------------------------*/
567 int8_t
568 rtcc_date_increment_seconds(simple_td_map *data, uint16_t seconds)
569 {
570  uint16_t aux;
571 
572  if(data == NULL) {
573  PRINTF("RTC: invalid argument\n");
574  return AB08_ERROR;
575  }
576 
577  if(rtcc_get_time_date(data) == AB08_ERROR) {
578  return AB08_ERROR;
579  }
580 
581  /* Nothing to do here but congratulate the user */
582  if(!seconds) {
583  return AB08_SUCCESS;
584  }
585 
586  aux = data->seconds + seconds;
587  data->seconds = (uint8_t)(aux % 60);
588 
589  /* Add the remainder seconds to the minutes counter */
590  if(aux > 59) {
591  aux /= 60;
592  aux += data->minutes;
593  data->minutes = (uint8_t)(aux % 60);
594  }
595 
596  /* Add the remainder minutes to the hours counter */
597  if(aux > 59) {
598  aux /= 60;
599  aux += data->hours;
600  data->hours = (uint8_t)(aux % 24);
601  }
602 
603  if(aux > 23) {
604  aux /= 24;
605  aux += data->day;
606 
607  if(data->months == 2) {
608  if(check_leap_year(data->years)) {
609  if(aux > 29) {
610  data->day = (uint8_t)(aux % 29);
611  data->months++;
612  }
613  } else if(aux > 28) {
614  data->day = (uint8_t)(aux % 28);
615  data->months++;
616  }
617  } else if((data->months == 4) || (data->months == 6) ||
618  (data->months == 9) || (data->months == 11)) {
619  if(aux > 30) {
620  data->day = (uint8_t)(aux % 30);
621  data->months++;
622  }
623  } else if(aux > 31) {
624  data->day = (uint8_t)(aux % 31);
625  data->months++;
626  }
627  }
628 
629  if(data->months > 12) {
630  data->months = data->months % 12;
631  data->years++;
632  }
633  return AB08_SUCCESS;
634 }
635 /*---------------------------------------------------------------------------*/
636 PROCESS(rtcc_int_process, "RTCC interruption process handler");
637 /*---------------------------------------------------------------------------*/
638 PROCESS_THREAD(rtcc_int_process, ev, data)
639 {
640  static uint8_t buf;
642  PROCESS_BEGIN();
643  while(1) {
644  PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
645 
646  if(ab08_read_status(&buf) == AB08_ERROR) {
647  PRINTF("RTC: failed to retrieve ARST value\n");
648  PROCESS_EXIT();
649  }
650 
651  /* We only handle the AIE (alarm interrupt) only */
652  if((buf & STATUS_ALM) && (rtcc_int1_callback != NULL)) {
653 #if RTCC_CLEAR_INT_MANUALLY
654  buf &= ~STATUS_ALM;
655  if(ab08_write_reg((STATUS_ADDR + CONFIG_MAP_OFFSET),
656  &buf, 1) == AB08_ERROR) {
657  PRINTF("RTC: failed to clear the alarm\n");
658  return AB08_ERROR;
659  }
660 #endif
661  rtcc_int1_callback(0);
662  }
663  }
664  PROCESS_END();
665 }
666 /*---------------------------------------------------------------------------*/
667 int8_t
668 rtcc_print(uint8_t value)
669 {
670  uint8_t i, len, reg;
671  char **name;
672  uint8_t rtc_buffer[RTCC_CONFIG_MAP_SIZE];
673 
674  if(value >= RTCC_PRINT_MAX) {
675  return AB08_ERROR;
676  }
677 
678  switch(value) {
679  case RTCC_PRINT_CONFIG:
680  len = (RTCC_CONFIG_MAP_SIZE - 1);
681  reg = STATUS_ADDR + CONFIG_MAP_OFFSET;
682  name = (char **)ab080x_config_register_name;
683  break;
684  case RTCC_PRINT_ALARM:
685  case RTCC_PRINT_ALARM_DEC:
686  len = RTCC_ALARM_MAP_SIZE;
687  reg = HUNDREDTHS_ALARM_ADDR + ALARM_MAP_OFFSET;
688  name = (char **)ab080x_td_register_name;
689  break;
690  case RTCC_PRINT_DATE:
691  case RTCC_PRINT_DATE_DEC:
692  len = RTCC_TD_MAP_SIZE;
693  reg = CENTHS_ADDR;
694  name = (char **)ab080x_td_register_name;
695  break;
696  default:
697  return AB08_ERROR;
698  }
699 
700  if(ab08_read_reg(reg, rtc_buffer, len) == AB08_ERROR) {
701  PRINTF("RTC: failed to retrieve values to print\n");
702  return AB08_ERROR;
703  }
704 
705  if(value == RTCC_PRINT_ALARM_DEC) {
706  printf("%02u/%02u (%02u) %02u:%02u:%02u/%02u\n",
707  bcd_to_dec(rtc_buffer[MONTHS_ALARM_ADDR]),
708  bcd_to_dec(rtc_buffer[DAY_ALARMS_ADDR]),
709  bcd_to_dec(rtc_buffer[WEEKDAYS_ALARM_ADDR]),
710  bcd_to_dec(rtc_buffer[HOURS_ALARM_ADDR]),
711  bcd_to_dec(rtc_buffer[MINUTES_ALARM_ADDR]),
712  bcd_to_dec(rtc_buffer[SECONDS_ALARM_ADDR]),
713  bcd_to_dec(rtc_buffer[HUNDREDTHS_ALARM_ADDR]));
714  return AB08_SUCCESS;
715  }
716 
717  if(value == RTCC_PRINT_DATE_DEC) {
718  printf("%02u/%02u/%02u (%02u) %02u:%02u:%02u/%02u\n",
719  bcd_to_dec(rtc_buffer[YEAR_ADDR]),
720  bcd_to_dec(rtc_buffer[MONTHS_ADDR]),
721  bcd_to_dec(rtc_buffer[DAY_ADDR]),
722  bcd_to_dec(rtc_buffer[WEEKDAYLS_ADDR]),
723  bcd_to_dec(rtc_buffer[HOUR_ADDR]),
724  bcd_to_dec(rtc_buffer[MIN_ADDR]),
725  bcd_to_dec(rtc_buffer[SEC_ADDR]),
726  bcd_to_dec(rtc_buffer[CENTHS_ADDR]));
727  return AB08_SUCCESS;
728  }
729 
730  for(i = 0; i < len; i++) {
731  printf("0x%02X <- %s\n", rtc_buffer[i], name[i]);
732  }
733 
734  return AB08_SUCCESS;
735 }
736 /*---------------------------------------------------------------------------*/
737 static void
738 rtcc_interrupt_handler(gpio_hal_pin_mask_t pin_mask)
739 {
740  process_poll(&rtcc_int_process);
741 }
742 /*---------------------------------------------------------------------------*/
743 int8_t
745 {
746  uint8_t aux;
747 
748  if(period > RTCC_AUTOCAL_9_MIN) {
749  PRINTF("RTC: invalid autocal value\n");
750  return AB08_ERROR;
751  }
752 
753  if(ab08_read_reg((OSC_CONTROL_ADDR + CONFIG_MAP_OFFSET),
754  &aux, 1) == AB08_ERROR) {
755  PRINTF("RTC: failed to read oscillator registers\n");
756  return AB08_ERROR;
757  }
758 
759  /* Clear ACAL */
760  aux &= ~OSCONTROL_ACAL_9_MIN;
761 
762  /* Unlock the key register */
763  ab08_key_reg(RTCC_CONFKEY_OSCONTROL);
764 
765  switch(period) {
766  case RTCC_AUTOCAL_DISABLE:
767  break;
768  case RTCC_AUTOCAL_ONCE:
769  case RTCC_AUTOCAL_17_MIN:
770  aux |= OSCONTROL_ACAL_17_MIN;
771  break;
772  case RTCC_AUTOCAL_9_MIN:
773  aux |= OSCONTROL_ACAL_9_MIN;
774  break;
775  default:
776  return AB08_ERROR;
777  }
778 
779  if(ab08_write_reg((OSC_CONTROL_ADDR + CONFIG_MAP_OFFSET),
780  &aux, 1) == AB08_ERROR) {
781  PRINTF("RTC: failed to clear the autocalibration\n");
782  return AB08_ERROR;
783  }
784 
785  if(period == RTCC_AUTOCAL_ONCE) {
786  clock_delay_usec(10000);
787  ab08_key_reg(RTCC_CONFKEY_OSCONTROL);
788  aux &= ~OSCONTROL_ACAL_9_MIN;
789  if(ab08_write_reg((OSC_CONTROL_ADDR + CONFIG_MAP_OFFSET),
790  &aux, 1) == AB08_ERROR) {
791  PRINTF("RTC: failed to clear the autocalibration\n");
792  return AB08_ERROR;
793  }
794  }
795 
796  return AB08_SUCCESS;
797 }
798 /*---------------------------------------------------------------------------*/
799 int8_t
800 rtcc_set_calibration(uint8_t mode, int32_t adjust)
801 {
802  int32_t adjint;
803  uint8_t adjreg[2];
804  uint8_t xtcal;
805 
806  if(mode > RTCC_CAL_RC_OSC) {
807  PRINTF("RTC: invalid calibration mode\n");
808  return AB08_ERROR;
809  }
810 
811  /* Fixed values dependant on the oscillator source (Application Manual) */
812  if((mode == RTCC_CAL_XT_OSC) && ((adjust <= -610) || (adjust >= 242))) {
813  PRINTF("RTC: invalid adjust value for XT oscillator\n");
814  return AB08_ERROR;
815  }
816 
817  if((mode == RTCC_CAL_RC_OSC) && ((adjust <= -65536) || (adjust >= 65520))) {
818  PRINTF("RTC: invalid adjust value for XT oscillator\n");
819  return AB08_ERROR;
820  }
821 
822  /* Calibration routine taken from the Application manual */
823  if(adjust < 0) {
824  adjint = ((adjust) * 1000 - 953);
825  } else {
826  adjint = ((adjust) * 1000 + 953);
827  }
828 
829  adjint = adjint / 1907;
830 
831  if(mode == RTCC_CAL_XT_OSC) {
832  if(adjint > 63) {
833  xtcal = 0;
834  /* CMDX = 1 */
835  adjreg[0] = ((adjint >> 1) & 0x3F) | 0x80;
836  } else if(adjint > -65) {
837  xtcal = 0;
838  adjreg[0] = (adjint & 0x7F);
839  } else if(adjint > -129) {
840  xtcal = 1;
841  adjreg[0] = ((adjint + 64) & 0x7F);
842  } else if(adjint > -193) {
843  xtcal = 2;
844  adjreg[0] = ((adjint + 128) & 0x7F);
845  } else if(adjint > -257) {
846  xtcal = 3;
847  adjreg[0] = ((adjint + 192) & 0x7F);
848  } else {
849  xtcal = 3;
850  adjreg[0] = ((adjint + 192) >> 1) & 0xFF;
851  }
852 
853  if(ab08_write_reg((CAL_XT_ADDR + CONFIG_MAP_OFFSET),
854  &adjreg[0], 1) == AB08_ERROR) {
855  PRINTF("RTC: failed to clear the autocalibration\n");
856  return AB08_ERROR;
857  }
858 
859  if(ab08_read_reg((OSC_STATUS_ADDR + CONFIG_MAP_OFFSET),
860  &adjreg[0], 1) == AB08_ERROR) {
861  PRINTF("RTC: failed to read oscillator registers\n");
862  return AB08_ERROR;
863  }
864 
865  /* Clear XTCAL and write new value */
866  adjreg[0] &= 0x3F;
867  adjreg[0] |= (xtcal << 6);
868 
869  if(ab08_write_reg((OSC_STATUS_ADDR + CONFIG_MAP_OFFSET),
870  &adjreg[0], 1) == AB08_ERROR) {
871  PRINTF("RTC: failed to clear the autocalibration\n");
872  return AB08_ERROR;
873  }
874  } else if(mode == RTCC_CAL_RC_OSC) {
875  if(adjint > 32767) {
876  adjreg[1] = ((adjint >> 3) & 0xFF);
877  adjreg[0] = ((adjint >> 11) | 0xC0);
878  } else if(adjint > 16383) {
879  adjreg[1] = ((adjint >> 2) & 0xFF);
880  adjreg[0] = ((adjint >> 10) | 0x80);
881  } else if(adjint > 8191) {
882  adjreg[1] = ((adjint >> 1) & 0xFF);
883  adjreg[0] = ((adjint >> 9) | 0x40);
884  } else if(adjint >= 0) {
885  adjreg[1] = ((adjint) & 0xFF);
886  adjreg[0] = (adjint >> 8);
887  } else if(adjint > -8193) {
888  adjreg[1] = ((adjint) & 0xFF);
889  adjreg[0] = (adjint >> 8) & 0x3F;
890  } else if(adjint > -16385) {
891  adjreg[1] = ((adjint >> 1) & 0xFF);
892  adjreg[0] = (adjint >> 9) & 0x7F;
893  } else if(adjint > -32769) {
894  adjreg[1] = ((adjint >> 2) & 0xFF);
895  adjreg[0] = (adjint >> 10) & 0xBF;
896  } else {
897  adjreg[1] = ((adjint >> 3) & 0xFF);
898  adjreg[0] = (adjint >> 11) & 0xFF;
899  }
900 
901  if(ab08_write_reg((CAL_RC_HI_ADDR + CONFIG_MAP_OFFSET),
902  adjreg, 2) == AB08_ERROR) {
903  PRINTF("RTC: failed to set the RC calibration\n");
904  return AB08_ERROR;
905  }
906 
907  /* This should not happen */
908  } else {
909  return AB08_ERROR;
910  }
911 
912  return AB08_SUCCESS;
913 }
914 /*---------------------------------------------------------------------------*/
915 static gpio_hal_event_handler_t rtcc_handler = {
916  .next = NULL,
917  .handler = rtcc_interrupt_handler,
918  .pin_mask = gpio_hal_pin_to_mask(RTC_INT1_PIN) << (RTC_INT1_PORT << 3),
919 };
920 /*---------------------------------------------------------------------------*/
921 int8_t
923 {
924  i2c_init(I2C_SDA_PORT, I2C_SDA_PIN, I2C_SCL_PORT, I2C_SCL_PIN,
925  I2C_SCL_NORMAL_BUS_SPEED);
926 
927 #if RTCC_SET_DEFAULT_CONFIG
928  write_default_config();
929 #endif
930 
931 #if RTCC_SET_AUTOCAL
932  rtcc_set_autocalibration(RTCC_AUTOCAL_17_MIN);
933 #endif
934 
935  /* Initialize interrupts handlers */
936  rtcc_int1_callback = NULL;
937 
938  /* Configure the interrupts pins */
939  GPIO_SOFTWARE_CONTROL(RTC_INT1_PORT_BASE, RTC_INT1_PIN_MASK);
940  GPIO_SET_INPUT(RTC_INT1_PORT_BASE, RTC_INT1_PIN_MASK);
941 
942  /* Pull-up resistor, detect falling edge */
943  GPIO_DETECT_EDGE(RTC_INT1_PORT_BASE, RTC_INT1_PIN_MASK);
944  GPIO_TRIGGER_SINGLE_EDGE(RTC_INT1_PORT_BASE, RTC_INT1_PIN_MASK);
945  GPIO_DETECT_FALLING(RTC_INT1_PORT_BASE, RTC_INT1_PIN_MASK);
946  gpio_hal_register_handler(&rtcc_handler);
947 
948  /* Spin process until an interrupt is received */
949  process_start(&rtcc_int_process, NULL);
950 
951  return AB08_SUCCESS;
952 }
953 /*---------------------------------------------------------------------------*/
954 /**
955  * @}
956  * @}
957  */
958 
Datatype for GPIO event handlers.
Definition: gpio-hal.h:180
#define GPIO_ENABLE_INTERRUPT(PORT_BASE, PIN_MASK)
Enable interrupt triggering for pins with PIN_MASK of port with PORT_BASE.
Definition: gpio.h:201
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
int8_t rtcc_date_increment_seconds(simple_td_map *data, uint16_t seconds)
Increments the current date by a number of seconds.
Definition: rtcc.c:568
uint8_t i2c_burst_send(uint8_t slave_addr, uint8_t *data, uint8_t len)
Perform all operations to send multiple bytes to a slave.
Definition: i2c.c:188
RTCC configuration file.
#define PROCESS_YIELD_UNTIL(c)
Yield the currently running process until a condition occurs.
Definition: process.h:178
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
Header file with register and macro declarations for the cc2538 GPIO module.
#define GPIO_DETECT_EDGE(PORT_BASE, PIN_MASK)
Set pins with PIN_MASK of port with PORT_BASE to detect edge.
Definition: gpio.h:154
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
int8_t rtcc_set_alarm_time_date(simple_td_map *data, uint8_t state, uint8_t repeat, uint8_t trigger)
Configure the RTCC to match an alarm counter.
Definition: rtcc.c:391
void clock_delay_usec(uint16_t dt)
Delay a given number of microseconds.
Definition: clock.c:150
int8_t rtcc_set_autocalibration(uint8_t period)
Set the autocallibration period.
Definition: rtcc.c:744
int8_t rtcc_get_time_date(simple_td_map *data)
Get the current time and date.
Definition: rtcc.c:368
#define GPIO_DETECT_FALLING(PORT_BASE, PIN_MASK)
Set pins with PIN_MASK of port with PORT_BASE to trigger an interrupt on falling edge.
Definition: gpio.h:193
void gpio_hal_register_handler(gpio_hal_event_handler_t *handler)
Register a function to be called whenever a pin triggers an event.
Definition: gpio-hal.c:55
#define GPIO_SOFTWARE_CONTROL(PORT_BASE, PIN_MASK)
Configure the pin to be software controlled with PIN_MASK of port with PORT_BASE. ...
Definition: gpio.h:258
#define PROCESS_EXITHANDLER(handler)
Specify an action when a process exits.
Definition: process.h:254
void i2c_init(uint8_t port_sda, uint8_t pin_sda, uint8_t port_scl, uint8_t pin_scl, uint32_t bus_speed)
Initialize the I2C peripheral and pins.
Definition: i2c.c:49
void process_poll(struct process *p)
Request a process to be polled.
Definition: process.c:371
int8_t rtcc_init(void)
Initialize the RTCC, configures the I2C bus, interrupts and registers.
Definition: rtcc.c:922
void ioc_set_over(uint8_t port, uint8_t pin, uint8_t over)
Set Port:Pin override function.
Definition: ioc.c:54
int8_t rtcc_print(uint8_t value)
Print data from the RTCC module, either from the memory map (values in BCD) or actual readable data (...
Definition: rtcc.c:668
#define GPIO_SET_INPUT(PORT_BASE, PIN_MASK)
Set pins with PIN_MASK of port with PORT_BASE to input.
Definition: gpio.h:78
Header file for the RE-Mote RF antenna switch.
uint8_t i2c_burst_receive(uint8_t slave_addr, uint8_t *data, uint8_t len)
Perform all operations to receive multiple bytes from a slave.
Definition: i2c.c:218
uint32_t gpio_hal_pin_mask_t
GPIO pin mask representation.
Definition: gpio-hal.h:142
#define IOC_OVERRIDE_PUE
Pull Up Enable.
Definition: ioc.h:223
int8_t rtcc_set_calibration(uint8_t mode, int32_t adjust)
Manually calibrate the RTCC.
Definition: rtcc.c:800
#define GPIO_TRIGGER_SINGLE_EDGE(PORT_BASE, PIN_MASK)
Set pins with PIN_MASK of port with PORT_BASE to trigger an interrupt on single edge (controlled by G...
Definition: gpio.h:177
PROCESS_THREAD(cc2538_rf_process, ev, data)
Implementation of the cc2538 RF driver process.
Definition: cc2538-rf.c:1110
#define gpio_hal_pin_to_mask(pin)
Convert a pin to a pin mask.
Definition: gpio-hal.h:255
Header file for the LED HAL.
int8_t rtcc_set_time_date(simple_td_map *data)
Set the time and date.
Definition: rtcc.c:271
uint8_t i2c_single_send(uint8_t slave_addr, uint8_t data)
Perform all operations to send a byte to a slave.
Definition: i2c.c:159
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99
void i2c_master_enable(void)
Enable master I2C module.
Definition: i2c.c:91
#define PROCESS_EXIT()
Exit the currently running process.
Definition: process.h:200