code: /**
   * Copyright (c) 2004-2005, Regents of the University of California
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * Redistributions of source code must retain the above copyright notice,
   * this list of conditions and the following disclaimer.
   *
   * Redistributions in binary form must reproduce the above copyright
   * notice, this list of conditions and the following disclaimer in the
   * documentation and/or other materials provided with the distribution.
   *
   * Neither the name of the University of California, Los Angeles nor the
   * names of its contributors may be used to endorse or promote products
   * derived from this software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   */
  
  package avrora.sim.platform;
  
  import avrora.sim.Simulator;
  import avrora.sim.SimulatorThread;
  import avrora.sim.clock.StepSynchronizer;
  import avrora.sim.clock.Synchronizer;
  import avrora.sim.mcu.Microcontroller;
  import java.util.Iterator;
  import java.util.LinkedList;
  import java.util.List;
  
  /**
   * Very simple implementation of pin interconnect between microcontrollers
   *
   * @author Jacob Everist
   */
  
  public class PinConnect {
  
      public static final PinConnect pinConnect;
  
      static {
          pinConnect = new PinConnect();
      }
  
      private final PinEvent pinEvent;
      public final Synchronizer synchronizer;
  
      // List of all the pin relationships
      protected LinkedList<PinNode> pinNodes;
      protected LinkedList<PinLink> pinConnections;
      
      // number of nodes
      protected int numNodes;
  
      // SERES link directions
      public static final int NONE = -1;
      public static final int NORTH = 0;
      public static final int EAST = 1;
      public static final int SOUTH = 2;
      public static final int WEST = 3;
      
      // Superbot link directions
      public static final int LED1 = 0;
      public static final int LED2 = 1;
      public static final int LED3 = 2;
      public static final int LED4 = 3;
      public static final int LED5 = 4;
      public static final int LED6 = 5;
      
      public PinConnect() {
          // period = 1
          pinNodes = new LinkedList<PinNode>();
          pinConnections = new LinkedList<PinLink>();
          pinEvent = new PinEvent();
          synchronizer = new StepSynchronizer(pinEvent);
          numNodes = 0;
      }
  
      public void addSeresNode(Microcontroller mcu, PinWire northTx, PinWire eastTx,
                               PinWire southTx, PinWire westTx, PinWire northRx, PinWire eastRx,
                               PinWire southRx, PinWire westRx, PinWire northInt, PinWire eastInt,
                               PinWire southInt, PinWire westInt) {
  
          pinNodes.add(new PinNode(mcu, northTx, eastTx, southTx, westTx, northRx, eastRx, southRx, westRx,
                  northInt, eastInt, southInt, westInt, numNodes));
          numNodes++;
      }
      
      public void addSuperbotNode(Microcontroller mcu, PinWire LED1Tx, PinWire LED2Tx, PinWire LED3Tx, PinWire LED4Tx,
      		PinWire LED5Tx, PinWire LED6Tx, PinWire LED1Rx, PinWire LED2Rx, PinWire LED3Rx, PinWire LED4Rx,
  			PinWire LED5Rx, PinWire LED6Rx, PinWire LED1Int, PinWire LED2Int, PinWire LED3Int,
  			PinWire LED4Int, PinWire LED5Int, PinWire LED6Int ) {
  
      	pinNodes.add(new PinNode(mcu, LED1Tx, LED2Tx, LED3Tx, LED4Tx, LED5Tx, LED6Tx, LED1Rx, LED2Rx, LED3Rx,
      			LED4Rx, LED5Rx, LED6Rx, LED1Int, LED2Int, LED3Int, LED4Int, LED5Int, LED6Int, numNodes));
      	numNodes++;
      }
      
      @Deprecated // dead/non functional code
      public void addSimulatorThread(SimulatorThread simThread) {
          /* DEAD CODE
          Simulator sim = simThread.getSimulator();
          Microcontroller currMCU = sim.getMicrocontroller();
  
   
          // iterator over PinNodes
          Iterator<PinNode> i = pinNodes.iterator();
  
          // go through the complete list of PinNodes
          while (i.hasNext()) {
  
              // get the next PinNode on the list
              PinNode p = i.next();
  
              // does this node have the equivalent Microcontroller?
              if (currMCU == p.mcu) {
  
                  // register the simulator thread with the appropriate PinNode
                  //p.addSimulatorThread(simThread);
  
                  // add simulator thread to PinClock and PinMeet
                  //synchronizer.addNode(simThread.getNode());
              }
          }*/
      }
  
      /**
       * Initialize the connections with a default topology of
       * a chain with connections on the north and south ports
       */
      public void initializeConnections() {
  
          // iterator over PinNodes
          Iterator<PinNode> i = pinNodes.iterator();
  
          if (!i.hasNext()) {
              return;
          }
  
          // the previous PinNode
          PinNode prevNode = i.next();
  
          // connect the nodes from North to South to create a long chain
          while (i.hasNext()) {
              // get next node on the list
              PinNode currNode = (PinNode) i.next();
              // two-way communication links between neighboring modules
              
              // two-way communication links between neighboring modules
              if ("SERES".equalsIgnoreCase(prevNode.platform)) {
              	prevNode.connectNodes(currNode, SOUTH, SOUTH);
              	prevNode.connectNodes(currNode, NORTH, NORTH);
              	prevNode.connectNodes(currNode, EAST, EAST);
              	prevNode.connectNodes(currNode, WEST, WEST);
              	//prevNode.connectNodes(prevNode, SOUTH, SOUTH);
              	//prevNode.connectNodes(prevNode, NORTH, NORTH);
              	//prevNode.connectNodes(prevNode, EAST, EAST);
              	//prevNode.connectNodes(prevNode, WEST, WEST);
              }
              else if ("Superbot".equalsIgnoreCase(prevNode.platform) ) {
              	prevNode.connectNodes(currNode, LED1, LED1);
              	prevNode.connectNodes(currNode, LED2, LED2);
              	prevNode.connectNodes(currNode, LED3, LED3);
              	prevNode.connectNodes(currNode, LED4, LED4);
              	prevNode.connectNodes(currNode, LED5, LED5);
              	prevNode.connectNodes(currNode, LED6, LED6);
              }
              else {
              	System.out.println("Unrecognized platform " + prevNode.platform );
              }
              // set this node as previous node
              prevNode = currNode;
  
          }
  
      }
  
      /**
       * This class stores all the information for a single controller node
       * and its PinWires.
       *
       * @author Jacob Everist
       */
      protected class PinNode {
  
          // node microcontroller
          public Microcontroller mcu;
  
          // transmit pins
          protected PinWire[] TxPins;
  
          // receive pins
          protected PinWire[] RxPins;
  
          // interrupt pins
          protected PinWire[] IntPins;
  
          // simulator thread
          //public SimulatorThread simThread;
  
          // node id and neighbors
      	public PinNode[] neighborNodes;
      	
      	// side we are connected to neighbors
      	public int[] neighborSides;
      	
      	// platform ID
      	public final String platform;
  
      	public PinNode(Microcontroller mcu, PinWire northTx, PinWire eastTx,
                             PinWire southTx, PinWire westTx, PinWire northRx, PinWire eastRx,
                             PinWire southRx, PinWire westRx, PinWire northInt, PinWire eastInt,
                             PinWire southInt, PinWire westInt, int node) {
  
              this.mcu = mcu;
              
              TxPins = new PinWire[]{northTx,eastTx,southTx,westTx};
              RxPins = new PinWire[]{northRx,eastRx,southRx,westRx};
              IntPins = new PinWire[]{northInt,eastInt,southInt,westInt};
              
              
              neighborNodes = new PinNode[]{null,null,null,null};
              neighborSides = new int[]{NONE,NONE,NONE,NONE};
  
              platform = "SERES";
  
          }
          
          public PinNode(Microcontroller mcu, PinWire LED1Tx, PinWire LED2Tx, PinWire LED3Tx, PinWire LED4Tx,
          		PinWire LED5Tx, PinWire LED6Tx, PinWire LED1Rx, PinWire LED2Rx, PinWire LED3Rx, PinWire LED4Rx,
  				PinWire LED5Rx, PinWire LED6Rx, PinWire LED1Int, PinWire LED2Int, PinWire LED3Int,
  				PinWire LED4Int, PinWire LED5Int, PinWire LED6Int, int node) {
  
          	this.mcu = mcu;
       
          	TxPins = new PinWire[]{LED1Tx, LED2Tx, LED3Tx, LED4Tx, LED5Tx, LED6Tx};
          	RxPins = new PinWire[]{LED1Rx, LED2Rx, LED3Rx, LED4Rx, LED5Rx, LED6Rx};
          	IntPins = new PinWire[]{LED1Int, LED2Int, LED3Int, LED4Int, LED5Int, LED6Int};
       
       
          	neighborNodes = new PinNode[]{null,null,null,null,null,null};
          	neighborSides = new int[]{NONE,NONE,NONE,NONE,NONE,NONE};
  
          	platform = "Superbot";
          }
          
          public void connectNodes(PinNode neighbor, int localSide, int neighborSide) {
          	
          	// check to see that either side has not previously been connected
          	if ( neighborNodes[localSide] != null || neighbor.neighborNodes[neighborSide] != null )
          		return;
          	
          	// set the nodes as neighbors
          	neighborNodes[localSide] = neighbor;
          	neighborSides[localSide] = neighborSide;
          	neighbor.neighborNodes[neighborSide] = this;
          	neighbor.neighborSides[neighborSide] = localSide;
          	
          	// connect the nodes on the appropriate sides
          	
              // output pin for tne local module
              PinLink localToNeighbor = new PinLink(TxPins[localSide]);
              localToNeighbor.outputNode = this;
              localToNeighbor.outputSide = localSide;
              localToNeighbor.inputNode = neighbor;
              localToNeighbor.inputSide = neighborSide;
  
              // input pins for the neighbor module
              localToNeighbor.addInputPin(neighbor.RxPins[neighborSide]);
              localToNeighbor.addInputPin(neighbor.IntPins[neighborSide]);
  
              // output pin for the neighbor module
              PinLink neighborToLocal = new PinLink(neighbor.TxPins[neighborSide]);
              neighborToLocal.outputNode = neighbor;
              neighborToLocal.outputSide = neighborSide;
              neighborToLocal.inputNode = this;
              neighborToLocal.inputSide = localSide;
  
              // input pins for the local module
              neighborToLocal.addInputPin(RxPins[localSide]);
              neighborToLocal.addInputPin(IntPins[localSide]);
  
              // add connections to the list
              pinConnections.add(localToNeighbor);
              pinConnections.add(neighborToLocal);
          }
  
          public void disconnectNodes(PinNode neighbor, int localSide, int neighborSide) {
          	
          	// set the nodes as neighbors
          	neighborNodes[localSide] = null;
          	neighborSides[localSide] = NONE;
          	neighbor.neighborNodes[neighborSide] = null;
          	neighbor.neighborSides[neighborSide] = NONE;
          	
          	// find the local to neighbor connections
          	List<PinLink> toRemove = new LinkedList<PinLink>();
          	for (PinLink curr : pinConnections) {        	
          		// if this is the correct link, delete it
          		if ( curr.outputNode == this && curr.outputSide == localSide 
          				&& curr.inputNode == neighbor && curr.inputSide == neighborSide ) {
          			toRemove.add(curr);
          		}
          		// find the neighbor to local connection
          		else if (curr.outputNode == neighbor
                          && curr.outputSide == neighborSide
                          && curr.inputNode == this
                          && curr.inputSide == localSide) {
                      toRemove.add(curr);
                  }
          	}
          	
          	for (PinLink del : toRemove) {
          	    pinConnections.remove(del);
          	}
          }
          /*
           * public void addSimulatorThread(SimulatorThread simThread) {
           * this.simThread = simThread; }
           */
      }
  
      /**
       * This class connects two PinNode devices together in two-way communication
       *
       * @author Jacob Everist
       */
      protected class PinLink {
  
          protected LinkedList<PinWire> pinWires;
          protected int currentDelay;
          
          public PinNode outputNode;
          public int outputSide;
          
          public PinNode inputNode;
          public int inputSide;
  
          // must start PinLink with an output pin
          public PinLink(PinWire outputPin) {
  
              pinWires = new LinkedList<PinWire>();
  
              // make sure it is set as output
              outputPin.wireOutput.enableOutput();
  
              // add to list of pins on this connection
              pinWires.add(outputPin);
  
          }
  
          // add an input pin on this connection
          public void addInputPin(PinWire inputPin) {
  
              // make sure it is set as input
              inputPin.wireInput.enableInput();
  
              // add to list of pins on this connection
              pinWires.add(inputPin);
  
          }
  
          // transmit the signals on this connection
          public void propagateSignals() {
              // iterator over PinWires
              PinWire currOutput = null;
  
              // go through the complete list of PinWires to find the output wire
              for (PinWire curr : pinWires) {
                  // if this wire accepts output
                  if (curr.outputReady()) {
                      // check that we haven't already found an output wire
                      if (currOutput != null) {
                          String s = "ERROR: More than one output wire on this PinLink";
                          System.out.println(s);
                          return;
                      } else {
                          // set this pin as the output wire
                          currOutput = curr;
                      }
  
                  }
              }
  
              // check if we have an output wire
              if (currOutput == null) {
                  // there is no output wire, so do nothing
              }
              // if we have an output wire, propagate its signal
              else {
                  for (PinWire curr : pinWires) {
                      // if this is not the output, propagate the signal
                      if (curr != currOutput) {
                          // write the value of output pin to the input pins
                          curr.wireOutput.write(currOutput.wireInput.read());
                          //System.out.println("Writing " + currOutput.wireInput.read()
                          //		+ " from " + currOutput.readName() + " to "
                          //		+ curr.readName());
                      }
                  }
              }
          }
      }
  
      protected class PinEvent implements Simulator.Event {
          public void fire() {
              // iterator over PinLinks            
              for (PinConnect.PinLink currLink : pinConnections) {
                  currLink.propagateSignals();
              }
          }
      }
      
  
  	/**
  	 * @return Returns the pinNodes.
  	 */
  	public LinkedList<PinNode> getPinNodes() {
  		return pinNodes;
  	}
  }
  