From 6ff7206e72412394f17f9ffbb05acb4c206e4e6d Mon Sep 17 00:00:00 2001 From: Peter Hinch Date: Tue, 7 Sep 2021 10:55:37 +0100 Subject: [PATCH] Smaller, faster writer.py. Requires fw V1.17 or later. --- README.md | 34 +++++++++++++++-------- gui/core/writer.py | 68 +++++++--------------------------------------- 2 files changed, 32 insertions(+), 70 deletions(-) diff --git a/README.md b/README.md index 5d50421..5387a6a 100644 --- a/README.md +++ b/README.md @@ -60,8 +60,9 @@ Code has been tested on ESP32, Pi Pico and Pyboard. The API shuld be stable. Code is new and issues are likely: please report any found. The project is under development so check for updates. -A recent firmware update [PR7682](https://github.com/micropython/micropython/pull/7682) -has provided a major boost to text rendering speed on color displays. See +Firmware V1.17 has provided a major boost to text rendering speed on color +display. V1.17 or later is now a requirement for color displays, although +there is a workround if it's impossible to upgrade. See [section 1.8](./README.md#18-performance-and-hardware-notes) for details. # 0. Contents @@ -127,6 +128,7 @@ has provided a major boost to text rendering speed on color displays. See      23.3.1 [Class Curve](./README.md#2331-class-curve)      23.3.2 [Class PolarCurve](./README.md#2332-class-polarcurve) 23.4 [Class TSequence](./README.md#234-class-tsequence) Plotting realtime, time sequential data. +24. [Old firmware](./README.md#24-old-firmware) For users of color displays who can't run current firmware. [Appendix 1 Application design](./README.md#appendix-1-application-design) Tab order, button layout, encoder interface, use of graphics primitives # 1. Basic concepts @@ -414,21 +416,20 @@ RAM usage. A smaller display or a Pyboard D would offer more headroom. #### A performance boost -As of Aug 2021 a firmware update -[PR7682](https://github.com/micropython/micropython/pull/7682) means that color -displays can benefit from a substantial performance boost in rendering text. To -take advantage of this, firmware should be dated after 26 Aug 21. The display -driver and GUI core files should be updated. Ensure that the new file -`drivers/boolpalette.py` exists on the target hardware. +A firmware change in V1.17 has enabled the code size to be reduced. It has also +accelerated text rendering on color displays. Use of color displays now +requires firmware V1.17 or later. Existing users should update the display +driver and GUI core files and should ensure that the new file +`drivers/boolpalette.py` exists. ###### [Contents](./README.md#0-contents) ## 1.9 Firmware and dependencies -Firmware should be V1.15 or later. For fast text rendering a daily build or -a release build >= 1.17 should be used. The source tree includes all -dependencies. These are listed to enable users to check for newer versions or -to read docs: +Users of color displays should ensure that firmware is V1.17 or later. If this +cannot be met, there is a [workround](./README.md#24-old-firmware). The source +tree includes all dependencies. These are listed to enable users to check for +newer versions or to read docs: * [writer.py](https://github.com/peterhinch/micropython-font-to-py/blob/master/writer/writer.py) Provides text rendering of Python font files. @@ -2612,6 +2613,15 @@ class TSeq(Screen): await asyncio.sleep_ms(400) t += 1 ``` +###### [Contents](./README.md#0-contents) + +# 24. Old firmware + +Current firmware is highly recommended. For users of color displays who cannot +run V1.17 or later it is possible to run under V1.15+. This involves copying +[this file](https://github.com/peterhinch/micropython-font-to-py/blob/master/writer/old_versions/writer_fw_compatible.py) +to `gui/core/writer.py`. This uses Python code to render text if the firmware +or driver are unable to support fast rendering. ###### [Contents](./README.md#0-contents) diff --git a/gui/core/writer.py b/gui/core/writer.py index f83eff2..7c9be14 100644 --- a/gui/core/writer.py +++ b/gui/core/writer.py @@ -1,6 +1,7 @@ # writer.py Implements the Writer class. # Handles colour, word wrap and tab stops +# V0.5.0 Sep 2021 Color now requires firmware >= 1.17. # V0.4.3 Aug 2021 Support for fast blit to color displays (PR7682). # V0.4.0 Jan 2021 Improved handling of word wrap and line clip. Upside-down # rendering no longer supported: delegate to device driver. @@ -24,27 +25,9 @@ from uctypes import bytearray_at, addressof from sys import implementation import os -__version__ = (0, 4, 3) +__version__ = (0, 5, 0) -def buildcheck(device): - if not hasattr(device, 'palette'): - return False - i0, i1, _ = implementation[1] - if i0 > 1 or i1 > 16: - return True - # After release of V1.17 require that build. Until then check for date. - # TODO simplify this once V1.17 is released. - try: - datestring = os.uname()[3] - date = datestring.split(' on')[1] - date = date.lstrip()[:10] - idate = tuple([int(x) for x in date.split('-')]) - return idate >= (2021, 8, 25) - except AttributeError: - return False - - -fast_mode = False # False for mono displays although actually these render fast +fast_mode = True # Does nothing. Kept to avoid breaking code. class DisplayState(): def __init__(self): @@ -202,7 +185,7 @@ class Writer(): break if mc + 1 == wd: break # All done: no trailing space - print('Truelen', char, wd, mc + 1) # TEST + # print('Truelen', char, wd, mc + 1) # TEST return mc + 1 def _get_char(self, char, recurse): @@ -272,19 +255,20 @@ class CWriter(Writer): def __init__(self, device, font, fgcolor=None, bgcolor=None, verbose=True): + if not hasattr(device, 'palette'): + raise OSError('Incompatible device driver.') + if implementation[1] < (1, 17, 0): + raise OSError('Firmware must be >= 1.17.') + super().__init__(device, font, verbose) - global fast_mode - fast_mode = buildcheck(device) if bgcolor is not None: # Assume monochrome. self.bgcolor = bgcolor if fgcolor is not None: self.fgcolor = fgcolor self.def_bgcolor = self.bgcolor self.def_fgcolor = self.fgcolor - self._printchar = self._pchfast if fast_mode else self._pchslow - verbose and print('Render {} using fast mode'.format('is' if fast_mode else 'not')) - def _pchfast(self, char, invert=False, recurse=False): + def _printchar(self, char, invert=False, recurse=False): s = self._getstate() self._get_char(char, recurse) if self.glyph is None: @@ -294,42 +278,10 @@ class CWriter(Writer): palette = self.device.palette palette.bg(self.fgcolor if invert else self.bgcolor) palette.fg(self.bgcolor if invert else self.fgcolor) - self.device.blit(fbc, s.text_col, s.text_row, -1, palette) s.text_col += self.char_width self.cpos += 1 - def _pchslow(self, char, invert=False, recurse=False): - s = self._getstate() - self._get_char(char, recurse) - if self.glyph is None: - return # All done - char_height = self.char_height - char_width = self.char_width - clip_width = self.clip_width - - div, mod = divmod(char_width, 8) - gbytes = div + 1 if mod else div # No. of bytes per row of glyph - device = self.device - fgcolor = self.bgcolor if invert else self.fgcolor - bgcolor = self.fgcolor if invert else self.bgcolor - drow = s.text_row # Destination row - wcol = s.text_col # Destination column of character start - for srow in range(char_height): # Source row - for scol in range(clip_width): # Source column - # Destination column: add writer column - dcol = wcol + scol - gbyte, gbit = divmod(scol, 8) - if gbit == 0: # Next glyph byte - data = self.glyph[srow * gbytes + gbyte] - pixel = fgcolor if data & (1 << (7 - gbit)) else bgcolor - device.pixel(dcol, drow, pixel) - drow += 1 - if drow >= self.screenheight or drow < 0: - break - s.text_col += char_width - self.cpos += 1 - def setcolor(self, fgcolor=None, bgcolor=None): if fgcolor is None and bgcolor is None: self.fgcolor = self.def_fgcolor