diff --git a/.gitignore b/.gitignore index 5419594..c64778c 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,7 @@ # PROS bin/ -.vscode/ +.vscode/* .cache/ compile_commands.json temp.log @@ -24,3 +24,6 @@ temp.errors # Linux debug.log + +# Always include development settings +!.vscode/settings.json \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index b242572..0120171 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,10 @@ { "githubPullRequests.ignoredPullRequestBranches": [ "main" + ], + "conventionalCommits.scopes": [ + "buttons", + "display", + "joysticks" ] } \ No newline at end of file diff --git a/include/gamepad/button.hpp b/include/gamepad/button.hpp index 1e25cff..a0a63ac 100644 --- a/include/gamepad/button.hpp +++ b/include/gamepad/button.hpp @@ -73,8 +73,8 @@ class Button { * * @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) + * @return 0 The listener was successfully registered + * @return INT32_MAX The listener was not successfully registered (there is already a listener with this name) * * @b Example: * @code {.cpp} @@ -84,7 +84,7 @@ class Button { * gamepad::master.Up.onPress("upPress1", []() { std::cout << "I was pressed!" << std::endl; }); * @endcode */ - bool onPress(std::string listenerName, std::function func) const; + int32_t onPress(std::string listenerName, std::function func) const; /** * @brief Register a function to run when the button is long pressed. * @@ -96,8 +96,8 @@ class Button { * * @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) + * @return 0 The listener was successfully registered + * @return INT32_MAX The listener was not successfully registered (there is already a listener with this name) * * @b Example: * @code {.cpp} @@ -108,14 +108,14 @@ class Button { * std::endl; }); * @endcode */ - bool onLongPress(std::string listenerName, std::function func) const; + int32_t 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) + * @return 0 The listener was successfully registered + * @return INT32_MAX The listener was not successfully registered (there is already a listener with this name) * * @b Example: * @code {.cpp} @@ -125,7 +125,7 @@ class Button { * gamepad::master.Y.onRelease("stopIntake", []() { intake.move(0); }); * @endcode */ - bool onRelease(std::string listenerName, std::function func) const; + int32_t onRelease(std::string listenerName, std::function func) const; /** * @brief Register a function to run when the button is short released. * @@ -136,8 +136,8 @@ class Button { * * @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) + * @return 0 The listener was successfully registered + * @return INT32_MAX The listener was not successfully registered (there is already a listener with this name) * * @b Example: * @code {.cpp} @@ -147,7 +147,7 @@ class Button { * gamepad::master.B.onShortRelease("intakeOnePiece", []() { intake.move_relative(600, 100); }); * @endcode */ - bool onShortRelease(std::string listenerName, std::function func) const; + int32_t onShortRelease(std::string listenerName, std::function func) const; /** * @brief Register a function to run when the button is long released. * @@ -156,8 +156,8 @@ class Button { * * @param listenerName The name of the listener, this must be a unique name * @param func The function to run when the button is long released, the function MUST NOT block - * @return true The listener was successfully registered - * @return false The listener was not successfully registered (there is already a listener with this name) + * @return 0 The listener was successfully registered + * @return INT32_MAX The listener was not successfully registered (there is already a listener with this name) * * @b Example: * @code {.cpp} @@ -168,7 +168,7 @@ class Button { * @endcode * */ - bool onLongRelease(std::string listenerName, std::function func) const; + int32_t onLongRelease(std::string listenerName, std::function func) const; /** * @brief Register a function to run periodically after its been held * @@ -177,8 +177,8 @@ class Button { * * @param listenerName The name of the listener, this must be a unique name * @param func the function to run periodically when the button is held, the function MUST NOT block - * @return true The listener was successfully registered - * @return false The listener was not successfully registered (there is already a listener with this name) + * @return 0 The listener was successfully registered + * @return INT32_MAX The listener was not successfully registered (there is already a listener with this name) * * @b Example: * @code {.cpp} @@ -189,15 +189,15 @@ class Button { * @endcode * */ - bool onRepeatPress(std::string listenerName, std::function func) const; + int32_t onRepeatPress(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) + * @return 0 The listener was successfully registered + * @return INT32_MAX The listener was not successfully registered (there is already a listener with this name) * * @b Example: * @code {.cpp} @@ -207,24 +207,25 @@ class Button { * gamepad::master.L1.addListener(gamepad::ON_RELEASE, "stop_spin", []() { motor1.brake(); }); * @endcode */ - bool addListener(EventType event, std::string listenerName, std::function func) const; + int32_t 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 event the event type of the listener * @param listenerName The name of the listener to remove - * @return true The specified listener was successfully removed - * @return false The specified listener could not be removed + * @return 0 The specified listener was successfully removed + * @return INT32_MAX 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); * // ...and now get rid of it - * gamepad::master.L1.removeListener("do_something"); + * gamepad::master.L1.removeListener(gamepad::ON_PRESS, "do_something"); * @endcode */ - bool removeListener(std::string listenerName) const; + int32_t removeListener(EventType event, std::string listenerName) const; /** * @brief Returns a value indicating whether the button is currently being held. @@ -240,6 +241,14 @@ class Button { * @param is_held Whether or not the button is currently held down */ void update(bool is_held); + /** + * @brief Get the handler object for the given event type + * + * @param event The desired event type + * @return nullptr The event value is invalid + * @return _impl::EventHandler* A pointer to the given event's handler + */ + _impl::EventHandler* get_handler(EventType event) const; /// How long the threshold should be for the longPress and shortRelease events mutable uint32_t m_long_press_threshold = 500; /// How often repeatPress is called diff --git a/include/gamepad/event_handler.hpp b/include/gamepad/event_handler.hpp index a5a7a5b..c9f3d47 100644 --- a/include/gamepad/event_handler.hpp +++ b/include/gamepad/event_handler.hpp @@ -24,37 +24,37 @@ template class EventHandler { * * @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) + * @return 0 The listener was successfully added + * @return INT32_MAX The listener was NOT successfully added (there is already a listener with the same key) */ - bool addListener(Key key, Listener func) { + int32_t addListener(Key key, Listener func) { std::lock_guard lock(m_mutex); - if (std::find(m_keys.begin(), m_keys.end(), key) != m_keys.end()) return false; + if (std::find(m_keys.begin(), m_keys.end(), key) != m_keys.end()) return INT32_MAX; m_keys.push_back(key); m_listeners.push_back(func); - return true; + return 0; } /** * @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) + * @return 0 The listener was successfully removed + * @return INT32_MAX The listener was NOT successfully removed (there is no listener with the same key) */ - bool removeListener(Key key) { + int32_t removeListener(Key key) { std::lock_guard lock(m_mutex); auto i = std::find(m_keys.begin(), m_keys.end(), key); if (i != m_keys.end()) { m_keys.erase(i); m_listeners.erase(m_listeners.begin() + (i - m_keys.begin())); - return true; + return 0; } - return false; + return INT32_MAX; } /** - * @brief Whther or not there are any listeners registered + * @brief Whether or not there are any listeners registered * * @return true There are listeners registered * @return false There are no listeners registered diff --git a/include/gamepad/gamepad.hpp b/include/gamepad/gamepad.hpp index 901739f..64bc7ea 100644 --- a/include/gamepad/gamepad.hpp +++ b/include/gamepad/gamepad.hpp @@ -49,12 +49,21 @@ class Gamepad { * @param line the line number to print the string on (0-2) * @param str the string to print onto the controller (\n to go to the next line) * + * This function uses the following value(s) of errno when an error state is reached: + * + * EINVAL: The line number is not in the interval [0, 2] + * EMSGSIZE: The string is more than 3 lines long + * * @b Example: * @code {.cpp} * gamepad::master.printLine(1, "This will print on the middle line"); * gamepad::master.printLine(0, "this will print\n\naround the middle line"); + * @endcode + * + * @return 0 if the line was printed successfully + * @return INT32_MAX if there was an error, setting errno */ - void printLine(uint8_t line, std::string str); + int32_t printLine(uint8_t line, std::string str); /** * @brief clears all lines on the controller, similar to the pros function (low priority) * @@ -62,6 +71,7 @@ class Gamepad { * @code {.cpp} * // clears the whole screen on the controller * gamepad::master.clear() + * @endcode */ void clear(); /** @@ -69,22 +79,39 @@ class Gamepad { * * @param line the line to clear (0-2) * + * This function uses the following value(s) of errno when an error state is reached: + * + * EINVAL: The line number is not in the interval [0, 2] + * * @b Example: * @code {.cpp} * // clears the center line on the controller * gamepad::master.clear(1); + * @endcode + * + * @return 0 if the line was cleared successfully + * @return INT32_MAX if there was an error, setting errno */ - void clear(uint8_t line); + int32_t clear(uint8_t line); /** * makes the controller rumble like pros (low priority) * * @param rumble_pattern A string consisting of the characters '.', '-', and ' ', where dots are short rumbles, * dashes are long rumbles, and spaces are pauses. Maximum supported length is 8 characters. * + * This function uses the following value(s) of errno when an error state is reached: + * + * EINVAL: The rumble pattern contains a character other than '.', '-', or ' ' + * EMSGSIZE: The pattern is more than 8 characters long + * * @b Example: * @code {.cpp} * // rumbles in the following pattern: short, pause, long, short short * gamepad::master.rumble(". -.."); + * @endcode + * + * @return 0 if the rumble was successful + * @return INT32_MAX if there was an error, setting errno */ void rumble(std::string rumble_pattern); /** @@ -150,7 +177,7 @@ class Gamepad { * @return std::string A unique listener name */ static std::string uniqueName(); - static Button Gamepad::*buttonToPtr(pros::controller_digital_e_t button); + static Button Gamepad::* buttonToPtr(pros::controller_digital_e_t button); void updateButton(pros::controller_digital_e_t button_id); void updateScreens(); diff --git a/include/gamepad/screens/alertScreen.hpp b/include/gamepad/screens/alertScreen.hpp index 50a40cc..3c8edc6 100644 --- a/include/gamepad/screens/alertScreen.hpp +++ b/include/gamepad/screens/alertScreen.hpp @@ -46,8 +46,17 @@ class AlertScreen : public AbstractScreen { * @param duration how long the alert should persist on the screen * @param rumble A string consisting of the characters '.', '-', and ' ', where dots are short rumbles, * dashes are long rumbles, and spaces are pauses. Maximum supported length is 8 characters. + * + * This function uses the following value(s) of errno when an error state is reached: + * + * EINVAL: The line number is not in the interval [0, 2] + * EMSGSIZE: The alert is more than 3 lines long + * + * @return 0 if the alert was added successfully + * @return INT32_MAX if there was an error, setting errno + * */ - void addAlerts(uint8_t line, std::string strs, uint32_t duration, std::string rumble = ""); + int32_t addAlerts(uint8_t line, std::string strs, uint32_t duration, std::string rumble = ""); private: struct AlertBuffer { ScreenBuffer screen; diff --git a/include/gamepad/screens/defaultScreen.hpp b/include/gamepad/screens/defaultScreen.hpp index f85363e..6c46c82 100644 --- a/include/gamepad/screens/defaultScreen.hpp +++ b/include/gamepad/screens/defaultScreen.hpp @@ -31,16 +31,32 @@ class DefaultScreen : public AbstractScreen { * * @param line the line number to print the string on (0-2) * @param str the string to print onto the controller (\n to go to the next line) + * + * This function uses the following value(s) of errno when an error state is reached: + * + * EINVAL: The line number is not in the interval [0, 2] + * EMSGSIZE: The string is more than 3 lines long + * + * @return 0 if the alert was added successfully + * @return INT32_MAX if there was an error, setting errno */ - void printLine(uint8_t line, std::string str); + int32_t printLine(uint8_t line, std::string str); /** * makes the controller rumble like pros * * @param rumble_pattern A string consisting of the characters '.', '-', and ' ', where dots are short rumbles, * dashes are long rumbles, and spaces are pauses. Maximum supported length is 8 characters. + * + * This function uses the following value(s) of errno when an error state is reached: + * + * EINVAL: The rumble pattern contains a character other than '.', '-', or ' ' + * EMSGSIZE: The pattern is more than 8 characters long + * + * @return 0 if the alert was added successfully + * @return INT32_MAX if there was an error, setting errno */ - void rumble(std::string rumble_pattern); + int32_t rumble(std::string rumble_pattern); private: ScreenBuffer m_current_buffer {}; pros::Mutex m_mutex {}; diff --git a/include/gamepad/todo.hpp b/include/gamepad/todo.hpp index c1e0b7b..4b0ffd4 100644 --- a/include/gamepad/todo.hpp +++ b/include/gamepad/todo.hpp @@ -1,5 +1,13 @@ #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 + +// We only define the TODO/FIXME macros if the file is being compiled by Microsoft Intellisense +// or clangd. This way, the TODO/FIXME messages don't clutter the compilation messages. +#if defined(_debug) || defined(__clang__) +#define TODO(x) DO_PRAGMA(message("TODO - " x)) +#define FIXME(x) DO_PRAGMA(warning("FIXME - " x)) +#else +#define TODO(x) +#define FIXME(x) +#endif \ No newline at end of file diff --git a/src/gamepad/button.cpp b/src/gamepad/button.cpp index d3f3965..f343eeb 100644 --- a/src/gamepad/button.cpp +++ b/src/gamepad/button.cpp @@ -4,57 +4,72 @@ #include namespace gamepad { +_impl::EventHandler* Button::get_handler(EventType event) const { + switch (event) { + case gamepad::EventType::ON_PRESS: return &m_on_press_event; + case gamepad::EventType::ON_LONG_PRESS: return &m_on_long_press_event; + case gamepad::EventType::ON_RELEASE: return &m_on_release_event; + case gamepad::EventType::ON_SHORT_RELEASE: return &m_on_short_release_event; + case gamepad::EventType::ON_LONG_RELEASE: return &m_on_long_release_event; + case gamepad::EventType::ON_REPEAT_PRESS: return &m_on_repeat_press_event; + default: return nullptr; + } +} + void Button::setLongPressThreshold(uint32_t threshold) const { m_long_press_threshold = threshold; } void Button::setRepeatCooldown(uint32_t cooldown) const { m_repeat_cooldown = cooldown; } -bool Button::onPress(std::string listenerName, std::function func) const { +int32_t Button::onPress(std::string listenerName, std::function func) const { return m_on_press_event.addListener(std::move(listenerName) + "_user", std::move(func)); } -bool Button::onLongPress(std::string listenerName, std::function func) const { +int32_t Button::onLongPress(std::string listenerName, std::function func) const { return m_on_long_press_event.addListener(std::move(listenerName) + "_user", std::move(func)); } -bool Button::onRelease(std::string listenerName, std::function func) const { +int32_t Button::onRelease(std::string listenerName, std::function func) const { return m_on_release_event.addListener(std::move(listenerName) + "_user", std::move(func)); } -bool Button::onShortRelease(std::string listenerName, std::function func) const { +int32_t Button::onShortRelease(std::string listenerName, std::function func) const { return m_on_short_release_event.addListener(std::move(listenerName) + "_user", std::move(func)); } -bool Button::onLongRelease(std::string listenerName, std::function func) const { +int32_t Button::onLongRelease(std::string listenerName, std::function func) const { return m_on_long_release_event.addListener(std::move(listenerName) + "_user", std::move(func)); } -bool Button::onRepeatPress(std::string listenerName, std::function func) const { +int32_t Button::onRepeatPress(std::string listenerName, std::function func) const { return m_on_repeat_press_event.addListener(std::move(listenerName) + "_user", 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)); - case gamepad::EventType::ON_LONG_RELEASE: return this->onLongRelease(std::move(listenerName), std::move(func)); - case gamepad::EventType::ON_REPEAT_PRESS: return this->onRepeatPress(std::move(listenerName), std::move(func)); - default: - TODO("add error logging") - errno = EINVAL; - return false; +int32_t Button::addListener(EventType event, std::string listenerName, std::function func) const { + auto handler = this->get_handler(event); + if (handler != nullptr) { + return handler->addListener(listenerName + "_user", func); + } else { + TODO("add error logging") + errno = EINVAL; + return INT32_MAX; } } -bool Button::removeListener(std::string listenerName) const { +int32_t Button::removeListener(EventType event, std::string listenerName) const { return m_on_press_event.removeListener(listenerName + "_user") || m_on_long_press_event.removeListener(listenerName + "_user") || m_on_release_event.removeListener(listenerName + "_user") || m_on_short_release_event.removeListener(listenerName + "_user") || m_on_long_release_event.removeListener(listenerName + "_user") || m_on_repeat_press_event.removeListener(listenerName + "_user"); + auto handler = this->get_handler(event); + if (handler != nullptr) { + return handler->removeListener(listenerName + "_user"); + } else { + TODO("add error logging") + errno = EINVAL; + return INT32_MAX; + } } void Button::update(const bool is_held) { diff --git a/src/gamepad/gamepad.cpp b/src/gamepad/gamepad.cpp index 486b7d7..cbaa797 100644 --- a/src/gamepad/gamepad.cpp +++ b/src/gamepad/gamepad.cpp @@ -19,7 +19,7 @@ Gamepad::Gamepad(pros::controller_id_e_t id) } void Gamepad::updateButton(pros::controller_digital_e_t button_id) { - Button Gamepad::*button = Gamepad::buttonToPtr(button_id); + Button Gamepad::* button = Gamepad::buttonToPtr(button_id); bool is_held = m_controller.get_digital(button_id); (this->*button).update(is_held); } @@ -130,11 +130,11 @@ void Gamepad::addScreen(std::shared_ptr screen) { m_screens.emplace(m_screens.begin() + pos, screen); } -void Gamepad::printLine(uint8_t line, std::string str) { m_default_screen->printLine(line, str); } +int32_t Gamepad::printLine(uint8_t line, std::string str) { return m_default_screen->printLine(line, str); } void Gamepad::clear() { m_default_screen->printLine(0, " \n \n "); } -void Gamepad::clear(uint8_t line) { m_default_screen->printLine(line, " "); } +int32_t Gamepad::clear(uint8_t line) { return m_default_screen->printLine(line, " "); } void Gamepad::rumble(std::string rumble_pattern) { m_default_screen->rumble(rumble_pattern); } @@ -146,10 +146,7 @@ float Gamepad::operator[](pros::controller_analog_e_t axis) { 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; - default: - TODO("add error logging") - errno = EINVAL; - return 0; + default: TODO("add error logging") return 0; } } @@ -158,7 +155,7 @@ std::string Gamepad::uniqueName() { return std::to_string(i++) + "_internal"; } -Button Gamepad::*Gamepad::buttonToPtr(pros::controller_digital_e_t button) { +Button Gamepad::* Gamepad::buttonToPtr(pros::controller_digital_e_t button) { switch (button) { case pros::E_CONTROLLER_DIGITAL_L1: return &Gamepad::m_L1; case pros::E_CONTROLLER_DIGITAL_L2: return &Gamepad::m_L2; @@ -172,10 +169,7 @@ Button Gamepad::*Gamepad::buttonToPtr(pros::controller_digital_e_t button) { case pros::E_CONTROLLER_DIGITAL_B: return &Gamepad::m_B; case pros::E_CONTROLLER_DIGITAL_Y: return &Gamepad::m_Y; case pros::E_CONTROLLER_DIGITAL_A: return &Gamepad::m_A; - default: - TODO("add error logging") - errno = EINVAL; - return &Gamepad::Fake; + default: TODO("add error logging") return &Gamepad::Fake; } } } // namespace gamepad diff --git a/src/gamepad/screens/alertScreen.cpp b/src/gamepad/screens/alertScreen.cpp index 4d23d45..d960d16 100644 --- a/src/gamepad/screens/alertScreen.cpp +++ b/src/gamepad/screens/alertScreen.cpp @@ -2,6 +2,7 @@ #include "gamepad/todo.hpp" #include "pros/rtos.hpp" #include +#include #include #include #include @@ -32,12 +33,19 @@ void AlertScreen::update(uint32_t delta_time) { if (pros::millis() - m_line_set_time >= m_screen_contents->duration) m_screen_contents = std::nullopt; } -void AlertScreen::addAlerts(uint8_t line, std::string str, uint32_t duration, std::string rumble) { - TODO("change handling for off screen lines") - if (line > 2) std::exit(1); +int32_t AlertScreen::addAlerts(uint8_t line, std::string str, uint32_t duration, std::string rumble) { + int32_t ret_val = 0; + if (line > 2) { + TODO("add error logging") + errno = EINVAL; + return INT32_MAX; + } - TODO("warn instead of throw error if there are too many lines") - if (std::ranges::count(str, '\n') > 2) std::exit(1); + if (std::ranges::count(str, '\n') > 2) { + TODO("add warn logging") + errno = EMSGSIZE; + ret_val = INT32_MAX; + } std::vector strs(3, ""); std::stringstream ss(str); @@ -56,6 +64,7 @@ void AlertScreen::addAlerts(uint8_t line, std::string str, uint32_t duration, st std::lock_guard guard(m_mutex); m_screen_buffer.push_back({buffer, duration}); + return ret_val; } } // namespace gamepad diff --git a/src/gamepad/screens/defaultScreen.cpp b/src/gamepad/screens/defaultScreen.cpp index 6fa23d4..eade5b1 100644 --- a/src/gamepad/screens/defaultScreen.cpp +++ b/src/gamepad/screens/defaultScreen.cpp @@ -2,6 +2,8 @@ #include "gamepad/screens/abstractScreen.hpp" #include "gamepad/todo.hpp" #include +#include +#include #include #include #include @@ -20,15 +22,22 @@ ScreenBuffer DefaultScreen::getScreen(std::set visible_lines) { return output; } -void DefaultScreen::printLine(uint8_t line, std::string str) { - TODO("change handling for off screen lines") - if (line > 2) std::exit(1); +int32_t DefaultScreen::printLine(uint8_t line, std::string str) { + int32_t ret_val = 0; + if (line > 2) { + TODO("add error logging") + errno = EINVAL; + return INT32_MAX; + } const std::lock_guard guard(m_mutex); if (str.find('\n') != std::string::npos) { - TODO("warn instead of throw error if there are too many lines") - if (std::ranges::count(str, '\n') > 2) std::exit(1); + if (std::ranges::count(str, '\n') > 2) { + TODO("add warn logging for too many lines") + errno = EMSGSIZE; + ret_val = INT32_MAX; + } std::vector strs(3); std::stringstream ss(str); @@ -40,18 +49,31 @@ void DefaultScreen::printLine(uint8_t line, std::string str) { for (uint8_t l = 0; l < 3; l++) { if (!strs[l].empty()) m_current_buffer[l] = (strs[l]); } - return; + return ret_val; } m_current_buffer[line] = std::move(str); + return ret_val; } -void DefaultScreen::rumble(std::string rumble_pattern) { - TODO("change handling for too long rumble patterns") - if (rumble_pattern.size() > 8) std::exit(1); +int32_t DefaultScreen::rumble(std::string rumble_pattern) { + int32_t ret_val = 0; + if (rumble_pattern.size() > 8) { + TODO("add error logging") + errno = EMSGSIZE; + ret_val = INT32_MAX; + rumble_pattern.resize(8); + } + + if (rumble_pattern.find_first_not_of(".- ") != std::string::npos) { + TODO("add error logging") + errno = EINVAL; + return INT32_MAX; + } std::lock_guard guard(m_mutex); m_current_buffer[3] = std::move(rumble_pattern); + return ret_val; } } // namespace gamepad \ No newline at end of file