Finish CDolphinController imp, ready for integration

This commit is contained in:
Phillip Stephens 2022-03-20 13:14:08 -07:00
parent 7e1b1ef248
commit be79334465
Signed by: Antidote
GPG Key ID: F8BEE4C83DACA60D
4 changed files with 139 additions and 24 deletions

View File

@ -25,15 +25,16 @@ enum class EAnalogButton {
};
class CControllerButton {
bool x0_;
bool x1_pressed;
bool x2_;
bool x0_pressed;
bool x1_pressEvent;
bool x2_releaseEvent;
public:
void SetIsPressed(bool pressed) { x1_pressed = pressed; }
[[nodiscard]] bool GetIsPressed() const { return x1_pressed; }
void SetPressEvent(bool press);
[[nodiscard]] bool GetPressEvent() const;
void SetReleaseEvent(bool release);
void SetIsPressed(bool pressed) { x0_pressed = pressed; }
[[nodiscard]] bool GetIsPressed() const { return x0_pressed; }
void SetPressEvent(bool press){ x1_pressEvent = press; }
[[nodiscard]] bool GetPressEvent() const{ return x1_pressEvent; }
void SetReleaseEvent(bool release) { x2_releaseEvent = release;};
[[nodiscard]] bool GetReleaseEvent() const { return x2_releaseEvent; }
};
} // namespace metaforce

View File

