firmware/shared/main.py
2024-04-18 09:29:05 -04:00

172 lines
4.4 KiB
Python

# (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC.
#
# main.py
#
# - importing this file starts the system, see "go()"
# - NO: main.loop is imported and "run forever" by boot.py, forced into place by COLDCARD/initfs code
# - cannot be changed by /flash/lib overrides, because already imported before that.
#
# see RAM_HEADER_BASE, and coldcardFirmwareHeader_t in sigheader.h
import pyb, sys, gc, glob
from imptask import IMPT, die_with_debug
assert not glob.dis, "main reimport"
# this makes the GC run when larger objects are free in an attempt to reduce fragmentation.
gc.threshold(4096)
# useful for debug: start serial port early, when possible
try:
from h import *
import ckcc
ckcc.vcp_enabled(True)
except:
# above will fail on release build, because:
# - 'h.py' not included
# - excludes serial port code access completely (see vcp_lockdown.c)
pass
# Sometimes useful: die early for debug
#raise SystemExit
print("---\nColdcard Wallet from Coinkite Inc. (c) 2018-2024.")
import version
datestamp,vers,_ = version.get_mpy_version()
print("Version: %s / %s\n" % (vers, datestamp))
# Setup display and get something onto it.
if version.has_qwerty:
from lcd_display import Display
else:
from display import Display
dis = Display()
dis.splash()
glob.dis = dis
# Slowish imports, some with side-effects
import ckcc, uasyncio
# Early setup code
try:
if version.has_qwerty:
import q1
q1.init0()
else:
import mk4
mk4.init0()
from psram import PSRAMWrapper
glob.PSRAM = PSRAMWrapper()
except BaseException as exc:
sys.print_exception(exc)
# continue tho
# Setup keypad/keyboard
if version.has_qwerty:
from keyboard import FullKeyboard
numpad = FullKeyboard()
glob.numpad = numpad
else:
from mempad import MembraneNumpad
numpad = MembraneNumpad()
glob.numpad = numpad
# NV settings
from nvstore import SettingsObject
settings = SettingsObject()
settings.load(glob.dis)
glob.settings = settings
async def more_setup():
# Boot up code; splash screen is being shown
try:
from files import CardSlot
CardSlot.setup()
# This "pa" object holds some state shared w/ bootloader about the PIN
try:
from pincodes import pa
pa.setup(b'') # just to see where we stand.
is_blank = pa.is_blank()
except RuntimeError as e:
is_blank = True
print("Problem: %r" % e)
if version.is_factory_mode:
print("factory mode")
# in factory mode, turn on USB early to allow debug/setup
from usb import enable_usb
enable_usb()
# always start the self test.
if not settings.get('tested', False):
from actions import start_selftest
await start_selftest()
elif is_blank:
# force them to accept terms (unless marked as already done in settings)
# only if no main PIN chosen
from actions import accept_terms
await accept_terms()
# Prompt for PIN and then pick appropriate top-level menu,
# based on contents of secure chip (ie. is there a wallet defined)
from actions import start_login_sequence
await start_login_sequence()
except BaseException as exc:
die_with_debug(exc)
# define contents of main menu
from actions import goto_top_menu
goto_top_menu()
# fetch this function for mainline to use
from ux import the_ux
doit = the_ux.interact
IMPT.start_task('mainline', mainline(doit))
async def mainline(doit):
# Mainline of program, after startup. Never stops.
#
# - Do not add to this function, its vars are
# in memory forever; instead, extend more_setup() above.
gc.collect()
#print("Free mem: %d" % gc.mem_free()) # 515536 on mk4!
while 1:
await doit()
def go():
# Wrapper for better error handling/recovery at top level.
#
try:
uasyncio.get_event_loop().run_forever()
raise RuntimeError('main.stop') # not expected
except BaseException as exc:
die_with_debug(exc)
if version.is_devmode:
# Start some debug-only code.
try:
import dev_helper
dev_helper.setup()
except: pass
# Simulator code
try:
import sim_quickstart
except: pass
uasyncio.create_task(more_setup())
go()
# EOF