Skip to content

Commit 61ed40b

Browse files
author
Tomáš Jozífek
committed
Move wait implementation to base class, make sleep amount tune-able
Remove busy-wait Fix initialization bug
1 parent 93e8a43 commit 61ed40b

File tree

3 files changed

+50
-44
lines changed

3 files changed

+50
-44
lines changed

Diff for: RPLCD/gpio.py

+10-14
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,6 @@
3030
from .lcd import BaseCharLCD
3131
from .compat import range
3232

33-
import sys
34-
if sys.version_info.major < 3:
35-
from time import clock as now
36-
else:
37-
from time import perf_counter as now
38-
3933
PinConfig = namedtuple('PinConfig', 'rs rw e d0 d1 d2 d3 d4 d5 d6 d7 backlight mode')
4034

4135

@@ -46,7 +40,8 @@ def __init__(self, numbering_mode=None, pin_rs=None, pin_rw=None, pin_e=None, pi
4640
cols=20, rows=4, dotsize=8,
4741
charmap='A02',
4842
auto_linebreaks=True,
49-
compat_mode=False):
43+
compat_mode=False,
44+
compat_mode_wait_time=0.001):
5045
"""
5146
Character LCD controller.
5247
@@ -94,6 +89,9 @@ def __init__(self, numbering_mode=None, pin_rs=None, pin_rw=None, pin_e=None, pi
9489
:param compat_mode: Whether to run additional checks to support older LCDs
9590
that may not run at the reference clock (or keep up with it).
9691
:type compat_mode: bool
92+
:param compat_mode_wait_time: Minimum time to pass between sends.
93+
if zero, turns off compat_mode Default: ``0.001`` seconds.
94+
:type compat_mode_wait_time: float
9795
9896
"""
9997

@@ -130,7 +128,8 @@ def __init__(self, numbering_mode=None, pin_rs=None, pin_rw=None, pin_e=None, pi
130128
super(CharLCD, self).__init__(cols, rows, dotsize,
131129
charmap=charmap,
132130
auto_linebreaks=auto_linebreaks,
133-
compat_mode=compat_mode)
131+
compat_mode=compat_mode,
132+
compat_mode_wait_time=compat_mode_wait_time)
134133

135134
# Set backlight status
136135
if pin_backlight is not None:
@@ -184,9 +183,8 @@ def _set_backlight_enabled(self, value):
184183
def _send(self, value, mode):
185184
"""Send the specified value to the display with automatic 4bit / 8bit
186185
selection. The rs_mode is either ``RS_DATA`` or ``RS_INSTRUCTION``."""
187-
# Wait, if compatibility mode is enabled
188-
if self.compat_mode:
189-
self._wait()
186+
# Wait if compatibility mode is enabled
187+
self._compat_mode_wait()
190188

191189
# Choose instruction or data mode
192190
GPIO.output(self.pins.rs, mode)
@@ -203,8 +201,7 @@ def _send(self, value, mode):
203201
self._write4bits(value)
204202

205203
# Record the time for the tail-end of the last send event
206-
if self.compat_mode:
207-
self.last_send_event = now()
204+
self._compat_mode_record_send_event()
208205

209206
def _send_data(self, value):
210207
"""Send data to the display. """
@@ -237,4 +234,3 @@ def _pulse_enable(self):
237234
GPIO.output(self.pins.e, 0)
238235
c.usleep(100) # commands need > 37us to settle
239236

240-

Diff for: RPLCD/lcd.py

+31-18
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,7 @@
3232
from time import clock as now
3333
else:
3434
from time import perf_counter as now
35-
36-
# Duration to rate-limit calls to _send
37-
COMPAT_MODE_WAIT_TIME = 0.001
35+
from time import sleep
3836

3937
LCDConfig = namedtuple('LCDConfig', 'rows cols dotsize')
4038

@@ -45,7 +43,8 @@ class BaseCharLCD(object):
4543

4644
# Init, setup, teardown
4745

48-
def __init__(self, cols=20, rows=4, dotsize=8, charmap='A02', auto_linebreaks=True, compat_mode=False):
46+
def __init__(self, cols=20, rows=4, dotsize=8, charmap='A02', auto_linebreaks=True, compat_mode=False,
47+
compat_mode_wait_time=0.001):
4948
"""
5049
Character LCD controller. Base class only, you should use a subclass.
5150
@@ -63,10 +62,21 @@ def __init__(self, cols=20, rows=4, dotsize=8, charmap='A02', auto_linebreaks=Tr
6362
auto_linebreaks:
6463
Whether or not to automatically insert line breaks.
6564
Default: True.
66-
65+
compat_mode:
66+
Whether to run additional checks to support older LCDs
67+
that may not run at the reference clock (or keep up with it).
68+
Default: False
69+
compat_mode_wait_time: Minimum time to pass between sends.
70+
if zero, turns off compat_mode
71+
Default: ``0.001`` seconds.
6772
"""
6873
assert dotsize in [8, 10], 'The ``dotsize`` argument should be either 8 or 10.'
6974

