From 09148aff5426156adb461a3792b66b914d0784a0 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Thu, 23 May 2024 12:43:44 -0700 Subject: [PATCH 01/60] Update devcontainer.json --- .devcontainer/devcontainer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index ab87be9..52968ab 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,3 +1,3 @@ { - "postCreateCommand": "chmod 777 .devcontainer/postCreateCommand.bash && .devcontainer/postCreateCommand.bash" -} \ No newline at end of file + "postCreateCommand": "chmod 777 .devcontainer/postCreateCommand.bash && .devcontainer/postCreateCommand.bash && source ~/.bashrc" +} From eabc9190d20a2a0f0ebdb2bbc3499095f79e0358 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Thu, 23 May 2024 12:44:07 -0700 Subject: [PATCH 02/60] Update postCreateCommand.bash --- .devcontainer/postCreateCommand.bash | 1 - 1 file changed, 1 deletion(-) diff --git a/.devcontainer/postCreateCommand.bash b/.devcontainer/postCreateCommand.bash index 0499fec..b0dbb37 100755 --- a/.devcontainer/postCreateCommand.bash +++ b/.devcontainer/postCreateCommand.bash @@ -6,4 +6,3 @@ curl https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu-rm/10.3 tar -xjvf gcc-arm-none-eabi-10.3-2021.10-x86_64-linux.tar.bz2 echo "PATH=$PATH:/home/codespace/gcc-arm-none-eabi-10.3-2021.10/bin" >> ~/.bashrc popd -source ~/.bashrc \ No newline at end of file From c8e0880b611e8510efacdd9389a1e2b9d05d84a9 Mon Sep 17 00:00:00 2001 From: Andrew Curtis <80860310+meisZWFLZ@users.noreply.github.com> Date: Thu, 23 May 2024 15:18:15 -0700 Subject: [PATCH 03/60] fix: :bug: Malformed URL on PR open event --- .github/workflows/pros-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pros-build.yml b/.github/workflows/pros-build.yml index abb219b..fb75934 100644 --- a/.github/workflows/pros-build.yml +++ b/.github/workflows/pros-build.yml @@ -13,6 +13,6 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: LemLib/pros-build@v1.0.0 + - uses: LemLib/pros-build@https://github.com/LemLib/Gamepad/actions/runs/9214344483/job/25350366702?pr=3 with: library-path: gamepad From a0f62b8f361ad906d17a7f0f0328370aadd9eec5 Mon Sep 17 00:00:00 2001 From: Andrew Curtis <80860310+meisZWFLZ@users.noreply.github.com> Date: Thu, 23 May 2024 15:22:33 -0700 Subject: [PATCH 04/60] :green_heart: That should be a SHA.. .. not a URL! how could ctrl c ctrl v have betrayed me :( --- .github/workflows/pros-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pros-build.yml b/.github/workflows/pros-build.yml index fb75934..6dbaaac 100644 --- a/.github/workflows/pros-build.yml +++ b/.github/workflows/pros-build.yml @@ -13,6 +13,6 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: LemLib/pros-build@https://github.com/LemLib/Gamepad/actions/runs/9214344483/job/25350366702?pr=3 + - uses: LemLib/pros-build@e0f3251974c2f5b044b8e5d8665db7cfcb5dfad7 with: library-path: gamepad From 7c5ac05e23b1646520dff21ac79fda0cc35bdad3 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Fri, 24 May 2024 21:30:28 +0000 Subject: [PATCH 05/60] add more event handling methods --- include/gamepad/controller.hpp | 21 +++++++++--------- src/gamepad/controller.cpp | 39 +++++++++++++++++++++++----------- 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/include/gamepad/controller.hpp b/include/gamepad/controller.hpp index 2c520e0..d7af3b1 100644 --- a/include/gamepad/controller.hpp +++ b/include/gamepad/controller.hpp @@ -24,24 +24,25 @@ class Button { bool rising_edge = false; bool falling_edge = false; bool is_pressed = false; - uint32_t last_press_time = pros::millis(); - uint32_t last_release_time = last_press_time; + //uint32_t last_press_time = pros::millis(); + //uint32_t last_release_time = last_press_time; uint32_t time_held = 0; uint32_t time_released = 0; uint32_t long_press_threshold = 500; - uint32_t onPress(std::function func); - uint32_t onLongPress(std::function func); - uint32_t onRelease(std::function func); - uint32_t addListener(EventType event, std::function func); - bool removeListener(uint32_t id); + uint32_t onPress(std::function func) const; + uint32_t onLongPress(std::function func) const; + uint32_t onRelease(std::function func) const; + uint32_t addListener(EventType event, std::function func) const; + bool removeListener(uint32_t id) const; private: void update(bool is_held); - EventHandler<> onPressEvent; - EventHandler<> onLongPressEvent; - EventHandler<> onReleaseEvent; + uint32_t last_update_time = pros::millis(); + mutable EventHandler<> onPressEvent{}; + mutable EventHandler<> onLongPressEvent{}; + mutable EventHandler<> onReleaseEvent{}; }; class Controller { diff --git a/src/gamepad/controller.cpp b/src/gamepad/controller.cpp index 4472527..cc7d994 100644 --- a/src/gamepad/controller.cpp +++ b/src/gamepad/controller.cpp @@ -3,28 +3,41 @@ namespace Gamepad { -uint32_t Button::onPress(std::function func) { +uint32_t Button::onPress(std::function func) const { return this->onPressEvent.add_listener(std::move(func)); } -uint32_t Button::onLongPress(std::function func) { +uint32_t Button::onLongPress(std::function func) const { return this->onLongPressEvent.add_listener(std::move(func)); } -uint32_t Button::onRelease(std::function func) { +uint32_t Button::onRelease(std::function func) const { return this->onReleaseEvent.add_listener(std::move(func)); } -void Button::update(const bool is_held) { - static uint32_t last_update_time = pros::millis(); +uint32_t Button::addListener(EventType event, std::function func) const { + switch (event) { + case Gamepad::EventType::ON_PRESS: + this->onPress(std::move(func)); + case Gamepad::EventType::ON_LONG_PRESS: + this->onLongPress(std::move(func)); + case Gamepad::EventType::ON_RELEASE: + this->onRelease(std::move(func)); + } +} +bool Button::removeListener(uint32_t id) const { + return this->onPressEvent.remove_listener(id) || this->onLongPressEvent.remove_listener(id) || this->onReleaseEvent.remove_listener(id); +} + +void Button::update(const bool is_held) { this->rising_edge = !this->is_pressed && is_held; this->falling_edge = this->is_pressed && !is_held; this->is_pressed = is_held; if (is_held) { - this->time_held += pros::millis() - last_update_time; + this->time_held += pros::millis() - this->last_update_time; } else { - this->time_released += pros::millis() - last_update_time; + this->time_released += pros::millis() - this->last_update_time; } if (this->rising_edge) { this->time_held = 0; @@ -34,12 +47,14 @@ void Button::update(const bool is_held) { } if (this->rising_edge) { - onPressEvent.fire(); - } else if (this->falling_edge) { - onReleaseEvent.fire(); + this->onPressEvent.fire(); + } else if (this->is_pressed && this->time_held >= this->long_press_threshold) { + TODO("change onLongPress handling if onPress is present") + this->onLongPressEvent.fire(); + }else if (this->falling_edge) { + this->onReleaseEvent.fire(); } - TODO("implement longPress"); - last_update_time = pros::millis(); + this->last_update_time = pros::millis(); } void Controller::updateButton(pros::controller_digital_e_t button_id) { From c3fa9796b54d02f4a1ed5728494a714fef6ba117 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Fri, 24 May 2024 21:33:58 +0000 Subject: [PATCH 06/60] add operator bool to Button --- include/gamepad/controller.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/gamepad/controller.hpp b/include/gamepad/controller.hpp index d7af3b1..7ba75ef 100644 --- a/include/gamepad/controller.hpp +++ b/include/gamepad/controller.hpp @@ -35,6 +35,9 @@ class Button { uint32_t onRelease(std::function func) const; uint32_t addListener(EventType event, std::function func) const; bool removeListener(uint32_t id) const; + explicit operator bool() const { + return is_pressed; + } private: void update(bool is_held); From 565ade4ea61504c55def8c09b6b9b8f8208244b2 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Fri, 24 May 2024 21:38:40 +0000 Subject: [PATCH 07/60] Format all files --- include/gamepad/controller.hpp | 56 ++++++++++++------------- include/gamepad/event_handler.hpp | 70 ++++++++++++++++--------------- include/gamepad/todo.hpp | 6 +-- src/gamepad/controller.cpp | 38 +++++++---------- 4 files changed, 80 insertions(+), 90 deletions(-) diff --git a/include/gamepad/controller.hpp b/include/gamepad/controller.hpp index 7ba75ef..1c4cf9d 100644 --- a/include/gamepad/controller.hpp +++ b/include/gamepad/controller.hpp @@ -19,38 +19,38 @@ enum EventType { }; class Button { - friend class Controller; + friend class Controller; public: - bool rising_edge = false; - bool falling_edge = false; - bool is_pressed = false; - //uint32_t last_press_time = pros::millis(); - //uint32_t last_release_time = last_press_time; - uint32_t time_held = 0; - uint32_t time_released = 0; - uint32_t long_press_threshold = 500; + bool rising_edge = false; + bool falling_edge = false; + bool is_pressed = false; + // uint32_t last_press_time = pros::millis(); + // uint32_t last_release_time = last_press_time; + uint32_t time_held = 0; + uint32_t time_released = 0; + uint32_t long_press_threshold = 500; - uint32_t onPress(std::function func) const; - uint32_t onLongPress(std::function func) const; - uint32_t onRelease(std::function func) const; - uint32_t addListener(EventType event, std::function func) const; - bool removeListener(uint32_t id) const; - explicit operator bool() const { - return is_pressed; - } - private: + uint32_t onPress(std::function func) const; + uint32_t onLongPress(std::function func) const; + uint32_t onRelease(std::function func) const; + uint32_t addListener(EventType event, std::function func) const; + bool removeListener(uint32_t id) const; - void update(bool is_held); + explicit operator bool() const { return is_pressed; } + private: + void update(bool is_held); - uint32_t last_update_time = pros::millis(); - mutable EventHandler<> onPressEvent{}; - mutable EventHandler<> onLongPressEvent{}; - mutable EventHandler<> onReleaseEvent{}; + uint32_t last_update_time = pros::millis(); + mutable EventHandler<> onPressEvent {}; + mutable EventHandler<> onLongPressEvent {}; + mutable EventHandler<> onReleaseEvent {}; }; class Controller { public: - explicit Controller(pros::controller_id_e_t id): controller(id) {} + explicit Controller(pros::controller_id_e_t id) + : controller(id) {} + /** * Updates the state of the gamepad (all joysticks and buttons), and also runs * any registered handlers. @@ -69,13 +69,11 @@ class Controller { */ float operator[](pros::controller_analog_e_t joystick); TODO("hide memebrs and expose getters/const refs") - Button L1{}, L2{}, R1{}, R2{}, - Up{}, Down{}, Left{}, Right{}, - X{}, B{}, Y{}, A{}; + Button L1 {}, L2 {}, R1 {}, R2 {}, Up {}, Down {}, Left {}, Right {}, X {}, B {}, Y {}, A {}; float LeftX = 0, LeftY = 0, RightX = 0, RightY = 0; private: - static Button Controller::* button_to_ptr(pros::controller_digital_e_t button); + static Button Controller::*button_to_ptr(pros::controller_digital_e_t button); void updateButton(pros::controller_digital_e_t button_id); pros::Controller controller; }; // namespace Gamepad -} \ No newline at end of file +} // namespace Gamepad \ No newline at end of file diff --git a/include/gamepad/event_handler.hpp b/include/gamepad/event_handler.hpp index 6bdc188..d4660a0 100644 --- a/include/gamepad/event_handler.hpp +++ b/include/gamepad/event_handler.hpp @@ -12,44 +12,46 @@ namespace Gamepad { class MonotonicCounter { - template friend class EventHandler; - static uint32_t next_value() { - static std::atomic counter = 0; - return ++counter; - } + template friend class EventHandler; + + static uint32_t next_value() { + static std::atomic counter = 0; + return ++counter; + } }; -template -class EventHandler { +template class EventHandler { public: - using Listener = std::function; - uint32_t add_listener(Listener func) { - std::lock_guard lock(mutex); - uint32_t id = MonotonicCounter::next_value(); - listeners.emplace(id, std::move(func)); - return id; - } - bool remove_listener(uint32_t id) { - std::lock_guard lock(mutex); - if(listeners.find(id) == listeners.end()) { - TODO("change handling maybe?") - return false; + using Listener = std::function; + + uint32_t add_listener(Listener func) { + std::lock_guard lock(mutex); + uint32_t id = MonotonicCounter::next_value(); + listeners.emplace(id, std::move(func)); + return id; + } + + bool remove_listener(uint32_t id) { + std::lock_guard lock(mutex); + if (listeners.find(id) == listeners.end()) { + TODO("change handling maybe?") + return false; + } + listeners.erase(id); + return true; + } + + bool is_empty() { + std::lock_guard lock(mutex); + return listeners.empty(); } - listeners.erase(id); - return true; - } - bool is_empty() { - std::lock_guard lock(mutex); - return listeners.empty(); - } - void fire(Args... args) { - std::lock_guard lock(mutex); - for(auto listener : listeners) { - listener.second(args...); + + void fire(Args... args) { + std::lock_guard lock(mutex); + for (auto listener : listeners) { listener.second(args...); } } - } private: - std::map listeners; - pros::Mutex mutex; + std::map listeners; + pros::Mutex mutex; }; -} \ No newline at end of file +} // namespace Gamepad \ No newline at end of file diff --git a/include/gamepad/todo.hpp b/include/gamepad/todo.hpp index 6d61cf6..c1e0b7b 100644 --- a/include/gamepad/todo.hpp +++ b/include/gamepad/todo.hpp @@ -1,5 +1,5 @@ #pragma once -#define DO_PRAGMA(x) _Pragma (#x) -#define TODO(x) DO_PRAGMA(message ("TODO - " #x)) -#define FIXME(x) DO_PRAGMA(warning ("FIXME - " #x)) \ No newline at end of file +#define DO_PRAGMA(x) _Pragma(#x) +#define TODO(x) DO_PRAGMA(message("TODO - " #x)) +#define FIXME(x) DO_PRAGMA(warning("FIXME - " #x)) \ No newline at end of file diff --git a/src/gamepad/controller.cpp b/src/gamepad/controller.cpp index cc7d994..f2a35a1 100644 --- a/src/gamepad/controller.cpp +++ b/src/gamepad/controller.cpp @@ -17,17 +17,15 @@ uint32_t Button::onRelease(std::function func) const { uint32_t Button::addListener(EventType event, std::function func) const { switch (event) { - case Gamepad::EventType::ON_PRESS: - this->onPress(std::move(func)); - case Gamepad::EventType::ON_LONG_PRESS: - this->onLongPress(std::move(func)); - case Gamepad::EventType::ON_RELEASE: - this->onRelease(std::move(func)); + case Gamepad::EventType::ON_PRESS: this->onPress(std::move(func)); + case Gamepad::EventType::ON_LONG_PRESS: this->onLongPress(std::move(func)); + case Gamepad::EventType::ON_RELEASE: this->onRelease(std::move(func)); } } bool Button::removeListener(uint32_t id) const { - return this->onPressEvent.remove_listener(id) || this->onLongPressEvent.remove_listener(id) || this->onReleaseEvent.remove_listener(id); + return this->onPressEvent.remove_listener(id) || this->onLongPressEvent.remove_listener(id) || + this->onReleaseEvent.remove_listener(id); } void Button::update(const bool is_held) { @@ -39,34 +37,28 @@ void Button::update(const bool is_held) { } else { this->time_released += pros::millis() - this->last_update_time; } - if (this->rising_edge) { - this->time_held = 0; - } - if (this->falling_edge) { - this->time_released = 0; - } + if (this->rising_edge) { this->time_held = 0; } + if (this->falling_edge) { this->time_released = 0; } if (this->rising_edge) { this->onPressEvent.fire(); } else if (this->is_pressed && this->time_held >= this->long_press_threshold) { TODO("change onLongPress handling if onPress is present") this->onLongPressEvent.fire(); - }else if (this->falling_edge) { + } else if (this->falling_edge) { this->onReleaseEvent.fire(); } this->last_update_time = pros::millis(); } void Controller::updateButton(pros::controller_digital_e_t button_id) { - Button Controller::* button = Controller::button_to_ptr(button_id); + Button Controller::*button = Controller::button_to_ptr(button_id); bool is_held = this->controller.get_digital(button_id); (this->*button).update(is_held); } void Controller::update() { - for(int i = DIGITAL_L1; i != DIGITAL_A; ++i) { - this->updateButton(static_cast(i)); - } + for (int i = DIGITAL_L1; i != DIGITAL_A; ++i) { this->updateButton(static_cast(i)); } this->LeftX = this->controller.get_analog(ANALOG_LEFT_X); this->LeftY = this->controller.get_analog(ANALOG_LEFT_Y); @@ -83,13 +75,12 @@ float Controller::operator[](pros::controller_analog_e_t axis) { case ANALOG_LEFT_X: return this->LeftX; case ANALOG_LEFT_Y: return this->LeftY; case ANALOG_RIGHT_X: return this->RightX; - case ANALOG_RIGHT_Y: return this->RightY; - TODO("change handling for default") + case ANALOG_RIGHT_Y: return this->RightY; TODO("change handling for default") default: std::exit(1); } } -Button Controller::* Controller::button_to_ptr(pros::controller_digital_e_t button) { +Button Controller::*Controller::button_to_ptr(pros::controller_digital_e_t button) { switch (button) { case DIGITAL_L1: return &Controller::L1; case DIGITAL_L2: return &Controller::L2; @@ -102,9 +93,8 @@ Button Controller::* Controller::button_to_ptr(pros::controller_digital_e_t butt case DIGITAL_X: return &Controller::X; case DIGITAL_B: return &Controller::B; case DIGITAL_Y: return &Controller::Y; - case DIGITAL_A: return &Controller::A; - TODO("change handling for default") + case DIGITAL_A: return &Controller::A; TODO("change handling for default") default: std::exit(1); } } -} \ No newline at end of file +} // namespace Gamepad \ No newline at end of file From 9ad720f01c642454976f53a99715e09ac7ff9743 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Mon, 27 May 2024 18:01:21 +0000 Subject: [PATCH 08/60] change handling of default cases --- include/gamepad/controller.hpp | 1 + src/gamepad/controller.cpp | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/include/gamepad/controller.hpp b/include/gamepad/controller.hpp index 1c4cf9d..1c09a2b 100644 --- a/include/gamepad/controller.hpp +++ b/include/gamepad/controller.hpp @@ -72,6 +72,7 @@ class Controller { Button L1 {}, L2 {}, R1 {}, R2 {}, Up {}, Down {}, Left {}, Right {}, X {}, B {}, Y {}, A {}; float LeftX = 0, LeftY = 0, RightX = 0, RightY = 0; private: + Button Fake{}; static Button Controller::*button_to_ptr(pros::controller_digital_e_t button); void updateButton(pros::controller_digital_e_t button_id); pros::Controller controller; diff --git a/src/gamepad/controller.cpp b/src/gamepad/controller.cpp index f2a35a1..1a2e1e5 100644 --- a/src/gamepad/controller.cpp +++ b/src/gamepad/controller.cpp @@ -75,8 +75,11 @@ float Controller::operator[](pros::controller_analog_e_t axis) { case ANALOG_LEFT_X: return this->LeftX; case ANALOG_LEFT_Y: return this->LeftY; case ANALOG_RIGHT_X: return this->RightX; - case ANALOG_RIGHT_Y: return this->RightY; TODO("change handling for default") - default: std::exit(1); + case ANALOG_RIGHT_Y: return this->RightY; + default: + TODO("add error logging") + errno = EINVAL; + return 0; } } @@ -94,7 +97,10 @@ Button Controller::*Controller::button_to_ptr(pros::controller_digital_e_t butto case DIGITAL_B: return &Controller::B; case DIGITAL_Y: return &Controller::Y; case DIGITAL_A: return &Controller::A; TODO("change handling for default") - default: std::exit(1); + default: + TODO("add error logging") + errno = EINVAL; + return &Controller::Fake; } } } // namespace Gamepad \ No newline at end of file From f4d01f38f23825c321401cd143de3b98a59053b4 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Mon, 27 May 2024 18:02:45 +0000 Subject: [PATCH 09/60] added missing return and default case to Button::addListener --- src/gamepad/controller.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/gamepad/controller.cpp b/src/gamepad/controller.cpp index 1a2e1e5..9a9a18e 100644 --- a/src/gamepad/controller.cpp +++ b/src/gamepad/controller.cpp @@ -17,9 +17,13 @@ uint32_t Button::onRelease(std::function func) const { uint32_t Button::addListener(EventType event, std::function func) const { switch (event) { - case Gamepad::EventType::ON_PRESS: this->onPress(std::move(func)); - case Gamepad::EventType::ON_LONG_PRESS: this->onLongPress(std::move(func)); - case Gamepad::EventType::ON_RELEASE: this->onRelease(std::move(func)); + case Gamepad::EventType::ON_PRESS: return this->onPress(std::move(func)); + case Gamepad::EventType::ON_LONG_PRESS: return this->onLongPress(std::move(func)); + case Gamepad::EventType::ON_RELEASE: return this->onRelease(std::move(func)); + default: + TODO("add error logging") + errno = EINVAL; + return 0; } } From 8466e2c194d7d77052f1ec711ee193cb5abbe23f Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Mon, 27 May 2024 18:03:38 +0000 Subject: [PATCH 10/60] fix switch formatting --- src/gamepad/controller.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/gamepad/controller.cpp b/src/gamepad/controller.cpp index 9a9a18e..7b81cc8 100644 --- a/src/gamepad/controller.cpp +++ b/src/gamepad/controller.cpp @@ -21,9 +21,9 @@ uint32_t Button::addListener(EventType event, std::function func) co case Gamepad::EventType::ON_LONG_PRESS: return this->onLongPress(std::move(func)); case Gamepad::EventType::ON_RELEASE: return this->onRelease(std::move(func)); default: - TODO("add error logging") - errno = EINVAL; - return 0; + TODO("add error logging") + errno = EINVAL; + return 0; } } @@ -81,9 +81,9 @@ float Controller::operator[](pros::controller_analog_e_t axis) { case ANALOG_RIGHT_X: return this->RightX; case ANALOG_RIGHT_Y: return this->RightY; default: - TODO("add error logging") - errno = EINVAL; - return 0; + TODO("add error logging") + errno = EINVAL; + return 0; } } @@ -102,9 +102,9 @@ Button Controller::*Controller::button_to_ptr(pros::controller_digital_e_t butto case DIGITAL_Y: return &Controller::Y; case DIGITAL_A: return &Controller::A; TODO("change handling for default") default: - TODO("add error logging") - errno = EINVAL; - return &Controller::Fake; + TODO("add error logging") + errno = EINVAL; + return &Controller::Fake; } } } // namespace Gamepad \ No newline at end of file From 0d221e67afafffb9a4deb7a7631448b7ae212090 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Mon, 27 May 2024 18:05:56 +0000 Subject: [PATCH 11/60] remove unnecessary todo --- src/gamepad/controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gamepad/controller.cpp b/src/gamepad/controller.cpp index 7b81cc8..fa50253 100644 --- a/src/gamepad/controller.cpp +++ b/src/gamepad/controller.cpp @@ -100,7 +100,7 @@ Button Controller::*Controller::button_to_ptr(pros::controller_digital_e_t butto case DIGITAL_X: return &Controller::X; case DIGITAL_B: return &Controller::B; case DIGITAL_Y: return &Controller::Y; - case DIGITAL_A: return &Controller::A; TODO("change handling for default") + case DIGITAL_A: return &Controller::A; default: TODO("add error logging") errno = EINVAL; From c397474b38ce28c428d6e464b597ad9730ea441f Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Mon, 27 May 2024 18:24:40 +0000 Subject: [PATCH 12/60] hide buttons / joystick values and expose const refs to users instead --- include/gamepad/controller.hpp | 23 ++++++++++++++++++++--- src/gamepad/controller.cpp | 32 ++++++++++++++++---------------- 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/include/gamepad/controller.hpp b/include/gamepad/controller.hpp index 1c09a2b..858a45c 100644 --- a/include/gamepad/controller.hpp +++ b/include/gamepad/controller.hpp @@ -69,10 +69,27 @@ class Controller { */ float operator[](pros::controller_analog_e_t joystick); TODO("hide memebrs and expose getters/const refs") - Button L1 {}, L2 {}, R1 {}, R2 {}, Up {}, Down {}, Left {}, Right {}, X {}, B {}, Y {}, A {}; - float LeftX = 0, LeftY = 0, RightX = 0, RightY = 0; + const Button& L1 {m_L1}; + const Button& L2 {m_L2}; + const Button& R1 {m_R1}; + const Button& R2 {m_R2}; + const Button& Up {m_Up}; + const Button& Down {m_Down}; + const Button& Left {m_Left}; + const Button& Right {m_Right}; + const Button& X {m_X}; + const Button& B {m_B}; + const Button& Y {m_Y}; + const Button& A {m_Down}; + const float& LeftX = m_LeftX; + const float& LeftY = m_LeftY; + const float& RightX = m_RightX; + const float& RightY = m_RightY; private: - Button Fake{}; + Button m_L1 {}, m_L2 {}, m_R1 {}, m_R2 {}, m_Up {}, m_Down {}, m_Left {}, m_Right {}, m_X {}, m_B {}, m_Y {}, + m_A {}; + float m_LeftX = 0, m_LeftY = 0, m_RightX = 0, m_RightY = 0; + Button Fake {}; static Button Controller::*button_to_ptr(pros::controller_digital_e_t button); void updateButton(pros::controller_digital_e_t button_id); pros::Controller controller; diff --git a/src/gamepad/controller.cpp b/src/gamepad/controller.cpp index fa50253..33e1412 100644 --- a/src/gamepad/controller.cpp +++ b/src/gamepad/controller.cpp @@ -64,10 +64,10 @@ void Controller::updateButton(pros::controller_digital_e_t button_id) { void Controller::update() { for (int i = DIGITAL_L1; i != DIGITAL_A; ++i) { this->updateButton(static_cast(i)); } - this->LeftX = this->controller.get_analog(ANALOG_LEFT_X); - this->LeftY = this->controller.get_analog(ANALOG_LEFT_Y); - this->RightX = this->controller.get_analog(ANALOG_RIGHT_X); - this->RightY = this->controller.get_analog(ANALOG_RIGHT_Y); + this->m_LeftX = this->controller.get_analog(ANALOG_LEFT_X); + this->m_LeftY = this->controller.get_analog(ANALOG_LEFT_Y); + this->m_RightX = this->controller.get_analog(ANALOG_RIGHT_X); + this->m_RightY = this->controller.get_analog(ANALOG_RIGHT_Y); } const Button& Controller::operator[](pros::controller_digital_e_t button) { @@ -89,18 +89,18 @@ float Controller::operator[](pros::controller_analog_e_t axis) { Button Controller::*Controller::button_to_ptr(pros::controller_digital_e_t button) { switch (button) { - case DIGITAL_L1: return &Controller::L1; - case DIGITAL_L2: return &Controller::L2; - case DIGITAL_R1: return &Controller::R1; - case DIGITAL_R2: return &Controller::R2; - case DIGITAL_UP: return &Controller::Up; - case DIGITAL_DOWN: return &Controller::Down; - case DIGITAL_LEFT: return &Controller::Left; - case DIGITAL_RIGHT: return &Controller::Right; - case DIGITAL_X: return &Controller::X; - case DIGITAL_B: return &Controller::B; - case DIGITAL_Y: return &Controller::Y; - case DIGITAL_A: return &Controller::A; + case DIGITAL_L1: return &Controller::m_L1; + case DIGITAL_L2: return &Controller::m_L2; + case DIGITAL_R1: return &Controller::m_R1; + case DIGITAL_R2: return &Controller::m_R2; + case DIGITAL_UP: return &Controller::m_Up; + case DIGITAL_DOWN: return &Controller::m_Down; + case DIGITAL_LEFT: return &Controller::m_Left; + case DIGITAL_RIGHT: return &Controller::m_Right; + case DIGITAL_X: return &Controller::m_X; + case DIGITAL_B: return &Controller::m_B; + case DIGITAL_Y: return &Controller::m_Y; + case DIGITAL_A: return &Controller::m_A; default: TODO("add error logging") errno = EINVAL; From af8e66d18a2aab533533c1f899e49e4f7d94e1f2 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Tue, 28 May 2024 22:05:39 +0000 Subject: [PATCH 13/60] implement nifty counter for Controller --- include/gamepad/controller.hpp | 13 +++++++++++-- src/gamepad/controller.cpp | 27 +++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/include/gamepad/controller.hpp b/include/gamepad/controller.hpp index 2c520e0..4758b38 100644 --- a/include/gamepad/controller.hpp +++ b/include/gamepad/controller.hpp @@ -45,8 +45,8 @@ class Button { }; class Controller { + friend struct ControllerInit; public: - explicit Controller(pros::controller_id_e_t id): controller(id) {} /** * Updates the state of the gamepad (all joysticks and buttons), and also runs * any registered handlers. @@ -70,8 +70,17 @@ class Controller { X{}, B{}, Y{}, A{}; float LeftX = 0, LeftY = 0, RightX = 0, RightY = 0; private: + explicit Controller(pros::controller_id_e_t id): controller(id) {} static Button Controller::* button_to_ptr(pros::controller_digital_e_t button); void updateButton(pros::controller_digital_e_t button_id); pros::Controller controller; -}; // namespace Gamepad +}; + +static struct ControllerInit { + ControllerInit(); + ~ControllerInit(); +} _controllerInit; + +extern Controller& master; +extern Controller& partner; } \ No newline at end of file diff --git a/src/gamepad/controller.cpp b/src/gamepad/controller.cpp index 4472527..4d96a9d 100644 --- a/src/gamepad/controller.cpp +++ b/src/gamepad/controller.cpp @@ -1,8 +1,35 @@ #include "gamepad/controller.hpp" #include "gamepad/todo.hpp" +#include "pros/misc.h" + +#include +#include +#include namespace Gamepad { +static int nifty_counter; // zero initialized at load time +static std::array master_buf alignas(Controller); +Controller& master = *reinterpret_cast (&*master_buf.begin()); +static std::array partner_buf alignas(Controller); +Controller& partner = *reinterpret_cast (&*partner_buf.begin()); + +ControllerInit::ControllerInit() { + if(nifty_counter == 0) { + new (&*master_buf.begin()) Controller(pros::E_CONTROLLER_MASTER); + new (&*partner_buf.begin()) Controller(pros::E_CONTROLLER_PARTNER); + } + ++nifty_counter; +} + +ControllerInit::~ControllerInit() { + --nifty_counter; + if(nifty_counter == 0) { + master.~Controller(); + partner.~Controller(); + } +} + uint32_t Button::onPress(std::function func) { return this->onPressEvent.add_listener(std::move(func)); } From 3dc4a6712ce4d0f64b997f2bf3bca3a185f4ea07 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Tue, 28 May 2024 22:05:52 +0000 Subject: [PATCH 14/60] use Gamepad in main.cpp --- src/main.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 1cc258a..381e9b0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,5 @@ #include "main.h" +#include "gamepad/api.hpp" /** * A callback function for LLEMU's center button. @@ -74,19 +75,15 @@ void autonomous() {} * task, not resume it from where it left off. */ void opcontrol() { - pros::Controller master(pros::E_CONTROLLER_MASTER); + pros::MotorGroup left_mg({1, -2, 3}); // Creates a motor group with forwards ports 1 & 3 and reversed port 2 pros::MotorGroup right_mg({-4, 5, -6}); // Creates a motor group with forwards port 4 and reversed ports 4 & 6 while (true) { - pros::lcd::print(0, "%d %d %d", (pros::lcd::read_buttons() & LCD_BTN_LEFT) >> 2, - (pros::lcd::read_buttons() & LCD_BTN_CENTER) >> 1, - - (pros::lcd::read_buttons() & LCD_BTN_RIGHT) >> 0); // Prints status of the emulated screen LCDs - + Gamepad::master.update(); // Arcade control scheme - int dir = master.get_analog(ANALOG_LEFT_Y); // Gets amount forward/backward from left joystick - int turn = master.get_analog(ANALOG_RIGHT_X); // Gets the turn left/right from right joystick + int dir = Gamepad::master.LeftY; // Gets amount forward/backward from left joystick + int turn = Gamepad::master.RightX; // Gets the turn left/right from right joystick left_mg.move(dir - turn); // Sets left motor voltage right_mg.move(dir + turn); // Sets right motor voltage pros::delay(20); // Run for 20 ms then update From 4ce005773d68544626e8c210b9765b3604aa015e Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Wed, 29 May 2024 16:57:35 +0000 Subject: [PATCH 15/60] use union instead of array for Controller buffer --- src/gamepad/controller.cpp | 59 +++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/src/gamepad/controller.cpp b/src/gamepad/controller.cpp index 4d96a9d..d151483 100644 --- a/src/gamepad/controller.cpp +++ b/src/gamepad/controller.cpp @@ -3,36 +3,43 @@ #include "pros/misc.h" #include -#include -#include namespace Gamepad { -static int nifty_counter; // zero initialized at load time -static std::array master_buf alignas(Controller); -Controller& master = *reinterpret_cast (&*master_buf.begin()); -static std::array partner_buf alignas(Controller); -Controller& partner = *reinterpret_cast (&*partner_buf.begin()); +union ControllerBuf { + // this is here to allow us to control when we initialize the Controller + char c; + Controller as_controller; + + // empty destructor, the Controller must be manually destroyed by ControllerInit + ~ControllerBuf() {} +}; + +static uint32_t nifty_counter; // zero initialized at load time +ControllerBuf master_buf {}; +Controller& master = master_buf.as_controller; +ControllerBuf partner_buf {}; +Controller& partner = partner_buf.as_controller; ControllerInit::ControllerInit() { - if(nifty_counter == 0) { - new (&*master_buf.begin()) Controller(pros::E_CONTROLLER_MASTER); - new (&*partner_buf.begin()) Controller(pros::E_CONTROLLER_PARTNER); + // only initialize once, if we're the first ControllerInit instance + if (nifty_counter == 0) { + new (&master_buf.as_controller) Controller(pros::E_CONTROLLER_MASTER); + new (&partner_buf.as_controller) Controller(pros::E_CONTROLLER_PARTNER); } ++nifty_counter; } ControllerInit::~ControllerInit() { --nifty_counter; - if(nifty_counter == 0) { + // only destroy if we're the last ControllerInit instance + if (nifty_counter == 0) { master.~Controller(); partner.~Controller(); } } -uint32_t Button::onPress(std::function func) { - return this->onPressEvent.add_listener(std::move(func)); -} +uint32_t Button::onPress(std::function func) { return this->onPressEvent.add_listener(std::move(func)); } uint32_t Button::onLongPress(std::function func) { return this->onLongPressEvent.add_listener(std::move(func)); @@ -53,12 +60,8 @@ void Button::update(const bool is_held) { } else { this->time_released += pros::millis() - last_update_time; } - if (this->rising_edge) { - this->time_held = 0; - } - if (this->falling_edge) { - this->time_released = 0; - } + if (this->rising_edge) { this->time_held = 0; } + if (this->falling_edge) { this->time_released = 0; } if (this->rising_edge) { onPressEvent.fire(); @@ -70,15 +73,13 @@ void Button::update(const bool is_held) { } void Controller::updateButton(pros::controller_digital_e_t button_id) { - Button Controller::* button = Controller::button_to_ptr(button_id); + Button Controller::*button = Controller::button_to_ptr(button_id); bool is_held = this->controller.get_digital(button_id); (this->*button).update(is_held); } void Controller::update() { - for(int i = DIGITAL_L1; i != DIGITAL_A; ++i) { - this->updateButton(static_cast(i)); - } + for (int i = DIGITAL_L1; i != DIGITAL_A; ++i) { this->updateButton(static_cast(i)); } this->LeftX = this->controller.get_analog(ANALOG_LEFT_X); this->LeftY = this->controller.get_analog(ANALOG_LEFT_Y); @@ -95,13 +96,12 @@ float Controller::operator[](pros::controller_analog_e_t axis) { case ANALOG_LEFT_X: return this->LeftX; case ANALOG_LEFT_Y: return this->LeftY; case ANALOG_RIGHT_X: return this->RightX; - case ANALOG_RIGHT_Y: return this->RightY; - TODO("change handling for default") + case ANALOG_RIGHT_Y: return this->RightY; TODO("change handling for default") default: std::exit(1); } } -Button Controller::* Controller::button_to_ptr(pros::controller_digital_e_t button) { +Button Controller::*Controller::button_to_ptr(pros::controller_digital_e_t button) { switch (button) { case DIGITAL_L1: return &Controller::L1; case DIGITAL_L2: return &Controller::L2; @@ -114,9 +114,8 @@ Button Controller::* Controller::button_to_ptr(pros::controller_digital_e_t butt case DIGITAL_X: return &Controller::X; case DIGITAL_B: return &Controller::B; case DIGITAL_Y: return &Controller::Y; - case DIGITAL_A: return &Controller::A; - TODO("change handling for default") + case DIGITAL_A: return &Controller::A; TODO("change handling for default") default: std::exit(1); } } -} \ No newline at end of file +} // namespace Gamepad \ No newline at end of file From 3ded29687561ec4ba78f946ff9c437e615ec83ea Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Wed, 29 May 2024 17:06:22 +0000 Subject: [PATCH 16/60] hide controllerInit in _impl namespace --- include/gamepad/controller.hpp | 62 ++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/include/gamepad/controller.hpp b/include/gamepad/controller.hpp index 4758b38..f00baf2 100644 --- a/include/gamepad/controller.hpp +++ b/include/gamepad/controller.hpp @@ -19,33 +19,32 @@ enum EventType { }; class Button { - friend class Controller; + friend class Controller; public: - bool rising_edge = false; - bool falling_edge = false; - bool is_pressed = false; - uint32_t last_press_time = pros::millis(); - uint32_t last_release_time = last_press_time; - uint32_t time_held = 0; - uint32_t time_released = 0; - uint32_t long_press_threshold = 500; + bool rising_edge = false; + bool falling_edge = false; + bool is_pressed = false; + uint32_t last_press_time = pros::millis(); + uint32_t last_release_time = last_press_time; + uint32_t time_held = 0; + uint32_t time_released = 0; + uint32_t long_press_threshold = 500; - uint32_t onPress(std::function func); - uint32_t onLongPress(std::function func); - uint32_t onRelease(std::function func); - uint32_t addListener(EventType event, std::function func); - bool removeListener(uint32_t id); + uint32_t onPress(std::function func); + uint32_t onLongPress(std::function func); + uint32_t onRelease(std::function func); + uint32_t addListener(EventType event, std::function func); + bool removeListener(uint32_t id); private: + void update(bool is_held); - void update(bool is_held); - - EventHandler<> onPressEvent; - EventHandler<> onLongPressEvent; - EventHandler<> onReleaseEvent; + EventHandler<> onPressEvent; + EventHandler<> onLongPressEvent; + EventHandler<> onReleaseEvent; }; class Controller { - friend struct ControllerInit; + friend struct ControllerInit; public: /** * Updates the state of the gamepad (all joysticks and buttons), and also runs @@ -65,22 +64,25 @@ class Controller { */ float operator[](pros::controller_analog_e_t joystick); TODO("hide memebrs and expose getters/const refs") - Button L1{}, L2{}, R1{}, R2{}, - Up{}, Down{}, Left{}, Right{}, - X{}, B{}, Y{}, A{}; + Button L1 {}, L2 {}, R1 {}, R2 {}, Up {}, Down {}, Left {}, Right {}, X {}, B {}, Y {}, A {}; float LeftX = 0, LeftY = 0, RightX = 0, RightY = 0; private: - explicit Controller(pros::controller_id_e_t id): controller(id) {} - static Button Controller::* button_to_ptr(pros::controller_digital_e_t button); + explicit Controller(pros::controller_id_e_t id) + : controller(id) {} + + static Button Controller::*button_to_ptr(pros::controller_digital_e_t button); void updateButton(pros::controller_digital_e_t button_id); pros::Controller controller; }; +extern Controller& master; +extern Controller& partner; + +namespace _impl { static struct ControllerInit { - ControllerInit(); - ~ControllerInit(); + ControllerInit(); + ~ControllerInit(); } _controllerInit; +} // namespace _impl -extern Controller& master; -extern Controller& partner; -} \ No newline at end of file +} // namespace Gamepad \ No newline at end of file From 6321e53cf5b59671463f7c98040714ef11bf138e Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Wed, 29 May 2024 17:09:05 +0000 Subject: [PATCH 17/60] fix compile error, move ControllerInit ctor and dtor to _impl namespace --- src/gamepad/controller.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gamepad/controller.cpp b/src/gamepad/controller.cpp index d151483..5754b54 100644 --- a/src/gamepad/controller.cpp +++ b/src/gamepad/controller.cpp @@ -21,7 +21,7 @@ Controller& master = master_buf.as_controller; ControllerBuf partner_buf {}; Controller& partner = partner_buf.as_controller; -ControllerInit::ControllerInit() { +_impl::ControllerInit::ControllerInit() { // only initialize once, if we're the first ControllerInit instance if (nifty_counter == 0) { new (&master_buf.as_controller) Controller(pros::E_CONTROLLER_MASTER); @@ -30,7 +30,7 @@ ControllerInit::ControllerInit() { ++nifty_counter; } -ControllerInit::~ControllerInit() { +_impl::ControllerInit::~ControllerInit() { --nifty_counter; // only destroy if we're the last ControllerInit instance if (nifty_counter == 0) { From fd24a3f09880d07afdd36d748dc2f95183dcb56d Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Wed, 29 May 2024 17:12:00 +0000 Subject: [PATCH 18/60] fixed more compile issues, fixed all declarations to be in correct namespace --- include/gamepad/controller.hpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/gamepad/controller.hpp b/include/gamepad/controller.hpp index f00baf2..acc7a9e 100644 --- a/include/gamepad/controller.hpp +++ b/include/gamepad/controller.hpp @@ -43,8 +43,15 @@ class Button { EventHandler<> onReleaseEvent; }; +namespace _impl { +static struct ControllerInit { + ControllerInit(); + ~ControllerInit(); +} _controllerInit; +} // namespace _impl + class Controller { - friend struct ControllerInit; + friend struct _impl::ControllerInit; public: /** * Updates the state of the gamepad (all joysticks and buttons), and also runs @@ -78,11 +85,4 @@ class Controller { extern Controller& master; extern Controller& partner; -namespace _impl { -static struct ControllerInit { - ControllerInit(); - ~ControllerInit(); -} _controllerInit; -} // namespace _impl - } // namespace Gamepad \ No newline at end of file From 8613f8fe4946529b0ef51e9ef9c4dc49efdf458c Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Sun, 2 Jun 2024 12:58:49 -0700 Subject: [PATCH 19/60] fix onLongPress so it does not repeatedly fire --- include/gamepad/controller.hpp | 1 + src/gamepad/controller.cpp | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/include/gamepad/controller.hpp b/include/gamepad/controller.hpp index 858a45c..b4ef6f4 100644 --- a/include/gamepad/controller.hpp +++ b/include/gamepad/controller.hpp @@ -42,6 +42,7 @@ class Button { uint32_t last_update_time = pros::millis(); mutable EventHandler<> onPressEvent {}; + uint32_t last_long_press_time = 0; mutable EventHandler<> onLongPressEvent {}; mutable EventHandler<> onReleaseEvent {}; }; diff --git a/src/gamepad/controller.cpp b/src/gamepad/controller.cpp index 33e1412..0ab9851 100644 --- a/src/gamepad/controller.cpp +++ b/src/gamepad/controller.cpp @@ -46,9 +46,11 @@ void Button::update(const bool is_held) { if (this->rising_edge) { this->onPressEvent.fire(); - } else if (this->is_pressed && this->time_held >= this->long_press_threshold) { + } else if (this->is_pressed && this->time_held >= this->long_press_threshold && + this->last_long_press_time > pros::millis() - this->time_held) { TODO("change onLongPress handling if onPress is present") this->onLongPressEvent.fire(); + this->last_long_press_time = pros::millis(); } else if (this->falling_edge) { this->onReleaseEvent.fire(); } From 7d22c8b66d3864488c3c943c2ebf8deb0c6c014d Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Wed, 5 Jun 2024 12:05:25 -0700 Subject: [PATCH 20/60] fix long press so it actually fires --- src/gamepad/controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gamepad/controller.cpp b/src/gamepad/controller.cpp index 0ab9851..2962876 100644 --- a/src/gamepad/controller.cpp +++ b/src/gamepad/controller.cpp @@ -47,7 +47,7 @@ void Button::update(const bool is_held) { if (this->rising_edge) { this->onPressEvent.fire(); } else if (this->is_pressed && this->time_held >= this->long_press_threshold && - this->last_long_press_time > pros::millis() - this->time_held) { + this->last_long_press_time <= pros::millis() - this->time_held) { TODO("change onLongPress handling if onPress is present") this->onLongPressEvent.fire(); this->last_long_press_time = pros::millis(); From 2b4d5ab2e2714caf2e0a97b144d90357b19975f1 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Wed, 5 Jun 2024 12:05:59 -0700 Subject: [PATCH 21/60] update example code in main.cpp --- src/main.cpp | 62 ++++++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 34 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 1cc258a..6836c8e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,20 +1,8 @@ #include "main.h" +#include "Gamepad/api.hpp" +#include "pros/screen.hpp" -/** - * A callback function for LLEMU's center button. - * - * When this callback is fired, it will toggle line 2 of the LCD text between - * "I was pressed!" and nothing. - */ -void on_center_button() { - static bool pressed = false; - pressed = !pressed; - if (pressed) { - pros::lcd::set_text(2, "I was pressed!"); - } else { - pros::lcd::clear_line(2); - } -} +Gamepad::Controller master(CONTROLLER_MASTER); /** * Runs initialization code. This occurs as soon as the program is started. @@ -23,10 +11,6 @@ void on_center_button() { * to keep execution time for this mode under a few seconds. */ void initialize() { - pros::lcd::initialize(); - pros::lcd::set_text(1, "Hello PROS User!"); - - pros::lcd::register_btn1_cb(on_center_button); } /** @@ -74,21 +58,31 @@ void autonomous() {} * task, not resume it from where it left off. */ void opcontrol() { - pros::Controller master(pros::E_CONTROLLER_MASTER); - pros::MotorGroup left_mg({1, -2, 3}); // Creates a motor group with forwards ports 1 & 3 and reversed port 2 - pros::MotorGroup right_mg({-4, 5, -6}); // Creates a motor group with forwards port 4 and reversed ports 4 & 6 - + master.Down.onPress([](){ + printf("Down Press!\n"); + }); + master.Down.onLongPress([](){ + printf("Down longPress!\n"); + }); + master.Down.onRelease([](){ + printf("Down Release!\n"); + }); + master.Up.onPress([](){ + printf("Up Press!\n"); + }); + master.Up.onLongPress([](){ + printf("Up longPress!\n"); + }); + auto i = master.Up.onRelease([](){ + printf("Up Release!\n"); + }); + master.Up.onRelease([=](){ + // master.Up.removeListener(i); + printf("Up Release 2!\n"); + }); while (true) { - pros::lcd::print(0, "%d %d %d", (pros::lcd::read_buttons() & LCD_BTN_LEFT) >> 2, - (pros::lcd::read_buttons() & LCD_BTN_CENTER) >> 1, - - (pros::lcd::read_buttons() & LCD_BTN_RIGHT) >> 0); // Prints status of the emulated screen LCDs - - // Arcade control scheme - int dir = master.get_analog(ANALOG_LEFT_Y); // Gets amount forward/backward from left joystick - int turn = master.get_analog(ANALOG_RIGHT_X); // Gets the turn left/right from right joystick - left_mg.move(dir - turn); // Sets left motor voltage - right_mg.move(dir + turn); // Sets right motor voltage - pros::delay(20); // Run for 20 ms then update + master.update(); + pros::screen::print(TEXT_MEDIUM, 3, "%f %f %f %f", master.LeftX, master.LeftY, master.RightX, master.RightY); + pros::delay(20); } } \ No newline at end of file From 6e152b84351608c630378a880fa473cd8ef77158 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Wed, 5 Jun 2024 12:15:22 -0700 Subject: [PATCH 22/60] Add RecursiveMutex class and fix deadlock in remove_listener --- include/gamepad/event_handler.hpp | 3 ++- include/gamepad/recursive_mutex.hpp | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 include/gamepad/recursive_mutex.hpp diff --git a/include/gamepad/event_handler.hpp b/include/gamepad/event_handler.hpp index d4660a0..1469c86 100644 --- a/include/gamepad/event_handler.hpp +++ b/include/gamepad/event_handler.hpp @@ -7,6 +7,7 @@ #include #include "gamepad/todo.hpp" +#include "gamepad/recursive_mutex.hpp" #include "pros/rtos.hpp" namespace Gamepad { @@ -52,6 +53,6 @@ template class EventHandler { } private: std::map listeners; - pros::Mutex mutex; + Gamepad::RecursiveMutex mutex; }; } // namespace Gamepad \ No newline at end of file diff --git a/include/gamepad/recursive_mutex.hpp b/include/gamepad/recursive_mutex.hpp new file mode 100644 index 0000000..42bdb46 --- /dev/null +++ b/include/gamepad/recursive_mutex.hpp @@ -0,0 +1,29 @@ +#include "pros/apix.h" +#include "pros/rtos.h" +#include + +namespace Gamepad { + +class RecursiveMutex { + public: + RecursiveMutex(): mutex(pros::c::mutex_recursive_create()) {} + bool take(std::uint32_t timeout = TIMEOUT_MAX) { + return pros::c::mutex_recursive_take(mutex, timeout); + } + void lock() { + if (!this->take()) throw std::system_error(); + } + bool try_lock() { + return this->take(0); + } + bool give() { + return pros::c::mutex_recursive_give(mutex); + } + void unlock() { + this->give(); + } + private: + pros::mutex_t mutex; +}; + +} \ No newline at end of file From 490620b63e32bf847c26ac2ab7152703bd335c97 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Wed, 5 Jun 2024 12:15:42 -0700 Subject: [PATCH 23/60] add removeListener test to main.cpp --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 6836c8e..ef74086 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -77,7 +77,7 @@ void opcontrol() { printf("Up Release!\n"); }); master.Up.onRelease([=](){ - // master.Up.removeListener(i); + master.Up.removeListener(i); printf("Up Release 2!\n"); }); while (true) { From b4742e5da66ed73fa05a4b62e8116d4737626cae Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Wed, 5 Jun 2024 12:17:52 -0700 Subject: [PATCH 24/60] Fix capitalization error in #include file path --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index ef74086..60d9185 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,5 @@ #include "main.h" -#include "Gamepad/api.hpp" +#include "gamepad/api.hpp" #include "pros/screen.hpp" Gamepad::Controller master(CONTROLLER_MASTER); From 1832d76d4ea9ce40464180376039f5a14da91c4c Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Thu, 6 Jun 2024 17:35:46 -0700 Subject: [PATCH 25/60] remove unnecessary todos and includes --- include/gamepad/controller.hpp | 1 - include/gamepad/event_handler.hpp | 3 --- 2 files changed, 4 deletions(-) diff --git a/include/gamepad/controller.hpp b/include/gamepad/controller.hpp index b4ef6f4..3615d3c 100644 --- a/include/gamepad/controller.hpp +++ b/include/gamepad/controller.hpp @@ -69,7 +69,6 @@ class Controller { * @param joystick Which joystick axis's value to return */ float operator[](pros::controller_analog_e_t joystick); - TODO("hide memebrs and expose getters/const refs") const Button& L1 {m_L1}; const Button& L2 {m_L2}; const Button& R1 {m_R1}; diff --git a/include/gamepad/event_handler.hpp b/include/gamepad/event_handler.hpp index 1469c86..d3be159 100644 --- a/include/gamepad/event_handler.hpp +++ b/include/gamepad/event_handler.hpp @@ -6,9 +6,7 @@ #include #include -#include "gamepad/todo.hpp" #include "gamepad/recursive_mutex.hpp" -#include "pros/rtos.hpp" namespace Gamepad { @@ -35,7 +33,6 @@ template class EventHandler { bool remove_listener(uint32_t id) { std::lock_guard lock(mutex); if (listeners.find(id) == listeners.end()) { - TODO("change handling maybe?") return false; } listeners.erase(id); From fb93b8412b958dd2875b2412d270f42790ba8e40 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Thu, 4 Jul 2024 17:33:30 -0700 Subject: [PATCH 26/60] feat: :sparkles: Add names to button listeners --- include/gamepad/controller.hpp | 17 ++++++------ include/gamepad/event_handler.hpp | 44 +++++++++++++----------------- src/gamepad/controller.cpp | 28 +++++++++---------- src/main.cpp | 45 +++++++++++-------------------- 4 files changed, 58 insertions(+), 76 deletions(-) diff --git a/include/gamepad/controller.hpp b/include/gamepad/controller.hpp index 3615d3c..1e2debf 100644 --- a/include/gamepad/controller.hpp +++ b/include/gamepad/controller.hpp @@ -2,6 +2,7 @@ #include #include +#include #ifndef PROS_USE_SIMPLE_NAMES #define PROS_USE_SIMPLE_NAMES #endif @@ -30,21 +31,21 @@ class Button { uint32_t time_released = 0; uint32_t long_press_threshold = 500; - uint32_t onPress(std::function func) const; - uint32_t onLongPress(std::function func) const; - uint32_t onRelease(std::function func) const; - uint32_t addListener(EventType event, std::function func) const; - bool removeListener(uint32_t id) const; + bool onPress(std::string listenerName, std::function func) const; + bool onLongPress(std::string listenerName, std::function func) const; + bool onRelease(std::string listenerName, std::function func) const; + bool addListener(EventType event, std::string listenerName, std::function func) const; + bool removeListener(std::string listenerName) const; explicit operator bool() const { return is_pressed; } private: void update(bool is_held); uint32_t last_update_time = pros::millis(); - mutable EventHandler<> onPressEvent {}; + mutable EventHandler onPressEvent {}; uint32_t last_long_press_time = 0; - mutable EventHandler<> onLongPressEvent {}; - mutable EventHandler<> onReleaseEvent {}; + mutable EventHandler onLongPressEvent {}; + mutable EventHandler onReleaseEvent {}; }; class Controller { diff --git a/include/gamepad/event_handler.hpp b/include/gamepad/event_handler.hpp index d3be159..e8fd680 100644 --- a/include/gamepad/event_handler.hpp +++ b/include/gamepad/event_handler.hpp @@ -1,42 +1,35 @@ #pragma once #include -#include #include -#include -#include +#include +#include #include "gamepad/recursive_mutex.hpp" namespace Gamepad { -class MonotonicCounter { - template friend class EventHandler; - - static uint32_t next_value() { - static std::atomic counter = 0; - return ++counter; - } -}; - -template class EventHandler { +template class EventHandler { public: using Listener = std::function; - uint32_t add_listener(Listener func) { + bool add_listener(Key key, Listener func) { std::lock_guard lock(mutex); - uint32_t id = MonotonicCounter::next_value(); - listeners.emplace(id, std::move(func)); - return id; + if (std::find(keys.begin(), keys.end(), key) == keys.end()) return false; + keys.push_back(key); + listeners.push_back(func); + return true; } - bool remove_listener(uint32_t id) { + bool remove_listener(Key key) { std::lock_guard lock(mutex); - if (listeners.find(id) == listeners.end()) { - return false; + auto i = std::find(keys.begin(), keys.end(), key); + if (i != keys.end()) { + keys.erase(i); + listeners.erase(listeners.begin() + (i - keys.begin())); + return true; } - listeners.erase(id); - return true; + return false; } bool is_empty() { @@ -46,10 +39,11 @@ template class EventHandler { void fire(Args... args) { std::lock_guard lock(mutex); - for (auto listener : listeners) { listener.second(args...); } + for (auto listener : listeners) { listener(args...); } } private: - std::map listeners; - Gamepad::RecursiveMutex mutex; + std::vector keys {}; + std::vector listeners {}; + Gamepad::RecursiveMutex mutex {}; }; } // namespace Gamepad \ No newline at end of file diff --git a/src/gamepad/controller.cpp b/src/gamepad/controller.cpp index 2962876..22af469 100644 --- a/src/gamepad/controller.cpp +++ b/src/gamepad/controller.cpp @@ -3,33 +3,33 @@ namespace Gamepad { -uint32_t Button::onPress(std::function func) const { - return this->onPressEvent.add_listener(std::move(func)); +bool Button::onPress(std::string listenerName, std::function func) const { + return this->onPressEvent.add_listener(std::move(listenerName), std::move(func)); } -uint32_t Button::onLongPress(std::function func) const { - return this->onLongPressEvent.add_listener(std::move(func)); +bool Button::onLongPress(std::string listenerName, std::function func) const { + return this->onLongPressEvent.add_listener(std::move(listenerName), std::move(func)); } -uint32_t Button::onRelease(std::function func) const { - return this->onReleaseEvent.add_listener(std::move(func)); +bool Button::onRelease(std::string listenerName, std::function func) const { + return this->onReleaseEvent.add_listener(std::move(listenerName), std::move(func)); } -uint32_t Button::addListener(EventType event, std::function func) const { +bool Button::addListener(EventType event, std::string listenerName, std::function func) const { switch (event) { - case Gamepad::EventType::ON_PRESS: return this->onPress(std::move(func)); - case Gamepad::EventType::ON_LONG_PRESS: return this->onLongPress(std::move(func)); - case Gamepad::EventType::ON_RELEASE: return this->onRelease(std::move(func)); + 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)); default: TODO("add error logging") errno = EINVAL; - return 0; + return false; } } -bool Button::removeListener(uint32_t id) const { - return this->onPressEvent.remove_listener(id) || this->onLongPressEvent.remove_listener(id) || - this->onReleaseEvent.remove_listener(id); +bool Button::removeListener(std::string listenerName) const { + return this->onPressEvent.remove_listener(listenerName) || this->onLongPressEvent.remove_listener(listenerName) || + this->onReleaseEvent.remove_listener(listenerName); } void Button::update(const bool is_held) { diff --git a/src/main.cpp b/src/main.cpp index 60d9185..db867db 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,8 +10,7 @@ Gamepad::Controller master(CONTROLLER_MASTER); * All other competition modes are blocked by initialize; it is recommended * to keep execution time for this mode under a few seconds. */ -void initialize() { -} +void initialize() {} /** * Runs while the robot is in the disabled state of Field Management System or @@ -58,31 +57,19 @@ void autonomous() {} * task, not resume it from where it left off. */ void opcontrol() { - master.Down.onPress([](){ - printf("Down Press!\n"); - }); - master.Down.onLongPress([](){ - printf("Down longPress!\n"); - }); - master.Down.onRelease([](){ - printf("Down Release!\n"); - }); - master.Up.onPress([](){ - printf("Up Press!\n"); - }); - master.Up.onLongPress([](){ - printf("Up longPress!\n"); - }); - auto i = master.Up.onRelease([](){ - printf("Up Release!\n"); - }); - master.Up.onRelease([=](){ - master.Up.removeListener(i); - printf("Up Release 2!\n"); - }); - while (true) { - master.update(); - pros::screen::print(TEXT_MEDIUM, 3, "%f %f %f %f", master.LeftX, master.LeftY, master.RightX, master.RightY); - pros::delay(20); - } + master.Down.onPress("downPress1", []() { printf("Down Press!\n"); }); + master.Down.onLongPress("downLongPress1", []() { printf("Down longPress!\n"); }); + master.Down.onRelease("downRelease1", []() { printf("Down Release!\n"); }); + master.Up.onPress("uppress1", []() { printf("Up Press!\n"); }); + master.Up.onLongPress("upLongPress1", []() { printf("Up longPress!\n"); }); + master.Up.onRelease("upRelease1", []() { printf("Up Release!\n"); }); + master.Up.onRelease("upRelease2", [=]() { + master.Up.removeListener("upRelease1"); + printf("Up Release 2!\n"); + }); + while (true) { + master.update(); + pros::screen::print(TEXT_MEDIUM, 3, "%f %f %f %f", master.LeftX, master.LeftY, master.RightX, master.RightY); + pros::delay(20); + } } \ No newline at end of file From e14160d32c3e89fa9c4cb2a672615087df09d03a Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Thu, 4 Jul 2024 17:42:08 -0700 Subject: [PATCH 27/60] feat: :sparkles: Add shortRelease button event --- include/gamepad/controller.hpp | 3 +++ src/gamepad/controller.cpp | 14 +++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/include/gamepad/controller.hpp b/include/gamepad/controller.hpp index 1e2debf..5d5e275 100644 --- a/include/gamepad/controller.hpp +++ b/include/gamepad/controller.hpp @@ -17,6 +17,7 @@ enum EventType { ON_PRESS, ON_LONG_PRESS, ON_RELEASE, + ON_SHORT_RELEASE, }; class Button { @@ -34,6 +35,7 @@ class Button { bool onPress(std::string listenerName, std::function func) const; bool onLongPress(std::string listenerName, std::function func) const; bool onRelease(std::string listenerName, std::function func) const; + bool onShortRelease(std::string listenerName, std::function func) const; bool addListener(EventType event, std::string listenerName, std::function func) const; bool removeListener(std::string listenerName) const; @@ -46,6 +48,7 @@ class Button { uint32_t last_long_press_time = 0; mutable EventHandler onLongPressEvent {}; mutable EventHandler onReleaseEvent {}; + mutable EventHandler onShortReleaseEvent {}; }; class Controller { diff --git a/src/gamepad/controller.cpp b/src/gamepad/controller.cpp index 22af469..e2c3438 100644 --- a/src/gamepad/controller.cpp +++ b/src/gamepad/controller.cpp @@ -15,11 +15,17 @@ bool Button::onRelease(std::string listenerName, std::function func) return this->onReleaseEvent.add_listener(std::move(listenerName), std::move(func)); } +bool Button::onShortRelease(std::string listenerName, std::function func) const { + return this->onShortReleaseEvent.add_listener(std::move(listenerName), std::move(func)); +} + bool Button::addListener(EventType event, std::string listenerName, std::function 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)); default: TODO("add error logging") errno = EINVAL; @@ -29,7 +35,8 @@ bool Button::addListener(EventType event, std::string listenerName, std::functio bool Button::removeListener(std::string listenerName) const { return this->onPressEvent.remove_listener(listenerName) || this->onLongPressEvent.remove_listener(listenerName) || - this->onReleaseEvent.remove_listener(listenerName); + this->onReleaseEvent.remove_listener(listenerName) || + this->onShortReleaseEvent.remove_listener(listenerName); } void Button::update(const bool is_held) { @@ -41,8 +48,6 @@ void Button::update(const bool is_held) { } else { this->time_released += pros::millis() - this->last_update_time; } - if (this->rising_edge) { this->time_held = 0; } - if (this->falling_edge) { this->time_released = 0; } if (this->rising_edge) { this->onPressEvent.fire(); @@ -53,7 +58,10 @@ void Button::update(const bool is_held) { this->last_long_press_time = pros::millis(); } else if (this->falling_edge) { this->onReleaseEvent.fire(); + if (this->time_held < this->long_press_threshold) { this->onShortReleaseEvent.fire(); } } + if (this->rising_edge) { this->time_held = 0; } + if (this->falling_edge) { this->time_released = 0; } this->last_update_time = pros::millis(); } From 54b5302f72b47777640c659b627670e3346b0f6d Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Mon, 8 Jul 2024 10:34:02 -0700 Subject: [PATCH 28/60] feat: :sparkles: Allow internal code to add listeners that don't conflict with user listener names --- include/gamepad/controller.hpp | 1 + src/gamepad/controller.cpp | 20 +++++++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/include/gamepad/controller.hpp b/include/gamepad/controller.hpp index 5d5e275..8b92af9 100644 --- a/include/gamepad/controller.hpp +++ b/include/gamepad/controller.hpp @@ -94,6 +94,7 @@ class Controller { m_A {}; float m_LeftX = 0, m_LeftY = 0, m_RightX = 0, m_RightY = 0; Button Fake {}; + static std::string unique_name(); static Button Controller::*button_to_ptr(pros::controller_digital_e_t button); void updateButton(pros::controller_digital_e_t button_id); pros::Controller controller; diff --git a/src/gamepad/controller.cpp b/src/gamepad/controller.cpp index e2c3438..e7a0b49 100644 --- a/src/gamepad/controller.cpp +++ b/src/gamepad/controller.cpp @@ -1,22 +1,23 @@ #include "gamepad/controller.hpp" #include "gamepad/todo.hpp" +#include namespace Gamepad { bool Button::onPress(std::string listenerName, std::function func) const { - return this->onPressEvent.add_listener(std::move(listenerName), std::move(func)); + return this->onPressEvent.add_listener(std::move(listenerName) + "_user", std::move(func)); } bool Button::onLongPress(std::string listenerName, std::function func) const { - return this->onLongPressEvent.add_listener(std::move(listenerName), std::move(func)); + return this->onLongPressEvent.add_listener(std::move(listenerName) + "_user", std::move(func)); } bool Button::onRelease(std::string listenerName, std::function func) const { - return this->onReleaseEvent.add_listener(std::move(listenerName), std::move(func)); + return this->onReleaseEvent.add_listener(std::move(listenerName) + "_user", std::move(func)); } bool Button::onShortRelease(std::string listenerName, std::function func) const { - return this->onShortReleaseEvent.add_listener(std::move(listenerName), std::move(func)); + return this->onShortReleaseEvent.add_listener(std::move(listenerName) + "_user", std::move(func)); } bool Button::addListener(EventType event, std::string listenerName, std::function func) const { @@ -34,9 +35,9 @@ bool Button::addListener(EventType event, std::string listenerName, std::functio } bool Button::removeListener(std::string listenerName) const { - return this->onPressEvent.remove_listener(listenerName) || this->onLongPressEvent.remove_listener(listenerName) || - this->onReleaseEvent.remove_listener(listenerName) || - this->onShortReleaseEvent.remove_listener(listenerName); + 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"); } void Button::update(const bool is_held) { @@ -97,6 +98,11 @@ float Controller::operator[](pros::controller_analog_e_t axis) { } } +std::string Controller::unique_name() { + static std::atomic i = 0; + return std::to_string(i++) + "_internal"; +} + Button Controller::*Controller::button_to_ptr(pros::controller_digital_e_t button) { switch (button) { case DIGITAL_L1: return &Controller::m_L1; From 55c678203627533301158b51b02e5aa3e9bbd32b Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Sat, 13 Jul 2024 10:54:24 -0700 Subject: [PATCH 29/60] fix: :bug: Allow handlers to actually be registered --- include/gamepad/event_handler.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/gamepad/event_handler.hpp b/include/gamepad/event_handler.hpp index e8fd680..4eeec0e 100644 --- a/include/gamepad/event_handler.hpp +++ b/include/gamepad/event_handler.hpp @@ -15,7 +15,7 @@ template class EventHandler { bool add_listener(Key key, Listener func) { std::lock_guard lock(mutex); - if (std::find(keys.begin(), keys.end(), key) == keys.end()) return false; + if (std::find(keys.begin(), keys.end(), key) != keys.end()) return false; keys.push_back(key); listeners.push_back(func); return true; From e02fedfe243190391442ea2cc64e70405d81bb7d Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Sat, 13 Jul 2024 10:55:30 -0700 Subject: [PATCH 30/60] test: :white_check_mark: Add shortRelease test in main.cpp --- src/main.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index db867db..11754d7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -57,12 +57,14 @@ void autonomous() {} * task, not resume it from where it left off. */ void opcontrol() { - master.Down.onPress("downPress1", []() { printf("Down Press!\n"); }); + auto i = master.Down.onPress("downPress1", []() { printf("Down Press!\n"); }); + if (!i) std::cout << "opcontrol ran again, event did not register!" << std::endl; master.Down.onLongPress("downLongPress1", []() { printf("Down longPress!\n"); }); master.Down.onRelease("downRelease1", []() { printf("Down Release!\n"); }); master.Up.onPress("uppress1", []() { printf("Up Press!\n"); }); master.Up.onLongPress("upLongPress1", []() { printf("Up longPress!\n"); }); master.Up.onRelease("upRelease1", []() { printf("Up Release!\n"); }); + master.Up.onShortRelease("upShortRelease1", []() { printf("Up Short Release!\n"); }); master.Up.onRelease("upRelease2", [=]() { master.Up.removeListener("upRelease1"); printf("Up Release 2!\n"); From 907cbf589ccff853202b9990ca4772590cbb2ccb Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Sat, 13 Jul 2024 11:23:28 -0700 Subject: [PATCH 31/60] docs: :memo: Add documentation to Button, Controller, and EventHandler classes --- include/gamepad/controller.hpp | 107 ++++++++++++++++++++++++++++-- include/gamepad/event_handler.hpp | 32 +++++++++ 2 files changed, 133 insertions(+), 6 deletions(-) diff --git a/include/gamepad/controller.hpp b/include/gamepad/controller.hpp index 8b92af9..ff73b99 100644 --- a/include/gamepad/controller.hpp +++ b/include/gamepad/controller.hpp @@ -23,29 +23,118 @@ enum EventType { class Button { friend class Controller; public: + /** + * @brief Whether the button has just been pressed + * + */ bool rising_edge = false; + /** + * @brief Whether the button has just been released + * + */ bool falling_edge = false; + /** + * @brief Whether the button is currently held down + * + */ bool is_pressed = false; - // uint32_t last_press_time = pros::millis(); - // uint32_t last_release_time = last_press_time; + /** + * @brief How long the button has been held down + * + */ uint32_t time_held = 0; + /** + * @brief How long the button has been released + * + */ uint32_t time_released = 0; + /** + * @brief How long the threshold should be for the longPress and shortRelease events + * + */ uint32_t long_press_threshold = 500; - + /** + * @brief Register a function to run when the button is pressed. + * + * @param listenerName The name of the listener, this must be a unique name + * @param func The function to run when the button is pressed, 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) + */ bool onPress(std::string listenerName, std::function func) const; + /** + * @brief Register a function to run when the button is long pressed (The button has been held down for 500ms or + * more, this threshold can be adjusted by changing long_press_threshold). + * + * @param listenerName The name of the listener, this must be a unique name + * @param func The function to run when the button is long pressed, 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) + */ bool onLongPress(std::string listenerName, std::function func) const; + /** + * @brief Register a function to run when the button is released. + * + * @param listenerName The name of the listener, this must be a unique name + * @param func The function to run when the button is 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) + */ bool onRelease(std::string listenerName, std::function func) const; + /** + * @brief Register a function to run when the button is short released (The button has been released before + * 500ms, this threshold can be adjusted by changing long_press_threshold). + * + * @param listenerName The name of the listener, this must be a unique name + * @param func The function to run when the button is short 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) + */ bool onShortRelease(std::string listenerName, std::function func) const; + /** + * @brief Register a function to run for a given event. + * + * @param event Which event to register the listener on. + * @param listenerName The name of the listener, this must be a unique name + * @param func The function to run for the given event, 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) + */ bool addListener(EventType event, std::string listenerName, std::function func) const; + /** + * @brief Removes a listener from the button + * + * @param listenerName The name of the listener to remove + * @return true The listener was successfully removed + * @return false The listener was not removed + */ bool removeListener(std::string listenerName) const; + /** + * @brief Returns a value indicating whether the button is currently being held. + * + * @return true The button is currently pressed + * @return false The button is not currently pressed + */ explicit operator bool() const { return is_pressed; } private: + /** + * @brief Updates the button and runs any event handlers, if necessary + * + * @param is_held Whether or not the button is currently held down + */ void update(bool is_held); - + /** + * @brief The last time the update function was called + * + */ uint32_t last_update_time = pros::millis(); - mutable EventHandler onPressEvent {}; + /** + * @brief The last time the long press event was fired + * + */ uint32_t last_long_press_time = 0; + mutable EventHandler onPressEvent {}; mutable EventHandler onLongPressEvent {}; mutable EventHandler onReleaseEvent {}; mutable EventHandler onShortReleaseEvent {}; @@ -60,7 +149,6 @@ class Controller { * Updates the state of the gamepad (all joysticks and buttons), and also runs * any registered handlers. * @note This function should be called at the beginning of every loop iteration. - * @note Create a separate instance for each task. */ void update(); /** @@ -94,6 +182,13 @@ class Controller { m_A {}; float m_LeftX = 0, m_LeftY = 0, m_RightX = 0, m_RightY = 0; Button Fake {}; + /** + * @brief Gets a unique name for a listener that will not conflict with user listener names. IMPORTANT: when + * using the function, you must register the listener by directly calling add_listener on the EventHandler, do + * NOT use onPress/addListener,etc. + * + * @return std::string A unique listener name + */ static std::string unique_name(); static Button Controller::*button_to_ptr(pros::controller_digital_e_t button); void updateButton(pros::controller_digital_e_t button_id); diff --git a/include/gamepad/event_handler.hpp b/include/gamepad/event_handler.hpp index 4eeec0e..6956acb 100644 --- a/include/gamepad/event_handler.hpp +++ b/include/gamepad/event_handler.hpp @@ -9,10 +9,24 @@ namespace Gamepad { +/** + * @brief Event handling class with thread safety that supports adding, removing, and running listeners + * + * @tparam Key the key type for (un)registering listener (this type MUST support operator== and operator!=) + * @tparam Args the types of the parameters that each listener is passed + */ template class EventHandler { public: using Listener = std::function; + /** + * @brief Add a listener to the list of listeners + * + * @param key The listener key (this must be a unique key value) + * @param func The function to run when this event is fired + * @return true The listener was successfully added + * @return false The listener was NOT successfully added (there is already a listener with the same key) + */ bool add_listener(Key key, Listener func) { std::lock_guard lock(mutex); if (std::find(keys.begin(), keys.end(), key) != keys.end()) return false; @@ -21,6 +35,13 @@ template class EventHandler { return true; } + /** + * @brief Remove a listener from the list of listeners + * + * @param key The listener key (this must be a unique key value) + * @return true The listener was successfully removed + * @return false The listener was NOT successfully removed (there is no listener with the same key) + */ bool remove_listener(Key key) { std::lock_guard lock(mutex); auto i = std::find(keys.begin(), keys.end(), key); @@ -32,11 +53,22 @@ template class EventHandler { return false; } + /** + * @brief Whther or not there are any listeners registered + * + * @return true There are listeners registered + * @return false There are no listeners registered + */ bool is_empty() { std::lock_guard lock(mutex); return listeners.empty(); } + /** + * @brief Runs each listener registered + * + * @param args The parameters to pass to each listener + */ void fire(Args... args) { std::lock_guard lock(mutex); for (auto listener : listeners) { listener(args...); } From 10f33ce03b6da86a9e9e0ec0f433a9cf3088278f Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Fri, 19 Jul 2024 11:11:08 -0700 Subject: [PATCH 32/60] refactor: :recycle: Move EventHandler and RecursiveMutex to Gamepad::_impl namespace --- include/gamepad/controller.hpp | 8 ++++---- include/gamepad/event_handler.hpp | 4 ++-- include/gamepad/recursive_mutex.hpp | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/gamepad/controller.hpp b/include/gamepad/controller.hpp index ff73b99..cf319f0 100644 --- a/include/gamepad/controller.hpp +++ b/include/gamepad/controller.hpp @@ -134,10 +134,10 @@ class Button { * */ uint32_t last_long_press_time = 0; - mutable EventHandler onPressEvent {}; - mutable EventHandler onLongPressEvent {}; - mutable EventHandler onReleaseEvent {}; - mutable EventHandler onShortReleaseEvent {}; + mutable _impl::EventHandler onPressEvent {}; + mutable _impl::EventHandler onLongPressEvent {}; + mutable _impl::EventHandler onReleaseEvent {}; + mutable _impl::EventHandler onShortReleaseEvent {}; }; class Controller { diff --git a/include/gamepad/event_handler.hpp b/include/gamepad/event_handler.hpp index 6956acb..a090964 100644 --- a/include/gamepad/event_handler.hpp +++ b/include/gamepad/event_handler.hpp @@ -7,7 +7,7 @@ #include "gamepad/recursive_mutex.hpp" -namespace Gamepad { +namespace Gamepad::_impl { /** * @brief Event handling class with thread safety that supports adding, removing, and running listeners @@ -76,6 +76,6 @@ template class EventHandler { private: std::vector keys {}; std::vector listeners {}; - Gamepad::RecursiveMutex mutex {}; + Gamepad::_impl::RecursiveMutex mutex {}; }; } // namespace Gamepad \ No newline at end of file diff --git a/include/gamepad/recursive_mutex.hpp b/include/gamepad/recursive_mutex.hpp index 42bdb46..2937339 100644 --- a/include/gamepad/recursive_mutex.hpp +++ b/include/gamepad/recursive_mutex.hpp @@ -2,7 +2,7 @@ #include "pros/rtos.h" #include -namespace Gamepad { +namespace Gamepad::_impl { class RecursiveMutex { public: From a829c7dcfb72dce3c3a9f2aa21cad627a57354c2 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Sat, 20 Jul 2024 11:43:34 -0700 Subject: [PATCH 33/60] ci: :construction_worker: Add clang-format workflow --- .github/workflows/clang-format.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .github/workflows/clang-format.yml diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml new file mode 100644 index 0000000..8a3ad87 --- /dev/null +++ b/.github/workflows/clang-format.yml @@ -0,0 +1,21 @@ +name: test-clang-format + +on: + push: + branches: + - '*' + pull_request: + workflow_dispatch: + + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - uses: DoozyX/clang-format-lint-action@v0.17 + with: + source: './src/lemlib ./include/lemlib' + extensions: 'hpp,cpp' + clangFormatVersion: 17 \ No newline at end of file From 646a77d715842035f9fc008ff3c3b8cc5f50c5e9 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Sat, 20 Jul 2024 11:44:34 -0700 Subject: [PATCH 34/60] ci: :green_heart: Fix pr-comment so it works with empty pr bodies --- .github/workflows/pr-comment.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-comment.yml b/.github/workflows/pr-comment.yml index f579cdd..74af922 100644 --- a/.github/workflows/pr-comment.yml +++ b/.github/workflows/pr-comment.yml @@ -26,7 +26,7 @@ jobs: const old_marker = new RegExp(marker.replace("\r\n", "\r?\n")).exec(old_body)?.[0] ?? marker; - body = old_body.split(old_marker)[0] + marker + body; + body = (old_body.split(old_marker)[0] ?? "") + marker + body; await github.request('PATCH /repos/{owner}/{repo}/pulls/{pull_number}', { owner: owner, repo: repo, From 3f0f5ffb7b313abf51e87ae405c917dadee88f48 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Sat, 20 Jul 2024 11:49:55 -0700 Subject: [PATCH 35/60] ci: :green_heart: Fix copy-paste error in clang-format workflow --- .github/workflows/clang-format.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index 8a3ad87..3bba911 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -16,6 +16,6 @@ jobs: - uses: actions/checkout@v2 - uses: DoozyX/clang-format-lint-action@v0.17 with: - source: './src/lemlib ./include/lemlib' + source: './src/gamepad ./include/gamepad' extensions: 'hpp,cpp' clangFormatVersion: 17 \ No newline at end of file From be072f051f1a4764266256f7cbad2361e89cb0bb Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Sat, 20 Jul 2024 11:54:05 -0700 Subject: [PATCH 36/60] ci: :green_heart: Fix pr-comment for real this time --- .github/workflows/pr-comment.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-comment.yml b/.github/workflows/pr-comment.yml index 74af922..f4d610b 100644 --- a/.github/workflows/pr-comment.yml +++ b/.github/workflows/pr-comment.yml @@ -26,7 +26,7 @@ jobs: const old_marker = new RegExp(marker.replace("\r\n", "\r?\n")).exec(old_body)?.[0] ?? marker; - body = (old_body.split(old_marker)[0] ?? "") + marker + body; + body = (old_body ?? "").split(old_marker)[0] + marker + body; await github.request('PATCH /repos/{owner}/{repo}/pulls/{pull_number}', { owner: owner, repo: repo, From d138ee07ed5a685f9c84843e6a6f053ebe372224 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Sat, 27 Jul 2024 16:56:21 -0700 Subject: [PATCH 37/60] style: :art: Fix formatting --- include/gamepad/controller.hpp | 49 +++++++++++----------- include/gamepad/event_handler.hpp | 70 ++++++++++++++++--------------- include/gamepad/todo.hpp | 6 +-- src/gamepad/controller.cpp | 28 ++++--------- src/main.cpp | 48 ++++++++++----------- 5 files changed, 96 insertions(+), 105 deletions(-) diff --git a/include/gamepad/controller.hpp b/include/gamepad/controller.hpp index 2c520e0..d3944a0 100644 --- a/include/gamepad/controller.hpp +++ b/include/gamepad/controller.hpp @@ -19,34 +19,35 @@ enum EventType { }; class Button { - friend class Controller; + friend class Controller; public: - bool rising_edge = false; - bool falling_edge = false; - bool is_pressed = false; - uint32_t last_press_time = pros::millis(); - uint32_t last_release_time = last_press_time; - uint32_t time_held = 0; - uint32_t time_released = 0; - uint32_t long_press_threshold = 500; + bool rising_edge = false; + bool falling_edge = false; + bool is_pressed = false; + uint32_t last_press_time = pros::millis(); + uint32_t last_release_time = last_press_time; + uint32_t time_held = 0; + uint32_t time_released = 0; + uint32_t long_press_threshold = 500; - uint32_t onPress(std::function func); - uint32_t onLongPress(std::function func); - uint32_t onRelease(std::function func); - uint32_t addListener(EventType event, std::function func); - bool removeListener(uint32_t id); + uint32_t onPress(std::function func); + uint32_t onLongPress(std::function func); + uint32_t onRelease(std::function func); + uint32_t addListener(EventType event, std::function func); + bool removeListener(uint32_t id); private: + void update(bool is_held); - void update(bool is_held); - - EventHandler<> onPressEvent; - EventHandler<> onLongPressEvent; - EventHandler<> onReleaseEvent; + EventHandler<> onPressEvent; + EventHandler<> onLongPressEvent; + EventHandler<> onReleaseEvent; }; class Controller { public: - explicit Controller(pros::controller_id_e_t id): controller(id) {} + explicit Controller(pros::controller_id_e_t id) + : controller(id) {} + /** * Updates the state of the gamepad (all joysticks and buttons), and also runs * any registered handlers. @@ -65,13 +66,11 @@ class Controller { */ float operator[](pros::controller_analog_e_t joystick); TODO("hide memebrs and expose getters/const refs") - Button L1{}, L2{}, R1{}, R2{}, - Up{}, Down{}, Left{}, Right{}, - X{}, B{}, Y{}, A{}; + Button L1 {}, L2 {}, R1 {}, R2 {}, Up {}, Down {}, Left {}, Right {}, X {}, B {}, Y {}, A {}; float LeftX = 0, LeftY = 0, RightX = 0, RightY = 0; private: - static Button Controller::* button_to_ptr(pros::controller_digital_e_t button); + static Button Controller::*button_to_ptr(pros::controller_digital_e_t button); void updateButton(pros::controller_digital_e_t button_id); pros::Controller controller; }; // namespace Gamepad -} \ No newline at end of file +} // namespace Gamepad \ No newline at end of file diff --git a/include/gamepad/event_handler.hpp b/include/gamepad/event_handler.hpp index 6bdc188..d4660a0 100644 --- a/include/gamepad/event_handler.hpp +++ b/include/gamepad/event_handler.hpp @@ -12,44 +12,46 @@ namespace Gamepad { class MonotonicCounter { - template friend class EventHandler; - static uint32_t next_value() { - static std::atomic counter = 0; - return ++counter; - } + template friend class EventHandler; + + static uint32_t next_value() { + static std::atomic counter = 0; + return ++counter; + } }; -template -class EventHandler { +template class EventHandler { public: - using Listener = std::function; - uint32_t add_listener(Listener func) { - std::lock_guard lock(mutex); - uint32_t id = MonotonicCounter::next_value(); - listeners.emplace(id, std::move(func)); - return id; - } - bool remove_listener(uint32_t id) { - std::lock_guard lock(mutex); - if(listeners.find(id) == listeners.end()) { - TODO("change handling maybe?") - return false; + using Listener = std::function; + + uint32_t add_listener(Listener func) { + std::lock_guard lock(mutex); + uint32_t id = MonotonicCounter::next_value(); + listeners.emplace(id, std::move(func)); + return id; + } + + bool remove_listener(uint32_t id) { + std::lock_guard lock(mutex); + if (listeners.find(id) == listeners.end()) { + TODO("change handling maybe?") + return false; + } + listeners.erase(id); + return true; + } + + bool is_empty() { + std::lock_guard lock(mutex); + return listeners.empty(); } - listeners.erase(id); - return true; - } - bool is_empty() { - std::lock_guard lock(mutex); - return listeners.empty(); - } - void fire(Args... args) { - std::lock_guard lock(mutex); - for(auto listener : listeners) { - listener.second(args...); + + void fire(Args... args) { + std::lock_guard lock(mutex); + for (auto listener : listeners) { listener.second(args...); } } - } private: - std::map listeners; - pros::Mutex mutex; + std::map listeners; + pros::Mutex mutex; }; -} \ No newline at end of file +} // namespace Gamepad \ No newline at end of file diff --git a/include/gamepad/todo.hpp b/include/gamepad/todo.hpp index 6d61cf6..c1e0b7b 100644 --- a/include/gamepad/todo.hpp +++ b/include/gamepad/todo.hpp @@ -1,5 +1,5 @@ #pragma once -#define DO_PRAGMA(x) _Pragma (#x) -#define TODO(x) DO_PRAGMA(message ("TODO - " #x)) -#define FIXME(x) DO_PRAGMA(warning ("FIXME - " #x)) \ No newline at end of file +#define DO_PRAGMA(x) _Pragma(#x) +#define TODO(x) DO_PRAGMA(message("TODO - " #x)) +#define FIXME(x) DO_PRAGMA(warning("FIXME - " #x)) \ No newline at end of file diff --git a/src/gamepad/controller.cpp b/src/gamepad/controller.cpp index 4472527..9b06ea4 100644 --- a/src/gamepad/controller.cpp +++ b/src/gamepad/controller.cpp @@ -3,9 +3,7 @@ namespace Gamepad { -uint32_t Button::onPress(std::function func) { - return this->onPressEvent.add_listener(std::move(func)); -} +uint32_t Button::onPress(std::function func) { return this->onPressEvent.add_listener(std::move(func)); } uint32_t Button::onLongPress(std::function func) { return this->onLongPressEvent.add_listener(std::move(func)); @@ -26,12 +24,8 @@ void Button::update(const bool is_held) { } else { this->time_released += pros::millis() - last_update_time; } - if (this->rising_edge) { - this->time_held = 0; - } - if (this->falling_edge) { - this->time_released = 0; - } + if (this->rising_edge) { this->time_held = 0; } + if (this->falling_edge) { this->time_released = 0; } if (this->rising_edge) { onPressEvent.fire(); @@ -43,15 +37,13 @@ void Button::update(const bool is_held) { } void Controller::updateButton(pros::controller_digital_e_t button_id) { - Button Controller::* button = Controller::button_to_ptr(button_id); + Button Controller::*button = Controller::button_to_ptr(button_id); bool is_held = this->controller.get_digital(button_id); (this->*button).update(is_held); } void Controller::update() { - for(int i = DIGITAL_L1; i != DIGITAL_A; ++i) { - this->updateButton(static_cast(i)); - } + for (int i = DIGITAL_L1; i != DIGITAL_A; ++i) { this->updateButton(static_cast(i)); } this->LeftX = this->controller.get_analog(ANALOG_LEFT_X); this->LeftY = this->controller.get_analog(ANALOG_LEFT_Y); @@ -68,13 +60,12 @@ float Controller::operator[](pros::controller_analog_e_t axis) { case ANALOG_LEFT_X: return this->LeftX; case ANALOG_LEFT_Y: return this->LeftY; case ANALOG_RIGHT_X: return this->RightX; - case ANALOG_RIGHT_Y: return this->RightY; - TODO("change handling for default") + case ANALOG_RIGHT_Y: return this->RightY; TODO("change handling for default") default: std::exit(1); } } -Button Controller::* Controller::button_to_ptr(pros::controller_digital_e_t button) { +Button Controller::*Controller::button_to_ptr(pros::controller_digital_e_t button) { switch (button) { case DIGITAL_L1: return &Controller::L1; case DIGITAL_L2: return &Controller::L2; @@ -87,9 +78,8 @@ Button Controller::* Controller::button_to_ptr(pros::controller_digital_e_t butt case DIGITAL_X: return &Controller::X; case DIGITAL_B: return &Controller::B; case DIGITAL_Y: return &Controller::Y; - case DIGITAL_A: return &Controller::A; - TODO("change handling for default") + case DIGITAL_A: return &Controller::A; TODO("change handling for default") default: std::exit(1); } } -} \ No newline at end of file +} // namespace Gamepad \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 1cc258a..3085d03 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,13 +7,13 @@ * "I was pressed!" and nothing. */ void on_center_button() { - static bool pressed = false; - pressed = !pressed; - if (pressed) { - pros::lcd::set_text(2, "I was pressed!"); - } else { - pros::lcd::clear_line(2); - } + static bool pressed = false; + pressed = !pressed; + if (pressed) { + pros::lcd::set_text(2, "I was pressed!"); + } else { + pros::lcd::clear_line(2); + } } /** @@ -23,10 +23,10 @@ void on_center_button() { * to keep execution time for this mode under a few seconds. */ void initialize() { - pros::lcd::initialize(); - pros::lcd::set_text(1, "Hello PROS User!"); + pros::lcd::initialize(); + pros::lcd::set_text(1, "Hello PROS User!"); - pros::lcd::register_btn1_cb(on_center_button); + pros::lcd::register_btn1_cb(on_center_button); } /** @@ -74,21 +74,21 @@ void autonomous() {} * task, not resume it from where it left off. */ void opcontrol() { - pros::Controller master(pros::E_CONTROLLER_MASTER); - pros::MotorGroup left_mg({1, -2, 3}); // Creates a motor group with forwards ports 1 & 3 and reversed port 2 - pros::MotorGroup right_mg({-4, 5, -6}); // Creates a motor group with forwards port 4 and reversed ports 4 & 6 + pros::Controller master(pros::E_CONTROLLER_MASTER); + pros::MotorGroup left_mg({1, -2, 3}); // Creates a motor group with forwards ports 1 & 3 and reversed port 2 + pros::MotorGroup right_mg({-4, 5, -6}); // Creates a motor group with forwards port 4 and reversed ports 4 & 6 - while (true) { - pros::lcd::print(0, "%d %d %d", (pros::lcd::read_buttons() & LCD_BTN_LEFT) >> 2, - (pros::lcd::read_buttons() & LCD_BTN_CENTER) >> 1, + while (true) { + pros::lcd::print(0, "%d %d %d", (pros::lcd::read_buttons() & LCD_BTN_LEFT) >> 2, + (pros::lcd::read_buttons() & LCD_BTN_CENTER) >> 1, - (pros::lcd::read_buttons() & LCD_BTN_RIGHT) >> 0); // Prints status of the emulated screen LCDs + (pros::lcd::read_buttons() & LCD_BTN_RIGHT) >> 0); // Prints status of the emulated screen LCDs - // Arcade control scheme - int dir = master.get_analog(ANALOG_LEFT_Y); // Gets amount forward/backward from left joystick - int turn = master.get_analog(ANALOG_RIGHT_X); // Gets the turn left/right from right joystick - left_mg.move(dir - turn); // Sets left motor voltage - right_mg.move(dir + turn); // Sets right motor voltage - pros::delay(20); // Run for 20 ms then update - } + // Arcade control scheme + int dir = master.get_analog(ANALOG_LEFT_Y); // Gets amount forward/backward from left joystick + int turn = master.get_analog(ANALOG_RIGHT_X); // Gets the turn left/right from right joystick + left_mg.move(dir - turn); // Sets left motor voltage + right_mg.move(dir + turn); // Sets right motor voltage + pros::delay(20); // Run for 20 ms then update + } } \ No newline at end of file From 9f1b114adcc87575d7d618b81b1872b71b20e07a Mon Sep 17 00:00:00 2001 From: Andrew Curtis <80860310+meisZWFLZ@users.noreply.github.com> Date: Fri, 9 Aug 2024 14:34:42 -0700 Subject: [PATCH 38/60] ci: :arrow_up: update pros-build to v2.0.2 --- .github/workflows/pros-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pros-build.yml b/.github/workflows/pros-build.yml index 6dbaaac..88566b5 100644 --- a/.github/workflows/pros-build.yml +++ b/.github/workflows/pros-build.yml @@ -13,6 +13,6 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: LemLib/pros-build@e0f3251974c2f5b044b8e5d8665db7cfcb5dfad7 + - uses: LemLib/pros-build@v2.0.2 with: library-path: gamepad From e9226df452d0cac0190c05a34b8e3d68a9f6eb79 Mon Sep 17 00:00:00 2001 From: Aang099 <65919137+Aang099@users.noreply.github.com> Date: Fri, 9 Aug 2024 14:40:02 -0700 Subject: [PATCH 39/60] Bump clang-format version --- .github/workflows/clang-format.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index 3bba911..29121bb 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -14,8 +14,8 @@ jobs: steps: - uses: actions/checkout@v2 - - uses: DoozyX/clang-format-lint-action@v0.17 + - uses: DoozyX/clang-format-lint-action@v0.18 with: source: './src/gamepad ./include/gamepad' extensions: 'hpp,cpp' - clangFormatVersion: 17 \ No newline at end of file + clangFormatVersion: 18 From df0eccdf9c6aca06677ba87c7f06939f65cf032d Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Sat, 10 Aug 2024 17:06:14 -0700 Subject: [PATCH 40/60] style: :art: Format everything --- include/gamepad/event_handler.hpp | 2 +- include/gamepad/recursive_mutex.hpp | 34 ++++++++++++++--------------- src/gamepad/controller.cpp | 3 ++- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/include/gamepad/event_handler.hpp b/include/gamepad/event_handler.hpp index a090964..4585f6c 100644 --- a/include/gamepad/event_handler.hpp +++ b/include/gamepad/event_handler.hpp @@ -78,4 +78,4 @@ template class EventHandler { std::vector listeners {}; Gamepad::_impl::RecursiveMutex mutex {}; }; -} // namespace Gamepad \ No newline at end of file +} // namespace Gamepad::_impl \ No newline at end of file diff --git a/include/gamepad/recursive_mutex.hpp b/include/gamepad/recursive_mutex.hpp index 2937339..f77c32f 100644 --- a/include/gamepad/recursive_mutex.hpp +++ b/include/gamepad/recursive_mutex.hpp @@ -6,24 +6,22 @@ namespace Gamepad::_impl { class RecursiveMutex { public: - RecursiveMutex(): mutex(pros::c::mutex_recursive_create()) {} - bool take(std::uint32_t timeout = TIMEOUT_MAX) { - return pros::c::mutex_recursive_take(mutex, timeout); - } - void lock() { - if (!this->take()) throw std::system_error(); - } - bool try_lock() { - return this->take(0); - } - bool give() { - return pros::c::mutex_recursive_give(mutex); - } - void unlock() { - this->give(); - } + RecursiveMutex() + : mutex(pros::c::mutex_recursive_create()) {} + + bool take(std::uint32_t timeout = TIMEOUT_MAX) { return pros::c::mutex_recursive_take(mutex, timeout); } + + void lock() { + if (!this->take()) throw std::system_error(); + } + + bool try_lock() { return this->take(0); } + + bool give() { return pros::c::mutex_recursive_give(mutex); } + + void unlock() { this->give(); } private: - pros::mutex_t mutex; + pros::mutex_t mutex; }; -} \ No newline at end of file +} // namespace Gamepad::_impl \ No newline at end of file diff --git a/src/gamepad/controller.cpp b/src/gamepad/controller.cpp index e7a0b49..a9606e5 100644 --- a/src/gamepad/controller.cpp +++ b/src/gamepad/controller.cpp @@ -35,7 +35,8 @@ bool Button::addListener(EventType event, std::string listenerName, std::functio } bool Button::removeListener(std::string listenerName) const { - return this->onPressEvent.remove_listener(listenerName + "_user") || this->onLongPressEvent.remove_listener(listenerName + "_user") || + 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"); } From de2e8e907048ec270636fd5e9e313d7b5b375cbf Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Sat, 10 Aug 2024 17:19:57 -0700 Subject: [PATCH 41/60] docs: :bulb: Remove obsolete todo in Button::update --- src/gamepad/controller.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/gamepad/controller.cpp b/src/gamepad/controller.cpp index a9606e5..4b45c94 100644 --- a/src/gamepad/controller.cpp +++ b/src/gamepad/controller.cpp @@ -55,7 +55,6 @@ void Button::update(const bool is_held) { this->onPressEvent.fire(); } else if (this->is_pressed && this->time_held >= this->long_press_threshold && this->last_long_press_time <= pros::millis() - this->time_held) { - TODO("change onLongPress handling if onPress is present") this->onLongPressEvent.fire(); this->last_long_press_time = pros::millis(); } else if (this->falling_edge) { From f34e6d7756b16de3046330a8a711abd20de980d3 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Sat, 10 Aug 2024 17:47:25 -0700 Subject: [PATCH 42/60] fix: :adhesive_bandage: Never throw in RecursiveMutex::lock --- include/gamepad/recursive_mutex.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/gamepad/recursive_mutex.hpp b/include/gamepad/recursive_mutex.hpp index f77c32f..de91ac1 100644 --- a/include/gamepad/recursive_mutex.hpp +++ b/include/gamepad/recursive_mutex.hpp @@ -12,7 +12,7 @@ class RecursiveMutex { bool take(std::uint32_t timeout = TIMEOUT_MAX) { return pros::c::mutex_recursive_take(mutex, timeout); } void lock() { - if (!this->take()) throw std::system_error(); + while (!this->take()) pros::delay(2); } bool try_lock() { return this->take(0); } From 402a0902d61fc883336be658d83bb0af32065a6b Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Mon, 12 Aug 2024 09:35:23 -0700 Subject: [PATCH 43/60] docs: :memo: Remove @brief from member vars in Button class --- include/gamepad/controller.hpp | 32 +++++++------------------------- 1 file changed, 7 insertions(+), 25 deletions(-) diff --git a/include/gamepad/controller.hpp b/include/gamepad/controller.hpp index cf319f0..a2245ee 100644 --- a/include/gamepad/controller.hpp +++ b/include/gamepad/controller.hpp @@ -23,35 +23,17 @@ enum EventType { class Button { friend class Controller; public: - /** - * @brief Whether the button has just been pressed - * - */ + /* Whether the button has just been pressed */ bool rising_edge = false; - /** - * @brief Whether the button has just been released - * - */ + /* Whether the button has just been released */ bool falling_edge = false; - /** - * @brief Whether the button is currently held down - * - */ + /* Whether the button is currently held down */ bool is_pressed = false; - /** - * @brief How long the button has been held down - * - */ + /* How long the button has been held down */ uint32_t time_held = 0; - /** - * @brief How long the button has been released - * - */ + /* How long the button has been released */ uint32_t time_released = 0; - /** - * @brief How long the threshold should be for the longPress and shortRelease events - * - */ + /* How long the threshold should be for the longPress and shortRelease events */ uint32_t long_press_threshold = 500; /** * @brief Register a function to run when the button is pressed. @@ -194,4 +176,4 @@ class Controller { void updateButton(pros::controller_digital_e_t button_id); pros::Controller controller; }; // namespace Gamepad -} // namespace Gamepad \ No newline at end of file +} // namespace Gamepad From 8f260677f43f9e76bb2585381e81c468e8540585 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Tue, 13 Aug 2024 17:30:14 +0000 Subject: [PATCH 44/60] style: :art: Fix formatting --- include/gamepad/event_handler.hpp | 70 ++++++++++++++++--------------- include/gamepad/todo.hpp | 6 +-- 2 files changed, 39 insertions(+), 37 deletions(-) diff --git a/include/gamepad/event_handler.hpp b/include/gamepad/event_handler.hpp index 6bdc188..d4660a0 100644 --- a/include/gamepad/event_handler.hpp +++ b/include/gamepad/event_handler.hpp @@ -12,44 +12,46 @@ namespace Gamepad { class MonotonicCounter { - template friend class EventHandler; - static uint32_t next_value() { - static std::atomic counter = 0; - return ++counter; - } + template friend class EventHandler; + + static uint32_t next_value() { + static std::atomic counter = 0; + return ++counter; + } }; -template -class EventHandler { +template class EventHandler { public: - using Listener = std::function; - uint32_t add_listener(Listener func) { - std::lock_guard lock(mutex); - uint32_t id = MonotonicCounter::next_value(); - listeners.emplace(id, std::move(func)); - return id; - } - bool remove_listener(uint32_t id) { - std::lock_guard lock(mutex); - if(listeners.find(id) == listeners.end()) { - TODO("change handling maybe?") - return false; + using Listener = std::function; + + uint32_t add_listener(Listener func) { + std::lock_guard lock(mutex); + uint32_t id = MonotonicCounter::next_value(); + listeners.emplace(id, std::move(func)); + return id; + } + + bool remove_listener(uint32_t id) { + std::lock_guard lock(mutex); + if (listeners.find(id) == listeners.end()) { + TODO("change handling maybe?") + return false; + } + listeners.erase(id); + return true; + } + + bool is_empty() { + std::lock_guard lock(mutex); + return listeners.empty(); } - listeners.erase(id); - return true; - } - bool is_empty() { - std::lock_guard lock(mutex); - return listeners.empty(); - } - void fire(Args... args) { - std::lock_guard lock(mutex); - for(auto listener : listeners) { - listener.second(args...); + + void fire(Args... args) { + std::lock_guard lock(mutex); + for (auto listener : listeners) { listener.second(args...); } } - } private: - std::map listeners; - pros::Mutex mutex; + std::map listeners; + pros::Mutex mutex; }; -} \ No newline at end of file +} // namespace Gamepad \ No newline at end of file diff --git a/include/gamepad/todo.hpp b/include/gamepad/todo.hpp index 6d61cf6..c1e0b7b 100644 --- a/include/gamepad/todo.hpp +++ b/include/gamepad/todo.hpp @@ -1,5 +1,5 @@ #pragma once -#define DO_PRAGMA(x) _Pragma (#x) -#define TODO(x) DO_PRAGMA(message ("TODO - " #x)) -#define FIXME(x) DO_PRAGMA(warning ("FIXME - " #x)) \ No newline at end of file +#define DO_PRAGMA(x) _Pragma(#x) +#define TODO(x) DO_PRAGMA(message("TODO - " #x)) +#define FIXME(x) DO_PRAGMA(warning("FIXME - " #x)) \ No newline at end of file From fbf8e84c13d2a192247b6d555617944615cf9b16 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Mon, 19 Aug 2024 19:15:37 +0000 Subject: [PATCH 45/60] fix: :adhesive_bandage: Fix memory leak in RecursiveMutex class --- include/gamepad/recursive_mutex.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/gamepad/recursive_mutex.hpp b/include/gamepad/recursive_mutex.hpp index de91ac1..8cd9c20 100644 --- a/include/gamepad/recursive_mutex.hpp +++ b/include/gamepad/recursive_mutex.hpp @@ -20,6 +20,8 @@ class RecursiveMutex { bool give() { return pros::c::mutex_recursive_give(mutex); } void unlock() { this->give(); } + + ~RecursiveMutex() { pros::c::mutex_delete(mutex); } private: pros::mutex_t mutex; }; From 4eb21f3ee5b3309ac99646cb2f1d78ee0db3de03 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Mon, 19 Aug 2024 19:16:46 +0000 Subject: [PATCH 46/60] refactor: :fire: Remove unnecessary include in recursive_mutex.hpp --- include/gamepad/recursive_mutex.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/include/gamepad/recursive_mutex.hpp b/include/gamepad/recursive_mutex.hpp index 8cd9c20..951d9d7 100644 --- a/include/gamepad/recursive_mutex.hpp +++ b/include/gamepad/recursive_mutex.hpp @@ -1,6 +1,5 @@ #include "pros/apix.h" #include "pros/rtos.h" -#include namespace Gamepad::_impl { From 020af19fdee5829f2d478b4da5b6655a26dffd0d Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Mon, 19 Aug 2024 19:24:09 +0000 Subject: [PATCH 47/60] docs: :memo: Document RecursiveMutex class --- include/gamepad/recursive_mutex.hpp | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/include/gamepad/recursive_mutex.hpp b/include/gamepad/recursive_mutex.hpp index 951d9d7..d892f2c 100644 --- a/include/gamepad/recursive_mutex.hpp +++ b/include/gamepad/recursive_mutex.hpp @@ -5,21 +5,55 @@ namespace Gamepad::_impl { class RecursiveMutex { public: + /** + * @brief Construct a new recursive mutex + * + */ RecursiveMutex() : mutex(pros::c::mutex_recursive_create()) {} + /** + * @brief Locks the recursive mutex, optionally bailing out after a timeout + * + * @param timeout How long to wait for the mutex before baling out + * @return true The mutex was successfully acquired + * @return false The mutex was not successfully acquired + */ bool take(std::uint32_t timeout = TIMEOUT_MAX) { return pros::c::mutex_recursive_take(mutex, timeout); } + /** + * @brief Locks the mutex, waiting indefinetely until the mutex is acquired + * + */ void lock() { while (!this->take()) pros::delay(2); } + /** + * @brief Attempts to lock the mutex without blocking the current thread + * + * @return true The mutex was successfully acquired + * @return false The mutex was not successfully acquired + */ bool try_lock() { return this->take(0); } + /** + * @brief Unlocks the mutex + * + * @return true The mutex was successfully released + * @return false The mutex was not successfully released + */ bool give() { return pros::c::mutex_recursive_give(mutex); } + /** + * @brief Unlocks the mutex, equivalent to \ref give() + * + */ void unlock() { this->give(); } + /** + * @brief Destroy the recursive mutex and free any allocated memory + */ ~RecursiveMutex() { pros::c::mutex_delete(mutex); } private: pros::mutex_t mutex; From 1b5c5f89991717d1710f53840bab3be1362b6682 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Mon, 19 Aug 2024 20:14:58 +0000 Subject: [PATCH 48/60] refactor: :recycle: Use inline variable instead of nifty counter --- include/gamepad/controller.hpp | 21 ++++----- src/gamepad/controller.cpp | 78 +++++++++------------------------- 2 files changed, 32 insertions(+), 67 deletions(-) diff --git a/include/gamepad/controller.hpp b/include/gamepad/controller.hpp index acc7a9e..12667ae 100644 --- a/include/gamepad/controller.hpp +++ b/include/gamepad/controller.hpp @@ -1,5 +1,6 @@ #pragma once +#include "pros/misc.h" #include #include #ifndef PROS_USE_SIMPLE_NAMES @@ -43,15 +44,7 @@ class Button { EventHandler<> onReleaseEvent; }; -namespace _impl { -static struct ControllerInit { - ControllerInit(); - ~ControllerInit(); -} _controllerInit; -} // namespace _impl - class Controller { - friend struct _impl::ControllerInit; public: /** * Updates the state of the gamepad (all joysticks and buttons), and also runs @@ -73,6 +66,10 @@ class Controller { TODO("hide memebrs and expose getters/const refs") Button L1 {}, L2 {}, R1 {}, R2 {}, Up {}, Down {}, Left {}, Right {}, X {}, B {}, Y {}, A {}; float LeftX = 0, LeftY = 0, RightX = 0, RightY = 0; + /// The master controller, same as @ref Gamepad::master + static Controller master; + /// The partner controller, same as @ref Gamepad::partner + static Controller partner; private: explicit Controller(pros::controller_id_e_t id) : controller(id) {} @@ -82,7 +79,11 @@ class Controller { pros::Controller controller; }; -extern Controller& master; -extern Controller& partner; +inline Controller Controller::master {pros::E_CONTROLLER_MASTER}; +inline Controller Controller::partner {pros::E_CONTROLLER_PARTNER}; +/// The master controller +inline Controller& master = Controller::master; +/// The partner controller +inline Controller& partner = Controller::partner; } // namespace Gamepad \ No newline at end of file diff --git a/src/gamepad/controller.cpp b/src/gamepad/controller.cpp index 5754b54..c1a6da2 100644 --- a/src/gamepad/controller.cpp +++ b/src/gamepad/controller.cpp @@ -2,43 +2,7 @@ #include "gamepad/todo.hpp" #include "pros/misc.h" -#include - namespace Gamepad { - -union ControllerBuf { - // this is here to allow us to control when we initialize the Controller - char c; - Controller as_controller; - - // empty destructor, the Controller must be manually destroyed by ControllerInit - ~ControllerBuf() {} -}; - -static uint32_t nifty_counter; // zero initialized at load time -ControllerBuf master_buf {}; -Controller& master = master_buf.as_controller; -ControllerBuf partner_buf {}; -Controller& partner = partner_buf.as_controller; - -_impl::ControllerInit::ControllerInit() { - // only initialize once, if we're the first ControllerInit instance - if (nifty_counter == 0) { - new (&master_buf.as_controller) Controller(pros::E_CONTROLLER_MASTER); - new (&partner_buf.as_controller) Controller(pros::E_CONTROLLER_PARTNER); - } - ++nifty_counter; -} - -_impl::ControllerInit::~ControllerInit() { - --nifty_counter; - // only destroy if we're the last ControllerInit instance - if (nifty_counter == 0) { - master.~Controller(); - partner.~Controller(); - } -} - uint32_t Button::onPress(std::function func) { return this->onPressEvent.add_listener(std::move(func)); } uint32_t Button::onLongPress(std::function func) { @@ -79,12 +43,12 @@ void Controller::updateButton(pros::controller_digital_e_t button_id) { } void Controller::update() { - for (int i = DIGITAL_L1; i != DIGITAL_A; ++i) { this->updateButton(static_cast(i)); } + for (int i = pros::E_CONTROLLER_DIGITAL_L1; i != pros::E_CONTROLLER_DIGITAL_A; ++i) { this->updateButton(static_cast(i)); } - this->LeftX = this->controller.get_analog(ANALOG_LEFT_X); - this->LeftY = this->controller.get_analog(ANALOG_LEFT_Y); - this->RightX = this->controller.get_analog(ANALOG_RIGHT_X); - this->RightY = this->controller.get_analog(ANALOG_RIGHT_Y); + this->LeftX = this->controller.get_analog(pros::E_CONTROLLER_ANALOG_LEFT_X); + this->LeftY = this->controller.get_analog(pros::E_CONTROLLER_ANALOG_LEFT_Y); + this->RightX = this->controller.get_analog(pros::E_CONTROLLER_ANALOG_RIGHT_X); + this->RightY = this->controller.get_analog(pros::E_CONTROLLER_ANALOG_RIGHT_Y); } const Button& Controller::operator[](pros::controller_digital_e_t button) { @@ -93,28 +57,28 @@ const Button& Controller::operator[](pros::controller_digital_e_t button) { float Controller::operator[](pros::controller_analog_e_t axis) { switch (axis) { - case ANALOG_LEFT_X: return this->LeftX; - case ANALOG_LEFT_Y: return this->LeftY; - case ANALOG_RIGHT_X: return this->RightX; - case ANALOG_RIGHT_Y: return this->RightY; TODO("change handling for default") + case pros::E_CONTROLLER_ANALOG_LEFT_X: return this->LeftX; + case pros::E_CONTROLLER_ANALOG_LEFT_Y: return this->LeftY; + case pros::E_CONTROLLER_ANALOG_RIGHT_X: return this->RightX; + case pros::E_CONTROLLER_ANALOG_RIGHT_Y: return this->RightY; TODO("change handling for default") default: std::exit(1); } } Button Controller::*Controller::button_to_ptr(pros::controller_digital_e_t button) { switch (button) { - case DIGITAL_L1: return &Controller::L1; - case DIGITAL_L2: return &Controller::L2; - case DIGITAL_R1: return &Controller::R1; - case DIGITAL_R2: return &Controller::R2; - case DIGITAL_UP: return &Controller::Up; - case DIGITAL_DOWN: return &Controller::Down; - case DIGITAL_LEFT: return &Controller::Left; - case DIGITAL_RIGHT: return &Controller::Right; - case DIGITAL_X: return &Controller::X; - case DIGITAL_B: return &Controller::B; - case DIGITAL_Y: return &Controller::Y; - case DIGITAL_A: return &Controller::A; TODO("change handling for default") + case pros::E_CONTROLLER_DIGITAL_L1: return &Controller::L1; + case pros::E_CONTROLLER_DIGITAL_L2: return &Controller::L2; + case pros::E_CONTROLLER_DIGITAL_R1: return &Controller::R1; + case pros::E_CONTROLLER_DIGITAL_R2: return &Controller::R2; + case pros::E_CONTROLLER_DIGITAL_UP: return &Controller::Up; + case pros::E_CONTROLLER_DIGITAL_DOWN: return &Controller::Down; + case pros::E_CONTROLLER_DIGITAL_LEFT: return &Controller::Left; + case pros::E_CONTROLLER_DIGITAL_RIGHT: return &Controller::Right; + case pros::E_CONTROLLER_DIGITAL_X: return &Controller::X; + case pros::E_CONTROLLER_DIGITAL_B: return &Controller::B; + case pros::E_CONTROLLER_DIGITAL_Y: return &Controller::Y; + case pros::E_CONTROLLER_DIGITAL_A: return &Controller::A; TODO("change handling for default") default: std::exit(1); } } From 641917bb23b146d92c1705ff979277f021094ecf Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Mon, 19 Aug 2024 21:05:33 +0000 Subject: [PATCH 49/60] style: :art: Format controller.cpp --- src/gamepad/controller.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gamepad/controller.cpp b/src/gamepad/controller.cpp index c1a6da2..9a601d9 100644 --- a/src/gamepad/controller.cpp +++ b/src/gamepad/controller.cpp @@ -43,7 +43,9 @@ void Controller::updateButton(pros::controller_digital_e_t button_id) { } void Controller::update() { - for (int i = pros::E_CONTROLLER_DIGITAL_L1; i != pros::E_CONTROLLER_DIGITAL_A; ++i) { this->updateButton(static_cast(i)); } + for (int i = pros::E_CONTROLLER_DIGITAL_L1; i != pros::E_CONTROLLER_DIGITAL_A; ++i) { + this->updateButton(static_cast(i)); + } this->LeftX = this->controller.get_analog(pros::E_CONTROLLER_ANALOG_LEFT_X); this->LeftY = this->controller.get_analog(pros::E_CONTROLLER_ANALOG_LEFT_Y); From 8a70ae0f60c318cb05ba566308f07964f89d3f6b Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Wed, 21 Aug 2024 16:53:33 +0000 Subject: [PATCH 50/60] style: :art: Fix formatting in main.cpp --- src/main.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index ab94d8b..30d56e9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -75,17 +75,16 @@ void autonomous() {} * task, not resume it from where it left off. */ void opcontrol() { - - pros::MotorGroup left_mg({1, -2, 3}); // Creates a motor group with forwards ports 1 & 3 and reversed port 2 - pros::MotorGroup right_mg({-4, 5, -6}); // Creates a motor group with forwards port 4 and reversed ports 4 & 6 + pros::MotorGroup left_mg({1, -2, 3}); // Creates a motor group with forwards ports 1 & 3 and reversed port 2 + pros::MotorGroup right_mg({-4, 5, -6}); // Creates a motor group with forwards port 4 and reversed ports 4 & 6 - while (true) { - Gamepad::master.update(); - // Arcade control scheme - int dir = Gamepad::master.LeftY; // Gets amount forward/backward from left joystick - int turn = Gamepad::master.RightX; // Gets the turn left/right from right joystick - left_mg.move(dir - turn); // Sets left motor voltage - right_mg.move(dir + turn); // Sets right motor voltage - pros::delay(20); // Run for 20 ms then update - } + while (true) { + Gamepad::master.update(); + // Arcade control scheme + int dir = Gamepad::master.LeftY; // Gets amount forward/backward from left joystick + int turn = Gamepad::master.RightX; // Gets the turn left/right from right joystick + left_mg.move(dir - turn); // Sets left motor voltage + right_mg.move(dir + turn); // Sets right motor voltage + pros::delay(25); // Run for 25 ms then update + } } \ No newline at end of file From 40468c4f6d88f9f124b3bb827d899c1967ea715c Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Wed, 21 Aug 2024 20:56:19 +0000 Subject: [PATCH 51/60] fix: :bug: Fix compiler errors from merging --- include/gamepad/controller.hpp | 1 + src/gamepad/controller.cpp | 33 +++++++++++++++++---------------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/include/gamepad/controller.hpp b/include/gamepad/controller.hpp index 16d20f7..a6dc191 100644 --- a/include/gamepad/controller.hpp +++ b/include/gamepad/controller.hpp @@ -162,6 +162,7 @@ class Controller { /// The partner controller, same as @ref Gamepad::partner static Controller partner; private: + Controller(pros::controller_id_e_t id): controller(id) {} Button m_L1 {}, m_L2 {}, m_R1 {}, m_R2 {}, m_Up {}, m_Down {}, m_Left {}, m_Right {}, m_X {}, m_B {}, m_Y {}, m_A {}; float m_LeftX = 0, m_LeftY = 0, m_RightX = 0, m_RightY = 0; diff --git a/src/gamepad/controller.cpp b/src/gamepad/controller.cpp index b353057..f54fc63 100644 --- a/src/gamepad/controller.cpp +++ b/src/gamepad/controller.cpp @@ -1,5 +1,6 @@ #include "gamepad/controller.hpp" #include "gamepad/todo.hpp" +#include "pros/misc.h" #include namespace Gamepad { @@ -76,10 +77,10 @@ void Controller::update() { this->updateButton(static_cast(i)); } - this->m_LeftX = this->controller.get_analog(ANALOG_LEFT_X); - this->m_LeftY = this->controller.get_analog(ANALOG_LEFT_Y); - this->m_RightX = this->controller.get_analog(ANALOG_RIGHT_X); - this->m_RightY = this->controller.get_analog(ANALOG_RIGHT_Y); + this->m_LeftX = this->controller.get_analog(pros::E_CONTROLLER_ANALOG_LEFT_X); + this->m_LeftY = this->controller.get_analog(pros::E_CONTROLLER_ANALOG_LEFT_Y); + this->m_RightX = this->controller.get_analog(pros::E_CONTROLLER_ANALOG_RIGHT_X); + this->m_RightY = this->controller.get_analog(pros::E_CONTROLLER_ANALOG_RIGHT_Y); } const Button& Controller::operator[](pros::controller_digital_e_t button) { @@ -106,18 +107,18 @@ std::string Controller::unique_name() { Button Controller::*Controller::button_to_ptr(pros::controller_digital_e_t button) { switch (button) { - case pros::E_CONTROLLER_DIGITAL_L1: return &Controller::L1; - case pros::E_CONTROLLER_DIGITAL_L2: return &Controller::L2; - case pros::E_CONTROLLER_DIGITAL_R1: return &Controller::R1; - case pros::E_CONTROLLER_DIGITAL_R2: return &Controller::R2; - case pros::E_CONTROLLER_DIGITAL_UP: return &Controller::Up; - case pros::E_CONTROLLER_DIGITAL_DOWN: return &Controller::Down; - case pros::E_CONTROLLER_DIGITAL_LEFT: return &Controller::Left; - case pros::E_CONTROLLER_DIGITAL_RIGHT: return &Controller::Right; - case pros::E_CONTROLLER_DIGITAL_X: return &Controller::X; - case pros::E_CONTROLLER_DIGITAL_B: return &Controller::B; - case pros::E_CONTROLLER_DIGITAL_Y: return &Controller::Y; - case pros::E_CONTROLLER_DIGITAL_A: return &Controller::A; + case pros::E_CONTROLLER_DIGITAL_L1: return &Controller::m_L1; + case pros::E_CONTROLLER_DIGITAL_L2: return &Controller::m_L2; + case pros::E_CONTROLLER_DIGITAL_R1: return &Controller::m_R1; + case pros::E_CONTROLLER_DIGITAL_R2: return &Controller::m_R2; + case pros::E_CONTROLLER_DIGITAL_UP: return &Controller::m_Up; + case pros::E_CONTROLLER_DIGITAL_DOWN: return &Controller::m_Down; + case pros::E_CONTROLLER_DIGITAL_LEFT: return &Controller::m_Left; + case pros::E_CONTROLLER_DIGITAL_RIGHT: return &Controller::m_Right; + case pros::E_CONTROLLER_DIGITAL_X: return &Controller::m_X; + case pros::E_CONTROLLER_DIGITAL_B: return &Controller::m_B; + case pros::E_CONTROLLER_DIGITAL_Y: return &Controller::m_Y; + case pros::E_CONTROLLER_DIGITAL_A: return &Controller::m_A; default: TODO("add error logging") errno = EINVAL; From 0597d8412991301513006ab965bb3079cfc7d72a Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Wed, 21 Aug 2024 20:58:24 +0000 Subject: [PATCH 52/60] refactor: :recycle: Rearrange main.cpp, improve docs in main.cpp --- src/main.cpp | 60 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 19 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 11754d7..f4fe531 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,8 +1,5 @@ #include "main.h" #include "gamepad/api.hpp" -#include "pros/screen.hpp" - -Gamepad::Controller master(CONTROLLER_MASTER); /** * Runs initialization code. This occurs as soon as the program is started. @@ -10,7 +7,36 @@ Gamepad::Controller master(CONTROLLER_MASTER); * All other competition modes are blocked by initialize; it is recommended * to keep execution time for this mode under a few seconds. */ -void initialize() {} + +void downPress1() { + printf("Down Press!\n"); +} + +void upRelease1() { + printf("Up Release!\n"); +} + +void leftLongPress1() { + printf("Left Long Press!\n"); +} + +void leftShortRelease1() { + printf("Left Short Release!\n"); +} + +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, + // just remember to give them different names + Gamepad::master.Left.onShortRelease("leftShortRelease", leftShortRelease1); + // And we can use lambda's too + Gamepad::master.X.onShortRelease("xShortRelease1", []() { printf("X Short Release!\n"); }); +} /** * Runs while the robot is in the disabled state of Field Management System or @@ -57,21 +83,17 @@ void autonomous() {} * task, not resume it from where it left off. */ void opcontrol() { - auto i = master.Down.onPress("downPress1", []() { printf("Down Press!\n"); }); - if (!i) std::cout << "opcontrol ran again, event did not register!" << std::endl; - master.Down.onLongPress("downLongPress1", []() { printf("Down longPress!\n"); }); - master.Down.onRelease("downRelease1", []() { printf("Down Release!\n"); }); - master.Up.onPress("uppress1", []() { printf("Up Press!\n"); }); - master.Up.onLongPress("upLongPress1", []() { printf("Up longPress!\n"); }); - master.Up.onRelease("upRelease1", []() { printf("Up Release!\n"); }); - master.Up.onShortRelease("upShortRelease1", []() { printf("Up Short Release!\n"); }); - master.Up.onRelease("upRelease2", [=]() { - master.Up.removeListener("upRelease1"); - printf("Up Release 2!\n"); - }); + pros::MotorGroup left_mg({1, -2, 3}); // Creates a motor group with forwards ports 1 & 3 and reversed port 2 + pros::MotorGroup right_mg({-4, 5, -6}); // Creates a motor group with forwards port 4 and reversed ports 4 & 6 + while (true) { - master.update(); - pros::screen::print(TEXT_MEDIUM, 3, "%f %f %f %f", master.LeftX, master.LeftY, master.RightX, master.RightY); - pros::delay(20); + // Remember to ALWAYS call update at the start of your while loop! + Gamepad::master.update(); + // We'll use the arcade control scheme + int dir = Gamepad::master.LeftY; // Gets amount forward/backward from left joystick + int turn = Gamepad::master.RightX; // Gets the turn left/right from right joystick + left_mg.move(dir - turn); // Sets left motor voltage + right_mg.move(dir + turn); // Sets right motor voltage + pros::delay(25); // Wait for 25 ms, then update the motor values again } } \ No newline at end of file From b2bfc2526423dfc0439dba6f37ccae2baaf6e44a Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Wed, 21 Aug 2024 21:09:37 +0000 Subject: [PATCH 53/60] style: :art: Reformat files --- include/gamepad/controller.hpp | 4 +++- src/main.cpp | 16 ++++------------ 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/include/gamepad/controller.hpp b/include/gamepad/controller.hpp index a6dc191..0c1d1ae 100644 --- a/include/gamepad/controller.hpp +++ b/include/gamepad/controller.hpp @@ -162,7 +162,9 @@ class Controller { /// The partner controller, same as @ref Gamepad::partner static Controller partner; private: - Controller(pros::controller_id_e_t id): controller(id) {} + Controller(pros::controller_id_e_t id) + : controller(id) {} + Button m_L1 {}, m_L2 {}, m_R1 {}, m_R2 {}, m_Up {}, m_Down {}, m_Left {}, m_Right {}, m_X {}, m_B {}, m_Y {}, m_A {}; float m_LeftX = 0, m_LeftY = 0, m_RightX = 0, m_RightY = 0; diff --git a/src/main.cpp b/src/main.cpp index f4fe531..2949002 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,21 +8,13 @@ * to keep execution time for this mode under a few seconds. */ -void downPress1() { - printf("Down Press!\n"); -} +void downPress1() { printf("Down Press!\n"); } -void upRelease1() { - printf("Up Release!\n"); -} +void upRelease1() { printf("Up Release!\n"); } -void leftLongPress1() { - printf("Left Long Press!\n"); -} +void leftLongPress1() { printf("Left Long Press!\n"); } -void leftShortRelease1() { - printf("Left Short Release!\n"); -} +void leftShortRelease1() { printf("Left Short Release!\n"); } void initialize() { // We can register functions to run when buttons are pressed From da27ae1b0b7862d28ee634f73a0e9d73e34b8c3e Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Wed, 21 Aug 2024 22:08:26 +0000 Subject: [PATCH 54/60] docs: :memo: Add example code to Button class methods --- include/gamepad/controller.hpp | 62 ++++++++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 10 deletions(-) diff --git a/include/gamepad/controller.hpp b/include/gamepad/controller.hpp index 0c1d1ae..0734f5c 100644 --- a/include/gamepad/controller.hpp +++ b/include/gamepad/controller.hpp @@ -24,17 +24,17 @@ enum EventType { class Button { friend class Controller; public: - /* Whether the button has just been pressed */ + /// Whether the button has just been pressed bool rising_edge = false; - /* Whether the button has just been released */ + /// Whether the button has just been released bool falling_edge = false; - /* Whether the button is currently held down */ + /// Whether the button is currently held down bool is_pressed = false; - /* How long the button has been held down */ + /// How long the button has been held down uint32_t time_held = 0; - /* How long the button has been released */ + /// How long the button has been released uint32_t time_released = 0; - /* How long the threshold should be for the longPress and shortRelease events */ + /// How long the threshold should be for the longPress and shortRelease events uint32_t long_press_threshold = 500; /** * @brief Register a function to run when the button is pressed. @@ -43,16 +43,32 @@ class Button { * @param func The function to run when the button is pressed, 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) + * Example: + * @code {.cpp} + * // Use a function... + * Gamepad::master.Down.onPress("downPress1", downPress1); + * // ...or a lambda + * Gamepad::master.Up.onPress("upPress1", []() { std::cout << "I was pressed!" << std::endl; }); + * @endcode + * */ bool onPress(std::string listenerName, std::function func) const; /** - * @brief Register a function to run when the button is long pressed (The button has been held down for 500ms or - * more, this threshold can be adjusted by changing long_press_threshold). + * @brief Register a function to run when the button is long pressed. WARNING: When using this event along + * with onPress, both the onPress and onlongPress listeners may fire together. (The button has been held + * down for 500ms or more, this threshold can be adjusted by changing long_press_threshold). * * @param listenerName The name of the listener, this must be a unique name * @param func The function to run when the button is long pressed, 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) + * Example: + * @code {.cpp} + * // Use a function... + * Gamepad::master.Left.onLongPress("fireCatapult", fireCatapult); + * // ...or a lambda + * Gamepad::master.Right.onLongPress("print_right", []() { std::cout << "Right button was long pressed!" << std::endl; }); + * @endcode */ bool onLongPress(std::string listenerName, std::function func) const; /** @@ -62,16 +78,30 @@ class Button { * @param func The function to run when the button is 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) + * Example: + * @code {.cpp} + * // Use a function... + * Gamepad::master.X.onRelease("stopFlywheel", stopFlywheel); + * // ...or a lambda + * Gamepad::master.Y.onRelease("stopIntake", []() { intake.move(0); }); + * @endcode */ bool onRelease(std::string listenerName, std::function func) const; /** - * @brief Register a function to run when the button is short released (The button has been released before - * 500ms, this threshold can be adjusted by changing long_press_threshold). + * @brief Register a function to run when the button is short released. This event will most likely be + * used along with the longPress event. (The default threshold for shortRelease to fire is 500ms or less, + * this threshold can be adjusted by changing long_press_threshold). * * @param listenerName The name of the listener, this must be a unique name * @param func The function to run when the button is short 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) + * @code {.cpp} + * // Use a function... + * Gamepad::master.A.onShortRelease("raiseLiftOneLevel", raiseLiftOneLevel); + * // ...or a lambda + * Gamepad::master.B.onShortRelease("intakeOnePicce", []() { intake.move_relative(600, 100); }); + * @endcode */ bool onShortRelease(std::string listenerName, std::function func) const; /** @@ -82,6 +112,12 @@ class Button { * @param func The function to run for the given event, 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) + * @code {.cpp} + * // Use a function... + * Gamepad::master.L1.addListener(Gamepad::ON_PRESS, "start_spin", startSpin); + * // ...or a lambda + * Gamepad::master.L1.addListener(Gamepad::ON_RELEASE, "stop_spin", []() { motor1.brake(); }); + * @endcode */ bool addListener(EventType event, std::string listenerName, std::function func) const; /** @@ -90,6 +126,12 @@ class Button { * @param listenerName The name of the listener to remove * @return true The listener was successfully removed * @return false The listener was not removed + * @code {.cpp} + * // Add an event listener... + * Gamepad::master.L1.addListener(Gamepad::ON_PRESS, "do_something", doSomething); + * // ...and now get rid of it + * Gamepad::master.L1.removeListener("do_something"); + * @endcode */ bool removeListener(std::string listenerName) const; From 2831ee26ba90c3c212222b62ddf9e46ab105e576 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Wed, 21 Aug 2024 22:09:09 +0000 Subject: [PATCH 55/60] style: :art: Fix formatting --- include/gamepad/controller.hpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/include/gamepad/controller.hpp b/include/gamepad/controller.hpp index 0734f5c..f94ee51 100644 --- a/include/gamepad/controller.hpp +++ b/include/gamepad/controller.hpp @@ -34,7 +34,7 @@ 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 + /// How long the threshold should be for the longPress and shortRelease events uint32_t long_press_threshold = 500; /** * @brief Register a function to run when the button is pressed. @@ -50,12 +50,12 @@ class Button { * // ...or a lambda * Gamepad::master.Up.onPress("upPress1", []() { std::cout << "I was pressed!" << std::endl; }); * @endcode - * + * */ bool onPress(std::string listenerName, std::function func) const; /** * @brief Register a function to run when the button is long pressed. WARNING: When using this event along - * with onPress, both the onPress and onlongPress listeners may fire together. (The button has been held + * with onPress, both the onPress and onlongPress listeners may fire together. (The button has been held * down for 500ms or more, this threshold can be adjusted by changing long_press_threshold). * * @param listenerName The name of the listener, this must be a unique name @@ -67,7 +67,8 @@ class Button { * // Use a function... * Gamepad::master.Left.onLongPress("fireCatapult", fireCatapult); * // ...or a lambda - * Gamepad::master.Right.onLongPress("print_right", []() { std::cout << "Right button was long pressed!" << std::endl; }); + * Gamepad::master.Right.onLongPress("print_right", []() { std::cout << "Right button was long pressed!" << + * std::endl; }); * @endcode */ bool onLongPress(std::string listenerName, std::function func) const; From 7f210fc50dce328825c0a435f42f877fb36aa75a Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Thu, 22 Aug 2024 18:19:19 +0000 Subject: [PATCH 56/60] docs: :memo: Improve docs formatting/grammar --- include/gamepad/controller.hpp | 75 ++++++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 22 deletions(-) diff --git a/include/gamepad/controller.hpp b/include/gamepad/controller.hpp index f94ee51..44e33fb 100644 --- a/include/gamepad/controller.hpp +++ b/include/gamepad/controller.hpp @@ -43,26 +43,29 @@ class Button { * @param func The function to run when the button is pressed, 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) - * Example: + * + * @b Example: * @code {.cpp} * // Use a function... * Gamepad::master.Down.onPress("downPress1", downPress1); * // ...or a lambda * Gamepad::master.Up.onPress("upPress1", []() { std::cout << "I was pressed!" << std::endl; }); * @endcode - * */ bool onPress(std::string listenerName, std::function func) const; /** - * @brief Register a function to run when the button is long pressed. WARNING: When using this event along - * with onPress, both the onPress and onlongPress listeners may fire together. (The button has been held - * down for 500ms or more, this threshold can be adjusted by changing long_press_threshold). + * @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. + * @warning When using this event along with onPress, both the onPress + * and onlongPress listeners may fire together. * * @param listenerName The name of the listener, this must be a unique name * @param func The function to run when the button is long pressed, 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) - * Example: + * + * @b Example: * @code {.cpp} * // Use a function... * Gamepad::master.Left.onLongPress("fireCatapult", fireCatapult); @@ -79,7 +82,8 @@ class Button { * @param func The function to run when the button is 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) - * Example: + * + * @b Example: * @code {.cpp} * // Use a function... * Gamepad::master.X.onRelease("stopFlywheel", stopFlywheel); @@ -89,14 +93,17 @@ class Button { */ bool onRelease(std::string listenerName, std::function func) const; /** - * @brief Register a function to run when the button is short released. This event will most likely be - * used along with the longPress event. (The default threshold for shortRelease to fire is 500ms or less, - * this threshold can be adjusted by changing long_press_threshold). + * @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. + * @note This event will most likely be used along with the longPress event. * * @param listenerName The name of the listener, this must be a unique name * @param func The function to run when the button is short 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.A.onShortRelease("raiseLiftOneLevel", raiseLiftOneLevel); @@ -113,6 +120,8 @@ class Button { * @param func The function to run for the given event, 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.L1.addListener(Gamepad::ON_PRESS, "start_spin", startSpin); @@ -123,10 +132,13 @@ class Button { bool addListener(EventType event, std::string listenerName, std::function func) const; /** * @brief Removes a listener from the button + * @warning Usage of this function is discouraged. * * @param listenerName The name of the listener to remove - * @return true The listener was successfully removed - * @return false The listener was not removed + * @return true The specified listener was successfully removed + * @return false The specified listener could not be removed + * + * @b Example: * @code {.cpp} * // Add an event listener... * Gamepad::master.L1.addListener(Gamepad::ON_PRESS, "do_something", doSomething); @@ -150,15 +162,9 @@ class Button { * @param is_held Whether or not the button is currently held down */ void update(bool is_held); - /** - * @brief The last time the update function was called - * - */ + /// he last time the update function was called uint32_t last_update_time = pros::millis(); - /** - * @brief The last time the long press event was fired - * - */ + /// The last time the long press event was fired uint32_t last_long_press_time = 0; mutable _impl::EventHandler onPressEvent {}; mutable _impl::EventHandler onLongPressEvent {}; @@ -172,16 +178,41 @@ class Controller { * Updates the state of the gamepad (all joysticks and buttons), and also runs * any registered handlers. * @note This function should be called at the beginning of every loop iteration. + * + * @b Example: + * @code {.cpp} + * while (true) { + * Gamepad::master.update(); + * // do robot control stuff here... + * pros::delay(25); + * } + * @endcode + * */ void update(); /** * Get the state of a button on the controller. - * @param button Which button's state you want. + * @param button Which button to return + * + * @b Example: + * @code {.cpp} + * if(Gamepad::master[DIGITAL_L1]) { + * // do something here... + * } + * @endcode + * */ const Button& operator[](pros::controller_digital_e_t button); /** * Get the value of a joystick axis on the controller. - * @param joystick Which joystick axis's value to return + * @param joystick Which joystick axis to return + * + * @b Example: + * @code {.cpp} + * // control a motor with a joystick + * intake.move(Gamepad::master[ANALOG_RIGHT_Y]); + * @endcode + * */ float operator[](pros::controller_analog_e_t joystick); const Button& L1 {m_L1}; From 6b75be8c6ee36d081df8aefc3ce4851f74b67c06 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Fri, 23 Aug 2024 16:11:57 +0000 Subject: [PATCH 57/60] docs: :memo: Fix formatting of docs for Controller --- include/gamepad/controller.hpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/include/gamepad/controller.hpp b/include/gamepad/controller.hpp index 44e33fb..5842604 100644 --- a/include/gamepad/controller.hpp +++ b/include/gamepad/controller.hpp @@ -55,8 +55,10 @@ class Button { bool onPress(std::string listenerName, std::function func) const; /** * @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. + * * @warning When using this event along with onPress, both the onPress * and onlongPress listeners may fire together. * @@ -94,8 +96,10 @@ class Button { bool onRelease(std::string listenerName, std::function func) const; /** * @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. + * * @note This event will most likely be used along with the longPress event. * * @param listenerName The name of the listener, this must be a unique name @@ -175,8 +179,9 @@ class Button { class Controller { public: /** - * Updates the state of the gamepad (all joysticks and buttons), and also runs - * any registered handlers. + * @brief Updates the state of the gamepad (all joysticks and buttons), and also runs + * any registered listeners. + * * @note This function should be called at the beginning of every loop iteration. * * @b Example: @@ -191,7 +196,8 @@ class Controller { */ void update(); /** - * Get the state of a button on the controller. + * @brief Get the state of a button on the controller. + * * @param button Which button to return * * @b Example: @@ -204,7 +210,8 @@ class Controller { */ const Button& operator[](pros::controller_digital_e_t button); /** - * Get the value of a joystick axis on the controller. + * @brief Get the value of a joystick axis on the controller. + * * @param joystick Which joystick axis to return * * @b Example: @@ -244,9 +251,10 @@ class Controller { float m_LeftX = 0, m_LeftY = 0, m_RightX = 0, m_RightY = 0; Button Fake {}; /** - * @brief Gets a unique name for a listener that will not conflict with user listener names. IMPORTANT: when - * using the function, you must register the listener by directly calling add_listener on the EventHandler, do - * NOT use onPress/addListener,etc. + * @brief Gets a unique name for a listener that will not conflict with user listener names. + * + * @important: when using the function, you must register the listener by + * directly calling add_listener on the EventHandler, do NOT use onPress/addListener,etc. * * @return std::string A unique listener name */ From da5a563a267e49d5b84fc8aed06deda431bf1406 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Fri, 23 Aug 2024 16:15:43 +0000 Subject: [PATCH 58/60] style: :art: Remove braces on single line ifs in controller.cpp --- src/gamepad/controller.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/gamepad/controller.cpp b/src/gamepad/controller.cpp index f54fc63..22f61d9 100644 --- a/src/gamepad/controller.cpp +++ b/src/gamepad/controller.cpp @@ -45,11 +45,8 @@ void Button::update(const bool is_held) { this->rising_edge = !this->is_pressed && is_held; this->falling_edge = this->is_pressed && !is_held; this->is_pressed = is_held; - if (is_held) { - this->time_held += pros::millis() - this->last_update_time; - } else { - this->time_released += pros::millis() - this->last_update_time; - } + if (is_held) this->time_held += pros::millis() - this->last_update_time; + else this->time_released += pros::millis() - this->last_update_time; if (this->rising_edge) { this->onPressEvent.fire(); @@ -59,10 +56,10 @@ void Button::update(const bool is_held) { this->last_long_press_time = pros::millis(); } else if (this->falling_edge) { this->onReleaseEvent.fire(); - if (this->time_held < this->long_press_threshold) { this->onShortReleaseEvent.fire(); } + if (this->time_held < this->long_press_threshold) this->onShortReleaseEvent.fire(); } - if (this->rising_edge) { this->time_held = 0; } - if (this->falling_edge) { this->time_released = 0; } + if (this->rising_edge) this->time_held = 0; + if (this->falling_edge) this->time_released = 0; this->last_update_time = pros::millis(); } From 6f1d7924f026cb8eaafbe24d0207550f6cbad96f Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Thu, 5 Sep 2024 09:15:56 -0700 Subject: [PATCH 59/60] fix: :bug: Fix A button not working --- src/gamepad/controller.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gamepad/controller.cpp b/src/gamepad/controller.cpp index 22f61d9..720c1f4 100644 --- a/src/gamepad/controller.cpp +++ b/src/gamepad/controller.cpp @@ -70,7 +70,7 @@ void Controller::updateButton(pros::controller_digital_e_t button_id) { } void Controller::update() { - for (int i = pros::E_CONTROLLER_DIGITAL_L1; i != pros::E_CONTROLLER_DIGITAL_A; ++i) { + for (int i = pros::E_CONTROLLER_DIGITAL_L1; i <= pros::E_CONTROLLER_DIGITAL_A; ++i) { this->updateButton(static_cast(i)); } @@ -122,4 +122,4 @@ Button Controller::*Controller::button_to_ptr(pros::controller_digital_e_t butto return &Controller::Fake; } } -} // namespace Gamepad \ No newline at end of file +} // namespace Gamepad From 766136a31fd787f21013a4b4cb48e7f301dc7916 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Fri, 6 Sep 2024 21:15:05 +0000 Subject: [PATCH 60/60] fix: :bug: Make A button actually work --- include/gamepad/controller.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/gamepad/controller.hpp b/include/gamepad/controller.hpp index 5842604..df78d52 100644 --- a/include/gamepad/controller.hpp +++ b/include/gamepad/controller.hpp @@ -233,7 +233,7 @@ class Controller { const Button& X {m_X}; const Button& B {m_B}; const Button& Y {m_Y}; - const Button& A {m_Down}; + const Button& A {m_A}; const float& LeftX = m_LeftX; const float& LeftY = m_LeftY; const float& RightX = m_RightX;