Skip to content

Commit

Permalink
Merge pull request #53 from OrangeFox86/52-handle-vmu-buttons-in-gamepad
Browse files Browse the repository at this point in the history
52 handle vmu buttons in gamepad
  • Loading branch information
Tails86 authored Jan 1, 2023
2 parents cd205de + 13dba56 commit 9b6bfe3
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 13 deletions.
20 changes: 20 additions & 0 deletions inc/hal/Usb/DreamcastControllerObserver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,30 @@ class DreamcastControllerObserver
uint8_t lAnalogLR; //!< 0: left; 128: neutral; 255: right
} __attribute__ ((packed));

//! The secondary controller condition bits
struct SecondaryControllerCondition
{
// Digital bits:
// 0: pressed
// 1: released
unsigned up:1;
unsigned down:1;
unsigned left:1;
unsigned right:1;
unsigned a:1;
unsigned b:1;
} __attribute__ ((packed));

//! Sets the current Dreamcast controller condition
//! @param[in] controllerCondition The current condition of the Dreamcast controller
virtual void setControllerCondition(const ControllerCondition& controllerCondition) = 0;

//! Sets the current Dreamcast secondary controller condition
//! @param[in] secondaryControllerCondition The current secondary condition of the
//! Dreamcast controller
virtual void setSecondaryControllerCondition(
const SecondaryControllerCondition& secondaryControllerCondition) = 0;

//! Called when controller connected
virtual void controllerConnected() = 0;

Expand Down
29 changes: 21 additions & 8 deletions src/hal/Usb/Hid/UsbGamepad.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#include "class/hid/hid.h"
#include "class/hid/hid_device.h"

#include "utils.h"

UsbGamepad::UsbGamepad(uint8_t interfaceId, uint8_t reportId) :
interfaceId(interfaceId),
reportId(reportId),
Expand All @@ -20,17 +22,26 @@ UsbGamepad::UsbGamepad(uint8_t interfaceId, uint8_t reportId) :

bool UsbGamepad::isButtonPressed()
{
return (currentDpad[DPAD_UP] || currentDpad[DPAD_DOWN] || currentDpad[DPAD_LEFT]
|| currentDpad[DPAD_RIGHT] || currentButtons != 0
|| currentLeftAnalog[0] != 0 || currentLeftAnalog[1] != 0 || currentLeftAnalog[2] != -128
|| currentRightAnalog[0] != 0 || currentRightAnalog[1] != 0 || currentRightAnalog[2] != -128);
return (
currentDpad[DPAD_UP]
|| currentDpad[DPAD_DOWN]
|| currentDpad[DPAD_LEFT]
|| currentDpad[DPAD_RIGHT]
|| currentButtons != 0
|| isAnalogPressed(currentLeftAnalog[0])
|| isAnalogPressed(currentLeftAnalog[1])
|| currentLeftAnalog[2] > (MIN_ANALOG_VALUE + ANALOG_PRESSED_TOL)
|| isAnalogPressed(currentRightAnalog[0])
|| isAnalogPressed(currentRightAnalog[1])
|| currentRightAnalog[2] > (MIN_ANALOG_VALUE + ANALOG_PRESSED_TOL));
}

