Drivers for Cassini box with IP Infusion OCNOS v5 supports CFP2-DCO and CFP2-ACO.

* patch 2: support of DP_8QAM
* patch 3: support of modulation change from roadm-gui
* patch 4, 5, 6, 7, 8: style
* patch 9: tested device EC_AS7716-24SC-OcNOS-5.0.187-OTN_IPBASE-S0-P0
* patch 10, 11, 12: style
* patch 13: comments by andrea

Change-Id: Ida475c61d5f48a79f8a56bff299dd708c9ad8eaf
diff --git a/apps/roadm/app/src/main/java/org/onosproject/roadm/RoadmManager.java b/apps/roadm/app/src/main/java/org/onosproject/roadm/RoadmManager.java
index 2cbc711..cd08337 100644
--- a/apps/roadm/app/src/main/java/org/onosproject/roadm/RoadmManager.java
+++ b/apps/roadm/app/src/main/java/org/onosproject/roadm/RoadmManager.java
@@ -328,13 +328,7 @@
         Direction component = Direction.ALL;
         if (device.is(ModulationConfig.class)) {
             ModulationConfig<Object> modulationConfig = device.as(ModulationConfig.class);
-            long bitRate = 0;
-            if (modulation.equalsIgnoreCase(ModulationScheme.DP_QPSK.name())) {
-                bitRate = 100;
-            } else {
-                bitRate = 200;
-            }
-            modulationConfig.setModulationScheme(portNumber, component, bitRate);
+            modulationConfig.setModulationScheme(portNumber, component, ModulationScheme.valueOf(modulation));
         }
 
     }
