Skip to content

Commit

Permalink
Merge branch 'main' into feature/joystick-enhancements
Browse files Browse the repository at this point in the history
  • Loading branch information
ion098 authored Oct 29, 2024
2 parents ae85554 + 0dc0a36 commit e3e6aa2
Show file tree
Hide file tree
Showing 6 changed files with 187 additions and 13 deletions.
24 changes: 24 additions & 0 deletions .github/workflows/pros-build-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Build Release

on:
release:
types: [published]

jobs:
build-release:
runs-on: ubuntu-latest

steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Build Template
id: build_step
uses: LemLib/[email protected]
with:
lib_folder_name: "gamepad"
copy_readme_and_license_to_include: true
no_commit_hash: true
- name: Upload Template To Release
uses: svenstaro/upload-release-action@v2
with:
file: ${{ github.workspace }}/${{ steps.build_step.outputs.name }}
15 changes: 12 additions & 3 deletions .github/workflows/pros-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,16 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- uses: LemLib/[email protected]
- name: Checkout Code
uses: actions/checkout@v4
- name: Build Template
id: build_step
uses: LemLib/[email protected]
with:
library-path: gamepad
lib_folder_name: "gamepad"
copy_readme_and_license_to_include: true
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: ${{ steps.build_step.outputs.name }}
path: ${{ github.workspace }}/template/*
3 changes: 1 addition & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,8 @@ EXCLUDE_COLD_LIBRARIES:=

# Set this to 1 to add additional rules to compile your project as a PROS library template
IS_LIBRARY:=1
# TODO: CHANGE THIS!
LIBNAME:=gamepad
VERSION:=0.0.1
VERSION:=0.2.0
# EXCLUDE_SRC_FROM_LIB= $(SRCDIR)/unpublishedfile.c
# this line excludes opcontrol.c and similar files
EXCLUDE_SRC_FROM_LIB+=$(foreach file, $(SRCDIR)/main,$(foreach cext,$(CEXTS),$(file).$(cext)) $(foreach cxxext,$(CXXEXTS),$(file).$(cxxext)))
Expand Down
103 changes: 97 additions & 6 deletions include/gamepad/button.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#pragma once

#include <cstdint>
#include <functional>
#include <string>

#include "event_handler.hpp"
Expand All @@ -10,6 +12,8 @@ enum EventType {
ON_LONG_PRESS,
ON_RELEASE,
ON_SHORT_RELEASE,
ON_LONG_RELEASE,
ON_REPEAT_PRESS,
};

class Button {
Expand All @@ -25,8 +29,45 @@ class Button {
uint32_t time_held = 0;
/// How long the button has been released
uint32_t time_released = 0;
/// How long the threshold should be for the longPress and shortRelease events
uint32_t long_press_threshold = 500;
/// How many times the button has been repeat-pressed
uint32_t repeat_iterations = 0;
/**
* @brief Set the time for a press to be considered a long press for the button
*
* @note this is likely to be used with the onLongPress(), onShortRelease(), onLongRelease(), or onRepeatPress()
* events
*
* @param threshold the time in ms that would be considered a long press
*
* @b Example:
* @code {.cpp}
* // change the threshold
* gamepad::master.Left.set_long_press_threshold(5000);
* // then call the function
* gamepad::master.Left.onLongPress("longPress1", []() {
* std::cout << "I was held for 5000ms instead of the 500ms default!" << std::endl;
* });
* @endcode
*/
void set_long_press_threshold(uint32_t threshold) const;
/**
* @brief Set the interval for the repeatPress event to repeat
*
* @note this is likely to be used with the onRepeatPress() event
*
* @param cooldown the interval in ms
*
* @b Example:
* @code {.cpp}
* // change the threshold
* gamepad::master.Up.set_repeat_cooldown(100);
* // then call the function
* gamepad::master.Up.onRepeatPress("repeatPress1", []() {
* std::cout << "I'm being repeated every 100ms instead of the 50ms default!" << std::endl;
* });
* @endcode
*/
void set_repeat_cooldown(uint32_t cooldown) const;
/**
* @brief Register a function to run when the button is pressed.
*
Expand All @@ -48,7 +89,7 @@ class Button {
* @brief Register a function to run when the button is long pressed.
*
* By default, onLongPress will fire when the button has been held down for
* 500ms or more, this threshold can be adjusted by changing long_press_threshold.
* 500ms or more, this threshold can be adjusted via the set_long_press_threshold() method.
*
* @warning When using this event along with onPress, both the onPress
* and onlongPress listeners may fire together.
Expand Down Expand Up @@ -89,7 +130,7 @@ class Button {
* @brief Register a function to run when the button is short released.
*
* By default, shortRelease will fire when the button has been released before 500ms, this threshold can be
* adjusted by changing long_press_threshold.
* adjusted via the set_long_press_threshold() method.
*
* @note This event will most likely be used along with the longPress event.
*
Expand All @@ -103,10 +144,52 @@ class Button {
* // Use a function...
* gamepad::master.A.onShortRelease("raiseLiftOneLevel", raiseLiftOneLevel);
* // ...or a lambda
* gamepad::master.B.onShortRelease("intakeOnePicce", []() { intake.move_relative(600, 100); });
* gamepad::master.B.onShortRelease("intakeOnePiece", []() { intake.move_relative(600, 100); });
* @endcode
*/
bool onShortRelease(std::string listenerName, std::function<void(void)> func) const;
/**
* @brief Register a function to run when the button is long released.
*
* By default, longRelease will fire when the button has been released after 500ms, this threshold can be
* adjusted via the set_long_press_threshold() method.
*
* @param listenerName The name of the listener, this must be a unique name
* @param func The function to run when the button is long released, the function MUST NOT block
* @return true The listener was successfully registered
* @return false The listener was not successfully registered (there is already a listener with this name)
*
* @b Example:
* @code {.cpp}
* // Use a function...
* gamepad::master.Up.onLongRelease("moveLiftToGround", moveLiftToGround);
* // ...or a lambda
* gamepad::master.Left.onLongRelease("spinIntake", []() { intake.move(127); });
* @endcode
*
*/
bool onLongRelease(std::string listenerName, std::function<void(void)> func) const;
/**
* @brief Register a function to run periodically after its been held
*
* By default repeatPress will start repeating after 500ms and repeat every 50ms, this can be adjusted via the
* set_long_press_threshold() and set_repeat_cooldown() methods respectively
*
* @param listenerName The name of the listener, this must be a unique name
* @param func the function to run periodically when the button is held, the function MUST NOT block
* @return true The listener was successfully registered
* @return false The listener was not successfully registered (there is already a listener with this name)
*
* @b Example:
* @code {.cpp}
* // Use a function...
* gamepad::master.X.onRepeatPress("shootDisk", shootOneDisk);
* // ...or a lambda
* gamepad::master.A.onRepeatPress("scoreOneRing", []() { intake.move_relative(200, 100); });
* @endcode
*
*/
bool onRepeatPress(std::string listenerName, std::function<void(void)> func) const;
/**
* @brief Register a function to run for a given event.
*
Expand Down Expand Up @@ -157,13 +240,21 @@ class Button {
* @param is_held Whether or not the button is currently held down
*/
void update(bool is_held);
/// he last time the update function was called
/// How long the threshold should be for the longPress and shortRelease events
mutable uint32_t long_press_threshold = 500;
/// How often repeatPress is called
mutable uint32_t repeat_cooldown = 50;
/// The last time the update function was called
uint32_t last_update_time = pros::millis();
/// The last time the long press event was fired
uint32_t last_long_press_time = 0;
/// The last time the repeat event was called
uint32_t last_repeat_time = 0;
mutable _impl::EventHandler<std::string> onPressEvent {};
mutable _impl::EventHandler<std::string> onLongPressEvent {};
mutable _impl::EventHandler<std::string> onReleaseEvent {};
mutable _impl::EventHandler<std::string> onShortReleaseEvent {};
mutable _impl::EventHandler<std::string> onLongReleaseEvent {};
mutable _impl::EventHandler<std::string> onRepeatPressEvent {};
};
} // namespace gamepad
29 changes: 28 additions & 1 deletion src/gamepad/button.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
#include "gamepad/button.hpp"
#include "gamepad/todo.hpp"
#include "pros/rtos.hpp"
#include <cstdint>
#include <sys/types.h>