//--------------------------------------------------------------------+
// EXTERNAL API
//--------------------------------------------------------------------+
void UsbGamepad::setAnalogThumbX(bool isLeft, int8_t x)
{
x = limit_value(x, MIN_ANALOG_VALUE, MAX_ANALOG_VALUE);
int8_t lastX = 0;
if (isLeft)
{
Expand All @@ -47,6 +58,7 @@ void UsbGamepad::setAnalogThumbX(bool isLeft, int8_t x)

void UsbGamepad::setAnalogThumbY(bool isLeft, int8_t y)
{
y = limit_value(y, MIN_ANALOG_VALUE, MAX_ANALOG_VALUE);
int8_t lastY = 0;
if (isLeft)
{
Expand All @@ -63,6 +75,7 @@ void UsbGamepad::setAnalogThumbY(bool isLeft, int8_t y)

void UsbGamepad::setAnalogTrigger(bool isLeft, int8_t z)
{
z = limit_value(z, MIN_ANALOG_VALUE, MAX_ANALOG_VALUE);
int8_t lastZ = 0;
if (isLeft)
{
Expand Down Expand Up @@ -120,9 +133,9 @@ void UsbGamepad::setDigitalPad(UsbGamepad::DpadButtons button, bool isPressed)
buttonsUpdated = buttonsUpdated || (oldValue != currentDpad[button]);
}

void UsbGamepad::setButtonMask(uint16_t mask, bool isPressed)
void UsbGamepad::setButtonMask(uint32_t mask, bool isPressed)
{
uint16_t lastButtons = currentButtons;
uint32_t lastButtons = currentButtons;
if (isPressed)
{
currentButtons |= mask;
Expand All @@ -145,10 +158,10 @@ void UsbGamepad::updateAllReleased()
{
currentLeftAnalog[0] = 0;
currentLeftAnalog[1] = 0;
currentLeftAnalog[2] = -128;
currentLeftAnalog[2] = MIN_ANALOG_VALUE;
currentRightAnalog[0] = 0;
currentRightAnalog[1] = 0;
currentRightAnalog[2] = -128;
currentRightAnalog[2] = MIN_ANALOG_VALUE;
currentDpad[DPAD_UP] = false;
currentDpad[DPAD_DOWN] = false;
currentDpad[DPAD_LEFT] = false;
Expand Down
38 changes: 36 additions & 2 deletions src/hal/Usb/Hid/UsbGamepad.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,23 @@ class UsbGamepad : public UsbControllerDevice
GAMEPAD_BUTTON_MODE = 12,
GAMEPAD_BUTTON_THUMBL = 13,
GAMEPAD_BUTTON_THUMBR = 14,
BUTTON15 = 15,
BUTTON16 = 16,
BUTTON17 = 17,
BUTTON18 = 18,
BUTTON19 = 19,
BUTTON20 = 20,
BUTTON21 = 21,
BUTTON22 = 22,
BUTTON23 = 23,
BUTTON24 = 24,
BUTTON25 = 25,
BUTTON26 = 26,
BUTTON27 = 27,
BUTTON28 = 28,
BUTTON29 = 29,
BUTTON30 = 30,
BUTTON31 = 31
};

public:
Expand Down Expand Up @@ -70,7 +87,7 @@ class UsbGamepad : public UsbControllerDevice
//! Sets or releases one or more of the 16 buttons as a mask value
//! @param[in] mask The mask value to set or release
//! @param[in] isPressed True to set the mask or false to release
void setButtonMask(uint16_t mask, bool isPressed);
void setButtonMask(uint32_t mask, bool isPressed);
//! Sets the state of a single button
//! @param[in] button Button value [0,15]
//! @param[in] isPressed The state of @p button
Expand All @@ -93,6 +110,23 @@ class UsbGamepad : public UsbControllerDevice
//! @returns the hat value based on current dpad state
uint8_t getHatValue();

private:
//! @param[in] analog The analog value to check
//! @returns true if the given analog is considered "pressed"
inline bool isAnalogPressed(int8_t analog)
{
return (analog > ANALOG_PRESSED_TOL || analog < -ANALOG_PRESSED_TOL);
}

public:
// TODO: Move these constants to descriptors that this header pulls from
//! Minumum analog value defined in USB HID descriptors
static const int8_t MIN_ANALOG_VALUE = -127;
//! Maximum analog value defined in USB HID descriptors
static const int8_t MAX_ANALOG_VALUE = 127;
//! Tolerance for when analog is considered "pressed" for status LED
static const int8_t ANALOG_PRESSED_TOL = 5;

private:
const uint8_t interfaceId;
//! The report ID to use when sending keys to host
Expand All @@ -104,7 +138,7 @@ class UsbGamepad : public UsbControllerDevice
//! Current d-pad buttons
bool currentDpad[DPAD_COUNT];
//! Current button states
uint16_t currentButtons;
uint32_t currentButtons;
//! True when something has been updated since the last successful send
bool buttonsUpdated;
};
Expand Down
13 changes: 13 additions & 0 deletions src/hal/Usb/Hid/UsbGamepadDreamcastControllerObserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,19 @@ void UsbGamepadDreamcastControllerObserver::setControllerCondition(const Control
mUsbController.send();
}

void UsbGamepadDreamcastControllerObserver::setSecondaryControllerCondition(
const SecondaryControllerCondition& secondaryControllerCondition)
{
mUsbController.setButton(UsbGamepad::GAMEPAD_BUTTON_MODE, 0 == secondaryControllerCondition.a);
mUsbController.setButton(UsbGamepad::BUTTON15, 0 == secondaryControllerCondition.b);
mUsbController.setButton(UsbGamepad::BUTTON16, 0 == secondaryControllerCondition.up);
mUsbController.setButton(UsbGamepad::BUTTON17, 0 == secondaryControllerCondition.down);
mUsbController.setButton(UsbGamepad::BUTTON18, 0 == secondaryControllerCondition.left);
mUsbController.setButton(UsbGamepad::BUTTON19, 0 == secondaryControllerCondition.right);

mUsbController.send();
}

void UsbGamepadDreamcastControllerObserver::controllerConnected()
{
mUsbController.updateControllerConnected(true);
Expand Down
6 changes: 6 additions & 0 deletions src/hal/Usb/Hid/UsbGamepadDreamcastControllerObserver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ class UsbGamepadDreamcastControllerObserver : public DreamcastControllerObserver
//! @param[in] controllerCondition The current condition of the Dreamcast controller
virtual void setControllerCondition(const ControllerCondition& controllerCondition) final;

//! Sets the current Dreamcast secondary controller condition
//! @param[in] secondaryControllerCondition The current secondary condition of the
//! Dreamcast controller
virtual void setSecondaryControllerCondition(
const SecondaryControllerCondition& secondaryControllerCondition) final;

//! Called when controller connected
virtual void controllerConnected() final;

Expand Down
35 changes: 32 additions & 3 deletions src/hostLib/peripherals/DreamcastTimer.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,29 @@
#include "DreamcastTimer.hpp"
#include <memory.h>

DreamcastTimer::DreamcastTimer(uint8_t addr,
uint32_t fd,
std::shared_ptr<EndpointTxSchedulerInterface> scheduler,
PlayerData playerData) :
DreamcastPeripheral("timer", addr, fd, scheduler, playerData.playerIndex)
{}
DreamcastPeripheral("timer", addr, fd, scheduler, playerData.playerIndex),
mGamepad(playerData.gamepad),
mButtonStatusId(0)
{
// Poll only the upper VMU button states
if (addr & SUB_PERIPHERAL_ADDR_START_MASK)
{
uint32_t payload = FUNCTION_CODE;
mButtonStatusId = mEndpointTxScheduler->add(
PrioritizedTxScheduler::TX_TIME_ASAP,
this,
COMMAND_GET_CONDITION,
&payload,
1,
true,
2,
BUTTON_POLL_PERIOD_US);
}
}

DreamcastTimer::~DreamcastTimer()
{}
Expand All @@ -23,4 +41,15 @@ void DreamcastTimer::txFailed(bool writeFailed,

void DreamcastTimer::txComplete(std::shared_ptr<const MaplePacket> packet,
std::shared_ptr<const Transmission> tx)
{}
{
if (tx->transmissionId == mButtonStatusId
&& packet->getFrameCommand() == COMMAND_RESPONSE_DATA_XFER
&& packet->payload.size() >= 2)
{
// Set controller!
const uint8_t cond = packet->payload[1] >> COND_RIGHT_SHIFT;
DreamcastControllerObserver::SecondaryControllerCondition secondaryCondition;
memcpy(&secondaryCondition, &cond, 1);
mGamepad.setSecondaryControllerCondition(secondaryCondition);
}
}
8 changes: 8 additions & 0 deletions src/hostLib/peripherals/DreamcastTimer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ class DreamcastTimer : public DreamcastPeripheral
public:
//! Function code for timer
static const uint32_t FUNCTION_CODE = DEVICE_FN_TIMER;
//! Polling period for the upper VMU button states
static const uint32_t BUTTON_POLL_PERIOD_US = 50000;
//! Number of bits to shift the condition word to the right
static const uint8_t COND_RIGHT_SHIFT = 24;

private:
//! Gamepad to send secondary status to
DreamcastControllerObserver& mGamepad;
//! Transmit ID of button status message
uint32_t mButtonStatusId;
};

0 comments on commit 9b6bfe3

Please sign in to comment.