package ptolemy.domains.pthales.lib; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import ptolemy.actor.TypedAtomicActor; import ptolemy.data.FloatToken; import ptolemy.data.Token; import ptolemy.data.expr.Parameter; import ptolemy.data.expr.StringParameter; import ptolemy.domains.pthales.kernel.PthalesDirector; import ptolemy.kernel.CompositeEntity; import ptolemy.kernel.Port; import ptolemy.kernel.util.Attribute; import ptolemy.kernel.util.IllegalActionException; import ptolemy.kernel.util.InternalErrorException; import ptolemy.kernel.util.NameDuplicationException; import ptolemy.kernel.util.Workspace; public class PThalesGenericActor extends TypedAtomicActor { /** Construct an actor in the default workspace with an empty string * as its name. The object is added to the workspace directory. * Increment the version number of the workspace. * @throws NameDuplicationException * @throws IllegalActionException */ public PThalesGenericActor() throws IllegalActionException, NameDuplicationException { super(); _initialize(); } /** Construct an actor in the specified workspace with an empty * string as a name. You can then change the name with setName(). * If the workspace argument is null, then use the default workspace. * The object is added to the workspace directory. * Increment the version number of the workspace. * @param workspace The workspace that will list the entity. * @throws NameDuplicationException * @throws IllegalActionException */ public PThalesGenericActor(Workspace workspace) throws IllegalActionException, NameDuplicationException { super(workspace); _initialize(); } /** Create a new actor in the specified container with the specified * name. The name must be unique within the container or an exception * is thrown. The container argument must not be null, or a * NullPointerException will be thrown. * * @param container The container. * @param name The name of this actor within the container. * @exception IllegalActionException If this actor cannot be contained * by the proposed container (see the setContainer() method). * @exception NameDuplicationException If the name coincides with * an entity already in the container. */ public PThalesGenericActor(CompositeEntity container, String name) throws NameDuplicationException, IllegalActionException { super(container, name); _initialize(); } /////////////////////////////////////////////////////////////////// //// ports and parameters //// private void _initialize() throws IllegalActionException, NameDuplicationException { if (getAttribute("internalRepetitions") == null) { internalRepetitions = new StringParameter(this, "internalRepetitions"); internalRepetitions.setExpression(""); } if (getAttribute("arguments") == null) { arguments = new StringParameter(this, "arguments"); arguments.setExpression(""); } if (getAttribute("function") == null) { function = new StringParameter(this, "function"); function.setExpression(""); } } /** If a positive integer, then the number of iterations before the * actor indicates to the scheduler that it is finished by returning * false in its postfire() method. */ public Parameter internalRepetitions; /** a String that is used to fill arguments when calling the function */ public Parameter arguments; /** the name of the function to call when the actor is fired */ public Parameter function; /** Create a new TypedIOPort with the specified name. * The container of the port is set to this actor. * This method is write-synchronized on the workspace. * * @param name The name for the new port. * @return The new port. * @exception NameDuplicationException If the actor already has a port * with the specified name. */ public Port newPort(String name) throws NameDuplicationException { try { _workspace.getWriteAccess(); PThalesIOPort port = new PThalesIOPort(this, name, false, false); return port; } catch (IllegalActionException ex) { // This exception should not occur, so we throw a runtime // exception. throw new InternalErrorException(this, ex, null); } finally { _workspace.doneWriting(); } } /////////////////////////////////////////////////////////////////// //// public methods //// /** If the argument is the <i>init</i> parameter, then reset the * state to the specified value. * @param attribute The attribute that changed. * @throws IllegalActionException If <i>init<i> cannot be evaluated * or cannot be converted to the output type, or if the superclass * throws it. */ /** Read all the array then (should) call JNI function * @exception IllegalActionException If there is no director, or the * input can not be read, or the output can not be sent. */ public void fire() throws IllegalActionException { // Variables List<PThalesIOPort> portsIn = null; List<PThalesIOPort> portsOut = null; int portNumber; // Input ports portsIn = inputPortList(); // Token Arrays from simulation Token[] tokensIn = null; // Real Arrays float[][] realIn = new float[portsIn.size()][]; // ouput ports portsOut = outputPortList(); // In the output case, each array is produced independantly Token[] tokensOut = null; // Real Array (only one) float[][] realOut = new float[portsOut.size()][]; // BEFORE CALLING TASK // portNumber = 0; // Input ports created and filled before elementary task called for (PThalesIOPort port : portsIn) { int dataSize = port.getPatternSize(); tokensIn = new FloatToken[dataSize]; tokensIn = port.get(0, dataSize); // Call array conversion realIn[portNumber] = convertToken(tokensIn); portNumber++; } portNumber = 0; // Outputs ports arrays created before elementary task called for (PThalesIOPort port : portsOut) { realOut[portNumber] = new float[port.getPatternSize()]; portNumber++; } /////////////////////////////////////// // Call to elemetary task (JNI or JAVA) /////////////////////////////////////// Object[] args = null; try { PthalesDirector director = (PthalesDirector) getDirector(); String libName = director.getLibName(); if (libName.length() > 0) { Class c = Class.forName("ptolemy.domains.pthales.JNI." + libName); Method[] methods = c.getMethods(); for (Method method : methods) { if (method.getName().equals(_function)) { try { // Arguments convertion and format as a list args = convertArguments(realIn, realOut); if (method.getParameterTypes().length == args.length) { // JNI Function call with arguments method.invoke(c, args); // Function call is ok break; } } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } } } } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } // AFTER CALLING TASK // portNumber = 0; // Output ports write for (PThalesIOPort port : portsOut) { int dataSize = port.getPatternSize(); tokensOut = convertReal(realOut[portNumber]); for (int i = 0; i < port.getWidth(); i++) { port.send(i, tokensOut, dataSize); } portNumber++; } } /** Attribute update */ public void attributeChanged(Attribute attribute) throws IllegalActionException { if (attribute == internalRepetitions) { _internalRepetitions = internalRepetitions.getExpression(); } if (attribute == function) { _function = function.getExpression(); } if (attribute == arguments) { _arguments = arguments.getExpression(); } } /** Conversion from Tokens to array used in JNI function * @param tokensIn */ public float[] convertToken(Token[] tokensIn) { float[] realIn; int nbData = tokensIn.length; realIn = new float[nbData]; for (int i = 0; i < nbData; i++) { realIn[i] = ((FloatToken) tokensIn[i]).floatValue(); } return realIn; } /** Conversion from array used in JNI function to Tokens * @param realOut */ public FloatToken[] convertReal(float[] realOut) { FloatToken[] tokensOut; int nbData = realOut.length; tokensOut = new FloatToken[nbData]; for (int i = 0; i < nbData; i++) { tokensOut[i] = new FloatToken(realOut[i]); } return tokensOut; } /** Unused */ public boolean postfire() throws IllegalActionException { return true; } public String getInternalRepetitions() { return _internalRepetitions; } /** Function which convert a list of arguments into real arguments * that will be used for JNI function call. * @param in * @param out * @return A list of arguments to be used for the JNI function call. */ public Object[] convertArguments(float[][] in, float[][] out) { List objs = new ArrayList(); int numIn = 0; int numOut = 0; int increase = 0; String[] listArgs = _arguments.split(";"); for (int i = 0; i < listArgs.length; i++) { // Argument is a port : check input or output if (listArgs[i].equals("port")) { if (listArgs[i + 1].equals("OUT")) { int[] sizes = ((PThalesIOPort) outputPortList().get(numOut)) .getPattern(); for (int size : sizes) { if (size > 1) objs.add(size); } objs.add(out[numOut]); numOut++; } if (listArgs[i + 1].equals("IN")) { int[] sizes = ((PThalesIOPort) inputPortList().get(numIn)) .getPattern(); for (int size : sizes) { if (size > 1) objs.add(size); } objs.add(in[numIn]); numIn++; } increase = 1; } // Argument is parameter => converted into type if (listArgs[i].equals("parameter")) { if (listArgs[i + 1].equals("int")) { objs.add(Integer.parseInt(listArgs[i + 2])); } else if (listArgs[i + 1].equals("long")) { objs.add(Long.parseLong(listArgs[i + 2])); } else if (listArgs[i + 1].equals("double") || listArgs[i + 1].equals("Spldouble")) { objs.add(Double.parseDouble(listArgs[i + 2])); } else if (listArgs[i + 1].equals("float") || listArgs[i + 1].equals("Splfloat")) { objs.add(Float.parseFloat(listArgs[i + 2])); } else { // Type is not a primitive => string objs.add(listArgs[i]); } increase = 2; } i += increase; } return objs.toArray(); } /////////////////////////////////////////////////////////////////// //// protected variables //// /** This is the value in parameter base. */ protected String _internalRepetitions = ""; protected String _function = ""; protected String _arguments = ""; }