summaryrefslogtreecommitdiff
path: root/source/codes/Codes.mc
diff options
context:
space:
mode:
authorcirakg <cirakg@cirakg.xyz>2026-10-25 14:17:45 +0100
committercirakg <cirakg@cirakg.xyz>2026-10-25 14:17:45 +0100
commit140a6660f63f88d05ba9aae0bf1c4b401bb6574d (patch)
tree943cbc93931e7ecabd979895ee29440a2c81c552 /source/codes/Codes.mc
parent67e7ce3d496c34a30ff498eaff2074543350318a (diff)
fix(codes): encoding progress follows the work
The QR percentage counted phases and the display froze at 90 % once encoding ended, so the first opening sat at 90 % while the slow stages ran. Each 2D symbology now weights its phases by measured cost, interpolates inside the long ones, and the display splits encode, pack and runs; a cached code counts its runs from 0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'source/codes/Codes.mc')
-rw-r--r--source/codes/Codes.mc72
1 files changed, 69 insertions, 3 deletions
diff --git a/source/codes/Codes.mc b/source/codes/Codes.mc
index 247acfa..9527a75 100644
--- a/source/codes/Codes.mc
+++ b/source/codes/Codes.mc
@@ -7,6 +7,7 @@
// come back as a CodeError with a message for the user, never an exception.
import Toybox.Lang;
+import Toybox.System;
module Codes {
@@ -174,6 +175,12 @@ module Codes {
result[6] = matrix.rowHeight;
}
+ // Progress 0-99 through the bytes.
+ function percent() as Number {
+ var full = _matrix.modules.size() / 8;
+ return full > 0 ? 99 * _i / full : 0;
+ }
+
function step(budget as Number) as Boolean {
var m = _matrix.modules;
var n = m.size();
@@ -235,6 +242,11 @@ module Codes {
result = new Runs(packed);
}
+ // Progress 0-99 through the rows.
+ function percent() as Number {
+ return 99 * _row / _packed.height;
+ }
+
function step(budget as Number) as Boolean {
var p = _packed;
var w = p.width;
@@ -276,31 +288,63 @@ module Codes {
// A 2D code from the cache or a fresh encoding to Runs: encode (unless
// cached), pack (`cache` then holds the bytes to store), find the runs.
+ // percent() follows the work: the encoder's share of 0-100 comes from
+ // its stageEnds(), then the packer's, then the run finder's; a cached
+ // code only runs the finder, over the whole range.
class DisplayJob extends Jobs.Job {
var error as String? = null;
var cache as ByteArray? = null;
var runs as Runs? = null;
+ // Milliseconds spent in each stage's steps (encode, pack, runs), for
+ // the debug log.
+ var stageMs as Array<Number> = [0, 0, 0];
private var _encoder as MatrixJob?;
private var _packer as Packer? = null;
private var _finder as RunFinder? = null;
+ private var _encodeEnd as Number = 0;
+ private var _packEnd as Number = 0;
// Either an encoder (fresh) or the cached bytes.
function initialize(encoder as MatrixJob?, packed as Packed?) {
Job.initialize();
_encoder = encoder;
+ if (encoder != null) {
+ var ends = encoder.stageEnds();
+ _encodeEnd = ends[0];
+ _packEnd = ends[1];
+ }
if (packed != null) {
_finder = new RunFinder(packed);
}
}
- // Progress 0-100: encoding is most of it.
+ // Progress 0-99 (100 is never shown: the code replaces this screen),
+ // never going back: each stage starts where the one before ended.
function percent() as Number {
var e = _encoder;
- return e != null ? e.percent() * 9 / 10 : 90;
+ var p = _packer;
+ var f = _finder;
+ var done = 0;
+ if (e != null) {
+ done = e.percent() * _encodeEnd / 100;
+ } else if (p != null) {
+ done = _encodeEnd + (_packEnd - _encodeEnd) * p.percent() / 100;
+ } else if (f != null) {
+ done = _packEnd + (100 - _packEnd) * f.percent() / 100;
+ }
+ return done < 99 ? done : 99;
}
function step(budget as Number) as Boolean {
+ var started = System.getTimer();
+ var stage = _finder != null ? 2 : (_packer != null ? 1 : 0);
+ var done = advance(budget);
+ stageMs[stage] += System.getTimer() - started;
+ return done;
+ }
+
+ private function advance(budget as Number) as Boolean {
var finder = _finder;
if (finder != null) {
if (!finder.step(budget)) {
@@ -344,11 +388,20 @@ module Codes {
Job.initialize();
}
- // Progress 0-100 for the UI.
+ // Progress 0-100 for the UI, following the work done so far.
function percent() as Number {
return 0;
}
+ // Where the pack and the run stages begin in a display job's 0-100
+ // (the encoding is [0, ends[0]], packing [ends[0], ends[1]], the
+ // runs the rest), weighted by their time in the simulator's
+ // benchmark: encoding takes by far the most, except for PDF417,
+ // whose wide matrices make the runs a third.
+ function stageEnds() as Array<Number> {
+ return [90, 92];
+ }
+
function matrix() as Matrix? {
return null;
}
@@ -379,6 +432,19 @@ module Codes {
return isLinear(symbology) || symbology == PDF417 ? 1 : 2;
}
+ // Progress 0-100 through phases: ends[i] is the percent at the end of
+ // phase i; `done` of `total` is how far the current phase has got (it
+ // may be a flat 0 for a phase that reports no progress). A finished job
+ // (phase past the last) is 100. Never goes back while `done` doesn't.
+ function phased(ends as Array<Number>, phase as Number, done as Number, total as Number) as Number {
+ if (phase >= ends.size()) {
+ return 100;
+ }
+ var from = phase > 0 ? ends[phase - 1] : 0;
+ var inside = total > 0 && done > 0 ? (done < total ? done : total) : 0;
+ return from + (ends[phase] - from) * inside / (total > 0 ? total : 1);
+ }
+
// True when a code of w x h modules (quiet zone included) at px pixels
// per module fits the screen: inside the circle (less a 4 px margin) on
// round screens; elsewhere the full width and the height less room for