diff options
Diffstat (limited to 'source/codes/Codes.mc')
| -rw-r--r-- | source/codes/Codes.mc | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/source/codes/Codes.mc b/source/codes/Codes.mc new file mode 100644 index 0000000..70c6c2d --- /dev/null +++ b/source/codes/Codes.mc @@ -0,0 +1,149 @@ +// Author: cirakg & claude ai +// Summary: Barcode symbology IDs, option bits, result types and the dispatcher to the encoders (README 12). +// +// A code entry stores its symbology in Entry.type and its options in +// Entry.options (bits below). encode() turns the payload text into either a +// LinearCode (one row of modules) or, from M6b, a matrix; validation errors +// come back as a CodeError with a message for the user, never an exception. + +import Toybox.Lang; + +module Codes { + + // Symbology IDs (Entry.type of code entries). Stored: never renumber. + const QR = 0; + const CODE128 = 1; + const CODE39 = 2; + const EAN13 = 3; + const EAN8 = 4; + const UPCA = 5; + const UPCE = 6; + const ITF = 7; + const CODABAR = 8; + const DATAMATRIX = 9; + const PDF417 = 10; + const AZTEC = 11; + + const NAMES = ["QR", "Code 128", "Code 39", "EAN-13", "EAN-8", "UPC-A", "UPC-E", "ITF", "Codabar", "Data Matrix", + "PDF417", "Aztec"]; + + // Entry.options bits. + const OPT_EC_MASK = 0x3; // error correction: 0 low, 1 medium, 2 quartile, 3 high + const OPT_CHECK_SHIFT = 2; // check digit: 0 add or verify, 1 fix if wrong, 2 off + const OPT_CHECK_MASK = 0xC; + const OPT_SHOW_TEXT = 0x10; // human-readable text under linear codes + const DEFAULT_OPTIONS = 0x11; // medium, add or verify, text on + + const CHECK_ADD_VERIFY = 0; + const CHECK_FIX = 1; + const CHECK_OFF = 2; + + // A row of modules: modules[i] is 1 for a bar, 0 for a space. The quiet + // zone is not included (the renderer adds it). + class LinearCode { + var modules as ByteArray; + // The human-readable text (digits as encoded, check digit included). + var text as String; + // A remark for the user (check digit added or fixed), or null. + var note as String? = null; + + function initialize(rowModules as ByteArray, readable as String) { + modules = rowModules; + text = readable; + } + } + + // Why a payload can't be encoded, in words for the user. + class CodeError { + var message as String; + + function initialize(msg as String) { + message = msg; + } + } + + function checkMode(options as Number) as Number { + return (options & OPT_CHECK_MASK) >> OPT_CHECK_SHIFT; + } + + function name(symbology as Number) as String { + return symbology >= 0 && symbology < NAMES.size() ? NAMES[symbology] as String : "Code"; + } + + function isLinear(symbology as Number) as Boolean { + return symbology >= CODE128 && symbology <= CODABAR; + } + + // Encode a payload; unsupported symbologies give a CodeError until + // their milestone (README 16, M6b-M6d). + function encode(symbology as Number, payload as String, options as Number) as LinearCode or CodeError { + var check = checkMode(options); + if (symbology == EAN13) { + return Ean.ean13(payload, check, "EAN-13", false); + } + if (symbology == UPCA) { + return Ean.ean13(payload, check, "UPC-A", true); + } + if (symbology == EAN8) { + return Ean.ean8(payload, check); + } + if (symbology == UPCE) { + return Ean.upce(payload, check); + } + if (symbology == CODE128) { + return Code128.encode(payload); + } + if (symbology == CODE39) { + return Code39.encode(payload, check != CHECK_OFF); + } + if (symbology == ITF) { + return Itf.encode(payload, check != CHECK_OFF); + } + if (symbology == CODABAR) { + return Codabar.encode(payload); + } + return new CodeError(name(symbology) + " is not supported yet"); + } + + // Append bar/space runs to modules: widths alternate bar, space, ..., + // starting with a bar when startWithBar. + function addRuns(modules as ByteArray, widths as Array<Number>, startWithBar as Boolean) as Void { + var bar = startWithBar; + for (var i = 0; i < widths.size(); i++) { + var w = widths[i]; + for (var k = 0; k < w; k++) { + modules.add(bar ? 1 : 0); + } + bar = !bar; + } + } + + // Append a bit pattern of `count` modules, most significant bit first. + function addBits(modules as ByteArray, bits as Number, count as Number) as Void { + for (var i = count - 1; i >= 0; i--) { + modules.add((bits >> i) & 1); + } + } + + // The digit values of text, or null when it holds anything else. + function digits(text as String) as Array<Number>? { + var chars = text.toCharArray(); + var out = [] as Array<Number>; + for (var i = 0; i < chars.size(); i++) { + var c = chars[i]; + if (c < '0' || c > '9') { + return null; + } + out.add(c.toNumber() - 48); + } + return out; + } + + function digitsText(values as Array<Number>) as String { + var s = ""; + for (var i = 0; i < values.size(); i++) { + s += values[i].toString(); + } + return s; + } +} |
