.. Copyright (C) 2020-2022 Evolabel AB. All rights reserved. Author: Henrik Bohre .. _code_matching-index: ############# Code Matching ############# ======== Overview ======== Code Matching provides a way to ensure that the scanned barcode data matches against expected data included in the print job. This prevents e.g. an existing barcode on a product to be mistaken for a successfully applied label. Example scenario: Applying label X on a product with an existing barcode Y. .. uml:: @startuml hide footbox skinparam BackgroundColor transparent skinparam shadowing false skinparam ActorBorderColor black skinparam ParticipantBorderColor black skinparam ParticipantBackgroundColor #EEEEEE skinparam ArrowColor black participant "Host PC" as host participant "Marker" as print participant "Product" as prod participant "Scanner" as scan host -[#green]-> print: Job A with data X activate print print -[#red]-> prod: Label A with data X\nwas dropped. print -[#green]-> scan: request scan activate scan scan -[#green]-> prod: reading existing barcode Y scan -[#green]-> print: send result Y (from an existing barcode) deactivate scan activate print print -[#green]-> print: Y = X? deactivate print print -[#green]-> host: A: no_match deactivate print note over host #lightgreen Detected mismatch reported to host end note @enduml If Code Matching would have not been used, the existing barcode Y of the same type would have been mistaken as a successful application of label X. Expected data can be included in print jobs using the special variable ``"_code_matching"``. This works for JSON-RPC and ZPL. .. seealso:: :ref:`concept-code_matching` in the JSON-RPC API documentation for details on pattern matching and matching policy. .. seealso:: `Including Job Metadata `_ in the :ref:`zpl-index`. ============= Error Classes ============= Barcode errors have been categorized in three different classes: ERR_TOO_FEW One or more barcode not readable because: - Label does not stick to the product. - Broken printhead dots. - Layout errors. - Media errors. ERR_TOO_MANY Unexpected barcodes read because of: - A stray label is visible by the scanner. - Barcodes already present on the product. ERR_SYNC Unexpected barcodes read because of: - Synchronization error (the host and the printer are mismatched -- possibly due to differing views on the job queue state). - Product conveying issues (products unexpectedly appearing or missing) before printing and applying. ===================== Validation Techniques ===================== Using a scanner it is possible to validate the existance of barcodes in different ways: Require *n* barcodes The basic way to use a scanner is to require a number of readable barcodes on each scan. This is only effective against ERR_TOO_FEW which is implied in all cases below. Require no_read - Not implemented A scanner can also give feedback whether any readable barcodes exist prior to label application. Internal Matching The printer matches the scanner against a *stored* expected data set. .. comment Automatic Code Matching - Not implemented Internal Matching, where the printer determines the expected data set from the layout. This can be used when barcodes are defined using barcode fields - but not if barcodes are sent as images. Requires some configuration or fuzziness in the matching. External Code Matching - Not implemented The expected data set is sent in a host-controlled scanning command. This way the marker doesn't need to hold any state, and any synchronization errors are catched as well. Requires the most integration work in the host system. The table describes which combination of errors (ERR_TOO_FEW and Require *n* barcodes is implied in all cases) can be detected using different validation strategies. - The first two columns denotes which *error classes* that are expected to be present. - The next three columns describes which *validation techniques* that are used. - Finally the **Detection** column sums up whether the combination of employed validation techniques will reliably detect the present *error classes*. .. csv-table:: :header: ERR TOO MANY, ERR SYNC, Require no_read, Internal Matching, External Matching, Detection :widths: 10, 10, 10, 10, 10, 40 :stub-columns: 2 --, --, --, --, --, *OK* -- Scanner detects non-readable barcodes. Yes, --, --, --, --, "**UNRELIABLE** -- if scanner cannot distinguish between a stray label/barcode and the printed label." Yes, --, --, Yes, --, "*Fair* -- Code Matching increases probability to find stray labels, but will only work for unique labels." Yes, --, Yes, --, --, "*OK* -- Requiring no_read before applying prevents stray labels or present barcordes to be mixed up with the last printed label." --, Yes, Yes/--, Yes/--, --, "**UNRELIABLE** -- Synchronization errors risk to pass undetected." --, Yes, Yes/--, --, Yes, "*OK* -- external Code Matching finds synchronization errors." Yes, Yes, --, --, Yes, "Possibly **UNRELIABLE** -- if scanner cannot distinguish between stray label and the printed label." Yes, Yes, Yes, --, Yes, "*OK* -- Requiring no read before applying prevents stray labels or present barcodes to be mixed up with the last printed label. Combined with external Code Matching this is the safest option." .. commented UNDETECTED: Failed Application Without Scanner ---------------------------------------------- Without a scanner, there is a risk that dropped or unreadable labels will go undetected. .. uml:: @startuml hide footbox skinparam BackgroundColor transparent skinparam shadowing false skinparam ActorBorderColor black skinparam ParticipantBorderColor black skinparam ParticipantBackgroundColor #EEEEEE skinparam ArrowColor black participant "Host PC" as host participant "Printer" as print participant "Applicator" as appl participant "Product" as prod participant "Scanner" as scan host -[#green]-> print: Job A with data X activate print print -[#green]-> appl: Label A with data X appl -[#red]-> prod: Label A with data X\nwas dropped\nor unreadable. print -[#green]-> host: A: successful deactivate print note over host #FFAAAA UNDETECTED FAILURE success reported to host end note @enduml ========= Scenarios ========= Failed Application With Scanner =============================== With a scanner, an unreadable barcode or non-existent label will be detected. .. uml:: @startuml hide footbox skinparam BackgroundColor transparent skinparam shadowing false skinparam ActorBorderColor black skinparam ParticipantBorderColor black skinparam ParticipantBackgroundColor #EEEEEE skinparam ArrowColor black participant "Host PC" as host participant "Printer" as print participant "Applicator" as appl participant "Product" as prod participant "Scanner" as scan host -[#green]-> print: Job A with data X activate print print -[#green]-> appl: Label A with data X appl -[#red]-> prod: Label A with data X\nwas dropped\nor unreadable. print -[#green]-> scan: request scan activate scan scan -[#green]-> print: send no_read deactivate scan print -[#green]-> host: A: failed deactivate print note over host #lightgreen failure reported to host end note @enduml UNDETECTED: Failed Application With Scanner and Stray Label =========================================================== Even with a scanner, a stray label, or old barcodes on the product itself could potentially be mistakenly taken for a successful labeling. .. uml:: @startuml hide footbox skinparam BackgroundColor transparent skinparam shadowing false skinparam ActorBorderColor black skinparam ParticipantBorderColor black skinparam ParticipantBackgroundColor #EEEEEE skinparam ArrowColor black participant "Host PC" as host participant "Printer" as print participant "Applicator" as appl participant "Product" as prod participant "Scanner" as scan host -[#green]-> print: Job A with data X activate print print -[#green]-> appl: Label A with data X appl -[#red]-> prod: Label A with data X\nwas dropped\nor unreadable. print -[#green]-> scan: request scan activate scan scan -[#red]-> print: send result Y (from a stray label) deactivate scan print -[#green]-> host: A: success deactivate print note over host #FFAAAA UNDETECTED FAILURE success reported to host end note @enduml Failed Application With Code Matching and Stray Label ===================================================== Using Code Matching we can decrease the probablity that a stray label would be mistaken for the real label. .. uml:: @startuml hide footbox skinparam BackgroundColor transparent skinparam shadowing false skinparam ActorBorderColor black skinparam ParticipantBorderColor black skinparam ParticipantBackgroundColor #EEEEEE skinparam ArrowColor black participant "Host PC" as host participant "Printer" as print participant "Applicator" as appl participant "Product" as prod participant "Scanner" as scan host -[#green]-> print: Job A with data X, MS=X activate print print -[#green]-> appl: Label A with data X appl -[#red]-> prod: Label A with data X\nwas dropped\nor unreadable. print -[#green]-> scan: request scan activate scan scan -[#red]-> print: send result Y (from a stray label) deactivate scan activate print print -[#green]-> print: Y in {X}? deactivate print print -[#green]-> host: A: failed deactivate print note over host #lightgreen failed match with expected data reported to host end note @enduml In summary, internal Code Matching helps with errors that happens external to the printer sequence. E.g. labels being mechanically dropped, or scanner potentially scanning other labels. UNDETECTED: Printer Synchronization Error With Code Matching ============================================================ If the host system and printer fails to synchronize their world views on the expected product to print and apply due to e.g. queuing issues, there is a risk that internal Code Matching does not detect any errors. .. uml:: @startuml hide footbox skinparam BackgroundColor transparent skinparam shadowing false skinparam ActorBorderColor black skinparam ParticipantBorderColor black skinparam ParticipantBackgroundColor #EEEEEE skinparam ArrowColor black participant "Host PC" as host participant "Printer" as print participant "Applicator" as appl participant "Product" as prod participant "Scanner" as scan host -[#lightgray]-> print: Job A with data X, MS=X activate print note over host #FFAAAA the host has forgot A and now wants to print B end note host -[#green]-> print: Job B with data Y, MS=Y print -[#green]-> appl: Label A with data X\n(the host wanted to print B) appl -[#green]-> prod: Label A with data X. print -[#green]-> scan: request scan activate scan scan -[#green]-> print: send result X deactivate scan activate print print -[#green]-> print: X in {X}? deactivate print print -[#green]-> host: A: success deactivate print note over host #FFAAAA UNDETECTED MISMATCH with expected data reported to host as success end note @enduml Printer Synchronization Error With External Code Matching ========================================================= By letting the host request the scanning with an explicit match data set, any synchronization errors can be detected. This requires a higher level of integration but would give the most robust solution to any interference during the print and apply sequence. .. uml:: @startuml hide footbox skinparam BackgroundColor transparent skinparam shadowing false skinparam ActorBorderColor black skinparam ParticipantBorderColor black skinparam ParticipantBackgroundColor #EEEEEE skinparam ArrowColor black participant "Host PC" as host participant "Printer" as print participant "Applicator" as appl participant "Product" as prod participant "Scanner" as scan host -[#lightgray]-> print: Job A with data X activate print note over host #FFAAAA the host has forgot A and now wants to print B end note host -[#green]-> print: Job B with data Y print -[#green]-> appl: Label A with data X\n(the host wanted to print B) appl -[#green]-> prod: Label A with data X. print -[#green]-> host: Apply Sequence finished host -[#green]-> print: request scan with match set {Y} print -[#green]-> scan: request scan activate scan scan -[#green]-> print: send result X deactivate scan activate print print -[#green]-> print: X in {Y}? deactivate print print -[#green]-> host: fail {Y} not matched by X deactivate print note over host #lightgreen detected mismatch reported correctly to host as failure end note @enduml .. Golden Path With Code Matching -------------------------- .. uml:: @startuml hide footbox skinparam BackgroundColor transparent skinparam shadowing false skinparam ActorBorderColor black skinparam ParticipantBorderColor black skinparam ParticipantBackgroundColor #EEEEEE skinparam ArrowColor black participant "Host PC" as host participant "Printer" as print participant "Applicator" as appl participant "Product" as prod participant "Scanner" as scan host -[#green]-> print: Job A with data X, MS=X activate print print -[#green]-> appl: Label A with data X appl -[#green]-> prod: Label A with data X print -[#green]-> scan: request scan activate scan scan -[#green]-> print: send result X deactivate scan activate print print -[#green]-> print: X in {X}? deactivate print print -[#green]-> host: A: successful deactivate print note over host #lightgreen successfully matched with expected data reported to host end note @enduml .. comment --------- Use Cases --------- UC1. Automatic Code Matching using JSON-RPC or ZPL Layouts ========================================================== *Alice* is responsible for traceability of produced goods. Pallets shall be labeled with two identical labels on adjacent sides (for wide angle readability). In order to ensure that the labels are applied, and that the barcodes are readable they have employed scanning as part of the sequence. To ensure that the scanner does not read something else than the applied label, Alice enabled the *Automatic Code Matching* feature. By using *Fuzzy* matching the barcode symbology characters that are present in the scanner data is ignored. The *Automatic Code Matching* feature builds a matching set from the barcode messages found in the layout. The default behavior is to require that the read barcode data matches at least one message in the matching set. As there are never a queue of print jobs, the risk of getting ERR_SYNC errors was deemed very low. Using the built-in *Automatic Code Matching* feature added a reasonable protection for ERR_TOO_MANY barcodes (stray labels). .. note:: There may be challenges when creating the match set automatically, as sometimes barcode generators change the data by encoding it, adding check digits etc. Scanner configuration will also affect what data they will output. In order to handle this robustly, we would have to create a tool that can reliably predict the scanner output from an input barcode message string. The result, if successful would be a simple but powerful *Code Matching* solution that would solve 80% of all customer requirements. UC1. Explicit Code Matching Using ZPL layouts ============================================= *Bob* has built a pallet marking system that prints and applies two copies of an SSCC label on adjacent sides. The variable data comes from the ERP system, and populates a template that is used for all products. The complete print job is then sent to the printer as a ZPL file. In order to prevent any errors in the ZPL conversion procedure to induce errors that the *Automatic Code Matching* would also fail to detect, *Bob* decided to use *Explicit Code Matching* by including the exact match data that the Print and Apply system should match against. As *Bob* has full control of the layouts, he designs his jobs such that the critical barcode fields are matched on each page. As some barcode generators adds check digits, he designs the match expression to ignore the last check digit. UI Configuration ---------------- #. The *Code Matching* Feature is enabled under :menuselection:`SETTINGS --> Print and Apply -> Label --> Scan --> Data Validation --> Type --> Code Matching` #. The :menuselection:`Code Matching --> Expected Data Source` is :menuselection:`Included In Job`. #. As the last digit is a calculated check digit, we add a wildcard in the last position of the *Expected Data* items. Enabling matching against an expression is performed by selecting :menuselection:`Code Matching --> Matching Method --> Pattern` Layout Data ----------- Each ZPL layout is augmented with code matching data in :command:`^FX` comments. .. code-block:: zpl ^XA^XFR:GENERIC.ZPL^FS ^FX Variable data like e.g. name and address --^FS ^FN1^FD12345678912^FS ^FX Expected Data -----------------------------^FS ^FX{"_code_matching":{"expected":[["12345678912?","ABC123"]]}}^FS ^XZ This solution is resistant to internal errors, as the data is sent explicitly in the print job. If no queue is held in the printer, synchronization errors are also very unlikely. .. _code_matching-moving_products: =============== Moving Products =============== For stationary marking, the scanner result is always matched against the *code matching data* associated with the latest label that was printed. When moving products are marked, the barcodes that are scanned are not necessarily the last to have been printed, and a queue of *code matching data* is used. Configuration ============= In order to be able to synchronize *code matching data* with a scanner result, specific configuration is required. .. _code_matching-moving_products_scanner_configuration: Scanner Configuration --------------------- The scanner needs to have its *Output Delay* such that it always produces a result a certain time period after the scan command was issued. Even if the scanning completes before the configured time, the scanner should withhold the result so that it is delivered to the printer after the configured amount of time has passed. .. _code_matching-moving_products_printer_configuration: Printer Configuration --------------------- - :menuselection:`SETTINGS --> Peripherals --> Scanners --> "Scanner" --> Start Condition` Since the printer must be aware of which label a certain scanner result is associated with, only the follwing start conditions are supported for moving products: - Label Printing - Label Printed - Label Applied - Applicator Home - :menuselection:`SETTINGS --> Peripherals --> Scanners --> "Scanner" --> Output Delay` Set this to be equal to the *Output Delay* configured for the scanner. Behavior ======== Scanning Windows ---------------- A *scanning window* is the time during which the printer accepts a result from the scanner for a specific label. When a label has been printed and applied, scanning is triggered on the configured *Start Condition*. The printer expects a result from the scanner within a time window covering the configured *Output Delay*. If the scanner fails to produce a scan result within the configured time window, a ``code_matching_timeout`` alarm will be raised. The size of the *scanning window* is based on the :ref:`Minimum Cycle Time ` to ensure that no two *scanning windows* overlap. .. container:: .. container:: header Revision History .. rubric:: Revision 2022-03-29 - Added support for moving products .. rubric:: Revision 2021-02-05 - Updated transport of expected data in ZPL files. .. rubric:: Revision 2021-01-31 - Minor changes to UI element naming and examples. .. rubric:: Revision 2021-01-22 - Changed pattern matching syntax from regular expressions to *Unix shell style* matching using easier to understand ``*`` and ``?`` wildcards. .. rubric:: Revision 2021-01-21 - Changed name from *Match Count* to *Matching Policy*. - Changed name from *Match Method* to *Matching Method*. - Updated pattern matching examples using valid regular expression syntax.