drv_rtc.c 3.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2021-04-13     armink       the first version
 */

#include <sys/time.h>
#include <string.h>
#include <rtthread.h>
#include <rtdevice.h>

#ifdef RT_USING_RTC

static struct rt_device rtc_dev;

#ifdef RT_USING_ALARM

static struct rt_rtc_wkalarm wkalarm;
static struct rt_timer alarm_time;

static void alarm_timeout(void *param)
{
    rt_alarm_update(param, 1);
}

static void soft_rtc_alarm_update(struct rt_rtc_wkalarm *palarm)
{
    rt_tick_t next_tick;

    if (palarm->enable)
    {
        next_tick = RT_TICK_PER_SECOND;
        rt_timer_control(&alarm_time, RT_TIMER_CTRL_SET_TIME, &next_tick);
        rt_timer_start(&alarm_time);
    }
    else
    {
        rt_timer_stop(&alarm_time);
    }
}

#endif

48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
static void get_rtc_timeval(struct timeval *tv)
{
    struct tm newtime = { 0 };
    SYSTEMTIME sys_time;

    GetSystemTime(&sys_time);
    newtime.tm_year = sys_time.wYear - 1900;
    newtime.tm_mon = sys_time.wMonth - 1;
    newtime.tm_mday = sys_time.wDay;
    newtime.tm_hour = sys_time.wHour;
    newtime.tm_min = sys_time.wMinute;
    newtime.tm_sec = sys_time.wSecond;

    tv->tv_sec = timegm(&newtime);
    tv->tv_usec = sys_time.wMilliseconds * 1000UL;
}

65 66 67
static rt_err_t soft_rtc_control(rt_device_t dev, int cmd, void *args)
{
    __time32_t *t;
68
    struct tm newtime;
69 70 71 72 73 74 75

    RT_ASSERT(dev != RT_NULL);

    switch (cmd)
    {
    case RT_DEVICE_CTRL_RTC_GET_TIME:
    {
76 77 78 79 80 81 82 83
        struct timeval tv;
        get_rtc_timeval(&tv);
        *(rt_uint32_t *) args = tv.tv_sec;
        break;
    }
    case RT_DEVICE_CTRL_RTC_GET_TIMEVAL:
    {
        get_rtc_timeval((struct timeval *) args);
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
        break;
    }
    case RT_DEVICE_CTRL_RTC_SET_TIME:
    {
#ifdef RT_USING_ALARM
        soft_rtc_alarm_update(&wkalarm);
#endif
        break;
    }
#ifdef RT_USING_ALARM
    case RT_DEVICE_CTRL_RTC_GET_ALARM:
        *((struct rt_rtc_wkalarm *)args) = wkalarm;
        break;
    case RT_DEVICE_CTRL_RTC_SET_ALARM:
        wkalarm = *((struct rt_rtc_wkalarm *)args);
        soft_rtc_alarm_update(&wkalarm);
        break;
#endif
102 103
    default:
        return -RT_ERROR;
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
    }

    return RT_EOK;
}

#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops soft_rtc_ops =
{
    RT_NULL,
    RT_NULL,
    RT_NULL,
    RT_NULL,
    RT_NULL,
    soft_rtc_control
};
#endif

int rt_win_rtc_init(void)
{
    static rt_bool_t init_ok = RT_FALSE;

    if (init_ok)
    {
        return 0;
    }
    /* make sure only one 'rtc' device */
    RT_ASSERT(!rt_device_find("rtc"));

#ifdef RT_USING_ALARM
    rt_timer_init(&alarm_time,
        "alarm",
        alarm_timeout,
        &rtc_dev,
        0,
        RT_TIMER_FLAG_SOFT_TIMER | RT_TIMER_FLAG_ONE_SHOT);
#endif

    rtc_dev.type = RT_Device_Class_RTC;

    /* register rtc device */
#ifdef RT_USING_DEVICE_OPS
    rtc_dev.ops = &soft_rtc_ops;
#else
    rtc_dev.init = RT_NULL;
    rtc_dev.open = RT_NULL;
    rtc_dev.close = RT_NULL;
    rtc_dev.read = RT_NULL;
    rtc_dev.write = RT_NULL;
    rtc_dev.control = soft_rtc_control;
#endif

    /* no private */
    rtc_dev.user_data = RT_NULL;

    rt_device_register(&rtc_dev, "rtc", RT_DEVICE_FLAG_RDWR);

    init_ok = RT_TRUE;

    return 0;
}
INIT_BOARD_EXPORT(rt_win_rtc_init);

#endif /* RT_USING_RTC */