Skip to content

Commit 1fdedc5

Browse files
authored
Encoder: use sysfs to write QEP attributes
1 parent 07b6c14 commit 1fdedc5

File tree

1 file changed

+97
-104
lines changed

1 file changed

+97
-104
lines changed

Adafruit_BBIO/Encoder.py

Lines changed: 97 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import os
55
import logging
66
import itertools
7+
import sysfs
78
import platform
89

910
if not platform.release().startswith('4.4'):
@@ -57,12 +58,15 @@ def __init__(self, channel, pin_A, pin_B, sys_path):
5758
rotary encoder
5859
sys_path (str): sys filesystem path to access the attributes
5960
of this eQEP module
61+
node (str): sys filesystem device node that contains the
62+
readable or writable attributes to control the QEP channel
6063
6164
'''
6265
self.channel = channel
6366
self.pin_A = pin_A
6467
self.pin_B = pin_B
6568
self.sys_path = sys_path
69+
self.node = sysfs.Node(sys_path)
6670

6771

6872
class RotaryEncoder(object):
@@ -90,156 +94,145 @@ def config_pin(self, pin):
9094

9195
self._run_cmd(["config-pin", pin, "qep"])
9296

93-
def cat_file(self, path):
94-
'''
95-
cat_file()
96-
Print contents of file
97-
'''
98-
99-
self._run_cmd(["cat", path])
100-
10197
def __init__(self, eqep_num):
102-
'''
103-
RotaryEncoder(eqep_num)
104-
Creates an instance of the class RotaryEncoder.
105-
eqep_num determines which eQEP pins are set up.
106-
eqep_num can be: EQEP0, EQEP1, EQEP2 or EQEP2b based on which pins \
107-
the rotary encoder is connected to.
108-
'''
98+
'''Creates an instance of the class RotaryEncoder.
10999
100+
Arguments:
101+
eqep_num: determines which eQEP pins are set up.
102+
Allowed values: EQEP0, EQEP1, EQEP2 or EQEP2b,
103+
based on which pins the physical rotary encoder
104+
is connected to.
105+
106+
'''
107+
# Set up logging at the module level
110108
self._logger = logging.getLogger(__name__)
111109
self._logger.addHandler(logging.NullHandler())
112110

113-
# Configure eqep module
111+
# Initialize the eQEP channel structures
114112
self._eqep = eQEP.fromdict(_eQEP_DEFS[eqep_num])
115113
self._logger.info(
116114
"Configuring: {}, pin A: {}, pin B: {}, sys path: {}".format(
117115
self._eqep.channel, self._eqep.pin_A, self._eqep.pin_B,
118116
self._eqep.sys_path))
119117

118+
# Configure the pins for the given channel
120119
self.config_pin(self._eqep.pin_A)
121120
self.config_pin(self._eqep.pin_B)
122121

123-
self.base_dir = self._eqep.sys_path
124122
self._logger.debug(
125-
"RotaryEncoder(): self.base_dir: {0}".format(self.base_dir))
123+
"RotaryEncoder(): sys node: {0}".format(self._eqep.sys_path))
126124

125+
# Enable the channel upon initialization
127126
self.enable()
128127

129-
def enable(self):
130-
'''
131-
enable()
132-
Turns the eQEP hardware ON
128+
def _setEnable(self, value):
129+
'''Turns the eQEP hardware ON or OFF
130+
131+
value (int): 1 represents enabled, 0 is disabled
133132
'''
134-
enable_file = "%s/enabled" % self.base_dir
135-
self._logger.debug("enable(): enable_file: {0}".format(enable_file))
136-
self._logger.warning(
137-
"enable(): TODO: not implemented, write 1 to {}".format(enable_file))
138-
# return sysfs.kernelFileIO(enable_file, '1')
133+
if value < 0 or value > 1:
134+
raise ValueError(
135+
'The "enabled" attribute can only be set to 0 or 1. '
136+
'You attempted to set it to {}.'.format(value))
137+
138+
self._eqep.node.enabled = str(int(value))
139+
self._logger.info("Channel: {}, enabled: {}".format(
140+
self._eqep.channel, self._eqep.node.enabled))
141+
142+
def enable(self):
143+
'''Turns the eQEP hardware ON'''
144+
145+
self._setEnable(1)
139146

140147
def disable(self):
148+
'''Turns the eQEP hardware OFF'''
149+
150+
self._setEnable(0)
151+
152+
def _setMode(self, value):
153+
'''Sets the eQEP mode as absolute (0) or relative (1).
154+
See the setAbsolute() and setRelative() methods for
155+
more information.
156+
141157
'''
142-
disable()
143-
Turns the eQEP hardware OFF
144-
'''
145-
enable_file = "%s/enabled" % self.base_dir
146-
self._logger.debug("disable(): enable_file: {0}".format(enable_file))
147-
self._logger.warning(
148-
"disable(): TODO: not implemented, write 0 to {}".format(
149-
enable_file))
150-
# return sysfs.kernelFileIO(enable_file, '0')
158+
if value < 0 or value > 1:
159+
raise ValueError(
160+
'The "mode" attribute can only be set to 0 or 1. '
161+
'You attempted to set it to {}.'.format(value))
162+
163+
self._eqep.node.mode = str(int(value))
164+
self._logger.debug("Mode set to: {}".format(
165+
self._eqep.node.mode))
151166

152167
def setAbsolute(self):
153-
'''
154-
setAbsolute()
155-
Set mode as Absolute
168+
'''Sets the eQEP mode as Absolute:
156169
The position starts at zero and is incremented or
157170
decremented by the encoder's movement
171+
158172
'''
159-
mode_file = "%s/mode" % self.base_dir
160-
self._logger.debug("setAbsolute(): mode_file: {0}".format(mode_file))
161-
self._logger.warning(
162-
"setAbsolute(): TODO: not implemented, write 0 to {}".format(
163-
mode_file))
164-
# return sysfs.kernelFileIO(mode_file, '0')
173+
self._setMode(0)
165174

