From 69c7cd39b5ccdf7f39f1010c7203803c620c8c92 Mon Sep 17 00:00:00 2001 From: Marek Ventur Date: Sun, 26 Aug 2018 20:27:23 +0100 Subject: [PATCH] Bootstrap --- .development/sync.py | 25 ++++++++++++++++++------- .development/tilda_tools.py | 25 ++++++++++++++++--------- boot.py | 11 ++++------- bootstrap.py | 30 +++++++++++++++++++++++++----- launcher/main.py | 6 +++--- lib/homescreen.py | 6 +++--- lib/http.py | 9 +++------ 7 files changed, 72 insertions(+), 40 deletions(-) diff --git a/.development/sync.py b/.development/sync.py index 043c17d..ab6d519 100644 --- a/.development/sync.py +++ b/.development/sync.py @@ -1,6 +1,6 @@ -import os, shutil, sys, fnmatch +import os, shutil, sys, fnmatch, glob -def sync(storage, patterns, resources, verbose): +def sync(storage, patterns, resources, verbose, skip_wifi): root = get_root(verbose) # Add all paths that are already files @@ -10,9 +10,10 @@ def sync(storage, patterns, resources, verbose): paths.add("boot.py") # wifi.json - wifi_path = os.path.join(root, "wifi.json") - if os.path.isfile(wifi_path): - paths.add(wifi_path) + if not skip_wifi: + wifi_path = os.path.join(root, "wifi.json") + if os.path.isfile(wifi_path): + paths.add(wifi_path) if not patterns: patterns = ["*"] @@ -28,7 +29,7 @@ def sync(storage, patterns, resources, verbose): print("Resource %s is going to be synced" % key) for path in resource['files'].keys(): paths.add(path) - if not found: + if not found and (pattern not in paths): print("WARN: No resources to copy found for pattern %s" % patterns) if not verbose: print("Copying %s files: " % len(paths), end="", flush=True) @@ -56,8 +57,18 @@ def sync(storage, patterns, resources, verbose): print(" DONE") return synced_resources +def clean(storage): + print("Cleaning:", end=" ", flush=True) + files = glob.glob(os.path.join(storage, "*")) + for f in files: + if os.path.isfile(f): + os.remove(f) + else: + shutil.rmtree(f) + print("DONE") + def ensure_dir(path, storage): - # micropython has a tendecy + # micropython has a tendecy to turn directories into files if not path or path == storage: return if os.path.isfile(path): diff --git a/.development/tilda_tools.py b/.development/tilda_tools.py index f31ce13..04a0d36 100755 --- a/.development/tilda_tools.py +++ b/.development/tilda_tools.py @@ -57,11 +57,13 @@ 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|app]', choices=['test', 'reset', 'sync', 'validate', 'run', 'wifi', 'firmware-update', 'app']) + cmd_parser.add_argument('command', nargs=1, help='command [test|reset|sync|run|validate|wifi|firmware-update|app|bootstrap]', choices=['test', 'reset', 'sync', 'validate', 'run', 'wifi', 'firmware-update', 'app', 'bootstrap']) + cmd_parser.add_argument('-c', '--clean', action='store_true', help='clean mass storage before writing') 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') cmd_parser.add_argument('-v', '--verbose', action='store_true', help='adds more output') + cmd_parser.add_argument('--skip-wifi', action='store_true', help='does not sync wifi.json') cmd_parser.add_argument('--print_resources', action='store_true', help='prints resources in json') cmd_parser.add_argument('--boot', help='defines which app to boot into after reboot') cmd_parser.add_argument('--run', help='like run, but after a sync') @@ -90,7 +92,7 @@ def main(): args.run = "%s/main.py" % args.paths[0] #args.boot = args.paths[0] - if command in ["test", "validate", "sync"]: + if command in ["test", "validate", "sync", "bootstrap"]: resources = get_resources(path) add_metadata(path, resources) validate(path, resources) @@ -111,15 +113,21 @@ def main(): else: args.paths = ["lib/test_%s.py" % p for p in args.paths] - - if command in ["reset", "sync"]: + if command in ["reset", "sync", "bootstrap"]: pyboard_util.stop_badge(args, args.verbose) - if command == "sync": - paths = args.paths if len(args.paths) else None - synced_resources = sync.sync(get_storage(args), paths, resources, args.verbose) + if command == "bootstrap": + sync.clean(get_storage(args)) + sync.sync(get_storage(args), ["bootstrap.py"], {}, args.verbose, args.skip_wifi) + pyboard_util.soft_reset(args) - if command in ["reset", "sync"]: + if command == "sync": + if args.clean: + sync.clean(get_storage(args)) + paths = args.paths if len(args.paths) else None + synced_resources = sync.sync(get_storage(args), paths, resources, args.verbose, args.skip_wifi) + + if (command in ["reset", "sync"]) or run_tests: sync.set_boot_app(get_storage(args), args.boot or "") if args.run: command = "run" @@ -135,7 +143,6 @@ 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) diff --git a/boot.py b/boot.py index d712cb8..484fd7c 100644 --- a/boot.py +++ b/boot.py @@ -1,7 +1,5 @@ import os, tilda -# micropython.alloc_emergency_exception_buf(100) # doesn't exist in TiLDA Mk4 yet - os.sync() root = os.listdir() @@ -21,14 +19,13 @@ def file(file, remove): print(str(e)) def any_home(): - return app(next(a for a in root if a.startswith("home"))) + h = [a for a in root if a.startswith("home")] + return h[0] if len(h) else False 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" - print(start) - #tilda.main(start) + print("Booting into %s" % start) + tilda.main(start) diff --git a/bootstrap.py b/bootstrap.py index b52044e..c55bd0b 100644 --- a/bootstrap.py +++ b/bootstrap.py @@ -14,12 +14,20 @@ def msg(text): for i, line in enumerate(lines): ugfx.text(5, 65 + i * 20, line, ugfx.BLACK) -def wifi_details(): +def wifi_details(final_try = False): if not "wifi.json" in os.listdir(): - with open("wifi.json", "w") as f: - f.write('{"ssid":"emfcamp","pw":"emfemf"}') + with open("wifi.json", "wt") as f: + f.write(json.dumps({"ssid":"emfcamp","pw":"emfemf"})) + f.flush() + os.sync() with open("wifi.json") as f: - return json.loads(f.read()) + try: + return json.loads(f.read()) + except Exception as e: + if final_try: + raise e + os.remove("wifi.json") + return wifi_details() def connect(wifi): details = wifi_details() @@ -34,9 +42,21 @@ def connect(wifi): raise OSError("Timeout while trying to\nconnect to wifi.\n\nPlease connect your\nbadge to your computer\nand edit wifi.json with\nyour wifi details"); time.sleep(0.1) +def addrinfo(host, port, retries_left = 20): + try: + return usocket.getaddrinfo(host, port)[0][4] + except OSError as e: + if ("-15" in str(e)) and retries_left: + # [addrinfo error -15] + # This tends to happen after startup and goes away after a while + time.sleep_ms(200) + return addrinfo(host, port, retries_left - 1) + else: + raise e + def get(path): s = usocket.socket() - s.connect(usocket.getaddrinfo(HOST, 80)[0][4]) + s.connect(addrinfo(HOST, 80)) body = b"" status = None try: diff --git a/launcher/main.py b/launcher/main.py index c80dd30..716c220 100644 --- a/launcher/main.py +++ b/launcher/main.py @@ -3,15 +3,15 @@ ___name___ = "Launcher" ___license___ = "MIT" ___categories___ = ["System"] -___dependencies___ = ["dialogs", "app"] +___dependencies___ = ["dialogs", "app", "ugfx_helper"] ___launchable___ = False ___bootstrapped___ = True -import ugfx +import ugfx_helper, ugfx from app import * from dialogs import * -ugfx.init() +ugfx_helper.init() ugfx.clear() options = [{"title": a.title, "app": a} for a in get_apps()] diff --git a/lib/homescreen.py b/lib/homescreen.py index ee82ada..106407b 100644 --- a/lib/homescreen.py +++ b/lib/homescreen.py @@ -17,16 +17,16 @@ They also *may*: """ ___license___ = "MIT" -___dependencies___ = ["database", "buttons", "random", "app", "sleep"] +___dependencies___ = ["database", "buttons", "random", "app", "sleep", "ugfx_helper"] -import database, ugfx, random, buttons, tilda, sleep +import database, ugfx, random, buttons, tilda, sleep, ugfx_helper from app import App _state = None def init(enable_menu_button = True): global _state _state = {"menu": False} - ugfx.init() + ugfx_helper.init() if enable_menu_button: pass diff --git a/lib/http.py b/lib/http.py index 54904b7..8a44aab 100644 --- a/lib/http.py +++ b/lib/http.py @@ -166,20 +166,17 @@ def open_http_socket(method, url, json=None, timeout=None, headers=None, data=No content = None # ToDo: Handle IPv6 addresses - addr = get_address_info(host, port) + addr = c(host, port) sock = usocket.socket(usocket.AF_INET, usocket.SOCK_STREAM) - if proto == 'https:': - # todo: fix this - sock = ussl.wrap_socket(sock, ca_certs="DST Root CA X3", cert_reqs=ussl.CERT_OPTIONAL) # , - if params: urlpath += "?" + urlencode(params) sock.connect(addr) + if proto == 'https:': - sock.settimeout(0) # Actually make timeouts working properly with ssl + sock = ussl.wrap_socket(sock, ca_certs="DST Root CA X3", cert_reqs=ussl.CERT_OPTIONAL) sock.send('%s /%s HTTP/1.0\r\nHost: %s\r\n' % (method, urlpath, host))