Solution
The error only occurs on serial devices that use one of the following Linux kernel drivers:
cp210x — Silicon Labs CP2102 / CP210x USB-to-serial converters cdc-acm — USB CDC-ACM class devices, such as GNSS receivers, USB radio dongles, and certain modems
The cp210x driver claims to support TIOCGICOUNT ioctl but it fails to update the tx counter. The tx field counts how many bytes have been physically transmitted off the wire by the UART interrupt handler. NI-VISA polls TIOCGICOUNT waiting for the tx counter to increment until timer expires, which eventually causes viWrite to return with 0 written byte, regardless of how much data actually reached the device.
A workaround for this is to redirect the affected device through NI-VISA's existing cdc-acm fallback path by creating a /dev/ttyACM_* udev symlink. NI-VISA detects the ttyACM prefix in the device name and uses the tcdrain fallback in place of the broken counter-polling path, which allows the write call to return successfully.
Steps to the workaround:
- Identify the USB vendor and product ID of the affected device (Optional):
In a terminal, list the device attributes for the affected ttyUSB* or ttyACM* node.
bash
udevadm info -a /dev/ttyUSB? | grep -E 'idVendor|idProduct'
**Note the idVendor and idProduct values from the first matching block. For a generic Silicon Labs CP2102, these are typically 10c4 and ea60.
- Create a udev rule that adds a
/dev/ttyACM_* symlink:
Create a new udev rule file. Replace 10c4 and ea60 with the values from Step 1, and choose a descriptive alias (for example, GNSS, KAR, or cp210x) so each device is uniquely identified:
bash
sudo tee /etc/udev/rules.d/99-visa-acm-workaround.rules << 'EOF'
SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", SYMLINK+="ttyACM_cp210x%n"
EOF
**The %n placeholder is replaced by the kernel device index, which keeps the symlink unique when multiple identical devices are connected.
- Reload the udev rules and verify the symlink:
sudo udevadm control --reload-rules
sudo udevadm trigger
ls -la /dev/ttyACM_cp210x*
The output shows the new symlink pointing at the original device node, for example:
/dev/ttyACM_cp210x0 -> ttyUSB0
- Update the NI-VISA configuration file to use the new symlink:
Edit /etc/ni-visa/visaconf.ini. Locate the entry for the affected ASRL resource and change its SystemName value to the new symlink. Set the Enabled field of any duplicate entry that still references the original /dev/ttyUSB? path to 0 so it does not appear as a second resource.
ini
Name3="ASRL4::INSTR"
Enabled3=1
Static3=0
SystemName3= Change from "/dev/ttyUSB?" to "/dev/ttyACM_cp210x?"
BaudRate3=9600
Parity3=0
StopBits3=10
DataBits3=8
FlowCtrl3=0
- Restart LabVIEW:
Close LabVIEW (or any other NI application that holds the resource) completely, then relaunch it. The next VISA Write call on the resource returns without timing out, and writeCount reflects the bytes that were actually transmitted.