kopia lustrzana https://github.com/peterhinch/micropython-samples
add micropip. Update SSD1306 for inherited framebuf.
rodzic
74e786740b
commit
7516fceedf
|
@ -160,6 +160,13 @@ of numbers following initialisation will always be the same.
|
|||
|
||||
See the code for usage and timing documentation.
|
||||
|
||||
# micropip
|
||||
|
||||
This is a version of upip which runs under Python 3.2 or above. It is intended
|
||||
for users of hardware which is not network enabled. It avoids the need for a
|
||||
Linux installation, and also avoids the need to compile the Unix build of
|
||||
MicroPython. Libraries may be installed to the PC for transfer to the target.
|
||||
|
||||
# A design for a hardware power meter
|
||||
|
||||
This uses a Pyboard to measure the power consumption of mains powered devices.
|
||||
|
|
|
@ -6,6 +6,7 @@ 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).
|
||||
|
||||
Requires firmware dated 1st Dec 2017 or later.
|
||||
|
||||

|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
# MicroPython SSD1306 OLED driver, I2C and SPI interfaces
|
||||
|
||||
from micropython import const
|
||||
import time
|
||||
import framebuf
|
||||
|
||||
|
||||
|
@ -24,30 +23,16 @@ SET_PRECHARGE = const(0xd9)
|
|||
SET_VCOM_DESEL = const(0xdb)
|
||||
SET_CHARGE_PUMP = const(0x8d)
|
||||
|
||||
|
||||
class SSD1306:
|
||||
# Subclassing FrameBuffer provides support for graphics primitives
|
||||
# http://docs.micropython.org/en/latest/pyboard/library/framebuf.html
|
||||
class SSD1306(framebuf.FrameBuffer):
|
||||
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)
|
||||
fb = framebuf.FrameBuffer(self.buffer, self.width, self.height, framebuf.MVLSB)
|
||||
self.framebuf = fb
|
||||
# Provide methods for accessing FrameBuffer graphics primitives. This is a workround
|
||||
# because inheritance from a native class is currently unsupported.
|
||||
# http://docs.micropython.org/en/latest/pyboard/library/framebuf.html
|
||||
self.fill = fb.fill # (col)
|
||||
self.pixel = fb.pixel # (x, y[, c])
|
||||
self.hline = fb.hline # (x, y, w, col)
|
||||
self.vline = fb.vline # (x, y, h, col)
|
||||
self.line = fb.line # (x1, y1, x2, y2, col)
|
||||
self.rect = fb.rect # (x, y, w, h, col)
|
||||
self.fill_rect = fb.fill_rect # (x, y, w, h, col)
|
||||
self.text = fb.text # (string, x, y, col=1)
|
||||
self.scroll = fb.scroll # (dx, dy)
|
||||
self.blit = fb.blit # (fbuf, x, y[, key])
|
||||
self.poweron()
|
||||
super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB)
|
||||
self.init_display()
|
||||
|
||||
def init_display(self):
|
||||
|
@ -80,6 +65,9 @@ class SSD1306:
|
|||
def poweroff(self):
|
||||
self.write_cmd(SET_DISP | 0x00)
|
||||
|
||||
def poweron(self):
|
||||
self.write_cmd(SET_DISP | 0x01)
|
||||
|
||||
def contrast(self, contrast):
|
||||
self.write_cmd(SET_CONTRAST)
|
||||
self.write_cmd(contrast)
|
||||
|
@ -123,9 +111,6 @@ class SSD1306_I2C(SSD1306):
|
|||
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):
|
||||
|
@ -137,6 +122,12 @@ class SSD1306_SPI(SSD1306):
|
|||
self.dc = dc
|
||||
self.res = res
|
||||
self.cs = cs
|
||||
import time
|
||||
self.res(1)
|
||||
time.sleep_ms(1)
|
||||
self.res(0)
|
||||
time.sleep_ms(10)
|
||||
self.res(1)
|
||||
super().__init__(width, height, external_vcc)
|
||||
|
||||
def write_cmd(self, cmd):
|
||||
|
@ -154,10 +145,3 @@ class SSD1306_SPI(SSD1306):
|
|||
self.cs(0)
|
||||
self.spi.write(buf)
|
||||
self.cs(1)
|
||||
|
||||
def poweron(self):
|
||||
self.res(1)
|
||||
time.sleep_ms(1)
|
||||
self.res(0)
|
||||
time.sleep_ms(10)
|
||||
self.res(1)
|
||||
|
|
|
@ -68,7 +68,7 @@ def test(use_spi=False):
|
|||
psda = machine.Pin('Y10', machine.Pin.OUT_PP)
|
||||
i2c = machine.I2C(scl=pscl, sda=psda)
|
||||
# i2c = machine.I2C(2)
|
||||
ssd = SSD1306_I2C(WIDTH, HEIGHT, i2c, 0x3c)
|
||||
ssd = SSD1306_I2C(WIDTH, HEIGHT, i2c)
|
||||
|
||||
rhs = WIDTH -1
|
||||
ssd.line(rhs - 20, 0, rhs, 20, 1)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# writer.py Implements the Writer class.
|
||||
# V0.21 Peter Hinch 21 March 2017: supports updated framebuf module.
|
||||
# V0.22 Peter Hinch 3rd Jan 2018: Supports new SSD1306 driver.
|
||||
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
|
@ -91,7 +91,7 @@ class Writer(object):
|
|||
self._newline()
|
||||
buf = bytearray(glyph)
|
||||
fbc = framebuf.FrameBuffer(buf, char_width, char_height, self.map)
|
||||
self.device.framebuf.blit(fbc, Writer.text_col, Writer.text_row)
|
||||
self.device.blit(fbc, Writer.text_col, Writer.text_row)
|
||||
Writer.text_col += char_width
|
||||
|
||||
# Bitwise rendering. Currently this is required for colour displays
|
||||
|
|
|
@ -0,0 +1,286 @@
|
|||
#! /usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
import os
|
||||
import errno
|
||||
import json
|
||||
import zlib
|
||||
import tarfile
|
||||
import tempfile
|
||||
import ssl as ussl
|
||||
import socket as usocket
|
||||
|
||||
debug = False
|
||||
g_install_path = os.getcwd() # Default install path
|
||||
gzdict_sz = 16 + 15
|
||||
|
||||
def version():
|
||||
print('Python version 3.2 or above is required.')
|
||||
sys.exit(1)
|
||||
|
||||
if sys.version_info.major < 3:
|
||||
version()
|
||||
elif sys.version_info.major == 3 and sys.version_info.minor < 2:
|
||||
version()
|
||||
|
||||
class NotFoundError(Exception):
|
||||
pass
|
||||
|
||||
# Read a line from a socket
|
||||
def read_line(sock):
|
||||
ret = b''
|
||||
while True:
|
||||
c = sock.recv(1)
|
||||
if c == b'':
|
||||
break
|
||||
elif c == b'\n':
|
||||
ret += c
|
||||
break
|
||||
else:
|
||||
ret += c
|
||||
return ret
|
||||
|
||||
# Read multiple lines from a socket
|
||||
def read_lines(sock):
|
||||
s = b''
|
||||
while True:
|
||||
s1 = read_line(sock)
|
||||
s += s1
|
||||
if s1 == b'\r\n' or s1 == b'':
|
||||
break
|
||||
return s
|
||||
|
||||
# Expects absolute path and *file* name
|
||||
def _makedirs(name):
|
||||
dirname = os.path.dirname(name)
|
||||
def split_path(lst, path):
|
||||
q = os.path.split(path)
|
||||
if q[1] != '':
|
||||
lst.append(q[1])
|
||||
split_path(lst, q[0])
|
||||
|
||||
lst = []
|
||||
split_path(lst, dirname)
|
||||
lst.reverse()
|
||||
mypath = os.path.abspath('/')
|
||||
for elem in lst:
|
||||
mypath = os.path.join(mypath, elem)
|
||||
if not os.path.exists(mypath):
|
||||
try:
|
||||
os.mkdir(mypath)
|
||||
except OSError as e:
|
||||
if e.args[0] != errno.EEXIST and e.args[0] != errno.EISDIR:
|
||||
raise
|
||||
|
||||
|
||||
def install_tar(f, prefix):
|
||||
meta = {}
|
||||
for info in f:
|
||||
#print(info)
|
||||
fname = info.name
|
||||
try:
|
||||
fname = fname[fname.index("/") + 1:]
|
||||
except ValueError:
|
||||
fname = ""
|
||||
|
||||
save = True
|
||||
for p in ("setup.", "PKG-INFO", "README"):
|
||||
#print(fname, p)
|
||||
if fname.startswith(p) or ".egg-info" in fname:
|
||||
if fname.endswith("/requires.txt"):
|
||||
meta["deps"] = f.extractfile(info).read()
|
||||
save = False
|
||||
if debug:
|
||||
print("Skipping", fname)
|
||||
break
|
||||
|
||||
if save:
|
||||
outfname = prefix + fname
|
||||
if info.type != tarfile.DIRTYPE:
|
||||
if debug:
|
||||
print("Extracting " + outfname)
|
||||
_makedirs(outfname)
|
||||
subf = f.extractfile(info)
|
||||
with open(outfname, "wb") as outf:
|
||||
outf.write(subf.read())
|
||||
return meta
|
||||
|
||||
warn_ussl = True
|
||||
def url_open(url):
|
||||
global warn_ussl
|
||||
|
||||
if debug:
|
||||
print(url)
|
||||
|
||||
proto, _, host, urlpath = url.split('/', 3)
|
||||
try:
|
||||
ai = usocket.getaddrinfo(host, 443)
|
||||
except OSError as e:
|
||||
fatal("Unable to resolve %s (no Internet?)" % host, e)
|
||||
# print("Address infos:", ai)
|
||||
addr = ai[0][4]
|
||||
|
||||
s = usocket.socket(ai[0][0])
|
||||
try:
|
||||
# print("Connect address:", addr)
|
||||
|
||||
if proto == "https:":
|
||||
s = ussl.wrap_socket(s)
|
||||
if warn_ussl:
|
||||
print("Warning: %s SSL certificate is not validated" % host)
|
||||
warn_ussl = False
|
||||
s.connect(addr)
|
||||
s.setblocking(True)
|
||||
|
||||
s.send(("GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n" % (urlpath, host)).encode('UTF8'))
|
||||
l = read_line(s)
|
||||
protover, status, msg = l.split(None, 2)
|
||||
if status != b"200":
|
||||
if status == b"404" or status == b"301":
|
||||
raise NotFoundError("Package not found")
|
||||
raise ValueError(status)
|
||||
while 1:
|
||||
l = read_line(s)
|
||||
if not l:
|
||||
raise ValueError("Unexpected EOF in HTTP headers")
|
||||
if l == b'\r\n':
|
||||
break
|
||||
except Exception as e:
|
||||
s.close()
|
||||
raise e
|
||||
|
||||
return s
|
||||
|
||||
def get_pkg_metadata(name):
|
||||
f = url_open("https://pypi.python.org/pypi/%s/json" % name)
|
||||
s = read_lines(f)
|
||||
try:
|
||||
return json.loads(s.decode('UTF8'))
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
def fatal(msg, exc=None):
|
||||
print("Error:", msg)
|
||||
if exc and debug:
|
||||
raise exc
|
||||
sys.exit(1)
|
||||
|
||||
def install_pkg(pkg_spec, install_path):
|
||||
data = get_pkg_metadata(pkg_spec)
|
||||
|
||||
latest_ver = data["info"]["version"]
|
||||
packages = data["releases"][latest_ver]
|
||||
assert len(packages) == 1
|
||||
package_url = packages[0]["url"]
|
||||
print("Installing %s %s from %s" % (pkg_spec, latest_ver, package_url))
|
||||
package_fname = os.path.basename(package_url)
|
||||
f1 = url_open(package_url)
|
||||
s = read_lines(f1)
|
||||
try:
|
||||
str1 = zlib.decompress(s, gzdict_sz)
|
||||
with tempfile.TemporaryFile() as temp_file:
|
||||
temp_file.write(str1)
|
||||
temp_file.seek(0)
|
||||
with tarfile.TarFile(fileobj=temp_file) as tar_file: # Expects a file object
|
||||
meta = install_tar(tar_file, install_path)
|
||||
finally:
|
||||
f1.close()
|
||||
return meta
|
||||
|
||||
|
||||
def install(to_install):
|
||||
install_path = g_install_path
|
||||
install_path = os.path.join(install_path, '') # Append final /
|
||||
if not isinstance(to_install, list):
|
||||
to_install = [to_install]
|
||||
print("Installing to: " + install_path)
|
||||
# sets would be perfect here, but don't depend on them
|
||||
installed = []
|
||||
try:
|
||||
while to_install:
|
||||
if debug:
|
||||
print("Queue:", to_install)
|
||||
pkg_spec = to_install.pop(0)
|
||||
if pkg_spec in installed:
|
||||
continue
|
||||
meta = install_pkg(pkg_spec, install_path)
|
||||
installed.append(pkg_spec)
|
||||
if debug:
|
||||
print(meta)
|
||||
deps = meta.get("deps", "").rstrip()
|
||||
if deps:
|
||||
deps = deps.decode("utf-8").split("\n")
|
||||
to_install.extend(deps)
|
||||
except Exception as e:
|
||||
print("Error installing '{}': {}, packages may be partially installed".format(
|
||||
pkg_spec, e),
|
||||
file=sys.stderr)
|
||||
|
||||
def help():
|
||||
print("""\
|
||||
micropip - Simple PyPI package manager for MicroPython
|
||||
Runs on a PC under Python 3.2 or above, and installs to a PC directory for
|
||||
subsequent transfer to target hardware.
|
||||
|
||||
Usage: micropip.py install [-p <path>] <package>... | -r <requirements.txt>
|
||||
The above requires micropip.py to have executable permission.
|
||||
Alternatively: python3 -m micropip install [-p <path>] <package>... | -r <requirements.txt>
|
||||
|
||||
If <path> is not given, packages will be installed into the current directory.
|
||||
|
||||
Note: only MicroPython packages (usually, named micropython-*) are supported
|
||||
for installation, upip does not support arbitrary code in setup.py.
|
||||
""")
|
||||
|
||||
def main():
|
||||
global debug
|
||||
global g_install_path
|
||||
|
||||
if len(sys.argv) < 2 or sys.argv[1] == "-h" or sys.argv[1] == "--help":
|
||||
help()
|
||||
return
|
||||
|
||||
if sys.argv[1] != "install":
|
||||
fatal("Only 'install' command supported")
|
||||
|
||||
to_install = []
|
||||
|
||||
i = 2
|
||||
while i < len(sys.argv) and sys.argv[i][0] == "-":
|
||||
opt = sys.argv[i]
|
||||
i += 1
|
||||
if opt == "-h" or opt == "--help":
|
||||
help()
|
||||
return
|
||||
elif opt == "-p":
|
||||
g_install_path = sys.argv[i]
|
||||
i += 1
|
||||
elif opt == "-r":
|
||||
list_file = sys.argv[i]
|
||||
i += 1
|
||||
with open(list_file) as f:
|
||||
while True:
|
||||
l = f.readline()
|
||||
if not l:
|
||||
break
|
||||
if l[0] == "#":
|
||||
continue
|
||||
to_install.append(l.rstrip())
|
||||
elif opt == "--debug":
|
||||
debug = True
|
||||
else:
|
||||
fatal("Unknown/unsupported option: " + opt)
|
||||
|
||||
to_install.extend(sys.argv[i:])
|
||||
if not to_install:
|
||||
help()
|
||||
return
|
||||
|
||||
g_install_path = os.path.expanduser(g_install_path)
|
||||
g_install_path = os.path.abspath(g_install_path)
|
||||
print('g_install_path', g_install_path)
|
||||
install(to_install)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Ładowanie…
Reference in New Issue