Skip to content

fix(keyence): read full barcode reply and release the read beam (LOFF)#1114

Open
dinukajayalath wants to merge 4 commits into
PyLabRobot:mainfrom
myotwin:fix/keyence-barcode-read-and-loff
Open

fix(keyence): read full barcode reply and release the read beam (LOFF)#1114
dinukajayalath wants to merge 4 commits into
PyLabRobot:mainfrom
myotwin:fix/keyence-barcode-read-and-loff

Conversation

@dinukajayalath

Copy link
Copy Markdown

Fixes #1101

Problem:

KeyenceBarcodeScannerBackend.scan_barcode() returns only the first character of a barcode, and leaves the reader's beam latched on:

  • send_command() calls self.io.read() with no num_bytes, and Serial.read defaults to 1 byte — no loop, no terminator scan so
    The reader's \r-terminated reply is truncated to one character.
  • scan_barcode() sends LON (which latches the read beam on) but never the matching LOFF, so the beam stays on after the call.

Verified on hardware (Keyence BL-600HA, Code 128 label Test): PLR returned data='T'; the same reader driven directly (LON →read to \r → LOFF) returned Test.

Fix:

  • send_command accumulates bytes until \r, stopping at the terminator or at the first byte-less read (the port timeout=1
    elapsed with no reply — e.g. no barcode present, a valid empty result). Replies now come back whole, and a present barcode returns the instant the terminator lands instead of blocking on a fixed byte count.
  • scan_barcode sends LOFF in a finally block to release the beam, whether the read succeeded or raised. LOFF runs through a try/except that logs rather than propagates, so a LOFF failure can't mask the scan's result or error.

Tests

keyence_backend_tests.py. Each fails against pre-fix code and passes after:

  • send_command: accumulates to \r, stops at the terminator, treats a byte-less read as an empty reply, writes \r-terminated
    commands.
  • scan_barcode: sends LOFF after LON on success / NG / ERR99; a failing LOFF masks neither a successful result nor a reader error.

Glad to make any change upon reviewing.

dinukajayalath and others added 4 commits June 24, 2026 11:02
send_command did a single io.read(), which returns one byte and truncated
every \r-terminated reply. Accumulate bytes until \r — or until a byte-less
read, which means the port timeout elapsed with no reply (e.g. no barcode).
Replies now come back whole, and a present barcode returns the instant the
terminator lands instead of blocking on a fixed byte count.

scan_barcode never turned the read beam off. LON latches it on, so release
it with LOFF in a finally, whether the read succeeded or raised. LOFF runs
through a try/except that logs instead of propagating, so a LOFF failure
can't mask the scan's result or error.

Fixes PyLabRobot#1101

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Regression tests for the send_command and scan_barcode fix. Each fails
against the pre-fix code: send_command's single io.read() truncated
multi-byte replies, and scan_barcode never sent LOFF.

- send_command accumulates bytes until \r, stops at the terminator, and
  treats a byte-less read as an empty reply.
- scan_barcode sends LOFF after LON on success, on NG, and on ERR99; a
  failing LOFF is swallowed and masks neither the result nor the error.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The committed tests added new mypy errors under `make typecheck`: mock
attributes (io.read.side_effect, send_command.assert_has_calls) aren't on
the real method signatures. Match the existing PLR convention (proflex_tests,
agrowdosepump_tests) with targeted `# type: ignore` and annotate replies/
raise_on. No behaviour change; the module is now mypy-clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

KeyenceBarcodeScannerBackend.scan_barcode() truncates barcodes to 1 character and never turns the beam off (no LOFF)

1 participant