From d52c0089bd5de953b9dc9db7436292a0c7ca944b Mon Sep 17 00:00:00 2001 From: "Peter D. Gray" Date: Mon, 8 Jan 2024 14:24:55 -0500 Subject: [PATCH] more q selftest --- shared/battery.py | 42 ++++++++++++---------- shared/selftest.py | 69 ++++++++++++++++++++++++++++--------- unix/variant/sim_battery.py | 6 ++-- unix/variant/sim_scanner.py | 2 +- 4 files changed, 81 insertions(+), 38 deletions(-) diff --git a/shared/battery.py b/shared/battery.py index 06f948cb..5cd59bee 100644 --- a/shared/battery.py +++ b/shared/battery.py @@ -1,8 +1,6 @@ # (c) Copyright 2023 by Coinkite Inc. This file is covered by license found in COPYING-CC. # -# battery.py - Q-specific code related to batteries and monitoring that. -# -# NOTE: Lots of hardware overlap with Mk4, so see mk4.py too! +# battery.py - Q-specific code related to batteries, their settings, and monitoring them. # from imptask import IMPT import uasyncio as asyncio @@ -14,7 +12,11 @@ DEFAULT_BATT_IDLE_TIMEOUT = const(30*60) # 0..255 brightness value for when on batteries DEFAULT_BATT_BRIGHTNESS = const(200) -nbat_pin = Pin('NOT_BATTERY') +# had to move this pin in RevD +# - TODO: remove this support once rev D's are around +rev_d_later = not Pin('REV_D', mode=Pin.IN, pull=Pin.PULL_UP) +nbat_pin = Pin('NOT_BATTERY_OLD' if not rev_d_later else 'NOT_BATTERY', + mode=Pin.IN, pull=Pin.PULL_UP) def setup_battery(): # setup and monitor things. @@ -22,22 +24,27 @@ def setup_battery(): IMPT.start_task('battery', batt_monitor_task()) - #nbat_pin.irq(_nbatt_irq, Pin.IRQ_FALLING|Pin.IRQ_RISING) async def batt_monitor_task(): - last_lvl = None + # Long-lived task to watch battery level and USB vs. battery power source + # TODO: be a class + from glob import dis + def maybe_update(unused_arg=None, last_lvl=-100): + lvl = get_batt_threshold() + if lvl != last_lvl: + dis.draw_status(bat=lvl) + return lvl + + if rev_d_later: + nbat_pin.irq(maybe_update, Pin.IRQ_FALLING|Pin.IRQ_RISING) + + last_lvl = None while 1: # slowly track battery level - await asyncio.sleep(5) + await asyncio.sleep(30 if rev_d_later else 5) - lvl = get_batt_threshold() - - if lvl != last_lvl: - from glob import dis - - dis.draw_status(bat=lvl) - last_lvl = lvl + last_lvl = maybe_update(last_lvl=last_lvl) def setup_adc(): # configure VREF source as internally generated @@ -58,12 +65,11 @@ def setup_adc(): def get_batt_level(): # return voltage from batteries, as a float # - will only work on battery power, else return None - # - reads a bit low (3.3v in => 2.7v here) try: from machine import ADC, Pin except ImportError: # simulator - return 2.99 + return 3.3 if nbat_pin() == 1: # not getting power from batteries, so don't know level @@ -79,9 +85,9 @@ def get_batt_threshold(): volts = get_batt_level() if volts is None: return None - if volts <= 2.1: + if volts <= 2.9: return 0 - if volts <= 3.0: + if volts <= 3.5: return 1 if volts <= 4.0: return 2 diff --git a/shared/selftest.py b/shared/selftest.py index 272cc377..750df03c 100644 --- a/shared/selftest.py +++ b/shared/selftest.py @@ -4,14 +4,13 @@ # import ckcc from uasyncio import sleep_ms -from glob import dis +from glob import dis, settings from ux import ux_wait_keyup, ux_clear_keys, ux_poll_key from ux import ux_show_story from callgate import get_is_bricked, get_genuine, clear_genuine from utils import problem_file_line import version -from glob import settings -from charcodes import KEY_ENTER, KEY_CANCEL +from charcodes import KEY_ENTER, KEY_CANCEL, KEY_QR try: from display import FontLarge @@ -19,7 +18,7 @@ except ImportError: FontLarge = None async def wait_ok(): - k = await ux_wait_keyup('xy' + KEY_ENTER + KEY_CANCEL) + k = await ux_wait_keyup('xy' + KEY_ENTER + KEY_CANCEL, flush=True) if k not in 'y' + KEY_ENTER: raise RuntimeError('Canceled') @@ -44,7 +43,7 @@ async def test_numpad(): dis.text(None,24, ch if ch != 'y' else 'OK', FontLarge) dis.show() - k = await ux_wait_keyup(ch + 'x') + k = await ux_wait_keyup(ch + 'x', flush=True) if k == 'x' and ch != 'x': raise RuntimeError("numpad test aborted") assert k == ch @@ -69,15 +68,44 @@ async def test_gpu(): dis.clear() async def test_keyboard(): - # for Q1 - # XXX - pass + # for Q1 - just some of them: one in each row and column + + keys = list('1wdvgy7k.p '+KEY_QR) + + for ch in keys: + dis.clear() + dis.text(None,2, "Keyboard Test. Press:") + dis.text(None,4, 'SPACE' if ch == ' ' else ch.upper()) + dis.show() + + k = await ux_wait_keyup(ch + KEY_CANCEL, flush=True) + if k == KEY_CANCEL: + raise RuntimeError("kbd test aborted") + assert k == ch async def test_qr_scanner(): - # QR Scanner module: assume pretested, just testing connection + # QR Scanner module: assume pretested, just testing connection really from glob import SCAN - assert SCAN - assert SCAN.version.startswith('V2.3.') + assert SCAN and SCAN.version and SCAN.version.startswith('V2.3.'), 'QR Scanner Missing' + +async def test_battery(): + from battery import get_batt_level + + while 1: + lvl = get_batt_level() + + if lvl and 3.2 <= lvl <= 3.4: + # pass + return + + dis.clear() + dis.text(None, 2, "Remove USB cable &") + dis.text(None, 3, "connect 3.3v reference.") + dis.text(None, 4, "Then press ENTER.") + if lvl: + dis.text(None, -1, "VIN Sense reads: %.1f volts" % lvl, dark=True) + dis.show() + await wait_ok() def set_genuine(): # PIN must be blank for this to work @@ -111,11 +139,11 @@ async def test_secure_element(): for ph in range(5): gg = get_genuine() + dis.clear() + if version.has_qwerty: - dis.clear() dis.text(0, 0, "^^-- Green? " if gg else " ^^-- Red?") else: - dis.clear() if gg: dis.text(-1, 8, "Green ON? -->") else: @@ -258,7 +286,7 @@ async def test_lcd(): dis.clear() async def test_microsd(): - #if ckcc.is_simulator(): return + if ckcc.is_simulator(): return from version import num_sd_slots from files import CardSlot import os @@ -311,20 +339,24 @@ async def test_microsd(): async def start_selftest(): try: + if version.has_qr: + await test_qr_scanner() + if not version.has_qwerty: await test_oled() else: await test_lcd() await test_gpu() + await test_psram() await test_nfc_light() await test_nfc() + if version.has_qwerty: await test_keyboard() else: await test_numpad() - if version.has_qr: - await test_qr_scanner() + await test_secure_element() await test_sd_active() await test_usb_light() @@ -332,9 +364,12 @@ async def start_selftest(): # add more tests here + # last, because required a DC power supply + if version.has_battery: + await test_battery() + settings.set('tested', True) await ux_show_story("Selftest complete", 'PASS') - dis.clear() except (RuntimeError, AssertionError) as e: e = str(e) or problem_file_line(e) diff --git a/unix/variant/sim_battery.py b/unix/variant/sim_battery.py index 3aca31cc..8eb8bc38 100644 --- a/unix/variant/sim_battery.py +++ b/unix/variant/sim_battery.py @@ -2,14 +2,16 @@ # # sim_battery.py - Simulate Q specific code related to batteries. # -import battery +import battery, sys battery.setup_battery = lambda: None battery.setup_adc = lambda: None def mock_get_batt_level(): - return 3.69 + if '--plugged' in sys.argv: + return None + return 3.3 battery.get_batt_level = mock_get_batt_level diff --git a/unix/variant/sim_scanner.py b/unix/variant/sim_scanner.py index 2f0c6a23..e07d5c61 100644 --- a/unix/variant/sim_scanner.py +++ b/unix/variant/sim_scanner.py @@ -12,7 +12,7 @@ DATA_FILE = 'qrdata.txt' class SimulatedQRScanner(QRScanner): def __init__(self): self.setup_done = True - self.version = '4.20' + self.version = 'V2.3.420' self.lock = asyncio.Lock() # returns a Q we append to as results come in self._q = Queue()