RTC revamp (#1867)

* get this started

* implement DSi RTC commands

* set up RTC clock timer. lay down basic idea of a clock.

* make the date/time registers writable

* move RTC state to its own structure, to make it easier to deal with

* more RTC work
lay base for date/time dialog

* get the bulk of the RTC functionality going

* much simpler design for RTC stuff

* aha, that is what it is

* start working on the RTC IRQ

* implement all types of RTC IRQ

* start refining sleep mode. code still kinda sucks.

* implement keypad IRQ

* refine it some more

* shut the fuck uuuuuupppppppppppppp
This commit is contained in:
Arisotura
2023-10-30 18:37:49 +01:00
committed by GitHub
parent 21590b0709
commit 9a450f5f28
21 changed files with 1470 additions and 214 deletions

View File

@ -7,6 +7,7 @@ set(SOURCES_QT_SDL
main_shaders.h
CheatsDialog.cpp
Config.cpp
DateTimeDialog.cpp
EmuSettingsDialog.cpp
PowerManagement/PowerManagementDialog.cpp
PowerManagement/resources/battery.qrc

View File

@ -19,6 +19,7 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#include "Platform.h"
#include "Config.h"
@ -140,6 +141,8 @@ int MouseHideSeconds;
bool PauseLostFocus;
int64_t RTCOffset;
bool DSBatteryLevelOkay;
int DSiBatteryLevel;
bool DSiBatteryCharging;
@ -339,6 +342,8 @@ ConfigEntry ConfigFile[] =
{"MouseHideSeconds", 0, &MouseHideSeconds, 5, false},
{"PauseLostFocus", 1, &PauseLostFocus, false, false},
{"RTCOffset", 3, &RTCOffset, (int64_t)0, true},
{"DSBatteryLevelOkay", 1, &DSBatteryLevelOkay, true, true},
{"DSiBatteryLevel", 0, &DSiBatteryLevel, 0xF, true},
{"DSiBatteryCharging", 1, &DSiBatteryCharging, true, true},
@ -406,6 +411,7 @@ void LoadFile(int inst)
case 0: *(int*)entry->Value = strtol(entryval, NULL, 10); break;
case 1: *(bool*)entry->Value = strtol(entryval, NULL, 10) ? true:false; break;
case 2: *(std::string*)entry->Value = entryval; break;
case 3: *(int64_t*)entry->Value = strtoll(entryval, NULL, 10); break;
}
break;
@ -426,6 +432,7 @@ void Load()
case 0: *(int*)entry->Value = std::get<int>(entry->Default); break;
case 1: *(bool*)entry->Value = std::get<bool>(entry->Default); break;
case 2: *(std::string*)entry->Value = std::get<std::string>(entry->Default); break;
case 3: *(int64_t*)entry->Value = std::get<int64_t>(entry->Default); break;
}
}
@ -462,6 +469,7 @@ void Save()
case 0: Platform::FileWriteFormatted(f, "%s=%d\r\n", entry->Name, *(int*)entry->Value); break;
case 1: Platform::FileWriteFormatted(f, "%s=%d\r\n", entry->Name, *(bool*)entry->Value ? 1:0); break;
case 2: Platform::FileWriteFormatted(f, "%s=%s\r\n", entry->Name, (*(std::string*)entry->Value).c_str()); break;
case 3: Platform::FileWriteFormatted(f, "%s=%" PRId64 "\r\n", entry->Name, *(int64_t*)entry->Value); break;
}
}

View File

@ -57,9 +57,9 @@ namespace Config
struct ConfigEntry
{
char Name[32];
int Type; // 0=int 1=bool 2=string
int Type; // 0=int 1=bool 2=string 3=64bit int
void* Value; // pointer to the value variable
std::variant<int, bool, std::string> Default;
std::variant<int, bool, std::string, int64_t> Default;
bool InstanceUnique; // whether the setting can exist individually for each instance in multiplayer
};
@ -185,6 +185,8 @@ extern bool MouseHide;
extern int MouseHideSeconds;
extern bool PauseLostFocus;
extern int64_t RTCOffset;
extern bool DSBatteryLevelOkay;
extern int DSiBatteryLevel;
extern bool DSiBatteryCharging;

