rtc.c 7.2 KB
Newer Older
D
dzzxzz@gmail.com 已提交
1
/*
2
 * Copyright (c) 2006-2021, RT-Thread Development Team
D
dzzxzz@gmail.com 已提交
3
 *
4
 * SPDX-License-Identifier: Apache-2.0
D
dzzxzz@gmail.com 已提交
5 6 7 8 9 10
 *
 * Change Logs:
 * Date           Author       Notes
 * 2012-01-29     aozima       first version.
 * 2012-04-12     aozima       optimization: find rtc device only first.
 * 2012-04-16     aozima       add scheduler lock for set_date and set_time.
11
 * 2018-02-16     armink       add auto sync time by NTP
mysterywolf's avatar
mysterywolf 已提交
12
 * 2021-05-09     Meco Man     remove NTP
mysterywolf's avatar
mysterywolf 已提交
13 14
 * 2021-06-11     iysheng      implement RTC framework V2.0
 * 2021-07-30     Meco Man     move rtc_core.c to rtc.c
D
dzzxzz@gmail.com 已提交
15 16
 */

mysterywolf's avatar
mysterywolf 已提交
17
#include <sys/time.h>
D
dzzxzz@gmail.com 已提交
18
#include <string.h>
19
#include <stdlib.h>
D
dzzxzz@gmail.com 已提交
20
#include <rtthread.h>
21
#include <drivers/rtc.h>
D
dzzxzz@gmail.com 已提交
22

23 24
#ifdef RT_USING_RTC

25 26 27
/*
 * This function initializes rtc_core
 */
mysterywolf's avatar
mysterywolf 已提交
28
static rt_err_t rt_rtc_init(struct rt_device *dev)
29 30 31 32 33 34 35 36 37 38
{
    rt_rtc_dev_t *rtc_core;

    RT_ASSERT(dev != RT_NULL);
    rtc_core = (rt_rtc_dev_t *)dev;
    if (rtc_core->ops->init)
    {
        return (rtc_core->ops->init());
    }

mysterywolf's avatar
mysterywolf 已提交
39
    return -RT_ENOSYS;
40 41
}

mysterywolf's avatar
mysterywolf 已提交
42
static rt_err_t rt_rtc_open(struct rt_device *dev, rt_uint16_t oflag)
43
{
mysterywolf's avatar
mysterywolf 已提交
44
    return RT_EOK;
45 46
}

mysterywolf's avatar
mysterywolf 已提交
47
static rt_err_t rt_rtc_close(struct rt_device *dev)
48 49 50 51
{
    /* Add close member function in rt_rtc_ops when need,
     * then call that function here.
     * */
mysterywolf's avatar
mysterywolf 已提交
52
    return RT_EOK;
53 54
}

mysterywolf's avatar
mysterywolf 已提交
55
static rt_err_t rt_rtc_control(struct rt_device *dev, int cmd, void *args)
56
{
mysterywolf's avatar
mysterywolf 已提交
57 58 59 60
#define TRY_DO_RTC_FUNC(rt_rtc_dev, func_name, args) \
    rt_rtc_dev->ops->func_name ?  rt_rtc_dev->ops->func_name(args) : -RT_EINVAL;

    rt_rtc_dev_t *rtc_device;
61 62 63
    rt_err_t ret = -RT_EINVAL;

    RT_ASSERT(dev != RT_NULL);
mysterywolf's avatar
mysterywolf 已提交
64
    rtc_device = (rt_rtc_dev_t *)dev;
65 66 67 68

    switch (cmd)
    {
        case RT_DEVICE_CTRL_RTC_GET_TIME:
mysterywolf's avatar
mysterywolf 已提交
69
            ret = TRY_DO_RTC_FUNC(rtc_device, get_secs, args);
70 71
            break;
        case RT_DEVICE_CTRL_RTC_SET_TIME:
mysterywolf's avatar
mysterywolf 已提交
72
            ret = TRY_DO_RTC_FUNC(rtc_device, set_secs, args);
73
            break;
74 75
        case RT_DEVICE_CTRL_RTC_GET_TIMEVAL:
            ret = TRY_DO_RTC_FUNC(rtc_device, get_timeval, args);
76
            break;
77 78
        case RT_DEVICE_CTRL_RTC_SET_TIMEVAL:
            ret = TRY_DO_RTC_FUNC(rtc_device, set_timeval, args);
79 80
            break;
        case RT_DEVICE_CTRL_RTC_GET_ALARM:
mysterywolf's avatar
mysterywolf 已提交
81
            ret = TRY_DO_RTC_FUNC(rtc_device, get_alarm, args);
82 83
            break;
        case RT_DEVICE_CTRL_RTC_SET_ALARM:
mysterywolf's avatar
mysterywolf 已提交
84
            ret = TRY_DO_RTC_FUNC(rtc_device, set_alarm, args);
85 86 87 88 89 90
            break;
        default:
            break;
    }

    return ret;
mysterywolf's avatar
mysterywolf 已提交
91 92

#undef TRY_DO_RTC_FUNC
93
}
mysterywolf's avatar
mysterywolf 已提交
94

