Skip to content

Commit 0bd0033

Browse files
committed
Extract ButtonBase class, move RemoteControl specifics into spec.json
1 parent 1763dc9 commit 0bd0033

File tree

4 files changed

+137
-89
lines changed

4 files changed

+137
-89
lines changed

ev3dev.py

Lines changed: 99 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1761,12 +1761,48 @@ def Led_all_off():
17611761

17621762

17631763
#~autogen
1764-
#~autogen button-class classes.button>currentClass
17651764

1766-
import fcntl
1767-
import array
1765+
class ButtonBase(object):
1766+
"""
1767+
Abstract button interface.
1768+
"""
1769+
1770+
on_change = None
1771+
1772+
_state = set([])
1773+
1774+
@property
1775+
def any(self):
1776+
"""
1777+
Checks if any button is pressed.
1778+
"""
1779+
return bool(self.buttons_pressed)
17681780

1769-
class Button(object):
1781+
def check_buttons(self,buttons=[]):
1782+
"""
1783+
Check if currently pressed buttons exactly match the given list.
1784+
"""
1785+
return set(self.buttons_pressed) == set(buttons)
1786+
1787+
def process(self):
1788+
"""
1789+
Check for currenly pressed buttons. If the new state differs from the
1790+
old state, call the appropriate button event handlers.
1791+
"""
1792+
new_state = set(self.buttons_pressed)
1793+
old_state = self._state
1794+
self._state = new_state
1795+
1796+
state_diff = new_state.symmetric_difference(old_state)
1797+
for button in state_diff:
1798+
handler = getattr(self, 'on_' + button)
1799+
if handler is not None: handler(button in new_state)
1800+
1801+
if self.on_change is not None and state_diff:
1802+
self.on_change([(button, button in new_state) for button in state_diff])
1803+
1804+
#~autogen button-class classes.button>currentClass
1805+
class Button(ButtonBase):
17701806

17711807
"""
17721808
Provides a generic button reading mechanism that can be adapted
@@ -1805,31 +1841,30 @@ def _button_buffer(self, name):
18051841
self.buffer_cache[name] = array.array( 'B', [0] * self.KEY_BUF_LEN )
18061842
return self.buffer_cache[name]
18071843

1808-
def read_buttons(self):
1844+
@property
1845+
def buttons_pressed(self):
18091846
for b in self.buffer_cache:
18101847
fcntl.ioctl(self.filehandle_cache[b], self.EVIOCGKEY, self.buffer_cache[b])
18111848

1812-
@property
1813-
def buttons_pressed(self):
18141849
pressed = []
1815-
self.read_buttons()
18161850
for k,v in self._buttons.items():
18171851
buf = self.buffer_cache[v['name']]
18181852
bit = v['value']
18191853
if not bool(buf[int(bit / 8)] & 1 << bit % 8):
18201854
pressed += [k]
18211855
return pressed
18221856

1823-
@property
1824-
def any(self):
1825-
return bool(self.buttons_pressed)
1826-
1827-
def check_buttons(self,buttons=[]):
1828-
return set(self.buttons_pressed) == set(buttons)
1829-
18301857
if current_platform() == 'ev3':
18311858
#~autogen button-property platforms.ev3.button>currentClass
1832-
_buttons = {
1859+
1860+
on_up = None
1861+
on_down = None
1862+
on_left = None
1863+
on_right = None
1864+
on_enter = None
1865+
on_backspace = None
1866+
1867+
_buttons = {
18331868
'up' : { 'name': '/dev/input/by-path/platform-gpio-keys.0-event', 'value': 103 },
18341869
'down' : { 'name': '/dev/input/by-path/platform-gpio-keys.0-event', 'value': 108 },
18351870
'left' : { 'name': '/dev/input/by-path/platform-gpio-keys.0-event', 'value': 105 },
@@ -1865,108 +1900,95 @@ def backspace(self):
18651900

18661901
#~autogen
18671902

1868-
class RemoteControl(object):
1903+
#~autogen remote-control classes.infraredSensor.remoteControl>currentClass
1904+
class RemoteControl(ButtonBase):
18691905
"""
1870-
EV3 Remote Control
1906+
EV3 Remote Controller
18711907
"""
18721908

18731909
_BUTTON_VALUES = {
1874-
1: ['red_up'],
1875-
2: ['red_down'],
1876-
3: ['blue_up'],
1877-
4: ['blue_down'],
1878-
5: ['red_up', 'blue_up'],
1879-
6: ['red_up', 'blue_down'],
1880-
7: ['red_down', 'blue_up'],
1881-
8: ['red_down', 'blue_down'],
1882-
9: ['beacon'],
1883-
10: ['red_up', 'red_down'],
1884-
11: ['blue_up', 'blue_down']
1910+
0: [],
1911+
1: ['red_up'],
1912+
2: ['red_down'],
1913+
3: ['blue_up'],
1914+
4: ['blue_down'],
1915+
5: ['red_up', 'blue_up'],
1916+
6: ['red_up', 'blue_down'],
1917+
7: ['red_down', 'blue_up'],
1918+
8: ['red_down', 'blue_down'],
1919+
9: ['beacon'],
1920+
10: ['red_up', 'red_down'],
1921+
11: ['blue_up', 'blue_down']
18851922
}
18861923

1887-
on_red_up = None
1888-
on_red_down = None
1889-
on_blue_up = None
1924+
on_red_up = None
1925+
on_red_down = None
1926+
on_blue_up = None
18901927
on_blue_down = None
1891-
on_beacon = None
1892-
on_change = None
1928+
on_beacon = None
18931929

1894-
def __init__(self, sensor=None, channel=1):
1895-
if sensor is None:
1896-
self._sensor = InfraredSensor()
1897-
else:
1898-
self._sensor = sensor
1899-
1900-
self._channel = max(1, min(4, channel)) - 1
1901-
self._state = set([])
1902-
1903-
if self._sensor.connected:
1904-
self._sensor.mode = 'IR-REMOTE'
1905-
1906-
@property
1907-
def buttons_pressed(self):
1908-
"""
1909-
Returns list of currently pressed buttons.
1910-
"""
1911-
return RemoteControl._BUTTON_VALUES.get(self._sensor.value(self._channel), [])
1912-
1913-
@property
1914-
def any(self):
1915-
"""
1916-
Checks if any button is pressed.
1917-
"""
1918-
return bool(self.buttons_pressed)
1919-
1920-
def check_buttons(self, buttons=[]):
1921-
return set(self.buttons_pressed) == set(buttons)
19221930

19231931
@property
19241932
def red_up(self):
19251933
"""
1926-
Checks if `red_up` button is pressed
1934+
Checks if `red_up` button is pressed.
19271935
"""
19281936
return 'red_up' in self.buttons_pressed
19291937

1938+
19301939
@property
19311940
def red_down(self):
19321941
"""
1933-
Checks if `red_down` button is pressed
1942+
Checks if `red_down` button is pressed.
19341943
"""
19351944
return 'red_down' in self.buttons_pressed
19361945

1946+
19371947
@property
19381948
def blue_up(self):
19391949
"""
1940-
Checks if `blue_up` button is pressed
1950+
Checks if `blue_up` button is pressed.
19411951
"""
19421952
return 'blue_up' in self.buttons_pressed
19431953

1954+
19441955
@property
19451956
def blue_down(self):
19461957
"""
1947-
Checks if `blue_down` button is pressed
1958+
Checks if `blue_down` button is pressed.
19481959
"""
19491960
return 'blue_down' in self.buttons_pressed
19501961

1962+
19511963
@property
19521964
def beacon(self):
19531965
"""
1954-
Checks if `beacon` button is pressed
1966+
Checks if `beacon` button is pressed.
19551967
"""
19561968
return 'beacon' in self.buttons_pressed
19571969

1958-
def process(self):
1959-
new_state = set(self.buttons_pressed)
1960-
old_state = self._state
1961-
self._state = new_state
19621970

1963-
state_diff = new_state.symmetric_difference(old_state)
1964-
for button in state_diff:
1965-
handler = getattr(self, 'on_' + button)
1966-
if handler is not None: handler(button in new_state)
19671971

1968-
if self.on_change is not None and state_diff:
1969-
self.on_change([(button, button in new_state) for button in state_diff])
1972+
#~autogen
1973+
1974+
def __init__(self, sensor=None, channel=1):
1975+
if sensor is None:
1976+
self._sensor = InfraredSensor()
1977+
else:
1978+
self._sensor = sensor
1979+
1980+
self._channel = max(1, min(4, channel)) - 1
1981+
self._state = set([])
1982+
1983+
if self._sensor.connected:
1984+
self._sensor.mode = 'IR-REMOTE'
1985+
1986+
@property
1987+
def buttons_pressed(self):
1988+
"""
1989+
Returns list of currently pressed buttons.
1990+
"""
1991+
return RemoteControl._BUTTON_VALUES.get(self._sensor.value(self._channel), [])
19701992

19711993
#~autogen generic-class classes.powerSupply>currentClass
19721994

templates/button-class.liquid

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
1-
{%
2-
assign class_name = currentClass.friendlyName | camel_case | capitalize %}{%
3-
assign base_class = 'object' %}
4-
import fcntl
5-
import array
6-
7-
class {{ class_name }}({{ base_class }}):
1+
class Button(ButtonBase):
82

93
"""{% for line in currentClass.description %}
104
{{ line }}{% endfor %}

