Short and Long button press

Btw henrygab. i did successfully implement the Debounce function above and had it working great. I started having some weirdness when implementing the state machine and transitions, but now i am taking a step back, because we are discussing your other recommendation of not having the IRQ directly connected to button.

We are considering a hybrid approach. (Ian’s idea)

Button triggers IRQ, IRQ starts 1ms timer. The timer uses the debounce algo, and re-enables button IRQ when done.

he already wrote some pseudo-code i am reviewing, but will probably be a bit until i get to it fully.

2 Likes

This is rough, just back of napkin:

bool debounce_switch() {
       debounce_state_history =
        (debounce_state_history << 1) |  // make room in the history
        !button_get(0) |  // one bit, unless button is pressed
        DEBOUNCE_STATE_MASK;
    return (debounce_state_history == DEBOUNCE_STATE_MASK);
}
// timer callback function for button debouncing
// we're sampling the button pin. we're looking at 7 regions:
// XXXX->T1(H)->XXX->T2(L)->XXXX->T3(H)->XXX
// DEB    HIGH  DEB  LOW   DEB  HIGH  DEB
bool button_timer_callback(struct repeating_timer *t) {
    static uint8_t current_state=0;
    uint32_t t1,t2,t3;

    //this is to demo without wrapping it up too much,
    //but the statemachine is probably not needed
    // if we use const array to store the states and the time
    // const uint8_t t[3];
    // const uint8_t states[]={1,0,1,0}; //for debounce switch, or just bool pin_state!=pin_state to flip 1 to 0
    //const uint32_t timeouts[3]={MAX_BUTT_TIME,MAX_BETWEEN_BUTT_TIME,MAX_BUTT_TIME};
    // ALSO: this is missing the ability to bail if we're happy we already know the press type
    // ALSO: t2 is probably not needed, we can bail if we find press or error
    switch(current_state){
        case 0: //IDLE, debounce
            if(debounce_switch(1)){
                current_state++;//update debounce to look for 12 x LOW or 12 X HIGH
                t1=t2=t3=0;
                t1=12; //because we have 12 cycles?
            }
            break;
        case 1: //HIGH, count how many ms
            if(debounce_switch(0)){ //count until we debounce low
                current_state++; //low, change state
            }else{
                t1++;
                if(t1>MAX_BUTT_TIME) current_state=0; //timeout, button pressed too long. maybe there's something on top of it
            }
            break;
        case 2: //LOW, count how many ms
            if(debounce_switch(1)){ //now count wuntil button debounce high again
                current_state++;
            }else{
                t2++;
                //NOTE advance to state 4 on timeout
                if(t2>MAX_BETWEEN_BUTT_TIME) current_state=4; //timeout, single press, process it
            }
            break;
        case 3: //HIGH, count how many ms
            if(debounce_switch(0)){ //now count until button debounce low again
                current_state++; //state 4 is done 
            }else{
                t3++;
                if(t3>MAX_BUTT_TIME) current_state=0; //timeout, button pressed too long. maybe there's something on top of it
            }
            break;
    }

    //ok, now we have our timers
    if(current_state==4){ //THIS COULD BE part of the switch, but I think the switch can be rolled into a loop
        uint8_t press_type=BP_BUTT_NO_PRESS_MASK; //0b0;

        //TODO: use masks for the push types
        // none=0b00, short=0b01, long=0b10

        if(t1> SHORT_PRESS_MIN && t1<SHORT_PRESS_MAX){ //or <LONG_PRESS_MIN? probaly good to have padding instead
            press_type=BP_BUTT_SHORT_PRESS_MASK;
        }else if(t1>LONG_PRESS_MIN && t1<LONG_PRESS_MAX){
            press_type=BP_BUTT_LONG_PRESS_MASK;
        }else{
            //error??
        }
        //press_type = 0bxxxx3311 last four bits encode the press type
        if(t3>SHORT_PRESS_MIN && t3<SHORT_PRESS_MAX){
            press_type|=(BP_BUTT_SHORT_PRESS_MASK<<2);
        }else if(t3>LONG_PRESS_MIN && t3<LONG_PRESS_MAX){
            press_type|=(BP_BUTT_LONG_PRESS_MASK<<2);
        }else{
            //error??
        }
        current_state=0; //reset state
//disable timer      
//set button press flag
//reenable the PIN IRQ
  
    }

}

// example irq callback handler, copy for your own uses
void button_irq_callback(uint gpio, uint32_t events){
    gpio_acknowledge_irq(gpio, events);
    //disable pin IRQ
    gpio_set_irq_enabled(gpio, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false);
    //start 1ms timer
    add_repeating_timer_ms(1, button_timer_callback, NULL, &button_timer);
}```

Bit of a mess.