esp32/boards: Add INKPLATE6 board.

pull/8493/head
Matt Trentini 2022-04-05 16:55:21 +10:00
rodzic 71344c15f4
commit 93172021b5
19 zmienionych plików z 2404 dodań i 0 usunięć

Wyświetl plik

@ -0,0 +1,20 @@
# MicroPython for the Inkplate6
![](https://www.crowdsupply.com/img/040a/inkplate-6-angle-01_png_project-main.jpg)
Inkplate is a powerful, Wi-Fi enabled ESP32 based e-paper display – recycled from a Kindle e-reader. Learn more about Inkplate on [official website](https://inkplate.io/). Inkplate6 was crowdfunded on [Crowd Supply Inkplate 6](https://www.crowdsupply.com/e-radionica/inkplate-6).
This board definition was based on [e-radionica/Inkplate-micropython](https://github.com/e-radionicacom/Inkplate-micropython) though the original software effort was by [tve](https://github.com/tve/micropython-inkplate6).
### Features
- Simple graphics class for monochrome use of the e-paper display
- Simple graphics class for 2 bits per pixel greyscale use of the e-paper display
- Support for partial updates
- Access to touch sensors
- Everything in pure python with screen updates virtually as fast as the Arduino C driver
- Bitmap drawing, although really slow
### Getting started with MicroPython on Inkplate
Download and flash the MicroPython firmware for the [INKPLATE6](https://micropython.org/download/inkplate6/) board.

Wyświetl plik

@ -0,0 +1,27 @@
{
"deploy": [
"../deploy.md"
],
"docs": "",
"features": [
"BLE",
"WiFi",
"Display",
"e-ink",
"Micro USB",
"MicroSD",
"SPIRAM"
],
"id": "inkplate6",
"images": [
"inkplate6.jpg"
],
"mcu": "esp32",
"product": "ESP32",
"thumbnail": "",
"url": "https://inkplate.io/",
"variants": {
"idf3": "Compiled with IDF 3.x"
},
"vendor": "e-radonica"
}

Wyświetl plik

@ -0,0 +1 @@
The following files are daily firmware builds for the Inkplate6.

Wyświetl plik

@ -0,0 +1,17 @@
# Examples
These examples, originally from [e-radionica/Inkplate/Examples/Inkplate6](https://github.com/e-radionicacom/Inkplate-micropython/tree/master/Examples/Inkplate6) are _not_ frozen into the board firmware; they're here for reference. Execute them on your Inkplate to try them out.
- basicBW.py -> demonstrates basic drawing capabilities, as well as drawing some images.
- basicGrayscale.py -> demonstrates basic drawing capabilities, as well as drawing some images.
- exampleNetwork.py -> demonstrates connection to WiFi network while drawing the HTTP request response on the screen.
- exampleSd.py -> demonstrates reading files and images from SD card.
- batteryAndTemperatureRead.py -> demonstrates how to read temperature and voltage from internal sensors.
- touchpads.py -> demonstrates how to use built in touchpads.
## To execute the examples
The recommended way to execute the examples is with `mpremote`. Install `mpremote` with `pipx` (`pipx install mpremote`) then run a script on the Inkplate, eg:
```bash
> mpremote connect [SERIALPORT] run basicBW.py
```

Wyświetl plik

@ -0,0 +1,39 @@
from inkplate6 import Inkplate
from image import *
import time
display = Inkplate(Inkplate.INKPLATE_1BIT)
if __name__ == "__main__":
# Must be called before using, line in Arduino
display.begin()
display.clearDisplay()
display.display()
for r in range(4):
# Sets the screen rotation
display.setRotation(r)
# All drawing functions
display.drawPixel(100, 100, display.BLACK)
display.drawRect(50, 50, 75, 75, display.BLACK)
display.drawCircle(200, 200, 30, display.BLACK)
display.fillCircle(300, 300, 30, display.BLACK)
display.drawFastHLine(20, 100, 50, display.BLACK)
display.drawFastVLine(100, 20, 50, display.BLACK)
display.drawLine(100, 100, 400, 400, display.BLACK)
display.drawRoundRect(100, 10, 100, 100, 10, display.BLACK)
display.fillRoundRect(10, 100, 100, 100, 10, display.BLACK)
display.drawTriangle(300, 100, 400, 150, 400, 100, display.BLACK)
if display.rotation % 2 == 0:
display.fillTriangle(500, 101, 400, 150, 400, 100, display.BLACK)
display.display()
time.sleep(5)
# Draws image from bytearray
display.setRotation(0)
display.drawBitmap(120, 200, image, 576, 100)
#Use display.partialUpdate instead of display.display() to draw only updated pixels
display.partialUpdate()

Wyświetl plik

@ -0,0 +1,33 @@
# Include needed libraries
from inkplate6 import Inkplate
from image import *
import time
# Initialize inkplate display
display = Inkplate(Inkplate.INKPLATE_2BIT)
# Main function, you can make infinite while loop inside this to run code indefinitely
if __name__ == "__main__":
# Must be called before using, line in Arduino
display.begin()
display.clearDisplay()
display.display()
# Draw palet of posible colors
#use color values 0, 1, 2, 3
display.writeFillRect(0, 0, 25, 600, 3)
display.writeFillRect(25, 0, 25, 600, 2)
display.writeFillRect(50, 0, 25, 600, 1)
display.writeFillRect(75, 0, 25, 600, 0)
display.display()
time.sleep(3)
# Draws image from bytearray
display.setRotation(0)
display.drawBitmap(120, 200, image, 576, 100)
display.display()
time.sleep(10)

Wyświetl plik

@ -0,0 +1,22 @@
from inkplate6 import Inkplate
from image import *
display = Inkplate(Inkplate.INKPLATE_1BIT)
if __name__ == "__main__":
display.begin()
display.clearDisplay()
display.display()
battery = str(display.readBattery())
display.setTextSize(2)
display.printText(100, 100, "batt: " + battery + "V")
display.display()
temperature = str(display.readTemperature())
display.setTextSize(2)
display.printText(100, 150, "TEMP: " + temperature + "C")
display.display()

Wyświetl plik

@ -0,0 +1,60 @@
import network
import time
from inkplate6 import Inkplate
ssid = "e-radionica.com"
password = "croduino"
# More info here: https://docs.micropython.org/en/latest/esp8266/tutorial/network_basics.html
def do_connect():
import network
sta_if = network.WLAN(network.STA_IF)
if not sta_if.isconnected():
print("connecting to network...")
sta_if.active(True)
sta_if.connect(ssid, password)
while not sta_if.isconnected():
pass
print("network config:", sta_if.ifconfig())
# More info here: https://docs.micropython.org/en/latest/esp8266/tutorial/network_tcp.html
def http_get(url):
import socket
res = ""
_, _, host, path = url.split("/", 3)
addr = socket.getaddrinfo(host, 80)[0][-1]
s = socket.socket()
s.connect(addr)
s.send(bytes("GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n" % (path, host), "utf8"))
while True:
data = s.recv(100)
if data:
res += str(data, "utf8")
else:
break
s.close()
return res
# Calling functions defined above
do_connect()
response = http_get("http://micropython.org/ks/test.html")
# Initialise our Inkplate object
display = Inkplate(Inkplate.INKPLATE_1BIT)
display.begin()
# Print response in lines
cnt = 0
for x in response.split("\n"):
display.printText(
10, 10 + cnt, x.upper()
) # Default font has only upper case letters
cnt += 10
# Display image from buffer
display.display()

Wyświetl plik

@ -0,0 +1,21 @@
import os, time
from inkplate6 import Inkplate
display = Inkplate(Inkplate.INKPLATE_2BIT)
display.begin()
# This prints all the files on card
print(os.listdir("/sd"))
f = open("sd/text.txt", "r")
# Print file contents
print(f.read())
f.close()
time.sleep(5)
# Utterly slow, can take minutes :(
display.drawImageFile(0, 0, "sd/1.bmp")
display.display()

Wyświetl plik

@ -0,0 +1,57 @@
from inkplate6 import Inkplate
from image import *
display = Inkplate(Inkplate.INKPLATE_1BIT)
circle_x = 400
circle_y = 300
circle_r = 40
#main function used by micropython
if __name__ == "__main__":
display.begin()
display.clearDisplay()
display.display()
# function to show text at the top of the screen
# need to be called every time we clear display
def topText():
display.setTextSize(2)
display.printText(100, 10, "TOUCHPADS EXAMPLE! 1, 3 TO MOVE CIRCLE, 2 TO RESET")
topText()
# Touchpads definitions
touch1, touch2, touch3 = display.TOUCH1, display.TOUCH2, display.TOUCH3
#draw initial circle for touchpad demonstration
display.drawCircle(circle_x, circle_y, circle_r, display.BLACK)
display.display()
#Main loop that will run forever or until battery is dead
while True:
#check if touchpad is pressed
if touch1():
circle_x -= 40
display.clearDisplay()
topText()
display.drawCircle(circle_x, circle_y, circle_r, display.BLACK)
display.partialUpdate()
if touch3():
circle_x += 40
display.clearDisplay()
topText()
display.drawCircle(circle_x, circle_y, circle_r, display.BLACK)
display.partialUpdate()
if touch2():
circle_x = 400
circle_y = 300
circle_r = 40
display.clearDisplay()
topText()
display.drawCircle(circle_x, circle_y, circle_r, display.BLACK)
display.partialUpdate()

Wyświetl plik

@ -0,0 +1,2 @@
include("$(PORT_DIR)/boards/manifest.py")
freeze("modules")

Wyświetl plik

@ -0,0 +1,545 @@
# The MIT License (MIT)
#
# Copyright (c) 2018 Kattni Rembor for Adafruit Industries
#
# 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.
"""
`gfx`
====================================================
CircuitPython pixel graphics drawing library.
* Author(s): Kattni Rembor, Tony DiCola, Jonah Yolles-Murphy, based on code by Phil Burgess
Implementation Notes
--------------------
**Hardware:**
**Software and Dependencies:**
* Adafruit CircuitPython firmware for the supported boards:
https://github.com/adafruit/circuitpython/releases
"""
__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_GFX.git"
# pylint: disable=invalid-name
class GFX:
# pylint: disable=too-many-instance-attributes
"""Create an instance of the GFX drawing class.
:param width: The width of the drawing area in pixels.
:param height: The height of the drawing area in pixels.
:param pixel: A function to call when a pixel is drawn on the display. This function
should take at least an x and y position and then any number of optional
color or other parameters.
:param hline: A function to quickly draw a horizontal line on the display.
This should take at least an x, y, and width parameter and
any number of optional color or other parameters.
:param vline: A function to quickly draw a vertical line on the display.
This should take at least an x, y, and height paraemter and
any number of optional color or other parameters.
:param fill_rect: A funtion to quickly draw a solid rectangle with four
input parameters: x,y, width, and height. Any number of other
parameters for color or screen specific data.
:param text: A function to quickly place text on the screen. The inputs include:
x, y data(top left as starting point).
:param font: An optional input to augment the default text method with a new font.
The input shoudl be a properly formatted dict.
"""
# pylint: disable=too-many-arguments
def __init__(
self,
width,
height,
pixel,
hline=None,
vline=None,
fill_rect=None,
text=None,
font=None,
):
# pylint: disable=too-many-instance-attributes
self.width = width
self.height = height
self._pixel = pixel
# Default to slow horizontal & vertical line implementations if no
# faster versions are provided.
if hline is None:
self.hline = self._slow_hline
else:
self.hline = hline
if vline is None:
self.vline = self._slow_vline
else:
self.vline = vline
if fill_rect is None:
self.fill_rect = self._fill_rect
else:
self.fill_rect = fill_rect
if text is None:
self.text = self._very_slow_text
# if no supplied font set to std
if font is None:
from gfx_standard_font_01 import ( # pylint: disable=import-outside-toplevel # changed
text_dict as std_font,
)
self.font = std_font
self.set_text_background()
else:
self.font = font
if not isinstance(self.font, dict):
raise ValueError(
"Font definitions must be contained in a dictionary object."
)
del self.set_text_background
else:
self.text = text
def pixel(self, x0, y0, *args, **kwargs):
"""A function to pass through in input pixel functionality."""
# This was added to mainitatn the abstrtion between gfx and the dislay library
self._pixel(x0, y0, *args, **kwargs)
def _slow_hline(self, x0, y0, width, *args, **kwargs):
"""Slow implementation of a horizontal line using pixel drawing.
This is used as the default horizontal line if no faster override
is provided."""
if y0 < 0 or y0 > self.height or x0 < -width or x0 > self.width:
return
for i in range(width):
self._pixel(x0 + i, y0, *args, **kwargs)
def _slow_vline(self, x0, y0, height, *args, **kwargs):
"""Slow implementation of a vertical line using pixel drawing.
This is used as the default vertical line if no faster override
is provided."""
if y0 < -height or y0 > self.height or x0 < 0 or x0 > self.width:
return
for i in range(height):
self._pixel(x0, y0 + i, *args, **kwargs)
def rect(self, x0, y0, width, height, *args, **kwargs):
"""Rectangle drawing function. Will draw a single pixel wide rectangle
starting in the upper left x0, y0 position and width, height pixels in
size."""
if y0 < -height or y0 > self.height or x0 < -width or x0 > self.width:
return
self.hline(x0, y0, width, *args, **kwargs)
self.hline(x0, y0 + height - 1, width, *args, **kwargs)
self.vline(x0, y0, height, *args, **kwargs)
self.vline(x0 + width - 1, y0, height, *args, **kwargs)
def _fill_rect(self, x0, y0, width, height, *args, **kwargs):
"""Filled rectangle drawing function. Will draw a single pixel wide
rectangle starting in the upper left x0, y0 position and width, height
pixels in size."""
if y0 < -height or y0 > self.height or x0 < -width or x0 > self.width:
return
for i in range(x0, x0 + width):
self.vline(i, y0, height, *args, **kwargs)
def line(self, x0, y0, x1, y1, *args, **kwargs):
"""Line drawing function. Will draw a single pixel wide line starting at
x0, y0 and ending at x1, y1."""
steep = abs(y1 - y0) > abs(x1 - x0)
if steep:
x0, y0 = y0, x0
x1, y1 = y1, x1
if x0 > x1:
x0, x1 = x1, x0
y0, y1 = y1, y0
dx = x1 - x0
dy = abs(y1 - y0)
err = dx // 2
ystep = 0
if y0 < y1:
ystep = 1
else:
ystep = -1
while x0 <= x1:
if steep:
self._pixel(y0, x0, *args, **kwargs)
else:
self._pixel(x0, y0, *args, **kwargs)
err -= dy
if err < 0:
y0 += ystep
err += dx
x0 += 1
def circle(self, x0, y0, radius, *args, **kwargs):
"""Circle drawing function. Will draw a single pixel wide circle with
center at x0, y0 and the specified radius."""
f = 1 - radius
ddF_x = 1
ddF_y = -2 * radius
x = 0
y = radius
self._pixel(x0, y0 + radius, *args, **kwargs) # bottom
self._pixel(x0, y0 - radius, *args, **kwargs) # top
self._pixel(x0 + radius, y0, *args, **kwargs) # right
self._pixel(x0 - radius, y0, *args, **kwargs) # left
while x < y:
if f >= 0:
y -= 1
ddF_y += 2
f += ddF_y
x += 1
ddF_x += 2
f += ddF_x
# angle notations are based on the unit circle and in diection of being drawn
self._pixel(x0 + x, y0 + y, *args, **kwargs) # 270 to 315
self._pixel(x0 - x, y0 + y, *args, **kwargs) # 270 to 255
self._pixel(x0 + x, y0 - y, *args, **kwargs) # 90 to 45
self._pixel(x0 - x, y0 - y, *args, **kwargs) # 90 to 135
self._pixel(x0 + y, y0 + x, *args, **kwargs) # 0 to 315
self._pixel(x0 - y, y0 + x, *args, **kwargs) # 180 to 225
self._pixel(x0 + y, y0 - x, *args, **kwargs) # 0 to 45
self._pixel(x0 - y, y0 - x, *args, **kwargs) # 180 to 135
def fill_circle(self, x0, y0, radius, *args, **kwargs):
"""Filled circle drawing function. Will draw a filled circule with
center at x0, y0 and the specified radius."""
self.vline(x0, y0 - radius, 2 * radius + 1, *args, **kwargs)
f = 1 - radius
ddF_x = 1
ddF_y = -2 * radius
x = 0
y = radius
while x < y:
if f >= 0:
y -= 1
ddF_y += 2
f += ddF_y
x += 1
ddF_x += 2
f += ddF_x
self.vline(x0 + x, y0 - y, 2 * y + 1, *args, **kwargs)
self.vline(x0 + y, y0 - x, 2 * x + 1, *args, **kwargs)
self.vline(x0 - x, y0 - y, 2 * y + 1, *args, **kwargs)
self.vline(x0 - y, y0 - x, 2 * x + 1, *args, **kwargs)
def triangle(self, x0, y0, x1, y1, x2, y2, *args, **kwargs):
# pylint: disable=too-many-arguments
"""Triangle drawing function. Will draw a single pixel wide triangle
around the points (x0, y0), (x1, y1), and (x2, y2)."""
self.line(x0, y0, x1, y1, *args, **kwargs)
self.line(x1, y1, x2, y2, *args, **kwargs)
self.line(x2, y2, x0, y0, *args, **kwargs)
def fill_triangle(self, x0, y0, x1, y1, x2, y2, *args, **kwargs):
# Filled triangle drawing function. Will draw a filled triangle around
# the points (x0, y0), (x1, y1), and (x2, y2).
if y0 > y1:
y0, y1 = y1, y0
x0, x1 = x1, x0
if y1 > y2:
y2, y1 = y1, y2
x2, x1 = x1, x2
if y0 > y1:
y0, y1 = y1, y0
x0, x1 = x1, x0
a = 0
b = 0
y = 0
last = 0
if y0 == y2:
a = x0
b = x0
if x1 < a:
a = x1
elif x1 > b:
b = x1
if x2 < a:
a = x2
elif x2 > b:
b = x2
self.hline(a, y0, b-a+1, *args, **kwargs)
return
dx01 = x1 - x0
dy01 = y1 - y0
dx02 = x2 - x0
dy02 = y2 - y0
dx12 = x2 - x1
dy12 = y2 - y1
if dy01 == 0:
dy01 = 1
if dy02 == 0:
dy02 = 1
if dy12 == 0:
dy12 = 1
sa = 0
sb = 0
if y1 == y2:
last = y1
else:
last = y1-1
for y in range(y0, last+1):
a = x0 + sa // dy01
b = x0 + sb // dy02
sa += dx01
sb += dx02
if a > b:
a, b = b, a
self.hline(a, y, b-a+1, *args, **kwargs)
y = last
sa = dx12 * (y - y1)
sb = dx02 * (y - y0)
while y <= y2:
a = x1 + sa // dy12
b = x0 + sb // dy02
sa += dx12
sb += dx02
if a > b:
a, b = b, a
self.hline(a, y, b-a+1, *args, **kwargs)
y += 1
def round_rect(self, x0, y0, width, height, radius, *args, **kwargs):
"""Rectangle with rounded corners drawing function.
This works like a regular rect though! if radius = 0
Will draw the outline of a rextabgle with rounded corners with (x0,y0) at the top left"""
# shift to correct for start point location
x0 += radius
y0 += radius
# ensure that the radius will only ever half of the shortest side or less
radius = int(min(radius, width / 2, height / 2))
if radius:
f = 1 - radius
ddF_x = 1
ddF_y = -2 * radius
x = 0
y = radius
self.vline(
x0 - radius, y0, height - 2 * radius + 1, *args, **kwargs
) # left
self.vline(
x0 + width - radius, y0, height - 2 * radius + 1, *args, **kwargs
) # right
self.hline(
x0, y0 + height - radius + 1, width - 2 * radius + 1, *args, **kwargs
) # bottom
self.hline(x0, y0 - radius, width - 2 *
radius + 1, *args, **kwargs) # top
while x < y:
if f >= 0:
y -= 1
ddF_y += 2
f += ddF_y
x += 1
ddF_x += 2
f += ddF_x
# angle notations are based on the unit circle and in diection of being drawn
# top left
self._pixel(x0 - y, y0 - x, *args, **kwargs) # 180 to 135
self._pixel(x0 - x, y0 - y, *args, **kwargs) # 90 to 135
# top right
self._pixel(
x0 + x + width - 2 * radius, y0 - y, *args, **kwargs
) # 90 to 45
self._pixel(
x0 + y + width - 2 * radius, y0 - x, *args, **kwargs
) # 0 to 45
# bottom right
self._pixel(
x0 + y + width - 2 * radius,
y0 + x + height - 2 * radius,
*args,
**kwargs,
) # 0 to 315
self._pixel(
x0 + x + width - 2 * radius,
y0 + y + height - 2 * radius,
*args,
**kwargs,
) # 270 to 315
# bottom left
self._pixel(
x0 - x, y0 + y + height - 2 * radius, *args, **kwargs
) # 270 to 255
self._pixel(
x0 - y, y0 + x + height - 2 * radius, *args, **kwargs
) # 180 to 225
def fill_round_rect(self, x0, y0, width, height, radius, *args, **kwargs):
"""Filled circle drawing function. Will draw a filled circule with
center at x0, y0 and the specified radius."""
# shift to correct for start point location
x0 += radius
y0 += radius
# ensure that the radius will only ever half of the shortest side or less
radius = int(min(radius, width / 2, height / 2))
self.fill_rect(
x0, y0 - radius, width - 2 * radius + 2, height + 2, *args, **kwargs
)
if radius:
f = 1 - radius
ddF_x = 1
ddF_y = -2 * radius
x = 0
y = radius
while x < y:
if f >= 0:
y -= 1
ddF_y += 2
f += ddF_y
x += 1
ddF_x += 2
f += ddF_x
# part notation starts with 0 on left and 1 on right, and direction is noted
# top left
self.vline(
x0 - y, y0 - x, 2 * x + 1 + height - 2 * radius, *args, **kwargs
) # 0 to .25
self.vline(
x0 - x, y0 - y, 2 * y + 1 + height - 2 * radius, *args, **kwargs
) # .5 to .25
# top right
self.vline(
x0 + x + width - 2 * radius,
y0 - y,
2 * y + 1 + height - 2 * radius,
*args,
**kwargs,
) # .5 to .75
self.vline(
x0 + y + width - 2 * radius,
y0 - x,
2 * x + 1 + height - 2 * radius,
*args,
**kwargs,
) # 1 to .75
def _place_char(self, x0, y0, char, size, *args, **kwargs):
"""A sub class used for placing a single character on the screen"""
# pylint: disable=undefined-loop-variable
arr = self.font[char]
width = arr[0]
height = arr[1]
# extract the char section of the data
data = arr[2:]
for x in range(width):
for y in range(height):
bit = bool(data[x] & 2 ** y)
# char pixel
if bit:
self.fill_rect(
size * x + x0,
size * (height - y - 1) + y0,
size,
size,
*args,
**kwargs,
)
# else background pixel
else:
try:
self.fill_rect(
size * x + x0,
size * (height - y - 1) + y0,
size,
size,
*self.text_bkgnd_args,
**self.text_bkgnd_kwargs,
)
except TypeError:
pass
del arr, width, height, data, x, y, x0, y0, char, size
def _very_slow_text(self, x0, y0, string, size, *args, **kwargs):
"""a function to place text on the display.(temporary)
to use special characters put "__" on either side of the desired characters.
letter format:
{'character_here' : bytearray(b',WIDTH,HEIGHT,right-most-data,
more-bytes-here,left-most-data') ,}
(replace the "," with backslashes!!)
each byte:
| lower most bit(lowest on display)
V
x0110100
^c
| top most bit (highest on display)"""
x_roll = x0 # rolling x
y_roll = y0 # rolling y
# highest_height = 0#wrap
sep_string = string.split("__")
for chunk in sep_string:
# print(chunk)
try:
self._place_char(x_roll, y_roll, chunk, size, *args, **kwargs)
x_roll += size * self.font[chunk][0] + size
# highest_height = max(highest_height, size*self.font[chunk][1] + 1) #wrap
except KeyError:
while chunk:
char = chunk[0]
# make sure something is sent even if not in font dict
try:
self._place_char(x_roll, y_roll, char,
size, *args, **kwargs)
except KeyError:
self._place_char(
x_roll, y_roll, "?CHAR?", size, *args, **kwargs
)
char = "?CHAR?"
x_roll += size * self.font[char][0]
# gap between letters
try:
self.fill_rect(
x_roll,
y_roll,
size,
size * self.font[char][1],
*self.text_bkgnd_args,
**self.text_bkgnd_kwargs,
)
except TypeError:
pass
x_roll += size
# highest_height = max(highest_height, size*self.font[char][1] + 1) #wrap
chunk = chunk[1:] # wrap
# if (x_roll >= self.width) or (chunk[0:2] == """\n"""): #wrap
# self._text(x0,y0+highest_height,"__".join(sep_string),size) #wrap
# print(highest_height) #wrap
def set_text_background(self, *args, **kwargs):
"""A method to change the background color of text, input any and all color paramsself.
run without any inputs to return to "clear" background
"""
self.text_bkgnd_args = args
self.text_bkgnd_kwargs = kwargs
# pylint: enable=too-many-arguments

Wyświetl plik

@ -0,0 +1,161 @@
# The MIT License (MIT)
#
# Copyright (c) 2018 Jonah Yolles-Murphy for Makers Anywhere!
#
# 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.
"""
`gfx_standard_font_01`
====================================================
CircuitPython pixel graphics drawing library.
* Author(s): Jonah Yolles-Murphy
Implementation Notes
--------------------
**Hardware:**
**Software and Dependencies:**
* Adafruit CircuitPython firmware for the supported boards:
https://github.com/adafruit/circuitpython/releases
* letter format:
{ 'character_here' : bytearray(WIDTH,HEIGHT,right-most-data,more-bytes-here,left-most-data')}
the right most bit is the top most bit of each vertical stripe of a char
* Key format:
keys of one length only represent one character. longer then one is either
extended characters or special characters like the degree sign.
all extended or special charaters have all capitalized keys.
"?CHAR?" is used when an input character is not in the font dictionary
"""
# pylint: disable=invalid-name
text_dict = {
"A": bytearray(b"\x05\x07?DDD?"),
"B": bytearray(b"\x05\x07\x7fAII6"),
"C": bytearray(b'\x05\x07>AAA"'),
"D": bytearray(b'\x05\x07\x7fAA"\x1c'),
"E": bytearray(b"\x05\x07\x7fIIIA"),
"F": bytearray(b"\x05\x07\x7fHH@@"),
"G": bytearray(b"\x05\x07>AII."),
"H": bytearray(b"\x05\x07\x7f\x08\x08\x08\x7f"),
"I": bytearray(b"\x05\x07AA\x7fAA"),
"J": bytearray(b"\x05\x07FA~@@"),
"K": bytearray(b"\x05\x07\x7f\x08\x08t\x03"),
"L": bytearray(b"\x05\x07\x7f\x01\x01\x01\x01"),
"M": bytearray(b"\x05\x07\x7f \x10 \x7f"),
"N": bytearray(b"\x05\x07\x7f \x1c\x02\x7f"),
"O": bytearray(b"\x05\x07>AAA>"),
"P": bytearray(b"\x05\x07\x7fHHH0"),
"Q": bytearray(b"\x05\x07>AEB="),
"R": bytearray(b"\x05\x07\x7fHLJ1"),
"S": bytearray(b"\x05\x072III&"),
"T": bytearray(b"\x05\x07@@\x7f@@"),
"U": bytearray(b"\x05\x07~\x01\x01\x01~"),
"V": bytearray(b"\x05\x07p\x0e\x01\x0ep"),
"W": bytearray(b"\x05\x07|\x03\x04\x03|"),
"X": bytearray(b"\x05\x07c\x14\x08\x14c"),
"Y": bytearray(b"\x05\x07`\x10\x0f\x10`"),
"Z": bytearray(b"\x05\x07CEIQa"),
#until we get proper support for lowercase letters
"a": bytearray(b"\x05\x07?DDD?"),
"b": bytearray(b"\x05\x07\x7fAII6"),
"c": bytearray(b'\x05\x07>AAA"'),
"d": bytearray(b'\x05\x07\x7fAA"\x1c'),
"e": bytearray(b"\x05\x07\x7fIIIA"),
"f": bytearray(b"\x05\x07\x7fHH@@"),
"g": bytearray(b"\x05\x07>AII."),
"h": bytearray(b"\x05\x07\x7f\x08\x08\x08\x7f"),
"i": bytearray(b"\x05\x07AA\x7fAA"),
"j": bytearray(b"\x05\x07FA~@@"),
"k": bytearray(b"\x05\x07\x7f\x08\x08t\x03"),
"l": bytearray(b"\x05\x07\x7f\x01\x01\x01\x01"),
"m": bytearray(b"\x05\x07\x7f \x10 \x7f"),
"n": bytearray(b"\x05\x07\x7f \x1c\x02\x7f"),
"o": bytearray(b"\x05\x07>AAA>"),
"p": bytearray(b"\x05\x07\x7fHHH0"),
"q": bytearray(b"\x05\x07>AEB="),
"r": bytearray(b"\x05\x07\x7fHLJ1"),
"s": bytearray(b"\x05\x072III&"),
"t": bytearray(b"\x05\x07@@\x7f@@"),
"u": bytearray(b"\x05\x07~\x01\x01\x01~"),
"v": bytearray(b"\x05\x07p\x0e\x01\x0ep"),
"w": bytearray(b"\x05\x07|\x03\x04\x03|"),
"x": bytearray(b"\x05\x07c\x14\x08\x14c"),
"y": bytearray(b"\x05\x07`\x10\x0f\x10`"),
"z": bytearray(b"\x05\x07CEIQa"),
"0": bytearray(b"\x05\x07>EIQ>"),
"1": bytearray(b"\x05\x07\x11!\x7f\x01\x01"),
"2": bytearray(b"\x05\x07!CEI1"),
"3": bytearray(b"\x05\x07FAQiF"),
"4": bytearray(b"\x05\x07x\x08\x08\x08\x7f"),
"5": bytearray(b"\x05\x07rQQQN"),
"6": bytearray(b"\x05\x07\x1e)II\x06"),
"7": bytearray(b"\x05\x07@GHP`"),
"8": bytearray(b"\x05\x076III6"),
"9": bytearray(b"\x05\x070IIJ<"),
")": bytearray(b"\x05\x07\x00A>\x00\x00"),
"(": bytearray(b"\x05\x07\x00\x00>A\x00"),
"[": bytearray(b"\x05\x07\x00\x00\x7fA\x00"),
"]": bytearray(b"\x05\x07\x00A\x7f\x00\x00"),
".": bytearray(b"\x05\x07\x00\x03\x03\x00\x00"),
"'": bytearray(b"\x05\x07\x00\x000\x00\x00"),
":": bytearray(b"\x05\x07\x00\x0066\x00"),
"?CHAR?": bytearray(b"\x05\x07\x7f_RG\x7f"),
"!": bytearray(b"\x05\x07\x00{{\x00\x00"),
"?": bytearray(b"\x05\x07 @EH0"),
",": bytearray(b"\x05\x07\x00\x05\x06\x00\x00"),
";": bytearray(b"\x05\x07\x0056\x00\x00"),
"/": bytearray(b"\x05\x07\x01\x06\x080@"),
">": bytearray(b"\x05\x07Ac6\x1c\x08"),
"<": bytearray(b"\x05\x07\x08\x1c6cA"),
"%": bytearray(b"\x05\x07af\x083C"),
"@": bytearray(b"\x05\x07&IOA>"),
"#": bytearray(b"\x05\x07\x14\x7f\x14\x7f\x14"),
"$": bytearray(b"\x05\x072I\x7fI&"),
"&": bytearray(b'\x05\x076IU"\x05'),
"*": bytearray(b"\x05\x07(\x10|\x10("),
"-": bytearray(b"\x05\x07\x00\x08\x08\x08\x00"),
"_": bytearray(b"\x05\x07\x01\x01\x01\x01\x01"),
"+": bytearray(b"\x05\x07\x08\x08>\x08\x08"),
"=": bytearray(b"\x05\x07\x00\x14\x14\x14\x00"),
'"': bytearray(b"\x05\x07\x00p\x00p\x00"),
"`": bytearray(b"\x05\x07\x00\x00 \x10\x00"),
"~": bytearray(b"\x05\x07\x08\x10\x08\x04\x08"),
" ": bytearray(b"\x05\x07\x00\x00\x00\x00\x00"),
"^": bytearray(b"\x05\x07\x10 @ \x10"),
"NONE": bytearray(b"\x00\x07"),
"BLANK": bytearray(b"\x05\x07\x00\x00\x00\x00\x00"),
"BATA0": bytearray(b"\x0b\x07\x7fAAAAAAAA\x7f\x1c"),
"BATA1": bytearray(b"\x0b\x07\x7fA]AAAAAA\x7f\x1c"),
"BATA2": bytearray(b"\x0b\x07\x7fA]]AAAAA\x7f\x1c"),
"BATA3": bytearray(b"\x0b\x07\x7fA]]]AAAA\x7f\x1c"),
"BATA4": bytearray(b"\x0b\x07\x7fA]]]]AAA\x7f\x1c"),
"BATA5": bytearray(b"\x0b\x07\x7fA]]]]]AA\x7f\x1c"),
"BATA6": bytearray(b"\x0b\x07\x7fA]]]]]]A\x7f\x1c"),
"BATACHRG": bytearray(b"\x07\x08\x7fAIYyOMIA\x7f\x1c"),
"BATB0": bytearray(b"\x0b\x07\x7fAAAAAAAA\x7f\x1c"),
"FULL": bytearray(b"\x05\x07\x7f\x7f\x7f\x7f\x7f"),
"\n": bytearray(b"\x05\x07\x00\x00\x00\x00\x00"),
"DEGREESIGN": bytearray(b"\x05\x07\x18$$\x18\x00"),
}

File diff suppressed because one or more lines are too long

Wyświetl plik

@ -0,0 +1,84 @@
# Copyright © 2020 by Thorsten von Eicken.
from machine import Pin as mPin
from micropython import const
# MCP23017 registers - defined as const(), which makes them module-global
IODIR = const(0)
IOCON = const(0xA)
GPPU = const(0xC)
GPIO = const(0x12)
OLAT = const(0x14)
# MCP23017 is a minimal driver for an 16-bit I2C I/O expander
class MCP23017:
def __init__(self, i2c, addr=0x20):
self.i2c = i2c
self.addr = addr
self.write(IOCON, 0x00)
self.write2(IODIR, 0xFF, 0xFF) # all inputs
self.gpio0 = 0
self.gpio1 = 0
self.write2(GPIO, 0, 0)
# read an 8-bit register, internal method
def read(self, reg):
return self.i2c.readfrom_mem(self.addr, reg, 1)[0]
# write an 8-bit register, internal method
def write(self, reg, v):
self.i2c.writeto_mem(self.addr, reg, bytes((v,)))
# write two 8-bit registers, internal method
def write2(self, reg, v1, v2):
self.i2c.writeto_mem(self.addr, reg, bytes((v1, v2)))
# writebuf writes multiple bytes to the same register
def writebuf(self, reg, v):
self.i2c.writeto_mem(self.addr, reg, v)
# bit reads or sets a bit in a register, caching the gpio register for performance
def bit(self, reg, num, v=None):
if v is None:
data = self.read(reg)
if reg == GPIO:
self.gpio0 = data
elif reg == GPIO + 1:
self.gpio1 = data
return (data >> num) & 1
else:
mask = 0xFF ^ (1 << num)
if reg == GPIO:
self.gpio0 = (self.gpio0 & mask) | ((v & 1) << num)
self.write(reg, self.gpio0)
elif reg == GPIO + 1:
self.gpio1 = (self.gpio1 & mask) | ((v & 1) << num)
self.write(reg, self.gpio1)
else:
data = (self.read(reg) & mask) | ((v & 1) << num)
self.write(reg, data)
def pin(self, num, mode=mPin.IN, pull=None, value=None):
return Pin(self, num, mode, pull, value)
# Pin implements a minimal machine.Pin look-alike for pins on the MCP23017
class Pin:
def __init__(self, mcp23017, num, mode=mPin.IN, pull=None, value=None):
self.bit = mcp23017.bit
incr = num >> 3 # bank selector
self.gpio = GPIO + incr
self.num = num = num & 0x7
if value is not None:
self.bit(self.gpio, num, value)
self.bit(IODIR + incr, num, 1 if mode == mPin.IN else 0)
self.bit(GPPU + incr, num, 1 if pull == mPin.PULL_UP else 0)
# value reads or write a pin value (0 or 1)
def value(self, v=None):
if v is None:
return self.bit(self.gpio, self.num)
else:
self.bit(self.gpio, self.num, v)
__call__ = value

Wyświetl plik

@ -0,0 +1,252 @@
# Copyright © 2020 by Thorsten von Eicken.
# Shapes is intended to be a mix-in that adds methods to a class that is derived from the
# MicroPython framebuf.FrameBuffer class. It adds methods to draw circles, rounded rectangles
# etc. All the code is cobbled together from elsewhere, please refer to the embedded copyright
# notices for the exact provenance.
# Methods in Shapes call self.pixel, self.line, self.hline, and self.vline, so these must be
# provided by the class that Shapes is mixed into.
class Shapes:
# __mix_me_in adds the methods of this class to another class. Typical usage is to put
# something like Shapes.__mix_me_in(MyClass) after the class definition.
@classmethod
def __mix_me_in(cls, target):
for func in dir(cls):
if not callable(getattr(cls, func)) or func.startswith("__"):
continue
setattr(target, func, getattr(cls, func))
# The following shapes are adapted from https://github.com/peterhinch/micropython-epaper
# Copyright 2015 Peter Hinch
#
# Licensed under the Apache License, Version 2.0 (the "License") you may not use this
# file except in compliance with the License. You may obtain a copy of the License at:
#
# http:#www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed under
# the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the specific language governing
# permissions and limitations under the License.
# Code translated and developed from https://developer.mbed.org/users/dreschpe/code/EaEpaper/
def circle(self, x0, y0, r, color): # Single pixel circle
x = -r
y = 0
err = 2 - 2 * r
while x <= 0:
self.pixel(x0 - x, y0 + y, color)
self.pixel(x0 + x, y0 + y, color)
self.pixel(x0 + x, y0 - y, color)
self.pixel(x0 - x, y0 - y, color)
e2 = err
if e2 <= y:
y += 1
err += y * 2 + 1
if -x == y and e2 <= x:
e2 = 0
if e2 > x:
x += 1
err += x * 2 + 1
def fill_circle(self, x0, y0, r, color): # Draw filled circle
x0, y0, r = int(x0), int(y0), int(r)
x = -r
y = 0
err = 2 - 2 * r
while x <= 0:
self.vline(x0 - x, y0 - y, 2*y+1, color)
self.vline(x0 + x, y0 - y, 2*y+1, color)
e2 = err
if e2 <= y:
y += 1
err += y * 2 + 1
if -x == y and e2 <= x:
e2 = 0
if e2 > x:
x += 1
err += x * 2 + 1
# The following shapes are adapted from https://github.com/adafruit/Adafruit_CircuitPython_GFX
# The MIT License (MIT)
#
# Copyright (c) 2018 Kattni Rembor for Adafruit Industries
#
# 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.
def triangle(self, x0, y0, x1, y1, x2, y2, color):
"""Triangle drawing function. Will draw a single pixel wide triangle
around the points (x0, y0), (x1, y1), and (x2, y2)."""
self.line(x0, y0, x1, y1, color)
self.line(x1, y1, x2, y2, color)
self.line(x2, y2, x0, y0, color)
def fill_triangle(self, x0, y0, x1, y1, x2, y2, color):
"""Filled triangle drawing function. Will draw a filled triangle around
the points (x0, y0), (x1, y1), and (x2, y2)."""
if y0 > y1:
y0, y1 = y1, y0
x0, x1 = x1, x0
if y1 > y2:
y2, y1 = y1, y2
x2, x1 = x1, x2
if y0 > y1:
y0, y1 = y1, y0
x0, x1 = x1, x0
a = 0
b = 0
y = 0
last = 0
if y0 == y2:
a = x0
b = x0
if x1 < a:
a = x1
elif x1 > b:
b = x1
if x2 < a:
a = x2
elif x2 > b:
b = x2
self.hline(a, y0, b - a + 1, color)
return
dx01 = x1 - x0
dy01 = y1 - y0
dx02 = x2 - x0
dy02 = y2 - y0
dx12 = x2 - x1
dy12 = y2 - y1
if dy01 == 0:
dy01 = 1
if dy02 == 0:
dy02 = 1
if dy12 == 0:
dy12 = 1
sa = 0
sb = 0
if y1 == y2:
last = y1
else:
last = y1 - 1
for y in range(y0, last + 1):
a = x0 + sa // dy01
b = x0 + sb // dy02
sa += dx01
sb += dx02
if a > b:
a, b = b, a
self.hline(a, y, b - a + 1, color)
sa = dx12 * (y - y1)
sb = dx02 * (y - y0)
while y <= y2:
a = x1 + sa // dy12
b = x0 + sb // dy02
sa += dx12
sb += dx02
if a > b:
a, b = b, a
self.hline(a, y, b - a + 1, color)
y += 1
def round_rect(self, x0, y0, width, height, radius, color):
"""Rectangle with rounded corners drawing function.
This works like a regular rect though! if radius = 0
Will draw the outline of a rextabgle with rounded corners with (x0,y0) at the top left"""
# shift to correct for start point location
x0 += radius
y0 += radius
# ensure that the radius will only ever half of the shortest side or less
radius = int(min(radius, width / 2, height / 2))
if radius:
f = 1 - radius
ddF_x = 1
ddF_y = -2 * radius
x = 0
y = radius
self.vline(x0 - radius, y0, height - 2 * radius + 1, color) # left
self.vline(x0 + width - radius, y0, height - 2 * radius + 1, color) # right
self.hline(x0, y0 + height - radius + 1, width - 2 * radius + 1, color) # bottom
self.hline(x0, y0 - radius, width - 2 * radius + 1, color) # top
while x < y:
if f >= 0:
y -= 1
ddF_y += 2
f += ddF_y
x += 1
ddF_x += 2
f += ddF_x
# angle notations are based on the unit circle and in diection of being drawn
# top left
self.pixel(x0 - y, y0 - x, color) # 180 to 135
self.pixel(x0 - x, y0 - y, color) # 90 to 135
# top right
self.pixel(x0 + x + width - 2 * radius, y0 - y, color) # 90 to 45
self.pixel(x0 + y + width - 2 * radius, y0 - x, color) # 0 to 45
# bottom right
self.pixel(
x0 + y + width - 2 * radius, y0 + x + height - 2 * radius, color
) # 0 to 315
self.pixel(
x0 + x + width - 2 * radius, y0 + y + height - 2 * radius, color
) # 270 to 315
# bottom left
self.pixel(x0 - x, y0 + y + height - 2 * radius, color) # 270 to 255
self.pixel(x0 - y, y0 + x + height - 2 * radius, color) # 180 to 225
def fill_round_rect(self, x0, y0, width, height, radius, color):
"""Filled circle drawing function. Will draw a filled circule with
center at x0, y0 and the specified radius."""
# shift to correct for start point location
x0 += radius
y0 += radius
# ensure that the radius will only ever half of the shortest side or less
radius = int(min(radius, width / 2, height / 2))
self.fill_rect(x0, y0 - radius, width - 2 * radius + 2, height + 2, color)
if radius:
f = 1 - radius
ddF_x = 1
ddF_y = -2 * radius
x = 0
y = radius
while x < y:
if f >= 0:
y -= 1
ddF_y += 2
f += ddF_y
x += 1
ddF_x += 2
f += ddF_x
# part notation starts with 0 on left and 1 on right, and direction is noted
# top left
self.vline(x0 - y, y0 - x, 2 * x + 1 + height - 2 * radius, color) # 0 to .25
self.vline(x0 - x, y0 - y, 2 * y + 1 + height - 2 * radius, color) # .5 to .25
# top right
self.vline(
x0 + x + width - 2 * radius, y0 - y, 2 * y + 1 + height - 2 * radius, color
) # .5 to .75
self.vline(
x0 + y + width - 2 * radius, y0 - x, 2 * x + 1 + height - 2 * radius, color
) # 1 to .75

Wyświetl plik

@ -0,0 +1,8 @@
set(SDKCONFIG_DEFAULTS
boards/sdkconfig.base
boards/sdkconfig.ble
boards/sdkconfig.spiram
)
if(NOT MICROPY_FROZEN_MANIFEST)
set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
endif()

Wyświetl plik

@ -0,0 +1,8 @@
#define MICROPY_HW_BOARD_NAME "Inkplate6"
#define MICROPY_HW_MCU_NAME "ESP32"
// easyC I2C port
#define MICROPY_HW_I2C0_SCL (22)
#define MICROPY_HW_I2C0_SDA (21)