Long press then long press2

Hi All, spent about 3 hrs struggling with trying to learn how to do a long press on a second long press from the following sketch
so long press > long press2 can it be done this way?




//// SWITCH ////
unsigned long timer = millis();
static const int buttonPin = 3;                    // switch pin
int buttonStatePrevious = LOW;                      // previousstate of the switch
unsigned long Duration = 100;
unsigned long minButtonLongPressDuration = 300;
unsigned long LDuration = 500;// Time we wait before we see the press as a long press
unsigned long buttonLongPressMillis;                // Time in ms when we the button was pressed
bool buttonStateLongPress = false;                  // True if it is a long press
int counter = 0;
const int intervalButton = 50;                      // Time between two readings of the button state
unsigned long previousButtonMillis;                 // Timestamp of the latest reading
bool buttonStateLongPress2 = false;  
unsigned long buttonPressDuration;                  // Time the button is pressed in ms

//// GENERAL ////

unsigned long currentMillis;          // Variabele to store the number of milleseconds since the Arduino has started

void setup() {
  Serial.begin(9600);                 // Initialise the serial monitor

  pinMode(buttonPin, INPUT);          // set buttonPin as input
  Serial.println("Press button");

}

// Function for reading the button state
void readButtonState() {

  // If the difference in time between the previous reading is larger than intervalButton
  if(currentMillis - previousButtonMillis > intervalButton) {
    
    // Read the digital value of the button (LOW/HIGH)
    int buttonState = digitalRead(buttonPin);    

    // If the button has been pushed AND
    // If the button wasn't pressed before AND
    // IF there was not already a measurement running to determine how long the button has been pressed
    if (buttonState == HIGH && buttonStatePrevious == LOW && !buttonStateLongPress) {
      buttonLongPressMillis = currentMillis;
      buttonStatePrevious = HIGH;
      Serial.println("Button pressed");
    }

    // Calculate how long the button has been pressed
    buttonPressDuration = currentMillis - buttonLongPressMillis;

    // If the button is pressed AND
    // If there is no measurement running to determine how long the button is pressed AND
    // If the time the button has been pressed is larger or equal to the time needed for a long press
    if (buttonState == HIGH && !buttonStateLongPress && buttonPressDuration >= minButtonLongPressDuration) {
      buttonStateLongPress = true;
      Serial.println("Button long pressed");
      counter == 0;
                  timer = millis();

    }
    
   
    // If the button is released AND
    // If the button was pressed before
    if (buttonState == LOW && buttonStatePrevious == HIGH) {
      buttonStatePrevious = LOW;
      buttonStateLongPress = false;
      
     Serial.println("Button released");
      Serial.println(timer);
     
    if (buttonState == HIGH && !buttonStateLongPress2 && timer > LDuration && counter > 0) {

     
        buttonStateLongPress = true;
        buttonStateLongPress2 = true;
        
      Serial.println("Button long pressed2");
     // counter = 0;
    }

      // If there is no measurement running to determine how long the button was pressed AND
      // If the time the button has been pressed is smaller than the minimal time needed for a long press
      // Note: The video shows:
      //       if (!buttonStateLongPress && buttonPressDuration < minButtonLongPressDuration) {
      //       since buttonStateLongPress is set to FALSE on line 75, !buttonStateLongPress is always TRUE
      //       and can be removed.
      if (buttonPressDuration < minButtonLongPressDuration) {
        Serial.println("Button pressed shortly");
      }
    }
    
    // store the current timestamp in previousButtonMillis
    previousButtonMillis = currentMillis;

  }

}

void loop() {

  currentMillis = millis();    // store the current time
  readButtonState();           // read the button state
  
}

Any help would be great.

Could you explain the problem so that even I can understand it ?

There is one button ? It needs to be pressed for at least a certain amount of time ? How long may or should it be released after that ? What if it takes a week before it is pressed a second time ? Should the second long press be longer or shorter than the first one ?

thanks for the reply yes one button

when you press the button for the hold duration then release it and press it again for a separate duration.

Maybe a bit longer.

i was trying after the first long press to set the time and when the button is pressed long again and the duration is => the duration form the first long press the button get engaged.

what if the previous press was an hour ago?

do you have to delay reporting a button press to wait for it to be very quickly re-pressed? (how long)

ok so after a certain amount of time should it returns back.

The first long button press is reported by a serial print, a short press is also reported the same way.
no i dont have a delay for that.

What I was trying to do is if the long press button was pressed start the timer and then if the time passed 500 and the long button was pressed again it would execute.

