diff --git a/wpilibc/src/main/native/cpp/DriverStation.cpp b/wpilibc/src/main/native/cpp/DriverStation.cpp index fde7158324..98a7fa6e64 100644 --- a/wpilibc/src/main/native/cpp/DriverStation.cpp +++ b/wpilibc/src/main/native/cpp/DriverStation.cpp @@ -76,6 +76,110 @@ void DriverStation::ReportError(bool is_error, int32_t code, location.c_str(locationTemp), stack.c_str(stackTemp), 1); } +/** + * The state of one joystick button. Button indexes begin at 1. + * + * @param stick The joystick to read. + * @param button The button index, beginning at 1. + * @return The state of the joystick button. + */ +bool DriverStation::GetStickButton(int stick, int button) { + if (stick >= kJoystickPorts) { + wpi_setWPIError(BadJoystickIndex); + return false; + } + if (button == 0) { + ReportJoystickUnpluggedError( + "ERROR: Button indexes begin at 1 in WPILib for C++ and Java"); + return false; + } + std::unique_lock lock(m_joystickDataMutex); + if (button > m_joystickButtons[stick].count) { + // Unlock early so error printing isn't locked. + lock.unlock(); + ReportJoystickUnpluggedWarning( + "Joystick Button missing, check if all controllers are " + "plugged in"); + return false; + } + + return m_joystickButtons[stick].buttons & 1 << (button - 1); +} + +/** + * Whether one joystick button was pressed since the last check. Button indexes + * begin at 1. + * + * @param stick The joystick to read. + * @param button The button index, beginning at 1. + * @return Whether the joystick button was pressed since the last check. + */ +bool DriverStation::GetStickButtonPressed(int stick, int button) { + if (stick >= kJoystickPorts) { + wpi_setWPIError(BadJoystickIndex); + return false; + } + if (button == 0) { + ReportJoystickUnpluggedError( + "ERROR: Button indexes begin at 1 in WPILib for C++ and Java"); + return false; + } + std::unique_lock lock(m_joystickDataMutex); + if (button > m_joystickButtons[stick].count) { + // Unlock early so error printing isn't locked. + lock.unlock(); + ReportJoystickUnpluggedWarning( + "Joystick Button missing, check if all controllers are " + "plugged in"); + return false; + } + + // If button was pressed, clear flag and return true + if (m_joystickButtonsPressed[stick] & 1 << (button - 1)) { + m_joystickButtonsPressed[stick] &= ~(1 << (button - 1)); + return true; + } else { + return false; + } +} + +/** + * Whether one joystick button was released since the last check. Button indexes + * begin at 1. + * + * @param stick The joystick to read. + * @param button The button index, beginning at 1. + * @return Whether the joystick button was released since the last check. + */ +bool DriverStation::GetStickButtonReleased(int stick, int button) { + if (stick >= kJoystickPorts) { + wpi_setWPIError(BadJoystickIndex); + return false; + } + if (button == 0) { + ReportJoystickUnpluggedError( + "ERROR: Button indexes begin at 1 in WPILib for C++ and Java"); + return false; + } + std::unique_lock lock(m_joystickDataMutex); + if (button > m_joystickButtons[stick].count) { + // Unlock early so error printing isn't locked. + lock.unlock(); + ReportJoystickUnpluggedWarning( + "Joystick Button missing, check if all controllers are " + "plugged in"); + return false; + } + + // If button was released, clear flag and return true + if (m_joystickButtonsReleased[stick] & 1 << (button - 1)) { + m_joystickButtonsReleased[stick] &= ~(1 << (button - 1)); + return true; + } else { + return false; + } +} + /** * Get the value of the axis on a joystick. * @@ -146,36 +250,6 @@ int DriverStation::GetStickButtons(int stick) const { return m_joystickButtons[stick].buttons; } -/** - * The state of one joystick button. Button indexes begin at 1. - * - * @param stick The joystick to read. - * @param button The button index, beginning at 1. - * @return The state of the joystick button. - */ -bool DriverStation::GetStickButton(int stick, int button) { - if (stick >= kJoystickPorts) { - wpi_setWPIError(BadJoystickIndex); - return false; - } - if (button == 0) { - ReportJoystickUnpluggedError( - "ERROR: Button indexes begin at 1 in WPILib for C++ and Java"); - return false; - } - std::unique_lock lock(m_joystickDataMutex); - if (button > m_joystickButtons[stick].count) { - // Unlock early so error printing isn't locked. - lock.unlock(); - ReportJoystickUnpluggedWarning( - "Joystick Button missing, check if all controllers are " - "plugged in"); - return false; - } - - return ((0x1 << (button - 1)) & m_joystickButtons[stick].buttons) != 0; -} - /** * Returns the number of axes on a given joystick port. * @@ -529,6 +603,17 @@ void DriverStation::GetData() { // Obtain a write lock on the data, swap the cached data into the // main data arrays std::lock_guard lock(m_joystickDataMutex); + + for (int32_t i = 0; i < kJoystickPorts; i++) { + // If buttons weren't pressed and are now, set flags in m_buttonsPressed + m_joystickButtonsPressed[i] |= + ~m_joystickButtons[i].buttons & m_joystickButtonsCache[i].buttons; + + // If buttons were pressed and aren't now, set flags in m_buttonsReleased + m_joystickButtonsReleased[i] |= + m_joystickButtons[i].buttons & ~m_joystickButtonsCache[i].buttons; + } + m_joystickAxes.swap(m_joystickAxesCache); m_joystickPOVs.swap(m_joystickPOVsCache); m_joystickButtons.swap(m_joystickButtonsCache); @@ -569,6 +654,9 @@ DriverStation::DriverStation() { m_joystickDescriptorCache[i].isXbox = 0; m_joystickDescriptorCache[i].type = -1; m_joystickDescriptorCache[i].name[0] = '\0'; + + m_joystickButtonsPressed[i] = 0; + m_joystickButtonsReleased[i] = 0; } m_dsThread = std::thread(&DriverStation::Run, this); diff --git a/wpilibc/src/main/native/cpp/GenericHID.cpp b/wpilibc/src/main/native/cpp/GenericHID.cpp index f175be2887..9153158c12 100644 --- a/wpilibc/src/main/native/cpp/GenericHID.cpp +++ b/wpilibc/src/main/native/cpp/GenericHID.cpp @@ -10,13 +10,53 @@ #include #include "DriverStation.h" +#include "WPIErrors.h" using namespace frc; GenericHID::GenericHID(int port) : m_ds(DriverStation::GetInstance()) { + if (port >= DriverStation::kJoystickPorts) { + wpi_setWPIError(BadJoystickIndex); + } m_port = port; } +/** + * Get the button value (starting at button 1). + * + * The buttons are returned in a single 16 bit value with one bit representing + * the state of each button. The appropriate button is returned as a boolean + * value. + * + * @param button The button number to be read (starting at 1) + * @return The state of the button. + */ +bool GenericHID::GetRawButton(int button) const { + return m_ds.GetStickButton(m_port, button); +} + +/** + * Whether the button was pressed since the last check. Button indexes begin at + * 1. + * + * @param button The button index, beginning at 1. + * @return Whether the button was pressed since the last check. + */ +bool GenericHID::GetRawButtonPressed(int button) { + return m_ds.GetStickButtonPressed(m_port, button); +} + +/** + * Whether the button was released since the last check. Button indexes begin at + * 1. + * + * @param button The button index, beginning at 1. + * @return Whether the button was released since the last check. + */ +bool GenericHID::GetRawButtonReleased(int button) { + return m_ds.GetStickButtonReleased(m_port, button); +} + /** * Get the value of the axis. * @@ -27,20 +67,6 @@ double GenericHID::GetRawAxis(int axis) const { return m_ds.GetStickAxis(m_port, axis); } -/** - * Get the button value (starting at button 1) - * - * The buttons are returned in a single 16 bit value with one bit representing - * the state of each button. The appropriate button is returned as a boolean - * value. - * - * @param button The button number to be read (starting at 1) - * @return The state of the button. - **/ -bool GenericHID::GetRawButton(int button) const { - return m_ds.GetStickButton(m_port, button); -} - /** * Get the angle in degrees of a POV on the HID. * @@ -50,23 +76,30 @@ bool GenericHID::GetRawButton(int button) const { * @param pov The index of the POV to read (starting at 0) * @return the angle of the POV in degrees, or -1 if the POV is not pressed. */ -int GenericHID::GetPOV(int pov) const { - return m_ds.GetStickPOV(GetPort(), pov); -} +int GenericHID::GetPOV(int pov) const { return m_ds.GetStickPOV(m_port, pov); } + +/** + * Get the number of axes for the HID. + * + * @return the number of axis for the current HID + */ +int GenericHID::GetAxisCount() const { return m_ds.GetStickAxisCount(m_port); } /** * Get the number of POVs for the HID. * * @return the number of POVs for the current HID */ -int GenericHID::GetPOVCount() const { return m_ds.GetStickPOVCount(GetPort()); } +int GenericHID::GetPOVCount() const { return m_ds.GetStickPOVCount(m_port); } /** - * Get the port number of the HID. + * Get the number of buttons for the HID. * - * @return The port number of the HID. + * @return the number of buttons on the current HID */ -int GenericHID::GetPort() const { return m_port; } +int GenericHID::GetButtonCount() const { + return m_ds.GetStickButtonCount(m_port); +} /** * Get the type of the HID. @@ -84,6 +117,22 @@ GenericHID::HIDType GenericHID::GetType() const { */ std::string GenericHID::GetName() const { return m_ds.GetJoystickName(m_port); } +/** + * Get the axis type of a joystick axis. + * + * @return the axis type of a joystick axis. + */ +int GenericHID::GetAxisType(int axis) const { + return m_ds.GetJoystickAxisType(m_port, axis); +} + +/** + * Get the port number of the HID. + * + * @return The port number of the HID. + */ +int GenericHID::GetPort() const { return m_port; } + /** * Set a single HID output value for the HID. * diff --git a/wpilibc/src/main/native/cpp/Joystick.cpp b/wpilibc/src/main/native/cpp/Joystick.cpp index 65ec8164d8..9b08dc493f 100644 --- a/wpilibc/src/main/native/cpp/Joystick.cpp +++ b/wpilibc/src/main/native/cpp/Joystick.cpp @@ -7,6 +7,8 @@ #include "Joystick.h" +#include +#include #include #include @@ -16,15 +18,9 @@ using namespace frc; -const int Joystick::kDefaultXAxis; -const int Joystick::kDefaultYAxis; -const int Joystick::kDefaultZAxis; -const int Joystick::kDefaultTwistAxis; -const int Joystick::kDefaultThrottleAxis; -const int Joystick::kDefaultTriggerButton; -const int Joystick::kDefaultTopButton; -static Joystick* joysticks[DriverStation::kJoystickPorts]; -static bool joySticksInitialized = false; +constexpr int Joystick::kMinNumAxes; + +constexpr double kPi = 3.14159265358979323846; /** * Construct an instance of a joystick. @@ -34,53 +30,113 @@ static bool joySticksInitialized = false; * @param port The port on the Driver Station that the joystick is plugged into * (0-5). */ -Joystick::Joystick(int port) : Joystick(port, kNumAxisTypes, kNumButtonTypes) { - m_axes[kXAxis] = kDefaultXAxis; - m_axes[kYAxis] = kDefaultYAxis; - m_axes[kZAxis] = kDefaultZAxis; - m_axes[kTwistAxis] = kDefaultTwistAxis; - m_axes[kThrottleAxis] = kDefaultThrottleAxis; - - m_buttons[kTriggerButton] = kDefaultTriggerButton; - m_buttons[kTopButton] = kDefaultTopButton; +Joystick::Joystick(int port) + : GenericHID(port), m_axes(std::max(GetAxisCount(), kMinNumAxes)) { + m_axes[static_cast(Axis::kX)] = kDefaultXAxis; + m_axes[static_cast(Axis::kY)] = kDefaultYAxis; + m_axes[static_cast(Axis::kZ)] = kDefaultZAxis; + m_axes[static_cast(Axis::kTwist)] = kDefaultTwistAxis; + m_axes[static_cast(Axis::kThrottle)] = kDefaultThrottleAxis; HAL_Report(HALUsageReporting::kResourceType_Joystick, port); } /** - * Version of the constructor to be called by sub-classes. + * Set the channel associated with a specified axis. * - * This constructor allows the subclass to configure the number of constants - * for axes and buttons. - * - * @param port The port on the Driver Station that the joystick is - * plugged into. - * @param numAxisTypes The number of axis types in the enum. - * @param numButtonTypes The number of button types in the enum. + * @param axis The axis to set the channel for. + * @param channel The channel to set the axis to. */ -Joystick::Joystick(int port, int numAxisTypes, int numButtonTypes) - : JoystickBase(port), - m_ds(DriverStation::GetInstance()), - m_axes(numAxisTypes), - m_buttons(numButtonTypes) { - if (!joySticksInitialized) { - for (auto& joystick : joysticks) joystick = nullptr; - joySticksInitialized = true; - } - if (GetPort() >= DriverStation::kJoystickPorts) { - wpi_setWPIError(BadJoystickIndex); - } else { - joysticks[GetPort()] = this; - } +void Joystick::SetAxisChannel(AxisType axis, int channel) { + m_axes[axis] = channel; } -Joystick* Joystick::GetStickForPort(int port) { - Joystick* stick = joysticks[port]; - if (stick == nullptr) { - stick = new Joystick(port); - joysticks[port] = stick; - } - return stick; +/** + * Set the channel associated with the X axis. + * + * @param channel The channel to set the axis to. + */ +void Joystick::SetXChannel(int channel) { + m_axes[static_cast(Axis::kX)] = channel; +} + +/** + * Set the channel associated with the Y axis. + * + * @param axis The axis to set the channel for. + * @param channel The channel to set the axis to. + */ +void Joystick::SetYChannel(int channel) { + m_axes[static_cast(Axis::kY)] = channel; +} + +/** + * Set the channel associated with the Z axis. + * + * @param axis The axis to set the channel for. + * @param channel The channel to set the axis to. + */ +void Joystick::SetZChannel(int channel) { + m_axes[static_cast(Axis::kZ)] = channel; +} + +/** + * Set the channel associated with the twist axis. + * + * @param axis The axis to set the channel for. + * @param channel The channel to set the axis to. + */ +void Joystick::SetTwistChannel(int channel) { + m_axes[static_cast(Axis::kTwist)] = channel; +} + +/** + * Set the channel associated with the throttle axis. + * + * @param axis The axis to set the channel for. + * @param channel The channel to set the axis to. + */ +void Joystick::SetThrottleChannel(int channel) { + m_axes[static_cast(Axis::kThrottle)] = channel; +} + +/** + * Get the channel currently associated with the X axis. + * + * @return The channel for the axis. + */ +int Joystick::GetXChannel() const { return m_axes[static_cast(Axis::kX)]; } + +/** + * Get the channel currently associated with the Y axis. + * + * @return The channel for the axis. + */ +int Joystick::GetYChannel() const { return m_axes[static_cast(Axis::kY)]; } + +/** + * Get the channel currently associated with the Z axis. + * + * @return The channel for the axis. + */ +int Joystick::GetZChannel() const { return m_axes[static_cast(Axis::kZ)]; } + +/** + * Get the channel currently associated with the twist axis. + * + * @return The channel for the axis. + */ +int Joystick::GetTwistChannel() const { + return m_axes[static_cast(Axis::kTwist)]; +} + +/** + * Get the channel currently associated with the throttle axis. + * + * @return The channel for the axis. + */ +int Joystick::GetThrottleChannel() const { + return m_axes[static_cast(Axis::kThrottle)]; } /** @@ -92,7 +148,7 @@ Joystick* Joystick::GetStickForPort(int port) { * here to complete the GenericHID interface. */ double Joystick::GetX(JoystickHand hand) const { - return GetRawAxis(m_axes[kXAxis]); + return GetRawAxis(m_axes[kDefaultXAxis]); } /** @@ -104,7 +160,7 @@ double Joystick::GetX(JoystickHand hand) const { * here to complete the GenericHID interface. */ double Joystick::GetY(JoystickHand hand) const { - return GetRawAxis(m_axes[kYAxis]); + return GetRawAxis(m_axes[kDefaultYAxis]); } /** @@ -112,16 +168,16 @@ double Joystick::GetY(JoystickHand hand) const { * * This depends on the mapping of the joystick connected to the current port. */ -double Joystick::GetZ(JoystickHand hand) const { - return GetRawAxis(m_axes[kZAxis]); -} +double Joystick::GetZ() const { return GetRawAxis(m_axes[kDefaultZAxis]); } /** * Get the twist value of the current joystick. * * This depends on the mapping of the joystick connected to the current port. */ -double Joystick::GetTwist() const { return GetRawAxis(m_axes[kTwistAxis]); } +double Joystick::GetTwist() const { + return GetRawAxis(m_axes[kDefaultTwistAxis]); +} /** * Get the throttle value of the current joystick. @@ -129,7 +185,7 @@ double Joystick::GetTwist() const { return GetRawAxis(m_axes[kTwistAxis]); } * This depends on the mapping of the joystick connected to the current port. */ double Joystick::GetThrottle() const { - return GetRawAxis(m_axes[kThrottleAxis]); + return GetRawAxis(m_axes[kDefaultThrottleAxis]); } /** @@ -145,15 +201,15 @@ double Joystick::GetThrottle() const { double Joystick::GetAxis(AxisType axis) const { switch (axis) { case kXAxis: - return this->GetX(); + return GetX(); case kYAxis: - return this->GetY(); + return GetY(); case kZAxis: - return this->GetZ(); + return GetZ(); case kTwistAxis: - return this->GetTwist(); + return GetTwist(); case kThrottleAxis: - return this->GetThrottle(); + return GetThrottle(); default: wpi_setWPIError(BadJoystickAxis); return 0.0; @@ -165,12 +221,28 @@ double Joystick::GetAxis(AxisType axis) const { * * Look up which button has been assigned to the trigger and read its state. * - * @param hand This parameter is ignored for the Joystick class and is only - * here to complete the GenericHID interface. * @return The state of the trigger. */ -bool Joystick::GetTrigger(JoystickHand hand) const { - return GetRawButton(m_buttons[kTriggerButton]); +bool Joystick::GetTrigger() const { + return GetRawButton(static_cast(Button::kTrigger)); +} + +/** + * Whether the trigger was pressed since the last check. + * + * @return Whether the button was pressed since the last check. + */ +bool Joystick::GetTriggerPressed() { + return GetRawButtonPressed(static_cast(Button::kTrigger)); +} + +/** + * Whether the trigger was released since the last check. + * + * @return Whether the button was released since the last check. + */ +bool Joystick::GetTriggerReleased() { + return GetRawButtonReleased(static_cast(Button::kTrigger)); } /** @@ -178,12 +250,39 @@ bool Joystick::GetTrigger(JoystickHand hand) const { * * Look up which button has been assigned to the top and read its state. * - * @param hand This parameter is ignored for the Joystick class and is only - * here to complete the GenericHID interface. * @return The state of the top button. */ -bool Joystick::GetTop(JoystickHand hand) const { - return GetRawButton(m_buttons[kTopButton]); +bool Joystick::GetTop() const { + return GetRawButton(static_cast(Button::kTop)); +} + +/** + * Whether the top button was pressed since the last check. + * + * @return Whether the button was pressed since the last check. + */ +bool Joystick::GetTopPressed() { + return GetRawButtonPressed(static_cast(Button::kTop)); +} + +/** + * Whether the top button was released since the last check. + * + * @return Whether the button was released since the last check. + */ +bool Joystick::GetTopReleased() { + return GetRawButtonReleased(static_cast(Button::kTop)); +} + +Joystick* Joystick::GetStickForPort(int port) { + static std::array, DriverStation::kJoystickPorts> + joysticks{}; + auto stick = joysticks[port].get(); + if (stick == nullptr) { + joysticks[port] = std::make_unique(port); + stick = joysticks[port].get(); + } + return stick; } /** @@ -195,57 +294,8 @@ bool Joystick::GetTop(JoystickHand hand) const { * @return The state of the button. */ bool Joystick::GetButton(ButtonType button) const { - switch (button) { - case kTriggerButton: - return GetTrigger(); - case kTopButton: - return GetTop(); - default: - return false; - } -} - -/** - * Get the number of axis for a joystick - * - * @return the number of axis for the current joystick - */ -int Joystick::GetAxisCount() const { return m_ds.GetStickAxisCount(GetPort()); } - -/** - * Get the axis type of a joystick axis. - * - * @return the axis type of a joystick axis. - */ -int Joystick::GetAxisType(int axis) const { - return m_ds.GetJoystickAxisType(GetPort(), axis); -} - -/** - * Get the number of buttons for a joystick. - * - * @return the number of buttons on the current joystick - */ -int Joystick::GetButtonCount() const { - return m_ds.GetStickButtonCount(GetPort()); -} - -/** - * Get the channel currently associated with the specified axis. - * - * @param axis The axis to look up the channel for. - * @return The channel fr the axis. - */ -int Joystick::GetAxisChannel(AxisType axis) const { return m_axes[axis]; } - -/** - * Set the channel associated with a specified axis. - * - * @param axis The axis to set the channel for. - * @param channel The channel to set the axis to. - */ -void Joystick::SetAxisChannel(AxisType axis, int channel) { - m_axes[axis] = channel; + int temp = button; + return GetRawButton(static_cast(static_cast