Skip to content

Commit c7e5c94

Browse files
authored
Encoder: convert get/set methods to properties, update apidoc strings
1 parent 92bd611 commit c7e5c94

File tree

1 file changed

+113
-53
lines changed

1 file changed

+113
-53
lines changed

Adafruit_BBIO/Encoder.py

Lines changed: 113 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,16 @@
1414
'Please upgrade your kernel to use this module.\n'
1515
'Your Linux kernel version is {}.'.format(platform.release()))
1616

17+
18+
# eQEP module channel identifiers
19+
# eQEP 2 and 2b are the same channel, exposed on two different sets of pins,
20+
# which are mutually exclusive
1721
eQEP0 = 0
1822
eQEP1 = 1
1923
eQEP2 = 2
2024
eQEP2b = 3
2125

26+
# Definitions to initialize the eQEP modules
2227
_OCP_PATH = "/sys/devices/platform/ocp"
2328
_eQEP_DEFS = [
2429
{'channel': 'eQEP0', 'pin_A': 'P9_92', 'pin_B': 'P9_27',
@@ -71,12 +76,31 @@ def __init__(self, channel, pin_A, pin_B, sys_path):
7176

7277

7378
class RotaryEncoder(object):
79+
'''
80+
Rotary encoder class abstraction to control a given QEP channel.
81+
82+
Constructor:
83+
eqep_num: QEP object that determines which channel to control
84+
85+
Properties:
86+
position: current position of the encoder
87+
frequency: frequency at which the encoder reports new positions
88+
enabled: (read only) true if the module is enabled, false otherwise
89+
mode: current mode of the encoder (absolute: 0, relative: 1)
90+
91+
Methods:
92+
enable: enable the QEP channel
93+
disable: disable the QEP channel
94+
setAbsolute: shortcut for setting the mode to absolute
95+
setRelative: shortcut for setting the mode to relative
96+
zero: shortcut for setting the position to 0
97+
'''
7498

7599
def _run_cmd(self, cmd):
76100
'''Runs a command. If not successful (i.e. error code different than
77101
zero), print the stderr output as a warning.
78-
'''
79102
103+
'''
80104
try:
81105
output = check_output(cmd, stderr=STDOUT)
82106
self._logger.info(
@@ -87,11 +111,8 @@ def _run_cmd(self, cmd):
87111
"_run_cmd(): cmd='{}' return code={} output={}".format(
88112
" ".join(cmd), e.returncode, e.output))
89113

90-
def config_pin(self, pin):
91-
'''
92-
config_pin()
93-
Config pin for QEP
94-
'''
114+
def _config_pin(self, pin):
115+
'''Configures a pin in QEP mode using the `config-pin` binary'''
95116

96117
self._run_cmd(["config-pin", pin, "qep"])
97118

@@ -103,8 +124,11 @@ def __init__(self, eqep_num):
103124
Allowed values: EQEP0, EQEP1, EQEP2 or EQEP2b,
104125
based on which pins the physical rotary encoder
105126
is connected to.
106-
127+
107128
'''
129+
# nanoseconds factor to convert period to frequency and back
130+
self._NS_FACTOR = 1000000000
131+
108132
# Set up logging at the module level
109133
self._logger = logging.getLogger(__name__)
110134
self._logger.addHandler(logging.NullHandler())
@@ -117,28 +141,41 @@ def __init__(self, eqep_num):
117141
self._eqep.sys_path))
118142

119143
# Configure the pins for the given channel
120-
self.config_pin(self._eqep.pin_A)
121-
self.config_pin(self._eqep.pin_B)
144+
self._config_pin(self._eqep.pin_A)
145+
self._config_pin(self._eqep.pin_B)
122146

123147
self._logger.debug(
124148
"RotaryEncoder(): sys node: {0}".format(self._eqep.sys_path))
125149

126150
# Enable the channel upon initialization
127151
self.enable()
128152

129-
def _setEnable(self, value):
153+
@property
154+
def enabled(self):
155+
'''Returns the enabled status of the module:
156+
157+
true: module is enabled
158+
false: module is disabled
159+
'''
160+
isEnabled = bool(int(self._eqep.node.enabled))
161+
162+
return isEnabled
163+
164+
def _setEnable(self, enabled):
130165
'''Turns the eQEP hardware ON or OFF
131166
132167
value (int): 1 represents enabled, 0 is disabled
168+
133169
'''
134-
if value < 0 or value > 1:
170+
enabled = int(enabled)
171+
if enabled < 0 or enabled > 1:
135172
raise ValueError(
136173
'The "enabled" attribute can only be set to 0 or 1. '
137-
'You attempted to set it to {}.'.format(value))
174+
'You attempted to set it to {}.'.format(enabled))
138175

139-
self._eqep.node.enabled = str(int(value))
176+
self._eqep.node.enabled = str(enabled)
140177
self._logger.info("Channel: {}, enabled: {}".format(
141-
self._eqep.channel, self._eqep.node.enabled))
178+
self._eqep.channel, self._eqep.node.enabled))
142179