What and how many button 'uses' do you already have, such that you require a double long press?

i would report a long press if a button long enough without being released and report a short press if released before the long press time.

but it sounds like your willing to wait for the button to be released before reporting a long press.

so when it is released, you need to capture a timestamp that is checked when pressed again to recognize a "quick repress" that sets a flag results in different button press results that 2nd press

no i think its being reported by when the long button press reaches 300.

so when it is released, you need to capture a timestamp that is checked when pressed again to recognize a "quick repress" that sets a flag results in different button press results that 2nd press

would i not need to do this when the button is pressed fist time long?

yes, you need a method that works "every time".

consider the very first press, is the timestamp, which is probably zero, valid? a flag could be used, or you could make sure a timestamp of zero (set to 1) is never used.

Does this look right

 if (buttonState == HIGH && !buttonStateLongPress2 && counter - timer > LDuration

counter is set to 0 and timer(millis) starts when the long button is pressed.

would that would go on a short press?

not following your logic

consider

const byte butPin = A1;

unsigned long msecPrev;
unsigned long msecPress;

unsigned long PeriodRepress = 500;
unsigned long PeriodLong    = 300;

bool          repress = false;
bool          butState;

enum { None, Short1, Long1, Short2, Long2 };

// -----------------------------------------------------------------------------
int
chkBut ()
{
    unsigned long msec = millis ();

    byte but = digitalRead (butPin);

    if (butState != but)  {
        butState = but;
        delay (10);         //debounce

        if (LOW == but)  {      // press
 //         Serial.println ("  press");

            repress   = (msec - msecPrev) < PeriodRepress;
            msecPress = msec ? msec : 1;
        }

        else {                  // release
 //         Serial.println ("  release");

            msecPrev  = msec ? msec : 1;     // not zero

            if ((msec - msecPress) < PeriodLong)  {
                msecPress = 0;
                if (repress)
                    return Short2;
                else
                    return Short1;
            }
        }

    }

    if (LOW == but)  {    // held pressed
        if (msecPress && (msec - msecPress) > PeriodLong)  {
            msecPress = 0;

            if (repress)
                return Long2;
            else
                return Long1;
        }
    }

    return None;
}

// -----------------------------------------------------------------------------
void loop() {

    switch (chkBut ())  {
    case Short1 :
        Serial.println ("short1");
        break;
    case Short2 :
        Serial.println ("short2");
        break;
    case Long1 :
        Serial.println ("long1");
        break;
    case Long2 :
        Serial.println ("long2");
        break;
    }
}

// -----------------------------------------------------------------------------
void setup ()
{
    Serial.begin(9600);

    pinMode (butPin, INPUT_PULLUP);
    butState = digitalRead (butPin);
}

sorry can i ask what this line means?
msec ? msec : 1;

msecPrev  = msec ? msec : 1;

'msec ? msec : 1' This format is what's called a ternary operator. So you have the condition that must evaluate to true/false, a question mark, then a value for if the condition is true, and one for if it's false.

So in this case: The msecPrev variable (the previous time that millis was captured) is going to be set to either the value of msec or '1', based on if msec is true or not. In this sense, true being 'not zero'.

Another way of writing the same code would be:

if (msec != 0) {
msecPrev = msec;
}
else if (msec == 0  {
msecPrev = 1;
}

ok Thanks

.Thanks for that, that makes a bit more sense.
How do you stop it going from 1st short press to long press2?

@gregchill Have you heard of a "Finite State Machine" ?

You have not answered the question how long the button may be released between the presses. What if a button a pressed for a long time, and a week later again for a long time ?
If you really don't care, then there should be a led that indicates that the sketch is waiting for the second long press.

Well within reason maybe a 3min total.

Yes im looking at videos and documentation of that too tried it and i have got so far with it.
but i think i realy need one concept down of how this is done.
my problem is between the 1st long and the second time the button long is pressed.
the gap time. i am trying to write it out in plain english and see if i can get it in my head.

do you not care about a 2nd short press? if so, in that case, does it matter how long the 2nd press is?

Just for fun:

Start the simulation and try to press two times between 190ms and 900ms with a very short release and a longer release in between. Can you select the '5' and the '7' ? Try pressing it longer than a second (I call that an 'escape').

That sketch is too long for you. That is what happens if millis-timers are used and the sketch is fully stretched out with straightforward code.
I think that a Finite State Machine with a state for each step is the best solution. It will be easy to change the behavior of each step if needed.