diff --git a/apps/roadm/app/src/main/java/org/onosproject/roadm/RoadmPortViewMessageHandler.java b/apps/roadm/app/src/main/java/org/onosproject/roadm/RoadmPortViewMessageHandler.java
index 7d5ceab..86c644f 100644
--- a/apps/roadm/app/src/main/java/org/onosproject/roadm/RoadmPortViewMessageHandler.java
+++ b/apps/roadm/app/src/main/java/org/onosproject/roadm/RoadmPortViewMessageHandler.java
@@ -237,11 +237,14 @@
 
         // Returns the current input power as a string, Unknown if no value can be found.
         private String getCurrentInputPower(DeviceId deviceId, PortNumber portNumber) {
-            PowerConfig powerConfig = deviceService.getDevice(deviceId).as(PowerConfig.class);
-            Optional<Double> currentInputPower = powerConfig.currentInputPower(portNumber, Direction.ALL);
             Double inputPowerVal = null;
-            if (currentInputPower.isPresent()) {
-                inputPowerVal = currentInputPower.orElse(Double.MIN_VALUE);
+            if (deviceService.getDevice(deviceId).is(PowerConfig.class)) {
+                PowerConfig powerConfig = deviceService.getDevice(deviceId).as(PowerConfig.class);
+                Optional<Double> currentInputPower = powerConfig.currentInputPower(portNumber, Direction.ALL);
+
+                if (currentInputPower.isPresent()) {
+                    inputPowerVal = currentInputPower.orElse(Double.MIN_VALUE);
+                }
             }
             return RoadmUtil.objectToString(inputPowerVal, RoadmUtil.UNKNOWN);
         }
diff --git a/apps/roadm/web/roadm-gui/lib/port/port.component.html b/apps/roadm/web/roadm-gui/lib/port/port.component.html
index 5c82dc4..18f8577 100644
--- a/apps/roadm/web/roadm-gui/lib/port/port.component.html
+++ b/apps/roadm/web/roadm-gui/lib/port/port.component.html
@@ -108,8 +108,9 @@
                     <td [ngClass]="(isDelta() ? 'delta' : '')">
                         <form [formGroup]="modulationForm" (ngSubmit)="submitModulation(devId, port.id)" *ngIf="port.type=='OCH'">
                             <select [(ngModel)]="port.modulation" formControlName="newModulation">
-                                <option value="dp_qpsk">qpsk</option>
-                                <option value="dp_16qam">16qam</option>
+                                <option value="DP_QPSK">DP_QPSK</option>
+                                <option value="DP_16QAM">DP_16QAM</option>
+                                <option value="DP_8QAM">DP_8QAM</option>
                             </select>
                             <button type="submit">Submit</button>
                         </form>
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/ModulationConfig.java b/core/api/src/main/java/org/onosproject/net/behaviour/ModulationConfig.java
index 8aa4dbe..d27b273 100644
--- a/core/api/src/main/java/org/onosproject/net/behaviour/ModulationConfig.java
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/ModulationConfig.java
@@ -53,5 +53,14 @@
      */
     void setModulationScheme(PortNumber port, T component, long bitRate);
 
+    /**
+     * Set the target Modulation Scheme on the component.
+     *
+     * @param port the port
+     * @param component the port component
+     * @param modulationScheme adopted modulation scheme
+     */
+    void setModulationScheme(PortNumber port, T component, ModulationScheme modulationScheme);
+
 }
 
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniOcnos5BitErrorRate.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniOcnos5BitErrorRate.java
new file mode 100644
index 0000000..de87bec
--- /dev/null
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniOcnos5BitErrorRate.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2022-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This work was partially supported by EC H2020 project B5G-OPEN (101016663).
+ */
+
+package org.onosproject.drivers.odtn;
+
+import org.apache.commons.configuration.XMLConfiguration;
+import org.onosproject.drivers.odtn.util.NetconfSessionUtility;
+import org.onosproject.drivers.utilities.XmlConfigParser;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.behaviour.BitErrorRateState;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.netconf.NetconfController;
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.netconf.NetconfSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Optional;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.odtn.behaviour.OdtnDeviceDescriptionDiscovery.OC_OPTICAL_CHANNEL_NAME;
+
+/**
+ * Implementation of BitErrorRateState interface for Cassini device running Ocnos v5.
+ */
+public class CassiniOcnos5BitErrorRate
+        extends AbstractHandlerBehaviour implements BitErrorRateState {
+
+    private static final Logger log = LoggerFactory.getLogger(CassiniOcnos5BitErrorRate.class);
+
+    private static final String RPC_TAG_NETCONF_BASE =
+            "<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">";
+
+    private static final String RPC_CLOSE_TAG = "</rpc>";
+    private static final String PRE_FEC_BER_TAG = "current-pre-fec-ber";
+    private static final String POST_FEC_BER_TAG = "current-post-fec-ber";
+    private static final String PRE_FEC_BER_FILTER =
+            "data.terminal-device.coherent-module.network-interfaces.interface.ber.state." + PRE_FEC_BER_TAG;
+    private static final String POST_FEC_BER_FILTER =
+            "data..terminal-device.coherent-module.network-interfaces.interface.ber.state." + POST_FEC_BER_TAG;
+
+    /*
+     * This method returns the instance of NetconfController from DriverHandler.
+     */
+    private NetconfController getController() {
+        return handler().get(NetconfController.class);
+    }
+
+    /**
+     * Get the BER value pre FEC.
+     *
+     * @param deviceId the device identifier
+     * @param port     the port identifier
+     * @return the decimal value of BER
+     */
+    @Override
+    public Optional<Double> getPreFecBer(DeviceId deviceId, PortNumber port) {
+        NetconfSession session = NetconfSessionUtility
+                .getNetconfSession(deviceId, getController());
+        checkNotNull(session);
+
+        String slotIndex = getOpticalChannel(port);
+
+        if (slotIndex != null) {
+
+            String reply;
+            try {
+                reply = session.get(getBerFilter(slotIndex, PRE_FEC_BER_TAG));
+            } catch (Exception e) {
+                throw new IllegalStateException(new NetconfException("Failed to retrieve getPreFecBer info.", e));
+            }
+
+            log.debug("REPLY from device: {}", reply);
+
+            XMLConfiguration xconf = (XMLConfiguration) XmlConfigParser.loadXmlString(reply);
+            if (xconf == null) {
+                log.error("Error in executing RPC");
+                return Optional.empty();
+            }
+
+            String powerString = xconf.getString((PRE_FEC_BER_FILTER));
+
+            log.debug("currentPreFecBer from device: {}", powerString);
+
+            if (powerString == null) {
+                return Optional.empty();
+            }
+
+            Double rational = 1e18;
+            return Optional.of(Double.valueOf(powerString) / rational);
+        }
+
+        return Optional.empty();
+    }
+
+    /**
+     * Get the OpenConfig component name for the OpticalChannel component.
+     *
+     * @param portNumber ONOS port number of the Line port ().
+     * @return the channel component name or null
+     */
+    protected String getOpticalChannel(PortNumber portNumber) {
+        Port clientPort = handler().get(DeviceService.class).getPort(did(), portNumber);
+        return clientPort.annotations().value(OC_OPTICAL_CHANNEL_NAME);
+    }
+
+    /**
+     * Get the deviceId for which the methods apply.
+     *
+     * @return The deviceId as contained in the handler data
+     */
+    private DeviceId did() {
+        return handler().data().deviceId();
+    }
+
+    /**
+     * Get the BER value post FEC.
+     *
+     * @param deviceId the device identifier
+     * @param port     the port identifier
+     * @return the decimal value of BER
+     */
+    @Override
+    public Optional<Double> getPostFecBer(DeviceId deviceId, PortNumber port) {
+        NetconfSession session = NetconfSessionUtility
+                .getNetconfSession(deviceId, getController());
+        checkNotNull(session);
+
+        String slotIndex = getOpticalChannel(port);
+
+        if (slotIndex != null) {
+
+            String reply;
+            try {
+                reply = session.get(getBerFilter(slotIndex, POST_FEC_BER_TAG));
+            } catch (Exception e) {
+                throw new IllegalStateException(new NetconfException("Failed to retrieve getPostFecBer info.", e));
+            }
+
+            log.debug("REPLY from device: {}", reply);
+
+            XMLConfiguration xconf = (XMLConfiguration) XmlConfigParser.loadXmlString(reply);
+            if (xconf == null) {
+                log.error("Error in executing RPC");
+                return Optional.empty();
+            }
+
+            String powerString = xconf.getString(POST_FEC_BER_FILTER);
+
+            log.debug("currentPostFecBer from device: {}", powerString);
+
+            if (powerString == null) {
+                return Optional.empty();
+            }
+
+            Double rational = 1e18;
+            return Optional.of(Double.valueOf(powerString) / rational);
+        }
+
+        return Optional.empty();
+    }
+
+    private String getBerFilter(String slotNumber, String filterBer) {
+        StringBuilder filter = new StringBuilder();
+
+        filter.append("<terminal-device xmlns='http://www.ipinfusion.com/yang/ocnos/ipi-platform-terminal-device'>"
+                + "<coherent-module>"
+                + "  <slot-index>" + slotNumber + "</slot-index>"
+                + "<network-interfaces>"
+                + "<interface>"
+                + "  <net-index>0</net-index>"
+                + "  <ber>"
+                + "    <state>"
+                + "      <" + filterBer + "/>"
+                + "    </state>"
+                + "  </ber>"
+                + "</interface>"
+                + "</network-interfaces>"
+                + "</coherent-module>"
+                + "</terminal-device>");
+
+        return filteredGetBuilder(filter.toString());
+    }
+
+    private String filteredGetBuilder(String filter) {
+        StringBuilder rpc = new StringBuilder(RPC_TAG_NETCONF_BASE);
+        rpc.append("<get>");
+        rpc.append("<filter type='subtree'>");
+        rpc.append(filter);
+        rpc.append("</filter>");
+        rpc.append("</get>");
+        rpc.append(RPC_CLOSE_TAG);
+        return rpc.toString();
+    }
+}
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniOcnos5DeviceDiscovery.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniOcnos5DeviceDiscovery.java
new file mode 100644
index 0000000..88e62bb
--- /dev/null
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniOcnos5DeviceDiscovery.java
@@ -0,0 +1,445 @@
+/*
+ * Copyright 2022-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This work was partially supported by EC H2020 project B5G-OPEN (101016663).
+ */
+
+package org.onosproject.drivers.odtn;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.commons.configuration.HierarchicalConfiguration;
+import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine;
+import org.onlab.packet.ChassisId;
+import org.onosproject.drivers.utilities.XmlConfigParser;
+import org.onosproject.net.Device;
+import org.onosproject.net.Port;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.SparseAnnotations;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.OchSignal;
+import org.onosproject.net.OduSignalType;
+import org.onosproject.net.ChannelSpacing;
+import org.onosproject.net.device.PortDescription;
+import org.onosproject.net.device.DefaultPortDescription;
+import org.onosproject.net.device.DeviceDescription;
+import org.onosproject.net.device.DefaultDeviceDescription;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.device.DeviceDescriptionDiscovery;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.optical.device.OchPortHelper;
+import org.onosproject.netconf.NetconfController;
+import org.onosproject.netconf.NetconfDevice;
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.netconf.NetconfSession;
+import org.onosproject.odtn.behaviour.OdtnDeviceDescriptionDiscovery;
+import org.slf4j.Logger;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+Tested on Cassini running OcNOS version EC_AS7716-24SC-OcNOS-5.0.187-OTN_IPBASE-S0-P0.
+
+- Driver consider proprietary YANG model by IP Infusion
+- The device also support an OpenConfig-based model that can be activated using NETCONF translation
+- Cassini CLI command to activate NETCONF translation
+ --- OcNOS# cml netconf translation (disable|openconfig)
+ */
+/**
+ * Implementation of DeviceDescriptionDiscovery interface for Cassini device running Ocnos v5.
+ */
+public class CassiniOcnos5DeviceDiscovery
+    extends AbstractHandlerBehaviour
+    implements OdtnDeviceDescriptionDiscovery, DeviceDescriptionDiscovery {
+
+        private static final String RPC_TAG_NETCONF_BASE =
+                "<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">";
+
+        private static final String RPC_CLOSE_TAG = "</rpc>";
+
+        private static final String OC_PLATFORM_TYPES_TRANSCEIVER =
+                "oc-platform-types:TRANSCEIVER";
+
+        private static final String OC_PLATFORM_TYPES_PORT =
+                "oc-platform-types:PORT";
+
+        private static final String OC_TRANSPORT_TYPES_OPTICAL_CHANNEL =
+                "oc-opt-types:OPTICAL_CHANNEL";
+
+        private static final Logger log = getLogger(CassiniOcnos5DeviceDiscovery.class);
+
+        /**
+         * Returns the NetconfSession with the device for which the method was called.
+         *
+         * @param deviceId device indetifier
+         *
+         * @return The netconf session or null
+         */
+        private NetconfSession getNetconfSession(DeviceId deviceId) {
+            NetconfController controller = handler().get(NetconfController.class);
+            NetconfDevice ncdev = controller.getDevicesMap().get(deviceId);
+            if (ncdev == null) {
+                log.trace("No netconf device, returning null session");
+                return null;
+            }
+            return ncdev.getSession();
+        }
+
+
+        /**
+         * Get the deviceId for which the methods apply.
+         *
+         * @return The deviceId as contained in the handler data
+         */
+        private DeviceId did() {
+            return handler().data().deviceId();
+        }
+
+
+        /**
+         * Get the device instance for which the methods apply.
+         *
+         * @return The device instance
+         */
+        private Device getDevice() {
+            DeviceService deviceService = checkNotNull(handler().get(DeviceService.class));
+            Device device = deviceService.getDevice(did());
+            return device;
+        }
+
+
+        /**
+         * Construct a String with a Netconf filtered get RPC Message.
+         *
+         * @param filter A valid XML tree with the filter to apply in the get
+         * @return a String containing the RPC XML Document
+         */
+        private String filteredGetBuilder(String filter) {
+            StringBuilder rpc = new StringBuilder(RPC_TAG_NETCONF_BASE);
+            rpc.append("<get>");
+            rpc.append("<filter type='subtree'>");
+            rpc.append(filter);
+            rpc.append("</filter>");
+            rpc.append("</get>");
+            rpc.append(RPC_CLOSE_TAG);
+            return rpc.toString();
+        }
+
+
+        /**
+         * Construct a String with a Netconf filtered get RPC Message.
+         *
+         * @param filter A valid XPath Expression with the filter to apply in the get
+         * @return a String containing the RPC XML Document
+         *
+         * Note: server must support xpath capability.
+
+         * <select=" /components/component[name='PORT-A-In-1']/properties/...
+         * ...property[name='onos-index']/config/value" type="xpath"/>
+         */
+        private String xpathFilteredGetBuilder(String filter) {
+            StringBuilder rpc = new StringBuilder(RPC_TAG_NETCONF_BASE);
+            rpc.append("<get>");
+            rpc.append("<filter type='xpath' select=\"");
+            rpc.append(filter);
+            rpc.append("\"/>");
+            rpc.append("</get>");
+            rpc.append(RPC_CLOSE_TAG);
+            return rpc.toString();
+        }
+
+
+        /**
+         * Builds a request to get Device details, operational data.
+         *
+         * @return A string with the Netconf RPC for a get with subtree rpcing based on
+         *    /components/component/state/type being oc-platform-types:OPERATING_SYSTEM
+         */
+        private String getDeviceDetailsBuilder() {
+            StringBuilder filter = new StringBuilder();
+            filter.append("<components xmlns='http://openconfig.net/yang/platform'>");
+            filter.append(" <component>");
+            filter.append("  <state>");
+            filter.append("   <type xmlns:oc-platform-types='http://openconfig.net/");
+            filter.append("yang/platform-types'>oc-platform-types:OPERATING_SYSTEM</type>");
+            filter.append("  </state>");
+            filter.append(" </component>");
+            filter.append("</components>");
+            return filteredGetBuilder(filter.toString());
+        }
+
+        private String getCassiniDeviceDetailsBuilder() {
+            StringBuilder filter = new StringBuilder();
+            filter.append("<components xmlns='http://www.ipinfusion.com/yang/ocnos/ipi-platform'>");
+            filter.append(" <component>");
+            filter.append("   <name>CHASSIS</name>");
+            filter.append(" </component>");
+            filter.append("</components>");
+            return filteredGetBuilder(filter.toString());
+        }
+
+        private String getCassiniDeviceComponentsBuilder() {
+                StringBuilder filter = new StringBuilder();
+                filter.append("<components xmlns='http://www.ipinfusion.com/yang/ocnos/ipi-platform'>");
+                filter.append("</components>");
+                return filteredGetBuilder(filter.toString());
+        }
+
+        /**
+         * Returns a DeviceDescription with Device info.
+         *
+         * @return DeviceDescription or null
+         *
+         * //CHECKSTYLE:OFF
+         * <pre>{@code
+         * <data>
+         * <components xmlns="http://openconfig.net/yang/platform">
+         *  <component>
+         *   <state>
+         *     <name>FIRMWARE</name>
+         *     <type>oc-platform-types:OPERATING_SYSTEM</type>
+         *     <description>CTTC METRO-HAUL Emulated OpenConfig TerminalDevice</description>
+         *     <version>0.0.1</version>
+         *   </state>
+         *  </component>
+         * </components>
+         * </data>
+         *}</pre>
+         * //CHECKSTYLE:ON
+         */
+        @Override
+        public DeviceDescription discoverDeviceDetails() {
+            log.info("CassiniOcnos5DeviceDiscovery::discoverDeviceDetails device {}", did());
+            boolean defaultAvailable = true;
+            SparseAnnotations annotations = DefaultAnnotations.builder().build();
+
+            org.onosproject.net.Device.Type type = Device.Type.TERMINAL_DEVICE;
+
+            // Some defaults
+            String vendor       = "Not loaded";
+            String hwVersion    = "Not loaded";
+            String swVersion    = "Not loaded";
+            String serialNumber = "Not loaded";
+            String chassisId    = "12";
+
+            // Get the session,
+            NetconfSession session = getNetconfSession(did());
+            if (session != null) {
+                try {
+                    String reply = session.get(getCassiniDeviceDetailsBuilder());
+                    XMLConfiguration xconf = (XMLConfiguration) XmlConfigParser.loadXmlString(reply);
+
+                    log.debug("REPLY from device: {}", xconf);
+
+                    vendor       = xconf.getString("data.components.component.chassis.state.vendor-name", vendor);
+                    serialNumber = xconf.getString("data.components.component.state.serial-no", serialNumber);
+                    // Requires OpenConfig >= 2018
+                    swVersion    = xconf.getString("data.components.component.state.software-version", swVersion);
+                    hwVersion    = xconf.getString("data.components.component.state.mfg-date", hwVersion);
+                } catch (Exception e) {
+                    throw new IllegalStateException(new NetconfException("Failed to retrieve version info.", e));
+                }
+            } else {
+                log.info("CassiniOcnos5DeviceDiscovery::discoverDeviceDetails - No netconf session for {}", did());
+            }
+
+            log.info("VENDOR    {}", vendor);
+            log.info("HWVERSION {}", hwVersion);
+            log.info("SWVERSION {}", swVersion);
+            log.info("SERIAL    {}", serialNumber);
+            log.info("CHASSISID {}", chassisId);
+
+            ChassisId cid = new ChassisId(Long.valueOf(chassisId, 10));
+
+            return new DefaultDeviceDescription(did().uri(),
+                    type, vendor, hwVersion, swVersion, serialNumber,
+                    cid, defaultAvailable, annotations);
+        }
+
+        /**
+         * Returns a list of PortDescriptions for the device.
+         *
+         * @return a list of descriptions.
+         *
+         * The RPC reply follows the following pattern:
+         * //CHECKSTYLE:OFF
+         * <pre>{@code
+         * <?xml version="1.0" encoding="UTF-8"?>
+         * <rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="7">
+         * <data>
+         *   <components xmlns="http://openconfig.net/yang/platform">
+         *     <component>....
+         *     </component>
+         *     <component>....
+         *     </component>
+         *   </components>
+         * </data>
+         * </rpc-reply>
+         * }</pre>
+         * //CHECKSTYLE:ON
+         */
+        @Override
+        public List<PortDescription> discoverPortDetails() {
+            try {
+                XPathExpressionEngine xpe = new XPathExpressionEngine();
+                NetconfSession session = getNetconfSession(did());
+                if (session == null) {
+                    log.error("discoverPortDetails called with null session for {}", did());
+                    return ImmutableList.of();
+                }
+
+                String reply = session.get(getCassiniDeviceComponentsBuilder());
+
+                XMLConfiguration xconf = (XMLConfiguration) XmlConfigParser.loadXmlString(reply);
+                xconf.setExpressionEngine(xpe);
+
+                HierarchicalConfiguration components = xconf.configurationAt("data/components");
+                return parsePorts(components);
+            } catch (Exception e) {
+                log.error("Exception discoverPortDetails() {}", did(), e);
+                return ImmutableList.of();
+            }
+        }
+
+        /**
+         * Parses port information from OpenConfig XML configuration.
+         *
+         * @param components the XML document with components root.
+         * @return List of ports
+         *
+         * //CHECKSTYLE:OFF
+         * <pre>{@code
+         *   <components xmlns="http://openconfig.net/yang/platform">
+         *     <component>....
+         *     </component>
+         *     <component>....
+         *     </component>
+         *   </components>
+         * }</pre>
+         * //CHECKSTYLE:ON
+         */
+        protected List<PortDescription> parsePorts(HierarchicalConfiguration components) {
+
+            return components.configurationsAt("component")
+                    .stream()
+                    .map(component -> {
+                                try {
+                                    // Pass the root document for cross-reference
+                                    return parsePortComponent(component);
+                                } catch (Exception e) {
+                                    return null;
+                                }
+                            }
+                    )
+                    .filter(Objects::nonNull)
+                    .collect(Collectors.toList());
+        }
+
+        /**
+         * Parses a component XML doc into a PortDescription.
+         *
+         * @param component subtree to parse. It must be a component ot type PORT.
+         *  case we need to check transceivers or optical channels.
+         *
+         * @return PortDescription or null if component does not have onos-index
+         */
+        private PortDescription parsePortComponent(HierarchicalConfiguration component) {
+            Map<String, String> annotations = new HashMap<>();
+            String name = component.getString("name");
+
+            log.info("Parsing Component {}", name);
+
+            // Build the port using heuristic
+            // NOTE: using portNumber(id, name) breaks things. Intent parsing, port resorce management, etc. There seems
+            // to be an issue with resource mapping
+
+            if (name.contains("QSFP")) {
+                annotations.put(PORT_TYPE, OdtnDeviceDescriptionDiscovery.OdtnPortType.CLIENT.value());
+
+                // Assing an ONOS port number
+                PortNumber portNum;
+                portNum = PortNumber.portNumber(fromPortNameToPortId(name));
+                log.info("--- CLIENT PORT {} assigned number {}", name, portNum);
+
+                DefaultPortDescription.Builder builder = DefaultPortDescription.builder();
+                builder.type(Port.Type.PACKET);
+                builder.withPortNumber(portNum);
+                builder.annotations(DefaultAnnotations.builder().putAll(annotations).build());
+
+                return builder.build();
+            }
+
+            //Could be improved checking if there is an OCH subcomponent or current <oper-status>
+            if (name.contains("PORT-coherent")) {
+                PortNumber portNum;
+                portNum = PortNumber.portNumber(fromPortNameToPortId(name));
+
+                annotations.put(PORT_TYPE, OdtnDeviceDescriptionDiscovery.OdtnPortType.LINE.value());
+
+                String state = component.configurationAt("state").getString("oper-status");
+
+                if (!state.contains("disabled")) {
+                    String slotName = String.valueOf(portNum.toLong() - 100);
+
+                    //Config annotations
+                    annotations.put(PORT_TYPE, OdtnPortType.LINE.value());
+                    annotations.put(OC_NAME, name);
+                    annotations.put(OC_OPTICAL_CHANNEL_NAME, slotName);
+
+                    log.info("--- LINE port {} assigned onos index {}", name, portNum);
+                    log.info("--- LINE port {} associated OPTICAL_CHANNEL {}", name, slotName);
+
+                    // TODO: To be configured
+                    OchSignal signalId = OchSignal.newDwdmSlot(ChannelSpacing.CHL_50GHZ, 1);
+
+                    return OchPortHelper.ochPortDescription(
+                            portNum, true,
+                            OduSignalType.ODU4, // TODO Client signal to be discovered
+                            true,
+                            signalId,
+                            DefaultAnnotations.builder().putAll(annotations).build());
+                } else {
+                    log.info("--- LINE port {} is disabled", name);
+                }
+            }
+
+            log.warn("Unknown port type");
+            return null;
+        }
+
+    //Client ports are reported in the model as QSFP-1, QSFP-2 and imported as 1, 2, ...
+    //Line ports are reported in the model as PORT-Coherent-1, PORT-Coherent-2 and imported as 101, 102
+        public int fromPortNameToPortId(String name) {
+            String[] portions;
+            if (name.contains("QSFP")) {
+                portions = name.split("-");
+                return Integer.parseInt(portions[1]);
+            }
+            if (name.contains("PORT")) {
+                portions = name.split("-");
+                return (100 + Integer.parseInt(portions[2]));
+            }
+            log.error("Port name not supported");
+            return 0;
+        }
+}
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniOcnos5FlowRuleProgrammable.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniOcnos5FlowRuleProgrammable.java
new file mode 100644
index 0000000..ac50a30
--- /dev/null
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniOcnos5FlowRuleProgrammable.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2022-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This work was partially supported by EC H2020 project B5G-OPEN (101016663).
+ */
+
+package org.onosproject.drivers.odtn;
+
+import com.google.common.collect.ImmutableList;
+import org.onosproject.drivers.odtn.impl.DeviceConnectionCache;
+import org.onosproject.drivers.odtn.impl.FlowRuleParser;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.flow.DefaultFlowEntry;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleProgrammable;
+import org.onosproject.netconf.DatastoreId;
+import org.onosproject.netconf.NetconfController;
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.netconf.NetconfSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.odtn.behaviour.OdtnDeviceDescriptionDiscovery.OC_OPTICAL_CHANNEL_NAME;
+
+/**
+ * Implementation of FlowRuleProgrammable interface for Cassini device running Ocnos v5.
+ */
+public class CassiniOcnos5FlowRuleProgrammable
+        extends AbstractHandlerBehaviour implements FlowRuleProgrammable {
+
+    private static final Logger log =
+            LoggerFactory.getLogger(CassiniOcnos5FlowRuleProgrammable.class);
+
+    private static final String RPC_TAG_NETCONF_BASE =
+            "<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">";
+
+    private static final String RPC_CLOSE_TAG = "</rpc>";
+
+
+    /**
+     * Apply the flow entries specified in the collection rules.
+     *
+     * @param rules A collection of Flow Rules to be applied
+     * @return The collection of added Flow Entries
+     */
+    @Override
+    public Collection<FlowRule> applyFlowRules(Collection<FlowRule> rules) {
+        NetconfSession session = getNetconfSession();
+        if (session == null) {
+            ocnosError("null session");
+            return ImmutableList.of();
+        }
+        List<FlowRule> added = new ArrayList<>();
+        for (FlowRule r : rules) {
+            try {
+                String connectionId = applyFlowRule(session, r);
+                getConnectionCache().add(did(), connectionId, r);
+                added.add(r);
+            } catch (Exception e) {
+                ocnosError("Error {}", e);
+                continue;
+            }
+        }
+        ocnosLog("applyFlowRules added {}", added.size());
+        return added;
+    }
+
+    /**
+     * Get the flow entries that are present on the device.
+     *
+     * @return A collection of Flow Entries
+     */
+    @Override
+    public Collection<FlowEntry> getFlowEntries() {
+        DeviceConnectionCache cache = getConnectionCache();
+        if (cache.get(did()) == null) {
+            return ImmutableList.of();
+        }
+
+        List<FlowEntry> entries = new ArrayList<>();
+        for (FlowRule r : cache.get(did())) {
+            entries.add(
+                    new DefaultFlowEntry(r, FlowEntry.FlowEntryState.ADDED, 0, 0, 0));
+        }
+        return entries;
+    }
+
+    /**
+     * Remove the specified flow rules.
+     *
+     * @param rules A collection of Flow Rules to be removed
+     * @return The collection of removed Flow Entries
+     */
+    @Override
+    public Collection<FlowRule> removeFlowRules(Collection<FlowRule> rules) {
+        NetconfSession session = getNetconfSession();
+        if (session == null) {
+            ocnosError("null session");
+            return ImmutableList.of();
+        }
+        List<FlowRule> removed = new ArrayList<>();
+        for (FlowRule r : rules) {
+            try {
+                String connectionId = removeFlowRule(session, r);
+                getConnectionCache().remove(did(), connectionId);
+                removed.add(r);
+            } catch (Exception e) {
+                ocnosError("Error {}", e);
+                continue;
+            }
+        }
+        ocnosLog("removedFlowRules removed {}", removed.size());
+        return removed;
+    }
+
+    private DeviceConnectionCache getConnectionCache() {
+        return DeviceConnectionCache.init();
+    }
+
+    /**
+     * Helper method to get the device id.
+     */
+    private DeviceId did() {
+        return data().deviceId();
+    }
+
+    /**
+     * Helper method to log from this class adding DeviceId.
+     */
+    private void ocnosLog(String format, Object... arguments) {
+        log.info("OCNOS5 {}: " + format, did(), arguments);
+    }
+
+    /**
+     * Helper method to log an error from this class adding DeviceId.
+     */
+    private void ocnosError(String format, Object... arguments) {
+        log.error("OCNOS5 {}: " + format, did(), arguments);
+    }
+
+    /**
+     * Helper method to get the Netconf Session.
+     */
+    private NetconfSession getNetconfSession() {
+        NetconfController controller =
+                checkNotNull(handler().get(NetconfController.class));
+        return controller.getNetconfDevice(did()).getSession();
+    }
+
+    /**
+     * Get the OpenConfig component name for the OpticalChannel component.
+     *
+     * @param portNumber ONOS port number of the Line port ().
+     * @return the channel component name or null
+     */
+    protected String getOpticalChannel(PortNumber portNumber) {
+        Port clientPort = handler().get(DeviceService.class).getPort(did(), portNumber);
+        return clientPort.annotations().value(OC_OPTICAL_CHANNEL_NAME);
+    }
+
+    public void setOpticalChannelFrequency(NetconfSession session, FlowRuleParser r)
+            throws NetconfException {
+        StringBuilder sbSet = new StringBuilder();
+
+        String slot = getOpticalChannel(r.getPortNumber());
+
+        sbSet.append("<terminal-device xmlns='http://www.ipinfusion.com/yang/ocnos/ipi-platform-terminal-device'>"
+                + "<coherent-module>"
+                + "  <slot-index>" + slot + "</slot-index>"
+                + "  <config>"
+                + "    <slot-index>" + slot + "</slot-index>"
+                + "  </config>"
+                + "<network-interfaces>"
+                + "<interface>"
+                + "  <net-index>0</net-index>"
+                + "  <config>"
+                + "    <net-index>0</net-index>"
+                + "    <frequency>" + r.getCentralFrequency().asHz() + "Hz</frequency>"
+                + "  </config>"
+                + "</interface>"
+                + "</network-interfaces>"
+                + "</coherent-module>"
+                + "</terminal-device>");
+
+        log.info("Configure optical channel {}", sbSet);
+
+        boolean set = session.editConfig(DatastoreId.CANDIDATE, null, sbSet.toString());
+        if (!set) {
+            throw new NetconfException("error editing channel frequency");
+        }
+
+        log.info("Commit configure optical channel");
+        boolean commit2 = session.commit();
+        if (!commit2) {
+            throw new NetconfException("error committing channel frequency");
+        }
+    };
+
+    public void deleteOpticalChannelFrequency(NetconfSession session, FlowRuleParser r)
+            throws NetconfException {
+        StringBuilder sb = new StringBuilder();
+
+        String slot = getOpticalChannel(r.getPortNumber());
+
+        sb.append("<terminal-device xmlns='http://www.ipinfusion.com/yang/ocnos/ipi-platform-terminal-device'>"
+                + "<coherent-module>"
+                + "  <slot-index>" + slot + "</slot-index>"
+                + "  <config>"
+                + "    <slot-index>" + slot + "</slot-index>"
+                + "  </config>"
+                + "<network-interfaces>"
+                + "<interface>"
+                + "  <net-index>0</net-index>"
+                + "  <config>"
+                + "    <net-index>0</net-index>"
+                + "    <frequency>" + r.getCentralFrequency().asHz() + "Hz</frequency>"
+                + "  </config>"
+                + "</interface>"
+                + "</network-interfaces>"
+                + "</coherent-module>"
+                + "</terminal-device>");
+
+        log.info("Disable service and delete optical channel {}", sb);
+        boolean edit = session.editConfig(DatastoreId.CANDIDATE, null, sb.toString());
+        if (!edit) {
+            throw new NetconfException("error editing channel frequency");
+        }
+
+        log.info("Commit optical channel");
+        boolean commit = session.commit();
+        if (!commit) {
+            throw new NetconfException("error committing channel frequency");
+        }
+    };
+
+
+    /**
+     * Apply the flowrule.
+     *
+     * @param session The Netconf session.
+     * @param r       Flow Rules to be applied.
+     * @return the optical channel + the frequency or just channel as identifier fo the config installed on the device
+     * @throws NetconfException if exchange goes wrong
+     */
+    protected String applyFlowRule(NetconfSession session, FlowRule r)
+            throws NetconfException {
+        FlowRuleParser frp = new FlowRuleParser(r);
+
+        setOpticalChannelFrequency(session, frp);
+        return frp.getPortNumber() + ":" + frp.getCentralFrequency().asGHz();
+    }
+
+
+    protected String removeFlowRule(NetconfSession session, FlowRule r)
+            throws NetconfException {
+        FlowRuleParser frp = new FlowRuleParser(r);
+
+        deleteOpticalChannelFrequency(session, frp);
+        return frp.getPortNumber() + ":" + frp.getCentralFrequency().asGHz();
+    }
+}
+
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniOcnos5Modulation.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniOcnos5Modulation.java
new file mode 100644
index 0000000..f73108d
--- /dev/null
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniOcnos5Modulation.java
@@ -0,0 +1,378 @@
+/*
+ * Copyright 2022-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This work was partially supported by EC H2020 project B5G-OPEN (101016663).
+ */
+
+package org.onosproject.drivers.odtn;
+
+import org.apache.commons.configuration.XMLConfiguration;
+import org.onosproject.drivers.utilities.XmlConfigParser;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.ModulationScheme;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.behaviour.ModulationConfig;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.netconf.DatastoreId;
+import org.onosproject.netconf.NetconfController;
+import org.onosproject.netconf.NetconfDevice;
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.netconf.NetconfSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Optional;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.odtn.behaviour.OdtnDeviceDescriptionDiscovery.OC_OPTICAL_CHANNEL_NAME;
+
+/**
+ * Implementation of ModulationConfig interface for Cassini device running Ocnos v5.
+ */
+public class CassiniOcnos5Modulation<T> extends AbstractHandlerBehaviour
+        implements ModulationConfig<T> {
+
+    private static final String RPC_TAG_NETCONF_BASE =
+            "<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">";
+
+    private static final String RPC_CLOSE_TAG = "</rpc>";
+
+    private static final Logger log = LoggerFactory.getLogger(CassiniOcnos5Modulation.class);
+
+    /**
+     * Returns the NetconfSession with the device for which the method was called.
+     *
+     * @param deviceId device indetifier
+     * @return The netconf session or null
+     */
+    private NetconfSession getNetconfSession(DeviceId deviceId) {
+        NetconfController controller = handler().get(NetconfController.class);
+        NetconfDevice ncdev = controller.getDevicesMap().get(deviceId);
+        if (ncdev == null) {
+            log.trace("No netconf device, returning null session");
+            return null;
+        }
+        return ncdev.getSession();
+    }
+
+    /**
+     * Get the OpenConfig component name for the OpticalChannel component.
+     *
+     * @param portNumber ONOS port number of the Line port ().
+     * @return the channel component name or null
+     */
+    protected String getOpticalChannel(PortNumber portNumber) {
+        Port clientPort = handler().get(DeviceService.class).getPort(did(), portNumber);
+        return clientPort.annotations().value(OC_OPTICAL_CHANNEL_NAME);
+    }
+
+    /*
+     *
+     * Get the deviceId for which the methods apply.
+     *
+     * @return The deviceId as contained in the handler data
+     */
+    private DeviceId did() {
+        return handler().data().deviceId();
+    }
+
+    private String getOpModeFilter(String slotName) {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append("<terminal-device xmlns='http://www.ipinfusion.com/yang/ocnos/ipi-platform-terminal-device'>"
+                + "<coherent-module>"
+                + "  <slot-index>" + slotName + "</slot-index>"
+                + "<network-interfaces>"
+                + "<interface>"
+                + "  <net-index>0</net-index>"
+                + "  <state>"
+                + "    <modulation-format/>"
+                + "  </state>"
+                + "</interface>"
+                + "</network-interfaces>"
+                + "</coherent-module>"
+                + "</terminal-device>");
+
+        return sb.toString();
+    }
+
+    /*Parse filtering string from port and component.
+     *
+     * @param portNumber Port Number
+     * @param modulation
+     * @return filtering string in xml format
+     */
+    private String setOpModeFilter(PortNumber portNumber, ModulationScheme modulation) {
+
+        String operationalMode = getOperationalMode(modulation);
+        String slotName = getOpticalChannel(portNumber);
+
+        StringBuilder sb = new StringBuilder();
+
+        sb.append("<terminal-device xmlns='http://www.ipinfusion.com/yang/ocnos/ipi-platform-terminal-device'>"
+                + "<coherent-module>"
+                + "  <slot-index>" + slotName + "</slot-index>"
+                + "  <config>"
+                + "    <slot-index>" + slotName + "</slot-index>"
+                + "  </config>"
+                + "<network-interfaces>"
+                + "<interface>"
+                + "  <net-index>0</net-index>"
+                + "  <config>"
+                + "    <net-index>0</net-index>"
+                + "    <modulation-format>" + operationalMode + "</modulation-format>"
+                + "  </config>"
+                + "</interface>"
+                + "</network-interfaces>"
+                + "</coherent-module>"
+                + "</terminal-device>");
+
+        return sb.toString();
+    }
+
+    /**
+     * Get the target Modulation Scheme on the component.
+     *
+     * @param port      the port
+     * @param component the port component
+     * @return ModulationScheme as per bitRate value
+     **/
+    @Override
+    public Optional<ModulationScheme> getModulationScheme(PortNumber port, T component) {
+        if (checkPortComponent(port, component)) {
+            return getOcnosModulationScheme(port, component);
+        }
+        return Optional.empty();
+    }
+
+    /**
+     * Set the target Modulation Scheme on the component.
+     *
+     * @param port      the port
+     * @param component the port component
+     * @param bitRate   bit rate in bps
+     **/
+    @Override
+    public void setModulationScheme(PortNumber port, T component, long bitRate) {
+        if (checkPortComponent(port, component)) {
+            setOcnosModulationScheme(port, component, bitRate);
+        }
+    }
+
+    /**
+     * Set the target Modulation Scheme on the component.
+     *
+     * @param port      the port
+     * @param component the port component
+     * @param modulationScheme   selecetd modulation
+     **/
+    @Override
+    public void setModulationScheme(PortNumber port, T component, ModulationScheme modulationScheme) {
+        if (checkPortComponent(port, component)) {
+            setOcnosModulationScheme(port, component, modulationScheme);
+        }
+    }
+
+    private String filteredEditConfigBuilder(String filterEditConfig) {
+        StringBuilder rpc = new StringBuilder();
+        rpc.append(RPC_TAG_NETCONF_BASE);
+        rpc.append("<edit-config>");
+        rpc.append("<target><" + DatastoreId.CANDIDATE + "/></target>");
+        rpc.append("<config>");
+        rpc.append(filterEditConfig);
+        rpc.append("</config>");
+        rpc.append("</edit-config>");
+        rpc.append(RPC_CLOSE_TAG);
+
+        return rpc.toString();
+    }
+
+    private String filteredGetBuilder(String filter) {
+        StringBuilder rpc = new StringBuilder();
+        rpc.append(RPC_TAG_NETCONF_BASE);
+        rpc.append("<get>");
+        rpc.append("<filter type='subtree'>");
+        rpc.append(filter);
+        rpc.append("</filter>");
+        rpc.append("</get>");
+        rpc.append(RPC_CLOSE_TAG);
+        return rpc.toString();
+    }
+
+    /**
+     * Set the ComponentType to invoke proper methods for different template T.
+     *
+     * @param port the component.
+     * @param component the component.
+     */
+    private Boolean checkPortComponent(PortNumber port, Object component) {
+
+        //Check componenet
+        String clsName = component.getClass().getName();
+        switch (clsName) {
+            case "org.onosproject.net.Direction":
+                break;
+            case "org.onosproject.net.OchSignal":
+                break;
+            default:
+                log.error("Cannot parse the component type {}.", clsName);
+                log.error("The component content is {}.", component.toString());
+                return false;
+        }
+
+        //Check that port has an associated optical channel
+        if (getOpticalChannel(port) == null) {
+            return false;
+        }
+
+        //Checks are ok
+        return true;
+    }
+
+    /*
+     * Set modulation scheme.
+     *
+     * @param port port
+     * @param component component
+     * @param power target value
+     */
+    void setOcnosModulationScheme(PortNumber port, Object component, ModulationScheme modulationScheme) {
+        NetconfSession session = getNetconfSession(did());
+        checkNotNull(session);
+
+        //log.info("Setting modulation scheme {}", modulationScheme);
+
+        String filter = setOpModeFilter(port, modulationScheme);
+        String rpcReq = filteredEditConfigBuilder(filter);
+
+        try {
+            session.rpc(rpcReq);
+        } catch (Exception e) {
+            log.error("Error writing operational mode on CANDIDATE", e);
+        }
+
+        //log.info("Modulation config sent {}", rpcReq);
+
+        try {
+            session.commit();
+        } catch (NetconfException e) {
+            log.error("Error committing operational mode", e);
+        }
+    }
+
+    /*
+     * Get modulation scheme.
+     *
+     * @param port port
+     * @param component component
+     * @return target modulation
+     */
+    Optional<ModulationScheme> getOcnosModulationScheme(PortNumber port, Object component) {
+        NetconfSession session = getNetconfSession(did());
+        checkNotNull(session);
+
+        String filter = getOpModeFilter(getOpticalChannel(port));
+
+        String reply;
+        try {
+            reply = session.get(filteredGetBuilder(filter));
+        } catch (Exception e) {
+            throw new IllegalStateException(new NetconfException("Failed to retrieve opMode.", e));
+        }
+
+        //log.info("REPLY from device: {}", reply);
+
+        XMLConfiguration xconf = (XMLConfiguration) XmlConfigParser.loadXmlString(reply);
+        if (xconf == null) {
+            log.error("Error in executing get");
+            return Optional.empty();
+        }
+
+        String opModeString = xconf.getString(("data." +
+                "terminal-device.coherent-module.network-interfaces.interface." +
+                "state.modulation-format"));
+
+        //log.info("Modulation format mode from device: {}", opModeString);
+
+        if (opModeString == null) {
+            return Optional.empty();
+        }
+
+        ModulationScheme modulation;
+        if (opModeString.equals("dp-8-qam")) {
+            modulation = ModulationScheme.DP_8QAM;
+        } else if (opModeString.equals("dp-16-qam")) {
+            modulation = ModulationScheme.DP_16QAM;
+        } else if (opModeString.equals("dp-qpsk")) {
+            modulation = ModulationScheme.DP_QPSK;
+        } else {
+            log.error("Current operational mode not supported by the driver");
+            return Optional.empty();
+        }
+        return Optional.of(modulation);
+    }
+
+    /*
+     * Set modulation scheme using bitrate.
+     *
+     * @param port port
+     * @param component component
+     * @param power target value
+     */
+    void setOcnosModulationScheme(PortNumber port, Object component, long bitRate) {
+        NetconfSession session = getNetconfSession(did());
+        checkNotNull(session);
+
+        ModulationScheme modulationScheme;
+        if (bitRate == 200) {
+            modulationScheme = ModulationScheme.DP_8QAM;
+        } else { // check if bitrate is greater than 100 Gig
+            modulationScheme = ModulationScheme.DP_QPSK;
+        }
+
+        String filter = setOpModeFilter(port, modulationScheme);
+        String rpcReq = filteredEditConfigBuilder(filter);
+
+        try {
+            session.rpc(rpcReq);
+        } catch (Exception e) {
+            log.error("Error writing operational mode on CANDIDATE", e);
+        }
+
+        log.info("Modulation config sent {}", rpcReq);
+
+        try {
+            session.commit();
+        } catch (NetconfException e) {
+            log.error("Error committing channel power", e);
+        }
+    }
+
+    private String getOperationalMode(ModulationScheme modulation) {
+        if (modulation.equals(ModulationScheme.DP_QPSK)) {
+            return "dp-qpsk";
+        }
+        if (modulation.equals(ModulationScheme.DP_16QAM)) {
+            return "dp-16-qam";
+        }
+        if (modulation.equals(ModulationScheme.DP_8QAM)) {
+            return "dp-8-qam";
+        }
+        log.error("Modulation scheme is not supported.");
+        return null;
+    }
+}
\ No newline at end of file
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniOcnos5PowerConfig.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniOcnos5PowerConfig.java
new file mode 100644
index 0000000..70d4a4a
--- /dev/null
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniOcnos5PowerConfig.java
@@ -0,0 +1,494 @@
+/*
+ * Copyright 2022-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This work was partially supported by EC H2020 project B5G-OPEN (101016663).
+ */
+
+package org.onosproject.drivers.odtn;
+
+import com.google.common.collect.Range;
+import org.apache.commons.configuration.XMLConfiguration;
+import org.onosproject.drivers.utilities.XmlConfigParser;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.behaviour.PowerConfig;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.netconf.NetconfSession;
+import org.onosproject.netconf.NetconfController;
+import org.onosproject.netconf.NetconfDevice;
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.netconf.DatastoreId;
+import org.slf4j.Logger;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.odtn.behaviour.OdtnDeviceDescriptionDiscovery.OC_OPTICAL_CHANNEL_NAME;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Implementation of PowerConfig interface for Cassini device running Ocnos v5.
+ */
+public class CassiniOcnos5PowerConfig<T>
+        extends AbstractHandlerBehaviour implements PowerConfig<T> {
+
+    public static final String RPC_TAG_NETCONF_BASE =
+            "<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">";
+
+    private static final String RPC_CLOSE_TAG = "</rpc>";
+
+    private static final Logger log = getLogger(CassiniOcnos5PowerConfig.class);
+
+    /**
+     * Returns the NetconfSession with the device for which the method was called.
+     *
+     * @param deviceId device indetifier
+     * @return The netconf session or null
+     */
+
+    private NetconfSession getNetconfSession(DeviceId deviceId) {
+        NetconfController controller = handler().get(NetconfController.class);
+        NetconfDevice ncdev = controller.getDevicesMap().get(deviceId);
+        if (ncdev == null) {
+            log.trace("No netconf device, returning null session");
+            return null;
+        }
+        return ncdev.getSession();
+    }
+
+    /**
+     * Get the deviceId for which the methods apply.
+     *
+     * @return The deviceId as contained in the handler data
+     */
+    private DeviceId did() {
+        return handler().data().deviceId();
+    }
+
+    /**
+     * Get the OpenConfig component name for the OpticalChannel component.
+     *
+     * @param portNumber ONOS port number of the Line port ().
+     * @return the channel component name or null
+     */
+    protected String getOpticalChannel(PortNumber portNumber) {
+        Port clientPort = handler().get(DeviceService.class).getPort(did(), portNumber);
+        return clientPort.annotations().value(OC_OPTICAL_CHANNEL_NAME);
+    }
+
+    /**
+     * Get the target-output-power value on specific optical-channel.
+     *
+     * @param port      the port
+     * @param component the port component. It should be 'oc-name' in the Annotations of Port.
+     *                  'oc-name' could be mapped to '/component/name' in openconfig yang.
+     * @return target power value
+     */
+    @Override
+    public Optional<Double> getTargetPower(PortNumber port, T component) {
+        if (checkPortComponent(port, component)) {
+            return getOcnosTargetPower(port, component);
+        }
+        return Optional.empty();
+    }
+
+    @Override
+    public void setTargetPower(PortNumber port, T component, double power) {
+        if (checkPortComponent(port, component)) {
+            setOcnosTargetPower(port, component, power);
+        }
+    }
+
+    @Override
+    public Optional<Double> currentPower(PortNumber port, T component) {
+        if (checkPortComponent(port, component)) {
+            return getOcnosCurrentPower(port, component);
+        }
+        return Optional.empty();
+    }
+
+    @Override
+    public Optional<Double> currentInputPower(PortNumber port, T component) {
+        if (checkPortComponent(port, component)) {
+            return getOcnosCurrentInputPower(port, component);
+        }
+        return Optional.empty();
+    }
+
+    @Override
+    public Optional<Range<Double>> getTargetPowerRange(PortNumber port, T component) {
+        if (checkPortComponent(port, component)) {
+            return getOcnosTargetPowerRange(port, component);
+        }
+        return Optional.empty();
+    }
+
+    @Override
+    public Optional<Range<Double>> getInputPowerRange(PortNumber port, T component) {
+        //FIXME to be implemented
+        if (checkPortComponent(port, component)) {
+            //return getOcnosInputPowerRange(port, component);
+            return Optional.empty();
+        }
+        return Optional.empty();
+    }
+
+    @Override
+    public List<PortNumber> getPorts(T component) {
+        return getOcnosPorts(component);
+    }
+
+    /**
+     * Set the ComponentType to invoke proper methods for different template T.
+     *
+     * @param port the component.
+     * @param component the component.
+     */
+    private Boolean checkPortComponent(PortNumber port, Object component) {
+
+        //Check componenet
+        String clsName = component.getClass().getName();
+        switch (clsName) {
+            case "org.onosproject.net.Direction":
+                break;
+            case "org.onosproject.net.OchSignal":
+                break;
+            default:
+                log.error("Cannot parse the component type {}.", clsName);
+                log.error("The component content is {}.", component.toString());
+                return false;
+        }
+
+        //Check that port has an associated optical channel
+        if (getOpticalChannel(port) == null) {
+            return false;
+        }
+
+        //Checks are ok
+        return true;
+    }
+
+    private String filteredEditConfigBuilder(String filterEditConfig) {
+        StringBuilder rpc = new StringBuilder();
+        rpc.append(RPC_TAG_NETCONF_BASE);
+        rpc.append("<edit-config>");
+        rpc.append("<target><" + DatastoreId.CANDIDATE + "/></target>");
+        rpc.append("<config>");
+        rpc.append(filterEditConfig);
+        rpc.append("</config>");
+        rpc.append("</edit-config>");
+        rpc.append(RPC_CLOSE_TAG);
+
+        return rpc.toString();
+    }
+
+    private String filteredGetBuilder(String filter) {
+        StringBuilder rpc = new StringBuilder();
+        rpc.append(RPC_TAG_NETCONF_BASE);
+        rpc.append("<get>");
+        rpc.append("<filter type='subtree'>");
+        rpc.append(filter);
+        rpc.append("</filter>");
+        rpc.append("</get>");
+        rpc.append(RPC_CLOSE_TAG);
+        return rpc.toString();
+    }
+
+    /**
+     * Parse filtering string from port and component.
+     *
+     * @param port Port Number
+     * @param power      power value set.
+     * @return filtering string in xml format
+     */
+    private String setTargetPowerFilter(PortNumber port, Double power) {
+
+        //Retrieve optical-channel name
+        String optChannelName = getOpticalChannel(port);
+
+        StringBuilder sb = new StringBuilder();
+        sb.append("<terminal-device xmlns='http://www.ipinfusion.com/yang/ocnos/ipi-platform-terminal-device'>"
+                + "<coherent-module>"
+                + "  <slot-index>" + optChannelName + "</slot-index>"
+                + "  <config>"
+                + "    <slot-index>" + optChannelName + "</slot-index>"
+                + "  </config>"
+                + "  <network-interfaces>"
+                + "    <interface>"
+                + "      <net-index>0</net-index>"
+                + "      <config>"
+                + "        <net-index>0</net-index>"
+                + "        <target-output-power>" + power + "</target-output-power>"
+                + "      </config>"
+                + "    </interface>"
+                + "  </network-interfaces>"
+                + "</coherent-module>"
+                + "</terminal-device>");
+
+        return sb.toString();
+    }
+
+    private String getTargetPower(String optChannelName) {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append("<terminal-device xmlns='http://www.ipinfusion.com/yang/ocnos/ipi-platform-terminal-device'>"
+                + "<coherent-module>"
+                + "  <slot-index>" + optChannelName + "</slot-index>"
+                + "<network-interfaces>"
+                + "<interface>"
+                + "  <net-index>0</net-index>"
+                + "  <state>"
+                + "    <target-output-power/>"
+                + "  </state>"
+                + "</interface>"
+                + "</network-interfaces>"
+                + "</coherent-module>"
+                + "</terminal-device>");
+
+        return sb.toString();
+    }
+
+    private String getInputPower(String optChannelName) {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append("<terminal-device xmlns='http://www.ipinfusion.com/yang/ocnos/ipi-platform-terminal-device'>"
+                + "<coherent-module>"
+                + "  <slot-index>" + optChannelName + "</slot-index>"
+                + "<network-interfaces>"
+                + "<interface>"
+                + "  <net-index>0</net-index>"
+                + "  <input-power>"
+                + "    <state>"
+                + "      <instant/>"
+                + "    </state>"
+                + "  </input-power>"
+                + "</interface>"
+                + "</network-interfaces>"
+                + "</coherent-module>"
+                + "</terminal-device>");
+
+        return sb.toString();
+    }
+
+    private String getOutputPower(String optChannelName) {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append("<terminal-device xmlns='http://www.ipinfusion.com/yang/ocnos/ipi-platform-terminal-device'>"
+                + "<coherent-module>"
+                + "  <slot-index>" + optChannelName + "</slot-index>"
+                + "<network-interfaces>"
+                + "<interface>"
+                + "  <net-index>0</net-index>"
+                + "  <output-power>"
+                + "    <state>"
+                + "      <instant/>"
+                + "    </state>"
+                + "  </output-power>"
+                + "</interface>"
+                + "</network-interfaces>"
+                + "</coherent-module>"
+                + "</terminal-device>");
+
+        return sb.toString();
+    }
+
+    /**
+     * getOcnosTargetPower.
+     *
+     * @param port      port
+     * @param component component
+     * @return target power
+     */
+    Optional<Double> getOcnosTargetPower(PortNumber port, Object component) {
+        NetconfSession session = getNetconfSession(did());
+        checkNotNull(session);
+
+        //Retrieve the optical channel name as port annotation
+        String optChannelName = getOpticalChannel(port);
+
+        //log.info("REQUEST get TargetPower to device/port: {}/{}", did(), port);
+
+        String reply;
+        try {
+            reply = session.get(filteredGetBuilder(getTargetPower(optChannelName)));
+        } catch (Exception e) {
+            throw new IllegalStateException(new NetconfException("Failed to retrieve getTargetPower.", e));
+        }
+
+        //log.info("REPLY from device: {}", reply);
+
+        XMLConfiguration xconf = (XMLConfiguration) XmlConfigParser.loadXmlString(reply);
+        if (xconf == null) {
+            log.error("Error in executingRpc");
+            return Optional.empty();
+        }
+
+        String powerString = xconf.getString(("data." +
+                "terminal-device.coherent-module.network-interfaces.interface." +
+                "state.target-output-power"));
+
+        //log.info("TargetPower from device: {}", powerString);
+
+        if (powerString == null) {
+            return Optional.empty();
+        }
+
+        return Optional.of(Double.valueOf(powerString));
+    }
+
+    /**
+     * setOcnosTargetPower.
+     *
+     * @param port      port
+     * @param component component
+     * @param power     target value
+     */
+    private void setOcnosTargetPower(PortNumber port, Object component, double power) {
+        NetconfSession session = getNetconfSession(did());
+        checkNotNull(session);
+
+        if (!getOcnosTargetPowerRange(port, component).get().contains(power)) {
+            log.error("Specified targetPower out of range {}",
+                    getOcnosTargetPowerRange(port, component).get());
+            return;
+        }
+
+        String rpcReq = filteredEditConfigBuilder(setTargetPowerFilter(port, power));
+
+        //log.info("Setting power {}", rpcReq);
+
+        try {
+            session.rpc(rpcReq);
+        } catch (NetconfException e) {
+            log.error("Error wring channel power on CANDIDATE", e);
+        }
+
+        try {
+            session.commit();
+        } catch (NetconfException e) {
+            log.error("Error committing channel power", e);
+        }
+    }
+
+    /**
+     * mirror method in the internal class.
+     *
+     * @param port      port
+     * @param component the component.
+     * @return current output power.
+     */
+    private Optional<Double> getOcnosCurrentPower(PortNumber port, Object component) {
+        NetconfSession session = getNetconfSession(did());
+        checkNotNull(session);
+
+        //Compute port name, then retrieve opt channel
+        String optChannelName = getOpticalChannel(port);
+
+        //log.info("REQUEST get CurrentPower to device/port: {}/{}", did(), port);
+
+        String reply;
+        try {
+            reply = session.get(filteredGetBuilder(getOutputPower(optChannelName)));
+        } catch (Exception e) {
+            throw new IllegalStateException(new NetconfException("Failed to retrieve getOcnosCurrentPower.", e));
+        }
+
+        //log.info("REPLY from device: {}", reply);
+
+        XMLConfiguration xconf = (XMLConfiguration) XmlConfigParser.loadXmlString(reply);
+        if (xconf == null) {
+            log.error("Error in executingRpc");
+            return Optional.empty();
+        }
+
+        String powerString = xconf.getString(("data." +
+                "terminal-device.coherent-module.network-interfaces.interface." +
+                "output-power.state.instant"));
+
+        //log.info("OutputPower from device: {}", powerString);
+
+        if (powerString == null) {
+            return Optional.empty();
+        }
+
+        return Optional.of(Double.valueOf(powerString));
+    }
+
+    /**
+     * This function get the current input power.
+     *
+     * @param port      port
+     * @param component the component
+     * @return current input power
+     */
+    private Optional<Double> getOcnosCurrentInputPower(PortNumber port, Object component) {
+        NetconfSession session = getNetconfSession(did());
+        checkNotNull(session);
+
+        //Compute port name, then retrieve opt channel
+        String optChannelName = getOpticalChannel(port);
+
+        //log.info("REQUEST get InputPower to device/port: {}/{}", did(), port);
+
+        String reply;
+        try {
+            reply = session.get(filteredGetBuilder(getInputPower(optChannelName)));
+        } catch (Exception e) {
+            throw new IllegalStateException(new NetconfException("Failed to retrieve getOcnosCurrentInputPower.", e));
+        }
+
+        //log.info("REPLY from device: {}", reply);
+
+        XMLConfiguration xconf = (XMLConfiguration) XmlConfigParser.loadXmlString(reply);
+        if (xconf == null) {
+            log.error("Error in executingRpc");
+            return Optional.empty();
+        }
+
+        String powerString = xconf.getString(("data." +
+                "terminal-device.coherent-module.network-interfaces.interface." +
+                "input-power.state.instant"));
+
+        //log.info("InputPower from device: {}", powerString);
+
+        if (powerString == null) {
+            return Optional.empty();
+        }
+
+        return Optional.of(Double.valueOf(powerString));
+    }
+
+    private Optional<Range<Double>> getOcnosTargetPowerRange(PortNumber port, Object component) {
+        double targetMin = -10;
+        double targetMax = 2;
+        return Optional.of(Range.open(targetMin, targetMax));
+    }
+
+    private Optional<Range<Double>> getOcnosInputPowerRange(PortNumber port, Object component) {
+        double targetMin = -30;
+        double targetMax = 1;
+        return Optional.of(Range.open(targetMin, targetMax));
+    }
+
+    private List<PortNumber> getOcnosPorts(Object component) {
+        // FIXME
+        log.warn("Not Implemented Yet!");
+        return new ArrayList<PortNumber>();
+    }
+}
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/TerminalDeviceModulationConfig.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/TerminalDeviceModulationConfig.java
index 3a2a95e..cdc2a9c 100644
--- a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/TerminalDeviceModulationConfig.java
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/TerminalDeviceModulationConfig.java
@@ -18,8 +18,6 @@
 
 package org.onosproject.drivers.odtn;
 
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.commons.configuration.HierarchicalConfiguration;
 import org.apache.commons.configuration.XMLConfiguration;
 import org.onlab.osgi.DefaultServiceDirectory;
