Skip to content

implement non_blocking_marquee #114

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Sep 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
282 changes: 165 additions & 117 deletions adafruit_ht16k33/segments.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
adafruit_ht16k33.segments
=========================
"""

from time import sleep
import time
from adafruit_ht16k33.ht16k33 import HT16K33

try:
Expand All @@ -17,107 +16,106 @@
except ImportError:
pass


__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_HT16K33.git"

# fmt: off
CHARS = (
0b00000000, 0b00000000, #
0b01000000, 0b00000110, # !
0b00000010, 0b00100000, # "
0b00010010, 0b11001110, # #
0b00010010, 0b11101101, # $
0b00001100, 0b00100100, # %
0b00100011, 0b01011101, # &
0b00000100, 0b00000000, # '
0b00100100, 0b00000000, # (
0b00001001, 0b00000000, # )
0b00111111, 0b11000000, # *
0b00010010, 0b11000000, # +
0b00001000, 0b00000000, # ,
0b00000000, 0b11000000, # -
0b00000000, 0b00000000, # .
0b00001100, 0b00000000, # /
0b00001100, 0b00111111, # 0
0b00000000, 0b00000110, # 1
0b00000000, 0b11011011, # 2
0b00000000, 0b10001111, # 3
0b00000000, 0b11100110, # 4
0b00100000, 0b01101001, # 5
0b00000000, 0b11111101, # 6
0b00000000, 0b00000111, # 7
0b00000000, 0b11111111, # 8
0b00000000, 0b11101111, # 9
0b00010010, 0b00000000, # :
0b00001010, 0b00000000, # ;
0b00100100, 0b01000000, # <
0b00000000, 0b11001000, # =
0b00001001, 0b10000000, # >
0b01100000, 0b10100011, # ?
0b00000010, 0b10111011, # @
0b00000000, 0b11110111, # A
0b00010010, 0b10001111, # B
0b00000000, 0b00111001, # C
0b00010010, 0b00001111, # D
0b00000000, 0b11111001, # E
0b00000000, 0b01110001, # F
0b00000000, 0b10111101, # G
0b00000000, 0b11110110, # H
0b00010010, 0b00000000, # I
0b00000000, 0b00011110, # J
0b00100100, 0b01110000, # K
0b00000000, 0b00111000, # L
0b00000101, 0b00110110, # M
0b00100001, 0b00110110, # N
0b00000000, 0b00111111, # O
0b00000000, 0b11110011, # P
0b00100000, 0b00111111, # Q
0b00100000, 0b11110011, # R
0b00000000, 0b11101101, # S
0b00010010, 0b00000001, # T
0b00000000, 0b00111110, # U
0b00001100, 0b00110000, # V
0b00101000, 0b00110110, # W
0b00101101, 0b00000000, # X
0b00010101, 0b00000000, # Y
0b00001100, 0b00001001, # Z
0b00000000, 0b00111001, # [
0b00100001, 0b00000000, # \
0b00000000, 0b00001111, # ]
0b00001100, 0b00000011, # ^
0b00000000, 0b00001000, # _
0b00000001, 0b00000000, # `
0b00010000, 0b01011000, # a
0b00100000, 0b01111000, # b
0b00000000, 0b11011000, # c
0b00001000, 0b10001110, # d
0b00001000, 0b01011000, # e
0b00000000, 0b01110001, # f
0b00000100, 0b10001110, # g
0b00010000, 0b01110000, # h
0b00010000, 0b00000000, # i
0b00000000, 0b00001110, # j
0b00110110, 0b00000000, # k
0b00000000, 0b00110000, # l
0b00010000, 0b11010100, # m
0b00010000, 0b01010000, # n
0b00000000, 0b11011100, # o
0b00000001, 0b01110000, # p
0b00000100, 0b10000110, # q
0b00000000, 0b01010000, # r
0b00100000, 0b10001000, # s
0b00000000, 0b01111000, # t
0b00000000, 0b00011100, # u
0b00100000, 0b00000100, # v
0b00101000, 0b00010100, # w
0b00101000, 0b11000000, # x
0b00100000, 0b00001100, # y
0b00001000, 0b01001000, # z
0b00001001, 0b01001001, # {
0b00010010, 0b00000000, # |
0b00100100, 0b10001001, # }
0b00000101, 0b00100000, # ~
0b00000000, 0b00000000, #
0b01000000, 0b00000110, # !
0b00000010, 0b00100000, # "
0b00010010, 0b11001110, # #
0b00010010, 0b11101101, # $
0b00001100, 0b00100100, # %
0b00100011, 0b01011101, # &
0b00000100, 0b00000000, # '
0b00100100, 0b00000000, # (
0b00001001, 0b00000000, # )
0b00111111, 0b11000000, # *
0b00010010, 0b11000000, # +
0b00001000, 0b00000000, # ,
0b00000000, 0b11000000, # -
0b00000000, 0b00000000, # .
0b00001100, 0b00000000, # /
0b00001100, 0b00111111, # 0
0b00000000, 0b00000110, # 1
0b00000000, 0b11011011, # 2
0b00000000, 0b10001111, # 3
0b00000000, 0b11100110, # 4
0b00100000, 0b01101001, # 5
0b00000000, 0b11111101, # 6
0b00000000, 0b00000111, # 7
0b00000000, 0b11111111, # 8
0b00000000, 0b11101111, # 9
0b00010010, 0b00000000, # :
0b00001010, 0b00000000, # ;
0b00100100, 0b01000000, # <
0b00000000, 0b11001000, # =
0b00001001, 0b10000000, # >
0b01100000, 0b10100011, # ?
0b00000010, 0b10111011, # @
0b00000000, 0b11110111, # A
0b00010010, 0b10001111, # B
0b00000000, 0b00111001, # C
0b00010010, 0b00001111, # D
0b00000000, 0b11111001, # E
0b00000000, 0b01110001, # F
0b00000000, 0b10111101, # G
0b00000000, 0b11110110, # H
0b00010010, 0b00000000, # I
0b00000000, 0b00011110, # J
0b00100100, 0b01110000, # K
0b00000000, 0b00111000, # L
0b00000101, 0b00110110, # M
0b00100001, 0b00110110, # N
0b00000000, 0b00111111, # O
0b00000000, 0b11110011, # P
0b00100000, 0b00111111, # Q
0b00100000, 0b11110011, # R
0b00000000, 0b11101101, # S
0b00010010, 0b00000001, # T
0b00000000, 0b00111110, # U
0b00001100, 0b00110000, # V
0b00101000, 0b00110110, # W
0b00101101, 0b00000000, # X
0b00010101, 0b00000000, # Y
0b00001100, 0b00001001, # Z
0b00000000, 0b00111001, # [
0b00100001, 0b00000000, # \
0b00000000, 0b00001111, # ]
0b00001100, 0b00000011, # ^
0b00000000, 0b00001000, # _
0b00000001, 0b00000000, # `
0b00010000, 0b01011000, # a
0b00100000, 0b01111000, # b
0b00000000, 0b11011000, # c
0b00001000, 0b10001110, # d
0b00001000, 0b01011000, # e
0b00000000, 0b01110001, # f
0b00000100, 0b10001110, # g
0b00010000, 0b01110000, # h
0b00010000, 0b00000000, # i
0b00000000, 0b00001110, # j
0b00110110, 0b00000000, # k
0b00000000, 0b00110000, # l
0b00010000, 0b11010100, # m
0b00010000, 0b01010000, # n
0b00000000, 0b11011100, # o
0b00000001, 0b01110000, # p
0b00000100, 0b10000110, # q
0b00000000, 0b01010000, # r
0b00100000, 0b10001000, # s
0b00000000, 0b01111000, # t
0b00000000, 0b00011100, # u
0b00100000, 0b00000100, # v
0b00101000, 0b00010100, # w
0b00101000, 0b11000000, # x
0b00100000, 0b00001100, # y
0b00001000, 0b01001000, # z
0b00001001, 0b01001001, # {
0b00010010, 0b00000000, # |
0b00100100, 0b10001001, # }
0b00000101, 0b00100000, # ~
0b00111111, 0b11111111,
)
# fmt: on
Expand Down Expand Up @@ -189,6 +187,10 @@ def __init__(

self._chars = chars_per_display * len(self.i2c_device)
self._bytes_per_char = 2
self._last_nb_scroll_time = -1
self._nb_scroll_text = None
self._nb_scroll_index = -1
self._nb_prev_char_is_dot = False

def print(self, value: Union[str, float], decimal: int = 0) -> None:
"""Print the value to the display.
Expand Down Expand Up @@ -367,38 +369,84 @@ def set_digit_raw(
if self._auto_write:
self.show()

def marquee(self, text: str, delay: float = 0.25, loop: bool = True) -> None:
def non_blocking_marquee(
self,
text: str,
delay: float = 0.25,
loop: bool = True,
space_between: bool = False,
) -> bool:
"""
Automatically scroll the text at the specified delay between characters
Scroll the text at the specified delay between characters. Must be called
repeatedly from main loop faster than delay time.

:param str text: The text to display
:param float delay: (optional) The delay in seconds to pause before scrolling
to the next character (default=0.25)
:param bool loop: (optional) Whether to endlessly loop the text (default=True)

:param bool space_between: (optional) Whether to seperate the end and beginning of
the text with a space. (default=False)
"""
# pylint: disable=too-many-nested-blocks
if isinstance(text, str):
self.fill(False)
if loop:
while True:
self._scroll_marquee(text, delay)
now = time.monotonic()
# if text is the same
if text == self._nb_scroll_text:
# if we delayed long enough, and it's time to scroll
if now >= self._last_nb_scroll_time + delay:
# if there are chars left in the text
if self._nb_scroll_index + 1 < len(text):
self._nb_scroll_index += 1

_character = text[self._nb_scroll_index]

if _character != "." or self._nb_prev_char_is_dot:
self._last_nb_scroll_time = now

self.print(text[self._nb_scroll_index])
self._nb_prev_char_is_dot = text[self._nb_scroll_index] == "."
else:
self._nb_scroll_index = -1
if loop:
if space_between:
self._last_nb_scroll_time = now
self.print(" ")
else:
return True
else:
self._scroll_marquee(text, delay)
# different text
self._nb_scroll_index = 0
self.fill(False)
self._nb_scroll_text = text
self._last_nb_scroll_time = now
self.print(text[0])

def _scroll_marquee(self, text: str, delay: float) -> None:
"""Scroll through the text string once using the delay"""
char_is_dot = False
for character in text:
self.print(character)
# Add delay if character is not a dot or more than 2 in a row
if character != "." or char_is_dot:
sleep(delay)
char_is_dot = character == "."
self.show()
return False

def marquee(
self, text: str, delay: float = 0.25, loop: bool = True, space_between=False
) -> None:
"""
Automatically scroll the text at the specified delay between characters

:param str text: The text to display
:param float delay: (optional) The delay in seconds to pause before scrolling
to the next character (default=0.25)
:param bool loop: (optional) Whether to endlessly loop the text (default=True)
:param bool space_between: (optional) Whether to seperate the end and beginning of
the text with a space. (default=False)
"""
if isinstance(text, str):
self.fill(False)
while True:
if self.non_blocking_marquee(
text=text, delay=delay, loop=loop, space_between=space_between
):
return


class _AbstractSeg7x4(Seg14x4):
POSITIONS = (0, 2, 6, 8) # The positions of characters.
POSITIONS = (0, 2, 6, 8) # The positions of characters.

def __init__( # pylint: disable=too-many-arguments
self,
Expand Down
31 changes: 31 additions & 0 deletions examples/ht16k33_segments_non_blocking_marquee.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# SPDX-FileCopyrightText: 2023 Tim Cocks for Adafruit Industries
# SPDX-License-Identifier: MIT
"""
Example that uses Non-Blocking Marquee to scroll text on 14x4 segment
while also blinking the on-board neopixel at a different rate from the
marquee scrolling.
"""

import time
import board
import neopixel
import adafruit_ht16k33.segments


i2c = board.I2C()
segment_display = adafruit_ht16k33.segments.Seg14x4(i2c)

pixel_pin = board.NEOPIXEL
pixels = neopixel.NeoPixel(pixel_pin, 1, brightness=0.1, auto_write=True)

pixels[0] = 0xFF0000
last_blink = 0
while True:
now = time.monotonic()
if now > last_blink + 0.3:
if pixels[0] == (255, 0, 255):
pixels[0] = 0x00FF00
else:
pixels[0] = 0xFF00FF
last_blink = now
segment_display.non_blocking_marquee("CircuitPython <3", delay=0.2)