@ -4,11 +4,16 @@ namespace metaforce {
CDolphinController::CDolphinController() {
static bool sIsInitialized = false;
if (!sIsInitialized) {
// PADSetSpec(5);
// PADInit();
PADSetSpec(5);
PADInit();
sIsInitialized = true;
}
}
void CDolphinController::Poll() {
ReadDevices();
ProcessInputData();
}
void CDolphinController::SetMotorState(EIOPort port, EMotorState state) { x194_motorStates[u32(port)] = state; }
float CDolphinController::GetAnalogStickMaxValue(EJoyAxis axis) {
@ -23,6 +28,66 @@ float CDolphinController::GetAnalogStickMaxValue(EJoyAxis axis) {
return 0.f;
}
void CDolphinController::ReadDevices() {
std::array<PADStatus, 4> status{};
PADRead(status.data());
if (status[0].xa_err == PAD::ERR_NONE) {
PADClamp(status.data());
x4_status = status;
} else {
x4_status[0].xa_err = status[0].xa_err;
x4_status[1].xa_err = status[1].xa_err;
x4_status[2].xa_err = status[2].xa_err;
x4_status[3].xa_err = status[3].xa_err;
}
for (u32 i = 0; i < 4; ++i) {
if (x4_status[i].xa_err != PAD::ERR_NOT_READY) {
if (x4_status[i].xa_err == PAD::ERR_NONE) {
x34_gamepadStates[i].SetDeviceIsPresent(true);
} else if (x4_status[i].xa_err == PAD::ERR_NO_CONTROLLER) {
x1c8_invalidControllers |= PAD::CHAN0_BIT >> i;
x34_gamepadStates[i].SetDeviceIsPresent(false);
}
}
if (x1b4_[i] == 0) {
const auto type = SIProbe(i);
if ((type & (SI::ERROR_NO_RESPONSE | SI::ERROR_UNKNOWN | SI::ERROR_BUSY)) == 0) {
x1b4_[i] = 0x3c;
if (type == SI::GC_WIRELESS) {
x1a4_controllerTypes[i] = skTypeWavebird;
} else if (type == SI::GBA) { /* here for completeness, the GameCube adapter does not support GBA */
x1a4_controllerTypes[i] = skTypeGBA;
} else if (type == SI::GC_STANDARD) {
x1a4_controllerTypes[i] = skTypeStandard;
}
} else {
x1a4_controllerTypes[i] = skTypeUnknown;
}
} else {
--x1b4_[i];
}
}
if (x1c8_invalidControllers != 0 && PADReset(x1c8_invalidControllers)) {
x1c8_invalidControllers = 0;
}
}
void CDolphinController::ProcessInputData() {
for (u32 i = 0; i < 4; ++i) {
if (!x34_gamepadStates[i].DeviceIsPresent()) {
continue;
}
ProcessAxis(i, EJoyAxis::LeftX);
ProcessAxis(i, EJoyAxis::LeftY);
ProcessAxis(i, EJoyAxis::RightX);
ProcessAxis(i, EJoyAxis::RightY);
ProcessButtons(i);
}
}
void CDolphinController::ProcessAxis(u32 controller, EJoyAxis axis) {
const auto maxAxisValue = GetAnalogStickMaxValue(axis);
auto& data = x34_gamepadStates[controller].GetAxis(axis);
@ -72,8 +137,48 @@ void CDolphinController::ProcessButtons(u32 controller) {
ProcessAnalogButton(x4_status[controller].x7_triggerR,
x34_gamepadStates[controller].GetAnalogButton(EAnalogButton::Right));
}
void CDolphinController::ProcessDigitalButton(u32 controller, CControllerButton& button, u16 mapping) {}
void CDolphinController::ProcessAnalogButton(float value, CControllerAxis& axis) {}
void CDolphinController::ProcessDigitalButton(u32 controller, CControllerButton& button, u16 mapping) {
bool btnPressed = (x4_status[controller].x0_buttons & mapping) != 0;
button.SetPressEvent(PADButtonDown(button.GetIsPressed(), btnPressed));
button.SetReleaseEvent(PADButtonUp(button.GetIsPressed(), btnPressed));
button.SetPressEvent(btnPressed);
}
void CDolphinController::ProcessAnalogButton(float value, CControllerAxis& axis) {
float absolute = value * (1 / 150.f);
if (value * (1 / 150.f) > 1.f) {
absolute = kAbsoluteMaximum;
}
void CDolphinController::Initialize() {}
float relative = absolute - axis.GetAbsoluteValue();
if (relative > kRelativeMaximum) {
relative = kRelativeMaximum;
}
axis.SetRelativeValue(relative);
axis.SetAbsoluteValue(absolute);
}
bool CDolphinController::Initialize() {
// GBAInit();
memset(x4_status.data(), 0, sizeof(PADStatus) * x4_status.size());
x34_gamepadStates[0].SetDeviceIsPresent(false);
x194_motorStates[0] = EMotorState::StopHard;
x1b4_[0] = 0;
x1a4_controllerTypes[0] = skTypeUnknown;
x34_gamepadStates[1].SetDeviceIsPresent(false);
x194_motorStates[1] = EMotorState::StopHard;
x1b4_[1] = 0;
x1a4_controllerTypes[0] = skTypeUnknown;
x34_gamepadStates[2].SetDeviceIsPresent(false);
x194_motorStates[2] = EMotorState::StopHard;
x1b4_[2] = 0;
x1a4_controllerTypes[0] = skTypeUnknown;
x34_gamepadStates[3].SetDeviceIsPresent(false);
x194_motorStates[3] = EMotorState::StopHard;
x1b4_[3] = 0;
x1a4_controllerTypes[0] = skTypeUnknown;
PADControlAllMotors(reinterpret_cast<const u32*>(x194_motorStates.data()));
Poll();
return true;
}
} // namespace metaforce

View File

@ -6,32 +6,38 @@
namespace metaforce {
class CDolphinController : public IController {
static constexpr u32 skTypeUnknown = SBIG('UNKN');
static constexpr u32 skTypeStandard = SBIG('STND');
static constexpr u32 skTypeGBA = SBIG('GBA_');
static constexpr u32 skTypeWavebird = SBIG('WAVE');
std::array<PADStatus, 4> x4_status;
std::array<PADStatus, 4> x4_status{};
std::array<CControllerGamepadData, 4> x34_gamepadStates{};
std::array<EMotorState, 4> x194_motorStates;
std::array<EMotorState, 4> x194_motorStates{};
std::array<u32, 4> x1a4_controllerTypes{};
std::array<u32, 4> x1b4_{};
u32 x1c4_ = 0xf0000000;
u32 x1c8_ = 0;
u32 x1c8_invalidControllers = 0;
u32 x1cc_ = 0;
public:
CDolphinController();
void Poll() override{};
void Poll() override;
[[nodiscard]] u32 GetDeviceCount() const override { return 4; };
[[nodiscard]] CControllerGamepadData& GetGamepadData(u32 controller) override {
return x34_gamepadStates[controller];
};
[[nodiscard]] u32 GetControllerType(u32 controller) const override { return x1a4_controllerTypes[controller]; }
void SetMotorState(EIOPort port, EMotorState state) override;
float GetAnalogStickMaxValue(EJoyAxis axis);
bool Initialize();
private:
void ReadDevices();
void ProcessInputData();
void ProcessAxis(u32 controller, EJoyAxis axis);
void ProcessButtons(u32 controller);
void ProcessDigitalButton(u32 controller, CControllerButton& button, u16 mapping);
void ProcessAnalogButton(float value, CControllerAxis& axis);
void Initialize();
};
} // namespace metaforce

View File

@ -51,8 +51,11 @@ enum CHAN : u32 {
} // namespace PAD
namespace SI {
constexpr u32 ERROR_UNKNOWN = 0x0040;
constexpr u32 ERROR_BUSY = 0x0080;
constexpr u32 ERROR_NO_RESPONSE = 0x0008;
constexpr u32 TYPE_GC = 0x08000000;
constexpr u32 GBA = 0x00040000;
constexpr u32 GC_STANDARD = 0x01000000;
constexpr u32 GC_WIRELESS = 0x80000000;
constexpr u32 WIRELESS_STATE = 0x02000000;
@ -63,15 +66,15 @@ constexpr u32 GC_WAVEBIRD = (TYPE_GC | GC_WIRELESS | GC_STANDARD | WIRELESS_STAT
} // namespace SI
using PADSamplingCallback = void (*)(void);
constexpr bool PADButtonDown(u16 lastButton, u16 button) { return ((lastButton ^ button) & button) != 0; }
constexpr bool PADButtonUp(u16 lastButton, u16 button) { return ((lastButton ^ button) & lastButton) != 0; }
constexpr bool PADButtonDown(bool lastButton, bool button) { return ((lastButton ^ button) & button) != 0; }
constexpr bool PADButtonUp(bool lastButton, bool button) { return ((lastButton ^ button) & lastButton) != 0; }
void PADClamp(PAD::Status* status);
void PADClampCircle(PAD::Status* status);
void PADInit();
bool PADIsBarrel(s32 chan);
u32 PADRead(PAD::Status* status);
bool PADRecalibrate(u32 mask);
bool PADReset(u32 mask);
static bool PADRecalibrate(u32 mask) { return true; }
static bool PADReset(u32 mask) { return true; }
void PADSetAnalog(u32 mode);
void PADSetSpec(s32 spec);
void PADSetSamplingCallback(PADSamplingCallback callback);