/**
 * Created on 09.11.2004
 * 
 * Copyright (c) 2004-2005, Olaf Landsiedel, Protocol Engineering and 
 * Distributed Systems, University of Tuebingen
 * 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.monitors;

import avrora.sim.Simulator;
import avrora.sim.mcu.AtmelMicrocontroller;
import avrora.sim.mcu.SPI;
import avrora.sim.platform.SPIForwarder;
import cck.util.*;
import java.util.HashMap;

/**
 * The <code>SerialMonitor</code> class is a monitor that that is capable of setting up a virtual
 * usart connection to the pc. You can connect the TinyOS serial forwarder to the port 2390.
 *
 * @author Olaf Landsiedel
 * @author Torsten Landschoff
 */
public class SPIMonitor extends MonitorFactory {

    protected final Option.List PORTS = newOptionList("ports", "0:2391",
            "The \"ports\" option specifies a list of server ports that the simulator will listen on " +
            "to connect to the serial forwarder for each node. The format is to first give " +
            "the node number, and then the port number " +
            "($node:$port,$node:$port).");

    protected final Option.Long BPS = newOption("bps", 2400,
            "This option controls the bit rate of the controlling SPI transfer device.");

    protected final Option.Bool MASTER = newOption("master", true,
            "This option controls whether the SPI forwarder device will act as the " +
            "master or the slave in the SPI connection.");

    HashMap<Integer, SocketConnection> portMap;

    abstract class Connection {
        //int spi;
        abstract void connect(SPI spi);
    }

    class SocketConnection extends Connection {
        int port;
        void connect(SPI spi) {
            new SPIForwarder(spi, port, (int)BPS.get(), MASTER.get());
        }
    }

    /**
     * The <code>SerialMonitor</code> class is a monitor that connects the USART of a node to a socket that allows data
     * to be read and written from the simulation.
     */
    public class Monitor implements avrora.monitors.Monitor {

        /**
         * construct a new monitor
         *
         * @param s Simulator
         */
        Monitor(Simulator s) {
            Connection conn = (Connection)portMap.get(new Integer(s.getID()));
            if ( conn != null ) {
                AtmelMicrocontroller mcu = (AtmelMicrocontroller)s.getMicrocontroller();
                SPI spi = (SPI)mcu.getDevice("spi");
                conn.connect(spi);
            }
        }

        public void report() {
            //no report
        }

    }

    /**
     * The constructor for the <code>SerialMonitor</code> class builds a new <code>MonitorFactory</code> capable of
     * creating monitors for each <code>Simulator</code> instance passed to the <code>newMonitor()</code> method.
     */
    public SPIMonitor() {
        super("The \"spi\" monitor allows the SPI of a node in the simulation to be " +
                "connected to a socket so that data from the program running in the simulation can be " +
                "outputted, and external data can be fed into the SPI of the simulated node.");
        portMap = new HashMap<Integer, SocketConnection>();
    }

    public void processOptions(Options o) {
        super.processOptions(o);
        processSocketConnections();
        //processDeviceConnections();
    }

    private void processSocketConnections() {
        for (String pid : PORTS.get()) {
            String[] str = pid.split(":");
            if ( str.length < 2 ) Util.userError("Format error in \"ports\" option");
            int nid = Integer.parseInt(str[0]);
            int port = Integer.parseInt(str[1]);
            SocketConnection conn = new SocketConnection();
            conn.port = port;
            portMap.put(new Integer(nid), conn);
        }
    }

    /**
     * The <code>newMonitor()</code> method creates a new monitor that is capable of setting up a virtual usart
     * connection to the pc. You can connect the TinyOS serial forwarder to the port 2390.
     *
     * @param s the simulator to create a monitor for
     * @return an instance of the <code>Monitor</code> interface for the specified simulator
     */
    public avrora.monitors.Monitor newMonitor(Simulator s) {
        return new Monitor(s);
    }

}



