I'm trying to read RFID cards with an RFID card reader plugged in USB on my raspi 3b+
Here is my code
ser = serial.Serial('/dev/tty1', 115200)
while True:
incomingByte = ser.read(10)
print(incomingByte.decode())
ser.flushInput()
ser.close()
When I scan a card, here is the output
0002429021
Which is what I expect. But after some time (few seconds) I have the following error message
line 45, in main
incomingByte = ser.read(10)
File "/usr/local/lib/python3.9/dist-packages/serial/serialposix.py", line 595, in read
raise SerialException(
serial.serialutil.SerialException: device reports readiness to read but returned no data (device disconnected or multiple access on port?)
So I've looked around and tried many things:
run raspi-config and under interfaces turn on serial, turn off console
Edit /boot/config.txt and add the line enable_uart=1
In /boot/cmdline.txt remove the references to console
Disabled getty sudo systemctl stop serial-getty#USB0.service
I've tried alternate codes:
**1/ with try...except
**
try:
incomingByte = ser.read(10)
print(incomingByte.decode())
ser.flushInput()
except Exception:
pass
==> I can read 1 card then the program get stuck (no errors but no more scan possible, prompt is stuck)
2/ with inwaiting() + try...except
while True:
while (ser.inWaiting()>0):
try:
incomingByte = ser.read(10)
print(incomingByte.decode())
ser.flushInput()
except (OSError, serial.serialutil.SerialException):
print("No data this time")
ser.close()
It outputs
No data this time
002429021
then the following error
line 549, in in_waiting
s = fcntl.ioctl(self.fd, TIOCINQ, TIOCM_zero_str)
OSError: [Errno 5] Input/output error
Note:
One of the main difference I see with many other people with similar code is that my rfid card reader is reachable on /dev/tty1 where I usually see /dev/ttyS1 or /dev/ttyAMA0 or /dev/ttyUSB0 or /dev/ttyACM0
I don't really know what's the difference between all of that but maybe it has an impact.
Thanks in advance for your help :)
Related
When I try to read data off of a microcontroller using PySerial, I get no response with the following code (a LoRa-E5 mini is atttached to my UART COM5 Port)
import serial
import time
print("serial test")
ser = serial.Serial()
ser.baudrate = 9600
ser.port = 'COM4'
ser.open()
print(ser.is_open)
ser.write("test".encode())
print("data received")
time.sleep(1)
numlines = 0
while True:
try:
ser_bytes = ser.readline()
decoded_bytes = float(ser_bytes[0:len(ser_bytes)-2].decode("utf-8"))
print(decoded_bytes)
except:
print("Keyboard Interrupt")
break
ser.close()
I just need to be able to read the data off of the LoRa E5 mini.
What could be done to remedy my probem?
Could be problem be that you read from the serial port line by line? Does your application in LoRa-E5 serial sends a line ending with \n?
You do not send line endings characters, and you open the serial port without timeout, which will result in the readline command blocking forever.
See readline doc.
readline() reads up to one line, including the \n at the end. Be careful when using readline(). Do specify a timeout when opening the serial port otherwise it could block forever if no newline character is received. If the \n is missing in the return value, it returned on timeout.
Default serial port parameters class serial.Serial
init(port=None, baudrate=9600, bytesize=EIGHTBITS, parity=PARITY_NONE, stopbits=STOPBITS_ONE, timeout=None, xonxoff=False, rtscts=False, write_timeout=None, dsrdtr=False, inter_byte_timeout=None, exclusive=None)
timeout = None: wait forever / until requested number of bytes are received
What you're not getting is how the LoRa-E5 is working: its AT firmware doesn't just spit out whatever it receives, but uses AT commands, and outputs hex-encoded strings. In the case of LoRa P2P, aka in the LoRa-E5 AT firmware "Test Mode", when the module receives a string it outputs +TEST: RX , followed by hex-encoded bytes. For instance, if you sent 012345, the incoming string will be +TEST: RX 303132333435.
So you need to take the hex part, decode it and THEN do your decoded_bytes = float(...).
And because it is AT firmware, sending meaningless strings like "test" won't do anything (especially when not terminated by CR/LF). If you want to make sure it is alive, send AT\r\n. You should at least then get a response: AT+OK\r\n.
I'm performing reads and writes with pyserial to a serial terminal running on a decawave DWM1001C. The serial connection goes from my Linux laptop to the device over a microUSB cable which also powers the device. The DWM1001C offers the serial connection internally on the chip. The connection is opened at the baudrate of 115200 with 8N1, as specified by the DWN1001C reference manual.
The problem I have is that when I call pyserial's write() on the serial device, I can only write a maximum of 7 characters per write call, sometimes as few as 4. Here's a minimal code to reproduce the issue:
import serial
import sys
import time
dev = "/dev/ttyACM0"
baudrate = 115200
try:
ser = serial.Serial(dev, baudrate, timeout=3)
except Exception as e:
print("Failed opening device: " + dev + ": " + str(e))
sys.exit(1)
try:
# Two CR's are required to open the terminal as the device default to "API" mode
ser.write(b"\r\r")
ser.flush()
time.sleep(2)
# only letters up to f are sent
ser.write(b"abcdefg hijklmn opqrstu vwxyz\n")
ser.flush()
time.sleep(2)
except Exception as e:
print("Failed writing instructions to device: " + str(e))
sys.exit(1)
while True:
try:
line = ser.readline()
if line == None:
continue
except Exception as e:
print("Failed reading from serial: " + str(e))
sys.exit(1)
s = line.decode("utf-8")
print("got data: " + s)
By using the readline() call and by monitoring the serial terminal over minicom, I have verified that only the 4-7 first characters appear in the terminal. Minicom can be used to interact with the serial terminal normally, so I assume minicom does something under the hood that this pyserial code doesn't.
I have a hacky workaround: Every time I perform writes, I split the input data into 4 character chunks and send them one-by-one over write(), then sleep for 0.1 seconds. This seems to work, but is likely about as platform specific as it can be.
The pyserial constructor takes a few different flow control flags and I tried setting each of them on independently. They are:
xonxoff=True
rtscts=True
dsrdtr=True
They didn't seem to do anything. I also tried lowering the baudrate to 57600 to no effect.
What should I read on to understand what's going on?
I have a Raspberry pi model B booted with Rasbian OS and a bluetooth dongle plugged into it. I am able to discover my pi when searching from my PC and am able to pair using Blueman GUI. This is the python program I am using for the pairing process:
from bluetooth import *
server_sock=BluetoothSocket(L2CAP)
server_sock.bind(("", 17))
with open(sys.path[0] + "/sdp_record.xml", "r") as fh:
service_record = fh.read()
self.bus = dbus.SystemBus()
self.manager = dbus.Interface(self.bus.get_object("org.bluez", "/"),"org.bluez.Manager")
adapter_path = self.manager.DefaultAdapter()
self.service = dbus.Interface(self.bus.get_object("org.bluez",adapter_path),
"org.bluez.Service")
service_handle = service.AddRecord(service_record)
print "Service record added"
server_sock.listen(1)
print("Waiting for connection on L2CAP")
try:
client_sock, client_info = server_sock.accept()
print("Accepted connection from ", client_info)
while True:
data = client_sock.recv(1024)
if len(data) == 0:
break
print("received [%s]" % data)
except IOError:
pass
except KeyboardInterrupt:
print "Stopping..."
stop_advertising(server_sock)
sys.exit()
print("disconnected")
client_sock.close()
server_sock.close()
print("all done")
I already have a working SDP record, which is being read and it is added to the SDP server.
At first when I posted this question I got this error:
Traceback (most recent call last):
File "pytest.py", line 4, in <module>
server_sock.bind(("", 17))
File "/usr/lib/python2.7/dist-packages/bluetooth/bluez.py", line 140, in bind
return self._sock.bind (addrport)
_bluetooth.error: (13, 'Permission denied')
This is because bluetooth needs root privileges. I ran the python code using sudo python code.py and this error was resolved. Thanks very much to guys who answered.
Now the problem I get is, the socket connection is not getting accepted even after pairing. For pairing, I run the code in one terminal and when it is waiting for connection on L2CAP, I open another console and pair the pi with my computer using the command sudo bluez-simple-agent hci0 computers_macaddress, it is getting paired after entering a pin in both the pi and computer. But after the pairing, the code is still waiting for connection:
Service record added
Waiting for connection on L2CAP
It seems to be looping at that server_sock.accept() function.
Can anyone give a solution?
I also faced the same kind of issue. The problem was with the operating power of the pi. USB ports usually provide only 500 mA, 5 V. Raspberry pi need a voltage source of about 4.75 to 5.25V and current in range of 700 to 1000 mA for optimum performance. Exactly how much current (mA) the Raspberry Pi requires is dependent on what you connect to it. Try changing the source, fetch power via a 1000 mA 5v adapter.
Let me know if it worked.
I am trying to write a very basic script which will allow me to have full control over a device via serial. I can send data (and I know the device receives it, leaving screen open on the device allows me to see the input appearing).
But I cannot receive data, with screen open, and inputting data via screen I get the error:
Traceback (most recent call last): File "serialRec.py", line 4, in
for line in ser: File "/usr/lib/python2.7/dist-packages/serial/serialposix.py", line 456, in
read
raise SerialException('device reports readiness to read but returned no data (device disconnected?)')
serial.serialutil.SerialException: device reports readiness to read
but returned no data (device disconnected?)
There is no error if I open the port waiting for a message without screen.
My application as I said sends data no problem... What can I do? How can I get this reading? I am running this script on a Ubuntu 12.04 installation... Screen works fine on the device the Ubuntu laptop is attatched to
The sys arguments are: argv[1] = device (/dev/ttyUSB0) and argv[2] = braud rate (e.g. 9600).
import serial
import sys
import time
def enterdata():
ser = serial.Serial(sys.argv[1], sys.argv[2])
scom = raw_input("type away:" )
incli = str(scom)
time.sleep(.2)
if (incli == "exit the app"):
print ("Exiting the data send, nothing was sent from the exit command")
else:
while True:
print ser.readline()
enterdata()
print ("Welcome to the serial CLI")
enterdata()
UPDATE:
I now have it working, but limited and ugly it prints the return on multiple lines from sending one command. Though for this I am going to try a few things out. I will post and share some nice working code once i get it to a good place.
import serial
import sys
import time
def enterdata():
ser = serial.Serial(sys.argv[1], sys.argv[2])
scom = raw_input()
incli = str(scom)
if (incli == "exit the app"):
print ("Exiting the data send, nothing was sent from the exit command")
else:
ser.write(incli+"\r\n")
time.sleep(0.5)
while True:
data = ser.read(ser.inWaiting())
if (len(data) > 0):
for i in range(len(data)):
sys.stdout.write(data[i])
break
ser.close()
enterdata()
print ("Welcome to the serial CLI, hit enter to activate:")
enterdata()
This is the changes I have made, it works. Though it seems to always print double or maybe send an extra character
You might want to try with a listener first, but you have to make sure that your device is sending data to your serial port at the correct baudrate.
import serial, sys
port = your_port_name
baudrate = 9600
ser = serial.Serial(port,baudrate,timeout=0.001)
while True:
data = ser.read(1)
data+= ser.read(ser.inWaiting())
sys.stdout.write(data)
sys.stdout.flush()
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