|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2022 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: //
8: // 電源周り
9: //
10:
11: #include "power.h"
12: #include "mainapp.h"
1.1.1.2 root 13: #include "mfp.h"
1.1 root 14: #include "scheduler.h"
1.1.1.3 root 15: #include "syncer.h"
1.1 root 16: #include "uimessage.h"
17:
1.1.1.4 root 18: //
19: // 共通クラス
20: //
21:
1.1 root 22: // コンストラクタ
23: PowerDevice::PowerDevice()
1.1.1.3 root 24: : inherited(OBJ_POWER)
1.1 root 25: {
26: }
27:
28: // デストラクタ
29: PowerDevice::~PowerDevice()
30: {
1.1.1.3 root 31: }
32:
33: // 初期化
34: bool
35: PowerDevice::Init()
36: {
37: if (inherited::Init() == false) {
38: return false;
39: }
40:
41: syncer = GetSyncer();
42:
43: scheduler->ConnectMessage(MessageID::RESET, this,
1.1.1.4 root 44: ToMessageCallback(&PowerDevice::ResetMessage));
1.1.1.3 root 45: scheduler->ConnectMessage(MessageID::POWEROFF_RESTART, this,
1.1.1.4 root 46: ToMessageCallback(&PowerDevice::PowerOffMessage));
1.1.1.3 root 47: scheduler->ConnectMessage(MessageID::POWER_BUTTON, this,
1.1.1.4 root 48: ToMessageCallback(&PowerDevice::PowerButtonMessage));
1.1.1.3 root 49:
50: return true;
1.1 root 51: }
52:
1.1.1.4 root 53: // 電源ボタンを押す。 (外部から呼ばれる用)
54: void
55: PowerDevice::PushPowerButton()
56: {
57: scheduler->SendMessage(MessageID::POWER_BUTTON);
58: }
59:
1.1 root 60: // リセットをスケジューラに指示する。(外部から呼ばれる用)
61: void
62: PowerDevice::MakeResetHard()
63: {
1.1.1.3 root 64: scheduler->SendMessage(MessageID::RESET);
1.1 root 65: }
66:
67: // リスタートをスケジューラに指示する。(外部から呼ばれる用)
68: void
69: PowerDevice::MakeRestart()
70: {
1.1.1.3 root 71: scheduler->SendMessage(MessageID::POWEROFF_RESTART);
1.1 root 72: }
73:
1.1.1.4 root 74: // 電源ボタンのメッセージコールバック
1.1 root 75: void
1.1.1.4 root 76: PowerDevice::PowerButtonMessage(MessageID msgid, uint32 arg)
1.1 root 77: {
1.1.1.4 root 78: DoPowerButton();
1.1 root 79: }
80:
81: // リセットのメッセージコールバック
82: void
1.1.1.4 root 83: PowerDevice::ResetMessage(MessageID msgid, uint32 arg)
1.1 root 84: {
85: DoResetHard();
86: }
87:
88: // 電源オフのメッセージコールバック
89: void
1.1.1.4 root 90: PowerDevice::PowerOffMessage(MessageID msgid, uint32 arg)
1.1 root 91: {
92: DoPowerOff(msgid);
93: }
94:
1.1.1.4 root 95: // 電源ボタン操作。
96: // ただ電源をオンオフするだけなら共通クラスのこれが使える。
97: // そうでない場合は継承側で対応すること。
1.1.1.2 root 98: void
1.1.1.4 root 99: PowerDevice::DoPowerButton()
1.1.1.2 root 100: {
1.1.1.4 root 101: putlog(1, "PowerButton");
102:
103: if (ispower == false) {
104: DoPowerOn();
105: } else {
106: DoPowerOff(MessageID::POWEROFF_EXIT);
107: }
108:
109: // LED の状態が変わったことを UI に通知。
110: led = ispower;
111: UIMessage::Post(UIMessage::LED);
1.1.1.2 root 112: }
113:
1.1 root 114: // 電源オン操作 (Device::ResetHard ではない)
115: void
116: PowerDevice::DoPowerOn()
117: {
118: putlog(1, "PowerOn");
119:
120: if (ispower == false) {
121: // 全デバイス電源オン
122: ispower = true;
123: for (auto obj : gMainApp.GetObjects()) {
124: auto dev = dynamic_cast<Device *>(obj);
125: if (dev) {
126: dev->ResetHard(true);
127: }
128: }
129:
130: // 動作モード変更
1.1.1.3 root 131: syncer->RequestPowerOffMode(false);
1.1 root 132: }
133: }
134:
135: // リセット操作 (Device::ResetHard ではない)
136: void
137: PowerDevice::DoResetHard()
138: {
139: putlog(1, "Reset");
140:
141: if (ispower) {
142: // 全デバイスをリセット
143: for (auto obj : gMainApp.GetObjects()) {
144: auto dev = dynamic_cast<Device *>(obj);
145: if (dev) {
146: dev->ResetHard(false);
147: }
148: }
149: }
150: }
151:
152: // 電源オフ操作 (Device::PowerOff ではない)
153: void
154: PowerDevice::DoPowerOff(MessageID msgid)
155: {
156: putlog(1, "PowerOff");
157:
158: assertmsg(msgid == MessageID::POWEROFF_EXIT ||
159: msgid == MessageID::POWEROFF_RESTART,
160: "msgid=%d", (int)msgid);
161:
162: if (ispower) {
163: // 全デバイス電源オフ
164: for (auto obj : gMainApp.GetObjects()) {
165: auto dev = dynamic_cast<Device *>(obj);
166: if (dev) {
167: dev->PowerOff();
168: }
169: }
170: ispower = false;
171:
172: // 動作モード変更
1.1.1.3 root 173: syncer->RequestPowerOffMode(true);
1.1 root 174: }
175:
176: // 電源オフ後の動作は引数によって異なる
177: if (msgid == MessageID::POWEROFF_RESTART) {
178: // 時間を始め直す
1.1.1.3 root 179: scheduler->StartTime();
1.1 root 180: // 再び電源オンにする (リスタート)
181: DoPowerOn();
182: } else {
183: // そうでなければ、GUI に終了を通知
184: UIMessage::Post(UIMessage::APPEXIT);
185: }
186: }
1.1.1.2 root 187:
1.1.1.4 root 188: // 電源ボタンの状態を返す。
189: PowerButtonState
190: PowerDevice::GetPowerButtonState() const
191: {
192: if (alternate_switch) {
193: return (PowerButtonState)power_button;
194: } else {
195: return PowerButtonState::NoState;
196: }
197: }
198:
199: // システム内の電源オン信号を受け取る。
200: // 呼ぶなら継承クラス側で対応すること。
1.1.1.2 root 201: void
1.1.1.4 root 202: PowerDevice::SetSystemPowerOn(bool poweron)
1.1.1.2 root 203: {
1.1.1.5 ! root 204: assertmsg(false, "PowerDevice::SetSystemPowerOn should not be called.");
1.1.1.4 root 205: }
206:
207:
208: //
209: // 電源周り (LUNA)
210: //
211:
212: // LUNA はフロントのモーメンタリスイッチで電源オンにする。オフには出来ない。
213: // 電源オフは PIO1 から制御する。PIO1 の PC4 を %0 にすると 1msec 後に
214: // 電源がオフになる。PC4 を %1 にすることで電源オフを回避できる。
215: // 特に PIO のモード変更をすると PC0-7 出力が一旦 %0 になるので、
216: // 必ず間髪入れずに回避しなければならないらしい。どうして…。
217: //
218: // 電源ボタン操作 -> PowerOn
219: // PC4 を %0 -> PowerOff イベントを開始
220: // PC4 を %1 -> PowerOff イベントを停止
221:
222: // コンストラクタ
223: LunaPowerDevice::LunaPowerDevice()
224: : inherited()
225: {
226: }
227:
228: // デストラクタ
229: LunaPowerDevice::~LunaPowerDevice()
230: {
231: }
1.1.1.2 root 232:
1.1.1.5 ! root 233: // 初期化
! 234: bool
! 235: LunaPowerDevice::Init()
! 236: {
! 237: if (inherited::Init() == false) {
! 238: return false;
! 239: }
! 240:
! 241: event.func = ToEventCallback(&LunaPowerDevice::PowerCallback);
! 242: event.time = 1_msec;
! 243: event.SetName("Power Off");
! 244: scheduler->RegistEvent(event);
! 245:
! 246: return true;
! 247: }
! 248:
1.1.1.4 root 249: // PIO1 の PC4 が繋がっているということにする。
250: void
251: LunaPowerDevice::SetSystemPowerOn(bool poweron)
252: {
253: if (poweron) {
254: if (event.IsRunning()) {
255: putlog(1, "Cancel Power-Off");
256: scheduler->StopEvent(event);
257: }
1.1.1.2 root 258: } else {
1.1.1.4 root 259: if (event.IsRunning() == false) {
260: putlog(1, "Start Power-Off timer");
261: scheduler->RestartEvent(event);
262: }
1.1.1.2 root 263: }
264: }
265:
1.1.1.4 root 266: // LUNA の電源オフが信号状態の変化に対し 1msec 遅れて応答することを
267: // エミュレートするためのイベントコールバック。
268: void
269: LunaPowerDevice::PowerCallback(Event& ev)
270: {
271: DoPowerOff(MessageID::POWEROFF_EXIT);
272:
273: // LED の状態が変わったことを UI に通知。
274: led = ispower;
275: UIMessage::Post(UIMessage::LED);
276: }
277:
278:
279: //
280: // 電源周り (X680x0)
281: //
282:
283: // X68030 はフロントのオルタネートスイッチで電源オンにする。
284: // RTC 等でも電源オンは可能だが現状サポートしていないので省略。
285: //
286: // 電源オン後は以下のいずれか一つでも成り立っている間は電源オン。
287: // 1 電源ボタンがオン状態
288: // 2 ALARM_OUT がアサート
289: // 3 システムポートが電源オフコマンドを発行していない。
290:
291: // コンストラクタ
292: X68030PowerDevice::X68030PowerDevice()
293: : inherited()
294: {
295: alternate_switch = true;
296: }
297:
298: // デストラクタ
299: X68030PowerDevice::~X68030PowerDevice()
300: {
301: }
302:
303: // 電源ボタン操作
304: void
305: X68030PowerDevice::DoPowerButton()
306: {
307: putlog(1, "PowerButton");
308:
309: // X68030 の電源ボタンはオルタネート動作
310: power_button = !power_button;
311: Change();
312:
313: // MFP の POWSW 信号は負論理
314: GetMFPDevice()->SetPowSW(!power_button);
315: }
316:
1.1.1.2 root 317: // RP5C15 の ALARM_OUT を受け取る
318: void
1.1.1.4 root 319: X68030PowerDevice::SetAlarmOut(bool alarm_out_)
1.1.1.2 root 320: {
321: alarm_out = alarm_out_;
322: Change();
323: }
324:
1.1.1.4 root 325: // システムポートからの電源オフコマンド発行で false が来る。
326: // 便宜上、電源投入時にはシステムポートがこれを true にする。
1.1.1.2 root 327: void
1.1.1.4 root 328: X68030PowerDevice::SetSystemPowerOn(bool poweron)
1.1.1.2 root 329: {
330: system_poweron = poweron;
331: Change();
332: }
333:
334: // 電源状態の変更。
335: // power_button、alarm_out、system_poweron のいずれかの変更で呼ぶこと。
336: void
1.1.1.4 root 337: X68030PowerDevice::Change()
1.1.1.2 root 338: {
339: bool old_power = ispower;
340: bool new_power = power_button | alarm_out | system_poweron;
1.1.1.5 ! root 341: putlog(1, "Change: old=%u new=%u (button=%u alarm=%u system=%u)",
1.1.1.4 root 342: old_power, new_power, power_button, alarm_out, system_poweron);
1.1.1.2 root 343:
344: if (old_power == false && new_power) {
345: DoPowerOn();
346: } else if (old_power && new_power == false) {
1.1.1.4 root 347: DoPowerOff(MessageID::POWEROFF_EXIT);
1.1.1.2 root 348: }
349:
350: bool old_led = led;
1.1.1.4 root 351: // 電源 LED は X68030 の電源制御部の回路による。
352: led = power_button | alarm_out;
353:
1.1.1.2 root 354: if (old_led != led) {
355: // LED の状態が変わったことを UI に通知
356: UIMessage::Post(UIMessage::LED);
357: }
358: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.