bxparks / AceButton

An adjustable, compact, event-driven button library for Arduino that debounces and dispatches events to a user-defined event handler.
MIT License
393 stars 37 forks source link

Multiple buttons, issue with none release button.... #39

Closed GitFun4All closed 4 years ago

GitFun4All commented 4 years ago

Hello,

1st of all, thank you for Acebutton! - I've been using it for a while on ESP32s and mostly loving it. I'm having a bit of a problem (conceptually) with code for a held button (stuck button event) that I'd like to cater for.

Essentially I'd like to be able to use kEventPressed and kEventReleased in combination with another button to take a different action when one is held down.

I've attached separate handlers for each button, and use Pressed and Released but get no other buttons when the button is held down.

Doubt this is an issue with the library but would appreciate your advice.

Cheers!

bxparks commented 4 years ago

Ha, "mostly loving it"? You mean it's the best button library you've ever used? :-) Can you attach the minimal reproducible code, reduced down to 2 buttons, and describe what your expected behavior was? I can't debug anything without code.

GitFun4All commented 4 years ago

;-) It's definitely the best button library I've ever used....... although (as may become very obvious) I don't have a whole lot of experience with all things Arduino or ESP32...

The code is very my 1st project & a WIP, I'm a little embarrassed to post it but here goes....

#include <Arduino.h>
#include <AceButton.h>       
using namespace ace_button;

uint8_t istatepriv = 0;
bool bstatepriv = false;

unsigned long time_now = 0;
unsigned long time_to_stop = 0;

const unsigned long inital_flash_time = 3000; // Default amount of time for flashes. (3s)
const int left_relay_pin = 22;
const int right_relay_pin = 23;

const int left_button_pin = 17;
const int right_button_pin = 18;
const int brake_button_pin = 16;

bool _relayON = LOW;
bool _relayOFF = HIGH;
bool bstate = false;

enum
{
  none,
  left,
  right
} istate;

ButtonConfig leftandrightConfig;
ButtonConfig brakeConfig;

AceButton left_button(&leftandrightConfig);
AceButton right_button(&leftandrightConfig);
AceButton brake_button(&brakeConfig);

void pretyprintbrk(bool state)
{
  if (state)
  {
    Serial.println("Brake On");
  }
  else
  {
    Serial.println("Brake Off");
  }
}

void pretyprintind(uint8_t state)
{
  switch (state)
  {
  case 0:
    Serial.println("None");
    break;
  case 1:
    Serial.println("Left Button Pressed");
    break;
  case 2:
    Serial.println("Right Button Pressed");
    break;
  }
}

void leftORrightHandler(AceButton *button, uint8_t eventType, uint8_t buttonState)
{
  uint8_t whichpin = button->getPin();
  unsigned long pin_time = millis();
  switch (whichpin)
  {
  case left_button_pin:
    if (time_to_stop != 0)
      istate = left;
    time_to_stop = inital_flash_time + pin_time;
    break;
  case right_button_pin:
    istate = right;
    time_to_stop = inital_flash_time + pin_time;
    break;
  }
}

void brakeHandler(AceButton *button, uint8_t eventType, uint8_t buttonState)
{
  //uint8_t whichpin = button->getPin();
  //unsigned long pin_time = millis();
  switch (eventType)
  {
  case AceButton::kEventPressed:
    bstate = true;
    break;
  case AceButton::kEventReleased:
    bstate = false;
    break;
  }
}

void setup()
{
  //Serial Console
  Serial.begin(115200);
  while (!Serial)
    ;

  istate = none;

  //Inputs
  pinMode(left_button_pin, INPUT_PULLUP);
  pinMode(right_button_pin, INPUT_PULLUP);
  pinMode(brake_button_pin, INPUT_PULLUP);
  // Outputs
  pinMode(left_relay_pin, OUTPUT);
  pinMode(right_relay_pin, OUTPUT);
  // Init State
  digitalWrite(right_relay_pin, _relayOFF);
  digitalWrite(right_relay_pin, _relayON);
  // AceButton Config
  leftandrightConfig.setEventHandler(leftORrightHandler);
  brakeConfig.setEventHandler(brakeHandler);

  left_button.init(left_button_pin);
  right_button.init(right_button_pin);
  brake_button.init(brake_button_pin);

  Serial.println("AA Flash Ready.");
}

void loop()
{
  time_now = millis();
  left_button.check();
  right_button.check();
  brake_button.check();

  if (istate != istatepriv)
  {
    istatepriv = istate;
    if ( bstate ) {
      Serial.print("Brakes ON --> ");
      pretyprintind(istate);
    } else {
      Serial.print("Brakes OFF --> ");
      pretyprintind(istate);
    }
  }

  if (bstate != bstatepriv)
  {
    pretyprintbrk(bstate);
    bstatepriv = bstate;
  }

  if ((time_to_stop != 0) && (time_now >= time_to_stop))
  {
    Serial.println("Timer expired, turning Indicator off!");
    istate = none; //Timer run out, turn everything off.
    time_to_stop = 0;
  }
}

The expectation was that whilst the 'brake pin' is held the left and right buttons still report a change in state. What I see currently is the break on, but no other events. I don't know if this is because of my duff programming or if I have I got my wires crossed? (excuse the pun).

Cheers!

bxparks commented 4 years ago

Ok, this is a bit more than a "minimal" version, so I need some time to parse through it, which I don't have time to do until this weekend.. or next weekend. If time is critical, I recommend distilling this down to just 2 buttons, and implement the simplest version of what you want. The 2 buttons are independent, so they should fire off their events independently. What you need is to encode a state-machine on top of the 2 buttons to implement rules like: "When Button1 is Pressed but not yet Released, Button2 Pressed triggers Action1. If Button1 is not Pressed, then Button2 Pressed triggers Action2".

GitFun4All commented 4 years ago

No worries, sorry the code isn't very concise. I don't want to waste your time, especially if the library handles concurrency without issue. I'll close this off and try to implement what you suggested to see if I can get it to work.

If you have some time and the inclination in future, I'd love to see a demo of concurrent button usage as another example for the library.

Thanks for the pointers!