kopia lustrzana https://github.com/micropython/micropython
esp32/boards: Add INKPLATE6 board.
rodzic
71344c15f4
commit
93172021b5
|
@ -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.
|
|
@ -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"
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
The following files are daily firmware builds for the Inkplate6.
|
|
@ -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
|
||||
```
|
|
@ -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()
|
|
@ -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)
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
include("$(PORT_DIR)/boards/manifest.py")
|
||||
freeze("modules")
|
|
@ -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
|
|
@ -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
Plik diff jest za duży
Load Diff
|
@ -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
|
|
@ -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
|
|
@ -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()
|
|
@ -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)
|
||||
|
||||
|
Ładowanie…
Reference in New Issue