diff --git a/README.md b/README.md index 20e52fe..e0ce544 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,7 @@ wiring details, pin names and hardware issues. 3.7 [Class Textbox](./README.md#37-class-textbox) Scrolling text display. 4. [ESP8266](./README.md#4-esp8266) This can work. Contains information on minimising the RAM and flash footprints of the GUI. + 5. [Old firmware](./README.md#5-old-firmware) For users of color displays who can't run current firmware. #### [Graph plotting module.](./FPLOT.md) @@ -113,6 +114,8 @@ my GUI's employ the American spelling of `color`. ## 1.1 Change log +7 Sep 2021 Code reduction and faster color text display. Color use now requires +firmware V1.17 or later. 26 Aug 2021 Support [PR7682](https://github.com/micropython/micropython/pull/7682) for fast text rendering. 25 Apr 2021 Support TTGO T-Display. @@ -236,19 +239,19 @@ active. ## 1.4 A performance boost -As of Aug 2021 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. Usge of -this mode is automatic but can be checked by running the `aclock.py` demo which -reports the status at the REPL. +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#contents) # 2. Files and Dependencies -Firmware should be V1.13 or later. On the Pi Pico firmware should be V1.15 or -later. For fast text rendering use a daily build or V1.17 or later. +On monochrome displays firmware should be V1.13 or later. On the Pi Pico +firmware should be V1.15 or later. For color displays it should be V1.17 or +later. Installation comprises copying the `gui` and `drivers` directories, with their contents, plus a hardware configuration file, to the target. The directory @@ -939,4 +942,14 @@ bytes, `tbox.py` reported 10512 bytes, sometimes more, as the demo progressed. With the 4 bit driver `scale.py` reported 18112 bytes. In conclusion I think that applications of moderate complexity should be feasible. +# 5. Old firmware + +Current firmware is highly recommended. For users of color displays who cannot +meet the requirements of +[Files and Dependencies](./README.md#2-files-and-dependencies) it is possible +to run. 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#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