View unanswered posts | View active topics It is currently Tue Jun 18, 2013 7:47 pm



Reply to topic  [ 10 posts ] 
 Python help needed 
Author Message
User avatar

Joined: Nov 18, 2008
Posts: 1741
Location: Berkeley, CA
Post Python help needed
I have a class (ifkit) that handles all communications with a piece of external hardware. The method that starts and manages the communications is startPhidgetThread. While most of the work involves reading the data flow from the hardware and maintaining states of Indigo custom devices, there are times when I need to write to the external hardware.

So far, I have the process working for reading the data. The communication management class is called from plugin.py as:
Code: Select all
def runConcurrentThread(self):
    threadIfkit = threading.Thread(target=self.ifkit.startPhidgetThread, name='ifKit')
    threadIfkit.start()

Now, I want to create a plugin action to "write" to the hardware. There is a function defined in ifkit.startPhidgetThread called setOutput that does what I need. I can create the action and define a callback method in plugin.py called ikfitWrite. But, the problem I am having is getting the callback method to call setOutput and pass the two arguments it requires, or find some other means to execute the code contained in setOutput.

ifkit looks like:
Code: Select all
class ifkit(object):
   ########################################
   def __init__(self, plugin):
      self.plugin = plugin
      self.shutdown = False

   def __del__(self):
      pass
               
   ######################
   def startPhidgetThread(self):
      indigo.server.log('ifKit thread starting', type="Phidgets Plugin")
   
      def setOutputI(port, value):
          interfaceKit.setOutputState(port, value)

                def <Additional Communications functions>
                    ...

                while not self.shutdown:
               time.sleep(0.5)


Any ideas, pointers, suggestions, examples, etc. most appreciated.

EDIT: FWIW, all communications from the hardware are event driven and managed by lower-level interface code provided by the manufacturer. startPhidgetThread also contains callback methods that are invoked by the lower-level interface as needed. That is why I have the endless wait loop at the bottom, waiting for these callbacks, or, my action invocation..


Thu Jan 26, 2012 1:20 pm
Profile
Site Admin
User avatar

Joined: Mar 19, 2008
Posts: 6848
Location: Austin, Texas
Post Re: Python help needed
I think you'll want to look at the iTunes or EasyDAQ plugins - both use a queue object to pass commands from the plugin to the individual device threads. Then in the device thread's main loop you check for any commands that need to be sent to the hardware and send them.

_________________
Jay (Indigo Support)
Image


Thu Jan 26, 2012 2:16 pm
Profile WWW

Joined: Nov 25, 2010
Posts: 172
Location: UK
Post Re: Python help needed
The serial test plugin uses a queue method too. Very easy to mod.


Thu Jan 26, 2012 3:06 pm
Profile
User avatar

Joined: Nov 18, 2008
Posts: 1741
Location: Berkeley, CA
Post Re: Python help needed
Thanks Jay and Mat. I had looked at the EasyDAQ plugin, but was hoping there was a way to build on what I already have. The current architecture is built on top of a large body of code provided by the Phidgets manufacturer and it is pretty easy to use as it now exists.

I wouldn't think it should be that hard to either call a method defined in a thread, or send a message to a thread to do something. But, if I can't figure out how to do that, I guess I'll take a look at at queues again.


Thu Jan 26, 2012 3:11 pm
Profile
Site Admin
User avatar

Joined: Mar 19, 2008
Posts: 6848
Location: Austin, Texas
Post Re: Python help needed
Threads require some kind of IPC if you want one thread to talk to another. Queues are the easiest way and they're built-in to Python.

_________________
Jay (Indigo Support)
Image


Thu Jan 26, 2012 3:41 pm
Profile WWW

Joined: Nov 25, 2010
Posts: 172
Location: UK
Post Re: Python help needed
I'm no python expert. Only took my first look last week.

I've moded the serial plugin to remove the queue as my serial device is "input only", and it receives commands faster than a Nintendo player with 16 fingers can push buttons on my iPad.

