You've already forked MicroPythonOS
mirror of
https://github.com/m5stack/MicroPythonOS.git
synced 2026-05-20 11:51:27 -07:00
149 lines
6.6 KiB
Python
149 lines
6.6 KiB
Python
import lvgl as lv
|
|
|
|
import _thread
|
|
import traceback
|
|
|
|
import mpos.info
|
|
import mpos.ui
|
|
from mpos.app.activity import Activity
|
|
from mpos.content.intent import Intent
|
|
from mpos.content.package_manager import PackageManager
|
|
|
|
def good_stack_size():
|
|
stacksize = 24*1024
|
|
import sys
|
|
if sys.platform == "esp32":
|
|
stacksize = 16*1024
|
|
return stacksize
|
|
|
|
# Run the script in the current thread:
|
|
# Returns True if successful
|
|
def execute_script(script_source, is_file, cwd=None, classname=None):
|
|
import utime # for timing read and compile
|
|
thread_id = _thread.get_ident()
|
|
compile_name = 'script' if not is_file else script_source
|
|
print(f"Thread {thread_id}: executing script with cwd: {cwd}")
|
|
try:
|
|
if is_file:
|
|
print(f"Thread {thread_id}: reading script from file {script_source}")
|
|
with open(script_source, 'r') as f: # No need to check if it exists as exceptions are caught
|
|
start_time = utime.ticks_ms()
|
|
script_source = f.read()
|
|
read_time = utime.ticks_diff(utime.ticks_ms(), start_time)
|
|
print(f"execute_script: reading script_source took {read_time}ms")
|
|
script_globals = {
|
|
'lv': lv,
|
|
'__name__': "__main__"
|
|
}
|
|
print(f"Thread {thread_id}: starting script")
|
|
import sys
|
|
path_before = sys.path
|
|
if cwd:
|
|
sys.path.append(cwd)
|
|
try:
|
|
start_time = utime.ticks_ms()
|
|
compiled_script = compile(script_source, compile_name, 'exec')
|
|
compile_time = utime.ticks_diff(utime.ticks_ms(), start_time)
|
|
print(f"execute_script: compiling script_source took {compile_time}ms")
|
|
start_time = utime.ticks_ms()
|
|
exec(compiled_script, script_globals)
|
|
end_time = utime.ticks_diff(utime.ticks_ms(), start_time)
|
|
print(f"apps.py execute_script: exec took {end_time}ms")
|
|
# Introspect globals
|
|
#classes = {k: v for k, v in script_globals.items() if isinstance(v, type)}
|
|
#functions = {k: v for k, v in script_globals.items() if callable(v) and not isinstance(v, type)}
|
|
#variables = {k: v for k, v in script_globals.items() if not callable(v)}
|
|
#print("Classes:", classes.keys())
|
|
#print("Functions:", functions.keys())
|
|
#print("Variables:", variables.keys())
|
|
if not classname:
|
|
print("Running without a classname isn't supported right now.")
|
|
return False
|
|
main_activity = script_globals.get(classname)
|
|
if main_activity:
|
|
start_time = utime.ticks_ms()
|
|
Activity.startActivity(None, Intent(activity_class=main_activity))
|
|
end_time = utime.ticks_diff(utime.ticks_ms(), start_time)
|
|
print(f"execute_script: Activity.startActivity took {end_time}ms")
|
|
else:
|
|
print(f"Warning: could not find app's main_activity {main_activity}")
|
|
return False
|
|
except Exception as e:
|
|
print(f"Thread {thread_id}: exception during execution:")
|
|
# Print stack trace with exception type, value, and traceback
|
|
tb = getattr(e, '__traceback__', None)
|
|
traceback.print_exception(type(e), e, tb)
|
|
return False
|
|
print(f"Thread {thread_id}: script {compile_name} finished, restoring sys.path to {sys.path}")
|
|
sys.path = path_before
|
|
return True
|
|
except Exception as e:
|
|
print(f"Thread {thread_id}: error:")
|
|
tb = getattr(e, '__traceback__', None)
|
|
traceback.print_exception(type(e), e, tb)
|
|
return False
|
|
|
|
""" Unused:
|
|
# Run the script in a new thread:
|
|
# NOTE: check if the script exists here instead of launching a new thread?
|
|
def execute_script_new_thread(scriptname, is_file):
|
|
print(f"main.py: execute_script_new_thread({scriptname},{is_file})")
|
|
try:
|
|
# 168KB maximum at startup but 136KB after loading display, drivers, LVGL gui etc so let's go for 128KB for now, still a lot...
|
|
# But then no additional threads can be created. A stacksize of 32KB allows for 4 threads, so 3 in the app itself, which might be tight.
|
|
# 16KB allows for 10 threads in the apps, but seems too tight for urequests on unix (desktop) targets
|
|
# 32KB seems better for the camera, but it forced me to lower other app threads from 16 to 12KB
|
|
#_thread.stack_size(24576) # causes camera issue...
|
|
# NOTE: This doesn't do anything if apps are started in the same thread!
|
|
if "camtest" in scriptname:
|
|
print("Starting camtest with extra stack size!")
|
|
stack=32*1024
|
|
elif "appstore" in scriptname:
|
|
print("Starting appstore with extra stack size!")
|
|
stack=24*1024 # this doesn't do anything because it's all started in the same thread
|
|
else:
|
|
stack=16*1024 # 16KB doesn't seem to be enough for the AppStore app on desktop
|
|
stack = mpos.apps.good_stack_size()
|
|
print(f"app.py: setting stack size for script to {stack}")
|
|
_thread.stack_size(stack)
|
|
_thread.start_new_thread(execute_script, (scriptname, is_file))
|
|
except Exception as e:
|
|
print("main.py: execute_script_new_thread(): error starting new thread thread: ", e)
|
|
"""
|
|
|
|
# Returns True if successful
|
|
def start_app(fullname):
|
|
mpos.ui.set_foreground_app(fullname)
|
|
import utime
|
|
start_time = utime.ticks_ms()
|
|
app = PackageManager.get(fullname)
|
|
if not app:
|
|
print(f"Warning: start_app can't find app {fullname}")
|
|
return
|
|
if not app.installed_path:
|
|
print(f"Warning: start_app can't start {fullname} because no it doesn't have an installed_path")
|
|
return
|
|
if not app.main_launcher_activity:
|
|
print(f"WARNING: start_app can't start {fullname} because it doesn't have a main_launcher_activity")
|
|
return
|
|
start_script_fullpath = f"{app.installed_path}/{app.main_launcher_activity.get('entrypoint')}"
|
|
result = execute_script(start_script_fullpath, True, app.installed_path + "/assets/", app.main_launcher_activity.get("classname"))
|
|
# Launchers have the bar, other apps don't have it
|
|
if app.is_valid_launcher():
|
|
mpos.ui.topmenu.open_bar()
|
|
else:
|
|
mpos.ui.topmenu.close_bar()
|
|
end_time = utime.ticks_diff(utime.ticks_ms(), start_time)
|
|
print(f"start_app() took {end_time}ms")
|
|
return result
|
|
|
|
|
|
# Starts the first launcher that's found
|
|
def restart_launcher():
|
|
print("restart_launcher")
|
|
# Stop all apps
|
|
mpos.ui.remove_and_stop_all_activities()
|
|
# No need to stop the other launcher first, because it exits after building the screen
|
|
return start_app(PackageManager.get_launcher().fullname)
|
|
|