import time import threading from eip import PLC _RISING = 1 _FALLING = 2 _ANY = 3 def waitForEdge(PLC, tagName, edgeType): ''' This waits for the appropriate edge to be seen from a boolean tag. Returns True when an edge is seen. Returns False on error. Will not return until the edge is actually seen. ''' # tags for tracking state changes oldVal = PLC.Read(tagName) newVal = oldVal if (edgeType == _RISING): while True: newVal = PLC.Read(tagName) # A rising edge occurs when the old state was False and the new state is True. if (newVal and not oldVal): return True # Retain the old state for the next loop. oldVal = newVal if (edgeType == _FALLING): while True: newVal = PLC.Read(tagName) # A falling edge occurs when the new state is False and the old state was True. if (oldVal and not newVal): return True # As always, retaining states. oldVal = newVal if (edgeType == _ANY): while True: newVal = PLC.Read(tagName) # Any edge is when the new state differs from the old state. if (oldVal != newVal): return True oldVal = newVal # If the edgeType wasn't valid, return False return False def waitForValue(PLC, tagName, targetValue): ''' This waits for the tag given to have a target value. Ex: wait for BoxesScanned to equal 100 This will return True when the tag reaches that value. ''' while (ret != targetValue): ret = PLC.Read(tagName) return True def waitForDuration(PLC, tagName, duration_ms): ''' This function is a glorified sleep call. The reason for its existence is so that a sleep call can happen with the same structure as the other waitFor* functions, for use in readOnTrigger and writeOnTrigger formats. ''' duration = duration_ms * 0.001 sleep(duration) return True def sendTrigger(PLC, tagName, duration_ms): ''' This writes a HIGH-LOW change to a given Boolean tag in the PLC. The tag will be held high for the given duration. ''' duration = duration_ms * 0.001 PLC.Write(tagName, True) sleep(duration) PLC.Write(tagName, False) def readOnTrigger(PLC, triggerTag, dataTag, triggerFunc, trigStateOrEdgeType): ''' Returns the value stored in dataTag when the trigger defined by triggerFunc and trigStateOrEdgeType is seen on triggerTag Later, we can add a dataAction argument, which defines what should be done with the data retrieved (put in database, etc) ''' # Note it is VERY IMPORTANT that trigger functions follow the structure someTriggerFunction(PLC, tagName, returnState) while True: triggerFunc(PLC, triggerTag, trigStateOrEdgeType) ret = PLC.Read(dataTag) print "New Data: " + str(ret) def writeOnTrigger(PLC, triggerTag, dataTag, triggerFunc, trigStateOrEdgeType, data): ''' Returns true when data has been written to dataTag, which will happen after the trigger is seen. Later, we can change the data argument to a function which fetches the data. ''' # Note it is VERY IMPORTANT that trigger functions follow the structure someTriggerFunction(PLC, tagName, returnState) while True: triggerFunc(PLC, triggerTag, trigStateOrEdgeType) PLC.Write(dataTag, data) print "Data Written: " + str(data) comm = PLC() comm.IPAddress = '192.168.16.51' comm.ProcessorSlot = 0 threads = [] threads.append(0) threads.append(0) # This is where we define each data transfer thread. When we move to fetch this as a configuration, we'll simply make this a loop that fetches each transfer definition and sets up a thread for it. # The name of each thread will be the ID in the configuration file. For now they're just arbitrary numbers. trigger1 = "Program:MainProgram.SendTrigger" data1 = "Program:MainProgram.RandStr" threads[0] = threading.Thread(name='1', target=readOnTrigger, args=(comm, trigger1, data1, waitForEdge, _RISING,)) trigger2 = "Program:MainProgram.RecvTrigger" data2 = "Program:MainProgram.TestData" #threads[1] = threading.Thread(name='2', target=writeOnTrigger, args=(comm, trigger2, data2, waitForEdge, _RISING, 'foo')) threads[1] = threading.Thread(name='2', target=readOnTrigger, args=(comm, trigger1, data1, waitForEdge, _RISING,)) # Start every thread for t in threads: t.start()