Source code for grove.button.button_gpio

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# The MIT License (MIT)
#
# Grove Base Hat for the Raspberry Pi, used to connect grove sensors.
# Copyright (C) 2018  Seeed Technology Co.,Ltd. 
#
'''
 This is the code for GPIO Button event detection.
'''
from __future__ import division
import time
import threading
from grove.button import Button
from grove.gpio import GPIO

__all__ = ["ButtonTypedGpio"]

_CYCLE_PERIOD    = 0.02   # 20 ms
_SINGLE_KEY_TM   = 0.03   # 30 ms
_KEY_INTERVAL    = 0.3    # 300 ms
_LONG_KEY_TM     = 2.0    # 2s

[docs] class ButtonTypedGpio(Button): ''' GPIO Button Class provide event checking ability to derived class, should not use directly by end-user. The checking events include: - Button.EV_SINGLE_CLICK - Button.EV_DOUBLE_CLICK - Button.EV_LONG_PRESS - Button.EV_LEVEL_CHANGED Args: pin(int) : GPIO pin number the button connected. low_pressed(bool): optional, default True True if the the button gpio level is low when pressed. False if level high when pressed ''' # all key states in FSM KEY_STATE_IDLE = 0 KEY_STATE_DOWN = 1 KEY_STATE_ONESHOT = 2 KEY_STATE_LONG = 3 def __init__(self, pin, low_pressed = True): super(ButtonTypedGpio, self).__init__(pin) self.__low_press = low_pressed self.__state = self.KEY_STATE_IDLE self.__duration = 0.0 self.__distance = _KEY_INTERVAL self.__thrd_exit = False self.__thrd = None self.__gpio = GPIO(pin, GPIO.IN) self.__gpio.on_event = self.__gpio_event if self.__thrd is None or not self.__thrd.is_alive(): self.__thrd = threading.Thread( \ target = ButtonTypedGpio.__thrd_chk_evt, \ args = (self,)) self.__thrd.setDaemon(True) self.__thrd.start() def __del__(self): self.__thrd_exit = True while self.__thrd.isAlive(): time.sleep(_CYCLE_PERIOD / _CYCLE_UNIT) self.__thrd.join()
[docs] def is_pressed(self, index = 0): ''' Get the button status if it's being pressed ? Args: index(int): optional, the arg `index` not be used. Returns: (bool): True if the button is being pressed. False if not. ''' v = self.__gpio.read() return self.__low_press != bool(v)
# called by GPIO library def __gpio_event(self, pin, value): press = self.is_pressed() tm = time.time() self._send_event(self.EV_LEVEL_CHANGED, press, tm) # key event FSM(finite state machine) def __key_evt_fsm(self, dt): r = 0 press = self.is_pressed() self.__distance = self.__distance + dt if self.__state == self.KEY_STATE_IDLE: if press: self.__duration = 0.0 self.__state = self.KEY_STATE_DOWN elif self.__state == self.KEY_STATE_DOWN: if press: self.__duration = self.__duration + dt if self.__duration >= _SINGLE_KEY_TM: self.__state = self.KEY_STATE_ONESHOT elif self.__state == self.KEY_STATE_ONESHOT: if not press: # print("distance {}".format(self.__distance)) if self.__distance >= _KEY_INTERVAL: r = self.EV_SINGLE_CLICK else: r = self.EV_DOUBLE_CLICK else: self.__duration = self.__duration + dt # print("duration {}".format(self.__duration)) if self.__duration >= _LONG_KEY_TM: r = self.EV_LONG_PRESS self.__state = self.KEY_STATE_LONG elif self.__state == self.KEY_STATE_LONG: if not press: self.__distance = _KEY_INTERVAL if not press: self.__state = self.KEY_STATE_IDLE if r == self.EV_DOUBLE_CLICK: self.__distance = _KEY_INTERVAL elif r == self.EV_SINGLE_CLICK: self.__distance = 0.0 return r, press # Thread to check events def __thrd_chk_evt(self): ''' # prevent dither time.sleep(0.01) v = self.__gpio.read() if self.__low_press == bool(v): return ''' self.__last_time = time.time(); while not self.__thrd_exit: # or self.__state != self.KEY_STATE_IDLE: t = time.time() dt, self.__last_time = t - self.__last_time, t r, pressed = self.__key_evt_fsm(dt) if r: self._send_event(r, pressed, t) time.sleep(_CYCLE_PERIOD)