75+
# Configure compatibility mode
76+
self.compat_mode = compat_mode and compat_mode_wait_time > 0
77+
self.compat_mode_wait_time = compat_mode_wait_time
78+
self._compat_mode_record_send_event()
79+
7080
# Initialize codec
7181
if charmap == 'A00':
7282
self.codec = codecs.A00Codec()
@@ -124,8 +134,6 @@ def __init__(self, cols=20, rows=4, dotsize=8, charmap='A02', auto_linebreaks=Tr
124134
else:
125135
raise ValueError('Invalid data bus mode: {}'.format(self.data_bus_mode))
126136

127-
128-
129137
# Write configuration to display
130138
self.command(c.LCD_FUNCTIONSET | displayfunction)
131139
c.usleep(50)
@@ -146,11 +154,6 @@ def __init__(self, cols=20, rows=4, dotsize=8, charmap='A02', auto_linebreaks=Tr
146154
self.command(c.LCD_ENTRYMODESET | self._text_align_mode | self._display_shift_mode)
147155
c.usleep(50)
148156

149-
# Configure compatibility mode
150-
self.compat_mode = compat_mode
151-
if compat_mode:
152-
self.last_send_event = now()
153-
154157
def close(self, clear=False):
155158
if clear:
156159
self.clear()
@@ -253,12 +256,6 @@ def _set_cursor_mode(self, value):
253256
cursor_mode = property(_get_cursor_mode, _set_cursor_mode,
254257
doc='How the cursor should behave (``hide``, ``line`` or ``blink``).')
255258

256-
def _wait(self):
257-
"""Rate limit the number of send events."""
258-
end = self.last_send_event + COMPAT_MODE_WAIT_TIME
259-
while now() < end:
260-
pass
261-
262259
# High level commands
263260

264261
def write_string(self, value):
@@ -467,3 +464,19 @@ def crlf(self): # type: () -> None
467464
"""Write a line feed and a carriage return (``\\r\\n``) character to the LCD."""
468465
self.write_string('\r\n')
469466

467+
def _is_compat_mode_on(self):
468+
"""Compat mode is on, when it's enabled and the wait time is > 0"""
469+
return self.compat_mode and self.compat_mode_wait_time > 0
470+
471+
def _compat_mode_wait(self):
472+
"""Wait the specified amount, if the compat mode is on, to rate limit the data transmission"""
473+
if self._is_compat_mode_on():
474+
end = self.last_send_event + self.compat_mode_wait_time
475+
sleep_duration = end - now()
476+
if sleep_duration > 0:
477+
sleep(sleep_duration)
478+
479+
def _compat_mode_record_send_event(self):
480+
"""Record when did the last send take place, so the rate limiting adapts to any slowdowns."""
481+
self.last_send_event = now()
482+

Diff for: RPLCD/pigpio.py

+9-12
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,6 @@
3131
from .lcd import BaseCharLCD
3232
from .compat import range
3333

34-
import sys
35-
if sys.version_info.major < 3:
36-
from time import clock as now
37-
else:
38-
from time import perf_counter as now
39-
4034
# https://diarmuid.ie/blog/pwm-exponential-led-fading-on-arduino-or-other-platforms/
4135
# p 101 .. maximum value of the PWM cycle
4236
# m 100 .. number of steps the LED will fade over
@@ -58,7 +52,8 @@ def __init__(self, pi,
5852
cols=20, rows=4, dotsize=8,
5953
charmap='A02',
6054
auto_linebreaks=True,
61-
compat_mode=False):
55+
compat_mode=False,
56+
compat_mode_wait_time=0.001):
6257
"""
6358
Character LCD controller.
6459
@@ -124,6 +119,9 @@ def __init__(self, pi,
124119
:param auto_linebreaks: Whether or not to automatically insert line
125120
breaks. Default: ``True``.
126121
:type auto_linebreaks: bool
122+
:param compat_mode_wait_time: Minimum time to pass between sends.
123+
if zero, turns off compat_mode Default: ``0.001`` seconds.
124+
:type compat_mode_wait_time: float
127125
128126
"""
129127

@@ -158,7 +156,8 @@ def __init__(self, pi,
158156
super(CharLCD, self).__init__(cols, rows, dotsize,
159157
charmap=charmap,
160158
auto_linebreaks=auto_linebreaks,
161-
compat_mode=compat_mode)
159+
compat_mode=compat_mode,
160+
compat_mode_wait_time=compat_mode_wait_time)
162161

163162
# Set backlight status
164163
if pin_backlight is not None:
@@ -308,8 +307,7 @@ def _send(self, value, mode):
308307
selection. The rs_mode is either ``RS_DATA`` or ``RS_INSTRUCTION``."""
309308

310309
# Wait, if compatibility mode is enabled
311-
if self.compat_mode:
312-
self._wait()
310+
self._compat_mode_wait()
313311

314312
# Assemble the parameters sent to the pigpio script
315313
params = [mode]
@@ -328,8 +326,7 @@ def _send(self, value, mode):
328326
pigpio.exceptions = True
329327

330328
# Record the time for the tail-end of the last send event
331-
if self.compat_mode:
332-
self.last_send_event = now()
329+
self._compat_mode_record_send_event()
333330

334331
def _send_data(self, value):
335332
"""Send data to the display. """

0 commit comments

Comments
 (0)