soft_rtc.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. /*
  2. * Copyright (c) 2006-2021, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2018-01-30 armink the first version
  9. */
  10. #include <sys/time.h>
  11. #include <string.h>
  12. #include <rtthread.h>
  13. #include <rtdevice.h>
  14. #ifdef RT_USING_SOFT_RTC
  15. /* 2018-01-30 14:44:50 = RTC_TIME_INIT(2018, 1, 30, 14, 44, 50) */
  16. #define RTC_TIME_INIT(year, month, day, hour, minute, second) \
  17. {.tm_year = year - 1900, .tm_mon = month - 1, .tm_mday = day, .tm_hour = hour, .tm_min = minute, .tm_sec = second}
  18. #ifndef SOFT_RTC_TIME_DEFAULT
  19. #define SOFT_RTC_TIME_DEFAULT RTC_TIME_INIT(2018, 1, 1, 0, 0 ,0)
  20. #endif
  21. static struct rt_device soft_rtc_dev;
  22. static rt_tick_t init_tick;
  23. static time_t init_time;
  24. #ifdef RT_USING_ALARM
  25. static struct rt_rtc_wkalarm wkalarm;
  26. static struct rt_timer alarm_time;
  27. static void alarm_timeout(void *param)
  28. {
  29. rt_alarm_update(param, 1);
  30. }
  31. static void soft_rtc_alarm_update(struct rt_rtc_wkalarm *palarm)
  32. {
  33. rt_tick_t next_tick;
  34. if (palarm->enable)
  35. {
  36. next_tick = RT_TICK_PER_SECOND;
  37. rt_timer_control(&alarm_time, RT_TIMER_CTRL_SET_TIME, &next_tick);
  38. rt_timer_start(&alarm_time);
  39. }
  40. else
  41. {
  42. rt_timer_stop(&alarm_time);
  43. }
  44. }
  45. #endif
  46. static rt_err_t soft_rtc_control(rt_device_t dev, int cmd, void *args)
  47. {
  48. time_t *t;
  49. struct tm time_temp;
  50. RT_ASSERT(dev != RT_NULL);
  51. rt_memset(&time_temp, 0, sizeof(struct tm));
  52. switch (cmd)
  53. {
  54. case RT_DEVICE_CTRL_RTC_GET_TIME:
  55. t = (time_t *) args;
  56. *t = init_time + (rt_tick_get() - init_tick) / RT_TICK_PER_SECOND;
  57. break;
  58. case RT_DEVICE_CTRL_RTC_SET_TIME:
  59. {
  60. t = (time_t *) args;
  61. init_time = *t - (rt_tick_get() - init_tick) / RT_TICK_PER_SECOND;
  62. #ifdef RT_USING_ALARM
  63. soft_rtc_alarm_update(&wkalarm);
  64. #endif
  65. break;
  66. }
  67. #ifdef RT_USING_ALARM
  68. case RT_DEVICE_CTRL_RTC_GET_ALARM:
  69. *((struct rt_rtc_wkalarm *)args) = wkalarm;
  70. break;
  71. case RT_DEVICE_CTRL_RTC_SET_ALARM:
  72. wkalarm = *((struct rt_rtc_wkalarm *)args);
  73. soft_rtc_alarm_update(&wkalarm);
  74. break;
  75. #endif
  76. }
  77. return RT_EOK;
  78. }
  79. #ifdef RT_USING_DEVICE_OPS
  80. const static struct rt_device_ops soft_rtc_ops =
  81. {
  82. RT_NULL,
  83. RT_NULL,
  84. RT_NULL,
  85. RT_NULL,
  86. RT_NULL,
  87. soft_rtc_control
  88. };
  89. #endif
  90. static int rt_soft_rtc_init(void)
  91. {
  92. static rt_bool_t init_ok = RT_FALSE;
  93. struct tm time_new = SOFT_RTC_TIME_DEFAULT;
  94. if (init_ok)
  95. {
  96. return 0;
  97. }
  98. /* make sure only one 'rtc' device */
  99. RT_ASSERT(!rt_device_find("rtc"));
  100. #ifdef RT_USING_ALARM
  101. rt_timer_init(&alarm_time,
  102. "alarm",
  103. alarm_timeout,
  104. &soft_rtc_dev,
  105. 0,
  106. RT_TIMER_FLAG_SOFT_TIMER|RT_TIMER_FLAG_ONE_SHOT);
  107. #endif
  108. init_tick = rt_tick_get();
  109. init_time = timegm(&time_new);
  110. soft_rtc_dev.type = RT_Device_Class_RTC;
  111. /* register rtc device */
  112. #ifdef RT_USING_DEVICE_OPS
  113. soft_rtc_dev.ops = &soft_rtc_ops;
  114. #else
  115. soft_rtc_dev.init = RT_NULL;
  116. soft_rtc_dev.open = RT_NULL;
  117. soft_rtc_dev.close = RT_NULL;
  118. soft_rtc_dev.read = RT_NULL;
  119. soft_rtc_dev.write = RT_NULL;
  120. soft_rtc_dev.control = soft_rtc_control;
  121. #endif
  122. /* no private */
  123. soft_rtc_dev.user_data = RT_NULL;
  124. rt_device_register(&soft_rtc_dev, "rtc", RT_DEVICE_FLAG_RDWR);
  125. init_ok = RT_TRUE;
  126. return 0;
  127. }
  128. INIT_DEVICE_EXPORT(rt_soft_rtc_init);
  129. #endif /* RT_USING_SOFT_RTC */