You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

227 lines
6.6 KiB

# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
# SPDX-License-Identifier: GPL-3.0-or-later
#
# SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
# SPDX-License-Identifier: GPL-3.0-only
#
# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard <coldcardwallet.com>
# and is covered by GPLv3 license found in COPYING.
#
# main.py - Main initialization code
#
import utime
import uasyncio.core as asyncio
from uasyncio import sleep_ms
from periodic import update_ambient_screen_brightness, update_battery_level, check_auto_shutdown, demo_loop
from schema_evolution import handle_schema_evolutions
#
# Show REPL welcome message
print("Entered main.py")
import gc
print('Available RAM = {}'.format(gc.mem_free()))
SETTINGS_FLASH_START = 0x81E0000
SETTINGS_FLASH_SIZE = 0x20000
# We run main in a separate task so that the startup loop's variables can be released
async def main():
from ux import the_ux
while 1:
await sleep_ms(10)
await the_ux.interact()
async def startup():
import common
from common import pa, loop
from actions import goto_top_menu, validate_passport_hw, initial_pin_setup, start_login_sequence
print("startup()")
common.system.hide_busy_bar()
import uctypes
buf = uctypes.bytearray_at(0x38000000, 1)
# Check for self-test
if buf[0] == 1:
from self_test_ux import SelfTestUX
self_test = SelfTestUX()
await self_test.show()
from accept_terms_ux import AcceptTermsUX
accept_terms = AcceptTermsUX()
await accept_terms.show()
await validate_passport_hw()
# Setup initial PIN if it's blank
if pa.is_blank():
await initial_pin_setup()
# Prompt for PIN and then pick appropriate top-level menu
await start_login_sequence()
# Set the key for the flash cache (cache is inaccessible prior to user logging in)
common.system.show_busy_bar()
common.flash_cache.set_key()
common.flash_cache.load()
# Trigger a get here so that the XFP & XPUB are captured
common.settings.get('xfp')
# See if an update was just performed -- we may need to run a schema evolution script
update_from_to = common.settings.get('update')
# print('update_from_to={}'.format(update_from_to))
if update_from_to:
await handle_schema_evolutions(update_from_to)
common.system.hide_busy_bar()
await goto_top_menu()
loop.create_task(main())
def go():
import common
from sram4 import viewfinder_buf
# Initialize the common objects
# Avalanche noise source
from foundation import Noise
common.noise = Noise()
# Initialize the seed of the PRNG in MicroPython with a real random number
# We only use the PRNG for non-critical randomness that just needs to be fast
import random
from utils import randint
random.seed(randint(0, 2147483647))
# Power monitor
from foundation import Powermon
common.powermon = Powermon()
# Get the async event loop to pass in where needed
common.loop = asyncio.get_event_loop()
# System
from foundation import System
common.system = System()
common.system.show_busy_bar()
# Initialize the keypad
from keypad import Keypad
common.keypad = Keypad()
# Initialize SD card
from files import CardSlot
CardSlot.setup()
# External SPI Flash
from sflash import SPIFlash
common.sf = SPIFlash()
# Initialize internal flash settings
from settings import Settings
common.settings = Settings(common.loop)
# Initialize the external flash cache
from flash_cache import FlashCache
common.flash_cache = FlashCache(common.loop)
# Initialize the display and show the splash screen
from display import Display
common.dis = Display()
common.dis.set_brightness(common.settings.get('screen_brightness', 100))
common.dis.splash()
# Allocate buffers for camera
from constants import VIEWFINDER_WIDTH, VIEWFINDER_HEIGHT, CAMERA_WIDTH, CAMERA_HEIGHT
# QR buf is 1 byte per pixel grayscale
import uctypes
common.qr_buf = uctypes.bytearray_at(0x20000000, CAMERA_WIDTH * CAMERA_HEIGHT)
# common.qr_buf = bytearray(CAMERA_WIDTH * CAMERA_HEIGHT)
# Viewfinder buf 1s 1 bit per pixel and we round the screen width up to 240
# so it's a multiple of 8 bits. The screen height of 303 minus 31 for the
# header and 31 for the footer gives 241 pixels, which we round down to 240
# to give one blank (white) line before the footer.
common.viewfinder_buf = bytearray((VIEWFINDER_WIDTH * VIEWFINDER_HEIGHT) // 8)
# Show REPL welcome message
print("Passport by Foundation Devices Inc. (C) 2020.\n")
from foundation import SettingsFlash
f = SettingsFlash()
try:
from pincodes import PinAttempt
common.pa = PinAttempt()
common.pa.setup(b'')
except RuntimeError as e:
print("Secure Element Problem: %r" % e)
# Setup the startup task
common.loop.create_task(startup())
# Setup check for automatic screen brightness control
# Not used at this time
# common.loop.create_task(update_ambient_screen_brightness())
# Setup check to read battery level and put it in common.battery_level
common.loop.create_task(update_battery_level())
# Setup check for auto shutdown
common.loop.create_task(check_auto_shutdown())
# Setup check to read battery level and put it in common.battery_level
common.loop.create_task(demo_loop())
gc.collect()
print('Available RAM after init = {}'.format(gc.mem_free()))
run_loop()
def run_loop():
# Wrapper for better error handling/recovery at top level.
try:
# This keeps all async tasks alive, including the main task created above
from common import loop
loop.run_forever()
except BaseException as exc:
import sys
sys.print_exception(exc)
# if isinstance(exc, KeyboardInterrupt):
# # preserve GUI state, but want to see where we are
# print("KeyboardInterrupt")
# raise
if isinstance(exc, SystemExit):
# Ctrl-D and warm reboot cause this, not bugs
raise
else:
print("Exception:")
# show stacktrace for debug photos
try:
import uio
import ux
tmp = uio.StringIO()
sys.print_exception(exc, tmp)
msg = tmp.getvalue()
del tmp
print(msg)
ux.show_fatal_error(msg)
except Exception as exc2:
sys.print_exception(exc2)
go()