Implementation of a button class and test program

Button.hpp

Committer:
JMF
Date:
2018-09-07
Revision:
1:c668e9604e63
Parent:
0:377a50b631cf

File content as of revision 1:c668e9604e63:

/**
* copyright (c) 2018, James Flynn
* SPDX-License-Identifier: MIT
*/

/**
*   @file   button.hpp
*   @brief  A small BUTTON class for detecting & debouncing button preesses
*
*   @author James Flynn
*
*   @date   24-Aug-2018
*/

#include "mbed.h"

#define BUTTON_DEBOUNCE           20     //specify the number of msec to debounce

class Button {
    protected:
        InterruptIn user_button;
        void (*br_cb)(int);    //button release callback
        void (*bp_cb)(void);   //button press callback

        Thread      *button_thread;
        void        button_monitor_task(void);
        EventQueue  button_queue;
        uint64_t    bp_time, bp_duration;  //button press start time and button press duration
        int         button_pressed;        //counts the number of times the button has been pressed

        void button_press_handler(void) {
            if( (rtos::Kernel::get_ms_count() - bp_time) < BUTTON_DEBOUNCE)
                return;
            bp_time = rtos::Kernel::get_ms_count();
            if( bp_cb )
                bp_cb();
        }

        void button_release_handler(void) {
            uint64_t tmp = rtos::Kernel::get_ms_count() - bp_time;
            if( tmp > BUTTON_DEBOUNCE ) {
                bp_duration = tmp;
                button_pressed++;
                if( br_cb )
                  br_cb(bp_duration);
                }
        }

    public:
        enum State { ActiveHigh = 0, ActiveLow };

        Button(PinName p, State s, void (*cb)(int)=NULL) : 
            user_button(p),
            br_cb(cb),
            bp_cb(NULL),
            bp_time(0),
            bp_duration(0),
            button_pressed(0)
            {
            // The user button is setup for the edge to generate an interrupt. 
            // The release is caught an event queue callback
            button_thread=new Thread(osPriorityNormal,256,NULL,"button_thread");
            button_thread->start(callback(&button_queue, &EventQueue::dispatch_forever));
            if( s == ActiveHigh ) {
                user_button.rise( Callback<void()>(this, &Button::button_press_handler) ); 
                user_button.fall( button_queue.event( Callback<void()>(this, &Button::button_release_handler)));
                }
            else{
                user_button.fall( Callback<void()>(this, &Button::button_press_handler) );
                user_button.rise(button_queue.event(Callback<void()>(this, &Button::button_release_handler)));
                }
            }

        ~Button() {
            button_thread->terminate();
            delete button_thread;
            }

        // will return the number of times the button has been pressed (if it was pressed > 1 time before checked)
        // and returns the duration of the last button press in duration
        int chkButton_press(int *duration) {
            int bp = button_pressed;
        
            if( button_pressed ) {
                *duration = bp_duration;
                bp_duration = 0;
                button_pressed = 0;
                }
            return bp;
            }
            
        //allows the user to set a callback for a button press in
        void setButton_press_cb( void (*buttonpresscb)(void) ) {
            bp_cb = buttonpresscb;
            }
};