From 8bff972a2983c10b83919ac409529b4a77b3f34f Mon Sep 17 00:00:00 2001 From: Peter Hinch Date: Tue, 15 Nov 2016 08:54:19 +0000 Subject: [PATCH] SSD1306 added --- README.md | 4 + SSD1306/README.md | 120 +++++++++++++++++++ SSD1306/freesans20.py | 248 +++++++++++++++++++++++++++++++++++++++ SSD1306/freeserif19.py | 242 ++++++++++++++++++++++++++++++++++++++ SSD1306/inconsolata14.py | 156 ++++++++++++++++++++++++ SSD1306/ssd1306.py | 161 +++++++++++++++++++++++++ SSD1306/ssd1306_drv.py | 122 +++++++++++++++++++ SSD1306/ssd1306_test.py | 76 ++++++++++++ SSD1306/writer.py | 123 +++++++++++++++++++ 9 files changed, 1252 insertions(+) create mode 100644 SSD1306/README.md create mode 100644 SSD1306/freesans20.py create mode 100644 SSD1306/freeserif19.py create mode 100644 SSD1306/inconsolata14.py create mode 100644 SSD1306/ssd1306.py create mode 100644 SSD1306/ssd1306_drv.py create mode 100644 SSD1306/ssd1306_test.py create mode 100644 SSD1306/writer.py diff --git a/README.md b/README.md index 2c22666..cb00316 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ # micropython-samples A place for assorted code ideas for MicroPython. Most are targeted at the Pyboard variants. +## ssd1306 + +A means of rendering multiple larger fonts to the SSD1306 OLED display + ## mutex A class providing mutal exclusion enabling interrupt handlers and the main program to access shared data in a manner which ensures data integrity. diff --git a/SSD1306/README.md b/SSD1306/README.md new file mode 100644 index 0000000..82b0261 --- /dev/null +++ b/SSD1306/README.md @@ -0,0 +1,120 @@ +# ssd1306: Introduction + +The official SSD1306 OLED display driver supports a single 8x8 pixel monospaced +font. Users of the 128x64 displays in particular may wish to use larger fonts. +This provides a means of extending the official driver to support this. Suitable +font files may be created from standard ``ttf`` or ``otf`` files using the utility +presented [here](https://github.com/peterhinch/micropython-font-to-py.git). + + +![Picture](ssd1306.JPG) + +# Files + +1. ssd1306_test.py A simple test program. +2. ssd1306.py A snapshot of the current official driver. +3. ssd1306_drv.py A temporary Python fix for a bug in the above. +4. writer.py A generic Writer class. Keeps track of the text insertion point +over multiple fonts, handles newline and vertical scrolling if required. + +In addition several font files are provided as samples. + +# Getting started + +Edit ``ssd1306_test.py`` to match your hardware, namely whether it uses SPI or +I2C and the value of HEIGHT. The file contains details of how to wire the device +to a Pyboard. It is untested on other platforms, but I'd expect it to be +portable to any device supporting the official driver. If in doubt, install and +test this first. + +Copy files 1-4 and ``freesans20.py`` to the target and issue + +```python +import ssd1306_test +``` + +# Principle of Operation + +Font files are converted to Python modules for ease of use and also (optionally) +to enable the modules to be frozen as bytecode to reduce RAM requirements. + +The user program should import all fonts which are to be used and declare a +``Writer`` instance for each one. Rendering text at the current insertion point +is then simply a matter of issuing the appropriate writer's ``printstring`` +method. After issuing all such calls required by your application the display +should be updated by issuing + +```python +ssd.show() +``` + +# The Writer class + +The principal interaction with the driver is via this class. One instance should +be created for each font in use. Its function is to keep track of the text +insertion point over successive uses with multiple fonts and to handle newline +characters and vertical scrolling. Its behaviour when text overruns the end of +a line or the bottom of the screen may be controlled using its ``set_clip`` +method. + +## Methods + +1. ``Constructor`` This takes the ``ssd`` display instance and the font module +as mandatory args. +2. ``printstring`` Takes a text string as argument and renders it at the current +insertion point. Respects newline characters. + +## Class methods + +1. ``set_textpos`` Mandatory integer args ``row``, ``col`` defined in pixels +relative to the top left hand corner of the display. Sets the current text +insertion point. The coordinates of a glyph refer to its top left corner. The +initial default is (0,0) with text being rendered at the top left of the display. +2. ``set_clip`` Mandatory boolean args ``row_clip``, ``col_clip``. These define +behaviour when text overruns the physical width or height of the display. By +default text overrunning the display width will continue on the next row. Setting +``col_clip`` overrides this such that overrunning text is lost. Similarly, by +default text overrunning the bottom of the display will cause text above to +scroll up to accommodate it. Setting ``row_clip`` will override this behaviour +causing text to be clipped. + +A final classmethod is provided for possible future use. + +``mapping`` The current official ssd1306 driver configures the hardware to use +an unorthodox mapping of bytes onto pixels. The original plan for the +``framebuf`` module was that it should support vertical and horizontal mappings +only. Should the official ssd1306 driver be changed to use vertical mapping +(which the device supports) this method may be used to accommodate it. This mode +has been tested. + +# Note + +The official SSD1306 driver is based on the framebuf module which is in a state +of active development. The code presented here extends the official driver and +consequently may be less than stable if there is significant change to the +underlying framebuffer class. Further, the official driver's scroll method is +buggy and at the time of writing there is a moratorium on PR's. I have coded a +Python workround in the file ssd1306_drv.py. Hopefully in time this file will +become redundant and the official driver will support vertical scrolling over +long distances. + +# License + +Any code placed here is released under the MIT License (MIT). +The MIT License (MIT) +Copyright (c) 2016 Peter Hinch +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/SSD1306/freesans20.py b/SSD1306/freesans20.py new file mode 100644 index 0000000..53007c9 --- /dev/null +++ b/SSD1306/freesans20.py @@ -0,0 +1,248 @@ +# Code generated by font-to-py.py. +# Font: FreeSans.ttf +version = '0.1' + +def height(): + return 20 + +def max_width(): + return 20 + +def hmap(): + return False + +def reverse(): + return False + +def monospaced(): + return False + +_font =\ +b'\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x07\x00\xfe\xcf\x00\xfe\xcf\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x7c\x00\x00\x3c\x00\x00'\ +b'\x00\x00\x00\x7c\x00\x00\x3c\x00\x00\x00\x00\x00\x00\x00\x00\x0b'\ +b'\x00\x00\x0c\x00\x60\x0c\x00\x60\xfc\x00\xe0\x3f\x00\xfc\x0c\x00'\ +b'\x64\x0c\x00\x60\xfc\x00\xe0\x3f\x00\xfc\x0c\x00\x64\x0c\x00\x60'\ +b'\x00\x00\x0b\x00\xf8\x30\x00\xfc\x71\x00\x8e\xe1\x00\x06\xc3\x00'\ +b'\xff\xff\x01\x06\xc3\x00\x06\xc2\x00\x0c\x66\x00\x3c\x7e\x00\x38'\ +b'\x3c\x00\x00\x00\x00\x12\x00\x70\x00\x00\xf8\x00\x00\x8c\x01\x00'\ +b'\x8c\x01\x00\x8c\x81\x00\xf8\x60\x00\x70\x18\x00\x00\x06\x00\x80'\ +b'\x01\x00\xc0\x38\x00\x30\x7c\x00\x0c\xee\x00\x00\xc6\x00\x00\xc6'\ +b'\x00\x00\xee\x00\x00\x7c\x00\x00\x38\x00\x00\x00\x00\x0d\x00\x00'\ +b'\x3c\x00\x00\x7e\x00\x70\xe6\x00\xf8\xc3\x00\x8c\xc1\x00\x8c\xc3'\ +b'\x00\x8c\xc6\x00\xf8\x6c\x00\x70\x38\x00\x00\x7e\x00\x00\xc6\x00'\ +b'\x00\x80\x00\x00\x00\x00\x04\x00\x7c\x00\x00\x3c\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x07\x00\x80\x3f\x00\xe0\xff\x00\x38\x80\x03\x06'\ +b'\x00\x0e\x00\x00\x08\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x08'\ +b'\x06\x00\x0e\x38\x80\x03\xe0\xff\x00\x80\x3f\x00\x00\x00\x00\x00'\ +b'\x00\x00\x08\x00\x08\x00\x00\x68\x00\x00\x1e\x00\x00\x68\x00\x00'\ +b'\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x00\x0c'\ +b'\x00\x00\x0c\x00\x00\x0c\x00\x80\xff\x00\x80\xff\x00\x00\x0c\x00'\ +b'\x00\x0c\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x06\x00\x00\xc0\x04\x00\xc0\x03\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x07\x00\x00\x06\x00\x00\x06\x00\x00\x06'\ +b'\x00\x00\x06\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00'\ +b'\xc0\x00\x00\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00'\ +b'\x00\xc0\x00\x00\x78\x00\x00\x0f\x00\xe0\x01\x00\x3c\x00\x00\x06'\ +b'\x00\x00\x0b\x00\xe0\x1f\x00\xf8\x7f\x00\x3c\xf0\x00\x0c\xc0\x00'\ +b'\x0c\xc0\x00\x0c\xc0\x00\x3c\xf0\x00\xf8\x7f\x00\xe0\x1f\x00\x00'\ +b'\x00\x00\x00\x00\x00\x0b\x00\x30\x00\x00\x30\x00\x00\xf8\xff\x00'\ +b'\xfc\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x30\xe0\x00\x38\xf0\x00'\ +b'\x1c\xd8\x00\x0c\xcc\x00\x0c\xc6\x00\x0c\xc6\x00\x1c\xc3\x00\xf8'\ +b'\xc1\x00\xf0\xc0\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x30\x30\x00'\ +b'\x38\x70\x00\x1c\xe0\x00\x0c\xc0\x00\x8c\xc1\x00\x8c\xc1\x00\x9c'\ +b'\xe3\x00\xf8\x7f\x00\x70\x3e\x00\x00\x00\x00\x00\x00\x00\x0b\x00'\ +b'\x00\x1c\x00\x00\x1b\x00\x80\x18\x00\x60\x18\x00\x30\x18\x00\xfc'\ +b'\xff\x00\xfc\xff\x00\x00\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x0b\x00\xc0\x21\x00\xfc\x61\x00\xbc\xc1\x00\xcc\xc0\x00\xcc'\ +b'\xc0\x00\xcc\xc0\x00\xcc\xe1\x00\x8c\x7f\x00\x00\x1f\x00\x00\x00'\ +b'\x00\x00\x00\x00\x0b\x00\xc0\x1f\x00\xf0\x7f\x00\x38\xe3\x00\x8c'\ +b'\xc1\x00\x8c\xc1\x00\x8c\xc1\x00\x9c\xe3\x00\x38\x7f\x00\x20\x3e'\ +b'\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x0c\x00\x00\x0c\x00\x00\x0c'\ +b'\xc0\x00\x0c\xf8\x00\x0c\x1e\x00\x8c\x03\x00\xec\x00\x00\x3c\x00'\ +b'\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x1c\x00\x70'\ +b'\x7e\x00\xf8\x63\x00\x8c\xc1\x00\x8c\xc1\x00\x8c\xc1\x00\xf8\x63'\ +b'\x00\x70\x7e\x00\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x0b\x00\xf0'\ +b'\x21\x00\xf8\x63\x00\x1c\xe7\x00\x0c\xc6\x00\x0c\xc6\x00\x0c\xc6'\ +b'\x00\x1c\x73\x00\xf8\x3f\x00\xe0\x0f\x00\x00\x00\x00\x00\x00\x00'\ +b'\x05\x00\x60\xc0\x00\x60\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x05\x00\xc0\xc0\x04\xc0\xc0\x03\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x0c\x00\x00\x0c\x00\x00\x1c\x00\x00\x1e\x00\x00\x12\x00'\ +b'\x00\x32\x00\x00\x23\x00\x00\x61\x00\x80\x61\x00\x80\x40\x00\xc0'\ +b'\xc0\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x00\x33\x00\x00\x33\x00'\ +b'\x00\x33\x00\x00\x33\x00\x00\x33\x00\x00\x33\x00\x00\x33\x00\x00'\ +b'\x33\x00\x00\x33\x00\x00\x33\x00\x00\x00\x00\x00\x00\x00\x0c\x00'\ +b'\x80\xc0\x00\x80\x41\x00\x80\x61\x00\x00\x61\x00\x00\x23\x00\x00'\ +b'\x32\x00\x00\x16\x00\x00\x1c\x00\x00\x0c\x00\x00\x0c\x00\x00\x00'\ +b'\x00\x00\x00\x00\x0b\x00\x18\x00\x00\x1c\x00\x00\x06\x00\x00\x06'\ +b'\xcc\x00\x06\xcf\x00\x8e\x01\x00\xfc\x00\x00\x78\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x1f\x00\xe0\x7f\x00\xf0'\ +b'\xe0\x01\x38\x80\x01\x1c\x1f\x03\x8c\x3f\x03\xce\x71\x06\xe6\x60'\ +b'\x06\x66\x60\x06\x66\x30\x06\x66\x38\x06\x86\x7f\x06\xcc\x63\x02'\ +b'\x0c\x60\x00\x18\x70\x00\x78\x38\x00\xf0\x1f\x00\xc0\x07\x00\x00'\ +b'\x00\x00\x00\x00\x00\x0d\x00\x00\x80\x00\x00\xe0\x00\x00\x7c\x00'\ +b'\x80\x1f\x00\xf0\x0d\x00\x3e\x0c\x00\x0e\x0c\x00\x3e\x0c\x00\xf8'\ +b'\x0d\x00\xc0\x0f\x00\x00\x7e\x00\x00\xf0\x00\x00\xc0\x00\x0d\x00'\ +b'\xfe\xff\x00\xfe\xff\x00\x86\xc1\x00\x86\xc1\x00\x86\xc1\x00\x86'\ +b'\xc1\x00\x86\xc1\x00\xce\xc1\x00\x7c\xe3\x00\x78\x7e\x00\x00\x3c'\ +b'\x00\x00\x00\x00\x00\x00\x00\x0e\x00\xe0\x0f\x00\xf8\x3f\x00\x3c'\ +b'\x78\x00\x0c\x60\x00\x06\xc0\x00\x06\xc0\x00\x06\xc0\x00\x06\xc0'\ +b'\x00\x06\xc0\x00\x0c\x70\x00\x1c\x78\x00\x10\x18\x00\x00\x00\x00'\ +b'\x00\x00\x00\x0e\x00\xfe\xff\x00\xfe\xff\x00\x06\xc0\x00\x06\xc0'\ +b'\x00\x06\xc0\x00\x06\xc0\x00\x06\xc0\x00\x0e\xe0\x00\x1c\x70\x00'\ +b'\xf8\x3f\x00\xe0\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d'\ +b'\x00\xfe\xff\x00\xfe\xff\x00\x86\xc1\x00\x86\xc1\x00\x86\xc1\x00'\ +b'\x86\xc1\x00\x86\xc1\x00\x86\xc1\x00\x86\xc1\x00\x06\xc0\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\xfe\xff\x00\xfe\xff\x00'\ +b'\x86\x01\x00\x86\x01\x00\x86\x01\x00\x86\x01\x00\x86\x01\x00\x86'\ +b'\x01\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\x00'\ +b'\xc0\x0f\x00\xf0\x3f\x00\x3c\x78\x00\x0c\x60\x00\x0e\xe0\x00\x06'\ +b'\xc0\x00\x06\xc0\x00\x06\xc3\x00\x06\xc3\x00\x06\x63\x00\x0c\x33'\ +b'\x00\x1c\x7f\x00\x10\xff\x00\x00\x00\x00\x00\x00\x00\x0e\x00\xfe'\ +b'\xff\x00\xfe\xff\x00\x80\x01\x00\x80\x01\x00\x80\x01\x00\x80\x01'\ +b'\x00\x80\x01\x00\x80\x01\x00\x80\x01\x00\xfe\xff\x00\xfe\xff\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\xfe\xff\x00\xfe\xff'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00'\ +b'\x38\x00\x00\x78\x00\x00\xe0\x00\x00\xc0\x00\x00\xc0\x00\x00\xe0'\ +b'\x00\xfe\x7f\x00\xfe\x3f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x0d\x00\xfe\xff\x00\xfe\xff\x00\x00\x03\x00\x80\x01\x00\xc0\x00'\ +b'\x00\xe0\x03\x00\x30\x07\x00\x18\x1c\x00\x0c\x38\x00\x06\xe0\x00'\ +b'\x02\xc0\x00\x00\x00\x00\x00\x00\x00\x0b\x00\xfe\xff\x00\xfe\xff'\ +b'\x00\x00\xc0\x00\x00\xc0\x00\x00\xc0\x00\x00\xc0\x00\x00\xc0\x00'\ +b'\x00\xc0\x00\x00\xc0\x00\x00\x00\x00\x00\x00\x00\x11\x00\xfe\xff'\ +b'\x00\xfe\xff\x00\x1e\x00\x00\xf8\x00\x00\xc0\x07\x00\x00\x3e\x00'\ +b'\x00\xf0\x00\x00\xe0\x00\x00\x3e\x00\xc0\x07\x00\xf8\x00\x00\x1e'\ +b'\x00\x00\xfe\xff\x00\xfe\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x0f\x00\xfe\xff\x00\xfe\xff\x00\x1e\x00\x00\x78\x00\x00\xe0'\ +b'\x00\x00\x80\x03\x00\x00\x0e\x00\x00\x38\x00\x00\xf0\x00\xfe\xff'\ +b'\x00\xfe\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x10\x00\xc0\x07\x00\xf0\x1f\x00\x38\x38\x00\x0c\x60\x00\x0e\xe0'\ +b'\x00\x06\xc0\x00\x06\xc0\x00\x06\xc0\x00\x06\xc0\x00\x0e\xe0\x00'\ +b'\x0c\x60\x00\x38\x38\x00\xf0\x1f\x00\xe0\x0f\x00\x00\x00\x00\x00'\ +b'\x00\x00\x0d\x00\xfe\xff\x00\xfe\xff\x00\x06\x03\x00\x06\x03\x00'\ +b'\x06\x03\x00\x06\x03\x00\x06\x03\x00\x8e\x03\x00\xfc\x01\x00\xf8'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\xc0\x07\x00'\ +b'\xf0\x1f\x00\x38\x38\x00\x0c\x60\x00\x0e\xe0\x00\x06\xc0\x00\x06'\ +b'\xc0\x00\x06\xc0\x00\x06\xd0\x00\x0e\x70\x00\x0c\x60\x00\x38\xf8'\ +b'\x00\xf0\xdf\x01\xe0\x07\x00\x00\x00\x00\x00\x00\x00\x0e\x00\xfe'\ +b'\xff\x00\xfe\xff\x00\x06\x03\x00\x06\x03\x00\x06\x03\x00\x06\x03'\ +b'\x00\x06\x03\x00\x06\x03\x00\x8e\x07\x00\xfc\xfe\x00\x78\xfc\x00'\ +b'\x00\x80\x00\x00\x00\x00\x00\x00\x00\x0d\x00\x78\x18\x00\xfc\x78'\ +b'\x00\xcc\x61\x00\x86\xe1\x00\x86\xc1\x00\x06\xc1\x00\x06\xc3\x00'\ +b'\x06\xc3\x00\x06\xc3\x00\x0c\x66\x00\x1c\x7e\x00\x18\x1c\x00\x00'\ +b'\x00\x00\x0d\x00\x06\x00\x00\x06\x00\x00\x06\x00\x00\x06\x00\x00'\ +b'\xfe\xff\x00\xfe\xff\x00\x06\x00\x00\x06\x00\x00\x06\x00\x00\x06'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\xfe\x1f\x00'\ +b'\xfe\x7f\x00\x00\x60\x00\x00\xc0\x00\x00\xc0\x00\x00\xc0\x00\x00'\ +b'\xc0\x00\x00\xc0\x00\x00\x60\x00\xfe\x7f\x00\xfe\x1f\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x0d\x00\x02\x00\x00\x0e\x00\x00\x7c'\ +b'\x00\x00\xe0\x03\x00\x00\x1f\x00\x00\xf8\x00\x00\xe0\x00\x00\xf8'\ +b'\x00\x00\x1f\x00\xe0\x03\x00\x7e\x00\x00\x0e\x00\x00\x00\x00\x00'\ +b'\x13\x00\x02\x00\x00\x3e\x00\x00\xfc\x03\x00\xc0\x3f\x00\x00\xf8'\ +b'\x00\x00\xf8\x00\x00\x7f\x00\xf0\x0f\x00\xfe\x00\x00\x1e\x00\x00'\ +b'\xfc\x00\x00\xe0\x0f\x00\x00\x7e\x00\x00\xe0\x00\x00\xfc\x00\xe0'\ +b'\x1f\x00\xfe\x01\x00\x1e\x00\x00\x00\x00\x00\x0d\x00\x00\x00\x00'\ +b'\x02\xc0\x00\x0e\xe0\x00\x1c\x78\x00\x70\x1c\x00\xe0\x07\x00\x80'\ +b'\x03\x00\xc0\x07\x00\x70\x1c\x00\x3c\x38\x00\x0e\xf0\x00\x06\xc0'\ +b'\x00\x00\x80\x00\x0e\x00\x00\x00\x00\x06\x00\x00\x0e\x00\x00\x3c'\ +b'\x00\x00\xf0\x00\x00\xc0\x01\x00\x80\xff\x00\x80\xff\x00\xc0\x01'\ +b'\x00\xf0\x00\x00\x3c\x00\x00\x0e\x00\x00\x06\x00\x00\x00\x00\x00'\ +b'\x0c\x00\x06\xe0\x00\x06\xf0\x00\x06\xdc\x00\x06\xce\x00\x06\xc7'\ +b'\x00\x86\xc3\x00\xe6\xc0\x00\x76\xc0\x00\x3e\xc0\x00\x0e\xc0\x00'\ +b'\x06\xc0\x00\x00\x00\x00\x06\x00\xfe\xff\x0f\xfe\xff\x0f\x06\x00'\ +b'\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x06\x00\x00\x3c'\ +b'\x00\x00\xe0\x01\x00\x00\x0f\x00\x00\x78\x00\x00\xc0\x00\x06\x00'\ +b'\x06\x00\x0c\xfe\xff\x0f\xfe\xff\x0f\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x09\x00\x00\x03\x00\xc0\x01\x00\x78\x00\x00\x0c\x00\x00'\ +b'\x3c\x00\x00\xe0\x00\x00\x80\x03\x00\x00\x00\x00\x00\x00\x00\x0c'\ +b'\x00\x00\x00\x01\x00\x00\x01\x00\x00\x01\x00\x00\x01\x00\x00\x01'\ +b'\x00\x00\x01\x00\x00\x01\x00\x00\x01\x00\x00\x01\x00\x00\x01\x00'\ +b'\x00\x01\x00\x00\x01\x05\x00\x02\x00\x00\x06\x00\x00\x0c\x00\x00'\ +b'\x08\x00\x00\x00\x00\x00\x0b\x00\xc0\x78\x00\xc0\xf8\x00\x60\xcc'\ +b'\x00\x60\xcc\x00\x60\xc4\x00\x60\x44\x00\x60\x64\x00\xc0\x7f\x00'\ +b'\xc0\xff\x00\x00\xc0\x00\x00\x00\x00\x0b\x00\xfe\xff\x00\xfe\xff'\ +b'\x00\xc0\x60\x00\x60\xc0\x00\x60\xc0\x00\x60\xc0\x00\x60\xc0\x00'\ +b'\xe0\x60\x00\xc0\x7f\x00\x00\x1f\x00\x00\x00\x00\x0a\x00\x00\x1f'\ +b'\x00\xc0\x7f\x00\xc0\xe0\x00\x60\xc0\x00\x60\xc0\x00\x60\xc0\x00'\ +b'\x60\xe0\x00\xc0\x70\x00\x80\x30\x00\x00\x00\x00\x0b\x00\x00\x1f'\ +b'\x00\xc0\x7f\x00\xe0\xe0\x00\x60\xc0\x00\x60\xc0\x00\x60\xc0\x00'\ +b'\xc0\x60\x00\xfe\xff\x00\xfe\xff\x00\x00\x00\x00\x00\x00\x00\x0b'\ +b'\x00\x00\x1f\x00\xc0\x7f\x00\xe0\xe6\x00\x60\xc6\x00\x60\xc6\x00'\ +b'\x60\xc6\x00\xe0\xe6\x00\xc0\x67\x00\x00\x27\x00\x00\x00\x00\x00'\ +b'\x00\x00\x06\x00\x60\x00\x00\xfc\xff\x00\xfe\xff\x00\x66\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x1f\x02\xc0\x7f\x06\xe0\xe0'\ +b'\x0c\x60\xc0\x0c\x60\xc0\x0c\x60\xc0\x0c\xc0\x60\x0e\xe0\xff\x07'\ +b'\xe0\xff\x03\x00\x00\x00\x00\x00\x00\x0b\x00\xfe\xff\x00\xfe\xff'\ +b'\x00\x80\x00\x00\x60\x00\x00\x60\x00\x00\x60\x00\x00\xe0\x00\x00'\ +b'\xe0\xff\x00\xc0\xff\x00\x00\x00\x00\x00\x00\x00\x04\x00\xe6\xff'\ +b'\x00\xe6\xff\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x0c\x00'\ +b'\x00\x0c\xe6\xff\x0f\xe6\xff\x07\x00\x00\x00\x0a\x00\xfe\xff\x00'\ +b'\xfe\xff\x00\x00\x06\x00\x00\x03\x00\x80\x0f\x00\xc0\x1c\x00\x60'\ +b'\x78\x00\x20\xe0\x00\x00\x80\x00\x00\x00\x00\x04\x00\xfe\xff\x00'\ +b'\xfe\xff\x00\x00\x00\x00\x00\x00\x00\x10\x00\xe0\xff\x00\xe0\xff'\ +b'\x00\xc0\x00\x00\x60\x00\x00\x60\x00\x00\x60\x00\x00\xe0\xff\x00'\ +b'\x80\xff\x00\xc0\x00\x00\x60\x00\x00\x60\x00\x00\x60\x00\x00\xe0'\ +b'\xff\x00\xc0\xff\x00\x00\x00\x00\x00\x00\x00\x0b\x00\xe0\xff\x00'\ +b'\xe0\xff\x00\x80\x00\x00\x40\x00\x00\x60\x00\x00\x60\x00\x00\xe0'\ +b'\x00\x00\xe0\xff\x00\xc0\xff\x00\x00\x00\x00\x00\x00\x00\x0b\x00'\ +b'\x00\x1f\x00\xc0\x7f\x00\xe0\xe0\x00\x60\xc0\x00\x60\xc0\x00\x60'\ +b'\xc0\x00\xe0\xe0\x00\xc0\x7f\x00\x00\x1f\x00\x00\x00\x00\x00\x00'\ +b'\x00\x0b\x00\xe0\xff\x07\xe0\xff\x07\xc0\x60\x00\x60\xc0\x00\x60'\ +b'\xc0\x00\x60\xc0\x00\x60\xc0\x00\xc0\x60\x00\xc0\x7f\x00\x00\x1f'\ +b'\x00\x00\x00\x00\x0b\x00\x00\x1f\x00\xc0\x7f\x00\xe0\xe0\x00\x60'\ +b'\xc0\x00\x60\xc0\x00\x60\xc0\x00\xc0\x60\x00\xe0\xff\x07\xe0\xff'\ +b'\x07\x00\x00\x00\x00\x00\x00\x07\x00\xe0\xff\x00\xe0\xff\x00\xc0'\ +b'\x00\x00\x60\x00\x00\x60\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00'\ +b'\x80\x63\x00\xc0\xe7\x00\x60\xc6\x00\x60\xc6\x00\x60\xcc\x00\x60'\ +b'\xcc\x00\xc0\x7c\x00\xc0\x38\x00\x00\x00\x00\x00\x00\x00\x06\x00'\ +b'\x60\x00\x00\xf8\xff\x00\xf8\xff\x00\x60\xc0\x00\x00\x00\x00\x00'\ +b'\x00\x00\x0b\x00\xe0\x7f\x00\xe0\xff\x00\x00\xe0\x00\x00\xc0\x00'\ +b'\x00\xc0\x00\x00\x40\x00\x00\x20\x00\xe0\xff\x00\xe0\xff\x00\x00'\ +b'\x00\x00\x00\x00\x00\x0a\x00\x20\x00\x00\xe0\x01\x00\xc0\x0f\x00'\ +b'\x00\x7c\x00\x00\xe0\x00\x00\xf0\x00\x00\x3e\x00\xc0\x07\x00\xe0'\ +b'\x00\x00\x20\x00\x00\x0e\x00\x60\x00\x00\xe0\x03\x00\x80\x3f\x00'\ +b'\x00\xf8\x00\x00\xf0\x00\x00\x3f\x00\xe0\x03\x00\xe0\x01\x00\xc0'\ +b'\x1f\x00\x00\xfc\x00\x00\xe0\x00\x00\x7e\x00\xe0\x07\x00\xe0\x00'\ +b'\x00\x0a\x00\x00\x00\x00\x60\xc0\x00\xe0\x60\x00\x80\x3b\x00\x00'\ +b'\x0f\x00\x00\x1f\x00\xc0\x71\x00\xe0\xe0\x00\x20\x80\x00\x00\x00'\ +b'\x00\x0a\x00\x20\x00\x00\xe0\x01\x0c\x80\x0f\x0c\x00\x7c\x0e\x00'\ +b'\xe0\x07\x00\xf0\x00\x00\x1e\x00\xc0\x07\x00\xe0\x00\x00\x00\x00'\ +b'\x00\x0a\x00\x60\xe0\x00\x60\xf0\x00\x60\xd8\x00\x60\xcc\x00\x60'\ +b'\xc6\x00\xe0\xc3\x00\xe0\xc1\x00\x60\xc0\x00\x00\x00\x00\x00\x00'\ +b'\x00\x07\x00\x00\x04\x00\x00\x0e\x00\xfc\xfb\x07\xfe\xfb\x0f\x06'\ +b'\x00\x0c\x00\x00\x00\x00\x00\x00\x05\x00\xfe\xff\x0f\xfe\xff\x0f'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x06\x00\x0c\xfe\xfb'\ +b'\x0f\xfc\xfb\x07\x00\x0e\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00'\ +b'\x0a\x00\x00\x03\x00\x80\x01\x00\x80\x01\x00\x00\x03\x00\x00\x02'\ +b'\x00\x00\x06\x00\x00\x06\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00'\ + +_index =\ +b'\x00\x00\x11\x00\x28\x00\x3f\x00\x62\x00\x85\x00\xbd\x00\xe6\x00'\ +b'\xf4\x00\x0b\x01\x22\x01\x3c\x01\x62\x01\x76\x01\x8d\x01\x9e\x01'\ +b'\xb2\x01\xd5\x01\xf8\x01\x1b\x02\x3e\x02\x61\x02\x84\x02\xa7\x02'\ +b'\xca\x02\xed\x02\x10\x03\x21\x03\x32\x03\x58\x03\x7e\x03\xa4\x03'\ +b'\xc7\x03\x05\x04\x2e\x04\x57\x04\x83\x04\xaf\x04\xd8\x04\xfe\x04'\ +b'\x2d\x05\x59\x05\x6d\x05\x90\x05\xb9\x05\xdc\x05\x11\x06\x40\x06'\ +b'\x72\x06\x9b\x06\xcd\x06\xf9\x06\x22\x07\x4b\x07\x77\x07\xa0\x07'\ +b'\xdb\x07\x04\x08\x30\x08\x56\x08\x6a\x08\x7e\x08\x92\x08\xaf\x08'\ +b'\xd5\x08\xe6\x08\x09\x09\x2c\x09\x4c\x09\x6f\x09\x92\x09\xa6\x09'\ +b'\xc9\x09\xec\x09\xfa\x09\x0b\x0a\x2b\x0a\x39\x0a\x6b\x0a\x8e\x0a'\ +b'\xb1\x0a\xd4\x0a\xf7\x0a\x0e\x0b\x2e\x0b\x42\x0b\x65\x0b\x85\x0b'\ +b'\xb1\x0b\xd1\x0b\xf1\x0b\x11\x0c\x28\x0c\x39\x0c\x50\x0c\x70\x0c'\ + + + +def _chr_addr(ordch): + offset = 2 * (ordch - 32) + return int.from_bytes(_index[offset:offset + 2], 'little') + +def get_ch(ch): + ordch = ord(ch) + ordch = ordch if ordch >= 32 and ordch <= 126 else ord('?') + offset = _chr_addr(ordch) + width = int.from_bytes(_font[offset:offset + 2], 'little') + next_offs = _chr_addr(ordch +1) + return memoryview(_font[offset + 2:next_offs]), 20, width + diff --git a/SSD1306/freeserif19.py b/SSD1306/freeserif19.py new file mode 100644 index 0000000..2d32467 --- /dev/null +++ b/SSD1306/freeserif19.py @@ -0,0 +1,242 @@ +# Code generated by font-to-py.py. +# Font: FreeSerif.ttf +version = '0.1' + +def height(): + return 19 + +def max_width(): + return 19 + +def hmap(): + return False + +def reverse(): + return False + +def monospaced(): + return False + +_font =\ +b'\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x07\x00\xfe\x31\x00\x7e\x30\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x1f\x00\x00\x0f\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x1f\x00\x00\x0f\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x0a\x00\x00\x02\x00\x20\x02\x00\x20\x3f\x00\xfc\x03\x00'\ +b'\x26\x02\x00\x20\x02\x00\xa0\x3f\x00\xfe\x02\x00\x22\x02\x00\x20'\ +b'\x00\x00\x0a\x00\x38\x1c\x00\x7c\x30\x00\x66\x20\x00\xc2\x20\x00'\ +b'\xff\x7f\x00\x82\x21\x00\x86\x31\x00\x0c\x1f\x00\x00\x0e\x00\x00'\ +b'\x00\x00\x11\x00\x78\x00\x00\xfc\x01\x00\x0c\x01\x00\x06\x21\x00'\ +b'\x82\x10\x00\xc2\x0c\x00\x3c\x03\x00\xc4\x00\x00\x24\x1e\x00\x1c'\ +b'\x3f\x00\x86\x23\x00\xc0\x20\x00\x40\x30\x00\x40\x18\x00\x80\x07'\ +b'\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x1e\x00\x00\x3f\x00\x80'\ +b'\x31\x00\xbc\x20\x00\xfe\x20\x00\xe1\x21\x00\xa1\x27\x00\x11\x1e'\ +b'\x00\x0e\x1c\x00\x20\x32\x00\xe0\x21\x00\x60\x20\x00\x20\x20\x00'\ +b'\x00\x10\x00\x00\x00\x00\x00\x00\x00\x04\x00\x1f\x00\x00\x0f\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x07\x00\xc0\x0f\x00\xf0\x3f\x00\x18'\ +b'\x60\x00\x04\x80\x00\x02\x00\x01\x00\x00\x00\x00\x00\x00\x07\x00'\ +b'\x02\x00\x01\x04\x80\x00\x18\x60\x00\xf0\x3f\x00\xc0\x0f\x00\x00'\ +b'\x00\x00\x00\x00\x00\x0a\x00\x4c\x00\x00\xb2\x01\x00\xfe\x01\x00'\ +b'\x30\x00\x00\x48\x00\x00\x4c\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x0b\x00\x00\x02\x00\x00\x02\x00\x00\x02\x00'\ +b'\x00\x02\x00\xe0\x3f\x00\x00\x02\x00\x00\x02\x00\x00\x02\x00\x00'\ +b'\x02\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x01\x00\xb0\x00'\ +b'\x00\x70\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x02\x00\x00\x02'\ +b'\x00\x00\x02\x00\x00\x02\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00'\ +b'\x05\x00\x00\x30\x00\x00\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x06\x00\x00\x20\x00\x00\x3c\x00\x80\x07\x00\xf0\x00\x00\x1e'\ +b'\x00\x00\x03\x00\x00\x0a\x00\xf0\x03\x00\xfc\x0f\x00\x06\x18\x00'\ +b'\x03\x30\x00\x01\x20\x00\x01\x20\x00\x03\x30\x00\x06\x18\x00\xfc'\ +b'\x0f\x00\xf0\x03\x00\x0a\x00\x02\x00\x00\x02\x20\x00\xff\x3f\x00'\ +b'\xff\x3f\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x0a\x00\x18\x20\x00\x04\x30\x00\x02\x38\x00'\ +b'\x02\x2c\x00\x02\x26\x00\x86\x21\x00\xfc\x20\x00\x38\x20\x00\x00'\ +b'\x10\x00\x00\x00\x00\x0a\x00\x04\x20\x00\x02\x20\x00\x42\x20\x00'\ +b'\x62\x20\x00\xe6\x20\x00\xfe\x10\x00\xcc\x0f\x00\x80\x07\x00\x00'\ +b'\x00\x00\x00\x00\x00\x0a\x00\x00\x07\x00\x80\x04\x00\x60\x04\x00'\ +b'\x10\x04\x00\x08\x04\x00\xfc\x3f\x00\xfe\x3f\x00\x00\x04\x00\x00'\ +b'\x00\x00\x00\x00\x00\x0a\x00\x00\x20\x00\x10\x20\x00\x3c\x20\x00'\ +b'\x32\x20\x00\x32\x20\x00\xe2\x10\x00\xe2\x0f\x00\xc2\x07\x00\x00'\ +b'\x00\x00\x00\x00\x00\x0a\x00\xe0\x07\x00\xf8\x1f\x00\x7c\x18\x00'\ +b'\x2c\x20\x00\x26\x20\x00\x22\x20\x00\x63\x30\x00\xc1\x1f\x00\x81'\ +b'\x0f\x00\x00\x00\x00\x0a\x00\x04\x00\x00\x02\x00\x00\x02\x00\x00'\ +b'\x02\x30\x00\x02\x0e\x00\xc2\x01\x00\x3a\x00\x00\x06\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x0a\x00\x1c\x0e\x00\x3e\x1f\x00\xf3\x30\x00'\ +b'\x61\x20\x00\xc1\x20\x00\xa3\x31\x00\x1e\x1f\x00\x1c\x0e\x00\x00'\ +b'\x00\x00\x00\x00\x00\x0a\x00\x7c\x00\x00\xfe\x40\x00\x83\x61\x00'\ +b'\x01\x31\x00\x01\x39\x00\x03\x1f\x00\xfe\x07\x00\xf8\x01\x00\x00'\ +b'\x00\x00\x00\x00\x00\x05\x00\x60\x30\x00\x60\x30\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x05\x00\x60\x00\x01\x60\xb0\x00\x00\x70'\ +b'\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x03\x00\x80\x03\x00\x80'\ +b'\x06\x00\xc0\x04\x00\x40\x0c\x00\x60\x08\x00\x20\x18\x00\x30\x10'\ +b'\x00\x10\x10\x00\x10\x30\x00\x00\x00\x00\x0b\x00\x80\x08\x00\x80'\ +b'\x08\x00\x80\x08\x00\x80\x08\x00\x80\x08\x00\x80\x08\x00\x80\x08'\ +b'\x00\x80\x08\x00\x80\x08\x00\x80\x08\x00\x00\x00\x00\x0b\x00\x30'\ +b'\x20\x00\x20\x20\x00\x20\x30\x00\x60\x10\x00\x40\x18\x00\xc0\x08'\ +b'\x00\x80\x0c\x00\x80\x05\x00\x00\x07\x00\x00\x03\x00\x00\x00\x00'\ +b'\x09\x00\x0e\x00\x00\x02\x00\x00\x01\x00\x00\x01\x30\x00\x81\x37'\ +b'\x00\x7f\x00\x00\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x11\x00\xe0'\ +b'\x03\x00\xf8\x07\x00\x1c\x0c\x00\x06\x18\x00\x82\x13\x00\xe1\x27'\ +b'\x00\x71\x24\x00\x11\x24\x00\x11\x22\x00\xe1\x27\x00\x72\x24\x00'\ +b'\x06\x14\x00\x0c\x02\x00\xf0\x01\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x0e\x00\x00\x20\x00\x00\x30\x00\x00\x38\x00\x00\x27\x00'\ +b'\xc0\x03\x00\x30\x02\x00\x0c\x02\x00\x3e\x02\x00\xf8\x02\x00\xc0'\ +b'\x23\x00\x00\x3f\x00\x00\x3c\x00\x00\x30\x00\x00\x20\x00\x0d\x00'\ +b'\x02\x20\x00\x02\x20\x00\xfe\x3f\x00\xfe\x3f\x00\x82\x20\x00\x82'\ +b'\x20\x00\x82\x20\x00\x82\x20\x00\x82\x20\x00\x46\x31\x00\x7c\x1f'\ +b'\x00\x38\x0e\x00\x00\x00\x00\x0d\x00\xf0\x03\x00\xfc\x0f\x00\x0e'\ +b'\x1c\x00\x02\x10\x00\x03\x30\x00\x01\x20\x00\x01\x20\x00\x01\x20'\ +b'\x00\x01\x20\x00\x02\x20\x00\x0e\x10\x00\x1f\x08\x00\x00\x00\x00'\ +b'\x0e\x00\x02\x20\x00\x02\x20\x00\xfe\x3f\x00\xfe\x3f\x00\x02\x20'\ +b'\x00\x02\x20\x00\x02\x20\x00\x02\x20\x00\x06\x20\x00\x04\x30\x00'\ +b'\x0c\x18\x00\x1c\x1c\x00\xf8\x0f\x00\xe0\x03\x00\x0c\x00\x02\x20'\ +b'\x00\xfe\x3f\x00\xfe\x3f\x00\x82\x20\x00\x82\x20\x00\x82\x20\x00'\ +b'\x82\x20\x00\x82\x20\x00\xc2\x21\x00\x06\x30\x00\x00\x08\x00\x00'\ +b'\x00\x00\x0b\x00\x02\x20\x00\xfe\x3f\x00\xfe\x3f\x00\x82\x20\x00'\ +b'\x82\x00\x00\x82\x00\x00\x82\x00\x00\x82\x00\x00\xc2\x01\x00\x06'\ +b'\x00\x00\x00\x00\x00\x0e\x00\xf0\x03\x00\xfc\x0f\x00\x0e\x1c\x00'\ +b'\x02\x10\x00\x03\x30\x00\x01\x20\x00\x01\x20\x00\x01\x20\x00\x01'\ +b'\x20\x00\x42\x20\x00\xc6\x1f\x00\xcf\x1f\x00\x40\x00\x00\x00\x00'\ +b'\x00\x0e\x00\x02\x20\x00\xfe\x3f\x00\xfe\x3f\x00\x82\x20\x00\x80'\ +b'\x00\x00\x80\x00\x00\x80\x00\x00\x80\x00\x00\x82\x20\x00\xfe\x3f'\ +b'\x00\xfe\x3f\x00\x02\x20\x00\x00\x00\x00\x00\x00\x00\x07\x00\x02'\ +b'\x20\x00\xfe\x3f\x00\xfe\x3f\x00\x02\x20\x00\x02\x20\x00\x00\x00'\ +b'\x00\x00\x00\x00\x08\x00\x00\x30\x00\x00\x30\x00\x00\x20\x00\x02'\ +b'\x20\x00\xfe\x1f\x00\xfe\x0f\x00\x02\x00\x00\x00\x00\x00\x0e\x00'\ +b'\x02\x20\x00\xfe\x3f\x00\xfe\x3f\x00\x82\x20\x00\xc0\x01\x00\xa0'\ +b'\x01\x00\x30\x03\x00\x1a\x26\x00\x0e\x3c\x00\x06\x38\x00\x02\x30'\ +b'\x00\x02\x20\x00\x00\x20\x00\x00\x00\x00\x0c\x00\x02\x20\x00\xfe'\ +b'\x3f\x00\xfe\x3f\x00\x02\x20\x00\x00\x20\x00\x00\x20\x00\x00\x20'\ +b'\x00\x00\x20\x00\x00\x20\x00\x00\x30\x00\x00\x38\x00\x00\x08\x00'\ +b'\x12\x00\x02\x00\x00\x02\x20\x00\xfe\x3f\x00\x1e\x20\x00\x7e\x00'\ +b'\x00\xf8\x01\x00\xe0\x03\x00\x80\x0f\x00\x00\x3e\x00\x00\x0c\x00'\ +b'\x00\x03\x00\xc0\x00\x00\x30\x00\x00\x0c\x20\x00\xfe\x3f\x00\xfe'\ +b'\x3f\x00\x02\x20\x00\x00\x00\x00\x0f\x00\x02\x20\x00\xfe\x3f\x00'\ +b'\x0e\x20\x00\x3c\x00\x00\x78\x00\x00\xe0\x00\x00\xc0\x01\x00\x80'\ +b'\x03\x00\x00\x0f\x00\x02\x1c\x00\xfe\x3f\x00\x02\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x0e\x00\xf0\x03\x00\xfc\x0f\x00\x0e'\ +b'\x1c\x00\x02\x10\x00\x01\x20\x00\x01\x20\x00\x01\x20\x00\x01\x20'\ +b'\x00\x02\x10\x00\x0e\x1c\x00\xfc\x0f\x00\xf0\x03\x00\x00\x00\x00'\ +b'\x00\x00\x00\x0c\x00\x02\x20\x00\xfe\x3f\x00\xfe\x3f\x00\x02\x21'\ +b'\x00\x02\x01\x00\x02\x01\x00\x02\x01\x00\x86\x01\x00\xfc\x00\x00'\ +b'\x78\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\xf0\x03\x00\xfc\x0f'\ +b'\x00\x0e\x18\x00\x02\x30\x00\x01\x20\x00\x01\x60\x00\x01\xe0\x00'\ +b'\x01\xe0\x01\x02\xb0\x01\x0e\x1c\x03\xfc\x0f\x02\xf0\x03\x02\x00'\ +b'\x00\x00\x00\x00\x00\x0d\x00\x02\x20\x00\xfe\x3f\x00\xfe\x3f\x00'\ +b'\x82\x20\x00\x82\x00\x00\x82\x03\x00\x82\x07\x00\x46\x0e\x00\x7c'\ +b'\x1c\x00\x38\x38\x00\x00\x30\x00\x00\x20\x00\x00\x00\x00\x0b\x00'\ +b'\x00\x04\x00\x1c\x38\x00\x3e\x10\x00\x73\x20\x00\x61\x20\x00\xc1'\ +b'\x20\x00\xc1\x20\x00\x82\x31\x00\x87\x1f\x00\x08\x0f\x00\x00\x00'\ +b'\x00\x0c\x00\x0e\x00\x00\x06\x00\x00\x02\x00\x00\x02\x00\x00\x02'\ +b'\x20\x00\xfe\x3f\x00\xfe\x3f\x00\x02\x20\x00\x02\x00\x00\x02\x00'\ +b'\x00\x06\x00\x00\x0e\x00\x00\x0e\x00\x02\x00\x00\xfe\x0f\x00\xfe'\ +b'\x1f\x00\x02\x30\x00\x00\x20\x00\x00\x20\x00\x00\x20\x00\x00\x20'\ +b'\x00\x00\x20\x00\x02\x10\x00\xfe\x0f\x00\x02\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x0e\x00\x02\x00\x00\x06\x00\x00\x0e\x00\x00\x3e\x00'\ +b'\x00\xf2\x00\x00\xc2\x03\x00\x00\x0f\x00\x00\x3c\x00\x00\x0e\x00'\ +b'\x80\x01\x00\x62\x00\x00\x1e\x00\x00\x06\x00\x00\x02\x00\x00\x13'\ +b'\x00\x02\x00\x00\x06\x00\x00\x1e\x00\x00\x7e\x00\x00\xe2\x03\x00'\ +b'\x80\x0f\x00\x02\x3e\x00\x02\x06\x00\xce\x01\x00\x3e\x00\x00\xf2'\ +b'\x01\x00\xc2\x07\x00\x00\x3f\x00\x00\x1c\x00\x80\x03\x00\x62\x00'\ +b'\x00\x1e\x00\x00\x06\x00\x00\x02\x00\x00\x0e\x00\x02\x20\x00\x02'\ +b'\x20\x00\x06\x30\x00\x0e\x28\x00\x1e\x26\x00\x72\x03\x00\xe0\x01'\ +b'\x00\xc0\x01\x00\xa0\x27\x00\x12\x2e\x00\x0a\x3c\x00\x06\x38\x00'\ +b'\x02\x30\x00\x02\x20\x00\x0e\x00\x02\x00\x00\x06\x00\x00\x0e\x00'\ +b'\x00\x1e\x00\x00\x3a\x20\x00\xf2\x20\x00\xc0\x3f\x00\x80\x3f\x00'\ +b'\x40\x20\x00\x22\x20\x00\x1a\x00\x00\x06\x00\x00\x02\x00\x00\x02'\ +b'\x00\x00\x0c\x00\x00\x20\x00\x0c\x30\x00\x06\x3c\x00\x02\x3e\x00'\ +b'\x02\x2f\x00\xc2\x23\x00\xe2\x20\x00\x72\x20\x00\x1e\x20\x00\x0e'\ +b'\x20\x00\x02\x30\x00\x00\x0c\x00\x07\x00\xfe\xff\x01\xfe\xff\x01'\ +b'\x02\x00\x01\x02\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06'\ +b'\x00\x03\x00\x00\x1e\x00\x00\xf0\x00\x00\x80\x07\x00\x00\x3c\x00'\ +b'\x00\x20\x00\x07\x00\x02\x00\x01\x02\x00\x01\xfe\xff\x01\xfe\xff'\ +b'\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x00\xc0'\ +b'\x00\x00\x70\x00\x00\x1c\x00\x00\x06\x00\x00\x0e\x00\x00\x38\x00'\ +b'\x00\xe0\x00\x00\x80\x00\x00\x0a\x00\x00\x40\x00\x00\x40\x00\x00'\ +b'\x40\x00\x00\x40\x00\x00\x40\x00\x00\x40\x00\x00\x40\x00\x00\x40'\ +b'\x00\x00\x40\x00\x00\x40\x00\x05\x00\x02\x00\x00\x04\x00\x00\x08'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\xc0\x18\x00\xe0\x3c\x00'\ +b'\x20\x22\x00\x20\x22\x00\xe0\x3f\x00\xc0\x3f\x00\x00\x20\x00\x00'\ +b'\x00\x00\x00\x00\x00\x0a\x00\x02\x00\x00\xfe\x1f\x00\xff\x3f\x00'\ +b'\x40\x20\x00\x20\x20\x00\x20\x20\x00\x60\x10\x00\xc0\x1f\x00\x80'\ +b'\x07\x00\x00\x00\x00\x09\x00\x00\x0f\x00\xc0\x1f\x00\x60\x30\x00'\ +b'\x20\x20\x00\x20\x20\x00\x60\x20\x00\x40\x10\x00\x00\x00\x00\x00'\ +b'\x00\x00\x0a\x00\x00\x0f\x00\xc0\x1f\x00\x60\x30\x00\x20\x20\x00'\ +b'\x20\x20\x00\x42\x20\x00\xfe\x3f\x00\xff\x3f\x00\x00\x00\x00\x00'\ +b'\x00\x00\x09\x00\x80\x0f\x00\xc0\x1f\x00\xc0\x38\x00\xa0\x30\x00'\ +b'\xa0\x20\x00\xa0\x20\x00\xe0\x20\x00\xc0\x18\x00\x00\x00\x00\x08'\ +b'\x00\x00\x20\x00\x20\x20\x00\xfc\x3f\x00\xfe\x3f\x00\x21\x20\x00'\ +b'\x21\x00\x00\x03\x00\x00\x03\x00\x00\x0a\x00\x00\x80\x03\x80\xf3'\ +b'\x07\xc0\x2b\x06\x20\x26\x04\x20\x24\x04\x60\x24\x04\xc0\x27\x04'\ +b'\xc0\x23\x02\x40\xc0\x01\x40\x00\x00\x0a\x00\x02\x20\x00\xfe\x3f'\ +b'\x00\xff\x3f\x00\x40\x20\x00\x20\x00\x00\x20\x00\x00\x20\x20\x00'\ +b'\xe0\x3f\x00\xc0\x3f\x00\x00\x20\x00\x06\x00\x00\x20\x00\x40\x20'\ +b'\x00\xc3\x3f\x00\xe3\x3f\x00\x00\x20\x00\x00\x00\x00\x07\x00\x00'\ +b'\x00\x04\x00\x00\x04\x00\x00\x04\x40\x00\x04\xe3\xff\x03\xe3\xff'\ +b'\x01\x00\x00\x00\x0a\x00\x02\x20\x00\xfe\x3f\x00\xff\x3f\x00\x00'\ +b'\x23\x00\x00\x07\x00\xa0\x2c\x00\x60\x38\x00\x20\x30\x00\x20\x20'\ +b'\x00\x00\x20\x00\x05\x00\x00\x20\x00\x02\x20\x00\xfe\x3f\x00\xff'\ +b'\x3f\x00\x00\x20\x00\x10\x00\x20\x20\x00\xe0\x3f\x00\xe0\x3f\x00'\ +b'\x40\x20\x00\x20\x00\x00\x20\x20\x00\xe0\x3f\x00\xc0\x3f\x00\x40'\ +b'\x20\x00\x20\x00\x00\x20\x20\x00\xe0\x3f\x00\xc0\x3f\x00\x00\x20'\ +b'\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x20\x20\x00\xe0\x3f\x00\xe0'\ +b'\x3f\x00\x40\x20\x00\x20\x00\x00\x20\x00\x00\x20\x20\x00\xe0\x3f'\ +b'\x00\xc0\x3f\x00\x00\x20\x00\x0a\x00\x80\x0f\x00\xc0\x1f\x00\x60'\ +b'\x38\x00\x20\x20\x00\x20\x20\x00\x20\x20\x00\xe0\x30\x00\xc0\x1f'\ +b'\x00\x80\x0f\x00\x00\x00\x00\x0a\x00\x20\x00\x04\xe0\xff\x07\xe0'\ +b'\xff\x07\x40\x20\x04\x20\x20\x00\x20\x20\x00\x60\x30\x00\xc0\x1f'\ +b'\x00\x80\x07\x00\x00\x00\x00\x0a\x00\x00\x0f\x00\xc0\x1f\x00\x60'\ +b'\x30\x00\x20\x20\x00\x20\x20\x00\x20\x20\x04\xc0\xff\x07\xe0\xff'\ +b'\x07\x00\x00\x04\x00\x00\x00\x07\x00\x00\x20\x00\xe0\x3f\x00\xe0'\ +b'\x3f\x00\x40\x20\x00\x20\x00\x00\x20\x00\x00\x00\x00\x00\x07\x00'\ +b'\xc0\x39\x00\x20\x13\x00\x20\x22\x00\x20\x26\x00\x40\x3e\x00\xe0'\ +b'\x1c\x00\x00\x00\x00\x06\x00\x20\x00\x00\xf0\x1f\x00\xf8\x3f\x00'\ +b'\x20\x20\x00\x00\x20\x00\x00\x00\x00\x0a\x00\x20\x00\x00\xe0\x1f'\ +b'\x00\xe0\x3f\x00\x00\x20\x00\x00\x20\x00\x00\x20\x00\x20\x10\x00'\ +b'\xe0\x3f\x00\xe0\x3f\x00\x00\x20\x00\x09\x00\x20\x00\x00\x60\x00'\ +b'\x00\xe0\x01\x00\x20\x07\x00\x00\x3c\x00\x00\x18\x00\x20\x07\x00'\ +b'\xe0\x00\x00\x20\x00\x00\x0e\x00\x20\x00\x00\xe0\x00\x00\xe0\x03'\ +b'\x00\x20\x0e\x00\x00\x38\x00\x20\x0c\x00\xe0\x02\x00\xe0\x03\x00'\ +b'\x20\x0e\x00\x00\x38\x00\x00\x0c\x00\xa0\x03\x00\x60\x00\x00\x20'\ +b'\x00\x00\x0a\x00\x20\x20\x00\x20\x30\x00\xe0\x28\x00\xe0\x05\x00'\ +b'\x00\x03\x00\xa0\x2e\x00\x60\x3c\x00\x20\x30\x00\x20\x20\x00\x00'\ +b'\x00\x00\x09\x00\x20\x00\x00\xe0\x00\x06\xe0\x03\x04\x20\x0f\x06'\ +b'\x00\xbc\x01\x00\x70\x00\x00\x0e\x00\xa0\x01\x00\x60\x00\x00\x08'\ +b'\x00\x60\x30\x00\x20\x38\x00\x20\x2c\x00\x20\x27\x00\xa0\x21\x00'\ +b'\xe0\x20\x00\x60\x30\x00\x00\x18\x00\x0a\x00\x00\x00\x00\x00\x03'\ +b'\x00\xfe\xff\x01\xff\xfc\x03\x01\x00\x02\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\xff\x3f\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x01\x00\x02\xff\xfc\x03\xfe'\ +b'\xff\x01\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x03\x00\x00'\ +b'\x01\x00\x00\x01\x00\x00\x01\x00\x00\x02\x00\x00\x02\x00\x00\x02'\ +b'\x00\x00\x03\x00\x00\x00\x00' + +_index =\ +b'\x00\x00\x11\x00\x28\x00\x42\x00\x62\x00\x82\x00\xb7\x00\xe9\x00'\ +b'\xf7\x00\x0e\x01\x25\x01\x45\x01\x68\x01\x79\x01\x90\x01\xa1\x01'\ +b'\xb5\x01\xd5\x01\xf5\x01\x15\x02\x35\x02\x55\x02\x75\x02\x95\x02'\ +b'\xb5\x02\xd5\x02\xf5\x02\x06\x03\x17\x03\x3a\x03\x5d\x03\x80\x03'\ +b'\x9d\x03\xd2\x03\xfe\x03\x27\x04\x50\x04\x7c\x04\xa2\x04\xc5\x04'\ +b'\xf1\x04\x1d\x05\x34\x05\x4e\x05\x7a\x05\xa0\x05\xd8\x05\x07\x06'\ +b'\x33\x06\x59\x06\x85\x06\xae\x06\xd1\x06\xf7\x06\x23\x07\x4f\x07'\ +b'\x8a\x07\xb6\x07\xe2\x07\x08\x08\x1f\x08\x33\x08\x4a\x08\x67\x08'\ +b'\x87\x08\x98\x08\xb5\x08\xd5\x08\xf2\x08\x12\x09\x2f\x09\x49\x09'\ +b'\x69\x09\x89\x09\x9d\x09\xb4\x09\xd4\x09\xe5\x09\x17\x0a\x37\x0a'\ +b'\x57\x0a\x77\x0a\x97\x0a\xae\x0a\xc5\x0a\xd9\x0a\xf9\x0a\x16\x0b'\ +b'\x42\x0b\x62\x0b\x7f\x0b\x99\x0b\xb9\x0b\xc7\x0b\xe7\x0b\x07\x0c'\ + + + +def _chr_addr(ordch): + offset = 2 * (ordch - 32) + return int.from_bytes(_index[offset:offset + 2], 'little') + +def get_ch(ch): + ordch = ord(ch) + ordch = ordch if ordch >= 32 and ordch <= 126 else ord('?') + offset = _chr_addr(ordch) + width = int.from_bytes(_font[offset:offset + 2], 'little') + next_offs = _chr_addr(ordch +1) + return memoryview(_font[offset + 2:next_offs]), 19, width + diff --git a/SSD1306/inconsolata14.py b/SSD1306/inconsolata14.py new file mode 100644 index 0000000..7037eb4 --- /dev/null +++ b/SSD1306/inconsolata14.py @@ -0,0 +1,156 @@ +# Code generated by font-to-py.py. +# Font: Inconsolata.otf +version = '0.1' + +def height(): + return 14 + +def max_width(): + return 8 + +def hmap(): + return False + +def reverse(): + return False + +def monospaced(): + return True + +_font =\ +b'\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x08\x00\xff\x06\x3f\x06\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x08\x00\x0f\x00\x02\x00\x00\x00\x0f\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x08\x00\x90\x00\x90\x04\xfc\x07\x8e\x00'\ +b'\x88\x07\xfe\x03\x8a\x00\x08\x00\x08\x00\x18\x03\x34\x06\x26\x04'\ +b'\xff\x0f\x46\x06\xcc\x03\x00\x00\x00\x00\x08\x00\x0c\x00\x1e\x06'\ +b'\x92\x03\xce\x00\x30\x03\x8c\x04\x86\x04\x00\x03\x08\x00\x00\x01'\ +b'\xcc\x07\x7e\x04\x62\x04\xd2\x04\x8c\x03\xc0\x07\x80\x04\x08\x00'\ +b'\x08\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x08\x00\xf0\x01\xbc\x07\x06\x0c\x02\x10\x01\x30\x00\x00\x00\x00'\ +b'\x00\x00\x08\x00\x03\x30\x02\x10\x06\x0c\x38\x07\xf0\x01\x00\x00'\ +b'\x00\x00\x00\x00\x08\x00\x00\x00\x30\x01\xa0\x01\x7c\x00\xfc\x00'\ +b'\xa0\x01\x30\x01\x00\x00\x08\x00\x20\x00\x20\x00\xfc\x01\xfc\x01'\ +b'\x20\x00\x20\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x16\x00\x0e'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x20\x00\x20\x00'\ +b'\x20\x00\x20\x00\x20\x00\x20\x00\x00\x00\x00\x00\x08\x00\x00\x06'\ +b'\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00'\ +b'\x00\x04\x00\x07\xe0\x01\x38\x00\x0e\x00\x03\x00\x00\x00\x00\x00'\ +b'\x08\x00\xf8\x01\x86\x07\xc2\x04\x32\x04\x1e\x06\xf8\x03\x00\x00'\ +b'\x00\x00\x08\x00\x04\x00\x04\x00\x02\x00\xfe\x07\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x08\x00\x04\x06\x06\x07\x82\x05\xc2\x04\x66\x04'\ +b'\x1c\x04\x00\x00\x00\x00\x08\x00\x00\x02\x02\x04\x22\x04\x22\x04'\ +b'\x5e\x06\x8c\x03\x00\x00\x00\x00\x08\x00\xc0\x00\xb0\x00\x98\x00'\ +b'\x86\x00\xfe\x07\x80\x00\x00\x00\x00\x00\x08\x00\x3c\x02\x3e\x06'\ +b'\x32\x04\x32\x04\x22\x06\xe2\x03\x00\x00\x00\x00\x08\x00\xf8\x01'\ +b'\x6c\x07\x32\x04\x32\x04\x22\x06\xc2\x03\x00\x00\x00\x00\x08\x00'\ +b'\x02\x00\x02\x06\x82\x07\xf2\x00\x1e\x00\x06\x00\x00\x00\x00\x00'\ +b'\x08\x00\x8c\x03\x5e\x06\x22\x04\x22\x04\x5e\x06\xcc\x03\x00\x00'\ +b'\x00\x00\x08\x00\x3c\x00\x66\x04\x42\x04\x42\x04\x66\x03\xfc\x01'\ +b'\x00\x00\x00\x00\x08\x00\x30\x06\x30\x06\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x30\x16\x30\x0e\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x20\x00\x60\x00\x70\x00'\ +b'\x90\x00\x98\x01\x08\x01\x0c\x03\x00\x02\x08\x00\x90\x00\x90\x00'\ +b'\x90\x00\x90\x00\x90\x00\x90\x00\x00\x00\x00\x00\x08\x00\x00\x02'\ +b'\x0c\x03\x08\x01\x98\x01\x90\x00\x70\x00\x60\x00\x20\x00\x08\x00'\ +b'\x06\x00\x03\x00\x81\x06\xe1\x06\x3f\x00\x1e\x00\x00\x00\x00\x00'\ +b'\x08\x00\x70\x00\xfc\x03\x06\x06\xf2\x04\x92\x04\x92\x04\xfc\x06'\ +b'\xf8\x00\x08\x00\x00\x04\x80\x07\xf0\x00\x9e\x00\xbc\x00\xe0\x00'\ +b'\x80\x07\x00\x04\x08\x00\xfe\x07\x22\x04\x22\x04\x22\x04\x76\x06'\ +b'\xdc\x03\x00\x00\x00\x00\x08\x00\xfc\x03\x06\x06\x02\x04\x02\x04'\ +b'\x02\x04\x06\x02\x00\x00\x00\x00\x08\x00\xfe\x07\x02\x04\x02\x04'\ +b'\x02\x04\x06\x02\xfc\x01\x00\x00\x00\x00\x08\x00\xfe\x07\x22\x04'\ +b'\x22\x04\x22\x04\x22\x04\x02\x04\x00\x00\x00\x00\x08\x00\xfe\x07'\ +b'\xfe\x07\x22\x00\x22\x00\x22\x00\x02\x00\x00\x00\x00\x00\x08\x00'\ +b'\x60\x00\xfc\x03\x06\x06\x02\x04\x42\x04\x42\x04\xc6\x07\xc0\x03'\ +b'\x08\x00\xfe\x07\x20\x00\x20\x00\x20\x00\x20\x00\xfe\x07\x00\x00'\ +b'\x00\x00\x08\x00\x02\x04\x02\x04\xfe\x07\xfe\x07\x02\x04\x00\x04'\ +b'\x00\x00\x00\x00\x08\x00\x00\x06\x00\x04\x02\x04\x02\x06\xfe\x03'\ +b'\x02\x00\x00\x00\x00\x00\x08\x00\xfe\x07\x20\x00\x78\x00\xcc\x01'\ +b'\x06\x03\x02\x06\x00\x00\x00\x00\x08\x00\xfe\x07\x00\x04\x00\x04'\ +b'\x00\x04\x00\x04\x00\x04\x00\x00\x00\x00\x08\x00\xfe\x07\x18\x00'\ +b'\x60\x00\x60\x00\x18\x00\xfe\x07\xfe\x07\x00\x00\x08\x00\xfe\x07'\ +b'\x0c\x00\x30\x00\xe0\x00\x80\x03\xfe\x07\x00\x00\x00\x00\x08\x00'\ +b'\xf0\x00\xfc\x03\x06\x06\x02\x04\x02\x04\x06\x06\xfc\x03\xf0\x00'\ +b'\x08\x00\xfe\x07\x62\x00\x62\x00\x62\x00\x26\x00\x3c\x00\x00\x00'\ +b'\x00\x00\x08\x00\xf0\x00\xfc\x03\x06\x06\x02\x0c\x02\x1c\x06\x16'\ +b'\xfc\x13\xf0\x00\x08\x00\xfe\x07\x62\x00\x62\x00\xe2\x00\xa6\x03'\ +b'\x3c\x06\x00\x00\x00\x00\x08\x00\x1c\x02\x36\x04\x22\x04\x62\x04'\ +b'\x42\x06\xc4\x03\x00\x00\x00\x00\x08\x00\x02\x00\x02\x00\x02\x00'\ +b'\xfe\x07\xfe\x07\x02\x00\x02\x00\x02\x00\x08\x00\xfe\x03\x00\x06'\ +b'\x00\x04\x00\x04\x00\x06\xfe\x03\x00\x00\x00\x00\x08\x00\x02\x00'\ +b'\x1e\x00\xf8\x00\xc0\x07\x80\x07\xf0\x00\x1e\x00\x02\x00\x08\x00'\ +b'\x06\x00\xfe\x03\x80\x07\x78\x00\x7c\x00\xc0\x07\xf8\x03\x0e\x00'\ +b'\x08\x00\x00\x00\x06\x06\x8c\x03\xf0\x00\xf0\x00\x8c\x03\x02\x06'\ +b'\x00\x00\x08\x00\x02\x00\x06\x00\x1c\x00\xf0\x07\xe0\x07\x38\x00'\ +b'\x06\x00\x00\x00\x08\x00\x02\x06\x82\x07\xe2\x04\x32\x04\x1e\x04'\ +b'\x06\x04\x00\x04\x00\x00\x08\x00\xff\x0f\x01\x08\x01\x08\x01\x08'\ +b'\x01\x08\x00\x00\x00\x00\x00\x00\x08\x00\x03\x00\x0e\x00\x38\x00'\ +b'\xe0\x01\x00\x07\x00\x04\x00\x00\x00\x00\x08\x00\x01\x08\x01\x08'\ +b'\x01\x08\x01\x08\xff\x0f\x00\x00\x00\x00\x00\x00\x08\x00\x20\x00'\ +b'\x18\x00\x0e\x00\x0e\x00\x18\x00\x00\x00\x00\x00\x00\x00\x08\x00'\ +b'\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08'\ +b'\x08\x00\x03\x00\x0e\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ +b'\x00\x00\x08\x00\x90\x07\x90\x04\x98\x04\xd8\x04\xd0\x06\xf0\x07'\ +b'\x00\x00\x00\x00\x08\x00\xff\x07\x10\x06\x18\x04\x18\x04\x10\x06'\ +b'\xf0\x03\x00\x00\x00\x00\x08\x00\xe0\x03\x30\x06\x18\x04\x18\x04'\ +b'\x18\x04\x30\x06\x00\x00\x00\x00\x08\x00\xf0\x03\x10\x06\x08\x04'\ +b'\x18\x04\x30\x02\xff\x07\x00\x00\x00\x00\x08\x00\xe0\x03\xd0\x06'\ +b'\xc8\x04\xc8\x04\xd0\x04\xf0\x02\x00\x00\x00\x00\x08\x00\x10\x00'\ +b'\xfc\x07\xfe\x07\x11\x00\x11\x00\x03\x00\x02\x00\x00\x00\x08\x00'\ +b'\x00\x00\xf0\x1f\x98\x37\x88\x27\x98\x26\xf0\x34\x08\x1c\x08\x00'\ +b'\x08\x00\xff\x07\x30\x00\x10\x00\x18\x00\x18\x00\xf0\x07\x00\x00'\ +b'\x00\x00\x08\x00\x00\x04\x18\x04\xfb\x07\xfb\x07\x00\x04\x00\x00'\ +b'\x00\x00\x00\x00\x08\x00\x00\x18\x18\x30\x18\x20\x1a\x18\xfb\x1f'\ +b'\x00\x00\x00\x00\x00\x00\x08\x00\xff\x07\x80\x00\xc0\x00\xa0\x01'\ +b'\x10\x03\x08\x06\x00\x00\x00\x00\x08\x00\x01\x04\x01\x04\xff\x07'\ +b'\xff\x07\x00\x04\x00\x04\x00\x00\x00\x00\x08\x00\xf8\x07\xf8\x07'\ +b'\x08\x00\xf8\x07\xf0\x07\x08\x00\xf8\x07\xf0\x07\x08\x00\xf8\x07'\ +b'\x30\x00\x10\x00\x18\x00\x18\x00\xf0\x07\x00\x00\x00\x00\x08\x00'\ +b'\xe0\x03\x10\x06\x18\x04\x18\x04\x10\x06\xf0\x03\x00\x00\x00\x00'\ +b'\x08\x00\xf8\x3f\x10\x06\x18\x04\x18\x04\x10\x06\xf0\x03\x80\x00'\ +b'\x00\x00\x08\x00\xf0\x03\x10\x06\x08\x04\x18\x04\x10\x02\xf8\x3f'\ +b'\x00\x00\x00\x00\x08\x00\xf8\x07\xf8\x07\x10\x00\x18\x00\x18\x00'\ +b'\x10\x00\x00\x00\x00\x00\x08\x00\x20\x02\x70\x04\xc8\x04\xc8\x04'\ +b'\x98\x04\x90\x03\x00\x00\x00\x00\x08\x00\x18\x00\x18\x00\xfe\x07'\ +b'\x18\x04\x18\x04\x18\x06\x00\x00\x00\x00\x08\x00\xf8\x03\x00\x06'\ +b'\x00\x04\x00\x04\x00\x02\xf8\x07\x00\x00\x00\x00\x08\x00\x08\x00'\ +b'\x38\x00\xe0\x01\x80\x07\x00\x07\xc0\x01\x38\x00\x00\x00\x08\x00'\ +b'\x38\x00\xf8\x03\x00\x06\xf0\x01\xf0\x00\x80\x07\xf8\x07\x38\x00'\ +b'\x08\x00\x18\x04\x30\x03\xe0\x01\xe0\x01\x30\x03\x18\x04\x00\x00'\ +b'\x00\x00\x08\x00\x00\x10\x38\x20\xe0\x30\x80\x1f\x00\x0f\xc0\x01'\ +b'\x78\x00\x08\x00\x08\x00\x18\x06\x18\x07\x98\x05\x78\x04\x38\x04'\ +b'\x18\x04\x00\x00\x00\x00\x08\x00\x40\x00\xf8\x0f\x3e\x1f\x02\x10'\ +b'\x02\x30\x02\x30\x00\x00\x00\x00\x08\x00\xff\x1f\xff\x1f\x00\x00'\ +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x02\x30\x02\x30'\ +b'\x02\x10\x3e\x1f\xf8\x0f\x40\x00\x00\x00\x00\x00\x08\x00\x00\x00'\ +b'\x30\x00\x18\x00\x18\x00\x30\x00\x20\x00\x10\x00\x10\x00' + +_index =\ +b'\x00\x00\x12\x00\x24\x00\x36\x00\x48\x00\x5a\x00\x6c\x00\x7e\x00'\ +b'\x90\x00\xa2\x00\xb4\x00\xc6\x00\xd8\x00\xea\x00\xfc\x00\x0e\x01'\ +b'\x20\x01\x32\x01\x44\x01\x56\x01\x68\x01\x7a\x01\x8c\x01\x9e\x01'\ +b'\xb0\x01\xc2\x01\xd4\x01\xe6\x01\xf8\x01\x0a\x02\x1c\x02\x2e\x02'\ +b'\x40\x02\x52\x02\x64\x02\x76\x02\x88\x02\x9a\x02\xac\x02\xbe\x02'\ +b'\xd0\x02\xe2\x02\xf4\x02\x06\x03\x18\x03\x2a\x03\x3c\x03\x4e\x03'\ +b'\x60\x03\x72\x03\x84\x03\x96\x03\xa8\x03\xba\x03\xcc\x03\xde\x03'\ +b'\xf0\x03\x02\x04\x14\x04\x26\x04\x38\x04\x4a\x04\x5c\x04\x6e\x04'\ +b'\x80\x04\x92\x04\xa4\x04\xb6\x04\xc8\x04\xda\x04\xec\x04\xfe\x04'\ +b'\x10\x05\x22\x05\x34\x05\x46\x05\x58\x05\x6a\x05\x7c\x05\x8e\x05'\ +b'\xa0\x05\xb2\x05\xc4\x05\xd6\x05\xe8\x05\xfa\x05\x0c\x06\x1e\x06'\ +b'\x30\x06\x42\x06\x54\x06\x66\x06\x78\x06\x8a\x06\x9c\x06\xae\x06'\ + + + +def _chr_addr(ordch): + offset = 2 * (ordch - 32) + return int.from_bytes(_index[offset:offset + 2], 'little') + +def get_ch(ch): + ordch = ord(ch) + ordch = ordch if ordch >= 32 and ordch <= 126 else ord('?') + offset = _chr_addr(ordch) + width = int.from_bytes(_font[offset:offset + 2], 'little') + next_offs = _chr_addr(ordch +1) + return memoryview(_font[offset + 2:next_offs]), 14, width + diff --git a/SSD1306/ssd1306.py b/SSD1306/ssd1306.py new file mode 100644 index 0000000..ad57725 --- /dev/null +++ b/SSD1306/ssd1306.py @@ -0,0 +1,161 @@ +# MicroPython SSD1306 OLED driver, I2C and SPI interfaces + +from micropython import const +import time +import framebuf + + +# register definitions +SET_CONTRAST = const(0x81) +SET_ENTIRE_ON = const(0xa4) +SET_NORM_INV = const(0xa6) +SET_DISP = const(0xae) +SET_MEM_ADDR = const(0x20) +SET_COL_ADDR = const(0x21) +SET_PAGE_ADDR = const(0x22) +SET_DISP_START_LINE = const(0x40) +SET_SEG_REMAP = const(0xa0) +SET_MUX_RATIO = const(0xa8) +SET_COM_OUT_DIR = const(0xc0) +SET_DISP_OFFSET = const(0xd3) +SET_COM_PIN_CFG = const(0xda) +SET_DISP_CLK_DIV = const(0xd5) +SET_PRECHARGE = const(0xd9) +SET_VCOM_DESEL = const(0xdb) +SET_CHARGE_PUMP = const(0x8d) + + +class SSD1306: + def __init__(self, width, height, external_vcc): + self.width = width + self.height = height + self.external_vcc = external_vcc + self.pages = self.height // 8 + self.buffer = bytearray(self.pages * self.width) + self.framebuf = framebuf.FrameBuffer1(self.buffer, self.width, self.height) + self.poweron() + self.init_display() + + def init_display(self): + for cmd in ( + SET_DISP | 0x00, # off + # address setting + SET_MEM_ADDR, 0x00, # horizontal + # resolution and layout + SET_DISP_START_LINE | 0x00, + SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0 + SET_MUX_RATIO, self.height - 1, + SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0 + SET_DISP_OFFSET, 0x00, + SET_COM_PIN_CFG, 0x02 if self.height == 32 else 0x12, + # timing and driving scheme + SET_DISP_CLK_DIV, 0x80, + SET_PRECHARGE, 0x22 if self.external_vcc else 0xf1, + SET_VCOM_DESEL, 0x30, # 0.83*Vcc + # display + SET_CONTRAST, 0xff, # maximum + SET_ENTIRE_ON, # output follows RAM contents + SET_NORM_INV, # not inverted + # charge pump + SET_CHARGE_PUMP, 0x10 if self.external_vcc else 0x14, + SET_DISP | 0x01): # on + self.write_cmd(cmd) + self.fill(0) + self.show() + + def poweroff(self): + self.write_cmd(SET_DISP | 0x00) + + def contrast(self, contrast): + self.write_cmd(SET_CONTRAST) + self.write_cmd(contrast) + + def invert(self, invert): + self.write_cmd(SET_NORM_INV | (invert & 1)) + + def show(self): + x0 = 0 + x1 = self.width - 1 + if self.width == 64: + # displays with width of 64 pixels are shifted by 32 + x0 += 32 + x1 += 32 + self.write_cmd(SET_COL_ADDR) + self.write_cmd(x0) + self.write_cmd(x1) + self.write_cmd(SET_PAGE_ADDR) + self.write_cmd(0) + self.write_cmd(self.pages - 1) + self.write_data(self.buffer) + + def fill(self, col): + self.framebuf.fill(col) + + def pixel(self, x, y, col): + self.framebuf.pixel(x, y, col) + + def scroll(self, dx, dy): + self.framebuf.scroll(dx, dy) + + def text(self, string, x, y, col=1): + self.framebuf.text(string, x, y, col) + + +class SSD1306_I2C(SSD1306): + def __init__(self, width, height, i2c, addr=0x3c, external_vcc=False): + self.i2c = i2c + self.addr = addr + self.temp = bytearray(2) + super().__init__(width, height, external_vcc) + + def write_cmd(self, cmd): + self.temp[0] = 0x80 # Co=1, D/C#=0 + self.temp[1] = cmd + self.i2c.writeto(self.addr, self.temp) + + def write_data(self, buf): + self.temp[0] = self.addr << 1 + self.temp[1] = 0x40 # Co=0, D/C#=1 + self.i2c.start() + self.i2c.write(self.temp) + self.i2c.write(buf) + self.i2c.stop() + + def poweron(self): + pass + + +class SSD1306_SPI(SSD1306): + def __init__(self, width, height, spi, dc, res, cs, external_vcc=False): + self.rate = 10 * 1024 * 1024 + dc.init(dc.OUT, value=0) + res.init(res.OUT, value=0) + cs.init(cs.OUT, value=1) + self.spi = spi + self.dc = dc + self.res = res + self.cs = cs + super().__init__(width, height, external_vcc) + + def write_cmd(self, cmd): + self.spi.init(baudrate=self.rate, polarity=0, phase=0) + self.cs.high() + self.dc.low() + self.cs.low() + self.spi.write(bytearray([cmd])) + self.cs.high() + + def write_data(self, buf): + self.spi.init(baudrate=self.rate, polarity=0, phase=0) + self.cs.high() + self.dc.high() + self.cs.low() + self.spi.write(buf) + self.cs.high() + + def poweron(self): + self.res.high() + time.sleep_ms(1) + self.res.low() + time.sleep_ms(10) + self.res.high() diff --git a/SSD1306/ssd1306_drv.py b/SSD1306/ssd1306_drv.py new file mode 100644 index 0000000..4c34788 --- /dev/null +++ b/SSD1306/ssd1306_drv.py @@ -0,0 +1,122 @@ +# ssd1306_drv.py An implementation of a Display class for SSD1306 based displays +# V0.1 Peter Hinch Nov 2016 + +# https://learn.adafruit.com/monochrome-oled-breakouts/wiring-128x32-spi-oled-display +# https://www.proto-pic.co.uk/monochrome-128x32-oled-graphic-display.html + +# Version supports vertical and "horizontal" modes. + +# The MIT License (MIT) +# +# Copyright (c) 2016 Peter Hinch +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +# SSD1306 classes to fix the official one whose scroll method is broken +# This also demonstrates a way to do scrolling for devices with true vertical +# mapping (the official driver sets the device into its "horizontal" mode). +# This is a hybrid mode where bytes are aligned vertically but arranged +# horizontally + +import ssd1306 + +class SSD1306(object): + def __init__(self, device): + self.width = device.width # In pixels + self.height = device.height + self.bpc = (self.height + 7) >> 3 + self.device = device + self.vmap = False # Currently the official driver uses "horizontal" + + @property + def buffer(self): # property emulates underlying device + return self.device.buffer + + def show(self): + self.device.show() + + # Return map-independent offset into buffer + def _offset(self, x, y): + if self.vmap: + return y + x * self.bpc + else: + return y * self.width + x + + def scroll(self, x, y): + dy = abs(y) + if dy: + self._scrolly(dy, y > 0) + dx = abs(x) + if dx: + self._scrollx(dx, x > 0) + + def _scrolly(self, ystep, down): + buf = self.device.buffer + bpc = self.bpc + ystep_bytes = (ystep >> 3) + 1 + ystep_bits = ystep & 7 + if down: + for x in range(self.width): + for ydest in range(bpc - 1, -1, -1): + ysource = ydest - ystep_bytes + data = 0 + if ysource + 1 >= 0: + data = buf[self._offset(x, ysource + 1)] << ystep_bits + if ysource >= 0: + data |= buf[self._offset(x, ysource)] >> 8 - ystep_bits + buf[self._offset(x, ydest)] = data + else: + for x in range(self.width): + for ydest in range(bpc): + ysource = ydest + ystep_bytes + data = 0 + if ysource < bpc: + data = buf[self._offset(x, ysource)] << (8-ystep_bits) + if ysource - 1 < bpc: + data |= buf[self._offset(x, ysource - 1)] >> ystep_bits + buf[self._offset(x, ydest)] = data + + def _scrollx(self, xstep, right): # scroll x + buf = self.device.buffer + bpc = self.bpc + for y in range(bpc): + if right: # Scroll right + for xdest in range(self.width - 1, -1, -1): + data = 0 + xsource = xdest - xstep + if xsource >= 0: + data = buf[self._offset(xsource, y)] + buf[self._offset(xdest, y)] = data + else: + for xdest in range(0, self.width): + data = 0 + xsource = xdest + xstep + if xsource < self.width: + data = buf[self._offset(xsource, y)] + buf[self._offset(xdest, y)] = data + +class SSD1306_I2C(SSD1306): + def __init__(self, width, height, i2c, addr=0x3c, external_vcc=False): + device = ssd1306.SSD1306_I2C(width, height, i2c, addr, external_vcc) + super().__init__(device) + +class SSD1306_SPI(SSD1306): + def __init__(self, width, height, spi, dc, res, cs, external_vcc=False): + device = ssd1306.SSD1306_SPI(width, height, spi, dc, res, cs, external_vcc) + super().__init__(device) diff --git a/SSD1306/ssd1306_test.py b/SSD1306/ssd1306_test.py new file mode 100644 index 0000000..57d305d --- /dev/null +++ b/SSD1306/ssd1306_test.py @@ -0,0 +1,76 @@ +# ssd1306_test.py Demo pogram for rendering arbitrary fonts to an SSD1306 OLED display + +# The MIT License (MIT) +# +# Copyright (c) 2016 Peter Hinch +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + + +# https://learn.adafruit.com/monochrome-oled-breakouts/wiring-128x32-spi-oled-display +# https://www.proto-pic.co.uk/monochrome-128x32-oled-graphic-display.html + +import machine +from ssd1306_drv import SSD1306_SPI, SSD1306_I2C +from writer import Writer + +# Fonts +import freesans20 +#import freeserif19 +#import inconsolata16 + +WIDTH = const(128) +SPI = False + +if SPI: + # Pyb SSD + # 3v3 Vin + # Gnd Gnd + # X1 DC + # X2 CS + # X3 Rst + # X6 CLK + # X8 DATA + HEIGHT = 32 + pdc = machine.Pin('X1', machine.Pin.OUT_PP) + pcs = machine.Pin('X2', machine.Pin.OUT_PP) + prst = machine.Pin('X3', machine.Pin.OUT_PP) + spi = machine.SPI(1) + ssd = SSD1306_SPI(WIDTH, HEIGHT, spi, pdc, prst, pcs) +else: # I2C + # Pyb SSD + # 3v3 Vin + # Gnd Gnd + # Y9 CLK + # Y10 DATA + HEIGHT = 64 + pscl = machine.Pin('Y9', machine.Pin.OUT_PP) + psda = machine.Pin('Y10', machine.Pin.OUT_PP) + i2c = machine.I2C(scl=pscl, sda=psda) + ssd = SSD1306_I2C(WIDTH, HEIGHT, i2c) + +#wri = Writer(ssd, freeserif19) +wri2 = Writer(ssd, freesans20) +Writer.set_clip(True, True) +wri2.printstring('Tuesday\n') +wri2.printstring('8 Nov 2016\n') +wri2.printstring('10.30am') + +ssd.show() + diff --git a/SSD1306/writer.py b/SSD1306/writer.py new file mode 100644 index 0000000..c97be20 --- /dev/null +++ b/SSD1306/writer.py @@ -0,0 +1,123 @@ +# writer.py Implements the Writer class. +# V0.1 Peter Hinch Nov 2016 + +# The MIT License (MIT) +# +# Copyright (c) 2016 Peter Hinch +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +# A Writer supports rendering text to a Display instance in a given font. +# Currently supports vertical mapping and the SSD1306 "pseudo-horizontal" map +# only +# Multiple Writer instances may be created, each rendering a font to the +# same Display object. + +VERT = 0 +HORIZ = 1 +WEIRD = 2 + +class Writer(object): + text_row = 0 # attributes common to all Writer instances + text_col = 0 + row_clip = False # Clip or scroll when screen full + col_clip = False # Clip or new line when row is full + bmap = WEIRD # SSD1306 pseudo-horizontal + + @classmethod + def set_textpos(cls, row, col): + cls.text_row = row + cls.text_col = col + + @classmethod + def set_clip(cls, row_clip, col_clip): + cls.row_clip = row_clip + cls.col_clip = col_clip + + @classmethod + def mapping(cls, bmap): + if bmap in (VERT, HORIZ): + cls.bmap = bmap + else: + raise ValueError('Unsupported mapping') + + def __init__(self, device, font): + super().__init__() + self.device = device + self.font = font + if font.hmap(): + raise OSError('Font must be vertically mapped') + self.screenwidth = device.width # In pixels + self.screenheight = device.height + div, mod = divmod(device.height, 8) + self.bytes_per_col = div + 1 if mod else div + + def _newline(self): + height = self.font.height() + Writer.text_row += height + Writer.text_col = 0 + margin = self.screenheight - (Writer.text_row + height) + if margin < 0: + if not Writer.row_clip: + self.device.scroll(0, margin) + Writer.text_row += margin + + def printstring(self, string): + for char in string: + self._printchar(char) + + def _printchar(self, char): + bmap = Writer.bmap # Buffer mapping + if char == '\n': + self._newline() + return + fbuff = self.device.buffer + glyph, char_height, char_width = self.font.get_ch(char) + if Writer.text_row+char_height > self.screenheight and Writer.row_clip: + return + if Writer.text_col + char_width > self.screenwidth: + if Writer.col_clip: + return + else: + self._newline() + div, mod = divmod(char_height, 8) + gbytes = div + 1 if mod else div # No. of bytes per column of glyph + start_row, align = divmod(Writer.text_row, 8) + for scol in range(0, char_width): # Source column + dcol = scol + Writer.text_col # Destination column + dest_row_byte = start_row + for gbyte in range(gbytes): # Each glyph byte in column + if bmap == VERT: + dest = dcol * self.bytes_per_col + dest_row_byte + elif bmap == WEIRD: + dest = dcol + dest_row_byte * self.screenwidth + source = scol * gbytes + gbyte + data = fbuff[dest] & (0xff >> (8 - align)) + fbuff[dest] = data | glyph[source] << align + if align and (dest_row_byte + 1) < self.bytes_per_col: + if bmap == VERT: + dest += 1 + elif bmap == WEIRD: + dest += self.screenwidth + data = fbuff[dest] & (0xff << align) + fbuff[dest] = data | glyph[source] >> (8 - align) + dest_row_byte += 1 + if dest_row_byte >= self.bytes_per_col: + break + Writer.text_col += char_width