166175
def setRelative(self):
167-
'''
168-
setRelative()
169-
Set mode as Relative
176+
'''Sets the eQEP mode as Relative:
170177
The position is reset when the unit timer overflows.
178+
171179
'''
172-
mode_file = "%s/mode" % self.base_dir
173-
self._logger.debug("setRelative(): mode_file: {0}".format(mode_file))
174-
self._logger.warning(
175-
"setRelative(): TODO: not implemented, write 1 to {}".format(
176-
mode_file))
177-
# return sysfs.kernelFileIO(mode_file, '1')
180+
self._setMode(1)
178181

179182
def getMode(self):
183+
'''Returns the mode the eQEP hardware is in (absolute or relative).
184+
180185
'''
181-
getMode()
182-
Returns the mode the eQEP hardware is in.
183-
'''
184-
mode_file = "%s/mode" % self.base_dir
185-
self._logger.debug("getMode(): mode_file: {0}".format(mode_file))
186-
self._logger.warning("getMode(): TODO: read mode_file")
187-
# return sysfs.kernelFileIO(mode_file)
186+
187+
mode = int(self._eqep.node.mode)
188+
189+
if mode == 0:
190+
mode_name = "absolute"
191+
elif mode == 1:
192+
mode_name = "relative"
193+
else:
194+
mode_name = "invalid"
195+
196+
self._logger.debug("getMode(): Channel {}, mode: {} ({})".format(
197+
self._eqep.channel, mode, mode_name))
198+
199+
return mode
188200

189201
def getPosition(self):
190-
'''
191-
getPosition()
192-
Get the current position of the encoder.
202+
'''Returns the current position of the encoder.
193203
In absolute mode, this attribute represents the current position
194204
of the encoder.
195205
In relative mode, this attribute represents the position of the
196206
encoder at the last unit timer overflow.
207+
197208
'''
198-
self._logger.debug("Channel: {}".format(self._eqep.channel))
199-
position_file = "%s/position" % self.base_dir
200-
self._logger.debug(
201-
"getPosition(): position_file: {0}".format(position_file))
202-
position_handle = open(position_file, 'r')
203-
self._logger.debug(
204-
"getPosition(): position_handle: {0}".format(position_handle))
205-
position = position_handle.read()
206-
self._logger.debug("getPosition(): position: {0}".format(position))
207-
# return sysfs.kernelFileIO(position_file)
209+
position = self._eqep.node.position
210+
211+
self._logger.debug("getPosition(): Channel {}, position: {}".format(
212+
self._eqep.channel, position))
208213

209-
return position
214+
return int(position)
210215

211216
def setFrequency(self, freq):
217+
'''Sets the frequency in Hz at which the driver reports
218+
new positions.
219+
212220
'''
213-
setFrequency(freq)
214-
Set the frequency in Hz at which the driver reports new positions.
215-
'''
216-
period_file = "%s/period" % self.base_dir
217-
self._logger.debug(
218-
"setFrequency(): period_file: {0}".format(period_file))
219-
self._logger.debug("setFrequency(): freq: {0}".format(freq))
221+
ns_factor = 1000000000
222+
period = ns_factor/freq # Period in nanoseconds
223+
self._eqep.node.period = str(period)
220224
self._logger.debug(
221-
"setFrequency(): 1000000000/freq: {0}".format(1000000000/freq))
222-
self._logger.debug("setFrequency(): str(1000000000/freq)): {0}".format(
223-
str(1000000000/freq)))
224-
self._logger.warning(
225-
"setFrequency(): TODO: not implemented, set {} to {}".format(
226-
period_file, str(1000000000/freq)))
227-
# return sysfs.kernelFileIO(period_file, str(1000000000/freq))
228-
229-
def setPosition(self, val):
230-
'''
231-
setPosition(value)
232-
Give a new value to the current position
233-
'''
234-
position_file = "%s/position" % self.base_dir
235-
self._logger.warning(
236-
"setPosition(): TODO: not implemented, write position to {}".format(
237-
position_file))
238-
# return sysfs.kernelFileIO(position_file, str(val))
225+
"setFrequency(): Channel {}, frequency: {} Hz, "
226+
"period: {} ns".format(
227+
self._eqep.channel, freq, period))
228+
229+
def setPosition(self, position):
230+
'''Sets the current position to a new value'''
231+
232+
position = int(position)
233+
self._eqep.node.position = str(position)
239234

240235
def zero(self):
241-
'''
242-
zero()s
243-
Set the current position to 0
244-
'''
236+
'''Resets the current position to 0'''
237+
245238
return self.setPosition(0)

0 commit comments

Comments
 (0)