MrYsLab / PyMata

A Python client class library for Interaction with Standard Firmata
GNU Affero General Public License v3.0
95 stars 40 forks source link

What should happen when calling PyMata twice? #2

Closed Vido closed 10 years ago

Vido commented 10 years ago

I know it might make no sense for a real code. But should the second call (Thread-4) cause a exception on the first thread (Thread-2)?

Python 2.7.3 (default, Jan  2 2013, 13:56:14) 
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from PyMata.pymata import PyMata
>>> firmata = PyMata("/dev/ttyUSB0")
PyMata version 1.57  Copyright(C) 2013-14 Alan Yorinks    All rights reserved.

Opening Arduino Serial port /dev/ttyUSB0 
Please wait while Arduino is being detected. This can take up to 30 seconds ...
Board initialized in 1 seconds
Total Number of Pins Detected = 20
Total Number of Analog Pins Detected = 6
>>> firmata2 = PyMata("/dev/ttyUSB0")
PyMata version 1.57  Copyright(C) 2013-14 Alan Yorinks    All rights reserved.

Opening Arduino Serial port /dev/ttyUSB0 
Please wait while Arduino is being detected. This can take up to 30 seconds ...
Exception in thread Thread-4:
Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 552, in __bootstrap_inner
    self.run()
  File "/usr/local/lib/python2.7/dist-packages/PyMata/pymata_command_handler.py", line 684, in run
    data = self.pymata.command_deque.popleft()
IndexError: pop from an empty deque

Exception in thread Thread-2:
Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 552, in __bootstrap_inner
    self.run()
  File "/usr/local/lib/python2.7/dist-packages/PyMata/pymata_command_handler.py", line 716, in run
    method = dispatch_entry[0]
TypeError: 'NoneType' object has no attribute '__getitem__'

Board Auto Discovery Failed!, Shutting Down
MrYsLab commented 10 years ago

Thanks for the comment. If I understand what you are saying is that you first successfully start PyMata and then while it is running you try to open another session to the same serial port. Is that correct? If it is, I am unable to reproduce what you are seeing. If you can provide a description of exactly how you generated the error, I would happy to take a look. BTW, I am running PyMata 1.58, but I don't think that will change anything.

Here is my test scenario:

When I open an application that uses PyMata (I used the blink_pymata.py application but bumped the iterations up to 100) and after it is up and running, open another instance of this application (in a second command window), here is what I see:

  1. The first instance is up and running and merrily counting iterations. The second has not been started yet.
  2. I start the second instance. The first instance crashes because the second instance closed the serial port and pyserial in instance 1 can no longer successfully write to the port and pyserial issues an exception. The thread is not identified.
  3. Meanwhile, the second instance is trying to do a board discovery, but it's thread crashes because it no longer is receiving characters from the serial port (I am assuming here that pyserial shut things down).
  4. Eventually the discovery timer expires and exceptions for that are then thrown.

I do not see mention of thread 4 in my scenario.

Vido commented 10 years ago

@MrYsLab, yes you got it right.The behavior you described is the same here. But the way I can reproduce this does not uses blink_pymata.py.

You can reproduce by running:

on Shell:

$ virtualenv .env_pymata
$ source .env_pymata/bin/activate
(.env_pymata)$ pip install PyMata
# Downloading PyMata-1.58.tar.gz....

on Python:

# change "/dev/ttyUSB0" if necessary
>>> from PyMata.pymata import PyMata
>>> firmata = PyMata("/dev/ttyUSB0")
>>> firmata2 = PyMata("/dev/ttyUSB0")
MrYsLab commented 10 years ago

I didn't realize that you were running from the python interpreter and not a command line. This really is not a valid way of running, since normally a script would be run from the command line, and trying to attach to the same port twice is also an invalid test. I think the order of the exceptions being reported may not be accurate because of a possible race condition of when each of the command handler threads receives the exception condition, the timeout of each read timer and the time to process the exceptions.

I did test using 2 arduino boards at the same time. I opened two separate python interpreters and started PyMata for the serial ports associated with each board and there were no exceptions.

Please let me know if you think what you found was bug so we can discuss it further.

Thanks, Alan