I have this code for sending file size from linux machine to embedded device:
#send length
device_port = serial.Serial("/dev/ttyUSB1", 115200, timeout=3)
device_port.write(program_length_str)
#get response
answer = device_port.readline()
if answer != "OK":
print "Size transmit failed:"
print `answer`
device_port.close()
quit()
The problem is that when I run this code (it always quits here) the programmer (which loads firmware to the device over the same serial port) quits with the bad file descriptor error. Replugging the device (no internal energy source in it) doesn't help, I have to reboot my computer. What is wrong with the Python code? How is it possible that the bad setting stays even when I replug the device (FT2232)?
Opening the port with cutecom enables programming the device, but when I close it again, the error is back.
UPDATE 1: Using strace I found out that first difference is in locks:
open("//var/lock/LCK..ttyUSB1", O_RDONLY) = 4 in the beginning of successfull load,
open("//var/lock/LCK..ttyUSB1", O_RDONLY) = -1 ENOENT (No such file or directory)
on failure. The second difference (and the whole error) may be bug in the loader, so I wrote on the toolchain forum (they consider read() returning 0 to be an error, call perror(), but there was no error, so EBAFD is stored in errno from earlier). But I am curious about the the locks. I couldn't find any reference in cutecom or python scripts (using strace), but the locks are affected somehow. Would it be possible to migrate this question to the Unix & Linux site?
UPDATE 2: As I mentioned before, the problem is that read() on the serial port returns 0. When I focused on this, I found out that read() should block or return EAGAIN in non-blocking mode. Under what circumstances the read() call can return 0?
UPDATE 3: I "resolved" the problem with the loader by wating for the device with the select() call. There is still the problem with PySerial changing something in the port.
I don't think your problem has anything to do with Python.
I faced the same problem when programming my Arduino using Ubuntu - sometimes, after a few times of plugging it in and unplugging it again, Ubuntu wouldn't recognize my device anymore. It then simply didn't show up in /dev/.
I guess that's also the source of your problems. bad file descriptor most like tells you that the path you specified doesn't actually exist. Have you checked /dev/ttyUSB0 ? If that doesn't work, I suggest to upgrade your installation to the newest one available.
I worked quite a lot with python serial and ubuntu, and the problem is about how ubuntu 'mount' serial ports, sometimes fails, and ...
could you post your dmesg output? this may help to double check the root of the problem.
Related
I have been looking for the answer for the error mentioned in the title but for the first time i haavent got an answer yet. We ll im trying to make my Raspberry pi read analog data but when i run the code in terminal window it gives me 'IOError: [Errno 5] Input/output error'.
The code im using to read analog data is shown below. Im using PCF8591 ADC converter.
from smbus import SMBus
bus = SMBus(0)
print "read a/d press ctrl + c to stop"
bus.write_byte(0x48, 0)
lastval = -1
while True:
reada = bus.read_byte(0x48)
if(abs(lastval-reada) > 2):
print(reada)
lastval=reada
I understand it might be because of the version changed in raspberry pi and i should change SMBus(0) to SMBus(1). For this i checked my RPi version which is not the revised one. But still I tried to run the program by changing the SMBus number, still no luck with it.
The error I get is shown below:
Traceback (most recent call last):
File "analogread.py", line 7, in <module>
bus.write_byte(0x48, 0)
IOError: [Errno 5] Input/output error
Any help is appreciated. This is the basic block in my bigger project which im trying to execute. So, the fas thinster i get thing working the better i can build my application.
Thank you
The cause to this might be that you're working remotely (SSH).
After you disconnect the remote session, your program is still working and could try to print or interact to console, which is not available any more. This is what happened to me.
While this thread is old, I want to share my resuly hoping someone else might be helped as all posts I came across did not mention this potential fix.
I was encountering a similar issue, but with different hardware (MCP23017 and an LCD).
After chasing the problem for some time, I found the problem was not software, but rather hardware. Specifically the pull up resistors on the SCL and SDA lines.
The RPI (3 in my case) has 1.8k resistors and my LCD had some pull up resistors installed as well (~2.2k). Running the LCD never had a problem, but the MCP23017 would randomly disappear from the bus and reappear when running a scan by issuing command "i2cdetect -y 1".
Removing the extra pull up resistors on the LCD fixed the problem and all works perfectly now.
These errors might be beyond programmer's control, caused by a random, yet usual, event.
One approach would be to try a couple of times before following with the error:
def try_io(call, tries=10):
assert tries > 0
error = None
result = None
while tries:
try:
result = call()
except IOError as e:
error = e
tries -= 1
else:
break
if not tries:
raise error
return result
try_io(lambda: bus.write_byte(0x48, 0))
The cause to this might be that you're pushing out the read/write calls faster than your hardware can accept them. So add small delays between read/write operations:
from time import sleep
from smbus import SMBus
bus = SMBus(0)
bus.write_byte(0x48, 0)
sleep(0.2) # Wait for device to actually settle down
lastval = -1
while True:
reada = bus.read_byte(0x48)
if(abs(lastval-reada) > 2):
print(reada)
lastval=reada
sleep(0.2) # This might be not needed.
Another possibility is that device is not actually present in this address. So if the timeouts don't help, try out i2c-tools (should be available via package management, unless you're using a custom software distribution) to check whether the device is actually available (sometimes it could be a wiring issue like forgotten GND):
i2cdetect -y [bus number]
Why i2c? Because SMBus is basically a modification of i2c bus with more strictly defined voltage levels and timings.
I experienced this problem when driving a 7-segment serial display over I2C with a model b+ rpi. I corrected the problem by adjusting the baud rate to match the device setting (9600). I believe the default is 100000.
To change the baud rate, I added the following line to /etc/modprobe.d/i2c.conf:
options i2c_bcm2708 baudrate=9600
After reboot, I verified the setting had taken effect with:
prompt$ sudo cat /sys/module/i2c_bcm2708/parameters/baudrate
9600
Since then, I've had no problems with intermittent I/O errors.
I know this topic is quite old but the same error occured with I2C and PCA9685 when I put values that were not in range. The way I figured it out was just simply disabling and enabling I2C:
sudo raspi-config
'5. Interfacing options'
'P5 I2C'
'No'
'OK'
sudo reboot now
sudo raspi-config
'5. Interfacing options'
'P5 I2C'
'Yes'
'OK'
sudo reboot now
After that, sudo i2cdetect -y 1 detects my I2C PWM module back again.
I had a similar problem in reading large volume csv file remotely (from the server) where I was connecting to workstation remotely and I was trying to read large size csv file from the Server. I copied the files to workstation that consequently 'IOError: [Errno 5] Input/output error' was resolved. I had a MemoryError after it that I resolved it by chunk reading and then converting to dataframe by pd.concat.
The code is as follows:
chunk=pd.read_csv(CSV_File_Loc,chunksize=1000000,low_memory=False)
DF_CSV=pd.concat(chunk)
I had the same problem in a RasPi -> ATMEGA communication and I resolve it on the slave. This error message occurs if your slave doesn't respond.
I tried the following code on RasPi, with an I2C slave connected on the I2C bus and configured with the 0x8 address :
from smbus import SMBus
I2C_Bus = SMBus(1)
SLAVE_ADD = 0x8
I2C_Bus.write_byte(SLAVE_ADD, 0xAA)
Providing the I2C slave is well configured to acknowledge, it should work!
The issue is old, but according to me very actual!
The solution(for RPi 3B+) is to set ALT0 mode for the GPIO at pin 3 & 5 (physical).
This can be done with the gpio command line tool:
gpio mode 8 alt0
gpio mode 9 alt0
8 and 9 as these are the numberings used by wiringpi for physical pin 3 & 5.
And this is exactly the issue... it uses wiringpi.
http://wiringpi.com/wiringpi-deprecated/
In my python code I could create a system call to those 2 commands (for me it works!)
However I would like a solution which does not use deprecated libs or tools.
Anyone?
In my case there was print statement that was causing this issue, I just removed that print statement and now that issue has been resolved for me.
I am having problems with sending triggers from a 32 bit PC with Windows XP Professional and Psychopy v.1.81.03 to the parallel port.
I am positive that the port address is 378, and am able to send triggers with Eprime and I am able to turn specific pins on and off with the software parmon (http://english.eazel.com/lv/group/view/kl35264/Parmon.htm)
I have tried using the experiment posted by Stéphanie and Nicholas (see this post in the psychopy google group: https://groups.google.com/forum/#!topic/psychopy-users/PxPhRDkuu2A)
I have verified that pywin32 (version 217) and parallel are installed, and tried both
port = parallel.ParallelPort(address=0x0378)
port = parallel.PParallelInpOut32(address=0x0378)
When using ParallelPort, I get:
Traceback (most recent call last):
File “ D:\SebastianKorb\untitled2_lastrun.py”, line 65, in
port = parallel.ParallelPort(address=0x0378) AttributeError: ‘module’
object has no attribute ‘ParallelPort’
Line 65 is where the command port = parallel.ParallelPort(address=0x0378)
is executed (note though that before that there is the line from psychopy import parallel)
When using PParallelInpOut32 I get the same (only now the error is about ‘PParallelInpOut32’)
I also tried to run the few lines of code shown on the psychopy reference manual (http://www.psychopy.org/api/parallel.html):
from psychopy import parallel
port = parallel.ParallelPort(address=0x0378)
port.setData(4)
port.readPin(2)
port.setPin(2, 1)
But again, I get the same type of error.
I should mention that I have also verified that I have administrator access to the file C:\Windows\system32\drivers\parport.sys
Can you please advise me on what I should try next?
I overlooked that it's actually the other way around. The direct calls to the parallel-port functions (as below) are deprecated. Nevertheless, they should still work. So maybe give it a try:
from psychopy import parallel
parallel.setPortAddress(0x378) #address for parallel port on many machines
parallel.setData(0) #sets all pins low
parallel.setPin(2,1) # set a certain pin high
parallel.setData(0) #sets all pins low
You should leave the pin high for a while or leave out the last line. Otherwise, you won't be able to detect the change. That's also how it is done in the Coder hardware demo "parallelPortOutput.py". Maybe try this first.
Best,
Axel
Addition:
Sebastian, my hunch at the moment is that the port does not even get initiated. I think the problem at the moment is that the respective error messages are only logged, but no informative error message is thrown (check the log files). That means that actually somehow the port drivers cannot be accessed on your system for some reason.
In the Coder Shell type from psychopy import parallel and then do next port = parallel.ParallelPort() (no address). Now just type port and paste the output here. My guess is that you only get the base class (ParallelPort) with which you cannot do anything, i.e., something like <psychopy.parallel.ParallelPort object at 0xe4805b0>. In that case, you would need to fix access to the drivers somehow.
I'm gong to back Axel's "hunch" here. I think it's extremely likely that either you don't have a parallel port driver installed or it isn't working. Try installing the InpOut32 driver from here, restart your computer and see if that fixes it:
http://www.highrez.co.uk/Downloads/InpOut32/
cheers,
Jon
I'm having trouble reading the response from a RS232 OBD2 interface via pySerial.
The code successfully enters the data, as I can see from a direct parallel terminal screen, but fails to read and print the response, regardless of the response.
Right now the code is not capable of printing the response in neither versions of Python.
The code looks something like this :
from serial import * # I also tried using /from serial import Serial
import time
ser = Serial("/dev/rfcomm1", 38400, timeout=1)
#print ('Starting up, formatting responses')
#ser.write("ATZ\r"),
#ser.write("ATSP0\r"),
#ser.write("ATS1\r"),
#ser.write("ATL1\r"),
#ser.write("ATH1\r"),
#ser.write("ATF1\r")
#time.sleep(1)
#print ('We have lift-off !')
if ser.inWaiting() > 0:
ser.flushInput()
#ser.timeout = 1.
time.sleep(1)
#print (raw_data)
ser.write("AT RV\r") #The response should be something like 13.5V, but nothing
ser.timeout = 1.
msg = ser.read(size=1024)
print msg
ser.close()
I left only the AT RV command because while I'm working on it I sent the text formatting commands to ease the job. Right now when I send it it just gives me a blank line (although the terminal which is running on the same machine displays the desired output)
There are no errors in the code, and the commands go through and are responded to by the interface, and I can see that in another live term, but nothing appears when running the Python code.
What should I do ?
You should read after writing, not before.
# before writing anything, ensure there is nothing in the buffer
if ser.inWaiting() > 0:
ser.flushInput()
# set the timeout to something reasonable, e.g., 1 s
ser.timeout = 1.
# send the commands:
ser.write("ATZ\r")
# ...
# read the response, guess a length that is more than the message
msg = ser.read(1024)
print msg
# send more commands
# read more responses
# ...
The point here is that there is no way to know when the response has been received. This code waits for one second after each command sent, unless more than 1024 bytes arrive during that time. There are more clever algorithms, but let's try with this one, first.
If you want to do something more complicated with the serial line, have a look at the pexpect module.
Some thoughts debugging python serial problems
Serial communication problems are sometimes a bit sticky to solve. pySerial is a reliable library, but as different platforms have different types of serial API, there are a lot of details. Things have not become any easier by the removal of physical serial ports, as the USB converters bring an extra layer into the game. Bluetooth converters are even worse.
The best way to debug the physical layer is to have some monitor hardware with two serial ports tapped into the serial lines. This kind of sniffer helps to isolate the problem to either end of the connection. Unfortunately, such sniffers are very rarely at hand when needed.
The next best thing is to short the RD and TD (RXD, TXD) pins of the serial line. This way all data will be echoed. If the data is received as sent, the physical connection is good. One thing to take care is handshaking. If you do not know what you are doing, disable all flow control (xon/xoff, rts/cts, dtr/dsr. pySerial disables these all if otherwise instructed.
In the case of the question above the physical connection is ok, as another piece of software demonstrates that the data is sent and understood by the other device. (Seeing that something is sent does not prove anything, as that information does not go through the physical layer, but seeing something produced by another device is received proves that the physical connection is ok.)
Now we know the data comes into the operating system, but pySerial does not see it. Or then our code is still somehow bad (no, it shouldn't, but...)
Let us suspect own own code and try someone else's code. This can be run from command prompt:
python -m serial.tools.miniterm /dev/rfcomm1 38400
Now we have a terminal which can be used to manually send/receive data form the other party. If the behaviour can be repeated (sends ok, data is received into the system, but not shown on the terminal) with this, then the problem is probably not in our code.
The next step then is to try:
sudo python -m serial.tools.miniterm /dev/rfcomm1 38400
In principle access right problems lead to situations where we can receive but not send. But it does not harm to test this, because odd rights cause odd problems.
pySerialhas a handy function readline which should read one line at a time from the serial line. This is often what is wanted. However, in this specific case the lines seem to end with \r instead of \n. The same may be repeated elsewhere in code, so with special data special care is needed. (The simple "read with timeout" is safe but slow in this sense.) This is discussed in: pySerial 2.6: specify end-of-line in readline()
The same issue plagues all terminal programs. For the pySerial miniterm, see its documentation (command-line option --cr).
If there are timeouts, they can and should be made longer for debugging purposes. A one-second timeout may be changed into a ten-second timeout to make sure the other device has ample time to answer.
I had exactly the same problem, through Python 2 IDLE no results displayed on the IDLE screen, but the results were redirected to picocom active at the terminal. I needed to capture results because my goal is to read incoming SMSs.
The following code solved my problem, I do not know the reason yet, ongoing analysis.
import time
import serial
modem1 = serial.Serial("/dev/ttyUSB3",baudrate=115200,timeout=0,rtscts=0,xonxoff=0)
def sendat1(cmd):
if cmd == 'res' : modem1.write('Z'); return
if cmd == 'out' : modem1.write(chr(26)); return
modem1.write('AT+'+cmd+'\r')
time.sleep(3)
obu = str(modem1.inWaiting())
msg = modem1.read(32798)
print(obu+':\n'+msg)
return
try:
if modem1.inWaiting()>0: modem1.flushInput()
sendat1('res')
sendat1('CMGF=1')
sendat1('CMGL')
sendat1('out')
finally:
modem1.close()
I have a raspberry pi (I'm using linux) and a device that measures some values.
I have a python server and when a client sends a "I want the values" command, I ask the device some values. This is the function for my device:
def usbDevice:
dev = usb.core.find(idVendor=0xXXXX, idProduct=0xXXXX)
if dev is None:
return 'Not found'
dev.set_configuration()
dev.write(1, '\x05', 0) # ask for the values
time.sleep(2)
ret = dev.read(0x81,2048 , 0,1200) # endpoint, siz, interf, timeout ->meas. vals
print ret
return ret
When I start the communication it always goes well (both ways, I send the command and I get the
proper response ...).However, the second time I try it (no matter if I wait too long or not) I'm getting no response from the device. I know I can send the request (I used a print "step XX" to see where it is failing), but I get no answer... I am usually getting a timeout exception, but sometimes getting a "resource busy" exception.
Should I close the usb communication after using it the first time? How? Despite, I'm always compiling with sudo permissions, I created a .rules file, so I think there's not the problem.
Apart from this, I would really like to know if something's wrong with this way to establish the USB communication as I used something similar in the past. ( and I'm not good with python...)
Can you provide additional information such as the linux distribution and kernel number e.g.
uname -a
There are known USB issues. The good news is that a recent fix may have resolved them. Basically, use rpi-update and it should update the kernel (you want at least #389).
I wrote a simple python program to play and pause banshee music player.
While its working on my own machine, I have trouble doing it to a remote computer, connected to the same router (LAN).
I edited the session.conf of the remote machine, to add this line:
<listen>tcp:host=localhost,port=12434</listen>
and here is my program:
import dbus
bus_obj=dbus.bus.BusConnection("tcp:host=localhost,port=12434")
proxy_object=bus_obj.get_object('org.bansheeproject.Banshee',
'/org/bansheeproject/Banshee/PlayerEngine')
playerengine_iface=dbus.Interface(proxy_object,
dbus_interface='org.bansheeproject.Banshee.PlayerEngine')
var=0
while (var!="3"):
var=raw_input("\nPress\n1 to play\n2 to pause\n3 to exit\n")
if var=="1":
print "playing..."
playerengine_iface.Play()
elif var=="2":
print "pausing"
playerengine_iface.Pause()
This is what i get when i try to execute it
Traceback (most recent call last):
File "dbus3.py", line 4, in <module>
bus_obj=dbus.bus.BusConnection("tcp:host=localhost,port=12434")
File "/usr/lib/python2.7/dist-packages/dbus/bus.py", line 125, in __new__
bus = cls._new_for_bus(address_or_type, mainloop=mainloop)
dbus.exceptions.DBusException: org.freedesktop.DBus.Error.NoServer: Failed to connect to socket "localhost:12434" Connection refused
What am I doing wrong here?
should i edit /usr/lib/python2.7/dist-packages/dbus/bus.py
UPDATE:
ok, here is the deal
when i add
<listen>tcp:host=192.168.1.7,port=12434</listen>
to to /etc/dbus-1/session.conf, then reboot, hoping it would start listening on reboot,
It never boots. It gets stuck on loading screen and occasionally, a black screen with the following text flashes:
Pulseaudio Configured For Per-user Sessions Saned Disabled;edit/etc/default/saned
so, when i go ctrl+alt+f1 , change session.conf to original state and reboot, it boots properly.
Whats all that about?
How can I make dbus daemon listen for tcp connections, without encountering problems?
I recently needed to set this up, and discovered that the trick is: order matters for the <listen> elements in session.conf. You should make sure the TCP element occurs first. Bizarre, I know, but true, at least for my case. (I see exactly the same black screen behavior if I reverse the order and put the UNIX socket <listen> element first.)
Also, prepending the TCP <listen> tag is necessary, but not sufficient. To make remote D-Bus connections via TCP work, you need to do three things:
Add a <listen> tag above the UNIX one, similar to this:
<listen>tcp:host=localhost,bind=*,port=55556,family=ipv4</listen>
<listen>unix:tmpdir=/tmp</listen>
Add a line (right below the <listen> tags is fine) that says:
<auth>ANONYMOUS</auth>
Add another line below these that says:
<allow_anonymous/>
The <auth> tag should be added in addition to any other <auth> tags that may be contained in your session.conf. In summary, your session.conf should contain a snippet that looks like this:
<listen>tcp:host=localhost,bind=*,port=55556,family=ipv4</listen>
<listen>unix:tmpdir=/tmp</listen>
<auth>ANONYMOUS</auth>
<allow_anonymous/>
After doing these three things, you should be able to connect to the session bus remotely. Here's how it looks when specifying a remote connection in D-Feet:
Note that, if you want to connect to the system bus, too, you need to make similar changes to /etc/dbus-1/system.conf, but specify a different TCP port, for example 55557. (Oddly enough, the element order appears not to matter in this case.)
The only weird behavior I've noticed in this configuration is that running Desktop apps with sudo (e.g., sudo gvim) tends to generate errors or fail outright saying "No D-BUS daemon running". But this is something I need to do so rarely that it hardly matters.
If you want to send to a remote machine using dbus-send, you need to set DBUS_SESSION_BUS_ADDRESS accordingly, e.g., to something like:
export DBUS_SESSION_BUS_ADDRESS=tcp:host=localhost,bind=*,port=55556,family=ipv4
This works even if the bus you want to send to is actually the system bus of the remote machine, as long as the setting matches the TCP <listen> tag in /etc/dbus-1/system.conf on the target. (Thanks to Martin Vidner for this tip. Until I stumbled across his answer to this question, I didn't believe dbus-send supported remote operation.)
UPDATE: If you're using systemd (and want to access the system bus), you might also need to add a line saying ListenStream=55557 to /lib/systemd/system/dbus.socket, like so:
[Socket]
ListenStream=/var/run/dbus/system_bus_socket
ListenStream=55557 # <-- Add this line
UPDATE2: Thanks to #altagir for pointing out that recent versions of D-Bus will enable AppArmor mediation on systems where it's available, so you may also need to add <apparmor mode="disabled"/> to session.conf/system.conf for these instructions to work.
since dbus 1.6.12 (e.g. kubuntu 13.10), your connection will also be rejected unless you add to your dbus config file (either /etc/dbus-1/mybus.conf or the interface requiring remote access i.e. system.d/my.interface.conf)
<apparmor mode="disabled"/>
UPDATE: After struggling to create a apparmor profile allowing the service to connect to the custom dbus-daemon, it seems the connection is always rejected due to a bug in DBUS... So for now we MUST disable apparmor whenever you use tcp=... Bug fix targetted for 14.04
I opened a bug at bugs.launchpad.net following discussion here with Tyler Hicks:
The AppArmor mediation code only has the ability to check peer labels
over UNIX domain sockets. It is most likely seeing an error when
getting the label and then refusing the connection.
Note:
the disable flag is not recognized by dbus < 1.6.12, so you need to package different versions of mydaemon.conf depending on systen), else dbus-daemon will fail on launch if no apparmor... I used for now in my CMakeLists.txt :
IF(EXISTS "/usr/sbin/apparmor_status")
install(FILES dbus_daemon-apparmordisabled.conf RENAME dbus_daemon.conf DESTINATION /etc/dbus-1/ )
ELSE (EXISTS "/usr/sbin/apparmor_status")
install(FILES dbus_daemon.conf DESTINATION /etc/dbus-1/ )
ENDIF(EXISTS "/usr/sbin/apparmor_status")
Another thanks #Shorin, and another FYI - I had to do something like this to make mine work:
<listen>tcp:host=localhost,bind=0.0.0.0,port=55884</listen>
Note the bind=0.0.0.0 - the bind=* didn't work for me, and I left out the family=ipv4 part. I'm on Ubuntu 12.04. I did use netstat on the remote machine to confirm dbus was listening on the port and telnet from local to confirm the port was open.
netstat -plntu | grep 55884
tcp 0 0 0.0.0.0:55884 0.0.0.0:* LISTEN 707/dbus-daemon
You have to see something like 0 0.0.0.0:55884 and not something like 0 127.0.0.1:55884.