--- nono/vm/power.cpp 2026/04/29 17:05:17 1.1.1.3 +++ nono/vm/power.cpp 2026/04/29 17:05:54 1.1.1.8 @@ -9,19 +9,21 @@ // #include "power.h" +#include "event.h" #include "mainapp.h" #include "mfp.h" #include "scheduler.h" #include "syncer.h" #include "uimessage.h" +// +// 共通クラス +// + // コンストラクタ PowerDevice::PowerDevice() : inherited(OBJ_POWER) { - event.func = ToEventCallback(&PowerDevice::PowerCallback); - event.time = 1_msec; - event.Regist("Power Off"); } // デストラクタ @@ -33,22 +35,26 @@ PowerDevice::~PowerDevice() bool PowerDevice::Init() { - if (inherited::Init() == false) { - return false; - } - syncer = GetSyncer(); + uimessage = gMainApp.GetUIMessage(); scheduler->ConnectMessage(MessageID::RESET, this, - ToMessageCallback(&PowerDevice::ResetCallback)); + ToMessageCallback(&PowerDevice::ResetMessage)); scheduler->ConnectMessage(MessageID::POWEROFF_RESTART, this, - ToMessageCallback(&PowerDevice::PowerOffCallback)); + ToMessageCallback(&PowerDevice::PowerOffMessage)); scheduler->ConnectMessage(MessageID::POWER_BUTTON, this, - ToMessageCallback(&PowerDevice::PowerButtonCallback)); + ToMessageCallback(&PowerDevice::PowerButtonMessage)); return true; } +// 電源ボタンを押す。 (外部から呼ばれる用) +void +PowerDevice::PushPowerButton() +{ + scheduler->SendMessage(MessageID::POWER_BUTTON); +} + // リセットをスケジューラに指示する。(外部から呼ばれる用) void PowerDevice::MakeResetHard() @@ -63,32 +69,44 @@ PowerDevice::MakeRestart() scheduler->SendMessage(MessageID::POWEROFF_RESTART); } -// 電源ボタンを押す。 (外部から呼ばれる用) +// 電源ボタンのメッセージコールバック void -PowerDevice::PowerButton() +PowerDevice::PowerButtonMessage(MessageID msgid, uint32 arg) { - scheduler->SendMessage(MessageID::POWER_BUTTON); + 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::PowerButtonCallback(MessageID msgid, uint32 arg) +PowerDevice::DoPowerButton() { - DoPowerButton(); + putlog(1, "PowerButton"); + + if (ispower == false) { + DoPowerOn(); + } else { + DoPowerOff(MessageID::POWEROFF_EXIT); + } + + // LED の状態が変わったことを UI に通知。 + led = ispower; + uimessage->Post(UIMessage::LED); } // 電源オン操作 (Device::ResetHard ではない) @@ -108,7 +126,7 @@ PowerDevice::DoPowerOn() } // 動作モード変更 - syncer->RequestPowerOffMode(false); + syncer->NotifyPowerOffMode(false); } } @@ -150,7 +168,7 @@ PowerDevice::DoPowerOff(MessageID msgid) ispower = false; // 動作モード変更 - syncer->RequestPowerOffMode(true); + syncer->NotifyPowerOffMode(true); } // 電源オフ後の動作は引数によって異なる @@ -161,44 +179,152 @@ PowerDevice::DoPowerOff(MessageID msgid) DoPowerOn(); } else { // そうでなければ、GUI に終了を通知 - UIMessage::Post(UIMessage::APPEXIT); + uimessage->Post(UIMessage::APPEXIT); } } -// 電源ボタン操作 +// 電源ボタンの状態を返す。 +PowerButtonState +PowerDevice::GetPowerButtonState() const +{ + if (alternate_switch) { + return (PowerButtonState)power_button; + } else { + return PowerButtonState::NoState; + } +} + +// システム内の電源オン信号を受け取る。 +// 呼ぶなら継承クラス側で対応すること。 void -PowerDevice::DoPowerButton() +PowerDevice::SetSystemPowerOn(bool poweron) { - putlog(1, "PowerButton"); + assertmsg(false, "PowerDevice::SetSystemPowerOn should not be called."); +} + + +// +// 電源周り (LUNA) +// - if (gMainApp.IsX68030()) { - // X68030 の電源ボタンはオルタネート動作 - power_button = !power_button; - Change(); - // MFP の POWSW 信号は負論理 - GetMFPDevice()->SetPowSW(!power_button); +// 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; + } + + auto evman = GetEventManager(); + event = evman->Regist(this, + ToEventCallback(&LunaPowerDevice::PowerCallback), + "Power Off"); + event->time = 1_msec; + + return true; +} + +// PIO1 の PC4 が繋がっているということにする。 +void +LunaPowerDevice::SetSystemPowerOn(bool poweron) +{ + if (poweron) { + if (event->IsRunning()) { + putlog(1, "Cancel Power-Off"); + scheduler->StopEvent(event); + } } else { - // LUNA の電源ボタンはモーメンタリ動作 - power_button = true; - Change(); - power_button = false; + 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 -PowerDevice::SetAlarmOut(bool alarm_out_) +X68030PowerDevice::SetAlarmOut(bool alarm_out_) { alarm_out = alarm_out_; Change(); } -// システム内の電源オン信号を受け取る。 -// __ -// X68030 だと PW ON/OFF 信号(の反転)、 -// LUNA だと PIO1 の POWF* 信号で、どちらの場合も true がオン。 +// システムポートからの電源オフコマンド発行で false が来る。 +// 便宜上、電源投入時にはシステムポートがこれを true にする。 void -PowerDevice::SetSystemPowerOn(bool poweron) +X68030PowerDevice::SetSystemPowerOn(bool poweron) { system_poweron = poweron; Change(); @@ -207,41 +333,25 @@ PowerDevice::SetSystemPowerOn(bool power // 電源状態の変更。 // power_button、alarm_out、system_poweron のいずれかの変更で呼ぶこと。 void -PowerDevice::Change() +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) { - if (gMainApp.IsX68030()) { - DoPowerOff(MessageID::POWEROFF_EXIT); - } else { - scheduler->RestartEvent(event); - } + DoPowerOff(MessageID::POWEROFF_EXIT); } bool old_led = led; - if (gMainApp.GetVMType() == VMType::X68030) { - // X68030 の電源制御部の回路による。 - led = power_button | alarm_out; - } else { - // LUNA の場合は電源の状態そのまま? - led = ispower; - } + // 電源 LED は X68030 の電源制御部の回路による。 + led = power_button | alarm_out; + if (old_led != led) { // LED の状態が変わったことを UI に通知 - UIMessage::Post(UIMessage::LED); - } -} - -// LUNA の電源オフが信号状態の変化に対し 1msec 遅れて応答することを -// エミュレートするためのイベントコールバック -void -PowerDevice::PowerCallback(Event& ev) -{ - if (system_poweron == false) { - DoPowerOff(MessageID::POWEROFF_EXIT); + uimessage->Post(UIMessage::LED); } }