Launcher and minimal home screen

philcrump-phil-add-ntp
Marek Ventur 2018-08-05 22:14:31 +01:00
parent 1c9e95db23
commit 7936cbf3a7
14 changed files with 165 additions and 51 deletions

View File

@ -309,7 +309,7 @@ class Pyboard:
print(data)
raise PyboardError('could not enter raw repl')
def exit_raw_repl(self):
def exit_raw_repl(self):\
self.serial.write(b'\r\x02') # ctrl-B: enter friendly REPL
def follow(self, timeout, data_consumer=None):

View File

@ -49,9 +49,7 @@ def soft_reset(args, verbose = True):
if verbose:
print("Soft reboot:", end="")
write_command(pyb, b'\x04') # ctrl-D: soft reset
#print("1")
data = pyb.read_until(1, b'soft reboot\r\n')
#print("2")
if data.endswith(b'soft reboot\r\n'):
if verbose:
print(" DONE")
@ -109,12 +107,18 @@ def run(args, paths, verbose=True):
pyboard.stdout_write_bytes(ret_err)
sys.exit(1)
# run any files
for filename in paths:
with open(filename, 'rb') as f:
print("-------- %s --------" % filename)
pyfile = f.read()
execbuffer(pyfile)
try:
# run any files
for filename in paths:
with open(filename, 'rb') as f:
print("-------- %s --------" % filename)
pyfile = f.read()
execbuffer(pyfile)
# exiting raw-REPL just drops to friendly-REPL mode
pyb.exit_raw_repl()
# exiting raw-REPL just drops to friendly-REPL mode
pyb.exit_raw_repl()
except OSError as e:
if "Device not configured" in str(e):
print("Connection to badge lost") # This can happen on a hard rest
else:
raise e

View File

@ -70,6 +70,16 @@ def set_boot_app(storage, app_to_boot):
if app_to_boot:
print("setting next boot to %s" % app_to_boot)
def set_no_boot(storage):
path = os.path.join(storage, 'no_boot')
try:
os.remove(path)
except OSError:
pass
with open(path, 'w') as f:
f.write("\n")
def get_root():
root = os.path.abspath(os.path.join(os.path.dirname( __file__ ), '..'))
if not os.path.isfile(os.path.join(root, "boot.py")):

View File

@ -19,10 +19,13 @@ $ tilda_tools sync my_game shared
$ tilda_tools sync <pattern1> <pattern2> ...
Sync (as above), but execute my_app after reboot
$ tilda_toold.py sync --boot my_app [<other sync parameter>]
$ tilda_tools sync --boot my_app [<other sync parameter>]
Sync (as above), but execute a single file afterwards without copying it to the badge
$ tilda_toold.py sync --run some_other_file.py
$ tilda_tools sync --run some_other_file.py
Sync a given app and execute it
$ tilda_tools app home_default
Executes a single file on the badge without copying anything (Using pyboard.py)
$ tilda_tools run my_app/main.py
@ -54,7 +57,7 @@ from resources import *
def main():
import argparse
cmd_parser = argparse.ArgumentParser(description='Toolchain for working with the TiLDA Mk4')
cmd_parser.add_argument('command', nargs=1, help='command [test|reset|sync|run|validate|wifi|firmware-update]', choices=['test', 'reset', 'sync', 'validate', 'run', 'wifi', 'firmware-update'])
cmd_parser.add_argument('command', nargs=1, help='command [test|reset|sync|run|validate|wifi|firmware-update|app]', choices=['test', 'reset', 'sync', 'validate', 'run', 'wifi', 'firmware-update', 'app'])
cmd_parser.add_argument('-d', '--device', help='the serial device of the badge')
cmd_parser.add_argument('-s', '--storage', help='the usb mass storage path of the badge')
cmd_parser.add_argument('-b', '--baudrate', default=115200, help='the baud rate of the serial device')
@ -76,6 +79,11 @@ def main():
if command == "wifi":
wifi.select_wifi()
if command == "app":
command = "sync"
args.run = "%s/main.py" % args.paths[0]
#args.boot = args.paths[0]
if command in ["test", "validate", "sync"]:
resources = get_resources(path)
add_metadata(path, resources)
@ -107,10 +115,12 @@ def main():
if command in ["reset", "sync"]:
sync.set_boot_app(get_storage(args), args.boot or "")
pyboard_util.soft_reset(args)
if args.run:
command = "run"
args.paths = [args.run]
sync.set_no_boot(get_storage(args))
pyboard_util.soft_reset(args)
if command == "run":
pyboard_util.check_run(args.paths)
@ -119,6 +129,7 @@ def main():
if run_tests:
for resource in synced_resources:
pyboard_util.check_run([resource])
sync.set_no_boot(get_storage(args))
pyboard_util.run(args, [resource], False)
pyboard_util.soft_reset(args, False)

View File

@ -87,7 +87,7 @@ def main_menu():
if option:
option["function"]()
else:
return
app.restart_to_default()
main_menu()
#show_app("launcher")

13
boot.py
View File

@ -26,9 +26,12 @@ def file(file, remove):
def any_home():
return app(next(a for a in root if a.startswith("home")))
start = None
if "main.py" in root:
start = "main.py"
start = file("once.txt", True) or file("default_app.txt", False) or any_home() or "bootstrap.py"
if "no_boot" in root:
os.remove("no_boot")
else:
start = None
if "main.py" in root:
start = "main.py"
start = file("once.txt", True) or file("default_app.txt", False) or any_home() or "bootstrap.py"
pyb.main(start)
pyb.main(start)

View File