95 96 97
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops rtc_core_ops =
{
mysterywolf's avatar
mysterywolf 已提交
98 99 100
    rt_rtc_init,
    rt_rtc_open,
    rt_rtc_close,
101 102
    RT_NULL,
    RT_NULL,
mysterywolf's avatar
mysterywolf 已提交
103
    rt_rtc_control,
104
};
mysterywolf's avatar
mysterywolf 已提交
105
#endif /* RT_USING_DEVICE_OPS */
106

mysterywolf's avatar
mysterywolf 已提交
107
rt_err_t rt_hw_rtc_register(rt_rtc_dev_t  *rtc,
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
                            const char    *name,
                            rt_uint32_t    flag,
                            void          *data)
{
    struct rt_device *device;
    RT_ASSERT(rtc != RT_NULL);

    device = &(rtc->parent);

    device->type        = RT_Device_Class_RTC;
    device->rx_indicate = RT_NULL;
    device->tx_complete = RT_NULL;

#ifdef RT_USING_DEVICE_OPS
    device->ops         = &rtc_core_ops;
#else
mysterywolf's avatar
mysterywolf 已提交
124 125 126
    device->init        = rt_rtc_init;
    device->open        = rt_rtc_open;
    device->close       = rt_rtc_close;
127 128
    device->read        = RT_NULL;
    device->write       = RT_NULL;
mysterywolf's avatar
mysterywolf 已提交
129 130
    device->control     = rt_rtc_control;
#endif /* RT_USING_DEVICE_OPS */
131 132 133 134 135 136
    device->user_data   = data;

    /* register a character device */
    return rt_device_register(device, name, flag);
}

137
/**
138
 * Set system date(time not modify, local timezone).
D
dzzxzz@gmail.com 已提交
139
 *
140 141 142 143 144
 * @param rt_uint32_t year  e.g: 2012.
 * @param rt_uint32_t month e.g: 12 (1~12).
 * @param rt_uint32_t day   e.g: 31.
 *
 * @return rt_err_t if set success, return RT_EOK.
D
dzzxzz@gmail.com 已提交
145 146 147 148 149 150 151 152 153 154 155
 */
rt_err_t set_date(rt_uint32_t year, rt_uint32_t month, rt_uint32_t day)
{
    time_t now;
    struct tm tm_new;
    rt_device_t device;
    rt_err_t ret = -RT_ERROR;

    /* get current time */
    now = time(RT_NULL);

156
    /* converts calendar time into local time. */
mysterywolf's avatar
mysterywolf 已提交
157
    localtime_r(&now, &tm_new);
D
dzzxzz@gmail.com 已提交
158 159 160 161 162 163

    /* update date. */
    tm_new.tm_year = year - 1900;
    tm_new.tm_mon  = month - 1; /* tm_mon: 0~11 */
    tm_new.tm_mday = day;

mysterywolf's avatar
mysterywolf 已提交
164
    /* converts the local time into the calendar time. */
D
dzzxzz@gmail.com 已提交
165 166 167 168 169 170 171 172 173 174 175 176 177 178
    now = mktime(&tm_new);

    device = rt_device_find("rtc");
    if (device == RT_NULL)
    {
        return -RT_ERROR;
    }

    /* update to RTC device. */
    ret = rt_device_control(device, RT_DEVICE_CTRL_RTC_SET_TIME, &now);

    return ret;
}

