# SPDX-FileCopyrightText: 2017 Dan Halbert for Adafruit Industries
# SPDX-FileCopyrightText: 2021 Daniel Flanagan
#
# SPDX-License-Identifier: MIT
"""
`adafruit_max7219.matrices`
====================================================
"""
from micropython import const
from adafruit_framebuf import BitmapFont
from adafruit_max7219 import max7219
try:
# Used only for typing
from typing import Tuple
import digitalio
import busio
except ImportError:
pass
__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_MAX7219.git"
_DECODEMODE = const(9)
_SCANLIMIT = const(11)
_SHUTDOWN = const(12)
_DISPLAYTEST = const(15)
[docs]
class Matrix8x8(max7219.MAX7219):
"""
Driver for a 8x8 LED matrix based on the MAX7219 chip.
:param ~busio.SPI spi: an spi busio or spi bitbangio object
:param ~digitalio.DigitalInOut cs: digital in/out to use as chip select signal
"""
def __init__(self, spi: busio.SPI, cs: digitalio.DigitalInOut):
super().__init__(8, 8, spi, cs)
[docs]
def init_display(self) -> None:
for cmd, data in (
(_SHUTDOWN, 0),
(_DISPLAYTEST, 0),
(_SCANLIMIT, 7),
(_DECODEMODE, 0),
(_SHUTDOWN, 1),
):
self.write_cmd(cmd, data)
self.fill(0)
self.show()
[docs]
def text(
self,
strg: str,
xpos: int,
ypos: int,
bit_value: int = 1,
*,
font_name: str = "font5x8.bin"
) -> None:
"""
Draw text in the 8x8 matrix.
:param str strg: string to place in to display
:param int xpos: x position of LED in matrix
:param int ypos: y position of LED in matrix
:param int bit_value: > 1 sets the text, otherwise resets
:param str font_name: path to binary font file (default: "font5x8.bin").
The font can only be set once, if you want a different font you must
re-initialize the matrix.
"""
self.framebuf.text(strg, xpos, ypos, bit_value, font_name=font_name)
[docs]
def clear_all(self) -> None:
"""
Clears all matrix leds.
"""
self.fill(0)
[docs]
class CustomMatrix(max7219.ChainableMAX7219):
"""
Driver for a custom 8x8 LED matrix constellation based on daisy chained MAX7219 chips.
:param ~busio.SPI spi: an spi busio or spi bitbangio object
:param ~digitalio.DigitalInOut cs: digital in/out to use as chip select signal
:param int width: the number of pixels wide
:param int height: the number of pixels high
:param int rotation: the number of times to rotate the coordinate system (default 1)
"""
def __init__(
self,
spi: busio.SPI,
cs: digitalio.DigitalInOut,
width: int,
height: int,
*,
rotation: int = 1
):
super().__init__(width, height, spi, cs)
self.y_offset = width // 8
self.y_index = self._calculate_y_coordinate_offsets()
self.framebuf.rotation = rotation
self.framebuf.fill_rect = self._fill_rect
self._font = None
def _calculate_y_coordinate_offsets(self) -> None:
y_chunks = []
for _ in range(self.chain_length // (self.width // 8)):
y_chunks.append([])
chunk = 0
chunk_size = 0
for index in range(self.chain_length * 8):
y_chunks[chunk].append(index)
chunk_size += 1
if chunk_size >= (self.width // 8):
chunk_size = 0
chunk += 1
if chunk >= len(y_chunks):
chunk = 0
y_index = []
for chunk in y_chunks:
y_index += chunk
return y_index
[docs]
def init_display(self) -> None:
for cmd, data in (
(_SHUTDOWN, 0),
(_DISPLAYTEST, 0),
(_SCANLIMIT, 7),
(_DECODEMODE, 0),
(_SHUTDOWN, 1),
):
self.write_cmd(cmd, data)
self.fill(0)
self.show()
[docs]
def clear_all(self) -> None:
"""
Clears all matrix leds.
"""
self.fill(0)
# pylint: disable=inconsistent-return-statements
[docs]
def pixel(self, xpos: int, ypos: int, bit_value: int = None) -> None:
"""
Set one buffer bit
:param int xpos: x position to set bit
:param int ypos: y position to set bit
:param int bit_value: value > 0 sets the buffer bit, else clears the buffer bit
"""
if xpos < 0 or ypos < 0 or xpos >= self.width or ypos >= self.height:
return
buffer_x, buffer_y = self._pixel_coords_to_framebuf_coords(xpos, ypos)
return super().pixel(buffer_x, buffer_y, bit_value=bit_value)
def _pixel_coords_to_framebuf_coords(self, xpos: int, ypos: int) -> Tuple[int]:
"""
Convert matrix pixel coordinates into coordinates in the framebuffer
:param int xpos: x position
:param int ypos: y position
:return: framebuffer coordinates (x, y)
:rtype: Tuple[int]
"""
return (xpos - ((xpos // 8) * 8)) % 8, xpos // 8 + self.y_index[
ypos * self.y_offset
]
def _get_pixel(self, xpos: int, ypos: int) -> int:
"""
Get value of a matrix pixel
:param int xpos: x position
:param int ypos: y position
:return: value of pixel in matrix
:rtype: int
"""
x, y = self._pixel_coords_to_framebuf_coords(xpos, ypos)
buffer_value = self._buffer[-1 * y - 1]
return ((buffer_value & 2**x) >> x) & 1
# Adafruit Circuit Python Framebuf Scroll Function
# Authors: Kattni Rembor, Melissa LeBlanc-Williams and Tony DiCola, for Adafruit Industries
# License: MIT License (https://opensource.org/licenses/MIT)
[docs]
def rect(
self, x: int, y: int, width: int, height: int, color: int, fill: bool = False
) -> None:
"""
Draw a rectangle at the given position of the given size, color, and fill.
:param int x: x position
:param int y: y position
:param int width: width of rectangle
:param int height: height of rectangle
:param int color: color of rectangle
:param bool fill: 1 pixel outline or filled rectangle (default: False)
"""
# pylint: disable=too-many-arguments
for row in range(height):
y_pos = row + y
for col in range(width):
x_pos = col + x
if fill:
self.pixel(x_pos, y_pos, color)
elif y_pos in (y, y + height - 1) or x_pos in (x, x + width - 1):
self.pixel(x_pos, y_pos, color)
else:
continue
def _fill_rect(self, x: int, y: int, width: int, height: int, color: int) -> None:
"""
Draw a filled rectangle at the given position of the given size, color.
:param int x: x position
:param int y: y position
:param int width: width of rectangle
:param int height: height of rectangle
:param int color: color of rectangle
"""
# pylint: disable=too-many-arguments
return self.rect(x, y, width, height, color, True)
# Adafruit Circuit Python Framebuf Text Function
# Authors: Kattni Rembor, Melissa LeBlanc-Williams and Tony DiCola, for Adafruit Industries
# License: MIT License (https://opensource.org/licenses/MIT)
[docs]
def text(
self,
strg: str,
xpos: int,
ypos: int,
color: int = 1,
*,
font_name: str = "font5x8.bin",
size: int = 1
) -> None:
"""
Draw text in the matrix.
:param str strg: string to place in to display
:param int xpos: x position of LED in matrix
:param int ypos: y position of LED in matrix
:param int color: > 1 sets the text, otherwise resets
:param str font_name: path to binary font file (default: "font5x8.bin")
:param int size: size of the font, acts as a multiplier
"""
for chunk in strg.split("\n"):
if not self._font or self._font.font_name != font_name:
# load the font!
self._font = BitmapFont(font_name)
width = self._font.font_width
height = self._font.font_height
for i, char in enumerate(chunk):
char_x = xpos + (i * (width + 1)) * size
if (
char_x + (width * size) > 0
and char_x < self.width
and ypos + (height * size) > 0
and ypos < self.height
):
self._font.draw_char(
char, char_x, ypos, self.framebuf, color, size=size
)
ypos += height * size