@ -8,13 +8,39 @@ newly activated or reset.
___name___ = "Homescreen (Default)"
___license___ = "GPL"
___categories___ = ["homescreen"]
___dependencies___ = ["homescreen"]
___launchable___ = False
___bootstrapped___ = True
print("there")
import ugfx, homescreen
import ugfx
from homescreen import *
import time
init()
# title
ugfx.set_default_font(ugfx.FONT_MEDIUM_BOLD)
ugfx.Label(0, 20, ugfx.width(), 40, "TiLDA Mk4", justification=ugfx.Label.CENTERTOP)
# name
if name():
ugfx.set_default_font(ugfx.FONT_NAME)
ugfx.Label(0, 60, ugfx.width(), 40, name(), justification=ugfx.Label.CENTERTOP)
else:
ugfx.set_default_font(ugfx.FONT_MEDIUM)
ugfx.Label(0, 60, ugfx.width(), 40, "Set your name in the settings app", justification=ugfx.Label.CENTERTOP)
# info
ugfx.Label(0, 200, ugfx.width(), 40, "Press MENU", justification=ugfx.Label.CENTERTOP)
ugfx.set_default_font(ugfx.FONT_MEDIUM)
status = ugfx.Label(0, 130, ugfx.width(), 40, "", justification=ugfx.Label.CENTERTOP)
# update loop
def tick():
status.text("wifi: %s%%\nbattery: %s%%" % (int(wifi_strength() * 100), int(battery() * 100)))
time.sleep_ms(500)
loop(tick)
homescreen.init(color = 0xe4ffdb)
ugfx.display_image(0, 0, "home_default/bg.gif")
ugfx.text(20, 20, homescreen.name(), ugfx.BLACK)

View File

@ -3,23 +3,21 @@
___name___ = "Launcher"
___license___ = "MIT"
___categories___ = ["System"]
___dependencies___ = ["dialogs", "app"]
___launchable___ = False
___bootstrapped___ = True
import ugfx
from app import *
from dialogs import *
ugfx.init()
ugfx.clear()
apps = range(1, 10)
cols = 4
options = [{"title": a.title, "app": a} for a in get_apps()]
option = prompt_option(options, none_text="Homescreen", text="Select App to start")
for i, p in enumerate(apps):
logical_x = i % cols
logical_y = i // cols
x = logical_x * width
print("launcher")
if not option:
restart_to_default()
else:
option["app"].boot()

View File

@ -7,6 +7,7 @@ ___license___ = "MIT"
___dependencies___ = ["metadata_reader", "ospath"]
from ospath import *
import os, machine
from metadata_reader import read_metadata
class App:
@ -63,6 +64,10 @@ class App:
except Exception as e:
pass
def boot(self):
write_launch_file(self.name)
machine.reset() # used to be pyb.hard_reset()
def __str__(self):
return self.title
@ -103,3 +108,13 @@ def get_categories():
_categories.update(app.categories)
return _categories
def write_launch_file(app, file = "once.txt"):
with open(file, "wt") as file:
file.write(app)
file.flush()
os.sync()
def restart_to_default():
write_launch_file("")
machine.reset() # used to be pyb.hard_reset()

View File

@ -42,7 +42,6 @@ def rotate(button):
"""remaps names of buttons to rotated values"""
return ROTATION_MAP[button]
def is_pressed(button):
pin = _get_pin(button)
if pin.pull() == pyb.Pin.PULL_DOWN:

View File

@ -16,29 +16,40 @@ They also *may*:
* Display remaining battery "homescreen.battery()" (0-1)
"""
__license___ = "MIT"
__dependencies___ = ["database", "buttons"]
___license___ = "MIT"
___dependencies___ = ["database", "buttons", "random", "app"]
import database, ugfx, buttons
import database, ugfx, random, buttons, time
from app import App
def init(color = 0xFFFFFF):
ugfx.init()
ugfx.orientation(90)
ugfx.clear(ugfx.html_color(color))
# A special loop that exits on menu being pressed
def loop(func, interval = 500):
buttons.init()
#buttons.enable_interrupt()
state = {"pressed": False} # This is a terrible hack
def irp(t):
state["pressed"] = True
buttons.enable_interrupt("BTN_MENU", irp, on_release = True)
while not state["pressed"]:
func()
time.sleep_ms(interval)
buttons.disable_interrupt("BTN_MENU")
App("launcher").boot()
def menu():
ugfx.clear()
def name():
return database.get("homescreen.name", "bar")
def mobile_strength():
return 0.75
def name(default = None):
return database.get("homescreen.name", default)
def wifi_strength():
return 0.65
return random.rand() / 256
def battery():
return 0.65
return random.rand() / 256

9
lib/random.py Normal file
View File

@ -0,0 +1,9 @@
"""Library to generate random numbers"""
___license___ = "MIT"
import os
# todo: write an actual useful function
def rand():
return int(os.urandom(1)[0])

20
lib/test_random.py Normal file
View File

@ -0,0 +1,20 @@
"""Tests for random lib"""
___license___ = "MIT"
___dependencies___ = ["upip:unittest", "random"]
import unittest
from random import *
class TestRandom(unittest.TestCase):
def test_rand(self):
for i in range(1, 100):
r = rand()
self.assertTrue(r>0)
self.assertTrue(r<256)
if __name__ == '__main__':
unittest.main()

View File

@ -5,5 +5,13 @@ ___license___ = "GPL"
___categories___ = ["System"]
___launchable___ = True
___bootstrapped___ = True
___dependencies___ = ["app", "dialogs"]
print("settings")
import app
from dialogs import *
ugfx.init()
option = prompt_option(["tbd"], none_text="Exit", title="Settings")
app.restart_to_default()