Skip to content

Commit

Permalink
Merge pull request #428 from odudex/capture_qr_refactor
Browse files Browse the repository at this point in the history
Capture QR Code - Show Frame Status and Refactor
  • Loading branch information
odudex authored Aug 9, 2024
2 parents d2ab267 + 200dffb commit 068c466
Show file tree
Hide file tree
Showing 28 changed files with 581 additions and 470 deletions.
2 changes: 1 addition & 1 deletion firmware/MaixPy
2 changes: 1 addition & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

[tool.poetry]
name = "krux"
version = "24.09.beta0"
version = "24.09.beta5"
description = "Open-source signing device firmware for Bitcoin"
authors = ["Jeff S <[email protected]>"]

Expand Down
67 changes: 8 additions & 59 deletions src/krux/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,7 @@

import gc
import sensor
import lcd
import board
from .qr import QRPartParser
from .wdt import wdt

OV2640_ID = 0x2642 # Lenses, vertical flip - Bit
OV5642_ID = 0x5642 # Lenses, horizontal flip - Bit
Expand Down Expand Up @@ -176,6 +173,14 @@ def disable_antiglare(self):
sensor.skip_frames()
self.antiglare_enabled = False

def toggle_antiglare(self):
"""Toggles anti-glare mode and returns the new state"""
if self.antiglare_enabled:
self.disable_antiglare()
return False
self.enable_antiglare()
return True

def snapshot(self):
"""Helper to take a customized snapshot from sensor"""
img = sensor.snapshot()
Expand All @@ -193,59 +198,3 @@ def stop_sensor(self):
"""Stops capturing from sensor"""
gc.collect()
sensor.run(0)

def capture_qr_code_loop(self, callback, flipped_x_coordinates=False):
"""Captures either singular or animated QRs and parses their contents until
all parts of the message have been captured. The part data are then ordered
and assembled into one message and returned.
"""
self.initialize_run()

parser = QRPartParser()

prev_parsed_count = 0
new_part = False
while True:
wdt.feed()
command = callback(parser.total_count(), parser.parsed_count(), new_part)
if not self.initialized:
# Ignores first callback as it may contain unintentional events
self.initialized = True
command = 0
if command == 1:
break
new_part = False

img = self.snapshot()
res = img.find_qrcodes()

# different cases of lcd.display to show a progress bar on different devices!
if board.config["type"] == "m5stickv":
img.lens_corr(strength=1.0, zoom=0.56)
lcd.display(img, oft=(0, 0), roi=(68, 52, 185, 135))
elif board.config["type"] == "amigo":
if flipped_x_coordinates:
lcd.display(img, oft=(40, 40))
else:
lcd.display(img, oft=(120, 40)) # X and Y are swapped
elif board.config["type"] == "cube":
lcd.display(img, oft=(0, 0), roi=(0, 0, 224, 240))
else:
lcd.display(img, oft=(0, 0), roi=(0, 0, 304, 240))

if len(res) > 0:
data = res[0].payload()

parser.parse(data)

if parser.processed_parts_count() > prev_parsed_count:
prev_parsed_count = parser.processed_parts_count()
new_part = True

if parser.is_complete():
break
self.stop_sensor()

if parser.is_complete():
return (parser.result(), parser.format)
return (None, None)
2 changes: 1 addition & 1 deletion src/krux/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,5 @@
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
VERSION = "24.09.beta0"
VERSION = "24.09.beta5"
SIGNER_PUBKEY = "03339e883157e45891e61ca9df4cd3bb895ef32d475b8e793559ea10a36766689b"
86 changes: 1 addition & 85 deletions src/krux/pages/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
STATUS_BAR_HEIGHT,
)
from ..qr import to_qr_codes
from ..krux_settings import t, Settings, DefaultWallet
from ..krux_settings import t, Settings
from ..sd_card import SDHandler

MENU_CONTINUE = 0
Expand All @@ -55,7 +55,6 @@
ESC_KEY = 1
FIXED_KEYS = 3 # 'More' key only appears when there are multiple keysets

ANTI_GLARE_WAIT_TIME = 500
SHUTDOWN_WAIT_TIME = 300

