diff --git a/apps/adventure_timer/__init__.py b/apps/adventure_timer/__init__.py index b1bb6a8..7c1f8ea 100644 --- a/apps/adventure_timer/__init__.py +++ b/apps/adventure_timer/__init__.py @@ -10,7 +10,7 @@ def init(): if CONFIG_NAME not in os.listdir("."): at_config = {"time_start": "unset"} - f = open(CONFIG_NAME, 'w') + f = open(CONFIG_NAME, "w") f.write(ujson.dumps(at_config)) f.close() @@ -21,7 +21,7 @@ def init(): def is_timestamp_set(): - f = open(CONFIG_NAME, 'r') + f = open(CONFIG_NAME, "r") c = ujson.loads(f.read()) f.close() if c["time_start"] == "unset": @@ -39,29 +39,29 @@ def triangle(disp, x, y, left): def timestamp_reset(): - f = open(CONFIG_NAME, 'r') + f = open(CONFIG_NAME, "r") c = ujson.loads(f.read()) c["time_start"] = "unset" f.close() - f = open(CONFIG_NAME, 'w') + f = open(CONFIG_NAME, "w") f.write(ujson.dumps(c)) f.close() def timestamp_read(): global time_start - f = open(CONFIG_NAME, 'r') + f = open(CONFIG_NAME, "r") c = ujson.loads(f.read()) time_start = c["time_start"] f.close() def timestamp_write(): - f = open(CONFIG_NAME, 'r') + f = open(CONFIG_NAME, "r") c = ujson.loads(f.read()) c["time_start"] = utime.time() f.close() - f = open(CONFIG_NAME, 'w') + f = open(CONFIG_NAME, "w") f.write(ujson.dumps(c)) f.close() diff --git a/apps/battery/__init__.py b/apps/battery/__init__.py index 77a1b01..ea77c84 100644 --- a/apps/battery/__init__.py +++ b/apps/battery/__init__.py @@ -6,6 +6,7 @@ import sys import buttons import power +import light_sensor def update_leds(batteryLevel): lastIndex = round(batteryLevel * 11) @@ -40,6 +41,9 @@ def display_logo(): disp = display.open() mode = 0 # 0 = Voltage & Percentage | 1 = waitAfterUpdate = False +light_sensor.start() +mode = math.floor(4 * min(8, max(1, light_sensor.get_reading() / 10))) +light_sensor.stop() display_logo() @@ -51,29 +55,33 @@ def display_logo(): ) if pressed & buttons.BOTTOM_LEFT != 0: - brightness = max(0, brightness - 3) - waitAfterUpdate = True + brightness = max(0, brightness - round(1 + brightness * 0.1)) + utime.sleep_ms(20) if pressed & buttons.BOTTOM_RIGHT != 0: - brightness = min(255, brightness + 3) - waitAfterUpdate = True + brightness = min(255, brightness + round(1 + brightness * 0.1)) + utime.sleep_ms(20) if pressed & buttons.TOP_RIGHT != 0: mode = mode + 1 - if mode > 2: - mode = 0 waitAfterUpdate = True voltage = os.read_battery() - batteryPercent = (voltage - minVoltage) / (maxVoltage - minVoltage) + batteryPercent = (voltage - minVoltage) ** 1.35 / (maxVoltage - minVoltage) ** 1.35 + batteryLevel = max(0, min(1, batteryPercent)) + mode = mode % ((4 - 1) + 4 * 8) + actualMode = mode % 4 - if mode == 0: + if actualMode < 3: + disp.backlight(math.floor(mode / 4 + 1)) + + if actualMode == 0: disp.print("Battery:") disp.print("%f%%" % (batteryLevel * 100), posy = 20) disp.print("%fV" % voltage, posy = 40, posx = 14) - if mode == 1: + if actualMode == 1: chargeCurrent = power.read_chargein_current() chargeVoltage = power.read_chargein_voltage() disp.print("Charging:", posy = 0) @@ -84,11 +92,15 @@ def display_logo(): disp.print("Voltage:", posy = 40) disp.print("%fV" % chargeVoltage, posy = 60) - if mode == 2: + if actualMode == 2: batteryCurrent = power.read_battery_current() disp.print("Drawing:", posy = 0) disp.print("%fA" % batteryCurrent, posy = 20) + if actualMode == 3: + leds.dim_top(math.floor(1 + mode / 4)) + disp.backlight(0) + update_leds(batteryLevel) update_rockets(batteryLevel) diff --git a/apps/card10_nickname/__init__.py b/apps/card10_nickname/__init__.py index 24b7f7b..16fc8ad 100644 --- a/apps/card10_nickname/__init__.py +++ b/apps/card10_nickname/__init__.py @@ -7,9 +7,9 @@ import ujson import os -FILENAME = 'nickname.txt' -FILENAME_ADV = 'nickname.json' -ANIM_TYPES = ['none', 'led', 'fade', 'gay', 'rainbow', 'rnd_led'] +FILENAME = "nickname.txt" +FILENAME_ADV = "nickname.json" +ANIM_TYPES = ["none", "led", "fade", "gay", "rainbow", "rnd_led"] def wheel(pos): @@ -40,7 +40,7 @@ def random_rgb(): """ rgb = [] for i in range(0, 3): - rand = int.from_bytes(os.urandom(1), 'little') + rand = int.from_bytes(os.urandom(1), "little") if rand > 255: rand = 255 rgb.append(rand) @@ -112,15 +112,15 @@ def get_time(): Generates a nice timestamp in format hh:mm:ss from the devices localtime :return: timestamp """ - timestamp = '' + timestamp = "" if utime.localtime()[3] < 10: - timestamp = timestamp + '0' - timestamp = timestamp + str(utime.localtime()[3]) + ':' + timestamp = timestamp + "0" + timestamp = timestamp + str(utime.localtime()[3]) + ":" if utime.localtime()[4] < 10: - timestamp = timestamp + '0' - timestamp = timestamp + str(utime.localtime()[4]) + ':' + timestamp = timestamp + "0" + timestamp = timestamp + str(utime.localtime()[4]) + ":" if utime.localtime()[5] < 10: - timestamp = timestamp + '0' + timestamp = timestamp + "0" timestamp = timestamp + str(utime.localtime()[5]) return timestamp @@ -154,7 +154,7 @@ def render_nickname(title, sub, fg, bg, fg_sub, bg_sub, main_bg, mode, bat): """ anim = mode posy = 30 - if sub != '': + if sub != "": posy = 18 r = 255 g = 0 @@ -164,7 +164,7 @@ def render_nickname(title, sub, fg, bg, fg_sub, bg_sub, main_bg, mode, bat): last_btn_poll = utime.time() - 2 while True: sleep = 0.5 - if sub == '#time': + if sub == "#time": r_sub = get_time() dark = 0 if light_sensor.get_reading() < 30: @@ -175,9 +175,7 @@ def render_nickname(title, sub, fg, bg, fg_sub, bg_sub, main_bg, mode, bat): r_bg_sub_color = bg_sub[dark] r_bg = main_bg[dark] # Button handling - pressed = buttons.read( - buttons.BOTTOM_LEFT | buttons.BOTTOM_RIGHT - ) + pressed = buttons.read(buttons.BOTTOM_LEFT | buttons.BOTTOM_RIGHT) if utime.time() - last_btn_poll >= 1: last_btn_poll = utime.time() if pressed & buttons.BOTTOM_RIGHT != 0: @@ -191,7 +189,7 @@ def render_nickname(title, sub, fg, bg, fg_sub, bg_sub, main_bg, mode, bat): anim = len(ANIM_TYPES) - 1 blink_led(0) # Animations - if ANIM_TYPES[anim] == 'fade': + if ANIM_TYPES[anim] == "fade": sleep = 0.1 leds.clear() toggle_rockets(False) @@ -207,7 +205,7 @@ def render_nickname(title, sub, fg, bg, fg_sub, bg_sub, main_bg, mode, bat): r_bg = [r, g, b] r_bg_color = r_bg r_bg_sub_color = r_bg - if ANIM_TYPES[anim] == 'led': + if ANIM_TYPES[anim] == "led": if dark == 1: for i in range(0, 11): leds.prep(i, r_bg) @@ -217,7 +215,7 @@ def render_nickname(title, sub, fg, bg, fg_sub, bg_sub, main_bg, mode, bat): else: leds.clear() toggle_rockets(False) - if ANIM_TYPES[anim] == 'rnd_led': + if ANIM_TYPES[anim] == "rnd_led": if dark == 1: for i in range(0, 11): leds.prep(i, random_rgb()) @@ -227,10 +225,10 @@ def render_nickname(title, sub, fg, bg, fg_sub, bg_sub, main_bg, mode, bat): else: leds.clear() toggle_rockets(False) - if ANIM_TYPES[anim] == 'gay': + if ANIM_TYPES[anim] == "gay": toggle_rockets(False) leds.gay(0.4) - if ANIM_TYPES[anim] == 'rainbow': + if ANIM_TYPES[anim] == "rainbow": for i in range(0, 11): lr, lg, lb = wheel(rainbow_led_pos + i * 3) leds.prep(i, [lr, lg, lb]) @@ -240,16 +238,28 @@ def render_nickname(title, sub, fg, bg, fg_sub, bg_sub, main_bg, mode, bat): leds.update() leds.dim_top(3) toggle_rockets(True) - if ANIM_TYPES[anim] == 'none': + if ANIM_TYPES[anim] == "none": leds.clear() toggle_rockets(False) with display.open() as disp: disp.rect(0, 0, 160, 80, col=r_bg, filled=True) if bat[0]: render_battery(disp, bat) - disp.print(title, fg=r_fg_color, bg=r_bg_color, posx=80 - round(len(title) / 2 * 14), posy=posy) - if r_sub != '': - disp.print(r_sub, fg=r_fg_sub_color, bg=r_bg_sub_color, posx=80 - round(len(r_sub) / 2 * 14), posy=42) + disp.print( + title, + fg=r_fg_color, + bg=r_bg_color, + posx=80 - round(len(title) / 2 * 14), + posy=posy, + ) + if r_sub != "": + disp.print( + r_sub, + fg=r_fg_sub_color, + bg=r_bg_sub_color, + posx=80 - round(len(r_sub) / 2 * 14), + posy=42, + ) disp.update() disp.close() utime.sleep(sleep) @@ -274,49 +284,65 @@ def get_key(json, key, default): disp.clear().update() disp.close() if FILENAME_ADV in os.listdir("."): - f = open(FILENAME_ADV, 'r') + f = open(FILENAME_ADV, "r") try: c = ujson.loads(f.read()) f.close() # parse config - nick = get_key(c, 'nickname', 'no nick') - sub = get_key(c, 'subtitle', '') - mode = get_key(c, 'mode', 0) + nick = get_key(c, "nickname", "no nick") + sub = get_key(c, "subtitle", "") + mode = get_key(c, "mode", 0) # battery - battery_show = get_key(c, 'battery', True) - battery_c_good = get_key(c, 'battery_color_good', [0, 230, 00]) - battery_c_ok = get_key(c, 'battery_color_ok', [255, 215, 0]) - battery_c_bad = get_key(c, 'battery_color_bad', [255, 0, 0]) + battery_show = get_key(c, "battery", True) + battery_c_good = get_key(c, "battery_color_good", [0, 230, 00]) + battery_c_ok = get_key(c, "battery_color_ok", [255, 215, 0]) + battery_c_bad = get_key(c, "battery_color_bad", [255, 0, 0]) # daytime values - background = get_key(c, 'background', [0, 0, 0]) - fg_color = get_key(c, 'fg_color', [255, 255, 255]) - bg_color = get_key(c, 'bg_color', background) - fg_sub_color = get_key(c, 'fg_sub_color', [255, 255, 255]) - bg_sub_color = get_key(c, 'bg_sub_color', background) + background = get_key(c, "background", [0, 0, 0]) + fg_color = get_key(c, "fg_color", [255, 255, 255]) + bg_color = get_key(c, "bg_color", background) + fg_sub_color = get_key(c, "fg_sub_color", [255, 255, 255]) + bg_sub_color = get_key(c, "bg_sub_color", background) # nighttime values - background_night = get_key(c, 'background_night', [0, 0, 0]) - fg_color_night = get_key(c, 'fg_color_night', [255, 255, 255]) - bg_color_night = get_key(c, 'bg_color_night', background_night) - fg_sub_color_night = get_key(c, 'fg_sub_color_night', [255, 255, 255]) - bg_sub_color_night = get_key(c, 'bg_sub_color_night', background_night) + background_night = get_key(c, "background_night", [0, 0, 0]) + fg_color_night = get_key(c, "fg_color_night", [255, 255, 255]) + bg_color_night = get_key(c, "bg_color_night", background_night) + fg_sub_color_night = get_key(c, "fg_sub_color_night", [255, 255, 255]) + bg_sub_color_night = get_key(c, "bg_sub_color_night", background_night) # render nickname - render_nickname(nick, sub, (fg_color, fg_color_night), (bg_color, bg_color_night), - (fg_sub_color, fg_sub_color_night), (bg_sub_color, bg_sub_color_night), - (background, background_night), mode, - (battery_show, battery_c_good, battery_c_ok, battery_c_bad)) + render_nickname( + nick, + sub, + (fg_color, fg_color_night), + (bg_color, bg_color_night), + (fg_sub_color, fg_sub_color_night), + (bg_sub_color, bg_sub_color_night), + (background, background_night), + mode, + (battery_show, battery_c_good, battery_c_ok, battery_c_bad), + ) except ValueError: - render_error('invalid', 'json') + render_error("invalid", "json") else: if FILENAME not in os.listdir("."): - render_error('file not', 'found') + render_error("file not", "found") else: - f = open(FILENAME, 'r') + f = open(FILENAME, "r") nick = f.read() f.close() if len(nick) > 11: - render_error('name too', 'long') + render_error("name too", "long") if len(nick) < 1: - render_error('nick file', 'empty') + render_error("nick file", "empty") else: - render_nickname(nick, '', ([255, 255, 255], [255, 255, 255]), ([0, 0, 0], [0, 0, 0]), - ([255, 255, 255], [255, 255, 255]), ([0, 0, 0], [0, 0, 0]), ([0, 0, 0], [0, 0, 0])) + render_nickname( + nick, + "", + ([255, 255, 255], [255, 255, 255]), + ([0, 0, 0], [0, 0, 0]), + ([255, 255, 255], [255, 255, 255]), + ([0, 0, 0], [0, 0, 0]), + ([0, 0, 0], [0, 0, 0]), + 0, + (0, [255, 0, 255], [255, 0, 255], [255, 0, 255]), + ) diff --git a/apps/ecg/__init__.py b/apps/ecg/__init__.py new file mode 100644 index 0000000..0ea3884 --- /dev/null +++ b/apps/ecg/__init__.py @@ -0,0 +1,242 @@ +import os +import display +import utime +import buttons +import max30001 +import math +import struct + +WIDTH = 160 +HEIGHT = 80 +OFFSET = 50 +ECG_RATE = 128 +HISTORY_MAX = ECG_RATE * 2 +DRAW_AFTER_SAMPLES = 5 +SCALE_FACTOR = 30 +MODE_USB = "USB" +MODE_FINGER = "Finger" +FILEBUFFERBLOCK = 4096 +COLOR_BACKGROUND = [0, 0, 0] +COLOR_LINE = [255, 255, 255] +COLOR_TEXT = [255, 255, 255] +COLOR_MODE_FINGER = [0, 255, 0] +COLOR_MODE_USB = [0, 0, 255] +COLOR_WRITE_FG = [255, 255, 255] +COLOR_WRITE_BG = [255, 0, 0] + +current_mode = MODE_FINGER +history = [] +filebuffer = bytearray() +write = 0 +bias = True +update_screen = 0 +pause_screen = 0 +sensor = 0 +disp = display.open() + + +def callback_ecg(datasets): + global update_screen, history, filebuffer, write + if len(datasets) > 0: + for value in datasets: + history.append(value) + update_screen += len(datasets) + if len(history) > HISTORY_MAX: + r = len(history) - HISTORY_MAX + for i in range(r): + history.pop(0) + + # buffer for writes + if write > 0: + if len(datasets) > 0: + for value in datasets: + filebuffer.extend(struct.pack("h", value)) + if len(filebuffer) >= FILEBUFFERBLOCK: + write_filebuffer() + + # don't update on every callback + if update_screen >= DRAW_AFTER_SAMPLES: + # print("history: %i, filebuffer: %i" % (len(history), len(filebuffer))) + draw_histogram() + update_screen = 0 + + +def write_filebuffer(): + global write, filebuffer + # write to file + chars = "" + lt = utime.localtime(write) + filename = "/ecg-%04d-%02d-%02d_%02d%02d%02d.log" % ( + lt[0], + lt[1], + lt[2], + lt[3], + lt[4], + lt[5], + ) + + # write stuff to disk + # print("Write %i bytes to %s" % (len(filebuffer), filename)) + try: + f = open(filename, "ab") + f.write(filebuffer) + f.close() + except OSError as e: + print("Please check the file or filesystem", e) + write = 0 + pause_screen = -1 + disp.clear(COLOR_BACKGROUND) + disp.print("IO Error", posy=0, fg=COLOR_TEXT) + disp.print("Please check", posy=20, fg=COLOR_TEXT) + disp.print("your", posy=40, fg=COLOR_TEXT) + disp.print("filesystem", posy=60, fg=COLOR_TEXT) + disp.update() + close_sensor() + except: + print("Unexpected error, stop writeing logfile") + write = 0 + + filebuffer = bytearray() + return + + +def open_sensor(): + global sensor + sensor = max30001.MAX30001( + usb=(False if current_mode == MODE_FINGER else True), + bias=bias, + sample_rate=ECG_RATE, + callback=callback_ecg, + ) + + +def close_sensor(): + global sensor + sensor.close() + + +def toggle_mode(): + global current_mode + close_sensor() + current_mode = MODE_USB if current_mode == MODE_FINGER else MODE_FINGER + open_sensor() + + +def toggle_bias(): + global bias + close_sensor() + bias = False if bias == True else True + open_sensor() + return + + +def toggle_write(): + global write, disp, pause_screen + pause_screen = utime.time_ms() + 1000 + disp.clear(COLOR_BACKGROUND) + if write > 0: + write_filebuffer() + write = 0 + disp.print("Stop", posx=50, posy=20, fg=COLOR_TEXT) + disp.print("logging", posx=30, posy=40, fg=COLOR_TEXT) + else: + filebuffer = bytearray() + write = utime.time() + disp.print("Start", posx=45, posy=20, fg=COLOR_TEXT) + disp.print("logging", posx=30, posy=40, fg=COLOR_TEXT) + + disp.update() + return + + +def draw_histogram(): + global disp, history, current_mode, bias, write, pause_screen + + # skip rendering due to message beeing shown + if pause_screen == -1: + return + elif pause_screen > 0: + t = utime.time_ms() + if t > pause_screen: + pause_screen = 0 + else: + return + + disp.clear(COLOR_BACKGROUND) + + # get max value and calc scale + value_max = 0 + for value in history: + if abs(value) > value_max: + value_max = abs(value) + scale = SCALE_FACTOR / (value_max if value_max > 0 else 1) + + # draw histogram + old = False + x = 0 + samples = len(history) + for i, value in enumerate(history): + if old == False: + old = (x, int(value * scale) + OFFSET) + x += 1 + continue + elif i > samples - WIDTH: + disp.line(old[0], old[1], x, int(value * scale) + OFFSET, col=COLOR_LINE) + old = (x, int(value * scale) + OFFSET) + x += 1 + + # draw text: mode/bias/write + disp.print( + current_mode + ("+Bias" if bias else ""), + posx=0, + posy=0, + fg=(COLOR_MODE_FINGER if current_mode == MODE_FINGER else COLOR_MODE_USB), + ) + + # announce writing ecg log + if write > 0: + t = utime.time() + if write > 0 and t % 2 == 0: + disp.print("LOG", posx=0, posy=60, fg=COLOR_WRITE_FG, bg=COLOR_WRITE_BG) + + disp.update() + + +def main(): + # show button layout + disp.clear(COLOR_BACKGROUND) + disp.print(" BUTTONS ", posx=0, posy=0, fg=COLOR_TEXT) + disp.print("Finger/USB>", posx=0, posy=20, fg=COLOR_MODE_FINGER) + disp.print(" Bias >", posx=0, posy=40, fg=COLOR_MODE_USB) + disp.print("< Write Log", posx=0, posy=60, fg=COLOR_WRITE_BG) + disp.update() + utime.sleep(3) + + # start ecg + open_sensor() + while True: + button_pressed = False + while True: + v = buttons.read( + buttons.BOTTOM_LEFT | buttons.BOTTOM_RIGHT | buttons.TOP_RIGHT + ) + if v == 0: + button_pressed = False + + if not button_pressed and v & buttons.BOTTOM_LEFT != 0: + button_pressed = True + toggle_write() + + elif not button_pressed and v & buttons.BOTTOM_RIGHT != 0: + button_pressed = True + toggle_bias() + + elif not button_pressed and v & buttons.TOP_RIGHT != 0: + button_pressed = True + toggle_mode() + + pass + + +if __name__ == "__main__": + main() diff --git a/apps/ecg/metadata.json b/apps/ecg/metadata.json new file mode 100644 index 0000000..8c553a3 --- /dev/null +++ b/apps/ecg/metadata.json @@ -0,0 +1 @@ +{"name":"ECG","description":"A simple ecg monitor which displays the heart rate and allows you to switch between usb and finger reader.","category":"hardware","author":"griffon","revision":1} diff --git a/apps/lsd_nickname/__init__.py b/apps/lsd_nickname/__init__.py index 9a269a5..8ac8be0 100644 --- a/apps/lsd_nickname/__init__.py +++ b/apps/lsd_nickname/__init__.py @@ -3,17 +3,20 @@ import utime _rand = 123456789 + + def rand(): global _rand - _rand = (1103515245 * _rand + 12345) & 0xffffff + _rand = (1103515245 * _rand + 12345) & 0xFFFFFF return _rand + gs = 160 -colors = [ ((i>>2)*gs, (i>>1&1)*gs, (i&1)*gs) for i in range(1, 8) ] +colors = [((i >> 2) * gs, (i >> 1 & 1) * gs, (i & 1) * gs) for i in range(1, 8)] -nick = 'sample text' +nick = "sample text" try: - with open('/nickname.txt') as f: + with open("/nickname.txt") as f: nick = f.read() except: pass @@ -21,17 +24,23 @@ def rand(): while True: with display.open() as d: for k in range(4): - (x1, y1) = (rand()%159, rand()%79) - (x2, y2) = (min(x1+rand()%40, 159), min(y1+rand()%40, 79)) + (x1, y1) = (rand() % 159, rand() % 79) + (x2, y2) = (min(x1 + rand() % 40, 159), min(y1 + rand() % 40, 79)) try: d.rect(x1, y1, x2, y2, col=colors[rand() % len(colors)], filled=True) except: pass - fg = colors[rand()%len(colors)] - nx = 80-round(len(nick)/2 * 14) - d.print(nick, fg=fg, bg=[0xff-c for c in fg], posx=(nx-8)+rand()%16, posy=22+rand()%16) + fg = colors[rand() % len(colors)] + nx = 80 - round(len(nick) / 2 * 14) + d.print( + nick, + fg=fg, + bg=[0xFF - c for c in fg], + posx=(nx - 8) + rand() % 16, + posy=22 + rand() % 16, + ) d.update() d.close() leds.set(rand() % 11, colors[rand() % len(colors)]) leds.set_rocket(rand() % 3, rand() % 32) - utime.sleep_us(1) # Feed watch doge \ No newline at end of file + utime.sleep_us(1) # Feed watch doge diff --git a/apps/scope/__init__.py b/apps/scope/__init__.py index 30b354e..b4e861a 100644 --- a/apps/scope/__init__.py +++ b/apps/scope/__init__.py @@ -5,8 +5,8 @@ import light_sensor import math -WIDTH=160 -HEIGHT=80 +WIDTH = 160 +HEIGHT = 80 disp = display.open() @@ -16,20 +16,20 @@ while True: disp.clear() - + value = light_sensor.get_reading() - + history.insert(0, value) if len(history) > WIDTH: history.pop() - disp.print("%i"%value) - - for i in range(0,len(history)): + disp.print("%i" % value) + + for i in range(0, len(history)): # Rescale to range 0 <= value < HEIGHT-1 - y = math.floor(history[i]*(HEIGHT-2)/max(history)) - - disp.pixel(WIDTH-i, HEIGHT-y-1) - + y = math.floor(history[i] * (HEIGHT - 2) / max(history)) + + disp.pixel(WIDTH - i, HEIGHT - y - 1) + disp.update() - utime.sleep(0.1) \ No newline at end of file + utime.sleep(0.1) diff --git a/apps/text_reader/__init__.py b/apps/text_reader/__init__.py index 906df27..35a4b08 100644 --- a/apps/text_reader/__init__.py +++ b/apps/text_reader/__init__.py @@ -16,6 +16,7 @@ SPECIAL_EMPTY = "# empty file" BUTTON_TIMER_POPPED = -1 + def list_files(): """Create a list of available text files.""" files = sorted(os.listdir("/")) @@ -30,9 +31,9 @@ def triangle(disp, x, y, left): """Draw a triangle to show there's more text in this line""" yf = 1 if left else -1 scale = 6 - disp.line(x - scale * yf, int(y + scale / 2), x, y, col=[255,0,0]) - disp.line(x, y, x, y + scale, col=[255,0,0]) - disp.line(x, y + scale, x - scale * yf, y + int(scale / 2), col=[255,0,0]) + disp.line(x - scale * yf, int(y + scale / 2), x, y, col=[255, 0, 0]) + disp.line(x, y, x, y + scale, col=[255, 0, 0]) + disp.line(x, y + scale, x - scale * yf, y + int(scale / 2), col=[255, 0, 0]) def button_events(timeout=0): @@ -68,6 +69,7 @@ def button_events(timeout=0): COLOR1, COLOR2 = (color.CHAOSBLUE_DARK, color.CHAOSBLUE) + def file_len(filename): i = -1 with open(filename) as fh: @@ -76,23 +78,19 @@ def file_len(filename): return i + 1 -def draw_filecontent(disp, filename, pos, linecount, lineoffset = 0): +def draw_filecontent(disp, filename, pos, linecount, lineoffset=0): disp.clear() with open(filename) as fh: # stop if file is empty if linecount <= 0: - disp.print( - SPECIAL_EMPTY, - posy=20, - bg=color.BLACK - ) + disp.print(SPECIAL_EMPTY, posy=20, bg=color.BLACK) return # calc start position start = 0 if pos > 0: - start = pos-1 + start = pos - 1 if start + 4 > linecount: start = linecount - 4 if start < 0: @@ -104,21 +102,26 @@ def draw_filecontent(disp, filename, pos, linecount, lineoffset = 0): break if i >= start: disp.rect( - 0, (i - start) * 20, 159, (i - start) * 20 + 20, - col=COLOR1 if i == pos else COLOR2 + 0, + (i - start) * 20, + 159, + (i - start) * 20 + 20, + col=COLOR1 if i == pos else COLOR2, ) off = 0 linelength = len(line) if i == pos and linelength > 11 and lineoffset > 0: - off = lineoffset if lineoffset + 11 < linelength else linelength - 11 + off = ( + lineoffset if lineoffset + 11 < linelength else linelength - 11 + ) if lineoffset > linelength: off = 0 disp.print( - line[off:(off+11)], + line[off : (off + 11)], posy=(i - start) * 20, - bg=COLOR1 if i == pos else COLOR2 + bg=COLOR1 if i == pos else COLOR2, ) if linelength > 11 and off < linelength - 11: triangle(disp, 153, (i - start) * 20 + 6, False) @@ -133,7 +136,7 @@ def draw_filelist(disp, filelist, pos, filecount, lineoffset): start = 0 if pos > 0: - start = pos-1 + start = pos - 1 if start + 4 > filecount: start = filecount - 4 if start < 0: @@ -144,8 +147,11 @@ def draw_filelist(disp, filelist, pos, filecount, lineoffset): break if i >= start: disp.rect( - 0, (i - start) * 20, 159, (i - start) * 20 + 20, - col=COLOR1 if i == pos else COLOR2 + 0, + (i - start) * 20, + 159, + (i - start) * 20 + 20, + col=COLOR1 if i == pos else COLOR2, ) off = 0 @@ -156,9 +162,9 @@ def draw_filelist(disp, filelist, pos, filecount, lineoffset): off = 0 disp.print( - " " + line[off:(off+10)], + " " + line[off : (off + 10)], posy=(i - start) * 20, - bg=COLOR1 if i == pos else COLOR2 + bg=COLOR1 if i == pos else COLOR2, ) if i == pos: disp.print(">", posy=(i - start) * 20, fg=color.COMMYELLOW, bg=COLOR1) @@ -214,11 +220,14 @@ def main(): elif ev == BUTTON_TIMER_POPPED: timercountpopped += 1 - if timercountpopped >= timerstartscroll and (timercountpopped - timerstartscroll) % timerscrollspeed == 0: + if ( + timercountpopped >= timerstartscroll + and (timercountpopped - timerstartscroll) % timerscrollspeed == 0 + ): lineoffset += 1 elif ev == buttons.TOP_RIGHT: - filename = filelist [ current_file % numfiles ] + filename = filelist[current_file % numfiles] # exit or ignore if filename == SPECIAL_EXIT: @@ -267,7 +276,10 @@ def main(): elif ev == BUTTON_TIMER_POPPED: timercountpopped += 1 - if timercountpopped >= timerstartscroll and (timercountpopped - timerstartscroll) % timerscrollspeed == 0: + if ( + timercountpopped >= timerstartscroll + and (timercountpopped - timerstartscroll) % timerscrollspeed == 0 + ): lineoffset += 1 elif ev == buttons.TOP_RIGHT: @@ -282,4 +294,4 @@ def main(): if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/card10.bin b/card10.bin index 0b9dfa6..66e631f 100644 Binary files a/card10.bin and b/card10.bin differ diff --git a/main.py b/main.py index db71681..d7f93b7 100644 --- a/main.py +++ b/main.py @@ -12,7 +12,6 @@ CONFIG_NAME = "clock.json" - def update_charging_indicator(): chargeVoltage = power.read_chargein_voltage() if chargeVoltage < 1: @@ -26,7 +25,6 @@ def update_charging_indicator(): utime.sleep_ms(250) - class Time: def __init__(self, start=0): self.time = start @@ -201,7 +199,7 @@ def loop(self): while True: self.updateClock(disp) update_charging_indicator() - + if self.run_once: break diff --git a/menu.py b/menu.py index 890b888..e0a84a8 100644 --- a/menu.py +++ b/menu.py @@ -31,7 +31,8 @@ def read_metadata(app_folder): with open(info_file) as f: information = f.read() return ujson.loads(information) - except BaseException as e: + except Exception as e: + print("Failed to read metadata for %s" % (app_folder)) sys.print_exception(e) return { "author": "", @@ -267,4 +268,14 @@ def main(): if __name__ == "__main__": - main() + try: + main() + except Exception as e: + sys.print_exception(e) + with display.open() as d: + d.clear(color.COMMYELLOW) + d.print("Menu", posx=52, posy=20, fg=color.COMMYELLOW_DARK, bg=color.COMMYELLOW) + d.print("crashed", posx=31, posy=40, fg=color.COMMYELLOW_DARK, bg=color.COMMYELLOW) + d.update() + utime.sleep(2) + os.exit(1)