Module Button
[frames] | no frames]

Source Code for Module Button

  1  # Button.py 
  2   
  3  ''' 
  4  Class that represents a push button on some GPIO port. 
  5   
  6   
  7   This software is part of the raspibrickpi module. 
  8   It is Open Source Free Software, so you may 
  9   - run the code for any purpose 
 10   - study how the code works and adapt it to your needs 
 11   - integrate all or parts of the code in your own programs 
 12   - redistribute copies of the code777 
 13   - improve the code and release your improvements to the public 
 14   However the use of the code is entirely your responsibility. 
 15  ''' 
 16   
 17  import RPi.GPIO as GPIO 
 18  import time 
 19  from threading import Thread 
 20   
 21  DEBUG = False 
 22   
 23  # Button event constants 
 24  BUTTON_PRESSED = 1 
 25  BUTTON_RELEASED = 2 
 26  BUTTON_LONGPRESSED = 3 
 27  BUTTON_CLICKED = 4 
 28  BUTTON_DOUBLECLICKED = 5 
 29  BUTTON_LONGPRESS_DURATION = 2 # default (in s) the button must be pressed to be a long press 
 30  BUTTON_DOUBLECLICK_TIME = 1 # default time (in s) to wait for a double click event 
 31   
32 -class _ClickThread(Thread):
33 - def __init__(self, button):
34 Thread.__init__(self) 35 self.button = button 36 self.start()
37
38 - def run(self):
39 if DEBUG: 40 print "===>ClickThread started" 41 self.isRunning = True 42 startTime = time.time() 43 while self.isRunning and (time.time() - startTime < BUTTON_DOUBLECLICK_TIME): 44 time.sleep(0.1) 45 if self.button.clickCount == 1 and not self.button.isLongPressEvent: 46 if self.button.xButtonListener != None: 47 self.button.xButtonListener(self.button, BUTTON_CLICKED) 48 self.button.clickThread = None 49 self.isRunning = False 50 if DEBUG: 51 print "===>ClickThread terminated"
52
53 - def stop(self):
54 self.isRunning = False
55
56 -class _ButtonThread(Thread):
57 - def __init__(self, button):
58 Thread.__init__(self) 59 self.button = button 60 self.isRunning = False
61
62 - def run(self):
63 if DEBUG: 64 print "===>ButtonThread started" 65 self.isRunning = True 66 startTime = time.time() 67 while self.isRunning and (time.time() - startTime < BUTTON_LONGPRESS_DURATION): 68 time.sleep(0.1) 69 if self.isRunning: 70 if self.button.buttonListener != None: 71 self.button.buttonListener(BUTTON_LONGPRESSED) 72 if DEBUG: 73 print "===>ButtonThread terminated"
74
75 - def stop(self):
76 self.isRunning = False
77
78 -class Button():
79 GPIO.setmode(GPIO.BOARD) 80 pinsEnabled = []
81 - def __init__(self, pin, enable = True):
82 ''' 83 Creates a button instance at given pin. If enable = True, the button events are immediately enabled; 84 otherwise they must be enabled by calling setEnable(True). 85 ''' 86 self._isButtonEnabled = enable 87 self.pin = pin 88 GPIO.setup(pin, GPIO.IN, GPIO.PUD_UP) 89 if not pin in Button.pinsEnabled: 90 GPIO.add_event_detect(pin, GPIO.BOTH, self._onButtonEvent) 91 Button.pinsEnabled.append(pin) 92 else: 93 GPIO.remove_event_detect(pin) 94 GPIO.add_event_detect(pin, GPIO.BOTH, self._onButtonEvent) 95 self.buttonThread = None 96 self.clickThread = None 97 self._inCallback = False
98
99 - def addXButtonListener(self, listener):
100 ''' 101 Registers a listener function to get notifications when the pushbutton is pressed, released, clicked, 102 double-clicked or long pressed. Sequences are: 103 click: BUTTON_PRESSED, BUTTON_RELEASED, BUTTON_CLICKED 104 double-click: BUTTON_PRESSED, BUTTON_RELEASED, BUTTON_PRESSED, BUTTON_RELEASED, BUTTON_DOUBLECLICKED 105 long pressed: BUTTON_PRESSED, BUTTON_LONGPRESSED, BUTTON_RELEASED 106 @param listener: the listener function (with integer parameter event) to register. 107 ''' 108 self.addButtonListener(self._onXButtonEvent) 109 self.xButtonListener = listener
110
111 - def addButtonListener(self, listener):
112 ''' 113 Registers a listener function to get notifications when the pushbutton is pressed and released. 114 @param listener: the listener function (with integer parameter event) to register. 115 ''' 116 self.buttonListener = listener
117 118 # Hardware callback
119 - def _onButtonEvent(self, channel):
120 if not self._isButtonEnabled: 121 return 122 if self._inCallback: # inhibit reentrance 123 return 124 self._inCallback = True 125 # switch may bounce: down-up-up, down-up-down, down-down-up etc. in fast sequence 126 if GPIO.input(self.pin) == GPIO.LOW: 127 if self.buttonThread == None: # down-down is suppressed 128 if DEBUG: 129 print "->ButtonDown" 130 self.buttonThread = _ButtonThread(self) 131 self.buttonThread.start() 132 if self.buttonListener != None: 133 self.buttonListener(self, BUTTON_PRESSED) 134 else: 135 if self.buttonThread != None: # up-up is suppressed 136 if DEBUG: 137 print "->ButtonUp" 138 self.buttonThread.stop() 139 self.buttonThread.join(200) # wait until finished 140 self.buttonThread = None 141 if self.buttonListener != None: 142 self.buttonListener(self, BUTTON_RELEASED) 143 self._inCallback = False
144
145 - def _onXButtonEvent(self, btn, event):
146 if event == BUTTON_PRESSED: 147 if self.xButtonListener != None: 148 self.xButtonListener(btn, BUTTON_PRESSED) 149 self.isLongPressEvent = False 150 if self.clickThread == None: 151 self.clickCount = 0 152 self.clickThread = _ClickThread(self) 153 154 elif event == BUTTON_RELEASED: 155 if self.xButtonListener != None: 156 self.xButtonListener(btn, BUTTON_RELEASED) 157 if self.isLongPressEvent and self.clickThread != None: 158 self.clickThread.stop() 159 self.clickThread = None 160 return 161 if self.clickThread != None and self.clickThread.isRunning: 162 self.clickCount += 1 163 if self.clickCount == 2: 164 self.clickThread.stop() 165 self.clickThread = None 166 if self.xButtonListener != None: 167 self.xButtonListener(btn, BUTTON_DOUBLECLICKED) 168 else: 169 self.clickThread = None 170 171 elif event == BUTTON_LONGPRESSED: 172 self.isLongPressEvent = True 173 if self.xButtonListener != None: 174 self.xButtonListener(btn, BUTTON_LONGPRESSED)
175
176 - def setEnable(self, enable):
177 ''' 178 Enables/disables the button events. 179 ''' 180 self._isButtonEnabled = enable
181