EDIT
I found out what the problem was and have answered my own question.
Original question below this line
I have a serial bridge between COM4 and COM5 implemented in software (Specifically, HDD's Free Virtual Serial Configuration Utility)
I have two different python scripts starting up in two different instances of Powershell, receive first:
import serial
receive = serial.Serial(port = 'COM5', baudrate = 9600)
text = receive.read(100)
receive.close()
print text
And then the sender:
import serial
send = serial.Serial(port = 'COM4', baudrate = 9600, timeout = 0)
send.write("Hello")
send.close()
When starting the sender script, the receiver script gets the sent message (So communication is clearly established) but the sender script immediately ends with an error:
Traceback (most recent call last):
File ".\sending.py", line 3, in <module>
send.writelines("Hello")
File "C:\Python27\lib\site-packages\serial\serialwin32.py", line 270, in write
raise writeTimeoutError
serial.serialutil.SerialTimeoutException: Write timeout
I get the same error when I change the sender script to
send = serial.Serial(port = 'COM4', baudrate = 9600)
So my question is: What exactly is timing out? How do I prevent that from happening? I mean, the data IS being sent so I could probably just put the whole thing in a try/except(and do nothing) block but that seems like a bad solution in the long run.
The clue is in the error message[1]
File "C:\Python27\lib\site-packages\serial\serialwin32.py", line 270, in write
raise writeTimeoutError
so we open that file and find:
if self._writeTimeout != 0: # if blocking (None) or w/ write timeout (>0)
# Wait for the write to complete.
#~ win32.WaitForSingleObject(self._overlappedWrite.hEvent, win32.INFINITE)
err = win32.GetOverlappedResult(self.hComPort, self._overlappedWrite, ctypes.byref(n), True)
if n.value != len(data):
raise writeTimeoutError
Read that first conditional again:
if self._writeTimeout != 0:
so let us rewrite our code from before
send = serial.Serial(port = 'COM4', baudrate = 9600, timeout = 0)
becomes
send = serial.Serial(port = 'COM4', baudrate = 9600, writeTimeout = 0)
and Et Voila: No exception.
[1] Well Designed Error Messages? That's new!
The problem may be that the interface tries to comply with RTS, CTS, DSR, or DTS signals. It is possible that if they are not properly virtually connected, they can mysteriously affect communication through a timeout.
I would also recommend looking at the configuration of the used virtual serial bridge.
One solution may be to ignore influence using rtscts=False and/or dsrdtr=False when opening the serial port in Python.
I could use an alternative solution for sniffing communication using hub4com, where I used the parameter --octs = off, for example in this way, but the virtual ports had to be created correctly before. hub4com --baud=115200 --route=0:All --route=1:All --route=2:All --no-default-fc-route=All:All --octs=off \\.\COM1 \\.\CNCB0 \\.\CNCB1
Related
In windows 10 I am trying to read the output of an attached serial device.
Using hterm I am able to see the data on serial port COM5. So the serial port works fine.
Now using WSL2 (Ubuntu 20.04.3) I am running the following python script
import serial
ser = serial.Serial("COM5", baudrate=115200)
which fails with the error
Traceback (most recent call last):
File "test1.py", line 6, in <module>
ser = serial.Serial("COM5", baudrate=115200)
File "/usr/lib/python3/dist-packages/serial/serialutil.py", line 240, in __init__
self.open()
File "/usr/lib/python3/dist-packages/serial/serialposix.py", line 268, in open
raise SerialException(msg.errno, "could not open port {}: {}".format(self._port, msg))
serial.serialutil.SerialException: [Errno 2] could not open port COM5: [Errno 2] No such file or directory: 'COM5'
I also tried to use the suggestions posted in this article at attach the USB port on which the serial device is connected to, to WSL.
The command usbipd wsl list in a windows powershell shows then
8-3 0403:6001 USB Serial Converter Attached - Ubuntu-20.04
But when then running the same python code in WSL2 gives the same error.
So how to fix this problem so I am able to just read all data from the serial port with python?
You could try using the following script.
import serial
ser = serial.Serial("COM5", baudrate=115200, timeout=1)`
while True:
data = ser.readline()
print(data)
[EDIT] Code updated and tested as per locking remarks[/EDIT]
I generally use a solution where I just identify the port name from USB VID:PID data.
This allows me to not hard code any com port name.
You must begin searching for the port name corresponding to your USB device (see find_device() below).
You should also use locks on your serial port while reading so you don't get multiple concurrent accesses, which especially on Windows will create permission errors. See with LOCK context manager for locking the serial reads.
Code has been tested from Python 2.7 to 3.11 on both Windows and Linux.
Of course you can adapt the serial port settings and perhaps the size of read bytes and/or timeout.
import serial.tools.list_ports
import serial
from threading import Lock
# Your USB SERIAL DEVICE identification
USB_VID = "0x0403"
USB_PID = "0x6001"
SERIAL_SETTINGS = {
"baudrate": 115200,
"bytesize": 8,
"parity": "N",
"stopbits": 1,
}
LOCK = Lock()
def find_devices():
# type: () -> List[str]
"""
Find all COM ports corresponding to your USB device
"""
_device_ports = []
for port in serial.tools.list_ports.comports():
if port.vid == int(USB_VID, 16) and port.pid == int(USB_PID, 16):
_device_ports.append(port.device)
return _device_ports
def read_device(device) -> str:
# type: (str) -> str
try:
with LOCK:
with serial.Serial(device_port, timeout=1, **SERIAL_SETTINGS) as ser:
result = ser.read(size=64).decode('utf-8')
if len(result) == 0:
return None
else:
return result.strip("\r\n")
return result
except serial.SerialException as exc:
error_message = "Cannot read serial port {}: {}".format(device_port, exc)
print(error_message) # or log it
raise OSerror(error_message)
for port in find_devices():
data = read_device(port)
print(data)
Hope this helps.
More examples of serial reading can be found in a library I wrote for reading USB temperature sensors, see this
I personally would get this to work in Ubuntu 20.04.3 first.
Just download a Virtual Machine of Ubuntu, install it (in a VM environment (or real machine if you have one spare) ) and test.
WSLx is really good but it still has some teething problems.
If you know it passes in a real (or VM) Ubuntu install then you are most of the way there.
I always do this as WSLx can have some weird quirks I have found. It shouldn't for note but it does, especially when it comes down to external hardware.
Since you are using Ubuntu, you can't use the Port-Names used by Windows. In Ubuntu Port names usually are in the format of dev/ttyUSB followed by the number of the port (dev/ttyUSB0).
Trying to communicate with a McPherson 747 Device Controller for the Filter Wheel on a lab instrument. It is connected to the lab computer through RS232 to usb. I've connected and communicated with other devices through serial before.
It seems that for a read request, I need to send an enquiry and header and then the Device will acknowledge and send data.
The manual for the Device says that all data is exchanged in ASCII format. Though there are also a few tables in the manual that has inputs in Hex ASCII code. The manual says that a three-byte enquiry is Hex 4E2105 or text N!< ENQ >. Acknowledge is Hex 4E2106 or text N!< ACK > . The header is a mix of several Hex ASCII inputs for reading and writing based on what information the user wants.
The issue I am having is when I code the serial information and send the enquire input, it always sends an error due to communication with the device. I am unfamiliar with Hex. Do I need to be sending the entire enquire, headeras one input, or can I send them separately? I can also try to set up communication with PyVisa but I've gotten similar errors.
Through serial:
import codecs
import serial
try:
ser = serial.Serial(port='COM1',
baudrate = 9600,
timeout = None,
xonxoff = False,
parity = serial.PARITY_NONE,
stopbits = serial.STOPBITS_ONE,
bytesize = serial.EIGHTBITS,
)
ser.close()
string = '4E2105'
enquire = codecs.decode(string,'hex')
ser.open()
ser.write(enquire); #ascii intput for pressing enter on keyboard
ser.read_until(size=None) #reads out feedback until no data is left
ser.close()
msg = f"Program communication initialized"
print(msg)
except Exception as ex:
msg = f"Error: {ex}"
print(msg)
Error: could not open port 'COM1': FileNotFoundError(2, 'The system cannot find the file specified.', None, 2)
Through Pyvisa:
import pyvisa
import serial
import codecs
string = '4E2105'
enquire = codecs.decode(string,'hex')
rm = pyvisa.ResourceManager()
rm.list_resources()
# ('ASRL1::INSTR', 'ASRL2::INSTR', 'GPIB0::12::INSTR')
inst = rm.open_resource('asrl1::instr')
inst.write_termination='\r'
inst.read_termination='\r'
inst.baud_rate = 9600
inst.data_bits = 8
inst.parity = visa.constants.Parity.none
inst.flow_control = visa.constants.VI_ASRL_FLOW_NONE
inst.write(enquire)
print(inst.query("N!<ENQ>"))
rm.close()
VisaIOError: VI_ERROR_RSRC_NFOUND (-1073807343): Insufficient location information or the requested device or resource is not present in the system.
I'm new with the python language
I have a uart bluetooth dongle, I wrote this code below and the write method works fine because I can see the response using the gtkterm software
Code:
import serial
ser = serial.Serial()
ser.baudrate = 115200
ser.port = '/dev/ttyUSB0'
ser.open()
print(ser.is_open)
ser.write(b'info\r\n') # get info command
ser.write(b'scan=00\r\n') # start scan command
The response displayed in gtkterm software:
Device information
firmware: nrf_dongle
firmware_version: 0.2.5-ba519b3
firmware_build: 20180413-104249
device_name: amine
serial_number: a58f2080352ac55bd1850576df54
mac_address: d1850576df54
device_state: 1
adv_state: 0
scan_state: 0
END
#scan:d1850576df54,20fabb03c064,-71,2,30,0201041aff4c00021570996ffaa2c34f00b776a3852c4bbd790cb90006c2
#scan:d1850576df54,20fabb044b2c,-62,2,30,0201041aff4c000215023f3d601143013582ba2e1e1603bcb9ffff02e5c5
#scan:d1850576df54,20fabb044b51,-54,3,30,0201041aff4c000215023f3d601143013582ba2e1e1603bcb9ffff02c8c5
#scan:d1850576df54,20fabb044b2c,-62,2,30,0201041aff4c000215023f3d601143013582ba2e1e1603bcb9ffff02e5c5
.
.
.
So my question is how can I read this data using the pyserial module or any other approach ?
There are many approaches to this problem. First of all the question is - do you want to implement every detail yourself as an exercise? If so then you can implement a function that will read from the serial port one byte at the time, like so:
def readline(port):
message = ""
byte = ""
while True:
byte = port.read()
if byte == "\n":
break
message += byte
return message
It will stop reading from the port when the newline character is encountered and return the message so far. But be aware that there are some problems here (is the end-of-line character always "\n"? What if there is a timeout on the read function?)
Here is the link to the documentation about how the read function behaves. Note, that if the Serial object has not been set with a timeout the function will block, which means that it will wait for the incoming data from the serial port.
The PySerial documentation is a great source of information on the topic - they also provide an example for using the readline function that takes into account problems connected to the newline differences (end-of-line characters). Here is the example from the docs rewritten for your example:
import serial
import io
ser = serial.Serial()
ser.baudrate = 115200
ser.port = '/dev/ttyUSB0'
ser.open()
print(ser.is_open)
sio = io.TextIOWrapper(io.BufferedRWPair(ser, ser))
sio.write(b'info\r\n')
sio.flush() # it is buffering. required to get the data out *now*
response = sio.readline()
print(response)
I strongly suggest to look at the miniterm.py module that is supplied with the PySerial module. Although it might be quite hard at first it is in my opinion a good source of learning material to get accustomed with this library.
I set up a bluetooth connection between Raspberry and a computer. I wish to carry out a pilot icon which would allow me to check if connection is always present. For that I carried out a Thread. For the test, I sending a message on the link of the PC towards RPi, if the Rpi receive something , she reference me a message and if I receive it on my computer is that the connection is always present. The probelm is that I have an error at the time of the reception side PC.
Here the detail: The operation of E/S was abort because of the stop of a thread or the request of an application.
Here two codes for the connection series:
Pc side with VB :
Private Sub checkBT()
Dim buffer As String = ""
While True
BluetoothPort.Write("Test")
buffer = BluetoothPort.ReadLine()
While buffer = ""
buffer = BluetoothPort.ReadLine()
End While
WriteInLog("" & buffer)
checkBT_thread.Sleep(20000)
End While
End Sub
Rpi side with Python:
import serial
serial_com = serial.Serial("/dev/rfcomm0", baudrate = 115200, timeout = 0, writeTimeout = 5)
print "INIT Bluetooth connection"
while 1:
x = serial_com.readline()
if x == "Test":
print x
serial_com.write("Recu")
Do you have an idea about the problem please?
Can the error come owing to the fact that I use of Windows forms?
I solved my problem with the serialPort.ReadExisting() method.
I have gotten the Simulator to finally start communicating back to me (see past question); however, I do not know what it is saying to me. Here is a simple code that sends a message to the simulator.
`import serial
port = '/dev/tty.usbserial-PXFO5L2L'
baudrate = 9600
timeout = 1
ser = serial.Serial(port = port, baudrate = baudrate, timeout = timeout)
ser.write('VOLT:LEVEL 4')
`
This is supposed to set the voltage 4, but all it returns is 12. Along with other commands, they all return ints. Can anyone tell me what this means? Or if I am using the write command correctly?