#!/usr/bin/env python #-*- coding: iso8859-15 -*- ########################################################## # EVENTS v1.0 # ########################################################## # Author: Juan Miguel Taboada Godoy # # Date: Malaga, 20th Agosto 2007 # # Description: Class that control events # # Version: 2007082000 # # # # Codigo fuente bajo licencia GNU/GPL # # Centrologic (Computational Logistic Center) # # http://www.centrologic.com - info@centrologic.com # ########################################################## # Libraries {{{1 import time from TAD import Stack from FILTER import extendvalue # }}}1 # ### EVENTS ### ############################################# ## \internal ## Clase base ## \version 20/08/2007 1750 Malaga class EVENTS: # Constructor {{{1 ## Constructor ## \param self - def __init__(self,signals=[]): # Save the list of signals self.__signals=signals # Create the structure to store information self.__variables=[] # Create the structure to store events self.__events=[] # Create the structure for data self.__data=[] # }}}1 # Translate positions of memory {{{1 ## Translate positions of memory ## \param self - ## \param position Position of memory ## \param analogdigit Is analogic or digital def __translate(self,position,analogdigit): # Break the position splitposition=position.split(",") if (len(splitposition)>1): # Get slot and pin (slot,pin)=splitposition # If is analogic is counting in a different way if (analogdigit=='a'): slot_pins=8 else: slot_pins=16 # Return the position of memory return (slot_pins*int(slot)+int(pin)) else: # Normal address, return it normally return position # }}}1 # Add a variable to the class {{{1 ## Add a variable to the class ## \param self - ## \param name Name of the variable ## \param ecuation Ecuation that define the contect of this variable def addvariable(self,name,ecuation): # Check if wasn't declared before here for (tname,tecuation,tswap,tstatus) in self.__variables: if (tname==name): raise IOError,"The class of events detected an error: name of the variable duplicated or already in use" # Check if wasn't declared before in signals if ((self.__signals.search(None,name))[1]!=None): raise IOError,"The class of events detected an error: name of the variable duplicated or already in use" # Clean the ecuation from spaces clean_ecuation="" lastspace=True for character in ecuation: if ((character!=" ") or (not lastspace)): clean_ecuation="%s%s" % (clean_ecuation,character) lastspace=(character==" ") else: lastspace=True if (clean_ecuation[-1]==" "): clean_ecuation=clean_ecuation[0:-1] # Save the name, ecuation, swap and status self.__variables.append((name,clean_ecuation,{},0)) # }}}1 # Get variable {{{1 ## Get variable value ## \param self - ## \param name Name of the variable def getvariable(self,name): for (varname,ecuation,swap,value) in self.__variables: if (name==varname): return value return None # }}}1 # Get data of some signal {{{1 ## \param self - ## \param name Name of the signal def getsignal(self,name): # Get data data=self.__data # Get the signal (senalid,tempname,telemando,descripcion,tiposenal,conector,param1,param2)=self.__signals.search(None,name) # If not found return no value if (tempname==None): return None # Break the conector (type,position)=conector.split(":")[0:2] neoposition=self.__translate(position,tiposenal) for (tempposition,temptype,value) in data: if ((str(position)==str(tempposition) or (str(neoposition)==str(tempposition))) and (type==temptype)): return value # Return no value return None # }}}1 # Get value {{{1 ## Get the value from variable and signals or make a float from it ## \param self - ## \param string def getvalue(self,name): # Get variable value=self.getvariable(name) # Variable not found if (value==None): # Find the signal value=self.getsignal(name) # Signal not found if (value==None): # Try to make it a number thanks to the calculater fo extended values try: value=extendvalue(name) except: raise IOError,"I tried to convert %s to a float, but it is not possible. Check the ecuation." % (name) return value # }}}1 # Add an event {{{1 ## Add an event ## \param self - def addevent(self,variable,controller,*arguments): # Save the event self.__events.append((variable,controller,arguments)) # }}}1 # Process all the data {{{1 ## Process all the data ## \param self - ## \param data List of data in this moment def process(self,data): # Save the data in the class self.__data=data # New data to be given to the class newdata=[] # For all variables update them status (not dinamically, all will change on the same moment) newvariables=[] for (name,ecuation,swap,value) in self.__variables: # Calculate the new value and get the new swap (swap,value)=self.__calculate(ecuation,swap) # Save the new status of the variable newvariables.append((name,ecuation,swap,value)) # Save the new enviroment of variables (all together) self.__variables=newvariables # For all events check if they should be launched for (variable,controller,arguments) in self.__events: # Get the value of the variable value=self.getvariable(variable) # Check if the event needs to act if (value): # Give to the controller the arguments controller.start(self,*arguments) # Return the new data to be given to this class return newdata # }}}1 # Operate {{{1 ## Operate ## \param self - ## \param value1 Value 1 ## \param operator Operator ## \param value2 Value 2 def __operate(self,value1,operator,value2): if ((value1==None) or (value2==None)): return None else: return eval("value1 %s value2" % (operator)) # }}}1 # Calculate an ecuation {{{1 ## \internal ## Calculate an ecuation ## \param self - ## \param ecuation Ecuation ## \param swap Internal use of the variable (keep information inside) def __calculate(self,ecuation,swap): # Split the ecuation in tokens tokens=ecuation.split(" ") # Check if brakets are balanced {{{2 parenthesis=0 for token in tokens: # Check open and closing of brakets if (token=='('): parenthesis=parenthesis+1 elif (token==')'): parenthesis=parenthesis-1 # Detect if we closed some parenthesis that wasn't opened before if (parenthesis<0): raise SyntaxError,"During the ecution I found closed parenthesis that were not opened before" # Check we did not leave parenthesis without closing if (parenthesis>0): raise SyntaxError,"Parenthesis are not balanced, there are %s parenthesis that have not been closed." % (parenthesis) # }}}2 # Filter the words of the ecuation (time, count) {{{2 filtered_tokens=[] itime=1 icount=1 for token in tokens: # Check if token has a reserved word if (token.upper()=="TIME"): # Add the index to this time newtoken="TIME#%s" % (itime) itime+=1 # Save the new token in swap if (not newtoken in swap): swap[newtoken]=None elif (token.upper()=="COUNT"): # Add the index to this count newtoken="COUNT#%s" % (icount) icount+=1 # Save the new token in swap if (not newtoken in swap): swap[newtoken]=(0,False) else: # Don't change anything newtoken=token # Save the token filtered_tokens.append(newtoken) # }}}2 # Inicialize variables read_data=True acumulator=0 operator="+" parenthesis=Stack() # For all tokens for token in filtered_tokens: # Startup the jumper to compute always jump=False # Check parenthesis {{{2 if (token=='('): # Opening parenthesis found, check we are ready to read a data (equiv: read_data) if (not read_data): raise SyntaxError,"Opening parenthesis found when I was waiting for a operator: it can not be opened a parenthesis after a value, it is necesary to say how is going to be operated this value." else: # If the parenthesis ir right, save the status parenthesis.push((acumulator,operator)) # Inicialize a new status acumulator=0 operator="+" # Don't compute anything on this step jump=True elif (token==')'): # Closing parenthesis found, check we are ready to read an operator (equiv: not read_data) if (read_data): raise SyntaxError,"Closing parenthesis found when I was waiting for a value: it can not be closed a parenthesis after a binary operator." else: # If the parenthesis is fine, get the acumulator result=acumulator # Recover the old status (acumulator,operator)=parenthesis.pop() # Calculate the result of the parenthesis acumulator=self.__operate(acumulator,operator,result) # Don't compute anythin in this step jump=True # }}}2 # Check the next element if (read_data and (not jump)): read_data=False # Get value value=self.getvalue(token) # Compute the result acumulator=self.__operate(acumulator,operator,value) elif ((not read_data) and (not jump)): read_data=True # Get an operator operator_split=token.split(":") operator=operator_split[0] if (len(operator_split)>1): operator_arguments=operator_split[1] else: operator_arguments=None # Operator: SQRT if (operator.upper()=="SQRT"): # Read another operator read_data=False # Acumulate the result acumulator=math.sqrt(acumulator) # Operator: NOT elif (operator.upper()=="NOT"): # Read another operator read_data=False # Acumulate the result if (acumulator==0): acumulator=1 else: acumulator=0 # Operator: BOOL elif (operator.upper()=="BOOL"): # Read another operator read_data=False # Acumulate the result if (acumulator): acumulator=1 else: acumulator=0 # Operator: TIME elif (operator.upper()[0:4]=="TIME"): read_data=False if (acumulator): if (swap[operator]==None): swap[operator]=time.time() acumulator=0 else: acumulator=time.time()-swap[operator] else: swap[operator]=time.time() acumulator=0 # Operator: COUNT elif (operator.upper()[0:5]=="COUNT"): read_data=False if (acumulator): if (not swap[operator][1]): swap[operator]=(swap[operator][0]+1,True) else: swap[operator]=(swap[operator][0],False) acumulator=swap[operator][0] # Translation of operators elif (operator=="^"): operator="**" elif (operator.upper()=="OR"): operator="or" elif (operator.upper()=="AND"): operator="and" # Return the result return (swap,acumulator) # }}}1