View File

@ -0,0 +1,91 @@
/*
Copyright 2016-2022 melonDS team
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 <stdio.h>
#include "types.h"
#include "Config.h"
#include "DateTimeDialog.h"
#include "ui_DateTimeDialog.h"
DateTimeDialog* DateTimeDialog::currentDlg = nullptr;
DateTimeDialog::DateTimeDialog(QWidget* parent) : QDialog(parent), ui(new Ui::DateTimeDialog)
{
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
QDateTime now = QDateTime::currentDateTime();
customTime = now.addSecs(Config::RTCOffset);
ui->chkChangeTime->setChecked(false);
ui->chkResetTime->setChecked(false);
ui->lblCustomTime->setText(customTime.toString(ui->txtNewCustomTime->displayFormat()));
startTimer(1000);
ui->txtNewCustomTime->setEnabled(ui->chkChangeTime->isChecked());
}
DateTimeDialog::~DateTimeDialog()
{
delete ui;
}
void DateTimeDialog::timerEvent(QTimerEvent* event)
{
customTime = customTime.addSecs(1);
ui->lblCustomTime->setText(customTime.toString(ui->txtNewCustomTime->displayFormat()));
}
void DateTimeDialog::done(int r)
{
if (r == QDialog::Accepted)
{
if (ui->chkChangeTime->isChecked())
{
QDateTime now = QDateTime::currentDateTime();
Config::RTCOffset = now.secsTo(ui->txtNewCustomTime->dateTime());
}
else if (ui->chkResetTime->isChecked())
Config::RTCOffset = 0;
Config::Save();
}
QDialog::done(r);
closeDlg();
}
void DateTimeDialog::on_chkChangeTime_clicked(bool checked)
{
if (checked) ui->chkResetTime->setChecked(false);
ui->txtNewCustomTime->setEnabled(checked);
}
void DateTimeDialog::on_chkResetTime_clicked(bool checked)
{
if (checked)
{
ui->chkChangeTime->setChecked(false);
ui->txtNewCustomTime->setEnabled(false);
}
}

View File

@ -0,0 +1,70 @@
/*
Copyright 2016-2022 melonDS team
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 DATETIMEDIALOG_H
#define DATETIMEDIALOG_H
#include <QDialog>
#include <QButtonGroup>
#include <QDateTime>
namespace Ui {class DateTimeDialog; }
class DateTimeDialog;
class DateTimeDialog : public QDialog
{
Q_OBJECT
public:
explicit DateTimeDialog(QWidget* parent);
~DateTimeDialog();
static DateTimeDialog* currentDlg;
static DateTimeDialog* openDlg(QWidget* parent)
{
if (currentDlg)
{
currentDlg->activateWindow();
return currentDlg;
}
currentDlg = new DateTimeDialog(parent);
currentDlg->open();
return currentDlg;
}
static void closeDlg()
{
currentDlg = nullptr;
}
protected:
void timerEvent(QTimerEvent* event) override;
private slots:
void done(int r);
void on_chkChangeTime_clicked(bool checked);
void on_chkResetTime_clicked(bool checked);
private:
Ui::DateTimeDialog* ui;
QDateTime customTime;
};
#endif // DATETIMEDIALOG_H

View File

@ -0,0 +1,148 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DateTimeDialog</class>
<widget class="QDialog" name="DateTimeDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>357</width>
<height>161</height>
</rect>
</property>
<property name="windowTitle">
<string>Date and time - melonDS</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Date and time</string>
</property>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Current value:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="lblCustomTime">
<property name="text">
<string>[placeholder]</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="chkChangeTime">
<property name="text">
<string>Change to:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDateTimeEdit" name="txtNewCustomTime">
<property name="dateTime">
<datetime>
<hour>0</hour>
<minute>0</minute>
<second>0</second>
<year>2000</year>
<month>1</month>
<day>1</day>
</datetime>
</property>
<property name="maximumDateTime">
<datetime>
<hour>23</hour>
<minute>59</minute>
<second>59</second>
<year>2099</year>
<month>12</month>
<day>31</day>
</datetime>
</property>
<property name="minimumDateTime">
<datetime>
<hour>0</hour>
<minute>0</minute>
<second>0</second>
<year>2000</year>
<month>1</month>
<day>1</day>
</datetime>
</property>
<property name="displayFormat">
<string>dd/MM/yyyy HH:mm:ss</string>
</property>
<property name="calendarPopup">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QCheckBox" name="chkResetTime">
<property name="text">
<string>Reset to system date and time</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>DateTimeDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>DateTimeDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -23,6 +23,7 @@
#include <string>
#include <QStandardPaths>
#include <QString>
#include <QDateTime>
#include <QDir>
#include <QThread>
#include <QSemaphore>
@ -610,6 +611,15 @@ void WriteFirmware(const SPI_Firmware::Firmware& firmware, u32 writeoffset, u32
}
void WriteDateTime(int year, int month, int day, int hour, int minute, int second)
{
QDateTime hosttime = QDateTime::currentDateTime();
QDateTime time = QDateTime(QDate(year, month, day), QTime(hour, minute, second));
Config::RTCOffset = hosttime.secsTo(time);
Config::Save();
}
bool MP_Init()
{
return LocalMP::Init();

View File

@ -28,6 +28,8 @@
#include <utility>
#include <fstream>
#include <QDateTime>
#include <zstd.h>
#ifdef ARCHIVE_SUPPORT_ENABLED
#include "ArchiveUtil.h"
@ -39,6 +41,7 @@
#include "NDS.h"
#include "DSi.h"
#include "SPI.h"
#include "RTC.h"
#include "DSi_I2C.h"
#include "FreeBIOS.h"
@ -589,6 +592,15 @@ void SetBatteryLevels()
}
}
void SetDateTime()
{
QDateTime hosttime = QDateTime::currentDateTime();
QDateTime time = hosttime.addSecs(Config::RTCOffset);
RTC::SetDateTime(time.date().year(), time.date().month(), time.date().day(),
time.time().hour(), time.time().minute(), time.time().second());
}
void Reset()
{
NDS::SetConsoleType(Config::ConsoleType);
@ -602,6 +614,7 @@ void Reset()
}
NDS::Reset();
SetBatteryLevels();
SetDateTime();
if ((CartType != -1) && NDSSave)
{
@ -678,6 +691,7 @@ bool LoadBIOS()
NDS::Reset();
SetBatteryLevels();
SetDateTime();
return true;
}
@ -1204,6 +1218,7 @@ bool LoadROM(QStringList filepath, bool reset)
NDS::Reset();
SetBatteryLevels();
SetDateTime();
}
u32 savelen = 0;

View File

@ -58,6 +58,7 @@
#include "main.h"
#include "Input.h"
#include "CheatsDialog.h"
#include "DateTimeDialog.h"
#include "EmuSettingsDialog.h"
#include "InputConfig/InputConfigDialog.h"
#include "VideoSettingsDialog.h"
@ -90,6 +91,7 @@
#include "LocalMP.h"
#include "Config.h"
#include "DSi_I2C.h"
#include "RTC.h"
#include "Savestate.h"
@ -313,6 +315,7 @@ void EmuThread::deinitOpenGL()
void EmuThread::run()
{
u32 mainScreenPos[3];
Platform::FileHandle* file;
NDS::Init();
@ -352,6 +355,15 @@ void EmuThread::run()
u32 winUpdateCount = 0, winUpdateFreq = 1;
u8 dsiVolumeLevel = 0x1F;
file = Platform::OpenLocalFile("rtc.bin", Platform::FileMode::Read);
if (file)
{
RTC::StateData state;
Platform::FileRead(&state, sizeof(state), 1, file);
Platform::CloseFile(file);
RTC::SetState(state);
}
char melontitle[100];
while (EmuRunning != emuStatus_Exit)
@ -650,6 +662,15 @@ void EmuThread::run()
}
}
file = Platform::OpenLocalFile("rtc.bin", Platform::FileMode::Write);
if (file)
{
RTC::StateData state;
RTC::GetState(state);
Platform::FileWrite(&state, sizeof(state), 1, file);
Platform::CloseFile(file);
}
EmuStatus = emuStatus_Exit;
GPU::DeInitRenderer();
@ -1525,6 +1546,9 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
actPowerManagement = menu->addAction("Power management");
connect(actPowerManagement, &QAction::triggered, this, &MainWindow::onOpenPowerManagement);
actDateTime = menu->addAction("Date and time");
connect(actDateTime, &QAction::triggered, this, &MainWindow::onOpenDateTime);
menu->addSeparator();
actEnableCheats = menu->addAction("Enable cheats");
@ -1787,6 +1811,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
actStop->setEnabled(false);
actFrameStep->setEnabled(false);
actDateTime->setEnabled(true);
actPowerManagement->setEnabled(false);
actSetupCheats->setEnabled(false);
@ -2737,6 +2762,16 @@ void MainWindow::onFrameStep()
emuThread->emuFrameStep();
}
void MainWindow::onOpenDateTime()
{
DateTimeDialog* dlg = DateTimeDialog::openDlg(this);
}
void MainWindow::onOpenPowerManagement()
{
PowerManagementDialog* dlg = PowerManagementDialog::openDlg(this);
}
void MainWindow::onEnableCheats(bool checked)
{
Config::EnableCheats = checked?1:0;
@ -2824,11 +2859,6 @@ void MainWindow::onEmuSettingsDialogFinished(int res)
actTitleManager->setEnabled(!Config::DSiNANDPath.empty());
}
void MainWindow::onOpenPowerManagement()
{
PowerManagementDialog* dlg = PowerManagementDialog::openDlg(this);
}
void MainWindow::onOpenInputConfig()
{
emuThread->emuPause();
@ -3148,6 +3178,7 @@ void MainWindow::onEmuStart()
actStop->setEnabled(true);
actFrameStep->setEnabled(true);
actDateTime->setEnabled(false);
actPowerManagement->setEnabled(true);
actTitleManager->setEnabled(false);
@ -3169,6 +3200,7 @@ void MainWindow::onEmuStop()
actStop->setEnabled(false);
actFrameStep->setEnabled(false);
actDateTime->setEnabled(true);
actPowerManagement->setEnabled(false);
actTitleManager->setEnabled(!Config::DSiNANDPath.empty());

View File

@ -299,6 +299,8 @@ private slots:
void onReset();
void onStop();
void onFrameStep();
void onOpenPowerManagement();
void onOpenDateTime();
void onEnableCheats(bool checked);
void onSetupCheats();
void onCheatsDialogFinished(int res);
@ -309,7 +311,6 @@ private slots:
void onOpenEmuSettings();
void onEmuSettingsDialogFinished(int res);
void onOpenPowerManagement();
void onOpenInputConfig();
void onInputConfigFinished(int res);
void onOpenVideoSettings();
@ -397,6 +398,8 @@ public:
QAction* actReset;
QAction* actStop;
QAction* actFrameStep;
QAction* actPowerManagement;
QAction* actDateTime;
QAction* actEnableCheats;
QAction* actSetupCheats;
QAction* actROMInfo;
@ -408,7 +411,6 @@ public:
#ifdef __APPLE__
QAction* actPreferences;
#endif
QAction* actPowerManagement;
QAction* actInputConfig;
QAction* actVideoSettings;
QAction* actCameraSettings;