summaryrefslogtreecommitdiff
path: root/source/ui/DebugMenu.mc
diff options
context:
space:
mode:
Diffstat (limited to 'source/ui/DebugMenu.mc')
-rw-r--r--source/ui/DebugMenu.mc110
1 files changed, 110 insertions, 0 deletions
diff --git a/source/ui/DebugMenu.mc b/source/ui/DebugMenu.mc
new file mode 100644
index 0000000..f1ab407
--- /dev/null
+++ b/source/ui/DebugMenu.mc
@@ -0,0 +1,110 @@
+// Author: cirakg & claude ai
+// Summary: Debug-only menu items: load demo entries, the performance overlay and the on-watch benchmark.
+//
+// Release builds compile the empty (:release) module instead, so none of this
+// reaches the Store build. The benchmark is how the watch's real speed gets
+// measured (docs/PERFORMANCE.md): sideload a debug build and run it.
+
+import Toybox.Lang;
+import Toybox.System;
+import Toybox.Timer;
+import Toybox.WatchUi;
+
+(:debug)
+module DebugMenu {
+
+ function addItems(menu as WatchUi.Menu2) as Void {
+ menu.addItem(new WatchUi.MenuItem("Debug: demo entries", "Adds fake entries", :debugDemo, null));
+ menu.addItem(new WatchUi.MenuItem("Debug: overlay", Diag.overlayOn ? "On" : "Off", :debugOverlay, null));
+ menu.addItem(new WatchUi.MenuItem("Debug: benchmark", "Takes a few seconds", :debugBench, null));
+ }
+
+ function handle(id as Object?) as Void {
+ if (id == :debugDemo) {
+ try {
+ Fixtures.load(AppState.theVault());
+ } catch (e instanceof VaultError) {
+ // Entry cap or full store: load what fits.
+ }
+ AppState.theCodes().clear();
+ WatchUi.popView(WatchUi.SLIDE_DOWN);
+ } else if (id == :debugOverlay) {
+ Diag.overlayOn = !Diag.overlayOn;
+ WatchUi.popView(WatchUi.SLIDE_DOWN);
+ } else if (id == :debugBench) {
+ var runner = new BenchRunner();
+ bench = runner;
+ WatchUi.switchToView(new InfoView("Benchmark", ["Measuring…"], "bench_running"), new InfoDelegate(),
+ WatchUi.SLIDE_LEFT);
+ runner.start();
+ }
+ }
+
+ // The running benchmark (kept so its timer isn't collected).
+ var bench as BenchRunner? = null;
+
+ // Times the operations the budgets depend on, one per timer event, so no
+ // event comes near the watchdog limit (it is enforced on the watch and in
+ // normal simulator runs).
+ class BenchRunner {
+
+ private var _lines as Array<String> = [] as Array<String>;
+ private var _step as Number = 0;
+ private var _timer as Timer.Timer? = null;
+
+ function initialize() {
+ }
+
+ function start() as Void {
+ var t = new Timer.Timer();
+ t.start(method(:tick), 200, true);
+ _timer = t;
+ }
+
+ function tick() as Void {
+ var t = System.getTimer();
+ if (_step == 0) {
+ for (var i = 0; i < 5; i++) {
+ Otp.totp(Hashes.SHA1, new [20]b, 1800000000l, 30, 6);
+ }
+ _lines.add("TOTP SHA-1: " + (System.getTimer() - t) / 5 + " ms");
+ } else if (_step == 1) {
+ Otp.totp(Hashes.SHA512, new [64]b, 1800000000l, 30, 6);
+ _lines.add("TOTP SHA-512: " + (System.getTimer() - t) + " ms");
+ } else if (_step == 2) {
+ _lines.add("PIN derivation: " + Kdf.calibrate(1000, Kdf.ITERATIONS_PER_STEP) + " iterations per second");
+ } else if (_step == 3) {
+ var vault = AppState.theVault();
+ var ids = vault.ids();
+ for (var i = 0; i < ids.size(); i++) {
+ vault.header(ids[i]);
+ }
+ _lines.add("Headers: " + ids.size() + " in " + (System.getTimer() - t) + " ms");
+ } else if (_step == 4) {
+ SelfTest.run();
+ _lines.add("Self-test: " + (System.getTimer() - t) + " ms");
+ } else {
+ var stats = System.getSystemStats();
+ _lines.add("Memory: " + stats.usedMemory / 1024 + " of " + stats.totalMemory / 1024 + " KB");
+ var timer = _timer;
+ if (timer != null) {
+ timer.stop();
+ }
+ bench = null;
+ WatchUi.switchToView(new InfoView("Benchmark", _lines, "bench"), new InfoDelegate(), WatchUi.SLIDE_IMMEDIATE);
+ return;
+ }
+ _step++;
+ }
+ }
+}
+
+(:release)
+module DebugMenu {
+
+ function addItems(menu as WatchUi.Menu2) as Void {
+ }
+
+ function handle(id as Object?) as Void {
+ }
+}