143180
def enable(self):
144181
'''Turns the eQEP hardware ON'''
@@ -150,56 +187,59 @@ def disable(self):
150187

151188
self._setEnable(0)
152189

153-
def _setMode(self, value):
190+
@property
191+
def mode(self):
192+
'''Returns the mode the eQEP hardware is in (absolute or relative).
193+
194+
'''
195+
mode = int(self._eqep.node.mode)
196+
197+
if mode == 0:
198+
mode_name = "absolute"
199+
elif mode == 1:
200+
mode_name = "relative"
201+
else:
202+
mode_name = "invalid"
203+
204+
self._logger.debug("getMode(): Channel {}, mode: {} ({})".format(
205+
self._eqep.channel, mode, mode_name))
206+
207+
return mode
208+
209+
@mode.setter
210+
def mode(self, mode):
154211
'''Sets the eQEP mode as absolute (0) or relative (1).
155212
See the setAbsolute() and setRelative() methods for
156213
more information.
157214
158215
'''
159-
if value < 0 or value > 1:
216+
mode = int(mode)
217+
if mode < 0 or mode > 1:
160218
raise ValueError(
161219
'The "mode" attribute can only be set to 0 or 1. '
162-
'You attempted to set it to {}.'.format(value))
220+
'You attempted to set it to {}.'.format(mode))
163221

164-
self._eqep.node.mode = str(int(value))
222+
self._eqep.node.mode = str(mode)
165223
self._logger.debug("Mode set to: {}".format(
166-
self._eqep.node.mode))
224+
self._eqep.node.mode))
167225

168226
def setAbsolute(self):
169227
'''Sets the eQEP mode as Absolute:
170228
The position starts at zero and is incremented or
171229
decremented by the encoder's movement
172230
173231
'''
174-
self._setMode(0)
232+
self.mode = 0
175233

176234
def setRelative(self):
177235
'''Sets the eQEP mode as Relative:
178236
The position is reset when the unit timer overflows.
179237
180238
'''
181-
self._setMode(1)
182-
183-
def getMode(self):
184-
'''Returns the mode the eQEP hardware is in (absolute or relative).
185-
186-
'''
239+
self.mode = 1
187240

188-
mode = int(self._eqep.node.mode)
189-
190-
if mode == 0:
191-
mode_name = "absolute"
192-
elif mode == 1:
193-
mode_name = "relative"
194-
else:
195-
mode_name = "invalid"
196-
197-
self._logger.debug("getMode(): Channel {}, mode: {} ({})".format(
198-
self._eqep.channel, mode, mode_name))
199-
200-
return mode
201-
202-
def getPosition(self):
241+
@property
242+
def position(self):
203243
'''Returns the current position of the encoder.
204244
In absolute mode, this attribute represents the current position
205245
of the encoder.
@@ -209,31 +249,51 @@ def getPosition(self):
209249
'''
210250
position = self._eqep.node.position
211251

212-
self._logger.debug("getPosition(): Channel {}, position: {}".format(
252+
self._logger.debug("Get position: Channel {}, position: {}".format(
213253
self._eqep.channel, position))
214254

215255
return int(position)
216256

217-
def setFrequency(self, freq):
257+
@position.setter
258+
def position(self, position):
259+
'''Sets the current position to a new value'''
260+
261+
position = int(position)
262+
self._eqep.node.position = str(position)
263+
264+
self._logger.debug("Set position: Channel {}, position: {}".format(
265+
self._eqep.channel, position))
266+
267+
268+
@property
269+
def frequency(self):
218270
'''Sets the frequency in Hz at which the driver reports
219271
new positions.
220272
221273
'''
222-
ns_factor = 1000000000
223-
period = ns_factor/freq # Period in nanoseconds
224-
self._eqep.node.period = str(period)
274+
frequency = self._eqep.node.period / self._NS_FACTOR
275+
225276
self._logger.debug(
226-
"setFrequency(): Channel {}, frequency: {} Hz, "
277+
"Set frequency(): Channel {}, frequency: {} Hz, "
227278
"period: {} ns".format(
228-
self._eqep.channel, freq, period))
279+
self._eqep.channel, frequency, period))
229280

230-
def setPosition(self, position):
231-
'''Sets the current position to a new value'''
281+
return frequency
232282

233-
position = int(position)
234-
self._eqep.node.position = str(position)
283+
@frequency.setter
284+
def frequency(self, frequency):
285+
'''Sets the frequency in Hz at which the driver reports
286+
new positions.
287+
288+
'''
289+
period = self._NS_FACTOR / frequency # Period in nanoseconds
290+
self._eqep.node.period = str(period)
291+
self._logger.debug(
292+
"Set frequency(): Channel {}, frequency: {} Hz, "
293+
"period: {} ns".format(
294+
self._eqep.channel, frequency, period))
235295

236296
def zero(self):
237297
'''Resets the current position to 0'''
238298

239-
return self.setPosition(0)
299+
self.position = 0

0 commit comments

Comments
 (0)