@@ -39,7 +37,6 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.IOException;
 import java.util.Optional;
 
 import static com.google.common.base.Preconditions.checkNotNull;
@@ -174,6 +171,10 @@
         }
     }
 
+    public void setModulationSchemeProcessor(PortNumber port, Object component, ModulationScheme modulationScheme) {
+        //TODO to be implemented
+    }
+
     public void setModulationSchemeProcessor(PortNumber port, Object component, long bitRate) {
         ModulationScheme modulation = null;
         String editConfig = null;
@@ -257,6 +258,19 @@
     }
 
     /**
+     * Set the target Modulation Scheme on the component.
+     *
+     * @param port      the port
+     * @param component the port component
+     * @param modulationScheme selected modulation scheme
+     **/
+    @Override
+    public void setModulationScheme(PortNumber port, T component, ModulationScheme modulationScheme) {
+        checkType(component);
+        state.setModulationScheme(port, component, modulationScheme);
+    }
+
+    /**
      * Get the Modulation Scheme on the component.
      *
      * @param conf HierarchicalConfiguration for path ../optical-channel/config
@@ -375,6 +389,16 @@
             terminalDevice.setModulationSchemeProcessor(port, component, bitRate);
         }
 
+        /*
+         * mirror method in the internal class.
+         * @param port port
+         * @param component component
+         * @param power target value
+         */
+        void setModulationScheme(PortNumber port, Object component, ModulationScheme modulationScheme) {
+            terminalDevice.setModulationSchemeProcessor(port, component, modulationScheme);
+        }
+
 
         /*
          * Get filtered content under <optical-channel><state>.
@@ -426,26 +450,6 @@
             return deviceService.getPort(deviceId, portNumber).annotations().value("oc-name");
         }
 
-        private static String channelSpacing(TerminalDeviceModulationConfig modulationConfig, PortNumber portNumber) {
-            DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
-            DeviceId deviceId = modulationConfig.handler().data().deviceId();
-            String lambda = deviceService.getPort(deviceId, portNumber).annotations().value("lambda");
-
-            ObjectMapper mapper = new ObjectMapper();
-            String channelSpacing = "";
-            try {
-                JsonNode actualObj = mapper.readTree(lambda);
-                JsonNode csNode = actualObj.get("channelSpacing");
-                channelSpacing = csNode.asText();
-                log.info("Channel_Spacing : " + channelSpacing);
-
-            } catch (IOException e) {
-                log.error("Error while parsing Json");
-            }
-            return channelSpacing;
-
-        }
-
         private double fetchDeviceSnr(TerminalDeviceModulationConfig modulationConfig, PortNumber portNumber) {
             double osnr = 0.0;
             XMLConfiguration xconf = getTerminalDeviceSnr(terminalDevice, portNumber);
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openconfig/GnmiTerminalDeviceModulationConfig.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openconfig/GnmiTerminalDeviceModulationConfig.java
index 5911293..eea6185 100644
--- a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openconfig/GnmiTerminalDeviceModulationConfig.java
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openconfig/GnmiTerminalDeviceModulationConfig.java
@@ -107,6 +107,11 @@
     }
 
     @Override
+    public void setModulationScheme(PortNumber portNumber, T component, ModulationScheme modulationScheme) {
+    //TODO to be implemented
+    }
+
+    @Override
     public void setModulationScheme(PortNumber portNumber, T component, long bitRate) {
         if (!setupBehaviour("getModulationScheme")) {
             return;
diff --git a/drivers/odtn-driver/src/main/resources/odtn-drivers.xml b/drivers/odtn-driver/src/main/resources/odtn-drivers.xml
index a008a60..f3a4ba8 100644
--- a/drivers/odtn-driver/src/main/resources/odtn-drivers.xml
+++ b/drivers/odtn-driver/src/main/resources/odtn-drivers.xml
@@ -45,7 +45,7 @@
                    impl="org.onosproject.drivers.odtn.openconfig.TerminalDeviceFlowRuleProgrammable"/>
     </driver>
 
-    <driver name="client-line-terminal-device"  manufacturer="CTTC" hwVersion="" swVersion="">
+    <driver name="client-line-terminal-device"  manufacturer="CNIT" hwVersion="" swVersion="">
         <behaviour api="org.onosproject.net.device.DeviceDescriptionDiscovery"
                    impl="org.onosproject.drivers.odtn.openconfig.ClientLineTerminalDeviceDiscovery"/>
         <behaviour api ="org.onosproject.net.optical.OpticalDevice"
@@ -97,6 +97,25 @@
         <behaviour api="org.onosproject.net.behaviour.BitErrorRateState"
                    impl="org.onosproject.drivers.odtn.CassiniBitErrorRateState"/>
     </driver>
+    <driver name="cassini-ocnos5"  manufacturer="Edgecore"
+            hwVersion="2019-05-29T06:35:43Z"
+            swVersion="EC_AS7716-24SC-OcNOS-5.0.187-OTN_IPBASE-S0-P0">
+        <behaviour api="org.onosproject.net.device.DeviceDescriptionDiscovery"
+                   impl="org.onosproject.drivers.odtn.CassiniOcnos5DeviceDiscovery"/>
+        <behaviour api ="org.onosproject.net.optical.OpticalDevice"
+                   impl="org.onosproject.net.optical.DefaultOpticalDevice"/>
+        <behaviour api ="org.onosproject.net.behaviour.LambdaQuery"
+                   impl="org.onosproject.drivers.odtn.openconfig.TerminalDeviceLambdaQuery"/>
+        <behaviour api="org.onosproject.net.flow.FlowRuleProgrammable"
+                   impl="org.onosproject.drivers.odtn.CassiniOcnos5FlowRuleProgrammable"/>
+        <behaviour api="org.onosproject.net.behaviour.PowerConfig"
+                   impl="org.onosproject.drivers.odtn.CassiniOcnos5PowerConfig"/>
+        <behaviour api="org.onosproject.net.behaviour.ModulationConfig"
+                   impl="org.onosproject.drivers.odtn.CassiniOcnos5Modulation"/>
+        <behaviour api="org.onosproject.net.behaviour.BitErrorRateState"
+                   impl="org.onosproject.drivers.odtn.CassiniOcnos5BitErrorRate"/>
+    </driver>
+
     <driver name="cassini-ocnos-old" manufacturer="Edgecore" hwVersion="cassini" swVersion="OcNOS">
         <behaviour api="org.onosproject.net.device.DeviceDescriptionDiscovery"
                    impl="org.onosproject.drivers.odtn.CassiniTerminalDeviceDiscoveryOld"/>