Example #1
0
    def show_pin_randomized(self, force_draw):
        # screen redraw, when we are "randomized"

        if force_draw:
            dis.clear()

            # prompt
            dis.text(5+3, 2, "ENTER PIN")
            dis.text(5+6, 17, ('1st part' if not self.pin_prefix else '2nd part'))

            # remapped keypad
            y = 2
            x = 89
            h = 16
            for i in range(0, 10, 3):
                if i == 9:
                    dis.text(x, y, '  %s' % self.randomize[0])
                else:
                    dis.text(x, y, ' '.join(self.randomize[1+i:1+i+3]))
                y += h
        else:
            # just clear what we need to: the PIN area
            dis.clear_rect(0, 40, 88, 20)

        # placeholder text
        msg = '[' + ('*'*len(self.pin)) + ']'
        x = 40 - ((10*len(msg))//2)
        dis.text(x, 40, msg, FontLarge)

        dis.show()
Example #2
0
    def draw_busy(self, msg, percent):
        from display import FontTiny
        from main import dis

        self.last_percent = 0.5

        # centered in bottom part of screen.
        y = 48

        if percent is not None:
            self.percent = percent

            # reset display once we're at 100%
            if percent >= 0.995:            # ~ last pixel
                self.percent = None
                self.busy_text = msg = None

        if msg is not None:
            self.busy_text = msg

        if self.busy_text is not None:
            # clear under it
            dis.clear_rect(0,y, 128, 64-y)
            dis.text(None, y, self.busy_text)

        if self.percent is not None:
            x = int(128 * self.percent)
            dis.dis.hline(0, 63, x, 1)
            dis.dis.hline(x+1, 63, 127, 0)

        dis.show()
Example #3
0
    async def wait_til_state(want):
        dis.clear()
        dis.text(None, 10, 'MicroSD Card:')
        dis.text(None, 34, 'Remove' if sd.present() else 'Insert', font=FontLarge)
        dis.show()

        while 1:
            if want == sd.present(): return
            await sleep_ms(100)
            if ux_poll_once():
                raise RuntimeError("MicroSD test aborted")
Example #4
0
async def test_oled():
    # all on/off tests
    for ph in (1, 0):
        dis.clear()
        dis.dis.fill(ph)
        dis.text(None,2, "Selftest", invert=ph)
        dis.text(None,30, "All on?" if ph else 'All off?', invert=ph, font=FontLarge)
        dis.show()

        ch = await ux_wait_keyup('yx')
        if ch != 'y':
            raise RuntimeError("OLED test aborted")
Example #5
0
async def ux_enter_number(prompt, max_value):
    # return the decimal number which the user has entered
    # - default/blank value assumed to be zero
    # - clamps large values to the max
    from main import dis
    from display import FontTiny
    from math import log

    # allow key repeat on X only
    press = PressRelease('1234567890y')

    y = 26
    value = ''
    max_w = int(log(max_value, 10) + 1)

    dis.clear()
    dis.text(0, 0, prompt)
    dis.text(None, -1, "X to DELETE, or OK when DONE.", FontTiny)
    dis.save()

    while 1:
        dis.restore()

        # text centered
        if value:
            bx = dis.text(None, y, value)
            dis.icon(bx + 1, y + 11, 'space')
        else:
            dis.icon(64 - 7, y + 11, 'space')

        dis.show()

        ch = await press.wait()
        if ch == 'y':

            if not value: return 0
            return min(max_value, int(value))

        elif ch == 'x':
            if value:
                value = value[0:-1]
            else:
                # quit if they press X on empty screen
                return 0
        else:
            if len(value) == max_w:
                value = value[0:-1] + ch
            else:
                value += ch

            # cleanup leading zeros and such
            value = str(int(value))
Example #6
0
    def show_pin(self, show_hint=False):
        filled = len(self.pin)
        if show_hint:
            filled -= 1
            hint = self.pin[-1] if not version.has_membrane else None

        dis.clear()

        if not self.pin_prefix:
            prompt="Enter PIN Prefix" 
        else:
            prompt="Enter rest of PIN" 


        if self.subtitle:
            dis.text(None, 0, self.subtitle)
            dis.text(None, 16, prompt, FontTiny)
        else:
            dis.text(None, 4, prompt)

        y = 27
        w = 18
        x = 12

        for idx in range(filled):
            dis.icon(x, y, 'xbox')
            x += w

        if show_hint:
            if not version.has_membrane:
                dis.text(x+1, y+1, hint, FontLarge)
                dis.icon(x, y, 'box')
            else:
                dis.icon(x, y, 'tbox')
        else:
            if len(self.pin) != MAX_PIN_PART_LEN:
                dis.icon(x, y, 'box')

        # BTW: √ also works here, but looks like square root, not a checkmark
        if self.footer:
            footer = self.footer
        elif self.is_repeat:
            footer = "CONFIRM PIN VALUE"
        elif not self.pin_prefix:
            footer = "X to CANCEL, or OK when DONE"
        else:
            footer = "X to CANCEL, or OK to CONTINUE"

        dis.text(None, -1, footer, FontTiny)

        dis.show()
    def redraw():
        dis.clear()

        w = 29  # because version=3
        XO, YO = 7, 3  # offsets

        if not invert:
            dis.dis.fill_rect(XO - YO, 0, 64, 64, 1)

        for x in range(w):
            for y in range(w):
                px = data[x][y]
                X = (x * 2) + XO
                Y = (y * 2) + YO
                dis.dis.fill_rect(X, Y, 2, 2, px if invert else (not px))

        x, y = 73, 0 if is_segwit else 2
        ll = 7  # per line
        for i in range(0, len(addr), ll):
            dis.text(x, y, addr[i:i + ll], FontSmall)
            y += 10 if is_segwit else 12

        if not invert:
            # show path number, very tiny
            ai = str(start_n + idx)
            if len(ai) == 1:
                dis.text(0, 30, ai[0], FontTiny)
            else:
                dis.text(0, 27, ai[0], FontTiny)
                dis.text(0, 27 + 7, ai[1], FontTiny)

        dis.busy_bar(False)  # includes show
Example #8
0
async def test_numpad():
    # do an interactive self test

    keys = list('123456789x0y')

    for ch in keys:
        dis.clear()
        dis.text(0,0, "Numpad Test. Press:")
        dis.text(None,24, ch if ch != 'y' else 'OK', FontLarge)
        dis.show()

        k = await ux_wait_keyup(ch + 'x')
        if k == 'x' and ch != 'x':
            raise RuntimeError("numpad test aborted")
        assert k == ch
Example #9
0
    def show_pin(self, show_hint=False):
        filled = len(self.pin)
        if show_hint:
            filled -= 1
            hint = self.pin[-1]
        else:
            hint = '' if len(self.pin) == MAX_PIN_PART_LEN else ' '

        dis.clear()

        if not self.pin_prefix:
            prompt="Enter PIN Prefix" 
        else:
            prompt="Enter rest of PIN" 


        if self.subtitle:
            dis.text(None, 0, self.subtitle)
            dis.text(None, 16, prompt, FontTiny)
        else:
            dis.text(None, 4, prompt)

        y = 26
        w = 18
        if 0:
            x = 64 - ((w * (filled+(1 if hint else 0))) // 2)
            x += w//2
        else:
            x = 12

        for idx in range(filled):
            dis.icon(x, y, 'xbox')
            x += w
        if hint:
            dis.text(x+1, y+1, hint, FontLarge)
            dis.icon(x, y, 'box')

        # BTW: √ also works here, but looks like square root, not a checkmark
        if self.is_repeat:
            footer = "CONFIRM PIN VALUE"
        elif not self.pin_prefix:
            footer = "X to CANCEL, or OK when DONE."
        else:
            footer = "X to CANCEL, or OK to CONTINUE."

        dis.text(None, -1, footer, FontTiny)

        dis.show()
Example #10
0
async def show_nickname(nick):
    # Show a nickname for this coldcard (as a personalization)
    # - no keys here, just show it until they press anything
    from main import dis
    from display import FontLarge, FontTiny, FontSmall
    from ux import ux_wait_keyup

    dis.clear()

    if dis.width(nick, FontLarge) <= dis.WIDTH:
        dis.text(None, 21, nick, font=FontLarge)
    else:
        dis.text(None, 27, nick, font=FontSmall)

    dis.show()

    await ux_wait_keyup()
Example #11
0
    def show(self):
        from main import dis, hsm_active

        # Plan: show "time til period reset", and some stats,
        # but never show amounts or private info.

        dis.dis.buffer[:] = self.screen_buf[:]

        left = hsm_active.get_time_left()
        if left is None:
            left = ' n/a'
        elif left == -1:
            left = ' --'
        else:
            left = period_display(left)

        # 3 statistics; see draw_background for X positions
        y = 28+1
        for x, val in [ (14, str(hsm_active.approvals)),
                        (51, str(hsm_active.refusals)),
                        (98, left)]:
            tw = 7*len(val)     # = dis.width(val, FontSmall)
            dis.text(x - tw//2, y, val)

        # heartbeat display
        if 1:
            #self.phase = (utime.ticks_ms() // 50) % len(cylon)
            self.phase = (self.phase + 1) % len(cylon)
            x = cylon[self.phase]
            w = 12
            dis.dis.line(x, 63, x+w-1, 63, True)

        if self.digits:
            # UX "feedback" for digits
            if len(self.digits) < 6:
                msg = self.digits + ('#' * (6-len(self.digits)))
            elif self.digits:
                msg = self.digits

            # dis.width('######', FontSmall) == 42
            x, y, w, h = 80, 0, 42, 14
            dis.clear_rect(x,y, x+w, y+h)
            dis.text(x, y, msg)

        # contains a dis.show()
        self.draw_busy(None, None)
Example #12
0
async def test_sflash():
    dis.clear()
    dis.text(None, 18, 'Serial Flash')
    dis.show()

    #if ckcc.is_simulator(): return

    from main import sf
    from ustruct import pack
    import tcc

    msize = 1024 * 1024
    sf.chip_erase()

    for phase in [0, 1]:
        steps = 7 * 4
        for i in range(steps):
            dis.progress_bar(i / steps)
            dis.show()
            await sleep_ms(250)
            if not sf.is_busy(): break

        assert not sf.is_busy(), "sflash erase didn't finish"

        # leave chip blank
        if phase == 1: break

        buf = bytearray(32)
        for addr in range(0, msize, 1024):
            sf.read(addr, buf)
            assert set(buf) == {255}, "sflash not blank:" + repr(buf)

            rnd = tcc.sha256(pack('I', addr)).digest()
            sf.write(addr, rnd)
            sf.read(addr, buf)
            assert buf == rnd, "sflash write failed"

            dis.progress_bar_show(addr / msize)

        # check no aliasing, also right size part
        for addr in range(0, msize, 1024):
            expect = tcc.sha256(pack('I', addr)).digest()
            sf.read(addr, buf)
            assert buf == expect, "sflash readback failed"

            dis.progress_bar_show(addr / msize)
Example #13
0
async def test_sd_active():
    # Mark 2: SD Card active light.
    from machine import Pin
    led = Pin('SD_ACTIVE', Pin.OUT)

    for ph in range(2):
        gg = not ph
        led.value(gg)

        dis.clear()
        if gg:
            dis.text(0,16, "<-- Green ON?")
        else:
            dis.text(0,16, "<-- Green off?")

        dis.show()
        k = await ux_wait_keyup('xy')
        assert k == 'y'     # "SD Active LED bust"
Example #14
0
def show_fatal_error(msg):
    # show a multi-line error message, over some kinda "fatal" banner
    from main import dis
    from display import FontTiny

    dis.clear()
    lines = msg.split('\n')[-6:]
    dis.text(None, 1, '>>>> Yikes!! <<<<')

    y = 13 + 2
    for num, ln in enumerate(lines):
        ln = ln.strip()

        if ln[0:6] == 'File "':
            # convert: File "main.py", line 63, in interact
            #    into: main.py:63  interact
            ln = ln[6:].replace('", line ', ':').replace(', in ', '  ')

        dis.text(0, y + (num * 8), ln, FontTiny)

    dis.show()
Example #15
0
    def _show_words(self, has_secondary=False):

        dis.clear()
        dis.text(None, 0, "Recognize these?" if (not self.is_setting) or self.is_repeat \
                            else "Write these down:")

        dis.show()
        dis.busy_bar(True)
        words = pincodes.PinAttempt.prefix_words(self.pin.encode())

        y = 15
        x = 18
        dis.text(x, y,    words[0], FontLarge)
        dis.text(x, y+18, words[1], FontLarge)

        if self.offer_second:
            dis.text(None, -1, "Press (2) for secondary wallet", FontTiny)
        else:
            dis.text(None, -1, "X to CANCEL, or OK to CONTINUE", FontTiny)

        dis.busy_bar(False)     # includes a dis.show()
Example #16
0
async def login_countdown(minutes):
    # show a countdown, which may need to
    # run for multiple **days**
    from main import dis
    from display import FontSmall, FontLarge

    sec = minutes * 60
    while sec:
        dis.clear()
        y = 0
        dis.text(None, y, 'Login countdown in', font=FontSmall); y += 14
        dis.text(None, y, 'effect. Must wait:', font=FontSmall); y += 14
        y += 5

        dis.text(None, y, pretty_short_delay(sec), font=FontLarge)

        dis.show()
        dis.busy_bar(1)

        # XXX this should be more accurate, errors are accumulating
        await sleep_ms(1000)

        sec -= 1

    dis.busy_bar(0)
Example #17
0
    def show_pin(self, force_draw=False):
        if self.randomize:
            return self.show_pin_randomized(force_draw)

        filled = len(self.pin)
        y = 27

        if force_draw:
            dis.clear()

            if not self.pin_prefix:
                prompt="Enter PIN Prefix" 
            else:
                prompt="Enter rest of PIN" 


            if self.subtitle:
                dis.text(None, 0, self.subtitle)
                dis.text(None, 16, prompt, FontTiny)
            else:
                dis.text(None, 4, prompt)

            if self.footer:
                footer = self.footer
            elif self.is_repeat:
                footer = "CONFIRM PIN VALUE"
            elif not self.pin_prefix:
                footer = "X to CANCEL, or OK when DONE"
            else:
                footer = "X to CANCEL, or OK to CONTINUE"

            dis.text(None, -1, footer, FontTiny)

        else:
            # just clear what we need to: the PIN area
            dis.clear_rect(0, y, 128, 21)

        w = 18

        # extra (empty) box after
        if not filled:
            dis.icon(64-(w//2), y, 'box')
        else:
            x = 64 - ((w*filled)//2)
            # filled boxes
            for idx in range(filled):
                dis.icon(x, y, 'xbox')
                x += w

        dis.show()
Example #18
0
async def test_ae508a():

    assert not get_is_bricked(), "AE508a is bricked"

    for ph in range(5):
        gg = get_genuine()

        dis.clear()
        if gg:
            dis.text(-1, 8, "Green ON? -->")
        else:
            dis.text(-1, 50, "Red ON? -->")

        dis.show()
        k = await ux_wait_keyup('xy')
        assert k == 'y', "LED bust"

        if ph and gg:
            # stop once it's on and we've tested both states
            return

        # attempt to switch to other state
        if gg:
            clear_genuine()
        else:
            # very slow!
            dis.text(0, 0, "Wait")
            dis.show()
            set_genuine()
            ux_clear_keys()

        ng = get_genuine()
        assert ng != gg, "Could not invert LED"
Example #19
0
async def login_countdown(minutes):
    # show a countdown, which may need to
    # run for multiple **days**
    from main import dis
    from display import FontSmall, FontLarge

    sec = minutes * 60
    while sec:
        dis.clear()
        y = 0
        dis.text(None, y, 'Login countdown in', font=FontSmall)
        y += 14
        dis.text(None, y, 'effect. Must wait:', font=FontSmall)
        y += 14
        y += 5

        if sec >= 3600:
            msg = '%2dh %2dm %2ds' % (sec // 3600, (sec // 60) % 60, sec % 60)
        else:
            msg = '%2dm %2ds' % ((sec // 60) % 60, sec % 60)

        dis.text(None, y, msg, font=FontLarge)

        dis.show()
        dis.busy_bar(1)
        await sleep_ms(1000)

        sec -= 1

    dis.busy_bar(0)
Example #20
0
    def show(self):
        #
        # Redraw the menu.
        #
        dis.clear()

        #print('cur=%d ypos=%d' % (self.cursor, self.ypos))

        # subclass hook
        self.early_draw(dis)

        x, y = (10, 2)
        h = 14
        for n in range(self.ypos + PER_M + 1):
            if n + self.ypos >= self.count: break
            msg = self.items[n + self.ypos].label
            is_sel = (self.cursor == n + self.ypos)
            if is_sel:
                dis.dis.fill_rect(0, y, 128, h - 1, 1)
                dis.icon(2, y, 'wedge', invert=1)
                dis.text(x, y, msg, invert=1)
            else:
                dis.text(x, y, msg)

            if msg[0] == ' ' and self.space_indicators:
                dis.icon(x - 2, y + 11, 'space', invert=is_sel)

            if self.chosen is not None and (n + self.ypos) == self.chosen:
                dis.icon(108, y, 'selected', invert=is_sel)

            y += h
            if y > 128: break

        # subclass hook
        self.late_draw(dis)

        if self.count > PER_M:
            dis.scroll_bar(self.ypos / (self.count - PER_M))

        dis.show()
Example #21
0
    def draw_background(self):
        # Render and capture static parts of screen one-time.
        from main import dis
        from display import FontTiny

        dis.clear()
        dis.text(6, 0, "HSM MODE")
        dis.show() # cover the 300ms or so it takes to draw the rest below

        dis.hline(15)

        x, y = 0, 28
        for lab, xoff, val in [ 
            ('APPROVED', 0, '0'),
            ('REFUSED', 0, '0'),
            ('PERIOD LEFT', 5, 'xx'),
        ]:
            nx = dis.text(x+xoff, y-7, lab, FontTiny)
            hw = nx - x
            if lab == 'REFUSED':
                dis.dis.line(nx+2, 0, nx+2, y+16, 1)
            else:
                if not xoff:
                    dis.dis.line(nx+2, y-12, nx+2, y+16, 1)

            # keep this:
            #print('%s @ x=%d' % (lab, x+(hw//2)-2))

            # was:
            #tw = 7*len(val)     # = dis.width(val, FontSmall)
            #dis.text(x+((hw-tw)//2)-1, y+1, val)
            x = nx + 7

        dis.hline(y+17)

        # no local confirmation code entered, typically
        dis.text(80, 0, '######')

        # save this static background
        self.screen_buf = dis.dis.buffer[:]
Example #22
0
    def show_pin(self, show_hint=False):
        if self.randomize:
            return self.show_pin_randomized()

        filled = len(self.pin)
        if show_hint:
            filled -= 1
            hint = None     # used to be: self.pin[-1]  (for Mk1)

        dis.clear()

        if not self.pin_prefix:
            prompt="Enter PIN Prefix" 
        else:
            prompt="Enter rest of PIN" 


        if self.subtitle:
            dis.text(None, 0, self.subtitle)
            dis.text(None, 16, prompt, FontTiny)
        else:
            dis.text(None, 4, prompt)

        y = 27
        w = 18
        x = 12

        for idx in range(filled):
            dis.icon(x, y, 'xbox')
            x += w

        if show_hint:
            dis.icon(x, y, 'tbox')
        else:
            if len(self.pin) != MAX_PIN_PART_LEN:
                dis.icon(x, y, 'box')

        if self.footer:
            footer = self.footer
        elif self.is_repeat:
            footer = "CONFIRM PIN VALUE"
        elif not self.pin_prefix:
            footer = "X to CANCEL, or OK when DONE"
        else:
            footer = "X to CANCEL, or OK to CONTINUE"

        dis.text(None, -1, footer, FontTiny)

        dis.show()
Example #23
0
    def show_words(self, words, has_secondary=False):

        dis.clear()
        dis.text(None, 0, "Recognize these?" if (not self.is_setting) or self.is_repeat \
                            else "Write these down:")

        y = 15
        x = 18
        dis.text(x, y,    words[0], FontLarge)
        dis.text(x, y+18, words[1], FontLarge)

        if not self.is_setting:
            dis.text(None, -1, "Press (2) for secondary wallet", FontTiny)

        dis.show()
Example #24
0
    def redraw(self):
        # Redraw screen.
        from main import dis
        from display import FontSmall, FontTiny

        # what we are showing inside the QR
        msg = self.addrs[self.idx]

        # make the QR, if needed.
        if not self.qr_data:
            dis.busy_bar(True)

            self.render_qr(msg)

        # draw display
        dis.clear()

        w = 29  # because version=3
        XO, YO = 7, 3  # offsets

        if not self.invert:
            dis.dis.fill_rect(XO - YO, 0, 64, 64, 1)

        data = self.qr_data
        inv = self.invert
        for x in range(w):
            for y in range(w):
                px = data[x][y]
                X = (x * 2) + XO
                Y = (y * 2) + YO
                dis.dis.fill_rect(X, Y, 2, 2, px if inv else (not px))

        x, y = 73, 0 if self.is_alnum else 2
        sidebar, ll = self.sidebar or (msg, 7)
        for i in range(0, len(sidebar), ll):
            dis.text(x, y, sidebar[i:i + ll], FontSmall)
            y += 10 if self.is_alnum else 12

        if not inv and len(self.addrs) > 1:
            # show path number, very tiny
            ai = str(self.start_n + self.idx)
            if len(ai) == 1:
                dis.text(0, 30, ai[0], FontTiny)
            else:
                dis.text(0, 27, ai[0], FontTiny)
                dis.text(0, 27 + 7, ai[1], FontTiny)

        dis.busy_bar(False)  # includes show
Example #25
0
    def _show_words(self, has_secondary=False):

        dis.clear()
        dis.text(None, 0, "Recognize these?" if (not self.is_setting) or self.is_repeat \
                            else "Write these down:")

        if not self.is_setting:
            dis.text(None, -1, "Press (2) for secondary wallet", FontTiny)

        dis.show()
        words = pincodes.PinAttempt.prefix_words(self.pin.encode())

        y = 15
        x = 18
        dis.text(x, y,    words[0], FontLarge)
        dis.text(x, y+18, words[1], FontLarge)

        dis.show()
Example #26
0
async def test_multipress():
    dis.clear()
    dis.text(None, 10, 'Welcome', font=FontLarge)
    dis.show()

    while 1:
        pr = await numpad.get()
        dis.clear()
        dis.text(None, 20, 'Pressed', font=FontSmall)
        dis.text(None, 35, pr, font=FontLarge)
        dis.show()
Example #27
0
    async def add_numbers(self, *a):
        # collect a series of digits
        from main import dis
        from display import FontTiny, FontSmall
        global pp_sofar

        # allow key repeat on X only
        press = PressRelease('1234567890y')

        footer = "X to DELETE, or OK when DONE."
        lx = 6
        y = 16
        here = ''

        dis.clear()
        dis.text(None, -1, footer, FontTiny)
        dis.save()

        while 1:
            dis.restore()

            # text centered
            msg = here
            by = y
            bx = dis.text(lx, y, msg[0:16])
            dis.text(lx, y - 9,
                     str(pp_sofar, 'ascii').replace(' ', '_'), FontTiny)

            if len(msg) > 16:
                # second line when needed (left just)
                by += 15
                bx = dis.text(lx, by, msg[16:])

            if len(here) < 32:
                dis.icon(bx, by - 2, 'sm_box')

            dis.show()

            ch = await press.wait()
            if ch == 'y':
                pp_sofar += here
                self.check_length()
                return
            elif ch == 'x':
                if here:
                    here = here[0:-1]
                else:
                    # quit if they press X on empty screen
                    return
            else:
                if len(here) < 32:
                    here += ch
Example #28
0
    async def do_delay(self, pa):
        # show # of failures and implement the delay, which could be 
        # very long.
        dis.clear()
        dis.text(None, 0, "Checking...", FontLarge)
        dis.text(None, 24, 'Wait '+pretty_delay(pa.delay_required * pa.seconds_per_tick))
        dis.text(None, 40, "(%d failures)" % pa.num_fails)

        while pa.is_delay_needed():
            dis.progress_bar(pa.delay_achieved / pa.delay_required)
            dis.show()

            pa.delay()
Example #29
0
async def test_secure_element():

    assert not get_is_bricked()         # bricked already

    # test right chips installed
    is_fat = ckcc.is_stm32l496()
    if is_fat:
        assert version.has_608          # expect 608a
        assert version.hw_label == 'mk3'
    else:
        assert not version.has_608      # expect 508a
        assert version.hw_label != 'mk3'

    if ckcc.is_simulator(): return

    for ph in range(5):
        gg = get_genuine()

        dis.clear()
        if gg:
            dis.text(-1, 8, "Green ON? -->")
        else:
            dis.text(-1,50, "Red ON? -->")

        dis.show()
        k = await ux_wait_keyup('xy')
        assert k == 'y'     # "LED bust"

        if ph and gg:
            # stop once it's on and we've tested both states
            return

        # attempt to switch to other state
        if gg:
            clear_genuine()
        else:
            # very slow!
            dis.text(0,0, "Wait")
            dis.show()
            set_genuine()
            ux_clear_keys()

        ng = get_genuine()
        assert ng != gg     # "Could not invert LED"
Example #30
0
    async def do_delay(self, pa):
        # show # of failures and implement the delay, which could be 
        # very long.
        from main import numpad

        dis.clear()
        dis.text(None, 0, "Checking...", FontLarge)
        dis.text(None, 24, 'Wait '+pretty_delay(pa.delay_required * pa.seconds_per_tick))
        dis.text(None, 40, "(%d failures)" % pa.num_fails)

        # save a little bit of interrupt load/overhead
        numpad.stop()

        while pa.is_delay_needed():
            dis.progress_bar(pa.delay_achieved / pa.delay_required)
            dis.show()

            pa.delay()

        numpad.start()