219 lines
5.6 KiB
C
219 lines
5.6 KiB
C
|
//! \file rtc.c
|
||
|
//! \author tkl
|
||
|
//! \date Jul 8, 2012
|
||
|
//! \brief Source file of the architecture independent rtc implementation.
|
||
|
#include <stddef.h>
|
||
|
#include <stdbool.h>
|
||
|
#include <string.h>
|
||
|
#include "rtc.h"
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
int rtc_open(const struct rtc *device) {
|
||
|
if(NULL == device) {
|
||
|
return (-1);
|
||
|
}
|
||
|
|
||
|
rtc_fp_open_t open = device->fp->open;
|
||
|
return (open(device->arch_dep_device));
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
int rtc_close(const struct rtc *device) {
|
||
|
if(NULL == device) {
|
||
|
return (-1);
|
||
|
}
|
||
|
|
||
|
rtc_fp_close_t close = device->fp->close;
|
||
|
return (close(device->arch_dep_device));
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void rtc_set_time(const struct rtc *device, const struct loki_time *time) {
|
||
|
if(NULL == device) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
rtc_fp_set_time_t set_time = device->fp->set_time;
|
||
|
set_time(device->arch_dep_device, time);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
struct loki_time *rtc_get_time(const struct rtc *device, struct loki_time *time) {
|
||
|
if(NULL == device) {
|
||
|
return (NULL);
|
||
|
}
|
||
|
|
||
|
rtc_fp_get_time_t get_time = device->fp->get_time;
|
||
|
return (get_time(device->arch_dep_device, time));
|
||
|
}
|
||
|
|
||
|
#ifndef __isleap
|
||
|
//! Nonzero if YEAR is a leap year (every 4 years, except every 100th isn't, and every 400th is).
|
||
|
#define __isleap(year) \
|
||
|
((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
|
||
|
#endif
|
||
|
|
||
|
//! Seconds per hour.
|
||
|
#define SECS_PER_HOUR (long)(60 * 60)
|
||
|
|
||
|
//! Seconds per day.
|
||
|
#define SECS_PER_DAY (long)(SECS_PER_HOUR * 24)
|
||
|
|
||
|
//! Clocks per sec.
|
||
|
#define CLOCKS_PER_SEC 1000
|
||
|
|
||
|
|
||
|
static const uint8_t __mon_lengths[2][12] = {
|
||
|
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, /* Normal years. */
|
||
|
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } /* Leap years. */
|
||
|
};
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
uint32_t time_to_tick(const struct loki_time *time) {
|
||
|
if(NULL == time) {
|
||
|
return (0);
|
||
|
}
|
||
|
uint32_t ret = 0;
|
||
|
uint32_t year = time->year - 1970;
|
||
|
ret = time->sec + time->min * 60 + time->hour * 3600;
|
||
|
uint32_t days_in_year = 0;
|
||
|
switch(time->mon) {
|
||
|
case 1:
|
||
|
days_in_year = time->day;
|
||
|
break;
|
||
|
case 2:
|
||
|
days_in_year = time->day + 31;
|
||
|
break;
|
||
|
case 3:
|
||
|
days_in_year = time->day + 31 + 28;
|
||
|
break;
|
||
|
case 4:
|
||
|
days_in_year = time->day + 31 + 28 + 31;
|
||
|
break;
|
||
|
case 5:
|
||
|
days_in_year = time->day + 31 + 28 + 31 + 30;
|
||
|
break;
|
||
|
case 6:
|
||
|
days_in_year = time->day + 31 + 28 + 31 + 30 + 31;
|
||
|
break;
|
||
|
case 7:
|
||
|
days_in_year = time->day + 31 + 28 + 31 + 30 + 31 + 30;
|
||
|
break;
|
||
|
case 8:
|
||
|
days_in_year = time->day + 31 + 28 + 31 + 30 + 31 + 30 + 31;
|
||
|
break;
|
||
|
case 9:
|
||
|
days_in_year = time->day + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31;
|
||
|
break;
|
||
|
case 10:
|
||
|
days_in_year = time->day + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30;
|
||
|
break;
|
||
|
case 11:
|
||
|
days_in_year = time->day + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31;
|
||
|
break;
|
||
|
case 12:
|
||
|
days_in_year = time->day + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30;
|
||
|
break;
|
||
|
}
|
||
|
if(days_in_year > 0) {
|
||
|
days_in_year--;
|
||
|
}
|
||
|
uint32_t leap_days = 0;
|
||
|
uint32_t y = time->year;
|
||
|
while(y >= 1970) {
|
||
|
leap_days += __isleap(y) ? 1 : 0;
|
||
|
y--;
|
||
|
}
|
||
|
if(__isleap(time->year)) {
|
||
|
if(days_in_year < 59) {
|
||
|
if(leap_days > 0) {
|
||
|
leap_days--;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
ret += (days_in_year + leap_days) * 60 * 60 * 24;
|
||
|
ret += (year * 60 * 60 * 24 * 365);
|
||
|
return (ret);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
struct loki_time tick_to_time(uint32_t tick) {
|
||
|
struct loki_time ret;
|
||
|
uint32_t days, rem;
|
||
|
uint32_t y;
|
||
|
char *ip;
|
||
|
|
||
|
days = tick / SECS_PER_DAY;
|
||
|
rem = tick % SECS_PER_DAY;
|
||
|
while (rem < 0) {
|
||
|
rem += SECS_PER_DAY;
|
||
|
--days;
|
||
|
}
|
||
|
while (rem >= SECS_PER_DAY) {
|
||
|
rem -= SECS_PER_DAY;
|
||
|
++days;
|
||
|
}
|
||
|
ret.hour = rem / SECS_PER_HOUR;
|
||
|
rem %= SECS_PER_HOUR;
|
||
|
ret.min = rem / 60;
|
||
|
ret.sec = rem % 60;
|
||
|
y = 1970;
|
||
|
while (days >= (rem = __isleap(y) ? 366 : 365)) {
|
||
|
++y;
|
||
|
days -= rem;
|
||
|
}
|
||
|
while (days < 0) {
|
||
|
--y;
|
||
|
days += __isleap(y) ? 366 : 365;
|
||
|
}
|
||
|
ret.year = y;
|
||
|
ip = (char *)__mon_lengths[__isleap(y)];
|
||
|
for (y = 0; days >= ip[y]; ++y)
|
||
|
days -= ip[y];
|
||
|
ret.mon = y + 1;
|
||
|
ret.day = days + 1;
|
||
|
return (ret);
|
||
|
}
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
int rtc_start_interval_event(const struct rtc *device, enum rtc_interval interval,
|
||
|
const void *callback, const void *argument) {
|
||
|
if(NULL == device) {
|
||
|
return (-1);
|
||
|
}
|
||
|
rtc_fp_start_interval_event start_interval = device->fp->start_interval;
|
||
|
return (start_interval(device->arch_dep_device, interval, callback, argument));
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
int rtc_stop_interval_event(const struct rtc *device) {
|
||
|
if(NULL == device) {
|
||
|
return (-1);
|
||
|
}
|
||
|
rtc_fp_stop_interval_event stop_interval = device->fp->stop_interval;
|
||
|
return (stop_interval(device->arch_dep_device));
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
int rtc_start_alarm_event(const struct rtc *device,
|
||
|
const struct loki_time *alarm_time, enum rtc_alarm_mask alarm_mask,
|
||
|
const void *callback, const void *argument)
|
||
|
{
|
||
|
if(NULL == device) {
|
||
|
return (-1);
|
||
|
}
|
||
|
rtc_fp_start_alarm_event start_alarm = device->fp->start_alarm;
|
||
|
return (start_alarm(device->arch_dep_device, alarm_time, alarm_mask,
|
||
|
callback, argument));
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
int rtc_stop_alarm_event(const struct rtc *device) {
|
||
|
if(NULL == device) {
|
||
|
return (-1);
|
||
|
}
|
||
|
rtc_fp_stop_alarm_event stop_alarm = device->fp->stop_alarm;
|
||
|
return (stop_alarm(device->arch_dep_device));
|
||
|
}
|