Show QR code when exploring addresses

This commit is contained in:
Peter D. Gray 2019-11-21 11:12:48 -05:00
parent 69fdc4b805
commit 240fc65775
3 changed files with 145 additions and 24 deletions

View File

@ -9,6 +9,7 @@ import chains, stash
from ux import ux_show_story, the_ux, ux_confirm
from actions import goto_top_menu
from menu import MenuSystem, MenuItem, start_chooser
from public_constants import AFC_BECH32
SCREEN_CHAR_WIDTH = const(16)
@ -71,11 +72,13 @@ async def choose_first_address(*a):
async def show_n_addresses(path, addr_fmt, start, n):
# Displays n addresses from start
from main import dis
import version
def make_msg(start):
msg = "Press 1 to save to MicroSD.\n\n"
msg += "Addresses %d..%d:\n\n" % (start, start + n - 1)
addrs = []
chain = chains.current_chain()
dis.fullscreen('Wait...')
@ -85,38 +88,48 @@ async def show_n_addresses(path, addr_fmt, start, n):
for idx in range(start, start + n):
subpath = path.format(account=0, change=0, idx=idx)
node = sv.derive_path(subpath, register=False)
msg += "%s =>\n%s\n\n" % (subpath, chain.address(node, addr_fmt))
addr = chain.address(node, addr_fmt)
addrs.append(addr)
msg += "%s =>\n%s\n\n" % (subpath, addr)
dis.progress_bar_show(idx/n)
stash.blank_object(node)
if version.has_fatram:
msg += "Press 4 to view QR Code. "
msg += "Press 9 to see next group, 7 to go back. X to quit."
return msg
return msg, addrs
msg = make_msg(start)
msg, addrs = make_msg(start)
while 1:
ch = await ux_show_story(msg, escape='179')
ch = await ux_show_story(msg, escape='1479')
if ch == '1':
# save addresses to MicroSD signal
await make_address_summary_file(path, addr_fmt)
# .. continue on same screen in case they want to write to multiple cards
if ch == '1':
# save addresses to MicroSD signal
await make_address_summary_file(path, addr_fmt)
# .. continue on same screen in case they want to write to multiple cards
if ch == 'x':
return
if ch == 'x':
return
if ch == '7' and start>0:
# go backwards in explorer
start -= n
msg = make_msg(start)
if ch == '4':
if not version.has_fatram: continue
await show_address_qr(addrs, (addr_fmt & AFC_BECH32), start)
continue
if ch == '9':
# go forwards
start += n
msg = make_msg(start)
if ch == '7' and start>0:
# go backwards in explorer
start -= n
elif ch == '9':
# go forwards
start += n
msg, addrs = make_msg(start)
def generate_address_csv(path, addr_fmt, n):
# Produce CSV file contents as a generator
@ -200,4 +213,106 @@ Press 4 to start.''', escape='4')
await show_n_addresses(path, addr_fmt, 0, 10)
async def show_address_qr(addrs, is_segwit, start_n):
# show a QR code for the address. can only work on Mk3
# Version 2 would be nice, but can't hold what we need, even at min error correction,
# so we are forced into version 3 = 29x29 pixels
# - see <https://www.qrcode.com/en/about/version.html>
# - to display 29x29 pixels, we have to double them up: 58x58
# - not really providing enough space around it
# - inverted QR (black/white swap) still readable by scanners, altho wrong
from utils import imported
from display import FontSmall, FontTiny
import uQR as uqr
from main import dis
idx = 0 # start with first address
invert = False # looks better, but neither mode is ideal
addr = addrs[idx]
def render(addr):
dis.busy_bar(True)
with imported('uQR') as uqr:
if is_segwit:
# targeting 'alpha numeric' mode, typical len is 42
ec = uqr.ERROR_CORRECT_Q
assert len(addr) <= 47
else:
# has to be 'binary' mode, altho shorter msg, typical 34-36
ec = uqr.ERROR_CORRECT_M
assert len(addr) <= 42
q = uqr.QRCode(version=3, box_size=1, border=0, mask_pattern=3, error_correction=ec)
if is_segwit:
here = uqr.QRData(addr.upper().encode('ascii'),
mode=uqr.MODE_ALPHA_NUM, check_data=False)
else:
here = uqr.QRData(addr.encode('ascii'), mode=uqr.MODE_8BIT_BYTE, check_data=False)
q.add_data(here)
q.make(fit=False)
return q.get_matrix()
data = render(addr)
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
redraw()
from ux import ux_wait_keyup
while 1:
ch = await ux_wait_keyup()
if ch == '1':
invert = not invert
redraw()
continue
elif ch in 'xy':
return
if ch == '5' or ch == '7':
if idx > 0:
idx -= 1
elif ch == '8' or ch == '9':
if idx != len(addrs)-1:
idx += 1
addr = addrs[idx]
data = render(addr)
redraw()
# EOF

View File

@ -1,4 +1,7 @@
# from https://github.com/JASchilz/uQR/blob/master/uQR.py @ 0d105634841368ef0b1bb210a63c48e4b50a9a94
#
# Please see <https://github.com/JASchilz/uQR/blob/master/LICENSE> for BSD-style license.
#
import ure as re
"""
@ -17,10 +20,10 @@ Formerly in constants.py
"""
# QR error correct levels
ERROR_CORRECT_L = 1
ERROR_CORRECT_M = 0
ERROR_CORRECT_Q = 3
ERROR_CORRECT_H = 2
ERROR_CORRECT_L = const(1)
ERROR_CORRECT_M = const(0)
ERROR_CORRECT_Q = const(3)
ERROR_CORRECT_H = const(2)
"""
LUT
@ -1022,7 +1025,7 @@ def create_data(version, error_correction, data_list):
bit_limit += block.data_count * 8
if len(buffer) > bit_limit:
raise exceptions.DataOverflowError(
raise DataOverflowError(
"Code length overflow. Data size (%s) > size available (%s)" %
(len(buffer), bit_limit))

View File

@ -18,15 +18,17 @@ if '-s' in sys.argv:
numpad.inject('4')
numpad.inject('y')
if '-a' in sys.argv:
if '--addr' in sys.argv:
# Address Explorer
from main import numpad
numpad.inject('4')
numpad.inject('y')
numpad.inject('4')
numpad.inject('8')
numpad.inject('8')
numpad.inject('y')
numpad.inject('y')
numpad.inject('4') # skips warning!
if '--dz' in sys.argv:
# Enter the "Danger Zone"
@ -36,6 +38,7 @@ if '--dz' in sys.argv:
numpad.inject('4')
numpad.inject('8')
numpad.inject('8')
numpad.inject('8')
numpad.inject('y')
if '--xw' in sys.argv: