Skip to content
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

No waveshare epaper hat available? Can fake it via the terminal console #45

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
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
9 changes: 9 additions & 0 deletions src/color_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,12 @@
gc.collect() # Precaution before instantiating framebuf
ssd = SSD(spi, pcs, pdc, prst, pbusy, landscape=True, asyn=False, full=True) # Create a display instance ssd = SSD(spi, pcs, pdc, prst, pbusy, landscape=True, asyn=False, full=False) for partial refresh
# ssdred = SSDred(spi, pcs, pdc, prst, pbusy, landscape=False) # Cread a red display instance (just for B model)

# begin #NO_SCREEN_AVAILABLE#
# If no e-paper-display: sleep it, cleanup, redefine ssd
ssd.sleep()
del RST_PIN, DC_PIN, CS_PIN, BUSY_PIN, prst, pbusy, spi, pdc, ssd, SSD
gc.collect()
from drivers.console_display import MonoConsoleDisplay as SSD
ssd = SSD(296, 128, "MONO_HLSB", invert=True)
# end #NO_SCREEN_AVAILABLE#
163 changes: 163 additions & 0 deletions src/drivers/console_display.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import framebuf


# index is binary representation of upper pixel + lower pixel
UTFBLKS = (
" ", # 0b00 or 0: space
chr(0x2584), # 0b01 or 1: lower-half
chr(0x2580), # 0b10 or 2: upper-half
chr(0x2588) # 0b11 or 3: full block
)
UTFBORDER = chr(0x2593) # shade


def hpixels_1x2(top, bottom, lsb=True):
"""
receives top and bottom byte for 8 1x2 pixel couples,
returns joined string of block elements to represent 8x2 pixel tile

top and bottom are both bitwise-anded with 2**i to select bit[i].
those powers of 2 are fed to int(bool()) resulting in 0 or 1 for each.
top is left shifted 1 bit then bitwise-ored with bottom for an intval (0-3)
to be used indexing UTFBLKS.
"""
bits = range(8)
if lsb:
bits = reversed(bits)

return ''.join(
(UTFBLKS[int(bool(top & 2**i)) << 1 | int(bool(bottom & 2**i))]
for i in bits
)
)


def vpixels_1x2(vpix_bytes):
"""
receives bytes of 8 vertical pixels side-by-side,
returns 4tuple of UTFBLKS indices of 1x2 pixels from left to right

each byte is bitwise-anded with 2**i to select bit[i] for all 8 bits.
those powers of 2 are fed to int(bool()) resulting in 0 or 1 for each.
the odd bits are left shifted 1 then ored with the adjacent even bit
for an intval (0-3) to be used by caller for indexing UTFBLKS.
"""
bits = range(0,8,2)

return tuple([
[row[j] for row in [
[int(bool(x & 2**i)) << 1 | int(bool(x & 2**(i+1))) for i in bits]
for x in vpix_bytes
]] for j in range(4)
])


def mono_vlsb(buf, w, h, invert=False, footnote=""):
'''
interprets buf as a MONO_VLSB frame buffer,
uses unicode block-element characters to display 4 possible 1x2 pixel couples,
8 pixel rows at a time -- 2 per line, from left to right and down.
'''

buf = bytearray(buf)
assert len(buf) == w // 8 * h
assert h % 8 == 0

if invert:
buf = bytearray([x ^ 255 for x in buf])

print(UTFBORDER * (w + 4))
for i in range(0, len(buf), w):
for line in vpixels_1x2(buf[i:i+w]):
print('{}{}{}'.format(
UTFBORDER * 2,
''.join([UTFBLKS[x] for x in line]),
UTFBORDER * 2
))
print(UTFBORDER * (2 + w - len(footnote)) + footnote + UTFBORDER * 2)


def mono_hlsb(buf, w, h, invert=False, footnote=""):
'''
interprets buf as a MONO_HLSB frame buffer,
uses unicode block-element characters to display 4 possible 1x2 pixel couples,
two pixel rows per line, from left to right and down.
'''
buf = bytearray(buf)
assert len(buf) == w // 8 * h
assert h % 2 == 0

if invert:
buf = bytearray([x ^ 255 for x in buf])

print(UTFBORDER * (w + 4))
for i in range(0, len(buf), w//8*2):
print("{}{}{}".format(
UTFBORDER * 2,
''.join((hpixels_1x2(buf[x], buf[x+w//8]) for x in range(i, i+w//8))),
UTFBORDER * 2
))
print(UTFBORDER * (2 + w - len(footnote)) + footnote + UTFBORDER * 2)


def mono_hmsb(buf, w, h, invert=False, footnote=""):
'''
interprets buf as a MONO_HMSB frame buffer,
uses unicode block-element characters to display 4 possible 1x2 pixel couples,
two pixel rows per line, from left to right and down.
'''
buf = bytearray(buf)
assert len(buf) == w // 8 * h
assert h % 2 == 0

if invert:
buf = bytearray([x ^ 255 for x in buf])

print(UTFBORDER * (w + 4))
for i in range(0, len(buf), w//8*2):
print("{}{}{}".format(
UTFBORDER * 2,
''.join((hpixels_1x2(buf[x], buf[x+w//8], lsb=False) for x in range(i, i+w//8))),
UTFBORDER * 2
))
print(UTFBORDER * (2 + w - len(footnote)) + footnote + UTFBORDER * 2)


class MonoConsoleDisplay(framebuf.FrameBuffer):
def __init__(self, width, height, mode="MONO_HLSB", invert=False):
self.width = int(width)
self.height = int(height)
if mode == "MONO_VLSB":
self.mode = framebuf.MONO_VLSB
self.renderer = mono_vlsb
elif mode == "MONO_HMSB":
self.mode = framebuf.MONO_HMSB
self.renderer = mono_hmsb
elif mode == "MONO_HLSB":
self.mode = framebuf.MONO_HLSB
self.renderer = mono_hlsb
else:
raise ValueError("mode not supported: %s" % mode)
self.invert = bool(invert)
self.buffer = bytearray(width // 8 * height)
self.show_calls = 0
super().__init__(self.buffer, width, height, self.mode)

@staticmethod
def rgb(r, g, b):
return int((r|g|b) > 0x7f)

def show(self):
self.show_calls += 1
self.renderer(self, self.width, self.height, invert=self.invert,
footnote=" {} {}, {} ".format(
"{}x{}".format(self.width, self.height),
self.renderer.__name__,
"show() calls: {}".format(self.show_calls)
)
)

def init(self): pass
def init_partial(self): pass
def wait_until_ready(self): pass
def sleep(self): pass