VOL-665: ADTRAN ONU support for OpenOMCI

Change-Id: I65bb69b7bd5e769b7fff123947391ddf87d6e7ce
diff --git a/voltha/adapters/adtran_onu/adtran_onu.py b/voltha/adapters/adtran_onu/adtran_onu.py
index b062aa0..d928395 100755
--- a/voltha/adapters/adtran_onu/adtran_onu.py
+++ b/voltha/adapters/adtran_onu/adtran_onu.py
@@ -17,10 +17,10 @@
 """
 Adtran ONU adapter.
 """
+import structlog
 import binascii
 from voltha.adapters.iadapter import OnuAdapter
 from voltha.protos import third_party
-from voltha.extensions.omci.omci import *
 from adtran_onu_handler import AdtranOnuHandler
 from twisted.internet import reactor
 
@@ -36,7 +36,7 @@
                                                device_handler_class=AdtranOnuHandler,
                                                name='adtran_onu',
                                                vendor='Adtran, Inc.',
-                                               version='0.5',
+                                               version='0.6',
                                                device_type='adtran_onu',
                                                vendor_id='ADTN')
 
@@ -76,7 +76,7 @@
     def receive_inter_adapter_message(self, msg):
         # Currently the only OLT Device adapter that uses this is the EdgeCore
 
-        log.info('receive_inter_adapter_message', msg=msg)
+        self.log.info('receive_inter_adapter_message', msg=msg)
         proxy_address = msg['proxy_address']
         assert proxy_address is not None
 
@@ -100,7 +100,7 @@
         raise NotImplementedError('Not an ONU method')
 
     def receive_proxied_message(self, proxy_address, msg):