namespace gamepad {
void Button::set_long_press_threshold(uint32_t threshold) const { this->long_press_threshold = threshold; }

void Button::set_repeat_cooldown(uint32_t cooldown) const { this->repeat_cooldown = cooldown; }

bool Button::onPress(std::string listenerName, std::function<void(void)> func) const {
return this->onPressEvent.add_listener(std::move(listenerName) + "_user", std::move(func));
}
Expand All @@ -19,13 +25,23 @@ bool Button::onShortRelease(std::string listenerName, std::function<void(void)>
return this->onShortReleaseEvent.add_listener(std::move(listenerName) + "_user", std::move(func));
}

bool Button::onLongRelease(std::string listenerName, std::function<void(void)> func) const {
return this->onLongReleaseEvent.add_listener(std::move(listenerName) + "_user", std::move(func));
}

bool Button::onRepeatPress(std::string listenerName, std::function<void(void)> func) const {
return this->onRepeatPressEvent.add_listener(std::move(listenerName) + "_user", std::move(func));
}

bool Button::addListener(EventType event, std::string listenerName, std::function<void(void)> func) const {
switch (event) {
case gamepad::EventType::ON_PRESS: return this->onPress(std::move(listenerName), std::move(func));
case gamepad::EventType::ON_LONG_PRESS: return this->onLongPress(std::move(listenerName), std::move(func));
case gamepad::EventType::ON_RELEASE: return this->onRelease(std::move(listenerName), std::move(func));
case gamepad::EventType::ON_SHORT_RELEASE:
return this->onShortRelease(std::move(listenerName), std::move(func));
case gamepad::EventType::ON_LONG_RELEASE: return this->onLongRelease(std::move(listenerName), std::move(func));
case gamepad::EventType::ON_REPEAT_PRESS: return this->onRepeatPress(std::move(listenerName), std::move(func));
default:
TODO("add error logging")
errno = EINVAL;
Expand All @@ -37,7 +53,9 @@ bool Button::removeListener(std::string listenerName) const {
return this->onPressEvent.remove_listener(listenerName + "_user") ||
this->onLongPressEvent.remove_listener(listenerName + "_user") ||
this->onReleaseEvent.remove_listener(listenerName + "_user") ||
this->onShortReleaseEvent.remove_listener(listenerName + "_user");
this->onShortReleaseEvent.remove_listener(listenerName + "_user") ||
this->onLongReleaseEvent.remove_listener(listenerName + "_user") ||
this->onRepeatPressEvent.remove_listener(listenerName + "_user");
}

void Button::update(const bool is_held) {
Expand All @@ -53,10 +71,19 @@ void Button::update(const bool is_held) {
this->last_long_press_time <= pros::millis() - this->time_held) {
this->onLongPressEvent.fire();
this->last_long_press_time = pros::millis();
this->last_repeat_time = pros::millis() - this->repeat_cooldown;
this->repeat_iterations = 0;
} else if (this->is_pressed && this->time_held >= this->long_press_threshold &&
pros::millis() - this->last_repeat_time >= this->repeat_cooldown) {
this->repeat_iterations++;
this->onRepeatPressEvent.fire();
this->last_repeat_time = pros::millis();
} else if (this->falling_edge) {
this->onReleaseEvent.fire();
if (this->time_held < this->long_press_threshold) this->onShortReleaseEvent.fire();
else this->onLongReleaseEvent.fire();
}

if (this->rising_edge) this->time_held = 0;
if (this->falling_edge) this->time_released = 0;
this->last_update_time = pros::millis();
Expand Down
26 changes: 25 additions & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
#include "main.h"
#include "gamepad/api.hpp"
#include "gamepad/controller.hpp"
#include "pros/rtos.hpp"
#include <cstdint>
#include <cstdio>

/**
* Runs initialization code. This occurs as soon as the program is started.
Expand All @@ -8,6 +12,8 @@
* to keep execution time for this mode under a few seconds.
*/

uint32_t last_repeat_press_time = pros::millis();

void downPress1() { printf("Down Press!\n"); }

void upRelease1() { printf("Up Release!\n"); }
Expand All @@ -16,16 +22,34 @@ void leftLongPress1() { printf("Left Long Press!\n"); }

void leftShortRelease1() { printf("Left Short Release!\n"); }

void leftLongRelease1() { printf("Left Long Release!\n"); }

void aPress1() {
last_repeat_press_time = pros::millis();
printf("A Pressed!\n");
}

void aRepeatPress1() {
printf("A Repeat Pressed %ims after last\n", pros::millis() - last_repeat_press_time);
last_repeat_press_time = pros::millis();
}

void initialize() {
// We can register functions to run when buttons are pressed
gamepad::master.Down.onPress("downPress1", downPress1);
// ...or when they're released
gamepad::master.Up.onRelease("downRelease1", upRelease1);
// There's also the longPress event
gamepad::master.Left.onLongPress("leftLongPress1", leftLongPress1);
// We can have two functions on one button,
// We can have two or even more functions on one button,
// just remember to give them different names
gamepad::master.Left.onShortRelease("leftShortRelease", leftShortRelease1);
gamepad::master.Left.onLongRelease("leftLongRelease", leftLongRelease1);
// We also have the repeat press event, where we can adjust the timing
gamepad::master.A.set_long_press_threshold(1000); // in ms
gamepad::master.A.set_repeat_cooldown(100); // in ms
gamepad::master.A.onPress("aStartPress", aPress1);
gamepad::master.A.onRepeatPress("aRepeatPress", aRepeatPress1);
// And we can use lambda's too
gamepad::master.X.onShortRelease("xShortRelease1", []() { printf("X Short Release!\n"); });
}
Expand Down

0 comments on commit e3e6aa2

Please sign in to comment.