|
|
1.1 root 1: //
2: // nono
1.1.1.3 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
7: #include "rtc.h"
8: #include <sys/time.h>
9:
10: // XXX rtc の読み書きはロックしたほうがいいような気がする
11:
1.1.1.2 root 12: std::unique_ptr<RTCDevice> gRTC;
1.1 root 13:
14: RTCDevice::RTCDevice()
15: {
16: }
17:
18: RTCDevice::~RTCDevice()
19: {
20: }
21:
1.1.1.4 ! root 22: void
! 23: RTCDevice::ResetHard()
! 24: {
! 25: // 秒への繰り上がりを許可。
! 26: rtc.enable_sec = true;
! 27: }
! 28:
1.1 root 29: // ホストの現在時刻を rtc に取得。
1.1.1.4 ! root 30: // (派生クラスの Init() から呼ばれる)
1.1 root 31: // localtime を内部時刻にするときは use_localtime == true
32: // UTC を内部時刻にするときは use_localtime == false にすること。
33: void
34: RTCDevice::LoadHostRTC(bool use_localtime)
35: {
36: struct timeval tv;
37: struct tm tm;
38:
39: // 起動した時の現在時刻で設定する
40: gettimeofday(&tv, NULL);
41: if (use_localtime) {
42: localtime_r(&tv.tv_sec, &tm);
43: } else {
44: gmtime_r(&tv.tv_sec, &tm);
45: }
46: // 秒未満の初期値もそれなりの精度にしておく (1000*1000 / 32 = 31250)
47: rtc.cnt = tv.tv_usec / 31250;
48: rtc.sec = tm.tm_sec;
49: rtc.min = tm.tm_min;
50: rtc.hour = tm.tm_hour;
51: // wday も tm_wday も日曜が 0
52: rtc.wday = tm.tm_wday;
53: rtc.mday = tm.tm_mday;
54: rtc.mon = tm.tm_mon + 1;
55: rtc.year = tm.tm_year + 1900;
56: }
57:
58: // 32Hz カウンタの処理。
59: // 戻り値は更新が起きた位。
60: // 派生クラスで用意した ClockIn() から呼び出すこと。
61: uint32
62: RTCDevice::CountUp()
63: {
64: uint32 updates;
65:
66: updates = 0;
67:
68: // 内部カウンタアップ
69: rtc.cnt++;
70: rtc.cnt &= 63;
71:
72: // RP5C15 の Timer Enable は内部カウンタは動作していて、
73: // 秒へのカウントアップをするかどうかのフラグ。
74: if (rtc.enable_sec == false) {
75: return updates;
76: }
77:
78: // 秒の繰り上がり処理。
79: // 32カウントで1秒だが、RP5C15 はタイマー停止中でも 1秒への繰り上がり
80: // 1回は内部で覚えているので、ここだけ 32 以上だったら 32 を引く運用。
81: if (rtc.cnt >= 32) {
82: rtc.cnt -= 32;
83: updates |= CarrySec(updates);
84: }
85: return updates;
86: }
87:
88: // 秒への繰り上がり処理。
89: // 戻り値は更新が起きた位。
90: uint32
91: RTCDevice::CarrySec(uint32 updates)
92: {
93: rtc.sec++;
94: updates |= RTCDevice::UPDATE_SEC;
95:
96: if (rtc.sec >= 60) {
97: rtc.sec = 0;
98: updates |= CarryMin(updates);
99: }
100: return updates;
101: }
102:
103: // 分への繰り上がり処理。
104: // 戻り値は更新が起きた位。
105: uint32
106: RTCDevice::CarryMin(uint32 updates)
107: {
108: rtc.min++;
109: updates |= RTCDevice::UPDATE_MIN;
110:
111: if (rtc.min >= 60) {
112: rtc.min = 0;
113: updates |= CarryHour(updates);
114: }
115: return updates;
116: }
117:
118: // 時への繰り上がり処理。時間は24時間計。
119: // 戻り値は更新が起きた位。
120: uint32
121: RTCDevice::CarryHour(uint32 updates)
122: {
123: rtc.hour++;
124: updates |= RTCDevice::UPDATE_HOUR;
125:
126: if (rtc.hour >= 24) {
127: rtc.hour = 0;
128: updates |= CarryDay(updates);
129: }
130: return updates;
131: }
132:
133: // 日への繰り上がり処理。
134: // 戻り値は更新が起きた位。
135: uint32
136: RTCDevice::CarryDay(uint32 updates)
137: {
138: // まず曜日
139: rtc.wday = (rtc.wday + 1) % 7;
140:
141: // 日にち
142: rtc.mday++;
143: updates |= RTCDevice::UPDATE_DAY;
144:
145: // 日が繰り上がった結果、月が繰り上がるかどうか
146: static const int mdays[] = {
147: 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
148: };
149: if (rtc.mday > (mdays[rtc.mon] + (IsLeapMon() ? 1 : 0))) {
150: rtc.mday = 1;
151: updates |= CarryMon(updates);
152: }
153: return updates;
154: }
155:
156: // 月への繰り上がり処理。
157: // 戻り値は更新が起きた位。
158: uint32
159: RTCDevice::CarryMon(uint32 updates)
160: {
161: rtc.mon++;
162: updates |= RTCDevice::UPDATE_MON;
163:
164: if (rtc.mon >= 12) {
165: rtc.mon = 1;
166: updates |= CarryYear(updates);
167: }
168: return updates;
169: }
170:
171: // 年への繰り上がり処理。
172: // 戻り値は更新が起きた位。
173: uint32
174: RTCDevice::CarryYear(uint32 updates)
175: {
176: rtc.year++;
177: updates |= RTCDevice::UPDATE_YEAR;
178:
179: // 特にすることはない
180:
181: return updates;
182: }
183:
184: // 閏年の2月なら true を返す。
185: bool
186: RTCDevice::IsLeapMon() const
187: {
188: // 1900年から2100年までの間は 4 で割るだけでよい。
189: if ((rtc.year % 4 == 0) && (rtc.mon == 2)) {
190: return true;
191: }
192: return false;
193: }
194:
195: // 曜日文字列
196: /*static*/ const char * const
197: RTCDevice::wdays[7] = {
198: "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
199: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.