-        log.debug('receive-proxied-message', proxy_address=proxy_address,
+        self.log.debug('receive-proxied-message', proxy_address=proxy_address,
                   device_id=proxy_address.device_id, msg=binascii.hexlify(msg))
         # Device_id from the proxy_address is the olt device id. We need to
         # get the onu device id using the port number in the proxy_address
diff --git a/voltha/adapters/adtran_onu/adtran_onu_handler.py b/voltha/adapters/adtran_onu/adtran_onu_handler.py
index dea1e78..60b4c69 100644
--- a/voltha/adapters/adtran_onu/adtran_onu_handler.py
+++ b/voltha/adapters/adtran_onu/adtran_onu_handler.py
@@ -15,10 +15,9 @@
 #
 
 import arrow
+import structlog
 
 from voltha.adapters.adtran_olt.xpon.adtran_xpon import AdtranXPON
-from omci.omci_cc import OMCI_CC
-from omci.omci_entities import onu_custom_entity_classes
 from pon_port import PonPort
 from uni_port import UniPort
 from heartbeat import HeartBeat
@@ -34,14 +33,15 @@
 from voltha.protos import third_party
 from voltha.protos.common_pb2 import OperStatus, ConnectStatus
 from voltha.protos.device_pb2 import Image
-from voltha.extensions.omci.omci import *
 from common.utils.indexpool import IndexPool
+from voltha.extensions.omci.openomci_agent import OpenOMCIAgent
 
 _ = third_party
 _MAXIMUM_PORT = 128          # PON and UNI ports
 _ONU_REBOOT_MIN = 60
 _ONU_REBOOT_RETRY = 10
 
+
 class AdtranOnuHandler(AdtranXPON):
     def __init__(self, adapter, device_id):
         kwargs = dict()
@@ -60,12 +60,17 @@
         self._upstream_channel_speed = 0
 
         self._unis = dict()         # Port # -> UniPort
-        self._pons = dict()         # Port # -> PonPort
+        self._pon = None
         self._heartbeat = HeartBeat.create(self, device_id)
 
         self._deferred = None
         self._event_deferred = None
-        self._omci = None
+
+        # TODO: Remove next two lines if/when OpenOMCI is in the core or a container
+        #       in order to support multiple ONUs per instance
+        self._omci_agent = OpenOMCIAgent(self.adapter_agent.core)
+        self._omci_agent.start()
+
         self._port_number_pool = IndexPool(_MAXIMUM_PORT, 1)
 
         self._olt_created = False   # True if deprecated method of OLT creating DA is used
@@ -128,8 +133,14 @@
         return self._olt_created    # ONU was created with deprecated 'child_device_detected' call
 
     @property
+    def omci_agent(self):
+        return self._omci_agent
+
+    @property
     def omci(self):
-        return self._omci
+        # TODO: Decrement access to Communications channel at this point?  What about current PM stuff?
+        _onu_omci_device = self._pon.onu_omci_device
+        return _onu_omci_device.omci_cc if _onu_omci_device is not None else None
 
     @property
     def heartbeat(self):
@@ -148,11 +159,8 @@
         return self._unis.get(port_no_or_name)
 
     @property
-    def pon_ports(self):
-        return self._pons.values()
-
-    def pon_port(self, port_no):
-        return self._pons.get(port_no)
+    def pon_port(self):
+        return self._pon
 
     @property
     def _next_port_number(self):
@@ -163,17 +171,10 @@
 
     def start(self):
         assert self._enabled, 'Start should only be called if enabled'
-        #
-        # TODO: Perform common startup tasks here
-        #
+
         self._cancel_deferred()
 
-        self._omci = OMCI_CC(self.adapter_agent,
-                             self.device_id,
-                             custom_me_entries=onu_custom_entity_classes)
-        self._omci.enabled = True
-
-        # Handle received ONU event messages
+        # Handle received ONU event messages   TODO: Deprecate this....
         self._event_messages = DeferredQueue()
         self._event_deferred = reactor.callLater(0, self._handle_onu_events)
 
@@ -181,10 +182,10 @@
         self.adapter_agent.register_for_inter_adapter_messages()
 
         # Port startup
-        for port in self.uni_ports:
-            port.enabled = True
+        if self._pon is not None:
+            self._pon.enabled = True
 
-        for port in self.pon_ports:
+        for port in self.uni_ports:
             port.enabled = True
 
         # Heartbeat
@@ -203,16 +204,16 @@
         # Heartbeat
         self._heartbeat.stop()
 
+        # OMCI Communications
+        # if self._onu_omci_device is not None:
+        #     self._onu_omci_device.stop()
+
         # Port shutdown
         for port in self.uni_ports:
             port.enabled = False
 
-        for port in self.pon_ports:
-            port.enabled = False
-
-        omci, self._omci = self._omci, None
-        if omci is not None:
-            omci.enabled = False
+        if self._pon is not None:
+            self._pon.enabled = False
 
         queue, self._event_deferred = self._event_deferred, None
         if queue is not None:
@@ -220,8 +221,8 @@
                 _ = yield queue.get()
 
     def receive_message(self, msg):
-        if self._omci is not None and self.enabled:
-            self._omci.receive_message(msg)
+        if self.omci is not None and self.enabled:
+            self.omci.receive_message(msg)
 
     def activate(self, device):
         self.log.info('activating')
@@ -271,28 +272,26 @@
         # Need to query ONU for number of supported uni ports
         # For now, temporarily set number of ports to 1 - port #2
 
-        # Register physical ports.  Should have at least one of each
-
-        pon_port = PonPort.create(self, self._next_port_number)
-
-        self._pons[pon_port.port_number] = pon_port
-        self.adapter_agent.add_port(device.id, pon_port.get_port())
-
         parent_device = self.adapter_agent.get_device(device.parent_id)
         self.logical_device_id = parent_device.parent_id
         assert self.logical_device_id, 'Invalid logical device ID'
 
+        # Register physical ports.  Should have at least one of each
+
+        self._pon = PonPort.create(self, self._next_port_number)
+        self.adapter_agent.add_port(device.id, self._pon.get_port())
+
         if self._olt_created:
             # vlan non-zero if created via legacy method (not xPON). Also
             # Set a random serial number since not xPON based
 
-            uni_port = UniPort.create(self, self._next_port_number,
-                                      'deprecated', device.vlan)
+            uni_port = UniPort.create(self, self._next_port_number, device.vlan,
+                                      'deprecated', device.vlan, None)
             self._unis[uni_port.port_number] = uni_port
             self.adapter_agent.add_port(device.id, uni_port.get_port())
 
             device.serial_number = uuid4().hex
-            uni_port.add_logical_port(device.vlan, control_vlan=device.vlan)
+            uni_port.add_logical_port(device.vlan, subscriber_vlan=device.vlan)
 
             # Start things up for this ONU Handler.
             self.enabled = True
@@ -376,7 +375,7 @@
         # self.log.info('bulk-flow-update', device_id=device.id, flows=flows)
 
         import voltha.core.flow_decomposer as fd
-        from voltha.protos.openflow_13_pb2 import OFPXMC_OPENFLOW_BASIC, ofp_port
+        from voltha.protos.openflow_13_pb2 import OFPXMC_OPENFLOW_BASIC
 
         def is_downstream(port):
             return port == 100  # Need a better way
@@ -384,7 +383,7 @@
         def is_upstream(port):
             return not is_downstream(port)
 
-        omci = self._omci
+        omci = self.omci
 
         for flow in flows:
             _type = None
@@ -482,7 +481,7 @@
 
                     elif action.type == fd.PUSH_VLAN:
                         _push_tpid = action.push.ethertype
-                        log.info('action-type-push-vlan',
+                        self.log.info('action-type-push-vlan',
                                  push_tpid=_push_tpid, in_port=_in_port)
                         if action.push.ethertype != 0x8100:
                             self.log.error('unhandled-tpid',
@@ -501,9 +500,8 @@
                             self.log.error('unsupported-action-set-field-type',
                                            field_type=_field.type)
                     else:
-                        log.error('unsupported-action-type',
-                                  action_type=action.type, in_port=_in_port)
-
+                        self.log.error('unsupported-action-type',
+                                       action_type=action.type, in_port=_in_port)
                 #
                 # All flows created from ONU adapter should be OMCI based
                 #
@@ -541,7 +539,7 @@
                     '''
 
             except Exception as e:
-                log.exception('failed-to-install-flow', e=e, flow=flow)
+                self.log.exception('failed-to-install-flow', e=e, flow=flow)
 
     @inlineCallbacks
     def reboot(self):
@@ -627,7 +625,6 @@
 
         self.log.info('reboot-complete', device_id=self.device_id)
 
-
     def self_test_device(self, device):
         """
         This is called to Self a device based on a NBI call.
@@ -673,9 +670,9 @@
                               portid=port_id)
 
         # Remove pon port from parent
-        for port in self.pon_ports:
+        if self._pon is not None:
             self.adapter_agent.delete_port_reference_from_parent(self.device_id,
-                                                                 port.get_port())
+                                                                 self._pon.get_port())
 
         # Just updating the port status may be an option as well
         # port.ofp_port.config = OFPPC_NO_RECV
@@ -715,10 +712,10 @@
             # self.uni_port = self._get_uni_port()   deprecated
 
             # Add the pon port reference to the parent
-            for port in self.pon_ports:
+            if self._pon is not None:
                 # TODO: Send 'enable' to PonPort?
                 self.adapter_agent.add_port_reference_to_parent(device.id,
-                                                                port.get_port())
+                                                                self._pon.get_port())
 
             # Update the connect status to REACHABLE
             device.connect_status = ConnectStatus.REACHABLE
@@ -732,7 +729,7 @@
             if self.olt_created:
                 # vlan non-zero if created via legacy method (not xPON)
                 self.uni_port('deprecated').add_logical_port(device.vlan, device.vlan,
-                                                             control_vlan=device.vlan)
+                                                             subscriber_vlan=device.vlan)
 
             device = self.adapter_agent.get_device(device.id)
             device.oper_status = OperStatus.ACTIVE
@@ -747,6 +744,12 @@
 
     def delete(self):
         self.log.info('deleting', device_id=self.device_id)
+
+        # OpenOMCI cleanup
+        if self._omci_agent is not None:
+            self._omci_agent.remove_device(self.device_id, cleanup=True)
+            #self._onu_omci_device = None
+            self._omci_agent = None
         #
         # handling needed here
         # self.enabled = False
@@ -783,7 +786,7 @@
     def _check_for_mock_config(self, data):
         # Check for MOCK configuration
         description = data.get('description')
-        if description is not None and description.lower() == 'mock':
+        if description is not None and 'mock' in description.lower():
             self._is_mock = True
 
     def on_ont_ani_create(self, ont_ani):
@@ -919,16 +922,22 @@
             # Set a random serial number since not xPON based
 
             device = self.adapter_agent.get_device(self.device_id)
-            ofp_port_no, cntl_vlan = UniPort.decode_openflow_port_and_control_vlan(self, venet)
+            ofp_port_no, subscriber_vlan, untagged_vlan = UniPort.decode_venet(venet)
 
             uni_port = UniPort.create(self, venet['name'],
                                       self._next_port_number,
-                                      cntl_vlan)
+                                      ofp_port_no,
+                                      subscriber_vlan,
+                                      untagged_vlan)
 
             self._unis[uni_port.port_number] = uni_port
             self.adapter_agent.add_port(device.id, uni_port.get_port())
 
-            uni_port.add_logical_port(ofp_port_no, control_vlan=cntl_vlan)
+            # If the PON has already synchronized, add the logical port now
+            # since we know we have been activated
+
+            if self._pon is not None and self._pon.connected:
+                uni_port.add_logical_port(ofp_port_no, subscriber_vlan=subscriber_vlan)
 
         # TODO: Next is just for debugging to see what this call returns after
         #       we add a UNI
@@ -987,11 +996,8 @@
         tcont['object'] = OnuTCont.create(self, tcont, traffic_descriptor,
                                           is_mock=self.is_mock)
 
-        # Look up any PON port  # TODO: Add the vont-ani 'name' to the PON Port and look up that way
-        pon_port = self.pon_ports[0]
-
-        if pon_port is not None:
-            pon_port.add_tcont(tcont['object'])
+        if self._pon is not None:
+            self._pon.add_tcont(tcont['object'])
 
         return tcont
 
@@ -1007,25 +1013,20 @@
 
         update['object'] = tc
 
-        # Look up any PON port  # TODO: Add the vont-ani 'name' to the PON Port and look up that way
-        pon_port = self.pon_ports[0]
-
-        if pon_port is not None:
+        if self._pon is not None:
             keys = [k for k in diffs.keys() if k in valid_keys]
 
             for k in keys:
                 if k == 'td-ref':
                     td = self.traffic_descriptors.get(update['td-ref'])
                     if td is not None:
-                        pon_port.update_tcont_td(tcont['alloc-id'], td)
+                        self._pon.update_tcont_td(tcont['alloc-id'], td)
 
         return update
 
     def on_tcont_delete(self, tcont):
-        pon_port = self.pon_ports[0]        # Look up any PON port  # TODO: Add the vont-ani 'name' to the PON Port and look up that way
-
-        if pon_port is not None:
-            pon_port.remove_tcont(tcont['alloc-id'])
+        if self._pon is not None:
+            self._pon.remove_tcont(tcont['alloc-id'])
 
         return None
 
@@ -1056,10 +1057,8 @@
                   if val['td-ref'] == td_name and td_name is not None}
 
         for tcont in tconts.itervalues():
-            pon_port = self.pon_ports[0]        # Look up any PON port  # TODO: Add the vont-ani 'name' to the PON Port and look up that way
-
-            if pon_port is not None:
-                pon_port.update_tcont_td(tcont['alloc-id'], update['object'])
+            if self._pon is not None:
+                self._pon.update_tcont_td(tcont['alloc-id'], update['object'])
 
         return update
 
@@ -1074,13 +1073,12 @@
 
     def on_gemport_create(self, gem_port):
         from onu_gem_port import OnuGemPort
+        assert self._pon is not None, 'No PON port'
 
-        gem_port['object'] = OnuGemPort.create(self, gem_port, is_mock=self.is_mock)
-        # Look up any PON port  # TODO: Add the vont-ani 'name' to the PON Port and look up that way
-        pon_port = self.pon_ports[0]
-        if pon_port is not None:
-            pon_port.add_gem_port(gem_port['object'])
-
+        gem_port['object'] = OnuGemPort.create(self, gem_port,
+                                               self._pon.next_gem_entity_id,
+                                               is_mock=self.is_mock)
+        self._pon.add_gem_port(gem_port['object'])
         return gem_port
 
     def on_gemport_modify(self, gem_port, update, diffs):
@@ -1106,9 +1104,8 @@
         return update
 
     def on_gemport_delete(self, gem_port):
-        pon_port = self.pon_ports[0]        # Look up any PON port  # TODO: Add the vont-ani 'name' to the PON Port and look up that way
-        if pon_port is not None:
-            pon_port.remove_gem_id(gem_port['gemport-id'])
+        if self._pon is not None:
+            self._pon.remove_gem_id(gem_port['gemport-id'])
 
         return None
 
diff --git a/voltha/adapters/adtran_onu/heartbeat.py b/voltha/adapters/adtran_onu/heartbeat.py
index 4e54459..b35daab 100644
--- a/voltha/adapters/adtran_onu/heartbeat.py
+++ b/voltha/adapters/adtran_onu/heartbeat.py
@@ -15,7 +15,8 @@
 import structlog
 from twisted.internet import reactor
 from voltha.protos.common_pb2 import OperStatus, ConnectStatus
-from omci.omci_me import OntGFrame
+from voltha.extensions.omci.omci_me import OntGFrame
+
 
 class HeartBeat(object):
     """Wraps health-check support for ONU"""
diff --git a/voltha/adapters/adtran_onu/omci/deprecated.py b/voltha/adapters/adtran_onu/omci/deprecated.py
deleted file mode 100644
index f93df0b..0000000
--- a/voltha/adapters/adtran_onu/omci/deprecated.py
+++ /dev/null
@@ -1,498 +0,0 @@
-# Copyright 2017-present Adtran, Inc.
-#
-# 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.
-
-from voltha.extensions.omci.omci import *
-
-
-DEFAULT_OMCI_TIMEOUT = 3            # Seconds
-
-# TODO: These are the older-style OMCI commands to send get/create/... frames
-
-
-def send_get_OntG(omci_cc, attribute, entity_id=0, timeout=DEFAULT_OMCI_TIMEOUT):
-    omci_cc.log.debug('send_get_OntG')
-    frame = OmciFrame(
-        transaction_id=omci_cc._get_tx_tid(),
-        message_type=OmciGet.message_id,
-        omci_message=OmciGet(
-            entity_class=OntG.class_id,
-            entity_id=entity_id,
-            attributes_mask=OntG.mask_for(attribute)
-        )
-    )
-    return omci_cc.send(frame, timeout)
-
-
-def send_create_vlan_tagging_filter_data(omci_cc, entity_id, vlan_id,
-                                         timeout=DEFAULT_OMCI_TIMEOUT):
-    frame = OmciFrame(
-        transaction_id=omci_cc._get_tx_tid(),
-        message_type=OmciCreate.message_id,
-        omci_message=OmciCreate(
-            entity_class=VlanTaggingFilterData.class_id,
-            entity_id=entity_id,
-            data=dict(
-                vlan_filter_0=vlan_id,
-                forward_operation=0x10,
-                number_of_entries=1
-            )
-        )
-    )
-    return omci_cc.send(frame, timeout)
-
-# TODO: Deprecated: replaced with send_set_pptp_ethernet_uni  (need to clean up)
-
-
-def send_set_adminState(omci_cc, entity_id, timeout=DEFAULT_OMCI_TIMEOUT):
-    omci_cc.log.debug('send_set_AdminState')
-    data = dict(
-        administrative_state=0
-    )
-    frame = OmciFrame(
-        transaction_id=omci_cc._get_tx_tid(),
-        message_type=OmciSet.message_id,
-        omci_message=OmciSet(
-            entity_class=PptpEthernetUni.class_id,
-            entity_id=entity_id,
-            attributes_mask=PptpEthernetUni.mask_for(*data.keys()),
-            data=data
-        )
-    )
-    return omci_cc.send(frame, timeout)
-
-
-def send_get_SoftwareImage(omci_cc, attribute, entity_id=0, timeout=DEFAULT_OMCI_TIMEOUT):
-    omci_cc.log.debug('send_get_SoftwareImage')
-    frame = OmciFrame(
-        transaction_id=omci_cc._get_tx_tid(),
-        message_type=OmciGet.message_id,
-        omci_message=OmciGet(
-            entity_class=SoftwareImage.class_id,
-            entity_id=entity_id,
-            attributes_mask=SoftwareImage.mask_for(attribute)
-        )
-    )
-    return omci_cc.send(frame, timeout)
-
-
-def send_set_extended_vlan_tagging_operation_vlan_configuration_data_untagged(omci_cc,
-                                                                              entity_id,
-                                                                              filter_inner_vid,
-                                                                              treatment_inner_vid,
-                                                                              timeout=DEFAULT_OMCI_TIMEOUT):
-    data = dict(
-        received_frame_vlan_tagging_operation_table=
-        VlanTaggingOperation(
-            filter_outer_priority=15,
-            filter_outer_vid=4096,
-            filter_outer_tpid_de=0,
-
-            filter_inner_priority=15,
-            filter_inner_vid=filter_inner_vid,
-            filter_inner_tpid_de=0,
-            filter_ether_type=0,
-
-            treatment_tags_to_remove=0,
-            treatment_outer_priority=15,
-            treatment_outer_vid=0,
-            treatment_outer_tpid_de=0,
-
-            treatment_inner_priority=0,
-            treatment_inner_vid=treatment_inner_vid,
-            treatment_inner_tpid_de=4
-        )
-    )
-    frame = OmciFrame(
-        transaction_id=omci_cc._get_tx_tid(),
-        message_type=OmciSet.message_id,
-        omci_message=OmciSet(
-            entity_class=
-            ExtendedVlanTaggingOperationConfigurationData.class_id,
-            entity_id=entity_id,
-            attributes_mask=
-            ExtendedVlanTaggingOperationConfigurationData.mask_for(
-                *data.keys()),
-            data=data
-        )
-    )
-    return omci_cc.send(frame, timeout)
-
-
-def send_set_extended_vlan_tagging_operation_vlan_configuration_data_single_tag(omci_cc,
-                                                                                entity_id,
-                                                                                filter_inner_priority,
-                                                                                filter_inner_vid,
-                                                                                filter_inner_tpid_de,
-                                                                                treatment_tags_to_remove,
-                                                                                treatment_inner_priority,
-                                                                                treatment_inner_vid,
-                                                                                timeout=DEFAULT_OMCI_TIMEOUT):
-    data = dict(
-        received_frame_vlan_tagging_operation_table=
-        VlanTaggingOperation(
-            filter_outer_priority=15,
-            filter_outer_vid=4096,
-            filter_outer_tpid_de=0,
-            filter_inner_priority=filter_inner_priority,
-            filter_inner_vid=filter_inner_vid,
-            filter_inner_tpid_de=filter_inner_tpid_de,
-            filter_ether_type=0,
-            treatment_tags_to_remove=treatment_tags_to_remove,
-            treatment_outer_priority=15,
-            treatment_outer_vid=0,
-            treatment_outer_tpid_de=0,
-            treatment_inner_priority=treatment_inner_priority,
-            treatment_inner_vid=treatment_inner_vid,
-            treatment_inner_tpid_de=4
-        )
-    )
-    frame = OmciFrame(
-        transaction_id=omci_cc._get_tx_tid(),
-        message_type=OmciSet.message_id,
-        omci_message=OmciSet(
-            entity_class=
-            ExtendedVlanTaggingOperationConfigurationData.class_id,
-            entity_id=entity_id,
-            attributes_mask=
-            ExtendedVlanTaggingOperationConfigurationData.mask_for(
-                *data.keys()),
-            data=data
-        )
-    )
-    return omci_cc.send(frame, timeout)
-
-
-def send_delete_vlan_tagging_filter_data(omci_cc,
-                                      entity_id):
-    frame = OmciFrame(
-        transaction_id=omci_cc._get_tx_tid(),
-        message_type=OmciDelete.message_id,
-        omci_message=OmciDelete(
-            entity_class=VlanTaggingFilterData.class_id,
-            entity_id=entity_id
-        )
-    )
-    return omci_cc.send(frame)
-
-# xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-
-
-def send_set_tcont(omci_cc, entity_id, alloc_id, timeout=DEFAULT_OMCI_TIMEOUT):
-    data = dict(
-        alloc_id=alloc_id
-    )
-    frame = OmciFrame(
-        transaction_id=omci_cc._get_tx_tid(),
-        message_type=OmciSet.message_id,
-        omci_message=OmciSet(
-            entity_class=Tcont.class_id,
-            entity_id=entity_id,
-            attributes_mask=Tcont.mask_for(*data.keys()),
-            data=data
-        )
-    )
-    return omci_cc.send(frame, timeout)
-
-
-def send_create_gem_port_network_ctp(omci_cc, entity_id, port_id,
-                                     tcont_id, direction, tm,
-                                     timeout=DEFAULT_OMCI_TIMEOUT):
-
-    _directions = {"upstream": 1, "downstream": 2, "bi-directional": 3}
-
-    if _directions.has_key(direction):
-        _direction = _directions[direction]
-    else:
-        omci_cc.log.error('invalid-gem-port-direction', direction=direction)
-        raise ValueError('Invalid GEM port direction: {_dir}'.format(_dir=direction))
-
-    frame = OmciFrame(
-        transaction_id=omci_cc._get_tx_tid(),
-        message_type=OmciCreate.message_id,
-        omci_message=OmciCreate(
-            entity_class=GemPortNetworkCtp.class_id,
-            entity_id=entity_id,
-            data=dict(
-                port_id=port_id,
-                tcont_pointer=tcont_id,
-                direction=_direction,
-                traffic_management_pointer_upstream=tm
-            )
-        )
-    )
-    return omci_cc.send(frame, timeout)
-
-
-def send_set_8021p_mapper_service_profile(omci_cc, entity_id,
-                                          interwork_tp_id,
-                                          timeout=DEFAULT_OMCI_TIMEOUT):
-    data = dict(
-        interwork_tp_pointer_for_p_bit_priority_0=interwork_tp_id,
-        interwork_tp_pointer_for_p_bit_priority_1=interwork_tp_id,
-        interwork_tp_pointer_for_p_bit_priority_2=interwork_tp_id,
-        interwork_tp_pointer_for_p_bit_priority_3=interwork_tp_id,
-        interwork_tp_pointer_for_p_bit_priority_4=interwork_tp_id,
-        interwork_tp_pointer_for_p_bit_priority_5=interwork_tp_id,
-        interwork_tp_pointer_for_p_bit_priority_6=interwork_tp_id,
-        interwork_tp_pointer_for_p_bit_priority_7=interwork_tp_id
-    )
-    frame = OmciFrame(
-        transaction_id=omci_cc._get_tx_tid(),
-        message_type=OmciSet.message_id,
-        omci_message=OmciSet(
-            entity_class=Ieee8021pMapperServiceProfile.class_id,
-            entity_id=entity_id,
-            attributes_mask=Ieee8021pMapperServiceProfile.mask_for(
-                *data.keys()),
-            data=data
-        )
-    )
-    return omci_cc.send(frame, timeout)
-
-
-def send_create_8021p_mapper_service_profile(omci_cc, entity_id, timeout=DEFAULT_OMCI_TIMEOUT):
-    frame = OmciFrame(
-        transaction_id=omci_cc._get_tx_tid(),
-        message_type=OmciCreate.message_id,
-        omci_message=OmciCreate(
-            entity_class=Ieee8021pMapperServiceProfile.class_id,
-            entity_id=entity_id,
-            data=dict(
-                tp_pointer=OmciNullPointer,
-                interwork_tp_pointer_for_p_bit_priority_0=OmciNullPointer,
-                interwork_tp_pointer_for_p_bit_priority_1=OmciNullPointer,
-                interwork_tp_pointer_for_p_bit_priority_2=OmciNullPointer,
-                interwork_tp_pointer_for_p_bit_priority_3=OmciNullPointer,
-                interwork_tp_pointer_for_p_bit_priority_4=OmciNullPointer,
-                interwork_tp_pointer_for_p_bit_priority_5=OmciNullPointer,
-                interwork_tp_pointer_for_p_bit_priority_6=OmciNullPointer,
-                interwork_tp_pointer_for_p_bit_priority_7=OmciNullPointer
-            )
-        )
-    )
-    return omci_cc.send(frame, timeout)
-
-
-def send_create_mac_bridge_service_profile(omci_cc, entity_id, timeout=DEFAULT_OMCI_TIMEOUT):
-    frame = OmciFrame(
-        transaction_id=omci_cc._get_tx_tid(),
-        message_type=OmciCreate.message_id,
-        omci_message=OmciCreate(
-            entity_class=MacBridgeServiceProfile.class_id,
-            entity_id=entity_id,
-            data=dict(
-                spanning_tree_ind=False,
-                # BP: Hack , this was not set in ADT configuration
-                # learning_ind=True,
-                # priority=0x8000,
-                # max_age=20 * 256,
-                # hello_time=2 * 256,
-                # forward_delay=15 * 256,
-                # unknown_mac_address_discard=True
-            )
-        )
-    )
-    return omci_cc.send(frame, timeout)
-
-
-def send_create_gal_ethernet_profile(omci_cc, entity_id, max_gem_payload_size,
-                                     timeout=DEFAULT_OMCI_TIMEOUT):
-    frame = OmciFrame(
-        transaction_id=omci_cc._get_tx_tid(),
-        message_type=OmciCreate.message_id,
-        omci_message=OmciCreate(
-            entity_class=GalEthernetProfile.class_id,
-            entity_id=entity_id,
-            data=dict(
-                max_gem_payload_size=max_gem_payload_size
-            )
-        )
-    )
-    return omci_cc.send(frame, timeout)
-
-
-def send_create_gem_inteworking_tp(omci_cc, entity_id, gem_port_net_ctp_id,
-                                   service_profile_id, timeout=DEFAULT_OMCI_TIMEOUT):
-    frame = OmciFrame(
-        transaction_id=omci_cc._get_tx_tid(),
-        message_type=OmciCreate.message_id,
-        omci_message=OmciCreate(
-            entity_class=GemInterworkingTp.class_id,
-            entity_id=entity_id,
-            data=dict(
-                gem_port_network_ctp_pointer=gem_port_net_ctp_id,
-                interworking_option=5,
-                service_profile_pointer=service_profile_id,
-                interworking_tp_pointer=0x0,
-                pptp_counter=1,
-                gal_profile_pointer=0x0   # BP: HACK old value 0x1
-            )
-        )
-    )
-    return omci_cc.send(frame, timeout)
-
-
-def send_create_mac_bridge_port_configuration_data(omci_cc, entity_id, bridge_id,
-                                                   port_id, tp_type, tp_id,
-                                                   timeout=DEFAULT_OMCI_TIMEOUT):
-    frame = OmciFrame(
-        transaction_id=omci_cc._get_tx_tid(),
-        message_type=OmciCreate.message_id,
-        omci_message=OmciCreate(
-            entity_class=MacBridgePortConfigurationData.class_id,
-            entity_id=entity_id,
-            data=dict(
-                bridge_id_pointer=bridge_id,
-                port_num=port_id,
-                tp_type=tp_type,
-                tp_pointer=tp_id
-            )
-        )
-    )
-    return omci_cc.send(frame, timeout)
-
-
-def send_get_circuit_pack(omci_cc, attribute, entity_id=0,
-                          timeout=DEFAULT_OMCI_TIMEOUT):
-    omci_cc.log.debug('send_get_circuit_pack')
-    frame = OmciFrame(
-        transaction_id=omci_cc._get_tx_tid(),
-        message_type=OmciGet.message_id,
-        omci_message=OmciGet(
-            entity_class=CircuitPack.class_id,
-            entity_id=entity_id,
-            attributes_mask=CircuitPack.mask_for(attribute)
-        )
-    )
-    return omci_cc.send(frame, timeout)
-
-
-def send_get_device_info(omci_cc, attribute, entity_id=0, timeout=DEFAULT_OMCI_TIMEOUT):
-    frame = OmciFrame(
-        transaction_id=omci_cc._get_tx_tid(),
-        message_type=OmciGet.message_id,
-        omci_message=OmciGet(
-            entity_class=CircuitPack.class_id,
-            entity_id=entity_id,
-            attributes_mask=CircuitPack.mask_for(attribute)
-        )
-    )
-    return omci_cc.send(frame, timeout)
-
-
-def send_get_Ont2G(omci_cc, attribute, entity_id=0, timeout=DEFAULT_OMCI_TIMEOUT):
-    omci_cc.log.debug('send_get_Ont2G')
-    frame = OmciFrame(
-        transaction_id=omci_cc._get_tx_tid(),
-        message_type=OmciGet.message_id,
-        omci_message=OmciGet(
-            entity_class=Ont2G.class_id,
-            entity_id=entity_id,
-            attributes_mask=Ont2G.mask_for(attribute)
-        )
-    )
-    return omci_cc.send(frame, timeout)
-
-
-def send_get_cardHolder(omci_cc, attribute, entity_id=0, timeout=DEFAULT_OMCI_TIMEOUT):
-    omci_cc.log.debug('send_get_cardHolder')
-    frame = OmciFrame(
-        transaction_id=omci_cc._get_tx_tid(),
-        message_type=OmciGet.message_id,
-        omci_message=OmciGet(
-            entity_class=Cardholder.class_id,
-            entity_id=entity_id,
-            attributes_mask=Cardholder.mask_for(attribute)
-        )
-    )
-    return omci_cc.send(frame, timeout)
-
-
-def send_set_pptp_ethernet_uni(omci_cc, entity_id, timeout=DEFAULT_OMCI_TIMEOUT):
-    omci_cc.log.debug('send_set_AdminState')
-    data = dict(
-        administrative_state=0
-    )
-    frame = OmciFrame(
-        transaction_id=omci_cc._get_tx_tid(),
-        message_type=OmciSet.message_id,
-        omci_message=OmciSet(
-            entity_class=PptpEthernetUni.class_id,
-            entity_id=entity_id,
-            attributes_mask=PptpEthernetUni.mask_for(*data.keys()),
-            data=data
-        )
-    )
-    return omci_cc.send(frame, timeout)
-
-
-def send_get_IpHostConfigData(omci_cc, attribute, entity_id=0, timeout=DEFAULT_OMCI_TIMEOUT):
-    omci_cc.log.debug('send_get_IpHostConfigData')
-    frame = OmciFrame(
-        transaction_id=omci_cc._get_tx_tid(),
-        message_type=OmciGet.message_id,
-        omci_message=OmciGet(
-            entity_class=IpHostConfigData.class_id,
-            entity_id=entity_id,
-            attributes_mask=IpHostConfigData.mask_for(attribute)
-        )
-    )
-    return omci_cc.send(frame, timeout)
-
-
-def send_create_extended_vlan_tagging_operation_configuration_data(omci_cc,
-                                                                   entity_id,
-                                                                   assoc_type,
-                                                                   assoc_me,
-                                                                   timeout=DEFAULT_OMCI_TIMEOUT):
-    frame = OmciFrame(
-        transaction_id=omci_cc._get_tx_tid(),
-        message_type=OmciCreate.message_id,
-        omci_message=OmciCreate(
-            entity_class=
-            ExtendedVlanTaggingOperationConfigurationData.class_id,
-            entity_id=entity_id,
-            data=dict(
-                association_type=assoc_type,
-                associated_me_pointer=assoc_me
-            )
-        )
-    )
-    return omci_cc.send(frame, timeout)
-
-
-def send_set_extended_vlan_tagging_operation_tpid_configuration_data(omci_cc,
-                                                                     entity_id,
-                                                                     input_tpid,
-                                                                     output_tpid,
-                                                                     timeout=DEFAULT_OMCI_TIMEOUT):
-    data = dict(
-        input_tpid=input_tpid,
-        output_tpid=output_tpid,
-        downstream_mode=0,  # inverse of upstream
-    )
-    frame = OmciFrame(
-        transaction_id=omci_cc._get_tx_tid(),
-        message_type=OmciSet.message_id,
-        omci_message=OmciSet(
-            entity_class=
-            ExtendedVlanTaggingOperationConfigurationData.class_id,
-            entity_id=entity_id,
-            attributes_mask=
-            ExtendedVlanTaggingOperationConfigurationData.mask_for(
-                *data.keys()),
-            data=data
-        )
-    )
-    return omci_cc.send(frame, timeout)
diff --git a/voltha/adapters/adtran_onu/omci/me_frame.py b/voltha/adapters/adtran_onu/omci/me_frame.py
deleted file mode 100644
index 1808d04..0000000
--- a/voltha/adapters/adtran_onu/omci/me_frame.py
+++ /dev/null
@@ -1,291 +0,0 @@
-#
-# Copyright 2017 the original author or authors.
-#
-# 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.
-#
-"""
-OMCI Managed Entity Message support base class
-"""
-from voltha.extensions.omci.omci import *
-
-# abbreviations
-OP = EntityOperations
-AA = AttributeAccess
-
-
-class MEFrame(object):
-    """Base class to help simplify Frame Creation"""
-    def __init__(self, entity_class, entity_id, data):
-        assert issubclass(entity_class, EntityClass), \
-            "'{}' must be a subclass of MEFrame".format(entity_class)
-        self.check_type(entity_id, int)
-
-        if not 0 <= entity_id <= 0xFFFF:
-            raise ValueError('entity_id should be 0..65535')
-
-        self._class = entity_class
-        self._entity_id = entity_id
-        self.data = data
-
-    def __str__(self):
-        return '{}: Entity_ID: {}, Data: {}'.\
-            format(self.entity_class_name, self._entity_id, self.data)
-
-    @property
-    def entity_class(self):
-        """
-        The Entity Class for this ME
-        :return: (EntityClass) Entity class
-        """
-        return self._class
-
-    @property
-    def entity_class_name(self):
-        return self._class.__name__
-
-    @property
-    def entity_id(self):
-        """
-        The Entity ID for this ME frame
-        :return: (int) Entity ID (0..0xFFFF)
-        """
-        return self._entity_id
-
-    @staticmethod
-    def check_type(param, types):
-        if not isinstance(param, types):
-            raise TypeError("Parameter '{}' should be a {}".format(param, types))
-
-    def _check_operation(self, operation):
-        allowed = self.entity_class.mandatory_operations | self.entity_class.optional_operations
-        assert operation in allowed, "{} not allowed for '{}'".format(operation.name,
-                                                                      self.entity_class_name)
-
-    def _check_attributes(self, attributes, access):
-        keys = attributes.keys() if isinstance(attributes, dict) else attributes
-        for attr_name in keys:
-            # Bad attribute name (invalid or spelling error)?
-            index = self.entity_class.attribute_name_to_index_map.get(attr_name)
-            if index is None:
-                raise KeyError("Attribute '{}' is not valid for '{}'".
-                               format(attr_name, self.entity_class_name))
-            # Invalid access?
-            assert access in self.entity_class.attributes[index].access, \
-                "Access '{}' for attribute '{}' is not valid for '{}'".format(access.name,
-                                                                              attr_name,
-                                                                              self.entity_class_name)
-
-        if access.value in [AA.W.value, AA.SBC.value] and isinstance(attributes, dict):
-            for attr_name, value in attributes.iteritems():
-                index = self.entity_class.attribute_name_to_index_map.get(attr_name)
-                attribute = self.entity_class.attributes[index]
-                if not attribute.valid(value):
-                    raise ValueError("Invalid value '{}' for attribute '{}' of '{}".
-                                     format(value, attr_name, self.entity_class_name))
-
-    @staticmethod
-    def _attr_to_data(attributes):
-        """
-        Convert an object into the 'data' set or dictionary for get/set/create/delete
-        requests.
-
-        This method takes a 'string', 'list', or 'set' for get requests and
-        converts it to a 'set' of attributes.
-
-        For create/set requests a dictionary of attribute/value pairs is required
-
-        :param attributes: (basestring, list, set, dict) attributes. For gets
-                           a string, list, set, or dict can be provided. For create/set
-                           operations, a dictionary should be provided. For delete
-                           the attributes may be None since they are ignored.
-
-        :return: (set, dict) set for get/deletes, dict for create/set
-        """
-        if isinstance(attributes, basestring):
-            # data = [str(attributes)]
-            data = set()
-            data.add(str(attributes))
-
-        elif isinstance(attributes, list):
-            assert all(isinstance(attr, basestring) for attr in attributes),\
-                'attribute list must be strings'
-            data = {str(attr) for attr in attributes}
-            assert len(data) == len(attributes), 'Attributes were not unique'
-
-        elif isinstance(attributes, set):
-            assert all(isinstance(attr, basestring) for attr in attributes),\
-                'attribute set must be strings'
-            data = {str(attr) for attr in attributes}
-
-        elif isinstance(attributes, (dict, type(None))):
-            data = attributes
-
-        else:
-            raise TypeError("Unsupported attributes type '{}'".format(type(attributes)))
-
-        return data
-
-    def create(self):
-        """
-        Create a Create request frame for this ME
-        :return: (OmciFrame) OMCI Frame
-        """
-        assert hasattr(self.entity_class, 'class_id'), 'class_id required for Create actions'
-        assert hasattr(self, 'entity_id'), 'entity_id required for Create actions'
-        assert hasattr(self, 'data'), 'data required for Create actions'
-
-        data = getattr(self, 'data')
-        MEFrame.check_type(data, dict)
-        assert len(data) > 0, 'No attributes supplied'
-
-        self._check_operation(OP.Create)
-        self._check_attributes(data, AA.Writable)
-
-        return OmciFrame(
-            transaction_id=None,
-            message_type=OmciCreate.message_id,
-            omci_message=OmciCreate(
-                entity_class=getattr(self.entity_class, 'class_id'),
-                entity_id=getattr(self, 'entity_id'),
-                data=data
-            ))
-
-    def delete(self):
-        """
-        Create a Delete request frame for this ME
-        :return: (OmciFrame) OMCI Frame
-        """
-        self._check_operation(OP.Delete)
-
-        return OmciFrame(
-            transaction_id=None,
-            message_type=OmciGet.message_id,
-            omci_message=OmciGet(
-                entity_class=getattr(self.entity_class, 'class_id'),
-                entity_id=getattr(self, 'entity_id')
-            ))
-
-    def set(self):
-        """
-        Create a Set request frame for this ME
-        :return: (OmciFrame) OMCI Frame
-        """
-        assert hasattr(self, 'data'), 'data required for Set actions'
-        data = getattr(self, 'data')
-        MEFrame.check_type(data, dict)
-        assert len(data) > 0, 'No attributes supplied'
-
-        self._check_operation(OP.Set)
-        self._check_attributes(data, AA.Writable)
-
-        return OmciFrame(
-            transaction_id=None,
-            message_type=OmciSet.message_id,
-            omci_message=OmciSet(
-                entity_class=getattr(self.entity_class, 'class_id'),
-                entity_id=getattr(self, 'entity_id'),
-                attributes_mask=self.entity_class.mask_for(*data.keys()),
-                data=data
-            ))
-
-    def get(self):
-        """
-        Create a Get request frame for this ME
-        :return: (OmciFrame) OMCI Frame
-        """
-        assert hasattr(self, 'data'), 'data required for Get actions'
-        data = getattr(self, 'data')
-        MEFrame.check_type(data, (list, set, dict))
-        assert len(data) > 0, 'No attributes supplied'
-
-        mask_set = data.keys() if isinstance(data, dict) else data
-
-        self._check_operation(OP.Get)
-        self._check_attributes(mask_set, AA.Readable)
-
-        return OmciFrame(
-            transaction_id=None,
-            message_type=OmciGet.message_id,
-            omci_message=OmciGet(
-                entity_class=getattr(self.entity_class, 'class_id'),
-                entity_id=getattr(self, 'entity_id'),
-                attributes_mask=self.entity_class.mask_for(*mask_set)
-            ))
-
-    def reboot(self):
-        """
-        Create a Reboot request from for this ME
-        :return: (OmciFrame) OMCI Frame
-        """
-        self._check_operation(OP.Reboot)
-
-        return OmciFrame(
-            transaction_id=None,
-            message_type=OmciReboot.message_id,
-            omci_message=OmciReboot(
-                entity_class=getattr(self.entity_class, 'class_id'),
-                entity_id=getattr(self, 'entity_id')
-            ))
-
-    def mib_reset(self):
-        """
-        Create a MIB Reset request from for this ME
-        :return: (OmciFrame) OMCI Frame
-        """
-        self._check_operation(OP.MibReset)
-
-        return OmciFrame(
-            transaction_id=None,
-            message_type=OmciMibReset.message_id,
-            omci_message=OmciMibReset(
-                entity_class=getattr(self.entity_class, 'class_id'),
-                entity_id=getattr(self, 'entity_id')
-            ))
-
-    def mib_upload(self):
-        """
-        Create a MIB Upload request from for this ME
-        :return: (OmciFrame) OMCI Frame
-        """
-        self._check_operation(OP.MibUpload)
-
-        return OmciFrame(
-            transaction_id=None,
-            message_type=OmciMibUpload.message_id,
-            omci_message=OmciMibUpload(
-                entity_class=getattr(self.entity_class, 'class_id'),
-                entity_id=getattr(self, 'entity_id')
-            ))
-
-    def mib_upload_next(self):
-        """
-        Create a MIB Upload Next request from for this ME
-        :return: (OmciFrame) OMCI Frame
-        """
-        assert hasattr(self, 'data'), 'data required for Set actions'
-        data = getattr(self, 'data')
-        MEFrame.check_type(data, dict)
-        assert len(data) > 0, 'No attributes supplied'
-        assert 'mib_data_sync' in data, "'mib_data_sync' not in attributes list"
-
-        self._check_operation(OP.MibUploadNext)
-        self._check_attributes(data, AA.Writable)
-
-        return OmciFrame(
-            transaction_id=None,
-            message_type=OmciMibUploadNext.message_id,
-            omci_message=OmciMibUploadNext(
-                entity_class=getattr(self.entity_class, 'class_id'),
-                entity_id=getattr(self, 'entity_id'),
-                command_sequence_number=data['mib_data_sync']
-            ))
diff --git a/voltha/adapters/adtran_onu/omci/omci_cc.py b/voltha/adapters/adtran_onu/omci/omci_cc.py
deleted file mode 100644
index 413a055..0000000
--- a/voltha/adapters/adtran_onu/omci/omci_cc.py
+++ /dev/null
@@ -1,504 +0,0 @@
-#
-# Copyright 2017 the original author or authors.
-#
-# 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.
-#
-
-"""
-OMCI Message support
-"""
-
-import sys
-import arrow
-from twisted.internet import reactor, defer
-from twisted.internet.defer import DeferredQueue, TimeoutError, CancelledError, failure, fail
-from voltha.protos import third_party
-from common.frameio.frameio import hexify
-from voltha.extensions.omci.omci import *
-from omci_entities import add_onu_me_entities
-from omci_me import OntGFrame, OntDataFrame
-
-_ = third_party
-
-_MAX_INCOMING_ALARM_MESSAGES = 256
-_MAX_INCOMING_AVC_MESSAGES = 256
-_MAX_INCOMING_TEST_RESULT_MESSAGES = 64
-
-DEFAULT_OMCI_TIMEOUT = 3            # Seconds
-MAX_OMCI_REQUEST_AGE = 60           # Seconds
-MAX_OMCI_TX_ID = 0xFFFF             # 2 Octets max
-
-# abbreviations
-# ECA = EntityClassAttribute
-# AA = AttributeAccess
-OP = EntityOperations
-
-
-class OMCI_CC(object):
-    """ Handle OMCI Communication Channel specifics for Adtran ONUs"""
-
-    def __init__(self, adapter_agent, device_id,
-                 custom_me_entries=None,
-                 alarm_queue_limit=_MAX_INCOMING_ALARM_MESSAGES,
-                 avc_queue_limit=_MAX_INCOMING_ALARM_MESSAGES,
-                 test_results_queue_limit=_MAX_INCOMING_TEST_RESULT_MESSAGES):
-
-        self.log = structlog.get_logger(device_id=device_id)
-        self._adapter_agent = adapter_agent
-        self._device_id = device_id
-        self._proxy_address = None
-        self._tx_tid = 1
-        self._enabled = False
-        self._requests = dict()       # Tx ID -> (timestamp, deferred, tx_frame, timeout)
-        self._alarm_queue = DeferredQueue(size=alarm_queue_limit)
-        self._avc_queue = DeferredQueue(size=avc_queue_limit)
-        self._test_results_queue = DeferredQueue(size=test_results_queue_limit)
-
-        # Statistics
-        self._tx_frames = 0
-        self._rx_frames = 0
-        self._rx_unknown_tid = 0      # Rx OMCI with no Tx TID match
-        self._rx_onu_frames = 0       # Autonomously generated ONU frames
-        self._rx_alarm_overflow = 0   # Autonomously generated ONU alarms rx overflow
-        self._rx_avc_overflow = 0     # Autonomously generated ONU AVC rx overflow
-        self._rx_onu_discards = 0     # Autonomously generated ONU unknown message types
-        self._rx_timeouts = 0
-        self._tx_errors = 0           # Exceptions during tx request
-        self._consecutive_errors = 0  # Rx & Tx errors in a row, a good RX resets this to 0
-        self._reply_min = sys.maxint  # Fastest successful tx -> rx
-        self._reply_max = 0           # Longest successful tx -> rx
-        self._reply_sum = 0.0         # Total seconds for successful tx->rx (float for average)
-
-        # If a list of custom ME Entities classes were provided, insert them into
-        # main class_id to entity map.
-        # TODO: If this class becomes hidden from the ONU DA, move this to the OMCI State Machine runner
-
-        if custom_me_entries is not None:
-            add_onu_me_entities(custom_me_entries)
-
-    def __str__(self):
-        return "OMCISupport: {}".format(self._device_id)
-
-    @property
-    def enabled(self):
-        return self._enabled
-
-    @enabled.setter
-    def enabled(self, value):
-        """
-        Enable/disable the OMCI Communications Channel
-
-        :param value: (boolean) True to enable, False to disable
-        """
-        assert isinstance(value, bool), 'enabled is a boolean'
-
-        if self._enabled != value:
-            self._enabled = value
-            if self._enabled:
-                self._start()
-            else:
-                self._stop()
-
-    @property
-    def tx_frames(self):
-        return self._tx_frames
-
-    @property
-    def rx_frames(self):
-        return self._rx_frames
-
-    @property
-    def rx_unknown_tid(self):
-        return self._rx_unknown_tid         # Tx TID not found
-
-    @property
-    def rx_onu_frames(self):
-        return self._rx_onu_frames
-
-    @property
-    def rx_alarm_overflow(self):
-        return self._rx_alarm_overflow      # Alarm ONU autonomous overflows
-
-    @property
-    def rx_avc_overflow(self):
-        return self._rx_avc_overflow        # Attribute Value change autonomous overflows
-
-    @property
-    def rx_onu_discards(self):
-        return self._rx_onu_discards        # Attribute Value change autonomous overflows
-
-    @property
-    def rx_timeouts(self):
-        return self._rx_timeouts
-
-    @property
-    def tx_errors(self):
-        return self._tx_errors
-
-    @property
-    def consecutive_errors(self):
-        return self._consecutive_errors
-
-    @property
-    def reply_min(self):
-        return int(round(self._reply_min * 1000.0))     # Milliseconds
-
-    @property
-    def reply_max(self):
-        return int(round(self._reply_max * 1000.0))     # Milliseconds
-
-    @property
-    def reply_average(self):
-        avg = self._reply_sum / self._rx_frames if self._rx_frames > 0 else 0.0
-        return int(round(avg * 1000.0))     # Milliseconds
-
-    @property
-    def get_alarm_message(self):
-        """
-        Attempt to retrieve and remove an ONU Alarm Message from the ONU
-        autonomous message queue.
-
-        TODO: We may want to deprecate this, see TODO comment around line 399 in
-              the _request_success() method below
-
-        :return: a Deferred which fires with the next Alarm Frame available in
-                 the queue.
-        """
-        return self._alarm_queue.get()
-
-    @property
-    def get_avc_message(self):
-        """
-        Attempt to retrieve and remove an ONU Attribute Value Change (AVC)
-        Message from the ONU autonomous message queue.
-
-        TODO: We may want to deprecate this, see TODO comment around line 399 in
-              the _request_success() method below
-
-        :return: a Deferred which fires with the next AVC Frame available in
-                 the queue.
-        """
-        return self._avc_queue.get()
-
-    @property
-    def get_test_results(self):
-        """
-        Attempt to retrieve and remove an ONU Test Results Message from the
-        ONU autonomous message queue.
-
-        TODO: We may want to deprecate this, see TODO comment around line 399 in
-              the _request_success() method below
-
-        :return: a Deferred which fires with the next Test Results Frame is
-                 available in the queue.
-        """
-        return self._test_results_queue.get()
-
-    def _start(self):
-        """
-        Start the OMCI Communications Channel
-        """
-        assert self._enabled, 'Start should only be called if enabled'
-        #
-        # TODO: Perform any other common startup tasks here
-        #
-        self.flush()
-
-        device = self._adapter_agent.get_device(self._device_id)
-        self._proxy_address = device.proxy_address
-
-    def _stop(self):
-        """
-        Stop the OMCI Communications Channel
-        """
-        assert not self._enabled, 'Stop should only be called if disabled'
-        #
-        # TODO: Perform common shutdown tasks here
-        #
-        self.flush()
-        self._proxy_address = None
-
-        # TODO: What is best way to clean up any outstanding futures for these queues
-        self._alarm_queue = None
-        self._avc_queue = None
-        self._test_results_queue = None
-
-    def _receive_onu_message(self, rx_frame):
-        """ Autonomously generated ONU frame Rx handler"""
-        from twisted.internet.defer import QueueOverflow
-
-        self.log.debug('rx-onu-frame', frame_type=type(rx_frame),
-                       frame=hexify(str(rx_frame)))
-
-        # TODO: Signal, via defer if Alarm Overflow or just an event?
-        msg_type = rx_frame.fields['message_type']
-
-        self._rx_onu_frames += 1
-
-        if msg_type == EntityOperations.AlarmNotification:
-            try:
-                self._alarm_queue.put((rx_frame, arrow.utcnow().float_timestamp))
-
-            except QueueOverflow:
-                self._rx_alarm_overflow += 1
-                self.log.warn('onu-rx-alarm-overflow', cnt=self._rx_alarm_overflow)
-
-        elif msg_type == EntityOperations.AttributeValueChange:
-            try:
-                self._alarm_queue.put((rx_frame, arrow.utcnow().float_timestamp))
-
-            except QueueOverflow:
-                self._rx_avc_overflow += 1
-                self.log.warn('onu-rx-avc-overflow', cnt=self._rx_avc_overflow)
-        else:
-            # TODO: Need to add test results message support
-
-            self.log.warn('onu-unsupported-autonomous-message', type=msg_type)
-            self._rx_onu_discards += 1
-
-    def receive_message(self, msg):
-        """
-        Receive and OMCI message from the proxy channel to the OLT.
-
-        Call this from your ONU Adapter on a new OMCI Rx on the proxy channel
-        """
-        if self.enabled:
-            try:
-                now = arrow.utcnow()
-                d = None
-
-                try:
-                    rx_frame = OmciFrame(msg)
-                    rx_tid = rx_frame.fields['transaction_id']
-
-                    if rx_tid == 0:
-                        return self._receive_onu_message(rx_frame)
-
-                    self._rx_frames += 1
-                    self._consecutive_errors = 0
-
-                except KeyError as e:
-                    # Unknown, Unsupported, or vendor-specific ME. Key is the unknown classID
-                    # TODO: Can we create a temporary one to hold it so upload does not always fail on new ME's?
-                    self.log.exception('frame-decode-key-error', msg=hexlify(msg), e=e)
-                    return
-
-                except Exception as e:
-                    self.log.exception('frame-decode', msg=hexlify(msg), e=e)
-                    return
-
-                try:
-                    (ts, d, _, _) = self._requests.pop(rx_tid)
-
-                    ts_diff = now - arrow.Arrow.utcfromtimestamp(ts)
-                    secs = ts_diff.total_seconds()
-                    self._reply_sum += secs
-
-                    if secs < self._reply_min:
-                        self._reply_min = secs
-
-                    if secs > self._reply_max:
-                        self._reply_max = secs
-
-                    # TODO: Could also validate response type based on request action
-
-                except KeyError:
-                    # Possible late Rx on a message that timed-out
-                    self._rx_unknown_tid += 1
-                    self.log.warn('tx-message-missing', rx_id=rx_tid, msg=hexlify(msg))
-                    return
-
-                except Exception as e:
-                    self.log.exception('frame-match', msg=hexlify(msg), e=e)
-                    if d is not None:
-                        return d.errback(failure.Failure(e))
-                    return
-
-                d.callback(rx_frame)
-
-            except Exception as e:
-                self.log.exception('rx-msg', e=e)
-
-    def flush(self, max_age=0):
-        limit = arrow.utcnow().float_timestamp - max_age
-        old = [tid for tid, (ts, _, _, _) in self._requests.iteritems()
-               if ts <= limit]
-
-        for tid in old:
-            (_, d, _, _) = self._requests.pop(tid)
-            if d is not None and not d.called:
-                d.cancel()
-
-        self._requests = dict()
-
-        if max_age == 0:
-            # Flush autonomous messages (Alarms & AVCs)
-            while self._alarm_queue.pending:
-                _ = yield self._alarm_queue.get()
-
-            while self._avc_queue.pending:
-                _ = yield self._avc_queue.get()
-
-    def _get_tx_tid(self):
-        """
-        Get the next Transaction ID for a tx.  Note TID=0 is reserved
-        for autonomously generated messages from an ONU
-
-        :return: (int) TID
-        """
-        tx_tid, self._tx_tid = self._tx_tid, self._tx_tid + 1
-        if self._tx_tid > MAX_OMCI_TX_ID:
-            self._tx_tid = 1
-
-        return tx_tid
-
-    def _request_failure(self, value, tx_tid):
-        """
-        Handle a transmit failure and/or Rx timeout
-
-        :param value: (Failure) Twisted failure
-        :param tx_tid: (int) Associated Tx TID
-        """
-        if tx_tid in self._requests:
-            (_, _, _, timeout) = self._requests.pop(tx_tid)
-        else:
-            timeout = 0
-
-        if isinstance(value, failure.Failure):
-            value.trap(CancelledError)
-            self._rx_timeouts += 1
-            self._consecutive_errors += 1
-            self.log.info('timeout', tx_id=tx_tid, timeout=timeout)
-            value = failure.Failure(TimeoutError(timeout, "Deferred"))
-
-        return value
-
-    def _request_success(self, rx_frame):
-        """
-        Handle transmit success (a matching Rx was received)
-
-        :param rx_frame: (OmciFrame) OMCI response frame with matching TID
-        :return: (OmciFrame) OMCI response frame with matching TID
-        """
-        #
-        # TODO: Here we could update the MIB database if we did a set/create/delete
-        #       or perhaps a verify if a GET.  Also could increment mib counter
-        #
-        # TODO: A better way to perform this in VOLTHA v1.3 would be to provide
-        #       a pub/sub capability for external users/tasks to monitor responses
-        #       that could optionally take a filter. This would allow a MIB-Sync
-        #       task to easily watch all AVC notifications as well as Set/Create/Delete
-        #       operations and keep them serialized.  It may also be a better/easier
-        #       way to handle things if we containerize OpenOMCI.
-        #
-        try:
-            if isinstance(rx_frame.omci_message, OmciGetResponse):
-                pass    # TODO: Implement MIB check or remove
-
-            elif isinstance(rx_frame.omci_message, OmciSetResponse):
-                pass    # TODO: Implement MIB update
-
-            elif isinstance(rx_frame.omci_message, OmciCreateResponse):
-                pass    # TODO: Implement MIB update
-
-            elif isinstance(rx_frame.omci_message, OmciDeleteResponse):
-                pass    # TODO: Implement MIB update
-
-        except Exception as e:
-            self.log.exception('omci-message', e=e)
-
-        return rx_frame
-
-    def send(self, frame, timeout=DEFAULT_OMCI_TIMEOUT):
-        """
-        Send the OMCI Frame to the ONU via the proxy_channel
-
-        :param frame: (OMCIFrame) Message to send
-        :param timeout: (int) Rx Timeout. 0=Forever
-        :return: (deferred) A deferred that fires when the response frame is received
-                            or if an error/timeout occurs
-        """
-        self.flush(max_age=MAX_OMCI_REQUEST_AGE)
-
-        assert timeout <= MAX_OMCI_REQUEST_AGE, \
-            'Maximum timeout is {} seconds'.format(MAX_OMCI_REQUEST_AGE)
-        assert isinstance(frame, OmciFrame), \
-            "Invalid frame class '{}'".format(type(frame))
-
-        if not self.enabled or self._proxy_address is None:
-            # TODO custom exceptions throughout this code would be helpful
-            return fail(result=failure.Failure(Exception('OMCI is not enabled')))
-
-        try:
-            tx_tid = frame.fields['transaction_id']
-            if tx_tid is None:
-                tx_tid = self._get_tx_tid()
-                frame.fields['transaction_id'] = tx_tid
-
-            assert tx_tid not in self._requests, 'TX TID {} is already exists'.format(tx_tid)
-            assert tx_tid >= 0, 'Invalid Tx TID: {}'.format(tx_tid)
-
-            ts = arrow.utcnow().float_timestamp
-            d = defer.Deferred()
-
-            self._adapter_agent.send_proxied_message(self._proxy_address,
-                                                     hexify(str(frame)))
-            self._tx_frames += 1
-            self._requests[tx_tid] = (ts, d, frame, timeout)
-
-            d.addCallbacks(self._request_success, self._request_failure,
-                           errbackArgs=(tx_tid,))
-
-            if timeout > 0:
-                d.addTimeout(timeout, reactor)
-
-        except Exception as e:
-            self._tx_errors += 1
-            self._consecutive_errors += 1
-            self.log.exception('send-omci', e=e)
-            return fail(result=failure.Failure(e))
-
-        return d
-
-    ###################################################################################
-    # MIB Action shortcuts
-
-    def send_mib_reset(self, timeout=DEFAULT_OMCI_TIMEOUT):
-        """
-        Perform a MIB Reset
-        """
-        self.log.debug('send-mib-reset')
-
-        frame = OntDataFrame().mib_reset()
-        return self.send(frame, timeout)
-
-    def send_mib_upload(self, timeout=DEFAULT_OMCI_TIMEOUT):
-        self.log.debug('send-mib-upload')
-
-        frame = OntDataFrame().mib_upload()
-        return self.send(frame, timeout)
-
-    def send_mib_upload_next(self, seq_no, timeout=DEFAULT_OMCI_TIMEOUT):
-        self.log.debug('send-mib-upload-next')
-
-        frame = OntDataFrame(seq_no).mib_upload_next()
-        return self.send(frame, timeout)
-
-    def send_reboot(self, timeout=DEFAULT_OMCI_TIMEOUT):
-        """
-        Send an ONU Device reboot request (ONU-G ME).
-        """
-        self.log.debug('send-mib-reboot')
-
-        frame = OntGFrame().reboot()
-        return self.send(frame, timeout)
diff --git a/voltha/adapters/adtran_onu/omci/omci_defs.py b/voltha/adapters/adtran_onu/omci/omci_defs.py
deleted file mode 100644
index 5b3f5a8..0000000
--- a/voltha/adapters/adtran_onu/omci/omci_defs.py
+++ /dev/null
@@ -1,32 +0,0 @@
-#
-# Copyright 2017 the original author or authors.
-#
-# 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.
-#
-""" Additional definitions not found in OMCI library"""
-
-from enum import Enum
-
-
-class ReasonCodes(Enum):
-    # OMCI Result and reason codes
-
-    Success = 0,            # Command processed successfully
-    ProcessingError = 1,    # Command processing error
-    NotSupported = 2,       # Command not supported
-    ParameterError = 3,     # Parameter error
-    UnknownEntity = 4,      # Unknown managed entity
-    UnknownInstance = 5,    # Unknown managed entity instance
-    DeviceBusy = 6,         # Device busy
-    InstanceExists = 7,     # Instance Exists
-    AttributeFailure = 9,   # Attribute(s) failed or unknown
diff --git a/voltha/adapters/adtran_onu/omci/omci_entities.py b/voltha/adapters/adtran_onu/omci/omci_entities.py
index 62c8516..6cef5ee 100644
--- a/voltha/adapters/adtran_onu/omci/omci_entities.py
+++ b/voltha/adapters/adtran_onu/omci/omci_entities.py
@@ -17,10 +17,7 @@
 import inspect
 
 import sys
-from scapy.fields import ByteField, ShortField
-from scapy.fields import IntField, StrFixedLenField
-
-
+from scapy.fields import ShortField
 from voltha.extensions.omci.omci_entities import EntityClassAttribute, \
     AttributeAccess, EntityOperations, EntityClass
 
@@ -89,21 +86,18 @@
 #################################################################################
 # entity class lookup table from entity_class values
 _onu_entity_classes_name_map = dict(
-    inspect.getmembers(sys.modules[__name__],
-    lambda o: inspect.isclass(o) and
-              issubclass(o, EntityClass) and
-              o is not EntityClass)
+    inspect.getmembers(sys.modules[__name__], lambda o:
+    inspect.isclass(o) and issubclass(o, EntityClass) and o is not EntityClass)
 )
-
-onu_custom_entity_classes = [c for c in _onu_entity_classes_name_map.itervalues()]
+_onu_custom_entity_classes = [c for c in _onu_entity_classes_name_map.itervalues()]
+_onu_custom_entity_id_to_class_map = dict()
 
 
-def add_onu_me_entities(new_me_classes):
-    from voltha.extensions.omci.omci_entities import entity_classes, entity_id_to_class_map
-
-    for entity_class in new_me_classes:
-        assert entity_class.class_id not in entity_id_to_class_map, \
+def onu_custom_me_entities():
+    for entity_class in _onu_custom_entity_classes:
+        assert entity_class.class_id not in _onu_custom_entity_id_to_class_map, \
             "Class ID '{}' already exists in the class map".format(entity_class.class_id)
-        entity_id_to_class_map[entity_class.class_id] = entity_class
+        _onu_custom_entity_id_to_class_map[entity_class.class_id] = entity_class
 
-    entity_classes.extend(new_me_classes)
+    return _onu_custom_entity_id_to_class_map
+
diff --git a/voltha/adapters/adtran_onu/omci/omci_me.py b/voltha/adapters/adtran_onu/omci/omci_me.py
deleted file mode 100644
index 6b26ad5..0000000
--- a/voltha/adapters/adtran_onu/omci/omci_me.py
+++ /dev/null
@@ -1,664 +0,0 @@
-#
-# Copyright 2017 the original author or authors.
-#
-# 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.
-#
-"""
-OMCI Managed Entity Frame support
-"""
-from voltha.extensions.omci.omci import *
-from me_frame import MEFrame
-
-
-class CardholderFrame(MEFrame):
-    """
-    This managed entity represents fixed equipment slot configuration
-    for the ONU
-    """
-    def __init__(self, single, slot_number, attributes):
-        """
-        :param single:(bool) True if the ONU is a single piece of integrated equipment,
-                             False if the ONU contains pluggable equipment modules
-        :param slot_number: (int) slot number (0..254)
-
-        :param attributes: (basestring, list, set, dict) attributes. For gets
-                           a string, list, or set can be provided. For create/set
-                           operations, a dictionary should be provided, for
-                           deletes None may be specified.
-        """
-        # Validate
-        MEFrame.check_type(single, bool)
-        MEFrame.check_type(slot_number, int)
-        if not 0 <= slot_number <= 254:
-            raise ValueError('slot_number should be 0..254')
-
-        entity_id = 256 + slot_number if single else slot_number
-
-        super(CardholderFrame, self).__init__(Cardholder, entity_id,
-                                              MEFrame._attr_to_data(attributes))
-
-
-class CircuitPackFrame(MEFrame):
-    """
-    This managed entity models a real or virtual circuit pack that is equipped in
-    a real or virtual ONU slot.
-    """
-    def __init__(self, entity_id, attributes):
-        """
-        :param entity_id: (int) This attribute uniquely identifies each instance of
-                                this managed entity. Its value is the same as that
-                                of the cardholder managed entity containing this
-                                circuit pack instance. (0..65535)
-
-        :param attributes: (basestring, list, set, dict) attributes. For gets
-                           a string, list, or set can be provided. For create/set
-                           operations, a dictionary should be provided, for
-                           deletes None may be specified.
-        """
-        super(CircuitPackFrame, self).__init__(CircuitPack, entity_id,
-                                               MEFrame._attr_to_data(attributes))
-
-
-class ExtendedVlanTaggingOperationConfigurationDataFrame(MEFrame):
-    """
-    This managed entity organizes data associated with VLAN tagging. Regardless
-    of its point of attachment, the specified tagging operations refer to the
-     upstream direction.
-    """
-    def __init__(self, entity_id, attributes):
-        """
-        :param entity_id: (int) This attribute uniquely identifies each instance of
-                                this managed entity. Its value is the same as that
-                                of the cardholder managed entity containing this
-                                circuit pack instance. (0..65535)
-
-        :param attributes: (basestring, list, set, dict) attributes. For gets
-                           a string, list, or set can be provided. For create/set
-                           operations, a dictionary should be provided, for
-                           deletes None may be specified.
-        """
-        super(ExtendedVlanTaggingOperationConfigurationDataFrame,
-              self).__init__(ExtendedVlanTaggingOperationConfigurationData,
-                             entity_id,
-                             MEFrame._attr_to_data(attributes))
-
-
-class IpHostConfigDataFrame(MEFrame):
-    """
-    The IP host config data configures IPv4 based services offered on the ONU.
-    """
-    def __init__(self, entity_id, attributes):
-        """
-        :param entity_id: (int) This attribute uniquely identifies each instance of
-                                this managed entity. (0..65535)
-
-        :param attributes: (basestring, list, set, dict) attributes. For gets
-                           a string, list, or set can be provided. For create/set
-                           operations, a dictionary should be provided, for
-                           deletes None may be specified.
-        """
-        super(IpHostConfigDataFrame, self).__init__(IpHostConfigData,
-                                                    entity_id,
-                                                    MEFrame._attr_to_data(attributes))
-
-
-class GalEthernetProfileFrame(MEFrame):
-    """
-    This managed entity organizes data that describe the GTC adaptation layer
-    processing functions of the ONU for Ethernet services.
-    """
-    def __init__(self, entity_id, max_gem_payload_size=None):
-        """
-        :param entity_id: (int) This attribute uniquely identifies each instance of
-                                this managed entity. (0..65535)
-
-        :param max_gem_payload_size: (int) This attribute defines the maximum payload
-                                     size generated in the associated GEM interworking
-                                     termination point managed entity. (0..65535
-        """
-        MEFrame.check_type(max_gem_payload_size, (int, type(None)))
-        if max_gem_payload_size is not None and not 0 <= max_gem_payload_size <= 0xFFFF:  # TODO: verify min/max
-            raise ValueError('max_gem_payload_size should be 0..0xFFFF')
-
-        data = None if max_gem_payload_size is None else\
-            {
-                'max_gem_payload_size': max_gem_payload_size
-            }
-        super(GalEthernetProfileFrame, self).__init__(GalEthernetProfile,
-                                                      entity_id,
-                                                      data)
-
-
-class GemInterworkingTpFrame(MEFrame):
-    """
-    An instance of this managed entity represents a point in the ONU where the
-    interworking of a bearer service (usually Ethernet) to the GEM layer takes
-    place.
-    """
-    def __init__(self, entity_id,
-                 gem_port_network_ctp_pointer=None,
-                 interworking_option=None,
-                 service_profile_pointer=None,
-                 interworking_tp_pointer=None,
-                 pptp_counter=None,
-                 gal_profile_pointer=None,
-                 attributes=None):
-        """
-        :param entity_id: (int) This attribute uniquely identifies each instance of
-                                this managed entity. (0..65535)
-
-        :param gem_port_network_ctp_pointer: (int) This attribute points to an instance of
-                                                 the GEM port network CTP. (0..65535)
-
-        :param interworking_option: (int) This attribute identifies the type
-                                of non-GEM function that is being interworked.
-                                The options are:
-                                    0 Circuit-emulated TDM
-                                    1 MAC bridged LAN
-                                    2 Reserved
-                                    3 Reserved
-                                    4 Video return path
-                                    5 IEEE 802.1p mapper
-                                    6 Downstream broadcast
-                                    7 MPLS PW TDM service
-
-        :param service_profile_pointer: (int) This attribute points to an instance of
-                                              a service profile.
-                            CES service profile                 if interworking option = 0
-                            MAC bridge service profile          if interworking option = 1
-                            Video return path service profile   if interworking option = 4
-                            IEEE 802.1p mapper service profile  if interworking option = 5
-                            Null pointer                        if interworking option = 6
-                            CES service profile                 if interworking option = 7
-
-        :param interworking_tp_pointer: (int) This attribute is used for the circuit
-                                              emulation service and IEEE 802.1p mapper
-                                              service without a MAC bridge.
-
-        :param gal_profile_pointer: (int) This attribute points to an instance of
-                                              a service profile.
-
-        :param attributes: (basestring, list, set, dict) additional ME attributes.
-                           not specifically specified as a parameter. For gets
-                           a string, list, or set can be provided. For create/set
-                           operations, a dictionary should be provided, for
-                           deletes None may be specified..
-        """
-        # Validate
-        self.check_type(gem_port_network_ctp_pointer, (int, type(None)))
-        self.check_type(interworking_option, (int, type(None)))
-        self.check_type(service_profile_pointer, (int, type(None)))
-        self.check_type(interworking_tp_pointer,(int, type(None)))
-        self.check_type(pptp_counter,(int, type(None)))
-        self.check_type(gal_profile_pointer, (int, type(None)))
-
-        if gem_port_network_ctp_pointer is not None and not 0 <= gem_port_network_ctp_pointer <= 0xFFFE:  # TODO: Verify max
-            raise ValueError('gem_port_network_ctp_pointer should be 0..0xFFFE')
-
-        if interworking_option is not None and not 0 <= interworking_option <= 7:
-            raise ValueError('interworking_option should be 0..7')
-
-        if service_profile_pointer is not None and not 0 <= service_profile_pointer <= 0xFFFE:  # TODO: Verify max
-            raise ValueError('service_profile_pointer should be 0..0xFFFE')
-
-        if interworking_tp_pointer is not None and not 0 <= interworking_tp_pointer <= 0xFFFE:  # TODO: Verify max
-            raise ValueError('interworking_tp_pointer should be 0..0xFFFE')
-
-        if pptp_counter is not None and not 0 <= pptp_counter <= 255:  # TODO: Verify max
-            raise ValueError('pptp_counter should be 0..255')
-
-        if gal_profile_pointer is not None and not 0 <= gal_profile_pointer <= 0xFFFE:  # TODO: Verify max
-            raise ValueError('gal_profile_pointer should be 0..0xFFFE')
-
-        data = MEFrame._attr_to_data(attributes)
-
-        if gem_port_network_ctp_pointer is not None or \
-                interworking_option is not None or \
-                service_profile_pointer is not None or \
-                interworking_tp_pointer is not None or \
-                gal_profile_pointer is not None:
-
-            data = data or dict()
-
-            if gem_port_network_ctp_pointer is not None:
-                data['gem_port_network_ctp_pointer'] = gem_port_network_ctp_pointer
-
-            if interworking_option is not None:
-                data['interworking_option'] = interworking_option
-
-            if service_profile_pointer is not None:
-                data['service_profile_pointer'] = service_profile_pointer
-
-            if interworking_tp_pointer is not None:
-                data['interworking_tp_pointer'] = interworking_tp_pointer
-
-            if gal_profile_pointer is not None:
-                data['gal_profile_pointer'] = gal_profile_pointer
-
-        super(GemInterworkingTpFrame, self).__init__(GemInterworkingTp,
-                                                     entity_id,
-                                                     data)
-
-
-class GemPortNetworkCtpFrame(MEFrame):
-    """
-    This managed entity represents the termination of a GEM port on an ONU.
-    """
-    def __init__(self, entity_id, port_id=None, tcont_id=None,
-                 direction=None, upstream_tm=None, attributes=None):
-        """
-        :param entity_id: (int) This attribute uniquely identifies each instance of
-                                this managed entity. (0..65535)
-
-        :param port_id: (int) This attribute is the port-ID of the GEM port associated
-                              with this CTP
-
-        :param tcont_id: (int) This attribute points to a T-CONT instance
-
-        :param direction: (string) Data direction.  Valid values are:
-                                   'upstream'       - UNI-to-ANI
-                                   'downstream'     - ANI-to-UNI
-                                   'bi-directional' - guess :-)
-
-        :param upstream_tm: (int) If the traffic management option attribute in
-                                  the ONU-G ME is 0 (priority controlled) or 2
-                                  (priority and rate controlled), this pointer
-                                  specifies the priority queue ME serving this GEM
-                                  port network CTP. If the traffic management
-                                  option attribute is 1 (rate controlled), this
-                                  attribute redundantly points to the T-CONT serving
-                                  this GEM port network CTP.
-
-        :param attributes: (basestring, list, set, dict) additional ME attributes.
-                           not specifically specified as a parameter. For gets
-                           a string, list, or set can be provided. For create/set
-                           operations, a dictionary should be provided, for
-                           deletes None may be specified.
-        """
-        _directions = {"upstream": 1, "downstream": 2, "bi-directional": 3}
-
-        # Validate
-        self.check_type(port_id, (int, type(None)))
-        self.check_type(tcont_id, (int, type(None)))
-        self.check_type(direction, (basestring, type(None)))
-        self.check_type(upstream_tm, (int, type(None)))
-
-        if port_id is not None and not 0 <= port_id <= 0xFFFE:  # TODO: Verify max
-            raise ValueError('port_id should be 0..0xFFFE')
-
-        if tcont_id is not None and not 0 <= tcont_id <= 0xFFFE:  # TODO: Verify max
-            raise ValueError('tcont_id should be 0..0xFFFE')
-
-        if direction is not None and str(direction).lower() not in _directions:
-            raise ValueError('direction should one of {}'.format(_directions.keys()))
-
-        if upstream_tm is not None and not 0 <= upstream_tm <= 0xFFFE:  # TODO: Verify max
-            raise ValueError('upstream_tm should be 0..0xFFFE')
-
-        data = MEFrame._attr_to_data(attributes)
-
-        if port_id is not None or tcont_id is not None or\
-                direction is not None or upstream_tm is not None:
-
-            data = data or dict()
-
-            if port_id is not None:
-                data['port_id'] = port_id
-            if tcont_id is not None:
-                data['tcont_pointer'] = tcont_id
-            if direction is not None:
-                data['direction'] = _directions[str(direction).lower()]
-            if upstream_tm is not None:
-                data['traffic_management_pointer_upstream'] = upstream_tm
-
-        super(GemPortNetworkCtpFrame, self).__init__(GemPortNetworkCtp,
-                                                     entity_id,
-                                                     data)
-
-
-class Ieee8021pMapperServiceProfileFrame(MEFrame):
-    """
-    This managed entity associates the priorities of IEEE 802.1p [IEEE
-    802.1D] priority tagged frames with specific connections.
-    """
-    def __init__(self, entity_id, tp_pointer=None, interwork_tp_pointers=None):
-        """
-        :param entity_id: (int) This attribute uniquely identifies each instance of
-                                this managed entity. (0..65535)
-
-        :param tp_pointer: (int) This attribute points to an instance of the
-                                 associated termination point. (0..65535)
-
-        :param interwork_tp_pointers: (list) List of 1 to 8 interworking termination
-                                   point IDs. The first entry is assigned
-                                   got p-bit priority 0. If less than 8 IDs
-                                   are provided, the last ID is used for
-                                   the remaining items.
-        """
-        if tp_pointer is None and interwork_tp_pointers is None:
-            data = dict(
-                    tp_pointer=OmciNullPointer,
-                    interwork_tp_pointer_for_p_bit_priority_0=OmciNullPointer,
-                    interwork_tp_pointer_for_p_bit_priority_1=OmciNullPointer,
-                    interwork_tp_pointer_for_p_bit_priority_2=OmciNullPointer,
-                    interwork_tp_pointer_for_p_bit_priority_3=OmciNullPointer,
-                    interwork_tp_pointer_for_p_bit_priority_4=OmciNullPointer,
-                    interwork_tp_pointer_for_p_bit_priority_5=OmciNullPointer,
-                    interwork_tp_pointer_for_p_bit_priority_6=OmciNullPointer,
-                    interwork_tp_pointer_for_p_bit_priority_7=OmciNullPointer
-                )
-        else:
-            self.check_type(tp_pointer, (list, type(None)))
-            self.check_type(interwork_tp_pointers, (list, type(None)))
-
-            data = dict()
-
-            if tp_pointer is not None:
-                data['tp_pointer'] = tp_pointer
-
-            if interwork_tp_pointers is not None:
-                assert all(isinstance(tp, int) and 0 <= tp <= 0xFFFF
-                           for tp in interwork_tp_pointers),\
-                    'Interworking TP IDs must be 0..0xFFFF'
-                assert 1 <= len(interwork_tp_pointers) <= 8, \
-                    'Invalid number of Interworking TP IDs. Must be 1..8'
-
-                data = dict()
-                for pbit in range(0, len(interwork_tp_pointers)):
-                    data['interwork_tp_pointer_for_p_bit_priority_{}'.format(pbit)] = \
-                        interwork_tp_pointers[pbit]
-
-                for pbit in range(len(interwork_tp_pointers), 7):
-                    data['interwork_tp_pointer_for_p_bit_priority_{}'.format(pbit)] = \
-                        interwork_tp_pointers[len(interwork_tp_pointers) - 1]
-
-        super(Ieee8021pMapperServiceProfileFrame, self).__init__(Ieee8021pMapperServiceProfile,
-                                                                 entity_id,
-                                                                 data)
-
-
-class MacBridgePortConfigurationDataFrame(MEFrame):
-    """
-    This managed entity represents the ONU as equipment.
-    """
-    def __init__(self, entity_id, bridge_id_pointer=None, port_num=None,
-                 tp_type=None, tp_pointer=None, attributes=None):
-        """
-        :param entity_id: (int) This attribute uniquely identifies each instance of
-                                this managed entity. (0..65535)
-
-        :param bridge_id_pointer: (int) This attribute points to an instance of the
-                                        MAC bridge service profile. (0..65535)
-
-        :param port_num: (int) This attribute is the bridge port number. (0..255)
-
-        :param tp_type: (int) This attribute identifies the type of termination point
-                              associated with this MAC bridge port. Valid values are:
-                        1  Physical path termination point Ethernet UNI
-                        2  Interworking VCC termination point
-                        3  IEEE 802.1p mapper service profile
-                        4  IP host config data or IPv6 host config data
-                        5  GEM interworking termination point
-                        6  Multicast GEM interworking termination point
-                        7  Physical path termination point xDSL UNI part 1
-                        8  Physical path termination point VDSL UNI
-                        9  Ethernet flow termination point
-                        10 Reserved
-                        11 Virtual Ethernet interface point
-                        12 Physical path termination point MoCA UNI
-
-        :param tp_pointer: (int) This attribute points to the termination point
-                                 associated with this MAC bridge por. (0..65535)
-
-        :param attributes: (basestring, list, set, dict) additional ME attributes.
-                           not specifically specified as a parameter. For gets
-                           a string, list, or set can be provided. For create/set
-                           operations, a dictionary should be provided, for
-                           deletes None may be specified.
-        """
-        # Validate
-        self.check_type(bridge_id_pointer, (int, type(None)))
-        self.check_type(port_num, (int, type(None)))
-        self.check_type(tp_type, (int, type(None)))
-        self.check_type(tp_pointer, (int, type(None)))
-
-        if bridge_id_pointer is not None and not 0 <= bridge_id_pointer <= 0xFFFE:  # TODO: Verify max
-            raise ValueError('bridge_id_pointer should be 0..0xFFFE')
-
-        if port_num is not None and not 0 <= port_num <= 255:
-            raise ValueError('port_num should be 0..255')       # TODO: Verify min,max
-
-        if tp_type is not None and not 1 <= tp_type <= 12:
-            raise ValueError('service_profile_pointer should be 1..12')
-
-        if tp_pointer is not None and not 0 <= tp_pointer <= 0xFFFE:  # TODO: Verify max
-            raise ValueError('interworking_tp_pointer should be 0..0xFFFE')
-
-        data = MEFrame._attr_to_data(attributes)
-
-        if bridge_id_pointer is not None or \
-                port_num is not None or \
-                tp_type is not None or \
-                tp_pointer is not None:
-
-            data = data or dict()
-
-            if bridge_id_pointer is not None:
-                data['bridge_id_pointer'] = bridge_id_pointer
-
-            if port_num is not None:
-                data['port_num'] = port_num
-
-            if tp_type is not None:
-                data['tp_type'] = tp_type
-
-            if tp_pointer is not None:
-                data['tp_pointer'] = tp_pointer
-
-        super(MacBridgePortConfigurationDataFrame, self).\
-            __init__(MacBridgePortConfigurationData, entity_id, data)
-
-
-class MacBridgeServiceProfileFrame(MEFrame):
-    """
-    This managed entity models a MAC bridge in its entirety; any number
-    of ports may be associated with the bridge through pointers to the
-    MAC bridge service profile managed entity.
-    """
-    def __init__(self, entity_id, attributes=None):
-        """
-        :param entity_id: (int) This attribute uniquely identifies each instance of
-                                this managed entity. (0..65535)
-
-        :param attributes: (basestring, list, set, dict) attributes. For gets
-                           a string, list, or set can be provided. For create/set
-                           operations, a dictionary should be provided, for
-                           deletes None may be specified.
-        """
-        super(MacBridgeServiceProfileFrame, self).__init__(MacBridgeServiceProfile,
-                                                           entity_id,
-                                                           MEFrame._attr_to_data(attributes))
-
-
-class OntGFrame(MEFrame):
-    """
-    This managed entity represents the ONU as equipment.
-    """
-    def __init__(self, attributes=None):
-        """
-        :param attributes: (basestring, list, set, dict) attributes. For gets
-                           a string, list, or set can be provided. For create/set
-                           operations, a dictionary should be provided, for
-                           deletes None may be specified.
-        """
-        super(OntGFrame, self).__init__(OntG, 0,
-                                        MEFrame._attr_to_data(attributes))
-
-
-class Ont2GFrame(MEFrame):
-    """
-    This managed entity contains additional attributes associated with a PON ONU.
-    """
-    def __init__(self, attributes=None):
-        """
-        :param attributes: (basestring, list, set, dict) attributes. For gets
-                           a string, list, or set can be provided. For create/set
-                           operations, a dictionary should be provided, for
-                           deletes None may be specified.
-        """
-        # Only one managed entity instance (Entity ID=0)
-        super(Ont2GFrame, self).__init__(Ont2G, 0,
-                                         MEFrame._attr_to_data(attributes))
-
-
-class PptpEthernetUniFrame(MEFrame):
-    """
-    This managed entity represents the point at an Ethernet UNI where the physical path
-    terminates and Ethernet physical level functions are performed.
-    """
-    def __init__(self, entity_id, attributes=None):
-        """
-        :param entity_id: (int) This attribute uniquely identifies each instance of
-                                this managed entity. (0..65535)
-
-        :param attributes: (basestring, list, set, dict) attributes. For gets
-                           a string, list, or set can be provided. For create/set
-                           operations, a dictionary should be provided, for
-                           deletes None may be specified.
-        """
-        super(PptpEthernetUniFrame, self).__init__(PptpEthernetUni, entity_id,
-                                                   MEFrame._attr_to_data(attributes))
-
-
-class SoftwareImageFrame(MEFrame):
-    """
-    This managed entity models an executable software image stored in the ONU.
-    """
-    def __init__(self, entity_id):
-        """
-        :param entity_id: (int) This attribute uniquely identifies each instance of
-                                this managed entity. (0..65535)
-        """
-        super(SoftwareImageFrame, self).__init__(SoftwareImage, entity_id, None)
-
-
-class TcontFrame(MEFrame):
-    """
-    An instance of the traffic container managed entity T-CONT represents a
-    logical connection group associated with a G-PON PLOAM layer alloc-ID.
-    """
-    def __init__(self, entity_id, alloc_id=None, policy=None):
-        """
-        :param entity_id: (int) This attribute uniquely identifies each instance of
-                                this managed entity. (0..65535)
-
-        :param alloc_id: (int) This attribute links the T-CONT with the alloc-ID
-                               assigned by the OLT in the assign_alloc-ID PLOAM
-                               message (0..0xFFF)
-
-        :param policy: (int) This attribute indicates the T-CONT's traffic scheduling
-                             policy. Valid values:
-                                0 - Null
-                                1 - Strict priority
-                                2 - WRR - Weighted round robin
-        """
-        # Validate
-        self.check_type(alloc_id, (int, type(None)))
-        self.check_type(policy, (int, type(None)))
-
-        if alloc_id is not None and not 0 <= alloc_id <= 0xFFF:
-            raise ValueError('alloc_id should be 0..0xFFF')
-
-        if policy is not None and not 0 <= policy <= 2:
-            raise ValueError('policy should be 0..2')
-
-        if alloc_id is None and policy is None:
-            data = None
-        else:
-            data = dict()
-
-            if alloc_id is not None:
-                data['alloc_id'] = alloc_id
-
-            if policy is not None:
-                data['policy'] = policy
-
-        super(TcontFrame, self).__init__(Tcont, entity_id, data)
-
-
-class VlanTaggingFilterDataFrame(MEFrame):
-    """
-    An instance of this managed entity represents a point in the ONU where the
-    interworking of a bearer service (usually Ethernet) to the GEM layer takes
-    place.
-    """
-    def __init__(self, entity_id, vlan_tcis=None, forward_operation=None):
-        """
-        :param entity_id: (int) This attribute uniquely identifies each instance of
-                                this managed entity. (0..65535)
-
-        :param vlan_tcis: (list) This attribute is a list of provisioned TCI values
-                                 for the bridge port. (0..0xFFFF)
-
-        :param forward_operation: (int) What to do.  See ITU spec for more information
-
-        """
-        # Validate
-        self.check_type(vlan_tcis, (list, type(None)))
-        self.check_type(forward_operation, (int, type(None)))
-
-        if forward_operation is not None and not 0 <= forward_operation <= 0x21:
-            raise ValueError('forward_operation should be 0..0x21')
-
-        if vlan_tcis is None and forward_operation is None:
-            data = None
-
-        else:
-            data = dict()
-
-            if vlan_tcis is not None:
-                assert all(isinstance(tci, int) and 0 <= tci <= 0xFFFF
-                           for tci in vlan_tcis), "VLAN TCI's are 0..0xFFFF"
-                assert 1 <= len(vlan_tcis) <= 12, 'Number of VLAN TCI values is 1..12'
-
-                for index in range(0, len(vlan_tcis)):
-                    data['vlan_filter_{}'.format(index)] = vlan_tcis[index]
-
-                data['number_of_entries'] = len(vlan_tcis)
-
-            if forward_operation is not None:
-                assert 0 <= forward_operation <= 0x21, 'forwarding_operation must be 0x00..0x21'
-                data['forward_operation'] = forward_operation
-
-        super(VlanTaggingFilterDataFrame, self).__init__(VlanTaggingFilterData,
-                                                         entity_id,
-                                                         data)
-
-
-class OntDataFrame(MEFrame):
-    """
-    This managed entity models the MIB itself
-    """
-    def __init__(self, mib_data_sync=None):
-        """
-        :param mib_data_sync: (int) This attribute is used to check the alignment
-                                    of the MIB of the ONU with the corresponding MIB
-                                    in the OLT. (0..255)
-        """
-        self.check_type(mib_data_sync, (int, type(None)))
-        if mib_data_sync is not None and not 0 <= mib_data_sync <= 255:
-            raise ValueError('mib_data_sync should be 0..255')
-
-        data = {'mib_data_sync': mib_data_sync} if mib_data_sync is not None else None
-
-        super(OntDataFrame, self).__init__(OntData, 0, data)
diff --git a/voltha/adapters/adtran_onu/onu_gem_port.py b/voltha/adapters/adtran_onu/onu_gem_port.py
index c0fb759..9d5bc61 100644
--- a/voltha/adapters/adtran_onu/onu_gem_port.py
+++ b/voltha/adapters/adtran_onu/onu_gem_port.py
@@ -16,20 +16,21 @@
 import structlog
 from voltha.adapters.adtran_olt.xpon.gem_port import GemPort
 from twisted.internet.defer import inlineCallbacks, returnValue, succeed
-from omci.omci_me import GemPortNetworkCtpFrame
+from voltha.extensions.omci.omci_me import GemPortNetworkCtpFrame, GemInterworkingTpFrame
 
 
 class OnuGemPort(GemPort):
     """
     Adtran ONU specific implementation
     """
-    def __init__(self, gem_id, alloc_id,
+    def __init__(self, gem_id, alloc_id, entity_id,
                  encryption=False,
                  omci_transport=False,
                  multicast=False,
                  tcont_ref=None,
                  traffic_class=None,
                  intf_ref=None,
+                 untagged=False,
                  exception=False,  # FIXED_ONU
                  name=None,
                  handler=None,
@@ -41,13 +42,19 @@
                                          tcont_ref=tcont_ref,
                                          traffic_class=traffic_class,
                                          intf_ref=intf_ref,
+                                         untagged=untagged,
                                          exception=exception,
                                          name=name,
                                          handler=handler)
         self._is_mock = is_mock
+        self._entity_id = entity_id
         self.log = structlog.get_logger(device_id=handler.device_id, gem_id=gem_id)
 
     @property
+    def entity_id(self):
+        return self._entity_id
+
+    @property
     def encryption(self):
         return self._encryption
 
@@ -57,102 +64,102 @@
 
         if self._encryption != value:
             self._encryption = value
-            omci = None     # TODO: Get from handler
 
     @staticmethod
-    def create(handler, gem_port, is_mock=False):
+    def create(handler, gem_port, entity_id, is_mock=False):
+
         return OnuGemPort(gem_port['gemport-id'],
                           None,
+                          entity_id,
                           encryption=gem_port['encryption'],  # aes_indicator,
                           tcont_ref=gem_port['tcont-ref'],
                           name=gem_port['name'],
                           traffic_class=gem_port['traffic-class'],
                           handler=handler,
+                          untagged='untagged' in gem_port['name'].lower(),
                           is_mock=is_mock)
 
     @inlineCallbacks
-    def add_to_hardware(self, omci):
+    def add_to_hardware(self, omci,
+                        tcont_entity_id,
+                        ieee_mapper_service_profile_entity_id,
+                        gal_enet_profile_entity_id):
+        self.log.debug('add-to-hardware', gem_id=self.gem_id,
+                       tcont_entity_id=tcont_entity_id,
+                       ieee_mapper_service_profile_entity_id=ieee_mapper_service_profile_entity_id,
+                       gal_enet_profile_entity_id=gal_enet_profile_entity_id)
         if self._is_mock:
             returnValue('mock')
 
-        omci = self._handler.omci
-        tcont = self.tcont
-        assert omci is not None, 'No OMCI engine'
-        assert tcont is not None, 'No TCONT'
-        assert tcont.entity_id == 0x8001, 'Hardcoded Entity ID NOT FOUND'
-
         try:
             direction = "downstream" if self.multicast else "bi-directional"
             assert not self.multicast, 'MCAST is not supported yet'
 
-            # TODO: For TCONT ID, get the TCONT's entity ID that you programmed
-            # TODO: For TM, is this the entity ID for a traffic descriptor?
-            # results = yield omci.send_create_gem_port_network_ctp(self.gem_id,      # Entity ID
-            #                                                       self.gem_id,      # Port ID
-            #                                                       tcont.entity_id,  # TCONT ID
-            #                                                       direction,        # Direction
-            #                                                       0x100)            # TM
-            results = None
-            # results = yield omci.send(GemPortNetworkCtpFrame(self.gem_id,      # Entity ID
-            #                                                  self.gem_id,      # Port ID
-            #                                                  tcont.entity_id,  # TCONT ID
-            #                                                  direction,        # Direction
-            #                                                  0x100).create()   # TM
+            frame = GemPortNetworkCtpFrame(
+                    self.entity_id,          # same entity id as GEM port
+                    port_id=self.gem_id,
+                    tcont_id=tcont_entity_id,
+                    direction=direction,
+                    upstream_tm=0x8000         # TM ID, 32768 unique ID set in TD set  TODO: Parameterize
+            ).create()
+            results = yield omci.send(frame)
+
+            status = results.fields['omci_message'].fields['success_code']
+            error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
+            self.log.debug('create-gem-port-network-ctp', status=status, error_mask=error_mask)
 
         except Exception as e:
             self.log.exception('gemport-create', e=e)
             raise
 
         try:
-            # GEM Interworking config
-            # TODO: For service mapper ID, always hardcoded or does it come from somewhere else
-            #       It is probably the TCONT entity ID
-            results = None
-            # results = yield omci.send_create_gem_inteworking_tp(self.gem_id,      # Entity ID
-            #                                                     self.gem_id,      # GEMPort NET CTP ID
-            #                                                     tcont.entity_id)  # Service Mapper Profile ID
+            frame = GemInterworkingTpFrame(
+                self.entity_id,          # same entity id as GEM port
+                gem_port_network_ctp_pointer=self.entity_id,
+                interworking_option=5,                             # IEEE 802.1
+                service_profile_pointer=ieee_mapper_service_profile_entity_id,
+                interworking_tp_pointer=0x0,
+                pptp_counter=1,
+                gal_profile_pointer=gal_enet_profile_entity_id
+            ).create()
+            results = yield omci.send(frame)
+
+            status = results.fields['omci_message'].fields['success_code']
+            error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
+            self.log.debug('create-gem-interworking-tp', status=status, error_mask=error_mask)
+
         except Exception as e:
             self.log.exception('interworking-create', e=e)
             raise
 
-        try:
-            # Mapper Service Profile config
-            # TODO: All p-bits currently go to the one and only GEMPORT ID for now
-            # TODO: The entity ID is probably the TCONT entity ID
-            results = None
-            # results = omci.send_set_8021p_mapper_service_profile(tcont.entity_id,  # Entity ID
-            #                                                      self.gem_id)      # Interworking TP ID
-        except Exception as e:
-            self.log.exception('mapper-set', e=e)
-            raise
-
         returnValue(results)
 
     @inlineCallbacks
     def remove_from_hardware(self, omci):
+        self.log.debug('remove-from-hardware',  gem_id=self.gem_id)
         if self._is_mock:
             returnValue('mock')
 
-        omci = self._handler.omci
-        assert omci is not None, 'No OMCI engine'
+        try:
+            frame = GemInterworkingTpFrame(self.entity_id).delete()
+            results = yield omci.send(frame)
 
-        results = succeed('TODO: Implement me')
+            status = results.fields['omci_message'].fields['success_code']
+            self.log.debug('delete-gem-interworking-tp', status=status)
 
-        # uri = AdtranOltHandler.GPON_GEM_CONFIG_URI.format(pon_id, onu_id, self.gem_id)
-        # name = 'gem-port-delete-{}-{}: {}'.format(pon_id, onu_id, self.gem_id)
-        # return session.request('DELETE', uri, name=name)
+        except Exception as e:
+            self.log.exception('interworking-delete', e=e)
+            raise
+
+        try:
+            frame = GemPortNetworkCtpFrame(self.entity_id).delete()
+            results = yield omci.send(frame)
+
+            status = results.fields['omci_message'].fields['success_code']
+            self.log.debug('delete-gem-port-network-ctp', status=status)
+
+        except Exception as e:
+            self.log.exception('gemport-delete', e=e)
+            raise
+
         returnValue(results)
-
-    def set_config(self, omci, value, leaf):
-        if self._is_mock:
-            return
-
-        # from ..adtran_olt_handler import AdtranOltHandler
-        #
-        # data = json.dumps({leaf: value})
-        # uri = AdtranOltHandler.GPON_GEM_CONFIG_URI.format(self.pon_id,
-        #                                                   self.onu_id,
-        #                                                   self.gem_id)
-        # name = 'onu-set-config-{}-{}-{}'.format(self._pon_id, leaf, str(value))
-        # return session.request('PATCH', uri, data=data, name=name)
-        pass # TODO: Implement me
diff --git a/voltha/adapters/adtran_onu/onu_tcont.py b/voltha/adapters/adtran_onu/onu_tcont.py
index 3d3e2bf..e926081 100644
--- a/voltha/adapters/adtran_onu/onu_tcont.py
+++ b/voltha/adapters/adtran_onu/onu_tcont.py
@@ -17,20 +17,20 @@
 
 from voltha.adapters.adtran_olt.xpon.tcont import TCont
 from voltha.adapters.adtran_olt.xpon.traffic_descriptor import TrafficDescriptor
-from omci.omci_me import TcontFrame
+from voltha.extensions.omci.omci_me import TcontFrame
 
 
 class OnuTCont(TCont):
     """
     Adtran ONU specific implementation
     """
-    def __init__(self, handler, alloc_id, traffic_descriptor, entity_id,
+    def __init__(self, handler, alloc_id, traffic_descriptor,
                  name=None, vont_ani=None, is_mock=False):
         super(OnuTCont, self).__init__(alloc_id, traffic_descriptor,
                                        name=name, vont_ani=vont_ani)
         self._handler = handler
         self._is_mock = is_mock
-        self._entity_id = entity_id
+        self._entity_id = None
         self.log = structlog.get_logger(device_id=handler.device_id, alloc_id=alloc_id)
 
     @property
@@ -42,33 +42,31 @@
         assert isinstance(tcont, dict), 'TCONT should be a dictionary'
         assert isinstance(td, TrafficDescriptor), 'Invalid Traffic Descriptor data type'
 
-        # TODO: Pass in a unique TCONT Entity ID from the ONU's PON Object
-        entity_id = 0x8001
-
         return OnuTCont(handler,
                         tcont['alloc-id'],
                         td,
-                        entity_id,
                         name=tcont['name'],
                         vont_ani=tcont['vont-ani'],
                         is_mock=is_mock)
 
     @inlineCallbacks
-    def add_to_hardware(self, omci):
+    def add_to_hardware(self, omci, tcont_entity_id):
+        self.log.debug('add-to-hardware', tcont_entity_id=tcont_entity_id)
+
+        self._entity_id = tcont_entity_id
         if self._is_mock:
             returnValue('mock')
 
         try:
-            # TODO: What is a valid Entity ID (compute and save if needed)
-            #
-            # NOTE: Entity ID should be computed. For NGPON2, they were starting
-            #       at 256 and incrementing.
-            results = None
-            # results = yield self._handler.omci.send_set_tcont(self._entity_id,  # Entity ID
-            #                                                   self.alloc_id)    # Alloc ID
+            frame = TcontFrame(self.entity_id, self.alloc_id).set()
+            results = yield omci.send(frame)
 
-            # response = yield omci.send(TcontFrame(self._entity_id,
-            #                                       alloc_id=self.alloc_id).get())
+            status = results.fields['omci_message'].fields['success_code']
+            failed_attributes_mask = results.fields['omci_message'].fields['failed_attributes_mask']
+            unsupported_attributes_mask = results.fields['omci_message'].fields['unsupported_attributes_mask']
+            self.log.debug('set-tcont', status=status,
+                           failed_attributes_mask=failed_attributes_mask,
+                           unsupported_attributes_mask=unsupported_attributes_mask)
 
         except Exception as e:
             self.log.exception('tcont-set', e=e)
@@ -78,20 +76,20 @@
 
     @inlineCallbacks
     def remove_from_hardware(self, omci):
+        self.log.debug('remove-from-hardware', tcont_entity_id=self.entity_id)
         if self._is_mock:
             returnValue('mock')
 
-        results = None
-        # results = yield omci.send(TcontFrame(self._entity_id).delete())
+        # Release tcont by setting alloc_id=0xFFFF
+        try:
+            frame = TcontFrame(self.entity_id, 0xFFFF).set()
+            results = yield omci.send(frame)
+
+            status = results.fields['omci_message'].fields['success_code']
+            self.log.debug('delete-tcont', status=status)
+
+        except Exception as e:
+            self.log.exception('tcont-delete', e=e)
+            raise
+
         returnValue(results)
-
-
-
-
-
-
-
-
-
-
-
diff --git a/voltha/adapters/adtran_onu/pon_port.py b/voltha/adapters/adtran_onu/pon_port.py
index b9c82ba..5cc8ff9 100644
--- a/voltha/adapters/adtran_onu/pon_port.py
+++ b/voltha/adapters/adtran_onu/pon_port.py
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 import structlog
-from twisted.internet.defer import inlineCallbacks, returnValue, succeed, TimeoutError
+from twisted.internet.defer import inlineCallbacks, returnValue, TimeoutError
 from twisted.internet import reactor
 
 from voltha.protos.common_pb2 import AdminState
@@ -21,38 +21,31 @@
 
 from voltha.protos.common_pb2 import OperStatus, ConnectStatus
 
-from omci.omci_me import *
-from omci.deprecated import *       # TODO: Remove this once OMCI_CC and ME_Frame refactoring is complete
-
-###################################################################################
-#
-# TODO: Notes -> This version is the fifth attempt. All calls converted with the
-#                exception of the mib-reset and upload.
-#
-#                Saving this off before moving things around.
-#
-#
-###################################################################################
-
+from omci.omci_entities import onu_custom_me_entities
+from voltha.extensions.omci.omci_me import *
 
 _STARTUP_RETRY_WAIT = 5
-BRDCM_DEFAULT_VLAN = 4091       # TODO: Deprecate later...
-
 # abbreviations
 OP = EntityOperations
 
 
 class PonPort(object):
     """Wraps northbound-port / vlan bridge support for ONU"""
+    MIN_GEM_ENTITY_ID = 0x4900
+    MAX_GEM_ENTITY_ID = 0x4AFF
 
     def __init__(self, handler, port_no):
         self._enabled = False
         self._valid = True
         self._handler = handler
         self._deferred = None
+        self._resync_deferred = None    # For TCont/GEM use
         self._port = None
         self._port_number = port_no
+        self._connected = False
+        self._dev_info_loaded = False
         self._bridge_initialized = False
+        self._next_entity_id = PonPort.MIN_GEM_ENTITY_ID
         self.log = structlog.get_logger(device_id=handler.device_id, port_no=port_no)
 
         self._admin_state = AdminState.ENABLED
@@ -60,13 +53,14 @@
 
         self._gem_ports = {}                           # gem-id -> GemPort
         self._tconts = {}                              # alloc-id -> TCont
+        self._in_sync_subscription = None
+        self._connectivity_subscription = None
 
-        # TODO: Until we have an external database, just save it here
-        self.mib_data_store = dict()  # TODO: Improve and make class attribute/property
+        self._onu_omci_device = handler.omci_agent.add_device(handler.device_id,
+                                                              handler.adapter_agent,
+                                                              onu_custom_me_entities())
         # TODO: Add stats, alarm reference, ...
 
-        pass
-
     def __str__(self):
         return "PonPort"      # TODO: Encode current state
 
@@ -82,16 +76,24 @@
         self._oper_status = OperStatus.ACTIVE
         self._update_adapter_agent()
 
-        # Begin ONU Activation sequence
-        self._deferred = reactor.callLater(_STARTUP_RETRY_WAIT,
-                                           self._initial_message_exchange)
-        # TODO: start h/w sync
-        pass
+        # Subscriber to events of interest in OpenOMCI
+        self._subscribe_to_events()
+        self._onu_omci_device.start()
+
+        # Begin ONU Activation sequence if already in sync
+        if self._onu_omci_device.mib_db_in_sync:
+            self._deferred = reactor.callLater(0, self._mib_in_sync)
+        else:
+            device = self._handler.adapter_agent.get_device(self._handler.device_id)
+            device.reason = 'Waiting for MIB upload completion'
+            self._handler.adapter_agent.update_device(device)
 
     def _stop(self):
         self._cancel_deferred()
+        # Unsubscribe to OpenOMCI Events
+        self._unsubscribe_to_events()
+        self._onu_omci_device.stop()
 
-        self._bridge_initialized = False
         self._admin_state = AdminState.DISABLED
         self._oper_status = OperStatus.UNKNOWN
         self._update_adapter_agent()
@@ -99,8 +101,18 @@
         pass
 
     def _cancel_deferred(self):
-        d, self._deferred = self._deferred, None
+        d1, self._deferred = self._deferred, None
+        d2, self._resync_deferred = self._resync_deferred, None
 
+        for d in [d1, d2]:
+            try:
+                if d is not None and not d.called:
+                    d.cancel()
+            except:
+                pass
+
+    def _cancel_resync_deferred(self):
+        d, self._resync_deferred = self._resync_deferred, None
         try:
             if d is not None and not d.called:
                 d.cancel()
@@ -128,13 +140,23 @@
                 self._stop()
 
     @property
-    def bridge_initialized(self):
-        return self._bridge_initialized
+    def connected(self):
+        return self._connected
 
     @property
     def port_number(self):
             return self._port_number
 
+    @property
+    def next_gem_entity_id(self):
+        entity_id = self._next_entity_id
+
+        self._next_entity_id = self._next_entity_id + 1
+        if self._next_entity_id > PonPort.MAX_GEM_ENTITY_ID:
+            self._next_entity_id = PonPort.MIN_GEM_ENTITY_ID
+
+        return entity_id
+
     def get_port(self):
         """
         Get the VOLTHA PORT object for this port
@@ -157,778 +179,477 @@
         # self.adapter_agent.update_port(self.olt.device_id, self.get_port())
         pass
 
-    @inlineCallbacks
-    def _initial_message_exchange(self):
-        """
-        Perform a MIB Reset and then collect some basic (read-only) attributes.
-        Upon success, begin MIB upload sequence
-        """
-        self.log.info('initial-message-exchange')
-        self._deferred = None
+    @property
+    def onu_omci_device(self):
+        return self._onu_omci_device
 
-        if self._handler.device_id is None or not self.enabled:
-            returnValue(succeed('deleted'))
+    def _mib_in_sync(self):
+        if self._handler.is_mock:
+            return  # Done, Mock has no bridge support
 
-        elif not self.enabled:
-            # Wait until enabled
-            returnValue('not-enabled')
+        if not self._dev_info_loaded:
+            # Here if in sync. But verify first
 
-        omci = self._handler.omci
-
-        try:
-            # reset incoming message queue
-            omci.flush()
-
-            ####################################################
-            # Start by getting some useful device information
+            omci = self._onu_omci_device
+            in_sync = omci.mib_db_in_sync
+            self.log.info('mib-in-sync', in_sync=in_sync, already_loaded=self._dev_info_loaded)
 
             device = self._handler.adapter_agent.get_device(self._handler.device_id)
-            device.oper_status = OperStatus.ACTIVATING
-            device.connect_status = ConnectStatus.UNREACHABLE
-            device.reason = 'Initial OMCI message exchange in progress'
-
-        except Exception as e:
-            self.log.exception('top-of-msg-exch', e=e)
-            device = None
-
-        if device is None:
-            # Wait until enabled
-            returnValue('no-device')
-
-        try:
-            # Note: May timeout to ONU not fully discovered (can happen in xPON case)
-            # or other errors.
-            # Decode fields in response and update device info
-
-            response = yield omci.send(OntGFrame('vendor_id').get())
-            # TODO: Get status for this and others below before getting other values...
-            omci_response = response.getfieldval("omci_message")
-            data = omci_response.getfieldval("data")
-            vendor = data["vendor_id"]
-            assert vendor == 'ADTN', \
-                "Invalid Device/Wrong device adapter assigned: '{}'".format(vendor)
-
-            # TODO: Get serial number and validate!
-
-            # Mark as reachable if at least first message gets through
-            device.connect_status = ConnectStatus.REACHABLE
-            self._handler.adapter_agent.update_device(device)
-
-            response = yield omci.send(CardholderFrame(True, 1,
-                                                       'actual_plugin_unit_type').get())
-
-            omci_response = response.getfieldval("omci_message")
-            data = omci_response.getfieldval("data")
-            # device.type = str(data["actual_plugin_unit_type"])
-
-            response = yield omci.send(CircuitPackFrame(257, 'number_of_ports').get())
-
-            omci_response = response.getfieldval("omci_message")
-            data = omci_response.getfieldval("data")
-            num_ports = data["number_of_ports"]
-            assert num_ports == 1, 'Invalid number of ports: {}'.format(num_ports)
-
-            response = yield omci.send(IpHostConfigDataFrame(515, 'mac_address').get())
-
-            omci_response = response.getfieldval("omci_message")
-            data = omci_response.getfieldval("data")
-            device.mac_address = str(data["mac_address"])
-
-            response = yield omci.send(Ont2GFrame('equipment_id').get())
-
-            omci_response = response.getfieldval("omci_message")
-            data = omci_response.getfieldval("data")
-            eqptId_bootVersion = str(data["equipment_id"])
-            eqptId = eqptId_bootVersion[0:10]          # ie) BVMDZ10DRA
-            bootVersion = eqptId_bootVersion[12:20]    # ie) CML.D55~
-
-            # response = yield omci.send_get_Ont2G('omcc_version', 0)
-            response = yield omci.send(Ont2GFrame('omcc_version').get())
-
-            omci_response = response.getfieldval("omci_message")
-            data = omci_response.getfieldval("data")
-            # decimal version
-            omciVersion = str(data["omcc_version"])
-
-            response = yield omci.send(Ont2GFrame('vendor_product_code').get())
-
-            omci_response = response.getfieldval("omci_message")
-            data = omci_response.getfieldval("data")
-            # decimal value
-            vendorProductCode = str(data["vendor_product_code"])
-
-            response = yield omci.send(OntGFrame('version').get())
-
-            omci_response = response.getfieldval("omci_message")
-            data = omci_response.getfieldval("data")
-            device.model = str(data["version"])             # such as 1287800F1
-
-            # TODO: Combine ONTG calls into a single call with multiple attributes
-            # TODO: Combine ONT2G calls into a single call with multiple attributes
-
-            # TODO: Look into ONTG and ONT2G to see if we can get other items of interest
-            #       such as max tconts, max gem ports, and so on. Make use of them
-
-            # Possibility of bug in ONT Firmware. uncomment this code after it is fixed.
-            # response = yield omci.send_get_SoftwareImage('version', 0)
-            #
-            # omci_response = response.getfieldval("omci_message")
-            # data = omci_response.getfieldval("data")
-            # device.firmware_version = str(data["version"])
-            # is_committed = data["is_committed"]
-            # is_active = data["is_active"]
-            # is_valid = data["is_valid"]
-
-            # TODO: May have some issue with the next one...
-            # response = yield omci.send_set_adminState(257)
-
-            # device.hardware_version = 'TODO: to be filled'
-            # TODO: Support more versions as needed
-            # images = Image(version=results.get('software_version', 'unknown'))
-            # device.images.image.extend([images])
-
-            # self.adapter_agent.update_device(device)
             device.oper_status = OperStatus.ACTIVE
             device.connect_status = ConnectStatus.REACHABLE
-            device.reason = 'Initial OMCI message exchange complete'
+            device.reason = 'MIB Synchronization complete'
             self._handler.adapter_agent.update_device(device)
 
-            # Start MIB synchronization
-            self._deferred = reactor.callLater(0, self._perform_mib_upload)
-            self.log.info('onu-activated')
+            # In Sync, we can register logical ports now. Ideally this could occur on
+            # the first time we received a successful (no timeout) OMCI Rx response.
+            try:
+                for uni in self._handler.uni_ports:
+                    uni.add_logical_port(None, None)
 
-        # These exceptions are not recoverable
-        except (TypeError, ValueError) as e:
-            self.log.exception('Failed', e=e)
-            device.oper_status = OperStatus.FAILED
-            device.reason = 'Initial message sequence failure: ' + e.message
-            self._handler.adapter_agent.update_device(device)
+                vendor = omci.query_mib_single_attribute(OntG.class_id, 0, 'vendor_id') or 'ADTN'
+                assert vendor == 'ADTN', \
+                    "Invalid Device/Wrong device adapter assigned: '{}'".format(vendor)
 
-        except TimeoutError as e:
-            self.log.debug('Failed', e=e)
-            self._handler.adapter_agent.update_device(device)
-            # Try again later. May not have been discovered
-            self._deferred = reactor.callLater(_STARTUP_RETRY_WAIT,
-                                               self._initial_message_exchange)
+                # TODO: Get serial number and validate!
+                num_ports = omci.query_mib_single_attribute(CircuitPack.class_id,
+                                                            257, 'number_of_ports') or 1
+                assert num_ports == 1, 'Invalid number of ports: {}'.format(num_ports)
 
-        except Exception as e:
-            self.log.exception('Failed', e=e)
-            device.reason = 'Initial message sequence failure: ' + e.message
-            self._handler.adapter_agent.update_device(device)
-            # Try again later. May not have been discovered
-            self._deferred = reactor.callLater(_STARTUP_RETRY_WAIT,
-                                               self._initial_message_exchange)
+                mac_address = omci.query_mib_single_attribute(IpHostConfigData.class_id,
+                                                              0, 'mac_address') or 'unknown'
+                device.mac_address = str(mac_address)
+
+                ont2_attributes = omci.query_mib(Ont2G.class_id, 0, ['equipment_id',
+                                                                     'omcc_version',
+                                                                     'vendor_product_code'])
+                equipment_id = ont2_attributes.get('equipment_id') or " unknown    unknown "
+                eqptId_bootVersion = str(equipment_id)
+                eqptId = eqptId_bootVersion[0:10]          # ie) BVMDZ10DRA
+                bootVersion = eqptId_bootVersion[12:20]    # ie) CML.D55~
+
+                omcc_version = str(ont2_attributes.get('omcc_version', 'unknown'))
+                vendorProductCode = str(ont2_attributes.get('vendor_product_code', 'unknown'))
+
+                version = omci.query_mib_single_attribute(OntG.class_id, 0, 'version') or 'unknown'
+                device.model = str(version)
+                # # TODO: Combine ONTG calls into a single call with multiple attributes
+                # # TODO: Look into ONTG and ONT2G to see if we can get other items of interest
+                # #       such as max tconts, max gem ports, and so on. Make use of them
+
+                sw_version = omci.query_mib_single_attribute(SoftwareImage.class_id, 0, 'version') or 'unknown'
+                device.firmware_version = str(sw_version)
+                # # is_committed = data["is_committed"]
+                # # is_active = data["is_active"]
+                # # is_valid = data["is_valid"]
+                # # device.hardware_version = 'TODO: to be filled'
+                # # TODO: Support more versions as needed
+                # # images = Image(version=results.get('software_version', 'unknown'))
+                # # device.images.image.extend([images])
+
+                self._handler.adapter_agent.update_device(device)
+                self._dev_info_loaded = True
+
+            except Exception as e:
+                self.log.exception('device-info-load', e=e)
+                self._deferred = reactor.callLater(_STARTUP_RETRY_WAIT, self._mib_in_sync())
+
+            self._deferred = reactor.callLater(0, self.resync_omci_settings)
 
     @inlineCallbacks
-    def _perform_mib_upload(self):
-        """
-        Called after basic OMCI MIB RESET message startup/exchange.
+    def resync_omci_settings(self):
+        self._cancel_resync_deferred()
 
-        Upon successful completion, proceed to establish a few basic structures
-        that we know will be required.  Once OpenOMCI is created, this sequence
-        should be skipped (go directly to MIB upload) and this info is available
-        from the uploaded MIB.
-
-        On failure, restart the initial message exchange
-        """
-        self.log.info('perform-mib-upload')
-        self._deferred = None
-
-        if self._handler.device_id is None or not self.enabled:
-            returnValue('not-enabled')
-
-        device = None
-        seq_no = 0
-        number_of_commands = 0
-        omci = self._handler.omci
-
-        if self._handler.is_mock:
-            self._deferred = reactor.callLater(0, self._perform_mib_download)
-            returnValue('is-mock')
-
-        try:
+        if not self._bridge_initialized:
+            self.log.info('resync-omci-settings', initialized=self._bridge_initialized)
             device = self._handler.adapter_agent.get_device(self._handler.device_id)
-            device.reason = 'Performing MIB Synchronization'
+
+            if not self.enabled or device is None:
+                returnValue('not-enabled')
+
+            device.reason = 'Performing OMCI Setup'
             self._handler.adapter_agent.update_device(device)
 
-            #########################################
-            # MIB Reset
-            results = yield omci.send_mib_reset()
-            status = results.fields['omci_message'].fields['success_code']
-            assert status == 0, 'Unexpected MIB reset response status: {}'.format(status)
-            # TODO: On a real system, need to flush the external MIB database
-            # TODO: Also would need to watch for any AVC being handled between the MIB reset and the DB flush
-            self.mib_data_store = dict()
+            omci = self._handler.omci
 
-            ########################################
-            # Begin MIB Upload
-            results = yield omci.send_mib_upload()
-            number_of_commands = results.fields['omci_message'].fields['number_of_commands']
+            #############################################
+            #  All our variables here
+            #  TODO: Move elsewhere in future version of this software
+            #  TODO: Make as many entity IDs dynamic/discovered as possible
+            frame = None
+            gal_enet_profile_entity_id = 0x100
+            ieee_mapper_service_profile_entity_id = 0x100
+            mac_bridge_service_profile_entity_id = 0x100
+            mac_bridge_port_ani_entity_id = 0x100
+            ethernet_uni_entity_id = 0x101
+            vlan_tcis_1 = 0x900
+            vlan_config_entity_id = vlan_tcis_1
+            cvid = device.vlan
 
-            for seq_no in xrange(number_of_commands):
-                results = yield omci.send_mib_upload_next(seq_no)
+            try:
+                ################################################################################
+                # TCONTS
+                # get tconts in database
+                omci_dev = self._onu_omci_device
+                tcont_idents = omci_dev.query_mib(Tcont.class_id)
+                self.log.debug('tcont-idents', tcont_idents=tcont_idents)
 
-                object_entity_class = results.fields['omci_message'].fields['object_entity_class']
-                object_entity_id = results.fields['omci_message'].fields['object_entity_id']
-                object_attributes_mask = results.fields['omci_message'].fields['object_attributes_mask']
-                object_data = results.fields['omci_message'].fields['object_data']
+                for tcont in self._tconts.itervalues():
+                    free_entity_id = next((k for k, v in tcont_idents.items()
+                                          if isinstance(k, int) and v.get('alloc_id', 0) == 0xFFFF), None)
+                    if free_entity_id is None:
+                        self.log.error('no-available-tconts')
+                        break
+                    results = yield tcont.add_to_hardware(omci, free_entity_id)
 
-                key = (object_entity_class, object_entity_id)
+                ################################################################################
+                # GEMS
+                for gem_port in self._gem_ports.itervalues():
+                    tcont = gem_port.tcont
+                    if tcont is None:
+                        self.log.error('unknown-tcont-reference', gem_id=gem_port.gem_id)
+                        continue
 
-                if key not in self.mib_data_store:
-                    self.mib_data_store[key] = (object_attributes_mask, object_data)
-                else:
-                    pass
+                    results = yield gem_port.add_to_hardware(omci,
+                                                             tcont.entity_id,
+                                                             ieee_mapper_service_profile_entity_id,
+                                                             gal_enet_profile_entity_id)
 
-            # Successful if here
-            device.reason = 'MIB Synchronization Complete'
-            self._handler.adapter_agent.update_device(device)
+                ########################################################################################
+                # Create GalEthernetProfile - Once per ONU/PON interface
+                #
+                #  EntityID will be referenced by:
+                #            - GEM Interworking TPs when a new GEM Port is created
+                #  References:
+                #            - Nothing
 
-            # Start up non-critical message exchange
-            self._deferred = reactor.callLater(0, self._perform_mib_download)
-            self.log.info('mib-synchronized')
+                frame = GalEthernetProfileFrame(gal_enet_profile_entity_id,
+                                                max_gem_payload_size=1518).create()  # Max GEM Payload size
+                results = yield omci.send(frame)
 
-        except TimeoutError as e:
-            self.log.warn('mib-upload', e=e, seq_no=seq_no, number_of_commands=number_of_commands)
+                status = results.fields['omci_message'].fields['success_code']
+                error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
+                self.log.debug('create-gal-ethernet-profile', status=status, error_mask=error_mask)
 
-            if device is not None:
-                device.reason = 'mib-upload-failure: Response Timeout'
+                ################################################################################
+                # MAC Bridge Service Profile - Once per UNI
+                #
+                #  EntityID will be referenced by:
+                #            - MAC Bridge Port Configuration Data
+                #  References:
+                #            - Nothing
+
+                attributes = {
+                    'spanning_tree_ind': False,
+                    #  TODO: CB: see if we need or can use any of the following...
+                    # 'learning_ind': True,
+                    # 'priority': 0x8000,
+                    # 'max_age': 20 * 256,
+                    # 'hello_time': 2 * 256,
+                    # 'forward_delay': 15 * 256,
+                    # 'unknown_mac_address_discard': True
+                }
+                frame = MacBridgeServiceProfileFrame(mac_bridge_service_profile_entity_id,
+                                                     attributes).create()
+                results = yield omci.send(frame)
+
+                status = results.fields['omci_message'].fields['success_code']
+                error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
+                self.log.debug('create-mac-bridge-service-profile', status=status, error_mask=error_mask)
+
+                ################################################################################
+                # IEEE 802.1 Mapper Service config - Once per PON
+                #
+                #  EntityID will be referenced by:
+                #            - MAC Bridge Port Configuration Data for the PON port
+                #  References:
+                #            - Nothing at this point. When a GEM port is created, this entity will
+                #              be updated to reference the GEM Interworking TP
+
+                frame = Ieee8021pMapperServiceProfileFrame(ieee_mapper_service_profile_entity_id).create()
+                results = yield omci.send(frame)
+
+                status = results.fields['omci_message'].fields['success_code']
+                error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
+                self.log.debug('create-8021p-mapper-service-profile', status=status, error_mask=error_mask)
+
+                ################################################################################
+                # Create MAC Bridge Port Configuration Data for the PON port via IEEE 802.1
+                # mapper service. Upon receipt by the ONU, the ONU will create an instance
+                # of the following before returning the response.
+                #
+                #     - MAC bridge port designation data
+                #     - MAC bridge port filter table data
+                #     - MAC bridge port bridge table data
+                #
+                #  EntityID will be referenced by:
+                #            - Implicitly by the VLAN tagging filter data
+                #            -
+                #            -
+                #            -
+                #  References:
+                #            - MAC Bridge Service Profile (the bridge)
+                #            - IEEE 802.1p mapper service profile for PON port
+
+                frame = MacBridgePortConfigurationDataFrame(
+                    mac_bridge_port_ani_entity_id,                           # Entity ID
+                    bridge_id_pointer=mac_bridge_service_profile_entity_id,  # Bridge Entity ID BP: oldvalue 0x201
+                    # TODO: The PORT number for this port and the UNI port are the same. Is this correct?
+                    port_num=0,                                              # Port ID          BP: oldvalue 2
+                    tp_type=3,                                               # TP Type (IEEE 802.1p mapper service)  BP: oldvalue 1, 802.1 mapper GPON intf
+                    tp_pointer=ieee_mapper_service_profile_entity_id         # TP ID, 8021p mapper ID   BP: oldvalue 0x102
+                ).create()
+                results = yield omci.send(frame)
+
+                status = results.fields['omci_message'].fields['success_code']
+                error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
+                self.log.debug('create-mac-bridge-port-configuration-data-part-1', status=status, error_mask=error_mask)
+
+                ################################################################################
+                # MAC Bridge Port config
+                # This configuration is for Ethernet UNI
+                #
+                #  EntityID will be referenced by:
+                #            -
+                #            -
+                #            -
+                #            -
+                #  References:
+                #            - MAC Bridge Service Profile (the bridge)
+                #            - PPTP Ethernet UNI
+
+                frame = MacBridgePortConfigurationDataFrame(
+                    0x000,                             # Entity ID                BP: oldvalue 0x201
+                    bridge_id_pointer=mac_bridge_service_profile_entity_id,  # Bridge Entity ID BP: oldvalue 0x201
+                    port_num=0,                        # Port ID                  BP: oldvalue 3
+                    tp_type=1,                         # PPTP Ethernet UNI        BP: oldvalue 3
+                    tp_pointer=ethernet_uni_entity_id  # TP ID, 8021p mapper Id   BP: oldvalue 0x8001
+                ).create()
+                results = yield omci.send(frame)
+
+                status = results.fields['omci_message'].fields['success_code']
+                error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
+                self.log.debug('create-mac-bridge-port-configuration-data-part-2', status=status, error_mask=error_mask)
+
+                ################################################################################
+                # VLAN Tagging Filter config
+                #
+                #  EntityID will be referenced by:
+                #            - Nothing
+                #  References:
+                #            - Implicitly linked to an instance of the MAC bridge port configuration data
+                #              for the PON port
+                # TODO: Probably need to get VLAN ID from device.vlan
+                # Set anything, this request will not be used when using Extended Vlan
+
+                frame = VlanTaggingFilterDataFrame(
+                    mac_bridge_port_ani_entity_id,       # Entity ID   BP: Oldvalue 0x2102
+                    vlan_tcis=[vlan_tcis_1],             # VLAN IDs     BP: cvid
+                    forward_operation=0x10
+                ).create()
+                results = yield omci.send(frame)
+
+                status = results.fields['omci_message'].fields['success_code']
+                error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
+                self.log.debug('create-vlan-tagging-filter-data', status=status, error_mask=error_mask)
+
+                ################################################################################
+                # Update the IEEE 802.1p Mapper Service Profile config
+                #
+                #  EntityID was created prior to this call
+                #  References:
+                #            -
+                #            -
+                # TODO: All p-bits currently go to the one and only GEMPORT ID for now
+
+                gem_entity_ids = []
+                for gem_port in self._gem_ports.itervalues():
+                    gem_entity_ids.append(gem_port.entity_id)
+
+                frame = Ieee8021pMapperServiceProfileFrame(
+                    ieee_mapper_service_profile_entity_id,      # 802.1p mapper Service Mapper Profile ID
+                    interwork_tp_pointers=gem_entity_ids  # Interworking TP IDs  BP: oldvalue self.gemid
+                ).set()
+                results = yield omci.send(frame)
+
+                status = results.fields['omci_message'].fields['success_code']
+                failed_attributes_mask = results.fields['omci_message'].fields['failed_attributes_mask']
+                unsupported_attributes_mask = results.fields['omci_message'].fields['unsupported_attributes_mask']
+                self.log.debug('set-8021p-mapper-service-profile', status=status,
+                               failed_attributes_mask=failed_attributes_mask,
+                               unsupported_attributes_mask=unsupported_attributes_mask)
+
+                ################################################################################
+                #  Unlock UNI
+                #
+                #  EntityID will be referenced by:
+                #            - MAC bridge port configuration data for the UNI side
+                #  References:
+                #            - Nothing
+
+                attributes = dict(
+                    administrative_state=0  # 0 - Unlock
+                )
+                frame = PptpEthernetUniFrame(
+                    ethernet_uni_entity_id,  # Entity ID
+                    attributes=attributes    # See above
+                ).set()
+                results = yield omci.send(frame)
+
+                status = results.fields['omci_message'].fields['success_code']
+                failed_attributes_mask = results.fields['omci_message'].fields['failed_attributes_mask']
+                unsupported_attributes_mask = results.fields['omci_message'].fields['unsupported_attributes_mask']
+                self.log.debug('set-pptp-ethernet-uni', status=status,
+                               failed_attributes_mask=failed_attributes_mask,
+                               unsupported_attributes_mask=unsupported_attributes_mask)
+
+                ################################################################################
+                # Create Extended VLAN Tagging Operation config
+                #
+                #  EntityID relates to the VLAN TCIS
+                #  References:
+                #            - VLAN TCIS from previously created VLAN Tagging filter data
+                #            - PPTP Ethernet UNI
+                #
+                # TODO: add entry here for additional UNI interfaces
+
+                attributes = dict(
+                    association_type=2,                           # Assoc Type, PPTP Ethernet UNI
+                    associated_me_pointer=ethernet_uni_entity_id  # Assoc ME, PPTP Entity Id
+                )
+
+                frame = ExtendedVlanTaggingOperationConfigurationDataFrame(
+                    vlan_config_entity_id,
+                    attributes=attributes
+                ).create()
+                results = yield omci.send(frame)
+
+                status = results.fields['omci_message'].fields['success_code']
+                error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
+                self.log.debug('create-extended-vlan-tagging-operation-configuration-data', status=status, error_mask=error_mask)
+
+                ################################################################################
+                # Update Extended VLAN Tagging Operation Config Data
+                #
+                # Specifies the TPIDs in use and that operations in the downstream direction are
+                # inverse to the operations in the upstream direction
+                # TODO: Downstream mode may need to be modified once we work more on the flow rules
+
+                attributes = dict(
+                    input_tpid=0x8100,   # input TPID
+                    output_tpid=0x8100,  # output TPID
+                    downstream_mode=0,   # inverse of upstream
+                )
+                frame = ExtendedVlanTaggingOperationConfigurationDataFrame(
+                    vlan_config_entity_id,
+                    attributes=attributes
+                ).set()
+                results = yield omci.send(frame)
+
+                status = results.fields['omci_message'].fields['success_code']
+                failed_attributes_mask = results.fields['omci_message'].fields['failed_attributes_mask']
+                unsupported_attributes_mask = results.fields['omci_message'].fields['unsupported_attributes_mask']
+                self.log.debug('set-extended-vlan-tagging-operation-configuration-data', status=status,
+                               failed_attributes_mask=failed_attributes_mask,
+                               unsupported_attributes_mask=unsupported_attributes_mask)
+
+                ################################################################################
+                # Update Extended VLAN Tagging Operation Config Data
+                #
+                # parameters: Entity Id ( 0x900), Filter Inner Vlan Id(0x1000-4096,do not filter on Inner vid,
+                #             Treatment Inner Vlan Id : 2
+
+                attributes = dict(
+                    received_frame_vlan_tagging_operation_table=
+                    VlanTaggingOperation(
+                        filter_outer_priority=15,       # This entry is not a double-tag rule
+                        filter_outer_vid=4096,          # Do not filter on the outer VID value
+                        filter_outer_tpid_de=0,         # Do not filter on the outer TPID field
+
+                        filter_inner_priority=15,       # This is a no-tag rule, ignore all other VLAN tag filter fields
+                        filter_inner_vid=0x1000,        # Do not filter on the inner VID
+                        filter_inner_tpid_de=0,         # Do not filter on inner TPID field
+                        filter_ether_type=0,            # Do not filter on EtherType
+
+                        treatment_tags_to_remove=0,     # Remove 0 tags
+                        treatment_outer_priority=15,    # Do not add an outer tag
+                        treatment_outer_vid=0,          # n/a
+                        treatment_outer_tpid_de=0,      # n/a
+
+                        treatment_inner_priority=0,     # Add an inner tag and insert this value as the priority
+                        treatment_inner_vid=cvid,       # use this value as the VID in the inner VLAN tag
+                        treatment_inner_tpid_de=4       # set TPID = 0x8100
+                    )
+                )
+                frame = ExtendedVlanTaggingOperationConfigurationDataFrame(
+                    vlan_config_entity_id,    # Entity ID       BP: Oldvalue 0x202
+                    attributes=attributes     # See above
+                ).set()
+                results = yield omci.send(frame)
+
+                status = results.fields['omci_message'].fields['success_code']
+                failed_attributes_mask = results.fields['omci_message'].fields['failed_attributes_mask']
+                unsupported_attributes_mask = results.fields['omci_message'].fields['unsupported_attributes_mask']
+                self.log.debug('set-extended-vlan-tagging-operation-configuration-data-untagged', status=status,
+                               failed_attributes_mask=failed_attributes_mask,
+                               unsupported_attributes_mask=unsupported_attributes_mask)
+
+                # BP: This is for AT&T RG's
+                #
+                #   TODO: CB: NOTE: TRY THIS ONCE OTHER SEQUENCES WORK
+                #
+                # Set AR - ExtendedVlanTaggingOperationConfigData
+                #          514 - RxVlanTaggingOperationTable - add VLAN <cvid> to priority tagged pkts - c-vid
+                # results = yield omci.send_set_extended_vlan_tagging_operation_vlan_configuration_data_single_tag(
+                #                                 0x900,  # Entity ID
+                #                                 8,      # Filter Inner Priority, do not filter on Inner Priority
+                #                                 0,    # Filter Inner VID, this will be 0 in CORD
+                #                                 0,      # Filter Inner TPID DE
+                #                                 1,      # Treatment tags, number of tags to remove
+                #                                 8,      # Treatment inner priority, copy Inner Priority
+                #                                 2)   # Treatment inner VID, this will be 2 in CORD
+
+                # Set AR - ExtendedVlanTaggingOperationConfigData
+                #          514 - RxVlanTaggingOperationTable - add VLAN <cvid> to priority tagged pkts - c-vid
+                # results = yield omci.send_set_extended_vlan_tagging_operation_vlan_configuration_data_single_tag(
+                #                                 0x200,  # Entity ID
+                #                                 8,      # Filter Inner Priority
+                #                                 0,      # Filter Inner VID
+                #                                 0,      # Filter Inner TPID DE
+                #                                 1,      # Treatment tags to remove
+                #                                 8,      # Treatment inner priority
+                #                                 cvid)   # Treatment inner VID
+                #
+                # Set AR - ExtendedVlanTaggingOperationConfigData
+                #          514 - RxVlanTaggingOperationTable - add VLAN <cvid> to untagged pkts - c-vid
+                #results = yield omci.send_set_extended_vlan_tagging_operation_vlan_configuration_data_untagged(
+                #                                0x100,   # Entity ID            BP: Oldvalue 0x202
+                #                                0x1000,  # Filter Inner VID     BP: Oldvalue 0x1000
+                #                                cvid)    # Treatment inner VID  BP: cvid
+
+                # success = results.fields['omci_message'].fields['success_code'] == 0
+                # error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
+
+                ###############################################################################
+                # If here, we are done
+                self._bridge_initialized = True
+                device.reason = ''
                 self._handler.adapter_agent.update_device(device)
 
-            # Try again later
-            self._deferred = reactor.callLater(_STARTUP_RETRY_WAIT,
-                                               self._initial_message_exchange)
+            except TimeoutError as e:
+                self.log.warn('rx-timeout', frame=frame)
+                self._deferred = reactor.callLater(_STARTUP_RETRY_WAIT,
+                                                   self.resync_omci_settings)
+                returnValue('retry-pending')
 
-        except Exception as e:
-            self.log.exception('mib-upload', e=e)
-            device.reason = 'MIB upload sequence failure: ' + e.message
-            self._handler.adapter_agent.update_device(device)
+            except Exception as e:
+                self.log.exception('omci-setup', e=e)
+                device.reason = 'OMCI setup sequence failure: ' + e.message
+                self._handler.adapter_agent.update_device(device)
 
-            # Try again later
-            self._deferred = reactor.callLater(_STARTUP_RETRY_WAIT,
-                                               self._initial_message_exchange)
-
-    @inlineCallbacks
-    def _perform_mib_download(self):
-        """
-        Called after basic OMCI Synchronization (MIB upload). Begin to set up
-        some basic OMCI settings common for most expected configurations
-
-        Upon successful completion, any xPON information received so far will be
-        acted upon.
-
-        On failure, restart the initial message exchange
-        """
-        self.log.info('mib-download-start')
-        self._deferred = None
-
-        if self._handler.device_id is None or not self.enabled:
-            returnValue('not-enabled')
-
-        omci = self._handler.omci
-
-        if self._handler.is_mock:
-            self._bridge_initialized = True
-            self._deferred = reactor.callLater(0, self._sync_existing_xpon)
-            returnValue('is-mock')
-
-        # reset incoming message queue
-        omci.flush()
-        device = self._handler.adapter_agent.get_device(self._handler.device_id)
-
-        device.reason = 'Performing MIB Download'
-        self._handler.adapter_agent.update_device(device)
-
-        if not self.enabled or device is None:
-            returnValue('not-enabled')
-
-        #############################################
-        #  All our variables here
-        #  TODO: Move elsewhere in future version of this software
-        frame = None
-        gal_enet_profile_entity_id = 0x100       # Any Unique Entity ID BP: old value 1
-        ieee_mapper_service_profile_entity_id = 0x100         # Entity ID BP: old value 0x8001
-        mac_bridge_service_profile_entity_id = 0x100  # Entity ID BP: old value 0x201
-        mac_bridge_port_ani_entity_id = 0x100       # BP: oldvalue 0x201
-        ethernet_uni_entity_id = 0x101
-        vlan_tcis_1 = 0x900
-        cvid = 2            # TODO: Get from xPON and/or device adapter
-        tcont_entity_id = 0x100   # Entity ID, ONT is set to 0x100
-        tcont_alloc_id = 0x400    # Alloc ID, 1024 - Tcont
-        gem_entity_id = 0x4900          # Entity ID, unique Id
-        gem_port_id = 0x400             # Port ID, 2304 - Gem Id
-        gem_interworking_entity_id = 0x4900
-        vlan_config_entity_id = vlan_tcis_1               # Entity ID       BP: Oldvalue 0x202
-
-        try:
-            ################################################################################
-            #
-            #
-            #  EntityID will be referenced by:
-            #            -
-            #            -
-            #            -
-            #            -
-            #  References:
-            #            -
-            #            -
-
-            frame = TcontFrame(tcont_entity_id, tcont_alloc_id).set()
-            results = yield omci.send(frame)
-            # results = yield send_set_tcont(omci, 0x100,  # Entity ID, ONT is set to 0x100
-            #                                0x400)  # Alloc ID, 1024 - Tcont
-
-            status = results.fields['omci_message'].fields['success_code']
-            failed_attributes_mask = results.fields['omci_message'].fields['failed_attributes_mask']
-            unsupported_attributes_mask = results.fields['omci_message'].fields['unsupported_attributes_mask']
-            self.log.debug('set-tcont', status=status,
-                           failed_attributes_mask=failed_attributes_mask,
-                           unsupported_attributes_mask=unsupported_attributes_mask)
-
-            ################################################################################
-            direction = "bi-directional"
-
-            # TODO: For TM, is this the entity ID for a traffic descriptor?
-            frame = GemPortNetworkCtpFrame(
-                    gem_entity_id,
-                    port_id=gem_port_id,       # Port ID, 2304 - Gem ID
-                    tcont_id=tcont_entity_id,  # TCONT Entity ID, as set in TCONT set
-                    direction=direction,       # Direction, bidirectional
-                    upstream_tm=0x8000         # TM ID, 32768 unique ID set in TD set  TODO: Parameterize
-            ).create()
-            results = yield omci.send(frame)
-            # results = yield send_create_gem_port_network_ctp(omci, 0x4900,    # Entity ID, unique Id
-            #                                                  0x400,     # Port ID, 2304 - Gem Id
-            #                                                  0x100,     # TCONT Entity ID, as set in TCONT set
-            #                                                  direction, # Direction, bidirectional
-            #                                                  0x8000)    # TM ID, 32768 unique Id set in TD set
-
-            status = results.fields['omci_message'].fields['success_code']
-            error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
-            self.log.debug('create-gem-port-network-ctp', status=status, error_mask=error_mask)
-
-            ################################################################################
-            # GEM Interworking config
-            #
-            #
-            #  EntityID will be referenced by:
-            #            -
-            #            -
-            #            -
-            #            -
-            #  References:
-            #            -
-            #            -
-            # TODO: for the service_profile_pointer=0x100, is this create/set somewhere later
-
-            frame = GemInterworkingTpFrame(
-                gem_interworking_entity_id,
-                gem_port_network_ctp_pointer=gem_entity_id,  # GEMPort NET CTP ID, as set in CTP create
-                interworking_option=5,                             # IEEE 802.1
-                service_profile_pointer=ieee_mapper_service_profile_entity_id,
-                interworking_tp_pointer=0x0,
-                pptp_counter=1,
-                gal_profile_pointer=0   # TODO:  make? -> gal_enet_profile_entity_id     # BP: HACK old value 0x1  (TODO: Balaji had this set to 0 in his test sequence)
-            ).create()
-            results = yield omci.send(frame)
-            # results = yield send_create_gem_inteworking_tp(omci, 0x4900, # any Unique Entity ID
-            #                                                0x4900, # GEMPort NET CTP ID, as set in CTP create
-            #                                                0x100)  # 802.1p mapper Service Mapper Profile ID
-
-            status = results.fields['omci_message'].fields['success_code']
-            error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
-            self.log.debug('create-gem-interworking-tp', status=status, error_mask=error_mask)
-
-            ########################################################################################
-            # Create GalEthernetProfile - Once per ONU/PON interface
-            #
-            #  EntityID will be referenced by:
-            #            - GEM Interworking TPs when a new GEM Port is created
-            #  References:
-            #            - Nothing
-
-            frame = GalEthernetProfileFrame(gal_enet_profile_entity_id,
-                                            max_gem_payload_size=1518).create()  # Max GEM Payload size
-            results = yield omci.send(frame)
-            # results = yield send_create_gal_ethernet_profile(omci,
-            #                                         0x100,   # Any Unique Entity ID BP: old value 1
-            #                                         1518)    # Max GEM Payload size
-
-            status = results.fields['omci_message'].fields['success_code']
-            error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
-            self.log.debug('create-gal-ethernet-profile', status=status, error_mask=error_mask)
-
-            ################################################################################
-            # MAC Bridge Service Profile - Once per UNI
-            #
-            #  EntityID will be referenced by:
-            #            - MAC Bridge Port Configuration Data
-            #  References:
-            #            - Nothing
-
-            attributes = {
-                'spanning_tree_ind': False,
-                #  TODO: CB: see if we need or can use any of the following...
-                # 'learning_ind': True,
-                # 'priority': 0x8000,
-                # 'max_age': 20 * 256,
-                # 'hello_time': 2 * 256,
-                # 'forward_delay': 15 * 256,
-                # 'unknown_mac_address_discard': True
-            }
-            frame = MacBridgeServiceProfileFrame(mac_bridge_service_profile_entity_id,
-                                                 attributes).create()
-            results = yield omci.send(frame)
-            # results = yield send_create_mac_bridge_service_profile(omci, 0x100)   # Entity ID BP: old value 0x201
-
-            status = results.fields['omci_message'].fields['success_code']
-            error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
-            self.log.debug('create-mac-bridge-service-profile', status=status, error_mask=error_mask)
-
-            ################################################################################
-            # IEEE 802.1 Mapper Service config - Once per PON
-            #
-            #  EntityID will be referenced by:
-            #            - MAC Bridge Port Configuration Data for the PON port
-            #  References:
-            #            - Nothing at this point. When a GEM port is created, this entity will
-            #              be updated to reference the GEM Interworking TP
-
-            frame = Ieee8021pMapperServiceProfileFrame(ieee_mapper_service_profile_entity_id).create()
-            results = yield omci.send(frame)
-            # results = yield send_create_8021p_mapper_service_profile(omci, 0x100)   # Entity ID BP: old value 0x8001
-
-            status = results.fields['omci_message'].fields['success_code']
-            error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
-            self.log.debug('create-8021p-mapper-service-profile', status=status, error_mask=error_mask)
-
-            ################################################################################
-            # Create MAC Bridge Port Configuration Data for the PON port via IEEE 802.1
-            # mapper service. Upon receipt by the ONU, the ONU will create an instance
-            # of the following before returning the response.
-            #
-            #     - MAC bridge port designation data
-            #     - MAC bridge port filter table data
-            #     - MAC bridge port bridge table data
-            #
-            #  EntityID will be referenced by:
-            #            - Implicitly by the VLAN tagging filter data
-            #            -
-            #            -
-            #            -
-            #  References:
-            #            - MAC Bridge Service Profile (the bridge)
-            #            - IEEE 802.1p mapper service profile for PON port
-
-            frame = MacBridgePortConfigurationDataFrame(
-                mac_bridge_port_ani_entity_id,                           # Entity ID
-                bridge_id_pointer=mac_bridge_service_profile_entity_id,  # Bridge Entity ID BP: oldvalue 0x201
-                # TODO: The PORT number for this port and the UNI port are the same. Is this correct?
-                port_num=0,                                              # Port ID          BP: oldvalue 2
-                tp_type=3,                                               # TP Type (IEEE 802.1p mapper service)  BP: oldvalue 1, 802.1 mapper GPON intf
-                tp_pointer=ieee_mapper_service_profile_entity_id         # TP ID, 8021p mapper ID   BP: oldvalue 0x102
-            ).create()
-            results = yield omci.send(frame)
-            # results = yield send_create_mac_bridge_port_configuration_data(omci,
-            #                                 0x100,   # Entity ID   BP: oldvalue 0x201
-            #                                 0x100,   # Bridge Entity ID   BP: oldvalue 0x201
-            #                                 0,       # Port ID     BP: oldvalue 2
-            #                                 3,       # TP Type    BP: oldvalue  1, 802.1 mapper GPON interface
-            #                                 0x100)   # TP ID, 8021p mapper Id      BP: oldvalue 0x102
-
-            status = results.fields['omci_message'].fields['success_code']
-            error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
-            self.log.debug('create-mac-bridge-port-configuration-data-part-1', status=status, error_mask=error_mask)
-
-            ################################################################################
-            # MAC Bridge Port config
-            # This configuration is for Ethernet UNI
-            #
-            #  EntityID will be referenced by:
-            #            -
-            #            -
-            #            -
-            #            -
-            #  References:
-            #            - MAC Bridge Service Profile (the bridge)
-            #            - PPTP Ethernet UNI
-
-            frame = MacBridgePortConfigurationDataFrame(
-                0x000,                             # Entity ID                BP: oldvalue 0x201
-                bridge_id_pointer=mac_bridge_service_profile_entity_id,  # Bridge Entity ID BP: oldvalue 0x201
-                port_num=0,                        # Port ID                  BP: oldvalue 3
-                tp_type=1,                         # PPTP Ethernet UNI        BP: oldvalue 3
-                tp_pointer=ethernet_uni_entity_id  # TP ID, 8021p mapper Id   BP: oldvalue 0x8001
-            ).create()
-            results = yield omci.send(frame)
-            # results = yield send_create_mac_bridge_port_configuration_data(omci,
-            #                                 0x000,   # Entity ID     BP: oldvalue 0x2102
-            #                                 0x100,   # Bridge Entity ID     BP: oldvalue 0x201
-            #                                 0,       # Port ID     BP: oldvalue 3
-            #                                 1,       # TP Type, Ethernet UNI     BP: oldvalue 3
-            #                                 0x101)   # TP ID, PPTP UNI Entity Id     BP: oldvalue 0x8001
-
-            status = results.fields['omci_message'].fields['success_code']
-            error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
-            self.log.debug('create-mac-bridge-port-configuration-data-part-2', status=status, error_mask=error_mask)
-
-            ################################################################################
-            # VLAN Tagging Filter config
-            #
-            #  EntityID will be referenced by:
-            #            - Nothing
-            #  References:
-            #            - Implicitly linked to an instance of the MAC bridge port configuration data
-            #              for the PON port
-            # TODO: Probably need to get VLAN ID from device.vlan
-            # Set anything, this request will not be used when using Extended Vlan
-
-            frame = VlanTaggingFilterDataFrame(
-                mac_bridge_port_ani_entity_id,       # Entity ID   BP: Oldvalue 0x2102
-                vlan_tcis=[vlan_tcis_1],             # VLAN IDs     BP: cvid
-                forward_operation=0x10
-            ).create()
-            results = yield omci.send(frame)
-            # results = yield send_create_vlan_tagging_filter_data(omci, 0x100,  # Entity ID   BP: Oldvalue 0x2102
-            #                                                      0x900)        # VLAN ID     BP: cvid
-
-            status = results.fields['omci_message'].fields['success_code']
-            error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
-            self.log.debug('create-vlan-tagging-filter-data', status=status, error_mask=error_mask)
-
-            ################################################################################
-            # Update the IEEE 802.1p Mapper Service Profile config
-            #
-            #  EntityID was created prior to this call
-            #  References:
-            #            -
-            #            -
-            # TODO: All p-bits currently go to the one and only GEMPORT ID for now
-
-            frame = Ieee8021pMapperServiceProfileFrame(
-                ieee_mapper_service_profile_entity_id,      # 802.1p mapper Service Mapper Profile ID
-                interwork_tp_pointers=[gem_entity_id]  # Interworking TP IDs  BP: oldvalue self.gemid
-            ).set()
-            results = yield omci.send(frame)
-            # results = yield send_set_8021p_mapper_service_profile(omci, 0x100, 0x4900)
-
-            status = results.fields['omci_message'].fields['success_code']
-            failed_attributes_mask = results.fields['omci_message'].fields['failed_attributes_mask']
-            unsupported_attributes_mask = results.fields['omci_message'].fields['unsupported_attributes_mask']
-            self.log.debug('set-8021p-mapper-service-profile', status=status,
-                           failed_attributes_mask=failed_attributes_mask,
-                           unsupported_attributes_mask=unsupported_attributes_mask)
-
-            ################################################################################
-            #  Unlock UNI
-            #
-            #  EntityID will be referenced by:
-            #            - MAC bridge port configuration data for the UNI side
-            #  References:
-            #            - Nothing
-
-            attributes = dict(
-                administrative_state=0  # 0 - Unlock
-            )
-            frame = PptpEthernetUniFrame(
-                ethernet_uni_entity_id,  # Entity ID
-                attributes=attributes    # See above
-            ).set()
-            results = yield omci.send(frame)
-            #results = yield send_set_pptp_ethernet_uni(omci, 0x101)  # Entity ID
-
-            status = results.fields['omci_message'].fields['success_code']
-            failed_attributes_mask = results.fields['omci_message'].fields['failed_attributes_mask']
-            unsupported_attributes_mask = results.fields['omci_message'].fields['unsupported_attributes_mask']
-            self.log.debug('set-pptp-ethernet-uni', status=status,
-                           failed_attributes_mask=failed_attributes_mask,
-                           unsupported_attributes_mask=unsupported_attributes_mask)
-
-            ################################################################################
-            # Create Extended VLAN Tagging Operation config
-            #
-            #  EntityID relates to the VLAN TCIS
-            #  References:
-            #            - VLAN TCIS from previously created VLAN Tagging filter data
-            #            - PPTP Ethernet UNI
-            #
-            # TODO: add entry here for additional UNI interfaces
-
-            attributes = dict(
-                association_type=2,                           # Assoc Type, PPTP Ethernet UNI   BP: Oldvalue 2
-                associated_me_pointer=ethernet_uni_entity_id  # Assoc ME, PPTP Entity Id        BP: Oldvalue 0x102
-            )
-
-            frame = ExtendedVlanTaggingOperationConfigurationDataFrame(
-                vlan_config_entity_id,
-                attributes=attributes     # See above
-            ).create()
-            results = yield omci.send(frame)
-            # results = yield send_create_extended_vlan_tagging_operation_configuration_data(omci,
-            #                                         0x900,  # Entity ID       BP: Oldvalue 0x202
-            #                                         2,      # Assoc Type, PPTP Ethernet UNI   BP: Oldvalue 2
-            #                                         0x101)  # Assoc ME, PPTP Entity Id   BP: Oldvalue 0x102
-
-            status = results.fields['omci_message'].fields['success_code']
-            error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
-            self.log.debug('create-extended-vlan-tagging-operation-configuration-data', status=status, error_mask=error_mask)
-
-            ################################################################################
-            # Update Extended VLAN Tagging Operation Config Data
-            #
-            # Specifies the TPIDs in use and that operations in the downstream direction are
-            # inverse to the operations in the upstream direction
-            # TODO: Downstream mode may need to be modified once we work more on the flow rules
-
-            attributes = dict(
-                input_tpid=0x8100,   # input TPID
-                output_tpid=0x8100,  # output TPID
-                downstream_mode=0,   # inverse of upstream
-            )
-            frame = ExtendedVlanTaggingOperationConfigurationDataFrame(
-                vlan_config_entity_id,    # Entity ID       BP: Oldvalue 0x202
-                attributes=attributes     # See above
-            ).set()
-            results = yield omci.send(frame)
-            # results = yield send_set_extended_vlan_tagging_operation_tpid_configuration_data(omci,
-            #                                         0x900,   # Entity ID      BP: Oldvalue 0x202
-            #                                         0x8100,  # input TPID
-            #                                         0x8100)  # output TPID
-
-            status = results.fields['omci_message'].fields['success_code']
-            failed_attributes_mask = results.fields['omci_message'].fields['failed_attributes_mask']
-            unsupported_attributes_mask = results.fields['omci_message'].fields['unsupported_attributes_mask']
-            self.log.debug('set-extended-vlan-tagging-operation-configuration-data', status=status,
-                           failed_attributes_mask=failed_attributes_mask,
-                           unsupported_attributes_mask=unsupported_attributes_mask)
-
-            ################################################################################
-            # Update Extended VLAN Tagging Operation Config Data
-            #
-            # parameters: Entity Id ( 0x900), Filter Inner Vlan Id(0x1000-4096,do not filter on Inner vid,
-            #             Treatment Inner Vlan Id : 2
-
-            attributes = dict(
-                received_frame_vlan_tagging_operation_table=
-                VlanTaggingOperation(
-                    filter_outer_priority=15,       # This entry is not a double-tag rule
-                    filter_outer_vid=4096,          # Do not filter on the outer VID value
-                    filter_outer_tpid_de=0,         # Do not filter on the outer TPID field
-
-                    filter_inner_priority=15,       # This is a no-tag rule, ignore all other VLAN tag filter fields
-                    filter_inner_vid=0x1000,        # Do not filter on the inner VID
-                    filter_inner_tpid_de=0,         # Do not filter on inner TPID field
-                    filter_ether_type=0,            # Do not filter on EtherType
-
-                    treatment_tags_to_remove=0,     # Remove 0 tags
-                    treatment_outer_priority=15,    # Do not add an outer tag
-                    treatment_outer_vid=0,          # n/a
-                    treatment_outer_tpid_de=0,      # n/a
-
-                    treatment_inner_priority=0,     # Add an inner tag and insert this value as the priority
-                    treatment_inner_vid=cvid,       # use this value as the VID in the inner VLAN tag
-                    treatment_inner_tpid_de=4       # set TPID = 0x8100
-                )
-            )
-            frame = ExtendedVlanTaggingOperationConfigurationDataFrame(
-                vlan_config_entity_id,    # Entity ID       BP: Oldvalue 0x202
-                attributes=attributes     # See above
-            ).set()
-            results = yield omci.send(frame)
-            # results = yield send_set_extended_vlan_tagging_operation_vlan_configuration_data_untagged(omci, 0x900,
-            #                                                                                           0x1000,
-            #                                                                                           2)
-            status = results.fields['omci_message'].fields['success_code']
-            failed_attributes_mask = results.fields['omci_message'].fields['failed_attributes_mask']
-            unsupported_attributes_mask = results.fields['omci_message'].fields['unsupported_attributes_mask']
-            self.log.debug('set-extended-vlan-tagging-operation-configuration-data-untagged', status=status,
-                           failed_attributes_mask=failed_attributes_mask,
-                           unsupported_attributes_mask=unsupported_attributes_mask)
-
-            # BP: This is for AT&T RG's
-            #
-            #   TODO: CB: NOTE: TRY THIS ONCE OTHER SEQUENCES WORK
-            #
-            # Set AR - ExtendedVlanTaggingOperationConfigData
-            #          514 - RxVlanTaggingOperationTable - add VLAN <cvid> to priority tagged pkts - c-vid
-            # results = yield omci.send_set_extended_vlan_tagging_operation_vlan_configuration_data_single_tag(
-            #                                 0x900,  # Entity ID
-            #                                 8,      # Filter Inner Priority, do not filter on Inner Priority
-            #                                 0,    # Filter Inner VID, this will be 0 in CORD
-            #                                 0,      # Filter Inner TPID DE
-            #                                 1,      # Treatment tags, number of tags to remove
-            #                                 8,      # Treatment inner priority, copy Inner Priority
-            #                                 2)   # Treatment inner VID, this will be 2 in CORD
-
-            # Set AR - ExtendedVlanTaggingOperationConfigData
-            #          514 - RxVlanTaggingOperationTable - add VLAN <cvid> to priority tagged pkts - c-vid
-            # results = yield omci.send_set_extended_vlan_tagging_operation_vlan_configuration_data_single_tag(
-            #                                 0x200,  # Entity ID
-            #                                 8,      # Filter Inner Priority
-            #                                 0,      # Filter Inner VID
-            #                                 0,      # Filter Inner TPID DE
-            #                                 1,      # Treatment tags to remove
-            #                                 8,      # Treatment inner priority
-            #                                 cvid)   # Treatment inner VID
-            #
-            # Set AR - ExtendedVlanTaggingOperationConfigData
-            #          514 - RxVlanTaggingOperationTable - add VLAN <cvid> to untagged pkts - c-vid
-            #results = yield omci.send_set_extended_vlan_tagging_operation_vlan_configuration_data_untagged(
-            #                                0x100,   # Entity ID            BP: Oldvalue 0x202
-            #                                0x1000,  # Filter Inner VID     BP: Oldvalue 0x1000
-            #                                cvid)    # Treatment inner VID  BP: cvid
-
-            # success = results.fields['omci_message'].fields['success_code'] == 0
-            # error_mask = results.fields['omci_message'].fields['parameter_error_attributes_mask']
-
-            ###############################################################################
-            # If here, we are done
-            device.reason = ''
-            self._handler.adapter_agent.update_device(device)
-
-            ######################################################################
-            # If here, we can add TCONTs/GEM Ports/... as needed
-
-            self._bridge_initialized = True
-            self._deferred = reactor.callLater(0, self._sync_existing_xpon)
-
-        except TimeoutError as e:
-            self.log.warn('rx-timeout', frame=frame)
-            # Try again later. May not have been discovered
-            self._deferred = reactor.callLater(_STARTUP_RETRY_WAIT,
-                                               self._initial_message_exchange)
-            returnValue('retry-pending')
-
-        except Exception as e:
-            self.log.exception('mib-download', e=e)
-            device.reason = 'MIB download sequence failure: ' + e.message
-            self._handler.adapter_agent.update_device(device)
-
-            # Try again later
-            self._deferred = reactor.callLater(_STARTUP_RETRY_WAIT,
-                                               self._initial_message_exchange)
-
-    @inlineCallbacks
-    def _sync_existing_xpon(self):
-        """
-        Run through existing TCONT and GEM Ports and push into hardware
-        """
-        # for tcont in self._tconts.itervalues():
-        #     try:
-        #         yield self.add_tcont(tcont, reflow=True)
-        #     except Exception as e:
-        #         self.log.exception('tcont-reflow', e=e, tcont=tcont)
-        #
-        # for gem_port in self._gem_ports.itervalues():
-        #     try:
-        #         yield self.add_gem_port(gem_port, reflow=True)
-        #
-        #     except Exception as e:
-        #         self.log.exception('gem-port-reflow', e=e, gem_port=gem_port)
-
-        returnValue('Done')
+                # Try again later
+                self._deferred = reactor.callLater(_STARTUP_RETRY_WAIT,
+                                                   self.resync_omci_settings)
 
-    @inlineCallbacks
     def add_tcont(self, tcont, reflow=False):
         """
         Creates/ a T-CONT with the given alloc-id
@@ -938,48 +659,37 @@
         :return: (deferred)
         """
         if not self._valid:
-            returnValue('Deleting')
+            return      # Deleting
 
         if not reflow and tcont.alloc_id in self._tconts:
-            returnValue('already created')
+            return      # already created
 
         self.log.info('add', tcont=tcont, reflow=reflow)
         self._tconts[tcont.alloc_id] = tcont
 
-        if not self.bridge_initialized:
-            returnValue('Bridge Not Initialized')
+        # only start setting sequence if there are at least one gem add
+        if len(self._gem_ports) > 0 and self._bridge_initialized:
+            self._cancel_resync_deferred()
+            self._bridge_initialized = False
+            self._resync_deferred = reactor.callLater(0, self.resync_omci_settings)
 
-        try:
-            results = yield tcont.add_to_hardware(self._handler.omci)
-
-        except Exception as e:
-            self.log.exception('tcont', tcont=tcont, reflow=reflow, e=e)
-            # May occur with xPON provisioning, use hw-resync to recover
-            results = 'resync needed'
-
-        returnValue(results)
-
-    @inlineCallbacks
     def update_tcont_td(self, alloc_id, new_td):
         tcont = self._tconts.get(alloc_id)
 
         if tcont is None:
-            returnValue('not-found')
+            return  # not-found
 
         tcont.traffic_descriptor = new_td
 
-        if not self.bridge_initialized:
-            returnValue('Bridge Not Initialized')
-
-        try:
-            results = yield tcont.add_to_hardware(self._handler.omci)
-
-        except Exception as e:
-            self.log.exception('tcont', tcont=tcont, e=e)
-            # May occur with xPON provisioning, use hw-resync to recover
-            results = 'resync needed'
-
-        returnValue(results)
+        # TODO: Not yet implemented
+        #TODO: How does this affect ONU tcont settings?
+        #try:
+        #    results = yield tcont.add_to_hardware(self._handler.omci)
+        #except Exception as e:
+        #    self.log.exception('tcont', tcont=tcont, e=e)
+        #    # May occur with xPON provisioning, use hw-resync to recover
+        #    results = 'resync needed'
+        # returnValue(results)
 
     @inlineCallbacks
     def remove_tcont(self, alloc_id):
@@ -988,20 +698,15 @@
         if tcont is None:
             returnValue('nop')
 
-        del self._tconts[alloc_id]
-
-        if not self.bridge_initialized:
-            returnValue('Bridge Not Initialized')
-
         try:
+            del self._tconts[alloc_id]
+
             results = yield tcont.remove_from_hardware(self._handler.omci)
+            returnValue(results)
 
         except Exception as e:
             self.log.exception('delete', e=e)
-            results = e
-        #     raise
-
-        returnValue(results)
+            raise
 
     def gem_port(self, gem_id):
         return self._gem_ports.get(gem_id)
@@ -1011,7 +716,6 @@
         """Get all GEM Port IDs used by this ONU"""
         return sorted([gem_id for gem_id, gem in self._gem_ports.items()])
 
-    @inlineCallbacks
     def add_gem_port(self, gem_port, reflow=False):
         """
         Add a GEM Port to this ONU
@@ -1021,47 +725,111 @@
         :return: (deferred)
         """
         if not self._valid:
-            returnValue('Deleting')
+            return  # Deleting
 
         if not reflow and gem_port.gem_id in self._gem_ports:
-            returnValue('nop')
+            return  # nop
 
         self.log.info('add', gem_port=gem_port, reflow=reflow)
         self._gem_ports[gem_port.gem_id] = gem_port
 
-        if not self.bridge_initialized:
-            returnValue('Bridge Not Initialized')
-
-        try:
-            results = yield gem_port.add_to_hardware(self._handler.omci)
-            # TODO: Are flows affected by this change?
-
-        except Exception as e:
-            self.log.exception('gem-port', gem_port=gem_port, reflow=reflow, e=e)
-            # This can happen with xPON if the ONU has been provisioned, but the PON Discovery
-            # has not occurred for the ONU. Rely on hw sync to recover
-            results = 'resync needed'
-
-        returnValue(results)
+        # assuming tcont was already added to start start settings sequence
+        if self._bridge_initialized:
+            self._cancel_resync_deferred()
+            self._bridge_initialized = False
+            self._resync_deferred = reactor.callLater(0, self.resync_omci_settings)
 
     @inlineCallbacks
     def remove_gem_id(self, gem_id):
+        """
+        Remove a GEM Port from this ONU
+
+        :param gem_port: (GemPort) GEM Port to remove
+        :return: deferred
+        """
         gem_port = self._gem_ports.get(gem_id)
 
         if gem_port is None:
             returnValue('nop')
 
-        del self._gem_ports[gem_id]
-
-        if not self.bridge_initialized:
-            returnValue('Bridge Not Initialized')
-
         try:
+            del self._gem_ports[gem_id]
+
             results = yield gem_port.remove_from_hardware(self._handler.omci)
-            # TODO: Are flows affected by this change?
+            returnValue(results)
 
         except Exception as ex:
             self.log.exception('gem-port-delete', e=ex)
             raise
 
-        returnValue(results)
+    def _subscribe_to_events(self):
+        from voltha.extensions.omci.onu_device_entry import OnuDeviceEvents, \
+            OnuDeviceEntry, IN_SYNC_KEY
+        from voltha.extensions.omci.omci_cc import OMCI_CC, OmciCCRxEvents, \
+            CONNECTED_KEY
+
+        def in_sync_handler(_topic, msg):
+            if self._in_sync_subscription is not None:
+                try:
+                    in_sync = msg[IN_SYNC_KEY]
+
+                    if in_sync:
+                        # Only call this once as well
+                        bus = self._onu_omci_device.event_bus
+                        bus.unsubscribe(self._in_sync_subscription)
+                        self._in_sync_subscription = None
+
+                        # Start up device_info load
+                        reactor.callLater(0, self._mib_in_sync)
+
+                except Exception as e:
+                    self.log.exception('in-sync', e=e)
+
+        def onu_is_reachable(_topic, msg):
+            """
+            Reach-ability change event
+            :param msg: (dict) 'connected' key holds True if reachable
+            """
+            if self._connectivity_subscription is not None:
+                try:
+                    connected = msg[CONNECTED_KEY]
+
+                    # TODO: For now, only care about the first.
+                    # Later we could use this for a heartbeat, but may want some hysteresis
+                    # Cancel any 'reachable' subscriptions
+                    if connected:
+                        evt_bus = self._onu_omci_device.omci_cc.event_bus
+                        evt_bus.unsubscribe(self._connectivity_subscription)
+                        self._connectivity_subscription = None
+                        self._connected = True
+
+                        device = self._handler.adapter_agent.get_device(self._handler.device_id)
+                        device.connect_status = ConnectStatus.REACHABLE
+                        self._handler.adapter_agent.update_device(device)
+
+                except Exception as e:
+                    self.log.exception('onu-reachable', e=e)
+
+        # OMCI MIB Database sync status
+        bus = self._onu_omci_device.event_bus
+        topic = OnuDeviceEntry.event_bus_topic(self._handler.device_id,
+                                               OnuDeviceEvents.MibDatabaseSyncEvent)
+        self._in_sync_subscription = bus.subscribe(topic, in_sync_handler)
+
+        # OMCI-CC Connectivity Events (for reachbility/heartbeat)
+        bus = self._onu_omci_device.omci_cc.event_bus
+        topic = OMCI_CC.event_bus_topic(self._handler.device_id,
+                                        OmciCCRxEvents.Connectivity)
+        self._connectivity_subscription = bus.subscribe(topic, onu_is_reachable)
+
+    def _unsubscribe_to_events(self):
+        if self._in_sync_subscription is not None:
+            bus = self._onu_omci_device.event_bus
+            bus.unsubscribe(self._in_sync_subscription)
+            self._in_sync_subscription = None
+
+        if self._connectivity_subscription is not None:
+            bus = self._onu_omci_device.omci_cc.event_bus
+            bus.unsubscribe(self._connectivity_subscription)
+            self._connectivity_subscription = None
+
diff --git a/voltha/adapters/adtran_onu/uni_port.py b/voltha/adapters/adtran_onu/uni_port.py
index 43ccfee..6fc7b04 100644
--- a/voltha/adapters/adtran_onu/uni_port.py
+++ b/voltha/adapters/adtran_onu/uni_port.py
@@ -24,8 +24,10 @@
 
 class UniPort(object):
     """Wraps southbound-port(s) support for ONU"""
+    DEFAULT_UNTAGGED_VLAN = 4092
 
-    def __init__(self, handler, name, port_no, control_vlan=None):
+    def __init__(self, handler, name, port_no, ofp_port_no, subscriber_vlan=None,
+                 untagged_vlan=None):
         self.log = structlog.get_logger(device_id=handler.device_id,
                                         port_no=port_no)
         self._enabled = False
@@ -33,21 +35,22 @@
         self._name = name
         self._port = None
         self._port_number = port_no
-        self._logical_port_number = None
-        self._control_vlan = control_vlan
+        self._ofp_port_no = ofp_port_no         # Set at by creator (vENET create)
+        self._logical_port_number = None        # Set at time of logical port creation
+        self._subscriber_vlan = subscriber_vlan
+        self._untagged_vlan = untagged_vlan
 
         self._admin_state = AdminState.ENABLED
         self._oper_status = OperStatus.ACTIVE
         # TODO Add state, stats, alarm reference, ...
-
         pass
 
     def __str__(self):
         return "UniPort: {}:{}".format(self.name, self.port_number)
 
     @staticmethod
-    def create(handler, name, port_no, control_vlan):
-        port = UniPort(handler, name, port_no, control_vlan)
+    def create(handler, name, port_no, ofp_port_no, subscriber_vlan, untagged_vlan):
+        port = UniPort(handler, name, port_no, ofp_port_no,subscriber_vlan, untagged_vlan)
         return port
 
     def _start(self):
@@ -117,20 +120,37 @@
         pass
 
     @staticmethod
-    def decode_openflow_port_and_control_vlan(self, venet_info):
+    def decode_venet(venet_info):
         try:
-            # Allow spaces or dashes as separator, select last as
-            # the port number
-
+            # Allow spaces or dashes as separator, select last as the
+            # port number.  UNI-1,  UNI 1, and UNI 3-2-1 are the same
             port_no = int(venet_info['name'].replace(' ', '-').split('-')[-1:][0])
-            cntl_vlan = port_no
+            subscriber_vlan = port_no
+            untagged_vlan = UniPort.DEFAULT_UNTAGGED_VLAN
+            try:
+                # Subscriber VLAN and Untagged vlan are comma separated
+                parts = venet_info['description'].split(',')
+                sub_part = next((part for part in parts if 'vlan' in part.lower()), None)
+                untagged_part = next((part for part in parts if 'untagged' in part.lower()), None)
+                try:
+                    if sub_part is not None:
+                        subscriber_vlan = int(sub_part.split(':')[-1:][0])
+                except Exception as e:
+                    pass
+                try:
+                    if untagged_part is not None:
+                        untagged_vlan = int(untagged_part.split(':')[-1:][0])
+                except Exception as e:
+                    pass
+            except Exception as e:
+                pass
 
-            return port_no, cntl_vlan
+            return port_no, subscriber_vlan, untagged_vlan
 
         except ValueError:
-            self.log.error('invalid-uni-port-name', name=venet_info['name'])
+            pass
         except KeyError:
-            self.log.error('invalid-venet-data', data=venet_info)
+            pass
 
     def get_port(self):
         """
@@ -145,28 +165,32 @@
                               oper_status=self._oper_status)
         return self._port
 
-    def add_logical_port(self, openflow_port_no, control_vlan=None,
+    def add_logical_port(self, openflow_port_no, subscriber_vlan=None,
                          capabilities=OFPPF_10GB_FD | OFPPF_FIBER,
                          speed=OFPPF_10GB_FD):
 
-        if self._logical_port_number is None:
-            self._logical_port_number = openflow_port_no
-            self._control_vlan = control_vlan
+        # Use vENET provisioned values if none supplied
+        port_no = openflow_port_no or self._ofp_port_no
+        vlan = subscriber_vlan or self._subscriber_vlan
+
+        if self._logical_port_number is None and port_no is not None:
+            self._logical_port_number = port_no
+            self._subscriber_vlan = vlan
 
             device = self._handler.adapter_agent.get_device(self._handler.device_id)
 
-            if control_vlan is not None and device.vlan != control_vlan:
-                device.vlan = control_vlan
+            if vlan is not None and device.vlan != vlan:
+                device.vlan = vlan
                 self._handler.adapter_agent.update_device(device)
 
             openflow_port = ofp_port(
-                port_no=openflow_port_no,
+                port_no=port_no,
                 hw_addr=mac_str_to_tuple('08:00:%02x:%02x:%02x:%02x' %
                                          ((device.parent_port_no >> 8 & 0xff),
                                           device.parent_port_no & 0xff,
-                                          (openflow_port_no >> 8) & 0xff,
-                                          openflow_port_no & 0xff)),
-                name='uni-{}'.format(openflow_port_no),
+                                          (port_no >> 8) & 0xff,
+                                          port_no & 0xff)),
+                name='uni-{}'.format(port_no),
                 config=0,
                 state=OFPPS_LIVE,
                 curr=capabilities,
@@ -177,7 +201,7 @@
             )
             self._handler.adapter_agent.add_logical_port(self._handler.logical_device_id,
                                                          LogicalPort(
-                                                             id='uni-{}'.format(openflow_port),
+                                                             id='uni-{}'.format(port_no),
                                                              ofp_port=openflow_port,
                                                              device_id=device.id,
                                                              device_port_no=self._port_number))