|
|
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.4 ! root 204: assert("PowerDevice::SetSystemPowerOn should not be called.");
! 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: event.func = ToEventCallback(&LunaPowerDevice::PowerCallback);
! 227: event.time = 1_msec;
! 228: event.Regist("Power Off");
! 229: }
! 230:
! 231: // デストラクタ
! 232: LunaPowerDevice::~LunaPowerDevice()
! 233: {
! 234: }
1.1.1.2 root 235:
1.1.1.4 ! root 236: // PIO1 の PC4 が繋がっているということにする。
! 237: void
! 238: LunaPowerDevice::SetSystemPowerOn(bool poweron)
! 239: {
! 240: if (poweron) {
! 241: if (event.IsRunning()) {
! 242: putlog(1, "Cancel Power-Off");
! 243: scheduler->StopEvent(event);
! 244: }
1.1.1.2 root 245: } else {
1.1.1.4 ! root 246: if (event.IsRunning() == false) {
! 247: putlog(1, "Start Power-Off timer");
! 248: scheduler->RestartEvent(event);
! 249: }
1.1.1.2 root 250: }
251: }
252:
1.1.1.4 ! root 253: // LUNA の電源オフが信号状態の変化に対し 1msec 遅れて応答することを
! 254: // エミュレートするためのイベントコールバック。
! 255: void
! 256: LunaPowerDevice::PowerCallback(Event& ev)
! 257: {
! 258: DoPowerOff(MessageID::POWEROFF_EXIT);
! 259:
! 260: // LED の状態が変わったことを UI に通知。
! 261: led = ispower;
! 262: UIMessage::Post(UIMessage::LED);
! 263: }
! 264:
! 265:
! 266: //
! 267: // 電源周り (X680x0)
! 268: //
! 269:
! 270: // X68030 はフロントのオルタネートスイッチで電源オンにする。
! 271: // RTC 等でも電源オンは可能だが現状サポートしていないので省略。
! 272: //
! 273: // 電源オン後は以下のいずれか一つでも成り立っている間は電源オン。
! 274: // 1 電源ボタンがオン状態
! 275: // 2 ALARM_OUT がアサート
! 276: // 3 システムポートが電源オフコマンドを発行していない。
! 277:
! 278: // コンストラクタ
! 279: X68030PowerDevice::X68030PowerDevice()
! 280: : inherited()
! 281: {
! 282: alternate_switch = true;
! 283: }
! 284:
! 285: // デストラクタ
! 286: X68030PowerDevice::~X68030PowerDevice()
! 287: {
! 288: }
! 289:
! 290: // 電源ボタン操作
! 291: void
! 292: X68030PowerDevice::DoPowerButton()
! 293: {
! 294: putlog(1, "PowerButton");
! 295:
! 296: // X68030 の電源ボタンはオルタネート動作
! 297: power_button = !power_button;
! 298: Change();
! 299:
! 300: // MFP の POWSW 信号は負論理
! 301: GetMFPDevice()->SetPowSW(!power_button);
! 302: }
! 303:
1.1.1.2 root 304: // RP5C15 の ALARM_OUT を受け取る
305: void
1.1.1.4 ! root 306: X68030PowerDevice::SetAlarmOut(bool alarm_out_)
1.1.1.2 root 307: {
308: alarm_out = alarm_out_;
309: Change();
310: }
311:
1.1.1.4 ! root 312: // システムポートからの電源オフコマンド発行で false が来る。
! 313: // 便宜上、電源投入時にはシステムポートがこれを true にする。
1.1.1.2 root 314: void
1.1.1.4 ! root 315: X68030PowerDevice::SetSystemPowerOn(bool poweron)
1.1.1.2 root 316: {
317: system_poweron = poweron;
318: Change();
319: }
320:
321: // 電源状態の変更。
322: // power_button、alarm_out、system_poweron のいずれかの変更で呼ぶこと。
323: void
1.1.1.4 ! root 324: X68030PowerDevice::Change()
1.1.1.2 root 325: {
326: bool old_power = ispower;
327: bool new_power = power_button | alarm_out | system_poweron;
1.1.1.4 ! root 328: putlog(1, "Change: old=%d new=%d (button=%d alarm=%d system=%d)",
! 329: old_power, new_power, power_button, alarm_out, system_poweron);
1.1.1.2 root 330:
331: if (old_power == false && new_power) {
332: DoPowerOn();
333: } else if (old_power && new_power == false) {
1.1.1.4 ! root 334: DoPowerOff(MessageID::POWEROFF_EXIT);
1.1.1.2 root 335: }
336:
337: bool old_led = led;
1.1.1.4 ! root 338: // 電源 LED は X68030 の電源制御部の回路による。
! 339: led = power_button | alarm_out;
! 340:
1.1.1.2 root 341: if (old_led != led) {
342: // LED の状態が変わったことを UI に通知
343: UIMessage::Post(UIMessage::LED);
344: }
345: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.