mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-07-04 22:32:57 +12:00
IR: Move to scheduler
This commit is contained in:
parent
b2904f391f
commit
dc7f8a48bd
7 changed files with 29 additions and 14 deletions
|
@ -12,7 +12,8 @@ struct Scheduler {
|
||||||
UpdateTimers = 1, // Update kernel timer objects
|
UpdateTimers = 1, // Update kernel timer objects
|
||||||
RunDSP = 2, // Make the emulated DSP run for one audio frame
|
RunDSP = 2, // Make the emulated DSP run for one audio frame
|
||||||
SignalY2R = 3, // Signal that a Y2R conversion has finished
|
SignalY2R = 3, // Signal that a Y2R conversion has finished
|
||||||
Panic = 4, // Dummy event that is always pending and should never be triggered (Timestamp = UINT64_MAX)
|
UpdateIR = 4, // Update an IR device (For now, just the CirclePad Pro/N3DS controls)
|
||||||
|
Panic = 5, // Dummy event that is always pending and should never be triggered (Timestamp = UINT64_MAX)
|
||||||
TotalNumberOfEvents // How many event types do we have in total?
|
TotalNumberOfEvents // How many event types do we have in total?
|
||||||
};
|
};
|
||||||
static constexpr usize totalNumberOfEvents = static_cast<usize>(EventType::TotalNumberOfEvents);
|
static constexpr usize totalNumberOfEvents = static_cast<usize>(EventType::TotalNumberOfEvents);
|
||||||
|
|
|
@ -44,7 +44,10 @@ namespace IR {
|
||||||
virtual void disconnect() override;
|
virtual void disconnect() override;
|
||||||
virtual void receivePayload(Payload payload) override;
|
virtual void receivePayload(Payload payload) override;
|
||||||
|
|
||||||
CirclePadPro(SendCallback sendCallback) : IR::Device(sendCallback) {}
|
CirclePadPro(SendCallback sendCallback, Scheduler& scheduler) : IR::Device(sendCallback, scheduler) {}
|
||||||
|
|
||||||
ButtonState state;
|
ButtonState state;
|
||||||
|
// The current polling period in cycles, configured via the ConfigurePolling command
|
||||||
|
s64 period = Scheduler::nsToCycles(16000);
|
||||||
};
|
};
|
||||||
} // namespace IR
|
} // namespace IR
|
|
@ -3,6 +3,7 @@
|
||||||
#include <span>
|
#include <span>
|
||||||
|
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
|
#include "scheduler.hpp"
|
||||||
|
|
||||||
namespace IR {
|
namespace IR {
|
||||||
class Device {
|
class Device {
|
||||||
|
@ -11,6 +12,7 @@ namespace IR {
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
using SendCallback = std::function<void(Payload)>; // Callback for sending data from IR device->3DS
|
using SendCallback = std::function<void(Payload)>; // Callback for sending data from IR device->3DS
|
||||||
|
Scheduler& scheduler;
|
||||||
SendCallback sendCallback;
|
SendCallback sendCallback;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -18,6 +20,6 @@ namespace IR {
|
||||||
virtual void disconnect() = 0;
|
virtual void disconnect() = 0;
|
||||||
virtual void receivePayload(Payload payload) = 0;
|
virtual void receivePayload(Payload payload) = 0;
|
||||||
|
|
||||||
Device(SendCallback sendCallback) : sendCallback(sendCallback) {}
|
Device(SendCallback sendCallback, Scheduler& scheduler) : sendCallback(sendCallback), scheduler(scheduler) {}
|
||||||
};
|
};
|
||||||
} // namespace IR
|
} // namespace IR
|
|
@ -16,6 +16,7 @@
|
||||||
class Kernel;
|
class Kernel;
|
||||||
|
|
||||||
class IRUserService {
|
class IRUserService {
|
||||||
|
using Payload = IR::Device::Payload;
|
||||||
using Handle = HorizonHandle;
|
using Handle = HorizonHandle;
|
||||||
|
|
||||||
enum class DeviceID : u8 {
|
enum class DeviceID : u8 {
|
||||||
|
@ -75,14 +76,11 @@ class IRUserService {
|
||||||
// The IR service uses CRC8 with generator polynomial = 0x07 for verifying packets received from IR devices
|
// The IR service uses CRC8 with generator polynomial = 0x07 for verifying packets received from IR devices
|
||||||
static u8 crc8(std::span<const u8> data);
|
static u8 crc8(std::span<const u8> data);
|
||||||
|
|
||||||
// IR service calls this to send a console->device payload
|
|
||||||
void receivePayload(std::span<const u8> data);
|
|
||||||
// IR devices call this to send a device->console payload
|
// IR devices call this to send a device->console payload
|
||||||
void sendPayload(std::span<const u8> payload);
|
void sendPayload(Payload payload);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IRUserService(Memory& mem, HIDService& hid, const EmulatorConfig& config, Kernel& kernel)
|
IRUserService(Memory& mem, HIDService& hid, const EmulatorConfig& config, Kernel& kernel);
|
||||||
: mem(mem), hid(hid), config(config), kernel(kernel), cpp([&](IR::Device::Payload payload) { sendPayload(payload); }) {}
|
|
||||||
|
|
||||||
void setCStickX(s16 value) { cpp.state.cStick.x = value; }
|
void setCStickX(s16 value) { cpp.state.cStick.x = value; }
|
||||||
void setCStickY(s16 value) { cpp.state.cStick.y = value; }
|
void setCStickY(s16 value) { cpp.state.cStick.y = value; }
|
||||||
|
|
|
@ -7,15 +7,20 @@
|
||||||
using namespace IR;
|
using namespace IR;
|
||||||
|
|
||||||
void CirclePadPro::connect() {}
|
void CirclePadPro::connect() {}
|
||||||
void CirclePadPro::disconnect() {}
|
void CirclePadPro::disconnect() { scheduler.removeEvent(Scheduler::EventType::UpdateIR); }
|
||||||
|
|
||||||
void CirclePadPro::receivePayload(Payload payload) {
|
void CirclePadPro::receivePayload(Payload payload) {
|
||||||
const u8 type = payload[0];
|
const u8 type = payload[0];
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case CPPRequestID::ConfigurePolling: {
|
case CPPRequestID::ConfigurePolling: {
|
||||||
[[maybe_unused]] const u8 pollingPeriodMs = payload[1];
|
// Convert polling period from ms to ns for easier use with the scheduler
|
||||||
// TODO
|
const s64 periodNs = s64(payload[1]) * 1000ll;
|
||||||
|
// Convert to cycles
|
||||||
|
period = Scheduler::nsToCycles(periodNs);
|
||||||
|
|
||||||
|
scheduler.removeEvent(Scheduler::EventType::UpdateIR);
|
||||||
|
scheduler.addEvent(Scheduler::EventType::UpdateIR, scheduler.currentTimestamp + period);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,9 @@ namespace IRUserCommands {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IRUserService::IRUserService(Memory& mem, HIDService& hid, const EmulatorConfig& config, Kernel& kernel)
|
||||||
|
: mem(mem), hid(hid), config(config), kernel(kernel), cpp([&](IR::Device::Payload payload) { sendPayload(payload); }, kernel.getScheduler()) {}
|
||||||
|
|
||||||
void IRUserService::reset() {
|
void IRUserService::reset() {
|
||||||
connectionStatusEvent = std::nullopt;
|
connectionStatusEvent = std::nullopt;
|
||||||
receiveEvent = std::nullopt;
|
receiveEvent = std::nullopt;
|
||||||
|
@ -285,7 +288,7 @@ void IRUserService::clearSendBuffer(u32 messagePointer) {
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRUserService::sendPayload(std::span<const u8> payload) {
|
void IRUserService::sendPayload(IRUserService::Payload payload) {
|
||||||
if (!receiveBuffer) {
|
if (!receiveBuffer) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -343,4 +346,8 @@ void IRUserService::updateCirclePadPro() {
|
||||||
std::vector<u8> response(sizeof(cppState));
|
std::vector<u8> response(sizeof(cppState));
|
||||||
std::memcpy(response.data(), &cppState, sizeof(cppState));
|
std::memcpy(response.data(), &cppState, sizeof(cppState));
|
||||||
sendPayload(response);
|
sendPayload(response);
|
||||||
|
|
||||||
|
// Schedule next IR event. TODO: Maybe account for cycle drift.
|
||||||
|
auto& scheduler = kernel.getScheduler();
|
||||||
|
scheduler.addEvent(Scheduler::EventType::UpdateIR, scheduler.currentTimestamp + cpp.period);
|
||||||
}
|
}
|
|
@ -139,8 +139,6 @@ void Emulator::runFrame() {
|
||||||
if (cheats.haveCheats()) [[unlikely]] {
|
if (cheats.haveCheats()) [[unlikely]] {
|
||||||
cheats.run();
|
cheats.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
getServiceManager().getIRUser().updateCirclePadPro();
|
|
||||||
} else if (romType != ROMType::None) {
|
} else if (romType != ROMType::None) {
|
||||||
// If the emulator is not running and a game is loaded, we still want to display the framebuffer otherwise we will get weird
|
// If the emulator is not running and a game is loaded, we still want to display the framebuffer otherwise we will get weird
|
||||||
// double-buffering issues
|
// double-buffering issues
|
||||||
|
@ -182,6 +180,7 @@ void Emulator::pollScheduler() {
|
||||||
}
|
}
|
||||||
|
|
||||||
case Scheduler::EventType::SignalY2R: kernel.getServiceManager().getY2R().signalConversionDone(); break;
|
case Scheduler::EventType::SignalY2R: kernel.getServiceManager().getY2R().signalConversionDone(); break;
|
||||||
|
case Scheduler::EventType::UpdateIR: kernel.getServiceManager().getIRUser().updateCirclePadPro(); break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
Helpers::panic("Scheduler: Unimplemented event type received: %d\n", static_cast<int>(eventType));
|
Helpers::panic("Scheduler: Unimplemented event type received: %d\n", static_cast<int>(eventType));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue