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.types;
  
  import avrora.Main;
  import avrora.core.LoadableProgram;
  import avrora.sim.Simulation;
  import avrora.sim.SimulatorThread;
  import avrora.sim.platform.PinConnect;
  import avrora.sim.platform.PlatformFactory;
  import cck.text.StringUtil;
  import cck.util.*;
  import java.util.Random;
  
  /**
   * The <code>WiredSimulation</code> class represents a simulation type where multiple nodes, each with a microcontroller
   * are connected together by wires. It supports options from the command line that allow a simulation to be constructed
   * with multiple nodes with multiple different programs.
   *
   * @author Jacob Everist
   */
  public class WiredSimulation extends Simulation {
  
      public static String HELP = "The wired network simulation is used for simulating multiple nodes " +
              "simultaneously. These nodes can communicate with each other over wires.";
  
      public final Option.List NODECOUNT = newOptionList("nodecount", "1",
              "This option is used to specify the number of nodes to be instantiated. " +
              "The format is a list of integers, where each integer specifies the number of " +
              "nodes to instantiate with each program supplied on the command line. For example, " +
              "when set to \"1,2\" one node will be created with the first program loaded onto it, " +
              "and two nodes created with the second program loaded onto them.");
      public final Option.Interval RANDOM_START = newOption("random-start", 0, 0,
              "This option inserts a random delay before starting " +
              "each node in order to prevent artificial cycle-level synchronization. The " +
              "starting delay is pseudo-randomly chosen with uniform distribution over the " +
              "specified interval, which is measured in clock cycles. If the \"random-seed\" " +
              "option is set to a non-zero value, then its value is used as the seed to the " +
              "pseudo-random number generator.");
      public final Option.Long STAGGER_START = newOption("stagger-start", 0,
              "This option causes the simulator to insert a progressively longer delay " +
              "before starting each node in order to avoid artificial cycle-level " +
              "synchronization between nodes. The starting times are staggered by the specified number " +
              "of clock cycles. For example, if this option is given the " +
              "value X, then node 0 will start at time 0, node 1 at time 1*X, node 2 at " +
              "time 2*X, etc.");
  
      /**
       * The <code>WiredNode</code> class extends the <code>Node</code> class of a simulation by adding a reference to the
       * radio device as well as sensor data input. It extends the <code>instantiate()</code> method to create a new
       * thread for the node and to attach the sensor data input.
       */
      protected class WiredNode extends Node {
  
          long startup;
  
          WiredNode(int id, PlatformFactory pf, LoadableProgram p) {
              super(id, pf, p);
          }
  
          /**
           * The <code>instantiate()</code> method of the sensor node extends the default simulation node by creating a
           * new thread to execute the node as well as getting references to the radio and adding it to the radio model,
           * adding an optional start up delay for each node, and connecting the node's sensor input to replay or random
           * data as specified on the command line.
           */
          protected void instantiate() {
              createNode();
          }
  
          private void createNode() {
              thread = new SimulatorThread(this);
              super.instantiate();
              simulator.delay(startup);
          }
  
          /**
           * The <code>remove()</code> method removes this node from the simulation. This method extends the default
           * simulation remove method by removing the node from the radio air implementation.
           */
          protected void remove() {
              // FIXME:perhaps disconnect wires?
          }
      }
  
      long stagger;
  
      // class that connects all the nodes together via wire interconnect
      PinConnect pinConnect;
  
      public WiredSimulation() {
          super("wired", HELP, null);
  
          pinConnect = PinConnect.pinConnect;
          synchronizer = pinConnect.synchronizer;
  
          addSection("WIRED SIMULATION OVERVIEW", help);
          addOptionSection("This simulation type supports simulating multiple nodes that communicate " +
                  "with each other over wires. There are options to specify how many of each type of node to " +
                  "instantiate, as well as the program to be loaded onto each node.", options);
  
          PLATFORM.setNewDefault("seres");
      }
  
      /**
       * The <code>newNode()</code> method creates a new node in the simulation. In this implementation, a
       * <code>WiredNode</code> is created that contains, in addition to the simulator, ID, program, etc, a reference to
       * the <code>Radio</code> instance for the node and a <code>SimulatorThread</code> for the node.
       *
       * @param id the integer identifier for the node
       * @param pf the platform factory to use to instantiate the node
       * @param p  the program to load onto the node
       * @return a new instance of the <code>WiredNode</code> class for the node
       */
      public Node newNode(int id, PlatformFactory pf, LoadableProgram p) {
          return new WiredNode(id, pf, p);
      }
  
      /**
       * The <code>process()</code> method processes options and arguments from the command line. In this implementation,
       * this method accepts multiple programs from the command line as arguments as well as options that describe how
       * many of each type of node to instantiate.
       *
       * @param o    the options from the command line
       * @param args the arguments from the command line
       * @throws Exception if there is a problem loading any of the files or instantiating the simulation
       */
      public void process(Options o, String[] args) throws Exception {
          options.process(o);
          processMonitorList();
  
          if (args.length == 0) Util.userError("Simulation error", "No program specified");
          Main.checkFilesExist(args);
          PlatformFactory pf = getPlatform();
  
          // create the nodes based on arguments
          createNodes(args, pf);
  
      }
  
      protected void instantiateNodes() {
          super.instantiateNodes();
  
          pinConnect.initializeConnections();
      }
  
      private void createNodes(String[] args, PlatformFactory pf) throws Exception {
          int cntr = 0;
          for (String str : NODECOUNT.get()) {
              if (args.length <= cntr) break;
  
              String pname = args[cntr++];
              LoadableProgram lp = new LoadableProgram(pname);
              lp.load();
  
              // create a number of nodes with the same program
              int max = StringUtil.evaluateIntegerLiteral(str);
              for (int node = 0; node < max; node++) {
                  WiredNode n = (WiredNode)createNode(pf, lp);
                  long r = processRandom();
                  long s = processStagger();
                  n.startup = r + s;
              }
          }
      }
  
      long processRandom() {
          long low = RANDOM_START.getLow();
          long size = RANDOM_START.getHigh() - low;
          long delay = 0;
          if (size > 0) {
              Random r = getRandom();
              delay = r.nextLong();
              if (delay < 0) delay = -delay;
              delay = delay % size;
          }
  
          return (low + delay);
      }
  
      long processStagger() {
          long st = stagger;
          stagger += STAGGER_START.get();
          return st;
      }
  
  }
  