LINC-OE Optical Switch Driveri changes
diff --git a/openflow/api/pom.xml b/openflow/api/pom.xml
index afc2faf..4e91328 100644
--- a/openflow/api/pom.xml
+++ b/openflow/api/pom.xml
@@ -30,7 +30,7 @@
             <groupId>org.projectfloodlight</groupId>
             <artifactId>openflowj</artifactId>
             <!-- FIXME once experimenter gets merged to upstream -->
-            <version>0.3.8-optical_experimenter</version>
+            <version>0.3.8-optical_experimenter2</version>
         </dependency>
         <dependency>
             <groupId>io.netty</groupId>
diff --git a/openflow/ctl/src/main/java/org/onlab/onos/openflow/drivers/impl/DriverManager.java b/openflow/ctl/src/main/java/org/onlab/onos/openflow/drivers/impl/DriverManager.java
index 868eb86..fafe546 100644
--- a/openflow/ctl/src/main/java/org/onlab/onos/openflow/drivers/impl/DriverManager.java
+++ b/openflow/ctl/src/main/java/org/onlab/onos/openflow/drivers/impl/DriverManager.java
@@ -57,6 +57,12 @@
             }
         }
 
+        String sw = desc.getSwDesc();
+        if (sw.startsWith("LINC-OE")) {
+            log.debug("Optical Emulator LINC-OE with DPID:{} found..",dpid);
+            return new OFOpticalSwitchImplLINC13(dpid,desc);
+        }
+
         log.warn("DriverManager could not identify switch desc: {}. "
                 + "Assigning AbstractOpenFlowSwich", desc);
         return new AbstractOpenFlowSwitch(dpid, desc) {
diff --git a/openflow/ctl/src/main/java/org/onlab/onos/openflow/drivers/impl/OFOpticalSwitchImplLINC13.java b/openflow/ctl/src/main/java/org/onlab/onos/openflow/drivers/impl/OFOpticalSwitchImplLINC13.java
new file mode 100644
index 0000000..99d77a6
--- /dev/null
+++ b/openflow/ctl/src/main/java/org/onlab/onos/openflow/drivers/impl/OFOpticalSwitchImplLINC13.java
@@ -0,0 +1,383 @@
+package org.onlab.onos.openflow.drivers.impl;
+
+import org.onlab.onos.openflow.controller.driver.SwitchDriverSubHandshakeAlreadyStarted;
+import org.onlab.onos.openflow.controller.driver.SwitchDriverSubHandshakeCompleted;
+import org.onlab.onos.openflow.controller.driver.SwitchDriverSubHandshakeNotStarted;
+import org.onlab.onos.openflow.controller.Dpid;
+import org.onlab.onos.openflow.controller.driver.AbstractOpenFlowSwitch;
+import org.projectfloodlight.openflow.protocol.OFCircuitPortsReply;
+import org.projectfloodlight.openflow.protocol.OFCircuitPortsRequest;
+import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
+import org.projectfloodlight.openflow.protocol.OFErrorMsg;
+import org.projectfloodlight.openflow.protocol.OFMatchV3;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFOxmList;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.OFPortOptical;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.protocol.action.OFActionCircuit;
+import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmInPort;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmOchSigid;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmOchSigidBasic;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmOchSigtype;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmOchSigtypeBasic;
+import org.projectfloodlight.openflow.types.CircuitSignalID;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.U8;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * LINC-OE Optical Emulator switch class.
+ */
+public class OFOpticalSwitchImplLINC13 extends AbstractOpenFlowSwitch {
+
+    private final AtomicBoolean driverHandshakeComplete;
+    private long barrierXidToWaitFor = -1;
+
+    private final Logger log =
+            LoggerFactory.getLogger(OFOpticalSwitchImplLINC13.class);
+
+    OFOpticalSwitchImplLINC13(Dpid dpid,OFDescStatsReply desc) {
+        super(dpid);
+        //setAttribute("optical", "true");
+        driverHandshakeComplete = new AtomicBoolean(false);
+        setSwitchDescription(desc);
+    }
+
+    @Override
+    public String toString() {
+        return "OFOpticalSwitchImplLINC13 [" + ((channel != null)
+                ? channel.getRemoteAddress() : "?")
+                + " DPID[" + ((getStringId() != null) ? getStringId() : "?") + "]]";
+    }
+
+    @Override
+    public void startDriverHandshake() {
+        log.debug("Starting driver handshake for sw {}", getStringId());
+        if (startDriverHandshakeCalled) {
+            throw new SwitchDriverSubHandshakeAlreadyStarted();
+        }
+        startDriverHandshakeCalled = true;
+        try {
+            sendHandshakeOFExperimenterPortDescRequest();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public boolean isDriverHandshakeComplete() {
+        if (!startDriverHandshakeCalled) {
+            throw new SwitchDriverSubHandshakeNotStarted();
+        }
+        return driverHandshakeComplete.get();
+    }
+
+    @Override
+    public void processDriverHandshakeMessage(OFMessage m) {
+        if (!startDriverHandshakeCalled) {
+            throw new SwitchDriverSubHandshakeNotStarted();
+        }
+        if (driverHandshakeComplete.get()) {
+            throw new SwitchDriverSubHandshakeCompleted(m);
+        }
+
+        switch (m.getType()) {
+            case BARRIER_REPLY:
+                if (m.getXid() == barrierXidToWaitFor) {
+                    log.debug("LINC-OE Received barrier response");
+                }
+                break;
+            case ERROR:
+                log.error("Switch {} Error {}", getStringId(), (OFErrorMsg) m);
+                break;
+            case FEATURES_REPLY:
+                break;
+            case FLOW_REMOVED:
+                break;
+            case GET_ASYNC_REPLY:
+                break;
+            case PACKET_IN:
+                break;
+            case PORT_STATUS:
+                break;
+            case QUEUE_GET_CONFIG_REPLY:
+                break;
+            case ROLE_REPLY:
+                break;
+            case STATS_REPLY:
+                log.debug("LINC-OE : Received stats reply message {}", m);
+                processHandshakeOFExperimenterPortDescRequest(
+                        (OFCircuitPortsReply) m);
+                driverHandshakeComplete.set(true);
+               /* try {
+                    testMA();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }*/
+                break;
+            default:
+                log.debug("Received message {} during switch-driver " +
+                                  "subhandshake " + "from switch {} ... " +
+                                  "Ignoring message", m,
+                          getStringId());
+
+        }
+    }
+
+
+    private void processHandshakeOFExperimenterPortDescRequest(
+            OFCircuitPortsReply sr) {
+        Collection<OFPortOptical> entries = sr.getEntries();
+        List<OFPortDesc> ofPortDescList = new ArrayList<>(entries.size());
+        for (OFPortOptical entry : entries) {
+            ofPortDescList.add(factory().buildPortDesc().
+                    setPortNo(entry.getPortNo())
+                                           .setConfig(entry.getConfig())
+                                           .setState(entry.getState())
+                                           .setHwAddr(entry.getHwAddr())
+                                           .setName(entry.getName())
+                                           .build());
+        }
+        setPortDescReply(factory().buildPortDescStatsReply().
+                setEntries(ofPortDescList).build());
+    }
+
+
+    private void sendHandshakeOFExperimenterPortDescRequest() throws
+            IOException {
+        // send multi part message for port description for optical switches
+        OFCircuitPortsRequest circuitPortsRequest = factory()
+                .buildCircuitPortsRequest().setXid(getNextTransactionId())
+                .build();
+        log.debug("LINC-OE : Sending experimented circuit port stats " +
+                          "message " +
+                          "{}",
+                  circuitPortsRequest.toString());
+        channel.write(Collections.singletonList(circuitPortsRequest));
+    }
+
+
+
+    //todo for testing
+    public static final U8 SIGNAL_TYPE = U8.of((short) 1);
+    private void testMA() throws IOException {
+        log.debug("LINC OE *** Testing MA ");
+        short lambda = 100;
+        if (getId() == 0x0000ffffffffff02L) {
+            final int inport = 10;
+            final int outport = 20;
+            //Circuit signal id
+            CircuitSignalID sigID = getSignalID(lambda);
+
+            OFOxmOchSigid fieldSigIDMatch = factory().oxms().ochSigid(sigID);
+            OFOxmOchSigtype fieldSigType = factory()
+                    .oxms()
+                    .ochSigtype(SIGNAL_TYPE);
+
+            OFOxmOchSigidBasic ofOxmOchSigidBasic =
+                    factory().oxms().ochSigidBasic(sigID);
+
+            OFOxmOchSigtypeBasic ofOxmOchSigtypeBasic =
+                    factory().oxms().ochSigtypeBasic(SIGNAL_TYPE);
+
+            //Match Port
+            OFOxmInPort fieldPort = factory().oxms()
+                                                .inPort(OFPort.of(inport));
+            OFMatchV3 matchPort =
+                    factory()
+                            .buildMatchV3().
+                            setOxmList(OFOxmList.of(fieldPort,
+                                                    fieldSigType,
+                                                    fieldSigIDMatch)).build();
+
+
+            // Set Action outport ,sigType and sigID
+            List<OFAction> actionList = new ArrayList<>();
+            OFAction actionOutPort =
+                    factory().actions().output(OFPort.of(outport),
+                                                  Short.MAX_VALUE);
+
+            OFActionCircuit actionCircuit = factory()
+                    .actions()
+                    .circuit(ofOxmOchSigidBasic);
+            OFActionCircuit setActionSigType = factory()
+                    .actions()
+                    .circuit(ofOxmOchSigtypeBasic);
+
+            actionList.add(actionOutPort);
+            actionList.add(setActionSigType);
+            actionList.add(actionCircuit);
+
+            OFInstruction instructionAction =
+                    factory().instructions().buildApplyActions()
+                                .setActions(actionList)
+                                .build();
+            List<OFInstruction> instructions =
+                    Collections.singletonList(instructionAction);
+
+            OFMessage opticalFlowEntry =
+                    factory().buildFlowAdd()
+                                .setMatch(matchPort)
+                                .setInstructions(instructions)
+                                .setXid(getNextTransactionId())
+                                .build();
+            log.debug("Adding optical flow in sw {}", getStringId());
+            List<OFMessage> msglist = new ArrayList<>(1);
+            msglist.add(opticalFlowEntry);
+            write(msglist);
+        } else if (getId() == 0x0000ffffffffff03L) {
+            final int inport = 21;
+            final int outport = 22;
+            //Circuit signal id
+            CircuitSignalID sigID = getSignalID(lambda);
+
+            OFOxmOchSigid fieldSigIDMatch = factory().oxms().ochSigid(sigID);
+            OFOxmOchSigtype fieldSigType = factory()
+                    .oxms()
+                    .ochSigtype(SIGNAL_TYPE);
+
+            OFOxmOchSigidBasic ofOxmOchSigidBasic =
+                    factory().oxms().ochSigidBasic(sigID);
+
+            OFOxmOchSigtypeBasic ofOxmOchSigtypeBasic =
+                    factory().oxms().ochSigtypeBasic(SIGNAL_TYPE);
+
+            //Match Port,SigType,SigID
+            OFOxmInPort fieldPort = factory()
+                    .oxms()
+                    .inPort(OFPort.of(inport));
+            OFMatchV3 matchPort = factory()
+                    .buildMatchV3()
+                    .setOxmList(OFOxmList.of(fieldPort,
+                                             fieldSigType,
+                                             fieldSigIDMatch))
+                    .build();
+
+            // Set Action outport ,SigType, sigID
+            List<OFAction> actionList = new ArrayList<>();
+            OFAction actionOutPort =
+                    factory().actions().output(OFPort.of(outport),
+                                                  Short.MAX_VALUE);
+
+            OFActionCircuit setActionSigType = factory()
+                    .actions()
+                    .circuit(ofOxmOchSigtypeBasic);
+            OFActionCircuit actionCircuit = factory()
+                    .actions()
+                    .circuit(ofOxmOchSigidBasic);
+
+
+            actionList.add(actionOutPort);
+            actionList.add(setActionSigType);
+            actionList.add(actionCircuit);
+
+            OFInstruction instructionAction =
+                    factory().instructions().buildApplyActions()
+                                .setActions(actionList)
+                                .build();
+            List<OFInstruction> instructions =
+                    Collections.singletonList(instructionAction);
+
+            OFMessage opticalFlowEntry =
+                    factory().buildFlowAdd()
+                                 .setMatch(matchPort)
+                                 .setInstructions(instructions)
+                                 .setXid(getNextTransactionId())
+                                 .build();
+            log.debug("Adding optical flow in sw {}", getStringId());
+            List<OFMessage> msglist = new ArrayList<>(1);
+            msglist.add(opticalFlowEntry);
+            write(msglist);
+
+        } else if (getId() == 0x0000ffffffffff04L) {
+            final int inport = 23;
+            final int outport = 11;
+            //Circuit signal id
+            CircuitSignalID sigID = getSignalID(lambda);
+
+            OFOxmOchSigid fieldSigIDMatch = factory().oxms().ochSigid(sigID);
+            OFOxmOchSigtype fieldSigType = factory()
+                    .oxms()
+                    .ochSigtype(SIGNAL_TYPE);
+
+
+            //Match Port, sig type and sig id
+            OFOxmInPort fieldPort = factory()
+                    .oxms()
+                    .inPort(OFPort.of(inport));
+            OFMatchV3 matchPort =
+                    factory().buildMatchV3()
+                                .setOxmList(OFOxmList.of(fieldPort,
+                                                         fieldSigType,
+                                                         fieldSigIDMatch))
+                                .build();
+
+            // Set Action outport
+            List<OFAction> actionList = new ArrayList<>();
+            OFAction actionOutPort =
+                    factory().actions().output(OFPort.of(outport),
+                                                  Short.MAX_VALUE);
+
+            actionList.add(actionOutPort);
+
+            OFInstruction instructionAction =
+                    factory().instructions().buildApplyActions()
+                                .setActions(actionList)
+                                .build();
+            List<OFInstruction> instructions =
+                    Collections.singletonList(instructionAction);
+
+            OFMessage opticalFlowEntry =
+                    factory().buildFlowAdd()
+                                 .setMatch(matchPort)
+                                 .setInstructions(instructions)
+                                 .setXid(getNextTransactionId())
+                                 .build();
+            log.debug("Adding optical flow in sw {}", getStringId());
+            List<OFMessage> msglist = new ArrayList<>(1);
+            msglist.add(opticalFlowEntry);
+            write(msglist);
+        }
+
+    }
+
+    // Todo remove - for testing purpose only
+    private static CircuitSignalID getSignalID(short lambda) {
+        byte myGrid = 1;
+        byte myCs = 2;
+        short myCn = lambda;
+        short mySw = 1;
+
+        CircuitSignalID signalID = new CircuitSignalID(myGrid,
+                                                       myCs,
+                                                       myCn,
+                                                       mySw);
+        return signalID;
+    }
+
+    @Override
+    public void write(OFMessage msg) {
+        this.channel.write(msg);
+    }
+
+    @Override
+    public void write(List<OFMessage> msgs) {
+        this.channel.write(msgs);
+    }
+
+    @Override
+    public Boolean supportNxRole() {
+        return false;
+    }
+
+}