mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-07-04 06:16:20 +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
|
||||
RunDSP = 2, // Make the emulated DSP run for one audio frame
|
||||
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?
|
||||
};
|
||||
static constexpr usize totalNumberOfEvents = static_cast<usize>(EventType::TotalNumberOfEvents);
|
||||
|
|
|
@ -44,7 +44,10 @@ namespace IR {
|
|||
virtual void disconnect() override;
|
||||
virtual void receivePayload(Payload payload) override;
|
||||
|
||||
CirclePadPro(SendCallback sendCallback) : IR::Device(sendCallback) {}
|
||||
CirclePadPro(SendCallback sendCallback, Scheduler& scheduler) : IR::Device(sendCallback, scheduler) {}
|
||||
|
||||
ButtonState state;
|
||||
// The current polling period in cycles, configured via the ConfigurePolling command
|
||||
s64 period = Scheduler::nsToCycles(16000);
|
||||
};
|
||||
} // namespace IR
|
|
@ -3,6 +3,7 @@
|
|||
#include <span>
|
||||
|
||||
#include "helpers.hpp"
|
||||
#include "scheduler.hpp"
|
||||
|
||||
namespace IR {
|
||||
class Device {
|
||||
|
@ -11,6 +12,7 @@ namespace IR {
|
|||
|
||||
protected:
|
||||
using SendCallback = std::function<void(Payload)>; // Callback for sending data from IR device->3DS
|
||||
Scheduler& scheduler;
|
||||
SendCallback sendCallback;
|
||||
|
||||
public:
|
||||
|
@ -18,6 +20,6 @@ namespace IR {
|
|||
virtual void disconnect() = 0;
|
||||
virtual void receivePayload(Payload payload) = 0;
|
||||
|
||||
Device(SendCallback sendCallback) : sendCallback(sendCallback) {}
|
||||
Device(SendCallback sendCallback, Scheduler& scheduler) : sendCallback(sendCallback), scheduler(scheduler) {}
|
||||
};
|
||||
} // namespace IR
|
|
@ -16,6 +16,7 @@
|
|||
class Kernel;
|
||||
|
||||
class IRUserService {
|
||||
using Payload = IR::Device::Payload;
|
||||
using Handle = HorizonHandle;
|
||||
|
||||
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
|
||||
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
|
||||
void sendPayload(std::span<const u8> payload);
|
||||
void sendPayload(Payload payload);
|
||||
|
||||
public:
|
||||
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); }) {}
|
||||
IRUserService(Memory& mem, HIDService& hid, const EmulatorConfig& config, Kernel& kernel);
|
||||
|
||||
void setCStickX(s16 value) { cpp.state.cStick.x = value; }
|
||||
void setCStickY(s16 value) { cpp.state.cStick.y = value; }
|
||||
|
|
|
@ -7,15 +7,20 @@
|
|||
using namespace IR;
|
||||
|
||||
void CirclePadPro::connect() {}
|
||||
void CirclePadPro::disconnect() {}
|
||||
void CirclePadPro::disconnect() { scheduler.removeEvent(Scheduler::EventType::UpdateIR); }
|
||||
|
||||
void CirclePadPro::receivePayload(Payload payload) {
|
||||
const u8 type = payload[0];
|
||||
|
||||
switch (type) {
|
||||
case CPPRequestID::ConfigurePolling: {
|
||||
[[maybe_unused]] const u8 pollingPeriodMs = payload[1];
|
||||
// TODO
|
||||
// Convert polling period from ms to ns for easier use with the scheduler
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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() {
|
||||
connectionStatusEvent = std::nullopt;
|
||||
receiveEvent = std::nullopt;
|
||||
|
@ -285,7 +288,7 @@ void IRUserService::clearSendBuffer(u32 messagePointer) {
|
|||
mem.write32(messagePointer + 4, Result::Success);
|
||||
}
|
||||
|
||||
void IRUserService::sendPayload(std::span<const u8> payload) {
|
||||
void IRUserService::sendPayload(IRUserService::Payload payload) {
|
||||
if (!receiveBuffer) {
|
||||
return;
|
||||
}
|
||||
|
@ -343,4 +346,8 @@ void IRUserService::updateCirclePadPro() {
|
|||
std::vector<u8> response(sizeof(cppState));
|
||||
std::memcpy(response.data(), &cppState, sizeof(cppState));
|
||||
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]] {
|
||||
cheats.run();
|
||||
}
|
||||
|
||||
getServiceManager().getIRUser().updateCirclePadPro();
|
||||
} 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
|
||||
// double-buffering issues
|
||||
|
@ -182,6 +180,7 @@ void Emulator::pollScheduler() {
|
|||
}
|
||||
|
||||
case Scheduler::EventType::SignalY2R: kernel.getServiceManager().getY2R().signalConversionDone(); break;
|
||||
case Scheduler::EventType::UpdateIR: kernel.getServiceManager().getIRUser().updateCirclePadPro(); break;
|
||||
|
||||
default: {
|
||||
Helpers::panic("Scheduler: Unimplemented event type received: %d\n", static_cast<int>(eventType));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue