diff --git a/README.md b/README.md index c9f207d..df58067 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,52 @@ # micropython-ssd1306 -A fork of the driver for SSD1306 displays to make it available on PyPi +This is a fork of the driver for SSD1306 displays which is hosted in the +[Micropython package](https://github.com/micropython/micropython). The purpose +of this fork is to make the driver available on PyPi and thus installable via +the upip package manager. + +## Installation +Use the upip package manager: + + upip.install('micropython-ssd1306') + +If your board or your computer doesn't have an active internet connection you +can also clone this project on your local drive and copy the *ssd1306.py* to +your board. + +## Example Usage +This shows an example usage on an *ESP32* board with an *SSD1306* display +with an resolution of 128x32 pixels. The display is connected via I2C. On the +*ESP32* the I2C pins are: SDA: 23, SCL: 22. + +First we set up the I2C bus on our *ESP32* and scan for devices. + + >>> import machine + >>> i2c = machine.I2C(sda=machine.Pin(23), scl=machine.Pin(22)) + >>> i2c.scan() + [60] + +This shows us that there is a device on address 60 which is 3C in Hex. That is +where our display is supposed to live. Now we create an object for our OLED +display. + + >>> from ssd1306 import SSD1306_I2C + >>> oled = SSD1306_I2C(128, 32, i2c) + +This is it. Now we can use our OLED display: + + >>> oled.fill(1) + >>> oled.show() + +This fills the whole display with white pixels. To clear the display do: + + >>> oled.fill(0) + >>> oled.show() + +Now we can also write some text: + + >>> oled.text('Hello', 0, 0) + >>> oled.text('World', 0, 10) + >>> oled.show() + +Find more information on how to use the SSD1306 on the great [tutorial about +the OLED featherwing from Adafruit](https://learn.adafruit.com/adafruit-oled-featherwing/circuitpython#usage-6-4). diff --git a/sdist_upip.py b/sdist_upip.py new file mode 100644 index 0000000..4ececc7 --- /dev/null +++ b/sdist_upip.py @@ -0,0 +1,145 @@ +# +# This module overrides distutils (also compatible with setuptools) "sdist" +# command to perform pre- and post-processing as required for MicroPython's +# upip package manager. +# +# Preprocessing steps: +# * Creation of Python resource module (R.py) from each top-level package's +# resources. +# Postprocessing steps: +# * Removing metadata files not used by upip (this includes setup.py) +# * Recompressing gzip archive with 4K dictionary size so it can be +# installed even on low-heap targets. +# +import sys +import os +import zlib +from subprocess import Popen, PIPE +import glob +import tarfile +import re +import io + +from distutils.filelist import FileList +from setuptools.command.sdist import sdist as _sdist + + +def gzip_4k(inf, fname): + comp = zlib.compressobj(level=9, wbits=16 + 12) + with open(fname + ".out", "wb") as outf: + while 1: + data = inf.read(1024) + if not data: + break + outf.write(comp.compress(data)) + outf.write(comp.flush()) + os.rename(fname, fname + ".orig") + os.rename(fname + ".out", fname) + + +FILTERS = [ + # include, exclude, repeat + (r".+\.egg-info/(PKG-INFO|requires\.txt)", r"setup.py$"), + (r".+\.py$", r"[^/]+$"), + (None, r".+\.egg-info/.+"), +] + + +outbuf = io.BytesIO() + +def filter_tar(name): + fin = tarfile.open(name, "r:gz") + fout = tarfile.open(fileobj=outbuf, mode="w") + for info in fin: +# print(info) + if not "/" in info.name: + continue + fname = info.name.split("/", 1)[1] + include = None + + for inc_re, exc_re in FILTERS: + if include is None and inc_re: + if re.match(inc_re, fname): + include = True + + if include is None and exc_re: + if re.match(exc_re, fname): + include = False + + if include is None: + include = True + + if include: + print("including:", fname) + else: + print("excluding:", fname) + continue + + farch = fin.extractfile(info) + fout.addfile(info, farch) + fout.close() + fin.close() + + +def make_resource_module(manifest_files): + resources = [] + # Any non-python file included in manifest is resource + for fname in manifest_files: + ext = fname.rsplit(".", 1) + if len(ext) > 1: + ext = ext[1] + else: + ext = "" + if ext != "py": + resources.append(fname) + + if resources: + print("creating resource module R.py") + resources.sort() + last_pkg = None + r_file = None + for fname in resources: + try: + pkg, res_name = fname.split("/", 1) + except ValueError: + print("not treating %s as a resource" % fname) + continue + if last_pkg != pkg: + last_pkg = pkg + if r_file: + r_file.write("}\n") + r_file.close() + r_file = open(pkg + "/R.py", "w") + r_file.write("R = {\n") + + with open(fname, "rb") as f: + r_file.write("%r: %r,\n" % (res_name, f.read())) + + if r_file: + r_file.write("}\n") + r_file.close() + + +class sdist(_sdist): + + def run(self): + self.filelist = FileList() + self.get_file_list() + make_resource_module(self.filelist.files) + + r = super().run() + + assert len(self.archive_files) == 1 + print("filtering files and recompressing with 4K dictionary") + filter_tar(self.archive_files[0]) + outbuf.seek(0) + gzip_4k(outbuf, self.archive_files[0]) + + return r + + +# For testing only +if __name__ == "__main__": + filter_tar(sys.argv[1]) + outbuf.seek(0) + gzip_4k(outbuf, sys.argv[1])