TOGGLE_BRIGHTNESS = (BUTTON_PAGE, BUTTON_PAGE_PREV)
Expand Down Expand Up @@ -83,7 +82,6 @@ class Page:
def __init__(self, ctx, menu=None):
self.ctx = ctx
self.menu = menu
self._time_frame = 0
# context has its own keypad mapping in case touch is not used
self.y_keypad_map = []
self.x_keypad_map = []
Expand Down Expand Up @@ -203,88 +201,6 @@ def capture_from_keypad(
self.ctx.input.touch.clear_regions()
return buffer

def capture_qr_code(self):
"""Captures a singular or animated series of QR codes and displays progress to the user.
Returns the contents of the QR code(s).
"""
self._time_frame = time.ticks_ms()

def callback(part_total, num_parts_captured, new_part):
# Turn on the light as long as the enter button is held down (M5stickV and Amigo)
if self.ctx.light:
if self.ctx.input.enter_value() == PRESSED:
self.ctx.light.turn_on()
else:
self.ctx.light.turn_off()
# If board don't have light, ENTER stops the capture
elif self.ctx.input.enter_event():
return 1

# Anti-glare mode
if self.ctx.input.page_event() or (
# Yahboom may have page or page_prev mapped to its single button
board.config["type"] == "yahboom"
and self.ctx.input.page_prev_event()
):
if self.ctx.camera.has_antiglare():
self._time_frame = time.ticks_ms()
self.ctx.display.to_portrait()
if not self.ctx.camera.antiglare_enabled:
self.ctx.camera.enable_antiglare()
self.ctx.display.draw_centered_text(t("Anti-glare enabled"))
else:
self.ctx.camera.disable_antiglare()
self.ctx.display.draw_centered_text(t("Anti-glare disabled"))
time.sleep_ms(ANTI_GLARE_WAIT_TIME)
self.ctx.display.to_landscape()
self.ctx.input.reset_ios_state()
return 0
return 1

# Exit the capture loop with PAGE_PREV or TOUCH
if self.ctx.input.page_prev_event() or self.ctx.input.touch_event():
return 1

# Indicate progress to the user that a new part was captured
if new_part:
self.ctx.display.to_portrait()
filled = self.ctx.display.width() * num_parts_captured
filled //= part_total
if board.config["type"] == "cube":
height = 225
elif self.ctx.display.height() < 320: # M5StickV
height = 210
elif self.ctx.display.height() > 320: # Amigo
height = 380
else:
height = 305
self.ctx.display.fill_rectangle(
0,
height,
filled,
15,
theme.fg_color,
)
self.ctx.display.to_landscape()

return 0

self.ctx.display.clear()
self.ctx.display.draw_centered_text(t("Loading Camera.."))
self.ctx.display.to_landscape()
code = None
qr_format = None
try:
code, qr_format = self.ctx.camera.capture_qr_code_loop(
callback, self.ctx.display.flipped_x_coordinates
)
except:
print("Camera error")
if self.ctx.light:
self.ctx.light.turn_off()
self.ctx.display.to_portrait()
return (code, qr_format)

def display_qr_codes(self, data, qr_format, title=""):
"""Displays a QR code or an animated series of QR codes to the user, encoding them
in the specified format
Expand Down
6 changes: 5 additions & 1 deletion src/krux/pages/encryption_ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,11 @@ def load_key(self):

def load_qr_encryption_key(self):
"""Loads and returns a key from a QR code"""
data, _ = self.capture_qr_code()

from .qr_capture import QRCodeCapture

qr_capture = QRCodeCapture(self.ctx)
data, _ = qr_capture.qr_capture_loop()
if data is None:
self.flash_error(t("Failed to load key"))
return None
Expand Down
5 changes: 4 additions & 1 deletion src/krux/pages/home_pages/addresses.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,10 @@ def pre_scan_address(self):

def scan_address(self, addr_type=0):
"""Handler for the 'receive' or 'change' menu item"""
data, qr_format = self.capture_qr_code()
from ..qr_capture import QRCodeCapture

qr_capture = QRCodeCapture(self.ctx)
data, qr_format = qr_capture.qr_capture_loop()
if data is None or qr_format != FORMAT_NONE:
self.flash_error(t("Failed to load address"))
return MENU_CONTINUE
Expand Down
5 changes: 4 additions & 1 deletion src/krux/pages/home_pages/home.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,10 @@ def load_psbt(self):
return (None, None, "")

if load_method == LOAD_FROM_CAMERA:
data, qr_format = self.capture_qr_code()
from ..qr_capture import QRCodeCapture

qr_capture = QRCodeCapture(self.ctx)
data, qr_format = qr_capture.qr_capture_loop()
return (data, qr_format, "")

# If load_method == LOAD_FROM_SD
Expand Down
5 changes: 4 additions & 1 deletion src/krux/pages/home_pages/sign_message_ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@ def load_message(self):
return (None, None, "")

if load_method == LOAD_FROM_CAMERA:
data, qr_format = self.capture_qr_code()
from ..qr_capture import QRCodeCapture

qr_capture = QRCodeCapture(self.ctx)
data, qr_format = qr_capture.qr_capture_loop()
return (data, qr_format, "")

# If load_method == LOAD_FROM_SD
Expand Down
5 changes: 4 additions & 1 deletion src/krux/pages/home_pages/wallet_descriptor.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,10 @@ def _load_wallet(self):
persisted = False
load_method = self.load_method()
if load_method == LOAD_FROM_CAMERA:
wallet_data, qr_format = self.capture_qr_code()
from ..qr_capture import QRCodeCapture

qr_capture = QRCodeCapture(self.ctx)
wallet_data, qr_format = qr_capture.qr_capture_loop()
elif load_method == LOAD_FROM_SD:
# Try to read the wallet output descriptor from a file on the SD card
qr_format = FORMAT_NONE
Expand Down
5 changes: 4 additions & 1 deletion src/krux/pages/login.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,10 @@ def _encrypted_qr_code(self, data):

def load_key_from_qr_code(self):
"""Handler for the 'via qr code' menu item"""
data, qr_format = self.capture_qr_code()
from .qr_capture import QRCodeCapture

qr_capture = QRCodeCapture(self.ctx)
data, qr_format = qr_capture.qr_capture_loop()
if data is None:
self.flash_error(t("Failed to load mnemonic"))
return MENU_CONTINUE
Expand Down
Loading

0 comments on commit 068c466

Please sign in to comment.