First pass at making libs work with Mk4
parent
80e1e03446
commit
42c27b9ce2
|
@ -1,7 +1,7 @@
|
||||||
import os, shutil, sys, fnmatch
|
import os, shutil, sys, fnmatch
|
||||||
|
|
||||||
def sync(storage, patterns, resources, verbose):
|
def sync(storage, patterns, resources, verbose):
|
||||||
root = get_root()
|
root = get_root(verbose)
|
||||||
|
|
||||||
# Add all paths that are already files
|
# Add all paths that are already files
|
||||||
paths = set([p for p in (patterns or []) if os.path.isfile(os.path.join(root, p))])
|
paths = set([p for p in (patterns or []) if os.path.isfile(os.path.join(root, p))])
|
||||||
|
@ -30,7 +30,6 @@ def sync(storage, patterns, resources, verbose):
|
||||||
paths.add(path)
|
paths.add(path)
|
||||||
if not found:
|
if not found:
|
||||||
print("WARN: No resources to copy found for pattern %s" % patterns)
|
print("WARN: No resources to copy found for pattern %s" % patterns)
|
||||||
|
|
||||||
if not verbose:
|
if not verbose:
|
||||||
print("Copying %s files: " % len(paths), end="")
|
print("Copying %s files: " % len(paths), end="")
|
||||||
for path in paths:
|
for path in paths:
|
||||||
|
@ -46,9 +45,7 @@ def sync(storage, patterns, resources, verbose):
|
||||||
|
|
||||||
target = os.path.join(storage, rel_path)
|
target = os.path.join(storage, rel_path)
|
||||||
target_dir = os.path.dirname(target)
|
target_dir = os.path.dirname(target)
|
||||||
if os.path.isfile(target_dir):
|
ensure_dir(target_dir, storage)
|
||||||
# micropython has the tendency to sometimes corrupt directories into files
|
|
||||||
os.remove(target_dir)
|
|
||||||
if not os.path.exists(target_dir):
|
if not os.path.exists(target_dir):
|
||||||
os.makedirs(target_dir)
|
os.makedirs(target_dir)
|
||||||
shutil.copy2(path, target)
|
shutil.copy2(path, target)
|
||||||
|
@ -59,6 +56,14 @@ def sync(storage, patterns, resources, verbose):
|
||||||
print(" DONE")
|
print(" DONE")
|
||||||
return synced_resources
|
return synced_resources
|
||||||
|
|
||||||
|
def ensure_dir(path, storage):
|
||||||
|
# micropython has a tendecy
|
||||||
|
if not path or path == storage:
|
||||||
|
return
|
||||||
|
if os.path.isfile(path):
|
||||||
|
os.remove(path)
|
||||||
|
ensure_dir(os.path.dirname(path), storage)
|
||||||
|
|
||||||
def set_boot_app(storage, app_to_boot):
|
def set_boot_app(storage, app_to_boot):
|
||||||
path = os.path.join(storage, 'once.txt')
|
path = os.path.join(storage, 'once.txt')
|
||||||
try:
|
try:
|
||||||
|
@ -79,8 +84,7 @@ def set_no_boot(storage):
|
||||||
with open(path, 'w') as f:
|
with open(path, 'w') as f:
|
||||||
f.write("\n")
|
f.write("\n")
|
||||||
|
|
||||||
|
def get_root(verbose=False):
|
||||||
def get_root():
|
|
||||||
root = os.path.abspath(os.path.join(os.path.dirname( __file__ ), '..'))
|
root = os.path.abspath(os.path.join(os.path.dirname( __file__ ), '..'))
|
||||||
if not os.path.isfile(os.path.join(root, "boot.py")):
|
if not os.path.isfile(os.path.join(root, "boot.py")):
|
||||||
print("Path %s doesn't contain a boot.py, aborting. Something is probably wrong with your setup.")
|
print("Path %s doesn't contain a boot.py, aborting. Something is probably wrong with your setup.")
|
||||||
|
|
|
@ -138,7 +138,7 @@ def main():
|
||||||
|
|
||||||
def find_storage():
|
def find_storage():
|
||||||
# todo: find solution for windows and linux
|
# todo: find solution for windows and linux
|
||||||
for pattern in ['/Volumes/PYBFLASH', '/Volumes/NO NAME']:
|
for pattern in ['/Volumes/TILDAMK4', '/Volumes/PYBFLASH', '/Volumes/NO NAME']:
|
||||||
for path in glob.glob(pattern):
|
for path in glob.glob(pattern):
|
||||||
return path
|
return path
|
||||||
print("Couldn't find badge storage - Please make it's plugged in and reset it if necessary")
|
print("Couldn't find badge storage - Please make it's plugged in and reset it if necessary")
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
.DS_Store
|
.DS_Store
|
||||||
__pycache__
|
__pycache__
|
||||||
wifi.json
|
wifi.json
|
||||||
|
wifi*.json
|
||||||
|
|
8
boot.py
8
boot.py
|
@ -1,8 +1,6 @@
|
||||||
import pyb, os, micropython, sys
|
import os, micropython, sys
|
||||||
|
|
||||||
micropython.alloc_emergency_exception_buf(100)
|
# micropython.alloc_emergency_exception_buf(100) # doesn't exist in TiLDA Mk4 yet
|
||||||
|
|
||||||
sys.path.append('/flash/upip')
|
|
||||||
|
|
||||||
os.sync()
|
os.sync()
|
||||||
root = os.listdir()
|
root = os.listdir()
|
||||||
|
@ -34,4 +32,4 @@ else:
|
||||||
start = "main.py"
|
start = "main.py"
|
||||||
start = file("once.txt", True) or file("default_app.txt", False) or any_home() or "bootstrap.py"
|
start = file("once.txt", True) or file("default_app.txt", False) or any_home() or "bootstrap.py"
|
||||||
|
|
||||||
pyb.main(start)
|
#todo: something like tilda.main(start)
|
||||||
|
|
|
@ -66,7 +66,7 @@ class App:
|
||||||
|
|
||||||
def boot(self):
|
def boot(self):
|
||||||
write_launch_file(self.name)
|
write_launch_file(self.name)
|
||||||
machine.reset() # used to be pyb.hard_reset()
|
machine.reset()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.title
|
return self.title
|
||||||
|
@ -116,5 +116,5 @@ def write_launch_file(app, file = "once.txt"):
|
||||||
|
|
||||||
def restart_to_default():
|
def restart_to_default():
|
||||||
write_launch_file("")
|
write_launch_file("")
|
||||||
machine.reset() # used to be pyb.hard_reset()
|
machine.reset()
|
||||||
|
|
||||||
|
|
|
@ -2,25 +2,17 @@
|
||||||
|
|
||||||
___license___ = "MIT"
|
___license___ = "MIT"
|
||||||
|
|
||||||
import pyb
|
import machine, time
|
||||||
|
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"JOY_UP": pyb.Pin.PULL_DOWN,
|
"JOY_UP": [1, machine.Pin.PULL_DOWN],
|
||||||
"JOY_DOWN": pyb.Pin.PULL_DOWN,
|
"JOY_DOWN": [2, machine.Pin.PULL_DOWN],
|
||||||
"JOY_RIGHT": pyb.Pin.PULL_DOWN,
|
"JOY_RIGHT": [4, machine.Pin.PULL_DOWN],
|
||||||
"JOY_LEFT": pyb.Pin.PULL_DOWN,
|
"JOY_LEFT": [3, machine.Pin.PULL_DOWN],
|
||||||
"JOY_CENTER": pyb.Pin.PULL_DOWN,
|
"JOY_CENTER": [0, machine.Pin.PULL_DOWN],
|
||||||
"BTN_MENU": pyb.Pin.PULL_UP,
|
"BTN_MENU": [5, machine.Pin.PULL_UP]
|
||||||
"BTN_A": pyb.Pin.PULL_UP,
|
|
||||||
"BTN_B": pyb.Pin.PULL_UP
|
|
||||||
}
|
|
||||||
|
|
||||||
ROTATION_MAP = {
|
|
||||||
"JOY_UP": "JOY_LEFT",
|
|
||||||
"JOY_LEFT": "JOY_DOWN",
|
|
||||||
"JOY_DOWN": "JOY_RIGHT",
|
|
||||||
"JOY_RIGHT": "JOY_UP",
|
|
||||||
}
|
}
|
||||||
|
# todo: port expander
|
||||||
|
|
||||||
_tilda_pins = {}
|
_tilda_pins = {}
|
||||||
_tilda_interrupts = {}
|
_tilda_interrupts = {}
|
||||||
|
@ -35,16 +27,12 @@ def init(buttons = CONFIG.keys()):
|
||||||
"""Inits all pins used by the TiLDA badge"""
|
"""Inits all pins used by the TiLDA badge"""
|
||||||
global _tilda_pins
|
global _tilda_pins
|
||||||
for button in buttons:
|
for button in buttons:
|
||||||
_tilda_pins[button] = pyb.Pin(button, pyb.Pin.IN)
|
_tilda_pins[button] = machine.Pin(CONFIG[button][0], machine.Pin.IN)
|
||||||
_tilda_pins[button].init(pyb.Pin.IN, CONFIG[button])
|
_tilda_pins[button].init(machine.Pin.IN, CONFIG[button][1])
|
||||||
|
|
||||||
def rotate(button):
|
|
||||||
"""remaps names of buttons to rotated values"""
|
|
||||||
return ROTATION_MAP[button]
|
|
||||||
|
|
||||||
def is_pressed(button):
|
def is_pressed(button):
|
||||||
pin = _get_pin(button)
|
pin = _get_pin(button)
|
||||||
if pin.pull() == pyb.Pin.PULL_DOWN:
|
if pin.pull() == machine.Pin.PULL_DOWN:
|
||||||
return pin.value() > 0
|
return pin.value() > 0
|
||||||
else:
|
else:
|
||||||
return pin.value() == 0
|
return pin.value() == 0
|
||||||
|
@ -58,19 +46,19 @@ def is_triggered(button, interval = 30):
|
||||||
global _tilda_bounce
|
global _tilda_bounce
|
||||||
if is_pressed(button):
|
if is_pressed(button):
|
||||||
if button in _tilda_bounce:
|
if button in _tilda_bounce:
|
||||||
if pyb.millis() > _tilda_bounce[button]:
|
if time.ticks_ms() > _tilda_bounce[button]:
|
||||||
del _tilda_bounce[button]
|
del _tilda_bounce[button]
|
||||||
else:
|
else:
|
||||||
return False # The button might have bounced back to high
|
return False # The button might have bounced back to high
|
||||||
|
|
||||||
# Wait for a while to avoid bounces to low
|
# Wait for a while to avoid bounces to low
|
||||||
pyb.delay(interval)
|
machine.sleep_ms(interval)
|
||||||
|
|
||||||
# Wait until button is released again
|
# Wait until button is released again
|
||||||
while is_pressed(button):
|
while is_pressed(button):
|
||||||
pyb.wfi()
|
machine.sleep_ms(1)
|
||||||
|
|
||||||
_tilda_bounce[button] = pyb.millis() + interval
|
_tilda_bounce[button] = time.ticks_ms() + interval
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def has_interrupt(button):
|
def has_interrupt(button):
|
||||||
|
@ -83,6 +71,7 @@ def has_interrupt(button):
|
||||||
|
|
||||||
|
|
||||||
def enable_interrupt(button, interrupt, on_press = True, on_release = False):
|
def enable_interrupt(button, interrupt, on_press = True, on_release = False):
|
||||||
|
raise Exception("interrupts don't work yet")
|
||||||
"""Attaches an interrupt to a button
|
"""Attaches an interrupt to a button
|
||||||
|
|
||||||
on_press defines whether it should be called when the button is pressed
|
on_press defines whether it should be called when the button is pressed
|
||||||
|
@ -104,35 +93,30 @@ def enable_interrupt(button, interrupt, on_press = True, on_release = False):
|
||||||
|
|
||||||
mode = None;
|
mode = None;
|
||||||
if on_press and on_release:
|
if on_press and on_release:
|
||||||
mode = pyb.ExtInt.IRQ_RISING_FALLING
|
mode = machine.ExtInt.IRQ_RISING_FALLING
|
||||||
else:
|
else:
|
||||||
if pin.pull() == pyb.Pin.PULL_DOWN:
|
if pin.pull() == machine.Pin.PULL_DOWN:
|
||||||
mode = pyb.ExtInt.IRQ_RISING if on_press else pyb.ExtInt.IRQ_FALLING
|
mode = machine.ExtInt.IRQ_RISING if on_press else machine.ExtInt.IRQ_FALLING
|
||||||
else:
|
else:
|
||||||
mode = pyb.ExtInt.IRQ_FALLING if on_press else pyb.ExtInt.IRQ_RISING
|
mode = machine.ExtInt.IRQ_FALLING if on_press else machine.ExtInt.IRQ_RISING
|
||||||
|
|
||||||
_tilda_interrupts[button] = {
|
_tilda_interrupts[button] = {
|
||||||
"interrupt": pyb.ExtInt(pin, mode, pin.pull(), interrupt),
|
"interrupt": machine.ExtInt(pin, mode, pin.pull(), interrupt),
|
||||||
"mode": mode,
|
"mode": mode,
|
||||||
"pin": pin
|
"pin": pin
|
||||||
}
|
}
|
||||||
|
|
||||||
def disable_interrupt(button):
|
def disable_interrupt(button):
|
||||||
|
raise Exception("interrupts don't work yet")
|
||||||
global _tilda_interrupts
|
global _tilda_interrupts
|
||||||
if button in _tilda_interrupts:
|
if button in _tilda_interrupts:
|
||||||
interrupt = _tilda_interrupts[button]
|
interrupt = _tilda_interrupts[button]
|
||||||
pyb.ExtInt(interrupt["pin"], interrupt["mode"], interrupt["pin"].pull(), None)
|
machine.ExtInt(interrupt["pin"], interrupt["mode"], interrupt["pin"].pull(), None)
|
||||||
del _tilda_interrupts[button]
|
del _tilda_interrupts[button]
|
||||||
init([button])
|
init([button])
|
||||||
|
|
||||||
def disable_all_interrupt():
|
def disable_all_interrupt():
|
||||||
|
raise Exception("interrupts don't work yet")
|
||||||
for interrupt in _tilda_interrupts:
|
for interrupt in _tilda_interrupts:
|
||||||
disable_interrupt(interrupt)
|
disable_interrupt(interrupt)
|
||||||
|
|
||||||
def enable_menu_reset():
|
|
||||||
import onboard
|
|
||||||
enable_interrupt("BTN_MENU", lambda t:onboard.semihard_reset(), on_release = True)
|
|
||||||
|
|
||||||
def disable_menu_reset():
|
|
||||||
disable_interrupt("BTN_MENU")
|
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
"""Some basic UGFX powered dialogs"""
|
"""Some basic UGFX powered dialogs"""
|
||||||
|
|
||||||
___license___ = "MIT"
|
___license___ = "MIT"
|
||||||
___dependencies___ = ["buttons"]
|
___dependencies___ = ["buttons", "sleep"]
|
||||||
|
|
||||||
import ugfx
|
import ugfx, buttons, sleep
|
||||||
import buttons
|
|
||||||
import pyb
|
|
||||||
|
|
||||||
default_style_badge = ugfx.Style()
|
default_style_badge = ugfx.Style()
|
||||||
default_style_badge.set_focus(ugfx.RED)
|
default_style_badge.set_focus(ugfx.RED)
|
||||||
|
@ -18,11 +16,13 @@ default_style_dialog.set_background(ugfx.html_color(0xFFFFFF))
|
||||||
|
|
||||||
|
|
||||||
TILDA_COLOR = ugfx.html_color(0x7c1143);
|
TILDA_COLOR = ugfx.html_color(0x7c1143);
|
||||||
|
FONT_SMALL = 0 #todo: find correct values
|
||||||
|
FONT_MEDIUM_BOLD = 0
|
||||||
|
|
||||||
def notice(text, title="TiLDA", close_text="Close", width = 260, height = 180, font=ugfx.FONT_SMALL, style=None):
|
def notice(text, title="TiLDA", close_text="Close", width = 260, height = 180, font=FONT_SMALL, style=None):
|
||||||
prompt_boolean(text, title = title, true_text = close_text, false_text = None, width = width, height = height, font=font, style=style)
|
prompt_boolean(text, title = title, true_text = close_text, false_text = None, width = width, height = height, font=font, style=style)
|
||||||
|
|
||||||
def prompt_boolean(text, title="TiLDA", true_text="Yes", false_text="No", width = 260, height = 180, font=ugfx.FONT_SMALL, style=None):
|
def prompt_boolean(text, title="TiLDA", true_text="Yes", false_text="No", width = 260, height = 180, font=FONT_SMALL, style=None):
|
||||||
"""A simple one and two-options dialog
|
"""A simple one and two-options dialog
|
||||||
|
|
||||||
if 'false_text' is set to None only one button is displayed.
|
if 'false_text' is set to None only one button is displayed.
|
||||||
|
@ -31,7 +31,7 @@ def prompt_boolean(text, title="TiLDA", true_text="Yes", false_text="No", width
|
||||||
global default_style_dialog
|
global default_style_dialog
|
||||||
if style == None:
|
if style == None:
|
||||||
style = default_style_dialog
|
style = default_style_dialog
|
||||||
ugfx.set_default_font(ugfx.FONT_MEDIUM_BOLD)
|
ugfx.set_default_font(FONT_MEDIUM_BOLD)
|
||||||
window = ugfx.Container((ugfx.width() - width) // 2, (ugfx.height() - height) // 2, width, height, style=style)
|
window = ugfx.Container((ugfx.width() - width) // 2, (ugfx.height() - height) // 2, width, height, style=style)
|
||||||
window.show()
|
window.show()
|
||||||
ugfx.set_default_font(font)
|
ugfx.set_default_font(font)
|
||||||
|
@ -44,7 +44,7 @@ def prompt_boolean(text, title="TiLDA", true_text="Yes", false_text="No", width
|
||||||
|
|
||||||
ugfx.set_default_font(font)
|
ugfx.set_default_font(font)
|
||||||
label = ugfx.Label(5, 30, width - 10, height - 80, text = text, parent=window)
|
label = ugfx.Label(5, 30, width - 10, height - 80, text = text, parent=window)
|
||||||
ugfx.set_default_font(ugfx.FONT_MEDIUM_BOLD)
|
ugfx.set_default_font(FONT_MEDIUM_BOLD)
|
||||||
button_yes = ugfx.Button(5, height - 40, width // 2 - 15 if false_text else width - 15, 30 , true_text, parent=window)
|
button_yes = ugfx.Button(5, height - 40, width // 2 - 15 if false_text else width - 15, 30 , true_text, parent=window)
|
||||||
button_no = ugfx.Button(width // 2 + 5, height - 40, width // 2 - 15, 30 , false_text, parent=window) if false_text else None
|
button_no = ugfx.Button(width // 2 + 5, height - 40, width // 2 - 15, 30 , false_text, parent=window) if false_text else None
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ def prompt_boolean(text, title="TiLDA", true_text="Yes", false_text="No", width
|
||||||
window.show()
|
window.show()
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
pyb.wfi()
|
sleep.wfi()
|
||||||
if buttons.is_triggered("BTN_A"): return True
|
if buttons.is_triggered("BTN_A"): return True
|
||||||
if buttons.is_triggered("BTN_B"): return False
|
if buttons.is_triggered("BTN_B"): return False
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ def prompt_boolean(text, title="TiLDA", true_text="Yes", false_text="No", width
|
||||||
if button_no: button_no.destroy()
|
if button_no: button_no.destroy()
|
||||||
label.destroy()
|
label.destroy()
|
||||||
|
|
||||||
def prompt_text(description, init_text = "", true_text="OK", false_text="Back", width = 300, height = 200, font=ugfx.FONT_MEDIUM_BOLD, style=default_style_badge):
|
def prompt_text(description, init_text = "", true_text="OK", false_text="Back", width = 300, height = 200, font=FONT_MEDIUM_BOLD, style=default_style_badge):
|
||||||
"""Shows a dialog and keyboard that allows the user to input/change a string
|
"""Shows a dialog and keyboard that allows the user to input/change a string
|
||||||
|
|
||||||
Returns None if user aborts with button B
|
Returns None if user aborts with button B
|
||||||
|
@ -86,7 +86,7 @@ def prompt_text(description, init_text = "", true_text="OK", false_text="Back",
|
||||||
ugfx.set_default_font(ugfx.FONT_MEDIUM)
|
ugfx.set_default_font(ugfx.FONT_MEDIUM)
|
||||||
kb = ugfx.Keyboard(0, int(height/2), width, int(height/2), parent=window)
|
kb = ugfx.Keyboard(0, int(height/2), width, int(height/2), parent=window)
|
||||||
edit = ugfx.Textbox(5, int(height/2)-30, int(width*4/5)-10, 25, text = init_text, parent=window)
|
edit = ugfx.Textbox(5, int(height/2)-30, int(width*4/5)-10, 25, text = init_text, parent=window)
|
||||||
ugfx.set_default_font(ugfx.FONT_SMALL)
|
ugfx.set_default_font(FONT_SMALL)
|
||||||
button_yes = ugfx.Button(int(width*4/5), int(height/2)-30, int(width*1/5)-3, 25 , true_text, parent=window)
|
button_yes = ugfx.Button(int(width*4/5), int(height/2)-30, int(width*1/5)-3, 25 , true_text, parent=window)
|
||||||
button_no = ugfx.Button(int(width*4/5), int(height/2)-30-30, int(width/5)-3, 25 , false_text, parent=window) if false_text else None
|
button_no = ugfx.Button(int(width*4/5), int(height/2)-30-30, int(width/5)-3, 25 , false_text, parent=window) if false_text else None
|
||||||
ugfx.set_default_font(font)
|
ugfx.set_default_font(font)
|
||||||
|
@ -101,7 +101,7 @@ def prompt_text(description, init_text = "", true_text="OK", false_text="Back",
|
||||||
window.show()
|
window.show()
|
||||||
edit.set_focus()
|
edit.set_focus()
|
||||||
while True:
|
while True:
|
||||||
pyb.wfi()
|
sleep.wfi()
|
||||||
ugfx.poll()
|
ugfx.poll()
|
||||||
#if buttons.is_triggered("BTN_A"): return edit.text()
|
#if buttons.is_triggered("BTN_A"): return edit.text()
|
||||||
if buttons.is_triggered("BTN_B"): return None
|
if buttons.is_triggered("BTN_B"): return None
|
||||||
|
@ -123,7 +123,7 @@ def prompt_option(options, index=0, text = "Please select one of the following:"
|
||||||
If none_text is specified the user can use the B or Menu button to skip the selection
|
If none_text is specified the user can use the B or Menu button to skip the selection
|
||||||
if title is specified a blue title will be displayed about the text
|
if title is specified a blue title will be displayed about the text
|
||||||
"""
|
"""
|
||||||
ugfx.set_default_font(ugfx.FONT_SMALL)
|
ugfx.set_default_font(FONT_SMALL)
|
||||||
window = ugfx.Container(5, 5, ugfx.width() - 10, ugfx.height() - 10)
|
window = ugfx.Container(5, 5, ugfx.width() - 10, ugfx.height() - 10)
|
||||||
window.show()
|
window.show()
|
||||||
|
|
||||||
|
@ -156,7 +156,7 @@ def prompt_option(options, index=0, text = "Please select one of the following:"
|
||||||
buttons.init()
|
buttons.init()
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
pyb.wfi()
|
sleep.wfi()
|
||||||
ugfx.poll()
|
ugfx.poll()
|
||||||
if buttons.is_triggered("BTN_A"): return options[options_list.selected_index()]
|
if buttons.is_triggered("BTN_A"): return options[options_list.selected_index()]
|
||||||
if button_none and buttons.is_triggered("BTN_B"): return None
|
if button_none and buttons.is_triggered("BTN_B"): return None
|
||||||
|
@ -180,15 +180,16 @@ class WaitingMessage:
|
||||||
self.label = ugfx.Label(5, 40, self.window.width() - 10, ugfx.height() - 40, text = text, parent=self.window)
|
self.label = ugfx.Label(5, 40, self.window.width() - 10, ugfx.height() - 40, text = text, parent=self.window)
|
||||||
|
|
||||||
# Indicator to show something is going on
|
# Indicator to show something is going on
|
||||||
self.indicator = ugfx.Label(ugfx.width() - 100, 0, 20, 20, text = "...", parent=self.window)
|
#self.indicator = ugfx.Label(ugfx.width() - 100, 0, 20, 20, text = "...", parent=self.window)
|
||||||
self.timer = pyb.Timer(3)
|
#self.timer = machine.Timer(3)
|
||||||
self.timer.init(freq=3)
|
#self.timer.init(freq=3)
|
||||||
self.timer.callback(lambda t: self.indicator.visible(not self.indicator.visible()))
|
#self.timer.callback(lambda t: self.indicator.visible(not self.indicator.visible()))
|
||||||
|
# todo: enable this once we have a timer somewhere
|
||||||
|
|
||||||
def destroy(self):
|
def destroy(self):
|
||||||
self.timer.deinit()
|
#self.timer.deinit()
|
||||||
self.label.destroy()
|
self.label.destroy()
|
||||||
self.indicator.destroy()
|
#self.indicator.destroy()
|
||||||
self.window.destroy()
|
self.window.destroy()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
"""Library for sleep related functions"""
|
||||||
|
|
||||||
|
import machine
|
||||||
|
|
||||||
|
|
||||||
|
_adc = None
|
||||||
|
def hall_effect_adc():
|
||||||
|
global _adc
|
||||||
|
if not _adc:
|
||||||
|
_adc = machine.ADC(machine.ADC.ADC_HALLEFFECT)
|
||||||
|
return _adc
|
||||||
|
|
||||||
|
def get_flux():
|
||||||
|
return hall_effect_adc().convert() # todo: convert this into something meaningful
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ In particular, they *should*:
|
||||||
|
|
||||||
* Call "homescreen.init()" at the beginning. This will initiate ugfx, clear the screen and
|
* Call "homescreen.init()" at the beginning. This will initiate ugfx, clear the screen and
|
||||||
initiate button handline.
|
initiate button handline.
|
||||||
* Use "pyb.wfi()" as much as possible to avoid draining the battery.
|
* Use "sleep.wfi()" as much as possible to avoid draining the battery.
|
||||||
* Not use
|
* Not use
|
||||||
|
|
||||||
They also *may*:
|
They also *may*:
|
||||||
|
@ -17,9 +17,9 @@ They also *may*:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
___license___ = "MIT"
|
___license___ = "MIT"
|
||||||
___dependencies___ = ["database", "buttons", "random", "app"]
|
___dependencies___ = ["database", "buttons", "random", "app", "sleep"]
|
||||||
|
|
||||||
import database, ugfx, random, buttons, time, select
|
import database, ugfx, random, select, buttons
|
||||||
from app import App
|
from app import App
|
||||||
|
|
||||||
_state = None
|
_state = None
|
||||||
|
@ -27,13 +27,10 @@ def init(enable_menu_button = True):
|
||||||
global _state
|
global _state
|
||||||
_state = {"menu": False}
|
_state = {"menu": False}
|
||||||
ugfx.init()
|
ugfx.init()
|
||||||
ugfx.orientation(90)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if enable_menu_button:
|
if enable_menu_button:
|
||||||
buttons.init()
|
buttons.init()
|
||||||
buttons.enable_interrupt("BTN_MENU", lambda t: set_state("menu"), on_release = True)
|
#buttons.enable_interrupt("BTN_MENU", lambda t: set_state("menu"), on_release = True)
|
||||||
|
|
||||||
def set_state(key, value = True):
|
def set_state(key, value = True):
|
||||||
# we can't allocate memory in interrupts, so make sure all keys are set beforehand and
|
# we can't allocate memory in interrupts, so make sure all keys are set beforehand and
|
||||||
|
@ -42,18 +39,13 @@ def set_state(key, value = True):
|
||||||
_state[key] = value
|
_state[key] = value
|
||||||
|
|
||||||
def clean_up():
|
def clean_up():
|
||||||
buttons.disable_all_interrupt()
|
pass
|
||||||
|
|
||||||
def check():
|
def sleep(interval = 500):
|
||||||
global _state
|
if button.is_triggered("BTN_MENU", interval=interval):
|
||||||
if _state["menu"]:
|
|
||||||
clean_up()
|
clean_up()
|
||||||
App("launcher").boot()
|
App("launcher").boot()
|
||||||
|
|
||||||
def sleep(interval = 500):
|
|
||||||
check()
|
|
||||||
time.sleep_ms(interval) # todo: deep sleep
|
|
||||||
check()
|
|
||||||
|
|
||||||
def name(default = None):
|
def name(default = None):
|
||||||
return database.get("homescreen.name", default)
|
return database.get("homescreen.name", default)
|
||||||
|
|
|
@ -8,7 +8,7 @@ Current known issues:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
___license___ = "MIT"
|
___license___ = "MIT"
|
||||||
___dependencies___ = ["urlencode"]
|
___dependencies___ = ["urlencode", "wifi"]
|
||||||
|
|
||||||
import usocket, ujson, os, time, gc, wifi
|
import usocket, ujson, os, time, gc, wifi
|
||||||
from urlencode import urlencode
|
from urlencode import urlencode
|
||||||
|
@ -144,6 +144,7 @@ def open_http_socket(method, url, json=None, timeout=None, headers=None, data=No
|
||||||
if proto == 'http:':
|
if proto == 'http:':
|
||||||
port = 80
|
port = 80
|
||||||
elif proto == 'https:':
|
elif proto == 'https:':
|
||||||
|
#todo make this work
|
||||||
raise OSError("HTTPS is currently not supported")
|
raise OSError("HTTPS is currently not supported")
|
||||||
port = 443
|
port = 443
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -10,10 +10,10 @@ import os
|
||||||
|
|
||||||
sep = "/"
|
sep = "/"
|
||||||
|
|
||||||
R_OK = const(4)
|
R_OK = 4
|
||||||
W_OK = const(2)
|
W_OK = 2
|
||||||
X_OK = const(1)
|
X_OK = 1
|
||||||
F_OK = const(0)
|
F_OK = 0
|
||||||
|
|
||||||
def join(*args):
|
def join(*args):
|
||||||
# TODO: this is non-compliant
|
# TODO: this is non-compliant
|
||||||
|
|
|
@ -5,6 +5,7 @@ Warning! Don't use this for anything important, it's probably biased
|
||||||
|
|
||||||
___license___ = "MIT"
|
___license___ = "MIT"
|
||||||
|
|
||||||
|
# todo: simplify this by using "urandom"
|
||||||
import os
|
import os
|
||||||
|
|
||||||
_bigrand_bytes = 10
|
_bigrand_bytes = 10
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
"""Library for sleep related functions"""
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
|
def sleep_ms(duration):
|
||||||
|
# todo: deepsleep?
|
||||||
|
time.sleep_ms(duration)
|
||||||
|
|
||||||
|
def wfi():
|
||||||
|
# todo: this is fake
|
||||||
|
sleep_ms(1)
|
|
@ -0,0 +1,34 @@
|
||||||
|
"""Tests for app lib
|
||||||
|
|
||||||
|
Very limited at the moment since we can't test the main input dialogs"""
|
||||||
|
|
||||||
|
___license___ = "MIT"
|
||||||
|
___dependencies___ = ["upip:unittest", "dialogs", "sleep"]
|
||||||
|
|
||||||
|
import unittest, ugfx
|
||||||
|
from machine import Pin
|
||||||
|
from dialogs import *
|
||||||
|
from sleep import *
|
||||||
|
|
||||||
|
class TestDialogs(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUpClass(self):
|
||||||
|
ugfx.init()
|
||||||
|
Pin(Pin.PWM_LCD_BLIGHT).on()
|
||||||
|
|
||||||
|
def tearDownClass(self):
|
||||||
|
Pin(Pin.PWM_LCD_BLIGHT).off()
|
||||||
|
|
||||||
|
def test_app_object(self):
|
||||||
|
count_max = 10
|
||||||
|
with WaitingMessage("Testing...", "Foo") as c:
|
||||||
|
for i in range(1, count_max):
|
||||||
|
sleep_ms(100)
|
||||||
|
c.text = "%d/%d" % (i, count_max)
|
||||||
|
|
||||||
|
print("done")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
|
@ -0,0 +1,17 @@
|
||||||
|
"""Tests for hall effect sensor"""
|
||||||
|
|
||||||
|
___license___ = "MIT"
|
||||||
|
___dependencies___ = ["upip:unittest", "hall_effect"]
|
||||||
|
|
||||||
|
import unittest, hall_effect
|
||||||
|
|
||||||
|
class TestHallEffect(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_hall(self):
|
||||||
|
flux = hall_effect.get_flux()
|
||||||
|
self.assertTrue(flux > 0)
|
||||||
|
self.assertTrue(flux < 4000)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
|
@ -9,29 +9,29 @@ from icons import *
|
||||||
class TestIcons(unittest.TestCase):
|
class TestIcons(unittest.TestCase):
|
||||||
|
|
||||||
# incomplete!
|
# incomplete!
|
||||||
|
# todo: fix me
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
ugfx.init()
|
ugfx.init()
|
||||||
ugfx.orientation(90)
|
|
||||||
ugfx.clear()
|
ugfx.clear()
|
||||||
|
|
||||||
def test_icon(self):
|
# def test_icon(self):
|
||||||
icon = Icon(44, 40, "Badge Store with", "badge_store/icon.gif")
|
# icon = Icon(44, 40, "Badge Store with", "badge_store/icon.gif")
|
||||||
icon.show()
|
# icon.show()
|
||||||
|
#
|
||||||
for s in [True, False, True]:
|
# for s in [True, False, True]:
|
||||||
icon.selected = s
|
# icon.selected = s
|
||||||
time.sleep(0.1)
|
# time.sleep(0.1)
|
||||||
|
#
|
||||||
icon.__del__()
|
# icon.__del__()
|
||||||
|
#
|
||||||
def test_icon_grid(self):
|
# def test_icon_grid(self):
|
||||||
items = []
|
# items = []
|
||||||
for i in range(50):
|
# for i in range(50):
|
||||||
items.append({
|
# items.append({
|
||||||
"title": "App %s" % i
|
# "title": "App %s" % i
|
||||||
})
|
# })
|
||||||
icon_grid = IconGrid(5, 5, items, None)
|
# icon_grid = IconGrid(5, 5, items, None)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
"""Tests for http"""
|
||||||
|
|
||||||
|
___license___ = "MIT"
|
||||||
|
___dependencies___ = ["upip:unittest", "sleep"]
|
||||||
|
|
||||||
|
import unittest, sleep
|
||||||
|
|
||||||
|
class TestSleep(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_sleep(self):
|
||||||
|
sleep.sleep_ms(100)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
|
@ -0,0 +1,15 @@
|
||||||
|
"""Tests for wifi"""
|
||||||
|
|
||||||
|
___license___ = "MIT"
|
||||||
|
___dependencies___ = ["upip:unittest", "wifi"]
|
||||||
|
|
||||||
|
import unittest, wifi
|
||||||
|
|
||||||
|
class TestWifi(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_connect(self):
|
||||||
|
wifi.connect()
|
||||||
|
self.assertTrue(wifi.is_connected())
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
36
lib/wifi.py
36
lib/wifi.py
|
@ -1,20 +1,17 @@
|
||||||
"""Handles connecting to a wifi access point based on a valid wifi.json file"""
|
"""Handles connecting to a wifi access point based on a valid wifi.json file"""
|
||||||
|
|
||||||
___license___ = "MIT"
|
___license___ = "MIT"
|
||||||
___dependencies___ = ["dialogs"]
|
___dependencies___ = ["dialogs", "sleep"]
|
||||||
|
|
||||||
import network
|
import network, os, json, dialogs, sleep, time
|
||||||
import os
|
|
||||||
import json
|
|
||||||
import pyb
|
|
||||||
import dialogs
|
|
||||||
|
|
||||||
_nic = None
|
_nic = None
|
||||||
|
|
||||||
def nic():
|
def nic():
|
||||||
global _nic
|
global _nic
|
||||||
if not _nic:
|
if not _nic:
|
||||||
_nic = network.CC3100()
|
_nic = network.WLAN()
|
||||||
|
_nic.active(True)
|
||||||
return _nic
|
return _nic
|
||||||
|
|
||||||
def connection_details():
|
def connection_details():
|
||||||
|
@ -37,7 +34,7 @@ def connect(wait=True, timeout=10, show_wait_message=False, prompt_on_fail=True,
|
||||||
retry_connect = True
|
retry_connect = True
|
||||||
|
|
||||||
while retry_connect:
|
while retry_connect:
|
||||||
if nic().is_connected():
|
if nic().isconnected():
|
||||||
return
|
return
|
||||||
|
|
||||||
details = connection_details()
|
details = connection_details()
|
||||||
|
@ -68,25 +65,27 @@ def connect(wait=True, timeout=10, show_wait_message=False, prompt_on_fail=True,
|
||||||
if not retry_connect:
|
if not retry_connect:
|
||||||
os.remove('wifi.json')
|
os.remove('wifi.json')
|
||||||
os.sync()
|
os.sync()
|
||||||
# We would rather let you choose a new network here, but
|
|
||||||
# scanning doesn't work after a connect at the moment
|
|
||||||
pyb.hard_reset()
|
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def connect_wifi(details, timeout, wait=False):
|
def connect_wifi(details, timeout, wait=False):
|
||||||
if 'pw' in details:
|
if 'pw' in details:
|
||||||
nic().connect(details['ssid'], details['pw'], timeout=timeout)
|
nic().connect(details['ssid'], details['pw'])
|
||||||
else:
|
else:
|
||||||
nic().connect(details['ssid'], timeout=timeout)
|
nic().connect(details['ssid'])
|
||||||
|
|
||||||
if wait:
|
if wait:
|
||||||
while not nic().is_connected():
|
wait_until = time.ticks_ms() + 2000
|
||||||
nic().update()
|
while not nic().isconnected():
|
||||||
pyb.delay(100)
|
#nic().update() # todo: do we need this?
|
||||||
|
if (time.ticks_ms() > wait_until):
|
||||||
|
raise Exception("Timeout while trying to connect to wifi")
|
||||||
|
sleep.sleep_ms(100)
|
||||||
|
|
||||||
|
|
||||||
def is_connected():
|
def is_connected():
|
||||||
return nic().is_connected()
|
return nic().isconnected()
|
||||||
|
|
||||||
def get_security_level(ap):
|
def get_security_level(ap):
|
||||||
n = nic()
|
n = nic()
|
||||||
|
@ -149,5 +148,4 @@ def choose_wifi(dialog_title='TiLDA'):
|
||||||
|
|
||||||
file.write(json.dumps(conn_details))
|
file.write(json.dumps(conn_details))
|
||||||
os.sync()
|
os.sync()
|
||||||
# We can't connect after scanning for some bizarre reason, so we reset instead
|
# todo: last time we had to hard reset here, is that still the case?
|
||||||
pyb.hard_reset()
|
|
||||||
|
|
Loading…
Reference in New Issue