diff --git a/src/DSi_I2C.cpp b/src/DSi_I2C.cpp index a421430b..5d13b2a6 100644 --- a/src/DSi_I2C.cpp +++ b/src/DSi_I2C.cpp @@ -22,6 +22,7 @@ #include "DSi_I2C.h" #include "DSi_Camera.h" #include "ARM.h" +#include "SPI.h" namespace DSi_BPTWL @@ -82,6 +83,19 @@ void DoSavestate(Savestate* file) u8 GetBootFlag() { return Registers[0x70]; } +bool GetBatteryCharging() { return Registers[0x20] >> 7; } +void SetBatteryCharging(bool charging) +{ + Registers[0x20] = (((charging ? 0x8 : 0x0) << 4) | (Registers[0x20] & 0x0F)); +} + +u8 GetBatteryLevel() { return Registers[0x20] & 0xF; } +void SetBatteryLevel(u8 batteryLevel) +{ + Registers[0x20] = ((Registers[0x20] & 0xF0) | (batteryLevel & 0x0F)); + SPI_Powerman::SetBatteryLevelOkay(batteryLevel > batteryLevel_Low ? true : false); +} + void Start() { //printf("BPTWL: start\n"); diff --git a/src/DSi_I2C.h b/src/DSi_I2C.h index b6313032..7350fb5a 100644 --- a/src/DSi_I2C.h +++ b/src/DSi_I2C.h @@ -19,11 +19,28 @@ #ifndef DSI_I2C_H #define DSI_I2C_H +#include "types.h" + namespace DSi_BPTWL { u8 GetBootFlag(); +bool GetBatteryCharging(); +void SetBatteryCharging(bool charging); + +enum +{ + batteryLevel_Critical = 0x0, + batteryLevel_AlmostEmpty = 0x1, + batteryLevel_Low = 0x3, + batteryLevel_Half = 0x7, + batteryLevel_ThreeQuarters = 0xB, + batteryLevel_Full = 0xF +}; + +u8 GetBatteryLevel(); +void SetBatteryLevel(u8 batteryLevel); } namespace DSi_I2C diff --git a/src/SPI.cpp b/src/SPI.cpp index 26aab8f9..009fb32f 100644 --- a/src/SPI.cpp +++ b/src/SPI.cpp @@ -624,6 +624,9 @@ void Reset() RegMasks[4] = 0x0F; } +bool GetBatteryLevelOkay() { return !Registers[1]; } +void SetBatteryLevelOkay(bool okay) { Registers[1] = okay ? 0x00 : 0x01; } + void DoSavestate(Savestate* file) { file->Section("SPPW"); diff --git a/src/SPI.h b/src/SPI.h index 10a8a0dc..8ac39484 100644 --- a/src/SPI.h +++ b/src/SPI.h @@ -37,6 +37,14 @@ u8* GetWifiMAC(); } +namespace SPI_Powerman +{ + +bool GetBatteryLevelOkay(); +void SetBatteryLevelOkay(bool okay); + +} + namespace SPI_TSC { diff --git a/src/frontend/qt_sdl/CMakeLists.txt b/src/frontend/qt_sdl/CMakeLists.txt index 8b29baec..ec88026f 100644 --- a/src/frontend/qt_sdl/CMakeLists.txt +++ b/src/frontend/qt_sdl/CMakeLists.txt @@ -6,6 +6,8 @@ SET(SOURCES_QT_SDL CheatsDialog.cpp Config.cpp EmuSettingsDialog.cpp + PowerManagement/PowerManagementDialog.cpp + PowerManagement/resources/battery.qrc InputConfig/InputConfigDialog.cpp InputConfig/MapButton.h InputConfig/resources/ds.qrc diff --git a/src/frontend/qt_sdl/PowerManagement/PowerManagementDialog.cpp b/src/frontend/qt_sdl/PowerManagement/PowerManagementDialog.cpp new file mode 100644 index 00000000..b67736a0 --- /dev/null +++ b/src/frontend/qt_sdl/PowerManagement/PowerManagementDialog.cpp @@ -0,0 +1,106 @@ +/* + Copyright 2016-2021 Rayyan Ansari + + This file is part of melonDS. + + melonDS is free software: you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + melonDS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with melonDS. If not, see http://www.gnu.org/licenses/. +*/ + +#include "PowerManagementDialog.h" +#include "ui_PowerManagementDialog.h" + +#include "SPI.h" +#include "DSi_I2C.h" +#include "NDS.h" + +#include "types.h" + +#include + +PowerManagementDialog* PowerManagementDialog::currentDlg = nullptr; + +PowerManagementDialog::PowerManagementDialog(QWidget* parent) : QDialog(parent), ui(new Ui::PowerManagementDialog) +{ + ui->setupUi(this); + setAttribute(Qt::WA_DeleteOnClose); + + if (NDS::ConsoleType) + ui->grpDSBattery->setEnabled(false); + else + ui->grpDSiBattery->setEnabled(false); + + updateDSBatteryLevelControls(); + + ui->cbDSiBatteryCharging->setChecked(DSi_BPTWL::GetBatteryCharging()); + int dsiBatterySliderPos; + switch (DSi_BPTWL::GetBatteryLevel()) + { + case DSi_BPTWL::batteryLevel_AlmostEmpty: dsiBatterySliderPos = 0; break; + case DSi_BPTWL::batteryLevel_Low: dsiBatterySliderPos = 1; break; + case DSi_BPTWL::batteryLevel_Half: dsiBatterySliderPos = 2; break; + case DSi_BPTWL::batteryLevel_ThreeQuarters: dsiBatterySliderPos = 3; break; + case DSi_BPTWL::batteryLevel_Full: dsiBatterySliderPos = 4; break; + } + ui->sliderDSiBatteryLevel->setValue(dsiBatterySliderPos); +} + +PowerManagementDialog::~PowerManagementDialog() +{ + delete ui; +} + +void PowerManagementDialog::done(int r) +{ + QDialog::done(r); + + closeDlg(); +} + +void PowerManagementDialog::on_rbDSBatteryLow_clicked() +{ + SPI_Powerman::SetBatteryLevelOkay(false); +} + +void PowerManagementDialog::on_rbDSBatteryOkay_clicked() +{ + SPI_Powerman::SetBatteryLevelOkay(true); +} + +void PowerManagementDialog::updateDSBatteryLevelControls() +{ + if (SPI_Powerman::GetBatteryLevelOkay()) + ui->rbDSBatteryOkay->setChecked(true); + else + ui->rbDSBatteryLow->setChecked(true); +} + +void PowerManagementDialog::on_cbDSiBatteryCharging_toggled() +{ + DSi_BPTWL::SetBatteryCharging(ui->cbDSiBatteryCharging->isChecked()); +} + +void PowerManagementDialog::on_sliderDSiBatteryLevel_valueChanged(int value) +{ + u8 newBatteryLevel; + switch (value) + { + case 0: newBatteryLevel = DSi_BPTWL::batteryLevel_AlmostEmpty; break; + case 1: newBatteryLevel = DSi_BPTWL::batteryLevel_Low; break; + case 2: newBatteryLevel = DSi_BPTWL::batteryLevel_Half; break; + case 3: newBatteryLevel = DSi_BPTWL::batteryLevel_ThreeQuarters; break; + case 4: newBatteryLevel = DSi_BPTWL::batteryLevel_Full; break; + } + DSi_BPTWL::SetBatteryLevel(newBatteryLevel); + updateDSBatteryLevelControls(); +} + diff --git a/src/frontend/qt_sdl/PowerManagement/PowerManagementDialog.h b/src/frontend/qt_sdl/PowerManagement/PowerManagementDialog.h new file mode 100644 index 00000000..c9f3b4a8 --- /dev/null +++ b/src/frontend/qt_sdl/PowerManagement/PowerManagementDialog.h @@ -0,0 +1,69 @@ +/* + Copyright 2016-2021 Rayyan Ansari + This file is part of melonDS. + + melonDS is free software: you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + melonDS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with melonDS. If not, see http://www.gnu.org/licenses/. +*/ + +#ifndef POWERMANAGEMENTDIALOG_H +#define POWERMANAGEMENTDIALOG_H + +#include +#include + +namespace Ui { class PowerManagementDialog; } +class PowerManagementDialog; + +class PowerManagementDialog : public QDialog +{ + Q_OBJECT + +public: + explicit PowerManagementDialog(QWidget* parent); + ~PowerManagementDialog(); + + static PowerManagementDialog* currentDlg; + static PowerManagementDialog* openDlg(QWidget* parent) + { + if (currentDlg) + { + currentDlg->activateWindow(); + return currentDlg; + } + + currentDlg = new PowerManagementDialog(parent); + currentDlg->open(); + return currentDlg; + } + static void closeDlg() + { + currentDlg = nullptr; + } + +private slots: + void done(int r); + + void on_rbDSBatteryLow_clicked(); + void on_rbDSBatteryOkay_clicked(); + + void on_cbDSiBatteryCharging_toggled(); + void on_sliderDSiBatteryLevel_valueChanged(int value); + +private: + Ui::PowerManagementDialog* ui; + + void updateDSBatteryLevelControls(); +}; + +#endif // POWERMANAGEMENTDIALOG_H + diff --git a/src/frontend/qt_sdl/PowerManagement/PowerManagementDialog.ui b/src/frontend/qt_sdl/PowerManagement/PowerManagementDialog.ui new file mode 100644 index 00000000..a2c12160 --- /dev/null +++ b/src/frontend/qt_sdl/PowerManagement/PowerManagementDialog.ui @@ -0,0 +1,258 @@ + + + PowerManagementDialog + + + + 0 + 0 + 562 + 279 + + + + + 0 + 0 + + + + Power management - melonDS + + + + + + DS Battery + + + + + + Low + + + + + + + Battery Level + + + + + + + Okay + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + DSi Battery + + + + + + Almost Empty + + + + + + + Qt::Horizontal + + + QSizePolicy::Preferred + + + + 20 + 20 + + + + + + + + Charging + + + + + + + Full + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Battery Level + + + Qt::AlignCenter + + + + + + + + + + :/dsibattery/dsi_batteryalmostempty.svg + + + false + + + + + + + + + + :/dsibattery/dsi_batterylow.svg + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + + + :/dsibattery/dsi_battery2.svg + + + Qt::AlignCenter + + + + + + + + + + :/dsibattery/dsi_battery3.svg + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + :/dsibattery/dsi_batteryfull.svg + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 4 + + + 1 + + + Qt::Horizontal + + + QSlider::TicksBothSides + + + 1 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + buttonBox + accepted() + PowerManagementDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + PowerManagementDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/frontend/qt_sdl/PowerManagement/resources/battery.qrc b/src/frontend/qt_sdl/PowerManagement/resources/battery.qrc new file mode 100644 index 00000000..7f9c95b4 --- /dev/null +++ b/src/frontend/qt_sdl/PowerManagement/resources/battery.qrc @@ -0,0 +1,9 @@ + + + dsi_batteryalmostempty.svg + dsi_batterylow.svg + dsi_battery2.svg + dsi_battery3.svg + dsi_batteryfull.svg + + diff --git a/src/frontend/qt_sdl/PowerManagement/resources/dsi_battery2.svg b/src/frontend/qt_sdl/PowerManagement/resources/dsi_battery2.svg new file mode 100644 index 00000000..e9c4b758 --- /dev/null +++ b/src/frontend/qt_sdl/PowerManagement/resources/dsi_battery2.svg @@ -0,0 +1,171 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/frontend/qt_sdl/PowerManagement/resources/dsi_battery3.svg b/src/frontend/qt_sdl/PowerManagement/resources/dsi_battery3.svg new file mode 100644 index 00000000..d464ef36 --- /dev/null +++ b/src/frontend/qt_sdl/PowerManagement/resources/dsi_battery3.svg @@ -0,0 +1,171 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/frontend/qt_sdl/PowerManagement/resources/dsi_batteryalmostempty.svg b/src/frontend/qt_sdl/PowerManagement/resources/dsi_batteryalmostempty.svg new file mode 100644 index 00000000..4f598fad --- /dev/null +++ b/src/frontend/qt_sdl/PowerManagement/resources/dsi_batteryalmostempty.svg @@ -0,0 +1,171 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/frontend/qt_sdl/PowerManagement/resources/dsi_batteryfull.svg b/src/frontend/qt_sdl/PowerManagement/resources/dsi_batteryfull.svg new file mode 100644 index 00000000..dbf84994 --- /dev/null +++ b/src/frontend/qt_sdl/PowerManagement/resources/dsi_batteryfull.svg @@ -0,0 +1,171 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/frontend/qt_sdl/PowerManagement/resources/dsi_batterylow.svg b/src/frontend/qt_sdl/PowerManagement/resources/dsi_batterylow.svg new file mode 100644 index 00000000..d337675b --- /dev/null +++ b/src/frontend/qt_sdl/PowerManagement/resources/dsi_batterylow.svg @@ -0,0 +1,171 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp index 7454ffc5..1296bb9c 100644 --- a/src/frontend/qt_sdl/main.cpp +++ b/src/frontend/qt_sdl/main.cpp @@ -62,6 +62,7 @@ #include "ROMInfoDialog.h" #include "RAMInfoDialog.h" #include "TitleManagerDialog.h" +#include "PowerManagement/PowerManagementDialog.h" #include "types.h" #include "version.h" @@ -1429,6 +1430,11 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) menu->addSeparator(); + actPowerManagement = menu->addAction("Power management"); + connect(actPowerManagement, &QAction::triggered, this, &MainWindow::onOpenPowerManagement); + + menu->addSeparator(); + actEnableCheats = menu->addAction("Enable cheats"); actEnableCheats->setCheckable(true); connect(actEnableCheats, &QAction::triggered, this, &MainWindow::onEnableCheats); @@ -1669,6 +1675,8 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) actStop->setEnabled(false); actFrameStep->setEnabled(false); + actPowerManagement->setEnabled(false); + actSetupCheats->setEnabled(false); actTitleManager->setEnabled(!Config::DSiNANDPath.empty()); @@ -2609,6 +2617,11 @@ void MainWindow::onEmuSettingsDialogFinished(int res) actTitleManager->setEnabled(!Config::DSiNANDPath.empty()); } +void MainWindow::onOpenPowerManagement() +{ + PowerManagementDialog* dlg = PowerManagementDialog::openDlg(this); +} + void MainWindow::onOpenInputConfig() { emuThread->emuPause(); @@ -2896,6 +2909,8 @@ void MainWindow::onEmuStart() actStop->setEnabled(true); actFrameStep->setEnabled(true); + actPowerManagement->setEnabled(true); + actTitleManager->setEnabled(false); } @@ -2915,6 +2930,8 @@ void MainWindow::onEmuStop() actStop->setEnabled(false); actFrameStep->setEnabled(false); + actPowerManagement->setEnabled(false); + actTitleManager->setEnabled(!Config::DSiNANDPath.empty()); } diff --git a/src/frontend/qt_sdl/main.h b/src/frontend/qt_sdl/main.h index 6929d69a..6466e3b9 100644 --- a/src/frontend/qt_sdl/main.h +++ b/src/frontend/qt_sdl/main.h @@ -257,6 +257,7 @@ private slots: void onOpenEmuSettings(); void onEmuSettingsDialogFinished(int res); + void onOpenPowerManagement(); void onOpenInputConfig(); void onInputConfigFinished(int res); void onOpenVideoSettings(); @@ -346,6 +347,7 @@ public: QAction* actTitleManager; QAction* actEmuSettings; + QAction* actPowerManagement; QAction* actInputConfig; QAction* actVideoSettings; QAction* actAudioSettings;