@@ -0,0 +1,11 @@ | |||||
all: images download | |||||
images: | |||||
cd gallery && for F in *.jpg; do ./convert_image.sh $F $F.bmp | |||||
download: jokes.json | |||||
jokes.json: | |||||
curl -o jokes.json https://github.com/wiz64/superfun/raw/main/database/ichd/jokes-file.json | |||||
@@ -0,0 +1,124 @@ | |||||
import epaper | |||||
import microbmp | |||||
import time | |||||
import random | |||||
import os | |||||
import storage | |||||
import gc | |||||
epd_colormap = [ | |||||
[0x00, 0x00, 0x00], # black | |||||
[0xff, 0xff, 0xff], # white | |||||
[0x00, 0x90, 0x10], # green | |||||
[0x00, 0x00, 0xee], # blue | |||||
[0xff, 0x00, 0x00], # red | |||||
[0xff, 0xdd, 0x00], # yellow | |||||
[0xff, 0x77, 0x00], # orange | |||||
] | |||||
max_free_height = 200 | |||||
def init_display(): | |||||
#print("ePaper init ", str(time.localtime())) | |||||
epd = epaper.EPD_5in65() | |||||
epd.fill(epd.White) | |||||
return epd | |||||
def draw_image(epd, filename): | |||||
global epd_colormap | |||||
global free_x, free_y, free_width, free_height | |||||
offset_x = 0 | |||||
offset_y = 0 | |||||
free_x = 0 | |||||
free_y = 0 | |||||
free_width = 0 | |||||
free_height = 0 | |||||
color_map = {} | |||||
def header_callback(header): | |||||
#print("header callback: ", str(header)) | |||||
#global epd | |||||
global offset_x, offset_y | |||||
global free_x, free_y, free_width, free_height | |||||
global max_free_height | |||||
w = header[0] | |||||
h = header[1] | |||||
rest_x = (epd.width - w) | |||||
rest_y = (epd.height - h) | |||||
free_x = 0 | |||||
free_y = max(h, epd.height - max_free_height) | |||||
free_width = epd.width | |||||
free_height = min(rest_y, max_free_height) | |||||
offset_x = rest_x//2 | |||||
offset_y = max(0, rest_y - max_free_height)//2 | |||||
def pixel_callback(x, y, color): | |||||
#global epd | |||||
global epd_colormap | |||||
global offset_x, offset_y | |||||
# translate color to color index | |||||
color_index = 0 | |||||
color_key = color[0] + color[1] << 8 + color[2] << 16 | |||||
if color_key in color_map: | |||||
color_index = color_map[color_key] | |||||
else: | |||||
# search for the best color | |||||
best_index = 0 | |||||
best_score = 1000 | |||||
for index in range(len(epd_colormap)): | |||||
c1 = epd_colormap[index] | |||||
c2 = color | |||||
score = abs(c1[0] - c2[0]) + abs(c1[1] - c2[1]) + abs(c1[2] - c2[2]) | |||||
if score < best_score: | |||||
best_score = score | |||||
best_index = index | |||||
if score < 10: | |||||
break | |||||
color_index = best_index | |||||
color_map[color_key] = color_index | |||||
epd.pixel(offset_x + x, offset_y + y, color_index) | |||||
#print(str(time.localtime()), " BMP ", filename, " loading") | |||||
time_start = time.ticks_ms() | |||||
epd.fill(epd.White) | |||||
microbmp.MicroBMP(header_callback=header_callback, data_callback=pixel_callback).load(filename) | |||||
time_loaded = time.ticks_ms() | |||||
print(" time to load: ", (time_loaded - time_start) / 1000, " s") | |||||
#print(str(time.localtime()), " BMP loaded") | |||||
#epd.EPD_5IN65F_Display(epd.buffer) | |||||
#print(str(time.localtime()), " ePaper printed") | |||||
return [free_x, free_y, free_width, free_height] | |||||
def draw_pattern(epd): | |||||
free_x = 0 | |||||
free_y = 400 | |||||
free_width = epd.width | |||||
free_height = epd.height - free_y | |||||
epd.fill_rect(0, 0, epd.width, free_y, random.randrange(2,7)) | |||||
return [free_x, free_y, free_width, free_height] | |||||
def print_text(epd, text, region, center=False): | |||||
fnt = 8 | |||||
x = region[0] | |||||
y = region[1] | |||||
w = region[2] | |||||
h = region[3] | |||||
if center: | |||||
x = (w - len(text)*fnt) // 2 | |||||
epd.text(text, x, y, epd.Black) | |||||
def draw_extra(epd, region, caption): | |||||
fnt = 8 | |||||
region[0] += 5 | |||||
region[1] += 8 | |||||
if region[2] < fnt or region[3] < fnt: | |||||
print("Not enough space for extra: ", str(region)) | |||||
return | |||||
#epd.rect(region[0], region[1], region[2], region[3], epd.Black) | |||||
#region[0] += random.randrange(50) | |||||
#print_text(str(time.localtime()), region, center=True) | |||||
if caption is not None: | |||||
#region[1] += fnt * 2 | |||||
print_text(epd, caption, region) | |||||
print("Caption: ", caption) | |||||
else: | |||||
print("No caption") | |||||
@@ -0,0 +1,52 @@ | |||||
import epaper | |||||
import microbmp | |||||
import time | |||||
import random | |||||
import os | |||||
import storage | |||||
import display | |||||
import gc | |||||
gc.enable() | |||||
epd = display.init_display() | |||||
disk = storage.Storage() | |||||
while True: | |||||
disk.mount() | |||||
images = list(filter(lambda x : x.endswith(".bmp"), os.listdir(disk.get_root_path()))) | |||||
epd.EPD_5IN65F_Init() | |||||
epd.fill(epd.White) | |||||
filename = random.choice(images) | |||||
print("TV drawing image ", filename) | |||||
free_space = [0,0,0,0] | |||||
try: | |||||
free_space = display.draw_image(epd, disk.get_root_path() + "/" + filename) | |||||
except Exception as e: | |||||
print("Failed drawing image from disk: ", e) | |||||
try: | |||||
free_space = display.draw_image(epd, "tiny.bmp") | |||||
except Exception as e: | |||||
print("Failed drawing fallback image: ", e) | |||||
free_space = display.draw_pattern(epd) | |||||
caption = None | |||||
try: | |||||
caption = storage.load_joke(disk.get_root_path()) | |||||
except Exception as e: | |||||
print("Failed loading a joke: ", e) | |||||
try: | |||||
display.draw_extra(epd, free_space, caption) | |||||
except Exception as e: | |||||
print("Failed drawing extra: ", e) | |||||
time_render_start = time.ticks_ms() | |||||
epd.EPD_5IN65F_Display(epd.buffer) | |||||
time_render_stop = time.ticks_ms() | |||||
print(" time to render: ", (time_render_stop - time_render_start) / 1000, " s") | |||||
print("TV showing ", filename) | |||||
epd.Sleep() | |||||
disk.umount() | |||||
print("") | |||||
gc.collect() | |||||
epd.delay_ms(10000 * 1) | |||||
@@ -0,0 +1,307 @@ | |||||
""" | |||||
MicroPython driver for SD cards using SPI bus. | |||||
Requires an SPI bus and a CS pin. Provides readblocks and writeblocks | |||||
methods so the device can be mounted as a filesystem. | |||||
Example usage on pyboard: | |||||
import pyb, sdcard, os | |||||
sd = sdcard.SDCard(pyb.SPI(1), pyb.Pin.board.X5) | |||||
pyb.mount(sd, '/sd2') | |||||
os.listdir('/') | |||||
Example usage on ESP8266: | |||||
import machine, sdcard, os | |||||
sd = sdcard.SDCard(machine.SPI(1), machine.Pin(15)) | |||||
os.mount(sd, '/sd') | |||||
os.listdir('/') | |||||
S.ource: https://raw.githubusercontent.com/micropython/micropython-lib/master/micropython/drivers/storage/sdcard/sdcard.py | |||||
""" | |||||
from micropython import const | |||||
import time | |||||
_CMD_TIMEOUT = const(100) | |||||
_R1_IDLE_STATE = const(1 << 0) | |||||
# R1_ERASE_RESET = const(1 << 1) | |||||
_R1_ILLEGAL_COMMAND = const(1 << 2) | |||||
# R1_COM_CRC_ERROR = const(1 << 3) | |||||
# R1_ERASE_SEQUENCE_ERROR = const(1 << 4) | |||||
# R1_ADDRESS_ERROR = const(1 << 5) | |||||
# R1_PARAMETER_ERROR = const(1 << 6) | |||||
_TOKEN_CMD25 = const(0xFC) | |||||
_TOKEN_STOP_TRAN = const(0xFD) | |||||
_TOKEN_DATA = const(0xFE) | |||||
class SDCard: | |||||
def __init__(self, spi, cs, baudrate=1320000): | |||||
self.spi = spi | |||||
self.cs = cs | |||||
self.cmdbuf = bytearray(6) | |||||
self.dummybuf = bytearray(512) | |||||
self.tokenbuf = bytearray(1) | |||||
for i in range(512): | |||||
self.dummybuf[i] = 0xFF | |||||
self.dummybuf_memoryview = memoryview(self.dummybuf) | |||||
# initialise the card | |||||
self.init_card(baudrate) | |||||
def init_spi(self, baudrate): | |||||
try: | |||||
master = self.spi.MASTER | |||||
except AttributeError: | |||||
# on ESP8266 | |||||
self.spi.init(baudrate=baudrate, phase=0, polarity=0) | |||||
else: | |||||
# on pyboard | |||||
self.spi.init(master, baudrate=baudrate, phase=0, polarity=0) | |||||
def init_card(self, baudrate): | |||||
# init CS pin | |||||
self.cs.init(self.cs.OUT, value=1) | |||||
# init SPI bus; use low data rate for initialisation | |||||
self.init_spi(100000) | |||||
# clock card at least 100 cycles with cs high | |||||
for i in range(16): | |||||
self.spi.write(b"\xff") | |||||
# CMD0: init card; should return _R1_IDLE_STATE (allow 5 attempts) | |||||
for _ in range(5): | |||||
if self.cmd(0, 0, 0x95) == _R1_IDLE_STATE: | |||||
break | |||||
else: | |||||
raise OSError("no SD card") | |||||
# CMD8: determine card version | |||||
r = self.cmd(8, 0x01AA, 0x87, 4) | |||||
if r == _R1_IDLE_STATE: | |||||
self.init_card_v2() | |||||
elif r == (_R1_IDLE_STATE | _R1_ILLEGAL_COMMAND): | |||||
self.init_card_v1() | |||||
else: | |||||
raise OSError("couldn't determine SD card version") | |||||
# get the number of sectors | |||||
# CMD9: response R2 (R1 byte + 16-byte block read) | |||||
if self.cmd(9, 0, 0, 0, False) != 0: | |||||
raise OSError("no response from SD card") | |||||
csd = bytearray(16) | |||||
self.readinto(csd) | |||||
if csd[0] & 0xC0 == 0x40: # CSD version 2.0 | |||||
self.sectors = ((csd[8] << 8 | csd[9]) + 1) * 1024 | |||||
elif csd[0] & 0xC0 == 0x00: # CSD version 1.0 (old, <=2GB) | |||||
c_size = (csd[6] & 0b11) << 10 | csd[7] << 2 | csd[8] >> 6 | |||||
c_size_mult = (csd[9] & 0b11) << 1 | csd[10] >> 7 | |||||
read_bl_len = csd[5] & 0b1111 | |||||
capacity = (c_size + 1) * (2 ** (c_size_mult + 2)) * (2**read_bl_len) | |||||
self.sectors = capacity // 512 | |||||
else: | |||||
raise OSError("SD card CSD format not supported") | |||||
# print('sectors', self.sectors) | |||||
# CMD16: set block length to 512 bytes | |||||
if self.cmd(16, 512, 0) != 0: | |||||
raise OSError("can't set 512 block size") | |||||
# set to high data rate now that it's initialised | |||||
self.init_spi(baudrate) | |||||
def init_card_v1(self): | |||||
for i in range(_CMD_TIMEOUT): | |||||
time.sleep_ms(50) | |||||
self.cmd(55, 0, 0) | |||||
if self.cmd(41, 0, 0) == 0: | |||||
# SDSC card, uses byte addressing in read/write/erase commands | |||||
self.cdv = 512 | |||||
# print("[SDCard] v1 card") | |||||
return | |||||
raise OSError("timeout waiting for v1 card") | |||||
def init_card_v2(self): | |||||
for i in range(_CMD_TIMEOUT): | |||||
time.sleep_ms(50) | |||||
self.cmd(58, 0, 0, 4) | |||||
self.cmd(55, 0, 0) | |||||
if self.cmd(41, 0x40000000, 0) == 0: | |||||
self.cmd(58, 0, 0, -4) # 4-byte response, negative means keep the first byte | |||||
ocr = self.tokenbuf[0] # get first byte of response, which is OCR | |||||
if not ocr & 0x40: | |||||
# SDSC card, uses byte addressing in read/write/erase commands | |||||
self.cdv = 512 | |||||
else: | |||||
# SDHC/SDXC card, uses block addressing in read/write/erase commands | |||||
self.cdv = 1 | |||||
# print("[SDCard] v2 card") | |||||
return | |||||
raise OSError("timeout waiting for v2 card") | |||||
def cmd(self, cmd, arg, crc, final=0, release=True, skip1=False): | |||||
self.cs(0) | |||||
# create and send the command | |||||
buf = self.cmdbuf | |||||
buf[0] = 0x40 | cmd | |||||
buf[1] = arg >> 24 | |||||
buf[2] = arg >> 16 | |||||
buf[3] = arg >> 8 | |||||
buf[4] = arg | |||||
buf[5] = crc | |||||
self.spi.write(buf) | |||||
if skip1: | |||||
self.spi.readinto(self.tokenbuf, 0xFF) | |||||
# wait for the response (response[7] == 0) | |||||
for i in range(_CMD_TIMEOUT): | |||||
self.spi.readinto(self.tokenbuf, 0xFF) | |||||
response = self.tokenbuf[0] | |||||
if not (response & 0x80): | |||||
# this could be a big-endian integer that we are getting here | |||||
# if final<0 then store the first byte to tokenbuf and discard the rest | |||||
if final < 0: | |||||
self.spi.readinto(self.tokenbuf, 0xFF) | |||||
final = -1 - final | |||||
for j in range(final): | |||||
self.spi.write(b"\xff") | |||||
if release: | |||||
self.cs(1) | |||||
self.spi.write(b"\xff") | |||||
return response | |||||
# timeout | |||||
self.cs(1) | |||||
self.spi.write(b"\xff") | |||||
return -1 | |||||
def readinto(self, buf): | |||||
self.cs(0) | |||||
# read until start byte (0xff) | |||||
for i in range(_CMD_TIMEOUT): | |||||
self.spi.readinto(self.tokenbuf, 0xFF) | |||||
if self.tokenbuf[0] == _TOKEN_DATA: | |||||
break | |||||
time.sleep_ms(1) | |||||
else: | |||||
self.cs(1) | |||||
raise OSError("timeout waiting for response") | |||||
# read data | |||||
mv = self.dummybuf_memoryview | |||||
if len(buf) != len(mv): | |||||
mv = mv[: len(buf)] | |||||
self.spi.write_readinto(mv, buf) | |||||
# read checksum | |||||
self.spi.write(b"\xff") | |||||
self.spi.write(b"\xff") | |||||
self.cs(1) | |||||
self.spi.write(b"\xff") | |||||
def write(self, token, buf): | |||||
self.cs(0) | |||||
# send: start of block, data, checksum | |||||
self.spi.read(1, token) | |||||
self.spi.write(buf) | |||||
self.spi.write(b"\xff") | |||||
self.spi.write(b"\xff") | |||||
# check the response | |||||
if (self.spi.read(1, 0xFF)[0] & 0x1F) != 0x05: | |||||
self.cs(1) | |||||
self.spi.write(b"\xff") | |||||
return | |||||
# wait for write to finish | |||||
while self.spi.read(1, 0xFF)[0] == 0: | |||||
pass | |||||
self.cs(1) | |||||
self.spi.write(b"\xff") | |||||
def write_token(self, token): | |||||
self.cs(0) | |||||
self.spi.read(1, token) | |||||
self.spi.write(b"\xff") | |||||
# wait for write to finish | |||||
while self.spi.read(1, 0xFF)[0] == 0x00: | |||||
pass | |||||
self.cs(1) | |||||
self.spi.write(b"\xff") | |||||
def readblocks(self, block_num, buf): | |||||
# workaround for shared bus, required for (at least) some Kingston | |||||
# devices, ensure MOSI is high before starting transaction | |||||
self.spi.write(b"\xff") | |||||
nblocks = len(buf) // 512 | |||||
assert nblocks and not len(buf) % 512, "Buffer length is invalid" | |||||
if nblocks == 1: | |||||
# CMD17: set read address for single block | |||||
if self.cmd(17, block_num * self.cdv, 0, release=False) != 0: | |||||
# release the card | |||||
self.cs(1) | |||||
raise OSError(5) # EIO | |||||
# receive the data and release card | |||||
self.readinto(buf) | |||||
else: | |||||
# CMD18: set read address for multiple blocks | |||||
if self.cmd(18, block_num * self.cdv, 0, release=False) != 0: | |||||
# release the card | |||||
self.cs(1) | |||||
raise OSError(5) # EIO | |||||
offset = 0 | |||||
mv = memoryview(buf) | |||||
while nblocks: | |||||
# receive the data and release card | |||||
self.readinto(mv[offset : offset + 512]) | |||||
offset += 512 | |||||
nblocks -= 1 | |||||
if self.cmd(12, 0, 0xFF, skip1=True): | |||||
raise OSError(5) # EIO | |||||
def writeblocks(self, block_num, buf): | |||||
# workaround for shared bus, required for (at least) some Kingston | |||||
# devices, ensure MOSI is high before starting transaction | |||||
self.spi.write(b"\xff") | |||||
nblocks, err = divmod(len(buf), 512) | |||||
assert nblocks and not err, "Buffer length is invalid" | |||||
if nblocks == 1: | |||||
# CMD24: set write address for single block | |||||
if self.cmd(24, block_num * self.cdv, 0) != 0: | |||||
raise OSError(5) # EIO | |||||
# send the data | |||||
self.write(_TOKEN_DATA, buf) | |||||
else: | |||||
# CMD25: set write address for first block | |||||
if self.cmd(25, block_num * self.cdv, 0) != 0: | |||||
raise OSError(5) # EIO | |||||
# send the data | |||||
offset = 0 | |||||
mv = memoryview(buf) | |||||
while nblocks: | |||||
self.write(_TOKEN_CMD25, mv[offset : offset + 512]) | |||||
offset += 512 | |||||
nblocks -= 1 | |||||
self.write_token(_TOKEN_STOP_TRAN) | |||||
def ioctl(self, op, arg): | |||||
if op == 4: # get number of blocks | |||||
return self.sectors | |||||
if op == 5: # get block size in bytes | |||||
return 512 |
@@ -0,0 +1,47 @@ | |||||
import machine | |||||
import sdcard | |||||
import uos | |||||
import random | |||||
class Storage: | |||||
def __init__(self): | |||||
self.cs = machine.Pin(17, machine.Pin.OUT) | |||||
self.spi = machine.SPI(0, | |||||
baudrate=1000000, | |||||
polarity=0, | |||||
phase=0, | |||||
bits=8, | |||||
firstbit=machine.SPI.MSB, | |||||
sck=machine.Pin(18), | |||||
mosi=machine.Pin(19), | |||||
miso=machine.Pin(16)) | |||||
self.sd = None | |||||
self.vfs = None | |||||
self.sd_path = "/sd" | |||||
def mount(self): | |||||
self.sd = sdcard.SDCard(self.spi, self.cs) | |||||
self.vfs = uos.VfsFat(self.sd) | |||||
uos.mount(self.vfs, self.sd_path) | |||||
def umount(self): | |||||
uos.umount(self.sd_path) | |||||
def get_root_path(self): | |||||
return self.sd_path | |||||
def load_joke(root): | |||||
filename = root + "/jokes.json" | |||||
num_lines = sum(1 for line in open(filename)) | |||||
with open(filename, mode="r") as f: | |||||
joke = None | |||||
start_pattern = "\"joke\": \"" | |||||
end_pattern = "\"" | |||||
for i in range(random.randrange(num_lines)): | |||||
line = f.readline() | |||||
for i in range(10): | |||||
line = f.readline() | |||||
joke_start = line.find(start_pattern) | |||||
joke_end = line.rfind(end_pattern) | |||||
if joke_start >= 0 and joke_end >= 0: | |||||
joke = line[joke_start+len(start_pattern):joke_end] | |||||
return joke | |||||
return None |
@@ -3,6 +3,7 @@ import microbmp | |||||
import time | import time | ||||
import random | import random | ||||
import os | import os | ||||
import storage | |||||
import gc | import gc | ||||
gc.enable() | gc.enable() | ||||
@@ -18,7 +19,6 @@ epd_colormap = [ | |||||
[0xff, 0x77, 0x00], # orange | [0xff, 0x77, 0x00], # orange | ||||
] | ] | ||||
images = list(filter(lambda x : x.endswith(".bmp"), os.listdir())) | |||||
max_free_height = 200 | max_free_height = 200 | ||||
def init_display(): | def init_display(): | ||||
@@ -107,6 +107,25 @@ def draw_pattern(): | |||||
epd.fill_rect(0, 0, epd_resolution[0], free_y, random.randrange(2,7)) | epd.fill_rect(0, 0, epd_resolution[0], free_y, random.randrange(2,7)) | ||||
return [free_x, free_y, free_width, free_height] | return [free_x, free_y, free_width, free_height] | ||||
def load_joke(root): | |||||
filename = root + "/jokes.json" | |||||
num_lines = sum(1 for line in open(filename)) | |||||
with open(filename, mode="r") as f: | |||||
joke = None | |||||
start_pattern = "\"joke\": \"" | |||||
end_pattern = "\"" | |||||
for i in range(random.randrange(num_lines)): | |||||
line = f.readline() | |||||
for i in range(10): | |||||
line = f.readline() | |||||
joke_start = line.find(start_pattern) | |||||
joke_end = line.rfind(end_pattern) | |||||
if joke_start >= 0 and joke_end >= 0: | |||||
joke = line[joke_start+len(start_pattern):joke_end] | |||||
return joke | |||||
return None | |||||
def print_text(text, region, center=False): | def print_text(text, region, center=False): | ||||
global epd | global epd | ||||
fnt = 8 | fnt = 8 | ||||
@@ -118,40 +137,61 @@ def print_text(text, region, center=False): | |||||
x = (w - len(text)*fnt) // 2 | x = (w - len(text)*fnt) // 2 | ||||
epd.text(text, x, y, epd.Black) | epd.text(text, x, y, epd.Black) | ||||
def draw_extra(region): | |||||
def draw_extra(region, caption): | |||||
fnt = 8 | fnt = 8 | ||||
region[0] += 5 | region[0] += 5 | ||||
region[1] += 5 | |||||
region[1] += 8 | |||||
if region[2] < fnt or region[3] < fnt: | if region[2] < fnt or region[3] < fnt: | ||||
print("Not enough space for extra: ", str(region)) | print("Not enough space for extra: ", str(region)) | ||||
return | return | ||||
#epd.rect(region[0], region[1], region[2], region[3], epd.Black) | #epd.rect(region[0], region[1], region[2], region[3], epd.Black) | ||||
#region[0] += random.randrange(50) | #region[0] += random.randrange(50) | ||||
print_text(str(time.localtime()), region, center=True) | |||||
region[1] += fnt * 3 | |||||
print_text(" Today: Rainy, 24 C", region) | |||||
region[1] += fnt * 2 | |||||
print_text("Tomorrow: Sunshine, 26 C", region) | |||||
#print_text(str(time.localtime()), region, center=True) | |||||
if caption is not None: | |||||
#region[1] += fnt * 2 | |||||
print_text(caption, region) | |||||
print("Caption: ", caption) | |||||
else: | |||||
print("No caption") | |||||
# MAIN | # MAIN | ||||
epd = init_display() | epd = init_display() | ||||
while True: | |||||
disk = storage.Storage() | |||||
while True: | |||||
disk.mount() | |||||
images = list(filter(lambda x : x.endswith(".bmp"), os.listdir(disk.get_root_path()))) | |||||
epd.EPD_5IN65F_Init() | epd.EPD_5IN65F_Init() | ||||
epd.fill(epd.White) | epd.fill(epd.White) | ||||
filename = random.choice(images) | filename = random.choice(images) | ||||
print("TV drawing image ", filename) | print("TV drawing image ", filename) | ||||
free_space = draw_image(filename) | |||||
#free_space = draw_pattern() | |||||
draw_extra(free_space) | |||||
free_space = [0,0,0,0] | |||||
try: | |||||
free_space = draw_image(disk.get_root_path() + "/" + filename) | |||||
except Exception as e: | |||||
print("Failed drawing image from disk: ", e) | |||||
try: | |||||
free_space = draw_image("tiny.bmp") | |||||
except Exception as e: | |||||
print("Failed drawing fallback image: ", e) | |||||
free_space = draw_pattern() | |||||
caption = None | |||||
try: | |||||
caption = load_joke(disk.get_root_path()) | |||||
except Exception as e: | |||||
print("Failed loading a joke: ", e) | |||||
try: | |||||
draw_extra(free_space, caption) | |||||
except Exception as e: | |||||
print("Failed drawing extra: ", e) | |||||
time_render_start = time.ticks_ms() | time_render_start = time.ticks_ms() | ||||
epd.EPD_5IN65F_Display(epd.buffer) | epd.EPD_5IN65F_Display(epd.buffer) | ||||
time_render_stop = time.ticks_ms() | time_render_stop = time.ticks_ms() | ||||
print(" time to render: ", (time_render_stop - time_render_start) / 1000, " s") | print(" time to render: ", (time_render_stop - time_render_start) / 1000, " s") | ||||
print("TV showing ", filename) | print("TV showing ", filename) | ||||
epd.Sleep() | epd.Sleep() | ||||
disk.umount() | |||||
print("") | print("") | ||||
gc.collect() | gc.collect() | ||||