If you use a queue method, watch CPU usage. I removed all the pauses in the serial test plugin code to send data without pausing between queue reads and 1 processor core sat at 98% for three days before I realised. Beginners mistake I guess.


Thu Jan 26, 2012 4:54 pm
Profile

Joined: Nov 25, 2010
Posts: 172
Location: UK
Post Re: Python help needed
This is what works for me. I don't claim to understand it but just followed the logic. As a really early beginner it works for me, but i'm sure it can be improved, even if I have pasted everything :lol: .

Code: Select all
   def sendSerialCommand(self, devId, command):
      dev = indigo.devices[devId]
      devProps = dev.pluginProps
      portName = devProps.get("serialPort")
      portBaudRate = devProps.get("portBaudRate")
      portParity = devProps.get("portParity")
      portDataBits = int(devProps.get("portDataBits"))
      portStopBits = int(devProps.get("portStopBits"))
      writeCommand = command
                conn = self.plugin.openSerial(dev.name, portName, baudrate=portBaudRate, parity=portParity, bytesize=portDataBits, stopbits=portStopBits, timeout=1, writeTimeout=1)
      sentCount = conn.write(writeCommand)


Thu Jan 26, 2012 5:13 pm
Profile
User avatar

Joined: Nov 18, 2008
Posts: 1741
Location: Berkeley, CA
Post Re: Python help needed
Thanks Mat. It is actually the queueing code that might interest me, and I took a look at an earlier version of your plugin to see what you did - similar to what Jay noted, but a little simpler because of the nature of your plugin. It helped a lot, thanks.

In my case, the communications is all via IP and is all handled by code that was provided, so all I have to do is call their code in a separate thread and wait for events to call functions in that thread. Very simple.

The problem I has was the occasional need to go the other way. I did find out how to send an event to a thread, but that was fairly limited. Though, it might work for you in place of managing a queue. The idea is you send a message to the thread saying an event has taken place. You cannot pass any data. So, the thread would then have to figure out what to do... probably read from some global variable or object. Klugy, and not well suited for multiple threads, but interesting none-the-less. Here is the URL where I could the information. Quite clearly presented.

For my case, it looks like a queue is the way to go, though I am still hoping for some way to directly call the function inside the thread.


Thu Jan 26, 2012 5:25 pm
Profile

Joined: Nov 25, 2010
Posts: 172
Location: UK
Post Re: Python help needed
No problem, but for the record, I didn't write the serial plugin, I just hacked it to bits to suit my needs. I can't take credit for the original!

Hope you sort it out.


Thu Jan 26, 2012 5:30 pm
Profile
User avatar

Joined: Nov 18, 2008
Posts: 1741
Location: Berkeley, CA
Post Re: Python help needed
I figured it out :D and it was actually pretty straight forward once I had the right model (which turned out to be a resettable timer).

The class is declared as:
class foo(threading.Thread):

and must have:
def __init__(... ...):
    threading.Thread.__init__(self)

Then I can declare all the methods I need, like
    def sendToComms(... ...)
plus the start method
    def run()
which starts things going, and stays open with a timer loop listening for events from the comms channel

Now, in the main plugin code I can start this thread by
self.myClass = foo(self, ... ...)
self.myClass.start()

and, anytime I need to send something to that thread I can just:
self.myClass.sendToComms(... ...)

No queues, no message passing. Now, In fact, since there will be multiple threads, I save the handles in a dictionary so I can grab the right one and talk to the correct thread. Like:
self.threadDict = {}
self.threadDict[dev.id] = foo(self, ... ...)
self.threadDict[dev.id] .start()

and then...
self.threadDict[dev.id].sendToComms(... ...)


Thu Feb 02, 2012 7:31 pm
Profile
Display posts from previous:  Sort by  
Reply to topic   [ 10 posts ] 

Who is online

Users browsing this forum: No registered users and 0 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.   Template designed by STSoftware.