4141import stat
4242import time
4343import errno
44+ import evdev
4445from os .path import abspath
4546from struct import pack , unpack
4647from subprocess import Popen , check_output , PIPE
@@ -137,6 +138,7 @@ def matches(attribute, pattern):
137138 if all ([matches (path + '/' + k , kwargs [k ]) for k in kwargs ]):
138139 yield f
139140
141+
140142# -----------------------------------------------------------------------------
141143# Define the base class from which all other ev3dev classes are defined.
142144
@@ -205,8 +207,8 @@ def __str__(self):
205207 else :
206208 return self .__class__ .__name__
207209
208- def _attribute_file_open ( self , name ):
209- path = self ._path + '/' + name
210+ def _attribute_file_open (self , name ):
211+ path = os . path . join ( self ._path , name )
210212 mode = stat .S_IMODE (os .stat (path )[stat .ST_MODE ])
211213 r_ok = mode & stat .S_IRGRP
212214 w_ok = mode & stat .S_IWGRP
@@ -2245,8 +2247,6 @@ class TouchSensor(Sensor):
22452247 Touch Sensor
22462248 """
22472249
2248- __slots__ = ['_poll' , '_value0' ]
2249-
22502250 SYSTEM_CLASS_NAME = Sensor .SYSTEM_CLASS_NAME
22512251 SYSTEM_DEVICE_NAME_CONVENTION = Sensor .SYSTEM_DEVICE_NAME_CONVENTION
22522252
@@ -2256,8 +2256,6 @@ class TouchSensor(Sensor):
22562256
22572257 def __init__ (self , address = None , name_pattern = SYSTEM_DEVICE_NAME_CONVENTION , name_exact = False , ** kwargs ):
22582258 super (TouchSensor , self ).__init__ (address , name_pattern , name_exact , driver_name = ['lego-ev3-touch' , 'lego-nxt-touch' ], ** kwargs )
2259- self ._poll = None
2260- self ._value0 = None
22612259
22622260 @property
22632261 def is_pressed (self ):
@@ -2272,40 +2270,42 @@ def is_pressed(self):
22722270 def is_released (self ):
22732271 return not self .is_pressed
22742272
2275- def _wait (self , wait_for_press , timeout_ms ):
2273+ def _wait (self , wait_for_press , timeout_ms , sleep_ms ):
22762274 tic = time .time ()
22772275
2278- if self ._poll is None :
2279- self ._value0 = self ._attribute_file_open ('value0' )
2280- self ._poll = select .poll ()
2281- self ._poll .register (self ._value0 , select .POLLPRI )
2276+ if sleep_ms :
2277+ sleep_ms = float (sleep_ms / 1000 )
22822278
2279+ # The kernel does not supoort POLLPRI or POLLIN for sensors so we have
2280+ # to drop into a loop and check often
22832281 while True :
2284- self ._poll .poll (timeout_ms )
22852282
22862283 if self .is_pressed == wait_for_press :
22872284 return True
22882285
22892286 if timeout_ms is not None and time .time () >= tic + timeout_ms / 1000 :
22902287 return False
22912288
2292- def wait_for_pressed (self , timeout_ms = None ):
2293- return self ._wait (True , timeout_ms )
2289+ if sleep_ms :
2290+ time .sleep (sleep_ms )
2291+
2292+ def wait_for_pressed (self , timeout_ms = None , sleep_ms = 10 ):
2293+ return self ._wait (True , timeout_ms , sleep_ms )
22942294
2295- def wait_for_released (self , timeout_ms = None ):
2296- return self ._wait (False , timeout_ms )
2295+ def wait_for_released (self , timeout_ms = None , sleep_ms = 10 ):
2296+ return self ._wait (False , timeout_ms , sleep_ms )
22972297
2298- def wait_for_bump (self , timeout_ms = None ):
2298+ def wait_for_bump (self , timeout_ms = None , sleep_ms = 10 ):
22992299 """
23002300 Wait for the touch sensor to be pressed down and then released.
23012301 Both actions must happen within timeout_ms.
23022302 """
23032303 start_time = time .time ()
23042304
2305- if self .wait_for_pressed (timeout_ms ):
2305+ if self .wait_for_pressed (timeout_ms , sleep_ms ):
23062306 if timeout_ms is not None :
23072307 timeout_ms -= int ((time .time () - start_time ) * 1000 )
2308- return self .wait_for_released (timeout_ms )
2308+ return self .wait_for_released (timeout_ms , sleep_ms )
23092309
23102310 return False
23112311
@@ -2629,6 +2629,8 @@ class ButtonBase(object):
26292629 Abstract button interface.
26302630 """
26312631
2632+ _state = set ([])
2633+
26322634 def __str__ (self ):
26332635 return self .__class__ .__name__
26342636
@@ -2641,8 +2643,6 @@ def on_change(changed_buttons):
26412643 """
26422644 pass
26432645
2644- _state = set ([])
2645-
26462646 def any (self ):
26472647 """
26482648 Checks if any button is pressed.
@@ -2655,6 +2655,19 @@ def check_buttons(self, buttons=[]):
26552655 """
26562656 return set (self .buttons_pressed ) == set (buttons )
26572657
2658+ @property
2659+ def evdev_device (self ):
2660+ """
2661+ Return our corresponding evdev device object
2662+ """
2663+ devices = [evdev .InputDevice (fn ) for fn in evdev .list_devices ()]
2664+
2665+ for device in devices :
2666+ if device .name == self .evdev_device_name :
2667+ return device
2668+
2669+ raise Exception ("%s: could not find evdev device '%s'" % (self , self .evdev_device_name ))
2670+
26582671 def process (self , new_state = None ):
26592672 """
26602673 Check for currenly pressed buttons. If the new state differs from the
@@ -2673,10 +2686,69 @@ def process(self, new_state=None):
26732686 if self .on_change is not None and state_diff :
26742687 self .on_change ([(button , button in new_state ) for button in state_diff ])
26752688
2689+ def process_forever (self ):
2690+ for event in self .evdev_device .read_loop ():
2691+ if event .type == evdev .ecodes .EV_KEY :
2692+ self .process ()
2693+
26762694 @property
26772695 def buttons_pressed (self ):
26782696 raise NotImplementedError ()
26792697
2698+ def _wait (self , wait_for_button_press , wait_for_button_release , timeout_ms ):
2699+ tic = time .time ()
2700+
2701+ # wait_for_button_press/release can be a list of buttons or a string
2702+ # with the name of a single button. If it is a string of a single
2703+ # button convert that to a list.
2704+ if isinstance (wait_for_button_press , str ):
2705+ wait_for_button_press = [wait_for_button_press , ]
2706+
2707+ if isinstance (wait_for_button_release , str ):
2708+ wait_for_button_release = [wait_for_button_release , ]
2709+
2710+ for event in self .evdev_device .read_loop ():
2711+ if event .type == evdev .ecodes .EV_KEY :
2712+ all_pressed = True
2713+ all_released = True
2714+ pressed = self .buttons_pressed
2715+
2716+ for button in wait_for_button_press :
2717+ if button not in pressed :
2718+ all_pressed = False
2719+ break
2720+
2721+ for button in wait_for_button_release :
2722+ if button in pressed :
2723+ all_released = False
2724+ break
2725+
2726+ if all_pressed and all_released :
2727+ return True
2728+
2729+ if timeout_ms is not None and time .time () >= tic + timeout_ms / 1000 :
2730+ return False
2731+
2732+ def wait_for_pressed (self , buttons , timeout_ms = None ):
2733+ return self ._wait (buttons , [], timeout_ms )
2734+
2735+ def wait_for_released (self , buttons , timeout_ms = None ):
2736+ return self ._wait ([], buttons , timeout_ms )
2737+
2738+ def wait_for_bump (self , buttons , timeout_ms = None ):
2739+ """
2740+ Wait for the button to be pressed down and then released.
2741+ Both actions must happen within timeout_ms.
2742+ """
2743+ start_time = time .time ()
2744+
2745+ if self .wait_for_pressed (buttons , timeout_ms ):
2746+ if timeout_ms is not None :
2747+ timeout_ms -= int ((time .time () - start_time ) * 1000 )
2748+ return self .wait_for_released (buttons , timeout_ms )
2749+
2750+ return False
2751+
26802752
26812753class InfraredSensor (Sensor , ButtonBase ):
26822754 """
@@ -3141,8 +3213,10 @@ class ButtonEVIO(ButtonBase):
31413213 _buttons = {}
31423214
31433215 def __init__ (self ):
3216+ ButtonBase .__init__ (self )
31443217 self ._file_cache = {}
31453218 self ._buffer_cache = {}
3219+
31463220 for b in self ._buttons :
31473221 name = self ._buttons [b ]['name' ]
31483222 if name not in self ._file_cache :
@@ -3167,8 +3241,10 @@ def buttons_pressed(self):
31673241 for k , v in self ._buttons .items ():
31683242 buf = self ._buffer_cache [v ['name' ]]
31693243 bit = v ['value' ]
3244+
31703245 if bool (buf [int (bit / 8 )] & 1 << bit % 8 ):
3171- pressed += [k ]
3246+ pressed .append (k )
3247+
31723248 return pressed
31733249
31743250
0 commit comments