templates/button-property.liquid

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
_buttons = { {%
2-
for instance in currentClass.instances %}
3-
'{{ instance.name }}' : { 'name': '{{ currentClass.systemPath }}/{{ instance.systemName }}', 'value': {{ instance.systemValue }} },{%
4-
endfor %}
5-
}
1+
{% for instance in currentClass.instances %}
2+
on_{{ instance.name }} = None{%
3+
endfor %}
4+
5+
_buttons = {
6+
{% for instance in currentClass.instances %} '{{ instance.name }}' : { 'name': '{{ currentClass.systemPath }}/{{ instance.systemName }}', 'value': {{ instance.systemValue }} },
7+
{% endfor %} }
68
{% for instance in currentClass.instances %}
79
@property
810
def {{ instance.name }}(self):

templates/remote-control.liquid

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
class RemoteControl(ButtonBase):
2+
"""{% for line in currentClass.description %}
3+
{{ line }}{% endfor %}
4+
"""
5+
6+
_BUTTON_VALUES = {
7+
{% for v in currentClass.values
8+
%} {{ v.value }}: [{%
9+
for s in v.state
10+
%}'{{ s | downcase | underscore_spaces }}'{%
11+
unless forloop.last %}, {%
12+
endunless %}{%
13+
endfor %}]{% unless forloop.last %},
14+
{% endunless %}{%
15+
endfor %}
16+
}
17+
{% for b in currentClass.buttons %}
18+
on_{{ b.name | downcase | underscore_spaces }} = None{%
19+
endfor %}
20+
21+
{% for b in currentClass.buttons %}{%
22+
assign name = b.name | downcase | underscore_spaces %}
23+
@property
24+
def {{ name }}(self):
25+
"""
26+
Checks if `{{ name }}` button is pressed.
27+
"""
28+
return '{{ name }}' in self.buttons_pressed
29+
30+
{% endfor %}

0 commit comments

Comments
 (0)