Wilmer
Wilmer
. 11 min read

Implementation of the BUTTON Class for BeagleBone Black

Implementation of the BUTTON Class for BeagleBone Black

In this post, I show a Button C++ class implementation in order to read an attached button to a GPIO pin in the BeagleBone Black. The public methods written in the C++ class BUTTON are:

  • int ReadButton()
  • int WaitForButton()
  • int WaitForButton(int)
  • int WhenButtonWasPressed(callbackType)
  • void StopWaitForButton()

The int ReadButton() method checks that the GPIO has been set up as INPUT and returns the value of the pin that is attached to the button. This is done through a call to the DigitalRead() method of the GPIO class.

The int WaitForButton() first checks if the GPIO attached to a button has been set up as INPUT and then wait until the button has changed from a LOW state to a HIGH state. This means the button has been pressed.

The int WaitForButton(int) is an overload method, its receives one of the next types of transition on the pin:

  • RISING
  • FALLING
  • BOTH

The int WhenButtonWasPressed(callbackType) method, receives a user customized function when the button has been pressed and creates a thread with a function pointer to that function which is executed in a parallel way to the main function in the program. In this user customized function any other methods of the class can be called, for example: WaitForButton() without affect the behavior of the main function.

The void StopWaitForButton() controls the execution of the WaitForButton() method. This is done through the bool member variable stopWaitForButtonFlag that can be set with a the right timing to stop that method.

Code

BUTTON.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#ifndef BUTTON_H
#define BUTTON_H

#include <thread>
#include "GPIO.h"

/* 
  Declare a type for a function pointer
  It is the construct for: using function_type = int (*) ()
    function_type:  the function name
    int: return type  
    (*): the dereference operator due to the adddress of the function name
    (): the arguments of the function, in this case void
  Stores the address of a function 
*/
using callbackType = int (*)();

class BUTTON : public GPIO
{
  private:
    int valueOnPin;
    int previousValueOnPin; 
    bool stopWaitForButtonFlag = false;

    std::thread whenButtonWasPressedThread; 

  public:
    // Overload constructor
    BUTTON(int);

    // Interface method to get the GPIO pin state
    virtual int ReadButton();

    // Method for wait for a press on a button with default rising edge
    virtual int WaitForButton();

    // Overloaded Method for wait for a press on a button with an Edge
    virtual int WaitForButton(int);

    // Method to do execute an user function when the button will be pressed
    virtual int WhenButtonWasPressed(callbackType);

    // Method to stop the function executed whe the button was pressed
    virtual void StopWaitForButton(bool);

    // Destructor
    ~BUTTON();
};

#endif // BUTTON_H

BUTTON.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#include <iostream>
#include <chrono>
#include <thread>

#include "BUTTON.h"

// Overload constructor
BUTTON::BUTTON(int newId) : GPIO(newId, INPUT) {}

/*
    Public method for reading the input from a button
    @return int:   The button state HIGH / LOW
                  -1 Error in the pin's mode
*/
int BUTTON::ReadButton()
{
    if (this->mode != INPUT)
    {
        perror("'ReadButton' method only works on INPUT mode");
        return -1;
    }
    valueOnPin = this->DigitalRead();
    return valueOnPin;
}

/*
    Public method for waiting a rising edge on the press of a button
    @return int:   1 The button was pressed
                  0 The button was not pressed
                  -1 Error in the pin's mode
*/
int BUTTON::WaitForButton()
{
  if (this->mode != INPUT)
  {
    perror("'waitForButton' method only works on INPUT mode");
    return -1;
  }
  string message;

  WriteFile(path, "edge", "rising");
  while (stopWaitForButtonFlag == false)
  {
    previousValueOnPin = ReadButton(); 
    if (previousValueOnPin == LOW)
      break; 
  }
  while (stopWaitForButtonFlag == false)
  {
    if (ReadButton() == HIGH)
      break; 
  }
  if (previousValueOnPin != valueOnPin)
  {
    message = "A RISING edge was detected!";
    cout << RainbowText(message, "Pink") << endl;
    return 1;
  }
  return 0;
}

/*
  Public overloaded method for waiting a specific type edge on the press of a button
  @param int: The desired edge type RISING / FALLING / BOTH
  @return int:  1 The button was pressed
                0 The button was not pressed
                -1 Error in the pin's mode
*/
int BUTTON::WaitForButton(int edge = RISING)
{
  if (this->mode != INPUT)
  {
    perror("'waitForButton' method only works on INPUT mode");
    return -1;
  }
  string message;
  switch (edge)
  {
  case RISING:
    WriteFile(path, "edge", "rising");
    while (stopWaitForButtonFlag == false)
    {
      previousValueOnPin = ReadButton(); 
      if (previousValueOnPin == LOW)
        break; 
    }
    while (stopWaitForButtonFlag == false)
    {
      if (ReadButton() == HIGH)
        break; 
    }
    if (previousValueOnPin != valueOnPin)
    {
      message = "A RISING edge was detected!";
      cout << RainbowText(message, "Pink") << endl;
      return 1;
    }
    break;
  case FALLING:
    WriteFile(path, "edge", "falling");
    while (stopWaitForButtonFlag == false)
    {
      previousValueOnPin = ReadButton(); 
      if (previousValueOnPin == HIGH)
        break; 
    }
    while (stopWaitForButtonFlag == false)
    {
      if (ReadButton() == LOW)
        break; 
    }
    if (previousValueOnPin != valueOnPin)
    {
      message = "A FALLING edge was detected!";
      cout << RainbowText(message, "Pink") << endl;
      return 1;
    }
    break;
  case BOTH:
    WriteFile(path, "edge", "both");
    previousValueOnPin = ReadButton();
    while (stopWaitForButtonFlag == false)
    {
      if (previousValueOnPin != ReadButton())
      {
        message = "A RISING OR FALLING edge was detected!";
        cout << RainbowText(message, "Yellow") << endl;
        return 1;
      }
    }
    break;
  }
  return 0;
}

/*
    Public callback method to do something when a button will be pressed
    @param callbackType: user function to execute
    @return int: 1 the user function was called
                -1 Error in the pin's mode
*/
int BUTTON::WhenButtonWasPressed(callbackType callbackFunction)
{
  if (this->mode != INPUT)
  {
    perror("'waitForButton' method only works on INPUT mode");
    return -1;
  }

  string message = "'WhenButtonWasPressed' method has been activated!!!";
  cout << RainbowText(message, "Orange") << endl;

  whenButtonWasPressedThread = thread(callbackFunction);

  return 1;
}

/*
    Public method to stop function executed whe the button was pressed
    @param bool: Flag to stop the thread
*/
void BUTTON::StopWaitForButton()
{
  stopWaitForButtonFlag = true;
}

// Destructor
BUTTON::~BUTTON()
{
  if (whenButtonWasPressedThread.joinable())
    whenButtonWasPressedThread.join();
}

Se you in the next post.

Rating:
comments powered by Disqus