Files
MesenCE/Core/Shared/BaseControlManager.cpp
NovaSquirrel 6312748563 SNES: Add Turbo File Twin support (#109)
* SNES: Add Turbo File Twin support

* SNES: Try to make write mode flag more accurate

Hardware tests on Turbo File Twin seem to be showing that if you write data then it stops reporting that the write flag is on, despite letting you write more data

* SNES: Move bit array access to a utility

Also add note about how bit 26 in STF report is not fully verified

* SNES: Add behavior seen when reading without read command

When you turn the strobe on and off outside of a read command, the shift register gets reloaded with the most recently read or written byte

* NES, SNES: Emulator::SaveBattery() for saving console and controller

* Fix range limit in SetBitInArray

* Add notes about unknown aspects of TFII mode

* Add comments to make it clear what's unknown

* STF mode ignores out-of-range addresses

Also allocate _data instead of putting it in the class
2026-05-15 00:05:31 -07:00

245 lines
5.9 KiB
C++

#include "pch.h"
#include "Shared/BaseControlManager.h"
#include "Shared/Emulator.h"
#include "Shared/EmuSettings.h"
#include "Shared/KeyManager.h"
#include "Shared/ControllerHub.h"
#include "Shared/Interfaces/IKeyManager.h"
#include "Shared/Interfaces/IInputProvider.h"
#include "Shared/Interfaces/IInputRecorder.h"
#include "Shared/SystemActionManager.h"
#include "Shared/EventType.h"
#include "Shared/MessageManager.h"
#include "Utilities/Serializer.h"
#include "Interfaces/IBattery.h"
BaseControlManager::BaseControlManager(Emulator* emu, CpuType cpuType)
{
_emu = emu;
_cpuType = cpuType;
_pollCounter = 0;
AddSystemControlDevice(_emu->GetSystemActionManager());
UpdateControlDevices();
}
BaseControlManager::~BaseControlManager()
{
}
void BaseControlManager::AddSystemControlDevice(shared_ptr<BaseControlDevice> device)
{
_controlDevices.clear();
_systemDevices.push_back(device);
UpdateControlDevices();
}
void BaseControlManager::RegisterInputProvider(IInputProvider* provider)
{
auto lock = _deviceLock.AcquireSafe();
_inputProviders.push_back(provider);
}
void BaseControlManager::UnregisterInputProvider(IInputProvider* provider)
{
auto lock = _deviceLock.AcquireSafe();
vector<IInputProvider*>& vec = _inputProviders;
vec.erase(std::remove(vec.begin(), vec.end(), provider), vec.end());
}
void BaseControlManager::RegisterInputRecorder(IInputRecorder* provider)
{
auto lock = _deviceLock.AcquireSafe();
_inputRecorders.push_back(provider);
}
void BaseControlManager::UnregisterInputRecorder(IInputRecorder* provider)
{
auto lock = _deviceLock.AcquireSafe();
vector<IInputRecorder*>& vec = _inputRecorders;
vec.erase(std::remove(vec.begin(), vec.end(), provider), vec.end());
}
vector<ControllerData> BaseControlManager::GetPortStates()
{
vector<ControllerData> states;
for(shared_ptr<BaseControlDevice>& device : _controlDevices) {
states.push_back({ device->GetControllerType(), device->GetRawState(), device->GetPort() });
}
return states;
}
shared_ptr<BaseControlDevice> BaseControlManager::GetControlDevice(uint8_t port, uint8_t subPort)
{
auto lock = _deviceLock.AcquireSafe();
for(size_t i = 0; i < _controlDevices.size(); i++) {
if(_controlDevices[i] && _controlDevices[i]->GetPort() == port) {
shared_ptr<IControllerHub> hub = std::dynamic_pointer_cast<IControllerHub>(_controlDevices[i]);
if(hub) {
return hub->GetController(subPort);
} else {
return subPort == 0 ? _controlDevices[i] : nullptr;
}
}
}
return nullptr;
}
shared_ptr<BaseControlDevice> BaseControlManager::GetControlDeviceByIndex(uint8_t index)
{
auto lock = _deviceLock.AcquireSafe();
int counter = 0;
for(size_t i = 0; i < _controlDevices.size(); i++) {
if(_controlDevices[i] && _controlDevices[i]->GetPort() <= 2) {
shared_ptr<IControllerHub> hub = std::dynamic_pointer_cast<IControllerHub>(_controlDevices[i]);
if(hub) {
int portCount = hub->GetHubPortCount();
for(int j = 0; j < portCount; j++) {
shared_ptr<BaseControlDevice> device = hub->GetController(j);
if(counter == index) {
return device;
}
counter++;
}
} else {
if(counter == index) {
return _controlDevices[i];
}
counter++;
}
}
}
return nullptr;
}
void BaseControlManager::RefreshHubState()
{
auto lock = _deviceLock.AcquireSafe();
for(size_t i = 0; i < _controlDevices.size(); i++) {
if(_controlDevices[i] && _controlDevices[i]->GetPort() <= 2) {
shared_ptr<IControllerHub> hub = std::dynamic_pointer_cast<IControllerHub>(_controlDevices[i]);
if(hub) {
hub->RefreshHubState();
}
}
}
}
vector<shared_ptr<BaseControlDevice>> BaseControlManager::GetControlDevices()
{
return _controlDevices;
}
void BaseControlManager::Serialize(Serializer& s)
{
SV(_pollCounter);
}
void BaseControlManager::RegisterControlDevice(shared_ptr<BaseControlDevice> controlDevice)
{
controlDevice->Init();
_controlDevices.push_back(controlDevice);
}
void BaseControlManager::ClearDevices()
{
_controlDevices.clear();
for(shared_ptr<BaseControlDevice> device : _systemDevices) {
RegisterControlDevice(device);
}
}
void BaseControlManager::UpdateInputState()
{
KeyManager::RefreshKeyState();
auto lock = _deviceLock.AcquireSafe();
//string log = "F: " + std::to_string(_emu->GetFrameCount()) + " C:" + std::to_string(_pollCounter) + " ";
for(shared_ptr<BaseControlDevice>& device : _controlDevices) {
device->ClearState();
device->SetStateFromInput();
for(size_t i = 0; i < _inputProviders.size(); i++) {
IInputProvider* provider = _inputProviders[i];
if(provider->SetInput(device.get())) {
break;
}
}
device->OnAfterSetState();
//log += "|" + device->GetTextState();
}
_emu->ProcessEvent(EventType::InputPolled, _cpuType);
if(!_emu->IsRunAheadFrame()) {
for(IInputRecorder* recorder : _inputRecorders) {
recorder->RecordInput(_controlDevices);
}
}
//MessageManager::Log(log);
_pollCounter++;
}
void BaseControlManager::ProcessEndOfFrame()
{
if(!_wasInputRead) {
_lagCounter++;
}
_wasInputRead = false;
}
void BaseControlManager::SetInputReadFlag()
{
//Used for lag counter - any frame where the input is read does not count as lag
_wasInputRead = true;
}
uint32_t BaseControlManager::GetLagCounter()
{
return _lagCounter;
}
void BaseControlManager::ResetLagCounter()
{
_lagCounter = 0;
}
bool BaseControlManager::HasControlDevice(ControllerType type)
{
auto lock = _deviceLock.AcquireSafe();
for(shared_ptr<BaseControlDevice>& device : _controlDevices) {
if(device->HasControllerType(type)) {
return true;
}
}
return false;
}
uint32_t BaseControlManager::GetPollCounter()
{
return _pollCounter;
}
void BaseControlManager::SetPollCounter(uint32_t value)
{
_pollCounter = value;
}
void BaseControlManager::SaveBattery()
{
for(shared_ptr<BaseControlDevice>& device : _controlDevices) {
shared_ptr<IBattery> batteryDevice = std::dynamic_pointer_cast<IBattery>(device);
if(batteryDevice) {
batteryDevice->SaveBattery();
}
}
}