Skip to content

Instantly share code, notes, and snippets.

@AFCMS
Last active April 23, 2024 09:10
Show Gist options
  • Save AFCMS/91d2bc9bcf197ece8389906e5108d8d9 to your computer and use it in GitHub Desktop.
Save AFCMS/91d2bc9bcf197ece8389906e5108d8d9 to your computer and use it in GitHub Desktop.
Arduino Input System
/*
SPDX-FileCopyrightText: 2024 AFCMS <afcm.contact@gmail.com>
SPDX-License-Identifier: GPL-3.0-or-later
*/
#include <Arduino.h>
#include "input.hpp"
namespace utils
{
namespace input
{
void IRAM_ATTR InputSystem::ISR(void *isrData)
{
ButtonDataISR *data = (ButtonDataISR *)isrData;
uint8_t btn = data->button;
InputSystem *inputSystem = data->inputSystem;
if (millis() - inputSystem->getButtonLastMillis(btn) > BUTTON_DEBOUNCE)
{ // Software debouncing button
inputSystem->buttonPressedQueue.insert(btn);
}
inputSystem->setButtonLastMillis(btn, millis());
};
InputSystem::InputSystem()
{
buttons = std::vector<uint8_t>();
buttonsLastMillis = std::map<uint8_t, unsigned long>();
buttonPressedQueue = std::set<uint8_t>();
buttonsData = std::map<uint8_t, ButtonDataISR>();
};
InputSystem::InputSystem(std::vector<uint8_t> _buttons)
{
buttons = _buttons;
buttonsLastMillis = std::map<uint8_t, unsigned long>();
buttonPressedQueue = std::set<uint8_t>();
buttonsData = std::map<uint8_t, ButtonDataISR>();
for (int i = 0; i < buttons.size(); i++)
{
buttonsData[buttons[i]] = {buttons[i], this};
}
};
void InputSystem::begin()
{
for (int i = 0; i < buttons.size(); i++)
{
pinMode(buttons[i], INPUT_PULLUP);
buttonsLastMillis[buttons[i]] = 0;
// volatile ButtonDataISR data = {buttons[i], this}; // Create a separate ButtonDataISR object for each button
attachInterruptArg(buttons[i], &InputSystem::ISR, (void *)(&buttonsData[i]), RISING);
}
};
std::set<uint8_t> InputSystem::step()
{
std::set<uint8_t> pressedButtons = buttonPressedQueue;
buttonPressedQueue.clear();
return pressedButtons;
};
std::vector<uint8_t> InputSystem::getButtons()
{
return buttons;
};
unsigned long InputSystem::getButtonLastMillis(uint8_t button)
{
return buttonsLastMillis[button];
};
void InputSystem::setButtonLastMillis(uint8_t button, unsigned long millis)
{
buttonsLastMillis[button] = millis;
};
}
};
/*
SPDX-FileCopyrightText: 2024 AFCMS <afcm.contact@gmail.com>
SPDX-License-Identifier: GPL-3.0-or-later
*/
#include <Arduino.h>
#include <vector>
#include <map>
#include <set>
namespace utils
{
namespace input
{
class InputSystem; // Forward declaration
struct ButtonDataISR
{
uint8_t button;
InputSystem *inputSystem;
};
/**
* A class to handle button presses and debouncing
*/
class InputSystem
{
private:
std::vector<uint8_t> buttons;
std::map<uint8_t, unsigned long> buttonsLastMillis;
std::set<uint8_t> buttonPressedQueue;
std::map<uint8_t, ButtonDataISR> buttonsData;
static void ISR(void *buttonPin);
unsigned long getButtonLastMillis(uint8_t button);
void setButtonLastMillis(uint8_t button, unsigned long millis);
public:
InputSystem();
/**
* Construct a new Input System object
*
* @param _buttons A vector of button pins
*/
InputSystem(std::vector<uint8_t> _buttons);
/**
* Initialize the input system
*
* This method should be called in the setup() function
*
* It initializes the pins and the interrupts
*/
void begin();
/**
* Update the input system
*
* This method should be called in the loop() function
*
* Iteturns a set of the buttons that have been pressed
*
* @return A set of the buttons that have been pressed
*/
std::set<uint8_t> step();
/**
* Get the registered buttons
*
* @return A vector of the button pins
*/
std::vector<uint8_t> getButtons();
/**
* The debounce time for the buttons
*/
static const unsigned long BUTTON_DEBOUNCE = 10;
};
}
};
/*
SPDX-FileCopyrightText: 2024 AFCMS <afcm.contact@gmail.com>
SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "input.hpp"
// name = pins
enum Buttons
{
BUTTON_A = 32,
};
utils::input::InputSystem inputSystem({BUTTON_A});
void setup()
{
inputSystem.begin();
}
void loop()
{
// Buttons Input
auto pressedButtons = inputSystem.step();
for (auto it = pressedButtons.begin(); it != pressedButtons.end(); ++it)
{
switch (*it)
{
case BUTTON_A:
// Button A pressed
break;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment