Your barcode scanner hangs off the controller's USB port, Linux names it /dev/ttyACM1, and the PLC project only offers COM ports that do not exist yet. The file that owns the mapping, plc_system.cfg, refuses every external edit: the web interface lists it write-protected, and a WinSCP transfer over WebDAV answers 403 Forbidden. That is deliberate — the file belongs to the runtime's internal data, and only the runtime itself can write it. This guide takes the supported route: name the device on the Linux side, prove the scanner talks with a two-line shell test, write the serial mapping from inside the runtime with the CmpSettings library, reboot, then open COM1 in your project. The worked example at the end puts numbers on the load one mapped port carries at a busy station.
What you need
- The controller with its Linux runtime and the matching engineering tool. In the worked example, controller, runtime and tool all sit at version 1.20; align your versions before you start.
- The scanner connected to a USB host port on the controller and powered.
- Shell access to the controller's Linux side, over SSH or the service console, for the device test.
- Library manager access in the engineering tool, so you can add CmpSettings to a small test project.
- A printed test label with a real code; an EAN-13 gives you 13 digits to check against.
If the reader itself is still to be chosen, this route applies to the wired USB class of handheld code readers. The cards below show the filters to match on the product page: Interface: USB, Connection: Wired.
- Resolution
- Up to 3 MP
- Shutter
- Global
- Interface
- USB
- Connection
- Wired
Why the runtime refuses outside edits
plc_system.cfg is not a text file you own. The runtime treats its settings as internal data and writes the file on its own terms, so the web interface keeps it read-only and file transfers are refused regardless of the account you use. An offline copy would not help either — the effective settings live inside the runtime, not in the file you can reach. The supported path runs from inside: the CmpSettings library lets a downloaded PLC program write runtime settings, and a change written that way activates at the next restart. One short program, one flag, one reboot.
Map the port, step by step
-
Name the device. In the controller's shell run
ls /dev/ttyACM* /dev/ttyUSB*, unplug the scanner, run it again. The entry that disappears is the scanner. Devices with native USB serial (the CDC-ACM class most scanners use) appear as ttyACM0, ttyACM1 and upward; USB-RS232 dongles appear as ttyUSB0 and upward. Copy the exact path — the mapping needs it character for character. If your hardware is a real RS232 scanner behind a dongle, the RS232 scanner connection to an embedded host guide covers the wiring side first. -
Prove the link from the shell before you touch the runtime. Set the line once with
stty -F /dev/ttyACM1 115200, then read the port raw withcat /dev/ttyACM1. Scan the test label: every trigger should print the 13 digits and a line ending. Garbage means a rate or framing mismatch between scanner and port — settle it now, not after the mapping. Trigger the scans with the reader lying on the bench aimed at the label; never stare into the aiming beam while you fire it by hand. -
Add CmpSettings to the library manager of a small test project, then download the project to the controller. The library carries the settings read and write calls the next step needs.
-
Write the mapping from a program, not by hand. The program's job: open the settings handle, write the serial mapping entries of the SysCom serial component — your COM index bound to the device path — then close the handle. Guard the whole block with a DoIt flag so the write runs once:
PROGRAM WriteSerialMap
VAR
DoIt : BOOL := FALSE; // set TRUE only for the write run
END_VAR
IF DoIt THEN
// open the settings handle (CmpSettings)
// write the SysCom serial mapping entries: COM1 -> /dev/ttyACM1
// close the handle
DoIt := FALSE; // write once, then stay idle
END_IF
The exact write call comes from CmpSettings in the library manager; every call in that library has the same shape — component name, setting name, new value.
-
Run the write once. Set DoIt to TRUE from the watch table (or force it before the download), let one cycle execute, and check that the write path ran. Return DoIt to FALSE so the program never writes again.
-
Reboot the controller. The mapping activates when the runtime restarts and reloads its settings. From here on, COM1 exists in the project and /dev/ttyACM1 sits behind it.
Verify it in the project
Open COM1 with your serial library — SysCom in this runtime — at the settings you tested in the shell: 115200 baud, 8 data bits, no parity, 1 stop bit. Scan the label. With CR/LF framing set on the scanner, one scan delivers exactly 15 bytes: the 13 EAN-13 digits plus the two terminator characters. Read them into a buffer and log a few scans. If the port opens but nothing arrives, either the mapping entry and the port index disagree or the scanner sits in keyboard mode — the fourth mistake below covers the second case. When strings arrive cleanly the transport is done; stripping a preamble or splitting fields is framing work, covered in prefix and suffix framing for barcode scanner input. Neighbouring runtime problems — USB device path conflicts, SDK access errors, frame matching — live on the systems topic page.
Common mistakes and their fixes
- Mapping the wrong ttyACM device. Enumeration order, not the connector, decides the name. The unplug test in step 1 is the only reliable check, and adding a second USB serial device later can swap the names at boot. Pin each device with a udev rule that matches its USB serial number and creates a stable symlink such as /dev/scanner, then map the symlink.
- Skipping the reboot. The written setting activates at restart. A project that opens COM1 straight after the download still finds no port, and no amount of re-downloading changes that.
- Leaving DoIt TRUE. The program then rewrites settings every scan cycle. Reset the flag after the first run.
- A scanner stuck in keyboard mode. Many USB handhelds ship configured as HID keyboards: they type into whatever has focus and never touch the serial channel. Switch the scanner to its USB serial mode before blaming the mapping; the keyboard-versus-serial comparison for a PLC HMI shows both modes side by side.
- Rate mismatch. The scanner sends at one rate and the port opens at another; every scan arrives as garbage characters. The garbage-character walkthrough traces that failure end to end, from wiring to framing.
- Testing through a laptop and assuming the controller behaves the same. On a Windows machine a USB-RS232 adapter can even come back with a different COM number after a reboot; the Windows USB serial COM port assignment fix covers that side of the problem. Map the device on the controller itself.
Worked example: mapping /dev/ttyACM1 to COM1 on a 1.20 runtime
Inputs, and where each comes from: the device path /dev/ttyACM1 and the target COM1 come from the set-up this guide works — one scanner on the controller's USB host port, with controller, runtime and engineering tool all at version 1.20. The line settings 115200 baud, 8 data bits, no parity, 1 stop bit are the shell-test settings from step 2. The payload is one EAN-13 scan with CR/LF framing: 13 + 2 = 15 bytes. The stress case is 20 scans per second, well above the pace of a manual station.
The rule in words: a serial line sends every byte inside a fixed frame, and with 8N1 that frame is 10 bits — 1 start, 8 data, 1 stop. Message time is bytes × 10 ÷ baud; utilization is message rate × message time against one second of line.
Arithmetic:
- Frame size: 15 × 10 = 150 bits per scan.
- At 115200: 150 ÷ 115200 = 0.001302 s = 1.30 ms per scan.
- At 9600, a conservative legacy rate: 150 ÷ 9600 = 0.015625 s = 15.6 ms.
- Stress case at 115200: 20 × 1.30 = 26.0 ms of line time per second, and 26.0 ÷ 1000 = 2.6% utilization.
Result: one scan occupies the mapped port for 1.30 ms, and the busy station uses 2.6% of the line — about 97% idle. The decision: serial mapping comfortably carries station-level scanning, and even 9600 baud spends only 16 ms per scan, fine for a part arriving every few hundred milliseconds. Keep 115200 if the cell might ever stream codes back to back. Move to Ethernet readers when several fixed readers must stream continuously at once — that is a different architecture, not a faster serial port.
Before you reboot: a short checklist
Linux side
- Device name confirmed with the unplug test, not assumed from the connector.
- Shell test passed: after
sttysets the line, the port prints clean digits on every scan. - A second USB serial device present? Pin the scanner with a udev symlink before you map.
Runtime side
- CmpSettings added in the library manager and downloaded with the project.
- Write program on the controller with DoIt at FALSE.
- DoIt set TRUE for one cycle, write path executed, flag back to FALSE.
- Reboot scheduled — the mapping activates only at restart.
After the restart
- COM1 opens at the tested settings.
- One scan delivers the expected byte count with CR/LF framing.
- Scanner confirmed in USB serial mode, not keyboard.
When not to map serial at all
Three cases argue against the mapping:
- Manual entry at an HMI. Skip serial: put the scanner in keyboard mode and let it type into the field.
- Continuous flow or a remote reader. Take a fixed Ethernet reader and carry its result as I/O data instead of serial bytes — the Ethernet/IP implicit I/O assembly mapping shows the data layout, and the fixed code readers category is where those readers live.
- A new station from scratch. Decide the transport first. The input-methods overview for PLCs lines up serial, USB and Ethernet, and USB or RS232 for a Linux PLC settles the Linux-side hardware choice. For the whole link — reader, cable, runtime, alarm behaviour — start from plan a reliable reader-to-PLC link.
One note on the box itself: where the PLC runtime and the vision software share a cabinet, a fanless vision controller is the usual host class. The model below carries 2 USB 3 ports, 3-4 LAN ports and 8 GB memory, and the vision controllers category holds the rest of the range.
- LAN ports
- 3-4 LAN ports
- USB 3 ports
- 2 USB 3 ports
- Light outputs
- 4 built-in channels
- Memory
- 8 GB
The decision, in one line each: a single scanner feeding a PLC program — map the USB serial port with CmpSettings and reboot; scanner data typed by hand — keyboard mode, no mapping; many readers streaming continuously — Ethernet readers with I/O mapping. If you want a reader chosen alongside the mapping, or a second opinion before you order, reach us through the contact page.
Questions
Why did my scanner come up as ttyACM1 rather than ttyACM0?
Enumeration order decides: the kernel hands out ttyACM0, ttyACM1 and upward in the order it detects CDC-ACM devices, not by connector position. If another USB serial interface — an internal service console, for example — is detected first, your scanner lands on ttyACM1. Never assume the name: run the unplug test from step 1. If you add devices later, pin each one with a udev rule that matches its USB serial number and creates a stable symlink, then map the symlink.
Can I edit plc_system.cfg over SSH, WinSCP or the web interface?
No. The refusals are the designed behaviour: the web interface lists the file write-protected, and a WebDAV transfer answers 403 Forbidden even with valid credentials, because the settings belong to the runtime's internal data. The supported route is a short PLC program using the CmpSettings library to write the mapping from inside the runtime, followed by a reboot to activate it. Keep a small test project for the job so the write program never lives in the production project.
Does the baud rate matter over a USB serial port?
Physically, no: a USB serial device moves data in USB packets, so there is no line-speed ceiling as there is on RS232. Logically, yes: both ends must agree, or the bytes arrive as garbage characters. Set the scanner's serial output and the runtime's COM port to the same value — 115200 with 8 data bits, no parity, 1 stop bit in the worked example — and re-run the shell test whenever a rate question comes up.
How do I stop the mapping breaking when another USB device is added?
Stop mapping by kernel name. Read the scanner's serial number with lsusb -v, then write a udev rule that matches that serial number and creates a fixed symlink such as /dev/scanner. Point the CmpSettings mapping entry at the symlink instead of ttyACM1, and reboot as usual. Enumeration order then stops mattering entirely: whichever connector the scanner uses, the symlink follows the device, and COM1 stays bound to the right reader.
The mapping is active but the PLC receives nothing — what is the next check?
Look at the scanner's output mode before the runtime. Many USB handhelds ship configured as HID keyboards: they type into whatever field has focus and never put data on the serial channel. Switch the scanner to its USB serial mode from its configuration menu or programming code sheet, then repeat the shell test. If the shell shows clean strings but the runtime still sees nothing, the COM index you wrote in the mapping and the port number your code opens disagree.


