--- nono/vm/power.cpp 2026/04/29 17:05:09 1.1 +++ nono/vm/power.cpp 2026/04/29 17:05:37 1.1.1.6 @@ -10,91 +10,103 @@ #include "power.h" #include "mainapp.h" +#include "mfp.h" #include "scheduler.h" -#include "sync.h" +#include "syncer.h" #include "uimessage.h" -// グローバル参照用 -PowerDevice *gPower; +// +// 共通クラス +// // コンストラクタ PowerDevice::PowerDevice() - : inherited("Power") + : inherited(OBJ_POWER) { - gScheduler->ConnectMessage(MessageID::POWERON, this, - ToMessageCallback(&PowerDevice::PowerOnCallback)); - gScheduler->ConnectMessage(MessageID::RESET, this, - ToMessageCallback(&PowerDevice::ResetCallback)); - gScheduler->ConnectMessage(MessageID::POWEROFF_EXIT, this, - ToMessageCallback(&PowerDevice::PowerOffCallback)); - gScheduler->ConnectMessage(MessageID::POWEROFF_RESTART, this, - ToMessageCallback(&PowerDevice::PowerOffCallback)); } // デストラクタ PowerDevice::~PowerDevice() { - gPower = NULL; } // 初期化 bool PowerDevice::Init() { - // 初期状態は電源オフ - ispower = false; + syncer = GetSyncer(); + + scheduler->ConnectMessage(MessageID::RESET, this, + ToMessageCallback(&PowerDevice::ResetMessage)); + scheduler->ConnectMessage(MessageID::POWEROFF_RESTART, this, + ToMessageCallback(&PowerDevice::PowerOffMessage)); + scheduler->ConnectMessage(MessageID::POWER_BUTTON, this, + ToMessageCallback(&PowerDevice::PowerButtonMessage)); + return true; } -// 電源オンをスケジューラに指示する。(外部から呼ばれる用) +// 電源ボタンを押す。 (外部から呼ばれる用) void -PowerDevice::MakePowerOn() +PowerDevice::PushPowerButton() { - gScheduler->SendMessage(MessageID::POWERON); + scheduler->SendMessage(MessageID::POWER_BUTTON); } // リセットをスケジューラに指示する。(外部から呼ばれる用) void PowerDevice::MakeResetHard() { - gScheduler->SendMessage(MessageID::RESET); -} - -// 電源オフ後終了をスケジューラに指示する。(外部から呼ばれる用) -void -PowerDevice::MakePowerOffExit() -{ - gScheduler->SendMessage(MessageID::POWEROFF_EXIT); + scheduler->SendMessage(MessageID::RESET); } // リスタートをスケジューラに指示する。(外部から呼ばれる用) void PowerDevice::MakeRestart() { - gScheduler->SendMessage(MessageID::POWEROFF_RESTART); + scheduler->SendMessage(MessageID::POWEROFF_RESTART); } -// 電源オンのメッセージコールバック +// 電源ボタンのメッセージコールバック void -PowerDevice::PowerOnCallback(MessageID msgid, uint32 arg) +PowerDevice::PowerButtonMessage(MessageID msgid, uint32 arg) { - DoPowerOn(); + DoPowerButton(); } // リセットのメッセージコールバック void -PowerDevice::ResetCallback(MessageID msgid, uint32 arg) +PowerDevice::ResetMessage(MessageID msgid, uint32 arg) { DoResetHard(); } // 電源オフのメッセージコールバック void -PowerDevice::PowerOffCallback(MessageID msgid, uint32 arg) +PowerDevice::PowerOffMessage(MessageID msgid, uint32 arg) { DoPowerOff(msgid); } +// 電源ボタン操作。 +// ただ電源をオンオフするだけなら共通クラスのこれが使える。 +// そうでない場合は継承側で対応すること。 +void +PowerDevice::DoPowerButton() +{ + putlog(1, "PowerButton"); + + if (ispower == false) { + DoPowerOn(); + } else { + DoPowerOff(MessageID::POWEROFF_EXIT); + } + + // LED の状態が変わったことを UI に通知。 + led = ispower; + UIMessage::Post(UIMessage::LED); +} + // 電源オン操作 (Device::ResetHard ではない) void PowerDevice::DoPowerOn() @@ -112,7 +124,7 @@ PowerDevice::DoPowerOn() } // 動作モード変更 - gSync->RequestPowerOffMode(false); + syncer->RequestPowerOffMode(false); } } @@ -154,13 +166,13 @@ PowerDevice::DoPowerOff(MessageID msgid) ispower = false; // 動作モード変更 - gSync->RequestPowerOffMode(true); + syncer->RequestPowerOffMode(true); } // 電源オフ後の動作は引数によって異なる if (msgid == MessageID::POWEROFF_RESTART) { // 時間を始め直す - gScheduler->StartTime(); + scheduler->StartTime(); // 再び電源オンにする (リスタート) DoPowerOn(); } else { @@ -168,3 +180,175 @@ PowerDevice::DoPowerOff(MessageID msgid) UIMessage::Post(UIMessage::APPEXIT); } } + +// 電源ボタンの状態を返す。 +PowerButtonState +PowerDevice::GetPowerButtonState() const +{ + if (alternate_switch) { + return (PowerButtonState)power_button; + } else { + return PowerButtonState::NoState; + } +} + +// システム内の電源オン信号を受け取る。 +// 呼ぶなら継承クラス側で対応すること。 +void +PowerDevice::SetSystemPowerOn(bool poweron) +{ + assertmsg(false, "PowerDevice::SetSystemPowerOn should not be called."); +} + + +// +// 電源周り (LUNA) +// + +// LUNA はフロントのモーメンタリスイッチで電源オンにする。オフには出来ない。 +// 電源オフは PIO1 から制御する。PIO1 の PC4 を %0 にすると 1msec 後に +// 電源がオフになる。PC4 を %1 にすることで電源オフを回避できる。 +// 特に PIO のモード変更をすると PC0-7 出力が一旦 %0 になるので、 +// 必ず間髪入れずに回避しなければならないらしい。どうして…。 +// +// 電源ボタン操作 -> PowerOn +// PC4 を %0 -> PowerOff イベントを開始 +// PC4 を %1 -> PowerOff イベントを停止 + +// コンストラクタ +LunaPowerDevice::LunaPowerDevice() + : inherited() +{ +} + +// デストラクタ +LunaPowerDevice::~LunaPowerDevice() +{ +} + +// 初期化 +bool +LunaPowerDevice::Init() +{ + if (inherited::Init() == false) { + return false; + } + + event.func = ToEventCallback(&LunaPowerDevice::PowerCallback); + event.time = 1_msec; + event.SetName("Power Off"); + scheduler->RegistEvent(event); + + return true; +} + +// PIO1 の PC4 が繋がっているということにする。 +void +LunaPowerDevice::SetSystemPowerOn(bool poweron) +{ + if (poweron) { + if (event.IsRunning()) { + putlog(1, "Cancel Power-Off"); + scheduler->StopEvent(event); + } + } else { + if (event.IsRunning() == false) { + putlog(1, "Start Power-Off timer"); + scheduler->RestartEvent(event); + } + } +} + +// LUNA の電源オフが信号状態の変化に対し 1msec 遅れて応答することを +// エミュレートするためのイベントコールバック。 +void +LunaPowerDevice::PowerCallback(Event& ev) +{ + DoPowerOff(MessageID::POWEROFF_EXIT); + + // LED の状態が変わったことを UI に通知。 + led = ispower; + UIMessage::Post(UIMessage::LED); +} + + +// +// 電源周り (X680x0) +// + +// X68030 はフロントのオルタネートスイッチで電源オンにする。 +// RTC 等でも電源オンは可能だが現状サポートしていないので省略。 +// +// 電源オン後は以下のいずれか一つでも成り立っている間は電源オン。 +// 1 電源ボタンがオン状態 +// 2 ALARM_OUT がアサート +// 3 システムポートが電源オフコマンドを発行していない。 + +// コンストラクタ +X68030PowerDevice::X68030PowerDevice() + : inherited() +{ + alternate_switch = true; +} + +// デストラクタ +X68030PowerDevice::~X68030PowerDevice() +{ +} + +// 電源ボタン操作 +void +X68030PowerDevice::DoPowerButton() +{ + putlog(1, "PowerButton"); + + // X68030 の電源ボタンはオルタネート動作 + power_button = !power_button; + Change(); + + // MFP の POWSW 信号は負論理 + GetMFPDevice()->SetPowSW(!power_button); +} + +// RP5C15 の ALARM_OUT を受け取る +void +X68030PowerDevice::SetAlarmOut(bool alarm_out_) +{ + alarm_out = alarm_out_; + Change(); +} + +// システムポートからの電源オフコマンド発行で false が来る。 +// 便宜上、電源投入時にはシステムポートがこれを true にする。 +void +X68030PowerDevice::SetSystemPowerOn(bool poweron) +{ + system_poweron = poweron; + Change(); +} + +// 電源状態の変更。 +// power_button、alarm_out、system_poweron のいずれかの変更で呼ぶこと。 +void +X68030PowerDevice::Change() +{ + bool old_power = ispower; + bool new_power = power_button | alarm_out | system_poweron; + putlog(1, "Change: old=%u new=%u (button=%u alarm=%u system=%u)", + old_power, new_power, power_button, alarm_out, system_poweron); + + if (old_power == false && new_power) { + DoPowerOn(); + } else if (old_power && new_power == false) { + DoPowerOff(MessageID::POWEROFF_EXIT); + } + + bool old_led = led; + // 電源 LED は X68030 の電源制御部の回路による。 + led = power_button | alarm_out; + + if (old_led != led) { + // LED の状態が変わったことを UI に通知 + UIMessage::Post(UIMessage::LED); + } +}