179
/**
180
 * Set system time(date not modify, local timezone).
181 182 183 184
 *
 * @param rt_uint32_t hour   e.g: 0~23.
 * @param rt_uint32_t minute e.g: 0~59.
 * @param rt_uint32_t second e.g: 0~59.
D
dzzxzz@gmail.com 已提交
185
 *
186
 * @return rt_err_t if set success, return RT_EOK.
D
dzzxzz@gmail.com 已提交
187 188 189 190 191 192 193 194 195 196 197
 */
rt_err_t set_time(rt_uint32_t hour, rt_uint32_t minute, rt_uint32_t second)
{
    time_t now;
    struct tm tm_new;
    rt_device_t device;
    rt_err_t ret = -RT_ERROR;

    /* get current time */
    now = time(RT_NULL);

198
    /* converts calendar time into local time. */
mysterywolf's avatar
mysterywolf 已提交
199
    localtime_r(&now, &tm_new);
D
dzzxzz@gmail.com 已提交
200 201 202 203 204 205

    /* update time. */
    tm_new.tm_hour = hour;
    tm_new.tm_min  = minute;
    tm_new.tm_sec  = second;

206
    /* converts the local time into the calendar time. */
D
dzzxzz@gmail.com 已提交
207 208 209 210 211 212 213 214 215 216 217 218 219 220
    now = mktime(&tm_new);

    device = rt_device_find("rtc");
    if (device == RT_NULL)
    {
        return -RT_ERROR;
    }

    /* update to RTC device. */
    ret = rt_device_control(device, RT_DEVICE_CTRL_RTC_SET_TIME, &now);

    return ret;
}

马志远 已提交
221
#ifdef RT_USING_FINSH
D
dzzxzz@gmail.com 已提交
222
#include <finsh.h>
223 224 225
/**
 * get date and time or set (local timezone) [year month day hour min sec]
 */
B
Bernard Xiong 已提交
226
static void date(int argc, char **argv)
227 228 229 230 231 232
{
    if (argc == 1)
    {
        time_t now;
        /* output current time */
        now = time(RT_NULL);
233
        rt_kprintf("%.*s", 25, ctime(&now));
234 235 236 237
    }
    else if (argc >= 7)
    {
        /* set time and date */
B
Bernard Xiong 已提交
238 239 240
        rt_uint16_t year;
        rt_uint8_t month, day, hour, min, sec;

241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
        year = atoi(argv[1]);
        month = atoi(argv[2]);
        day = atoi(argv[3]);
        hour = atoi(argv[4]);
        min = atoi(argv[5]);
        sec = atoi(argv[6]);
        if (year > 2099 || year < 2000)
        {
            rt_kprintf("year is out of range [2000-2099]\n");
            return;
        }
        if (month == 0 || month > 12)
        {
            rt_kprintf("month is out of range [1-12]\n");
            return;
        }
        if (day == 0 || day > 31)
        {
            rt_kprintf("day is out of range [1-31]\n");
            return;
        }
        if (hour > 23)
        {
            rt_kprintf("hour is out of range [0-23]\n");
            return;
        }
        if (min > 59)
        {
            rt_kprintf("minute is out of range [0-59]\n");
            return;
        }
        if (sec > 59)
        {
            rt_kprintf("second is out of range [0-59]\n");
            return;
        }
        set_time(hour, min, sec);
        set_date(year, month, day);
    }
    else
    {
        rt_kprintf("please input: date [year month day hour min sec] or date\n");
        rt_kprintf("e.g: date 2018 01 01 23 59 59 or date\n");
    }
}
286
MSH_CMD_EXPORT(date, get date and time or set (local timezone) [year month day hour min sec])
马志远 已提交
287
#endif /* RT_USING_FINSH */
288

289
#endif /* RT_USING_RTC */